ref: bd12cb47ce937deb09657fa79c20a036f9b2a73a
parent: 2fe3b28f86ed4aa291fb8a620b948abe9c6a1f84
author: aiju <devnull@localhost>
date: Thu Jun 15 11:58:52 EDT 2017
vmx: implement virtio reset
--- a/sys/src/cmd/vmx/virtio.c
+++ b/sys/src/cmd/vmx/virtio.c
@@ -15,6 +15,8 @@
BUFWR = 2,
USEDNOIRQ = 1,
+
+ DRIVEROK = 4, /* devstat */
};
struct VIOBuf {
@@ -37,6 +39,8 @@
u32int addr;
u16int availidx, usedidx;
void (*notify)(VIOQueue*);
+ int livebuf;
+ Rendez livebufrend;
};
struct VIONetDev {
@@ -66,6 +70,7 @@
VIOQueue *qu;
int nqu;
u32int (*io)(int, u16int, u32int, int, VIODev *);
+ void (*reset)(VIODev *);
union {
VIONetDev net;
VIOBlkDev blk;
@@ -119,7 +124,7 @@
qlock(q);
waitloop:
- while(q->desc == nil || (gidx = GET16(q->avail, 2), gidx == q->availidx)){
+ while((q->d->devstat & DRIVEROK) == 0 || q->desc == nil || (gidx = GET16(q->avail, 2), gidx == q->availidx)){
if(!wait){
qunlock(q);
return nil;
@@ -151,6 +156,7 @@
}
q->availidx++;
if(rb == nil) goto waitloop;
+ q->livebuf++;
qunlock(q);
return rb;
}
@@ -165,6 +171,10 @@
if(b == nil) return;
q = b->qu;
qlock(q);
+ if((q->d->devstat & DRIVEROK) == 0){
+ qunlock(q);
+ goto end;
+ }
if(q->used == nil)
vmerror("virtio device %#x: address was set to an invalid value while holding buffer", q->d->pci->bdf);
else{
@@ -173,9 +183,12 @@
PUT32(p, 0, b->idx);
PUT16(q->used, 2, ++q->usedidx);
}
+ if(--q->livebuf <= 0)
+ rwakeup(&q->livebufrend);
qunlock(q);
if(q->avail != nil && (GET16(q->avail, 0) & USEDNOIRQ) == 0)
vioirq(q->d, 1);
+end:
while(b != nil){
bn = b->next;
free(b);
@@ -292,6 +305,29 @@
qunlock(q);
}
+static void
+viodevstatset(VIODev *v, u32int val)
+{
+ int i;
+
+ v->devstat = val;
+ if(val == 0){
+ if(v->reset != nil)
+ v->reset(v);
+ v->guestfeat = 0;
+ vioirq(v, 0);
+ for(i = 0; i < v->nqu; i++){
+ qlock(&v->qu[i]);
+ while(v->qu[i].livebuf > 0)
+ rsleep(&v->qu[i].livebufrend);
+ qunlock(&v->qu[i]);
+ }
+ }else{
+ for(i = 0; i < v->nqu; i++)
+ v->qu[i].notify(&v->qu[i]);
+ }
+}
+
u32int
vioio(int isin, u16int port, u32int val, int sz, void *vp)
{
@@ -305,7 +341,7 @@
case 0x8: if(v->qsel < v->nqu) vioqaddrset(&v->qu[v->qsel], val); return 0;
case 0xe: v->qsel = val; return 0;
case 0x10: if(val < v->nqu) v->qu[val].notify(&v->qu[val]); return 0;
- case 0x12: v->devstat = val; return 0;
+ case 0x12: viodevstatset(v, val); return 0;
case 0x10000: return v->devfeat;
case 0x10004: return v->guestfeat;
case 0x10008: return v->qsel >= v->nqu ? 0 : v->qu[v->qsel].addr;
@@ -353,6 +389,7 @@
q = d->qu + d->nqu++;
memset(q, 0, sizeof(VIOQueue));
q->Rendez.l = q;
+ q->livebufrend.l = q;
q->size = sz;
q->d = d;
q->notify = fn;
@@ -475,7 +512,7 @@
continue;
}
if(rc < len){
- vmerror("write(vionetwproc): incomplete write");
+ vmerror("write(vionetwproc): incomplete write (%d < %d)", rc, len);
continue;
}
}
@@ -562,6 +599,14 @@
}
}
+void
+vionetreset(VIODev *d)
+{
+ d->net.flags = 0;
+ d->net.macbloom = 0;
+ d->net.multibloom = 0;
+}
+
int
mkvionet(char *net)
{
@@ -581,6 +626,7 @@
d->net.mac[0] = d->net.mac[0] & ~1 | 2;
d->devfeat = 1<<5|1<<16|1<<17|1<<18|1<<20;
d->io = vionetio;
+ d->reset = vionetreset;
d->net.readfd = d->net.writefd = fd;
proccreate(vionetrproc, d, 8192);
proccreate(vionetwproc, d, 8192);