From 4099818842abd98ef2b18a8ac7a2e2ad3bc3d7c2 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Fri, 2 Sep 2011 13:32:32 -0400 Subject: iommu/core: use the existing IS_ALIGNED macro Replace iommu's alignment checks with the existing IS_ALIGNED macro, to drop a few lines of code and utilize IS_ALIGNED's type safety. Signed-off-by: Ohad Ben-Cohen Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/iommu/iommu.c') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 6e6b6a1..e61a9ba 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include #include @@ -97,13 +98,11 @@ EXPORT_SYMBOL_GPL(iommu_domain_has_cap); int iommu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t paddr, int gfp_order, int prot) { - unsigned long invalid_mask; size_t size; size = 0x1000UL << gfp_order; - invalid_mask = size - 1; - BUG_ON((iova | paddr) & invalid_mask); + BUG_ON(!IS_ALIGNED(iova | paddr, size)); return iommu_ops->map(domain, iova, paddr, gfp_order, prot); } @@ -111,13 +110,11 @@ EXPORT_SYMBOL_GPL(iommu_map); int iommu_unmap(struct iommu_domain *domain, unsigned long iova, int gfp_order) { - unsigned long invalid_mask; size_t size; size = 0x1000UL << gfp_order; - invalid_mask = size - 1; - BUG_ON(iova & invalid_mask); + BUG_ON(!IS_ALIGNED(iova, size)); return iommu_ops->unmap(domain, iova, gfp_order); } -- cgit v1.1 From 85410340e0d0224c78c7d40a3ac7e1b3e9670cf1 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 6 Sep 2011 14:36:17 +0200 Subject: iommu/core: Use PAGE_SIZE instead of hard-coded value Replace the hard-coded 4kb by PAGE_SIZE to make iommu-api implementations possible on architectures where PAGE_SIZE != 4kb. Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/iommu/iommu.c') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index e61a9ba..30b0644 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -100,7 +100,7 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, { size_t size; - size = 0x1000UL << gfp_order; + size = PAGE_SIZE << gfp_order; BUG_ON(!IS_ALIGNED(iova | paddr, size)); @@ -112,7 +112,7 @@ int iommu_unmap(struct iommu_domain *domain, unsigned long iova, int gfp_order) { size_t size; - size = 0x1000UL << gfp_order; + size = PAGE_SIZE << gfp_order; BUG_ON(!IS_ALIGNED(iova, size)); -- cgit v1.1 From 4f3f8d9db359bbc780d482849f2a9c8b12f910b6 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Tue, 13 Sep 2011 15:25:23 -0400 Subject: iommu/core: Add fault reporting mechanism Add iommu fault report mechanism to the IOMMU API, so implementations could report about mmu faults (translation errors, hardware errors, etc..). Fault reports can be used in several ways: - mere logging - reset the device that accessed the faulting address (may be necessary in case the device is a remote processor for example) - implement dynamic PTE/TLB loading A dedicated iommu_set_fault_handler() API has been added to allow users, who are interested to receive such reports, to provide their handler. Signed-off-by: Ohad Ben-Cohen Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/iommu/iommu.c') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 6e6b6a1..b75d9fb 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -39,6 +39,19 @@ bool iommu_found(void) } EXPORT_SYMBOL_GPL(iommu_found); +/** + * iommu_set_fault_handler() - set a fault handler for an iommu domain + * @domain: iommu domain + * @handler: fault handler + */ +void iommu_set_fault_handler(struct iommu_domain *domain, + iommu_fault_handler_t handler) +{ + BUG_ON(!domain); + + domain->handler = handler; +} + struct iommu_domain *iommu_domain_alloc(void) { struct iommu_domain *domain; -- cgit v1.1 From 30bd918c7132adddd370c79fd5619bf108efd702 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Mon, 26 Sep 2011 09:11:46 -0400 Subject: iommu/core: export iommu_set_fault_handler() commit 4f3f8d9 "iommu/core: Add fault reporting mechanism" added the public iommu_set_fault_handler() symbol but forgot to export it. Fix that. Signed-off-by: Ohad Ben-Cohen Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/iommu/iommu.c') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index b75d9fb..3a07259 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -51,6 +51,7 @@ void iommu_set_fault_handler(struct iommu_domain *domain, domain->handler = handler; } +EXPORT_SYMBOL_GPL(iommu_set_fault_handler); struct iommu_domain *iommu_domain_alloc(void) { -- cgit v1.1 From 0ed6d2d27bcc2ace454a8c55446e1bc3efd2d529 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Tue, 27 Sep 2011 07:36:40 -0400 Subject: iommu/core: let drivers know if an iommu fault handler isn't installed Make report_iommu_fault() return -ENOSYS whenever an iommu fault handler isn't installed, so IOMMU drivers can then do their own platform-specific default behavior if they wanted. Fault handlers can still return -ENOSYS in case they want to elicit the default behavior of the IOMMU drivers. Signed-off-by: Ohad Ben-Cohen Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/iommu/iommu.c') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 3a07259..bd2d4d2 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -43,6 +43,12 @@ EXPORT_SYMBOL_GPL(iommu_found); * iommu_set_fault_handler() - set a fault handler for an iommu domain * @domain: iommu domain * @handler: fault handler + * + * This function should be used by IOMMU users which want to be notified + * whenever an IOMMU fault happens. + * + * The fault handler itself should return 0 on success, and an appropriate + * error code otherwise. */ void iommu_set_fault_handler(struct iommu_domain *domain, iommu_fault_handler_t handler) -- cgit v1.1 From ff21776d12ff7993a6b236b8273ef62777d25dfb Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 26 Aug 2011 16:48:26 +0200 Subject: Driver core: Add iommu_ops to bus_type This is the starting point to make the iommu_ops used for the iommu-api a per-bus-type structure. It is required to easily implement bus-specific setup in the iommu-layer. The first user will be the iommu-group attribute in sysfs. Acked-by: Greg Kroah-Hartman Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'drivers/iommu/iommu.c') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 30b0644..3343264 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -34,6 +34,37 @@ void register_iommu(struct iommu_ops *ops) iommu_ops = ops; } +static void iommu_bus_init(struct bus_type *bus, struct iommu_ops *ops) +{ +} + +/** + * bus_set_iommu - set iommu-callbacks for the bus + * @bus: bus. + * @ops: the callbacks provided by the iommu-driver + * + * This function is called by an iommu driver to set the iommu methods + * used for a particular bus. Drivers for devices on that bus can use + * the iommu-api after these ops are registered. + * This special function is needed because IOMMUs are usually devices on + * the bus itself, so the iommu drivers are not initialized when the bus + * is set up. With this function the iommu-driver can set the iommu-ops + * afterwards. + */ +int bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops) +{ + if (bus->iommu_ops != NULL) + return -EBUSY; + + bus->iommu_ops = ops; + + /* Do IOMMU specific setup for this bus-type */ + iommu_bus_init(bus, ops); + + return 0; +} +EXPORT_SYMBOL_GPL(bus_set_iommu); + bool iommu_found(void) { return iommu_ops != NULL; -- cgit v1.1 From 905d66c1e5dc8149e111f04a32bb193f25da1d53 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 6 Sep 2011 16:03:26 +0200 Subject: iommu/core: Add bus_type parameter to iommu_domain_alloc This is necessary to store a pointer to the bus-specific iommu_ops in the iommu-domain structure. It will be used later to call into bus-specific iommu-ops. Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/iommu/iommu.c') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 3343264..46e1c24 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include #include @@ -71,15 +72,26 @@ bool iommu_found(void) } EXPORT_SYMBOL_GPL(iommu_found); -struct iommu_domain *iommu_domain_alloc(void) +struct iommu_domain *iommu_domain_alloc(struct bus_type *bus) { struct iommu_domain *domain; + struct iommu_ops *ops; int ret; + if (bus->iommu_ops) + ops = bus->iommu_ops; + else + ops = iommu_ops; + + if (ops == NULL) + return NULL; + domain = kmalloc(sizeof(*domain), GFP_KERNEL); if (!domain) return NULL; + domain->ops = ops; + ret = iommu_ops->domain_init(domain); if (ret) goto out_free; -- cgit v1.1 From a1b60c1cd913c5ccfb38c717ba0bd22622425fa7 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 6 Sep 2011 18:46:34 +0200 Subject: iommu/core: Convert iommu_found to iommu_present With per-bus iommu_ops the iommu_found function needs to work on a bus_type too. This patch adds a bus_type parameter to that function and converts all call-places. The function is also renamed to iommu_present because the function now checks if an iommu is present for a given bus and does not check for a global iommu anymore. Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/iommu/iommu.c') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 46e1c24..ad8ce1a 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -66,11 +66,14 @@ int bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops) } EXPORT_SYMBOL_GPL(bus_set_iommu); -bool iommu_found(void) +bool iommu_present(struct bus_type *bus) { - return iommu_ops != NULL; + if (bus->iommu_ops != NULL) + return true; + else + return iommu_ops != NULL; } -EXPORT_SYMBOL_GPL(iommu_found); +EXPORT_SYMBOL_GPL(iommu_present); struct iommu_domain *iommu_domain_alloc(struct bus_type *bus) { -- cgit v1.1 From e5aa7f00776f2d73f410ede5c1f68246cdc83de1 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 6 Sep 2011 16:44:29 +0200 Subject: iommu/core: Use bus->iommu_ops in the iommu-api Use the per-bus iommu-ops in the functions of the iommu-api instead of the global iommu_ops. Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) (limited to 'drivers/iommu/iommu.c') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index ad8ce1a..1575aaa 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -110,34 +110,48 @@ EXPORT_SYMBOL_GPL(iommu_domain_alloc); void iommu_domain_free(struct iommu_domain *domain) { - iommu_ops->domain_destroy(domain); + if (likely(domain->ops->domain_destroy != NULL)) + domain->ops->domain_destroy(domain); + kfree(domain); } EXPORT_SYMBOL_GPL(iommu_domain_free); int iommu_attach_device(struct iommu_domain *domain, struct device *dev) { - return iommu_ops->attach_dev(domain, dev); + if (unlikely(domain->ops->attach_dev == NULL)) + return -ENODEV; + + return domain->ops->attach_dev(domain, dev); } EXPORT_SYMBOL_GPL(iommu_attach_device); void iommu_detach_device(struct iommu_domain *domain, struct device *dev) { - iommu_ops->detach_dev(domain, dev); + if (unlikely(domain->ops->detach_dev == NULL)) + return; + + domain->ops->detach_dev(domain, dev); } EXPORT_SYMBOL_GPL(iommu_detach_device); phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, unsigned long iova) { - return iommu_ops->iova_to_phys(domain, iova); + if (unlikely(domain->ops->iova_to_phys == NULL)) + return 0; + + return domain->ops->iova_to_phys(domain, iova); } EXPORT_SYMBOL_GPL(iommu_iova_to_phys); int iommu_domain_has_cap(struct iommu_domain *domain, unsigned long cap) { - return iommu_ops->domain_has_cap(domain, cap); + if (unlikely(domain->ops->domain_has_cap == NULL)) + return 0; + + return domain->ops->domain_has_cap(domain, cap); } EXPORT_SYMBOL_GPL(iommu_domain_has_cap); @@ -146,11 +160,14 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, { size_t size; + if (unlikely(domain->ops->map == NULL)) + return -ENODEV; + size = PAGE_SIZE << gfp_order; BUG_ON(!IS_ALIGNED(iova | paddr, size)); - return iommu_ops->map(domain, iova, paddr, gfp_order, prot); + return domain->ops->map(domain, iova, paddr, gfp_order, prot); } EXPORT_SYMBOL_GPL(iommu_map); @@ -158,10 +175,13 @@ int iommu_unmap(struct iommu_domain *domain, unsigned long iova, int gfp_order) { size_t size; + if (unlikely(domain->ops->unmap == NULL)) + return -ENODEV; + size = PAGE_SIZE << gfp_order; BUG_ON(!IS_ALIGNED(iova, size)); - return iommu_ops->unmap(domain, iova, gfp_order); + return domain->ops->unmap(domain, iova, gfp_order); } EXPORT_SYMBOL_GPL(iommu_unmap); -- cgit v1.1 From 94441c3bd99287b9d84f148a08cc9a44675ec749 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 6 Sep 2011 18:58:54 +0200 Subject: iommu/core: Remove global iommu_ops and register_iommu With all IOMMU drivers being converted to bus_set_iommu the global iommu_ops are no longer required. The same is true for the deprecated register_iommu function. Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) (limited to 'drivers/iommu/iommu.c') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 1575aaa..64419c8 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -25,16 +25,6 @@ #include #include -static struct iommu_ops *iommu_ops; - -void register_iommu(struct iommu_ops *ops) -{ - if (iommu_ops) - BUG(); - - iommu_ops = ops; -} - static void iommu_bus_init(struct bus_type *bus, struct iommu_ops *ops) { } @@ -68,34 +58,25 @@ EXPORT_SYMBOL_GPL(bus_set_iommu); bool iommu_present(struct bus_type *bus) { - if (bus->iommu_ops != NULL) - return true; - else - return iommu_ops != NULL; + return bus->iommu_ops != NULL; } EXPORT_SYMBOL_GPL(iommu_present); struct iommu_domain *iommu_domain_alloc(struct bus_type *bus) { struct iommu_domain *domain; - struct iommu_ops *ops; int ret; - if (bus->iommu_ops) - ops = bus->iommu_ops; - else - ops = iommu_ops; - - if (ops == NULL) + if (bus == NULL || bus->iommu_ops == NULL) return NULL; domain = kmalloc(sizeof(*domain), GFP_KERNEL); if (!domain) return NULL; - domain->ops = ops; + domain->ops = bus->iommu_ops; - ret = iommu_ops->domain_init(domain); + ret = domain->ops->domain_init(domain); if (ret) goto out_free; -- cgit v1.1