More implement of PciScanBus, now read hack flags from table (PciGetHAckFlags), and check for critical device (PciIsCriticalDeviceClass) and VGA device on PCI bridge

Do check for skipping some function (double decker ghost, Intel Alder SMP Pentium Pro machine, hacl flag, more), PciSkipThisfunction
Do check for PDO already exist for function (PciFindPdoByFunction)
Finish impement PciFindParentPciFdoExtension

svn path=/trunk/; revision=48098
This commit is contained in:
evb 2010-07-17 15:09:19 +00:00
parent 11006f580c
commit 7ebde38343
4 changed files with 344 additions and 6 deletions

View file

@ -16,16 +16,93 @@
/* FUNCTIONS ******************************************************************/ /* FUNCTIONS ******************************************************************/
BOOLEAN
NTAPI
PciSkipThisFunction(IN PPCI_COMMON_HEADER PciData,
IN PCI_SLOT_NUMBER Slot,
IN UCHAR OperationType,
IN ULONGLONG HackFlags)
{
do
{
/* Check if this is device enumeration */
if (OperationType == PCI_SKIP_DEVICE_ENUMERATION)
{
/* Check if there's a hackflag saying not to enumerate this device */
if (HackFlags & PCI_HACK_NO_ENUM_AT_ALL) break;
/* Check if this is the high end of a double decker device */
if ((HackFlags & PCI_HACK_DOUBLE_DECKER) &&
(Slot.u.bits.DeviceNumber >= 16))
{
/* It belongs to the same device, so skip it */
DPRINT1(" Device (Ven %04x Dev %04x (d=0x%x, f=0x%x)) is a ghost.\n",
PciData->VendorID,
PciData->DeviceID,
Slot.u.bits.DeviceNumber,
Slot.u.bits.FunctionNumber);
break;
}
}
else if (OperationType == PCI_SKIP_RESOURCE_ENUMERATION)
{
/* Resource enumeration, check for a hackflag saying not to do it */
if (HackFlags & PCI_HACK_ENUM_NO_RESOURCE) break;
}
else
{
/* Logic error in the driver */
ASSERTMSG(FALSE, "PCI Skip Function - Operation type unknown.");
}
/* Check for legacy bridges during resource enumeration */
if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
(PciData->SubClass <= PCI_SUBCLASS_BR_MCA) &&
(OperationType == PCI_SKIP_RESOURCE_ENUMERATION))
{
/* Their resources are not enumerated, only PCI and Cardbus/PCMCIA */
break;
}
else if (PciData->BaseClass == PCI_CLASS_NOT_DEFINED)
{
/* Undefined base class (usually a PCI BIOS/ROM bug) */
DPRINT1(" Vendor %04x, Device %04x has class code of PCI_CLASS_NOT_DEFINED\n",
PciData->VendorID,
PciData->DeviceID);
/*
* The Alder has an Intel Extended Express System Support Controller
* which presents apparently spurious BARs. When the PCI resource
* code tries to reassign these BARs, the second IO-APIC gets
* disabled (with disastrous consequences). The first BAR is the
* actual IO-APIC, the remaining five bars seem to be spurious
* resources, so ignore this device completely.
*/
if ((PciData->VendorID == 0x8086) && (PciData->DeviceID == 8)) break;
}
/* Other normal PCI cards and bridges are enumerated */
if (PCI_CONFIGURATION_TYPE(PciData) <= PCI_CARDBUS_BRIDGE_TYPE) return FALSE;
} while (FALSE);
/* Hit one of the known bugs/hackflags, or this is a new kind of PCI unit */
DPRINT1(" Device skipped (not enumerated).\n");
return TRUE;
}
NTSTATUS NTSTATUS
NTAPI NTAPI
PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension) PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
{ {
ULONG MaxDevice = PCI_MAX_DEVICES; ULONG MaxDevice = PCI_MAX_DEVICES;
ULONG i, j, k; ULONG i, j, k;
LONGLONG HackFlags;
UCHAR Buffer[PCI_COMMON_HDR_LENGTH]; UCHAR Buffer[PCI_COMMON_HDR_LENGTH];
PPCI_COMMON_HEADER PciData = (PVOID)Buffer; PPCI_COMMON_HEADER PciData = (PVOID)Buffer;
PCI_SLOT_NUMBER PciSlot; PCI_SLOT_NUMBER PciSlot;
PWCHAR DescriptionText; PWCHAR DescriptionText;
USHORT SubVendorId, SubSystemId;
PPCI_PDO_EXTENSION PdoExtension;
DPRINT1("PCI Scan Bus: FDO Extension @ 0x%x, Base Bus = 0x%x\n", DPRINT1("PCI Scan Bus: FDO Extension @ 0x%x, Base Bus = 0x%x\n",
DeviceExtension, DeviceExtension->BaseBus); DeviceExtension, DeviceExtension->BaseBus);
@ -89,6 +166,65 @@ PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
UNIMPLEMENTED; UNIMPLEMENTED;
while (TRUE); while (TRUE);
} }
/* Check for non-simple devices */
if ((PCI_MULTIFUNCTION_DEVICE(PciData)) ||
(PciData->BaseClass == PCI_CLASS_BRIDGE_DEV))
{
/* No subsystem data defined for these kinds of bridges */
SubVendorId = 0;
SubSystemId = 0;
}
else
{
/* Read the subsystem information from the PCI header */
SubVendorId = PciData->u.type0.SubVendorID;
SubSystemId = PciData->u.type0.SubSystemID;
}
/* Get any hack flags for this device */
HackFlags = PciGetHackFlags(PciData->VendorID,
PciData->DeviceID,
SubVendorId,
SubSystemId,
PciData->RevisionID);
/* Check if this device is considered critical by the OS */
if (PciIsCriticalDeviceClass(PciData->BaseClass, PciData->SubClass))
{
/* Check if normally the decodes would be disabled */
if (!(HackFlags & PCI_HACK_DONT_DISABLE_DECODES))
{
/* Because this device is critical, don't disable them */
DPRINT1("Not allowing PM Because device is critical\n");
HackFlags |= PCI_HACK_CRITICAL_DEVICE;
}
}
/* PCI bridges with a VGA card are also considered critical */
if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
(PciData->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) &&
(PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA) &&
!(HackFlags & PCI_HACK_DONT_DISABLE_DECODES))
{
/* Do not disable their decodes either */
DPRINT1("Not allowing PM because device is VGA\n");
HackFlags |= PCI_HACK_CRITICAL_DEVICE;
}
/* Also skip devices that should not be enumerated */
if (PciSkipThisFunction(PciData, PciSlot, 1, HackFlags)) continue;
/* Check if a PDO has already been created for this device */
PdoExtension = PciFindPdoByFunction(DeviceExtension,
PciSlot.u.bits.FunctionNumber,
PciData);
if (PdoExtension)
{
/* Rescan scenarios are not yet implemented */
UNIMPLEMENTED;
while (TRUE);
}
} }
} }

View file

@ -506,11 +506,15 @@ PciAddDevice(IN PDRIVER_OBJECT DriverObject,
if (PciBreakOnDefault) if (PciBreakOnDefault)
{ {
/* If a second bus is found and there's still no data, crash */ /* If a second bus is found and there's still no data, crash */
#if 0 // ros bug?
KeBugCheckEx(PCI_BUS_DRIVER_INTERNAL, KeBugCheckEx(PCI_BUS_DRIVER_INTERNAL,
0xDEAD0010u, 0xDEAD0010u,
(ULONG_PTR)DeviceObject, (ULONG_PTR)DeviceObject,
0, 0,
0); 0);
#else
DPRINT1("Windows would crash!\n");
#endif
} }
/* Warn that a default configuration will be used, and set bus 0 */ /* Warn that a default configuration will be used, and set bus 0 */

View file

@ -56,6 +56,12 @@
#define PCI_INTERFACE_FDO 0x02 #define PCI_INTERFACE_FDO 0x02
#define PCI_INTERFACE_ROOT 0x04 #define PCI_INTERFACE_ROOT 0x04
//
// PCI Skip Function FLags
//
#define PCI_SKIP_DEVICE_ENUMERATION 0x01
#define PCI_SKIP_RESOURCE_ENUMERATION 0x02
// //
// Device Extension, Interface, Translator and Arbiter Signatures // Device Extension, Interface, Translator and Arbiter Signatures
// //
@ -657,6 +663,31 @@ PciFindNextSecondaryExtension(
IN PCI_SIGNATURE ExtensionType IN PCI_SIGNATURE ExtensionType
); );
ULONGLONG
NTAPI
PciGetHackFlags(
IN USHORT VendorId,
IN USHORT DeviceId,
IN USHORT SubVendorId,
IN USHORT SubSystemId,
IN UCHAR RevisionId
);
PPCI_PDO_EXTENSION
NTAPI
PciFindPdoByFunction(
IN PPCI_FDO_EXTENSION DeviceExtension,
IN ULONG FunctionNumber,
IN PPCI_COMMON_HEADER PciData
);
BOOLEAN
NTAPI
PciIsCriticalDeviceClass(
IN UCHAR BaseClass,
IN UCHAR SubClass
);
// //
// Configuration Routines // Configuration Routines
// //
@ -1000,5 +1031,6 @@ extern PCI_INTERFACE AgpTargetInterface;
extern PCI_INTERFACE TranslatorInterfaceInterrupt; extern PCI_INTERFACE TranslatorInterfaceInterrupt;
extern PDRIVER_OBJECT PciDriverObject; extern PDRIVER_OBJECT PciDriverObject;
extern PWATCHDOG_TABLE WdTable; extern PWATCHDOG_TABLE WdTable;
extern PPCI_HACK_ENTRY PciHackTable;
/* EOF */ /* EOF */

View file

@ -338,9 +338,11 @@ NTAPI
PciFindParentPciFdoExtension(IN PDEVICE_OBJECT DeviceObject, PciFindParentPciFdoExtension(IN PDEVICE_OBJECT DeviceObject,
IN PKEVENT Lock) IN PKEVENT Lock)
{ {
PPCI_FDO_EXTENSION FoundExtension; PPCI_FDO_EXTENSION DeviceExtension;
PPCI_PDO_EXTENSION SearchExtension, FoundExtension;
/* Assume we'll find nothing */ /* Assume we'll find nothing */
SearchExtension = DeviceObject->DeviceExtension;
FoundExtension = NULL; FoundExtension = NULL;
/* Check if a lock was specified */ /* Check if a lock was specified */
@ -352,11 +354,31 @@ PciFindParentPciFdoExtension(IN PDEVICE_OBJECT DeviceObject,
} }
/* Now search for the extension */ /* Now search for the extension */
if (PciFdoExtensionListHead.Next) DeviceExtension = (PPCI_FDO_EXTENSION)PciFdoExtensionListHead.Next;
while (DeviceExtension)
{ {
/* This case should not be hit yet */ /* Acquire this device's lock */
UNIMPLEMENTED; KeEnterCriticalRegion();
while (TRUE); KeWaitForSingleObject(&DeviceExtension->ChildListLock,
Executive,
KernelMode,
FALSE,
NULL);
/* Scan all children PDO, stop when no more PDOs, or found it */
for (FoundExtension = DeviceExtension->ChildPdoList;
FoundExtension && (FoundExtension != SearchExtension);
FoundExtension = FoundExtension->Next);
/* If we found it, break out */
if (FoundExtension) break;
/* Release this device's lock */
KeSetEvent(&DeviceExtension->ChildListLock, IO_NO_INCREMENT, FALSE);
KeLeaveCriticalRegion();
/* Move to the next device */
DeviceExtension = (PPCI_FDO_EXTENSION)DeviceExtension->List.Next;
} }
/* Check if we had acquired a lock previously */ /* Check if we had acquired a lock previously */
@ -368,7 +390,7 @@ PciFindParentPciFdoExtension(IN PDEVICE_OBJECT DeviceObject,
} }
/* Return which extension was found, if any */ /* Return which extension was found, if any */
return FoundExtension; return DeviceExtension;
} }
VOID VOID
@ -575,4 +597,148 @@ PciFindNextSecondaryExtension(IN PSINGLE_LIST_ENTRY ListHead,
return NULL; return NULL;
} }
ULONGLONG
NTAPI
PciGetHackFlags(IN USHORT VendorId,
IN USHORT DeviceId,
IN USHORT SubVendorId,
IN USHORT SubSystemId,
IN UCHAR RevisionId)
{
PPCI_HACK_ENTRY HackEntry;
ULONGLONG HackFlags;
ULONG LastWeight, MatchWeight;
ULONG EntryFlags;
/* Initialize the variables before looping */
LastWeight = 0;
HackFlags = 0;
ASSERT(PciHackTable);
/* Scan the hack table */
for (HackEntry = PciHackTable;
HackEntry->VendorID != PCI_INVALID_VENDORID;
++HackEntry)
{
/* Check if there's an entry for this device */
if ((HackEntry->DeviceID == DeviceId) &&
(HackEntry->VendorID == VendorId))
{
/* This is a basic match */
EntryFlags = HackEntry->Flags;
MatchWeight = 1;
/* Does the entry have revision information? */
if (EntryFlags & PCI_HACK_HAS_REVISION_INFO)
{
/* Check if the revision matches, if so, this is a better match */
if (HackEntry->RevisionID != RevisionId) continue;
MatchWeight = 3;
}
/* Does the netry have subsystem information? */
if (EntryFlags & PCI_HACK_HAS_SUBSYSTEM_INFO)
{
/* Check if it matches, if so, this is the best possible match */
if ((HackEntry->SubVendorID != SubVendorId) ||
(HackEntry->SubSystemID != SubSystemId))
{
continue;
}
MatchWeight += 4;
}
/* Is this the best match yet? */
if (MatchWeight > LastWeight)
{
/* This is the best match for now, use this as the hack flags */
HackFlags = HackEntry->HackFlags;
LastWeight = MatchWeight;
}
}
}
/* Return the best match */
return HackFlags;
}
BOOLEAN
NTAPI
PciIsCriticalDeviceClass(IN UCHAR BaseClass,
IN UCHAR SubClass)
{
/* Check for system or bridge devices */
if (BaseClass == PCI_CLASS_BASE_SYSTEM_DEV)
{
/* Interrupt controlers are critical */
return SubClass == PCI_SUBCLASS_SYS_INTERRUPT_CTLR;
}
else if (BaseClass == PCI_CLASS_BRIDGE_DEV)
{
/* ISA Bridges are critical */
return SubClass == PCI_SUBCLASS_BR_ISA;
}
else
{
/* All display controllers are critical */
return BaseClass == PCI_CLASS_DISPLAY_CTLR;
}
}
PPCI_PDO_EXTENSION
NTAPI
PciFindPdoByFunction(IN PPCI_FDO_EXTENSION DeviceExtension,
IN ULONG FunctionNumber,
IN PPCI_COMMON_HEADER PciData)
{
KIRQL Irql;
PPCI_PDO_EXTENSION PdoExtension;
/* Get the current IRQL when this call was made */
Irql = KeGetCurrentIrql();
/* Is this a low-IRQL call? */
if (Irql < DISPATCH_LEVEL)
{
/* Acquire this device's lock */
KeEnterCriticalRegion();
KeWaitForSingleObject(&DeviceExtension->ChildListLock,
Executive,
KernelMode,
FALSE,
NULL);
}
/* Loop every child PDO */
for (PdoExtension = DeviceExtension->ChildPdoList;
PdoExtension;
PdoExtension = PdoExtension->Next)
{
/* Find only enumerated PDOs */
if (!PdoExtension->ReportedMissing)
{
/* Check if the function number and header data matches */
if ((FunctionNumber == PdoExtension->Slot.u.bits.FunctionNumber) &&
(PdoExtension->VendorId == PciData->VendorID) &&
(PdoExtension->DeviceId == PciData->DeviceID) &&
(PdoExtension->RevisionId == PciData->RevisionID))
{
/* This is considered to be the same PDO */
break;
}
}
}
/* Was this a low-IRQL call? */
if (Irql < DISPATCH_LEVEL)
{
/* Release this device's lock */
KeSetEvent(&DeviceExtension->ChildListLock, IO_NO_INCREMENT, FALSE);
KeLeaveCriticalRegion();
}
/* If the search found something, this is non-NULL, otherwise it's NULL */
return PdoExtension;
}
/* EOF */ /* EOF */