= MMC device API = [[PageOutline]] == __A) General principles__ == This device allows the kernel to access an L2 cache, seen as an internal peripherals (distributed in all clusters), and containing addressable registers used for three different purposes: 1. instrumentation, 1. L2/L3 software cache coherence. 1. addressing error signaling. The "kernel" API contains defines five command to access those three types of registers, details in section C. As all L2 caches can be accessed by any thread running in any cluster, a calling thread must get exclusive access to this MMC configuration interface. As these operations consume few cycles, and access conflicts are expected to be rare events, the calling threads can use a busy waiting strategy to get the device busy lock. They do not register in the device waiting queue, and do not use any server thread. These MMC devices can rise an MMC_IRQ when a bad address is detected for a write transaction. In this case, the error is reported by the ''ioc_driver_isr()'' function (ISR stand for Interrupt Service Routine). To access the various drivers, the IOC device defines a lower-level "driver" API, that is detailed in section D below. All MMC device structures and access functions are defined in the [https://www-soc.lip6.fr/trac/almos-mkh/browser/trunk/kernel/devices/dev_mmc.c dev_mmc.c] et [https://www-soc.lip6.fr/trac/almos-mkh/browser/trunk/kernel/devices/dev_mmc.h dev_mmc.h] files. == __B) Initialisation__ == The '''dev_mmc_init( chdev_t * chdev )''' function makes the following initializations : * This function initializes the driver specific fields in the generic MMC device descriptor. * It initialise the implementation specific MMC driver. * It links the MMC_IRQ to the local core identified by (lpid == 0), and enables this IRQ. It must be executed once in any cluster containing an L2 cache. == __C) The "kernel" API__ == All these operations are blocking (return only when the transfer is completed), and use all a polling policy. * The '''dev_mmc_inval( xptr_t buffer_xp , uint32_t nbytes )''' blocking function invalidates all cache lines covering a memory buffer in the physical address space, defined by the extended pointer and by the argument. It can be executed by any thread in any cluster, because it uses remote accesses to access both the MMC chdev descriptor, and the MMC registers. * The '''dev_mmc_sync( xptr_t buffer_xp , uint32_t nbytes )''' blocking function forces the L2 cache to synchronize the L3 cache for all cache lines covering a memory buffer in the physical address space, defined by the extended pointer and by the argument. It can be executed by any thread in any cluster, because it uses remote accesses to access both the MMC chdev descriptor, and the MMC registers. * The '''dev_mmc_error_set( cxy_t cxy , uint32_t index , uint32_t wdata )''' function set the value in one MMC_ERROR register identified by the cluster identifier, and by the register . It can be executed by any thread in any cluster, because it uses remote accesses to access both the MMC chdev descriptor, and the MMC registers. * The '''dev_mmc_error_get( cxy_t cxy , uint32_t index , uint32_t rdata )''' function returns in the value contained in one MMC_ERROR register identified by the cluster identifier, and by the register . It can be executed by any thread in any cluster, because it uses remote accesses to access both the MMC chdev descriptor, and the MMC registers. * The '''dev_mmc_instr_get( cxy_t cxy , uint32_t index , uint32_t * rdata )''' function returns in the value contained in one MMC_INST register identified by the cluster identifier, and by the register . It can be executed by any thread in any cluster, because it uses remote accesses to access both the MMC chdev descriptor, and the MMC register. == __D) The "driver" API__ == All MMC drivers must define three functions : * void '''mmc_driver_init( chdev_t *ioc_chdev )''' * void '''mmc_driver_cmd( xptr_t thread_xp )''' * void '''mmc_driver_isr( chdev_t * ioc_chdev )''' The ''mmc_driver_cmd()'' function arguments are actually defined in the ''mmc_command_t'' structure embedded in the client thread descriptor. One command contains four informations: - '''type''' : operation type (defined below). - '''buf_ptr''' : local pointer on buffer in kernel space (for INVAL/SYNC). - '''buf_size''' : number of bytes in buf_ptr buffer. - '''reg_index''' : register index in MMC peripheral. - '''reg_ptr''' : local pointer on source/destination buffer (for GET/SET). The set of available instrumentation registers depend on the implementation. The five command types for the MMC driver(s) are the following: * '''MMC_CC_INVAL''' : invalidate all cache lines covering a given buffer in L2 cache. * '''MMC_CC_SYNC''' : synchronize all cache lines covering a given buffer to L3 cache. * '''MMC_ERROR_SET''' : set a given error signaling register. * '''MMC_ERROR_GET''' : return the content of a given error signaling register. * '''MMC_INSTRU_GET''' : return the content of a given instrumentation register. The '''mmc_driver_isr()''' must acknowledge the MMC_IRQ.