plan 9 kernel history: overview | file list | diff list

1991/0402/power/devhotrod.c (diff list | history)

1991/0402/sys/src/9/power/devhotrod.c:1,5611991/0403/sys/src/9/power/devhotrod.c:1,573 (short | long | prev | next)
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/0306    
/* 
1991/0307    
 * If defined, ENABMEMTEST causes memory test to be run at device open 
1991/0306    
 */ 
#ifdef	ENABMEMTEST 
1991/0303    
void	mem(Hot*, ulong*, ulong); 
1991/0307    
#define	NTESTBUF	256 
ulong	testbuf[NTESTBUF]; 
1991/0306    
#endif 
1991/0328    
/* 
 * If defined, ENABBUSTEST causes bus error diagnostic to be run at device open 
 */ 
1991/0303    
 
/* 
1991/0307    
 * If 1, ENABCKSUM causes data transfers to have checksums 
1991/0303    
 */ 
1991/0402    
#define	ENABCKSUM	1 
1991/0403    
#define	ENABCKSUM	0 
1991/0303    
 
1990/1013    
typedef struct Hotrod	Hotrod; 
 
1991/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)) 
 
1991/0209    
struct Hotrod{ 
	QLock; 
1991/0403    
	Lock; 
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    
	int		wi;		/* where to write next cmd */ 
1991/0401    
	int		ri;		/* where to read next reply */ 
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 
 */ 
void 
1991/0403    
 
Hotmsg** 
1991/0209    
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/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 */ 
		if(++l > 1000*1000){ 
			l = 0; 
			print("hotsend blocked\n"); 
		} 
	} 
1991/0403    
	return; 
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 
		 */ 
		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) 
{ 
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/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) 
{ 
1990/1106    
	Hotrod *hp; 
1991/0212    
	Hotmsg *mp; 
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/0209    
		hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->khot); 
1991/0403    
		hmp = hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->khot); 
		hotwait(hmp); 
1991/0215    
		delay(100); 
1991/0214    
		print("reset\n"); 
1991/0219    
 
1991/0306    
#ifdef ENABMEMTEST 
1991/0219    
		/* 
		 * Issue test 
		 */ 
		mp = &u->khot; 
1991/0307    
		mp->cmd = Utest; 
1991/0227    
		mp->param[0] = MP2VME(testbuf); 
		mp->param[1] = NTESTBUF; 
1991/0219    
		hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->khot); 
1991/0403    
		hmp = hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->khot); 
		hotwait(hmp); 
1991/0219    
		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/0328    
#endif 
#ifdef ENABBUSTEST 
		/* 
		 * Issue test 
		 */ 
		mp = &u->khot; 
		mp->cmd = Ubus; 
		hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->khot); 
1991/0403    
		hmp = hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->khot, 0); 
		hotwait(hmp); 
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; 
1991/0403    
	Hotmsg **hmp; 
1991/0209    
 
	hp = &hotrod[c->dev]; 
	if(c->qid.path != CHDIR){ 
1991/0307    
		u->khot.cmd = Ureboot; 
1991/0209    
		hotsend(hp, &((User*)(u->p->upage->pa|KZERO))->khot); 
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	  
hotrodread(Chan *c, void *buf, long n) 
{ 
	Hotrod *hp; 
1991/0212    
	Hotmsg *mp; 
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){ 
			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 
			 */ 
1991/0306    
			isflush = 0; 
1991/0402    
memset(buf, 0, n); 
1991/0306    
			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/0212    
			qlock(hp); 
1991/0307    
			mp->cmd = Uread; 
1991/0212    
			mp->param[0] = MP2VME(buf); 
			mp->param[1] = n; 
1991/0306    
			mp->abort = isflush; 
			mp->intr = 0; 
			hotsend(hp, mp); 
1991/0212    
			qunlock(hp); 
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])){ 
1991/0307    
				hp->addr->error++; 
1991/0303    
				print("hotrod cksum err is %lux sb %lux\n", 
1991/0402    
					hotsum(buf, m, 1), mp->param[2]); 
1991/0403    
/* 
1991/0402    
				print("addr %lux\n", ((char*)buf)+m); 
				{ 
					int i; 
					ulong *p = buf; 
					for(i=2; i<m/4; i++) 
						if(p[i] != i-2) 
							print("%d sb %d %lux %lux\n", p[i], i-2, p[i], &p[i]); 
				} 
1991/0403    
*/ 
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); 
			qlock(hp); 
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; 
			hotsend(hp, mp); 
1991/0212    
			qunlock(hp); 
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])){ 
1991/0307    
				hp->addr->error++; 
1991/0303    
				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); 
1991/0307    
{int i; for(i=0; i<8; i++) print("%lux\n", ((ulong*)buf)[i]); } 
1991/0303    
				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	  
hotrodwrite(Chan *c, void *buf, long n) 
{ 
	Hotrod *hp; 
1991/0212    
	Hotmsg *mp; 
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/0402    
			mp->wtype = ((char*)buf)[0]; 
1991/0403    
			mp->wlen = n; 
1991/0306    
			if(mp->abort)	/* use reserved flush msg */ 
				mp = &((User*)(u->p->upage->pa|KZERO))->fhot; 
1991/0212    
			qlock(hp); 
1991/0307    
			mp->cmd = Uwrite; 
1991/0212    
			mp->param[0] = MP2VME(buf); 
			mp->param[1] = n; 
1991/0303    
			mp->param[2] = hotsum(buf, n, ENABCKSUM); 
1991/0306    
			hotsend(hp, mp); 
1991/0212    
			qunlock(hp); 
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/0402    
			mp->wtype = ((char*)buf)[0]; 
1991/0403    
			mp->wlen = n; 
1991/0212    
			qlock(&hp->buflock); 
			qlock(hp); 
1991/0318    
			memmove(hp->buf, buf, n); 
1991/0307    
			mp->cmd = Uwrite; 
1991/0212    
			mp->param[0] = MP2VME(hp->buf); 
			mp->param[1] = n; 
1991/0303    
			mp->param[2] = hotsum((ulong*)hp->buf, n, ENABCKSUM); 
1991/0306    
			hotsend(hp, mp); 
1991/0212    
			qunlock(hp); 
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) 
{ 
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) 
{ 
1991/0306    
	Hotrod *h; 
	Hotmsg *hm; 
1991/0326    
	ulong l; 
1990/1013    
 
1991/0306    
	h = &hotrod[vec - Vmevec]; 
1991/0326    
	if(h<hotrod || h>&hotrod[Nhotrod]){ 
1990/1013    
		print("bad hotrod vec\n"); 
		return; 
	} 
1991/0306    
	h->addr->lcsr3 &= ~INT_VME; 
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; 
		if(hm->abort) 
			print("abort wakeup\n"); 
		else 
			wakeup(&hm->r); 
	} 
1991/0303    
} 
 
1991/0306    
#ifdef	ENABMEMTEST 
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    
} 
1991/0306    
#endif 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)