~kris/9p

9hist

7348ba1589386643265d0c522f20ad2edc07cb96 — David du Colombier 23 years ago a91755a
Plan 9 from Bell Labs 2003-03-01
M alphapc/dat.h => alphapc/dat.h +16 -16
@@ 160,7 160,7 @@ struct Mach
	int	load;
	int	intr;
	int	flushmmu;		/* make current proc flush it's mmu state */
	int		ilockdepth;
	int	ilockdepth;

	ulong	spuriousintr;
	int	lastintr;


@@ 197,18 197,18 @@ struct PCArch
	int	(*intrvecno)(int);
	int	(*intrdisable)(int);

	int		(*_inb)(int);
	int	(*_inb)(int);
	ushort	(*_ins)(int);
	ulong	(*_inl)(int);
	void		(*_outb)(int, int);
	void		(*_outs)(int, ushort);
	void		(*_outl)(int, ulong);
	void		(*_insb)(int, void*, int);
	void		(*_inss)(int, void*, int);
	void		(*_insl)(int, void*, int);
	void		(*_outsb)(int, void*, int);
	void		(*_outss)(int, void*, int);
	void		(*_outsl)(int, void*, int);
	void	(*_outb)(int, int);
	void	(*_outs)(int, ushort);
	void	(*_outl)(int, ulong);
	void	(*_insb)(int, void*, int);
	void	(*_inss)(int, void*, int);
	void	(*_insl)(int, void*, int);
	void	(*_outsb)(int, void*, int);
	void	(*_outss)(int, void*, int);
	void	(*_outsl)(int, void*, int);
};

/*


@@ 217,9 217,9 @@ struct PCArch
#define NISAOPT		8

struct ISAConf {
	char		*type;
	char	*type;
	ulong	port;
	ulong	irq;
	int	irq;
	ulong	dma;
	ulong	mem;
	ulong	size;


@@ 242,13 242,13 @@ extern register Proc	*up;
 */
typedef struct {
	ulong	port;	
	int		size;
	int	size;
} port_t;

struct DevConf
{
	ulong	intnum;	/* interrupt number */
	char		*type;	/* card type, malloced */
	int		nports;	/* Number of ports */
	char	*type;	/* card type, malloced */
	int	nports;	/* Number of ports */
	port_t	*ports;	/* The ports themselves */
};

M alphapc/devether.c => alphapc/devether.c +1 -492
@@ 1,492 1,1 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "ureg.h"
#include "../port/error.h"
#include "../port/netif.h"

#include "etherif.h"

static volatile Ether *etherxx[MaxEther];

Chan*
etherattach(char* spec)
{
	ulong ctlrno;
	char *p;
	Chan *chan;

	ctlrno = 0;
	if(spec && *spec){
		ctlrno = strtoul(spec, &p, 0);
		if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
			error(Ebadarg);
	}
	if(etherxx[ctlrno] == 0)
		error(Enodev);

	chan = devattach('l', spec);
	chan->dev = ctlrno;
	if(etherxx[ctlrno]->attach)
		etherxx[ctlrno]->attach(etherxx[ctlrno]);
	return chan;
}

static Walkqid*
etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
{
	return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
}

static int
etherstat(Chan* chan, uchar* dp, int n)
{
	return netifstat(etherxx[chan->dev], chan, dp, n);
}

static Chan*
etheropen(Chan* chan, int omode)
{
	return netifopen(etherxx[chan->dev], chan, omode);
}

static void
ethercreate(Chan*, char*, int, ulong)
{
}

static void
etherclose(Chan* chan)
{
	netifclose(etherxx[chan->dev], chan);
}

static long
etherread(Chan* chan, void* buf, long n, vlong off)
{
	Ether *ether;
	ulong offset = off;

	ether = etherxx[chan->dev];
	if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
		/*
		 * With some controllers it is necessary to reach
		 * into the chip to extract statistics.
		 */
		if(NETTYPE(chan->qid.path) == Nifstatqid)
			return ether->ifstat(ether, buf, n, offset);
		else if(NETTYPE(chan->qid.path) == Nstatqid)
			ether->ifstat(ether, buf, 0, offset);
	}

	return netifread(ether, chan, buf, n, offset);
}

static Block*
etherbread(Chan* chan, long n, ulong offset)
{
	return netifbread(etherxx[chan->dev], chan, n, offset);
}

static int
etherwstat(Chan* chan, uchar* dp, int n)
{
	return netifwstat(etherxx[chan->dev], chan, dp, n);
}

static void
etherrtrace(Netfile* f, Etherpkt* pkt, int len)
{
	int i, n;
	Block *bp;

	if(qwindow(f->in) <= 0)
		return;
	if(len > 58)
		n = 58;
	else
		n = len;
	bp = iallocb(64);
	if(bp == nil)
		return;
	memmove(bp->wp, pkt->d, n);
	i = TK2MS(MACHP(0)->ticks);
	bp->wp[58] = len>>8;
	bp->wp[59] = len;
	bp->wp[60] = i>>24;
	bp->wp[61] = i>>16;
	bp->wp[62] = i>>8;
	bp->wp[63] = i;
	bp->wp += 64;
	qpass(f->in, bp);
}

Block*
etheriq(Ether* ether, Block* bp, int fromwire)
{
	Etherpkt *pkt;
	ushort type;
	int len, multi, tome, fromme;
	Netfile **ep, *f, **fp, *fx;
	Block *xbp;

	ether->inpackets++;

	pkt = (Etherpkt*)bp->rp;
	len = BLEN(bp);
	type = (pkt->type[0]<<8)|pkt->type[1];
	fx = 0;
	ep = &ether->f[Ntypes];

	multi = pkt->d[0] & 1;
	/* check for valid multcast addresses */
	if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
			if(fromwire){
				freeb(bp);
				bp = 0;
			}
			return bp;
		}
	}

	/* is it for me? */
	tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
	fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;

	/*
	 * Multiplex the packet to all the connections which want it.
	 * If the packet is not to be used subsequently (fromwire != 0),
	 * attempt to simply pass it into one of the connections, thereby
	 * saving a copy of the data (usual case hopefully).
	 */
	for(fp = ether->f; fp < ep; fp++){
		if(f = *fp)
		if(f->type == type || f->type < 0)
		if(tome || multi || f->prom){
			/* Don't want to hear bridged packets */
			if(f->bridge && !fromwire && !fromme)
				continue;
			if(!f->headersonly){
				if(fromwire && fx == 0)
					fx = f;
				else if(xbp = iallocb(len)){
					memmove(xbp->wp, pkt, len);
					xbp->wp += len;
					if(qpass(f->in, xbp) < 0)
						ether->soverflows++;
				}
				else
					ether->soverflows++;
			}
			else
				etherrtrace(f, pkt, len);
		}
	}

	if(fx){
		if(qpass(fx->in, bp) < 0)
			ether->soverflows++;
		return 0;
	}
	if(fromwire){
		freeb(bp);
		return 0;
	}

	return bp;
}

static int
etheroq(Ether* ether, Block* bp)
{
	int len, loopback, s;
	Etherpkt *pkt;

	ether->outpackets++;

	/*
	 * Check if the packet has to be placed back onto the input queue,
	 * i.e. if it's a loopback or broadcast packet or the interface is
	 * in promiscuous mode.
	 * If it's a loopback packet indicate to etheriq that the data isn't
	 * needed and return, etheriq will pass-on or free the block.
	 * To enable bridging to work, only packets that were originated
	 * by this interface are fed back.
	 */
	pkt = (Etherpkt*)bp->rp;
	len = BLEN(bp);
	loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
		s = splhi();
		etheriq(ether, bp, 0);
		splx(s);
	}

	if(!loopback){
		qbwrite(ether->oq, bp);
		ether->transmit(ether);
	} else
		freeb(bp);

	return len;
}

static long
etherwrite(Chan* chan, void* buf, long n, vlong)
{
	Ether *ether;
	Block *bp;
	int nn;

	ether = etherxx[chan->dev];
	if(NETTYPE(chan->qid.path) != Ndataqid) {
		nn = netifwrite(ether, chan, buf, n);
		if(nn >= 0)
			return nn;
		if(n == sizeof("nonblocking")-1 && strncmp((char*)buf, "nonblocking", n) == 0){
			qnoblock(ether->oq, 1);
			return n;
		}
		if(ether->ctl!=nil)
			return ether->ctl(ether,buf,n);

		error(Ebadctl);
	}

	if(n > ether->maxmtu)
		error(Etoobig);
	if(n < ether->minmtu)
		error(Etoosmall);

	bp = allocb(n);
	if(waserror()){
		freeb(bp);
		nexterror();
	}
	memmove(bp->rp, buf, n);
	memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
	poperror();
	bp->wp += n;

	return etheroq(ether, bp);
}

static long
etherbwrite(Chan* chan, Block* bp, ulong)
{
	Ether *ether;
	long n;

	n = BLEN(bp);
	if(NETTYPE(chan->qid.path) != Ndataqid){
		if(waserror()) {
			freeb(bp);
			nexterror();
		}
		n = etherwrite(chan, bp->rp, n, 0);
		poperror();
		freeb(bp);
		return n;
	}
	ether = etherxx[chan->dev];

	if(n > ether->maxmtu){
		freeb(bp);
		error(Etoobig);
	}
	if(n < ether->minmtu){
		freeb(bp);
		error(Etoosmall);
	}

	return etheroq(ether, bp);
}

static struct {
	char*	type;
	int	(*reset)(Ether*);
} cards[MaxEther+1];

void
addethercard(char* t, int (*r)(Ether*))
{
	static int ncard;

	if(ncard == MaxEther)
		panic("too many ether cards");
	cards[ncard].type = t;
	cards[ncard].reset = r;
	ncard++;
}

int
parseether(uchar *to, char *from)
{
	char nip[4];
	char *p;
	int i;

	p = from;
	for(i = 0; i < Eaddrlen; i++){
		if(*p == 0)
			return -1;
		nip[0] = *p++;
		if(*p == 0)
			return -1;
		nip[1] = *p++;
		nip[2] = 0;
		to[i] = strtoul(nip, 0, 16);
		if(*p == ':')
			p++;
	}
	return 0;
}

static void
etherreset(void)
{
	Ether *ether;
	int i, n, ctlrno;
	char name[32], buf[256];

	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
		if(ether == 0)
			ether = malloc(sizeof(Ether));
		memset(ether, 0, sizeof(Ether));
		ether->ctlrno = ctlrno;
		ether->tbdf = BUSUNKNOWN;
		ether->mbps = 10;
		ether->minmtu = ETHERMINTU;
		ether->maxmtu = ETHERMAXTU;
		if(isaconfig("ether", ctlrno, ether) == 0)
			continue;
		for(n = 0; cards[n].type; n++){
			if(cistrcmp(cards[n].type, ether->type))
				continue;
			for(i = 0; i < ether->nopt; i++){
				if(strncmp(ether->opt[i], "ea=", 3))
					continue;
				if(parseether(ether->ea, &ether->opt[i][3]))
					memset(ether->ea, 0, Eaddrlen);
			}
			if(cards[n].reset(ether))
				break;

			/*
			 * IRQ2 doesn't really exist, it's used to gang the interrupt
			 * controllers together. A device set to IRQ2 will appear on
			 * the second interrupt controller as IRQ9.
			 */
			if(ether->irq == 2 && BUSTYPE(ether->tbdf) != BusPCI)
				ether->irq = 9;
			snprint(name, sizeof(name), "ether%d", ctlrno);
			/*
			 * If ether->irq is 0, it is a hack to indicate no
			 * interrupt used by ethersink.
			 */
			if(ether->irq > 0)
				intrenable(ether->irq, ether->interrupt,
					ether, ether->tbdf, name);

			i = sprint(buf, "#l%d (%s): %s: %dMbps port 0x%luX irq %lud",
				ctlrno, name, ether->type, ether->mbps,
				ether->port, ether->irq);
			if(ether->mem)
				i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));
			if(ether->size)
				i += sprint(buf+i, " size 0x%luX", ether->size);
			i += sprint(buf+i, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX",
				ether->ea[0], ether->ea[1], ether->ea[2],
				ether->ea[3], ether->ea[4], ether->ea[5]);
			sprint(buf+i, "\n");
			print(buf);

			if(ether->mbps == 100){
				netifinit(ether, name, Ntypes, 256*1024);
				if(ether->oq == 0)
					ether->oq = qopen(256*1024, Qmsg, 0, 0);
			}
			else{
				netifinit(ether, name, Ntypes, 65*1024);
				if(ether->oq == 0)
					ether->oq = qopen(65*1024, Qmsg, 0, 0);
			}
			if(ether->oq == 0)
				panic("etherreset %s", name);
			ether->alen = Eaddrlen;
			memmove(ether->addr, ether->ea, Eaddrlen);
			memset(ether->bcast, 0xFF, Eaddrlen);

			etherxx[ctlrno] = ether;
			ether = 0;
			break;
		}
	}
	if(ether)
		free(ether);
}

/* imported from ../pc; not ready for use yet */
static void
ethershutdown(void)
{
	Ether *ether;
	int i;

	for(i = 0; i < MaxEther; i++){
		ether = etherxx[i];
		if(ether == nil)
			continue;
		if(ether->shutdown == nil) {
			print("#l%d: no shutdown fuction\n", i);
			continue;
		}
		(*ether->shutdown)(ether);
	}
}


#define POLY 0xedb88320

/* really slow 32 bit crc for ethers */
ulong
ethercrc(uchar *p, int len)
{
	int i, j;
	ulong crc, b;

	crc = 0xffffffff;
	for(i = 0; i < len; i++){
		b = *p++;
		for(j = 0; j < 8; j++){
			crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
			b >>= 1;
		}
	}
	return crc;
}

Dev etherdevtab = {
	'l',
	"ether",

	etherreset,
	devinit,
	devshutdown,
	etherattach,
	etherwalk,
	etherstat,
	etheropen,
	ethercreate,
	etherclose,
	etherread,
	etherbread,
	etherwrite,
	etherbwrite,
	devremove,
	etherwstat,
};
#include "../pc/devether.c"

M alphapc/trap.c => alphapc/trap.c +1 -16
@@ 238,23 238,8 @@ intr(Ureg *ur)
		if(ctl->eoi)
			ctl->eoi(vno);

		/* 
		 *  preemptive scheduling.  to limit stack depth,
		 *  make sure process has a chance to return from
		 *  the current interrupt before being preempted a
		 *  second time.
		 */
		if(ctl->isintr)
		if(up && up->state == Running)
		if(anyhigher())
		if(up->preempted == 0)
		if(!active.exiting){
			up->preempted = 1;
			sched();
			splhi();
			up->preempted = 0;
			return;
		}
			preempted();
	}
	else if(vno >= VectorPIC && vno <= MaxVectorPIC){
		/*

M mtx/dat.h => mtx/dat.h +1 -1
@@ 183,7 183,7 @@ struct
struct ISAConf {
	char		*type;
	ulong	port;
	ulong	irq;
	int	irq;
	ulong	dma;
	ulong	mem;
	ulong	size;

M mtx/devether.c => mtx/devether.c +3 -3
@@ 387,13 387,13 @@ etherreset(void)
			snprint(name, sizeof(name), "ether%d", ctlrno);

			/*
			 * If ether->irq is 0, it is a hack to indicate no interrupt
			 * If ether->irq is <0, it is a hack to indicate no interrupt
			 * used by ethersink.
			 */
			if(ether->irq > 0)
			if(ether->irq >= 0)
				intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);

			i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %lud",
			i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
				ctlrno, ether->type, ether->mbps, ether->port, ether->irq);
			if(ether->mem)
				i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));

M mtx/trap.c => mtx/trap.c +1 -16
@@ 386,22 386,7 @@ intr(Ureg *ureg)
	if(ctl->eoi)
		ctl->eoi(vno);

	/* 
	 *  preemptive scheduling.  to limit stack depth,
	 *  make sure process has a chance to return from
	 *  the current interrupt before being preempted a
	 *  second time.
	 */
	if(up && up->state == Running)
	if(anyhigher())
	if(up->preempted == 0)
	if(!active.exiting){
		up->preempted = 1;
		sched();
		splhi();
		up->preempted = 0;
		return;
	}
	preempted();
}

char*

M pc/dat.h => pc/dat.h +1 -1
@@ 253,7 253,7 @@ struct PCArch
struct ISAConf {
	char	*type;
	ulong	port;
	ulong	irq;
	int	irq;
	ulong	dma;
	ulong	mem;
	ulong	size;

M pc/devether.c => pc/devether.c +3 -3
@@ 399,13 399,13 @@ etherprobe(int cardno, int ctlrno)
	snprint(name, sizeof(name), "ether%d", ctlrno);

	/*
	 * If ether->irq is 0, it is a hack to indicate no interrupt
	 * If ether->irq is <0, it is a hack to indicate no interrupt
	 * used by ethersink.
	 */
	if(ether->irq > 0)
	if(ether->irq >= 0)
		intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);

	i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %lud",
	i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
		ctlrno, cards[cardno].type, ether->mbps, ether->port, ether->irq);
	if(ether->mem)
		i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));

M pc/devpccard.c => pc/devpccard.c +1 -1
@@ 1136,7 1136,7 @@ pccard_pcmspecial(char *idstr, ISAConf *isa)
	pi->irq = isa->irq;
	unlock(cb);

	print("#Y%d: %s irq %ld, port %lX\n", (int)(cb - cbslots), pi->verstr, isa->irq, isa->port);
	print("#Y%d: %s irq %d, port %lX\n", (int)(cb - cbslots), pi->verstr, isa->irq, isa->port);
	return (int)(cb - cbslots);
}


M pc/devusb.c => pc/devusb.c +1 -1
@@ 429,7 429,7 @@ usbprobe(int cardno, int ctlrno)
	intrenable(uh->irq, uh->interrupt, uh, uh->tbdf, name);

	ebuf = buf + sizeof buf;
	p = seprint(buf, ebuf, "#U/usb%d: %s: port 0x%luX irq %lud", ctlrno, usbtypes[cardno].type, uh->port, uh->irq);
	p = seprint(buf, ebuf, "#U/usb%d: %s: port 0x%luX irq %d", ctlrno, usbtypes[cardno].type, uh->port, uh->irq);
	if(uh->mem)
		p = seprint(p, ebuf, " addr 0x%luX", PADDR(uh->mem));
	if(uh->size)

M pc/ethersink.c => pc/ethersink.c +1 -1
@@ 48,7 48,7 @@ reset(Ether* ether)
	ether->mbps = 1000;
	ether->attach = nop;
	ether->transmit = nop;
	ether->irq = 0;
	ether->irq = -1;
	ether->interrupt = nil;
	ether->ifstat = nil;
	ether->ctl = ctl;

M pc/mp.c => pc/mp.c +1 -1
@@ 631,7 631,7 @@ mpintrenablex(Vctl* v, int tbdf)
			irq = (dno<<2)|(n-1);
		else
			irq = -1;
		//print("pcidev %uX: irq %uX v->irq %uX\n", tbdf, irq, v->irq);
		//print("pcidev %uX: irq %d v->irq %uX\n", tbdf, irq, v->irq);
	}
	else
		irq = v->irq;

M pc/pcmciamodem.c => pc/pcmciamodem.c +1 -1
@@ 67,7 67,7 @@ pcmciamodemlink(void)
				com2used = 1;
			if(ioalloc(isa.port, 8, 0, modems[j]) < 0)
				print("%s port %lux already in use\n", modems[j], isa.port);
			print("%s in pcmcia slot %d port 0x%lux irq %lud\n",
			print("%s in pcmcia slot %d port 0x%lux irq %d\n",
				modems[j], slot, isa.port, isa.irq);
		}
	}

M pc/wavelan.c => pc/wavelan.c +1 -1
@@ 1197,7 1197,7 @@ wavelanreset(Ether* ether, Ctlr *ctlr)
	ether->scanbs = w_scanbs;
	ether->arg = ether;

	DEBUG("#l%d: irq %ld port %lx type %s",
	DEBUG("#l%d: irq %d port %lx type %s",
		ether->ctlrno, ether->irq, ether->port,	ether->type);
	DEBUG(" %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX\n",
		ether->ea[0], ether->ea[1], ether->ea[2],

M port/devaudio.c => port/devaudio.c +2 -2
@@ 692,7 692,7 @@ ess1688(ISAConf* sbconf)
		i = 0x50|(3<<2);
		break;
	default:
		print("#A: bad ESS1688 irq %lud\n", sbconf->irq);
		print("#A: bad ESS1688 irq %d\n", sbconf->irq);
		return 1;
	}
	ess1688w(0xB1, i);


@@ 766,7 766,7 @@ audioinit(void)
	case 10:
		break;
	default:
		print("#A: bad irq %lud\n", sbconf.irq);
		print("#A: bad irq %d\n", sbconf.irq);
		iofree(sbconf.port);
		iofree(sbconf.port+0x100);
		return;

M port/proc.c => port/proc.c +29 -16
@@ 192,6 192,20 @@ preempted(void)
	return 0;
}

/*
 *  ready(p) picks a new priority for a process and sticks it in the
 *  runq for that priority.
 *
 *  - fixed priority processes never move
 *  - a process that uses all its quanta before blocking goes down a
 *    priority level
 *  - a process that uses less than half its quanta before blocking
 *    goes up a priority level
 *  - a process that blocks after using up half or more of it's quanta
 *    stays at the same level
 *
 *  new quanta are assigned each time a process blocks or changes level
 */
void
ready(Proc *p)
{


@@ 214,15 228,8 @@ ready(Proc *p)
	} else if(p->state == Running){
		if(p->quanta <= 0){
			/* degrade priority of anyone that used their whole quanta */

			/* processes > PriNormal and those below don't mix */
			if(p->basepri > PriNormal){
				if(pri > PriNormal)
					pri--;
			} else {
				if(pri > 0)
					pri--;
			}
			if(pri > 0)
				pri--;
			p->quanta = quanta[pri];
		}
	} else {


@@ 256,7 263,7 @@ Proc*
runproc(void)
{
	Schedq *rq;
	Proc *p, *l;
	Proc *p, *l, *tp;
	ulong start, now;
	int i;



@@ 274,19 281,21 @@ loop:
	spllo();
	for(i = 0;; i++){
		/*
		 *  get highest priority process that this
		 *  find the highest priority target process that this
		 *  processor can run given affinity constraints
		 */
		for(rq = &runq[Nrq-1]; rq >= runq; rq--){
			p = rq->head;
			if(p == 0)
			tp = rq->head;
			if(tp == 0)
				continue;
			for(; p; p = p->rnext){
				if(p->mp == MACHP(m->machno) || (!p->wired && i > 0))
			for(; tp; tp = tp->rnext){
				if(tp->mp == nil || tp->mp == MACHP(m->machno)
				|| (!tp->wired && i > 0))
					goto found;
			}
		}

		/* waste time or halt the CPU */
		idlehands();

		/* remember how much time we're here */


@@ 300,9 309,13 @@ found:
	if(!canlock(runq))
		goto loop;

	/*
	 *  the queue may have changed before we locked runq,
	 *  refind the target process.
	 */
	l = 0;
	for(p = rq->head; p; p = p->rnext){
		if(p->mp == MACHP(m->machno) || (!p->wired && i > 0))
		if(p == tp)
			break;
		l = p;
	}