iommu/core: Add fault reporting mechanism
Ohad Ben-Cohen [Tue, 13 Sep 2011 19:25:23 +0000 (15:25 -0400)]
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 <ohad@wizery.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>

drivers/iommu/iommu.c
include/linux/iommu.h

index 30b0644..c0afcd4 100644 (file)
@@ -40,6 +40,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;
index 9940319..d084e87 100644 (file)
 #define IOMMU_CACHE    (4) /* DMA cache coherency */
 
 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 {
        void *priv;
+       iommu_fault_handler_t handler;
 };
 
 #define IOMMU_CAP_CACHE_COHERENCY      0x1
@@ -67,6 +76,43 @@ extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
                                      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).
+ */
+static inline int report_iommu_fault(struct iommu_domain *domain,
+               struct device *dev, unsigned long iova, int flags)
+{
+       int ret = 0;
+
+       /*
+        * if upper layers showed interest and installed a fault handler,
+        * invoke it.
+        */
+       if (domain->handler)
+               ret = domain->handler(domain, dev, iova, flags);
+
+       return ret;
+}
 
 #else /* CONFIG_IOMMU_API */
 
@@ -123,6 +169,11 @@ static inline int domain_has_cap(struct iommu_domain *domain,
        return 0;
 }
 
+static inline void iommu_set_fault_handler(struct iommu_domain *domain,
+                                       iommu_fault_handler_t handler)
+{
+}
+
 #endif /* CONFIG_IOMMU_API */
 
 #endif /* __LINUX_IOMMU_H */