~kris/9p

9hist

8c434f55d5ae88abd4ad1303c86bc013b574a1be — David du Colombier 34 years ago e2a008c
Plan 9 from Bell Labs 1992-06-12
5 files changed, 206 insertions(+), 533 deletions(-)

M port/malloc.c
M power/devhotrod.c
M power/devhs.c
M power/io.h
M power/trap.c
M port/malloc.c => port/malloc.c +61 -405
@@ 1,430 1,86 @@
/* compile-time features
   IALLOC use all blocks given to ifree, otherwise ignore unordered blocks
   MSTATS enable statistics 
   debug enable assertion checking
   longdebug full arena checks at every transaction
*/
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include <u.h>
#include <libc.h>

#define INT int
#define ALIGN int
#define NALIGN 1
#define WORD sizeof(union store)
#define BLOCK 4096
#define BUSY 1
#define NULL 0
#define testbusy(p) ((INT)(p)&BUSY)
#define setbusy(p) (union store *)((INT)(p)|BUSY)
#define clearbusy(p) (union store *)((INT)(p)&~BUSY)
#define IALLOC

typedef
union store
enum
{
	union store	*ptr;
	ALIGN	dummy[NALIGN];
	int	calloc;		/*calloc clears an array of integers*/
} Store;

static	int	draincache(void);
static	void*	stdmalloc(long);
static	int	stdfree(Store*);
static	void	ifree(char*, long);
	MAGIC		= 0xDEADBABE,
	MAX2SIZE	= 20
};

#ifdef longdebug
#define debug 1
#endif
#ifdef debug
#define ASSERT(p) if(!(p))botch("p");else
static
botch(char *s)
typedef struct Bucket Bucket;
struct Bucket
{
	char *c;

	c = "assertion botched: ";
	write(2, c, strlen(c));
	write(2, s, strlen(s));
	write(2, "\n", 1);
	abort();
}
static	int	allock(Store*);
#else
#define ASSERT(p)
#endif

/*	C storage allocator
 *	circular first-fit strategy
 *	works with noncontiguous, but monotonically linked, arena
 *	each block is preceded by a ptr to the (pointer of) 
 *	the next following block
 *	blocks are exact number of words long 
 *	aligned to the data type requirements of ALIGN
 *	pointers to blocks must have BUSY bit 0
 *	bit in ptr is 1 for busy, 0 for idle
 *	gaps in arena are merely noted as busy blocks
 *	last block of arena is empty and
 *	has a pointer to first
 *	idle blocks are coalesced during space search
 *
 *	a different implementation may need to redefine
 *	ALIGN, NALIGN, BLOCK, BUSY, INT
 *	where INT is integer type to which a pointer can be cast
 */


/* alloca should have type union store.
 * The funny business gets it initialized without complaint
 */
#define addr(a) (Store*)&a
static	char *alloca;
static	char *alloca = (char*)&alloca + BUSY;	/* initial arena */
static	Store *allocs = addr(alloca);	/*arena base*/
static	Store *allocc = addr(alloca);	/*all prev blocks known busy*/
static	Store *allocp = addr(alloca);	/*search ptr*/
static	Store *alloct = addr(alloca);	/*top cell*/
static	Store *allocx;	/*for benefit of realloc*/

/* a cache list of frequently-used sizes is maintained. From each
 * cache entry hangs a chain of available blocks 
 * malloc(0) shuts off caching (to keep freed data clean)
 */

#define CACHEMAX 256	/* largest block to be cached (in words) */
#define CACHESIZ  53	/* number of entries (prime) */

static Store *cache[CACHESIZ];
static int cachemax = CACHEMAX;

#ifdef	MSTATS
#define	Mstats(e) e
static	long	nmalloc, nrealloc, nfree;	/* call statistics */
static	long	walloc, wfree;			/* space statistics */
static	long	chit, ccoll, cdrain, cavail;	/* cache statistics */
#else
#define Mstats(e)
#endif
	int	size;
	int	magic;
	Bucket	*next;
	char	data[1];
};

typedef struct Arena Arena;
struct Arena
{
	Lock;
	Bucket	*btab[MAX2SIZE];	
};

static QLock mlock;
static Arena arena;
#define datoff		((int)&((Bucket*)0)->data)

void*
malloc(ulong nbytes)
malloc(uint size)
{
	Store *p;
	long nw;
	Store **cp;
	void *mem;
	int pow;
	Bucket *bp;

	nw = (nbytes+WORD+WORD-1)/WORD;
	qlock(&mlock);
	Mstats((nmalloc++, walloc += nw));
	if(nw<cachemax) { 
		if(nw >= 2) {
			cp = &cache[nw%CACHESIZ];
			p = *cp;
			if(p && nw == clearbusy(p->ptr)-p) {
				ASSERT(testbusy(p->ptr));
				*cp = (++p)->ptr;
				Mstats((chit++, cavail--));
				qunlock(&mlock);
				return (char*)p;
			}
		} else {
			draincache();
			cachemax = 0;
		}
	for(pow = 1; pow < MAX2SIZE; pow++) {
		if(size <= (1<<pow))
			goto good;
	}
	p = stdmalloc(nw);
	qunlock(&mlock);
	return p;
}

static void*
stdmalloc(long nw)
{
	Store *p, *q;
	int temp;
	Page *page;

	ASSERT(allock(allocp));
	for(;;) {	/* done at most thrice */
		p = allocp;
		for(temp=0; ; ) {
			if(!testbusy(p->ptr)) {
				allocp = p;
				while(!testbusy((q=p->ptr)->ptr)) {
					ASSERT(q>p);
					p->ptr = q->ptr;
				}
				if(q>=p+nw && p+nw>=p)
					goto found;
			}
			q = p;
			p = clearbusy(p->ptr);
			if(p <= q) {
				ASSERT(p == allocs && q == alloct);
				if(++temp>1)
					break;
				ASSERT(allock(allocc));
				p = allocc;
			}
		}
	return nil;
good:
	/* Allocate off this list */
	lock(&arena);
	bp = arena.btab[pow];
	if(bp) {
		arena.btab[pow] = bp->next;
		arena.unlock();

		/* No memory in the free list.  Call newpage and kmap to get
		 * some more, and ifree to put it in the list.
		 */
		page = newpage(1, 0, 0);
		page->va = VA(kmap(page));
		draincache();
		ifree((char *) page->va, 1 << PGSHIFT);
	}
found:
	allocp += nw;
	if(q>allocp) {
		allocx = allocp->ptr;
		allocp->ptr = p->ptr;
	}
	p->ptr = setbusy(allocp);
	if(p<=allocc) {
		ASSERT(p==allocc);
		while(testbusy(allocc->ptr)
		     && (q=clearbusy(allocc->ptr))>allocc)
			allocc = q;
	}
	return(p+1);
}
		if(bp->magic != 0)
			abort();

void
free(void *ap)
{
	Store *p = ap, *q;
	long nw;
	Store **cp;
		bp->magic = MAGIC;

	if(p==NULL)
		return;
	--p;
	qlock(&mlock);
	ASSERT(allock(p));
	ASSERT(testbusy(p->ptr));
	ASSERT(!cached(p));
	nw = clearbusy(p->ptr) - p;
	Mstats((nfree++, wfree += nw));
	ASSERT(nw>0);
	if(nw<cachemax && nw>=2) {
		cp = &cache[nw%CACHESIZ];
		q = *cp;
		if(!q || nw==clearbusy(q->ptr)-q) {
			p[1].ptr = q;
			*cp = p;
			Mstats(cavail++);
			qunlock(&mlock);
			return;
		} else Mstats(q && ccoll++);
		memset(bp->data, 0,  size);
		return  bp->data;
	}
	stdfree(p+1);
	qunlock(&mlock);
}

/*	freeing strategy tuned for LIFO allocation
*/
static
stdfree(Store *p)
{
	allocp = --p;
	if(p < allocc)
		allocc = p;
	ASSERT(allock(allocp));
	p->ptr = clearbusy(p->ptr);
	ASSERT(p->ptr > allocp);
}
	unlock(&arena);
	size = sizeof(Bucket)+(1<<pow);
	bp = sbrk(size);
	if((int)bp < 0)
		return nil;

static
draincache(void)
{
	Store **cp = cache+CACHESIZ;
	Store *q;
	int anyfreed = 0;
	bp->size = pow;
	bp->magic = MAGIC;

	while(--cp>=cache) {
		while(q = *cp) {
			ASSERT(testbusy(q->ptr));
			ASSERT((clearbusy(q->ptr)-q)%CACHESIZ==cp-cache);
			ASSERT(q>=allocs&&q<=alloct);
			stdfree(++q);
			anyfreed++;
			*cp = q->ptr;
		}
	}
	Mstats((cdrain+=anyfreed, cavail=0));
	return anyfreed;
	return bp->data;
}

/* ifree(q, nbytes) inserts a block that did not come
 * from malloc into the arena
 *
 * q points to new block
 * r points to last of new block
 * p points to last cell of arena before new block
 * s points to first cell of arena after new block
*/

static
void
ifree(char *qq, long nbytes)
{
	Store *p, *q, *r, *s;

	q = (Store *)qq;
	r = q + (nbytes/WORD) - 1;
	q->ptr = r;
	if(q > alloct) {
		p = alloct;
		s = allocs;
		alloct = r;
	} else {
#ifdef IALLOC
		/* useful only in small address spaces */
		for(p=allocs; ; p=s) {
			s = clearbusy(p->ptr);
			if(s==allocs)
				break;
			ASSERT(s>p);
			if(s>r) {
				if(p<q)
					break;
				else
					ASSERT(p>r);
			}
		}
		if(allocs > q)
			allocs = q;
		if(allocc > q)
			allocc = q;
		allocp = allocc;
#else
		return;
#endif
	}
	p->ptr = q==p+1? q: setbusy(q);
	r->ptr = s==r+1? s: setbusy(s);
	while(testbusy(allocc->ptr))
		allocc = clearbusy(allocc->ptr);
}

/*	realloc(p, nbytes) reallocates a block obtained from malloc()
 *	and freed since last call of malloc()
 *	to have new size nbytes, and old content
 *	returns new location, or 0 on failure
*/

void*
realloc(void *pp, ulong nbytes)
{
	Store *p = pp;
	Store *s, *t;
	Store *q;
	long nw, onw;

	if(p==NULL)
		return malloc(nbytes);
	qlock(&mlock);
	Mstats(nrealloc++);
	ASSERT(allock(p-1));
	if(testbusy(p[-1].ptr))
		stdfree(p);
	onw = p[-1].ptr - p;
	nw = (nbytes+WORD-1)/WORD;
	q = (Store *)stdmalloc(nw+1);
	if(q!=NULL && q!=p) {
		ASSERT(q<p||q>p[-1].ptr);
		if(nw<onw) {
			Mstats(wfree += onw-nw);
			onw = nw;
		} else Mstats(walloc += nw-onw);
		for(s=p, t=q; onw--!=0; )
			*t++ = *s++;
		ASSERT(clearbusy(q[-1].ptr)-q==nw);
		if(q<p && q+nw>=p)
			(q+(q+nw-p))->ptr = allocx;
		ASSERT(allock(q-1));
	}
	qunlock(&mlock);
	return q;
}

#ifdef debug
static
allock(Store *q)
{
#ifdef longdebug
	register Store *p, *r;
	register Store **cp;
	int x, y;
	for(cp=cache+CACHESIZ; --cp>=cache; ) {
		if((p= *cp)==0)
			continue;
		x = clearbusy(p->ptr) - p;
		ASSERT(x%CACHESIZ==cp-cache);
		for( ; p; p = p[1].ptr) {
			ASSERT(testbusy(p->ptr));
			ASSERT(clearbusy(p->ptr)-p==x);
		}
	}
	x = 0, y = 0;
	p = allocs;
	for( ; (r=clearbusy(p->ptr)) > p; p=r) {
		if(p==allocc)
			y++;
		ASSERT(y||testbusy(p->ptr));
		if(p==q)
			x++;
	}
	ASSERT(r==allocs);
	ASSERT(x==1||p==q);
	ASSERT(y||p==allocc);
	return(1);
#else
	ASSERT((unsigned)q/WORD*WORD==(unsigned)q);
	ASSERT(q>=allocs&&q<=alloct);
#endif
}
#endif

mstats(void)
free(void *ptr)
{
#ifdef MSTATS
	fprint(2, "Malloc statistics, including overhead bytes\n");
	fprint(2, "Arena: bottom %ld, top %ld\n",
		(long)clearbusy(alloca), (long)alloct);
	fprint(2, "Calls: malloc %ld, realloc %ld, free %ld\n",
		nmalloc, nrealloc, nfree);
	fprint(2, "Bytes: allocated or extended %ld, ",
		walloc*WORD);
	fprint(2, "freed or cut %ld\n", wfree*WORD);
	fprint(2,"Cache: hits %ld, collisions %ld, discards %ld, avail %ld\n",
		chit, ccoll, cdrain, cavail);
#endif
}
	Bucket *bp, **l;

#ifdef debug
cached(Store *p)
{
	Store *q = cache[(clearbusy(p->ptr)-p)%CACHESIZ];
	for( ; q; q=q[1].ptr)
		ASSERT(p!=q);
	return 0;
}
#endif
	/* Find the start of the structure */
	bp = (Bucket*)((uint)ptr - datoff);

void *calloc(ulong n, ulong size){
	void *p;
	if(bp->magic != MAGIC)
		panic("free");

	size = size*n;
	p = malloc(size);
	memset(p, 0, size);
	return p;
	bp->magic = 0;
	lock(&arena);
	l = &arena.btab[bp->size];
	bp->next = *l;
	*l = bp;
	unlock(&arena);
}

M power/devhotrod.c => power/devhotrod.c +5 -2
@@ 261,7 261,7 @@ hotrodread(Chan *c, void *buf, long n, ulong offset)
				isflush = 1;
			}
			mp->param[2] = 0;	/* reply checksum */
			mp->param[3] = 0;	/* reply count */
			mp->param[3] = 0xDEADBEEF;	/* reply count */
			mp->cmd = Uread;
			mp->param[0] = MP2VME(buf);
			mp->param[1] = n;


@@ 273,6 273,7 @@ hotrodread(Chan *c, void *buf, long n, ulong offset)
				do
					m = mp->param[3];
				while(m==0 && --l>0);
				print("isflush blocked\n");
			}else{
				if(waserror()){
					if(*hmp && *hmp==mp)


@@ 284,7 285,7 @@ hotrodread(Chan *c, void *buf, long n, ulong offset)
				m = mp->param[3];
			}
			if(m==0 || m>n){
				print("devhotrod: count %ld %ld\n", m, n);
				print("devhotrod: count 0x%lux 0x%lux\n", m, n);
				error(Egreg);
			}
			if(mp->param[2] != hotsum(buf, m, mp->param[2])){


@@ 424,6 425,8 @@ hotrodintr(int vec)
		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);
	}

M power/devhs.c => power/devhs.c +123 -125
@@ 8,37 8,53 @@

#include	"io.h"

typedef struct Hsvme	Hsvme;
typedef struct Device	Device;
typedef struct Hs	Hs;

enum {
	Maxburst=	1023,		/* maximum transmit burst size */
	Vmevec=		0xd0,		/* vme vector for interrupts */
	Intvec=		0xd0,		/* vme vector for interrupts */
	Intlevel=	5,		/* level to interrupt on */
	Nhsvme=		1,
};
	Nhs=		1,

#define NOW (MACHP(0)->ticks*MS2HZ)
	/*
	 * csr flags
	 */
	ALIVE		= 0x0001,
	IENABLE		= 0x0004,
	EXOFLOW		= 0x0008,
	IRQ		= 0x0010,
	EMUTE		= 0x0020,
	EPARITY		= 0x0040,
	EFRAME		= 0x0080,
	EROFLOW		= 0x0100,
	REF		= 0x0800,
	XFF		= 0x4000,
	XHF		= 0x8000,

/*
 *  hsvme datakit board
 */
struct Device {
	ushort	version;
	ushort	pad0x02;
	ushort	vector;
	ushort	pad0x06;
	ushort	csr;
	ushort	pad0x0A;
	ushort	data;
	/*
	 * csr reset flags
	 */
	FORCEW		= 0x0008,
	NORESET		= 0xFF00,
	RESET		= 0x0000,

	/*
	 * data flags
	 */
	CTL		= 0x0100,
	CHNO		= 0x0200,
	TXEOD		= 0x0400,
	NND		= 0x8000,
};
#define HSVME		VMEA24SUP(Device, 0xF90000)

struct Hsvme {
#define NOW (MACHP(0)->ticks*MS2HZ)
#define IPL(x)		((x)<<5)

struct Hs {
	QLock;

	QLock	xmit;
	Device	*addr;
	HSdev	*addr;
	int	vec;		/* interupt vector */
	Rendez	r;		/* output process */
	Rendez	kr;		/* input kernel process */


@@ 59,55 75,30 @@ struct Hsvme {
	ulong	out;		/* bytes out */
};

Hsvme hsvme[Nhsvme];

#define ALIVE		0x0001
#define IENABLE		0x0004
#define EXOFLOW		0x0008
#define IRQ		0x0010
#define EMUTE		0x0020
#define EPARITY		0x0040
#define EFRAME		0x0080
#define EROFLOW		0x0100
#define REF		0x0800
#define XFF		0x4000
#define XHF		0x8000

#define FORCEW		0x0008
#define IPL(x)		((x)<<5)
#define NORESET		0xFF00
#define RESET		0x0000

#define CTL		0x0100
#define CHNO		0x0200
#define TXEOD		0x0400
#define NND		0x8000
Hs hs[Nhs];

static void hsvmeintr(int);
static void hsvmekproc(void*);
static void hsintr(int);
static void hskproc(void*);

/*
 *  hsvme stream module definition
 *  hs stream module definition
 */
static void hsvmeoput(Queue*, Block*);
static void hsvmestopen(Queue*, Stream*);
static void hsvmestclose(Queue*);
Qinfo hsvmeinfo =
static void hsoput(Queue*, Block*);
static void hsstopen(Queue*, Stream*);
static void hsstclose(Queue*);
Qinfo hsinfo =
{
	nullput,
	hsvmeoput,
	hsvmestopen,
	hsvmestclose,
	"hsvme"
	hsoput,
	hsstopen,
	hsstclose,
	"hs"
};

/*
 *  restart a VME board
 */
void
hsvmerestart(Hsvme *hp)
hsrestart(Hs *hp)
{
	Device *addr;
	HSdev *addr;

	addr = hp->addr;



@@ 117,7 108,7 @@ hsvmerestart(Hsvme *hp)

	/*
	 *  set interrupt vector
	 *  turn on addrice
	 *  turn on device
	 *  set forcew to a known value
	 *  interrupt on level `Intlevel'
	 */


@@ 135,23 126,24 @@ hsvmerestart(Hsvme *hp)
 *  reset all vme boards
 */
void
hsvmereset(void)
hsreset(void)
{
	int i;
	Hsvme *hp;

	for(i=0; i<Nhsvme; i++){
		hsvme[i].addr = HSVME+i;
		hsvme[i].vec = Vmevec+i;
		hsvme[i].addr->csr = RESET;
		setvmevec(hsvme[i].vec, hsvmeintr);
	Hs *hp;

	for(i=0; i<Nhs; i++){
		hp = &hs[i];
		hp->addr = HSDEV+i;
		hp->vec = Intvec+i;
		hp->addr->csr = RESET;
		setvmevec(hp->vec, hsintr);
	}	
	wbflush();
	delay(20);
}

void
hsvmeinit(void)
hsinit(void)
{
}



@@ 159,18 151,18 @@ hsvmeinit(void)
 *  enable the device for interrupts, spec is the device number
 */
Chan*
hsvmeattach(char *spec)
hsattach(char *spec)
{
	Hsvme *hp;
	Hs *hp;
	int i;
	Chan *c;

	i = strtoul(spec, 0, 0);
	if(i >= Nhsvme)
	if(i >= Nhs)
		error(Ebadarg);
	hp = &hsvme[i];
	hp = &hs[i];
	if(!hp->started)
		hsvmerestart(hp);
		hsrestart(hp);

	c = devattach('h', spec);
	c->dev = i;


@@ 179,31 171,31 @@ hsvmeattach(char *spec)
}

Chan*
hsvmeclone(Chan *c, Chan *nc)
hsclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);
}

int	 
hsvmewalk(Chan *c, char *name)
hswalk(Chan *c, char *name)
{
	return devwalk(c, name, 0, 0, streamgen);
}

void	 
hsvmestat(Chan *c, char *dp)
hsstat(Chan *c, char *dp)
{
	devstat(c, dp, 0, 0, streamgen);
}

Chan*
hsvmeopen(Chan *c, int omode)
hsopen(Chan *c, int omode)
{
	if(c->qid.path == CHDIR){
		if(omode != OREAD)
			error(Eperm);
	}else
		streamopen(c, &hsvmeinfo);
		streamopen(c, &hsinfo);
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;


@@ 211,40 203,40 @@ hsvmeopen(Chan *c, int omode)
}

void	 
hsvmecreate(Chan *c, char *name, int omode, ulong perm)
hscreate(Chan *c, char *name, int omode, ulong perm)
{
	USED(c);
	error(Eperm);
}

void	 
hsvmeclose(Chan *c)
hsclose(Chan *c)
{
	if(c->qid.path != CHDIR)
		streamclose(c);
}

long	 
hsvmeread(Chan *c, void *buf, long n, ulong offset)
hsread(Chan *c, void *buf, long n, ulong offset)
{
	return streamread(c, buf, n);
}

long	 
hsvmewrite(Chan *c, void *buf, long n, ulong offset)
hswrite(Chan *c, void *buf, long n, ulong offset)
{
	return streamwrite(c, buf, n, 0);
}

void	 
hsvmeremove(Chan *c)
hsremove(Chan *c)
{
	USED(c);
	error(Eperm);
}

void	 
hsvmewstat(Chan *c, char *dp)
hswstat(Chan *c, char *dp)
{
	USED(c);
	error(Eperm);


@@ 258,40 250,45 @@ hsvmewstat(Chan *c, char *dp)
 *  create the kernel process for input
 */
static void
hsvmestopen(Queue *q, Stream *s)
hsstopen(Queue *q, Stream *s)
{
	Hsvme *hp;
	Hs *hp;
	char name[32];

	hp = &hsvme[s->dev];
	sprint(name, "hsvme%d", s->dev);
	hp = &hs[s->dev];
	sprint(name, "hs%d", s->dev);
	q->ptr = q->other->ptr = hp;
	hp->rq = q;
	kproc(name, hsvmekproc, hp);
	kproc(name, hskproc, hp);
}

/*
 *  kill off the kernel process
 *  ask kproc to die and wait till it happens
 */
static int
kdead(void *arg)
{
	Hsvme *hp;
	Hs *hp;

	hp = (Hsvme *)arg;
	hp = (Hs *)arg;
	return hp->kstarted == 0;
}
static void
hsvmestclose(Queue * q)
hsstclose(Queue * q)
{
	Hsvme *hp;
	Hs *hp;

	hp = (Hsvme *)q->ptr;
	hp = (Hs *)q->ptr;
	qlock(hp);
	hp->rq = 0;
	qunlock(hp);
	wakeup(&hp->kr);
	sleep(&hp->r, kdead, hp);
	while(waserror())
		;
	while(hp->kstarted){
		wakeup(&hp->kr);
		sleep(&hp->r, kdead, hp);
	}
	poperror();
}

/*


@@ 317,9 314,9 @@ freemsg(Queue *q, Block *bp)
static int
halfempty(void *arg)
{
	Device *addr;
	HSdev *addr;

	addr = (Device*)arg;
	addr = (HSdev*)arg;
	return addr->csr & XHF;
}



@@ 331,10 328,10 @@ halfempty(void *arg)
 *  character.
 */
void
hsvmeoput(Queue *q, Block *bp)
hsoput(Queue *q, Block *bp)
{
	Device *addr;
	Hsvme *hp;
	HSdev *addr;
	Hs *hp;
	int burst;
	int chan;
	int ctl;


@@ 354,12 351,12 @@ hsvmeoput(Queue *q, Block *bp)
	/*
	 *  one transmitter at a time
	 */
	hp = (Hsvme *)q->ptr;
	hp = (Hs *)q->ptr;
	qlock(&hp->xmit);
	if(waserror()){
		qunlock(&hp->xmit);
		nexterror();
	}
	qlock(&hp->xmit);
	addr = hp->addr;

	/*


@@ 369,6 366,7 @@ hsvmeoput(Queue *q, Block *bp)
	if(bp->wptr - bp->rptr < 3){
		freemsg(q, bp);
		qunlock(&hp->xmit);
		poperror();
		return;
	}
	chan = CHNO | bp->rptr[0] | (bp->rptr[1]<<8);


@@ 435,9 433,9 @@ hsvmeoput(Queue *q, Block *bp)
static int
notempty(void *arg)
{
	Device *addr;
	HSdev *addr;

	addr = (Device *)arg;
	addr = (HSdev *)arg;
	return addr->csr & REF;
}



@@ 445,7 443,7 @@ notempty(void *arg)
 *  fill a block with what is currently buffered and send it upstream
 */
static void
upstream(Hsvme *hp, unsigned int ctl)
upstream(Hs *hp, unsigned int ctl)
{
	int n;
	Block *bp;


@@ 470,14 468,14 @@ upstream(Hsvme *hp, unsigned int ctl)
 *  fifo fill up.
 */
static void
hsvmekproc(void *arg)
hskproc(void *arg)
{
	Hsvme *hp;
	Device *addr;
	Hs *hp;
	HSdev *addr;
	unsigned int c;
	int locked;

	hp = (Hsvme *)arg;
	hp = (Hs *)arg;
	addr = hp->addr;
	hp->kstarted = 1;
	hp->wptr = hp->buf;


@@ 509,7 507,7 @@ hsvmekproc(void *arg)
		/*
		 *  0xFFFF means an empty fifo
		 */
		while ((c = addr->data) != 0xFFFF) {
		while((c = addr->data) != 0xFFFF){
			hp->in++;
			if(c & CHNO){
				c &= 0x1FF;


@@ 561,31 559,31 @@ hsvmekproc(void *arg)
 *  and not empty bits to figure out whom to wake.
 */
static void
hsvmeintr(int vec)
hsintr(int vec)
{
	ushort csr;
	Device *addr;
	Hsvme *hp;
	HSdev *addr;
	Hs *hp;

	hp = &hsvme[vec - Vmevec];
	if(hp < hsvme || hp > &hsvme[Nhsvme]){
		print("bad hsvme vec\n");
	hp = &hs[vec - Intvec];
	if(hp < hs || hp > &hs[Nhs]){
		print("bad hs vec\n");
		return;
	}
	csr = hp->addr->csr;

	if (csr & REF) {
	if(csr & REF){
		hp->rintr++;
		wakeup(&hp->kr);
	}
	if (csr & XHF) {
	if(csr & XHF){
		hp->tintr++;
		wakeup(&hp->r);
	}
	if ((csr^XFF) & (XFF|EROFLOW|EFRAME|EPARITY|EXOFLOW)) {
	if((csr^XFF) & (XFF|EROFLOW|EFRAME|EPARITY|EXOFLOW)){
		hp->parity++;
		hsvmerestart(hp);
		print("hsvme %d: reset, csr = 0x%ux\n",
			vec - Vmevec, csr);
		hsrestart(hp);
		print("hs %d: reset, csr = 0x%ux\n",
			vec - Intvec, csr);
	}
}

M power/io.h => power/io.h +16 -0
@@ 117,3 117,19 @@ struct INTVEC {
#define       PROM_REINIT     3   /* re-init monitor, then cmd loop */
#define       PROM_REBOOT     4   /* check bootmode, no config */
#define       PROM_AUTOBOOT   5   /* autoboot the system */

/*
 *  hs datakit board
 */
typedef struct HSdev	HSdev;
struct HSdev {
	ushort	version;
	ushort	pad0x02;
	ushort	vector;
	ushort	pad0x06;
	ushort	csr;
	ushort	pad0x0A;
	ushort	data;
};
#define HSDEV		VMEA24SUP(HSdev, 0xF90000)


M power/trap.c => power/trap.c +1 -1
@@ 599,7 599,7 @@ setvmevec(int v, void (*f)(int))

	v &= 0xff;
	g = vmevec[v];
	if(g && g != novme)
	if(g && g != novme && g != f)
		print("second setvmevec to 0x%.2x\n", v);
	vmevec[v] = f;
}