diff --git a/src/drivers/net/virtio-net.c b/src/drivers/net/virtio-net.c index 40367b89..4151532e 100644 --- a/src/drivers/net/virtio-net.c +++ b/src/drivers/net/virtio-net.c @@ -77,13 +77,8 @@ enum { QUEUE_NB }; -enum { - /** Max number of pending rx packets */ - NUM_RX_BUF = 8, - - /** Max Ethernet frame length, including FCS and VLAN tag */ - RX_BUF_SIZE = 1522, -}; +/** Max number of pending rx packets */ +#define NUM_RX_BUF 8 struct virtnet_nic { /** Base pio register address */ @@ -160,12 +155,13 @@ static void virtnet_enqueue_iob ( struct net_device *netdev, */ static void virtnet_refill_rx_virtqueue ( struct net_device *netdev ) { struct virtnet_nic *virtnet = netdev->priv; + size_t len = ( netdev->max_pkt_len + 4 /* VLAN */ ); while ( virtnet->rx_num_iobufs < NUM_RX_BUF ) { struct io_buffer *iobuf; /* Try to allocate a buffer, stop for now if out of memory */ - iobuf = alloc_iob ( RX_BUF_SIZE ); + iobuf = alloc_iob ( len ); if ( ! iobuf ) break; @@ -173,7 +169,7 @@ static void virtnet_refill_rx_virtqueue ( struct net_device *netdev ) { list_add ( &iobuf->list, &virtnet->rx_iobufs ); /* Mark packet length until we know the actual size */ - iob_put ( iobuf, RX_BUF_SIZE ); + iob_put ( iobuf, len ); virtnet_enqueue_iob ( netdev, RX_INDEX, iobuf ); virtnet->rx_num_iobufs++; @@ -237,7 +233,8 @@ static int virtnet_open_legacy ( struct net_device *netdev ) { /* Driver is ready */ features = vp_get_features ( ioaddr ); - vp_set_features ( ioaddr, features & ( 1 << VIRTIO_NET_F_MAC ) ); + vp_set_features ( ioaddr, features & ( ( 1 << VIRTIO_NET_F_MAC ) | + ( 1 << VIRTIO_NET_F_MTU ) ) ); vp_set_status ( ioaddr, VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK ); return 0; } @@ -260,6 +257,7 @@ static int virtnet_open_modern ( struct net_device *netdev ) { } vpm_set_features ( &virtnet->vdev, features & ( ( 1ULL << VIRTIO_NET_F_MAC ) | + ( 1ULL << VIRTIO_NET_F_MTU ) | ( 1ULL << VIRTIO_F_VERSION_1 ) | ( 1ULL << VIRTIO_F_ANY_LAYOUT ) ) ); vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_FEATURES_OK ); @@ -389,7 +387,7 @@ static void virtnet_process_rx_packets ( struct net_device *netdev ) { virtnet->rx_num_iobufs--; /* Update iobuf length */ - iob_unput ( iobuf, RX_BUF_SIZE ); + iob_unput ( iobuf, iob_len ( iobuf ) ); iob_put ( iobuf, len - sizeof ( struct virtio_net_hdr ) ); DBGC2 ( virtnet, "VIRTIO-NET %p rx complete iobuf %p len %zd\n", @@ -461,6 +459,7 @@ static int virtnet_probe_legacy ( struct pci_device *pci ) { struct net_device *netdev; struct virtnet_nic *virtnet; u32 features; + u16 mtu; int rc; /* Allocate and hook up net device */ @@ -480,7 +479,7 @@ static int virtnet_probe_legacy ( struct pci_device *pci ) { adjust_pci_device ( pci ); vp_reset ( ioaddr ); - /* Load MAC address */ + /* Load MAC address and MTU */ features = vp_get_features ( ioaddr ); if ( features & ( 1 << VIRTIO_NET_F_MAC ) ) { vp_get ( ioaddr, offsetof ( struct virtio_net_config, mac ), @@ -488,6 +487,12 @@ static int virtnet_probe_legacy ( struct pci_device *pci ) { DBGC ( virtnet, "VIRTIO-NET %p mac=%s\n", virtnet, eth_ntoa ( netdev->hw_addr ) ); } + if ( features & ( 1ULL << VIRTIO_NET_F_MTU ) ) { + vp_get ( ioaddr, offsetof ( struct virtio_net_config, mtu ), + &mtu, sizeof ( mtu ) ); + DBGC ( virtnet, "VIRTIO-NET %p mtu=%d\n", virtnet, mtu ); + netdev->max_pkt_len = ( mtu + ETH_HLEN ); + } /* Register network device */ if ( ( rc = register_netdev ( netdev ) ) != 0 ) @@ -517,6 +522,7 @@ static int virtnet_probe_modern ( struct pci_device *pci, int *found_dev ) { struct net_device *netdev; struct virtnet_nic *virtnet; u64 features; + u16 mtu; int rc, common, isr, notify, config, device; common = virtio_pci_find_capability ( pci, VIRTIO_PCI_CAP_COMMON_CFG ); @@ -583,7 +589,7 @@ static int virtnet_probe_modern ( struct pci_device *pci, int *found_dev ) { vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_ACKNOWLEDGE ); vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_DRIVER ); - /* Load MAC address */ + /* Load MAC address and MTU */ if ( device ) { features = vpm_get_features ( &virtnet->vdev ); if ( features & ( 1ULL << VIRTIO_NET_F_MAC ) ) { @@ -593,6 +599,14 @@ static int virtnet_probe_modern ( struct pci_device *pci, int *found_dev ) { DBGC ( virtnet, "VIRTIO-NET %p mac=%s\n", virtnet, eth_ntoa ( netdev->hw_addr ) ); } + if ( features & ( 1ULL << VIRTIO_NET_F_MTU ) ) { + vpm_get ( &virtnet->vdev, + offsetof ( struct virtio_net_config, mtu ), + &mtu, sizeof ( mtu ) ); + DBGC ( virtnet, "VIRTIO-NET %p mtu=%d\n", virtnet, + mtu ); + netdev->max_pkt_len = ( mtu + ETH_HLEN ); + } } /* We need a valid MAC address */ diff --git a/src/drivers/net/virtio-net.h b/src/drivers/net/virtio-net.h index c2b4a17c..ff58d3ef 100644 --- a/src/drivers/net/virtio-net.h +++ b/src/drivers/net/virtio-net.h @@ -4,6 +4,7 @@ /* The feature bitmap for virtio net */ #define VIRTIO_NET_F_CSUM 0 /* Host handles pkts w/ partial csum */ #define VIRTIO_NET_F_GUEST_CSUM 1 /* Guest handles pkts w/ partial csum */ +#define VIRTIO_NET_F_MTU 3 /* Initial MTU advice */ #define VIRTIO_NET_F_MAC 5 /* Host has given MAC address. */ #define VIRTIO_NET_F_GSO 6 /* Host handles pkts w/ any GSO type */ #define VIRTIO_NET_F_GUEST_TSO4 7 /* Guest can handle TSOv4 in. */ @@ -25,6 +26,15 @@ struct virtio_net_config { /* The config defining mac address (if VIRTIO_NET_F_MAC) */ u8 mac[6]; + /* See VIRTIO_NET_F_STATUS and VIRTIO_NET_S_* above */ + u16 status; + /* Maximum number of each of transmit and receive queues; + * see VIRTIO_NET_F_MQ and VIRTIO_NET_CTRL_MQ. + * Legal values are between 1 and 0x8000 + */ + u16 max_virtqueue_pairs; + /* Default maximum transmit unit advice */ + u16 mtu; } __attribute__((packed)); /* This is the first element of the scatter-gather list. If you don't