diff options
| author | Karthikeyan Ramasubramanian <kramasub@codeaurora.org> | 2016-02-11 16:14:54 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-22 11:08:48 -0700 |
| commit | 12ca113b10ad665c247031f51e5de6ef8554f5f5 (patch) | |
| tree | 44ac19b25366d7ba1aecd46ed9535d915e24da77 | |
| parent | a8d687d1ee857d5b7c75dc94a2d905e2e09e387d (diff) | |
Documentation: arm: msm: Add document for SMEM Driver
The Shared Memory Manager driver implements an interface for allocating
and accessing items in the memory area shared among all of the
processors in a Qualcomm platform.
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
| -rw-r--r-- | Documentation/arm/msm/msm_smem.txt | 595 |
1 files changed, 595 insertions, 0 deletions
diff --git a/Documentation/arm/msm/msm_smem.txt b/Documentation/arm/msm/msm_smem.txt new file mode 100644 index 000000000000..6d31344a17a1 --- /dev/null +++ b/Documentation/arm/msm/msm_smem.txt @@ -0,0 +1,595 @@ +Introduction +============ +The Shared Memory (SMEM) protocol allows multiple processors in Qualcomm +Technologies, Inc. MSM System on Chips to communicate at a low level using a +segment of shared system memory that is accessible by any of the processors. +This is accomplished by an operating-system independent mechanism that allows a +client on any processor to dynamically allocate a block of memory from shared +system memory which is then visible and accessible to clients on other +processors for the purpose of storing and exchanging data. + + + +-------------+ + SMEM | Processor 1 | + +---------+ +------------+ +-------------+ + | |+--------------->| Item 1 |<----------------+ ^ + | Linux | | | | + | |<---------------+| |+-------------------+ + +---------+ +------------+ + ^ + | Item 2 | +-------------+ + | | | |<--------------+| Processor 2 | + | | | |+-------------->| | + | | | | +-------------+ + | | | | + | | | | +-------------+ + | | +------------+ | Processor 3 | + | | . +-------------+ + | | . + ^ . + | | +------------+ | | . + | +----------------->| Item N |<-----------------+ | . + +---------------------+| |+--------------------+ . + | | +-------------+ + | |+-------------->| | + | | | Processor N | + | |<--------------+| | + +------------+ +-------------+ + +The SMEM driver supports all known versions of the SMEM protocol. + +Hardware description +==================== +The SMEM protocol requires a contiguous segment of system memory that is +accessible by both the local processor and one or more remote processors. +Each processor supporting the SMEM protocol must configure their MMUs and other +applicable hardware such that accesses to shared memory are non-cacheable. + +Optionally, additional segments of system memory may be provided to act as +auxiliary memory areas for the SMEM protocol. Such segments may provide +performance benefits to certain processors by optimizing access latency. Such +auxiliary memory areas must be a slave to the single main SMEM area. + +While the SMEM protocol has provisions for software-based remote spinlocks to +manage synchronization between processors, this functionality may be +substituted with dedicated hardware. Such hardware is expected to be managed +by another driver providing a standardized API. + +Software description +==================== +At its core, the SMEM protocol is a heap memory management system. The core +functionality consists of allocating segments of memory, and lookup operations +to find the address of existing segments of memory. There is no provision to +free memory that is allocated. + +Allocated segments of memory are called SMEM items. Each SMEM item has a unique +32-bit identifier which maps each specific SMEM item to a slot in the table of +contents that lives at the start of the SMEM region. + +A SMEM client that wishes to allocate a SMEM item will provide the item +identifier and a desired size in bytes. Assuming there is enough free space in +the SMEM region to accommodate the request, the amount of desired bytes will be +carved out, and the base address and size for the item will be stored in the +table of contents. The base address will be returned as a pointer to the +client, so that the client may use the SMEM item as if it were normal memory +allocated through "malloc". + +A SMEM client that wishes to find an already allocated SMEM item will provide +the item identifier and the size in bytes that the client expects for the item. +A lookup in the table of contents for the specified item identifier will be +performed. Assuming a matching SMEM item is found, the size of the item that +is stored in the table of contents will be compared to the size specified by the +client. This sanity check of the expected vs actual size is done to ensure that +all users of a particular SMEM item agree on the size of the data to be +exchanged under the assumption that if the users do not agree on the item size, +then they will not be able to sucessfully communicate as one or more sides may +view a corruption of the data stored in the SMEM item. Assuming the sizes +match, the virtual address corresponding to the base address stored in the table +of contents for the item will be returned to the client. + + +------+ Request +-----------+ Memory + |Client|+----------------->|SMEM Driver| +---------------+ + +------+ Item X of size Y +-----------+ | | + ^ + | | + | | Lookup/Alloc +---------------+ Find X + | +--------------->| TOC[X] |+--------+ + | +---------------+ | + | | | | + | | | | + | | | | + | | | | + | | | | + | | | | + | Return pointer for client +---------------+ | + +---------------------------------------------+| Item X |<--------+ + +---------------+ + | | + | | + | | + +---------------+ + +The SMEM driver depends on the kernel memory management subsystem for managing +the system memory that SMEM uses. The main SMEM memory region is statically +mapped at boot, and the virtual address for the base of the region is stored +in MSM_SHARED_RAM_BASE. Auxiliary memory regions are ioremap'd at driver init. +All SMEM regions are mapped as non-cacheable. + +Although the SMEM driver is aware of auxiliary memory regions, and capable of +understanding SMEM items that exist in auxiliary memory regions, the SMEM +driver does not allocate from the auxiliary memory regions. A detailed +description of the purpose and use of auxiliary memory regions is outside the +scope of this document. + +Design +====== +The SMEM protocol requires that the system bootloader initialize (zero out) and +bootstrap the main SMEM region before any processor in the system has booted to +avoid an initialization race condition. + +SMEM regions are configured as non-cachable memory. While this results in a +small performance hit, it significantly reduces the complexity for the SMEM +driver and clients in terms of cache management and memory barriers. Clients +are generally able to treat their SMEM items like regular local memory, which +eases the requirements to write correct code. + +The unsigned data type is assumed to be an unsigned 32-bit integer value. + +The root structure at the base of the main SMEM region is: + +#define SMD_HEAP_SIZE 512 + +struct smem_shared { + struct smem_proc_comm proc_comm[4]; + unsigned version[32]; + struct smem_heap_info heap_info; + struct smem_heap_entry heap_toc[SMD_HEAP_SIZE]; +}; + +This structure and its fields are initialized by the bootloader. + +The proc_comm field is reserved as the first part of the SMEM region to maintain +compatibility with legacy systems, but is otherwise deprecated. While the +proc comm driver is beyond the scope of this document, the remaining structure +definition to fully define smem_shared is: + +struct smem_proc_comm { + unsigned command; + unsigned status; + unsigned data1; + unsigned data2; +}; + +The version field of the smem_shared struct is an array of version entries +specifying the SMEM protocol version of every supporting processor active in the +system. Each unsigned value in the array corresponds to one entry. This +provides a mechanism for ensuring protocol version compatability between +processors. While the full table of assigned and reserved entries in the array +is beyond the scope of this document, index 8 (smem_shared.version[8]) is +reserved for any future use by Linux. The bootloader always initializes it's +entry (index 7, or smem_shared.version[7]) to the SMEM protocol version +supported by the bootloader. Checking the value of the bootloader's entry can +be used as a sanity check to determine if the SMEM region was sucessfully +initialized. + +The heap_info field of smem_shared contains basic information of the SMEM heap. +The bootloader fills in values corresponding to the main SMEM region when it +initializes the heap. It is defined as: + +struct smem_heap_info { + unsigned initialized; + unsigned free_offset; + unsigned heap_remaining; + unsigned reserved; +}; + +The initialized field is set to 1 by the bootloader when it initializes the +heap. The free_offset field contains the offset from the base of the SMEM +region for the first free byte in the heap. When a new SMEM item is allocated, +free_offset is incremented by the size of the allocated item. SMEM item sizes +are 8-byte aligned. The heap_remaining field contains the number of free bytes +remaining in the heap. When a new SMEM item is allocated, heap_remaining is +decremented by the size of the item. The reserved field is defined to be 0. + +The heap_toc field of smem_shared is the heap table of contents. It is an array +containing a slot for every defined SMEM item. SMEM item identifiers index into +this array. The structures definition is: + +struct smem_heap_entry { + unsigned allocated; + unsigned offset; + unsigned size; + unsigned reserved; /* bits 1:0 reserved, bits 31:2 aux smem base addr */ +}; + +If an SMEM item is allocated, the allocated field is 1. The offset field is +either the offset from the main SMEM region base where this SMEM item exists, or +the offset from the auxiliary SMEM region base specified in the reserved field. +The size field contains the size of the SMEM item in bytes. The size is defined +to be 8-byte aligned. The reserved field is 0 if the SMEM item is located in +the main SMEM region, or bits 31(MSB) to 2 specify the physical address of the +auxiliary SMEM region where the SMEM item resides. If reserved is used as a +physical address, then the address must be 4-byte aligned per ARM architectural +requirements. + +The bootloader allocates and intializes the following SMEM items: + +Name ID Size (bytes) +---------------------------------------------------- +SMEM_PROC_COMM 0 64 +SMEM_HEAP_INFO 1 16 +SMEM_ALLOCATION_TABLE 2 8192 +SMEM_VERSION_INFO 3 128 +SMEM_HW_RESET_DETECT 4 8 +SMEM_AARM_WARM_BOOT 5 4 +SMEM_DIAG_ERR_MESSAGE 6 200 +SMEM_SPINLOCK_ARRAY 7 32 +SMEM_MEMORY_BARRIER_LOCATION 8 4 + +All other SMEM items are dynamically allocated by processors in the system. + +Although the SMEM protocol requires the bootloader to initialize the SMEM region +before any processor in the system is active, early development of new systems +do not always have a fully functional bootloader. To determine if the +bootloader initialized the main SMEM region properly, the SMEM driver will check +the expected values of smem_shared.heap_info.initialized, +smem_shared.heap_info.reserved, and the bootloader entry of the +SMEM_VERSION_INFO SMEM item. If this check fails, the SMEM driver will print +an error message to the kernel log, and enter a disabled state. + +Security Feature +---------------- +The SMEM protocol supports an optional security feature that segments the main +SMEM region into multiple partitions. Each partition becomes a unique item +namespace. Access to partitions is restricted to a maximum of two processors +and enforced by Memory Protection Units (MPUs). The exceptions to this are the +Partition Table of Contents partition, which is read-only accessible by all +processors, and the Legacy/Default partition, which is freely accessible by all +processors. + + +-------------------------+ SMEM Base address + |Legacy/Default | + |SMEM Partition | + +-------------------------+ + |SMEM Partition 0 | + |Processor 1 - Processor 2| + +-------------------------+ + |SMEM Partition 1 | + |Processor 1 - Processor 3| + +-------------------------+ + |SMEM Partition 2 | + |Processor 4 - Processor 5| + +-------------------------+ + . + . + . + +-------------------------+ + |SMEM Partition N | + |Processor N - Processor M| + +-------------------------+ SMEM Base address + SMEM size - 4k + |Table of Contents | + | | + +-------------------------+ SMEM Base address + SMEM size + +SMEM items which are point-to-point in nature and accessed by two or fewer +processors may be allocated from a partition that is restricted to those +processors. SMEM items which are non-sensitive, accessed by 3 or more +processors, and/or do not correspond to a secured partition are allocated from +the Legacy/Default partition. + +During the firmware boot process, the Table of Contents is initialized with a +description of all the secured partitions. Each secured partition is also +initialized. The required MPU settings to protect the Table of Contents and the +secured partitions are also established. The Table of Contents is located 4k +bytes prior to the end of the main SMEM region so that it is in a known position +for all processors to find and do local configuration. + +The Table of Contents is defined as: + +struct smem_toc { + /* + * Identifier is a constant for use in debugging and identifying this + * struct in a binary capture. Set to 0x434f5424 ("$TOC"). + */ + uint32_t identifier; + + /* Version number */ + uint32_t version; + + /* Number of entries in the table */ + uint32_t num_entries; + + uint32_t reserved[5]; + + /* Zero or more entries follow */ + struct smem_toc_entry entry[]; +}; + +Each entry in the Table of Contents is defined as: + +struct smem_toc_entry { + /* Offset in bytes from SMEM base of the region */ + uint32_t offset; + + /* Size in bytes of the region */ + uint32_t size; + + /* Flags for this region */ + uint32_t flags; + + /* + * IDs for the 2 subsystems which have access to this partition. + * Order does not matter. + * For the entry which describes the TOC itself, these are both set to + * SMEM_INVALID_HOST. + * Use uint16_t, rather than enum type, to ensure size. + */ + uint16_t host0; + uint16_t host1; + + /* + * Lowest common multiple of cacheline sizes for both endpoints. For + * example, if host0 has cacheline size of 32 and host1 has cacheline + * size of 64, this value is set to 64. + */ + uint32_t size_cacheline; + + uint32_t reserved[3]; + + /* + * Sizes of sub ranges that are part of the region, but are excluded + * from the SMEM heap. These are allocated from the end of the region + * starting with sizes[0]. Set to 0 when not used. + */ + uint32_t exclusion_sizes[SMEM_TOC_MAX_EXCLUSIONS]; +}; + +While the Legacy/Default partition maintains the structure and format of the +main SMEM region with the security feature disabled, the secured partitions have +a different format and structure: + + +--------------+ +--------------------------+ Partition Base Address + | | | Partition Header | + | | | | + + | Uncached Page| +--------------------------+ | + | | | Item A Header | | + | | +--------------------------+ | + | | | Item A Data | | + +--------------+ | | | + | | | | | + | | +--------------------------+ | + | Uncached Page| | Item B Header | |Direction of heap growth + | | +--------------------------+ | + | | | Item B Data | | + | | | | | + +--------------+ | | | + | | +--------------------------+ | + | | | | | + | Uncached Page| | Unused Heap | | + | | | space to | v + | | | page boundry | + | | | | + +--------------+ +--------------------------+<----------+ End of heap + . . . . . . + Free Space + Can be used for + either heap. + . . . . . . + +--------------+ +--------------------------+<----------+ End of heap + | | | | + | | | Unused Heap | + | Cached Page | | space to | ^ + | | | page boundry | | + | | +--------------------------+ | + | | | Item Y Data | | + +--------------+ | | | + | | +--------------------------+ | + | | | Item Y Header | | + | Cached Page | +--------------------------+ | + | | | Item Y Header Padding | |Direction of heap growth + | | +--------------------------+ | + | | | Item Z Data | | + +--------------+ | | | + | | | | | + | | | | | + | Cached Page | +--------------------------+ | + | | | Item Z Header | | + | | +--------------------------+ + Padding is here to ensure + | | | Item Z Header Padding | the the data buffer start + +--------------+ +--------------------------+ and end addresses are + | | aligned to cachelines for + | | Exclusion Range both endpoints. + | Uncached Page|. . . Free Space . . . + | | +--------------------------+ + | | | Exclusion Ranges 0..N | + | | | | + +--------------+ +--------------------------+ Partition Base Address + size + +The design of the secured partitions has two advantages over the Legacy/Default +Partition + 1. Using a linked list instead of a static array to track allocated SMEM + items maximizes space utilization + 2. Creating two heaps allows one to be cacheline aligned, thus providing + an option for a higher level of performance to clients (requires + client to specify they want their SMEM item allocated in the + cached area) + +The partition header struct is defined as: + +struct smem_partition_header { + /* Identifier magic number - 0x54525024 ("$PRT") */ + uint32_t identifier; + + /* + * IDs for the 2 subsystems which have access to this partition. + * Order does not matter. + * Use uint16_t, rather than enum type, to ensure size. + */ + uint16_t host0; + uint16_t host1; + + /* Partition size, in bytes, not including the exclusion ranges */ + uint32_t size; + + /* Offset of the byte following the last allocation in uncached heap */ + uint32_t offset_free_uncached; + + /* Offset of the byte following the last allocation in cached heap */ + uint32_t offset_free_cached; + + uint32_t reserved[3]; +}; + +The allocated SMEM item header struct is defined as: + +struct smem_partition_allocation_header { + /* 0xa5a5 canary value to detect overrun problems */ + uint16_t canary; + + /* SMEM item ID. Use uint16_t here, rather than enum, to ensure size. */ + uint16_t smem_id; + + /* Size of the allocated item, includes any necessary padding. */ + uint32_t size; + + /* Size of the data padding for cacheline alignment, if applicable */ + uint16_t data_padding; + + /* Size of the header padding for cacheline alignment, if applicable */ + uint16_t header_padding; + + uint32_t reserved[1]; +}; + +SMP/multi-core +============== +The SMEM driver expects a remote spinlock driver to provide inter-processor +synchronization primitives which not only provide locking between multiple cores +but locking between multiple processors to protect the state of structures +stored in SMEM regions during allocation and lookup. Once a pointer to a SMEM +item is returned to a client, that client is expected to provide all the +necessary locking and other synchronization as required. + +The remote spinlocks may make use of the SMEM_SPINLOCK_ARRAY SMEM item (typical +of legacy systems). + +SMEM regions are non-cachable to maintain a consistent state of the data +throughout all operations. This simplifies cache management and memory barrier +requirements to a few key points in the SMEM item allocation process, and allows +clients to treat SMEM items like local memory once allocated. + +Security +======== +SMEM by default provides no security of SMEM items. If a SMEM item is intended +to only be used between clients on processors A and B, malicious clients on +processor C are free to sniff or inject data into the SMEM item. + +An optional security feature may be enabled that makes use of Memory Protection +Units (MPUs) to limit access of special segments of the main SMEM region. +Access to these partitions is limited to two processors, so only point-to-point +traffic (such as SMD or SMP2P) is able to be protected. Auxiliary SMEM regions +are not protected under this feature. Support for this feature is activated by +a Device Tree property. + +Performance +=========== +Some client use cases such as SMD may benefit from caching, but that places an +additional burden of cache maintenance and protocol design onto the clients. + +Interface +========= +Kernel-space APIs: + +/** + * smem_alloc() - Find an existing item, otherwise allocate it with security + * support + * + * @id: ID of SMEM item + * @size_in: Size of the SMEM item + * @to_proc: SMEM host that shares the item with apps + * @flags: Item attribute flags + * @returns: Pointer to SMEM item, NULL if it couldn't be found/allocated, or + * -EPROBE_DEFER if the driver is not ready + */ +void *smem_alloc(unsigned id, unsigned size_in, unsigned to_proc, + unsigned flags); + +/** + * smem_get_entry() - Get existing item with security support + * + * @id: ID of SMEM item + * @size: Pointer to size variable for storing the result + * @to_proc: SMEM host that shares the item with apps + * @flags: Item attribute flags + * @returns: Pointer to SMEM item, NULL if it doesn't exist, or -EPROBE_DEFER + * if the driver isn't ready + */ +void *smem_get_entry(unsigned id, unsigned *size, unsigned to_proc, + unsigned flags); + +/** + * smem_get_entry_no_rlock() - Get existing item without using remote spinlock. + * + * @id: ID of SMEM item + * @size_out: Pointer to size variable for storing the result + * @to_proc: SMEM host that shares the item with apps + * @flags: Item attribute flags + * @returns: Pointer to SMEM item, NULL if it doesn't exist, or -EPROBE_DEFER + * if the driver isn't ready + * + * This function does not lock the remote spinlock and should only be used in + * failure-recover cases such as retrieving the subsystem failure reason during + * subsystem restart. + */ +void *smem_get_entry_no_rlock(unsigned id, unsigned *size_out, unsigned to_proc, + unsigned flags); + +/** + * smem_find() - Find existing item with security support + * + * @id: ID of SMEM item + * @size_in: Size of the SMEM item + * @to_proc: SMEM host that shares the item with apps + * @flags: Item attribute flags + * @returns: Pointer to SMEM item, NULL if it doesn't exist, or -EPROBE_DEFER + * if the driver is not ready + */ +void *smem_find(unsigned id, unsigned size); + +/** + * smem_virt_to_phys() - Convert SMEM address to physical address. + * + * @smem_address: Address of SMEM item (returned by smem_alloc(), etc) + * @returns: Physical address (or NULL if there is a failure) + * + * This function should only be used if an SMEM item needs to be handed + * off to a DMA engine. This function will not return a version of EPROBE_DEFER + * if the driver is not ready since the caller should obtain @smem_address from + * one of the other public APIs and get EPROBE_DEFER at that time, if + * applicable. + */ +phys_addr_t smem_virt_to_phys(void *smem_address); + +Driver parameters +================= +Module parameters: +debug_mask - 0 for off (default), 1 for on. + Enables or disables printing debug messages to the kernel log + +Config options +============== +Configuration of SMEM regions is done via Device Tree per the format in +Documentation/devicetree/bindings/arm/msm/smem.txt. + +Dependencies +============ +Drivers needed: + Remote spinlocks + +Depends on the system bootloader to initialize the main SMEM region. + +Known issues +============ +None. + +To do +===== +Convert use of the unsigned data type to well defined value such as uint32_t for +better portability. |
