From d9329cfd73c4b72130b3adb72a5f0ef3629ba49b Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sat, 13 Jun 1992 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1992-06-13 --- port/devmnt.c | 7 +- power/dat.h | 37 +--- power/devcyc.c | 398 ++++++++++++++++++++++++++++++++++++++++++ power/devhotrod.c | 433 ---------------------------------------------- 4 files changed, 408 insertions(+), 467 deletions(-) create mode 100644 power/devcyc.c delete mode 100644 power/devhotrod.c diff --git a/port/devmnt.c b/port/devmnt.c index 2b2f6d8b9015d624d055aea24e84c2b294a77ae6..f770895af74c5bc9a9e4a1d9a3a27826545ee009 100644 --- a/port/devmnt.c +++ b/port/devmnt.c @@ -48,8 +48,7 @@ struct Mntalloc int id; }mntalloc; -#define BITBOTCH 256 -#define MAXRPC (MAXFDATA+MAXMSG+BITBOTCH) +#define MAXRPC (MAXFDATA+MAXMSG) #define limit(n, max) (n > max ? max : n) Chan *mattach(Mnt*, char*, char*); @@ -540,8 +539,8 @@ mntrdwr(int type, Chan *c, void *buf, long n, ulong offset) void mountrpc(Mnt *m, Mntrpc *r) { - r->reply.tag = 0; /* safety check */ - r->reply.type = 4; /* safety check */ + r->reply.tag = 0; /* safety checks */ + r->reply.type = 4; mountio(m, r); if(r->reply.type == Rerror) error(r->reply.ename); diff --git a/power/dat.h b/power/dat.h index 7a6d30b9c6c234f07d2877793dbedb43f686539b..c08ce0e128527badb5d2e355eda7f1c24a8b28e6 100644 --- a/power/dat.h +++ b/power/dat.h @@ -1,7 +1,6 @@ -typedef struct Bit3msg Bit3msg; typedef struct Conf Conf; typedef struct FPsave FPsave; -typedef struct Hotmsg Hotmsg; +typedef struct Cycmsg Cycmsg; typedef struct Lance Lance; typedef struct Lancemem Lancemem; typedef struct Label Label; @@ -101,25 +100,12 @@ struct PMMU #include "../port/portdat.h" -/* - * machine dependent definitions not used by ../port/dat.h - */ -struct Bit3msg -{ - ulong cmd; - ulong addr; - ulong count; - ulong rcount; -}; - -struct Hotmsg +struct Cycmsg { ulong cmd; ulong param[5]; Rendez r; uchar intr; /* flag: interrupt has occurred */ - uchar abort; /* flag: don't interrupt */ - ushort wlen; /* length of last message written */ }; struct Mach @@ -221,7 +207,7 @@ struct User Chan *dot; /* * Rest of structure controlled by devproc.c and friends. - * lock(&p->debug) to modify. + * qlock(&p->debug) to modify. */ Note note[NNOTE]; short nnote; @@ -236,22 +222,13 @@ struct User * machine dependent User stuff */ /* - * I/O point for bit3 and hotrod interfaces. + * I/O point for hotrod interfaces. * This is the easiest way to allocate * them, but not the prettiest or most general. */ - union{ /* for i/o from kernel */ - Bit3msg kbit3; - Hotmsg khot; - }; - union{ /* for i/o from user */ - Bit3msg ubit3; - Hotmsg uhot; - }; - union{ /* special location for Tflush */ - Bit3msg fbit3; - Hotmsg fhot; - }; + Cycmsg kcyc; + Cycmsg ucyc; + Cycmsg fcyc; }; extern register Mach *m; diff --git a/power/devcyc.c b/power/devcyc.c new file mode 100644 index 0000000000000000000000000000000000000000..98d474e08e7f100fa49f3a5a3151890eb1f3810c --- /dev/null +++ b/power/devcyc.c @@ -0,0 +1,398 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "devtab.h" +#include "fcall.h" + +#include "io.h" +#include "../../fs/cyc/comm.h" + + +typedef struct Commcyc Commcyc; + +enum +{ + Vmevec= 0xd2, /* vme vector for interrupts */ + Intlevel= 5, /* level to interrupt on */ + Qdir= 0, /* Qid's */ + Qcyc= 1, + Ncyc= 1, +}; + +Dirtab cycdir[]={ + "cyc", {Qcyc}, 0, 0600, +}; + +#define NCYCDIR (sizeof cycdir/sizeof(Dirtab)) + +struct Commcyc +{ + Lock; + QLock buflock; + Lock busy; + Comm *addr; /* address of the device */ + int vec; /* vme interrupt vector */ + int wi; /* where to write next cmd */ + int ri; /* where to read next reply */ + uchar buf[MAXFDATA+MAXMSG]; +}; + +Commcyc cyclone[Ncyc]; + +void cycintr(int); + +#define CYCLONE VMEA24SUP(Comm, 0x10000); + +/* + * Commands + */ + +Cycmsg** +cycsend(Commcyc *h, Cycmsg *m) +{ + Cycmsg **mp; + + lock(h); + mp = (Cycmsg**)&h->addr->reqstq[h->wi]; + *mp = (Cycmsg*)MP2VME(m); + h->wi++; + if(h->wi >= NRQ) + h->wi = 0; + unlock(h); + return mp; +} + +void +cycwait(Cycmsg **mp) +{ + ulong l; + + l = 0; + while(*mp){ + delay(0); /* just a subroutine call; stay off VME */ + if(++l > 10*1000*1000){ + l = 0; + panic("cycsend blocked"); + } + } + return; +} + +/* + * reset all cyclone boards + */ +void +cycreset(void) +{ + int i; + Commcyc *cp; + + for(cp=cyclone,i=0; iaddr = CYCLONE+i; + /* + * Write queue is at end of cyclone memory + */ + cp->vec = Vmevec+i; + setvmevec(cp->vec, cycintr); + } +} + +void +cycinit(void) +{ +} + +/* + * enable the device for interrupts, spec is the device number + */ +Chan* +cycattach(char *spec) +{ + int i; + Chan *c; + + i = strtoul(spec, 0, 0); + if(i >= Ncyc) + error(Ebadarg); + + c = devattach('C', spec); + c->dev = i; + c->qid.path = CHDIR; + c->qid.vers = 0; + return c; +} + +Chan* +cycclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +cycwalk(Chan *c, char *name) +{ + return devwalk(c, name, cycdir, NCYCDIR, devgen); +} + +void +cycstat(Chan *c, char *dp) +{ + devstat(c, dp, cycdir, NCYCDIR, devgen); +} + +Chan* +cycopen(Chan *c, int omode) +{ + Commcyc *cp; + Cycmsg *mp, **cmp; + + if(c->qid.path == CHDIR){ + if(omode != OREAD) + error(Eperm); + }else if(c->qid.path == Qcyc){ + cp = &cyclone[c->dev]; + if(!canlock(&cp->busy)) + error(Einuse); + /* + * Clear communications region + */ + memset(cp->addr->reqstq, 0, NRQ*sizeof(ulong)); + cp->addr->reqstp = 0; + memset(cp->addr->replyq, 0, NRQ*sizeof(ulong)); + cp->addr->replyp = 0; + + /* + * Issue reset + */ + cp->wi = 0; + cp->ri = 0; + mp = &u->kcyc; + mp->cmd = Ureset; + cmp = cycsend(cp, &((User*)(u->p->upage->pa|KZERO))->kcyc); + cycwait(cmp); + delay(100); + print("reset\n"); + } + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +cyccreate(Chan *c, char *name, int omode, ulong perm) +{ + USED(c, name, omode, perm); + error(Eperm); +} + +void +cycclose(Chan *c) +{ + Commcyc *cp; + Cycmsg **cmp; + + cp = &cyclone[c->dev]; + if(c->qid.path != CHDIR){ + u->kcyc.cmd = Ureboot; + cmp = cycsend(cp, &((User*)(u->p->upage->pa|KZERO))->kcyc); + cycwait(cmp); + unlock(&cp->busy); + } +} + + +int +cycmsgintr(Cycmsg *hm) +{ + return hm->intr; +} + +/* + * Read and write use physical addresses if they can, which they usually can. + * Most I/O is from devmnt, which has local buffers. Therefore just check + * that buf is in KSEG0 and is at an even address. + */ + +long +cycread(Chan *c, void *buf, long n, ulong offset) +{ + User *pu; + Commcyc *cp; + Cycmsg *mp, **cmp; + ulong l, m, isflush; + + cp = &cyclone[c->dev]; + switch(c->qid.path & ~CHDIR){ + case Qdir: + return devdirread(c, buf, n, cycdir, NCYCDIR, devgen); + + case Qcyc: + if(n > sizeof cp->buf){ + print("cyclone bufsize %d %d\n", n, sizeof cp->buf); + error(Egreg); + } + pu = (User*)(u->p->upage->pa|KZERO); + if((((ulong)buf)&(KSEGM|3)) == KSEG0){ + /* + * use supplied buffer, no need to lock for reply + */ + + mp = &pu->kcyc; + mp->cmd = Uread; + mp->param[0] = MP2VME(buf); + mp->param[1] = n; + mp->param[2] = 0; /* reply checksum */ + mp->param[3] = 0xdeadbeef; /* reply count */ + mp->intr = 0; + cycsend(cp, mp); + + while(waserror()) + ; + sleep(&mp->r, cycmsgintr, mp); + poperror(); + + m = mp->param[3]; + if(m==0 || m>n){ + print("devcyc: count 0x%lux 0x%lux\n", m, n); + error(Egreg); + } + } + else{ + /* + * use cyclone buffer. lock the buffer until the reply + */ + mp = &pu->ucyc; + qlock(&cp->buflock); + mp->cmd = Uread; + mp->param[0] = MP2VME(cp->buf); + mp->param[1] = n; + mp->param[2] = 0; /* reply checksum */ + mp->param[3] = 0; /* reply count */ + mp->intr = 0; + cmp = cycsend(cp, mp); + cycwait(cmp); + l = 100*1000*1000; + do + m = mp->param[3]; + while(m==0 && --l>0); + if(m==0 || m>n){ + print("devcyc: count %ld %ld\n", m, n); + qunlock(&cp->buflock); + error(Egreg); + } + memmove(buf, cp->buf, m); + qunlock(&cp->buflock); + } + return m; + } + print("devcyc read unk\n"); + error(Egreg); + return 0; +} + +long +cycwrite(Chan *c, void *buf, long n, ulong offset) +{ + User *pu; + Commcyc *cp; + Cycmsg *mp, **cmp; + + cp = &cyclone[c->dev]; + switch(c->qid.path & ~CHDIR){ + case Qdir: + return devdirread(c, buf, n, cycdir, NCYCDIR, devgen); + + case Qcyc: + if(n > sizeof cp->buf){ + print("cyclone write bufsize\n"); + error(Egreg); + } + pu = (User*)(u->p->upage->pa|KZERO); + if((((ulong)buf)&(KSEGM|3)) == KSEG0){ + /* + * use supplied buffer, no need to lock for reply + */ + mp = &pu->kcyc; + + mp->cmd = Uwrite; + mp->param[0] = MP2VME(buf); + mp->param[1] = n; + mp->param[2] = 0; + + cmp = cycsend(cp, mp); + cycwait(cmp); + }else{ + /* + * use cyclone buffer. lock the buffer until the reply + */ + mp = &pu->ucyc; + qlock(&cp->buflock); + memmove(cp->buf, buf, n); + + mp->cmd = Uwrite; + mp->param[0] = MP2VME(cp->buf); + mp->param[1] = n; + mp->param[2] = 0; + + cmp = cycsend(cp, mp); + cycwait(cmp); + qunlock(&cp->buflock); + } + return n; + } + print("cyclone write unk\n"); + error(Egreg); + return 0; +} + +void +cycremove(Chan *c) +{ + USED(c); + error(Eperm); +} + +void +cycwstat(Chan *c, char *dp) +{ + USED(c, dp); + error(Eperm); +} + +void +cycintr(int vec) +{ + Cycmsg *cm; + Commcyc *h; + ulong l, n, *r; + + h = &cyclone[vec - Vmevec]; + if(h&cyclone[Ncyc]){ + print("bad cyclone vec\n"); + return; + } + + r = h->addr->replyq; + + for(;;) { + l = r[h->ri]; + if(l == 0) + break; + + r[h->ri++] = 0; + if(h->ri >= NRQ) + h->ri = 0; + + cm = (Cycmsg*)VME2MP(l); + cm->intr = 1; + n = cm->param[3]; + if(n==0 || n > 10000) + print("cycintr count 0x%lux\n", n); + + wakeup(&cm->r); + } +} diff --git a/power/devhotrod.c b/power/devhotrod.c deleted file mode 100644 index 725151084d39c165d7479a52b122bd37afb92c45..0000000000000000000000000000000000000000 --- a/power/devhotrod.c +++ /dev/null @@ -1,433 +0,0 @@ -#define BITBOTCH 256 /* remove with BIT3 */ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "../port/error.h" -#include "devtab.h" -#include "fcall.h" - -#include "io.h" -#include "../../fs/cyc/comm.h" - - -typedef struct Commrod Commrod; - -enum -{ - Vmevec= 0xd2, /* vme vector for interrupts */ - Intlevel= 5, /* level to interrupt on */ - Qdir= 0, /* Qid's */ - Qhotrod= 1, - Nhotrod= 1, -}; - -Dirtab hotroddir[]={ - "hotrod", {Qhotrod}, 0, 0600, -}; - -#define NHOTRODDIR (sizeof hotroddir/sizeof(Dirtab)) - -struct Commrod -{ - Lock; - QLock buflock; - Lock busy; - Comm *addr; /* address of the device */ - int vec; /* vme interrupt vector */ - int wi; /* where to write next cmd */ - int ri; /* where to read next reply */ - uchar buf[MAXFDATA+MAXMSG+BITBOTCH]; -}; - -Commrod hotrod[Nhotrod]; - -void hotrodintr(int); - -#define HOTROD VMEA24SUP(Comm, 0x10000); - -/* - * Commands - */ - -Hotmsg** -hotsend(Commrod *h, Hotmsg *m) -{ - Hotmsg **mp; -int i; - - lock(h); - mp = (Hotmsg**)&h->addr->reqstq[h->wi]; - *mp = (Hotmsg*)MP2VME(m); - h->wi++; - if(h->wi >= NRQ) - h->wi = 0; - unlock(h); - return mp; -} - -void -hotwait(Hotmsg **mp) -{ - ulong l; - - l = 0; - while(*mp){ - delay(0); /* just a subroutine call; stay off VME */ - if(++l > 10*1000*1000){ - l = 0; - panic("hotsend blocked"); - } - } - return; -} - -/* - * reset all hotrod boards - */ -void -hotrodreset(void) -{ - int i; - Commrod *hp; - - for(hp=hotrod,i=0; iaddr = HOTROD+i; - /* - * Write queue is at end of hotrod memory - */ - hp->vec = Vmevec+i; - setvmevec(hp->vec, hotrodintr); - } -} - -void -hotrodinit(void) -{ -} - -/* - * enable the device for interrupts, spec is the device number - */ -Chan* -hotrodattach(char *spec) -{ - Commrod *hp; - int i; - Chan *c; - - i = strtoul(spec, 0, 0); - if(i >= Nhotrod) - error(Ebadarg); - - c = devattach('H', spec); - c->dev = i; - c->qid.path = CHDIR; - c->qid.vers = 0; - return c; -} - -Chan* -hotrodclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int -hotrodwalk(Chan *c, char *name) -{ - return devwalk(c, name, hotroddir, NHOTRODDIR, devgen); -} - -void -hotrodstat(Chan *c, char *dp) -{ - devstat(c, dp, hotroddir, NHOTRODDIR, devgen); -} - -Chan* -hotrodopen(Chan *c, int omode) -{ - Commrod *hp; - Hotmsg *mp, **hmp; - - if(c->qid.path == CHDIR){ - if(omode != OREAD) - error(Eperm); - }else if(c->qid.path == Qhotrod){ - hp = &hotrod[c->dev]; - if(!canlock(&hp->busy)) - error(Einuse); - /* - * Clear communications region - */ - memset(hp->addr->reqstq, 0, NRQ*sizeof(ulong)); - hp->addr->reqstp = 0; - memset(hp->addr->replyq, 0, NRQ*sizeof(ulong)); - hp->addr->replyp = 0; - - /* - * Issue reset - */ - hp->wi = 0; - hp->ri = 0; - mp = &u->khot; - mp->cmd = Ureset; - hmp = hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->khot); - hotwait(hmp); - delay(100); - print("reset\n"); - } - c->mode = openmode(omode); - c->flag |= COPEN; - c->offset = 0; - return c; -} - -void -hotrodcreate(Chan *c, char *name, int omode, ulong perm) -{ - USED(c, name, omode, perm); - error(Eperm); -} - -void -hotrodclose(Chan *c) -{ - Commrod *hp; - Hotmsg **hmp; - - hp = &hotrod[c->dev]; - if(c->qid.path != CHDIR){ - u->khot.cmd = Ureboot; - hmp = hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->khot); - hotwait(hmp); - unlock(&hp->busy); - } -} - -ulong -hotsum(ulong *p, int n, ulong doit) -{ - ulong sum; - - if(!doit) - return 0; - sum = 0; - n = (n+sizeof(ulong)-1)/sizeof(ulong); - while(--n >= 0) - sum += *p++; - return sum; -} - -int -hotmsgintr(Hotmsg *hm) -{ - return hm->intr; -} - -/* - * Read and write use physical addresses if they can, which they usually can. - * Most I/O is from devmnt, which has local buffers. Therefore just check - * that buf is in KSEG0 and is at an even address. - */ - -long -hotrodread(Chan *c, void *buf, long n, ulong offset) -{ - Commrod *hp; - Hotmsg *mp, **hmp; - ulong l, m, isflush; - - hp = &hotrod[c->dev]; - switch(c->qid.path & ~CHDIR){ - case Qdir: - return devdirread(c, buf, n, hotroddir, NHOTRODDIR, devgen); - - case Qhotrod: - if(n > sizeof hp->buf){ - print("hotrod bufsize %d %d\n", n, sizeof hp->buf); - error(Egreg); - } - if((((ulong)buf)&(KSEGM|3)) == KSEG0){ - /* - * use supplied buffer, no need to lock for reply - */ - isflush = 0; - mp = &((User*)(u->p->upage->pa|KZERO))->khot; - if(mp->abort){ /* use reserved flush msg */ - mp = &((User*)(u->p->upage->pa|KZERO))->fhot; - isflush = 1; - } - mp->param[2] = 0; /* reply checksum */ - mp->param[3] = 0xDEADBEEF; /* reply count */ - mp->cmd = Uread; - mp->param[0] = MP2VME(buf); - mp->param[1] = n; - mp->abort = isflush; - mp->intr = 0; - hmp = hotsend(hp, mp); - if(isflush){ /* busy loop */ - l = 100*1000*1000; - do - m = mp->param[3]; - while(m==0 && --l>0); - print("isflush blocked\n"); - }else{ - if(waserror()){ - if(*hmp && *hmp==mp) - hotwait(hmp); - mp->abort = 1; - nexterror(); - } - sleep(&mp->r, hotmsgintr, mp); - m = mp->param[3]; - } - if(m==0 || m>n){ - print("devhotrod: count 0x%lux 0x%lux\n", m, n); - error(Egreg); - } - if(mp->param[2] != hotsum(buf, m, mp->param[2])){ - print("hotrod cksum err is %lux sb %lux\n", - hotsum(buf, m, 1), mp->param[2]); - error(Eio); - } - mp->abort = 0; - if(isflush) - u->khot.abort = 0; /* flushed message's done too */ - else - poperror(); - }else{ - /* - * use hotrod buffer. lock the buffer until the reply - */ - mp = &((User*)(u->p->upage->pa|KZERO))->uhot; - mp->param[2] = 0; /* reply checksum */ - mp->param[3] = 0; /* reply count */ - qlock(&hp->buflock); - mp->cmd = Uread; - mp->param[0] = MP2VME(hp->buf); - mp->param[1] = n; - mp->abort = 1; - mp->intr = 0; - hmp = hotsend(hp, mp); - hotwait(hmp); - l = 100*1000*1000; - do - m = mp->param[3]; - while(m==0 && --l>0); - if(m==0 || m>n){ - print("devhotrod: count %ld %ld\n", m, n); - qunlock(&hp->buflock); - error(Egreg); - } - if(mp->param[2] != hotsum((ulong*)hp->buf, m, mp->param[2])){ - print("hotrod cksum err is %lux sb %lux\n", - hotsum((ulong*)hp->buf, m, 1), mp->param[2]); - qunlock(&hp->buflock); - error(Eio); - } - memmove(buf, hp->buf, m); - mp->abort = 0; - qunlock(&hp->buflock); - } - return m; - } - print("hotrod read unk\n"); - error(Egreg); - return 0; -} - -long -hotrodwrite(Chan *c, void *buf, long n, ulong offset) -{ - Commrod *hp; - Hotmsg *mp, **hmp; - - hp = &hotrod[c->dev]; - switch(c->qid.path & ~CHDIR){ - case Qdir: - return devdirread(c, buf, n, hotroddir, NHOTRODDIR, devgen); - - case Qhotrod: - if(n > sizeof hp->buf){ - print("hotrod write bufsize\n"); - error(Egreg); - } - if((((ulong)buf)&(KSEGM|3)) == KSEG0){ - /* - * use supplied buffer, no need to lock for reply - */ - mp = &((User*)(u->p->upage->pa|KZERO))->khot; - mp->wlen = n; - if(mp->abort) /* use reserved flush msg */ - mp = &((User*)(u->p->upage->pa|KZERO))->fhot; - mp->cmd = Uwrite; - mp->param[0] = MP2VME(buf); - mp->param[1] = n; - mp->param[2] = 0; - hmp = hotsend(hp, mp); - hotwait(hmp); - }else{ - /* - * use hotrod buffer. lock the buffer until the reply - */ - mp = &((User*)(u->p->upage->pa|KZERO))->uhot; - mp->wlen = n; - qlock(&hp->buflock); - memmove(hp->buf, buf, n); - mp->cmd = Uwrite; - mp->param[0] = MP2VME(hp->buf); - mp->param[1] = n; - mp->param[2] = 0; - hmp = hotsend(hp, mp); - hotwait(hmp); - qunlock(&hp->buflock); - } - return n; - } - print("hotrod write unk\n"); - error(Egreg); - return 0; -} - -void -hotrodremove(Chan *c) -{ - USED(c); - error(Eperm); -} - -void -hotrodwstat(Chan *c, char *dp) -{ - USED(c, dp); - error(Eperm); -} - -void -hotrodintr(int vec) -{ - Commrod *h; - Hotmsg *hm; - ulong l; - - h = &hotrod[vec - Vmevec]; - if(h&hotrod[Nhotrod]){ - print("bad hotrod vec\n"); - return; - } - while(l = h->addr->replyq[h->ri]){ /* assign = */ - hm = (Hotmsg*)(VME2MP(l)); - h->addr->replyq[h->ri] = 0; - h->ri++; - if(h->ri >= NRQ) - h->ri = 0; - hm->intr = 1; - if(hm->param[3]==0 || hm->param[3] > 10000) - print("hotrodintr count 0x%lux\n", hm->param[3]); - if(!hm->abort) - wakeup(&hm->r); - } -}