aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Fainelli <f.fainelli@gmail.com>2014-07-21 18:29:24 -0400
committerDavid S. Miller <davem@davemloft.net>2014-07-21 19:04:31 -0400
commitc51de7f3976b649d72d3ff006954640aec2fe58c (patch)
tree0a468b8d542758560eccddd77f594ede2f43d567
parent8562056f267db98f5c078fcf7f071c8a4a752ef3 (diff)
net: bcmgenet: add Wake-on-LAN support code
Add all the required code to program the GENET hardware to enter Wake-on-LAN mode and wake using MagicPackets with or without SecureOn password. This code is hooked to the build system, but is not yet referenced from ethtool or the main bcmgenet driver. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/broadcom/genet/Makefile2
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.h9
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c206
3 files changed, 216 insertions, 1 deletions
diff --git a/drivers/net/ethernet/broadcom/genet/Makefile b/drivers/net/ethernet/broadcom/genet/Makefile
index 31f55a90a197..9b6885efa9e7 100644
--- a/drivers/net/ethernet/broadcom/genet/Makefile
+++ b/drivers/net/ethernet/broadcom/genet/Makefile
@@ -1,2 +1,2 @@
1obj-$(CONFIG_BCMGENET) += genet.o 1obj-$(CONFIG_BCMGENET) += genet.o
2genet-objs := bcmgenet.o bcmmii.o 2genet-objs := bcmgenet.o bcmmii.o bcmgenet_wol.o
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index 64bc53d86480..c61cd98b662e 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -456,6 +456,7 @@ struct enet_cb {
456enum bcmgenet_power_mode { 456enum bcmgenet_power_mode {
457 GENET_POWER_CABLE_SENSE = 0, 457 GENET_POWER_CABLE_SENSE = 0,
458 GENET_POWER_PASSIVE, 458 GENET_POWER_PASSIVE,
459 GENET_POWER_WOL_MAGIC,
459}; 460};
460 461
461struct bcmgenet_priv; 462struct bcmgenet_priv;
@@ -626,4 +627,12 @@ int bcmgenet_mii_config(struct net_device *dev);
626void bcmgenet_mii_exit(struct net_device *dev); 627void bcmgenet_mii_exit(struct net_device *dev);
627void bcmgenet_mii_reset(struct net_device *dev); 628void bcmgenet_mii_reset(struct net_device *dev);
628 629
630/* Wake-on-LAN routines */
631void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol);
632int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol);
633int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
634 enum bcmgenet_power_mode mode);
635void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
636 enum bcmgenet_power_mode mode);
637
629#endif /* __BCMGENET_H__ */ 638#endif /* __BCMGENET_H__ */
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
new file mode 100644
index 000000000000..b82b7e4e06b2
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -0,0 +1,206 @@
1/*
2 * Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support
3 *
4 * Copyright (c) 2014 Broadcom Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#define pr_fmt(fmt) "bcmgenet_wol: " fmt
12
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/sched.h>
16#include <linux/types.h>
17#include <linux/interrupt.h>
18#include <linux/string.h>
19#include <linux/init.h>
20#include <linux/errno.h>
21#include <linux/delay.h>
22#include <linux/pm.h>
23#include <linux/clk.h>
24#include <linux/version.h>
25#include <linux/platform_device.h>
26#include <net/arp.h>
27
28#include <linux/mii.h>
29#include <linux/ethtool.h>
30#include <linux/netdevice.h>
31#include <linux/inetdevice.h>
32#include <linux/etherdevice.h>
33#include <linux/skbuff.h>
34#include <linux/in.h>
35#include <linux/ip.h>
36#include <linux/ipv6.h>
37#include <linux/phy.h>
38
39#include "bcmgenet.h"
40
41/* ethtool function - get WOL (Wake on LAN) settings, Only Magic Packet
42 * Detection is supported through ethtool
43 */
44void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
45{
46 struct bcmgenet_priv *priv = netdev_priv(dev);
47 u32 reg;
48
49 wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE;
50 wol->wolopts = priv->wolopts;
51 memset(wol->sopass, 0, sizeof(wol->sopass));
52
53 if (wol->wolopts & WAKE_MAGICSECURE) {
54 reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_MS);
55 put_unaligned_be16(reg, &wol->sopass[0]);
56 reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_LS);
57 put_unaligned_be32(reg, &wol->sopass[2]);
58 }
59}
60
61/* ethtool function - set WOL (Wake on LAN) settings.
62 * Only for magic packet detection mode.
63 */
64int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
65{
66 struct bcmgenet_priv *priv = netdev_priv(dev);
67 struct device *kdev = &priv->pdev->dev;
68 u32 reg;
69
70 if (!device_can_wakeup(kdev))
71 return -ENOTSUPP;
72
73 if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE))
74 return -EINVAL;
75
76 if (wol->wolopts & WAKE_MAGICSECURE) {
77 bcmgenet_umac_writel(priv, get_unaligned_be16(&wol->sopass[0]),
78 UMAC_MPD_PW_MS);
79 bcmgenet_umac_writel(priv, get_unaligned_be32(&wol->sopass[2]),
80 UMAC_MPD_PW_LS);
81 reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
82 reg |= MPD_PW_EN;
83 bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
84 }
85
86 /* Flag the device and relevant IRQ as wakeup capable */
87 if (wol->wolopts) {
88 device_set_wakeup_enable(kdev, 1);
89 enable_irq_wake(priv->wol_irq);
90 priv->wol_irq_disabled = false;
91 } else {
92 device_set_wakeup_enable(kdev, 0);
93 /* Avoid unbalanced disable_irq_wake calls */
94 if (!priv->wol_irq_disabled)
95 disable_irq_wake(priv->wol_irq);
96 priv->wol_irq_disabled = true;
97 }
98
99 priv->wolopts = wol->wolopts;
100
101 return 0;
102}
103
104static int bcmgenet_poll_wol_status(struct bcmgenet_priv *priv)
105{
106 struct net_device *dev = priv->dev;
107 int retries = 0;
108
109 while (!(bcmgenet_rbuf_readl(priv, RBUF_STATUS)
110 & RBUF_STATUS_WOL)) {
111 retries++;
112 if (retries > 5) {
113 netdev_crit(dev, "polling wol mode timeout\n");
114 return -ETIMEDOUT;
115 }
116 mdelay(1);
117 }
118
119 return retries;
120}
121
122int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
123 enum bcmgenet_power_mode mode)
124{
125 struct net_device *dev = priv->dev;
126 u32 cpu_mask_clear;
127 int retries = 0;
128 u32 reg;
129
130 if (mode != GENET_POWER_WOL_MAGIC) {
131 netif_err(priv, wol, dev, "unsupported mode: %d\n", mode);
132 return -EINVAL;
133 }
134
135 /* disable RX */
136 reg = bcmgenet_umac_readl(priv, UMAC_CMD);
137 reg &= ~CMD_RX_EN;
138 bcmgenet_umac_writel(priv, reg, UMAC_CMD);
139 mdelay(10);
140
141 reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
142 reg |= MPD_EN;
143 bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
144
145 /* Do not leave UniMAC in MPD mode only */
146 retries = bcmgenet_poll_wol_status(priv);
147 if (retries < 0) {
148 reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
149 reg &= ~MPD_EN;
150 bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
151 return retries;
152 }
153
154 netif_dbg(priv, wol, dev, "MPD WOL-ready status set after %d msec\n",
155 retries);
156
157 /* Enable CRC forward */
158 reg = bcmgenet_umac_readl(priv, UMAC_CMD);
159 priv->crc_fwd_en = 1;
160 reg |= CMD_CRC_FWD;
161
162 /* Receiver must be enabled for WOL MP detection */
163 reg |= CMD_RX_EN;
164 bcmgenet_umac_writel(priv, reg, UMAC_CMD);
165
166 if (priv->hw_params->flags & GENET_HAS_EXT) {
167 reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
168 reg &= ~EXT_ENERGY_DET_MASK;
169 bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
170 }
171
172 /* Enable the MPD interrupt */
173 cpu_mask_clear = UMAC_IRQ_MPD_R;
174
175 bcmgenet_intrl2_0_writel(priv, cpu_mask_clear, INTRL2_CPU_MASK_CLEAR);
176
177 return 0;
178}
179
180void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
181 enum bcmgenet_power_mode mode)
182{
183 u32 cpu_mask_set;
184 u32 reg;
185
186 if (mode != GENET_POWER_WOL_MAGIC) {
187 netif_err(priv, wol, priv->dev, "invalid mode: %d\n", mode);
188 return;
189 }
190
191 reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
192 reg &= ~MPD_EN;
193 bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
194
195 /* Disable CRC Forward */
196 reg = bcmgenet_umac_readl(priv, UMAC_CMD);
197 reg &= ~CMD_CRC_FWD;
198 bcmgenet_umac_writel(priv, reg, UMAC_CMD);
199 priv->crc_fwd_en = 0;
200
201 /* Stop monitoring magic packet IRQ */
202 cpu_mask_set = UMAC_IRQ_MPD_R;
203
204 /* Stop monitoring magic packet IRQ */
205 bcmgenet_intrl2_0_writel(priv, cpu_mask_set, INTRL2_CPU_MASK_SET);
206}