| plan 9 kernel history: overview | file list | diff list |
1992/0508/power/devhotrod.c (diff list | history)
| 1992/0508/sys/src/9/power/devhotrod.c:1,433 – 1992/0609/sys/src/9/power/devhotrod.c:1,430 (short | long | prev | next) | ||
| 1991/1003 | #define BITBOTCH 256 /* remove with BIT3 */ | |
| 1990/1013 | #include "u.h" | |
| 1992/0321 | #include "../port/lib.h" | |
| 1990/1013 | #include "mem.h" #include "dat.h" #include "fns.h" | |
| 1992/0111 | #include "../port/error.h" | |
| 1990/1013 | #include "devtab.h" | |
| 1991/0212 | #include "fcall.h" | |
| 1990/1013 | #include "io.h" | |
| 1992/0229 | #include "../../fs/cyc/comm.h" | |
| 1990/1013 | ||
| 1991/0303 | ||
| 1992/0229 | typedef struct Commrod Commrod; | |
| 1990/1013 | ||
| 1992/0306 | enum { | |
| 1990/1013 | Vmevec= 0xd2, /* vme vector for interrupts */ Intlevel= 5, /* level to interrupt on */ | |
| 1991/0209 | Qdir= 0, /* Qid's */ Qhotrod= 1, Nhotrod= 1, | |
| 1990/1013 | }; | |
| 1991/0307 | Dirtab hotroddir[]={ "hotrod", {Qhotrod}, 0, 0600, }; #define NHOTRODDIR (sizeof hotroddir/sizeof(Dirtab)) | |
| 1992/0229 | struct Commrod { | |
| 1991/0403 | Lock; | |
| 1991/0212 | QLock buflock; | |
| 1991/0209 | Lock busy; | |
| 1992/0229 | Comm *addr; /* address of the device */ | |
| 1990/1106 | int vec; /* vme interrupt vector */ | |
| 1991/0209 | int wi; /* where to write next cmd */ | |
| 1991/0401 | int ri; /* where to read next reply */ | |
| 1991/1003 | uchar buf[MAXFDATA+MAXMSG+BITBOTCH]; | |
| 1990/1013 | }; | |
| 1992/0229 | Commrod hotrod[Nhotrod]; | |
| 1990/1013 | ||
| 1990/1106 | void hotrodintr(int); | |
| 1990/1013 | ||
| 1992/0229 | #define HOTROD VMEA24SUP(Comm, 0x10000); | |
| 1991/0215 | ||
| 1991/0209 | /* * Commands */ | |
| 1991/0403 | Hotmsg** | |
| 1992/0229 | hotsend(Commrod *h, Hotmsg *m) | |
| 1990/1013 | { | |
| 1991/0304 | Hotmsg **mp; | |
| 1992/0428 | int i; | |
| 1991/0304 | ||
| 1991/0403 | lock(h); | |
| 1991/0401 | mp = (Hotmsg**)&h->addr->reqstq[h->wi]; | |
| 1991/0304 | *mp = (Hotmsg*)MP2VME(m); | |
| 1991/0209 | h->wi++; | |
| 1991/0306 | if(h->wi >= NRQ) | |
| 1991/0209 | h->wi = 0; | |
| 1991/0403 | unlock(h); return mp; } void hotwait(Hotmsg **mp) { ulong l; | |
| 1991/0304 | l = 0; while(*mp){ delay(0); /* just a subroutine call; stay off VME */ | |
| 1992/0609 | if(++l > 10*1000*1000){ | |
| 1991/0304 | l = 0; | |
| 1992/0609 | panic("hotsend blocked"); | |
| 1991/0304 | } } | |
| 1991/0403 | return; | |
| 1990/1013 | } /* * reset all hotrod boards */ void hotrodreset(void) { int i; | |
| 1992/0229 | Commrod *hp; | |
| 1990/1013 | ||
| 1991/0209 | for(hp=hotrod,i=0; i<Nhotrod; i++,hp++){ hp->addr = HOTROD+i; /* * Write queue is at end of hotrod memory */ hp->vec = Vmevec+i; setvmevec(hp->vec, hotrodintr); | |
| 1990/1013 | } } void hotrodinit(void) { } /* * enable the device for interrupts, spec is the device number */ Chan* hotrodattach(char *spec) { | |
| 1992/0229 | Commrod *hp; | |
| 1990/1013 | int i; Chan *c; i = strtoul(spec, 0, 0); if(i >= Nhotrod) | |
| 1990/11211 | error(Ebadarg); | |
| 1990/1013 | c = devattach('H', spec); c->dev = i; | |
| 1990/11211 | c->qid.path = CHDIR; c->qid.vers = 0; | |
| 1990/1013 | return c; } Chan* hotrodclone(Chan *c, Chan *nc) { return devclone(c, nc); } int hotrodwalk(Chan *c, char *name) { | |
| 1991/0307 | return devwalk(c, name, hotroddir, NHOTRODDIR, devgen); | |
| 1990/1013 | } void hotrodstat(Chan *c, char *dp) { | |
| 1991/0307 | devstat(c, dp, hotroddir, NHOTRODDIR, devgen); | |
| 1990/1013 | } Chan* hotrodopen(Chan *c, int omode) { | |
| 1992/0229 | Commrod *hp; | |
| 1991/0403 | Hotmsg *mp, **hmp; | |
| 1990/1106 | ||
| 1990/11211 | if(c->qid.path == CHDIR){ | |
| 1990/1013 | if(omode != OREAD) | |
| 1990/11211 | error(Eperm); | |
| 1991/0209 | }else if(c->qid.path == Qhotrod){ hp = &hotrod[c->dev]; if(!canlock(&hp->busy)) error(Einuse); /* * Clear communications region */ | |
| 1991/0401 | memset(hp->addr->reqstq, 0, NRQ*sizeof(ulong)); hp->addr->reqstp = 0; memset(hp->addr->replyq, 0, NRQ*sizeof(ulong)); hp->addr->replyp = 0; | |
| 1991/0209 | /* * Issue reset */ hp->wi = 0; hp->ri = 0; | |
| 1991/0212 | mp = &u->khot; | |
| 1991/0307 | mp->cmd = Ureset; | |
| 1991/0403 | hmp = hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->khot); hotwait(hmp); | |
| 1991/0215 | delay(100); | |
| 1991/0214 | print("reset\n"); | |
| 1990/1018 | } | |
| 1990/1013 | c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } void hotrodcreate(Chan *c, char *name, int omode, ulong perm) { | |
| 1991/1216 | USED(c, name, omode, perm); | |
| 1990/11211 | error(Eperm); | |
| 1990/1013 | } void hotrodclose(Chan *c) { | |
| 1992/0229 | Commrod *hp; | |
| 1991/0403 | Hotmsg **hmp; | |
| 1991/0209 | hp = &hotrod[c->dev]; if(c->qid.path != CHDIR){ | |
| 1991/0307 | u->khot.cmd = Ureboot; | |
| 1991/0403 | hmp = hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->khot); hotwait(hmp); | |
| 1991/0209 | unlock(&hp->busy); } | |
| 1990/1013 | } | |
| 1991/0303 | 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; } | |
| 1991/0306 | int hotmsgintr(Hotmsg *hm) { return hm->intr; } | |
| 1990/1013 | /* | |
| 1991/0212 | * 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. | |
| 1990/1013 | */ | |
| 1991/0212 | ||
| 1990/1013 | long | |
| 1991/0411 | hotrodread(Chan *c, void *buf, long n, ulong offset) | |
| 1990/1013 | { | |
| 1992/0229 | Commrod *hp; | |
| 1991/0403 | Hotmsg *mp, **hmp; | |
| 1991/0306 | ulong l, m, isflush; | |
| 1990/1013 | hp = &hotrod[c->dev]; | |
| 1991/0307 | switch(c->qid.path & ~CHDIR){ case Qdir: return devdirread(c, buf, n, hotroddir, NHOTRODDIR, devgen); | |
| 1991/0212 | case Qhotrod: | |
| 1991/0220 | if(n > sizeof hp->buf){ | |
| 1991/1003 | print("hotrod bufsize %d %d\n", n, sizeof hp->buf); | |
| 1991/0212 | error(Egreg); | |
| 1991/0220 | } | |
| 1991/0212 | if((((ulong)buf)&(KSEGM|3)) == KSEG0){ /* * use supplied buffer, no need to lock for reply */ | |
| 1991/0306 | 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; } | |
| 1991/0307 | mp->param[2] = 0; /* reply checksum */ | |
| 1991/0303 | mp->param[3] = 0; /* reply count */ | |
| 1991/0307 | mp->cmd = Uread; | |
| 1991/0212 | mp->param[0] = MP2VME(buf); mp->param[1] = n; | |
| 1991/0306 | mp->abort = isflush; mp->intr = 0; | |
| 1991/0403 | hmp = hotsend(hp, mp); | |
| 1991/0306 | if(isflush){ /* busy loop */ l = 100*1000*1000; do m = mp->param[3]; while(m==0 && --l>0); }else{ if(waserror()){ | |
| 1991/0403 | if(*hmp && *hmp==mp) hotwait(hmp); | |
| 1991/0306 | mp->abort = 1; nexterror(); } sleep(&mp->r, hotmsgintr, mp); | |
| 1991/0303 | m = mp->param[3]; | |
| 1991/0306 | } | |
| 1991/0303 | if(m==0 || m>n){ print("devhotrod: count %ld %ld\n", m, n); | |
| 1991/0215 | error(Egreg); } | |
| 1991/0303 | if(mp->param[2] != hotsum(buf, m, mp->param[2])){ print("hotrod cksum err is %lux sb %lux\n", | |
| 1991/0402 | hotsum(buf, m, 1), mp->param[2]); | |
| 1991/0303 | error(Eio); } | |
| 1991/0402 | mp->abort = 0; if(isflush) u->khot.abort = 0; /* flushed message's done too */ else | |
| 1991/0306 | poperror(); | |
| 1991/0212 | }else{ /* | |
| 1991/0306 | * use hotrod buffer. lock the buffer until the reply | |
| 1991/0212 | */ | |
| 1991/0306 | mp = &((User*)(u->p->upage->pa|KZERO))->uhot; | |
| 1991/0307 | mp->param[2] = 0; /* reply checksum */ | |
| 1991/0303 | mp->param[3] = 0; /* reply count */ | |
| 1991/0212 | qlock(&hp->buflock); | |
| 1991/0307 | mp->cmd = Uread; | |
| 1991/0212 | mp->param[0] = MP2VME(hp->buf); mp->param[1] = n; | |
| 1991/0306 | mp->abort = 1; mp->intr = 0; | |
| 1991/0403 | hmp = hotsend(hp, mp); hotwait(hmp); | |
| 1991/0215 | l = 100*1000*1000; | |
| 1991/0212 | do | |
| 1991/0303 | 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); | |
| 1991/0215 | error(Egreg); } | |
| 1991/0303 | if(mp->param[2] != hotsum((ulong*)hp->buf, m, mp->param[2])){ print("hotrod cksum err is %lux sb %lux\n", | |
| 1991/0402 | hotsum((ulong*)hp->buf, m, 1), mp->param[2]); | |
| 1991/0303 | qunlock(&hp->buflock); error(Eio); } | |
| 1991/0318 | memmove(buf, hp->buf, m); | |
| 1991/0402 | mp->abort = 0; | |
| 1991/0303 | qunlock(&hp->buflock); | |
| 1991/0212 | } | |
| 1991/0303 | return m; | |
| 1990/1020 | } | |
| 1991/0220 | print("hotrod read unk\n"); | |
| 1991/0212 | error(Egreg); return 0; | |
| 1990/1013 | } long | |
| 1991/0411 | hotrodwrite(Chan *c, void *buf, long n, ulong offset) | |
| 1990/1013 | { | |
| 1992/0229 | Commrod *hp; | |
| 1991/0403 | Hotmsg *mp, **hmp; | |
| 1990/1013 | hp = &hotrod[c->dev]; | |
| 1991/0307 | switch(c->qid.path & ~CHDIR){ case Qdir: return devdirread(c, buf, n, hotroddir, NHOTRODDIR, devgen); case Qhotrod: | |
| 1991/0220 | if(n > sizeof hp->buf){ print("hotrod write bufsize\n"); | |
| 1991/0212 | error(Egreg); | |
| 1991/0220 | } | |
| 1991/0212 | if((((ulong)buf)&(KSEGM|3)) == KSEG0){ /* | |
| 1991/0306 | * use supplied buffer, no need to lock for reply | |
| 1991/0212 | */ | |
| 1991/0306 | mp = &((User*)(u->p->upage->pa|KZERO))->khot; | |
| 1991/0403 | mp->wlen = n; | |
| 1991/0306 | if(mp->abort) /* use reserved flush msg */ mp = &((User*)(u->p->upage->pa|KZERO))->fhot; | |
| 1991/0307 | mp->cmd = Uwrite; | |
| 1991/0212 | mp->param[0] = MP2VME(buf); mp->param[1] = n; | |
| 1992/0306 | mp->param[2] = 0; | |
| 1991/0403 | hmp = hotsend(hp, mp); hotwait(hmp); | |
| 1991/0212 | }else{ /* | |
| 1991/0306 | * use hotrod buffer. lock the buffer until the reply | |
| 1991/0212 | */ | |
| 1991/0306 | mp = &((User*)(u->p->upage->pa|KZERO))->uhot; | |
| 1991/0403 | mp->wlen = n; | |
| 1991/0212 | qlock(&hp->buflock); | |
| 1991/0318 | memmove(hp->buf, buf, n); | |
| 1991/0307 | mp->cmd = Uwrite; | |
| 1991/0212 | mp->param[0] = MP2VME(hp->buf); mp->param[1] = n; | |
| 1992/0306 | mp->param[2] = 0; | |
| 1991/0403 | hmp = hotsend(hp, mp); hotwait(hmp); | |
| 1991/0212 | qunlock(&hp->buflock); } return n; } | |
| 1991/0220 | print("hotrod write unk\n"); | |
| 1991/0212 | error(Egreg); return 0; | |
| 1990/1013 | } void hotrodremove(Chan *c) { | |
| 1991/1216 | USED(c); | |
| 1990/11211 | error(Eperm); | |
| 1990/1013 | } void hotrodwstat(Chan *c, char *dp) { | |
| 1991/1216 | USED(c, dp); | |
| 1990/11211 | error(Eperm); | |
| 1990/1013 | } | |
| 1990/1106 | void | |
| 1990/1013 | hotrodintr(int vec) { | |
| 1992/0229 | Commrod *h; | |
| 1991/0306 | Hotmsg *hm; | |
| 1991/0326 | ulong l; | |
| 1990/1013 | ||
| 1992/0508 |
| |
| 1991/0306 | h = &hotrod[vec - Vmevec]; | |
| 1991/0326 | if(h<hotrod || h>&hotrod[Nhotrod]){ | |
| 1990/1013 | print("bad hotrod vec\n"); | |
| 1992/0508 |
| |
| 1990/1013 | return; } | |
| 1991/0401 | while(l = h->addr->replyq[h->ri]){ /* assign = */ | |
| 1991/0326 | hm = (Hotmsg*)(VME2MP(l)); | |
| 1991/0401 | h->addr->replyq[h->ri] = 0; | |
| 1991/0326 | h->ri++; if(h->ri >= NRQ) h->ri = 0; hm->intr = 1; | |
| 1992/0317 | if(!hm->abort) | |
| 1991/0326 | wakeup(&hm->r); } | |
| 1992/0508 |
| |
| 1991/0303 | } | |