~kris/9p

9hist

36af2dc80ce2824b027931856ea86324dd158e73 — David du Colombier 24 years ago 6d848cf
Plan 9 from Bell Labs 2001-12-15
11 files changed, 1334 insertions(+), 151 deletions(-)

M boot/boot.h
D boot/dosboot.c
M mtx/fns.h
A mtx/i8259.c
M mtx/io.h
M mtx/main.c
M mtx/mem.h
A mtx/pci.c
A mtx/raven.c
M mtx/trap.c
M pc/pci.c
M boot/boot.h => boot/boot.h +7 -0
@@ 55,15 55,22 @@ extern int	parsefields(char*, char**, int, char*);
extern void	configil(Method*);
extern int	authil(void);
extern int	connectil(void);

extern void	configtcp(Method*);
extern int	authtcp(void);
extern int	connecttcp(void);

extern void	configlocal(Method*);
extern int	authlocal(void);
extern int	connectlocal(void);

extern void	configsac(Method*);
extern int	authsac(void);
extern int	connectsac(void);

extern void	configpaq(Method*);
extern int	authpaq(void);
extern int	connectpaq(void);

/* hack for passing authentication address */
extern char	*authaddr;

D boot/dosboot.c => boot/dosboot.c +0 -77
@@ 1,77 0,0 @@
#include <u.h>
#include <libc.h>
#include "../boot/boot.h"

int	printcol;

static void	dossrv(void);
static void	swapproc(void);

void
dosboot(void)
{
	int fd;

	open("#c/cons", OREAD);
	open("#c/cons", OWRITE);
	open("#c/cons", OWRITE);

	/*
	 *  start to dos file system server
	 */
	dossrv();
	sleep(1000);
	fd = open("#s/boot", ORDWR);
	if(fd < 0)
		fatal("open #s/boot");

	/*
	 *  pick a floppy and mount it as root
	 */
	if(bind("/", "/", MREPL) < 0)
		fatal("bind /");
	if(mount(fd, -1, "/", MAFTER|MCREATE, "#f/fd0disk") < 0)
		if(mount(fd, -1, "/", MAFTER|MCREATE, "#f/fd1disk") < 0)
			if(mount(fd, -1, "/", MAFTER|MCREATE, "#S/sdC0/dos") < 0)
				fatal("mount /");
	close(fd);

	settime(1, -1);
	swapproc();

	execl("/386/init", "init", "-mt", 0);
	fatal("/386/init");
}

static void
dossrv(void)
{
	print("dossrv...");
	if(bind("#c", "/dev", MREPL) < 0)
		fatal("bind #c");
	if(bind("#p", "/proc", MREPL) < 0)
		fatal("bind #p");
	switch(fork()){
	case -1:
		fatal("fork");
	case 0:
		execl("/cfs", "cfs", "boot", 0);
		fatal("can't exec cfs");
	default:
		break;
	}
}

static void
swapproc(void)
{
	int fd;

	fd = open("#c/swap", OWRITE);
	if(fd < 0){
		warning("opening #c/swap");
		return;
	}
	if(write(fd, "start", 5) <= 0)
		warning("starting swap kproc");
}

M mtx/fns.h => mtx/fns.h +19 -0
@@ 65,12 65,30 @@ void	links(void);
void	mathinit(void);
void	mmuinit(void);
ulong*	mmuwalk(ulong*, ulong, int);
void	mpicenable(int);
void	mpiceoi(void);
int	mpicintack(void);
void	outb(int, int);
void	outsb(int, void*, int);
void	outs(int, ushort);
void	outss(int, void*, int);
void	outl(int, ulong);
void	outsl(int, void*, int);
int	pciscan(int, Pcidev **);
ulong pcibarsize(Pcidev *, int);
int	pcicfgr8(Pcidev*, int);
int	pcicfgr16(Pcidev*, int);
int	pcicfgr32(Pcidev*, int);
void	pcicfgw8(Pcidev*, int, int);
void	pcicfgw16(Pcidev*, int, int);
void	pcicfgw32(Pcidev*, int, int);
void pciclrbme(Pcidev*);
void	pcihinv(Pcidev*);
uchar pciipin(Pcidev *, uchar);
Pcidev* pcimatch(Pcidev*, int, int);
Pcidev* pcimatchtbdf(int);
void	pcireset(void);
void	pcisetbme(Pcidev*);
int		pcmspecial(char*, ISAConf*);
void	pcmspecialclose(int);
#define	procrestore(p)


@@ 81,6 99,7 @@ void	procsetup(Proc*);
void	putdec(ulong);
void	putmsr(ulong);
void	putcasid(ulong);
void	raveninit(void);
void	screeninit(void);
void	setpanic(void);
int	screenprint(char*, ...);			/* debugging */

A mtx/i8259.c => mtx/i8259.c +199 -0
@@ 0,0 1,199 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"

/*
 *  8259 interrupt controllers
 */
enum
{
	Int0ctl=	0x20,		/* control port (ICW1, OCW2, OCW3) */
	Int0aux=	0x21,		/* everything else (ICW2, ICW3, ICW4, OCW1) */
	Int1ctl=	0xA0,		/* control port */
	Int1aux=	0xA1,		/* everything else (ICW2, ICW3, ICW4, OCW1) */

	Icw1=		0x10,		/* select bit in ctl register */
	Ocw2=		0x00,
	Ocw3=		0x08,

	EOI=		0x20,		/* non-specific end of interrupt */

	Elcr1=		0x4D0,		/* Edge/Level Triggered Register */
	Elcr2=		0x4D1,
};

static Lock i8259lock;
static int i8259mask = 0xFFFF;		/* disabled interrupts */
int i8259elcr;				/* mask of level-triggered interrupts */

void
i8259init(void)
{
	int x;

	ioalloc(Int0ctl, 2, 0, "i8259.0");
	ioalloc(Int1ctl, 2, 0, "i8259.1");
	ilock(&i8259lock);

	/*
	 *  Set up the first 8259 interrupt processor.
	 *  Make 8259 interrupts start at CPU vector VectorPIC.
	 *  Set the 8259 as master with edge triggered
	 *  input with fully nested interrupts.
	 */
	outb(Int0ctl, (1<<4)|(0<<3)|(1<<0));	/* ICW1 - master, edge triggered,
					  	   ICW4 will be sent */
	outb(Int0aux, VectorPIC);		/* ICW2 - interrupt vector offset */
	outb(Int0aux, 0x04);			/* ICW3 - have slave on level 2 */
	outb(Int0aux, 0x01);			/* ICW4 - 8086 mode, not buffered */

	/*
	 *  Set up the second 8259 interrupt processor.
	 *  Make 8259 interrupts start at CPU vector VectorPIC+8.
	 *  Set the 8259 as slave with edge triggered
	 *  input with fully nested interrupts.
	 */
	outb(Int1ctl, (1<<4)|(0<<3)|(1<<0));	/* ICW1 - master, edge triggered,
					  	   ICW4 will be sent */
	outb(Int1aux, VectorPIC+8);		/* ICW2 - interrupt vector offset */
	outb(Int1aux, 0x02);			/* ICW3 - I am a slave on level 2 */
	outb(Int1aux, 0x01);			/* ICW4 - 8086 mode, not buffered */
	outb(Int1aux, (i8259mask>>8) & 0xFF);

	/*
	 *  pass #2 8259 interrupts to #1
	 */
	i8259mask &= ~0x04;
	outb(Int0aux, i8259mask & 0xFF);

	/*
	 * Set Ocw3 to return the ISR when ctl read.
	 * After initialisation status read is set to IRR.
	 * Read IRR first to possibly deassert an outstanding
	 * interrupt.
	 */
	inb(Int0ctl);
	outb(Int0ctl, Ocw3|0x03);
	inb(Int1ctl);
	outb(Int1ctl, Ocw3|0x03);

	/*
	 * Check for Edge/Level register.
	 * This check may not work for all chipsets.
	 * First try a non-intrusive test - the bits for
	 * IRQs 13, 8, 2, 1 and 0 must be edge (0). If
	 * that's OK try a R/W test.
	 */
	x = (inb(Elcr2)<<8)|inb(Elcr1);
	if(!(x & 0x2107)){
		outb(Elcr1, 0);
		if(inb(Elcr1) == 0){
			outb(Elcr1, 0x20);
			if(inb(Elcr1) == 0x20)
				i8259elcr = x;
			outb(Elcr1, x & 0xFF);
			print("ELCR: %4.4uX\n", i8259elcr);
		}
	}
	iunlock(&i8259lock);
}

int
i8259isr(int vno)
{
	int irq, isr;

	if(vno < VectorPIC || vno > VectorPIC+MaxIrqPIC)
		return 0;
	irq = vno-VectorPIC;

	/*
	 *  tell the 8259 that we're done with the
	 *  highest level interrupt (interrupts are still
	 *  off at this point)
	 */
	ilock(&i8259lock);
	isr = inb(Int0ctl);
	outb(Int0ctl, EOI);
	if(irq >= 8){
		isr |= inb(Int1ctl)<<8;
		outb(Int1ctl, EOI);
	}
	iunlock(&i8259lock);

	return isr & (1<<irq);
}

int
i8259enable(Vctl* v)
{
	int irq, irqbit;

	/*
	 * Given an IRQ, enable the corresponding interrupt in the i8259
	 * and return the vector to be used. The i8259 is set to use a fixed
	 * range of vectors starting at VectorPIC.
	 */
	irq = v->irq;
	if(irq < 0 || irq > MaxIrqPIC){
		print("i8259enable: irq %d out of range\n", irq);
		return -1;
	}
	irqbit = 1<<irq;

	ilock(&i8259lock);
	if(!(i8259mask & irqbit) && !(i8259elcr & irqbit)){
		print("i8259enable: irq %d shared but not level\n", irq);
		iunlock(&i8259lock);
		return -1;
	}
	i8259mask &= ~irqbit;
	if(irq < 8)
		outb(Int0aux, i8259mask & 0xFF);
	else
		outb(Int1aux, (i8259mask>>8) & 0xFF);

	if(i8259elcr & irqbit)
		v->eoi = i8259isr;
	else
		v->isr = i8259isr;
	iunlock(&i8259lock);

	return VectorPIC+irq;
}

int
i8259vecno(int irq)
{
	return VectorPIC+irq;
}

int
i8259disable(int irq)
{
	int irqbit;

	/*
	 * Given an IRQ, disable the corresponding interrupt
	 * in the 8259.
	 */
	if(irq < 0 || irq > MaxIrqPIC){
		print("i8259disable: irq %d out of range\n", irq);
		return -1;
	}
	irqbit = 1<<irq;

	ilock(&i8259lock);
	if(!(i8259mask & irqbit)){
		i8259mask |= irqbit;
		if(irq < 8)
			outb(Int0aux, i8259mask & 0xFF);
		else
			outb(Int1aux, (i8259mask>>8) & 0xFF);
	}
	iunlock(&i8259lock);
	return 0;
}

M mtx/io.h => mtx/io.h +32 -7
@@ 13,7 13,7 @@ enum {
	IrqATA1		= 15,
	MaxIrqPIC	= 15,

	VectorPIC	= 64,
	VectorPIC	= 32,
	MaxVectorPIC	= VectorPIC+MaxIrqPIC,
};



@@ 85,7 85,6 @@ enum {					/* type 0 and type 1 pre-defined header */

	PciBAR0		= 0x10,		/* base address */
	PciBAR1		= 0x14,
	PciROM		= 0x30,

	PciINTL		= 0x3C,		/* interrupt line */
	PciINTP		= 0x3D,		/* interrupt pin */


@@ 99,7 98,7 @@ enum {					/* type 0 pre-defined header */
	PciCIS		= 0x28,		/* cardbus CIS pointer */
	PciSVID		= 0x2C,		/* subsystem vendor ID */
	PciSID		= 0x2E,		/* cardbus CIS pointer */
	PciEBAR0	= 0x30,		/* xpansion ROM base address */
	PciEBAR0	= 0x30,		/* expansion ROM base address */
	PciMGNT		= 0x3E,		/* burst period length */
	PciMLT		= 0x3F,		/* maximum latency between bursts */
};


@@ 124,6 123,34 @@ enum {					/* type 1 pre-defined header */
	PciBCR		= 0x3E,		/* bridge control register */
};

enum {					/* type 2 pre-defined header */
	PciCBExCA	= 0x10,
	PciCBSPSR	= 0x16,
	PciCBPBN	= 0x18,		/* primary bus number */
	PciCBSBN	= 0x19,		/* secondary bus number */
	PciCBUBN	= 0x1A,		/* subordinate bus number */
	PciCBSLTR	= 0x1B,		/* secondary latency timer */
	PciCBMBR0	= 0x1C,
	PciCBMLR0	= 0x20,
	PciCBMBR1	= 0x24,
	PciCBMLR1	= 0x28,
	PciCBIBR0	= 0x2C,		/* I/O base */
	PciCBILR0	= 0x30,		/* I/O limit */
	PciCBIBR1	= 0x34,		/* I/O base */
	PciCBILR1	= 0x38,		/* I/O limit */
	PciCBSVID	= 0x40,		/* subsystem vendor ID */
	PciCBSID	= 0x42,		/* subsystem ID */
	PciCBLMBAR	= 0x44,		/* legacy mode base address */
};

typedef struct Pcisiz Pcisiz;
struct Pcisiz
{
	Pcidev*	dev;
	int	siz;
	int	bar;
};

typedef struct Pcidev Pcidev;
typedef struct Pcidev {
	int	tbdf;			/* type+bus+device+function */


@@ 153,7 180,5 @@ typedef struct Pcidev {
	ulong	pcr;
};

//#define PCIWINDOW	0x40000000
//#define PCIWADDR(va)	(PADDR(va)+PCIWINDOW)
//#define ISAWINDOW	0x00800000
//#define ISAWADDR(va)	(PADDR(va)+ISAWINDOW)
#define PCIWINDOW	0
#define PCIWADDR(va)	(PADDR(va)+PCIWINDOW)

M mtx/main.c => mtx/main.c +3 -0
@@ 21,9 21,12 @@ main(void)
	print("\nPlan 9\n");
	confinit();
	xinit();
	raveninit();
	trapinit();
	printinit();
	cpuidprint();
pcihinv(nil);
firmware();
	mmuinit();
	procinit0();
	initseg();

M mtx/mem.h => mtx/mem.h +5 -2
@@ 196,9 196,12 @@
#define	USTKSIZE	(4*1024*1024)		/* size of user stack */
#define	UREGSIZE	((8+32)*4)

#define	PCI1			0x40000000
#define	PCI0			0xfd000000
#define	PCIMEM0		0xf0000000
#define	PCISIZE0		0x0e000000
#define	PCIMEM1		0xc0000000
#define	PCISIZE1		0x30000000
#define	IOMEM		0xfe000000
#define	IOSIZE		0x00800000
#define	FALCON		0xfef80000
#define	RAVEN		0xfeff0000
#define	FLASHA		0xff000000

A mtx/pci.c => mtx/pci.c +911 -0
@@ 0,0 1,911 @@
/*
 * PCI support code.
 */
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"

#define DBG	if(0) pcilog

struct
{
	char	output[16384];
	int	ptr;
}PCICONS;

int
pcilog(char *fmt, ...)
{
	int n;
	va_list arg;
	char buf[PRINTSIZE];

	va_start(arg, fmt);
	n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf;
	va_end(arg);

	memmove(PCICONS.output+PCICONS.ptr, buf, n);
	PCICONS.ptr += n;
	return n;
}

enum
{					/* configuration mechanism #1 */
	PciADDR		= 0xCF8,	/* CONFIG_ADDRESS */
	PciDATA		= 0xCFC,	/* CONFIG_DATA */

					/* configuration mechanism #2 */
	PciCSE		= 0xCF8,	/* configuration space enable */
	PciFORWARD	= 0xCFA,	/* which bus */

	MaxFNO		= 7,
	MaxUBN		= 255,
};

enum
{					/* command register */
	IOen		= (1<<0),
	MEMen		= (1<<1),
	MASen		= (1<<2),
	MemWrInv	= (1<<4),
	PErrEn		= (1<<6),
	SErrEn		= (1<<8),
};

static Lock pcicfglock;
static QLock pcicfginitlock;
static int pcicfgmode = -1;
static int pcimaxbno = 7;
static int pcimaxdno;
static Pcidev* pciroot;
static Pcidev* pcilist;
static Pcidev* pcitail;

static int pcicfgrw32(int, int, int, int);
static int pcicfgrw8(int, int, int, int);

static char* bustypes[] = {
	"CBUSI",
	"CBUSII",
	"EISA",
	"FUTURE",
	"INTERN",
	"ISA",
	"MBI",
	"MBII",
	"MCA",
	"MPI",
	"MPSA",
	"NUBUS",
	"PCI",
	"PCMCIA",
	"TC",
	"VL",
	"VME",
	"XPRESS",
};

#pragma	varargck	type	"T"	int

static int
tbdfconv(va_list* arg, Fconv* f)
{
	char *p;
	int l, type, tbdf;

	p = malloc(READSTR);
	if(p == nil){
		strconv("(tbdfconv)", f);
		return sizeof(int);
	}
		
	switch(f->chr){
	case 'T':
		tbdf = va_arg(*arg, int);
		type = BUSTYPE(tbdf);
		if(type < nelem(bustypes))
			l = snprint(p, READSTR, bustypes[type]);
		else
			l = snprint(p, READSTR, "%d", type);
		snprint(p+l, READSTR-l, ".%d.%d.%d",
			BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
		break;

	default:
		snprint(p, READSTR, "(tbdfconv)");
		break;
	}
	strconv(p, f);
	free(p);

	return sizeof(int);
}

ulong
pcibarsize(Pcidev *p, int rno)
{
	ulong v, size;

	v = pcicfgrw32(p->tbdf, rno, 0, 1);
	pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
	size = pcicfgrw32(p->tbdf, rno, 0, 1);
	if(v & 1)
		size |= 0xFFFF0000;
	pcicfgrw32(p->tbdf, rno, v, 0);

	return -(size & ~0x0F);
}

static int
pcisizcmp(void *a, void *b)
{
	Pcisiz *aa, *bb;

	aa = a;
	bb = b;
	return aa->siz - bb->siz;
}

static ulong
pcimask(ulong v)
{
	ulong m;

	m = BI2BY*sizeof(v);
	for(m = 1<<(m-1); m != 0; m >>= 1) {
		if(m & v)
			break;
	}

	m--;
	if((v & m) == 0)
		return v;

	v |= m;
	return v+1;
}

static void
pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg)
{
	Pcidev *p;
	int ntb, i, size, rno, hole;
	ulong v, mema, ioa, sioa, smema, base, limit;
	Pcisiz *table, *tptr, *mtb, *itb;
	extern void qsort(void*, long, long, int (*)(void*, void*));

	ioa = *pioa;
	mema = *pmema;

	DBG("pcibusmap wr=%d %T mem=%luX io=%luX\n", 
		wrreg, root->tbdf, mema, ioa);

	ntb = 0;
	for(p = root; p != nil; p = p->link)
		ntb++;

	ntb *= (PciCIS-PciBAR0)/4;
	table = malloc(2*ntb*sizeof(Pcisiz));
	itb = table;
	mtb = table+ntb;

	/*
	 * Build a table of sizes
	 */
	for(p = root; p != nil; p = p->link) {
		if(p->ccrb == 0x06) {
			if(p->ccru == 0x04 && p->bridge != nil) {
				sioa = ioa;
				smema = mema;
				pcibusmap(p->bridge, &smema, &sioa, 0);
	
				hole = pcimask(smema-mema);
				if(hole < (1<<20))
					hole = 1<<20;
				p->mema.size = hole;
	
				hole = pcimask(sioa-ioa);
				if(hole < (1<<12))
					hole = 1<<12;
	
				p->ioa.size = hole;
	
				itb->dev = p;
				itb->bar = -1;
				itb->siz = p->ioa.size;
				itb++;
	
				mtb->dev = p;
				mtb->bar = -1;
				mtb->siz = p->mema.size;
				mtb++;
			}
			if((pcicfgr8(p, PciHDT)&0x7f) != 0)
				continue;
		}

		for(i = 0; i <= 5; i++) {
			rno = PciBAR0 + i*4;
			v = pcicfgrw32(p->tbdf, rno, 0, 1);
			size = pcibarsize(p, rno);
			if(size == 0)
				continue;

			if(v & 1) {
				itb->dev = p;
				itb->bar = i;
				itb->siz = size;
				itb++;
			}
			else {
				mtb->dev = p;
				mtb->bar = i;
				mtb->siz = size;
				mtb++;
			}

			p->mem[i].size = size;
		}
	}

	/*
	 * Sort both tables IO smallest first, Memory largest
	 */
	qsort(table, itb-table, sizeof(Pcisiz), pcisizcmp);
	tptr = table+ntb;
	qsort(tptr, mtb-tptr, sizeof(Pcisiz), pcisizcmp);

	/*
	 * Allocate IO address space on this bus
	 */
	for(tptr = table; tptr < itb; tptr++) {
		hole = tptr->siz;
		if(tptr->bar == -1)
			hole = 1<<12;
		ioa = (ioa+hole-1) & ~(hole-1);

		p = tptr->dev;
		if(tptr->bar == -1)
			p->ioa.bar = ioa;
		else {
			p->pcr |= IOen;
			p->mem[tptr->bar].bar = ioa|1;
			if(wrreg)
				pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), ioa|1, 0);
		}

		ioa += tptr->siz;
	}

	/*
	 * Allocate Memory address space on this bus
	 */
	for(tptr = table+ntb; tptr < mtb; tptr++) {
		hole = tptr->siz;
		if(tptr->bar == -1)
			hole = 1<<20;
		mema = (mema+hole-1) & ~(hole-1);

		p = tptr->dev;
		if(tptr->bar == -1)
			p->mema.bar = mema;
		else {
			p->pcr |= MEMen;
			p->mem[tptr->bar].bar = mema;
			if(wrreg)
				pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), mema, 0);
		}
		mema += tptr->siz;
	}

	*pmema = mema;
	*pioa = ioa;
	free(table);

	if(wrreg == 0)
		return;

	/*
	 * Finally set all the bridge addresses & registers
	 */
	for(p = root; p != nil; p = p->link) {
		if(p->bridge == nil) {
			pcicfgrw8(p->tbdf, PciLTR, 64, 0);

			p->pcr |= MASen;
			pcicfgrw32(p->tbdf, PciPCR, p->pcr, 0);
			continue;
		}

		base = p->ioa.bar;
		limit = base+p->ioa.size-1;
		v = pcicfgrw32(p->tbdf, PciBAR3, 0, 1);
		v = (v&0xFFFF0000)|(limit & 0xF000)|((base & 0xF000)>>8);
		pcicfgrw32(p->tbdf, PciBAR3, v, 0);
		v = (limit & 0xFFFF0000)|(base>>16);
		pcicfgrw32(p->tbdf, 0x30, v, 0);

		base = p->mema.bar;
		limit = base+p->mema.size-1;
		v = (limit & 0xFFF00000)|((base & 0xFFF00000)>>16);
		pcicfgrw32(p->tbdf, PciBAR4, v, 0);

		/*
		 * Disable memory prefetch
		 */
		pcicfgrw32(p->tbdf, PciBAR5, 0x0000FFFF, 0);
		pcicfgrw8(p->tbdf, PciLTR, 64, 0);

		/*
		 * Enable the bridge
		 */
		v = 0xFFFF0000 | IOen | MEMen | MASen;
		pcicfgrw32(p->tbdf, PciPCR, v, 0);

		sioa = p->ioa.bar;
		smema = p->mema.bar;
		pcibusmap(p->bridge, &smema, &sioa, 1);
	}
}

static int
pcilscan(int bno, Pcidev** list)
{
	Pcidev *p, *head, *tail;
	int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;

	maxubn = bno;
	head = nil;
	tail = nil;
	for(dno = 0; dno <= pcimaxdno; dno++){
		maxfno = 0;
		for(fno = 0; fno <= maxfno; fno++){
			/*
			 * For this possible device, form the
			 * bus+device+function triplet needed to address it
			 * and try to read the vendor and device ID.
			 * If successful, allocate a device struct and
			 * start to fill it in with some useful information
			 * from the device's configuration space.
			 */
			tbdf = MKBUS(BusPCI, bno, dno, fno);
			l = pcicfgrw32(tbdf, PciVID, 0, 1);
			if(l == 0xFFFFFFFF || l == 0)
				continue;
			p = malloc(sizeof(*p));
			p->tbdf = tbdf;
			p->vid = l;
			p->did = l>>16;

			if(pcilist != nil)
				pcitail->list = p;
			else
				pcilist = p;
			pcitail = p;

			p->rid = pcicfgr8(p, PciRID);
			p->ccrp = pcicfgr8(p, PciCCRp);
			p->ccru = pcicfgr8(p, PciCCRu);
			p->ccrb = pcicfgr8(p, PciCCRb);
			p->pcr = pcicfgr32(p, PciPCR);

			p->intl = pcicfgr8(p, PciINTL);

			/*
			 * If the device is a multi-function device adjust the
			 * loop count so all possible functions are checked.
			 */
			hdt = pcicfgr8(p, PciHDT);
			if(hdt & 0x80)
				maxfno = MaxFNO;

			/*
			 * If appropriate, read the base address registers
			 * and work out the sizes.
			 */
			switch(p->ccrb) {
			case 0x01:		/* mass storage controller */
			case 0x02:		/* network controller */
			case 0x03:		/* display controller */
			case 0x04:		/* multimedia device */
			case 0x06:		/* bridge device */
			case 0x07:		/* simple comm. controllers */
			case 0x08:		/* base system peripherals */
			case 0x09:		/* input devices */
			case 0x0A:		/* docking stations */
			case 0x0B:		/* processors */
			case 0x0C:		/* serial bus controllers */
				if((hdt & 0x7F) != 0)
					break;
				rno = PciBAR0 - 4;
				for(i = 0; i < nelem(p->mem); i++) {
					rno += 4;
					p->mem[i].bar = pcicfgr32(p, rno);
					p->mem[i].size = pcibarsize(p, rno);
				}
				break;

			case 0x00:
			case 0x05:		/* memory controller */
			default:
				break;
			}

			if(head != nil)
				tail->link = p;
			else
				head = p;
			tail = p;
		}
	}

	*list = head;
	for(p = head; p != nil; p = p->link){
		/*
		 * Find PCI-PCI bridges and recursively descend the tree.
		 */
		if(p->ccrb != 0x06 || p->ccru != 0x04)
			continue;

		/*
		 * If the secondary or subordinate bus number is not
		 * initialised try to do what the PCI BIOS should have
		 * done and fill in the numbers as the tree is descended.
		 * On the way down the subordinate bus number is set to
		 * the maximum as it's not known how many buses are behind
		 * this one; the final value is set on the way back up.
		 */
		sbn = pcicfgr8(p, PciSBN);
		ubn = pcicfgr8(p, PciUBN);

		if(sbn == 0 || ubn == 0) {
			sbn = maxubn+1;
			/*
			 * Make sure memory, I/O and master enables are
			 * off, set the primary, secondary and subordinate
			 * bus numbers and clear the secondary status before
			 * attempting to scan the secondary bus.
			 *
			 * Initialisation of the bridge should be done here.
			 */
			pcicfgw32(p, PciPCR, 0xFFFF0000);
			l = (MaxUBN<<16)|(sbn<<8)|bno;
			pcicfgw32(p, PciPBN, l);
			pcicfgw16(p, PciSPSR, 0xFFFF);
			maxubn = pcilscan(sbn, &p->bridge);
			l = (maxubn<<16)|(sbn<<8)|bno;

			pcicfgw32(p, PciPBN, l);
		}
		else {
			maxubn = ubn;
			pcilscan(sbn, &p->bridge);
		}
	}

	return maxubn;
}

int
pciscan(int bno, Pcidev **list)
{
	int ubn;

	qlock(&pcicfginitlock);
	ubn = pcilscan(bno, list);
	qunlock(&pcicfginitlock);
	return ubn;
}

static void
pcicfginit(void)
{
	char *p;
	int bno;
	Pcidev **list;
	ulong mema, ioa;

	qlock(&pcicfginitlock);
	if(pcicfgmode != -1)
		goto out;

	/*
	 * Try to determine which PCI configuration mode is implemented.
	 * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses
	 * a DWORD at 0xCF8 and another at 0xCFC and will pass through
	 * any non-DWORD accesses as normal I/O cycles. There shouldn't be
	 * a device behind these addresses so if Mode2 accesses fail try
	 * for Mode1 (which is preferred, Mode2 is deprecated).
	 */
	outb(PciCSE, 0);
	if(inb(PciCSE) == 0){
		pcicfgmode = 2;
		pcimaxdno = 15;
	}
	else {
		outl(PciADDR, 0);
		if(inl(PciADDR) == 0){
			pcicfgmode = 1;
			pcimaxdno = 31;
		}
	}
	
	if(pcicfgmode < 0)
		goto out;

	fmtinstall('T', tbdfconv);

	if(p = getconf("*pcimaxbno"))
		pcimaxbno = strtoul(p, 0, 0);
	if(p = getconf("*pcimaxdno"))
		pcimaxdno = strtoul(p, 0, 0);

	list = &pciroot;
	for(bno = 0; bno <= pcimaxbno; bno++) {
		int sbno = bno;
		bno = pcilscan(bno, list);

		while(*list)
			list = &(*list)->link;

		if (sbno == 0) {
			Pcidev *pci;

			/*
			  * If we have found a PCI-to-Cardbus bridge, make sure
			  * it has no valid mappings anymore.  
			  */
			pci = pciroot;
			while (pci) {
				if (pci->ccrb == 6 && pci->ccru == 7) {
					ushort bcr;

					/* reset the cardbus */
					bcr = pcicfgr16(pci, PciBCR);
					pcicfgw16(pci, PciBCR, 0x40 | bcr);
					delay(50);
				}
				pci = pci->link;
			}
		}
	}

	if(pciroot == nil)
		goto out;

	/*
	 * Work out how big the top bus is
	 */
	mema = 0;
	ioa = 0;
	pcibusmap(pciroot, &mema, &ioa, 0);

	DBG("Sizes: mem=%8.8lux size=%8.8lux io=%8.8lux\n",
		mema, pcimask(mema), ioa);

	/*
	 * Align the windows and map it
	 */
	ioa = 0x1000;
	mema = 0;

	pcilog("Mask sizes: mem=%lux io=%lux\n", mema, ioa);

	pcibusmap(pciroot, &mema, &ioa, 1);
	DBG("Sizes2: mem=%lux io=%lux\n", mema, ioa);

out:
	qunlock(&pcicfginitlock);
}

static int
pcicfgrw8(int tbdf, int rno, int data, int read)
{
	int o, type, x;

	if(pcicfgmode == -1)
		pcicfginit();

	if(BUSBNO(tbdf))
		type = 0x01;
	else
		type = 0x00;
	x = -1;
	if(BUSDNO(tbdf) > pcimaxdno)
		return x;

	lock(&pcicfglock);
	switch(pcicfgmode){

	case 1:
		o = rno & 0x03;
		rno &= ~0x03;
		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
		if(read)
			x = inb(PciDATA+o);
		else
			outb(PciDATA+o, data);
		outl(PciADDR, 0);
		break;

	case 2:
		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
		outb(PciFORWARD, BUSBNO(tbdf));
		if(read)
			x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno);
		else
			outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
		outb(PciCSE, 0);
		break;
	}
	unlock(&pcicfglock);

	return x;
}

int
pcicfgr8(Pcidev* pcidev, int rno)
{
	return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
}

void
pcicfgw8(Pcidev* pcidev, int rno, int data)
{
	pcicfgrw8(pcidev->tbdf, rno, data, 0);
}

static int
pcicfgrw16(int tbdf, int rno, int data, int read)
{
	int o, type, x;

	if(pcicfgmode == -1)
		pcicfginit();

	if(BUSBNO(tbdf))
		type = 0x01;
	else
		type = 0x00;
	x = -1;
	if(BUSDNO(tbdf) > pcimaxdno)
		return x;

	lock(&pcicfglock);
	switch(pcicfgmode){

	case 1:
		o = rno & 0x02;
		rno &= ~0x03;
		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
		if(read)
			x = ins(PciDATA+o);
		else
			outs(PciDATA+o, data);
		outl(PciADDR, 0);
		break;

	case 2:
		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
		outb(PciFORWARD, BUSBNO(tbdf));
		if(read)
			x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno);
		else
			outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
		outb(PciCSE, 0);
		break;
	}
	unlock(&pcicfglock);

	return x;
}

int
pcicfgr16(Pcidev* pcidev, int rno)
{
	return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
}

void
pcicfgw16(Pcidev* pcidev, int rno, int data)
{
	pcicfgrw16(pcidev->tbdf, rno, data, 0);
}

static int
pcicfgrw32(int tbdf, int rno, int data, int read)
{
	int type, x;

	if(pcicfgmode == -1)
		pcicfginit();

	if(BUSBNO(tbdf))
		type = 0x01;
	else
		type = 0x00;
	x = -1;
	if(BUSDNO(tbdf) > pcimaxdno)
		return x;

	lock(&pcicfglock);
	switch(pcicfgmode){

	case 1:
		rno &= ~0x03;
		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
		if(read)
			x = inl(PciDATA);
		else
			outl(PciDATA, data);
		outl(PciADDR, 0);
		break;

	case 2:
		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
		outb(PciFORWARD, BUSBNO(tbdf));
		if(read)
			x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno);
		else
			outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
		outb(PciCSE, 0);
		break;
	}
	unlock(&pcicfglock);

	return x;
}

int
pcicfgr32(Pcidev* pcidev, int rno)
{
	return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
}

void
pcicfgw32(Pcidev* pcidev, int rno, int data)
{
	pcicfgrw32(pcidev->tbdf, rno, data, 0);
}

Pcidev*
pcimatch(Pcidev* prev, int vid, int did)
{
	if(pcicfgmode == -1)
		pcicfginit();

	if(prev == nil)
		prev = pcilist;
	else
		prev = prev->list;

	while(prev != nil){
		if((vid == 0 || prev->vid == vid)
		&& (did == 0 || prev->did == did))
			break;
		prev = prev->list;
	}
	return prev;
}

Pcidev*
pcimatchtbdf(int tbdf)
{
	Pcidev *pcidev;

	if(pcicfgmode == -1)
		pcicfginit();

	for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
		if(pcidev->tbdf == tbdf)
			break;
	}
	return pcidev;
}

uchar
pciipin(Pcidev *pci, uchar pin)
{
	if (pci == nil)
		pci = pcilist;

	while (pci) {
		uchar intl;

		if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff)
			return pci->intl;

		if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0)
			return intl;

		pci = pci->list;
	}
	return 0;
}

static void
pcilhinv(Pcidev* p)
{
	int i;
	Pcidev *t;

	if(p == nil) {
		putstrn(PCICONS.output, PCICONS.ptr);
		p = pciroot;
		print("bus dev type vid  did intl memory\n");
	}
	for(t = p; t != nil; t = t->link) {
		print("%d  %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d  ",
			BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
			t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);

		for(i = 0; i < nelem(p->mem); i++) {
			if(t->mem[i].size == 0)
				continue;
			print("%d:%.8lux %d ", i,
				t->mem[i].bar, t->mem[i].size);
		}
		if(t->ioa.bar || t->ioa.size)
			print("ioa:%.8lux %d ", t->ioa.bar, t->ioa.size);
		if(t->mema.bar || t->mema.size)
			print("mema:%.8lux %d ", t->mema.bar, t->mema.size);
		if(t->bridge)
			print("->%d", BUSBNO(t->bridge->tbdf));
		print("\n");
	}
	while(p != nil) {
		if(p->bridge != nil)
			pcilhinv(p->bridge);
		p = p->link;
	}	
}

void
pcihinv(Pcidev* p)
{
	if(pcicfgmode == -1)
		pcicfginit();
	qlock(&pcicfginitlock);
	pcilhinv(p);
	qunlock(&pcicfginitlock);
}

void
pcireset(void)
{
	Pcidev *p;
	int pcr;

	if(pcicfgmode == -1)
		pcicfginit();

	for(p = pcilist; p != nil; p = p->list){
		pcr = pcicfgr16(p, PciPCR);
		pcr &= ~0x0004;
		pcicfgw16(p, PciPCR, pcr);
	}
}

void
pcisetbme(Pcidev* p)
{
	int pcr;

	pcr = pcicfgr16(p, PciPCR);
	pcr |= MASen;
	pcicfgw16(p, PciPCR, pcr);
}

void
pciclrbme(Pcidev* p)
{
	int pcr;

	pcr = pcicfgr16(p, PciPCR);
	pcr &= ~MASen;
	pcicfgw16(p, PciPCR, pcr);
}

A mtx/raven.c => mtx/raven.c +143 -0
@@ 0,0 1,143 @@
/*
 *	``Nevermore!''
 */
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"

typedef struct Raven Raven;
struct Raven
{
	ushort	vid;
	ushort	did;
	uchar	_pad4;
	uchar	rev;
	uchar	_pad6[2];
	ushort	gcsr;
	ushort	feat;
	uchar	_padC[7];
	uchar	padj;
	uchar	_pad14[12];
	ushort	errtst;
	ushort	erren;
	uchar	_pad24[3];
	uchar	errst;
	ulong	errad;
	uchar	_pad2C[2];
	ushort	errat;
	ulong	piack;
	uchar	_pad34[12];

	struct {
		ushort	start;
		ushort	end;
		ushort	off;
		uchar	_pad;
		uchar	attr;
	} map[4];

	struct {
		ulong	cntl;
		uchar	_pad[3];
		uchar	stat;
	} wdt[2];

	ulong	gpr[4];
};

enum {
	/* map[] attr bits */
	Iom = (1<<0),
	Mem = (1<<1),
	Wpen = (1<<4),
	Wen = (1<<6),
	Ren = (1<<7),
};

static Raven *raven = (Raven*)RAVEN;
static ulong mpic;

static void
setmap(int i, ulong addr, ulong len, ulong busaddr, int attr)
{
	raven->map[i].start = addr>>16;
	raven->map[i].end = (addr+len-1)>>16;
	raven->map[i].off = (busaddr-addr)>>16;
	raven->map[i].attr = attr;
}

static ulong
swap32(ulong x)
{
	return (x>>24)|((x>>8)&0xff00)|((x<<8)&0xff0000)|(x<<24);
}

static ulong
mpic32r(int rno)
{
	return swap32(*(ulong*)(mpic+rno));
}

static void
mpic32w(int rno, ulong x)
{
	*(ulong*)(mpic+rno) = swap32(x);
	eieio();
}

void
raveninit(void)
{
	int i;
	Pcidev *p;

	if(raven->vid != 0x1057 || raven->did !=0x4801)
		panic("raven not found");

	/* set up a sensible hardware memory/IO map */
	setmap(0, PCIMEM0, PCISIZE0, 0, Wen|Ren|Mem);
	setmap(1, KZERO, IOSIZE, 0, Wen|Ren);	/* keeps PPCbug happy */
	setmap(2, PCIMEM1, PCISIZE1, PCISIZE0, Wen|Ren|Mem);
	setmap(3, IOMEM, IOSIZE, 0, Wen|Ren);	/* I/O must be slot 3 for PCI cfg space */

	p = pcimatch(nil, 0x1057, 0x4801);
	if(p == nil)
		panic("raven PCI regs not found");
	mpic = (p->mem[1].bar+PCIMEM0);

	/* ensure all interrupts are off, and routed to cpu 0 */
	for(i = 0; i < 16; i++) {
		mpic32w(0x10000+0x20*i, (1<<31));	/* mask */
		mpic32w(0x10010+0x20*i, 1);			/* route to cpu 0 */
	}

	mpic32w(0x20080, 1);			/* cpu 0 task pri */
//	mpic32w(0x21080, 1);			/* cpu 1 task pri */
	mpic32w(0x1020, (1<<29));		/* Mixed mode (8259 & Raven intrs both available) */
}

void
mpicenable(int vec)
{
	ulong x;

	x = (1<<22)|(15<<16)|vec;
	if(vec == 0)
		x |= (1<<23);
	mpic32w(0x10000+0x20*vec, x);
}

int
mpicintack(void)
{
	return mpic32r(0x200A0 + (m->machno<<12));
}

void
mpiceoi(void)
{
	mpic32w(0x200B0 + (m->machno<<12), 0);
}

M mtx/trap.c => mtx/trap.c +13 -65
@@ 26,11 26,13 @@ struct Handler

struct
{
	Handler	*ivec[128];
	Handler	*ivec[MaxVectorPIC+1];
	Handler	h[Maxhandler];
	int	free;
} halloc;

Lock	veclock;

void	faultpower(Ureg *ur, ulong addr, int read);
void	syscall(Ureg* ureg);
void	noted(Ureg*, ulong);


@@ 198,11 200,6 @@ spurious(Ureg *ur, void *a)
	panic("bad interrupt");
}

#define	LEV(n)	(((n)<<1)|1)
#define	IRQ(n)	(((n)<<1)|0)

Lock	veclock;

void
sethvec(int v, void (*r)(void))
{


@@ 242,92 239,43 @@ trapinit(void)
void
intrenable(int v, void (*r)(Ureg*, void*), void *arg, int, char *name)
{
#ifdef BLOG
	Handler *h;
	IMM *io;

	if(halloc.free >= Maxhandler)
		panic("out of interrupt handlers");
	v -= VectorPIC;
	if(v < 0 || v >= nelem(halloc.ivec))
		panic("intrenable(%d)", v+VectorPIC);
		panic("intrenable(%d)", v);
	ilock(&veclock);
	if(v < VectorCPIC || (h = halloc.ivec[v]) == nil){
		h = &halloc.h[halloc.free++];
		h->next = halloc.ivec[v];
		halloc.ivec[v] = h;
	}
	h = &halloc.h[halloc.free++];
	h->next = halloc.ivec[v];
	halloc.ivec[v] = h;
	h->r = r;
	h->arg = arg;

	/*
	 * enable corresponding interrupt in SIU/CPM
	 */

	eieio();
	io = m->iomem;
	if(v >= VectorCPIC){
		v -= VectorCPIC;
		io->cimr |= 1<<(v&0x1F);
	}
	else if(v >= VectorIRQ)
		io->simask |= 1<<(31-IRQ(v&7));
	else
		io->simask |= 1<<(31-LEV(v));
	eieio();
	iunlock(&veclock);
#endif
}

void
intr(Ureg *ur)
{
#ifdef BLOG
	int b, v;
	IMM *io;
	Handler *h;
	long t0;

	ur->cause &= ~0xff;
	io = m->iomem;
	b = io->sivec>>2;
	v = b>>1;
	if(b & 1) {
		if(v == CPIClevel){
			io->civr = 1;
			eieio();
			v = VectorCPIC+(io->civr>>11);
		}
	}else
		v += VectorIRQ;
	ur->cause |= v;
	h = halloc.ivec[v];
	if(h == nil){
		print("unknown interrupt %d pc=0x%lux\n", v, ur->pc);
		uartwait();
		return;
	}
	if(h->edge){
		io->sipend |= 1<<(31-b);
		eieio();

	v = mpicintack();
	if(v == 0) {			/* 8259 */
	}

	/*
	 *  call the interrupt handlers
	 */
	do {
/*	do {
		h->nintr++;
		t0 = getdec();
		(*h->r)(ur, h->arg);
		t0 -= getdec();
		h->ticks += t0;
		if(h->maxtick < t0)
			h->maxtick = t0;
		h = h->next;
	} while(h != nil);
	if(v >= VectorCPIC)
		io->cisr |= 1<<(v-VectorCPIC);
	eieio();
#endif
*/
}

int

M pc/pci.c => pc/pci.c +2 -0
@@ 1155,6 1155,8 @@ pcilhinv(Pcidev* p)
void
pcihinv(Pcidev* p)
{
	if(pcicfgmode == -1)
		pcicfginit();
	qlock(&pcicfginitlock);
	pcilhinv(p);
	qunlock(&pcicfginitlock);