| /* 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. |
| * |
| */ |
| |
| #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_id 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. |
| * @physmem: 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. |
| * |
| * physmems 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_dev_addr() - Return the device address of a reservation. |
| * @res: The reservation of interest. |
| * |
| * |
| * On success this function returns the device address of a reservation. On |
| * error it returns: |
| * 1 res is invalid. |
| * |
| * Note: This may return a kernel address if the reservation was |
| * created from vcm_create_from_prebuilt() and the prebuilt ext_vcm_id |
| * references a VM page table. |
| */ |
| phys_addr_t vcm_get_dev_addr(struct res *res); |
| |
| |
| /** |
| * 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_id is invalid. |
| */ |
| size_t vcm_translate(struct device *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(phys_addr_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(phys_addr_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. |
| */ |
| phys_addr_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. |
| */ |
| phys_addr_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. |
| * @vcm: VCM to use for translation. |
| * @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. |
| */ |
| phys_addr_t vcm_dev_addr_to_phys_addr(struct vcm *vcm, 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(size_t dev); |
| |
| #endif /* _VCM_H_ */ |
| |