2014-10-07 05:36:57

by Hayes Wang

[permalink] [raw]
Subject: [PATCH net-next] r8152: use mutex for hw settings

Use mutex to avoid that the serial hw settings would be interrupted
by other settings. Although there is no problem now, it makes the
driver more safe.

Signed-off-by: Hayes Wang <[email protected]>
---
drivers/net/usb/r8152.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 67 insertions(+), 2 deletions(-)

diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 6532620..4f99c43 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -26,7 +26,7 @@
#include <linux/mdio.h>

/* Version Information */
-#define DRIVER_VERSION "v1.06.1 (2014/10/01)"
+#define DRIVER_VERSION "v1.07.0 (2014/10/07)"
#define DRIVER_AUTHOR "Realtek linux nic maintainers <[email protected]>"
#define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
#define MODULENAME "r8152"
@@ -566,6 +566,7 @@ struct r8152 {
spinlock_t rx_lock, tx_lock;
struct delayed_work schedule;
struct mii_if_info mii;
+ struct mutex control; /* use for hw setting */

struct rtl_ops {
void (*init)(struct r8152 *);
@@ -984,12 +985,16 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;

+ mutex_lock(&tp->control);
+
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);

ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, 8, addr->sa_data);
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);

+ mutex_unlock(&tp->control);
+
return 0;
}

@@ -2139,6 +2144,8 @@ static int rtl8152_set_features(struct net_device *dev,
netdev_features_t changed = features ^ dev->features;
struct r8152 *tp = netdev_priv(dev);

+ mutex_lock(&tp->control);
+
if (changed & NETIF_F_HW_VLAN_CTAG_RX) {
if (features & NETIF_F_HW_VLAN_CTAG_RX)
rtl_rx_vlan_en(tp, true);
@@ -2146,6 +2153,8 @@ static int rtl8152_set_features(struct net_device *dev,
rtl_rx_vlan_en(tp, false);
}

+ mutex_unlock(&tp->control);
+
return 0;
}

@@ -2844,6 +2853,11 @@ static void rtl_work_func_t(struct work_struct *work)
if (test_bit(RTL8152_UNPLUG, &tp->flags))
goto out1;

+ if (!mutex_trylock(&tp->control)) {
+ schedule_delayed_work(&tp->schedule, 0);
+ goto out1;
+ }
+
if (test_bit(RTL8152_LINK_CHG, &tp->flags))
set_carrier(tp);

@@ -2859,6 +2873,8 @@ static void rtl_work_func_t(struct work_struct *work)
if (test_bit(PHY_RESET, &tp->flags))
rtl_phy_reset(tp);

+ mutex_unlock(&tp->control);
+
out1:
usb_autopm_put_interface(tp->intf);
}
@@ -2878,6 +2894,8 @@ static int rtl8152_open(struct net_device *netdev)
goto out;
}

+ mutex_lock(&tp->control);
+
/* The WORK_ENABLE may be set when autoresume occurs */
if (test_bit(WORK_ENABLE, &tp->flags)) {
clear_bit(WORK_ENABLE, &tp->flags);
@@ -2906,6 +2924,8 @@ static int rtl8152_open(struct net_device *netdev)
free_all_mem(tp);
}

+ mutex_unlock(&tp->control);
+
usb_autopm_put_interface(tp->intf);

out:
@@ -2926,6 +2946,8 @@ static int rtl8152_close(struct net_device *netdev)
if (res < 0) {
rtl_drop_queued_tx(tp);
} else {
+ mutex_lock(&tp->control);
+
/* The autosuspend may have been enabled and wouldn't
* be disable when autoresume occurs, because the
* netif_running() would be false.
@@ -2938,6 +2960,9 @@ static int rtl8152_close(struct net_device *netdev)
tasklet_disable(&tp->tl);
tp->rtl_ops.down(tp);
tasklet_enable(&tp->tl);
+
+ mutex_unlock(&tp->control);
+
usb_autopm_put_interface(tp->intf);
}

@@ -3162,6 +3187,8 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
{
struct r8152 *tp = usb_get_intfdata(intf);

+ mutex_lock(&tp->control);
+
if (PMSG_IS_AUTO(message))
set_bit(SELECTIVE_SUSPEND, &tp->flags);
else
@@ -3181,6 +3208,8 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
tasklet_enable(&tp->tl);
}

+ mutex_unlock(&tp->control);
+
return 0;
}

@@ -3188,6 +3217,8 @@ static int rtl8152_resume(struct usb_interface *intf)
{
struct r8152 *tp = usb_get_intfdata(intf);

+ mutex_lock(&tp->control);
+
if (!test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
tp->rtl_ops.init(tp);
netif_device_attach(tp->netdev);
@@ -3213,6 +3244,8 @@ static int rtl8152_resume(struct usb_interface *intf)
usb_submit_urb(tp->intr_urb, GFP_KERNEL);
}

+ mutex_unlock(&tp->control);
+
return 0;
}

@@ -3223,9 +3256,13 @@ static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
if (usb_autopm_get_interface(tp->intf) < 0)
return;

+ mutex_lock(&tp->control);
+
wol->supported = WAKE_ANY;
wol->wolopts = __rtl_get_wol(tp);

+ mutex_unlock(&tp->control);
+
usb_autopm_put_interface(tp->intf);
}

@@ -3238,9 +3275,13 @@ static int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
if (ret < 0)
goto out_set_wol;

+ mutex_lock(&tp->control);
+
__rtl_set_wol(tp, wol->wolopts);
tp->saved_wolopts = wol->wolopts & WAKE_ANY;

+ mutex_unlock(&tp->control);
+
usb_autopm_put_interface(tp->intf);

out_set_wol:
@@ -3275,11 +3316,18 @@ static
int rtl8152_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
{
struct r8152 *tp = netdev_priv(netdev);
+ int ret;

if (!tp->mii.mdio_read)
return -EOPNOTSUPP;

- return mii_ethtool_gset(&tp->mii, cmd);
+ mutex_lock(&tp->control);
+
+ ret = mii_ethtool_gset(&tp->mii, cmd);
+
+ mutex_unlock(&tp->control);
+
+ return ret;
}

static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -3291,8 +3339,12 @@ static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if (ret < 0)
goto out;

+ mutex_lock(&tp->control);
+
ret = rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex);

+ mutex_unlock(&tp->control);
+
usb_autopm_put_interface(tp->intf);

out:
@@ -3452,8 +3504,12 @@ rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *edata)
if (ret < 0)
goto out;

+ mutex_lock(&tp->control);
+
ret = tp->rtl_ops.eee_get(tp, edata);

+ mutex_unlock(&tp->control);
+
usb_autopm_put_interface(tp->intf);

out:
@@ -3470,10 +3526,14 @@ rtl_ethtool_set_eee(struct net_device *net, struct ethtool_eee *edata)
if (ret < 0)
goto out;

+ mutex_lock(&tp->control);
+
ret = tp->rtl_ops.eee_set(tp, edata);
if (!ret)
ret = mii_nway_restart(&tp->mii);

+ mutex_unlock(&tp->control);
+
usb_autopm_put_interface(tp->intf);

out:
@@ -3515,7 +3575,9 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
break;

case SIOCGMIIREG:
+ mutex_lock(&tp->control);
data->val_out = r8152_mdio_read(tp, data->reg_num);
+ mutex_unlock(&tp->control);
break;

case SIOCSMIIREG:
@@ -3523,7 +3585,9 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
res = -EPERM;
break;
}
+ mutex_lock(&tp->control);
r8152_mdio_write(tp, data->reg_num, data->val_in);
+ mutex_unlock(&tp->control);
break;

default:
@@ -3716,6 +3780,7 @@ static int rtl8152_probe(struct usb_interface *intf,
goto out;

tasklet_init(&tp->tl, bottom_half, (unsigned long)tp);
+ mutex_init(&tp->control);
INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t);

netdev->netdev_ops = &rtl8152_netdev_ops;
--
1.9.3


2014-10-08 19:45:19

by David Miller

[permalink] [raw]
Subject: Re: [PATCH net-next] r8152: use mutex for hw settings

From: Hayes Wang <[email protected]>
Date: Tue, 7 Oct 2014 13:36:30 +0800

> Use mutex to avoid that the serial hw settings would be interrupted
> by other settings. Although there is no problem now, it makes the
> driver more safe.
>
> Signed-off-by: Hayes Wang <[email protected]>

I think a much simpler fix is to take rtnl_lock() in the workqueue
function and suspend/resume ops.

Every other place you are adding the mutex already holds the RTNL
mutex.

2014-10-09 06:25:13

by Hayes Wang

[permalink] [raw]
Subject: [PATCH net-next] r8152: add rtnl_lock

Add rtnl_lock() for suspend/resume and workqueue.

Signed-off-by: Hayes Wang <[email protected]>
---
drivers/net/usb/r8152.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 5cfd414..2b2b679 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -26,7 +26,7 @@
#include <linux/mdio.h>

/* Version Information */
-#define DRIVER_VERSION "v1.06.1 (2014/10/01)"
+#define DRIVER_VERSION "v1.07.0 (2014/10/09)"
#define DRIVER_AUTHOR "Realtek linux nic maintainers <[email protected]>"
#define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
#define MODULENAME "r8152"
@@ -2851,6 +2851,11 @@ static void rtl_work_func_t(struct work_struct *work)
if (test_bit(RTL8152_UNPLUG, &tp->flags))
goto out1;

+ if (!rtnl_trylock()) {
+ schedule_delayed_work(&tp->schedule, 0);
+ goto out1;
+ }
+
if (test_bit(RTL8152_LINK_CHG, &tp->flags))
set_carrier(tp);

@@ -2866,6 +2871,8 @@ static void rtl_work_func_t(struct work_struct *work)
if (test_bit(PHY_RESET, &tp->flags))
rtl_phy_reset(tp);

+ rtnl_unlock();
+
out1:
usb_autopm_put_interface(tp->intf);
}
@@ -3169,6 +3176,8 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
{
struct r8152 *tp = usb_get_intfdata(intf);

+ rtnl_lock();
+
if (PMSG_IS_AUTO(message))
set_bit(SELECTIVE_SUSPEND, &tp->flags);
else
@@ -3188,6 +3197,8 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
tasklet_enable(&tp->tl);
}

+ rtnl_unlock();
+
return 0;
}

@@ -3195,6 +3206,8 @@ static int rtl8152_resume(struct usb_interface *intf)
{
struct r8152 *tp = usb_get_intfdata(intf);

+ rtnl_lock();
+
if (!test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
tp->rtl_ops.init(tp);
netif_device_attach(tp->netdev);
@@ -3220,6 +3233,8 @@ static int rtl8152_resume(struct usb_interface *intf)
usb_submit_urb(tp->intr_urb, GFP_KERNEL);
}

+ rtnl_unlock();
+
return 0;
}

--
1.9.3

2014-10-09 07:59:53

by Hayes Wang

[permalink] [raw]
Subject: RE: [PATCH net-next] r8152: add rtnl_lock

> -----Original Message-----
> From: Hayes Wang
> Sent: Thursday, October 09, 2014 2:25 PM
> To: [email protected]
> Cc: nic_swsd; [email protected];
> [email protected]; Hayes Wang
> Subject: [PATCH net-next] r8152: add rtnl_lock
>
> Add rtnl_lock() for suspend/resume and workqueue.
>
> Signed-off-by: Hayes Wang <[email protected]>

Excuse me. The patch has the dead lock issue when
enabling autosuspend. Please ignore this patch.

Best Regards,
Hayes

2014-10-09 08:00:03

by Hayes Wang

[permalink] [raw]
Subject: RE: [PATCH net-next] r8152: use mutex for hw settings

David Miller [mailto:[email protected]]
> Sent: Thursday, October 09, 2014 3:45 AM
[..]
> I think a much simpler fix is to take rtnl_lock() in the workqueue
> function and suspend/resume ops.
>
> Every other place you are adding the mutex already holds the RTNL
> mutex.

If I use the rtnl_lock(), I get a dead lock when enabling autosuspend.

Case 1:
autosuspend before calling open.
rtnl_lock()
call open
try to autoresume and rtl8152_resume is called.
dead lock occurs.

Case 2:
autosuspend occurs.
rtnl_lock()
call close
try to autoresume and rtl8152_resume is called.
dead lock occurs.

Best Regards,
Hayes

2014-10-09 10:00:49

by Hayes Wang

[permalink] [raw]
Subject: [PATCH net-next v2 0/3] r8152: use mutex for hw settings

v2:
Make sure the autoresume wouldn't occur inside the mutex, otherwise
the dead lock would happen. For the purpose, adjust some code about
autosuspend/autoresume.

v1:
Use mutex to avoid that the serial hw settings would be interrupted
by other settings. Although there is no problem now, it makes the
driver more safe.

Hayes Wang (3):
r8152: autoresume before setting feature
r8152: adjust usb_autopm_xxx
r8152: add mutex for hw settings

drivers/net/usb/r8152.c | 98 +++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 83 insertions(+), 15 deletions(-)

--
1.9.3

2014-10-09 10:01:07

by Hayes Wang

[permalink] [raw]
Subject: [PATCH net-next v2 3/3] r8152: add mutex for hw settings

Use the mutex to avoid the settings are interrupted by other ones.

Signed-off-by: Hayes Wang <[email protected]>
---
drivers/net/usb/r8152.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 63 insertions(+), 1 deletion(-)

diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 1d2fc8e..864159e 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -26,7 +26,7 @@
#include <linux/mdio.h>

/* Version Information */
-#define DRIVER_VERSION "v1.06.1 (2014/10/01)"
+#define DRIVER_VERSION "v1.07.0 (2014/10/09)"
#define DRIVER_AUTHOR "Realtek linux nic maintainers <[email protected]>"
#define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
#define MODULENAME "r8152"
@@ -566,6 +566,7 @@ struct r8152 {
spinlock_t rx_lock, tx_lock;
struct delayed_work schedule;
struct mii_if_info mii;
+ struct mutex control; /* use for hw setting */

struct rtl_ops {
void (*init)(struct r8152 *);
@@ -977,12 +978,16 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
if (ret < 0)
goto out1;

+ mutex_lock(&tp->control);
+
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);

ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, 8, addr->sa_data);
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);

+ mutex_unlock(&tp->control);
+
usb_autopm_put_interface(tp->intf);
out1:
return ret;
@@ -2139,6 +2144,8 @@ static int rtl8152_set_features(struct net_device *dev,
if (ret < 0)
goto out;

+ mutex_lock(&tp->control);
+
if (changed & NETIF_F_HW_VLAN_CTAG_RX) {
if (features & NETIF_F_HW_VLAN_CTAG_RX)
rtl_rx_vlan_en(tp, true);
@@ -2146,6 +2153,8 @@ static int rtl8152_set_features(struct net_device *dev,
rtl_rx_vlan_en(tp, false);
}

+ mutex_unlock(&tp->control);
+
usb_autopm_put_interface(tp->intf);

out:
@@ -2847,6 +2856,11 @@ static void rtl_work_func_t(struct work_struct *work)
if (test_bit(RTL8152_UNPLUG, &tp->flags))
goto out1;

+ if (!mutex_trylock(&tp->control)) {
+ schedule_delayed_work(&tp->schedule, 0);
+ goto out1;
+ }
+
if (test_bit(RTL8152_LINK_CHG, &tp->flags))
set_carrier(tp);

@@ -2862,6 +2876,8 @@ static void rtl_work_func_t(struct work_struct *work)
if (test_bit(PHY_RESET, &tp->flags))
rtl_phy_reset(tp);

+ mutex_unlock(&tp->control);
+
out1:
usb_autopm_put_interface(tp->intf);
}
@@ -2881,6 +2897,8 @@ static int rtl8152_open(struct net_device *netdev)
goto out;
}

+ mutex_lock(&tp->control);
+
/* The WORK_ENABLE may be set when autoresume occurs */
if (test_bit(WORK_ENABLE, &tp->flags)) {
clear_bit(WORK_ENABLE, &tp->flags);
@@ -2909,6 +2927,8 @@ static int rtl8152_open(struct net_device *netdev)
free_all_mem(tp);
}

+ mutex_unlock(&tp->control);
+
usb_autopm_put_interface(tp->intf);

out:
@@ -2929,6 +2949,8 @@ static int rtl8152_close(struct net_device *netdev)
if (res < 0) {
rtl_drop_queued_tx(tp);
} else {
+ mutex_lock(&tp->control);
+
/* The autosuspend may have been enabled and wouldn't
* be disable when autoresume occurs, because the
* netif_running() would be false.
@@ -2941,6 +2963,9 @@ static int rtl8152_close(struct net_device *netdev)
tasklet_disable(&tp->tl);
tp->rtl_ops.down(tp);
tasklet_enable(&tp->tl);
+
+ mutex_unlock(&tp->control);
+
usb_autopm_put_interface(tp->intf);
}

@@ -3165,6 +3190,8 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
{
struct r8152 *tp = usb_get_intfdata(intf);

+ mutex_lock(&tp->control);
+
if (PMSG_IS_AUTO(message))
set_bit(SELECTIVE_SUSPEND, &tp->flags);
else
@@ -3184,6 +3211,8 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
tasklet_enable(&tp->tl);
}

+ mutex_unlock(&tp->control);
+
return 0;
}

@@ -3191,6 +3220,8 @@ static int rtl8152_resume(struct usb_interface *intf)
{
struct r8152 *tp = usb_get_intfdata(intf);

+ mutex_lock(&tp->control);
+
if (!test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
tp->rtl_ops.init(tp);
netif_device_attach(tp->netdev);
@@ -3216,6 +3247,8 @@ static int rtl8152_resume(struct usb_interface *intf)
usb_submit_urb(tp->intr_urb, GFP_KERNEL);
}

+ mutex_unlock(&tp->control);
+
return 0;
}

@@ -3226,9 +3259,13 @@ static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
if (usb_autopm_get_interface(tp->intf) < 0)
return;

+ mutex_lock(&tp->control);
+
wol->supported = WAKE_ANY;
wol->wolopts = __rtl_get_wol(tp);

+ mutex_unlock(&tp->control);
+
usb_autopm_put_interface(tp->intf);
}

@@ -3241,9 +3278,13 @@ static int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
if (ret < 0)
goto out_set_wol;

+ mutex_lock(&tp->control);
+
__rtl_set_wol(tp, wol->wolopts);
tp->saved_wolopts = wol->wolopts & WAKE_ANY;

+ mutex_unlock(&tp->control);
+
usb_autopm_put_interface(tp->intf);

out_set_wol:
@@ -3287,8 +3328,12 @@ int rtl8152_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
if (ret < 0)
goto out;

+ mutex_lock(&tp->control);
+
ret = mii_ethtool_gset(&tp->mii, cmd);

+ mutex_unlock(&tp->control);
+
usb_autopm_put_interface(tp->intf);

out:
@@ -3304,8 +3349,12 @@ static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if (ret < 0)
goto out;

+ mutex_lock(&tp->control);
+
ret = rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex);

+ mutex_unlock(&tp->control);
+
usb_autopm_put_interface(tp->intf);

out:
@@ -3465,8 +3514,12 @@ rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *edata)
if (ret < 0)
goto out;

+ mutex_lock(&tp->control);
+
ret = tp->rtl_ops.eee_get(tp, edata);

+ mutex_unlock(&tp->control);
+
usb_autopm_put_interface(tp->intf);

out:
@@ -3483,10 +3536,14 @@ rtl_ethtool_set_eee(struct net_device *net, struct ethtool_eee *edata)
if (ret < 0)
goto out;

+ mutex_lock(&tp->control);
+
ret = tp->rtl_ops.eee_set(tp, edata);
if (!ret)
ret = mii_nway_restart(&tp->mii);

+ mutex_unlock(&tp->control);
+
usb_autopm_put_interface(tp->intf);

out:
@@ -3528,7 +3585,9 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
break;

case SIOCGMIIREG:
+ mutex_lock(&tp->control);
data->val_out = r8152_mdio_read(tp, data->reg_num);
+ mutex_unlock(&tp->control);
break;

case SIOCSMIIREG:
@@ -3536,7 +3595,9 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
res = -EPERM;
break;
}
+ mutex_lock(&tp->control);
r8152_mdio_write(tp, data->reg_num, data->val_in);
+ mutex_unlock(&tp->control);
break;

default:
@@ -3729,6 +3790,7 @@ static int rtl8152_probe(struct usb_interface *intf,
goto out;

tasklet_init(&tp->tl, bottom_half, (unsigned long)tp);
+ mutex_init(&tp->control);
INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t);

netdev->netdev_ops = &rtl8152_netdev_ops;
--
1.9.3

2014-10-09 10:01:14

by Hayes Wang

[permalink] [raw]
Subject: [PATCH net-next v2 2/3] r8152: adjust usb_autopm_xxx

Add usb_autopm_xxx for rtl8152_get_settings() ,and remove
usb_autopm_xxx from read_mii_word() and write_mii_word().

Signed-off-by: Hayes Wang <[email protected]>
---
drivers/net/usb/r8152.c | 24 +++++++++++-------------
1 file changed, 11 insertions(+), 13 deletions(-)

diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index c5afe8c..1d2fc8e 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -942,15 +942,8 @@ static int read_mii_word(struct net_device *netdev, int phy_id, int reg)
if (phy_id != R8152_PHY_ID)
return -EINVAL;

- ret = usb_autopm_get_interface(tp->intf);
- if (ret < 0)
- goto out;
-
ret = r8152_mdio_read(tp, reg);

- usb_autopm_put_interface(tp->intf);
-
-out:
return ret;
}

@@ -965,12 +958,7 @@ void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val)
if (phy_id != R8152_PHY_ID)
return;

- if (usb_autopm_get_interface(tp->intf) < 0)
- return;
-
r8152_mdio_write(tp, reg, val);
-
- usb_autopm_put_interface(tp->intf);
}

static int
@@ -3290,11 +3278,21 @@ static
int rtl8152_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
{
struct r8152 *tp = netdev_priv(netdev);
+ int ret;

if (!tp->mii.mdio_read)
return -EOPNOTSUPP;

- return mii_ethtool_gset(&tp->mii, cmd);
+ ret = usb_autopm_get_interface(tp->intf);
+ if (ret < 0)
+ goto out;
+
+ ret = mii_ethtool_gset(&tp->mii, cmd);
+
+ usb_autopm_put_interface(tp->intf);
+
+out:
+ return ret;
}

static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
--
1.9.3

2014-10-09 10:01:20

by Hayes Wang

[permalink] [raw]
Subject: [PATCH net-next v2 1/3] r8152: autoresume before setting feature

Resume the device before setting the feature.

Signed-off-by: Hayes Wang <[email protected]>
---
drivers/net/usb/r8152.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 5cfd414..c5afe8c 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -2145,6 +2145,11 @@ static int rtl8152_set_features(struct net_device *dev,
{
netdev_features_t changed = features ^ dev->features;
struct r8152 *tp = netdev_priv(dev);
+ int ret;
+
+ ret = usb_autopm_get_interface(tp->intf);
+ if (ret < 0)
+ goto out;

if (changed & NETIF_F_HW_VLAN_CTAG_RX) {
if (features & NETIF_F_HW_VLAN_CTAG_RX)
@@ -2153,7 +2158,10 @@ static int rtl8152_set_features(struct net_device *dev,
rtl_rx_vlan_en(tp, false);
}

- return 0;
+ usb_autopm_put_interface(tp->intf);
+
+out:
+ return ret;
}

#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
--
1.9.3

2014-10-09 23:05:22

by David Miller

[permalink] [raw]
Subject: Re: [PATCH net-next] r8152: use mutex for hw settings

From: Hayes Wang <[email protected]>
Date: Thu, 9 Oct 2014 07:59:35 +0000

> If I use the rtnl_lock(), I get a dead lock when enabling autosuspend.
>
> Case 1:
> autosuspend before calling open.
> rtnl_lock()
> call open
> try to autoresume and rtl8152_resume is called.
> dead lock occurs.
>
> Case 2:
> autosuspend occurs.
> rtnl_lock()
> call close
> try to autoresume and rtl8152_resume is called.
> dead lock occurs.

That's really unfortunate that we can variably get into the resume
handlers from contexts holding the RTNL mutex.

2014-10-09 23:06:35

by David Miller

[permalink] [raw]
Subject: Re: [PATCH net-next v2 0/3] r8152: use mutex for hw settings

From: Hayes Wang <[email protected]>
Date: Thu, 9 Oct 2014 18:00:23 +0800

> v2:
> Make sure the autoresume wouldn't occur inside the mutex, otherwise
> the dead lock would happen. For the purpose, adjust some code about
> autosuspend/autoresume.
>
> v1:
> Use mutex to avoid that the serial hw settings would be interrupted
> by other settings. Although there is no problem now, it makes the
> driver more safe.

Series applied, thanks.