Skip to content

Commit

Permalink
gve: Add Gvnic stats AQ command and ethtool show/set-priv-flags.
Browse files Browse the repository at this point in the history
This adds functionality to report driver stats to Hypervisor.
(Users may want to turn this feature off as a matter of privacy
so a "report-stats" flag is added as an ethtool priv option.
It is also disabled by default.)
The hypervisor would trigger a stats report in case "too many"
packets dropped; the stats would be useful in debugging stuck
queues.
A "stats_report_trigger_cnt" stat is added to count the number of times
the hypervisor attempts to trigger stats report.

A timer is also added so that when report-stats is enabled, stat are
updated once every 20 seconds.

Reviewed-by: Yangchun Fu <yangchun@google.com>
Signed-off-by: Kuo Zhao <kuozhao@google.com>
Signed-off-by: David Awogbemila <awogbemila@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Kuo Zhao authored and David S. Miller committed Sep 11, 2020
1 parent 0d5775d commit 24aeb56
Show file tree
Hide file tree
Showing 6 changed files with 369 additions and 32 deletions.
71 changes: 61 additions & 10 deletions drivers/net/ethernet/google/gve/gve.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@
/* 1 for management, 1 for rx, 1 for tx */
#define GVE_MIN_MSIX 3

/* Numbers of gve tx/rx stats in stats report. */
#define GVE_TX_STATS_REPORT_NUM 5
#define GVE_RX_STATS_REPORT_NUM 2

/* Interval to schedule a stats report update, 20000ms. */
#define GVE_STATS_REPORT_TIMER_PERIOD 20000

/* Each slot in the desc ring has a 1:1 mapping to a slot in the data ring */
struct gve_rx_desc_queue {
struct gve_rx_desc *desc_ring; /* the descriptor ring */
Expand Down Expand Up @@ -220,31 +227,47 @@ struct gve_priv {
u32 adminq_destroy_rx_queue_cnt;
u32 adminq_dcfg_device_resources_cnt;
u32 adminq_set_driver_parameter_cnt;
u32 adminq_report_stats_cnt;

/* Global stats */
u32 interface_up_cnt; /* count of times interface turned up since last reset */
u32 interface_down_cnt; /* count of times interface turned down since last reset */
u32 reset_cnt; /* count of reset */
u32 page_alloc_fail; /* count of page alloc fails */
u32 dma_mapping_error; /* count of dma mapping errors */

u32 stats_report_trigger_cnt; /* count of device-requested stats-reports since last reset */
struct workqueue_struct *gve_wq;
struct work_struct service_task;
struct work_struct stats_report_task;
unsigned long service_task_flags;
unsigned long state_flags;

struct gve_stats_report *stats_report;
u64 stats_report_len;
dma_addr_t stats_report_bus; /* dma address for the stats report */
unsigned long ethtool_flags;

unsigned long stats_report_timer_period;
struct timer_list stats_report_timer;

};

enum gve_service_task_flags {
GVE_PRIV_FLAGS_DO_RESET = BIT(1),
GVE_PRIV_FLAGS_RESET_IN_PROGRESS = BIT(2),
GVE_PRIV_FLAGS_PROBE_IN_PROGRESS = BIT(3),
enum gve_service_task_flags_bit {
GVE_PRIV_FLAGS_DO_RESET = 1,
GVE_PRIV_FLAGS_RESET_IN_PROGRESS = 2,
GVE_PRIV_FLAGS_PROBE_IN_PROGRESS = 3,
GVE_PRIV_FLAGS_DO_REPORT_STATS = 4,
};

enum gve_state_flags {
GVE_PRIV_FLAGS_ADMIN_QUEUE_OK = BIT(1),
GVE_PRIV_FLAGS_DEVICE_RESOURCES_OK = BIT(2),
GVE_PRIV_FLAGS_DEVICE_RINGS_OK = BIT(3),
GVE_PRIV_FLAGS_NAPI_ENABLED = BIT(4),
enum gve_state_flags_bit {
GVE_PRIV_FLAGS_ADMIN_QUEUE_OK = 1,
GVE_PRIV_FLAGS_DEVICE_RESOURCES_OK = 2,
GVE_PRIV_FLAGS_DEVICE_RINGS_OK = 3,
GVE_PRIV_FLAGS_NAPI_ENABLED = 4,
};

enum gve_ethtool_flags_bit {
GVE_PRIV_FLAGS_REPORT_STATS = 0,
};

static inline bool gve_get_do_reset(struct gve_priv *priv)
Expand Down Expand Up @@ -294,6 +317,22 @@ static inline void gve_clear_probe_in_progress(struct gve_priv *priv)
clear_bit(GVE_PRIV_FLAGS_PROBE_IN_PROGRESS, &priv->service_task_flags);
}

static inline bool gve_get_do_report_stats(struct gve_priv *priv)
{
return test_bit(GVE_PRIV_FLAGS_DO_REPORT_STATS,
&priv->service_task_flags);
}

static inline void gve_set_do_report_stats(struct gve_priv *priv)
{
set_bit(GVE_PRIV_FLAGS_DO_REPORT_STATS, &priv->service_task_flags);
}

static inline void gve_clear_do_report_stats(struct gve_priv *priv)
{
clear_bit(GVE_PRIV_FLAGS_DO_REPORT_STATS, &priv->service_task_flags);
}

static inline bool gve_get_admin_queue_ok(struct gve_priv *priv)
{
return test_bit(GVE_PRIV_FLAGS_ADMIN_QUEUE_OK, &priv->state_flags);
Expand Down Expand Up @@ -354,6 +393,16 @@ static inline void gve_clear_napi_enabled(struct gve_priv *priv)
clear_bit(GVE_PRIV_FLAGS_NAPI_ENABLED, &priv->state_flags);
}

static inline bool gve_get_report_stats(struct gve_priv *priv)
{
return test_bit(GVE_PRIV_FLAGS_REPORT_STATS, &priv->ethtool_flags);
}

static inline void gve_clear_report_stats(struct gve_priv *priv)
{
clear_bit(GVE_PRIV_FLAGS_REPORT_STATS, &priv->ethtool_flags);
}

/* Returns the address of the ntfy_blocks irq doorbell
*/
static inline __be32 __iomem *gve_irq_doorbell(struct gve_priv *priv,
Expand Down Expand Up @@ -476,6 +525,8 @@ int gve_reset(struct gve_priv *priv, bool attempt_teardown);
int gve_adjust_queues(struct gve_priv *priv,
struct gve_queue_config new_rx_config,
struct gve_queue_config new_tx_config);
/* report stats handling */
void gve_handle_report_stats(struct gve_priv *priv);
/* exported by ethtool.c */
extern const struct ethtool_ops gve_ethtool_ops;
/* needed by ethtool */
Expand Down
20 changes: 20 additions & 0 deletions drivers/net/ethernet/google/gve/gve_adminq.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ int gve_adminq_alloc(struct device *dev, struct gve_priv *priv)
priv->adminq_destroy_rx_queue_cnt = 0;
priv->adminq_dcfg_device_resources_cnt = 0;
priv->adminq_set_driver_parameter_cnt = 0;
priv->adminq_report_stats_cnt = 0;

/* Setup Admin queue with the device */
iowrite32be(priv->adminq_bus_addr / PAGE_SIZE,
Expand Down Expand Up @@ -183,6 +184,9 @@ int gve_adminq_execute_cmd(struct gve_priv *priv,
case GVE_ADMINQ_SET_DRIVER_PARAMETER:
priv->adminq_set_driver_parameter_cnt++;
break;
case GVE_ADMINQ_REPORT_STATS:
priv->adminq_report_stats_cnt++;
break;
default:
dev_err(&priv->pdev->dev, "unknown AQ command opcode %d\n", opcode);
}
Expand Down Expand Up @@ -433,3 +437,19 @@ int gve_adminq_set_mtu(struct gve_priv *priv, u64 mtu)

return gve_adminq_execute_cmd(priv, &cmd);
}

int gve_adminq_report_stats(struct gve_priv *priv, u64 stats_report_len,
dma_addr_t stats_report_addr, u64 interval)
{
union gve_adminq_command cmd;

memset(&cmd, 0, sizeof(cmd));
cmd.opcode = cpu_to_be32(GVE_ADMINQ_REPORT_STATS);
cmd.report_stats = (struct gve_adminq_report_stats) {
.stats_report_len = cpu_to_be64(stats_report_len),
.stats_report_addr = cpu_to_be64(stats_report_addr),
.interval = cpu_to_be64(interval),
};

return gve_adminq_execute_cmd(priv, &cmd);
}
38 changes: 38 additions & 0 deletions drivers/net/ethernet/google/gve/gve_adminq.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ enum gve_adminq_opcodes {
GVE_ADMINQ_DESTROY_RX_QUEUE = 0x8,
GVE_ADMINQ_DECONFIGURE_DEVICE_RESOURCES = 0x9,
GVE_ADMINQ_SET_DRIVER_PARAMETER = 0xB,
GVE_ADMINQ_REPORT_STATS = 0xC,
};

/* Admin queue status codes */
Expand Down Expand Up @@ -172,6 +173,40 @@ struct gve_adminq_set_driver_parameter {

static_assert(sizeof(struct gve_adminq_set_driver_parameter) == 16);

struct gve_adminq_report_stats {
__be64 stats_report_len;
__be64 stats_report_addr;
__be64 interval;
};

static_assert(sizeof(struct gve_adminq_report_stats) == 24);

struct stats {
__be32 stat_name;
__be32 queue_id;
__be64 value;
};

static_assert(sizeof(struct stats) == 16);

struct gve_stats_report {
__be64 written_count;
struct stats stats[0];
};

static_assert(sizeof(struct gve_stats_report) == 8);

enum gve_stat_names {
// stats from gve
TX_WAKE_CNT = 1,
TX_STOP_CNT = 2,
TX_FRAMES_SENT = 3,
TX_BYTES_SENT = 4,
TX_LAST_COMPLETION_PROCESSED = 5,
RX_NEXT_EXPECTED_SEQUENCE = 6,
RX_BUFFERS_POSTED = 7,
};

union gve_adminq_command {
struct {
__be32 opcode;
Expand All @@ -187,6 +222,7 @@ union gve_adminq_command {
struct gve_adminq_register_page_list reg_page_list;
struct gve_adminq_unregister_page_list unreg_page_list;
struct gve_adminq_set_driver_parameter set_driver_param;
struct gve_adminq_report_stats report_stats;
};
};
u8 reserved[64];
Expand Down Expand Up @@ -214,4 +250,6 @@ int gve_adminq_register_page_list(struct gve_priv *priv,
struct gve_queue_page_list *qpl);
int gve_adminq_unregister_page_list(struct gve_priv *priv, u32 page_list_id);
int gve_adminq_set_mtu(struct gve_priv *priv, u64 mtu);
int gve_adminq_report_stats(struct gve_priv *priv, u64 stats_report_len,
dma_addr_t stats_report_addr, u64 interval);
#endif /* _GVE_ADMINQ_H */
Loading

0 comments on commit 24aeb56

Please sign in to comment.