Commit eda5891f authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'ena-driver-metrics-changes'

David Arinzon says:

====================
ENA driver metrics changes

This patchset contains an introduction of new metrics
available to ENA users.
====================

Link: https://patch.msgid.link/20240909084704.13856-1-darinzon@amazon.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 46ae4d0a 403cdc41
......@@ -230,6 +230,11 @@ per-queue stats) from the device.
In addition the driver logs the stats to syslog upon device reset.
On supported instance types, the statistics will also include the
ENA Express data (fields prefixed with `ena_srd`). For a complete
documentation of ENA Express data refer to
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ena-express.html#ena-express-monitor
MTU
===
......
......@@ -7,6 +7,21 @@
#define ENA_ADMIN_RSS_KEY_PARTS 10
#define ENA_ADMIN_CUSTOMER_METRICS_SUPPORT_MASK 0x3F
#define ENA_ADMIN_CUSTOMER_METRICS_MIN_SUPPORT_MASK 0x1F
/* customer metrics - in correlation with
* ENA_ADMIN_CUSTOMER_METRICS_SUPPORT_MASK
*/
enum ena_admin_customer_metrics_id {
ENA_ADMIN_BW_IN_ALLOWANCE_EXCEEDED = 0,
ENA_ADMIN_BW_OUT_ALLOWANCE_EXCEEDED = 1,
ENA_ADMIN_PPS_ALLOWANCE_EXCEEDED = 2,
ENA_ADMIN_CONNTRACK_ALLOWANCE_EXCEEDED = 3,
ENA_ADMIN_LINKLOCAL_ALLOWANCE_EXCEEDED = 4,
ENA_ADMIN_CONNTRACK_ALLOWANCE_AVAILABLE = 5,
};
enum ena_admin_aq_opcode {
ENA_ADMIN_CREATE_SQ = 1,
ENA_ADMIN_DESTROY_SQ = 2,
......@@ -51,6 +66,9 @@ enum ena_admin_aq_feature_id {
/* device capabilities */
enum ena_admin_aq_caps_id {
ENA_ADMIN_ENI_STATS = 0,
/* ENA SRD customer metrics */
ENA_ADMIN_ENA_SRD_INFO = 1,
ENA_ADMIN_CUSTOMER_METRICS = 2,
};
enum ena_admin_placement_policy_type {
......@@ -99,6 +117,9 @@ enum ena_admin_get_stats_type {
ENA_ADMIN_GET_STATS_TYPE_EXTENDED = 1,
/* extra HW stats for specific network interface */
ENA_ADMIN_GET_STATS_TYPE_ENI = 2,
/* extra HW stats for ENA SRD */
ENA_ADMIN_GET_STATS_TYPE_ENA_SRD = 3,
ENA_ADMIN_GET_STATS_TYPE_CUSTOMER_METRICS = 4,
};
enum ena_admin_get_stats_scope {
......@@ -106,6 +127,16 @@ enum ena_admin_get_stats_scope {
ENA_ADMIN_ETH_TRAFFIC = 1,
};
/* ENA SRD configuration for ENI */
enum ena_admin_ena_srd_flags {
/* Feature enabled */
ENA_ADMIN_ENA_SRD_ENABLED = BIT(0),
/* UDP support enabled */
ENA_ADMIN_ENA_SRD_UDP_ENABLED = BIT(1),
/* Bypass Rx UDP ordering */
ENA_ADMIN_ENA_SRD_UDP_ORDERING_BYPASS_ENABLED = BIT(2),
};
struct ena_admin_aq_common_desc {
/* 11:0 : command_id
* 15:12 : reserved12
......@@ -363,6 +394,9 @@ struct ena_admin_aq_get_stats_cmd {
* stats of other device
*/
u16 device_id;
/* a bitmap representing the requested metric values */
u64 requested_metrics;
};
/* Basic Statistics Command. */
......@@ -419,6 +453,40 @@ struct ena_admin_eni_stats {
u64 linklocal_allowance_exceeded;
};
struct ena_admin_ena_srd_stats {
/* Number of packets transmitted over ENA SRD */
u64 ena_srd_tx_pkts;
/* Number of packets transmitted or could have been
* transmitted over ENA SRD
*/
u64 ena_srd_eligible_tx_pkts;
/* Number of packets received over ENA SRD */
u64 ena_srd_rx_pkts;
/* Percentage of the ENA SRD resources that is in use */
u64 ena_srd_resource_utilization;
};
/* ENA SRD Statistics Command */
struct ena_admin_ena_srd_info {
/* ENA SRD configuration bitmap. See ena_admin_ena_srd_flags for
* details
*/
u64 flags;
struct ena_admin_ena_srd_stats ena_srd_stats;
};
/* Customer Metrics Command. */
struct ena_admin_customer_metrics {
/* A bitmap representing the reported customer metrics according to
* the order they are reported
*/
u64 reported_metrics;
};
struct ena_admin_acq_get_stats_resp {
struct ena_admin_acq_common_desc acq_common_desc;
......@@ -428,6 +496,10 @@ struct ena_admin_acq_get_stats_resp {
struct ena_admin_basic_stats basic_stats;
struct ena_admin_eni_stats eni_stats;
struct ena_admin_ena_srd_info ena_srd_info;
struct ena_admin_customer_metrics customer_metrics;
} u;
};
......
......@@ -1881,6 +1881,56 @@ int ena_com_get_link_params(struct ena_com_dev *ena_dev,
return ena_com_get_feature(ena_dev, resp, ENA_ADMIN_LINK_CONFIG, 0);
}
static int ena_get_dev_stats(struct ena_com_dev *ena_dev,
struct ena_com_stats_ctx *ctx,
enum ena_admin_get_stats_type type)
{
struct ena_admin_acq_get_stats_resp *get_resp = &ctx->get_resp;
struct ena_admin_aq_get_stats_cmd *get_cmd = &ctx->get_cmd;
struct ena_com_admin_queue *admin_queue;
int ret;
admin_queue = &ena_dev->admin_queue;
get_cmd->aq_common_descriptor.opcode = ENA_ADMIN_GET_STATS;
get_cmd->aq_common_descriptor.flags = 0;
get_cmd->type = type;
ret = ena_com_execute_admin_command(admin_queue,
(struct ena_admin_aq_entry *)get_cmd,
sizeof(*get_cmd),
(struct ena_admin_acq_entry *)get_resp,
sizeof(*get_resp));
if (unlikely(ret))
netdev_err(ena_dev->net_device, "Failed to get stats. error: %d\n", ret);
return ret;
}
static void ena_com_set_supported_customer_metrics(struct ena_com_dev *ena_dev)
{
struct ena_customer_metrics *customer_metrics;
struct ena_com_stats_ctx ctx;
int ret;
customer_metrics = &ena_dev->customer_metrics;
if (!ena_com_get_cap(ena_dev, ENA_ADMIN_CUSTOMER_METRICS)) {
customer_metrics->supported_metrics = ENA_ADMIN_CUSTOMER_METRICS_MIN_SUPPORT_MASK;
return;
}
memset(&ctx, 0x0, sizeof(ctx));
ctx.get_cmd.requested_metrics = ENA_ADMIN_CUSTOMER_METRICS_SUPPORT_MASK;
ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_CUSTOMER_METRICS);
if (likely(ret == 0))
customer_metrics->supported_metrics =
ctx.get_resp.u.customer_metrics.reported_metrics;
else
netdev_err(ena_dev->net_device,
"Failed to query customer metrics support. error: %d\n", ret);
}
int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
struct ena_com_dev_get_features_ctx *get_feat_ctx)
{
......@@ -1960,6 +2010,8 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
else
return rc;
ena_com_set_supported_customer_metrics(ena_dev);
return 0;
}
......@@ -2104,50 +2156,44 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev,
return 0;
}
static int ena_get_dev_stats(struct ena_com_dev *ena_dev,
struct ena_com_stats_ctx *ctx,
enum ena_admin_get_stats_type type)
int ena_com_get_eni_stats(struct ena_com_dev *ena_dev,
struct ena_admin_eni_stats *stats)
{
struct ena_admin_aq_get_stats_cmd *get_cmd = &ctx->get_cmd;
struct ena_admin_acq_get_stats_resp *get_resp = &ctx->get_resp;
struct ena_com_admin_queue *admin_queue;
struct ena_com_stats_ctx ctx;
int ret;
admin_queue = &ena_dev->admin_queue;
get_cmd->aq_common_descriptor.opcode = ENA_ADMIN_GET_STATS;
get_cmd->aq_common_descriptor.flags = 0;
get_cmd->type = type;
ret = ena_com_execute_admin_command(admin_queue,
(struct ena_admin_aq_entry *)get_cmd,
sizeof(*get_cmd),
(struct ena_admin_acq_entry *)get_resp,
sizeof(*get_resp));
if (!ena_com_get_cap(ena_dev, ENA_ADMIN_ENI_STATS)) {
netdev_err(ena_dev->net_device, "Capability %d isn't supported\n",
ENA_ADMIN_ENI_STATS);
return -EOPNOTSUPP;
}
if (unlikely(ret))
netdev_err(ena_dev->net_device, "Failed to get stats. error: %d\n", 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_eni_stats(struct ena_com_dev *ena_dev,
struct ena_admin_eni_stats *stats)
int ena_com_get_ena_srd_info(struct ena_com_dev *ena_dev,
struct ena_admin_ena_srd_info *info)
{
struct ena_com_stats_ctx ctx;
int ret;
if (!ena_com_get_cap(ena_dev, ENA_ADMIN_ENI_STATS)) {
if (!ena_com_get_cap(ena_dev, ENA_ADMIN_ENA_SRD_INFO)) {
netdev_err(ena_dev->net_device, "Capability %d isn't supported\n",
ENA_ADMIN_ENI_STATS);
ENA_ADMIN_ENA_SRD_INFO);
return -EOPNOTSUPP;
}
memset(&ctx, 0x0, sizeof(ctx));
ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_ENI);
ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_ENA_SRD);
if (likely(ret == 0))
memcpy(stats, &ctx.get_resp.u.eni_stats,
sizeof(ctx.get_resp.u.eni_stats));
memcpy(info, &ctx.get_resp.u.ena_srd_info,
sizeof(ctx.get_resp.u.ena_srd_info));
return ret;
}
......@@ -2167,6 +2213,50 @@ int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev,
return ret;
}
int ena_com_get_customer_metrics(struct ena_com_dev *ena_dev, char *buffer, u32 len)
{
struct ena_admin_aq_get_stats_cmd *get_cmd;
struct ena_com_stats_ctx ctx;
int ret;
if (unlikely(len > ena_dev->customer_metrics.buffer_len)) {
netdev_err(ena_dev->net_device,
"Invalid buffer size %u. The given buffer is too big.\n", len);
return -EINVAL;
}
if (!ena_com_get_cap(ena_dev, ENA_ADMIN_CUSTOMER_METRICS)) {
netdev_err(ena_dev->net_device, "Capability %d not supported.\n",
ENA_ADMIN_CUSTOMER_METRICS);
return -EOPNOTSUPP;
}
if (!ena_dev->customer_metrics.supported_metrics) {
netdev_err(ena_dev->net_device, "No supported customer metrics.\n");
return -EOPNOTSUPP;
}
get_cmd = &ctx.get_cmd;
memset(&ctx, 0x0, sizeof(ctx));
ret = ena_com_mem_addr_set(ena_dev,
&get_cmd->u.control_buffer.address,
ena_dev->customer_metrics.buffer_dma_addr);
if (unlikely(ret)) {
netdev_err(ena_dev->net_device, "Memory address set failed.\n");
return ret;
}
get_cmd->u.control_buffer.length = ena_dev->customer_metrics.buffer_len;
get_cmd->requested_metrics = ena_dev->customer_metrics.supported_metrics;
ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_CUSTOMER_METRICS);
if (likely(ret == 0))
memcpy(buffer, ena_dev->customer_metrics.buffer_virt_addr, len);
else
netdev_err(ena_dev->net_device, "Failed to get customer metrics. error: %d\n", ret);
return ret;
}
int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu)
{
struct ena_com_admin_queue *admin_queue;
......@@ -2706,6 +2796,24 @@ int ena_com_allocate_debug_area(struct ena_com_dev *ena_dev,
return 0;
}
int ena_com_allocate_customer_metrics_buffer(struct ena_com_dev *ena_dev)
{
struct ena_customer_metrics *customer_metrics = &ena_dev->customer_metrics;
customer_metrics->buffer_len = ENA_CUSTOMER_METRICS_BUFFER_SIZE;
customer_metrics->buffer_virt_addr = NULL;
customer_metrics->buffer_virt_addr =
dma_alloc_coherent(ena_dev->dmadev, customer_metrics->buffer_len,
&customer_metrics->buffer_dma_addr, GFP_KERNEL);
if (!customer_metrics->buffer_virt_addr) {
customer_metrics->buffer_len = 0;
return -ENOMEM;
}
return 0;
}
void ena_com_delete_host_info(struct ena_com_dev *ena_dev)
{
struct ena_host_attribute *host_attr = &ena_dev->host_attr;
......@@ -2728,6 +2836,19 @@ void ena_com_delete_debug_area(struct ena_com_dev *ena_dev)
}
}
void ena_com_delete_customer_metrics_buffer(struct ena_com_dev *ena_dev)
{
struct ena_customer_metrics *customer_metrics = &ena_dev->customer_metrics;
if (customer_metrics->buffer_virt_addr) {
dma_free_coherent(ena_dev->dmadev, customer_metrics->buffer_len,
customer_metrics->buffer_virt_addr,
customer_metrics->buffer_dma_addr);
customer_metrics->buffer_virt_addr = NULL;
customer_metrics->buffer_len = 0;
}
}
int ena_com_set_host_attributes(struct ena_com_dev *ena_dev)
{
struct ena_host_attribute *host_attr = &ena_dev->host_attr;
......
......@@ -42,6 +42,8 @@
#define ADMIN_CQ_SIZE(depth) ((depth) * sizeof(struct ena_admin_acq_entry))
#define ADMIN_AENQ_SIZE(depth) ((depth) * sizeof(struct ena_admin_aenq_entry))
#define ENA_CUSTOMER_METRICS_BUFFER_SIZE 512
/*****************************************************************************/
/*****************************************************************************/
/* ENA adaptive interrupt moderation settings */
......@@ -278,6 +280,16 @@ struct ena_rss {
};
struct ena_customer_metrics {
/* in correlation with ENA_ADMIN_CUSTOMER_METRICS_SUPPORT_MASK
* and ena_admin_customer_metrics_id
*/
u64 supported_metrics;
dma_addr_t buffer_dma_addr;
void *buffer_virt_addr;
u32 buffer_len;
};
struct ena_host_attribute {
/* Debug area */
u8 *debug_area_virt_addr;
......@@ -327,6 +339,8 @@ struct ena_com_dev {
struct ena_intr_moder_entry *intr_moder_tbl;
struct ena_com_llq_info llq_info;
struct ena_customer_metrics customer_metrics;
};
struct ena_com_dev_get_features_ctx {
......@@ -595,6 +609,24 @@ int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev,
int ena_com_get_eni_stats(struct ena_com_dev *ena_dev,
struct ena_admin_eni_stats *stats);
/* ena_com_get_ena_srd_info - Get ENA SRD network interface statistics
* @ena_dev: ENA communication layer struct
* @info: ena srd stats and flags
*
* @return: 0 on Success and negative value otherwise.
*/
int ena_com_get_ena_srd_info(struct ena_com_dev *ena_dev,
struct ena_admin_ena_srd_info *info);
/* ena_com_get_customer_metrics - Get customer metrics for network interface
* @ena_dev: ENA communication layer struct
* @buffer: buffer for returned customer metrics
* @len: size of the buffer
*
* @return: 0 on Success and negative value otherwise.
*/
int ena_com_get_customer_metrics(struct ena_com_dev *ena_dev, char *buffer, u32 len);
/* ena_com_set_dev_mtu - Configure the device mtu.
* @ena_dev: ENA communication layer struct
* @mtu: mtu value
......@@ -805,6 +837,13 @@ int ena_com_allocate_host_info(struct ena_com_dev *ena_dev);
int ena_com_allocate_debug_area(struct ena_com_dev *ena_dev,
u32 debug_area_size);
/* ena_com_allocate_customer_metrics_buffer - Allocate customer metrics resources.
* @ena_dev: ENA communication layer struct
*
* @return: 0 on Success and negative value otherwise.
*/
int ena_com_allocate_customer_metrics_buffer(struct ena_com_dev *ena_dev);
/* ena_com_delete_debug_area - Free the debug area resources.
* @ena_dev: ENA communication layer struct
*
......@@ -819,6 +858,13 @@ void ena_com_delete_debug_area(struct ena_com_dev *ena_dev);
*/
void ena_com_delete_host_info(struct ena_com_dev *ena_dev);
/* ena_com_delete_customer_metrics_buffer - Free the customer metrics resources.
* @ena_dev: ENA communication layer struct
*
* Free the allocated customer metrics area.
*/
void ena_com_delete_customer_metrics_buffer(struct ena_com_dev *ena_dev);
/* ena_com_set_host_attributes - Update the device with the host
* attributes (debug area and host info) base address.
* @ena_dev: ENA communication layer struct
......@@ -975,6 +1021,28 @@ static inline bool ena_com_get_cap(struct ena_com_dev *ena_dev,
return !!(ena_dev->capabilities & BIT(cap_id));
}
/* ena_com_get_customer_metric_support - query whether device supports a given customer metric.
* @ena_dev: ENA communication layer struct
* @metric_id: enum value representing the customer metric
*
* @return - true if customer metric is supported or false otherwise
*/
static inline bool ena_com_get_customer_metric_support(struct ena_com_dev *ena_dev,
enum ena_admin_customer_metrics_id metric_id)
{
return !!(ena_dev->customer_metrics.supported_metrics & BIT(metric_id));
}
/* ena_com_get_customer_metric_count - return the number of supported customer metrics.
* @ena_dev: ENA communication layer struct
*
* @return - the number of supported customer metrics
*/
static inline int ena_com_get_customer_metric_count(struct ena_com_dev *ena_dev)
{
return hweight64(ena_dev->customer_metrics.supported_metrics);
}
/* ena_com_update_intr_reg - Prepare interrupt register
* @intr_reg: interrupt register to update.
* @rx_delay_interval: Rx interval in usecs
......
......@@ -14,6 +14,10 @@ struct ena_stats {
int stat_offset;
};
struct ena_hw_metrics {
char name[ETH_GSTRING_LEN];
};
#define ENA_STAT_ENA_COM_ENTRY(stat) { \
.name = #stat, \
.stat_offset = offsetof(struct ena_com_stats_admin, stat) / sizeof(u64) \
......@@ -41,6 +45,18 @@ struct ena_stats {
#define ENA_STAT_ENI_ENTRY(stat) \
ENA_STAT_HW_ENTRY(stat, eni_stats)
#define ENA_STAT_ENA_SRD_ENTRY(stat) \
ENA_STAT_HW_ENTRY(stat, ena_srd_stats)
#define ENA_STAT_ENA_SRD_MODE_ENTRY(stat) { \
.name = #stat, \
.stat_offset = offsetof(struct ena_admin_ena_srd_info, flags) / sizeof(u64) \
}
#define ENA_METRIC_ENI_ENTRY(stat) { \
.name = #stat \
}
static const struct ena_stats ena_stats_global_strings[] = {
ENA_STAT_GLOBAL_ENTRY(tx_timeout),
ENA_STAT_GLOBAL_ENTRY(suspend),
......@@ -52,6 +68,9 @@ static const struct ena_stats ena_stats_global_strings[] = {
ENA_STAT_GLOBAL_ENTRY(reset_fail),
};
/* A partial list of hw stats. Used when admin command
* with type ENA_ADMIN_GET_STATS_TYPE_CUSTOMER_METRICS is not supported
*/
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),
......@@ -60,6 +79,23 @@ static const struct ena_stats ena_stats_eni_strings[] = {
ENA_STAT_ENI_ENTRY(linklocal_allowance_exceeded),
};
static const struct ena_hw_metrics ena_hw_stats_strings[] = {
ENA_METRIC_ENI_ENTRY(bw_in_allowance_exceeded),
ENA_METRIC_ENI_ENTRY(bw_out_allowance_exceeded),
ENA_METRIC_ENI_ENTRY(pps_allowance_exceeded),
ENA_METRIC_ENI_ENTRY(conntrack_allowance_exceeded),
ENA_METRIC_ENI_ENTRY(linklocal_allowance_exceeded),
ENA_METRIC_ENI_ENTRY(conntrack_allowance_available),
};
static const struct ena_stats ena_srd_info_strings[] = {
ENA_STAT_ENA_SRD_MODE_ENTRY(ena_srd_mode),
ENA_STAT_ENA_SRD_ENTRY(ena_srd_tx_pkts),
ENA_STAT_ENA_SRD_ENTRY(ena_srd_eligible_tx_pkts),
ENA_STAT_ENA_SRD_ENTRY(ena_srd_rx_pkts),
ENA_STAT_ENA_SRD_ENTRY(ena_srd_resource_utilization)
};
static const struct ena_stats ena_stats_tx_strings[] = {
ENA_STAT_TX_ENTRY(cnt),
ENA_STAT_TX_ENTRY(bytes),
......@@ -112,7 +148,9 @@ 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)
#define ENA_STATS_ARRAY_ENI ARRAY_SIZE(ena_stats_eni_strings)
#define ENA_STATS_ARRAY_ENA_SRD ARRAY_SIZE(ena_srd_info_strings)
#define ENA_METRICS_ARRAY_ENI ARRAY_SIZE(ena_hw_stats_strings)
static void ena_safe_update_stat(u64 *src, u64 *dst,
struct u64_stats_sync *syncp)
......@@ -125,6 +163,57 @@ static void ena_safe_update_stat(u64 *src, u64 *dst,
} while (u64_stats_fetch_retry(syncp, start));
}
static void ena_metrics_stats(struct ena_adapter *adapter, u64 **data)
{
struct ena_com_dev *dev = adapter->ena_dev;
const struct ena_stats *ena_stats;
u64 *ptr;
int i;
if (ena_com_get_cap(dev, ENA_ADMIN_CUSTOMER_METRICS)) {
u32 supported_metrics_count;
int len;
supported_metrics_count = ena_com_get_customer_metric_count(dev);
len = supported_metrics_count * sizeof(u64);
/* Fill the data buffer, and advance its pointer */
ena_com_get_customer_metrics(dev, (char *)(*data), len);
(*data) += supported_metrics_count;
} else if (ena_com_get_cap(dev, ENA_ADMIN_ENI_STATS)) {
ena_com_get_eni_stats(dev, &adapter->eni_stats);
/* Updating regardless of rc - once we told ethtool how many stats we have
* it will print that much stats. We can't leave holes in the stats
*/
for (i = 0; i < ENA_STATS_ARRAY_ENI; 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);
}
}
if (ena_com_get_cap(dev, ENA_ADMIN_ENA_SRD_INFO)) {
ena_com_get_ena_srd_info(dev, &adapter->ena_srd_info);
/* Get ENA SRD mode */
ptr = (u64 *)&adapter->ena_srd_info;
ena_safe_update_stat(ptr, (*data)++, &adapter->syncp);
for (i = 1; i < ENA_STATS_ARRAY_ENA_SRD; i++) {
ena_stats = &ena_srd_info_strings[i];
/* Wrapped within an outer struct - need to accommodate an
* additional offset of the ENA SRD mode that was already processed
*/
ptr = (u64 *)&adapter->ena_srd_info +
ena_stats->stat_offset + 1;
ena_safe_update_stat(ptr, (*data)++, &adapter->syncp);
}
}
}
static void ena_queue_stats(struct ena_adapter *adapter, u64 **data)
{
const struct ena_stats *ena_stats;
......@@ -179,7 +268,7 @@ static void ena_dev_admin_queue_stats(struct ena_adapter *adapter, u64 **data)
static void ena_get_stats(struct ena_adapter *adapter,
u64 *data,
bool eni_stats_needed)
bool hw_stats_needed)
{
const struct ena_stats *ena_stats;
u64 *ptr;
......@@ -193,17 +282,8 @@ static void ena_get_stats(struct ena_adapter *adapter,
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);
}
}
if (hw_stats_needed)
ena_metrics_stats(adapter, &data);
ena_queue_stats(adapter, &data);
ena_dev_admin_queue_stats(adapter, &data);
......@@ -214,9 +294,8 @@ static void ena_get_ethtool_stats(struct net_device *netdev,
u64 *data)
{
struct ena_adapter *adapter = netdev_priv(netdev);
struct ena_com_dev *dev = adapter->ena_dev;
ena_get_stats(adapter, data, ena_com_get_cap(dev, ENA_ADMIN_ENI_STATS));
ena_get_stats(adapter, data, true);
}
static int ena_get_sw_stats_count(struct ena_adapter *adapter)
......@@ -228,9 +307,17 @@ static int ena_get_sw_stats_count(struct ena_adapter *adapter)
static int ena_get_hw_stats_count(struct ena_adapter *adapter)
{
bool supported = ena_com_get_cap(adapter->ena_dev, ENA_ADMIN_ENI_STATS);
struct ena_com_dev *dev = adapter->ena_dev;
int count;
count = ENA_STATS_ARRAY_ENA_SRD * ena_com_get_cap(dev, ENA_ADMIN_ENA_SRD_INFO);
return ENA_STATS_ARRAY_ENI(adapter) * supported;
if (ena_com_get_cap(dev, ENA_ADMIN_CUSTOMER_METRICS))
count += ena_com_get_customer_metric_count(dev);
else if (ena_com_get_cap(dev, ENA_ADMIN_ENI_STATS))
count += ENA_STATS_ARRAY_ENI;
return count;
}
int ena_get_sset_count(struct net_device *netdev, int sset)
......@@ -246,6 +333,35 @@ int ena_get_sset_count(struct net_device *netdev, int sset)
return -EOPNOTSUPP;
}
static void ena_metrics_stats_strings(struct ena_adapter *adapter, u8 **data)
{
struct ena_com_dev *dev = adapter->ena_dev;
const struct ena_hw_metrics *ena_metrics;
const struct ena_stats *ena_stats;
int i;
if (ena_com_get_cap(dev, ENA_ADMIN_CUSTOMER_METRICS)) {
for (i = 0; i < ENA_METRICS_ARRAY_ENI; i++) {
if (ena_com_get_customer_metric_support(dev, i)) {
ena_metrics = &ena_hw_stats_strings[i];
ethtool_puts(data, ena_metrics->name);
}
}
} else if (ena_com_get_cap(dev, ENA_ADMIN_ENI_STATS)) {
for (i = 0; i < ENA_STATS_ARRAY_ENI; i++) {
ena_stats = &ena_stats_eni_strings[i];
ethtool_puts(data, ena_stats->name);
}
}
if (ena_com_get_cap(dev, ENA_ADMIN_ENA_SRD_INFO)) {
for (i = 0; i < ENA_STATS_ARRAY_ENA_SRD; i++) {
ena_stats = &ena_srd_info_strings[i];
ethtool_puts(data, ena_stats->name);
}
}
}
static void ena_queue_strings(struct ena_adapter *adapter, u8 **data)
{
const struct ena_stats *ena_stats;
......@@ -291,7 +407,7 @@ static void ena_com_dev_strings(u8 **data)
static void ena_get_strings(struct ena_adapter *adapter,
u8 *data,
bool eni_stats_needed)
bool hw_stats_needed)
{
const struct ena_stats *ena_stats;
int i;
......@@ -301,12 +417,8 @@ static void ena_get_strings(struct ena_adapter *adapter,
ethtool_puts(&data, ena_stats->name);
}
if (eni_stats_needed) {
for (i = 0; i < ENA_STATS_ARRAY_ENI(adapter); i++) {
ena_stats = &ena_stats_eni_strings[i];
ethtool_puts(&data, ena_stats->name);
}
}
if (hw_stats_needed)
ena_metrics_stats_strings(adapter, &data);
ena_queue_strings(adapter, &data);
ena_com_dev_strings(&data);
......@@ -317,11 +429,10 @@ static void ena_get_ethtool_strings(struct net_device *netdev,
u8 *data)
{
struct ena_adapter *adapter = netdev_priv(netdev);
struct ena_com_dev *dev = adapter->ena_dev;
switch (sset) {
case ETH_SS_STATS:
ena_get_strings(adapter, data, ena_com_get_cap(dev, ENA_ADMIN_ENI_STATS));
ena_get_strings(adapter, data, true);
break;
}
}
......
......@@ -2798,19 +2798,6 @@ static void ena_config_debug_area(struct ena_adapter *adapter)
ena_com_delete_debug_area(adapter->ena_dev);
}
int ena_update_hw_stats(struct ena_adapter *adapter)
{
int rc;
rc = ena_com_get_eni_stats(adapter->ena_dev, &adapter->eni_stats);
if (rc) {
netdev_err(adapter->netdev, "Failed to get ENI stats\n");
return rc;
}
return 0;
}
static void ena_get_stats64(struct net_device *netdev,
struct rtnl_link_stats64 *stats)
{
......@@ -3944,10 +3931,16 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, adapter);
rc = ena_com_allocate_customer_metrics_buffer(ena_dev);
if (rc) {
netdev_err(netdev, "ena_com_allocate_customer_metrics_buffer failed\n");
goto err_netdev_destroy;
}
rc = ena_map_llq_mem_bar(pdev, ena_dev, bars);
if (rc) {
dev_err(&pdev->dev, "ENA LLQ bar mapping failed\n");
goto err_netdev_destroy;
goto err_metrics_destroy;
}
rc = ena_device_init(adapter, pdev, &get_feat_ctx, &wd_state);
......@@ -3955,7 +3948,7 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_err(&pdev->dev, "ENA device init failed\n");
if (rc == -ETIME)
rc = -EPROBE_DEFER;
goto err_netdev_destroy;
goto err_metrics_destroy;
}
/* Initial TX and RX interrupt delay. Assumes 1 usec granularity.
......@@ -4076,6 +4069,8 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err_device_destroy:
ena_com_delete_host_info(ena_dev);
ena_com_admin_destroy(ena_dev);
err_metrics_destroy:
ena_com_delete_customer_metrics_buffer(ena_dev);
err_netdev_destroy:
free_netdev(netdev);
err_free_region:
......@@ -4139,6 +4134,8 @@ static void __ena_shutoff(struct pci_dev *pdev, bool shutdown)
ena_com_delete_host_info(ena_dev);
ena_com_delete_customer_metrics_buffer(ena_dev);
ena_release_bars(ena_dev, pdev);
pci_disable_device(pdev);
......
......@@ -373,6 +373,7 @@ struct ena_adapter {
struct u64_stats_sync syncp;
struct ena_stats_dev dev_stats;
struct ena_admin_eni_stats eni_stats;
struct ena_admin_ena_srd_info ena_srd_info;
/* last queue index that was checked for uncompleted tx packets */
u32 last_monitored_tx_qid;
......@@ -390,7 +391,6 @@ void ena_dump_stats_to_dmesg(struct ena_adapter *adapter);
void ena_dump_stats_to_buf(struct ena_adapter *adapter, u8 *buf);
int ena_update_hw_stats(struct ena_adapter *adapter);
int ena_update_queue_params(struct ena_adapter *adapter,
u32 new_tx_size,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment