]> git.ipfire.org Git - thirdparty/pciutils.git/commitdiff
pcilmr: Add PCIe Gen 6 (64 GT/s) support master
authorKurtis Bohlen <kurtis.bohlen@asteralabs.com>
Wed, 6 May 2026 23:03:28 +0000 (23:03 +0000)
committerMartin Mareš <mj@ucw.cz>
Tue, 12 May 2026 08:22:17 +0000 (10:22 +0200)
- Extend speed-indexed arrays in lmr.h to support link_speed=6
- Allow Gen 6 link speed in margin_verify_link()
- Fix NULL dereference crash in margin_fill_link() when either
  port lacks LMR capability
- Fix scan_links() and find_ready_links() to check up port has
  LMR capability before reporting link as available
- Fix GT/s display formula in margin_log_link() for Gen 6
- Update user-facing strings to include 64 GT/s

lmr/lmr.h
lmr/margin_args.c
lmr/margin_hw.c
lmr/margin_log.c
lmr/margin_results.c
pcilmr.c

index 98df17a6803ba99615fecddf4e4837e21ca3df26..d9995e0bee7aca73fd31b1dc8c305a6ebf11fb84 100644 (file)
--- a/lmr/lmr.h
+++ b/lmr/lmr.h
@@ -18,7 +18,7 @@
 enum margin_hw { MARGIN_HW_DEFAULT, MARGIN_ICE_LAKE_RC };
 
 // in ps
-static const double margin_ui[] = { 62.5, 31.25 };
+static const double margin_ui[] = { 62.5, 31.25, 31.25 };
 
 /* PCI Device wrapper for margining functions */
 struct margin_dev {
@@ -194,7 +194,7 @@ bool margin_port_is_down(struct pci_dev *dev);
 bool margin_find_pair(struct pci_access *pacc, struct pci_dev *dev, struct pci_dev **down_port,
                       struct pci_dev **up_port);
 
-/* Verify that devices form the link with 16 GT/s or 32 GT/s data rate */
+/* Verify that devices form the link with valid data rate */
 bool margin_verify_link(struct pci_dev *down_port, struct pci_dev *up_port);
 
 /* Check Margining Ready bit from Margining Port Status Register */
@@ -258,11 +258,11 @@ void margin_log_hw_quirks(struct margin_recv *recv);
 // (Transmitter Electrical Compliance)
 
 // values in ps
-static const double margin_ew_min[] = { 18.75, 9.375 };
-static const double margin_ew_rec[] = { 23.75, 10.1565 };
+static const double margin_ew_min[] = { 18.75, 9.375, 9.375 };
+static const double margin_ew_rec[] = { 23.75, 10.1565, 10.1565 };
 
-static const double margin_eh_min[] = { 15, 15 };
-static const double margin_eh_rec[] = { 21, 19.75 };
+static const double margin_eh_min[] = { 15, 15, 5 };
+static const double margin_eh_rec[] = { 21, 19.75, 7 };
 
 void margin_results_print_brief(struct margin_results *results, u8 recvs_n,
                                 struct margin_link_args *args);
index 57a1d0aa96db731fec5a2dbccc76b29840348439..a1adbf05c49989cb74f43634d4228f5b0addcc54 100644 (file)
@@ -86,6 +86,7 @@ find_ready_links(struct pci_access *pacc, struct margin_link *links, bool cnt_on
           margin_find_pair(pacc, p, &down, &up);
 
           if (down && margin_verify_link(down, up)
+              && pci_find_cap(up, PCI_EXT_CAP_ID_LMR, PCI_CAP_EXTENDED)
               && (margin_check_ready_bit(down) || margin_check_ready_bit(up)))
             {
               if (!cnt_only)
@@ -284,7 +285,7 @@ margin_parse_util_args(struct pci_access *pacc, int argc, char **argv, enum marg
             {
               margin_gen_bdfs(down, up, err, sizeof(err));
               die("Link %s is not ready for margining.\n"
-                  "Link data rate must be 16 GT/s or 32 GT/s.\n"
+                  "Link data rate must be 16 GT/s, 32 GT/s, or 64 GT/s.\n"
                   "Downstream Component must be at D0 PM state.\n",
                   err);
             }
index c6785f16c5f2c7c9eece7951c54cf7e9e8b2941a..47102a34085c2cd2397c446499770afc90c1012a 100644 (file)
@@ -87,7 +87,7 @@ margin_verify_link(struct pci_dev *down_port, struct pci_dev *up_port)
     return false;
   if ((pci_read_word(down_port, cap->addr + PCI_EXP_LNKSTA) & PCI_EXP_LNKSTA_SPEED) < 4)
     return false;
-  if ((pci_read_word(down_port, cap->addr + PCI_EXP_LNKSTA) & PCI_EXP_LNKSTA_SPEED) > 5)
+  if ((pci_read_word(down_port, cap->addr + PCI_EXP_LNKSTA) & PCI_EXP_LNKSTA_SPEED) > 6)
     return false;
 
   u8 down_sec = pci_read_byte(down_port, PCI_SECONDARY_BUS);
@@ -133,6 +133,10 @@ margin_fill_link(struct pci_dev *down_port, struct pci_dev *up_port, struct marg
   memset(wrappers, 0, sizeof(*wrappers));
   if (!margin_verify_link(down_port, up_port))
     return false;
+  if (!pci_find_cap(down_port, PCI_EXT_CAP_ID_LMR, PCI_CAP_EXTENDED))
+    return false;
+  if (!pci_find_cap(up_port, PCI_EXT_CAP_ID_LMR, PCI_CAP_EXTENDED))
+    return false;
   wrappers->down_port = fill_dev_wrapper(down_port);
   wrappers->up_port = fill_dev_wrapper(up_port);
   return true;
index 2cb01c8179ce8da3daa54e828f8a27f006f0a960..ce8381bd194f18427ff69636edff8346998fddda 100644 (file)
@@ -54,7 +54,7 @@ margin_log_link(struct margin_link *link)
   margin_log("Link ");
   margin_log_bdfs(link->down_port.dev, link->up_port.dev);
   margin_log("\nNegotiated Link Width: %d\n", link->down_port.neg_width);
-  margin_log("Link Speed: %d.0 GT/s = Gen %d\n", (link->down_port.link_speed - 3) * 16,
+  margin_log("Link Speed: %d.0 GT/s = Gen %d\n", 16 << (link->down_port.link_speed - 4),
              link->down_port.link_speed);
   margin_log("Available receivers: ");
   int receivers_n = 2 + 2 * link->down_port.retimers_n;
index b0c5c26615dae8745a306c0191fe2785054f68ea..95431006b58a5afa862d4d4e562fb4220e68db98 100644 (file)
@@ -64,7 +64,7 @@ margin_results_print_brief(struct margin_results *results, u8 recvs_n,
   char *no_test_msgs[] = { "",
                            "Margining Ready bit is Clear",
                            "Error during caps reading",
-                           "Margining prerequisites are not satisfied (16/32 GT/s, D0)",
+                           "Margining prerequisites are not satisfied (supported rate, D0)",
                            "Invalid lanes specified with arguments",
                            "Invalid receivers specified with arguments",
                            "Couldn't disable ASPM" };
index accee447ed05f9104a32720c695689129d2c819e..b9844c70bd5f177e2c13260c2163c59968e8071e 100644 (file)
--- a/pcilmr.c
+++ b/pcilmr.c
@@ -32,7 +32,7 @@ scan_links(struct pci_access *pacc, bool only_ready)
           struct pci_dev *up = NULL;
           margin_find_pair(pacc, p, &down, &up);
 
-          if (down && margin_verify_link(down, up))
+          if (down && margin_verify_link(down, up) && pci_find_cap(up, PCI_EXT_CAP_ID_LMR, PCI_CAP_EXTENDED))
             {
               margin_log_bdfs(down, up);
               if (!only_ready && (margin_check_ready_bit(down) || margin_check_ready_bit(up)))