📄 pciautoconfiglib.c
字号:
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 bridge is * on bus zero (primary bus = zero) 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 += (priBus > 0) ? (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", 0, 0, 0, 0, 0, 0); } } break; default: /* Mask off all but bus attribute bits to inherit */ inheritAttrib &= ( PCI_AUTO_ATTR_BUS_4GB_IO | PCI_AUTO_ATTR_BUS_PREFETCH ); /* devices inherit bus attributes from their bridge */ pciLoc.attribute |= inheritAttrib; break; } /* Add this function to the PCI function list */ if (*pListSize < PCI_AUTO_MAX_FUNCTIONS) { memcpy (*ppPciList, &pciLoc, sizeof (PCI_LOC)); (*ppPciList)++; (*pListSize)++; } /* If the device is a PCI-to-PCI bridge, then scan behind it */ if (pciLoc.attribute & PCI_AUTO_ATTR_BUS_PCI) { PCI_AUTO_DEBUG_MSG("pciAutoDevProbe: scanning bus[%d]\n", (subBus+1), 0, 0, 0, 0, 0 ); subBus = pciAutoBusProbe (pSystem, bus, subBus+1, &pciLoc, ppPciList, pListSize); } /* Proceed to next device if this is a single function device */ if (function == 0) { pciConfigInByte (pciLoc.bus, pciLoc.device, pciLoc.function, PCI_CFG_HEADER_TYPE, &btemp); if ((btemp & PCI_HEADER_MULTI_FUNC) == 0) { break; /* No more functions - proceed to next PCI device */ } } } } return (subBus); }/******************************************************************************** pciAutoFuncConfigAll - Configure all PCI functions contained in list** This routine initializes all PCI functions within the specified* list. This may be anything from a full list to a single entry.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -