NT4/private/ntos/nthals/halalpha/pcisup.c

2454 lines
62 KiB
C
Raw Normal View History

2001-01-01 00:00:00 +01:00
/*++
Copyright (c) 1989 Microsoft Corporation
Copyright (c) 1994 Digital Equipment Corporation
Module Name:
pcisup.c
Abstract:
Platform-independent PCI bus routines
Author:
Environment:
Kernel mode
Revision History:
--*/
#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))
#if !defined(AXP_FIRMWARE)
VOID
HalpRegisterPciBus(
IN PCONFIGURATION_COMPONENT Component,
IN PVOID ConfigurationData
)
/*++
Routine Description:
This function uses information obtained from the ARC configuration
tree to create PCI bus handlers. If configuration data was passed
with the PCI component, then that information is used to create the
bus handler. Otherwise, we use a priori knowledge (and bus scanning)
to generate the bus handler data. This function supports firmware
that both provide and do not provide configuration data payloads.
Arguments:
Component - The ARC configuration component for this bus.
ConfigurationData - The configuration data payload (or NULL).
Return Value:
None.
--*/
{
BOOLEAN ConfigurationDataPresent;
ARC_PCI_CONFIGURATION ArcPciConfiguration;
ULONG BusNumber;
ULONG HwBusNumber;
BOOLEAN BusIsAcrossPPB;
PBUS_HANDLER BusHandler;
PPCIPBUSDATA BusData;
RTL_BITMAP DevicePresent;
PCI_SLOT_NUMBER SlotNumber;
ULONG DeviceNumber;
ULONG FunctionNumber;
PCI_COMMON_CONFIG CommonConfig;
PCI_SLOT_NUMBER Dummy;
memset(&Dummy, 0, sizeof(PCI_SLOT_NUMBER) );
//
// Ascertain whether the ARC firmware provided configuration data as part
// of the multi-function adapter component.
//
ConfigurationDataPresent = Component->ConfigurationDataLength != 0;
//
// If configuration data was provided use it to allocate and initialize
// the handler for this bus. Otherwise, use a priori knowledge to
// generate reasonable values.
//
if (ConfigurationDataPresent) {
//
// Copy the configuration data from the component.
//
RtlCopyMemory(
&ArcPciConfiguration,
ConfigurationData,
sizeof (ARC_PCI_CONFIGURATION)
);
//
// Use the values provided.
//
BusNumber = ArcPciConfiguration.BusNumber;
HwBusNumber = ArcPciConfiguration.HwBusNumber;
BusIsAcrossPPB = ArcPciConfiguration.BusIsAcrossPPB;
//
// Despite its name, PCIMaxBus is really the number of busses present
// in the system.
//
if (PCIMaxBus < BusNumber + 1) {
PCIMaxBus = BusNumber + 1;
}
} else {
//
// PCIMaxBus keeps a running count of the number of busses seen up
// to this point. Use the current value as the bus number and advance
// the counter. Set HwBusNumber and BusIsAcrossPPB to reasonable
// values.
//
BusNumber = PCIMaxBus++;
HwBusNumber = 0;
BusIsAcrossPPB = BusNumber != 0;
}
//
// Allocate and initialize the handler for this bus. N.B. device-present
// checking is disabled at this point. We will enable it below.
//
BusHandler = HalpAllocateAndInitPCIBusHandler(
BusNumber,
HwBusNumber,
BusIsAcrossPPB,
0, // MS here
Dummy // MS here
);
//
// Get a pointer to the bus-specific data.
//
BusData = (PPCIPBUSDATA)BusHandler->BusData;
//
// Compute the device-present bitmap for this bus. If configuration
// data is present then the bitmap has been pre-computed for us by the
// firmware. In this case, use the bitmap provided. otherwise, we
// have to do the work now of generating the bitmap.
//
if (ConfigurationDataPresent) {
//
// Initialize the device-present bitmap for this bus.
//
RtlInitializeBitMap(
&BusData->DevicePresent,
BusData->DevicePresentBits,
PCI_MAX_DEVICES * PCI_MAX_FUNCTION
);
//
// The firmware has already computed the device-present bitmap for
// us. Copy the bitmap from the configuration data.
//
RtlCopyMemory(
BusData->DevicePresentBits,
ArcPciConfiguration.DevicePresentBits,
sizeof (BusData->DevicePresentBits)
);
} else {
//
// Initialize a bitmap which we will use to accumulate the results
// of the device-present scan. N.B. Device-present checking is
// currently disabled.
//
RtlInitializeBitMap(
&DevicePresent,
BusData->DevicePresentBits,
PCI_MAX_DEVICES * PCI_MAX_FUNCTION
);
RtlClearBits(
&DevicePresent,
0,
PCI_MAX_DEVICES * PCI_MAX_FUNCTION
);
//
// Initialize the slot number.
//
SlotNumber.u.AsULONG = 0;
//
// Loop through each device number.
//
for (DeviceNumber = 0;
DeviceNumber < PCI_MAX_DEVICES;
DeviceNumber++) {
SlotNumber.u.bits.DeviceNumber = DeviceNumber;
//
// Loop through each function number.
//
for (FunctionNumber = 0;
FunctionNumber < PCI_MAX_FUNCTION;
FunctionNumber++) {
SlotNumber.u.bits.FunctionNumber = FunctionNumber;
//
// Read the common configuration header.
//
HalpReadPCIConfig(
BusHandler,
SlotNumber,
&CommonConfig,
0,
PCI_COMMON_HDR_LENGTH
);
//
// If the Vendor ID is invalid, then no device is present
// at this device/function number.
//
if (CommonConfig.VendorID == PCI_INVALID_VENDORID) {
if (FunctionNumber == 0) {
break;
}
continue;
}
//
// Set a bit indicating a device is present.
//
RtlSetBits(
&DevicePresent,
PciBitIndex(DeviceNumber, FunctionNumber),
1
);
//
// If this is not a multi-function device, then terminate
// the function number loop.
//
if ((CommonConfig.HeaderType & PCI_MULTIFUNCTION) == 0) {
break;
}
}
}
//
// Enable device-present checking.
//
BusData->DevicePresent = DevicePresent;
}
}
#endif
#if !defined(AXP_FIRMWARE)
VOID
HalpQueryPciBusConfiguration(
IN PCONFIGURATION_COMPONENT_DATA Root
)
/*++
Routine Description:
This function loops through each multi-function adapter component
in the ARC configuration tree and calls HalpRegisterPciBus() to create
a bus handler for it.
Arguments:
Root - The root of the ARC configuration tree.
Return Value:
None.
--*/
{
ULONG Key;
PCONFIGURATION_COMPONENT_DATA Adapter;
//
// Loop through each multi-function adapter component in the ARC
// configuration tree.
//
for (Key = 0; TRUE; Key++) {
//
// Get a pointer to the component data.
//
Adapter = KeFindConfigurationEntry(
Root,
AdapterClass,
MultiFunctionAdapter,
&Key
);
//
// If there are no more multi-function adapters in the ARC
// configuration tree, then we're done.
//
if (Adapter == NULL) {
break;
}
//
// Ascertain whether this is a PCI multi-function adapter component.
// If so, register a bus handler for it.
//
if (_stricmp(Adapter->ComponentEntry.Identifier, "PCI") == 0) {
HalpRegisterPciBus(
&Adapter->ComponentEntry,
Adapter->ConfigurationData
);
}
}
}
#endif
VOID
HalpInitializePCIBus(
IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
/*++
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.
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.
--*/
{
//
// Only initialize the PCI subsystem once.
//
if (PCIInitialized) {
return;
}
//
// Initialize PCI subsystem variables.
//
#ifdef AXP_FIRMWARE
PCIMaxBus = PCI_MAX_BUSSES;
#else
PCIMaxBus = 0;
#endif
PCIMaxLocalDevice = PCI_MAX_LOCAL_DEVICE;
PCIMaxDevice = PCI_MAX_DEVICES - 1;
//
// Initialize the PCI configuration spinlock.
//
KeInitializeSpinLock(&HalpPCIConfigLock);
#if !AXP_FIRMWARE
//
// Consult the ARC configuration tree and register bus handlers for
// all PCI multi-function adapter nodes.
//
HalpQueryPciBusConfiguration(LoaderBlock->ConfigurationRoot);
#endif
//
// The PCI subsystem has been initialized.
//
PCIInitialized = TRUE;
}
PBUS_HANDLER
HalpAllocateAndInitPCIBusHandler (
IN ULONG BusNo,
IN ULONG HwBusNo,
IN BOOLEAN BusIsAcrossPPB,
IN ULONG PPBBusNumber,
IN PCI_SLOT_NUMBER PPBSlotNumber
)
{
PBUS_HANDLER Bus;
PPCIPBUSDATA BusData;
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
BusData = (PPCIPBUSDATA) Bus->BusData;
BusData->HwBusNumber = HwBusNo;
BusData->BusIsAcrossPPB = BusIsAcrossPPB;
BusData->PPBBusNumber = PPBBusNumber;
BusData->PPBSlotNumber = PPBSlotNumber;
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
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;
}
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 BUS_HANDLER for the target configuration space
RootHandler - Register BUS_HANDLER 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) {
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 BUS_HANDLER for the target configuration space
RootHandler - Register BUS_HANDLER 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) {
// no device
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) ) {
return InvalidSlot;
}
//
// Get the config cycle type for the proposed bus.
// (PciConfigTypeInvalid indicates a non-existent bus.)
//
PciConfigType = HalpPCIConfigCycleType(BusHandler);
//
// 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;
//
// Setup platform-dependent state for configuration space access
//
HalpPCIConfigAddr(BusHandler, 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;
#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 BUS_HANDLER for the target configuration space
RootHandler - Register BUS_HANDLER 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) {
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