More PciScanBus codes now to check saved PCI BIOS config header saved in registry (PciGetBiosConfig, PciSaveBiosConfig) and support load save compare (PcipIsSameDevice) if change in interrupt line

Also for interrupt line use HAL to get parent bus IRQ# if device connected (PciGetAdjustedInterruptLine)
For PCI debug HW PciIsDeviceOnDebugPath to detect, but have not real machine with this kind of device to test
Support PCI_HACK_NO_SUBSYSTEM and PCI_HACK_NO_SUBSYSTEM/REVISION_AFTER_D3 for when compareing
New config function required PciWriteDeviceConfig to update IRQ line from BIOS registry data
Save initial, current Command enables to PDO extension, interrupt data too

svn path=/trunk/; revision=48100
This commit is contained in:
evb 2010-07-17 16:53:18 +00:00
parent 693551c36a
commit 54dcdffd9e
4 changed files with 338 additions and 10 deletions

View file

@ -16,6 +16,40 @@
/* FUNCTIONS ******************************************************************/
BOOLEAN
NTAPI
PcipIsSameDevice(IN PPCI_PDO_EXTENSION DeviceExtension,
IN PPCI_COMMON_HEADER PciData)
{
BOOLEAN IdMatch, RevMatch, SubsysMatch;
ULONGLONG HackFlags = DeviceExtension->HackFlags;
/* Check if the IDs match */
IdMatch = (PciData->VendorID == DeviceExtension->VendorId) &&
(PciData->DeviceID == DeviceExtension->DeviceId);
if (!IdMatch) return FALSE;
/* If the device has a valid revision, check if it matches */
RevMatch = (HackFlags & PCI_HACK_NO_REVISION_AFTER_D3) ||
(PciData->RevisionID == DeviceExtension->RevisionId);
if (!RevMatch) return FALSE;
/* For multifunction devices, this is enough to assume they're the same */
if (PCI_MULTIFUNCTION_DEVICE(PciData)) return TRUE;
/* For bridge devices, there's also nothing else that can be checked */
if (DeviceExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) return TRUE;
/* Devices, on the other hand, have subsystem data that can be compared */
SubsysMatch = (HackFlags & (PCI_HACK_NO_SUBSYSTEM |
PCI_HACK_NO_SUBSYSTEM_AFTER_D3)) ||
((DeviceExtension->SubsystemVendorId ==
PciData->u.type0.SubVendorID) &&
(DeviceExtension->SubsystemId ==
PciData->u.type0.SubSystemID));
return SubsysMatch;
}
BOOLEAN
NTAPI
PciSkipThisFunction(IN PPCI_COMMON_HEADER PciData,
@ -100,7 +134,9 @@ PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
LONGLONG HackFlags;
PDEVICE_OBJECT DeviceObject;
UCHAR Buffer[PCI_COMMON_HDR_LENGTH];
UCHAR BiosBuffer[PCI_COMMON_HDR_LENGTH];
PPCI_COMMON_HEADER PciData = (PVOID)Buffer;
PPCI_COMMON_HEADER BiosData = (PVOID)BiosBuffer;
PCI_SLOT_NUMBER PciSlot;
NTSTATUS Status;
PPCI_PDO_EXTENSION PdoExtension, NewExtension;
@ -160,7 +196,8 @@ PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
/* Find description for this device for the debugger's sake */
DescriptionText = PciGetDeviceDescriptionMessage(PciData->BaseClass,
PciData->SubClass);
DPRINT1("Device Description \"%S\".\n", DescriptionText ? DescriptionText : L"(NULL)");
DPRINT1("Device Description \"%S\".\n",
DescriptionText ? DescriptionText : L"(NULL)");
if (DescriptionText) ExFreePoolWithTag(DescriptionText, 0);
/* Check if there is an ACPI Watchdog Table */
@ -258,7 +295,7 @@ PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
NewExtension->BaseClass = PciData->BaseClass;
NewExtension->HeaderType = PCI_CONFIGURATION_TYPE(PciData);
/* Check for PCI or Cardbus bridges, which are supported by this driver */
/* Check for modern bridge types, which are managed by the driver */
if ((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
((NewExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) ||
(NewExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS)))
@ -281,10 +318,84 @@ PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
ASSERT(NewExtension->NextBridge == NULL);
/* Release this device's lock */
KeSetEvent(&DeviceExtension->ChildListLock, IO_NO_INCREMENT, FALSE);
KeSetEvent(&DeviceExtension->ChildListLock,
IO_NO_INCREMENT,
FALSE);
KeLeaveCriticalRegion();
}
/* Get the PCI BIOS configuration saved in the registry */
Status = PciGetBiosConfig(NewExtension, BiosData);
if (NT_SUCCESS(Status))
{
/* This path has not yet been fully tested by eVb */
DPRINT1("Have BIOS configuration!\n");
UNIMPLEMENTED;
/* Check if the PCI BIOS configuration has changed */
if (!PcipIsSameDevice(NewExtension, BiosData))
{
/* This is considered failure, and new data will be saved */
Status = STATUS_UNSUCCESSFUL;
}
else
{
/* Data is still correct, check for interrupt line change */
if (BiosData->u.type0.InterruptLine !=
PciData->u.type0.InterruptLine)
{
/* Update the current BIOS with the saved interrupt line */
PciWriteDeviceConfig(NewExtension,
&BiosData->u.type0.InterruptLine,
FIELD_OFFSET(PCI_COMMON_HEADER,
u.type0.InterruptLine),
sizeof(UCHAR));
}
/* Save the BIOS interrupt line and the initial command */
NewExtension->RawInterruptLine = BiosData->u.type0.InterruptLine;
NewExtension->InitialCommand = BiosData->Command;
}
}
/* Check if no saved data was present or if it was a mismatch */
if (!NT_SUCCESS(Status))
{
/* Save the new data */
Status = PciSaveBiosConfig(NewExtension, PciData);
ASSERT(NT_SUCCESS(Status));
/* Save the interrupt line and command from the device */
NewExtension->RawInterruptLine = PciData->u.type0.InterruptLine;
NewExtension->InitialCommand = PciData->Command;
}
/* Save original command from the device and hack flags */
NewExtension->CommandEnables = PciData->Command;
NewExtension->HackFlags = HackFlags;
/* Save interrupt pin */
NewExtension->InterruptPin = PciData->u.type0.InterruptPin;
/*
* Use either this device's actual IRQ line or, if it's connected on
* a master bus whose IRQ line is actually connected to the host, use
* the HAL to query the bus' IRQ line and store that as the adjusted
* interrupt line instead
*/
NewExtension->AdjustedInterruptLine = PciGetAdjustedInterruptLine(NewExtension);
/* Check if this device is used for PCI debugger cards */
NewExtension->OnDebugPath = PciIsDeviceOnDebugPath(NewExtension);
/* Check for devices with invalid/bogus subsystem data */
if (HackFlags & PCI_HACK_NO_SUBSYSTEM)
{
/* Set the subsystem information to zero instead */
NewExtension->SubsystemVendorId = 0;
NewExtension->SubsystemId = 0;
}
/* Check for IDE controllers */
if ((NewExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
(NewExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
@ -292,26 +403,27 @@ PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
/* Do not allow them to power down completely */
NewExtension->DisablePowerDown = TRUE;
}
/*
* Check if this is a legacy bridge. Note that the i82375 PCI/EISA
* bridge that is present on certain NT Alpha machines appears as
* bridge that is present on certain NT Alpha machines appears as
* non-classified so detect it manually by scanning for its VID/PID.
*/
if (((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
((NewExtension->SubClass == PCI_SUBCLASS_BR_ISA) ||
(NewExtension->SubClass == PCI_SUBCLASS_BR_EISA) ||
(NewExtension->SubClass == PCI_SUBCLASS_BR_MCA))) ||
((NewExtension->VendorId == 0x8086) && (NewExtension->DeviceId == 0x482)))
((NewExtension->VendorId == 0x8086) &&
(NewExtension->DeviceId == 0x482)))
{
/* Do not allow these legacy bridges to be powered down */
NewExtension->DisablePowerDown = TRUE;
}
/* Save latency and cache size information */
NewExtension->SavedLatencyTimer = PciData->LatencyTimer;
NewExtension->SavedCacheLineSize = PciData->CacheLineSize;
/* The PDO is now ready to go */
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
}

View file

@ -57,11 +57,16 @@
#define PCI_INTERFACE_ROOT 0x04
//
// PCI Skip Function FLags
// PCI Skip Function Flags
//
#define PCI_SKIP_DEVICE_ENUMERATION 0x01
#define PCI_SKIP_RESOURCE_ENUMERATION 0x02
//
// PCI Debugging Device Support
//
#define MAX_DEBUGGING_DEVICES_SUPPORTED 0x04
//
// Device Extension, Interface, Translator and Arbiter Signatures
//
@ -900,6 +905,26 @@ PciIsCriticalDeviceClass(
IN UCHAR SubClass
);
BOOLEAN
NTAPI
PciIsDeviceOnDebugPath(
IN PPCI_PDO_EXTENSION DeviceExtension
);
NTSTATUS
NTAPI
PciGetBiosConfig(
IN PPCI_PDO_EXTENSION DeviceExtension,
OUT PPCI_COMMON_HEADER PciData
);
NTSTATUS
NTAPI
PciSaveBiosConfig(
IN PPCI_PDO_EXTENSION DeviceExtension,
OUT PPCI_COMMON_HEADER PciData
);
//
// Configuration Routines
//
@ -919,6 +944,21 @@ PciReadSlotConfig(
IN ULONG Length
);
VOID
NTAPI
PciWriteDeviceConfig(
IN PPCI_PDO_EXTENSION DeviceExtension,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
);
UCHAR
NTAPI
PciGetAdjustedInterruptLine(
IN PPCI_PDO_EXTENSION PdoExtension
);
//
// State Machine Logic Transition Routines
//

View file

@ -18,6 +18,31 @@ BOOLEAN PciAssignBusNumbers;
/* FUNCTIONS ******************************************************************/
UCHAR
NTAPI
PciGetAdjustedInterruptLine(IN PPCI_PDO_EXTENSION PdoExtension)
{
UCHAR InterruptLine = 0, PciInterruptLine;
ULONG Length;
/* Does the device have an interrupt pin? */
if (PdoExtension->InterruptPin)
{
/* Find the associated line on the parent bus */
Length = HalGetBusDataByOffset(PCIConfiguration,
PdoExtension->ParentFdoExtension->BaseBus,
PdoExtension->Slot.u.AsULONG,
&PciInterruptLine,
FIELD_OFFSET(PCI_COMMON_HEADER,
u.type0.InterruptLine),
sizeof(UCHAR));
if (Length) InterruptLine = PciInterruptLine;
}
/* Either keep the original interrupt line, or the one on the master bus */
return InterruptLine ? PdoExtension->RawInterruptLine : InterruptLine;
}
VOID
NTAPI
PciReadWriteConfigSpace(IN PPCI_FDO_EXTENSION DeviceExtension,
@ -61,6 +86,22 @@ PciReadWriteConfigSpace(IN PPCI_FDO_EXTENSION DeviceExtension,
}
}
VOID
NTAPI
PciWriteDeviceConfig(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,
FALSE);
}
VOID
NTAPI
PciReadSlotConfig(IN PPCI_FDO_EXTENSION DeviceExtension,

View file

@ -14,6 +14,8 @@
/* GLOBALS ********************************************************************/
ULONG PciDebugPortsCount;
RTL_RANGE_LIST PciIsaBitExclusionList;
RTL_RANGE_LIST PciVgaAndIsaBitExclusionList;
@ -741,4 +743,137 @@ PciFindPdoByFunction(IN PPCI_FDO_EXTENSION DeviceExtension,
return PdoExtension;
}
BOOLEAN
NTAPI
PciIsDeviceOnDebugPath(IN PPCI_PDO_EXTENSION DeviceExtension)
{
PAGED_CODE();
/* Check for too many, or no, debug ports */
ASSERT(PciDebugPortsCount <= MAX_DEBUGGING_DEVICES_SUPPORTED);
if (!PciDebugPortsCount) return FALSE;
/* eVb has not been able to test such devices yet */
UNIMPLEMENTED;
while (TRUE);
}
NTSTATUS
NTAPI
PciGetBiosConfig(IN PPCI_PDO_EXTENSION DeviceExtension,
OUT PPCI_COMMON_HEADER PciData)
{
HANDLE KeyHandle, SubKeyHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName, KeyValue;
WCHAR Buffer[32];
WCHAR DataBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + PCI_COMMON_HDR_LENGTH];
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)DataBuffer;
NTSTATUS Status;
ULONG ResultLength;
PAGED_CODE();
/* Open the PCI key */
Status = IoOpenDeviceRegistryKey(DeviceExtension->ParentFdoExtension->
PhysicalDeviceObject,
TRUE,
KEY_ALL_ACCESS,
&KeyHandle);
if (!NT_SUCCESS(Status)) return Status;
/* Create a volatile BIOS configuration key */
RtlInitUnicodeString(&KeyName, L"BiosConfig");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_KERNEL_HANDLE,
KeyHandle,
NULL);
Status = ZwCreateKey(&SubKeyHandle,
KEY_READ,
&ObjectAttributes,
0,
NULL,
REG_OPTION_VOLATILE,
NULL);
ZwClose(KeyHandle);
if (!NT_SUCCESS(Status)) return Status;
/* Create the key value based on the device and function number */
swprintf(Buffer,
L"DEV_%02x&FUN_%02x",
DeviceExtension->Slot.u.bits.DeviceNumber,
DeviceExtension->Slot.u.bits.FunctionNumber);
RtlInitUnicodeString(&KeyValue, Buffer);
/* Query the value information (PCI BIOS configuration header) */
Status = ZwQueryValueKey(SubKeyHandle,
&KeyValue,
KeyValuePartialInformation,
PartialInfo,
sizeof(DataBuffer),
&ResultLength);
ZwClose(SubKeyHandle);
if (!NT_SUCCESS(Status)) return Status;
/* If any information was returned, go ahead and copy its data */
ASSERT(PartialInfo->DataLength == PCI_COMMON_HDR_LENGTH);
RtlCopyMemory(PciData, PartialInfo->Data, PCI_COMMON_HDR_LENGTH);
return Status;
}
NTSTATUS
NTAPI
PciSaveBiosConfig(IN PPCI_PDO_EXTENSION DeviceExtension,
IN PPCI_COMMON_HEADER PciData)
{
HANDLE KeyHandle, SubKeyHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName, KeyValue;
WCHAR Buffer[32];
NTSTATUS Status;
PAGED_CODE();
/* Open the PCI key */
Status = IoOpenDeviceRegistryKey(DeviceExtension->ParentFdoExtension->
PhysicalDeviceObject,
TRUE,
KEY_READ | KEY_WRITE,
&KeyHandle);
if (!NT_SUCCESS(Status)) return Status;
/* Create a volatile BIOS configuration key */
RtlInitUnicodeString(&KeyName, L"BiosConfig");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_KERNEL_HANDLE,
KeyHandle,
NULL);
Status = ZwCreateKey(&SubKeyHandle,
KEY_READ | KEY_WRITE,
&ObjectAttributes,
0,
NULL,
REG_OPTION_VOLATILE,
NULL);
ZwClose(KeyHandle);
if (!NT_SUCCESS(Status)) return Status;
/* Create the key value based on the device and function number */
swprintf(Buffer,
L"DEV_%02x&FUN_%02x",
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,
0,
REG_BINARY,
PciData,
PCI_COMMON_HDR_LENGTH);
ZwClose(SubKeyHandle);
return Status;
}
/* EOF */