diff options
Diffstat (limited to 'drivers/net/tulip/tulip_core.c')
-rw-r--r-- | drivers/net/tulip/tulip_core.c | 115 |
1 files changed, 108 insertions, 7 deletions
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); | |||
272 | static struct net_device_stats *tulip_get_stats(struct net_device *dev); | 271 | static struct net_device_stats *tulip_get_stats(struct net_device *dev); |
273 | static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | 272 | static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); |
274 | static void set_rx_mode(struct net_device *dev); | 273 | static void set_rx_mode(struct net_device *dev); |
274 | static void tulip_set_wolopts(struct pci_dev *pdev, u32 wolopts); | ||
275 | #ifdef CONFIG_NET_POLL_CONTROLLER | 275 | #ifdef CONFIG_NET_POLL_CONTROLLER |
276 | static void poll_tulip(struct net_device *dev); | 276 | static 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 | |||
885 | static 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 | |||
898 | static 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 | |||
879 | static const struct ethtool_ops ops = { | 909 | static 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 */ | ||
1815 | static 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 | |||
1771 | static int tulip_suspend (struct pci_dev *pdev, pm_message_t state) | 1846 | static 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) | |||
1786 | save_state: | 1863 | save_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: | |||
1795 | static int tulip_resume(struct pci_dev *pdev) | 1881 | static 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)) |