Commit 8b792f84 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents eb507906 85005b82
...@@ -860,23 +860,17 @@ static netdev_tx_t mlxsw_sp_port_xmit(struct sk_buff *skb, ...@@ -860,23 +860,17 @@ static netdev_tx_t mlxsw_sp_port_xmit(struct sk_buff *skb,
u64 len; u64 len;
int err; 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)); memset(skb->cb, 0, sizeof(struct mlxsw_skb_cb));
if (mlxsw_core_skb_transmit_busy(mlxsw_sp->core, &tx_info)) if (mlxsw_core_skb_transmit_busy(mlxsw_sp->core, &tx_info))
return NETDEV_TX_BUSY; 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)) { if (eth_skb_pad(skb)) {
this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped); this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
return NETDEV_TX_OK; return NETDEV_TX_OK;
...@@ -1215,6 +1209,9 @@ static void update_stats_cache(struct work_struct *work) ...@@ -1215,6 +1209,9 @@ static void update_stats_cache(struct work_struct *work)
periodic_hw_stats.update_dw.work); periodic_hw_stats.update_dw.work);
if (!netif_carrier_ok(mlxsw_sp_port->dev)) 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; goto out;
mlxsw_sp_port_get_hw_stats(mlxsw_sp_port->dev, 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, ...@@ -4324,6 +4321,15 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port,
return 0; 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, static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg,
char *pude_pl, void *priv) char *pude_pl, void *priv)
{ {
...@@ -4345,6 +4351,7 @@ static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg, ...@@ -4345,6 +4351,7 @@ static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg,
} else { } else {
netdev_info(mlxsw_sp_port->dev, "link down\n"); netdev_info(mlxsw_sp_port->dev, "link down\n");
netif_carrier_off(mlxsw_sp_port->dev); 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, ...@@ -5132,6 +5139,27 @@ static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core,
return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); 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) static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)
{ {
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
...@@ -5634,7 +5662,7 @@ static struct mlxsw_driver mlxsw_sp2_driver = { ...@@ -5634,7 +5662,7 @@ static struct mlxsw_driver mlxsw_sp2_driver = {
static struct mlxsw_driver mlxsw_sp3_driver = { static struct mlxsw_driver mlxsw_sp3_driver = {
.kind = mlxsw_sp3_driver_name, .kind = mlxsw_sp3_driver_name,
.priv_size = sizeof(struct mlxsw_sp), .priv_size = sizeof(struct mlxsw_sp),
.init = mlxsw_sp2_init, .init = mlxsw_sp3_init,
.fini = mlxsw_sp_fini, .fini = mlxsw_sp_fini,
.basic_trap_groups_set = mlxsw_sp_basic_trap_groups_set, .basic_trap_groups_set = mlxsw_sp_basic_trap_groups_set,
.port_split = mlxsw_sp_port_split, .port_split = mlxsw_sp_port_split,
......
...@@ -195,6 +195,20 @@ mlxsw_sp_qdisc_get_xstats(struct mlxsw_sp_port *mlxsw_sp_port, ...@@ -195,6 +195,20 @@ mlxsw_sp_qdisc_get_xstats(struct mlxsw_sp_port *mlxsw_sp_port,
return -EOPNOTSUPP; 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 static void
mlxsw_sp_qdisc_bstats_per_priority_get(struct mlxsw_sp_port_xstats *xstats, mlxsw_sp_qdisc_bstats_per_priority_get(struct mlxsw_sp_port_xstats *xstats,
u8 prio_bitmap, u64 *tx_packets, 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, ...@@ -269,7 +283,7 @@ mlxsw_sp_setup_tc_qdisc_red_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port,
&stats_base->tx_bytes); &stats_base->tx_bytes);
red_base->prob_mark = xstats->ecn; red_base->prob_mark = xstats->ecn;
red_base->prob_drop = xstats->wred_drop[tclass_num]; 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->overlimits = red_base->prob_drop + red_base->prob_mark;
stats_base->drops = red_base->prob_drop + red_base->pdrop; 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, ...@@ -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; early_drops = xstats->wred_drop[tclass_num] - xstats_base->prob_drop;
marks = xstats->ecn - xstats_base->prob_mark; 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->pdrop += pdrops;
res->prob_drop += early_drops; res->prob_drop += early_drops;
...@@ -403,9 +418,10 @@ mlxsw_sp_qdisc_get_red_stats(struct mlxsw_sp_port *mlxsw_sp_port, ...@@ -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 - overlimits = xstats->wred_drop[tclass_num] + xstats->ecn -
stats_base->overlimits; 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; 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); _bstats_update(stats_ptr->bstats, tx_bytes, tx_packets);
stats_ptr->qstats->overlimits += overlimits; stats_ptr->qstats->overlimits += overlimits;
...@@ -576,9 +592,9 @@ mlxsw_sp_qdisc_get_prio_stats(struct mlxsw_sp_port *mlxsw_sp_port, ...@@ -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; tx_packets = stats->tx_packets - stats_base->tx_packets;
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 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]; drops += xstats->wred_drop[i];
backlog += xstats->backlog[i]; backlog += mlxsw_sp_xstats_backlog(xstats, i);
} }
drops = drops - stats_base->drops; drops = drops - stats_base->drops;
...@@ -614,7 +630,7 @@ mlxsw_sp_setup_tc_qdisc_prio_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port, ...@@ -614,7 +630,7 @@ mlxsw_sp_setup_tc_qdisc_prio_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port,
stats_base->drops = 0; stats_base->drops = 0;
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 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]; stats_base->drops += xstats->wred_drop[i];
} }
......
...@@ -299,22 +299,17 @@ static netdev_tx_t mlxsw_sx_port_xmit(struct sk_buff *skb, ...@@ -299,22 +299,17 @@ static netdev_tx_t mlxsw_sx_port_xmit(struct sk_buff *skb,
u64 len; u64 len;
int err; 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)); memset(skb->cb, 0, sizeof(struct mlxsw_skb_cb));
if (mlxsw_core_skb_transmit_busy(mlxsw_sx->core, &tx_info)) if (mlxsw_core_skb_transmit_busy(mlxsw_sx->core, &tx_info))
return NETDEV_TX_BUSY; 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); mlxsw_sx_txhdr_construct(skb, &tx_info);
/* TX header is consumed by HW on the way so we shouldn't count its /* TX header is consumed by HW on the way so we shouldn't count its
* bytes as being sent. * bytes as being sent.
......
...@@ -232,7 +232,7 @@ test_mc_aware() ...@@ -232,7 +232,7 @@ test_mc_aware()
stop_traffic stop_traffic
local ucth1=${uc_rate[1]} 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 d0=$(date +%s)
local t0=$(ethtool_stats_get $h3 rx_octets_prio_0) local t0=$(ethtool_stats_get $h3 rx_octets_prio_0)
...@@ -254,7 +254,11 @@ test_mc_aware() ...@@ -254,7 +254,11 @@ test_mc_aware()
ret = 100 * ($ucth1 - $ucth2) / $ucth1 ret = 100 * ($ucth1 - $ucth2) / $ucth1
if (ret > 0) { ret } else { 0 } 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 interval=$((d1 - d0))
local mc_ir=$(rate $u0 $u1 $interval) local mc_ir=$(rate $u0 $u1 $interval)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment