diff options
Diffstat (limited to 'drivers/net/ethernet/emulex/benet/be_ethtool.c')
| -rw-r--r-- | drivers/net/ethernet/emulex/benet/be_ethtool.c | 177 | 
1 files changed, 167 insertions, 10 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index 76b302f30c8..5733cde88e2 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 - 2011 Emulex + * Copyright (C) 2005 - 2013 Emulex   * All rights reserved.   *   * This program is free software; you can redistribute it and/or @@ -54,7 +54,7 @@ static const struct be_ethtool_stat et_stats[] = {  	/* Received packets dropped when they don't pass the unicast or  	 * multicast address filtering.  	 */ -	{DRVSTAT_INFO(rx_address_mismatch_drops)}, +	{DRVSTAT_INFO(rx_address_filtered)},  	/* Received packets dropped when IP packet length field is less than  	 * the IP header length field.  	 */ @@ -680,7 +680,8 @@ be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)  	if (be_is_wol_supported(adapter)) {  		wol->supported |= WAKE_MAGIC; -		wol->wolopts |= WAKE_MAGIC; +		if (adapter->wol) +			wol->wolopts |= WAKE_MAGIC;  	} else  		wol->wolopts = 0;  	memset(&wol->sopass, 0, sizeof(wol->sopass)); @@ -719,10 +720,8 @@ be_test_ddr_dma(struct be_adapter *adapter)  	ddrdma_cmd.size = sizeof(struct be_cmd_req_ddrdma_test);  	ddrdma_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, ddrdma_cmd.size,  					   &ddrdma_cmd.dma, GFP_KERNEL); -	if (!ddrdma_cmd.va) { -		dev_err(&adapter->pdev->dev, "Memory allocation failure\n"); +	if (!ddrdma_cmd.va)  		return -ENOMEM; -	}  	for (i = 0; i < 2; i++) {  		ret = be_cmd_ddr_dma_test(adapter, pattern[i], @@ -757,6 +756,12 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)  	int status;  	u8 link_status = 0; +	if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC) { +		dev_err(&adapter->pdev->dev, "Self test not supported\n"); +		test->flags |= ETH_TEST_FL_FAILED; +		return; +	} +  	memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM);  	if (test->flags & ETH_TEST_FL_OFFLINE) { @@ -845,11 +850,8 @@ be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,  	eeprom_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, eeprom_cmd.size,  					   &eeprom_cmd.dma, GFP_KERNEL); -	if (!eeprom_cmd.va) { -		dev_err(&adapter->pdev->dev, -			"Memory allocation failure. Could not read eeprom\n"); +	if (!eeprom_cmd.va)  		return -ENOMEM; -	}  	status = be_cmd_get_seeprom_data(adapter, &eeprom_cmd); @@ -939,6 +941,159 @@ static void be_set_msg_level(struct net_device *netdev, u32 level)  	return;  } +static u64 be_get_rss_hash_opts(struct be_adapter *adapter, u64 flow_type) +{ +	u64 data = 0; + +	switch (flow_type) { +	case TCP_V4_FLOW: +		if (adapter->rss_flags & RSS_ENABLE_IPV4) +			data |= RXH_IP_DST | RXH_IP_SRC; +		if (adapter->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) +			data |= RXH_IP_DST | RXH_IP_SRC; +		if (adapter->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) +			data |= RXH_IP_DST | RXH_IP_SRC; +		if (adapter->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) +			data |= RXH_IP_DST | RXH_IP_SRC; +		if (adapter->rss_flags & RSS_ENABLE_UDP_IPV6) +			data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; +		break; +	} + +	return data; +} + +static int be_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, +		      u32 *rule_locs) +{ +	struct be_adapter *adapter = netdev_priv(netdev); + +	if (!be_multi_rxq(adapter)) { +		dev_info(&adapter->pdev->dev, +			 "ethtool::get_rxnfc: RX flow hashing is disabled\n"); +		return -EINVAL; +	} + +	switch (cmd->cmd) { +	case ETHTOOL_GRXFH: +		cmd->data = be_get_rss_hash_opts(adapter, cmd->flow_type); +		break; +	case ETHTOOL_GRXRINGS: +		cmd->data = adapter->num_rx_qs - 1; +		break; +	default: +		return -EINVAL; +	} + +	return 0; +} + +static int be_set_rss_hash_opts(struct be_adapter *adapter, +				struct ethtool_rxnfc *cmd) +{ +	struct be_rx_obj *rxo; +	int status = 0, i, j; +	u8 rsstable[128]; +	u32 rss_flags = adapter->rss_flags; + +	if (cmd->data != L3_RSS_FLAGS && +	    cmd->data != (L3_RSS_FLAGS | L4_RSS_FLAGS)) +		return -EINVAL; + +	switch (cmd->flow_type) { +	case TCP_V4_FLOW: +		if (cmd->data == L3_RSS_FLAGS) +			rss_flags &= ~RSS_ENABLE_TCP_IPV4; +		else if (cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS)) +			rss_flags |= RSS_ENABLE_IPV4 | +					RSS_ENABLE_TCP_IPV4; +		break; +	case TCP_V6_FLOW: +		if (cmd->data == L3_RSS_FLAGS) +			rss_flags &= ~RSS_ENABLE_TCP_IPV6; +		else if (cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS)) +			rss_flags |= RSS_ENABLE_IPV6 | +					RSS_ENABLE_TCP_IPV6; +		break; +	case UDP_V4_FLOW: +		if ((cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS)) && +		    BEx_chip(adapter)) +			return -EINVAL; + +		if (cmd->data == L3_RSS_FLAGS) +			rss_flags &= ~RSS_ENABLE_UDP_IPV4; +		else if (cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS)) +			rss_flags |= RSS_ENABLE_IPV4 | +					RSS_ENABLE_UDP_IPV4; +		break; +	case UDP_V6_FLOW: +		if ((cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS)) && +		    BEx_chip(adapter)) +			return -EINVAL; + +		if (cmd->data == L3_RSS_FLAGS) +			rss_flags &= ~RSS_ENABLE_UDP_IPV6; +		else if (cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS)) +			rss_flags |= RSS_ENABLE_IPV6 | +					RSS_ENABLE_UDP_IPV6; +		break; +	default: +		return -EINVAL; +	} + +	if (rss_flags == adapter->rss_flags) +		return status; + +	if (be_multi_rxq(adapter)) { +		for (j = 0; j < 128; j += adapter->num_rx_qs - 1) { +			for_all_rss_queues(adapter, rxo, i) { +				if ((j + i) >= 128) +					break; +				rsstable[j + i] = rxo->rss_id; +			} +		} +	} +	status = be_cmd_rss_config(adapter, rsstable, rss_flags, 128); +	if (!status) +		adapter->rss_flags = rss_flags; + +	return status; +} + +static int be_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) +{ +	struct be_adapter *adapter = netdev_priv(netdev); +	int status = 0; + +	if (!be_multi_rxq(adapter)) { +		dev_err(&adapter->pdev->dev, +			"ethtool::set_rxnfc: RX flow hashing is disabled\n"); +		return -EINVAL; +	} + +	switch (cmd->cmd) { +	case ETHTOOL_SRXFH: +		status = be_set_rss_hash_opts(adapter, cmd); +		break; +	default: +		return -EINVAL; +	} + +	return status; +} +  const struct ethtool_ops be_ethtool_ops = {  	.get_settings = be_get_settings,  	.get_drvinfo = be_get_drvinfo, @@ -962,4 +1117,6 @@ const struct ethtool_ops be_ethtool_ops = {  	.get_regs = be_get_regs,  	.flash_device = be_do_flash,  	.self_test = be_self_test, +	.get_rxnfc = be_get_rxnfc, +	.set_rxnfc = be_set_rxnfc,  };  |