176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* virtio-net.c - etherboot driver for virtio network interface
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * (c) Copyright 2008 Bull S.A.S.
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  Author: Laurent Vivier <Laurent.Vivier@bull.net>
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * some parts from Linux Virtio PCI driver
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  Copyright IBM Corp. 2007
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  Authors: Anthony Liguori  <aliguori@us.ibm.com>
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  some parts from Linux Virtio Ring
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  Copyright Rusty Russell IBM Corporation 2007
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This work is licensed under the terms of the GNU GPL, version 2 or later.
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * See the COPYING file in the top-level directory.
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "etherboot.h"
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "nic.h"
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "gpxe/virtio-ring.h"
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "gpxe/virtio-pci.h"
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "virtio-net.h"
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define BUG() do { \
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   printf("BUG: failure at %s:%d/%s()!\n", \
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          __FILE__, __LINE__, __FUNCTION__); \
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   while(1); \
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} while (0)
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define BUG_ON(condition) do { if (condition) BUG(); } while (0)
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Ethernet header */
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct eth_hdr {
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   unsigned char dst_addr[ETH_ALEN];
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   unsigned char src_addr[ETH_ALEN];
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   unsigned short type;
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct eth_frame {
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   struct eth_hdr hdr;
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   unsigned char data[ETH_FRAME_LEN];
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* TX: virtio header and eth buffer */
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct virtio_net_hdr tx_virtio_hdr;
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct eth_frame tx_eth_frame;
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* RX: virtio headers and buffers */
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define RX_BUF_NB  6
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct virtio_net_hdr rx_hdr[RX_BUF_NB];
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic unsigned char rx_buffer[RX_BUF_NB][ETH_FRAME_LEN];
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* virtio queues and vrings */
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanenum {
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   RX_INDEX = 0,
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   TX_INDEX,
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   QUEUE_NB
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct vring_virtqueue virtqueue[QUEUE_NB];
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * virtnet_disable
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Turn off ethernet interface
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void virtnet_disable(struct nic *nic)
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   int i;
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   for (i = 0; i < QUEUE_NB; i++) {
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           vring_disable_cb(&virtqueue[i]);
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           vp_del_vq(nic->ioaddr, i);
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   }
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   vp_reset(nic->ioaddr);
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * virtnet_poll
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Wait for a frame
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * return true if there is a packet ready to read
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * nic->packet should contain data on return
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * nic->packetlen should contain length of data
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int virtnet_poll(struct nic *nic, int retrieve)
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   unsigned int len;
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   u16 token;
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   struct virtio_net_hdr *hdr;
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   struct vring_list list[2];
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   if (!vring_more_used(&virtqueue[RX_INDEX]))
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           return 0;
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   if (!retrieve)
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           return 1;
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   token = vring_get_buf(&virtqueue[RX_INDEX], &len);
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   BUG_ON(len > sizeof(struct virtio_net_hdr) + ETH_FRAME_LEN);
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   hdr = &rx_hdr[token];   /* FIXME: check flags */
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   len -= sizeof(struct virtio_net_hdr);
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   nic->packetlen = len;
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   memcpy(nic->packet, (char *)rx_buffer[token], nic->packetlen);
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   /* add buffer to desc */
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   list[0].addr = (char*)&rx_hdr[token];
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   list[0].length = sizeof(struct virtio_net_hdr);
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   list[1].addr = (char*)&rx_buffer[token];
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   list[1].length = ETH_FRAME_LEN;
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   vring_add_buf(&virtqueue[RX_INDEX], list, 0, 2, token, 0);
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   vring_kick(nic->ioaddr, &virtqueue[RX_INDEX], 1);
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   return 1;
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * virtnet_transmit
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Transmit a frame
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void virtnet_transmit(struct nic *nic, const char *destaddr,
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        unsigned int type, unsigned int len, const char *data)
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   struct vring_list list[2];
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   /*
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    * from http://www.etherboot.org/wiki/dev/devmanual :
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    *     "You do not need more than one transmit buffer."
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    */
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   /* FIXME: initialize header according to vp_get_features() */
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   tx_virtio_hdr.flags = 0;
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   tx_virtio_hdr.csum_offset = 0;
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   tx_virtio_hdr.csum_start = 0;
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   tx_virtio_hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE;
15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   tx_virtio_hdr.gso_size = 0;
15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   tx_virtio_hdr.hdr_len = 0;
16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   /* add ethernet frame into vring */
16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   BUG_ON(len > sizeof(tx_eth_frame.data));
16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   memcpy(tx_eth_frame.hdr.dst_addr, destaddr, ETH_ALEN);
16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   memcpy(tx_eth_frame.hdr.src_addr, nic->node_addr, ETH_ALEN);
16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   tx_eth_frame.hdr.type = htons(type);
16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   memcpy(tx_eth_frame.data, data, len);
16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   list[0].addr = (char*)&tx_virtio_hdr;
17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   list[0].length = sizeof(struct virtio_net_hdr);
17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   list[1].addr = (char*)&tx_eth_frame;
17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   list[1].length = ETH_FRAME_LEN;
17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   vring_add_buf(&virtqueue[TX_INDEX], list, 2, 0, 0, 0);
17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   vring_kick(nic->ioaddr, &virtqueue[TX_INDEX], 1);
17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   /*
18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    * http://www.etherboot.org/wiki/dev/devmanual
18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    *
18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    *   "You should ensure the packet is fully transmitted
18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    *    before returning from this routine"
18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    */
18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   while (!vring_more_used(&virtqueue[TX_INDEX])) {
18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           mb();
18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           udelay(10);
18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   }
19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   /* free desc */
19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   (void)vring_get_buf(&virtqueue[TX_INDEX], NULL);
19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void virtnet_irq(struct nic *nic __unused, irq_action_t action)
19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   switch ( action ) {
19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   case DISABLE :
20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           vring_disable_cb(&virtqueue[RX_INDEX]);
20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           vring_disable_cb(&virtqueue[TX_INDEX]);
20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           break;
20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   case ENABLE :
20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           vring_enable_cb(&virtqueue[RX_INDEX]);
20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           vring_enable_cb(&virtqueue[TX_INDEX]);
20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           break;
20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   case FORCE :
20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           break;
20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   }
21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void provide_buffers(struct nic *nic)
21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   int i;
21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   struct vring_list list[2];
21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   for (i = 0; i < RX_BUF_NB; i++) {
21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           list[0].addr = (char*)&rx_hdr[i];
21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           list[0].length = sizeof(struct virtio_net_hdr);
22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           list[1].addr = (char*)&rx_buffer[i];
22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           list[1].length = ETH_FRAME_LEN;
22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           vring_add_buf(&virtqueue[RX_INDEX], list, 0, 2, i, i);
22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   }
22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   /* nofify */
22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   vring_kick(nic->ioaddr, &virtqueue[RX_INDEX], i);
22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct nic_operations virtnet_operations = {
23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.connect = dummy_connect,
23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.poll = virtnet_poll,
23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.transmit = virtnet_transmit,
23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.irq = virtnet_irq,
23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * virtnet_probe
23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Look for a virtio network adapter
24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int virtnet_probe(struct nic *nic, struct pci_device *pci)
24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   u32 features;
24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   int i;
24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   /* Mask the bit that says "this is an io addr" */
25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   nic->ioaddr = pci->ioaddr & ~3;
25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   /* Copy IRQ from PCI information */
25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   nic->irqno = pci->irq;
25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   printf("I/O address 0x%08x, IRQ #%d\n", nic->ioaddr, nic->irqno);
25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   adjust_pci_device(pci);
26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   vp_reset(nic->ioaddr);
26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   features = vp_get_features(nic->ioaddr);
26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   if (features & (1 << VIRTIO_NET_F_MAC)) {
26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           vp_get(nic->ioaddr, offsetof(struct virtio_net_config, mac),
26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                  nic->node_addr, ETH_ALEN);
26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           printf("MAC address ");
26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	   for (i = 0; i < ETH_ALEN; i++) {
26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                   printf("%02x%c", nic->node_addr[i],
27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                          (i == ETH_ALEN - 1) ? '\n' : ':');
27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           }
27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   }
27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   /* initialize emit/receive queue */
27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   for (i = 0; i < QUEUE_NB; i++) {
27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           virtqueue[i].free_head = 0;
27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           virtqueue[i].last_used_idx = 0;
27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           memset((char*)&virtqueue[i].queue, 0, sizeof(virtqueue[i].queue));
28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           if (vp_find_vq(nic->ioaddr, i, &virtqueue[i]) == -1)
28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                   printf("Cannot register queue #%d\n", i);
28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   }
28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   /* provide some receive buffers */
28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    provide_buffers(nic);
28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   /* define NIC interface */
28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    nic->nic_op = &virtnet_operations;
29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   /* driver is ready */
29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   vp_set_features(nic->ioaddr, features & (1 << VIRTIO_NET_F_MAC));
29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   vp_set_status(nic->ioaddr, VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   return 1;
29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct pci_device_id virtnet_nics[] = {
30176d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x1af4, 0x1000, "virtio-net",              "Virtio Network Interface", 0),
30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
30476d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_DRIVER ( virtnet_driver, virtnet_nics, PCI_NO_CLASS );
30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
30676d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanDRIVER ( "VIRTIO-NET", nic_driver, pci_driver, virtnet_driver,
30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 virtnet_probe, virtnet_disable );
308