Commit | Line | Data |
---|---|---|
47dd7a54 GC |
1 | /******************************************************************************* |
2 | STMMAC Ethtool support | |
3 | ||
4 | Copyright (C) 2007-2009 STMicroelectronics Ltd | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify it | |
7 | under the terms and conditions of the GNU General Public License, | |
8 | version 2, as published by the Free Software Foundation. | |
9 | ||
10 | This program is distributed in the hope it will be useful, but WITHOUT | |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License along with | |
16 | this program; if not, write to the Free Software Foundation, Inc., | |
17 | 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | |
18 | ||
19 | The full GNU General Public License is included in this distribution in | |
20 | the file called "COPYING". | |
21 | ||
22 | Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> | |
23 | *******************************************************************************/ | |
24 | ||
25 | #include <linux/etherdevice.h> | |
26 | #include <linux/ethtool.h> | |
a6b7a407 | 27 | #include <linux/interrupt.h> |
47dd7a54 GC |
28 | #include <linux/mii.h> |
29 | #include <linux/phy.h> | |
b7f080cf | 30 | #include <asm/io.h> |
47dd7a54 GC |
31 | |
32 | #include "stmmac.h" | |
aec7ff27 | 33 | #include "dwmac_dma.h" |
47dd7a54 GC |
34 | |
35 | #define REG_SPACE_SIZE 0x1054 | |
36 | #define MAC100_ETHTOOL_NAME "st_mac100" | |
37 | #define GMAC_ETHTOOL_NAME "st_gmac" | |
38 | ||
39 | struct stmmac_stats { | |
40 | char stat_string[ETH_GSTRING_LEN]; | |
41 | int sizeof_stat; | |
42 | int stat_offset; | |
43 | }; | |
44 | ||
45 | #define STMMAC_STAT(m) \ | |
46 | { #m, FIELD_SIZEOF(struct stmmac_extra_stats, m), \ | |
47 | offsetof(struct stmmac_priv, xstats.m)} | |
48 | ||
1c901a46 | 49 | static const struct stmmac_stats stmmac_gstrings_stats[] = { |
47dd7a54 GC |
50 | STMMAC_STAT(tx_underflow), |
51 | STMMAC_STAT(tx_carrier), | |
52 | STMMAC_STAT(tx_losscarrier), | |
3c20f72f | 53 | STMMAC_STAT(vlan_tag), |
47dd7a54 GC |
54 | STMMAC_STAT(tx_deferred), |
55 | STMMAC_STAT(tx_vlan), | |
56 | STMMAC_STAT(rx_vlan), | |
57 | STMMAC_STAT(tx_jabber), | |
58 | STMMAC_STAT(tx_frame_flushed), | |
59 | STMMAC_STAT(tx_payload_error), | |
60 | STMMAC_STAT(tx_ip_header_error), | |
61 | STMMAC_STAT(rx_desc), | |
3c20f72f GC |
62 | STMMAC_STAT(sa_filter_fail), |
63 | STMMAC_STAT(overflow_error), | |
64 | STMMAC_STAT(ipc_csum_error), | |
47dd7a54 GC |
65 | STMMAC_STAT(rx_collision), |
66 | STMMAC_STAT(rx_crc), | |
1b924032 | 67 | STMMAC_STAT(rx_length), |
47dd7a54 GC |
68 | STMMAC_STAT(rx_mii), |
69 | STMMAC_STAT(rx_multicast), | |
70 | STMMAC_STAT(rx_gmac_overflow), | |
71 | STMMAC_STAT(rx_watchdog), | |
72 | STMMAC_STAT(da_rx_filter_fail), | |
73 | STMMAC_STAT(sa_rx_filter_fail), | |
74 | STMMAC_STAT(rx_missed_cntr), | |
75 | STMMAC_STAT(rx_overflow_cntr), | |
76 | STMMAC_STAT(tx_undeflow_irq), | |
77 | STMMAC_STAT(tx_process_stopped_irq), | |
78 | STMMAC_STAT(tx_jabber_irq), | |
79 | STMMAC_STAT(rx_overflow_irq), | |
80 | STMMAC_STAT(rx_buf_unav_irq), | |
81 | STMMAC_STAT(rx_process_stopped_irq), | |
82 | STMMAC_STAT(rx_watchdog_irq), | |
83 | STMMAC_STAT(tx_early_irq), | |
84 | STMMAC_STAT(fatal_bus_error_irq), | |
85 | STMMAC_STAT(threshold), | |
86 | STMMAC_STAT(tx_pkt_n), | |
87 | STMMAC_STAT(rx_pkt_n), | |
88 | STMMAC_STAT(poll_n), | |
89 | STMMAC_STAT(sched_timer_n), | |
90 | STMMAC_STAT(normal_irq_n), | |
91 | }; | |
92 | #define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats) | |
93 | ||
1c901a46 GC |
94 | /* HW MAC Management counters (if supported) */ |
95 | #define STMMAC_MMC_STAT(m) \ | |
96 | { #m, FIELD_SIZEOF(struct stmmac_counters, m), \ | |
97 | offsetof(struct stmmac_priv, mmc.m)} | |
98 | ||
38fe7a93 | 99 | static const struct stmmac_stats stmmac_mmc[] = { |
1c901a46 GC |
100 | STMMAC_MMC_STAT(mmc_tx_octetcount_gb), |
101 | STMMAC_MMC_STAT(mmc_tx_framecount_gb), | |
102 | STMMAC_MMC_STAT(mmc_tx_broadcastframe_g), | |
103 | STMMAC_MMC_STAT(mmc_tx_multicastframe_g), | |
104 | STMMAC_MMC_STAT(mmc_tx_64_octets_gb), | |
105 | STMMAC_MMC_STAT(mmc_tx_65_to_127_octets_gb), | |
106 | STMMAC_MMC_STAT(mmc_tx_128_to_255_octets_gb), | |
107 | STMMAC_MMC_STAT(mmc_tx_256_to_511_octets_gb), | |
108 | STMMAC_MMC_STAT(mmc_tx_512_to_1023_octets_gb), | |
109 | STMMAC_MMC_STAT(mmc_tx_1024_to_max_octets_gb), | |
110 | STMMAC_MMC_STAT(mmc_tx_unicast_gb), | |
111 | STMMAC_MMC_STAT(mmc_tx_multicast_gb), | |
112 | STMMAC_MMC_STAT(mmc_tx_broadcast_gb), | |
113 | STMMAC_MMC_STAT(mmc_tx_underflow_error), | |
114 | STMMAC_MMC_STAT(mmc_tx_singlecol_g), | |
115 | STMMAC_MMC_STAT(mmc_tx_multicol_g), | |
116 | STMMAC_MMC_STAT(mmc_tx_deferred), | |
117 | STMMAC_MMC_STAT(mmc_tx_latecol), | |
118 | STMMAC_MMC_STAT(mmc_tx_exesscol), | |
119 | STMMAC_MMC_STAT(mmc_tx_carrier_error), | |
120 | STMMAC_MMC_STAT(mmc_tx_octetcount_g), | |
121 | STMMAC_MMC_STAT(mmc_tx_framecount_g), | |
122 | STMMAC_MMC_STAT(mmc_tx_excessdef), | |
123 | STMMAC_MMC_STAT(mmc_tx_pause_frame), | |
124 | STMMAC_MMC_STAT(mmc_tx_vlan_frame_g), | |
125 | STMMAC_MMC_STAT(mmc_rx_framecount_gb), | |
126 | STMMAC_MMC_STAT(mmc_rx_octetcount_gb), | |
127 | STMMAC_MMC_STAT(mmc_rx_octetcount_g), | |
128 | STMMAC_MMC_STAT(mmc_rx_broadcastframe_g), | |
129 | STMMAC_MMC_STAT(mmc_rx_multicastframe_g), | |
130 | STMMAC_MMC_STAT(mmc_rx_crc_errror), | |
131 | STMMAC_MMC_STAT(mmc_rx_align_error), | |
132 | STMMAC_MMC_STAT(mmc_rx_run_error), | |
133 | STMMAC_MMC_STAT(mmc_rx_jabber_error), | |
134 | STMMAC_MMC_STAT(mmc_rx_undersize_g), | |
135 | STMMAC_MMC_STAT(mmc_rx_oversize_g), | |
136 | STMMAC_MMC_STAT(mmc_rx_64_octets_gb), | |
137 | STMMAC_MMC_STAT(mmc_rx_65_to_127_octets_gb), | |
138 | STMMAC_MMC_STAT(mmc_rx_128_to_255_octets_gb), | |
139 | STMMAC_MMC_STAT(mmc_rx_256_to_511_octets_gb), | |
140 | STMMAC_MMC_STAT(mmc_rx_512_to_1023_octets_gb), | |
141 | STMMAC_MMC_STAT(mmc_rx_1024_to_max_octets_gb), | |
142 | STMMAC_MMC_STAT(mmc_rx_unicast_g), | |
143 | STMMAC_MMC_STAT(mmc_rx_length_error), | |
144 | STMMAC_MMC_STAT(mmc_rx_autofrangetype), | |
145 | STMMAC_MMC_STAT(mmc_rx_pause_frames), | |
146 | STMMAC_MMC_STAT(mmc_rx_fifo_overflow), | |
147 | STMMAC_MMC_STAT(mmc_rx_vlan_frames_gb), | |
148 | STMMAC_MMC_STAT(mmc_rx_watchdog_error), | |
149 | STMMAC_MMC_STAT(mmc_rx_ipc_intr_mask), | |
150 | STMMAC_MMC_STAT(mmc_rx_ipc_intr), | |
151 | STMMAC_MMC_STAT(mmc_rx_ipv4_gd), | |
152 | STMMAC_MMC_STAT(mmc_rx_ipv4_hderr), | |
153 | STMMAC_MMC_STAT(mmc_rx_ipv4_nopay), | |
154 | STMMAC_MMC_STAT(mmc_rx_ipv4_frag), | |
155 | STMMAC_MMC_STAT(mmc_rx_ipv4_udsbl), | |
156 | STMMAC_MMC_STAT(mmc_rx_ipv4_gd_octets), | |
157 | STMMAC_MMC_STAT(mmc_rx_ipv4_hderr_octets), | |
158 | STMMAC_MMC_STAT(mmc_rx_ipv4_nopay_octets), | |
159 | STMMAC_MMC_STAT(mmc_rx_ipv4_frag_octets), | |
160 | STMMAC_MMC_STAT(mmc_rx_ipv4_udsbl_octets), | |
161 | STMMAC_MMC_STAT(mmc_rx_ipv6_gd_octets), | |
162 | STMMAC_MMC_STAT(mmc_rx_ipv6_hderr_octets), | |
163 | STMMAC_MMC_STAT(mmc_rx_ipv6_nopay_octets), | |
164 | STMMAC_MMC_STAT(mmc_rx_ipv6_gd), | |
165 | STMMAC_MMC_STAT(mmc_rx_ipv6_hderr), | |
166 | STMMAC_MMC_STAT(mmc_rx_ipv6_nopay), | |
167 | STMMAC_MMC_STAT(mmc_rx_udp_gd), | |
168 | STMMAC_MMC_STAT(mmc_rx_udp_err), | |
169 | STMMAC_MMC_STAT(mmc_rx_tcp_gd), | |
170 | STMMAC_MMC_STAT(mmc_rx_tcp_err), | |
171 | STMMAC_MMC_STAT(mmc_rx_icmp_gd), | |
172 | STMMAC_MMC_STAT(mmc_rx_icmp_err), | |
173 | STMMAC_MMC_STAT(mmc_rx_udp_gd_octets), | |
174 | STMMAC_MMC_STAT(mmc_rx_udp_err_octets), | |
175 | STMMAC_MMC_STAT(mmc_rx_tcp_gd_octets), | |
176 | STMMAC_MMC_STAT(mmc_rx_tcp_err_octets), | |
177 | STMMAC_MMC_STAT(mmc_rx_icmp_gd_octets), | |
178 | STMMAC_MMC_STAT(mmc_rx_icmp_err_octets), | |
179 | }; | |
38fe7a93 | 180 | #define STMMAC_MMC_STATS_LEN ARRAY_SIZE(stmmac_mmc) |
1c901a46 | 181 | |
8ee17ae6 | 182 | static void stmmac_ethtool_getdrvinfo(struct net_device *dev, |
183 | struct ethtool_drvinfo *info) | |
47dd7a54 GC |
184 | { |
185 | struct stmmac_priv *priv = netdev_priv(dev); | |
186 | ||
1c901a46 | 187 | if (priv->plat->has_gmac) |
47dd7a54 | 188 | strcpy(info->driver, GMAC_ETHTOOL_NAME); |
1c901a46 GC |
189 | else |
190 | strcpy(info->driver, MAC100_ETHTOOL_NAME); | |
47dd7a54 GC |
191 | |
192 | strcpy(info->version, DRV_MODULE_VERSION); | |
193 | info->fw_version[0] = '\0'; | |
47dd7a54 GC |
194 | } |
195 | ||
8ee17ae6 | 196 | static int stmmac_ethtool_getsettings(struct net_device *dev, |
197 | struct ethtool_cmd *cmd) | |
47dd7a54 GC |
198 | { |
199 | struct stmmac_priv *priv = netdev_priv(dev); | |
200 | struct phy_device *phy = priv->phydev; | |
201 | int rc; | |
202 | if (phy == NULL) { | |
203 | pr_err("%s: %s: PHY is not registered\n", | |
204 | __func__, dev->name); | |
205 | return -ENODEV; | |
206 | } | |
207 | if (!netif_running(dev)) { | |
208 | pr_err("%s: interface is disabled: we cannot track " | |
209 | "link speed / duplex setting\n", dev->name); | |
210 | return -EBUSY; | |
211 | } | |
212 | cmd->transceiver = XCVR_INTERNAL; | |
213 | spin_lock_irq(&priv->lock); | |
214 | rc = phy_ethtool_gset(phy, cmd); | |
215 | spin_unlock_irq(&priv->lock); | |
216 | return rc; | |
217 | } | |
218 | ||
8ee17ae6 | 219 | static int stmmac_ethtool_setsettings(struct net_device *dev, |
220 | struct ethtool_cmd *cmd) | |
47dd7a54 GC |
221 | { |
222 | struct stmmac_priv *priv = netdev_priv(dev); | |
223 | struct phy_device *phy = priv->phydev; | |
224 | int rc; | |
225 | ||
226 | spin_lock(&priv->lock); | |
227 | rc = phy_ethtool_sset(phy, cmd); | |
228 | spin_unlock(&priv->lock); | |
229 | ||
230 | return rc; | |
231 | } | |
232 | ||
8ee17ae6 | 233 | static u32 stmmac_ethtool_getmsglevel(struct net_device *dev) |
47dd7a54 GC |
234 | { |
235 | struct stmmac_priv *priv = netdev_priv(dev); | |
236 | return priv->msg_enable; | |
237 | } | |
238 | ||
8ee17ae6 | 239 | static void stmmac_ethtool_setmsglevel(struct net_device *dev, u32 level) |
47dd7a54 GC |
240 | { |
241 | struct stmmac_priv *priv = netdev_priv(dev); | |
242 | priv->msg_enable = level; | |
243 | ||
244 | } | |
245 | ||
8ee17ae6 | 246 | static int stmmac_check_if_running(struct net_device *dev) |
47dd7a54 GC |
247 | { |
248 | if (!netif_running(dev)) | |
249 | return -EBUSY; | |
250 | return 0; | |
251 | } | |
252 | ||
8ee17ae6 | 253 | static int stmmac_ethtool_get_regs_len(struct net_device *dev) |
47dd7a54 GC |
254 | { |
255 | return REG_SPACE_SIZE; | |
256 | } | |
257 | ||
8ee17ae6 | 258 | static void stmmac_ethtool_gregs(struct net_device *dev, |
47dd7a54 GC |
259 | struct ethtool_regs *regs, void *space) |
260 | { | |
261 | int i; | |
262 | u32 *reg_space = (u32 *) space; | |
263 | ||
264 | struct stmmac_priv *priv = netdev_priv(dev); | |
265 | ||
266 | memset(reg_space, 0x0, REG_SPACE_SIZE); | |
267 | ||
9dfeb4d9 | 268 | if (!priv->plat->has_gmac) { |
47dd7a54 GC |
269 | /* MAC registers */ |
270 | for (i = 0; i < 12; i++) | |
ad01b7d4 | 271 | reg_space[i] = readl(priv->ioaddr + (i * 4)); |
47dd7a54 GC |
272 | /* DMA registers */ |
273 | for (i = 0; i < 9; i++) | |
274 | reg_space[i + 12] = | |
ad01b7d4 GC |
275 | readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4))); |
276 | reg_space[22] = readl(priv->ioaddr + DMA_CUR_TX_BUF_ADDR); | |
277 | reg_space[23] = readl(priv->ioaddr + DMA_CUR_RX_BUF_ADDR); | |
47dd7a54 GC |
278 | } else { |
279 | /* MAC registers */ | |
280 | for (i = 0; i < 55; i++) | |
ad01b7d4 | 281 | reg_space[i] = readl(priv->ioaddr + (i * 4)); |
47dd7a54 GC |
282 | /* DMA registers */ |
283 | for (i = 0; i < 22; i++) | |
284 | reg_space[i + 55] = | |
ad01b7d4 | 285 | readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4))); |
47dd7a54 | 286 | } |
47dd7a54 GC |
287 | } |
288 | ||
47dd7a54 GC |
289 | static void |
290 | stmmac_get_pauseparam(struct net_device *netdev, | |
291 | struct ethtool_pauseparam *pause) | |
292 | { | |
293 | struct stmmac_priv *priv = netdev_priv(netdev); | |
294 | ||
295 | spin_lock(&priv->lock); | |
296 | ||
297 | pause->rx_pause = 0; | |
298 | pause->tx_pause = 0; | |
299 | pause->autoneg = priv->phydev->autoneg; | |
300 | ||
301 | if (priv->flow_ctrl & FLOW_RX) | |
302 | pause->rx_pause = 1; | |
303 | if (priv->flow_ctrl & FLOW_TX) | |
304 | pause->tx_pause = 1; | |
305 | ||
306 | spin_unlock(&priv->lock); | |
47dd7a54 GC |
307 | } |
308 | ||
309 | static int | |
310 | stmmac_set_pauseparam(struct net_device *netdev, | |
311 | struct ethtool_pauseparam *pause) | |
312 | { | |
313 | struct stmmac_priv *priv = netdev_priv(netdev); | |
314 | struct phy_device *phy = priv->phydev; | |
315 | int new_pause = FLOW_OFF; | |
316 | int ret = 0; | |
317 | ||
318 | spin_lock(&priv->lock); | |
319 | ||
320 | if (pause->rx_pause) | |
321 | new_pause |= FLOW_RX; | |
322 | if (pause->tx_pause) | |
323 | new_pause |= FLOW_TX; | |
324 | ||
325 | priv->flow_ctrl = new_pause; | |
64c7f304 | 326 | phy->autoneg = pause->autoneg; |
47dd7a54 GC |
327 | |
328 | if (phy->autoneg) { | |
1334cb60 DD |
329 | if (netif_running(netdev)) |
330 | ret = phy_start_aneg(phy); | |
ad01b7d4 GC |
331 | } else |
332 | priv->hw->mac->flow_ctrl(priv->ioaddr, phy->duplex, | |
db98a0b0 | 333 | priv->flow_ctrl, priv->pause); |
47dd7a54 GC |
334 | spin_unlock(&priv->lock); |
335 | return ret; | |
336 | } | |
337 | ||
338 | static void stmmac_get_ethtool_stats(struct net_device *dev, | |
339 | struct ethtool_stats *dummy, u64 *data) | |
340 | { | |
341 | struct stmmac_priv *priv = netdev_priv(dev); | |
1c901a46 | 342 | int i, j = 0; |
47dd7a54 | 343 | |
1c901a46 GC |
344 | /* Update the DMA HW counters for dwmac10/100 */ |
345 | if (!priv->plat->has_gmac) | |
346 | priv->hw->dma->dma_diagnostic_fr(&dev->stats, | |
347 | (void *) &priv->xstats, | |
348 | priv->ioaddr); | |
349 | else { | |
350 | /* If supported, for new GMAC chips expose the MMC counters */ | |
38fe7a93 GC |
351 | if (priv->dma_cap.rmon) { |
352 | dwmac_mmc_read(priv->ioaddr, &priv->mmc); | |
1c901a46 | 353 | |
38fe7a93 GC |
354 | for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) { |
355 | char *p; | |
356 | p = (char *)priv + stmmac_mmc[i].stat_offset; | |
1c901a46 | 357 | |
38fe7a93 GC |
358 | data[j++] = (stmmac_mmc[i].sizeof_stat == |
359 | sizeof(u64)) ? (*(u64 *)p) : | |
360 | (*(u32 *)p); | |
361 | } | |
1c901a46 GC |
362 | } |
363 | } | |
47dd7a54 GC |
364 | for (i = 0; i < STMMAC_STATS_LEN; i++) { |
365 | char *p = (char *)priv + stmmac_gstrings_stats[i].stat_offset; | |
1c901a46 GC |
366 | data[j++] = (stmmac_gstrings_stats[i].sizeof_stat == |
367 | sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); | |
47dd7a54 | 368 | } |
47dd7a54 GC |
369 | } |
370 | ||
371 | static int stmmac_get_sset_count(struct net_device *netdev, int sset) | |
372 | { | |
1c901a46 GC |
373 | struct stmmac_priv *priv = netdev_priv(netdev); |
374 | int len; | |
375 | ||
47dd7a54 GC |
376 | switch (sset) { |
377 | case ETH_SS_STATS: | |
1c901a46 GC |
378 | len = STMMAC_STATS_LEN; |
379 | ||
38fe7a93 | 380 | if (priv->dma_cap.rmon) |
1c901a46 GC |
381 | len += STMMAC_MMC_STATS_LEN; |
382 | ||
383 | return len; | |
47dd7a54 GC |
384 | default: |
385 | return -EOPNOTSUPP; | |
386 | } | |
387 | } | |
388 | ||
389 | static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data) | |
390 | { | |
391 | int i; | |
392 | u8 *p = data; | |
1c901a46 | 393 | struct stmmac_priv *priv = netdev_priv(dev); |
47dd7a54 GC |
394 | |
395 | switch (stringset) { | |
396 | case ETH_SS_STATS: | |
38fe7a93 | 397 | if (priv->dma_cap.rmon) |
1c901a46 | 398 | for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) { |
38fe7a93 | 399 | memcpy(p, stmmac_mmc[i].stat_string, |
1c901a46 GC |
400 | ETH_GSTRING_LEN); |
401 | p += ETH_GSTRING_LEN; | |
402 | } | |
47dd7a54 GC |
403 | for (i = 0; i < STMMAC_STATS_LEN; i++) { |
404 | memcpy(p, stmmac_gstrings_stats[i].stat_string, | |
405 | ETH_GSTRING_LEN); | |
406 | p += ETH_GSTRING_LEN; | |
407 | } | |
408 | break; | |
409 | default: | |
410 | WARN_ON(1); | |
411 | break; | |
412 | } | |
47dd7a54 GC |
413 | } |
414 | ||
415 | /* Currently only support WOL through Magic packet. */ | |
416 | static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | |
417 | { | |
418 | struct stmmac_priv *priv = netdev_priv(dev); | |
419 | ||
420 | spin_lock_irq(&priv->lock); | |
543876c9 | 421 | if (device_can_wakeup(priv->device)) { |
74ae2fd7 | 422 | wol->supported = WAKE_MAGIC | WAKE_UCAST; |
47dd7a54 GC |
423 | wol->wolopts = priv->wolopts; |
424 | } | |
425 | spin_unlock_irq(&priv->lock); | |
426 | } | |
427 | ||
428 | static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | |
429 | { | |
430 | struct stmmac_priv *priv = netdev_priv(dev); | |
74ae2fd7 | 431 | u32 support = WAKE_MAGIC | WAKE_UCAST; |
47dd7a54 | 432 | |
543876c9 | 433 | if (!device_can_wakeup(priv->device)) |
47dd7a54 GC |
434 | return -EINVAL; |
435 | ||
436 | if (wol->wolopts & ~support) | |
437 | return -EINVAL; | |
438 | ||
543876c9 GC |
439 | if (wol->wolopts) { |
440 | pr_info("stmmac: wakeup enable\n"); | |
47dd7a54 | 441 | device_set_wakeup_enable(priv->device, 1); |
3172d3af | 442 | enable_irq_wake(priv->wol_irq); |
543876c9 GC |
443 | } else { |
444 | device_set_wakeup_enable(priv->device, 0); | |
3172d3af | 445 | disable_irq_wake(priv->wol_irq); |
543876c9 | 446 | } |
47dd7a54 GC |
447 | |
448 | spin_lock_irq(&priv->lock); | |
449 | priv->wolopts = wol->wolopts; | |
450 | spin_unlock_irq(&priv->lock); | |
451 | ||
452 | return 0; | |
453 | } | |
454 | ||
455 | static struct ethtool_ops stmmac_ethtool_ops = { | |
456 | .begin = stmmac_check_if_running, | |
457 | .get_drvinfo = stmmac_ethtool_getdrvinfo, | |
458 | .get_settings = stmmac_ethtool_getsettings, | |
459 | .set_settings = stmmac_ethtool_setsettings, | |
460 | .get_msglevel = stmmac_ethtool_getmsglevel, | |
461 | .set_msglevel = stmmac_ethtool_setmsglevel, | |
462 | .get_regs = stmmac_ethtool_gregs, | |
463 | .get_regs_len = stmmac_ethtool_get_regs_len, | |
464 | .get_link = ethtool_op_get_link, | |
47dd7a54 GC |
465 | .get_pauseparam = stmmac_get_pauseparam, |
466 | .set_pauseparam = stmmac_set_pauseparam, | |
467 | .get_ethtool_stats = stmmac_get_ethtool_stats, | |
468 | .get_strings = stmmac_get_strings, | |
469 | .get_wol = stmmac_get_wol, | |
470 | .set_wol = stmmac_set_wol, | |
471 | .get_sset_count = stmmac_get_sset_count, | |
47dd7a54 GC |
472 | }; |
473 | ||
474 | void stmmac_set_ethtool_ops(struct net_device *netdev) | |
475 | { | |
476 | SET_ETHTOOL_OPS(netdev, &stmmac_ethtool_ops); | |
477 | } |