NT4/private/ntos/nthals/halflex/xxpcisup.c
2020-09-30 17:12:29 +02:00

2392 lines
60 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (C) 1989-1995 Microsoft Corporation
Copyright (C) 1994,1995 Digital Equipment Corporation
Module Name:
pcisup.c
Abstract:
Platform-independent PCI bus routines
Environment:
Kernel mode
--*/
#include "halp.h"
#include "pci.h"
#include "pcip.h"
typedef ULONG (*FncConfigIO) (
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
typedef struct {
FncConfigIO ConfigRead[3];
FncConfigIO ConfigWrite[3];
} CONFIG_HANDLER, *PCONFIG_HANDLER;
//
// Define PCI slot validity
//
typedef enum _VALID_SLOT {
InvalidBus = 0,
InvalidSlot,
ValidSlot
} VALID_SLOT;
//
// Local prototypes for routines supporting PCI bus handler routines
//
ULONG
HalpGetPCIData (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN ULONG Slot,
IN PUCHAR Buffer,
IN ULONG Offset,
IN ULONG Length
);
ULONG
HalpSetPCIData (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN ULONG Slot,
IN PUCHAR Buffer,
IN ULONG Offset,
IN ULONG Length
);
NTSTATUS
HalpAdjustPCIResourceList (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
);
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
);
VOID
HalpReadPCIConfig (
IN PBUS_HANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
);
VOID
HalpWritePCIConfig (
IN PBUS_HANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
);
VALID_SLOT
HalpValidPCISlot (
IN PBUS_HANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot
);
VOID
HalpPCIConfig (
IN PBUS_HANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PUCHAR Buffer,
IN ULONG Offset,
IN ULONG Length,
IN FncConfigIO *ConfigIO
);
ULONG HalpPCIReadUlong (
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
ULONG HalpPCIReadUchar (
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
ULONG HalpPCIReadUshort (
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
ULONG HalpPCIWriteUlong (
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
ULONG HalpPCIWriteUchar (
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
ULONG HalpPCIWriteUshort (
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
VOID
HalpPCILine2PinNop (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN PCI_SLOT_NUMBER SlotNumber,
IN PPCI_COMMON_CONFIG PciNewData,
IN PPCI_COMMON_CONFIG PciOldData
);
VOID
HalpPCIPin2LineNop (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN PCI_SLOT_NUMBER SlotNumber,
IN PPCI_COMMON_CONFIG PciData
);
#if DBG
BOOLEAN
HalpValidPCIAddr(
IN PBUS_HANDLER BusHandler,
IN PHYSICAL_ADDRESS BAddr,
IN ULONG Length,
IN ULONG AddressSpace
);
#endif
//
// Local prototypes of functions that are not built for Alpha AXP firmware
//
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
);
#if DBG
VOID
HalpTestPci (
ULONG
);
#endif
//
// Pragmas to assign functions to different kinds of pages.
//
#if !defined(AXP_FIRMWARE)
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,HalpInitializePCIBus)
#pragma alloc_text(INIT,HalpAllocateAndInitPCIBusHandler)
#pragma alloc_text(INIT,HalpRegisterPCIInstallHandler )
#pragma alloc_text(INIT,HalpDefaultPCIInstallHandler )
#pragma alloc_text(INIT,HalpDeterminePCIDevicesPresent )
#pragma alloc_text(PAGE,HalpAssignPCISlotResources)
#pragma alloc_text(PAGE,HalpAdjustPCIResourceList)
#endif // ALLOC_PRAGMA
#endif // !defined(AXP_FIRMWARE)
#ifdef AXP_FIRMWARE
#define ExFreePool(PoolData)
#pragma alloc_text(DISTEXT, HalpInitializePCIBus )
#pragma alloc_text(DISTEXT, HalpAllocateAndInitPCIBusHandler)
#pragma alloc_text(DISTEXT, HalpRegisterPCIInstallHandler )
#pragma alloc_text(DISTEXT, HalpDefaultPCIInstallHandler )
#pragma alloc_text(DISTEXT, HalpDeterminePCIDevicesPresent )
#pragma alloc_text(DISTEXT, HalpGetPCIData )
#pragma alloc_text(DISTEXT, HalpSetPCIData )
#pragma alloc_text(DISTEXT, HalpReadPCIConfig )
#pragma alloc_text(DISTEXT, HalpWritePCIConfig )
#pragma alloc_text(DISTEXT, HalpValidPCISlot )
#if DBG
#pragma alloc_text(DISTEXT, HalpValidPCIAddr )
#endif
#pragma alloc_text(DISTEXT, HalpPCIConfig )
#pragma alloc_text(DISTEXT, HalpPCIReadUchar )
#pragma alloc_text(DISTEXT, HalpPCIReadUshort )
#pragma alloc_text(DISTEXT, HalpPCIReadUlong )
#pragma alloc_text(DISTEXT, HalpPCIWriteUchar )
#pragma alloc_text(DISTEXT, HalpPCIWriteUshort )
#pragma alloc_text(DISTEXT, HalpPCIWriteUlong )
#pragma alloc_text(DISTEXT, HalpAssignPCISlotResources)
#pragma alloc_text(DISTEXT, HalpAdjustPCIResourceList)
#endif // AXP_FIRMWARE
//
// Globals
//
KSPIN_LOCK HalpPCIConfigLock;
BOOLEAN PCIInitialized = FALSE;
ULONG PCIMaxLocalDevice;
ULONG PCIMaxDevice;
ULONG PCIMaxBus;
PINSTALL_BUS_HANDLER PCIInstallHandler = HalpDefaultPCIInstallHandler;
CONFIG_HANDLER PCIConfigHandlers = {
{
HalpPCIReadUlong, // 0
HalpPCIReadUchar, // 1
HalpPCIReadUshort // 2
},
{
HalpPCIWriteUlong, // 0
HalpPCIWriteUchar, // 1
HalpPCIWriteUshort // 2
}
};
UCHAR PCIDeref[4][4] = { {0,1,2,2},{1,1,1,1},{2,1,2,2},{1,1,1,1} };
WCHAR rgzMultiFunctionAdapter[] = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter";
WCHAR rgzConfigurationData[] = L"Configuration Data";
WCHAR rgzIdentifier[] = L"Identifier";
WCHAR rgzPCIIndetifier[] = L"PCI";
#define Is64BitBaseAddress(a) \
(((a & PCI_ADDRESS_IO_SPACE) == 0) && \
((a & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT))
VOID
HalpInitializePCIBus (
VOID
)
/*++
Routine Description:
The function intializes global PCI bus state from the registry.
The Arc firmware is responsible for building configuration information
about the number of PCI buses on the system and nature (local vs. secondary
- across a PCI-PCI bridge) of the each bus. This state is held in
PCIRegInfo.
The maximum virtual slot number on the local (type 0 config cycle)
PCI bus is registered here, based on the machine dependent define
PCI_MAX_LOCAL_DEVICE. This state is carried in PCIMaxLocalDevice.
The maximum number of virtual slots on a secondary bus is fixed by the
PCI Specification and is represented by PCI_MAX_DEVICES. This
state is held in PCIMaxDevice.
Arguments:
None.
Return Value:
None.
--*/
{
#if !defined(AXP_FIRMWARE)
//
// x86 Hal's can query the registry, while on Alpha pltforms we cannot.
// So we let the ARC firmware actually configure the bus/bridges.
//
PCI_SLOT_NUMBER SlotNumber;
ULONG DeviceNumber;
ULONG FunctionNumber;
PCI_COMMON_CONFIG CommonConfig;
ULONG BusNumber;
ULONG ibus;
PBUS_HANDLER Bus0;
//
// Has the PCI bus already been initialized?
//
if (PCIInitialized) {
return;
}
//
// Intialize PCI configuration to the maximum configuration for starters.
//
PCIMaxLocalDevice = PCI_MAX_LOCAL_DEVICE;
PCIMaxDevice = PCI_MAX_DEVICES - 1;
//
// Unless there exists any PCI-to-PCI bridges, there will only be 1
// bus.
//
PCIMaxBus = 1;
//
// For each "local" PCI bus present, allocate a handler structure and
// fill in the dispatch functions
//
// After we determine how many "remote" PCI buses are present, we will
// add them.
//
for (ibus = 0; ibus < PCIMaxBus; ibus++) {
//
// If handler not already built, do it now
//
if (!HaliHandlerForBus (PCIBus, ibus)) {
HalpAllocateAndInitPCIBusHandler (ibus);
}
}
//
// Initialize the slot number struct.
//
SlotNumber.u.AsULONG = 0;
//
// Loop through each device.
//
Bus0 = HaliHandlerForBus(PCIBus, 0);
for (DeviceNumber = 0; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++) {
SlotNumber.u.bits.DeviceNumber = DeviceNumber;
//
// Loop through each function.
//
for (FunctionNumber = 0; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++) {
SlotNumber.u.bits.FunctionNumber = FunctionNumber;
//
// Read the device's configuration space.
//
HalpReadPCIConfig(Bus0,
SlotNumber,
&CommonConfig,
0,
PCI_COMMON_HDR_LENGTH);
//
// No device exists at this device/function number.
//
if (CommonConfig.VendorID == PCI_INVALID_VENDORID) {
//
// If this is the first function number, then break, because
// we know a priori there will not be any devices on the
// other function numbers.
//
if (FunctionNumber == 0) {
break;
}
//
// Check the next function number.
//
continue;
}
//
// A PCI-to-PCI bridge has been discovered.
//
if (CommonConfig.BaseClass == 0x06 &&
CommonConfig.SubClass == 0x04 &&
CommonConfig.ProgIf == 0x00) {
//
// Get the subordinate bus number (which is the highest
// numbered bus this bridge will forward to) and add 1.
//
BusNumber = CommonConfig.u.type1.SubordinateBus + 1;
//
// The maximum subordinate across the local bus is the
// maximum number of busses.
//
if (PCIMaxBus < BusNumber) {
PCIMaxBus = BusNumber;
}
}
//
// If this is not a multi-function device then break out now.
//
if ((CommonConfig.HeaderType & PCI_MULTIFUNCTION) == 0) {
break;
}
}
}
//
// For each additional PCI bus present, allocate a handler structure and
// fill in the dispatch functions. If there are no additional
// PCI buses, (i.e., no PCI-PCI bridges were found), this loop
// will exit before a single iteration.
//
for (ibus = 1; ibus < PCIMaxBus; ibus++) {
//
// If handler not already built, do it now
//
if (!HaliHandlerForBus (PCIBus, ibus)) {
HalpAllocateAndInitPCIBusHandler (ibus);
}
}
KeInitializeSpinLock (&HalpPCIConfigLock);
PCIInitialized = TRUE;
#if DBG
HalpTestPci (0);
#endif
#else
PCIMaxLocalDevice = PCI_MAX_LOCAL_DEVICE;
PCIMaxDevice = PCI_MAX_DEVICES - 1;
PCIMaxBus = PCI_MAX_BUSSES;
//
// Note:
// Firmware will allocate bus handlers during
// PCI configuration.
//
KeInitializeSpinLock (&HalpPCIConfigLock);
PCIInitialized = TRUE;
#endif // !AXP_FIRMWARE
}
PBUS_HANDLER
HalpAllocateAndInitPCIBusHandler (
IN ULONG BusNo
)
{
PBUS_HANDLER Bus;
HaliRegisterBusHandler (
PCIBus, // Interface type
PCIConfiguration, // Has this configuration space
BusNo, // Bus Number
Internal, // child of this bus
0, // and number
sizeof (PCIPBUSDATA), // sizeof bus specific buffer
PCIInstallHandler, // PCI install handler
&Bus); // Bushandler return
return Bus;
}
NTSTATUS
HalpDefaultPCIInstallHandler(
IN PBUS_HANDLER Bus
)
{
PPCIPBUSDATA BusData;
//
// Fill in PCI handlers
//
Bus->GetBusData = (PGETSETBUSDATA) HalpGetPCIData;
Bus->SetBusData = (PGETSETBUSDATA) HalpSetPCIData;
Bus->AdjustResourceList = (PADJUSTRESOURCELIST) HalpAdjustPCIResourceList;
Bus->AssignSlotResources = (PASSIGNSLOTRESOURCES) HalpAssignPCISlotResources;
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)HalpPCIPin2LineNop;
BusData->CommonData.Line2Pin = (PciLine2Pin)HalpPCILine2PinNop;
// set defaults
//
// ecrfix - if we knew more about the PCI bus at this
// point (e.g., local vs. across bridge, PCI config
// space base QVA, APECS vs. Sable T2/T4 vs. LCA4 vs. ??? config
// cycle type 0 mechanism), we could put this info into
// the "BusData" structure. The nice thing about this is
// that we could eliminate the platform-dependent module
// PCIBUS.C.
//
BusData->MaxDevice = PCI_MAX_DEVICES - 1; // not currently used anywhere
#if !defined(AXP_FIRMWARE)
//
// Perform DevicePresent scan for this bus.
//
HalpDeterminePCIDevicesPresent(Bus);
#endif // !AXP_FIRMWARE
return STATUS_SUCCESS;
}
VOID
HalpRegisterPCIInstallHandler(
IN PINSTALL_BUS_HANDLER MachineSpecificPCIInstallHandler
)
/*++
Routine Description:
The function register's a machine-specific PCI Install Handler.
This allows a specific platform to override the default PCI install
handler, DefaultPCIInstallHandler().
Arguments:
MachineSpecificPCIInstallHandler - Function that provides machine
specific PCI Bus Handler setup.
Return Value:
None.
--*/
{
PCIInstallHandler = MachineSpecificPCIInstallHandler;
return;
}
VOID
HalpDeterminePCIDevicesPresent(
IN PBUS_HANDLER Bus
)
/*++
Routine Description:
The function determines which PCI devices and functions are
present on a given PCI bus. An RTL_BITMAP vector in the bus handler's
PCI-specific BusData is updated to reflect the devices that actually
exist on this bus.
THIS COULD BE DONE IN FIRMWARE!
Arguments:
Bus - BusHandler for the bus to be searched. This bus handler must
have already been allocated and initialized.
Return Value:
None.
--*/
{
PCI_COMMON_CONFIG CommonConfig;
PCI_SLOT_NUMBER Slot;
ULONG DeviceNumber;
ULONG FunctionNumber;
ULONG cnt;
RTL_BITMAP DevicePresent;
PPCIPBUSDATA BusData;
//
// Formally disable DevicePresent checking for this bus.
//
BusData = (PPCIPBUSDATA) Bus->BusData;
BusData->DevicePresent.Buffer = NULL;
//
// Initialize local copy of device present bitmap
// (Can't update bus handler data because we need to probe
// the bus in question.)
//
RtlInitializeBitMap (&DevicePresent,
BusData->DevicePresentBits, 256);
//
// For this bus, probe each possible slot. If no device
// is present than indicate that in the DevicePresent structure.
//
Slot.u.AsULONG = 0;
for( DeviceNumber=0; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++ ){
Slot.u.bits.DeviceNumber = DeviceNumber;
for (FunctionNumber = 0; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
{
Slot.u.bits.FunctionNumber = FunctionNumber;
//
// Read only first ULONG of PCI config space, which
// contains the Vendor ID.
//
// (DevicePresent checking is *not* in effect yet
// for this bus.)
//
HalpReadPCIConfig(Bus,
Slot,
&CommonConfig,
0,
sizeof(ULONG));
//
// See if a device & function is present. If so, set a bit.
//
if (CommonConfig.VendorID != PCI_INVALID_VENDORID) {
cnt = PciBitIndex(Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber);
RtlSetBits (&DevicePresent, cnt, 1);
}
} // end for( FunctionNumber=0; ...
} // end for( DeviceNumber=0; ...
//
// Update bus data now that we know what's present on the bus.
// (DevicePresent checking is now in effect yet for this bus.)
//
BusData->DevicePresent = DevicePresent;
return;
}
ULONG
HalpGetPCIData (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN ULONG Slot,
IN PUCHAR Buffer,
IN ULONG Offset,
IN ULONG Length
)
/*++
Routine Description:
The function returns the PCI bus data for a device.
Arguments:
BusHandler - Registered BUSHANDLER for the target configuration space
RootHandler - Register BUSHANDLER for the orginating HalGetBusData request.
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];
ULONG Len;
PCI_SLOT_NUMBER PciSlot;
if (Length > sizeof (PCI_COMMON_CONFIG)) {
Length = sizeof (PCI_COMMON_CONFIG);
}
Len = 0;
PciData = (PPCI_COMMON_CONFIG) iBuffer;
PciSlot = *((PPCI_SLOT_NUMBER) &Slot);
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, PciSlot, PciData, 0, sizeof(ULONG));
//
// Check for invalid slot
//
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
//
//
// Read this PCI devices slot data
//
Len = PCI_COMMON_HDR_LENGTH;
HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, Len);
//
// Check for invalid slot
//
if (PciData->VendorID == PCI_INVALID_VENDORID ||
PCI_CONFIG_TYPE (PciData) != 0) {
PciData->VendorID = PCI_INVALID_VENDORID;
Len = 2; // only return invalid id
}
//
// 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, PciSlot, Buffer, Offset, Length);
Len += Length;
}
}
return Len;
}
ULONG
HalpSetPCIData (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN ULONG Slot,
IN PUCHAR Buffer,
IN ULONG Offset,
IN ULONG Length
)
/*++
Routine Description:
The function returns the Pci bus data for a device.
Arguments:
BusHandler - Registered BUSHANDLER for the target configuration space
RootHandler - Register BUSHANDLER for the orginating HalSetBusData request.
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];
ULONG Len;
PCI_SLOT_NUMBER PciSlot;
if (Length > sizeof (PCI_COMMON_CONFIG)) {
Length = sizeof (PCI_COMMON_CONFIG);
}
Len = 0;
PciData = (PPCI_COMMON_CONFIG) iBuffer;
PciData2 = (PPCI_COMMON_CONFIG) iBuffer2;
PciSlot = *((PPCI_SLOT_NUMBER) &Slot);
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, PciSlot, PciData, 0, sizeof(ULONG));
if (PciData->VendorID == PCI_INVALID_VENDORID ||
PciData->VendorID == 0x00) {
return 0;
}
} else {
//
// Caller requested to set at least some data within the
// common header.
//
Len = PCI_COMMON_HDR_LENGTH;
HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, Len);
if (PciData->VendorID == PCI_INVALID_VENDORID ||
PciData->VendorID == 0x00 ||
PCI_CONFIG_TYPE (PciData) != 0) {
// no device, or header type unkown
return 0;
}
//
// Copy COMMON_HDR values to buffer2, then overlay callers changes.
//
RtlMoveMemory (iBuffer2, iBuffer, Len);
Len -= Offset;
if (Len > Length) {
Len = Length;
}
RtlMoveMemory (iBuffer2+Offset, Buffer, Len);
#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 configation value changed\n");
DbgBreakPoint ();
}
#endif // DBG
//
// Set new PCI configuration
//
HalpWritePCIConfig (BusHandler, PciSlot, 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, PciSlot, Buffer, Offset, Length);
Len += Length;
}
}
return Len;
}
VOID
HalpPCILine2PinNop (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN PCI_SLOT_NUMBER SlotNumber,
IN PPCI_COMMON_CONFIG PciNewData,
IN PPCI_COMMON_CONFIG PciOldData
)
{
// line-pin mappings not needed on alpha machines
return ;
}
VOID
HalpPCIPin2LineNop (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN PCI_SLOT_NUMBER SlotNumber,
IN PPCI_COMMON_CONFIG PciData
)
{
// line-pin mappings not needed on alpha machines
return ;
}
VOID
HalpReadPCIConfig (
IN PBUS_HANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
)
{
#if 0
if (!HalpValidPCISlot (BusHandler, Slot)) {
//
// Invalid SlotID return no data
//
RtlFillMemory (Buffer, Length, (UCHAR) -1);
return ;
}
HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length,
PCIConfigHandlers.ConfigRead);
#endif // 0
//
// Read the slot, if it's valid.
// Otherwise, return an Invalid VendorId for a invalid slot on an existing bus
// or a null (zero) buffer if we have a non-existant bus.
//
switch (HalpValidPCISlot (BusHandler, Slot))
{
case ValidSlot:
HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length,
PCIConfigHandlers.ConfigRead);
break;
case InvalidSlot:
//
// Invalid SlotID return no data (Invalid Slot ID = 0xFFFF)
//
RtlFillMemory (Buffer, Length, (UCHAR) -1);
break ;
case InvalidBus:
//
// Invalid Bus, return return no data
//
RtlFillMemory (Buffer, Length, (UCHAR) 0);
break ;
}
return;
}
VOID
HalpWritePCIConfig (
IN PBUS_HANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
)
{
if (HalpValidPCISlot (BusHandler, Slot) != ValidSlot) {
//
// Invalid SlotID do nothing
//
return ;
}
HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length,
PCIConfigHandlers.ConfigWrite);
}
VALID_SLOT
HalpValidPCISlot (
IN PBUS_HANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot
)
{
ULONG BusNumber;
PPCIPBUSDATA BusData;
PCI_SLOT_NUMBER Slot2;
PCI_CONFIGURATION_TYPES PciConfigType;
UCHAR HeaderType;
ULONG i, bit;
BusNumber = BusHandler->BusNumber;
BusData = (PPCIPBUSDATA) BusHandler->BusData;
if (Slot.u.bits.Reserved != 0) {
return FALSE;
}
//
// If the initial device probe has been completed and no device
// is present for this slot then simply return invalid slot.
//
bit = PciBitIndex(Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber);
if( ( (BusData->DevicePresent).Buffer != NULL) &&
!RtlCheckBit(&BusData->DevicePresent, bit) ) {
#if HALDBG
DbgPrint( "Config access supressed for bus = %d, device = %d, function = %d\n",
BusNumber,
Slot.u.bits.DeviceNumber,
Slot.u.bits.FunctionNumber );
#endif // HALDBG
return InvalidSlot;
}
//
// Get the config cycle type for the proposed bus.
// (PciConfigTypeInvalid indicates a non-existent bus.)
//
PciConfigType = HalpPCIConfigCycleType(BusNumber);
//
// The number of devices allowed on a local PCI bus may be different
// than that across a PCI-PCI bridge.
//
switch(PciConfigType) {
case PciConfigType0:
if (Slot.u.bits.DeviceNumber > PCIMaxLocalDevice) {
#if HALDBG
DbgPrint("Invalid local PCI Slot %x\n", Slot.u.bits.DeviceNumber);
#endif
return InvalidSlot;
}
break;
case PciConfigType1:
if (Slot.u.bits.DeviceNumber > PCIMaxDevice) {
#if HALDBG
DbgPrint("Invalid remote PCI Slot %x\n", Slot.u.bits.DeviceNumber);
#endif
return InvalidSlot;
}
break;
case PciConfigTypeInvalid:
#if HALDBG
DbgPrint("Invalid PCI Bus %x\n", BusNumber);
#endif
return InvalidBus;
break;
}
//
// Check function number
//
if (Slot.u.bits.FunctionNumber == 0) {
return ValidSlot;
}
//
// 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 InvalidSlot;
}
return ValidSlot;
}
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;
PCI_CFG_CYCLE_BITS PciAddr;
ULONG BusNumber;
BusNumber = BusHandler->BusNumber;
//
// Setup platform-dependent state for configuration space access
//
HalpPCIConfigAddr(BusNumber, Slot, &PciAddr);
//
// Synchronize with PCI config space
//
KeAcquireSpinLock (&HalpPCIConfigLock, &OldIrql);
//
// Do the I/O to PCI configuration space
//
while (Length) {
i = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)];
i = ConfigIO[i] (&PciAddr, Buffer, Offset);
Offset += i;
Buffer += i;
Length -= i;
}
//
// Release spinlock
//
KeReleaseSpinLock (&HalpPCIConfigLock, OldIrql);
return;
}
ULONG
HalpPCIReadUchar (
IN PPCI_CFG_CYCLE_BITS PciCfg,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
ULONG ConfigurationCycleType;
//
// The configuration cycle type is extracted from bits[1:0] of PciCfg.
//
// Since an LCA4 register generates the configuration cycle type
// on the PCI bus, and because Offset bits[1:0] are used to
// generate the PCI byte enables (C/BE[3:0]), clear PciCfg bits [1:0]
// out before adding in Offset.
//
ConfigurationCycleType = PciCfg->u.bits.Reserved1;
PciCfg->u.bits.Reserved1 = 0;
*Buffer = READ_CONFIG_UCHAR ((PUCHAR) (PciCfg->u.AsULONG + Offset),
ConfigurationCycleType);
//
// Reset state to preserve config cycle type across calls
//
PciCfg->u.bits.Reserved1 = ConfigurationCycleType;
return sizeof (UCHAR);
}
ULONG
HalpPCIReadUshort (
IN PPCI_CFG_CYCLE_BITS PciCfg,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
ULONG ConfigurationCycleType;
ConfigurationCycleType = PciCfg->u.bits.Reserved1;
PciCfg->u.bits.Reserved1 = 0;
*((PUSHORT) Buffer) = READ_CONFIG_USHORT ((PUSHORT) (PciCfg->u.AsULONG + Offset),
ConfigurationCycleType);
//
// Reset state to preserve config cycle type across calls
//
PciCfg->u.bits.Reserved1 = ConfigurationCycleType;
return sizeof (USHORT);
}
ULONG
HalpPCIReadUlong (
IN PPCI_CFG_CYCLE_BITS PciCfg,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
ULONG ConfigurationCycleType;
ConfigurationCycleType = PciCfg->u.bits.Reserved1;
PciCfg->u.bits.Reserved1 = 0;
*((PULONG) Buffer) = READ_CONFIG_ULONG ((PULONG) (PciCfg->u.AsULONG + Offset),
ConfigurationCycleType);
//
// Reset state to preserve config cycle type across calls
//
PciCfg->u.bits.Reserved1 = ConfigurationCycleType;
return sizeof (ULONG);
}
ULONG
HalpPCIWriteUchar (
IN PPCI_CFG_CYCLE_BITS PciCfg,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
ULONG ConfigurationCycleType;
ConfigurationCycleType = PciCfg->u.bits.Reserved1;
PciCfg->u.bits.Reserved1 = 0;
WRITE_CONFIG_UCHAR ((PUCHAR) (PciCfg->u.AsULONG + Offset), *Buffer,
ConfigurationCycleType);
//
// Reset state to preserve config cycle type across calls
//
PciCfg->u.bits.Reserved1 = ConfigurationCycleType;
return sizeof (UCHAR);
}
ULONG
HalpPCIWriteUshort (
IN PPCI_CFG_CYCLE_BITS PciCfg,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
ULONG ConfigurationCycleType;
ConfigurationCycleType = PciCfg->u.bits.Reserved1;
PciCfg->u.bits.Reserved1 = 0;
WRITE_CONFIG_USHORT ((PUSHORT) (PciCfg->u.AsULONG + Offset), *((PUSHORT) Buffer),
ConfigurationCycleType);
//
// Reset state to preserve config cycle type across calls
//
PciCfg->u.bits.Reserved1 = ConfigurationCycleType;
return sizeof (USHORT);
}
ULONG
HalpPCIWriteUlong (
IN PPCI_CFG_CYCLE_BITS PciCfg,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
ULONG ConfigurationCycleType;
ConfigurationCycleType = PciCfg->u.bits.Reserved1;
PciCfg->u.bits.Reserved1 = 0;
WRITE_CONFIG_ULONG ((PULONG) (PciCfg->u.AsULONG + Offset), *((PULONG) Buffer),
ConfigurationCycleType);
//
// Reset state to preserve config cycle type across calls
//
PciCfg->u.bits.Reserved1 = ConfigurationCycleType;
return sizeof (ULONG);
}
#if DBG
BOOLEAN
HalpValidPCIAddr(
IN PBUS_HANDLER BusHandler,
IN PHYSICAL_ADDRESS BAddr,
IN ULONG Length,
IN ULONG AddressSpace)
/*++
Routine Description:
Checks to see that the begining and ending 64 bit PCI bus addresses
of the 32 bit range of length Length are supported on the system.
Arguments:
BAddr - the 64 bit starting address
Length - a 32 bit length
AddressSpace - is this I/O (1) or memory space (0)
Return Value:
TRUE or FALSE
--*/
{
PHYSICAL_ADDRESS EAddr, TBAddr, TEAddr;
LARGE_INTEGER LiILen;
ULONG inIoSpace, inIoSpace2;
BOOLEAN flag, flag2;
ULONG BusNumber;
BusNumber = BusHandler->BusNumber;
//
// Translated address to system global setting and verify
// resource is available.
//
// Note that this code will need to be changed to support
// 64 bit PCI bus addresses.
//
LiILen.QuadPart = (ULONG)(Length - 1); // Inclusive length
EAddr.QuadPart = BAddr.QuadPart + LiILen.QuadPart;
inIoSpace = inIoSpace2 = AddressSpace;
flag = HalTranslateBusAddress ( PCIBus,
BusNumber,
BAddr,
&inIoSpace,
&TBAddr
);
flag2 = HalTranslateBusAddress (PCIBus,
BusNumber,
EAddr,
&inIoSpace2,
&TEAddr
);
if (flag == FALSE || flag2 == FALSE || inIoSpace != inIoSpace2) {
//
// HalAdjustResourceList should ensure that the returned range
// for the bus is within the bus limits and no translation
// within those limits should ever fail
//
DbgPrint ("HalpValidPCIAddr: Error return for HalTranslateBusAddress %x.%x:%x %x.%x:%x\n",
BAddr.HighPart, BAddr.LowPart, flag,
EAddr.HighPart, EAddr.LowPart, flag2);
return FALSE;
}
return TRUE;
}
#endif
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 the firmwaire-assigned resources.
Calls IoReportResources to report/confirm them.
Returns the assignments to the caller.
Arguments:
Return Value:
STATUS_SUCCESS or error
--*/
{
NTSTATUS status;
PUCHAR WorkingPool;
PPCI_COMMON_CONFIG PciData, PciOrigData;
PCI_SLOT_NUMBER PciSlot;
PCM_RESOURCE_LIST CmRes;
PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc;
PHYSICAL_ADDRESS BAddr;
ULONG addr;
ULONG Command;
ULONG cnt, len;
BOOLEAN conflict;
ULONG i, j, m, length, holdvalue;
ULONG BusNumber;
BusNumber = BusHandler->BusNumber;
*pAllocatedResources = NULL;
PciSlot = *((PPCI_SLOT_NUMBER) &Slot);
//
// Allocate some pool for working space
//
i = sizeof (CM_RESOURCE_LIST) +
sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2) +
PCI_COMMON_HDR_LENGTH * 2;
WorkingPool = (PUCHAR) ExAllocatePool (PagedPool, i);
if (!WorkingPool) {
return STATUS_NO_MEMORY;
}
//
// Zero initialize pool, and get pointers into memory - here we allocate
// a single chunk of memory and partition it into three pieces, pointed
// to by three separate pointers.
//
RtlZeroMemory (WorkingPool, i);
CmRes = (PCM_RESOURCE_LIST) WorkingPool;
PciData = (PPCI_COMMON_CONFIG)(WorkingPool + i - PCI_COMMON_HDR_LENGTH * 2);
PciOrigData = (PPCI_COMMON_CONFIG)(WorkingPool + i - PCI_COMMON_HDR_LENGTH);
//
// Read the PCI device configuration
//
HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
if (PciData->VendorID == PCI_INVALID_VENDORID || // empty slot
PciData->VendorID == 0x00) { // non-existant bus
ExFreePool (WorkingPool);
return STATUS_NO_SUCH_DEVICE;
}
//
// Make a copy of the devices current settings
//
RtlMoveMemory (PciOrigData, PciData, PCI_COMMON_HDR_LENGTH);
//
// Set resources to all bits on to see what type of resources
// are required.
//
for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
PciData->u.type0.BaseAddresses[j] = 0xFFFFFFFF;
}
PciData->u.type0.ROMBaseAddress = 0xFFFFFFFF;
PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE);
PciData->u.type0.ROMBaseAddress &= ~PCI_ROMADDRESS_ENABLED;
HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
//
// Build an CM_RESOURCE_LIST for the PCI device to report resources
// to IoReportResourceUsage.
//
// This code does *not* use IoAssignoResources, as the PCI
// address space resources have been previously assigned by the ARC firmware
//
CmRes->Count = 1;
CmRes->List[0].InterfaceType = PCIBus;
CmRes->List[0].BusNumber = BusNumber;
CmRes->List[0].PartialResourceList.Count = 0;
//
// Set current CM_RESOURCE_LIST version and revision
//
CmRes->List[0].PartialResourceList.Version = 0;
CmRes->List[0].PartialResourceList.Revision = 0;
CmDesc = CmRes->List[0].PartialResourceList.PartialDescriptors;
#if DBG
DbgPrint ("HalAssignSlotResources: Resource List V%d.%d for slot %x:\n",
CmRes->List[0].PartialResourceList.Version,
CmRes->List[0].PartialResourceList.Revision,
Slot);
#endif
//
// Interrupt resource
//
if (PciData->u.type0.InterruptPin) {
CmDesc->Type = CmResourceTypeInterrupt;
CmDesc->ShareDisposition = CmResourceShareShared;
CmDesc->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
CmDesc->u.Interrupt.Level = PciData->u.type0.InterruptLine;
CmDesc->u.Interrupt.Vector = PciData->u.type0.InterruptLine;
#if DBG
DbgPrint (" INT Level %x, Vector %x\n",
CmDesc->u.Interrupt.Level, CmDesc->u.Interrupt.Vector );
#endif
CmRes->List[0].PartialResourceList.Count++;
CmDesc++;
}
//
// Add a memory or port resoruce for each PCI resource
// (Compute the ROM address as well. Just append it to the Base
// Address table.)
//
holdvalue = PciData->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES];
PciData->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES] =
PciData->u.type0.ROMBaseAddress & ~PCI_ADDRESS_IO_SPACE;
Command = PciOrigData->Command;
for (j=0; j < PCI_TYPE0_ADDRESSES + 1; j++) {
if (PciData->u.type0.BaseAddresses[j]) {
addr = i = PciData->u.type0.BaseAddresses[j];
//
// calculate the length necessary - note there is more complicated
// code in the x86 HAL that probably isn't necessary
//
length = ~(i & ~((i & 1) ? 3 : 15)) + 1;
//
// I/O space resource
//
if (addr & PCI_ADDRESS_IO_SPACE) {
CmDesc->Type = CmResourceTypePort;
CmDesc->ShareDisposition = CmResourceShareDeviceExclusive;
CmDesc->Flags = CM_RESOURCE_PORT_IO;
BAddr.LowPart = PciOrigData->u.type0.BaseAddresses[j] & ~3;
BAddr.HighPart = 0;
#if DBG
HalpValidPCIAddr(BusHandler, BAddr, length, 1); // I/O space
#endif
CmDesc->u.Port.Start = BAddr;
CmDesc->u.Port.Length = length;
Command |= PCI_ENABLE_IO_SPACE;
#if DBG
DbgPrint (" IO Start %x:%08x, Len %x\n",
CmDesc->u.Port.Start.HighPart, CmDesc->u.Port.Start.LowPart,
CmDesc->u.Port.Length );
#endif
//
// Memory space resource
//
} else {
CmDesc->Type = CmResourceTypeMemory;
CmDesc->ShareDisposition = CmResourceShareDeviceExclusive;
if (j == PCI_TYPE0_ADDRESSES) {
// this is a ROM address
if ((PciOrigData->u.type0.ROMBaseAddress & PCI_ROMADDRESS_ENABLED) == 0) {
//
// Ignore expansion ROMs which are not enabled by
// the firmware/ROM BIOS.
//
continue;
}
CmDesc->Flags = CM_RESOURCE_MEMORY_READ_ONLY;
BAddr.LowPart = PciOrigData->u.type0.ROMBaseAddress &
~PCI_ROMADDRESS_ENABLED;
BAddr.HighPart = 0;
} else {
// this is a memory space base address
CmDesc->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
BAddr.LowPart = PciOrigData->u.type0.BaseAddresses[j] & ~15;
BAddr.HighPart = 0;
}
#if DBG
HalpValidPCIAddr(BusHandler, BAddr, length, 0); // Memory space
#endif
CmDesc->u.Memory.Start = BAddr;
CmDesc->u.Memory.Length = length;
Command |= PCI_ENABLE_MEMORY_SPACE;
#if DBG
DbgPrint (" MEM Start %x:%08x, Len %x\n",
CmDesc->u.Memory.Start.HighPart, CmDesc->u.Memory.Start.LowPart,
CmDesc->u.Memory.Length );
#endif
}
CmRes->List[0].PartialResourceList.Count++;
CmDesc++;
if (Is64BitBaseAddress(addr)) {
// skip upper half of 64 bit address since we
// only supports 32 bits PCI addresses for now.
j++;
}
}
}
//
// Setup the resource list.
// Count only the acquired resources.
//
*pAllocatedResources = CmRes;
cnt = CmRes->List[0].PartialResourceList.Count;
len = sizeof (CM_RESOURCE_LIST) +
cnt * sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR);
#if DBG
DbgPrint("HalAssignSlotResources: Acq. Resourses = %d (len %x list %x\n)",
cnt, len, *pAllocatedResources);
#endif
//
// Report the IO resource assignments
//
if (!DeviceObject) {
status = IoReportResourceUsage (
DriverClassName,
DriverObject, // DriverObject
*pAllocatedResources, // DriverList
len, // DriverListSize
DeviceObject, // DeviceObject
NULL, // DeviceList
0, // DeviceListSize
FALSE, // override conflict
&conflict // conflicted detected
);
} else {
status = IoReportResourceUsage (
DriverClassName,
DriverObject, // DriverObject
NULL, // DriverList
0, // DriverListSize
DeviceObject,
*pAllocatedResources, // DeviceList
len, // DeviceListSize
FALSE, // override conflict
&conflict // conflicted detected
);
}
if (NT_SUCCESS(status) && conflict) {
//
// IopReportResourceUsage saw a conflict?
//
#if DBG
DbgPrint("HalAssignSlotResources: IoAssignResources detected a conflict: %x\n",
status);
#endif
status = STATUS_CONFLICTING_ADDRESSES;
goto CleanUp;
}
if (!NT_SUCCESS(status)) {
#if DBG
DbgPrint("HalAssignSlotResources: IoAssignResources failed: %x\n", status);
#endif
goto CleanUp;
}
//
// Restore orginial data, turning on the appropiate decodes
//
#if DBG
DbgPrint ("HalAssignSlotResources: IoReportResourseUsage succeeded\n");
#endif
// enable IO & Memory decodes
PciOrigData->Command |= (USHORT) Command;
HalpWritePCIConfig (
BusHandler,
PciSlot,
PciOrigData,
0,
PCI_COMMON_HDR_LENGTH
);
#if DBG
DbgPrint ("HalAssignSlotResources: PCI Config Space updated with Command = %x\n",
Command);
#endif
CleanUp:
if (!NT_SUCCESS(status)) {
//
// Failure, if there are any allocated resources free them
//
i = 0;
if (*pAllocatedResources) {
if (!DeviceObject) {
status = IoReportResourceUsage (
DriverClassName,
DriverObject, // DriverObject
(PCM_RESOURCE_LIST) &i, // DriverList
sizeof (i), // DriverListSize
DeviceObject,
NULL, // DeviceList
0, // DeviceListSize
FALSE, // override conflict
&conflict // conflicted detected
);
} else {
status = IoReportResourceUsage (
DriverClassName,
DriverObject, // DriverObject
NULL, // DriverList
0, // DriverListSize
DeviceObject,
(PCM_RESOURCE_LIST) &i, // DeviceList
sizeof (i), // DeviceListSize
FALSE, // override conflict
&conflict // conflicted detected
);
}
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,
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)
);
}
return status;
}
NTSTATUS
HalpAdjustPCIResourceList (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
)
/*++
Routine Description:
The function adjusts a PCI pResourceList and forces it to match the
pre-configured values in PCI configuration space for this device.
Arguments:
BusHandler - Registered BUSHANDLER for the target configuration space
RootHandler - Register BUSHANDLER for the orginating HalAdjustResourceList request.
pResourceList - Supplies the PIO_RESOURCE_REQUIREMENTS_LIST to be checked.
Return Value:
STATUS_SUCCESS
--*/
{
UCHAR buffer[PCI_COMMON_HDR_LENGTH];
PCI_SLOT_NUMBER PciSlot;
PPCI_COMMON_CONFIG PciData;
PIO_RESOURCE_REQUIREMENTS_LIST CompleteList;
PIO_RESOURCE_LIST ResourceList;
PIO_RESOURCE_DESCRIPTOR Descriptor;
ULONG alt, cnt, bcnt;
ULONG MemoryBaseAddress, RomIndex;
PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1];
//
// Fix any requested resources for this device to be the
// value set in PCI configuration space for this device.
//
//
// Get PCI common configuration space for this slot
//
PciSlot = *((PPCI_SLOT_NUMBER) &(*pResourceList)->SlotNumber),
PciData = (PPCI_COMMON_CONFIG) buffer;
HalGetBusData (
PCIConfiguration,
BusHandler->BusNumber,
PciSlot.u.AsULONG,
PciData,
PCI_COMMON_HDR_LENGTH
);
if (PciData->VendorID == PCI_INVALID_VENDORID ||
PCI_CONFIG_TYPE (PciData) != 0) {
return STATUS_UNSUCCESSFUL;
}
//
// Copy base addresses based on configuration data type
//
switch (PCI_CONFIG_TYPE(PciData)) {
case 0 :
for (bcnt=0; bcnt < PCI_TYPE0_ADDRESSES; bcnt++) {
BaseAddress[bcnt] = &PciData->u.type0.BaseAddresses[bcnt];
}
BaseAddress[bcnt] = &PciData->u.type0.ROMBaseAddress;
RomIndex = bcnt;
break;
case 1:
for (bcnt=0; bcnt < PCI_TYPE1_ADDRESSES; bcnt++) {
BaseAddress[bcnt] = &PciData->u.type1.BaseAddresses[bcnt];
}
BaseAddress[bcnt] = &PciData->u.type0.ROMBaseAddress;
RomIndex = bcnt;
break;
default:
return STATUS_NO_SUCH_DEVICE;
}
//
// Walk each ResourceList and confine resources
// to preconfigured settings.
//
CompleteList = *pResourceList;
ResourceList = CompleteList->List;
ResourceList->Version = 1;
ResourceList->Revision = 1;
for (alt=0; alt < CompleteList->AlternativeLists; alt++) {
Descriptor = ResourceList->Descriptors;
//
// For each alternative list, reset to review entire
// set of Base Address registers
//
// We assume that the order of resource descriptors for
// each alternative list matches the order of the
// PCI configuration space base address registers
//
bcnt = 0;
for (cnt = ResourceList->Count; cnt; cnt--) {
//
// Limit desctiptor to to preconfigured setting
// held in the InterruptLine register.
//
switch (Descriptor->Type) {
case CmResourceTypeInterrupt:
//
// Confine interrupt vector to preconfigured setting.
//
Descriptor->u.Interrupt.MinimumVector = PciData->u.type0.InterruptLine;
Descriptor->u.Interrupt.MaximumVector = PciData->u.type0.InterruptLine;
break;
case CmResourceTypePort:
//
// Assure that requested descriptor is valid
//
if (bcnt > RomIndex) {
return STATUS_INVALID_PARAMETER;
}
//
// Confine to preconfigured setting.
//
Descriptor->u.Port.MinimumAddress.QuadPart =
*BaseAddress[bcnt++] & ~0x3;
Descriptor->u.Port.MaximumAddress.QuadPart =
Descriptor->u.Port.MinimumAddress.QuadPart +
Descriptor->u.Port.Length - 1;
#if HALDBG
DbgPrint("AdjustPCIResourceList\nPort: MinimumAddress set to %x\n",
Descriptor->u.Port.MinimumAddress.QuadPart);
DbgPrint(" MaximumAddress set to %x\n",
Descriptor->u.Port.MaximumAddress.QuadPart);
#endif
break;
case CmResourceTypeMemory:
//
// Assure that requested descriptor is valid
//
if (bcnt > RomIndex) {
return STATUS_INVALID_PARAMETER;
}
//
// Confine to preconfigured setting.
//
MemoryBaseAddress = *BaseAddress[bcnt];
if (bcnt == RomIndex) {
Descriptor->u.Memory.MinimumAddress.QuadPart =
*BaseAddress[bcnt++] & ~PCI_ROMADDRESS_ENABLED;
} else {
Descriptor->u.Memory.MinimumAddress.QuadPart =
*BaseAddress[bcnt++] & ~0xF;
}
Descriptor->u.Memory.MaximumAddress.QuadPart =
Descriptor->u.Memory.MinimumAddress.QuadPart +
Descriptor->u.Memory.Length - 1;
if (Is64BitBaseAddress(MemoryBaseAddress)) {
// skip upper half of 64 bit address since we
// only supports 32 bits PCI addresses for now.
bcnt++;
}
#if HALDBG
DbgPrint("AdjustPCIResourceList\nMemory: MinimumAddress set to %x\n",
Descriptor->u.Memory.MinimumAddress.QuadPart);
DbgPrint(" MaximumAddress set to %x\n",
Descriptor->u.Memory.MaximumAddress.QuadPart);
#endif
break;
case CmResourceTypeDma:
break;
default:
return STATUS_INVALID_PARAMETER;
}
//
// Next descriptor
//
Descriptor++;
}
//
// Next Resource List
//
ResourceList = (PIO_RESOURCE_LIST) Descriptor;
}
return STATUS_SUCCESS;
}
#define TEST_PCI 1
#if DBG && TEST_PCI
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 < 32; i++) {
SlotNumber.u.bits.DeviceNumber = i;
for (f = 0; f < 8; f++) {
SlotNumber.u.bits.FunctionNumber = f;
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)
);
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)
);
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 ("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
//
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)
);
//
// Next
//
if (k) {
DbgPrint ("\n\n");
}
}
}
}
DbgBreakPoint();
}
#endif // DBG && TEST_PCI