📄 pciconfiglib.c
字号:
int funcNo; UINT32 device; UINT32 vendor; UINT8 header; if (pciLibInitStatus != OK) /* sanity check */ cont = FALSE; for (busNo = 0; cont == TRUE && busNo <= pciMaxBus; busNo++) for (deviceNo = 0; ((cont == TRUE) && (deviceNo < PCI_MAX_DEV)); ++deviceNo) for (funcNo = 0; cont == TRUE && funcNo < PCI_MAX_FUNC; funcNo++) { /* avoid a special bus cycle */ if ((deviceNo == 0x1f) && (funcNo == 0x07)) continue; pciConfigInLong (busNo, deviceNo, funcNo, PCI_CFG_VENDOR_ID, &vendor); /* * If nonexistent device, skip to next, only look at * vendor ID field for existence check */ if (((vendor & 0x0000ffff) == 0x0000FFFF) && (funcNo == 0)) break; device = vendor >> 16; device &= 0x0000FFFF; vendor &= 0x0000FFFF; if ((vendor == (UINT32)vendorId) && (device == (UINT32)deviceId) && (index-- == 0)) { *pBusNo = busNo; *pDeviceNo = deviceNo; *pFuncNo = funcNo; status = OK; cont = FALSE; /* terminate all loops */ continue; } /* goto next if current device is single function */ pciConfigInByte (busNo, deviceNo, funcNo, PCI_CFG_HEADER_TYPE, &header); if ((header & PCI_HEADER_MULTI_FUNC) != PCI_HEADER_MULTI_FUNC && funcNo == 0) break; } return (status); }/********************************************************************************* pciFindClass - find the nth occurence of a device by PCI class code.** This routine finds the nth device with the given 24-bit PCI class code* (class subclass prog_if).* * The classcode arg of must be carfully constructed from class and sub-class* macros. * * Example : To find an ethernet class device, construct the classcode arg * as follows:** .CS* ((PCI_CLASS_NETWORK_CTLR << 16 | PCI_SUBCLASS_NET_ETHERNET << 8))* .CE** RETURNS:* OK, or ERROR if the class didn't match.*/STATUS pciFindClass ( int classCode, /* 24-bit class code */ int index, /* desired instance of device */ int * pBusNo, /* bus number */ int * pDeviceNo, /* device number */ int * pFuncNo /* function number */ ) { STATUS status = ERROR; BOOL cont = TRUE; int busNo; int deviceNo; int funcNo; UINT32 classCodeReg; UINT32 vendor; UINT8 header; if (pciLibInitStatus != OK) /* sanity check */ cont = FALSE; for (busNo = 0; cont == TRUE && busNo <= pciMaxBus; busNo++) for (deviceNo = 0; ((cont == TRUE) && (deviceNo < PCI_MAX_DEV)); ++deviceNo) for (funcNo = 0; cont == TRUE && funcNo < PCI_MAX_FUNC; funcNo++) { /* avoid a special bus cycle */ if ((deviceNo == 0x1f) && (funcNo == 0x07)) continue; pciConfigInLong (busNo, deviceNo, funcNo, PCI_CFG_VENDOR_ID, &vendor); /* * If nonexistent device, skip to next, only look at * vendor ID field for existence check */ if (((vendor & 0x0000ffff) == 0x0000FFFF) && (funcNo == 0)) break; pciConfigInLong (busNo, deviceNo, funcNo, PCI_CFG_REVISION, &classCodeReg); if ((((classCodeReg >> 8) & 0x00ffffff) == classCode) && (index-- == 0)) { *pBusNo = busNo; *pDeviceNo = deviceNo; *pFuncNo = funcNo; status = OK; cont = FALSE; /* terminate all loops */ continue; } /* goto next if current device is single function */ pciConfigInByte (busNo, deviceNo, funcNo, PCI_CFG_HEADER_TYPE, &header); if ((header & PCI_HEADER_MULTI_FUNC) != PCI_HEADER_MULTI_FUNC && funcNo == 0) break; } return (status); }/******************************************************************************** pciDevConfig - configure a device on a PCI bus** This routine configures a device that is on a Peripheral Component* Interconnect (PCI) bus by writing to the configuration header of the* selected device.** It first disables the device by clearing the command register in the* configuration header. It then sets the I/O and/or memory space base* address registers, the latency timer value and the cache line size.* Finally, it re-enables the device by loading the command register with* the specified command.** NOTE: This routine is designed for Type 0 PCI Configuration Headers ONLY.* It is NOT usable for configuring, for example, a PCI-to-PCI bridge.** RETURNS: OK always.*/STATUS pciDevConfig ( int pciBusNo, /* PCI bus number */ int pciDevNo, /* PCI device number */ int pciFuncNo, /* PCI function number */ UINT32 devIoBaseAdrs, /* device IO base address */ UINT32 devMemBaseAdrs, /* device memory base address */ UINT32 command /* command to issue */ ) { INT32 ix; UINT32 tmp32; /* * Disable device by clearing its command register field in its * configuration header. Write 0 clears command and preserves status. */ pciConfigOutLong (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_COMMAND, 0x0); /* * Due to system constraints, this is a partial implementation * of enabling the Base Address Registers (BARs). * It is hoped that all PCI devices only require at most one * I/O space and/or one memory space. * If not, this code will re-allocate the device's memory to * each BAR implemented. Sounds like future trouble! */ for (ix = PCI_CFG_BASE_ADDRESS_0; ix <= PCI_CFG_BASE_ADDRESS_5; ix+=4) { /* Write all f's and read back value */ pciConfigOutLong (pciBusNo, pciDevNo, pciFuncNo, ix, 0xffffffff); pciConfigInLong (pciBusNo, pciDevNo, pciFuncNo, ix, &tmp32); /* BAR implemented? */ if (tmp32 == 0) { /* * No! According to the spec, BARs must be implemented * in sequence starting at BAR 0. So, all done. */ break; } /* I/O space requested? */ /* Yes, set specified I/O space base address */ if (tmp32 & 0x1) { pciConfigOutLong (pciBusNo, pciDevNo, pciFuncNo, ix, devIoBaseAdrs | 0x1); } /* No, memory space required, set specified base address */ else { pciConfigOutLong (pciBusNo, pciDevNo, pciFuncNo, ix, devMemBaseAdrs & ~0x1); } } /* Configure Cache Line Size Register */ pciConfigOutByte (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_CACHE_LINE_SIZE, PCI_CACHE_LINE_SIZE); /* Configure Latency Timer */ pciConfigOutByte (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_LATENCY_TIMER, PCI_LATENCY_TIMER); /* * Enable the device's capabilities as specified, do not * reset any status bits in doing so. */ pciConfigModifyLong (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_COMMAND, (PCI_CMD_MASK | command), command); return (OK); }/********************************************************************************* pciConfigBdfPack - pack parameters for the Configuration Address Register** This routine packs three parameters into one integer for accessing the* Configuration Address Register** RETURNS: packed integer encoded version of bus, device, and function numbers.*/int pciConfigBdfPack ( int busNo, /* bus number */ int deviceNo, /* device number */ int funcNo /* function number */ ) { return (((busNo << 16) & 0x00ff0000) | ((deviceNo << 11) & 0x0000f800) | ((funcNo << 8) & 0x00000700)); }/********************************************************************************* pciConfigExtCapFind - find extended capability in ECP linked list** This routine searches for an extended capability in the linked list of * capabilities in config space. If found, the offset of the first byte * of the capability of interest in config space is returned via pOffset.** RETURNS: OK if Extended Capability found, ERROR otherwise*/STATUS pciConfigExtCapFind ( UINT8 extCapFindId, /* Extended capabilities ID to search for */ int bus, /* PCI bus number */ int device, /* PCI device number */ int function, /* PCI function number */ UINT8 * pOffset /* returned config space offset */ ) { STATUS retStat = ERROR; UINT16 tmpStat; UINT8 tmpOffset; UINT8 capOffset = 0x00; UINT8 capId = 0x00; /* Check to see if the device has any extended capabilities */ pciConfigInWord(bus, device, function, PCI_CFG_STATUS, &tmpStat); if ((tmpStat & PCI_STATUS_NEW_CAP) == 0) { return retStat; } /* Get the initial ECP offset and make longword aligned */ pciConfigInByte(bus, device, function, PCI_CFG_CAP_PTR, &capOffset); capOffset &= ~0x02; /* Bounds check the ECP offset */ if (capOffset < 0x40) { return retStat; } /* Look for the specified Extended Cap item in the linked list */ while (capOffset != 0x00) { /* Get the Capability ID and check */ pciConfigInByte(bus, device, function, (int)capOffset, &capId); if (capId == extCapFindId) { *pOffset = (capOffset + (UINT8)0x02); retStat = OK; break; } /* Get the offset to the next New Capabilities item */ tmpOffset = capOffset + (UINT8)0x01; pciConfigInByte(bus, device, function, (int)tmpOffset, &capOffset); } return retStat; }#ifndef USE_PCI_SIMULATOR/********************************************************************************* pciConfigInByte - read one byte from the PCI configuration space** This routine reads one byte from the PCI configuration space** RETURNS: OK, or ERROR if this library is not initialized*/STATUS pciConfigInByte ( int busNo, /* bus number */ int deviceNo, /* device number */ int funcNo, /* function number */ int offset, /* offset into the configuration space */ UINT8 * pData /* data read from the offset */ ) { UINT8 retval = 0; UINT32 retvallong = 0; STATUS retStat = ERROR; int key; if (pciLibInitStatus != OK) /* sanity check */ return (ERROR); key = intLock (); /* mutual exclusion start */ switch (pciConfigMech) { case PCI_MECHANISM_0: if (pciConfigRead (busNo, deviceNo, funcNo, offset, 1, (void *)&retval) == ERROR) { retval = 0xff; } else { retStat = OK; } break; case PCI_MECHANISM_1: PCI_OUT_LONG (pciConfigAddr0, pciConfigBdfPack (busNo, deviceNo, funcNo) | (offset & 0xfc) | 0x80000000); retval = PCI_IN_BYTE (pciConfigAddr1 + (offset & 0x3)); retStat = OK; break; case PCI_MECHANISM_2: PCI_OUT_BYTE (pciConfigAddr0, 0xf0 | (funcNo << 1)); PCI_OUT_BYTE (pciConfigAddr1, busNo); retvallong = PCI_IN_LONG(pciConfigAddr2 | ((deviceNo & 0x000f) << 8) \ | (offset & 0xfc)); PCI_OUT_BYTE (pciConfigAddr0, 0); retvallong >>= (offset & 0x03) * 8; retval = (UINT8)(retvallong & 0xff); retStat = OK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -