xref: /linux/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 1999 - 2010 Intel Corporation.
4  * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
5  *
6  * This code was derived from the Intel e1000e Linux driver.
7  */
8 #include "pch_gbe.h"
9 #include "pch_gbe_phy.h"
10 
11 static const char pch_driver_version[] = "1.01";
12 
13 /*
14  * pch_gbe_stats - Stats item information
15  */
16 struct pch_gbe_stats {
17 	char string[ETH_GSTRING_LEN];
18 	size_t size;
19 	size_t offset;
20 };
21 
22 #define PCH_GBE_STAT(m)						\
23 {								\
24 	.string = #m,						\
25 	.size = sizeof_field(struct pch_gbe_hw_stats, m),	\
26 	.offset = offsetof(struct pch_gbe_hw_stats, m),		\
27 }
28 
29 /*
30  * pch_gbe_gstrings_stats - ethtool information status name list
31  */
32 static const struct pch_gbe_stats pch_gbe_gstrings_stats[] = {
33 	PCH_GBE_STAT(rx_packets),
34 	PCH_GBE_STAT(tx_packets),
35 	PCH_GBE_STAT(rx_bytes),
36 	PCH_GBE_STAT(tx_bytes),
37 	PCH_GBE_STAT(rx_errors),
38 	PCH_GBE_STAT(tx_errors),
39 	PCH_GBE_STAT(rx_dropped),
40 	PCH_GBE_STAT(tx_dropped),
41 	PCH_GBE_STAT(multicast),
42 	PCH_GBE_STAT(collisions),
43 	PCH_GBE_STAT(rx_crc_errors),
44 	PCH_GBE_STAT(rx_frame_errors),
45 	PCH_GBE_STAT(rx_alloc_buff_failed),
46 	PCH_GBE_STAT(tx_length_errors),
47 	PCH_GBE_STAT(tx_aborted_errors),
48 	PCH_GBE_STAT(tx_carrier_errors),
49 	PCH_GBE_STAT(tx_timeout_count),
50 	PCH_GBE_STAT(tx_restart_count),
51 	PCH_GBE_STAT(intr_rx_dsc_empty_count),
52 	PCH_GBE_STAT(intr_rx_frame_err_count),
53 	PCH_GBE_STAT(intr_rx_fifo_err_count),
54 	PCH_GBE_STAT(intr_rx_dma_err_count),
55 	PCH_GBE_STAT(intr_tx_fifo_err_count),
56 	PCH_GBE_STAT(intr_tx_dma_err_count),
57 	PCH_GBE_STAT(intr_tcpip_err_count)
58 };
59 
60 #define PCH_GBE_QUEUE_STATS_LEN 0
61 #define PCH_GBE_GLOBAL_STATS_LEN	ARRAY_SIZE(pch_gbe_gstrings_stats)
62 #define PCH_GBE_STATS_LEN (PCH_GBE_GLOBAL_STATS_LEN + PCH_GBE_QUEUE_STATS_LEN)
63 
64 #define PCH_GBE_MAC_REGS_LEN    (sizeof(struct pch_gbe_regs) / 4)
65 #define PCH_GBE_REGS_LEN        (PCH_GBE_MAC_REGS_LEN + PCH_GBE_PHY_REGS_LEN)
66 /**
67  * pch_gbe_get_link_ksettings - Get device-specific settings
68  * @netdev: Network interface device structure
69  * @ecmd:   Ethtool command
70  * Returns:
71  *	0:			Successful.
72  *	Negative value:		Failed.
73  */
pch_gbe_get_link_ksettings(struct net_device * netdev,struct ethtool_link_ksettings * ecmd)74 static int pch_gbe_get_link_ksettings(struct net_device *netdev,
75 				      struct ethtool_link_ksettings *ecmd)
76 {
77 	struct pch_gbe_adapter *adapter = netdev_priv(netdev);
78 	u32 supported, advertising;
79 
80 	mii_ethtool_get_link_ksettings(&adapter->mii, ecmd);
81 
82 	ethtool_convert_link_mode_to_legacy_u32(&supported,
83 						ecmd->link_modes.supported);
84 	ethtool_convert_link_mode_to_legacy_u32(&advertising,
85 						ecmd->link_modes.advertising);
86 
87 	supported &= ~(SUPPORTED_TP | SUPPORTED_1000baseT_Half);
88 	advertising &= ~(ADVERTISED_TP | ADVERTISED_1000baseT_Half);
89 
90 	ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.supported,
91 						supported);
92 	ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.advertising,
93 						advertising);
94 
95 	if (!netif_carrier_ok(adapter->netdev))
96 		ecmd->base.speed = SPEED_UNKNOWN;
97 
98 	return 0;
99 }
100 
101 /**
102  * pch_gbe_set_link_ksettings - Set device-specific settings
103  * @netdev: Network interface device structure
104  * @ecmd:   Ethtool command
105  * Returns:
106  *	0:			Successful.
107  *	Negative value:		Failed.
108  */
pch_gbe_set_link_ksettings(struct net_device * netdev,const struct ethtool_link_ksettings * ecmd)109 static int pch_gbe_set_link_ksettings(struct net_device *netdev,
110 				      const struct ethtool_link_ksettings *ecmd)
111 {
112 	struct pch_gbe_adapter *adapter = netdev_priv(netdev);
113 	struct pch_gbe_hw *hw = &adapter->hw;
114 	struct ethtool_link_ksettings copy_ecmd;
115 	u32 speed = ecmd->base.speed;
116 	u32 advertising;
117 	int ret;
118 
119 	pch_gbe_phy_write_reg_miic(hw, MII_BMCR, BMCR_RESET);
120 
121 	memcpy(&copy_ecmd, ecmd, sizeof(*ecmd));
122 
123 	/* when set_settings() is called with a ethtool_cmd previously
124 	 * filled by get_settings() on a down link, speed is -1: */
125 	if (speed == UINT_MAX) {
126 		speed = SPEED_1000;
127 		copy_ecmd.base.speed = speed;
128 		copy_ecmd.base.duplex = DUPLEX_FULL;
129 	}
130 	ret = mii_ethtool_set_link_ksettings(&adapter->mii, &copy_ecmd);
131 	if (ret) {
132 		netdev_err(netdev, "Error: mii_ethtool_set_link_ksettings\n");
133 		return ret;
134 	}
135 	hw->mac.link_speed = speed;
136 	hw->mac.link_duplex = copy_ecmd.base.duplex;
137 	ethtool_convert_link_mode_to_legacy_u32(
138 		&advertising, copy_ecmd.link_modes.advertising);
139 	hw->phy.autoneg_advertised = advertising;
140 	hw->mac.autoneg = copy_ecmd.base.autoneg;
141 
142 	/* reset the link */
143 	if (netif_running(adapter->netdev)) {
144 		pch_gbe_down(adapter);
145 		ret = pch_gbe_up(adapter);
146 	} else {
147 		pch_gbe_reset(adapter);
148 	}
149 	return ret;
150 }
151 
152 /**
153  * pch_gbe_get_regs_len - Report the size of device registers
154  * @netdev: Network interface device structure
155  * Returns: the size of device registers.
156  */
pch_gbe_get_regs_len(struct net_device * netdev)157 static int pch_gbe_get_regs_len(struct net_device *netdev)
158 {
159 	return PCH_GBE_REGS_LEN * (int)sizeof(u32);
160 }
161 
162 /**
163  * pch_gbe_get_drvinfo - Report driver information
164  * @netdev:  Network interface device structure
165  * @drvinfo: Driver information structure
166  */
pch_gbe_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * drvinfo)167 static void pch_gbe_get_drvinfo(struct net_device *netdev,
168 				 struct ethtool_drvinfo *drvinfo)
169 {
170 	struct pch_gbe_adapter *adapter = netdev_priv(netdev);
171 
172 	strscpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
173 	strscpy(drvinfo->version, pch_driver_version, sizeof(drvinfo->version));
174 	strscpy(drvinfo->bus_info, pci_name(adapter->pdev),
175 		sizeof(drvinfo->bus_info));
176 }
177 
178 /**
179  * pch_gbe_get_regs - Get device registers
180  * @netdev: Network interface device structure
181  * @regs:   Ethtool register structure
182  * @p:      Buffer pointer of read device register date
183  */
pch_gbe_get_regs(struct net_device * netdev,struct ethtool_regs * regs,void * p)184 static void pch_gbe_get_regs(struct net_device *netdev,
185 				struct ethtool_regs *regs, void *p)
186 {
187 	struct pch_gbe_adapter *adapter = netdev_priv(netdev);
188 	struct pch_gbe_hw *hw = &adapter->hw;
189 	struct pci_dev *pdev = adapter->pdev;
190 	u32 *regs_buff = p;
191 	u16 i, tmp;
192 
193 	regs->version = 0x1000000 | (__u32)pdev->revision << 16 | pdev->device;
194 	for (i = 0; i < PCH_GBE_MAC_REGS_LEN; i++)
195 		*regs_buff++ = ioread32(&hw->reg->INT_ST + i);
196 	/* PHY register */
197 	for (i = 0; i < PCH_GBE_PHY_REGS_LEN; i++) {
198 		pch_gbe_phy_read_reg_miic(&adapter->hw, i, &tmp);
199 		*regs_buff++ = tmp;
200 	}
201 }
202 
203 /**
204  * pch_gbe_get_wol - Report whether Wake-on-Lan is enabled
205  * @netdev: Network interface device structure
206  * @wol:    Wake-on-Lan information
207  */
pch_gbe_get_wol(struct net_device * netdev,struct ethtool_wolinfo * wol)208 static void pch_gbe_get_wol(struct net_device *netdev,
209 				struct ethtool_wolinfo *wol)
210 {
211 	struct pch_gbe_adapter *adapter = netdev_priv(netdev);
212 
213 	wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
214 	wol->wolopts = 0;
215 
216 	if ((adapter->wake_up_evt & PCH_GBE_WLC_IND))
217 		wol->wolopts |= WAKE_UCAST;
218 	if ((adapter->wake_up_evt & PCH_GBE_WLC_MLT))
219 		wol->wolopts |= WAKE_MCAST;
220 	if ((adapter->wake_up_evt & PCH_GBE_WLC_BR))
221 		wol->wolopts |= WAKE_BCAST;
222 	if ((adapter->wake_up_evt & PCH_GBE_WLC_MP))
223 		wol->wolopts |= WAKE_MAGIC;
224 }
225 
226 /**
227  * pch_gbe_set_wol - Turn Wake-on-Lan on or off
228  * @netdev: Network interface device structure
229  * @wol:    Pointer of wake-on-Lan information straucture
230  * Returns:
231  *	0:			Successful.
232  *	Negative value:		Failed.
233  */
pch_gbe_set_wol(struct net_device * netdev,struct ethtool_wolinfo * wol)234 static int pch_gbe_set_wol(struct net_device *netdev,
235 				struct ethtool_wolinfo *wol)
236 {
237 	struct pch_gbe_adapter *adapter = netdev_priv(netdev);
238 
239 	if ((wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)))
240 		return -EOPNOTSUPP;
241 	/* these settings will always override what we currently have */
242 	adapter->wake_up_evt = 0;
243 
244 	if ((wol->wolopts & WAKE_UCAST))
245 		adapter->wake_up_evt |= PCH_GBE_WLC_IND;
246 	if ((wol->wolopts & WAKE_MCAST))
247 		adapter->wake_up_evt |= PCH_GBE_WLC_MLT;
248 	if ((wol->wolopts & WAKE_BCAST))
249 		adapter->wake_up_evt |= PCH_GBE_WLC_BR;
250 	if ((wol->wolopts & WAKE_MAGIC))
251 		adapter->wake_up_evt |= PCH_GBE_WLC_MP;
252 	return 0;
253 }
254 
255 /**
256  * pch_gbe_nway_reset - Restart autonegotiation
257  * @netdev: Network interface device structure
258  * Returns:
259  *	0:			Successful.
260  *	Negative value:		Failed.
261  */
pch_gbe_nway_reset(struct net_device * netdev)262 static int pch_gbe_nway_reset(struct net_device *netdev)
263 {
264 	struct pch_gbe_adapter *adapter = netdev_priv(netdev);
265 
266 	return mii_nway_restart(&adapter->mii);
267 }
268 
269 /**
270  * pch_gbe_get_ringparam - Report ring sizes
271  * @netdev:  Network interface device structure
272  * @ring:    Ring param structure
273  * @kernel_ring:	Ring external param structure
274  * @extack:	netlink handle
275  */
pch_gbe_get_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)276 static void pch_gbe_get_ringparam(struct net_device *netdev,
277 				  struct ethtool_ringparam *ring,
278 				  struct kernel_ethtool_ringparam *kernel_ring,
279 				  struct netlink_ext_ack *extack)
280 {
281 	struct pch_gbe_adapter *adapter = netdev_priv(netdev);
282 	struct pch_gbe_tx_ring *txdr = adapter->tx_ring;
283 	struct pch_gbe_rx_ring *rxdr = adapter->rx_ring;
284 
285 	ring->rx_max_pending = PCH_GBE_MAX_RXD;
286 	ring->tx_max_pending = PCH_GBE_MAX_TXD;
287 	ring->rx_pending = rxdr->count;
288 	ring->tx_pending = txdr->count;
289 }
290 
291 /**
292  * pch_gbe_set_ringparam - Set ring sizes
293  * @netdev:  Network interface device structure
294  * @ring:    Ring param structure
295  * @kernel_ring:	Ring external param structure
296  * @extack:	netlink handle
297  * Returns
298  *	0:			Successful.
299  *	Negative value:		Failed.
300  */
pch_gbe_set_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)301 static int pch_gbe_set_ringparam(struct net_device *netdev,
302 				 struct ethtool_ringparam *ring,
303 				 struct kernel_ethtool_ringparam *kernel_ring,
304 				 struct netlink_ext_ack *extack)
305 {
306 	struct pch_gbe_adapter *adapter = netdev_priv(netdev);
307 	struct pch_gbe_tx_ring *txdr, *tx_old;
308 	struct pch_gbe_rx_ring *rxdr, *rx_old;
309 	int tx_ring_size, rx_ring_size;
310 	int err = 0;
311 
312 	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
313 		return -EINVAL;
314 	tx_ring_size = (int)sizeof(struct pch_gbe_tx_ring);
315 	rx_ring_size = (int)sizeof(struct pch_gbe_rx_ring);
316 
317 	if ((netif_running(adapter->netdev)))
318 		pch_gbe_down(adapter);
319 	tx_old = adapter->tx_ring;
320 	rx_old = adapter->rx_ring;
321 
322 	txdr = kzalloc(tx_ring_size, GFP_KERNEL);
323 	if (!txdr) {
324 		err = -ENOMEM;
325 		goto err_alloc_tx;
326 	}
327 	rxdr = kzalloc(rx_ring_size, GFP_KERNEL);
328 	if (!rxdr) {
329 		err = -ENOMEM;
330 		goto err_alloc_rx;
331 	}
332 	adapter->tx_ring = txdr;
333 	adapter->rx_ring = rxdr;
334 
335 	rxdr->count =
336 		clamp_val(ring->rx_pending, PCH_GBE_MIN_RXD, PCH_GBE_MAX_RXD);
337 	rxdr->count = roundup(rxdr->count, PCH_GBE_RX_DESC_MULTIPLE);
338 
339 	txdr->count =
340 		clamp_val(ring->tx_pending, PCH_GBE_MIN_RXD, PCH_GBE_MAX_RXD);
341 	txdr->count = roundup(txdr->count, PCH_GBE_TX_DESC_MULTIPLE);
342 
343 	if ((netif_running(adapter->netdev))) {
344 		/* Try to get new resources before deleting old */
345 		err = pch_gbe_setup_rx_resources(adapter, adapter->rx_ring);
346 		if (err)
347 			goto err_setup_rx;
348 		err = pch_gbe_setup_tx_resources(adapter, adapter->tx_ring);
349 		if (err)
350 			goto err_setup_tx;
351 		pch_gbe_free_rx_resources(adapter, rx_old);
352 		pch_gbe_free_tx_resources(adapter, tx_old);
353 		kfree(tx_old);
354 		kfree(rx_old);
355 		adapter->rx_ring = rxdr;
356 		adapter->tx_ring = txdr;
357 		err = pch_gbe_up(adapter);
358 	}
359 	return err;
360 
361 err_setup_tx:
362 	pch_gbe_free_rx_resources(adapter, adapter->rx_ring);
363 err_setup_rx:
364 	adapter->rx_ring = rx_old;
365 	adapter->tx_ring = tx_old;
366 	kfree(rxdr);
367 err_alloc_rx:
368 	kfree(txdr);
369 err_alloc_tx:
370 	if (netif_running(adapter->netdev))
371 		pch_gbe_up(adapter);
372 	return err;
373 }
374 
375 /**
376  * pch_gbe_get_pauseparam - Report pause parameters
377  * @netdev:  Network interface device structure
378  * @pause:   Pause parameters structure
379  */
pch_gbe_get_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)380 static void pch_gbe_get_pauseparam(struct net_device *netdev,
381 				       struct ethtool_pauseparam *pause)
382 {
383 	struct pch_gbe_adapter *adapter = netdev_priv(netdev);
384 	struct pch_gbe_hw *hw = &adapter->hw;
385 
386 	pause->autoneg =
387 	    ((hw->mac.fc_autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE);
388 
389 	if (hw->mac.fc == PCH_GBE_FC_RX_PAUSE) {
390 		pause->rx_pause = 1;
391 	} else if (hw->mac.fc == PCH_GBE_FC_TX_PAUSE) {
392 		pause->tx_pause = 1;
393 	} else if (hw->mac.fc == PCH_GBE_FC_FULL) {
394 		pause->rx_pause = 1;
395 		pause->tx_pause = 1;
396 	}
397 }
398 
399 /**
400  * pch_gbe_set_pauseparam - Set pause parameters
401  * @netdev:  Network interface device structure
402  * @pause:   Pause parameters structure
403  * Returns:
404  *	0:			Successful.
405  *	Negative value:		Failed.
406  */
pch_gbe_set_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)407 static int pch_gbe_set_pauseparam(struct net_device *netdev,
408 				       struct ethtool_pauseparam *pause)
409 {
410 	struct pch_gbe_adapter *adapter = netdev_priv(netdev);
411 	struct pch_gbe_hw *hw = &adapter->hw;
412 	int ret = 0;
413 
414 	hw->mac.fc_autoneg = pause->autoneg;
415 	if ((pause->rx_pause) && (pause->tx_pause))
416 		hw->mac.fc = PCH_GBE_FC_FULL;
417 	else if ((pause->rx_pause) && (!pause->tx_pause))
418 		hw->mac.fc = PCH_GBE_FC_RX_PAUSE;
419 	else if ((!pause->rx_pause) && (pause->tx_pause))
420 		hw->mac.fc = PCH_GBE_FC_TX_PAUSE;
421 	else if ((!pause->rx_pause) && (!pause->tx_pause))
422 		hw->mac.fc = PCH_GBE_FC_NONE;
423 
424 	if (hw->mac.fc_autoneg == AUTONEG_ENABLE) {
425 		if ((netif_running(adapter->netdev))) {
426 			pch_gbe_down(adapter);
427 			ret = pch_gbe_up(adapter);
428 		} else {
429 			pch_gbe_reset(adapter);
430 		}
431 	} else {
432 		ret = pch_gbe_mac_force_mac_fc(hw);
433 	}
434 	return ret;
435 }
436 
437 /**
438  * pch_gbe_get_strings - Return a set of strings that describe the requested
439  *			 objects
440  * @netdev:    Network interface device structure
441  * @stringset: Select the stringset. [ETH_SS_TEST] [ETH_SS_STATS]
442  * @data:      Pointer of read string data.
443  */
pch_gbe_get_strings(struct net_device * netdev,u32 stringset,u8 * data)444 static void pch_gbe_get_strings(struct net_device *netdev, u32 stringset,
445 					u8 *data)
446 {
447 	u8 *p = data;
448 	int i;
449 
450 	switch (stringset) {
451 	case (u32) ETH_SS_STATS:
452 		for (i = 0; i < PCH_GBE_GLOBAL_STATS_LEN; i++) {
453 			memcpy(p, pch_gbe_gstrings_stats[i].string,
454 			       ETH_GSTRING_LEN);
455 			p += ETH_GSTRING_LEN;
456 		}
457 		break;
458 	}
459 }
460 
461 /**
462  * pch_gbe_get_ethtool_stats - Return statistics about the device
463  * @netdev: Network interface device structure
464  * @stats:  Ethtool statue structure
465  * @data:   Pointer of read status area
466  */
pch_gbe_get_ethtool_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)467 static void pch_gbe_get_ethtool_stats(struct net_device *netdev,
468 				  struct ethtool_stats *stats, u64 *data)
469 {
470 	struct pch_gbe_adapter *adapter = netdev_priv(netdev);
471 	int i;
472 	const struct pch_gbe_stats *gstats = pch_gbe_gstrings_stats;
473 	char *hw_stats = (char *)&adapter->stats;
474 
475 	pch_gbe_update_stats(adapter);
476 	for (i = 0; i < PCH_GBE_GLOBAL_STATS_LEN; i++) {
477 		char *p = hw_stats + gstats->offset;
478 		data[i] = gstats->size == sizeof(u64) ? *(u64 *)p:(*(u32 *)p);
479 		gstats++;
480 	}
481 }
482 
pch_gbe_get_sset_count(struct net_device * netdev,int sset)483 static int pch_gbe_get_sset_count(struct net_device *netdev, int sset)
484 {
485 	switch (sset) {
486 	case ETH_SS_STATS:
487 		return PCH_GBE_STATS_LEN;
488 	default:
489 		return -EOPNOTSUPP;
490 	}
491 }
492 
493 static const struct ethtool_ops pch_gbe_ethtool_ops = {
494 	.get_drvinfo = pch_gbe_get_drvinfo,
495 	.get_regs_len = pch_gbe_get_regs_len,
496 	.get_regs = pch_gbe_get_regs,
497 	.get_wol = pch_gbe_get_wol,
498 	.set_wol = pch_gbe_set_wol,
499 	.nway_reset = pch_gbe_nway_reset,
500 	.get_link = ethtool_op_get_link,
501 	.get_ringparam = pch_gbe_get_ringparam,
502 	.set_ringparam = pch_gbe_set_ringparam,
503 	.get_pauseparam = pch_gbe_get_pauseparam,
504 	.set_pauseparam = pch_gbe_set_pauseparam,
505 	.get_strings = pch_gbe_get_strings,
506 	.get_ethtool_stats = pch_gbe_get_ethtool_stats,
507 	.get_sset_count = pch_gbe_get_sset_count,
508 	.get_link_ksettings = pch_gbe_get_link_ksettings,
509 	.set_link_ksettings = pch_gbe_set_link_ksettings,
510 };
511 
pch_gbe_set_ethtool_ops(struct net_device * netdev)512 void pch_gbe_set_ethtool_ops(struct net_device *netdev)
513 {
514 	netdev->ethtool_ops = &pch_gbe_ethtool_ops;
515 }
516