Commit 6963e463 authored by Mengyuan Lou's avatar Mengyuan Lou Committed by David S. Miller

net: ngbe: add Wake on Lan support

Implement ethtool_ops get_wol and set_wol.
Implement Wake-on-LAN support.

Wol requires hardware board support which use sub id
to identify.
Magic packets are checked by fw, for now just support
WAKE_MAGIC.
Signed-off-by: default avatarMengyuan Lou <mengyuanlou@net-swift.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 88085b3b
...@@ -1501,7 +1501,7 @@ static void wx_restore_vlan(struct wx *wx) ...@@ -1501,7 +1501,7 @@ static void wx_restore_vlan(struct wx *wx)
* *
* Configure the Rx unit of the MAC after a reset. * Configure the Rx unit of the MAC after a reset.
**/ **/
static void wx_configure_rx(struct wx *wx) void wx_configure_rx(struct wx *wx)
{ {
u32 psrtype, i; u32 psrtype, i;
int ret; int ret;
...@@ -1545,6 +1545,7 @@ static void wx_configure_rx(struct wx *wx) ...@@ -1545,6 +1545,7 @@ static void wx_configure_rx(struct wx *wx)
wx_enable_rx(wx); wx_enable_rx(wx);
wx_enable_sec_rx_path(wx); wx_enable_sec_rx_path(wx);
} }
EXPORT_SYMBOL(wx_configure_rx);
static void wx_configure_isb(struct wx *wx) static void wx_configure_isb(struct wx *wx)
{ {
......
...@@ -25,6 +25,7 @@ void wx_disable_rx(struct wx *wx); ...@@ -25,6 +25,7 @@ void wx_disable_rx(struct wx *wx);
void wx_set_rx_mode(struct net_device *netdev); void wx_set_rx_mode(struct net_device *netdev);
int wx_change_mtu(struct net_device *netdev, int new_mtu); int wx_change_mtu(struct net_device *netdev, int new_mtu);
void wx_disable_rx_queue(struct wx *wx, struct wx_ring *ring); void wx_disable_rx_queue(struct wx *wx, struct wx_ring *ring);
void wx_configure_rx(struct wx *wx);
void wx_configure(struct wx *wx); void wx_configure(struct wx *wx);
void wx_start_hw(struct wx *wx); void wx_start_hw(struct wx *wx);
int wx_disable_pcie_master(struct wx *wx); int wx_disable_pcie_master(struct wx *wx);
......
...@@ -160,6 +160,10 @@ ...@@ -160,6 +160,10 @@
#define WX_PSR_LAN_FLEX_DW_H(_i) (0x15C04 + ((_i) * 16)) #define WX_PSR_LAN_FLEX_DW_H(_i) (0x15C04 + ((_i) * 16))
#define WX_PSR_LAN_FLEX_MSK(_i) (0x15C08 + ((_i) * 16)) #define WX_PSR_LAN_FLEX_MSK(_i) (0x15C08 + ((_i) * 16))
#define WX_PSR_WKUP_CTL 0x15B80
/* Wake Up Filter Control Bit */
#define WX_PSR_WKUP_CTL_MAG BIT(1) /* Magic Packet Wakeup Enable */
/* vlan tbl */ /* vlan tbl */
#define WX_PSR_VLAN_TBL(_i) (0x16000 + ((_i) * 4)) #define WX_PSR_VLAN_TBL(_i) (0x16000 + ((_i) * 4))
...@@ -846,7 +850,7 @@ struct wx { ...@@ -846,7 +850,7 @@ struct wx {
int duplex; int duplex;
struct phy_device *phydev; struct phy_device *phydev;
bool wol_enabled; bool wol_hw_supported;
bool ncsi_enabled; bool ncsi_enabled;
bool gpio_ctrl; bool gpio_ctrl;
raw_spinlock_t gpio_lock; raw_spinlock_t gpio_lock;
......
...@@ -6,14 +6,49 @@ ...@@ -6,14 +6,49 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include "../libwx/wx_ethtool.h" #include "../libwx/wx_ethtool.h"
#include "../libwx/wx_type.h"
#include "ngbe_ethtool.h" #include "ngbe_ethtool.h"
static void ngbe_get_wol(struct net_device *netdev,
struct ethtool_wolinfo *wol)
{
struct wx *wx = netdev_priv(netdev);
if (!wx->wol_hw_supported)
return;
wol->supported = WAKE_MAGIC;
wol->wolopts = 0;
if (wx->wol & WX_PSR_WKUP_CTL_MAG)
wol->wolopts |= WAKE_MAGIC;
}
static int ngbe_set_wol(struct net_device *netdev,
struct ethtool_wolinfo *wol)
{
struct wx *wx = netdev_priv(netdev);
struct pci_dev *pdev = wx->pdev;
if (!wx->wol_hw_supported)
return -EOPNOTSUPP;
wx->wol = 0;
if (wol->wolopts & WAKE_MAGIC)
wx->wol = WX_PSR_WKUP_CTL_MAG;
netdev->wol_enabled = !!(wx->wol);
wr32(wx, WX_PSR_WKUP_CTL, wx->wol);
device_set_wakeup_enable(&pdev->dev, netdev->wol_enabled);
return 0;
}
static const struct ethtool_ops ngbe_ethtool_ops = { static const struct ethtool_ops ngbe_ethtool_ops = {
.get_drvinfo = wx_get_drvinfo, .get_drvinfo = wx_get_drvinfo,
.get_link = ethtool_op_get_link, .get_link = ethtool_op_get_link,
.get_link_ksettings = phy_ethtool_get_link_ksettings, .get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings, .set_link_ksettings = phy_ethtool_set_link_ksettings,
.nway_reset = phy_ethtool_nway_reset, .nway_reset = phy_ethtool_nway_reset,
.get_wol = ngbe_get_wol,
.set_wol = ngbe_set_wol,
}; };
void ngbe_set_ethtool_ops(struct net_device *netdev) void ngbe_set_ethtool_ops(struct net_device *netdev)
......
...@@ -62,7 +62,7 @@ static void ngbe_init_type_code(struct wx *wx) ...@@ -62,7 +62,7 @@ static void ngbe_init_type_code(struct wx *wx)
em_mac_type_rgmii : em_mac_type_rgmii :
em_mac_type_mdi; em_mac_type_mdi;
wx->wol_enabled = (wol_mask == NGBE_WOL_SUP) ? 1 : 0; wx->wol_hw_supported = (wol_mask == NGBE_WOL_SUP) ? 1 : 0;
wx->ncsi_enabled = (ncsi_mask == NGBE_NCSI_MASK || wx->ncsi_enabled = (ncsi_mask == NGBE_NCSI_MASK ||
type_mask == NGBE_SUBID_OCP_CARD) ? 1 : 0; type_mask == NGBE_SUBID_OCP_CARD) ? 1 : 0;
...@@ -440,14 +440,26 @@ static void ngbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake) ...@@ -440,14 +440,26 @@ static void ngbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake)
{ {
struct wx *wx = pci_get_drvdata(pdev); struct wx *wx = pci_get_drvdata(pdev);
struct net_device *netdev; struct net_device *netdev;
u32 wufc = wx->wol;
netdev = wx->netdev; netdev = wx->netdev;
rtnl_lock();
netif_device_detach(netdev); netif_device_detach(netdev);
rtnl_lock();
if (netif_running(netdev)) if (netif_running(netdev))
ngbe_down(wx); ngbe_close(netdev);
wx_clear_interrupt_scheme(wx);
rtnl_unlock(); rtnl_unlock();
if (wufc) {
wx_set_rx_mode(netdev);
wx_configure_rx(wx);
wr32(wx, NGBE_PSR_WKUP_CTL, wufc);
} else {
wr32(wx, NGBE_PSR_WKUP_CTL, 0);
}
pci_wake_from_d3(pdev, !!wufc);
*enable_wake = !!wufc;
wx_control_hw(wx, false); wx_control_hw(wx, false);
pci_disable_device(pdev); pci_disable_device(pdev);
...@@ -621,12 +633,11 @@ static int ngbe_probe(struct pci_dev *pdev, ...@@ -621,12 +633,11 @@ static int ngbe_probe(struct pci_dev *pdev,
} }
wx->wol = 0; wx->wol = 0;
if (wx->wol_enabled) if (wx->wol_hw_supported)
wx->wol = NGBE_PSR_WKUP_CTL_MAG; wx->wol = NGBE_PSR_WKUP_CTL_MAG;
wx->wol_enabled = !!(wx->wol); netdev->wol_enabled = !!(wx->wol);
wr32(wx, NGBE_PSR_WKUP_CTL, wx->wol); wr32(wx, NGBE_PSR_WKUP_CTL, wx->wol);
device_set_wakeup_enable(&pdev->dev, wx->wol); device_set_wakeup_enable(&pdev->dev, wx->wol);
/* Save off EEPROM version number and Option Rom version which /* Save off EEPROM version number and Option Rom version which
...@@ -712,11 +723,52 @@ static void ngbe_remove(struct pci_dev *pdev) ...@@ -712,11 +723,52 @@ static void ngbe_remove(struct pci_dev *pdev)
pci_disable_device(pdev); pci_disable_device(pdev);
} }
static int ngbe_suspend(struct pci_dev *pdev, pm_message_t state)
{
bool wake;
ngbe_dev_shutdown(pdev, &wake);
device_set_wakeup_enable(&pdev->dev, wake);
return 0;
}
static int ngbe_resume(struct pci_dev *pdev)
{
struct net_device *netdev;
struct wx *wx;
u32 err;
wx = pci_get_drvdata(pdev);
netdev = wx->netdev;
err = pci_enable_device_mem(pdev);
if (err) {
wx_err(wx, "Cannot enable PCI device from suspend\n");
return err;
}
pci_set_master(pdev);
device_wakeup_disable(&pdev->dev);
ngbe_reset_hw(wx);
rtnl_lock();
err = wx_init_interrupt_scheme(wx);
if (!err && netif_running(netdev))
err = ngbe_open(netdev);
if (!err)
netif_device_attach(netdev);
rtnl_unlock();
return 0;
}
static struct pci_driver ngbe_driver = { static struct pci_driver ngbe_driver = {
.name = ngbe_driver_name, .name = ngbe_driver_name,
.id_table = ngbe_pci_tbl, .id_table = ngbe_pci_tbl,
.probe = ngbe_probe, .probe = ngbe_probe,
.remove = ngbe_remove, .remove = ngbe_remove,
.suspend = ngbe_suspend,
.resume = ngbe_resume,
.shutdown = ngbe_shutdown, .shutdown = ngbe_shutdown,
}; };
......
...@@ -236,6 +236,7 @@ static void ngbe_phy_fixup(struct wx *wx) ...@@ -236,6 +236,7 @@ static void ngbe_phy_fixup(struct wx *wx)
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
phydev->mac_managed_pm = true;
if (wx->mac_type != em_mac_type_mdi) if (wx->mac_type != em_mac_type_mdi)
return; return;
/* disable EEE, internal phy does not support eee */ /* disable EEE, internal phy does not support eee */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment