On Tue, Feb 27, 2024 at 04:03:00PM +0800, Xuan Zhuo wrote: > As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82 > > make virtio-net support getting the stats from the device by ethtool -S > <eth0>. > > Signed-off-by: Xuan Zhuo <xuanzhuo@xxxxxxxxxxxxxxxxx> ... > +static int virtnet_get_hw_stats(struct virtnet_info *vi, > + struct virtnet_stats_ctx *ctx) > +{ > + struct virtio_net_ctrl_queue_stats *req; > + struct virtio_net_stats_reply_hdr *hdr; > + struct scatterlist sgs_in, sgs_out; > + u32 num_rx, num_tx, num_cq, offset; > + int qnum, i, j, qid, res_size; > + struct virtnet_stats_map *m; > + void *reply, *p; > + u64 bitmap; > + int ok; > + u64 *v; > + > + if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_DEVICE_STATS)) > + return 0; > + > + qnum = 0; > + if (ctx->bitmap_cq) > + qnum += 1; > + > + if (ctx->bitmap_rx) > + qnum += vi->curr_queue_pairs; > + > + if (ctx->bitmap_tx) > + qnum += vi->curr_queue_pairs; > + > + req = kcalloc(qnum, sizeof(*req), GFP_KERNEL); > + if (!req) > + return -ENOMEM; > + > + res_size = (ctx->size_rx + ctx->size_tx) * vi->curr_queue_pairs + ctx->size_cq; > + reply = kmalloc(res_size, GFP_KERNEL); > + if (!reply) { > + kfree(req); > + return -ENOMEM; > + } > + > + j = 0; > + for (i = 0; i < vi->curr_queue_pairs; ++i) { > + if (ctx->bitmap_rx) { > + req->stats[j].vq_index = cpu_to_le16(i * 2); > + req->stats[j].types_bitmap[0] = cpu_to_le64(ctx->bitmap_rx); > + ++j; > + } > + > + if (ctx->bitmap_tx) { > + req->stats[j].vq_index = cpu_to_le16(i * 2 + 1); > + req->stats[j].types_bitmap[0] = cpu_to_le64(ctx->bitmap_tx); > + ++j; > + } > + } > + > + if (ctx->size_cq) { > + req->stats[j].vq_index = cpu_to_le16(vi->max_queue_pairs * 2); > + req->stats[j].types_bitmap[0] = cpu_to_le64(ctx->bitmap_cq); > + ++j; > + } > + > + sg_init_one(&sgs_out, req, sizeof(*req) * j); > + sg_init_one(&sgs_in, reply, res_size); > + > + ok = virtnet_send_command(vi, VIRTIO_NET_CTRL_STATS, > + VIRTIO_NET_CTRL_STATS_GET, > + &sgs_out, &sgs_in); > + kfree(req); > + > + if (!ok) { > + kfree(reply); > + return ok; > + } > + > + num_rx = VIRTNET_RQ_STATS_LEN + ctx->num_rx; > + num_tx = VIRTNET_SQ_STATS_LEN + ctx->num_tx; > + num_cq = ctx->num_tx; > + > + for (p = reply; p - reply < res_size; p += le16_to_cpu(hdr->size)) { > + hdr = p; > + > + qid = le16_to_cpu(hdr->vq_index); > + > + if (qid == vi->max_queue_pairs * 2) { > + offset = 0; > + bitmap = ctx->bitmap_cq; > + } else if (qid % 2) { > + offset = num_cq + num_rx * vi->curr_queue_pairs + num_tx * (qid / 2); > + offset += VIRTNET_SQ_STATS_LEN; > + bitmap = ctx->bitmap_tx; > + } else { > + offset = num_cq + num_rx * (qid / 2) + VIRTNET_RQ_STATS_LEN; > + bitmap = ctx->bitmap_rx; > + } > + > + for (i = 0; i < ARRAY_SIZE(virtio_net_stats_map); ++i) { > + m = &virtio_net_stats_map[i]; > + > + if (m->stat_type & bitmap) > + offset += m->num; > + > + if (hdr->type != m->reply_type) > + continue; > + > + for (j = 0; j < m->num; ++j) { > + v = p + m->desc[j].offset; > + ctx->data[offset + j] = le64_to_cpu(*v); Hi Xuan Zhuo, Sparse complains about the line above because the type of *v is u64, but le64_to_cpu() expects __le64. > + } > + > + break; > + } > + } > + > + kfree(reply); > + return 0; > +} > + > static void virtnet_get_strings(struct net_device *dev, u32 stringset, u8 *data) > { > struct virtnet_info *vi = netdev_priv(dev); ...