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

📄 pci.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
/* * PCI support code. * To do: *	initialise bridge mappings if the PCI BIOS didn't. */#include "all.h"#include "io.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 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);}static voidcmd_pcihinv(int argc, char *argv[]){	int i, flags = 0;	for (i = 1; i < argc; i++)		if (strcmp(argv[i], "-v") == 0)			flags |= 1;		else {			print("unknown pcihinv option %s; options are: -v\n", argv[i]);			return;		}	pcihinv(nil, flags);		/* print the whole device tree */}static intpciscan(int bno, Pcidev** list){	Pcidev *p, *head, *tail;	int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;	static int first = 1;	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 = ialloc(sizeof(*p), 0);			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->ccrb = pcicfgr8(p, PciCCRb);			p->pcr = pcicfgr32(p, PciPCR);			/* ccru is uchar in cpu kernel */			/* p->ccru = pcicfgr8(p, PciCCRu); */			p->ccru = pcicfgr16(p, PciCCRu);			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->ccru>>8){			case 0x01:		/* mass storage controller */			case 0x02:		/* network controller */			case 0x03:		/* display controller */			case 0x04:		/* multimedia device */			case 0x07:		/* simple communication 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->ccru != ((0x06<<8)|0x04))			continue;		/*		 * If the secondary or subordinate bus number is not initialized		 * 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 = pciscan(sbn, &p->bridge);			l = (maxubn<<16)|(sbn<<8)|bno;			pcicfgw32(p, PciPBN, l);		}		else{			maxubn = ubn;			pciscan(sbn, &p->bridge);		}	}	if (first) {		first = 0;		cmd_install("pcihinv", "-- print PCI bus device inventory",			cmd_pcihinv);	}	return maxubn;}static voidpcicfginit(void){	char *p;	int bno;	Pcidev **list;	lock(&pcicfginitlock);	if(pcicfgmode == -1){		/*		 * 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){			if(p = getconf("*pcimaxdno"))				pcimaxdno = strtoul(p, 0, 0);			list = &pciroot;			for(bno = 0; bno < 256; bno++){				bno = pciscan(bno, list);				while(*list)					list = &(*list)->link;			}						}	}	unlock(&pcicfginitlock);}static intpcicfgrw8(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;}intpcicfgr8(Pcidev* pcidev, int rno){	return pcicfgrw8(pcidev->tbdf, rno, 0, 1);}voidpcicfgw8(Pcidev* pcidev, int rno, int data){	pcicfgrw8(pcidev->tbdf, rno, data, 0);}static intpcicfgrw16(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;}intpcicfgr16(Pcidev* pcidev, int rno){	return pcicfgrw16(pcidev->tbdf, rno, 0, 1);}voidpcicfgw16(Pcidev* pcidev, int rno, int data){	pcicfgrw16(pcidev->tbdf, rno, data, 0);}static intpcicfgrw32(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;}intpcicfgr32(Pcidev* pcidev, int rno){	return pcicfgrw32(pcidev->tbdf, rno, 0, 1);}voidpcicfgw32(Pcidev* pcidev, int rno, int data){	pcicfgrw32(pcidev->tbdf, rno, data, 0);}voidpciclrmwi(Pcidev* p){	p->pcr &= ~MemWrInv;	pcicfgw16(p, PciPCR, p->pcr);}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;}static char *ccru2name(int ccru){	switch (ccru>>8) {	case 0x01:		/* mass storage controller */		return "disks";	case 0x02:		/* network controller */		return "net";	/* probably ether */	case 0x03:		/* display controller */		return "video";	case 0x04:		/* multimedia device */		return "audio";	case 0x07:		/* simple communication controllers */		return "serial";	case 0x08:		/* base system peripherals */		return "basic";	case 0x09:		/* input devices */		return "input";	case 0x0A:		/* docking stations */		return "dock";	case 0x0B:		/* processors */		return "cpu";	case 0x0C:		/* serial bus controllers */		return "usb";	case 0x00:	case 0x05:		/* memory controller */		return "memctl";	case 0x06:		/* bridge device */		return "bridge";	default:		return "*GOK*";	}}static char *vid2name(int vid){	switch (vid) {	case 0x1000:		return "ncr";	case 0x1002:		return "ati";	case 0x100b:		return "natsemi";	case 0x1011:		return "dec";	case 0x1013:		return "cirrus";	case 0x1022:		return "amd";	case 0x1023:		return "cyber?";	case 0x102b:		return "matrox";	case 0x102c:		return "hiq";	case 0x1039:		return "sis";	case 0x104b:		return "mylex";	case 0x105a:		return "promise";	case 0x105d:		return "number9";	case 0x10a9:		return "sgi";	case 0x10b7:		return "3com";	case 0x10c8:		return "neomagic";	/* or magicgraph */	case 0x10de:		return "nvidia";	case 0x11ab:		return "marvell";	case 0x11ad:		return "(pnic?)";	case 0x121a:		return "voodoo";	case 0x12ae:		return "alteon";	case 0x1385:		return "netgear";	case 0x15ad:		return "vmware";	case 0x16ec:		return "usrobot";	case 0x5333:			/* "S" "3".  har, har. */		return "s3";	case 0x8086:		return "intel";	default:		return "*GOK*";	}}voidpcihinv(Pcidev* p, ulong flags){	int i;	Pcidev *t;	if(p == nil) {		p = pciroot;		print("bus dev type ");		if (flags)			print("%7s", "");		print("vid  ");		if (flags)			print("%8s", "");		print("did intl memory\n");	}	for(t = p; t != nil; t = t->link) {		print("%d  %2d/%d %.4ux", BUSBNO(t->tbdf), BUSDNO(t->tbdf),			BUSFNO(t->tbdf), t->ccru);		if (flags)			print(" %-6s", ccru2name(t->ccru));		print(" %.4ux", t->vid);		if (flags)			print(" %-7s", vid2name(t->vid));		print(" %.4ux %2d  ", 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);		}		print("\n");	}	while(p != nil) {		if(p->bridge != nil)			pcihinv(p->bridge, flags);		p = p->link;	}}voidpcireset(void){	Pcidev *p;	int pcr;	if(pcicfgmode == -1)		pcicfginit();	for(p = pcilist; p != nil; p = p->list){		pcr = pcicfgr16(p, PciPSR);		pcicfgw16(p, PciPSR, pcr & ~0x04);	}}voidpcisetbme(Pcidev* p){	int pcr;	pcr = pcicfgr16(p, PciPCR);	pcr |= 0x04;	pcicfgw16(p, PciPCR, pcr);}voidpciclrbme(Pcidev* p){	p->pcr &= ~MASen;	pcicfgw16(p, PciPCR, p->pcr);}

⌨️ 快捷键说明

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