📄 pciautoconfiglib.c
字号:
if ((classCode & mask) == (pciClass & mask))
{
*index = i;
*pPciFunc = pciList[i];
return (TRUE);
}
}
return (FALSE);
}
/******************************************************************************
*
* pciAutoDevConfig - Allocate memory and I/O space to PCI function.
*
* This routine allocates memory and I/O space to functions on an
* individual PCI bus.
*
* LIMITATIONS:
*
* do not sort the include function list before this routine is
* called. This routine requires each function in the list to be in the
* same order as the probe occurred.
*
* RETURNS: N/A.
*/
LOCAL void pciAutoDevConfig
(
PCI_SYSTEM * pSystem, /* PCI system info */
UINT bus, /* Current bus number */
PCI_LOC **ppPciList, /* Pointer to function list */
UINT *nSize /* Number of remaining funcs */
)
{
PCI_LOC *pPciFunc; /* Pointer to PCI function */
UINT nextBus; /* Bus where function is located */
short pciClass; /* Class field of function */
/* Process each function within the list */
while (*nSize > 0)
{
/* Setup local variables */
pPciFunc = *ppPciList;
nextBus = pPciFunc->bus;
/* Decrease recursion depth if this function is on a parent bus */
if (nextBus < bus)
{
return;
}
/* Allocate and assign space to functions on this bus */
pciAutoFuncConfig (pSystem, pPciFunc);
(*nSize)--;
(*ppPciList)++;
/* Increase recursion depth if this function is a PCI-PCI bridge */
pciConfigInWord (pPciFunc->bus, pPciFunc->device, pPciFunc->function,
PCI_CFG_SUBCLASS, &pciClass);
switch (pciClass)
{
case (( PCI_CLASS_BRIDGE_CTLR << 8) + PCI_SUBCLASS_P2P_BRIDGE ):
/* PCI-PCI bridge functions increase recursion depth */
pciAutoBusConfig (pSystem, pPciFunc, ppPciList, nSize);
break;
default:
/* Maintain current recursion depth */
break;
}
}
}
/******************************************************************************
*
* pciAutoFuncConfig - Assign memory and/or I/O space to single function.
*
* This routine allocates and assigns memory and/or I/O space to a
* single PCI function. Allocations are made for each implemented
* base address register (BAR) in the PCI configuration header.
*
* RETURNS: N/A.
*/
LOCAL void pciAutoFuncConfig
(
PCI_SYSTEM * pSystem,
PCI_LOC * pPciFunc /* input: "Include list" pointer to function */
)
{
UINT baMax; /* Total number of base addresses */
UINT baI; /* Base address register index */
UINT baseAddr; /* PCI Offset of base address */
UINT readVar; /* Contents of base address register */
UINT addrInfo; /* PCI address type information */
UINT sizeMask; /* LSbit for size calculation */
UCHAR headerType; /* Read from PCI config header */
UINT dev_vend;
/* If there is a function, then consult the exclusion routine */
if ( (pSystem->includeRtn) != NULL )
{
pciConfigInLong (pPciFunc->bus, pPciFunc->device, pPciFunc->function,
PCI_CFG_VENDOR_ID, &dev_vend);
if ( ((pSystem->includeRtn) (pSystem, pPciFunc, dev_vend)) == ERROR )
{
if ((pPciFunc->attribute & PCI_AUTO_ATTR_BUS_PCI) == 0)
{
pPciFunc->attribute |= PCI_AUTO_ATTR_DEV_EXCLUDE;
PCI_AUTO_DEBUG_MSG("pciAutoFuncConfig: exc [%d,%d,%d,0x%02x]\n",
pPciFunc->bus, pPciFunc->device, pPciFunc->function,
pPciFunc->attribute,0,0);
return;
}
}
}
/* Disable the function */
pciAutoFuncDisable (pPciFunc);
/* Determine the number of base address registers present */
pciConfigInByte (pPciFunc->bus, pPciFunc->device, pPciFunc->function,
PCI_CFG_HEADER_TYPE, &headerType);
headerType &= 0x7f;
switch (headerType)
{
case PCI_HEADER_TYPE0:
baMax = 6;
break;
case PCI_HEADER_PCI_PCI:
baMax = 2;
break;
default:
baMax = 0;
break;
}
/* Allocate Memory or I/O space for each implemented base addr register */
for (baI = 0; baI < baMax; baI++)
{
/* Get the base address register contents */
baseAddr = PCI_CFG_BASE_ADDRESS_0 + (baI * 4);
pciConfigOutLong (pPciFunc->bus, pPciFunc->device, pPciFunc->function,
baseAddr, 0xFFFFFFFF);
pciConfigInLong (pPciFunc->bus, pPciFunc->device, pPciFunc->function,
baseAddr, &readVar);
/* Go to the next BAR when an unimplemented one (BAR==0) is found */
if (readVar == 0)
{
continue;
}
/* Mask off all but space, memory type, and prefetchable bits */
addrInfo = readVar & PCI_BAR_ALL_MASK;
/* Check for type, setup mask variables (based on type) */
if ((addrInfo & PCI_BAR_SPACE_MASK) == PCI_BAR_SPACE_IO)
{
PCI_AUTO_DEBUG_MSG("pciAutoFuncConfig: IO Space found at BAR[%d]\n",
baI, 0, 0, 0, 0, 0);
sizeMask = (1 << 2);
}
else
{
PCI_AUTO_DEBUG_MSG("pciAutoFuncConfig: MemSpace found at BAR[%d]\n",
baI, 0, 0, 0, 0, 0);
sizeMask = (1 << 4);
}
/* Loop until we find a bit set or until we run out of bits */
for (; sizeMask; sizeMask <<= 1)
{
/* is this bit set? if not, keep looking */
if (readVar & sizeMask)
{
baI += pciAutoRegConfig (pSystem, pPciFunc, baseAddr, sizeMask,
addrInfo);
break;
}
}
}
}
/******************************************************************************
*
* pciAutoRegConfig - Assign PCI space to a single PCI base address register.
*
* This routine allocates and assigns PCI space (either memory or I/O)
* to a single PCI base address register.
*
* RETURNS:
*
* Returns (1) if BAR supports mapping anywhere in 64-bit address space.
* Returns (0) otherwise.
*/
UINT pciAutoRegConfig
(
PCI_SYSTEM * pSystem, /* Pointer to PCI System structure */
PCI_LOC *pPciFunc, /* Pointer to function in device list */
UINT baseAddr, /* Offset of base PCI address */
UINT nSize, /* Size and alignment requirements */
UINT addrInfo /* PCI address type information */
)
{
UINT addr; /* Working address variable */
UINT spaceEnable = 0; /* PCI space enable bit */
UINT baseaddr_mask; /* Mask for base address register */
UINT register64Bit; /* 64 bit register flag */
/* Select the appropriate PCI address space for this register */
if ((addrInfo & PCI_BAR_SPACE_MASK) == PCI_BAR_SPACE_IO)
{
/* Configure this register for PCI I/O space */
spaceEnable = PCI_CMD_IO_ENABLE;
baseaddr_mask = 0xFFFFFFFC;
register64Bit = pciAutoIoAlloc (pSystem, pPciFunc, &addr, nSize);
}
else
{
/* Configure this register for PCI memory space */
spaceEnable = PCI_CMD_MEM_ENABLE;
baseaddr_mask = 0xFFFFFFF0;
register64Bit = pciAutoMemAlloc (pSystem, pPciFunc, &addr, nSize,
addrInfo);
}
/*
* Do not exceed the upper boundary! If this occurs, all we can
* do here is return, as this is called early in the initialization
* process, before I/O is available to print error messages.
*/
if (addr != NO_ALLOCATION)
{
/* Program the base address register */
PCI_AUTO_DEBUG_MSG("pciAutoRegConfig:[0x%08x] written to BAR[0x%08x]\n",
addr, baseAddr, 0, 0, 0, 0);
pciConfigModifyLong (pPciFunc->bus, pPciFunc->device,
pPciFunc->function, baseAddr,
baseaddr_mask, addr);
if (register64Bit)
{
/*
* Write the base address for 64-bit addressable memory devices:
* initialize the next base address register to zero, the PReP
* address map does support physical addresses above 4GB (i.e.,
* 32-bit address space)
*/
pciConfigOutLong (pPciFunc->bus, pPciFunc->device,
pPciFunc->function,
baseAddr + 4, 0);
}
/* Set the appropriate enable bit, preserve status bits */
pciConfigModifyLong (pPciFunc->bus, pPciFunc->device,
pPciFunc->function, PCI_CFG_COMMAND,
(0xffff0000 | spaceEnable), spaceEnable);
}
return (register64Bit);
}
/******************************************************************************
*
* pciAutoIoAlloc - Select appropriate I/O space for device.
*
* This routine determines which PCI I/O space (16-bit or 32-bit) to assign
* to a particular function. Note that functions located on subordinate
* busses must be assigned to the 16 bit PCI I/O space due to 16 bit
* decoder limitations of certain bridges and functions. The PCI
* specification limits each I/O base address register to 256 bytes, so
* this size should not be a problem.
*
* RETURNS: 0, indicating I/O space not located anywhere in 64-bit space.
*/
UINT pciAutoIoAlloc
(
PCI_SYSTEM * pPciSys, /* PCI system structure */
PCI_LOC *pPciFunc, /* input: Pointer to PCI function element */
UINT *pAlloc, /* output: Pointer to PCI space alloc pointer */
UINT nSize /* requested size (power of 2) */
)
{
UINT * pBase;
UINT32 alignedBase;
UINT32 sizeAdj;
UINT * pAvail = NULL;
STATUS retStat = ERROR;
/* Assign this register to PCI I/O space */
if ((pPciFunc->bus == 0) &&
((pPciFunc->attribute & PCI_AUTO_ATTR_BUS_4GB_IO) != 0))
{
PCI_AUTO_DEBUG_MSG("pciAutoIoAlloc: 32-bit I/O\n", 0, 0, 0, 0, 0, 0);
pBase = &(pPciSys->pciIo32);
pAvail = &(pPciSys->pciIo32Size);
}
else
{
PCI_AUTO_DEBUG_MSG("pciAutoIoAlloc: 16-bit I/O\n", 0, 0, 0, 0, 0, 0);
pBase = &(pPciSys->pciIo16);
pAvail = &(pPciSys->pciIo16Size);
}
/* Adjust for alignment */
if (*pAvail > 0)
{
retStat = pciAutoAddrAlign (*pBase,
(*pBase + *pAvail),
nSize,
&alignedBase);
}
/* If the space is exhausted, then return an invalid pointer */
if (retStat == ERROR)
{
logMsg("Warning: PCI I/O allocation failed\n", 0, 0, 0, 0, 0, 0);
*pAlloc = NO_ALLOCATION;
return 0;
}
PCI_AUTO_DEBUG_MSG("pciAutoIoAlloc: Pre/Post alloc: \n", 0, 0, 0, 0, 0, 0);
PCI_AUTO_DEBUG_MSG(" Pre: pBase[0x%08x], pAvail[0x%08x]\n",
(int)(*pBase), (int)(*pAvail), 0, 0, 0, 0);
*pAlloc = alignedBase;
sizeAdj = (alignedBase - *pBase) + nSize;
*pBase += sizeAdj;
*pAvail -= sizeAdj;
PCI_AUTO_DEBUG_MSG(" Post: pBase[0x%08x], pAvail[0x%08x]\n",
(int)(*pBase), (int)(*pAvail), 0, 0, 0, 0);
return 0; /* can't have 64 bit i/o addresses */
}
/******************************************************************************
*
* pciAutoMemAlloc - Select appropriate memory space for device.
*
* This routine determines which PCI memory space pool to use for assignment
* to a particular function. Note that functions located on subordinate
* busses must be assigned to the 32 bit PCI memory space due to 32 bit
* requirements of functions using more than 1MB memory space.
*
* LIMITATIONS:
*
* Does not support 64-bit Memory space
*
* RETURNS:
*
* Returns 1 if 64-bit addressable memory space.
* Returns zero (0) otherwise.
*/
UINT pciAutoMemAlloc
(
PCI_SYSTEM * pPciSys, /* PCI system structure */
PCI_LOC * pPciFunc, /* Pointer to PCI function element */
UINT * pAlloc, /* Pointer to PCI space alloc pointer */
UINT size, /* space requested (power of 2) */
UINT a
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -