summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-03-12 11:33:35 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-03-12 11:33:35 -0700
commit2c7e63d702f6c4209c5af833308e7fcbc7d4ab17 (patch)
treee46b218ced108b588a1d83364397d57334121efd /drivers
parent281f36d4a9970c206c2c44042904d4e34c092fbe (diff)
parentc38b8f5f791ecce13ab77e2257f8fd2444ba80f6 (diff)
Merge tag 'net-7.0-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Pull networking fixes from Paolo Abeni: "Including fixes from CAN and netfilter. Current release - regressions: - eth: mana: Null service_wq on setup error to prevent double destroy Previous releases - regressions: - nexthop: fix percpu use-after-free in remove_nh_grp_entry - sched: teql: fix NULL pointer dereference in iptunnel_xmit on TEQL slave xmit - bpf: fix nd_tbl NULL dereference when IPv6 is disabled - neighbour: restore protocol != 0 check in pneigh update - tipc: fix divide-by-zero in tipc_sk_filter_connect() - eth: - mlx5: - fix crash when moving to switchdev mode - fix DMA FIFO desync on error CQE SQ recovery - iavf: fix PTP use-after-free during reset - bonding: fix type confusion in bond_setup_by_slave() - lan78xx: fix WARN in __netif_napi_del_locked on disconnect Previous releases - always broken: - core: add xmit recursion limit to tunnel xmit functions - net-shapers: don't free reply skb after genlmsg_reply() - netfilter: - fix stack out-of-bounds read in pipapo_drop() - fix OOB read in nfnl_cthelper_dump_table() - mctp: - fix device leak on probe failure - i2c: fix skb memory leak in receive path - can: keep the max bitrate error at 5% - eth: - bonding: fix nd_tbl NULL dereference when IPv6 is disabled - bnxt_en: fix RSS table size check when changing ethtool channels - amd-xgbe: prevent CRC errors during RX adaptation with AN disabled - octeontx2-af: devlink: fix NIX RAS reporter recovery condition" * tag 'net-7.0-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (71 commits) net: prevent NULL deref in ip[6]tunnel_xmit() octeontx2-af: devlink: fix NIX RAS reporter to use RAS interrupt status octeontx2-af: devlink: fix NIX RAS reporter recovery condition net: ethernet: ti: am65-cpsw-nuss: Fix rx_filter value for PTP support net/mana: Null service_wq on setup error to prevent double destroy selftests: rtnetlink: add neighbour update test neighbour: restore protocol != 0 check in pneigh update net: dsa: realtek: Fix LED group port bit for non-zero LED group tipc: fix divide-by-zero in tipc_sk_filter_connect() net: dsa: microchip: Fix error path in PTP IRQ setup bpf: bpf_out_neigh_v6: Fix nd_tbl NULL dereference when IPv6 is disabled bpf: bpf_out_neigh_v4: Fix nd_tbl NULL dereference when IPv6 is disabled net: bonding: Fix nd_tbl NULL dereference when IPv6 is disabled ipv6: move the disable_ipv6_mod knob to core code net: bcmgenet: fix broken EEE by converting to phylib-managed state net-shapers: don't free reply skb after genlmsg_reply() net: dsa: mxl862xx: don't set user_mii_bus net: ethernet: arc: emac: quiesce interrupts before requesting IRQ page_pool: store detach_time as ktime_t to avoid false-negatives net: macb: Shuffle the tx ring before enabling tx ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/bonding/bond_main.c70
-rw-r--r--drivers/net/caif/caif_serial.c3
-rw-r--r--drivers/net/can/dev/calc_bittiming.c2
-rw-r--r--drivers/net/can/spi/hi311x.c5
-rw-r--r--drivers/net/dsa/microchip/ksz_ptp.c11
-rw-r--r--drivers/net/dsa/mxl862xx/mxl862xx.c1
-rw-r--r--drivers/net/dsa/realtek/rtl8365mb.c3
-rw-r--r--drivers/net/dsa/realtek/rtl8366rb-leds.c6
-rw-r--r--drivers/net/dsa/sja1105/sja1105_main.c7
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-drv.c19
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c82
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe.h4
-rw-r--r--drivers/net/ethernet/arc/emac_main.c11
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c4
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c31
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.h5
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmmii.c10
-rw-r--r--drivers/net/ethernet/cadence/macb_main.c98
-rw-r--r--drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c24
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c14
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf.h3
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_ethtool.c19
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_main.c81
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_virtchnl.c1
-rw-r--r--drivers/net/ethernet/intel/ice/devlink/devlink.c4
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rx.c23
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c45
-rw-r--r--drivers/net/ethernet/microsoft/mana/gdma_main.c1
-rw-r--r--drivers/net/ethernet/spacemit/k1_emac.c19
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-nuss.c16
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-nuss.h2
-rw-r--r--drivers/net/mctp/mctp-i2c.c1
-rw-r--r--drivers/net/mctp/mctp-usb.c3
-rw-r--r--drivers/net/phy/sfp.c8
-rw-r--r--drivers/net/usb/lan78xx.c12
-rw-r--r--drivers/net/usb/lan78xx.h3
-rw-r--r--drivers/net/usb/qmi_wwan.c4
-rw-r--r--drivers/net/usb/usbnet.c7
45 files changed, 449 insertions, 235 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 14ed91391fcc..707419270ebf 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1509,6 +1509,50 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
return features;
}
+static int bond_header_create(struct sk_buff *skb, struct net_device *bond_dev,
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned int len)
+{
+ struct bonding *bond = netdev_priv(bond_dev);
+ const struct header_ops *slave_ops;
+ struct slave *slave;
+ int ret = 0;
+
+ rcu_read_lock();
+ slave = rcu_dereference(bond->curr_active_slave);
+ if (slave) {
+ slave_ops = READ_ONCE(slave->dev->header_ops);
+ if (slave_ops && slave_ops->create)
+ ret = slave_ops->create(skb, slave->dev,
+ type, daddr, saddr, len);
+ }
+ rcu_read_unlock();
+ return ret;
+}
+
+static int bond_header_parse(const struct sk_buff *skb, unsigned char *haddr)
+{
+ struct bonding *bond = netdev_priv(skb->dev);
+ const struct header_ops *slave_ops;
+ struct slave *slave;
+ int ret = 0;
+
+ rcu_read_lock();
+ slave = rcu_dereference(bond->curr_active_slave);
+ if (slave) {
+ slave_ops = READ_ONCE(slave->dev->header_ops);
+ if (slave_ops && slave_ops->parse)
+ ret = slave_ops->parse(skb, haddr);
+ }
+ rcu_read_unlock();
+ return ret;
+}
+
+static const struct header_ops bond_header_ops = {
+ .create = bond_header_create,
+ .parse = bond_header_parse,
+};
+
static void bond_setup_by_slave(struct net_device *bond_dev,
struct net_device *slave_dev)
{
@@ -1516,7 +1560,8 @@ static void bond_setup_by_slave(struct net_device *bond_dev,
dev_close(bond_dev);
- bond_dev->header_ops = slave_dev->header_ops;
+ bond_dev->header_ops = slave_dev->header_ops ?
+ &bond_header_ops : NULL;
bond_dev->type = slave_dev->type;
bond_dev->hard_header_len = slave_dev->hard_header_len;
@@ -2801,8 +2846,14 @@ static void bond_miimon_commit(struct bonding *bond)
continue;
+ case BOND_LINK_FAIL:
+ case BOND_LINK_BACK:
+ slave_dbg(bond->dev, slave->dev, "link_new_state %d on slave\n",
+ slave->link_new_state);
+ continue;
+
default:
- slave_err(bond->dev, slave->dev, "invalid new link %d on slave\n",
+ slave_err(bond->dev, slave->dev, "invalid link_new_state %d on slave\n",
slave->link_new_state);
bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
@@ -3377,7 +3428,7 @@ int bond_rcv_validate(const struct sk_buff *skb, struct bonding *bond,
} else if (is_arp) {
return bond_arp_rcv(skb, bond, slave);
#if IS_ENABLED(CONFIG_IPV6)
- } else if (is_ipv6) {
+ } else if (is_ipv6 && likely(ipv6_mod_enabled())) {
return bond_na_rcv(skb, bond, slave);
#endif
} else {
@@ -5069,13 +5120,18 @@ static void bond_set_slave_arr(struct bonding *bond,
{
struct bond_up_slave *usable, *all;
- usable = rtnl_dereference(bond->usable_slaves);
- rcu_assign_pointer(bond->usable_slaves, usable_slaves);
- kfree_rcu(usable, rcu);
-
all = rtnl_dereference(bond->all_slaves);
rcu_assign_pointer(bond->all_slaves, all_slaves);
kfree_rcu(all, rcu);
+
+ if (BOND_MODE(bond) == BOND_MODE_BROADCAST) {
+ kfree_rcu(usable_slaves, rcu);
+ return;
+ }
+
+ usable = rtnl_dereference(bond->usable_slaves);
+ rcu_assign_pointer(bond->usable_slaves, usable_slaves);
+ kfree_rcu(usable, rcu);
}
static void bond_reset_slave_arr(struct bonding *bond)
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c
index b90890030751..1873d8287bb9 100644
--- a/drivers/net/caif/caif_serial.c
+++ b/drivers/net/caif/caif_serial.c
@@ -297,6 +297,7 @@ static void ser_release(struct work_struct *work)
dev_close(ser->dev);
unregister_netdevice(ser->dev);
debugfs_deinit(ser);
+ tty_kref_put(tty->link);
tty_kref_put(tty);
}
rtnl_unlock();
@@ -331,6 +332,7 @@ static int ldisc_open(struct tty_struct *tty)
ser = netdev_priv(dev);
ser->tty = tty_kref_get(tty);
+ tty_kref_get(tty->link);
ser->dev = dev;
debugfs_init(ser, tty);
tty->receive_room = 4096;
@@ -339,6 +341,7 @@ static int ldisc_open(struct tty_struct *tty)
rtnl_lock();
result = register_netdevice(dev);
if (result) {
+ tty_kref_put(tty->link);
tty_kref_put(tty);
rtnl_unlock();
free_netdev(dev);
diff --git a/drivers/net/can/dev/calc_bittiming.c b/drivers/net/can/dev/calc_bittiming.c
index cc4022241553..42498e9d3f38 100644
--- a/drivers/net/can/dev/calc_bittiming.c
+++ b/drivers/net/can/dev/calc_bittiming.c
@@ -8,7 +8,7 @@
#include <linux/units.h>
#include <linux/can/dev.h>
-#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
+#define CAN_CALC_MAX_ERROR 500 /* max error 5% */
/* CiA recommended sample points for Non Return to Zero encoding. */
static int can_calc_sample_point_nrz(const struct can_bittiming *bt)
diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c
index e00d3dbc4cf4..91b1fa970f8f 100644
--- a/drivers/net/can/spi/hi311x.c
+++ b/drivers/net/can/spi/hi311x.c
@@ -755,7 +755,9 @@ static int hi3110_open(struct net_device *net)
return ret;
mutex_lock(&priv->hi3110_lock);
- hi3110_power_enable(priv->transceiver, 1);
+ ret = hi3110_power_enable(priv->transceiver, 1);
+ if (ret)
+ goto out_close_candev;
priv->force_quit = 0;
priv->tx_skb = NULL;
@@ -790,6 +792,7 @@ static int hi3110_open(struct net_device *net)
hi3110_hw_sleep(spi);
out_close:
hi3110_power_enable(priv->transceiver, 0);
+ out_close_candev:
close_candev(net);
mutex_unlock(&priv->hi3110_lock);
return ret;
diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c
index 4a2cc57a628f..8b98039320ad 100644
--- a/drivers/net/dsa/microchip/ksz_ptp.c
+++ b/drivers/net/dsa/microchip/ksz_ptp.c
@@ -1108,6 +1108,7 @@ static int ksz_ptp_msg_irq_setup(struct ksz_port *port, u8 n)
const struct ksz_dev_ops *ops = port->ksz_dev->dev_ops;
struct ksz_irq *ptpirq = &port->ptpirq;
struct ksz_ptp_irq *ptpmsg_irq;
+ int ret;
ptpmsg_irq = &port->ptpmsg_irq[n];
ptpmsg_irq->num = irq_create_mapping(ptpirq->domain, n);
@@ -1119,9 +1120,13 @@ static int ksz_ptp_msg_irq_setup(struct ksz_port *port, u8 n)
strscpy(ptpmsg_irq->name, name[n]);
- return request_threaded_irq(ptpmsg_irq->num, NULL,
- ksz_ptp_msg_thread_fn, IRQF_ONESHOT,
- ptpmsg_irq->name, ptpmsg_irq);
+ ret = request_threaded_irq(ptpmsg_irq->num, NULL,
+ ksz_ptp_msg_thread_fn, IRQF_ONESHOT,
+ ptpmsg_irq->name, ptpmsg_irq);
+ if (ret)
+ irq_dispose_mapping(ptpmsg_irq->num);
+
+ return ret;
}
int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p)
diff --git a/drivers/net/dsa/mxl862xx/mxl862xx.c b/drivers/net/dsa/mxl862xx/mxl862xx.c
index b1e2094b5816..d7ab04f5afef 100644
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -149,7 +149,6 @@ static int mxl862xx_setup_mdio(struct dsa_switch *ds)
return -ENOMEM;
bus->priv = priv;
- ds->user_mii_bus = bus;
bus->name = KBUILD_MODNAME "-mii";
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(dev));
bus->read_c45 = mxl862xx_phy_read_c45_mii_bus;
diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c
index f938a3f701cc..31fa94dac627 100644
--- a/drivers/net/dsa/realtek/rtl8365mb.c
+++ b/drivers/net/dsa/realtek/rtl8365mb.c
@@ -1480,8 +1480,7 @@ static void rtl8365mb_stats_update(struct realtek_priv *priv, int port)
stats->rx_packets = cnt[RTL8365MB_MIB_ifInUcastPkts] +
cnt[RTL8365MB_MIB_ifInMulticastPkts] +
- cnt[RTL8365MB_MIB_ifInBroadcastPkts] -
- cnt[RTL8365MB_MIB_ifOutDiscards];
+ cnt[RTL8365MB_MIB_ifInBroadcastPkts];
stats->tx_packets = cnt[RTL8365MB_MIB_ifOutUcastPkts] +
cnt[RTL8365MB_MIB_ifOutMulticastPkts] +
diff --git a/drivers/net/dsa/realtek/rtl8366rb-leds.c b/drivers/net/dsa/realtek/rtl8366rb-leds.c
index 99c890681ae6..509ffd3f8db5 100644
--- a/drivers/net/dsa/realtek/rtl8366rb-leds.c
+++ b/drivers/net/dsa/realtek/rtl8366rb-leds.c
@@ -12,11 +12,11 @@ static inline u32 rtl8366rb_led_group_port_mask(u8 led_group, u8 port)
case 0:
return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
case 1:
- return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
+ return FIELD_PREP(RTL8366RB_LED_X_1_CTRL_MASK, BIT(port));
case 2:
- return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
+ return FIELD_PREP(RTL8366RB_LED_2_X_CTRL_MASK, BIT(port));
case 3:
- return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
+ return FIELD_PREP(RTL8366RB_LED_X_3_CTRL_MASK, BIT(port));
default:
return 0;
}
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index 94d17b06da40..c72c2bfdcffb 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -2339,14 +2339,13 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
goto out;
}
+ rc = sja1105_reload_cbs(priv);
+
+out:
dsa_switch_for_each_available_port(dp, ds)
if (dp->pl)
phylink_replay_link_end(dp->pl);
- rc = sja1105_reload_cbs(priv);
- if (rc < 0)
- goto out;
-out:
mutex_unlock(&priv->mgmt_lock);
mutex_unlock(&priv->fdb_lock);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index 8b79d88480db..23beea48ae26 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -1271,20 +1271,25 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
if (ret)
goto err_napi;
+ /* Reset the phy settings */
+ ret = xgbe_phy_reset(pdata);
+ if (ret)
+ goto err_irqs;
+
+ /* Start the phy */
ret = phy_if->phy_start(pdata);
if (ret)
goto err_irqs;
hw_if->enable_tx(pdata);
hw_if->enable_rx(pdata);
+ /* Synchronize flag with hardware state after enabling TX/RX.
+ * This prevents stale state after device restart cycles.
+ */
+ pdata->data_path_stopped = false;
udp_tunnel_nic_reset_ntf(netdev);
- /* Reset the phy settings */
- ret = xgbe_phy_reset(pdata);
- if (ret)
- goto err_txrx;
-
netif_tx_start_all_queues(netdev);
xgbe_start_timers(pdata);
@@ -1294,10 +1299,6 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
return 0;
-err_txrx:
- hw_if->disable_rx(pdata);
- hw_if->disable_tx(pdata);
-
err_irqs:
xgbe_free_irqs(pdata);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
index c63ddb12237e..b8cf6ccfe641 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
@@ -1942,7 +1942,7 @@ static void xgbe_set_rx_adap_mode(struct xgbe_prv_data *pdata,
static void xgbe_rx_adaptation(struct xgbe_prv_data *pdata)
{
struct xgbe_phy_data *phy_data = pdata->phy_data;
- unsigned int reg;
+ int reg;
/* step 2: force PCS to send RX_ADAPT Req to PHY */
XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_EQ_CTRL4,
@@ -1964,11 +1964,20 @@ static void xgbe_rx_adaptation(struct xgbe_prv_data *pdata)
/* Step 4: Check for Block lock */
- /* Link status is latched low, so read once to clear
- * and then read again to get current state
- */
- reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
+ if (reg < 0)
+ goto set_mode;
+
+ /* Link status is latched low so that momentary link drops
+ * can be detected. If link was already down read again
+ * to get the latest state.
+ */
+ if (!pdata->phy.link && !(reg & MDIO_STAT1_LSTATUS)) {
+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
+ if (reg < 0)
+ goto set_mode;
+ }
+
if (reg & MDIO_STAT1_LSTATUS) {
/* If the block lock is found, update the helpers
* and declare the link up
@@ -2008,6 +2017,48 @@ rx_adapt_reinit:
xgbe_rx_adaptation(pdata);
}
+/*
+ * xgbe_phy_stop_data_path - Stop TX/RX to prevent packet corruption
+ * @pdata: driver private data
+ *
+ * This function stops the data path (TX and RX) to prevent packet
+ * corruption during critical PHY operations like RX adaptation.
+ * Must be called before initiating RX adaptation when link goes down.
+ */
+static void xgbe_phy_stop_data_path(struct xgbe_prv_data *pdata)
+{
+ if (pdata->data_path_stopped)
+ return;
+
+ /* Stop TX/RX to prevent packet corruption during RX adaptation */
+ pdata->hw_if.disable_tx(pdata);
+ pdata->hw_if.disable_rx(pdata);
+ pdata->data_path_stopped = true;
+
+ netif_dbg(pdata, link, pdata->netdev,
+ "stopping data path for RX adaptation\n");
+}
+
+/*
+ * xgbe_phy_start_data_path - Re-enable TX/RX after RX adaptation
+ * @pdata: driver private data
+ *
+ * This function re-enables the data path (TX and RX) after RX adaptation
+ * has completed successfully. Only called when link is confirmed up.
+ */
+static void xgbe_phy_start_data_path(struct xgbe_prv_data *pdata)
+{
+ if (!pdata->data_path_stopped)
+ return;
+
+ pdata->hw_if.enable_rx(pdata);
+ pdata->hw_if.enable_tx(pdata);
+ pdata->data_path_stopped = false;
+
+ netif_dbg(pdata, link, pdata->netdev,
+ "restarting data path after RX adaptation\n");
+}
+
static void xgbe_phy_rx_reset(struct xgbe_prv_data *pdata)
{
int reg;
@@ -2801,13 +2852,27 @@ static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart)
if (pdata->en_rx_adap) {
/* if the link is available and adaptation is done,
* declare link up
+ *
+ * Note: When link is up and adaptation is done, we can
+ * safely re-enable the data path if it was stopped
+ * for adaptation.
*/
- if ((reg & MDIO_STAT1_LSTATUS) && pdata->rx_adapt_done)
+ if ((reg & MDIO_STAT1_LSTATUS) && pdata->rx_adapt_done) {
+ xgbe_phy_start_data_path(pdata);
return 1;
+ }
/* If either link is not available or adaptation is not done,
* retrigger the adaptation logic. (if the mode is not set,
* then issue mailbox command first)
*/
+
+ /* CRITICAL: Stop data path BEFORE triggering RX adaptation
+ * to prevent CRC errors from packets corrupted during
+ * the adaptation process. This is especially important
+ * when AN is OFF in 10G KR mode.
+ */
+ xgbe_phy_stop_data_path(pdata);
+
if (pdata->mode_set) {
xgbe_phy_rx_adaptation(pdata);
} else {
@@ -2815,8 +2880,11 @@ static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart)
xgbe_phy_set_mode(pdata, phy_data->cur_mode);
}
- if (pdata->rx_adapt_done)
+ if (pdata->rx_adapt_done) {
+ /* Adaptation complete, safe to re-enable data path */
+ xgbe_phy_start_data_path(pdata);
return 1;
+ }
} else if (reg & MDIO_STAT1_LSTATUS)
return 1;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index e1d7d7150e16..438033a71523 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -1243,6 +1243,10 @@ struct xgbe_prv_data {
bool en_rx_adap;
int rx_adapt_retries;
bool rx_adapt_done;
+ /* Flag to track if data path (TX/RX) was stopped for RX adaptation.
+ * This prevents packet corruption during the adaptation window.
+ */
+ bool data_path_stopped;
bool mode_set;
bool sph;
};
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index 8283aeee35fb..dde4046cbf01 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -934,6 +934,17 @@ int arc_emac_probe(struct net_device *ndev, int interface)
/* Set poll rate so that it polls every 1 ms */
arc_reg_set(priv, R_POLLRATE, clock_frequency / 1000000);
+ /*
+ * Put the device into a known quiescent state before requesting
+ * the IRQ. Clear only EMAC interrupt status bits here; leave the
+ * MDIO completion bit alone and avoid writing TXPL_MASK, which is
+ * used to force TX polling rather than acknowledge interrupts.
+ */
+ arc_reg_set(priv, R_ENABLE, 0);
+ arc_reg_set(priv, R_STATUS, RXINT_MASK | TXINT_MASK | ERR_MASK |
+ TXCH_MASK | MSER_MASK | RXCR_MASK |
+ RXFR_MASK | RXFL_MASK);
+
ndev->irq = irq;
dev_info(dev, "IRQ is %d\n", ndev->irq);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index ba47e8294fff..28d0ece2e7b1 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -979,8 +979,8 @@ static int bnxt_set_channels(struct net_device *dev,
if (bnxt_get_nr_rss_ctxs(bp, req_rx_rings) !=
bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings) &&
- netif_is_rxfh_configured(dev)) {
- netdev_warn(dev, "RSS table size change required, RSS table entries must be default to proceed\n");
+ (netif_is_rxfh_configured(dev) || bp->num_rss_ctx)) {
+ netdev_warn(dev, "RSS table size change required, RSS table entries must be default (with no additional RSS contexts present) to proceed\n");
return -EINVAL;
}
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index a71cd729fde6..482a31e7b72b 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1342,8 +1342,7 @@ static void bcmgenet_get_ethtool_stats(struct net_device *dev,
}
}
-void bcmgenet_eee_enable_set(struct net_device *dev, bool enable,
- bool tx_lpi_enabled)
+void bcmgenet_eee_enable_set(struct net_device *dev, bool enable)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
u32 off = priv->hw_params->tbuf_offset + TBUF_ENERGY_CTRL;
@@ -1363,7 +1362,7 @@ void bcmgenet_eee_enable_set(struct net_device *dev, bool enable,
/* Enable EEE and switch to a 27Mhz clock automatically */
reg = bcmgenet_readl(priv->base + off);
- if (tx_lpi_enabled)
+ if (enable)
reg |= TBUF_EEE_EN | TBUF_PM_EN;
else
reg &= ~(TBUF_EEE_EN | TBUF_PM_EN);
@@ -1382,14 +1381,12 @@ void bcmgenet_eee_enable_set(struct net_device *dev, bool enable,
priv->clk_eee_enabled = false;
}
- priv->eee.eee_enabled = enable;
- priv->eee.tx_lpi_enabled = tx_lpi_enabled;
}
static int bcmgenet_get_eee(struct net_device *dev, struct ethtool_keee *e)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
- struct ethtool_keee *p = &priv->eee;
+ int ret;
if (GENET_IS_V1(priv))
return -EOPNOTSUPP;
@@ -1397,17 +1394,21 @@ static int bcmgenet_get_eee(struct net_device *dev, struct ethtool_keee *e)
if (!dev->phydev)
return -ENODEV;
- e->tx_lpi_enabled = p->tx_lpi_enabled;
+ ret = phy_ethtool_get_eee(dev->phydev, e);
+ if (ret)
+ return ret;
+
+ /* tx_lpi_timer is maintained by the MAC hardware register; the
+ * PHY-level eee_cfg timer is not set for GENET.
+ */
e->tx_lpi_timer = bcmgenet_umac_readl(priv, UMAC_EEE_LPI_TIMER);
- return phy_ethtool_get_eee(dev->phydev, e);
+ return 0;
}
static int bcmgenet_set_eee(struct net_device *dev, struct ethtool_keee *e)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
- struct ethtool_keee *p = &priv->eee;
- bool active;
if (GENET_IS_V1(priv))
return -EOPNOTSUPP;
@@ -1415,15 +1416,7 @@ static int bcmgenet_set_eee(struct net_device *dev, struct ethtool_keee *e)
if (!dev->phydev)
return -ENODEV;
- p->eee_enabled = e->eee_enabled;
-
- if (!p->eee_enabled) {
- bcmgenet_eee_enable_set(dev, false, false);
- } else {
- active = phy_init_eee(dev->phydev, false) >= 0;
- bcmgenet_umac_writel(priv, e->tx_lpi_timer, UMAC_EEE_LPI_TIMER);
- bcmgenet_eee_enable_set(dev, active, e->tx_lpi_enabled);
- }
+ bcmgenet_umac_writel(priv, e->tx_lpi_timer, UMAC_EEE_LPI_TIMER);
return phy_ethtool_set_eee(dev->phydev, e);
}
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index 5ec3979779ec..9e4110c7fdf6 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -665,8 +665,6 @@ struct bcmgenet_priv {
u8 sopass[SOPASS_MAX];
struct bcmgenet_mib_counters mib;
-
- struct ethtool_keee eee;
};
static inline bool bcmgenet_has_40bits(struct bcmgenet_priv *priv)
@@ -749,7 +747,6 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
int bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
enum bcmgenet_power_mode mode);
-void bcmgenet_eee_enable_set(struct net_device *dev, bool enable,
- bool tx_lpi_enabled);
+void bcmgenet_eee_enable_set(struct net_device *dev, bool enable);
#endif /* __BCMGENET_H__ */
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
index 38f854b94a79..a4e0d5a68268 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -29,7 +29,6 @@ static void bcmgenet_mac_config(struct net_device *dev)
struct bcmgenet_priv *priv = netdev_priv(dev);
struct phy_device *phydev = dev->phydev;
u32 reg, cmd_bits = 0;
- bool active;
/* speed */
if (phydev->speed == SPEED_1000)
@@ -90,10 +89,6 @@ static void bcmgenet_mac_config(struct net_device *dev)
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
spin_unlock_bh(&priv->reg_lock);
- active = phy_init_eee(phydev, 0) >= 0;
- bcmgenet_eee_enable_set(dev,
- priv->eee.eee_enabled && active,
- priv->eee.tx_lpi_enabled);
}
/* setup netdev link state when PHY link status change and
@@ -113,6 +108,8 @@ void bcmgenet_mii_setup(struct net_device *dev)
bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
}
+ bcmgenet_eee_enable_set(dev, phydev->enable_tx_lpi);
+
phy_print_status(phydev);
}
@@ -412,6 +409,9 @@ int bcmgenet_mii_probe(struct net_device *dev)
/* Indicate that the MAC is responsible for PHY PM */
dev->phydev->mac_managed_pm = true;
+ if (!GENET_IS_V1(priv))
+ phy_support_eee(dev->phydev);
+
return 0;
}
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index 5bc35f651ebd..f290d608b409 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -36,6 +36,7 @@
#include <linux/tcp.h>
#include <linux/types.h>
#include <linux/udp.h>
+#include <linux/gcd.h>
#include <net/pkt_sched.h>
#include "macb.h"
@@ -668,6 +669,97 @@ static void macb_mac_link_down(struct phylink_config *config, unsigned int mode,
netif_tx_stop_all_queues(ndev);
}
+/* Use juggling algorithm to left rotate tx ring and tx skb array */
+static void gem_shuffle_tx_one_ring(struct macb_queue *queue)
+{
+ unsigned int head, tail, count, ring_size, desc_size;
+ struct macb_tx_skb tx_skb, *skb_curr, *skb_next;
+ struct macb_dma_desc *desc_curr, *desc_next;
+ unsigned int i, cycles, shift, curr, next;
+ struct macb *bp = queue->bp;
+ unsigned char desc[24];
+ unsigned long flags;
+
+ desc_size = macb_dma_desc_get_size(bp);
+
+ if (WARN_ON_ONCE(desc_size > ARRAY_SIZE(desc)))
+ return;
+
+ spin_lock_irqsave(&queue->tx_ptr_lock, flags);
+ head = queue->tx_head;
+ tail = queue->tx_tail;
+ ring_size = bp->tx_ring_size;
+ count = CIRC_CNT(head, tail, ring_size);
+
+ if (!(tail % ring_size))
+ goto unlock;
+
+ if (!count) {
+ queue->tx_head = 0;
+ queue->tx_tail = 0;
+ goto unlock;
+ }
+
+ shift = tail % ring_size;
+ cycles = gcd(ring_size, shift);
+
+ for (i = 0; i < cycles; i++) {
+ memcpy(&desc, macb_tx_desc(queue, i), desc_size);
+ memcpy(&tx_skb, macb_tx_skb(queue, i),
+ sizeof(struct macb_tx_skb));
+
+ curr = i;
+ next = (curr + shift) % ring_size;
+
+ while (next != i) {
+ desc_curr = macb_tx_desc(queue, curr);
+ desc_next = macb_tx_desc(queue, next);
+
+ memcpy(desc_curr, desc_next, desc_size);
+
+ if (next == ring_size - 1)
+ desc_curr->ctrl &= ~MACB_BIT(TX_WRAP);
+ if (curr == ring_size - 1)
+ desc_curr->ctrl |= MACB_BIT(TX_WRAP);
+
+ skb_curr = macb_tx_skb(queue, curr);
+ skb_next = macb_tx_skb(queue, next);
+ memcpy(skb_curr, skb_next, sizeof(struct macb_tx_skb));
+
+ curr = next;
+ next = (curr + shift) % ring_size;
+ }
+
+ desc_curr = macb_tx_desc(queue, curr);
+ memcpy(desc_curr, &desc, desc_size);
+ if (i == ring_size - 1)
+ desc_curr->ctrl &= ~MACB_BIT(TX_WRAP);
+ if (curr == ring_size - 1)
+ desc_curr->ctrl |= MACB_BIT(TX_WRAP);
+ memcpy(macb_tx_skb(queue, curr), &tx_skb,
+ sizeof(struct macb_tx_skb));
+ }
+
+ queue->tx_head = count;
+ queue->tx_tail = 0;
+
+ /* Make descriptor updates visible to hardware */
+ wmb();
+
+unlock:
+ spin_unlock_irqrestore(&queue->tx_ptr_lock, flags);
+}
+
+/* Rotate the queue so that the tail is at index 0 */
+static void gem_shuffle_tx_rings(struct macb *bp)
+{
+ struct macb_queue *queue;
+ int q;
+
+ for (q = 0, queue = bp->queues; q < bp->num_queues; q++, queue++)
+ gem_shuffle_tx_one_ring(queue);
+}
+
static void macb_mac_link_up(struct phylink_config *config,
struct phy_device *phy,
unsigned int mode, phy_interface_t interface,
@@ -706,8 +798,6 @@ static void macb_mac_link_up(struct phylink_config *config,
ctrl |= MACB_BIT(PAE);
for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
- queue->tx_head = 0;
- queue->tx_tail = 0;
queue_writel(queue, IER,
bp->rx_intr_mask | MACB_TX_INT_FLAGS | MACB_BIT(HRESP));
}
@@ -721,8 +811,10 @@ static void macb_mac_link_up(struct phylink_config *config,
spin_unlock_irqrestore(&bp->lock, flags);
- if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC))
+ if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC)) {
macb_set_tx_clk(bp, speed);
+ gem_shuffle_tx_rings(bp);
+ }
/* Enable Rx and Tx; Enable PTP unicast */
ctrl = macb_readl(bp, NCR);
diff --git a/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c b/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c
index 7fd39f895290..92a0f824dae7 100644
--- a/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c
+++ b/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c
@@ -333,11 +333,13 @@ static int netc_get_phy_addr(struct device_node *np)
mdio_node = of_get_child_by_name(np, "mdio");
if (!mdio_node)
- return 0;
+ return -ENODEV;
phy_node = of_get_next_child(mdio_node, NULL);
- if (!phy_node)
+ if (!phy_node) {
+ err = -ENODEV;
goto of_put_mdio_node;
+ }
err = of_property_read_u32(phy_node, "reg", &addr);
if (err)
@@ -423,6 +425,9 @@ static int imx95_enetc_mdio_phyaddr_config(struct platform_device *pdev)
addr = netc_get_phy_addr(gchild);
if (addr < 0) {
+ if (addr == -ENODEV)
+ continue;
+
dev_err(dev, "Failed to get PHY address\n");
return addr;
}
@@ -433,12 +438,6 @@ static int imx95_enetc_mdio_phyaddr_config(struct platform_device *pdev)
return -EINVAL;
}
- /* The default value of LaBCR[MDIO_PHYAD_PRTAD ] is
- * 0, so no need to set the register.
- */
- if (!addr)
- continue;
-
switch (bus_devfn) {
case IMX95_ENETC0_BUS_DEVFN:
netc_reg_write(priv->ierb, IERB_LBCR(0),
@@ -578,16 +577,13 @@ static int imx94_enetc_mdio_phyaddr_config(struct netc_blk_ctrl *priv,
addr = netc_get_phy_addr(np);
if (addr < 0) {
+ if (addr == -ENODEV)
+ return 0;
+
dev_err(dev, "Failed to get PHY address\n");
return addr;
}
- /* The default value of LaBCR[MDIO_PHYAD_PRTAD] is 0,
- * so no need to set the register.
- */
- if (!addr)
- return 0;
-
if (phy_mask & BIT(addr)) {
dev_err(dev,
"Find same PHY address in EMDIO and ENETC node\n");
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 3d7648a119e5..9b09eb144b81 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -2952,8 +2952,6 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
dma_error:
dev_err(&pdev->dev, "TX DMA map failed\n");
buffer_info->dma = 0;
- if (count)
- count--;
while (count--) {
if (i == 0)
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 35dab1e3132f..9befdacd6730 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -5652,8 +5652,6 @@ static int e1000_tx_map(struct e1000_ring *tx_ring, struct sk_buff *skb,
dma_error:
dev_err(&pdev->dev, "Tx DMA map failed\n");
buffer_info->dma = 0;
- if (count)
- count--;
while (count--) {
if (i == 0)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index fdf40f8fb239..a26c3d47ec15 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -3833,10 +3833,10 @@ static int i40e_vc_del_cloud_filter(struct i40e_vf *vf, u8 *msg)
cfilter.n_proto = ETH_P_IP;
if (mask.dst_ip[0] & tcf.dst_ip[0])
memcpy(&cfilter.ip.v4.dst_ip, tcf.dst_ip,
- ARRAY_SIZE(tcf.dst_ip));
- else if (mask.src_ip[0] & tcf.dst_ip[0])
+ sizeof(cfilter.ip.v4.dst_ip));
+ else if (mask.src_ip[0] & tcf.src_ip[0])
memcpy(&cfilter.ip.v4.src_ip, tcf.src_ip,
- ARRAY_SIZE(tcf.dst_ip));
+ sizeof(cfilter.ip.v4.src_ip));
break;
case VIRTCHNL_TCP_V6_FLOW:
cfilter.n_proto = ETH_P_IPV6;
@@ -3891,7 +3891,7 @@ static int i40e_vc_del_cloud_filter(struct i40e_vf *vf, u8 *msg)
/* for ipv6, mask is set for all sixteen bytes (4 words) */
if (cfilter.n_proto == ETH_P_IPV6 && mask.dst_ip[3])
if (memcmp(&cfilter.ip.v6.dst_ip6, &cf->ip.v6.dst_ip6,
- sizeof(cfilter.ip.v6.src_ip6)))
+ sizeof(cfilter.ip.v6.dst_ip6)))
continue;
if (mask.vlan_id)
if (cfilter.vlan_id != cf->vlan_id)
@@ -3979,10 +3979,10 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf *vf, u8 *msg)
cfilter->n_proto = ETH_P_IP;
if (mask.dst_ip[0] & tcf.dst_ip[0])
memcpy(&cfilter->ip.v4.dst_ip, tcf.dst_ip,
- ARRAY_SIZE(tcf.dst_ip));
- else if (mask.src_ip[0] & tcf.dst_ip[0])
+ sizeof(cfilter->ip.v4.dst_ip));
+ else if (mask.src_ip[0] & tcf.src_ip[0])
memcpy(&cfilter->ip.v4.src_ip, tcf.src_ip,
- ARRAY_SIZE(tcf.dst_ip));
+ sizeof(cfilter->ip.v4.src_ip));
break;
case VIRTCHNL_TCP_V6_FLOW:
cfilter->n_proto = ETH_P_IPV6;
diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
index a87e0c6d4017..e9fb0a0919e3 100644
--- a/drivers/net/ethernet/intel/iavf/iavf.h
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -260,7 +260,6 @@ struct iavf_adapter {
struct work_struct adminq_task;
struct work_struct finish_config;
wait_queue_head_t down_waitqueue;
- wait_queue_head_t reset_waitqueue;
wait_queue_head_t vc_waitqueue;
struct iavf_q_vector *q_vectors;
struct list_head vlan_filter_list;
@@ -626,5 +625,5 @@ void iavf_add_adv_rss_cfg(struct iavf_adapter *adapter);
void iavf_del_adv_rss_cfg(struct iavf_adapter *adapter);
struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
const u8 *macaddr);
-int iavf_wait_for_reset(struct iavf_adapter *adapter);
+void iavf_reset_step(struct iavf_adapter *adapter);
#endif /* _IAVF_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
index f3a1b2fb9bf8..ab67c709d5a0 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
@@ -492,7 +492,6 @@ static int iavf_set_ringparam(struct net_device *netdev,
{
struct iavf_adapter *adapter = netdev_priv(netdev);
u32 new_rx_count, new_tx_count;
- int ret = 0;
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
return -EINVAL;
@@ -537,13 +536,11 @@ static int iavf_set_ringparam(struct net_device *netdev,
}
if (netif_running(netdev)) {
- iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
- ret = iavf_wait_for_reset(adapter);
- if (ret)
- netdev_warn(netdev, "Changing ring parameters timeout or interrupted waiting for reset");
+ adapter->flags |= IAVF_FLAG_RESET_NEEDED;
+ iavf_reset_step(adapter);
}
- return ret;
+ return 0;
}
/**
@@ -1723,7 +1720,6 @@ static int iavf_set_channels(struct net_device *netdev,
{
struct iavf_adapter *adapter = netdev_priv(netdev);
u32 num_req = ch->combined_count;
- int ret = 0;
if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) &&
adapter->num_tc) {
@@ -1745,13 +1741,10 @@ static int iavf_set_channels(struct net_device *netdev,
adapter->num_req_queues = num_req;
adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
- iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
+ adapter->flags |= IAVF_FLAG_RESET_NEEDED;
+ iavf_reset_step(adapter);
- ret = iavf_wait_for_reset(adapter);
- if (ret)
- netdev_warn(netdev, "Changing channel count timeout or interrupted waiting for reset");
-
- return ret;
+ return 0;
}
/**
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index 86c1964f42e1..7925ee152c76 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -186,31 +186,6 @@ static bool iavf_is_reset_in_progress(struct iavf_adapter *adapter)
}
/**
- * iavf_wait_for_reset - Wait for reset to finish.
- * @adapter: board private structure
- *
- * Returns 0 if reset finished successfully, negative on timeout or interrupt.
- */
-int iavf_wait_for_reset(struct iavf_adapter *adapter)
-{
- int ret = wait_event_interruptible_timeout(adapter->reset_waitqueue,
- !iavf_is_reset_in_progress(adapter),
- msecs_to_jiffies(5000));
-
- /* If ret < 0 then it means wait was interrupted.
- * If ret == 0 then it means we got a timeout while waiting
- * for reset to finish.
- * If ret > 0 it means reset has finished.
- */
- if (ret > 0)
- return 0;
- else if (ret < 0)
- return -EINTR;
- else
- return -EBUSY;
-}
-
-/**
* iavf_allocate_dma_mem_d - OS specific memory alloc for shared code
* @hw: pointer to the HW structure
* @mem: ptr to mem struct to fill out
@@ -3036,6 +3011,8 @@ static void iavf_disable_vf(struct iavf_adapter *adapter)
adapter->flags |= IAVF_FLAG_PF_COMMS_FAILED;
+ iavf_ptp_release(adapter);
+
/* We don't use netif_running() because it may be true prior to
* ndo_open() returning, so we can't assume it means all our open
* tasks have finished, since we're not holding the rtnl_lock here.
@@ -3111,18 +3088,16 @@ static void iavf_reconfig_qs_bw(struct iavf_adapter *adapter)
}
/**
- * iavf_reset_task - Call-back task to handle hardware reset
- * @work: pointer to work_struct
+ * iavf_reset_step - Perform the VF reset sequence
+ * @adapter: board private structure
*
- * During reset we need to shut down and reinitialize the admin queue
- * before we can use it to communicate with the PF again. We also clear
- * and reinit the rings because that context is lost as well.
- **/
-static void iavf_reset_task(struct work_struct *work)
+ * Requests a reset from PF, polls for completion, and reconfigures
+ * the driver. Caller must hold the netdev instance lock.
+ *
+ * This can sleep for several seconds while polling HW registers.
+ */
+void iavf_reset_step(struct iavf_adapter *adapter)
{
- struct iavf_adapter *adapter = container_of(work,
- struct iavf_adapter,
- reset_task);
struct virtchnl_vf_resource *vfres = adapter->vf_res;
struct net_device *netdev = adapter->netdev;
struct iavf_hw *hw = &adapter->hw;
@@ -3133,7 +3108,7 @@ static void iavf_reset_task(struct work_struct *work)
int i = 0, err;
bool running;
- netdev_lock(netdev);
+ netdev_assert_locked(netdev);
iavf_misc_irq_disable(adapter);
if (adapter->flags & IAVF_FLAG_RESET_NEEDED) {
@@ -3178,7 +3153,6 @@ static void iavf_reset_task(struct work_struct *work)
dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n",
reg_val);
iavf_disable_vf(adapter);
- netdev_unlock(netdev);
return; /* Do not attempt to reinit. It's dead, Jim. */
}
@@ -3190,7 +3164,6 @@ continue_reset:
iavf_startup(adapter);
queue_delayed_work(adapter->wq, &adapter->watchdog_task,
msecs_to_jiffies(30));
- netdev_unlock(netdev);
return;
}
@@ -3211,6 +3184,8 @@ continue_reset:
iavf_change_state(adapter, __IAVF_RESETTING);
adapter->flags &= ~IAVF_FLAG_RESET_PENDING;
+ iavf_ptp_release(adapter);
+
/* free the Tx/Rx rings and descriptors, might be better to just
* re-use them sometime in the future
*/
@@ -3331,9 +3306,6 @@ continue_reset:
adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
- wake_up(&adapter->reset_waitqueue);
- netdev_unlock(netdev);
-
return;
reset_err:
if (running) {
@@ -3342,10 +3314,21 @@ reset_err:
}
iavf_disable_vf(adapter);
- netdev_unlock(netdev);
dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n");
}
+static void iavf_reset_task(struct work_struct *work)
+{
+ struct iavf_adapter *adapter = container_of(work,
+ struct iavf_adapter,
+ reset_task);
+ struct net_device *netdev = adapter->netdev;
+
+ netdev_lock(netdev);
+ iavf_reset_step(adapter);
+ netdev_unlock(netdev);
+}
+
/**
* iavf_adminq_task - worker thread to clean the admin queue
* @work: pointer to work_struct containing our data
@@ -4611,22 +4594,17 @@ static int iavf_close(struct net_device *netdev)
static int iavf_change_mtu(struct net_device *netdev, int new_mtu)
{
struct iavf_adapter *adapter = netdev_priv(netdev);
- int ret = 0;
netdev_dbg(netdev, "changing MTU from %d to %d\n",
netdev->mtu, new_mtu);
WRITE_ONCE(netdev->mtu, new_mtu);
if (netif_running(netdev)) {
- iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
- ret = iavf_wait_for_reset(adapter);
- if (ret < 0)
- netdev_warn(netdev, "MTU change interrupted waiting for reset");
- else if (ret)
- netdev_warn(netdev, "MTU change timed out waiting for reset");
+ adapter->flags |= IAVF_FLAG_RESET_NEEDED;
+ iavf_reset_step(adapter);
}
- return ret;
+ return 0;
}
/**
@@ -5431,9 +5409,6 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Setup the wait queue for indicating transition to down status */
init_waitqueue_head(&adapter->down_waitqueue);
- /* Setup the wait queue for indicating transition to running state */
- init_waitqueue_head(&adapter->reset_waitqueue);
-
/* Setup the wait queue for indicating virtchannel events */
init_waitqueue_head(&adapter->vc_waitqueue);
diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index 88156082a41d..a52c100dcbc5 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -2736,7 +2736,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
case VIRTCHNL_OP_ENABLE_QUEUES:
/* enable transmits */
iavf_irq_enable(adapter, true);
- wake_up(&adapter->reset_waitqueue);
adapter->flags &= ~IAVF_FLAG_QUEUES_DISABLED;
break;
case VIRTCHNL_OP_DISABLE_QUEUES:
diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink.c b/drivers/net/ethernet/intel/ice/devlink/devlink.c
index 6c72bd15db6d..6144cee8034d 100644
--- a/drivers/net/ethernet/intel/ice/devlink/devlink.c
+++ b/drivers/net/ethernet/intel/ice/devlink/devlink.c
@@ -1360,7 +1360,7 @@ ice_devlink_enable_roce_get(struct devlink *devlink, u32 id,
cdev = pf->cdev_info;
if (!cdev)
- return -ENODEV;
+ return -EOPNOTSUPP;
ctx->val.vbool = !!(cdev->rdma_protocol & IIDC_RDMA_PROTOCOL_ROCEV2);
@@ -1427,7 +1427,7 @@ ice_devlink_enable_iw_get(struct devlink *devlink, u32 id,
cdev = pf->cdev_info;
if (!cdev)
- return -ENODEV;
+ return -EOPNOTSUPP;
ctx->val.vbool = !!(cdev->rdma_protocol & IIDC_RDMA_PROTOCOL_IWARP);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
index fb15c794efc9..a29f1ea04c7d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
@@ -327,10 +327,10 @@ static int rvu_nix_report_show(struct devlink_fmsg *fmsg, void *ctx,
rvu_report_pair_end(fmsg);
break;
case NIX_AF_RVU_RAS:
- intr_val = nix_event_context->nix_af_rvu_err;
+ intr_val = nix_event_context->nix_af_rvu_ras;
rvu_report_pair_start(fmsg, "NIX_AF_RAS");
devlink_fmsg_u64_pair_put(fmsg, "\tNIX RAS Interrupt Reg ",
- nix_event_context->nix_af_rvu_err);
+ nix_event_context->nix_af_rvu_ras);
devlink_fmsg_string_put(fmsg, "\n\tPoison Data on:");
if (intr_val & BIT_ULL(34))
devlink_fmsg_string_put(fmsg, "\n\tNIX_AQ_INST_S");
@@ -475,7 +475,7 @@ static int rvu_hw_nix_ras_recover(struct devlink_health_reporter *reporter,
if (blkaddr < 0)
return blkaddr;
- if (nix_event_ctx->nix_af_rvu_int)
+ if (nix_event_ctx->nix_af_rvu_ras)
rvu_write64(rvu, blkaddr, NIX_AF_RAS_ENA_W1S, ~0ULL);
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
index 60ba840e00fa..afdeb1b3d425 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
@@ -47,7 +47,6 @@ static void mlx5e_reset_txqsq_cc_pc(struct mlx5e_txqsq *sq)
"SQ 0x%x: cc (0x%x) != pc (0x%x)\n",
sq->sqn, sq->cc, sq->pc);
sq->cc = 0;
- sq->dma_fifo_cc = 0;
sq->pc = 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
index 197a1c6930c0..329608c59313 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
@@ -2912,7 +2912,7 @@ void mlx5e_ipsec_disable_events(struct mlx5e_priv *priv)
goto out;
peer_priv = mlx5_devcom_get_next_peer_data(priv->devcom, &tmp);
- if (peer_priv)
+ if (peer_priv && peer_priv->ipsec)
complete_all(&peer_priv->ipsec->comp);
mlx5_devcom_for_each_peer_end(priv->devcom);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index efcfcddab376..268e20884757 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -1589,6 +1589,7 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi
struct skb_shared_info *sinfo;
u32 frag_consumed_bytes;
struct bpf_prog *prog;
+ u8 nr_frags_free = 0;
struct sk_buff *skb;
dma_addr_t addr;
u32 truesize;
@@ -1631,15 +1632,13 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi
prog = rcu_dereference(rq->xdp_prog);
if (prog) {
- u8 nr_frags_free, old_nr_frags = sinfo->nr_frags;
+ u8 old_nr_frags = sinfo->nr_frags;
if (mlx5e_xdp_handle(rq, prog, mxbuf)) {
if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT,
rq->flags)) {
struct mlx5e_wqe_frag_info *pwi;
- wi -= old_nr_frags - sinfo->nr_frags;
-
for (pwi = head_wi; pwi < wi; pwi++)
pwi->frag_page->frags++;
}
@@ -1647,10 +1646,8 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi
}
nr_frags_free = old_nr_frags - sinfo->nr_frags;
- if (unlikely(nr_frags_free)) {
- wi -= nr_frags_free;
+ if (unlikely(nr_frags_free))
truesize -= nr_frags_free * frag_info->frag_stride;
- }
}
skb = mlx5e_build_linear_skb(
@@ -1666,7 +1663,7 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi
if (xdp_buff_has_frags(&mxbuf->xdp)) {
/* sinfo->nr_frags is reset by build_skb, calculate again. */
- xdp_update_skb_frags_info(skb, wi - head_wi - 1,
+ xdp_update_skb_frags_info(skb, wi - head_wi - nr_frags_free - 1,
sinfo->xdp_frags_size, truesize,
xdp_buff_get_skb_flags(&mxbuf->xdp));
@@ -1957,14 +1954,13 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w
if (prog) {
u8 nr_frags_free, old_nr_frags = sinfo->nr_frags;
+ u8 new_nr_frags;
u32 len;
if (mlx5e_xdp_handle(rq, prog, mxbuf)) {
if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) {
struct mlx5e_frag_page *pfp;
- frag_page -= old_nr_frags - sinfo->nr_frags;
-
for (pfp = head_page; pfp < frag_page; pfp++)
pfp->frags++;
@@ -1975,13 +1971,12 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w
return NULL; /* page/packet was consumed by XDP */
}
- nr_frags_free = old_nr_frags - sinfo->nr_frags;
- if (unlikely(nr_frags_free)) {
- frag_page -= nr_frags_free;
+ new_nr_frags = sinfo->nr_frags;
+ nr_frags_free = old_nr_frags - new_nr_frags;
+ if (unlikely(nr_frags_free))
truesize -= (nr_frags_free - 1) * PAGE_SIZE +
ALIGN(pg_consumed_bytes,
BIT(rq->mpwqe.log_stride_sz));
- }
len = mxbuf->xdp.data_end - mxbuf->xdp.data;
@@ -2003,7 +1998,7 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w
struct mlx5e_frag_page *pagep;
/* sinfo->nr_frags is reset by build_skb, calculate again. */
- xdp_update_skb_frags_info(skb, frag_page - head_page,
+ xdp_update_skb_frags_info(skb, new_nr_frags,
sinfo->xdp_frags_size,
truesize,
xdp_buff_get_skb_flags(&mxbuf->xdp));
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index d3af87a94a18..123c96716a54 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -1072,10 +1072,11 @@ static void mlx5_eswitch_event_handler_register(struct mlx5_eswitch *esw)
static void mlx5_eswitch_event_handler_unregister(struct mlx5_eswitch *esw)
{
- if (esw->mode == MLX5_ESWITCH_OFFLOADS && mlx5_eswitch_is_funcs_handler(esw->dev))
+ if (esw->mode == MLX5_ESWITCH_OFFLOADS &&
+ mlx5_eswitch_is_funcs_handler(esw->dev)) {
mlx5_eq_notifier_unregister(esw->dev, &esw->esw_funcs.nb);
-
- flush_workqueue(esw->work_queue);
+ atomic_inc(&esw->esw_funcs.generation);
+ }
}
static void mlx5_eswitch_clear_vf_vports_info(struct mlx5_eswitch *esw)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index 6841caef02d1..c2563bee74df 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -335,10 +335,12 @@ struct esw_mc_addr { /* SRIOV only */
struct mlx5_host_work {
struct work_struct work;
struct mlx5_eswitch *esw;
+ int work_gen;
};
struct mlx5_esw_functions {
struct mlx5_nb nb;
+ atomic_t generation;
bool host_funcs_disabled;
u16 num_vfs;
u16 num_ec_vfs;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index 1366f6e489bd..7a9ee36b8dca 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -1241,21 +1241,17 @@ static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw,
flows[peer_vport->index] = flow;
}
- if (mlx5_esw_host_functions_enabled(esw->dev)) {
- mlx5_esw_for_each_vf_vport(peer_esw, i, peer_vport,
- mlx5_core_max_vfs(peer_dev)) {
- esw_set_peer_miss_rule_source_port(esw, peer_esw,
- spec,
- peer_vport->vport);
-
- flow = mlx5_add_flow_rules(mlx5_eswitch_get_slow_fdb(esw),
- spec, &flow_act, &dest, 1);
- if (IS_ERR(flow)) {
- err = PTR_ERR(flow);
- goto add_vf_flow_err;
- }
- flows[peer_vport->index] = flow;
+ mlx5_esw_for_each_vf_vport(peer_esw, i, peer_vport,
+ mlx5_core_max_vfs(peer_dev)) {
+ esw_set_peer_miss_rule_source_port(esw, peer_esw, spec,
+ peer_vport->vport);
+ flow = mlx5_add_flow_rules(mlx5_eswitch_get_slow_fdb(esw),
+ spec, &flow_act, &dest, 1);
+ if (IS_ERR(flow)) {
+ err = PTR_ERR(flow);
+ goto add_vf_flow_err;
}
+ flows[peer_vport->index] = flow;
}
if (mlx5_core_ec_sriov_enabled(peer_dev)) {
@@ -1347,7 +1343,8 @@ static void esw_del_fdb_peer_miss_rules(struct mlx5_eswitch *esw,
mlx5_del_flow_rules(flows[peer_vport->index]);
}
- if (mlx5_core_is_ecpf_esw_manager(peer_dev)) {
+ if (mlx5_core_is_ecpf_esw_manager(peer_dev) &&
+ mlx5_esw_host_functions_enabled(peer_dev)) {
peer_vport = mlx5_eswitch_get_vport(peer_esw, MLX5_VPORT_PF);
mlx5_del_flow_rules(flows[peer_vport->index]);
}
@@ -3582,22 +3579,28 @@ static void esw_offloads_steering_cleanup(struct mlx5_eswitch *esw)
}
static void
-esw_vfs_changed_event_handler(struct mlx5_eswitch *esw, const u32 *out)
+esw_vfs_changed_event_handler(struct mlx5_eswitch *esw, int work_gen,
+ const u32 *out)
{
struct devlink *devlink;
bool host_pf_disabled;
u16 new_num_vfs;
+ devlink = priv_to_devlink(esw->dev);
+ devl_lock(devlink);
+
+ /* Stale work from one or more mode changes ago. Bail out. */
+ if (work_gen != atomic_read(&esw->esw_funcs.generation))
+ goto unlock;
+
new_num_vfs = MLX5_GET(query_esw_functions_out, out,
host_params_context.host_num_of_vfs);
host_pf_disabled = MLX5_GET(query_esw_functions_out, out,
host_params_context.host_pf_disabled);
if (new_num_vfs == esw->esw_funcs.num_vfs || host_pf_disabled)
- return;
+ goto unlock;
- devlink = priv_to_devlink(esw->dev);
- devl_lock(devlink);
/* Number of VFs can only change from "0 to x" or "x to 0". */
if (esw->esw_funcs.num_vfs > 0) {
mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs);
@@ -3612,6 +3615,7 @@ esw_vfs_changed_event_handler(struct mlx5_eswitch *esw, const u32 *out)
}
}
esw->esw_funcs.num_vfs = new_num_vfs;
+unlock:
devl_unlock(devlink);
}
@@ -3628,7 +3632,7 @@ static void esw_functions_changed_event_handler(struct work_struct *work)
if (IS_ERR(out))
goto out;
- esw_vfs_changed_event_handler(esw, out);
+ esw_vfs_changed_event_handler(esw, host_work->work_gen, out);
kvfree(out);
out:
kfree(host_work);
@@ -3648,6 +3652,7 @@ int mlx5_esw_funcs_changed_handler(struct notifier_block *nb, unsigned long type
esw = container_of(esw_funcs, struct mlx5_eswitch, esw_funcs);
host_work->esw = esw;
+ host_work->work_gen = atomic_read(&esw_funcs->generation);
INIT_WORK(&host_work->work, esw_functions_changed_event_handler);
queue_work(esw->work_queue, &host_work->work);
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index 37d2f108a839..786186c9a115 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -1934,6 +1934,7 @@ remove_irq:
mana_gd_remove_irqs(pdev);
free_workqueue:
destroy_workqueue(gc->service_wq);
+ gc->service_wq = NULL;
dev_err(&pdev->dev, "%s failed (error %d)\n", __func__, err);
return err;
}
diff --git a/drivers/net/ethernet/spacemit/k1_emac.c b/drivers/net/ethernet/spacemit/k1_emac.c
index 338a2637b1da..15d43e4a748b 100644
--- a/drivers/net/ethernet/spacemit/k1_emac.c
+++ b/drivers/net/ethernet/spacemit/k1_emac.c
@@ -565,7 +565,9 @@ static void emac_alloc_rx_desc_buffers(struct emac_priv *priv)
DMA_FROM_DEVICE);
if (dma_mapping_error(&priv->pdev->dev, rx_buf->dma_addr)) {
dev_err_ratelimited(&ndev->dev, "Mapping skb failed\n");
- goto err_free_skb;
+ dev_kfree_skb_any(skb);
+ rx_buf->skb = NULL;
+ break;
}
rx_desc_addr = &((struct emac_desc *)rx_ring->desc_addr)[i];
@@ -590,10 +592,6 @@ static void emac_alloc_rx_desc_buffers(struct emac_priv *priv)
rx_ring->head = i;
return;
-
-err_free_skb:
- dev_kfree_skb_any(skb);
- rx_buf->skb = NULL;
}
/* Returns number of packets received */
@@ -735,7 +733,7 @@ static void emac_tx_mem_map(struct emac_priv *priv, struct sk_buff *skb)
struct emac_desc tx_desc, *tx_desc_addr;
struct device *dev = &priv->pdev->dev;
struct emac_tx_desc_buffer *tx_buf;
- u32 head, old_head, frag_num, f;
+ u32 head, old_head, frag_num, f, i;
bool buf_idx;
frag_num = skb_shinfo(skb)->nr_frags;
@@ -803,6 +801,15 @@ static void emac_tx_mem_map(struct emac_priv *priv, struct sk_buff *skb)
err_free_skb:
dev_dstats_tx_dropped(priv->ndev);
+
+ i = old_head;
+ while (i != head) {
+ emac_free_tx_buf(priv, i);
+
+ if (++i == tx_ring->total_cnt)
+ i = 0;
+ }
+
dev_kfree_skb_any(skb);
}
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
index 967918050433..265ce5479915 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
@@ -1351,7 +1351,7 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow,
ndev_priv = netdev_priv(ndev);
am65_cpsw_nuss_set_offload_fwd_mark(skb, ndev_priv->offload_fwd_mark);
skb_put(skb, pkt_len);
- if (port->rx_ts_enabled)
+ if (port->rx_ts_filter)
am65_cpts_rx_timestamp(common->cpts, skb);
skb_mark_for_recycle(skb);
skb->protocol = eth_type_trans(skb, ndev);
@@ -1811,11 +1811,14 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev,
switch (cfg->rx_filter) {
case HWTSTAMP_FILTER_NONE:
- port->rx_ts_enabled = false;
+ port->rx_ts_filter = HWTSTAMP_FILTER_NONE;
break;
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ port->rx_ts_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+ cfg->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+ break;
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
@@ -1825,8 +1828,8 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev,
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
- port->rx_ts_enabled = true;
- cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT | HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+ port->rx_ts_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+ cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
break;
case HWTSTAMP_FILTER_ALL:
case HWTSTAMP_FILTER_SOME:
@@ -1863,7 +1866,7 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev,
ts_ctrl |= AM65_CPSW_TS_TX_ANX_ALL_EN |
AM65_CPSW_PN_TS_CTL_TX_VLAN_LT1_EN;
- if (port->rx_ts_enabled)
+ if (port->rx_ts_filter)
ts_ctrl |= AM65_CPSW_TS_RX_ANX_ALL_EN |
AM65_CPSW_PN_TS_CTL_RX_VLAN_LT1_EN;
@@ -1888,8 +1891,7 @@ static int am65_cpsw_nuss_hwtstamp_get(struct net_device *ndev,
cfg->flags = 0;
cfg->tx_type = port->tx_ts_enabled ?
HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
- cfg->rx_filter = port->rx_ts_enabled ? HWTSTAMP_FILTER_PTP_V2_EVENT |
- HWTSTAMP_FILTER_PTP_V1_L4_EVENT : HWTSTAMP_FILTER_NONE;
+ cfg->rx_filter = port->rx_ts_filter;
return 0;
}
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.h b/drivers/net/ethernet/ti/am65-cpsw-nuss.h
index 917c37e4e89b..7750448e4746 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.h
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.h
@@ -52,7 +52,7 @@ struct am65_cpsw_port {
bool disabled;
struct am65_cpsw_slave_data slave;
bool tx_ts_enabled;
- bool rx_ts_enabled;
+ enum hwtstamp_rx_filters rx_ts_filter;
struct am65_cpsw_qos qos;
struct devlink_port devlink_port;
struct bpf_prog *xdp_prog;
diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c
index de6bc1736734..15fe4d1163c1 100644
--- a/drivers/net/mctp/mctp-i2c.c
+++ b/drivers/net/mctp/mctp-i2c.c
@@ -343,6 +343,7 @@ static int mctp_i2c_recv(struct mctp_i2c_dev *midev)
} else {
status = NET_RX_DROP;
spin_unlock_irqrestore(&midev->lock, flags);
+ kfree_skb(skb);
}
if (status == NET_RX_SUCCESS) {
diff --git a/drivers/net/mctp/mctp-usb.c b/drivers/net/mctp/mctp-usb.c
index ef860cfc629f..3b5dff144177 100644
--- a/drivers/net/mctp/mctp-usb.c
+++ b/drivers/net/mctp/mctp-usb.c
@@ -329,7 +329,7 @@ static int mctp_usb_probe(struct usb_interface *intf,
SET_NETDEV_DEV(netdev, &intf->dev);
dev = netdev_priv(netdev);
dev->netdev = netdev;
- dev->usbdev = usb_get_dev(interface_to_usbdev(intf));
+ dev->usbdev = interface_to_usbdev(intf);
dev->intf = intf;
usb_set_intfdata(intf, dev);
@@ -365,7 +365,6 @@ static void mctp_usb_disconnect(struct usb_interface *intf)
mctp_unregister_netdev(dev->netdev);
usb_free_urb(dev->tx_urb);
usb_free_urb(dev->rx_urb);
- usb_put_dev(dev->usbdev);
free_netdev(dev->netdev);
}
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index f4bf53da3d4f..5db841377199 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -367,6 +367,12 @@ static void sfp_fixup_ignore_tx_fault(struct sfp *sfp)
sfp->state_ignore_mask |= SFP_F_TX_FAULT;
}
+static void sfp_fixup_ignore_tx_fault_and_los(struct sfp *sfp)
+{
+ sfp_fixup_ignore_tx_fault(sfp);
+ sfp_fixup_ignore_los(sfp);
+}
+
static void sfp_fixup_ignore_hw(struct sfp *sfp, unsigned int mask)
{
sfp->state_hw_mask &= ~mask;
@@ -530,7 +536,7 @@ static const struct sfp_quirk sfp_quirks[] = {
// Huawei MA5671A can operate at 2500base-X, but report 1.2GBd NRZ in
// their EEPROM
SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex,
- sfp_fixup_ignore_tx_fault),
+ sfp_fixup_ignore_tx_fault_and_los),
// Lantech 8330-262D-E and 8330-265D can operate at 2500base-X, but
// incorrectly report 2500MBd NRZ in their EEPROM.
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
index a0021df12fde..19cdf69fa589 100644
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -3119,6 +3119,10 @@ static int lan78xx_init_ltm(struct lan78xx_net *dev)
int ret;
u32 buf;
+ /* LAN7850 is USB 2.0 and does not support LTM */
+ if (dev->chipid == ID_REV_CHIP_ID_7850_)
+ return 0;
+
ret = lan78xx_read_reg(dev, USB_CFG1, &buf);
if (ret < 0)
goto init_ltm_failed;
@@ -3829,6 +3833,7 @@ static void lan78xx_rx_csum_offload(struct lan78xx_net *dev,
*/
if (!(dev->net->features & NETIF_F_RXCSUM) ||
unlikely(rx_cmd_a & RX_CMD_A_ICSM_) ||
+ unlikely(rx_cmd_a & RX_CMD_A_CSE_MASK_) ||
((rx_cmd_a & RX_CMD_A_FVTG_) &&
!(dev->net->features & NETIF_F_HW_VLAN_CTAG_RX))) {
skb->ip_summed = CHECKSUM_NONE;
@@ -3901,7 +3906,8 @@ static int lan78xx_rx(struct lan78xx_net *dev, struct sk_buff *skb,
return 0;
}
- if (unlikely(rx_cmd_a & RX_CMD_A_RED_)) {
+ if (unlikely(rx_cmd_a & RX_CMD_A_RED_) &&
+ (rx_cmd_a & RX_CMD_A_RX_HARD_ERRS_MASK_)) {
netif_dbg(dev, rx_err, dev->net,
"Error rx_cmd_a=0x%08x", rx_cmd_a);
} else {
@@ -4176,7 +4182,7 @@ static struct skb_data *lan78xx_tx_buf_fill(struct lan78xx_net *dev,
}
tx_data += len;
- entry->length += len;
+ entry->length += max_t(unsigned int, len, ETH_ZLEN);
entry->num_of_packet += skb_shinfo(skb)->gso_segs ?: 1;
dev_kfree_skb_any(skb);
@@ -4546,8 +4552,6 @@ static void lan78xx_disconnect(struct usb_interface *intf)
phylink_disconnect_phy(dev->phylink);
rtnl_unlock();
- netif_napi_del(&dev->napi);
-
unregister_netdev(net);
timer_shutdown_sync(&dev->stat_monitor);
diff --git a/drivers/net/usb/lan78xx.h b/drivers/net/usb/lan78xx.h
index 968e5e5faee0..17a934acff3d 100644
--- a/drivers/net/usb/lan78xx.h
+++ b/drivers/net/usb/lan78xx.h
@@ -74,6 +74,9 @@
#define RX_CMD_A_ICSM_ (0x00004000)
#define RX_CMD_A_LEN_MASK_ (0x00003FFF)
+#define RX_CMD_A_RX_HARD_ERRS_MASK_ \
+ (RX_CMD_A_RX_ERRS_MASK_ & ~RX_CMD_A_CSE_MASK_)
+
/* Rx Command B */
#define RX_CMD_B_CSUM_SHIFT_ (16)
#define RX_CMD_B_CSUM_MASK_ (0xFFFF0000)
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 3a4985b582cb..05acac10cd2b 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -928,7 +928,7 @@ err:
static const struct driver_info qmi_wwan_info = {
.description = "WWAN/QMI device",
- .flags = FLAG_WWAN | FLAG_SEND_ZLP,
+ .flags = FLAG_WWAN | FLAG_NOMAXMTU | FLAG_SEND_ZLP,
.bind = qmi_wwan_bind,
.unbind = qmi_wwan_unbind,
.manage_power = qmi_wwan_manage_power,
@@ -937,7 +937,7 @@ static const struct driver_info qmi_wwan_info = {
static const struct driver_info qmi_wwan_info_quirk_dtr = {
.description = "WWAN/QMI device",
- .flags = FLAG_WWAN | FLAG_SEND_ZLP,
+ .flags = FLAG_WWAN | FLAG_NOMAXMTU | FLAG_SEND_ZLP,
.bind = qmi_wwan_bind,
.unbind = qmi_wwan_unbind,
.manage_power = qmi_wwan_manage_power,
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index ed86ba87ca4e..b72ba0803392 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1829,11 +1829,12 @@ usbnet_probe(struct usb_interface *udev, const struct usb_device_id *prod)
if ((dev->driver_info->flags & FLAG_NOARP) != 0)
net->flags |= IFF_NOARP;
- if (net->max_mtu > (dev->hard_mtu - net->hard_header_len))
+ if ((dev->driver_info->flags & FLAG_NOMAXMTU) == 0 &&
+ net->max_mtu > (dev->hard_mtu - net->hard_header_len))
net->max_mtu = dev->hard_mtu - net->hard_header_len;
- if (net->mtu > net->max_mtu)
- net->mtu = net->max_mtu;
+ if (net->mtu > (dev->hard_mtu - net->hard_header_len))
+ net->mtu = dev->hard_mtu - net->hard_header_len;
} else if (!info->in || !info->out)
status = usbnet_get_endpoints(dev, udev);