forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-11 297b60346df8beafee954a0fd7c2d64f33f3b9bc
kernel/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
....@@ -1,11 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support
34 *
4
- * Copyright (c) 2014-2017 Broadcom
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.
5
+ * Copyright (c) 2014-2020 Broadcom
96 */
107
118 #define pr_fmt(fmt) "bcmgenet_wol: " fmt
....@@ -44,18 +41,20 @@
4441 void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
4542 {
4643 struct bcmgenet_priv *priv = netdev_priv(dev);
47
- u32 reg;
44
+ struct device *kdev = &priv->pdev->dev;
4845
49
- wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE;
46
+ if (!device_can_wakeup(kdev)) {
47
+ wol->supported = 0;
48
+ wol->wolopts = 0;
49
+ return;
50
+ }
51
+
52
+ wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER;
5053 wol->wolopts = priv->wolopts;
5154 memset(wol->sopass, 0, sizeof(wol->sopass));
5255
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
- }
56
+ if (wol->wolopts & WAKE_MAGICSECURE)
57
+ memcpy(wol->sopass, priv->sopass, sizeof(priv->sopass));
5958 }
6059
6160 /* ethtool function - set WOL (Wake on LAN) settings.
....@@ -65,25 +64,15 @@
6564 {
6665 struct bcmgenet_priv *priv = netdev_priv(dev);
6766 struct device *kdev = &priv->pdev->dev;
68
- u32 reg;
6967
7068 if (!device_can_wakeup(kdev))
7169 return -ENOTSUPP;
7270
73
- if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE))
71
+ if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER))
7472 return -EINVAL;
7573
76
- reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
77
- if (wol->wolopts & WAKE_MAGICSECURE) {
78
- bcmgenet_umac_writel(priv, get_unaligned_be16(&wol->sopass[0]),
79
- UMAC_MPD_PW_MS);
80
- bcmgenet_umac_writel(priv, get_unaligned_be32(&wol->sopass[2]),
81
- UMAC_MPD_PW_LS);
82
- reg |= MPD_PW_EN;
83
- } else {
84
- reg &= ~MPD_PW_EN;
85
- }
86
- bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
74
+ if (wol->wolopts & WAKE_MAGICSECURE)
75
+ memcpy(priv->sopass, wol->sopass, sizeof(priv->sopass));
8776
8877 /* Flag the device and relevant IRQ as wakeup capable */
8978 if (wol->wolopts) {
....@@ -123,39 +112,78 @@
123112 return retries;
124113 }
125114
115
+static void bcmgenet_set_mpd_password(struct bcmgenet_priv *priv)
116
+{
117
+ bcmgenet_umac_writel(priv, get_unaligned_be16(&priv->sopass[0]),
118
+ UMAC_MPD_PW_MS);
119
+ bcmgenet_umac_writel(priv, get_unaligned_be32(&priv->sopass[2]),
120
+ UMAC_MPD_PW_LS);
121
+}
122
+
126123 int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
127124 enum bcmgenet_power_mode mode)
128125 {
129126 struct net_device *dev = priv->dev;
127
+ struct bcmgenet_rxnfc_rule *rule;
128
+ u32 reg, hfb_ctrl_reg, hfb_enable = 0;
130129 int retries = 0;
131
- u32 reg;
132130
133131 if (mode != GENET_POWER_WOL_MAGIC) {
134132 netif_err(priv, wol, dev, "unsupported mode: %d\n", mode);
135133 return -EINVAL;
136134 }
137135
138
- /* disable RX */
136
+ /* Can't suspend with WoL if MAC is still in reset */
139137 reg = bcmgenet_umac_readl(priv, UMAC_CMD);
138
+ if (reg & CMD_SW_RESET)
139
+ reg &= ~CMD_SW_RESET;
140
+
141
+ /* disable RX */
140142 reg &= ~CMD_RX_EN;
141143 bcmgenet_umac_writel(priv, reg, UMAC_CMD);
142144 mdelay(10);
143145
144
- reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
145
- reg |= MPD_EN;
146
- bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
146
+ if (priv->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) {
147
+ reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
148
+ reg |= MPD_EN;
149
+ if (priv->wolopts & WAKE_MAGICSECURE) {
150
+ bcmgenet_set_mpd_password(priv);
151
+ reg |= MPD_PW_EN;
152
+ }
153
+ bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
154
+ }
155
+
156
+ hfb_ctrl_reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
157
+ if (priv->wolopts & WAKE_FILTER) {
158
+ list_for_each_entry(rule, &priv->rxnfc_list, list)
159
+ if (rule->fs.ring_cookie == RX_CLS_FLOW_WAKE)
160
+ hfb_enable |= (1 << rule->fs.location);
161
+ reg = (hfb_ctrl_reg & ~RBUF_HFB_EN) | RBUF_ACPI_EN;
162
+ bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
163
+ }
147164
148165 /* Do not leave UniMAC in MPD mode only */
149166 retries = bcmgenet_poll_wol_status(priv);
150167 if (retries < 0) {
151168 reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
152
- reg &= ~MPD_EN;
169
+ reg &= ~(MPD_EN | MPD_PW_EN);
153170 bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
171
+ bcmgenet_hfb_reg_writel(priv, hfb_ctrl_reg, HFB_CTRL);
154172 return retries;
155173 }
156174
157175 netif_dbg(priv, wol, dev, "MPD WOL-ready status set after %d msec\n",
158176 retries);
177
+
178
+ clk_prepare_enable(priv->clk_wol);
179
+ priv->wol_active = 1;
180
+
181
+ if (hfb_enable) {
182
+ bcmgenet_hfb_reg_writel(priv, hfb_enable,
183
+ HFB_FLT_ENABLE_V3PLUS + 4);
184
+ hfb_ctrl_reg = RBUF_HFB_EN | RBUF_ACPI_EN;
185
+ bcmgenet_hfb_reg_writel(priv, hfb_ctrl_reg, HFB_CTRL);
186
+ }
159187
160188 /* Enable CRC forward */
161189 reg = bcmgenet_umac_readl(priv, UMAC_CMD);
....@@ -165,6 +193,12 @@
165193 /* Receiver must be enabled for WOL MP detection */
166194 reg |= CMD_RX_EN;
167195 bcmgenet_umac_writel(priv, reg, UMAC_CMD);
196
+
197
+ reg = UMAC_IRQ_MPD_R;
198
+ if (hfb_enable)
199
+ reg |= UMAC_IRQ_HFB_SM | UMAC_IRQ_HFB_MM;
200
+
201
+ bcmgenet_intrl2_0_writel(priv, reg, INTRL2_CPU_MASK_CLEAR);
168202
169203 return 0;
170204 }
....@@ -179,15 +213,33 @@
179213 return;
180214 }
181215
182
- reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
183
- if (!(reg & MPD_EN))
184
- return; /* already powered up so skip the rest */
185
- reg &= ~MPD_EN;
186
- bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
216
+ if (!priv->wol_active)
217
+ return; /* failed to suspend so skip the rest */
218
+
219
+ priv->wol_active = 0;
220
+ clk_disable_unprepare(priv->clk_wol);
221
+ priv->crc_fwd_en = 0;
222
+
223
+ /* Disable Magic Packet Detection */
224
+ if (priv->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) {
225
+ reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
226
+ if (!(reg & MPD_EN))
227
+ return; /* already reset so skip the rest */
228
+ reg &= ~(MPD_EN | MPD_PW_EN);
229
+ bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
230
+ }
231
+
232
+ /* Disable WAKE_FILTER Detection */
233
+ if (priv->wolopts & WAKE_FILTER) {
234
+ reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
235
+ if (!(reg & RBUF_ACPI_EN))
236
+ return; /* already reset so skip the rest */
237
+ reg &= ~(RBUF_HFB_EN | RBUF_ACPI_EN);
238
+ bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
239
+ }
187240
188241 /* Disable CRC Forward */
189242 reg = bcmgenet_umac_readl(priv, UMAC_CMD);
190243 reg &= ~CMD_CRC_FWD;
191244 bcmgenet_umac_writel(priv, reg, UMAC_CMD);
192
- priv->crc_fwd_en = 0;
193245 }