[dev][virtio-net] sync feature bits with virtio v1.3

Add new feature bits for the net device
Since the new feature bits are >= 32, add support for reading higher
than 32bit feature words from the virtio mmio interface.
This commit is contained in:
Travis Geiselbrecht
2024-03-20 00:26:58 -07:00
parent c3cf81a8d8
commit 3288b15a39
6 changed files with 90 additions and 23 deletions

View File

@@ -209,7 +209,7 @@ status_t virtio_block_init(struct virtio_device *dev, uint32_t host_features) {
VIRTIO_BLK_F_TOPOLOGY |
VIRTIO_BLK_F_DISCARD |
VIRTIO_BLK_F_WRITE_ZEROES);
virtio_set_guest_features(dev, bdev->guest_features);
virtio_set_guest_features(dev, 0, bdev->guest_features);
/* TODO: handle a RO feature */

View File

@@ -42,7 +42,8 @@ struct virtio_device {
void virtio_reset_device(struct virtio_device *dev);
void virtio_status_acknowledge_driver(struct virtio_device *dev);
void virtio_set_guest_features(struct virtio_device *dev, uint32_t features);
uint32_t virtio_read_host_feature_word(struct virtio_device *dev, uint32_t word);
void virtio_set_guest_features(struct virtio_device *dev, uint32_t word, uint32_t features);
void virtio_status_driver_ok(struct virtio_device *dev);
/* api used by devices to interact with the virtio bus */

View File

@@ -11,7 +11,7 @@
#include <sys/types.h>
#include <dev/virtio.h>
status_t virtio_net_init(struct virtio_device *dev, uint32_t host_features) __NONNULL();
status_t virtio_net_init(struct virtio_device *dev) __NONNULL();
status_t virtio_net_start(void);
/* return the count of virtio interfaces found */

View File

@@ -8,6 +8,7 @@
#include <dev/virtio/net.h>
#include <stdlib.h>
#include <inttypes.h>
#include <lk/debug.h>
#include <assert.h>
#include <lk/trace.h>
@@ -27,25 +28,47 @@ struct virtio_net_config {
uint8_t mac[6];
uint16_t status;
uint16_t max_virtqueue_pairs;
uint16_t mtu;
uint32_t speed;
uint8_t duplex;
uint8_t rss_max_key_size;
uint16_t rss_max_indirection_table_length;
uint32_t supported_hash_types;
uint32_t supported_tunnel_types;
};
STATIC_ASSERT(sizeof(struct virtio_net_config) == 10);
STATIC_ASSERT(sizeof(struct virtio_net_config) == 28);
struct virtio_net_hdr {
#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1
#define VIRTIO_NET_HDR_F_DATA_VALID 2
#define VIRTIO_NET_HDR_F_RSC_INFO 4
uint8_t flags;
#define VIRTIO_NET_HDR_GSO_NONE 0
#define VIRTIO_NET_HDR_GSO_TCPV4 1
#define VIRTIO_NET_HDR_GSO_UDP 3
#define VIRTIO_NET_HDR_GSO_TCPV6 4
#define VIRTIO_NET_HDR_GSO_UDP_L4 5
#define VIRTIO_NET_HDR_GSO_ECN 0x80
uint8_t gso_type;
uint16_t hdr_len;
uint16_t gso_size;
uint16_t csum_start;
uint16_t csum_offset;
uint16_t num_buffers; // unused in tx
// Only if VIRTIO_NET_HASH_REPORT negotiated
//uint32_t hash_value;
//uint16_t hash_report;
//uint16_t padding_reserved;
};
STATIC_ASSERT(sizeof(struct virtio_net_hdr) == 12);
#define VIRTIO_NET_F_CSUM (1<<0)
#define VIRTIO_NET_F_GUEST_CSUM (1<<1)
#define VIRTIO_NET_F_CTRL_GUEST_OFFLOADS (1<<2)
#define VIRTIO_NET_F_MTU (1<<3)
#define VIRTIO_NET_F_MAC (1<<5)
#define VIRTIO_NET_F_GSO (1<<6)
#define VIRTIO_NET_F_GSO (1<<6) // removed in v1.3
#define VIRTIO_NET_F_GUEST_TSO4 (1<<7)
#define VIRTIO_NET_F_GUEST_TSO6 (1<<8)
#define VIRTIO_NET_F_GUEST_ECN (1<<9)
@@ -62,6 +85,18 @@ STATIC_ASSERT(sizeof(struct virtio_net_hdr) == 12);
#define VIRTIO_NET_F_GUEST_ANNOUNCE (1<<21)
#define VIRTIO_NET_F_MQ (1<<22)
#define VIRTIO_NET_F_CTRL_MAC_ADDR (1<<23)
#define VIRTIO_NET_F_HASH_TUNNEL (1ULL<<51)
#define VIRTIO_NET_F_VQ_NOTF_COAL (1ULL<<52)
#define VIRTIO_NET_F_NOTF_COAL (1ULL<<53)
#define VIRTIO_NET_F_GUEST_USO4 (1ULL<<54)
#define VIRTIO_NET_F_GUEST_USO6 (1ULL<<55)
#define VIRTIO_NET_F_HOST_USO (1ULL<<56)
#define VIRTIO_NET_F_HASH_REPORT (1ULL<<57)
#define VIRTIO_NET_F_GUEST_HDRLEN (1ULL<<59)
#define VIRTIO_NET_F_RSS (1ULL<<60)
#define VIRTIO_NET_F_RSC_EXT (1ULL<<61)
#define VIRTIO_NET_F_STANDBY (1ULL<<62)
#define VIRTIO_NET_F_SPEED_DUPLEX (1ULL<<63)
#define VIRTIO_NET_S_LINK_UP (1<<0)
#define VIRTIO_NET_S_ANNOUNCE (1<<1)
@@ -98,11 +133,12 @@ static status_t virtio_net_queue_rx(struct virtio_net_dev *ndev, pktbuf_t *p);
// XXX remove need for this
static struct virtio_net_dev *the_ndev;
static void dump_feature_bits(uint32_t feature) {
printf("virtio-net host features (0x%x):", feature);
static void dump_feature_bits(uint64_t feature) {
printf("virtio-net host features (%#" PRIx64 "):", feature);
if (feature & VIRTIO_NET_F_CSUM) printf(" CSUM");
if (feature & VIRTIO_NET_F_GUEST_CSUM) printf(" GUEST_CSUM");
if (feature & VIRTIO_NET_F_CTRL_GUEST_OFFLOADS) printf(" CTRL_GUEST_OFFLOADS");
if (feature & VIRTIO_NET_F_MTU) printf(" MTU");
if (feature & VIRTIO_NET_F_MAC) printf(" MAC");
if (feature & VIRTIO_NET_F_GSO) printf(" GSO");
if (feature & VIRTIO_NET_F_GUEST_TSO4) printf(" GUEST_TSO4");
@@ -121,11 +157,23 @@ static void dump_feature_bits(uint32_t feature) {
if (feature & VIRTIO_NET_F_GUEST_ANNOUNCE) printf(" GUEST_ANNOUNCE");
if (feature & VIRTIO_NET_F_MQ) printf(" MQ");
if (feature & VIRTIO_NET_F_CTRL_MAC_ADDR) printf(" CTRL_MAC_ADDR");
if (feature & VIRTIO_NET_F_HASH_TUNNEL) printf(" HASH_TUNNEL");
if (feature & VIRTIO_NET_F_VQ_NOTF_COAL) printf(" VQ_NOTF_COAL");
if (feature & VIRTIO_NET_F_NOTF_COAL) printf(" NOTF_COAL");
if (feature & VIRTIO_NET_F_GUEST_USO4) printf(" GUEST_USO4");
if (feature & VIRTIO_NET_F_GUEST_USO6) printf(" GUEST_USO6");
if (feature & VIRTIO_NET_F_HOST_USO) printf(" HOST_USO");
if (feature & VIRTIO_NET_F_HASH_REPORT) printf(" HASH_REPORT");
if (feature & VIRTIO_NET_F_GUEST_HDRLEN) printf(" GUEST_HDRLEN");
if (feature & VIRTIO_NET_F_RSS) printf(" RSS");
if (feature & VIRTIO_NET_F_RSC_EXT) printf(" RSC_EXT");
if (feature & VIRTIO_NET_F_STANDBY) printf(" STANDBY");
if (feature & VIRTIO_NET_F_SPEED_DUPLEX) printf(" SPEED_DUPLEX");
printf("\n");
}
status_t virtio_net_init(struct virtio_device *dev, uint32_t host_features) {
LTRACEF("dev %p, host_features 0x%x\n", dev, host_features);
status_t virtio_net_init(struct virtio_device *dev) {
LTRACEF("dev %p\n", dev);
/* allocate a new net device */
struct virtio_net_dev *ndev = calloc(1, sizeof(struct virtio_net_dev));
@@ -146,6 +194,7 @@ status_t virtio_net_init(struct virtio_device *dev, uint32_t host_features) {
virtio_status_acknowledge_driver(dev);
// XXX check features bits and ack/nak them
uint64_t host_features = virtio_read_host_feature_word(dev, 0) | (uint64_t)virtio_read_host_feature_word(dev, 1) << 32;
dump_feature_bits(host_features);
/* set our irq handler */

View File

@@ -143,6 +143,8 @@ int virtio_mmio_detect(void *ptr, uint count, const uint irqs[], size_t stride)
continue;
}
// TODO: handle version 2
#if LOCAL_TRACE
if (mmio->device_id != 0) {
dump_mmio_config(mmio);
@@ -156,7 +158,7 @@ int virtio_mmio_detect(void *ptr, uint count, const uint irqs[], size_t stride)
dev->mmio_config = mmio;
dev->config_ptr = (void *)mmio->config;
status_t err = virtio_block_init(dev, mmio->host_features);
status_t err = virtio_block_init(dev, virtio_read_host_feature_word(dev, 0));
if (err >= 0) {
// good device
dev->valid = true;
@@ -173,7 +175,7 @@ int virtio_mmio_detect(void *ptr, uint count, const uint irqs[], size_t stride)
dev->mmio_config = mmio;
dev->config_ptr = (void *)mmio->config;
status_t err = virtio_net_init(dev, mmio->host_features);
status_t err = virtio_net_init(dev);
if (err >= 0) {
// good device
dev->valid = true;
@@ -190,7 +192,7 @@ int virtio_mmio_detect(void *ptr, uint count, const uint irqs[], size_t stride)
dev->mmio_config = mmio;
dev->config_ptr = (void *)mmio->config;
status_t err = virtio_gpu_init(dev, mmio->host_features);
status_t err = virtio_gpu_init(dev, virtio_read_host_feature_word(dev, 0));
if (err >= 0) {
// good device
dev->valid = true;
@@ -367,11 +369,16 @@ void virtio_status_driver_ok(struct virtio_device *dev) {
dev->mmio_config->status |= VIRTIO_STATUS_DRIVER_OK;
}
void virtio_set_guest_features(struct virtio_device *dev, uint32_t features) {
dev->mmio_config->guest_features_sel = 0;
void virtio_set_guest_features(struct virtio_device *dev, uint32_t word, uint32_t features) {
dev->mmio_config->guest_features_sel = word;
dev->mmio_config->guest_features = features;
}
uint32_t virtio_read_host_feature_word(struct virtio_device *dev, uint32_t word) {
dev->mmio_config->host_features_sel = word;
return dev->mmio_config->host_features;
}
static void virtio_init(uint level) {
}

View File

@@ -10,32 +10,42 @@
#include <lk/compiler.h>
#include <stdint.h>
// V1 config
struct virtio_mmio_config {
/* 0x00 */ uint32_t magic;
/* 0x00 */
uint32_t magic;
uint32_t version;
uint32_t device_id;
uint32_t vendor_id;
/* 0x10 */ uint32_t host_features;
/* 0x10 */
uint32_t host_features;
uint32_t host_features_sel;
uint32_t __reserved0[2];
/* 0x20 */ uint32_t guest_features;
/* 0x20 */
uint32_t guest_features;
uint32_t guest_features_sel;
uint32_t guest_page_size;
uint32_t __reserved1[1];
/* 0x30 */ uint32_t queue_sel;
/* 0x30 */
uint32_t queue_sel;
uint32_t queue_num_max;
uint32_t queue_num;
uint32_t queue_align;
/* 0x40 */ uint32_t queue_pfn;
/* 0x40 */
uint32_t queue_pfn;
uint32_t __reserved2[3];
/* 0x50 */ uint32_t queue_notify;
/* 0x50 */
uint32_t queue_notify;
uint32_t __reserved3[3];
/* 0x60 */ uint32_t interrupt_status;
/* 0x60 */
uint32_t interrupt_status;
uint32_t interrupt_ack;
uint32_t __reserved4[2];
/* 0x70 */ uint32_t status;
/* 0x70 */
uint32_t status;
uint8_t __reserved5[0x8c];
/* 0x100 */ uint32_t config[0];
/* 0x100 */
uint32_t config[0];
};
STATIC_ASSERT(sizeof(struct virtio_mmio_config) == 0x100);