Author: sir_richard
Date: Mon Jul 19 15:15:39 2010
New Revision: 48116
URL: http://svn.reactos.org/svn/reactos?rev=48116&view=rev
Log:
Joint patch
By sir_richard: [PCIX]: - Implement PciIsSlotPresentInParentMethod for ACPI query, and PcoDecodeEnable utility function.
- Implement PciConfigureIdeController based on WDHC Whitepaper "How Windows Switches a Controller to Native Mode". Check for PciEanbleNativeModeATA in registry, InitSafeBootMode, and call the ACPI driver to evaluate if NATA is present on the slot. Only configure the controller if both channels support native mode, as this is a Windows restriction.
- Implement PciApplyHacks for enumeration and resource update cases. In the first case, we handle legacy DEC Alpha Intel i82375 and i82378 PCI-to-(E)ISA bridges with invalid class codes. In the second, we configure IDE controllers for Native mode, except the OPTi Viper-M, which is known to cause issues. We also support cards with legacy VGA decodes by telling the arbiter to enable full access to the rangesm and finally we completely disable the decodes on Compaq PCI Hotplug Controllers (Revision 17) on PAE systems, as they have bugs handling 64-bit addresses. Finally, on resource updates, we apply a vendor-specific errata to the IBM 20H2999 PCI Docking Bridge (Hotplug) used on Thinkpad 600 Series laptops, and we attempt to avoid issues that can happen on certain devices that are plugged into an ICH1/2/3/4 Intel Hub when it has been configured to do subtractive decode. Full information on these workarounds can be seen in the comments. Finally, we also enable CardBUS devices for ACPI-compliant mode, by crossing out the LegacyBaseAddress in the CardBUS Type 2 PCI Configuration Header.
- Miscelleaneous code cleanups.
By eVb: More PciScanBus support, for debug PCI caps that driver use are dump, and detect nonBIOS configure device (spec is said that CacheLineSize != 0, LatencyTimer != 0 (on PCI-X, != 64)), if found NeedsHotPlugConfiguration to be set
By eVb: Support PCI_HACK_VIDEO_LEGACY_DECODE (call ario_ApplyBrokenVideoHack, but no arb support to do work)
Modified:
trunk/reactos/drivers/bus/pcix/arb/ar_memio.c
trunk/reactos/drivers/bus/pcix/enum.c
trunk/reactos/drivers/bus/pcix/pci.h
trunk/reactos/drivers/bus/pcix/utils.c
Modified: trunk/reactos/drivers/bus/pcix/arb/ar_memio.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/bus/pcix/arb/ar_me…
==============================================================================
--- trunk/reactos/drivers/bus/pcix/arb/ar_memio.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/bus/pcix/arb/ar_memio.c [iso-8859-1] Mon Jul 19 15:15:39 2010
@@ -91,6 +91,46 @@
return Status;
}
+VOID
+NTAPI
+ario_ApplyBrokenVideoHack(IN PPCI_FDO_EXTENSION FdoExtension)
+{
+ PPCI_ARBITER_INSTANCE PciArbiter;
+ //PARBITER_INSTANCE CommonInstance;
+ NTSTATUS Status;
+
+ /* Only valid for root FDOs who are being applied the hack for the first time */
+ ASSERT(!FdoExtension->BrokenVideoHackApplied);
+ ASSERT(PCI_IS_ROOT_FDO(FdoExtension));
+
+ /* Find the I/O arbiter */
+ PciArbiter = (PVOID)PciFindNextSecondaryExtension(FdoExtension->
+ SecondaryExtension.Next,
+ PciArb_Io);
+ ASSERT(PciArbiter);
+#if 0 // when arb exist
+ /* Get the Arb instance */
+ CommonInstance = &PciArbiter->CommonInstance;
+
+ /* Free the two lists, enabling full VGA access */
+ ArbFreeOrderingList(&CommonInstance->OrderingList);
+ ArbFreeOrderingList(&CommonInstance->ReservedList);
+
+ /* Build the ordering for broken video PCI access */
+ Status = ArbBuildAssignmentOrdering(CommonInstance,
+ L"Pci",
+ L"BrokenVideo",
+ NULL);
+ ASSERT(NT_SUCCESS(Status));
+#else
+ Status = STATUS_SUCCESS;
+ UNIMPLEMENTED;
+ while (TRUE);
+#endif
+ /* Now the hack has been applied */
+ FdoExtension->BrokenVideoHackApplied = TRUE;
+}
+
NTSTATUS
NTAPI
armem_Initializer(IN PVOID Instance)
Modified: trunk/reactos/drivers/bus/pcix/enum.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/bus/pcix/enum.c?re…
==============================================================================
--- trunk/reactos/drivers/bus/pcix/enum.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/bus/pcix/enum.c [iso-8859-1] Mon Jul 19 15:15:39 2010
@@ -15,6 +15,429 @@
/* GLOBALS ********************************************************************/
/* FUNCTIONS ******************************************************************/
+
+/*
+ * 7. The IO/MEM/Busmaster decodes are disabled for the device.
+ * 8. The PCI bus driver sets the operating mode bits of the Programming
+ * Interface byte to switch the controller to native mode.
+ *
+ * Important: When the controller is set to native mode, it must quiet itself
+ * and must not decode I/O resources or generate interrupts until the operating
+ * system has enabled the ports in the PCI configuration header.
+ * The IO/MEM/BusMaster bits will be disabled before the mode change, but it
+ * is not possible to disable interrupts on the device. The device must not
+ * generate interrupts (either legacy or native mode) while the decodes are
+ * disabled in the command register.
+ *
+ * This operation is expected to be instantaneous and the operating system does
+ * not stall afterward. It is also expected that the interrupt pin register in
+ * the PCI Configuration space for this device is accurate. The operating system
+ * re-reads this data after previously ignoring it.
+ */
+BOOLEAN
+NTAPI
+PciConfigureIdeController(IN PPCI_PDO_EXTENSION PdoExtension,
+ IN PPCI_COMMON_HEADER PciData,
+ IN BOOLEAN Initial)
+{
+ UCHAR MasterMode, SlaveMode, MasterFixed, SlaveFixed, ProgIf, NewProgIf;
+ BOOLEAN Switched;
+ USHORT Command;
+
+ /* Assume it won't work */
+ Switched = FALSE;
+
+ /* Get master and slave current settings, and programmability flag */
+ ProgIf = PciData->ProgIf;
+ MasterMode = (ProgIf & 1) == 1;
+ MasterFixed = (ProgIf & 2) == 0;
+ SlaveMode = (ProgIf & 4) == 4;
+ SlaveFixed = (ProgIf & 8) == 0;
+
+ /*
+ * [..] In order for Windows XP SP1 and Windows Server 2003 to switch an ATA
+ * ATA controller from compatible mode to native mode, the following must be
+ * true:
+ *
+ * - The controller must indicate in its programming interface that both channels
+ * can be switched to native mode. Windows XP SP1 and Windows Server 2003 do
+ * not support switching only one IDE channel to native mode. See the PCI IDE
+ * Controller Specification Revision 1.0 for details.
+ */
+ if ((MasterMode != SlaveMode) || (MasterFixed != SlaveFixed))
+ {
+ /* Windows does not support this configuration, fail */
+ DPRINT1("PCI: Warning unsupported IDE controller configuration for VEN_%04x&DEV_%04x!",
+ PdoExtension->VendorId,
+ PdoExtension->DeviceId);
+ return Switched;
+ }
+
+ /* Check if the controller is already in native mode */
+ if ((MasterMode) && (SlaveMode))
+ {
+ /* Check if I/O decodes should be disabled */
+ if ((Initial) || (PdoExtension->IoSpaceUnderNativeIdeControl))
+ {
+ /* Read the current command */
+ PciReadDeviceConfig(PdoExtension,
+ &Command,
+ FIELD_OFFSET(PCI_COMMON_HEADER, Command),
+ sizeof(USHORT));
+
+ /* Disable I/O space decode */
+ Command &= ~PCI_ENABLE_IO_SPACE;
+
+ /* Update new command in PCI IDE controller */
+ PciWriteDeviceConfig(PdoExtension,
+ &Command,
+ FIELD_OFFSET(PCI_COMMON_HEADER, Command),
+ sizeof(USHORT));
+
+ /* Save updated command value */
+ PciData->Command = Command;
+ }
+
+ /* The controller is now in native mode */
+ Switched = TRUE;
+ }
+ else if (!(MasterFixed) &&
+ !(SlaveFixed) &&
+ (PdoExtension->BIOSAllowsIDESwitchToNativeMode) &&
+ !(PdoExtension->HackFlags & PCI_HACK_DISABLE_IDE_NATIVE_MODE))
+ {
+ /* Turn off decodes */
+ PciDecodeEnable(PdoExtension, FALSE, NULL);
+
+ /* Update the current command */
+ PciReadDeviceConfig(PdoExtension,
+ &PciData->Command,
+ FIELD_OFFSET(PCI_COMMON_HEADER, Command),
+ sizeof(USHORT));
+
+ /* Enable native mode */
+ ProgIf = PciData->ProgIf | 5;
+ PciWriteDeviceConfig(PdoExtension,
+ &ProgIf,
+ FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf),
+ sizeof(UCHAR));
+
+ /* Verify the setting "stuck" */
+ PciReadDeviceConfig(PdoExtension,
+ &NewProgIf,
+ FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf),
+ sizeof(UCHAR));
+ if (NewProgIf == ProgIf)
+ {
+ /* Update the header and PDO data with the new programming mode */
+ PciData->ProgIf = ProgIf;
+ PdoExtension->ProgIf = NewProgIf;
+
+ /* Clear the first four BARs to reset current BAR setttings */
+ PciData->u.type0.BaseAddresses[0] = 0;
+ PciData->u.type0.BaseAddresses[1] = 0;
+ PciData->u.type0.BaseAddresses[2] = 0;
+ PciData->u.type0.BaseAddresses[3] = 0;
+ PciWriteDeviceConfig(PdoExtension,
+ PciData->u.type0.BaseAddresses,
+ FIELD_OFFSET(PCI_COMMON_HEADER,
+ u.type0.BaseAddresses),
+ 4 * sizeof(ULONG));
+
+ /* Re-read the BARs to have the latest data for native mode IDE */
+ PciReadDeviceConfig(PdoExtension,
+ PciData->u.type0.BaseAddresses,
+ FIELD_OFFSET(PCI_COMMON_HEADER,
+ u.type0.BaseAddresses),
+ 4 * sizeof(ULONG));
+
+ /* Re-read the interrupt pin used for native mode IDE */
+ PciReadDeviceConfig(PdoExtension,
+ &PciData->u.type0.InterruptPin,
+ FIELD_OFFSET(PCI_COMMON_HEADER,
+ u.type0.InterruptPin),
+ sizeof(UCHAR));
+
+ /* The IDE Controller is now in native mode */
+ Switched = TRUE;
+ }
+ else
+ {
+ /* Settings did not work, fail */
+ DPRINT1("PCI: Warning failed switch to native mode for IDE controller VEN_%04x&DEV_%04x!",
+ PciData->VendorID,
+ PciData->DeviceID);
+ }
+ }
+
+ /* Return whether or not native mode was enabled on the IDE controller */
+ return Switched;
+}
+
+VOID
+NTAPI
+PciApplyHacks(IN PPCI_FDO_EXTENSION DeviceExtension,
+ IN PPCI_COMMON_HEADER PciData,
+ IN PCI_SLOT_NUMBER SlotNumber,
+ IN ULONG OperationType,
+ PPCI_PDO_EXTENSION PdoExtension)
+{
+ ULONG LegacyBaseAddress;
+ USHORT Command;
+ UCHAR RegValue;
+
+ /* There should always be a PDO extension passed in */
+ ASSERT(PdoExtension);
+
+ /* Check what kind of hack operation this is */
+ switch (OperationType)
+ {
+ /*
+ * This is mostly concerned with fixing up incorrect class data that can
+ * exist on certain PCI hardware before the 2.0 spec was ratified.
+ */
+ case PCI_HACK_FIXUP_BEFORE_CONFIGURATION:
+
+ /* Note that the i82375 PCI/EISA and the i82378 PCI/ISA bridges that
+ * are present on certain DEC/NT Alpha machines are pre-PCI 2.0 devices
+ * and appear as non-classified, so their correct class/subclass data
+ * is written here instead.
+ */
+ if ((PciData->VendorID == 0x8086) &&
+ ((PciData->DeviceID == 0x482) || (PciData->DeviceID == 0x484)))
+ {
+ /* Note that 0x482 is the i82375 (EISA), 0x484 is the i82378 (ISA) */
+ PciData->SubClass = PciData->DeviceID == 0x482 ?
+ PCI_SUBCLASS_BR_EISA : PCI_SUBCLASS_BR_ISA;
+ PciData->BaseClass = PCI_CLASS_BRIDGE_DEV;
+
+ /*
+ * Because the software is modifying the actual header data from
+ * the BIOS, this flag tells the driver to ignore failures when
+ * comparing the original BIOS data with the PCI data.
+ */
+ if (PdoExtension) PdoExtension->ExpectedWritebackFailure = TRUE;
+ }
+
+ /* Note that in this case, an immediate return is issued */
+ return;
+
+ /*
+ * This is concerned with setting up interrupts correctly for native IDE
+ * mode, but will also handle broken VGA decoding on older bridges as
+ * well as a PAE-specific hack for certain Compaq Hot-Plug Controllers.
+ */
+ case PCI_HACK_FIXUP_AFTER_CONFIGURATION:
+
+ /*
+ * On the OPTi Viper-M IDE controller, Linux doesn't support IDE-DMA
+ * and FreeBSD bug reports indicate that the system crashes when the
+ * feature is enabled (so it's disabled on that OS as well). In the
+ * NT PCI Bus Driver, it seems Microsoft too, completely disables
+ * Native IDE functionality on this controller, so it would seem OPTi
+ * simply frelled up this controller.
+ */
+ if ((PciData->VendorID == 0x1045) && (PciData->DeviceID != 0xC621))
+ {
+ /* Disable native mode */
+ PciData->ProgIf &= ~5;
+ PciData->u.type0.InterruptPin = 0;
+
+ /*
+ * Because the software is modifying the actual header data from
+ * the BIOS, this flag tells the driver to ignore failures when
+ * comparing the original BIOS data with the PCI data.
+ */
+ PdoExtension->ExpectedWritebackFailure = TRUE;
+ }
+ else if ((PciData->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
+ (PciData->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
+ {
+ /* For other IDE controllers, start out in compatible mode */
+ PdoExtension->BIOSAllowsIDESwitchToNativeMode = FALSE;
+
+ /*
+ * Registry must have enabled native mode (typically as a result
+ * of an INF file directive part of the IDE controller's driver)
+ * and the system must not be booted in Safe Mode. If that checks
+ * out, then evaluate the ACPI NATA method to see if the platform
+ * supports this. See the section "BIOS and Platform Prerequisites
+ * for Switching a Native-Mode-Capable Controller" in the Storage
+ * section of the Windows Driver Kit for more details:
+ *
+ * 5. For each ATA controller enumerated, the PCI bus driver checks
+ * the Programming Interface register of the IDE controller to
+ * see if it supports switching both channels to native mode.
+ * 6. The PCI bus driver checks whether the BIOS/platform supports
+ * switching the controller by checking the NATA method described
+ * earlier in this article.
+ *
+ * If an ATA controller does not indicate that it is native
+ * mode-capable, or if the BIOS NATA control method is missing
+ * or does not list that device, the PCI bus driver does not
+ * switch the controller and it is assigned legacy resources.
+ *
+ * If both the controller and the BIOS indicate that the controller
+ * can be switched, the process of switching the controller begins
+ * with the next step.
+ */
+ if ((PciEnableNativeModeATA) &&
+ !(InitSafeBootMode) &&
+ (PciIsSlotPresentInParentMethod(PdoExtension, 'ATAN')))
+ {
+ /* The platform supports it, remember that */
+ PdoExtension->BIOSAllowsIDESwitchToNativeMode = TRUE;
+
+ /*
+ * Now switch the controller into native mode if both channels
+ * support native IDE mode. See "How Windows Switches an ATA
+ * Controller to Native Mode" in the Storage section of the
+ * Windows Driver Kit for more details.
+ */
+ PdoExtension->SwitchedIDEToNativeMode =
+ PciConfigureIdeController(PdoExtension, PciData, 1);
+ }
+
+ /* Is native mode enabled after all? */
+ if ((PciData->ProgIf & 5) != 5)
+ {
+ /* Compatible mode, so force ISA-style IRQ14 and IRQ 15 */
+ PciData->u.type0.InterruptPin = 0;
+ }
+ }
+
+ /* Is this a PCI device with legacy VGA card decodes on the root bus? */
+ if ((PdoExtension->HackFlags & PCI_HACK_VIDEO_LEGACY_DECODE) &&
+ (PCI_IS_ROOT_FDO(DeviceExtension)) &&
+ !(DeviceExtension->BrokenVideoHackApplied))
+ {
+ /* Tell the arbiter to apply a hack for these older devices */
+ ario_ApplyBrokenVideoHack(DeviceExtension);
+ }
+
+ /* Is this a Compaq PCI Hotplug Controller (r17) on a PAE system ? */
+ if ((PciData->VendorID == 0xE11) &&
+ (PciData->DeviceID == 0xA0F7) &&
+ (PciData->RevisionID == 17) &&
+ (ExIsProcessorFeaturePresent(PF_PAE_ENABLED)))
+ {
+ /* Turn off the decodes immediately */
+ PciData->Command &= ~(PCI_ENABLE_IO_SPACE |
+ PCI_ENABLE_MEMORY_SPACE |
+ PCI_ENABLE_BUS_MASTER);
+ PciWriteDeviceConfig(PdoExtension,
+ &PciData->Command,
+ FIELD_OFFSET(PCI_COMMON_HEADER, Command),
+ sizeof(USHORT));
+
+ /* Do not EVER turn them on again, this will blow up the system */
+ PdoExtension->CommandEnables &= ~(PCI_ENABLE_IO_SPACE |
+ PCI_ENABLE_MEMORY_SPACE |
+ PCI_ENABLE_BUS_MASTER);
+ PdoExtension->HackFlags |= PCI_HACK_PRESERVE_COMMAND;
+ }
+ break;
+
+ /*
+ * This is called whenever resources are changed and hardware needs to be
+ * updated. It is concerned with two highly specific erratas on an IBM
+ * hot-plug docking bridge used on the Thinkpad 600 Series and on Intel's
+ * ICH PCI Bridges.
+ */
+ case PCI_HACK_FIXUP_BEFORE_UPDATE:
+
+ /* Is this an IBM 20H2999 PCI Docking Bridge, used on Thinkpads? */
+ if ((PdoExtension->VendorId == 0x1014) &&
+ (PdoExtension->DeviceId == 0x95))
+ {
+ /* Read the current command */
+ PciReadDeviceConfig(PdoExtension,
+ &Command,
+ FIELD_OFFSET(PCI_COMMON_HEADER, Command),
+ sizeof(USHORT));
+
+ /* Turn off the decodes */
+ PciDecodeEnable(PdoExtension, FALSE, &Command);
+
+ /* Apply the required IBM workaround */
+ PciReadDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR));
+ RegValue &= ~2;
+ RegValue |= 1;
+ PciWriteDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR));
+
+ /* Restore the command to its original value */
+ PciWriteDeviceConfig(PdoExtension,
+ &Command,
+ FIELD_OFFSET(PCI_COMMON_HEADER, Command),
+ sizeof(USHORT));
+
+ }
+
+ /*
+ * Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
+ * i820, i840, i845 Chipsets) that have subtractive decode enabled,
+ * and whose hack flags do not specifiy that this support is broken.
+ */
+ if ((PdoExtension->HeaderType == PCI_BRIDGE_TYPE) &&
+ (PdoExtension->Dependent.type1.SubtractiveDecode) &&
+ ((PdoExtension->VendorId == 0x8086) &&
+ ((PdoExtension->DeviceId == 0x2418) ||
+ (PdoExtension->DeviceId == 0x2428) ||
+ (PdoExtension->DeviceId == 0x244E) ||
+ (PdoExtension->DeviceId == 0x2448))) &&
+ !(PdoExtension->HackFlags & PCI_HACK_BROKEN_SUBTRACTIVE_DECODE))
+ {
+ /*
+ * The positive decode window shouldn't be used, these values are
+ * normally all read-only or initialized to 0 by the BIOS, but
+ * it appears Intel doesn't do this, so the PCI Bus Driver will
+ * do it in software instead. Note that this is used to prevent
+ * certain non-compliant PCI devices from breaking down due to the
+ * fact that these ICH bridges have a known "quirk" (which Intel
+ * documents as a known "erratum", although it's not not really
+ * an ICH bug since the PCI specification does allow for it) in
+ * that they will sometimes send non-zero addresses during special
+ * cycles (ie: non-zero data during the address phase). These
+ * broken PCI cards will mistakenly attempt to claim the special
+ * cycle and corrupt their I/O and RAM ranges. Again, in Intel's
+ * defense, the PCI specification only requires stable data, not
+ * necessarily zero data, during the address phase.
+ */
+ PciData->u.type1.MemoryBase = 0xFFFF;
+ PciData->u.type1.PrefetchBase = 0xFFFF;
+ PciData->u.type1.IOBase = 0xFF;
+ PciData->u.type1.IOLimit = 0;
+ PciData->u.type1.MemoryLimit = 0;
+ PciData->u.type1.PrefetchLimit = 0;
+ PciData->u.type1.PrefetchBaseUpper32 = 0;
+ PciData->u.type1.PrefetchLimitUpper32 = 0;
+ PciData->u.type1.IOBaseUpper16 = 0;
+ PciData->u.type1.IOLimitUpper16 = 0;
+ }
+ break;
+
+ default:
+ return;
+ }
+
+ /* Finally, also check if this is this a CardBUS device? */
+ if (PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE)
+ {
+ /*
+ * At offset 44h the LegacyBaseAddress is stored, which is cleared by
+ * ACPI-aware versions of Windows, to disable legacy-mode I/O access to
+ * CardBus controllers. For more information, see "Supporting CardBus
+ * Controllers under ACPI" in the "CardBus Controllers and Windows"
+ * Whitepaper on WHDC.
+ */
+ LegacyBaseAddress = 0;
+ PciWriteDeviceConfig(PdoExtension,
+ &LegacyBaseAddress,
+ sizeof(PCI_COMMON_HEADER) + sizeof(ULONG),
+ sizeof(ULONG));
+ }
+}
+
BOOLEAN
NTAPI
@@ -250,7 +673,8 @@
{
ULONG MaxDevice = PCI_MAX_DEVICES;
BOOLEAN ProcessFlag = FALSE;
- ULONG i, j, k;
+ ULONG i, j, k, Size;
+ USHORT CapOffset, TempOffset;
LONGLONG HackFlags;
PDEVICE_OBJECT DeviceObject;
UCHAR Buffer[PCI_COMMON_HDR_LENGTH];
@@ -258,11 +682,13 @@
PPCI_COMMON_HEADER PciData = (PVOID)Buffer;
PPCI_COMMON_HEADER BiosData = (PVOID)BiosBuffer;
PCI_SLOT_NUMBER PciSlot;
+ PCHAR Name;
NTSTATUS Status;
PPCI_PDO_EXTENSION PdoExtension, NewExtension;
PPCI_PDO_EXTENSION* BridgeExtension;
PWCHAR DescriptionText;
USHORT SubVendorId, SubSystemId;
+ PCI_CAPABILITIES_HEADER CapHeader, PcixCapHeader;
DPRINT1("PCI Scan Bus: FDO Extension @ 0x%x, Base Bus = 0x%x\n",
DeviceExtension, DeviceExtension->BaseBus);
@@ -302,6 +728,13 @@
&PciData->DeviceID,
sizeof(USHORT),
PCI_COMMON_HDR_LENGTH - sizeof(USHORT));
+
+ /* Apply any hacks before even analyzing the configuration header */
+ PciApplyHacks(DeviceExtension,
+ PciData,
+ PciSlot,
+ PCI_HACK_FIXUP_BEFORE_CONFIGURATION,
+ NULL);
/* Dump device that was found */
DPRINT1("Scan Found Device 0x%x (b=0x%x, d=0x%x, f=0x%x)\n",
@@ -373,8 +806,15 @@
HackFlags |= PCI_HACK_CRITICAL_DEVICE;
}
- /* Also skip devices that should not be enumerated */
- if (PciSkipThisFunction(PciData, PciSlot, 1, HackFlags)) continue;
+ /* Check if the device should be skipped for whatever reason */
+ if (PciSkipThisFunction(PciData,
+ PciSlot,
+ PCI_SKIP_DEVICE_ENUMERATION,
+ HackFlags))
+ {
+ /* Skip this device */
+ continue;
+ }
/* Check if a PDO has already been created for this device */
PdoExtension = PciFindPdoByFunction(DeviceExtension,
@@ -500,6 +940,13 @@
/* Power up the device */
PciSetPowerManagedDevicePowerState(NewExtension, PowerDeviceD0, FALSE);
+ /* Apply any device hacks required for enumeration */
+ PciApplyHacks(DeviceExtension,
+ PciData,
+ PciSlot,
+ PCI_HACK_FIXUP_AFTER_CONFIGURATION,
+ NewExtension);
+
/* Save interrupt pin */
NewExtension->InterruptPin = PciData->u.type0.InterruptPin;
@@ -520,6 +967,81 @@
/* Set the subsystem information to zero instead */
NewExtension->SubsystemVendorId = 0;
NewExtension->SubsystemId = 0;
+ }
+
+ /* Scan all capabilities */
+ CapOffset = NewExtension->CapabilitiesPtr;
+ while (CapOffset)
+ {
+ /* Read this header */
+ TempOffset = PciReadDeviceCapability(NewExtension,
+ CapOffset,
+ 0,
+ &CapHeader,
+ sizeof(PCI_CAPABILITIES_HEADER));
+ if (TempOffset != CapOffset)
+ {
+ /* This is a strange issue that shouldn't happen normally */
+ DPRINT1("PCI - Failed to read PCI capability at offset 0x%02x\n",
+ CapOffset);
+ ASSERT(TempOffset == CapOffset);
+ }
+
+ /* Check for capabilities that this driver cares about */
+ switch (CapHeader.CapabilityID)
+ {
+ /* Power management capability is heavily used by the bus */
+ case PCI_CAPABILITY_ID_POWER_MANAGEMENT:
+
+ /* Dump the capability */
+ Name = "POWER";
+ Size = sizeof(PCI_PM_CAPABILITY);
+ break;
+
+ /* AGP capability is required for AGP bus functionality */
+ case PCI_CAPABILITY_ID_AGP:
+
+ /* Dump the capability */
+ Name = "AGP";
+ Size = sizeof(PCI_AGP_CAPABILITY);
+ break;
+
+ /* This driver doesn't really use anything other than that */
+ default:
+
+ /* Windows prints this, we could do a translation later */
+ Name = "UNKNOWN CAPABILITY";
+ Size = 0;
+ break;
+ }
+
+ /* Check if this is a capability that should be dumped */
+ if (Size)
+ {
+ /* Read the whole capability data */
+ TempOffset = PciReadDeviceCapability(NewExtension,
+ CapOffset,
+ CapHeader.CapabilityID,
+ &CapHeader,
+ Size);
+
+ if (TempOffset != CapOffset)
+ {
+ /* Again, a strange issue that shouldn't be seen */
+ DPRINT1("- Failed to read capability data. ***\n");
+ ASSERT(TempOffset == CapOffset);
+ }
+ }
+
+ /* Dump this capability */
+ DPRINT1("CAP @%02x ID %02x (%s)\n",
+ CapOffset, CapHeader.CapabilityID, Name);
+ for (i = 0; i < Size; i += 2)
+ DPRINT1(" %04x\n", *(PUSHORT)((ULONG_PTR)&CapHeader + i));
+ DPRINT1("\n");
+
+ /* Check the next capability */
+ CapOffset = CapHeader.Next;
}
/* Check for IDE controllers */
@@ -544,6 +1066,39 @@
{
/* Do not allow these legacy bridges to be powered down */
NewExtension->DisablePowerDown = TRUE;
+ }
+
+ /* Check if the BIOS did not configure a cache line size */
+ if (!PciData->CacheLineSize)
+ {
+ /* Check if the device is disabled */
+ if (!(NewExtension->CommandEnables & (PCI_ENABLE_IO_SPACE |
+ PCI_ENABLE_MEMORY_SPACE |
+ PCI_ENABLE_BUS_MASTER)))
+ {
+ /* Check if this is a PCI-X device*/
+ TempOffset = PciReadDeviceCapability(NewExtension,
+ NewExtension->CapabilitiesPtr,
+ PCI_CAPABILITY_ID_PCIX,
+ &PcixCapHeader,
+ sizeof(PCI_CAPABILITIES_HEADER));
+
+ /*
+ * A device with default cache line size and latency timer
+ * settings is considered to be unconfigured. Note that on
+ * PCI-X, the reset value of the latency timer field in the
+ * header is 64, not 0, hence why the check for PCI-X caps
+ * was required, and the value used here below.
+ */
+ if (!(PciData->LatencyTimer) ||
+ ((TempOffset) && (PciData->LatencyTimer == 64)))
+ {
+ /* Keep track of the fact that it needs configuration */
+ DPRINT1("PCI - ScanBus, PDOx %x found unconfigured\n",
+ NewExtension);
+ NewExtension->NeedsHotPlugConfiguration = TRUE;
+ }
+ }
}
/* Save latency and cache size information */
Modified: trunk/reactos/drivers/bus/pcix/pci.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/bus/pcix/pci.h?rev…
==============================================================================
--- trunk/reactos/drivers/bus/pcix/pci.h [iso-8859-1] (original)
+++ trunk/reactos/drivers/bus/pcix/pci.h [iso-8859-1] Mon Jul 19 15:15:39 2010
@@ -63,6 +63,13 @@
#define PCI_SKIP_RESOURCE_ENUMERATION 0x02
//
+// PCI Apply Hack Flags
+//
+#define PCI_HACK_FIXUP_BEFORE_CONFIGURATION 0x00
+#define PCI_HACK_FIXUP_AFTER_CONFIGURATION 0x01
+#define PCI_HACK_FIXUP_BEFORE_UPDATE 0x03
+
+//
// PCI Debugging Device Support
//
#define MAX_DEBUGGING_DEVICES_SUPPORTED 0x04
@@ -71,7 +78,7 @@
// PCI Driver Verifier Failures
//
#define PCI_VERIFIER_CODES 0x04
-
+
//
// Device Extension, Interface, Translator and Arbiter Signatures
//
@@ -974,6 +981,21 @@
IN BOOLEAN ForPowerDown
);
+BOOLEAN
+NTAPI
+PciIsSlotPresentInParentMethod(
+ IN PPCI_PDO_EXTENSION PdoExtension,
+ IN ULONG Method
+);
+
+VOID
+NTAPI
+PciDecodeEnable(
+ IN PPCI_PDO_EXTENSION PdoExtension,
+ IN BOOLEAN Enable,
+ OUT PUSHORT Command
+);
+
//
// Configuration Routines
//
@@ -1232,6 +1254,12 @@
IN USHORT Version,
IN USHORT Size,
IN PINTERFACE Interface
+);
+
+VOID
+NTAPI
+ario_ApplyBrokenVideoHack(
+ IN PPCI_FDO_EXTENSION FdoExtension
);
NTSTATUS
@@ -1342,5 +1370,9 @@
extern PDRIVER_OBJECT PciDriverObject;
extern PWATCHDOG_TABLE WdTable;
extern PPCI_HACK_ENTRY PciHackTable;
+extern BOOLEAN PciEnableNativeModeATA;
+
+/* Exported by NTOS, should this go in the NDK? */
+extern NTSYSAPI BOOLEAN InitSafeBootMode;
/* EOF */
Modified: trunk/reactos/drivers/bus/pcix/utils.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/bus/pcix/utils.c?r…
==============================================================================
--- trunk/reactos/drivers/bus/pcix/utils.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/bus/pcix/utils.c [iso-8859-1] Mon Jul 19 15:15:39 2010
@@ -1041,4 +1041,117 @@
return !(HackFlags & PCI_HACK_NO_PM_CAPS);
}
+BOOLEAN
+NTAPI
+PciIsSlotPresentInParentMethod(IN PPCI_PDO_EXTENSION PdoExtension,
+ IN ULONG Method)
+{
+ BOOLEAN FoundSlot;
+ PACPI_METHOD_ARGUMENT Argument;
+ ACPI_EVAL_INPUT_BUFFER InputBuffer;
+ PACPI_EVAL_OUTPUT_BUFFER OutputBuffer;
+ ULONG i, Length;
+ NTSTATUS Status;
+ PAGED_CODE();
+
+ /* Assume slot is not part of the parent method */
+ FoundSlot = FALSE;
+
+ /* Allocate a 2KB buffer for the method return parameters */
+ Length = sizeof(ACPI_EVAL_OUTPUT_BUFFER) + 2048;
+ OutputBuffer = ExAllocatePoolWithTag(PagedPool, Length, 'BicP');
+ if (OutputBuffer)
+ {
+ /* Clear out the output buffer */
+ RtlZeroMemory(OutputBuffer, Length);
+
+ /* Initialize the input buffer with the method requested */
+ InputBuffer.Signature = 0;
+ *(PULONG)InputBuffer.MethodName = Method;
+ InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
+
+ /* Send it to the ACPI driver */
+ Status = PciSendIoctl(PdoExtension->ParentFdoExtension->PhysicalDeviceObject,
+ IOCTL_ACPI_EVAL_METHOD,
+ &InputBuffer,
+ sizeof(ACPI_EVAL_INPUT_BUFFER),
+ OutputBuffer,
+ Length);
+ if (NT_SUCCESS(Status))
+ {
+ /* Scan all output arguments */
+ for (i = 0; i < OutputBuffer->Count; i++)
+ {
+ /* Make sure it's an integer */
+ Argument = &OutputBuffer->Argument[i];
+ if (Argument->Type != ACPI_METHOD_ARGUMENT_INTEGER) continue;
+
+ /* Check if the argument matches this PCI slot structure */
+ if (Argument->Argument == ((PdoExtension->Slot.u.bits.DeviceNumber) |
+ ((PdoExtension->Slot.u.bits.FunctionNumber) << 16)))
+ {
+ /* This slot has been found, return it */
+ FoundSlot = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* Finished with the buffer, free it */
+ ExFreePoolWithTag(OutputBuffer, 0);
+ }
+
+ /* Return if the slot was found */
+ return FoundSlot;
+}
+
+VOID
+NTAPI
+PciDecodeEnable(IN PPCI_PDO_EXTENSION PdoExtension,
+ IN BOOLEAN Enable,
+ OUT PUSHORT Command)
+{
+ USHORT CommandValue;
+
+ /*
+ * If decodes are being disabled, make sure it's allowed, and in both cases,
+ * make sure that a hackflag isn't preventing touching the decodes at all.
+ */
+ if (((Enable) || (PciCanDisableDecodes(PdoExtension, 0, 0, 0))) &&
+ !(PdoExtension->HackFlags & PCI_HACK_PRESERVE_COMMAND))
+ {
+ /* Did the caller already have a command word? */
+ if (Command)
+ {
+ /* Use the caller's */
+ CommandValue = *Command;
+ }
+ else
+ {
+ /* Otherwise, read the current command */
+ PciReadDeviceConfig(PdoExtension,
+ &Command,
+ FIELD_OFFSET(PCI_COMMON_HEADER, Command),
+ sizeof(USHORT));
+ }
+
+ /* Turn off decodes by default */
+ CommandValue &= ~(PCI_ENABLE_IO_SPACE |
+ PCI_ENABLE_MEMORY_SPACE |
+ PCI_ENABLE_BUS_MASTER);
+
+ /* If requested, enable the decodes that were enabled at init time */
+ if (Enable) CommandValue |= PdoExtension->CommandEnables &
+ (PCI_ENABLE_IO_SPACE |
+ PCI_ENABLE_MEMORY_SPACE |
+ PCI_ENABLE_BUS_MASTER);
+
+ /* Update the command word */
+ PciWriteDeviceConfig(PdoExtension,
+ &CommandValue,
+ FIELD_OFFSET(PCI_COMMON_HEADER, Command),
+ sizeof(USHORT));
+ }
+}
+
/* EOF */
Author: evb
Date: Sun Jul 18 18:58:33 2010
New Revision: 48107
URL: http://svn.reactos.org/svn/reactos?rev=48107&view=rev
Log:
Can't sleep so write more source codes! add scan bus functions to get power caps (PciGetEnhancedCapabilities) and AGP caps, use PciReadDeviceCapability util function, now can get wake levels, PCI power state plus target AGP ID. Now can find PCI Device that can't sleep neither! Ha-ha!
Support PCI_HACK_NO_PM_CAPS, PCI_HACK_PRESERVE_COMMAND, PCI_HACK_DONT_DISABLE_DECOES
Add scan bus function to set power for PCI, for now to power up (PciSetPowerManagedDevicePowerState), with support for device that is critical/broken (PciCanDisableDecodes)
Check spec-correct with PciStallForPowerChange after define PciPowerDelayTable for D0<->D3 crossmatrix spec timings (add PciReadDeviceConfig for support)
If bad spec timing use PCI verifier support (PciVerifierRetrieveFailureData) + STATUS_DEVICE_PROTOCOL_ERROR
Add PciVerifierFailureTable with all failure type
Almost the time for resource discovery of BARs!
Modified:
trunk/reactos/drivers/bus/pcix/enum.c
trunk/reactos/drivers/bus/pcix/pci.h
trunk/reactos/drivers/bus/pcix/pci/config.c
trunk/reactos/drivers/bus/pcix/pcivrify.c
trunk/reactos/drivers/bus/pcix/power.c
trunk/reactos/drivers/bus/pcix/utils.c
Modified: trunk/reactos/drivers/bus/pcix/enum.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/bus/pcix/enum.c?re…
==============================================================================
--- trunk/reactos/drivers/bus/pcix/enum.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/bus/pcix/enum.c [iso-8859-1] Sun Jul 18 18:58:33 2010
@@ -122,6 +122,126 @@
/* Hit one of the known bugs/hackflags, or this is a new kind of PCI unit */
DPRINT1(" Device skipped (not enumerated).\n");
return TRUE;
+}
+
+VOID
+NTAPI
+PciGetEnhancedCapabilities(IN PPCI_PDO_EXTENSION PdoExtension,
+ IN PPCI_COMMON_HEADER PciData)
+{
+ ULONG HeaderType, CapPtr, TargetAgpCapabilityId;
+ DEVICE_POWER_STATE WakeLevel;
+ PCI_CAPABILITIES_HEADER AgpCapability;
+ PCI_PM_CAPABILITY PowerCapabilities;
+ PAGED_CODE();
+
+ /* Assume no known wake level */
+ PdoExtension->PowerState.DeviceWakeLevel = PowerDeviceUnspecified;
+
+ /* Make sure the device has capabilities */
+ if (!(PciData->Status & PCI_STATUS_CAPABILITIES_LIST))
+ {
+ /* If it doesn't, there will be no power management */
+ PdoExtension->CapabilitiesPtr = 0;
+ PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
+ }
+ else
+ {
+ /* There's capabilities, need to figure out where to get the offset */
+ HeaderType = PCI_CONFIGURATION_TYPE(PciData);
+ if (HeaderType == PCI_CARDBUS_BRIDGE_TYPE)
+ {
+ /* Use the bridge's header */
+ CapPtr = PciData->u.type2.CapabilitiesPtr;
+ }
+ else
+ {
+ /* Use the device header */
+ ASSERT(HeaderType <= PCI_CARDBUS_BRIDGE_TYPE);
+ CapPtr = PciData->u.type0.CapabilitiesPtr;
+ }
+
+ /* Make sure the pointer is spec-aligned and located, and save it */
+ DPRINT1("Device has capabilities at: %lx\n", CapPtr);
+ ASSERT(((CapPtr & 0x3) == 0) && (CapPtr >= PCI_COMMON_HDR_LENGTH));
+ PdoExtension->CapabilitiesPtr = CapPtr;
+
+ /* Check for PCI-to-PCI Bridges and AGP bridges */
+ if ((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
+ ((PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST) ||
+ (PdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI)))
+ {
+ /* Query either the raw AGP capabilitity, or the Target AGP one */
+ TargetAgpCapabilityId = (PdoExtension->SubClass ==
+ PCI_SUBCLASS_BR_PCI_TO_PCI) ?
+ PCI_CAPABILITY_ID_AGP_TARGET :
+ PCI_CAPABILITY_ID_AGP;
+ if (PciReadDeviceCapability(PdoExtension,
+ PdoExtension->CapabilitiesPtr,
+ TargetAgpCapabilityId,
+ &AgpCapability,
+ sizeof(PCI_CAPABILITIES_HEADER)))
+ {
+ /* AGP target ID was found, store it */
+ DPRINT1("AGP ID: %lx\n", TargetAgpCapabilityId);
+ PdoExtension->TargetAgpCapabilityId = TargetAgpCapabilityId;
+ }
+ }
+
+ /* Check for devices that are known not to have proper power management */
+ if (!(PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS))
+ {
+ /* Query if this device supports power management */
+ if (!PciReadDeviceCapability(PdoExtension,
+ PdoExtension->CapabilitiesPtr,
+ PCI_CAPABILITY_ID_POWER_MANAGEMENT,
+ &PowerCapabilities.Header,
+ sizeof(PCI_PM_CAPABILITY)))
+ {
+ /* No power management, so act as if it had the hackflag set */
+ DPRINT1("No PM caps, disabling PM\n");
+ PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
+ }
+ else
+ {
+ /* Otherwise, pick the highest wake level that is supported */
+ WakeLevel = PowerDeviceUnspecified;
+ if (PowerCapabilities.PMC.Capabilities.Support.PMED0)
+ WakeLevel = PowerDeviceD0;
+ if (PowerCapabilities.PMC.Capabilities.Support.PMED1)
+ WakeLevel = PowerDeviceD1;
+ if (PowerCapabilities.PMC.Capabilities.Support.PMED2)
+ WakeLevel = PowerDeviceD2;
+ if (PowerCapabilities.PMC.Capabilities.Support.PMED3Hot)
+ WakeLevel = PowerDeviceD3;
+ if (PowerCapabilities.PMC.Capabilities.Support.PMED3Cold)
+ WakeLevel = PowerDeviceD3;
+ PdoExtension->PowerState.DeviceWakeLevel = WakeLevel;
+
+ /* Convert the PCI power state to the NT power state */
+ PdoExtension->PowerState.CurrentDeviceState =
+ PowerCapabilities.PMCSR.ControlStatus.PowerState + 1;
+
+ /* Save all the power capabilities */
+ PdoExtension->PowerCapabilities = PowerCapabilities.PMC.Capabilities;
+ DPRINT1("PM Caps Found! Wake Level: %d Power State: %d\n",
+ WakeLevel, PdoExtension->PowerState.CurrentDeviceState);
+ }
+ }
+ }
+
+ /* At the very end of all this, does this device not have power management? */
+ if (PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS)
+ {
+ /* Then guess the current state based on whether the decodes are on */
+ PdoExtension->PowerState.CurrentDeviceState =
+ PciData->Command & (PCI_ENABLE_IO_SPACE |
+ PCI_ENABLE_MEMORY_SPACE |
+ PCI_ENABLE_BUS_MASTER) ?
+ PowerDeviceD0: PowerDeviceD3;
+ DPRINT1("PM is off, so assumed device is: %d based on enables\n",
+ PdoExtension->PowerState.CurrentDeviceState);
+ }
}
NTSTATUS
@@ -374,6 +494,12 @@
NewExtension->CommandEnables = PciData->Command;
NewExtension->HackFlags = HackFlags;
+ /* Get power, AGP, and other capability data */
+ PciGetEnhancedCapabilities(NewExtension, PciData);
+
+ /* Power up the device */
+ PciSetPowerManagedDevicePowerState(NewExtension, PowerDeviceD0, FALSE);
+
/* Save interrupt pin */
NewExtension->InterruptPin = PciData->u.type0.InterruptPin;
Modified: trunk/reactos/drivers/bus/pcix/pci.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/bus/pcix/pci.h?rev…
==============================================================================
--- trunk/reactos/drivers/bus/pcix/pci.h [iso-8859-1] (original)
+++ trunk/reactos/drivers/bus/pcix/pci.h [iso-8859-1] Sun Jul 18 18:58:33 2010
@@ -67,6 +67,11 @@
//
#define MAX_DEBUGGING_DEVICES_SUPPORTED 0x04
+//
+// PCI Driver Verifier Failures
+//
+#define PCI_VERIFIER_CODES 0x04
+
//
// Device Extension, Interface, Translator and Arbiter Signatures
//
@@ -376,6 +381,17 @@
} PCI_ARBITER_INSTANCE, *PPCI_ARBITER_INSTANCE;
//
+// PCI Verifier Data
+//
+typedef struct _PCI_VERIFIER_DATA
+{
+ ULONG FailureCode;
+ VF_FAILURE_CLASS FailureClass;
+ ULONG AssertionControl;
+ PCHAR DebuggerMessageText;
+} PCI_VERIFIER_DATA, *PPCI_VERIFIER_DATA;
+
+//
// IRP Dispatch Routines
//
NTSTATUS
@@ -440,6 +456,14 @@
IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_FDO_EXTENSION DeviceExtension
+);
+
+NTSTATUS
+NTAPI
+PciSetPowerManagedDevicePowerState(
+ IN PPCI_PDO_EXTENSION DeviceExtension,
+ IN DEVICE_POWER_STATE DeviceState,
+ IN BOOLEAN IrpSet
);
//
@@ -776,6 +800,12 @@
NTAPI
PciVerifierInit(
IN PDRIVER_OBJECT DriverObject
+);
+
+PPCI_VERIFIER_DATA
+NTAPI
+PciVerifierRetrieveFailureData(
+ IN ULONG FailureCode
);
//
@@ -925,6 +955,25 @@
OUT PPCI_COMMON_HEADER PciData
);
+UCHAR
+NTAPI
+PciReadDeviceCapability(
+ IN PPCI_PDO_EXTENSION DeviceExtension,
+ IN UCHAR Offset,
+ IN ULONG CapabilityId,
+ OUT PPCI_CAPABILITIES_HEADER Buffer,
+ IN ULONG Length
+);
+
+BOOLEAN
+NTAPI
+PciCanDisableDecodes(
+ IN PPCI_PDO_EXTENSION DeviceExtension,
+ IN PPCI_COMMON_HEADER Config,
+ IN ULONGLONG HackFlags,
+ IN BOOLEAN ForPowerDown
+);
+
//
// Configuration Routines
//
@@ -947,6 +996,15 @@
VOID
NTAPI
PciWriteDeviceConfig(
+ IN PPCI_PDO_EXTENSION DeviceExtension,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+);
+
+VOID
+NTAPI
+PciReadDeviceConfig(
IN PPCI_PDO_EXTENSION DeviceExtension,
IN PVOID Buffer,
IN ULONG Offset,
Modified: trunk/reactos/drivers/bus/pcix/pci/config.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/bus/pcix/pci/confi…
==============================================================================
--- trunk/reactos/drivers/bus/pcix/pci/config.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/bus/pcix/pci/config.c [iso-8859-1] Sun Jul 18 18:58:33 2010
@@ -24,7 +24,7 @@
{
UCHAR InterruptLine = 0, PciInterruptLine;
ULONG Length;
-
+
/* Does the device have an interrupt pin? */
if (PdoExtension->InterruptPin)
{
@@ -100,6 +100,22 @@
Offset,
Length,
FALSE);
+}
+
+VOID
+NTAPI
+PciReadDeviceConfig(IN PPCI_PDO_EXTENSION DeviceExtension,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length)
+{
+ /* Call the generic worker function */
+ PciReadWriteConfigSpace(DeviceExtension->ParentFdoExtension,
+ DeviceExtension->Slot,
+ Buffer,
+ Offset,
+ Length,
+ TRUE);
}
VOID
Modified: trunk/reactos/drivers/bus/pcix/pcivrify.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/bus/pcix/pcivrify.…
==============================================================================
--- trunk/reactos/drivers/bus/pcix/pcivrify.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/bus/pcix/pcivrify.c [iso-8859-1] Sun Jul 18 18:58:33 2010
@@ -17,7 +17,61 @@
BOOLEAN PciVerifierRegistered;
PVOID PciVerifierNotificationHandle;
+PCI_VERIFIER_DATA PciVerifierFailureTable[PCI_VERIFIER_CODES] =
+{
+ {
+ 1,
+ VFFAILURE_FAIL_LOGO,
+ 0,
+ "The BIOS has reprogrammed the bus numbers of an active PCI device "
+ "(!devstack %DevObj) during a dock or undock!"
+ },
+ {
+ 2,
+ VFFAILURE_FAIL_LOGO,
+ 0,
+ "A device in the system did not update it's PMCSR register in the spec "
+ "mandated time (!devstack %DevObj, Power state D%Ulong)"
+ },
+ {
+ 3,
+ VFFAILURE_FAIL_LOGO,
+ 0,
+ "A driver controlling a PCI device has tried to access OS controlled "
+ "configuration space registers (!devstack %DevObj, Offset 0x%Ulong1, "
+ "Length 0x%Ulong2)"
+ },
+ {
+ 4,
+ VFFAILURE_FAIL_UNDER_DEBUGGER,
+ 0,
+ "A driver controlling a PCI device has tried to read or write from an "
+ "invalid space using IRP_MN_READ/WRITE_CONFIG or via BUS_INTERFACE_STANDARD."
+ " NB: These functions take WhichSpace parameters of the form PCI_WHICHSPACE_*"
+ " and not a BUS_DATA_TYPE (!devstack %DevObj, WhichSpace 0x%Ulong1)"
+ },
+};
+
/* FUNCTIONS ******************************************************************/
+
+PPCI_VERIFIER_DATA
+NTAPI
+PciVerifierRetrieveFailureData(IN ULONG FailureCode)
+{
+ PPCI_VERIFIER_DATA VerifierData;
+
+ /* Scan the verifier failure table for this code */
+ VerifierData = PciVerifierFailureTable;
+ while (VerifierData->FailureCode != FailureCode)
+ {
+ /* Keep searching */
+ ++VerifierData;
+ ASSERT(VerifierData < &PciVerifierFailureTable[PCI_VERIFIER_CODES]);
+ }
+
+ /* Return the entry for this code */
+ return VerifierData;
+}
NTSTATUS
NTAPI
Modified: trunk/reactos/drivers/bus/pcix/power.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/bus/pcix/power.c?r…
==============================================================================
--- trunk/reactos/drivers/bus/pcix/power.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/bus/pcix/power.c [iso-8859-1] Sun Jul 18 18:58:33 2010
@@ -14,7 +14,191 @@
/* GLOBALS ********************************************************************/
+ULONG PciPowerDelayTable[PowerDeviceD3 * PowerDeviceD3] =
+{
+ 0, // D0 -> D0
+ 0, // D1 -> D0
+ 200, // D2 -> D0
+ 10000, // D3 -> D0
+
+ 0, // D0 -> D1
+ 0, // D1 -> D1
+ 200, // D2 -> D1
+ 10000, // D3 -> D1
+
+ 200, // D0 -> D2
+ 200, // D1 -> D2
+ 0, // D2 -> D2
+ 10000, // D3 -> D2
+
+ 10000, // D0 -> D3
+ 10000, // D1 -> D3
+ 10000, // D2 -> D3
+ 0 // D3 -> D3
+};
+
/* FUNCTIONS ******************************************************************/
+
+NTSTATUS
+NTAPI
+PciStallForPowerChange(IN PPCI_PDO_EXTENSION PdoExtension,
+ IN DEVICE_POWER_STATE PowerState,
+ IN ULONG_PTR CapOffset)
+{
+ ULONG PciState, TimeoutEntry, PmcsrOffset, TryCount;
+ PPCI_VERIFIER_DATA VerifierData;
+ LARGE_INTEGER Interval;
+ PCI_PMCSR Pmcsr;
+ KIRQL Irql;
+
+ /* Make sure the power state is valid, and the device can support it */
+ ASSERT((PdoExtension->PowerState.CurrentDeviceState >= PowerDeviceD0) &&
+ (PdoExtension->PowerState.CurrentDeviceState <= PowerDeviceD3));
+ ASSERT((PowerState >= PowerDeviceD0) && (PowerState <= PowerDeviceD3));
+ ASSERT(!(PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS));
+
+ /* Save the current IRQL */
+ Irql = KeGetCurrentIrql();
+
+ /* Pick the expected timeout for this transition */
+ TimeoutEntry = PciPowerDelayTable[PowerState * PdoExtension->PowerState.CurrentDeviceState];
+
+ /* PCI power states are one less than NT power states */
+ PciState = PowerState - 1;
+
+ /* The state status is stored in the PMCSR offset */
+ PmcsrOffset = CapOffset + FIELD_OFFSET(PCI_PM_CAPABILITY, PMCSR);
+
+ /* Try changing the power state up to 100 times */
+ TryCount = 100;
+ while (--TryCount)
+ {
+ /* Check if this state transition will take time */
+ if (TimeoutEntry > 0)
+ {
+ /* Check if this is happening at high IRQL */
+ if (Irql >= DISPATCH_LEVEL)
+ {
+ /* Can't wait at high IRQL, stall the processor */
+ KeStallExecutionProcessor(TimeoutEntry);
+ }
+ else
+ {
+ /* Do a wait for the timeout specified instead */
+ Interval.QuadPart = -10 * TimeoutEntry;
+ Interval.QuadPart -= KeQueryTimeIncrement() - 1;
+ KeDelayExecutionThread(0, 0, &Interval);
+ }
+ }
+
+ /* Read the PMCSR and see if the state has changed */
+ PciReadDeviceConfig(PdoExtension, &Pmcsr, PmcsrOffset, sizeof(PCI_PMCSR));
+ if (Pmcsr.PowerState == PciState) return STATUS_SUCCESS;
+
+ /* Try again, forcing a timeout of 1ms */
+ TimeoutEntry = 1000;
+ }
+
+ /* Call verifier with this error */
+ VerifierData = PciVerifierRetrieveFailureData(2);
+ ASSERT(VerifierData);
+ VfFailDeviceNode(PdoExtension->PhysicalDeviceObject,
+ PCI_VERIFIER_DETECTED_VIOLATION,
+ 2, // The PMCSR register was not updated within the spec-mandated time.
+ VerifierData->FailureClass,
+ &VerifierData->AssertionControl,
+ VerifierData->DebuggerMessageText,
+ "%DevObj%Ulong",
+ PdoExtension->PhysicalDeviceObject,
+ PciState);
+
+ return STATUS_DEVICE_PROTOCOL_ERROR;
+}
+
+NTSTATUS
+NTAPI
+PciSetPowerManagedDevicePowerState(IN PPCI_PDO_EXTENSION DeviceExtension,
+ IN DEVICE_POWER_STATE DeviceState,
+ IN BOOLEAN IrpSet)
+{
+ NTSTATUS Status;
+ PCI_PM_CAPABILITY PmCaps;
+ ULONG CapsOffset;
+
+ /* Assume success */
+ Status = STATUS_SUCCESS;
+
+ /* Check if this device can support low power states */
+ if (!(PciCanDisableDecodes(DeviceExtension, NULL, 0, TRUE)) &&
+ (DeviceState != PowerDeviceD0))
+ {
+ /* Simply return success, ignoring this request */
+ DPRINT1("Cannot disable decodes on this device, ignoring PM request...\n");
+ return Status;
+ }
+
+ /* Does the device support power management at all? */
+ if (!(DeviceExtension->HackFlags & PCI_HACK_NO_PM_CAPS))
+ {
+ /* Get the PM capabailities register */
+ CapsOffset = PciReadDeviceCapability(DeviceExtension,
+ DeviceExtension->CapabilitiesPtr,
+ PCI_CAPABILITY_ID_POWER_MANAGEMENT,
+ &PmCaps.Header,
+ sizeof(PCI_PM_CAPABILITY));
+ ASSERT(CapsOffset);
+ ASSERT(DeviceState != PowerDeviceUnspecified);
+
+ /* Check if the device is being powered up */
+ if (DeviceState == PowerDeviceD0)
+ {
+ /* Set full power state */
+ PmCaps.PMCSR.ControlStatus.PowerState = 0;
+
+ /* Check if the device supports Cold-D3 poweroff */
+ if (PmCaps.PMC.Capabilities.Support.PMED3Cold)
+ {
+ /* If there was a pending PME, clear it */
+ PmCaps.PMCSR.ControlStatus.PMEStatus = 1;
+ }
+ }
+ else
+ {
+ /* Otherwise, just set the new power state, converting from NT */
+ PmCaps.PMCSR.ControlStatus.PowerState = DeviceState - 1;
+ }
+
+ /* Write the new power state in the PMCSR */
+ PciWriteDeviceConfig(DeviceExtension,
+ &PmCaps.PMCSR,
+ CapsOffset + FIELD_OFFSET(PCI_PM_CAPABILITY, PMCSR),
+ sizeof(PCI_PMCSR));
+
+ /* Now wait for the change to "stick" based on the spec-mandated time */
+ Status = PciStallForPowerChange(DeviceExtension, DeviceState, CapsOffset);
+ if (!NT_SUCCESS(Status)) return Status;
+ }
+ else
+ {
+ /* Nothing to do! */
+ DPRINT1("No PM on this device, ignoring request\n");
+ }
+
+ /* Check if new resources have to be assigned */
+ if (IrpSet)
+ {
+ /* Check if the new device state is lower (higher power) than now */
+ if (DeviceState < DeviceExtension->PowerState.CurrentDeviceState)
+ {
+ /* We would normally re-assign resources after powerup */
+ UNIMPLEMENTED;
+ while (TRUE);
+ }
+ }
+
+ /* Return the power state change status */
+ return Status;
+}
NTSTATUS
NTAPI
Modified: trunk/reactos/drivers/bus/pcix/utils.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/bus/pcix/utils.c?r…
==============================================================================
--- trunk/reactos/drivers/bus/pcix/utils.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/bus/pcix/utils.c [iso-8859-1] Sun Jul 18 18:58:33 2010
@@ -864,7 +864,7 @@
DeviceExtension->Slot.u.bits.DeviceNumber,
DeviceExtension->Slot.u.bits.FunctionNumber);
RtlInitUnicodeString(&KeyValue, Buffer);
-
+
/* Set the value data (the PCI BIOS configuration header) */
Status = ZwSetValueKey(SubKeyHandle,
&KeyValue,
@@ -876,4 +876,169 @@
return Status;
}
+UCHAR
+NTAPI
+PciReadDeviceCapability(IN PPCI_PDO_EXTENSION DeviceExtension,
+ IN UCHAR Offset,
+ IN ULONG CapabilityId,
+ OUT PPCI_CAPABILITIES_HEADER Buffer,
+ IN ULONG Length)
+{
+ ULONG CapabilityCount = 0;
+
+ /* If the device has no capabilility list, fail */
+ if (!Offset) return 0;
+
+ /* Validate a PDO with capabilities, a valid buffer, and a valid length */
+ ASSERT(DeviceExtension->ExtensionType == PciPdoExtensionType);
+ ASSERT(DeviceExtension->CapabilitiesPtr != 0);
+ ASSERT(Buffer);
+ ASSERT(Length >= sizeof(PCI_CAPABILITIES_HEADER));
+
+ /* Loop all capabilities */
+ while (Offset)
+ {
+ /* Make sure the pointer is spec-aligned and spec-sized */
+ ASSERT((Offset >= PCI_COMMON_HDR_LENGTH) && ((Offset & 0x3) == 0));
+
+ /* Read the capability header */
+ PciReadDeviceConfig(DeviceExtension,
+ Buffer,
+ Offset,
+ sizeof(PCI_CAPABILITIES_HEADER));
+
+ /* Check if this is the capability being looked up */
+ if ((Buffer->CapabilityID == CapabilityId) || !(CapabilityId))
+ {
+ /* Check if was at a valid offset and length */
+ if ((Offset) && (Length > sizeof(PCI_CAPABILITIES_HEADER)))
+ {
+ /* Sanity check */
+ ASSERT(Length <= (sizeof(PCI_COMMON_CONFIG) - Offset));
+
+ /* Now read the whole capability data into the buffer */
+ PciReadDeviceConfig(DeviceExtension,
+ (PVOID)((ULONG_PTR)Buffer +
+ sizeof(PCI_CAPABILITIES_HEADER)),
+ Offset + sizeof(PCI_CAPABILITIES_HEADER),
+ Length - sizeof(PCI_CAPABILITIES_HEADER));
+ }
+
+ /* Return the offset where the capability was found */
+ return Offset;
+ }
+
+ /* Try the next capability instead */
+ CapabilityCount++;
+ Offset = Buffer->Next;
+
+ /* There can't be more than 48 capabilities (256 bytes max) */
+ if (CapabilityCount > 48)
+ {
+ /* Fail, since this is basically a broken PCI device */
+ DPRINT1("PCI device %p capabilities list is broken.\n", DeviceExtension);
+ return 0;
+ }
+ }
+
+ /* Capability wasn't found, fail */
+ return 0;
+}
+
+BOOLEAN
+NTAPI
+PciCanDisableDecodes(IN PPCI_PDO_EXTENSION DeviceExtension,
+ IN PPCI_COMMON_HEADER Config,
+ IN ULONGLONG HackFlags,
+ IN BOOLEAN ForPowerDown)
+{
+ UCHAR BaseClass, SubClass;
+ BOOLEAN IsVga;
+
+ /* Is there a device extension or should the PCI header be used? */
+ if (DeviceExtension)
+ {
+ /* Never disable decodes for a debug PCI Device */
+ if (DeviceExtension->OnDebugPath) return FALSE;
+
+ /* Hack flags will be obtained from the extension, not the caller */
+ ASSERT(HackFlags == 0);
+
+ /* Get hacks and classification from the device extension */
+ HackFlags = DeviceExtension->HackFlags;
+ SubClass = DeviceExtension->SubClass;
+ BaseClass = DeviceExtension->BaseClass;
+ }
+ else
+ {
+ /* There must be a PCI header, go read the classification information */
+ ASSERT(Config != NULL);
+ BaseClass = Config->BaseClass;
+ SubClass = Config->SubClass;
+ }
+
+ /* Check for hack flags that prevent disabling the decodes */
+ if (HackFlags & (PCI_HACK_PRESERVE_COMMAND |
+ PCI_HACK_CB_SHARE_CMD_BITS |
+ PCI_HACK_DONT_DISABLE_DECODES))
+ {
+ /* Don't do it */
+ return FALSE;
+ }
+
+ /* Is this a VGA adapter? */
+ if ((BaseClass == PCI_CLASS_DISPLAY_CTLR) &&
+ (SubClass == PCI_SUBCLASS_VID_VGA_CTLR))
+ {
+ /* Never disable decodes if this is for power down */
+ return ForPowerDown;
+ }
+
+ /* Check for legacy devices */
+ if (BaseClass == PCI_CLASS_PRE_20)
+ {
+ /* Never disable video adapter cards if this is for power down */
+ if (SubClass == PCI_SUBCLASS_PRE_20_VGA) return ForPowerDown;
+ }
+ else if (BaseClass == PCI_CLASS_DISPLAY_CTLR)
+ {
+ /* Never disable VGA adapters if this is for power down */
+ if (SubClass == PCI_SUBCLASS_VID_VGA_CTLR) return ForPowerDown;
+ }
+ else if (BaseClass == PCI_CLASS_BRIDGE_DEV)
+ {
+ /* Check for legacy bridges */
+ if ((SubClass == PCI_SUBCLASS_BR_ISA) ||
+ (SubClass == PCI_SUBCLASS_BR_EISA) ||
+ (SubClass == PCI_SUBCLASS_BR_MCA) ||
+ (SubClass == PCI_SUBCLASS_BR_HOST) ||
+ (SubClass == PCI_SUBCLASS_BR_OTHER))
+ {
+ /* Never disable these */
+ return FALSE;
+ }
+ else if ((SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) ||
+ (SubClass == PCI_SUBCLASS_BR_CARDBUS))
+ {
+ /* This is a supported bridge, but does it have a VGA card? */
+ if (!DeviceExtension)
+ {
+ /* Read the bridge control flag from the PCI header */
+ IsVga = Config->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA;
+ }
+ else
+ {
+ /* Read the cached flag in the device extension */
+ IsVga = DeviceExtension->Dependent.type1.VgaBitSet;
+ }
+
+ /* Never disable VGA adapters if this is for power down */
+ if (IsVga) return ForPowerDown;
+ }
+ }
+
+ /* Finally, never disable decodes if there's no power management */
+ return !(HackFlags & PCI_HACK_NO_PM_CAPS);
+}
+
/* EOF */