diff options
Diffstat (limited to 'drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c')
| -rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c | 208 | 
1 files changed, 170 insertions, 38 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 89ddf7f7d7d..9e9e78a5c4d 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -78,8 +78,46 @@ static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {  	"tx numbytes",  }; -#define QLCNIC_STATS_LEN	ARRAY_SIZE(qlcnic_gstrings_stats) +static const char qlcnic_mac_stats_strings [][ETH_GSTRING_LEN] = { +	"mac_tx_frames", +	"mac_tx_bytes", +	"mac_tx_mcast_pkts", +	"mac_tx_bcast_pkts", +	"mac_tx_pause_cnt", +	"mac_tx_ctrl_pkt", +	"mac_tx_lt_64b_pkts", +	"mac_tx_lt_127b_pkts", +	"mac_tx_lt_255b_pkts", +	"mac_tx_lt_511b_pkts", +	"mac_tx_lt_1023b_pkts", +	"mac_tx_lt_1518b_pkts", +	"mac_tx_gt_1518b_pkts", +	"mac_rx_frames", +	"mac_rx_bytes", +	"mac_rx_mcast_pkts", +	"mac_rx_bcast_pkts", +	"mac_rx_pause_cnt", +	"mac_rx_ctrl_pkt", +	"mac_rx_lt_64b_pkts", +	"mac_rx_lt_127b_pkts", +	"mac_rx_lt_255b_pkts", +	"mac_rx_lt_511b_pkts", +	"mac_rx_lt_1023b_pkts", +	"mac_rx_lt_1518b_pkts", +	"mac_rx_gt_1518b_pkts", +	"mac_rx_length_error", +	"mac_rx_length_small", +	"mac_rx_length_large", +	"mac_rx_jabber", +	"mac_rx_dropped", +	"mac_rx_crc_error", +	"mac_align_error", +}; + +#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats) +#define QLCNIC_MAC_STATS_LEN ARRAY_SIZE(qlcnic_mac_stats_strings)  #define QLCNIC_DEVICE_STATS_LEN	ARRAY_SIZE(qlcnic_device_gstrings_stats) +#define QLCNIC_TOTAL_STATS_LEN QLCNIC_STATS_LEN + QLCNIC_MAC_STATS_LEN  static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {  	"Register_Test_on_offline", @@ -644,8 +682,8 @@ static int qlcnic_get_sset_count(struct net_device *dev, int sset)  		return QLCNIC_TEST_LEN;  	case ETH_SS_STATS:  		if (adapter->flags & QLCNIC_ESWITCH_ENABLED) -			return QLCNIC_STATS_LEN + QLCNIC_DEVICE_STATS_LEN; -		return QLCNIC_STATS_LEN; +			return QLCNIC_TOTAL_STATS_LEN + QLCNIC_DEVICE_STATS_LEN; +		return QLCNIC_TOTAL_STATS_LEN;  	default:  		return -EOPNOTSUPP;  	} @@ -851,7 +889,7 @@ static void  qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)  {  	struct qlcnic_adapter *adapter = netdev_priv(dev); -	int index, i; +	int index, i, j;  	switch (stringset) {  	case ETH_SS_TEST: @@ -864,6 +902,11 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)  			       qlcnic_gstrings_stats[index].stat_string,  			       ETH_GSTRING_LEN);  		} +		for (j = 0; j < QLCNIC_MAC_STATS_LEN; index++, j++) { +			memcpy(data + index * ETH_GSTRING_LEN, +			       qlcnic_mac_stats_strings[j], +			       ETH_GSTRING_LEN); +		}  		if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))  			return;  		for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) { @@ -874,22 +917,64 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)  	}  } -#define QLCNIC_FILL_ESWITCH_STATS(VAL1) \ -	(((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) ? 0 : VAL1) -  static void -qlcnic_fill_device_stats(int *index, u64 *data, -		struct __qlcnic_esw_statistics *stats) +qlcnic_fill_stats(int *index, u64 *data, void *stats, int type)  {  	int ind = *index; -	data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->unicast_frames); -	data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->multicast_frames); -	data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->broadcast_frames); -	data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->dropped_frames); -	data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->errors); -	data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->local_frames); -	data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->numbytes); +	if (type == QLCNIC_MAC_STATS) { +		struct qlcnic_mac_statistics *mac_stats = +					(struct qlcnic_mac_statistics *)stats; +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts); +		data[ind++] = +			QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts); +		data[ind++] = +			QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts); +		data[ind++] = +			QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts); +		data[ind++] = +			QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts); +		data[ind++] = +			QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts); +		data[ind++] = +			QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_crc_error); +		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_align_error); +	} else if (type == QLCNIC_ESW_STATS) { +		struct __qlcnic_esw_statistics *esw_stats = +				(struct __qlcnic_esw_statistics *)stats; +		data[ind++] = QLCNIC_FILL_STATS(esw_stats->unicast_frames); +		data[ind++] = QLCNIC_FILL_STATS(esw_stats->multicast_frames); +		data[ind++] = QLCNIC_FILL_STATS(esw_stats->broadcast_frames); +		data[ind++] = QLCNIC_FILL_STATS(esw_stats->dropped_frames); +		data[ind++] = QLCNIC_FILL_STATS(esw_stats->errors); +		data[ind++] = QLCNIC_FILL_STATS(esw_stats->local_frames); +		data[ind++] = QLCNIC_FILL_STATS(esw_stats->numbytes); +	}  	*index = ind;  } @@ -900,6 +985,7 @@ qlcnic_get_ethtool_stats(struct net_device *dev,  {  	struct qlcnic_adapter *adapter = netdev_priv(dev);  	struct qlcnic_esw_statistics port_stats; +	struct qlcnic_mac_statistics mac_stats;  	int index, ret;  	for (index = 0; index < QLCNIC_STATS_LEN; index++) { @@ -911,6 +997,11 @@ qlcnic_get_ethtool_stats(struct net_device *dev,  		     sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);  	} +	/* Retrieve MAC statistics from firmware */ +	memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics)); +	qlcnic_get_mac_stats(adapter, &mac_stats); +	qlcnic_fill_stats(&index, data, &mac_stats, QLCNIC_MAC_STATS); +  	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))  		return; @@ -920,14 +1011,14 @@ qlcnic_get_ethtool_stats(struct net_device *dev,  	if (ret)  		return; -	qlcnic_fill_device_stats(&index, data, &port_stats.rx); +	qlcnic_fill_stats(&index, data, &port_stats.rx, QLCNIC_ESW_STATS);  	ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,  			QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);  	if (ret)  		return; -	qlcnic_fill_device_stats(&index, data, &port_stats.tx); +	qlcnic_fill_stats(&index, data, &port_stats.tx, QLCNIC_ESW_STATS);  }  static int qlcnic_set_led(struct net_device *dev, @@ -1132,11 +1223,21 @@ qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)  	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; +	if (!fw_dump->tmpl_hdr) { +		netdev_err(adapter->netdev, "FW Dump not supported\n"); +		return -ENOTSUPP; +	} +  	if (fw_dump->clr)  		dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;  	else  		dump->len = 0; -	dump->flag = fw_dump->tmpl_hdr->drv_cap_mask; + +	if (!fw_dump->enable) +		dump->flag = ETH_FW_DUMP_DISABLE; +	else +		dump->flag = fw_dump->tmpl_hdr->drv_cap_mask; +  	dump->version = adapter->fw_version;  	return 0;  } @@ -1150,6 +1251,11 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,  	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; +	if (!fw_dump->tmpl_hdr) { +		netdev_err(netdev, "FW Dump not supported\n"); +		return -ENOTSUPP; +	} +  	if (!fw_dump->clr) {  		netdev_info(netdev, "Dump not available\n");  		return -EINVAL; @@ -1177,55 +1283,74 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,  static int  qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)  { -	int ret = 0; +	int i;  	struct qlcnic_adapter *adapter = netdev_priv(netdev);  	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; +	u32 state;  	switch (val->flag) {  	case QLCNIC_FORCE_FW_DUMP_KEY: +		if (!fw_dump->tmpl_hdr) { +			netdev_err(netdev, "FW dump not supported\n"); +			return -ENOTSUPP; +		}  		if (!fw_dump->enable) {  			netdev_info(netdev, "FW dump not enabled\n"); -			return ret; +			return 0;  		}  		if (fw_dump->clr) {  			netdev_info(netdev,  			"Previous dump not cleared, not forcing dump\n"); -			return ret; +			return 0;  		}  		netdev_info(netdev, "Forcing a FW dump\n");  		qlcnic_dev_request_reset(adapter);  		break;  	case QLCNIC_DISABLE_FW_DUMP: -		if (fw_dump->enable) { +		if (fw_dump->enable && fw_dump->tmpl_hdr) {  			netdev_info(netdev, "Disabling FW dump\n");  			fw_dump->enable = 0;  		} -		break; +		return 0;  	case QLCNIC_ENABLE_FW_DUMP: -		if (!fw_dump->enable && fw_dump->tmpl_hdr) { +		if (!fw_dump->tmpl_hdr) { +			netdev_err(netdev, "FW dump not supported\n"); +			return -ENOTSUPP; +		} +		if (!fw_dump->enable) {  			netdev_info(netdev, "Enabling FW dump\n");  			fw_dump->enable = 1;  		} -		break; +		return 0;  	case QLCNIC_FORCE_FW_RESET:  		netdev_info(netdev, "Forcing a FW reset\n");  		qlcnic_dev_request_reset(adapter);  		adapter->flags &= ~QLCNIC_FW_RESET_OWNER; -		break; +		return 0; +	case QLCNIC_SET_QUIESCENT: +	case QLCNIC_RESET_QUIESCENT: +		state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); +		if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) +			netdev_info(netdev, "Device in FAILED state\n"); +		return 0;  	default: -		if (val->flag > QLCNIC_DUMP_MASK_MAX || -			val->flag < QLCNIC_DUMP_MASK_MIN) { -				netdev_info(netdev, -				"Invalid dump level: 0x%x\n", val->flag); -				ret = -EINVAL; -				goto out; +		if (!fw_dump->tmpl_hdr) { +			netdev_err(netdev, "FW dump not supported\n"); +			return -ENOTSUPP; +		} +		for (i = 0; i < ARRAY_SIZE(FW_DUMP_LEVELS); i++) { +			if (val->flag == FW_DUMP_LEVELS[i]) { +				fw_dump->tmpl_hdr->drv_cap_mask = +							val->flag; +				netdev_info(netdev, "Driver mask changed to: 0x%x\n", +					fw_dump->tmpl_hdr->drv_cap_mask); +				return 0; +			}  		} -		fw_dump->tmpl_hdr->drv_cap_mask = val->flag & 0xff; -		netdev_info(netdev, "Driver mask changed to: 0x%x\n", -			fw_dump->tmpl_hdr->drv_cap_mask); +		netdev_info(netdev, "Invalid dump level: 0x%x\n", val->flag); +		return -EINVAL;  	} -out: -	return ret; +	return 0;  }  const struct ethtool_ops qlcnic_ethtool_ops = { @@ -1258,3 +1383,10 @@ const struct ethtool_ops qlcnic_ethtool_ops = {  	.get_dump_data = qlcnic_get_dump_data,  	.set_dump = qlcnic_set_dump,  }; + +const struct ethtool_ops qlcnic_ethtool_failed_ops = { +	.get_settings = qlcnic_get_settings, +	.get_drvinfo = qlcnic_get_drvinfo, +	.set_msglevel = qlcnic_set_msglevel, +	.get_msglevel = qlcnic_get_msglevel, +};  |