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

📄 pci.c

📁 umon bootloader source code, support mips cpu.
💻 C
📖 第 1 页 / 共 2 页
字号:
/* pci.c:
 * This file provides the monitor with a reusable mechanism for
 * interfacing with a PCI bus.  Four target-specific functions are
 * required:
 *
 *	pciCtrl(), pciCfgRead(), pciCfgWrite(), pciShow()
 *
 * The two most important are pciCfgRead() and pciCfgWrite().  Refer to
 * the bottom of pci.h for further details.
 */
#include "config.h"
#include "pci.h"
#include "stddefs.h"
#include "genlib.h"
#include "cli.h"

int pciVerbose;
int pciBusNum;

#define IMPLEMENTED	0x80000000

#ifdef USE_DEFAULT_PCISHOW
void
pciShow(int interface)
{
	printf("No fixed devices on this platform\n");
}
#endif

/* pciCfgAddress():
 * Return a 32-bit value based on the input 
 * bus number, device number, function number and register
 * number:
 *
 *  31 30 .... 24 23 ... 16 15 ... 11 10 ....  8 7 ...    2 1 0
 * --------------------------------------------------------------
 * |  |          |  Bus    | Device  | Function | Register |0|T|
 * |En| Reserved |  Number | Number  | Number   | Number   | | |
 * --------------------------------------------------------------
 *  ^                                                         ^
 *  |---- Enable bit 1=enabled, 0=disabled                    |
 *                                                            |
 *       Type0: 0 --------------------------------------------|
 *       Type1: 1 --------------------------------------------|
 *
 * See pg 32 of the PCI2.2 spec for more details.
 */

unsigned long
pciCfgAddress(int busno,int devno,int fncno,int regno)
{
	int	type;

	if (busno > 0)
		type = 1;
	else
		type = 0;

	return((type | PCICFG_ENABLE_BIT |
			((busno & PCICFG_BUSNO_MASK) << PCICFG_BUSNO_SHIFT) |
			((devno & PCICFG_DEVNO_MASK) << PCICFG_DEVNO_SHIFT) |
			((fncno & PCICFG_FNCNO_MASK) << PCICFG_FNCNO_SHIFT) |
			((regno & PCICFG_REGNO_MASK) << PCICFG_REGNO_SHIFT)));
}

/* pciBaseClass():
 * Based on appendix D of spec, return a simple string that describes
 * the base class of the incoming class code.
 */
char *
pciBaseClass(unsigned long classcode)
{
	unsigned long baseclass;
	unsigned long subclass_progif;

	baseclass = (classcode >> 16) & 0xff;
	subclass_progif = classcode & 0xffff;

	switch(baseclass) {
		case 0:
			return("pre-class-code-definitions");
		case 1:
			return("mass storage ctrlr");
		case 2:
			return("network ctrlr");
		case 3:
			return("display ctrlr");
		case 4:
			return("multimedia device");
		case 5:
			return("memory ctrlr");
		case 6:	/* Supply additional information for bridge class...
				 */
			switch(subclass_progif) {
				case 0x0000:
					return("host/pci bridge");
				case 0x0100:
					return("pci/isa bridge");
				case 0x0200:
					return("pci/eisa bridge");
				case 0x0300:
					return("pci/microchannel bridge");
				case 0x0400:
					return("pci/pci bridge");
				case 0x0500:
					return("pci/pcmcia bridge");
				case 0x0600:
					return("pci/nubus bridge");
				case 0x0700:
					return("pci/cardbus bridge");
				case 0x8000:
					return("other bridge type");
				default:
					return("bridge device");
			}
		case 7:
			return("simple communication ctrlr");
		case 8:
			return("base system peripheral");
		case 9:
			return("input device");
		case 10:
			return("docking station");
		case 11:
			return("processor");
		case 12:
			return("serial bus ctrlr");
		case 13:
			return("wireless ctrlr");
		case 14:
			return("intelligent io ctrlr");
		case 15:
			return("satellite communication ctrlr");
		case 16:
			return("encrypt/decrypt ctrlr");
		case 17:
			return("data acquisition ctrlr");
		case 256:
			return("no fit");
		default:
			return("reserved");
	}
}

/* pciscan():
 * This function is used by "pci scan" and "pci enum" to look
 * at the devices on the pci bus.  When the enumerate flag is set,
 * this function will recursively nest itself each time it sees a
 * PCI-to-PCI bridge device on the bus, and while doing this, it will
 * assign bus numbers to each bridge appropriately.  This function does
 * not assign address ranges or anything else, it simply provides a quick
 * means of scanning all devices on the bus(es).
 * 
 * NOTE: This has only been tested with simple PCI bus configurations (one
 * bridge deep) so deeper configurations (bridges on bridges on bridges...)
 * are untested as far as I know.
 */
void
pciscan(long interface, long bus, long func, int showhdr, int enumerate)
{
	long	device;
	uchar	hdr_type, rev_id;
	ushort	vendor_id, device_id;
	ulong	value, class_code;

	if (showhdr) {
		printf("\nInterface %ld...\n",interface);
		printf("Bus Dev Vndr  Dev   Rev Hdr  Class\n");  
		printf("Num Num Id    Id    Id  Type Code\n");  
	}

	if ((enumerate == 1) && (bus == 0))
		pciBusNum = 0;

	for(device=0;device<=31;device++) {
		/* Retrieve portions of the configuration header that
		 * are required by all PCI compliant devices...
		 * Vendor, Device and Revision IDs, Class Code and Header Type
		 * (see pg 191 of spec).
		 */

		/* Read reg_0 for vendor and device ids:
		 */
		value = pciCfgRead(interface,bus,device,func,0);
		if (value == NO_DEVICE)
			continue;

		vendor_id = (ushort)(value & 0xffff);
		device_id = (ushort)((value>>16) & 0xffff);

		/* Read reg_2 for class code and revision id:
		 */
		value = pciCfgRead(interface,bus,device,func,2);
		rev_id = (uchar)(value & 0xff);
		class_code = (ulong)((value>>8) & 0xffffff);

		/* Read reg_3:  header type:
		 */
		value = pciCfgRead(interface,bus,device,func,3);
		hdr_type = (uchar)((value>>16) & 0xff);
			
		printf("%2ld  %02ld  x%04x x%04x",bus,
			device,vendor_id,device_id);
		printf(" x%02x x%02x  x%06lx (%s)\n",rev_id,
			hdr_type,class_code,pciBaseClass(class_code));

		/* If enumeration is enabled, see if this is a PCI-to-PCI
		 * bridge.  If it is, then nest into pciscan...
		 */
		if ((enumerate) && (class_code == 0x060400)) {
			ulong pribus, secbus, subbus;

			pribus = pciBusNum & 0x0000ff;
			pciBusNum++;
			secbus = ((pciBusNum << 8) & 0x00ff00);
			subbus = ((pciBusNum << 16) & 0xff0000);

			value = pciCfgRead(interface,bus,device,func,6);
			value &= 0xffff0000;
			value |= (pribus | secbus);
			pciCfgWrite(interface,bus,device,func,6,value);

			pciscan(interface,pciBusNum,func,0,1);

			value = pciCfgRead(interface,bus,device,func,6);
			value &= 0xff000000;
			value |= (subbus | pribus | secbus);
			pciCfgWrite(interface,bus,device,func,6,value);
		}
	}
}

/* getBarInfo():
 * Apply the algorithm as specified in PCI spec...
 * Place size information in sizehi & sizelo (to support 64-bit).
 * Return 0 if not implemented; else return value to indicate
 * size (32 or 64 bit) and type (mem or io).
 */
ulong
getBarInfo(long interface,long bus,long device,long func,int barnum,
	ulong *sizehi, ulong *sizelo)
{
	int barregno;
	ulong implemented, barval1, barval2, barinfo1, barinfo2, cmd;

	/* Translate the incoming bar number to a register number
	 * in PCI config space:
	 */
	barregno = barnum + 4;

	/* Disable decoding through the command register:
	 */
	cmd = pciCfgRead(interface,bus,device,func,1);
	pciCfgWrite(interface,bus,device,func,1,
		cmd & ~(IO_SPACE | MEMORY_SPACE));

	/* Read the BAR:
	 */
	barval1 = pciCfgRead(interface,bus,device,func,barregno);

	/* Write 0xffffffff to the BAR:
	 */
	pciCfgWrite(interface,bus,device,func,barregno,0xffffffff);

	/* Read the value returned as a result of writing
	 * 0xffffffff to the BAR:
	 */
	barinfo1 = pciCfgRead(interface,bus,device,func,barregno);

	/* Restore original bar:
	 */
	pciCfgWrite(interface,bus,device,func,barregno,barval1);

	if (barinfo1 == 0) {
		implemented = 0;
	}
	else {
		implemented = IMPLEMENTED;

		if (barval1 & BASEADDRESS_IO) {
			implemented |= BASEADDRESS_IO;

			if (sizelo) {
				/* Clear encoding bits:
				 */
				barinfo1 &= 0xfffffffe;
				/* Invert and add 1:
				 */
				*sizelo = (~barinfo1 + 1) & 0xffff;
	
				if (sizehi)
					*sizehi = 0;
			}
		}
		else {
			implemented |= (barinfo1 & PREFETCHABLE);

			if (barval1 & TYPE_64) {
				implemented |= TYPE_64;

				/* Apply same sequence as above to the next bar...
				 */
				barregno++;
				barval2 = pciCfgRead(interface,bus,device,func,barregno);
				pciCfgWrite(interface,bus,device,func,barregno,0xffffffff);
				barinfo2 = pciCfgRead(interface,bus,device,func,barregno);
				pciCfgWrite(interface,bus,device,func,barregno,barval2);
	
	
				if (sizelo) {
					barinfo1 &= 0xfffffff0;
					*sizelo = ~barinfo1 + 1;
					if (sizehi)
						*sizehi = ~barinfo2 + 1;
				}
			}
			else {
				if (sizelo) {
					barinfo1 &= 0xfffffff0;
					*sizelo = ~barinfo1 + 1;
	
					if (sizehi)
						*sizehi = 0;
				}
			}
		}
	}

	/* Now that we've completed messing with the BARS,
	 * restore original cmd:
	 */
	pciCfgWrite(interface,bus,device,func,1,cmd);

	return(implemented);
}

int
showBar(int barnum,long interface,long bus,long device,long func)
{
	int	rtot;
	ulong bar, barnext, sizehi, sizelo, implemented;

	if ((barnum < 0) || (barnum > 5))
		return(-1);

	bar = pciCfgRead(interface,bus,device,func,barnum+4);

	implemented = getBarInfo(interface,bus,device,func,
			barnum,&sizehi,&sizelo);

	if (!implemented) {
		printf("BAR%d  : not implemented\n",barnum);
		return(0);
	}

	if (!(implemented & BASEADDRESS_IO) && (implemented & TYPE_64)) {
		barnext = pciCfgRead(interface,bus,device,func,barnum+5);
		printf("BAR%d-%d: 0x%08lx 0x%08lx", barnum,barnum+1,bar,barnext);
	}
	else {

⌨️ 快捷键说明

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