提交 776ac63a 编写于 作者: T Takashi Iwai 提交者: David S. Miller

r8152: Fix a deadlock by doubly PM resume

r8152 driver sets up the MAC address at reset-resume, while
rtl8152_set_mac_address() has the temporary autopm get/put.  This may
lead to a deadlock as the PM lock has been already taken for the
execution of the runtime PM callback.

This patch adds the workaround to avoid the superfluous autpm when
called from rtl8152_reset_resume().

Link: https://bugzilla.suse.com/show_bug.cgi?id=1186194Signed-off-by: NTakashi Iwai <tiwai@suse.de>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 9c23aa51
...@@ -1552,7 +1552,8 @@ static int ...@@ -1552,7 +1552,8 @@ static int
rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex, rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex,
u32 advertising); 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 r8152 *tp = netdev_priv(netdev);
struct sockaddr *addr = p; struct sockaddr *addr = p;
...@@ -1561,9 +1562,11 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *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)) if (!is_valid_ether_addr(addr->sa_data))
goto out1; goto out1;
ret = usb_autopm_get_interface(tp->intf); if (!in_resume) {
if (ret < 0) ret = usb_autopm_get_interface(tp->intf);
goto out1; if (ret < 0)
goto out1;
}
mutex_lock(&tp->control); mutex_lock(&tp->control);
...@@ -1575,11 +1578,17 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p) ...@@ -1575,11 +1578,17 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
mutex_unlock(&tp->control); mutex_unlock(&tp->control);
usb_autopm_put_interface(tp->intf); if (!in_resume)
usb_autopm_put_interface(tp->intf);
out1: out1:
return ret; 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 /* Devices containing proper chips can support a persistent
* host system provided MAC address. * host system provided MAC address.
* Examples of this are Dell TB15 and Dell WD15 docks * 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) ...@@ -1698,7 +1707,7 @@ static int determine_ethernet_addr(struct r8152 *tp, struct sockaddr *sa)
return ret; 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 net_device *dev = tp->netdev;
struct sockaddr sa; struct sockaddr sa;
...@@ -1711,7 +1720,7 @@ static int set_ethernet_addr(struct r8152 *tp) ...@@ -1711,7 +1720,7 @@ static int set_ethernet_addr(struct r8152 *tp)
if (tp->version == RTL_VER_01) if (tp->version == RTL_VER_01)
ether_addr_copy(dev->dev_addr, sa.sa_data); ether_addr_copy(dev->dev_addr, sa.sa_data);
else else
ret = rtl8152_set_mac_address(dev, &sa); ret = __rtl8152_set_mac_address(dev, &sa, in_resume);
return ret; return ret;
} }
...@@ -8444,7 +8453,7 @@ static int rtl8152_reset_resume(struct usb_interface *intf) ...@@ -8444,7 +8453,7 @@ static int rtl8152_reset_resume(struct usb_interface *intf)
clear_bit(SELECTIVE_SUSPEND, &tp->flags); clear_bit(SELECTIVE_SUSPEND, &tp->flags);
tp->rtl_ops.init(tp); tp->rtl_ops.init(tp);
queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0); queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0);
set_ethernet_addr(tp); set_ethernet_addr(tp, true);
return rtl8152_resume(intf); return rtl8152_resume(intf);
} }
...@@ -9645,7 +9654,7 @@ static int rtl8152_probe(struct usb_interface *intf, ...@@ -9645,7 +9654,7 @@ static int rtl8152_probe(struct usb_interface *intf,
tp->rtl_fw.retry = true; tp->rtl_fw.retry = true;
#endif #endif
queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0); 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); usb_set_intfdata(intf, tp);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册