|
@@ -30,7 +30,6 @@
|
|
|
#include <linux/etherdevice.h>
|
|
|
#include <linux/delay.h>
|
|
|
#include <linux/mii.h>
|
|
|
-#include <linux/ethtool.h>
|
|
|
#include <linux/crc32.h>
|
|
|
#include <asm/unaligned.h>
|
|
|
#include <asm/uaccess.h>
|
|
@@ -272,6 +271,7 @@ static void tulip_down(struct net_device *dev);
|
|
|
static struct net_device_stats *tulip_get_stats(struct net_device *dev);
|
|
|
static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
|
|
|
static void set_rx_mode(struct net_device *dev);
|
|
|
+static void tulip_set_wolopts(struct pci_dev *pdev, u32 wolopts);
|
|
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
|
|
static void poll_tulip(struct net_device *dev);
|
|
|
#endif
|
|
@@ -309,6 +309,11 @@ static void tulip_up(struct net_device *dev)
|
|
|
/* Wake the chip from sleep/snooze mode. */
|
|
|
tulip_set_power_state (tp, 0, 0);
|
|
|
|
|
|
+ /* Disable all WOL events */
|
|
|
+ pci_enable_wake(tp->pdev, PCI_D3hot, 0);
|
|
|
+ pci_enable_wake(tp->pdev, PCI_D3cold, 0);
|
|
|
+ tulip_set_wolopts(tp->pdev, 0);
|
|
|
+
|
|
|
/* On some chip revs we must set the MII/SYM port before the reset!? */
|
|
|
if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii))
|
|
|
iowrite32(0x00040000, ioaddr + CSR6);
|
|
@@ -345,8 +350,8 @@ static void tulip_up(struct net_device *dev)
|
|
|
} else if (tp->flags & COMET_MAC_ADDR) {
|
|
|
iowrite32(addr_low, ioaddr + 0xA4);
|
|
|
iowrite32(addr_high, ioaddr + 0xA8);
|
|
|
- iowrite32(0, ioaddr + 0xAC);
|
|
|
- iowrite32(0, ioaddr + 0xB0);
|
|
|
+ iowrite32(0, ioaddr + CSR27);
|
|
|
+ iowrite32(0, ioaddr + CSR28);
|
|
|
}
|
|
|
} else {
|
|
|
/* 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
|
|
|
strcpy(info->bus_info, pci_name(np->pdev));
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+static int tulip_ethtool_set_wol(struct net_device *dev,
|
|
|
+ struct ethtool_wolinfo *wolinfo)
|
|
|
+{
|
|
|
+ struct tulip_private *tp = netdev_priv(dev);
|
|
|
+
|
|
|
+ if (wolinfo->wolopts & (~tp->wolinfo.supported))
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ tp->wolinfo.wolopts = wolinfo->wolopts;
|
|
|
+ device_set_wakeup_enable(&tp->pdev->dev, tp->wolinfo.wolopts);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void tulip_ethtool_get_wol(struct net_device *dev,
|
|
|
+ struct ethtool_wolinfo *wolinfo)
|
|
|
+{
|
|
|
+ struct tulip_private *tp = netdev_priv(dev);
|
|
|
+
|
|
|
+ wolinfo->supported = tp->wolinfo.supported;
|
|
|
+ wolinfo->wolopts = tp->wolinfo.wolopts;
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
static const struct ethtool_ops ops = {
|
|
|
- .get_drvinfo = tulip_get_drvinfo
|
|
|
+ .get_drvinfo = tulip_get_drvinfo,
|
|
|
+ .set_wol = tulip_ethtool_set_wol,
|
|
|
+ .get_wol = tulip_ethtool_get_wol,
|
|
|
};
|
|
|
|
|
|
/* Provide ioctl() calls to examine the MII xcvr state. */
|
|
@@ -1093,8 +1125,8 @@ static void set_rx_mode(struct net_device *dev)
|
|
|
iowrite32(3, ioaddr + CSR13);
|
|
|
iowrite32(mc_filter[1], ioaddr + CSR14);
|
|
|
} else if (tp->flags & COMET_MAC_ADDR) {
|
|
|
- iowrite32(mc_filter[0], ioaddr + 0xAC);
|
|
|
- iowrite32(mc_filter[1], ioaddr + 0xB0);
|
|
|
+ iowrite32(mc_filter[0], ioaddr + CSR27);
|
|
|
+ iowrite32(mc_filter[1], ioaddr + CSR28);
|
|
|
}
|
|
|
tp->mc_filter[0] = mc_filter[0];
|
|
|
tp->mc_filter[1] = mc_filter[1];
|
|
@@ -1434,6 +1466,19 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
|
|
|
|
|
|
tp->chip_id = chip_idx;
|
|
|
tp->flags = tulip_tbl[chip_idx].flags;
|
|
|
+
|
|
|
+ tp->wolinfo.supported = 0;
|
|
|
+ tp->wolinfo.wolopts = 0;
|
|
|
+ /* COMET: Enable power management only for AN983B */
|
|
|
+ if (chip_idx == COMET ) {
|
|
|
+ u32 sig;
|
|
|
+ pci_read_config_dword (pdev, 0x80, &sig);
|
|
|
+ if (sig == 0x09811317) {
|
|
|
+ tp->flags |= COMET_PM;
|
|
|
+ tp->wolinfo.supported = WAKE_PHY | WAKE_MAGIC;
|
|
|
+ printk(KERN_INFO "tulip_init_one: Enabled WOL support for AN983B\n");
|
|
|
+ }
|
|
|
+ }
|
|
|
tp->pdev = pdev;
|
|
|
tp->base_addr = ioaddr;
|
|
|
tp->revision = pdev->revision;
|
|
@@ -1766,11 +1811,43 @@ err_out_free_netdev:
|
|
|
}
|
|
|
|
|
|
|
|
|
+/* set the registers according to the given wolopts */
|
|
|
+static void tulip_set_wolopts (struct pci_dev *pdev, u32 wolopts)
|
|
|
+{
|
|
|
+ struct net_device *dev = pci_get_drvdata(pdev);
|
|
|
+ struct tulip_private *tp = netdev_priv(dev);
|
|
|
+ void __iomem *ioaddr = tp->base_addr;
|
|
|
+
|
|
|
+ if (tp->flags & COMET_PM) {
|
|
|
+
|
|
|
+ unsigned int tmp;
|
|
|
+
|
|
|
+ tmp = ioread32(ioaddr + CSR18);
|
|
|
+ tmp &= ~(comet_csr18_pmes_sticky | comet_csr18_apm_mode | comet_csr18_d3a);
|
|
|
+ tmp |= comet_csr18_pm_mode;
|
|
|
+ iowrite32(tmp, ioaddr + CSR18);
|
|
|
+
|
|
|
+ /* Set the Wake-up Control/Status Register to the given WOL options*/
|
|
|
+ tmp = ioread32(ioaddr + CSR13);
|
|
|
+ tmp &= ~(comet_csr13_linkoffe | comet_csr13_linkone | comet_csr13_wfre | comet_csr13_lsce | comet_csr13_mpre);
|
|
|
+ if (wolopts & WAKE_MAGIC)
|
|
|
+ tmp |= comet_csr13_mpre;
|
|
|
+ if (wolopts & WAKE_PHY)
|
|
|
+ tmp |= comet_csr13_linkoffe | comet_csr13_linkone | comet_csr13_lsce;
|
|
|
+ /* Clear the event flags */
|
|
|
+ tmp |= comet_csr13_wfr | comet_csr13_mpr | comet_csr13_lsc;
|
|
|
+ iowrite32(tmp, ioaddr + CSR13);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
#ifdef CONFIG_PM
|
|
|
|
|
|
+
|
|
|
static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
|
|
|
{
|
|
|
+ pci_power_t pstate;
|
|
|
struct net_device *dev = pci_get_drvdata(pdev);
|
|
|
+ struct tulip_private *tp = netdev_priv(dev);
|
|
|
|
|
|
if (!dev)
|
|
|
return -EINVAL;
|
|
@@ -1786,7 +1863,16 @@ static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
|
|
|
save_state:
|
|
|
pci_save_state(pdev);
|
|
|
pci_disable_device(pdev);
|
|
|
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
|
|
|
+ pstate = pci_choose_state(pdev, state);
|
|
|
+ if (state.event == PM_EVENT_SUSPEND && pstate != PCI_D0) {
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ tulip_set_wolopts(pdev, tp->wolinfo.wolopts);
|
|
|
+ rc = pci_enable_wake(pdev, pstate, tp->wolinfo.wolopts);
|
|
|
+ if (rc)
|
|
|
+ printk("tulip: pci_enable_wake failed (%d)\n", rc);
|
|
|
+ }
|
|
|
+ pci_set_power_state(pdev, pstate);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -1795,7 +1881,10 @@ save_state:
|
|
|
static int tulip_resume(struct pci_dev *pdev)
|
|
|
{
|
|
|
struct net_device *dev = pci_get_drvdata(pdev);
|
|
|
+ struct tulip_private *tp = netdev_priv(dev);
|
|
|
+ void __iomem *ioaddr = tp->base_addr;
|
|
|
int retval;
|
|
|
+ unsigned int tmp;
|
|
|
|
|
|
if (!dev)
|
|
|
return -EINVAL;
|
|
@@ -1816,6 +1905,18 @@ static int tulip_resume(struct pci_dev *pdev)
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
+ if (tp->flags & COMET_PM) {
|
|
|
+ pci_enable_wake(pdev, PCI_D3hot, 0);
|
|
|
+ pci_enable_wake(pdev, PCI_D3cold, 0);
|
|
|
+
|
|
|
+ /* Clear the PMES flag */
|
|
|
+ tmp = ioread32(ioaddr + CSR20);
|
|
|
+ tmp |= comet_csr20_pmes;
|
|
|
+ iowrite32(tmp, ioaddr + CSR20);
|
|
|
+
|
|
|
+ /* Disable all wake-up events */
|
|
|
+ tulip_set_wolopts(pdev, 0);
|
|
|
+ }
|
|
|
netif_device_attach(dev);
|
|
|
|
|
|
if (netif_running(dev))
|