~kris/9p

9hist

e39f40f3792e2f5ca04f30da3315a9274ca41cf2 — David du Colombier 31 years ago 6d69477
Plan 9 from Bell Labs 1995-07-21
10 files changed, 566 insertions(+), 49 deletions(-)

M pc/devether.c
M pc/ether2000.c
M pc/ether4100.c
M pc/ether509.c
A pc/ether79c970.c
M pc/ether8003.c
M pc/ether8390.c
M pc/etherif.h
M pc/fns.h
M pc/pci.c
M pc/devether.c => pc/devether.c +7 -8
@@ 101,7 101,7 @@ etherwstat(Chan *c, char *dp)
}

void
etherrloop(Ether *ctlr, Etherpkt *pkt, long len, int tome)
etherrloop(Ether *ctlr, Etherpkt *pkt, long len)
{
	Block *bp;
	ushort type;


@@ 111,7 111,7 @@ etherrloop(Ether *ctlr, Etherpkt *pkt, long len, int tome)
	type = (pkt->type[0]<<8)|pkt->type[1];
	ep = &ctlr->f[Ntypes];
	for(fp = ctlr->f; fp < ep; fp++){
		if((f = *fp) && ((tome && f->type==type) || f->type < 0)){
		if((f = *fp) && (f->type == type || f->type < 0)){
			if(f->type > -2){
				if(qproduce(f->in, pkt->d, len) < 0)
					ctlr->soverflows++;


@@ 139,18 139,17 @@ etherrloop(Ether *ctlr, Etherpkt *pkt, long len, int tome)
static int
etherwloop(Ether *ctlr, Etherpkt *pkt, long len)
{
	int s, tome, bcast;
	int s, different;

	tome = memcmp(pkt->d, ctlr->ea, sizeof(pkt->d)) == 0;
	bcast = memcmp(pkt->d, ctlr->bcast, sizeof(pkt->d)) == 0;
	if(!tome && !bcast && ctlr->prom==0 && ctlr->all==0)
	different = memcmp(pkt->d, ctlr->ea, sizeof(pkt->d));
	if(different && memcmp(pkt->d, ctlr->bcast, sizeof(pkt->d)))
		return 0;

	s = splhi();
	etherrloop(ctlr, pkt, len, tome||bcast);
	etherrloop(ctlr, pkt, len);
	splx(s);

	return tome;
	return different == 0;
}

long

M pc/ether2000.c => pc/ether2000.c +3 -3
@@ 48,8 48,8 @@ reset(Ether *ether)
		ether->size = 16*1024;
	port = ether->port;

	ether->private = malloc(sizeof(Dp8390));
	dp8390 = ether->private;
	ether->ctlr = malloc(sizeof(Dp8390));
	dp8390 = ether->ctlr;
	dp8390->bit16 = 1;
	dp8390->ram = 0;



@@ 81,7 81,7 @@ reset(Ether *ether)
	memset(buf, 0, sizeof(buf));
	dp8390read(dp8390, buf, 0, sizeof(buf));
	if((buf[0x0E] & 0xFF) != 0x57 || (buf[0x0F] & 0xFF) != 0x57){
		free(ether->private);
		free(ether->ctlr);
		return -1;
	}


M pc/ether4100.c => pc/ether4100.c +2 -2
@@ 52,8 52,8 @@ reset(Ether *ether)
		ether->size = 16*1024;
	port = ether->port;

	ether->private = malloc(sizeof(Dp8390));
	dp8390 = ether->private;
	ether->ctlr = malloc(sizeof(Dp8390));
	dp8390 = ether->ctlr;
	dp8390->bit16 = 1;
	dp8390->ram = 0;


M pc/ether509.c => pc/ether509.c +6 -6
@@ 190,7 190,7 @@ receive(Ether *ether)
			/*
			 * Copy the packet to whoever wants it.
			 */
			etherrloop(ether, &ether->rpkt, len, 1);
			etherrloop(ether, &ether->rpkt, len);
		}

		/*


@@ 571,16 571,16 @@ static PCIcfg*
tcm590(Ether *ether)
{
	PCIcfg* pcicfg;
	static uchar devno = 0;
	ulong port;
	static int devno = 0;
	int port;
	Adapter *ap;

	pcicfg = malloc(sizeof(PCIcfg));
	while(devno < 16){
	for(;;){
		pcicfg->vid = 0x10B7;
		pcicfg->did = 0;
		if(pcimatch(0, devno++, pcicfg) == 0)
			continue;
		if((devno = pcimatch(0, devno, pcicfg)) == -1)
			break;

		port = pcicfg->baseaddr[0] & ~0x01;
		COMMAND(port, GlobalReset, 0);

A pc/ether79c970.c => pc/ether79c970.c +491 -0
@@ 0,0 1,491 @@
/*
 * AM79C970
 * PCnet-PCI Single-Chip Ethernet Controller for PCI Local Bus
 * To do:
 *	only issue transmit interrupt if necessary?
 *	dynamically increase rings as necessary?
 *	use Block's as receive buffers?
 */
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"

#include "etherif.h"

enum {
	Lognrdre	= 6,
	Nrdre		= (1<<Lognrdre),	/* receive descriptor ring entries */
	Logntdre	= 4,
	Ntdre		= (1<<Logntdre),	/* transmit descriptor ring entries */

	Rbsize		= ETHERMAXTU+4,		/* ring buffer size (+4 for CRC) */
};

enum {						/* DWIO I/O resource map */
	Aprom		= 0x0000,		/* physical address */
	Rdp		= 0x0010,		/* register data port */
	Rap		= 0x0014,		/* register address port */
	Sreset		= 0x0018,		/* software reset */
	Bdp		= 0x001C,		/* bus configuration register data port */
};

enum {						/* CSR0 */
	Init		= 0x0001,		/* begin initialisation */
	Strt		= 0x0002,		/* enable chip */
	Stop		= 0x0004,		/* disable chip */
	Tdmd		= 0x0008,		/* transmit demand */
	Txon		= 0x0010,		/* transmitter on */
	Rxon		= 0x0020,		/* receiver on */
	Iena		= 0x0040,		/* interrupt enable */
	Intr		= 0x0080,		/* interrupt flag */
	Idon		= 0x0100,		/* initialisation done */
	Tint		= 0x0200,		/* transmit interrupt */
	Rint		= 0x0400,		/* receive interrupt */
	Merr		= 0x0800,		/* memory error */
	Miss		= 0x1000,		/* missed frame */
	Cerr		= 0x2000,		/* collision */
	Babl		= 0x4000,		/* transmitter timeout */
	Err		= 0x8000,		/* Babl|Cerr|Miss|Merr */
};
	
enum {						/* CSR3 */
	Bswp		= 0x0004,		/* byte swap */
	Emba		= 0x0008,		/* enable modified back-off algorithm */
	Dxmt2pd		= 0x0010,		/* disable transmit two part deferral */
	Lappen		= 0x0020,		/* look-ahead packet processing enable */
	Idonm		= 0x0100,		/* initialisation done mask */
	Tintm		= 0x0200,		/* transmit interrupt mask */
	Rintm		= 0x0400,		/* receive interrupt mask */
	Merrm		= 0x0800,		/* memory error mask */
	Missm		= 0x1000,		/* missed frame mask */
	Bablm		= 0x4000,		/* babl mask */
};

enum {						/* CSR4 */
	ApadXmt		= 0x0800,		/* auto pad transmit */
};

enum {						/* CSR15 */
	Prom		= 0x8000,		/* promiscuous mode */
};

typedef struct {				/* Initialisation Block */
	ushort	mode;
	uchar	rlen;				/* upper 4 bits */
	uchar	tlen;				/* upper 4 bits */
	uchar	padr[6];
	uchar	res[2];
	uchar	ladr[8];
	ulong	rdra;
	ulong	tdra;
} Iblock;

typedef struct {				/* receive descriptor ring entry */
	ulong	rbadr;
	ulong	rmd1;				/* status|bcnt */
	ulong	rmd2;				/* rcc|rpc|mcnt */
	ulong	rmd3;				/* reserved */
} Rdre;

typedef struct {				/* transmit descriptor ring entry */
	ulong	tbadr;
	ulong	tmd1;				/* status|bcnt */
	ulong	tmd2;				/* errors */
	ulong	tmd3;				/* reserved */
} Tdre;

enum {						/* [RT]dre status bits */
	Enp		= 0x01000000,		/* end of packet */
	Stp		= 0x02000000,		/* start of packet */
	RxBuff		= 0x04000000,		/* buffer error */
	TxDef		= 0x04000000,		/* deferred */
	RxCrc		= 0x08000000,		/* CRC error */
	TxOne		= 0x08000000,		/* one retry needed */
	RxOflo		= 0x10000000,		/* overflow error */
	TxMore		= 0x10000000,		/* more than one retry needed */
	Fram		= 0x20000000,		/* framing error */
	RxErr		= 0x40000000,		/* Fram|Oflo|Crc|RxBuff */
	TxErr		= 0x40000000,		/* Uflo|Lcol|Lcar|Rtry */
	Own		= 0x80000000,
};

typedef struct {
	Lock	raplock;			/* registers other than CSR0 */

	Iblock	iblock;

	Rdre*	rdr;				/* receive descriptor ring */
	void*	rrb;				/* receive ring buffers */
	int	rdrx;				/* index into rdr */

	Rendez	trendez;			/* wait here for free tdre */
	Tdre*	tdr;				/* transmit descriptor ring */
	void*	trb;				/* transmit ring buffers */
	int	tdrx;				/* index into tdr */
} Ctlr;

static void
attach(Ether* ether)
{
	int port;

	port = ether->port;
	outl(port+Rdp, Iena|Strt);
}

static void
ringinit(Ctlr* ctlr)
{
	int i, x;

	/*
	 * Initialise the receive and transmit buffer rings. The ring
	 * entries must be aligned on 16-byte boundaries.
	 */
	if(ctlr->rdr == 0)
		ctlr->rdr = xspanalloc(Nrdre*sizeof(Rdre), 0x10, 0);
	if(ctlr->rrb == 0)
		ctlr->rrb = xalloc(Nrdre*Rbsize);
	x = PADDR(ctlr->rrb);
	for(i = 0; i < Nrdre; i++){
		ctlr->rdr[i].rbadr = x;
		x += Rbsize;
		ctlr->rdr[i].rmd1 = Own|(-Rbsize & 0xFFFF);
	}
	ctlr->rdrx = 0;

	if(ctlr->tdr == 0)
		ctlr->tdr = xspanalloc(Ntdre*sizeof(Tdre), 0x10, 0);
	if(ctlr->trb == 0)
		ctlr->trb = xalloc(Ntdre*Rbsize);
	x = PADDR(ctlr->trb);
	for(i = 0; i < Ntdre; i++){
		ctlr->tdr[i].tbadr = x;
		x += Rbsize;
	}
	ctlr->tdrx = 0;
}

static void
promiscuous(void* arg, int on)
{
	Ether *ether;
	int port, x;
	Ctlr *ctlr;

	ether = arg;
	port = ether->port;
	ctlr = ether->ctlr;

	/*
	 * Put the chip into promiscuous mode. First we must wait until
	 * anyone transmitting is done, then we can stop the chip and put
	 * it in promiscuous mode. Restarting is made harder by the chip
	 * reloading the transmit and receive descriptor pointers with their
	 * base addresses when Strt is set (unlike the older Lance chip),
	 * so the rings must be re-initialised.
	 */
	qlock(&ether->tlock);

	ilock(&ctlr->raplock);
	outl(port+Rdp, Stop);

	outl(port+Rap, 15);
	x = inl(port+Rdp) & ~Prom;
	if(on)
		x |= Prom;
	outl(port+Rdp, x);
	outl(port+Rap, 0);

	ringinit(ctlr);
	outl(port+Rdp, Iena|Strt);
	iunlock(&ctlr->raplock);

	qunlock(&ether->tlock);
}

static int
owntdre(void* arg)
{
	return (((Tdre*)arg)->tmd1 & Own) == 0;
}

static long
write(Ether* ether, void* buf, long n)
{
	int port;
	Ctlr *ctlr;
	Tdre *tdre;
	Etherpkt *pkt;

	port = ether->port;
	ctlr = ether->ctlr;

	/*
	 * Wait for a transmit ring descriptor (and hence a buffer) to become
	 * free. If none become free after a reasonable period, give up.
	 */
	tdre = &ctlr->tdr[ctlr->tdrx];
	tsleep(&ctlr->trendez, owntdre, tdre, 100);
	if(owntdre(tdre) == 0)
		return 0;

	/*
	 * Copy the packet to the transmit buffer and fill in our
	 * source ethernet address. There's no need to pad to ETHERMINTU
	 * here as we set ApadXmit in CSR4.
	 */
	pkt = KADDR(tdre->tbadr);
	memmove(pkt->d, buf, n);
	memmove(pkt->s, ether->ea, sizeof(pkt->s));

	/*
	 * Give ownership of the descriptor to the chip, increment the
	 * software ring descriptor pointer and tell the chip to poll.
	 */
	tdre->tmd2 = 0;
	tdre->tmd1 = Own|Stp|Enp|(-n & 0xFFFF);
	ctlr->tdrx = NEXT(ctlr->tdrx, Ntdre);
	outl(port+Rdp, Iena|Tdmd);

	ether->outpackets++;
	return n;
}

static void
interrupt(Ureg*, void* arg)
{
	Ether *ether;
	int port, csr0, status;
	Ctlr *ctlr;
	Rdre *rdre;
	Etherpkt *pkt;

	ether = arg;
	port = ether->port;
	ctlr = ether->ctlr;

	/*
	 * Acknowledge all interrupts and whine about those that shouldn't
	 * happen.
	 */
	csr0 = inl(port+Rdp);
	outl(port+Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena);
	if(csr0 & (Babl|Miss|Merr))
		print("AMD70C970#%d: csr0 = 0x%uX\n", ether->ctlrno, csr0);

	/*
	 * Receiver interrupt: run round the descriptor ring logging
	 * errors and passing valid receive data up to the higher levels
	 * until we encounter a descriptor still owned by the chip.
	 */
	if(csr0 & Rint){
		rdre = &ctlr->rdr[ctlr->rdrx];
		while(((status = rdre->rmd1) & Own) == 0){
			if(status & RxErr){
				if(status & RxBuff)
					ether->buffs++;
				if(status & RxCrc)
					ether->crcs++;
				if(status & RxOflo)
					ether->overflows++;
			}
			else{
				ether->inpackets++;
				pkt = KADDR(rdre->rbadr);
				etherrloop(ether, pkt, (rdre->rmd2 & 0x0FFF)-4);
			}

			/*
			 * Finished with this descriptor, reinitialise it,
			 * give it back to the chip, then on to the next...
			 */
			rdre->rmd2 = 0;
			rdre->rmd1 = Own|(-Rbsize & 0xFFFF);

			ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
			rdre = &ctlr->rdr[ctlr->rdrx];
		}
	}

	/*
	 * Transmitter interrupt: wakeup anyone waiting for a free descriptor.
	 */
	if(csr0 & Tint)
		wakeup(&ctlr->trendez);
}

typedef struct Adapter Adapter;
struct Adapter {
	Adapter*	next;
	int		port;
	PCIcfg*		pcicfg;
};
static Adapter *adapter;

static PCIcfg*
amd79c90(Ether* ether)
{
	PCIcfg *pcicfg;
	static int devno = 0;
	int port;
	Adapter *ap;

	pcicfg = malloc(sizeof(PCIcfg));
	for(;;){
		pcicfg->vid = 0x1022;
		pcicfg->did = 0x2000;
		if((devno = pcimatch(0, devno, pcicfg)) == -1)
			break;

		port = pcicfg->baseaddr[0] & ~0x01;
		if(ether->port == 0 || ether->port == port)
			return pcicfg;

		ap = malloc(sizeof(Adapter));
		ap->pcicfg = pcicfg;
		ap->port = port;
		ap->next = adapter;
		adapter = ap;

		pcicfg = malloc(sizeof(PCIcfg));
	}
	free(pcicfg);

	return 0;
}

static int
reset(Ether* ether)
{
	int port, x;
	PCIcfg *pcicfg;
	Adapter *ap, **app;
	uchar ea[Eaddrlen];
	Ctlr *ctlr;

	/*
	 * Any adapter matches if no ether->port is supplied, otherwise the
	 * ports must match. First see if we've already found an adapter that fits
	 * the bill. If not then scan for another.
	 */
	port = 0;
	pcicfg = 0;
	for(app = &adapter, ap = *app; ap; app = &ap->next, ap = ap->next){
		if(ether->port == 0 || ether->port == ap->port){
			port = ap->port;
			pcicfg = ap->pcicfg;
			*app = ap->next;
			free(ap);
			break;
		}
	}
	if(port == 0 && (pcicfg = amd79c90(ether))){
		port = pcicfg->baseaddr[0] & ~0x01;
		ether->irq = pcicfg->irq;
	}
	if(port == 0)
		return -1;

	if(pcicfg)
		free(pcicfg);

	/*
	 * How can we tell what mode we're in at this point - if we're in WORD
	 * mode then the only 32-bit access we are allowed to make is a write to
	 * the RDP, which forces the chip to DWORD mode; if we're in DWORD mode
	 * then we're not allowed to make any non-DWORD accesses?
	 * Assuming we do a DWORD write to the RDP, how can we tell what we're
	 * about to overwrite as we can't reliably access the RAP?
	 *
	 * Force DWORD mode by writing to RDP, doing a reset then writing to RDP
	 * again; at least we know what state we're in now. The value of RAP after
	 * a reset is 0, so the second DWORD write will be to CSR0.
	 * Set the software style in BCR20 to be PCnet-PCI to ensure 32-bit access.
	 * Set the auto pad transmit in CSR4.
	 */
	outl(port+Rdp, 0x00);
	inl(port+Sreset);
	outl(port+Rdp, Stop);

	outl(port+Rap, 20);
	outl(port+Bdp, 0x0002);

	outl(port+Rap, 4);
	x = inl(port+Rdp) & 0xFFFF;
	outl(port+Rdp, ApadXmt|x);

	outl(port+Rap, 0);

	/*
	 * Check if we are going to override the adapter's station address.
	 * If not, read it from the I/O-space and set in ether->ea prior to loading the
	 * station address in the initialisation block.
	 */
	memset(ea, 0, Eaddrlen);
	if(memcmp(ea, ether->ea, Eaddrlen) == 0){
		x = inl(port+Aprom);
		ether->ea[0] = x & 0xFF;
		ether->ea[1] = (x>>8) & 0xFF;
		ether->ea[2] = (x>>16) & 0xFF;
		ether->ea[3] = (x>>24) & 0xFF;
		x = inl(port+Aprom+4);
		ether->ea[4] = x & 0xFF;
		ether->ea[5] = (x>>8) & 0xFF;
	}

	/*
	 * Allocate a controller structure and start to fill in the
	 * initialisation block (must be DWORD aligned).
	 */
	ether->ctlr = malloc(sizeof(Ctlr));
	ctlr = ether->ctlr;

	ctlr->iblock.rlen = Lognrdre<<4;
	ctlr->iblock.tlen = Logntdre<<4;
	memmove(ctlr->iblock.padr, ether->ea, sizeof(ctlr->iblock.padr));

	ringinit(ctlr);
	ctlr->iblock.rdra = PADDR(ctlr->rdr);
	ctlr->iblock.tdra = PADDR(ctlr->tdr);

	/*
	 * Point the chip at the initialisation block and tell it to go.
	 * Mask the Idon interrupt and poll for completion. Strt and interrupt
	 * enables will be set later when we're ready to attach to the network.
	 */
	x = PADDR(&ctlr->iblock);
	outl(port+Rap, 1);
	outl(port+Rdp, x & 0xFFFF);
	outl(port+Rap, 2);
	outl(port+Rdp, (x>>16) & 0xFFFF);
	outl(port+Rap, 3);
	outl(port+Rdp, Idonm);
	outl(port+Rap, 0);
	outl(port+Rdp, Init);

	while((inl(port+Rdp) & Idon) == 0)
		;
	outl(port+Rdp, Idon|Stop);
	
	ether->port = port;
	ether->attach = attach;
	ether->write = write;
	ether->interrupt = interrupt;

	ether->promiscuous = promiscuous;
	ether->arg = ether;

	return 0;
}

void
ether79c970link(void)
{
	addethercard("AMD79C970",  reset);
}

M pc/ether8003.c => pc/ether8003.c +2 -2
@@ 104,8 104,8 @@ reset(Ether *ether)
	if(sum != 0xFF)
		return -1;

	ether->private = malloc(sizeof(Dp8390));
	dp8390 = ether->private;
	ether->ctlr = malloc(sizeof(Dp8390));
	dp8390 = ether->ctlr;
	dp8390->ram = 1;

	/*

M pc/ether8390.c => pc/ether8390.c +10 -10
@@ 189,7 189,7 @@ dp8390ring(Dp8390 *dp8390)
void
dp8390setea(Ether *ether)
{
	ulong port = ((Dp8390*)ether->private)->dp8390;
	ulong port = ((Dp8390*)ether->ctlr)->dp8390;
	uchar cr;
	int i;



@@ 210,7 210,7 @@ dp8390setea(Ether *ether)
void
dp8390getea(Ether *ether)
{
	ulong port = ((Dp8390*)ether->private)->dp8390;
	ulong port = ((Dp8390*)ether->ctlr)->dp8390;
	uchar cr;
	int i;



@@ 384,7 384,7 @@ receive(Ether *ether)
	Hdr hdr;
	ulong port, data, len, len1;

	dp8390 = ether->private;
	dp8390 = ether->ctlr;
	port = dp8390->dp8390;
	for(curr = getcurr(dp8390); dp8390->nxtpkt != curr; curr = getcurr(dp8390)){
		ether->inpackets++;


@@ 455,7 455,7 @@ receive(Ether *ether)
			/*
			 * Copy the packet to whoever wants it.
			 */
			etherrloop(ether, &ether->rpkt, len, 1);
			etherrloop(ether, &ether->rpkt, len);
		}

		/*


@@ 484,7 484,7 @@ write(Ether *ether, void *buf, long len)
	ulong port;
	Etherpkt *pkt;

	dp8390 = ether->private;
	dp8390 = ether->ctlr;
	port = dp8390->dp8390;

	tsleep(&ether->tr, istxavail, ether, 10000);


@@ 534,7 534,7 @@ overflow(Ether *ether)
	uchar txp;
	int resend;

	dp8390 = ether->private;
	dp8390 = ether->ctlr;
	port = dp8390->dp8390;

	/*


@@ 572,7 572,7 @@ interrupt(Ureg *ur, void *arg)
	USED(ur);

	ether = arg;
	dp8390 = ether->private;
	dp8390 = ether->ctlr;
	port = dp8390->dp8390;

	/*


@@ 631,7 631,7 @@ interrupt(Ureg *ur, void *arg)
static void
promiscuous(void *arg, int on)
{
	Dp8390 *dp8390 = ((Ether*)arg)->private;
	Dp8390 *dp8390 = ((Ether*)arg)->ctlr;

	/*
	 * Set/reset promiscuous mode.


@@ 645,7 645,7 @@ promiscuous(void *arg, int on)
static void
attach(Ether *ether)
{
	Dp8390 *dp8390 = ether->private;
	Dp8390 *dp8390 = ether->ctlr;

	/*
	 * Enable the chip for transmit/receive.


@@ 663,7 663,7 @@ dp8390reset(Ether *ether)
	Dp8390 *dp8390;
	ulong port;

	dp8390 = ether->private;
	dp8390 = ether->ctlr;
	port = dp8390->dp8390;

	/*

M pc/etherif.h => pc/etherif.h +3 -2
@@ 6,11 6,12 @@ enum {
typedef struct Ether Ether;
struct Ether {
	ISAConf;			/* hardware info */
	int	ctlrno;

	void	(*attach)(Ether*);	/* filled in by reset routine */
	long	(*write)(Ether*, void*, long);
	void	(*interrupt)(Ureg*, void*);
	void	*private;
	void	*ctlr;

	Etherpkt tpkt;			/* transmit buffer */
	Etherpkt rpkt;			/* receive buffer */


@@ 22,7 23,7 @@ struct Ether {
	Netif;
};

extern void etherrloop(Ether*, Etherpkt*, long, int);
extern void etherrloop(Ether*, Etherpkt*, long);
extern void addethercard(char*, int(*)(Ether*));

/*

M pc/fns.h => pc/fns.h +3 -2
@@ 62,8 62,9 @@ void	outs(int, ushort);
void	outss(int, void*, int);
void	outl(int, ulong);
void	outsl(int, void*, int);
void	pcicfgr(uchar, uchar, uchar, uchar, void*, int);
int	pcimatch(uchar, uchar, PCIcfg*);
void	pcicfgr(int, int, int, int, void*, int);
void	pcicfgw(int, int, int, int, void*, int);
int	pcimatch(int, int, PCIcfg*);
PCMmap*	pcmmap(int, ulong, int, int);
int	pcmspecial(char*, ISAConf*);
void	pcmspecialclose(int);

M pc/pci.c => pc/pci.c +39 -14
@@ 14,10 14,10 @@ static Lock pcicfglock;
 * nbytes are DWORD aligned.
 */
void
pcicfgr(uchar busno, uchar devno, uchar funcno, uchar regno, void* data, int nbytes)
pcicfgr(int busno, int devno, int funcno, int regno, void* data, int nbytes)
{
	ulong base, *p;
	int len;
	ulong* p;
	int base, len;

	lock(&pcicfglock);
	outb(PCIcse, 0x80|((funcno & 0x07)<<1));


@@ 28,7 28,29 @@ pcicfgr(uchar busno, uchar devno, uchar funcno, uchar regno, void* data, int nby
	for(len = nbytes/sizeof(ulong); len > 0; len--){
		*p = inl(base);
		p++;
		base += sizeof(ulong);
		base += sizeof(*p);
	}

	outb(PCIcse, 0x00);
	unlock(&pcicfglock);
}

void
pcicfgw(int busno, int devno, int funcno, int regno, void* data, int nbytes)
{
	ulong* p;
	int base, len;

	lock(&pcicfglock);
	outb(PCIcse, 0x80|((funcno & 0x07)<<1));
	outb(PCIforward, busno);

	base = (0xC000|(devno<<8)) + regno;
	p = data;
	for(len = nbytes/sizeof(ulong); len > 0; len--){
		outl(base, *p);
		p++;
		base += sizeof(*p);
	}

	outb(PCIcse, 0x00);


@@ 36,17 58,20 @@ pcicfgr(uchar busno, uchar devno, uchar funcno, uchar regno, void* data, int nby
}

int
pcimatch(uchar busno, uchar devno, PCIcfg* pcicfg)
pcimatch(int busno, int devno, PCIcfg* pcicfg)
{
	ulong l;

	l = 0;
	pcicfgr(busno, devno, 0, 0, &l, sizeof(ulong));
	if((l & 0xFFFF) != pcicfg->vid)
		return 0;
	if(pcicfg->did && ((l>>16) & 0xFFFF) != pcicfg->did)
		return 0;
	pcicfgr(busno, devno, 0, 0, pcicfg, sizeof(PCIcfg));

	return 1;
	while(devno < MaxPCI){
		l = 0;
		pcicfgr(busno, devno, 0, 0, &l, sizeof(ulong));
		devno++;
		if((l & 0xFFFF) != pcicfg->vid)
			continue;
		if(pcicfg->did && ((l>>16) & 0xFFFF) != pcicfg->did)
			continue;
		pcicfgr(busno, devno-1, 0, 0, pcicfg, sizeof(PCIcfg));
		return devno;
	}
	return -1;
}