Merge branch 'mlxsw-Various-fixes'
Ido Schimmel says: ==================== mlxsw: Various fixes This patch set contains various fixes for mlxsw. Patch #1 splits the init() callback between Spectrum-2 and Spectrum-3 in order to avoid enforcing the same firmware version for both ASICs, as this can't possibly work. Without this patch the driver cannot boot with the Spectrum-3 ASIC. Patches #2-#3 fix a long standing race condition that was recently exposed while testing the driver on an emulator, which is very slow compared to the actual hardware. The problem is explained in detail in the commit messages. Patch #4 fixes a selftest. Patch #5 prevents offloaded qdiscs from presenting a non-zero backlog to the user when the netdev is down. This is done by clearing the cached backlog in the driver when the netdev goes down. Patch #6 fixes qdisc statistics (backlog and tail drops) to also take into account the multicast traffic classes. v2: * Patches #2-#3: use skb_cow_head() instead of skb_unshare() as suggested by Jakub. Remove unnecessary check regarding headroom * Patches #5-#6: new ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
8b792f84c6
drivers/net/ethernet/mellanox/mlxsw
tools/testing/selftests/drivers/net/mlxsw
@ -860,23 +860,17 @@ static netdev_tx_t mlxsw_sp_port_xmit(struct sk_buff *skb,
|
||||
u64 len;
|
||||
int err;
|
||||
|
||||
if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) {
|
||||
this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
memset(skb->cb, 0, sizeof(struct mlxsw_skb_cb));
|
||||
|
||||
if (mlxsw_core_skb_transmit_busy(mlxsw_sp->core, &tx_info))
|
||||
return NETDEV_TX_BUSY;
|
||||
|
||||
if (unlikely(skb_headroom(skb) < MLXSW_TXHDR_LEN)) {
|
||||
struct sk_buff *skb_orig = skb;
|
||||
|
||||
skb = skb_realloc_headroom(skb, MLXSW_TXHDR_LEN);
|
||||
if (!skb) {
|
||||
this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
|
||||
dev_kfree_skb_any(skb_orig);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
dev_consume_skb_any(skb_orig);
|
||||
}
|
||||
|
||||
if (eth_skb_pad(skb)) {
|
||||
this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
|
||||
return NETDEV_TX_OK;
|
||||
@ -1215,6 +1209,9 @@ static void update_stats_cache(struct work_struct *work)
|
||||
periodic_hw_stats.update_dw.work);
|
||||
|
||||
if (!netif_carrier_ok(mlxsw_sp_port->dev))
|
||||
/* Note: mlxsw_sp_port_down_wipe_counters() clears the cache as
|
||||
* necessary when port goes down.
|
||||
*/
|
||||
goto out;
|
||||
|
||||
mlxsw_sp_port_get_hw_stats(mlxsw_sp_port->dev,
|
||||
@ -4324,6 +4321,15 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_sp_port_down_wipe_counters(struct mlxsw_sp_port *mlxsw_sp_port)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < TC_MAX_QUEUE; i++)
|
||||
mlxsw_sp_port->periodic_hw_stats.xstats.backlog[i] = 0;
|
||||
}
|
||||
|
||||
static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg,
|
||||
char *pude_pl, void *priv)
|
||||
{
|
||||
@ -4345,6 +4351,7 @@ static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg,
|
||||
} else {
|
||||
netdev_info(mlxsw_sp_port->dev, "link down\n");
|
||||
netif_carrier_off(mlxsw_sp_port->dev);
|
||||
mlxsw_sp_port_down_wipe_counters(mlxsw_sp_port);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5132,6 +5139,27 @@ static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core,
|
||||
return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);
|
||||
}
|
||||
|
||||
static int mlxsw_sp3_init(struct mlxsw_core *mlxsw_core,
|
||||
const struct mlxsw_bus_info *mlxsw_bus_info,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
|
||||
|
||||
mlxsw_sp->kvdl_ops = &mlxsw_sp2_kvdl_ops;
|
||||
mlxsw_sp->afa_ops = &mlxsw_sp2_act_afa_ops;
|
||||
mlxsw_sp->afk_ops = &mlxsw_sp2_afk_ops;
|
||||
mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops;
|
||||
mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops;
|
||||
mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr;
|
||||
mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask;
|
||||
mlxsw_sp->rif_ops_arr = mlxsw_sp2_rif_ops_arr;
|
||||
mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals;
|
||||
mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops;
|
||||
mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops;
|
||||
|
||||
return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);
|
||||
}
|
||||
|
||||
static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)
|
||||
{
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
|
||||
@ -5634,7 +5662,7 @@ static struct mlxsw_driver mlxsw_sp2_driver = {
|
||||
static struct mlxsw_driver mlxsw_sp3_driver = {
|
||||
.kind = mlxsw_sp3_driver_name,
|
||||
.priv_size = sizeof(struct mlxsw_sp),
|
||||
.init = mlxsw_sp2_init,
|
||||
.init = mlxsw_sp3_init,
|
||||
.fini = mlxsw_sp_fini,
|
||||
.basic_trap_groups_set = mlxsw_sp_basic_trap_groups_set,
|
||||
.port_split = mlxsw_sp_port_split,
|
||||
|
@ -195,6 +195,20 @@ mlxsw_sp_qdisc_get_xstats(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static u64
|
||||
mlxsw_sp_xstats_backlog(struct mlxsw_sp_port_xstats *xstats, int tclass_num)
|
||||
{
|
||||
return xstats->backlog[tclass_num] +
|
||||
xstats->backlog[tclass_num + 8];
|
||||
}
|
||||
|
||||
static u64
|
||||
mlxsw_sp_xstats_tail_drop(struct mlxsw_sp_port_xstats *xstats, int tclass_num)
|
||||
{
|
||||
return xstats->tail_drop[tclass_num] +
|
||||
xstats->tail_drop[tclass_num + 8];
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_sp_qdisc_bstats_per_priority_get(struct mlxsw_sp_port_xstats *xstats,
|
||||
u8 prio_bitmap, u64 *tx_packets,
|
||||
@ -269,7 +283,7 @@ mlxsw_sp_setup_tc_qdisc_red_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
&stats_base->tx_bytes);
|
||||
red_base->prob_mark = xstats->ecn;
|
||||
red_base->prob_drop = xstats->wred_drop[tclass_num];
|
||||
red_base->pdrop = xstats->tail_drop[tclass_num];
|
||||
red_base->pdrop = mlxsw_sp_xstats_tail_drop(xstats, tclass_num);
|
||||
|
||||
stats_base->overlimits = red_base->prob_drop + red_base->prob_mark;
|
||||
stats_base->drops = red_base->prob_drop + red_base->pdrop;
|
||||
@ -370,7 +384,8 @@ mlxsw_sp_qdisc_get_red_xstats(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
|
||||
early_drops = xstats->wred_drop[tclass_num] - xstats_base->prob_drop;
|
||||
marks = xstats->ecn - xstats_base->prob_mark;
|
||||
pdrops = xstats->tail_drop[tclass_num] - xstats_base->pdrop;
|
||||
pdrops = mlxsw_sp_xstats_tail_drop(xstats, tclass_num) -
|
||||
xstats_base->pdrop;
|
||||
|
||||
res->pdrop += pdrops;
|
||||
res->prob_drop += early_drops;
|
||||
@ -403,9 +418,10 @@ mlxsw_sp_qdisc_get_red_stats(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
|
||||
overlimits = xstats->wred_drop[tclass_num] + xstats->ecn -
|
||||
stats_base->overlimits;
|
||||
drops = xstats->wred_drop[tclass_num] + xstats->tail_drop[tclass_num] -
|
||||
drops = xstats->wred_drop[tclass_num] +
|
||||
mlxsw_sp_xstats_tail_drop(xstats, tclass_num) -
|
||||
stats_base->drops;
|
||||
backlog = xstats->backlog[tclass_num];
|
||||
backlog = mlxsw_sp_xstats_backlog(xstats, tclass_num);
|
||||
|
||||
_bstats_update(stats_ptr->bstats, tx_bytes, tx_packets);
|
||||
stats_ptr->qstats->overlimits += overlimits;
|
||||
@ -576,9 +592,9 @@ mlxsw_sp_qdisc_get_prio_stats(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
tx_packets = stats->tx_packets - stats_base->tx_packets;
|
||||
|
||||
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
|
||||
drops += xstats->tail_drop[i];
|
||||
drops += mlxsw_sp_xstats_tail_drop(xstats, i);
|
||||
drops += xstats->wred_drop[i];
|
||||
backlog += xstats->backlog[i];
|
||||
backlog += mlxsw_sp_xstats_backlog(xstats, i);
|
||||
}
|
||||
drops = drops - stats_base->drops;
|
||||
|
||||
@ -614,7 +630,7 @@ mlxsw_sp_setup_tc_qdisc_prio_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
|
||||
stats_base->drops = 0;
|
||||
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
|
||||
stats_base->drops += xstats->tail_drop[i];
|
||||
stats_base->drops += mlxsw_sp_xstats_tail_drop(xstats, i);
|
||||
stats_base->drops += xstats->wred_drop[i];
|
||||
}
|
||||
|
||||
|
@ -299,22 +299,17 @@ static netdev_tx_t mlxsw_sx_port_xmit(struct sk_buff *skb,
|
||||
u64 len;
|
||||
int err;
|
||||
|
||||
if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) {
|
||||
this_cpu_inc(mlxsw_sx_port->pcpu_stats->tx_dropped);
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
memset(skb->cb, 0, sizeof(struct mlxsw_skb_cb));
|
||||
|
||||
if (mlxsw_core_skb_transmit_busy(mlxsw_sx->core, &tx_info))
|
||||
return NETDEV_TX_BUSY;
|
||||
|
||||
if (unlikely(skb_headroom(skb) < MLXSW_TXHDR_LEN)) {
|
||||
struct sk_buff *skb_orig = skb;
|
||||
|
||||
skb = skb_realloc_headroom(skb, MLXSW_TXHDR_LEN);
|
||||
if (!skb) {
|
||||
this_cpu_inc(mlxsw_sx_port->pcpu_stats->tx_dropped);
|
||||
dev_kfree_skb_any(skb_orig);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
dev_consume_skb_any(skb_orig);
|
||||
}
|
||||
mlxsw_sx_txhdr_construct(skb, &tx_info);
|
||||
/* TX header is consumed by HW on the way so we shouldn't count its
|
||||
* bytes as being sent.
|
||||
|
@ -232,7 +232,7 @@ test_mc_aware()
|
||||
stop_traffic
|
||||
local ucth1=${uc_rate[1]}
|
||||
|
||||
start_traffic $h1 own bc bc
|
||||
start_traffic $h1 192.0.2.65 bc bc
|
||||
|
||||
local d0=$(date +%s)
|
||||
local t0=$(ethtool_stats_get $h3 rx_octets_prio_0)
|
||||
@ -254,7 +254,11 @@ test_mc_aware()
|
||||
ret = 100 * ($ucth1 - $ucth2) / $ucth1
|
||||
if (ret > 0) { ret } else { 0 }
|
||||
")
|
||||
check_err $(bc <<< "$deg > 25")
|
||||
|
||||
# Minimum shaper of 200Mbps on MC TCs should cause about 20% of
|
||||
# degradation on 1Gbps link.
|
||||
check_err $(bc <<< "$deg < 15") "Minimum shaper not in effect"
|
||||
check_err $(bc <<< "$deg > 25") "MC traffic degrades UC performance too much"
|
||||
|
||||
local interval=$((d1 - d0))
|
||||
local mc_ir=$(rate $u0 $u1 $interval)
|
||||
|
Loading…
x
Reference in New Issue
Block a user