~kris/9p

9hist

b4ab588719514adc812c17357e29c0122bad8143 — David du Colombier 28 years ago 9898e6b
Plan 9 from Bell Labs 1997-10-11
10 files changed, 269 insertions(+), 156 deletions(-)

M pc/devvga.c
M pc/ether79c970.c
M pc/ether82557.c
M pc/etherelnk3.c
M pc/fns.h
M pc/io.h
M pc/memory.c
M pc/mmu.c
M pc/pci.c
M pc/trap.c
M pc/devvga.c => pc/devvga.c +8 -1
@@ 354,9 354,16 @@ vgactl(char *arg)
		if(mem == 0)
			error("not enough free address space");

		/*
		 * Be very careful here, upamalloc now returns a
		 * PHYSICAL address. This won't work once devices
		 * start mapping PCI framebuffers at the address
		 * the BIOS sets, but that hopefully will be after
		 * conversion to the Draw kernel.
		 */
		if(screenmem != SCREENMEM)
			upafree(screenmem, footprint);
		screenmem = mem;
		screenmem = (ulong)KADDR(mem);
		gscreen.base = (void*)screenmem;
		footprint = size;
		for(n = 0; n < 31; n++)

M pc/ether79c970.c => pc/ether79c970.c +15 -21
@@ 427,25 427,14 @@ amd79c970adapter(Block** bpp, int port, int irq, int tbdf)
	*bpp = bp;
}

static int
amd79c90(Ether* ether)
static void
amd79c970pci(void)
{
	static Pcidev *p;
	int irq, port;

	while(p = pcimatch(p, 0x1022, 0x2000)){
		port = p->bar[0] & ~0x01;
		irq = p->intl;
		if(ether->port == 0 || ether->port == port){
			ether->irq = irq;
			ether->tbdf = p->tbdf;
			return port;
		}

		amd79c970adapter(&adapter, port, irq, p->tbdf);
	}
	Pcidev *p;

	return 0;
	p = nil;
	while(p = pcimatch(p, 0x1022, 0x2000))
		amd79c970adapter(&adapter, p->mem[0].bar & ~0x01, p->intl, p->tbdf);
}

static int


@@ 456,11 445,16 @@ reset(Ether* ether)
	Adapter *ap;
	uchar ea[Eaddrlen];
	Ctlr *ctlr;
	static int scandone;

	if(scandone == 0){
		amd79c970pci();
		scandone = 1;
	}

	/*
	 * Any adapter matches if no ether->port is supplied, otherwise the
	 * ports must match. First see if an adapter that fits the bill has
	 * already been found. If not, scan for another.
	 * Any adapter matches if no port is supplied,
	 * otherwise the ports must match.
	 */
	port = 0;
	bpp = &adapter;


@@ 476,7 470,7 @@ reset(Ether* ether)
		}
		bpp = &bp->next;
	}
	if(port == 0 && (port = amd79c90(ether)) == 0)
	if(port == 0)
		return -1;

	/*

M pc/ether82557.c => pc/ether82557.c +4 -2
@@ 255,12 255,14 @@ command(Ctlr* ctlr, int c, int v)
	 * Only back-to-back CUresume can be done
	 * without waiting for any previous command to complete.
	 * This should be the common case.
	 */
	 * Unfortunately there's a chip errata where back-to-back
	 * CUresumes can be lost, the fix is to always wait.
	if(c == CUresume && ctlr->command == CUresume){
		csr8w(ctlr, CommandR, c);
		iunlock(&ctlr->rlock);
		return;
	}
	 */

	while(csr8r(ctlr, CommandR))
		;


@@ 757,7 759,7 @@ i82557pci(void)
		 * bar[1] is the I/O port register address (32 bytes) and
		 * bar[2] is for the flash ROM (1MB).
		 */
		i82557adapter(&adapter, p->bar[1] & ~0x01, p->intl, p->tbdf);
		i82557adapter(&adapter, p->mem[1].bar & ~0x01, p->intl, p->tbdf);
	}
}


M pc/etherelnk3.c => pc/etherelnk3.c +1 -1
@@ 1335,7 1335,7 @@ tcm59Xpci(void)

	p = nil;
	while(p = pcimatch(p, 0x10B7, 0)){
		port = p->bar[0] & ~0x01;
		port = p->mem[0].bar & ~0x01;
		irq = p->intl;
		COMMAND(port, GlobalReset, 0);
		while(STATUS(port) & commandInProgress)

M pc/fns.h => pc/fns.h +4 -0
@@ 57,6 57,8 @@ void	mathinit(void);
#define mmuflushtlb(pdb) putcr3(pdb)
void	meminit(ulong);
void	mmuinit(void);
ulong	mmukmap(ulong, ulong, int);
int	mmukmapsync(ulong);
#define	mmunewpage(x)
ulong*	mmuwalk(ulong*, ulong, int);
void	ns16552install(void);


@@ 69,12 71,14 @@ void	outs(int, ushort);
void	outss(int, void*, int);
void	outl(int, ulong);
void	outsl(int, void*, int);
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	pcihinv(Pcidev*);
Pcidev* pcimatch(Pcidev*, int, int);
void	pcireset(void);
PCMmap*	pcmmap(int, ulong, int, int);

M pc/io.h => pc/io.h +12 -3
@@ 131,11 131,20 @@ typedef struct Pcidev {
	int	tbdf;			/* type+bus+device+function */
	ushort	vid;			/* vendor ID */
	ushort	did;			/* device ID */
	ulong	bar[2];			/* base address */

	struct {
		ulong	bar;		/* base address */
		int	size;
	} mem[3];

	uchar	intl;			/* interrupt line */
	ushort	ccru;

	Pcidev*	next;			/* next device on this bno */
} Pcidev;

	Pcidev*	list;
	Pcidev*	bridge;			/* down a bus */
	Pcidev*	link;			/* next device on this bno */
};

/*
 * PCMCIA support code.

M pc/memory.c => pc/memory.c +27 -50
@@ 99,7 99,7 @@ dumpmembank(void)
#endif /* notdef */

void
mapfree(RMap* rmap, ulong addr, int size)
mapfree(RMap* rmap, ulong addr, ulong size)
{
	Map *mp;
	ulong t;


@@ 256,7 256,7 @@ ramscan(ulong maxmem)
	 * the BIOS data area.
	 */
	x = PADDR(CPU0MACH+BY2PG);
	bda = (uchar*)(KZERO|0x400);
	bda = (uchar*)KADDR(0x400);
	mapfree(&rmapram, x, ((bda[0x14]<<8)|bda[0x13])*KB-x);

	x = PADDR(PGROUND((ulong)end));


@@ 290,7 290,7 @@ ramscan(ulong maxmem)
	 * be written and read correctly. The page tables are created here
	 * on the fly, allocating from low memory as necessary.
	 */
	k0 = (ulong*)KZERO;
	k0 = (ulong*)KADDR(0);
	kzero = *k0;
	map = 0;
	x = 0x12345678;


@@ 383,47 383,11 @@ ramscan(ulong maxmem)
		mapfree(&rmapram, map, BY2PG);
	if(pa < maxmem)
		mapfree(&rmapupa, pa, maxmem-pa);
	if(maxmem < 0xFEC00000)
		mapfree(&rmapupa, maxmem, 0xFEC00000-maxmem);
	*k0 = kzero;
}

static void
upainit(void)
{
	ulong addr, pa, pae, *table, *va, x;

	/*
	 * Allocate an 8MB chunk aligned to 16MB. Later can
	 * make the region selectable via conf if necessary.
	 */
	if((addr = mapalloc(&rmapupa, 0, 8*MB, 16*MB)) == 0)
		return;

	pa = addr;
	pae = pa+(8*MB);
	while(pa < pae){
		va = KADDR(pa);
		table = &((ulong*)m->pdb)[PDX(va)];
		if((pa % (4*MB)) == 0 && (m->cpuiddx & 0x08)){
			*table = pa|PTESIZE|PTEWRITE|PTEUNCACHED|PTEVALID;
			pa += (4*MB);
		}
		else{
			if(*table == 0){
				if((x = mapalloc(&rmapram, 0, BY2PG, BY2PG)) == 0)
					break;
				memset(KADDR(x), 0, BY2PG);
				*table = x|PTEWRITE|PTEVALID;
			}
			table = (ulong*)(KZERO|PPN(*table));
			table[PTX(va)] = pa|PTEWRITE|PTEUNCACHED|PTEVALID;
			pa += BY2PG;
		}
	}

	mapfree(&xrmapupa, addr, pa-addr);
}


void
meminit(ulong maxmem)
{


@@ 448,7 412,6 @@ meminit(ulong maxmem)

	umbscan();
	ramscan(maxmem);
	upainit();

	/*
	 * Set the conf entries describing two banks of allocatable memory.


@@ 477,7 440,7 @@ umbmalloc(ulong addr, int size, int align)
	ulong a;

	if(a = mapalloc(&rmapumb, addr, size, align))
		return KZERO|a;
		return (ulong)KADDR(a);

	return 0;
}


@@ 485,7 448,7 @@ umbmalloc(ulong addr, int size, int align)
void
umbfree(ulong addr, int size)
{
	mapfree(&rmapumb, addr & ~KZERO, size);
	mapfree(&rmapumb, PADDR(addr), size);
}

ulong


@@ 495,7 458,7 @@ umbrwmalloc(ulong addr, int size, int align)
	uchar *p;

	if(a = mapalloc(&rmapumbrw, addr, size, align))
		return KZERO|a;
		return(ulong)KADDR(a);

	/*
	 * Perhaps the memory wasn't visible before


@@ 516,22 479,36 @@ umbrwmalloc(ulong addr, int size, int align)
void
umbrwfree(ulong addr, int size)
{
	mapfree(&rmapumbrw, addr & ~KZERO, size);
	mapfree(&rmapumbrw, PADDR(addr), size);
}

ulong
upamalloc(ulong addr, int size, int align)
{
	ulong a;
	ulong a, ae;

	if(a = mapalloc(&xrmapupa, addr, size, align))
		return KZERO|a;
		return (ulong)KADDR(a);

	return 0;
	if((a = mapalloc(&rmapupa, addr, size, align)) == 0)
		return 0;

	ae = mmukmap(a, 0, size);

	/*
	 * Should check here that it was all delivered
	 * and put it back and barf if not.
	 */
	USED(ae);

	/*
	 * Be very careful this returns a PHYSICAL address.
	 */
	return a;
}

void
upafree(ulong addr, int size)
{
	mapfree(&xrmapupa, addr & ~KZERO, size);
	mapfree(&xrmapupa, addr, size);
}

M pc/mmu.c => pc/mmu.c +97 -26
@@ 23,8 23,6 @@ Segdesc gdt[6] =
#define PDX(va)		((((ulong)(va))>>22) & 0x03FF)
#define PTX(va)		((((ulong)(va))>>12) & 0x03FF)

static int ptebits = 0;

static void
taskswitch(ulong pagetbl, ulong stack)
{


@@ 71,23 69,6 @@ mmuinit(void)
	ltr(TSSSEL);
}

ulong*
mmuwalk(ulong *pdb, ulong va, int create)
{
	ulong *table, x;

	table = &pdb[PDX(va)];
	if(*table == 0){
		if(create == 0)
			return 0;
		x = PADDR((ulong)xspanalloc(BY2PG, BY2PG, 0));
		*table = x|ptebits|PTEWRITE|PTEVALID;
	}
	table = (ulong*)(KZERO|PPN(*table));
	va = PTX(va);
	return &table[va];
}

void
flushmmu(void)
{


@@ 100,7 81,7 @@ flushmmu(void)
}

static void
mmuptefree(Proc *p)
mmuptefree(Proc* p)
{
	ulong *pdb;
	Page **lpg, *pg;


@@ 119,7 100,7 @@ mmuptefree(Proc *p)
}

void
mmuswitch(Proc *p)
mmuswitch(Proc* p)
{
	ulong *top;



@@ 138,7 119,7 @@ mmuswitch(Proc *p)
}

void
mmurelease(Proc *p)
mmurelease(Proc* p)
{
	Page *pg, *next;



@@ 216,7 197,7 @@ mmupdballoc(void)
}

void
putmmu(ulong va, ulong pa, Page *pg)
putmmu(ulong va, ulong pa, Page* pg)
{
	int pdbx;
	ulong *pdb, *pt;


@@ 237,17 218,107 @@ putmmu(ulong va, ulong pa, Page *pg)
			up->mmufree = pg->next;
			memset((void*)pg->va, 0, BY2PG);
		}
		pdb[pdbx] = PPN(pg->pa)|ptebits|PTEUSER|PTEWRITE|PTEVALID;
		pdb[pdbx] = PPN(pg->pa)|PTEUSER|PTEWRITE|PTEVALID;
		pg->daddr = pdbx;
		pg->next = up->mmuused;
		up->mmuused = pg;
	}

	pt = (ulong*)(PPN(pdb[pdbx])|KZERO);
	pt[PTX(va)] = pa|ptebits|PTEUSER;
	pt[PTX(va)] = pa|PTEUSER;

	s = splhi();
	pdb[PDX(MACHADDR)] = ((ulong*)m->pdb)[PDX(MACHADDR)];
	putcr3(up->mmupdb->pa);
	mmuflushtlb(up->mmupdb->pa);
	splx(s);
}

ulong*
mmuwalk(ulong* pdb, ulong va, int create)
{
	ulong pa, *table;

	table = &pdb[PDX(va)];
	if(*table == 0){
		if(create == 0)
			return 0;
		pa = PADDR((ulong)xspanalloc(BY2PG, BY2PG, 0));
		*table = pa|PTEWRITE|PTEVALID;
	}
	if(*table & PTESIZE)
		return table;

	table = (ulong*)(KZERO|PPN(*table));
	va = PTX(va);

	return &table[va];
}

static Lock mmukmaplock;

int
mmukmapsync(ulong va)
{
	Mach *mach0;
	ulong entry;

	mach0 = MACHP(0);

	lock(&mmukmaplock);

	if(mmuwalk(mach0->pdb, va, 0) == nil){
		unlock(&mmukmaplock);
		return 0;
	}
	entry = ((ulong*)mach0->pdb)[PDX(va)];

	if(!(((ulong*)m->pdb)[PDX(va)] & PTEVALID))
		((ulong*)m->pdb)[PDX(va)] = entry;

	if(up && up->mmupdb){
		((ulong*)up->mmupdb->va)[PDX(va)] = entry;
		mmuflushtlb(up->mmupdb->pa);
	}
	else
		mmuflushtlb(PADDR(m->pdb));

	unlock(&mmukmaplock);

	return 1;
}

ulong
mmukmap(ulong pa, ulong va, int size)
{
	Mach *mach0;
	ulong ova, pae, *table, pgsz, *pte;

	pa &= ~(BY2PG-1);
	if(va == 0)
		va = (ulong)KADDR(pa);
	va &= ~(BY2PG-1);
	ova = va;

	pae = pa + size;
	mach0 = MACHP(0);
	lock(&mmukmaplock);
	while(pa < pae){
		table = &((ulong*)mach0->pdb)[PDX(va)];
		if((pa % (4*MB)) == 0 && (mach0->cpuiddx & 0x08)){
			*table = pa|PTESIZE|PTEWRITE|PTEUNCACHED|PTEVALID;
			pgsz = 4*MB;
		}
		else{
			pte = mmuwalk(mach0->pdb, va, 1);
			*pte = pa|PTEWRITE|PTEUNCACHED|PTEVALID;
			pgsz = BY2PG;
		}
		pa += pgsz;
		va += pgsz;
	}
	unlock(&mmukmaplock);

	mmukmapsync(ova);

	return pa;
}

M pc/pci.c => pc/pci.c +97 -50
@@ 28,6 28,7 @@ static Lock pcicfginitlock;
static int pcicfgmode = -1;
static int pcimaxdno;
static Pcidev* pciroot;
static Pcidev* pcilist;

static int pcicfgrw8(int, int, int, int);
static int pcicfgrw16(int, int, int, int);


@@ 36,11 37,13 @@ static int pcicfgrw32(int, int, int, int);
static int
pciscan(int bno, Pcidev** list)
{
	ulong v;
	Pcidev *p, *head, *tail;
	int dno, fno, l, maxfno, maxubn, sbn, tbdf, ubn;
	int dno, fno, i, l, maxfno, maxubn, rno, sbn, tbdf, ubn;

	maxubn = bno;
	head = tail = 0;
	head = nil;
	tail = nil;
	for(dno = 0; dno <= pcimaxdno; dno++){
		maxfno = 0;
		for(fno = 0; fno <= maxfno; fno++){


@@ 59,30 62,30 @@ pciscan(int bno, Pcidev** list)
			p->tbdf = tbdf;
			p->vid = l;
			p->did = l>>16;
			p->bar[0] = pcicfgrw32(tbdf, PciBAR0, 0, 1);
			p->bar[1] = pcicfgrw32(tbdf, PciBAR1, 0, 1);
			p->intl = pcicfgrw8(tbdf, PciINTL, 0, 1);
			p->list = pcilist;
			pcilist = p;

			/*
			 * Read the base and sub- class and if the device is
			 * a bridge put it on a list of buses to be descended
			 * later.
			 * If it's not a bridge just add it to the tail of the
			 * device list.
			 */
			l = pcicfgrw16(tbdf, PciCCRu, 0, 1);
			if(l == ((0x06<<8)|0x04)){
				if(head)
					tail->next = p;
				else
					head = p;
				tail = p;
			}
			else{
				*list = p;
				list = &p->next;
			p->intl = pcicfgrw8(tbdf, PciINTL, 0, 1);
			p->ccru = pcicfgrw16(tbdf, PciCCRu, 0, 1);

			rno = PciBAR0 - 4;
			for(i = 0; i < nelem(p->mem); i++) {
				rno += 4;
				p->mem[i].bar = pcicfgrw32(tbdf, rno, 0, 1);
				if(i > 0 && p->ccru == ((0x06<<8)|0x04))
					continue;
				pcicfgrw32(tbdf, rno, -1, 0);
				v = pcicfgrw32(tbdf, rno, 0, 1);
				pcicfgrw32(tbdf, rno, p->mem[i].bar, 0);
				p->mem[i].size = -(v & ~0xF);
			}

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

			/*
			 * If the device is a multi-function device adjust the
			 * loop count so all possible functions are checked.


@@ 93,20 96,25 @@ pciscan(int bno, Pcidev** list)
		}
	}

	/*
	 * If any bridges were found, recursively descend the tree.
	 * The end result will be a single list of all devices in ascending
	 * bus number order.
	 */
	for(p = head; p; p = head){
	*list = head;
	for(p = head; p != nil; p = p->link){
		/*
		 * Take the primary bridge device off the bridge list
		 * and link to the end of the final device list.
		 * Find bridges and recursively descend the tree.
		 * Special case the Intel 82454GX Host-to-PCI bridge,
		 * there can be two of them.
		 * Otherwise, only descend PCI-to-PCI bridges.
		 */
		head = p->next;
		p->next = 0;
		*list = p;
		list = &p->next;
		if(p->ccru == ((0x06<<8)|0) && p->vid == 0x8086 && p->did == 0x84C4){
			tbdf = p->tbdf;
			if((sbn = pcicfgrw8(tbdf, 0x4A, 0, 1)) == 0)
				continue;
			ubn = pcicfgrw8(tbdf, 0x4B, 0, 1);
			maxubn = ubn;
			pciscan(sbn, &p->bridge);
			continue;
		}
		if(p->ccru != ((0x06<<8)|0x04))
			continue;

		/*
		 * If the secondary or subordinate bus number is not initialised


@@ 133,13 141,13 @@ pciscan(int bno, Pcidev** list)
			l = (MaxUBN<<16)|(sbn<<8)|bno;
			pcicfgrw32(tbdf, PciPBN, l, 0);
			pcicfgrw16(tbdf, PciSPSR, 0xFFFF, 0);
			maxubn = pciscan(sbn, list);
			maxubn = pciscan(sbn, &p->bridge);
			l = (maxubn<<16)|(sbn<<8)|bno;
			pcicfgrw32(tbdf, PciPBN, l, 0);
		}
		else{
			maxubn = ubn;
			pciscan(sbn, list);
			pciscan(sbn, &p->bridge);
		}
	}



@@ 348,27 356,36 @@ pcicfgw32(Pcidev* pcidev, int rno, int data)
	pcicfgrw32(pcidev->tbdf, rno, data, 0);
}

Pcidev*
pcimatch(Pcidev* previous, int vid, int did)
ulong
pcibarsize(Pcidev* p, int rno)
{
	Pcidev *p;
	ulong v, size;

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

	return -(size & ~0x0F);
}

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

	if(previous == 0)
		previous = pciroot;
	if(prev == nil)
		prev = pcilist;
	else
		previous = previous->next;
		prev = prev->list;

	for(p = previous; p; p = p->next) {
		if(p->vid != vid)
			continue;
		if(did == 0 || p->did == did)
	while(prev != nil) {
		if(prev->vid == vid && (did == 0 || prev->did == did))
			break;
		prev = prev->list;
	}

	return p;
	return prev;
}

void


@@ 380,12 397,42 @@ pcireset(void)
	if(pcicfgmode == -1)
		pcicfginit();

	for(p = pciroot; p; p = p->next){
	for(p = pcilist; p != nil; p = p->list){
		pcr = pcicfgr16(p, PciPSR);
		pcicfgw16(p, PciPSR, pcr & ~0x04);
	}
}

void
pcihinv(Pcidev* p)
{
	int i;
	Pcidev *t;

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

		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);
		}
		print("\n");
	}
	while(p != nil) {
		if(p->bridge != nil)
			pcihinv(p->bridge);
		p = p->link;
	}
}

/*
 * Hack for now to get SYMBIOS controller on-line.
 */

M pc/trap.c => pc/trap.c +4 -2
@@ 295,8 295,10 @@ fault386(Ureg* ureg, void*)
			postnote(up, 1, buf, NDebug);
			return;
		}
		dumpregs(ureg);
		panic("fault: 0x%lux\n", addr);
		if(mmukmapsync(addr) == 0){	
			dumpregs(ureg);
			panic("fault: 0x%lux\n", addr);
		}
	}
	up->insyscall = insyscall;
}