📄 pciautoconfiglib.c
字号:
break;
else if ( pSystem->pciRollcallRtn () == TRUE )
break;
}
pciAutoFuncConfigAll (pSystem, pPciList, listSize);
lastPciListSize = listSize;
pLastPciList = pPciList;
/* If the function list is malloc'ed at runtime, then release it */
#if defined(PCI_AUTO_RECLAIM_LIST)
# if defined(PCI_AUTO_STATIC_LIST)
# error "Can't do PCI_AUTO_RECLAIM_LIST with PCI_AUTO_STATIC_LIST"
# endif
free(pPciList);
lastPciListSize = 0;
pLastPciList = NULL;
#endif
}
/******************************************************************************
*
* pciAutoListCreate - probe for all functions and make a PCI probe list
*
* This routine creates a dynamic probelist containing all PCI functions
* located in the PCI configuration hierarchy. In addition, it assigns
* base addresses for the 32-bit prefetchable memory allocation pool,
* the 32-bit non-prefetchable memory allocation pool, the 32-bit I/O
* allocation pool, and the 16-bit I/O allocation pool. When I/O space
* or memory space is actually assigned (not in this routine), the space
* allocation will begin with the base address in each of these categories
* and proceed to higher numbered addresses.
*
* Note that 20-bit memory space is not currently handled as a special case.
*
* RETURNS: pointer to newly populated PCI device list
*/
LOCAL PCI_LOC * pciAutoListCreate
(
PCI_SYSTEM * pSystem,
int *pListSize
)
{
PCI_LOC pciLoc; /* PCI bus/device/function structure */
PCI_LOC *pPciList;
PCI_LOC *pRetPciList;
/* Initialize the list pointer in preparation for probing */
#if defined(PCI_AUTO_STATIC_LIST)
pPciList = pciAutoLocalFuncList;
pRetPciList = pPciList;
#else
pPciList = malloc(sizeof(PCI_LOC) * PCI_AUTO_MAX_FUNCTIONS);
if (pPciList == NULL)
{
return NULL;
}
pRetPciList = pPciList;
#endif
lastPciListSize = 0;
*pListSize = 0;
/* Begin the scanning process at [0,0,0] */
pciLoc.bus = (UINT8)0;
pciLoc.device = (UINT8)0;
pciLoc.function = (UINT8)0;
/*
* Note that the host bridge is assumed to support 32-bit I/O addressing
* (PCI_AUTO_ATTR_BUS_4GB_IO) and prefetchable memory
* (PCI_AUTO_ATTR_BUS_PREFETCH)
*/
pciMaxBus = pciAutoDevProbe (pSystem, pciLoc.bus, (UCHAR)0,
(UCHAR)( PCI_AUTO_ATTR_BUS_4GB_IO |
PCI_AUTO_ATTR_BUS_PREFETCH),
&pPciList, pListSize);
pSystem->maxBus = pciMaxBus;
return (pRetPciList);
}
/******************************************************************************
*
* pciAutoDevReset - Quiesce a PCI device and reset all writeable status bits
*
* This routine turns 'off' a PCI device by disabling the Memory decoders, I/O
* decoders, and Bus Master capability. The routine also resets all writeable
* status bits in the status word that follows the command word sequentially
* in PCI config space by performing a longword access.
*
* RETURNS: OK, always
*/
STATUS pciAutoDevReset
(
PCI_LOC * pPciLoc /* device to be reset */
)
{
/* Disable the device and reset all writeable status bits */
pciConfigOutLong (pPciLoc->bus, pPciLoc->device,
pPciLoc->function,
PCI_CFG_COMMAND, 0xffff0000);
return OK;
}
/******************************************************************************
*
* pciAutoBusNumberSet - Set the primary, secondary, and subordinate bus number
*
* This routine sets the primary, secondary, and subordinate bus numbers for
* a device that implements the Type 1 PCI Configuration Space Header.
*
* This routine has external visibility to enable it to be used by BSP
* Developers for initialization of PCI Host Bridges that may implement
* registers similar to those found in the Type 1 Header.
*
* RETURNS: OK, always
*/
STATUS pciAutoBusNumberSet
(
PCI_LOC * pPciLoc,
UINT primary,
UINT secondary,
UINT subordinate
)
{
UINT workvar = 0; /* Working variable */
workvar = (subordinate << 16) + (secondary << 8) + primary;
/* longword write */
pciConfigModifyLong (pPciLoc->bus,
pPciLoc->device,
pPciLoc->function,
PCI_CFG_PRIMARY_BUS,
0x00ffffff,
workvar);
return OK;
}
/******************************************************************************
*
* pciAutoBusProbe - Configure a bridge and probe all devices behind it
*
* This routine assigns an initial range of subordinate busses to a
* PCI bridge, searches for functions under this bridge, and then
* updates the range assignment to the correct value. It calls
* pciAutoDevProbe() which in turn calls this function in a recursive
* manner. In addition to actually programming the PCI-PCI bridge
* headers with correct bus numbers, the 'pciLoc' list of functions
* is extended as each new PCI function is found.
*
* RETURNS: subordinate bus number.
*/
LOCAL UINT pciAutoBusProbe
(
PCI_SYSTEM * pSystem, /* PCI system information */
UINT priBus, /* Primary PCI bus */
UINT secBus, /* Secondary PCI bus */
PCI_LOC* pPciLoc, /* PCI address of this bridge */
PCI_LOC** ppPciList, /* Pointer to next PCI location */
/* entry pointer */
int * pListSize /* number of PCI_LOC entries */
)
{
UINT subBus = 0xff; /* Highest subordinate PCI bus */
UCHAR offset = 0; /* Interrupt routing offset for this bus*/
/* Disable I/O, Mem, and upstream transactions / reset status bits */
pciAutoDevReset (pPciLoc);
/* Set the bus numbers, subordinate bus is 0xff */
pciAutoBusNumberSet (pPciLoc, priBus, secBus, 0xff);
PCI_AUTO_DEBUG_MSG("pciAutoBusProbe: using bridge [%d,%d,%d,0x%02x]\n",
(pPciLoc->bus),
(pPciLoc->device),
(pPciLoc->function),
(pPciLoc->attribute),
0,
0
);
/* Probe all devices on this bus */
PCI_AUTO_DEBUG_MSG("pciAutoBusProbe: calling pciAutoDevProbe on bus [%d]\n",
secBus, 0, 0, 0, 0, 0);
/*
* compute the route offset for this bridge: if this is the
* first Pci-To-Pci Bridge to be discovered, then its contribution
* is null, otherwise it depends on its location on the bus and
* on the contribution of all of the upper Pci-To-Pci Bridges.
*/
pPciLoc->offset += (secBus > 1) ? (pPciLoc->device % 4) : 0;
offset = pPciLoc->offset;
PCI_AUTO_DEBUG_MSG("pciAutoBusProbe: int route offset for bridge is [%d]\n",
offset, 0, 0, 0, 0, 0);
subBus = pciAutoDevProbe (pSystem, secBus, offset, (pPciLoc->attribute),
ppPciList, pListSize);
/* Set the range assignment to cover the correct range of busses */
PCI_AUTO_DEBUG_MSG("pciAutoBusProbe: post-config subordinate bus as [%d]\n",
subBus, 0, 0, 0, 0, 0);
pciAutoBusNumberSet (pPciLoc, priBus, secBus, subBus);
/* Return the highest subordinate bus */
return subBus;
}
/******************************************************************************
*
* pciAutoDevProbe - Probe all devices on a single PCI bus.
*
* This routine probes a single PCI bus and adds each detected PCI function
* to the function list. In case a PCI-PCI bridge is found, pciAutoBusProbe()
* is called to probe that bus. pciAutoBusProbe() in turn calls this function
* in a recursive manner until all busses have been probed.
*
* RETURNS: Highest subordinate bus number found during probing process.
*/
LOCAL UINT pciAutoDevProbe
(
PCI_SYSTEM * pSystem, /* PCI system info */
UINT bus, /* current bus number to probe */
UCHAR offset, /* bridge contrib to int vector xlation */
UCHAR inheritAttrib, /* attributes inherited from bridge */
PCI_LOC **ppPciList, /* Pointer to next PCI location entry */
int * pListSize /* Number of PCI_LOC's currently in list*/
)
{
PCI_LOC pciLoc; /* PCI bus/device/function structure */
short pciclass; /* PCI class/subclass contents */
UINT dev_vend; /* Device/Vendor identifier */
int device; /* Device location */
int function; /* Function location */
int subBus; /* Highest subordinate PCI bus */
UCHAR btemp; /* Temporary holding area */
UINT temp;
/* Initialize variables */
bzero ((char *)&pciLoc, sizeof (PCI_LOC));
pciLoc.bus = bus;
subBus = bus;
/* if attributes indicate a host bus, then set equal to pciLoc.attrib */
/* Locate each active function on the current bus */
for (device = 0; device < PCI_MAX_DEV; device++)
{
pciLoc.device = device;
/* Check each function until an unused one is detected */
for (function = 0; function < PCI_MAX_FUNC; function++)
{
pciLoc.function = function;
/* Check for a valid device/vendor number */
pciConfigInLong (pciLoc.bus, pciLoc.device, pciLoc.function,
PCI_CFG_VENDOR_ID, &dev_vend);
/* If function 0 then check next dev else check next function */
if ( ((dev_vend & 0x0000ffff) == PCI_CONFIG_ABSENT_F) ||
((dev_vend & 0x0000ffff) == PCI_CONFIG_ABSENT_0) )
{
if (function == 0)
{
break; /* non-existent device, goto next device */
}
else
{
continue; /* function empty, try the next function */
}
}
/* store the translation offset for the int routing */
pciLoc.offset = offset;
pciLoc.attribute = 0;
/* Check to see if this function belongs to a PCI-PCI bridge */
pciConfigInWord (pciLoc.bus, pciLoc.device, pciLoc.function,
PCI_CFG_SUBCLASS, &pciclass);
/* Set Bridge device attributes for this device */
switch(pciclass)
{
/* PCI Host Bridge */
case ((PCI_CLASS_BRIDGE_CTLR << 8) + PCI_SUBCLASS_HOST_PCI_BRIDGE):
pciLoc.attribute |= ( PCI_AUTO_ATTR_DEV_EXCLUDE |
PCI_AUTO_ATTR_BUS_HOST );
break;
/* ISA Bridge */
case ((PCI_CLASS_BRIDGE_CTLR << 8) + PCI_SUBCLASS_ISA_BRIDGE):
pciLoc.attribute |= PCI_AUTO_ATTR_BUS_ISA;
break;
/* Display Device */
case (PCI_CLASS_DISPLAY_CTLR << 8):
pciLoc.attribute |= PCI_AUTO_ATTR_DEV_DISPLAY;
break;
/* PCI-to-PCI Bridge */
case ((PCI_CLASS_BRIDGE_CTLR << 8) + PCI_SUBCLASS_P2P_BRIDGE):
/* Setup and probe this bridge device */
pciLoc.attribute |= PCI_AUTO_ATTR_BUS_PCI;
/*
* Check for 32 bit I/O addressability,
* but only if the parent bridge supports it
*/
if (inheritAttrib & PCI_AUTO_ATTR_BUS_4GB_IO)
{
pciConfigInByte (pciLoc.bus,
pciLoc.device,
pciLoc.function,
PCI_CFG_IO_BASE, &btemp);
if ((btemp & 0x0F) == 0x01)
{
pciConfigInByte (pciLoc.bus,
pciLoc.device, pciLoc.function,
PCI_CFG_IO_LIMIT, &btemp);
if ((btemp & 0x0F) == 0x01)
{
pciLoc.attribute |= PCI_AUTO_ATTR_BUS_4GB_IO;
PCI_AUTO_DEBUG_MSG("pciAutoDevProbe: 4G I/O \n",
0, 0, 0, 0, 0, 0);
}
}
}
/* Disable prefetch */
pciConfigModifyLong (pciLoc.bus,
pciLoc.device,
pciLoc.function,
PCI_CFG_PRE_MEM_BASE,
0xfff0fff0, 0x0000fff0);
pciConfigOutLong (pciLoc.bus,
pciLoc.device,
pciLoc.function,
PCI_CFG_PRE_MEM_LIMIT_U, 0);
pciConfigOutLong (pciLoc.bus,
pciLoc.device,
pciLoc.function,
PCI_CFG_PRE_MEM_BASE_U, 0xffffffff);
/* Check for Prefetch memory support */
if (inheritAttrib & PCI_AUTO_ATTR_BUS_PREFETCH)
{
pciConfigInLong (pciLoc.bus,
pciLoc.device,
pciLoc.function,
PCI_CFG_PRE_MEM_BASE, &temp);
/* PF Registers return 0 if PF is not implemented */
if (temp != 0)
{
pciLoc.attribute |= PCI_AUTO_ATTR_BUS_PREFETCH;
PCI_AUTO_DEBUG_MSG("pciAutoDevProbe: PF present\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -