📄 pciautoconfiglib.c
字号:
** RETURNS: N/A.*/LOCAL void pciAutoFuncConfigAll ( PCI_SYSTEM * pSystem, /* PCI system info */ PCI_LOC *pPciList, /* input: Pointer to first function */ UINT nSize /* input: Number of functions to init */ ) { PCI_LOC *pPciFunc; /* Pointer to next function */ UINT nLoop; /* Loop control variable */ UINT nEnd; /* End of function list */ /* Disable all devices before we initialize any */ /* Allocate and assign PCI space to each device */ pPciFunc = pPciList; nEnd = nSize; pciAutoDevConfig (pSystem, pPciList->bus, &pPciFunc, &nEnd); /* Enable each device on the device list */ pPciFunc = pPciList; for (nLoop = 0; nLoop < nSize; nLoop++) { pciAutoFuncEnable (pSystem, pPciFunc); pPciFunc++; } }/******************************************************************************** pciAutoFuncDisable - Disable a specific PCI function.** This routine clears the I/O, mem, master, & ROM space enable bits* for a single PCI function.** The PCI spec says that devices should normally clear these by default after* reset but in actual practice, some PCI devices do not fully comply. This* routine ensures that the devices have all been disabled before configuration* is started.** RETURNS: N/A.**/void pciAutoFuncDisable ( PCI_LOC *pPciFunc /* input: Pointer to PCI function struct */ ) { UCHAR cTemp; /* Temporary storage */ UINT16 wTemp; if ((pPciFunc->attribute) & PCI_AUTO_ATTR_DEV_EXCLUDE) { return; } PCI_AUTO_DEBUG_MSG("pciAutoFuncDisable: disable device [%d,%d,%d,0x%02x]\n", (pPciFunc->bus), (pPciFunc->device), (pPciFunc->function), (pPciFunc->attribute), 0, 0 ); /* Disable Memory, I/O, and Bus Mastering, save status bits */ wTemp = (PCI_CMD_IO_ENABLE | PCI_CMD_MEM_ENABLE | PCI_CMD_MASTER_ENABLE ); pciConfigModifyLong (pPciFunc->bus, pPciFunc->device, pPciFunc->function, PCI_CFG_COMMAND, (0xffff0000 | wTemp), 0x0); /* Disable header dependent fields */ pciConfigInByte (pPciFunc->bus, pPciFunc->device, pPciFunc->function, PCI_CFG_HEADER_TYPE, &cTemp); cTemp &= PCI_HEADER_TYPE_MASK; switch (cTemp) { case PCI_HEADER_TYPE0: /* non PCI-PCI bridge */ /* * Disable Expansion ROM address decode for the device. * Note that no mem space is allocated for the Expansion * ROM, so a re-enable later should NOT be done. */ pciConfigModifyLong (pPciFunc->bus, pPciFunc->device, pPciFunc->function, PCI_CFG_EXPANSION_ROM, 0x1, 0); break; case PCI_HEADER_PCI_PCI: /* PCI-PCI bridge */ pciConfigModifyLong (pPciFunc->bus, pPciFunc->device, pPciFunc->function, PCI_CFG_ROM_BASE, 0x1, 0); break; default: break; } return; }/******************************************************************************** pciAutoFuncEnable - Perform final configuration and enable a function** Depending upon whether the device is included, this routine initializes* a single PCI function as follows:** Initialize the cache line size register* Initialize the PCI-PCI bridge latency timers* Enable the master PCI bit for non-display devices* Set the interrupt line value with the value from the BSP.** RETURNS: N/A.**/void pciAutoFuncEnable ( PCI_SYSTEM * pSystem, /* PCI system info */ PCI_LOC * pFunc /* input: Pointer to PCI function structure */ ) { short pciClass; /* PCI class/subclass contents */ UCHAR intLine = 0xff; /* Interrupt "Line" value */ UCHAR intPin = 0xff; /* Interrupt "Pin" value */ if ((pFunc->attribute) & PCI_AUTO_ATTR_DEV_EXCLUDE) { return; } PCI_AUTO_DEBUG_MSG("pciAutoFuncConfig: enable device [%d,%d,%d,0x%02x]\n", (pFunc->bus), (pFunc->device), (pFunc->function), (pFunc->attribute), 0, 0 ); /* Initialize the cache line size register */ pciConfigOutByte (pFunc->bus, pFunc->device, pFunc->function, PCI_CFG_CACHE_LINE_SIZE, pSystem->cacheSize); /* Initialize the latency timer */ pciConfigOutByte (pFunc->bus, pFunc->device, pFunc->function, PCI_CFG_LATENCY_TIMER, pSystem->maxLatency); /* Get the PCI class code */ pciConfigInWord (pFunc->bus, pFunc->device, pFunc->function, PCI_CFG_SUBCLASS, &pciClass); /* Enable Bus Mastering (preserve status bits) */ pciConfigModifyLong (pFunc->bus, pFunc->device, pFunc->function, PCI_CFG_COMMAND, (0xffff0000 | PCI_CMD_MASTER_ENABLE), PCI_CMD_MASTER_ENABLE); /* * If an interrupt assignment routine is registered, assign the * interrupt and record interrupt line in config header, else * write 0xff (default value) to the interrupt line reg */ pciConfigInByte (pFunc->bus, pFunc->device, pFunc->function, PCI_CFG_DEV_INT_PIN, &intPin); intLine = pciAutoIntAssign (pSystem, pFunc, intPin); pciConfigOutByte (pFunc->bus, pFunc->device, pFunc->function, PCI_CFG_DEV_INT_LINE, intLine); /* Reset all writeable status bits */ pciConfigOutWord (pFunc->bus, pFunc->device, pFunc->function, PCI_CFG_STATUS, (UINT16)0xFFFF); return; }/******************************************************************************** pciAutoIntAssign - Compute the interrupt number for a given PCI device.** This routine computes the interrupt number for a PCI device identified* by the parameter <pFunc>.** The algorithm used is the following: if the device is on the PCI bus 0,* then the bsp interrupt assign routine (if any) is called to get the * actual IRQ number used. In adddition, if the device is a Pci-To-Pci * Bridge, then this routine populates a routing table that will be used * later for all of the PCI devices on its every subourdinate buses.* Conversely, if the device sits on any PCI bus other than bus 0, this* routines only looks at that table. The index used depends not* only on the device's location on the bus, but also on the routing offset* of the most immediate Pci-To-Pci Bridge. This offset, in turn, is based* on its location in the PCI hierarchy and was computed earlier by the * PCI configuration process. However, the user may skip this automatic * interrupt assignment process by simply setting the variable autoIntRouting* in the relevant PCI_SYSTEM structure to FALSE. In this case the bsp * interrupt assign routine will be called to get the IRQ number for the device.** RETURNS: the interrupt number associated with the device.*/ UCHAR pciAutoIntAssign ( PCI_SYSTEM * pSystem, /* PCI system info */ PCI_LOC * pFunc, /* input: Pointer to PCI function structure */ UCHAR intPin /* Interrupt "Pin" value */ ) { UCHAR retVal = 0xFF; /* * if the bsp provides interrupt routing for all PCI devices, * then there's no need of any computation whatsoever */ if ((!(pSystem->autoIntRouting)) && (intPin != 0)) { if ((pSystem->intAssignRtn) != NULL ) { retVal = (pSystem->intAssignRtn) (pSystem, pFunc, intPin); return (retVal); } } /* default interrupt routing: let's find out the IRQ for this device */ switch (pFunc->bus) { case 0: if (((pSystem->intAssignRtn) != NULL) && (intPin != 0)) { retVal = (pSystem->intAssignRtn) (pSystem, pFunc, intPin); } /* * if this is a P2P Bridge, then populate its interrupt * routing table. This will be used later for all the devices * belonging to its every subourdinate bus */ if (((pFunc->attribute) & PCI_AUTO_ATTR_BUS_PCI) > 0) { int i = 0; for (i = 0; i < 4; i++) { if ((pSystem->intAssignRtn) != NULL ) { pciAutoIntRoutingTable [i] = (pSystem->intAssignRtn) (pSystem, pFunc, (i+1)); } } } break; default: retVal = pciAutoIntRoutingTable [(((pFunc->device) + (intPin - 1) + (pFunc->offset)) % 4)]; break; } PCI_AUTO_DEBUG_MSG("pciAutoIntAssign: int for [%d,%d,%d] pin %d is [%d]\n", pFunc->bus, pFunc->device, pFunc->function, intPin, retVal, 0); return retVal; }/******************************************************************************** pciAutoGetNextClass - find the next device of specific type from probe list** The function uses the probe list which was built during the probing* process. Using configuration accesses, it searches for the* occurrence of the device subject to the 'class' and 'mask'* restrictions outlined below. Setting 'class' to zero and 'mask' to* zero allows searching the entire set of devices found regardless of* class.** RETURNS: TRUE if a device was found, else FALSE**/STATUS pciAutoGetNextClass ( PCI_SYSTEM *pPciSystem, PCI_LOC *pPciFunc, /* output: Contains the BDF of the device found */ UINT *index, /* Zero-based device instance number */ UINT pciClass, /* class code field from the PCI header */ UINT mask /* mask is ANDed with the class field */ ) { UINT i; UINT idx = *index; UINT classCode; UINT nSize; PCI_LOC *pciList; nSize = (UINT)lastPciListSize; pciList = pLastPciList; PCI_AUTO_DEBUG_MSG("\npciAutoGetNextClass: index[%d] listSiz[%d]\n", *index, nSize, 0, 0, 0, 0); PCI_AUTO_DEBUG_MSG(" pciClass[0x%08x], mask[0x%08x]\n", pciClass, mask, 0, 0, 0, 0); if ((nSize <= idx) || (pciList == NULL)) return (FALSE); /* No more devices */ for (i = idx; i < nSize; i++) { /* Grab the class code 24-bit field */ pciConfigInLong ((UINT)pciList[i].bus, (UINT)pciList[i].device, (UINT)pciList[i].function, (PCI_CFG_CLASS & 0xfc), &classCode); classCode >>= 8; /* Isolate class code in low order bits */ 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -