mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
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:
+1
-1
@@ -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/
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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] +
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user