1/*
2 * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
3 * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
4 * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
5 *
6 * Derived from Intel e1000 driver
7 * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
12 * any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program; if not, write to the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22 */
23
24#include <linux/types.h>
25#include <linux/pci.h>
26#include <linux/ethtool.h>
27#include <linux/netdevice.h>
28#include <linux/mii.h>
29#include <asm/uaccess.h>
30
31#include "atl1.h"
32
33struct atl1_stats {
34	char stat_string[ETH_GSTRING_LEN];
35	int sizeof_stat;
36	int stat_offset;
37};
38
39#define ATL1_STAT(m) sizeof(((struct atl1_adapter *)0)->m), \
40	offsetof(struct atl1_adapter, m)
41
42static struct atl1_stats atl1_gstrings_stats[] = {
43	{"rx_packets", ATL1_STAT(soft_stats.rx_packets)},
44	{"tx_packets", ATL1_STAT(soft_stats.tx_packets)},
45	{"rx_bytes", ATL1_STAT(soft_stats.rx_bytes)},
46	{"tx_bytes", ATL1_STAT(soft_stats.tx_bytes)},
47	{"rx_errors", ATL1_STAT(soft_stats.rx_errors)},
48	{"tx_errors", ATL1_STAT(soft_stats.tx_errors)},
49	{"rx_dropped", ATL1_STAT(net_stats.rx_dropped)},
50	{"tx_dropped", ATL1_STAT(net_stats.tx_dropped)},
51	{"multicast", ATL1_STAT(soft_stats.multicast)},
52	{"collisions", ATL1_STAT(soft_stats.collisions)},
53	{"rx_length_errors", ATL1_STAT(soft_stats.rx_length_errors)},
54	{"rx_over_errors", ATL1_STAT(soft_stats.rx_missed_errors)},
55	{"rx_crc_errors", ATL1_STAT(soft_stats.rx_crc_errors)},
56	{"rx_frame_errors", ATL1_STAT(soft_stats.rx_frame_errors)},
57	{"rx_fifo_errors", ATL1_STAT(soft_stats.rx_fifo_errors)},
58	{"rx_missed_errors", ATL1_STAT(soft_stats.rx_missed_errors)},
59	{"tx_aborted_errors", ATL1_STAT(soft_stats.tx_aborted_errors)},
60	{"tx_carrier_errors", ATL1_STAT(soft_stats.tx_carrier_errors)},
61	{"tx_fifo_errors", ATL1_STAT(soft_stats.tx_fifo_errors)},
62	{"tx_window_errors", ATL1_STAT(soft_stats.tx_window_errors)},
63	{"tx_abort_exce_coll", ATL1_STAT(soft_stats.excecol)},
64	{"tx_abort_late_coll", ATL1_STAT(soft_stats.latecol)},
65	{"tx_deferred_ok", ATL1_STAT(soft_stats.deffer)},
66	{"tx_single_coll_ok", ATL1_STAT(soft_stats.scc)},
67	{"tx_multi_coll_ok", ATL1_STAT(soft_stats.mcc)},
68	{"tx_underun", ATL1_STAT(soft_stats.tx_underun)},
69	{"tx_trunc", ATL1_STAT(soft_stats.tx_trunc)},
70	{"tx_pause", ATL1_STAT(soft_stats.tx_pause)},
71	{"rx_pause", ATL1_STAT(soft_stats.rx_pause)},
72	{"rx_rrd_ov", ATL1_STAT(soft_stats.rx_rrd_ov)},
73	{"rx_trunc", ATL1_STAT(soft_stats.rx_trunc)}
74};
75
76static void atl1_get_ethtool_stats(struct net_device *netdev,
77				struct ethtool_stats *stats, u64 *data)
78{
79	struct atl1_adapter *adapter = netdev_priv(netdev);
80	int i;
81	char *p;
82
83	for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) {
84		p = (char *)adapter+atl1_gstrings_stats[i].stat_offset;
85		data[i] = (atl1_gstrings_stats[i].sizeof_stat ==
86			sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
87	}
88
89}
90
91static int atl1_get_stats_count(struct net_device *netdev)
92{
93	return ARRAY_SIZE(atl1_gstrings_stats);
94}
95
96static int atl1_get_settings(struct net_device *netdev,
97				struct ethtool_cmd *ecmd)
98{
99	struct atl1_adapter *adapter = netdev_priv(netdev);
100	struct atl1_hw *hw = &adapter->hw;
101
102	ecmd->supported = (SUPPORTED_10baseT_Half |
103			   SUPPORTED_10baseT_Full |
104			   SUPPORTED_100baseT_Half |
105			   SUPPORTED_100baseT_Full |
106			   SUPPORTED_1000baseT_Full |
107			   SUPPORTED_Autoneg | SUPPORTED_TP);
108	ecmd->advertising = ADVERTISED_TP;
109	if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
110	    hw->media_type == MEDIA_TYPE_1000M_FULL) {
111		ecmd->advertising |= ADVERTISED_Autoneg;
112		if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR) {
113			ecmd->advertising |= ADVERTISED_Autoneg;
114			ecmd->advertising |=
115			    (ADVERTISED_10baseT_Half |
116			     ADVERTISED_10baseT_Full |
117			     ADVERTISED_100baseT_Half |
118			     ADVERTISED_100baseT_Full |
119			     ADVERTISED_1000baseT_Full);
120		}
121		else
122			ecmd->advertising |= (ADVERTISED_1000baseT_Full);
123	}
124	ecmd->port = PORT_TP;
125	ecmd->phy_address = 0;
126	ecmd->transceiver = XCVR_INTERNAL;
127
128	if (netif_carrier_ok(adapter->netdev)) {
129		u16 link_speed, link_duplex;
130		atl1_get_speed_and_duplex(hw, &link_speed, &link_duplex);
131		ecmd->speed = link_speed;
132		if (link_duplex == FULL_DUPLEX)
133			ecmd->duplex = DUPLEX_FULL;
134		else
135			ecmd->duplex = DUPLEX_HALF;
136	} else {
137		ecmd->speed = -1;
138		ecmd->duplex = -1;
139	}
140	if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
141	    hw->media_type == MEDIA_TYPE_1000M_FULL)
142		ecmd->autoneg = AUTONEG_ENABLE;
143	else
144		ecmd->autoneg = AUTONEG_DISABLE;
145
146	return 0;
147}
148
149static int atl1_set_settings(struct net_device *netdev,
150				struct ethtool_cmd *ecmd)
151{
152	struct atl1_adapter *adapter = netdev_priv(netdev);
153	struct atl1_hw *hw = &adapter->hw;
154	u16 phy_data;
155	int ret_val = 0;
156	u16 old_media_type = hw->media_type;
157
158	if (netif_running(adapter->netdev)) {
159		dev_dbg(&adapter->pdev->dev, "ethtool shutting down adapter\n");
160		atl1_down(adapter);
161	}
162
163	if (ecmd->autoneg == AUTONEG_ENABLE)
164		hw->media_type = MEDIA_TYPE_AUTO_SENSOR;
165	else {
166		if (ecmd->speed == SPEED_1000) {
167			if (ecmd->duplex != DUPLEX_FULL) {
168				dev_warn(&adapter->pdev->dev,
169					"can't force to 1000M half duplex\n");
170				ret_val = -EINVAL;
171				goto exit_sset;
172			}
173			hw->media_type = MEDIA_TYPE_1000M_FULL;
174		} else if (ecmd->speed == SPEED_100) {
175			if (ecmd->duplex == DUPLEX_FULL) {
176				hw->media_type = MEDIA_TYPE_100M_FULL;
177			} else
178				hw->media_type = MEDIA_TYPE_100M_HALF;
179		} else {
180			if (ecmd->duplex == DUPLEX_FULL)
181				hw->media_type = MEDIA_TYPE_10M_FULL;
182			else
183				hw->media_type = MEDIA_TYPE_10M_HALF;
184		}
185	}
186	switch (hw->media_type) {
187	case MEDIA_TYPE_AUTO_SENSOR:
188		ecmd->advertising =
189		    ADVERTISED_10baseT_Half |
190		    ADVERTISED_10baseT_Full |
191		    ADVERTISED_100baseT_Half |
192		    ADVERTISED_100baseT_Full |
193		    ADVERTISED_1000baseT_Full |
194		    ADVERTISED_Autoneg | ADVERTISED_TP;
195		break;
196	case MEDIA_TYPE_1000M_FULL:
197		ecmd->advertising =
198		    ADVERTISED_1000baseT_Full |
199		    ADVERTISED_Autoneg | ADVERTISED_TP;
200		break;
201	default:
202		ecmd->advertising = 0;
203		break;
204	}
205	if (atl1_phy_setup_autoneg_adv(hw)) {
206		ret_val = -EINVAL;
207		dev_warn(&adapter->pdev->dev,
208			"invalid ethtool speed/duplex setting\n");
209		goto exit_sset;
210	}
211	if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
212	    hw->media_type == MEDIA_TYPE_1000M_FULL)
213		phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN;
214	else {
215		switch (hw->media_type) {
216		case MEDIA_TYPE_100M_FULL:
217			phy_data =
218			    MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 |
219			    MII_CR_RESET;
220			break;
221		case MEDIA_TYPE_100M_HALF:
222			phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
223			break;
224		case MEDIA_TYPE_10M_FULL:
225			phy_data =
226			    MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET;
227			break;
228		default:	/* MEDIA_TYPE_10M_HALF: */
229			phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
230			break;
231		}
232	}
233	atl1_write_phy_reg(hw, MII_BMCR, phy_data);
234exit_sset:
235	if (ret_val)
236		hw->media_type = old_media_type;
237
238	if (netif_running(adapter->netdev)) {
239		dev_dbg(&adapter->pdev->dev, "ethtool starting adapter\n");
240		atl1_up(adapter);
241	} else if (!ret_val) {
242		dev_dbg(&adapter->pdev->dev, "ethtool resetting adapter\n");
243		atl1_reset(adapter);
244	}
245	return ret_val;
246}
247
248static void atl1_get_drvinfo(struct net_device *netdev,
249				struct ethtool_drvinfo *drvinfo)
250{
251	struct atl1_adapter *adapter = netdev_priv(netdev);
252
253	strncpy(drvinfo->driver, atl1_driver_name, sizeof(drvinfo->driver));
254	strncpy(drvinfo->version, atl1_driver_version,
255		sizeof(drvinfo->version));
256	strncpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
257	strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
258		sizeof(drvinfo->bus_info));
259	drvinfo->eedump_len = ATL1_EEDUMP_LEN;
260}
261
262static void atl1_get_wol(struct net_device *netdev,
263			    struct ethtool_wolinfo *wol)
264{
265	struct atl1_adapter *adapter = netdev_priv(netdev);
266
267	wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
268	wol->wolopts = 0;
269	if (adapter->wol & ATL1_WUFC_EX)
270		wol->wolopts |= WAKE_UCAST;
271	if (adapter->wol & ATL1_WUFC_MC)
272		wol->wolopts |= WAKE_MCAST;
273	if (adapter->wol & ATL1_WUFC_BC)
274		wol->wolopts |= WAKE_BCAST;
275	if (adapter->wol & ATL1_WUFC_MAG)
276		wol->wolopts |= WAKE_MAGIC;
277	return;
278}
279
280static int atl1_set_wol(struct net_device *netdev,
281			struct ethtool_wolinfo *wol)
282{
283	struct atl1_adapter *adapter = netdev_priv(netdev);
284
285	if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
286		return -EOPNOTSUPP;
287	adapter->wol = 0;
288	if (wol->wolopts & WAKE_UCAST)
289		adapter->wol |= ATL1_WUFC_EX;
290	if (wol->wolopts & WAKE_MCAST)
291		adapter->wol |= ATL1_WUFC_MC;
292	if (wol->wolopts & WAKE_BCAST)
293		adapter->wol |= ATL1_WUFC_BC;
294	if (wol->wolopts & WAKE_MAGIC)
295		adapter->wol |= ATL1_WUFC_MAG;
296	return 0;
297}
298
299static void atl1_get_ringparam(struct net_device *netdev,
300			    struct ethtool_ringparam *ring)
301{
302	struct atl1_adapter *adapter = netdev_priv(netdev);
303	struct atl1_tpd_ring *txdr = &adapter->tpd_ring;
304	struct atl1_rfd_ring *rxdr = &adapter->rfd_ring;
305
306	ring->rx_max_pending = ATL1_MAX_RFD;
307	ring->tx_max_pending = ATL1_MAX_TPD;
308	ring->rx_mini_max_pending = 0;
309	ring->rx_jumbo_max_pending = 0;
310	ring->rx_pending = rxdr->count;
311	ring->tx_pending = txdr->count;
312	ring->rx_mini_pending = 0;
313	ring->rx_jumbo_pending = 0;
314}
315
316static int atl1_set_ringparam(struct net_device *netdev,
317				struct ethtool_ringparam *ring)
318{
319	struct atl1_adapter *adapter = netdev_priv(netdev);
320	struct atl1_tpd_ring *tpdr = &adapter->tpd_ring;
321	struct atl1_rrd_ring *rrdr = &adapter->rrd_ring;
322	struct atl1_rfd_ring *rfdr = &adapter->rfd_ring;
323
324	struct atl1_tpd_ring tpd_old, tpd_new;
325	struct atl1_rfd_ring rfd_old, rfd_new;
326	struct atl1_rrd_ring rrd_old, rrd_new;
327	struct atl1_ring_header rhdr_old, rhdr_new;
328	int err;
329
330	tpd_old = adapter->tpd_ring;
331	rfd_old = adapter->rfd_ring;
332	rrd_old = adapter->rrd_ring;
333	rhdr_old = adapter->ring_header;
334
335	if (netif_running(adapter->netdev))
336		atl1_down(adapter);
337
338	rfdr->count = (u16) max(ring->rx_pending, (u32) ATL1_MIN_RFD);
339	rfdr->count = rfdr->count > ATL1_MAX_RFD ? ATL1_MAX_RFD :
340			rfdr->count;
341	rfdr->count = (rfdr->count + 3) & ~3;
342	rrdr->count = rfdr->count;
343
344	tpdr->count = (u16) max(ring->tx_pending, (u32) ATL1_MIN_TPD);
345	tpdr->count = tpdr->count > ATL1_MAX_TPD ? ATL1_MAX_TPD :
346			tpdr->count;
347	tpdr->count = (tpdr->count + 3) & ~3;
348
349	if (netif_running(adapter->netdev)) {
350		/* try to get new resources before deleting old */
351		err = atl1_setup_ring_resources(adapter);
352		if (err)
353			goto err_setup_ring;
354
355		/*
356		 * save the new, restore the old in order to free it,
357		 * then restore the new back again
358		 */
359
360		rfd_new = adapter->rfd_ring;
361		rrd_new = adapter->rrd_ring;
362		tpd_new = adapter->tpd_ring;
363		rhdr_new = adapter->ring_header;
364		adapter->rfd_ring = rfd_old;
365		adapter->rrd_ring = rrd_old;
366		adapter->tpd_ring = tpd_old;
367		adapter->ring_header = rhdr_old;
368		atl1_free_ring_resources(adapter);
369		adapter->rfd_ring = rfd_new;
370		adapter->rrd_ring = rrd_new;
371		adapter->tpd_ring = tpd_new;
372		adapter->ring_header = rhdr_new;
373
374		err = atl1_up(adapter);
375		if (err)
376			return err;
377	}
378	return 0;
379
380err_setup_ring:
381	adapter->rfd_ring = rfd_old;
382	adapter->rrd_ring = rrd_old;
383	adapter->tpd_ring = tpd_old;
384	adapter->ring_header = rhdr_old;
385	atl1_up(adapter);
386	return err;
387}
388
389static void atl1_get_pauseparam(struct net_device *netdev,
390			     struct ethtool_pauseparam *epause)
391{
392	struct atl1_adapter *adapter = netdev_priv(netdev);
393	struct atl1_hw *hw = &adapter->hw;
394
395	if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
396	    hw->media_type == MEDIA_TYPE_1000M_FULL) {
397		epause->autoneg = AUTONEG_ENABLE;
398	} else {
399		epause->autoneg = AUTONEG_DISABLE;
400	}
401	epause->rx_pause = 1;
402	epause->tx_pause = 1;
403}
404
405static int atl1_set_pauseparam(struct net_device *netdev,
406			     struct ethtool_pauseparam *epause)
407{
408	struct atl1_adapter *adapter = netdev_priv(netdev);
409	struct atl1_hw *hw = &adapter->hw;
410
411	if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
412	    hw->media_type == MEDIA_TYPE_1000M_FULL) {
413		epause->autoneg = AUTONEG_ENABLE;
414	} else {
415		epause->autoneg = AUTONEG_DISABLE;
416	}
417
418	epause->rx_pause = 1;
419	epause->tx_pause = 1;
420
421	return 0;
422}
423
424static u32 atl1_get_rx_csum(struct net_device *netdev)
425{
426	return 1;
427}
428
429static void atl1_get_strings(struct net_device *netdev, u32 stringset,
430				u8 *data)
431{
432	u8 *p = data;
433	int i;
434
435	switch (stringset) {
436	case ETH_SS_STATS:
437		for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) {
438			memcpy(p, atl1_gstrings_stats[i].stat_string,
439				ETH_GSTRING_LEN);
440			p += ETH_GSTRING_LEN;
441		}
442		break;
443	}
444}
445
446static int atl1_nway_reset(struct net_device *netdev)
447{
448	struct atl1_adapter *adapter = netdev_priv(netdev);
449	struct atl1_hw *hw = &adapter->hw;
450
451	if (netif_running(netdev)) {
452		u16 phy_data;
453		atl1_down(adapter);
454
455		if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
456			hw->media_type == MEDIA_TYPE_1000M_FULL) {
457			phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN;
458		} else {
459			switch (hw->media_type) {
460			case MEDIA_TYPE_100M_FULL:
461				phy_data = MII_CR_FULL_DUPLEX |
462					MII_CR_SPEED_100 | MII_CR_RESET;
463				break;
464			case MEDIA_TYPE_100M_HALF:
465				phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
466				break;
467			case MEDIA_TYPE_10M_FULL:
468				phy_data = MII_CR_FULL_DUPLEX |
469					MII_CR_SPEED_10 | MII_CR_RESET;
470				break;
471			default:  /* MEDIA_TYPE_10M_HALF */
472				phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
473			}
474		}
475		atl1_write_phy_reg(hw, MII_BMCR, phy_data);
476		atl1_up(adapter);
477	}
478	return 0;
479}
480
481const struct ethtool_ops atl1_ethtool_ops = {
482	.get_settings		= atl1_get_settings,
483	.set_settings		= atl1_set_settings,
484	.get_drvinfo		= atl1_get_drvinfo,
485	.get_wol		= atl1_get_wol,
486	.set_wol		= atl1_set_wol,
487	.get_ringparam		= atl1_get_ringparam,
488	.set_ringparam		= atl1_set_ringparam,
489	.get_pauseparam		= atl1_get_pauseparam,
490	.set_pauseparam 	= atl1_set_pauseparam,
491	.get_rx_csum		= atl1_get_rx_csum,
492	.get_tx_csum		= ethtool_op_get_tx_csum,
493	.set_tx_csum		= ethtool_op_set_tx_hw_csum,
494	.get_link		= ethtool_op_get_link,
495	.get_sg			= ethtool_op_get_sg,
496	.set_sg			= ethtool_op_set_sg,
497	.get_strings		= atl1_get_strings,
498	.nway_reset		= atl1_nway_reset,
499	.get_ethtool_stats	= atl1_get_ethtool_stats,
500	.get_stats_count	= atl1_get_stats_count,
501	.get_tso		= ethtool_op_get_tso,
502	.set_tso		= ethtool_op_set_tso,
503};
504