shithub: riscv

Download patch

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);