From 55f39ef1a331dc562284da5adc59c2f3d3291796 Mon Sep 17 00:00:00 2001 From: evb Date: Mon, 9 Aug 2010 19:07:52 +0000 Subject: [PATCH] Support PCI device resource dicsovery for limit and current now, so bridge + device BAR functionning PciScanBus second pass enabled: PciProcessBus, most stubs now until VGA/ISA system tested PciClassifyDeviceType implement as helper function PCI Enumeration 100% complete! svn path=/trunk/; revision=48492 --- reactos/drivers/bus/pcix/device.c | 225 ++++++++++++++++++++++++++++-- reactos/drivers/bus/pcix/enum.c | 69 ++++++++- reactos/drivers/bus/pcix/pci.h | 19 +++ reactos/drivers/bus/pcix/utils.c | 18 +++ 4 files changed, 317 insertions(+), 14 deletions(-) diff --git a/reactos/drivers/bus/pcix/device.c b/reactos/drivers/bus/pcix/device.c index 05d307dc57f..4dbd16bcfdc 100644 --- a/reactos/drivers/bus/pcix/device.c +++ b/reactos/drivers/bus/pcix/device.c @@ -20,32 +20,238 @@ VOID NTAPI Device_SaveCurrentSettings(IN PPCI_CONFIGURATOR_CONTEXT Context) { - UNIMPLEMENTED; - while (TRUE); + PPCI_COMMON_HEADER PciData; + PIO_RESOURCE_DESCRIPTOR IoDescriptor; + PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor; + PPCI_FUNCTION_RESOURCES Resources; + PULONG BarArray; + ULONG Bar, BarMask, i; + + /* Get variables from context */ + PciData = Context->Current; + Resources = Context->PdoExtension->Resources; + + /* Loop all the PCI BARs */ + BarArray = PciData->u.type0.BaseAddresses; + for (i = 0; i <= PCI_TYPE0_ADDRESSES; i++) + { + /* Get the resource descriptor and limit descriptor for this BAR */ + CmDescriptor = &Resources->Current[i]; + IoDescriptor = &Resources->Limit[i]; + + /* Build the resource descriptor based on the limit descriptor */ + CmDescriptor->Type = IoDescriptor->Type; + if (CmDescriptor->Type == CmResourceTypeNull) continue; + CmDescriptor->Flags = IoDescriptor->Flags; + CmDescriptor->ShareDisposition = IoDescriptor->ShareDisposition; + CmDescriptor->u.Generic.Start.HighPart = 0; + CmDescriptor->u.Generic.Length = IoDescriptor->u.Generic.Length; + + /* Read the actual BAR value */ + Bar = BarArray[i]; + + /* Check which BAR is being processed now */ + if (i != PCI_TYPE0_ADDRESSES) + { + /* Check if this is an I/O BAR */ + if (Bar & PCI_ADDRESS_IO_SPACE) + { + /* Use the right mask to get the I/O port base address */ + ASSERT(CmDescriptor->Type == CmResourceTypePort); + BarMask = PCI_ADDRESS_IO_ADDRESS_MASK; + } + else + { + /* It's a RAM BAR, use the right mask to get the base address */ + ASSERT(CmDescriptor->Type == CmResourceTypeMemory); + BarMask = PCI_ADDRESS_MEMORY_ADDRESS_MASK; + + /* Check if it's a 64-bit BAR */ + if ((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT) + { + /* The next BAR value is actually the high 32-bits */ + CmDescriptor->u.Memory.Start.HighPart = BarArray[i + 1]; + } + else if ((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_20BIT) + { + /* Legacy BAR, don't read more than 20 bits of the address */ + BarMask = 0xFFFF0; + } + } + } + else + { + /* Actually a ROM BAR, so read the correct register */ + Bar = PciData->u.type0.ROMBaseAddress; + + /* Apply the correct mask for ROM BARs */ + BarMask = PCI_ADDRESS_ROM_ADDRESS_MASK; + + /* Make sure it's enabled */ + if (!(Bar & PCI_ROMADDRESS_ENABLED)) + { + /* If it isn't, then a descriptor won't be built for it */ + CmDescriptor->Type = CmResourceTypeNull; + continue; + } + } + + /* Now we have the right mask, read the actual address from the BAR */ + Bar &= BarMask; + CmDescriptor->u.Memory.Start.LowPart = Bar; + + /* And check for invalid BAR addresses */ + if (!(CmDescriptor->u.Memory.Start.HighPart | Bar)) + { + /* Skip these descriptors */ + CmDescriptor->Type = CmResourceTypeNull; + DPRINT1("Invalid BAR\n"); + } + } + + /* Also save the sub-IDs that came directly from the PCI header */ + Context->PdoExtension->SubsystemVendorId = PciData->u.type0.SubVendorID; + Context->PdoExtension->SubsystemId = PciData->u.type0.SubSystemID; } VOID NTAPI Device_SaveLimits(IN PPCI_CONFIGURATOR_CONTEXT Context) { - UNIMPLEMENTED; - while (TRUE); + PPCI_COMMON_HEADER Current, PciData; + PPCI_PDO_EXTENSION PdoExtension; + PULONG BarArray; + PIO_RESOURCE_DESCRIPTOR Limit; + ULONG i; + + /* Get pointers from the context */ + PdoExtension = Context->PdoExtension; + Current = Context->Current; + PciData = Context->PciData; + + /* And get the array of bARs */ + BarArray = PciData->u.type0.BaseAddresses; + + /* First, check for IDE controllers that are not in native mode */ + if ((PdoExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) && + (PdoExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR) && + (PdoExtension->ProgIf & 5) != 5) + { + /* They should not be using any non-legacy resources */ + BarArray[0] = 0; + BarArray[1] = 0; + BarArray[2] = 0; + BarArray[3] = 0; + } + else if ((PdoExtension->VendorId == 0x5333) && + ((PdoExtension->DeviceId == 0x88F0) || + (PdoExtension->DeviceId == 0x8880))) + { + /* + * The problem is caused by the S3 Vision 968/868 video controller which + * is used on the Diamond Stealth 64 Video 3000 series, Number Nine 9FX + * motion 771, and other popular video cards, all containing a memory bug. + * The 968/868 claims to require 32 MB of memory, but it actually decodes + * 64 MB of memory. + */ + for (i = 0; i < PCI_TYPE0_ADDRESSES; i++) + { + /* Find its 32MB RAM BAR */ + if (BarArray[i] == 0xFE000000) + { + /* Increase it to 64MB to make sure nobody touches the buffer */ + BarArray[i] = 0xFC000000; + DPRINT1("PCI - Adjusted broken S3 requirement from 32MB to 64MB\n"); + } + } + } + + /* Check for Cirrus Logic GD5430/5440 cards */ + if ((PdoExtension->VendorId == 0x1013) && (PdoExtension->DeviceId == 0xA0)) + { + /* Check for the I/O port requirement */ + if (BarArray[1] == 0xFC01) + { + /* Check for completely bogus BAR */ + if (Current->u.type0.BaseAddresses[1] == 1) + { + /* Ignore it */ + BarArray[1] = 0; + DPRINT1("PCI - Ignored Cirrus GD54xx broken IO requirement (400 ports)\n"); + } + else + { + /* Otherwise, this BAR seems okay */ + DPRINT1("PCI - Cirrus GD54xx 400 port IO requirement has a valid setting (%08x)\n", + Current->u.type0.BaseAddresses[1]); + } + } + else if (BarArray[1]) + { + /* Strange, the I/O BAR was not found as expected (or at all) */ + DPRINT1("PCI - Warning Cirrus Adapter 101300a0 has unexpected resource requirement (%08x)\n", + BarArray[1]); + } + } + + /* Finally, process all the limit descriptors */ + Limit = PdoExtension->Resources->Limit; + for (i = 0; i < PCI_TYPE0_ADDRESSES; i++) + { + /* And build them based on the BARs */ + if (PciCreateIoDescriptorFromBarLimit(&Limit[i], &BarArray[i], FALSE)) + { + /* This function returns TRUE if the BAR was 64-bit, handle this */ + ASSERT((i + 1) < PCI_TYPE0_ADDRESSES); + i++; + (&Limit[i])->Type == CmResourceTypeNull; + } + } + + /* Create the last descriptor based on the ROM address */ + PciCreateIoDescriptorFromBarLimit(&Limit[i], + &PciData->u.type0.ROMBaseAddress, + TRUE); } VOID NTAPI Device_MassageHeaderForLimitsDetermination(IN PPCI_CONFIGURATOR_CONTEXT Context) { - UNIMPLEMENTED; - while (TRUE); + PPCI_COMMON_HEADER PciData; + PPCI_PDO_EXTENSION PdoExtension; + PULONG BarArray; + ULONG i = 0; + + /* Get pointers from context data */ + PdoExtension = Context->PdoExtension; + PciData = Context->PciData; + + /* Get the array of BARs */ + BarArray = PciData->u.type0.BaseAddresses; + + /* Check for IDE controllers that are not in native mode */ + if ((PdoExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) && + (PdoExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR) && + (PdoExtension->ProgIf & 5) != 5) + { + /* These controllers only use legacy resources */ + i = 4; + } + + /* Set all the bits on, which will allow us to recover the limit data */ + for (i = 0; i < PCI_TYPE0_ADDRESSES; i++) BarArray[i] = 0xFFFFFFFF; + + /* Do the same for the PCI ROM BAR */ + PciData->u.type0.ROMBaseAddress = PCI_ADDRESS_ROM_ADDRESS_MASK; } VOID NTAPI Device_RestoreCurrent(IN PPCI_CONFIGURATOR_CONTEXT Context) { - UNIMPLEMENTED; - while (TRUE); + /* Nothing to do for devices */ + return; } VOID @@ -54,6 +260,7 @@ Device_GetAdditionalResourceDescriptors(IN PPCI_CONFIGURATOR_CONTEXT Context, IN PPCI_COMMON_HEADER PciData, IN PIO_RESOURCE_DESCRIPTOR IoDescriptor) { + /* Not yet implemented */ UNIMPLEMENTED; while (TRUE); } @@ -62,6 +269,7 @@ VOID NTAPI Device_ResetDevice(IN PPCI_CONFIGURATOR_CONTEXT Context) { + /* Not yet implemented */ UNIMPLEMENTED; while (TRUE); } @@ -70,6 +278,7 @@ VOID NTAPI Device_ChangeResourceSettings(IN PPCI_CONFIGURATOR_CONTEXT Context) { + /* Not yet implemented */ UNIMPLEMENTED; while (TRUE); } diff --git a/reactos/drivers/bus/pcix/enum.c b/reactos/drivers/bus/pcix/enum.c index dc771f2fb53..a4d53dd9fec 100644 --- a/reactos/drivers/bus/pcix/enum.c +++ b/reactos/drivers/bus/pcix/enum.c @@ -32,7 +32,7 @@ PCI_CONFIGURATOR PciConfigurators[] = PPBridge_SaveCurrentSettings, PPBridge_ChangeResourceSettings, PPBridge_GetAdditionalResourceDescriptors, - PPBridge_ResetDevice + PPBridge_ResetDevice }, { Cardbus_MassageHeaderForLimitsDetermination, @@ -44,7 +44,7 @@ PCI_CONFIGURATOR PciConfigurators[] = Cardbus_ResetDevice } }; - + /* FUNCTIONS ******************************************************************/ /* @@ -715,10 +715,10 @@ PciWriteLimitsAndRestoreCurrent(IN PVOID Reserved, /* Write the limit discovery header */ PciWriteDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH); - + /* Now read what the device indicated the limits are */ PciReadDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH); - + /* Then write back the original configuration header */ PciWriteDeviceConfig(PdoExtension, Current, 0, PCI_COMMON_HDR_LENGTH); @@ -735,7 +735,7 @@ PciWriteLimitsAndRestoreCurrent(IN PVOID Reserved, /* Copy back the original status that was saved as well */ Current->Status = Context->Status; - + /* Call the configurator to restore any other data that might've changed */ Context->Configurator->RestoreCurrent(Context); } @@ -917,6 +917,62 @@ PciGetFunctionLimits(IN PPCI_PDO_EXTENSION PdoExtension, return Status; } +VOID +NTAPI +PciProcessBus(IN PPCI_FDO_EXTENSION DeviceExtension) +{ + PPCI_PDO_EXTENSION PdoExtension; + PDEVICE_OBJECT PhysicalDeviceObject; + PAGED_CODE(); + + /* Get the PDO Extension */ + PhysicalDeviceObject = DeviceExtension->PhysicalDeviceObject; + PdoExtension = (PPCI_PDO_EXTENSION)PhysicalDeviceObject->DeviceExtension; + + /* Cheeck if this is the root bus */ + if (!PCI_IS_ROOT_FDO(DeviceExtension)) + { + /* Not really handling this year */ + UNIMPLEMENTED; + while (TRUE); + + /* Check for PCI bridges with the ISA bit set, or required */ + if ((PdoExtension) && + (PciClassifyDeviceType(PdoExtension) == PciTypePciBridge) && + ((PdoExtension->Dependent.type1.IsaBitRequired) || + (PdoExtension->Dependent.type1.IsaBitSet))) + { + /* We'll need to do some legacy support */ + UNIMPLEMENTED; + while (TRUE); + } + } + else + { + /* Scan all of the root bus' children bridges */ + for (PdoExtension = DeviceExtension->ChildBridgePdoList; + PdoExtension; + PdoExtension = PdoExtension->NextBridge) + { + /* Find any that have the VGA decode bit on */ + if (PdoExtension->Dependent.type1.VgaBitSet) + { + /* Again, some more legacy support we'll have to do */ + UNIMPLEMENTED; + while (TRUE); + } + } + } + + /* Check for ACPI systems where the OS assigns bus numbers */ + if (PciAssignBusNumbers) + { + /* Not yet supported */ + UNIMPLEMENTED; + while (TRUE); + } +} + NTSTATUS NTAPI PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension) @@ -1363,7 +1419,8 @@ PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension) } } - /* Enumeration is completed */ + /* Enumeration completed, do a final pass now that all devices are found */ + if (ProcessFlag) PciProcessBus(DeviceExtension); return STATUS_SUCCESS; } diff --git a/reactos/drivers/bus/pcix/pci.h b/reactos/drivers/bus/pcix/pci.h index 306265f03aa..93a5f140276 100644 --- a/reactos/drivers/bus/pcix/pci.h +++ b/reactos/drivers/bus/pcix/pci.h @@ -102,6 +102,18 @@ typedef enum _PCI_SIGNATURE PciInterface_Location = 'icP?' } PCI_SIGNATURE, *PPCI_SIGNATURE; +// +// Driver-handled PCI Device Types +// +typedef enum _PCI_DEVICE_TYPES +{ + PciTypeInvalid, + PciTypeHostBridge, + PciTypePciBridge, + PciTypeCardbusBridge, + PciTypeDevice +} PCI_DEVICE_TYPES; + // // Device Extension Logic States // @@ -1064,6 +1076,12 @@ PciCanDisableDecodes( IN BOOLEAN ForPowerDown ); +PCI_DEVICE_TYPES +NTAPI +PciClassifyDeviceType( + IN PPCI_PDO_EXTENSION PdoExtension +); + ULONG_PTR NTAPI PciExecuteCriticalSystemRoutine( @@ -1607,6 +1625,7 @@ extern PCI_INTERFACE TranslatorInterfaceInterrupt; extern PDRIVER_OBJECT PciDriverObject; extern PWATCHDOG_TABLE WdTable; extern PPCI_HACK_ENTRY PciHackTable; +extern BOOLEAN PciAssignBusNumbers; extern BOOLEAN PciEnableNativeModeATA; /* Exported by NTOS, should this go in the NDK? */ diff --git a/reactos/drivers/bus/pcix/utils.c b/reactos/drivers/bus/pcix/utils.c index 94f411b900d..f450a261a74 100644 --- a/reactos/drivers/bus/pcix/utils.c +++ b/reactos/drivers/bus/pcix/utils.c @@ -1041,6 +1041,24 @@ PciCanDisableDecodes(IN PPCI_PDO_EXTENSION DeviceExtension, return !(HackFlags & PCI_HACK_NO_PM_CAPS); } +PCI_DEVICE_TYPES +NTAPI +PciClassifyDeviceType(IN PPCI_PDO_EXTENSION PdoExtension) +{ + ASSERT(PdoExtension->ExtensionType == PciPdoExtensionType); + + /* Differenriate between devices and bridges */ + if (PdoExtension->BaseClass != PCI_CLASS_BRIDGE_DEV) return PciTypeDevice; + + /* The PCI Bus driver handles only CardBus and PCI bridges (plus host) */ + if (PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST) return PciTypeHostBridge; + if (PdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) return PciTypePciBridge; + if (PdoExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS) return PciTypeCardbusBridge; + + /* Any other kind of bridge is treated like a device */ + return PciTypeDevice; +} + ULONG_PTR NTAPI PciExecuteCriticalSystemRoutine(IN ULONG_PTR IpiContext)