From ba9568b8b4b7b9119765be3acc28be27f038209e Mon Sep 17 00:00:00 2001 From: Igor Romanov Date: Thu, 24 Sep 2020 13:12:21 +0100 Subject: [PATCH] common/sfc_efx/base: add Xilinx capabilities table lookup 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 Signed-off-by: Andrew Rybchenko Reviewed-by: Andy Moreton --- drivers/common/sfc_efx/base/efx_impl.h | 15 ++++++ drivers/common/sfc_efx/base/efx_pci.c | 61 ++++++++++++++++++++++++ drivers/common/sfc_efx/base/rhead_impl.h | 7 +++ drivers/common/sfc_efx/base/rhead_nic.c | 50 +++++++++++++++++++ drivers/common/sfc_efx/base/rhead_pci.c | 51 +++++++++++++++++++- 5 files changed, 183 insertions(+), 1 deletion(-) diff --git a/drivers/common/sfc_efx/base/efx_impl.h b/drivers/common/sfc_efx/base/efx_impl.h index 422f97c5ca..dfe5f1fecf 100644 --- a/drivers/common/sfc_efx/base/efx_impl.h +++ b/drivers/common/sfc_efx/base/efx_impl.h @@ -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 diff --git a/drivers/common/sfc_efx/base/efx_pci.c b/drivers/common/sfc_efx/base/efx_pci.c index 8707220849..bdf995cf84 100644 --- a/drivers/common/sfc_efx/base/efx_pci.c +++ b/drivers/common/sfc_efx/base/efx_pci.c @@ -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 */ diff --git a/drivers/common/sfc_efx/base/rhead_impl.h b/drivers/common/sfc_efx/base/rhead_impl.h index c62cf8c2c6..91347c335a 100644 --- a/drivers/common/sfc_efx/base/rhead_impl.h +++ b/drivers/common/sfc_efx/base/rhead_impl.h @@ -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 diff --git a/drivers/common/sfc_efx/base/rhead_nic.c b/drivers/common/sfc_efx/base/rhead_nic.c index a773a43bcc..787afb37a3 100644 --- a/drivers/common/sfc_efx/base/rhead_nic.c +++ b/drivers/common/sfc_efx/base/rhead_nic.c @@ -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 */ diff --git a/drivers/common/sfc_efx/base/rhead_pci.c b/drivers/common/sfc_efx/base/rhead_pci.c index 47e89cf8a2..0a6e72f076 100644 --- a/drivers/common/sfc_efx/base/rhead_pci.c +++ b/drivers/common/sfc_efx/base/rhead_pci.c @@ -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: -- 2.20.1