All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lukas Wunner <lukas@wunner.de>
To: Steve Glendinning <steve.glendinning@shawell.net>,
	UNGLinuxDriver@microchip.com, Oliver Neukum <oneukum@suse.com>,
	"David S. Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>
Cc: netdev@vger.kernel.org, linux-usb@vger.kernel.org,
	Andre Edich <andre.edich@microchip.com>,
	Oleksij Rempel <o.rempel@pengutronix.de>,
	Martyn Welch <martyn.welch@collabora.com>,
	Gabriel Hojda <ghojda@yo2urs.ro>,
	Christoph Fritz <chf.fritz@googlemail.com>,
	Lino Sanfilippo <LinoSanfilippo@gmx.de>,
	Philipp Rosenberger <p.rosenberger@kunbus.com>,
	Heiner Kallweit <hkallweit1@gmail.com>,
	Andrew Lunn <andrew@lunn.ch>,
	Russell King <linux@armlinux.org.uk>
Subject: [PATCH net-next 4/7] usbnet: smsc95xx: Avoid link settings race on interrupt reception
Date: Wed, 27 Apr 2022 07:48:04 +0200	[thread overview]
Message-ID: <28fd5a3d53a401cdf8ae0a116108702a46d2c7a2.1651037513.git.lukas@wunner.de> (raw)
In-Reply-To: <cover.1651037513.git.lukas@wunner.de>

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.

Signed-off-by: Lukas Wunner <lukas@wunner.de>
---
 drivers/net/usb/smsc95xx.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 6c37c7adde1b..36abfaeae3c6 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,14 @@ 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) {
+		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 +607,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 +1070,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 +1976,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,
-- 
2.35.2


  parent reply	other threads:[~2022-04-27  6:10 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-27  5:48 [PATCH net-next 0/7] Polling be gone on LAN95xx Lukas Wunner
2022-04-27  5:48 ` [PATCH net-next 1/7] usbnet: Run unregister_netdev() before unbind() again Lukas Wunner
2022-04-27  7:44   ` Oliver Neukum
2022-04-27  7:45   ` Oliver Neukum
2022-04-27  5:48 ` [PATCH net-next 2/7] usbnet: smsc95xx: Don't clear read-only PHY interrupt Lukas Wunner
2022-04-27  5:48 ` [PATCH net-next 3/7] usbnet: smsc95xx: Don't reset PHY behind PHY driver's back Lukas Wunner
2022-04-27  5:48 ` Lukas Wunner [this message]
2022-04-27 11:50   ` [PATCH net-next 4/7] usbnet: smsc95xx: Avoid link settings race on interrupt reception Andrew Lunn
2022-04-27  5:48 ` [PATCH net-next 5/7] usbnet: smsc95xx: Forward PHY interrupts to PHY driver to avoid polling Lukas Wunner
2022-04-27 12:03   ` Andrew Lunn
2022-04-27 12:26   ` Andrew Lunn
2022-04-27  5:48 ` [PATCH net-next 6/7] net: phy: smsc: Cache interrupt mask Lukas Wunner
2022-04-27 12:14   ` Andrew Lunn
2022-04-27 12:51     ` Lukas Wunner
2022-04-27  5:48 ` [PATCH net-next 7/7] net: phy: smsc: Cope with hot-removal in interrupt handler Lukas Wunner
2022-04-27  7:46   ` Oliver Neukum
2022-04-27 12:37 ` [PATCH net-next 0/7] Polling be gone on LAN95xx Oleksij Rempel
2022-04-28 12:19   ` Lukas Wunner
2022-05-02 20:33 ` Ferry Toth
2022-05-03  8:26   ` Lukas Wunner
2022-05-03 14:26     ` Ferry Toth
2022-05-04  8:15       ` Lukas Wunner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=28fd5a3d53a401cdf8ae0a116108702a46d2c7a2.1651037513.git.lukas@wunner.de \
    --to=lukas@wunner.de \
    --cc=LinoSanfilippo@gmx.de \
    --cc=UNGLinuxDriver@microchip.com \
    --cc=andre.edich@microchip.com \
    --cc=andrew@lunn.ch \
    --cc=chf.fritz@googlemail.com \
    --cc=davem@davemloft.net \
    --cc=ghojda@yo2urs.ro \
    --cc=hkallweit1@gmail.com \
    --cc=kuba@kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=martyn.welch@collabora.com \
    --cc=netdev@vger.kernel.org \
    --cc=o.rempel@pengutronix.de \
    --cc=oneukum@suse.com \
    --cc=p.rosenberger@kunbus.com \
    --cc=pabeni@redhat.com \
    --cc=steve.glendinning@shawell.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.