diff options
Diffstat (limited to 'drivers/net/ethernet/intel/ice/ice_ethtool.c')
| -rw-r--r-- | drivers/net/ethernet/intel/ice/ice_ethtool.c | 52 | 
1 files changed, 39 insertions, 13 deletions
| diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 1db304c01d10..c71a9b528d6d 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -26,7 +26,7 @@ static int ice_q_stats_len(struct net_device *netdev)  {  	struct ice_netdev_priv *np = netdev_priv(netdev); -	return ((np->vsi->num_txq + np->vsi->num_rxq) * +	return ((np->vsi->alloc_txq + np->vsi->alloc_rxq) *  		(sizeof(struct ice_q_stats) / sizeof(u64)));  } @@ -218,7 +218,7 @@ static void ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data)  			p += ETH_GSTRING_LEN;  		} -		ice_for_each_txq(vsi, i) { +		ice_for_each_alloc_txq(vsi, i) {  			snprintf(p, ETH_GSTRING_LEN,  				 "tx-queue-%u.tx_packets", i);  			p += ETH_GSTRING_LEN; @@ -226,7 +226,7 @@ static void ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data)  			p += ETH_GSTRING_LEN;  		} -		ice_for_each_rxq(vsi, i) { +		ice_for_each_alloc_rxq(vsi, i) {  			snprintf(p, ETH_GSTRING_LEN,  				 "rx-queue-%u.rx_packets", i);  			p += ETH_GSTRING_LEN; @@ -253,6 +253,24 @@ static int ice_get_sset_count(struct net_device *netdev, int sset)  {  	switch (sset) {  	case ETH_SS_STATS: +		/* The number (and order) of strings reported *must* remain +		 * constant for a given netdevice. This function must not +		 * report a different number based on run time parameters +		 * (such as the number of queues in use, or the setting of +		 * a private ethtool flag). This is due to the nature of the +		 * ethtool stats API. +		 * +		 * User space programs such as ethtool must make 3 separate +		 * ioctl requests, one for size, one for the strings, and +		 * finally one for the stats. Since these cross into +		 * user space, changes to the number or size could result in +		 * undefined memory access or incorrect string<->value +		 * correlations for statistics. +		 * +		 * Even if it appears to be safe, changes to the size or +		 * order of strings will suffer from race conditions and are +		 * not safe. +		 */  		return ICE_ALL_STATS_LEN(netdev);  	default:  		return -EOPNOTSUPP; @@ -280,18 +298,26 @@ ice_get_ethtool_stats(struct net_device *netdev,  	/* populate per queue stats */  	rcu_read_lock(); -	ice_for_each_txq(vsi, j) { +	ice_for_each_alloc_txq(vsi, j) {  		ring = READ_ONCE(vsi->tx_rings[j]); -		if (!ring) -			continue; -		data[i++] = ring->stats.pkts; -		data[i++] = ring->stats.bytes; +		if (ring) { +			data[i++] = ring->stats.pkts; +			data[i++] = ring->stats.bytes; +		} else { +			data[i++] = 0; +			data[i++] = 0; +		}  	} -	ice_for_each_rxq(vsi, j) { +	ice_for_each_alloc_rxq(vsi, j) {  		ring = READ_ONCE(vsi->rx_rings[j]); -		data[i++] = ring->stats.pkts; -		data[i++] = ring->stats.bytes; +		if (ring) { +			data[i++] = ring->stats.pkts; +			data[i++] = ring->stats.bytes; +		} else { +			data[i++] = 0; +			data[i++] = 0; +		}  	}  	rcu_read_unlock(); @@ -519,7 +545,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)  		goto done;  	} -	for (i = 0; i < vsi->num_txq; i++) { +	for (i = 0; i < vsi->alloc_txq; i++) {  		/* clone ring and setup updated count */  		tx_rings[i] = *vsi->tx_rings[i];  		tx_rings[i].count = new_tx_cnt; @@ -551,7 +577,7 @@ process_rx:  		goto done;  	} -	for (i = 0; i < vsi->num_rxq; i++) { +	for (i = 0; i < vsi->alloc_rxq; i++) {  		/* clone ring and setup updated count */  		rx_rings[i] = *vsi->rx_rings[i];  		rx_rings[i].count = new_rx_cnt; |