windows-nt/Source/XPSP1/NT/base/boot/lib/i386/ixpcibus.c
2020-09-26 16:20:57 +08:00

1402 lines
35 KiB
C

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
ixpcidat.c
Abstract:
Get/Set bus data routines for the PCI bus
Author:
Environment:
Kernel mode
Revision History:
--*/
#include "bootx86.h"
#include "arc.h"
#include "ixfwhal.h"
#include "ntconfig.h"
#include "pci.h"
//extern WCHAR rgzMultiFunctionAdapter[];
//extern WCHAR rgzConfigurationData[];
//extern WCHAR rgzIdentifier[];
//extern WCHAR rgzPCIIdentifier[];
//
// Hal specific PCI bus structures
//
typedef struct tagPCIPBUSDATA {
union {
struct {
PULONG Address;
ULONG Data;
} Type1;
struct {
PUCHAR CSE;
PUCHAR Forward;
ULONG Base;
} Type2;
} Config;
} PCIPBUSDATA, *PPCIPBUSDATA;
#define PciBitIndex(Dev,Fnc) (Fnc*32 + Dev);
#define PCI_CONFIG_TYPE(PciData) ((PciData)->HeaderType & ~PCI_MULTIFUNCTION)
#define BUSHANDLER _BUSHANDLER
#define PBUSHANDLER _PBUSHANDLER
// thunk for NtLdr
typedef struct {
ULONG NoBuses;
ULONG BusNumber;
PVOID BusData;
PCIPBUSDATA theBusData;
} BUSHANDLER, *PBUSHANDLER;
#define HalpPCIPin2Line(bus,rbus,slot,pcidata)
#define HalpPCILine2Pin(bus,rbus,slot,pcidata,pcidata2)
#define ExAllocatePool(a,l) FwAllocatePool(l)
// thunk for NtLdr
typedef ULONG (*FncConfigIO) (
IN PPCIPBUSDATA BusData,
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
typedef VOID (*FncSync) (
IN PBUSHANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PKIRQL Irql,
IN PVOID State
);
typedef VOID (*FncReleaseSync) (
IN PBUSHANDLER BusHandler,
IN KIRQL Irql
);
typedef struct {
FncSync Synchronize;
FncReleaseSync ReleaseSynchronzation;
FncConfigIO ConfigRead[3];
FncConfigIO ConfigWrite[3];
} CONFIG_HANDLER, *PCONFIG_HANDLER;
//
// Prototypes
//
ULONG
HalpGetPCIData (
IN ULONG BusNumber,
IN PCI_SLOT_NUMBER SlotNumber,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
);
ULONG
HalpSetPCIData (
IN ULONG BusNumber,
IN PCI_SLOT_NUMBER SlotNumber,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
);
extern ULONG
HalpGetPCIInterruptVector (
IN PBUSHANDLER BusHandler,
IN PBUSHANDLER RootHandler,
IN ULONG BusInterruptLevel,
IN ULONG BusInterruptVector,
OUT PKIRQL Irql,
OUT PKAFFINITY Affinity
);
NTSTATUS
HalpAdjustPCIResourceList (
IN PBUSHANDLER BusHandler,
IN PBUSHANDLER RootHandler,
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
);
NTSTATUS
HalpAssignPCISlotResources (
IN ULONG BusNumber,
IN ULONG SlotNumber,
IN OUT PCM_RESOURCE_LIST *AllocatedResources
);
VOID
HalpInitializePciBuses (
VOID
);
//VOID
//HalpPCIPin2Line (
// IN PBUSHANDLER BusHandler,
// IN PBUSHANDLER RootHandler,
// IN PCI_SLOT_NUMBER Slot,
// IN PPCI_COMMON_CONFIG PciData
// );
//
//VOID
//HalpPCILine2Pin (
// IN PBUSHANDLER BusHandler,
// IN PBUSHANDLER RootHandler,
// IN PCI_SLOT_NUMBER SlotNumber,
// IN PPCI_COMMON_CONFIG PciNewData,
// IN PPCI_COMMON_CONFIG PciOldData
// );
BOOLEAN
HalpValidPCISlot (
IN PBUSHANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot
);
VOID
HalpReadPCIConfig (
IN PBUSHANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
);
VOID
HalpWritePCIConfig (
IN PBUSHANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
);
PBUSHANDLER
HalpGetPciBusHandler (
IN ULONG BusNumber
);
//-------------------------------------------------
VOID HalpPCISynchronizeType1 (
IN PBUSHANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PKIRQL Irql,
IN PVOID State
);
VOID HalpPCIReleaseSynchronzationType1 (
IN PBUSHANDLER BusHandler,
IN KIRQL Irql
);
ULONG HalpPCIReadUlongType1 (
IN PPCIPBUSDATA BusData,
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
ULONG HalpPCIReadUcharType1 (
IN PPCIPBUSDATA BusData,
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
ULONG HalpPCIReadUshortType1 (
IN PPCIPBUSDATA BusData,
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
ULONG HalpPCIWriteUlongType1 (
IN PPCIPBUSDATA BusData,
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
ULONG HalpPCIWriteUcharType1 (
IN PPCIPBUSDATA BusData,
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
ULONG HalpPCIWriteUshortType1 (
IN PPCIPBUSDATA BusData,
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
VOID HalpPCISynchronizeType2 (
IN PBUSHANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PKIRQL Irql,
IN PVOID State
);
VOID HalpPCIReleaseSynchronzationType2 (
IN PBUSHANDLER BusHandler,
IN KIRQL Irql
);
ULONG HalpPCIReadUlongType2 (
IN PPCIPBUSDATA BusData,
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
ULONG HalpPCIReadUcharType2 (
IN PPCIPBUSDATA BusData,
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
ULONG HalpPCIReadUshortType2 (
IN PPCIPBUSDATA BusData,
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
ULONG HalpPCIWriteUlongType2 (
IN PPCIPBUSDATA BusData,
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
ULONG HalpPCIWriteUcharType2 (
IN PPCIPBUSDATA BusData,
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
ULONG HalpPCIWriteUshortType2 (
IN PPCIPBUSDATA BusData,
IN PVOID State,
IN PUCHAR Buffer,
IN ULONG Offset
);
#define DISABLE_INTERRUPTS() //_asm { cli }
#define ENABLE_INTERRUPTS() //_asm { sti }
//
// Globals
//
ULONG PCIMaxDevice;
BUSHANDLER PCIBusHandler;
CONFIG_HANDLER PCIConfigHandlers = {
HalpPCISynchronizeType1,
HalpPCIReleaseSynchronzationType1,
{
HalpPCIReadUlongType1, // 0
HalpPCIReadUcharType1, // 1
HalpPCIReadUshortType1 // 2
},
{
HalpPCIWriteUlongType1, // 0
HalpPCIWriteUcharType1, // 1
HalpPCIWriteUshortType1 // 2
}
};
CONFIG_HANDLER PCIConfigHandlersType2 = {
HalpPCISynchronizeType2,
HalpPCIReleaseSynchronzationType2,
{
HalpPCIReadUlongType2, // 0
HalpPCIReadUcharType2, // 1
HalpPCIReadUshortType2 // 2
},
{
HalpPCIWriteUlongType2, // 0
HalpPCIWriteUcharType2, // 1
HalpPCIWriteUshortType2 // 2
}
};
UCHAR PCIDeref[4][4] = { {0,1,2,2},{1,1,1,1},{2,1,2,2},{1,1,1,1} };
VOID
HalpPCIConfig (
IN PBUSHANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PUCHAR Buffer,
IN ULONG Offset,
IN ULONG Length,
IN FncConfigIO *ConfigIO
);
VOID
HalpInitializePciBus (
VOID
)
{
PPCI_REGISTRY_INFO PCIRegInfo;
PPCIPBUSDATA BusData;
PBUSHANDLER Bus;
PCONFIGURATION_COMPONENT_DATA ConfigData;
PCM_PARTIAL_RESOURCE_LIST Desc;
PCM_PARTIAL_RESOURCE_DESCRIPTOR PDesc;
ULONG i;
ULONG HwType;
Bus = &PCIBusHandler;
PCIBusHandler.BusData = &PCIBusHandler.theBusData;
PCIRegInfo = NULL; // not found
ConfigData = NULL; // start at begining
do {
ConfigData = KeFindConfigurationNextEntry (
FwConfigurationTree,
AdapterClass,
MultiFunctionAdapter,
NULL,
&ConfigData
);
if (ConfigData == NULL) {
// PCI info not found
return ;
}
if (ConfigData->ComponentEntry.Identifier == NULL ||
_stricmp (ConfigData->ComponentEntry.Identifier, "PCI") != 0) {
continue;
}
PCIRegInfo = NULL;
Desc = ConfigData->ConfigurationData;
PDesc = Desc->PartialDescriptors;
for (i = 0; i < Desc->Count; i++) {
if (PDesc->Type == CmResourceTypeDeviceSpecific) {
PCIRegInfo = (PPCI_REGISTRY_INFO) (PDesc+1);
break;
}
PDesc++;
}
} while (!PCIRegInfo) ;
//
// PCIRegInfo describes the system's PCI support as indicated
// by the BIOS.
//
HwType = PCIRegInfo->HardwareMechanism & 0xf;
switch (HwType) {
case 1:
// this is the default case
PCIMaxDevice = PCI_MAX_DEVICES;
break;
//
// Type2 does not work MP, nor does the default type2
// support more the 0xf device slots
//
case 2:
RtlMoveMemory (&PCIConfigHandlers,
&PCIConfigHandlersType2,
sizeof (PCIConfigHandlersType2));
PCIMaxDevice = 0x10;
break;
default:
// unsupport type
PCIRegInfo->NoBuses = 0;
}
PCIBusHandler.NoBuses = PCIRegInfo->NoBuses;
if (PCIRegInfo->NoBuses) {
BusData = (PPCIPBUSDATA) Bus->BusData;
switch (HwType) {
case 1:
BusData->Config.Type1.Address = PCI_TYPE1_ADDR_PORT;
BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT;
break;
case 2:
BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT;
BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT;
BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE;
break;
}
}
}
PBUSHANDLER
HalpGetPciBusHandler (
IN ULONG BusNumber
)
{
if (PCIBusHandler.BusData == NULL) {
HalpInitializePciBus ();
}
if (BusNumber > PCIBusHandler.NoBuses) {
return NULL;
}
PCIBusHandler.BusNumber = BusNumber;
return &PCIBusHandler;
}
ULONG
HalpGetPCIData (
IN ULONG BusNumber,
IN PCI_SLOT_NUMBER Slot,
IN PUCHAR Buffer,
IN ULONG Offset,
IN ULONG Length
)
/*++
Routine Description:
The function returns the Pci bus data for a device.
Arguments:
BusNumber - Indicates which bus.
VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word)
Buffer - Supplies the space to store the data.
Length - Supplies a count in bytes of the maximum amount to return.
Return Value:
Returns the amount of data stored into the buffer.
If this PCI slot has never been set, then the configuration information
returned is zeroed.
--*/
{
PBUSHANDLER BusHandler;
PPCI_COMMON_CONFIG PciData;
UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
PPCIPBUSDATA BusData;
ULONG Len;
BusHandler = HalpGetPciBusHandler (BusNumber);
if (!BusHandler) {
return 0;
}
if (Length > sizeof (PCI_COMMON_CONFIG)) {
Length = sizeof (PCI_COMMON_CONFIG);
}
Len = 0;
PciData = (PPCI_COMMON_CONFIG) iBuffer;
if (Offset >= PCI_COMMON_HDR_LENGTH) {
//
// The user did not request any data from the common
// header. Verify the PCI device exists, then continue
// in the device specific area.
//
HalpReadPCIConfig (BusHandler, Slot, PciData, 0, sizeof(ULONG));
if (PciData->VendorID == PCI_INVALID_VENDORID) {
return 0;
}
} else {
//
// Caller requested at least some data within the
// common header. Read the whole header, effect the
// fields we need to and then copy the user's requested
// bytes from the header
//
//
// Read this PCI devices slot data
//
Len = PCI_COMMON_HDR_LENGTH;
HalpReadPCIConfig (BusHandler, Slot, PciData, 0, Len);
if (PciData->VendorID == PCI_INVALID_VENDORID) {
Len = 2; // only return invalid id
}
//
// Has this PCI device been configured?
//
BusData = (PPCIPBUSDATA) BusHandler->BusData;
HalpPCIPin2Line (BusHandler, RootHandler, Slot, PciData);
//
// 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 & WORD aligned.
//
// To use a BYTE access if the requested length is exactly
// a BYTE long.
//
HalpReadPCIConfig (BusHandler, Slot, Buffer, Offset, Length);
Len += Length;
}
}
return Len;
}
ULONG
HalpSetPCIData (
IN ULONG BusNumber,
IN PCI_SLOT_NUMBER Slot,
IN PUCHAR Buffer,
IN ULONG Offset,
IN ULONG Length
)
/*++
Routine Description:
The function returns the Pci bus data for a device.
Arguments:
VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word)
Buffer - Supplies the space to store the data.
Length - Supplies a count in bytes of the maximum amount to return.
Return Value:
Returns the amount of data stored into the buffer.
--*/
{
PBUSHANDLER BusHandler;
PPCI_COMMON_CONFIG PciData, PciData2;
UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
UCHAR iBuffer2[PCI_COMMON_HDR_LENGTH];
PPCIPBUSDATA BusData;
ULONG Len;
BusHandler = HalpGetPciBusHandler (BusNumber);
if (!BusHandler) {
return 0;
}
if (Length > sizeof (PCI_COMMON_CONFIG)) {
Length = sizeof (PCI_COMMON_CONFIG);
}
Len = 0;
PciData = (PPCI_COMMON_CONFIG) iBuffer;
PciData2 = (PPCI_COMMON_CONFIG) iBuffer2;
if (Offset >= PCI_COMMON_HDR_LENGTH) {
//
// The user did not request any data from the common
// header. Verify the PCI device exists, then continue in
// the device specific area.
//
HalpReadPCIConfig (BusHandler, Slot, PciData, 0, sizeof(ULONG));
if (PciData->VendorID == PCI_INVALID_VENDORID) {
return 0;
}
} else {
//
// Caller requested to set at least some data within the
// common header.
//
Len = PCI_COMMON_HDR_LENGTH;
HalpReadPCIConfig (BusHandler, Slot, PciData, 0, Len);
if (PciData->VendorID == PCI_INVALID_VENDORID ||
PCI_CONFIG_TYPE (PciData) != 0) {
// no device, or header type unkown
return 0;
}
//
// Set this device as configured
//
BusData = (PPCIPBUSDATA) BusHandler->BusData;
//
// 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);
// in case interrupt line or pin was editted
HalpPCILine2Pin (BusHandler, RootHandler, Slot, PciData2, PciData);
//
// Set new PCI configuration
//
HalpWritePCIConfig (BusHandler, Slot, iBuffer2+Offset, Offset, Len);
Offset += Len;
Buffer += Len;
Length -= Len;
}
if (Length) {
if (Offset >= PCI_COMMON_HDR_LENGTH) {
//
// The remaining Buffer comes from the Device Specific
// area - put on the kitten gloves and write it
//
// Specific read/writes to the PCI device specific area
// are guarenteed:
//
// Not to read/write any byte outside the area specified
// by the caller. (this may cause WORD or BYTE references
// to the area in order to read the non-dword aligned
// ends of the request)
//
// To use a WORD access if the requested length is exactly
// a WORD long & WORD aligned.
//
// To use a BYTE access if the requested length is exactly
// a BYTE long.
//
HalpWritePCIConfig (BusHandler, Slot, Buffer, Offset, Length);
Len += Length;
}
}
return Len;
}
VOID
HalpReadPCIConfig (
IN PBUSHANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
)
{
if (!HalpValidPCISlot (BusHandler, Slot)) {
//
// Invalid SlotID return no data
//
RtlFillMemory (Buffer, Length, (UCHAR) -1);
return ;
}
HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length,
PCIConfigHandlers.ConfigRead);
}
VOID
HalpWritePCIConfig (
IN PBUSHANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
)
{
if (!HalpValidPCISlot (BusHandler, Slot)) {
//
// Invalid SlotID do nothing
//
return ;
}
HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length,
PCIConfigHandlers.ConfigWrite);
}
BOOLEAN
HalpValidPCISlot (
IN PBUSHANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot
)
{
PCI_SLOT_NUMBER Slot2;
UCHAR HeaderType;
ULONG i;
if (Slot.u.bits.Reserved != 0) {
return FALSE;
}
if (Slot.u.bits.DeviceNumber >= PCIMaxDevice) {
return FALSE;
}
if (Slot.u.bits.FunctionNumber == 0) {
return TRUE;
}
//
// Non zero function numbers are only supported if the
// device has the PCI_MULTIFUNCTION bit set in it's header
//
i = Slot.u.bits.DeviceNumber;
//
// Read DeviceNumber, Function zero, to determine if the
// PCI supports multifunction devices
//
Slot2 = Slot;
Slot2.u.bits.FunctionNumber = 0;
HalpReadPCIConfig (
BusHandler,
Slot2,
&HeaderType,
FIELD_OFFSET (PCI_COMMON_CONFIG, HeaderType),
sizeof (UCHAR)
);
if (!(HeaderType & PCI_MULTIFUNCTION) || HeaderType == 0xFF) {
// this device doesn't exists or doesn't support MULTIFUNCTION types
return FALSE;
}
return TRUE;
}
VOID
HalpPCIConfig (
IN PBUSHANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PUCHAR Buffer,
IN ULONG Offset,
IN ULONG Length,
IN FncConfigIO *ConfigIO
)
{
KIRQL OldIrql;
ULONG i;
UCHAR State[20];
PPCIPBUSDATA BusData;
BusData = (PPCIPBUSDATA) BusHandler->BusData;
PCIConfigHandlers.Synchronize (BusHandler, Slot, &OldIrql, State);
while (Length) {
i = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)];
i = ConfigIO[i] (BusData, State, Buffer, Offset);
Offset += i;
Buffer += i;
Length -= i;
}
PCIConfigHandlers.ReleaseSynchronzation (BusHandler, OldIrql);
}
VOID HalpPCISynchronizeType1 (
IN PBUSHANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PKIRQL Irql,
IN PPCI_TYPE1_CFG_BITS PciCfg1
)
{
//
// Initialize PciCfg1
//
PciCfg1->u.AsULONG = 0;
PciCfg1->u.bits.BusNumber = BusHandler->BusNumber;
PciCfg1->u.bits.DeviceNumber = Slot.u.bits.DeviceNumber;
PciCfg1->u.bits.FunctionNumber = Slot.u.bits.FunctionNumber;
PciCfg1->u.bits.Enable = TRUE;
//
// Synchronize with PCI type1 config space
//
//KeAcquireSpinLock (&HalpPCIConfigLock, Irql);
}
VOID HalpPCIReleaseSynchronzationType1 (
IN PBUSHANDLER BusHandler,
IN KIRQL Irql
)
{
PCI_TYPE1_CFG_BITS PciCfg1;
PPCIPBUSDATA BusData;
//
// Disable PCI configuration space
//
PciCfg1.u.AsULONG = 0;
BusData = (PPCIPBUSDATA) BusHandler->BusData;
WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1.u.AsULONG);
//
// Release spinlock
//
//KeReleaseSpinLock (&HalpPCIConfigLock, Irql);
}
ULONG
HalpPCIReadUcharType1 (
IN PPCIPBUSDATA BusData,
IN PPCI_TYPE1_CFG_BITS PciCfg1,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
ULONG i;
i = Offset % sizeof(ULONG);
PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
*Buffer = READ_PORT_UCHAR ((PUCHAR) (BusData->Config.Type1.Data + i));
return sizeof (UCHAR);
}
ULONG
HalpPCIReadUshortType1 (
IN PPCIPBUSDATA BusData,
IN PPCI_TYPE1_CFG_BITS PciCfg1,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
ULONG i;
i = Offset % sizeof(ULONG);
PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
*((PUSHORT) Buffer) = READ_PORT_USHORT ((PUSHORT) (BusData->Config.Type1.Data + i));
return sizeof (USHORT);
}
ULONG
HalpPCIReadUlongType1 (
IN PPCIPBUSDATA BusData,
IN PPCI_TYPE1_CFG_BITS PciCfg1,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
*((PULONG) Buffer) = READ_PORT_ULONG ((PULONG) BusData->Config.Type1.Data);
return sizeof (ULONG);
}
ULONG
HalpPCIWriteUcharType1 (
IN PPCIPBUSDATA BusData,
IN PPCI_TYPE1_CFG_BITS PciCfg1,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
ULONG i;
i = Offset % sizeof(ULONG);
PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
WRITE_PORT_UCHAR ((PUCHAR) (BusData->Config.Type1.Data + i), *Buffer);
return sizeof (UCHAR);
}
ULONG
HalpPCIWriteUshortType1 (
IN PPCIPBUSDATA BusData,
IN PPCI_TYPE1_CFG_BITS PciCfg1,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
ULONG i;
i = Offset % sizeof(ULONG);
PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
WRITE_PORT_USHORT ((PUSHORT) (BusData->Config.Type1.Data + i), *((PUSHORT) Buffer));
return sizeof (USHORT);
}
ULONG
HalpPCIWriteUlongType1 (
IN PPCIPBUSDATA BusData,
IN PPCI_TYPE1_CFG_BITS PciCfg1,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
WRITE_PORT_ULONG ((PULONG) BusData->Config.Type1.Data, *((PULONG) Buffer));
return sizeof (ULONG);
}
VOID HalpPCISynchronizeType2 (
IN PBUSHANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PKIRQL Irql,
IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr
)
{
PCI_TYPE2_CSE_BITS PciCfg2Cse;
PPCIPBUSDATA BusData;
BusData = (PPCIPBUSDATA) BusHandler->BusData;
//
// Initialize Cfg2Addr
//
PciCfg2Addr->u.AsUSHORT = 0;
PciCfg2Addr->u.bits.Agent = (USHORT) Slot.u.bits.DeviceNumber;
PciCfg2Addr->u.bits.AddressBase = (USHORT) BusData->Config.Type2.Base;
//
// Synchronize with type2 config space - type2 config space
// remaps 4K of IO space, so we can not allow other I/Os to occur
// while using type2 config space, hence the disable_interrupts.
//
//KeAcquireSpinLock (&HalpPCIConfigLock, Irql);
//DISABLE_INTERRUPTS (); // is not MP safe
PciCfg2Cse.u.AsUCHAR = 0;
PciCfg2Cse.u.bits.Enable = TRUE;
PciCfg2Cse.u.bits.FunctionNumber = (UCHAR) Slot.u.bits.FunctionNumber;
PciCfg2Cse.u.bits.Key = 0xff;
//
// Select bus & enable type 2 configuration space
//
WRITE_PORT_UCHAR (BusData->Config.Type2.Forward, (UCHAR) BusHandler->BusNumber);
WRITE_PORT_UCHAR (BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
}
VOID HalpPCIReleaseSynchronzationType2 (
IN PBUSHANDLER BusHandler,
IN KIRQL Irql
)
{
PCI_TYPE2_CSE_BITS PciCfg2Cse;
PPCIPBUSDATA BusData;
//
// disable PCI configuration space
//
BusData = (PPCIPBUSDATA) BusHandler->BusData;
PciCfg2Cse.u.AsUCHAR = 0;
WRITE_PORT_UCHAR (BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
//
// Restore interrupts, release spinlock
//
//ENABLE_INTERRUPTS ();
//KeReleaseSpinLock (&HalpPCIConfigLock, Irql);
}
ULONG
HalpPCIReadUcharType2 (
IN PPCIPBUSDATA BusData,
IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
*Buffer = READ_PORT_UCHAR ((PUCHAR) PciCfg2Addr->u.AsUSHORT);
return sizeof (UCHAR);
}
ULONG
HalpPCIReadUshortType2 (
IN PPCIPBUSDATA BusData,
IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
*((PUSHORT) Buffer) = READ_PORT_USHORT ((PUSHORT) PciCfg2Addr->u.AsUSHORT);
return sizeof (USHORT);
}
ULONG
HalpPCIReadUlongType2 (
IN PPCIPBUSDATA BusData,
IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
*((PULONG) Buffer) = READ_PORT_ULONG ((PULONG) PciCfg2Addr->u.AsUSHORT);
return sizeof(ULONG);
}
ULONG
HalpPCIWriteUcharType2 (
IN PPCIPBUSDATA BusData,
IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
WRITE_PORT_UCHAR ((PUCHAR) PciCfg2Addr->u.AsUSHORT, *Buffer);
return sizeof (UCHAR);
}
ULONG
HalpPCIWriteUshortType2 (
IN PPCIPBUSDATA BusData,
IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
WRITE_PORT_USHORT ((PUSHORT) PciCfg2Addr->u.AsUSHORT, *((PUSHORT) Buffer));
return sizeof (USHORT);
}
ULONG
HalpPCIWriteUlongType2 (
IN PPCIPBUSDATA BusData,
IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
IN PUCHAR Buffer,
IN ULONG Offset
)
{
PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
WRITE_PORT_ULONG ((PULONG) PciCfg2Addr->u.AsUSHORT, *((PULONG) Buffer));
return sizeof(ULONG);
}
NTSTATUS
HalpAssignPCISlotResources (
IN ULONG BusNumber,
IN ULONG Slot,
IN OUT PCM_RESOURCE_LIST *pAllocatedResources
)
/*++
Routine Description:
Reads the targeted device to determine it's required resources.
Calls IoAssignResources to allocate them.
Sets the targeted device with it's assigned resoruces
and returns the assignments to the caller.
Arguments:
Return Value:
STATUS_SUCCESS or error
--*/
{
PBUSHANDLER BusHandler;
UCHAR buffer[PCI_COMMON_HDR_LENGTH];
UCHAR buffer2[PCI_COMMON_HDR_LENGTH];
PPCI_COMMON_CONFIG PciData, PciData2;
PCI_SLOT_NUMBER PciSlot;
ULONG i, j, length, type;
PHYSICAL_ADDRESS Address;
PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor;
static PCM_RESOURCE_LIST CmResList;
USHORT NewCommand;
BusHandler = HalpGetPciBusHandler (BusNumber);
if (!BusHandler) {
return 0;
}
*pAllocatedResources = NULL;
PciData = (PPCI_COMMON_CONFIG) buffer;
PciData2 = (PPCI_COMMON_CONFIG) buffer2;
PciSlot = *((PPCI_SLOT_NUMBER) &Slot);
BusNumber = BusHandler->BusNumber;
//
// Read the PCI device's configuration
//
HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
if (PciData->VendorID == PCI_INVALID_VENDORID) {
return STATUS_NO_SUCH_DEVICE;
}
//
// Make a copy of the device's current settings
//
RtlMoveMemory (buffer2, buffer, 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;
NewCommand = PciData->Command;
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);
HalpPCIPin2Line (BusHandler, RootHandler, PciSlot, PciData);
//
// Restore the device's settings in case we don't complete
//
HalpWritePCIConfig (BusHandler, PciSlot, buffer2, 0, PCI_COMMON_HDR_LENGTH);
//
// Build a CmResource descriptor list for the device
//
if (!CmResList) {
// NtLdr pool is only allocated and never freed. Allocate the
// buffer once, and from then on just use the buffer over
CmResList = ExAllocatePool (PagedPool,
sizeof (CM_RESOURCE_LIST) +
sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2)
);
}
if (!CmResList) {
return STATUS_NO_MEMORY;
}
RtlZeroMemory (CmResList,
sizeof (CM_RESOURCE_LIST) +
sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2)
);
*pAllocatedResources = CmResList;
CmResList->List[0].InterfaceType = PCIBus;
CmResList->List[0].BusNumber = BusNumber;
CmDescriptor = CmResList->List[0].PartialResourceList.PartialDescriptors;
if (PciData->u.type0.InterruptPin) {
CmDescriptor->Type = CmResourceTypeInterrupt;
CmDescriptor->ShareDisposition = CmResourceShareShared;
CmDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
// in the loader interrupts aren't actually enabled, so just
// pass back the untranslated values
CmDescriptor->u.Interrupt.Level = PciData->u.type0.InterruptLine;
CmDescriptor->u.Interrupt.Vector = PciData->u.type0.InterruptLine;
CmDescriptor->u.Interrupt.Affinity = 1;
CmResList->List[0].PartialResourceList.Count++;
CmDescriptor++;
}
// clear last address index + 1
PciData->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES] = 0;
if (PciData2->u.type0.ROMBaseAddress & PCI_ROMADDRESS_ENABLED) {
// put rom address in last index+1
PciData->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES] =
PciData->u.type0.ROMBaseAddress & ~PCI_ADDRESS_IO_SPACE;
PciData2->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES] =
PciData2->u.type0.ROMBaseAddress & ~PCI_ADDRESS_IO_SPACE;
}
for (j=0; j < PCI_TYPE0_ADDRESSES + 1; j++) {
if (PciData->u.type0.BaseAddresses[j]) {
i = PciData->u.type0.BaseAddresses[j];
//
// Make sure the appropriate decode is turned on for this BAR.
//
if (i & PCI_ADDRESS_IO_SPACE) {
NewCommand |= PCI_ENABLE_IO_SPACE;
} else {
NewCommand |= PCI_ENABLE_MEMORY_SPACE;
}
// scan for first set bit, that's the length & alignment
length = 1 << (i & PCI_ADDRESS_IO_SPACE ? 2 : 4);
Address.HighPart = 0;
Address.LowPart = PciData2->u.type0.BaseAddresses[j] & ~(length-1);
while (!(i & length) && length) {
length <<= 1;
}
// translate bus specific address
type = (i & PCI_ADDRESS_IO_SPACE) ? 0 : 1;
if (!HalTranslateBusAddress (
PCIBus,
BusNumber,
Address,
&type,
&Address )) {
// translation failed, skip it
continue;
}
// fill in CmDescriptor to return
if (type == 0) {
CmDescriptor->Type = CmResourceTypePort;
CmDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
CmDescriptor->Flags = CM_RESOURCE_PORT_IO;
CmDescriptor->u.Port.Length = length;
CmDescriptor->u.Port.Start = Address;
} else {
CmDescriptor->Type = CmResourceTypeMemory;
CmDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
CmDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
CmDescriptor->u.Memory.Length = length;
CmDescriptor->u.Memory.Start = Address;
if (j == PCI_TYPE0_ADDRESSES) {
// this is a ROM address
CmDescriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY;
}
}
CmResList->List[0].PartialResourceList.Count++;
CmDescriptor++;
if (i & PCI_TYPE_64BIT) {
// skip upper half of 64 bit address.
j++;
}
}
}
//
// If any decodes need to be turned on, do this now.
//
if (NewCommand != PciData2->Command) {
HalpWritePCIConfig(BusHandler,
PciSlot,
&NewCommand,
FIELD_OFFSET(PCI_COMMON_CONFIG, Command),
sizeof(NewCommand));
}
return STATUS_SUCCESS;
}