ref: b554ad054bee15040c59faa65c134a876cee654e
parent: 1caaa0318b216bbbe6c18a7d9c27f87fa34c9a31
author: cinap_lenrek <[email protected]>
date: Sun Jun 7 13:33:31 EDT 2015
zynq: fix /dev/pl prevent double sleep(): callers to sleep() need to be serialized as there can only be one process sleeping at a time. plrlock and plwlock do this. wait for dma to complete in plwrite(): we have to wait for the dma to complete before touching plbuf again. maintain COPEN flag in archopen()/archclose(): when open fails because it was in use, clear the COPEN flag, so archclose() wont screw stuff up.
--- a/sys/src/9/zynq/devarch.c
+++ b/sys/src/9/zynq/devarch.c
@@ -26,10 +26,11 @@
int temp = -128;
ulong *devc;
int dmadone;
-QLock pllock;
enum { PLBUFSIZ = 8192 };
uchar *plbuf;
Rendez plinitr, pldoner, pldmar;
+QLock plrlock, plwlock;
+Ref plwopen;
enum {
DEVCTRL = 0,
@@ -160,7 +161,6 @@
if((fl & DONE) != 0){
slcr[0x900/4] = 0xf;
slcr[0x240/4] = 0;
- print("DONE!\n");
devc[DEVMASK] |= DONE;
wakeup(&pldoner);
}
@@ -195,33 +195,35 @@
static void
plconf(void)
{
- if(!canqlock(&pllock))
- error(Einuse);
slcr[0x240/4] = 0xf;
slcr[0x900/4] = 0xa;
- dmadone = 1;
devc[DEVISTS] = DONE|INITPE|DMADONE;
devc[DEVCTRL] |= PROG;
devc[DEVCTRL] &= ~PROG;
devc[DEVMASK] &= ~DONE;
devc[DEVCTRL] |= PROG;
+
+ while(waserror())
+ ;
sleep(&plinitr, isplinit, nil);
- plbuf = smalloc(PLBUFSIZ);
+ poperror();
}
static long
plwrite(uintptr pa, long n)
{
- long w;
-
- w = n >> 2;
- sleep(&pldmar, isdmadone, nil);
dmadone = 0;
coherence();
devc[DMASRC] = pa;
devc[DMADST] = -1;
- devc[DMASRCL] = w;
+ devc[DMASRCL] = n>>2;
devc[DMADSTL] = 0;
+
+ while(waserror())
+ ;
+ sleep(&pldmar, isdmadone, nil);
+ poperror();
+
return n;
}
@@ -234,6 +236,13 @@
if((n & 3) != 0 || n <= 0)
error(Eshort);
+
+ eqlock(&plwlock);
+ if(waserror()){
+ qunlock(&plwlock);
+ nexterror();
+ }
+
ret = n;
pa = PADDR(plbuf);
while(n > 0){
@@ -246,43 +255,10 @@
clean2pa(pa, pa + nn);
n -= plwrite(pa, nn);
}
- return ret;
-}
-static long
-userdma(void *a, long n, long (*f)(uintptr, long))
-{
- ulong s;
- void *va;
- uintptr pa;
- long off, nn, ret;
+ qunlock(&plwlock);
+ poperror();
- evenaddr((uintptr) a);
- if((n & 3) != 0)
- error(Eshort);
-
- ret = n;
- while(n > 0){
- off = (uintptr)a & BY2PG - 1;
- va = (void *) ((uintptr)a & ~(BY2PG - 1));
- s = splhi();
- while(pa = palookur(va), (pa & 1) != 0){
- splx(s);
- if(fault(pa, 1) < 0)
- error(Egreg);
- s = splhi();
- }
- if(off + n >= BY2PG)
- nn = BY2PG - off;
- else
- nn = n;
- pa = (pa & ~(BY2PG - 1)) + off;
- cleandse((char *) a + off, (char*) a + off + nn);
- clean2pa(pa, pa + nn);
- n -= f(pa, nn);
- splx(s);
- a = (char *) va + BY2PG;
- }
return ret;
}
@@ -306,7 +282,14 @@
snprint(buf, sizeof(buf), "%d.%d\n", temp/10, temp%10);
return readstr(offset, a, n, buf);
case Qpl:
+ eqlock(&plrlock);
+ if(waserror()){
+ qunlock(&plrlock);
+ nexterror();
+ }
sleep(&pldoner, ispldone, nil);
+ qunlock(&plrlock);
+ poperror();
return 0;
default:
error(Egreg);
@@ -315,7 +298,7 @@
}
static long
-archwrite(Chan *c, void *a, long n, vlong offset)
+archwrite(Chan *c, void *a, long n, vlong)
{
switch((ulong)c->qid.path){
case Qpl:
@@ -342,8 +325,15 @@
archopen(Chan* c, int omode)
{
devopen(c, omode, archdir, narchdir, devgen);
- if((ulong)c->qid.path == Qpl && c->mode == OWRITE)
+ if((ulong)c->qid.path == Qpl && (c->mode == OWRITE || c->mode == ORDWR)){
+ if(incref(&plwopen) != 1){
+ c->flag &= ~COPEN;
+ decref(&plwopen);
+ error(Einuse);
+ }
+ plbuf = smalloc(PLBUFSIZ);
plconf();
+ }
return c;
}
@@ -350,15 +340,11 @@
static void
archclose(Chan* c)
{
- if((ulong)c->qid.path == Qpl && c->mode == OWRITE){
- /* cleandse(plbuf, plbuf + plbufn);
- clean2pa(PADDR(plbuf), PADDR(plbuf) + plbufn);
- plwrite(PADDR(plbuf), 4096);
- plwrite(PADDR(plbuf) + 4096, plbufn - 4096);
- plbufn = 0;*/
+ if((c->flag & COPEN) != 0)
+ if((ulong)c->qid.path == Qpl && (c->mode == OWRITE || c->mode == ORDWR)){
free(plbuf);
plbuf = nil;
- qunlock(&pllock);
+ decref(&plwopen);
}
}