📄 pci.c
字号:
/* 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 + -