Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "io.h"
- #include "ureg.h"
- #include "../port/error.h"
- #include "../port/netif.h"
- #include "etherif.h"
- #include "ethermii.h"
- //
- //
- // Virtio
- //
- //
- typedef struct Vioreqhdr Vioreqhdr;
- typedef struct Vringhdr Vringhdr;
- typedef struct Vdesc Vdesc;
- typedef struct Vused Vused;
- typedef struct Vqueue Vqueue;
- typedef struct Vdev Vdev;
- enum {
- Acknowledge = 1,
- Driver = 2,
- DriverOk = 4,
- Failed = 128,
- };
- enum {
- Devfeat = 0,
- Drvfeat = 4,
- Qaddr = 8,
- Qsize = 12,
- Qselect = 14,
- Qnotify = 16,
- Status = 18,
- Isr = 19,
- Devspec = 20,
- };
- enum {
- Next = 1,
- Write = 2,
- Indirect = 4,
- };
- enum {
- VIRTIO_F_NOTIFY_ON_EMPTY = (1 << 24),
- VIRTIO_F_RING_INDIRECT_DESC = (1 << 28),
- VIRTIO_F_RING_EVENT_IDX = (1 << 29),
- };
- enum {
- VRING_AVAIL_F_NO_INTERRUPT = (1 << 0),
- };
- struct Vioreqhdr
- {
- u32int typ;
- u32int prio;
- u64int lba;
- };
- struct Vringhdr
- {
- u16int flags;
- u16int idx;
- };
- struct Vdesc
- {
- u64int addr;
- u32int len;
- u16int flags;
- u16int next;
- };
- struct Vused
- {
- u32int id;
- u32int len;
- };
- struct Key
- {
- void* kaddr;
- ulong paddr;
- };
- typedef struct Key Key;
- struct Vqueue
- {
- int size;
- int free;
- int nfree;
- Vdesc *desc;
- Vringhdr *avail;
- u16int *availent;
- u16int *availevent;
- Vringhdr *used;
- Vused *usedent;
- u16int *usedevent;
- u16int lastused;
- Key *key;
- Rendez;
- QLock;
- Lock;
- };
- struct Vdev
- {
- int typ;
- Pcidev *pci;
- ulong port;
- ulong features;
- int nqueue;
- Vqueue *queue[16];
- int active;
- Vdev *next;
- };
- static Vqueue*
- mkvqueue(int size)
- {
- Vqueue *q;
- uchar *p;
- int i;
- q = malloc(sizeof(*q));
- p = mallocalign(
- PGROUND(sizeof(Vdesc)*size +
- sizeof(Vringhdr) +
- sizeof(u16int)*size +
- sizeof(u16int)) +
- PGROUND(sizeof(Vringhdr) +
- sizeof(Vused)*size +
- sizeof(u16int)),
- BY2PG, 0, 0);
- if(p == nil || q == nil){
- print("mkvqueue: no memory for Vqueue\n");
- free(p);
- free(q);
- return nil;
- }
- q->desc = (void*)p;
- p += sizeof(Vdesc)*size;
- q->avail = (void*)p;
- p += sizeof(Vringhdr);
- q->availent = (void*)p;
- p += sizeof(u16int)*size;
- q->availevent = (void*)p;
- p += sizeof(u16int);
- p = (uchar*)PGROUND((ulong)p);
- q->used = (void*)p;
- p += sizeof(Vringhdr);
- q->usedent = (void*)p;
- p += sizeof(Vused)*size;
- q->usedevent = (void*)p;
- q->key = malloc(sizeof(Key) * size);
- q->free = -1;
- q->nfree = q->size = size;
- for(i=0; i<size; i++){
- q->desc[i].next = q->free;
- q->free = i;
- }
- return q;
- }
- //
- //
- // Virtio-Net specific
- //
- //
- typedef struct Vnetcfg Vnetcfg;
- typedef struct Vnetctrl Vnetctrl;
- /* Virtio-net queue number */
- enum {
- VIRTIO_NET_Q_RX = 0,
- VIRTIO_NET_Q_TX = 1,
- VIRTIO_NET_Q_CTLR = 2,
- };
- /* Virtio-net specific Device features */
- enum {
- VIRTIO_NET_F_CSUM = (1 << 0),
- VIRTIO_NET_F_GUEST_CSUM = (1 << 1),
- VIRTIO_NET_F_MAC = (1 << 5),
- VIRTIO_NET_F_GSO = (1 << 6),
- VIRTIO_NET_F_GUEST_TSO4 = (1 << 7),
- VIRTIO_NET_F_GUEST_TSO6 = (1 << 8),
- VIRTIO_NET_F_GUEST_ECN = (1 << 9),
- VIRTIO_NET_F_GUEST_UFO = (1 << 10),
- VIRTIO_NET_F_HOST_TSO4 = (1 << 11),
- VIRTIO_NET_F_HOST_TSO6 = (1 << 12),
- VIRTIO_NET_F_HOST_ECN = (1 << 13),
- VIRTIO_NET_F_HOST_UFO = (1 << 14),
- VIRTIO_NET_F_MRG_RXBUF = (1 << 15),
- VIRTIO_NET_F_STATUS = (1 << 16),
- VIRTIO_NET_F_CTRL_VQ = (1 << 17),
- VIRTIO_NET_F_CTRL_RX = (1 << 18),
- VIRTIO_NET_F_CTRL_VLAN = (1 << 19),
- VIRTIO_NET_F_GUEST_ANNOUNCE = (1 << 21),
- };
- /* Virtio-net Device Status */
- enum {
- VIRTIO_NET_S_LINK_UP = 1,
- VIRTIO_NET_S_ANNOUNCE = 2,
- };
- /* Not used : Virtio-net Device Specific Region */
- struct Vnetcfg {
- u8int mac[6];
- u16int status;
- };
- /* Vnetreqhdr, flags */
- enum {
- VIRTIO_NET_HDR_F_NEEDS_CSUM =~1,
- };
- /* Vnetreqhdr, gso_type */
- enum {
- VIRTIO_NET_HDR_GSO_NONE = 0,
- VIRTIO_NET_HDR_GSO_TCPV4 = 1,
- VIRTIO_NET_HDR_GSO_UDP = 3,
- VIRTIO_NET_HDR_GSO_TCPV6 = 4,
- VIRTIO_NET_HDR_GSO_ECN = 0x80,
- };
- /* Virtio-net request header */
- #pragma pack on
- typedef struct Vnetreqhdr Vnetreqhdr;
- struct Vnetreqhdr {
- u8int flags;
- u8int gso_type;
- u16int hdr_len;
- u16int gso_size;
- u16int csum_start;
- u16int csum_offset;
- };
- #pragma pack off
- int Vnetreqhdrsize = 10;
- /* Virtio-Net Control Requext Class */
- enum {
- VIRTIO_NET_CTRL_RX_CLASS = 0,
- };
- /* Virtio-net Control Request Command */
- enum {
- VIRTIO_NET_CTRL_RX_CMD_PROMISC = 0,
- VIRTIO_NET_CTRL_RX_CMD_ALLMULTI = 1,
- };
- /* on off */
- enum {
- VIRTIO_NET_CTRL_RX_OFF = 0,
- VIRTIO_NET_CTRL_RX_ON = 1,
- };
- /* ack value */
- enum {
- VIRTIO_NET_CTRL_ACK_OK = 0,
- VIRTIO_NET_CTRL_ACK_ERR = 1,
- };
- /* Virtio-net control request */
- struct Vnetctrl {
- u8int class;
- u8int command;
- };
- /* followed by u8int onoff, u8int ack */
- Vdev *vionethead = nil;
- Vdev *vionettail = nil;
- /////////////////////////////////////////////////////////////////////
- // Virtio-net helper funcs
- /////////////////////////////////////////////////////////////////////
- /*********** Interrupt ***********/
- /*
- * Free descriptors used for this transmit
- */
- static void
- vionettxfree(Vqueue* q, int head)
- {
- Vdesc *d;
- int bufid;
- Vdesc *bufd;
- //ulong paddr;
- //void* kaddr;
- Block *bp;
- Vnetreqhdr *vnetreqhdr;
- print("txfree q %p head %d\n", q, head);
- /* get Vnetreqhdr */
- d = &q->desc[head];
- /* Vnetreqhdr is followed by real buffer descriptor */
- bufid = d->next;
- bufd = &q->desc[bufid];
- /* free header */
- vnetreqhdr = q->key[head].kaddr;
- free(vnetreqhdr);
- d->len = d->flags = 0;
- q->key[head].kaddr = nil;
- /* calculate original Block address and free */
- bp = q->key[bufid].kaddr;
- freeb(bp);
- q->key[bufid].kaddr = nil;
- /* put vdesc for header back */
- d->next = q->free;
- q->free = head;
- q->nfree++;
- /* pub vdesc for buffer back */
- bufd->next = q->free;
- q->free = bufid;
- q->nfree++;
- }
- /*
- * Interrupt on Tx vq.
- * responsible for checking vq change and cleanup
- */
- static void
- vionettxinterrupt(Vdev* vd)
- {
- Vqueue* q;
- int id, m;
- print("txinterrupt : in\n");
- q = vd->queue[VIRTIO_NET_Q_TX];
- print("txinterrupt : vd = %p\n", vd);
- print("txinterrupt : q= %p\n", q);
- m = (q->size-1);
- //lock(q);
- print("txinterrupt: %d ?? %d\n",
- (q->lastused % m), (q->used->idx &m));
- while((q->lastused % m) != (q->used->idx % m)) {
- id = q->usedent[q->lastused++ % (q->size-1)].id;
- vionettxfree(q, id);
- }
- //unlock(q);
- print("txinterrupt : out\n");
- }
- static void
- vionetrxproc(Ether* edev, Vqueue* q, int id)
- {
- Vdesc* d;
- Vdesc* bufd;
- void* buf;
- Block *bp;
- Vnetreqhdr* vnetreqhdr;
- d = &q->desc[id];
- bufd = &q->desc[d->next];
- vnetreqhdr = (Vnetreqhdr*)q->key[id].kaddr;
- print("rxproc : d %p len %d\n", d, d->len);
- print("rxporc : vnetreqhdr %p flags %d len %d\n",
- vnetreqhdr, vnetreqhdr->flags, vnetreqhdr->hdr_len);
- print("rxproc : bufd %p size %d\n", bufd, bufd->len);
- buf = (void*)q->key[d->next].kaddr;
- bp = iallocb(ETHERMAXTU); // XXX
- memmove(bp->rp, buf, ETHERMAXTU); // XXX
- bp->wp += ETHERMAXTU;
- bp->lim = bp->wp; /* lie like a dog */
- /* go up */
- etheriq(edev, bp, 1);
- /* clean current buffer : XXX */
- d->len = sizeof(Vnetreqhdr);
- d->flags = Next|Write;
- vnetreqhdr->hdr_len = ETHERMAXTU;
- bufd->len = ETHERMAXTU;
- bufd->flags = Write;
- }
- static void
- vionetrxinterrupt(Ether* edev)
- {
- Vqueue* q;
- int id, m;
- Vdev* vd;
- int i, head;
- print("vionetrxinterrupt: in, edev %p\n", edev);
- vd = edev->ctlr;
- print("vionetrxinterrupt: in, vd %p\n", vd);
- q = vd->queue[VIRTIO_NET_Q_RX];
- print("vionetrxinterrupt: in, q %p\n", q);
- m = (q->size-1);
- //lock(q);
- print("vionetrxinterrupt: forward and process lastused %d to used->idx %d\n",
- q->lastused, q->used->idx);
- i = 0;
- while((q->lastused % m) != (q->used->idx % m)) {
- id = q->usedent[q->lastused++ % m].id;
- vionetrxproc(edev, q, id);
- /*
- * here id is free. we do push back to free list?
- * NO. push back to avail ring as is.
- */
- coherence();
- i++;
- q->availent[(q->avail->idx++) % m] = id;
- }
- coherence();
- if (i) {
- coherence();
- outs(vd->port+Qnotify, VIRTIO_NET_Q_RX);
- }
- print("vionetrxinterrupt: fixedup receive buffer\n");
- print("vionetrxinterrupt: out\n");
- }
- /************ Initialize ****************/
- static void
- vionettxinit(Vdev* vd)
- {
- print("vionettxinit: in\n");
- if (vd->nqueue < 2) {
- return;
- }
- /* no interrupt */
- print("vionettxinit: in\n");
- // vd->queue[VIRTIO_NET_Q_RX]->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
- print("vionettxinit: in\n");
- vd->queue[VIRTIO_NET_Q_RX]->lastused = 0;
- print("vionettxinit: out\n");
- }
- static int
- vionetrxinithead(Vqueue* q)
- {
- Vdesc* d;
- int head, free;
- Vnetreqhdr* vnetreqhdr;
- void* buf;
- if (q->nfree < 2)
- return -1;
- head = free = q->free;
- d = &q->desc[free];
- /* setup Vnethdr */
- vnetreqhdr = malloc(sizeof(Vnetreqhdr));
- vnetreqhdr->hdr_len = ETHERMAXTU;//sizeof(Vnetreqhdr);
- vnetreqhdr->flags = 0; // XXX
- // vnetreqhdr->num_buffers = 1;
- /* setup vdesc for Vnetreqhdr */
- d->addr = PADDR(vnetreqhdr);
- d->len = Vnetreqhdrsize;//sizeof(Vnetreqhdr);
- d->flags = Next|Write ;
- /* save key */
- q->key[head].paddr = d->addr;
- q->key[head].kaddr = vnetreqhdr;
- free = d->next;
- /* get vdesc for data buffer : a real frame */
- d = &q->desc[free];
- /* setup vdesc */
- buf = malloc(ETHERMAXTU);
- d->addr = PADDR(buf);
- d->len = ETHERMAXTU;
- d->flags = Write;
- /* save key */
- q->key[free].paddr = d->addr;
- q->key[free].kaddr = buf;
- free = d->next;
- q->nfree -= 2;
- q->free = free;
- return head;
- }
- static void
- vionetrxinit(Vdev* vd)
- {
- Vqueue *q;
- Vdesc *d;
- int nadded;
- int head, free;
- Vnetreqhdr* vnetreqhdr;
- void* buf;
- print("vionetrxinit: in\n");
- if (vd->nqueue < 1) {
- return;
- }
- print("vionetrxinit: fetch queuen\n");
- q = vd->queue[VIRTIO_NET_Q_RX];
- print("vionetrxinit: each vdesc has %d byte buffer\n", ETHERMAXTU);
- /*
- q->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
- */
- print("vionetrxinit: allocating buffer\n");
- /* allocate receive buffer */
- nadded = 0;
- while(1) {
- head = vionetrxinithead(q);
- if (head < 0)
- break;
- coherence();
- /* put head's number into avail ring */
- nadded++;
- q->availent[(q->avail->idx++) % (q->size-1)] = head;
- coherence();
- }
- if (nadded > 0) {
- coherence();
- /* update avail idx */
- coherence();
- outs(vd->port+Qnotify, VIRTIO_NET_Q_RX);
- }
- print("vionetrxinit: allocated %d buffers\n", nadded);
- q->lastused = 0;
- print("vionettxinit: out\n");
- }
- static void
- vionetvqinit(Vdev* vd)
- {
- int i;
- int size;
- u32int a;
- for (i = 0; i < nelem(vd->queue) ; i++) {
- /* select operating queue */
- outs(vd->port + Qselect, i);
- /* get operating queue size (0 : disabled) */
- if ((size = ins(vd->port + Qsize)) == 0)
- break;
- if ((vd->queue[i] = mkvqueue(size)) == nil)
- break;
- coherence();
- a = PADDR(vd->queue[i]->desc)/BY2PG;
- /* write addr of operating queue at Qaddr */
- outl(vd->port + Qaddr, a);
- }
- vd->nqueue = i;
- /* setup rx */
- vionettxinit(vd);
- /* setup tx */
- vionetrxinit(vd);
- }
- /*
- * Negotiates Device features and given Driver features
- */
- static ulong
- vio_negotiate_feature(Vdev *vd, ulong drvfeat)
- {
- ulong features;
- print("vio neto fet: in %ld + %d\n", vd->port, Devfeat);
- /* read device features */
- features = inl(vd->port + Devfeat);
- print("vio neto fet: in sec\n");
- features &= drvfeat;
- print("vio neto fet: out %ld %d\n", vd->port, Drvfeat);
- /* write back features */
- outl(vd->port + Drvfeat, features);
- print("vio neto fet: out\n");
- return features;
- }
- static void
- vionetinit1(Ether* edev, Vdev* vd)
- {
- int i;
- print("vionetinit1: in\n");
- /* check feature bit : F_MAC */
- if (vd->features & VIRTIO_NET_F_MAC) {
- for (i = 0; i < 6; i++) {
- edev->ea[i] = inb(vd->port + Devspec + i);
- }
- } else {
- for (i = 0; i < 6; i++) {
- edev->ea[i] = 0xff;
- outb(vd->port + Devspec + i, edev->ea[i]);
- }
- }
- /* check feature bit : F_STATUS */
- if (vd->features & VIRTIO_NET_F_STATUS) {
- /* check and up the link */
- edev->link = (0x01 & ins(vd->port + Devspec + Eaddrlen));
- print("vionetinit1: link is %d\n", edev->link);
- edev->link &= 0x01;
- print("vionetinit1: link is %d\n", edev->link);
- outs(vd->port + Devspec + Eaddrlen, edev->link);
- } else {
- /* spec says assume active */
- edev->link = 0x01;
- }
- print("vionetinit1: out\n");
- }
- /*
- * Initialize device&driver
- */
- static void
- vionetinit(Vdev* vd)
- {
- int is_ctrl_vq = 0;
- print("vionetinit: in\n");
- /* negotiate features */
- vd->features = vio_negotiate_feature(vd,
- VIRTIO_F_NOTIFY_ON_EMPTY |
- VIRTIO_NET_F_MAC |
- VIRTIO_NET_F_STATUS |
- // VIRTIO_NET_F_CTRL_VQ |
- VIRTIO_NET_F_CTRL_RX |
- 0
- );
- print("vionetinit: negotiated\n");
- /* negotiate features */
- /* check feature bit : F_CTRL_VQ */
- if (vd->features & VIRTIO_NET_F_CTRL_VQ) {
- is_ctrl_vq = 1;
- }
- /* setup virtqueue */
- print("vionetinit: call vionetvqinit\n");
- vionetvqinit(vd);
- print("vionetinit: called vionetvqinit\n");
- /* check if ctrlvq is valid */
- if (is_ctrl_vq && vd->nqueue != 3) {
- print("vionetinit(): ctrl queue is invalid\n");
- }
- print("vionetinit: out\n");
- return;
- }
- /////////////////////////////////////////////////////////////////////
- // Generic Network driver funcs
- /////////////////////////////////////////////////////////////////////
- static void
- vionetattach(Ether*)
- {
- /* nothing to do */
- }
- void
- vionettransmit(Ether* edev)
- {
- Block* bp; /* bp->rp has address */
- Vdev* vd;
- int head, free;
- Vdesc *d;
- Vqueue *q;
- int nadded = 0;
- Vnetreqhdr* vnetreqhdr;
- vd = edev->ctlr;
- q = vd->queue[VIRTIO_NET_Q_TX];
- print("vionettransmit: in\n");
- //lock(q);
- for (;;) {
- /* needs 2 entries for transmit */
- if (q->nfree < 2) {
- //unlock(q);
- //error("out of virtio descriptors");
- print("vionettransmit: run out of queue : break;\n");
- break;
- }
- /* get next frame to send */
- if ((bp = qget(edev->oq)) == nil) {
- print("vionettransmit: run out of oq : break;\n");
- break;
- }
- head = free = q->free;
- print("vionettransmit: head is %d\n", head);
- /* get vdesc for Vnethdr */
- d = &q->desc[free]; free = d->next;
- /* setup Vnethdr */
- vnetreqhdr = malloc(Vnetreqhdrsize/*sizeof(Vnetreqhdr)*/);
- // vnetreqhdr->hdr_len = Vnetreqhdrsize;//sizeof(Vnetreqhdr);
- vnetreqhdr->flags = 0; // XXX
- // vnetreqhdr->num_buffers = 1;
- /* setup vdesc for Vnethdr */
- d->addr = PADDR(vnetreqhdr);
- d->len = Vnetreqhdrsize;//sizeof(Vnetreqhdr);
- d->flags = Next;
- /* save paddr and kaddr */
- q->key[head].paddr = d->addr;
- q->key[head].kaddr = vnetreqhdr;
- /* get vdesc for data buffer : a real frame */
- print("vionettransmit: buffer is %d\n", free);
- d = &q->desc[free]; free = d->next;
- /* setup vdesc for data buffer */
- d->addr = PADDR(bp->rp);
- d->len = BLEN(bp);
- d->flags = 0;
- /* save paddr and kaddr , paddr */
- q->key[free].paddr = d->addr;
- q->key[free].kaddr = bp;
- print("vionettransmit: q->free %d, q->nfree %d\n", q->free, q->nfree);
- q->nfree -= 2;
- q->free = free;
- coherence();
- /* put head's number into avail ring */
- print("vionettransmit: set head %d at idx %d + nadded %d q->size %d\n",
- head, q->avail->idx, nadded, q->size);
- nadded++;
- /* update avail idx */
- q->availent[(q->avail->idx++) & (q->size-1)] = head;
- coherence();
- print("vionettransmit: nadded is %d q->free %d, q->nfree %d\n",
- nadded, q->free, q->nfree);
- }
- coherence();
- //unlock(q);
- if (nadded > 0) {
- print("vionettransmit: updated idx to %d\n", q->avail->idx);
- /* notify */
- outs(vd->port+Qnotify, VIRTIO_NET_Q_TX);
- }
- print("vionettransmit: done\n");
- print("vionettransmit: out\n");
- }
- static void
- vionetinterrupt(Ureg*, void* arg)
- {
- Vdev *vd;
- Ether *edev;
- edev = arg;
- vd = edev->ctlr;
- if (edev == nil || vd == nil)
- return;
- print("vionetinterrupt: in edev %p vd %p\n", edev, vd);
- if (inb(vd->port + Isr) & 1) {
- print("vionetinterrupt: in Isr\n");
- /* wakeup ctrl op */
- // if (vd->nqueue > VIRTIO_NET_Q_CTLR) {
- // wakeup(vd->queue[VIRTIO_NET_Q_CTLR]);
- // }
- /* control vq */
- // vionetctrlinterrupt(vd);
- /* transmit vq */
- print("vionetinterrupt: in tx\n");
- vionettxinterrupt(vd);
- /* receive vq */
- print("vionetinterrupt: in rx\n");
- vionetrxinterrupt(edev);
- print("vionetinterrupt: in done\n");
- }
- if (inb(vd->port + Isr) & 2) {
- /* config space has changed */
- print("vionetinterrupt: config changed\n");
- }
- print("vionetinterrupt: out\n");
- }
- static long
- vionetifstat(Ether*, void*, long, ulong)
- {
- return 0;
- }
- static void
- vionetshutdown()
- {
- /* do cleanup */
- return;
- }
- static long
- vionetctl(Ether*, void*, long)
- {
- /* do nothing */
- return 0;
- }
- /*
- static void
- vionetdone(void *arg)
- {
- struct Rock *r;
- Vqueue *q;
- u16int i;
- r = arg;
- q = r->q;
- for (i = q->lastused; i != q->used->idx; i++) {
- if (q->usedent[i % q->size].id == r->id) {
- if (i == q->lastused)
- q->lastused++;
- r->done =1;
- break;
- }
- }
- return r->done;
- }
- */
- /*
- static void
- vionetwait(Vqueue *q, int id)
- {
- struct Rock r;
- r.q = q;
- r.id = id;
- r.done = 0;
- do {
- //qlock(q);
- while(waserror());
- sleep(q, vionetdone, &r);
- poperror();
- //qunlock(q);
- } while(!r.done);
- }
- */
- /*
- * Send Control request to device.
- */
- static void
- vionetctrl(Ether* edev, u8int cmd, u8int on)
- {
- Vnetctrl vnetctrl;
- Vdev* vd;
- Vqueue* q;
- int free, head;
- Vdesc *d;
- u8int ack;
- u8int onoff;
- vd = edev->ctlr;
- onoff = on ? VIRTIO_NET_CTRL_RX_ON : VIRTIO_NET_CTRL_RX_OFF;
- ack = VIRTIO_NET_CTRL_ACK_ERR;
- q = vd->queue[VIRTIO_NET_Q_CTLR];
- //lock(q);
- /* get idx of head of free entry */
- head = free = q->free;
- /* allocate Vnetctrl entry */
- vnetctrl.class = VIRTIO_NET_CTRL_RX_CLASS;
- vnetctrl.command = cmd;
- /* push vnetctrl */
- d = &q->desc[free]; free = d->next;
- d->addr = PADDR(&vnetctrl);
- d->len = sizeof(vnetctrl);
- d->flags = Next;
- /* push onoff */
- d = &q->desc[free]; free = d->next;
- d->addr = PADDR(&onoff);
- d->len = sizeof(u8int);
- d->flags = Next;
- /* push ack */
- d = &q->desc[free]; free = d->next;
- d->addr = PADDR(&ack);
- d->len = sizeof(u8int);
- d->flags = Write;
- d->next = -1;
- q->free = free;
- q->nfree -= 3; /* pushed 3 */
- coherence(); /* sync */
- q->availent[q->avail->idx++ & q->size] = head;
- //unlock(q);
- coherence();
- /* commit notify */
- outs(vd->port + Qnotify, VIRTIO_NET_Q_CTLR);
- /* blocking */
- //vionetwait(q, head);
- if (ack != VIRTIO_NET_CTRL_RX_ON) {
- print("vionetctrl: cmd = %d ack is ERR\n", cmd);
- error(Eio);
- }
- return;
- }
- static void
- vionetpromiscuous(void* arg, int on)
- {
- Ether* edev;
- edev = arg;
- vionetctrl(edev, VIRTIO_NET_CTRL_RX_CMD_PROMISC, on);
- return;
- }
- static void
- vionetmulticast(void* arg, uchar*, int on)
- {
- Ether* edev;
- edev = arg;
- vionetctrl(edev, VIRTIO_NET_CTRL_RX_CMD_ALLMULTI, on);
- return;
- }
- /*
- * Finds all virtio-net devices and list up in vionethead to vionettail.
- * Do virtio-dev init and mkvqueue
- */
- static void
- vionetpci(void)
- {
- Pcidev* p;
- Vdev *vd;
- print("vionetpci: in %d %d \n",
- sizeof(Vnetreqhdr), sizeof(Vnetctrl));
- for (p = nil; p = pcimatch(p, 0, 0);) {
- if (p->vid != 0x1af4)
- continue;
- if ((p->did < 0x1000) || (p->did >= 0x1040))
- continue;
- if (p->rid != 0)
- continue;
- if (pcicfgr16(p, 0x2e) != 1 /* virtio-net subid */)
- continue;
- print("vionetpci: found device\n");
- if ((vd = malloc(sizeof(*vd))) == nil) {
- print("vionetpci(): cannnot allocate Vdev\n");
- break;
- }
- print("vionetpci: vd alloced\n");
- vd->port = p->mem[0].bar & ~0x1;
- if (ioalloc(vd->port, p->mem[0].size, 0, "virtio") < 0) {
- print("virtio: port %lux in use\n", vd->port);
- free(vd);
- continue;
- }
- vd->typ = 1 /* nic */;
- vd->pci = p;
- /* reset */
- outb(vd->port + Status, 0);
- /* set Acknowkedge and Driver */
- print("vionetpci: Acknowledge and Driver to device\n");
- outl(vd->port+Status, inb(vd->port+Status)|Acknowledge|Driver);
- print("vionetpci: sent Acknowledge and Driver to device\n");
- /* prepare vionet device */
- print("vionetpci: call vionetinit()\n");
- vionetinit(vd);
- print("vionetpci: called vionetinit()\n");
- print("vionetpnp: enable interrupt¥n");
- //intrenable(vd->pci->intl, vionetinterrupt, vd, vd->pci->tbdf, "ethervirtio");
- print("vionetpnp: enabled interrupt¥n");
- /* done initialization */
- print("vionetpnp: set status DriverOk\n");
- outb(vd->port + Status, inb(vd->port + Status) | DriverOk);
- print("vionetpnp: seted status DriverOk\n");
- vd->next = nil;
- if (vionethead == nil)
- vionethead = vd;
- else
- vionettail->next = vd;
- vionettail = vd;
- print("inited : vd %p\n", vd);
- print("inited : vd q0 %p\n", vd->queue[0]);
- print("inited : vd q1 %p\n", vd->queue[1]);
- }
- print("vionetpci: out\n");
- }
- static int
- vionetpnp(Ether* edev)
- {
- Vdev* vd;
- static int done;
- if (!done) {
- vionetpci(); /* do initialize each device */
- done = 1;
- }
- for (vd = vionethead; ; vd = vd->next) {
- if (vd == nil)
- return -1;
- if (vd->active)
- continue;
- if (edev->port == 0 || edev->port == vd->port) {
- vd->active = 1;
- break;
- }
- }
- if (vd == nil)
- return -1;
- edev->ctlr = vd;
- edev->port = vd->port;
- edev->irq = vd->pci->intl;
- edev->tbdf = vd->pci->tbdf;
- edev->mbps = 1000;
- print("vionetpnp: edev %p\n", edev);
- print("vionetpnp: vd %p\n", vd);
- print("vionetpnp: call vionetinit1\n");
- vionetinit1(edev, vd);
- print("vionetpnp: called vionetinit1\n");
- /*
- * set handler functions
- */
- edev->attach = vionetattach;
- edev->transmit = vionettransmit;
- edev->interrupt = vionetinterrupt;
- edev->ifstat = vionetifstat;
- edev->shutdown = vionetshutdown;
- edev->ctl = vionetctl;
- edev->arg = edev;
- /*
- edev->promiscuous = vionetpromiscuous;
- edev->multicast = vionetmulticast;
- */
- print("vionetpnp: out\n");
- return 0;
- }
- void
- ethervirtiolink(void)
- {
- addethercard("virtio", vionetpnp);
- }
Add Comment
Please, Sign In to add comment