|
|
1.1 ! root 1: /* ! 2: * (c) Copyright 2010 Stefan Hajnoczi <[email protected]> ! 3: * ! 4: * based on the Etherboot virtio-net driver ! 5: * ! 6: * (c) Copyright 2008 Bull S.A.S. ! 7: * ! 8: * Author: Laurent Vivier <[email protected]> ! 9: * ! 10: * some parts from Linux Virtio PCI driver ! 11: * ! 12: * Copyright IBM Corp. 2007 ! 13: * Authors: Anthony Liguori <[email protected]> ! 14: * ! 15: * some parts from Linux Virtio Ring ! 16: * ! 17: * Copyright Rusty Russell IBM Corporation 2007 ! 18: * ! 19: * This work is licensed under the terms of the GNU GPL, version 2 or later. ! 20: * See the COPYING file in the top-level directory. ! 21: */ ! 22: ! 23: FILE_LICENCE ( GPL2_OR_LATER ); ! 24: ! 25: #include <errno.h> ! 26: #include <stdlib.h> ! 27: #include <ipxe/list.h> ! 28: #include <ipxe/iobuf.h> ! 29: #include <ipxe/netdevice.h> ! 30: #include <ipxe/pci.h> ! 31: #include <ipxe/if_ether.h> ! 32: #include <ipxe/ethernet.h> ! 33: #include <ipxe/virtio-ring.h> ! 34: #include <ipxe/virtio-pci.h> ! 35: #include "virtio-net.h" ! 36: ! 37: /* ! 38: * Virtio network device driver ! 39: * ! 40: * Specification: ! 41: * http://ozlabs.org/~rusty/virtio-spec/ ! 42: * ! 43: * The virtio network device is supported by Linux virtualization software ! 44: * including QEMU/KVM and lguest. This driver supports the virtio over PCI ! 45: * transport; virtual machines have one virtio-net PCI adapter per NIC. ! 46: * ! 47: * Virtio-net is different from hardware NICs because virtio devices ! 48: * communicate with the hypervisor via virtqueues, not traditional descriptor ! 49: * rings. Virtqueues are unordered queues, they support add_buf() and ! 50: * get_buf() operations. To transmit a packet, the driver has to add the ! 51: * packet buffer onto the virtqueue. To receive a packet, the driver must ! 52: * first add an empty buffer to the virtqueue and then get the filled packet ! 53: * buffer on completion. ! 54: * ! 55: * Virtqueues are an abstraction that is commonly implemented using the vring ! 56: * descriptor ring layout. The vring is the actual shared memory structure ! 57: * that allows the virtual machine to communicate buffers with the hypervisor. ! 58: * Because the vring layout is optimized for flexibility and performance rather ! 59: * than space, it is heavy-weight and allocated like traditional descriptor ! 60: * rings in the open() function of the driver and not in probe(). ! 61: * ! 62: * There is no true interrupt enable/disable. Virtqueues have callback ! 63: * enable/disable flags but these are only hints. The hypervisor may still ! 64: * raise an interrupt. Nevertheless, this driver disables callbacks in the ! 65: * hopes of avoiding interrupts. ! 66: */ ! 67: ! 68: /* Driver types are declared here so virtio-net.h can be easily synced with its ! 69: * Linux source. ! 70: */ ! 71: ! 72: /* Virtqueue indicies */ ! 73: enum { ! 74: RX_INDEX = 0, ! 75: TX_INDEX, ! 76: QUEUE_NB ! 77: }; ! 78: ! 79: enum { ! 80: /** Max number of pending rx packets */ ! 81: NUM_RX_BUF = 8, ! 82: ! 83: /** Max Ethernet frame length, including FCS and VLAN tag */ ! 84: RX_BUF_SIZE = 1522, ! 85: }; ! 86: ! 87: struct virtnet_nic { ! 88: /** Base pio register address */ ! 89: unsigned long ioaddr; ! 90: ! 91: /** RX/TX virtqueues */ ! 92: struct vring_virtqueue *virtqueue; ! 93: ! 94: /** RX packets handed to the NIC waiting to be filled in */ ! 95: struct list_head rx_iobufs; ! 96: ! 97: /** Pending rx packet count */ ! 98: unsigned int rx_num_iobufs; ! 99: ! 100: /** Virtio net packet header, we only need one */ ! 101: struct virtio_net_hdr empty_header; ! 102: }; ! 103: ! 104: /** Add an iobuf to a virtqueue ! 105: * ! 106: * @v netdev Network device ! 107: * @v vq_idx Virtqueue index (RX_INDEX or TX_INDEX) ! 108: * @v iobuf I/O buffer ! 109: * ! 110: * The virtqueue is kicked after the iobuf has been added. ! 111: */ ! 112: static void virtnet_enqueue_iob ( struct net_device *netdev, ! 113: int vq_idx, struct io_buffer *iobuf ) { ! 114: struct virtnet_nic *virtnet = netdev->priv; ! 115: struct vring_virtqueue *vq = &virtnet->virtqueue[vq_idx]; ! 116: unsigned int out = ( vq_idx == TX_INDEX ) ? 2 : 0; ! 117: unsigned int in = ( vq_idx == TX_INDEX ) ? 0 : 2; ! 118: struct vring_list list[] = { ! 119: { ! 120: /* Share a single zeroed virtio net header between all ! 121: * rx and tx packets. This works because this driver ! 122: * does not use any advanced features so none of the ! 123: * header fields get used. ! 124: */ ! 125: .addr = ( char* ) &virtnet->empty_header, ! 126: .length = sizeof ( virtnet->empty_header ), ! 127: }, ! 128: { ! 129: .addr = ( char* ) iobuf->data, ! 130: .length = iob_len ( iobuf ), ! 131: }, ! 132: }; ! 133: ! 134: DBGC ( virtnet, "VIRTIO-NET %p enqueuing iobuf %p on vq %d\n", ! 135: virtnet, iobuf, vq_idx ); ! 136: ! 137: vring_add_buf ( vq, list, out, in, iobuf, 0 ); ! 138: vring_kick ( virtnet->ioaddr, vq, 1 ); ! 139: } ! 140: ! 141: /** Try to keep rx virtqueue filled with iobufs ! 142: * ! 143: * @v netdev Network device ! 144: */ ! 145: static void virtnet_refill_rx_virtqueue ( struct net_device *netdev ) { ! 146: struct virtnet_nic *virtnet = netdev->priv; ! 147: ! 148: while ( virtnet->rx_num_iobufs < NUM_RX_BUF ) { ! 149: struct io_buffer *iobuf; ! 150: ! 151: /* Try to allocate a buffer, stop for now if out of memory */ ! 152: iobuf = alloc_iob ( RX_BUF_SIZE ); ! 153: if ( ! iobuf ) ! 154: break; ! 155: ! 156: /* Keep track of iobuf so close() can free it */ ! 157: list_add ( &iobuf->list, &virtnet->rx_iobufs ); ! 158: ! 159: /* Mark packet length until we know the actual size */ ! 160: iob_put ( iobuf, RX_BUF_SIZE ); ! 161: ! 162: virtnet_enqueue_iob ( netdev, RX_INDEX, iobuf ); ! 163: virtnet->rx_num_iobufs++; ! 164: } ! 165: } ! 166: ! 167: /** Open network device ! 168: * ! 169: * @v netdev Network device ! 170: * @ret rc Return status code ! 171: */ ! 172: static int virtnet_open ( struct net_device *netdev ) { ! 173: struct virtnet_nic *virtnet = netdev->priv; ! 174: unsigned long ioaddr = virtnet->ioaddr; ! 175: u32 features; ! 176: int i; ! 177: ! 178: /* Reset for sanity */ ! 179: vp_reset ( ioaddr ); ! 180: ! 181: /* Allocate virtqueues */ ! 182: virtnet->virtqueue = zalloc ( QUEUE_NB * ! 183: sizeof ( *virtnet->virtqueue ) ); ! 184: if ( ! virtnet->virtqueue ) ! 185: return -ENOMEM; ! 186: ! 187: /* Initialize rx/tx virtqueues */ ! 188: for ( i = 0; i < QUEUE_NB; i++ ) { ! 189: if ( vp_find_vq ( ioaddr, i, &virtnet->virtqueue[i] ) == -1 ) { ! 190: DBGC ( virtnet, "VIRTIO-NET %p cannot register queue %d\n", ! 191: virtnet, i ); ! 192: free ( virtnet->virtqueue ); ! 193: virtnet->virtqueue = NULL; ! 194: return -ENOENT; ! 195: } ! 196: } ! 197: ! 198: /* Initialize rx packets */ ! 199: INIT_LIST_HEAD ( &virtnet->rx_iobufs ); ! 200: virtnet->rx_num_iobufs = 0; ! 201: virtnet_refill_rx_virtqueue ( netdev ); ! 202: ! 203: /* Disable interrupts before starting */ ! 204: netdev_irq ( netdev, 0 ); ! 205: ! 206: /* Driver is ready */ ! 207: features = vp_get_features ( ioaddr ); ! 208: vp_set_features ( ioaddr, features & ( 1 << VIRTIO_NET_F_MAC ) ); ! 209: vp_set_status ( ioaddr, VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK ); ! 210: return 0; ! 211: } ! 212: ! 213: /** Close network device ! 214: * ! 215: * @v netdev Network device ! 216: */ ! 217: static void virtnet_close ( struct net_device *netdev ) { ! 218: struct virtnet_nic *virtnet = netdev->priv; ! 219: struct io_buffer *iobuf; ! 220: struct io_buffer *next_iobuf; ! 221: ! 222: vp_reset ( virtnet->ioaddr ); ! 223: ! 224: /* Virtqueues can be freed now that NIC is reset */ ! 225: free ( virtnet->virtqueue ); ! 226: virtnet->virtqueue = NULL; ! 227: ! 228: /* Free rx iobufs */ ! 229: list_for_each_entry_safe ( iobuf, next_iobuf, &virtnet->rx_iobufs, list ) { ! 230: free_iob ( iobuf ); ! 231: } ! 232: INIT_LIST_HEAD ( &virtnet->rx_iobufs ); ! 233: virtnet->rx_num_iobufs = 0; ! 234: } ! 235: ! 236: /** Transmit packet ! 237: * ! 238: * @v netdev Network device ! 239: * @v iobuf I/O buffer ! 240: * @ret rc Return status code ! 241: */ ! 242: static int virtnet_transmit ( struct net_device *netdev, ! 243: struct io_buffer *iobuf ) { ! 244: virtnet_enqueue_iob ( netdev, TX_INDEX, iobuf ); ! 245: return 0; ! 246: } ! 247: ! 248: /** Complete packet transmission ! 249: * ! 250: * @v netdev Network device ! 251: */ ! 252: static void virtnet_process_tx_packets ( struct net_device *netdev ) { ! 253: struct virtnet_nic *virtnet = netdev->priv; ! 254: struct vring_virtqueue *tx_vq = &virtnet->virtqueue[TX_INDEX]; ! 255: ! 256: while ( vring_more_used ( tx_vq ) ) { ! 257: struct io_buffer *iobuf = vring_get_buf ( tx_vq, NULL ); ! 258: ! 259: DBGC ( virtnet, "VIRTIO-NET %p tx complete iobuf %p\n", ! 260: virtnet, iobuf ); ! 261: ! 262: netdev_tx_complete ( netdev, iobuf ); ! 263: } ! 264: } ! 265: ! 266: /** Complete packet reception ! 267: * ! 268: * @v netdev Network device ! 269: */ ! 270: static void virtnet_process_rx_packets ( struct net_device *netdev ) { ! 271: struct virtnet_nic *virtnet = netdev->priv; ! 272: struct vring_virtqueue *rx_vq = &virtnet->virtqueue[RX_INDEX]; ! 273: ! 274: while ( vring_more_used ( rx_vq ) ) { ! 275: unsigned int len; ! 276: struct io_buffer *iobuf = vring_get_buf ( rx_vq, &len ); ! 277: ! 278: /* Release ownership of iobuf */ ! 279: list_del ( &iobuf->list ); ! 280: virtnet->rx_num_iobufs--; ! 281: ! 282: /* Update iobuf length */ ! 283: iob_unput ( iobuf, RX_BUF_SIZE ); ! 284: iob_put ( iobuf, len - sizeof ( struct virtio_net_hdr ) ); ! 285: ! 286: DBGC ( virtnet, "VIRTIO-NET %p rx complete iobuf %p len %zd\n", ! 287: virtnet, iobuf, iob_len ( iobuf ) ); ! 288: ! 289: /* Pass completed packet to the network stack */ ! 290: netdev_rx ( netdev, iobuf ); ! 291: } ! 292: ! 293: virtnet_refill_rx_virtqueue ( netdev ); ! 294: } ! 295: ! 296: /** Poll for completed and received packets ! 297: * ! 298: * @v netdev Network device ! 299: */ ! 300: static void virtnet_poll ( struct net_device *netdev ) { ! 301: struct virtnet_nic *virtnet = netdev->priv; ! 302: ! 303: /* Acknowledge interrupt. This is necessary for UNDI operation and ! 304: * interrupts that are raised despite VRING_AVAIL_F_NO_INTERRUPT being ! 305: * set (that flag is just a hint and the hypervisor not not have to ! 306: * honor it). ! 307: */ ! 308: vp_get_isr ( virtnet->ioaddr ); ! 309: ! 310: virtnet_process_tx_packets ( netdev ); ! 311: virtnet_process_rx_packets ( netdev ); ! 312: } ! 313: ! 314: /** Enable or disable interrupts ! 315: * ! 316: * @v netdev Network device ! 317: * @v enable Interrupts should be enabled ! 318: */ ! 319: static void virtnet_irq ( struct net_device *netdev, int enable ) { ! 320: struct virtnet_nic *virtnet = netdev->priv; ! 321: int i; ! 322: ! 323: for ( i = 0; i < QUEUE_NB; i++ ) { ! 324: if ( enable ) ! 325: vring_enable_cb ( &virtnet->virtqueue[i] ); ! 326: else ! 327: vring_disable_cb ( &virtnet->virtqueue[i] ); ! 328: } ! 329: } ! 330: ! 331: /** virtio-net device operations */ ! 332: static struct net_device_operations virtnet_operations = { ! 333: .open = virtnet_open, ! 334: .close = virtnet_close, ! 335: .transmit = virtnet_transmit, ! 336: .poll = virtnet_poll, ! 337: .irq = virtnet_irq, ! 338: }; ! 339: ! 340: /** ! 341: * Probe PCI device ! 342: * ! 343: * @v pci PCI device ! 344: * @v id PCI ID ! 345: * @ret rc Return status code ! 346: */ ! 347: static int virtnet_probe ( struct pci_device *pci ) { ! 348: unsigned long ioaddr = pci->ioaddr; ! 349: struct net_device *netdev; ! 350: struct virtnet_nic *virtnet; ! 351: u32 features; ! 352: int rc; ! 353: ! 354: /* Allocate and hook up net device */ ! 355: netdev = alloc_etherdev ( sizeof ( *virtnet ) ); ! 356: if ( ! netdev ) ! 357: return -ENOMEM; ! 358: netdev_init ( netdev, &virtnet_operations ); ! 359: virtnet = netdev->priv; ! 360: virtnet->ioaddr = ioaddr; ! 361: pci_set_drvdata ( pci, netdev ); ! 362: netdev->dev = &pci->dev; ! 363: ! 364: DBGC ( virtnet, "VIRTIO-NET %p busaddr=%s ioaddr=%#lx irq=%d\n", ! 365: virtnet, pci->dev.name, ioaddr, pci->irq ); ! 366: ! 367: /* Enable PCI bus master and reset NIC */ ! 368: adjust_pci_device ( pci ); ! 369: vp_reset ( ioaddr ); ! 370: ! 371: /* Load MAC address */ ! 372: features = vp_get_features ( ioaddr ); ! 373: if ( features & ( 1 << VIRTIO_NET_F_MAC ) ) { ! 374: vp_get ( ioaddr, offsetof ( struct virtio_net_config, mac ), ! 375: netdev->hw_addr, ETH_ALEN ); ! 376: DBGC ( virtnet, "VIRTIO-NET %p mac=%s\n", virtnet, ! 377: eth_ntoa ( netdev->hw_addr ) ); ! 378: } ! 379: ! 380: /* Register network device */ ! 381: if ( ( rc = register_netdev ( netdev ) ) != 0 ) ! 382: goto err_register_netdev; ! 383: ! 384: /* Mark link as up, control virtqueue is not used */ ! 385: netdev_link_up ( netdev ); ! 386: ! 387: return 0; ! 388: ! 389: unregister_netdev ( netdev ); ! 390: err_register_netdev: ! 391: vp_reset ( ioaddr ); ! 392: netdev_nullify ( netdev ); ! 393: netdev_put ( netdev ); ! 394: return rc; ! 395: } ! 396: ! 397: /** ! 398: * Remove device ! 399: * ! 400: * @v pci PCI device ! 401: */ ! 402: static void virtnet_remove ( struct pci_device *pci ) { ! 403: struct net_device *netdev = pci_get_drvdata ( pci ); ! 404: ! 405: unregister_netdev ( netdev ); ! 406: netdev_nullify ( netdev ); ! 407: netdev_put ( netdev ); ! 408: } ! 409: ! 410: static struct pci_device_id virtnet_nics[] = { ! 411: PCI_ROM(0x1af4, 0x1000, "virtio-net", "Virtio Network Interface", 0), ! 412: }; ! 413: ! 414: struct pci_driver virtnet_driver __pci_driver = { ! 415: .ids = virtnet_nics, ! 416: .id_count = ( sizeof ( virtnet_nics ) / sizeof ( virtnet_nics[0] ) ), ! 417: .probe = virtnet_probe, ! 418: .remove = virtnet_remove, ! 419: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.