Skip to content

Commit 0f62aee

Browse files
committed
Merge branch 'ravb-sh_eth-fix-sleep-in-atomic-by-reusing-shared-ethtool-handlers'
Vladimir Zapolskiy says: ==================== ravb/sh_eth: fix sleep in atomic by reusing shared ethtool handlers For ages trivial changes to RAVB and SuperH ethernet links by means of standard 'ethtool' trigger a 'sleeping function called from invalid context' bug, to visualize it on r8a7795 ULCB: % ethtool -r eth0 BUG: sleeping function called from invalid context at kernel/locking/mutex.c:747 in_atomic(): 1, irqs_disabled(): 128, pid: 554, name: ethtool INFO: lockdep is turned off. irq event stamp: 0 hardirqs last enabled at (0): [<0000000000000000>] (null) hardirqs last disabled at (0): [<ffff0000080e1d3c>] copy_process.isra.7.part.8+0x2cc/0x1918 softirqs last enabled at (0): [<ffff0000080e1d3c>] copy_process.isra.7.part.8+0x2cc/0x1918 softirqs last disabled at (0): [<0000000000000000>] (null) CPU: 5 PID: 554 Comm: ethtool Not tainted 4.17.0-rc4-arm64-renesas+ #33 Hardware name: Renesas H3ULCB board based on r8a7795 ES2.0+ (DT) Call trace: dump_backtrace+0x0/0x198 show_stack+0x24/0x30 dump_stack+0xb8/0xf4 ___might_sleep+0x1c8/0x1f8 __might_sleep+0x58/0x90 __mutex_lock+0x50/0x890 mutex_lock_nested+0x3c/0x50 phy_start_aneg_priv+0x38/0x180 phy_start_aneg+0x24/0x30 ravb_nway_reset+0x3c/0x68 dev_ethtool+0x3dc/0x2338 dev_ioctl+0x19c/0x490 sock_do_ioctl+0xe0/0x238 sock_ioctl+0x254/0x460 do_vfs_ioctl+0xb0/0x918 ksys_ioctl+0x50/0x80 sys_ioctl+0x34/0x48 __sys_trace_return+0x0/0x4 The root cause is that an attempt to modify ECMR and GECMR registers only when RX/TX function is disabled was too overcomplicated in its original implementation, also processing of an optional Link Change interrupt added even more complexity, as a result the implementation was error prone. The new locking scheme is confirmed to be correct by dumping driver specific and generic PHY framework function calls with aid of ftrace while running more or less advanced tests. Please note that sh_eth patches from the series were built-tested only. On purpose I do not add Fixes tags, the reused PHY handlers were added way later than the fixed problems were firstly found in the drivers. Changes from v1 to v2: * the original patches are split to bugfixes and enhancements only, both v1 and v2 series are absolutely equal in total, thus I omit description of changes in individual patches, * the latter implies that there should be no strict need for retesting, but because formally two series are different, I have to drop the tags given by Geert and Andrew, please send your tags again. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 70ba5b6 + 44f3d55 commit 0f62aee

File tree

2 files changed

+34
-153
lines changed

2 files changed

+34
-153
lines changed

drivers/net/ethernet/renesas/ravb_main.c

Lines changed: 17 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,13 @@ static void ravb_adjust_link(struct net_device *ndev)
980980
struct ravb_private *priv = netdev_priv(ndev);
981981
struct phy_device *phydev = ndev->phydev;
982982
bool new_state = false;
983+
unsigned long flags;
984+
985+
spin_lock_irqsave(&priv->lock, flags);
986+
987+
/* Disable TX and RX right over here, if E-MAC change is ignored */
988+
if (priv->no_avb_link)
989+
ravb_rcv_snd_disable(ndev);
983990

984991
if (phydev->link) {
985992
if (phydev->duplex != priv->duplex) {
@@ -997,18 +1004,21 @@ static void ravb_adjust_link(struct net_device *ndev)
9971004
ravb_modify(ndev, ECMR, ECMR_TXF, 0);
9981005
new_state = true;
9991006
priv->link = phydev->link;
1000-
if (priv->no_avb_link)
1001-
ravb_rcv_snd_enable(ndev);
10021007
}
10031008
} else if (priv->link) {
10041009
new_state = true;
10051010
priv->link = 0;
10061011
priv->speed = 0;
10071012
priv->duplex = -1;
1008-
if (priv->no_avb_link)
1009-
ravb_rcv_snd_disable(ndev);
10101013
}
10111014

1015+
/* Enable TX and RX right over here, if E-MAC change is ignored */
1016+
if (priv->no_avb_link && phydev->link)
1017+
ravb_rcv_snd_enable(ndev);
1018+
1019+
mmiowb();
1020+
spin_unlock_irqrestore(&priv->lock, flags);
1021+
10121022
if (new_state && netif_msg_link(priv))
10131023
phy_print_status(phydev);
10141024
}
@@ -1096,75 +1106,6 @@ static int ravb_phy_start(struct net_device *ndev)
10961106
return 0;
10971107
}
10981108

1099-
static int ravb_get_link_ksettings(struct net_device *ndev,
1100-
struct ethtool_link_ksettings *cmd)
1101-
{
1102-
struct ravb_private *priv = netdev_priv(ndev);
1103-
unsigned long flags;
1104-
1105-
if (!ndev->phydev)
1106-
return -ENODEV;
1107-
1108-
spin_lock_irqsave(&priv->lock, flags);
1109-
phy_ethtool_ksettings_get(ndev->phydev, cmd);
1110-
spin_unlock_irqrestore(&priv->lock, flags);
1111-
1112-
return 0;
1113-
}
1114-
1115-
static int ravb_set_link_ksettings(struct net_device *ndev,
1116-
const struct ethtool_link_ksettings *cmd)
1117-
{
1118-
struct ravb_private *priv = netdev_priv(ndev);
1119-
unsigned long flags;
1120-
int error;
1121-
1122-
if (!ndev->phydev)
1123-
return -ENODEV;
1124-
1125-
spin_lock_irqsave(&priv->lock, flags);
1126-
1127-
/* Disable TX and RX */
1128-
ravb_rcv_snd_disable(ndev);
1129-
1130-
error = phy_ethtool_ksettings_set(ndev->phydev, cmd);
1131-
if (error)
1132-
goto error_exit;
1133-
1134-
if (cmd->base.duplex == DUPLEX_FULL)
1135-
priv->duplex = 1;
1136-
else
1137-
priv->duplex = 0;
1138-
1139-
ravb_set_duplex(ndev);
1140-
1141-
error_exit:
1142-
mdelay(1);
1143-
1144-
/* Enable TX and RX */
1145-
ravb_rcv_snd_enable(ndev);
1146-
1147-
mmiowb();
1148-
spin_unlock_irqrestore(&priv->lock, flags);
1149-
1150-
return error;
1151-
}
1152-
1153-
static int ravb_nway_reset(struct net_device *ndev)
1154-
{
1155-
struct ravb_private *priv = netdev_priv(ndev);
1156-
int error = -ENODEV;
1157-
unsigned long flags;
1158-
1159-
if (ndev->phydev) {
1160-
spin_lock_irqsave(&priv->lock, flags);
1161-
error = phy_start_aneg(ndev->phydev);
1162-
spin_unlock_irqrestore(&priv->lock, flags);
1163-
}
1164-
1165-
return error;
1166-
}
1167-
11681109
static u32 ravb_get_msglevel(struct net_device *ndev)
11691110
{
11701111
struct ravb_private *priv = netdev_priv(ndev);
@@ -1377,7 +1318,7 @@ static int ravb_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
13771318
}
13781319

13791320
static const struct ethtool_ops ravb_ethtool_ops = {
1380-
.nway_reset = ravb_nway_reset,
1321+
.nway_reset = phy_ethtool_nway_reset,
13811322
.get_msglevel = ravb_get_msglevel,
13821323
.set_msglevel = ravb_set_msglevel,
13831324
.get_link = ethtool_op_get_link,
@@ -1387,8 +1328,8 @@ static const struct ethtool_ops ravb_ethtool_ops = {
13871328
.get_ringparam = ravb_get_ringparam,
13881329
.set_ringparam = ravb_set_ringparam,
13891330
.get_ts_info = ravb_get_ts_info,
1390-
.get_link_ksettings = ravb_get_link_ksettings,
1391-
.set_link_ksettings = ravb_set_link_ksettings,
1331+
.get_link_ksettings = phy_ethtool_get_link_ksettings,
1332+
.set_link_ksettings = phy_ethtool_set_link_ksettings,
13921333
.get_wol = ravb_get_wol,
13931334
.set_wol = ravb_set_wol,
13941335
};

drivers/net/ethernet/renesas/sh_eth.c

Lines changed: 17 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1927,8 +1927,15 @@ static void sh_eth_adjust_link(struct net_device *ndev)
19271927
{
19281928
struct sh_eth_private *mdp = netdev_priv(ndev);
19291929
struct phy_device *phydev = ndev->phydev;
1930+
unsigned long flags;
19301931
int new_state = 0;
19311932

1933+
spin_lock_irqsave(&mdp->lock, flags);
1934+
1935+
/* Disable TX and RX right over here, if E-MAC change is ignored */
1936+
if (mdp->cd->no_psr || mdp->no_ether_link)
1937+
sh_eth_rcv_snd_disable(ndev);
1938+
19321939
if (phydev->link) {
19331940
if (phydev->duplex != mdp->duplex) {
19341941
new_state = 1;
@@ -1947,18 +1954,21 @@ static void sh_eth_adjust_link(struct net_device *ndev)
19471954
sh_eth_modify(ndev, ECMR, ECMR_TXF, 0);
19481955
new_state = 1;
19491956
mdp->link = phydev->link;
1950-
if (mdp->cd->no_psr || mdp->no_ether_link)
1951-
sh_eth_rcv_snd_enable(ndev);
19521957
}
19531958
} else if (mdp->link) {
19541959
new_state = 1;
19551960
mdp->link = 0;
19561961
mdp->speed = 0;
19571962
mdp->duplex = -1;
1958-
if (mdp->cd->no_psr || mdp->no_ether_link)
1959-
sh_eth_rcv_snd_disable(ndev);
19601963
}
19611964

1965+
/* Enable TX and RX right over here, if E-MAC change is ignored */
1966+
if ((mdp->cd->no_psr || mdp->no_ether_link) && phydev->link)
1967+
sh_eth_rcv_snd_enable(ndev);
1968+
1969+
mmiowb();
1970+
spin_unlock_irqrestore(&mdp->lock, flags);
1971+
19621972
if (new_state && netif_msg_link(mdp))
19631973
phy_print_status(phydev);
19641974
}
@@ -2030,60 +2040,6 @@ static int sh_eth_phy_start(struct net_device *ndev)
20302040
return 0;
20312041
}
20322042

2033-
static int sh_eth_get_link_ksettings(struct net_device *ndev,
2034-
struct ethtool_link_ksettings *cmd)
2035-
{
2036-
struct sh_eth_private *mdp = netdev_priv(ndev);
2037-
unsigned long flags;
2038-
2039-
if (!ndev->phydev)
2040-
return -ENODEV;
2041-
2042-
spin_lock_irqsave(&mdp->lock, flags);
2043-
phy_ethtool_ksettings_get(ndev->phydev, cmd);
2044-
spin_unlock_irqrestore(&mdp->lock, flags);
2045-
2046-
return 0;
2047-
}
2048-
2049-
static int sh_eth_set_link_ksettings(struct net_device *ndev,
2050-
const struct ethtool_link_ksettings *cmd)
2051-
{
2052-
struct sh_eth_private *mdp = netdev_priv(ndev);
2053-
unsigned long flags;
2054-
int ret;
2055-
2056-
if (!ndev->phydev)
2057-
return -ENODEV;
2058-
2059-
spin_lock_irqsave(&mdp->lock, flags);
2060-
2061-
/* disable tx and rx */
2062-
sh_eth_rcv_snd_disable(ndev);
2063-
2064-
ret = phy_ethtool_ksettings_set(ndev->phydev, cmd);
2065-
if (ret)
2066-
goto error_exit;
2067-
2068-
if (cmd->base.duplex == DUPLEX_FULL)
2069-
mdp->duplex = 1;
2070-
else
2071-
mdp->duplex = 0;
2072-
2073-
if (mdp->cd->set_duplex)
2074-
mdp->cd->set_duplex(ndev);
2075-
2076-
error_exit:
2077-
mdelay(1);
2078-
2079-
/* enable tx and rx */
2080-
sh_eth_rcv_snd_enable(ndev);
2081-
2082-
spin_unlock_irqrestore(&mdp->lock, flags);
2083-
2084-
return ret;
2085-
}
2086-
20872043
/* If it is ever necessary to increase SH_ETH_REG_DUMP_MAX_REGS, the
20882044
* version must be bumped as well. Just adding registers up to that
20892045
* limit is fine, as long as the existing register indices don't
@@ -2263,22 +2219,6 @@ static void sh_eth_get_regs(struct net_device *ndev, struct ethtool_regs *regs,
22632219
pm_runtime_put_sync(&mdp->pdev->dev);
22642220
}
22652221

2266-
static int sh_eth_nway_reset(struct net_device *ndev)
2267-
{
2268-
struct sh_eth_private *mdp = netdev_priv(ndev);
2269-
unsigned long flags;
2270-
int ret;
2271-
2272-
if (!ndev->phydev)
2273-
return -ENODEV;
2274-
2275-
spin_lock_irqsave(&mdp->lock, flags);
2276-
ret = phy_start_aneg(ndev->phydev);
2277-
spin_unlock_irqrestore(&mdp->lock, flags);
2278-
2279-
return ret;
2280-
}
2281-
22822222
static u32 sh_eth_get_msglevel(struct net_device *ndev)
22832223
{
22842224
struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -2429,7 +2369,7 @@ static int sh_eth_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
24292369
static const struct ethtool_ops sh_eth_ethtool_ops = {
24302370
.get_regs_len = sh_eth_get_regs_len,
24312371
.get_regs = sh_eth_get_regs,
2432-
.nway_reset = sh_eth_nway_reset,
2372+
.nway_reset = phy_ethtool_nway_reset,
24332373
.get_msglevel = sh_eth_get_msglevel,
24342374
.set_msglevel = sh_eth_set_msglevel,
24352375
.get_link = ethtool_op_get_link,
@@ -2438,8 +2378,8 @@ static const struct ethtool_ops sh_eth_ethtool_ops = {
24382378
.get_sset_count = sh_eth_get_sset_count,
24392379
.get_ringparam = sh_eth_get_ringparam,
24402380
.set_ringparam = sh_eth_set_ringparam,
2441-
.get_link_ksettings = sh_eth_get_link_ksettings,
2442-
.set_link_ksettings = sh_eth_set_link_ksettings,
2381+
.get_link_ksettings = phy_ethtool_get_link_ksettings,
2382+
.set_link_ksettings = phy_ethtool_set_link_ksettings,
24432383
.get_wol = sh_eth_get_wol,
24442384
.set_wol = sh_eth_set_wol,
24452385
};

0 commit comments

Comments
 (0)