diff options
Diffstat (limited to 'private/ntos/nthals/halr96b/mips/pcibus.c')
-rw-r--r-- | private/ntos/nthals/halr96b/mips/pcibus.c | 3585 |
1 files changed, 3585 insertions, 0 deletions
diff --git a/private/ntos/nthals/halr96b/mips/pcibus.c b/private/ntos/nthals/halr96b/mips/pcibus.c new file mode 100644 index 000000000..a77edf46e --- /dev/null +++ b/private/ntos/nthals/halr96b/mips/pcibus.c @@ -0,0 +1,3585 @@ +// #pragma comment(exestr, "@(#) pcibus.c 1.1 95/09/28 15:45:56 nec") +/*++ + + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + ixpcidat.c + +Abstract: + + Get/Set bus data routines for the PCI bus + +Author: + + Ken Reneris (kenr) 14-June-1994 + +Environment: + + Kernel mode + +Revision History: + +Modification History: + + H001 Fri Jun 30 02:54:08 1995 kbnes!kisimoto + - Merge build 1057 ixpcibus.c + H002 Tue Jul 4 20:43:12 1995 kbnes!kisimoto + - disable preferred setting for back-to-back + support. If enable, IoAssign... allocates + current enabled address space. + H003 Wed Jul 5 14:27:46 1995 kbnes!kisimoto + - initialize with FALSE + H004 Tue Sep 5 20:06:16 1995 kbnes!kisimoto + - PCI Fast Back-to-back transfer support + +--*/ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" + +#if defined(_R94A_) // H001 +#include "r94adef.h" +#include "string.h" +#endif // _R94A_ + +extern WCHAR rgzMultiFunctionAdapter[]; +extern WCHAR rgzConfigurationData[]; +extern WCHAR rgzIdentifier[]; +extern WCHAR rgzPCIIdentifier[]; + + +typedef ULONG (*FncConfigIO) ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +typedef VOID (*FncSync) ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PVOID State + ); + +typedef VOID (*FncReleaseSync) ( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql + ); + +typedef struct _PCI_CONFIG_HANDLER { + FncSync Synchronize; + FncReleaseSync ReleaseSynchronzation; + FncConfigIO ConfigRead[3]; + FncConfigIO ConfigWrite[3]; +} PCI_CONFIG_HANDLER, *PPCI_CONFIG_HANDLER; + + + +// +// Prototypes +// + +ULONG +HalpGetPCIData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +ULONG +HalpSetPCIData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +NTSTATUS +HalpAssignPCISlotResources ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName OPTIONAL, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN ULONG SlotNumber, + IN OUT PCM_RESOURCE_LIST *AllocatedResources + ); + +#if 0 +VOID +HalpInitializePciBus ( + VOID + ); +#endif + +BOOLEAN +HalpIsValidPCIDevice ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot + ); + +BOOLEAN +HalpValidPCISlot ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot + ); + +//------------------------------------------------- + +VOID HalpPCISynchronizeType1 ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PVOID State + ); + +VOID HalpPCIReleaseSynchronzationType1 ( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql + ); + +ULONG HalpPCIReadUlongType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIReadUcharType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIReadUshortType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUlongType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUcharType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUshortType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +VOID HalpPCISynchronizeType2 ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PVOID State + ); + +VOID HalpPCIReleaseSynchronzationType2 ( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql + ); + +ULONG HalpPCIReadUlongType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIReadUcharType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIReadUshortType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUlongType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUcharType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUshortType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + + +// +// Globals +// + +// KSPIN_LOCK HalpPCIConfigLock; // H001 + +PCI_CONFIG_HANDLER PCIConfigHandler; + +PCI_CONFIG_HANDLER PCIConfigHandlerType1 = { + HalpPCISynchronizeType1, + HalpPCIReleaseSynchronzationType1, + { + HalpPCIReadUlongType1, // 0 + HalpPCIReadUcharType1, // 1 + HalpPCIReadUshortType1 // 2 + }, + { + HalpPCIWriteUlongType1, // 0 + HalpPCIWriteUcharType1, // 1 + HalpPCIWriteUshortType1 // 2 + } +}; + +PCI_CONFIG_HANDLER PCIConfigHandlerType2 = { + HalpPCISynchronizeType2, + HalpPCIReleaseSynchronzationType2, + { + HalpPCIReadUlongType2, // 0 + HalpPCIReadUcharType2, // 1 + HalpPCIReadUshortType2 // 2 + }, + { + HalpPCIWriteUlongType2, // 0 + HalpPCIWriteUcharType2, // 1 + HalpPCIWriteUshortType2 // 2 + } +}; + +UCHAR PCIDeref[4][4] = { {0,1,2,2},{1,1,1,1},{2,1,2,2},{1,1,1,1} }; + +BOOLEAN HalpDoingCrashDump = FALSE; // H003 +ULONG HalpFoundUncapablePCIDevice = 0; // H004 +ULONG HalpPCINumberOfMappedGA = 0; +ULONG HalpPCIBackToBackReg0Start = 0; +ULONG HalpPCIBackToBackReg1Start = 0; +ULONG HalpPCIBackToBackReg0Open = 1; +ULONG HalpPCIBackToBackReg1Open = 1; +ULONG HalpNumberOfPCIGA = 0; +ULONG HalpPCIMemoryLimit = 0xffffffff; + +#define INIT_VALUE_OF_BACK_TO_BACK_ADDR 0x00000000 +#define INIT_VALUE_OF_BACK_TO_BACK_MASK 0xffffffff + +VOID +HalpPCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length, + IN FncConfigIO *ConfigIO + ); + +#if defined(_R94A_) // H001 +ULONG +HalpGetPCIInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); +ULONG +HalpGetNumberOfPCIGA( + IN ULONG NumberBuses + ); +VOID +HalpSetBackToBackSpace( + IN PPCI_COMMON_CONFIG PciConfigRequired, + IN PPCI_COMMON_CONFIG PciConfigMapped, + IN PBUS_HANDLER BusHandler + ); +VOID +HalpSetBackToBackRegister( + IN ULONG BaseAddress, + IN ULONG Length, + IN ULONG Register + ); +#endif // _R94A_ + +#if DBG +#define DBGMSG(a) DbgPrint(a) +ULONG R94aDoTestPci = 0; +ULONG R94aDoTestPciNec = 0; +ULONG R94aDoOtherTest = 0; +VOID +HalpTestPciNec ( + ULONG + ); +VOID +HalpTestPciPrintResult( + IN PULONG Buffer, + IN ULONG Length + ); +VOID +HalpOtherTestNec ( + ULONG + ); +VOID +HalpTestPci ( + ULONG + ); +#else +#define DBGMSG(a) +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpInitializePciBus) +#pragma alloc_text(INIT,HalpAllocateAndInitPciBusHandler) +#pragma alloc_text(INIT,HalpIsValidPCIDevice) +#pragma alloc_text(PAGE,HalpAssignPCISlotResources) +#endif + + + +VOID +HalpInitializePciBus ( + VOID + ) +{ + PPCI_REGISTRY_INFO PCIRegInfo; + UNICODE_STRING unicodeString, ConfigName, IdentName; + OBJECT_ATTRIBUTES objectAttributes; + HANDLE hMFunc, hBus; + NTSTATUS status; + UCHAR buffer [sizeof(PPCI_REGISTRY_INFO) + 99]; + PWSTR p; + WCHAR wstr[8]; + ULONG i, d, junk, HwType, BusNo, f; + PBUS_HANDLER BusHandler; + PCI_SLOT_NUMBER SlotNumber; + PPCI_COMMON_CONFIG PciData; + UCHAR iBuffer[PCI_COMMON_HDR_LENGTH]; + PKEY_VALUE_FULL_INFORMATION ValueInfo; + PCM_FULL_RESOURCE_DESCRIPTOR Desc; + PCM_PARTIAL_RESOURCE_DESCRIPTOR PDesc; + + PCI_REGISTRY_INFO tPCIRegInfo; // H001 + +#if 0 // H001 + // + // Search the hardware description looking for any reported + // PCI bus. The first ARC entry for a PCI bus will contain + // the PCI_REGISTRY_INFO. + + RtlInitUnicodeString (&unicodeString, rgzMultiFunctionAdapter); + InitializeObjectAttributes ( + &objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE, + NULL, // handle + NULL); + + + status = ZwOpenKey (&hMFunc, KEY_READ, &objectAttributes); + if (!NT_SUCCESS(status)) { + return ; + } + + unicodeString.Buffer = wstr; + unicodeString.MaximumLength = sizeof (wstr); + + RtlInitUnicodeString (&ConfigName, rgzConfigurationData); + RtlInitUnicodeString (&IdentName, rgzIdentifier); + + ValueInfo = (PKEY_VALUE_FULL_INFORMATION) buffer; + + for (i=0; TRUE; i++) { + RtlIntegerToUnicodeString (i, 10, &unicodeString); + InitializeObjectAttributes ( + &objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE, + hMFunc, + NULL); + + status = ZwOpenKey (&hBus, KEY_READ, &objectAttributes); + if (!NT_SUCCESS(status)) { + // + // Out of Multifunction adapter entries... + // + + ZwClose (hMFunc); + return ; + } + + // + // Check the Indentifier to see if this is a PCI entry + // + + status = ZwQueryValueKey ( + hBus, + &IdentName, + KeyValueFullInformation, + ValueInfo, + sizeof (buffer), + &junk + ); + + if (!NT_SUCCESS (status)) { + ZwClose (hBus); + continue; + } + + p = (PWSTR) ((PUCHAR) ValueInfo + ValueInfo->DataOffset); + if (p[0] != L'P' || p[1] != L'C' || p[2] != L'I' || p[3] != 0) { + ZwClose (hBus); + continue; + } + + // + // The first PCI entry has the PCI_REGISTRY_INFO structure + // attached to it. + // + + status = ZwQueryValueKey ( + hBus, + &ConfigName, + KeyValueFullInformation, + ValueInfo, + sizeof (buffer), + &junk + ); + + ZwClose (hBus); + if (!NT_SUCCESS(status)) { + continue ; + } + + Desc = (PCM_FULL_RESOURCE_DESCRIPTOR) ((PUCHAR) + ValueInfo + ValueInfo->DataOffset); + PDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR) + Desc->PartialResourceList.PartialDescriptors); + + if (PDesc->Type == CmResourceTypeDeviceSpecific) { + // got it.. + PCIRegInfo = (PPCI_REGISTRY_INFO) (PDesc+1); + break; + } + } + + // + // Initialize spinlock for synchronizing access to PCI space + // + +// KeInitializeSpinLock (&HalpPCIConfigLock); // H001 + PciData = (PPCI_COMMON_CONFIG) iBuffer; + +#endif // 0 + +#if defined(_R94A_) // H001 + + PCIRegInfo = &tPCIRegInfo; + PCIRegInfo->NoBuses = 1; + PCIRegInfo->HardwareMechanism=0x1; // HURRICANE PCI Config Type + +#if DBG + DbgPrint("PCI System Get Data:\n"); + DbgPrint("MajorRevision %x\n", PCIRegInfo->MajorRevision ); + DbgPrint("MinorRevision %x\n", PCIRegInfo->MinorRevision ); + DbgPrint("NoBuses %x\n", PCIRegInfo->NoBuses ); + DbgPrint("HwMechanism %x\n", PCIRegInfo->HardwareMechanism ); +#endif // DBG + +#endif // _R94A_ + + // + // 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 + // + +#if 0 // H001 + do { +#endif + 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. + // + +#if 0 // H001 + } 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. + // + + 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); + + // + // 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); + } + + } // next function + } // next device + } // next bus +#endif + + // + // H005 + // Compute the number of PCI-GA device and + // initialize Fast Back-to-back register. + // + + HalpNumberOfPCIGA = HalpGetNumberOfPCIGA(PCIRegInfo->NoBuses); + +#if DBG + HalpTestPci (0); +#if defined(_R94A_) + DbgPrint("HalpInitializePciBus: Call HalpTestPci(%x)\n",R94aDoTestPci); + HalpTestPci (R94aDoTestPci); + DbgPrint("HalpInitializePciBus: Call HalpTestPciNec(%x)\n",R94aDoTestPciNec); + HalpTestPciNec (R94aDoTestPciNec); + DbgPrint("HalpInitializePciBus: Call HalpOtherTest(%x)\n",R94aDoOtherTest); + HalpOtherTestNec (R94aDoOtherTest); +#endif +#endif +} + + +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 + ); + + // + // Fill in PCI handlers + // + + Bus->GetBusData = (PGETSETBUSDATA) HalpGetPCIData; + Bus->SetBusData = (PGETSETBUSDATA) HalpSetPCIData; +#if defined(_R94A_) + Bus->GetInterruptVector = (PGETINTERRUPTVECTOR) HalpGetPCIInterruptVector; +#else + Bus->GetInterruptVector = (PGETINTERRUPTVECTOR) HalpGetPCIIntOnISABus; +#endif + 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)); + +#if defined(_R94A_) // H001 + BusData->Config.Type1.Address = (PULONG)R94A_PCI_TYPE1_ADDR_PORT; + BusData->Config.Type1.Data = R94A_PCI_TYPE1_DATA_PORT; +#else + BusData->Config.Type1.Address = PCI_TYPE1_ADDR_PORT; + BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT; +#endif // _R94A_ + 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 +HalpIsValidPCIDevice ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot + ) +/*++ + +Routine Description: + + Reads the device configuration data for the given slot and + returns TRUE if the configuration data appears to be valid for + a PCI device; otherwise returns FALSE. + +Arguments: + + BusHandler - Bus to check + Slot - Slot to check + +--*/ + +{ + PPCI_COMMON_CONFIG PciData; + UCHAR iBuffer[PCI_COMMON_HDR_LENGTH]; + ULONG i, j; + + + PciData = (PPCI_COMMON_CONFIG) iBuffer; + + // + // Read device common header + // + + HalpReadPCIConfig (BusHandler, Slot, PciData, 0, PCI_COMMON_HDR_LENGTH); + + // + // Valid device header? + // + + if (PciData->VendorID == PCI_INVALID_VENDORID || + PCI_CONFIG_TYPE (PciData) != PCI_DEVICE_TYPE) { + + return FALSE; + } + + // + // Check fields for reasonable values + // + + if ((PciData->u.type0.InterruptPin && PciData->u.type0.InterruptPin > 4) || + (PciData->u.type0.InterruptLine & 0x70)) { + return FALSE; + } + + for (i=0; i < PCI_TYPE0_ADDRESSES; i++) { + j = PciData->u.type0.BaseAddresses[i]; + + if (j & PCI_ADDRESS_IO_SPACE) { + if ((j > 0x2 && j < 0xffff) || j > 0xffffff) { // H001 + // IO port < 64KB | IO port > 16MB + return FALSE; + } + } else { + if (j > 0xf && j < 0x3ffffff) { // H001 + // Mem address < 64MB + return FALSE; + } + } + + if (Is64BitBaseAddress(j)) { + i += 1; + } + } + + // + // Guess it's a valid device.. + // + + return TRUE; +} + + + + + +ULONG +HalpGetPCIData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) +/*++ + +Routine Description: + + The function returns the Pci bus data for a device. + +Arguments: + + BusNumber - Indicates which bus. + + VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word) + + Buffer - Supplies the space to store the data. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + + If this PCI slot has never been set, then the configuration information + returned is zeroed. + + +--*/ +{ + PPCI_COMMON_CONFIG PciData; + UCHAR iBuffer[PCI_COMMON_HDR_LENGTH]; + PPCIPBUSDATA BusData; + ULONG Len; + ULONG i, bit; + + if (Length > sizeof (PCI_COMMON_CONFIG)) { + Length = sizeof (PCI_COMMON_CONFIG); + } + + Len = 0; + PciData = (PPCI_COMMON_CONFIG) iBuffer; + + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The user did not request any data from the common + // header. Verify the PCI device exists, then continue + // in the device specific area. + // + + HalpReadPCIConfig (BusHandler, Slot, PciData, 0, sizeof(ULONG)); + + if (PciData->VendorID == PCI_INVALID_VENDORID) { + return 0; + } + + } else { + + // + // Caller requested at least some data within the + // common header. Read the whole header, effect the + // fields we need to and then copy the user's requested + // bytes from the header + // + + BusData = (PPCIPBUSDATA) BusHandler->BusData; + + // + // Read this PCI devices slot data + // + + Len = PCI_COMMON_HDR_LENGTH; + HalpReadPCIConfig (BusHandler, Slot, PciData, 0, Len); + +#if 0 + DbgPrint ("--------------->>> Now Print the Slot Information\n"); + DbgPrint ("PCI Bus %d Slot %2d %2d ID:%04lx-%04lx Rev:%04lx", + BusHandler->BusNumber, Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber, PciData->VendorID, PciData->DeviceID, + PciData->RevisionID); + + + if (PciData->u.type0.InterruptPin) { + DbgPrint (" IntPin:%x", PciData->u.type0.InterruptPin); + } + + if (PciData->u.type0.InterruptLine) { + DbgPrint (" IntLine:%x", PciData->u.type0.InterruptLine); + } + + if (PciData->u.type0.ROMBaseAddress) { + DbgPrint (" ROM:%08lx", PciData->u.type0.ROMBaseAddress); + } + + DbgPrint ("\n ProgIf:%04x SubClass:%04x BaseClass:%04lx\n", + PciData->ProgIf, PciData->SubClass, PciData->BaseClass); + + { ULONG k, j; + k = 0; + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + if (PciData->u.type0.BaseAddresses[j]) { + DbgPrint (" Ad%d:%08lx", j, PciData->u.type0.BaseAddresses[j]); + k = 1; + } + } + DbgPrint("\n"); + } +#endif // DBG + + if (PciData->VendorID == PCI_INVALID_VENDORID || + PCI_CONFIG_TYPE (PciData) != PCI_DEVICE_TYPE) { + PciData->VendorID = PCI_INVALID_VENDORID; + Len = 2; // only return invalid id + + } else { + + BusData->CommonData.Pin2Line (BusHandler, RootHandler, Slot, PciData); + } + + // + // Has this PCI device been configured? + // + +#if DBG + + // + // On DBG build, if this PCI device has not yet been configured, + // then don't report any current configuration the device may have. + // + + bit = PciBitIndex(Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber); + if (!RtlCheckBit(&BusData->DeviceConfigured, bit)) { + + for (i=0; i < PCI_TYPE0_ADDRESSES; i++) { + PciData->u.type0.BaseAddresses[i] = 0; + } + + PciData->u.type0.ROMBaseAddress = 0; + PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE); + } +#endif + + + // + // Copy whatever data overlaps into the callers buffer + // + + if (Len < Offset) { + // no data at caller's buffer + return 0; + } + + Len -= Offset; + if (Len > Length) { + Len = Length; + } + + RtlMoveMemory(Buffer, iBuffer + Offset, Len); + + Offset += Len; + Buffer += Len; + Length -= Len; + } + + if (Length) { + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The remaining Buffer comes from the Device Specific + // area - put on the kitten gloves and read from it. + // + // Specific read/writes to the PCI device specific area + // are guarenteed: + // + // Not to read/write any byte outside the area specified + // by the caller. (this may cause WORD or BYTE references + // to the area in order to read the non-dword aligned + // ends of the request) + // + // To use a WORD access if the requested length is exactly + // a WORD long. + // + // To use a BYTE access if the requested length is exactly + // a BYTE long. + // + + HalpReadPCIConfig (BusHandler, Slot, Buffer, Offset, Length); + Len += Length; + } + } + + return Len; +} + +ULONG +HalpSetPCIData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) +/*++ + +Routine Description: + + The function returns the Pci bus data for a device. + +Arguments: + + + VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word) + + Buffer - Supplies the space to store the data. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + +--*/ +{ + PPCI_COMMON_CONFIG PciData, PciData2; + UCHAR iBuffer[PCI_COMMON_HDR_LENGTH]; + UCHAR iBuffer2[PCI_COMMON_HDR_LENGTH]; + PPCIPBUSDATA BusData; + ULONG Len, cnt; + + + if (Length > sizeof (PCI_COMMON_CONFIG)) { + Length = sizeof (PCI_COMMON_CONFIG); + } + + + Len = 0; + PciData = (PPCI_COMMON_CONFIG) iBuffer; + PciData2 = (PPCI_COMMON_CONFIG) iBuffer2; + + + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The user did not request any data from the common + // header. Verify the PCI device exists, then continue in + // the device specific area. + // + + HalpReadPCIConfig (BusHandler, Slot, PciData, 0, sizeof(ULONG)); + + if (PciData->VendorID == PCI_INVALID_VENDORID) { + return 0; + } + + } else { + + // + // Caller requested to set at least some data within the + // common header. + // + + Len = PCI_COMMON_HDR_LENGTH; + HalpReadPCIConfig (BusHandler, Slot, PciData, 0, Len); + if (PciData->VendorID == PCI_INVALID_VENDORID || + PCI_CONFIG_TYPE (PciData) != PCI_DEVICE_TYPE) { + + // no device, or header type unkown + return 0; + } + + + // + // Set this device as configured + // + + BusData = (PPCIPBUSDATA) BusHandler->BusData; +#if DBG + cnt = PciBitIndex(Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber); + RtlSetBits (&BusData->DeviceConfigured, cnt, 1); +#endif + // + // Copy COMMON_HDR values to buffer2, then overlay callers changes. + // + + RtlMoveMemory (iBuffer2, iBuffer, Len); + BusData->CommonData.Pin2Line (BusHandler, RootHandler, Slot, PciData2); + + Len -= Offset; + if (Len > Length) { + Len = Length; + } + + RtlMoveMemory (iBuffer2+Offset, Buffer, Len); + + // in case interrupt line or pin was editted + BusData->CommonData.Line2Pin (BusHandler, RootHandler, Slot, PciData2, PciData); + +#if DBG + // + // Verify R/O fields haven't changed + // + if (PciData2->VendorID != PciData->VendorID || + PciData2->DeviceID != PciData->DeviceID || + PciData2->RevisionID != PciData->RevisionID || + PciData2->ProgIf != PciData->ProgIf || + PciData2->SubClass != PciData->SubClass || + PciData2->BaseClass != PciData->BaseClass || + PciData2->HeaderType != PciData->HeaderType || + PciData2->BaseClass != PciData->BaseClass || + PciData2->u.type0.MinimumGrant != PciData->u.type0.MinimumGrant || + PciData2->u.type0.MaximumLatency != PciData->u.type0.MaximumLatency) { + DbgPrint ("PCI SetBusData: Read-Only configuration value changed\n"); + DbgBreakPoint (); + } +#endif + // + // Set new PCI configuration + // + +#if DBG // H001 + DbgPrint("SetPciData: PciData2->u.type0.InterruptLine:%x\n",PciData2->u.type0.InterruptLine); +#endif + HalpWritePCIConfig (BusHandler, Slot, iBuffer2+Offset, Offset, Len); + + Offset += Len; + Buffer += Len; + Length -= Len; + } + + if (Length) { + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The remaining Buffer comes from the Device Specific + // area - put on the kitten gloves and write it + // + // Specific read/writes to the PCI device specific area + // are guarenteed: + // + // Not to read/write any byte outside the area specified + // by the caller. (this may cause WORD or BYTE references + // to the area in order to read the non-dword aligned + // ends of the request) + // + // To use a WORD access if the requested length is exactly + // a WORD long. + // + // To use a BYTE access if the requested length is exactly + // a BYTE long. + // + + HalpWritePCIConfig (BusHandler, Slot, Buffer, Offset, Length); + Len += Length; + } + } + + return Len; +} + +VOID +HalpReadPCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ) +{ + USHORT IdValue; // H001 + ULONG OrigData; // H001 + + if (!HalpValidPCISlot (BusHandler, Slot)) { + // + // Invalid SlotID return no data + // + RtlFillMemory (Buffer, Length, (UCHAR) -1); + + return ; + } + +#if defined(_R94A_) // H001 + + // + // resolve PCI master abort during we are looking for PCI device + // check to see if spcified slot is valid. + // + + // + // Disable PCI-MasterAbort interrupt during configration read. + // + + OrigData = READ_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->PCIInterruptEnable); + WRITE_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->PCIInterruptEnable, OrigData & 0xffffff7f); + + HalpPCIConfig (BusHandler, Slot, (PUCHAR) &IdValue, 0, 2, + PCIConfigHandler.ConfigRead); + + if (IdValue == 0xffff){ + + // + // This PCI slot has no card + // wait until ReceivedMasterAbort bit is set + // + + while(!(READ_REGISTER_USHORT(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->PCIStatus) & 0x2000)) + ; + + // + // clear the ReceivedMasterAbort bit + // + + WRITE_REGISTER_USHORT(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->PCIStatus, 0x2000); + + // + // Clear memory address error registers. + // + + { + LARGE_INTEGER registerLarge; + READ_REGISTER_DWORD((PVOID)&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->InvalidAddress, ®isterLarge); + } + + // + // Restore the PCIInterruptEnable register, and return no data + // + + WRITE_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->PCIInterruptEnable, OrigData); + RtlFillMemory (Buffer, Length, (UCHAR) -1); + + return ; + } + + // + // Restore the PCIInterruptEnable register. + // + + WRITE_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->PCIInterruptEnable, OrigData); + +#endif // _R94A_ + + HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length, + PCIConfigHandler.ConfigRead); +} + +VOID +HalpWritePCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ) +{ + USHORT IdValue; // H001 + ULONG OrigData; // H001 + + if (!HalpValidPCISlot (BusHandler, Slot)) { + // + // Invalid SlotID do nothing + // + return ; + } + +#if defined(_R94A_) // H001 + + // + // resolve PCI master abort during we are looking for PCI device + // check to see if spcified slot is valid. + // + + // + // Disable PCI-MasterAbort interrupt during configration read. + // + + OrigData = READ_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->PCIInterruptEnable); + WRITE_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->PCIInterruptEnable, OrigData & 0xffffff7f); + + HalpPCIConfig (BusHandler, Slot, (PUCHAR) &IdValue, 0, 2, + PCIConfigHandler.ConfigRead); + + if (IdValue == 0xffff){ + + // + // This PCI slot has no card + // wait until ReceivedMasterAbort bit is set + // + + while(!(READ_REGISTER_USHORT(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->PCIStatus) & 0x2000)) + ; + + // + // clear the ReceivedMasterAbort bit + // + + WRITE_REGISTER_USHORT(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->PCIStatus, 0x2000); + + // + // Clear memory address error registers. + // + + { + LARGE_INTEGER registerLarge; + READ_REGISTER_DWORD((PVOID)&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->InvalidAddress, ®isterLarge); + } + + // + // Restore the PCIInterruptEnable register, and return no data + // + + WRITE_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->PCIInterruptEnable, OrigData); + RtlFillMemory (Buffer, Length, (UCHAR) -1); + + return ; + } + + // + // Restore the PCIInterruptEnable register. + // + + WRITE_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->PCIInterruptEnable, OrigData); + +#endif // _R94A_ + + HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length, + PCIConfigHandler.ConfigWrite); +} + +BOOLEAN +HalpValidPCISlot ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot + ) +{ + PCI_SLOT_NUMBER Slot2; + PPCIPBUSDATA BusData; + UCHAR HeaderType; + ULONG i; + + BusData = (PPCIPBUSDATA) BusHandler->BusData; + + if (Slot.u.bits.Reserved != 0) { + return FALSE; + } + +#if defined(_R94A_) // H001 + if (Slot.u.bits.DeviceNumber < 3 || + Slot.u.bits.DeviceNumber > 20) { + return FALSE; + } +#else + if (Slot.u.bits.DeviceNumber >= BusData->MaxDevice) { + return FALSE; + } +#endif // _R94A_ + + if (Slot.u.bits.FunctionNumber == 0) { + return TRUE; + } + + // + // Non zero function numbers are only supported if the + // device has the PCI_MULTIFUNCTION bit set in it's header + // + + i = Slot.u.bits.DeviceNumber; + + // + // Read DeviceNumber, Function zero, to determine if the + // PCI supports multifunction devices + // + + Slot2 = Slot; + Slot2.u.bits.FunctionNumber = 0; + + HalpReadPCIConfig ( + BusHandler, + Slot2, + &HeaderType, + FIELD_OFFSET (PCI_COMMON_CONFIG, HeaderType), + sizeof (UCHAR) + ); + + if (!(HeaderType & PCI_MULTIFUNCTION) || HeaderType == 0xFF) { + // this device doesn't exists or doesn't support MULTIFUNCTION types + return FALSE; + } + + return TRUE; +} + + +VOID +HalpPCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length, + IN FncConfigIO *ConfigIO + ) +{ + KIRQL OldIrql; + ULONG i; + UCHAR State[20]; + PPCIPBUSDATA BusData; + + BusData = (PPCIPBUSDATA) BusHandler->BusData; + + if (Slot.u.bits.DeviceNumber < 3) { // H001 +#if DBG + DbgPrint("HalpPCIConfig: Ignore Slot %x\n",Slot.u.bits.DeviceNumber); +#endif + return; + } + + PCIConfigHandler.Synchronize (BusHandler, Slot, &OldIrql, State); + + while (Length) { + i = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)]; + i = ConfigIO[i] (BusData, State, Buffer, Offset); + + Offset += i; + Buffer += i; + Length -= i; + } + + PCIConfigHandler.ReleaseSynchronzation (BusHandler, OldIrql); +} + +VOID HalpPCISynchronizeType1 ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PPCI_TYPE1_CFG_BITS PciCfg1 + ) +{ + // + // Initialize PciCfg1 + // + + PciCfg1->u.AsULONG = 0; + PciCfg1->u.bits.BusNumber = BusHandler->BusNumber; + PciCfg1->u.bits.DeviceNumber = Slot.u.bits.DeviceNumber; + PciCfg1->u.bits.FunctionNumber = Slot.u.bits.FunctionNumber; + PciCfg1->u.bits.Enable = TRUE; + + // + // Synchronize with PCI type1 config space + // + + if (!HalpDoingCrashDump) { + KeRaiseIrql (PROFILE_LEVEL, Irql); // H001 + KiAcquireSpinLock (&HalpPCIConfigLock); + } else { + *Irql = HIGH_LEVEL; + } +} + +VOID HalpPCIReleaseSynchronzationType1 ( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql + ) +{ + PCI_TYPE1_CFG_BITS PciCfg1; + PPCIPBUSDATA BusData; + + // + // Disable PCI configuration space + // + + PciCfg1.u.AsULONG = 0; + BusData = (PPCIPBUSDATA) BusHandler->BusData; + WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1.u.AsULONG); + + // + // Release spinlock + // + + if (!HalpDoingCrashDump) { + KiReleaseSpinLock (&HalpPCIConfigLock); + KeLowerIrql (Irql); // H001 + } +} + + +ULONG +HalpPCIReadUcharType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG); + *Buffer = READ_PORT_UCHAR ((PUCHAR) (BusData->Config.Type1.Data + i)); + return sizeof (UCHAR); +} + +ULONG +HalpPCIReadUshortType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG); + *((PUSHORT) Buffer) = READ_PORT_USHORT ((PUSHORT) (BusData->Config.Type1.Data + i)); + return sizeof (USHORT); +} + +ULONG +HalpPCIReadUlongType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG); + *((PULONG) Buffer) = READ_PORT_ULONG ((PULONG) BusData->Config.Type1.Data); + return sizeof (ULONG); +} + + +ULONG +HalpPCIWriteUcharType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG); + WRITE_PORT_UCHAR ((PUCHAR) (BusData->Config.Type1.Data + i), *Buffer); + return sizeof (UCHAR); +} + +ULONG +HalpPCIWriteUshortType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG); + WRITE_PORT_USHORT ((PUSHORT) (BusData->Config.Type1.Data + i), *((PUSHORT) Buffer)); + return sizeof (USHORT); +} + +ULONG +HalpPCIWriteUlongType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG); + WRITE_PORT_ULONG ((PULONG) BusData->Config.Type1.Data, *((PULONG) Buffer)); + return sizeof (ULONG); +} + + +VOID HalpPCISynchronizeType2 ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr + ) +{ + PCI_TYPE2_CSE_BITS PciCfg2Cse; + PPCIPBUSDATA BusData; + + BusData = (PPCIPBUSDATA) BusHandler->BusData; + + // + // Initialize Cfg2Addr + // + + PciCfg2Addr->u.AsUSHORT = 0; + PciCfg2Addr->u.bits.Agent = (USHORT) Slot.u.bits.DeviceNumber; + PciCfg2Addr->u.bits.AddressBase = (USHORT) BusData->Config.Type2.Base; + + // + // Synchronize with type2 config space - type2 config space + // remaps 4K of IO space, so we can not allow other I/Os to occur + // while using type2 config space. + // + + HalpPCIAcquireType2Lock (&HalpPCIConfigLock, Irql); + + PciCfg2Cse.u.AsUCHAR = 0; + PciCfg2Cse.u.bits.Enable = TRUE; + PciCfg2Cse.u.bits.FunctionNumber = (UCHAR) Slot.u.bits.FunctionNumber; + PciCfg2Cse.u.bits.Key = 0xff; + + // + // Select bus & enable type 2 configuration space + // + + WRITE_PORT_UCHAR (BusData->Config.Type2.Forward, (UCHAR) BusHandler->BusNumber); + WRITE_PORT_UCHAR (BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR); +} + + +VOID HalpPCIReleaseSynchronzationType2 ( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql + ) +{ + PCI_TYPE2_CSE_BITS PciCfg2Cse; + PPCIPBUSDATA BusData; + + // + // disable PCI configuration space + // + + BusData = (PPCIPBUSDATA) BusHandler->BusData; + + PciCfg2Cse.u.AsUCHAR = 0; + WRITE_PORT_UCHAR (BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR); + WRITE_PORT_UCHAR (BusData->Config.Type2.Forward, (UCHAR) 0); + + // + // Restore interrupts, release spinlock + // + + HalpPCIReleaseType2Lock (&HalpPCIConfigLock, Irql); +} + + +ULONG +HalpPCIReadUcharType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset; + *Buffer = READ_PORT_UCHAR ((PUCHAR) PciCfg2Addr->u.AsUSHORT); + return sizeof (UCHAR); +} + +ULONG +HalpPCIReadUshortType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset; + *((PUSHORT) Buffer) = READ_PORT_USHORT ((PUSHORT) PciCfg2Addr->u.AsUSHORT); + return sizeof (USHORT); +} + +ULONG +HalpPCIReadUlongType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset; + *((PULONG) Buffer) = READ_PORT_ULONG ((PULONG) PciCfg2Addr->u.AsUSHORT); + return sizeof(ULONG); +} + + +ULONG +HalpPCIWriteUcharType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset; + WRITE_PORT_UCHAR ((PUCHAR) PciCfg2Addr->u.AsUSHORT, *Buffer); + return sizeof (UCHAR); +} + +ULONG +HalpPCIWriteUshortType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset; + WRITE_PORT_USHORT ((PUSHORT) PciCfg2Addr->u.AsUSHORT, *((PUSHORT) Buffer)); + return sizeof (USHORT); +} + +ULONG +HalpPCIWriteUlongType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset; + WRITE_PORT_ULONG ((PULONG) PciCfg2Addr->u.AsUSHORT, *((PULONG) Buffer)); + return sizeof(ULONG); +} + + +NTSTATUS +HalpAssignPCISlotResources ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName OPTIONAL, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN ULONG Slot, + IN OUT PCM_RESOURCE_LIST *pAllocatedResources + ) +/*++ + +Routine Description: + + Reads the targeted device to determine it's required resources. + Calls IoAssignResources to allocate them. + Sets the targeted device with it's assigned resoruces + and returns the assignments to the caller. + +Arguments: + +Return Value: + + STATUS_SUCCESS or error + +--*/ +{ + NTSTATUS status; + PUCHAR WorkingPool; + PPCI_COMMON_CONFIG PciData, PciOrigData, PciData2; + PCI_COMMON_CONFIG PciData3; // H005 + PCI_SLOT_NUMBER PciSlot; + PPCIPBUSDATA BusData; + PIO_RESOURCE_REQUIREMENTS_LIST CompleteList; + PIO_RESOURCE_DESCRIPTOR Descriptor; + PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor; + ULONG BusNumber; + ULONG i, j, m, length, memtype; + ULONG NoBaseAddress, RomIndex, Option; + PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1]; + PULONG OrigAddress[PCI_TYPE0_ADDRESSES + 1]; + BOOLEAN Match, EnableRomBase; + + + *pAllocatedResources = NULL; + PciSlot = *((PPCI_SLOT_NUMBER) &Slot); + BusNumber = BusHandler->BusNumber; + BusData = (PPCIPBUSDATA) BusHandler->BusData; + + // + // Allocate some pool for working space + // + + i = sizeof (IO_RESOURCE_REQUIREMENTS_LIST) + + sizeof (IO_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2) * 2 + + PCI_COMMON_HDR_LENGTH * 3; + + WorkingPool = (PUCHAR) ExAllocatePool (PagedPool, i); + if (!WorkingPool) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Zero initialize pool, and get pointers into memory + // + + RtlZeroMemory (WorkingPool, i); + CompleteList = (PIO_RESOURCE_REQUIREMENTS_LIST) WorkingPool; + PciData = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH * 3); + PciData2 = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH * 2); + PciOrigData = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH * 1); + + // + // Read the PCI device's configuration + // + + HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); + if (PciData->VendorID == PCI_INVALID_VENDORID) { + ExFreePool (WorkingPool); + return STATUS_NO_SUCH_DEVICE; + } + + // + // Make a copy of the device's current settings + // + + RtlMoveMemory (PciOrigData, PciData, PCI_COMMON_HDR_LENGTH); + + // + // Initialize base addresses base on configuration data type + // + + switch (PCI_CONFIG_TYPE(PciData)) { + case 0 : + NoBaseAddress = PCI_TYPE0_ADDRESSES+1; + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + BaseAddress[j] = &PciData->u.type0.BaseAddresses[j]; + OrigAddress[j] = &PciOrigData->u.type0.BaseAddresses[j]; + } + BaseAddress[j] = &PciData->u.type0.ROMBaseAddress; + OrigAddress[j] = &PciOrigData->u.type0.ROMBaseAddress; + RomIndex = j; + break; + case 1: + NoBaseAddress = PCI_TYPE1_ADDRESSES+1; + for (j=0; j < PCI_TYPE1_ADDRESSES; j++) { + BaseAddress[j] = &PciData->u.type1.BaseAddresses[j]; + OrigAddress[j] = &PciOrigData->u.type1.BaseAddresses[j]; + } + BaseAddress[j] = &PciData->u.type1.ROMBaseAddress; + OrigAddress[j] = &PciOrigData->u.type1.ROMBaseAddress; + RomIndex = j; + break; + + default: + ExFreePool (WorkingPool); + return STATUS_NO_SUCH_DEVICE; + } + + // + // If the BIOS doesn't have the device's ROM enabled, then we won't + // enable it either. Remove it from the list. + // + + EnableRomBase = TRUE; + +#if 0 // H001 + if (!(*BaseAddress[RomIndex] & PCI_ROMADDRESS_ENABLED)) { + ASSERT (RomIndex+1 == NoBaseAddress); + EnableRomBase = FALSE; + NoBaseAddress -= 1; + } +#endif + + // + // Set resources to all bits on to see what type of resources + // are required. + // + + for (j=0; j < NoBaseAddress; j++) { + *BaseAddress[j] = 0xFFFFFFFF; + } + + PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE); + *BaseAddress[RomIndex] &= ~PCI_ROMADDRESS_ENABLED; + HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); + HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); + + // + // H004 + // Make a copy of the device's current settings + // + + RtlMoveMemory ((PPCI_COMMON_CONFIG)&PciData3, PciData, PCI_COMMON_HDR_LENGTH); + + // note type0 & type1 overlay ROMBaseAddress, InterruptPin, and InterruptLine + BusData->CommonData.Pin2Line (BusHandler, RootHandler, PciSlot, PciData); + + // + // Build an IO_RESOURCE_REQUIREMENTS_LIST for the PCI device + // + + CompleteList->InterfaceType = PCIBus; + CompleteList->BusNumber = BusNumber; + CompleteList->SlotNumber = Slot; + CompleteList->AlternativeLists = 1; + + CompleteList->List[0].Version = 1; + CompleteList->List[0].Revision = 1; + + Descriptor = CompleteList->List[0].Descriptors; + + // + // If PCI device has an interrupt resource, add it + // + + if (PciData->u.type0.InterruptPin) { + CompleteList->List[0].Count++; + + Descriptor->Option = 0; + Descriptor->Type = CmResourceTypeInterrupt; + Descriptor->ShareDisposition = CmResourceShareShared; + Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + + // Fill in any vector here - we'll pick it back up in + // HalAdjustResourceList and adjust it to it's allowed settings + Descriptor->u.Interrupt.MinimumVector = 0; + Descriptor->u.Interrupt.MaximumVector = 0xff; + Descriptor++; + } + + // + // Add a memory/port resoruce for each PCI resource + // + + // Clear ROM reserved bits + + *BaseAddress[RomIndex] &= ~0x7FF; + + for (j=0; j < NoBaseAddress; j++) { + if (*BaseAddress[j]) { + i = *BaseAddress[j]; + + // scan for first set bit, that's the length & alignment + length = 1 << (i & PCI_ADDRESS_IO_SPACE ? 2 : 4); + while (!(i & length) && length) { + length <<= 1; + } + + // scan for last set bit, that's the maxaddress + 1 + for (m = length; i & m; m <<= 1) ; + m--; + + // check for hosed PCI configuration requirements + if (length & ~m) { +#if DBG + DbgPrint ("PCI: defective device! Bus %d, Slot %d, Function %d\n", + BusNumber, + PciSlot.u.bits.DeviceNumber, + PciSlot.u.bits.FunctionNumber + ); + + DbgPrint ("PCI: BaseAddress[%d] = %08lx\n", j, i); +#endif + // the device is in error - punt. don't allow this + // resource any option - it either gets set to whatever + // bits it was able to return, or it doesn't get set. + + if (i & PCI_ADDRESS_IO_SPACE) { + m = i & ~0x3; + Descriptor->u.Port.MinimumAddress.LowPart = m; + } else { + m = i & ~0xf; + Descriptor->u.Memory.MinimumAddress.LowPart = m; + } + + m += length; // max address is min address + length + } + + // + // Add requested resource + // + + Descriptor->Option = 0; + if (i & PCI_ADDRESS_IO_SPACE) { + memtype = 0; + +#if 0 // H002 + if (!Is64BitBaseAddress(i) && + PciOrigData->Command & PCI_ENABLE_IO_SPACE) { + + // + // The IO range is/was already enabled at some location, add that + // as it's preferred setting. + // + + Descriptor->Type = CmResourceTypePort; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_PORT_IO; + Descriptor->Option = IO_RESOURCE_PREFERRED; + + Descriptor->u.Port.Length = length; + Descriptor->u.Port.Alignment = length; + Descriptor->u.Port.MinimumAddress.LowPart = *OrigAddress[j] & ~0x3; + Descriptor->u.Port.MaximumAddress.LowPart = + Descriptor->u.Port.MinimumAddress.LowPart + length - 1; + + CompleteList->List[0].Count++; + Descriptor++; + + Descriptor->Option = IO_RESOURCE_ALTERNATIVE; + } +#endif + // + // Add this IO range + // + + Descriptor->Type = CmResourceTypePort; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_PORT_IO; + + Descriptor->u.Port.Length = length; + Descriptor->u.Port.Alignment = length; + Descriptor->u.Port.MaximumAddress.LowPart = m; + +#if DBG // H001 + DbgPrint("HalpAssign: Port %x len %x align %x\n", length, length, m); +#endif // DBG + + } else { + + memtype = i & PCI_ADDRESS_MEMORY_TYPE_MASK; + + Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; + if (j == RomIndex) { + // this is a ROM address + Descriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY; + } + + if (i & PCI_ADDRESS_MEMORY_PREFETCHABLE) { + Descriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; + } + +#if 0 // H002 + if (!Is64BitBaseAddress(i) && + (j == RomIndex || + PciOrigData->Command & PCI_ENABLE_MEMORY_SPACE)) { + + // + // The memory range is/was already enabled at some location, add that + // as it's preferred setting. + // + + Descriptor->Type = CmResourceTypeMemory; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Option = IO_RESOURCE_PREFERRED; + + Descriptor->u.Port.Length = length; + Descriptor->u.Port.Alignment = length; + Descriptor->u.Port.MinimumAddress.LowPart = *OrigAddress[j] & ~0xF; + Descriptor->u.Port.MaximumAddress.LowPart = + Descriptor->u.Port.MinimumAddress.LowPart + length - 1; + + CompleteList->List[0].Count++; + Descriptor++; + + Descriptor->Flags = Descriptor[-1].Flags; + Descriptor->Option = IO_RESOURCE_ALTERNATIVE; + } +#endif + // + // Add this memory range + // + + Descriptor->Type = CmResourceTypeMemory; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + + Descriptor->u.Memory.Length = length; + Descriptor->u.Memory.Alignment = length; + Descriptor->u.Memory.MaximumAddress.LowPart = m; + + if (memtype == PCI_TYPE_20BIT && m > 0xFFFFF) { + // limit to 20 bit address + Descriptor->u.Memory.MaximumAddress.LowPart = 0xFFFFF; + } + +#if DBG // H001 + DbgPrint("HalpAssign: Memory %x len %x align %x\n", length, length, m); +#endif // DBG + + } + + CompleteList->List[0].Count++; + Descriptor++; + + + if (Is64BitBaseAddress(i)) { + // skip upper half of 64 bit address since this processor + // only supports 32 bits of address space + j++; + } + } + } + + CompleteList->ListSize = (ULONG) + ((PUCHAR) Descriptor - (PUCHAR) CompleteList); + + // + // Restore the device settings as we found them, enable memory + // and io decode after setting base addresses. This is done in + // case HalAdjustResourceList wants to read the current settings + // in the device. + // + + HalpWritePCIConfig ( + BusHandler, + PciSlot, + &PciOrigData->Status, + FIELD_OFFSET (PCI_COMMON_CONFIG, Status), + PCI_COMMON_HDR_LENGTH - FIELD_OFFSET (PCI_COMMON_CONFIG, Status) + ); + + HalpWritePCIConfig ( + BusHandler, + PciSlot, + PciOrigData, + 0, + FIELD_OFFSET (PCI_COMMON_CONFIG, Status) + ); + + // + // Have the IO system allocate resource assignments + // + +#if DBG // H001 + DbgPrint("Call IoAssignResources\n"); +#endif // DBG + + status = IoAssignResources ( + RegistryPath, + DriverClassName, + DriverObject, + DeviceObject, + CompleteList, + pAllocatedResources + ); + + if (!NT_SUCCESS(status)) { + goto CleanUp; + } + + // + // Slurp the assigments back into the PciData structure and + // perform them + // + + CmDescriptor = (*pAllocatedResources)->List[0].PartialResourceList.PartialDescriptors; + + // + // If PCI device has an interrupt resource then that was + // passed in as the first requested resource + // + + if (PciData->u.type0.InterruptPin) { + PciData->u.type0.InterruptLine = (UCHAR) CmDescriptor->u.Interrupt.Vector; + BusData->CommonData.Line2Pin (BusHandler, RootHandler, PciSlot, PciData, PciOrigData); + CmDescriptor++; + } + + // + // Pull out resources in the order they were passed to IoAssignResources + // + + for (j=0; j < NoBaseAddress; j++) { + i = *BaseAddress[j]; + if (i) { + if (i & PCI_ADDRESS_IO_SPACE) { + *BaseAddress[j] = CmDescriptor->u.Port.Start.LowPart; +#if DBG // H001 + DbgPrint("HalpAssign assigned: Port %x\n", *BaseAddress[j]); +#endif // DBG + } else { + *BaseAddress[j] = CmDescriptor->u.Memory.Start.LowPart; +#if DBG // H001 + DbgPrint("HalpAssign assigned: Memory %x\n", *BaseAddress[j]); +#endif // DBG + } + CmDescriptor++; + } + + if (Is64BitBaseAddress(i)) { + // skip upper 32 bits + j++; + } + } + + // + // Turn off decodes, then set new addresses + // + +#if DBG // H001 + DbgPrint("Set Assigned Resources\n"); +#endif // DBG + + HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); + + // + // Read configuration back and verify address settings took + // + +#if DBG // H001 + DbgPrint("Read Common header to see write results\n"); +#endif // DBG + + HalpReadPCIConfig(BusHandler, PciSlot, PciData2, 0, PCI_COMMON_HDR_LENGTH); + + Match = TRUE; + if (PciData->u.type0.InterruptLine != PciData2->u.type0.InterruptLine || + PciData->u.type0.InterruptPin != PciData2->u.type0.InterruptPin || + PciData->u.type0.ROMBaseAddress != PciData2->u.type0.ROMBaseAddress) { + Match = FALSE; + } + + for (j=0; j < NoBaseAddress; j++) { + if (*BaseAddress[j]) { + if (*BaseAddress[j] & PCI_ADDRESS_IO_SPACE) { + i = (ULONG) ~0x3; + } else { + i = (ULONG) ~0xF; + } + + if ((*BaseAddress[j] & i) != + *((PULONG) ((PUCHAR) BaseAddress[j] - + (PUCHAR) PciData + + (PUCHAR) PciData2)) & i) { + + Match = FALSE; + } + + if (Is64BitBaseAddress(*BaseAddress[j])) { + // skip upper 32 bits + j++; + } + } + } + + if (!Match) { +#if DBG + DbgPrint ("PCI: defective device! Bus %d, Slot %d, Function %d\n", + BusNumber, + PciSlot.u.bits.DeviceNumber, + PciSlot.u.bits.FunctionNumber + ); +#endif + status = STATUS_DEVICE_PROTOCOL_ERROR; + goto CleanUp; + } + + // + // H004 + // set memory space as back-to-back available + // + + HalpSetBackToBackSpace(&PciData3, PciData2, BusHandler); + + // + // Settings took - turn on the appropiate decodes + // + + if (EnableRomBase && *BaseAddress[RomIndex]) { + // a rom address was allocated and should be enabled + *BaseAddress[RomIndex] |= PCI_ROMADDRESS_ENABLED; + HalpWritePCIConfig ( + BusHandler, + PciSlot, + BaseAddress[RomIndex], + (ULONG) ((PUCHAR) BaseAddress[RomIndex] - (PUCHAR) PciData), + sizeof (ULONG) + ); + } + + // + // Enable IO, Memory, and BUS_MASTER decodes + // (use HalSetBusData since valid settings now set) + // + + PciData->Command |= PCI_ENABLE_IO_SPACE | + PCI_ENABLE_MEMORY_SPACE | + PCI_ENABLE_BUS_MASTER; + + HalSetBusDataByOffset ( + PCIConfiguration, + BusHandler->BusNumber, + PciSlot.u.AsULONG, + &PciData->Command, + FIELD_OFFSET (PCI_COMMON_CONFIG, Command), + sizeof (PciData->Command) + ); + +CleanUp: + if (!NT_SUCCESS(status)) { + + // + // Failure, if there are any allocated resources free them + // + + if (*pAllocatedResources) { + IoAssignResources ( + RegistryPath, + DriverClassName, + DriverObject, + DeviceObject, + NULL, + NULL + ); + + ExFreePool (*pAllocatedResources); + *pAllocatedResources = NULL; + } + + // + // Restore the device settings as we found them, enable memory + // and io decode after setting base addresses + // + + HalpWritePCIConfig ( + BusHandler, + PciSlot, + &PciOrigData->Status, + FIELD_OFFSET (PCI_COMMON_CONFIG, Status), + PCI_COMMON_HDR_LENGTH - FIELD_OFFSET (PCI_COMMON_CONFIG, Status) + ); + + HalpWritePCIConfig ( + BusHandler, + PciSlot, + PciOrigData, + 0, + FIELD_OFFSET (PCI_COMMON_CONFIG, Status) + ); + } + + ExFreePool (WorkingPool); + return status; +} + +#if DBG +VOID +HalpTestPci (ULONG flag2) +{ + PCI_SLOT_NUMBER SlotNumber; + PCI_COMMON_CONFIG PciData, OrigData; + ULONG i, f, j, k, bus; + BOOLEAN flag; + + + if (!flag2) { + return ; + } + + DbgBreakPoint (); + SlotNumber.u.bits.Reserved = 0; + + // + // Read every possible PCI Device/Function and display it's + // default info. + // + // (note this destories it's current settings) + // + + flag = TRUE; + for (bus = 0; flag; bus++) { + + for (i = 0; i < PCI_MAX_DEVICES; i++) { + SlotNumber.u.bits.DeviceNumber = i; + + for (f = 0; f < PCI_MAX_FUNCTION; f++) { + SlotNumber.u.bits.FunctionNumber = f; + + // + // Note: This is reading the DeviceSpecific area of + // the device's configuration - normally this should + // only be done on device for which the caller understands. + // I'm doing it here only for debugging. + // + + j = HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + if (j == 0) { + // out of buses + flag = FALSE; + break; + } + + if (j < PCI_COMMON_HDR_LENGTH) { + continue; + } + + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + 1 + ); + + HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + +#if 0 + memcpy (&OrigData, &PciData, sizeof PciData); + + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + PciData.u.type0.BaseAddresses[j] = 0xFFFFFFFF; + } + + PciData.u.type0.ROMBaseAddress = 0xFFFFFFFF; + + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); +#endif + + DbgPrint ("PCI Bus %d Slot %2d %2d ID:%04lx-%04lx Rev:%04lx", + bus, i, f, PciData.VendorID, PciData.DeviceID, + PciData.RevisionID); + + + if (PciData.u.type0.InterruptPin) { + DbgPrint (" IntPin:%x", PciData.u.type0.InterruptPin); + } + + if (PciData.u.type0.InterruptLine) { + DbgPrint (" IntLine:%x", PciData.u.type0.InterruptLine); + } + + if (PciData.u.type0.ROMBaseAddress) { + DbgPrint (" ROM:%08lx", PciData.u.type0.ROMBaseAddress); + } + + DbgPrint ("\n Cmd:%04x Status:%04x ProgIf:%04x SubClass:%04x BaseClass:%04lx\n", + PciData.Command, PciData.Status, PciData.ProgIf, + PciData.SubClass, PciData.BaseClass); + + k = 0; + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + if (PciData.u.type0.BaseAddresses[j]) { + DbgPrint (" Ad%d:%08lx", j, PciData.u.type0.BaseAddresses[j]); + k = 1; + } + } + +#if 0 + if (PciData.u.type0.ROMBaseAddress == 0xC08001) { + + PciData.u.type0.ROMBaseAddress = 0xC00001; + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + DbgPrint ("\n Bogus rom address, edit yields:%08lx", + PciData.u.type0.ROMBaseAddress); + } +#endif + + if (k) { + DbgPrint ("\n"); + } + + if (PciData.VendorID == 0x8086) { + // dump complete buffer + DbgPrint ("Command %x, Status %x, BIST %x\n", + PciData.Command, PciData.Status, + PciData.BIST + ); + + DbgPrint ("CacheLineSz %x, LatencyTimer %x", + PciData.CacheLineSize, PciData.LatencyTimer + ); + + for (j=0; j < 192; j++) { + if ((j & 0xf) == 0) { + DbgPrint ("\n%02x: ", j + 0x40); + } + DbgPrint ("%02x ", PciData.DeviceSpecific[j]); + } + DbgPrint ("\n"); + } + + +#if 0 + // + // now print original data + // + + if (OrigData.u.type0.ROMBaseAddress) { + DbgPrint (" oROM:%08lx", OrigData.u.type0.ROMBaseAddress); + } + + DbgPrint ("\n"); + k = 0; + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + if (OrigData.u.type0.BaseAddresses[j]) { + DbgPrint (" oAd%d:%08lx", j, OrigData.u.type0.BaseAddresses[j]); + k = 1; + } + } + + // + // Restore original settings + // + + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &OrigData, + sizeof (PciData) + ); +#endif + + // + // Next + // + + if (k) { + DbgPrint ("\n\n"); + } + } + } + } + DbgBreakPoint (); +} + +#if defined (_R94A_) // H001 +VOID +HalpTestPciNec (ULONG flag2) +{ + PCI_SLOT_NUMBER SlotNumber; + PCI_COMMON_CONFIG PciData, OrigData; + ULONG i, f, j, k, bus; + BOOLEAN flag; + + + if (!flag2) { + return ; + } + + DbgBreakPoint (); + SlotNumber.u.bits.Reserved = 0; + + // + // Read every possible PCI Device/Function and display it's + // default info. + // + // (note this destories it's current settings) + // + + flag = TRUE; + for (bus = 0; flag && bus < 1; bus++) { /* R94A_ Support Only 1 */ + + for (i = 0; i < PCI_MAX_DEVICES; i++) { /* R94A_ Support Only 2 slots(include bridge) */ + SlotNumber.u.bits.DeviceNumber = i; + + for (f = 0; f < 8; f++) { + SlotNumber.u.bits.FunctionNumber = f; + DbgPrint("===== GetBusData slot(%d) func(%d)\n", i, f); + j = HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + HalpTestPciPrintResult((PULONG)&PciData, j); + if (j == 0) { + // out of buses + flag = FALSE; + break; + } + + if (j < PCI_COMMON_HDR_LENGTH) { + continue; + } + DbgPrint("===== SetBusData slot(%d) func(%d)\n", i, f); + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + 1 + ); + HalpTestPciPrintResult((PULONG)&PciData, 1); + DbgPrint("===== GetBusData slot(%d) func(%d)\n", i, f); + HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + HalpTestPciPrintResult((PULONG)&PciData, sizeof (PciData)); + memcpy (&OrigData, &PciData, sizeof PciData); + + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + PciData.u.type0.BaseAddresses[j] = 0xFFFFFFFF; + } + + PciData.u.type0.ROMBaseAddress = 0xFFFFFFFF; + PciData.u.type0.InterruptLine = 5; // For trial + DbgPrint("===== (Change Contents (SetBusData) slot(%d) func(%d)\n", i, f); + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + PCI_COMMON_HDR_LENGTH // To avoid alias problem(HDR <--> DevSpecific) + ); + HalpTestPciPrintResult((PULONG)&PciData, PCI_COMMON_HDR_LENGTH); + DbgPrint("===== GetBusData slot(%d) func(%d)\n", i, f); + HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + HalpTestPciPrintResult((PULONG)&PciData, sizeof (PciData)); + + DbgPrint ("--------------->>> Now Print the Slot Information\n"); + DbgPrint ("PCI Bus %d Slot %2d %2d ID:%04lx-%04lx Rev:%04lx", + bus, i, f, PciData.VendorID, PciData.DeviceID, + PciData.RevisionID); + + + if (PciData.u.type0.InterruptPin) { + DbgPrint (" IntPin:%x", PciData.u.type0.InterruptPin); + } + + if (PciData.u.type0.InterruptLine) { + DbgPrint (" IntLine:%x", PciData.u.type0.InterruptLine); + } + + if (PciData.u.type0.ROMBaseAddress) { + DbgPrint (" ROM:%08lx", PciData.u.type0.ROMBaseAddress); + } + + DbgPrint ("\n ProgIf:%04x SubClass:%04x BaseClass:%04lx\n", + PciData.ProgIf, PciData.SubClass, PciData.BaseClass); + + k = 0; + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + if (PciData.u.type0.BaseAddresses[j]) { + DbgPrint (" Ad%d:%08lx", j, PciData.u.type0.BaseAddresses[j]); + k = 1; + } + } + + if (PciData.u.type0.ROMBaseAddress == 0xC08001) { + + PciData.u.type0.ROMBaseAddress = 0xC00001; + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + DbgPrint ("\n Bogus rom address, edit yields:%08lx", + PciData.u.type0.ROMBaseAddress); + } + + if (k) { + DbgPrint ("\n"); + } + + if (PciData.VendorID == 0x8086) { + // dump complete buffer + DbgPrint ("We got the bridge\n"); + DbgPrint ("Command %x, Status %x, BIST %x\n", + PciData.Command, PciData.Status, + PciData.BIST + ); + + DbgPrint ("CacheLineSz %x, LatencyTimer %x", + PciData.CacheLineSize, PciData.LatencyTimer + ); + + for (j=0; j < 192; j++) { + if ((j & 0xf) == 0) { + DbgPrint ("\n%02x: ", j + 0x40); + } + DbgPrint ("%02x ", PciData.DeviceSpecific[j]); + } + DbgPrint ("\n"); + } + + + // + // now print original data + // + DbgPrint ("--------------->>> Now Print the Original Slot Information\n"); + if (OrigData.u.type0.ROMBaseAddress) { + DbgPrint (" oROM:%08lx", OrigData.u.type0.ROMBaseAddress); + } + + DbgPrint ("\n"); + k = 0; + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + if (OrigData.u.type0.BaseAddresses[j]) { + DbgPrint (" oAd%d:%08lx", j, OrigData.u.type0.BaseAddresses[j]); + k = 1; + } + } + + // + // Restore original settings + // + DbgPrint("===== Restore (GetBusData) slot(%d) func(%d)\n", i, f); + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &OrigData, + sizeof (PciData) + ); + HalpTestPciPrintResult((PULONG)&OrigData, sizeof (PciData)); + // + // Next + // + + if (k) { + DbgPrint ("\n\n"); + } + } + } + } + DbgBreakPoint (); +} + + +VOID +HalpTestPciPrintResult( + IN PULONG Buffer, + IN ULONG Length +) +{ + ULONG i, Lines, pchar; + + DbgPrint("----- I/O Data. (%d)byts.\n", Length); + + for (Lines = 0, pchar = 0; Lines < ((Length + 15)/ 16) && pchar < Length; Lines++) { + DbgPrint("%08x: ", Lines * 16); + for (i = 0; i < 4; pchar += 4, i++) { + if (pchar >= Length) + break; + DbgPrint("%08x ", *Buffer++); + } + DbgPrint("\n"); + } +} + +VOID +HalpOtherTestNec ( + IN ULONG doOtherTest +) +{ + if (!doOtherTest) + return; + + + DbgPrint("\n\n===== Additional Testing...\n"); + { + CM_EISA_SLOT_INFORMATION EisaSlotInfo; + PCM_EISA_SLOT_INFORMATION EisaBuffer; + PCM_EISA_FUNCTION_INFORMATION EisaFunctionInfo; + ULONG slot, funcs, Length; + + #define MAX_EISA_SLOT 4 + + DbgPrint("----- Read Eisa Configration:\n"); + for (slot = 0; slot < MAX_EISA_SLOT; slot++) { + Length = HalGetBusData (EisaConfiguration,0,slot,&EisaSlotInfo,sizeof (EisaSlotInfo)); + if (Length < sizeof(CM_EISA_SLOT_INFORMATION)) { + + // + // The data is messed up since this should never occur + // + + break; + } + Length = sizeof(CM_EISA_SLOT_INFORMATION) + + (sizeof(CM_EISA_FUNCTION_INFORMATION) * EisaSlotInfo.NumberFunctions); + EisaBuffer = ExAllocatePool(NonPagedPool, Length); + HalGetBusData (EisaConfiguration,0,slot,&EisaBuffer,Length); + // Print all Eisa Data + + EisaFunctionInfo = (PCM_EISA_FUNCTION_INFORMATION) + ((char *)&EisaBuffer + sizeof(CM_EISA_SLOT_INFORMATION)); + + DbgPrint("----- HalGetBusData Eisa Slot No=%d\n", slot); + DbgPrint("ReturnCode = 0x%x, ReturnFlags = 0x%x, MajorRev = 0x%x, MinorRev = 0x%x, \n", + EisaBuffer->ReturnCode, EisaBuffer->ReturnFlags, + EisaBuffer->MajorRevision, EisaBuffer->MinorRevision); + DbgPrint("CheckSum = 0x%x, NumberFunctions = 0x%x, FunctionInformation = 0x%x, CompressedId = 0x%x\n", + EisaBuffer->Checksum, + EisaBuffer->NumberFunctions, + EisaBuffer->FunctionInformation, + EisaBuffer->CompressedId); + for (funcs = 0; funcs < EisaBuffer->NumberFunctions; funcs++) { + DbgPrint("CompressId = 0x%x, IdSlotFlags1 = 0x%x, IdSlotFlags2 = 0x%x, MinorRevision = 0x%x, MajorRevision = 0x%x\n", + EisaFunctionInfo->CompressedId, EisaFunctionInfo->IdSlotFlags1, + EisaFunctionInfo->IdSlotFlags2, EisaFunctionInfo->MinorRevision, + EisaFunctionInfo->MajorRevision); + + // EisaFunctionInfo->Selections[26]; + // EisaFunctionInfo->FunctionFlags; + // EisaFunctionInfo->TypeString[80]; + // EISA_MEMORY_CONFIGURATION EisaFunctionInfo->EisaMemory[9]; + // EISA_IRQ_CONFIGURATION EisaFunctionInfo->EisaIrq[7]; + // EISA_DMA_CONFIGURATION EisaFunctionInfo->EisaDma[4]; + // EISA_PORT_CONFIGURATION EisaFunctionInfo->EisaPort[20]; + // UCHAR EisaFunctionInfo->InitializationData[60]; + EisaFunctionInfo++; + } + + } + } + DbgBreakPoint (); + { + #define MEMORY_SPACE 0 + #define IO_SPACE 1 + PHYSICAL_ADDRESS cardAddress; + ULONG addressSpace = IO_SPACE; + PHYSICAL_ADDRESS PhysAddr; + + PhysAddr.LowPart = 0; + PhysAddr.HighPart = 0; + + + + DbgPrint("----- Translate Internal Bus Address(I/O): "); + HalTranslateBusAddress(Internal, (ULONG)0, PhysAddr, &addressSpace, &cardAddress); + DbgPrint("H-AD: %x\tL-AD: %x\n\n", cardAddress.HighPart, cardAddress.LowPart); + + DbgPrint("Translate Eisa Bus Address(I/O): "); + addressSpace = IO_SPACE; + HalTranslateBusAddress(Eisa, (ULONG)0, PhysAddr, &addressSpace, &cardAddress); + DbgPrint("H-AD: %x\tL-AD: %x\n\n", cardAddress.HighPart, cardAddress.LowPart); + + DbgPrint("Translate Isa Bus Address(I/O): "); + addressSpace = IO_SPACE; + HalTranslateBusAddress(Isa, (ULONG)0, PhysAddr, &addressSpace, &cardAddress); + DbgPrint("H-AD: %x\tL-AD: %x\n\n", cardAddress.HighPart, cardAddress.LowPart); + + DbgPrint("Translate PCI Bus Address(I/O): "); + addressSpace = IO_SPACE; + HalTranslateBusAddress(PCIBus, (ULONG)0, PhysAddr, &addressSpace, &cardAddress); + DbgPrint("H-AD: %x\tL-AD: %x\n\n", cardAddress.HighPart, cardAddress.LowPart); + + DbgPrint("Translate Internal Bus Address(MEMORY): "); + addressSpace = MEMORY_SPACE; + HalTranslateBusAddress(Internal, (ULONG)0, PhysAddr, &addressSpace, &cardAddress); + DbgPrint("H-AD: %x\tL-AD: %x\n\n", cardAddress.HighPart, cardAddress.LowPart); + + DbgPrint("Translate Eisa Bus Address(MEMORY): "); + addressSpace = MEMORY_SPACE; + HalTranslateBusAddress(Eisa, (ULONG)0, PhysAddr, &addressSpace, &cardAddress); + DbgPrint("H-AD: %x\tL-AD: %x\n\n", cardAddress.HighPart, cardAddress.LowPart); + + DbgPrint("Translate Isa Bus Address(MEMORY): "); + addressSpace = MEMORY_SPACE; + HalTranslateBusAddress(Isa, (ULONG)0, PhysAddr, &addressSpace, &cardAddress); + DbgPrint("H-AD: %x\tL-AD: %x\n\n", cardAddress.HighPart, cardAddress.LowPart); + + DbgPrint("Translate PCI Bus Address(MEMORY): "); + addressSpace = MEMORY_SPACE; + HalTranslateBusAddress(PCIBus, (ULONG)0, PhysAddr, &addressSpace, &cardAddress); + DbgPrint("H-AD: %x\tL-AD: %x\n\n", cardAddress.HighPart, cardAddress.LowPart); + } + DbgBreakPoint (); + + { + KAFFINITY affinity; + KIRQL Irql; + ULONG Vec; + + DbgPrint("----- GetInterruptVector internal\n"); + Vec = HalGetInterruptVector(Internal, 0, 0, 0, &Irql, &affinity); + DbgPrint(" Irql = 0x%x, affinity = 0x%x, vector = 0x%x\n\n", Irql, affinity, Vec); + + DbgPrint("GetInterruptVector Eisa\n"); + Vec = HalGetInterruptVector(Eisa, 0, 0, 0, &Irql, &affinity); + DbgPrint(" Irql = 0x%x, affinity = 0x%x, vector = 0x%x\n\n", Irql, affinity, Vec); + + DbgPrint("GetInterruptVector Isa\n"); + Vec = HalGetInterruptVector(Isa, 0, 0, 0, &Irql, &affinity); + DbgPrint(" Irql = 0x%x, affinity = 0x%x, vector = 0x%x\n\n", Irql, affinity, Vec); + + DbgPrint("GetInterruptVector PCI\n"); + Vec = HalGetInterruptVector(PCIBus, 0, 0, 0, &Irql, &affinity); + DbgPrint(" Irql = 0x%x, affinity = 0x%x, vector = 0x%x\n\n", Irql, affinity, Vec); + + } + DbgBreakPoint (); +} + +#endif // _R94A_ +#endif // DBG + +VOID +HalpSetBackToBackSpace( + IN PPCI_COMMON_CONFIG PciConfigRequired, + IN PPCI_COMMON_CONFIG PciConfigMapped, + IN PBUS_HANDLER BusHandler + ) +/*++ + +Routine Description: + + This function sets memory space of PCI device to Fast Back-to-back register. + +Arguments: + + PciConfigRequired - Supplies the description of the memory space which + device required. + PciConfigMapped - Supplies the description of the memory space which + should be mapped to back-to-back space. + BusHandler - Supplies the pointer to Bushandler. + +Return Value: + + None. + +--*/ + +{ + ULONG NoBaseAddress; + ULONG BaseAddress, LowerAddress; + ULONG CurrentAddress; + ULONG FoundMemoryAddress; + ULONG i, j, Length; + +#if DBG + DbgPrint(" check PCI-device!\n"); + DbgPrint(" - VendorID ................ %04x\n", PciConfigMapped->VendorID); + DbgPrint(" - DeviceID ................ %04x\n", PciConfigMapped->DeviceID); + DbgPrint(" - back-to-back capable? ... %s\n", (PciConfigMapped->Status & 0x80) ? "o" : "x"); + if (PciConfigMapped->BaseClass == 0x03 + || (PciConfigMapped->BaseClass == 0x00 && PciConfigMapped->SubClass == 0x01)){ + DbgPrint(" - Is this GA device? ...... o\n"); + } else { + DbgPrint(" - Is this GA device? ...... x\n"); + } +#endif + + KiAcquireSpinLock(&HalpPCIBackToBackLock); + + // + // calulate memory region of this device. + // + + switch (PCI_CONFIG_TYPE(PciConfigMapped)) { + case 0 : + NoBaseAddress = PCI_TYPE0_ADDRESSES; + break; + case 1: + NoBaseAddress = PCI_TYPE1_ADDRESSES; + break; + default: + // never come here. + // (already except by HalpAssignPCISlotResources) + return; + } + + Length = 0; + BaseAddress = 0xffffffff; + LowerAddress = 0xffffffff; + FoundMemoryAddress = 0; + + // + // get base and limit address + // + + for (i = 0; i < NoBaseAddress; i++) { + CurrentAddress = PciConfigMapped->u.type0.BaseAddresses[i]; + if (!(CurrentAddress & PCI_ADDRESS_IO_SPACE) + && ((CurrentAddress & PCI_ADDRESS_MEMORY_TYPE_MASK) != 0x2)) { + + // + // this is memory space and not need to map below 1M + // + + CurrentAddress = CurrentAddress & 0xfffffff0; + if (CurrentAddress) { + FoundMemoryAddress = 1; + if (LowerAddress > CurrentAddress) + LowerAddress = CurrentAddress; + // scan for first set bit, that's the length & alignment + j = 1 << 4; + while (!(PciConfigRequired->u.type0.BaseAddresses[i] & j) && j) + j <<= 1; +#if DBG + DbgPrint(" - [%d]MemoryAddress ........ 0x%08x\n", i, CurrentAddress); + DbgPrint(" - [%d]Length ............... 0x%08x\n", i, j); +#endif + if (Length < j){ + BaseAddress = CurrentAddress; + Length = j; + } + } + } + } + +#if DBG + DbgPrint(" - LowerAddress ............ 0x%08x\n", LowerAddress); + DbgPrint(" - BaseAddress ............. 0x%08x\n", BaseAddress); + DbgPrint(" - Length .................. 0x%08x\n", Length); +#endif + + // + // If this device has memory space, then change memory limit + // value used be allocation for PCI memory space to + // 'LowerAddress - 1' of this device, otherwise release spinlock + // and return. + // + + if (FoundMemoryAddress) { + HalpPCIMemoryLimit = LowerAddress - 1; + } else { + goto NotSetBackToBack; + } + + // + // We do not support the PCI devices which connected under + // PCI-PCI bridge. + // + + if (BusHandler->BusNumber == 0) { + + if (PciConfigMapped->Status & 0x80) { + + // + // This device is back-to-back capable. + // We can map the memory space of this device as + // back-to-back available. + // Set flag to indicate setting started. + // + + if (!HalpPCIBackToBackReg0Start) { + HalpPCIBackToBackReg0Start = 1; + + } else if (HalpPCIBackToBackReg0Start && !HalpPCIBackToBackReg0Open) { + HalpPCIBackToBackReg1Start = 1; + + } + + // + // BUGBUG: Some pci drivers assign its memory space by itself. + // This means that we can not control the memory address of + // such device by MemoryLimit value. So, we can not enable the + // following codes now. + // N.B. following code does not finished. + // + +// if (!HalpFoundUncapablePCIDevice) { +// +// // +// // Uncapable device not mapped yet, so we can expand +// // back-to-back space. +// // We expand back-to-back space until uncapable device +// // is found. +// // +// +// if (back-to-back reg0 == initialize value){ +// HalpSetBackToBackRegister(BaseAddress, Length, (ULONG)0); +// } else { +// back-to-back reg0 =+ add this memory range; +// MemoryLimit = the BaseAddress of this device; +// } +// +// if (PciConfigMapped->BaseClass == 0x03 +// || (PciConfigMapped->BaseClass == 0x00 +// && PciConfigMapped->SubClass == 0x01)) { +// HalpPCINumberOfMappedGA++; +// } +// +// } else { + + if (HalpNumberOfPCIGA > 1) { + + // + // There are some PCI-GA cards. + // If this is PCI-GA, then set to back-to-back, + // else we do not map. + // + + if (PciConfigMapped->BaseClass == 0x03 + || (PciConfigMapped->BaseClass == 0x00 + && PciConfigMapped->SubClass == 0x01)) { + + switch (HalpPCINumberOfMappedGA) { + + case 0: + + // + // We need set PCI-GA to both back-to-back space. + // The control reach here, it indicates PCI-GA + // not mapped to back-to-back space yet. + // + + HalpSetBackToBackRegister(BaseAddress, Length, (ULONG)0); + HalpPCIBackToBackReg0Open = 0; + break; + + case 1: + + // + // Control is transfered to this routine when one PCI-GA + // is already mapped. This means that reg0 had already used. + // We use reg1. + // + + HalpSetBackToBackRegister(BaseAddress, Length, (ULONG)1); + HalpPCIBackToBackReg1Open = 0; + + } + + HalpPCINumberOfMappedGA++; + } + + } else { + + // + // There is only one-card as PCI-GA. + // We need set PCI-GA to back-to-back. + // If this is GA and reg0 is opened, then use reg0. + // If this is GA and reg0 is closeed, then use reg1. + // + + if (PciConfigMapped->BaseClass == 0x03 + || (PciConfigMapped->BaseClass == 0x00 + && PciConfigMapped->SubClass == 0x01)) { + + if (HalpPCIBackToBackReg0Open) { + HalpSetBackToBackRegister(BaseAddress, Length, (ULONG)0); + HalpPCIBackToBackReg0Open = 0; + + } else { + HalpSetBackToBackRegister(BaseAddress, Length, (ULONG)1); + HalpPCIBackToBackReg1Open = 0; + + } + + HalpPCINumberOfMappedGA++; + + } else { + + // + // We can set only if reg0 or reg1 is not used. + // + + if (HalpPCIBackToBackReg0Open) { + HalpSetBackToBackRegister(BaseAddress, Length, (ULONG)0); + HalpPCIBackToBackReg0Open = 0; + + } else if (HalpPCIBackToBackReg1Open){ + HalpSetBackToBackRegister(BaseAddress, Length, (ULONG)1); + HalpPCIBackToBackReg1Open = 0; + + } + } + } +// } + + } else { + + // + // This is back-to-back uncapable. + // + + HalpFoundUncapablePCIDevice = 1; + + // + // if device is back-to-back uncapableˇ¤map only GA. + // + + if (PciConfigMapped->BaseClass == 0x03 + || (PciConfigMapped->BaseClass == 0x00 + && PciConfigMapped->SubClass == 0x01)) { + + // + // In case of two or more cards are connected, the + // process is depend on the number of PCI-GA which + // already mapped. + // But we do not need to map 3rd PCI-GA or more. + // + + if (HalpNumberOfPCIGA > 1) { + + switch (HalpPCINumberOfMappedGA) { + + case 0: + + // + // Re-nitialize all values to void already settings, + // and use reg0 + // + + HalpPCIBackToBackReg0Start = 1; + HalpPCIBackToBackReg1Start = 0; + HalpPCIBackToBackReg0Open = 1; + HalpPCIBackToBackReg1Open = 1; + HalpSetBackToBackRegister(BaseAddress, Length, (ULONG)0); + break; + + case 1: + + // + // Control is transfered to this routine when one PCI-GA + // is already mapped. This means that reg0 had already used. + // We use reg1. + // + // N.B. We do not know reg0 is opened or closed, so close + // reg0 here. + // (ex) 1st mapped ... capable = 1, not GA + // 2nd mapped ... capable = 0, GA + // + + HalpPCIBackToBackReg0Open = 0; + HalpPCIBackToBackReg1Start = 1; + HalpSetBackToBackRegister(BaseAddress, Length, (ULONG)1); + + } + + } else { + + // + // There is only one-card as PCI-GA. + // If back-to-back reg0 not being useed, use reg0, + // else close the space of reg0 and use reg1. + // (Also when reg0 is closed, use reg1) + // + + if (!HalpPCIBackToBackReg0Start) { + HalpPCIBackToBackReg0Start = 1; + HalpSetBackToBackRegister(BaseAddress, Length, (ULONG)0); + + } else { + HalpPCIBackToBackReg0Open = 0; + HalpPCIBackToBackReg1Start = 1; + HalpSetBackToBackRegister(BaseAddress, Length, (ULONG)1); + + } + } + } + + // + // if being to set to back-to-back register, we have to close. + // + + if (HalpPCIBackToBackReg0Start && HalpPCIBackToBackReg0Open) { + HalpPCIBackToBackReg0Open = 0; + + } else if (HalpPCIBackToBackReg1Start && HalpPCIBackToBackReg1Open) { + HalpPCIBackToBackReg1Open = 0; + + } + + } + + } + +NotSetBackToBack: + KiReleaseSpinLock(&HalpPCIBackToBackLock); + +} + +VOID +HalpSetBackToBackRegister( + IN ULONG BaseAddress, + IN ULONG Length, + IN ULONG Register + ) +/*++ + +Routine Description: + + This function sets memory space of PCI device to Fast Back-to-back register. + +Arguments: + + BaseAddress - Supplies the address which to be mapped with back-to-back. + Length - Supplies the length which to be mapped with back-to-back. + Register - Supplies the back-to-back register number. + +Return Value: + + None. + +--*/ + +{ + ULONG Mask; + + // + // make mask value + // + + Mask = ~(Length - 1); + + // + // set to back-to-back register + // + +#if DBG + DbgPrint(" set back-to-back register.\n"); + DbgPrint(" - Register ................ %d\n", Register); + DbgPrint(" - Address ................. 0x%08x\n", BaseAddress); + DbgPrint(" - Mask .................... 0x%08x\n", Mask); +#endif + + WRITE_REGISTER_ULONG( + &DMA_CONTROL->PCIFastBackToBack[Register].Address, + BaseAddress + ); + + WRITE_REGISTER_ULONG( + &DMA_CONTROL->PCIFastBackToBack[Register].Mask, + Mask + ); + +} + +ULONG +HalpGetNumberOfPCIGA( + IN ULONG NumberBuses + ) +/*++ + +Routine Description: + + This function determines the number of PCI-GAs. + And initialize Fast Back-to-back register. + +Arguments: + + NumberBuses - Supplies the number of the PCI-buses. + +Return Value: + + number of PCI-GA. + +--*/ + +{ + UCHAR iBuffer[PCI_COMMON_HDR_LENGTH]; + ULONG Bus; + ULONG Slot; + ULONG Function; + PBUS_HANDLER BusHandler; + PCI_SLOT_NUMBER SlotNumber; + PPCI_COMMON_CONFIG PciData; + ULONG Count; + ULONG Register; + USHORT commandValue; + + Count = 0; + PciData = (PPCI_COMMON_CONFIG)&iBuffer; + + // + // BUGBUG: Fast Back-to-back transaction can be used + // only bus number zero on this version. + // PCI devices connected on bus number 1 or more will + // be available with back-to-back on future. + // + + NumberBuses = 1; + + // + // Look for PCI controllers which have known work-arounds, and make + // sure they are applied. + // + + SlotNumber.u.bits.Reserved = 0; + for (Bus = 0; Bus < NumberBuses; Bus++) { + BusHandler = HalpHandlerForBus (PCIBus, Bus); + + for (Slot = 0; Slot < PCI_MAX_DEVICES; Slot++) { + SlotNumber.u.bits.DeviceNumber = Slot; + + for (Function = 0; Function < PCI_MAX_FUNCTION; Function++) { + SlotNumber.u.bits.FunctionNumber = Function; + + // + // Read PCI configuration information + // + + HalpReadPCIConfig (BusHandler, SlotNumber, PciData, 0, PCI_COMMON_HDR_LENGTH); + + // + // Check for chips with known work-arounds to apply + // + + if (PciData->BaseClass == 0x03 + || (PciData->BaseClass == 0x00 && PciData->SubClass == 0x01)){ + + // + // This is Graphics Adapter. Inclement count. + // + + Count++; + } + + } // next PCI function + + } // next PCI slot + + } // next PCI bus + +#if DBG + DbgPrint(" number of PCI-GA.\n"); + DbgPrint(" - number of PCI-GA ........ %d\n", Count); +#endif + + // + // Initialize Fast Back-to-back register. + // + + for (Register = 0; Register < 2; Register++) { + WRITE_REGISTER_ULONG( + &DMA_CONTROL->PCIFastBackToBack[Register].Address, + INIT_VALUE_OF_BACK_TO_BACK_ADDR + ); + + WRITE_REGISTER_ULONG( + &DMA_CONTROL->PCIFastBackToBack[Register].Mask, + INIT_VALUE_OF_BACK_TO_BACK_MASK + ); + } + + commandValue = READ_REGISTER_USHORT(&DMA_CONTROL->PCICommand); + WRITE_REGISTER_USHORT(&DMA_CONTROL->PCICommand, (commandValue & ~0x0200)); + + return Count; + +} |