Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support
  4 *
  5 * Copyright (c) 2014-2024 Broadcom
  6 */
  7
  8#define pr_fmt(fmt)				"bcmgenet_wol: " fmt
  9
 10#include <linux/kernel.h>
 11#include <linux/module.h>
 12#include <linux/sched.h>
 13#include <linux/types.h>
 14#include <linux/interrupt.h>
 15#include <linux/string.h>
 16#include <linux/init.h>
 17#include <linux/errno.h>
 18#include <linux/delay.h>
 19#include <linux/pm.h>
 20#include <linux/clk.h>
 
 21#include <linux/platform_device.h>
 22#include <net/arp.h>
 23
 24#include <linux/mii.h>
 25#include <linux/ethtool.h>
 26#include <linux/netdevice.h>
 27#include <linux/inetdevice.h>
 28#include <linux/etherdevice.h>
 29#include <linux/skbuff.h>
 30#include <linux/in.h>
 31#include <linux/ip.h>
 32#include <linux/ipv6.h>
 33#include <linux/phy.h>
 34
 35#include "bcmgenet.h"
 36
 37/* ethtool function - get WOL (Wake on LAN) settings, Only Magic Packet
 38 * Detection is supported through ethtool
 39 */
 40void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 41{
 42	struct bcmgenet_priv *priv = netdev_priv(dev);
 43	struct device *kdev = &priv->pdev->dev;
 44	u32 phy_wolopts = 0;
 45
 46	if (dev->phydev) {
 47		phy_ethtool_get_wol(dev->phydev, wol);
 48		phy_wolopts = wol->wolopts;
 49	}
 50
 51	/* MAC is not wake-up capable, return what the PHY does */
 52	if (!device_can_wakeup(kdev))
 53		return;
 54
 55	/* Overlay MAC capabilities with that of the PHY queried before */
 56	wol->supported |= WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER;
 57	wol->wolopts |= priv->wolopts;
 58
 59	/* Return the PHY configured magic password */
 60	if (phy_wolopts & WAKE_MAGICSECURE)
 61		return;
 62
 63	/* Otherwise the MAC one */
 
 64	memset(wol->sopass, 0, sizeof(wol->sopass));
 
 65	if (wol->wolopts & WAKE_MAGICSECURE)
 66		memcpy(wol->sopass, priv->sopass, sizeof(priv->sopass));
 67}
 68
 69/* ethtool function - set WOL (Wake on LAN) settings.
 70 * Only for magic packet detection mode.
 71 */
 72int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 73{
 74	struct bcmgenet_priv *priv = netdev_priv(dev);
 75	struct device *kdev = &priv->pdev->dev;
 76	int ret;
 77
 78	/* Try Wake-on-LAN from the PHY first */
 79	if (dev->phydev) {
 80		ret = phy_ethtool_set_wol(dev->phydev, wol);
 81		if (ret != -EOPNOTSUPP && wol->wolopts)
 82			return ret;
 83	}
 84
 85	if (!device_can_wakeup(kdev))
 86		return -ENOTSUPP;
 87
 88	if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER))
 89		return -EINVAL;
 90
 91	if (wol->wolopts & WAKE_MAGICSECURE)
 92		memcpy(priv->sopass, wol->sopass, sizeof(priv->sopass));
 93
 94	/* Flag the device and relevant IRQ as wakeup capable */
 95	if (wol->wolopts) {
 96		device_set_wakeup_enable(kdev, 1);
 97		/* Avoid unbalanced enable_irq_wake calls */
 98		if (priv->wol_irq_disabled) {
 99			enable_irq_wake(priv->wol_irq);
100			enable_irq_wake(priv->irq0);
101		}
102		priv->wol_irq_disabled = false;
103	} else {
104		device_set_wakeup_enable(kdev, 0);
105		/* Avoid unbalanced disable_irq_wake calls */
106		if (!priv->wol_irq_disabled) {
107			disable_irq_wake(priv->wol_irq);
108			disable_irq_wake(priv->irq0);
109		}
110		priv->wol_irq_disabled = true;
111	}
112
113	priv->wolopts = wol->wolopts;
114
115	return 0;
116}
117
118static int bcmgenet_poll_wol_status(struct bcmgenet_priv *priv)
119{
120	struct net_device *dev = priv->dev;
121	int retries = 0;
122
123	while (!(bcmgenet_rbuf_readl(priv, RBUF_STATUS)
124		& RBUF_STATUS_WOL)) {
125		retries++;
126		if (retries > 5) {
127			netdev_crit(dev, "polling wol mode timeout\n");
128			return -ETIMEDOUT;
129		}
130		mdelay(1);
131	}
132
133	return retries;
134}
135
136static void bcmgenet_set_mpd_password(struct bcmgenet_priv *priv)
137{
138	bcmgenet_umac_writel(priv, get_unaligned_be16(&priv->sopass[0]),
139			     UMAC_MPD_PW_MS);
140	bcmgenet_umac_writel(priv, get_unaligned_be32(&priv->sopass[2]),
141			     UMAC_MPD_PW_LS);
142}
143
144int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
145				enum bcmgenet_power_mode mode)
146{
147	struct net_device *dev = priv->dev;
148	struct bcmgenet_rxnfc_rule *rule;
149	u32 reg, hfb_ctrl_reg, hfb_enable = 0;
150	int retries = 0;
151
152	if (mode != GENET_POWER_WOL_MAGIC) {
153		netif_err(priv, wol, dev, "unsupported mode: %d\n", mode);
154		return -EINVAL;
155	}
156
157	/* Can't suspend with WoL if MAC is still in reset */
158	spin_lock_bh(&priv->reg_lock);
159	reg = bcmgenet_umac_readl(priv, UMAC_CMD);
160	if (reg & CMD_SW_RESET)
161		reg &= ~CMD_SW_RESET;
162
163	/* disable RX */
164	reg &= ~CMD_RX_EN;
165	bcmgenet_umac_writel(priv, reg, UMAC_CMD);
166	spin_unlock_bh(&priv->reg_lock);
167	mdelay(10);
168
169	if (priv->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) {
170		reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
171		reg |= MPD_EN;
172		if (priv->wolopts & WAKE_MAGICSECURE) {
173			bcmgenet_set_mpd_password(priv);
174			reg |= MPD_PW_EN;
175		}
176		bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
177	}
178
179	hfb_ctrl_reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
180	if (priv->wolopts & WAKE_FILTER) {
181		list_for_each_entry(rule, &priv->rxnfc_list, list)
182			if (rule->fs.ring_cookie == RX_CLS_FLOW_WAKE)
183				hfb_enable |= (1 << rule->fs.location);
184		reg = (hfb_ctrl_reg & ~RBUF_HFB_EN) | RBUF_ACPI_EN;
185		bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
186	}
187
188	/* Do not leave UniMAC in MPD mode only */
189	retries = bcmgenet_poll_wol_status(priv);
190	if (retries < 0) {
191		reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
192		reg &= ~(MPD_EN | MPD_PW_EN);
193		bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
194		bcmgenet_hfb_reg_writel(priv, hfb_ctrl_reg, HFB_CTRL);
195		return retries;
196	}
197
198	netif_dbg(priv, wol, dev, "MPD WOL-ready status set after %d msec\n",
199		  retries);
200
201	clk_prepare_enable(priv->clk_wol);
202	priv->wol_active = 1;
203
204	if (hfb_enable) {
205		bcmgenet_hfb_reg_writel(priv, hfb_enable,
206					HFB_FLT_ENABLE_V3PLUS + 4);
207		hfb_ctrl_reg = RBUF_HFB_EN | RBUF_ACPI_EN;
208		bcmgenet_hfb_reg_writel(priv, hfb_ctrl_reg, HFB_CTRL);
209	}
210
211	/* Enable CRC forward */
212	spin_lock_bh(&priv->reg_lock);
213	reg = bcmgenet_umac_readl(priv, UMAC_CMD);
214	priv->crc_fwd_en = 1;
215	reg |= CMD_CRC_FWD;
216
217	/* Receiver must be enabled for WOL MP detection */
218	reg |= CMD_RX_EN;
219	bcmgenet_umac_writel(priv, reg, UMAC_CMD);
220	spin_unlock_bh(&priv->reg_lock);
 
 
 
 
 
221
222	reg = UMAC_IRQ_MPD_R;
223	if (hfb_enable)
224		reg |=  UMAC_IRQ_HFB_SM | UMAC_IRQ_HFB_MM;
225
226	bcmgenet_intrl2_0_writel(priv, reg, INTRL2_CPU_MASK_CLEAR);
227
228	return 0;
229}
230
231void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
232			       enum bcmgenet_power_mode mode)
233{
234	u32 reg;
235
236	if (mode != GENET_POWER_WOL_MAGIC) {
237		netif_err(priv, wol, priv->dev, "invalid mode: %d\n", mode);
238		return;
239	}
240
241	if (!priv->wol_active)
242		return;	/* failed to suspend so skip the rest */
243
244	priv->wol_active = 0;
245	clk_disable_unprepare(priv->clk_wol);
246	priv->crc_fwd_en = 0;
247
248	/* Disable Magic Packet Detection */
249	if (priv->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) {
250		reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
251		if (!(reg & MPD_EN))
252			return;	/* already reset so skip the rest */
253		reg &= ~(MPD_EN | MPD_PW_EN);
254		bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
255	}
256
257	/* Disable WAKE_FILTER Detection */
258	if (priv->wolopts & WAKE_FILTER) {
259		reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
260		if (!(reg & RBUF_ACPI_EN))
261			return;	/* already reset so skip the rest */
262		reg &= ~(RBUF_HFB_EN | RBUF_ACPI_EN);
263		bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
264	}
265
266	/* Disable CRC Forward */
267	spin_lock_bh(&priv->reg_lock);
268	reg = bcmgenet_umac_readl(priv, UMAC_CMD);
269	reg &= ~CMD_CRC_FWD;
270	bcmgenet_umac_writel(priv, reg, UMAC_CMD);
271	spin_unlock_bh(&priv->reg_lock);
272}
v5.9
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support
  4 *
  5 * Copyright (c) 2014-2020 Broadcom
  6 */
  7
  8#define pr_fmt(fmt)				"bcmgenet_wol: " fmt
  9
 10#include <linux/kernel.h>
 11#include <linux/module.h>
 12#include <linux/sched.h>
 13#include <linux/types.h>
 14#include <linux/interrupt.h>
 15#include <linux/string.h>
 16#include <linux/init.h>
 17#include <linux/errno.h>
 18#include <linux/delay.h>
 19#include <linux/pm.h>
 20#include <linux/clk.h>
 21#include <linux/version.h>
 22#include <linux/platform_device.h>
 23#include <net/arp.h>
 24
 25#include <linux/mii.h>
 26#include <linux/ethtool.h>
 27#include <linux/netdevice.h>
 28#include <linux/inetdevice.h>
 29#include <linux/etherdevice.h>
 30#include <linux/skbuff.h>
 31#include <linux/in.h>
 32#include <linux/ip.h>
 33#include <linux/ipv6.h>
 34#include <linux/phy.h>
 35
 36#include "bcmgenet.h"
 37
 38/* ethtool function - get WOL (Wake on LAN) settings, Only Magic Packet
 39 * Detection is supported through ethtool
 40 */
 41void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 42{
 43	struct bcmgenet_priv *priv = netdev_priv(dev);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 44
 45	wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER;
 46	wol->wolopts = priv->wolopts;
 47	memset(wol->sopass, 0, sizeof(wol->sopass));
 48
 49	if (wol->wolopts & WAKE_MAGICSECURE)
 50		memcpy(wol->sopass, priv->sopass, sizeof(priv->sopass));
 51}
 52
 53/* ethtool function - set WOL (Wake on LAN) settings.
 54 * Only for magic packet detection mode.
 55 */
 56int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 57{
 58	struct bcmgenet_priv *priv = netdev_priv(dev);
 59	struct device *kdev = &priv->pdev->dev;
 
 
 
 
 
 
 
 
 60
 61	if (!device_can_wakeup(kdev))
 62		return -ENOTSUPP;
 63
 64	if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER))
 65		return -EINVAL;
 66
 67	if (wol->wolopts & WAKE_MAGICSECURE)
 68		memcpy(priv->sopass, wol->sopass, sizeof(priv->sopass));
 69
 70	/* Flag the device and relevant IRQ as wakeup capable */
 71	if (wol->wolopts) {
 72		device_set_wakeup_enable(kdev, 1);
 73		/* Avoid unbalanced enable_irq_wake calls */
 74		if (priv->wol_irq_disabled)
 75			enable_irq_wake(priv->wol_irq);
 
 
 76		priv->wol_irq_disabled = false;
 77	} else {
 78		device_set_wakeup_enable(kdev, 0);
 79		/* Avoid unbalanced disable_irq_wake calls */
 80		if (!priv->wol_irq_disabled)
 81			disable_irq_wake(priv->wol_irq);
 
 
 82		priv->wol_irq_disabled = true;
 83	}
 84
 85	priv->wolopts = wol->wolopts;
 86
 87	return 0;
 88}
 89
 90static int bcmgenet_poll_wol_status(struct bcmgenet_priv *priv)
 91{
 92	struct net_device *dev = priv->dev;
 93	int retries = 0;
 94
 95	while (!(bcmgenet_rbuf_readl(priv, RBUF_STATUS)
 96		& RBUF_STATUS_WOL)) {
 97		retries++;
 98		if (retries > 5) {
 99			netdev_crit(dev, "polling wol mode timeout\n");
100			return -ETIMEDOUT;
101		}
102		mdelay(1);
103	}
104
105	return retries;
106}
107
108static void bcmgenet_set_mpd_password(struct bcmgenet_priv *priv)
109{
110	bcmgenet_umac_writel(priv, get_unaligned_be16(&priv->sopass[0]),
111			     UMAC_MPD_PW_MS);
112	bcmgenet_umac_writel(priv, get_unaligned_be32(&priv->sopass[2]),
113			     UMAC_MPD_PW_LS);
114}
115
116int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
117				enum bcmgenet_power_mode mode)
118{
119	struct net_device *dev = priv->dev;
120	struct bcmgenet_rxnfc_rule *rule;
121	u32 reg, hfb_ctrl_reg, hfb_enable = 0;
122	int retries = 0;
123
124	if (mode != GENET_POWER_WOL_MAGIC) {
125		netif_err(priv, wol, dev, "unsupported mode: %d\n", mode);
126		return -EINVAL;
127	}
128
129	/* Can't suspend with WoL if MAC is still in reset */
 
130	reg = bcmgenet_umac_readl(priv, UMAC_CMD);
131	if (reg & CMD_SW_RESET)
132		reg &= ~CMD_SW_RESET;
133
134	/* disable RX */
135	reg &= ~CMD_RX_EN;
136	bcmgenet_umac_writel(priv, reg, UMAC_CMD);
 
137	mdelay(10);
138
139	if (priv->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) {
140		reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
141		reg |= MPD_EN;
142		if (priv->wolopts & WAKE_MAGICSECURE) {
143			bcmgenet_set_mpd_password(priv);
144			reg |= MPD_PW_EN;
145		}
146		bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
147	}
148
149	hfb_ctrl_reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
150	if (priv->wolopts & WAKE_FILTER) {
151		list_for_each_entry(rule, &priv->rxnfc_list, list)
152			if (rule->fs.ring_cookie == RX_CLS_FLOW_WAKE)
153				hfb_enable |= (1 << rule->fs.location);
154		reg = (hfb_ctrl_reg & ~RBUF_HFB_EN) | RBUF_ACPI_EN;
155		bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
156	}
157
158	/* Do not leave UniMAC in MPD mode only */
159	retries = bcmgenet_poll_wol_status(priv);
160	if (retries < 0) {
161		reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
162		reg &= ~(MPD_EN | MPD_PW_EN);
163		bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
164		bcmgenet_hfb_reg_writel(priv, hfb_ctrl_reg, HFB_CTRL);
165		return retries;
166	}
167
168	netif_dbg(priv, wol, dev, "MPD WOL-ready status set after %d msec\n",
169		  retries);
170
171	clk_prepare_enable(priv->clk_wol);
172	priv->wol_active = 1;
173
174	if (hfb_enable) {
175		bcmgenet_hfb_reg_writel(priv, hfb_enable,
176					HFB_FLT_ENABLE_V3PLUS + 4);
177		hfb_ctrl_reg = RBUF_HFB_EN | RBUF_ACPI_EN;
178		bcmgenet_hfb_reg_writel(priv, hfb_ctrl_reg, HFB_CTRL);
179	}
180
181	/* Enable CRC forward */
 
182	reg = bcmgenet_umac_readl(priv, UMAC_CMD);
183	priv->crc_fwd_en = 1;
184	reg |= CMD_CRC_FWD;
185
186	/* Receiver must be enabled for WOL MP detection */
187	reg |= CMD_RX_EN;
188	bcmgenet_umac_writel(priv, reg, UMAC_CMD);
189
190	if (priv->hw_params->flags & GENET_HAS_EXT) {
191		reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
192		reg &= ~EXT_ENERGY_DET_MASK;
193		bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
194	}
195
196	reg = UMAC_IRQ_MPD_R;
197	if (hfb_enable)
198		reg |=  UMAC_IRQ_HFB_SM | UMAC_IRQ_HFB_MM;
199
200	bcmgenet_intrl2_0_writel(priv, reg, INTRL2_CPU_MASK_CLEAR);
201
202	return 0;
203}
204
205void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
206			       enum bcmgenet_power_mode mode)
207{
208	u32 reg;
209
210	if (mode != GENET_POWER_WOL_MAGIC) {
211		netif_err(priv, wol, priv->dev, "invalid mode: %d\n", mode);
212		return;
213	}
214
215	if (!priv->wol_active)
216		return;	/* failed to suspend so skip the rest */
217
218	priv->wol_active = 0;
219	clk_disable_unprepare(priv->clk_wol);
220	priv->crc_fwd_en = 0;
221
222	/* Disable Magic Packet Detection */
223	if (priv->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) {
224		reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
225		if (!(reg & MPD_EN))
226			return;	/* already reset so skip the rest */
227		reg &= ~(MPD_EN | MPD_PW_EN);
228		bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
229	}
230
231	/* Disable WAKE_FILTER Detection */
232	if (priv->wolopts & WAKE_FILTER) {
233		reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
234		if (!(reg & RBUF_ACPI_EN))
235			return;	/* already reset so skip the rest */
236		reg &= ~(RBUF_HFB_EN | RBUF_ACPI_EN);
237		bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
238	}
239
240	/* Disable CRC Forward */
 
241	reg = bcmgenet_umac_readl(priv, UMAC_CMD);
242	reg &= ~CMD_CRC_FWD;
243	bcmgenet_umac_writel(priv, reg, UMAC_CMD);
 
244}