ixgb_ethtool.c 21.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/*******************************************************************************

3 4 5 6 7 8 9 10 11 12
  Intel PRO/10GbE Linux driver
  Copyright(c) 1999 - 2006 Intel Corporation.

  This program is free software; you can redistribute it and/or modify it
  under the terms and conditions of the GNU General Public License,
  version 2, as published by the Free Software Foundation.

  This program is distributed in the hope it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
L
Linus Torvalds 已提交
13
  more details.
14

L
Linus Torvalds 已提交
15
  You should have received a copy of the GNU General Public License along with
16 17 18 19 20 21
  this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.

  The full GNU General Public License is included in this distribution in
  the file called "COPYING".

L
Linus Torvalds 已提交
22 23
  Contact Information:
  Linux NICS <linux.nics@intel.com>
24
  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
L
Linus Torvalds 已提交
25 26 27 28 29 30 31 32 33 34
  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497

*******************************************************************************/

/* ethtool support for ixgb */

#include "ixgb.h"

#include <asm/uaccess.h>

A
Auke Kok 已提交
35 36
#define IXGB_ALL_RAR_ENTRIES 16

L
Linus Torvalds 已提交
37 38 39 40 41 42
struct ixgb_stats {
	char stat_string[ETH_GSTRING_LEN];
	int sizeof_stat;
	int stat_offset;
};

J
Julia Lawall 已提交
43
#define IXGB_STAT(m) FIELD_SIZEOF(struct ixgb_adapter, m), \
L
Linus Torvalds 已提交
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
		      offsetof(struct ixgb_adapter, m)
static struct ixgb_stats ixgb_gstrings_stats[] = {
	{"rx_packets", IXGB_STAT(net_stats.rx_packets)},
	{"tx_packets", IXGB_STAT(net_stats.tx_packets)},
	{"rx_bytes", IXGB_STAT(net_stats.rx_bytes)},
	{"tx_bytes", IXGB_STAT(net_stats.tx_bytes)},
	{"rx_errors", IXGB_STAT(net_stats.rx_errors)},
	{"tx_errors", IXGB_STAT(net_stats.tx_errors)},
	{"rx_dropped", IXGB_STAT(net_stats.rx_dropped)},
	{"tx_dropped", IXGB_STAT(net_stats.tx_dropped)},
	{"multicast", IXGB_STAT(net_stats.multicast)},
	{"collisions", IXGB_STAT(net_stats.collisions)},

/*	{ "rx_length_errors", IXGB_STAT(net_stats.rx_length_errors) },	*/
	{"rx_over_errors", IXGB_STAT(net_stats.rx_over_errors)},
	{"rx_crc_errors", IXGB_STAT(net_stats.rx_crc_errors)},
	{"rx_frame_errors", IXGB_STAT(net_stats.rx_frame_errors)},
61
	{"rx_no_buffer_count", IXGB_STAT(stats.rnbc)},
L
Linus Torvalds 已提交
62 63 64 65 66 67 68 69
	{"rx_fifo_errors", IXGB_STAT(net_stats.rx_fifo_errors)},
	{"rx_missed_errors", IXGB_STAT(net_stats.rx_missed_errors)},
	{"tx_aborted_errors", IXGB_STAT(net_stats.tx_aborted_errors)},
	{"tx_carrier_errors", IXGB_STAT(net_stats.tx_carrier_errors)},
	{"tx_fifo_errors", IXGB_STAT(net_stats.tx_fifo_errors)},
	{"tx_heartbeat_errors", IXGB_STAT(net_stats.tx_heartbeat_errors)},
	{"tx_window_errors", IXGB_STAT(net_stats.tx_window_errors)},
	{"tx_deferred_ok", IXGB_STAT(stats.dc)},
A
Auke Kok 已提交
70
	{"tx_timeout_count", IXGB_STAT(tx_timeout_count) },
71
	{"tx_restart_queue", IXGB_STAT(restart_queue) },
L
Linus Torvalds 已提交
72 73 74 75 76 77 78 79 80 81 82 83 84 85
	{"rx_long_length_errors", IXGB_STAT(stats.roc)},
	{"rx_short_length_errors", IXGB_STAT(stats.ruc)},
	{"tx_tcp_seg_good", IXGB_STAT(stats.tsctc)},
	{"tx_tcp_seg_failed", IXGB_STAT(stats.tsctfc)},
	{"rx_flow_control_xon", IXGB_STAT(stats.xonrxc)},
	{"rx_flow_control_xoff", IXGB_STAT(stats.xoffrxc)},
	{"tx_flow_control_xon", IXGB_STAT(stats.xontxc)},
	{"tx_flow_control_xoff", IXGB_STAT(stats.xofftxc)},
	{"rx_csum_offload_good", IXGB_STAT(hw_csum_rx_good)},
	{"rx_csum_offload_errors", IXGB_STAT(hw_csum_rx_error)},
	{"tx_csum_offload_good", IXGB_STAT(hw_csum_tx_good)},
	{"tx_csum_offload_errors", IXGB_STAT(hw_csum_tx_error)}
};

86
#define IXGB_STATS_LEN	ARRAY_SIZE(ixgb_gstrings_stats)
L
Linus Torvalds 已提交
87 88 89 90

static int
ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
91
	struct ixgb_adapter *adapter = netdev_priv(netdev);
L
Linus Torvalds 已提交
92 93

	ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
94
	ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
L
Linus Torvalds 已提交
95 96 97
	ecmd->port = PORT_FIBRE;
	ecmd->transceiver = XCVR_EXTERNAL;

98
	if (netif_carrier_ok(adapter->netdev)) {
L
Linus Torvalds 已提交
99 100 101 102 103 104 105 106 107 108 109
		ecmd->speed = SPEED_10000;
		ecmd->duplex = DUPLEX_FULL;
	} else {
		ecmd->speed = -1;
		ecmd->duplex = -1;
	}

	ecmd->autoneg = AUTONEG_DISABLE;
	return 0;
}

110 111 112 113 114 115 116 117 118 119
static void ixgb_set_speed_duplex(struct net_device *netdev)
{
	struct ixgb_adapter *adapter = netdev_priv(netdev);
	/* be optimistic about our link, since we were up before */
	adapter->link_speed = 10000;
	adapter->link_duplex = FULL_DUPLEX;
	netif_carrier_on(netdev);
	netif_wake_queue(netdev);
}

L
Linus Torvalds 已提交
120 121 122
static int
ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
123
	struct ixgb_adapter *adapter = netdev_priv(netdev);
L
Linus Torvalds 已提交
124

125
	if (ecmd->autoneg == AUTONEG_ENABLE ||
L
Linus Torvalds 已提交
126 127
	   ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)
		return -EINVAL;
J
Jesse Brandeburg 已提交
128

129
	if (netif_running(adapter->netdev)) {
J
Joe Perches 已提交
130
		ixgb_down(adapter, true);
L
Linus Torvalds 已提交
131 132
		ixgb_reset(adapter);
		ixgb_up(adapter);
133
		ixgb_set_speed_duplex(netdev);
L
Linus Torvalds 已提交
134 135 136 137 138 139 140 141 142 143
	} else
		ixgb_reset(adapter);

	return 0;
}

static void
ixgb_get_pauseparam(struct net_device *netdev,
			 struct ethtool_pauseparam *pause)
{
144
	struct ixgb_adapter *adapter = netdev_priv(netdev);
L
Linus Torvalds 已提交
145
	struct ixgb_hw *hw = &adapter->hw;
J
Jesse Brandeburg 已提交
146

L
Linus Torvalds 已提交
147
	pause->autoneg = AUTONEG_DISABLE;
J
Jesse Brandeburg 已提交
148

149
	if (hw->fc.type == ixgb_fc_rx_pause)
L
Linus Torvalds 已提交
150
		pause->rx_pause = 1;
151
	else if (hw->fc.type == ixgb_fc_tx_pause)
L
Linus Torvalds 已提交
152
		pause->tx_pause = 1;
153
	else if (hw->fc.type == ixgb_fc_full) {
L
Linus Torvalds 已提交
154 155 156 157 158 159 160 161 162
		pause->rx_pause = 1;
		pause->tx_pause = 1;
	}
}

static int
ixgb_set_pauseparam(struct net_device *netdev,
			 struct ethtool_pauseparam *pause)
{
163
	struct ixgb_adapter *adapter = netdev_priv(netdev);
L
Linus Torvalds 已提交
164
	struct ixgb_hw *hw = &adapter->hw;
J
Jesse Brandeburg 已提交
165

166
	if (pause->autoneg == AUTONEG_ENABLE)
L
Linus Torvalds 已提交
167 168
		return -EINVAL;

169
	if (pause->rx_pause && pause->tx_pause)
L
Linus Torvalds 已提交
170
		hw->fc.type = ixgb_fc_full;
171
	else if (pause->rx_pause && !pause->tx_pause)
L
Linus Torvalds 已提交
172
		hw->fc.type = ixgb_fc_rx_pause;
173
	else if (!pause->rx_pause && pause->tx_pause)
L
Linus Torvalds 已提交
174
		hw->fc.type = ixgb_fc_tx_pause;
175
	else if (!pause->rx_pause && !pause->tx_pause)
L
Linus Torvalds 已提交
176 177
		hw->fc.type = ixgb_fc_none;

178
	if (netif_running(adapter->netdev)) {
J
Joe Perches 已提交
179
		ixgb_down(adapter, true);
L
Linus Torvalds 已提交
180
		ixgb_up(adapter);
181
		ixgb_set_speed_duplex(netdev);
L
Linus Torvalds 已提交
182 183
	} else
		ixgb_reset(adapter);
J
Jesse Brandeburg 已提交
184

L
Linus Torvalds 已提交
185 186 187
	return 0;
}

188
static u32
L
Linus Torvalds 已提交
189 190
ixgb_get_rx_csum(struct net_device *netdev)
{
191 192
	struct ixgb_adapter *adapter = netdev_priv(netdev);

L
Linus Torvalds 已提交
193 194 195 196
	return adapter->rx_csum;
}

static int
197
ixgb_set_rx_csum(struct net_device *netdev, u32 data)
L
Linus Torvalds 已提交
198
{
199 200
	struct ixgb_adapter *adapter = netdev_priv(netdev);

L
Linus Torvalds 已提交
201 202
	adapter->rx_csum = data;

203
	if (netif_running(netdev)) {
J
Joe Perches 已提交
204
		ixgb_down(adapter, true);
L
Linus Torvalds 已提交
205
		ixgb_up(adapter);
206
		ixgb_set_speed_duplex(netdev);
L
Linus Torvalds 已提交
207 208 209 210
	} else
		ixgb_reset(adapter);
	return 0;
}
J
Jesse Brandeburg 已提交
211

212
static u32
L
Linus Torvalds 已提交
213 214 215 216 217 218
ixgb_get_tx_csum(struct net_device *netdev)
{
	return (netdev->features & NETIF_F_HW_CSUM) != 0;
}

static int
219
ixgb_set_tx_csum(struct net_device *netdev, u32 data)
L
Linus Torvalds 已提交
220 221 222 223 224 225 226 227 228 229
{
	if (data)
		netdev->features |= NETIF_F_HW_CSUM;
	else
		netdev->features &= ~NETIF_F_HW_CSUM;

	return 0;
}

static int
230
ixgb_set_tso(struct net_device *netdev, u32 data)
L
Linus Torvalds 已提交
231
{
232
	if (data)
L
Linus Torvalds 已提交
233 234 235 236
		netdev->features |= NETIF_F_TSO;
	else
		netdev->features &= ~NETIF_F_TSO;
	return 0;
J
Jesse Brandeburg 已提交
237
}
L
Linus Torvalds 已提交
238

239
static u32
240 241
ixgb_get_msglevel(struct net_device *netdev)
{
242
	struct ixgb_adapter *adapter = netdev_priv(netdev);
243 244 245 246
	return adapter->msg_enable;
}

static void
247
ixgb_set_msglevel(struct net_device *netdev, u32 data)
248
{
249
	struct ixgb_adapter *adapter = netdev_priv(netdev);
250 251
	adapter->msg_enable = data;
}
L
Linus Torvalds 已提交
252 253
#define IXGB_GET_STAT(_A_, _R_) _A_->stats._R_

J
Jesse Brandeburg 已提交
254
static int
L
Linus Torvalds 已提交
255 256
ixgb_get_regs_len(struct net_device *netdev)
{
257
#define IXGB_REG_DUMP_LEN  136*sizeof(u32)
L
Linus Torvalds 已提交
258 259 260 261 262 263 264
	return IXGB_REG_DUMP_LEN;
}

static void
ixgb_get_regs(struct net_device *netdev,
		   struct ethtool_regs *regs, void *p)
{
265
	struct ixgb_adapter *adapter = netdev_priv(netdev);
L
Linus Torvalds 已提交
266
	struct ixgb_hw *hw = &adapter->hw;
267 268 269
	u32 *reg = p;
	u32 *reg_start = reg;
	u8 i;
L
Linus Torvalds 已提交
270

271
	/* the 1 (one) below indicates an attempt at versioning, if the
272 273
	 * interface in ethtool or the driver changes, this 1 should be
	 * incremented */
274
	regs->version = (1<<24) | hw->revision_id << 16 | hw->device_id;
L
Linus Torvalds 已提交
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302

	/* General Registers */
	*reg++ = IXGB_READ_REG(hw, CTRL0);	/*   0 */
	*reg++ = IXGB_READ_REG(hw, CTRL1);	/*   1 */
	*reg++ = IXGB_READ_REG(hw, STATUS);	/*   2 */
	*reg++ = IXGB_READ_REG(hw, EECD);	/*   3 */
	*reg++ = IXGB_READ_REG(hw, MFS);	/*   4 */

	/* Interrupt */
	*reg++ = IXGB_READ_REG(hw, ICR);	/*   5 */
	*reg++ = IXGB_READ_REG(hw, ICS);	/*   6 */
	*reg++ = IXGB_READ_REG(hw, IMS);	/*   7 */
	*reg++ = IXGB_READ_REG(hw, IMC);	/*   8 */

	/* Receive */
	*reg++ = IXGB_READ_REG(hw, RCTL);	/*   9 */
	*reg++ = IXGB_READ_REG(hw, FCRTL);	/*  10 */
	*reg++ = IXGB_READ_REG(hw, FCRTH);	/*  11 */
	*reg++ = IXGB_READ_REG(hw, RDBAL);	/*  12 */
	*reg++ = IXGB_READ_REG(hw, RDBAH);	/*  13 */
	*reg++ = IXGB_READ_REG(hw, RDLEN);	/*  14 */
	*reg++ = IXGB_READ_REG(hw, RDH);	/*  15 */
	*reg++ = IXGB_READ_REG(hw, RDT);	/*  16 */
	*reg++ = IXGB_READ_REG(hw, RDTR);	/*  17 */
	*reg++ = IXGB_READ_REG(hw, RXDCTL);	/*  18 */
	*reg++ = IXGB_READ_REG(hw, RAIDC);	/*  19 */
	*reg++ = IXGB_READ_REG(hw, RXCSUM);	/*  20 */

303
	/* there are 16 RAR entries in hardware, we only use 3 */
304
	for (i = 0; i < IXGB_ALL_RAR_ENTRIES; i++) {
L
Linus Torvalds 已提交
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
		*reg++ = IXGB_READ_REG_ARRAY(hw, RAL, (i << 1)); /*21,...,51 */
		*reg++ = IXGB_READ_REG_ARRAY(hw, RAH, (i << 1)); /*22,...,52 */
	}

	/* Transmit */
	*reg++ = IXGB_READ_REG(hw, TCTL);	/*  53 */
	*reg++ = IXGB_READ_REG(hw, TDBAL);	/*  54 */
	*reg++ = IXGB_READ_REG(hw, TDBAH);	/*  55 */
	*reg++ = IXGB_READ_REG(hw, TDLEN);	/*  56 */
	*reg++ = IXGB_READ_REG(hw, TDH);	/*  57 */
	*reg++ = IXGB_READ_REG(hw, TDT);	/*  58 */
	*reg++ = IXGB_READ_REG(hw, TIDV);	/*  59 */
	*reg++ = IXGB_READ_REG(hw, TXDCTL);	/*  60 */
	*reg++ = IXGB_READ_REG(hw, TSPMT);	/*  61 */
	*reg++ = IXGB_READ_REG(hw, PAP);	/*  62 */

	/* Physical */
	*reg++ = IXGB_READ_REG(hw, PCSC1);	/*  63 */
	*reg++ = IXGB_READ_REG(hw, PCSC2);	/*  64 */
	*reg++ = IXGB_READ_REG(hw, PCSS1);	/*  65 */
	*reg++ = IXGB_READ_REG(hw, PCSS2);	/*  66 */
	*reg++ = IXGB_READ_REG(hw, XPCSS);	/*  67 */
	*reg++ = IXGB_READ_REG(hw, UCCR);	/*  68 */
	*reg++ = IXGB_READ_REG(hw, XPCSTC);	/*  69 */
	*reg++ = IXGB_READ_REG(hw, MACA);	/*  70 */
	*reg++ = IXGB_READ_REG(hw, APAE);	/*  71 */
	*reg++ = IXGB_READ_REG(hw, ARD);	/*  72 */
	*reg++ = IXGB_READ_REG(hw, AIS);	/*  73 */
	*reg++ = IXGB_READ_REG(hw, MSCA);	/*  74 */
	*reg++ = IXGB_READ_REG(hw, MSRWD);	/*  75 */

	/* Statistics */
	*reg++ = IXGB_GET_STAT(adapter, tprl);	/*  76 */
	*reg++ = IXGB_GET_STAT(adapter, tprh);	/*  77 */
	*reg++ = IXGB_GET_STAT(adapter, gprcl);	/*  78 */
	*reg++ = IXGB_GET_STAT(adapter, gprch);	/*  79 */
	*reg++ = IXGB_GET_STAT(adapter, bprcl);	/*  80 */
	*reg++ = IXGB_GET_STAT(adapter, bprch);	/*  81 */
	*reg++ = IXGB_GET_STAT(adapter, mprcl);	/*  82 */
	*reg++ = IXGB_GET_STAT(adapter, mprch);	/*  83 */
	*reg++ = IXGB_GET_STAT(adapter, uprcl);	/*  84 */
	*reg++ = IXGB_GET_STAT(adapter, uprch);	/*  85 */
	*reg++ = IXGB_GET_STAT(adapter, vprcl);	/*  86 */
	*reg++ = IXGB_GET_STAT(adapter, vprch);	/*  87 */
	*reg++ = IXGB_GET_STAT(adapter, jprcl);	/*  88 */
	*reg++ = IXGB_GET_STAT(adapter, jprch);	/*  89 */
	*reg++ = IXGB_GET_STAT(adapter, gorcl);	/*  90 */
	*reg++ = IXGB_GET_STAT(adapter, gorch);	/*  91 */
	*reg++ = IXGB_GET_STAT(adapter, torl);	/*  92 */
	*reg++ = IXGB_GET_STAT(adapter, torh);	/*  93 */
	*reg++ = IXGB_GET_STAT(adapter, rnbc);	/*  94 */
	*reg++ = IXGB_GET_STAT(adapter, ruc);	/*  95 */
	*reg++ = IXGB_GET_STAT(adapter, roc);	/*  96 */
	*reg++ = IXGB_GET_STAT(adapter, rlec);	/*  97 */
	*reg++ = IXGB_GET_STAT(adapter, crcerrs);	/*  98 */
	*reg++ = IXGB_GET_STAT(adapter, icbc);	/*  99 */
	*reg++ = IXGB_GET_STAT(adapter, ecbc);	/* 100 */
	*reg++ = IXGB_GET_STAT(adapter, mpc);	/* 101 */
	*reg++ = IXGB_GET_STAT(adapter, tptl);	/* 102 */
	*reg++ = IXGB_GET_STAT(adapter, tpth);	/* 103 */
	*reg++ = IXGB_GET_STAT(adapter, gptcl);	/* 104 */
	*reg++ = IXGB_GET_STAT(adapter, gptch);	/* 105 */
	*reg++ = IXGB_GET_STAT(adapter, bptcl);	/* 106 */
	*reg++ = IXGB_GET_STAT(adapter, bptch);	/* 107 */
	*reg++ = IXGB_GET_STAT(adapter, mptcl);	/* 108 */
	*reg++ = IXGB_GET_STAT(adapter, mptch);	/* 109 */
	*reg++ = IXGB_GET_STAT(adapter, uptcl);	/* 110 */
	*reg++ = IXGB_GET_STAT(adapter, uptch);	/* 111 */
	*reg++ = IXGB_GET_STAT(adapter, vptcl);	/* 112 */
	*reg++ = IXGB_GET_STAT(adapter, vptch);	/* 113 */
	*reg++ = IXGB_GET_STAT(adapter, jptcl);	/* 114 */
	*reg++ = IXGB_GET_STAT(adapter, jptch);	/* 115 */
	*reg++ = IXGB_GET_STAT(adapter, gotcl);	/* 116 */
	*reg++ = IXGB_GET_STAT(adapter, gotch);	/* 117 */
	*reg++ = IXGB_GET_STAT(adapter, totl);	/* 118 */
	*reg++ = IXGB_GET_STAT(adapter, toth);	/* 119 */
	*reg++ = IXGB_GET_STAT(adapter, dc);	/* 120 */
	*reg++ = IXGB_GET_STAT(adapter, plt64c);	/* 121 */
	*reg++ = IXGB_GET_STAT(adapter, tsctc);	/* 122 */
	*reg++ = IXGB_GET_STAT(adapter, tsctfc);	/* 123 */
	*reg++ = IXGB_GET_STAT(adapter, ibic);	/* 124 */
	*reg++ = IXGB_GET_STAT(adapter, rfc);	/* 125 */
	*reg++ = IXGB_GET_STAT(adapter, lfc);	/* 126 */
	*reg++ = IXGB_GET_STAT(adapter, pfrc);	/* 127 */
	*reg++ = IXGB_GET_STAT(adapter, pftc);	/* 128 */
	*reg++ = IXGB_GET_STAT(adapter, mcfrc);	/* 129 */
	*reg++ = IXGB_GET_STAT(adapter, mcftc);	/* 130 */
	*reg++ = IXGB_GET_STAT(adapter, xonrxc);	/* 131 */
	*reg++ = IXGB_GET_STAT(adapter, xontxc);	/* 132 */
	*reg++ = IXGB_GET_STAT(adapter, xoffrxc);	/* 133 */
	*reg++ = IXGB_GET_STAT(adapter, xofftxc);	/* 134 */
	*reg++ = IXGB_GET_STAT(adapter, rjc);	/* 135 */

398
	regs->len = (reg - reg_start) * sizeof(u32);
L
Linus Torvalds 已提交
399 400 401 402 403 404 405 406 407 408 409
}

static int
ixgb_get_eeprom_len(struct net_device *netdev)
{
	/* return size in bytes */
	return (IXGB_EEPROM_SIZE << 1);
}

static int
ixgb_get_eeprom(struct net_device *netdev,
410
		  struct ethtool_eeprom *eeprom, u8 *bytes)
L
Linus Torvalds 已提交
411
{
412
	struct ixgb_adapter *adapter = netdev_priv(netdev);
L
Linus Torvalds 已提交
413
	struct ixgb_hw *hw = &adapter->hw;
A
Al Viro 已提交
414
	__le16 *eeprom_buff;
L
Linus Torvalds 已提交
415 416 417
	int i, max_len, first_word, last_word;
	int ret_val = 0;

418
	if (eeprom->len == 0) {
L
Linus Torvalds 已提交
419 420 421 422 423 424 425 426
		ret_val = -EINVAL;
		goto geeprom_error;
	}

	eeprom->magic = hw->vendor_id | (hw->device_id << 16);

	max_len = ixgb_get_eeprom_len(netdev);

427
	if (eeprom->offset > eeprom->offset + eeprom->len) {
L
Linus Torvalds 已提交
428 429 430 431
		ret_val = -EINVAL;
		goto geeprom_error;
	}

432
	if ((eeprom->offset + eeprom->len) > max_len)
L
Linus Torvalds 已提交
433 434 435 436 437
		eeprom->len = (max_len - eeprom->offset);

	first_word = eeprom->offset >> 1;
	last_word = (eeprom->offset + eeprom->len - 1) >> 1;

A
Al Viro 已提交
438
	eeprom_buff = kmalloc(sizeof(__le16) *
L
Linus Torvalds 已提交
439
			(last_word - first_word + 1), GFP_KERNEL);
440
	if (!eeprom_buff)
L
Linus Torvalds 已提交
441 442 443
		return -ENOMEM;

	/* note the eeprom was good because the driver loaded */
444
	for (i = 0; i <= (last_word - first_word); i++)
L
Linus Torvalds 已提交
445 446
		eeprom_buff[i] = ixgb_get_eeprom_word(hw, (first_word + i));

447
	memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
L
Linus Torvalds 已提交
448 449 450 451 452 453 454 455
	kfree(eeprom_buff);

geeprom_error:
	return ret_val;
}

static int
ixgb_set_eeprom(struct net_device *netdev,
456
		  struct ethtool_eeprom *eeprom, u8 *bytes)
L
Linus Torvalds 已提交
457
{
458
	struct ixgb_adapter *adapter = netdev_priv(netdev);
L
Linus Torvalds 已提交
459
	struct ixgb_hw *hw = &adapter->hw;
460
	u16 *eeprom_buff;
L
Linus Torvalds 已提交
461 462
	void *ptr;
	int max_len, first_word, last_word;
463
	u16 i;
L
Linus Torvalds 已提交
464

465
	if (eeprom->len == 0)
L
Linus Torvalds 已提交
466 467
		return -EINVAL;

468
	if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
L
Linus Torvalds 已提交
469 470 471 472
		return -EFAULT;

	max_len = ixgb_get_eeprom_len(netdev);

473
	if (eeprom->offset > eeprom->offset + eeprom->len)
L
Linus Torvalds 已提交
474 475
		return -EINVAL;

476
	if ((eeprom->offset + eeprom->len) > max_len)
L
Linus Torvalds 已提交
477 478 479 480 481
		eeprom->len = (max_len - eeprom->offset);

	first_word = eeprom->offset >> 1;
	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
	eeprom_buff = kmalloc(max_len, GFP_KERNEL);
482
	if (!eeprom_buff)
L
Linus Torvalds 已提交
483 484 485 486
		return -ENOMEM;

	ptr = (void *)eeprom_buff;

487
	if (eeprom->offset & 1) {
L
Linus Torvalds 已提交
488 489 490 491 492
		/* need read/modify/write of first changed EEPROM word */
		/* only the second byte of the word is being modified */
		eeprom_buff[0] = ixgb_read_eeprom(hw, first_word);
		ptr++;
	}
493
	if ((eeprom->offset + eeprom->len) & 1) {
L
Linus Torvalds 已提交
494 495
		/* need read/modify/write of last changed EEPROM word */
		/* only the first byte of the word is being modified */
J
Jesse Brandeburg 已提交
496
		eeprom_buff[last_word - first_word]
L
Linus Torvalds 已提交
497 498 499 500
			= ixgb_read_eeprom(hw, last_word);
	}

	memcpy(ptr, bytes, eeprom->len);
501
	for (i = 0; i <= (last_word - first_word); i++)
L
Linus Torvalds 已提交
502 503 504
		ixgb_write_eeprom(hw, first_word + i, eeprom_buff[i]);

	/* Update the checksum over the first part of the EEPROM if needed */
505
	if (first_word <= EEPROM_CHECKSUM_REG)
L
Linus Torvalds 已提交
506 507 508 509 510 511 512 513 514 515
		ixgb_update_eeprom_checksum(hw);

	kfree(eeprom_buff);
	return 0;
}

static void
ixgb_get_drvinfo(struct net_device *netdev,
		   struct ethtool_drvinfo *drvinfo)
{
516
	struct ixgb_adapter *adapter = netdev_priv(netdev);
L
Linus Torvalds 已提交
517 518 519 520 521 522 523 524 525 526 527 528 529 530

	strncpy(drvinfo->driver,  ixgb_driver_name, 32);
	strncpy(drvinfo->version, ixgb_driver_version, 32);
	strncpy(drvinfo->fw_version, "N/A", 32);
	strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
	drvinfo->n_stats = IXGB_STATS_LEN;
	drvinfo->regdump_len = ixgb_get_regs_len(netdev);
	drvinfo->eedump_len = ixgb_get_eeprom_len(netdev);
}

static void
ixgb_get_ringparam(struct net_device *netdev,
		struct ethtool_ringparam *ring)
{
531
	struct ixgb_adapter *adapter = netdev_priv(netdev);
L
Linus Torvalds 已提交
532 533 534
	struct ixgb_desc_ring *txdr = &adapter->tx_ring;
	struct ixgb_desc_ring *rxdr = &adapter->rx_ring;

J
Jesse Brandeburg 已提交
535
	ring->rx_max_pending = MAX_RXD;
L
Linus Torvalds 已提交
536 537 538 539 540 541 542 543 544
	ring->tx_max_pending = MAX_TXD;
	ring->rx_mini_max_pending = 0;
	ring->rx_jumbo_max_pending = 0;
	ring->rx_pending = rxdr->count;
	ring->tx_pending = txdr->count;
	ring->rx_mini_pending = 0;
	ring->rx_jumbo_pending = 0;
}

J
Jesse Brandeburg 已提交
545
static int
L
Linus Torvalds 已提交
546 547 548
ixgb_set_ringparam(struct net_device *netdev,
		struct ethtool_ringparam *ring)
{
549
	struct ixgb_adapter *adapter = netdev_priv(netdev);
L
Linus Torvalds 已提交
550 551 552 553 554 555 556 557
	struct ixgb_desc_ring *txdr = &adapter->tx_ring;
	struct ixgb_desc_ring *rxdr = &adapter->rx_ring;
	struct ixgb_desc_ring tx_old, tx_new, rx_old, rx_new;
	int err;

	tx_old = adapter->tx_ring;
	rx_old = adapter->rx_ring;

558
	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
L
Linus Torvalds 已提交
559 560
		return -EINVAL;

561
	if (netif_running(adapter->netdev))
J
Joe Perches 已提交
562
		ixgb_down(adapter, true);
L
Linus Torvalds 已提交
563

564 565
	rxdr->count = max(ring->rx_pending,(u32)MIN_RXD);
	rxdr->count = min(rxdr->count,(u32)MAX_RXD);
566
	rxdr->count = ALIGN(rxdr->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE);
L
Linus Torvalds 已提交
567

568 569
	txdr->count = max(ring->tx_pending,(u32)MIN_TXD);
	txdr->count = min(txdr->count,(u32)MAX_TXD);
570
	txdr->count = ALIGN(txdr->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE);
L
Linus Torvalds 已提交
571

572
	if (netif_running(adapter->netdev)) {
L
Linus Torvalds 已提交
573
		/* Try to get new resources before deleting old */
574
		if ((err = ixgb_setup_rx_resources(adapter)))
L
Linus Torvalds 已提交
575
			goto err_setup_rx;
576
		if ((err = ixgb_setup_tx_resources(adapter)))
L
Linus Torvalds 已提交
577 578 579 580 581 582 583 584 585 586 587 588 589
			goto err_setup_tx;

		/* save the new, restore the old in order to free it,
		 * then restore the new back again */

		rx_new = adapter->rx_ring;
		tx_new = adapter->tx_ring;
		adapter->rx_ring = rx_old;
		adapter->tx_ring = tx_old;
		ixgb_free_rx_resources(adapter);
		ixgb_free_tx_resources(adapter);
		adapter->rx_ring = rx_new;
		adapter->tx_ring = tx_new;
590
		if ((err = ixgb_up(adapter)))
L
Linus Torvalds 已提交
591
			return err;
592
		ixgb_set_speed_duplex(netdev);
L
Linus Torvalds 已提交
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
	}

	return 0;
err_setup_tx:
	ixgb_free_rx_resources(adapter);
err_setup_rx:
	adapter->rx_ring = rx_old;
	adapter->tx_ring = tx_old;
	ixgb_up(adapter);
	return err;
}

/* toggle LED 4 times per second = 2 "blinks" per second */
#define IXGB_ID_INTERVAL	(HZ/4)

/* bit defines for adapter->led_status */
#define IXGB_LED_ON		0

static void
ixgb_led_blink_callback(unsigned long data)
{
	struct ixgb_adapter *adapter = (struct ixgb_adapter *)data;

616
	if (test_and_change_bit(IXGB_LED_ON, &adapter->led_status))
L
Linus Torvalds 已提交
617 618 619 620 621 622 623 624
		ixgb_led_off(&adapter->hw);
	else
		ixgb_led_on(&adapter->hw);

	mod_timer(&adapter->blink_timer, jiffies + IXGB_ID_INTERVAL);
}

static int
625
ixgb_phys_id(struct net_device *netdev, u32 data)
L
Linus Torvalds 已提交
626
{
627
	struct ixgb_adapter *adapter = netdev_priv(netdev);
L
Linus Torvalds 已提交
628

S
Stephen Hemminger 已提交
629 630
	if (!data)
		data = INT_MAX;
L
Linus Torvalds 已提交
631

632
	if (!adapter->blink_timer.function) {
L
Linus Torvalds 已提交
633 634 635 636 637 638 639
		init_timer(&adapter->blink_timer);
		adapter->blink_timer.function = ixgb_led_blink_callback;
		adapter->blink_timer.data = (unsigned long)adapter;
	}

	mod_timer(&adapter->blink_timer, jiffies);

640
	msleep_interruptible(data * 1000);
L
Linus Torvalds 已提交
641 642 643 644 645 646 647
	del_timer_sync(&adapter->blink_timer);
	ixgb_led_off(&adapter->hw);
	clear_bit(IXGB_LED_ON, &adapter->led_status);

	return 0;
}

J
Jesse Brandeburg 已提交
648
static int
649
ixgb_get_sset_count(struct net_device *netdev, int sset)
L
Linus Torvalds 已提交
650
{
651 652 653 654 655 656
	switch (sset) {
	case ETH_SS_STATS:
		return IXGB_STATS_LEN;
	default:
		return -EOPNOTSUPP;
	}
L
Linus Torvalds 已提交
657 658
}

J
Jesse Brandeburg 已提交
659 660
static void
ixgb_get_ethtool_stats(struct net_device *netdev,
661
		struct ethtool_stats *stats, u64 *data)
L
Linus Torvalds 已提交
662
{
663
	struct ixgb_adapter *adapter = netdev_priv(netdev);
L
Linus Torvalds 已提交
664 665 666
	int i;

	ixgb_update_stats(adapter);
667
	for (i = 0; i < IXGB_STATS_LEN; i++) {
J
Jesse Brandeburg 已提交
668 669
		char *p = (char *)adapter+ixgb_gstrings_stats[i].stat_offset;
		data[i] = (ixgb_gstrings_stats[i].sizeof_stat ==
670
			sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
L
Linus Torvalds 已提交
671 672 673
	}
}

J
Jesse Brandeburg 已提交
674
static void
675
ixgb_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
L
Linus Torvalds 已提交
676 677 678 679 680
{
	int i;

	switch(stringset) {
	case ETH_SS_STATS:
681
		for (i = 0; i < IXGB_STATS_LEN; i++) {
J
Jesse Brandeburg 已提交
682
			memcpy(data + i * ETH_GSTRING_LEN,
L
Linus Torvalds 已提交
683 684 685 686 687 688 689
			ixgb_gstrings_stats[i].stat_string,
			ETH_GSTRING_LEN);
		}
		break;
	}
}

690
static const struct ethtool_ops ixgb_ethtool_ops = {
L
Linus Torvalds 已提交
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
	.get_settings = ixgb_get_settings,
	.set_settings = ixgb_set_settings,
	.get_drvinfo = ixgb_get_drvinfo,
	.get_regs_len = ixgb_get_regs_len,
	.get_regs = ixgb_get_regs,
	.get_link = ethtool_op_get_link,
	.get_eeprom_len = ixgb_get_eeprom_len,
	.get_eeprom = ixgb_get_eeprom,
	.set_eeprom = ixgb_set_eeprom,
	.get_ringparam = ixgb_get_ringparam,
	.set_ringparam = ixgb_set_ringparam,
	.get_pauseparam	= ixgb_get_pauseparam,
	.set_pauseparam	= ixgb_set_pauseparam,
	.get_rx_csum = ixgb_get_rx_csum,
	.set_rx_csum = ixgb_set_rx_csum,
	.get_tx_csum = ixgb_get_tx_csum,
	.set_tx_csum = ixgb_set_tx_csum,
	.set_sg	= ethtool_op_set_sg,
709 710
	.get_msglevel = ixgb_get_msglevel,
	.set_msglevel = ixgb_set_msglevel,
L
Linus Torvalds 已提交
711 712 713
	.set_tso = ixgb_set_tso,
	.get_strings = ixgb_get_strings,
	.phys_id = ixgb_phys_id,
714
	.get_sset_count = ixgb_get_sset_count,
L
Linus Torvalds 已提交
715 716 717 718 719 720 721
	.get_ethtool_stats = ixgb_get_ethtool_stats,
};

void ixgb_set_ethtool_ops(struct net_device *netdev)
{
	SET_ETHTOOL_OPS(netdev, &ixgb_ethtool_ops);
}