iommu/amd: Introduce Support for Extended Feature 2 Register
authorSuravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Wed, 13 Jul 2022 22:56:44 +0000 (17:56 -0500)
committerJoerg Roedel <jroedel@suse.de>
Fri, 15 Jul 2022 08:41:02 +0000 (10:41 +0200)
AMD IOMMU spec introduces additional extended feature register
in the IVRS IVHD offset 80h (for IVHD type 11h and 40h) and MMIO
offset 1A0h.

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Link: https://lore.kernel.org/r/20220713225651.20758-3-suravee.suthikulpanit@amd.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/amd/amd_iommu_types.h
drivers/iommu/amd/init.c

index 7c830e3..3c1205b 100644 (file)
@@ -67,6 +67,7 @@
 #define MMIO_INTCAPXT_EVT_OFFSET       0x0170
 #define MMIO_INTCAPXT_PPR_OFFSET       0x0178
 #define MMIO_INTCAPXT_GALOG_OFFSET     0x0180
+#define MMIO_EXT_FEATURES2     0x01A0
 #define MMIO_CMD_HEAD_OFFSET   0x2000
 #define MMIO_CMD_TAIL_OFFSET   0x2008
 #define MMIO_EVT_HEAD_OFFSET   0x2010
@@ -645,6 +646,9 @@ struct amd_iommu {
        /* Extended features */
        u64 features;
 
+       /* Extended features 2 */
+       u64 features2;
+
        /* IOMMUv2 */
        bool is_iommu_v2;
 
index a3c4fdd..15a836b 100644 (file)
@@ -114,7 +114,7 @@ struct ivhd_header {
 
        /* Following only valid on IVHD type 11h and 40h */
        u64 efr_reg; /* Exact copy of MMIO_EXT_FEATURES */
-       u64 res;
+       u64 efr_reg2;
 } __attribute__((packed));
 
 /*
@@ -283,8 +283,10 @@ static bool check_feature_on_all_iommus(u64 mask)
 static void __init early_iommu_features_init(struct amd_iommu *iommu,
                                             struct ivhd_header *h)
 {
-       if (amd_iommu_ivinfo & IOMMU_IVINFO_EFRSUP)
+       if (amd_iommu_ivinfo & IOMMU_IVINFO_EFRSUP) {
                iommu->features = h->efr_reg;
+               iommu->features2 = h->efr_reg2;
+       }
        if (amd_iommu_ivinfo & IOMMU_IVINFO_DMA_REMAP)
                amdr_ivrs_remap_support = true;
 }
@@ -1912,7 +1914,7 @@ static ssize_t amd_iommu_show_features(struct device *dev,
                                       char *buf)
 {
        struct amd_iommu *iommu = dev_to_amd_iommu(dev);
-       return sprintf(buf, "%llx\n", iommu->features);
+       return sprintf(buf, "%llx:%llx\n", iommu->features2, iommu->features);
 }
 static DEVICE_ATTR(features, S_IRUGO, amd_iommu_show_features, NULL);
 
@@ -1939,16 +1941,18 @@ static const struct attribute_group *amd_iommu_groups[] = {
  */
 static void __init late_iommu_features_init(struct amd_iommu *iommu)
 {
-       u64 features;
+       u64 features, features2;
 
        if (!(iommu->cap & (1 << IOMMU_CAP_EFR)))
                return;
 
        /* read extended feature bits */
        features = readq(iommu->mmio_base + MMIO_EXT_FEATURES);
+       features2 = readq(iommu->mmio_base + MMIO_EXT_FEATURES2);
 
        if (!iommu->features) {
                iommu->features = features;
+               iommu->features2 = features2;
                return;
        }
 
@@ -1956,9 +1960,13 @@ static void __init late_iommu_features_init(struct amd_iommu *iommu)
         * Sanity check and warn if EFR values from
         * IVHD and MMIO conflict.
         */
-       if (features != iommu->features)
-               pr_warn(FW_WARN "EFR mismatch. Use IVHD EFR (%#llx : %#llx).\n",
-                       features, iommu->features);
+       if (features != iommu->features ||
+           features2 != iommu->features2) {
+               pr_warn(FW_WARN
+                       "EFR mismatch. Use IVHD EFR (%#llx : %#llx), EFR2 (%#llx : %#llx).\n",
+                       features, iommu->features,
+                       features2, iommu->features2);
+       }
 }
 
 static int __init iommu_init_pci(struct amd_iommu *iommu)
@@ -2083,7 +2091,7 @@ static void print_iommu_info(void)
                pci_info(pdev, "Found IOMMU cap 0x%x\n", iommu->cap_ptr);
 
                if (iommu->cap & (1 << IOMMU_CAP_EFR)) {
-                       pr_info("Extended features (%#llx):", iommu->features);
+                       pr_info("Extended features (%#llx, %#llx):", iommu->features, iommu->features2);
 
                        for (i = 0; i < ARRAY_SIZE(feat_str); ++i) {
                                if (iommu_feature(iommu, (1ULL << i)))