return (rc);
}
+static __checkReturn efx_rc_t
+efx_mcdi_get_nic_addr_caps(
+ __in efx_nic_t *enp)
+{
+ efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
+ uint32_t mapping_type;
+ efx_rc_t rc;
+
+ rc = efx_mcdi_get_nic_addr_info(enp, &mapping_type);
+ if (rc != 0) {
+ if (rc == ENOTSUP) {
+ encp->enc_dma_mapping = EFX_NIC_DMA_MAPPING_FLAT;
+ goto out;
+ }
+ goto fail1;
+ }
+
+ switch (mapping_type) {
+ case MC_CMD_GET_DESC_ADDR_INFO_OUT_MAPPING_FLAT:
+ encp->enc_dma_mapping = EFX_NIC_DMA_MAPPING_FLAT;
+ break;
+ case MC_CMD_GET_DESC_ADDR_INFO_OUT_MAPPING_REGIONED:
+ encp->enc_dma_mapping = EFX_NIC_DMA_MAPPING_REGIONED;
+ rc = efx_mcdi_get_nic_addr_regions(enp,
+ &enp->en_dma.end_u.endu_region_info);
+ if (rc != 0)
+ goto fail2;
+ break;
+ default:
+ goto fail3;
+ }
+
+out:
+ return (0);
+
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
__checkReturn efx_rc_t
efx_mcdi_nic_board_cfg(
__in efx_nic_t *enp)
encp->enc_intr_vec_base = base;
encp->enc_intr_limit = nvec;
+ rc = efx_mcdi_get_nic_addr_caps(enp);
+ if (rc != 0)
+ goto fail12;
+
return (0);
+fail12:
+ EFSYS_PROBE(fail12);
fail11:
EFSYS_PROBE(fail11);
fail10:
EFX_VI_WINDOW_SHIFT_64K = 16,
} efx_vi_window_shift_t;
+typedef enum efx_nic_dma_mapping_e {
+ EFX_NIC_DMA_MAPPING_UNKNOWN = 0,
+ EFX_NIC_DMA_MAPPING_FLAT,
+ EFX_NIC_DMA_MAPPING_REGIONED,
+
+ EFX_NIC_DMA_MAPPING_NTYPES
+} efx_nic_dma_mapping_t;
+
typedef struct efx_nic_cfg_s {
uint32_t enc_board_type;
uint32_t enc_phy_type;
uint32_t enc_filter_action_mark_max;
/* Port assigned to this PCI function */
uint32_t enc_assigned_port;
+ /* NIC DMA mapping type */
+ efx_nic_dma_mapping_t enc_dma_mapping;
} efx_nic_cfg_t;
#define EFX_PCI_VF_INVALID 0xffff
#endif /* EFSYS_OPT_VIRTIO */
+LIBEFX_API
+extern __checkReturn efx_rc_t
+efx_nic_dma_config_add(
+ __in efx_nic_t *enp,
+ __in efsys_dma_addr_t trgt_addr,
+ __in size_t len,
+ __out_opt efsys_dma_addr_t *nic_basep,
+ __out_opt efsys_dma_addr_t *trgt_basep,
+ __out_opt size_t *map_lenp);
+
+LIBEFX_API
+extern __checkReturn efx_rc_t
+efx_nic_dma_reconfigure(
+ __in efx_nic_t *enp);
+
+typedef enum efx_nic_dma_addr_type_e {
+ EFX_NIC_DMA_ADDR_MCDI_BUF,
+ EFX_NIC_DMA_ADDR_MAC_STATS_BUF,
+ EFX_NIC_DMA_ADDR_EVENT_RING,
+ EFX_NIC_DMA_ADDR_RX_RING,
+ EFX_NIC_DMA_ADDR_TX_RING,
+ EFX_NIC_DMA_ADDR_RX_BUF,
+ EFX_NIC_DMA_ADDR_TX_BUF,
+
+ EFX_NIC_DMA_ADDR_NTYPES
+} efx_nic_dma_addr_type_t;
+
+LIBEFX_API
+extern __checkReturn efx_rc_t
+efx_nic_dma_map(
+ __in efx_nic_t *enp,
+ __in efx_nic_dma_addr_type_t addr_type,
+ __in efsys_dma_addr_t tgt_addr,
+ __in size_t len,
+ __out efsys_dma_addr_t *nic_addrp);
+
#ifdef __cplusplus
}
#endif
#define EFX_RXQ_LIMIT_TARGET 512
#endif
+typedef struct efx_nic_dma_region_s {
+ efsys_dma_addr_t endr_nic_base;
+ efsys_dma_addr_t endr_trgt_base;
+ unsigned int endr_window_log2;
+ unsigned int endr_align_log2;
+ boolean_t endr_inuse;
+} efx_nic_dma_region_t;
+
+typedef struct efx_nic_dma_region_info_s {
+ unsigned int endri_count;
+ efx_nic_dma_region_t *endri_regions;
+} efx_nic_dma_region_info_t;
+
+typedef struct efx_nic_dma_s {
+ union {
+ /* No configuration in the case flat mapping type */
+ efx_nic_dma_region_info_t endu_region_info;
+ } end_u;
+} efx_nic_dma_t;
#if EFSYS_OPT_FILTER
const efx_rx_ops_t *en_erxop;
efx_fw_variant_t efv;
char en_drv_version[EFX_DRV_VER_MAX];
+ efx_nic_dma_t en_dma;
#if EFSYS_OPT_FILTER
efx_filter_t en_filter;
const efx_filter_ops_t *en_efop;
#endif /* EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() */
+ __checkReturn efx_rc_t
+efx_mcdi_get_nic_addr_info(
+ __in efx_nic_t *enp,
+ __out uint32_t *mapping_typep)
+{
+ EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_DESC_ADDR_INFO_IN_LEN,
+ MC_CMD_GET_DESC_ADDR_INFO_OUT_LEN);
+ efx_mcdi_req_t req;
+ efx_rc_t rc;
+
+ req.emr_cmd = MC_CMD_GET_DESC_ADDR_INFO;
+ req.emr_in_buf = payload;
+ req.emr_in_length = MC_CMD_GET_DESC_ADDR_INFO_IN_LEN;
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_GET_DESC_ADDR_INFO_OUT_LEN;
+
+ efx_mcdi_execute_quiet(enp, &req);
+
+ if (req.emr_rc != 0) {
+ rc = req.emr_rc;
+ goto fail1;
+ }
+
+ if (req.emr_out_length_used < MC_CMD_GET_DESC_ADDR_INFO_OUT_LEN) {
+ rc = EMSGSIZE;
+ goto fail2;
+ }
+
+ *mapping_typep =
+ MCDI_OUT_DWORD(req, GET_DESC_ADDR_INFO_OUT_MAPPING_TYPE);
+
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mcdi_get_nic_addr_regions(
+ __in efx_nic_t *enp,
+ __out efx_nic_dma_region_info_t *endrip)
+{
+ EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_DESC_ADDR_REGIONS_IN_LEN,
+ MC_CMD_GET_DESC_ADDR_REGIONS_OUT_LENMAX_MCDI2);
+ efx_xword_t *regions;
+ efx_mcdi_req_t req;
+ efx_rc_t rc;
+ size_t alloc_size;
+ unsigned int nregions;
+ unsigned int i;
+
+ req.emr_cmd = MC_CMD_GET_DESC_ADDR_REGIONS;
+ req.emr_in_buf = payload;
+ req.emr_in_length = MC_CMD_GET_DESC_ADDR_REGIONS_IN_LEN;
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_GET_DESC_ADDR_REGIONS_OUT_LENMAX_MCDI2;
+
+ efx_mcdi_execute_quiet(enp, &req);
+
+ if (req.emr_rc != 0) {
+ rc = req.emr_rc;
+ goto fail1;
+ }
+
+ if (req.emr_out_length_used <
+ MC_CMD_GET_DESC_ADDR_REGIONS_OUT_LENMIN) {
+ rc = EMSGSIZE;
+ goto fail2;
+ }
+
+ nregions = MC_CMD_GET_DESC_ADDR_REGIONS_OUT_REGIONS_NUM(
+ req.emr_out_length_used);
+
+ EFX_STATIC_ASSERT(sizeof (*regions) == DESC_ADDR_REGION_LEN);
+ regions = MCDI_OUT2(req, efx_xword_t,
+ GET_DESC_ADDR_REGIONS_OUT_REGIONS);
+
+ alloc_size = nregions * sizeof(endrip->endri_regions[0]);
+ if (alloc_size / sizeof (endrip->endri_regions[0]) != nregions) {
+ rc = ENOMEM;
+ goto fail3;
+ }
+
+ EFSYS_KMEM_ALLOC(enp->en_esip,
+ alloc_size,
+ endrip->endri_regions);
+ if (endrip->endri_regions == NULL) {
+ rc = ENOMEM;
+ goto fail4;
+ }
+
+ endrip->endri_count = nregions;
+ for (i = 0; i < nregions; ++i) {
+ efx_nic_dma_region_t *region_info;
+
+ region_info = &endrip->endri_regions[i];
+
+ region_info->endr_inuse = B_FALSE;
+
+ region_info->endr_nic_base =
+ MCDI_OUT_INDEXED_MEMBER_QWORD(req,
+ GET_DESC_ADDR_REGIONS_OUT_REGIONS, i,
+ DESC_ADDR_REGION_DESC_ADDR_BASE);
+
+ region_info->endr_trgt_base =
+ MCDI_OUT_INDEXED_MEMBER_QWORD(req,
+ GET_DESC_ADDR_REGIONS_OUT_REGIONS, i,
+ DESC_ADDR_REGION_TRGT_ADDR_BASE);
+
+ region_info->endr_window_log2 =
+ MCDI_OUT_INDEXED_MEMBER_DWORD(req,
+ GET_DESC_ADDR_REGIONS_OUT_REGIONS, i,
+ DESC_ADDR_REGION_WINDOW_SIZE_LOG2);
+
+ region_info->endr_align_log2 =
+ MCDI_OUT_INDEXED_MEMBER_DWORD(req,
+ GET_DESC_ADDR_REGIONS_OUT_REGIONS, i,
+ DESC_ADDR_REGION_TRGT_ADDR_ALIGN_LOG2);
+ }
+
+ return (0);
+
+fail4:
+ EFSYS_PROBE(fail4);
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mcdi_set_nic_addr_regions(
+ __in efx_nic_t *enp,
+ __in const efx_nic_dma_region_info_t *endrip)
+{
+ EFX_MCDI_DECLARE_BUF(payload,
+ MC_CMD_SET_DESC_ADDR_REGIONS_IN_LENMAX_MCDI2,
+ MC_CMD_SET_DESC_ADDR_REGIONS_OUT_LEN);
+ efx_qword_t *trgt_addr_base;
+ efx_mcdi_req_t req;
+ unsigned int i;
+ efx_rc_t rc;
+
+ if (endrip->endri_count >
+ MC_CMD_SET_DESC_ADDR_REGIONS_IN_TRGT_ADDR_BASE_MAXNUM) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ req.emr_cmd = MC_CMD_SET_DESC_ADDR_REGIONS;
+ req.emr_in_buf = payload;
+ req.emr_in_length =
+ MC_CMD_SET_DESC_ADDR_REGIONS_IN_LEN(endrip->endri_count);
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_SET_DESC_ADDR_REGIONS_OUT_LEN;
+
+ EFX_STATIC_ASSERT(sizeof (*trgt_addr_base) ==
+ MC_CMD_SET_DESC_ADDR_REGIONS_IN_TRGT_ADDR_BASE_LEN);
+ trgt_addr_base = MCDI_OUT2(req, efx_qword_t,
+ SET_DESC_ADDR_REGIONS_IN_TRGT_ADDR_BASE);
+
+ for (i = 0; i < endrip->endri_count; ++i) {
+ const efx_nic_dma_region_t *region_info;
+
+ region_info = &endrip->endri_regions[i];
+
+ if (region_info->endr_inuse != B_TRUE)
+ continue;
+
+ EFX_STATIC_ASSERT(sizeof (1U) * 8 >=
+ MC_CMD_SET_DESC_ADDR_REGIONS_IN_TRGT_ADDR_BASE_MAXNUM);
+ MCDI_IN_SET_DWORD(req,
+ SET_DESC_ADDR_REGIONS_IN_SET_REGION_MASK, 1U << i);
+
+ MCDI_IN_SET_INDEXED_QWORD(req,
+ SET_DESC_ADDR_REGIONS_IN_TRGT_ADDR_BASE, i,
+ region_info->endr_trgt_base);
+ }
+
+ efx_mcdi_execute_quiet(enp, &req);
+
+ if (req.emr_rc != 0) {
+ rc = req.emr_rc;
+ goto fail2;
+ }
+
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
#endif /* EFSYS_OPT_MCDI */
__in size_t len,
__out_bcount(len) uint8_t *data);
+LIBEFX_INTERNAL
+extern __checkReturn efx_rc_t
+efx_mcdi_get_nic_addr_info(
+ __in efx_nic_t *enp,
+ __out uint32_t *mapping_typep);
+
+struct efx_nic_dma_region_info_s;
+
+LIBEFX_INTERNAL
+extern __checkReturn efx_rc_t
+efx_mcdi_get_nic_addr_regions(
+ __in efx_nic_t *enp,
+ __out struct efx_nic_dma_region_info_s *endrip);
+
+LIBEFX_INTERNAL
+extern __checkReturn efx_rc_t
+efx_mcdi_set_nic_addr_regions(
+ __in efx_nic_t *enp,
+ __in const struct efx_nic_dma_region_info_s *endrip);
+
#define MCDI_IN(_emr, _type, _ofst) \
((_type *)((_emr).emr_in_buf + (_ofst)))
EFX_POPULATE_DWORD_1(*(MCDI_IN2(_emr, efx_dword_t, _ofst) + \
(_idx)), EFX_DWORD_0, _value) \
+#define MCDI_IN_SET_QWORD(_emr, _ofst, _value) \
+ EFX_POPULATE_QWORD_2(*MCDI_IN2(_emr, efx_qword_t, _ofst), \
+ EFX_DWORD_0, ((_value) & 0xffffffff), \
+ EFX_DWORD_1, ((_value) >> 32))
+
+#define MCDI_IN_SET_INDEXED_QWORD(_emr, _ofst, _idx, _value) \
+ EFX_POPULATE_QWORD_2(*(MCDI_IN2(_emr, efx_qword_t, _ofst) + \
+ (_idx)), \
+ EFX_DWORD_0, ((_value) & 0xffffffff), \
+ EFX_DWORD_1, ((_value) >> 32))
+
#define MCDI_IN_POPULATE_DWORD_1(_emr, _ofst, _field1, _value1) \
EFX_POPULATE_DWORD_1(*MCDI_IN2(_emr, efx_dword_t, _ofst), \
MC_CMD_ ## _field1, _value1)
return (rc);
}
+
+/* Required en_eslp lock held */
+static __checkReturn efx_rc_t
+efx_nic_dma_config_regioned_find_region(
+ __in const efx_nic_t *enp,
+ __in efsys_dma_addr_t trgt_addr,
+ __in size_t len,
+ __out const efx_nic_dma_region_t **regionp)
+{
+ const efx_nic_dma_region_info_t *region_info;
+ const efx_nic_dma_region_t *region;
+ unsigned int i;
+ efx_rc_t rc;
+
+ if (efx_nic_cfg_get(enp)->enc_dma_mapping !=
+ EFX_NIC_DMA_MAPPING_REGIONED) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ region_info = &enp->en_dma.end_u.endu_region_info;
+
+ for (i = 0; i < region_info->endri_count; ++i) {
+ efsys_dma_addr_t offset;
+
+ region = ®ion_info->endri_regions[i];
+ if (region->endr_inuse == B_FALSE)
+ continue;
+
+ if (trgt_addr < region->endr_trgt_base)
+ continue;
+
+ EFSYS_ASSERT3U(region->endr_window_log2, <, 64);
+ offset = trgt_addr - region->endr_trgt_base;
+ if (offset + len > (1ULL << region->endr_window_log2))
+ continue;
+
+ *regionp = region;
+ return (0);
+ }
+
+ rc = ENOENT;
+ goto fail2;
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+static __checkReturn efx_rc_t
+efx_nic_dma_config_regioned_add_region(
+ __in efx_nic_t *enp,
+ __in efsys_dma_addr_t trgt_addr,
+ __in size_t len,
+ __out const efx_nic_dma_region_t **regionp)
+{
+ efx_nic_dma_region_info_t *region_info;
+ efx_nic_dma_region_t *region;
+ unsigned int i;
+ efx_rc_t rc;
+
+ if (efx_nic_cfg_get(enp)->enc_dma_mapping !=
+ EFX_NIC_DMA_MAPPING_REGIONED) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ region_info = &enp->en_dma.end_u.endu_region_info;
+
+ for (i = 0; i < region_info->endri_count; ++i) {
+ efsys_dma_addr_t trgt_base;
+ efsys_dma_addr_t offset;
+
+ region = ®ion_info->endri_regions[i];
+ if (region->endr_inuse == B_TRUE)
+ continue;
+
+ /*
+ * Align target address base in accordance with
+ * the region requirements.
+ */
+ EFSYS_ASSERT3U(region->endr_align_log2, <, 64);
+ trgt_base = EFX_P2ALIGN(efsys_dma_addr_t, trgt_addr,
+ (1ULL << region->endr_align_log2));
+
+ offset = trgt_addr - trgt_base;
+
+ /* Check if region window is sufficient */
+ EFSYS_ASSERT3U(region->endr_window_log2, <, 64);
+ if (offset + len > (1ULL << region->endr_window_log2))
+ continue;
+
+ region->endr_trgt_base = trgt_base;
+ region->endr_inuse = B_TRUE;
+
+ *regionp = region;
+ return (0);
+ }
+
+ /* No suitable free region found */
+ rc = ENOMEM;
+ goto fail2;
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+static __checkReturn efx_rc_t
+efx_nic_dma_config_regioned_add(
+ __in efx_nic_t *enp,
+ __in efsys_dma_addr_t trgt_addr,
+ __in size_t len,
+ __out_opt efsys_dma_addr_t *nic_basep,
+ __out_opt efsys_dma_addr_t *trgt_basep,
+ __out_opt size_t *map_lenp)
+{
+ const efx_nic_dma_region_t *region;
+ efsys_lock_state_t state;
+ efx_rc_t rc;
+
+ EFSYS_LOCK(enp->en_eslp, state);
+
+ rc = efx_nic_dma_config_regioned_find_region(enp, trgt_addr, len,
+ ®ion);
+ switch (rc) {
+ case 0:
+ /* Already covered by existing mapping */
+ break;
+ case ENOENT:
+ /* No existing mapping found */
+ rc = efx_nic_dma_config_regioned_add_region(enp,
+ trgt_addr, len, ®ion);
+ if (rc != 0)
+ goto fail1;
+ break;
+ default:
+ goto fail2;
+ }
+
+ if (nic_basep != NULL)
+ *nic_basep = region->endr_nic_base;
+ if (trgt_basep != NULL)
+ *trgt_basep = region->endr_trgt_base;
+ if (map_lenp != NULL)
+ *map_lenp = 1ULL << region->endr_window_log2;
+
+ EFSYS_UNLOCK(enp->en_eslp, state);
+
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ EFSYS_UNLOCK(enp->en_eslp, state);
+
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_nic_dma_config_add(
+ __in efx_nic_t *enp,
+ __in efsys_dma_addr_t trgt_addr,
+ __in size_t len,
+ __out_opt efsys_dma_addr_t *nic_basep,
+ __out_opt efsys_dma_addr_t *trgt_basep,
+ __out_opt size_t *map_lenp)
+{
+ const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
+ efx_rc_t rc;
+
+ switch (encp->enc_dma_mapping) {
+ case EFX_NIC_DMA_MAPPING_FLAT:
+ /* No mapping is required */
+ if (nic_basep != NULL)
+ *nic_basep = 0;
+ if (trgt_basep != NULL)
+ *trgt_basep = 0;
+ if (map_lenp != NULL)
+ *map_lenp = 0;
+ break;
+ case EFX_NIC_DMA_MAPPING_REGIONED:
+ rc = efx_nic_dma_config_regioned_add(enp, trgt_addr, len,
+ nic_basep, trgt_basep, map_lenp);
+ if (rc != 0)
+ goto fail1;
+ break;
+ case EFX_NIC_DMA_MAPPING_UNKNOWN:
+ default:
+ rc = ENOTSUP;
+ goto fail2;
+ }
+
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+static __checkReturn efx_rc_t
+efx_nic_dma_reconfigure_regioned(
+ __in efx_nic_t *enp)
+{
+ efx_rc_t rc;
+
+ rc = efx_mcdi_set_nic_addr_regions(enp,
+ &enp->en_dma.end_u.endu_region_info);
+ if (rc != 0)
+ goto fail1;
+
+ return (0);
+
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+
+}
+
+ __checkReturn efx_rc_t
+efx_nic_dma_reconfigure(
+ __in efx_nic_t *enp)
+{
+ const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
+ efx_rc_t rc;
+
+ switch (encp->enc_dma_mapping) {
+ case EFX_NIC_DMA_MAPPING_UNKNOWN:
+ case EFX_NIC_DMA_MAPPING_FLAT:
+ /* Nothing to do */
+ break;
+ case EFX_NIC_DMA_MAPPING_REGIONED:
+ rc = efx_nic_dma_reconfigure_regioned(enp);
+ if (rc != 0)
+ goto fail1;
+ break;
+ default:
+ rc = ENOTSUP;
+ goto fail2;
+ }
+
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+static __checkReturn efx_rc_t
+efx_nic_dma_unknown_map(
+ __in efx_nic_t *enp,
+ __in efx_nic_dma_addr_type_t addr_type,
+ __in efsys_dma_addr_t trgt_addr,
+ __in size_t len,
+ __out efsys_dma_addr_t *nic_addrp)
+{
+ efx_rc_t rc;
+
+ /* This function may be called before the NIC has been probed. */
+ if (enp->en_mod_flags & EFX_MOD_PROBE) {
+ EFSYS_ASSERT3U(efx_nic_cfg_get(enp)->enc_dma_mapping, ==,
+ EFX_NIC_DMA_MAPPING_UNKNOWN);
+ }
+
+ switch (addr_type) {
+ case EFX_NIC_DMA_ADDR_MCDI_BUF:
+ /*
+ * MC cares about MCDI buffer mapping itself since it cannot
+ * be really mapped using MCDI because mapped MCDI
+ * buffer is required to execute MCDI commands.
+ */
+ *nic_addrp = trgt_addr;
+ break;
+
+ case EFX_NIC_DMA_ADDR_MAC_STATS_BUF:
+ case EFX_NIC_DMA_ADDR_EVENT_RING:
+ case EFX_NIC_DMA_ADDR_RX_RING:
+ case EFX_NIC_DMA_ADDR_TX_RING:
+ case EFX_NIC_DMA_ADDR_RX_BUF:
+ case EFX_NIC_DMA_ADDR_TX_BUF:
+ /* Mapping type must be discovered first */
+ rc = EFAULT;
+ goto fail1;
+
+ default:
+ rc = EINVAL;
+ goto fail2;
+ }
+
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+static __checkReturn efx_rc_t
+efx_nic_dma_flat_map(
+ __in efx_nic_t *enp,
+ __in efx_nic_dma_addr_type_t addr_type,
+ __in efsys_dma_addr_t trgt_addr,
+ __in size_t len,
+ __out efsys_dma_addr_t *nic_addrp)
+{
+ _NOTE(ARGUNUSED(addr_type, len))
+
+ EFSYS_ASSERT3U(efx_nic_cfg_get(enp)->enc_dma_mapping, ==,
+ EFX_NIC_DMA_MAPPING_FLAT);
+
+ /* No re-mapping is required */
+ *nic_addrp = trgt_addr;
+
+ return (0);
+}
+
+static __checkReturn efx_rc_t
+efx_nic_dma_regioned_map(
+ __in efx_nic_t *enp,
+ __in efx_nic_dma_addr_type_t addr_type,
+ __in efsys_dma_addr_t trgt_addr,
+ __in size_t len,
+ __out efsys_dma_addr_t *nic_addrp)
+{
+ const efx_nic_dma_region_t *region;
+ efsys_lock_state_t state;
+ efx_rc_t rc;
+
+ if (efx_nic_cfg_get(enp)->enc_dma_mapping !=
+ EFX_NIC_DMA_MAPPING_REGIONED) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ switch (addr_type) {
+ case EFX_NIC_DMA_ADDR_MCDI_BUF:
+ case EFX_NIC_DMA_ADDR_MAC_STATS_BUF:
+ /*
+ * MC cares about MCDI buffer mapping itself since it cannot
+ * be really mapped using MCDI because mapped MCDI buffer is
+ * required to execute MCDI commands. It is not a problem
+ * for MAC stats buffer, but since MC can care about mapping
+ * itself, it may be done for MAC stats buffer as well.
+ */
+ *nic_addrp = trgt_addr;
+ goto out;
+
+ case EFX_NIC_DMA_ADDR_EVENT_RING:
+ case EFX_NIC_DMA_ADDR_RX_RING:
+ case EFX_NIC_DMA_ADDR_TX_RING:
+ case EFX_NIC_DMA_ADDR_RX_BUF:
+ case EFX_NIC_DMA_ADDR_TX_BUF:
+ /* Rings and buffer addresses should be mapped */
+ break;
+
+ default:
+ rc = EINVAL;
+ goto fail2;
+ }
+
+ EFSYS_LOCK(enp->en_eslp, state);
+
+ rc = efx_nic_dma_config_regioned_find_region(enp, trgt_addr, len,
+ ®ion);
+ if (rc != 0)
+ goto fail3;
+
+ *nic_addrp = region->endr_nic_base +
+ (trgt_addr - region->endr_trgt_base);
+
+ EFSYS_UNLOCK(enp->en_eslp, state);
+
+out:
+ return (0);
+
+fail3:
+ EFSYS_PROBE(fail3);
+ EFSYS_UNLOCK(enp->en_eslp, state);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_nic_dma_map(
+ __in efx_nic_t *enp,
+ __in efx_nic_dma_addr_type_t addr_type,
+ __in efsys_dma_addr_t trgt_addr,
+ __in size_t len,
+ __out efsys_dma_addr_t *nic_addrp)
+{
+ efx_nic_dma_mapping_t mapping;
+ efx_rc_t rc;
+
+ /*
+ * We cannot check configuration of a NIC that hasn't been probed.
+ * Use EFX_NIC_DMA_MAPPING_UNKNOWN by default.
+ */
+ if ((enp->en_mod_flags & EFX_MOD_PROBE) == 0)
+ mapping = EFX_NIC_DMA_MAPPING_UNKNOWN;
+ else
+ mapping = efx_nic_cfg_get(enp)->enc_dma_mapping;
+
+ switch (mapping) {
+ case EFX_NIC_DMA_MAPPING_UNKNOWN:
+ rc = efx_nic_dma_unknown_map(enp, addr_type, trgt_addr,
+ len, nic_addrp);
+ if (rc != 0)
+ goto fail1;
+ break;
+ case EFX_NIC_DMA_MAPPING_FLAT:
+ rc = efx_nic_dma_flat_map(enp, addr_type, trgt_addr,
+ len, nic_addrp);
+ if (rc != 0)
+ goto fail2;
+ break;
+ case EFX_NIC_DMA_MAPPING_REGIONED:
+ rc = efx_nic_dma_regioned_map(enp, addr_type, trgt_addr,
+ len, nic_addrp);
+ if (rc != 0)
+ goto fail3;
+ break;
+ default:
+ rc = ENOTSUP;
+ goto fail4;
+ }
+
+ return (0);
+
+fail4:
+ EFSYS_PROBE(fail4);
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
encp->enc_mae_supported = B_FALSE;
encp->enc_mae_admin = B_FALSE;
+ encp->enc_dma_mapping = EFX_NIC_DMA_MAPPING_FLAT;
+
return (0);
fail2:
efx_nic_check_pcie_link_speed;
efx_nic_create;
efx_nic_destroy;
+ efx_nic_dma_config_add;
+ efx_nic_dma_map;
+ efx_nic_dma_reconfigure;
efx_nic_fini;
efx_nic_get_bar_region;
efx_nic_get_board_info;