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

📄 pci.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * PCI support code. * To do: *	initialise bridge mappings if the PCI BIOS didn't. */#include "u.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "error.h"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 pcicfgrw32(int, int, int, int);static int pcicfgrw8(int, int, int, int);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);}intpciscan(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 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 and PCI-Cardbus 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.		 */		ubn = pcicfgr8(p, PciUBN);		sbn = pcicfgr8(p, PciSBN);		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 = pciscan(sbn, &p->bridge);			l = (maxubn<<16)|(sbn<<8)|bno;			pcicfgw32(p, PciPBN, l);		}		else{			/*			 * You can't go back.			 * This shouldn't be possible, but the			 * Iwill DK8-HTX seems to have subordinate			 * bus numbers which get smaller on the			 * way down. Need to look more closely at			 * this.			 */			if(ubn > maxubn)				maxubn = ubn;			pciscan(sbn, &p->bridge);		}	}	return maxubn;}static ucharnull_link(Pcidev *, uchar ){	return 0;}static voidnull_init(Pcidev *, uchar , uchar ){}static ucharpIIx_link(Pcidev *router, uchar link){	uchar pirq;	/* link should be 0x60, 0x61, 0x62, 0x63 */	pirq = pcicfgr8(router, link);	return (pirq < 16)? pirq: 0;}static voidpIIx_init(Pcidev *router, uchar link, uchar irq){	pcicfgw8(router, link, irq);}static ucharvia_link(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 voidvia_init(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 ucharopti_link(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 voidopti_init(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 ucharali_link(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 voidali_init(Pcidev *router, uchar link, uchar irq){	/* Inverse of map in ali_link */	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 ucharcyrix_link(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 voidcyrix_init(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 {	ushort	sb_vid, sb_did;	uchar	(*sb_translate)(Pcidev *, uchar);	void	(*sb_initialize)(Pcidev *, uchar, uchar);} bridge_t;static bridge_t southbridges[] = {	{ 0x8086, 0x122e, pIIx_link, pIIx_init },	// Intel 82371FB	{ 0x8086, 0x1234, pIIx_link, pIIx_init },	// Intel 82371MX	{ 0x8086, 0x7000, pIIx_link, pIIx_init },	// Intel 82371SB	{ 0x8086, 0x7110, pIIx_link, pIIx_init },	// Intel 82371AB	{ 0x8086, 0x7198, pIIx_link, pIIx_init },	// Intel 82443MX (fn 1)	{ 0x8086, 0x2410, pIIx_link, pIIx_init },	// Intel 82801AA	{ 0x8086, 0x2420, pIIx_link, pIIx_init },	// Intel 82801AB	{ 0x8086, 0x2440, pIIx_link, pIIx_init },	// Intel 82801BA	{ 0x8086, 0x244c, pIIx_link, pIIx_init },	// Intel 82801BAM	{ 0x8086, 0x2480, pIIx_link, pIIx_init },	// Intel 82801CA	{ 0x8086, 0x248c, pIIx_link, pIIx_init },	// Intel 82801CAM	{ 0x8086, 0x24c0, pIIx_link, pIIx_init },	// Intel 82801DBL	{ 0x8086, 0x24cc, pIIx_link, pIIx_init },	// Intel 82801DBM	{ 0x8086, 0x24d0, pIIx_link, pIIx_init },	// Intel 82801EB	{ 0x8086, 0x2640, pIIx_link, pIIx_init },	// Intel 82801FB	{ 0x8086, 0x27b9, pIIx_link, pIIx_init },	// Intel 82801GBM	{ 0x1106, 0x0586, via_link, via_init },		// Viatech 82C586	{ 0x1106, 0x0596, via_link, via_init },		// Viatech 82C596	{ 0x1106, 0x0686, via_link, via_init },		// Viatech 82C686	{ 0x1106, 0x3227, via_link, via_init },		// Viatech VT8237	{ 0x1045, 0xc700, opti_link, opti_init },	// Opti 82C700	{ 0x10b9, 0x1533, ali_link, ali_init },		// Al M1533	{ 0x1039, 0x0008, pIIx_link, pIIx_init },	// SI 503	{ 0x1039, 0x0496, pIIx_link, pIIx_init },	// SI 496	{ 0x1078, 0x0100, cyrix_link, cyrix_init },	// Cyrix 5530 Legacy	{ 0x1002, 0x4377, nil, nil },		// ATI Radeon Xpress 200M	{ 0x1022, 0x746B, nil, nil },		// AMD 8111	{ 0x10DE, 0x00D1, nil, nil },		// NVIDIA nForce 3	{ 0x1166, 0x0200, nil, nil },		// ServerWorks ServerSet III LE};typedef struct {	uchar	e_bus;			// Pci bus number	uchar	e_dev;			// Pci device number	uchar	e_maps[12];		// Avoid structs!  Link and mask.	uchar	e_slot;			// Add-in/built-in slot	uchar	e_reserved;} slot_t;typedef struct {	uchar	rt_signature[4];	// Routing table signature	uchar	rt_version[2];		// Version number	uchar	rt_size[2];			// Total table size	uchar	rt_bus;			// Interrupt router bus number	uchar	rt_devfn;			// Router's devfunc	uchar	rt_pciirqs[2];		// Exclusive PCI irqs	uchar	rt_compat[4];		// Compatible PCI interrupt router	uchar	rt_miniport[4];		// Miniport data	uchar	rt_reserved[11];	uchar	rt_checksum;} router_t;static ushort pciirqs;			// Exclusive PCI irqsstatic bridge_t *southbridge;	// Which southbridge to use.static voidpcirouting(void){	uchar *p, pin, irq;	ulong tbdf, vdid;	ushort vid, did;	router_t *r;	slot_t *e;	int size, i, fn;	Pcidev *sbpci, *pci;	// Peek in the BIOS	for (p = (uchar *)KADDR(0xf0000); p < (uchar *)KADDR(0xfffff); p += 16)		if (p[0] == '$' && p[1] == 'P' && p[2] == 'I' && p[3] == 'R')			break;	if (p >= (uchar *)KADDR(0xfffff))		return;	r = (router_t *)p;	// print("PCI interrupt routing table version %d.%d at %.6uX\n",	// 	r->rt_version[0], r->rt_version[1], (ulong)r & 0xfffff);	tbdf = (BusPCI << 24)|(r->rt_bus << 16)|(r->rt_devfn << 8);	vdid = pcicfgrw32(tbdf, PciVID, 0, 1);	vid = vdid;	did = vdid >> 16;	for (i = 0; i != nelem(southbridges); i++)		if (vid == southbridges[i].sb_vid && did == southbridges[i].sb_did)			break;	if (i == nelem(southbridges)) {		print("pcirouting: South bridge %.4uX, %.4uX not found\n", vid, did);		return;	}	southbridge = &southbridges[i];	if ((sbpci = pcimatch(nil, vid, did)) == nil) {		print("pcirouting: Cannot match south bridge %.4uX, %.4uX\n",			  vid, did);		return;	}	pciirqs = (r->rt_pciirqs[1] << 8)|r->rt_pciirqs[0];	size = (r->rt_size[1] << 8)|r->rt_size[0];	for (e = (slot_t *)&r[1]; (uchar *)e < p + size; e++) {		// print("%.2uX/%.2uX %.2uX: ", e->e_bus, e->e_dev, e->e_slot);		// for (i = 0; i != 4; i++) {		// 	uchar *m = &e->e_maps[i * 3];		// 	print("[%d] %.2uX %.4uX ",		// 		i, m[0], (m[2] << 8)|m[1]);		// }		// print("\n");		for (fn = 0; fn != 8; fn++) {			uchar *m;			// Retrieve the did and vid through the devfn before			// obtaining the Pcidev structure.			tbdf = (BusPCI << 24)|(e->e_bus << 16)|((e->e_dev | fn) << 8);			vdid = pcicfgrw32(tbdf, PciVID, 0, 1);			if (vdid == 0xFFFFFFFF || vdid == 0)				continue;			vid = vdid;			did = vdid >> 16;			pci = nil;			while ((pci = pcimatch(pci, vid, did)) != nil) {				if (pci->intl != 0 && pci->intl != 0xFF)					continue;				pin = pcicfgr8(pci, PciINTP);				if (pin == 0 || pin == 0xff)					continue;				m = &e->e_maps[(pin - 1) * 3];				irq = southbridge->sb_translate(sbpci, m[0]);				if (irq) {					print("pcirouting: %.4uX/%.4uX at pin %d irq %d\n",						  vid, did, pin, irq);					pcicfgw8(pci, PciINTL, irq);					pci->intl = irq;				}			}		}	}}static voidpcicfginit(void){	char *p;	int bno, n;	Pcidev **list;	lock(&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

⌨️ 快捷键说明

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