diff options
Diffstat (limited to 'drivers/net/ethernet/emulex/benet/be_ethtool.c')
| -rw-r--r-- | drivers/net/ethernet/emulex/benet/be_ethtool.c | 333 | 
1 files changed, 174 insertions, 159 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index b440a1fac77..e2da4d20dd3 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -1,5 +1,5 @@  /* - * Copyright (C) 2005 - 2013 Emulex + * Copyright (C) 2005 - 2014 Emulex   * All rights reserved.   *   * This program is free software; you can redistribute it and/or @@ -116,7 +116,12 @@ static const struct be_ethtool_stat et_stats[] = {  	{DRVSTAT_INFO(rx_drops_mtu)},  	/* Number of packets dropped due to random early drop function */  	{DRVSTAT_INFO(eth_red_drops)}, -	{DRVSTAT_INFO(be_on_die_temperature)} +	{DRVSTAT_INFO(be_on_die_temperature)}, +	{DRVSTAT_INFO(rx_roce_bytes_lsd)}, +	{DRVSTAT_INFO(rx_roce_bytes_msd)}, +	{DRVSTAT_INFO(rx_roce_frames)}, +	{DRVSTAT_INFO(roce_drops_payload_len)}, +	{DRVSTAT_INFO(roce_drops_crc)}  };  #define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats) @@ -127,6 +132,7 @@ static const struct be_ethtool_stat et_rx_stats[] = {  	{DRVSTAT_RX_INFO(rx_bytes)},/* If moving this member see above note */  	{DRVSTAT_RX_INFO(rx_pkts)}, /* If moving this member see above note */  	{DRVSTAT_RX_INFO(rx_compl)}, +	{DRVSTAT_RX_INFO(rx_compl_err)},  	{DRVSTAT_RX_INFO(rx_mcast_pkts)},  	/* Number of page allocation failures while posting receive buffers  	 * to HW. @@ -155,7 +161,9 @@ static const struct be_ethtool_stat et_tx_stats[] = {  	/* Number of times the TX queue was stopped due to lack  	 * of spaces in the TXQ.  	 */ -	{DRVSTAT_TX_INFO(tx_stops)} +	{DRVSTAT_TX_INFO(tx_stops)}, +	/* Pkts dropped in the driver's transmit path */ +	{DRVSTAT_TX_INFO(tx_drv_drops)}  };  #define ETHTOOL_TXSTATS_NUM (ARRAY_SIZE(et_tx_stats)) @@ -174,7 +182,7 @@ static const char et_self_tests[][ETH_GSTRING_LEN] = {  #define BE_NO_LOOPBACK 0xff  static void be_get_drvinfo(struct net_device *netdev, -				struct ethtool_drvinfo *drvinfo) +			   struct ethtool_drvinfo *drvinfo)  {  	struct be_adapter *adapter = netdev_priv(netdev); @@ -194,8 +202,7 @@ static void be_get_drvinfo(struct net_device *netdev,  	drvinfo->eedump_len = 0;  } -static u32 -lancer_cmd_get_file_len(struct be_adapter *adapter, u8 *file_name) +static u32 lancer_cmd_get_file_len(struct be_adapter *adapter, u8 *file_name)  {  	u32 data_read = 0, eof;  	u8 addn_status; @@ -205,14 +212,14 @@ lancer_cmd_get_file_len(struct be_adapter *adapter, u8 *file_name)  	memset(&data_len_cmd, 0, sizeof(data_len_cmd));  	/* data_offset and data_size should be 0 to get reg len */  	status = lancer_cmd_read_object(adapter, &data_len_cmd, 0, 0, -				file_name, &data_read, &eof, &addn_status); +					file_name, &data_read, &eof, +					&addn_status);  	return data_read;  } -static int -lancer_cmd_read_file(struct be_adapter *adapter, u8 *file_name, -		u32 buf_len, void *buf) +static int lancer_cmd_read_file(struct be_adapter *adapter, u8 *file_name, +				u32 buf_len, void *buf)  {  	struct be_dma_mem read_cmd;  	u32 read_len = 0, total_read_len = 0, chunk_size; @@ -222,11 +229,11 @@ lancer_cmd_read_file(struct be_adapter *adapter, u8 *file_name,  	read_cmd.size = LANCER_READ_FILE_CHUNK;  	read_cmd.va = pci_alloc_consistent(adapter->pdev, read_cmd.size, -			&read_cmd.dma); +					   &read_cmd.dma);  	if (!read_cmd.va) {  		dev_err(&adapter->pdev->dev, -				"Memory allocation failure while reading dump\n"); +			"Memory allocation failure while reading dump\n");  		return -ENOMEM;  	} @@ -235,8 +242,8 @@ lancer_cmd_read_file(struct be_adapter *adapter, u8 *file_name,  				LANCER_READ_FILE_CHUNK);  		chunk_size = ALIGN(chunk_size, 4);  		status = lancer_cmd_read_object(adapter, &read_cmd, chunk_size, -				total_read_len, file_name, &read_len, -				&eof, &addn_status); +						total_read_len, file_name, +						&read_len, &eof, &addn_status);  		if (!status) {  			memcpy(buf + total_read_len, read_cmd.va, read_len);  			total_read_len += read_len; @@ -247,13 +254,12 @@ lancer_cmd_read_file(struct be_adapter *adapter, u8 *file_name,  		}  	}  	pci_free_consistent(adapter->pdev, read_cmd.size, read_cmd.va, -			read_cmd.dma); +			    read_cmd.dma);  	return status;  } -static int -be_get_reg_len(struct net_device *netdev) +static int be_get_reg_len(struct net_device *netdev)  {  	struct be_adapter *adapter = netdev_priv(netdev);  	u32 log_size = 0; @@ -264,7 +270,7 @@ be_get_reg_len(struct net_device *netdev)  	if (be_physfn(adapter)) {  		if (lancer_chip(adapter))  			log_size = lancer_cmd_get_file_len(adapter, -					LANCER_FW_DUMP_FILE); +							   LANCER_FW_DUMP_FILE);  		else  			be_cmd_get_reg_len(adapter, &log_size);  	} @@ -280,7 +286,7 @@ be_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf)  		memset(buf, 0, regs->len);  		if (lancer_chip(adapter))  			lancer_cmd_read_file(adapter, LANCER_FW_DUMP_FILE, -					regs->len, buf); +					     regs->len, buf);  		else  			be_cmd_get_regs(adapter, regs->len, buf);  	} @@ -290,19 +296,19 @@ static int be_get_coalesce(struct net_device *netdev,  			   struct ethtool_coalesce *et)  {  	struct be_adapter *adapter = netdev_priv(netdev); -	struct be_eq_obj *eqo = &adapter->eq_obj[0]; +	struct be_aic_obj *aic = &adapter->aic_obj[0]; -	et->rx_coalesce_usecs = eqo->cur_eqd; -	et->rx_coalesce_usecs_high = eqo->max_eqd; -	et->rx_coalesce_usecs_low = eqo->min_eqd; +	et->rx_coalesce_usecs = aic->prev_eqd; +	et->rx_coalesce_usecs_high = aic->max_eqd; +	et->rx_coalesce_usecs_low = aic->min_eqd; -	et->tx_coalesce_usecs = eqo->cur_eqd; -	et->tx_coalesce_usecs_high = eqo->max_eqd; -	et->tx_coalesce_usecs_low = eqo->min_eqd; +	et->tx_coalesce_usecs = aic->prev_eqd; +	et->tx_coalesce_usecs_high = aic->max_eqd; +	et->tx_coalesce_usecs_low = aic->min_eqd; -	et->use_adaptive_rx_coalesce = eqo->enable_aic; -	et->use_adaptive_tx_coalesce = eqo->enable_aic; +	et->use_adaptive_rx_coalesce = aic->enable; +	et->use_adaptive_tx_coalesce = aic->enable;  	return 0;  } @@ -314,22 +320,24 @@ static int be_set_coalesce(struct net_device *netdev,  			   struct ethtool_coalesce *et)  {  	struct be_adapter *adapter = netdev_priv(netdev); +	struct be_aic_obj *aic = &adapter->aic_obj[0];  	struct be_eq_obj *eqo;  	int i;  	for_all_evt_queues(adapter, eqo, i) { -		eqo->enable_aic = et->use_adaptive_rx_coalesce; -		eqo->max_eqd = min(et->rx_coalesce_usecs_high, BE_MAX_EQD); -		eqo->min_eqd = min(et->rx_coalesce_usecs_low, eqo->max_eqd); -		eqo->eqd = et->rx_coalesce_usecs; +		aic->enable = et->use_adaptive_rx_coalesce; +		aic->max_eqd = min(et->rx_coalesce_usecs_high, BE_MAX_EQD); +		aic->min_eqd = min(et->rx_coalesce_usecs_low, aic->max_eqd); +		aic->et_eqd = min(et->rx_coalesce_usecs, aic->max_eqd); +		aic->et_eqd = max(aic->et_eqd, aic->min_eqd); +		aic++;  	}  	return 0;  } -static void -be_get_ethtool_stats(struct net_device *netdev, -		struct ethtool_stats *stats, uint64_t *data) +static void be_get_ethtool_stats(struct net_device *netdev, +				 struct ethtool_stats *stats, uint64_t *data)  {  	struct be_adapter *adapter = netdev_priv(netdev);  	struct be_rx_obj *rxo; @@ -347,10 +355,10 @@ be_get_ethtool_stats(struct net_device *netdev,  		struct be_rx_stats *stats = rx_stats(rxo);  		do { -			start = u64_stats_fetch_begin_bh(&stats->sync); +			start = u64_stats_fetch_begin_irq(&stats->sync);  			data[base] = stats->rx_bytes;  			data[base + 1] = stats->rx_pkts; -		} while (u64_stats_fetch_retry_bh(&stats->sync, start)); +		} while (u64_stats_fetch_retry_irq(&stats->sync, start));  		for (i = 2; i < ETHTOOL_RXSTATS_NUM; i++) {  			p = (u8 *)stats + et_rx_stats[i].offset; @@ -363,26 +371,25 @@ be_get_ethtool_stats(struct net_device *netdev,  		struct be_tx_stats *stats = tx_stats(txo);  		do { -			start = u64_stats_fetch_begin_bh(&stats->sync_compl); +			start = u64_stats_fetch_begin_irq(&stats->sync_compl);  			data[base] = stats->tx_compl; -		} while (u64_stats_fetch_retry_bh(&stats->sync_compl, start)); +		} while (u64_stats_fetch_retry_irq(&stats->sync_compl, start));  		do { -			start = u64_stats_fetch_begin_bh(&stats->sync); +			start = u64_stats_fetch_begin_irq(&stats->sync);  			for (i = 1; i < ETHTOOL_TXSTATS_NUM; i++) {  				p = (u8 *)stats + et_tx_stats[i].offset;  				data[base + i] =  					(et_tx_stats[i].size == sizeof(u64)) ?  						*(u64 *)p : *(u32 *)p;  			} -		} while (u64_stats_fetch_retry_bh(&stats->sync, start)); +		} while (u64_stats_fetch_retry_irq(&stats->sync, start));  		base += ETHTOOL_TXSTATS_NUM;  	}  } -static void -be_get_stat_strings(struct net_device *netdev, uint32_t stringset, -		uint8_t *data) +static void be_get_stat_strings(struct net_device *netdev, uint32_t stringset, +				uint8_t *data)  {  	struct be_adapter *adapter = netdev_priv(netdev);  	int i, j; @@ -632,16 +639,15 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)  	adapter->rx_fc = ecmd->rx_pause;  	status = be_cmd_set_flow_control(adapter, -					adapter->tx_fc, adapter->rx_fc); +					 adapter->tx_fc, adapter->rx_fc);  	if (status)  		dev_warn(&adapter->pdev->dev, "Pause param set failed.\n");  	return status;  } -static int -be_set_phys_id(struct net_device *netdev, -	       enum ethtool_phys_id_state state) +static int be_set_phys_id(struct net_device *netdev, +			  enum ethtool_phys_id_state state)  {  	struct be_adapter *adapter = netdev_priv(netdev); @@ -698,43 +704,41 @@ static int be_set_dump(struct net_device *netdev, struct ethtool_dump *dump)  	return status;  } -static void -be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +static void be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)  {  	struct be_adapter *adapter = netdev_priv(netdev); -	if (be_is_wol_supported(adapter)) { +	if (adapter->wol_cap & BE_WOL_CAP) {  		wol->supported |= WAKE_MAGIC; -		if (adapter->wol) +		if (adapter->wol_en)  			wol->wolopts |= WAKE_MAGIC; -	} else +	} else {  		wol->wolopts = 0; +	}  	memset(&wol->sopass, 0, sizeof(wol->sopass));  } -static int -be_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +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 -EOPNOTSUPP; -	if (!be_is_wol_supported(adapter)) { +	if (!(adapter->wol_cap & BE_WOL_CAP)) {  		dev_warn(&adapter->pdev->dev, "WOL not supported\n");  		return -EOPNOTSUPP;  	}  	if (wol->wolopts & WAKE_MAGIC) -		adapter->wol = true; +		adapter->wol_en = true;  	else -		adapter->wol = false; +		adapter->wol_en = false;  	return 0;  } -static int -be_test_ddr_dma(struct be_adapter *adapter) +static int be_test_ddr_dma(struct be_adapter *adapter)  {  	int ret, i;  	struct be_dma_mem ddrdma_cmd; @@ -750,7 +754,7 @@ be_test_ddr_dma(struct be_adapter *adapter)  	for (i = 0; i < 2; i++) {  		ret = be_cmd_ddr_dma_test(adapter, pattern[i], -					4096, &ddrdma_cmd); +					  4096, &ddrdma_cmd);  		if (ret != 0)  			goto err;  	} @@ -762,20 +766,17 @@ err:  }  static u64 be_loopback_test(struct be_adapter *adapter, u8 loopback_type, -				u64 *status) +			    u64 *status)  { -	be_cmd_set_loopback(adapter, adapter->hba_port_num, -				loopback_type, 1); +	be_cmd_set_loopback(adapter, adapter->hba_port_num, loopback_type, 1);  	*status = be_cmd_loopback_test(adapter, adapter->hba_port_num, -				loopback_type, 1500, -				2, 0xabc); -	be_cmd_set_loopback(adapter, adapter->hba_port_num, -				BE_NO_LOOPBACK, 1); +				       loopback_type, 1500, 2, 0xabc); +	be_cmd_set_loopback(adapter, adapter->hba_port_num, BE_NO_LOOPBACK, 1);  	return *status;  } -static void -be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) +static void be_self_test(struct net_device *netdev, struct ethtool_test *test, +			 u64 *data)  {  	struct be_adapter *adapter = netdev_priv(netdev);  	int status; @@ -790,17 +791,17 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)  	memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM);  	if (test->flags & ETH_TEST_FL_OFFLINE) { -		if (be_loopback_test(adapter, BE_MAC_LOOPBACK, -						&data[0]) != 0) { +		if (be_loopback_test(adapter, BE_MAC_LOOPBACK, &data[0]) != 0)  			test->flags |= ETH_TEST_FL_FAILED; -		} -		if (be_loopback_test(adapter, BE_PHY_LOOPBACK, -						&data[1]) != 0) { -			test->flags |= ETH_TEST_FL_FAILED; -		} -		if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK, -						&data[2]) != 0) { + +		if (be_loopback_test(adapter, BE_PHY_LOOPBACK, &data[1]) != 0)  			test->flags |= ETH_TEST_FL_FAILED; + +		if (test->flags & ETH_TEST_FL_EXTERNAL_LB) { +			if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK, +					     &data[2]) != 0) +				test->flags |= ETH_TEST_FL_FAILED; +			test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;  		}  	} @@ -819,16 +820,14 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)  	}  } -static int -be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) +static int be_do_flash(struct net_device *netdev, struct ethtool_flash *efl)  {  	struct be_adapter *adapter = netdev_priv(netdev);  	return be_load_fw(adapter, efl->data);  } -static int -be_get_eeprom_len(struct net_device *netdev) +static int be_get_eeprom_len(struct net_device *netdev)  {  	struct be_adapter *adapter = netdev_priv(netdev); @@ -838,18 +837,17 @@ be_get_eeprom_len(struct net_device *netdev)  	if (lancer_chip(adapter)) {  		if (be_physfn(adapter))  			return lancer_cmd_get_file_len(adapter, -					LANCER_VPD_PF_FILE); +						       LANCER_VPD_PF_FILE);  		else  			return lancer_cmd_get_file_len(adapter, -					LANCER_VPD_VF_FILE); +						       LANCER_VPD_VF_FILE);  	} else {  		return BE_READ_SEEPROM_LEN;  	}  } -static int -be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, -			uint8_t *data) +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; @@ -862,10 +860,10 @@ be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,  	if (lancer_chip(adapter)) {  		if (be_physfn(adapter))  			return lancer_cmd_read_file(adapter, LANCER_VPD_PF_FILE, -					eeprom->len, data); +						    eeprom->len, data);  		else  			return lancer_cmd_read_file(adapter, LANCER_VPD_VF_FILE, -					eeprom->len, data); +						    eeprom->len, data);  	}  	eeprom->magic = BE_VENDOR_ID | (adapter->pdev->device<<16); @@ -894,73 +892,21 @@ static u32 be_get_msg_level(struct net_device *netdev)  {  	struct be_adapter *adapter = netdev_priv(netdev); -	if (lancer_chip(adapter)) { -		dev_err(&adapter->pdev->dev, "Operation not supported\n"); -		return -EOPNOTSUPP; -	} -  	return adapter->msg_enable;  } -static void be_set_fw_log_level(struct be_adapter *adapter, u32 level) -{ -	struct be_dma_mem extfat_cmd; -	struct be_fat_conf_params *cfgs; -	int status; -	int i, j; - -	memset(&extfat_cmd, 0, sizeof(struct be_dma_mem)); -	extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps); -	extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size, -					     &extfat_cmd.dma); -	if (!extfat_cmd.va) { -		dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n", -			__func__); -		goto err; -	} -	status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd); -	if (!status) { -		cfgs = (struct be_fat_conf_params *)(extfat_cmd.va + -					sizeof(struct be_cmd_resp_hdr)); -		for (i = 0; i < le32_to_cpu(cfgs->num_modules); i++) { -			u32 num_modes = le32_to_cpu(cfgs->module[i].num_modes); -			for (j = 0; j < num_modes; j++) { -				if (cfgs->module[i].trace_lvl[j].mode == -								MODE_UART) -					cfgs->module[i].trace_lvl[j].dbg_lvl = -							cpu_to_le32(level); -			} -		} -		status = be_cmd_set_ext_fat_capabilites(adapter, &extfat_cmd, -							cfgs); -		if (status) -			dev_err(&adapter->pdev->dev, -				"Message level set failed\n"); -	} else { -		dev_err(&adapter->pdev->dev, "Message level get failed\n"); -	} - -	pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va, -			    extfat_cmd.dma); -err: -	return; -} -  static void be_set_msg_level(struct net_device *netdev, u32 level)  {  	struct be_adapter *adapter = netdev_priv(netdev); -	if (lancer_chip(adapter)) { -		dev_err(&adapter->pdev->dev, "Operation not supported\n"); -		return; -	} -  	if (adapter->msg_enable == level)  		return;  	if ((level & NETIF_MSG_HW) != (adapter->msg_enable & NETIF_MSG_HW)) -		be_set_fw_log_level(adapter, level & NETIF_MSG_HW ? -				    FW_LOG_LEVEL_DEFAULT : FW_LOG_LEVEL_FATAL); +		if (BEx_chip(adapter)) +			be_cmd_set_fw_log_level(adapter, level & NETIF_MSG_HW ? +						FW_LOG_LEVEL_DEFAULT : +						FW_LOG_LEVEL_FATAL);  	adapter->msg_enable = level;  	return; @@ -972,27 +918,27 @@ static u64 be_get_rss_hash_opts(struct be_adapter *adapter, u64 flow_type)  	switch (flow_type) {  	case TCP_V4_FLOW: -		if (adapter->rss_flags & RSS_ENABLE_IPV4) +		if (adapter->rss_info.rss_flags & RSS_ENABLE_IPV4)  			data |= RXH_IP_DST | RXH_IP_SRC; -		if (adapter->rss_flags & RSS_ENABLE_TCP_IPV4) +		if (adapter->rss_info.rss_flags & RSS_ENABLE_TCP_IPV4)  			data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;  		break;  	case UDP_V4_FLOW: -		if (adapter->rss_flags & RSS_ENABLE_IPV4) +		if (adapter->rss_info.rss_flags & RSS_ENABLE_IPV4)  			data |= RXH_IP_DST | RXH_IP_SRC; -		if (adapter->rss_flags & RSS_ENABLE_UDP_IPV4) +		if (adapter->rss_info.rss_flags & RSS_ENABLE_UDP_IPV4)  			data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;  		break;  	case TCP_V6_FLOW: -		if (adapter->rss_flags & RSS_ENABLE_IPV6) +		if (adapter->rss_info.rss_flags & RSS_ENABLE_IPV6)  			data |= RXH_IP_DST | RXH_IP_SRC; -		if (adapter->rss_flags & RSS_ENABLE_TCP_IPV6) +		if (adapter->rss_info.rss_flags & RSS_ENABLE_TCP_IPV6)  			data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;  		break;  	case UDP_V6_FLOW: -		if (adapter->rss_flags & RSS_ENABLE_IPV6) +		if (adapter->rss_info.rss_flags & RSS_ENABLE_IPV6)  			data |= RXH_IP_DST | RXH_IP_SRC; -		if (adapter->rss_flags & RSS_ENABLE_UDP_IPV6) +		if (adapter->rss_info.rss_flags & RSS_ENABLE_UDP_IPV6)  			data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;  		break;  	} @@ -1001,7 +947,7 @@ static u64 be_get_rss_hash_opts(struct be_adapter *adapter, u64 flow_type)  }  static int be_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, -		      u32 *rule_locs) +			u32 *rule_locs)  {  	struct be_adapter *adapter = netdev_priv(netdev); @@ -1031,7 +977,7 @@ static int be_set_rss_hash_opts(struct be_adapter *adapter,  	struct be_rx_obj *rxo;  	int status = 0, i, j;  	u8 rsstable[128]; -	u32 rss_flags = adapter->rss_flags; +	u32 rss_flags = adapter->rss_info.rss_flags;  	if (cmd->data != L3_RSS_FLAGS &&  	    cmd->data != (L3_RSS_FLAGS | L4_RSS_FLAGS)) @@ -1078,7 +1024,7 @@ static int be_set_rss_hash_opts(struct be_adapter *adapter,  		return -EINVAL;  	} -	if (rss_flags == adapter->rss_flags) +	if (rss_flags == adapter->rss_info.rss_flags)  		return status;  	if (be_multi_rxq(adapter)) { @@ -1090,9 +1036,11 @@ static int be_set_rss_hash_opts(struct be_adapter *adapter,  			}  		}  	} -	status = be_cmd_rss_config(adapter, rsstable, rss_flags, 128); + +	status = be_cmd_rss_config(adapter, adapter->rss_info.rsstable, +				   rss_flags, 128, adapter->rss_info.rss_hkey);  	if (!status) -		adapter->rss_flags = rss_flags; +		adapter->rss_info.rss_flags = rss_flags;  	return status;  } @@ -1142,6 +1090,69 @@ static int be_set_channels(struct net_device  *netdev,  	return be_update_queues(adapter);  } +static u32 be_get_rxfh_indir_size(struct net_device *netdev) +{ +	return RSS_INDIR_TABLE_LEN; +} + +static u32 be_get_rxfh_key_size(struct net_device *netdev) +{ +	return RSS_HASH_KEY_LEN; +} + +static int be_get_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey) +{ +	struct be_adapter *adapter = netdev_priv(netdev); +	int i; +	struct rss_info *rss = &adapter->rss_info; + +	if (indir) { +		for (i = 0; i < RSS_INDIR_TABLE_LEN; i++) +			indir[i] = rss->rss_queue[i]; +	} + +	if (hkey) +		memcpy(hkey, rss->rss_hkey, RSS_HASH_KEY_LEN); + +	return 0; +} + +static int be_set_rxfh(struct net_device *netdev, const u32 *indir, +		       const u8 *hkey) +{ +	int rc = 0, i, j; +	struct be_adapter *adapter = netdev_priv(netdev); +	u8 rsstable[RSS_INDIR_TABLE_LEN]; + +	if (indir) { +		struct be_rx_obj *rxo; +		for (i = 0; i < RSS_INDIR_TABLE_LEN; i++) { +			j = indir[i]; +			rxo = &adapter->rx_obj[j]; +			rsstable[i] = rxo->rss_id; +			adapter->rss_info.rss_queue[i] = j; +		} +	} else { +		memcpy(rsstable, adapter->rss_info.rsstable, +		       RSS_INDIR_TABLE_LEN); +	} + +	if (!hkey) +		hkey =  adapter->rss_info.rss_hkey; + +	rc = be_cmd_rss_config(adapter, rsstable, +			adapter->rss_info.rss_flags, +			RSS_INDIR_TABLE_LEN, hkey); +	if (rc) { +		adapter->rss_info.rss_flags = RSS_ENABLE_NONE; +		return -EIO; +	} +	memcpy(adapter->rss_info.rss_hkey, hkey, RSS_HASH_KEY_LEN); +	memcpy(adapter->rss_info.rsstable, rsstable, +	       RSS_INDIR_TABLE_LEN); +	return 0; +} +  const struct ethtool_ops be_ethtool_ops = {  	.get_settings = be_get_settings,  	.get_drvinfo = be_get_drvinfo, @@ -1168,6 +1179,10 @@ const struct ethtool_ops be_ethtool_ops = {  	.self_test = be_self_test,  	.get_rxnfc = be_get_rxnfc,  	.set_rxnfc = be_set_rxnfc, +	.get_rxfh_indir_size = be_get_rxfh_indir_size, +	.get_rxfh_key_size = be_get_rxfh_key_size, +	.get_rxfh = be_get_rxfh, +	.set_rxfh = be_set_rxfh,  	.get_channels = be_get_channels,  	.set_channels = be_set_channels  };  | 
