⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pci.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * PCI support code. * Needs a massive rewrite. */#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) pcilogstruct{	char	output[16384];	int	ptr;}PCICONS;intpcilog(char *fmt, ...){	int n;	va_list arg;	char buf[PRINTSIZE];	va_start(arg, fmt);	n = vseprint(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 Lock pcicfginitlock;static int pcicfgmode = -1;static int pcimaxbno = 7;static int pcimaxdno;static Pcidev* pciroot;static Pcidev* pcilist;static Pcidev* pcitail;static int nobios, nopcirouting;static int pcicfgrw32(int, int, int, int);static int pcicfgrw16(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"	intstatic inttbdffmt(Fmt* fmt){	char *p;	int l, r, type, tbdf;	if((p = malloc(READSTR)) == nil)		return fmtstrcpy(fmt, "(tbdfconv)");			switch(fmt->r){	case 'T':		tbdf = va_arg(fmt->args, 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;	}	r = fmtstrcpy(fmt, p);	free(p);	return r;}ulongpcibarsize(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 intpcisizcmp(void *a, void *b){	Pcisiz *aa, *bb;	aa = a;	bb = b;	return aa->siz - bb->siz;}static ulongpcimask(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 voidpcibusmap(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;	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) {//				DBG("pci: ignored bridge %T\n", p->tbdf);				continue;			}			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++;			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;			pcicfgrw16(p->tbdf, PciPCR, p->pcr, 0);			continue;		}		base = p->ioa.bar;		limit = base+p->ioa.size-1;		v = pcicfgrw32(p->tbdf, PciIBR, 0, 1);		v = (v&0xFFFF0000)|(limit & 0xF000)|((base & 0xF000)>>8);		pcicfgrw32(p->tbdf, PciIBR, v, 0);		v = (limit & 0xFFFF0000)|(base>>16);		pcicfgrw32(p->tbdf, PciIUBR, v, 0);		base = p->mema.bar;		limit = base+p->mema.size-1;		v = (limit & 0xFFF00000)|((base & 0xFFF00000)>>16);		pcicfgrw32(p->tbdf, PciMBR, v, 0);		/*		 * Disable memory prefetch		 */		pcicfgrw32(p->tbdf, PciPMBR, 0x0000FFFF, 0);		pcicfgrw8(p->tbdf, PciLTR, 64, 0);		/*		 * Enable the bridge		 */		p->pcr |= IOen|MEMen|MASen;		pcicfgrw32(p->tbdf, PciPCR, 0xFFFF0000|p->pcr , 0);		sioa = p->ioa.bar;		smema = p->mema.bar;		pcibusmap(p->bridge, &smema, &sioa, 1);	}}static intpcilscan(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->pcr = pcicfgr16(p, PciPCR);			p->rid = pcicfgr8(p, PciRID);			p->ccrp = pcicfgr8(p, PciCCRp);			p->ccru = pcicfgr8(p, PciCCRu);			p->ccrb = pcicfgr8(p, PciCCRb);			p->cls = pcicfgr8(p, PciCLS);			p->ltr = pcicfgr8(p, PciLTR);			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 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 */			case 0x06:		/* bridge device */			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 || nobios) {			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 {			if(ubn > maxubn)				maxubn = ubn;			pcilscan(sbn, &p->bridge);		}	}	return maxubn;}intpciscan(int bno, Pcidev **list){	int ubn;	lock(&pcicfginitlock);	ubn = pcilscan(bno, list);	unlock(&pcicfginitlock);	return ubn;}static uchar pIIxget(Pcidev *router, uchar link){	uchar pirq;	/* link should be 0x60, 0x61, 0x62, 0x63 */	pirq = pcicfgr8(router, link);	return (pirq < 16)? pirq: 0;}static void pIIxset(Pcidev *router, uchar link, uchar irq){	pcicfgw8(router, link, irq);}static uchar viaget(Pcidev *router, uchar link){	uchar pirq;	/* link should be 1, 2, 3, 5 */	pirq = (link < 6)? pcicfgr8(router, 0x55 + (link>>1)): 0;	return (link & 1)? (pirq >> 4): (pirq & 15);}static void viaset(Pcidev *router, uchar link, uchar irq){	uchar pirq;	pirq = pcicfgr8(router, 0x55 + (link >> 1));	pirq &= (link & 1)? 0x0f: 0xf0;	pirq |= (link & 1)? (irq << 4): (irq & 15);	pcicfgw8(router, 0x55 + (link>>1), pirq);}static uchar optiget(Pcidev *router, uchar link){	uchar pirq = 0;	/* link should be 0x02, 0x12, 0x22, 0x32 */	if ((link & 0xcf) == 0x02)		pirq = pcicfgr8(router, 0xb8 + (link >> 5));	return (link & 0x10)? (pirq >> 4): (pirq & 15);}static void optiset(Pcidev *router, uchar link, uchar irq){	uchar pirq;	pirq = pcicfgr8(router, 0xb8 + (link >> 5));    	pirq &= (link & 0x10)? 0x0f : 0xf0;    	pirq |= (link & 0x10)? (irq << 4): (irq & 15);	pcicfgw8(router, 0xb8 + (link >> 5), pirq);}static uchar aliget(Pcidev *router, uchar link){	/* No, you're not dreaming */	static const uchar map[] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };	uchar pirq;	/* link should be 0x01..0x08 */	pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));	return (link & 1)? map[pirq&15]: map[pirq>>4];}static void aliset(Pcidev *router, uchar link, uchar irq){	/* Inverse of map in aliget */	static const uchar map[] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };	uchar pirq;	pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));	pirq &= (link & 1)? 0x0f: 0xf0;	pirq |= (link & 1)? (map[irq] << 4): (map[irq] & 15);	pcicfgw8(router, 0x48 + ((link-1)>>1), pirq);}static uchar cyrixget(Pcidev *router, uchar link){	uchar pirq;	/* link should be 1, 2, 3, 4 */	pirq = pcicfgr8(router, 0x5c + ((link-1)>>1));	return ((link & 1)? pirq >> 4: pirq & 15);}static void cyrixset(Pcidev *router, uchar link, uchar irq){	uchar pirq;	pirq = pcicfgr8(router, 0x5c + (link>>1));	pirq &= (link & 1)? 0x0f: 0xf0;	pirq |= (link & 1)? (irq << 4): (irq & 15);	pcicfgw8(router, 0x5c + (link>>1), pirq);}typedef struct Bridge Bridge;struct Bridge{	ushort	vid;	ushort	did;	uchar	(*get)(Pcidev *, uchar);	void	(*set)(Pcidev *, uchar, uchar);	};static Bridge southbridges[] = {	{ 0x8086, 0x122e, pIIxget, pIIxset },	// Intel 82371FB	{ 0x8086, 0x1234, pIIxget, pIIxset },	// Intel 82371MX	{ 0x8086, 0x7000, pIIxget, pIIxset },	// Intel 82371SB	{ 0x8086, 0x7110, pIIxget, pIIxset },	// Intel 82371AB	{ 0x8086, 0x7198, pIIxget, pIIxset },	// Intel 82443MX (fn 1)	{ 0x8086, 0x2410, pIIxget, pIIxset },	// Intel 82801AA	{ 0x8086, 0x2420, pIIxget, pIIxset },	// Intel 82801AB	{ 0x8086, 0x2440, pIIxget, pIIxset },	// Intel 82801BA	{ 0x8086, 0x244c, pIIxget, pIIxset },	// Intel 82801BAM	{ 0x8086, 0x2480, pIIxget, pIIxset },	// Intel 82801CA	{ 0x8086, 0x248c, pIIxget, pIIxset },	// Intel 82801CAM	{ 0x8086, 0x24c0, pIIxget, pIIxset },	// Intel 82801DBL	{ 0x8086, 0x24cc, pIIxget, pIIxset },	// Intel 82801DBM	{ 0x8086, 0x24d0, pIIxget, pIIxset },	// Intel 82801EB	{ 0x8086, 0x2640, pIIxget, pIIxset },	// Intel 82801FB	{ 0x8086, 0x27b9, pIIxget, pIIxset },	// Intel 82801GBM	{ 0x1106, 0x0586, viaget, viaset },	// Viatech 82C586	{ 0x1106, 0x0596, viaget, viaset },	// Viatech 82C596	{ 0x1106, 0x0686, viaget, viaset },	// Viatech 82C686	{ 0x1106, 0x3227, viaget, viaset },	// Viatech VT8237	{ 0x1045, 0xc700, optiget, optiset },	// Opti 82C700	{ 0x10b9, 0x1533, aliget, aliset },	// Al M1533	{ 0x1039, 0x0008, pIIxget, pIIxset },	// SI 503	{ 0x1039, 0x0496, pIIxget, pIIxset },	// SI 496	{ 0x1078, 0x0100, cyrixget, cyrixset },	// Cyrix 5530 Legacy	{ 0x1022, 0x746B, nil, nil },		// AMD 8111	{ 0x10DE, 0x00D1, nil, nil },		// NVIDIA nForce 3	{ 0x1166, 0x0200, nil, nil },		// ServerWorks ServerSet III LE	{ 0x1002, 0x4377, nil, nil },		// ATI Radeon Xpress 200M};typedef struct Slot Slot;struct Slot {	uchar	bus;			// Pci bus number	uchar	dev;			// Pci device number	uchar	maps[12];		// Avoid structs!  Link and mask.	uchar	slot;			// Add-in/built-in slot	uchar	reserved;};typedef struct Router Router;struct Router {	uchar	signature[4];		// Routing table signature	uchar	version[2];		// Version number	uchar	size[2];		// Total table size	uchar	bus;			// Interrupt router bus number	uchar	devfn;			// Router's devfunc	uchar	pciirqs[2];		// Exclusive PCI irqs	uchar	compat[4];		// Compatible PCI interrupt router	uchar	miniport[4];		// Miniport data	uchar	reserved[11];	uchar	checksum;};static ushort pciirqs;			// Exclusive PCI irqsstatic Bridge *southbridge;		// Which southbridge to use.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -