iommu/amd: Don't copy GCR3 table root pointer
authorBaoquan He <bhe@redhat.com>
Wed, 9 Aug 2017 08:33:43 +0000 (16:33 +0800)
committerJoerg Roedel <jroedel@suse.de>
Tue, 15 Aug 2017 16:14:41 +0000 (18:14 +0200)
When iommu is pre_enabled in kdump kernel, if a device is set up with
guest translations (DTE.GV=1), then don't copy GCR3 table root pointer
but move the device over to an empty guest-cr3 table and handle the
faults in the PPR log (which answer them with INVALID). After all these
PPR faults are recoverable for the device and we should not allow the
device to change old-kernels data when we don't have to.

Signed-off-by: Baoquan He <bhe@redhat.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_init.c
drivers/iommu/amd_iommu_proto.h
drivers/iommu/amd_iommu_types.h
drivers/iommu/amd_iommu_v2.c

index eebf4590cef9f4ec69b3173649ba61c6a5537ab5..9e8ea190779606d4ce07657fa688f54e68676f22 100644 (file)
@@ -102,30 +102,6 @@ int amd_iommu_max_glx_val = -1;
 
 static const struct dma_map_ops amd_iommu_dma_ops;
 
-/*
- * This struct contains device specific data for the IOMMU
- */
-struct iommu_dev_data {
-       struct list_head list;            /* For domain->dev_list */
-       struct list_head dev_data_list;   /* For global dev_data_list */
-       struct protection_domain *domain; /* Domain the device is bound to */
-       u16 devid;                        /* PCI Device ID */
-       u16 alias;                        /* Alias Device ID */
-       bool iommu_v2;                    /* Device can make use of IOMMUv2 */
-       bool passthrough;                 /* Device is identity mapped */
-       struct {
-               bool enabled;
-               int qdep;
-       } ats;                            /* ATS state */
-       bool pri_tlp;                     /* PASID TLB required for
-                                            PPR completions */
-       u32 errata;                       /* Bitmap for errata to apply */
-       bool use_vapic;                   /* Enable device to use vapic mode */
-       bool defer_attach;
-
-       struct ratelimit_state rs;        /* Ratelimit IOPF messages */
-};
-
 /*
  * general struct to manage commands send to an IOMMU
  */
@@ -386,10 +362,11 @@ static struct iommu_dev_data *find_dev_data(u16 devid)
        return dev_data;
 }
 
-static struct iommu_dev_data *get_dev_data(struct device *dev)
+struct iommu_dev_data *get_dev_data(struct device *dev)
 {
        return dev->archdata.iommu;
 }
+EXPORT_SYMBOL(get_dev_data);
 
 /*
 * Find or create an IOMMU group for a acpihid device.
@@ -2540,6 +2517,7 @@ static int dir2prot(enum dma_data_direction direction)
        else
                return 0;
 }
+
 /*
  * This function contains common code for mapping of a physically
  * contiguous memory region into DMA address space. It is used by all
index c348732f27d7a1591f51ebaca407589441d8dac4..88e7a6e950ae547769e4e3d5f33c496e2c5fcaff 100644 (file)
@@ -214,6 +214,7 @@ u16 *amd_iommu_alias_table;
  * for a specific device. It is also indexed by the PCI device id.
  */
 struct amd_iommu **amd_iommu_rlookup_table;
+EXPORT_SYMBOL(amd_iommu_rlookup_table);
 
 /*
  * This table is used to find the irq remapping table for a given device id
@@ -269,6 +270,7 @@ bool translation_pre_enabled(struct amd_iommu *iommu)
 {
        return (iommu->flags & AMD_IOMMU_FLAG_TRANS_PRE_ENABLED);
 }
+EXPORT_SYMBOL(translation_pre_enabled);
 
 static void clear_translation_pre_enabled(struct amd_iommu *iommu)
 {
@@ -859,6 +861,7 @@ static bool copy_device_table(void)
        struct amd_iommu *iommu;
        u16 dom_id, dte_v, irq_v;
        gfp_t gfp_flag;
+       u64 tmp;
 
        if (!amd_iommu_pre_enabled)
                return false;
@@ -910,6 +913,15 @@ static bool copy_device_table(void)
                        old_dev_tbl_cpy[devid].data[0] = old_devtb[devid].data[0];
                        old_dev_tbl_cpy[devid].data[1] = old_devtb[devid].data[1];
                        __set_bit(dom_id, amd_iommu_pd_alloc_bitmap);
+                       /* If gcr3 table existed, mask it out */
+                       if (old_devtb[devid].data[0] & DTE_FLAG_GV) {
+                               tmp = DTE_GCR3_VAL_B(~0ULL) << DTE_GCR3_SHIFT_B;
+                               tmp |= DTE_GCR3_VAL_C(~0ULL) << DTE_GCR3_SHIFT_C;
+                               old_dev_tbl_cpy[devid].data[1] &= ~tmp;
+                               tmp = DTE_GCR3_VAL_A(~0ULL) << DTE_GCR3_SHIFT_A;
+                               tmp |= DTE_FLAG_GV;
+                               old_dev_tbl_cpy[devid].data[0] &= ~tmp;
+                       }
                }
 
                irq_v = old_devtb[devid].data[2] & DTE_IRQ_REMAP_ENABLE;
index a9666d2005bb7d957c4fd026ab3c5fbf87b724f9..90e62e9b01c5a48bccd79c6b4f544081e68b8524 100644 (file)
@@ -88,4 +88,5 @@ static inline bool iommu_feature(struct amd_iommu *iommu, u64 f)
 }
 
 extern bool translation_pre_enabled(struct amd_iommu *iommu);
+extern struct iommu_dev_data *get_dev_data(struct device *dev);
 #endif /* _ASM_X86_AMD_IOMMU_PROTO_H  */
index f0979183ec9b96c98d0430c5807d368b35a642e6..9e5af13be7c5cdd846154aa321f23e6f886fda2a 100644 (file)
@@ -618,6 +618,30 @@ struct devid_map {
        bool cmd_line;
 };
 
+/*
+ * This struct contains device specific data for the IOMMU
+ */
+struct iommu_dev_data {
+       struct list_head list;            /* For domain->dev_list */
+       struct list_head dev_data_list;   /* For global dev_data_list */
+       struct protection_domain *domain; /* Domain the device is bound to */
+       u16 devid;                        /* PCI Device ID */
+       u16 alias;                        /* Alias Device ID */
+       bool iommu_v2;                    /* Device can make use of IOMMUv2 */
+       bool passthrough;                 /* Device is identity mapped */
+       struct {
+               bool enabled;
+               int qdep;
+       } ats;                            /* ATS state */
+       bool pri_tlp;                     /* PASID TLB required for
+                                            PPR completions */
+       u32 errata;                       /* Bitmap for errata to apply */
+       bool use_vapic;                   /* Enable device to use vapic mode */
+       bool defer_attach;
+
+       struct ratelimit_state rs;        /* Ratelimit IOPF messages */
+};
+
 /* Map HPET and IOAPIC ids to the devid used by the IOMMU */
 extern struct list_head ioapic_map;
 extern struct list_head hpet_map;
index 6629c472eafd828bb45a9e7fe3a4260c2e199de2..e705fac89cb4448a56876ced9c0ac8e086f08723 100644 (file)
@@ -562,14 +562,30 @@ static int ppr_notifier(struct notifier_block *nb, unsigned long e, void *data)
        unsigned long flags;
        struct fault *fault;
        bool finish;
-       u16 tag;
+       u16 tag, devid;
        int ret;
+       struct iommu_dev_data *dev_data;
+       struct pci_dev *pdev = NULL;
 
        iommu_fault = data;
        tag         = iommu_fault->tag & 0x1ff;
        finish      = (iommu_fault->tag >> 9) & 1;
 
+       devid = iommu_fault->device_id;
+       pdev = pci_get_bus_and_slot(PCI_BUS_NUM(devid), devid & 0xff);
+       if (!pdev)
+               return -ENODEV;
+       dev_data = get_dev_data(&pdev->dev);
+
+       /* In kdump kernel pci dev is not initialized yet -> send INVALID */
        ret = NOTIFY_DONE;
+       if (translation_pre_enabled(amd_iommu_rlookup_table[devid])
+               && dev_data->defer_attach) {
+               amd_iommu_complete_ppr(pdev, iommu_fault->pasid,
+                                      PPR_INVALID, tag);
+               goto out;
+       }
+
        dev_state = get_device_state(iommu_fault->device_id);
        if (dev_state == NULL)
                goto out;