diff mbox series

[RFC,v2,3/3] lspci: Add function to display cxl1.1 device link status

Message ID 20240227083313.87699-4-kobayashi.da-06@fujitsu.com
State Superseded
Headers show
Series Display cxl1.1 device link status | expand

Commit Message

Daisuke Kobayashi (Fujitsu) Feb. 27, 2024, 8:33 a.m. UTC
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(+)

Comments

Martin Mareš Feb. 28, 2024, 8:34 a.m. UTC | #1
Hello!

> 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.

I like using sysfs to access the RCRB, but since it is specific to Linux,
you cannot do it in ls-caps.c (everything in this file is platform-independent).

The right way is to extend libpci and its interface to platform-specific
back-ends to provide this functionality. However, I am not sure that we should
add special functions just for this purpose. I will think of something more
general and let you know soon.

Otherwise, please follow the coding style of the rest of the file.

				Martin
Daisuke Kobayashi (Fujitsu) March 1, 2024, 7:02 a.m. UTC | #2
> -----Original Message-----
> From: Martin Mareš <mj@ucw.cz>
> Sent: Wednesday, February 28, 2024 5:35 PM
> To: Kobayashi, Daisuke/小林 大介 <kobayashi.da-06@fujitsu.com>
> Cc: Kobayashi, Daisuke/小林 大介 <kobayashi.da-06@fujitsu.com>;
> linux-cxl@vger.kernel.org; Gotou, Yasunori/五島 康文 <y-goto@fujitsu.com>;
> linux-pci@vger.kernel.org; dan.j.williams@intel.com
> Subject: Re: [RFC PATCH v2 3/3] lspci: Add function to display cxl1.1 device
> link status
> 
> Hello!
> 
> > 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.
> 
> I like using sysfs to access the RCRB, but since it is specific to Linux, you
> cannot do it in ls-caps.c (everything in this file is platform-independent).
> 
> The right way is to extend libpci and its interface to platform-specific
> back-ends to provide this functionality. However, I am not sure that we should
> add special functions just for this purpose. I will think of something more
> general and let you know soon.
> 
> Otherwise, please follow the coding style of the rest of the file.
> 
> 				Martin

Thank you for your comment.
I understand that ls-caps.c requires a platform-independent implementation.
I will look for an appropriate place to implement that.
Is there a good place to add code to read files output to sysfs?
For example, is it practical to add a function to lib/sysfs.c that reads and uses a specific sysfs file?
diff mbox series

Patch

diff --git a/ls-caps.c b/ls-caps.c
index 1b63262..5c60321 100644
--- a/ls-caps.c
+++ b/ls-caps.c
@@ -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)