Commit 3c9e154d authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'Enhance-current-features-in-ena-driver'



Sameeh Jubran says:

====================
Enhance current features in ena driver

This series adds the following:
* Exposes new device stats using ethtool.
* Adds and exposes the stats of xdp TX queues through ethtool.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e5484658 4cd28b21
Loading
Loading
Loading
Loading
+36 −1
Original line number Diff line number Diff line
@@ -117,6 +117,8 @@ enum ena_admin_completion_policy_type {
enum ena_admin_get_stats_type {
	ENA_ADMIN_GET_STATS_TYPE_BASIC              = 0,
	ENA_ADMIN_GET_STATS_TYPE_EXTENDED           = 1,
	/* extra HW stats for specific network interface */
	ENA_ADMIN_GET_STATS_TYPE_ENI                = 2,
};

enum ena_admin_get_stats_scope {
@@ -410,10 +412,43 @@ struct ena_admin_basic_stats {
	u32 tx_drops_high;
};

/* ENI Statistics Command. */
struct ena_admin_eni_stats {
	/* The number of packets shaped due to inbound aggregate BW
	 * allowance being exceeded
	 */
	u64 bw_in_allowance_exceeded;

	/* The number of packets shaped due to outbound aggregate BW
	 * allowance being exceeded
	 */
	u64 bw_out_allowance_exceeded;

	/* The number of packets shaped due to PPS allowance being exceeded */
	u64 pps_allowance_exceeded;

	/* The number of packets shaped due to connection tracking
	 * allowance being exceeded and leading to failure in establishment
	 * of new connections
	 */
	u64 conntrack_allowance_exceeded;

	/* The number of packets shaped due to linklocal packet rate
	 * allowance being exceeded
	 */
	u64 linklocal_allowance_exceeded;
};

struct ena_admin_acq_get_stats_resp {
	struct ena_admin_acq_common_desc acq_common_desc;

	union {
		u64 raw[7];

		struct ena_admin_basic_stats basic_stats;

		struct ena_admin_eni_stats eni_stats;
	} u;
};

struct ena_admin_get_set_feature_common_desc {
+17 −2
Original line number Diff line number Diff line
@@ -2167,6 +2167,21 @@ static int ena_get_dev_stats(struct ena_com_dev *ena_dev,
	return ret;
}

int ena_com_get_eni_stats(struct ena_com_dev *ena_dev,
			  struct ena_admin_eni_stats *stats)
{
	struct ena_com_stats_ctx ctx;
	int ret;

	memset(&ctx, 0x0, sizeof(ctx));
	ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_ENI);
	if (likely(ret == 0))
		memcpy(stats, &ctx.get_resp.u.eni_stats,
		       sizeof(ctx.get_resp.u.eni_stats));

	return ret;
}

int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev,
				struct ena_admin_basic_stats *stats)
{
@@ -2176,8 +2191,8 @@ int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev,
	memset(&ctx, 0x0, sizeof(ctx));
	ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_BASIC);
	if (likely(ret == 0))
		memcpy(stats, &ctx.get_resp.basic_stats,
		       sizeof(ctx.get_resp.basic_stats));
		memcpy(stats, &ctx.get_resp.u.basic_stats,
		       sizeof(ctx.get_resp.u.basic_stats));

	return ret;
}
+9 −0
Original line number Diff line number Diff line
@@ -616,6 +616,15 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev,
				struct ena_admin_basic_stats *stats);

/* ena_com_get_eni_stats - Get extended network interface statistics
 * @ena_dev: ENA communication layer struct
 * @stats: stats return value
 *
 * @return: 0 on Success and negative value otherwise.
 */
int ena_com_get_eni_stats(struct ena_com_dev *ena_dev,
			  struct ena_admin_eni_stats *stats);

/* ena_com_set_dev_mtu - Configure the device mtu.
 * @ena_dev: ENA communication layer struct
 * @mtu: mtu value
+125 −45
Original line number Diff line number Diff line
@@ -41,12 +41,17 @@ struct ena_stats {

#define ENA_STAT_ENA_COM_ENTRY(stat) { \
	.name = #stat, \
	.stat_offset = offsetof(struct ena_com_stats_admin, stat) \
	.stat_offset = offsetof(struct ena_com_stats_admin, stat) / sizeof(u64) \
}

#define ENA_STAT_ENTRY(stat, stat_type) { \
	.name = #stat, \
	.stat_offset = offsetof(struct ena_stats_##stat_type, stat) \
	.stat_offset = offsetof(struct ena_stats_##stat_type, stat) / sizeof(u64) \
}

#define ENA_STAT_HW_ENTRY(stat, stat_type) { \
	.name = #stat, \
	.stat_offset = offsetof(struct ena_admin_##stat_type, stat) / sizeof(u64) \
}

#define ENA_STAT_RX_ENTRY(stat) \
@@ -58,6 +63,9 @@ struct ena_stats {
#define ENA_STAT_GLOBAL_ENTRY(stat) \
	ENA_STAT_ENTRY(stat, dev)

#define ENA_STAT_ENI_ENTRY(stat) \
	ENA_STAT_HW_ENTRY(stat, eni_stats)

static const struct ena_stats ena_stats_global_strings[] = {
	ENA_STAT_GLOBAL_ENTRY(tx_timeout),
	ENA_STAT_GLOBAL_ENTRY(suspend),
@@ -68,6 +76,14 @@ static const struct ena_stats ena_stats_global_strings[] = {
	ENA_STAT_GLOBAL_ENTRY(admin_q_pause),
};

static const struct ena_stats ena_stats_eni_strings[] = {
	ENA_STAT_ENI_ENTRY(bw_in_allowance_exceeded),
	ENA_STAT_ENI_ENTRY(bw_out_allowance_exceeded),
	ENA_STAT_ENI_ENTRY(pps_allowance_exceeded),
	ENA_STAT_ENI_ENTRY(conntrack_allowance_exceeded),
	ENA_STAT_ENI_ENTRY(linklocal_allowance_exceeded),
};

static const struct ena_stats ena_stats_tx_strings[] = {
	ENA_STAT_TX_ENTRY(cnt),
	ENA_STAT_TX_ENTRY(bytes),
@@ -100,6 +116,11 @@ static const struct ena_stats ena_stats_rx_strings[] = {
	ENA_STAT_RX_ENTRY(bad_req_id),
	ENA_STAT_RX_ENTRY(empty_rx_ring),
	ENA_STAT_RX_ENTRY(csum_unchecked),
	ENA_STAT_RX_ENTRY(xdp_aborted),
	ENA_STAT_RX_ENTRY(xdp_drop),
	ENA_STAT_RX_ENTRY(xdp_pass),
	ENA_STAT_RX_ENTRY(xdp_tx),
	ENA_STAT_RX_ENTRY(xdp_invalid),
};

static const struct ena_stats ena_stats_ena_com_strings[] = {
@@ -114,6 +135,8 @@ static const struct ena_stats ena_stats_ena_com_strings[] = {
#define ENA_STATS_ARRAY_TX		ARRAY_SIZE(ena_stats_tx_strings)
#define ENA_STATS_ARRAY_RX		ARRAY_SIZE(ena_stats_rx_strings)
#define ENA_STATS_ARRAY_ENA_COM		ARRAY_SIZE(ena_stats_ena_com_strings)
#define ENA_STATS_ARRAY_ENI(adapter)	\
	(ARRAY_SIZE(ena_stats_eni_strings) * (adapter)->eni_stats_supported)

static void ena_safe_update_stat(u64 *src, u64 *dst,
				 struct u64_stats_sync *syncp)
@@ -134,32 +157,33 @@ static void ena_queue_stats(struct ena_adapter *adapter, u64 **data)
	u64 *ptr;
	int i, j;

	for (i = 0; i < adapter->num_io_queues; i++) {
	for (i = 0; i < adapter->num_io_queues + adapter->xdp_num_queues; i++) {
		/* Tx stats */
		ring = &adapter->tx_ring[i];

		for (j = 0; j < ENA_STATS_ARRAY_TX; j++) {
			ena_stats = &ena_stats_tx_strings[j];

			ptr = (u64 *)((uintptr_t)&ring->tx_stats +
				(uintptr_t)ena_stats->stat_offset);
			ptr = (u64 *)&ring->tx_stats + ena_stats->stat_offset;

			ena_safe_update_stat(ptr, (*data)++, &ring->syncp);
		}

		/* XDP TX queues don't have a RX queue counterpart */
		if (!ENA_IS_XDP_INDEX(adapter, i)) {
			/* Rx stats */
			ring = &adapter->rx_ring[i];

			for (j = 0; j < ENA_STATS_ARRAY_RX; j++) {
				ena_stats = &ena_stats_rx_strings[j];

			ptr = (u64 *)((uintptr_t)&ring->rx_stats +
				(uintptr_t)ena_stats->stat_offset);
				ptr = (u64 *)&ring->rx_stats +
					ena_stats->stat_offset;

				ena_safe_update_stat(ptr, (*data)++, &ring->syncp);
			}
		}
	}
}

static void ena_dev_admin_queue_stats(struct ena_adapter *adapter, u64 **data)
{
@@ -170,18 +194,17 @@ static void ena_dev_admin_queue_stats(struct ena_adapter *adapter, u64 **data)
	for (i = 0; i < ENA_STATS_ARRAY_ENA_COM; i++) {
		ena_stats = &ena_stats_ena_com_strings[i];

		ptr = (u64 *)((uintptr_t)&adapter->ena_dev->admin_queue.stats +
			(uintptr_t)ena_stats->stat_offset);
		ptr = (u64 *)&adapter->ena_dev->admin_queue.stats +
			ena_stats->stat_offset;

		*(*data)++ = *ptr;
	}
}

static void ena_get_ethtool_stats(struct net_device *netdev,
				  struct ethtool_stats *stats,
				  u64 *data)
static void ena_get_stats(struct ena_adapter *adapter,
			  u64 *data,
			  bool eni_stats_needed)
{
	struct ena_adapter *adapter = netdev_priv(netdev);
	const struct ena_stats *ena_stats;
	u64 *ptr;
	int i;
@@ -189,16 +212,48 @@ static void ena_get_ethtool_stats(struct net_device *netdev,
	for (i = 0; i < ENA_STATS_ARRAY_GLOBAL; i++) {
		ena_stats = &ena_stats_global_strings[i];

		ptr = (u64 *)((uintptr_t)&adapter->dev_stats +
			(uintptr_t)ena_stats->stat_offset);
		ptr = (u64 *)&adapter->dev_stats + ena_stats->stat_offset;

		ena_safe_update_stat(ptr, data++, &adapter->syncp);
	}

	if (eni_stats_needed) {
		ena_update_hw_stats(adapter);
		for (i = 0; i < ENA_STATS_ARRAY_ENI(adapter); i++) {
			ena_stats = &ena_stats_eni_strings[i];

			ptr = (u64 *)&adapter->eni_stats +
				ena_stats->stat_offset;

			ena_safe_update_stat(ptr, data++, &adapter->syncp);
		}
	}

	ena_queue_stats(adapter, &data);
	ena_dev_admin_queue_stats(adapter, &data);
}

static void ena_get_ethtool_stats(struct net_device *netdev,
				  struct ethtool_stats *stats,
				  u64 *data)
{
	struct ena_adapter *adapter = netdev_priv(netdev);

	ena_get_stats(adapter, data, adapter->eni_stats_supported);
}

static int ena_get_sw_stats_count(struct ena_adapter *adapter)
{
	return adapter->num_io_queues * (ENA_STATS_ARRAY_TX + ENA_STATS_ARRAY_RX)
		+ adapter->xdp_num_queues * ENA_STATS_ARRAY_TX
		+ ENA_STATS_ARRAY_GLOBAL + ENA_STATS_ARRAY_ENA_COM;
}

static int ena_get_hw_stats_count(struct ena_adapter *adapter)
{
	return ENA_STATS_ARRAY_ENI(adapter);
}

int ena_get_sset_count(struct net_device *netdev, int sset)
{
	struct ena_adapter *adapter = netdev_priv(netdev);
@@ -206,25 +261,31 @@ int ena_get_sset_count(struct net_device *netdev, int sset)
	if (sset != ETH_SS_STATS)
		return -EOPNOTSUPP;

	return adapter->num_io_queues * (ENA_STATS_ARRAY_TX + ENA_STATS_ARRAY_RX)
		+ ENA_STATS_ARRAY_GLOBAL + ENA_STATS_ARRAY_ENA_COM;
	return ena_get_sw_stats_count(adapter) + ena_get_hw_stats_count(adapter);
}

static void ena_queue_strings(struct ena_adapter *adapter, u8 **data)
{
	const struct ena_stats *ena_stats;
	bool is_xdp;
	int i, j;

	for (i = 0; i < adapter->num_io_queues; i++) {
	for (i = 0; i < adapter->num_io_queues + adapter->xdp_num_queues; i++) {
		is_xdp = ENA_IS_XDP_INDEX(adapter, i);
		/* Tx stats */
		for (j = 0; j < ENA_STATS_ARRAY_TX; j++) {
			ena_stats = &ena_stats_tx_strings[j];

			snprintf(*data, ETH_GSTRING_LEN,
				 "queue_%u_tx_%s", i, ena_stats->name);
				 "queue_%u_%s_%s", i,
				 is_xdp ? "xdp_tx" : "tx", ena_stats->name);
			(*data) += ETH_GSTRING_LEN;
		}
		/* Rx stats */

		if (!is_xdp) {
			/* RX stats, in XDP there isn't a RX queue
			 * counterpart
			 */
			for (j = 0; j < ENA_STATS_ARRAY_RX; j++) {
				ena_stats = &ena_stats_rx_strings[j];

@@ -234,6 +295,7 @@ static void ena_queue_strings(struct ena_adapter *adapter, u8 **data)
			}
		}
	}
}

static void ena_com_dev_strings(u8 **data)
{
@@ -249,25 +311,43 @@ static void ena_com_dev_strings(u8 **data)
	}
}

static void ena_get_strings(struct net_device *netdev, u32 sset, u8 *data)
static void ena_get_strings(struct ena_adapter *adapter,
			    u8 *data,
			    bool eni_stats_needed)
{
	struct ena_adapter *adapter = netdev_priv(netdev);
	const struct ena_stats *ena_stats;
	int i;

	if (sset != ETH_SS_STATS)
		return;

	for (i = 0; i < ENA_STATS_ARRAY_GLOBAL; i++) {
		ena_stats = &ena_stats_global_strings[i];
		memcpy(data, ena_stats->name, ETH_GSTRING_LEN);
		data += ETH_GSTRING_LEN;
	}

	if (eni_stats_needed) {
		for (i = 0; i < ENA_STATS_ARRAY_ENI(adapter); i++) {
			ena_stats = &ena_stats_eni_strings[i];
			memcpy(data, ena_stats->name, ETH_GSTRING_LEN);
			data += ETH_GSTRING_LEN;
		}
	}

	ena_queue_strings(adapter, &data);
	ena_com_dev_strings(&data);
}

static void ena_get_ethtool_strings(struct net_device *netdev,
				    u32 sset,
				    u8 *data)
{
	struct ena_adapter *adapter = netdev_priv(netdev);

	if (sset != ETH_SS_STATS)
		return;

	ena_get_strings(adapter, data, adapter->eni_stats_supported);
}

static int ena_get_link_ksettings(struct net_device *netdev,
				  struct ethtool_link_ksettings *link_ksettings)
{
@@ -847,7 +927,7 @@ static const struct ethtool_ops ena_ethtool_ops = {
	.get_ringparam		= ena_get_ringparam,
	.set_ringparam		= ena_set_ringparam,
	.get_sset_count         = ena_get_sset_count,
	.get_strings		= ena_get_strings,
	.get_strings		= ena_get_ethtool_strings,
	.get_ethtool_stats      = ena_get_ethtool_stats,
	.get_rxnfc		= ena_get_rxnfc,
	.set_rxnfc		= ena_set_rxnfc,
@@ -875,7 +955,7 @@ static void ena_dump_stats_ex(struct ena_adapter *adapter, u8 *buf)
	int strings_num;
	int i, rc;

	strings_num = ena_get_sset_count(netdev, ETH_SS_STATS);
	strings_num = ena_get_sw_stats_count(adapter);
	if (strings_num <= 0) {
		netif_err(adapter, drv, netdev, "Can't get stats num\n");
		return;
@@ -895,13 +975,13 @@ static void ena_dump_stats_ex(struct ena_adapter *adapter, u8 *buf)
				GFP_ATOMIC);
	if (!data_buf) {
		netif_err(adapter, drv, netdev,
			  "failed to allocate data buf\n");
			  "Failed to allocate data buf\n");
		devm_kfree(&adapter->pdev->dev, strings_buf);
		return;
	}

	ena_get_strings(netdev, ETH_SS_STATS, strings_buf);
	ena_get_ethtool_stats(netdev, NULL, data_buf);
	ena_get_strings(adapter, strings_buf, false);
	ena_get_stats(adapter, data_buf, false);

	/* If there is a buffer, dump stats, otherwise print them to dmesg */
	if (buf)
+36 −3
Original line number Diff line number Diff line
@@ -365,6 +365,7 @@ static int ena_xdp_execute(struct ena_ring *rx_ring,
{
	struct bpf_prog *xdp_prog;
	u32 verdict = XDP_PASS;
	u64 *xdp_stat;

	rcu_read_lock();
	xdp_prog = READ_ONCE(rx_ring->xdp_bpf_prog);
@@ -374,17 +375,31 @@ static int ena_xdp_execute(struct ena_ring *rx_ring,

	verdict = bpf_prog_run_xdp(xdp_prog, xdp);

	if (verdict == XDP_TX)
	if (verdict == XDP_TX) {
		ena_xdp_xmit_buff(rx_ring->netdev,
				  xdp,
				  rx_ring->qid + rx_ring->adapter->num_io_queues,
				  rx_info);
	else if (unlikely(verdict == XDP_ABORTED))

		xdp_stat = &rx_ring->rx_stats.xdp_tx;
	} else if (unlikely(verdict == XDP_ABORTED)) {
		trace_xdp_exception(rx_ring->netdev, xdp_prog, verdict);
	else if (unlikely(verdict > XDP_TX))
		xdp_stat = &rx_ring->rx_stats.xdp_aborted;
	} else if (unlikely(verdict == XDP_DROP)) {
		xdp_stat = &rx_ring->rx_stats.xdp_drop;
	} else if (unlikely(verdict == XDP_PASS)) {
		xdp_stat = &rx_ring->rx_stats.xdp_pass;
	} else {
		bpf_warn_invalid_xdp_action(verdict);
		xdp_stat = &rx_ring->rx_stats.xdp_invalid;
	}

	u64_stats_update_begin(&rx_ring->syncp);
	(*xdp_stat)++;
	u64_stats_update_end(&rx_ring->syncp);
out:
	rcu_read_unlock();

	return verdict;
}

@@ -3178,6 +3193,19 @@ err:
	ena_com_delete_debug_area(adapter->ena_dev);
}

int ena_update_hw_stats(struct ena_adapter *adapter)
{
	int rc = 0;

	rc = ena_com_get_eni_stats(adapter->ena_dev, &adapter->eni_stats);
	if (rc) {
		dev_info_once(&adapter->pdev->dev, "Failed to get ENI stats\n");
		return rc;
	}

	return 0;
}

static void ena_get_stats64(struct net_device *netdev,
			    struct rtnl_link_stats64 *stats)
{
@@ -4296,6 +4324,11 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)

	ena_config_debug_area(adapter);

	if (!ena_update_hw_stats(adapter))
		adapter->eni_stats_supported = true;
	else
		adapter->eni_stats_supported = false;

	memcpy(adapter->netdev->perm_addr, adapter->mac_addr, netdev->addr_len);

	netif_carrier_off(netdev);
Loading