Commit 3ccec4bd authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mlx5-next'

Saeed Mahameed says:

====================
Mellanox 100G extending mlx5 ethtool support

Changes from V0:
	- Dropped: net/mlx5e: Disable link up on INIT HCA command
	  Due to Ido's and Or's requests we will submit this patch to net and will need it for -stable.
	- Rebased to: 11afbff8 ("Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next"

)

This series is centralized around extending and improving mlx5 ethernet driver ethtool
support. We've done some code refactoring for ethtool statistics reporting, making it
more scalable and robust, now each reported ethtool counter belongs to a group and has
its own descriptor within that group, the descriptor holds the counter name and offset
in memory in that group memory block.

Added new counters:
	- Reporting more error and drop counter in ifconig/ip tool.
	- Per priority pause and traffic counter in ethtool.
	- link down events counter in ethtool.

Set features handling was also refactored a little bit to be more resilient and generic,
now setting more than one feature will not stop on the first failed one, but instead
it will try to continue setting others. We made it generic to make it simpler for adding
more features support, it is now done easily by only introducing a handler function of
the new supported netdev feature, and let the generic handler do the job.

New netdev features and ethtool support:
	- Netdev feature RXALL, set on/off FCS check offload.
	- Netdev feature HW_VLAN_CTAG_RX, set on/off rx-vlan stripping offload.
	- Ethtool interface identify.
	- Ethtool dump module EEPROM.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4e095a9a 1b223dd3
......@@ -46,6 +46,7 @@
#include <linux/rhashtable.h>
#include "wq.h"
#include "mlx5_core.h"
#include "en_stats.h"
#define MLX5E_MAX_NUM_TC 8
......@@ -148,245 +149,6 @@ struct mlx5e_umr_wqe {
#define MLX5E_MIN_BW_ALLOC 1 /* Min percentage of BW allocation */
#endif
static const char vport_strings[][ETH_GSTRING_LEN] = {
/* vport statistics */
"rx_packets",
"rx_bytes",
"tx_packets",
"tx_bytes",
"rx_error_packets",
"rx_error_bytes",
"tx_error_packets",
"tx_error_bytes",
"rx_unicast_packets",
"rx_unicast_bytes",
"tx_unicast_packets",
"tx_unicast_bytes",
"rx_multicast_packets",
"rx_multicast_bytes",
"tx_multicast_packets",
"tx_multicast_bytes",
"rx_broadcast_packets",
"rx_broadcast_bytes",
"tx_broadcast_packets",
"tx_broadcast_bytes",
/* SW counters */
"tso_packets",
"tso_bytes",
"tso_inner_packets",
"tso_inner_bytes",
"lro_packets",
"lro_bytes",
"rx_csum_good",
"rx_csum_none",
"rx_csum_sw",
"tx_csum_offload",
"tx_csum_inner",
"tx_queue_stopped",
"tx_queue_wake",
"tx_queue_dropped",
"rx_wqe_err",
"rx_mpwqe_filler",
"rx_mpwqe_frag",
"rx_buff_alloc_err",
};
struct mlx5e_vport_stats {
/* HW counters */
u64 rx_packets;
u64 rx_bytes;
u64 tx_packets;
u64 tx_bytes;
u64 rx_error_packets;
u64 rx_error_bytes;
u64 tx_error_packets;
u64 tx_error_bytes;
u64 rx_unicast_packets;
u64 rx_unicast_bytes;
u64 tx_unicast_packets;
u64 tx_unicast_bytes;
u64 rx_multicast_packets;
u64 rx_multicast_bytes;
u64 tx_multicast_packets;
u64 tx_multicast_bytes;
u64 rx_broadcast_packets;
u64 rx_broadcast_bytes;
u64 tx_broadcast_packets;
u64 tx_broadcast_bytes;
/* SW counters */
u64 tso_packets;
u64 tso_bytes;
u64 tso_inner_packets;
u64 tso_inner_bytes;
u64 lro_packets;
u64 lro_bytes;
u64 rx_csum_good;
u64 rx_csum_none;
u64 rx_csum_sw;
u64 tx_csum_offload;
u64 tx_csum_inner;
u64 tx_queue_stopped;
u64 tx_queue_wake;
u64 tx_queue_dropped;
u64 rx_wqe_err;
u64 rx_mpwqe_filler;
u64 rx_mpwqe_frag;
u64 rx_buff_alloc_err;
#define NUM_VPORT_COUNTERS 38
};
static const char pport_strings[][ETH_GSTRING_LEN] = {
/* IEEE802.3 counters */
"frames_tx",
"frames_rx",
"check_seq_err",
"alignment_err",
"octets_tx",
"octets_received",
"multicast_xmitted",
"broadcast_xmitted",
"multicast_rx",
"broadcast_rx",
"in_range_len_errors",
"out_of_range_len",
"too_long_errors",
"symbol_err",
"mac_control_tx",
"mac_control_rx",
"unsupported_op_rx",
"pause_ctrl_rx",
"pause_ctrl_tx",
/* RFC2863 counters */
"in_octets",
"in_ucast_pkts",
"in_discards",
"in_errors",
"in_unknown_protos",
"out_octets",
"out_ucast_pkts",
"out_discards",
"out_errors",
"in_multicast_pkts",
"in_broadcast_pkts",
"out_multicast_pkts",
"out_broadcast_pkts",
/* RFC2819 counters */
"drop_events",
"octets",
"pkts",
"broadcast_pkts",
"multicast_pkts",
"crc_align_errors",
"undersize_pkts",
"oversize_pkts",
"fragments",
"jabbers",
"collisions",
"p64octets",
"p65to127octets",
"p128to255octets",
"p256to511octets",
"p512to1023octets",
"p1024to1518octets",
"p1519to2047octets",
"p2048to4095octets",
"p4096to8191octets",
"p8192to10239octets",
};
#define NUM_IEEE_802_3_COUNTERS 19
#define NUM_RFC_2863_COUNTERS 13
#define NUM_RFC_2819_COUNTERS 21
#define NUM_PPORT_COUNTERS (NUM_IEEE_802_3_COUNTERS + \
NUM_RFC_2863_COUNTERS + \
NUM_RFC_2819_COUNTERS)
struct mlx5e_pport_stats {
__be64 IEEE_802_3_counters[NUM_IEEE_802_3_COUNTERS];
__be64 RFC_2863_counters[NUM_RFC_2863_COUNTERS];
__be64 RFC_2819_counters[NUM_RFC_2819_COUNTERS];
};
static const char qcounter_stats_strings[][ETH_GSTRING_LEN] = {
"rx_out_of_buffer",
};
struct mlx5e_qcounter_stats {
u32 rx_out_of_buffer;
#define NUM_Q_COUNTERS 1
};
static const char rq_stats_strings[][ETH_GSTRING_LEN] = {
"packets",
"bytes",
"csum_none",
"csum_sw",
"lro_packets",
"lro_bytes",
"wqe_err",
"mpwqe_filler",
"mpwqe_frag",
"buff_alloc_err",
};
struct mlx5e_rq_stats {
u64 packets;
u64 bytes;
u64 csum_none;
u64 csum_sw;
u64 lro_packets;
u64 lro_bytes;
u64 wqe_err;
u64 mpwqe_filler;
u64 mpwqe_frag;
u64 buff_alloc_err;
#define NUM_RQ_STATS 10
};
static const char sq_stats_strings[][ETH_GSTRING_LEN] = {
"packets",
"bytes",
"tso_packets",
"tso_bytes",
"tso_inner_packets",
"tso_inner_bytes",
"csum_offload_inner",
"nop",
"csum_offload_none",
"stopped",
"wake",
"dropped",
};
struct mlx5e_sq_stats {
/* commonly accessed in data path */
u64 packets;
u64 bytes;
u64 tso_packets;
u64 tso_bytes;
u64 tso_inner_packets;
u64 tso_inner_bytes;
u64 csum_offload_inner;
u64 nop;
/* less likely accessed in data path */
u64 csum_offload_none;
u64 stopped;
u64 wake;
u64 dropped;
#define NUM_SQ_STATS 12
};
struct mlx5e_stats {
struct mlx5e_vport_stats vport;
struct mlx5e_pport_stats pport;
struct mlx5e_qcounter_stats qcnt;
};
struct mlx5e_params {
u8 log_sq_size;
u8 rq_wq_type;
......@@ -404,6 +166,7 @@ struct mlx5e_params {
u8 rss_hfunc;
u8 toeplitz_hash_key[40];
u32 indirection_rqt[MLX5E_INDIR_RQT_SIZE];
bool vlan_strip_disable;
#ifdef CONFIG_MLX5_CORE_EN_DCB
struct ieee_ets ets;
#endif
......@@ -813,6 +576,8 @@ int mlx5e_vlan_rx_kill_vid(struct net_device *dev, __always_unused __be16 proto,
void mlx5e_enable_vlan_filter(struct mlx5e_priv *priv);
void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv);
int mlx5e_modify_rqs_vsd(struct mlx5e_priv *priv, bool vsd);
int mlx5e_redirect_rqt(struct mlx5e_priv *priv, enum mlx5e_rqt_ix rqt_ix);
void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv);
......
......@@ -174,8 +174,14 @@ static int mlx5e_dcbnl_ieee_getpfc(struct net_device *dev,
{
struct mlx5e_priv *priv = netdev_priv(dev);
struct mlx5_core_dev *mdev = priv->mdev;
struct mlx5e_pport_stats *pstats = &priv->stats.pport;
int i;
pfc->pfc_cap = mlx5_max_tc(mdev) + 1;
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
pfc->requests[i] = PPORT_PER_PRIO_GET(pstats, i, tx_pause);
pfc->indications[i] = PPORT_PER_PRIO_GET(pstats, i, rx_pause);
}
return mlx5_query_port_pfc(mdev, &pfc->pfc_en, NULL);
}
......
......@@ -165,7 +165,26 @@ static const struct {
},
};
static unsigned long mlx5e_query_pfc_combined(struct mlx5e_priv *priv)
{
struct mlx5_core_dev *mdev = priv->mdev;
u8 pfc_en_tx;
u8 pfc_en_rx;
int err;
err = mlx5_query_port_pfc(mdev, &pfc_en_tx, &pfc_en_rx);
return err ? 0 : pfc_en_tx | pfc_en_rx;
}
#define MLX5E_NUM_Q_CNTRS(priv) (NUM_Q_COUNTERS * (!!priv->q_counter))
#define MLX5E_NUM_RQ_STATS(priv) \
(NUM_RQ_STATS * priv->params.num_channels * \
test_bit(MLX5E_STATE_OPENED, &priv->state))
#define MLX5E_NUM_SQ_STATS(priv) \
(NUM_SQ_STATS * priv->params.num_channels * priv->params.num_tc * \
test_bit(MLX5E_STATE_OPENED, &priv->state))
#define MLX5E_NUM_PFC_COUNTERS(priv) hweight8(mlx5e_query_pfc_combined(priv))
static int mlx5e_get_sset_count(struct net_device *dev, int sset)
{
......@@ -173,21 +192,85 @@ static int mlx5e_get_sset_count(struct net_device *dev, int sset)
switch (sset) {
case ETH_SS_STATS:
return NUM_VPORT_COUNTERS + NUM_PPORT_COUNTERS +
return NUM_SW_COUNTERS +
MLX5E_NUM_Q_CNTRS(priv) +
priv->params.num_channels * NUM_RQ_STATS +
priv->params.num_channels * priv->params.num_tc *
NUM_SQ_STATS;
NUM_VPORT_COUNTERS + NUM_PPORT_COUNTERS +
MLX5E_NUM_RQ_STATS(priv) +
MLX5E_NUM_SQ_STATS(priv) +
MLX5E_NUM_PFC_COUNTERS(priv);
/* fallthrough */
default:
return -EOPNOTSUPP;
}
}
static void mlx5e_fill_stats_strings(struct mlx5e_priv *priv, uint8_t *data)
{
int i, j, tc, prio, idx = 0;
unsigned long pfc_combined;
/* SW counters */
for (i = 0; i < NUM_SW_COUNTERS; i++)
strcpy(data + (idx++) * ETH_GSTRING_LEN, sw_stats_desc[i].name);
/* Q counters */
for (i = 0; i < MLX5E_NUM_Q_CNTRS(priv); i++)
strcpy(data + (idx++) * ETH_GSTRING_LEN, q_stats_desc[i].name);
/* VPORT counters */
for (i = 0; i < NUM_VPORT_COUNTERS; i++)
strcpy(data + (idx++) * ETH_GSTRING_LEN,
vport_stats_desc[i].name);
/* PPORT counters */
for (i = 0; i < NUM_PPORT_802_3_COUNTERS; i++)
strcpy(data + (idx++) * ETH_GSTRING_LEN,
pport_802_3_stats_desc[i].name);
for (i = 0; i < NUM_PPORT_2863_COUNTERS; i++)
strcpy(data + (idx++) * ETH_GSTRING_LEN,
pport_2863_stats_desc[i].name);
for (i = 0; i < NUM_PPORT_2819_COUNTERS; i++)
strcpy(data + (idx++) * ETH_GSTRING_LEN,
pport_2819_stats_desc[i].name);
for (prio = 0; prio < NUM_PPORT_PRIO; prio++) {
for (i = 0; i < NUM_PPORT_PER_PRIO_TRAFFIC_COUNTERS; i++)
sprintf(data + (idx++) * ETH_GSTRING_LEN, "prio%d_%s",
prio,
pport_per_prio_traffic_stats_desc[i].name);
}
pfc_combined = mlx5e_query_pfc_combined(priv);
for_each_set_bit(prio, &pfc_combined, NUM_PPORT_PRIO) {
for (i = 0; i < NUM_PPORT_PER_PRIO_PFC_COUNTERS; i++) {
sprintf(data + (idx++) * ETH_GSTRING_LEN, "prio%d_%s",
prio, pport_per_prio_pfc_stats_desc[i].name);
}
}
if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
return;
/* per channel counters */
for (i = 0; i < priv->params.num_channels; i++)
for (j = 0; j < NUM_RQ_STATS; j++)
sprintf(data + (idx++) * ETH_GSTRING_LEN, "rx%d_%s", i,
rq_stats_desc[j].name);
for (tc = 0; tc < priv->params.num_tc; tc++)
for (i = 0; i < priv->params.num_channels; i++)
for (j = 0; j < NUM_SQ_STATS; j++)
sprintf(data + (idx++) * ETH_GSTRING_LEN,
"tx%d_%s",
priv->channeltc_to_txq_map[i][tc],
sq_stats_desc[j].name);
}
static void mlx5e_get_strings(struct net_device *dev,
uint32_t stringset, uint8_t *data)
{
int i, j, tc, idx = 0;
struct mlx5e_priv *priv = netdev_priv(dev);
switch (stringset) {
......@@ -198,35 +281,7 @@ static void mlx5e_get_strings(struct net_device *dev,
break;
case ETH_SS_STATS:
/* VPORT counters */
for (i = 0; i < NUM_VPORT_COUNTERS; i++)
strcpy(data + (idx++) * ETH_GSTRING_LEN,
vport_strings[i]);
/* Q counters */
for (i = 0; i < MLX5E_NUM_Q_CNTRS(priv); i++)
strcpy(data + (idx++) * ETH_GSTRING_LEN,
qcounter_stats_strings[i]);
/* PPORT counters */
for (i = 0; i < NUM_PPORT_COUNTERS; i++)
strcpy(data + (idx++) * ETH_GSTRING_LEN,
pport_strings[i]);
/* per channel counters */
for (i = 0; i < priv->params.num_channels; i++)
for (j = 0; j < NUM_RQ_STATS; j++)
sprintf(data + (idx++) * ETH_GSTRING_LEN,
"rx%d_%s", i, rq_stats_strings[j]);
for (tc = 0; tc < priv->params.num_tc; tc++)
for (i = 0; i < priv->params.num_channels; i++)
for (j = 0; j < NUM_SQ_STATS; j++)
sprintf(data +
(idx++) * ETH_GSTRING_LEN,
"tx%d_%s",
priv->channeltc_to_txq_map[i][tc],
sq_stats_strings[j]);
mlx5e_fill_stats_strings(priv, data);
break;
}
}
......@@ -235,7 +290,8 @@ static void mlx5e_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data)
{
struct mlx5e_priv *priv = netdev_priv(dev);
int i, j, tc, idx = 0;
int i, j, tc, prio, idx = 0;
unsigned long pfc_combined;
if (!data)
return;
......@@ -245,28 +301,59 @@ static void mlx5e_get_ethtool_stats(struct net_device *dev,
mlx5e_update_stats(priv);
mutex_unlock(&priv->state_lock);
for (i = 0; i < NUM_VPORT_COUNTERS; i++)
data[idx++] = ((u64 *)&priv->stats.vport)[i];
for (i = 0; i < NUM_SW_COUNTERS; i++)
data[idx++] = MLX5E_READ_CTR64_CPU(&priv->stats.sw,
sw_stats_desc, i);
for (i = 0; i < MLX5E_NUM_Q_CNTRS(priv); i++)
data[idx++] = ((u32 *)&priv->stats.qcnt)[i];
data[idx++] = MLX5E_READ_CTR32_CPU(&priv->stats.qcnt,
q_stats_desc, i);
for (i = 0; i < NUM_PPORT_COUNTERS; i++)
data[idx++] = be64_to_cpu(((__be64 *)&priv->stats.pport)[i]);
for (i = 0; i < NUM_VPORT_COUNTERS; i++)
data[idx++] = MLX5E_READ_CTR64_BE(priv->stats.vport.query_vport_out,
vport_stats_desc, i);
for (i = 0; i < NUM_PPORT_802_3_COUNTERS; i++)
data[idx++] = MLX5E_READ_CTR64_BE(&priv->stats.pport.IEEE_802_3_counters,
pport_802_3_stats_desc, i);
for (i = 0; i < NUM_PPORT_2863_COUNTERS; i++)
data[idx++] = MLX5E_READ_CTR64_BE(&priv->stats.pport.RFC_2863_counters,
pport_2863_stats_desc, i);
for (i = 0; i < NUM_PPORT_2819_COUNTERS; i++)
data[idx++] = MLX5E_READ_CTR64_BE(&priv->stats.pport.RFC_2819_counters,
pport_2819_stats_desc, i);
for (prio = 0; prio < NUM_PPORT_PRIO; prio++) {
for (i = 0; i < NUM_PPORT_PER_PRIO_TRAFFIC_COUNTERS; i++)
data[idx++] = MLX5E_READ_CTR64_BE(&priv->stats.pport.per_prio_counters[prio],
pport_per_prio_traffic_stats_desc, i);
}
pfc_combined = mlx5e_query_pfc_combined(priv);
for_each_set_bit(prio, &pfc_combined, NUM_PPORT_PRIO) {
for (i = 0; i < NUM_PPORT_PER_PRIO_PFC_COUNTERS; i++) {
data[idx++] = MLX5E_READ_CTR64_BE(&priv->stats.pport.per_prio_counters[prio],
pport_per_prio_pfc_stats_desc, i);
}
}
if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
return;
/* per channel counters */
for (i = 0; i < priv->params.num_channels; i++)
for (j = 0; j < NUM_RQ_STATS; j++)
data[idx++] = !test_bit(MLX5E_STATE_OPENED,
&priv->state) ? 0 :
((u64 *)&priv->channel[i]->rq.stats)[j];
data[idx++] =
MLX5E_READ_CTR64_CPU(&priv->channel[i]->rq.stats,
rq_stats_desc, j);
for (tc = 0; tc < priv->params.num_tc; tc++)
for (i = 0; i < priv->params.num_channels; i++)
for (j = 0; j < NUM_SQ_STATS; j++)
data[idx++] = !test_bit(MLX5E_STATE_OPENED,
&priv->state) ? 0 :
((u64 *)&priv->channel[i]->sq[tc].stats)[j];
data[idx++] = MLX5E_READ_CTR64_CPU(&priv->channel[i]->sq[tc].stats,
sq_stats_desc, j);
}
static void mlx5e_get_ringparam(struct net_device *dev,
......@@ -1048,6 +1135,108 @@ static int mlx5e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
return mlx5_set_port_wol(mdev, mlx5_wol_mode);
}
static int mlx5e_set_phys_id(struct net_device *dev,
enum ethtool_phys_id_state state)
{
struct mlx5e_priv *priv = netdev_priv(dev);
struct mlx5_core_dev *mdev = priv->mdev;
u16 beacon_duration;
if (!MLX5_CAP_GEN(mdev, beacon_led))
return -EOPNOTSUPP;
switch (state) {
case ETHTOOL_ID_ACTIVE:
beacon_duration = MLX5_BEACON_DURATION_INF;
break;
case ETHTOOL_ID_INACTIVE:
beacon_duration = MLX5_BEACON_DURATION_OFF;
break;
default:
return -EOPNOTSUPP;
}
return mlx5_set_port_beacon(mdev, beacon_duration);
}
static int mlx5e_get_module_info(struct net_device *netdev,
struct ethtool_modinfo *modinfo)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5_core_dev *dev = priv->mdev;
int size_read = 0;
u8 data[4];
size_read = mlx5_query_module_eeprom(dev, 0, 2, data);
if (size_read < 2)
return -EIO;
/* data[0] = identifier byte */
switch (data[0]) {
case MLX5_MODULE_ID_QSFP:
modinfo->type = ETH_MODULE_SFF_8436;
modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
break;
case MLX5_MODULE_ID_QSFP_PLUS:
case MLX5_MODULE_ID_QSFP28:
/* data[1] = revision id */
if (data[0] == MLX5_MODULE_ID_QSFP28 || data[1] >= 0x3) {
modinfo->type = ETH_MODULE_SFF_8636;
modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
} else {
modinfo->type = ETH_MODULE_SFF_8436;
modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
}
break;
case MLX5_MODULE_ID_SFP:
modinfo->type = ETH_MODULE_SFF_8472;
modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
break;
default:
netdev_err(priv->netdev, "%s: cable type not recognized:0x%x\n",
__func__, data[0]);
return -EINVAL;
}
return 0;
}
static int mlx5e_get_module_eeprom(struct net_device *netdev,
struct ethtool_eeprom *ee,
u8 *data)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5_core_dev *mdev = priv->mdev;
int offset = ee->offset;
int size_read;
int i = 0;
if (!ee->len)
return -EINVAL;