diff mbox series

[07/15] pciutils-pcilmr: Add all-in-one device margining parameters reading function

Message ID 20231208091734.12225-8-n.proshkin@yadro.com (mailing list archive)
State Superseded
Headers show
Series pciutils: Add utility for Lane Margining | expand

Commit Message

Nikita Proshkin Dec. 8, 2023, 9:17 a.m. UTC
Implement a function that performs all necessary actions to obtain device
margining parameters for subsequent processing without running the actual
margining test.

Reviewed-by: Sergei Miroshnichenko <s.miroshnichenko@yadro.com>
Signed-off-by: Nikita Proshkin <n.proshkin@yadro.com>
---
 lmr_lib/margin.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++
 lmr_lib/margin.h |  4 +++
 2 files changed, 89 insertions(+)
diff mbox series

Patch

diff --git a/lmr_lib/margin.c b/lmr_lib/margin.c
index 38a80bf..41c8fbf 100644
--- a/lmr_lib/margin.c
+++ b/lmr_lib/margin.c
@@ -414,3 +414,88 @@  void margin_free_results(struct margin_results *results, uint8_t results_n)
   }
   free(results);
 }
+
+bool margin_read_params_standalone(struct pci_access *pacc, struct pci_dev *dev, 
+                                    int8_t recvn, struct margin_recv *caps)
+{
+  struct pci_cap *cap = pci_find_cap(dev, PCI_CAP_ID_EXP, PCI_CAP_NORMAL);
+  uint8_t dev_dir = (pci_read_word(dev, cap->addr + PCI_EXP_FLAGS) & PCI_EXP_FLAGS_TYPE) >> 4;
+
+  bool dev_down;
+  if (dev_dir == 4 || dev_dir == 6)
+    dev_down = true;
+  else
+    dev_down = false;
+
+  if (recvn == -1)
+  {
+    if (dev_down)
+      recvn = 1;
+    else
+      recvn = 6;
+  }
+
+  if (recvn < 1 || recvn > 6)
+    return false;
+  if (dev_down && recvn == 6)
+    return false;
+  if (!dev_down && recvn != 6)
+    return false;
+
+  caps->recvn = recvn;
+
+  struct pci_dev *down = NULL;
+  struct pci_dev *up = NULL;
+  struct margin_dev down_w;
+  struct margin_dev up_w;
+
+  for (struct pci_dev *p = pacc->devices; p; p = p->next)
+  {
+    if (dev_down && pci_read_byte(dev, PCI_SECONDARY_BUS) == p->bus && dev->domain == p->domain && p->func == 0)
+    {
+      down = dev;
+      up = p;
+      break;
+    }
+    else if (!dev_down && pci_read_byte(p, PCI_SECONDARY_BUS) == dev->bus && dev->domain == p->domain)
+    {
+      down = p;
+      up = dev;
+      break;
+    }
+  }
+
+  if (!down)
+    return false;
+  if (!margin_verify_link(down, up))
+    return false;
+
+  down_w = margin_fill_wrapper(down);
+  up_w = margin_fill_wrapper(up);
+
+  caps->dev = (dev_down ? &down_w : &up_w);
+  if (!margin_check_ready_bit(caps->dev->dev))
+    return false;
+
+  if (!margin_prep_dev(&down_w))
+    return false;
+  if (!margin_prep_dev(&up_w))
+  {
+    margin_restore_dev(&down_w);
+    return false;
+  }
+
+  bool status;
+  caps->lane_reversal = false;
+  status = margin_read_params(caps);
+  if (!status)
+  {
+    caps->lane_reversal = true;
+    status = margin_read_params(caps);
+  }
+
+  margin_restore_dev(&down_w);
+  margin_restore_dev(&up_w);
+
+  return status;
+}
diff --git a/lmr_lib/margin.h b/lmr_lib/margin.h
index bb57a76..13cfa73 100644
--- a/lmr_lib/margin.h
+++ b/lmr_lib/margin.h
@@ -172,6 +172,10 @@  union margin_cmd margin_make_cmd(uint8_t payload, uint8_t type, uint8_t recvn);
 dev, recvn and lane_reversal fields must be initialized*/
 bool margin_read_params(struct margin_recv *recv);
 
+/*Fill margin_recv without calling other functions*/
+bool margin_read_params_standalone(struct pci_access *pacc, struct pci_dev* dev, 
+                                   int8_t recvn, struct margin_recv* caps);
+
 bool margin_report_cmd(struct margin_dev *dev, uint8_t lane, 
                        union margin_cmd cmd, union margin_payload *result);