EFX_FAMILY_NTYPES
} efx_family_t;
+typedef enum efx_bar_type_e {
+ EFX_BAR_TYPE_MEM,
+ EFX_BAR_TYPE_IO
+} efx_bar_type_t;
+
+typedef struct efx_bar_region_s {
+ efx_bar_type_t ebr_type;
+ int ebr_index;
+ efsys_dma_addr_t ebr_offset;
+ efsys_dma_addr_t ebr_length;
+} efx_bar_region_t;
+
+/* The function is deprecated. It is used only if Riverhead is not supported. */
LIBEFX_API
extern __checkReturn efx_rc_t
efx_family(
__out efx_family_t *efp,
__out unsigned int *membarp);
+#if EFSYS_OPT_PCI
+
+/* Determine EFX family and perform lookup of the function control window
+ *
+ * The function requires PCI config handle from which all memory bars can
+ * be accessed.
+ * A user of the API must be aware of memory bars indexes (not available
+ * on Windows).
+ */
+LIBEFX_API
+extern __checkReturn efx_rc_t
+efx_family_probe_bar(
+ __in uint16_t venid,
+ __in uint16_t devid,
+ __in efsys_pci_config_t *espcp,
+ __out efx_family_t *efp,
+ __out efx_bar_region_t *ebrp);
+
+#endif /* EFSYS_OPT_PCI */
+
#define EFX_PCI_VENID_SFC 0x1924
#define EFX_PCI_VENID_XILINX 0x10EE
# endif
#endif /* EFSYS_OPT_EVB */
+#if EFSYS_OPT_PCI
+# if !EFSYS_OPT_RIVERHEAD
+# error "PCI requires RIVERHEAD"
+# endif
+#endif /* EFSYS_OPT_PCI */
+
#endif /* _SYS_EFX_CHECK_H */
#endif /* EFSYS_OPT_MAC_STATS */
+#if EFSYS_OPT_PCI
+
+/*
+ * Find the next extended capability in a PCI device's config space
+ * with specified capability id.
+ * Passing 0 offset makes the function search from the start.
+ * If search succeeds, found capability is in modified offset.
+ *
+ * Returns ENOENT if a capability is not found.
+ */
+LIBEFX_INTERNAL
+extern __checkReturn efx_rc_t
+efx_pci_config_find_next_ext_cap(
+ __in efsys_pci_config_t *espcp,
+ __in uint16_t cap_id,
+ __inout size_t *offsetp);
+
+/*
+ * Get the next extended capability in a PCI device's config space.
+ * Passing 0 offset makes the function get the first capability.
+ * If search succeeds, the capability is in modified offset.
+ *
+ * Returns ENOENT if there is no next capability.
+ */
+LIBEFX_INTERNAL
+extern __checkReturn efx_rc_t
+efx_pci_config_next_ext_cap(
+ __in efsys_pci_config_t *espcp,
+ __inout size_t *offsetp);
+
+/*
+ * Find the next Xilinx capabilities table location by searching
+ * PCI extended capabilities.
+ *
+ * Returns ENOENT if a table location is not found.
+ */
+LIBEFX_INTERNAL
+extern __checkReturn efx_rc_t
+efx_pci_find_next_xilinx_cap_table(
+ __in efsys_pci_config_t *espcp,
+ __inout size_t *pci_cap_offsetp,
+ __out unsigned int *xilinx_tbl_barp,
+ __out efsys_dma_addr_t *xilinx_tbl_offsetp);
+
+/*
+ * Read a Xilinx extended PCI capability that gives the location
+ * of a Xilinx capabilities table.
+ *
+ * Returns ENOENT if the extended PCI capability does not contain
+ * Xilinx capabilities table locator.
+ */
+LIBEFX_INTERNAL
+extern __checkReturn efx_rc_t
+efx_pci_read_ext_cap_xilinx_table(
+ __in efsys_pci_config_t *espcp,
+ __in size_t cap_offset,
+ __out unsigned int *barp,
+ __out efsys_dma_addr_t *offsetp);
+
+#endif /* EFSYS_OPT_PCI */
+
#ifdef __cplusplus
}
#endif
return (ENOTSUP);
}
+#if EFSYS_OPT_PCI
+
+ __checkReturn efx_rc_t
+efx_family_probe_bar(
+ __in uint16_t venid,
+ __in uint16_t devid,
+ __in efsys_pci_config_t *espcp,
+ __out efx_family_t *efp,
+ __out efx_bar_region_t *ebrp)
+{
+ efx_rc_t rc;
+ unsigned int membar;
+
+ if (venid == EFX_PCI_VENID_XILINX) {
+ switch (devid) {
+#if EFSYS_OPT_RIVERHEAD
+ case EFX_PCI_DEVID_RIVERHEAD:
+ case EFX_PCI_DEVID_RIVERHEAD_VF:
+ rc = rhead_pci_nic_membar_lookup(espcp, ebrp);
+ if (rc == 0)
+ *efp = EFX_FAMILY_RIVERHEAD;
+
+ return (rc);
+#endif /* EFSYS_OPT_RIVERHEAD */
+ default:
+ break;
+ }
+ }
+
+ rc = efx_family(venid, devid, efp, &membar);
+ if (rc == 0) {
+ ebrp->ebr_type = EFX_BAR_TYPE_MEM;
+ ebrp->ebr_index = membar;
+ ebrp->ebr_offset = 0;
+ ebrp->ebr_length = 0;
+ }
+
+ return (rc);
+}
+
+#endif /* EFSYS_OPT_PCI */
#if EFSYS_OPT_SIENA
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright(c) 2019-2020 Xilinx, Inc.
+ * Copyright(c) 2019 Solarflare Communications Inc.
+ */
+
+#include "efx.h"
+#include "efx_impl.h"
+
+#if EFSYS_OPT_PCI
+
+ __checkReturn efx_rc_t
+efx_pci_config_next_ext_cap(
+ __in efsys_pci_config_t *espcp,
+ __inout size_t *offsetp)
+{
+ efx_dword_t hdr;
+ efx_rc_t rc = 0;
+ size_t next;
+
+ if (offsetp == NULL) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ if (*offsetp == 0) {
+ *offsetp = ESE_GZ_PCI_BASE_CONFIG_SPACE_SIZE;
+ } else {
+ EFSYS_PCI_CONFIG_READD(espcp, *offsetp +
+ (EFX_LOW_BIT(ESF_GZ_PCI_EXPRESS_XCAP_ID) / 8),
+ &hdr, &rc);
+ if (rc != 0) {
+ rc = EIO;
+ goto fail2;
+ }
+
+ next = EFX_DWORD_FIELD(hdr, ESF_GZ_PCI_EXPRESS_XCAP_NEXT);
+ if (next < ESE_GZ_PCI_BASE_CONFIG_SPACE_SIZE)
+ rc = ENOENT;
+ else
+ *offsetp = next;
+ }
+
+ /*
+ * Returns 0 if the next capability is present otherwise ENOENT
+ * indicating that the function finished correctly.
+ */
+ return (rc);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_pci_config_find_next_ext_cap(
+ __in efsys_pci_config_t *espcp,
+ __in uint16_t cap_id,
+ __inout size_t *offsetp)
+{
+ efx_dword_t hdr;
+ size_t position;
+ efx_rc_t rc;
+
+ if (offsetp == NULL) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ position = *offsetp;
+
+ while (1) {
+ rc = efx_pci_config_next_ext_cap(espcp, &position);
+ if (rc != 0) {
+ if (rc == ENOENT)
+ break;
+ else
+ goto fail2;
+ }
+
+ EFSYS_PCI_CONFIG_READD(espcp, position +
+ (EFX_LOW_BIT(ESF_GZ_PCI_EXPRESS_XCAP_ID) / 8),
+ &hdr, &rc);
+ if (rc != 0) {
+ rc = EIO;
+ goto fail3;
+ }
+
+ if (EFX_DWORD_FIELD(hdr, ESF_GZ_PCI_EXPRESS_XCAP_ID) ==
+ cap_id) {
+ *offsetp = position;
+ rc = 0;
+ break;
+ }
+ }
+
+ /*
+ * Returns 0 if found otherwise ENOENT indicating that search finished
+ * correctly.
+ */
+ return (rc);
+
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_pci_find_next_xilinx_cap_table(
+ __in efsys_pci_config_t *espcp,
+ __inout size_t *pci_cap_offsetp,
+ __out unsigned int *xilinx_tbl_barp,
+ __out efsys_dma_addr_t *xilinx_tbl_offsetp)
+{
+ size_t cap_offset;
+ efx_rc_t rc;
+
+ if (pci_cap_offsetp == NULL) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ cap_offset = *pci_cap_offsetp;
+
+ while (1) {
+ unsigned int tbl_bar;
+ efsys_dma_addr_t tbl_offset;
+
+ rc = efx_pci_config_find_next_ext_cap(espcp,
+ ESE_GZ_PCI_EXPRESS_XCAP_ID_VNDR, &cap_offset);
+ if (rc != 0) {
+ if (rc == ENOENT)
+ break;
+ else
+ goto fail2;
+ }
+
+ /*
+ * The found extended PCI capability is a vendor-specific
+ * capability, but not necessarily a Xilinx capabilities table
+ * locator. Try to read it and skip it if the capability is
+ * not the locator.
+ */
+ rc = efx_pci_read_ext_cap_xilinx_table(espcp, cap_offset,
+ &tbl_bar, &tbl_offset);
+ if (rc == 0) {
+ *xilinx_tbl_barp = tbl_bar;
+ *xilinx_tbl_offsetp = tbl_offset;
+ *pci_cap_offsetp = cap_offset;
+ break;
+ } else {
+ if (rc == ENOENT)
+ continue;
+ else
+ goto fail3;
+ }
+ }
+
+ /*
+ * Returns 0 if found otherwise ENOENT indicating that search finished
+ * correctly.
+ */
+ return (rc);
+
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_pci_read_ext_cap_xilinx_table(
+ __in efsys_pci_config_t *espcp,
+ __in size_t cap_offset,
+ __out unsigned int *barp,
+ __out efsys_dma_addr_t *offsetp)
+{
+ size_t vsec_offset = cap_offset + ESE_GZ_PCI_EXPRESS_XCAP_HDR_SIZE;
+ efx_dword_t cap_hdr;
+ efx_oword_t vsec;
+ uint32_t vsec_len;
+ uint32_t vsec_id;
+ uint32_t vsec_rev;
+ uint32_t offset_low;
+ uint32_t offset_high = 0;
+ unsigned int bar;
+ efsys_dma_addr_t offset;
+ efx_rc_t rc;
+
+ EFSYS_PCI_CONFIG_READD(espcp, cap_offset +
+ (EFX_LOW_BIT(ESF_GZ_PCI_EXPRESS_XCAP_ID) / 8),
+ &cap_hdr, &rc);
+ if (rc != 0) {
+ rc = EIO;
+ goto fail1;
+ }
+
+ if (EFX_DWORD_FIELD(cap_hdr, ESF_GZ_PCI_EXPRESS_XCAP_VER) !=
+ ESE_GZ_PCI_EXPRESS_XCAP_VER_VSEC) {
+ rc = EINVAL;
+ goto fail2;
+ }
+
+ EFSYS_PCI_CONFIG_READD(espcp, vsec_offset +
+ (EFX_LOW_BIT(ESF_GZ_VSEC_ID) / 8),
+ &vsec.eo_dword[0], &rc);
+ if (rc != 0) {
+ rc = EIO;
+ goto fail3;
+ }
+
+ vsec_len = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_LEN);
+ vsec_id = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_ID);
+ vsec_rev = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_VER);
+
+ /*
+ * Condition of the vendor-specific extended PCI capability not being
+ * a Xilinx capabilities table locator.
+ */
+ if (vsec_id != ESE_GZ_XILINX_VSEC_ID) {
+ rc = ENOENT;
+ goto fail4;
+ }
+
+ if (vsec_rev != ESE_GZ_VSEC_VER_XIL_CFGBAR ||
+ vsec_len < ESE_GZ_VSEC_LEN_MIN) {
+ rc = EINVAL;
+ goto fail5;
+ }
+
+ EFSYS_PCI_CONFIG_READD(espcp, vsec_offset +
+ (EFX_LOW_BIT(ESF_GZ_VSEC_TBL_BAR) / 8),
+ &vsec.eo_dword[1], &rc);
+ if (rc != 0) {
+ rc = EIO;
+ goto fail6;
+ }
+
+ bar = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_TBL_BAR);
+ offset_low = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_TBL_OFF_LO);
+
+ if (vsec_len >= ESE_GZ_VSEC_LEN_HIGH_OFFT) {
+ EFSYS_PCI_CONFIG_READD(espcp, vsec_offset +
+ (EFX_LOW_BIT(ESF_GZ_VSEC_TBL_OFF_HI) / 8),
+ &vsec.eo_dword[2], &rc);
+ if (rc != 0) {
+ rc = EIO;
+ goto fail7;
+ }
+
+ offset_high = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_TBL_OFF_HI);
+ }
+
+ /* High bits of low offset are discarded by the shift */
+ offset = offset_low << ESE_GZ_VSEC_TBL_OFF_LO_BYTES_SHIFT;
+
+ /*
+ * Avoid the 'left shift count >= width of type' warning on systems
+ * without uint64_t support.
+ */
+#if EFSYS_HAS_UINT64
+ offset |= (uint64_t)offset_high << ESE_GZ_VSEC_TBL_OFF_HI_BYTES_SHIFT;
+#else
+ _NOTE(ARGUNUSED(offset_high))
+#endif
+
+ *offsetp = offset;
+ *barp = bar;
+
+ return (0);
+
+fail7:
+ EFSYS_PROBE(fail7);
+fail6:
+ EFSYS_PROBE(fail6);
+fail5:
+ EFSYS_PROBE(fail5);
+fail4:
+ EFSYS_PROBE(fail4);
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+#endif /* EFSYS_OPT_PCI */
'efx_mon.c',
'efx_nic.c',
'efx_nvram.c',
+ 'efx_pci.c',
'efx_phy.c',
'efx_port.c',
'efx_proxy.c',
'rhead_ev.c',
'rhead_intr.c',
'rhead_nic.c',
+ 'rhead_pci.c',
'rhead_rx.c',
'rhead_tx.c',
]
#endif /* EFSYS_OPT_QSTATS */
+#if EFSYS_OPT_PCI
+
+/*
+ * Perform discovery of function control window by looking for a
+ * EF100 locator in Xilinx capabilities tables.
+ */
+LIBEFX_INTERNAL
+extern __checkReturn efx_rc_t
+rhead_pci_nic_membar_lookup(
+ __in efsys_pci_config_t *espcp,
+ __out efx_bar_region_t *ebrp);
+
+#endif /* EFSYS_OPT_PCI */
#ifdef __cplusplus
}
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright(c) 2019-2020 Xilinx, Inc.
+ * Copyright(c) 2019 Solarflare Communications Inc.
+ */
+
+#include "efx.h"
+#include "efx_impl.h"
+
+#if EFSYS_OPT_RIVERHEAD && EFSYS_OPT_PCI
+
+ __checkReturn efx_rc_t
+rhead_pci_nic_membar_lookup(
+ __in efsys_pci_config_t *espcp,
+ __out efx_bar_region_t *ebrp)
+{
+ boolean_t xilinx_tbl_found = B_FALSE;
+ unsigned int xilinx_tbl_bar;
+ efsys_dma_addr_t xilinx_tbl_offset;
+ size_t pci_capa_offset = 0;
+ boolean_t bar_found = B_FALSE;
+ efx_rc_t rc = ENOENT;
+
+ /*
+ * SF-119689-TC Riverhead Host Interface section 4.2.2. describes
+ * the following discovery steps.
+ */
+ while (1) {
+ rc = efx_pci_find_next_xilinx_cap_table(espcp, &pci_capa_offset,
+ &xilinx_tbl_bar,
+ &xilinx_tbl_offset);
+ if (rc != 0) {
+ /*
+ * SF-119689-TC Riverhead Host Interface section 4.2.2.
+ * defines the following fallbacks for the memory bar
+ * and the offset when no Xilinx capabilities table is
+ * found.
+ */
+ if (rc == ENOENT && xilinx_tbl_found == B_FALSE) {
+ ebrp->ebr_type = EFX_BAR_TYPE_MEM;
+ ebrp->ebr_index = EFX_MEM_BAR_RIVERHEAD;
+ ebrp->ebr_offset = 0;
+ ebrp->ebr_length = 0;
+ bar_found = B_TRUE;
+ break;
+ } else {
+ goto fail1;
+ }
+
+ }
+
+ xilinx_tbl_found = B_TRUE;
+ }
+
+ if (bar_found == B_FALSE)
+ goto fail2;
+
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+#endif /* EFSYS_OPT_RIVERHEAD && EFSYS_OPT_PCI */
#define EFSYS_OPT_MCDI_PROXY_AUTH_SERVER 0
+#define EFSYS_OPT_PCI 0
+
/* ID */
typedef struct __efsys_identifier_s efsys_identifier_t;
efx_evq_size;
efx_family;
+ efx_family_probe_bar;
efx_filter_fini;
efx_filter_init;