aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tulip/tulip_core.c
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/tulip/tulip_core.c
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/tulip/tulip_core.c')
-rw-r--r--drivers/net/tulip/tulip_core.c115
1 files changed, 108 insertions, 7 deletions
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index bd3b41daa89..03e96b928c0 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))