📄 pciconfiglib.c
字号:
int vendorId, /* vendor ID */
int deviceId, /* device ID */
int index, /* desired instance of device */
int * pBusNo, /* bus number */
int * pDeviceNo, /* device number */
int * pFuncNo /* function number */
)
{
STATUS status = ERROR;
BOOL cont = TRUE;
int busNo;
int deviceNo;
int funcNo;
UINT32 device;
UINT32 vendor;
UINT8 header;
if (pciLibInitStatus != OK) /* sanity check */
cont = FALSE;
for (busNo = 0; cont == TRUE && busNo <= pciMaxBus; busNo++)
for (deviceNo = 0;
((cont == TRUE) && (deviceNo < PCI_MAX_DEV));
++deviceNo)
for (funcNo = 0; cont == TRUE && funcNo < PCI_MAX_FUNC; funcNo++)
{
/* avoid a special bus cycle */
if ((deviceNo == 0x1f) && (funcNo == 0x07))
continue;
pciConfigInLong (busNo, deviceNo, funcNo, PCI_CFG_VENDOR_ID,
&vendor);
/*
* If nonexistent device, skip to next, only look at
* vendor ID field for existence check
*/
if (((vendor & 0x0000ffff) == 0x0000FFFF) && (funcNo == 0))
break;
device = vendor >> 16;
device &= 0x0000FFFF;
vendor &= 0x0000FFFF;
if ((vendor == (UINT32)vendorId) &&
(device == (UINT32)deviceId) &&
(index-- == 0))
{
*pBusNo = busNo;
*pDeviceNo = deviceNo;
*pFuncNo = funcNo;
status = OK;
cont = FALSE; /* terminate all loops */
continue;
}
/* goto next if current device is single function */
pciConfigInByte (busNo, deviceNo, funcNo, PCI_CFG_HEADER_TYPE,
&header);
if ((header & PCI_HEADER_MULTI_FUNC) != PCI_HEADER_MULTI_FUNC &&
funcNo == 0)
break;
}
return (status);
}
/*******************************************************************************
*
* pciFindClass - find the nth occurence of a device by PCI class code.
*
* This routine finds the nth device with the given 24-bit PCI class code
* (class subclass prog_if).
*
* The classcode arg of must be carfully constructed from class and sub-class
* macros.
*
* Example : To find an ethernet class device, construct the classcode arg
* as follows:
*
* .CS
* ((PCI_CLASS_NETWORK_CTLR << 16 | PCI_SUBCLASS_NET_ETHERNET << 8))
* .CE
*
* RETURNS:
* OK, or ERROR if the class didn't match.
*/
STATUS pciFindClass
(
int classCode, /* 24-bit class code */
int index, /* desired instance of device */
int * pBusNo, /* bus number */
int * pDeviceNo, /* device number */
int * pFuncNo /* function number */
)
{
STATUS status = ERROR;
BOOL cont = TRUE;
int busNo;
int deviceNo;
int funcNo;
UINT32 classCodeReg;
UINT32 vendor;
UINT8 header;
if (pciLibInitStatus != OK) /* sanity check */
cont = FALSE;
for (busNo = 0; cont == TRUE && busNo <= pciMaxBus; busNo++)
for (deviceNo = 0;
((cont == TRUE) && (deviceNo < PCI_MAX_DEV));
++deviceNo)
for (funcNo = 0; cont == TRUE && funcNo < PCI_MAX_FUNC; funcNo++)
{
/* avoid a special bus cycle */
if ((deviceNo == 0x1f) && (funcNo == 0x07))
continue;
pciConfigInLong (busNo, deviceNo, funcNo, PCI_CFG_VENDOR_ID,
&vendor);
/*
* If nonexistent device, skip to next, only look at
* vendor ID field for existence check
*/
if (((vendor & 0x0000ffff) == 0x0000FFFF) && (funcNo == 0))
break;
pciConfigInLong (busNo, deviceNo, funcNo, PCI_CFG_REVISION,
&classCodeReg);
if ((((classCodeReg >> 8) & 0x00ffffff) == classCode) &&
(index-- == 0))
{
*pBusNo = busNo;
*pDeviceNo = deviceNo;
*pFuncNo = funcNo;
status = OK;
cont = FALSE; /* terminate all loops */
continue;
}
/* goto next if current device is single function */
pciConfigInByte (busNo, deviceNo, funcNo, PCI_CFG_HEADER_TYPE,
&header);
if ((header & PCI_HEADER_MULTI_FUNC) != PCI_HEADER_MULTI_FUNC &&
funcNo == 0)
break;
}
return (status);
}
/******************************************************************************
*
* pciDevConfig - configure a device on a PCI bus
*
* This routine configures a device that is on a Peripheral Component
* Interconnect (PCI) bus by writing to the configuration header of the
* selected device.
*
* It first disables the device by clearing the command register in the
* configuration header. It then sets the I/O and/or memory space base
* address registers, the latency timer value and the cache line size.
* Finally, it re-enables the device by loading the command register with
* the specified command.
*
* NOTE: This routine is designed for Type 0 PCI Configuration Headers ONLY.
* It is NOT usable for configuring, for example, a PCI-to-PCI bridge.
*
* RETURNS: OK always.
*/
STATUS pciDevConfig
(
int pciBusNo, /* PCI bus number */
int pciDevNo, /* PCI device number */
int pciFuncNo, /* PCI function number */
UINT32 devIoBaseAdrs, /* device IO base address */
UINT32 devMemBaseAdrs, /* device memory base address */
UINT32 command /* command to issue */
)
{
INT32 ix;
UINT32 tmp32;
/*
* Disable device by clearing its command register field in its
* configuration header. Write 0 clears command and preserves status.
*/
pciConfigOutLong (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_COMMAND,
0x0);
/*
* Due to system constraints, this is a partial implementation
* of enabling the Base Address Registers (BARs).
* It is hoped that all PCI devices only require at most one
* I/O space and/or one memory space.
* If not, this code will re-allocate the device's memory to
* each BAR implemented. Sounds like future trouble!
*/
for (ix = PCI_CFG_BASE_ADDRESS_0; ix <= PCI_CFG_BASE_ADDRESS_5; ix+=4)
{
/* Write all f's and read back value */
pciConfigOutLong (pciBusNo, pciDevNo, pciFuncNo, ix, 0xffffffff);
pciConfigInLong (pciBusNo, pciDevNo, pciFuncNo, ix, &tmp32);
/* BAR implemented? */
if (tmp32 == 0)
{
/*
* No! According to the spec, BARs must be implemented
* in sequence starting at BAR 0. So, all done.
*/
break;
}
/* I/O space requested? */
/* Yes, set specified I/O space base address */
if (tmp32 & 0x1)
{
pciConfigOutLong (pciBusNo, pciDevNo, pciFuncNo, ix,
devIoBaseAdrs | 0x1);
}
/* No, memory space required, set specified base address */
else
{
pciConfigOutLong (pciBusNo, pciDevNo, pciFuncNo, ix,
devMemBaseAdrs & ~0x1);
}
}
/* Configure Cache Line Size Register */
pciConfigOutByte (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_CACHE_LINE_SIZE,
PCI_CACHE_LINE_SIZE);
/* Configure Latency Timer */
pciConfigOutByte (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_LATENCY_TIMER,
PCI_LATENCY_TIMER);
/*
* Enable the device's capabilities as specified, do not
* reset any status bits in doing so.
*/
pciConfigModifyLong (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_COMMAND,
(PCI_CMD_MASK | command), command);
return (OK);
}
/*******************************************************************************
*
* pciConfigBdfPack - pack parameters for the Configuration Address Register
*
* This routine packs three parameters into one integer for accessing the
* Configuration Address Register
*
* RETURNS: packed integer encoded version of bus, device, and function numbers.
*/
int pciConfigBdfPack
(
int busNo, /* bus number */
int deviceNo, /* device number */
int funcNo /* function number */
)
{
return (((busNo << 16) & 0x00ff0000) |
((deviceNo << 11) & 0x0000f800) |
((funcNo << 8) & 0x00000700));
}
/*******************************************************************************
*
* pciConfigExtCapFind - find extended capability in ECP linked list
*
* This routine searches for an extended capability in the linked list of
* capabilities in config space. If found, the offset of the first byte
* of the capability of interest in config space is returned via pOffset.
*
* RETURNS: OK if Extended Capability found, ERROR otherwise
*/
STATUS pciConfigExtCapFind
(
UINT8 extCapFindId, /* Extended capabilities ID to search for */
int bus, /* PCI bus number */
int device, /* PCI device number */
int function, /* PCI function number */
UINT8 * pOffset /* returned config space offset */
)
{
STATUS retStat = ERROR;
UINT16 tmpStat;
UINT8 tmpOffset;
UINT8 capOffset = 0x00;
UINT8 capId = 0x00;
/* Check to see if the device has any extended capabilities */
pciConfigInWord(bus, device, function, PCI_CFG_STATUS, &tmpStat);
if ((tmpStat & PCI_STATUS_NEW_CAP) == 0)
{
return retStat;
}
/* Get the initial ECP offset and make longword aligned */
pciConfigInByte(bus, device, function, PCI_CFG_CAP_PTR, &capOffset);
capOffset &= ~0x02;
/* Bounds check the ECP offset */
if (capOffset < 0x40)
{
return retStat;
}
/* Look for the specified Extended Cap item in the linked list */
while (capOffset != 0x00)
{
/* Get the Capability ID and check */
pciConfigInByte(bus, device, function, (int)capOffset, &capId);
if (capId == extCapFindId)
{
*pOffset = (capOffset + (UINT8)0x02);
retStat = OK;
break;
}
/* Get the offset to the next New Capabilities item */
tmpOffset = capOffset + (UINT8)0x01;
pciConfigInByte(bus, device, function, (int)tmpOffset, &capOffset);
}
return retStat;
}
#ifndef USE_PCI_SIMULATOR
/*******************************************************************************
*
* pciConfigInByte - read one byte from the PCI configuration space
*
* This routine reads one byte from the PCI configuration space
*
* RETURNS: OK, or ERROR if this library is not initialized
*/
STATUS pciConfigInByte
(
int busNo, /* bus number */
int deviceNo, /* device number */
int funcNo, /* function number */
int offset, /* offset into the configuration space */
UINT8 * pData /* data read from the offset */
)
{
int key;
#if 0
UINT8 retval = 0;
UINT32 retvallong = 0;
STATUS retStat = ERROR;
if (pciLibInitStatus != OK) /* sanity check */
return (ERROR);
#endif
key = intLock (); /* mutual exclusion start */
#if 0
switch (pciConfigMech)
{
case PCI_MECHANISM_0:
if (pciConfigRead (busNo, deviceNo, funcNo,
offset, 1, (void *)&retval)
== ERROR)
{
retval = 0xff;
}
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -