mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	virtio-net: support queue stat
To enhance functionality, we now support reporting statistics through the netdev-generic netlink (netdev-genl) queue stats interface. However, this does not extend to all statistics, so a new field, qstat_offset, has been introduced. This field determines which statistics should be reported via netdev-genl queue stats. Given that queue stats are retrieved individually per queue, it's necessary for the virtnet_get_hw_stats() function to be capable of fetching statistics for a specific queue. As the document https://docs.kernel.org/next/networking/statistics.html#notes-for-driver-authors We should not duplicate the stats which get reported via the netlink API in ethtool. If the stats are for queue stat, that will not be reported by ethtool -S. python3 ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/netdev.yaml --dump qstats-get --json '{"scope": "queue"}' [{'ifindex': 2, 'queue-id': 0, 'queue-type': 'rx', 'rx-bytes': 157844011, 'rx-csum-bad': 0, 'rx-csum-none': 0, 'rx-csum-unnecessary': 2195386, 'rx-hw-drop-overruns': 0, 'rx-hw-drop-ratelimits': 0, 'rx-hw-drops': 12964, 'rx-packets': 598929}, {'ifindex': 2, 'queue-id': 0, 'queue-type': 'tx', 'tx-bytes': 1938511, 'tx-csum-none': 0, 'tx-hw-drop-errors': 0, 'tx-hw-drop-ratelimits': 0, 'tx-hw-drops': 0, 'tx-needs-csum': 61263, 'tx-packets': 15515}] Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com> Reviewed-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
		
							parent
							
								
									0cfe71f45f
								
							
						
					
					
						commit
						d888f04c09
					
				
					 1 changed files with 371 additions and 21 deletions
				
			
		| 
						 | 
					@ -24,6 +24,7 @@
 | 
				
			||||||
#include <net/xdp.h>
 | 
					#include <net/xdp.h>
 | 
				
			||||||
#include <net/net_failover.h>
 | 
					#include <net/net_failover.h>
 | 
				
			||||||
#include <net/netdev_rx_queue.h>
 | 
					#include <net/netdev_rx_queue.h>
 | 
				
			||||||
 | 
					#include <net/netdev_queues.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int napi_weight = NAPI_POLL_WEIGHT;
 | 
					static int napi_weight = NAPI_POLL_WEIGHT;
 | 
				
			||||||
module_param(napi_weight, int, 0444);
 | 
					module_param(napi_weight, int, 0444);
 | 
				
			||||||
| 
						 | 
					@ -78,6 +79,7 @@ static const unsigned long guest_offloads[] = {
 | 
				
			||||||
struct virtnet_stat_desc {
 | 
					struct virtnet_stat_desc {
 | 
				
			||||||
	char desc[ETH_GSTRING_LEN];
 | 
						char desc[ETH_GSTRING_LEN];
 | 
				
			||||||
	size_t offset;
 | 
						size_t offset;
 | 
				
			||||||
 | 
						size_t qstat_offset;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct virtnet_sq_free_stats {
 | 
					struct virtnet_sq_free_stats {
 | 
				
			||||||
| 
						 | 
					@ -107,12 +109,24 @@ struct virtnet_rq_stats {
 | 
				
			||||||
	u64_stats_t kicks;
 | 
						u64_stats_t kicks;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VIRTNET_SQ_STAT(name, m) {name, offsetof(struct virtnet_sq_stats, m)}
 | 
					#define VIRTNET_SQ_STAT(name, m) {name, offsetof(struct virtnet_sq_stats, m), -1}
 | 
				
			||||||
#define VIRTNET_RQ_STAT(name, m) {name, offsetof(struct virtnet_rq_stats, m)}
 | 
					#define VIRTNET_RQ_STAT(name, m) {name, offsetof(struct virtnet_rq_stats, m), -1}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VIRTNET_SQ_STAT_QSTAT(name, m)				\
 | 
				
			||||||
 | 
						{							\
 | 
				
			||||||
 | 
							name,						\
 | 
				
			||||||
 | 
							offsetof(struct virtnet_sq_stats, m),		\
 | 
				
			||||||
 | 
							offsetof(struct netdev_queue_stats_tx, m),	\
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VIRTNET_RQ_STAT_QSTAT(name, m)				\
 | 
				
			||||||
 | 
						{							\
 | 
				
			||||||
 | 
							name,						\
 | 
				
			||||||
 | 
							offsetof(struct virtnet_rq_stats, m),		\
 | 
				
			||||||
 | 
							offsetof(struct netdev_queue_stats_rx, m),	\
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct virtnet_stat_desc virtnet_sq_stats_desc[] = {
 | 
					static const struct virtnet_stat_desc virtnet_sq_stats_desc[] = {
 | 
				
			||||||
	VIRTNET_SQ_STAT("packets",      packets),
 | 
					 | 
				
			||||||
	VIRTNET_SQ_STAT("bytes",        bytes),
 | 
					 | 
				
			||||||
	VIRTNET_SQ_STAT("xdp_tx",       xdp_tx),
 | 
						VIRTNET_SQ_STAT("xdp_tx",       xdp_tx),
 | 
				
			||||||
	VIRTNET_SQ_STAT("xdp_tx_drops", xdp_tx_drops),
 | 
						VIRTNET_SQ_STAT("xdp_tx_drops", xdp_tx_drops),
 | 
				
			||||||
	VIRTNET_SQ_STAT("kicks",        kicks),
 | 
						VIRTNET_SQ_STAT("kicks",        kicks),
 | 
				
			||||||
| 
						 | 
					@ -120,8 +134,6 @@ static const struct virtnet_stat_desc virtnet_sq_stats_desc[] = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct virtnet_stat_desc virtnet_rq_stats_desc[] = {
 | 
					static const struct virtnet_stat_desc virtnet_rq_stats_desc[] = {
 | 
				
			||||||
	VIRTNET_RQ_STAT("packets",       packets),
 | 
					 | 
				
			||||||
	VIRTNET_RQ_STAT("bytes",         bytes),
 | 
					 | 
				
			||||||
	VIRTNET_RQ_STAT("drops",         drops),
 | 
						VIRTNET_RQ_STAT("drops",         drops),
 | 
				
			||||||
	VIRTNET_RQ_STAT("xdp_packets",   xdp_packets),
 | 
						VIRTNET_RQ_STAT("xdp_packets",   xdp_packets),
 | 
				
			||||||
	VIRTNET_RQ_STAT("xdp_tx",        xdp_tx),
 | 
						VIRTNET_RQ_STAT("xdp_tx",        xdp_tx),
 | 
				
			||||||
| 
						 | 
					@ -130,14 +142,25 @@ static const struct virtnet_stat_desc virtnet_rq_stats_desc[] = {
 | 
				
			||||||
	VIRTNET_RQ_STAT("kicks",         kicks),
 | 
						VIRTNET_RQ_STAT("kicks",         kicks),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct virtnet_stat_desc virtnet_sq_stats_desc_qstat[] = {
 | 
				
			||||||
 | 
						VIRTNET_SQ_STAT_QSTAT("packets", packets),
 | 
				
			||||||
 | 
						VIRTNET_SQ_STAT_QSTAT("bytes",   bytes),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct virtnet_stat_desc virtnet_rq_stats_desc_qstat[] = {
 | 
				
			||||||
 | 
						VIRTNET_RQ_STAT_QSTAT("packets", packets),
 | 
				
			||||||
 | 
						VIRTNET_RQ_STAT_QSTAT("bytes",   bytes),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VIRTNET_STATS_DESC_CQ(name) \
 | 
					#define VIRTNET_STATS_DESC_CQ(name) \
 | 
				
			||||||
	{#name, offsetof(struct virtio_net_stats_cvq, name)}
 | 
						{#name, offsetof(struct virtio_net_stats_cvq, name), -1}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VIRTNET_STATS_DESC_RX(class, name) \
 | 
					#define VIRTNET_STATS_DESC_RX(class, name) \
 | 
				
			||||||
	{#name, offsetof(struct virtio_net_stats_rx_ ## class, rx_ ## name)}
 | 
						{#name, offsetof(struct virtio_net_stats_rx_ ## class, rx_ ## name), -1}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VIRTNET_STATS_DESC_TX(class, name) \
 | 
					#define VIRTNET_STATS_DESC_TX(class, name) \
 | 
				
			||||||
	{#name, offsetof(struct virtio_net_stats_tx_ ## class, tx_ ## name)}
 | 
						{#name, offsetof(struct virtio_net_stats_tx_ ## class, tx_ ## name), -1}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct virtnet_stat_desc virtnet_stats_cvq_desc[] = {
 | 
					static const struct virtnet_stat_desc virtnet_stats_cvq_desc[] = {
 | 
				
			||||||
	VIRTNET_STATS_DESC_CQ(command_num),
 | 
						VIRTNET_STATS_DESC_CQ(command_num),
 | 
				
			||||||
| 
						 | 
					@ -177,6 +200,63 @@ static const struct virtnet_stat_desc virtnet_stats_tx_speed_desc[] = {
 | 
				
			||||||
	VIRTNET_STATS_DESC_TX(speed, ratelimit_bytes),
 | 
						VIRTNET_STATS_DESC_TX(speed, ratelimit_bytes),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VIRTNET_STATS_DESC_RX_QSTAT(class, name, qstat_field)			\
 | 
				
			||||||
 | 
						{									\
 | 
				
			||||||
 | 
							#name,								\
 | 
				
			||||||
 | 
							offsetof(struct virtio_net_stats_rx_ ## class, rx_ ## name),	\
 | 
				
			||||||
 | 
							offsetof(struct netdev_queue_stats_rx, qstat_field),		\
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VIRTNET_STATS_DESC_TX_QSTAT(class, name, qstat_field)			\
 | 
				
			||||||
 | 
						{									\
 | 
				
			||||||
 | 
							#name,								\
 | 
				
			||||||
 | 
							offsetof(struct virtio_net_stats_tx_ ## class, tx_ ## name),	\
 | 
				
			||||||
 | 
							offsetof(struct netdev_queue_stats_tx, qstat_field),		\
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct virtnet_stat_desc virtnet_stats_rx_basic_desc_qstat[] = {
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_RX_QSTAT(basic, drops,         hw_drops),
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_RX_QSTAT(basic, drop_overruns, hw_drop_overruns),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct virtnet_stat_desc virtnet_stats_tx_basic_desc_qstat[] = {
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_TX_QSTAT(basic, drops,          hw_drops),
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_TX_QSTAT(basic, drop_malformed, hw_drop_errors),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct virtnet_stat_desc virtnet_stats_rx_csum_desc_qstat[] = {
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_RX_QSTAT(csum, csum_valid, csum_unnecessary),
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_RX_QSTAT(csum, csum_none,  csum_none),
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_RX_QSTAT(csum, csum_bad,   csum_bad),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct virtnet_stat_desc virtnet_stats_tx_csum_desc_qstat[] = {
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_TX_QSTAT(csum, csum_none,  csum_none),
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_TX_QSTAT(csum, needs_csum, needs_csum),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct virtnet_stat_desc virtnet_stats_rx_gso_desc_qstat[] = {
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_RX_QSTAT(gso, gso_packets,           hw_gro_packets),
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_RX_QSTAT(gso, gso_bytes,             hw_gro_bytes),
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_RX_QSTAT(gso, gso_packets_coalesced, hw_gro_wire_packets),
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_RX_QSTAT(gso, gso_bytes_coalesced,   hw_gro_wire_bytes),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct virtnet_stat_desc virtnet_stats_tx_gso_desc_qstat[] = {
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_TX_QSTAT(gso, gso_packets,        hw_gso_packets),
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_TX_QSTAT(gso, gso_bytes,          hw_gso_bytes),
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_TX_QSTAT(gso, gso_segments,       hw_gso_wire_packets),
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_TX_QSTAT(gso, gso_segments_bytes, hw_gso_wire_bytes),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct virtnet_stat_desc virtnet_stats_rx_speed_desc_qstat[] = {
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_RX_QSTAT(speed, ratelimit_packets, hw_drop_ratelimits),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct virtnet_stat_desc virtnet_stats_tx_speed_desc_qstat[] = {
 | 
				
			||||||
 | 
						VIRTNET_STATS_DESC_TX_QSTAT(speed, ratelimit_packets, hw_drop_ratelimits),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VIRTNET_Q_TYPE_RX 0
 | 
					#define VIRTNET_Q_TYPE_RX 0
 | 
				
			||||||
#define VIRTNET_Q_TYPE_TX 1
 | 
					#define VIRTNET_Q_TYPE_TX 1
 | 
				
			||||||
#define VIRTNET_Q_TYPE_CQ 2
 | 
					#define VIRTNET_Q_TYPE_CQ 2
 | 
				
			||||||
| 
						 | 
					@ -2215,6 +2295,10 @@ static int virtnet_receive(struct receive_queue *rq, int budget,
 | 
				
			||||||
		src = (u64_stats_t *)((u8 *)&stats + offset);
 | 
							src = (u64_stats_t *)((u8 *)&stats + offset);
 | 
				
			||||||
		u64_stats_add(item, u64_stats_read(src));
 | 
							u64_stats_add(item, u64_stats_read(src));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u64_stats_add(&rq->stats.packets, u64_stats_read(&stats.packets));
 | 
				
			||||||
 | 
						u64_stats_add(&rq->stats.bytes, u64_stats_read(&stats.bytes));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u64_stats_update_end(&rq->stats.syncp);
 | 
						u64_stats_update_end(&rq->stats.syncp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return packets;
 | 
						return packets;
 | 
				
			||||||
| 
						 | 
					@ -3474,6 +3558,9 @@ static void virtnet_get_stats_string(struct virtnet_info *vi, int type, int qid,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct virtnet_stats_ctx {
 | 
					struct virtnet_stats_ctx {
 | 
				
			||||||
 | 
						/* The stats are write to qstats or ethtool -S */
 | 
				
			||||||
 | 
						bool to_qstat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Used to calculate the offset inside the output buffer. */
 | 
						/* Used to calculate the offset inside the output buffer. */
 | 
				
			||||||
	u32 desc_num[3];
 | 
						u32 desc_num[3];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3489,11 +3576,71 @@ struct virtnet_stats_ctx {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void virtnet_stats_ctx_init(struct virtnet_info *vi,
 | 
					static void virtnet_stats_ctx_init(struct virtnet_info *vi,
 | 
				
			||||||
				   struct virtnet_stats_ctx *ctx,
 | 
									   struct virtnet_stats_ctx *ctx,
 | 
				
			||||||
				   u64 *data)
 | 
									   u64 *data, bool to_qstat)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 queue_type;
 | 
						u32 queue_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx->data = data;
 | 
						ctx->data = data;
 | 
				
			||||||
 | 
						ctx->to_qstat = to_qstat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (to_qstat) {
 | 
				
			||||||
 | 
							ctx->desc_num[VIRTNET_Q_TYPE_RX] = ARRAY_SIZE(virtnet_rq_stats_desc_qstat);
 | 
				
			||||||
 | 
							ctx->desc_num[VIRTNET_Q_TYPE_TX] = ARRAY_SIZE(virtnet_sq_stats_desc_qstat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							queue_type = VIRTNET_Q_TYPE_RX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_BASIC) {
 | 
				
			||||||
 | 
								ctx->bitmap[queue_type]   |= VIRTIO_NET_STATS_TYPE_RX_BASIC;
 | 
				
			||||||
 | 
								ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_rx_basic_desc_qstat);
 | 
				
			||||||
 | 
								ctx->size[queue_type]     += sizeof(struct virtio_net_stats_rx_basic);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_CSUM) {
 | 
				
			||||||
 | 
								ctx->bitmap[queue_type]   |= VIRTIO_NET_STATS_TYPE_RX_CSUM;
 | 
				
			||||||
 | 
								ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_rx_csum_desc_qstat);
 | 
				
			||||||
 | 
								ctx->size[queue_type]     += sizeof(struct virtio_net_stats_rx_csum);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_GSO) {
 | 
				
			||||||
 | 
								ctx->bitmap[queue_type]   |= VIRTIO_NET_STATS_TYPE_RX_GSO;
 | 
				
			||||||
 | 
								ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_rx_gso_desc_qstat);
 | 
				
			||||||
 | 
								ctx->size[queue_type]     += sizeof(struct virtio_net_stats_rx_gso);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_SPEED) {
 | 
				
			||||||
 | 
								ctx->bitmap[queue_type]   |= VIRTIO_NET_STATS_TYPE_RX_SPEED;
 | 
				
			||||||
 | 
								ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_rx_speed_desc_qstat);
 | 
				
			||||||
 | 
								ctx->size[queue_type]     += sizeof(struct virtio_net_stats_rx_speed);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							queue_type = VIRTNET_Q_TYPE_TX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_BASIC) {
 | 
				
			||||||
 | 
								ctx->bitmap[queue_type]   |= VIRTIO_NET_STATS_TYPE_TX_BASIC;
 | 
				
			||||||
 | 
								ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_tx_basic_desc_qstat);
 | 
				
			||||||
 | 
								ctx->size[queue_type]     += sizeof(struct virtio_net_stats_tx_basic);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_CSUM) {
 | 
				
			||||||
 | 
								ctx->bitmap[queue_type]   |= VIRTIO_NET_STATS_TYPE_TX_CSUM;
 | 
				
			||||||
 | 
								ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_tx_csum_desc_qstat);
 | 
				
			||||||
 | 
								ctx->size[queue_type]     += sizeof(struct virtio_net_stats_tx_csum);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_GSO) {
 | 
				
			||||||
 | 
								ctx->bitmap[queue_type]   |= VIRTIO_NET_STATS_TYPE_TX_GSO;
 | 
				
			||||||
 | 
								ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_tx_gso_desc_qstat);
 | 
				
			||||||
 | 
								ctx->size[queue_type]     += sizeof(struct virtio_net_stats_tx_gso);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_SPEED) {
 | 
				
			||||||
 | 
								ctx->bitmap[queue_type]   |= VIRTIO_NET_STATS_TYPE_TX_SPEED;
 | 
				
			||||||
 | 
								ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_tx_speed_desc_qstat);
 | 
				
			||||||
 | 
								ctx->size[queue_type]     += sizeof(struct virtio_net_stats_tx_speed);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx->desc_num[VIRTNET_Q_TYPE_RX] = ARRAY_SIZE(virtnet_rq_stats_desc);
 | 
						ctx->desc_num[VIRTNET_Q_TYPE_RX] = ARRAY_SIZE(virtnet_rq_stats_desc);
 | 
				
			||||||
	ctx->desc_num[VIRTNET_Q_TYPE_TX] = ARRAY_SIZE(virtnet_sq_stats_desc);
 | 
						ctx->desc_num[VIRTNET_Q_TYPE_TX] = ARRAY_SIZE(virtnet_sq_stats_desc);
 | 
				
			||||||
| 
						 | 
					@ -3590,7 +3737,104 @@ static void virtnet_fill_total_fields(struct virtnet_info *vi,
 | 
				
			||||||
	stats_sum_queue(data, num_tx, first_tx_q, vi->curr_queue_pairs);
 | 
						stats_sum_queue(data, num_tx, first_tx_q, vi->curr_queue_pairs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* virtnet_fill_stats - copy the stats to ethtool -S
 | 
					static void virtnet_fill_stats_qstat(struct virtnet_info *vi, u32 qid,
 | 
				
			||||||
 | 
									     struct virtnet_stats_ctx *ctx,
 | 
				
			||||||
 | 
									     const u8 *base, bool drv_stats, u8 reply_type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct virtnet_stat_desc *desc;
 | 
				
			||||||
 | 
						const u64_stats_t *v_stat;
 | 
				
			||||||
 | 
						u64 offset, bitmap;
 | 
				
			||||||
 | 
						const __le64 *v;
 | 
				
			||||||
 | 
						u32 queue_type;
 | 
				
			||||||
 | 
						int i, num;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						queue_type = vq_type(vi, qid);
 | 
				
			||||||
 | 
						bitmap = ctx->bitmap[queue_type];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (drv_stats) {
 | 
				
			||||||
 | 
							if (queue_type == VIRTNET_Q_TYPE_RX) {
 | 
				
			||||||
 | 
								desc = &virtnet_rq_stats_desc_qstat[0];
 | 
				
			||||||
 | 
								num = ARRAY_SIZE(virtnet_rq_stats_desc_qstat);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								desc = &virtnet_sq_stats_desc_qstat[0];
 | 
				
			||||||
 | 
								num = ARRAY_SIZE(virtnet_sq_stats_desc_qstat);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (i = 0; i < num; ++i) {
 | 
				
			||||||
 | 
								offset = desc[i].qstat_offset / sizeof(*ctx->data);
 | 
				
			||||||
 | 
								v_stat = (const u64_stats_t *)(base + desc[i].offset);
 | 
				
			||||||
 | 
								ctx->data[offset] = u64_stats_read(v_stat);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bitmap & VIRTIO_NET_STATS_TYPE_RX_BASIC) {
 | 
				
			||||||
 | 
							desc = &virtnet_stats_rx_basic_desc_qstat[0];
 | 
				
			||||||
 | 
							num = ARRAY_SIZE(virtnet_stats_rx_basic_desc_qstat);
 | 
				
			||||||
 | 
							if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_BASIC)
 | 
				
			||||||
 | 
								goto found;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bitmap & VIRTIO_NET_STATS_TYPE_RX_CSUM) {
 | 
				
			||||||
 | 
							desc = &virtnet_stats_rx_csum_desc_qstat[0];
 | 
				
			||||||
 | 
							num = ARRAY_SIZE(virtnet_stats_rx_csum_desc_qstat);
 | 
				
			||||||
 | 
							if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_CSUM)
 | 
				
			||||||
 | 
								goto found;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bitmap & VIRTIO_NET_STATS_TYPE_RX_GSO) {
 | 
				
			||||||
 | 
							desc = &virtnet_stats_rx_gso_desc_qstat[0];
 | 
				
			||||||
 | 
							num = ARRAY_SIZE(virtnet_stats_rx_gso_desc_qstat);
 | 
				
			||||||
 | 
							if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_GSO)
 | 
				
			||||||
 | 
								goto found;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bitmap & VIRTIO_NET_STATS_TYPE_RX_SPEED) {
 | 
				
			||||||
 | 
							desc = &virtnet_stats_rx_speed_desc_qstat[0];
 | 
				
			||||||
 | 
							num = ARRAY_SIZE(virtnet_stats_rx_speed_desc_qstat);
 | 
				
			||||||
 | 
							if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_SPEED)
 | 
				
			||||||
 | 
								goto found;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bitmap & VIRTIO_NET_STATS_TYPE_TX_BASIC) {
 | 
				
			||||||
 | 
							desc = &virtnet_stats_tx_basic_desc_qstat[0];
 | 
				
			||||||
 | 
							num = ARRAY_SIZE(virtnet_stats_tx_basic_desc_qstat);
 | 
				
			||||||
 | 
							if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_BASIC)
 | 
				
			||||||
 | 
								goto found;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bitmap & VIRTIO_NET_STATS_TYPE_TX_CSUM) {
 | 
				
			||||||
 | 
							desc = &virtnet_stats_tx_csum_desc_qstat[0];
 | 
				
			||||||
 | 
							num = ARRAY_SIZE(virtnet_stats_tx_csum_desc_qstat);
 | 
				
			||||||
 | 
							if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_CSUM)
 | 
				
			||||||
 | 
								goto found;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bitmap & VIRTIO_NET_STATS_TYPE_TX_GSO) {
 | 
				
			||||||
 | 
							desc = &virtnet_stats_tx_gso_desc_qstat[0];
 | 
				
			||||||
 | 
							num = ARRAY_SIZE(virtnet_stats_tx_gso_desc_qstat);
 | 
				
			||||||
 | 
							if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_GSO)
 | 
				
			||||||
 | 
								goto found;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bitmap & VIRTIO_NET_STATS_TYPE_TX_SPEED) {
 | 
				
			||||||
 | 
							desc = &virtnet_stats_tx_speed_desc_qstat[0];
 | 
				
			||||||
 | 
							num = ARRAY_SIZE(virtnet_stats_tx_speed_desc_qstat);
 | 
				
			||||||
 | 
							if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_SPEED)
 | 
				
			||||||
 | 
								goto found;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					found:
 | 
				
			||||||
 | 
						for (i = 0; i < num; ++i) {
 | 
				
			||||||
 | 
							offset = desc[i].qstat_offset / sizeof(*ctx->data);
 | 
				
			||||||
 | 
							v = (const __le64 *)(base + desc[i].offset);
 | 
				
			||||||
 | 
							ctx->data[offset] = le64_to_cpu(*v);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* virtnet_fill_stats - copy the stats to qstats or ethtool -S
 | 
				
			||||||
 * The stats source is the device or the driver.
 | 
					 * The stats source is the device or the driver.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @vi: virtio net info
 | 
					 * @vi: virtio net info
 | 
				
			||||||
| 
						 | 
					@ -3611,6 +3855,9 @@ static void virtnet_fill_stats(struct virtnet_info *vi, u32 qid,
 | 
				
			||||||
	const __le64 *v;
 | 
						const __le64 *v;
 | 
				
			||||||
	int i, num;
 | 
						int i, num;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ctx->to_qstat)
 | 
				
			||||||
 | 
							return virtnet_fill_stats_qstat(vi, qid, ctx, base, drv_stats, reply_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	num_cq = ctx->desc_num[VIRTNET_Q_TYPE_CQ];
 | 
						num_cq = ctx->desc_num[VIRTNET_Q_TYPE_CQ];
 | 
				
			||||||
	num_rx = ctx->desc_num[VIRTNET_Q_TYPE_RX];
 | 
						num_rx = ctx->desc_num[VIRTNET_Q_TYPE_RX];
 | 
				
			||||||
	num_tx = ctx->desc_num[VIRTNET_Q_TYPE_TX];
 | 
						num_tx = ctx->desc_num[VIRTNET_Q_TYPE_TX];
 | 
				
			||||||
| 
						 | 
					@ -3770,22 +4017,34 @@ static void virtnet_make_stat_req(struct virtnet_info *vi,
 | 
				
			||||||
	*idx += 1;
 | 
						*idx += 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* qid: -1: get stats of all vq.
 | 
				
			||||||
 | 
					 *     > 0: get the stats for the special vq. This must not be cvq.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
static int virtnet_get_hw_stats(struct virtnet_info *vi,
 | 
					static int virtnet_get_hw_stats(struct virtnet_info *vi,
 | 
				
			||||||
				struct virtnet_stats_ctx *ctx)
 | 
									struct virtnet_stats_ctx *ctx, int qid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						int qnum, i, j, res_size, qtype, last_vq, first_vq;
 | 
				
			||||||
	struct virtio_net_ctrl_queue_stats *req;
 | 
						struct virtio_net_ctrl_queue_stats *req;
 | 
				
			||||||
	int qnum, i, j, res_size, qtype, last_vq;
 | 
						bool enable_cvq;
 | 
				
			||||||
	void *reply;
 | 
						void *reply;
 | 
				
			||||||
	int ok;
 | 
						int ok;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_DEVICE_STATS))
 | 
						if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_DEVICE_STATS))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (qid == -1) {
 | 
				
			||||||
		last_vq = vi->curr_queue_pairs * 2 - 1;
 | 
							last_vq = vi->curr_queue_pairs * 2 - 1;
 | 
				
			||||||
 | 
							first_vq = 0;
 | 
				
			||||||
 | 
							enable_cvq = true;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							last_vq = qid;
 | 
				
			||||||
 | 
							first_vq = qid;
 | 
				
			||||||
 | 
							enable_cvq = false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	qnum = 0;
 | 
						qnum = 0;
 | 
				
			||||||
	res_size = 0;
 | 
						res_size = 0;
 | 
				
			||||||
	for (i = 0; i <= last_vq ; ++i) {
 | 
						for (i = first_vq; i <= last_vq ; ++i) {
 | 
				
			||||||
		qtype = vq_type(vi, i);
 | 
							qtype = vq_type(vi, i);
 | 
				
			||||||
		if (ctx->bitmap[qtype]) {
 | 
							if (ctx->bitmap[qtype]) {
 | 
				
			||||||
			++qnum;
 | 
								++qnum;
 | 
				
			||||||
| 
						 | 
					@ -3793,7 +4052,7 @@ static int virtnet_get_hw_stats(struct virtnet_info *vi,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ctx->bitmap[VIRTNET_Q_TYPE_CQ]) {
 | 
						if (enable_cvq && ctx->bitmap[VIRTNET_Q_TYPE_CQ]) {
 | 
				
			||||||
		res_size += ctx->size[VIRTNET_Q_TYPE_CQ];
 | 
							res_size += ctx->size[VIRTNET_Q_TYPE_CQ];
 | 
				
			||||||
		qnum += 1;
 | 
							qnum += 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -3809,9 +4068,10 @@ static int virtnet_get_hw_stats(struct virtnet_info *vi,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	j = 0;
 | 
						j = 0;
 | 
				
			||||||
	for (i = 0; i <= last_vq ; ++i)
 | 
						for (i = first_vq; i <= last_vq ; ++i)
 | 
				
			||||||
		virtnet_make_stat_req(vi, ctx, req, i, &j);
 | 
							virtnet_make_stat_req(vi, ctx, req, i, &j);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (enable_cvq)
 | 
				
			||||||
		virtnet_make_stat_req(vi, ctx, req, vi->max_queue_pairs * 2, &j);
 | 
							virtnet_make_stat_req(vi, ctx, req, vi->max_queue_pairs * 2, &j);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ok = __virtnet_get_hw_stats(vi, ctx, req, sizeof(*req) * j, reply, res_size);
 | 
						ok = __virtnet_get_hw_stats(vi, ctx, req, sizeof(*req) * j, reply, res_size);
 | 
				
			||||||
| 
						 | 
					@ -3853,7 +4113,7 @@ static int virtnet_get_sset_count(struct net_device *dev, int sset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (sset) {
 | 
						switch (sset) {
 | 
				
			||||||
	case ETH_SS_STATS:
 | 
						case ETH_SS_STATS:
 | 
				
			||||||
		virtnet_stats_ctx_init(vi, &ctx, NULL);
 | 
							virtnet_stats_ctx_init(vi, &ctx, NULL, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pair_count = ctx.desc_num[VIRTNET_Q_TYPE_RX] + ctx.desc_num[VIRTNET_Q_TYPE_TX];
 | 
							pair_count = ctx.desc_num[VIRTNET_Q_TYPE_RX] + ctx.desc_num[VIRTNET_Q_TYPE_TX];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3872,8 +4132,8 @@ static void virtnet_get_ethtool_stats(struct net_device *dev,
 | 
				
			||||||
	unsigned int start, i;
 | 
						unsigned int start, i;
 | 
				
			||||||
	const u8 *stats_base;
 | 
						const u8 *stats_base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtnet_stats_ctx_init(vi, &ctx, data);
 | 
						virtnet_stats_ctx_init(vi, &ctx, data, false);
 | 
				
			||||||
	if (virtnet_get_hw_stats(vi, &ctx))
 | 
						if (virtnet_get_hw_stats(vi, &ctx, -1))
 | 
				
			||||||
		dev_warn(&vi->dev->dev, "Failed to get hw stats.\n");
 | 
							dev_warn(&vi->dev->dev, "Failed to get hw stats.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < vi->curr_queue_pairs; i++) {
 | 
						for (i = 0; i < vi->curr_queue_pairs; i++) {
 | 
				
			||||||
| 
						 | 
					@ -4428,6 +4688,95 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
 | 
				
			||||||
	.set_rxnfc = virtnet_set_rxnfc,
 | 
						.set_rxnfc = virtnet_set_rxnfc,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void virtnet_get_queue_stats_rx(struct net_device *dev, int i,
 | 
				
			||||||
 | 
									       struct netdev_queue_stats_rx *stats)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct virtnet_info *vi = netdev_priv(dev);
 | 
				
			||||||
 | 
						struct receive_queue *rq = &vi->rq[i];
 | 
				
			||||||
 | 
						struct virtnet_stats_ctx ctx = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtnet_stats_ctx_init(vi, &ctx, (void *)stats, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtnet_get_hw_stats(vi, &ctx, i * 2);
 | 
				
			||||||
 | 
						virtnet_fill_stats(vi, i * 2, &ctx, (void *)&rq->stats, true, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void virtnet_get_queue_stats_tx(struct net_device *dev, int i,
 | 
				
			||||||
 | 
									       struct netdev_queue_stats_tx *stats)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct virtnet_info *vi = netdev_priv(dev);
 | 
				
			||||||
 | 
						struct send_queue *sq = &vi->sq[i];
 | 
				
			||||||
 | 
						struct virtnet_stats_ctx ctx = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtnet_stats_ctx_init(vi, &ctx, (void *)stats, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtnet_get_hw_stats(vi, &ctx, i * 2 + 1);
 | 
				
			||||||
 | 
						virtnet_fill_stats(vi, i * 2 + 1, &ctx, (void *)&sq->stats, true, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void virtnet_get_base_stats(struct net_device *dev,
 | 
				
			||||||
 | 
									   struct netdev_queue_stats_rx *rx,
 | 
				
			||||||
 | 
									   struct netdev_queue_stats_tx *tx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct virtnet_info *vi = netdev_priv(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* The queue stats of the virtio-net will not be reset. So here we
 | 
				
			||||||
 | 
						 * return 0.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						rx->bytes = 0;
 | 
				
			||||||
 | 
						rx->packets = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_BASIC) {
 | 
				
			||||||
 | 
							rx->hw_drops = 0;
 | 
				
			||||||
 | 
							rx->hw_drop_overruns = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_CSUM) {
 | 
				
			||||||
 | 
							rx->csum_unnecessary = 0;
 | 
				
			||||||
 | 
							rx->csum_none = 0;
 | 
				
			||||||
 | 
							rx->csum_bad = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_GSO) {
 | 
				
			||||||
 | 
							rx->hw_gro_packets = 0;
 | 
				
			||||||
 | 
							rx->hw_gro_bytes = 0;
 | 
				
			||||||
 | 
							rx->hw_gro_wire_packets = 0;
 | 
				
			||||||
 | 
							rx->hw_gro_wire_bytes = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_SPEED)
 | 
				
			||||||
 | 
							rx->hw_drop_ratelimits = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tx->bytes = 0;
 | 
				
			||||||
 | 
						tx->packets = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_BASIC) {
 | 
				
			||||||
 | 
							tx->hw_drops = 0;
 | 
				
			||||||
 | 
							tx->hw_drop_errors = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_CSUM) {
 | 
				
			||||||
 | 
							tx->csum_none = 0;
 | 
				
			||||||
 | 
							tx->needs_csum = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_GSO) {
 | 
				
			||||||
 | 
							tx->hw_gso_packets = 0;
 | 
				
			||||||
 | 
							tx->hw_gso_bytes = 0;
 | 
				
			||||||
 | 
							tx->hw_gso_wire_packets = 0;
 | 
				
			||||||
 | 
							tx->hw_gso_wire_bytes = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_SPEED)
 | 
				
			||||||
 | 
							tx->hw_drop_ratelimits = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct netdev_stat_ops virtnet_stat_ops = {
 | 
				
			||||||
 | 
						.get_queue_stats_rx	= virtnet_get_queue_stats_rx,
 | 
				
			||||||
 | 
						.get_queue_stats_tx	= virtnet_get_queue_stats_tx,
 | 
				
			||||||
 | 
						.get_base_stats		= virtnet_get_base_stats,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void virtnet_freeze_down(struct virtio_device *vdev)
 | 
					static void virtnet_freeze_down(struct virtio_device *vdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct virtnet_info *vi = vdev->priv;
 | 
						struct virtnet_info *vi = vdev->priv;
 | 
				
			||||||
| 
						 | 
					@ -5231,6 +5580,7 @@ static int virtnet_probe(struct virtio_device *vdev)
 | 
				
			||||||
	dev->priv_flags |= IFF_UNICAST_FLT | IFF_LIVE_ADDR_CHANGE |
 | 
						dev->priv_flags |= IFF_UNICAST_FLT | IFF_LIVE_ADDR_CHANGE |
 | 
				
			||||||
			   IFF_TX_SKB_NO_LINEAR;
 | 
								   IFF_TX_SKB_NO_LINEAR;
 | 
				
			||||||
	dev->netdev_ops = &virtnet_netdev;
 | 
						dev->netdev_ops = &virtnet_netdev;
 | 
				
			||||||
 | 
						dev->stat_ops = &virtnet_stat_ops;
 | 
				
			||||||
	dev->features = NETIF_F_HIGHDMA;
 | 
						dev->features = NETIF_F_HIGHDMA;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev->ethtool_ops = &virtnet_ethtool_ops;
 | 
						dev->ethtool_ops = &virtnet_ethtool_ops;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue