Template Version: @(#)onepager.txt 1.29 04/11/15 SMI This information is Copyright 2006 Sun Microsystems, Inc. 1. Introduction 1.1. Project/Component Working Name: Allocating memory from the DDI with Cache Disable Support on X86 1.2. Name of Document Author/Supplier: Eiji Ota (eiji.ota@sun.com) Mark Johnson (mark.johnson@sun.com) 1.3. Date of This Document: 03/22/06 1.4. Name of Major Document Customer(s)/Consumer(s): 1.4.1. The PAC or CPT you expect to review your project: Solaris PAC 1.4.2. The ARC(s) you expect to review your project: PSARC 1.4.3. The Director/VP who is "Sponsoring" this project: Barry Cooks (barry.cooks@sun.com) 1.4.4. The name of your business unit: OPG, Solaris Core Technologies 1.5. Email Aliases: 1.5.1. Responsible Manager: peter.luk@sun.com 1.5.2. Responsible Engineer: eiji.ota@sun.com, mark.johnson@sun.com 1.5.3. Marketing Manager: chris.ratcliffe@sun.com 1.5.4. Interest List: iom-interest@Sun.Com 2. Project Summary 2.1. Project Description: The project provides a method to access uncacheable memory, which is required for some graphics drivers running on X86/AMD64 architecture. 2.2. Risks and Assumptions: None that we know of. 3. Business Summary 3.1. Problem Area: Some graphics drivers on X86/AMD64 require a method to have access to memory with the uncacheable attribute to keep coherency between a graphic chip and the rest on the system, but Solaris doesn't provide any interfaces those drivers can use. As a result, they have to implement how to access the uncacheable memory in their own ways. This could be seen inconvenient by Solaris driver developers and inconsistent by Solaris kernel developers. 3.2. Market/Requester: Graphic device drivers running on X86 architecture. 3.3. Business Justification: Uncacheable memory access is required for some graphics chips on X86/AMD64 architecture these days. However, Solaris doesn't provide the DDI interface for that purpose yet. This project provides the unified and consistent method to support those graphics drivers running on X86/AMD64. 3.4. Competitive Analysis: Major operating systems running on X86/AMD64 (i.e. Linux/Windows) support similar functions already. 4. Technical Description: 4.1. Details: New cache attribute flags (See 4.3) are introduced to provide the uncacheable memory access via the DDI interface. Those flags should be passed to ddi_dma_mem_alloc(), devmap_umem_setup() or devmap_pmem_setup() when a driver wants to access memory with the uncacheable attribute. If no flags is specified, IOMEM_DATA_CACHED is used to keep compatibilty. ddi_dma_mem_alloc() is used to allocate non-pageable kernel memory for a driver. The new flags are used to provide a driver with an access to the uncacheable memory in the same manner. devmap_umem_setup() and devmap_umem_remap() are used to export kernel memory to the userland. The new flag are used to allow an application to have access to the uncacheable memory by mmap(). devmap_pmem_setup() and devmap_pmem_remap() are used to export kernel physical memory to graphics drivers. The new flags are used to provide a driver with access to the uncacheable memory in the same manner. The gfx_private module is also updated to implement the uncacheable memory access by the new flags. 4.2. Bug/RFE Number(s): 6212057 ddi_dma_mem_alloc should support DDI_STRICTORDER_ACC in x86 4.3. Interfaces: +-------------------------+----------------+------------------------+ | Interface Name | Classification | Comments | +-------------------------+----------------+------------------------+ | IOMEM_DATA_CACHED | Evolving | default value. | | | | | | IOMEM_DATA_UC_WR_COMBINE| Evolving | data is not cached, but| | | | writes may occur out of| | | | order or be combined. | | | | | | IOMEM_DATA_UNCACHED | Evolving | data is not cached. | | | | strict ordering. | +-------------------------+----------------+------------------------+ The following examples show how to use this flag for the uncacheable memory access; a driver doesn't need any other things than just setting IOMEM_DATA_UNCACHED to have access to ucacheable memory as follows. o ddi_dma_mem_alloc() if (ddi_dma_mem_alloc(dma_handle, size, &dev_attr, DDI_DMA_CONSISTENT | IOMEM_DATA_UNCACHED, DDI_DMA_SLEEP, NULL, (caddr_t *)&addr, &alloc_len, &accessp) != DDI_SUCCESS) { : } o devmap_umem_setup() if (devmap_umem_setup(dhp, dip, callbackops, cookie, offset, length, PROT_ALL, IOMEM_DATA_UNCACHED, &endian_attr) < 0) { : } o devmap_pmem_setup() if (devmap_pmem_setup(cookie, dip, &cb, cookie, offset, len, PROT_ALL, IOMEM_DATA_UNCACHED, &attr)) < 0) { : } 4.6. Doc Impact: Man pages (ddi_dma_mem_alloc(9F) and devmap_devmem_setup(9F)) The differences are attached below.(the changes have bars on the left) 4.7. Admin/Config Impact: No impact on Admin/Config. 4.8. HA Impact: No impact on HA. 4.9. I18N/L10N Impact: No impact on I18N/L10L 4.10. Packaging & Delivery: No impact on packages, clusters and metaclusters. No impact on install/upgrade. 4.11. Security Impact: No impact on Security. 4.12. Dependencies: None. 5. Reference Documents: PSARC 2004/151 AGPgart project PSARC 2005/475 Graphics private misc module for x86 PSARC 2005/623 gfx_private update for devmap and DMA 6. Resources and Schedule: 6.1. Projected Availability: April/2006 6.4. Product Approval Committee requested information: 6.4.1. Consolidation or Component Name: ON 6.4.3. Type of CPT Review and Approval expected: FastTrack 6.4.7. Target RTI Date/Release: onnv_b39 6.4.8. Target Code Design Review Date: 4/4 6.5. ARC review type: FastTrack (ddi_dma_mem_alloc()) Kernel Functions for Drivers ddi_dma_mem_alloc(9F) NAME ddi_dma_mem_alloc - allocate memory for DMA transfer SYNOPSIS #include #include int ddi_dma_mem_alloc(ddi_dma_handle_t handle, size_t length, ddi_device_acc_attr_t *accattrp, uint_t flags, int (*waitfp) (caddr_t), caddr_t arg, caddr_t *kaddrp, size_t *real_length, ddi_acc_handle_t *handlep); INTERFACE LEVEL Solaris DDI specific (Solaris DDI). PARAMETERS handle The DMA handle previously allocated by a call to ddi_dma_alloc_handle(9F). length The length in bytes of the desired alloca- tion. | accattrp Pointer to a ddi_device_acc_attr(9S) struc- | ture of this device (see ddi_device_acc_attr(9S)). | The value in devacc_attr_dataorder is ignored in | the current release. The value in | devacc_attr_endian_flags is meaningful on the sparc | architecture only. | flags Used to determine the data transfer mode and/or | the cache attribute. | | Possible values of the data tranfer mode are: | | DDI_DMA_STREAMING Sequential, uni- | directional, block- | sized, and block- | aligned transfers. | | DDI_DMA_CONSISTENT Nonsequential | transfers of small | objects. | | Possible values of the cache attribute are: | | IOMEM_DATA_CACHED The CPU can cache the data | it fetches and push it to memory | at a later time. This is the | default attribute and used if | no cache attributes is specified. | | IOMEM_DATA_UC_WR_COMBINE The CPU never caches the data | but writes may occur out of order | or be combined. It implies | re-ordering. | | IOMEM_DATA_UNCACHED The CPU never caches the data but | has uncacheable access to memory. | It also implies strict ordering. | | The cache attributes are mutually exclusive, and any | combination of the values leads to a failure. | On the sparc architecture, only IOMEM_DATA_CACHED is | meaningful, but others lead to a failure. waitfp The address of a function to call back later if resources are not available now. The callback function indicates how a caller wants to handle the possibility of resources not being available. If callback is set to DDI_DMA_DONTWAIT, the caller does not care if the allocation fails, and can handle an allocation failure appropriately. If call- back is set to DDI_DMA_SLEEP, the caller wishes to have the allocation routines wait for resources to become available. If any other value is set and a DMA resource allo- cation fails, this value is assumed to be the address of a function to be called when resources become available. When the speci- fied function is called, arg is passed to it as an argument. The specified callback func- tion must return either DDI_DMA_CALLBACK_RUNOUT or DDI_DMA_CALLBACK_DONE. DDI_DMA_CALLBACK_RUNOUT indicates that the callback function attempted to allocate DMA resources but failed. In this case, the callback function is put back on a list to be called again later. DDI_DMA_CALLBACK_DONE indicates that either the allocation of DMA resources was successful or the driver no longer wishes to retry. The callback func- tion is called in interrupt context. There- fore, only system functions accessible from interrupt context are available. The callback function must take whatever steps are necessary to protect its critical resources, data structures, queues, and so on. arg Argument to be passed to the callback func- tion, if such a function is specified. kaddrp On successful return, kaddrp points to the allocated memory. real_length The amount of memory, in bytes, allocated. Alignment and padding requirements may require ddi_dma_mem_alloc() to allocate more memory than requested in length. handlep Pointer to a data access handle. DESCRIPTION ddi_dma_mem_alloc() allocates memory for DMA transfers to or from a device. The allocation will obey the alignment, pad- ding constraints and device granularity as specified by the DMA attributes (see ddi_dma_attr(9S)) passed to ddi_dma_alloc_handle(9F) and the more restrictive attributes imposed by the system. flags should be set to DDI_DMA_STREAMING if the device is doing sequential, unidirectional, block-sized, and block- aligned transfers to or from memory. The alignment and pad- ding constraints specified by the minxfer and burstsizes fields in the DMA attribute structure, ddi_dma_attr(9S) (see ddi_dma_alloc_handle(9F)) will be used to allocate the most effective hardware support for large transfers. For example, if an I/O transfer can be sped up by using an I/O cache, which has a minimum transfer of one cache line, ddi_dma_mem_alloc() will align the memory at a cache line boundary and it will round up real_length to a multiple of the cache line size. flags should be set to DDI_DMA_CONSISTENT if the device accesses memory randomly, or if synchronization steps using ddi_dma_sync(9F) need to be as efficient as possible. I/O parameter blocks used for communication between a device and a driver should be allocated using DDI_DMA_CONSISTENT. The device access attributes are specified in the location pointed by the accattrp argument (see ddi_device_acc_attr(9S)). The data access handle is returned in handlep. handlep is opaque - drivers may not attempt to interpret its value. To access the data content, the driver must invoke ddi_get8(9F) or ddi_put8(9F) (depending on the data transfer direction) with the data access handle. DMA resources must be established before performing a DMA transfer by passing kaddrp and real_length as returned from ddi_dma_mem_alloc() and the flag DDI_DMA_STREAMING or DDI_DMA_CONSISTENT to ddi_dma_addr_bind_handle(9F). In addi- tion, to ensure the consistency of a memory object shared between the CPU and the device after a DMA transfer, expli- cit synchronization steps using ddi_dma_sync(9F) or ddi_dma_unbind_handle(9F) are required. RETURN VALUES ddi_dma_mem_alloc() returns: DDI_SUCCESS Memory successfully allocated. DDI_FAILURE Memory allocation failed. CONTEXT ddi_dma_mem_alloc() can be called from user or interrupt context, except when waitfp is set to DDI_DMA_SLEEP, in which case it can be called from user context only. SEE ALSO ddi_dma_addr_bind_handle(9F), ddi_dma_alloc_handle(9F), ddi_dma_mem_free(9F), ddi_dma_sync(9F), ddi_dma_unbind_handle(9F), ddi_get8(9F), ddi_put8(9F), ddi_device_acc_attr(9S), ddi_dma_attr(9S) Writing Device Drivers WARNINGS If DDI_NEVERSWAP_ACC is specified, memory can be used for any purpose; but if either endian mode is specified, you must use ddi_get/put* and never anything else. (devmap_umem_setup()) Kernel Functions for Drivers devmap_devmem_setup(9F) NAME devmap_devmem_setup, devmap_umem_setup - set driver memory mapping parameters SYNOPSIS #include #include int devmap_devmem_setup(devmap_cookie_t dhp, dev_info_t *dip, struct devmap_callback_ctl *callbackops, uint_t rnumber, offset_t roff, size_t len, uint_t maxprot, uint_t flags, ddi_device_acc_attr_t *accattrp); int devmap_umem_setup(devmap_cookie_t dhp, dev_info_t *dip, struct devmap_callback_ctl *callbackops, ddi_umem_cookie_t cookie, offset_t koff, size_t len, uint_t maxprot, uint_t flags, ddi_device_acc_attr_t *accattrp); INTERFACE LEVEL Solaris DDI specific (Solaris DDI). PARAMETERS devmap_devmem_setup() parameters: dhp An opaque mapping handle that the system uses to describe the mapping. dip Pointer to the device's dev_info structure. callbackops Pointer to a devmap_callback_ctl(9S) struc- ture. The structure contains pointers to device driver-supplied functions that manage events on the device mapping. The framework will copy the structure to the system private memory. rnumber Index number to the register address space set. roff Offset into the register address space. len Length (in bytes) of the mapping to be mapped. maxprot Maximum protection flag possible for attempted mapping. Some combinations of pos- sible settings are: PROT_READ Read access is allowed. PROT_WRITE Write access is allowed. PROT_EXEC Execute access is allowed. PROT_USER User-level access is allowed (the mapping is being done as a result of a mmap(2) system call). PROT_ALL All access is allowed. flags Must be set to 0. accattrp Pointer to a ddi_device_acc_attr(9S) struc- ture. The structure contains the device access attributes to be applied to this range of memory. devmap_umem_setup() parameters: dhp An opaque data structure that the system uses to describe the mapping. dip Pointer to the device's dev_info structure. callbackops Pointer to a devmap_callback_ctl(9S) struc- ture. The structure contains pointers to device driver-supplied functions that manage events on the device mapping. cookie A kernel memory cookie (see ddi_umem_alloc(9F)). koff Offset into the kernel memory defined by cookie. len Length (in bytes) of the mapping to be mapped. maxprot Maximum protection flag possible for attempted mapping. Some combinations of pos- sible settings are: PROT_READ Read access is allowed. PROT_WRITE Write access is allowed. PROT_EXEC Execute access is allowed. PROT_USER User-level access is allowed (the mapping is being done as a result of a mmap(2) system call). PROT_ALL All access is allowed. | flags Used to determine the cache attribute. | | Possible values of the cache attribute are: | | IOMEM_DATA_CACHED The CPU can cache the data | it fetches and push it to memory | at a later time. This is the | default attribute and used if | no cache attributes is specified. | | IOMEM_DATA_UC_WR_COMBINE The CPU never caches the data | but writes may occur out of order | or be combined. It implies | re-ordering. | | IOMEM_DATA_UNCACHED The CPU never caches the data but | has uncacheable access to memory. | It also implies strict ordering. | | The cache attributes are mutually exclusive, and any | combination of the values leads to a failure. | On the sparc architecture, only IOMEM_DATA_CACHED is | meaningful, but others lead to a failure. | accattrp Pointer to a ddi_device_acc_attr(9S) struc- | ture of this device (see ddi_device_acc_attr(9S)). | The value in devacc_attr_dataorder is ignored in | the current release. The value in | devacc_attr_endian_flags is meaningful on the sparc | architecture only. DESCRIPTION devmap_devmem_setup() and devmap_umem_setup() are used in the devmap(9E) entry point to pass mapping parameters from the driver to the system. dhp is a device mapping handle that the system uses to store all mapping parameters of a physical contiguous memory. The system copies the data pointed to by callbackops to a system private memory. This allows the driver to free the data after returning from either devmap_devmem_setup() or devmap_umem_setup(). The driver is notified of user events on the mappings via the entry points defined by devmap_callback_ctl(9S). The driver is notified of the fol- lowing user events: Mapping Setup User has called mmap(2) to create a mapping to the device memory. Access User has accessed an address in the mapping that has no translations. Duplication User has duplicated the mapping. Mappings are duplicated when the process calls fork(2). Unmapping User has called munmap(2) on the mapping or is exiting, exit(2). See devmap_map(9E), devmap_access(9E), devmap_dup(9E), and devmap_unmap(9E) for details on these entry points. By specifying a valid callbackops to the system, device drivers can manage events on a device mapping. For example, the devmap_access(9E) entry point allows the drivers to perform context switching by unloading the mappings of other processes and to load the mapping of the calling process. Device drivers may specify NULL to callbackops which means the drivers do not want to be notified by the system. The maximum protection allowed for the mapping is specified in maxprot. accattrp defines the device access attributes. See ddi_device_acc_attr(9S) for more details. devmap_devmem_setup() is used for device memory to map in the register set given by rnumber and the offset into the register address space given by roff. The system uses rnumber and roff to go up the device tree to get the physi- cal address that corresponds to roff. The range to be affected is defined by len and roff. The range from roff to roff + len must be a physical contiguous memory and page aligned. Drivers use devmap_umem_setup() for kernel memory to map in the kernel memory described by cookie and the offset into the kernel memory space given by koff. cookie is a kernel memory pointer obtained from ddi_umem_alloc(9F). If cookie is NULL, devmap_umem_setup() returns -1. The range to be affected is defined by len and koff. The range from koff to koff + len must be within the limits of the kernel memory described by koff + len and must be page aligned. Drivers use devmap_umem_setup() to export the kernel memory allocated by ddi_umem_alloc(9F) to user space. The system selects a user virtual address that is aligned with the ker- nel virtual address being mapped to avoid cache incoherence if the mapping is not MAP_FIXED. RETURN VALUES 0 Successful completion. -1 An error occurred. CONTEXT devmap_devmem_setup() and devmap_umem_setup() can be called from user, kernel, and interrupt context. SEE ALSO exit(2), fork(2), mmap(2), munmap(2), devmap(9E), ddi_umem_alloc(9F), ddi_device_acc_attr(9S), devmap_callback_ctl(9S) Writing Device Drivers