?? pcicfg.c
字號:
Status = ((PFN_CONFIGENTRY)(Info.ConfigInfo->ConfigEntryFn))(PCIBUS_CONFIG_RSRC, &Info, g_MemHead, g_IoHead, pMemSize, pIoSize);
if (Status != ERROR_SUCCESS) {
if (Status == ERROR_NOT_SUPPORTED) {
// ConfigEntry point doesn't support this type of call, so do it here
// Read the base address registers to determine space to allocate
if (!PCICfgCheckBARs(&Info, pMemSize, pIoSize, NULL)) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCICfgCardBusBridge: Failed PCICfgCheckBARs call\r\n"));
return FALSE;
}
} else {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCICfgCardBusBridge: Failed %s:%s call\r\n", Info.DllName, Info.ConfigEntryName));
return FALSE;
}
}
} else {
// Read the base address registers to determine space to allocate
if (!PCICfgCheckBARs(&Info, pMemSize, pIoSize, NULL)) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCICfgCardBusBridge: Failed PCICfgCheckBARs call\r\n"));
return FALSE;
}
}
// If device not already placed, configure interrupt
if (!(pCfg->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE))) {
DEVICE_LOCATION DevLoc;
DWORD Irq = 0xFF;
Reg = PCIConfig_Read(Bus, Device, Function, PCI_CONFIG_INTERRUPT);
if (((PPCI_INT)(&Reg))->InterruptLine==0xff || ((PPCI_INT)(&Reg))->InterruptLine==0) { // Not be configured
// Fill in device location structure
DevLoc.IfcType = PCIBus;
DevLoc.BusNumber = Bus;
DevLoc.LogicalLoc = (Bus << 16) | (Device << 8) | Function;
DevLoc.Pin = ((PPCI_INT)(&Reg))->InterruptPin;
if (DevLoc.Pin) {
// Interrupts used, get IRQ from OAL
if (!RequestIrq(&DevLoc, &Irq)) {
DEBUGMSG(ZONE_WARNING, (L"PCIBUS!PCICfgCardBusBridge: Get IRQ call failed.\r\n"));
// No Interrupt
Irq = 0xff;
}
else if (Irq > 254) {
DEBUGMSG(ZONE_WARNING, (L"PCIBUS!PCICfgCardBusBridge: IRQ returned from OAL is outside of range (0-254). Ignoring.\r\n"));
// No interrupts
Irq = 0xFF;
}
}
DEBUGMSG(ZONE_INIT, (L"RequestIrq(%d/%d/%d) returns %d\r\n", Bus, Device, Function, Irq));
((PPCI_INT)(&Reg))->InterruptLine = (BYTE)Irq;
PCIConfig_Write(Bus, Device, Function, PCI_CONFIG_INTERRUPT, Reg);
}
}
// Disable memory and I/O windows
PCIConfig_Write(Bus, Device, Function, PCICARDBUS_MEMBASE0, 0xFFFFF000);
PCIConfig_Write(Bus, Device, Function, PCICARDBUS_MEMLIMIT0, 0x0);
PCIConfig_Write(Bus, Device, Function, PCICARDBUS_MEMBASE1, 0xFFFFF000);
PCIConfig_Write(Bus, Device, Function, PCICARDBUS_MEMLIMIT1, 0x0);
PCIConfig_Write(Bus, Device, Function, PCICARDBUS_IOBASE0, 0xFFFFFFFC);
PCIConfig_Write(Bus, Device, Function, PCICARDBUS_IOLIMIT0, 0x0);
PCIConfig_Write(Bus, Device, Function, PCICARDBUS_IOBASE1, 0xFFFFFFFC);
PCIConfig_Write(Bus, Device, Function, PCICARDBUS_IOLIMIT1, 0x0);
// Set bridge control register
Reg = PCIConfig_Read(Bus, Device, Function, PCI_CONFIG_INTERRUPT);
Reg = (Reg & 0x0000FFFF) | Info.BridgeControl << 16;
PCIConfig_Write(Bus, Device, Function, PCI_CONFIG_INTERRUPT, Reg);
// Set Latency register
Info.Latency = (Info.Latency > 0) ? Info.Latency : pBusInfo->Latency; // use global bus value if not defined for bridge
if (Info.Latency) {
// Reprogram only if non-zero
Reg = PCIConfig_Read(Bus, Device, Function, PCI_CONFIG_HEAD);
Reg = (Reg & 0xFFFF00FF) | ((Info.Latency & 0xFF) << 8);
PCIConfig_Write(Bus, Device, Function, PCI_CONFIG_HEAD, Reg);
}
// Set the bus numbers & secondary (CardBus) latency
// Assume There is no bridge type device attached the CardBus Bridge
(*pSubordinateBus)++;
Info.SecondaryLatency = (Info.SecondaryLatency > 0) ? Info.SecondaryLatency : pBusInfo->SecondaryLatency; // use global bus value if not defined for bridge
Reg = PCIConfig_Read(Bus, Device, Function, PCICARDBUS_BUS_NUMBER);
((PBRIDGE_BUS)(&Reg))->PrimaryBusNumber = (BYTE)Bus;
((PBRIDGE_BUS)(&Reg))->SecondaryBusNumber = (BYTE)(*pSubordinateBus);
((PBRIDGE_BUS)(&Reg))->SubordinateBusNumber = (BYTE)(*pSubordinateBus);
if (Info.SecondaryLatency) ((PBRIDGE_BUS)(&Reg))->SecondaryLatencyTimer = (BYTE)Info.SecondaryLatency;
PCIConfig_Write(Bus, Device, Function, PCICARDBUS_BUS_NUMBER, Reg);
// Write command value and reset device status
Reg = PCIConfig_Read(Bus, Device, Function, PCI_CONFIG_COMMAND_STATUS);
Reg &= 0x7;
Reg |= 0xFFFF0000 | (Info.Command & 0x000003FF);
PCIConfig_Write(Bus, Device, Function, PCI_CONFIG_COMMAND_STATUS, Reg);
DEBUGMSG(ZONE_FUNCTION, (L"PCIBUS!PCICfgCardBusBridge-\r\n"));
return TRUE;
}
//
// Read and check Base Address Registers, calculate size and allocate resources
//
static BOOL
PCICfgCheckBARs(
PPCI_DEV_INFO pInfo,
PULONG pMemSize,
PULONG pIoSize,
PULONG pPrefetchMemSize
)
{
DWORD NumberOfRegs;
ULONG Offset;
ULONG i;
ULONG BaseAddress;
ULONG Size;
ULONG Type;
BOOL Prefetchable;
DWORD Reg;
BOOL Placed = FALSE;
BOOL SizeFound;
DWORD IoIndex = 0;
DWORD MemIndex = 0;
DWORD Bus = pInfo->Bus;
DWORD Device = pInfo->Device;
DWORD Function = pInfo->Function;
PPCI_COMMON_CONFIG pCfg = pInfo->Cfg;
DEBUGMSG(ZONE_FUNCTION, (L"PCIBUS!PCICfgCheckBARs+(Bus %d, Device %d, Function %d)\r\n",
Bus, Device, Function));
// Check to see if device/function already enabled
if (pCfg->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE)) {
// Either Memory or I/O access enabled
Placed = TRUE;
#ifdef DEBUG
if (!pInfo->Matched) {
DEBUGMSG(ZONE_WARNING, (L"PCIBUS!PCICfgCheckBARs: WARNING: No matching registry key was found for placed device %d/%d/%d.\r\n",
Bus, Device, Function));
DEBUGMSG(ZONE_WARNING, (L"PCIBUS!PCICfgCheckBARs: Problems can result if the device is being used while configuring PCIbus.\r\n"));
}
#endif
}
// Determine number of BARs to examine from header type
switch (pCfg->HeaderType & ~PCI_MULTIFUNCTION) {
case PCI_DEVICE_TYPE:
NumberOfRegs = PCI_TYPE0_ADDRESSES;
break;
case PCI_BRIDGE_TYPE:
NumberOfRegs = PCI_TYPE1_ADDRESSES;
break;
case PCI_CARDBUS_TYPE:
NumberOfRegs = PCI_TYPE2_ADDRESSES;
break;
default:
return FALSE;
}
for (i = 0, Offset = 0x10; i < NumberOfRegs; i++, Offset += 4) {
// Get base address register value
Reg = pCfg->u.type0.BaseAddresses[i];
Type = Reg & PCI_ADDRESS_IO_SPACE;
Prefetchable = ( Type==0 && (Reg & PCI_ADDRESS_MEMORY_PREFETCHABLE)!=0 && pPrefetchMemSize!=NULL) ;
if (Placed && pInfo->Matched && (pInfo->IoLen.Num + pInfo->MemLen.Num) != 0) {
// Device already placed and has matching registry entry
if (Type) {
// I/O space
Size = pInfo->IoLen.Reg[IoIndex++];
Reg &= PCI_ADDRESS_IO_ADDRESS_MASK;
SizeFound = (IoIndex <= pInfo->IoLen.Num);
} else {
// Memory space
Size = pInfo->MemLen.Reg[MemIndex++];
Reg &= PCI_ADDRESS_MEMORY_ADDRESS_MASK;
SizeFound = (MemIndex <= pInfo->MemLen.Num);
}
} else {
// Device not placed or is placed and has no matching registry entry => Probe hardware for size
PCIConfig_Write(Bus,Device,Function,Offset,0xFFFFFFFF);
BaseAddress = PCIConfig_Read(Bus,Device,Function,Offset);
PCIConfig_Write(Bus, Device, Function, Offset, Reg);
if (Type) {
// IO space
// Re-adjust BaseAddress if upper 16-bits are 0 (allowable in PCI 2.2 spec)
if (((BaseAddress & PCI_ADDRESS_IO_ADDRESS_MASK) != 0) && ((BaseAddress & 0xFFFF0000) == 0)) {
BaseAddress |= 0xFFFF0000;
}
Size = ~(BaseAddress & PCI_ADDRESS_IO_ADDRESS_MASK);
Reg &= PCI_ADDRESS_IO_ADDRESS_MASK;
} else {
// Memory space
if ((Reg & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_20BIT) {
// PCI 2.2 spec no longer supports this type of memory addressing
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCICfgCheckBARs: 20-bit addressing not supported\r\n"));
return FALSE;
}
// Re-adjust BaseAddress if upper 16-bits are 0 (allowed by PCI 2.2 spec)
if (((BaseAddress & PCI_ADDRESS_MEMORY_ADDRESS_MASK) != 0) && ((BaseAddress & 0xFFFF0000) == 0)) {
BaseAddress |= 0xFFFF0000;
}
Size = ~(BaseAddress & PCI_ADDRESS_MEMORY_ADDRESS_MASK);
Reg &= PCI_ADDRESS_MEMORY_ADDRESS_MASK;
}
// Check that the register has a valid format; it should have consecutive high 1's and consecutive low 0's
SizeFound = (BaseAddress != 0) && (BaseAddress != 0xFFFFFFFF) && (((Size + 1) & Size) == 0);
Size +=1;
}
if (SizeFound) {
PPCI_RSRC Rsrc = PCIRsrc_New(Bus, Device, Function, Offset, Reg, Size, FALSE, 0, Placed, NULL);
if (!Rsrc) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCICfgCheckBARs: Failed local alloc of Rsrc\r\n"));
return FALSE;
}
if (Type == PCI_ADDRESS_IO_SPACE) {
*pIoSize += Size;
PCIRsrc_Add(g_IoHead, Rsrc);
} else {
if (Prefetchable && g_PrefetchMemHead!=NULL) {
*pPrefetchMemSize += Size;
PCIRsrc_Add(g_PrefetchMemHead, Rsrc);
}
else {
*pMemSize += Size;
PCIRsrc_Add(g_MemHead, Rsrc);
}
}
DEBUGMSG(ZONE_INIT, (L"PCIBUS!PCICfgCheckBars: BAR(%d/%d/%d): Offset 0x%x, Type %s, Size 0x%X\r\n",
Bus, Device, Function, Offset, (Type == PCI_ADDRESS_IO_SPACE) ? TEXT("I/O") : TEXT("Memory"), Size));
} else {
// Some devices have invalid BARs before valid ones (allowed by PCI 2.2 spec). Skip invalid BARs.
continue;
}
// check for 64 bit device (memory only)
if ((Type == PCI_ADDRESS_MEMORY_SPACE) && ((Reg & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)) {
// 64 bit device - BAR is twice as wide - zero out high part
Offset += 4;
i++;
PCIConfig_Write(Bus, Device, Function, Offset, 0x0);
}
}
DEBUGMSG(ZONE_FUNCTION, (L"PCIBUS!PCICfgCheckBars-\r\n", Bus, Device, Function));
return TRUE;
}
//
// For each I/O resource, allocate I/O space on PCIbus and assign address to BAR
//
static BOOL
PCICfgAllocateIoSpace(
DWORD Bus,
DWORD Base,
DWORD Size
)
{
PPCI_RSRC Rsrc, BusHead;
ULONG IoBase;
DWORD Reg;
DEBUGMSG(ZONE_FUNCTION, (L"PCIBUS!PCICfgAllocateIoSpace+(Bus %d, Base 0x%X, Size 0x%X)\r\n", Bus, Base, Size));
// Create bus head node with available address range
if (!(BusHead = PCIRsrc_New(Bus, 0, 0, 0, Base, Size, TRUE, 0, TRUE, NULL))) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCICfgAllocateIoSpace: Failed local alloc of BusHead\r\n"));
return FALSE;
}
while (Rsrc = PCIRsrc_GetNext(g_IoHead, Bus)) {
// Place resource
if (!PCIRsrc_Place(BusHead, Rsrc)) {
DEBUGMSG(ZONE_ERROR,
(L"PCIBUS!PCICfgAllocIoSpace: Failed to place %s resource: Bus %d, Device %d, Function %d\r\n",
(Rsrc->Bridge) ? L"Bridge" : L"Device", Rsrc->Bus, Rsrc->Device, Rsrc->Function));
continue;
}
DEBUGMSG(ZONE_INIT, (L"PCIBUS!PciIinitAllocIoSpace (%s): Bus %d, Device %d, Function %d, Offset 0x%X, IoBase 0x%X, IoSize 0x%X\r\n",
(Rsrc->Bridge) ? L"PCI-PCI Bridge" : L"Device", Rsrc->Bus, Rsrc->Device, Rsrc->Function, Rsrc->Offset, Rsrc->Base, Rsrc->Size));
if (Rsrc->Bridge) {
// PCI-PCI bridge
BOOL Use32bitIo;
// Allocate resources for bridge's secondary bus
PCICfgAllocateIoSpace(Rsrc->SecBus, Rsrc->Base, Rsrc->Size);
// Write I/O base and limit registers
IoBase = PCIConfig_Read(Rsrc->Bus, Rsrc->Device, Rsrc->Function, PCIBRIDGE_IO);
// Check to see if the bridge is using 16-bit I/O or 32-bit I/O
Use32bitIo = ((IoBase & 0xF) == PCI_SECONDARY_IO32);
// Set bridge's base and limit address registers
((PBRIDGE_IO)(&IoBase))->IoLimit.Address = (BYTE)(((Rsrc->Base + Rsrc->Size - 1) & 0xF000) >> 12);
((PBRIDGE_IO)(&IoBase))->IoBase.Address = (BYTE)(((Rsrc->Base) & 0xF000) >> 12);
PCIConfig_Write(Rsrc->Bus, Rsrc->Device, Rsrc->Function, PCIBRIDGE_IO, IoBase);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -