* [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management @ 2010-07-06 15:42 Zach Pfeffer 2010-07-06 15:42 ` [RFC 2/3] mm: iommu: A physical allocator for the VCMM Zach Pfeffer 2010-07-06 15:42 ` [RFC 3/3 v3] mm: iommu: The Virtual Contiguous Memory Manager Zach Pfeffer 0 siblings, 2 replies; 55+ messages in thread From: Zach Pfeffer @ 2010-07-06 15:42 UTC (permalink / raw) To: mel Cc: linux-arch, dwalker, linux-mm, linux-kernel, linux-arm-msm, linux-omap, Zach Pfeffer This patch contains the documentation for the API, termed the Virtual Contiguous Memory Manager. Its use would allow all of the IOMMU to VM, VM to device and device to IOMMU interoperation code to be refactored into platform independent code. Comments, suggestions and criticisms are welcome and wanted. Signed-off-by: Zach Pfeffer <zpfeffer@codeaurora.org> --- Documentation/vcm.txt | 587 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 587 insertions(+), 0 deletions(-) create mode 100644 Documentation/vcm.txt diff --git a/Documentation/vcm.txt b/Documentation/vcm.txt new file mode 100644 index 0000000..1c6a8be --- /dev/null +++ b/Documentation/vcm.txt @@ -0,0 +1,587 @@ +What is this document about? +============================ + +This document covers how to use the Virtual Contiguous Memory Manager +(VCMM), how the first implementation works with a specific low-level +Input/Output Memory Management Unit (IOMMU) and the way the VCMM is used +from user-space. It also contains a section that describes why something +like the VCMM is needed in the kernel. + +If anything in this document is wrong, please send patches to the +maintainer of this file, listed at the bottom of the document. + + +The Virtual Contiguous Memory Manager +===================================== + +The VCMM was built to solve the system-wide memory mapping issues that +occur when many bus-masters have IOMMUs. + +An IOMMU maps device addresses to physical addresses. It also insulates +the system from spurious or malicious device bus transactions and allows +fine-grained mapping attribute control. The Linux kernel core does not +contain a generic API to handle IOMMU mapped memory; device driver writers +must implement device specific code to interoperate with the Linux kernel +core. As the number of IOMMUs increases, coordinating the many address +spaces mapped by all discrete IOMMUs becomes difficult without in-kernel +support. + +The VCMM API enables device independent IOMMU control, virtual memory +manager (VMM) interoperation and non-IOMMU enabled device interoperation +by treating devices with or without IOMMUs and all CPUs with or without +MMUs, their mapping contexts and their mappings using common +abstractions. Physical hardware is given a generic device type and mapping +contexts are abstracted into Virtual Contiguous Memory (VCM) +regions. Users "reserve" memory from VCMs and "back" their reservations +with physical memory. + +Why the VCMM is Needed +---------------------- + +Driver writers who control devices with IOMMUs must contend with device +control and memory management. Driver writers have a large device driver +API that they can leverage to control their devices, but they are lacking +a unified API to help them program mappings into IOMMUs and share those +mappings with other devices and CPUs in the system. + +Sharing is complicated by Linux's CPU-centric VMM. The CPU-centric model +generally makes sense because average hardware only contains a MMU for the +CPU and possibly a graphics MMU. If every device in the system has one or +more MMUs the CPU-centric memory management (MM) programming model breaks +down. + +Abstracting IOMMU device programming into a common API has already begun +in the Linux kernel. It was built to abstract the difference between AMD +and Intel IOMMUs to support x86 virtualization on both platforms. The +interface is listed in include/linux/iommu.h. It contains +interfaces for mapping and unmapping as well as domain management. This +interface has not gained widespread use outside the x86; PA-RISC, Alpha +and SPARC architectures and ARM and PowerPC platforms all use their own +mapping modules to control their IOMMUs. The VCMM contains an IOMMU +programming layer, but since its abstraction supports map management +independent of device control, the layer is not used directly. This +higher-level view enables a new kernel service, not just an IOMMU +interoperation layer. + +The General Idea: Map Management using Graphs +--------------------------------------------- + +Looking at mapping from a system-wide perspective reveals a general graph +problem. The VCMM's API is built to manage the general mapping graph. Each +node that talks to memory, either through an MMU or directly (physically +mapped) can be thought of as the device-end of a mapping edge. The other +edge is the physical memory (or intermediate virtual space) that is +mapped. + +In the direct-mapped case the device is assigned a one-to-one MMU. This +scheme allows direct mapped devices to participate in general graph +management. + +The CPU nodes can also be brought under the same mapping abstraction with +the use of a light overlay on the existing VMM. This light overlay allows +VMM-managed mappings to interoperate with the common API. The light +overlay enables this without substantial modifications to the existing +VMM. + +In addition to CPU nodes that are running Linux (and the VMM), remote CPU +nodes that may be running other operating systems can be brought into the +general abstraction. Routing all memory management requests from a remote +node through the central memory management framework enables new features +like system-wide memory migration. This feature may only be feasible for +large buffers that are managed outside of the fast-path, but having remote +allocation in a system enables features that are impossible to build +without it. + +The fundamental objects that support graph-based map management are: + +1) Virtual Contiguous Memory Regions + +2) Reservations + +3) Associated Virtual Contiguous Memory Regions + +4) Memory Targets + +5) Physical Memory Allocations + +Usage Overview +-------------- + +In a nutshell, users allocate Virtual Contiguous Memory Regions and +associate those regions with one or more devices by creating an Associated +Virtual Contiguous Memory Region. Users then create Reservations from the +Virtual Contiguous Memory Region. At this point no physical memory has +been committed to the reservation. To associate physical memory with a +reservation a Physical Memory Allocation is created and the Reservation is +backed with this allocation. + +include/linux/vcm.h includes comments documenting each API. + +Virtual Contiguous Memory Regions +--------------------------------- + +A Virtual Contiguous Memory Region (VCM) abstracts the memory space a +device sees. The addresses of the region are only used by the devices +which are associated with the region. This address space would normally be +implemented as a device page table. + +A VCM is created and destroyed with three functions: + + struct vcm *vcm_create(unsigned long start_addr, unsigned long len); + + struct vcm *vcm_create_from_prebuilt(size_t ext_vcm_id); + + int vcm_free(struct vcm *vcm); + +start_addr is an offset into the address space where allocations will +start from. len is the length from start_addr of the VCM. Both functions +generate an instance of a VCM. + +ext_vcm_id is used to pass a request to the VMM to generate a VCM +instance. In the current implementation the call simply makes a note that +the VCM instance is a VMM VCM instance for other interfaces usage. This +muxing is seen throughout the implementation. + +vcm_create() and vcm_create_from_prebuilt() produce VCM instances for +virtually mapped devices (IOMMUs and CPUs). To create a one-to-one mapped +VCM, users pass the start_addr and len of the physical region. The VCMM +matches this and records that the VCM instance is a one-to-one VCM. + +The newly created VCM instance can be passed to any function that needs to +operate on or with a virtual contiguous memory region. Its main attributes +are a start_addr and a len as well as an internal setting that allows the +implementation to mux between true virtual spaces, one-to-one mapped +spaces and VMM managed spaces. + +The current implementation uses the genalloc library to manage the VCM for +IOMMU devices. Return values and more in-depth per-function documentation +for these and the ones listed below are in include/linux/vcm.h. + +Reservations +------------ + +A Reservation is a contiguous region allocated from a VCM. There is no +physical memory associated with it. + +A Reservation is created and destroyed with: + + struct res *vcm_reserve(struct vcm *vcm, size_t len, u32 attr); + + int vcm_unreserve(struct res *res); + +A vcm is a VCM created above. len is the length of the request. It can be +up to the length of the VCM region the reservation is being created +from. attr are mapping attributes: read, write, execute, user, supervisor, +secure, not-cached, write-back/write-allocate, write-back/no +write-allocate, write-through. These attrs are appropriate for ARM but can +be changed to match to any architecture. + +The implementation calls gen_pool_alloc() for IOMMU devices, +alloc_vm_area() for VMM areas and is a pass-through for one-to-one mapped +areas. + +Associated Virtual Contiguous Memory Regions and Activation +----------------------------------------------------------- + +An Associated Virtual Contiguous Memory Region (AVCM) is a mapping of a +VCM to a device. The mapping can be active or inactive. + +An AVCM is managed with: + + struct avcm *vcm_assoc(struct vcm *vcm, struct device *dev, u32 attr); + + int vcm_deassoc(struct avcm *avcm); + + int vcm_activate(struct avcm *avcm); + + int vcm_deactivate(struct avcm *avcm); + +A VCM instance is a VCM created above. A dev is an opaque device handle +thats passed down to the device driver the VCMM muxes in to handle a +request. attr are association attributes: split, use-high or +use-low. split controls which transactions hit a high-address page-table +and which transactions hit a low-address page-table. For instance, all +transactions whose most significant address bit is one would use the +high-address page-table, any other transaction would use the low address +page-table. This scheme is ARM-specific and could be changed in other +architectures. One VCM instance can be associated with many devices and +many VCM instances can be associated with one device. + +An AVCM is only a link. To program and deprogram a device with a VCM the +user calls vcm_activate() and vcm_deactivate(). For IOMMU devices, +activating a mapping programs the base address of a page table into an +IOMMU. For VMM and one-to-one based devices, mappings are active +immediately but the API does require an activation call for them for +internal reference counting. + +Memory Targets +-------------- + +A Memory Target is a platform independent way of specifying a physical +pool; it abstracts a pool of physical memory. The physical memory pool may +be physically discontiguous, need to be allocated from in a unique way or +have other user-defined attributes. + +Physical Memory Allocation and Reservation Backing +-------------------------------------------------- + +Physical memory is allocated as a separate step from reserving +memory. This allows multiple reservations to back the same physical +memory. + +A Physical Memory Allocation is managed using the following functions: + + struct physmem *vcm_phys_alloc(enum memtype_t memtype, + size_t len, u32 attr); + + int vcm_phys_free(struct physmem *physmem); + + int vcm_back(struct res *res, struct physmem *physmem); + + int vcm_unback(struct res *res); + +attr can include an alignment request, a specification to map memory using +various block sizes and/or to use physically contiguous memory. memtype is +one of the memory types listed in Memory Targets. + +The current implementation manages two pools of memory. One pool is a +contiguous block of memory and the other is a set of contiguous block +pools. In the current implementation the block pools contain 4K, 64K and +1M blocks. The physical allocator does not try to split blocks from the +contiguous block pools to satisfy requests. + +The use of 4K, 64K and 1M blocks solves a problem with some IOMMU +hardware. IOMMUs are placed in front of multimedia engines to provide a +contiguous address space to the device. Multimedia devices need large +buffers and large buffers may map to a large number of physical +blocks. IOMMUs tend to have small translation lookaside buffers +(TLBs). Since the TLB is small the number of physical blocks that map a +given range needs to be small or else the IOMMU will continually fetch new +translations during a typical streamed multimedia flow. By using a 1 MB +mapping (or 64K mapping) instead of a 4K mapping the number of misses can +be minimized, allowing the multimedia block to meet its performance goals. + +Low Level Control +----------------- + +It is necessary in some instances to access attributes and provide +higher-level control of the low-level hardware abstraction. The API +contains many members and functions for this task but the two that are +typically used are: + + res->dev_addr; + + int vcm_hook(struct device *dev, vcm_handler handler, void *data); + +res->dev_addr is the device address given a reservation. This device +address is a virtual IOMMU address for reservations on IOMMU VCMs, a +virtual VMM address for reservations on VMM VCMs and a virtual (really +physical since its one-to-one mapped) address for one-to-one devices. + +The function, vcm_hook, allows a caller in the kernel to register a +user_handler. The handler is passed the data member passed to vcm_hook +during a fault. The user can return 1 to indicate that the underlying +driver should handle the fault and retry the transaction or they can +return 0 to halt the transaction. If the user doesn't register a +handler the low-level driver will print a warning and terminate the +transaction. + +A Detailed Walk Through +----------------------- + +The following call sequence walks through a typical allocation +sequence. In the first stage the memory for a device is reserved and +backed. This occurs without mapping the memory into a VMM VCM region. The +second stage maps the first VCM region into a VMM VCM region so the kernel +can read or write it. The second stage is not necessary if the VMM does +not need to read or modify the contents of the original mapping. + + Stage 1: Map and Allocate Memory for a Device + + The call sequence starts by creating a VCM region: + + vcm = vcm_create(start_addr, len); + + The next call associates a VCM region with a device: + + avcm = vcm_assoc(vcm, dev, attr); + + To activate the association, users call vcm_activate() on the avcm from + the associate call. This programs the underlining device with the + mappings. + + ret = vcm_activate(avcm); + + Once a VCM region is created and associated it can be reserved from + with: + + res = vcm_reserve(vcm, res_len, res_attr); + + A user then allocates physical memory with: + + physmem = vcm_phys_alloc(memtype, len, phys_attr); + + To back the reservation with the physical memory allocation the user + calls: + + vcm_back(res, physmem); + + + Stage 2: Map the Device's Memory into the VMM's VCM region + + If the VMM needs to read and/or write the region that was just created, + the following calls are made. + + The first call creates a prebuilt VCM with: + + vcm_vmm = vcm_from_prebuilt(ext_vcm_id); + + The prebuilt VCM is associated with the CPU device and activated with: + + avcm_vmm = vcm_assoc(vcm_vmm, dev_cpu, attr); + vcm_activate(avcm_vmm); + + A reservation is made on the VMM VCM with: + + res_vmm = vcm_reserve(vcm_vmm, res_len, attr); + + Finally, once the topology has been set up a vcm_back() allows the VMM + to read the memory using the physmem generated in stage 1: + + vcm_back(res_vmm, physmem); + +Mapping IOMMU, one-to-one and VMM Reservations +---------------------------------------------- + +The following example demonstrates mapping IOMMU, one-to-one and VMM +reservations to the same physical memory. It shows the use of phys_addr +and phys_size to create a contiguous VCM for one-to-one mapped devices. + + The user allocates physical memory: + + physmem = vcm_phys_alloc(memtype, SZ_2MB + SZ_4K, CONTIGUOUS); + + Creates an IOMMU VCM: + + vcm_iommu = vcm_create(SZ_1K, SZ_16M); + + Creates a one-to-one VCM: + + vcm_onetoone = vcm_create(phys_addr, phys_size); + + Creates a Prebuit VCM: + + vcm_vmm = vcm_from_prebuit(ext_vcm_id); + + Associate and activate all three to their respective devices: + + avcm_iommu = vcm_assoc(vcm_iommu, dev_iommu, attr0); + avcm_onetoone = vcm_assoc(vcm_onetoone, dev_onetoone, attr1); + avcm_vmm = vcm_assoc(vcm_vmm, dev_cpu, attr2); + vcm_activate(avcm_iommu); + vcm_activate(avcm_onetoone); + vcm_activate(avcm_vmm); + + Associations that fail return 0. + + And finally, creates and backs reservations on all 3 such that they + all point to the same memory: + + res_iommu = vcm_reserve(vcm_iommu, SZ_2MB + SZ_4K, attr); + res_onetoone = vcm_reserve(vcm_onetoone, SZ_2MB + SZ_4K, attr); + res_vmm = vcm_reserve(vcm_vmm, SZ_2MB + SZ_4K, attr); + vcm_back(res_iommu, physmem); + vcm_back(res_onetoone, physmem); + vcm_back(res_vmm, physmem); + + Like associations, reservations that fail return 0. + +VCM Summary +----------- + +The VCMM is an attempt to abstract attributes of three distinct classes of +mappings into one API. The VCMM allows users to reason about mappings as +first class objects. It also allows memory mappings to flow from the +traditional 4K mappings prevalent on systems today to more efficient block +sizes. Finally, it allows users to manage mapping interoperation without +becoming VMM experts. These features will allow future systems with many +MMU mapped devices to interoperate simply and therefore correctly. + + +IOMMU Hardware Control +====================== + +The VCM currently supports a single type of IOMMU, a Qualcomm System MMU +(SMMU). The SMMU interface contains functions to map and unmap virtual +addresses, perform address translations and initialize hardware. A +Qualcomm SMMU can contain multiple MMU contexts. Each context can +translate in parallel. All contexts in a SMMU share one global translation +look-aside buffer (TLB). + +To support context muxing the SMMU module creates and manages device +independent virtual contexts. These context abstractions are bound to +actual contexts at run-time. Once bound, a context can be activated. This +activation programs the underlying context with the virtual context +affecting a context switch. + +The following functions are all documented in: + + arch/arm/mach-msm/include/mach/smmu_driver.h. + +Mapping +------- + +To map and unmap a virtual page into physical space the VCM calls: + + int smmu_map(struct smmu_dev *dev, unsigned long pa, + unsigned long va, unsigned long len, unsigned int attr); + + int smmu_unmap(struct smmu_dev *dev, unsigned long va, + unsigned long len); + + int smmu_update_start(struct smmu_dev *dev); + + int smmu_update_done(struct smmu_dev *dev); + +The size given to map must be 4K, 64K, 1M or 16M and the VA and PA must be +aligned to the given size. smmu_update_start() and smmu_update_done() +should be called before and after each map or unmap. + +Translation +----------- + +To request a hardware VA to PA translation on a single address the VCM +calls: + + unsigned long smmu_translate(struct smmu_dev *dev, + unsigned long va); + +Fault Handling +-------------- + +To register an interrupt handler for a context the VCM calls: + + int smmu_hook_interrupt(struct smmu_dev *dev, vcm_handler handler, + void *data); + +The registered interrupt handler should return 1 if it wants the SMMU +driver to retry the transaction again and 0 if it wants the SMMU driver to +terminate the transaction. + +Managing SMMU Initialization and Contexts +----------------------------------------- + +SMMU hardware initialization and management happens in 2 steps. The first +step initializes global SMMU devices and abstract device contexts. The +second step binds contexts and devices. + +An SMMU hardware instance is built with: + + int smmu_drvdata_init(struct smmu_driver *drv, unsigned long base, + int irq); + +An SMMU context is initialized and deinitialized with: + + struct smmu_dev *smmu_ctx_init(int ctx); + int smmu_ctx_deinit(struct smmu_dev *dev); + +An abstract SMMU context is bound to a particular SMMU with: + + int smmu_ctx_bind(struct smmu_dev *ctx, struct smmu_driver *drv); + +Activation +---------- + +Activation affects a context switch. + +Activation, deactivation and activation state testing are done with: + + int smmu_activate(struct smmu_dev *dev); + int smmu_deactivate(struct smmu_dev *dev); + int smmu_is_active(struct smmu_dev *dev); + + +Userspace Access to Devices with IOMMUs +======================================= + +A device that issues transactions through an IOMMU must work with two +APIs. The first API is the VCM. The VCM API is device independent. Users +pass the VCM a dev_id and the VCM makes calls on the hardware device it +has been configured with using this dev_id. The second API is whatever +device topology has been created to organize the particular IOMMUs in a +system. The only constraint on this second API is that it must give the +user a single dev_id that it can pass through the VCM. + +For the Qualcomm SMMUs the second API consists of a tree of platform +devices and two platform drivers as well as a context lookup function that +traverses the device tree and returns a dev_id given a context name. + +Qualcomm SMMU Device Tree +------------------------- + +The current tree organizes the devices into a tree that looks like the +following: + +smmu/ + smmu0/ + ctx0 + ctx1 + ctx2 + smmu1/ + ctx3 + + +Each context, ctx[n] and each smmu, smmu[n] is given a name. Since users +are interested in contexts not smmus, the context name is passed to a +function to find the dev_id associated with that name. The functions to +find, free and get the base address (since the device probe function calls +ioremap to map the SMMUs configuration registers into the kernel) are +listed here: + + struct smmu_dev *smmu_get_ctx_instance(char *ctx_name); + int smmu_free_ctx_instance(struct smmu_dev *dev); + unsigned long smmu_get_base_addr(struct smmu_dev *dev); + +Documentation for these functions is in: + + arch/arm/mach-msm/include/mach/smmu_device.h + +Each context is given a dev node named after the context. For example: + + /dev/vcodec_a_mm1 + /dev/vcodec_b_mm2 + /dev/vcodec_stream + etc... + +Users open, close and mmap these nodes to access VCM buffers from +userspace in the same way that they used to open, close and mmap /dev +nodes that represented large physically contiguous buffers (called PMEM +buffers on Android). + +Example +------- + +An abbreviated example is shown here: + +Users get the dev_id associated with their target context, create a VCM +topology appropriate for their device and finally associate the VCMs of +the topology with the contexts that will take the VCMs: + + dev_id = smmu_get_ctx_instance(vcodec_a_stream); + +create vcm and needed topology + + avcm = vcm_assoc(vcm, dev_id, attr); + +Tying it all Together +--------------------- + +VCMs, IOMMUs and the device tree all work to support system-wide memory +mappings. The use of each API in this system allows users to concentrate +on the relevant details without needing to worry about low-level +details. The API's clear separation of memory spaces and the devices that +support those memory spaces continues the Linux tradition of abstracting the +what from the how. + + +Maintainer: Zach Pfeffer <zpfeffer@codeaurora.org> -- 1.7.0.2 -- Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply related [flat|nested] 55+ messages in thread
* [RFC 2/3] mm: iommu: A physical allocator for the VCMM 2010-07-06 15:42 [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management Zach Pfeffer @ 2010-07-06 15:42 ` Zach Pfeffer 2010-07-06 15:42 ` [RFC 3/3 v3] mm: iommu: The Virtual Contiguous Memory Manager Zach Pfeffer 1 sibling, 0 replies; 55+ messages in thread From: Zach Pfeffer @ 2010-07-06 15:42 UTC (permalink / raw) To: mel Cc: linux-arch, dwalker, linux-mm, linux-kernel, linux-arm-msm, linux-omap, Zach Pfeffer The Virtual Contiguous Memory Manager (VCMM) needs a physical pool to allocate from. It breaks up the pool into sub-pools of same-sized chunks. In particular, it breaks the pool it manages into sub-pools of 1 MB, 64 KB and 4 KB chunks. When a user makes a request, this allocator satisfies that request from the sub-pools using a "maximum-munch" strategy. This strategy attempts to satisfy a request using the largest chunk-size without over-allocating, then moving on to the next smallest size without over-allocating and finally completing the request with the smallest sized chunk, over-allocating if necessary. The maximum-munch strategy allows physical page allocation for small TLBs that need to map a given range using the minimum number of mappings. Although the allocator has been configured for 1 MB, 64 KB and 4 KB chunks, it can be easily extended to other chunk sizes. Signed-off-by: Zach Pfeffer <zpfeffer@codeaurora.org> --- arch/arm/mm/vcm_alloc.c | 425 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/vcm_alloc.h | 70 ++++++++ 2 files changed, 495 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mm/vcm_alloc.c create mode 100644 include/linux/vcm_alloc.h diff --git a/arch/arm/mm/vcm_alloc.c b/arch/arm/mm/vcm_alloc.c new file mode 100644 index 0000000..e592e71 --- /dev/null +++ b/arch/arm/mm/vcm_alloc.c @@ -0,0 +1,425 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/vcm_alloc.h> +#include <linux/string.h> +#include <asm/sizes.h> + +/* Amount of memory managed by VCM */ +#define TOTAL_MEM_SIZE SZ_32M + +static unsigned int base_pa = 0x80000000; +int basicalloc_init; + +int chunk_sizes[NUM_CHUNK_SIZES] = {SZ_1M, SZ_64K, SZ_4K}; +int init_num_chunks[] = { + (TOTAL_MEM_SIZE/2) / SZ_1M, + (TOTAL_MEM_SIZE/4) / SZ_64K, + (TOTAL_MEM_SIZE/4) / SZ_4K +}; +#define LAST_SZ() (ARRAY_SIZE(chunk_sizes) - 1) + +#define vcm_alloc_err(a, ...) \ + pr_err("ERROR %s %i " a, __func__, __LINE__, ##__VA_ARGS__) + +struct phys_chunk_head { + struct list_head head; + int num; +}; + +struct phys_mem { + struct phys_chunk_head heads[ARRAY_SIZE(chunk_sizes)]; +} phys_mem; + +static int is_allocated(struct list_head *allocated) +{ + /* This should not happen under normal conditions */ + if (!allocated) { + vcm_alloc_err("no allocated\n"); + return 0; + } + + if (!basicalloc_init) { + vcm_alloc_err("no basicalloc_init\n"); + return 0; + } + return !list_empty(allocated); +} + +static int count_allocated_size(enum chunk_size_idx idx) +{ + int cnt = 0; + struct phys_chunk *chunk, *tmp; + + if (!basicalloc_init) { + vcm_alloc_err("no basicalloc_init\n"); + return 0; + } + + list_for_each_entry_safe(chunk, tmp, + &phys_mem.heads[idx].head, list) { + if (is_allocated(&chunk->allocated)) + cnt++; + } + + return cnt; +} + + +int vcm_alloc_get_mem_size(void) +{ + return TOTAL_MEM_SIZE; +} +EXPORT_SYMBOL(vcm_alloc_get_mem_size); + + +int vcm_alloc_blocks_avail(enum chunk_size_idx idx) +{ + if (!basicalloc_init) { + vcm_alloc_err("no basicalloc_init\n"); + return 0; + } + + return phys_mem.heads[idx].num; +} +EXPORT_SYMBOL(vcm_alloc_blocks_avail); + + +int vcm_alloc_get_num_chunks(void) +{ + return ARRAY_SIZE(chunk_sizes); +} +EXPORT_SYMBOL(vcm_alloc_get_num_chunks); + + +int vcm_alloc_all_blocks_avail(void) +{ + int i; + int cnt = 0; + + if (!basicalloc_init) { + vcm_alloc_err("no basicalloc_init\n"); + return 0; + } + + for (i = 0; i < ARRAY_SIZE(chunk_sizes); ++i) + cnt += vcm_alloc_blocks_avail(i); + return cnt; +} +EXPORT_SYMBOL(vcm_alloc_all_blocks_avail); + + +int vcm_alloc_count_allocated(void) +{ + int i; + int cnt = 0; + + if (!basicalloc_init) { + vcm_alloc_err("no basicalloc_init\n"); + return 0; + } + + for (i = 0; i < ARRAY_SIZE(chunk_sizes); ++i) + cnt += count_allocated_size(i); + return cnt; +} +EXPORT_SYMBOL(vcm_alloc_count_allocated); + + +void vcm_alloc_print_list(int just_allocated) +{ + int i; + struct phys_chunk *chunk, *tmp; + + if (!basicalloc_init) { + vcm_alloc_err("no basicalloc_init\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(chunk_sizes); ++i) { + if (list_empty(&phys_mem.heads[i].head)) + continue; + list_for_each_entry_safe(chunk, tmp, + &phys_mem.heads[i].head, list) { + if (just_allocated && !is_allocated(&chunk->allocated)) + continue; + + printk(KERN_INFO "pa = %#x, size = %#x\n", + chunk->pa, chunk_sizes[chunk->size_idx]); + } + } +} +EXPORT_SYMBOL(vcm_alloc_print_list); + + +int vcm_alloc_idx_to_size(int idx) +{ + return chunk_sizes[idx]; +} +EXPORT_SYMBOL(vcm_alloc_idx_to_size); + + +int vcm_alloc_destroy(void) +{ + int i; + struct phys_chunk *chunk, *tmp; + + if (!basicalloc_init) { + vcm_alloc_err("no basicalloc_init\n"); + return -1; + } + + /* can't destroy a space that has allocations */ + if (vcm_alloc_count_allocated()) { + vcm_alloc_err("allocations still present\n"); + return -1; + } + for (i = 0; i < ARRAY_SIZE(chunk_sizes); ++i) { + + if (list_empty(&phys_mem.heads[i].head)) + continue; + list_for_each_entry_safe(chunk, tmp, + &phys_mem.heads[i].head, list) { + list_del(&chunk->list); + memset(chunk, 0, sizeof(*chunk)); + kfree(chunk); + } + } + + basicalloc_init = 0; + + return 0; +} +EXPORT_SYMBOL(vcm_alloc_destroy); + + +int vcm_alloc_init(unsigned int set_base_pa) +{ + int i = 0, j = 0; + struct phys_chunk *chunk; + int pa; + + if (set_base_pa) + base_pa = set_base_pa; + + pa = base_pa; + + /* no double inits */ + if (basicalloc_init) { + vcm_alloc_err("double basicalloc_init\n"); + BUG(); + return -1; + } + + /* separate out to ensure good cleanup */ + for (i = 0; i < ARRAY_SIZE(chunk_sizes); ++i) { + INIT_LIST_HEAD(&phys_mem.heads[i].head); + phys_mem.heads[i].num = 0; + } + + for (i = 0; i < ARRAY_SIZE(chunk_sizes); ++i) { + for (j = 0; j < init_num_chunks[i]; ++j) { + chunk = kzalloc(sizeof(*chunk), GFP_KERNEL); + if (!chunk) { + vcm_alloc_err("null chunk\n"); + goto fail; + } + chunk->pa = pa; pa += chunk_sizes[i]; + chunk->size_idx = i; + INIT_LIST_HEAD(&chunk->allocated); + list_add_tail(&chunk->list, &phys_mem.heads[i].head); + phys_mem.heads[i].num++; + } + } + + basicalloc_init = 1; + return 0; +fail: + vcm_alloc_destroy(); + return -1; +} +EXPORT_SYMBOL(vcm_alloc_init); + + +int vcm_alloc_free_blocks(struct phys_chunk *alloc_head) +{ + struct phys_chunk *chunk, *tmp; + + if (!basicalloc_init) { + vcm_alloc_err("no basicalloc_init\n"); + goto fail; + } + + if (!alloc_head) { + vcm_alloc_err("no alloc_head\n"); + goto fail; + } + + list_for_each_entry_safe(chunk, tmp, &alloc_head->allocated, + allocated) { + list_del_init(&chunk->allocated); + phys_mem.heads[chunk->size_idx].num++; + } + + return 0; +fail: + return -1; +} +EXPORT_SYMBOL(vcm_alloc_free_blocks); + + +int vcm_alloc_num_blocks(int num, + enum chunk_size_idx idx, /* chunk size */ + struct phys_chunk *alloc_head) +{ + struct phys_chunk *chunk; + int num_allocated = 0; + + if (!basicalloc_init) { + vcm_alloc_err("no basicalloc_init\n"); + goto fail; + } + + if (!alloc_head) { + vcm_alloc_err("no alloc_head\n"); + goto fail; + } + + if (list_empty(&phys_mem.heads[idx].head)) { + vcm_alloc_err("list is empty\n"); + goto fail; + } + + if (vcm_alloc_blocks_avail(idx) < num) { + vcm_alloc_err("not enough blocks? num=%d\n", num); + goto fail; + } + + list_for_each_entry(chunk, &phys_mem.heads[idx].head, list) { + if (num_allocated == num) + break; + if (is_allocated(&chunk->allocated)) + continue; + + list_add_tail(&chunk->allocated, &alloc_head->allocated); + phys_mem.heads[idx].num--; + num_allocated++; + } + return num_allocated; +fail: + return 0; +} +EXPORT_SYMBOL(vcm_alloc_num_blocks); + + +int vcm_alloc_max_munch(int len, + struct phys_chunk *alloc_head) +{ + int i; + + int blocks_req = 0; + int block_residual = 0; + int blocks_allocated = 0; + + int ba = 0; + + if (!basicalloc_init) { + vcm_alloc_err("basicalloc_init is 0\n"); + goto fail; + } + + if (!alloc_head) { + vcm_alloc_err("alloc_head is NULL\n"); + goto fail; + } + + for (i = 0; i < ARRAY_SIZE(chunk_sizes); ++i) { + blocks_req = len / chunk_sizes[i]; + block_residual = len % chunk_sizes[i]; + + len = block_residual; /* len left */ + if (blocks_req) { + int blocks_available = 0; + int blocks_diff = 0; + int bytes_diff = 0; + + blocks_available = vcm_alloc_blocks_avail(i); + if (blocks_available < blocks_req) { + blocks_diff = + (blocks_req - blocks_available); + bytes_diff = + blocks_diff * chunk_sizes[i]; + + /* add back in the rest */ + len += bytes_diff; + } else { + /* got all the blocks I need */ + blocks_available = + (blocks_available > blocks_req) + ? blocks_req : blocks_available; + } + + ba = vcm_alloc_num_blocks(blocks_available, i, + alloc_head); + + if (ba != blocks_available) { + vcm_alloc_err("blocks allocated (%i) !=" + " blocks_available (%i):" + " chunk size = %#x," + " alloc_head = %p\n", + ba, blocks_available, + i, (void *) alloc_head); + goto fail; + } + blocks_allocated += blocks_available; + } + } + + if (len) { + int blocks_available = 0; + + blocks_available = vcm_alloc_blocks_avail(LAST_SZ()); + + if (blocks_available > 1) { + ba = vcm_alloc_num_blocks(1, LAST_SZ(), alloc_head); + if (ba != 1) { + vcm_alloc_err("blocks allocated (%i) !=" + " blocks_available (%i):" + " chunk size = %#x," + " alloc_head = %p\n", + ba, 1, + LAST_SZ(), + (void *) alloc_head); + goto fail; + } + blocks_allocated += 1; + } else { + vcm_alloc_err("blocks_available (%#x) <= 1\n", + blocks_available); + goto fail; + } + } + + return blocks_allocated; +fail: + vcm_alloc_free_blocks(alloc_head); + return 0; +} +EXPORT_SYMBOL(vcm_alloc_max_munch); diff --git a/include/linux/vcm_alloc.h b/include/linux/vcm_alloc.h new file mode 100644 index 0000000..e3e3b31 --- /dev/null +++ b/include/linux/vcm_alloc.h @@ -0,0 +1,70 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef VCM_ALLOC_H +#define VCM_ALLOC_H + +#include <linux/list.h> + +#define NUM_CHUNK_SIZES 3 + +enum chunk_size_idx { + IDX_1M = 0, + IDX_64K, + IDX_4K +}; + +struct phys_chunk { + struct list_head list; + struct list_head allocated; /* used to record is allocated */ + + struct list_head refers_to; + + /* TODO: change to unsigned long */ + int pa; + int size_idx; +}; + +int vcm_alloc_get_mem_size(void); +int vcm_alloc_blocks_avail(enum chunk_size_idx idx); +int vcm_alloc_get_num_chunks(void); +int vcm_alloc_all_blocks_avail(void); +int vcm_alloc_count_allocated(void); +void vcm_alloc_print_list(int just_allocated); +int vcm_alloc_idx_to_size(int idx); +int vcm_alloc_destroy(void); +int vcm_alloc_init(unsigned int set_base_pa); +int vcm_alloc_free_blocks(struct phys_chunk *alloc_head); +int vcm_alloc_num_blocks(int num, + enum chunk_size_idx idx, /* chunk size */ + struct phys_chunk *alloc_head); +int vcm_alloc_max_munch(int len, + struct phys_chunk *alloc_head); + +#endif /* VCM_ALLOC_H */ -- 1.7.0.2 -- Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply related [flat|nested] 55+ messages in thread
* [RFC 3/3 v3] mm: iommu: The Virtual Contiguous Memory Manager 2010-07-06 15:42 [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management Zach Pfeffer 2010-07-06 15:42 ` [RFC 2/3] mm: iommu: A physical allocator for the VCMM Zach Pfeffer @ 2010-07-06 15:42 ` Zach Pfeffer 1 sibling, 0 replies; 55+ messages in thread From: Zach Pfeffer @ 2010-07-06 15:42 UTC (permalink / raw) To: mel Cc: linux-arch, dwalker, linux-mm, linux-kernel, linux-arm-msm, linux-omap, Zach Pfeffer The Virtual Contiguous Memory Manager (VCMM) allows the CPU, IOMMU devices and physically mapped devices to map the same physical memory using a common API. It achieves this by abstracting mapping into graph management. Within the graph abstraction, the device end-points are CPUs with and without MMUs and devices with and without IOMMUs. The mapped memory is the other end-point. In the [IO]MMU case this is readily apparent. In the non-[IO]MMU case, it is as apparent if you give each device a "one-to-one" mapper. These mappings are wrapped up into "reservations" represented by struct res's. Also part of this graph is a mapping of a virtual space, struct vcm, to a device. One virtual space may be associated with multiple devices and multiple virtual-spaces may be associated with the same device. In the case of a one-to-one device this virtual-space mirrors the physical-space. A virtual-space is tied to a device using a "association", a struct avcm. A device may be associated with a virtual-space without being programed to translate based on that virtual-space. Programming occurs using an activate call. The physical side of the mapping (or intermediate address-space side in virtualized environments) is represented by a struct physmem. Due to the peculiar needs of various IOMMUs, the VCM contains a physical allocation subsystem that manages blocks of different sizes from different pools. This allows fine grained control of block and physical placement, a feature many advanced IOMMU devices need. Once a user has made a reservation on a VCM and allocated physical memory, the two graph end-points are joined in a backing step. This step allows multiple reservations to map the same physical location. Many of the functions in the API take various attributes that provide fine grained control of the objects they create. For instance, reservations can map cachable memory and physical allocations can be constrained to use a particular subset of block sizes. Signed-off-by: Zach Pfeffer <zpfeffer@codeaurora.org> --- arch/arm/mm/vcm.c | 1877 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/vcm.h | 661 ++++++++++++++++ include/linux/vcm_types.h | 338 ++++++++ 3 files changed, 2876 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mm/vcm.c create mode 100644 include/linux/vcm.h create mode 100644 include/linux/vcm_types.h diff --git a/arch/arm/mm/vcm.c b/arch/arm/mm/vcm.c new file mode 100644 index 0000000..2c951c3 --- /dev/null +++ b/arch/arm/mm/vcm.c @@ -0,0 +1,1877 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/vcm_mm.h> +#include <linux/vcm.h> +#include <linux/vcm_types.h> +#include <linux/errno.h> +#include <linux/spinlock.h> + +#include <asm/page.h> +#include <asm/sizes.h> + +#ifdef CONFIG_SMMU +#include <mach/smmu_driver.h> +#endif + +/* alloc_vm_area */ +#include <linux/pfn.h> +#include <linux/mm.h> +#include <linux/vmalloc.h> + +/* may be temporary */ +#include <linux/bootmem.h> + +#include <asm/cacheflush.h> +#include <asm/mach/map.h> + +#define BOOTMEM_SZ SZ_32M +#define BOOTMEM_ALIGN SZ_1M + +#define CONT_SZ SZ_8M +#define CONT_ALIGN SZ_1M + +#define ONE_TO_ONE_CHK 1 + +#define vcm_err(a, ...) \ + pr_err("ERROR %s %i " a, __func__, __LINE__, ##__VA_ARGS__) + +static void *bootmem; +static void *bootmem_cont; +static struct vcm *cont_vcm; +static struct phys_chunk *cont_phys_chunk; + +DEFINE_SPINLOCK(vcmlock); + +static int vcm_no_res(struct vcm *vcm) +{ + if (!vcm) { + vcm_err("NULL vcm\n"); + goto fail; + } + + return list_empty(&vcm->res_head); +fail: + return -EINVAL; +} + +static int vcm_no_assoc(struct vcm *vcm) +{ + if (!vcm) { + vcm_err("NULL vcm\n"); + goto fail; + } + + return list_empty(&vcm->assoc_head); +fail: + return -EINVAL; +} + +static int vcm_all_activated(struct vcm *vcm) +{ + struct avcm *avcm; + + if (!vcm) { + vcm_err("NULL vcm\n"); + goto fail; + } + + list_for_each_entry(avcm, &vcm->assoc_head, assoc_elm) + if (!avcm->is_active) + return 0; + + return 1; +fail: + return -1; +} + +static void vcm_destroy_common(struct vcm *vcm) +{ + if (!vcm) { + vcm_err("NULL vcm\n"); + return; + } + + memset(vcm, 0, sizeof(*vcm)); + kfree(vcm); +} + +static struct vcm *vcm_create_common(void) +{ + struct vcm *vcm = 0; + + vcm = kzalloc(sizeof(*vcm), GFP_KERNEL); + if (!vcm) { + vcm_err("kzalloc(%i, GFP_KERNEL) ret 0\n", + sizeof(*vcm)); + goto fail; + } + + INIT_LIST_HEAD(&vcm->res_head); + INIT_LIST_HEAD(&vcm->assoc_head); + + return vcm; + +fail: + return NULL; +} + + +static int vcm_create_pool(struct vcm *vcm, size_t start_addr, size_t len) +{ + int ret = 0; + + if (!vcm) { + vcm_err("NULL vcm\n"); + goto fail; + } + + vcm->start_addr = start_addr; + vcm->len = len; + + vcm->pool = gen_pool_create(PAGE_SHIFT, -1); + if (!vcm->pool) { + vcm_err("gen_pool_create(%x, -1) ret 0\n", PAGE_SHIFT); + goto fail; + } + + ret = gen_pool_add(vcm->pool, start_addr, len, -1); + if (ret) { + vcm_err("gen_pool_add(%p, %p, %i, -1) ret %i\n", vcm->pool, + (void *) start_addr, len, ret); + goto fail2; + } + + return 0; + +fail2: + gen_pool_destroy(vcm->pool); +fail: + return -1; +} + + +static struct vcm *vcm_create_flagged(int flag, size_t start_addr, size_t len) +{ + int ret = 0; + struct vcm *vcm = 0; + + vcm = vcm_create_common(); + if (!vcm) { + vcm_err("NULL vcm\n"); + goto fail; + } + + /* special one-to-one mapping case */ + if ((flag & ONE_TO_ONE_CHK) && + bootmem_cont && + __pa(bootmem_cont) && + start_addr == __pa(bootmem_cont) && + len == CONT_SZ) { + vcm->type = VCM_ONE_TO_ONE; + } else { + ret = vcm_create_pool(vcm, start_addr, len); + vcm->type = VCM_DEVICE; + } + + if (ret) { + vcm_err("vcm_create_pool(%p, %p, %i) ret %i\n", vcm, + (void *) start_addr, len, ret); + goto fail2; + } + + return vcm; + +fail2: + vcm_destroy_common(vcm); +fail: + return NULL; +} + +struct vcm *vcm_create(unsigned long start_addr, size_t len) +{ + unsigned long flags; + struct vcm *vcm; + + spin_lock_irqsave(&vcmlock, flags); + vcm = vcm_create_flagged(ONE_TO_ONE_CHK, start_addr, len); + spin_unlock_irqrestore(&vcmlock, flags); + return vcm; +} + + +static int ext_vcm_id_valid(size_t ext_vcm_id) +{ + return ((ext_vcm_id == VCM_PREBUILT_KERNEL) || + (ext_vcm_id == VCM_PREBUILT_USER)); +} + + +struct vcm *vcm_create_from_prebuilt(size_t ext_vcm_id) +{ + unsigned long flags; + struct vcm *vcm = 0; + + spin_lock_irqsave(&vcmlock, flags); + + if (!ext_vcm_id_valid(ext_vcm_id)) { + vcm_err("ext_vcm_id_valid(%i) ret 0\n", ext_vcm_id); + goto fail; + } + + vcm = vcm_create_common(); + if (!vcm) { + vcm_err("NULL vcm\n"); + goto fail; + } + + if (ext_vcm_id == VCM_PREBUILT_KERNEL) + vcm->type = VCM_EXT_KERNEL; + else if (ext_vcm_id == VCM_PREBUILT_USER) + vcm->type = VCM_EXT_USER; + else { + vcm_err("UNREACHABLE ext_vcm_id is illegal\n"); + goto fail_free; + } + + /* TODO: set kernel and userspace start_addr and len, if this + * makes sense */ + + spin_unlock_irqrestore(&vcmlock, flags); + return vcm; + +fail_free: + vcm_destroy_common(vcm); +fail: + spin_unlock_irqrestore(&vcmlock, flags); + return NULL; +} + + +struct vcm *vcm_clone(struct vcm *vcm) +{ + return 0; +} + + +/* No lock needed, vcm->start_addr is never updated after creation */ +size_t vcm_get_start_addr(struct vcm *vcm) +{ + if (!vcm) { + vcm_err("NULL vcm\n"); + return 1; + } + + return vcm->start_addr; +} + + +/* No lock needed, vcm->len is never updated after creation */ +size_t vcm_get_len(struct vcm *vcm) +{ + if (!vcm) { + vcm_err("NULL vcm\n"); + return 0; + } + + return vcm->len; +} + + +static int vcm_free_common_rule(struct vcm *vcm) +{ + int ret; + + if (!vcm) { + vcm_err("NULL vcm\n"); + goto fail; + } + + ret = vcm_no_res(vcm); + if (!ret) { + vcm_err("vcm_no_res(%p) ret 0\n", vcm); + goto fail_busy; + } + + if (ret == -EINVAL) { + vcm_err("vcm_no_res(%p) ret -EINVAL\n", vcm); + goto fail; + } + + ret = vcm_no_assoc(vcm); + if (!ret) { + vcm_err("vcm_no_assoc(%p) ret 0\n", vcm); + goto fail_busy; + } + + if (ret == -EINVAL) { + vcm_err("vcm_no_assoc(%p) ret -EINVAL\n", vcm); + goto fail; + } + + return 0; + +fail_busy: + return -EBUSY; +fail: + return -EINVAL; +} + + +static int vcm_free_pool_rule(struct vcm *vcm) +{ + if (!vcm) { + vcm_err("NULL vcm\n"); + goto fail; + } + + /* A vcm always has a valid pool, don't free the vcm because + what we got is probably invalid. + */ + if (!vcm->pool) { + vcm_err("NULL vcm->pool\n"); + goto fail; + } + + return 0; + +fail: + return -EINVAL; +} + + +static void vcm_free_common(struct vcm *vcm) +{ + memset(vcm, 0, sizeof(*vcm)); + + kfree(vcm); +} + + +static int vcm_free_pool(struct vcm *vcm) +{ + if (!vcm) { + vcm_err("NULL vcm\n"); + goto fail; + } + + gen_pool_destroy(vcm->pool); + + return 0; + +fail: + return -1; +} + + +static int __vcm_free(struct vcm *vcm) +{ + int ret; + + if (!vcm) { + vcm_err("NULL vcm\n"); + goto fail; + } + + ret = vcm_free_common_rule(vcm); + if (ret != 0) { + vcm_err("vcm_free_common_rule(%p) ret %i\n", vcm, ret); + goto fail; + } + + if (vcm->type == VCM_DEVICE) { + ret = vcm_free_pool_rule(vcm); + if (ret != 0) { + vcm_err("vcm_free_pool_rule(%p) ret %i\n", + (void *) vcm, ret); + goto fail; + } + + ret = vcm_free_pool(vcm); + if (ret != 0) { + vcm_err("vcm_free_pool(%p) ret %i", (void *) vcm, ret); + goto fail; + } + } + + vcm_free_common(vcm); + + return 0; + +fail: + return -EINVAL; +} + +int vcm_free(struct vcm *vcm) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&vcmlock, flags); + ret = __vcm_free(vcm); + spin_unlock_irqrestore(&vcmlock, flags); + + return ret; +} + + +static struct res *__vcm_reserve(struct vcm *vcm, size_t len, u32 attr) +{ + struct res *res = NULL; + + if (!vcm) { + vcm_err("NULL vcm\n"); + goto fail; + } + + if (len == 0) { + vcm_err("len is 0\n"); + goto fail; + } + + res = kzalloc(sizeof(*res), GFP_KERNEL); + if (!res) { + vcm_err("kzalloc(%i, GFP_KERNEL) ret 0", sizeof(*res)); + goto fail; + } + + INIT_LIST_HEAD(&res->res_elm); + res->vcm = vcm; + res->len = len; + res->attr = attr; + + if (len/SZ_1M) + res->alignment_req = SZ_1M; + else if (len/SZ_64K) + res->alignment_req = SZ_64K; + else + res->alignment_req = SZ_4K; + + res->aligned_len = res->alignment_req + len; + + switch (vcm->type) { + case VCM_DEVICE: + /* should always be not zero */ + if (!vcm->pool) { + vcm_err("NULL vcm->pool\n"); + goto fail2; + } + + res->ptr = gen_pool_alloc(vcm->pool, res->aligned_len); + if (!res->ptr) { + vcm_err("gen_pool_alloc(%p, %i) ret 0\n", + vcm->pool, res->aligned_len); + goto fail2; + } + + /* Calculate alignment... this will all change anyway */ + res->dev_addr = res->ptr + + (res->alignment_req - + (res->ptr & (res->alignment_req - 1))); + + break; + case VCM_EXT_KERNEL: + res->vm_area = alloc_vm_area(res->aligned_len); + res->mapped = 0; /* be explicit */ + if (!res->vm_area) { + vcm_err("NULL res->vm_area\n"); + goto fail2; + } + + res->dev_addr = (size_t) res->vm_area->addr + + (res->alignment_req - + ((size_t) res->vm_area->addr & + (res->alignment_req - 1))); + + break; + case VCM_ONE_TO_ONE: + break; + default: + vcm_err("%i is an invalid vcm->type\n", vcm->type); + goto fail2; + } + + list_add_tail(&res->res_elm, &vcm->res_head); + + return res; + +fail2: + kfree(res); +fail: + return 0; +} + + +struct res *vcm_reserve(struct vcm *vcm, size_t len, u32 attr) +{ + unsigned long flags; + struct res *res; + + spin_lock_irqsave(&vcmlock, flags); + res = __vcm_reserve(vcm, len, attr); + spin_unlock_irqrestore(&vcmlock, flags); + + return res; +} + + +struct res *vcm_reserve_at(enum memtarget_t memtarget, struct vcm* vcm, + size_t len, u32 attr) +{ + return 0; +} + + +/* No lock needed, res->vcm is never updated after creation */ +struct vcm *vcm_get_vcm_from_res(struct res *res) +{ + if (!res) { + vcm_err("NULL res\n"); + return 0; + } + + return res->vcm; +} + + +static int __vcm_unreserve(struct res *res) +{ + struct vcm *vcm; + + if (!res) { + vcm_err("NULL res\n"); + goto fail; + } + + if (!res->vcm) { + vcm_err("NULL res->vcm\n"); + goto fail; + } + + vcm = res->vcm; + if (!vcm) { + vcm_err("NULL vcm\n"); + goto fail; + } + + switch (vcm->type) { + case VCM_DEVICE: + if (!res->vcm->pool) { + vcm_err("NULL (res->vcm))->pool\n"); + goto fail; + } + + /* res->ptr could be zero, this isn't an error */ + gen_pool_free(res->vcm->pool, res->ptr, + res->aligned_len); + break; + case VCM_EXT_KERNEL: + if (res->mapped) { + vcm_err("res->mapped is true\n"); + goto fail; + } + + /* This may take a little explaining. + * In the kernel vunmap will free res->vm_area + * so if we've called it then we shouldn't call + * free_vm_area(). If we've called it we set + * res->vm_area to 0. + */ + if (res->vm_area) { + free_vm_area(res->vm_area); + res->vm_area = 0; + } + + break; + case VCM_ONE_TO_ONE: + break; + default: + vcm_err("%i is an invalid vcm->type\n", vcm->type); + goto fail; + } + + list_del(&res->res_elm); + + /* be extra careful by clearing the memory before freeing it */ + memset(res, 0, sizeof(*res)); + + kfree(res); + + return 0; + +fail: + return -EINVAL; +} + + +int vcm_unreserve(struct res *res) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&vcmlock, flags); + ret = __vcm_unreserve(res); + spin_unlock_irqrestore(&vcmlock, flags); + + return ret; +} + + +/* No lock needed, res->len is never updated after creation */ +size_t vcm_get_res_len(struct res *res) +{ + if (!res) { + vcm_err("res is 0\n"); + return 0; + } + + return res->len; +} + + +int vcm_set_res_attr(struct res *res, u32 attr) +{ + return 0; +} + + +size_t vcm_get_num_res(struct vcm *vcm) +{ + return 0; +} + + +struct res *vcm_get_next_res(struct vcm *vcm, struct res *res) +{ + return 0; +} + + +size_t vcm_res_copy(struct res *to, size_t to_off, struct res *from, + size_t from_off, size_t len) +{ + return 0; +} + + +size_t vcm_get_min_page_size(void) +{ + return PAGE_SIZE; +} + + +static int vcm_to_smmu_attr(u32 attr) +{ + int smmu_attr = 0; + + switch (attr & VCM_CACHE_POLICY) { + case VCM_NOTCACHED: + smmu_attr = VCM_DEV_ATTR_NONCACHED; + break; + case VCM_WB_WA: + smmu_attr = VCM_DEV_ATTR_CACHED_WB_WA; + smmu_attr |= VCM_DEV_ATTR_SH; + break; + case VCM_WB_NWA: + smmu_attr = VCM_DEV_ATTR_CACHED_WB_NWA; + smmu_attr |= VCM_DEV_ATTR_SH; + break; + case VCM_WT: + smmu_attr = VCM_DEV_ATTR_CACHED_WT; + smmu_attr |= VCM_DEV_ATTR_SH; + break; + default: + return -1; + } + + return smmu_attr; +} + + +/* TBD if you vcm_back again what happens? */ +int vcm_back(struct res *res, struct physmem *physmem) +{ + unsigned long flags; + struct vcm *vcm; + struct phys_chunk *chunk; + size_t va = 0; + int ret; + int attr; + + spin_lock_irqsave(&vcmlock, flags); + + if (!res) { + vcm_err("NULL res\n"); + goto fail; + } + + vcm = res->vcm; + if (!vcm) { + vcm_err("NULL vcm\n"); + goto fail; + } + + switch (vcm->type) { + case VCM_DEVICE: + case VCM_EXT_KERNEL: /* hack part 1 */ + attr = vcm_to_smmu_attr(res->attr); + if (attr == -1) { + vcm_err("Bad SMMU attr\n"); + goto fail; + } + break; + default: + attr = 0; + break; + } + + if (!physmem) { + vcm_err("NULL physmem\n"); + goto fail; + } + + if (res->len == 0) { + vcm_err("res->len is 0\n"); + goto fail; + } + + if (physmem->len == 0) { + vcm_err("physmem->len is 0\n"); + goto fail; + } + + if (res->len != physmem->len) { + vcm_err("res->len (%i) != physmem->len (%i)\n", + res->len, physmem->len); + goto fail; + } + + if (physmem->is_cont) { + if (physmem->res == 0) { + vcm_err("cont physmem->res is 0"); + goto fail; + } + } else { + /* fail if no physmem */ + if (list_empty(&physmem->alloc_head.allocated)) { + vcm_err("no allocated phys memory"); + goto fail; + } + } + + ret = vcm_no_assoc(res->vcm); + if (ret == 1) { + vcm_err("can't back un associated VCM\n"); + goto fail; + } + + if (ret == -1) { + vcm_err("vcm_no_assoc() ret -1\n"); + goto fail; + } + + ret = vcm_all_activated(res->vcm); + if (ret == 0) { + vcm_err("can't back, not all associations are activated\n"); + goto fail_eagain; + } + + if (ret == -1) { + vcm_err("vcm_all_activated() ret -1\n"); + goto fail; + } + + va = res->dev_addr; + + list_for_each_entry(chunk, &physmem->alloc_head.allocated, + allocated) { + struct vcm *vcm = res->vcm; + size_t chunk_size = vcm_alloc_idx_to_size(chunk->size_idx); + + switch (vcm->type) { + case VCM_DEVICE: + { +#ifdef CONFIG_SMMU + struct avcm *avcm; + /* map all */ + list_for_each_entry(avcm, &vcm->assoc_head, + assoc_elm) { + + ret = smmu_map( + (struct smmu_dev *) avcm->dev, + chunk->pa, va, chunk_size, attr); + if (ret != 0) { + vcm_err("smmu_map(%p, %p, %p, 0x%x," + "0x%x)" + " ret %i", + (void *) avcm->dev, + (void *) chunk->pa, + (void *) va, + (int) chunk_size, attr, ret); + goto fail; + /* TODO handle weird inter-map case */ + } + } + break; +#else + vcm_err("No SMMU support - VCM_DEVICE not supported\n"); + goto fail; +#endif + } + + case VCM_EXT_KERNEL: + { + unsigned int pages_in_chunk = chunk_size / PAGE_SIZE; + unsigned long loc_va = va; + unsigned long loc_pa = chunk->pa; + + const struct mem_type *mtype; + + /* TODO: get this based on MEMTYPE */ + mtype = get_mem_type(MT_DEVICE); + if (!mtype) { + vcm_err("mtype is 0\n"); + goto fail; + } + + /* TODO: Map with the same chunk size */ + while (pages_in_chunk--) { + ret = ioremap_page(loc_va, + loc_pa, + mtype); + if (ret != 0) { + vcm_err("ioremap_page(%p, %p, %p) ret" + " %i", (void *) loc_va, + (void *) loc_pa, + (void *) mtype, ret); + goto fail; + /* TODO handle weird + inter-map case */ + } + + /* hack part 2 */ + /* we're changing the PT entry behind + * linux's back + */ + ret = cpu_set_attr(loc_va, PAGE_SIZE, attr); + if (ret != 0) { + vcm_err("cpu_set_attr(%p, %lu, %x)" + "ret %i\n", + (void *) loc_va, PAGE_SIZE, + attr, ret); + goto fail; + /* TODO handle weird + inter-map case */ + } + + res->mapped = 1; + + loc_va += PAGE_SIZE; + loc_pa += PAGE_SIZE; + } + + flush_cache_vmap(va, loc_va); + break; + } + case VCM_ONE_TO_ONE: + va = chunk->pa; + break; + default: + /* this should never happen */ + goto fail; + } + + va += chunk_size; + /* also add res to the allocated chunk list of refs */ + } + + /* note the reservation */ + res->physmem = physmem; + + spin_unlock_irqrestore(&vcmlock, flags); + return 0; +fail_eagain: + spin_unlock_irqrestore(&vcmlock, flags); + return -EAGAIN; +fail: + spin_unlock_irqrestore(&vcmlock, flags); + return -EINVAL; +} + + +int vcm_unback(struct res *res) +{ + unsigned long flags; + struct vcm *vcm; + struct physmem *physmem; + int ret; + + spin_lock_irqsave(&vcmlock, flags); + + if (!res) + goto fail; + + vcm = res->vcm; + if (!vcm) { + vcm_err("NULL vcm\n"); + goto fail; + } + + if (!res->physmem) { + vcm_err("can't unback a non-backed reservation\n"); + goto fail; + } + + physmem = res->physmem; + if (!physmem) { + vcm_err("physmem is NULL\n"); + goto fail; + } + + if (list_empty(&physmem->alloc_head.allocated)) { + vcm_err("physmem allocation is empty\n"); + goto fail; + } + + ret = vcm_no_assoc(res->vcm); + if (ret == 1) { + vcm_err("can't unback a unassociated reservation\n"); + goto fail; + } + + if (ret == -1) { + vcm_err("vcm_no_assoc(%p) ret -1\n", (void *) res->vcm); + goto fail; + } + + ret = vcm_all_activated(res->vcm); + if (ret == 0) { + vcm_err("can't unback, not all associations are active\n"); + goto fail_eagain; + } + + if (ret == -1) { + vcm_err("vcm_all_activated(%p) ret -1\n", (void *) res->vcm); + goto fail; + } + + + switch (vcm->type) { + case VCM_EXT_KERNEL: + if (!res->mapped) { + vcm_err("can't unback an unmapped VCM_EXT_KERNEL" + " VCM\n"); + goto fail; + } + + /* vunmap free's vm_area */ + vunmap(res->vm_area->addr); + res->vm_area = 0; + + res->mapped = 0; + break; + + case VCM_DEVICE: + { +#ifdef CONFIG_SMMU + struct phys_chunk *chunk; + size_t va = res->dev_addr; + + list_for_each_entry(chunk, &physmem->alloc_head.allocated, + allocated) { + struct vcm *vcm = res->vcm; + size_t chunk_size = + vcm_alloc_idx_to_size(chunk->size_idx); + struct avcm *avcm; + + /* un map all */ + list_for_each_entry(avcm, &vcm->assoc_head, assoc_elm) { + ret = smmu_unmap( + (struct smmu_dev *) avcm->dev, + va, chunk_size); + if (ret != 0) { + vcm_err("smmu_unmap(%p, %p, 0x%x)" + " ret %i", + (void *) avcm->dev, + (void *) va, + (int) chunk_size, ret); + goto fail; + /* TODO handle weird inter-unmap state*/ + } + } + va += chunk_size; + /* may to a light unback, depending on the requested + * functionality + */ + } +#else + vcm_err("No SMMU support - VCM_DEVICE memory not supported\n"); + goto fail; +#endif + break; + } + + case VCM_ONE_TO_ONE: + break; + default: + /* this should never happen */ + goto fail; + } + + /* clear the reservation */ + res->physmem = 0; + + spin_unlock_irqrestore(&vcmlock, flags); + return 0; +fail_eagain: + spin_unlock_irqrestore(&vcmlock, flags); + return -EAGAIN; +fail: + spin_unlock_irqrestore(&vcmlock, flags); + return -EINVAL; +} + + +enum memtarget_t vcm_get_memtype_of_res(struct res *res) +{ + return VCM_INVALID; +} + +static int vcm_free_max_munch_cont(struct phys_chunk *head) +{ + struct phys_chunk *chunk, *tmp; + + if (!head) + return -1; + + list_for_each_entry_safe(chunk, tmp, &head->allocated, + allocated) { + list_del_init(&chunk->allocated); + } + + return 0; +} + +static int vcm_alloc_max_munch_cont(size_t start_addr, size_t len, + struct phys_chunk *head) +{ + /* this function should always succeed, since it + parallels a VCM */ + + int i, j; + + if (!head) { + vcm_err("head is NULL in continuous map.\n"); + goto fail; + } + + if (start_addr < __pa(bootmem_cont)) { + vcm_err("phys start addr (%p) < base (%p)\n", + (void *) start_addr, (void *) __pa(bootmem_cont)); + goto fail; + } + + if ((start_addr + len) >= (__pa(bootmem_cont) + CONT_SZ)) { + vcm_err("requested region (%p + %i) > " + " available region (%p + %i)", + (void *) start_addr, (int) len, + (void *) __pa(bootmem_cont), CONT_SZ); + goto fail; + } + + i = (start_addr - __pa(bootmem_cont))/SZ_4K; + + for (j = 0; j < ARRAY_SIZE(chunk_sizes); ++j) { + while (len/chunk_sizes[j]) { + if (!list_empty(&cont_phys_chunk[i].allocated)) { + vcm_err("chunk %i ( addr %p) already mapped\n", + i, (void *) (start_addr + + (i*chunk_sizes[j]))); + goto fail_free; + } + list_add_tail(&cont_phys_chunk[i].allocated, + &head->allocated); + cont_phys_chunk[i].size_idx = j; + + len -= chunk_sizes[j]; + i += chunk_sizes[j]/SZ_4K; + } + } + + if (len % SZ_4K) { + if (!list_empty(&cont_phys_chunk[i].allocated)) { + vcm_err("chunk %i (addr %p) already mapped\n", + i, (void *) (start_addr + (i*SZ_4K))); + goto fail_free; + } + len -= SZ_4K; + list_add_tail(&cont_phys_chunk[i].allocated, + &head->allocated); + + i++; + } + + return i; + +fail_free: + { + struct phys_chunk *chunk, *tmp; + /* just remove from list, if we're double alloc'ing + we don't want to stamp on the other guy */ + list_for_each_entry_safe(chunk, tmp, &head->allocated, + allocated) { + list_del(&chunk->allocated); + } + } +fail: + return 0; +} + +struct physmem *vcm_phys_alloc(enum memtype_t memtype, size_t len, + u32 attr) +{ + unsigned long flags; + int ret; + struct physmem *physmem = NULL; + int blocks_allocated; + + spin_lock_irqsave(&vcmlock, flags); + + physmem = kzalloc(sizeof(*physmem), GFP_KERNEL); + if (!physmem) { + vcm_err("physmem is NULL\n"); + goto fail; + } + + physmem->memtype = memtype; + physmem->len = len; + physmem->attr = attr; + + INIT_LIST_HEAD(&physmem->alloc_head.allocated); + + if (attr & VCM_PHYS_CONT) { + if (!cont_vcm) { + vcm_err("cont_vcm is NULL\n"); + goto fail2; + } + + physmem->is_cont = 1; + + /* TODO: get attributes */ + physmem->res = __vcm_reserve(cont_vcm, len, 0); + if (physmem->res == 0) { + vcm_err("contiguous space allocation failed\n"); + goto fail2; + } + + /* if we're here we know we have memory, create + the shadow physmem links*/ + blocks_allocated = + vcm_alloc_max_munch_cont( + physmem->res->dev_addr, + len, + &physmem->alloc_head); + + if (blocks_allocated == 0) { + vcm_err("shadow physmem allocation failed\n"); + goto fail3; + } + } else { + blocks_allocated = vcm_alloc_max_munch(len, + &physmem->alloc_head); + if (blocks_allocated == 0) { + vcm_err("physical allocation failed:" + " vcm_alloc_max_munch(%i, %p) ret 0\n", + len, &physmem->alloc_head); + goto fail2; + } + } + + spin_unlock_irqrestore(&vcmlock, flags); + return physmem; + +fail3: + ret = __vcm_unreserve(physmem->res); + if (ret != 0) { + vcm_err("vcm_unreserve(%p) ret %i during cleanup", + (void *) physmem->res, ret); + spin_unlock_irqrestore(&vcmlock, flags); + return 0; + } +fail2: + kfree(physmem); +fail: + spin_unlock_irqrestore(&vcmlock, flags); + return 0; +} + + +int vcm_phys_free(struct physmem *physmem) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&vcmlock, flags); + + if (!physmem) { + vcm_err("physmem is NULL\n"); + goto fail; + } + + if (physmem->is_cont) { + if (physmem->res == 0) { + vcm_err("contiguous reservation is NULL\n"); + goto fail; + } + + ret = vcm_free_max_munch_cont(&physmem->alloc_head); + if (ret != 0) { + vcm_err("failed to free physical blocks:" + " vcm_free_max_munch_cont(%p) ret %i\n", + (void *) &physmem->alloc_head, ret); + goto fail; + } + + ret = __vcm_unreserve(physmem->res); + if (ret != 0) { + vcm_err("failed to free virtual blocks:" + " vcm_unreserve(%p) ret %i\n", + (void *) physmem->res, ret); + goto fail; + } + + } else { + + ret = vcm_alloc_free_blocks(&physmem->alloc_head); + if (ret != 0) { + vcm_err("failed to free physical blocks:" + " vcm_alloc_free_blocks(%p) ret %i\n", + (void *) &physmem->alloc_head, ret); + goto fail; + } + } + + memset(physmem, 0, sizeof(*physmem)); + + kfree(physmem); + + spin_unlock_irqrestore(&vcmlock, flags); + return 0; + +fail: + spin_unlock_irqrestore(&vcmlock, flags); + return -EINVAL; +} + + +struct avcm *vcm_assoc(struct vcm *vcm, struct device *dev, u32 attr) +{ + unsigned long flags; + struct avcm *avcm = NULL; + + spin_lock_irqsave(&vcmlock, flags); + + if (!vcm) { + vcm_err("vcm is NULL\n"); + goto fail; + } + + if (!dev) { + vcm_err("dev is NULL\n"); + goto fail; + } + + if (vcm->type == VCM_EXT_KERNEL && !list_empty(&vcm->assoc_head)) { + vcm_err("only one device may be assocoated with a" + " VCM_EXT_KERNEL\n"); + goto fail; + } + + avcm = kzalloc(sizeof(*avcm), GFP_KERNEL); + if (!avcm) { + vcm_err("kzalloc(%i, GFP_KERNEL) ret NULL\n", sizeof(*avcm)); + goto fail; + } + + avcm->dev = dev; + + avcm->vcm = vcm; + avcm->attr = attr; + avcm->is_active = 0; + + INIT_LIST_HEAD(&avcm->assoc_elm); + list_add(&avcm->assoc_elm, &vcm->assoc_head); + + spin_unlock_irqrestore(&vcmlock, flags); + return avcm; + +fail: + spin_unlock_irqrestore(&vcmlock, flags); + return 0; +} + + +int vcm_deassoc(struct avcm *avcm) +{ + unsigned long flags; + + spin_lock_irqsave(&vcmlock, flags); + + if (!avcm) { + vcm_err("avcm is NULL\n"); + goto fail; + } + + if (list_empty(&avcm->assoc_elm)) { + vcm_err("nothing to deassociate\n"); + goto fail; + } + + if (avcm->is_active) { + vcm_err("association still activated\n"); + goto fail_busy; + } + + list_del(&avcm->assoc_elm); + + memset(avcm, 0, sizeof(*avcm)); + + kfree(avcm); + spin_unlock_irqrestore(&vcmlock, flags); + return 0; +fail_busy: + spin_unlock_irqrestore(&vcmlock, flags); + return -EBUSY; +fail: + spin_unlock_irqrestore(&vcmlock, flags); + return -EINVAL; +} + + +int vcm_set_assoc_attr(struct avcm *avcm, u32 attr) +{ + return 0; +} + + +int vcm_activate(struct avcm *avcm) +{ + unsigned long flags; + struct vcm *vcm; + + spin_lock_irqsave(&vcmlock, flags); + + if (!avcm) { + vcm_err("avcm is NULL\n"); + goto fail; + } + + vcm = avcm->vcm; + if (!vcm) { + vcm_err("NULL vcm\n"); + goto fail; + } + + if (!avcm->dev) { + vcm_err("cannot activate without a device\n"); + goto fail_nodev; + } + + if (avcm->is_active) { + vcm_err("double activate\n"); + goto fail_busy; + } + + if (vcm->type == VCM_DEVICE) { +#ifdef CONFIG_SMMU + int ret = smmu_is_active((struct smmu_dev *) avcm->dev); + if (ret == -1) { + vcm_err("smmu_is_active(%p) ret -1\n", + (void *) avcm->dev); + goto fail_dev; + } + + if (ret == 1) { + vcm_err("SMMU is already active\n"); + goto fail_busy; + } + + /* TODO, pmem check */ + ret = smmu_activate((struct smmu_dev *) avcm->dev); + if (ret != 0) { + vcm_err("smmu_activate(%p) ret %i" + " SMMU failed to activate\n", + (void *) avcm->dev, ret); + goto fail_dev; + } +#else + vcm_err("No SMMU support - cannot activate/deactivate\n"); + goto fail_nodev; +#endif + } + + avcm->is_active = 1; + spin_unlock_irqrestore(&vcmlock, flags); + return 0; + +#ifdef CONFIG_SMMU +fail_dev: + spin_unlock_irqrestore(&vcmlock, flags); + return -1; +#endif +fail_busy: + spin_unlock_irqrestore(&vcmlock, flags); + return -EBUSY; +fail_nodev: + spin_unlock_irqrestore(&vcmlock, flags); + return -ENODEV; +fail: + spin_unlock_irqrestore(&vcmlock, flags); + return -EINVAL; +} + + +int vcm_deactivate(struct avcm *avcm) +{ + unsigned long flags; + struct vcm *vcm; + + spin_lock_irqsave(&vcmlock, flags); + + if (!avcm) + goto fail; + + vcm = avcm->vcm; + if (!vcm) { + vcm_err("NULL vcm\n"); + goto fail; + } + + if (!avcm->dev) { + vcm_err("cannot deactivate without a device\n"); + goto fail; + } + + if (!avcm->is_active) { + vcm_err("double deactivate\n"); + goto fail_nobusy; + } + + if (vcm->type == VCM_DEVICE) { +#ifdef CONFIG_SMMU + int ret = smmu_is_active((struct smmu_dev *) avcm->dev); + if (ret == -1) { + vcm_err("smmu_is_active(%p) ret %i\n", + (void *) avcm->dev, ret); + goto fail_dev; + } + + if (ret == 0) { + vcm_err("double SMMU deactivation\n"); + goto fail_nobusy; + } + + /* TODO, pmem check */ + ret = smmu_deactivate((struct smmu_dev *) avcm->dev); + if (ret != 0) { + vcm_err("smmu_deactivate(%p) ret %i\n", + (void *) avcm->dev, ret); + goto fail_dev; + } +#else + vcm_err("No SMMU support - cannot activate/deactivate\n"); + goto fail; +#endif + } + + avcm->is_active = 0; + spin_unlock_irqrestore(&vcmlock, flags); + return 0; +#ifdef CONFIG_SMMU +fail_dev: + spin_unlock_irqrestore(&vcmlock, flags); + return -1; +#endif +fail_nobusy: + spin_unlock_irqrestore(&vcmlock, flags); + return -ENOENT; +fail: + spin_unlock_irqrestore(&vcmlock, flags); + return -EINVAL; +} + +struct bound *vcm_create_bound(struct vcm *vcm, size_t len) +{ + return 0; +} + + +int vcm_free_bound(struct bound *bound) +{ + return -1; +} + + +struct res *vcm_reserve_from_bound(struct bound *bound, size_t len, + u32 attr) +{ + return 0; +} + + +size_t vcm_get_bound_start_addr(struct bound *bound) +{ + return 0; +} + + +size_t vcm_get_bound_len(struct bound *bound) +{ + return 0; +} + + +struct physmem *vcm_map_phys_addr(size_t phys, size_t len) +{ + return 0; +} + + +size_t vcm_get_next_phys_addr(struct physmem *physmem, size_t phys, size_t *len) +{ + return 0; +} + +struct res *vcm_get_res(unsigned long dev_addr, struct vcm *vcm) +{ + return 0; +} + + +size_t vcm_translate(size_t src_dev, struct vcm *src_vcm, struct vcm *dst_vcm) +{ + return 0; +} + + +size_t vcm_get_phys_num_res(size_t phys) +{ + return 0; +} + + +struct res *vcm_get_next_phys_res(size_t phys, struct res *res, size_t *len) +{ + return 0; +} + + +size_t vcm_get_pgtbl_pa(struct vcm *vcm) +{ + return 0; +} + + +/* No lock needed, smmu_translate has its own lock */ +size_t vcm_dev_addr_to_phys_addr(struct device *dev, unsigned long dev_addr) +{ +#ifdef CONFIG_SMMU + int ret; + ret = smmu_translate((struct smmu_dev *) dev, dev_addr); + if (ret == -1) + vcm_err("smmu_translate(%p, %p) ret %i\n", + (void *) dev, (void *) dev_addr, ret); + + return ret; +#else + vcm_err("No support for SMMU - manual translation not supported\n"); + return -1; +#endif +} + + +/* No lock needed, bootmem_cont never changes after */ +size_t vcm_get_cont_memtype_pa(enum memtype_t memtype) +{ + if (memtype != VCM_MEMTYPE_0) { + vcm_err("memtype != VCM_MEMTYPE_0\n"); + goto fail; + } + + if (!bootmem_cont) { + vcm_err("bootmem_cont 0\n"); + goto fail; + } + + return (size_t) __pa(bootmem_cont); +fail: + return 0; +} + + +/* No lock needed, constant */ +size_t vcm_get_cont_memtype_len(enum memtype_t memtype) +{ + if (memtype != VCM_MEMTYPE_0) { + vcm_err("memtype != VCM_MEMTYPE_0\n"); + return 0; + } + + return CONT_SZ; +} + +int vcm_hook(struct device *dev, vcm_handler handler, void *data) +{ +#ifdef CONFIG_SMMU + int ret; + + ret = smmu_hook_irpt((struct smmu_dev *) dev, handler, data); + if (ret != 0) + vcm_err("smmu_hook_irpt(%p, %p, %p) ret %i\n", (void *) dev, + (void *) handler, (void *) data, ret); + + return ret; +#else + vcm_err("No support for SMMU - interrupts not supported\n"); + return -1; +#endif +} + + +size_t vcm_hw_ver(struct device *dev) +{ + return 0; +} + + +static int vcm_cont_phys_chunk_init(void) +{ + int i; + int cont_pa; + + if (!cont_phys_chunk) { + vcm_err("cont_phys_chunk 0\n"); + goto fail; + } + + if (!bootmem_cont) { + vcm_err("bootmem_cont 0\n"); + goto fail; + } + + cont_pa = (int) __pa(bootmem_cont); + + for (i = 0; i < CONT_SZ/PAGE_SIZE; ++i) { + cont_phys_chunk[i].pa = (int) cont_pa; cont_pa += PAGE_SIZE; + cont_phys_chunk[i].size_idx = IDX_4K; + INIT_LIST_HEAD(&cont_phys_chunk[i].allocated); + } + + return 0; + +fail: + return -1; +} + + +int vcm_sys_init(void) +{ + int ret; + printk(KERN_INFO "VCM Initialization\n"); + if (!bootmem) { + vcm_err("bootmem is 0\n"); + ret = -1; + goto fail; + } + + if (!bootmem_cont) { + vcm_err("bootmem_cont is 0\n"); + ret = -1; + goto fail; + } + + ret = vcm_setup_tex_classes(); + if (ret != 0) { + printk(KERN_INFO "Could not determine TEX attribute mapping\n"); + ret = -1; + goto fail; + } + + + ret = vcm_alloc_init(__pa(bootmem)); + if (ret != 0) { + vcm_err("vcm_alloc_init(%p) ret %i\n", (void *) __pa(bootmem), + ret); + ret = -1; + goto fail; + } + + cont_phys_chunk = kzalloc(sizeof(*cont_phys_chunk)*(CONT_SZ/PAGE_SIZE), + GFP_KERNEL); + if (!cont_phys_chunk) { + vcm_err("kzalloc(%lu, GFP_KERNEL) ret 0", + sizeof(*cont_phys_chunk)*(CONT_SZ/PAGE_SIZE)); + goto fail_free; + } + + /* the address and size will hit our special case unless we + pass an override */ + cont_vcm = vcm_create_flagged(0, __pa(bootmem_cont), CONT_SZ); + if (cont_vcm == 0) { + vcm_err("vcm_create_flagged(0, %p, %i) ret 0\n", + (void *) __pa(bootmem_cont), CONT_SZ); + ret = -1; + goto fail_free2; + } + + ret = vcm_cont_phys_chunk_init(); + if (ret != 0) { + vcm_err("vcm_cont_phys_chunk_init() ret %i\n", ret); + goto fail_free3; + } + + printk(KERN_INFO "VCM Initialization OK\n"); + return 0; + +fail_free3: + ret = __vcm_free(cont_vcm); + if (ret != 0) { + vcm_err("vcm_free(%p) ret %i during failure path\n", + (void *) cont_vcm, ret); + return -1; + } + +fail_free2: + kfree(cont_phys_chunk); + cont_phys_chunk = 0; + +fail_free: + ret = vcm_alloc_destroy(); + if (ret != 0) + vcm_err("vcm_alloc_destroy() ret %i during failure path\n", + ret); + + ret = -1; +fail: + return ret; +} + + +int vcm_sys_destroy(void) +{ + int ret = 0; + + if (!cont_phys_chunk) { + vcm_err("cont_phys_chunk is 0\n"); + return -1; + } + + if (!cont_vcm) { + vcm_err("cont_vcm is 0\n"); + return -1; + } + + ret = __vcm_free(cont_vcm); + if (ret != 0) { + vcm_err("vcm_free(%p) ret %i\n", (void *) cont_vcm, ret); + return -1; + } + + cont_vcm = 0; + + kfree(cont_phys_chunk); + cont_phys_chunk = 0; + + ret = vcm_alloc_destroy(); + if (ret != 0) { + vcm_err("vcm_alloc_destroy() ret %i\n", ret); + return -1; + } + + return ret; +} + +int vcm_init(void) +{ + int ret; + + bootmem = __alloc_bootmem(BOOTMEM_SZ, BOOTMEM_ALIGN, 0); + if (!bootmem) { + vcm_err("segregated block pool alloc failed:" + " __alloc_bootmem(%i, %i, 0)\n", + BOOTMEM_SZ, BOOTMEM_ALIGN); + goto fail; + } + + bootmem_cont = __alloc_bootmem(CONT_SZ, CONT_ALIGN, 0); + if (!bootmem_cont) { + vcm_err("contiguous pool alloc failed:" + " __alloc_bootmem(%i, %i, 0)\n", + CONT_SZ, CONT_ALIGN); + goto fail_free; + } + + ret = vcm_sys_init(); + if (ret != 0) { + vcm_err("vcm_sys_init() ret %i\n", ret); + goto fail_free2; + } + + return 0; + +fail_free2: + free_bootmem(__pa(bootmem_cont), CONT_SZ); +fail_free: + free_bootmem(__pa(bootmem), BOOTMEM_SZ); +fail: + return -1; +}; + +/* Useful for testing, and if VCM is ever unloaded */ +void vcm_exit(void) +{ + int ret; + + if (!bootmem_cont) { + vcm_err("bootmem_cont is 0\n"); + goto fail; + } + + if (!bootmem) { + vcm_err("bootmem is 0\n"); + goto fail; + } + + ret = vcm_sys_destroy(); + if (ret != 0) { + vcm_err("vcm_sys_destroy() ret %i\n", ret); + goto fail; + } + + free_bootmem(__pa(bootmem_cont), CONT_SZ); + free_bootmem(__pa(bootmem), BOOTMEM_SZ); +fail: + return; +} +early_initcall(vcm_init); +module_exit(vcm_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Zach Pfeffer <zpfeffer@codeaurora.org>"); diff --git a/include/linux/vcm.h b/include/linux/vcm.h new file mode 100644 index 0000000..b95dab5 --- /dev/null +++ b/include/linux/vcm.h @@ -0,0 +1,661 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#ifndef _VCM_H_ +#define _VCM_H_ + + +/* All undefined types must be defined using platform specific headers */ + +#include <linux/vcm_types.h> + + +/* + * Virtual contiguous memory (VCM) region primitives. + * + * Current memory mapping software uses a CPU centric management + * model. This makes sense in general, average hardware only contains an + * CPU MMU and possibly a graphics MMU. If every device in the system + * has one or more MMUs a CPU centric MM programming model breaks down. + * + * Looking at mapping from a system-wide perspective reveals a general + * graph problem. Each node that talks to memory, either through an MMU + * or directly (via physical memory) can be thought of as the device end + * of a mapping edge. The other edge is the physical memory that is + * mapped. + * + * In the direct mapped case, it is useful to give the device an + * MMU. This one-to-one MMU allows direct mapped devices to + * participate in graph management, they simply see memory through a + * one-to-one mapping. + * + * The CPU nodes can also be brought under the same mapping + * abstraction with the use of a light overlay on the existing + * VMM. This light overlay brings the VMM's page table abstraction for + * each process and the kernel into the graph management API. + * + * Taken together this system wide approach provides a capability that + * is greater than the sum of its parts by allowing users to reason + * about system wide mapping issues without getting bogged down in CPU + * centric device page table management issues. + */ + + +/* + * Creating, freeing and managing VCMs. + * + * A VCM region is a virtual space that can be reserved from and + * associated with one or more devices. At creation the user can + * specify an offset to start addresses and a length of the entire VCM + * region. Reservations out of a VCM region are always contiguous. + */ + + +/** + * vcm_create() - Create a VCM region + * @start_addr: The starting address of the VCM region. + * @len: The len of the VCM region. This must be at least + * vcm_get_min_page_size() bytes. + * + * A VCM typically abstracts a page table. + * + * All functions in this API are passed and return opaque things + * because the underlying implementations will vary. The goal + * is really graph management. vcm_create() creates the "device end" + * of an edge in the mapping graph. + * + * The return value is non-zero if a VCM has successfully been + * created. It will return zero if a VCM region cannot be created or + * len is invalid. + */ +struct vcm *vcm_create(unsigned long start_addr, size_t len); + + +/** + * vcm_create_from_prebuilt() - Create a VCM region from an existing region + * @ext_vcm_id: An external opaque value that allows the + * implementation to reference an already built table. + * + * The ext_vcm_id will probably reference a page table that's been built + * by the VM. + * + * The platform specific implementation will provide this. + * + * The return value is non-zero if a VCM has successfully been created. + */ +struct vcm *vcm_create_from_prebuilt(size_t ext_vcm_id); + + +/** + * vcm_clone() - Clone a VCM + * @vcm: A VCM to clone from. + * + * Perform a VCM "deep copy." The resulting VCM will match the original at + * the point of cloning. Subsequent updates to either VCM will only be + * seen by that VCM. + * + * The return value is non-zero if a VCM has been successfully cloned. + */ +struct vcm *vcm_clone(struct vcm *vcm); + + +/** + * vcm_get_start_addr() - Get the starting address of the VCM region. + * @vcm: The VCM we're interested in getting the starting + * address of. + * + * The return value will be 1 if an error has occurred. + */ +size_t vcm_get_start_addr(struct vcm *vcm); + + +/** + * vcm_get_len() - Get the length of the VCM region. + * @vcm: The VCM we're interested in reading the length from. + * + * The return value will be non-zero for a valid VCM. VCM regions + * cannot have 0 len. + */ +size_t vcm_get_len(struct vcm *vcm); + + +/** + * vcm_free() - Free a VCM. + * @vcm: The VCM we're interested in freeing. + * + * The return value is 0 if the VCM has been freed or: + * -EBUSY The VCM region contains reservations or has been + * associated (active or not) and cannot be freed. + * -EINVAL The vcm argument is invalid. + */ +int vcm_free(struct vcm *vcm); + + +/* + * Creating, freeing and managing reservations out of a VCM. + * + */ + +/** + * vcm_reserve() - Create a reservation from a VCM region. + * @vcm: The VCM region to reserve from. + * @len: The length of the reservation. Must be at least + * vcm_get_min_page_size() bytes. + * @attr: See 'Reservation Attributes'. + * + * A reservation, res_t, is a contiguous range from a VCM region. + * + * The return value is non-zero if a reservation has been successfully + * created. It is 0 if any of the parameters are invalid. + */ +struct res *vcm_reserve(struct vcm *vcm, size_t len, u32 attr); + + +/** + * vcm_reserve_at() - Make a reservation at a given logical location. + * @memtarget: A logical location to start the reservation from. + * @vcm: The VCM region to start the reservation from. + * @len: The length of the reservation. + * @attr: See 'Reservation Attributes'. + * + * The return value is non-zero if a reservation has been successfully + * created. + */ +struct res *vcm_reserve_at(enum memtarget_t memtarget, struct vcm *vcm, + size_t len, u32 attr); + + +/** + * vcm_get_vcm_from_res() - Return the VCM region of a reservation. + * @res: The reservation to return the VCM region of. + * + * Te return value will be non-zero if the reservation is valid. A valid + * reservation is always associated with a VCM region; there is no such + * thing as an orphan reservation. + */ +struct vcm *vcm_get_vcm_from_res(struct res *res); + + +/** + * vcm_unreserve() - Unreserve the reservation. + * @res: The reservation to unreserve. + * + * The return value will be 0 if the reservation was successfully + * unreserved and: + * -EBUSY The reservation is still backed, + * -EINVAL The vcm argument is invalid. + */ +int vcm_unreserve(struct res *res); + + +/** + * vcm_set_res_attr() - Set attributes of an existing reservation. + * @res: An existing reservation of interest. + * @attr: See 'Reservation Attributes'. + * + * This function can only be used on an existing reservation; there + * are no orphan reservations. All attributes can be set on a existing + * reservation. + * + * The return value will be 0 for a success, otherwise it will be: + * -EINVAL res or attr are invalid. + */ +int vcm_set_res_attr(struct res *res, u32 attr); + + +/** + * vcm_get_num_res() - Return the number of reservations in a VCM region. + * @vcm: The VCM region of interest. + */ +size_t vcm_get_num_res(struct vcm *vcm); + + +/** + * vcm_get_next_res() - Read each reservation one at a time. + * @vcm: The VCM region of interest. + * @res: Contains the last reservation. Pass NULL on the + * first call. + * + * This function works like a foreach reservation in a VCM region. + * + * The return value will be non-zero for each reservation in a VCM. A + * zero indicates no further reservations. + */ +struct res *vcm_get_next_res(struct vcm *vcm, struct res *res); + + +/** + * vcm_res_copy() - Copy len bytes from one reservation to another. + * @to: The reservation to copy to. + * @from: The reservation to copy from. + * @len: The length of bytes to copy. + * + * The return value is the number of bytes copied. + */ +size_t vcm_res_copy(struct res *to, size_t to_off, struct res *from, size_t + from_off, size_t len); + + +/** + * vcm_get_min_page_size() - Return the minimum page size supported by + * the architecture. + */ +size_t vcm_get_min_page_size(void); + + +/** + * vcm_back() - Physically back a reservation. + * @res: The reservation containing the virtual contiguous + * region to back. + * @physmem: The physical memory that will back the virtual + * contiguous memory region. + * + * One VCM can be associated with multiple devices. When you vcm_back() + * each association must be active. This is not strictly necessary. It may + * be changed in the future. + * + * This function returns 0 on a successful physical backing. Otherwise + * it returns: + * -EINVAL res or physmem is invalid or res's len + * is different from physmem's len. + * -EAGAIN Try again, one of the devices hasn't been activated. + */ +int vcm_back(struct res *res, struct physmem *physmem); + + +/** + * vcm_unback() - Unback a reservation. + * @res: The reservation to unback. + * + * One VCM can be associated with multiple devices. When you vcm_unback() + * each association must be active. + * + * This function returns 0 on a successful unbacking. Otherwise + * it returns: + * -EINVAL res is invalid. + * -EAGAIN Try again, one of the devices hasn't been activated. + */ +int vcm_unback(struct res *res); + + +/** + * vcm_phys_alloc() - Allocate physical memory for the VCM region. + * @memtype: The memory type to allocate. + * @len: The length of the allocation. + * @attr: See 'Physical Allocation Attributes'. + * + * This function will allocate chunks of memory according to the attr + * it is passed. + * + * The return value is non-zero if physical memory has been + * successfully allocated. + */ +struct physmem *vcm_phys_alloc(enum memtype_t memtype, size_t len, + u32 attr); + + +/** + * vcm_phys_free() - Free a physical allocation. + * @physmem: The physical allocation to free. + * + * The return value is 0 if the physical allocation has been freed or: + * -EBUSY Their are reservation mapping the physical memory. + * -EINVAL The physmem argument is invalid. + */ +int vcm_phys_free(struct physmem *physmem); + + +/** + * vcm_get_physmem_from_res() - Return a reservation's physmem + * @res: An existing reservation of interest. + * + * The return value will be non-zero on success, otherwise it will be: + * -EINVAL res is invalid + * -ENOMEM res is unbacked + */ +struct physmem *vcm_get_physmem_from_res(struct res *res); + + +/** + * vcm_get_memtype_of_physalloc() - Return the memtype of a reservation. + * @physmem: The physical allocation of interest. + * + * This function returns the memtype of a reservation or VCM_INVALID + * if res is invalid. + */ +enum memtype_t vcm_get_memtype_of_physalloc(struct physmem *physmem); + + +/* + * Associate a VCM with a device, activate that association and remove it. + * + */ + +/** + * vcm_assoc() - Associate a VCM with a device. + * @vcm: The VCM region of interest. + * @dev: The device to associate the VCM with. + * @attr: See 'Association Attributes'. + * + * This function returns non-zero if a association is made. It returns 0 + * if any of its parameters are invalid or VCM_ATTR_VALID is not present. + */ +struct avcm *vcm_assoc(struct vcm *vcm, struct device *dev, u32 attr); + + +/** + * vcm_deassoc() - Deassociate a VCM from a device. + * @avcm: The association we want to break. + * + * The function returns 0 on success or: + * -EBUSY The association is currently activated. + * -EINVAL The avcm parameter is invalid. + */ +int vcm_deassoc(struct avcm *avcm); + + +/** + * vcm_set_assoc_attr() - Set an AVCM's attributes. + * @avcm: The AVCM of interest. + * @attr: The new attr. See 'Association Attributes'. + * + * Every attribute can be set at runtime if an association isn't activated. + * + * This function returns 0 on success or: + * -EBUSY The association is currently activated. + * -EINVAL The avcm parameter is invalid. + */ +int vcm_set_assoc_attr(struct avcm *avcm, u32 attr); + + +/** + * vcm_get_assoc_attr() - Return an AVCM's attributes. + * @avcm: The AVCM of interest. + * + * This function returns 0 on error. + */ +u32 vcm_get_assoc_attr(struct avcm *avcm); + + +/** + * vcm_activate() - Activate an AVCM. + * @avcm: The AVCM to activate. + * + * You have to deactivate, before you activate. + * + * This function returns 0 on success or: + * -EINVAL avcm is invalid + * -ENODEV no device + * -EBUSY device is already active + * -1 hardware failure + */ +int vcm_activate(struct avcm *avcm); + + +/** + * vcm_deactivate() - Deactivate an association. + * @avcm: The AVCM to deactivate. + * + * This function returns 0 on success or: + * -ENOENT avcm is not activate + * -EINVAL avcm is invalid + * -1 Hardware failure + */ +int vcm_deactivate(struct avcm *avcm); + + +/** + * vcm_is_active() - Query if an AVCM is active. + * @avcm: The AVCM of interest. + * + * returns 0 for not active, 1 for active or -EINVAL for error. + * + */ +int vcm_is_active(struct avcm *avcm); + + +/* + * Create, manage and remove a boundary in a VCM. + */ + +/** + * vcm_create_bound() - Create a bound in a VCM. + * @vcm: The VCM that needs a bound. + * @len: The len of the bound. + * + * The allocator picks the virtual addresses of the bound. + * + * This function returns non-zero if a bound was created. + */ +struct bound *vcm_create_bound(struct vcm *vcm, size_t len); + + +/** + * vcm_free_bound() - Free a bound. + * @bound: The bound to remove. + * + * This function returns 0 if bound has been removed or: + * -EBUSY The bound contains reservations and cannot be] + * removed. + * -EINVAL The bound is invalid. + */ +int vcm_free_bound(struct bound *bound); + + +/** + * vcm_reserve_from_bound() - Make a reservation from a bounded area. + * @bound: The bound to reserve from. + * @len: The len of the reservation. + * @attr: See 'Reservation Attributes'. + * + * The return value is non-zero on success. It is 0 if any parameter + * is invalid. + */ +struct res *vcm_reserve_from_bound(struct bound *bound, size_t len, + u32 attr); + + +/** + * vcm_get_bound_start_addr() - Return the starting device address of the bound + * @bound: The bound of interest. + * + * On success this function returns the starting addres of the bound. On error + * it returns: + * 1 bound is invalid. + */ +size_t vcm_get_bound_start_addr(struct bound *bound); + + +/* + * Perform low-level control over VCM regions and reservations. + */ + +/** + * vcm_map_phys_addr() - Produce a physmem from a contiguous + * physical address + * + * @phys: The physical address of the contiguous range. + * @len: The len of the contiguous address range. + * + * Returns non-zero on success, 0 on failure. + */ +struct physmem *vcm_map_phys_addr(phys_addr_t phys, size_t len); + + +/** + * vcm_get_next_phys_addr() - Get the next physical addr and len of a + * physmem. + * @res: The physmem of interest. + * @phys: The current physical address. Set this to NULL to + * start the iteration. + * @len: An output: the len of the next physical segment. + * + * physmem's may contain physically discontiguous sections. This + * function returns the next physical address and len. Pass NULL to + * phys to get the first physical address. The len of the physical + * segment is returned in *len. + * + * Returns 0 if there is no next physical address. + */ +size_t vcm_get_next_phys_addr(struct physmem *physmem, phys_addr_t phys, + size_t *len); + + +/** + * vcm_get_res() - Return the reservation from a device address and a VCM + * @dev_addr: The device address of interest. + * @vcm: The VCM that contains the reservation + * + * This function returns 0 if there is no reservation whose device + * address is dev_addr. + */ +struct res *vcm_get_res(unsigned long dev_addr, struct vcm *vcm); + + +/** + * vcm_translate() - Translate from one device address to another. + * @src_dev: The source device address. + * @src_vcm: The source VCM region. + * @dst_vcm: The destination VCM region. + * + * Derive the device address from a VCM region that maps the same physical + * memory as a device address from another VCM region. + * + * On success this function returns the device address of a translation. On + * error it returns: + * 1 res is invalid. + */ +size_t vcm_translate(size_t src_dev, struct vcm *src_vcm, + struct vcm *dst_vcm); + + +/** + * vcm_get_phys_num_res() - Return the number of reservations mapping a + * physical address. + * @phys: The physical address to read. + */ +size_t vcm_get_phys_num_res(size_t phys); + + +/** + * vcm_get_next_phys_res() - Return the next reservation mapped to a physical + * address. + * @phys: The physical address to map. + * @res: The starting reservation. Set this to NULL for the first + * reservation. + * @len: The virtual length of the reservation + * + * This function returns 0 for the last reservation or no reservation. + */ +struct res *vcm_get_next_phys_res(size_t phys, struct res *res, size_t *len); + + +/** + * vcm_get_pgtbl_pa() - Return the physcial address of a VCM's page table. + * @vcm: The VCM region of interest. + * + * This function returns non-zero on success. + */ +size_t vcm_get_pgtbl_pa(struct vcm *vcm); + + +/** + * vcm_get_cont_memtype_pa() - Return the phys base addr of a memtype's + * first contiguous region. + * @memtype: The memtype of interest. + * + * This function returns non-zero on success. A zero return indicates that + * the given memtype does not have a contiguous region or that the memtype + * is invalid. + */ +size_t vcm_get_cont_memtype_pa(enum memtype_t memtype); + + +/** + * vcm_get_cont_memtype_len() - Return the len of a memtype's + * first contiguous region. + * @memtype: The memtype of interest. + * + * This function returns non-zero on success. A zero return indicates that + * the given memtype does not have a contiguous region or that the memtype + * is invalid. + */ +size_t vcm_get_cont_memtype_len(enum memtype_t memtype); + + +/** + * vcm_dev_addr_to_phys_addr() - Perform a device address page-table lookup. + * @dev: The device that has the table. + * @dev_addr: The device address to map. + * + * This function returns the pa of a va from a device's page-table. It will + * fault if the dev_addr is not mapped. + */ +size_t vcm_dev_addr_to_phys_addr(struct device *dev, unsigned long dev_addr); + + +/* + * Fault Hooks + * + * vcm_hook() + */ + +/** + * vcm_hook() - Add a fault handler. + * @dev: The device. + * @handler: The handler. + * @data: A private piece of data that will get passed to the + * handler. + * + * This function returns 0 for a successful registration or: + * -EINVAL The arguments are invalid. + */ +int vcm_hook(struct device *dev, vcm_handler handler, void *data); + + +/* + * Low level, platform agnostic, HW control. + * + * vcm_hw_ver() + */ + +/** + * vcm_hw_ver() - Return the hardware version of a device, if it has one. + * @dev: The device. + */ +size_t vcm_hw_ver(struct device *dev); + + +/* bring-up init, destroy */ +int vcm_sys_init(void); +int vcm_sys_destroy(void); + +#endif /* _VCM_H_ */ + diff --git a/include/linux/vcm_types.h b/include/linux/vcm_types.h new file mode 100644 index 0000000..671e80f --- /dev/null +++ b/include/linux/vcm_types.h @@ -0,0 +1,338 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef VCM_TYPES_H +#define VCM_TYPES_H + +#include <linux/types.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> +#include <linux/genalloc.h> +#include <linux/vcm_alloc.h> +#include <linux/list.h> +#include <linux/device.h> + +/* + * Reservation Attributes + * + * Used in vcm_reserve(), vcm_reserve_at(), vcm_set_res_attr() and + * vcm_reserve_bound(). + * + * VCM_READ Specifies that the reservation can be read. + * VCM_WRITE Specifies that the reservation can be written. + * VCM_EXECUTE Specifies that the reservation can be executed. + * VCM_USER Specifies that this reservation is used for + * userspace access. + * VCM_SUPERVISOR Specifies that this reservation is used for + * supervisor access. + * VCM_SECURE Specifies that the target of the reservation is + * secure. The usage of this setting is TBD. + * + * Caching behavior as a 4 bit field: + * VCM_NOTCACHED The VCM region is not cached. + * VCM_INNER_WB_WA The VCM region is inner cached + * and is write-back and write-allocate. + * VCM_INNER_WT_NWA The VCM region is inner cached and is + * write-through and no-write-allocate. + * VCM_INNER_WB_NWA The VCM region is inner cached and is + * write-back and no-write-allocate. + * VCM_OUTER_WB_WA The VCM region is outer cached and is + * write-back and write-allocate. + * VCM_OUTER_WT_NWA The VCM region is outer cached and is + * write-through and no-write-allocate. + * VCM_OUTER_WB_NWA The VCM region is outer cached and is + * write-back and no-write-allocate. + * VCM_WB_WA The VCM region is cached and is write + * -back and write-allocate. + * VCM_WT_NWA The VCM region is cached and is write + * -through and no-write-allocate. + * VCM_WB_NWA The VCM region is cached and is write + * -back and no-write-allocate. + */ + +#define VCM_CACHE_POLICY (0xF << 0) + +#define VCM_READ (1UL << 9) +#define VCM_WRITE (1UL << 8) +#define VCM_EXECUTE (1UL << 7) +#define VCM_USER (1UL << 6) +#define VCM_SUPERVISOR (1UL << 5) +#define VCM_SECURE (1UL << 4) +#define VCM_NOTCACHED (0UL << 0) +#define VCM_WB_WA (1UL << 0) +#define VCM_WB_NWA (2UL << 0) +#define VCM_WT (3UL << 0) + + +/* + * Physical Allocation Attributes + * + * Used in vcm_phys_alloc(). + * + * Alignment as a power of 2 starting at 4 KB. 5 bit field. + * 1 = 4KB, 2 = 8KB, etc. + * + * Specifies that the reservation should have the + * alignment specified. + * + * VCM_4KB Specifies that the reservation should use 4KB pages. + * VCM_64KB Specifies that the reservation should use 64KB pages. + * VCM_1MB specifies that the reservation should use 1MB pages. + * VCM_ALL Specifies that the reservation should use all + * available page sizes. + * VCM_PHYS_CONT Specifies that a reservation should be backed with + * physically contiguous memory. + * VCM_COHERENT Specifies that the reservation must be kept coherent + * because it's shared. + */ + +#define VCM_ALIGNMENT_MASK (0x1FUL << 6) /* 5-bit field */ +#define VCM_4KB (1UL << 5) +#define VCM_64KB (1UL << 4) +#define VCM_1MB (1UL << 3) +#define VCM_ALL (1UL << 2) +#define VCM_PAGE_SEL_MASK (0xFUL << 2) +#define VCM_PHYS_CONT (1UL << 1) +#define VCM_COHERENT (1UL << 0) + + +#define SHIFT_4KB (12) + +#define ALIGN_REQ_BYTES(attr) (1UL << (((attr & VCM_ALIGNMENT_MASK) >> 6) + 12)) +/* set the alignment in pow 2, 0 = 4KB */ +#define SET_ALIGN_REQ_BYTES(attr, align) \ + ((attr & ~VCM_ALIGNMENT_MASK) | ((align << 6) & VCM_ALIGNMENT_MASK)) + +/* + * Association Attributes + * + * Used in vcm_assoc(), vcm_set_assoc_attr(). + * + * VCM_USE_LOW_BASE Use the low base register. + * VCM_USE_HIGH_BASE Use the high base register. + * + * VCM_SPLIT A 5 bit field that defines the + * high/low split. This value defines + * the number of 0's left-filled into the + * split register. Addresses that match + * this will use VCM_USE_LOW_BASE + * otherwise they'll use + * VCM_USE_HIGH_BASE. An all 0's value + * directs all translations to + * VCM_USE_LOW_BASE. + */ + +#define VCM_SPLIT (1UL << 3) +#define VCM_USE_LOW_BASE (1UL << 2) +#define VCM_USE_HIGH_BASE (1UL << 1) + +/* + * External VCMs + * + * Used in vcm_create_from_prebuilt() + * + * Externally created VCM IDs for creating kernel and user space + * mappings to VCMs and kernel and user space buffers out of + * VCM_MEMTYPE_0,1,2, etc. + * + */ +#define VCM_PREBUILT_KERNEL 1 +#define VCM_PREBUILT_USER 2 + +/** + * enum memtarget_t - A logical location in a VCM. + * @vcm_start: Indicates the start of a VCM_REGION. + */ +enum memtarget_t { + VCM_START +}; + + +/** + * enum memtype_t - A logical location in a VCM. + * @vcm_memtype_0: Generic memory type 0 + * @vcm_memtype_1: Generic memory type 1 + * @vcm_memtype_2: Generic memory type 2 + * + * A memtype encapsulates a platform specific memory arrangement. The + * memtype needn't refer to a single type of memory, it can refer to a + * set of memories that can back a reservation. + * + */ +enum memtype_t { + VCM_INVALID, + VCM_MEMTYPE_0, + VCM_MEMTYPE_1, + VCM_MEMTYPE_2, +}; + + +/** + * vcm_handler - The signature of the fault hook. + * @dev: The device id of the faulting device. + * @data: The generic data pointer. + * @fault_data: System specific common fault data. + * + * The handler should return 0 for success. This indicates that the + * fault was handled. A non-zero return value is an error and will be + * propagated up the stack. + */ +typedef int (*vcm_handler)(size_t dev, void *data, void *fault_data); + + +/** + * enum vcm_type - The type of VCM. + * @vcm_memtype_0: Generic memory type 0 + * @vcm_memtype_1: Generic memory type 1 + * @vcm_memtype_2: Generic memory type 2 + * + * A memtype encapsulates a platform specific memory arrangement. The + * memtype needn't refer to a single type of memory, it can refer to a + * set of memories that can back a reservation. + * + */ +enum vcm_type { + VCM_DEVICE, + VCM_EXT_KERNEL, + VCM_EXT_USER, + VCM_ONE_TO_ONE, +}; + +/** + * struct vcm - A Virtually Contiguous Memory region. + * @start_addr: The starting address of the VCM region. + * @len: The len of the VCM region. This must be at least + * vcm_min() bytes. + */ +struct vcm { + /* public */ + unsigned long start_addr; + size_t len; + + + /* private */ + enum vcm_type type; + + struct device *dev; /* opaque device control */ + + /* allocator dependent */ + struct gen_pool *pool; + + struct list_head res_head; + + /* this will be a very short list */ + struct list_head assoc_head; +}; + +/** + * struct avcm - A VCM to device association + * @vcm: The VCM region of interest. + * @dev: The device to associate the VCM with. + * @attr: See 'Association Attributes'. + */ +struct avcm { + /* public */ + struct vcm *vcm; + struct device *dev; + u32 attr; + + /* private */ + struct list_head assoc_elm; + + int is_active; /* is this particular association active */ +}; + + +/** + * struct bound - A boundary to reserve from in a VCM region. + * @vcm: The VCM that needs a bound. + * @len: The len of the bound. + */ +struct bound { + struct vcm *vcm; + size_t len; +}; + + +/** + * struct physmem - A physical memory allocation. + * @memtype: The memory type of the VCM region. + * @len: The len of the physical memory allocation. + * @attr: See 'Physical Allocation Attributes'. + * + */ +struct physmem { + /* public */ + enum memtype_t memtype; + size_t len; +b u32 attr; + + /* private */ + struct phys_chunk alloc_head; + + /* if the physmem is cont then use the built in VCM */ + int is_cont; + struct res *res; +}; + + +/** + * struct res - A reservation in a VCM region. + * @vcm: The VCM region to reserve from. + * @len: The length of the reservation. Must be at least vcm_min() + * bytes. + * @attr: See 'Reservation Attributes'. + * @dev_addr: The device-side address. + */ +struct res { + /* public */ + struct vcm *vcm; + size_t len; + u32 attr; + unsigned long dev_addr; + + + /* private */ + struct physmem *physmem; + + /* allocator dependent */ + size_t alignment_req; + size_t aligned_len; + unsigned long ptr; + + struct list_head res_elm; + + /* type VCM_EXT_KERNEL */ + struct vm_struct *vm_area; + int mapped; +}; + +extern int chunk_sizes[NUM_CHUNK_SIZES]; + +#endif /* VCM_TYPES_H */ -- 1.7.0.2 -- Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management
@ 2010-07-21 5:18 stepanm
0 siblings, 0 replies; 55+ messages in thread
From: stepanm @ 2010-07-21 5:18 UTC (permalink / raw)
To: FUJITA Tomonori
Cc: zpfeffer, linux, ebiederm, linux-arch, dwalker, mel,
linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap,
linux-arm-kernel
> What is the problem about mapping a 1MB buffer with the DMA API?
>
> Possibly, an IOMMU can't find space for 1MB but it's not the problem of
the DMA API.
As you have pointed out, one of the issues is that allocation can fail.
While technically VCMM allocations can fail as well, these allocations can
be made from one or more memory pools that have been set aside
specifically to be used by devices. Thus, the kernel's normal allocator
will not encroach on the large physically-contiguous chunks (of size 1MB
or even 16MB) that are not easy to get back, and would be forced to deal
with increasing memory pressure in other ways.
Additionally, some of the memory pools may have special properties, such
as being part of on-chip memory with higher performance than regular
memory, and some devices may have special requirements regarding what type
or memory they need. The VCMM allocator solves the problem in a generic
way by being able to deal with multiple memory pools and supporting
prioritization schemes for which subset of the memory pools is to be used
for each physical allocation.
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 55+ messages in thread
* [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management @ 2010-07-03 5:38 Zach Pfeffer 2010-07-03 19:06 ` Eric W. Biederman 0 siblings, 1 reply; 55+ messages in thread From: Zach Pfeffer @ 2010-07-03 5:38 UTC (permalink / raw) To: mel Cc: andi, dwalker, linux-mm, linux-kernel, linux-arm-msm, linux-omap, linux-arm-kernel, Zach Pfeffer This patch contains the documentation for the API, termed the Virtual Contiguous Memory Manager. Its use would allow all of the IOMMU to VM, VM to device and device to IOMMU interoperation code to be refactored into platform independent code. Comments, suggestions and criticisms are welcome and wanted. Signed-off-by: Zach Pfeffer <zpfeffer@codeaurora.org> --- Documentation/vcm.txt | 587 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 587 insertions(+), 0 deletions(-) create mode 100644 Documentation/vcm.txt diff --git a/Documentation/vcm.txt b/Documentation/vcm.txt new file mode 100644 index 0000000..1c6a8be --- /dev/null +++ b/Documentation/vcm.txt @@ -0,0 +1,587 @@ +What is this document about? +============================ + +This document covers how to use the Virtual Contiguous Memory Manager +(VCMM), how the first implementation works with a specific low-level +Input/Output Memory Management Unit (IOMMU) and the way the VCMM is used +from user-space. It also contains a section that describes why something +like the VCMM is needed in the kernel. + +If anything in this document is wrong, please send patches to the +maintainer of this file, listed at the bottom of the document. + + +The Virtual Contiguous Memory Manager +===================================== + +The VCMM was built to solve the system-wide memory mapping issues that +occur when many bus-masters have IOMMUs. + +An IOMMU maps device addresses to physical addresses. It also insulates +the system from spurious or malicious device bus transactions and allows +fine-grained mapping attribute control. The Linux kernel core does not +contain a generic API to handle IOMMU mapped memory; device driver writers +must implement device specific code to interoperate with the Linux kernel +core. As the number of IOMMUs increases, coordinating the many address +spaces mapped by all discrete IOMMUs becomes difficult without in-kernel +support. + +The VCMM API enables device independent IOMMU control, virtual memory +manager (VMM) interoperation and non-IOMMU enabled device interoperation +by treating devices with or without IOMMUs and all CPUs with or without +MMUs, their mapping contexts and their mappings using common +abstractions. Physical hardware is given a generic device type and mapping +contexts are abstracted into Virtual Contiguous Memory (VCM) +regions. Users "reserve" memory from VCMs and "back" their reservations +with physical memory. + +Why the VCMM is Needed +---------------------- + +Driver writers who control devices with IOMMUs must contend with device +control and memory management. Driver writers have a large device driver +API that they can leverage to control their devices, but they are lacking +a unified API to help them program mappings into IOMMUs and share those +mappings with other devices and CPUs in the system. + +Sharing is complicated by Linux's CPU-centric VMM. The CPU-centric model +generally makes sense because average hardware only contains a MMU for the +CPU and possibly a graphics MMU. If every device in the system has one or +more MMUs the CPU-centric memory management (MM) programming model breaks +down. + +Abstracting IOMMU device programming into a common API has already begun +in the Linux kernel. It was built to abstract the difference between AMD +and Intel IOMMUs to support x86 virtualization on both platforms. The +interface is listed in include/linux/iommu.h. It contains +interfaces for mapping and unmapping as well as domain management. This +interface has not gained widespread use outside the x86; PA-RISC, Alpha +and SPARC architectures and ARM and PowerPC platforms all use their own +mapping modules to control their IOMMUs. The VCMM contains an IOMMU +programming layer, but since its abstraction supports map management +independent of device control, the layer is not used directly. This +higher-level view enables a new kernel service, not just an IOMMU +interoperation layer. + +The General Idea: Map Management using Graphs +--------------------------------------------- + +Looking at mapping from a system-wide perspective reveals a general graph +problem. The VCMM's API is built to manage the general mapping graph. Each +node that talks to memory, either through an MMU or directly (physically +mapped) can be thought of as the device-end of a mapping edge. The other +edge is the physical memory (or intermediate virtual space) that is +mapped. + +In the direct-mapped case the device is assigned a one-to-one MMU. This +scheme allows direct mapped devices to participate in general graph +management. + +The CPU nodes can also be brought under the same mapping abstraction with +the use of a light overlay on the existing VMM. This light overlay allows +VMM-managed mappings to interoperate with the common API. The light +overlay enables this without substantial modifications to the existing +VMM. + +In addition to CPU nodes that are running Linux (and the VMM), remote CPU +nodes that may be running other operating systems can be brought into the +general abstraction. Routing all memory management requests from a remote +node through the central memory management framework enables new features +like system-wide memory migration. This feature may only be feasible for +large buffers that are managed outside of the fast-path, but having remote +allocation in a system enables features that are impossible to build +without it. + +The fundamental objects that support graph-based map management are: + +1) Virtual Contiguous Memory Regions + +2) Reservations + +3) Associated Virtual Contiguous Memory Regions + +4) Memory Targets + +5) Physical Memory Allocations + +Usage Overview +-------------- + +In a nutshell, users allocate Virtual Contiguous Memory Regions and +associate those regions with one or more devices by creating an Associated +Virtual Contiguous Memory Region. Users then create Reservations from the +Virtual Contiguous Memory Region. At this point no physical memory has +been committed to the reservation. To associate physical memory with a +reservation a Physical Memory Allocation is created and the Reservation is +backed with this allocation. + +include/linux/vcm.h includes comments documenting each API. + +Virtual Contiguous Memory Regions +--------------------------------- + +A Virtual Contiguous Memory Region (VCM) abstracts the memory space a +device sees. The addresses of the region are only used by the devices +which are associated with the region. This address space would normally be +implemented as a device page table. + +A VCM is created and destroyed with three functions: + + struct vcm *vcm_create(unsigned long start_addr, unsigned long len); + + struct vcm *vcm_create_from_prebuilt(size_t ext_vcm_id); + + int vcm_free(struct vcm *vcm); + +start_addr is an offset into the address space where allocations will +start from. len is the length from start_addr of the VCM. Both functions +generate an instance of a VCM. + +ext_vcm_id is used to pass a request to the VMM to generate a VCM +instance. In the current implementation the call simply makes a note that +the VCM instance is a VMM VCM instance for other interfaces usage. This +muxing is seen throughout the implementation. + +vcm_create() and vcm_create_from_prebuilt() produce VCM instances for +virtually mapped devices (IOMMUs and CPUs). To create a one-to-one mapped +VCM, users pass the start_addr and len of the physical region. The VCMM +matches this and records that the VCM instance is a one-to-one VCM. + +The newly created VCM instance can be passed to any function that needs to +operate on or with a virtual contiguous memory region. Its main attributes +are a start_addr and a len as well as an internal setting that allows the +implementation to mux between true virtual spaces, one-to-one mapped +spaces and VMM managed spaces. + +The current implementation uses the genalloc library to manage the VCM for +IOMMU devices. Return values and more in-depth per-function documentation +for these and the ones listed below are in include/linux/vcm.h. + +Reservations +------------ + +A Reservation is a contiguous region allocated from a VCM. There is no +physical memory associated with it. + +A Reservation is created and destroyed with: + + struct res *vcm_reserve(struct vcm *vcm, size_t len, u32 attr); + + int vcm_unreserve(struct res *res); + +A vcm is a VCM created above. len is the length of the request. It can be +up to the length of the VCM region the reservation is being created +from. attr are mapping attributes: read, write, execute, user, supervisor, +secure, not-cached, write-back/write-allocate, write-back/no +write-allocate, write-through. These attrs are appropriate for ARM but can +be changed to match to any architecture. + +The implementation calls gen_pool_alloc() for IOMMU devices, +alloc_vm_area() for VMM areas and is a pass-through for one-to-one mapped +areas. + +Associated Virtual Contiguous Memory Regions and Activation +----------------------------------------------------------- + +An Associated Virtual Contiguous Memory Region (AVCM) is a mapping of a +VCM to a device. The mapping can be active or inactive. + +An AVCM is managed with: + + struct avcm *vcm_assoc(struct vcm *vcm, struct device *dev, u32 attr); + + int vcm_deassoc(struct avcm *avcm); + + int vcm_activate(struct avcm *avcm); + + int vcm_deactivate(struct avcm *avcm); + +A VCM instance is a VCM created above. A dev is an opaque device handle +thats passed down to the device driver the VCMM muxes in to handle a +request. attr are association attributes: split, use-high or +use-low. split controls which transactions hit a high-address page-table +and which transactions hit a low-address page-table. For instance, all +transactions whose most significant address bit is one would use the +high-address page-table, any other transaction would use the low address +page-table. This scheme is ARM-specific and could be changed in other +architectures. One VCM instance can be associated with many devices and +many VCM instances can be associated with one device. + +An AVCM is only a link. To program and deprogram a device with a VCM the +user calls vcm_activate() and vcm_deactivate(). For IOMMU devices, +activating a mapping programs the base address of a page table into an +IOMMU. For VMM and one-to-one based devices, mappings are active +immediately but the API does require an activation call for them for +internal reference counting. + +Memory Targets +-------------- + +A Memory Target is a platform independent way of specifying a physical +pool; it abstracts a pool of physical memory. The physical memory pool may +be physically discontiguous, need to be allocated from in a unique way or +have other user-defined attributes. + +Physical Memory Allocation and Reservation Backing +-------------------------------------------------- + +Physical memory is allocated as a separate step from reserving +memory. This allows multiple reservations to back the same physical +memory. + +A Physical Memory Allocation is managed using the following functions: + + struct physmem *vcm_phys_alloc(enum memtype_t memtype, + size_t len, u32 attr); + + int vcm_phys_free(struct physmem *physmem); + + int vcm_back(struct res *res, struct physmem *physmem); + + int vcm_unback(struct res *res); + +attr can include an alignment request, a specification to map memory using +various block sizes and/or to use physically contiguous memory. memtype is +one of the memory types listed in Memory Targets. + +The current implementation manages two pools of memory. One pool is a +contiguous block of memory and the other is a set of contiguous block +pools. In the current implementation the block pools contain 4K, 64K and +1M blocks. The physical allocator does not try to split blocks from the +contiguous block pools to satisfy requests. + +The use of 4K, 64K and 1M blocks solves a problem with some IOMMU +hardware. IOMMUs are placed in front of multimedia engines to provide a +contiguous address space to the device. Multimedia devices need large +buffers and large buffers may map to a large number of physical +blocks. IOMMUs tend to have small translation lookaside buffers +(TLBs). Since the TLB is small the number of physical blocks that map a +given range needs to be small or else the IOMMU will continually fetch new +translations during a typical streamed multimedia flow. By using a 1 MB +mapping (or 64K mapping) instead of a 4K mapping the number of misses can +be minimized, allowing the multimedia block to meet its performance goals. + +Low Level Control +----------------- + +It is necessary in some instances to access attributes and provide +higher-level control of the low-level hardware abstraction. The API +contains many members and functions for this task but the two that are +typically used are: + + res->dev_addr; + + int vcm_hook(struct device *dev, vcm_handler handler, void *data); + +res->dev_addr is the device address given a reservation. This device +address is a virtual IOMMU address for reservations on IOMMU VCMs, a +virtual VMM address for reservations on VMM VCMs and a virtual (really +physical since its one-to-one mapped) address for one-to-one devices. + +The function, vcm_hook, allows a caller in the kernel to register a +user_handler. The handler is passed the data member passed to vcm_hook +during a fault. The user can return 1 to indicate that the underlying +driver should handle the fault and retry the transaction or they can +return 0 to halt the transaction. If the user doesn't register a +handler the low-level driver will print a warning and terminate the +transaction. + +A Detailed Walk Through +----------------------- + +The following call sequence walks through a typical allocation +sequence. In the first stage the memory for a device is reserved and +backed. This occurs without mapping the memory into a VMM VCM region. The +second stage maps the first VCM region into a VMM VCM region so the kernel +can read or write it. The second stage is not necessary if the VMM does +not need to read or modify the contents of the original mapping. + + Stage 1: Map and Allocate Memory for a Device + + The call sequence starts by creating a VCM region: + + vcm = vcm_create(start_addr, len); + + The next call associates a VCM region with a device: + + avcm = vcm_assoc(vcm, dev, attr); + + To activate the association, users call vcm_activate() on the avcm from + the associate call. This programs the underlining device with the + mappings. + + ret = vcm_activate(avcm); + + Once a VCM region is created and associated it can be reserved from + with: + + res = vcm_reserve(vcm, res_len, res_attr); + + A user then allocates physical memory with: + + physmem = vcm_phys_alloc(memtype, len, phys_attr); + + To back the reservation with the physical memory allocation the user + calls: + + vcm_back(res, physmem); + + + Stage 2: Map the Device's Memory into the VMM's VCM region + + If the VMM needs to read and/or write the region that was just created, + the following calls are made. + + The first call creates a prebuilt VCM with: + + vcm_vmm = vcm_from_prebuilt(ext_vcm_id); + + The prebuilt VCM is associated with the CPU device and activated with: + + avcm_vmm = vcm_assoc(vcm_vmm, dev_cpu, attr); + vcm_activate(avcm_vmm); + + A reservation is made on the VMM VCM with: + + res_vmm = vcm_reserve(vcm_vmm, res_len, attr); + + Finally, once the topology has been set up a vcm_back() allows the VMM + to read the memory using the physmem generated in stage 1: + + vcm_back(res_vmm, physmem); + +Mapping IOMMU, one-to-one and VMM Reservations +---------------------------------------------- + +The following example demonstrates mapping IOMMU, one-to-one and VMM +reservations to the same physical memory. It shows the use of phys_addr +and phys_size to create a contiguous VCM for one-to-one mapped devices. + + The user allocates physical memory: + + physmem = vcm_phys_alloc(memtype, SZ_2MB + SZ_4K, CONTIGUOUS); + + Creates an IOMMU VCM: + + vcm_iommu = vcm_create(SZ_1K, SZ_16M); + + Creates a one-to-one VCM: + + vcm_onetoone = vcm_create(phys_addr, phys_size); + + Creates a Prebuit VCM: + + vcm_vmm = vcm_from_prebuit(ext_vcm_id); + + Associate and activate all three to their respective devices: + + avcm_iommu = vcm_assoc(vcm_iommu, dev_iommu, attr0); + avcm_onetoone = vcm_assoc(vcm_onetoone, dev_onetoone, attr1); + avcm_vmm = vcm_assoc(vcm_vmm, dev_cpu, attr2); + vcm_activate(avcm_iommu); + vcm_activate(avcm_onetoone); + vcm_activate(avcm_vmm); + + Associations that fail return 0. + + And finally, creates and backs reservations on all 3 such that they + all point to the same memory: + + res_iommu = vcm_reserve(vcm_iommu, SZ_2MB + SZ_4K, attr); + res_onetoone = vcm_reserve(vcm_onetoone, SZ_2MB + SZ_4K, attr); + res_vmm = vcm_reserve(vcm_vmm, SZ_2MB + SZ_4K, attr); + vcm_back(res_iommu, physmem); + vcm_back(res_onetoone, physmem); + vcm_back(res_vmm, physmem); + + Like associations, reservations that fail return 0. + +VCM Summary +----------- + +The VCMM is an attempt to abstract attributes of three distinct classes of +mappings into one API. The VCMM allows users to reason about mappings as +first class objects. It also allows memory mappings to flow from the +traditional 4K mappings prevalent on systems today to more efficient block +sizes. Finally, it allows users to manage mapping interoperation without +becoming VMM experts. These features will allow future systems with many +MMU mapped devices to interoperate simply and therefore correctly. + + +IOMMU Hardware Control +====================== + +The VCM currently supports a single type of IOMMU, a Qualcomm System MMU +(SMMU). The SMMU interface contains functions to map and unmap virtual +addresses, perform address translations and initialize hardware. A +Qualcomm SMMU can contain multiple MMU contexts. Each context can +translate in parallel. All contexts in a SMMU share one global translation +look-aside buffer (TLB). + +To support context muxing the SMMU module creates and manages device +independent virtual contexts. These context abstractions are bound to +actual contexts at run-time. Once bound, a context can be activated. This +activation programs the underlying context with the virtual context +affecting a context switch. + +The following functions are all documented in: + + arch/arm/mach-msm/include/mach/smmu_driver.h. + +Mapping +------- + +To map and unmap a virtual page into physical space the VCM calls: + + int smmu_map(struct smmu_dev *dev, unsigned long pa, + unsigned long va, unsigned long len, unsigned int attr); + + int smmu_unmap(struct smmu_dev *dev, unsigned long va, + unsigned long len); + + int smmu_update_start(struct smmu_dev *dev); + + int smmu_update_done(struct smmu_dev *dev); + +The size given to map must be 4K, 64K, 1M or 16M and the VA and PA must be +aligned to the given size. smmu_update_start() and smmu_update_done() +should be called before and after each map or unmap. + +Translation +----------- + +To request a hardware VA to PA translation on a single address the VCM +calls: + + unsigned long smmu_translate(struct smmu_dev *dev, + unsigned long va); + +Fault Handling +-------------- + +To register an interrupt handler for a context the VCM calls: + + int smmu_hook_interrupt(struct smmu_dev *dev, vcm_handler handler, + void *data); + +The registered interrupt handler should return 1 if it wants the SMMU +driver to retry the transaction again and 0 if it wants the SMMU driver to +terminate the transaction. + +Managing SMMU Initialization and Contexts +----------------------------------------- + +SMMU hardware initialization and management happens in 2 steps. The first +step initializes global SMMU devices and abstract device contexts. The +second step binds contexts and devices. + +An SMMU hardware instance is built with: + + int smmu_drvdata_init(struct smmu_driver *drv, unsigned long base, + int irq); + +An SMMU context is initialized and deinitialized with: + + struct smmu_dev *smmu_ctx_init(int ctx); + int smmu_ctx_deinit(struct smmu_dev *dev); + +An abstract SMMU context is bound to a particular SMMU with: + + int smmu_ctx_bind(struct smmu_dev *ctx, struct smmu_driver *drv); + +Activation +---------- + +Activation affects a context switch. + +Activation, deactivation and activation state testing are done with: + + int smmu_activate(struct smmu_dev *dev); + int smmu_deactivate(struct smmu_dev *dev); + int smmu_is_active(struct smmu_dev *dev); + + +Userspace Access to Devices with IOMMUs +======================================= + +A device that issues transactions through an IOMMU must work with two +APIs. The first API is the VCM. The VCM API is device independent. Users +pass the VCM a dev_id and the VCM makes calls on the hardware device it +has been configured with using this dev_id. The second API is whatever +device topology has been created to organize the particular IOMMUs in a +system. The only constraint on this second API is that it must give the +user a single dev_id that it can pass through the VCM. + +For the Qualcomm SMMUs the second API consists of a tree of platform +devices and two platform drivers as well as a context lookup function that +traverses the device tree and returns a dev_id given a context name. + +Qualcomm SMMU Device Tree +------------------------- + +The current tree organizes the devices into a tree that looks like the +following: + +smmu/ + smmu0/ + ctx0 + ctx1 + ctx2 + smmu1/ + ctx3 + + +Each context, ctx[n] and each smmu, smmu[n] is given a name. Since users +are interested in contexts not smmus, the context name is passed to a +function to find the dev_id associated with that name. The functions to +find, free and get the base address (since the device probe function calls +ioremap to map the SMMUs configuration registers into the kernel) are +listed here: + + struct smmu_dev *smmu_get_ctx_instance(char *ctx_name); + int smmu_free_ctx_instance(struct smmu_dev *dev); + unsigned long smmu_get_base_addr(struct smmu_dev *dev); + +Documentation for these functions is in: + + arch/arm/mach-msm/include/mach/smmu_device.h + +Each context is given a dev node named after the context. For example: + + /dev/vcodec_a_mm1 + /dev/vcodec_b_mm2 + /dev/vcodec_stream + etc... + +Users open, close and mmap these nodes to access VCM buffers from +userspace in the same way that they used to open, close and mmap /dev +nodes that represented large physically contiguous buffers (called PMEM +buffers on Android). + +Example +------- + +An abbreviated example is shown here: + +Users get the dev_id associated with their target context, create a VCM +topology appropriate for their device and finally associate the VCMs of +the topology with the contexts that will take the VCMs: + + dev_id = smmu_get_ctx_instance(vcodec_a_stream); + +create vcm and needed topology + + avcm = vcm_assoc(vcm, dev_id, attr); + +Tying it all Together +--------------------- + +VCMs, IOMMUs and the device tree all work to support system-wide memory +mappings. The use of each API in this system allows users to concentrate +on the relevant details without needing to worry about low-level +details. The API's clear separation of memory spaces and the devices that +support those memory spaces continues the Linux tradition of abstracting the +what from the how. + + +Maintainer: Zach Pfeffer <zpfeffer@codeaurora.org> -- 1.7.0.2 -- Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-03 5:38 Zach Pfeffer @ 2010-07-03 19:06 ` Eric W. Biederman 2010-07-07 22:44 ` Zach Pfeffer 0 siblings, 1 reply; 55+ messages in thread From: Eric W. Biederman @ 2010-07-03 19:06 UTC (permalink / raw) To: Zach Pfeffer Cc: mel, andi, dwalker, linux-mm, linux-kernel, linux-arm-msm, linux-omap, linux-arm-kernel Zach Pfeffer <zpfeffer@codeaurora.org> writes: > This patch contains the documentation for the API, termed the Virtual > Contiguous Memory Manager. Its use would allow all of the IOMMU to VM, > VM to device and device to IOMMU interoperation code to be refactored > into platform independent code. > > Comments, suggestions and criticisms are welcome and wanted. How does this differ from the dma api? You probably want to copy linux-arch on something that is aimed at affecting multiple architectures like this proposal is. Eric > > Signed-off-by: Zach Pfeffer <zpfeffer@codeaurora.org> > --- > Documentation/vcm.txt | 587 +++++++++++++++++++++++++++++++++++++++++++++++++ > 1 files changed, 587 insertions(+), 0 deletions(-) > create mode 100644 Documentation/vcm.txt > > diff --git a/Documentation/vcm.txt b/Documentation/vcm.txt > new file mode 100644 > index 0000000..1c6a8be > --- /dev/null > +++ b/Documentation/vcm.txt > @@ -0,0 +1,587 @@ > +What is this document about? > +============================ > + > +This document covers how to use the Virtual Contiguous Memory Manager > +(VCMM), how the first implementation works with a specific low-level > +Input/Output Memory Management Unit (IOMMU) and the way the VCMM is used > +from user-space. It also contains a section that describes why something > +like the VCMM is needed in the kernel. > + > +If anything in this document is wrong, please send patches to the > +maintainer of this file, listed at the bottom of the document. > + > + > +The Virtual Contiguous Memory Manager > +===================================== > + > +The VCMM was built to solve the system-wide memory mapping issues that > +occur when many bus-masters have IOMMUs. > + > +An IOMMU maps device addresses to physical addresses. It also insulates > +the system from spurious or malicious device bus transactions and allows > +fine-grained mapping attribute control. The Linux kernel core does not > +contain a generic API to handle IOMMU mapped memory; device driver writers > +must implement device specific code to interoperate with the Linux kernel > +core. As the number of IOMMUs increases, coordinating the many address > +spaces mapped by all discrete IOMMUs becomes difficult without in-kernel > +support. > + > +The VCMM API enables device independent IOMMU control, virtual memory > +manager (VMM) interoperation and non-IOMMU enabled device interoperation > +by treating devices with or without IOMMUs and all CPUs with or without > +MMUs, their mapping contexts and their mappings using common > +abstractions. Physical hardware is given a generic device type and mapping > +contexts are abstracted into Virtual Contiguous Memory (VCM) > +regions. Users "reserve" memory from VCMs and "back" their reservations > +with physical memory. > + > +Why the VCMM is Needed > +---------------------- > + > +Driver writers who control devices with IOMMUs must contend with device > +control and memory management. Driver writers have a large device driver > +API that they can leverage to control their devices, but they are lacking > +a unified API to help them program mappings into IOMMUs and share those > +mappings with other devices and CPUs in the system. > + > +Sharing is complicated by Linux's CPU-centric VMM. The CPU-centric model > +generally makes sense because average hardware only contains a MMU for the > +CPU and possibly a graphics MMU. If every device in the system has one or > +more MMUs the CPU-centric memory management (MM) programming model breaks > +down. > + > +Abstracting IOMMU device programming into a common API has already begun > +in the Linux kernel. It was built to abstract the difference between AMD > +and Intel IOMMUs to support x86 virtualization on both platforms. The > +interface is listed in include/linux/iommu.h. It contains > +interfaces for mapping and unmapping as well as domain management. This > +interface has not gained widespread use outside the x86; PA-RISC, Alpha > +and SPARC architectures and ARM and PowerPC platforms all use their own > +mapping modules to control their IOMMUs. The VCMM contains an IOMMU > +programming layer, but since its abstraction supports map management > +independent of device control, the layer is not used directly. This > +higher-level view enables a new kernel service, not just an IOMMU > +interoperation layer. > + > +The General Idea: Map Management using Graphs > +--------------------------------------------- > + > +Looking at mapping from a system-wide perspective reveals a general graph > +problem. The VCMM's API is built to manage the general mapping graph. Each > +node that talks to memory, either through an MMU or directly (physically > +mapped) can be thought of as the device-end of a mapping edge. The other > +edge is the physical memory (or intermediate virtual space) that is > +mapped. > + > +In the direct-mapped case the device is assigned a one-to-one MMU. This > +scheme allows direct mapped devices to participate in general graph > +management. > + > +The CPU nodes can also be brought under the same mapping abstraction with > +the use of a light overlay on the existing VMM. This light overlay allows > +VMM-managed mappings to interoperate with the common API. The light > +overlay enables this without substantial modifications to the existing > +VMM. > + > +In addition to CPU nodes that are running Linux (and the VMM), remote CPU > +nodes that may be running other operating systems can be brought into the > +general abstraction. Routing all memory management requests from a remote > +node through the central memory management framework enables new features > +like system-wide memory migration. This feature may only be feasible for > +large buffers that are managed outside of the fast-path, but having remote > +allocation in a system enables features that are impossible to build > +without it. > + > +The fundamental objects that support graph-based map management are: > + > +1) Virtual Contiguous Memory Regions > + > +2) Reservations > + > +3) Associated Virtual Contiguous Memory Regions > + > +4) Memory Targets > + > +5) Physical Memory Allocations > + > +Usage Overview > +-------------- > + > +In a nutshell, users allocate Virtual Contiguous Memory Regions and > +associate those regions with one or more devices by creating an Associated > +Virtual Contiguous Memory Region. Users then create Reservations from the > +Virtual Contiguous Memory Region. At this point no physical memory has > +been committed to the reservation. To associate physical memory with a > +reservation a Physical Memory Allocation is created and the Reservation is > +backed with this allocation. > + > +include/linux/vcm.h includes comments documenting each API. > + > +Virtual Contiguous Memory Regions > +--------------------------------- > + > +A Virtual Contiguous Memory Region (VCM) abstracts the memory space a > +device sees. The addresses of the region are only used by the devices > +which are associated with the region. This address space would normally be > +implemented as a device page table. > + > +A VCM is created and destroyed with three functions: > + > + struct vcm *vcm_create(unsigned long start_addr, unsigned long len); > + > + struct vcm *vcm_create_from_prebuilt(size_t ext_vcm_id); > + > + int vcm_free(struct vcm *vcm); > + > +start_addr is an offset into the address space where allocations will > +start from. len is the length from start_addr of the VCM. Both functions > +generate an instance of a VCM. > + > +ext_vcm_id is used to pass a request to the VMM to generate a VCM > +instance. In the current implementation the call simply makes a note that > +the VCM instance is a VMM VCM instance for other interfaces usage. This > +muxing is seen throughout the implementation. > + > +vcm_create() and vcm_create_from_prebuilt() produce VCM instances for > +virtually mapped devices (IOMMUs and CPUs). To create a one-to-one mapped > +VCM, users pass the start_addr and len of the physical region. The VCMM > +matches this and records that the VCM instance is a one-to-one VCM. > + > +The newly created VCM instance can be passed to any function that needs to > +operate on or with a virtual contiguous memory region. Its main attributes > +are a start_addr and a len as well as an internal setting that allows the > +implementation to mux between true virtual spaces, one-to-one mapped > +spaces and VMM managed spaces. > + > +The current implementation uses the genalloc library to manage the VCM for > +IOMMU devices. Return values and more in-depth per-function documentation > +for these and the ones listed below are in include/linux/vcm.h. > + > +Reservations > +------------ > + > +A Reservation is a contiguous region allocated from a VCM. There is no > +physical memory associated with it. > + > +A Reservation is created and destroyed with: > + > + struct res *vcm_reserve(struct vcm *vcm, size_t len, u32 attr); > + > + int vcm_unreserve(struct res *res); > + > +A vcm is a VCM created above. len is the length of the request. It can be > +up to the length of the VCM region the reservation is being created > +from. attr are mapping attributes: read, write, execute, user, supervisor, > +secure, not-cached, write-back/write-allocate, write-back/no > +write-allocate, write-through. These attrs are appropriate for ARM but can > +be changed to match to any architecture. > + > +The implementation calls gen_pool_alloc() for IOMMU devices, > +alloc_vm_area() for VMM areas and is a pass-through for one-to-one mapped > +areas. > + > +Associated Virtual Contiguous Memory Regions and Activation > +----------------------------------------------------------- > + > +An Associated Virtual Contiguous Memory Region (AVCM) is a mapping of a > +VCM to a device. The mapping can be active or inactive. > + > +An AVCM is managed with: > + > + struct avcm *vcm_assoc(struct vcm *vcm, struct device *dev, u32 attr); > + > + int vcm_deassoc(struct avcm *avcm); > + > + int vcm_activate(struct avcm *avcm); > + > + int vcm_deactivate(struct avcm *avcm); > + > +A VCM instance is a VCM created above. A dev is an opaque device handle > +thats passed down to the device driver the VCMM muxes in to handle a > +request. attr are association attributes: split, use-high or > +use-low. split controls which transactions hit a high-address page-table > +and which transactions hit a low-address page-table. For instance, all > +transactions whose most significant address bit is one would use the > +high-address page-table, any other transaction would use the low address > +page-table. This scheme is ARM-specific and could be changed in other > +architectures. One VCM instance can be associated with many devices and > +many VCM instances can be associated with one device. > + > +An AVCM is only a link. To program and deprogram a device with a VCM the > +user calls vcm_activate() and vcm_deactivate(). For IOMMU devices, > +activating a mapping programs the base address of a page table into an > +IOMMU. For VMM and one-to-one based devices, mappings are active > +immediately but the API does require an activation call for them for > +internal reference counting. > + > +Memory Targets > +-------------- > + > +A Memory Target is a platform independent way of specifying a physical > +pool; it abstracts a pool of physical memory. The physical memory pool may > +be physically discontiguous, need to be allocated from in a unique way or > +have other user-defined attributes. > + > +Physical Memory Allocation and Reservation Backing > +-------------------------------------------------- > + > +Physical memory is allocated as a separate step from reserving > +memory. This allows multiple reservations to back the same physical > +memory. > + > +A Physical Memory Allocation is managed using the following functions: > + > + struct physmem *vcm_phys_alloc(enum memtype_t memtype, > + size_t len, u32 attr); > + > + int vcm_phys_free(struct physmem *physmem); > + > + int vcm_back(struct res *res, struct physmem *physmem); > + > + int vcm_unback(struct res *res); > + > +attr can include an alignment request, a specification to map memory using > +various block sizes and/or to use physically contiguous memory. memtype is > +one of the memory types listed in Memory Targets. > + > +The current implementation manages two pools of memory. One pool is a > +contiguous block of memory and the other is a set of contiguous block > +pools. In the current implementation the block pools contain 4K, 64K and > +1M blocks. The physical allocator does not try to split blocks from the > +contiguous block pools to satisfy requests. > + > +The use of 4K, 64K and 1M blocks solves a problem with some IOMMU > +hardware. IOMMUs are placed in front of multimedia engines to provide a > +contiguous address space to the device. Multimedia devices need large > +buffers and large buffers may map to a large number of physical > +blocks. IOMMUs tend to have small translation lookaside buffers > +(TLBs). Since the TLB is small the number of physical blocks that map a > +given range needs to be small or else the IOMMU will continually fetch new > +translations during a typical streamed multimedia flow. By using a 1 MB > +mapping (or 64K mapping) instead of a 4K mapping the number of misses can > +be minimized, allowing the multimedia block to meet its performance goals. > + > +Low Level Control > +----------------- > + > +It is necessary in some instances to access attributes and provide > +higher-level control of the low-level hardware abstraction. The API > +contains many members and functions for this task but the two that are > +typically used are: > + > + res->dev_addr; > + > + int vcm_hook(struct device *dev, vcm_handler handler, void *data); > + > +res->dev_addr is the device address given a reservation. This device > +address is a virtual IOMMU address for reservations on IOMMU VCMs, a > +virtual VMM address for reservations on VMM VCMs and a virtual (really > +physical since its one-to-one mapped) address for one-to-one devices. > + > +The function, vcm_hook, allows a caller in the kernel to register a > +user_handler. The handler is passed the data member passed to vcm_hook > +during a fault. The user can return 1 to indicate that the underlying > +driver should handle the fault and retry the transaction or they can > +return 0 to halt the transaction. If the user doesn't register a > +handler the low-level driver will print a warning and terminate the > +transaction. > + > +A Detailed Walk Through > +----------------------- > + > +The following call sequence walks through a typical allocation > +sequence. In the first stage the memory for a device is reserved and > +backed. This occurs without mapping the memory into a VMM VCM region. The > +second stage maps the first VCM region into a VMM VCM region so the kernel > +can read or write it. The second stage is not necessary if the VMM does > +not need to read or modify the contents of the original mapping. > + > + Stage 1: Map and Allocate Memory for a Device > + > + The call sequence starts by creating a VCM region: > + > + vcm = vcm_create(start_addr, len); > + > + The next call associates a VCM region with a device: > + > + avcm = vcm_assoc(vcm, dev, attr); > + > + To activate the association, users call vcm_activate() on the avcm from > + the associate call. This programs the underlining device with the > + mappings. > + > + ret = vcm_activate(avcm); > + > + Once a VCM region is created and associated it can be reserved from > + with: > + > + res = vcm_reserve(vcm, res_len, res_attr); > + > + A user then allocates physical memory with: > + > + physmem = vcm_phys_alloc(memtype, len, phys_attr); > + > + To back the reservation with the physical memory allocation the user > + calls: > + > + vcm_back(res, physmem); > + > + > + Stage 2: Map the Device's Memory into the VMM's VCM region > + > + If the VMM needs to read and/or write the region that was just created, > + the following calls are made. > + > + The first call creates a prebuilt VCM with: > + > + vcm_vmm = vcm_from_prebuilt(ext_vcm_id); > + > + The prebuilt VCM is associated with the CPU device and activated with: > + > + avcm_vmm = vcm_assoc(vcm_vmm, dev_cpu, attr); > + vcm_activate(avcm_vmm); > + > + A reservation is made on the VMM VCM with: > + > + res_vmm = vcm_reserve(vcm_vmm, res_len, attr); > + > + Finally, once the topology has been set up a vcm_back() allows the VMM > + to read the memory using the physmem generated in stage 1: > + > + vcm_back(res_vmm, physmem); > + > +Mapping IOMMU, one-to-one and VMM Reservations > +---------------------------------------------- > + > +The following example demonstrates mapping IOMMU, one-to-one and VMM > +reservations to the same physical memory. It shows the use of phys_addr > +and phys_size to create a contiguous VCM for one-to-one mapped devices. > + > + The user allocates physical memory: > + > + physmem = vcm_phys_alloc(memtype, SZ_2MB + SZ_4K, CONTIGUOUS); > + > + Creates an IOMMU VCM: > + > + vcm_iommu = vcm_create(SZ_1K, SZ_16M); > + > + Creates a one-to-one VCM: > + > + vcm_onetoone = vcm_create(phys_addr, phys_size); > + > + Creates a Prebuit VCM: > + > + vcm_vmm = vcm_from_prebuit(ext_vcm_id); > + > + Associate and activate all three to their respective devices: > + > + avcm_iommu = vcm_assoc(vcm_iommu, dev_iommu, attr0); > + avcm_onetoone = vcm_assoc(vcm_onetoone, dev_onetoone, attr1); > + avcm_vmm = vcm_assoc(vcm_vmm, dev_cpu, attr2); > + vcm_activate(avcm_iommu); > + vcm_activate(avcm_onetoone); > + vcm_activate(avcm_vmm); > + > + Associations that fail return 0. > + > + And finally, creates and backs reservations on all 3 such that they > + all point to the same memory: > + > + res_iommu = vcm_reserve(vcm_iommu, SZ_2MB + SZ_4K, attr); > + res_onetoone = vcm_reserve(vcm_onetoone, SZ_2MB + SZ_4K, attr); > + res_vmm = vcm_reserve(vcm_vmm, SZ_2MB + SZ_4K, attr); > + vcm_back(res_iommu, physmem); > + vcm_back(res_onetoone, physmem); > + vcm_back(res_vmm, physmem); > + > + Like associations, reservations that fail return 0. > + > +VCM Summary > +----------- > + > +The VCMM is an attempt to abstract attributes of three distinct classes of > +mappings into one API. The VCMM allows users to reason about mappings as > +first class objects. It also allows memory mappings to flow from the > +traditional 4K mappings prevalent on systems today to more efficient block > +sizes. Finally, it allows users to manage mapping interoperation without > +becoming VMM experts. These features will allow future systems with many > +MMU mapped devices to interoperate simply and therefore correctly. > + > + > +IOMMU Hardware Control > +====================== > + > +The VCM currently supports a single type of IOMMU, a Qualcomm System MMU > +(SMMU). The SMMU interface contains functions to map and unmap virtual > +addresses, perform address translations and initialize hardware. A > +Qualcomm SMMU can contain multiple MMU contexts. Each context can > +translate in parallel. All contexts in a SMMU share one global translation > +look-aside buffer (TLB). > + > +To support context muxing the SMMU module creates and manages device > +independent virtual contexts. These context abstractions are bound to > +actual contexts at run-time. Once bound, a context can be activated. This > +activation programs the underlying context with the virtual context > +affecting a context switch. > + > +The following functions are all documented in: > + > + arch/arm/mach-msm/include/mach/smmu_driver.h. > + > +Mapping > +------- > + > +To map and unmap a virtual page into physical space the VCM calls: > + > + int smmu_map(struct smmu_dev *dev, unsigned long pa, > + unsigned long va, unsigned long len, unsigned int attr); > + > + int smmu_unmap(struct smmu_dev *dev, unsigned long va, > + unsigned long len); > + > + int smmu_update_start(struct smmu_dev *dev); > + > + int smmu_update_done(struct smmu_dev *dev); > + > +The size given to map must be 4K, 64K, 1M or 16M and the VA and PA must be > +aligned to the given size. smmu_update_start() and smmu_update_done() > +should be called before and after each map or unmap. > + > +Translation > +----------- > + > +To request a hardware VA to PA translation on a single address the VCM > +calls: > + > + unsigned long smmu_translate(struct smmu_dev *dev, > + unsigned long va); > + > +Fault Handling > +-------------- > + > +To register an interrupt handler for a context the VCM calls: > + > + int smmu_hook_interrupt(struct smmu_dev *dev, vcm_handler handler, > + void *data); > + > +The registered interrupt handler should return 1 if it wants the SMMU > +driver to retry the transaction again and 0 if it wants the SMMU driver to > +terminate the transaction. > + > +Managing SMMU Initialization and Contexts > +----------------------------------------- > + > +SMMU hardware initialization and management happens in 2 steps. The first > +step initializes global SMMU devices and abstract device contexts. The > +second step binds contexts and devices. > + > +An SMMU hardware instance is built with: > + > + int smmu_drvdata_init(struct smmu_driver *drv, unsigned long base, > + int irq); > + > +An SMMU context is initialized and deinitialized with: > + > + struct smmu_dev *smmu_ctx_init(int ctx); > + int smmu_ctx_deinit(struct smmu_dev *dev); > + > +An abstract SMMU context is bound to a particular SMMU with: > + > + int smmu_ctx_bind(struct smmu_dev *ctx, struct smmu_driver *drv); > + > +Activation > +---------- > + > +Activation affects a context switch. > + > +Activation, deactivation and activation state testing are done with: > + > + int smmu_activate(struct smmu_dev *dev); > + int smmu_deactivate(struct smmu_dev *dev); > + int smmu_is_active(struct smmu_dev *dev); > + > + > +Userspace Access to Devices with IOMMUs > +======================================= > + > +A device that issues transactions through an IOMMU must work with two > +APIs. The first API is the VCM. The VCM API is device independent. Users > +pass the VCM a dev_id and the VCM makes calls on the hardware device it > +has been configured with using this dev_id. The second API is whatever > +device topology has been created to organize the particular IOMMUs in a > +system. The only constraint on this second API is that it must give the > +user a single dev_id that it can pass through the VCM. > + > +For the Qualcomm SMMUs the second API consists of a tree of platform > +devices and two platform drivers as well as a context lookup function that > +traverses the device tree and returns a dev_id given a context name. > + > +Qualcomm SMMU Device Tree > +------------------------- > + > +The current tree organizes the devices into a tree that looks like the > +following: > + > +smmu/ > + smmu0/ > + ctx0 > + ctx1 > + ctx2 > + smmu1/ > + ctx3 > + > + > +Each context, ctx[n] and each smmu, smmu[n] is given a name. Since users > +are interested in contexts not smmus, the context name is passed to a > +function to find the dev_id associated with that name. The functions to > +find, free and get the base address (since the device probe function calls > +ioremap to map the SMMUs configuration registers into the kernel) are > +listed here: > + > + struct smmu_dev *smmu_get_ctx_instance(char *ctx_name); > + int smmu_free_ctx_instance(struct smmu_dev *dev); > + unsigned long smmu_get_base_addr(struct smmu_dev *dev); > + > +Documentation for these functions is in: > + > + arch/arm/mach-msm/include/mach/smmu_device.h > + > +Each context is given a dev node named after the context. For example: > + > + /dev/vcodec_a_mm1 > + /dev/vcodec_b_mm2 > + /dev/vcodec_stream > + etc... > + > +Users open, close and mmap these nodes to access VCM buffers from > +userspace in the same way that they used to open, close and mmap /dev > +nodes that represented large physically contiguous buffers (called PMEM > +buffers on Android). > + > +Example > +------- > + > +An abbreviated example is shown here: > + > +Users get the dev_id associated with their target context, create a VCM > +topology appropriate for their device and finally associate the VCMs of > +the topology with the contexts that will take the VCMs: > + > + dev_id = smmu_get_ctx_instance(vcodec_a_stream); > + > +create vcm and needed topology > + > + avcm = vcm_assoc(vcm, dev_id, attr); > + > +Tying it all Together > +--------------------- > + > +VCMs, IOMMUs and the device tree all work to support system-wide memory > +mappings. The use of each API in this system allows users to concentrate > +on the relevant details without needing to worry about low-level > +details. The API's clear separation of memory spaces and the devices that > +support those memory spaces continues the Linux tradition of abstracting the > +what from the how. > + > + > +Maintainer: Zach Pfeffer <zpfeffer@codeaurora.org> > -- > 1.7.0.2 > > -- > Sent by an employee of the Qualcomm Innovation Center, Inc. > The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. > -- > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > Please read the FAQ at http://www.tux.org/lkml/ -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-03 19:06 ` Eric W. Biederman @ 2010-07-07 22:44 ` Zach Pfeffer 2010-07-07 23:07 ` Russell King - ARM Linux 0 siblings, 1 reply; 55+ messages in thread From: Zach Pfeffer @ 2010-07-07 22:44 UTC (permalink / raw) To: Eric W. Biederman Cc: mel, andi, dwalker, linux-mm, linux-kernel, linux-arm-msm, linux-omap, linux-arm-kernel, linux-arch Eric W. Biederman wrote: > Zach Pfeffer <zpfeffer@codeaurora.org> writes: > >> This patch contains the documentation for the API, termed the Virtual >> Contiguous Memory Manager. Its use would allow all of the IOMMU to VM, >> VM to device and device to IOMMU interoperation code to be refactored >> into platform independent code. >> >> Comments, suggestions and criticisms are welcome and wanted. > > How does this differ from the dma api? The DMA API handles the allocation and use of DMA channels. It can configure physical transfer settings, manage scatter-gather lists, etc. The VCM is a different thing. The VCM allows a Virtual Contiguous Memory region to be created and associated with a device that addresses the bus virtually or physically. If the bus is addressed physically the Virtual Contiguous Memory is one-to-one mapped. If the bus is virtually mapped than a contiguous virtual reservation may be backed by a discontiguous list of physical blocks. This discontiguous list could be a SG list of just a list of physical blocks that would back the entire virtual reservation. The VCM allows all device buffers to be passed between all devices in the system without passing those buffers through each domain's API. This means that instead of writing code to interoperate between DMA engines, IOMMU mapped spaces, CPUs and physically addressed devices the user can simply target a device with a buffer using the same API regardless of how that device maps or otherwise accesses the buffer. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-07 22:44 ` Zach Pfeffer @ 2010-07-07 23:07 ` Russell King - ARM Linux 2010-07-08 23:59 ` Zach Pfeffer 0 siblings, 1 reply; 55+ messages in thread From: Russell King - ARM Linux @ 2010-07-07 23:07 UTC (permalink / raw) To: Zach Pfeffer Cc: Eric W. Biederman, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Wed, Jul 07, 2010 at 03:44:27PM -0700, Zach Pfeffer wrote: > The DMA API handles the allocation and use of DMA channels. It can > configure physical transfer settings, manage scatter-gather lists, > etc. You're confused about what the DMA API is. You're talking about the DMA engine subsystem (drivers/dma) not the DMA API (see Documentation/DMA-API.txt, include/linux/dma-mapping.h, and arch/arm/include/asm/dma-mapping.h) > The VCM allows all device buffers to be passed between all devices in > the system without passing those buffers through each domain's > API. This means that instead of writing code to interoperate between > DMA engines, IOMMU mapped spaces, CPUs and physically addressed > devices the user can simply target a device with a buffer using the > same API regardless of how that device maps or otherwise accesses the > buffer. With the DMA API, if we have a SG list which refers to the physical pages (as a struct page, offset, length tuple), the DMA API takes care of dealing with CPU caches and IOMMUs to make the data in the buffer visible to the target device. It provides you with a set of cookies referring to the SG lists, which may be coalesced if the IOMMU can do so. If you have a kernel virtual address, the DMA API has single buffer mapping/unmapping functions to do the same thing, and provide you with a cookie to pass to the device to refer to that buffer. These cookies are whatever the device needs to be able to access the buffer - for instance, if system SDRAM is located at 0xc0000000 virtual, 0x80000000 physical and 0x40000000 as far as the DMA device is concerned, then the cookie for a buffer at 0xc0000000 virtual will be 0x40000000 and not 0x80000000. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-07 23:07 ` Russell King - ARM Linux @ 2010-07-08 23:59 ` Zach Pfeffer 2010-07-12 1:25 ` FUJITA Tomonori 0 siblings, 1 reply; 55+ messages in thread From: Zach Pfeffer @ 2010-07-08 23:59 UTC (permalink / raw) To: Russell King - ARM Linux Cc: Eric W. Biederman, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel Russell King - ARM Linux wrote: > On Wed, Jul 07, 2010 at 03:44:27PM -0700, Zach Pfeffer wrote: >> The DMA API handles the allocation and use of DMA channels. It can >> configure physical transfer settings, manage scatter-gather lists, >> etc. > > You're confused about what the DMA API is. You're talking about > the DMA engine subsystem (drivers/dma) not the DMA API (see > Documentation/DMA-API.txt, include/linux/dma-mapping.h, and > arch/arm/include/asm/dma-mapping.h) Thanks for the clarification. > >> The VCM allows all device buffers to be passed between all devices in >> the system without passing those buffers through each domain's >> API. This means that instead of writing code to interoperate between >> DMA engines, IOMMU mapped spaces, CPUs and physically addressed >> devices the user can simply target a device with a buffer using the >> same API regardless of how that device maps or otherwise accesses the >> buffer. > > With the DMA API, if we have a SG list which refers to the physical > pages (as a struct page, offset, length tuple), the DMA API takes > care of dealing with CPU caches and IOMMUs to make the data in the > buffer visible to the target device. It provides you with a set of > cookies referring to the SG lists, which may be coalesced if the > IOMMU can do so. > > If you have a kernel virtual address, the DMA API has single buffer > mapping/unmapping functions to do the same thing, and provide you > with a cookie to pass to the device to refer to that buffer. > > These cookies are whatever the device needs to be able to access > the buffer - for instance, if system SDRAM is located at 0xc0000000 > virtual, 0x80000000 physical and 0x40000000 as far as the DMA device > is concerned, then the cookie for a buffer at 0xc0000000 virtual will > be 0x40000000 and not 0x80000000. It sounds like I've got some work to do. I appreciate the feedback. The problem I'm trying to solve boils down to this: map a set of contiguous physical buffers to an aligned IOMMU address. I need to allocate the set of physical buffers in a particular way: use 1 MB contiguous physical memory, then 64 KB, then 4 KB, etc. and I need to align the IOMMU address in a particular way. I also need to swap out the IOMMU address spaces and map the buffers into the kernel. I have this all solved, but it sounds like I'll need to migrate to the DMA API to upstream it. -- Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-08 23:59 ` Zach Pfeffer @ 2010-07-12 1:25 ` FUJITA Tomonori 2010-07-13 5:57 ` Zach Pfeffer 0 siblings, 1 reply; 55+ messages in thread From: FUJITA Tomonori @ 2010-07-12 1:25 UTC (permalink / raw) To: zpfeffer Cc: linux, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Thu, 08 Jul 2010 16:59:52 -0700 Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > The problem I'm trying to solve boils down to this: map a set of > contiguous physical buffers to an aligned IOMMU address. I need to > allocate the set of physical buffers in a particular way: use 1 MB > contiguous physical memory, then 64 KB, then 4 KB, etc. and I need to > align the IOMMU address in a particular way. Sounds like the DMA API already supports what you want. You can set segment_boundary_mask in struct device_dma_parameters if you want to align the IOMMU address. See IOMMU implementations that support dma_get_seg_boundary() properly. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-12 1:25 ` FUJITA Tomonori @ 2010-07-13 5:57 ` Zach Pfeffer 2010-07-13 6:03 ` FUJITA Tomonori 0 siblings, 1 reply; 55+ messages in thread From: Zach Pfeffer @ 2010-07-13 5:57 UTC (permalink / raw) To: FUJITA Tomonori Cc: linux, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel FUJITA Tomonori wrote: > On Thu, 08 Jul 2010 16:59:52 -0700 > Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > >> The problem I'm trying to solve boils down to this: map a set of >> contiguous physical buffers to an aligned IOMMU address. I need to >> allocate the set of physical buffers in a particular way: use 1 MB >> contiguous physical memory, then 64 KB, then 4 KB, etc. and I need to >> align the IOMMU address in a particular way. > > Sounds like the DMA API already supports what you want. > > You can set segment_boundary_mask in struct device_dma_parameters if > you want to align the IOMMU address. See IOMMU implementations that > support dma_get_seg_boundary() properly. That function takes the wrong argument in a VCM world: unsigned long dma_get_seg_boundary(struct device *dev); The boundary should be an attribute of the device side mapping, independent of the device. This would allow better code reuse. -- Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-13 5:57 ` Zach Pfeffer @ 2010-07-13 6:03 ` FUJITA Tomonori 2010-07-13 12:14 ` Zach Pfeffer 0 siblings, 1 reply; 55+ messages in thread From: FUJITA Tomonori @ 2010-07-13 6:03 UTC (permalink / raw) To: zpfeffer Cc: fujita.tomonori, linux, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Mon, 12 Jul 2010 22:57:06 -0700 Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > FUJITA Tomonori wrote: > > On Thu, 08 Jul 2010 16:59:52 -0700 > > Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > > > >> The problem I'm trying to solve boils down to this: map a set of > >> contiguous physical buffers to an aligned IOMMU address. I need to > >> allocate the set of physical buffers in a particular way: use 1 MB > >> contiguous physical memory, then 64 KB, then 4 KB, etc. and I need to > >> align the IOMMU address in a particular way. > > > > Sounds like the DMA API already supports what you want. > > > > You can set segment_boundary_mask in struct device_dma_parameters if > > you want to align the IOMMU address. See IOMMU implementations that > > support dma_get_seg_boundary() properly. > > That function takes the wrong argument in a VCM world: > > unsigned long dma_get_seg_boundary(struct device *dev); > > The boundary should be an attribute of the device side mapping, > independent of the device. This would allow better code reuse. You mean that you want to specify this alignment attribute every time you create an IOMMU mapping? Then you can set segment_boundary_mask every time you create an IOMMU mapping. It's odd but it should work. Another possible solution is extending struct dma_attrs. We could add the alignment attribute to it. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-13 6:03 ` FUJITA Tomonori @ 2010-07-13 12:14 ` Zach Pfeffer 2010-07-14 1:59 ` FUJITA Tomonori 0 siblings, 1 reply; 55+ messages in thread From: Zach Pfeffer @ 2010-07-13 12:14 UTC (permalink / raw) To: FUJITA Tomonori Cc: linux, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Tue, Jul 13, 2010 at 03:03:25PM +0900, FUJITA Tomonori wrote: > On Mon, 12 Jul 2010 22:57:06 -0700 > Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > > > FUJITA Tomonori wrote: > > > On Thu, 08 Jul 2010 16:59:52 -0700 > > > Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > > > > > >> The problem I'm trying to solve boils down to this: map a set of > > >> contiguous physical buffers to an aligned IOMMU address. I need to > > >> allocate the set of physical buffers in a particular way: use 1 MB > > >> contiguous physical memory, then 64 KB, then 4 KB, etc. and I need to > > >> align the IOMMU address in a particular way. > > > > > > Sounds like the DMA API already supports what you want. > > > > > > You can set segment_boundary_mask in struct device_dma_parameters if > > > you want to align the IOMMU address. See IOMMU implementations that > > > support dma_get_seg_boundary() properly. > > > > That function takes the wrong argument in a VCM world: > > > > unsigned long dma_get_seg_boundary(struct device *dev); > > > > The boundary should be an attribute of the device side mapping, > > independent of the device. This would allow better code reuse. > > You mean that you want to specify this alignment attribute every time > you create an IOMMU mapping? Then you can set segment_boundary_mask > every time you create an IOMMU mapping. It's odd but it should work. Kinda. I want to forget about IOMMUs, devices and CPUs. I just want to create a mapping that has the alignment I specify, regardless of the mapper. The mapping is created on a VCM and the VCM is associated with a mapper: a CPU, an IOMMU'd device or a direct mapped device. > > Another possible solution is extending struct dma_attrs. We could add > the alignment attribute to it. That may be useful, but in the current DMA-API may be seen as redundant info. -- Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-13 12:14 ` Zach Pfeffer @ 2010-07-14 1:59 ` FUJITA Tomonori 2010-07-14 20:11 ` Zach Pfeffer 0 siblings, 1 reply; 55+ messages in thread From: FUJITA Tomonori @ 2010-07-14 1:59 UTC (permalink / raw) To: zpfeffer Cc: fujita.tomonori, linux, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Tue, 13 Jul 2010 05:14:21 -0700 Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > > You mean that you want to specify this alignment attribute every time > > you create an IOMMU mapping? Then you can set segment_boundary_mask > > every time you create an IOMMU mapping. It's odd but it should work. > > Kinda. I want to forget about IOMMUs, devices and CPUs. I just want to > create a mapping that has the alignment I specify, regardless of the > mapper. The mapping is created on a VCM and the VCM is associated with > a mapper: a CPU, an IOMMU'd device or a direct mapped device. Sounds like you can do the above with the combination of the current APIs, create a virtual address and then an I/O address. The above can't be a reason to add a new infrastructure includes more than 3,000 lines. > > Another possible solution is extending struct dma_attrs. We could add > > the alignment attribute to it. > > That may be useful, but in the current DMA-API may be seen as > redundant info. If there is real requirement, we can extend the DMA-API. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-14 1:59 ` FUJITA Tomonori @ 2010-07-14 20:11 ` Zach Pfeffer 2010-07-14 22:05 ` Russell King - ARM Linux 2010-07-14 23:07 ` FUJITA Tomonori 0 siblings, 2 replies; 55+ messages in thread From: Zach Pfeffer @ 2010-07-14 20:11 UTC (permalink / raw) To: FUJITA Tomonori Cc: linux, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Wed, Jul 14, 2010 at 10:59:38AM +0900, FUJITA Tomonori wrote: > On Tue, 13 Jul 2010 05:14:21 -0700 > Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > > > > You mean that you want to specify this alignment attribute every time > > > you create an IOMMU mapping? Then you can set segment_boundary_mask > > > every time you create an IOMMU mapping. It's odd but it should work. > > > > Kinda. I want to forget about IOMMUs, devices and CPUs. I just want to > > create a mapping that has the alignment I specify, regardless of the > > mapper. The mapping is created on a VCM and the VCM is associated with > > a mapper: a CPU, an IOMMU'd device or a direct mapped device. > > Sounds like you can do the above with the combination of the current > APIs, create a virtual address and then an I/O address. > Yes, and that's what the implementation does - and all the other implementations that need to do this same thing. Why not solve the problem once? > The above can't be a reason to add a new infrastructure includes more > than 3,000 lines. Right now its 3000 lines because I haven't converted to a function pointer based implementation. Once I do that the size of the implementation will shrink and the code will act as a lib. Users pass buffer mappers and the lib will ease the management of of those buffers. > > > > > Another possible solution is extending struct dma_attrs. We could add > > > the alignment attribute to it. > > > > That may be useful, but in the current DMA-API may be seen as > > redundant info. > > If there is real requirement, we can extend the DMA-API. If the DMA-API contained functions to allocate virtual space separate from physical space and reworked how chained buffers functioned it would probably work - but then things start to look like the VCM API which does graph based map management. > > -- > To unsubscribe, send a message with 'unsubscribe linux-mm' in > the body to majordomo@kvack.org. For more info on Linux MM, > see: http://www.linux-mm.org/ . > Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-14 20:11 ` Zach Pfeffer @ 2010-07-14 22:05 ` Russell King - ARM Linux 2010-07-15 1:29 ` Zach Pfeffer 2010-07-14 23:07 ` FUJITA Tomonori 1 sibling, 1 reply; 55+ messages in thread From: Russell King - ARM Linux @ 2010-07-14 22:05 UTC (permalink / raw) To: Zach Pfeffer Cc: FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Wed, Jul 14, 2010 at 01:11:49PM -0700, Zach Pfeffer wrote: > If the DMA-API contained functions to allocate virtual space separate > from physical space and reworked how chained buffers functioned it > would probably work - but then things start to look like the VCM API > which does graph based map management. Every additional virtual mapping of a physical buffer results in additional cache aliases on aliasing caches, and more workload for developers to sort out the cache aliasing issues. What does VCM to do mitigate that? -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-14 22:05 ` Russell King - ARM Linux @ 2010-07-15 1:29 ` Zach Pfeffer 2010-07-15 1:47 ` Eric W. Biederman ` (2 more replies) 0 siblings, 3 replies; 55+ messages in thread From: Zach Pfeffer @ 2010-07-15 1:29 UTC (permalink / raw) To: Russell King - ARM Linux Cc: FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Wed, Jul 14, 2010 at 11:05:36PM +0100, Russell King - ARM Linux wrote: > On Wed, Jul 14, 2010 at 01:11:49PM -0700, Zach Pfeffer wrote: > > If the DMA-API contained functions to allocate virtual space separate > > from physical space and reworked how chained buffers functioned it > > would probably work - but then things start to look like the VCM API > > which does graph based map management. > > Every additional virtual mapping of a physical buffer results in > additional cache aliases on aliasing caches, and more workload for > developers to sort out the cache aliasing issues. > > What does VCM to do mitigate that? The VCM ensures that all mappings that map a given physical buffer: IOMMU mappings, CPU mappings and one-to-one device mappings all map that buffer using the same (or compatible) attributes. At this point the only attribute that users can pass is CACHED. In the absence of CACHED all accesses go straight through to the physical memory. The architecture of the VCM allows these sorts of consistency checks to be made since all mappers of a given physical resource are tracked. This is feasible because the physical resources we're tracking are typically large. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-15 1:29 ` Zach Pfeffer @ 2010-07-15 1:47 ` Eric W. Biederman 2010-07-15 5:40 ` Zach Pfeffer 2010-07-15 5:35 ` Zach Pfeffer 2010-07-15 8:55 ` Russell King - ARM Linux 2 siblings, 1 reply; 55+ messages in thread From: Eric W. Biederman @ 2010-07-15 1:47 UTC (permalink / raw) To: Zach Pfeffer Cc: Russell King - ARM Linux, FUJITA Tomonori, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel Zach Pfeffer <zpfeffer@codeaurora.org> writes: > On Wed, Jul 14, 2010 at 11:05:36PM +0100, Russell King - ARM Linux wrote: >> On Wed, Jul 14, 2010 at 01:11:49PM -0700, Zach Pfeffer wrote: >> > If the DMA-API contained functions to allocate virtual space separate >> > from physical space and reworked how chained buffers functioned it >> > would probably work - but then things start to look like the VCM API >> > which does graph based map management. >> >> Every additional virtual mapping of a physical buffer results in >> additional cache aliases on aliasing caches, and more workload for >> developers to sort out the cache aliasing issues. >> >> What does VCM to do mitigate that? > > The VCM ensures that all mappings that map a given physical buffer: > IOMMU mappings, CPU mappings and one-to-one device mappings all map > that buffer using the same (or compatible) attributes. At this point > the only attribute that users can pass is CACHED. In the absence of > CACHED all accesses go straight through to the physical memory. > > The architecture of the VCM allows these sorts of consistency checks > to be made since all mappers of a given physical resource are > tracked. This is feasible because the physical resources we're > tracking are typically large. On x86 this is implemented in the pat code, and could reasonably be generalized to be cross platform. This is controlled by HAVE_PFNMAP_TRACKING and with entry points like track_pfn_vma_new. Given that we already have an implementation that tracks the cached vs non-cached attribute using the dma api. I don't see that the API has to change. An implementation of the cached vs non-cached status for arm and other architectures is probably appropriate. It is definitely true that getting your mapping caching attributes out of sync can be a problem. Eric -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-15 1:47 ` Eric W. Biederman @ 2010-07-15 5:40 ` Zach Pfeffer 0 siblings, 0 replies; 55+ messages in thread From: Zach Pfeffer @ 2010-07-15 5:40 UTC (permalink / raw) To: Eric W. Biederman Cc: Russell King - ARM Linux, FUJITA Tomonori, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Wed, Jul 14, 2010 at 06:47:34PM -0700, Eric W. Biederman wrote: > Zach Pfeffer <zpfeffer@codeaurora.org> writes: > > > On Wed, Jul 14, 2010 at 11:05:36PM +0100, Russell King - ARM Linux wrote: > >> On Wed, Jul 14, 2010 at 01:11:49PM -0700, Zach Pfeffer wrote: > >> > If the DMA-API contained functions to allocate virtual space separate > >> > from physical space and reworked how chained buffers functioned it > >> > would probably work - but then things start to look like the VCM API > >> > which does graph based map management. > >> > >> Every additional virtual mapping of a physical buffer results in > >> additional cache aliases on aliasing caches, and more workload for > >> developers to sort out the cache aliasing issues. > >> > >> What does VCM to do mitigate that? > > > > The VCM ensures that all mappings that map a given physical buffer: > > IOMMU mappings, CPU mappings and one-to-one device mappings all map > > that buffer using the same (or compatible) attributes. At this point > > the only attribute that users can pass is CACHED. In the absence of > > CACHED all accesses go straight through to the physical memory. > > > > The architecture of the VCM allows these sorts of consistency checks > > to be made since all mappers of a given physical resource are > > tracked. This is feasible because the physical resources we're > > tracking are typically large. > > On x86 this is implemented in the pat code, and could reasonably be > generalized to be cross platform. > > This is controlled by HAVE_PFNMAP_TRACKING and with entry points > like track_pfn_vma_new. > > Given that we already have an implementation that tracks the cached > vs non-cached attribute using the dma api. I don't see that the > API has to change. An implementation of the cached vs non-cached > status for arm and other architectures is probably appropriate. > > It is definitely true that getting your mapping caching attributes > out of sync can be a problem. Sure, but we're still stuck with needing lots of scatterlist list elements and needing to copy them to share physical buffers. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-15 1:29 ` Zach Pfeffer 2010-07-15 1:47 ` Eric W. Biederman @ 2010-07-15 5:35 ` Zach Pfeffer 2010-07-15 8:55 ` Russell King - ARM Linux 2 siblings, 0 replies; 55+ messages in thread From: Zach Pfeffer @ 2010-07-15 5:35 UTC (permalink / raw) To: Russell King - ARM Linux Cc: FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Wed, Jul 14, 2010 at 06:29:58PM -0700, Zach Pfeffer wrote: > On Wed, Jul 14, 2010 at 11:05:36PM +0100, Russell King - ARM Linux wrote: > > On Wed, Jul 14, 2010 at 01:11:49PM -0700, Zach Pfeffer wrote: > > > If the DMA-API contained functions to allocate virtual space separate > > > from physical space and reworked how chained buffers functioned it > > > would probably work - but then things start to look like the VCM API > > > which does graph based map management. > > > > Every additional virtual mapping of a physical buffer results in > > additional cache aliases on aliasing caches, and more workload for > > developers to sort out the cache aliasing issues. > > > > What does VCM to do mitigate that? > > The VCM ensures that all mappings that map a given physical buffer: > IOMMU mappings, CPU mappings and one-to-one device mappings all map > that buffer using the same (or compatible) attributes. At this point > the only attribute that users can pass is CACHED. In the absence of > CACHED all accesses go straight through to the physical memory. > > The architecture of the VCM allows these sorts of consistency checks > to be made since all mappers of a given physical resource are > tracked. This is feasible because the physical resources we're > tracking are typically large. A few more things... In addition to CACHED, the VCMM can support different cache policies as long as the architecture can support it - they get passed down through the device map call. In addition, handling physical mappings in the VCMM enables it to perform refcounting on the physical chunks (ie, to see how many virtual spaces it's been mapped to, including the kernel's). This allows it to turn on any coherency protocols that are available in hardware (ie, setting the shareable bit on something that is mapped to more than one virtual space). That same attribute can be left off on a buffer that has only one virtual mapping (ie, scratch buffers used by one device only). It is then up to the underlying system to deal with that shared attribute - to enable redirection if it's supported, or to force something to be non-cacheable, etc. Doing it all through the VCMM allows all these mechanisms be worked out once per architecture and then reused. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-15 1:29 ` Zach Pfeffer 2010-07-15 1:47 ` Eric W. Biederman 2010-07-15 5:35 ` Zach Pfeffer @ 2010-07-15 8:55 ` Russell King - ARM Linux 2010-07-16 0:48 ` Tim HRM 2010-07-19 6:52 ` Zach Pfeffer 2 siblings, 2 replies; 55+ messages in thread From: Russell King - ARM Linux @ 2010-07-15 8:55 UTC (permalink / raw) To: Zach Pfeffer Cc: FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Wed, Jul 14, 2010 at 06:29:58PM -0700, Zach Pfeffer wrote: > The VCM ensures that all mappings that map a given physical buffer: > IOMMU mappings, CPU mappings and one-to-one device mappings all map > that buffer using the same (or compatible) attributes. At this point > the only attribute that users can pass is CACHED. In the absence of > CACHED all accesses go straight through to the physical memory. So what you're saying is that if I have a buffer in kernel space which I already have its virtual address, I can pass this to VCM and tell it !CACHED, and it'll setup another mapping which is not cached for me? You are aware that multiple V:P mappings for the same physical page with different attributes are being outlawed with ARMv6 and ARMv7 due to speculative prefetching. The cache can be searched even for a mapping specified as 'normal, uncached' and you can get cache hits because the data has been speculatively loaded through a separate cached mapping of the same physical page. FYI, during the next merge window, I will be pushing a patch which makes ioremap() of system RAM fail, which should be the last core code creator of mappings with different memory types. This behaviour has been outlawed (as unpredictable) in the architecture specification and does cause problems on some CPUs. We've also the issue of multiple mappings with differing cache attributes which needs addressing too... -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-15 8:55 ` Russell King - ARM Linux @ 2010-07-16 0:48 ` Tim HRM 2010-07-16 7:58 ` Russell King - ARM Linux 2010-07-19 6:52 ` Zach Pfeffer 1 sibling, 1 reply; 55+ messages in thread From: Tim HRM @ 2010-07-16 0:48 UTC (permalink / raw) To: Russell King - ARM Linux Cc: Zach Pfeffer, FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Thu, Jul 15, 2010 at 4:55 AM, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote: > On Wed, Jul 14, 2010 at 06:29:58PM -0700, Zach Pfeffer wrote: >> The VCM ensures that all mappings that map a given physical buffer: >> IOMMU mappings, CPU mappings and one-to-one device mappings all map >> that buffer using the same (or compatible) attributes. At this point >> the only attribute that users can pass is CACHED. In the absence of >> CACHED all accesses go straight through to the physical memory. > > So what you're saying is that if I have a buffer in kernel space > which I already have its virtual address, I can pass this to VCM and > tell it !CACHED, and it'll setup another mapping which is not cached > for me? > > You are aware that multiple V:P mappings for the same physical page > with different attributes are being outlawed with ARMv6 and ARMv7 > due to speculative prefetching. The cache can be searched even for > a mapping specified as 'normal, uncached' and you can get cache hits > because the data has been speculatively loaded through a separate > cached mapping of the same physical page. > > FYI, during the next merge window, I will be pushing a patch which makes > ioremap() of system RAM fail, which should be the last core code creator > of mappings with different memory types. This behaviour has been outlawed > (as unpredictable) in the architecture specification and does cause > problems on some CPUs. > > We've also the issue of multiple mappings with differing cache attributes > which needs addressing too... > -- > To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > Interesting, since I seem to remember the MSM devices mostly conduct IO through regions of normal RAM, largely accomplished through ioremap() calls. Without more public domain documentation of the MSM chips and AMSS interfaces I wouldn't know how to avoid this, but I can imagine it creates a bit of urgency for Qualcomm developers as they attempt to upstream support for this most interesting SoC. -- Timothy Meade tmzt #htc-linux -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-16 0:48 ` Tim HRM @ 2010-07-16 7:58 ` Russell King - ARM Linux 2010-07-17 0:01 ` Larry Bassel ` (2 more replies) 0 siblings, 3 replies; 55+ messages in thread From: Russell King - ARM Linux @ 2010-07-16 7:58 UTC (permalink / raw) To: Tim HRM Cc: Zach Pfeffer, FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Thu, Jul 15, 2010 at 08:48:36PM -0400, Tim HRM wrote: > Interesting, since I seem to remember the MSM devices mostly conduct > IO through regions of normal RAM, largely accomplished through > ioremap() calls. > > Without more public domain documentation of the MSM chips and AMSS > interfaces I wouldn't know how to avoid this, but I can imagine it > creates a bit of urgency for Qualcomm developers as they attempt to > upstream support for this most interesting SoC. As the patch has been out for RFC since early April on the linux-arm-kernel mailing list (Subject: [RFC] Prohibit ioremap() on kernel managed RAM), and no comments have come back from Qualcomm folk. The restriction on creation of multiple V:P mappings with differing attributes is also fairly hard to miss in the ARM architecture specification when reading the sections about caches. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-16 7:58 ` Russell King - ARM Linux @ 2010-07-17 0:01 ` Larry Bassel 2010-07-19 9:21 ` Tim HRM 2010-07-19 17:55 ` Michael Bohan 2010-07-20 20:45 ` Zach Pfeffer 2 siblings, 1 reply; 55+ messages in thread From: Larry Bassel @ 2010-07-17 0:01 UTC (permalink / raw) To: Russell King - ARM Linux Cc: Tim HRM, Zach Pfeffer, FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On 16 Jul 10 08:58, Russell King - ARM Linux wrote: > On Thu, Jul 15, 2010 at 08:48:36PM -0400, Tim HRM wrote: > > Interesting, since I seem to remember the MSM devices mostly conduct > > IO through regions of normal RAM, largely accomplished through > > ioremap() calls. > > > > Without more public domain documentation of the MSM chips and AMSS > > interfaces I wouldn't know how to avoid this, but I can imagine it > > creates a bit of urgency for Qualcomm developers as they attempt to > > upstream support for this most interesting SoC. > > As the patch has been out for RFC since early April on the linux-arm-kernel > mailing list (Subject: [RFC] Prohibit ioremap() on kernel managed RAM), > and no comments have come back from Qualcomm folk. We are investigating the impact of this change on us, and I will send out more detailed comments next week. > > The restriction on creation of multiple V:P mappings with differing > attributes is also fairly hard to miss in the ARM architecture > specification when reading the sections about caches. > Larry Bassel -- Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-17 0:01 ` Larry Bassel @ 2010-07-19 9:21 ` Tim HRM 2010-07-21 0:44 ` Zach Pfeffer 0 siblings, 1 reply; 55+ messages in thread From: Tim HRM @ 2010-07-19 9:21 UTC (permalink / raw) To: Larry Bassel Cc: Russell King - ARM Linux, Zach Pfeffer, FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Fri, Jul 16, 2010 at 8:01 PM, Larry Bassel <lbassel@codeaurora.org> wrote: > On 16 Jul 10 08:58, Russell King - ARM Linux wrote: >> On Thu, Jul 15, 2010 at 08:48:36PM -0400, Tim HRM wrote: >> > Interesting, since I seem to remember the MSM devices mostly conduct >> > IO through regions of normal RAM, largely accomplished through >> > ioremap() calls. >> > >> > Without more public domain documentation of the MSM chips and AMSS >> > interfaces I wouldn't know how to avoid this, but I can imagine it >> > creates a bit of urgency for Qualcomm developers as they attempt to >> > upstream support for this most interesting SoC. >> >> As the patch has been out for RFC since early April on the linux-arm-kernel >> mailing list (Subject: [RFC] Prohibit ioremap() on kernel managed RAM), >> and no comments have come back from Qualcomm folk. > > We are investigating the impact of this change on us, and I > will send out more detailed comments next week. > >> >> The restriction on creation of multiple V:P mappings with differing >> attributes is also fairly hard to miss in the ARM architecture >> specification when reading the sections about caches. >> > > Larry Bassel > > -- > Sent by an employee of the Qualcomm Innovation Center, Inc. > The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. > Hi Larry and Qualcomm people. I'm curious what your reason for introducing this new api (or adding to dma) is. Specifically how this would be used to make the memory mapping of the MSM chip dynamic in contrast to the fixed _PHYS defines in the Android and Codeaurora trees. I'm also interested in how this ability to map memory regions as files for devices like KGSL/DRI or PMEM might work and why this is better suited to that purpose than existing methods, where this fits into camera preview and other issues that have been dealt with in these trees in novel ways (from my perspective). Thanks, Timothy Meade tmzt #htc-linux -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-19 9:21 ` Tim HRM @ 2010-07-21 0:44 ` Zach Pfeffer 2010-07-21 1:44 ` Timothy Meade 0 siblings, 1 reply; 55+ messages in thread From: Zach Pfeffer @ 2010-07-21 0:44 UTC (permalink / raw) To: Tim HRM Cc: Larry Bassel, Russell King - ARM Linux, FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Mon, Jul 19, 2010 at 05:21:35AM -0400, Tim HRM wrote: > On Fri, Jul 16, 2010 at 8:01 PM, Larry Bassel <lbassel@codeaurora.org> wrote: > > On 16 Jul 10 08:58, Russell King - ARM Linux wrote: > >> On Thu, Jul 15, 2010 at 08:48:36PM -0400, Tim HRM wrote: > >> > Interesting, since I seem to remember the MSM devices mostly conduct > >> > IO through regions of normal RAM, largely accomplished through > >> > ioremap() calls. > >> > > >> > Without more public domain documentation of the MSM chips and AMSS > >> > interfaces I wouldn't know how to avoid this, but I can imagine it > >> > creates a bit of urgency for Qualcomm developers as they attempt to > >> > upstream support for this most interesting SoC. > >> > >> As the patch has been out for RFC since early April on the linux-arm-kernel > >> mailing list (Subject: [RFC] Prohibit ioremap() on kernel managed RAM), > >> and no comments have come back from Qualcomm folk. > > > > We are investigating the impact of this change on us, and I > > will send out more detailed comments next week. > > > >> > >> The restriction on creation of multiple V:P mappings with differing > >> attributes is also fairly hard to miss in the ARM architecture > >> specification when reading the sections about caches. > >> > > > > Larry Bassel > > > > -- > > Sent by an employee of the Qualcomm Innovation Center, Inc. > > The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. > > > > Hi Larry and Qualcomm people. > I'm curious what your reason for introducing this new api (or adding > to dma) is. Specifically how this would be used to make the memory > mapping of the MSM chip dynamic in contrast to the fixed _PHYS defines > in the Android and Codeaurora trees. The MSM has many integrated engines that allow offloading a variety of workloads. These engines have always addressed memory using physical addresses, because of this we had to reserve large (10's MB) buffers at boot. These buffers are never freed regardless of whether an engine is actually using them. As you can imagine, needing to reserve memory for all time on a device that doesn't have a lot of memory in the first place is not ideal because that memory could be used for other things, running apps, etc. To solve this problem we put IOMMUs in front of a lot of the engines. IOMMUs allow us to map physically discontiguous memory into a virtually contiguous address range. This means that we could ask the OS for 10 MB of pages and map all of these into our IOMMU space and the engine would still see a contiguous range. In reality, limitations in the hardware meant that we needed to map memory using larger mappings to minimize the number of TLB misses. This, plus the number of IOMMUs and the extreme use cases we needed to design for led us to a generic design. This generic design solved our problem and the general mapping problem. We thought other people, who had this same big-buffer interoperation problem would also appreciate a common API that was built with their needs in mind so we pushed our idea up. > > I'm also interested in how this ability to map memory regions as files > for devices like KGSL/DRI or PMEM might work and why this is better > suited to that purpose than existing methods, where this fits into > camera preview and other issues that have been dealt with in these > trees in novel ways (from my perspective). The file based approach was driven by Android's buffer passing scheme and the need to write userspace drivers for multimedia, etc... -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-21 0:44 ` Zach Pfeffer @ 2010-07-21 1:44 ` Timothy Meade 2010-07-22 4:06 ` Zach Pfeffer 0 siblings, 1 reply; 55+ messages in thread From: Timothy Meade @ 2010-07-21 1:44 UTC (permalink / raw) To: Zach Pfeffer Cc: Larry Bassel, Russell King - ARM Linux, FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Tue, Jul 20, 2010 at 8:44 PM, Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > On Mon, Jul 19, 2010 at 05:21:35AM -0400, Tim HRM wrote: >> On Fri, Jul 16, 2010 at 8:01 PM, Larry Bassel <lbassel@codeaurora.org> wrote: >> > On 16 Jul 10 08:58, Russell King - ARM Linux wrote: >> >> On Thu, Jul 15, 2010 at 08:48:36PM -0400, Tim HRM wrote: >> >> > Interesting, since I seem to remember the MSM devices mostly conduct >> >> > IO through regions of normal RAM, largely accomplished through >> >> > ioremap() calls. >> >> > >> >> > Without more public domain documentation of the MSM chips and AMSS >> >> > interfaces I wouldn't know how to avoid this, but I can imagine it >> >> > creates a bit of urgency for Qualcomm developers as they attempt to >> >> > upstream support for this most interesting SoC. >> >> >> >> As the patch has been out for RFC since early April on the linux-arm-kernel >> >> mailing list (Subject: [RFC] Prohibit ioremap() on kernel managed RAM), >> >> and no comments have come back from Qualcomm folk. >> > >> > We are investigating the impact of this change on us, and I >> > will send out more detailed comments next week. >> > >> >> >> >> The restriction on creation of multiple V:P mappings with differing >> >> attributes is also fairly hard to miss in the ARM architecture >> >> specification when reading the sections about caches. >> >> >> > >> > Larry Bassel >> > >> > -- >> > Sent by an employee of the Qualcomm Innovation Center, Inc. >> > The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. >> > >> >> Hi Larry and Qualcomm people. >> I'm curious what your reason for introducing this new api (or adding >> to dma) is. Specifically how this would be used to make the memory >> mapping of the MSM chip dynamic in contrast to the fixed _PHYS defines >> in the Android and Codeaurora trees. > > The MSM has many integrated engines that allow offloading a variety of > workloads. These engines have always addressed memory using physical > addresses, because of this we had to reserve large (10's MB) buffers > at boot. These buffers are never freed regardless of whether an engine > is actually using them. As you can imagine, needing to reserve memory > for all time on a device that doesn't have a lot of memory in the > first place is not ideal because that memory could be used for other > things, running apps, etc. > > To solve this problem we put IOMMUs in front of a lot of the > engines. IOMMUs allow us to map physically discontiguous memory into a > virtually contiguous address range. This means that we could ask the > OS for 10 MB of pages and map all of these into our IOMMU space and > the engine would still see a contiguous range. > I see. Much like I suspected, this is used to replace the static regime of the earliest Android kernel. You mention placing IOMMUs in front of the A11 engines, you are involved in this architecture as an engineer or similar? Is there a reason a cooperative approach using RPC or another mechanism is not used for memory reservation, this is something that can be accomplished fully on APPS side? > In reality, limitations in the hardware meant that we needed to map > memory using larger mappings to minimize the number of TLB > misses. This, plus the number of IOMMUs and the extreme use cases we > needed to design for led us to a generic design. > > This generic design solved our problem and the general mapping > problem. We thought other people, who had this same big-buffer > interoperation problem would also appreciate a common API that was > built with their needs in mind so we pushed our idea up. > >> >> I'm also interested in how this ability to map memory regions as files >> for devices like KGSL/DRI or PMEM might work and why this is better >> suited to that purpose than existing methods, where this fits into >> camera preview and other issues that have been dealt with in these >> trees in novel ways (from my perspective). > > The file based approach was driven by Android's buffer passing scheme > and the need to write userspace drivers for multimedia, etc... > > So the Android file backed approach is obiviated by GEM and other mechanisms? Thanks you for you help, Timothy Meade -tmzt #htc-linux (facebook.com/HTCLinux) -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-21 1:44 ` Timothy Meade @ 2010-07-22 4:06 ` Zach Pfeffer 0 siblings, 0 replies; 55+ messages in thread From: Zach Pfeffer @ 2010-07-22 4:06 UTC (permalink / raw) To: Timothy Meade Cc: Larry Bassel, Russell King - ARM Linux, FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Tue, Jul 20, 2010 at 09:44:12PM -0400, Timothy Meade wrote: > On Tue, Jul 20, 2010 at 8:44 PM, Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > > On Mon, Jul 19, 2010 at 05:21:35AM -0400, Tim HRM wrote: > >> On Fri, Jul 16, 2010 at 8:01 PM, Larry Bassel <lbassel@codeaurora.org> wrote: > >> > On 16 Jul 10 08:58, Russell King - ARM Linux wrote: > >> >> On Thu, Jul 15, 2010 at 08:48:36PM -0400, Tim HRM wrote: > >> >> > Interesting, since I seem to remember the MSM devices mostly conduct > >> >> > IO through regions of normal RAM, largely accomplished through > >> >> > ioremap() calls. > >> >> > > >> >> > Without more public domain documentation of the MSM chips and AMSS > >> >> > interfaces I wouldn't know how to avoid this, but I can imagine it > >> >> > creates a bit of urgency for Qualcomm developers as they attempt to > >> >> > upstream support for this most interesting SoC. > >> >> > >> >> As the patch has been out for RFC since early April on the linux-arm-kernel > >> >> mailing list (Subject: [RFC] Prohibit ioremap() on kernel managed RAM), > >> >> and no comments have come back from Qualcomm folk. > >> > > >> > We are investigating the impact of this change on us, and I > >> > will send out more detailed comments next week. > >> > > >> >> > >> >> The restriction on creation of multiple V:P mappings with differing > >> >> attributes is also fairly hard to miss in the ARM architecture > >> >> specification when reading the sections about caches. > >> >> > >> > > >> > Larry Bassel > >> > > >> > -- > >> > Sent by an employee of the Qualcomm Innovation Center, Inc. > >> > The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. > >> > > >> > >> Hi Larry and Qualcomm people. > >> I'm curious what your reason for introducing this new api (or adding > >> to dma) is. ?Specifically how this would be used to make the memory > >> mapping of the MSM chip dynamic in contrast to the fixed _PHYS defines > >> in the Android and Codeaurora trees. > > > > The MSM has many integrated engines that allow offloading a variety of > > workloads. These engines have always addressed memory using physical > > addresses, because of this we had to reserve large (10's MB) buffers > > at boot. These buffers are never freed regardless of whether an engine > > is actually using them. As you can imagine, needing to reserve memory > > for all time on a device that doesn't have a lot of memory in the > > first place is not ideal because that memory could be used for other > > things, running apps, etc. > > > > To solve this problem we put IOMMUs in front of a lot of the > > engines. IOMMUs allow us to map physically discontiguous memory into a > > virtually contiguous address range. This means that we could ask the > > OS for 10 MB of pages and map all of these into our IOMMU space and > > the engine would still see a contiguous range. > > > > > I see. Much like I suspected, this is used to replace the static > regime of the earliest Android kernel. You mention placing IOMMUs in > front of the A11 engines, you are involved in this architecture as an > engineer or similar? I'm involved to the extent of designing and implementing VCM and, finding it useful for this class of problems, trying push it upstream. > Is there a reason a cooperative approach using > RPC or another mechanism is not used for memory reservation, this is > something that can be accomplished fully on APPS side? It can be accomplished a few ways. At this point we let the application processor manage the buffers. Other cooperative approaches have been talked about. As you can see in the short, but voluminous cannon of MSM Linux support there is a degree of RPC used to communicate with other nodes in the system. As time progresses the cannon of code shows this usage going down. > > > In reality, limitations in the hardware meant that we needed to map > > memory using larger mappings to minimize the number of TLB > > misses. This, plus the number of IOMMUs and the extreme use cases we > > needed to design for led us to a generic design. > > > > This generic design solved our problem and the general mapping > > problem. We thought other people, who had this same big-buffer > > interoperation problem would also appreciate a common API that was > > built with their needs in mind so we pushed our idea up. > > > >> > >> I'm also interested in how this ability to map memory regions as files > >> for devices like KGSL/DRI or PMEM might work and why this is better > >> suited to that purpose than existing methods, where this fits into > >> camera preview and other issues that have been dealt with in these > >> trees in novel ways (from my perspective). > > > > The file based approach was driven by Android's buffer passing scheme > > and the need to write userspace drivers for multimedia, etc... > > > > > So the Android file backed approach is obiviated by GEM and other mechanisms? Aye. > > Thanks you for you help, > Timothy Meade > -tmzt #htc-linux (facebook.com/HTCLinux) -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-16 7:58 ` Russell King - ARM Linux 2010-07-17 0:01 ` Larry Bassel @ 2010-07-19 17:55 ` Michael Bohan 2010-07-19 18:40 ` Russell King - ARM Linux 2010-07-20 20:45 ` Zach Pfeffer 2 siblings, 1 reply; 55+ messages in thread From: Michael Bohan @ 2010-07-19 17:55 UTC (permalink / raw) To: Russell King - ARM Linux Cc: Tim HRM, Zach Pfeffer, FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On 7/16/2010 12:58 AM, Russell King - ARM Linux wrote: > As the patch has been out for RFC since early April on the linux-arm-kernel > mailing list (Subject: [RFC] Prohibit ioremap() on kernel managed RAM), > and no comments have come back from Qualcomm folk. Would it be unreasonable to allow a map request to succeed if the requested attributes matched that of the preexisting mapping? Michael -- Employee of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-19 17:55 ` Michael Bohan @ 2010-07-19 18:40 ` Russell King - ARM Linux 2010-07-20 22:02 ` stepanm 0 siblings, 1 reply; 55+ messages in thread From: Russell King - ARM Linux @ 2010-07-19 18:40 UTC (permalink / raw) To: Michael Bohan Cc: Tim HRM, Zach Pfeffer, FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Mon, Jul 19, 2010 at 10:55:15AM -0700, Michael Bohan wrote: > > On 7/16/2010 12:58 AM, Russell King - ARM Linux wrote: > >> As the patch has been out for RFC since early April on the linux-arm-kernel >> mailing list (Subject: [RFC] Prohibit ioremap() on kernel managed RAM), >> and no comments have come back from Qualcomm folk. > > Would it be unreasonable to allow a map request to succeed if the > requested attributes matched that of the preexisting mapping? What would be the point of creating such a mapping? -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-19 18:40 ` Russell King - ARM Linux @ 2010-07-20 22:02 ` stepanm 2010-07-20 22:29 ` Russell King - ARM Linux 0 siblings, 1 reply; 55+ messages in thread From: stepanm @ 2010-07-20 22:02 UTC (permalink / raw) To: Russell King - ARM Linux Cc: Michael Bohan, Tim HRM, Zach Pfeffer, FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel Russell- If a driver wants to allow a device to access memory (and cache coherency is off/not present for device addesses), the driver needs to remap that memory as non-cacheable. Suppose there exists a chunk of physically-contiguous memory (say, memory reserved for device use) that happened to be already mapped into the kernel as normal memory (cacheable, etc). One way to remap this memory is to use ioremap (and then never touch the original virtual mapping, which would now have conflicting attributes). I feel as if there should be a better way to remap memory for device access, either by altering the attributes on the original mapping, or removing the original mapping and creating a new one with attributes set to non-cacheable. Is there a better way to do this than calling ioremap() on that memory? Please advise. Thanks Steve Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. > On Mon, Jul 19, 2010 at 10:55:15AM -0700, Michael Bohan wrote: >> >> On 7/16/2010 12:58 AM, Russell King - ARM Linux wrote: >> >>> As the patch has been out for RFC since early April on the >>> linux-arm-kernel >>> mailing list (Subject: [RFC] Prohibit ioremap() on kernel managed RAM), >>> and no comments have come back from Qualcomm folk. >> >> Would it be unreasonable to allow a map request to succeed if the >> requested attributes matched that of the preexisting mapping? > > What would be the point of creating such a mapping? > -- > To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" > in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-20 22:02 ` stepanm @ 2010-07-20 22:29 ` Russell King - ARM Linux 2010-07-21 5:49 ` Shilimkar, Santosh 0 siblings, 1 reply; 55+ messages in thread From: Russell King - ARM Linux @ 2010-07-20 22:29 UTC (permalink / raw) To: stepanm Cc: Michael Bohan, Tim HRM, Zach Pfeffer, FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Tue, Jul 20, 2010 at 03:02:34PM -0700, stepanm@codeaurora.org wrote: > Russell- > > If a driver wants to allow a device to access memory (and cache coherency > is off/not present for device addesses), the driver needs to remap that > memory as non-cacheable. If that memory is not part of the kernel's managed memory, then that's fine. But if it _is_ part of the kernel's managed memory, then it is not permitted by the ARM architecture specification to allow maps of the memory with differing [memory type, sharability, cache] attributes. Basically, if a driver wants to create these kinds of mappings, then they should expect the system to become unreliable and unpredictable. That's not something any sane person should be aiming to do. > Suppose there exists a chunk of > physically-contiguous memory (say, memory reserved for device use) that > happened to be already mapped into the kernel as normal memory (cacheable, > etc). One way to remap this memory is to use ioremap (and then never touch > the original virtual mapping, which would now have conflicting > attributes). This doesn't work, and is unpredictable on ARMv6 and ARMv7. Not touching the original mapping is _not_ _sufficient_ to guarantee that the mapping is not used. (We've seen problems on OMAP as a result of this.) Any mapping which exists can be speculatively prefetched by such CPUs at any time, which can lead it to be read into the cache. Then, your different attributes for your "other" mapping can cause problems if you hit one of these cache lines - and then you can have (possibly silent) data corruption. > I feel as if there should be a better way to remap memory for > device access, either by altering the attributes on the original mapping, > or removing the original mapping and creating a new one with attributes > set to non-cacheable. This is difficult to achieve without remapping kernel memory using L2 page tables, so we can unmap pages on 4K page granularity. That's going to increase TLB overhead and result in lower system performance as there'll be a greater number of MMU misses. However, one obvious case would be to use highmem-only pages for remapping - but you then have to ensure that those pages are never kmapped in any way, because those mappings will fall into the same unpredictable category that we're already trying to avoid. This may be possible, but you'll have to ensure that most of the system RAM is in highmem - which poses other problems (eg, if lowmem gets low.) -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* RE: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-20 22:29 ` Russell King - ARM Linux @ 2010-07-21 5:49 ` Shilimkar, Santosh 2010-07-21 7:28 ` Russell King - ARM Linux 0 siblings, 1 reply; 55+ messages in thread From: Shilimkar, Santosh @ 2010-07-21 5:49 UTC (permalink / raw) To: Russell King - ARM Linux, stepanm@codeaurora.org Cc: linux-arch@vger.kernel.org, dwalker@codeaurora.org, mel@csn.ul.ie, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, FUJITA Tomonori, linux-mm@kvack.org, andi@firstfloor.org, Zach Pfeffer, Michael Bohan, Tim HRM, linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org, ebiederm@xmission.com > -----Original Message----- > From: linux-arm-kernel-bounces@lists.infradead.org [mailto:linux-arm- > kernel-bounces@lists.infradead.org] On Behalf Of Russell King - ARM Linux > Sent: Wednesday, July 21, 2010 4:00 AM > To: stepanm@codeaurora.org > Cc: linux-arch@vger.kernel.org; dwalker@codeaurora.org; mel@csn.ul.ie; > linux-arm-msm@vger.kernel.org; linux-kernel@vger.kernel.org; FUJITA > Tomonori; linux-mm@kvack.org; andi@firstfloor.org; Zach Pfeffer; Michael > Bohan; Tim HRM; linux-omap@vger.kernel.org; linux-arm- > kernel@lists.infradead.org; ebiederm@xmission.com > Subject: Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device > memory management > > On Tue, Jul 20, 2010 at 03:02:34PM -0700, stepanm@codeaurora.org wrote: > > Russell- > > > > If a driver wants to allow a device to access memory (and cache > coherency > > is off/not present for device addesses), the driver needs to remap that > > memory as non-cacheable. > > If that memory is not part of the kernel's managed memory, then that's > fine. But if it _is_ part of the kernel's managed memory, then it is > not permitted by the ARM architecture specification to allow maps of > the memory with differing [memory type, sharability, cache] attributes. > > Basically, if a driver wants to create these kinds of mappings, then > they should expect the system to become unreliable and unpredictable. > That's not something any sane person should be aiming to do. > > > Suppose there exists a chunk of > > physically-contiguous memory (say, memory reserved for device use) that > > happened to be already mapped into the kernel as normal memory > (cacheable, > > etc). One way to remap this memory is to use ioremap (and then never > touch > > the original virtual mapping, which would now have conflicting > > attributes). > > This doesn't work, and is unpredictable on ARMv6 and ARMv7. Not touching > the original mapping is _not_ _sufficient_ to guarantee that the mapping > is not used. (We've seen problems on OMAP as a result of this.) > > Any mapping which exists can be speculatively prefetched by such CPUs > at any time, which can lead it to be read into the cache. Then, your > different attributes for your "other" mapping can cause problems if you > hit one of these cache lines - and then you can have (possibly silent) > data corruption. > > > I feel as if there should be a better way to remap memory for > > device access, either by altering the attributes on the original > mapping, > > or removing the original mapping and creating a new one with attributes > > set to non-cacheable. > > This is difficult to achieve without remapping kernel memory using L2 > page tables, so we can unmap pages on 4K page granularity. That's > going to increase TLB overhead and result in lower system performance > as there'll be a greater number of MMU misses. > > However, one obvious case would be to use highmem-only pages for > remapping - but you then have to ensure that those pages are never > kmapped in any way, because those mappings will fall into the same > unpredictable category that we're already trying to avoid. This > may be possible, but you'll have to ensure that most of the system > RAM is in highmem - which poses other problems (eg, if lowmem gets > low.) > Why can't we consider an option of removing the old mappings when we need to create new ones with different attributes as suggested by Catalin on similar thread previously. This will avoid the duplicate mapping with different attributes issue on newer ARMs. Is this something can't be worked out? Regards, Santosh -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-21 5:49 ` Shilimkar, Santosh @ 2010-07-21 7:28 ` Russell King - ARM Linux 2010-07-21 7:45 ` Shilimkar, Santosh 2010-07-21 18:04 ` stepanm 0 siblings, 2 replies; 55+ messages in thread From: Russell King - ARM Linux @ 2010-07-21 7:28 UTC (permalink / raw) To: Shilimkar, Santosh Cc: stepanm@codeaurora.org, linux-arch@vger.kernel.org, dwalker@codeaurora.org, mel@csn.ul.ie, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, FUJITA Tomonori, linux-mm@kvack.org, andi@firstfloor.org, Zach Pfeffer, Michael Bohan, Tim HRM, linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org, ebiederm@xmission.com On Wed, Jul 21, 2010 at 11:19:58AM +0530, Shilimkar, Santosh wrote: > > -----Original Message----- > > From: linux-arm-kernel-bounces@lists.infradead.org [mailto:linux-arm- > > kernel-bounces@lists.infradead.org] On Behalf Of Russell King - ARM Linux > > Sent: Wednesday, July 21, 2010 4:00 AM > > To: stepanm@codeaurora.org > > Cc: linux-arch@vger.kernel.org; dwalker@codeaurora.org; mel@csn.ul.ie; > > linux-arm-msm@vger.kernel.org; linux-kernel@vger.kernel.org; FUJITA > > Tomonori; linux-mm@kvack.org; andi@firstfloor.org; Zach Pfeffer; Michael > > Bohan; Tim HRM; linux-omap@vger.kernel.org; linux-arm- > > kernel@lists.infradead.org; ebiederm@xmission.com > > Subject: Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device > > memory management ************************************************************************* > > This is difficult to achieve without remapping kernel memory using L2 > > page tables, so we can unmap pages on 4K page granularity. That's > > going to increase TLB overhead and result in lower system performance > > as there'll be a greater number of MMU misses. ************************************************************************* > > However, one obvious case would be to use highmem-only pages for > > remapping - but you then have to ensure that those pages are never > > kmapped in any way, because those mappings will fall into the same > > unpredictable category that we're already trying to avoid. This > > may be possible, but you'll have to ensure that most of the system > > RAM is in highmem - which poses other problems (eg, if lowmem gets > > low.) > > Why can't we consider an option of removing the old mappings when > we need to create new ones with different attributes as suggested > by Catalin on similar thread previously. This will avoid the duplicate > mapping with different attributes issue on newer ARMs. See the first paragraph which I've highlighted above. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* RE: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-21 7:28 ` Russell King - ARM Linux @ 2010-07-21 7:45 ` Shilimkar, Santosh 2010-07-21 18:04 ` stepanm 1 sibling, 0 replies; 55+ messages in thread From: Shilimkar, Santosh @ 2010-07-21 7:45 UTC (permalink / raw) To: Russell King - ARM Linux Cc: stepanm@codeaurora.org, linux-arch@vger.kernel.org, dwalker@codeaurora.org, mel@csn.ul.ie, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, FUJITA Tomonori, linux-mm@kvack.org, andi@firstfloor.org, Zach Pfeffer, Michael Bohan, Tim HRM, linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org, ebiederm@xmission.com > -----Original Message----- > From: Russell King - ARM Linux [mailto:linux@arm.linux.org.uk] > Sent: Wednesday, July 21, 2010 12:59 PM > To: Shilimkar, Santosh > Cc: stepanm@codeaurora.org; linux-arch@vger.kernel.org; > dwalker@codeaurora.org; mel@csn.ul.ie; linux-arm-msm@vger.kernel.org; > linux-kernel@vger.kernel.org; FUJITA Tomonori; linux-mm@kvack.org; > andi@firstfloor.org; Zach Pfeffer; Michael Bohan; Tim HRM; linux- > omap@vger.kernel.org; linux-arm-kernel@lists.infradead.org; > ebiederm@xmission.com > Subject: Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device > memory management > > On Wed, Jul 21, 2010 at 11:19:58AM +0530, Shilimkar, Santosh wrote: > > > -----Original Message----- > > > From: linux-arm-kernel-bounces@lists.infradead.org [mailto:linux-arm- > > > kernel-bounces@lists.infradead.org] On Behalf Of Russell King - ARM > Linux > > > Sent: Wednesday, July 21, 2010 4:00 AM > > > To: stepanm@codeaurora.org > > > Cc: linux-arch@vger.kernel.org; dwalker@codeaurora.org; mel@csn.ul.ie; > > > linux-arm-msm@vger.kernel.org; linux-kernel@vger.kernel.org; FUJITA > > > Tomonori; linux-mm@kvack.org; andi@firstfloor.org; Zach Pfeffer; > Michael > > > Bohan; Tim HRM; linux-omap@vger.kernel.org; linux-arm- > > > kernel@lists.infradead.org; ebiederm@xmission.com > > > Subject: Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and > device > > > memory management > > ************************************************************************* > > > This is difficult to achieve without remapping kernel memory using L2 > > > page tables, so we can unmap pages on 4K page granularity. That's > > > going to increase TLB overhead and result in lower system performance > > > as there'll be a greater number of MMU misses. > ************************************************************************* > > > > However, one obvious case would be to use highmem-only pages for > > > remapping - but you then have to ensure that those pages are never > > > kmapped in any way, because those mappings will fall into the same > > > unpredictable category that we're already trying to avoid. This > > > may be possible, but you'll have to ensure that most of the system > > > RAM is in highmem - which poses other problems (eg, if lowmem gets > > > low.) > > > > Why can't we consider an option of removing the old mappings when > > we need to create new ones with different attributes as suggested > > by Catalin on similar thread previously. This will avoid the duplicate > > mapping with different attributes issue on newer ARMs. > > See the first paragraph which I've highlighted above. > Sorry about missing that para Russell. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-21 7:28 ` Russell King - ARM Linux 2010-07-21 7:45 ` Shilimkar, Santosh @ 2010-07-21 18:04 ` stepanm 1 sibling, 0 replies; 55+ messages in thread From: stepanm @ 2010-07-21 18:04 UTC (permalink / raw) To: Russell King - ARM Linux Cc: Shilimkar, Santosh, stepanm@codeaurora.org, linux-arch@vger.kernel.org, dwalker@codeaurora.org, mel@csn.ul.ie, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, FUJITA Tomonori, linux-mm@kvack.org, andi@firstfloor.org, Zach Pfeffer, Michael Bohan, Tim HRM, linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org, ebiederm@xmission.com > ************************************************************************* >> > This is difficult to achieve without remapping kernel memory using L2 >> > page tables, so we can unmap pages on 4K page granularity. That's >> > going to increase TLB overhead and result in lower system performance >> > as there'll be a greater number of MMU misses. > ************************************************************************* Given how the buffers in question can be on the orders of tens of MB (and I don't think they will ever be less than 1MB), would we be able to get the desired effect by unmapping and then remapping on a 1MB granularity (ie, L1 sections)? It seems to me like this should be sufficient, and would not require using L2 mappings. Thoughts? Thanks Steve Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-16 7:58 ` Russell King - ARM Linux 2010-07-17 0:01 ` Larry Bassel 2010-07-19 17:55 ` Michael Bohan @ 2010-07-20 20:45 ` Zach Pfeffer 2010-07-20 20:54 ` Russell King - ARM Linux 2 siblings, 1 reply; 55+ messages in thread From: Zach Pfeffer @ 2010-07-20 20:45 UTC (permalink / raw) To: Russell King - ARM Linux Cc: Tim HRM, FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Fri, Jul 16, 2010 at 08:58:56AM +0100, Russell King - ARM Linux wrote: > On Thu, Jul 15, 2010 at 08:48:36PM -0400, Tim HRM wrote: > > Interesting, since I seem to remember the MSM devices mostly conduct > > IO through regions of normal RAM, largely accomplished through > > ioremap() calls. > > > > Without more public domain documentation of the MSM chips and AMSS > > interfaces I wouldn't know how to avoid this, but I can imagine it > > creates a bit of urgency for Qualcomm developers as they attempt to > > upstream support for this most interesting SoC. > > As the patch has been out for RFC since early April on the linux-arm-kernel > mailing list (Subject: [RFC] Prohibit ioremap() on kernel managed RAM), > and no comments have come back from Qualcomm folk. > > The restriction on creation of multiple V:P mappings with differing > attributes is also fairly hard to miss in the ARM architecture > specification when reading the sections about caches. As you mention in your patch the things that can't conflict are memory type (strongly- ordered/device/normal), cache policy (cacheable/non-cacheable, copy- back/write-through), and coherency realm (non-shareable/inner- shareable/outer-shareable). You can conflict in allocation preferences (write-allocate/write-no-allocate), as those are just "hints". You can also conflict in access permissions which can and do conflict (which are what multiple mappings are all about...some buffer can get some access, while others get different access). The VCM API allows the same memory to be mapped as long as it makes sense and allows those attributes that can change to be specified. It could be the alternative, globally applicable approach, your looking for and request in your patch. Without the VCM API (or something like it) there will just be a bunch of duplicated code that's basically doing ioremap. This code will probably fail to configure its mappings correctly, in which case your patch is a bad idea because it'll spawn bugs all over the place instead of at a know location. We could instead change ioremap to match the attributes of System RAM if that's what its mapping. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-20 20:45 ` Zach Pfeffer @ 2010-07-20 20:54 ` Russell King - ARM Linux 2010-07-20 21:56 ` Zach Pfeffer 0 siblings, 1 reply; 55+ messages in thread From: Russell King - ARM Linux @ 2010-07-20 20:54 UTC (permalink / raw) To: Zach Pfeffer Cc: Tim HRM, FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Tue, Jul 20, 2010 at 01:45:17PM -0700, Zach Pfeffer wrote: > As you mention in your patch the things that can't conflict are memory > type (strongly- ordered/device/normal), cache policy > (cacheable/non-cacheable, copy- back/write-through), and coherency > realm (non-shareable/inner- shareable/outer-shareable). You can > conflict in allocation preferences (write-allocate/write-no-allocate), > as those are just "hints". What you refer to as "hints" I refer to as cache policy - practically on ARM they're all tied up into the same set of bits. > You can also conflict in access permissions which can and do conflict > (which are what multiple mappings are all about...some buffer can get > some access, while others get different access). Access permissions don't conflict between mappings - each mapping has unique access permissions. > The VCM API allows the same memory to be mapped as long as it makes > sense and allows those attributes that can change to be specified. It > could be the alternative, globally applicable approach, your looking > for and request in your patch. I very much doubt it - there's virtually no call for creating an additional mapping of existing kernel memory with different permissions. The only time kernel memory gets remapped is with vmalloc(), where we want to create a virtually contiguous mapping from a collection of (possibly) non-contiguous pages. Such allocations are always created with R/W permissions. There are some cases where the vmalloc APIs are used to create mappings with different memory properties, but as already covered, this has become illegal with ARMv6 and v7 architectures. So no, VCM doesn't help because there's nothing that could be solved here. Creating read-only mappings is pointless, and creating mappings with different memory type, sharability or cache attributes is illegal. > Without the VCM API (or something like it) there will just be a bunch > of duplicated code that's basically doing ioremap. This code will > probably fail to configure its mappings correctly, in which case your > patch is a bad idea because it'll spawn bugs all over the place > instead of at a know location. We could instead change ioremap to > match the attributes of System RAM if that's what its mapping. And as I say, what is the point of creating another identical mapping to the one we already have? -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-20 20:54 ` Russell King - ARM Linux @ 2010-07-20 21:56 ` Zach Pfeffer 0 siblings, 0 replies; 55+ messages in thread From: Zach Pfeffer @ 2010-07-20 21:56 UTC (permalink / raw) To: Russell King - ARM Linux Cc: Tim HRM, FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Tue, Jul 20, 2010 at 09:54:33PM +0100, Russell King - ARM Linux wrote: > On Tue, Jul 20, 2010 at 01:45:17PM -0700, Zach Pfeffer wrote: > > You can also conflict in access permissions which can and do conflict > > (which are what multiple mappings are all about...some buffer can get > > some access, while others get different access). > > Access permissions don't conflict between mappings - each mapping has > unique access permissions. Yes. Bad choice of words. > > The VCM API allows the same memory to be mapped as long as it makes > > sense and allows those attributes that can change to be specified. It > > could be the alternative, globally applicable approach, your looking > > for and request in your patch. > > I very much doubt it - there's virtually no call for creating an > additional mapping of existing kernel memory with different permissions. > The only time kernel memory gets remapped is with vmalloc(), where we > want to create a virtually contiguous mapping from a collection of > (possibly) non-contiguous pages. Such allocations are always created > with R/W permissions. > > There are some cases where the vmalloc APIs are used to create mappings > with different memory properties, but as already covered, this has become > illegal with ARMv6 and v7 architectures. > > So no, VCM doesn't help because there's nothing that could be solved here. > Creating read-only mappings is pointless, and creating mappings with > different memory type, sharability or cache attributes is illegal. I don't think its pointless; it may have limited utility but things like read-only mappings can be useful. > > Without the VCM API (or something like it) there will just be a bunch > > of duplicated code that's basically doing ioremap. This code will > > probably fail to configure its mappings correctly, in which case your > > patch is a bad idea because it'll spawn bugs all over the place > > instead of at a know location. We could instead change ioremap to > > match the attributes of System RAM if that's what its mapping. > > And as I say, what is the point of creating another identical mapping to > the one we already have? As you say probably not much. We do still have a problem (and other people have it as well) we need to map in large contiguous buffers with various attributes and point the kernel and various engines at them. This seems like something that would be globally useful. The feedback I've gotten is that we should just keep our usage private to our mach-msm branch. I've got a couple of questions: Do you think a global solution to this problem is appropriate? What would that solution need to look like, transparent huge pages? How should people change various mapping attributes for these large sections of memory? -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-15 8:55 ` Russell King - ARM Linux 2010-07-16 0:48 ` Tim HRM @ 2010-07-19 6:52 ` Zach Pfeffer 2010-07-19 7:44 ` Eric W. Biederman 1 sibling, 1 reply; 55+ messages in thread From: Zach Pfeffer @ 2010-07-19 6:52 UTC (permalink / raw) To: Russell King - ARM Linux Cc: FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Thu, Jul 15, 2010 at 09:55:35AM +0100, Russell King - ARM Linux wrote: > On Wed, Jul 14, 2010 at 06:29:58PM -0700, Zach Pfeffer wrote: > > The VCM ensures that all mappings that map a given physical buffer: > > IOMMU mappings, CPU mappings and one-to-one device mappings all map > > that buffer using the same (or compatible) attributes. At this point > > the only attribute that users can pass is CACHED. In the absence of > > CACHED all accesses go straight through to the physical memory. > > So what you're saying is that if I have a buffer in kernel space > which I already have its virtual address, I can pass this to VCM and > tell it !CACHED, and it'll setup another mapping which is not cached > for me? Not quite. The existing mapping will be represented by a reservation from the prebuilt VCM of the VM. This reservation has been marked non-cached. Another reservation on a IOMMU VCM, also marked non-cached will be backed with the same physical memory. This is legal in ARM, allowing the vcm_back call to succeed. If you instead passed cached on the second mapping, the first mapping would be non-cached and the second would be cached. If the underlying architecture supported this than the vcm_back would go through. > > You are aware that multiple V:P mappings for the same physical page > with different attributes are being outlawed with ARMv6 and ARMv7 > due to speculative prefetching. The cache can be searched even for > a mapping specified as 'normal, uncached' and you can get cache hits > because the data has been speculatively loaded through a separate > cached mapping of the same physical page. I didn't know that. Thanks for the heads up. > FYI, during the next merge window, I will be pushing a patch which makes > ioremap() of system RAM fail, which should be the last core code creator > of mappings with different memory types. This behaviour has been outlawed > (as unpredictable) in the architecture specification and does cause > problems on some CPUs. That's fair enough, but it seems like it should only be outlawed for those processors on which it breaks. > > We've also the issue of multiple mappings with differing cache attributes > which needs addressing too... The VCM has been architected to handle these things. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-19 6:52 ` Zach Pfeffer @ 2010-07-19 7:44 ` Eric W. Biederman 2010-07-22 4:25 ` Zach Pfeffer 0 siblings, 1 reply; 55+ messages in thread From: Eric W. Biederman @ 2010-07-19 7:44 UTC (permalink / raw) To: Zach Pfeffer Cc: Russell King - ARM Linux, FUJITA Tomonori, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel Zach Pfeffer <zpfeffer@codeaurora.org> writes: > On Thu, Jul 15, 2010 at 09:55:35AM +0100, Russell King - ARM Linux wrote: >> On Wed, Jul 14, 2010 at 06:29:58PM -0700, Zach Pfeffer wrote: >> > The VCM ensures that all mappings that map a given physical buffer: >> > IOMMU mappings, CPU mappings and one-to-one device mappings all map >> > that buffer using the same (or compatible) attributes. At this point >> > the only attribute that users can pass is CACHED. In the absence of >> > CACHED all accesses go straight through to the physical memory. >> >> So what you're saying is that if I have a buffer in kernel space >> which I already have its virtual address, I can pass this to VCM and >> tell it !CACHED, and it'll setup another mapping which is not cached >> for me? > > Not quite. The existing mapping will be represented by a reservation > from the prebuilt VCM of the VM. This reservation has been marked > non-cached. Another reservation on a IOMMU VCM, also marked non-cached > will be backed with the same physical memory. This is legal in ARM, > allowing the vcm_back call to succeed. If you instead passed cached on > the second mapping, the first mapping would be non-cached and the > second would be cached. If the underlying architecture supported this > than the vcm_back would go through. How does this compare with the x86 pat code? >> You are aware that multiple V:P mappings for the same physical page >> with different attributes are being outlawed with ARMv6 and ARMv7 >> due to speculative prefetching. The cache can be searched even for >> a mapping specified as 'normal, uncached' and you can get cache hits >> because the data has been speculatively loaded through a separate >> cached mapping of the same physical page. > > I didn't know that. Thanks for the heads up. > >> FYI, during the next merge window, I will be pushing a patch which makes >> ioremap() of system RAM fail, which should be the last core code creator >> of mappings with different memory types. This behaviour has been outlawed >> (as unpredictable) in the architecture specification and does cause >> problems on some CPUs. > > That's fair enough, but it seems like it should only be outlawed for > those processors on which it breaks. To my knowledge mismatch of mapping attributes is a problem on most cpus on every architecture. I don't see it making sense to encourage coding constructs that will fail in the strangest most difficult to debug ways. Eric -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-19 7:44 ` Eric W. Biederman @ 2010-07-22 4:25 ` Zach Pfeffer 2010-07-22 7:34 ` Russell King - ARM Linux 0 siblings, 1 reply; 55+ messages in thread From: Zach Pfeffer @ 2010-07-22 4:25 UTC (permalink / raw) To: Eric W. Biederman Cc: Russell King - ARM Linux, FUJITA Tomonori, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Mon, Jul 19, 2010 at 12:44:49AM -0700, Eric W. Biederman wrote: > Zach Pfeffer <zpfeffer@codeaurora.org> writes: > > > On Thu, Jul 15, 2010 at 09:55:35AM +0100, Russell King - ARM Linux wrote: > >> On Wed, Jul 14, 2010 at 06:29:58PM -0700, Zach Pfeffer wrote: > >> > The VCM ensures that all mappings that map a given physical buffer: > >> > IOMMU mappings, CPU mappings and one-to-one device mappings all map > >> > that buffer using the same (or compatible) attributes. At this point > >> > the only attribute that users can pass is CACHED. In the absence of > >> > CACHED all accesses go straight through to the physical memory. > >> > >> So what you're saying is that if I have a buffer in kernel space > >> which I already have its virtual address, I can pass this to VCM and > >> tell it !CACHED, and it'll setup another mapping which is not cached > >> for me? > > > > Not quite. The existing mapping will be represented by a reservation > > from the prebuilt VCM of the VM. This reservation has been marked > > non-cached. Another reservation on a IOMMU VCM, also marked non-cached > > will be backed with the same physical memory. This is legal in ARM, > > allowing the vcm_back call to succeed. If you instead passed cached on > > the second mapping, the first mapping would be non-cached and the > > second would be cached. If the underlying architecture supported this > > than the vcm_back would go through. > > How does this compare with the x86 pat code? First, thanks for asking this question. I wasn't aware of the x86 pat code and I got to read about it. From my initial read the VCM differs in 2 ways: 1. The attributes are explicitly set on virtual address ranges. These reservations can then map physical memory with these attributes. 2. We explicitly allow multiple mappings (as long as the attributes are compatible). One such mapping may come from a IOMMU's virtual address space while another comes from the CPUs virtual address space. These mappings may exist at the same time. > > >> You are aware that multiple V:P mappings for the same physical page > >> with different attributes are being outlawed with ARMv6 and ARMv7 > >> due to speculative prefetching. The cache can be searched even for > >> a mapping specified as 'normal, uncached' and you can get cache hits > >> because the data has been speculatively loaded through a separate > >> cached mapping of the same physical page. > > > > I didn't know that. Thanks for the heads up. > > > >> FYI, during the next merge window, I will be pushing a patch which makes > >> ioremap() of system RAM fail, which should be the last core code creator > >> of mappings with different memory types. This behaviour has been outlawed > >> (as unpredictable) in the architecture specification and does cause > >> problems on some CPUs. > > > > That's fair enough, but it seems like it should only be outlawed for > > those processors on which it breaks. > > To my knowledge mismatch of mapping attributes is a problem on most > cpus on every architecture. I don't see it making sense to encourage > coding constructs that will fail in the strangest most difficult to > debug ways. Yes it is a problem, as Russell has brought up, but there's something I probably haven't communicated well. I'll use the following example: There are 3 devices: A CPU, a decoder and a video output device. All 3 devices need to map the same 12 MB buffer at the same time. Once this buffer has served its purpose it gets freed and goes back into the pool of big buffers. When the same usage case exists again the buffer needs to get reallocated and the same devices need to map to it. This usage case does exist, not only for Qualcomm but for all of these SoC media engines that have started running Linux. The VCM API attempts to cover this case for the Linux kernel. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-22 4:25 ` Zach Pfeffer @ 2010-07-22 7:34 ` Russell King - ARM Linux 2010-07-22 16:25 ` Zach Pfeffer 0 siblings, 1 reply; 55+ messages in thread From: Russell King - ARM Linux @ 2010-07-22 7:34 UTC (permalink / raw) To: Zach Pfeffer Cc: Eric W. Biederman, FUJITA Tomonori, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Wed, Jul 21, 2010 at 09:25:28PM -0700, Zach Pfeffer wrote: > Yes it is a problem, as Russell has brought up, but there's something > I probably haven't communicated well. I'll use the following example: > > There are 3 devices: A CPU, a decoder and a video output device. All 3 > devices need to map the same 12 MB buffer at the same time. Why do you need the same buffer mapped by the CPU? Let's take your example of a video decoder and video output device. Surely the CPU doesn't want to be writing to the same memory region used for the output picture as the decoder is writing to. So what's the point of mapping that memory into the CPU's address space? Surely the video output device doesn't need to see the input data to the decoder either? Surely, all you need is: 1. a mapping for the CPU for a chunk of memory to pass data to the decoder. 2. a mapping for the decoder to see the chunk of memory to receive data from the CPU. 3. a mapping for the decoder to see a chunk of memory used for the output video buffer. 4. a mapping for the output device to see the video buffer. So I don't see why everything needs to be mapped by everything else. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-22 7:34 ` Russell King - ARM Linux @ 2010-07-22 16:25 ` Zach Pfeffer 0 siblings, 0 replies; 55+ messages in thread From: Zach Pfeffer @ 2010-07-22 16:25 UTC (permalink / raw) To: Russell King - ARM Linux Cc: Eric W. Biederman, FUJITA Tomonori, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Thu, Jul 22, 2010 at 08:34:55AM +0100, Russell King - ARM Linux wrote: > On Wed, Jul 21, 2010 at 09:25:28PM -0700, Zach Pfeffer wrote: > > Yes it is a problem, as Russell has brought up, but there's something > > I probably haven't communicated well. I'll use the following example: > > > > There are 3 devices: A CPU, a decoder and a video output device. All 3 > > devices need to map the same 12 MB buffer at the same time. > > Why do you need the same buffer mapped by the CPU? > > Let's take your example of a video decoder and video output device. > Surely the CPU doesn't want to be writing to the same memory region > used for the output picture as the decoder is writing to. So what's > the point of mapping that memory into the CPU's address space? It may, especially if you're doing some software post processing. Also by mapping all the buffers its extremly fast to "pass the buffers" around in this senario - the buffer passing becomes a simple signal. > > Surely the video output device doesn't need to see the input data to > the decoder either? No, but other devices may (like the CPU). > > Surely, all you need is: > > 1. a mapping for the CPU for a chunk of memory to pass data to the > decoder. > 2. a mapping for the decoder to see the chunk of memory to receive data > from the CPU. > 3. a mapping for the decoder to see a chunk of memory used for the output > video buffer. > 4. a mapping for the output device to see the video buffer. > > So I don't see why everything needs to be mapped by everything else. That's fair, but we do share buffers and we do have many, very large mappings, and we do need to pull these from a separate pools because they need to exhibit a particular allocation profile. I agree with you that things should work like you've listed, but with Qualcomm's ARM multimedia engines we're seeing some different usage scenarios. Its the giant buffers, needing to use our own buffer allocator, the need to share and the need to swap out virtual IOMMU space (which we haven't talked about much) which make the DMA API seem like a mismatch. (we haven't even talked about graphics usage ;) ). -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-14 20:11 ` Zach Pfeffer 2010-07-14 22:05 ` Russell King - ARM Linux @ 2010-07-14 23:07 ` FUJITA Tomonori 2010-07-15 1:41 ` Zach Pfeffer 1 sibling, 1 reply; 55+ messages in thread From: FUJITA Tomonori @ 2010-07-14 23:07 UTC (permalink / raw) To: zpfeffer Cc: fujita.tomonori, linux, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Wed, 14 Jul 2010 13:11:49 -0700 Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > On Wed, Jul 14, 2010 at 10:59:38AM +0900, FUJITA Tomonori wrote: > > On Tue, 13 Jul 2010 05:14:21 -0700 > > Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > > > > > > You mean that you want to specify this alignment attribute every time > > > > you create an IOMMU mapping? Then you can set segment_boundary_mask > > > > every time you create an IOMMU mapping. It's odd but it should work. > > > > > > Kinda. I want to forget about IOMMUs, devices and CPUs. I just want to > > > create a mapping that has the alignment I specify, regardless of the > > > mapper. The mapping is created on a VCM and the VCM is associated with > > > a mapper: a CPU, an IOMMU'd device or a direct mapped device. > > > > Sounds like you can do the above with the combination of the current > > APIs, create a virtual address and then an I/O address. > > > > Yes, and that's what the implementation does - and all the other > implementations that need to do this same thing. Why not solve the > problem once? Why we we need a new abstraction layer to solve the problem that the current API can handle? The above two operations don't sound too complicated. The combination of the current API sounds much simpler than your new abstraction. Please show how the combination of the current APIs doesn't work. Otherwise, we can't see what's the benefit of your new abstraction. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-14 23:07 ` FUJITA Tomonori @ 2010-07-15 1:41 ` Zach Pfeffer 2010-07-19 8:22 ` Russell King - ARM Linux 0 siblings, 1 reply; 55+ messages in thread From: Zach Pfeffer @ 2010-07-15 1:41 UTC (permalink / raw) To: FUJITA Tomonori Cc: linux, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Thu, Jul 15, 2010 at 08:07:28AM +0900, FUJITA Tomonori wrote: > On Wed, 14 Jul 2010 13:11:49 -0700 > Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > > > On Wed, Jul 14, 2010 at 10:59:38AM +0900, FUJITA Tomonori wrote: > > > On Tue, 13 Jul 2010 05:14:21 -0700 > > > Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > > > > > > > > You mean that you want to specify this alignment attribute every time > > > > > you create an IOMMU mapping? Then you can set segment_boundary_mask > > > > > every time you create an IOMMU mapping. It's odd but it should work. > > > > > > > > Kinda. I want to forget about IOMMUs, devices and CPUs. I just want to > > > > create a mapping that has the alignment I specify, regardless of the > > > > mapper. The mapping is created on a VCM and the VCM is associated with > > > > a mapper: a CPU, an IOMMU'd device or a direct mapped device. > > > > > > Sounds like you can do the above with the combination of the current > > > APIs, create a virtual address and then an I/O address. > > > > > > > Yes, and that's what the implementation does - and all the other > > implementations that need to do this same thing. Why not solve the > > problem once? > > Why we we need a new abstraction layer to solve the problem that the > current API can handle? The current API can't really handle it because the DMA API doesn't separate buffer allocation from buffer mapping. To use the DMA API a scatterlist would need to be synthesized from the physical buffers that we've allocated. For instance: I need 10, 1 MB physical buffers and a 64 KB physical buffer. With the DMA API I need to allocate 10*1MB/PAGE_SIZE + 64 KB/PAGE_SIZE scatterlist elements, fix them all up to follow the chaining specification and then go through all of them again to fix up their virtual mappings for the mapper that's mapping the physical buffer. If I want to share the buffer with another device I have to make a copy of the entire thing then fix up the virtual mappings for the other device I'm sharing with. The VCM splits the two things up so that I do a physical allocation, then 2 virtual allocations and then map both. > > The above two operations don't sound too complicated. The combination > of the current API sounds much simpler than your new abstraction. > > Please show how the combination of the current APIs doesn't > work. Otherwise, we can't see what's the benefit of your new > abstraction. See above. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-15 1:41 ` Zach Pfeffer @ 2010-07-19 8:22 ` Russell King - ARM Linux 2010-07-20 10:09 ` FUJITA Tomonori 2010-07-20 22:20 ` Zach Pfeffer 0 siblings, 2 replies; 55+ messages in thread From: Russell King - ARM Linux @ 2010-07-19 8:22 UTC (permalink / raw) To: Zach Pfeffer Cc: FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Wed, Jul 14, 2010 at 06:41:48PM -0700, Zach Pfeffer wrote: > On Thu, Jul 15, 2010 at 08:07:28AM +0900, FUJITA Tomonori wrote: > > Why we we need a new abstraction layer to solve the problem that the > > current API can handle? > > The current API can't really handle it because the DMA API doesn't > separate buffer allocation from buffer mapping. That's not entirely correct. The DMA API provides two things: 1. An API for allocating DMA coherent buffers 2. An API for mapping streaming buffers Some implementations of (2) end up using (1) to work around broken hardware - but that's a separate problem (and causes its own set of problems.) > For instance: I need 10, 1 MB physical buffers and a 64 KB physical > buffer. With the DMA API I need to allocate 10*1MB/PAGE_SIZE + 64 > KB/PAGE_SIZE scatterlist elements, fix them all up to follow the > chaining specification and then go through all of them again to fix up > their virtual mappings for the mapper that's mapping the physical > buffer. You're making it sound like extremely hard work. struct scatterlist *sg; int i, nents = 11; sg = kmalloc(sizeof(*sg) * nents, GFP_KERNEL); if (!sg) return -ENOMEM; sg_init_table(sg, nents); for (i = 0; i < nents; i++) { if (i != nents - 1) len = 1048576; else len = 64*1024; buf = alloc_buffer(len); sg_set_buf(&sg[i], buf, len); } There's no need to split the scatterlist elements up into individual pages - the block layer doesn't do that when it passes scatterlists down to block device drivers. I'm not saying that it's reasonable to pass (or even allocate) a 1MB buffer via the DMA API. > If I want to share the buffer with another device I have to > make a copy of the entire thing then fix up the virtual mappings for > the other device I'm sharing with. This is something the DMA API doesn't do - probably because there hasn't been a requirement for it. One of the issues for drivers is that by separating the mapped scatterlist from the input buffer scatterlist, it creates something else for them to allocate, which causes an additional failure point - and as all users sit well with the current API, there's little reason to change especially given the number of drivers which would need to be updated. What you can do is: struct map { dma_addr_t addr; size_t len; }; int map_sg(struct device *dev, struct scatterlist *list, unsigned int nents, struct map *map, enum dma_data_direction dir) { struct scatterlist *sg; unsigned int i, j = 0; for_each_sg(list, sg, nents, i) { map[j]->addr = dma_map_page(dev, sg_page(sg), sg->offset, sg->length, dir); map[j]->len = length; if (dma_mapping_error(map[j]->addr)) break; j++; } return j; } void unmap(struct device *dev, struct map *map, unsigned int nents, enum dma_data_direction dir) { while (nents) { dma_unmap_page(dev, map->addr, map->len, dir); map++; nents--; } } Note: this may not be portable to all architectures. It may also break if there's something like the dmabounce or swiotlb code remapping buffers which don't fit the DMA mask for the device - that's a different problem. You can then map the same scatterlist into multiple different 'map' arrays for several devices simultaneously. What you can't do is access the buffers from the CPU while they're mapped to any device. I'm not saying that you should do the above - I'm just proving that it's not as hard as you seem to be making out. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-19 8:22 ` Russell King - ARM Linux @ 2010-07-20 10:09 ` FUJITA Tomonori 2010-07-20 22:20 ` Zach Pfeffer 1 sibling, 0 replies; 55+ messages in thread From: FUJITA Tomonori @ 2010-07-20 10:09 UTC (permalink / raw) To: linux Cc: zpfeffer, fujita.tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Mon, 19 Jul 2010 09:22:13 +0100 Russell King - ARM Linux <linux@arm.linux.org.uk> wrote: > > If I want to share the buffer with another device I have to > > make a copy of the entire thing then fix up the virtual mappings for > > the other device I'm sharing with. > > This is something the DMA API doesn't do - probably because there hasn't > been a requirement for it. > > One of the issues for drivers is that by separating the mapped scatterlist > from the input buffer scatterlist, it creates something else for them to > allocate, which causes an additional failure point - and as all users sit > well with the current API, there's little reason to change especially > given the number of drivers which would need to be updated. Agreed. There was the discussion about separating 'dma_addr and dma_len' from scatterlist struct but I don't think that it's worth doing so. > I'm just proving that it's not as hard as you seem to be making out. Agreed again. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-19 8:22 ` Russell King - ARM Linux 2010-07-20 10:09 ` FUJITA Tomonori @ 2010-07-20 22:20 ` Zach Pfeffer 2010-07-21 1:44 ` FUJITA Tomonori 1 sibling, 1 reply; 55+ messages in thread From: Zach Pfeffer @ 2010-07-20 22:20 UTC (permalink / raw) To: Russell King - ARM Linux Cc: FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Mon, Jul 19, 2010 at 09:22:13AM +0100, Russell King - ARM Linux wrote: > On Wed, Jul 14, 2010 at 06:41:48PM -0700, Zach Pfeffer wrote: > > On Thu, Jul 15, 2010 at 08:07:28AM +0900, FUJITA Tomonori wrote: > > > Why we we need a new abstraction layer to solve the problem that the > > > current API can handle? > > > > The current API can't really handle it because the DMA API doesn't > > separate buffer allocation from buffer mapping. > > That's not entirely correct. The DMA API provides two things: > > 1. An API for allocating DMA coherent buffers > 2. An API for mapping streaming buffers > > Some implementations of (2) end up using (1) to work around broken > hardware - but that's a separate problem (and causes its own set of > problems.) > > > For instance: I need 10, 1 MB physical buffers and a 64 KB physical > > buffer. With the DMA API I need to allocate 10*1MB/PAGE_SIZE + 64 > > KB/PAGE_SIZE scatterlist elements, fix them all up to follow the > > chaining specification and then go through all of them again to fix up > > their virtual mappings for the mapper that's mapping the physical > > buffer. > > You're making it sound like extremely hard work. > > struct scatterlist *sg; > int i, nents = 11; > > sg = kmalloc(sizeof(*sg) * nents, GFP_KERNEL); > if (!sg) > return -ENOMEM; > > sg_init_table(sg, nents); > for (i = 0; i < nents; i++) { > if (i != nents - 1) > len = 1048576; > else > len = 64*1024; > buf = alloc_buffer(len); > sg_set_buf(&sg[i], buf, len); > } > > There's no need to split the scatterlist elements up into individual > pages - the block layer doesn't do that when it passes scatterlists > down to block device drivers. Okay. Thank you for the example. > > I'm not saying that it's reasonable to pass (or even allocate) a 1MB > buffer via the DMA API. But given a bunch of large chunks of memory, is there any API that can manage them (asked this on the other thread as well)? > > If I want to share the buffer with another device I have to > > make a copy of the entire thing then fix up the virtual mappings for > > the other device I'm sharing with. > > This is something the DMA API doesn't do - probably because there hasn't > been a requirement for it. > > One of the issues for drivers is that by separating the mapped scatterlist > from the input buffer scatterlist, it creates something else for them to > allocate, which causes an additional failure point - and as all users sit > well with the current API, there's little reason to change especially > given the number of drivers which would need to be updated. > > What you can do is: > > struct map { > dma_addr_t addr; > size_t len; > }; > > int map_sg(struct device *dev, struct scatterlist *list, > unsigned int nents, struct map *map, enum dma_data_direction dir) > { > struct scatterlist *sg; > unsigned int i, j = 0; > > for_each_sg(list, sg, nents, i) { > map[j]->addr = dma_map_page(dev, sg_page(sg), sg->offset, > sg->length, dir); > map[j]->len = length; > if (dma_mapping_error(map[j]->addr)) > break; > j++; > } > > return j; > } > > void unmap(struct device *dev, struct map *map, unsigned int nents, > enum dma_data_direction dir) > { > while (nents) { > dma_unmap_page(dev, map->addr, map->len, dir); > map++; > nents--; > } > } > > Note: this may not be portable to all architectures. It may also break > if there's something like the dmabounce or swiotlb code remapping buffers > which don't fit the DMA mask for the device - that's a different problem. True but given a higher-level "map(virtual_range, physical_chunks)" wouldn't break on all architectures. > You can then map the same scatterlist into multiple different 'map' > arrays for several devices simultaneously. What you can't do is access > the buffers from the CPU while they're mapped to any device. Which is considered a feature ;) > I'm not saying that you should do the above - I'm just proving that it's > not as hard as you seem to be making out. That's fair. I didn't mean to say things were hard, just that using the DMA API for big buffer management and mapping was not ideal since our goals are to allocate big buffers using a device specific algorithm, give them various attributes and share them. What we created looked generally useful. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-20 22:20 ` Zach Pfeffer @ 2010-07-21 1:44 ` FUJITA Tomonori 2010-07-22 4:30 ` Zach Pfeffer 0 siblings, 1 reply; 55+ messages in thread From: FUJITA Tomonori @ 2010-07-21 1:44 UTC (permalink / raw) To: zpfeffer Cc: linux, fujita.tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Tue, 20 Jul 2010 15:20:01 -0700 Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > > I'm not saying that it's reasonable to pass (or even allocate) a 1MB > > buffer via the DMA API. > > But given a bunch of large chunks of memory, is there any API that can > manage them (asked this on the other thread as well)? What is the problem about mapping a 1MB buffer with the DMA API? Possibly, an IOMMU can't find space for 1MB but it's not the problem of the DMA API. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-21 1:44 ` FUJITA Tomonori @ 2010-07-22 4:30 ` Zach Pfeffer 2010-07-22 4:43 ` FUJITA Tomonori 2010-07-22 7:39 ` Russell King - ARM Linux 0 siblings, 2 replies; 55+ messages in thread From: Zach Pfeffer @ 2010-07-22 4:30 UTC (permalink / raw) To: FUJITA Tomonori Cc: linux, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Wed, Jul 21, 2010 at 10:44:37AM +0900, FUJITA Tomonori wrote: > On Tue, 20 Jul 2010 15:20:01 -0700 > Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > > > > I'm not saying that it's reasonable to pass (or even allocate) a 1MB > > > buffer via the DMA API. > > > > But given a bunch of large chunks of memory, is there any API that can > > manage them (asked this on the other thread as well)? > > What is the problem about mapping a 1MB buffer with the DMA API? > > Possibly, an IOMMU can't find space for 1MB but it's not the problem > of the DMA API. This goes to the nub of the issue. We need a lot of 1 MB physically contiguous chunks. The system is going to fragment and we'll never get our 12 1 MB chunks that we'll need, since the DMA API allocator uses the system pool it will never succeed. For this reason we reserve a pool of 1 MB chunks (and 16 MB, 64 KB etc...) to satisfy our requests. This same use case is seen on most embedded "media" engines that are getting built today. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-22 4:30 ` Zach Pfeffer @ 2010-07-22 4:43 ` FUJITA Tomonori 2010-07-22 16:44 ` Zach Pfeffer 2010-07-22 7:39 ` Russell King - ARM Linux 1 sibling, 1 reply; 55+ messages in thread From: FUJITA Tomonori @ 2010-07-22 4:43 UTC (permalink / raw) To: zpfeffer Cc: fujita.tomonori, linux, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Wed, 21 Jul 2010 21:30:34 -0700 Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > On Wed, Jul 21, 2010 at 10:44:37AM +0900, FUJITA Tomonori wrote: > > On Tue, 20 Jul 2010 15:20:01 -0700 > > Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > > > > > > I'm not saying that it's reasonable to pass (or even allocate) a 1MB > > > > buffer via the DMA API. > > > > > > But given a bunch of large chunks of memory, is there any API that can > > > manage them (asked this on the other thread as well)? > > > > What is the problem about mapping a 1MB buffer with the DMA API? > > > > Possibly, an IOMMU can't find space for 1MB but it's not the problem > > of the DMA API. > > This goes to the nub of the issue. We need a lot of 1 MB physically > contiguous chunks. The system is going to fragment and we'll never get > our 12 1 MB chunks that we'll need, since the DMA API allocator uses > the system pool it will never succeed. For this reason we reserve a > pool of 1 MB chunks (and 16 MB, 64 KB etc...) to satisfy our > requests. This same use case is seen on most embedded "media" engines > that are getting built today. We don't need a new abstraction to reserve some memory. If you want pre-allocated memory pool per device (and share them with some), the DMA API can for coherent memory (see dma_alloc_from_coherent). You can extend the DMA API if necessary. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-22 4:43 ` FUJITA Tomonori @ 2010-07-22 16:44 ` Zach Pfeffer 0 siblings, 0 replies; 55+ messages in thread From: Zach Pfeffer @ 2010-07-22 16:44 UTC (permalink / raw) To: FUJITA Tomonori Cc: linux, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Thu, Jul 22, 2010 at 01:43:26PM +0900, FUJITA Tomonori wrote: > On Wed, 21 Jul 2010 21:30:34 -0700 > Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > > > On Wed, Jul 21, 2010 at 10:44:37AM +0900, FUJITA Tomonori wrote: > > > On Tue, 20 Jul 2010 15:20:01 -0700 > > > Zach Pfeffer <zpfeffer@codeaurora.org> wrote: > > > > > > > > I'm not saying that it's reasonable to pass (or even allocate) a 1MB > > > > > buffer via the DMA API. > > > > > > > > But given a bunch of large chunks of memory, is there any API that can > > > > manage them (asked this on the other thread as well)? > > > > > > What is the problem about mapping a 1MB buffer with the DMA API? > > > > > > Possibly, an IOMMU can't find space for 1MB but it's not the problem > > > of the DMA API. > > > > This goes to the nub of the issue. We need a lot of 1 MB physically > > contiguous chunks. The system is going to fragment and we'll never get > > our 12 1 MB chunks that we'll need, since the DMA API allocator uses > > the system pool it will never succeed. For this reason we reserve a > > pool of 1 MB chunks (and 16 MB, 64 KB etc...) to satisfy our > > requests. This same use case is seen on most embedded "media" engines > > that are getting built today. > > We don't need a new abstraction to reserve some memory. > > If you want pre-allocated memory pool per device (and share them with > some), the DMA API can for coherent memory (see > dma_alloc_from_coherent). You can extend the DMA API if necessary. That function won't work for us. We can't use bitmap_find_free_region(), we need to use our own allocator. If anything we need a dma_alloc_from_custom(my_allocator). Take a look at: mm: iommu: A physical allocator for the VCMM vcm_alloc_max_munch() -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-22 4:30 ` Zach Pfeffer 2010-07-22 4:43 ` FUJITA Tomonori @ 2010-07-22 7:39 ` Russell King - ARM Linux 2010-07-22 16:28 ` Zach Pfeffer 1 sibling, 1 reply; 55+ messages in thread From: Russell King - ARM Linux @ 2010-07-22 7:39 UTC (permalink / raw) To: Zach Pfeffer Cc: FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Wed, Jul 21, 2010 at 09:30:34PM -0700, Zach Pfeffer wrote: > This goes to the nub of the issue. We need a lot of 1 MB physically > contiguous chunks. The system is going to fragment and we'll never get > our 12 1 MB chunks that we'll need, since the DMA API allocator uses > the system pool it will never succeed. By the "DMA API allocator" I assume you mean the coherent DMA interface, The DMA coherent API and DMA streaming APIs are two separate sub-interfaces of the DMA API and are not dependent on each other. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management 2010-07-22 7:39 ` Russell King - ARM Linux @ 2010-07-22 16:28 ` Zach Pfeffer 0 siblings, 0 replies; 55+ messages in thread From: Zach Pfeffer @ 2010-07-22 16:28 UTC (permalink / raw) To: Russell King - ARM Linux Cc: FUJITA Tomonori, ebiederm, linux-arch, dwalker, mel, linux-arm-msm, linux-kernel, linux-mm, andi, linux-omap, linux-arm-kernel On Thu, Jul 22, 2010 at 08:39:17AM +0100, Russell King - ARM Linux wrote: > On Wed, Jul 21, 2010 at 09:30:34PM -0700, Zach Pfeffer wrote: > > This goes to the nub of the issue. We need a lot of 1 MB physically > > contiguous chunks. The system is going to fragment and we'll never get > > our 12 1 MB chunks that we'll need, since the DMA API allocator uses > > the system pool it will never succeed. > > By the "DMA API allocator" I assume you mean the coherent DMA interface, > The DMA coherent API and DMA streaming APIs are two separate sub-interfaces > of the DMA API and are not dependent on each other. I didn't know that, but yes. As far as I can tell they both allocate memory from the VM. We'd need a way to hook in our our own minimized mapping allocator. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 55+ messages in thread
end of thread, other threads:[~2010-07-22 16:44 UTC | newest] Thread overview: 55+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-07-06 15:42 [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management Zach Pfeffer 2010-07-06 15:42 ` [RFC 2/3] mm: iommu: A physical allocator for the VCMM Zach Pfeffer 2010-07-06 15:42 ` [RFC 3/3 v3] mm: iommu: The Virtual Contiguous Memory Manager Zach Pfeffer -- strict thread matches above, loose matches on Subject: below -- 2010-07-21 5:18 [RFC 1/3 v3] mm: iommu: An API to unify IOMMU, CPU and device memory management stepanm 2010-07-03 5:38 Zach Pfeffer 2010-07-03 19:06 ` Eric W. Biederman 2010-07-07 22:44 ` Zach Pfeffer 2010-07-07 23:07 ` Russell King - ARM Linux 2010-07-08 23:59 ` Zach Pfeffer 2010-07-12 1:25 ` FUJITA Tomonori 2010-07-13 5:57 ` Zach Pfeffer 2010-07-13 6:03 ` FUJITA Tomonori 2010-07-13 12:14 ` Zach Pfeffer 2010-07-14 1:59 ` FUJITA Tomonori 2010-07-14 20:11 ` Zach Pfeffer 2010-07-14 22:05 ` Russell King - ARM Linux 2010-07-15 1:29 ` Zach Pfeffer 2010-07-15 1:47 ` Eric W. Biederman 2010-07-15 5:40 ` Zach Pfeffer 2010-07-15 5:35 ` Zach Pfeffer 2010-07-15 8:55 ` Russell King - ARM Linux 2010-07-16 0:48 ` Tim HRM 2010-07-16 7:58 ` Russell King - ARM Linux 2010-07-17 0:01 ` Larry Bassel 2010-07-19 9:21 ` Tim HRM 2010-07-21 0:44 ` Zach Pfeffer 2010-07-21 1:44 ` Timothy Meade 2010-07-22 4:06 ` Zach Pfeffer 2010-07-19 17:55 ` Michael Bohan 2010-07-19 18:40 ` Russell King - ARM Linux 2010-07-20 22:02 ` stepanm 2010-07-20 22:29 ` Russell King - ARM Linux 2010-07-21 5:49 ` Shilimkar, Santosh 2010-07-21 7:28 ` Russell King - ARM Linux 2010-07-21 7:45 ` Shilimkar, Santosh 2010-07-21 18:04 ` stepanm 2010-07-20 20:45 ` Zach Pfeffer 2010-07-20 20:54 ` Russell King - ARM Linux 2010-07-20 21:56 ` Zach Pfeffer 2010-07-19 6:52 ` Zach Pfeffer 2010-07-19 7:44 ` Eric W. Biederman 2010-07-22 4:25 ` Zach Pfeffer 2010-07-22 7:34 ` Russell King - ARM Linux 2010-07-22 16:25 ` Zach Pfeffer 2010-07-14 23:07 ` FUJITA Tomonori 2010-07-15 1:41 ` Zach Pfeffer 2010-07-19 8:22 ` Russell King - ARM Linux 2010-07-20 10:09 ` FUJITA Tomonori 2010-07-20 22:20 ` Zach Pfeffer 2010-07-21 1:44 ` FUJITA Tomonori 2010-07-22 4:30 ` Zach Pfeffer 2010-07-22 4:43 ` FUJITA Tomonori 2010-07-22 16:44 ` Zach Pfeffer 2010-07-22 7:39 ` Russell King - ARM Linux 2010-07-22 16:28 ` Zach Pfeffer
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).