@@ -10,6 +10,8 @@
#include <stdio.h>
#include <string.h>
+#include <fcntl.h>
+#include <stdlib.h>
#include "lspci.h"
@@ -1381,6 +1383,97 @@ static void cap_express_slot2(struct device *d UNUSED, int where UNUSED)
/* No capabilities that require this field in PCIe rev2.0 spec. */
}
+#define OBJNAMELEN 1024
+#define OBJBUFSIZE 64
+static int
+get_rcd_sysfs_obj_file(struct pci_dev *d, char *object, char *result)
+{
+ char namebuf[OBJNAMELEN];
+ int n = snprintf(namebuf, OBJNAMELEN, "%s/devices/%04x:%02x:%02x.%d/%s",
+ pci_get_param(d->access, "sysfs.path"),
+ d->domain, d->bus, d->dev, d->func, object);
+ if (n < 0 || n >= OBJNAMELEN){
+ d->access->error("Failed to get filename");
+ return -1;
+ }
+ int fd = open(namebuf, O_RDONLY);
+ if(fd < 0)
+ return -1;
+ n = read(fd, result, OBJBUFSIZE);
+ if (n < 0 || n >= OBJBUFSIZE){
+ d->access->error("Failed to read the file");
+ return -1;
+ }
+ return 0;
+}
+
+static void cap_express_link_rcd(struct device *d){
+ u32 t, aspm, cap_speed, cap_width, sta_speed, sta_width;
+ u16 w;
+ struct pci_dev *pdev = d->dev;
+ char buf[OBJBUFSIZE];
+
+ if(get_rcd_sysfs_obj_file(pdev, "rcd_link_cap", buf))
+ return;
+ t = (u32)strtoul(buf, NULL, 16);
+
+ aspm = (t & PCI_EXP_LNKCAP_ASPM) >> 10;
+ cap_speed = t & PCI_EXP_LNKCAP_SPEED;
+ cap_width = (t & PCI_EXP_LNKCAP_WIDTH) >> 4;
+ printf("\t\tLnkCap:\tPort #%d, Speed %s, Width x%d, ASPM %s",
+ t >> 24,
+ link_speed(cap_speed), cap_width,
+ aspm_support(aspm));
+ if (aspm)
+ {
+ printf(", Exit Latency ");
+ if (aspm & 1)
+ printf("L0s %s", latency_l0s((t & PCI_EXP_LNKCAP_L0S) >> 12));
+ if (aspm & 2)
+ printf("%sL1 %s", (aspm & 1) ? ", " : "",
+ latency_l1((t & PCI_EXP_LNKCAP_L1) >> 15));
+ }
+ printf("\n");
+ printf("\t\t\tClockPM%c Surprise%c LLActRep%c BwNot%c ASPMOptComp%c\n",
+ FLAG(t, PCI_EXP_LNKCAP_CLOCKPM),
+ FLAG(t, PCI_EXP_LNKCAP_SURPRISE),
+ FLAG(t, PCI_EXP_LNKCAP_DLLA),
+ FLAG(t, PCI_EXP_LNKCAP_LBNC),
+ FLAG(t, PCI_EXP_LNKCAP_AOC));
+
+ if(!get_rcd_sysfs_obj_file(pdev, "rcd_link_ctrl", buf)){
+ w = (u16)strtoul(buf, NULL, 16);
+ printf("\t\tLnkCtl:\tASPM %s;", aspm_enabled(w & PCI_EXP_LNKCTL_ASPM));
+ printf(" Disabled%c CommClk%c\n\t\t\tExtSynch%c ClockPM%c AutWidDis%c BWInt%c AutBWInt%c\n",
+ FLAG(w, PCI_EXP_LNKCTL_DISABLE),
+ FLAG(w, PCI_EXP_LNKCTL_CLOCK),
+ FLAG(w, PCI_EXP_LNKCTL_XSYNCH),
+ FLAG(w, PCI_EXP_LNKCTL_CLOCKPM),
+ FLAG(w, PCI_EXP_LNKCTL_HWAUTWD),
+ FLAG(w, PCI_EXP_LNKCTL_BWMIE),
+ FLAG(w, PCI_EXP_LNKCTL_AUTBWIE));
+ }
+
+ if(!get_rcd_sysfs_obj_file(pdev, "rcd_link_status", buf)){
+ w = (u16)strtoul(buf, NULL, 16);
+ sta_speed = w & PCI_EXP_LNKSTA_SPEED;
+ sta_width = (w & PCI_EXP_LNKSTA_WIDTH) >> 4;
+ printf("\t\tLnkSta:\tSpeed %s%s, Width x%d%s\n",
+ link_speed(sta_speed),
+ link_compare(PCI_EXP_TYPE_ROOT_INT_EP, sta_speed, cap_speed),
+ sta_width,
+ link_compare(PCI_EXP_TYPE_ROOT_INT_EP, sta_width, cap_width));
+ printf("\t\t\tTrErr%c Train%c SlotClk%c DLActive%c BWMgmt%c ABWMgmt%c\n",
+ FLAG(w, PCI_EXP_LNKSTA_TR_ERR),
+ FLAG(w, PCI_EXP_LNKSTA_TRAIN),
+ FLAG(w, PCI_EXP_LNKSTA_SL_CLK),
+ FLAG(w, PCI_EXP_LNKSTA_DL_ACT),
+ FLAG(w, PCI_EXP_LNKSTA_BWMGMT),
+ FLAG(w, PCI_EXP_LNKSTA_AUTBW));
+ }
+ return;
+}
+
static int
cap_express(struct device *d, int where, int cap)
{
@@ -1445,6 +1538,9 @@ cap_express(struct device *d, int where, int cap)
cap_express_dev(d, where, type);
if (link)
cap_express_link(d, where, type);
+ else if (type == PCI_EXP_TYPE_ROOT_INT_EP)
+ cap_express_link_rcd(d);
+
if (slot)
cap_express_slot(d, where);
if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_ROOT_EC)
This patch adds a function to output the link status of the CXL1.1 device when it is connected. In CXL1.1, the link status of the device is included in the RCRB mapped to the memory mapped register area. The value of that register is outputted to sysfs, and based on that, displays the link status information. Signed-off-by: "Kobayashi,Daisuke" <kobayashi.da-06@fujitsu.com> --- ls-caps.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+)