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

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
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -1501,7 +1501,7 @@ static void wx_restore_vlan(struct wx *wx)
 *
 * 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;
	int ret;
@@ -1545,6 +1545,7 @@ static void wx_configure_rx(struct wx *wx)
	wx_enable_rx(wx);
	wx_enable_sec_rx_path(wx);
}
EXPORT_SYMBOL(wx_configure_rx);

static void wx_configure_isb(struct wx *wx)
{
+1 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ void wx_disable_rx(struct wx *wx);
void wx_set_rx_mode(struct net_device *netdev);
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_configure_rx(struct wx *wx);
void wx_configure(struct wx *wx);
void wx_start_hw(struct wx *wx);
int wx_disable_pcie_master(struct wx *wx);
+5 −1
Original line number Diff line number Diff line
@@ -160,6 +160,10 @@
#define WX_PSR_LAN_FLEX_DW_H(_i)     (0x15C04 + ((_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 */
#define WX_PSR_VLAN_TBL(_i)          (0x16000 + ((_i) * 4))

@@ -846,7 +850,7 @@ struct wx {
	int duplex;
	struct phy_device *phydev;

	bool wol_enabled;
	bool wol_hw_supported;
	bool ncsi_enabled;
	bool gpio_ctrl;
	raw_spinlock_t gpio_lock;
+35 −0
Original line number Diff line number Diff line
@@ -6,14 +6,49 @@
#include <linux/netdevice.h>

#include "../libwx/wx_ethtool.h"
#include "../libwx/wx_type.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 = {
	.get_drvinfo		= wx_get_drvinfo,
	.get_link		= ethtool_op_get_link,
	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
	.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)
+58 −6
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@ static void ngbe_init_type_code(struct wx *wx)
		       em_mac_type_rgmii :
		       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 ||
			   type_mask == NGBE_SUBID_OCP_CARD) ? 1 : 0;

@@ -440,14 +440,26 @@ static void ngbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake)
{
	struct wx *wx = pci_get_drvdata(pdev);
	struct net_device *netdev;
	u32 wufc = wx->wol;

	netdev = wx->netdev;
	rtnl_lock();
	netif_device_detach(netdev);

	rtnl_lock();
	if (netif_running(netdev))
		ngbe_down(wx);
		ngbe_close(netdev);
	wx_clear_interrupt_scheme(wx);
	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);

	pci_disable_device(pdev);
@@ -621,12 +633,11 @@ static int ngbe_probe(struct pci_dev *pdev,
	}

	wx->wol = 0;
	if (wx->wol_enabled)
	if (wx->wol_hw_supported)
		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);

	device_set_wakeup_enable(&pdev->dev, wx->wol);

	/* Save off EEPROM version number and Option Rom version which
@@ -712,11 +723,52 @@ static void ngbe_remove(struct pci_dev *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 = {
	.name     = ngbe_driver_name,
	.id_table = ngbe_pci_tbl,
	.probe    = ngbe_probe,
	.remove   = ngbe_remove,
	.suspend  = ngbe_suspend,
	.resume   = ngbe_resume,
	.shutdown = ngbe_shutdown,
};

Loading