| plan 9 kernel history: overview | file list | diff list |
1991/0304/power/devhotrod.c (diff list | history)
| power/devhotrod.c on 1990/1013 | ||
| 1990/1013 | #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "errno.h" #include "devtab.h" | |
| 1991/0212 | #include "fcall.h" | |
| 1990/1013 | #include "io.h" | |
| 1991/0215 | #include "hrod.h" | |
| 1990/1013 | ||
| 1991/0303 | void mem(Hot*, ulong*, ulong); /* * If set, causes data transfers to have checksums */ | |
| 1991/0304 | #define ENABCKSUM 0 | |
| 1991/0303 | ||
| 1990/1013 | typedef struct Hotrod Hotrod; | |
| 1991/0209 | typedef struct HotQ HotQ; | |
| 1990/1013 | enum { Vmevec= 0xd2, /* vme vector for interrupts */ Intlevel= 5, /* level to interrupt on */ | |
| 1991/0209 | Qdir= 0, /* Qid's */ Qhotrod= 1, | |
| 1991/0215 | NhotQ= NRQ, /* size of communication queues */ | |
| 1991/0209 | Nhotrod= 1, | |
| 1990/1013 | }; | |
| 1991/0209 | struct HotQ{ ulong i; /* index into queue */ Hotmsg *msg[NhotQ]; /* pointer to command buffer */ ulong pad[3]; /* unused; for hotrod prints */ }; | |
| 1990/1013 | ||
| 1991/0209 | struct Hotrod{ QLock; | |
| 1991/0212 | QLock buflock; | |
| 1991/0209 | Lock busy; | |
| 1991/0215 | Hot *addr; /* address of the device */ | |
| 1990/1106 | int vec; /* vme interrupt vector */ | |
| 1991/0209 | HotQ *wq; /* write this queue to send cmds */ int wi; /* where to write next cmd */ HotQ rq; /* read this queue to receive replies */ int ri; /* where to read next response */ | |
| 1990/1106 | Rendez r; | |
| 1991/0220 | uchar buf[MAXFDATA+MAXMSG]; | |
| 1990/1013 | }; Hotrod hotrod[Nhotrod]; | |
| 1990/1106 | void hotrodintr(int); | |
| 1990/1013 | ||
| 1991/0215 | #define HOTROD VMEA24SUP(Hot, 0xB00000); | |
| 1991/0209 | /* * Commands */ enum{ RESET= 0, /* params: Q address, length of queue */ REBOOT= 1, /* params: none */ | |
| 1991/0303 | READ= 2, /* params: buffer, count, sum, returned count */ WRITE= 3, /* params: buffer, count, sum */ | |
| 1991/0214 | TEST= 7, /* params: none */ | |
| 1991/0209 | }; void hotsend(Hotrod *h, Hotmsg *m) | |
| 1990/1013 | { | |
| 1991/0304 | Hotmsg **mp; long l; | |
| 1991/0220 | /* print("hotsend send %d %d %lux %lux\n", h->wi, m->cmd, m, m->param[0]); /**/ | |
| 1991/0304 | mp = &h->wq->msg[h->wi]; *mp = (Hotmsg*)MP2VME(m); | |
| 1991/0209 | h->wi++; if(h->wi >= NhotQ) h->wi = 0; | |
| 1991/0304 | l = 0; while(*mp){ delay(0); /* just a subroutine call; stay off VME */ if(++l > 1000*1000){ l = 0; print("hotsend blocked\n"); } } | |
| 1990/1013 | } /* * reset all hotrod boards */ void hotrodreset(void) { int i; | |
| 1990/1018 | Hotrod *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 */ | |
| 1991/0215 | hp->wq = (HotQ*)(&hp->addr->hostrp); | |
| 1991/0209 | hp->vec = Vmevec+i; setvmevec(hp->vec, hotrodintr); | |
| 1990/1013 | } wbflush(); delay(20); } void hotrodinit(void) { } /* * enable the device for interrupts, spec is the device number */ Chan* hotrodattach(char *spec) { | |
| 1990/1106 | Hotrod *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/0209 | if(c->qid.path != CHDIR) return 0; if(strncmp(name, "hotrod", 6) == 0){ c->qid.path = Qhotrod; return 1; } return 0; | |
| 1990/1013 | } void hotrodstat(Chan *c, char *dp) { | |
| 1991/0209 | print("hotrodstat\n"); error(Egreg); | |
| 1990/1013 | } | |
| 1991/0227 | #define NTESTBUF 256 ulong testbuf[NTESTBUF]; | |
| 1990/1013 | Chan* hotrodopen(Chan *c, int omode) { | |
| 1990/1106 | Hotrod *hp; | |
| 1991/0212 | Hotmsg *mp; | |
| 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 */ memset(hp->wq->msg, 0, sizeof(hp->wq->msg)); hp->wq->i = 0; /* * Issue reset */ hp->wi = 0; hp->ri = 0; | |
| 1991/0212 | mp = &u->khot; mp->cmd = RESET; mp->param[0] = MP2VME(&hp->rq); mp->param[1] = NhotQ; | |
| 1991/0209 | hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->khot); | |
| 1991/0215 | delay(100); | |
| 1991/0214 | print("reset\n"); | |
| 1991/0219 | ||
| 1991/0302 | #ifdef asdf | |
| 1991/0219 | /* * Issue test */ mp = &u->khot; mp->cmd = TEST; | |
| 1991/0227 | mp->param[0] = MP2VME(testbuf); mp->param[1] = NTESTBUF; | |
| 1991/0219 | hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->khot); delay(100); | |
| 1991/0303 | print("testing addr %lux size %ld\n", mp->param[0], mp->param[1]); for(;;){ print("-"); mem(hp->addr, &hp->addr->ram[(mp->param[0]-0x40000)/sizeof(ulong)], mp->param[1]); } | |
| 1991/0302 | #endif | |
| 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) { | |
| 1990/11211 | error(Eperm); | |
| 1990/1013 | } void hotrodclose(Chan *c) { | |
| 1991/0209 | Hotrod *hp; hp = &hotrod[c->dev]; if(c->qid.path != CHDIR){ u->khot.cmd = REBOOT; hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->khot); 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; } | |
| 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 hotrodread(Chan *c, void *buf, long n) { Hotrod *hp; | |
| 1991/0212 | Hotmsg *mp; | |
| 1991/0303 | ulong l, m; | |
| 1990/1013 | hp = &hotrod[c->dev]; | |
| 1991/0212 | switch(c->qid.path){ case Qhotrod: | |
| 1991/0220 | if(n > sizeof hp->buf){ print("hotrod bufsize\n"); | |
| 1991/0212 | error(Egreg); | |
| 1991/0220 | } | |
| 1991/0212 | if((((ulong)buf)&(KSEGM|3)) == KSEG0){ /* * use supplied buffer, no need to lock for reply */ mp = &u->khot; | |
| 1991/0303 | mp->param[2] = 0; /* checksum */ mp->param[3] = 0; /* reply count */ | |
| 1991/0212 | qlock(hp); mp->cmd = READ; mp->param[0] = MP2VME(buf); mp->param[1] = n; hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->khot); qunlock(hp); | |
| 1991/0220 | 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); | |
| 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", hotsum(buf, n, 1), mp->param[2]); error(Eio); } | |
| 1991/0212 | }else{ /* | |
| 1991/0215 | * use hotrod buffer. lock the buffer until the reply | |
| 1991/0212 | */ mp = &u->uhot; | |
| 1991/0303 | mp->param[2] = 0; /* checksum */ mp->param[3] = 0; /* reply count */ | |
| 1991/0212 | qlock(&hp->buflock); qlock(hp); mp->cmd = READ; mp->param[0] = MP2VME(hp->buf); mp->param[1] = n; hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->uhot); qunlock(hp); | |
| 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", hotsum((ulong*)hp->buf, n, 1), mp->param[2]); qunlock(&hp->buflock); error(Eio); } memcpy(buf, hp->buf, m); 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 | } /* * write hotrod memory */ long hotrodwrite(Chan *c, void *buf, long n) { Hotrod *hp; | |
| 1991/0212 | Hotmsg *mp; | |
| 1990/1013 | hp = &hotrod[c->dev]; | |
| 1991/0212 | switch(c->qid.path){ case 1: | |
| 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){ /* * use supplied buffer, no need to lock for reply */ mp = &u->khot; qlock(hp); mp->cmd = WRITE; mp->param[0] = MP2VME(buf); mp->param[1] = n; | |
| 1991/0303 | mp->param[2] = hotsum(buf, n, ENABCKSUM); | |
| 1991/0212 | hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->khot); qunlock(hp); }else{ /* | |
| 1991/0304 | * use hotrod buffer. lock the buffer until the reply | |
| 1991/0212 | */ mp = &u->uhot; qlock(&hp->buflock); qlock(hp); memcpy(hp->buf, buf, n); mp->cmd = WRITE; mp->param[0] = MP2VME(hp->buf); mp->param[1] = n; | |
| 1991/0303 | mp->param[2] = hotsum((ulong*)hp->buf, n, ENABCKSUM); | |
| 1991/0212 | hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->uhot); qunlock(hp); qunlock(&hp->buflock); } return n; } | |
| 1991/0220 | print("hotrod write unk\n"); | |
| 1991/0212 | error(Egreg); return 0; | |
| 1990/1013 | } void hotrodremove(Chan *c) { | |
| 1990/11211 | error(Eperm); | |
| 1990/1013 | } void hotrodwstat(Chan *c, char *dp) { | |
| 1990/11211 | error(Eperm); | |
| 1990/1013 | } | |
| 1990/1106 | void | |
| 1990/1013 | hotrodintr(int vec) { Hotrod *hp; | |
| 1991/0220 | /* print("hotrod%d interrupt\n", vec - Vmevec); /**/ | |
| 1990/1013 | hp = &hotrod[vec - Vmevec]; if(hp < hotrod || hp > &hotrod[Nhotrod]){ print("bad hotrod vec\n"); return; } | |
| 1991/0219 | hp->addr->lcsr3 &= ~INT_VME; | |
| 1991/0303 | } void mem(Hot *hot, ulong *buf, ulong size) { long i, j, k, l; ulong *p, bit, u; int q; goto part4; /* one bit */ bit = 0; p = buf; for(i=0; i<size; i++,p++) { if(bit == 0) bit = 1; *p = bit; bit <<= 1; } bit = 0; p = buf; for(i=0; i<size; i++,p++) { if(bit == 0) bit = 1; if(*p != bit) { print("A: %lux is %lux sb %lux\n", p, *p, bit); hot->error++; delay(500); } bit <<= 1; } /* all but one bit */ bit = 0; p = buf; for(i=0; i<size; i++,p++) { if(bit == 0) bit = 1; *p = ~bit; bit <<= 1; } bit = 0; p = buf; for(i=0; i<size; i++,p++) { if(bit == 0) bit = 1; if(*p != ~bit) { print("B: %lux is %lux sb %lux\n", p, *p, ~bit); hot->error++; delay(500); } bit <<= 1; } /* rand bit */ bit = 0; p = buf; for(i=0; i<size; i++,p++) { if(bit == 0) bit = 1; *p = bit; bit += PRIME; } bit = 0; p = buf; for(i=0; i<size; i++,p++) { if(bit == 0) bit = 1; if(*p != bit) { print("C: %lux is %lux sb %lux\n", p, *p, bit); hot->error++; delay(500); } bit += PRIME; } part4: /* address */ p = buf; for(i=0; i<size; i++,p++) *p = i; for(j=0; j<200; j++) { p = buf; for(i=0; i<size; i++,p++) { u = *p; if(u != i+j) { print("D: %lux is %lux sb %lux (%lux)\n", p, u, i+j, *p); hot->error++; delay(500); } *p = i+j+1; } } | |
| 1990/1013 | } | |