1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /******************************************************************************* |
3 | STMMAC Ethtool support |
4 | |
5 | Copyright (C) 2007-2009 STMicroelectronics Ltd |
6 | |
7 | |
8 | Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> |
9 | *******************************************************************************/ |
10 | |
11 | #include <linux/etherdevice.h> |
12 | #include <linux/ethtool.h> |
13 | #include <linux/interrupt.h> |
14 | #include <linux/mii.h> |
15 | #include <linux/phylink.h> |
16 | #include <linux/net_tstamp.h> |
17 | #include <asm/io.h> |
18 | |
19 | #include "stmmac.h" |
20 | #include "dwmac_dma.h" |
21 | #include "dwxgmac2.h" |
22 | |
23 | #define REG_SPACE_SIZE 0x1060 |
24 | #define GMAC4_REG_SPACE_SIZE 0x116C |
25 | #define MAC100_ETHTOOL_NAME "st_mac100" |
26 | #define GMAC_ETHTOOL_NAME "st_gmac" |
27 | #define XGMAC_ETHTOOL_NAME "st_xgmac" |
28 | |
29 | /* Same as DMA_CHAN_BASE_ADDR defined in dwmac4_dma.h |
30 | * |
31 | * It is here because dwmac_dma.h and dwmac4_dam.h can not be included at the |
32 | * same time due to the conflicting macro names. |
33 | */ |
34 | #define GMAC4_DMA_CHAN_BASE_ADDR 0x00001100 |
35 | |
36 | #define ETHTOOL_DMA_OFFSET 55 |
37 | |
38 | struct stmmac_stats { |
39 | char stat_string[ETH_GSTRING_LEN]; |
40 | int sizeof_stat; |
41 | int stat_offset; |
42 | }; |
43 | |
44 | #define STMMAC_STAT(m) \ |
45 | { #m, sizeof_field(struct stmmac_extra_stats, m), \ |
46 | offsetof(struct stmmac_priv, xstats.m)} |
47 | |
48 | static const struct stmmac_stats stmmac_gstrings_stats[] = { |
49 | /* Transmit errors */ |
50 | STMMAC_STAT(tx_underflow), |
51 | STMMAC_STAT(tx_carrier), |
52 | STMMAC_STAT(tx_losscarrier), |
53 | STMMAC_STAT(vlan_tag), |
54 | STMMAC_STAT(tx_deferred), |
55 | STMMAC_STAT(tx_vlan), |
56 | STMMAC_STAT(tx_jabber), |
57 | STMMAC_STAT(tx_frame_flushed), |
58 | STMMAC_STAT(tx_payload_error), |
59 | STMMAC_STAT(tx_ip_header_error), |
60 | /* Receive errors */ |
61 | STMMAC_STAT(rx_desc), |
62 | STMMAC_STAT(sa_filter_fail), |
63 | STMMAC_STAT(overflow_error), |
64 | STMMAC_STAT(ipc_csum_error), |
65 | STMMAC_STAT(rx_collision), |
66 | STMMAC_STAT(rx_crc_errors), |
67 | STMMAC_STAT(dribbling_bit), |
68 | STMMAC_STAT(rx_length), |
69 | STMMAC_STAT(rx_mii), |
70 | STMMAC_STAT(rx_multicast), |
71 | STMMAC_STAT(rx_gmac_overflow), |
72 | STMMAC_STAT(rx_watchdog), |
73 | STMMAC_STAT(da_rx_filter_fail), |
74 | STMMAC_STAT(sa_rx_filter_fail), |
75 | STMMAC_STAT(rx_missed_cntr), |
76 | STMMAC_STAT(rx_overflow_cntr), |
77 | STMMAC_STAT(rx_vlan), |
78 | STMMAC_STAT(rx_split_hdr_pkt_n), |
79 | /* Tx/Rx IRQ error info */ |
80 | STMMAC_STAT(tx_undeflow_irq), |
81 | STMMAC_STAT(tx_process_stopped_irq), |
82 | STMMAC_STAT(tx_jabber_irq), |
83 | STMMAC_STAT(rx_overflow_irq), |
84 | STMMAC_STAT(rx_buf_unav_irq), |
85 | STMMAC_STAT(rx_process_stopped_irq), |
86 | STMMAC_STAT(rx_watchdog_irq), |
87 | STMMAC_STAT(tx_early_irq), |
88 | STMMAC_STAT(fatal_bus_error_irq), |
89 | /* Tx/Rx IRQ Events */ |
90 | STMMAC_STAT(rx_early_irq), |
91 | STMMAC_STAT(threshold), |
92 | STMMAC_STAT(irq_receive_pmt_irq_n), |
93 | /* MMC info */ |
94 | STMMAC_STAT(mmc_tx_irq_n), |
95 | STMMAC_STAT(mmc_rx_irq_n), |
96 | STMMAC_STAT(mmc_rx_csum_offload_irq_n), |
97 | /* EEE */ |
98 | STMMAC_STAT(irq_tx_path_in_lpi_mode_n), |
99 | STMMAC_STAT(irq_tx_path_exit_lpi_mode_n), |
100 | STMMAC_STAT(irq_rx_path_in_lpi_mode_n), |
101 | STMMAC_STAT(irq_rx_path_exit_lpi_mode_n), |
102 | STMMAC_STAT(phy_eee_wakeup_error_n), |
103 | /* Extended RDES status */ |
104 | STMMAC_STAT(ip_hdr_err), |
105 | STMMAC_STAT(ip_payload_err), |
106 | STMMAC_STAT(ip_csum_bypassed), |
107 | STMMAC_STAT(ipv4_pkt_rcvd), |
108 | STMMAC_STAT(ipv6_pkt_rcvd), |
109 | STMMAC_STAT(no_ptp_rx_msg_type_ext), |
110 | STMMAC_STAT(ptp_rx_msg_type_sync), |
111 | STMMAC_STAT(ptp_rx_msg_type_follow_up), |
112 | STMMAC_STAT(ptp_rx_msg_type_delay_req), |
113 | STMMAC_STAT(ptp_rx_msg_type_delay_resp), |
114 | STMMAC_STAT(ptp_rx_msg_type_pdelay_req), |
115 | STMMAC_STAT(ptp_rx_msg_type_pdelay_resp), |
116 | STMMAC_STAT(ptp_rx_msg_type_pdelay_follow_up), |
117 | STMMAC_STAT(ptp_rx_msg_type_announce), |
118 | STMMAC_STAT(ptp_rx_msg_type_management), |
119 | STMMAC_STAT(ptp_rx_msg_pkt_reserved_type), |
120 | STMMAC_STAT(ptp_frame_type), |
121 | STMMAC_STAT(ptp_ver), |
122 | STMMAC_STAT(timestamp_dropped), |
123 | STMMAC_STAT(av_pkt_rcvd), |
124 | STMMAC_STAT(av_tagged_pkt_rcvd), |
125 | STMMAC_STAT(vlan_tag_priority_val), |
126 | STMMAC_STAT(l3_filter_match), |
127 | STMMAC_STAT(l4_filter_match), |
128 | STMMAC_STAT(l3_l4_filter_no_match), |
129 | /* PCS */ |
130 | STMMAC_STAT(irq_pcs_ane_n), |
131 | STMMAC_STAT(irq_pcs_link_n), |
132 | STMMAC_STAT(irq_rgmii_n), |
133 | /* DEBUG */ |
134 | STMMAC_STAT(mtl_tx_status_fifo_full), |
135 | STMMAC_STAT(mtl_tx_fifo_not_empty), |
136 | STMMAC_STAT(mmtl_fifo_ctrl), |
137 | STMMAC_STAT(mtl_tx_fifo_read_ctrl_write), |
138 | STMMAC_STAT(mtl_tx_fifo_read_ctrl_wait), |
139 | STMMAC_STAT(mtl_tx_fifo_read_ctrl_read), |
140 | STMMAC_STAT(mtl_tx_fifo_read_ctrl_idle), |
141 | STMMAC_STAT(mac_tx_in_pause), |
142 | STMMAC_STAT(mac_tx_frame_ctrl_xfer), |
143 | STMMAC_STAT(mac_tx_frame_ctrl_idle), |
144 | STMMAC_STAT(mac_tx_frame_ctrl_wait), |
145 | STMMAC_STAT(mac_tx_frame_ctrl_pause), |
146 | STMMAC_STAT(mac_gmii_tx_proto_engine), |
147 | STMMAC_STAT(mtl_rx_fifo_fill_level_full), |
148 | STMMAC_STAT(mtl_rx_fifo_fill_above_thresh), |
149 | STMMAC_STAT(mtl_rx_fifo_fill_below_thresh), |
150 | STMMAC_STAT(mtl_rx_fifo_fill_level_empty), |
151 | STMMAC_STAT(mtl_rx_fifo_read_ctrl_flush), |
152 | STMMAC_STAT(mtl_rx_fifo_read_ctrl_read_data), |
153 | STMMAC_STAT(mtl_rx_fifo_read_ctrl_status), |
154 | STMMAC_STAT(mtl_rx_fifo_read_ctrl_idle), |
155 | STMMAC_STAT(mtl_rx_fifo_ctrl_active), |
156 | STMMAC_STAT(mac_rx_frame_ctrl_fifo), |
157 | STMMAC_STAT(mac_gmii_rx_proto_engine), |
158 | /* EST */ |
159 | STMMAC_STAT(mtl_est_cgce), |
160 | STMMAC_STAT(mtl_est_hlbs), |
161 | STMMAC_STAT(mtl_est_hlbf), |
162 | STMMAC_STAT(mtl_est_btre), |
163 | STMMAC_STAT(mtl_est_btrlm), |
164 | }; |
165 | #define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats) |
166 | |
167 | /* statistics collected in queue which will be summed up for all TX or RX |
168 | * queues, or summed up for both TX and RX queues(napi_poll, normal_irq_n). |
169 | */ |
170 | static const char stmmac_qstats_string[][ETH_GSTRING_LEN] = { |
171 | "rx_pkt_n" , |
172 | "rx_normal_irq_n" , |
173 | "tx_pkt_n" , |
174 | "tx_normal_irq_n" , |
175 | "tx_clean" , |
176 | "tx_set_ic_bit" , |
177 | "tx_tso_frames" , |
178 | "tx_tso_nfrags" , |
179 | "normal_irq_n" , |
180 | "napi_poll" , |
181 | }; |
182 | #define STMMAC_QSTATS ARRAY_SIZE(stmmac_qstats_string) |
183 | |
184 | /* HW MAC Management counters (if supported) */ |
185 | #define STMMAC_MMC_STAT(m) \ |
186 | { #m, sizeof_field(struct stmmac_counters, m), \ |
187 | offsetof(struct stmmac_priv, mmc.m)} |
188 | |
189 | static const struct stmmac_stats stmmac_mmc[] = { |
190 | STMMAC_MMC_STAT(mmc_tx_octetcount_gb), |
191 | STMMAC_MMC_STAT(mmc_tx_framecount_gb), |
192 | STMMAC_MMC_STAT(mmc_tx_broadcastframe_g), |
193 | STMMAC_MMC_STAT(mmc_tx_multicastframe_g), |
194 | STMMAC_MMC_STAT(mmc_tx_64_octets_gb), |
195 | STMMAC_MMC_STAT(mmc_tx_65_to_127_octets_gb), |
196 | STMMAC_MMC_STAT(mmc_tx_128_to_255_octets_gb), |
197 | STMMAC_MMC_STAT(mmc_tx_256_to_511_octets_gb), |
198 | STMMAC_MMC_STAT(mmc_tx_512_to_1023_octets_gb), |
199 | STMMAC_MMC_STAT(mmc_tx_1024_to_max_octets_gb), |
200 | STMMAC_MMC_STAT(mmc_tx_unicast_gb), |
201 | STMMAC_MMC_STAT(mmc_tx_multicast_gb), |
202 | STMMAC_MMC_STAT(mmc_tx_broadcast_gb), |
203 | STMMAC_MMC_STAT(mmc_tx_underflow_error), |
204 | STMMAC_MMC_STAT(mmc_tx_singlecol_g), |
205 | STMMAC_MMC_STAT(mmc_tx_multicol_g), |
206 | STMMAC_MMC_STAT(mmc_tx_deferred), |
207 | STMMAC_MMC_STAT(mmc_tx_latecol), |
208 | STMMAC_MMC_STAT(mmc_tx_exesscol), |
209 | STMMAC_MMC_STAT(mmc_tx_carrier_error), |
210 | STMMAC_MMC_STAT(mmc_tx_octetcount_g), |
211 | STMMAC_MMC_STAT(mmc_tx_framecount_g), |
212 | STMMAC_MMC_STAT(mmc_tx_excessdef), |
213 | STMMAC_MMC_STAT(mmc_tx_pause_frame), |
214 | STMMAC_MMC_STAT(mmc_tx_vlan_frame_g), |
215 | STMMAC_MMC_STAT(mmc_tx_oversize_g), |
216 | STMMAC_MMC_STAT(mmc_tx_lpi_usec), |
217 | STMMAC_MMC_STAT(mmc_tx_lpi_tran), |
218 | STMMAC_MMC_STAT(mmc_rx_framecount_gb), |
219 | STMMAC_MMC_STAT(mmc_rx_octetcount_gb), |
220 | STMMAC_MMC_STAT(mmc_rx_octetcount_g), |
221 | STMMAC_MMC_STAT(mmc_rx_broadcastframe_g), |
222 | STMMAC_MMC_STAT(mmc_rx_multicastframe_g), |
223 | STMMAC_MMC_STAT(mmc_rx_crc_error), |
224 | STMMAC_MMC_STAT(mmc_rx_align_error), |
225 | STMMAC_MMC_STAT(mmc_rx_run_error), |
226 | STMMAC_MMC_STAT(mmc_rx_jabber_error), |
227 | STMMAC_MMC_STAT(mmc_rx_undersize_g), |
228 | STMMAC_MMC_STAT(mmc_rx_oversize_g), |
229 | STMMAC_MMC_STAT(mmc_rx_64_octets_gb), |
230 | STMMAC_MMC_STAT(mmc_rx_65_to_127_octets_gb), |
231 | STMMAC_MMC_STAT(mmc_rx_128_to_255_octets_gb), |
232 | STMMAC_MMC_STAT(mmc_rx_256_to_511_octets_gb), |
233 | STMMAC_MMC_STAT(mmc_rx_512_to_1023_octets_gb), |
234 | STMMAC_MMC_STAT(mmc_rx_1024_to_max_octets_gb), |
235 | STMMAC_MMC_STAT(mmc_rx_unicast_g), |
236 | STMMAC_MMC_STAT(mmc_rx_length_error), |
237 | STMMAC_MMC_STAT(mmc_rx_autofrangetype), |
238 | STMMAC_MMC_STAT(mmc_rx_pause_frames), |
239 | STMMAC_MMC_STAT(mmc_rx_fifo_overflow), |
240 | STMMAC_MMC_STAT(mmc_rx_vlan_frames_gb), |
241 | STMMAC_MMC_STAT(mmc_rx_watchdog_error), |
242 | STMMAC_MMC_STAT(mmc_rx_error), |
243 | STMMAC_MMC_STAT(mmc_rx_lpi_usec), |
244 | STMMAC_MMC_STAT(mmc_rx_lpi_tran), |
245 | STMMAC_MMC_STAT(mmc_rx_discard_frames_gb), |
246 | STMMAC_MMC_STAT(mmc_rx_discard_octets_gb), |
247 | STMMAC_MMC_STAT(mmc_rx_align_err_frames), |
248 | STMMAC_MMC_STAT(mmc_rx_ipv4_gd), |
249 | STMMAC_MMC_STAT(mmc_rx_ipv4_hderr), |
250 | STMMAC_MMC_STAT(mmc_rx_ipv4_nopay), |
251 | STMMAC_MMC_STAT(mmc_rx_ipv4_frag), |
252 | STMMAC_MMC_STAT(mmc_rx_ipv4_udsbl), |
253 | STMMAC_MMC_STAT(mmc_rx_ipv4_gd_octets), |
254 | STMMAC_MMC_STAT(mmc_rx_ipv4_hderr_octets), |
255 | STMMAC_MMC_STAT(mmc_rx_ipv4_nopay_octets), |
256 | STMMAC_MMC_STAT(mmc_rx_ipv4_frag_octets), |
257 | STMMAC_MMC_STAT(mmc_rx_ipv4_udsbl_octets), |
258 | STMMAC_MMC_STAT(mmc_rx_ipv6_gd_octets), |
259 | STMMAC_MMC_STAT(mmc_rx_ipv6_hderr_octets), |
260 | STMMAC_MMC_STAT(mmc_rx_ipv6_nopay_octets), |
261 | STMMAC_MMC_STAT(mmc_rx_ipv6_gd), |
262 | STMMAC_MMC_STAT(mmc_rx_ipv6_hderr), |
263 | STMMAC_MMC_STAT(mmc_rx_ipv6_nopay), |
264 | STMMAC_MMC_STAT(mmc_rx_udp_gd), |
265 | STMMAC_MMC_STAT(mmc_rx_udp_err), |
266 | STMMAC_MMC_STAT(mmc_rx_tcp_gd), |
267 | STMMAC_MMC_STAT(mmc_rx_tcp_err), |
268 | STMMAC_MMC_STAT(mmc_rx_icmp_gd), |
269 | STMMAC_MMC_STAT(mmc_rx_icmp_err), |
270 | STMMAC_MMC_STAT(mmc_rx_udp_gd_octets), |
271 | STMMAC_MMC_STAT(mmc_rx_udp_err_octets), |
272 | STMMAC_MMC_STAT(mmc_rx_tcp_gd_octets), |
273 | STMMAC_MMC_STAT(mmc_rx_tcp_err_octets), |
274 | STMMAC_MMC_STAT(mmc_rx_icmp_gd_octets), |
275 | STMMAC_MMC_STAT(mmc_rx_icmp_err_octets), |
276 | STMMAC_MMC_STAT(mmc_sgf_pass_fragment_cntr), |
277 | STMMAC_MMC_STAT(mmc_sgf_fail_fragment_cntr), |
278 | STMMAC_MMC_STAT(mmc_tx_fpe_fragment_cntr), |
279 | STMMAC_MMC_STAT(mmc_tx_hold_req_cntr), |
280 | STMMAC_MMC_STAT(mmc_tx_gate_overrun_cntr), |
281 | STMMAC_MMC_STAT(mmc_rx_packet_assembly_err_cntr), |
282 | STMMAC_MMC_STAT(mmc_rx_packet_smd_err_cntr), |
283 | STMMAC_MMC_STAT(mmc_rx_packet_assembly_ok_cntr), |
284 | STMMAC_MMC_STAT(mmc_rx_fpe_fragment_cntr), |
285 | }; |
286 | #define STMMAC_MMC_STATS_LEN ARRAY_SIZE(stmmac_mmc) |
287 | |
288 | static const char stmmac_qstats_tx_string[][ETH_GSTRING_LEN] = { |
289 | "tx_pkt_n" , |
290 | "tx_irq_n" , |
291 | #define STMMAC_TXQ_STATS ARRAY_SIZE(stmmac_qstats_tx_string) |
292 | }; |
293 | |
294 | static const char stmmac_qstats_rx_string[][ETH_GSTRING_LEN] = { |
295 | "rx_pkt_n" , |
296 | "rx_irq_n" , |
297 | #define STMMAC_RXQ_STATS ARRAY_SIZE(stmmac_qstats_rx_string) |
298 | }; |
299 | |
300 | static void stmmac_ethtool_getdrvinfo(struct net_device *dev, |
301 | struct ethtool_drvinfo *info) |
302 | { |
303 | struct stmmac_priv *priv = netdev_priv(dev); |
304 | |
305 | if (priv->plat->has_gmac || priv->plat->has_gmac4) |
306 | strscpy(info->driver, GMAC_ETHTOOL_NAME, sizeof(info->driver)); |
307 | else if (priv->plat->has_xgmac) |
308 | strscpy(info->driver, XGMAC_ETHTOOL_NAME, sizeof(info->driver)); |
309 | else |
310 | strscpy(info->driver, MAC100_ETHTOOL_NAME, |
311 | sizeof(info->driver)); |
312 | |
313 | if (priv->plat->pdev) { |
314 | strscpy(info->bus_info, pci_name(priv->plat->pdev), |
315 | sizeof(info->bus_info)); |
316 | } |
317 | } |
318 | |
319 | static int stmmac_ethtool_get_link_ksettings(struct net_device *dev, |
320 | struct ethtool_link_ksettings *cmd) |
321 | { |
322 | struct stmmac_priv *priv = netdev_priv(dev); |
323 | |
324 | if (!(priv->plat->flags & STMMAC_FLAG_HAS_INTEGRATED_PCS) && |
325 | (priv->hw->pcs & STMMAC_PCS_RGMII || |
326 | priv->hw->pcs & STMMAC_PCS_SGMII)) { |
327 | struct rgmii_adv adv; |
328 | u32 supported, advertising, lp_advertising; |
329 | |
330 | if (!priv->xstats.pcs_link) { |
331 | cmd->base.speed = SPEED_UNKNOWN; |
332 | cmd->base.duplex = DUPLEX_UNKNOWN; |
333 | return 0; |
334 | } |
335 | cmd->base.duplex = priv->xstats.pcs_duplex; |
336 | |
337 | cmd->base.speed = priv->xstats.pcs_speed; |
338 | |
339 | /* Get and convert ADV/LP_ADV from the HW AN registers */ |
340 | if (stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv)) |
341 | return -EOPNOTSUPP; /* should never happen indeed */ |
342 | |
343 | /* Encoding of PSE bits is defined in 802.3z, 37.2.1.4 */ |
344 | |
345 | ethtool_convert_link_mode_to_legacy_u32( |
346 | legacy_u32: &supported, src: cmd->link_modes.supported); |
347 | ethtool_convert_link_mode_to_legacy_u32( |
348 | legacy_u32: &advertising, src: cmd->link_modes.advertising); |
349 | ethtool_convert_link_mode_to_legacy_u32( |
350 | legacy_u32: &lp_advertising, src: cmd->link_modes.lp_advertising); |
351 | |
352 | if (adv.pause & STMMAC_PCS_PAUSE) |
353 | advertising |= ADVERTISED_Pause; |
354 | if (adv.pause & STMMAC_PCS_ASYM_PAUSE) |
355 | advertising |= ADVERTISED_Asym_Pause; |
356 | if (adv.lp_pause & STMMAC_PCS_PAUSE) |
357 | lp_advertising |= ADVERTISED_Pause; |
358 | if (adv.lp_pause & STMMAC_PCS_ASYM_PAUSE) |
359 | lp_advertising |= ADVERTISED_Asym_Pause; |
360 | |
361 | /* Reg49[3] always set because ANE is always supported */ |
362 | cmd->base.autoneg = ADVERTISED_Autoneg; |
363 | supported |= SUPPORTED_Autoneg; |
364 | advertising |= ADVERTISED_Autoneg; |
365 | lp_advertising |= ADVERTISED_Autoneg; |
366 | |
367 | if (adv.duplex) { |
368 | supported |= (SUPPORTED_1000baseT_Full | |
369 | SUPPORTED_100baseT_Full | |
370 | SUPPORTED_10baseT_Full); |
371 | advertising |= (ADVERTISED_1000baseT_Full | |
372 | ADVERTISED_100baseT_Full | |
373 | ADVERTISED_10baseT_Full); |
374 | } else { |
375 | supported |= (SUPPORTED_1000baseT_Half | |
376 | SUPPORTED_100baseT_Half | |
377 | SUPPORTED_10baseT_Half); |
378 | advertising |= (ADVERTISED_1000baseT_Half | |
379 | ADVERTISED_100baseT_Half | |
380 | ADVERTISED_10baseT_Half); |
381 | } |
382 | if (adv.lp_duplex) |
383 | lp_advertising |= (ADVERTISED_1000baseT_Full | |
384 | ADVERTISED_100baseT_Full | |
385 | ADVERTISED_10baseT_Full); |
386 | else |
387 | lp_advertising |= (ADVERTISED_1000baseT_Half | |
388 | ADVERTISED_100baseT_Half | |
389 | ADVERTISED_10baseT_Half); |
390 | cmd->base.port = PORT_OTHER; |
391 | |
392 | ethtool_convert_legacy_u32_to_link_mode( |
393 | dst: cmd->link_modes.supported, legacy_u32: supported); |
394 | ethtool_convert_legacy_u32_to_link_mode( |
395 | dst: cmd->link_modes.advertising, legacy_u32: advertising); |
396 | ethtool_convert_legacy_u32_to_link_mode( |
397 | dst: cmd->link_modes.lp_advertising, legacy_u32: lp_advertising); |
398 | |
399 | return 0; |
400 | } |
401 | |
402 | return phylink_ethtool_ksettings_get(priv->phylink, cmd); |
403 | } |
404 | |
405 | static int |
406 | stmmac_ethtool_set_link_ksettings(struct net_device *dev, |
407 | const struct ethtool_link_ksettings *cmd) |
408 | { |
409 | struct stmmac_priv *priv = netdev_priv(dev); |
410 | |
411 | if (!(priv->plat->flags & STMMAC_FLAG_HAS_INTEGRATED_PCS) && |
412 | (priv->hw->pcs & STMMAC_PCS_RGMII || |
413 | priv->hw->pcs & STMMAC_PCS_SGMII)) { |
414 | /* Only support ANE */ |
415 | if (cmd->base.autoneg != AUTONEG_ENABLE) |
416 | return -EINVAL; |
417 | |
418 | mutex_lock(&priv->lock); |
419 | stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, priv->hw->ps, 0); |
420 | mutex_unlock(lock: &priv->lock); |
421 | |
422 | return 0; |
423 | } |
424 | |
425 | return phylink_ethtool_ksettings_set(priv->phylink, cmd); |
426 | } |
427 | |
428 | static u32 stmmac_ethtool_getmsglevel(struct net_device *dev) |
429 | { |
430 | struct stmmac_priv *priv = netdev_priv(dev); |
431 | return priv->msg_enable; |
432 | } |
433 | |
434 | static void stmmac_ethtool_setmsglevel(struct net_device *dev, u32 level) |
435 | { |
436 | struct stmmac_priv *priv = netdev_priv(dev); |
437 | priv->msg_enable = level; |
438 | |
439 | } |
440 | |
441 | static int stmmac_check_if_running(struct net_device *dev) |
442 | { |
443 | if (!netif_running(dev)) |
444 | return -EBUSY; |
445 | return 0; |
446 | } |
447 | |
448 | static int stmmac_ethtool_get_regs_len(struct net_device *dev) |
449 | { |
450 | struct stmmac_priv *priv = netdev_priv(dev); |
451 | |
452 | if (priv->plat->has_xgmac) |
453 | return XGMAC_REGSIZE * 4; |
454 | else if (priv->plat->has_gmac4) |
455 | return GMAC4_REG_SPACE_SIZE; |
456 | return REG_SPACE_SIZE; |
457 | } |
458 | |
459 | static void stmmac_ethtool_gregs(struct net_device *dev, |
460 | struct ethtool_regs *regs, void *space) |
461 | { |
462 | struct stmmac_priv *priv = netdev_priv(dev); |
463 | u32 *reg_space = (u32 *) space; |
464 | |
465 | stmmac_dump_mac_regs(priv, priv->hw, reg_space); |
466 | stmmac_dump_dma_regs(priv, priv->ioaddr, reg_space); |
467 | |
468 | /* Copy DMA registers to where ethtool expects them */ |
469 | if (priv->plat->has_gmac4) { |
470 | /* GMAC4 dumps its DMA registers at its DMA_CHAN_BASE_ADDR */ |
471 | memcpy(®_space[ETHTOOL_DMA_OFFSET], |
472 | ®_space[GMAC4_DMA_CHAN_BASE_ADDR / 4], |
473 | NUM_DWMAC4_DMA_REGS * 4); |
474 | } else if (!priv->plat->has_xgmac) { |
475 | memcpy(®_space[ETHTOOL_DMA_OFFSET], |
476 | ®_space[DMA_BUS_MODE / 4], |
477 | NUM_DWMAC1000_DMA_REGS * 4); |
478 | } |
479 | } |
480 | |
481 | static int stmmac_nway_reset(struct net_device *dev) |
482 | { |
483 | struct stmmac_priv *priv = netdev_priv(dev); |
484 | |
485 | return phylink_ethtool_nway_reset(priv->phylink); |
486 | } |
487 | |
488 | static void stmmac_get_ringparam(struct net_device *netdev, |
489 | struct ethtool_ringparam *ring, |
490 | struct kernel_ethtool_ringparam *kernel_ring, |
491 | struct netlink_ext_ack *extack) |
492 | { |
493 | struct stmmac_priv *priv = netdev_priv(dev: netdev); |
494 | |
495 | ring->rx_max_pending = DMA_MAX_RX_SIZE; |
496 | ring->tx_max_pending = DMA_MAX_TX_SIZE; |
497 | ring->rx_pending = priv->dma_conf.dma_rx_size; |
498 | ring->tx_pending = priv->dma_conf.dma_tx_size; |
499 | } |
500 | |
501 | static int stmmac_set_ringparam(struct net_device *netdev, |
502 | struct ethtool_ringparam *ring, |
503 | struct kernel_ethtool_ringparam *kernel_ring, |
504 | struct netlink_ext_ack *extack) |
505 | { |
506 | if (ring->rx_mini_pending || ring->rx_jumbo_pending || |
507 | ring->rx_pending < DMA_MIN_RX_SIZE || |
508 | ring->rx_pending > DMA_MAX_RX_SIZE || |
509 | !is_power_of_2(n: ring->rx_pending) || |
510 | ring->tx_pending < DMA_MIN_TX_SIZE || |
511 | ring->tx_pending > DMA_MAX_TX_SIZE || |
512 | !is_power_of_2(n: ring->tx_pending)) |
513 | return -EINVAL; |
514 | |
515 | return stmmac_reinit_ringparam(dev: netdev, rx_size: ring->rx_pending, |
516 | tx_size: ring->tx_pending); |
517 | } |
518 | |
519 | static void |
520 | stmmac_get_pauseparam(struct net_device *netdev, |
521 | struct ethtool_pauseparam *pause) |
522 | { |
523 | struct stmmac_priv *priv = netdev_priv(dev: netdev); |
524 | struct rgmii_adv adv_lp; |
525 | |
526 | if (priv->hw->pcs && !stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv_lp)) { |
527 | pause->autoneg = 1; |
528 | if (!adv_lp.pause) |
529 | return; |
530 | } else { |
531 | phylink_ethtool_get_pauseparam(priv->phylink, pause); |
532 | } |
533 | } |
534 | |
535 | static int |
536 | stmmac_set_pauseparam(struct net_device *netdev, |
537 | struct ethtool_pauseparam *pause) |
538 | { |
539 | struct stmmac_priv *priv = netdev_priv(dev: netdev); |
540 | struct rgmii_adv adv_lp; |
541 | |
542 | if (priv->hw->pcs && !stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv_lp)) { |
543 | pause->autoneg = 1; |
544 | if (!adv_lp.pause) |
545 | return -EOPNOTSUPP; |
546 | return 0; |
547 | } else { |
548 | return phylink_ethtool_set_pauseparam(priv->phylink, pause); |
549 | } |
550 | } |
551 | |
552 | static u64 stmmac_get_rx_normal_irq_n(struct stmmac_priv *priv, int q) |
553 | { |
554 | u64 total; |
555 | int cpu; |
556 | |
557 | total = 0; |
558 | for_each_possible_cpu(cpu) { |
559 | struct stmmac_pcpu_stats *pcpu; |
560 | unsigned int start; |
561 | u64 irq_n; |
562 | |
563 | pcpu = per_cpu_ptr(priv->xstats.pcpu_stats, cpu); |
564 | do { |
565 | start = u64_stats_fetch_begin(syncp: &pcpu->syncp); |
566 | irq_n = u64_stats_read(p: &pcpu->rx_normal_irq_n[q]); |
567 | } while (u64_stats_fetch_retry(syncp: &pcpu->syncp, start)); |
568 | total += irq_n; |
569 | } |
570 | return total; |
571 | } |
572 | |
573 | static u64 stmmac_get_tx_normal_irq_n(struct stmmac_priv *priv, int q) |
574 | { |
575 | u64 total; |
576 | int cpu; |
577 | |
578 | total = 0; |
579 | for_each_possible_cpu(cpu) { |
580 | struct stmmac_pcpu_stats *pcpu; |
581 | unsigned int start; |
582 | u64 irq_n; |
583 | |
584 | pcpu = per_cpu_ptr(priv->xstats.pcpu_stats, cpu); |
585 | do { |
586 | start = u64_stats_fetch_begin(syncp: &pcpu->syncp); |
587 | irq_n = u64_stats_read(p: &pcpu->tx_normal_irq_n[q]); |
588 | } while (u64_stats_fetch_retry(syncp: &pcpu->syncp, start)); |
589 | total += irq_n; |
590 | } |
591 | return total; |
592 | } |
593 | |
594 | static void stmmac_get_per_qstats(struct stmmac_priv *priv, u64 *data) |
595 | { |
596 | u32 tx_cnt = priv->plat->tx_queues_to_use; |
597 | u32 rx_cnt = priv->plat->rx_queues_to_use; |
598 | unsigned int start; |
599 | int q; |
600 | |
601 | for (q = 0; q < tx_cnt; q++) { |
602 | struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[q]; |
603 | u64 pkt_n; |
604 | |
605 | do { |
606 | start = u64_stats_fetch_begin(syncp: &txq_stats->napi_syncp); |
607 | pkt_n = u64_stats_read(p: &txq_stats->napi.tx_pkt_n); |
608 | } while (u64_stats_fetch_retry(syncp: &txq_stats->napi_syncp, start)); |
609 | |
610 | *data++ = pkt_n; |
611 | *data++ = stmmac_get_tx_normal_irq_n(priv, q); |
612 | } |
613 | |
614 | for (q = 0; q < rx_cnt; q++) { |
615 | struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[q]; |
616 | u64 pkt_n; |
617 | |
618 | do { |
619 | start = u64_stats_fetch_begin(syncp: &rxq_stats->napi_syncp); |
620 | pkt_n = u64_stats_read(p: &rxq_stats->napi.rx_pkt_n); |
621 | } while (u64_stats_fetch_retry(syncp: &rxq_stats->napi_syncp, start)); |
622 | |
623 | *data++ = pkt_n; |
624 | *data++ = stmmac_get_rx_normal_irq_n(priv, q); |
625 | } |
626 | } |
627 | |
628 | static void stmmac_get_ethtool_stats(struct net_device *dev, |
629 | struct ethtool_stats *dummy, u64 *data) |
630 | { |
631 | struct stmmac_priv *priv = netdev_priv(dev); |
632 | u32 rx_queues_count = priv->plat->rx_queues_to_use; |
633 | u32 tx_queues_count = priv->plat->tx_queues_to_use; |
634 | u64 napi_poll = 0, normal_irq_n = 0; |
635 | int i, j = 0, pos, ret; |
636 | unsigned long count; |
637 | unsigned int start; |
638 | |
639 | if (priv->dma_cap.asp) { |
640 | for (i = 0; i < STMMAC_SAFETY_FEAT_SIZE; i++) { |
641 | if (!stmmac_safety_feat_dump(priv, &priv->sstats, i, |
642 | &count, NULL)) |
643 | data[j++] = count; |
644 | } |
645 | } |
646 | |
647 | /* Update the DMA HW counters for dwmac10/100 */ |
648 | ret = stmmac_dma_diagnostic_fr(priv, &priv->xstats, priv->ioaddr); |
649 | if (ret) { |
650 | /* If supported, for new GMAC chips expose the MMC counters */ |
651 | if (priv->dma_cap.rmon) { |
652 | stmmac_mmc_read(priv, priv->mmcaddr, &priv->mmc); |
653 | |
654 | for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) { |
655 | char *p; |
656 | p = (char *)priv + stmmac_mmc[i].stat_offset; |
657 | |
658 | data[j++] = (stmmac_mmc[i].sizeof_stat == |
659 | sizeof(u64)) ? (*(u64 *)p) : |
660 | (*(u32 *)p); |
661 | } |
662 | } |
663 | if (priv->eee_enabled) { |
664 | int val = phylink_get_eee_err(priv->phylink); |
665 | if (val) |
666 | priv->xstats.phy_eee_wakeup_error_n = val; |
667 | } |
668 | |
669 | if (priv->synopsys_id >= DWMAC_CORE_3_50) |
670 | stmmac_mac_debug(priv, priv->ioaddr, |
671 | (void *)&priv->xstats, |
672 | rx_queues_count, tx_queues_count); |
673 | } |
674 | for (i = 0; i < STMMAC_STATS_LEN; i++) { |
675 | char *p = (char *)priv + stmmac_gstrings_stats[i].stat_offset; |
676 | data[j++] = (stmmac_gstrings_stats[i].sizeof_stat == |
677 | sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); |
678 | } |
679 | |
680 | pos = j; |
681 | for (i = 0; i < rx_queues_count; i++) { |
682 | struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[i]; |
683 | struct stmmac_napi_rx_stats snapshot; |
684 | u64 n_irq; |
685 | |
686 | j = pos; |
687 | do { |
688 | start = u64_stats_fetch_begin(syncp: &rxq_stats->napi_syncp); |
689 | snapshot = rxq_stats->napi; |
690 | } while (u64_stats_fetch_retry(syncp: &rxq_stats->napi_syncp, start)); |
691 | |
692 | data[j++] += u64_stats_read(p: &snapshot.rx_pkt_n); |
693 | n_irq = stmmac_get_rx_normal_irq_n(priv, q: i); |
694 | data[j++] += n_irq; |
695 | normal_irq_n += n_irq; |
696 | napi_poll += u64_stats_read(p: &snapshot.poll); |
697 | } |
698 | |
699 | pos = j; |
700 | for (i = 0; i < tx_queues_count; i++) { |
701 | struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[i]; |
702 | struct stmmac_napi_tx_stats napi_snapshot; |
703 | struct stmmac_q_tx_stats q_snapshot; |
704 | u64 n_irq; |
705 | |
706 | j = pos; |
707 | do { |
708 | start = u64_stats_fetch_begin(syncp: &txq_stats->q_syncp); |
709 | q_snapshot = txq_stats->q; |
710 | } while (u64_stats_fetch_retry(syncp: &txq_stats->q_syncp, start)); |
711 | do { |
712 | start = u64_stats_fetch_begin(syncp: &txq_stats->napi_syncp); |
713 | napi_snapshot = txq_stats->napi; |
714 | } while (u64_stats_fetch_retry(syncp: &txq_stats->napi_syncp, start)); |
715 | |
716 | data[j++] += u64_stats_read(p: &napi_snapshot.tx_pkt_n); |
717 | n_irq = stmmac_get_tx_normal_irq_n(priv, q: i); |
718 | data[j++] += n_irq; |
719 | normal_irq_n += n_irq; |
720 | data[j++] += u64_stats_read(p: &napi_snapshot.tx_clean); |
721 | data[j++] += u64_stats_read(p: &q_snapshot.tx_set_ic_bit) + |
722 | u64_stats_read(p: &napi_snapshot.tx_set_ic_bit); |
723 | data[j++] += u64_stats_read(p: &q_snapshot.tx_tso_frames); |
724 | data[j++] += u64_stats_read(p: &q_snapshot.tx_tso_nfrags); |
725 | napi_poll += u64_stats_read(p: &napi_snapshot.poll); |
726 | } |
727 | normal_irq_n += priv->xstats.rx_early_irq; |
728 | data[j++] = normal_irq_n; |
729 | data[j++] = napi_poll; |
730 | |
731 | stmmac_get_per_qstats(priv, data: &data[j]); |
732 | } |
733 | |
734 | static int stmmac_get_sset_count(struct net_device *netdev, int sset) |
735 | { |
736 | struct stmmac_priv *priv = netdev_priv(dev: netdev); |
737 | u32 tx_cnt = priv->plat->tx_queues_to_use; |
738 | u32 rx_cnt = priv->plat->rx_queues_to_use; |
739 | int i, len, safety_len = 0; |
740 | |
741 | switch (sset) { |
742 | case ETH_SS_STATS: |
743 | len = STMMAC_STATS_LEN + STMMAC_QSTATS + |
744 | STMMAC_TXQ_STATS * tx_cnt + |
745 | STMMAC_RXQ_STATS * rx_cnt; |
746 | |
747 | if (priv->dma_cap.rmon) |
748 | len += STMMAC_MMC_STATS_LEN; |
749 | if (priv->dma_cap.asp) { |
750 | for (i = 0; i < STMMAC_SAFETY_FEAT_SIZE; i++) { |
751 | if (!stmmac_safety_feat_dump(priv, |
752 | &priv->sstats, i, |
753 | NULL, NULL)) |
754 | safety_len++; |
755 | } |
756 | |
757 | len += safety_len; |
758 | } |
759 | |
760 | return len; |
761 | case ETH_SS_TEST: |
762 | return stmmac_selftest_get_count(priv); |
763 | default: |
764 | return -EOPNOTSUPP; |
765 | } |
766 | } |
767 | |
768 | static void stmmac_get_qstats_string(struct stmmac_priv *priv, u8 *data) |
769 | { |
770 | u32 tx_cnt = priv->plat->tx_queues_to_use; |
771 | u32 rx_cnt = priv->plat->rx_queues_to_use; |
772 | int q, stat; |
773 | |
774 | for (q = 0; q < tx_cnt; q++) { |
775 | for (stat = 0; stat < STMMAC_TXQ_STATS; stat++) { |
776 | snprintf(buf: data, ETH_GSTRING_LEN, fmt: "q%d_%s" , q, |
777 | stmmac_qstats_tx_string[stat]); |
778 | data += ETH_GSTRING_LEN; |
779 | } |
780 | } |
781 | for (q = 0; q < rx_cnt; q++) { |
782 | for (stat = 0; stat < STMMAC_RXQ_STATS; stat++) { |
783 | snprintf(buf: data, ETH_GSTRING_LEN, fmt: "q%d_%s" , q, |
784 | stmmac_qstats_rx_string[stat]); |
785 | data += ETH_GSTRING_LEN; |
786 | } |
787 | } |
788 | } |
789 | |
790 | static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data) |
791 | { |
792 | int i; |
793 | u8 *p = data; |
794 | struct stmmac_priv *priv = netdev_priv(dev); |
795 | |
796 | switch (stringset) { |
797 | case ETH_SS_STATS: |
798 | if (priv->dma_cap.asp) { |
799 | for (i = 0; i < STMMAC_SAFETY_FEAT_SIZE; i++) { |
800 | const char *desc; |
801 | if (!stmmac_safety_feat_dump(priv, |
802 | &priv->sstats, i, |
803 | NULL, &desc)) { |
804 | memcpy(p, desc, ETH_GSTRING_LEN); |
805 | p += ETH_GSTRING_LEN; |
806 | } |
807 | } |
808 | } |
809 | if (priv->dma_cap.rmon) |
810 | for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) { |
811 | memcpy(p, stmmac_mmc[i].stat_string, |
812 | ETH_GSTRING_LEN); |
813 | p += ETH_GSTRING_LEN; |
814 | } |
815 | for (i = 0; i < STMMAC_STATS_LEN; i++) { |
816 | memcpy(p, stmmac_gstrings_stats[i].stat_string, ETH_GSTRING_LEN); |
817 | p += ETH_GSTRING_LEN; |
818 | } |
819 | for (i = 0; i < STMMAC_QSTATS; i++) { |
820 | memcpy(p, stmmac_qstats_string[i], ETH_GSTRING_LEN); |
821 | p += ETH_GSTRING_LEN; |
822 | } |
823 | stmmac_get_qstats_string(priv, data: p); |
824 | break; |
825 | case ETH_SS_TEST: |
826 | stmmac_selftest_get_strings(priv, data: p); |
827 | break; |
828 | default: |
829 | WARN_ON(1); |
830 | break; |
831 | } |
832 | } |
833 | |
834 | /* Currently only support WOL through Magic packet. */ |
835 | static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) |
836 | { |
837 | struct stmmac_priv *priv = netdev_priv(dev); |
838 | |
839 | if (!priv->plat->pmt) |
840 | return phylink_ethtool_get_wol(priv->phylink, wol); |
841 | |
842 | mutex_lock(&priv->lock); |
843 | if (device_can_wakeup(dev: priv->device)) { |
844 | wol->supported = WAKE_MAGIC | WAKE_UCAST; |
845 | if (priv->hw_cap_support && !priv->dma_cap.pmt_magic_frame) |
846 | wol->supported &= ~WAKE_MAGIC; |
847 | wol->wolopts = priv->wolopts; |
848 | } |
849 | mutex_unlock(lock: &priv->lock); |
850 | } |
851 | |
852 | static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) |
853 | { |
854 | struct stmmac_priv *priv = netdev_priv(dev); |
855 | u32 support = WAKE_MAGIC | WAKE_UCAST; |
856 | |
857 | if (!device_can_wakeup(dev: priv->device)) |
858 | return -EOPNOTSUPP; |
859 | |
860 | if (!priv->plat->pmt) { |
861 | int ret = phylink_ethtool_set_wol(priv->phylink, wol); |
862 | |
863 | if (!ret) |
864 | device_set_wakeup_enable(dev: priv->device, enable: !!wol->wolopts); |
865 | return ret; |
866 | } |
867 | |
868 | /* By default almost all GMAC devices support the WoL via |
869 | * magic frame but we can disable it if the HW capability |
870 | * register shows no support for pmt_magic_frame. */ |
871 | if ((priv->hw_cap_support) && (!priv->dma_cap.pmt_magic_frame)) |
872 | wol->wolopts &= ~WAKE_MAGIC; |
873 | |
874 | if (wol->wolopts & ~support) |
875 | return -EINVAL; |
876 | |
877 | if (wol->wolopts) { |
878 | pr_info("stmmac: wakeup enable\n" ); |
879 | device_set_wakeup_enable(dev: priv->device, enable: 1); |
880 | /* Avoid unbalanced enable_irq_wake calls */ |
881 | if (priv->wol_irq_disabled) |
882 | enable_irq_wake(irq: priv->wol_irq); |
883 | priv->wol_irq_disabled = false; |
884 | } else { |
885 | device_set_wakeup_enable(dev: priv->device, enable: 0); |
886 | /* Avoid unbalanced disable_irq_wake calls */ |
887 | if (!priv->wol_irq_disabled) |
888 | disable_irq_wake(irq: priv->wol_irq); |
889 | priv->wol_irq_disabled = true; |
890 | } |
891 | |
892 | mutex_lock(&priv->lock); |
893 | priv->wolopts = wol->wolopts; |
894 | mutex_unlock(lock: &priv->lock); |
895 | |
896 | return 0; |
897 | } |
898 | |
899 | static int stmmac_ethtool_op_get_eee(struct net_device *dev, |
900 | struct ethtool_keee *edata) |
901 | { |
902 | struct stmmac_priv *priv = netdev_priv(dev); |
903 | |
904 | if (!priv->dma_cap.eee) |
905 | return -EOPNOTSUPP; |
906 | |
907 | edata->tx_lpi_timer = priv->tx_lpi_timer; |
908 | edata->tx_lpi_enabled = priv->tx_lpi_enabled; |
909 | |
910 | return phylink_ethtool_get_eee(link: priv->phylink, eee: edata); |
911 | } |
912 | |
913 | static int stmmac_ethtool_op_set_eee(struct net_device *dev, |
914 | struct ethtool_keee *edata) |
915 | { |
916 | struct stmmac_priv *priv = netdev_priv(dev); |
917 | int ret; |
918 | |
919 | if (!priv->dma_cap.eee) |
920 | return -EOPNOTSUPP; |
921 | |
922 | if (priv->tx_lpi_enabled != edata->tx_lpi_enabled) |
923 | netdev_warn(dev: priv->dev, |
924 | format: "Setting EEE tx-lpi is not supported\n" ); |
925 | |
926 | if (!edata->eee_enabled) |
927 | stmmac_disable_eee_mode(priv); |
928 | |
929 | ret = phylink_ethtool_set_eee(link: priv->phylink, eee: edata); |
930 | if (ret) |
931 | return ret; |
932 | |
933 | if (edata->eee_enabled && |
934 | priv->tx_lpi_timer != edata->tx_lpi_timer) { |
935 | priv->tx_lpi_timer = edata->tx_lpi_timer; |
936 | stmmac_eee_init(priv); |
937 | } |
938 | |
939 | return 0; |
940 | } |
941 | |
942 | static u32 stmmac_usec2riwt(u32 usec, struct stmmac_priv *priv) |
943 | { |
944 | unsigned long clk = clk_get_rate(clk: priv->plat->stmmac_clk); |
945 | |
946 | if (!clk) { |
947 | clk = priv->plat->clk_ref_rate; |
948 | if (!clk) |
949 | return 0; |
950 | } |
951 | |
952 | return (usec * (clk / 1000000)) / 256; |
953 | } |
954 | |
955 | static u32 stmmac_riwt2usec(u32 riwt, struct stmmac_priv *priv) |
956 | { |
957 | unsigned long clk = clk_get_rate(clk: priv->plat->stmmac_clk); |
958 | |
959 | if (!clk) { |
960 | clk = priv->plat->clk_ref_rate; |
961 | if (!clk) |
962 | return 0; |
963 | } |
964 | |
965 | return (riwt * 256) / (clk / 1000000); |
966 | } |
967 | |
968 | static int __stmmac_get_coalesce(struct net_device *dev, |
969 | struct ethtool_coalesce *ec, |
970 | int queue) |
971 | { |
972 | struct stmmac_priv *priv = netdev_priv(dev); |
973 | u32 max_cnt; |
974 | u32 rx_cnt; |
975 | u32 tx_cnt; |
976 | |
977 | rx_cnt = priv->plat->rx_queues_to_use; |
978 | tx_cnt = priv->plat->tx_queues_to_use; |
979 | max_cnt = max(rx_cnt, tx_cnt); |
980 | |
981 | if (queue < 0) |
982 | queue = 0; |
983 | else if (queue >= max_cnt) |
984 | return -EINVAL; |
985 | |
986 | if (queue < tx_cnt) { |
987 | ec->tx_coalesce_usecs = priv->tx_coal_timer[queue]; |
988 | ec->tx_max_coalesced_frames = priv->tx_coal_frames[queue]; |
989 | } else { |
990 | ec->tx_coalesce_usecs = 0; |
991 | ec->tx_max_coalesced_frames = 0; |
992 | } |
993 | |
994 | if (priv->use_riwt && queue < rx_cnt) { |
995 | ec->rx_max_coalesced_frames = priv->rx_coal_frames[queue]; |
996 | ec->rx_coalesce_usecs = stmmac_riwt2usec(riwt: priv->rx_riwt[queue], |
997 | priv); |
998 | } else { |
999 | ec->rx_max_coalesced_frames = 0; |
1000 | ec->rx_coalesce_usecs = 0; |
1001 | } |
1002 | |
1003 | return 0; |
1004 | } |
1005 | |
1006 | static int stmmac_get_coalesce(struct net_device *dev, |
1007 | struct ethtool_coalesce *ec, |
1008 | struct kernel_ethtool_coalesce *kernel_coal, |
1009 | struct netlink_ext_ack *extack) |
1010 | { |
1011 | return __stmmac_get_coalesce(dev, ec, queue: -1); |
1012 | } |
1013 | |
1014 | static int stmmac_get_per_queue_coalesce(struct net_device *dev, u32 queue, |
1015 | struct ethtool_coalesce *ec) |
1016 | { |
1017 | return __stmmac_get_coalesce(dev, ec, queue); |
1018 | } |
1019 | |
1020 | static int __stmmac_set_coalesce(struct net_device *dev, |
1021 | struct ethtool_coalesce *ec, |
1022 | int queue) |
1023 | { |
1024 | struct stmmac_priv *priv = netdev_priv(dev); |
1025 | bool all_queues = false; |
1026 | unsigned int rx_riwt; |
1027 | u32 max_cnt; |
1028 | u32 rx_cnt; |
1029 | u32 tx_cnt; |
1030 | |
1031 | rx_cnt = priv->plat->rx_queues_to_use; |
1032 | tx_cnt = priv->plat->tx_queues_to_use; |
1033 | max_cnt = max(rx_cnt, tx_cnt); |
1034 | |
1035 | if (queue < 0) |
1036 | all_queues = true; |
1037 | else if (queue >= max_cnt) |
1038 | return -EINVAL; |
1039 | |
1040 | if (priv->use_riwt) { |
1041 | rx_riwt = stmmac_usec2riwt(usec: ec->rx_coalesce_usecs, priv); |
1042 | |
1043 | if ((rx_riwt > MAX_DMA_RIWT) || (rx_riwt < MIN_DMA_RIWT)) |
1044 | return -EINVAL; |
1045 | |
1046 | if (all_queues) { |
1047 | int i; |
1048 | |
1049 | for (i = 0; i < rx_cnt; i++) { |
1050 | priv->rx_riwt[i] = rx_riwt; |
1051 | stmmac_rx_watchdog(priv, priv->ioaddr, |
1052 | rx_riwt, i); |
1053 | priv->rx_coal_frames[i] = |
1054 | ec->rx_max_coalesced_frames; |
1055 | } |
1056 | } else if (queue < rx_cnt) { |
1057 | priv->rx_riwt[queue] = rx_riwt; |
1058 | stmmac_rx_watchdog(priv, priv->ioaddr, |
1059 | rx_riwt, queue); |
1060 | priv->rx_coal_frames[queue] = |
1061 | ec->rx_max_coalesced_frames; |
1062 | } |
1063 | } |
1064 | |
1065 | if ((ec->tx_coalesce_usecs == 0) && |
1066 | (ec->tx_max_coalesced_frames == 0)) |
1067 | return -EINVAL; |
1068 | |
1069 | if ((ec->tx_coalesce_usecs > STMMAC_MAX_COAL_TX_TICK) || |
1070 | (ec->tx_max_coalesced_frames > STMMAC_TX_MAX_FRAMES)) |
1071 | return -EINVAL; |
1072 | |
1073 | if (all_queues) { |
1074 | int i; |
1075 | |
1076 | for (i = 0; i < tx_cnt; i++) { |
1077 | priv->tx_coal_frames[i] = |
1078 | ec->tx_max_coalesced_frames; |
1079 | priv->tx_coal_timer[i] = |
1080 | ec->tx_coalesce_usecs; |
1081 | } |
1082 | } else if (queue < tx_cnt) { |
1083 | priv->tx_coal_frames[queue] = |
1084 | ec->tx_max_coalesced_frames; |
1085 | priv->tx_coal_timer[queue] = |
1086 | ec->tx_coalesce_usecs; |
1087 | } |
1088 | |
1089 | return 0; |
1090 | } |
1091 | |
1092 | static int stmmac_set_coalesce(struct net_device *dev, |
1093 | struct ethtool_coalesce *ec, |
1094 | struct kernel_ethtool_coalesce *kernel_coal, |
1095 | struct netlink_ext_ack *extack) |
1096 | { |
1097 | return __stmmac_set_coalesce(dev, ec, queue: -1); |
1098 | } |
1099 | |
1100 | static int stmmac_set_per_queue_coalesce(struct net_device *dev, u32 queue, |
1101 | struct ethtool_coalesce *ec) |
1102 | { |
1103 | return __stmmac_set_coalesce(dev, ec, queue); |
1104 | } |
1105 | |
1106 | static int stmmac_get_rxnfc(struct net_device *dev, |
1107 | struct ethtool_rxnfc *rxnfc, u32 *rule_locs) |
1108 | { |
1109 | struct stmmac_priv *priv = netdev_priv(dev); |
1110 | |
1111 | switch (rxnfc->cmd) { |
1112 | case ETHTOOL_GRXRINGS: |
1113 | rxnfc->data = priv->plat->rx_queues_to_use; |
1114 | break; |
1115 | default: |
1116 | return -EOPNOTSUPP; |
1117 | } |
1118 | |
1119 | return 0; |
1120 | } |
1121 | |
1122 | static u32 stmmac_get_rxfh_key_size(struct net_device *dev) |
1123 | { |
1124 | struct stmmac_priv *priv = netdev_priv(dev); |
1125 | |
1126 | return sizeof(priv->rss.key); |
1127 | } |
1128 | |
1129 | static u32 stmmac_get_rxfh_indir_size(struct net_device *dev) |
1130 | { |
1131 | struct stmmac_priv *priv = netdev_priv(dev); |
1132 | |
1133 | return ARRAY_SIZE(priv->rss.table); |
1134 | } |
1135 | |
1136 | static int stmmac_get_rxfh(struct net_device *dev, |
1137 | struct ethtool_rxfh_param *rxfh) |
1138 | { |
1139 | struct stmmac_priv *priv = netdev_priv(dev); |
1140 | int i; |
1141 | |
1142 | if (rxfh->indir) { |
1143 | for (i = 0; i < ARRAY_SIZE(priv->rss.table); i++) |
1144 | rxfh->indir[i] = priv->rss.table[i]; |
1145 | } |
1146 | |
1147 | if (rxfh->key) |
1148 | memcpy(rxfh->key, priv->rss.key, sizeof(priv->rss.key)); |
1149 | rxfh->hfunc = ETH_RSS_HASH_TOP; |
1150 | |
1151 | return 0; |
1152 | } |
1153 | |
1154 | static int stmmac_set_rxfh(struct net_device *dev, |
1155 | struct ethtool_rxfh_param *rxfh, |
1156 | struct netlink_ext_ack *extack) |
1157 | { |
1158 | struct stmmac_priv *priv = netdev_priv(dev); |
1159 | int i; |
1160 | |
1161 | if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && |
1162 | rxfh->hfunc != ETH_RSS_HASH_TOP) |
1163 | return -EOPNOTSUPP; |
1164 | |
1165 | if (rxfh->indir) { |
1166 | for (i = 0; i < ARRAY_SIZE(priv->rss.table); i++) |
1167 | priv->rss.table[i] = rxfh->indir[i]; |
1168 | } |
1169 | |
1170 | if (rxfh->key) |
1171 | memcpy(priv->rss.key, rxfh->key, sizeof(priv->rss.key)); |
1172 | |
1173 | return stmmac_rss_configure(priv, priv->hw, &priv->rss, |
1174 | priv->plat->rx_queues_to_use); |
1175 | } |
1176 | |
1177 | static void stmmac_get_channels(struct net_device *dev, |
1178 | struct ethtool_channels *chan) |
1179 | { |
1180 | struct stmmac_priv *priv = netdev_priv(dev); |
1181 | |
1182 | chan->rx_count = priv->plat->rx_queues_to_use; |
1183 | chan->tx_count = priv->plat->tx_queues_to_use; |
1184 | chan->max_rx = priv->dma_cap.number_rx_queues; |
1185 | chan->max_tx = priv->dma_cap.number_tx_queues; |
1186 | } |
1187 | |
1188 | static int stmmac_set_channels(struct net_device *dev, |
1189 | struct ethtool_channels *chan) |
1190 | { |
1191 | struct stmmac_priv *priv = netdev_priv(dev); |
1192 | |
1193 | if (chan->rx_count > priv->dma_cap.number_rx_queues || |
1194 | chan->tx_count > priv->dma_cap.number_tx_queues || |
1195 | !chan->rx_count || !chan->tx_count) |
1196 | return -EINVAL; |
1197 | |
1198 | return stmmac_reinit_queues(dev, rx_cnt: chan->rx_count, tx_cnt: chan->tx_count); |
1199 | } |
1200 | |
1201 | static int stmmac_get_ts_info(struct net_device *dev, |
1202 | struct ethtool_ts_info *info) |
1203 | { |
1204 | struct stmmac_priv *priv = netdev_priv(dev); |
1205 | |
1206 | if ((priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp)) { |
1207 | |
1208 | info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | |
1209 | SOF_TIMESTAMPING_TX_HARDWARE | |
1210 | SOF_TIMESTAMPING_RX_SOFTWARE | |
1211 | SOF_TIMESTAMPING_RX_HARDWARE | |
1212 | SOF_TIMESTAMPING_SOFTWARE | |
1213 | SOF_TIMESTAMPING_RAW_HARDWARE; |
1214 | |
1215 | if (priv->ptp_clock) |
1216 | info->phc_index = ptp_clock_index(ptp: priv->ptp_clock); |
1217 | |
1218 | info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); |
1219 | |
1220 | info->rx_filters = ((1 << HWTSTAMP_FILTER_NONE) | |
1221 | (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | |
1222 | (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | |
1223 | (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | |
1224 | (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | |
1225 | (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | |
1226 | (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | |
1227 | (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | |
1228 | (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | |
1229 | (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | |
1230 | (1 << HWTSTAMP_FILTER_ALL)); |
1231 | return 0; |
1232 | } else |
1233 | return ethtool_op_get_ts_info(dev, eti: info); |
1234 | } |
1235 | |
1236 | static int stmmac_get_tunable(struct net_device *dev, |
1237 | const struct ethtool_tunable *tuna, void *data) |
1238 | { |
1239 | struct stmmac_priv *priv = netdev_priv(dev); |
1240 | int ret = 0; |
1241 | |
1242 | switch (tuna->id) { |
1243 | case ETHTOOL_RX_COPYBREAK: |
1244 | *(u32 *)data = priv->rx_copybreak; |
1245 | break; |
1246 | default: |
1247 | ret = -EINVAL; |
1248 | break; |
1249 | } |
1250 | |
1251 | return ret; |
1252 | } |
1253 | |
1254 | static int stmmac_set_tunable(struct net_device *dev, |
1255 | const struct ethtool_tunable *tuna, |
1256 | const void *data) |
1257 | { |
1258 | struct stmmac_priv *priv = netdev_priv(dev); |
1259 | int ret = 0; |
1260 | |
1261 | switch (tuna->id) { |
1262 | case ETHTOOL_RX_COPYBREAK: |
1263 | priv->rx_copybreak = *(u32 *)data; |
1264 | break; |
1265 | default: |
1266 | ret = -EINVAL; |
1267 | break; |
1268 | } |
1269 | |
1270 | return ret; |
1271 | } |
1272 | |
1273 | static const struct ethtool_ops stmmac_ethtool_ops = { |
1274 | .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
1275 | ETHTOOL_COALESCE_MAX_FRAMES, |
1276 | .begin = stmmac_check_if_running, |
1277 | .get_drvinfo = stmmac_ethtool_getdrvinfo, |
1278 | .get_msglevel = stmmac_ethtool_getmsglevel, |
1279 | .set_msglevel = stmmac_ethtool_setmsglevel, |
1280 | .get_regs = stmmac_ethtool_gregs, |
1281 | .get_regs_len = stmmac_ethtool_get_regs_len, |
1282 | .get_link = ethtool_op_get_link, |
1283 | .nway_reset = stmmac_nway_reset, |
1284 | .get_ringparam = stmmac_get_ringparam, |
1285 | .set_ringparam = stmmac_set_ringparam, |
1286 | .get_pauseparam = stmmac_get_pauseparam, |
1287 | .set_pauseparam = stmmac_set_pauseparam, |
1288 | .self_test = stmmac_selftest_run, |
1289 | .get_ethtool_stats = stmmac_get_ethtool_stats, |
1290 | .get_strings = stmmac_get_strings, |
1291 | .get_wol = stmmac_get_wol, |
1292 | .set_wol = stmmac_set_wol, |
1293 | .get_eee = stmmac_ethtool_op_get_eee, |
1294 | .set_eee = stmmac_ethtool_op_set_eee, |
1295 | .get_sset_count = stmmac_get_sset_count, |
1296 | .get_rxnfc = stmmac_get_rxnfc, |
1297 | .get_rxfh_key_size = stmmac_get_rxfh_key_size, |
1298 | .get_rxfh_indir_size = stmmac_get_rxfh_indir_size, |
1299 | .get_rxfh = stmmac_get_rxfh, |
1300 | .set_rxfh = stmmac_set_rxfh, |
1301 | .get_ts_info = stmmac_get_ts_info, |
1302 | .get_coalesce = stmmac_get_coalesce, |
1303 | .set_coalesce = stmmac_set_coalesce, |
1304 | .get_per_queue_coalesce = stmmac_get_per_queue_coalesce, |
1305 | .set_per_queue_coalesce = stmmac_set_per_queue_coalesce, |
1306 | .get_channels = stmmac_get_channels, |
1307 | .set_channels = stmmac_set_channels, |
1308 | .get_tunable = stmmac_get_tunable, |
1309 | .set_tunable = stmmac_set_tunable, |
1310 | .get_link_ksettings = stmmac_ethtool_get_link_ksettings, |
1311 | .set_link_ksettings = stmmac_ethtool_set_link_ksettings, |
1312 | }; |
1313 | |
1314 | void stmmac_set_ethtool_ops(struct net_device *netdev) |
1315 | { |
1316 | netdev->ethtool_ops = &stmmac_ethtool_ops; |
1317 | } |
1318 | |