Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 193608
b: refs/heads/master
c: e175944
h: refs/heads/master
v: v3
  • Loading branch information
Rafael J. Wysocki authored and David S. Miller committed Mar 17, 2010
1 parent bd8bab5 commit 08d5710
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 28 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ff6e2163f28a1094fb5ca5950fe2b43c3cf6bc7a
refs/heads/master: e175944115db6762d3e98520c709e5a87f933c61
152 changes: 125 additions & 27 deletions trunk/drivers/net/r8169.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <linux/tcp.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/pm_runtime.h>

#include <asm/system.h>
#include <asm/io.h>
Expand Down Expand Up @@ -504,6 +505,7 @@ struct rtl8169_private {

struct mii_if_info mii;
struct rtl8169_counters counters;
u32 saved_wolopts;
};

MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
Expand Down Expand Up @@ -744,53 +746,61 @@ static void rtl8169_check_link_status(struct net_device *dev,

spin_lock_irqsave(&tp->lock, flags);
if (tp->link_ok(ioaddr)) {
/* This is to cancel a scheduled suspend if there's one. */
pm_request_resume(&tp->pci_dev->dev);
netif_carrier_on(dev);
netif_info(tp, ifup, dev, "link up\n");
} else {
netif_carrier_off(dev);
netif_info(tp, ifdown, dev, "link down\n");
pm_schedule_suspend(&tp->pci_dev->dev, 100);
}
spin_unlock_irqrestore(&tp->lock, flags);
}

static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)

static u32 __rtl8169_get_wol(struct rtl8169_private *tp)
{
struct rtl8169_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
u8 options;

wol->wolopts = 0;

#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
wol->supported = WAKE_ANY;

spin_lock_irq(&tp->lock);
u32 wolopts = 0;

options = RTL_R8(Config1);
if (!(options & PMEnable))
goto out_unlock;
return 0;

options = RTL_R8(Config3);
if (options & LinkUp)
wol->wolopts |= WAKE_PHY;
wolopts |= WAKE_PHY;
if (options & MagicPacket)
wol->wolopts |= WAKE_MAGIC;
wolopts |= WAKE_MAGIC;

options = RTL_R8(Config5);
if (options & UWF)
wol->wolopts |= WAKE_UCAST;
wolopts |= WAKE_UCAST;
if (options & BWF)
wol->wolopts |= WAKE_BCAST;
wolopts |= WAKE_BCAST;
if (options & MWF)
wol->wolopts |= WAKE_MCAST;
wolopts |= WAKE_MCAST;

out_unlock:
spin_unlock_irq(&tp->lock);
return wolopts;
}

static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct rtl8169_private *tp = netdev_priv(dev);

spin_lock_irq(&tp->lock);

wol->supported = WAKE_ANY;
wol->wolopts = __rtl8169_get_wol(tp);

spin_unlock_irq(&tp->lock);
}

static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
{
void __iomem *ioaddr = tp->mmio_addr;
unsigned int i;
static const struct {
Expand All @@ -807,23 +817,29 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{ WAKE_ANY, Config5, LanWake }
};

spin_lock_irq(&tp->lock);

RTL_W8(Cfg9346, Cfg9346_Unlock);

for (i = 0; i < ARRAY_SIZE(cfg); i++) {
u8 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
if (wol->wolopts & cfg[i].opt)
if (wolopts & cfg[i].opt)
options |= cfg[i].mask;
RTL_W8(cfg[i].reg, options);
}

RTL_W8(Cfg9346, Cfg9346_Lock);
}

static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct rtl8169_private *tp = netdev_priv(dev);

spin_lock_irq(&tp->lock);

if (wol->wolopts)
tp->features |= RTL_FEATURE_WOL;
else
tp->features &= ~RTL_FEATURE_WOL;
__rtl8169_set_wol(tp, wol->wolopts);
device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts);

spin_unlock_irq(&tp->lock);
Expand Down Expand Up @@ -3189,6 +3205,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)

device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);

if (pci_dev_run_wake(pdev)) {
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
}
pm_runtime_idle(&pdev->dev);

out:
return rc;

Expand All @@ -3211,10 +3233,18 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
struct rtl8169_private *tp = netdev_priv(dev);

pm_runtime_get_sync(&pdev->dev);

flush_scheduled_work();

unregister_netdev(dev);

if (pci_dev_run_wake(pdev)) {
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
}
pm_runtime_put_noidle(&pdev->dev);

/* restore original MAC address */
rtl_rar_set(tp, dev->perm_addr);

Expand All @@ -3237,6 +3267,7 @@ static int rtl8169_open(struct net_device *dev)
struct pci_dev *pdev = tp->pci_dev;
int retval = -ENOMEM;

pm_runtime_get_sync(&pdev->dev);

rtl8169_set_rxbufsize(tp, dev);

Expand All @@ -3247,7 +3278,7 @@ static int rtl8169_open(struct net_device *dev)
tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES,
&tp->TxPhyAddr);
if (!tp->TxDescArray)
goto out;
goto err_pm_runtime_put;

tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES,
&tp->RxPhyAddr);
Expand All @@ -3274,6 +3305,9 @@ static int rtl8169_open(struct net_device *dev)

rtl8169_request_timer(dev);

tp->saved_wolopts = 0;
pm_runtime_put_noidle(&pdev->dev);

rtl8169_check_link_status(dev, tp, tp->mmio_addr);
out:
return retval;
Expand All @@ -3283,9 +3317,13 @@ static int rtl8169_open(struct net_device *dev)
err_free_rx_1:
pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray,
tp->RxPhyAddr);
tp->RxDescArray = NULL;
err_free_tx_0:
pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray,
tp->TxPhyAddr);
tp->TxDescArray = NULL;
err_pm_runtime_put:
pm_runtime_put_noidle(&pdev->dev);
goto out;
}

Expand Down Expand Up @@ -4692,6 +4730,8 @@ static int rtl8169_close(struct net_device *dev)
struct rtl8169_private *tp = netdev_priv(dev);
struct pci_dev *pdev = tp->pci_dev;

pm_runtime_get_sync(&pdev->dev);

/* update counters before going down */
rtl8169_update_counters(dev);

Expand All @@ -4706,6 +4746,8 @@ static int rtl8169_close(struct net_device *dev)
tp->TxDescArray = NULL;
tp->RxDescArray = NULL;

pm_runtime_put_sync(&pdev->dev);

return 0;
}

Expand Down Expand Up @@ -4804,28 +4846,84 @@ static int rtl8169_suspend(struct device *device)
return 0;
}

static void __rtl8169_resume(struct net_device *dev)
{
netif_device_attach(dev);
rtl8169_schedule_work(dev, rtl8169_reset_task);
}

static int rtl8169_resume(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct net_device *dev = pci_get_drvdata(pdev);

if (!netif_running(dev))
goto out;
if (netif_running(dev))
__rtl8169_resume(dev);

netif_device_attach(dev);
return 0;
}

static int rtl8169_runtime_suspend(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct net_device *dev = pci_get_drvdata(pdev);
struct rtl8169_private *tp = netdev_priv(dev);

if (!tp->TxDescArray)
return 0;

spin_lock_irq(&tp->lock);
tp->saved_wolopts = __rtl8169_get_wol(tp);
__rtl8169_set_wol(tp, WAKE_ANY);
spin_unlock_irq(&tp->lock);

rtl8169_net_suspend(dev);

return 0;
}

static int rtl8169_runtime_resume(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct net_device *dev = pci_get_drvdata(pdev);
struct rtl8169_private *tp = netdev_priv(dev);

if (!tp->TxDescArray)
return 0;

spin_lock_irq(&tp->lock);
__rtl8169_set_wol(tp, tp->saved_wolopts);
tp->saved_wolopts = 0;
spin_unlock_irq(&tp->lock);

__rtl8169_resume(dev);

rtl8169_schedule_work(dev, rtl8169_reset_task);
out:
return 0;
}

static int rtl8169_runtime_idle(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct net_device *dev = pci_get_drvdata(pdev);
struct rtl8169_private *tp = netdev_priv(dev);

if (!tp->TxDescArray)
return 0;

rtl8169_check_link_status(dev, tp, tp->mmio_addr);
return -EBUSY;
}

static const struct dev_pm_ops rtl8169_pm_ops = {
.suspend = rtl8169_suspend,
.resume = rtl8169_resume,
.freeze = rtl8169_suspend,
.thaw = rtl8169_resume,
.poweroff = rtl8169_suspend,
.restore = rtl8169_resume,
.runtime_suspend = rtl8169_runtime_suspend,
.runtime_resume = rtl8169_runtime_resume,
.runtime_idle = rtl8169_runtime_idle,
};

#define RTL8169_PM_OPS (&rtl8169_pm_ops)
Expand Down

0 comments on commit 08d5710

Please sign in to comment.