Index: arch/arm/mach-tegra/nv/include/mach/iovmm.h |
diff --git a/arch/arm/mach-tegra/nv/include/mach/iovmm.h b/arch/arm/mach-tegra/nv/include/mach/iovmm.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..606c434da4cba5852afee98a9b3d2fc5bcd1dc40 |
--- /dev/null |
+++ b/arch/arm/mach-tegra/nv/include/mach/iovmm.h |
@@ -0,0 +1,273 @@ |
+/* |
+ * arch/arm/mach-tegra/include/mach/iovmm.h |
+ * |
+ * Copyright (c) 2010, NVIDIA Corporation. |
+ * |
+ * This program is free software; you can redistribute it and/or modify |
+ * it under the terms of the GNU General Public License as published by |
+ * the Free Software Foundation; either version 2 of the License, or |
+ * (at your option) any later version. |
+ * |
+ * This program is distributed i 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/list.h> |
+#include <linux/platform_device.h> |
+#include <linux/rbtree.h> |
+#include <linux/rwsem.h> |
+#include <linux/spinlock.h> |
+#include <linux/types.h> |
+ |
+#ifndef _MACH_TEGRA_IOVMM_H_ |
+#define _MACH_TEGRA_IOVMM_H_ |
+ |
+#if defined(CONFIG_ARCH_TEGRA_1x_SOC) || defined(CONFIG_ARCH_TEGRA_2x_SOC) |
+typedef u32 tegra_iovmm_addr_t; |
+#else |
+#error "Unsupported tegra architecture family" |
+#endif |
+ |
+struct tegra_iovmm_device_ops; |
+ |
+/* each I/O virtual memory manager unit should register a device with |
+ * the iovmm system |
+ */ |
+struct tegra_iovmm_device { |
+ struct tegra_iovmm_device_ops *ops; |
+ const char *name; |
+ struct list_head list; |
+ int pgsize_bits; |
+}; |
+ |
+/* tegra_iovmm_domain serves a purpose analagous to mm_struct as defined in |
+ * <linux/mm_types.h> - it defines a virtual address space within which |
+ * tegra_iovmm_areas can be created. |
+ */ |
+struct tegra_iovmm_domain { |
+ atomic_t clients; |
+ atomic_t locks; |
+ spinlock_t block_lock; |
+ unsigned long flags; |
+ wait_queue_head_t delay_lock; /* when lock_client fails */ |
+ struct rw_semaphore map_lock; |
+ struct rb_root all_blocks; /* ordered by address */ |
+ struct rb_root free_blocks; /* ordered by size */ |
+ struct tegra_iovmm_device *dev; |
+}; |
+ |
+/* tegra_iovmm_client is analagous to an individual task in the task group |
+ * which owns an mm_struct. |
+ */ |
+ |
+struct iovmm_share_group; |
+ |
+struct tegra_iovmm_client { |
+ const char *name; |
+ unsigned long flags; |
+ struct iovmm_share_group *group; |
+ struct tegra_iovmm_domain *domain; |
+ struct list_head list; |
+}; |
+ |
+/* tegra_iovmm_area serves a purpose analagous to vm_area_struct as defined |
+ * in <linux/mm_types.h> - it defines a virtual memory area which can be |
+ * mapped to physical memory by a client-provided mapping function. */ |
+ |
+struct tegra_iovmm_area { |
+ struct tegra_iovmm_domain *domain; |
+ tegra_iovmm_addr_t iovm_start; |
+ tegra_iovmm_addr_t iovm_length; |
+ pgprot_t pgprot; |
+ struct tegra_iovmm_area_ops *ops; |
+}; |
+ |
+struct tegra_iovmm_device_ops { |
+ /* maps a VMA using the page residency functions provided by the VMA */ |
+ int (*map)(struct tegra_iovmm_device *dev, |
+ struct tegra_iovmm_area *io_vma); |
+ /* marks all PTEs in a VMA as invalid; decommits the virtual addres |
+ * space (potentially freeing PDEs when decommit is true.) */ |
+ void (*unmap)(struct tegra_iovmm_device *dev, |
+ struct tegra_iovmm_area *io_vma, bool decommit); |
+ void (*map_pfn)(struct tegra_iovmm_device *dev, |
+ struct tegra_iovmm_area *io_vma, |
+ tegra_iovmm_addr_t offs, unsigned long pfn); |
+ /* ensures that a domain is resident in the hardware's mapping region |
+ * so that it may be used by a client */ |
+ int (*lock_domain)(struct tegra_iovmm_device *dev, |
+ struct tegra_iovmm_domain *domain); |
+ void (*unlock_domain)(struct tegra_iovmm_device *dev, |
+ struct tegra_iovmm_domain *domain); |
+ /* allocates a vmm_domain for the specified client; may return the same |
+ * domain for multiple clients */ |
+ struct tegra_iovmm_domain* (*alloc_domain)( |
+ struct tegra_iovmm_device *dev, |
+ struct tegra_iovmm_client *client); |
+ void (*free_domain)(struct tegra_iovmm_device *dev, |
+ struct tegra_iovmm_domain *domain); |
+}; |
+ |
+struct tegra_iovmm_area_ops { |
+ /* ensures that the page of data starting at the specified offset |
+ * from the start of the iovma is resident and pinned for use by |
+ * DMA, returns the system pfn, or an invalid pfn if the |
+ * operation fails. */ |
+ unsigned long (*lock_makeresident)(struct tegra_iovmm_area *area, |
+ tegra_iovmm_addr_t offs); |
+ /* called when the page is unmapped from the I/O VMA */ |
+ void (*release)(struct tegra_iovmm_area *area, tegra_iovmm_addr_t offs); |
+}; |
+ |
+#ifdef CONFIG_TEGRA_IOVMM |
+/* called by clients to allocate an I/O VMM client mapping context which |
+ * will be shared by all clients in the same share_group */ |
+struct tegra_iovmm_client *tegra_iovmm_alloc_client(const char *name, |
+ const char *share_group); |
+ |
+size_t tegra_iovmm_get_vm_size(struct tegra_iovmm_client *client); |
+ |
+void tegra_iovmm_free_client(struct tegra_iovmm_client *client); |
+ |
+/* called by clients to ensure that their mapping context is resident |
+ * before performing any DMA operations addressing I/O VMM regions. |
+ * client_lock may return -EINTR. */ |
+int tegra_iovmm_client_lock(struct tegra_iovmm_client *client); |
+int tegra_iovmm_client_trylock(struct tegra_iovmm_client *client); |
+ |
+/* called by clients after DMA operations are complete */ |
+void tegra_iovmm_client_unlock(struct tegra_iovmm_client *client); |
+ |
+/* called by clients to allocate a new iovmm_area and reserve I/O virtual |
+ * address space for it. if ops is NULL, clients should subsequently call |
+ * tegra_iovmm_vm_map_pages and/or tegra_iovmm_vm_insert_pfn to explicitly |
+ * map the I/O virtual address to an OS-allocated page or physical address, |
+ * respectively. VM operations may be called before this call returns */ |
+struct tegra_iovmm_area *tegra_iovmm_create_vm( |
+ struct tegra_iovmm_client *client, struct tegra_iovmm_area_ops *ops, |
+ unsigned long size, pgprot_t pgprot); |
+ |
+/* called by clients to "zap" an iovmm_area, and replace all mappings |
+ * in it with invalid ones, without freeing the virtual address range */ |
+void tegra_iovmm_zap_vm(struct tegra_iovmm_area *vm); |
+ |
+/* after zapping a demand-loaded iovmm_area, the client should unzap it |
+ * to allow the VMM device to remap the page range. */ |
+void tegra_iovmm_unzap_vm(struct tegra_iovmm_area *vm); |
+ |
+/* called by clients to return an iovmm_area to the free pool for the domain */ |
+void tegra_iovmm_free_vm(struct tegra_iovmm_area *vm); |
+ |
+/* called by client software to map the page-aligned I/O address vaddr to |
+ * a specific physical address pfn. I/O VMA should have been created with |
+ * a NULL tegra_iovmm_area_ops structure. */ |
+void tegra_iovmm_vm_insert_pfn(struct tegra_iovmm_area *area, |
+ tegra_iovmm_addr_t vaddr, unsigned long pfn); |
+ |
+/* called by clients to return the iovmm_area containing addr, or NULL if |
+ * addr has not been allocated. caller should call tegra_iovmm_put_area when |
+ * finished using the returned pointer */ |
+struct tegra_iovmm_area *tegra_iovmm_find_area_get( |
+ struct tegra_iovmm_client *client, tegra_iovmm_addr_t addr); |
+ |
+struct tegra_iovmm_area *tegra_iovmm_area_get(struct tegra_iovmm_area *vm); |
+void tegra_iovmm_area_put(struct tegra_iovmm_area *vm); |
+ |
+/* called by drivers to initialize a tegra_iovmm_domain structure */ |
+int tegra_iovmm_domain_init(struct tegra_iovmm_domain *domain, |
+ struct tegra_iovmm_device *dev, tegra_iovmm_addr_t start, |
+ tegra_iovmm_addr_t end); |
+ |
+/* called by drivers to register an I/O VMM device with the system */ |
+int tegra_iovmm_register(struct tegra_iovmm_device *dev); |
+ |
+/* called by drivers to remove an I/O VMM device from the system */ |
+int tegra_iovmm_unregister(struct tegra_iovmm_device *dev); |
+ |
+ |
+ |
+#else /* CONFIG_TEGRA_IOVMM */ |
+ |
+static inline struct tegra_iovmm_client *tegra_iovmm_alloc_client( |
+ const char *name, const char *share_group) |
+{ |
+ return NULL; |
+} |
+ |
+static inline size_t tegra_iovmm_get_vm_size(struct tegra_iovmm_client *client) |
+{ |
+ return 0; |
+} |
+ |
+static inline void tegra_iovmm_free_client(struct tegra_iovmm_client *client) |
+{} |
+ |
+static inline int tegra_iovmm_client_lock(struct tegra_iovmm_client *client) |
+{ |
+ return 0; |
+} |
+ |
+static inline int tegra_iovmm_client_trylock(struct tegra_iovmm_client *client) |
+{ |
+ return 0; |
+} |
+ |
+static inline void tegra_iovmm_client_unlock(struct tegra_iovmm_client *client) |
+{} |
+ |
+static inline struct tegra_iovmm_area *tegra_iovmm_create_vm( |
+ struct tegra_iovmm_client *client, struct tegra_iovmm_area_ops *ops, |
+ unsigned long size, pgprot_t pgprot) |
+{ |
+ return NULL; |
+} |
+ |
+static inline void tegra_iovmm_zap_vm(struct tegra_iovmm_area *vm) { } |
+ |
+static inline void tegra_iovmm_unzap_vm(struct tegra_iovmm_area *vm) { } |
+ |
+static inline void tegra_iovmm_free_vm(struct tegra_iovmm_area *vm) { } |
+ |
+static inline void tegra_iovmm_vm_insert_pfn(struct tegra_iovmm_area *area, |
+ tegra_iovmm_addr_t vaddr, unsigned long pfn) { } |
+ |
+static inline struct tegra_iovmm_area *tegra_iovmm_find_area_get( |
+ struct tegra_iovmm_client *client, tegra_iovmm_addr_t addr) |
+{ |
+ return NULL; |
+} |
+ |
+static inline struct tegra_iovmm_area *tegra_iovmm_area_get( |
+ struct tegra_iovmm_area *vm) |
+{ |
+ return NULL; |
+} |
+ |
+static inline void tegra_iovmm_area_put(struct tegra_iovmm_area *vm) { } |
+ |
+static inline int tegra_iovmm_domain_init(struct tegra_iovmm_domain *domain, |
+ struct tegra_iovmm_device *dev, tegra_iovmm_addr_t start, |
+ tegra_iovmm_addr_t end) |
+{ |
+ return 0; |
+} |
+ |
+static inline int tegra_iovmm_register(struct tegra_iovmm_device *dev) |
+{ |
+ return 0; |
+} |
+ |
+static inline int tegra_iovmm_unregister(struct tegra_iovmm_device *dev) |
+{ |
+ return 0; |
+} |
+#endif /* CONFIG_TEGRA_IOVMM */ |
+ |
+ |
+#endif |