summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Mustacchi <rm@fingolfin.org>2021-10-18 15:15:15 -0700
committerRobert Mustacchi <rm@fingolfin.org>2021-10-28 14:30:51 -0700
commitbc729d490568bb6599aac50d559e64c366738e85 (patch)
tree6c6f946281f35158ef8628d2794ae0522d01ab05
parentaa8590303de9350e3cbe3b4eb3c3d8f951d77f46 (diff)
downloadillumos-joyent-bc729d490568bb6599aac50d559e64c366738e85.tar.gz
14174 pcieadm needs to handle v1 pcie cap better
14175 pcieadm show-devs can do better on missing pcidb entries 14176 pcieadm aer cap compares wrong field Reviewed by: Patrick Mooney <pmooney@pfmooney.com> Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r--usr/src/cmd/pcieadm/pcieadm_cfgspace.c140
-rw-r--r--usr/src/cmd/pcieadm/pcieadm_devs.c10
2 files changed, 144 insertions, 6 deletions
diff --git a/usr/src/cmd/pcieadm/pcieadm_cfgspace.c b/usr/src/cmd/pcieadm/pcieadm_cfgspace.c
index 58fd81fdd9..9737c04fa1 100644
--- a/usr/src/cmd/pcieadm/pcieadm_cfgspace.c
+++ b/usr/src/cmd/pcieadm/pcieadm_cfgspace.c
@@ -1749,8 +1749,56 @@ static pcieadm_regdef_t pcieadm_regdef_pcie_slotsts2[] = {
{ -1, -1, NULL }
};
+static pcieadm_cfgspace_print_t pcieadm_cap_pcie_v1_dev[] = {
+ { PCIE_PCIECAP, 2, "cap", "Capability Register",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_cap },
+ { PCIE_DEVCAP, 4, "devcap", "Device Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap },
+ { PCIE_DEVSTS, 2, "devsts", "Device Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_pcie_v1_link[] = {
+ { PCIE_PCIECAP, 2, "cap", "Capability Register",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_cap },
+ { PCIE_DEVCAP, 4, "devcap", "Device Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap },
+ { PCIE_DEVSTS, 2, "devsts", "Device Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts },
+ { PCIE_LINKCAP, 4, "linkcap", "Link Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkcap },
+ { PCIE_LINKCTL, 2, "linkctl", "Link Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkctl },
+ { PCIE_LINKSTS, 2, "linksts", "Link Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linksts },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_pcie_v1_slot[] = {
+ { PCIE_PCIECAP, 2, "cap", "Capability Register",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_cap },
+ { PCIE_DEVCAP, 4, "devcap", "Device Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap },
+ { PCIE_DEVSTS, 2, "devsts", "Device Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts },
+ { PCIE_LINKCAP, 4, "linkcap", "Link Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkcap },
+ { PCIE_LINKCTL, 2, "linkctl", "Link Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkctl },
+ { PCIE_LINKSTS, 2, "linksts", "Link Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linksts },
+ { PCIE_SLOTCAP, 4, "slotcap", "Slot Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotcap },
+ { PCIE_SLOTCTL, 2, "slotctl", "Slot Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotctl },
+ { PCIE_SLOTSTS, 2, "slotsts", "Slot Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotsts },
+ { -1, -1, NULL }
+};
-static pcieadm_cfgspace_print_t pcieadm_cap_pcie_v1[] = {
+
+static pcieadm_cfgspace_print_t pcieadm_cap_pcie_v1_all[] = {
{ PCIE_PCIECAP, 2, "cap", "Capability Register",
pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_cap },
{ PCIE_DEVCAP, 4, "devcap", "Device Capabilities",
@@ -3908,6 +3956,90 @@ pcieadm_cap_info_pcipm(pcieadm_cfgspace_walk_t *walkp,
}
/*
+ * The PCIe capability underwent a few changes. In version 1 of the capability,
+ * devices were not required to implement the entire capability. In particular,
+ * endpoints did not need to implement anything more than the link status
+ * register. In the v2 capability, this was changed such that all devices had to
+ * implement the entire capbility, but otherwise hardcode registers to zero. As
+ * such we get to play guess the length based on the device type.
+ */
+static pcieadm_cap_vers_t pcieadm_cap_vers_pcie_v1_dev = {
+ 1, 0x0c, pcieadm_cap_pcie_v1_dev
+};
+
+static pcieadm_cap_vers_t pcieadm_cap_vers_pcie_v1_link = {
+ 1, 0x14, pcieadm_cap_pcie_v1_link
+};
+
+static pcieadm_cap_vers_t pcieadm_cap_vers_pcie_v1_slot = {
+ 1, 0x1c, pcieadm_cap_pcie_v1_slot
+};
+
+static pcieadm_cap_vers_t pcieadm_cap_vers_pcie_v1_all = {
+ 1, 0x24, pcieadm_cap_pcie_v1_all
+};
+
+static pcieadm_cap_vers_t pcieadm_cap_vers_pcie_v2 = {
+ 2, 0x4c, pcieadm_cap_pcie_v2
+};
+
+static void
+pcieadm_cap_info_pcie(pcieadm_cfgspace_walk_t *walkp,
+ const pcieadm_pci_cap_t *cap, uint32_t off,
+ const pcieadm_cap_vers_t **versp, uint32_t *lenp,
+ const pcieadm_subcap_t **subcap)
+{
+ uint8_t vers = walkp->pcw_data->pcb_u8[off + 2] & 0xf;
+ uint16_t pcie = walkp->pcw_data->pcb_u8[off + 2] |
+ (walkp->pcw_data->pcb_u8[off + 3] << 8);
+
+ /*
+ * Version 2 is simple. There's only one thing to do, so we do it. For
+ * version 1 we need to look at the device type.
+ */
+ *subcap = NULL;
+ if (vers == 2) {
+ *versp = &pcieadm_cap_vers_pcie_v2;
+ *lenp = (*versp)->ppr_len;
+ return;
+ } else if (vers != 1) {
+ *versp = NULL;
+ *lenp = 0;
+ return;
+ }
+
+ switch (pcie & PCIE_PCIECAP_DEV_TYPE_MASK) {
+ case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV:
+ case PCIE_PCIECAP_DEV_TYPE_PCI_DEV:
+ *versp = &pcieadm_cap_vers_pcie_v1_link;
+ break;
+ case PCIE_PCIECAP_DEV_TYPE_RC_IEP:
+ *versp = &pcieadm_cap_vers_pcie_v1_dev;
+ break;
+ case PCIE_PCIECAP_DEV_TYPE_UP:
+ case PCIE_PCIECAP_DEV_TYPE_DOWN:
+ case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI:
+ case PCIE_PCIECAP_DEV_TYPE_PCI2PCIE:
+ if ((pcie & PCIE_PCIECAP_SLOT_IMPL) != 0) {
+ *versp = &pcieadm_cap_vers_pcie_v1_slot;
+ } else {
+ *versp = &pcieadm_cap_vers_pcie_v1_link;
+ }
+ break;
+ case PCIE_PCIECAP_DEV_TYPE_ROOT:
+ case PCIE_PCIECAP_DEV_TYPE_RC_EC:
+ *versp = &pcieadm_cap_vers_pcie_v1_all;
+ break;
+ default:
+ *versp = NULL;
+ *lenp = 0;
+ return;
+ }
+
+ *lenp = (*versp)->ppr_len;
+}
+
+/*
* The length of the MSI capability depends on bits in its control field. As
* such we use a custom function to extract the length and treat each of these
* variants as thought it were a different version.
@@ -3998,7 +4130,7 @@ pcieadm_cap_info_aer(pcieadm_cfgspace_walk_t *walkp,
const pcieadm_cap_vers_t **versp, uint32_t *lenp,
const pcieadm_subcap_t **subcap)
{
- if (walkp->pcw_dtype == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) {
+ if (walkp->pcw_pcietype == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) {
uint8_t vers;
*subcap = NULL;
@@ -4156,9 +4288,7 @@ pcieadm_pci_cap_t pcieadm_pci_caps[] = {
pcieadm_cap_info_fixed, { 0, 8, pcieadm_cap_bridge_subsys } },
{ PCI_CAP_ID_AGP_8X, "agp8x", "AGP 8x" },
{ PCI_CAP_ID_SECURE_DEV, "secdev", "Secure Device" },
- { PCI_CAP_ID_PCI_E, "pcie", "PCI Express", pcieadm_cap_info_vers,
- { { 1, 0x24, pcieadm_cap_pcie_v1 },
- { 2, 0x3c, pcieadm_cap_pcie_v2 } } },
+ { PCI_CAP_ID_PCI_E, "pcie", "PCI Express", pcieadm_cap_info_pcie },
{ PCI_CAP_ID_MSI_X, "msix", "MSI-X", pcieadm_cap_info_fixed,
{ { 0, 12, pcieadm_cap_msix } } },
{ PCI_CAP_ID_SATA, "sata", "Serial ATA Configuration",
diff --git a/usr/src/cmd/pcieadm/pcieadm_devs.c b/usr/src/cmd/pcieadm/pcieadm_devs.c
index 5ca19ea1d9..dc157d8d2a 100644
--- a/usr/src/cmd/pcieadm/pcieadm_devs.c
+++ b/usr/src/cmd/pcieadm/pcieadm_devs.c
@@ -327,6 +327,7 @@ pcieadm_show_devs_walk_cb(di_node_t node, void *arg)
char *path = NULL;
pcieadm_show_devs_t *psd = arg;
int ret = DI_WALK_CONTINUE;
+ char venstr[64], devstr[64];
pcieadm_show_devs_ofmt_t oarg;
pcidb_hdl_t *pcidb = psd->psd_pia->pia_pcidb;
@@ -376,6 +377,10 @@ pcieadm_show_devs_walk_cb(di_node_t node, void *arg)
oarg.psdo_vid);
if (vend != NULL) {
oarg.psdo_vendor = pcidb_vendor_name(vend);
+ } else {
+ (void) snprintf(venstr, sizeof (venstr),
+ "Unknown vendor: 0x%x", oarg.psdo_vid);
+ oarg.psdo_vendor = venstr;
}
}
@@ -385,7 +390,10 @@ pcieadm_show_devs_walk_cb(di_node_t node, void *arg)
oarg.psdo_vid, oarg.psdo_did);
if (dev != NULL) {
oarg.psdo_device = pcidb_device_name(dev);
-
+ } else {
+ (void) snprintf(devstr, sizeof (devstr),
+ "Unknown device: 0x%x", oarg.psdo_did);
+ oarg.psdo_device = devstr;
}
}