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
  ...
This commit is contained in:
Linus Torvalds
2026-03-12 11:33:35 -07:00
77 changed files with 668 additions and 327 deletions
+1 -1
View File
@@ -16358,7 +16358,6 @@ F: net/dsa/tag_mtk.c
MEDIATEK T7XX 5G WWAN MODEM DRIVER
M: Chandrashekar Devegowda <chandrashekar.devegowda@intel.com>
R: Chiranjeevi Rapolu <chiranjeevi.rapolu@linux.intel.com>
R: Liu Haijun <haijun.liu@mediatek.com>
R: Ricardo Martinez <ricardo.martinez@linux.intel.com>
L: netdev@vger.kernel.org
@@ -25759,6 +25758,7 @@ F: include/net/pkt_cls.h
F: include/net/pkt_sched.h
F: include/net/sch_priv.h
F: include/net/tc_act/
F: include/net/tc_wrapper.h
F: include/uapi/linux/pkt_cls.h
F: include/uapi/linux/pkt_sched.h
F: include/uapi/linux/tc_act/
+63 -7
View File
@@ -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)
+3
View File
@@ -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);
+1 -1
View File
@@ -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)
+4 -1
View File
@@ -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;
+8 -3
View File
@@ -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)
-1
View File
@@ -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;
+1 -2
View File
@@ -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] +
+3 -3
View File
@@ -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;
}
+3 -4
View File
@@ -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);
+10 -9
View File
@@ -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);
+75 -7
View File
@@ -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);
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.
*/
reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
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;
+4
View File
@@ -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;
};
+11
View File
@@ -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);
@@ -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;
}
+12 -19
View File
@@ -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);
}
@@ -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__ */
+5 -5
View File
@@ -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;
}
+95 -3
View File
@@ -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);
@@ -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");

Some files were not shown because too many files have changed in this diff Show More