Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

586 lines
17 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
ixpcisup.c
Abstract:
Support functions for doing PCI the bus-handler
way.
Author:
Ken Reneris (kenr) 14-June-1994
Environment:
Kernel mode
Revision History:
Moved code into this file so that it would be
easier to build a non-bus-handler HAL. This
file will only be compiled into HALs that
use bus handlers. -- Jake Oshins 2-Dec-1997
--*/
#include "halp.h"
#include "pci.h"
#include "pcip.h"
#include "chiphacks.h"
BOOLEAN
HalpIsIdeDevice(
IN PPCI_COMMON_CONFIG PciData
);
VOID
HalpGetNMICrashFlag (
VOID
);
extern BOOLEAN HalpDisableHibernate;
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,HalpInitializePciBus)
#pragma alloc_text(INIT,HalpIsIdeDevice)
#pragma alloc_text(INIT,HalpAllocateAndInitPciBusHandler)
#endif
VOID
HalpInitializePciBus (
VOID
)
{
PPCI_REGISTRY_INFO_INTERNAL PCIRegInfo;
ULONG i, d, HwType, BusNo, f;
PBUS_HANDLER BusHandler;
PCI_SLOT_NUMBER SlotNumber;
PPCI_COMMON_CONFIG PciData;
UCHAR iBuffer[PCI_COMMON_HDR_LENGTH + sizeof(TYPE2EXTRAS)];
ULONG OPBNumber;
BOOLEAN OPBA2B0Found, COPBInbPostingEnabled;
UCHAR buffer [4];
BOOLEAN fullDecodeChipset = FALSE;
NTSTATUS Status;
ULONG flags;
PCIRegInfo = HalpQueryPciRegistryInfo();
if (!PCIRegInfo) {
return;
}
//
// Initialize spinlock for synchronizing access to PCI space
//
KeInitializeSpinLock (&HalpPCIConfigLock);
PciData = (PPCI_COMMON_CONFIG) iBuffer;
//
// PCIRegInfo describes the system's PCI support as indicated by the BIOS.
//
HwType = PCIRegInfo->HardwareMechanism & 0xf;
//
// Some AMI bioses claim machines are Type2 configuration when they
// are really type1. If this is a Type2 with at least one bus,
// try to verify it's not really a type1 bus
//
if (PCIRegInfo->NoBuses && HwType == 2) {
//
// Check each slot for a valid device. Which every style configuration
// space shows a valid device first will be used
//
SlotNumber.u.bits.Reserved = 0;
SlotNumber.u.bits.FunctionNumber = 0;
for (d = 0; d < PCI_MAX_DEVICES; d++) {
SlotNumber.u.bits.DeviceNumber = d;
//
// First try what the BIOS claims - type 2. Allocate type2
// test handle for PCI bus 0.
//
HwType = 2;
BusHandler = HalpAllocateAndInitPciBusHandler (HwType, 0, TRUE);
if (HalpIsValidPCIDevice (BusHandler, SlotNumber)) {
break;
}
//
// Valid device not found on Type2 access for this slot.
// Reallocate the bus handler are Type1 and take a look.
//
HwType = 1;
BusHandler = HalpAllocateAndInitPciBusHandler (HwType, 0, TRUE);
if (HalpIsValidPCIDevice (BusHandler, SlotNumber)) {
break;
}
HwType = 2;
}
//
// Reset handler for PCI bus 0 to whatever style config space
// was finally decided.
//
HalpAllocateAndInitPciBusHandler (HwType, 0, FALSE);
}
//
// For each PCI bus present, allocate a handler structure and
// fill in the dispatch functions
//
do {
for (i=0; i < PCIRegInfo->NoBuses; i++) {
//
// If handler not already built, do it now
//
if (!HalpHandlerForBus (PCIBus, i)) {
HalpAllocateAndInitPciBusHandler (HwType, i, FALSE);
}
}
//
// Bus handlers for all PCI buses have been allocated, go collect
// pci bridge information.
//
} while (HalpGetPciBridgeConfig (HwType, &PCIRegInfo->NoBuses)) ;
//
// Fixup SUPPORTED_RANGES
//
HalpFixupPciSupportedRanges (PCIRegInfo->NoBuses);
//
// Look for PCI controllers which have known work-arounds, and make
// sure they are applied.
//
// In addition, fill in the bitmask HalpPciIrqMask with all the
// interrupts that PCI devices might use.
//
OPBNumber = 0;
OPBA2B0Found = FALSE;
COPBInbPostingEnabled = FALSE;
SlotNumber.u.bits.Reserved = 0;
for (BusNo=0; BusNo < PCIRegInfo->NoBuses; BusNo++) {
BusHandler = HalpHandlerForBus (PCIBus, BusNo);
for (d = 0; d < PCI_MAX_DEVICES; d++) {
SlotNumber.u.bits.DeviceNumber = d;
for (f = 0; f < PCI_MAX_FUNCTION; f++) {
SlotNumber.u.bits.FunctionNumber = f;
//
// Read PCI configuration information
//
HalpReadPCIConfig (BusHandler, SlotNumber, PciData, 0, PCI_COMMON_HDR_LENGTH);
if (*((PULONG)(PciData)) == 0xffffffff) {
continue;
}
if (PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE) {
HalpReadPCIConfig(
BusHandler,
SlotNumber,
PciData+1,
FIELD_OFFSET(PCI_COMMON_CONFIG, DeviceSpecific),
sizeof(TYPE2EXTRAS)
);
}
#ifndef SUBCLASSPCI
//
// Look at interrupt line register and fill in HalpPciIrqMask,
// but not for an IDE controller, as IDE controllers really
// trigger interrupts like ISA devices.
//
if (PCI_CONFIGURATION_TYPE(PciData) != 1) {
if ((PciData->u.type0.InterruptPin != 0) &&
(PciData->u.type0.InterruptLine != 0) &&
(PciData->u.type0.InterruptLine < PIC_VECTORS) &&
!HalpIsIdeDevice(PciData)) {
HalpPciIrqMask |= 1 << PciData->u.type0.InterruptLine;
}
}
#endif
//
// Check for chips with known work-arounds to apply
//
if (PciData->VendorID == 0x8086 &&
PciData->DeviceID == 0x04A3 &&
PciData->RevisionID < 0x11) {
//
// 82430 PCMC controller
//
HalpReadPCIConfig (BusHandler, SlotNumber, buffer, 0x53, 2);
buffer[0] &= ~0x08; // turn off bit 3 register 0x53
if (PciData->RevisionID == 0x10) { // on rev 0x10, also turn
buffer[1] &= ~0x01; // bit 0 register 0x54
}
HalpWritePCIConfig (BusHandler, SlotNumber, buffer, 0x53, 2);
}
if (PciData->VendorID == 0x8086 &&
PciData->DeviceID == 0x0484 &&
PciData->RevisionID <= 3) {
//
// 82378 ISA bridge & SIO
//
HalpReadPCIConfig (BusHandler, SlotNumber, buffer, 0x41, 1);
buffer[0] &= ~0x1; // turn off bit 0 register 0x41
HalpWritePCIConfig (BusHandler, SlotNumber, buffer, 0x41, 1);
}
//
// Look for Orion PCI Bridge
//
if (PciData->VendorID == 0x8086 &&
PciData->DeviceID == 0x84c4 ) {
//
// 82450 Orion PCI Bridge Workaround
// Need a workaround if following conditions are true:
// i) 2 OPBs present
// ii)There is an A2/B0 step OPB present.
// iii) Inbound posting on the compatibility OPB is
// enabled.
// NOTE: Inbound Posting on the non-compatibility OPB
// MUST BE disabled by BIOS
//
OPBNumber += 1;
if (PciData->RevisionID <= 4) {
OPBA2B0Found = TRUE;
}
if (SlotNumber.u.bits.DeviceNumber == (0xc8>>3)) {
// Found compatibility OPB. Determine if the compatibility
// OPB has inbound posting enabled by testing bit 0 of reg 54
HalpReadPCIConfig (BusHandler, SlotNumber, buffer, 0x54, 2);
COPBInbPostingEnabled = (buffer[0] & 0x1) ? TRUE : FALSE;
} else {
// The compatibility OPB ALWAYS has a device
// number 0xc8. Save the ncOPB slot number
// and BusHandler
HalpOrionOPB.Slot = SlotNumber;
HalpOrionOPB.Handler = BusHandler;
}
}
//
// Check the list for host bridges who's existance will mark a
// chipset as 16bit decode. We use this to cover for BIOS
// writers who list "fixed" PnPBIOS resources without noticing
// that such a descriptor implies their device is 10bit decode.
//
if ((!fullDecodeChipset) &&
HalpIsRecognizedCard(PCIRegInfo, PciData,
PCIFT_FULLDECODE_HOSTBRIDGE)) {
fullDecodeChipset = TRUE;
}
//
// Look for ICH, or any other Intel or VIA UHCI USB controller.
//
if ((PciData->BaseClass == PCI_CLASS_SERIAL_BUS_CTLR) &&
(PciData->SubClass == PCI_SUBCLASS_SB_USB) &&
(PciData->ProgIf == 0x00)) {
if (PciData->VendorID == 0x8086) {
HalpStopUhciInterrupt(BusNo,
SlotNumber,
TRUE);
} else if (PciData->VendorID == 0x1106) {
HalpStopUhciInterrupt(BusNo,
SlotNumber,
FALSE);
}
}
//
// Look for an OHCI-compliant USB controller.
//
if ((PciData->BaseClass == PCI_CLASS_SERIAL_BUS_CTLR) &&
(PciData->SubClass == PCI_SUBCLASS_SB_USB) &&
(PciData->ProgIf == 0x10)) {
HalpStopOhciInterrupt(BusNo,
SlotNumber);
}
Status = HalpGetChipHacks(PciData->VendorID,
PciData->DeviceID,
0,
&flags);
if (NT_SUCCESS(Status)) {
if (flags & DISABLE_HIBERNATE_HACK_FLAG) {
HalpDisableHibernate = TRUE;
}
if (flags & WHACK_ICH_USB_SMI_HACK_FLAG) {
HalpWhackICHUsbSmi(BusNo, SlotNumber);
}
}
} // next function
} // next device
} // next bus
//
// Is Orion B0 workaround needed?
//
if (OPBNumber >= 2 && OPBA2B0Found && COPBInbPostingEnabled) {
//
// Replace synchronization functions with Orion specific functions
//
ASSERT (PCIConfigHandler.Synchronize == HalpPCISynchronizeType1);
MmLockPagableCodeSection (&HalpPCISynchronizeOrionB0);
PCIConfigHandler.Synchronize = HalpPCISynchronizeOrionB0;
PCIConfigHandler.ReleaseSynchronzation = HalpPCIReleaseSynchronzationOrionB0;
}
//
// Check if we should crashdump on NMI.
//
HalpGetNMICrashFlag();
#if DBG
HalpTestPci (0);
#endif
//
// Mark the chipset appropriately.
//
HalpMarkChipsetDecode(fullDecodeChipset);
ExFreePool(PCIRegInfo);
}
PBUS_HANDLER
HalpAllocateAndInitPciBusHandler (
IN ULONG HwType,
IN ULONG BusNo,
IN BOOLEAN TestAllocation
)
{
PBUS_HANDLER Bus;
PPCIPBUSDATA BusData;
Bus = HalpAllocateBusHandler (
PCIBus, // Interface type
PCIConfiguration, // Has this configuration space
BusNo, // bus #
Internal, // child of this bus
0, // and number
sizeof (PCIPBUSDATA) // sizeof bus specific buffer
);
if (!Bus) {
return NULL;
}
//
// Fill in PCI handlers
//
Bus->GetBusData = (PGETSETBUSDATA) HalpGetPCIData;
Bus->SetBusData = (PGETSETBUSDATA) HalpSetPCIData;
Bus->GetInterruptVector = (PGETINTERRUPTVECTOR) HalpGetPCIIntOnISABus;
Bus->AdjustResourceList = (PADJUSTRESOURCELIST) HalpAdjustPCIResourceList;
Bus->AssignSlotResources = (PASSIGNSLOTRESOURCES) HalpAssignPCISlotResources;
Bus->BusAddresses->Dma.Limit = 0;
BusData = (PPCIPBUSDATA) Bus->BusData;
//
// Fill in common PCI data
//
BusData->CommonData.Tag = PCI_DATA_TAG;
BusData->CommonData.Version = PCI_DATA_VERSION;
BusData->CommonData.ReadConfig = (PciReadWriteConfig) HalpReadPCIConfig;
BusData->CommonData.WriteConfig = (PciReadWriteConfig) HalpWritePCIConfig;
BusData->CommonData.Pin2Line = (PciPin2Line) HalpPCIPin2ISALine;
BusData->CommonData.Line2Pin = (PciLine2Pin) HalpPCIISALine2Pin;
//
// Set defaults
//
BusData->MaxDevice = PCI_MAX_DEVICES;
BusData->GetIrqRange = (PciIrqRange) HalpGetISAFixedPCIIrq;
RtlInitializeBitMap (&BusData->DeviceConfigured,
BusData->ConfiguredBits, 256);
switch (HwType) {
case 1:
//
// Initialize access port information for Type1 handlers
//
RtlCopyMemory (&PCIConfigHandler,
&PCIConfigHandlerType1,
sizeof (PCIConfigHandler));
BusData->Config.Type1.Address = PCI_TYPE1_ADDR_PORT;
BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT;
break;
case 2:
//
// Initialize access port information for Type2 handlers
//
RtlCopyMemory (&PCIConfigHandler,
&PCIConfigHandlerType2,
sizeof (PCIConfigHandler));
BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT;
BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT;
BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE;
//
// Early PCI machines didn't decode the last bit of
// the device id. Shrink type 2 support max device.
//
BusData->MaxDevice = 0x10;
break;
default:
// unsupport type
DBGMSG ("HAL: Unkown PCI type\n");
}
if (!TestAllocation) {
#ifdef SUBCLASSPCI
HalpSubclassPCISupport (Bus, HwType);
#endif
}
return Bus;
}
BOOLEAN
HalpIsIdeDevice(
IN PPCI_COMMON_CONFIG PciData
)
{
if ((PciData->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
(PciData->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR)) {
return TRUE;
}
//
// Now look for old, hard to recognize controllers.
//
if (PciData->VendorID == 0x1c1c) { // Old Symphony controller
return TRUE;
}
if ((PciData->VendorID == 0x10B9) &&
((PciData->DeviceID == 0x5215) ||
(PciData->DeviceID == 0x5219))) { // ALI controllers
return TRUE;
}
if ((PciData->VendorID == 0x1097) &&
(PciData->DeviceID == 0x0038)) { // Appian controller
return TRUE;
}
if ((PciData->VendorID == 0x0E11) &&
(PciData->DeviceID == 0xAE33)) { // Compaq controller
return TRUE;
}
if ((PciData->VendorID == 0x1042) &&
(PciData->DeviceID == 0x1000)) { // PCTECH controller
return TRUE;
}
if ((PciData->VendorID == 0x1039) &&
((PciData->DeviceID == 0x0601) ||
(PciData->DeviceID == 0x5513))) { // SIS controllers
return TRUE;
}
if ((PciData->VendorID == 0x10AD) &&
((PciData->DeviceID == 0x0001) ||
(PciData->DeviceID == 0x0150))) { // Newer Symphony controllers
return TRUE;
}
if ((PciData->VendorID == 0x1060) &&
(PciData->DeviceID == 0x0101)) { // United Microelectronics controller
return TRUE;
}
return FALSE;
}