From: Joerg Roedel Date: Fri, 30 Sep 2011 14:47:19 +0000 (+0200) Subject: Merge branches 'debug/dma-api', 'arm/omap', 'arm/msm', 'core', 'iommu/fault-reporting... X-Git-Tag: next-20111004~31^2 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=1a9ca7b0591d4806014bdf24fd8c12ea494f6673;p=karo-tx-linux.git Merge branches 'debug/dma-api', 'arm/omap', 'arm/msm', 'core', 'iommu/fault-reporting' and 'api/iommu-ops-per-bus' into next Conflicts: drivers/iommu/iommu.c --- 1a9ca7b0591d4806014bdf24fd8c12ea494f6673 diff --cc drivers/iommu/iommu.c index 6e6b6a11b3ce,bd2d4d2764dd,64419c88727e..2fb2963df553 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@@@ -23,23 -23,43 -25,44 +25,64 @@@@ #include #include -- static struct iommu_ops *iommu_ops; ++ static void iommu_bus_init(struct bus_type *bus, struct iommu_ops *ops) ++ { ++ } -- void register_iommu(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 (iommu_ops) -- BUG(); ++ if (bus->iommu_ops != NULL) ++ return -EBUSY; + - iommu_ops = ops; ++ bus->iommu_ops = ops; ++ ++ /* Do IOMMU specific setup for this bus-type */ ++ iommu_bus_init(bus, ops); + - iommu_ops = ops; ++ return 0; } ++ EXPORT_SYMBOL_GPL(bus_set_iommu); -- bool iommu_found(void) ++ bool iommu_present(struct bus_type *bus) { -- return iommu_ops != NULL; ++ return bus->iommu_ops != NULL; } -- EXPORT_SYMBOL_GPL(iommu_found); ++ EXPORT_SYMBOL_GPL(iommu_present); - struct iommu_domain *iommu_domain_alloc(void) + +/** + + * 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) + +{ + + BUG_ON(!domain); + + + + domain->handler = handler; + +} + +EXPORT_SYMBOL_GPL(iommu_set_fault_handler); + + - struct iommu_domain *iommu_domain_alloc(void) ++ struct iommu_domain *iommu_domain_alloc(struct bus_type *bus) { struct iommu_domain *domain; int ret; diff --cc include/linux/iommu.h index 9940319d6f9d,ddad0ae0a433,609ebf6bbe0c..432acc4c054d --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@@@ -25,10 -25,19 -25,13 +25,22 @@@@ #define IOMMU_WRITE (2) #define IOMMU_CACHE (4) /* DMA cache coherency */ ++ struct iommu_ops; ++ struct bus_type; struct device; + +struct iommu_domain; + + + +/* iommu fault flags */ + +#define IOMMU_FAULT_READ 0x0 + +#define IOMMU_FAULT_WRITE 0x1 + + + +typedef int (*iommu_fault_handler_t)(struct iommu_domain *, + + struct device *, unsigned long, int); struct iommu_domain { ++ struct iommu_ops *ops; void *priv; + + iommu_fault_handler_t handler; }; #define IOMMU_CAP_CACHE_COHERENCY 0x1 @@@@ -67,14 -76,55 -70,12 +79,53 @@@@ extern phys_addr_t iommu_iova_to_phys(s unsigned long iova); extern int iommu_domain_has_cap(struct iommu_domain *domain, unsigned long cap); + +extern void iommu_set_fault_handler(struct iommu_domain *domain, + + iommu_fault_handler_t handler); + + + +/** + + * report_iommu_fault() - report about an IOMMU fault to the IOMMU framework + + * @domain: the iommu domain where the fault has happened + + * @dev: the device where the fault has happened + + * @iova: the faulting address + + * @flags: mmu fault flags (e.g. IOMMU_FAULT_READ/IOMMU_FAULT_WRITE/...) + + * + + * This function should be called by the low-level IOMMU implementations + + * whenever IOMMU faults happen, to allow high-level users, that are + + * interested in such events, to know about them. + + * + + * This event may be useful for several possible use cases: + + * - mere logging of the event + + * - dynamic TLB/PTE loading + + * - if restarting of the faulting device is required + + * + + * Returns 0 on success and an appropriate error code otherwise (if dynamic + + * PTE/TLB loading will one day be supported, implementations will be able + + * to tell whether it succeeded or not according to this return value). + + * + + * Specifically, -ENOSYS is returned if a fault handler isn't installed + + * (though fault handlers can also return -ENOSYS, in case they want to + + * elicit the default behavior of the IOMMU drivers). + + */ + +static inline int report_iommu_fault(struct iommu_domain *domain, + + struct device *dev, unsigned long iova, int flags) + +{ + + int ret = -ENOSYS; + - #else /* CONFIG_IOMMU_API */ + + /* + + * if upper layers showed interest and installed a fault handler, + + * invoke it. + + */ + + if (domain->handler) + + ret = domain->handler(domain, dev, iova, flags); + - static inline void register_iommu(struct iommu_ops *ops) - { + + return ret; +} - static inline bool iommu_found(void) + #else /* CONFIG_IOMMU_API */ + - static inline void register_iommu(struct iommu_ops *ops) - { - } ++ struct iommu_ops {}; + - static inline bool iommu_found(void) ++ static inline bool iommu_present(struct bus_type *bus) { return false; }