1 | /* |
2 | * AMD 10Gb Ethernet driver |
3 | * |
4 | * This file is available to you under your choice of the following two |
5 | * licenses: |
6 | * |
7 | * License 1: GPLv2 |
8 | * |
9 | * Copyright (c) 2014-2016 Advanced Micro Devices, Inc. |
10 | * |
11 | * This file is free software; you may copy, redistribute and/or modify |
12 | * it under the terms of the GNU General Public License as published by |
13 | * the Free Software Foundation, either version 2 of the License, or (at |
14 | * your option) any later version. |
15 | * |
16 | * This file is distributed in the hope that it will be useful, but |
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
19 | * General Public License for more details. |
20 | * |
21 | * You should have received a copy of the GNU General Public License |
22 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
23 | * |
24 | * This file incorporates work covered by the following copyright and |
25 | * permission notice: |
26 | * The Synopsys DWC ETHER XGMAC Software Driver and documentation |
27 | * (hereinafter "Software") is an unsupported proprietary work of Synopsys, |
28 | * Inc. unless otherwise expressly agreed to in writing between Synopsys |
29 | * and you. |
30 | * |
31 | * The Software IS NOT an item of Licensed Software or Licensed Product |
32 | * under any End User Software License Agreement or Agreement for Licensed |
33 | * Product with Synopsys or any supplement thereto. Permission is hereby |
34 | * granted, free of charge, to any person obtaining a copy of this software |
35 | * annotated with this license and the Software, to deal in the Software |
36 | * without restriction, including without limitation the rights to use, |
37 | * copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
38 | * of the Software, and to permit persons to whom the Software is furnished |
39 | * to do so, subject to the following conditions: |
40 | * |
41 | * The above copyright notice and this permission notice shall be included |
42 | * in all copies or substantial portions of the Software. |
43 | * |
44 | * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" |
45 | * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
46 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
47 | * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS |
48 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
49 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
50 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
51 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
52 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
53 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
54 | * THE POSSIBILITY OF SUCH DAMAGE. |
55 | * |
56 | * |
57 | * License 2: Modified BSD |
58 | * |
59 | * Copyright (c) 2014-2016 Advanced Micro Devices, Inc. |
60 | * All rights reserved. |
61 | * |
62 | * Redistribution and use in source and binary forms, with or without |
63 | * modification, are permitted provided that the following conditions are met: |
64 | * * Redistributions of source code must retain the above copyright |
65 | * notice, this list of conditions and the following disclaimer. |
66 | * * Redistributions in binary form must reproduce the above copyright |
67 | * notice, this list of conditions and the following disclaimer in the |
68 | * documentation and/or other materials provided with the distribution. |
69 | * * Neither the name of Advanced Micro Devices, Inc. nor the |
70 | * names of its contributors may be used to endorse or promote products |
71 | * derived from this software without specific prior written permission. |
72 | * |
73 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
74 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
75 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
76 | * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY |
77 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
78 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
79 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
80 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
81 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
82 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
83 | * |
84 | * This file incorporates work covered by the following copyright and |
85 | * permission notice: |
86 | * The Synopsys DWC ETHER XGMAC Software Driver and documentation |
87 | * (hereinafter "Software") is an unsupported proprietary work of Synopsys, |
88 | * Inc. unless otherwise expressly agreed to in writing between Synopsys |
89 | * and you. |
90 | * |
91 | * The Software IS NOT an item of Licensed Software or Licensed Product |
92 | * under any End User Software License Agreement or Agreement for Licensed |
93 | * Product with Synopsys or any supplement thereto. Permission is hereby |
94 | * granted, free of charge, to any person obtaining a copy of this software |
95 | * annotated with this license and the Software, to deal in the Software |
96 | * without restriction, including without limitation the rights to use, |
97 | * copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
98 | * of the Software, and to permit persons to whom the Software is furnished |
99 | * to do so, subject to the following conditions: |
100 | * |
101 | * The above copyright notice and this permission notice shall be included |
102 | * in all copies or substantial portions of the Software. |
103 | * |
104 | * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" |
105 | * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
106 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
107 | * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS |
108 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
109 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
110 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
111 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
112 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
113 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
114 | * THE POSSIBILITY OF SUCH DAMAGE. |
115 | */ |
116 | |
117 | #include <linux/spinlock.h> |
118 | #include <linux/phy.h> |
119 | #include <linux/net_tstamp.h> |
120 | |
121 | #include "xgbe.h" |
122 | #include "xgbe-common.h" |
123 | |
124 | struct xgbe_stats { |
125 | char stat_string[ETH_GSTRING_LEN]; |
126 | int stat_size; |
127 | int stat_offset; |
128 | }; |
129 | |
130 | #define XGMAC_MMC_STAT(_string, _var) \ |
131 | { _string, \ |
132 | sizeof_field(struct xgbe_mmc_stats, _var), \ |
133 | offsetof(struct xgbe_prv_data, mmc_stats._var), \ |
134 | } |
135 | |
136 | #define XGMAC_EXT_STAT(_string, _var) \ |
137 | { _string, \ |
138 | sizeof_field(struct xgbe_ext_stats, _var), \ |
139 | offsetof(struct xgbe_prv_data, ext_stats._var), \ |
140 | } |
141 | |
142 | static const struct xgbe_stats xgbe_gstring_stats[] = { |
143 | XGMAC_MMC_STAT("tx_bytes" , txoctetcount_gb), |
144 | XGMAC_MMC_STAT("tx_packets" , txframecount_gb), |
145 | XGMAC_MMC_STAT("tx_unicast_packets" , txunicastframes_gb), |
146 | XGMAC_MMC_STAT("tx_broadcast_packets" , txbroadcastframes_gb), |
147 | XGMAC_MMC_STAT("tx_multicast_packets" , txmulticastframes_gb), |
148 | XGMAC_MMC_STAT("tx_vlan_packets" , txvlanframes_g), |
149 | XGMAC_EXT_STAT("tx_vxlan_packets" , tx_vxlan_packets), |
150 | XGMAC_EXT_STAT("tx_tso_packets" , tx_tso_packets), |
151 | XGMAC_MMC_STAT("tx_64_byte_packets" , tx64octets_gb), |
152 | XGMAC_MMC_STAT("tx_65_to_127_byte_packets" , tx65to127octets_gb), |
153 | XGMAC_MMC_STAT("tx_128_to_255_byte_packets" , tx128to255octets_gb), |
154 | XGMAC_MMC_STAT("tx_256_to_511_byte_packets" , tx256to511octets_gb), |
155 | XGMAC_MMC_STAT("tx_512_to_1023_byte_packets" , tx512to1023octets_gb), |
156 | XGMAC_MMC_STAT("tx_1024_to_max_byte_packets" , tx1024tomaxoctets_gb), |
157 | XGMAC_MMC_STAT("tx_underflow_errors" , txunderflowerror), |
158 | XGMAC_MMC_STAT("tx_pause_frames" , txpauseframes), |
159 | |
160 | XGMAC_MMC_STAT("rx_bytes" , rxoctetcount_gb), |
161 | XGMAC_MMC_STAT("rx_packets" , rxframecount_gb), |
162 | XGMAC_MMC_STAT("rx_unicast_packets" , rxunicastframes_g), |
163 | XGMAC_MMC_STAT("rx_broadcast_packets" , rxbroadcastframes_g), |
164 | XGMAC_MMC_STAT("rx_multicast_packets" , rxmulticastframes_g), |
165 | XGMAC_MMC_STAT("rx_vlan_packets" , rxvlanframes_gb), |
166 | XGMAC_EXT_STAT("rx_vxlan_packets" , rx_vxlan_packets), |
167 | XGMAC_MMC_STAT("rx_64_byte_packets" , rx64octets_gb), |
168 | XGMAC_MMC_STAT("rx_65_to_127_byte_packets" , rx65to127octets_gb), |
169 | XGMAC_MMC_STAT("rx_128_to_255_byte_packets" , rx128to255octets_gb), |
170 | XGMAC_MMC_STAT("rx_256_to_511_byte_packets" , rx256to511octets_gb), |
171 | XGMAC_MMC_STAT("rx_512_to_1023_byte_packets" , rx512to1023octets_gb), |
172 | XGMAC_MMC_STAT("rx_1024_to_max_byte_packets" , rx1024tomaxoctets_gb), |
173 | XGMAC_MMC_STAT("rx_undersize_packets" , rxundersize_g), |
174 | XGMAC_MMC_STAT("rx_oversize_packets" , rxoversize_g), |
175 | XGMAC_MMC_STAT("rx_crc_errors" , rxcrcerror), |
176 | XGMAC_MMC_STAT("rx_crc_errors_small_packets" , rxrunterror), |
177 | XGMAC_MMC_STAT("rx_crc_errors_giant_packets" , rxjabbererror), |
178 | XGMAC_MMC_STAT("rx_length_errors" , rxlengtherror), |
179 | XGMAC_MMC_STAT("rx_out_of_range_errors" , rxoutofrangetype), |
180 | XGMAC_MMC_STAT("rx_fifo_overflow_errors" , rxfifooverflow), |
181 | XGMAC_MMC_STAT("rx_watchdog_errors" , rxwatchdogerror), |
182 | XGMAC_EXT_STAT("rx_csum_errors" , rx_csum_errors), |
183 | XGMAC_EXT_STAT("rx_vxlan_csum_errors" , rx_vxlan_csum_errors), |
184 | XGMAC_MMC_STAT("rx_pause_frames" , rxpauseframes), |
185 | XGMAC_EXT_STAT("rx_split_header_packets" , rx_split_header_packets), |
186 | XGMAC_EXT_STAT("rx_buffer_unavailable" , rx_buffer_unavailable), |
187 | }; |
188 | |
189 | #define XGBE_STATS_COUNT ARRAY_SIZE(xgbe_gstring_stats) |
190 | |
191 | static void xgbe_get_strings(struct net_device *netdev, u32 stringset, u8 *data) |
192 | { |
193 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
194 | int i; |
195 | |
196 | switch (stringset) { |
197 | case ETH_SS_STATS: |
198 | for (i = 0; i < XGBE_STATS_COUNT; i++) { |
199 | memcpy(data, xgbe_gstring_stats[i].stat_string, |
200 | ETH_GSTRING_LEN); |
201 | data += ETH_GSTRING_LEN; |
202 | } |
203 | for (i = 0; i < pdata->tx_ring_count; i++) { |
204 | sprintf(buf: data, fmt: "txq_%u_packets" , i); |
205 | data += ETH_GSTRING_LEN; |
206 | sprintf(buf: data, fmt: "txq_%u_bytes" , i); |
207 | data += ETH_GSTRING_LEN; |
208 | } |
209 | for (i = 0; i < pdata->rx_ring_count; i++) { |
210 | sprintf(buf: data, fmt: "rxq_%u_packets" , i); |
211 | data += ETH_GSTRING_LEN; |
212 | sprintf(buf: data, fmt: "rxq_%u_bytes" , i); |
213 | data += ETH_GSTRING_LEN; |
214 | } |
215 | break; |
216 | } |
217 | } |
218 | |
219 | static void xgbe_get_ethtool_stats(struct net_device *netdev, |
220 | struct ethtool_stats *stats, u64 *data) |
221 | { |
222 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
223 | u8 *stat; |
224 | int i; |
225 | |
226 | pdata->hw_if.read_mmc_stats(pdata); |
227 | for (i = 0; i < XGBE_STATS_COUNT; i++) { |
228 | stat = (u8 *)pdata + xgbe_gstring_stats[i].stat_offset; |
229 | *data++ = *(u64 *)stat; |
230 | } |
231 | for (i = 0; i < pdata->tx_ring_count; i++) { |
232 | *data++ = pdata->ext_stats.txq_packets[i]; |
233 | *data++ = pdata->ext_stats.txq_bytes[i]; |
234 | } |
235 | for (i = 0; i < pdata->rx_ring_count; i++) { |
236 | *data++ = pdata->ext_stats.rxq_packets[i]; |
237 | *data++ = pdata->ext_stats.rxq_bytes[i]; |
238 | } |
239 | } |
240 | |
241 | static int xgbe_get_sset_count(struct net_device *netdev, int stringset) |
242 | { |
243 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
244 | int ret; |
245 | |
246 | switch (stringset) { |
247 | case ETH_SS_STATS: |
248 | ret = XGBE_STATS_COUNT + |
249 | (pdata->tx_ring_count * 2) + |
250 | (pdata->rx_ring_count * 2); |
251 | break; |
252 | |
253 | default: |
254 | ret = -EOPNOTSUPP; |
255 | } |
256 | |
257 | return ret; |
258 | } |
259 | |
260 | static void xgbe_get_pauseparam(struct net_device *netdev, |
261 | struct ethtool_pauseparam *pause) |
262 | { |
263 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
264 | |
265 | pause->autoneg = pdata->phy.pause_autoneg; |
266 | pause->tx_pause = pdata->phy.tx_pause; |
267 | pause->rx_pause = pdata->phy.rx_pause; |
268 | } |
269 | |
270 | static int xgbe_set_pauseparam(struct net_device *netdev, |
271 | struct ethtool_pauseparam *pause) |
272 | { |
273 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
274 | struct ethtool_link_ksettings *lks = &pdata->phy.lks; |
275 | int ret = 0; |
276 | |
277 | if (pause->autoneg && (pdata->phy.autoneg != AUTONEG_ENABLE)) { |
278 | netdev_err(dev: netdev, |
279 | format: "autoneg disabled, pause autoneg not available\n" ); |
280 | return -EINVAL; |
281 | } |
282 | |
283 | pdata->phy.pause_autoneg = pause->autoneg; |
284 | pdata->phy.tx_pause = pause->tx_pause; |
285 | pdata->phy.rx_pause = pause->rx_pause; |
286 | |
287 | XGBE_CLR_ADV(lks, Pause); |
288 | XGBE_CLR_ADV(lks, Asym_Pause); |
289 | |
290 | if (pause->rx_pause) { |
291 | XGBE_SET_ADV(lks, Pause); |
292 | XGBE_SET_ADV(lks, Asym_Pause); |
293 | } |
294 | |
295 | if (pause->tx_pause) { |
296 | /* Equivalent to XOR of Asym_Pause */ |
297 | if (XGBE_ADV(lks, Asym_Pause)) |
298 | XGBE_CLR_ADV(lks, Asym_Pause); |
299 | else |
300 | XGBE_SET_ADV(lks, Asym_Pause); |
301 | } |
302 | |
303 | if (netif_running(dev: netdev)) |
304 | ret = pdata->phy_if.phy_config_aneg(pdata); |
305 | |
306 | return ret; |
307 | } |
308 | |
309 | static int xgbe_get_link_ksettings(struct net_device *netdev, |
310 | struct ethtool_link_ksettings *cmd) |
311 | { |
312 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
313 | struct ethtool_link_ksettings *lks = &pdata->phy.lks; |
314 | |
315 | cmd->base.phy_address = pdata->phy.address; |
316 | |
317 | if (netif_carrier_ok(dev: netdev)) { |
318 | cmd->base.speed = pdata->phy.speed; |
319 | cmd->base.duplex = pdata->phy.duplex; |
320 | } else { |
321 | cmd->base.speed = SPEED_UNKNOWN; |
322 | cmd->base.duplex = DUPLEX_UNKNOWN; |
323 | } |
324 | |
325 | cmd->base.autoneg = pdata->phy.autoneg; |
326 | cmd->base.port = PORT_NONE; |
327 | |
328 | XGBE_LM_COPY(cmd, supported, lks, supported); |
329 | XGBE_LM_COPY(cmd, advertising, lks, advertising); |
330 | XGBE_LM_COPY(cmd, lp_advertising, lks, lp_advertising); |
331 | |
332 | return 0; |
333 | } |
334 | |
335 | static int xgbe_set_link_ksettings(struct net_device *netdev, |
336 | const struct ethtool_link_ksettings *cmd) |
337 | { |
338 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
339 | struct ethtool_link_ksettings *lks = &pdata->phy.lks; |
340 | __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising); |
341 | u32 speed; |
342 | int ret; |
343 | |
344 | speed = cmd->base.speed; |
345 | |
346 | if (cmd->base.phy_address != pdata->phy.address) { |
347 | netdev_err(dev: netdev, format: "invalid phy address %hhu\n" , |
348 | cmd->base.phy_address); |
349 | return -EINVAL; |
350 | } |
351 | |
352 | if ((cmd->base.autoneg != AUTONEG_ENABLE) && |
353 | (cmd->base.autoneg != AUTONEG_DISABLE)) { |
354 | netdev_err(dev: netdev, format: "unsupported autoneg %hhu\n" , |
355 | cmd->base.autoneg); |
356 | return -EINVAL; |
357 | } |
358 | |
359 | if (cmd->base.autoneg == AUTONEG_DISABLE) { |
360 | if (!pdata->phy_if.phy_valid_speed(pdata, speed)) { |
361 | netdev_err(dev: netdev, format: "unsupported speed %u\n" , speed); |
362 | return -EINVAL; |
363 | } |
364 | |
365 | if (cmd->base.duplex != DUPLEX_FULL) { |
366 | netdev_err(dev: netdev, format: "unsupported duplex %hhu\n" , |
367 | cmd->base.duplex); |
368 | return -EINVAL; |
369 | } |
370 | } |
371 | |
372 | netif_dbg(pdata, link, netdev, |
373 | "requested advertisement 0x%*pb, phy supported 0x%*pb\n" , |
374 | __ETHTOOL_LINK_MODE_MASK_NBITS, cmd->link_modes.advertising, |
375 | __ETHTOOL_LINK_MODE_MASK_NBITS, lks->link_modes.supported); |
376 | |
377 | linkmode_and(dst: advertising, a: cmd->link_modes.advertising, |
378 | b: lks->link_modes.supported); |
379 | |
380 | if ((cmd->base.autoneg == AUTONEG_ENABLE) && |
381 | bitmap_empty(src: advertising, nbits: __ETHTOOL_LINK_MODE_MASK_NBITS)) { |
382 | netdev_err(dev: netdev, |
383 | format: "unsupported requested advertisement\n" ); |
384 | return -EINVAL; |
385 | } |
386 | |
387 | ret = 0; |
388 | pdata->phy.autoneg = cmd->base.autoneg; |
389 | pdata->phy.speed = speed; |
390 | pdata->phy.duplex = cmd->base.duplex; |
391 | linkmode_copy(dst: lks->link_modes.advertising, src: advertising); |
392 | |
393 | if (cmd->base.autoneg == AUTONEG_ENABLE) |
394 | XGBE_SET_ADV(lks, Autoneg); |
395 | else |
396 | XGBE_CLR_ADV(lks, Autoneg); |
397 | |
398 | if (netif_running(dev: netdev)) |
399 | ret = pdata->phy_if.phy_config_aneg(pdata); |
400 | |
401 | return ret; |
402 | } |
403 | |
404 | static void xgbe_get_drvinfo(struct net_device *netdev, |
405 | struct ethtool_drvinfo *drvinfo) |
406 | { |
407 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
408 | struct xgbe_hw_features *hw_feat = &pdata->hw_feat; |
409 | |
410 | strscpy(drvinfo->driver, XGBE_DRV_NAME, sizeof(drvinfo->driver)); |
411 | strscpy(drvinfo->bus_info, dev_name(pdata->dev), |
412 | sizeof(drvinfo->bus_info)); |
413 | snprintf(buf: drvinfo->fw_version, size: sizeof(drvinfo->fw_version), fmt: "%d.%d.%d" , |
414 | XGMAC_GET_BITS(hw_feat->version, MAC_VR, USERVER), |
415 | XGMAC_GET_BITS(hw_feat->version, MAC_VR, DEVID), |
416 | XGMAC_GET_BITS(hw_feat->version, MAC_VR, SNPSVER)); |
417 | } |
418 | |
419 | static u32 xgbe_get_msglevel(struct net_device *netdev) |
420 | { |
421 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
422 | |
423 | return pdata->msg_enable; |
424 | } |
425 | |
426 | static void xgbe_set_msglevel(struct net_device *netdev, u32 msglevel) |
427 | { |
428 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
429 | |
430 | pdata->msg_enable = msglevel; |
431 | } |
432 | |
433 | static int xgbe_get_coalesce(struct net_device *netdev, |
434 | struct ethtool_coalesce *ec, |
435 | struct kernel_ethtool_coalesce *kernel_coal, |
436 | struct netlink_ext_ack *extack) |
437 | { |
438 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
439 | |
440 | memset(ec, 0, sizeof(struct ethtool_coalesce)); |
441 | |
442 | ec->rx_coalesce_usecs = pdata->rx_usecs; |
443 | ec->rx_max_coalesced_frames = pdata->rx_frames; |
444 | |
445 | ec->tx_max_coalesced_frames = pdata->tx_frames; |
446 | |
447 | return 0; |
448 | } |
449 | |
450 | static int xgbe_set_coalesce(struct net_device *netdev, |
451 | struct ethtool_coalesce *ec, |
452 | struct kernel_ethtool_coalesce *kernel_coal, |
453 | struct netlink_ext_ack *extack) |
454 | { |
455 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
456 | struct xgbe_hw_if *hw_if = &pdata->hw_if; |
457 | unsigned int rx_frames, rx_riwt, rx_usecs; |
458 | unsigned int tx_frames; |
459 | |
460 | rx_riwt = hw_if->usec_to_riwt(pdata, ec->rx_coalesce_usecs); |
461 | rx_usecs = ec->rx_coalesce_usecs; |
462 | rx_frames = ec->rx_max_coalesced_frames; |
463 | |
464 | /* Use smallest possible value if conversion resulted in zero */ |
465 | if (rx_usecs && !rx_riwt) |
466 | rx_riwt = 1; |
467 | |
468 | /* Check the bounds of values for Rx */ |
469 | if (rx_riwt > XGMAC_MAX_DMA_RIWT) { |
470 | netdev_err(dev: netdev, format: "rx-usec is limited to %d usecs\n" , |
471 | hw_if->riwt_to_usec(pdata, XGMAC_MAX_DMA_RIWT)); |
472 | return -EINVAL; |
473 | } |
474 | if (rx_frames > pdata->rx_desc_count) { |
475 | netdev_err(dev: netdev, format: "rx-frames is limited to %d frames\n" , |
476 | pdata->rx_desc_count); |
477 | return -EINVAL; |
478 | } |
479 | |
480 | tx_frames = ec->tx_max_coalesced_frames; |
481 | |
482 | /* Check the bounds of values for Tx */ |
483 | if (tx_frames > pdata->tx_desc_count) { |
484 | netdev_err(dev: netdev, format: "tx-frames is limited to %d frames\n" , |
485 | pdata->tx_desc_count); |
486 | return -EINVAL; |
487 | } |
488 | |
489 | pdata->rx_riwt = rx_riwt; |
490 | pdata->rx_usecs = rx_usecs; |
491 | pdata->rx_frames = rx_frames; |
492 | hw_if->config_rx_coalesce(pdata); |
493 | |
494 | pdata->tx_frames = tx_frames; |
495 | hw_if->config_tx_coalesce(pdata); |
496 | |
497 | return 0; |
498 | } |
499 | |
500 | static int xgbe_get_rxnfc(struct net_device *netdev, |
501 | struct ethtool_rxnfc *rxnfc, u32 *rule_locs) |
502 | { |
503 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
504 | |
505 | switch (rxnfc->cmd) { |
506 | case ETHTOOL_GRXRINGS: |
507 | rxnfc->data = pdata->rx_ring_count; |
508 | break; |
509 | default: |
510 | return -EOPNOTSUPP; |
511 | } |
512 | |
513 | return 0; |
514 | } |
515 | |
516 | static u32 xgbe_get_rxfh_key_size(struct net_device *netdev) |
517 | { |
518 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
519 | |
520 | return sizeof(pdata->rss_key); |
521 | } |
522 | |
523 | static u32 xgbe_get_rxfh_indir_size(struct net_device *netdev) |
524 | { |
525 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
526 | |
527 | return ARRAY_SIZE(pdata->rss_table); |
528 | } |
529 | |
530 | static int xgbe_get_rxfh(struct net_device *netdev, |
531 | struct ethtool_rxfh_param *rxfh) |
532 | { |
533 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
534 | unsigned int i; |
535 | |
536 | if (rxfh->indir) { |
537 | for (i = 0; i < ARRAY_SIZE(pdata->rss_table); i++) |
538 | rxfh->indir[i] = XGMAC_GET_BITS(pdata->rss_table[i], |
539 | MAC_RSSDR, DMCH); |
540 | } |
541 | |
542 | if (rxfh->key) |
543 | memcpy(rxfh->key, pdata->rss_key, sizeof(pdata->rss_key)); |
544 | |
545 | rxfh->hfunc = ETH_RSS_HASH_TOP; |
546 | |
547 | return 0; |
548 | } |
549 | |
550 | static int xgbe_set_rxfh(struct net_device *netdev, |
551 | struct ethtool_rxfh_param *rxfh, |
552 | struct netlink_ext_ack *extack) |
553 | { |
554 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
555 | struct xgbe_hw_if *hw_if = &pdata->hw_if; |
556 | unsigned int ret; |
557 | |
558 | if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && |
559 | rxfh->hfunc != ETH_RSS_HASH_TOP) { |
560 | netdev_err(dev: netdev, format: "unsupported hash function\n" ); |
561 | return -EOPNOTSUPP; |
562 | } |
563 | |
564 | if (rxfh->indir) { |
565 | ret = hw_if->set_rss_lookup_table(pdata, rxfh->indir); |
566 | if (ret) |
567 | return ret; |
568 | } |
569 | |
570 | if (rxfh->key) { |
571 | ret = hw_if->set_rss_hash_key(pdata, rxfh->key); |
572 | if (ret) |
573 | return ret; |
574 | } |
575 | |
576 | return 0; |
577 | } |
578 | |
579 | static int xgbe_get_ts_info(struct net_device *netdev, |
580 | struct ethtool_ts_info *ts_info) |
581 | { |
582 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
583 | |
584 | ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | |
585 | SOF_TIMESTAMPING_RX_SOFTWARE | |
586 | SOF_TIMESTAMPING_SOFTWARE | |
587 | SOF_TIMESTAMPING_TX_HARDWARE | |
588 | SOF_TIMESTAMPING_RX_HARDWARE | |
589 | SOF_TIMESTAMPING_RAW_HARDWARE; |
590 | |
591 | if (pdata->ptp_clock) |
592 | ts_info->phc_index = ptp_clock_index(ptp: pdata->ptp_clock); |
593 | else |
594 | ts_info->phc_index = -1; |
595 | |
596 | ts_info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); |
597 | ts_info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | |
598 | (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | |
599 | (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | |
600 | (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | |
601 | (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | |
602 | (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | |
603 | (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | |
604 | (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | |
605 | (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | |
606 | (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | |
607 | (1 << HWTSTAMP_FILTER_ALL); |
608 | |
609 | return 0; |
610 | } |
611 | |
612 | static int xgbe_get_module_info(struct net_device *netdev, |
613 | struct ethtool_modinfo *modinfo) |
614 | { |
615 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
616 | |
617 | return pdata->phy_if.module_info(pdata, modinfo); |
618 | } |
619 | |
620 | static int xgbe_get_module_eeprom(struct net_device *netdev, |
621 | struct ethtool_eeprom *eeprom, u8 *data) |
622 | { |
623 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
624 | |
625 | return pdata->phy_if.module_eeprom(pdata, eeprom, data); |
626 | } |
627 | |
628 | static void |
629 | xgbe_get_ringparam(struct net_device *netdev, |
630 | struct ethtool_ringparam *ringparam, |
631 | struct kernel_ethtool_ringparam *kernel_ringparam, |
632 | struct netlink_ext_ack *extack) |
633 | { |
634 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
635 | |
636 | ringparam->rx_max_pending = XGBE_RX_DESC_CNT_MAX; |
637 | ringparam->tx_max_pending = XGBE_TX_DESC_CNT_MAX; |
638 | ringparam->rx_pending = pdata->rx_desc_count; |
639 | ringparam->tx_pending = pdata->tx_desc_count; |
640 | } |
641 | |
642 | static int xgbe_set_ringparam(struct net_device *netdev, |
643 | struct ethtool_ringparam *ringparam, |
644 | struct kernel_ethtool_ringparam *kernel_ringparam, |
645 | struct netlink_ext_ack *extack) |
646 | { |
647 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
648 | unsigned int rx, tx; |
649 | |
650 | if (ringparam->rx_mini_pending || ringparam->rx_jumbo_pending) { |
651 | netdev_err(dev: netdev, format: "unsupported ring parameter\n" ); |
652 | return -EINVAL; |
653 | } |
654 | |
655 | if ((ringparam->rx_pending < XGBE_RX_DESC_CNT_MIN) || |
656 | (ringparam->rx_pending > XGBE_RX_DESC_CNT_MAX)) { |
657 | netdev_err(dev: netdev, |
658 | format: "rx ring parameter must be between %u and %u\n" , |
659 | XGBE_RX_DESC_CNT_MIN, XGBE_RX_DESC_CNT_MAX); |
660 | return -EINVAL; |
661 | } |
662 | |
663 | if ((ringparam->tx_pending < XGBE_TX_DESC_CNT_MIN) || |
664 | (ringparam->tx_pending > XGBE_TX_DESC_CNT_MAX)) { |
665 | netdev_err(dev: netdev, |
666 | format: "tx ring parameter must be between %u and %u\n" , |
667 | XGBE_TX_DESC_CNT_MIN, XGBE_TX_DESC_CNT_MAX); |
668 | return -EINVAL; |
669 | } |
670 | |
671 | rx = __rounddown_pow_of_two(n: ringparam->rx_pending); |
672 | if (rx != ringparam->rx_pending) |
673 | netdev_notice(dev: netdev, |
674 | format: "rx ring parameter rounded to power of two: %u\n" , |
675 | rx); |
676 | |
677 | tx = __rounddown_pow_of_two(n: ringparam->tx_pending); |
678 | if (tx != ringparam->tx_pending) |
679 | netdev_notice(dev: netdev, |
680 | format: "tx ring parameter rounded to power of two: %u\n" , |
681 | tx); |
682 | |
683 | if ((rx == pdata->rx_desc_count) && |
684 | (tx == pdata->tx_desc_count)) |
685 | goto out; |
686 | |
687 | pdata->rx_desc_count = rx; |
688 | pdata->tx_desc_count = tx; |
689 | |
690 | xgbe_restart_dev(pdata); |
691 | |
692 | out: |
693 | return 0; |
694 | } |
695 | |
696 | static void xgbe_get_channels(struct net_device *netdev, |
697 | struct ethtool_channels *channels) |
698 | { |
699 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
700 | unsigned int rx, tx, combined; |
701 | |
702 | /* Calculate maximums allowed: |
703 | * - Take into account the number of available IRQs |
704 | * - Do not take into account the number of online CPUs so that |
705 | * the user can over-subscribe if desired |
706 | * - Tx is additionally limited by the number of hardware queues |
707 | */ |
708 | rx = min(pdata->hw_feat.rx_ch_cnt, pdata->rx_max_channel_count); |
709 | rx = min(rx, pdata->channel_irq_count); |
710 | tx = min(pdata->hw_feat.tx_ch_cnt, pdata->tx_max_channel_count); |
711 | tx = min(tx, pdata->channel_irq_count); |
712 | tx = min(tx, pdata->tx_max_q_count); |
713 | |
714 | combined = min(rx, tx); |
715 | |
716 | channels->max_combined = combined; |
717 | channels->max_rx = rx ? rx - 1 : 0; |
718 | channels->max_tx = tx ? tx - 1 : 0; |
719 | |
720 | /* Get current settings based on device state */ |
721 | rx = pdata->new_rx_ring_count ? : pdata->rx_ring_count; |
722 | tx = pdata->new_tx_ring_count ? : pdata->tx_ring_count; |
723 | |
724 | combined = min(rx, tx); |
725 | rx -= combined; |
726 | tx -= combined; |
727 | |
728 | channels->combined_count = combined; |
729 | channels->rx_count = rx; |
730 | channels->tx_count = tx; |
731 | } |
732 | |
733 | static void xgbe_print_set_channels_input(struct net_device *netdev, |
734 | struct ethtool_channels *channels) |
735 | { |
736 | netdev_err(dev: netdev, format: "channel inputs: combined=%u, rx-only=%u, tx-only=%u\n" , |
737 | channels->combined_count, channels->rx_count, |
738 | channels->tx_count); |
739 | } |
740 | |
741 | static int xgbe_set_channels(struct net_device *netdev, |
742 | struct ethtool_channels *channels) |
743 | { |
744 | struct xgbe_prv_data *pdata = netdev_priv(dev: netdev); |
745 | unsigned int rx, rx_curr, tx, tx_curr, combined; |
746 | |
747 | /* Calculate maximums allowed: |
748 | * - Take into account the number of available IRQs |
749 | * - Do not take into account the number of online CPUs so that |
750 | * the user can over-subscribe if desired |
751 | * - Tx is additionally limited by the number of hardware queues |
752 | */ |
753 | rx = min(pdata->hw_feat.rx_ch_cnt, pdata->rx_max_channel_count); |
754 | rx = min(rx, pdata->channel_irq_count); |
755 | tx = min(pdata->hw_feat.tx_ch_cnt, pdata->tx_max_channel_count); |
756 | tx = min(tx, pdata->tx_max_q_count); |
757 | tx = min(tx, pdata->channel_irq_count); |
758 | |
759 | combined = min(rx, tx); |
760 | |
761 | /* Should not be setting other count */ |
762 | if (channels->other_count) { |
763 | netdev_err(dev: netdev, |
764 | format: "other channel count must be zero\n" ); |
765 | return -EINVAL; |
766 | } |
767 | |
768 | /* Require at least one Combined (Rx and Tx) channel */ |
769 | if (!channels->combined_count) { |
770 | netdev_err(dev: netdev, |
771 | format: "at least one combined Rx/Tx channel is required\n" ); |
772 | xgbe_print_set_channels_input(netdev, channels); |
773 | return -EINVAL; |
774 | } |
775 | |
776 | /* Check combined channels */ |
777 | if (channels->combined_count > combined) { |
778 | netdev_err(dev: netdev, |
779 | format: "combined channel count cannot exceed %u\n" , |
780 | combined); |
781 | xgbe_print_set_channels_input(netdev, channels); |
782 | return -EINVAL; |
783 | } |
784 | |
785 | /* Can have some Rx-only or Tx-only channels, but not both */ |
786 | if (channels->rx_count && channels->tx_count) { |
787 | netdev_err(dev: netdev, |
788 | format: "cannot specify both Rx-only and Tx-only channels\n" ); |
789 | xgbe_print_set_channels_input(netdev, channels); |
790 | return -EINVAL; |
791 | } |
792 | |
793 | /* Check that we don't exceed the maximum number of channels */ |
794 | if ((channels->combined_count + channels->rx_count) > rx) { |
795 | netdev_err(dev: netdev, |
796 | format: "total Rx channels (%u) requested exceeds maximum available (%u)\n" , |
797 | channels->combined_count + channels->rx_count, rx); |
798 | xgbe_print_set_channels_input(netdev, channels); |
799 | return -EINVAL; |
800 | } |
801 | |
802 | if ((channels->combined_count + channels->tx_count) > tx) { |
803 | netdev_err(dev: netdev, |
804 | format: "total Tx channels (%u) requested exceeds maximum available (%u)\n" , |
805 | channels->combined_count + channels->tx_count, tx); |
806 | xgbe_print_set_channels_input(netdev, channels); |
807 | return -EINVAL; |
808 | } |
809 | |
810 | rx = channels->combined_count + channels->rx_count; |
811 | tx = channels->combined_count + channels->tx_count; |
812 | |
813 | rx_curr = pdata->new_rx_ring_count ? : pdata->rx_ring_count; |
814 | tx_curr = pdata->new_tx_ring_count ? : pdata->tx_ring_count; |
815 | |
816 | if ((rx == rx_curr) && (tx == tx_curr)) |
817 | goto out; |
818 | |
819 | pdata->new_rx_ring_count = rx; |
820 | pdata->new_tx_ring_count = tx; |
821 | |
822 | xgbe_full_restart_dev(pdata); |
823 | |
824 | out: |
825 | return 0; |
826 | } |
827 | |
828 | static const struct ethtool_ops xgbe_ethtool_ops = { |
829 | .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS | |
830 | ETHTOOL_COALESCE_MAX_FRAMES, |
831 | .get_drvinfo = xgbe_get_drvinfo, |
832 | .get_msglevel = xgbe_get_msglevel, |
833 | .set_msglevel = xgbe_set_msglevel, |
834 | .get_link = ethtool_op_get_link, |
835 | .get_coalesce = xgbe_get_coalesce, |
836 | .set_coalesce = xgbe_set_coalesce, |
837 | .get_pauseparam = xgbe_get_pauseparam, |
838 | .set_pauseparam = xgbe_set_pauseparam, |
839 | .get_strings = xgbe_get_strings, |
840 | .get_ethtool_stats = xgbe_get_ethtool_stats, |
841 | .get_sset_count = xgbe_get_sset_count, |
842 | .get_rxnfc = xgbe_get_rxnfc, |
843 | .get_rxfh_key_size = xgbe_get_rxfh_key_size, |
844 | .get_rxfh_indir_size = xgbe_get_rxfh_indir_size, |
845 | .get_rxfh = xgbe_get_rxfh, |
846 | .set_rxfh = xgbe_set_rxfh, |
847 | .get_ts_info = xgbe_get_ts_info, |
848 | .get_link_ksettings = xgbe_get_link_ksettings, |
849 | .set_link_ksettings = xgbe_set_link_ksettings, |
850 | .get_module_info = xgbe_get_module_info, |
851 | .get_module_eeprom = xgbe_get_module_eeprom, |
852 | .get_ringparam = xgbe_get_ringparam, |
853 | .set_ringparam = xgbe_set_ringparam, |
854 | .get_channels = xgbe_get_channels, |
855 | .set_channels = xgbe_set_channels, |
856 | }; |
857 | |
858 | const struct ethtool_ops *xgbe_get_ethtool_ops(void) |
859 | { |
860 | return &xgbe_ethtool_ops; |
861 | } |
862 | |