]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iommu/amd: Allow matching ACPI HID devices without matching UIDs
authorMario Limonciello <mario.limonciello@amd.com>
Mon, 12 May 2025 17:30:32 +0000 (12:30 -0500)
committerJoerg Roedel <jroedel@suse.de>
Fri, 16 May 2025 06:48:18 +0000 (08:48 +0200)
A BIOS upgrade has changed the IVRS DTE UID for a device that no
longer matches the UID in the SSDT. In this case there is only
one ACPI device on the system with that _HID but the _UID mismatch.

IVRS:
```
              Subtable Type : F0 [Device Entry: ACPI HID Named Device]
                  Device ID : 0060
Data Setting (decoded below) : 40
                 INITPass : 0
                 EIntPass : 0
                 NMIPass : 0
                 Reserved : 0
                 System MGMT : 0
                 LINT0 Pass : 1
                 LINT1 Pass : 0
                   ACPI HID : "MSFT0201"
                   ACPI CID : 0000000000000000
                 UID Format : 02
                 UID Length : 09
                        UID : "\_SB.MHSP"
```

SSDT:
```
Device (MHSP)
{
    Name (_ADR, Zero)  // _ADR: Address
    Name (_HID, "MSFT0201")  // _HID: Hardware ID
    Name (_UID, One)  // _UID: Unique ID
```

To handle this case; while enumerating ACPI devices in
get_acpihid_device_id() count the number of matching ACPI devices with
a matching _HID. If there is exactly one _HID match then accept it even
if the UID doesn't match. Other operating systems allow this, but the
current IVRS spec leaves some ambiguity whether to allow or disallow it.
This should be clarified in future revisions of the spec. Output
'Firmware Bug' for this case to encourage it to be solved in the BIOS.

Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Reviewed-by: Vasant Hegde <vasant.hegde@amd.com>
Link: https://lore.kernel.org/r/20250512173129.1274275-1-superm1@kernel.org
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/amd/iommu.c

index 95520bcf6c0e1230d8799ee4db02369ec8d3ca0b..e6506440b92754158586fa39fe2d0d2175ae2e1e 100644 (file)
@@ -241,7 +241,9 @@ static inline int get_acpihid_device_id(struct device *dev,
                                        struct acpihid_map_entry **entry)
 {
        struct acpi_device *adev = ACPI_COMPANION(dev);
-       struct acpihid_map_entry *p;
+       struct acpihid_map_entry *p, *p1 = NULL;
+       int hid_count = 0;
+       bool fw_bug;
 
        if (!adev)
                return -ENODEV;
@@ -249,12 +251,33 @@ static inline int get_acpihid_device_id(struct device *dev,
        list_for_each_entry(p, &acpihid_map, list) {
                if (acpi_dev_hid_uid_match(adev, p->hid,
                                           p->uid[0] ? p->uid : NULL)) {
-                       if (entry)
-                               *entry = p;
-                       return p->devid;
+                       p1 = p;
+                       fw_bug = false;
+                       hid_count = 1;
+                       break;
+               }
+
+               /*
+                * Count HID matches w/o UID, raise FW_BUG but allow exactly one match
+                */
+               if (acpi_dev_hid_match(adev, p->hid)) {
+                       p1 = p;
+                       hid_count++;
+                       fw_bug = true;
                }
        }
-       return -EINVAL;
+
+       if (!p1)
+               return -EINVAL;
+       if (fw_bug)
+               dev_err_once(dev, FW_BUG "No ACPI device matched UID, but %d device%s matched HID.\n",
+                            hid_count, hid_count > 1 ? "s" : "");
+       if (hid_count > 1)
+               return -EINVAL;
+       if (entry)
+               *entry = p1;
+
+       return p1->devid;
 }
 
 static inline int get_device_sbdf_id(struct device *dev)