diff options
Diffstat (limited to 'private/ntos/nthals/extender/pci/bus.c')
-rw-r--r-- | private/ntos/nthals/extender/pci/bus.c | 670 |
1 files changed, 670 insertions, 0 deletions
diff --git a/private/ntos/nthals/extender/pci/bus.c b/private/ntos/nthals/extender/pci/bus.c new file mode 100644 index 000000000..bd6e3aaf5 --- /dev/null +++ b/private/ntos/nthals/extender/pci/bus.c @@ -0,0 +1,670 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + bus.c + +Abstract: + + +Author: + + Ken Reneris (kenr) March-13-1885 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "pciport.h" + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,PcipCheckBus) +#pragma alloc_text(PAGE,PciCtlCheckDevice) +#pragma alloc_text(PAGE,PcipCrackBAR) +#pragma alloc_text(PAGE,PcipVerifyBarBits) +#pragma alloc_text(PAGE,PcipGetBarBits) +#pragma alloc_text(PAGE,PcipFindDeviceData) +#endif + + +VOID +PcipCheckBus ( + PPCI_PORT PciPort, + BOOLEAN Initialize + ) +{ + NTSTATUS Status; + PBUS_HANDLER Handler; + PCI_SLOT_NUMBER SlotNumber; + ULONG Device, Function; + PPCIBUSDATA PciBusData; + PPCI_COMMON_CONFIG PciData; + UCHAR buffer[PCI_COMMON_HDR_LENGTH]; + BOOLEAN BusCheck, SkipDevice; + PDEVICE_DATA DeviceData; + PDEVICE_HANDLER_OBJECT DeviceHandler; + ULONG ObjectSize; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE Handle; + PSINGLE_LIST_ENTRY *Link; + BOOLEAN State; + POWER_STATE PowerState; + ULONG BufferSize; + + PAGED_CODE(); + + Handler = PciPort->Handler; + BusCheck = FALSE; + PciBusData = (PPCIBUSDATA) (Handler->BusData); + PciData = (PPCI_COMMON_CONFIG) buffer; + + // + // We may be removing references to this bus handler, so add + // a reference now + // + + HalReferenceBusHandler (Handler); + + // + // Check for any obslete device data entries + // + + ExAcquireFastMutex (&PcipMutex); + + Link = &PciPort->ValidSlots.Next; + while (*Link) { + DeviceData = CONTAINING_RECORD (*Link, DEVICE_DATA, Next); + if (!DeviceData->Valid) { + + // + // Remove it from the list + // + + *Link = (*Link)->Next; + BusCheck = TRUE; + PciPort->NoValidSlots -= 1; + HalDereferenceBusHandler (Handler); + + // + // Dereference each obsolete device handler object once. This + // counters the original reference made to the device handler + // object when the object was created by this driver. + // + + DeviceHandler = DeviceData2DeviceHandler(DeviceData); + ObDereferenceObject (DeviceHandler); + continue; + } + + Link = & ((*Link)->Next); + } + + ExReleaseFastMutex (&PcipMutex); + + + // + // Check the bus for new devices + // + + SlotNumber.u.AsULONG = 0; + for (Device=0; Device < PCI_MAX_DEVICES; Device++) { + SlotNumber.u.bits.DeviceNumber = Device; + for (Function=0; Function < PCI_MAX_FUNCTION; Function++) { + SlotNumber.u.bits.FunctionNumber = Function; + + // + // Read in the device id + // + + PciBusData->ReadConfig ( + Handler, + SlotNumber, + PciData, + 0, + PCI_COMMON_HDR_LENGTH + ); + + // + // If not valid, skip it + // + + if (PciData->VendorID == PCI_INVALID_VENDORID || + PciData->VendorID == 0) { + break; + } + + // + // Check to see if this known configuration type + // + + switch (PCI_CONFIG_TYPE(PciData)) { + case PCI_DEVICE_TYPE: + case PCI_BRIDGE_TYPE: + SkipDevice = FALSE; + break; + default: + SkipDevice = TRUE; + break; + } + + if (SkipDevice) { + break; + } + + ExAcquireFastMutex (&PcipMutex); + DeviceData = PcipFindDeviceData (PciPort, SlotNumber); + + if (DeviceData == NULL) { + + // + // Initialize the object attributes that will be used to create the + // Device Handler Object. + // + + InitializeObjectAttributes( + &ObjectAttributes, + NULL, + 0, + NULL, + NULL + ); + + ObjectSize = PcipDeviceHandlerObjectSize + sizeof (DEVICE_DATA); + + // + // Create the object + // + + Status = ObCreateObject( + KernelMode, + *IoDeviceHandlerObjectType, + &ObjectAttributes, + KernelMode, + NULL, + ObjectSize, + 0, + 0, + (PVOID *) &DeviceHandler + ); + + if (NT_SUCCESS(Status)) { + RtlZeroMemory (DeviceHandler, ObjectSize); + + DeviceHandler->Type = (USHORT) *IoDeviceHandlerObjectType; + DeviceHandler->Size = (USHORT) ObjectSize; + DeviceHandler->SlotNumber = SlotNumber.u.AsULONG; + + // + // Get a reference to the object + // + + Status = ObReferenceObjectByPointer( + DeviceHandler, + FILE_READ_DATA | FILE_WRITE_DATA, + *IoDeviceHandlerObjectType, + KernelMode + ); + } + + if (NT_SUCCESS(Status)) { + + // + // Insert it into the object table + // + + Status = ObInsertObject( + DeviceHandler, + NULL, + FILE_READ_DATA | FILE_WRITE_DATA, + 0, + NULL, + &Handle + ); + } + + + if (!NT_SUCCESS(Status)) { + + // + // Object not created correctly + // + + ExReleaseFastMutex (&PcipMutex); + break; + } + + ZwClose (Handle); + + + // + // Intialize structure to track device + // + + DebugPrint ((8, "PCI: adding slot %x (for device %04x-%04x)\n", + SlotNumber, + PciData->VendorID, + PciData->DeviceID + )); + + DeviceData = DeviceHandler2DeviceData (DeviceHandler); + + // + // Get BAR decode bits which are supported + // + + Status = PcipGetBarBits (DeviceData, PciPort->Handler); + + if (NT_SUCCESS(Status)) { + + // + // Add it to the list of devices for this bus + // + + DeviceHandler->BusHandler = Handler; + HalReferenceBusHandler (Handler); + + DeviceData->Valid = TRUE; + PciPort->NoValidSlots += 1; + PushEntryList (&PciPort->ValidSlots, &DeviceData->Next); + BusCheck = TRUE; + } + + // + // Obtain an extra reference to the device handler for + // sending some DeviceControls + // + + ObReferenceObjectByPointer ( + DeviceHandler, + FILE_READ_DATA | FILE_WRITE_DATA, + *IoDeviceHandlerObjectType, + KernelMode + ); + + // + // If we are installing the initail bus support, then + // all devices are installed as locked & powered up. + // If this is a dynamically located new device, then + // the device is started as unlocked & powered down. + // + + if (Initialize) { + + // + // Set initial state as locked + // + + State = TRUE; + BufferSize = sizeof (State); + HalDeviceControl ( + DeviceHandler, + NULL, + BCTL_SET_LOCK, + &State, + &BufferSize, + NULL, + NULL + ); + + // + // Set initial power state as Powered Up + // + + PowerState = PowerUp; + BufferSize = sizeof (PowerState); + HalDeviceControl ( + DeviceHandler, + NULL, + BCTL_SET_POWER, + (PVOID) &PowerState, + &BufferSize, + NULL, + NULL + ); + } + + // + // Free once + // + + ObDereferenceObject (DeviceHandler); + } + + ExReleaseFastMutex (&PcipMutex); + } + } + + // + // Undo reference to bus handler from top of function + // + + HalDereferenceBusHandler (Handler); + + // + // Do we need to notify the system buscheck callback? + // + + if (BusCheck) { + ExNotifyCallback ( + PciHalCallbacks.BusCheck, + (PVOID) PciPort->Handler->InterfaceType, + (PVOID) PciPort->Handler->BusNumber + ); + } + +} + +NTSTATUS +PcipVerifyBarBits ( + PDEVICE_DATA DeviceData, + PBUS_HANDLER Handler + ) +{ + NTSTATUS Status; + + PAGED_CODE (); + + Status = STATUS_SUCCESS; + if (!DeviceData->BARBitsSet) { + + DeviceData->BARBitsSet = TRUE; + Status = PcipGetBarBits (DeviceData, Handler); + + if (!NT_SUCCESS(Status)) { + DeviceData->BARBitsSet = FALSE; + } + } + + return Status; +} + + + +NTSTATUS +PcipGetBarBits ( + PDEVICE_DATA DeviceData, + PBUS_HANDLER Handler + ) +{ + PPCIBUSDATA PciBusData; + PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1]; + ULONG NoBaseAddress, RomIndex; + PULONG BaseAddress2[PCI_TYPE0_ADDRESSES + 1]; + ULONG NoBaseAddress2, RomIndex2; + ULONG j; + PPCI_COMMON_CONFIG PciData; + UCHAR buffer[PCI_COMMON_HDR_LENGTH]; + LONGLONG bits, base, length, max; + BOOLEAN BrokenDevice; + PCI_SLOT_NUMBER SlotNumber; + + PAGED_CODE (); + + PciData = (PPCI_COMMON_CONFIG) buffer; + PciBusData = (PPCIBUSDATA) (Handler->BusData); + SlotNumber.u.AsULONG = DeviceDataSlot(DeviceData); + + // + // Get the device's current configuration + // + + if (!DeviceData->CurrentConfig) { + DeviceData->CurrentConfig = (PPCI_COMMON_CONFIG) + ExAllocatePoolWithTag (NonPagedPool, PCI_COMMON_HDR_LENGTH, 'cICP'); + + if (!DeviceData->CurrentConfig) { + return STATUS_INSUFFICIENT_RESOURCES; + } + } + + PciBusData->ReadConfig ( + Handler, + SlotNumber, + PciData, + 0, + PCI_COMMON_HDR_LENGTH + ); + + RtlCopyMemory (DeviceData->CurrentConfig, PciData, PCI_COMMON_HDR_LENGTH); + + // + // Get BaseAddress array, and check if ROM was originally enabled + // + + DeviceData->EnableRom = PcipCalcBaseAddrPointers ( + DeviceData, + PciData, + BaseAddress, + &NoBaseAddress, + &RomIndex + ); + + // + // If the device's current configuration isn't enabled, then set for + // not powered on + // + + if (!(PciData->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE))) { + DeviceData->Power = FALSE; + DeviceData->Locked = FALSE; + } + + // + // Check to see if there are any BARs + // + + for (j=0; j < NoBaseAddress; j++) { + DeviceData->BARBits[j] = 0; + if (*BaseAddress[j]) { + DeviceData->BARBitsSet = TRUE; + } + } + + // + // If not BarBitsSet, then don't attempt to determine the possible + // device settings now + // + + if (!DeviceData->BARBitsSet) { + DebugPrint ((2, "PCI: ghost added device %04x-%04x in slot %x\n", + PciData->VendorID, + PciData->DeviceID, + SlotNumber)); + + return STATUS_SUCCESS; + } + + // + // Set BARs to all on, and read them back + // + + DebugPrint ((3, "PCI: getting valid BAR bits on device %04x-%04x in slot %x\n", + PciData->VendorID, + PciData->DeviceID, + SlotNumber + )); + + + PciData->Command &= ~(PCI_ENABLE_IO_SPACE | + PCI_ENABLE_MEMORY_SPACE | + PCI_ENABLE_BUS_MASTER); + + for (j=0; j < NoBaseAddress; j++) { + *BaseAddress[j] = 0xFFFFFFFF; + } + + PciBusData->WriteConfig ( + Handler, + SlotNumber, + PciData, + 0, + PCI_COMMON_HDR_LENGTH + ); + + PciBusData->ReadConfig ( + Handler, + SlotNumber, + PciData, + 0, + PCI_COMMON_HDR_LENGTH + ); + + + PcipCalcBaseAddrPointers ( + DeviceData, + PciData, + BaseAddress, + &NoBaseAddress, + &RomIndex + ); + + PcipCalcBaseAddrPointers ( + DeviceData, + DeviceData->CurrentConfig, + BaseAddress2, + &NoBaseAddress2, + &RomIndex2 + ); + + + for (j=0; j < NoBaseAddress; j++) { + if (*BaseAddress[j]) { + + // + // Remember the original bits + // + + DeviceData->BARBits[j] = *BaseAddress[j]; + if (Is64BitBaseAddress(*BaseAddress[j])) { + DeviceData->BARBits[j+1] = *BaseAddress[j+1]; + } + + // + // Crack bits & check for BrokenDevice + // + + BrokenDevice = PcipCrackBAR ( + BaseAddress2, + DeviceData->BARBits, + &j, + &base, + &length, + &max + ); + + if (BrokenDevice) { + DeviceData->BrokenDevice = TRUE; + } + } + } + + if (DeviceData->BrokenDevice) { + DebugPrint ((2, "PCI: added defective device %04x-%04x in slot %x\n", + PciData->VendorID, + PciData->DeviceID, + SlotNumber)); + + } else { + DebugPrint ((2, "PCI: added device %04x-%04x in slot %x\n", + PciData->VendorID, + PciData->DeviceID, + SlotNumber)); + } + + return STATUS_SUCCESS; +} + +PDEVICE_DATA +PcipFindDeviceData ( + IN PPCI_PORT PciPort, + IN PCI_SLOT_NUMBER SlotNumber + ) +{ + PDEVICE_DATA DeviceData; + PSINGLE_LIST_ENTRY Link; + PDEVICE_HANDLER_OBJECT DeviceHandler; + + PAGED_CODE (); + + for (Link = PciPort->ValidSlots.Next; Link; Link = Link->Next) { + DeviceData = CONTAINING_RECORD (Link, DEVICE_DATA, Next); + DeviceHandler = DeviceData2DeviceHandler(DeviceData); + if (DeviceHandler->SlotNumber == SlotNumber.u.AsULONG) { + break; + } + } + + if (!Link) { + return NULL; + } + + return DeviceData; +} + + +BOOLEAN +PcipCrackBAR ( + IN PULONG *BaseAddress, + IN PULONG BarBits, + IN OUT PULONG Index, + OUT PLONGLONG pbase, + OUT PLONGLONG plength, + OUT PLONGLONG pmax + ) +{ + LONGLONG base, length, max, bits; + BOOLEAN Status; + + PAGED_CODE (); + + // + // Get initial base & bits + // + + base = *BaseAddress[*Index]; + bits = BarBits[*Index]; + + if (Is64BitBaseAddress(base)) { + *Index += 1; + base |= ((LONGLONG) *BaseAddress[*Index]) << 32; + bits |= ((LONGLONG) BarBits[*Index]) << 32; + } + + // + // Scan for first set bit, that's the BARs length and alignment + // + + length = (base & PCI_ADDRESS_IO_SPACE) ? 1 << 2 : 1 << 4; + while (!(bits & length) && length) { + length <<= 1; + } + + // + // Scan for last set bit, that's that BARs max address + 1 + // + + for (max = length; bits & max; max <<= 1) ; + max -= 1; + + // + // Check for defective BAR + // + + Status = (bits & ~max) ? TRUE : FALSE; + + // + // return results + // + + *pbase = base; + *plength = length; + *pmax = max; + return Status; +} |