#include <linux/errno.h>
#include <linux/iommu.h>
-- 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;
#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
unsigned long iova);
extern int iommu_domain_has_cap(struct iommu_domain *domain,
unsigned long cap);
- #else /* CONFIG_IOMMU_API */
+ +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;
+
- static inline void register_iommu(struct iommu_ops *ops)
- {
+ + /*
+ + * if upper layers showed interest and installed a fault handler,
+ + * invoke it.
+ + */
+ + if (domain->handler)
+ + ret = domain->handler(domain, dev, iova, flags);
+
+ + 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;
}