Message ID | 9891d6dab3ad4a77add7b4833e9cf202da71d059.1652343655.git.lukas@wunner.de (mailing list archive) |
---|---|
State | Accepted |
Commit | 8960f878e39fadc03d74292a6731f1e914cf2019 |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | Polling be gone on LAN95xx | expand |
Context | Check | Description |
---|---|---|
netdev/tree_selection | success | Clearly marked for net-next |
netdev/fixes_present | success | Fixes tag not required for -next series |
netdev/subject_prefix | success | Link |
netdev/cover_letter | success | Series has a cover letter |
netdev/patch_count | success | Link |
netdev/header_inline | success | No static functions without inline keyword in header files |
netdev/build_32bit | success | Errors and warnings before: 1 this patch: 1 |
netdev/cc_maintainers | success | CCed 8 of 8 maintainers |
netdev/build_clang | success | Errors and warnings before: 0 this patch: 0 |
netdev/module_param | success | Was 0 now: 0 |
netdev/verify_signedoff | success | Signed-off-by tag matches author and committer |
netdev/verify_fixes | success | No Fixes tag |
netdev/build_allmodconfig_warn | success | Errors and warnings before: 1 this patch: 1 |
netdev/checkpatch | success | total: 0 errors, 0 warnings, 0 checks, 50 lines checked |
netdev/kdoc | success | Errors and warnings before: 0 this patch: 0 |
netdev/source_inline | success | Was 0 now: 0 |
On Thu, May 12, 2022 at 10:42:04AM +0200, Lukas Wunner wrote: > When a PHY interrupt is signaled, the SMSC LAN95xx driver updates the > MAC full duplex mode and PHY flow control registers based on cached data > in struct phy_device: > > smsc95xx_status() # raises EVENT_LINK_RESET > usbnet_deferred_kevent() > smsc95xx_link_reset() # uses cached data in phydev > > Simultaneously, phylib polls link status once per second and updates > that cached data: > > phy_state_machine() > phy_check_link_status() > phy_read_status() > lan87xx_read_status() > genphy_read_status() # updates cached data in phydev > > If smsc95xx_link_reset() wins the race against genphy_read_status(), > the registers may be updated based on stale data. > > E.g. if the link was previously down, phydev->duplex is set to > DUPLEX_UNKNOWN and that's what smsc95xx_link_reset() will use, even > though genphy_read_status() may update it to DUPLEX_FULL afterwards. > > PHY interrupts are currently only enabled on suspend to trigger wakeup, > so the impact of the race is limited, but we're about to enable them > perpetually. > > Avoid the race by delaying execution of smsc95xx_link_reset() until > phy_state_machine() has done its job and calls back via > smsc95xx_handle_link_change(). > > Signaling EVENT_LINK_RESET on wakeup is not necessary because phylib > picks up link status changes through polling. So drop the declaration > of a ->link_reset() callback. > > Note that the semicolon on a line by itself added in smsc95xx_status() > is a placeholder for a function call which will be added in a subsequent > commit. That function call will actually handle the INT_ENP_PHY_INT_ > interrupt. > > Tested-by: Oleksij Rempel <o.rempel@pengutronix.de> # LAN9514/9512/9500 > Tested-by: Ferry Toth <fntoth@gmail.com> # LAN9514 > Signed-off-by: Lukas Wunner <lukas@wunner.de> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Andrew kindly provided this tag here: https://lore.kernel.org/netdev/YnGrUdmqtzt3Ogn+@lunn.ch/ Forgot to add it to the commit. Sending it in separately so patchwork picks it up. My apologies for the inconvenience.
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 6c37c7adde1b..6309ff8e75de 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -566,7 +566,7 @@ static int smsc95xx_phy_update_flowcontrol(struct usbnet *dev) return smsc95xx_write_reg(dev, AFC_CFG, afc_cfg); } -static int smsc95xx_link_reset(struct usbnet *dev) +static void smsc95xx_mac_update_fullduplex(struct usbnet *dev) { struct smsc95xx_priv *pdata = dev->driver_priv; unsigned long flags; @@ -583,14 +583,16 @@ static int smsc95xx_link_reset(struct usbnet *dev) spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); ret = smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr); - if (ret < 0) - return ret; + if (ret < 0) { + if (ret != -ENODEV) + netdev_warn(dev->net, + "Error updating MAC full duplex mode\n"); + return; + } ret = smsc95xx_phy_update_flowcontrol(dev); if (ret < 0) netdev_warn(dev->net, "Error updating PHY flow control\n"); - - return ret; } static void smsc95xx_status(struct usbnet *dev, struct urb *urb) @@ -607,7 +609,7 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb) netif_dbg(dev, link, dev->net, "intdata: 0x%08X\n", intdata); if (intdata & INT_ENP_PHY_INT_) - usbnet_defer_kevent(dev, EVENT_LINK_RESET); + ; else netdev_warn(dev->net, "unexpected interrupt, intdata=0x%08X\n", intdata); @@ -1070,6 +1072,7 @@ static void smsc95xx_handle_link_change(struct net_device *net) struct usbnet *dev = netdev_priv(net); phy_print_status(net->phydev); + smsc95xx_mac_update_fullduplex(dev); usbnet_defer_kevent(dev, EVENT_LINK_CHANGE); } @@ -1975,7 +1978,6 @@ static const struct driver_info smsc95xx_info = { .description = "smsc95xx USB 2.0 Ethernet", .bind = smsc95xx_bind, .unbind = smsc95xx_unbind, - .link_reset = smsc95xx_link_reset, .reset = smsc95xx_reset, .check_connect = smsc95xx_start_phy, .stop = smsc95xx_stop,