Commit 5bc461fd authored by David S. Miller's avatar David S. Miller

Merge branch 'Add-GVE-Features'

David Awogbemila says:

====================
Add GVE Features.

Note: Patch 4 in v3 was dropped.

Patch 4 (patch 5 in v3): Start/stop timer only when report stats is
				enabled/disabled.
Patch 7 (patch 8 in v3): Use netdev_info, not dev_info, to log
				device link status.
====================
Acked-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e7a08121 7e074d5a
...@@ -27,6 +27,17 @@ ...@@ -27,6 +27,17 @@
/* 1 for management, 1 for rx, 1 for tx */ /* 1 for management, 1 for rx, 1 for tx */
#define GVE_MIN_MSIX 3 #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
/* Numbers of NIC tx/rx stats in stats report. */
#define NIC_TX_STATS_REPORT_NUM 0
#define NIC_RX_STATS_REPORT_NUM 4
/* Each slot in the desc ring has a 1:1 mapping to a slot in the data ring */ /* 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_queue {
struct gve_rx_desc *desc_ring; /* the descriptor ring */ struct gve_rx_desc *desc_ring; /* the descriptor ring */
...@@ -71,6 +82,11 @@ struct gve_rx_ring { ...@@ -71,6 +82,11 @@ struct gve_rx_ring {
u32 cnt; /* free-running total number of completed packets */ u32 cnt; /* free-running total number of completed packets */
u32 fill_cnt; /* free-running total number of descs and buffs posted */ u32 fill_cnt; /* free-running total number of descs and buffs posted */
u32 mask; /* masks the cnt and fill_cnt to the size of the ring */ u32 mask; /* masks the cnt and fill_cnt to the size of the ring */
u64 rx_copybreak_pkt; /* free-running count of copybreak packets */
u64 rx_copied_pkt; /* free-running total number of copied packets */
u64 rx_skb_alloc_fail; /* free-running count of skb alloc fails */
u64 rx_buf_alloc_fail; /* free-running count of buffer alloc fails */
u64 rx_desc_err_dropped_pkt; /* free-running count of packets dropped by descriptor error */
u32 q_num; /* queue index */ u32 q_num; /* queue index */
u32 ntfy_id; /* notification block index */ u32 ntfy_id; /* notification block index */
struct gve_queue_resources *q_resources; /* head and tail pointer idx */ struct gve_queue_resources *q_resources; /* head and tail pointer idx */
...@@ -202,24 +218,63 @@ struct gve_priv { ...@@ -202,24 +218,63 @@ struct gve_priv {
dma_addr_t adminq_bus_addr; dma_addr_t adminq_bus_addr;
u32 adminq_mask; /* masks prod_cnt to adminq size */ u32 adminq_mask; /* masks prod_cnt to adminq size */
u32 adminq_prod_cnt; /* free-running count of AQ cmds executed */ u32 adminq_prod_cnt; /* free-running count of AQ cmds executed */
u32 adminq_cmd_fail; /* free-running count of AQ cmds failed */
u32 adminq_timeouts; /* free-running count of AQ cmds timeouts */
/* free-running count of per AQ cmd executed */
u32 adminq_describe_device_cnt;
u32 adminq_cfg_device_resources_cnt;
u32 adminq_register_page_list_cnt;
u32 adminq_unregister_page_list_cnt;
u32 adminq_create_tx_queue_cnt;
u32 adminq_create_rx_queue_cnt;
u32 adminq_destroy_tx_queue_cnt;
u32 adminq_destroy_rx_queue_cnt;
u32 adminq_dcfg_device_resources_cnt;
u32 adminq_set_driver_parameter_cnt;
u32 adminq_report_stats_cnt;
u32 adminq_report_link_speed_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 workqueue_struct *gve_wq;
struct work_struct service_task; struct work_struct service_task;
struct work_struct stats_report_task;
unsigned long service_task_flags; unsigned long service_task_flags;
unsigned long state_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;
/* Gvnic device link speed from hypervisor. */
u64 link_speed;
}; };
enum gve_service_task_flags { enum gve_service_task_flags_bit {
GVE_PRIV_FLAGS_DO_RESET = BIT(1), GVE_PRIV_FLAGS_DO_RESET = 1,
GVE_PRIV_FLAGS_RESET_IN_PROGRESS = BIT(2), GVE_PRIV_FLAGS_RESET_IN_PROGRESS = 2,
GVE_PRIV_FLAGS_PROBE_IN_PROGRESS = BIT(3), GVE_PRIV_FLAGS_PROBE_IN_PROGRESS = 3,
GVE_PRIV_FLAGS_DO_REPORT_STATS = 4,
}; };
enum gve_state_flags { enum gve_state_flags_bit {
GVE_PRIV_FLAGS_ADMIN_QUEUE_OK = BIT(1), GVE_PRIV_FLAGS_ADMIN_QUEUE_OK = 1,
GVE_PRIV_FLAGS_DEVICE_RESOURCES_OK = BIT(2), GVE_PRIV_FLAGS_DEVICE_RESOURCES_OK = 2,
GVE_PRIV_FLAGS_DEVICE_RINGS_OK = BIT(3), GVE_PRIV_FLAGS_DEVICE_RINGS_OK = 3,
GVE_PRIV_FLAGS_NAPI_ENABLED = BIT(4), 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) static inline bool gve_get_do_reset(struct gve_priv *priv)
...@@ -269,6 +324,22 @@ static inline void gve_clear_probe_in_progress(struct gve_priv *priv) ...@@ -269,6 +324,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); 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) static inline bool gve_get_admin_queue_ok(struct gve_priv *priv)
{ {
return test_bit(GVE_PRIV_FLAGS_ADMIN_QUEUE_OK, &priv->state_flags); return test_bit(GVE_PRIV_FLAGS_ADMIN_QUEUE_OK, &priv->state_flags);
...@@ -329,6 +400,16 @@ static inline void gve_clear_napi_enabled(struct gve_priv *priv) ...@@ -329,6 +400,16 @@ static inline void gve_clear_napi_enabled(struct gve_priv *priv)
clear_bit(GVE_PRIV_FLAGS_NAPI_ENABLED, &priv->state_flags); 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 /* Returns the address of the ntfy_blocks irq doorbell
*/ */
static inline __be32 __iomem *gve_irq_doorbell(struct gve_priv *priv, static inline __be32 __iomem *gve_irq_doorbell(struct gve_priv *priv,
...@@ -426,7 +507,8 @@ static inline bool gve_can_recycle_pages(struct net_device *dev) ...@@ -426,7 +507,8 @@ static inline bool gve_can_recycle_pages(struct net_device *dev)
} }
/* buffers */ /* buffers */
int gve_alloc_page(struct device *dev, struct page **page, dma_addr_t *dma, int gve_alloc_page(struct gve_priv *priv, struct device *dev,
struct page **page, dma_addr_t *dma,
enum dma_data_direction); enum dma_data_direction);
void gve_free_page(struct device *dev, struct page *page, dma_addr_t dma, void gve_free_page(struct device *dev, struct page *page, dma_addr_t dma,
enum dma_data_direction); enum dma_data_direction);
...@@ -450,6 +532,8 @@ int gve_reset(struct gve_priv *priv, bool attempt_teardown); ...@@ -450,6 +532,8 @@ int gve_reset(struct gve_priv *priv, bool attempt_teardown);
int gve_adjust_queues(struct gve_priv *priv, int gve_adjust_queues(struct gve_priv *priv,
struct gve_queue_config new_rx_config, struct gve_queue_config new_rx_config,
struct gve_queue_config new_tx_config); struct gve_queue_config new_tx_config);
/* report stats handling */
void gve_handle_report_stats(struct gve_priv *priv);
/* exported by ethtool.c */ /* exported by ethtool.c */
extern const struct ethtool_ops gve_ethtool_ops; extern const struct ethtool_ops gve_ethtool_ops;
/* needed by ethtool */ /* needed by ethtool */
......
...@@ -21,6 +21,8 @@ enum gve_adminq_opcodes { ...@@ -21,6 +21,8 @@ enum gve_adminq_opcodes {
GVE_ADMINQ_DESTROY_RX_QUEUE = 0x8, GVE_ADMINQ_DESTROY_RX_QUEUE = 0x8,
GVE_ADMINQ_DECONFIGURE_DEVICE_RESOURCES = 0x9, GVE_ADMINQ_DECONFIGURE_DEVICE_RESOURCES = 0x9,
GVE_ADMINQ_SET_DRIVER_PARAMETER = 0xB, GVE_ADMINQ_SET_DRIVER_PARAMETER = 0xB,
GVE_ADMINQ_REPORT_STATS = 0xC,
GVE_ADMINQ_REPORT_LINK_SPEED = 0xD
}; };
/* Admin queue status codes */ /* Admin queue status codes */
...@@ -172,6 +174,51 @@ struct gve_adminq_set_driver_parameter { ...@@ -172,6 +174,51 @@ struct gve_adminq_set_driver_parameter {
static_assert(sizeof(struct gve_adminq_set_driver_parameter) == 16); 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 gve_adminq_report_link_speed {
__be64 link_speed_address;
};
static_assert(sizeof(struct gve_adminq_report_link_speed) == 8);
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,
// stats from NIC
RX_QUEUE_DROP_CNT = 65,
RX_NO_BUFFERS_POSTED = 66,
RX_DROPS_PACKET_OVER_MRU = 67,
RX_DROPS_INVALID_CHECKSUM = 68,
};
union gve_adminq_command { union gve_adminq_command {
struct { struct {
__be32 opcode; __be32 opcode;
...@@ -187,6 +234,8 @@ union gve_adminq_command { ...@@ -187,6 +234,8 @@ union gve_adminq_command {
struct gve_adminq_register_page_list reg_page_list; struct gve_adminq_register_page_list reg_page_list;
struct gve_adminq_unregister_page_list unreg_page_list; struct gve_adminq_unregister_page_list unreg_page_list;
struct gve_adminq_set_driver_parameter set_driver_param; struct gve_adminq_set_driver_parameter set_driver_param;
struct gve_adminq_report_stats report_stats;
struct gve_adminq_report_link_speed report_link_speed;
}; };
}; };
u8 reserved[64]; u8 reserved[64];
...@@ -197,8 +246,6 @@ static_assert(sizeof(union gve_adminq_command) == 64); ...@@ -197,8 +246,6 @@ static_assert(sizeof(union gve_adminq_command) == 64);
int gve_adminq_alloc(struct device *dev, struct gve_priv *priv); int gve_adminq_alloc(struct device *dev, struct gve_priv *priv);
void gve_adminq_free(struct device *dev, struct gve_priv *priv); void gve_adminq_free(struct device *dev, struct gve_priv *priv);
void gve_adminq_release(struct gve_priv *priv); void gve_adminq_release(struct gve_priv *priv);
int gve_adminq_execute_cmd(struct gve_priv *priv,
union gve_adminq_command *cmd_orig);
int gve_adminq_describe_device(struct gve_priv *priv); int gve_adminq_describe_device(struct gve_priv *priv);
int gve_adminq_configure_device_resources(struct gve_priv *priv, int gve_adminq_configure_device_resources(struct gve_priv *priv,
dma_addr_t counter_array_bus_addr, dma_addr_t counter_array_bus_addr,
...@@ -206,12 +253,15 @@ int gve_adminq_configure_device_resources(struct gve_priv *priv, ...@@ -206,12 +253,15 @@ int gve_adminq_configure_device_resources(struct gve_priv *priv,
dma_addr_t db_array_bus_addr, dma_addr_t db_array_bus_addr,
u32 num_ntfy_blks); u32 num_ntfy_blks);
int gve_adminq_deconfigure_device_resources(struct gve_priv *priv); int gve_adminq_deconfigure_device_resources(struct gve_priv *priv);
int gve_adminq_create_tx_queue(struct gve_priv *priv, u32 queue_id); int gve_adminq_create_tx_queues(struct gve_priv *priv, u32 num_queues);
int gve_adminq_destroy_tx_queue(struct gve_priv *priv, u32 queue_id); int gve_adminq_destroy_tx_queues(struct gve_priv *priv, u32 queue_id);
int gve_adminq_create_rx_queue(struct gve_priv *priv, u32 queue_id); int gve_adminq_create_rx_queues(struct gve_priv *priv, u32 num_queues);
int gve_adminq_destroy_rx_queue(struct gve_priv *priv, u32 queue_id); int gve_adminq_destroy_rx_queues(struct gve_priv *priv, u32 queue_id);
int gve_adminq_register_page_list(struct gve_priv *priv, int gve_adminq_register_page_list(struct gve_priv *priv,
struct gve_queue_page_list *qpl); struct gve_queue_page_list *qpl);
int gve_adminq_unregister_page_list(struct gve_priv *priv, u32 page_list_id); 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_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);
int gve_adminq_report_link_speed(struct gve_priv *priv);
#endif /* _GVE_ADMINQ_H */ #endif /* _GVE_ADMINQ_H */
This diff is collapsed.
...@@ -23,5 +23,6 @@ struct gve_registers { ...@@ -23,5 +23,6 @@ struct gve_registers {
enum gve_device_status_flags { enum gve_device_status_flags {
GVE_DEVICE_STATUS_RESET_MASK = BIT(1), GVE_DEVICE_STATUS_RESET_MASK = BIT(1),
GVE_DEVICE_STATUS_LINK_STATUS_MASK = BIT(2), GVE_DEVICE_STATUS_LINK_STATUS_MASK = BIT(2),
GVE_DEVICE_STATUS_REPORT_STATS_MASK = BIT(3),
}; };
#endif /* _GVE_REGISTER_H_ */ #endif /* _GVE_REGISTER_H_ */
...@@ -225,7 +225,8 @@ static enum pkt_hash_types gve_rss_type(__be16 pkt_flags) ...@@ -225,7 +225,8 @@ static enum pkt_hash_types gve_rss_type(__be16 pkt_flags)
return PKT_HASH_TYPE_L2; return PKT_HASH_TYPE_L2;
} }
static struct sk_buff *gve_rx_copy(struct net_device *dev, static struct sk_buff *gve_rx_copy(struct gve_rx_ring *rx,
struct net_device *dev,
struct napi_struct *napi, struct napi_struct *napi,
struct gve_rx_slot_page_info *page_info, struct gve_rx_slot_page_info *page_info,
u16 len) u16 len)
...@@ -242,6 +243,11 @@ static struct sk_buff *gve_rx_copy(struct net_device *dev, ...@@ -242,6 +243,11 @@ static struct sk_buff *gve_rx_copy(struct net_device *dev,
skb_copy_to_linear_data(skb, va, len); skb_copy_to_linear_data(skb, va, len);
skb->protocol = eth_type_trans(skb, dev); skb->protocol = eth_type_trans(skb, dev);
u64_stats_update_begin(&rx->statss);
rx->rx_copied_pkt++;
u64_stats_update_end(&rx->statss);
return skb; return skb;
} }
...@@ -284,8 +290,12 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc, ...@@ -284,8 +290,12 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc,
u16 len; u16 len;
/* drop this packet */ /* drop this packet */
if (unlikely(rx_desc->flags_seq & GVE_RXF_ERR)) if (unlikely(rx_desc->flags_seq & GVE_RXF_ERR)) {
u64_stats_update_begin(&rx->statss);
rx->rx_desc_err_dropped_pkt++;
u64_stats_update_end(&rx->statss);
return true; return true;
}
len = be16_to_cpu(rx_desc->len) - GVE_RX_PAD; len = be16_to_cpu(rx_desc->len) - GVE_RX_PAD;
page_info = &rx->data.page_info[idx]; page_info = &rx->data.page_info[idx];
...@@ -300,11 +310,14 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc, ...@@ -300,11 +310,14 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc,
if (PAGE_SIZE == 4096) { if (PAGE_SIZE == 4096) {
if (len <= priv->rx_copybreak) { if (len <= priv->rx_copybreak) {
/* Just copy small packets */ /* Just copy small packets */
skb = gve_rx_copy(dev, napi, page_info, len); skb = gve_rx_copy(rx, dev, napi, page_info, len);
u64_stats_update_begin(&rx->statss);
rx->rx_copybreak_pkt++;
u64_stats_update_end(&rx->statss);
goto have_skb; goto have_skb;
} }
if (unlikely(!gve_can_recycle_pages(dev))) { if (unlikely(!gve_can_recycle_pages(dev))) {
skb = gve_rx_copy(dev, napi, page_info, len); skb = gve_rx_copy(rx, dev, napi, page_info, len);
goto have_skb; goto have_skb;
} }
pagecount = page_count(page_info->page); pagecount = page_count(page_info->page);
...@@ -314,8 +327,12 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc, ...@@ -314,8 +327,12 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc,
* stack. * stack.
*/ */
skb = gve_rx_add_frags(dev, napi, page_info, len); skb = gve_rx_add_frags(dev, napi, page_info, len);
if (!skb) if (!skb) {
u64_stats_update_begin(&rx->statss);
rx->rx_skb_alloc_fail++;
u64_stats_update_end(&rx->statss);
return true; return true;
}
/* Make sure the kernel stack can't release the page */ /* Make sure the kernel stack can't release the page */
get_page(page_info->page); get_page(page_info->page);
/* "flip" to other packet buffer on this page */ /* "flip" to other packet buffer on this page */
...@@ -324,21 +341,25 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc, ...@@ -324,21 +341,25 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc,
/* We have previously passed the other half of this /* We have previously passed the other half of this
* page up the stack, but it has not yet been freed. * page up the stack, but it has not yet been freed.
*/ */
skb = gve_rx_copy(dev, napi, page_info, len); skb = gve_rx_copy(rx, dev, napi, page_info, len);
} else { } else {
WARN(pagecount < 1, "Pagecount should never be < 1"); WARN(pagecount < 1, "Pagecount should never be < 1");
return false; return false;
} }
} else { } else {
skb = gve_rx_copy(dev, napi, page_info, len); skb = gve_rx_copy(rx, dev, napi, page_info, len);
} }
have_skb: have_skb:
/* We didn't manage to allocate an skb but we haven't had any /* We didn't manage to allocate an skb but we haven't had any
* reset worthy failures. * reset worthy failures.
*/ */
if (!skb) if (!skb) {
u64_stats_update_begin(&rx->statss);
rx->rx_skb_alloc_fail++;
u64_stats_update_end(&rx->statss);
return true; return true;
}
if (likely(feat & NETIF_F_RXCSUM)) { if (likely(feat & NETIF_F_RXCSUM)) {
/* NIC passes up the partial sum */ /* NIC passes up the partial sum */
......
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