Commit 3e2a5e15 authored by Sergio Prado's avatar Sergio Prado Committed by David S. Miller

net: macb: add wake-on-lan support via magic packet

Tested on Acqua A5 SoM (http://www.acmesystems.it/acqua).
Signed-off-by: default avatarSergio Prado <sergio.prado@e-labworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e6515203
...@@ -25,6 +25,8 @@ Required properties: ...@@ -25,6 +25,8 @@ Required properties:
Optional properties for PHY child node: Optional properties for PHY child node:
- reset-gpios : Should specify the gpio for phy reset - reset-gpios : Should specify the gpio for phy reset
- cdns,magic-packet : If present, indicates that the hardware supports waking
up via magic packet.
Examples: Examples:
......
...@@ -58,6 +58,9 @@ ...@@ -58,6 +58,9 @@
#define GEM_MTU_MIN_SIZE 68 #define GEM_MTU_MIN_SIZE 68
#define MACB_WOL_HAS_MAGIC_PACKET (0x1 << 0)
#define MACB_WOL_ENABLED (0x1 << 1)
/* /*
* Graceful stop timeouts in us. We should allow up to * Graceful stop timeouts in us. We should allow up to
* 1 frame time (10 Mbits/s, full-duplex, ignoring collisions) * 1 frame time (10 Mbits/s, full-duplex, ignoring collisions)
...@@ -2124,6 +2127,39 @@ static void macb_get_regs(struct net_device *dev, struct ethtool_regs *regs, ...@@ -2124,6 +2127,39 @@ static void macb_get_regs(struct net_device *dev, struct ethtool_regs *regs,
} }
} }
static void macb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
struct macb *bp = netdev_priv(netdev);
wol->supported = 0;
wol->wolopts = 0;
if (bp->wol & MACB_WOL_HAS_MAGIC_PACKET) {
wol->supported = WAKE_MAGIC;
if (bp->wol & MACB_WOL_ENABLED)
wol->wolopts |= WAKE_MAGIC;
}
}
static int macb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
struct macb *bp = netdev_priv(netdev);
if (!(bp->wol & MACB_WOL_HAS_MAGIC_PACKET) ||
(wol->wolopts & ~WAKE_MAGIC))
return -EOPNOTSUPP;
if (wol->wolopts & WAKE_MAGIC)
bp->wol |= MACB_WOL_ENABLED;
else
bp->wol &= ~MACB_WOL_ENABLED;
device_set_wakeup_enable(&bp->pdev->dev, bp->wol & MACB_WOL_ENABLED);
return 0;
}
static const struct ethtool_ops macb_ethtool_ops = { static const struct ethtool_ops macb_ethtool_ops = {
.get_settings = macb_get_settings, .get_settings = macb_get_settings,
.set_settings = macb_set_settings, .set_settings = macb_set_settings,
...@@ -2131,6 +2167,8 @@ static const struct ethtool_ops macb_ethtool_ops = { ...@@ -2131,6 +2167,8 @@ static const struct ethtool_ops macb_ethtool_ops = {
.get_regs = macb_get_regs, .get_regs = macb_get_regs,
.get_link = ethtool_op_get_link, .get_link = ethtool_op_get_link,
.get_ts_info = ethtool_op_get_ts_info, .get_ts_info = ethtool_op_get_ts_info,
.get_wol = macb_get_wol,
.set_wol = macb_set_wol,
}; };
static const struct ethtool_ops gem_ethtool_ops = { static const struct ethtool_ops gem_ethtool_ops = {
...@@ -2890,6 +2928,11 @@ static int macb_probe(struct platform_device *pdev) ...@@ -2890,6 +2928,11 @@ static int macb_probe(struct platform_device *pdev)
if (macb_config) if (macb_config)
bp->jumbo_max_len = macb_config->jumbo_max_len; bp->jumbo_max_len = macb_config->jumbo_max_len;
bp->wol = 0;
if (of_get_property(np, "cdns,magic-packet", NULL))
bp->wol |= MACB_WOL_HAS_MAGIC_PACKET;
device_init_wakeup(&pdev->dev, bp->wol & MACB_WOL_HAS_MAGIC_PACKET);
spin_lock_init(&bp->lock); spin_lock_init(&bp->lock);
/* setup capabilities */ /* setup capabilities */
...@@ -3006,9 +3049,15 @@ static int __maybe_unused macb_suspend(struct device *dev) ...@@ -3006,9 +3049,15 @@ static int __maybe_unused macb_suspend(struct device *dev)
netif_carrier_off(netdev); netif_carrier_off(netdev);
netif_device_detach(netdev); netif_device_detach(netdev);
clk_disable_unprepare(bp->tx_clk); if (bp->wol & MACB_WOL_ENABLED) {
clk_disable_unprepare(bp->hclk); macb_writel(bp, IER, MACB_BIT(WOL));
clk_disable_unprepare(bp->pclk); macb_writel(bp, WOL, MACB_BIT(MAG));
enable_irq_wake(bp->queues[0].irq);
} else {
clk_disable_unprepare(bp->tx_clk);
clk_disable_unprepare(bp->hclk);
clk_disable_unprepare(bp->pclk);
}
return 0; return 0;
} }
...@@ -3019,9 +3068,15 @@ static int __maybe_unused macb_resume(struct device *dev) ...@@ -3019,9 +3068,15 @@ static int __maybe_unused macb_resume(struct device *dev)
struct net_device *netdev = platform_get_drvdata(pdev); struct net_device *netdev = platform_get_drvdata(pdev);
struct macb *bp = netdev_priv(netdev); struct macb *bp = netdev_priv(netdev);
clk_prepare_enable(bp->pclk); if (bp->wol & MACB_WOL_ENABLED) {
clk_prepare_enable(bp->hclk); macb_writel(bp, IDR, MACB_BIT(WOL));
clk_prepare_enable(bp->tx_clk); macb_writel(bp, WOL, 0);
disable_irq_wake(bp->queues[0].irq);
} else {
clk_prepare_enable(bp->pclk);
clk_prepare_enable(bp->hclk);
clk_prepare_enable(bp->tx_clk);
}
netif_device_attach(netdev); netif_device_attach(netdev);
......
...@@ -312,6 +312,8 @@ ...@@ -312,6 +312,8 @@
#define MACB_PFR_SIZE 1 #define MACB_PFR_SIZE 1
#define MACB_PTZ_OFFSET 13 /* Enable pause time zero interrupt */ #define MACB_PTZ_OFFSET 13 /* Enable pause time zero interrupt */
#define MACB_PTZ_SIZE 1 #define MACB_PTZ_SIZE 1
#define MACB_WOL_OFFSET 14 /* Enable wake-on-lan interrupt */
#define MACB_WOL_SIZE 1
/* Bitfields in MAN */ /* Bitfields in MAN */
#define MACB_DATA_OFFSET 0 /* data */ #define MACB_DATA_OFFSET 0 /* data */
...@@ -842,6 +844,8 @@ struct macb { ...@@ -842,6 +844,8 @@ struct macb {
unsigned int rx_frm_len_mask; unsigned int rx_frm_len_mask;
unsigned int jumbo_max_len; unsigned int jumbo_max_len;
u32 wol;
}; };
static inline bool macb_is_gem(struct macb *bp) static inline bool macb_is_gem(struct macb *bp)
......
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