common/sfc_efx/base: add Xilinx capabilities table lookup
authorIgor Romanov <igor.romanov@oktetlabs.ru>
Thu, 24 Sep 2020 12:12:21 +0000 (13:12 +0100)
committerFerruh Yigit <ferruh.yigit@intel.com>
Wed, 30 Sep 2020 17:19:13 +0000 (19:19 +0200)
APIs for searching a capability in a Xilinx capabilities table and
reading table entries are needed for function control window lookup
to get the bar index and offset of the window.

Signed-off-by: Igor Romanov <igor.romanov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
drivers/common/sfc_efx/base/efx_impl.h
drivers/common/sfc_efx/base/efx_pci.c
drivers/common/sfc_efx/base/rhead_impl.h
drivers/common/sfc_efx/base/rhead_nic.c
drivers/common/sfc_efx/base/rhead_pci.c

index 422f97c..dfe5f1f 100644 (file)
@@ -1617,6 +1617,21 @@ efx_pci_read_ext_cap_xilinx_table(
        __out                           unsigned int *barp,
        __out                           efsys_dma_addr_t *offsetp);
 
+/*
+ * Find a capability with specified format_id in a Xilinx capabilities table.
+ * Searching is started from provided offset, taking skip_first into account.
+ * If search succeeds, found capability is in modified offset.
+ *
+ * Returns ENOENT if an entry with specified format id is not found.
+ */
+LIBEFX_INTERNAL
+extern __checkReturn                   efx_rc_t
+efx_pci_xilinx_cap_tbl_find(
+       __in                            efsys_bar_t *esbp,
+       __in                            uint32_t format_id,
+       __in                            boolean_t skip_first,
+       __inout                         efsys_dma_addr_t *entry_offsetp);
+
 #endif /* EFSYS_OPT_PCI */
 
 #ifdef __cplusplus
index 8707220..bdf995c 100644 (file)
@@ -299,4 +299,65 @@ fail1:
        return (rc);
 }
 
+       __checkReturn                   efx_rc_t
+efx_pci_xilinx_cap_tbl_find(
+       __in                            efsys_bar_t *esbp,
+       __in                            uint32_t format_id,
+       __in                            boolean_t skip_first,
+       __inout                         efsys_dma_addr_t *entry_offsetp)
+{
+       efsys_dma_addr_t offset = *entry_offsetp;
+       boolean_t skip = skip_first;
+       efx_qword_t header;
+       uint32_t format;
+       uint32_t last;
+       efx_rc_t rc;
+
+       if (entry_offsetp == NULL) {
+               rc = EINVAL;
+               goto fail1;
+       }
+
+       rc = ENOENT;
+       /*
+        * SF-119689-TC Riverhead Host Interface section 4.2.2.
+        * describes the following discovery steps.
+        */
+       do {
+               /*
+                * Xilinx Capabilities Table requires 32bit aligned reads.
+                * See SF-119689-TC section 4.2.2 "Discovery Steps".
+                */
+               EFSYS_BAR_READD(esbp, offset +
+                               (EFX_LOW_BIT(ESF_GZ_CFGBAR_ENTRY_FORMAT) / 8),
+                               &header.eq_dword[0], B_FALSE);
+               EFSYS_BAR_READD(esbp, offset +
+                               (EFX_LOW_BIT(ESF_GZ_CFGBAR_ENTRY_SIZE) / 8),
+                               &header.eq_dword[1], B_FALSE);
+
+               format = EFX_QWORD_FIELD32(header, ESF_GZ_CFGBAR_ENTRY_FORMAT);
+               last = EFX_QWORD_FIELD32(header, ESF_GZ_CFGBAR_ENTRY_LAST);
+
+               if (skip == B_FALSE && format == format_id) {
+                       *entry_offsetp = offset;
+                       rc = 0;
+                       break;
+               }
+
+               offset += EFX_QWORD_FIELD32(header, ESF_GZ_CFGBAR_ENTRY_SIZE);
+               skip = B_FALSE;
+       } while (last == B_FALSE);
+
+       /*
+        * Returns 0 if found otherwise ENOENT indicating that
+        * search finished correctly.
+        */
+       return (rc);
+
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       return (rc);
+}
+
 #endif /* EFSYS_OPT_PCI */
index c62cf8c..91347c3 100644 (file)
@@ -451,6 +451,13 @@ rhead_pci_nic_membar_lookup(
 
 #endif /* EFSYS_OPT_PCI */
 
+LIBEFX_INTERNAL
+extern __checkReturn                   efx_rc_t
+rhead_nic_xilinx_cap_tbl_read_ef100_locator(
+       __in                            efsys_bar_t *esbp,
+       __in                            efsys_dma_addr_t offset,
+       __out                           efx_bar_region_t *ebrp);
+
 #ifdef __cplusplus
 }
 #endif
index a773a43..787afb3 100644 (file)
@@ -518,4 +518,54 @@ fail1:
 
 #endif /* EFSYS_OPT_DIAG */
 
+       __checkReturn                   efx_rc_t
+rhead_nic_xilinx_cap_tbl_read_ef100_locator(
+       __in                            efsys_bar_t *esbp,
+       __in                            efsys_dma_addr_t offset,
+       __out                           efx_bar_region_t *ebrp)
+{
+       efx_oword_t entry;
+       uint32_t rev;
+       uint32_t len;
+       efx_rc_t rc;
+
+       /*
+        * Xilinx Capabilities Table requires 32bit aligned reads.
+        * See SF-119689-TC section 4.2.2 "Discovery Steps".
+        */
+       EFSYS_BAR_READD(esbp, offset +
+                       (EFX_LOW_BIT(ESF_GZ_CFGBAR_ENTRY_FORMAT) / 8),
+                       &entry.eo_dword[0], B_FALSE);
+       EFSYS_BAR_READD(esbp, offset +
+                       (EFX_LOW_BIT(ESF_GZ_CFGBAR_ENTRY_SIZE) / 8),
+                       &entry.eo_dword[1], B_FALSE);
+
+       rev = EFX_OWORD_FIELD32(entry, ESF_GZ_CFGBAR_ENTRY_REV);
+       len = EFX_OWORD_FIELD32(entry, ESF_GZ_CFGBAR_ENTRY_SIZE);
+
+       if (rev != ESE_GZ_CFGBAR_ENTRY_REV_EF100 ||
+           len < ESE_GZ_CFGBAR_ENTRY_SIZE_EF100) {
+               rc = EINVAL;
+               goto fail1;
+       }
+
+       EFSYS_BAR_READD(esbp, offset +
+                       (EFX_LOW_BIT(ESF_GZ_CFGBAR_EF100_BAR) / 8),
+                       &entry.eo_dword[2], B_FALSE);
+
+       ebrp->ebr_index = EFX_OWORD_FIELD32(entry, ESF_GZ_CFGBAR_EF100_BAR);
+       ebrp->ebr_offset = EFX_OWORD_FIELD32(entry,
+                       ESF_GZ_CFGBAR_EF100_FUNC_CTL_WIN_OFF) <<
+                       ESE_GZ_EF100_FUNC_CTL_WIN_OFF_SHIFT;
+       ebrp->ebr_type = EFX_BAR_TYPE_MEM;
+       ebrp->ebr_length = 0;
+
+       return (0);
+
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       return (rc);
+}
+
 #endif /* EFSYS_OPT_RIVERHEAD */
index 47e89cf..0a6e72f 100644 (file)
@@ -9,6 +9,41 @@
 
 #if EFSYS_OPT_RIVERHEAD && EFSYS_OPT_PCI
 
+/*
+ * Search for a EF100 resource locator from the given offset of an entry
+ * in a Xilinx capabilities table.
+ */
+static __checkReturn                   efx_rc_t
+rhead_xilinx_cap_tbl_find_ef100_locator(
+       __in                            efsys_bar_t *esbp,
+       __in                            efsys_dma_addr_t tbl_offset,
+       __out                           efx_bar_region_t *ef100_ebrp)
+{
+       efx_rc_t rc;
+       efsys_dma_addr_t entry_offset = tbl_offset;
+
+       rc = efx_pci_xilinx_cap_tbl_find(esbp, ESE_GZ_CFGBAR_ENTRY_EF100,
+                                          B_FALSE, &entry_offset);
+       if (rc != 0) {
+               /* EF100 locator not found (ENOENT) or other error */
+               goto fail1;
+       }
+
+       rc = rhead_nic_xilinx_cap_tbl_read_ef100_locator(esbp, entry_offset,
+                                                        ef100_ebrp);
+       if (rc != 0)
+               goto fail2;
+
+       return (0);
+
+fail2:
+       EFSYS_PROBE(fail2);
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       return (rc);
+}
+
        __checkReturn                   efx_rc_t
 rhead_pci_nic_membar_lookup(
        __in                            efsys_pci_config_t *espcp,
@@ -55,13 +90,27 @@ rhead_pci_nic_membar_lookup(
                EFSYS_PCI_FIND_MEM_BAR(espcp, xilinx_tbl_bar, &xil_eb, &rc);
                if (rc != 0)
                        goto fail2;
+
+               rc = rhead_xilinx_cap_tbl_find_ef100_locator(&xil_eb,
+                                                            xilinx_tbl_offset,
+                                                            ebrp);
+               if (rc == 0) {
+                       /* Found valid EF100 locator. */
+                       bar_found = B_TRUE;
+                       break;
+               } else if (rc != ENOENT) {
+                       /* Table access failed, so terminate search. */
+                       goto fail3;
+               }
        }
 
        if (bar_found == B_FALSE)
-               goto fail3;
+               goto fail4;
 
        return (0);
 
+fail4:
+       EFSYS_PROBE(fail4);
 fail3:
        EFSYS_PROBE(fail3);
 fail2: