From 3288b15a3904b68f305a8e8cca3566a0695938e1 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Wed, 20 Mar 2024 00:26:58 -0700 Subject: [PATCH] [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. --- dev/virtio/block/virtio-block.c | 2 +- dev/virtio/include/dev/virtio.h | 3 +- dev/virtio/net/include/dev/virtio/net.h | 2 +- dev/virtio/net/virtio-net.c | 61 ++++++++++++++++++++++--- dev/virtio/virtio.c | 17 +++++-- dev/virtio/virtio_priv.h | 28 ++++++++---- 6 files changed, 90 insertions(+), 23 deletions(-) diff --git a/dev/virtio/block/virtio-block.c b/dev/virtio/block/virtio-block.c index bb69b51014..1150d841d8 100644 --- a/dev/virtio/block/virtio-block.c +++ b/dev/virtio/block/virtio-block.c @@ -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 */ diff --git a/dev/virtio/include/dev/virtio.h b/dev/virtio/include/dev/virtio.h index 00f8a69630..e231b55b26 100644 --- a/dev/virtio/include/dev/virtio.h +++ b/dev/virtio/include/dev/virtio.h @@ -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 */ diff --git a/dev/virtio/net/include/dev/virtio/net.h b/dev/virtio/net/include/dev/virtio/net.h index 433bb9baa5..f010bbf0de 100644 --- a/dev/virtio/net/include/dev/virtio/net.h +++ b/dev/virtio/net/include/dev/virtio/net.h @@ -11,7 +11,7 @@ #include #include -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 */ diff --git a/dev/virtio/net/virtio-net.c b/dev/virtio/net/virtio-net.c index ba2235936e..8a1ea66098 100644 --- a/dev/virtio/net/virtio-net.c +++ b/dev/virtio/net/virtio-net.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -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 */ diff --git a/dev/virtio/virtio.c b/dev/virtio/virtio.c index 182520a2e6..8d36648c4c 100644 --- a/dev/virtio/virtio.c +++ b/dev/virtio/virtio.c @@ -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) { } diff --git a/dev/virtio/virtio_priv.h b/dev/virtio/virtio_priv.h index 0235329105..82f190ac1c 100644 --- a/dev/virtio/virtio_priv.h +++ b/dev/virtio/virtio_priv.h @@ -10,32 +10,42 @@ #include #include +// 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);