Config0 = 0x51,
Config1 = 0x52,
Config2 = 0x53,
+#define PME_SIGNAL (1 << 5) /* 8168c and later */
+
Config3 = 0x54,
Config4 = 0x55,
Config5 = 0x56,
u16 cp_cmd;
u16 event_slow;
+ bool runtime_suspended;
struct mdio_ops {
void (*write)(void __iomem *, int, int);
#define RTL_FIRMWARE_UNKNOWN ERR_PTR(-EAGAIN)
};
+static int aspm_disable = 0;
+module_param(aspm_disable, int, 0444);
+MODULE_PARM_DESC(aspm_disable, "Disable ASPM completely.");
+
MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
module_param(use_dac, int, 0);
u16 reg;
u8 mask;
} cfg[] = {
- { WAKE_ANY, Config1, PMEnable },
{ WAKE_PHY, Config3, LinkUp },
{ WAKE_MAGIC, Config3, MagicPacket },
{ WAKE_UCAST, Config5, UWF },
{ WAKE_MCAST, Config5, MWF },
{ WAKE_ANY, Config5, LanWake }
};
+ u8 options;
RTL_W8(Cfg9346, Cfg9346_Unlock);
for (i = 0; i < ARRAY_SIZE(cfg); i++) {
- u8 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
+ options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
if (wolopts & cfg[i].opt)
options |= cfg[i].mask;
RTL_W8(cfg[i].reg, options);
}
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_01 ... RTL_GIGA_MAC_VER_17:
+ options = RTL_R8(Config1) & ~PMEnable;
+ if (wolopts)
+ options |= PMEnable;
+ RTL_W8(Config1, options);
+ break;
+ default:
+ options = RTL_R8(Config2) & ~PME_SIGNAL;
+ if (wolopts)
+ options |= PME_SIGNAL;
+ RTL_W8(Config2, options);
+ break;
+ }
+
RTL_W8(Cfg9346, Cfg9346_Lock);
}
}
}
+static void rtl_speed_down(struct rtl8169_private *tp)
+{
+ u32 adv;
+ int lpa;
+
+ rtl_writephy(tp, 0x1f, 0x0000);
+ lpa = rtl_readphy(tp, MII_LPA);
+
+ if (lpa & (LPA_10HALF | LPA_10FULL))
+ adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full;
+ else if (lpa & (LPA_100HALF | LPA_100FULL))
+ adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
+ else
+ adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
+ (tp->mii.supports_gmii ?
+ ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full : 0);
+
+ rtl8169_set_speed(tp->dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL,
+ adv);
+}
+
static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
if (!(__rtl8169_get_wol(tp) & WAKE_ANY))
return false;
- rtl_writephy(tp, 0x1f, 0x0000);
- rtl_writephy(tp, MII_BMCR, 0x0000);
-
+ rtl_speed_down(tp);
rtl_wol_suspend_quirk(tp);
return true;
rtl_unlock_work(tp);
tp->saved_wolopts = 0;
+ tp->runtime_suspended = false;
pm_runtime_put_noidle(&pdev->dev);
rtl8169_check_link_status(dev, tp, ioaddr);
{
struct pci_dev *pdev = to_pci_dev(device);
struct net_device *dev = pci_get_drvdata(pdev);
+ struct rtl8169_private *tp = netdev_priv(dev);
+
+ rtl_lock_work(tp);
+ tp->saved_wolopts = __rtl8169_get_wol(tp);
+ rtl_unlock_work(tp);
rtl8169_net_suspend(dev);
struct net_device *dev = pci_get_drvdata(pdev);
struct rtl8169_private *tp = netdev_priv(dev);
+ rtl_lock_work(tp);
+ __rtl8169_set_wol(tp, tp->saved_wolopts);
+ rtl_unlock_work(tp);
+
rtl8169_init_phy(dev, tp);
if (netif_running(dev))
rtl_lock_work(tp);
tp->saved_wolopts = __rtl8169_get_wol(tp);
__rtl8169_set_wol(tp, WAKE_ANY);
+ tp->runtime_suspended = true;
rtl_unlock_work(tp);
rtl8169_net_suspend(dev);
rtl_lock_work(tp);
__rtl8169_set_wol(tp, tp->saved_wolopts);
tp->saved_wolopts = 0;
+ tp->runtime_suspended = false;
rtl_unlock_work(tp);
rtl8169_init_phy(dev, tp);
struct net_device *dev = pci_get_drvdata(pdev);
struct rtl8169_private *tp = netdev_priv(dev);
+ __rtl8169_check_link_status(dev, tp, tp->mmio_addr, true);
return tp->TxDescArray ? -EBUSY : 0;
}
pm_runtime_get_sync(d);
+ /* Get the device back to D0 state if it was runtime suspended. */
+ if (tp->runtime_suspended)
+ pci_set_power_state(pdev, PCI_D0);
+
rtl8169_net_suspend(dev);
/* Restore original MAC address */
rtl8169_hw_reset(tp);
+ /* Restore WOL flags if they were messed around with. */
+ if (tp->saved_wolopts)
+ __rtl8169_set_wol(tp, tp->saved_wolopts);
+
if (system_state == SYSTEM_POWER_OFF) {
if (__rtl8169_get_wol(tp) & WAKE_ANY) {
rtl_wol_suspend_quirk(tp);
msi = RTL_FEATURE_MSI;
}
}
- if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
- RTL_W8(Config2, cfg2);
+ RTL_W8(Config2, cfg2);
return msi;
}
/* disable ASPM completely as that cause random device stop working
* problems as well as full system hangs for some PCIe devices users */
- pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
- PCIE_LINK_STATE_CLKPM);
+ if (aspm_disable) {
+ pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S |
+ PCIE_LINK_STATE_L1 |
+ PCIE_LINK_STATE_CLKPM);
+ dprintk("ASPM disabled");
+ }
/* enable device (incl. PCI PM wakeup and hotplug setup) */
rc = pci_enable_device(pdev);
RTL_W8(Cfg9346, Cfg9346_Unlock);
RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
- RTL_W8(Config5, RTL_R8(Config5) & PMEStatus);
- if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0)
- tp->features |= RTL_FEATURE_WOL;
- if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0)
- tp->features |= RTL_FEATURE_WOL;
+ RTL_W8(Config3, 0);
+ RTL_W8(Config5, PMEStatus);
tp->features |= rtl_try_msi(tp, cfg);
RTL_W8(Cfg9346, Cfg9346_Lock);