be_ethtool.c 19.5 KB
Newer Older
S
Sathya Perla 已提交
1
/*
2
 * Copyright (C) 2005 - 2011 Emulex
S
Sathya Perla 已提交
3 4 5 6 7 8 9 10
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.  The full GNU General
 * Public License is included in this distribution in the file called COPYING.
 *
 * Contact Information:
11
 * linux-drivers@emulex.com
S
Sathya Perla 已提交
12
 *
13 14 15
 * Emulex
 * 3333 Susan Street
 * Costa Mesa, CA 92626
S
Sathya Perla 已提交
16 17 18
 */

#include "be.h"
19
#include "be_cmds.h"
S
Sathya Perla 已提交
20 21 22 23 24 25 26 27 28
#include <linux/ethtool.h>

struct be_ethtool_stat {
	char desc[ETH_GSTRING_LEN];
	int type;
	int size;
	int offset;
};

29
enum {NETSTAT, PORTSTAT, MISCSTAT, DRVSTAT_TX, DRVSTAT_RX, ERXSTAT,
30
			PMEMSTAT, DRVSTAT};
S
Sathya Perla 已提交
31 32 33 34 35
#define FIELDINFO(_struct, field) FIELD_SIZEOF(_struct, field), \
					offsetof(_struct, field)
#define NETSTAT_INFO(field) 	#field, NETSTAT,\
					FIELDINFO(struct net_device_stats,\
						field)
36 37 38 39
#define DRVSTAT_TX_INFO(field)	#field, DRVSTAT_TX,\
					FIELDINFO(struct be_tx_stats, field)
#define DRVSTAT_RX_INFO(field)	#field, DRVSTAT_RX,\
					FIELDINFO(struct be_rx_stats, field)
S
Sathya Perla 已提交
40 41 42 43 44 45 46
#define MISCSTAT_INFO(field) 	#field, MISCSTAT,\
					FIELDINFO(struct be_rxf_stats, field)
#define PORTSTAT_INFO(field) 	#field, PORTSTAT,\
					FIELDINFO(struct be_port_rxf_stats, \
						field)
#define ERXSTAT_INFO(field) 	#field, ERXSTAT,\
					FIELDINFO(struct be_erx_stats, field)
47 48
#define PMEMSTAT_INFO(field) 	#field, PMEMSTAT,\
					FIELDINFO(struct be_pmem_stats, field)
49 50 51
#define	DRVSTAT_INFO(field)	#field, DRVSTAT,\
					FIELDINFO(struct be_drv_stats, \
						field)
S
Sathya Perla 已提交
52 53 54 55 56 57 58 59 60 61

static const struct be_ethtool_stat et_stats[] = {
	{NETSTAT_INFO(rx_packets)},
	{NETSTAT_INFO(tx_packets)},
	{NETSTAT_INFO(rx_bytes)},
	{NETSTAT_INFO(tx_bytes)},
	{NETSTAT_INFO(rx_errors)},
	{NETSTAT_INFO(tx_errors)},
	{NETSTAT_INFO(rx_dropped)},
	{NETSTAT_INFO(tx_dropped)},
62 63 64 65 66 67
	{DRVSTAT_TX_INFO(be_tx_rate)},
	{DRVSTAT_TX_INFO(be_tx_reqs)},
	{DRVSTAT_TX_INFO(be_tx_wrbs)},
	{DRVSTAT_TX_INFO(be_tx_stops)},
	{DRVSTAT_TX_INFO(be_tx_events)},
	{DRVSTAT_TX_INFO(be_tx_compl)},
S
Sathya Perla 已提交
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
	{PORTSTAT_INFO(rx_unicast_frames)},
	{PORTSTAT_INFO(rx_multicast_frames)},
	{PORTSTAT_INFO(rx_broadcast_frames)},
	{PORTSTAT_INFO(rx_crc_errors)},
	{PORTSTAT_INFO(rx_alignment_symbol_errors)},
	{PORTSTAT_INFO(rx_pause_frames)},
	{PORTSTAT_INFO(rx_control_frames)},
	{PORTSTAT_INFO(rx_in_range_errors)},
	{PORTSTAT_INFO(rx_out_range_errors)},
	{PORTSTAT_INFO(rx_frame_too_long)},
	{PORTSTAT_INFO(rx_address_match_errors)},
	{PORTSTAT_INFO(rx_vlan_mismatch)},
	{PORTSTAT_INFO(rx_dropped_too_small)},
	{PORTSTAT_INFO(rx_dropped_too_short)},
	{PORTSTAT_INFO(rx_dropped_header_too_small)},
	{PORTSTAT_INFO(rx_dropped_tcp_length)},
	{PORTSTAT_INFO(rx_dropped_runt)},
	{PORTSTAT_INFO(rx_fifo_overflow)},
	{PORTSTAT_INFO(rx_input_fifo_overflow)},
	{PORTSTAT_INFO(rx_ip_checksum_errs)},
	{PORTSTAT_INFO(rx_tcp_checksum_errs)},
	{PORTSTAT_INFO(rx_udp_checksum_errs)},
	{PORTSTAT_INFO(rx_non_rss_packets)},
	{PORTSTAT_INFO(rx_ipv4_packets)},
	{PORTSTAT_INFO(rx_ipv6_packets)},
93 94 95
	{PORTSTAT_INFO(rx_switched_unicast_packets)},
	{PORTSTAT_INFO(rx_switched_multicast_packets)},
	{PORTSTAT_INFO(rx_switched_broadcast_packets)},
S
Sathya Perla 已提交
96 97 98 99 100 101 102 103 104 105 106 107
	{PORTSTAT_INFO(tx_unicastframes)},
	{PORTSTAT_INFO(tx_multicastframes)},
	{PORTSTAT_INFO(tx_broadcastframes)},
	{PORTSTAT_INFO(tx_pauseframes)},
	{PORTSTAT_INFO(tx_controlframes)},
	{MISCSTAT_INFO(rx_drops_no_pbuf)},
	{MISCSTAT_INFO(rx_drops_no_txpb)},
	{MISCSTAT_INFO(rx_drops_no_erx_descr)},
	{MISCSTAT_INFO(rx_drops_no_tpre_descr)},
	{MISCSTAT_INFO(rx_drops_too_many_frags)},
	{MISCSTAT_INFO(rx_drops_invalid_ring)},
	{MISCSTAT_INFO(forwarded_packets)},
108 109 110
	{MISCSTAT_INFO(rx_drops_mtu)},
	{MISCSTAT_INFO(port0_jabber_events)},
	{MISCSTAT_INFO(port1_jabber_events)},
111 112
	{PMEMSTAT_INFO(eth_red_drops)},
	{DRVSTAT_INFO(be_on_die_temperature)}
S
Sathya Perla 已提交
113 114 115
};
#define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats)

116 117 118 119 120 121 122 123 124 125 126 127 128 129
/* Stats related to multi RX queues */
static const struct be_ethtool_stat et_rx_stats[] = {
	{DRVSTAT_RX_INFO(rx_bytes)},
	{DRVSTAT_RX_INFO(rx_pkts)},
	{DRVSTAT_RX_INFO(rx_rate)},
	{DRVSTAT_RX_INFO(rx_polls)},
	{DRVSTAT_RX_INFO(rx_events)},
	{DRVSTAT_RX_INFO(rx_compl)},
	{DRVSTAT_RX_INFO(rx_mcast_pkts)},
	{DRVSTAT_RX_INFO(rx_post_fail)},
	{ERXSTAT_INFO(rx_drops_no_fragments)}
};
#define ETHTOOL_RXSTATS_NUM (ARRAY_SIZE(et_rx_stats))

130 131 132 133
static const char et_self_tests[][ETH_GSTRING_LEN] = {
	"MAC Loopback test",
	"PHY Loopback test",
	"External Loopback test",
134
	"DDR DMA test",
135
	"Link test"
136 137 138 139 140 141
};

#define ETHTOOL_TESTS_NUM ARRAY_SIZE(et_self_tests)
#define BE_MAC_LOOPBACK 0x0
#define BE_PHY_LOOPBACK 0x1
#define BE_ONE_PORT_EXT_LOOPBACK 0x2
142
#define BE_NO_LOOPBACK 0xff
143

S
Sathya Perla 已提交
144 145 146 147 148 149 150 151 152 153 154 155 156 157
static void
be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
{
	struct be_adapter *adapter = netdev_priv(netdev);

	strcpy(drvinfo->driver, DRV_NAME);
	strcpy(drvinfo->version, DRV_VER);
	strncpy(drvinfo->fw_version, adapter->fw_ver, FW_VER_LEN);
	strcpy(drvinfo->bus_info, pci_name(adapter->pdev));
	drvinfo->testinfo_len = 0;
	drvinfo->regdump_len = 0;
	drvinfo->eedump_len = 0;
}

158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
static int
be_get_reg_len(struct net_device *netdev)
{
	struct be_adapter *adapter = netdev_priv(netdev);
	u32 log_size = 0;

	be_cmd_get_reg_len(adapter, &log_size);
	return log_size;
}

static void
be_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf)
{
	struct be_adapter *adapter = netdev_priv(netdev);

	memset(buf, 0, regs->len);
	be_cmd_get_regs(adapter, regs->len, buf);
}

S
Sathya Perla 已提交
177 178 179 180
static int
be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
{
	struct be_adapter *adapter = netdev_priv(netdev);
181
	struct be_eq_obj *rx_eq = &adapter->rx_obj[0].rx_eq;
S
Sathya Perla 已提交
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
	struct be_eq_obj *tx_eq = &adapter->tx_eq;

	coalesce->rx_coalesce_usecs = rx_eq->cur_eqd;
	coalesce->rx_coalesce_usecs_high = rx_eq->max_eqd;
	coalesce->rx_coalesce_usecs_low = rx_eq->min_eqd;

	coalesce->tx_coalesce_usecs = tx_eq->cur_eqd;
	coalesce->tx_coalesce_usecs_high = tx_eq->max_eqd;
	coalesce->tx_coalesce_usecs_low = tx_eq->min_eqd;

	coalesce->use_adaptive_rx_coalesce = rx_eq->enable_aic;
	coalesce->use_adaptive_tx_coalesce = tx_eq->enable_aic;

	return 0;
}

/*
199
 * This routine is used to set interrup coalescing delay
S
Sathya Perla 已提交
200 201 202 203 204
 */
static int
be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
{
	struct be_adapter *adapter = netdev_priv(netdev);
205 206
	struct be_rx_obj *rxo;
	struct be_eq_obj *rx_eq;
S
Sathya Perla 已提交
207 208 209
	struct be_eq_obj *tx_eq = &adapter->tx_eq;
	u32 tx_max, tx_min, tx_cur;
	u32 rx_max, rx_min, rx_cur;
210
	int status = 0, i;
S
Sathya Perla 已提交
211 212 213 214

	if (coalesce->use_adaptive_tx_coalesce == 1)
		return -EINVAL;

215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
	for_all_rx_queues(adapter, rxo, i) {
		rx_eq = &rxo->rx_eq;

		if (!rx_eq->enable_aic && coalesce->use_adaptive_rx_coalesce)
			rx_eq->cur_eqd = 0;
		rx_eq->enable_aic = coalesce->use_adaptive_rx_coalesce;

		rx_max = coalesce->rx_coalesce_usecs_high;
		rx_min = coalesce->rx_coalesce_usecs_low;
		rx_cur = coalesce->rx_coalesce_usecs;

		if (rx_eq->enable_aic) {
			if (rx_max > BE_MAX_EQD)
				rx_max = BE_MAX_EQD;
			if (rx_min > rx_max)
				rx_min = rx_max;
			rx_eq->max_eqd = rx_max;
			rx_eq->min_eqd = rx_min;
			if (rx_eq->cur_eqd > rx_max)
				rx_eq->cur_eqd = rx_max;
			if (rx_eq->cur_eqd < rx_min)
				rx_eq->cur_eqd = rx_min;
		} else {
			if (rx_cur > BE_MAX_EQD)
				rx_cur = BE_MAX_EQD;
			if (rx_eq->cur_eqd != rx_cur) {
				status = be_cmd_modify_eqd(adapter, rx_eq->q.id,
						rx_cur);
				if (!status)
					rx_eq->cur_eqd = rx_cur;
			}
		}
S
Sathya Perla 已提交
247 248 249 250 251 252 253 254 255
	}

	tx_max = coalesce->tx_coalesce_usecs_high;
	tx_min = coalesce->tx_coalesce_usecs_low;
	tx_cur = coalesce->tx_coalesce_usecs;

	if (tx_cur > BE_MAX_EQD)
		tx_cur = BE_MAX_EQD;
	if (tx_eq->cur_eqd != tx_cur) {
256
		status = be_cmd_modify_eqd(adapter, tx_eq->q.id, tx_cur);
S
Sathya Perla 已提交
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
		if (!status)
			tx_eq->cur_eqd = tx_cur;
	}

	return 0;
}

static u32 be_get_rx_csum(struct net_device *netdev)
{
	struct be_adapter *adapter = netdev_priv(netdev);

	return adapter->rx_csum;
}

static int be_set_rx_csum(struct net_device *netdev, uint32_t data)
{
	struct be_adapter *adapter = netdev_priv(netdev);

	if (data)
		adapter->rx_csum = true;
	else
		adapter->rx_csum = false;

	return 0;
}

static void
be_get_ethtool_stats(struct net_device *netdev,
		struct ethtool_stats *stats, uint64_t *data)
{
	struct be_adapter *adapter = netdev_priv(netdev);
288
	struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats_cmd.va);
S
Sathya Perla 已提交
289
	struct be_erx_stats *erx_stats = &hw_stats->erx;
290
	struct be_rx_obj *rxo;
S
Sathya Perla 已提交
291
	void *p = NULL;
292
	int i, j;
S
Sathya Perla 已提交
293 294 295 296

	for (i = 0; i < ETHTOOL_STATS_NUM; i++) {
		switch (et_stats[i].type) {
		case NETSTAT:
297
			p = &netdev->stats;
S
Sathya Perla 已提交
298
			break;
299 300
		case DRVSTAT_TX:
			p = &adapter->tx_stats;
S
Sathya Perla 已提交
301 302
			break;
		case PORTSTAT:
303
			p = &hw_stats->rxf.port[adapter->port_num];
S
Sathya Perla 已提交
304 305
			break;
		case MISCSTAT:
306
			p = &hw_stats->rxf;
S
Sathya Perla 已提交
307
			break;
308 309 310
		case PMEMSTAT:
			p = &hw_stats->pmem;
			break;
311 312 313
		case DRVSTAT:
			p = &adapter->drv_stats;
			break;
S
Sathya Perla 已提交
314 315 316 317 318 319
		}

		p = (u8 *)p + et_stats[i].offset;
		data[i] = (et_stats[i].size == sizeof(u64)) ?
				*(u64 *)p: *(u32 *)p;
	}
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335

	for_all_rx_queues(adapter, rxo, j) {
		for (i = 0; i < ETHTOOL_RXSTATS_NUM; i++) {
			switch (et_rx_stats[i].type) {
			case DRVSTAT_RX:
				p = (u8 *)&rxo->stats + et_rx_stats[i].offset;
				break;
			case ERXSTAT:
				p = (u32 *)erx_stats + rxo->q.id;
				break;
			}
			data[ETHTOOL_STATS_NUM + j * ETHTOOL_RXSTATS_NUM + i] =
				(et_rx_stats[i].size == sizeof(u64)) ?
					*(u64 *)p: *(u32 *)p;
		}
	}
S
Sathya Perla 已提交
336 337 338 339 340 341
}

static void
be_get_stat_strings(struct net_device *netdev, uint32_t stringset,
		uint8_t *data)
{
342 343 344
	struct be_adapter *adapter = netdev_priv(netdev);
	int i, j;

S
Sathya Perla 已提交
345 346 347 348 349 350
	switch (stringset) {
	case ETH_SS_STATS:
		for (i = 0; i < ETHTOOL_STATS_NUM; i++) {
			memcpy(data, et_stats[i].desc, ETH_GSTRING_LEN);
			data += ETH_GSTRING_LEN;
		}
351 352 353 354 355 356 357
		for (i = 0; i < adapter->num_rx_qs; i++) {
			for (j = 0; j < ETHTOOL_RXSTATS_NUM; j++) {
				sprintf(data, "rxq%d: %s", i,
					et_rx_stats[j].desc);
				data += ETH_GSTRING_LEN;
			}
		}
S
Sathya Perla 已提交
358
		break;
359 360 361 362 363 364
	case ETH_SS_TEST:
		for (i = 0; i < ETHTOOL_TESTS_NUM; i++) {
			memcpy(data, et_self_tests[i], ETH_GSTRING_LEN);
			data += ETH_GSTRING_LEN;
		}
		break;
S
Sathya Perla 已提交
365 366 367
	}
}

368
static int be_get_sset_count(struct net_device *netdev, int stringset)
S
Sathya Perla 已提交
369
{
370 371
	struct be_adapter *adapter = netdev_priv(netdev);

372
	switch (stringset) {
373 374
	case ETH_SS_TEST:
		return ETHTOOL_TESTS_NUM;
375
	case ETH_SS_STATS:
376 377
		return ETHTOOL_STATS_NUM +
			adapter->num_rx_qs * ETHTOOL_RXSTATS_NUM;
378 379 380
	default:
		return -EINVAL;
	}
S
Sathya Perla 已提交
381 382 383 384
}

static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
385
	struct be_adapter *adapter = netdev_priv(netdev);
386 387 388
	struct be_dma_mem phy_cmd;
	struct be_cmd_resp_get_phy_info *resp;
	u8 mac_speed = 0;
389 390
	u16 link_speed = 0;
	bool link_up = false;
391
	int status;
392
	u16 intf_type;
393

394
	if ((adapter->link_speed < 0) || (!(netdev->flags & IFF_UP))) {
395 396 397
		status = be_cmd_link_status_query(adapter, &link_up,
						&mac_speed, &link_speed);

398
		be_link_status_update(adapter, link_up);
399 400 401 402 403 404 405 406 407 408 409 410 411
		/* link_speed is in units of 10 Mbps */
		if (link_speed) {
			ecmd->speed = link_speed*10;
		} else {
			switch (mac_speed) {
			case PHY_LINK_SPEED_1GBPS:
				ecmd->speed = SPEED_1000;
				break;
			case PHY_LINK_SPEED_10GBPS:
				ecmd->speed = SPEED_10000;
				break;
			}
		}
412

413
		phy_cmd.size = sizeof(struct be_cmd_req_get_phy_info);
I
Ivan Vecera 已提交
414 415 416
		phy_cmd.va = dma_alloc_coherent(&adapter->pdev->dev,
						phy_cmd.size, &phy_cmd.dma,
						GFP_KERNEL);
417 418 419 420 421
		if (!phy_cmd.va) {
			dev_err(&adapter->pdev->dev, "Memory alloc failure\n");
			return -ENOMEM;
		}
		status = be_cmd_get_phy_info(adapter, &phy_cmd);
422
		if (!status) {
423 424 425 426 427 428 429
			resp = (struct be_cmd_resp_get_phy_info *) phy_cmd.va;
			intf_type = le16_to_cpu(resp->interface_type);

			switch (intf_type) {
			case PHY_TYPE_XFP_10GB:
			case PHY_TYPE_SFP_1GB:
			case PHY_TYPE_SFP_PLUS_10GB:
430 431 432 433 434 435
				ecmd->port = PORT_FIBRE;
				break;
			default:
				ecmd->port = PORT_TP;
				break;
			}
436 437 438 439 440

			switch (intf_type) {
			case PHY_TYPE_KR_10GB:
			case PHY_TYPE_KX4_10GB:
				ecmd->autoneg = AUTONEG_ENABLE;
441
			ecmd->transceiver = XCVR_INTERNAL;
442 443 444 445 446 447
				break;
			default:
				ecmd->autoneg = AUTONEG_DISABLE;
				ecmd->transceiver = XCVR_EXTERNAL;
				break;
			}
448
		}
449 450 451 452

		/* Save for future use */
		adapter->link_speed = ecmd->speed;
		adapter->port_type = ecmd->port;
453
		adapter->transceiver = ecmd->transceiver;
454
		adapter->autoneg = ecmd->autoneg;
I
Ivan Vecera 已提交
455 456
		dma_free_coherent(&adapter->pdev->dev, phy_cmd.size, phy_cmd.va,
				  phy_cmd.dma);
457 458 459
	} else {
		ecmd->speed = adapter->link_speed;
		ecmd->port = adapter->port_type;
460
		ecmd->transceiver = adapter->transceiver;
461
		ecmd->autoneg = adapter->autoneg;
462
	}
463

S
Sathya Perla 已提交
464
	ecmd->duplex = DUPLEX_FULL;
465
	ecmd->phy_address = adapter->port_num;
466 467 468 469 470 471 472 473 474 475 476
	switch (ecmd->port) {
	case PORT_FIBRE:
		ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
		break;
	case PORT_TP:
		ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_TP);
		break;
	case PORT_AUI:
		ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_AUI);
		break;
	}
477

478 479 480 481 482 483 484
	if (ecmd->autoneg) {
		ecmd->supported |= SUPPORTED_1000baseT_Full;
		ecmd->supported |= SUPPORTED_Autoneg;
		ecmd->advertising |= (ADVERTISED_10000baseT_Full |
				ADVERTISED_1000baseT_Full);
	}

S
Sathya Perla 已提交
485 486 487 488 489 490 491 492
	return 0;
}

static void
be_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
{
	struct be_adapter *adapter = netdev_priv(netdev);

493
	ring->rx_max_pending = adapter->rx_obj[0].q.len;
S
Sathya Perla 已提交
494 495
	ring->tx_max_pending = adapter->tx_obj.q.len;

496
	ring->rx_pending = atomic_read(&adapter->rx_obj[0].q.used);
S
Sathya Perla 已提交
497 498 499 500 501 502 503 504
	ring->tx_pending = atomic_read(&adapter->tx_obj.q.used);
}

static void
be_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
{
	struct be_adapter *adapter = netdev_priv(netdev);

505
	be_cmd_get_flow_control(adapter, &ecmd->tx_pause, &ecmd->rx_pause);
506
	ecmd->autoneg = 0;
S
Sathya Perla 已提交
507 508 509 510 511 512 513 514
}

static int
be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
{
	struct be_adapter *adapter = netdev_priv(netdev);
	int status;

515
	if (ecmd->autoneg != 0)
S
Sathya Perla 已提交
516
		return -EINVAL;
517 518
	adapter->tx_fc = ecmd->tx_pause;
	adapter->rx_fc = ecmd->rx_pause;
S
Sathya Perla 已提交
519

520 521 522
	status = be_cmd_set_flow_control(adapter,
					adapter->tx_fc, adapter->rx_fc);
	if (status)
S
Sathya Perla 已提交
523 524 525 526 527
		dev_warn(&adapter->pdev->dev, "Pause param set failed.\n");

	return status;
}

528 529 530 531 532 533 534
static int
be_phys_id(struct net_device *netdev, u32 data)
{
	struct be_adapter *adapter = netdev_priv(netdev);
	int status;
	u32 cur;

535
	be_cmd_get_beacon_state(adapter, adapter->hba_port_num, &cur);
536 537 538 539 540 541 542

	if (cur == BEACON_STATE_ENABLED)
		return 0;

	if (data < 2)
		data = 2;

543
	status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
544 545 546 547
			BEACON_STATE_ENABLED);
	set_current_state(TASK_INTERRUPTIBLE);
	schedule_timeout(data*HZ);

548
	status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
549 550 551 552 553
			BEACON_STATE_DISABLED);

	return status;
}

554 555 556 557 558 559 560 561 562
static bool
be_is_wol_supported(struct be_adapter *adapter)
{
	if (!be_physfn(adapter))
		return false;
	else
		return true;
}

563 564 565 566 567
static void
be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
	struct be_adapter *adapter = netdev_priv(netdev);

568 569 570
	if (be_is_wol_supported(adapter))
		wol->supported = WAKE_MAGIC;

571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
	if (adapter->wol)
		wol->wolopts = WAKE_MAGIC;
	else
		wol->wolopts = 0;
	memset(&wol->sopass, 0, sizeof(wol->sopass));
}

static int
be_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
	struct be_adapter *adapter = netdev_priv(netdev);

	if (wol->wolopts & ~WAKE_MAGIC)
		return -EINVAL;

586
	if ((wol->wolopts & WAKE_MAGIC) && be_is_wol_supported(adapter))
587 588 589 590 591 592 593
		adapter->wol = true;
	else
		adapter->wol = false;

	return 0;
}

594 595 596 597 598
static int
be_test_ddr_dma(struct be_adapter *adapter)
{
	int ret, i;
	struct be_dma_mem ddrdma_cmd;
J
Joe Perches 已提交
599 600 601
	static const u64 pattern[2] = {
		0x5a5a5a5a5a5a5a5aULL, 0xa5a5a5a5a5a5a5a5ULL
	};
602 603

	ddrdma_cmd.size = sizeof(struct be_cmd_req_ddrdma_test);
I
Ivan Vecera 已提交
604 605
	ddrdma_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, ddrdma_cmd.size,
					   &ddrdma_cmd.dma, GFP_KERNEL);
606
	if (!ddrdma_cmd.va) {
607
		dev_err(&adapter->pdev->dev, "Memory allocation failure\n");
608 609 610 611 612 613 614 615 616 617 618
		return -ENOMEM;
	}

	for (i = 0; i < 2; i++) {
		ret = be_cmd_ddr_dma_test(adapter, pattern[i],
					4096, &ddrdma_cmd);
		if (ret != 0)
			goto err;
	}

err:
I
Ivan Vecera 已提交
619 620
	dma_free_coherent(&adapter->pdev->dev, ddrdma_cmd.size, ddrdma_cmd.va,
			  ddrdma_cmd.dma);
621 622 623
	return ret;
}

624 625 626
static u64 be_loopback_test(struct be_adapter *adapter, u8 loopback_type,
				u64 *status)
{
627
	be_cmd_set_loopback(adapter, adapter->hba_port_num,
628
				loopback_type, 1);
629
	*status = be_cmd_loopback_test(adapter, adapter->hba_port_num,
630 631
				loopback_type, 1500,
				2, 0xabc);
632
	be_cmd_set_loopback(adapter, adapter->hba_port_num,
633 634 635 636
				BE_NO_LOOPBACK, 1);
	return *status;
}

637 638 639 640
static void
be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
{
	struct be_adapter *adapter = netdev_priv(netdev);
641 642 643
	bool link_up;
	u8 mac_speed = 0;
	u16 qos_link_speed = 0;
644 645 646 647

	memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM);

	if (test->flags & ETH_TEST_FL_OFFLINE) {
648 649
		if (be_loopback_test(adapter, BE_MAC_LOOPBACK,
						&data[0]) != 0) {
650
			test->flags |= ETH_TEST_FL_FAILED;
651 652 653
		}
		if (be_loopback_test(adapter, BE_PHY_LOOPBACK,
						&data[1]) != 0) {
654
			test->flags |= ETH_TEST_FL_FAILED;
655 656 657
		}
		if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK,
						&data[2]) != 0) {
658
			test->flags |= ETH_TEST_FL_FAILED;
659
		}
660
	}
661

662 663 664
	if (be_test_ddr_dma(adapter) != 0) {
		data[3] = 1;
		test->flags |= ETH_TEST_FL_FAILED;
665 666
	}

667 668 669 670
	if (be_cmd_link_status_query(adapter, &link_up, &mac_speed,
				&qos_link_speed) != 0) {
		test->flags |= ETH_TEST_FL_FAILED;
		data[4] = -1;
671 672
	} else if (!mac_speed) {
		test->flags |= ETH_TEST_FL_FAILED;
673 674
		data[4] = 1;
	}
675 676
}

677 678 679 680 681 682 683 684 685 686 687 688 689 690
static int
be_do_flash(struct net_device *netdev, struct ethtool_flash *efl)
{
	struct be_adapter *adapter = netdev_priv(netdev);
	char file_name[ETHTOOL_FLASH_MAX_FILENAME];
	u32 region;

	file_name[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0;
	strcpy(file_name, efl->data);
	region = efl->region;

	return be_load_fw(adapter, file_name);
}

691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
static int
be_get_eeprom_len(struct net_device *netdev)
{
	return BE_READ_SEEPROM_LEN;
}

static int
be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
			uint8_t *data)
{
	struct be_adapter *adapter = netdev_priv(netdev);
	struct be_dma_mem eeprom_cmd;
	struct be_cmd_resp_seeprom_read *resp;
	int status;

	if (!eeprom->len)
		return -EINVAL;

	eeprom->magic = BE_VENDOR_ID | (adapter->pdev->device<<16);

	memset(&eeprom_cmd, 0, sizeof(struct be_dma_mem));
	eeprom_cmd.size = sizeof(struct be_cmd_req_seeprom_read);
I
Ivan Vecera 已提交
713 714
	eeprom_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, eeprom_cmd.size,
					   &eeprom_cmd.dma, GFP_KERNEL);
715 716 717 718 719 720 721 722 723 724 725

	if (!eeprom_cmd.va) {
		dev_err(&adapter->pdev->dev,
			"Memory allocation failure. Could not read eeprom\n");
		return -ENOMEM;
	}

	status = be_cmd_get_seeprom_data(adapter, &eeprom_cmd);

	if (!status) {
		resp = (struct be_cmd_resp_seeprom_read *) eeprom_cmd.va;
726
		memcpy(data, resp->seeprom_data + eeprom->offset, eeprom->len);
727
	}
I
Ivan Vecera 已提交
728 729
	dma_free_coherent(&adapter->pdev->dev, eeprom_cmd.size, eeprom_cmd.va,
			  eeprom_cmd.dma);
730 731 732 733

	return status;
}

734
const struct ethtool_ops be_ethtool_ops = {
S
Sathya Perla 已提交
735 736
	.get_settings = be_get_settings,
	.get_drvinfo = be_get_drvinfo,
737 738
	.get_wol = be_get_wol,
	.set_wol = be_set_wol,
S
Sathya Perla 已提交
739
	.get_link = ethtool_op_get_link,
740 741
	.get_eeprom_len = be_get_eeprom_len,
	.get_eeprom = be_read_eeprom,
S
Sathya Perla 已提交
742 743 744 745 746 747 748 749
	.get_coalesce = be_get_coalesce,
	.set_coalesce = be_set_coalesce,
	.get_ringparam = be_get_ringparam,
	.get_pauseparam = be_get_pauseparam,
	.set_pauseparam = be_set_pauseparam,
	.get_rx_csum = be_get_rx_csum,
	.set_rx_csum = be_set_rx_csum,
	.get_tx_csum = ethtool_op_get_tx_csum,
750
	.set_tx_csum = ethtool_op_set_tx_hw_csum,
S
Sathya Perla 已提交
751 752 753 754 755
	.get_sg = ethtool_op_get_sg,
	.set_sg = ethtool_op_set_sg,
	.get_tso = ethtool_op_get_tso,
	.set_tso = ethtool_op_set_tso,
	.get_strings = be_get_stat_strings,
756
	.phys_id = be_phys_id,
757
	.get_sset_count = be_get_sset_count,
S
Sathya Perla 已提交
758
	.get_ethtool_stats = be_get_ethtool_stats,
759 760
	.get_regs_len = be_get_reg_len,
	.get_regs = be_get_regs,
761
	.flash_device = be_do_flash,
762
	.self_test = be_self_test,
S
Sathya Perla 已提交
763
};