📄 pciautoconfiglib.c
字号:
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 addrInfo /* PCI address type information */ ) { UINT register64Bit = 0; /* 64 bit register flag */ UINT * pBase; UINT * pAvail; UINT32 alignedBase; UINT32 sizeAdj; STATUS retStat = ERROR; /* Process address attribute info */ switch (addrInfo & (UINT)PCI_BAR_MEM_TYPE_MASK ) { case PCI_BAR_MEM_BELOW_1MB: break; case PCI_BAR_MEM_ADDR64: /* * Check for a 64-bit addressable memory device, currently * the PReP address map does not support physical addresses * above 4Gb (i.e., 32-bits), so the configuration process * will initialize the upper base register to zero (i.e., * the safe thing to do), so for right now we'll skip the * next base address register which belongs to the 64-bit * pair of 32-bit base address registers. */ register64Bit = 1; break; case PCI_BAR_MEM_ADDR32: break; case PCI_BAR_MEM_RESERVED: /* fall through */ default: *pAlloc = NO_ALLOCATION; return 0; } if ( (addrInfo & PCI_BAR_MEM_PREFETCH) && ((pPciFunc->attribute) & PCI_AUTO_ATTR_BUS_PREFETCH) ) { PCI_AUTO_DEBUG_MSG("pciAutoMemAlloc: PF Mem requested" "\n", 0, 0, 0, 0, 0, 0); pBase = &(pPciSys->pciMem32); pAvail = &(pPciSys->pciMem32Size); if (*pAvail > 0) { retStat = pciAutoAddrAlign (*pBase, (*pBase + *pAvail), size, &alignedBase); } if (retStat == ERROR) { /* If no PF memory available, then try conventional */ PCI_AUTO_DEBUG_MSG("pciAutoMemAlloc: No PF Mem available" "Trying MemIO\n", 0, 0, 0, 0, 0, 0); pBase = &(pPciSys->pciMemIo32); pAvail = &(pPciSys->pciMemIo32Size); if (*pAvail > 0) { retStat = pciAutoAddrAlign (*pBase, (*pBase + *pAvail), size, &alignedBase); } if (retStat == ERROR) { logMsg("Warning: PCI PF Mem alloc failed\n", 0, 0, 0, 0, 0, 0); *pAlloc = NO_ALLOCATION; return 0; } } } else { /* Use 32-bit Non-Prefetch Mem
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -