-/*-
- * BSD LICENSE
+/* SPDX-License-Identifier: BSD-3-Clause
*
- * Copyright (c) 2016-2017 Solarflare Communications Inc.
- * All rights reserved.
+ * Copyright(c) 2019-2021 Xilinx, Inc.
+ * Copyright(c) 2016-2019 Solarflare Communications Inc.
*
* This software was jointly developed between OKTET Labs (under contract
* for Solarflare) and Solarflare Communications, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <rte_bitmap.h>
+
#include "efx.h"
#include "sfc.h"
+#include "sfc_debug.h"
#include "sfc_log.h"
#include "sfc_kvargs.h"
/**
* Update MAC statistics in the buffer.
*
- * @param sa Adapter
+ * @param sa Adapter
+ * @param force_upload Flag to upload MAC stats in any case
*
* @return Status code
* @retval 0 Success
* @retval ENOMEM Memory allocation failure
*/
int
-sfc_port_update_mac_stats(struct sfc_adapter *sa)
+sfc_port_update_mac_stats(struct sfc_adapter *sa, boolean_t force_upload)
{
struct sfc_port *port = &sa->port;
efsys_mem_t *esmp = &port->mac_stats_dma_mem;
unsigned int nb_attempts = 0;
int rc;
- SFC_ASSERT(rte_spinlock_is_locked(&port->mac_stats_lock));
+ SFC_ASSERT(sfc_adapter_is_locked(sa));
- if (sa->state != SFC_ADAPTER_STARTED)
- return EINVAL;
+ if (sa->state != SFC_ETHDEV_STARTED)
+ return 0;
/*
* If periodic statistics DMA'ing is off or if not supported,
* make a manual request and keep an eye on timer if need be
*/
if (!port->mac_stats_periodic_dma_supported ||
- (port->mac_stats_update_period_ms == 0)) {
+ (port->mac_stats_update_period_ms == 0) || force_upload) {
if (port->mac_stats_update_period_ms != 0) {
uint64_t timestamp = sfc_get_system_msecs();
return 0;
}
+static void
+sfc_port_reset_sw_stats(struct sfc_adapter *sa)
+{
+ struct sfc_port *port = &sa->port;
+
+ /*
+ * Reset diff stats explicitly since check which does not allow
+ * the statistics to grow backward could deny it.
+ */
+ port->ipackets = 0;
+}
+
int
sfc_port_reset_mac_stats(struct sfc_adapter *sa)
{
- struct sfc_port *port = &sa->port;
int rc;
- rte_spinlock_lock(&port->mac_stats_lock);
+ SFC_ASSERT(sfc_adapter_is_locked(sa));
+
rc = efx_mac_stats_clear(sa->nic);
- rte_spinlock_unlock(&port->mac_stats_lock);
+ if (rc == 0)
+ sfc_port_reset_sw_stats(sa);
return rc;
}
return 0;
}
+#if EFSYS_OPT_LOOPBACK
+
+static efx_link_mode_t
+sfc_port_phy_caps_to_max_link_speed(uint32_t phy_caps)
+{
+ if (phy_caps & (1u << EFX_PHY_CAP_100000FDX))
+ return EFX_LINK_100000FDX;
+ if (phy_caps & (1u << EFX_PHY_CAP_50000FDX))
+ return EFX_LINK_50000FDX;
+ if (phy_caps & (1u << EFX_PHY_CAP_40000FDX))
+ return EFX_LINK_40000FDX;
+ if (phy_caps & (1u << EFX_PHY_CAP_25000FDX))
+ return EFX_LINK_25000FDX;
+ if (phy_caps & (1u << EFX_PHY_CAP_10000FDX))
+ return EFX_LINK_10000FDX;
+ if (phy_caps & (1u << EFX_PHY_CAP_1000FDX))
+ return EFX_LINK_1000FDX;
+ return EFX_LINK_UNKNOWN;
+}
+
+#endif
+
+static void
+sfc_port_fill_mac_stats_info(struct sfc_adapter *sa)
+{
+ unsigned int mac_stats_nb_supported = 0;
+ struct sfc_port *port = &sa->port;
+ unsigned int stat_idx;
+
+ efx_mac_stats_get_mask(sa->nic, port->mac_stats_mask,
+ sizeof(port->mac_stats_mask));
+
+ for (stat_idx = 0; stat_idx < EFX_MAC_NSTATS; ++stat_idx) {
+ if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, stat_idx))
+ continue;
+
+ port->mac_stats_by_id[mac_stats_nb_supported] = stat_idx;
+ mac_stats_nb_supported++;
+ }
+
+ port->mac_stats_nb_supported = mac_stats_nb_supported;
+}
+
int
sfc_port_start(struct sfc_adapter *sa)
{
uint32_t phy_adv_cap;
const uint32_t phy_pause_caps =
((1u << EFX_PHY_CAP_PAUSE) | (1u << EFX_PHY_CAP_ASYM));
- unsigned int i;
sfc_log_init(sa, "entry");
if (rc != 0)
goto fail_port_init;
+#if EFSYS_OPT_LOOPBACK
+ if (sa->eth_dev->data->dev_conf.lpbk_mode != 0) {
+ efx_link_mode_t link_mode;
+
+ link_mode =
+ sfc_port_phy_caps_to_max_link_speed(port->phy_adv_cap);
+ sfc_log_init(sa, "set loopback link_mode=%u type=%u", link_mode,
+ sa->eth_dev->data->dev_conf.lpbk_mode);
+ rc = efx_port_loopback_set(sa->nic, link_mode,
+ sa->eth_dev->data->dev_conf.lpbk_mode);
+ if (rc != 0)
+ goto fail_loopback_set;
+ }
+#endif
+
sfc_log_init(sa, "set flow control to %#x autoneg=%u",
port->flow_ctrl, port->flow_ctrl_autoneg);
rc = efx_mac_fcntl_set(sa->nic, port->flow_ctrl,
SFC_ASSERT((port->phy_adv_cap & phy_pause_caps) == 0);
phy_adv_cap = port->phy_adv_cap | (phy_adv_cap & phy_pause_caps);
+ /*
+ * No controls for FEC yet. Use default FEC mode.
+ * I.e. advertise everything supported (*_FEC=1), but do not request
+ * anything explicitly (*_FEC_REQUESTED=0).
+ */
+ phy_adv_cap |= port->phy_adv_cap_mask &
+ (1u << EFX_PHY_CAP_BASER_FEC |
+ 1u << EFX_PHY_CAP_RS_FEC |
+ 1u << EFX_PHY_CAP_25G_BASER_FEC);
+
sfc_log_init(sa, "set phy adv caps to %#x", phy_adv_cap);
rc = efx_phy_adv_cap_set(sa->nic, phy_adv_cap);
if (rc != 0)
if (rc != 0)
goto fail_mac_pdu_set;
- if (!port->isolated) {
- struct ether_addr *mac_addrs = sa->eth_dev->data->mac_addrs;
+ if (!sfc_sa2shared(sa)->isolated) {
+ struct rte_ether_addr *addr = &port->default_mac_addr;
sfc_log_init(sa, "set MAC address");
- rc = efx_mac_addr_set(sa->nic, mac_addrs[0].addr_bytes);
+ rc = efx_mac_addr_set(sa->nic, addr->addr_bytes);
if (rc != 0)
goto fail_mac_addr_set;
B_TRUE : B_FALSE;
port->allmulti = (sa->eth_dev->data->all_multicast != 0) ?
B_TRUE : B_FALSE;
- rc = sfc_set_rx_mode(sa);
+ rc = sfc_set_rx_mode_unchecked(sa);
if (rc != 0)
goto fail_mac_filter_set;
port->mac_stats_reset_pending = B_FALSE;
}
- efx_mac_stats_get_mask(sa->nic, port->mac_stats_mask,
- sizeof(port->mac_stats_mask));
-
- for (i = 0, port->mac_stats_nb_supported = 0; i < EFX_MAC_NSTATS; ++i)
- if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i))
- port->mac_stats_nb_supported++;
+ sfc_port_fill_mac_stats_info(sa);
port->mac_stats_update_generation = 0;
fail_mac_pdu_set:
fail_phy_adv_cap_set:
fail_mac_fcntl_set:
+#if EFSYS_OPT_LOOPBACK
+fail_loopback_set:
+#endif
efx_port_fini(sa->nic);
fail_port_init:
(void)efx_mac_stats_periodic(sa->nic, &sa->port.mac_stats_dma_mem,
0, B_FALSE);
+ sfc_port_update_mac_stats(sa, B_TRUE);
+
efx_port_fini(sa->nic);
efx_filter_fini(sa->nic);
sfc_log_init(sa, "entry");
- if (dev_data->dev_conf.rxmode.jumbo_frame)
- port->pdu = dev_data->dev_conf.rxmode.max_rx_pkt_len;
- else
- port->pdu = EFX_MAC_PDU(dev_data->mtu);
+ port->pdu = EFX_MAC_PDU(dev_data->mtu);
return 0;
}
sfc_port_attach(struct sfc_adapter *sa)
{
struct sfc_port *port = &sa->port;
+ const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
+ const struct rte_ether_addr *from;
+ uint32_t mac_nstats;
+ size_t mac_stats_size;
long kvarg_stats_update_period_ms;
int rc;
port->flow_ctrl = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
port->flow_ctrl_autoneg = B_TRUE;
+ RTE_BUILD_BUG_ON(sizeof(encp->enc_mac_addr) != sizeof(*from));
+ from = (const struct rte_ether_addr *)(encp->enc_mac_addr);
+ rte_ether_addr_copy(from, &port->default_mac_addr);
+
port->max_mcast_addrs = EFX_MAC_MULTICAST_LIST_MAX;
port->nb_mcast_addrs = 0;
port->mcast_addrs = rte_calloc_socket("mcast_addr_list_buf",
goto fail_mcast_addr_list_buf_alloc;
}
- rte_spinlock_init(&port->mac_stats_lock);
-
rc = ENOMEM;
port->mac_stats_buf = rte_calloc_socket("mac_stats_buf", EFX_MAC_NSTATS,
sizeof(uint64_t), 0,
if (port->mac_stats_buf == NULL)
goto fail_mac_stats_buf_alloc;
- rc = sfc_dma_alloc(sa, "mac_stats", 0, EFX_MAC_STATS_SIZE,
+ mac_nstats = efx_nic_cfg_get(sa->nic)->enc_mac_stats_nstats;
+ mac_stats_size = RTE_ALIGN(mac_nstats * sizeof(uint64_t), EFX_BUF_SIZE);
+ rc = sfc_dma_alloc(sa, "mac_stats", 0, EFX_NIC_DMA_ADDR_MAC_STATS_BUF,
+ mac_stats_size,
sa->socket_id, &port->mac_stats_dma_mem);
if (rc != 0)
goto fail_mac_stats_dma_alloc;
return 0;
fail_kvarg_stats_update_period_ms:
+ sfc_dma_free(sa, &port->mac_stats_dma_mem);
+
fail_mac_stats_dma_alloc:
rte_free(port->mac_stats_buf);
+
fail_mac_stats_buf_alloc:
+ rte_free(port->mcast_addrs);
+
fail_mcast_addr_list_buf_alloc:
sfc_log_init(sa, "failed %d", rc);
return rc;
sfc_dma_free(sa, &port->mac_stats_dma_mem);
rte_free(port->mac_stats_buf);
+ rte_free(port->mcast_addrs);
+
sfc_log_init(sa, "done");
}
+static boolean_t
+sfc_get_requested_all_ucast(struct sfc_port *port)
+{
+ return port->promisc;
+}
+
+static boolean_t
+sfc_get_requested_all_mcast(struct sfc_port *port)
+{
+ return port->promisc || port->allmulti;
+}
+
+int
+sfc_set_rx_mode_unchecked(struct sfc_adapter *sa)
+{
+ struct sfc_port *port = &sa->port;
+ boolean_t requested_all_ucast = sfc_get_requested_all_ucast(port);
+ boolean_t requested_all_mcast = sfc_get_requested_all_mcast(port);
+ int rc;
+
+ rc = efx_mac_filter_set(sa->nic, requested_all_ucast, B_TRUE,
+ requested_all_mcast, B_TRUE);
+ if (rc != 0)
+ return rc;
+
+ return 0;
+}
+
int
sfc_set_rx_mode(struct sfc_adapter *sa)
{
struct sfc_port *port = &sa->port;
+ boolean_t old_all_ucast;
+ boolean_t old_all_mcast;
+ boolean_t requested_all_ucast = sfc_get_requested_all_ucast(port);
+ boolean_t requested_all_mcast = sfc_get_requested_all_mcast(port);
+ boolean_t actual_all_ucast;
+ boolean_t actual_all_mcast;
int rc;
- rc = efx_mac_filter_set(sa->nic, port->promisc, B_TRUE,
- port->promisc || port->allmulti, B_TRUE);
+ efx_mac_filter_get_all_ucast_mcast(sa->nic, &old_all_ucast,
+ &old_all_mcast);
- return rc;
+ rc = sfc_set_rx_mode_unchecked(sa);
+ if (rc != 0)
+ return rc;
+
+ efx_mac_filter_get_all_ucast_mcast(sa->nic, &actual_all_ucast,
+ &actual_all_mcast);
+
+ if (actual_all_ucast != requested_all_ucast ||
+ actual_all_mcast != requested_all_mcast) {
+ /*
+ * MAC filter set succeeded but not all requested modes
+ * were applied. The rollback is necessary to bring back the
+ * consistent old state.
+ */
+ (void)efx_mac_filter_set(sa->nic, old_all_ucast, B_TRUE,
+ old_all_mcast, B_TRUE);
+
+ return EPERM;
+ }
+
+ return 0;
}
void
memset(link_info, 0, sizeof(*link_info));
if ((link_mode == EFX_LINK_DOWN) || (link_mode == EFX_LINK_UNKNOWN))
- link_info->link_status = ETH_LINK_DOWN;
+ link_info->link_status = RTE_ETH_LINK_DOWN;
else
- link_info->link_status = ETH_LINK_UP;
+ link_info->link_status = RTE_ETH_LINK_UP;
switch (link_mode) {
case EFX_LINK_10HDX:
- link_info->link_speed = ETH_SPEED_NUM_10M;
- link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
+ link_info->link_speed = RTE_ETH_SPEED_NUM_10M;
+ link_info->link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
break;
case EFX_LINK_10FDX:
- link_info->link_speed = ETH_SPEED_NUM_10M;
- link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
+ link_info->link_speed = RTE_ETH_SPEED_NUM_10M;
+ link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
break;
case EFX_LINK_100HDX:
- link_info->link_speed = ETH_SPEED_NUM_100M;
- link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
+ link_info->link_speed = RTE_ETH_SPEED_NUM_100M;
+ link_info->link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
break;
case EFX_LINK_100FDX:
- link_info->link_speed = ETH_SPEED_NUM_100M;
- link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
+ link_info->link_speed = RTE_ETH_SPEED_NUM_100M;
+ link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
break;
case EFX_LINK_1000HDX:
- link_info->link_speed = ETH_SPEED_NUM_1G;
- link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
+ link_info->link_speed = RTE_ETH_SPEED_NUM_1G;
+ link_info->link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
break;
case EFX_LINK_1000FDX:
- link_info->link_speed = ETH_SPEED_NUM_1G;
- link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
+ link_info->link_speed = RTE_ETH_SPEED_NUM_1G;
+ link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
break;
case EFX_LINK_10000FDX:
- link_info->link_speed = ETH_SPEED_NUM_10G;
- link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
+ link_info->link_speed = RTE_ETH_SPEED_NUM_10G;
+ link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ case EFX_LINK_25000FDX:
+ link_info->link_speed = RTE_ETH_SPEED_NUM_25G;
+ link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
break;
case EFX_LINK_40000FDX:
- link_info->link_speed = ETH_SPEED_NUM_40G;
- link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
+ link_info->link_speed = RTE_ETH_SPEED_NUM_40G;
+ link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ case EFX_LINK_50000FDX:
+ link_info->link_speed = RTE_ETH_SPEED_NUM_50G;
+ link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ case EFX_LINK_100000FDX:
+ link_info->link_speed = RTE_ETH_SPEED_NUM_100G;
+ link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
break;
default:
SFC_ASSERT(B_FALSE);
/* FALLTHROUGH */
case EFX_LINK_UNKNOWN:
case EFX_LINK_DOWN:
- link_info->link_speed = ETH_SPEED_NUM_NONE;
+ link_info->link_speed = RTE_ETH_SPEED_NUM_NONE;
link_info->link_duplex = 0;
break;
}
- link_info->link_autoneg = ETH_LINK_AUTONEG;
+ link_info->link_autoneg = RTE_ETH_LINK_AUTONEG;
+}
+
+int
+sfc_port_get_mac_stats(struct sfc_adapter *sa, struct rte_eth_xstat *xstats,
+ unsigned int xstats_count, unsigned int *nb_written)
+{
+ struct sfc_port *port = &sa->port;
+ uint64_t *mac_stats;
+ unsigned int i;
+ int nstats = 0;
+ int ret;
+
+ sfc_adapter_lock(sa);
+
+ ret = sfc_port_update_mac_stats(sa, B_FALSE);
+ if (ret != 0) {
+ SFC_ASSERT(ret > 0);
+ ret = -ret;
+ goto unlock;
+ }
+
+ mac_stats = port->mac_stats_buf;
+
+ for (i = 0; i < EFX_MAC_NSTATS; ++i) {
+ if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
+ if (nstats < (int)xstats_count) {
+ xstats[nstats].id = nstats;
+ xstats[nstats].value = mac_stats[i];
+ (*nb_written)++;
+ }
+ nstats++;
+ }
+ }
+ ret = nstats;
+
+unlock:
+ sfc_adapter_unlock(sa);
+
+ return ret;
+}
+
+int
+sfc_port_get_mac_stats_by_id(struct sfc_adapter *sa, const uint64_t *ids,
+ uint64_t *values, unsigned int n)
+{
+ struct sfc_port *port = &sa->port;
+ uint64_t *mac_stats;
+ unsigned int i;
+ int ret;
+ int rc;
+
+ sfc_adapter_lock(sa);
+
+ rc = sfc_port_update_mac_stats(sa, B_FALSE);
+ if (rc != 0) {
+ SFC_ASSERT(rc > 0);
+ ret = -rc;
+ goto unlock;
+ }
+
+ mac_stats = port->mac_stats_buf;
+
+ SFC_ASSERT(port->mac_stats_nb_supported <=
+ RTE_DIM(port->mac_stats_by_id));
+
+ for (i = 0; i < n; i++) {
+ if (ids[i] < port->mac_stats_nb_supported)
+ values[i] = mac_stats[port->mac_stats_by_id[ids[i]]];
+ }
+
+ ret = 0;
+
+unlock:
+ sfc_adapter_unlock(sa);
+
+ return ret;
}