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