Since 24.11, DPDK has supported APIs to control lane count of the physical link. Provide driver-level support for that on adaptors that are netport MCDI capabale (Medford4, for instance).
Signed-off-by: Ivan Malov <ivan.ma...@arknetworks.am> Reviewed-by: Andy Moreton <andy.more...@amd.com> Reviewed-by: Pieter Jansen Van Vuuren <pieter.jansen-van-vuu...@amd.com> --- drivers/net/sfc/sfc.h | 2 + drivers/net/sfc/sfc_ethdev.c | 147 +++++++++++++++++++++++++++++++++++ drivers/net/sfc/sfc_port.c | 19 +++++ 3 files changed, 168 insertions(+) diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h index 819ce52529..af32ccfaa3 100644 --- a/drivers/net/sfc/sfc.h +++ b/drivers/net/sfc/sfc.h @@ -67,6 +67,8 @@ struct sfc_dp_rx; struct sfc_port { unsigned int lsc_seq; + efx_phy_lane_count_t phy_lane_count_active; + efx_phy_lane_count_t phy_lane_count_req; uint32_t phy_adv_cap_mask; uint32_t phy_adv_cap; uint32_t fec_cfg; diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c index 80eb39e58d..b38fc79d62 100644 --- a/drivers/net/sfc/sfc_ethdev.c +++ b/drivers/net/sfc/sfc_ethdev.c @@ -291,6 +291,150 @@ sfc_dev_link_update(struct rte_eth_dev *dev, int wait_to_complete) return ret; } +static int +sfc_dev_speed_lanes_get(struct rte_eth_dev *dev, uint32_t *lane_countp) +{ + struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev); + struct sfc_port *port; + int rc = 0; + + if (lane_countp == NULL) + return -EINVAL; + + sfc_adapter_lock(sa); + port = &sa->port; + + if (sa->state != SFC_ETHDEV_STARTED) { + /* The API wants 'active' lanes, so it is safe to indicate 0. */ + *lane_countp = 0; + goto unlock; + } + + if (port->phy_lane_count_active == EFX_PHY_LANE_COUNT_DEFAULT) { + rc = ENOTSUP; + goto unlock; + } + + *lane_countp = port->phy_lane_count_active; + +unlock: + sfc_adapter_unlock(sa); + return -rc; +} + +static int +sfc_dev_speed_lanes_set(struct rte_eth_dev *dev, uint32_t lane_count) +{ + struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev); + int rc = 0; + + sfc_adapter_lock(sa); + + if (sa->state == SFC_ETHDEV_STARTED) { + rc = EBUSY; + goto unlock; + } + + if (lane_count == 0) { + rc = EINVAL; + goto unlock; + } + + sa->port.phy_lane_count_req = lane_count; + +unlock: + sfc_adapter_unlock(sa); + return -rc; +} + +static int +sfc_dev_speed_lane_cap_handle(const efx_nic_cfg_t *encp, + efx_link_mode_t link_mode, + unsigned int *nb_caps_to_fillp, + struct rte_eth_speed_lanes_capa **capp) +{ + uint32_t lane_counts = encp->enc_phy_lane_counts[link_mode].ed_u32[0]; + struct rte_eth_speed_lanes_capa *cap = *capp; + uint32_t speed; + + if (lane_counts == 0) { + /* + * The mask of supported lane counts for this link mode is + * empty. Do not waste output entries for such link modes. + */ + return 0; + } + + switch (link_mode) { + case EFX_LINK_1000FDX: + speed = RTE_ETH_SPEED_NUM_1G; + break; + case EFX_LINK_10000FDX: + speed = RTE_ETH_SPEED_NUM_10G; + break; + case EFX_LINK_25000FDX: + speed = RTE_ETH_SPEED_NUM_25G; + break; + case EFX_LINK_40000FDX: + speed = RTE_ETH_SPEED_NUM_40G; + break; + case EFX_LINK_50000FDX: + speed = RTE_ETH_SPEED_NUM_50G; + break; + case EFX_LINK_100000FDX: + speed = RTE_ETH_SPEED_NUM_100G; + break; + case EFX_LINK_200000FDX: + speed = RTE_ETH_SPEED_NUM_200G; + break; + default: + /* No lane counts for this link mode. */ + return 0; + } + + if (*nb_caps_to_fillp == 0) { + if (cap == NULL) { + /* Dry run. Indicate that an entry is available. */ + return 1; + } + + /* We have run out of space in the user output buffer. */ + return 0; + } + + cap->capa = lane_counts; + cap->speed = speed; + + --(*nb_caps_to_fillp); + ++(*capp); + return 1; +} + +static int +sfc_dev_speed_lanes_get_capa(struct rte_eth_dev *dev, + struct rte_eth_speed_lanes_capa *caps, + unsigned int nb_caps) +{ + struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev); + const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic); + efx_link_mode_t i; + int ret = 0; + + sfc_adapter_lock(sa); + + if (sa->state < SFC_ETHDEV_INITIALIZED) { + ret = -ENODATA; + goto unlock; + } + + for (i = 0; i < EFX_LINK_NMODES; ++i) + ret += sfc_dev_speed_lane_cap_handle(encp, i, &nb_caps, &caps); + +unlock: + sfc_adapter_unlock(sa); + return ret; +} + static int sfc_dev_stop(struct rte_eth_dev *dev) { @@ -2759,6 +2903,9 @@ static const struct eth_dev_ops sfc_eth_dev_ops = { .allmulticast_enable = sfc_dev_allmulti_enable, .allmulticast_disable = sfc_dev_allmulti_disable, .link_update = sfc_dev_link_update, + .speed_lanes_get = sfc_dev_speed_lanes_get, + .speed_lanes_set = sfc_dev_speed_lanes_set, + .speed_lanes_get_capa = sfc_dev_speed_lanes_get_capa, .stats_get = sfc_stats_get, .stats_reset = sfc_stats_reset, .xstats_get = sfc_xstats_get, diff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c index 0a31a394d5..e5a7b8358d 100644 --- a/drivers/net/sfc/sfc_port.c +++ b/drivers/net/sfc/sfc_port.c @@ -187,6 +187,7 @@ sfc_port_fill_mac_stats_info(struct sfc_adapter *sa) int sfc_port_start(struct sfc_adapter *sa) { + efx_phy_link_state_t link_state = {0}; struct sfc_port *port = &sa->port; int rc; uint32_t phy_adv_cap; @@ -243,6 +244,20 @@ sfc_port_start(struct sfc_adapter *sa) if (rc != 0) goto fail_phy_adv_cap_set; + sfc_log_init(sa, "set phy lane count -- %s", + (port->phy_lane_count_req == EFX_PHY_LANE_COUNT_DEFAULT) ? + "let EFX pick default value" : "use custom value"); + rc = efx_phy_lane_count_set(sa->nic, port->phy_lane_count_req); + if (rc != 0) + goto fail_phy_lane_count_set; + + sfc_log_init(sa, "get phy lane count"); + rc = efx_phy_link_state_get(sa->nic, &link_state); + if (rc != 0) + goto fail_phy_lane_count_get; + + port->phy_lane_count_active = link_state.epls_lane_count; + sfc_log_init(sa, "set MAC PDU %u", (unsigned int)port->pdu); rc = efx_mac_pdu_set(sa->nic, port->pdu); if (rc != 0) @@ -350,6 +365,8 @@ sfc_port_start(struct sfc_adapter *sa) fail_mac_filter_set: fail_mac_addr_set: fail_mac_pdu_set: +fail_phy_lane_count_get: +fail_phy_lane_count_set: fail_phy_adv_cap_set: fail_mac_fcntl_set: fail_mac_vlan_strip_set: @@ -427,6 +444,8 @@ sfc_port_attach(struct sfc_adapter *sa) sfc_log_init(sa, "entry"); + port->phy_lane_count_req = EFX_PHY_LANE_COUNT_DEFAULT; + efx_phy_adv_cap_get(sa->nic, EFX_PHY_CAP_PERM, &port->phy_adv_cap_mask); /* Enable flow control by default */ -- 2.39.5