📄 pciinit.c
字号:
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 1995-2000 Microsoft Corporation
Module Name: pciinit.c
Abstract: Boot loader PCI initialization functions.
Functions:
PCIConfig_Read
PCIConfig_Write
PCIConfig_WriteW
PciInit
PciInitBus
PciInitDevice
PciInitBridge
PciInitCheckBARs
PciInitAllocateIoSpace
PciInitAllocateMemSpace
PciInitListDevices
PciInitSearchForDevice
PCIInitListDevicesSummary
Notes:
--*/
#include <windows.h>
#include <ceddk.h>
#include "pciinit.h"
#include "pci.h"
#include "bldr.h"
#pragma warning (disable: 4002)
// Preprocessor definitions.
//
#define MAX_SPACE 120
#define MAX_DEVICE 32
#define DPF EdbgOutputDebugString
#define VDPF
// Global variables.
//
ULONG nSpaceDesc = 0;
SPACE_DESC SpaceDesc[MAX_SPACE];
ULONG nDev = 0;
ULONG SortOrder = 0;
PCI_DEVICE pDev[MAX_DEVICE];
DWORD
PCIConfig_Read(
ULONG bus,
ULONG device,
ULONG function,
ULONG offset
)
{
PCI_SLOT_NUMBER slotNumber;
int length;
DWORD dwRet = 0;
DEBUGMSG(ZONE_FUNCTION, (TEXT("+PciConfigRead (%d:%d:%d 0x%x)..."), bus, device, function, offset));
slotNumber.u.bits.DeviceNumber = device;
slotNumber.u.bits.FunctionNumber = function;
length = PCIGetBusDataByOffset(bus, slotNumber.u.AsULONG,
&dwRet, offset, sizeof(dwRet));
DEBUGMSG(ZONE_INFO, (TEXT("0x%x read\r\n"), dwRet));
return(dwRet);
}
BOOL
PCIConfig_Write(
ULONG bus,
ULONG device,
ULONG function,
ULONG offset,
ULONG dwValue
)
{
PCI_SLOT_NUMBER slotNumber;
int length;
DEBUGMSG(ZONE_FUNCTION, (TEXT("+PciConfigWrite (%d:%d:%d 0x%x)..."), bus, device, function, offset));
slotNumber.u.bits.DeviceNumber = device;
slotNumber.u.bits.FunctionNumber = function;
length = PCISetBusDataByOffset(bus, slotNumber.u.AsULONG,
&dwValue, offset, sizeof(dwValue));
DEBUGMSG(ZONE_INFO, (TEXT("0x%x written\r\n"), dwValue));
return(FALSE);
}
BOOL
PCIConfig_WriteW(
ULONG bus,
ULONG device,
ULONG function,
ULONG offset,
ULONG wValue
)
{
PCI_SLOT_NUMBER slotNumber;
int length;
DEBUGMSG(ZONE_FUNCTION, (TEXT("+PciConfigWrite (%d:%d:%d 0x%x)..."), bus, device, function, offset));
slotNumber.u.bits.DeviceNumber = device;
slotNumber.u.bits.FunctionNumber = function;
length = PCISetBusDataByOffset(bus, slotNumber.u.AsULONG,
&wValue, offset, sizeof(wValue));
DEBUGMSG(ZONE_INFO, (TEXT("0x%x written\r\n"), wValue));
return(FALSE);
}
BOOL PciInit(void)
{
ULONG SubordinateBus = 0;
ULONG MemSize = 0;
ULONG IoSize = 0;
BOOL Status = TRUE;
SortOrder = 0;
nSpaceDesc = 0;
nDev = 0;
DEBUGMSG(ZONE_FUNCTION, (TEXT("+PciInit\r\n")));
if (!PciInitBus(0,&SubordinateBus,&MemSize,&IoSize)) {
RETAILMSG(1, (TEXT("ERROR: Too many PCI devices initializing PCI Bus\r\n")));
return(FALSE);
}
if (MemSize > (g_nPCI_BUS0_MEM_LIMIT - g_nPCI_BUS0_MEM_BASE)) {
RETAILMSG(1, (TEXT("ERROR: Not enough memory space allocated for PCI Bus\r\n")));
Status = FALSE;
}
if (IoSize > (g_nPCI_BUS0_IO_LIMIT - g_nPCI_BUS0_IO_BASE)) {
RETAILMSG(1, (TEXT("ERROR: Not enough I/O space allocated for PCI Bus\r\n")));
Status = FALSE;
}
//InitSerial2();
if (!PciInitAllocateMemSpace(g_nPCI_BUS0_MEM_LIMIT, g_nPCI_BUS0_MEM_BASE, 0)) {
Status = FALSE;
RETAILMSG(1, (TEXT("ERROR: Failure allocating PCI memory space\r\n")));
}
if (!PciInitAllocateIoSpace(g_nPCI_BUS0_IO_LIMIT, g_nPCI_BUS0_IO_BASE, 0)) {
Status = FALSE;
RETAILMSG(1, (TEXT("ERROR: Failure allocation PCI IO space\r\n")));
}
return(Status);
}
BOOL
PciInitBus(
ULONG Bus,
PULONG pSubordinateBus,
PULONG pMemSize,
PULONG pIoSize
)
{
ULONG Device;
ULONG VendorID;
ULONG HeaderType;
ULONG Function;
DEBUGMSG(ZONE_FUNCTION, (TEXT("InitBus %d\r\n"), Bus));
//
// Loop through all device numbers (slots)
//
for (Device = 0; Device < 32; Device++) {
DEBUGMSG(ZONE_FUNCTION, (TEXT("InitBus (device %d)\r\n"), Device));
//
// Loop through all functions
//
for (Function = 0; Function < 8; Function++) {
DEBUGMSG(ZONE_FUNCTION, (TEXT("InitBus (device %d, func %d)\r\n"), Device, Function));
//
// Check Device Present
//
PCIConfig_Write(Bus,Device,Function,PCI_CONFIG_BASE0,0xFFFFFFFF);
VendorID = PCIConfig_Read(Bus,Device,Function,PCI_CONFIG_ID);
if (((VendorID & 0xFFFF0000) != 0xFFFF0000) &&
((VendorID & 0x0000FFFF) != 0x0000FFFF) &&
((VendorID & 0x0000FFFF) != 0x00000000)) {
pDev[nDev].Bus = Bus;
pDev[nDev].Device = Device;
pDev[nDev].Function = Function;
pDev[nDev].VendorID = VendorID;
nDev++;
if (nDev == MAX_DEVICE) {
return(FALSE);
}
//
// Check header type
//
HeaderType = PCIConfig_Read(Bus,Device,Function,PCI_CONFIG_HEAD);
if (((PPCI_BHLC)(&HeaderType))->HeadType.HeadType == 0x00) {
//
// regular device
//
if (!PciInitDevice(Bus,Device,Function,pMemSize,pIoSize)) {
return(FALSE);
}
} else {
//
// Bridge device
//
if (!PciInitBridge(Bus,
Device,
Function,
pSubordinateBus,
pMemSize,
pIoSize)) {
return(FALSE);
}
}
//
// check if multifunction device
//
// TODO - National CS5330 SouthBridge doesn't report itself as a multifuntion.
// This check should be made platform-dependent.
if (((VendorID & 0xFF00FFFF) != 0x01001078) && ((PPCI_BHLC)(&HeaderType))->HeadType.MultiFunctionDevice == 0) {
break;
}
} else {
break;
}
}
}
DEBUGMSG(ZONE_FUNCTION, (TEXT("--InitBus %d\r\n"), Bus));
return(TRUE);
}
BOOL
PciInitDevice(
ULONG Bus,
ULONG Device,
ULONG Function,
PULONG pMemSize,
PULONG pIoSize
)
{
ULONG Reg;
DWORD dwVendorDevice;
dwVendorDevice = PCIConfig_Read(Bus,Device,Function,0);
DEBUGMSG(ZONE_FUNCTION, (TEXT("InitDevice %d %d %d %X\r\n"), Bus, Device, Function, dwVendorDevice));
//
// read the base address registers to determine space to allocate
//
if (!PciInitCheckBARs(Bus,Device,Function,6,pMemSize,pIoSize)) {
return(FALSE);
}
//
// disable expansion ROM
// Enable device
//
PCIConfig_Write(Bus,Device,Function,PCI_CONFIG_ROM,0);
PCIConfig_Write(Bus,Device,Function,PCI_CONFIG_COMMAND_STATUS,0x7);
Reg = PCIConfig_Read(Bus,Device,Function,PCI_CONFIG_INTERRUPT);
((PPCI_INT)(&Reg))->InterruptLine = 0xFF;
PCIConfig_Write(Bus,Device,Function,PCI_CONFIG_INTERRUPT,Reg);
return(TRUE);
}
BOOL
PciInitBridge(
ULONG Bus,
ULONG Device,
ULONG Function,
PULONG pSubordinateBus,
PULONG pMemSize,
PULONG pIoSize
)
{
ULONG BusReg;
ULONG SecondaryMemSize;
ULONG SecondaryIoSize;
ULONG i;
ULONG Reg;
DWORD dwVal;
dwVal = PCIConfig_Read(Bus,Device,Function,0);
DEBUGMSG(ZONE_FUNCTION, (TEXT("InitBridge %d %d %d %X\r\n"), Bus, Device, Function, dwVal));
//
// read the base address registers to determine space to allocate
//
if (!PciInitCheckBARs(Bus,Device,Function,2,pMemSize,pIoSize)) {
RETAILMSG(1, (TEXT("ERROR PciInitCheckBARs failed.\r\n")));
return(FALSE);
}
//
// Enable bridge
// disable expansion ROM
// zero all the base and limit registers - these will get written later
// zero the IRQ register
//
DEBUGMSG(ZONE_INFO, (TEXT("IB (enable bridge)\r\n")));
PCIConfig_Write(Bus,Device,Function,PCI_CONFIG_COMMAND_STATUS,0x7);
PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_ROM,0x0);
PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_PREFETCHABLE,0x0);
PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_BASE_UPPER32,0x0);
PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_LIMIT_UPPER32,0x0);
PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_MEMORY,0);
PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_IO_UPPER16,0);
Reg = PCIConfig_Read(Bus,Device,Function,PCIBRIDGE_IO);
((PBRIDGE_IO)(&Reg))->IoLimit.Address = 0;
((PBRIDGE_IO)(&Reg))->IoBase.Address = 0;
PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_IO,Reg);
Reg = PCIConfig_Read(Bus,Device,Function,PCI_CONFIG_INTERRUPT);
((PPCI_INT)(&Reg))->InterruptLine = 0xFF;
PCIConfig_Write(Bus,Device,Function,PCI_CONFIG_INTERRUPT,Reg);
//
// Set the bus numbers
// Need to set the subordinate bus as max for now, then write
// actual number after found all downstream busses
//
(*pSubordinateBus)++;
BusReg = PCIConfig_Read(Bus,Device,Function,PCIBRIDGE_BUS_NUMBER);
((PBRIDGE_BUS)(&BusReg))->PrimaryBusNumber = (BYTE)Bus;
((PBRIDGE_BUS)(&BusReg))->SecondaryBusNumber = (BYTE)(*pSubordinateBus);
((PBRIDGE_BUS)(&BusReg))->SubordinateBusNumber = 0xFF;
PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_BUS_NUMBER,BusReg);
DEBUGMSG(ZONE_INFO, (TEXT("InitBridge %d %d %d %d %X\r\n"), Bus, Device,
Function, *pSubordinateBus,
PCIConfig_Read(Bus,Device,Function,0)));
//
// Call initbus routine recursively
//
SecondaryMemSize = 0;
SecondaryIoSize = 0;
if (!PciInitBus(*pSubordinateBus,
pSubordinateBus,
&SecondaryMemSize,
&SecondaryIoSize)) {
RETAILMSG(1, (TEXT("ERROR: PciInitBus failed.\r\n")));
return(FALSE);
}
//
// fill in the proper value for subordinate bus
//
((PBRIDGE_BUS)(&BusReg))->SubordinateBusNumber = (BYTE)(*pSubordinateBus);
PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_BUS_NUMBER,BusReg);
//
// Add bridge to list to come back later and fill in limit registers
// Round up space required by secondary bus to 1MB boundary and then
// align to proper boundary after that
//
SecondaryMemSize = (SecondaryMemSize + 0x000FFFFF) & 0xFFF00000;
if (((SecondaryMemSize - 1) & (SecondaryMemSize)) != 0) {
for (i = 31; i > 1; i--) {
if (SecondaryMemSize & (1 << i)) {
SecondaryMemSize = (1 << (i+1));
break;
}
}
}
SecondaryIoSize = (SecondaryIoSize + 0x00000FFF) & 0xFFFFF000;
if (((SecondaryIoSize - 1) & (SecondaryIoSize)) != 0) {
for (i = 31; i > 1; i--) {
if (SecondaryIoSize & (1 << i)) {
SecondaryIoSize = (1 << (i+1));
break;
}
}
}
DEBUGMSG(ZONE_INFO, (TEXT("Bridgespace %X %X %X\r\n"),
SecondaryMemSize, SecondaryIoSize,BusReg));
SpaceDesc[nSpaceDesc].Bus = Bus;
SpaceDesc[nSpaceDesc].Device = Device;
SpaceDesc[nSpaceDesc].Function = Function;
SpaceDesc[nSpaceDesc].MemSize = SecondaryMemSize;
SpaceDesc[nSpaceDesc].IoSize = SecondaryIoSize;
SpaceDesc[nSpaceDesc].Bridge = 1;
SpaceDesc[nSpaceDesc].SecondaryBus =
((PBRIDGE_BUS)(&BusReg))->SecondaryBusNumber;
nSpaceDesc++;
if (nSpaceDesc == MAX_SPACE) {
RETAILMSG(1, (TEXT("ERROR: MAX_SPACE.\r\n")));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -