git: 1e6db7be6921 - main - pciconf(8): dump AMD IOMMU Base Capability

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Wed, 10 Apr 2024 05:28:59 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=1e6db7be692198acfa7f02dea83aa9aa1dfce273

commit 1e6db7be692198acfa7f02dea83aa9aa1dfce273
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-04-09 22:13:59 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-04-10 05:28:24 +0000

    pciconf(8): dump AMD IOMMU Base Capability
    
    Reviewed by:    emaste
    Sponsored by:   Advanced Micro Devices (AMD)
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D44732
---
 usr.sbin/pciconf/cap.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 115 insertions(+)

diff --git a/usr.sbin/pciconf/cap.c b/usr.sbin/pciconf/cap.c
index 8595bff3d3d7..e252926ab9be 100644
--- a/usr.sbin/pciconf/cap.c
+++ b/usr.sbin/pciconf/cap.c
@@ -376,6 +376,118 @@ cap_subvendor(int fd, struct pci_conf *p, uint8_t ptr)
 	printf("PCI Bridge subvendor=0x%04x subdevice=0x%04x", ssvid, ssid);
 }
 
+static const char *
+cap_secdev_amdiommu_decode_vasize(uint32_t misc0)
+{
+	switch (misc0 & PCIM_AMDIOMMU_MISC0_VASIZE_MASK) {
+	case PCIM_AMDIOMMU_MISC0_VASIZE_32:
+		return ("32bit");
+	case PCIM_AMDIOMMU_MISC0_VASIZE_40:
+		return ("40bit");
+	case PCIM_AMDIOMMU_MISC0_VASIZE_48:
+		return ("48bit");
+	case PCIM_AMDIOMMU_MISC0_VASIZE_64:
+		return ("64bit");
+	default:
+		return ("unknown");
+	}
+}
+
+static const char *
+cap_secdev_amdiommu_decode_pasize(uint32_t misc0)
+{
+	switch (misc0 & PCIM_AMDIOMMU_MISC0_PASIZE_MASK) {
+	case PCIM_AMDIOMMU_MISC0_PASIZE_40:
+		return ("40bit");
+	case PCIM_AMDIOMMU_MISC0_PASIZE_48:
+		return ("48bit");
+	case PCIM_AMDIOMMU_MISC0_PASIZE_52:
+		return ("52bit");
+	default:
+		return ("unknown");
+	}
+}
+
+static const char *
+cap_secdev_amdiommu_decode_gvasize(uint32_t misc0)
+{
+	switch (misc0 & PCIM_AMDIOMMU_MISC0_GVASIZE_MASK) {
+	case PCIM_AMDIOMMU_MISC0_GVASIZE_48:
+		return ("48bit");
+	case PCIM_AMDIOMMU_MISC0_GVASIZE_57:
+		return ("57bit");
+	default:
+		return ("unknown");
+	}
+}
+
+static void
+cap_secdev(int fd, struct pci_conf *p, uint8_t ptr)
+{
+	uint32_t cap_h;
+	uint32_t cap_type, cap_rev;
+	uint32_t base_low, base_high;
+	uint32_t range;
+	uint32_t misc0, misc1;
+	const char *delim;
+
+	cap_h = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_CAP_HEADER, 4);
+	cap_type = cap_h & PCIM_AMDIOMMU_CAP_TYPE_MASK;
+	cap_rev = cap_h & PCIM_AMDIOMMU_CAP_REV_MASK;
+	if (cap_type != PCIM_AMDIOMMU_CAP_TYPE_VAL ||
+	    cap_rev != PCIM_AMDIOMMU_CAP_REV_VAL) {
+		printf("Secure Device Type=0x%1x Rev=0x%02x\n",
+		    cap_type >> 16, cap_rev >> 19);
+		return;
+	}
+	base_low = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_BASE_LOW,
+	    4);
+	base_high = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_BASE_HIGH,
+	    4);
+	printf("AMD IOMMU Base Capability Base=%#018jx/%sabled",
+	    (uintmax_t)(base_low & PCIM_AMDIOMMU_BASE_LOW_ADDRM) +
+	    ((uintmax_t)base_high << 32),
+	    (base_low & PCIM_AMDIOMMU_BASE_LOW_EN) != 0 ? "En" : "Dis");
+
+	delim = "\n\t\t";
+#define	PRINTCAP(bit, name)				\
+	if ((cap_h & PCIM_AMDIOMMU_CAP_ ##bit) != 0) {	\
+		printf("%s%s", delim, #name);		\
+		delim = ",";				\
+	}
+	PRINTCAP(CAPEXT, CapExt);
+	PRINTCAP(EFR, EFRSup);
+	PRINTCAP(NPCACHE, NpCache);
+	PRINTCAP(HTTUN, HtTunnel);
+	PRINTCAP(IOTLB, IotlbSup);
+#undef PRINTCAP
+
+	range = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_RANGE, 4);
+	printf("\n\t\tUnitId=%d", range & PCIM_AMDIOMMU_RANGE_UNITID_MASK);
+	if ((range & PCIM_AMDIOMMU_RANGE_RNGVALID) != 0) {
+		printf(" BusNum=%#06x FirstDev=%#06x LastDev=%#06x",
+		    (range & PCIM_AMDIOMMU_RANGE_BUSNUM_MASK) >> 8,
+		    (range & PCIM_AMDIOMMU_RANGE_FIRSTDEV_MASK) >> 16,
+		    (range & PCIM_AMDIOMMU_RANGE_LASTDEV_MASK) >> 24);
+	}
+
+	misc0 = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_MISC0, 4);
+	printf("\n\t\tMsiNum=%d MsiNumPPR=%d HtAtsResv=%d",
+	    misc0 & PCIM_AMDIOMMU_MISC0_MSINUM_MASK,
+	    (misc0 & PCIM_AMDIOMMU_MISC0_MSINUMPPR_MASK) >> 27,
+	    (misc0 & PCIM_AMDIOMMU_MISC0_HTATSRESV) != 0);
+	if ((cap_h & PCIM_AMDIOMMU_CAP_CAPEXT) != 0) {
+		misc1 = read_config(fd, &p->pc_sel,
+		    ptr + PCIR_AMDIOMMU_MISC1, 4);
+		printf(" MsiNumGA=%d",
+		    misc1 & PCIM_AMDIOMMU_MISC1_MSINUMGA_MASK);
+	}
+	printf("\n\t\tVAsize=%s PAsize=%s GVAsize=%s",
+	    cap_secdev_amdiommu_decode_vasize(misc0),
+	    cap_secdev_amdiommu_decode_pasize(misc0),
+	    cap_secdev_amdiommu_decode_gvasize(misc0));
+}
+
 #define	MAX_PAYLOAD(field)		(128 << (field))
 
 static const char *
@@ -813,6 +925,9 @@ list_caps(int fd, struct pci_conf *p, int level)
 		case PCIY_SUBVENDOR:
 			cap_subvendor(fd, p, ptr);
 			break;
+		case PCIY_SECDEV:
+			cap_secdev(fd, p, ptr);
+			break;
 		case PCIY_EXPRESS:
 			express = 1;
 			cap_express(fd, p, ptr);