summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2021-07-14 14:57:55 -0700
committerDavid S. Miller <davem@davemloft.net>2021-07-14 14:57:55 -0700
commit3ffd3dad4b5d9202c2aff6b7e7d7af7be792f9ed (patch)
treef72f2491cc4b8ed9c1153537e1b15d9a8a8ade10
parent8096acd7442e613fad0354fc8dfdb2003cceea0b (diff)
parent776ac63a986d211286230c4fd70f85390eabedcd (diff)
Merge branch 'r8152-pm-fixxes'
Takashi Iwai says: ==================== r8152: Fix a couple of PM problems it seems that r8152 driver suffers from the deadlock at both runtime and system PM. Formerly, it was seen more often at hibernation resume, but now it's triggered more frequently, as reported in SUSE Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1186194 While debugging the problem, I stumbled on a few obvious bugs and here is the results with two patches for addressing the resume problem. *** However, the story doesn't end here, unfortunately, and those patches don't seem sufficing. The rest major problem is that the driver calls napi_disable() and napi_enable() in the PM suspend callbacks. This makes the system stalling at (runtime-)suspend. If we drop napi_disable() and napi_enable() calls in the PM suspend callbacks, it starts working (that was the result in Bugzilla comment 13): https://bugzilla.suse.com/show_bug.cgi?id=1186194#c13 So, my patches aren't enough and we still need to investigate further. It'd be appreciated if anyone can give a fix or a hint for more debugging. The usage of napi_disable() at PM callbacks is unique in this driver and looks rather suspicious to me; but I'm no expert in this area so I might be wrong... ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/usb/r8152.c30
1 files changed, 20 insertions, 10 deletions
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 1692d3b1b6e1..e09b107b5c99 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -1552,7 +1552,8 @@ static int
rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex,
u32 advertising);
-static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
+static int __rtl8152_set_mac_address(struct net_device *netdev, void *p,
+ bool in_resume)
{
struct r8152 *tp = netdev_priv(netdev);
struct sockaddr *addr = p;
@@ -1561,9 +1562,11 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
goto out1;
- ret = usb_autopm_get_interface(tp->intf);
- if (ret < 0)
- goto out1;
+ if (!in_resume) {
+ ret = usb_autopm_get_interface(tp->intf);
+ if (ret < 0)
+ goto out1;
+ }
mutex_lock(&tp->control);
@@ -1575,11 +1578,17 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
mutex_unlock(&tp->control);
- usb_autopm_put_interface(tp->intf);
+ if (!in_resume)
+ usb_autopm_put_interface(tp->intf);
out1:
return ret;
}
+static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
+{
+ return __rtl8152_set_mac_address(netdev, p, false);
+}
+
/* Devices containing proper chips can support a persistent
* host system provided MAC address.
* Examples of this are Dell TB15 and Dell WD15 docks
@@ -1698,7 +1707,7 @@ static int determine_ethernet_addr(struct r8152 *tp, struct sockaddr *sa)
return ret;
}
-static int set_ethernet_addr(struct r8152 *tp)
+static int set_ethernet_addr(struct r8152 *tp, bool in_resume)
{
struct net_device *dev = tp->netdev;
struct sockaddr sa;
@@ -1711,7 +1720,7 @@ static int set_ethernet_addr(struct r8152 *tp)
if (tp->version == RTL_VER_01)
ether_addr_copy(dev->dev_addr, sa.sa_data);
else
- ret = rtl8152_set_mac_address(dev, &sa);
+ ret = __rtl8152_set_mac_address(dev, &sa, in_resume);
return ret;
}
@@ -6763,9 +6772,10 @@ static int rtl8152_close(struct net_device *netdev)
tp->rtl_ops.down(tp);
mutex_unlock(&tp->control);
+ }
+ if (!res)
usb_autopm_put_interface(tp->intf);
- }
free_all_mem(tp);
@@ -8443,7 +8453,7 @@ static int rtl8152_reset_resume(struct usb_interface *intf)
clear_bit(SELECTIVE_SUSPEND, &tp->flags);
tp->rtl_ops.init(tp);
queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0);
- set_ethernet_addr(tp);
+ set_ethernet_addr(tp, true);
return rtl8152_resume(intf);
}
@@ -9644,7 +9654,7 @@ static int rtl8152_probe(struct usb_interface *intf,
tp->rtl_fw.retry = true;
#endif
queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0);
- set_ethernet_addr(tp);
+ set_ethernet_addr(tp, false);
usb_set_intfdata(intf, tp);