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@xxxxxxxxx> Signed-off-by: Nikita Proshkin <n.proshkin@xxxxxxxxx> --- lmr_lib/margin.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ lmr_lib/margin.h | 4 +++ 2 files changed, 89 insertions(+) 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); -- 2.34.1