aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorSteven Walter <stevenrwalter@gmail.com>2010-05-31 08:34:43 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-01 03:15:51 -0400
commitdb6f30078dcb0117336f20275e4828c86132e46e (patch)
tree2fb0213d26c06ceb98b0b8b4ad47afde8ef9a71e /drivers/net
parent7a1d7f01b5e90f85d0b4ec4bfd5a5da769d2bb1d (diff)
tulip: implement wake-on-lan support
Based on a patch from http://simon.baatz.info/wol-support-for-an983b/ Tested to resume from suspend by magic packet. Signed-off-by: Steven Walter <stevenrwalter@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/tulip/tulip.h64
-rw-r--r--drivers/net/tulip/tulip_core.c115
2 files changed, 156 insertions, 23 deletions
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 0afa2d4f9472..e525875ed67d 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -20,6 +20,7 @@
20#include <linux/types.h> 20#include <linux/types.h>
21#include <linux/spinlock.h> 21#include <linux/spinlock.h>
22#include <linux/netdevice.h> 22#include <linux/netdevice.h>
23#include <linux/ethtool.h>
23#include <linux/timer.h> 24#include <linux/timer.h>
24#include <linux/delay.h> 25#include <linux/delay.h>
25#include <linux/pci.h> 26#include <linux/pci.h>
@@ -51,22 +52,23 @@ struct tulip_chip_table {
51 52
52 53
53enum tbl_flag { 54enum tbl_flag {
54 HAS_MII = 0x0001, 55 HAS_MII = 0x00001,
55 HAS_MEDIA_TABLE = 0x0002, 56 HAS_MEDIA_TABLE = 0x00002,
56 CSR12_IN_SROM = 0x0004, 57 CSR12_IN_SROM = 0x00004,
57 ALWAYS_CHECK_MII = 0x0008, 58 ALWAYS_CHECK_MII = 0x00008,
58 HAS_ACPI = 0x0010, 59 HAS_ACPI = 0x00010,
59 MC_HASH_ONLY = 0x0020, /* Hash-only multicast filter. */ 60 MC_HASH_ONLY = 0x00020, /* Hash-only multicast filter. */
60 HAS_PNICNWAY = 0x0080, 61 HAS_PNICNWAY = 0x00080,
61 HAS_NWAY = 0x0040, /* Uses internal NWay xcvr. */ 62 HAS_NWAY = 0x00040, /* Uses internal NWay xcvr. */
62 HAS_INTR_MITIGATION = 0x0100, 63 HAS_INTR_MITIGATION = 0x00100,
63 IS_ASIX = 0x0200, 64 IS_ASIX = 0x00200,
64 HAS_8023X = 0x0400, 65 HAS_8023X = 0x00400,
65 COMET_MAC_ADDR = 0x0800, 66 COMET_MAC_ADDR = 0x00800,
66 HAS_PCI_MWI = 0x1000, 67 HAS_PCI_MWI = 0x01000,
67 HAS_PHY_IRQ = 0x2000, 68 HAS_PHY_IRQ = 0x02000,
68 HAS_SWAPPED_SEEPROM = 0x4000, 69 HAS_SWAPPED_SEEPROM = 0x04000,
69 NEEDS_FAKE_MEDIA_TABLE = 0x8000, 70 NEEDS_FAKE_MEDIA_TABLE = 0x08000,
71 COMET_PM = 0x10000,
70}; 72};
71 73
72 74
@@ -120,6 +122,11 @@ enum tulip_offsets {
120 CSR13 = 0x68, 122 CSR13 = 0x68,
121 CSR14 = 0x70, 123 CSR14 = 0x70,
122 CSR15 = 0x78, 124 CSR15 = 0x78,
125 CSR18 = 0x88,
126 CSR19 = 0x8c,
127 CSR20 = 0x90,
128 CSR27 = 0xAC,
129 CSR28 = 0xB0,
123}; 130};
124 131
125/* register offset and bits for CFDD PCI config reg */ 132/* register offset and bits for CFDD PCI config reg */
@@ -289,6 +296,30 @@ enum t21143_csr6_bits {
289 csr6_mask_100bt = (csr6_scr | csr6_pcs | csr6_hbd), 296 csr6_mask_100bt = (csr6_scr | csr6_pcs | csr6_hbd),
290}; 297};
291 298
299enum tulip_comet_csr13_bits {
300/* The LINKOFFE and LINKONE work in conjunction with LSCE, i.e. they
301 * determine which link status transition wakes up if LSCE is
302 * enabled */
303 comet_csr13_linkoffe = (1 << 17),
304 comet_csr13_linkone = (1 << 16),
305 comet_csr13_wfre = (1 << 10),
306 comet_csr13_mpre = (1 << 9),
307 comet_csr13_lsce = (1 << 8),
308 comet_csr13_wfr = (1 << 2),
309 comet_csr13_mpr = (1 << 1),
310 comet_csr13_lsc = (1 << 0),
311};
312
313enum tulip_comet_csr18_bits {
314 comet_csr18_pmes_sticky = (1 << 24),
315 comet_csr18_pm_mode = (1 << 19),
316 comet_csr18_apm_mode = (1 << 18),
317 comet_csr18_d3a = (1 << 7)
318};
319
320enum tulip_comet_csr20_bits {
321 comet_csr20_pmes = (1 << 15),
322};
292 323
293/* Keep the ring sizes a power of two for efficiency. 324/* Keep the ring sizes a power of two for efficiency.
294 Making the Tx ring too large decreases the effectiveness of channel 325 Making the Tx ring too large decreases the effectiveness of channel
@@ -411,6 +442,7 @@ struct tulip_private {
411 unsigned int csr6; /* Current CSR6 control settings. */ 442 unsigned int csr6; /* Current CSR6 control settings. */
412 unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */ 443 unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */
413 void (*link_change) (struct net_device * dev, int csr5); 444 void (*link_change) (struct net_device * dev, int csr5);
445 struct ethtool_wolinfo wolinfo; /* WOL settings */
414 u16 sym_advertise, mii_advertise; /* NWay capabilities advertised. */ 446 u16 sym_advertise, mii_advertise; /* NWay capabilities advertised. */
415 u16 lpar; /* 21143 Link partner ability. */ 447 u16 lpar; /* 21143 Link partner ability. */
416 u16 advertising[4]; 448 u16 advertising[4];
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index bd3b41daa892..03e96b928c04 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -30,7 +30,6 @@
30#include <linux/etherdevice.h> 30#include <linux/etherdevice.h>
31#include <linux/delay.h> 31#include <linux/delay.h>
32#include <linux/mii.h> 32#include <linux/mii.h>
33#include <linux/ethtool.h>
34#include <linux/crc32.h> 33#include <linux/crc32.h>
35#include <asm/unaligned.h> 34#include <asm/unaligned.h>
36#include <asm/uaccess.h> 35#include <asm/uaccess.h>
@@ -272,6 +271,7 @@ static void tulip_down(struct net_device *dev);
272static struct net_device_stats *tulip_get_stats(struct net_device *dev); 271static struct net_device_stats *tulip_get_stats(struct net_device *dev);
273static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); 272static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
274static void set_rx_mode(struct net_device *dev); 273static void set_rx_mode(struct net_device *dev);
274static void tulip_set_wolopts(struct pci_dev *pdev, u32 wolopts);
275#ifdef CONFIG_NET_POLL_CONTROLLER 275#ifdef CONFIG_NET_POLL_CONTROLLER
276static void poll_tulip(struct net_device *dev); 276static void poll_tulip(struct net_device *dev);
277#endif 277#endif
@@ -309,6 +309,11 @@ static void tulip_up(struct net_device *dev)
309 /* Wake the chip from sleep/snooze mode. */ 309 /* Wake the chip from sleep/snooze mode. */
310 tulip_set_power_state (tp, 0, 0); 310 tulip_set_power_state (tp, 0, 0);
311 311
312 /* Disable all WOL events */
313 pci_enable_wake(tp->pdev, PCI_D3hot, 0);
314 pci_enable_wake(tp->pdev, PCI_D3cold, 0);
315 tulip_set_wolopts(tp->pdev, 0);
316
312 /* On some chip revs we must set the MII/SYM port before the reset!? */ 317 /* On some chip revs we must set the MII/SYM port before the reset!? */
313 if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii)) 318 if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii))
314 iowrite32(0x00040000, ioaddr + CSR6); 319 iowrite32(0x00040000, ioaddr + CSR6);
@@ -345,8 +350,8 @@ static void tulip_up(struct net_device *dev)
345 } else if (tp->flags & COMET_MAC_ADDR) { 350 } else if (tp->flags & COMET_MAC_ADDR) {
346 iowrite32(addr_low, ioaddr + 0xA4); 351 iowrite32(addr_low, ioaddr + 0xA4);
347 iowrite32(addr_high, ioaddr + 0xA8); 352 iowrite32(addr_high, ioaddr + 0xA8);
348 iowrite32(0, ioaddr + 0xAC); 353 iowrite32(0, ioaddr + CSR27);
349 iowrite32(0, ioaddr + 0xB0); 354 iowrite32(0, ioaddr + CSR28);
350 } 355 }
351 } else { 356 } else {
352 /* This is set_rx_mode(), but without starting the transmitter. */ 357 /* This is set_rx_mode(), but without starting the transmitter. */
@@ -876,8 +881,35 @@ static void tulip_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *in
876 strcpy(info->bus_info, pci_name(np->pdev)); 881 strcpy(info->bus_info, pci_name(np->pdev));
877} 882}
878 883
884
885static int tulip_ethtool_set_wol(struct net_device *dev,
886 struct ethtool_wolinfo *wolinfo)
887{
888 struct tulip_private *tp = netdev_priv(dev);
889
890 if (wolinfo->wolopts & (~tp->wolinfo.supported))
891 return -EOPNOTSUPP;
892
893 tp->wolinfo.wolopts = wolinfo->wolopts;
894 device_set_wakeup_enable(&tp->pdev->dev, tp->wolinfo.wolopts);
895 return 0;
896}
897
898static void tulip_ethtool_get_wol(struct net_device *dev,
899 struct ethtool_wolinfo *wolinfo)
900{
901 struct tulip_private *tp = netdev_priv(dev);
902
903 wolinfo->supported = tp->wolinfo.supported;
904 wolinfo->wolopts = tp->wolinfo.wolopts;
905 return;
906}
907
908
879static const struct ethtool_ops ops = { 909static const struct ethtool_ops ops = {
880 .get_drvinfo = tulip_get_drvinfo 910 .get_drvinfo = tulip_get_drvinfo,
911 .set_wol = tulip_ethtool_set_wol,
912 .get_wol = tulip_ethtool_get_wol,
881}; 913};
882 914
883/* Provide ioctl() calls to examine the MII xcvr state. */ 915/* Provide ioctl() calls to examine the MII xcvr state. */
@@ -1093,8 +1125,8 @@ static void set_rx_mode(struct net_device *dev)
1093 iowrite32(3, ioaddr + CSR13); 1125 iowrite32(3, ioaddr + CSR13);
1094 iowrite32(mc_filter[1], ioaddr + CSR14); 1126 iowrite32(mc_filter[1], ioaddr + CSR14);
1095 } else if (tp->flags & COMET_MAC_ADDR) { 1127 } else if (tp->flags & COMET_MAC_ADDR) {
1096 iowrite32(mc_filter[0], ioaddr + 0xAC); 1128 iowrite32(mc_filter[0], ioaddr + CSR27);
1097 iowrite32(mc_filter[1], ioaddr + 0xB0); 1129 iowrite32(mc_filter[1], ioaddr + CSR28);
1098 } 1130 }
1099 tp->mc_filter[0] = mc_filter[0]; 1131 tp->mc_filter[0] = mc_filter[0];
1100 tp->mc_filter[1] = mc_filter[1]; 1132 tp->mc_filter[1] = mc_filter[1];
@@ -1434,6 +1466,19 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
1434 1466
1435 tp->chip_id = chip_idx; 1467 tp->chip_id = chip_idx;
1436 tp->flags = tulip_tbl[chip_idx].flags; 1468 tp->flags = tulip_tbl[chip_idx].flags;
1469
1470 tp->wolinfo.supported = 0;
1471 tp->wolinfo.wolopts = 0;
1472 /* COMET: Enable power management only for AN983B */
1473 if (chip_idx == COMET ) {
1474 u32 sig;
1475 pci_read_config_dword (pdev, 0x80, &sig);
1476 if (sig == 0x09811317) {
1477 tp->flags |= COMET_PM;
1478 tp->wolinfo.supported = WAKE_PHY | WAKE_MAGIC;
1479 printk(KERN_INFO "tulip_init_one: Enabled WOL support for AN983B\n");
1480 }
1481 }
1437 tp->pdev = pdev; 1482 tp->pdev = pdev;
1438 tp->base_addr = ioaddr; 1483 tp->base_addr = ioaddr;
1439 tp->revision = pdev->revision; 1484 tp->revision = pdev->revision;
@@ -1766,11 +1811,43 @@ err_out_free_netdev:
1766} 1811}
1767 1812
1768 1813
1814/* set the registers according to the given wolopts */
1815static void tulip_set_wolopts (struct pci_dev *pdev, u32 wolopts)
1816{
1817 struct net_device *dev = pci_get_drvdata(pdev);
1818 struct tulip_private *tp = netdev_priv(dev);
1819 void __iomem *ioaddr = tp->base_addr;
1820
1821 if (tp->flags & COMET_PM) {
1822
1823 unsigned int tmp;
1824
1825 tmp = ioread32(ioaddr + CSR18);
1826 tmp &= ~(comet_csr18_pmes_sticky | comet_csr18_apm_mode | comet_csr18_d3a);
1827 tmp |= comet_csr18_pm_mode;
1828 iowrite32(tmp, ioaddr + CSR18);
1829
1830 /* Set the Wake-up Control/Status Register to the given WOL options*/
1831 tmp = ioread32(ioaddr + CSR13);
1832 tmp &= ~(comet_csr13_linkoffe | comet_csr13_linkone | comet_csr13_wfre | comet_csr13_lsce | comet_csr13_mpre);
1833 if (wolopts & WAKE_MAGIC)
1834 tmp |= comet_csr13_mpre;
1835 if (wolopts & WAKE_PHY)
1836 tmp |= comet_csr13_linkoffe | comet_csr13_linkone | comet_csr13_lsce;
1837 /* Clear the event flags */
1838 tmp |= comet_csr13_wfr | comet_csr13_mpr | comet_csr13_lsc;
1839 iowrite32(tmp, ioaddr + CSR13);
1840 }
1841}
1842
1769#ifdef CONFIG_PM 1843#ifdef CONFIG_PM
1770 1844
1845
1771static int tulip_suspend (struct pci_dev *pdev, pm_message_t state) 1846static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
1772{ 1847{
1848 pci_power_t pstate;
1773 struct net_device *dev = pci_get_drvdata(pdev); 1849 struct net_device *dev = pci_get_drvdata(pdev);
1850 struct tulip_private *tp = netdev_priv(dev);
1774 1851
1775 if (!dev) 1852 if (!dev)
1776 return -EINVAL; 1853 return -EINVAL;
@@ -1786,7 +1863,16 @@ static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
1786save_state: 1863save_state:
1787 pci_save_state(pdev); 1864 pci_save_state(pdev);
1788 pci_disable_device(pdev); 1865 pci_disable_device(pdev);
1789 pci_set_power_state(pdev, pci_choose_state(pdev, state)); 1866 pstate = pci_choose_state(pdev, state);
1867 if (state.event == PM_EVENT_SUSPEND && pstate != PCI_D0) {
1868 int rc;
1869
1870 tulip_set_wolopts(pdev, tp->wolinfo.wolopts);
1871 rc = pci_enable_wake(pdev, pstate, tp->wolinfo.wolopts);
1872 if (rc)
1873 printk("tulip: pci_enable_wake failed (%d)\n", rc);
1874 }
1875 pci_set_power_state(pdev, pstate);
1790 1876
1791 return 0; 1877 return 0;
1792} 1878}
@@ -1795,7 +1881,10 @@ save_state:
1795static int tulip_resume(struct pci_dev *pdev) 1881static int tulip_resume(struct pci_dev *pdev)
1796{ 1882{
1797 struct net_device *dev = pci_get_drvdata(pdev); 1883 struct net_device *dev = pci_get_drvdata(pdev);
1884 struct tulip_private *tp = netdev_priv(dev);
1885 void __iomem *ioaddr = tp->base_addr;
1798 int retval; 1886 int retval;
1887 unsigned int tmp;
1799 1888
1800 if (!dev) 1889 if (!dev)
1801 return -EINVAL; 1890 return -EINVAL;
@@ -1816,6 +1905,18 @@ static int tulip_resume(struct pci_dev *pdev)
1816 return retval; 1905 return retval;
1817 } 1906 }
1818 1907
1908 if (tp->flags & COMET_PM) {
1909 pci_enable_wake(pdev, PCI_D3hot, 0);
1910 pci_enable_wake(pdev, PCI_D3cold, 0);
1911
1912 /* Clear the PMES flag */
1913 tmp = ioread32(ioaddr + CSR20);
1914 tmp |= comet_csr20_pmes;
1915 iowrite32(tmp, ioaddr + CSR20);
1916
1917 /* Disable all wake-up events */
1918 tulip_set_wolopts(pdev, 0);
1919 }
1819 netif_device_attach(dev); 1920 netif_device_attach(dev);
1820 1921
1821 if (netif_running(dev)) 1922 if (netif_running(dev))