Hi, After the PCI PM core code has been updated, PCI network drivers (especially those using pci_enable_wake() for setting up WOL) should be adapted to it. This series of patches modifies three drivers, skge, sky2 and e100, for this purpose. [Note for Andrew: Patch 1/3 has been in -mm for some time, but the present one has a better changelog (IMO).] Please consider for applying. Thanks, Rafael --
Adapt the sky2 driver to the reworked PCI PM
* Use device_set_wakeup_enable() and friends as needed
* Remove an open-coded reference to the standard PCI PM registers
* Use pci_prepare_to_sleep() and pci_back_from_sleep() in the
->suspend() and ->resume() callbacks
* Use the observation that it is sufficient to call pci_enable_wake()
once, unless it fails
Tested on Asus M3A32-MVP (Yukon-2 EC Ultra rev 3).
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/net/sky2.c | 34 ++++++++++------------------------
1 file changed, 10 insertions(+), 24 deletions(-)
Index: linux-2.6/drivers/net/sky2.c
===================================================================
--- linux-2.6.orig/drivers/net/sky2.c
+++ linux-2.6/drivers/net/sky2.c
@@ -3035,7 +3035,8 @@ static int sky2_set_wol(struct net_devic
struct sky2_port *sky2 = netdev_priv(dev);
struct sky2_hw *hw = sky2->hw;
- if (wol->wolopts & ~sky2_wol_supported(sky2->hw))
+ if ((wol->wolopts & ~sky2_wol_supported(sky2->hw))
+ || !device_can_wakeup(&hw->pdev->dev))
return -EOPNOTSUPP;
sky2->wol = wol->wolopts;
@@ -3046,6 +3047,8 @@ static int sky2_set_wol(struct net_devic
sky2_write32(hw, B0_CTST, sky2->wol
? Y2_HW_WOL_ON : Y2_HW_WOL_OFF);
+ device_set_wakeup_enable(&hw->pdev->dev, sky2->wol);
+
if (!netif_running(dev))
sky2_wol_init(sky2);
return 0;
@@ -4167,18 +4170,6 @@ static int __devinit sky2_test_msi(struc
return err;
}
-static int __devinit pci_wake_enabled(struct pci_dev *dev)
-{
- int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
- u16 value;
-
- if (!pm)
- return 0;
- if (pci_read_config_word(dev, pm + PCI_PM_CTRL, &value))
- return 0;
- return value & PCI_PM_CTRL_PME_ENABLE;
-}
-
/* This driver supports yukon2 chipset only */
static const char *sky2_name(u8 chipid, char *buf, int sz)
{
@@ -4239,7 +4230,7 @@ static int __devinit sky2_probe(struct p
}
}
- wol_default = pci_wake_enabled(pdev) ? WAKE_MAGIC : 0;
+ wol_default = ...On Thu, 14 Aug 2008 23:38:17 +0200 There was a regression in earlier releases caused because some BIOS's are wrong, and device can wakeup. --
device_can_wakeup() returns 'true' if the device is capable of generating PME# from at least one low power state (this is determined on the basis of the contents of the device's PCI PM registers - please have a look at drivers/pci/pci_pm_init() for details) or if ACPI tells us it can wake up. IOW, the BIOSes opinion doesn't matter if we find that the device is capable of generating PME#, so the regression must have been related to something else. I'm very interested in the details, if available. Of course, since we rely on the ability of the device to generate PME# and device_can_wakeup() returning 'false' means that the device cannot generate PME# from any state, it's reasonable to check it IMO. Thanks, Rafael --
drivers/pci/pci.c:pci_pm_init(), sorry. --
BTW, if device_can_wakeup(&pdev->dev) returns 'false', pci_enable_wake(pdev, state, true) will fail for any 'state', so the wake-up won't work regardless of the change above. Thanks, Rafael --
On Fri, 15 Aug 2008 15:32:13 +0200 Okay, the problem was false positives from ACPI. It looks like this won't make the problem any worse. --
[Note: I have no hardware to test this patch, but it seems pretty
straightforward.]
Adapt the e100 driver to the reworked PCI PM
* Use device_set_wakeup_enable() and friends as needed
* Use pci_pme_active() to clear PME_Status and disable PME#
* Use the observation that it is sufficient to call pci_enable_wake()
once, unless it fails
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/net/e100.c | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
Index: linux-2.6/drivers/net/e100.c
===================================================================
--- linux-2.6.orig/drivers/net/e100.c
+++ linux-2.6/drivers/net/e100.c
@@ -2322,7 +2322,8 @@ static int e100_set_wol(struct net_devic
{
struct nic *nic = netdev_priv(netdev);
- if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
+ if ((wol->wolopts && wol->wolopts != WAKE_MAGIC) ||
+ !device_can_wakeup(&nic->pdev->dev))
return -EOPNOTSUPP;
if(wol->wolopts)
@@ -2330,6 +2331,8 @@ static int e100_set_wol(struct net_devic
else
nic->flags &= ~wol_magic;
+ device_set_wakeup_enable(&nic->pdev->dev, wol->wolopts);
+
e100_exec_cb(nic, NULL, e100_configure);
return 0;
@@ -2734,13 +2737,13 @@ static int __devinit e100_probe(struct p
/* Wol magic packet can be enabled from eeprom */
if((nic->mac >= mac_82558_D101_A4) &&
- (nic->eeprom[eeprom_id] & eeprom_id_wol))
+ (nic->eeprom[eeprom_id] & eeprom_id_wol)) {
nic->flags |= wol_magic;
+ device_set_wakeup_enable(&pdev->dev, true);
+ }
/* ack any pending wake events, disable PME */
- err = pci_enable_wake(pdev, 0, 0);
- if (err)
- DPRINTK(PROBE, ERR, "Error clearing wake event\n");
+ pci_pme_active(pdev, false);
strcpy(netdev->name, "eth%d");
if((err = register_netdev(netdev))) {
@@ -2796,11 +2799,10 @@ static int e100_suspend(struct pci_dev *
pci_save_state(pdev);
if ((nic->flags & wol_magic) | e100_asf(nic)) {
- pci_enable_wake(pdev, PCI_D3hot, ...We have tested the patch in our labs and systems wake from S5 just fine. Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> -- Cheers, Jeff --
From: Rafael J. Wysocki <rjw@sisk.pl>
Adapt the skge driver to the reworked PCI PM
* Use device_set_wakeup_enable() and friends as needed
* Remove an open-coded reference to the standard PCI PM registers
* Use pci_prepare_to_sleep() and pci_back_from_sleep() in the
->suspend() and ->resume() callbacks
* Use the observation that it is sufficient to call pci_enable_wake()
once, unless it fails
Tested on Asus L5D (Yukon-Lite rev 7).
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/net/skge.c | 38 +++++++++++---------------------------
1 file changed, 11 insertions(+), 27 deletions(-)
Index: linux-next/drivers/net/skge.c
===================================================================
--- linux-next.orig/drivers/net/skge.c
+++ linux-next/drivers/net/skge.c
@@ -149,24 +149,6 @@ static u32 wol_supported(const struct sk
return WAKE_MAGIC | WAKE_PHY;
}
-static u32 pci_wake_enabled(struct pci_dev *dev)
-{
- int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
- u16 value;
-
- /* If device doesn't support PM Capabilities, but request is to disable
- * wake events, it's a nop; otherwise fail */
- if (!pm)
- return 0;
-
- pci_read_config_word(dev, pm + PCI_PM_PMC, &value);
-
- value &= PCI_PM_CAP_PME_MASK;
- value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */
-
- return value != 0;
-}
-
static void skge_wol_init(struct skge_port *skge)
{
struct skge_hw *hw = skge->hw;
@@ -254,10 +236,14 @@ static int skge_set_wol(struct net_devic
struct skge_port *skge = netdev_priv(dev);
struct skge_hw *hw = skge->hw;
- if (wol->wolopts & ~wol_supported(hw))
+ if ((wol->wolopts & ~wol_supported(hw))
+ || !device_can_wakeup(&hw->pdev->dev))
return -EOPNOTSUPP;
skge->wol = wol->wolopts;
+
+ device_set_wakeup_enable(&hw->pdev->dev, skge->wol);
+
return 0;
}
@@ -3842,7 +3828,7 @@ static struct net_device *skge_devinit(s
skge->speed = -1;
skge->advertising = skge_supported_modes(hw);
- if ...