diff mbox

[net,1/3] r8169:fix nic sometimes doesn't work after changing the mac address.

Message ID 1456476046-5436-2-git-send-email-hau@realtek.com
State Changes Requested, archived
Delegated to: David Miller
Headers show

Commit Message

Hau Feb. 26, 2016, 8:40 a.m. UTC
When there is no AC power, NIC doesn't work after changing mac address.
Please refer to following link.
http://www.spinics.net/lists/netdev/msg356572.html

This issue is caused by runtime power management. When there is no AC power, if we
put NIC down (ifconfig down), the driver will be put in runtime suspend state and
device will in D3 state. In this time, driver cannot access hardware regisers. So
if you set new mac address during this time, it will not work. And then, after
resume, the NIC will keep using the old mac address and so the network will not
work normally.

In this patch I add detecting runtime pm state when setting mac address. If
driver is in runtime suspend, I will skip setting mac address and  set the new
mac address during runtime resume.

Signed-off-by: Chunhao Lin <hau@realtek.com>
---
 drivers/net/ethernet/realtek/r8169.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

Comments

Francois Romieu Feb. 26, 2016, 11:31 p.m. UTC | #1
Chunhao Lin <hau@realtek.com> :
> When there is no AC power, NIC doesn't work after changing mac address.
> Please refer to following link.
> http://www.spinics.net/lists/netdev/msg356572.html
> 
> This issue is caused by runtime power management. When there is no AC power, if we
> put NIC down (ifconfig down), the driver will be put in runtime suspend state and
> device will in D3 state. In this time, driver cannot access hardware regisers. So
> if you set new mac address during this time, it will not work. And then, after
> resume, the NIC will keep using the old mac address and so the network will not
> work normally.
> 
> In this patch I add detecting runtime pm state when setting mac address. If
> driver is in runtime suspend, I will skip setting mac address and  set the new
> mac address during runtime resume.

Instead of taking the device out of suspended mode to perform the required
action, the driver is moving to a model where 1) said action may be scheduled
to a later time - or result from past time work - and 2) rpm handler must
handle a lot of pm unrelated work.

rtl8169_ethtool_ops.{get_wol, get_regs, get_settings} aren't even fixed
yet (what about the .set_xyz handlers ?).

I can't help thinking that the driver should return to a state where it
stupidly does what it is asked to. No software caching, plain device
access, resume when needed, suspend as "suspend" instead of suspend as
"anticipate whatever may happen to avoid waking up".
Hau Feb. 27, 2016, 6:19 p.m. UTC | #2
> Instead of taking the device out of suspended mode to perform the required
> action, the driver is moving to a model where 1) said action may be
> scheduled to a later time - or result from past time work - and 2) rpm handler
> must handle a lot of pm unrelated work.
> 
> rtl8169_ethtool_ops.{get_wol, get_regs, get_settings} aren't even fixed yet
> (what about the .set_xyz handlers ?).
> 
> I can't help thinking that the driver should return to a state where it stupidly
> does what it is asked to. No software caching, plain device access, resume
> when needed, suspend as "suspend" instead of suspend as "anticipate
> whatever may happen to avoid waking up".
>

This rpm related patches just the workaround for the issues reported by end users.  As you say, the Linux kernel should handle these events when driver is in runtime suspend state.
 
------Please consider the environment before printing this e-mail.
diff mbox

Patch

diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 4caeacb..432b278 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -4457,6 +4457,7 @@  static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr)
 static int rtl_set_mac_address(struct net_device *dev, void *p)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
+	struct pci_dev *pdev = tp->pci_dev;
 	struct sockaddr *addr = p;
 
 	if (!is_valid_ether_addr(addr->sa_data))
@@ -4464,7 +4465,12 @@  static int rtl_set_mac_address(struct net_device *dev, void *p)
 
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 
-	rtl_rar_set(tp, dev->dev_addr);
+	pm_runtime_get_noresume(&pdev->dev);
+
+	if (pm_runtime_active(&pdev->dev))
+		rtl_rar_set(tp, dev->dev_addr);
+
+	pm_runtime_put_noidle(&pdev->dev);
 
 	return 0;
 }
@@ -7872,6 +7878,8 @@  static int rtl8169_runtime_resume(struct device *device)
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct rtl8169_private *tp = netdev_priv(dev);
 
+	rtl_rar_set(tp, dev->dev_addr);
+
 	if (!tp->TxDescArray)
 		return 0;