2020-09-30 17:12:29 +02:00

898 lines
23 KiB
C

/*++
Copyright (c) 1995 DeskStation Technology
Module Name:
pcisup.c
Abstract:
This module contains the routines that support PCI configuration cycles
and PCI interrupts.
Author:
Michael D. Kinney 30-Apr-1995
Environment:
Kernel mode
Revision History:
--*/
#include "halp.h"
#include "pci.h"
#include "pcip.h"
#define INVALID_PCI_CONFIGURATION_ADDRESS (0xffffff00)
#define NO_PCI_DEVSEL_DATA_VALUE (0xffffffff)
//
// The following tables are used to map between PCI interrupt pins, PCI interrupt lines,
// and virtual ISA interrupt indexes. The Uniflex architecture uses a 16 bit interrupt
// controller for ISA interrupts and all PCI interrupts. An InterruptLine value of 0x20
// is reserved for the ISA PIC. InterruptLine values between 0x10 and 0x20 are reserved
// for PCI devices. InterruptLine values between 0x00 and 0x0f are reserved for ISA IRQs.
//
UCHAR Treb13InterruptLineToBit[0x11] = {7,2,3,1,4,5,6,9,10,11,16,16,16,16,15,14,0};
UCHAR Treb13BitToInterruptLine[0x10] = {0x10,0x03,0x01,0x02,0x04,0x05,0x06,0x00,0x00,0x07,0x08,0x09,0x00,0x00,0x0f,0x0e};
UCHAR Treb13InterruptLineToVirtualIsa[0x10] = {0,1,2,3,8,9,10,11,4,5,0,0,0,0,0,0};
UCHAR Treb13VirtualIsaToInterruptLine[0x10] = {0x10,0x11,0x12,0x13,0x18,0x19,0,0,0x14,0x15,0x16,0x17,0,0,0,0};
UCHAR Treb20InterruptLineToBit[0x11] = {1,2,3,4,5,6,7,8,9,16,16,16,16,16,16,16,0};
UCHAR Treb20BitToInterruptLine[0x10] = {0x10,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00};
UCHAR Treb20InterruptLineToVirtualIsa[0x11] = {0,1,2,3,4,5,6,7,8,0,0,0,0,0,0,0,9};
UCHAR Treb20VirtualIsaToInterruptLine[0x10] = {0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x20,0,0,0,0,0,0};
//
// Interrupt mask for all active PCI interrupts including ISA Bus PICs
//
static volatile ULONG HalpPciInterruptMask;
//
// Interrupt mask for PCI interrupts that have been connected through device drivers.
//
static volatile ULONG HalpPciDeviceInterruptMask;
//
// Interrupt mask showing which bit cooresponds to ISA Bus #0 PIC
//
static volatile ULONG HalpEisaInterruptMask;
//
// Interrupt mask showing which bit cooresponds to ISA Bus #1 PIC
//
static volatile ULONG HalpEisa1InterruptMask;
VOID
HalpWritePciInterruptRegister(
VOID
)
/*++
Routine Description:
This function writes the interrupt mask register for PCI interrupts.
Arguments:
None.
Return Value:
None.
--*/
{
if (HalpIoArchitectureType == EV5_PROCESSOR_MODULE) {
HalpWriteAbsoluteUlong(0xfffffca8,0x00000010, (HalpPciInterruptMask & 0xff) << 8);
HalpWriteAbsoluteUlong(0xfffffc88,0x00000010, HalpPciInterruptMask & 0xff00);
} else {
HalpWriteAbsoluteUlong(0xfffffc03,0x2000000c, HalpPciInterruptMask & 0xff);
HalpWriteAbsoluteUlong(0xfffffc03,0x6000000c, HalpPciInterruptMask >> 8);
}
}
ULONG
HalpReadPciInterruptRegister(
VOID
)
/*++
Routine Description:
This function reads the interrupt status register for PCI interrupts.
Arguments:
None.
Return Value:
The lower 16 bits contains the status of each interrupt line going to the PCI
interrupt controller.
--*/
{
if (HalpIoArchitectureType == EV5_PROCESSOR_MODULE) {
return ( ((HalpReadAbsoluteUlong(0xfffffca8,0x00000000)>>8)&0xff) |
(HalpReadAbsoluteUlong(0xfffffc88,0x00000000) & 0xff00) );
} else {
return ( (HalpReadAbsoluteUlong(0xfffffc03,0x2000000c) &0xff) |
((HalpReadAbsoluteUlong(0xfffffc03,0x6000000c)<<8) & 0xff00) );
}
}
ULONG
HalpGetModuleChipSetRevision(
VOID
)
/*++
Routine Description:
This function identifies the chip set revision of the processor module installed in the
system.
Arguments:
None.
Return Value:
The chip set revision.
--*/
{
ULONG Temp;
ULONG ReturnValue;
if (HalpIoArchitectureType == EV5_PROCESSOR_MODULE) {
Temp = HalpPciInterruptMask;
HalpPciInterruptMask = 0;
HalpWritePciInterruptRegister();
ReturnValue = (HalpReadPciInterruptRegister() >> 4) & 0x0f;
HalpPciInterruptMask = Temp;
HalpWritePciInterruptRegister();
}
if (HalpIoArchitectureType == EV4_PROCESSOR_MODULE) {
ReturnValue = HalpReadAbsoluteUlong(0xfffffc03,0xe000000c);
ReturnValue = (ReturnValue & 0x0f) ^ ((ReturnValue >> 4) & 0x0f);
}
return(ReturnValue);
}
VOID
HalpSetPciInterruptBit (
ULONG Bit
)
/*++
Routine Description:
This function sets a bit in the PCI interrupt mask and writes the new mask
to the interrupt controller.
Arguments:
Bit - The bit number to set in the PCI interrupt mask.
Return Value:
None.
--*/
{
HalpPciDeviceInterruptMask = HalpPciDeviceInterruptMask | (1<<Bit);
HalpPciInterruptMask = HalpPciInterruptMask | (1<<Bit);
HalpWritePciInterruptRegister();
}
VOID
HalpClearPciInterruptBit (
ULONG Bit
)
/*++
Routine Description:
This function clears a bit in the PCI interrupt mask and writes the new mask
to the interrupt controller.
Arguments:
Bit - The bit number to clear from the PCI interrupt mask.
Return Value:
None.
--*/
{
HalpPciDeviceInterruptMask = HalpPciDeviceInterruptMask & ~(1<<Bit);
HalpPciInterruptMask = HalpPciInterruptMask & ~(1<<Bit);
HalpWritePciInterruptRegister();
}
VOID
HalpEnablePciInterrupt (
IN ULONG Vector
)
/*++
Routine Description:
This function enables a PCI interrupt.
Arguments:
Vector - Specifies the interrupt to enable.
Return Value:
None.
--*/
{
if (Vector >= UNIFLEX_PCI_VECTORS && Vector <= UNIFLEX_MAXIMUM_PCI_VECTOR) {
HalpSetPciInterruptBit(HalpInterruptLineToBit[Vector-UNIFLEX_PCI_VECTORS]);
}
}
VOID
HalpDisablePciInterrupt (
IN ULONG Vector
)
/*++
Routine Description:
This function disables a PCI interrupt.
Arguments:
Vector - Specifies the interrupt to disable.
Return Value:
None.
--*/
{
if (Vector >= UNIFLEX_PCI_VECTORS && Vector <= UNIFLEX_MAXIMUM_PCI_VECTOR) {
HalpClearPciInterruptBit(HalpInterruptLineToBit[Vector-UNIFLEX_PCI_VECTORS]);
}
}
ULONG
HalpVirtualIsaInterruptToInterruptLine (
IN ULONG Index
)
/*++
Routine Description:
This function maps a virtual ISA interrupt to a PCI interrupt line value.
This provides the ability to use an ISA device driver on a PCI device.
Arguments:
Index - Index into a platform specific table that maps PCI interrupts to
virtual ISA interrupts.
Return Value:
None.
--*/
{
return(HalpVirtualIsaToInterruptLine[Index]);
}
ULONG HalpClearLockCacheLineAddress[32];
BOOLEAN
HalpPciDispatch(
IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext
)
/*++
Routine Description:
This is the interrupt dispatcher for all PCI interrupts.
Arguments:
Interrupt - Supplies a pointer to the interrupt object.
ServiceContext - not used.
Return Value:
Returns the value returned from the second level routine.
--*/
{
ULONG PciInterruptStatus;
PULONG dispatchCode;
PKINTERRUPT interruptObject;
USHORT PCRInOffset;
BOOLEAN returnValue = FALSE;
ULONG i;
if (HalpIoArchitectureType != EV5_PROCESSOR_MODULE) {
Halp21064ClearLockRegister(&(HalpClearLockCacheLineAddress[16]));
}
//
// Get the active interrupt bits
//
PciInterruptStatus = HalpReadPciInterruptRegister();
//
// See if this is the interrupt for ISA Bus #0 PIC
//
if (PciInterruptStatus & HalpEisaInterruptMask) {
returnValue = HalpEisaDispatch(Interrupt,ServiceContext,0);
//
// If there really was an interrupt on ISA Bus #0, then return now.
//
if (returnValue) {
return(returnValue);
}
}
//
// See if this is the interrupt for ISA Bus #1 PIC
//
if (PciInterruptStatus & HalpEisa1InterruptMask) {
returnValue = HalpEisaDispatch(Interrupt,ServiceContext,1);
//
// If there really was an interrupt on ISA Bus #1, then return now.
//
if (returnValue) {
return(returnValue);
}
}
//
// Only keep interrupt bits that have been connected by device drivers.
//
PciInterruptStatus &= HalpPciDeviceInterruptMask;
//
// Dispatch to the ISRs of interrupts that have been connected by device drivers.
//
for(i=0;i<16;i++) {
if (PciInterruptStatus & (1<<i)) {
PCRInOffset = UNIFLEX_PCI_VECTORS + HalpBitToInterruptLine[i];
//
// Dispatch to the secondary interrupt service routine.
//
dispatchCode = (PULONG)(PCR->InterruptRoutine[PCRInOffset]);
interruptObject = CONTAINING_RECORD(dispatchCode,
KINTERRUPT,
DispatchCode);
returnValue =
((PSECONDARY_DISPATCH)interruptObject->DispatchAddress)
(interruptObject);
}
}
return(returnValue);
}
UCHAR HalpGetInterruptLine(ULONG BusNumber,ULONG DeviceNumber,ULONG InterruptPin)
/*++
Routine Description:
This routine maps a PCI interrupt described by the device's bus number, device number, and
interrupt pin into the interrupt line value that is stored in the PCI config header.
Arguments:
BusNumber - PCI bus number of the device.
DeviceNumber - PCI device number of the device.
InterruptPin - PCI interrupt pin of the device (A=1,B=2,C=3,D=4).
Return Value:
Returns the PCI Interrupt Line value for the PCI device.
--*/
{
UCHAR InterruptLine;
if (HalpMotherboardType == TREBBIA13) {
if (BusNumber > 1)
{
BusNumber = 1;
}
switch (BusNumber<<16 | DeviceNumber<<8 | InterruptPin) {
case 0x010401 : InterruptLine = 0x10; break; // Bus 1, Device 4, Int A
case 0x010601 : InterruptLine = 0x11; break; // Bus 1, Device 6, Int A
case 0x010501 : InterruptLine = 0x12; break; // Bus 1, Device 5, Int A
case 0x010701 : InterruptLine = 0x13; break; // Bus 1, Device 7, Int A
case 0x010402 : InterruptLine = 0x17; break; // Bus 1, Device 4, Int B
case 0x010602 : InterruptLine = 0x14; break; // Bus 1, Device 6, Int B
case 0x010502 : InterruptLine = 0x14; break; // Bus 1, Device 5, Int B
case 0x010702 : InterruptLine = 0x17; break; // Bus 1, Device 7, Int B
case 0x010403 : InterruptLine = 0x18; break; // Bus 1, Device 4, Int C
case 0x010603 : InterruptLine = 0x15; break; // Bus 1, Device 6, Int C
case 0x010503 : InterruptLine = 0x15; break; // Bus 1, Device 5, Int C
case 0x010703 : InterruptLine = 0x18; break; // Bus 1, Device 7, Int C
case 0x010404 : InterruptLine = 0x19; break; // Bus 1, Device 4, Int D
case 0x010604 : InterruptLine = 0x16; break; // Bus 1, Device 6, Int D
case 0x010504 : InterruptLine = 0x16; break; // Bus 1, Device 5, Int D
case 0x010704 : InterruptLine = 0x19; break; // Bus 1, Device 7, Int D
case 0x000d01 : InterruptLine = 0x1e; break; // Bus 0, Device 13, Int A
case 0x000f01 : InterruptLine = 0x1f; break; // Bus 0, Device 15, Int A
case 0x001001 : InterruptLine = 0x20; break; // Bus 0, Device 16, Int A
default : InterruptLine = 0xff; break;
}
}
if (HalpMotherboardType == TREBBIA20) {
if (BusNumber == 0) {
return(0xff);
}
if (BusNumber >= HalpSecondPciBridgeBusNumber) {
BusNumber = 1;
} else {
BusNumber = 0;
}
switch (BusNumber<<16 | DeviceNumber<<8 | InterruptPin) {
case 0x000401 : InterruptLine = 0x20; break;
case 0x000501 :
case 0x000603 :
case 0x000704 : InterruptLine = 0x10; break;
case 0x000502 :
case 0x000604 :
case 0x000701 : InterruptLine = 0x11; break;
case 0x000503 :
case 0x000601 :
case 0x000702 : InterruptLine = 0x12; break;
case 0x000504 :
case 0x000602 :
case 0x000703 : InterruptLine = 0x13; break;
case 0x010401 :
case 0x010504 :
case 0x010603 : InterruptLine = 0x14; break;
case 0x010402 :
case 0x010501 :
case 0x010604 : InterruptLine = 0x15; break;
case 0x010403 :
case 0x010502 :
case 0x010601 : InterruptLine = 0x16; break;
case 0x010404 :
case 0x010503 :
case 0x010602 : InterruptLine = 0x17; break;
case 0x010701 : InterruptLine = 0x18; break;
default : InterruptLine = 0xff; break;
}
}
return(InterruptLine);
}
VOID
HalpConnectInterruptDispatchers(
VOID
)
/*++
Routine Description:
This function connects the PCI interrupt dispatch routine and enables
ISA interrupts so they will generate processor interrupts.
Arguments:
None.
Return Value:
None.
--*/
{
UCHAR InterruptLine;
if (HalpIoArchitectureType == EV5_PROCESSOR_MODULE) {
PCR->InterruptRoutine[22] = (PKINTERRUPT_ROUTINE)HalpPciDispatch;
} else {
PCR->InterruptRoutine[14] = (PKINTERRUPT_ROUTINE)HalpPciDispatch;
}
//DbgPrint("Intel82378 : Bus=%d Device=%d\n\r",HalpIntel82378BusNumber,HalpIntel82378DeviceNumber);
//DbgPrint("SecondIntel82378 : Bus=%d Device=%d\n\r",HalpSecondPciBridgeBusNumber,HalpSecondIntel82378DeviceNumber);
InterruptLine = HalpGetInterruptLine(HalpIntel82378BusNumber,HalpIntel82378DeviceNumber,1);
HalpEisaInterruptMask = 0x0000;
if (InterruptLine != 0xff) {
HalpEisaInterruptMask = (1 << HalpInterruptLineToBit[InterruptLine-0x10]) & 0xffff;
}
InterruptLine = HalpGetInterruptLine(HalpSecondPciBridgeBusNumber,HalpSecondIntel82378DeviceNumber,1);
HalpEisa1InterruptMask = 0x0000;
if (InterruptLine != 0xff) {
HalpEisa1InterruptMask = (1 << HalpInterruptLineToBit[InterruptLine-0x10]) & 0xffff;
}
//DbgPrint("HalpEisaInterruptMask = %08x\n\r",HalpEisaInterruptMask);
//DbgPrint("HalpEisa1InterruptMask = %08x\n\r",HalpEisa1InterruptMask);
//
// Enable ISA Interrupts on Apocolypse's PIC
//
HalpPciDeviceInterruptMask = 0x0000;
HalpPciInterruptMask = HalpEisaInterruptMask | HalpEisa1InterruptMask;
HalpWritePciInterruptRegister();
}
VOID
HalpDisableAllInterrupts(
VOID
)
/*++
Routine Description:
This function disables all external interrupt sources.
Arguments:
None.
Return Value:
None.
--*/
{
ULONG i;
//
// Mask off all ISA Interrupts
//
for(i=0;i<HalpNumberOfIsaBusses;i++) {
WRITE_REGISTER_UCHAR((PUCHAR)((ULONG)HalpEisaControlBase[i]+0x21),0xff);
WRITE_REGISTER_UCHAR((PUCHAR)((ULONG)HalpEisaControlBase[i]+0xa1),0xff);
}
//
// Mask off all PCI Interrupts
//
HalpPciDeviceInterruptMask = 0x0000;
HalpPciInterruptMask = 0x0000;
HalpWritePciInterruptRegister();
}
PCI_CONFIGURATION_TYPES
HalpPCIConfigCycleType (IN ULONG BusNumber)
{
if (BusNumber == 0) {
return PciConfigType0;
} else if (BusNumber < PCIMaxBus) {
return PciConfigType1;
} else {
return PciConfigTypeInvalid;
}
}
VOID
HalpPCIConfigAddr (
IN ULONG BusNumber,
IN PCI_SLOT_NUMBER Slot,
PPCI_CFG_CYCLE_BITS pPciAddr
)
{
PCI_CONFIGURATION_TYPES ConfigType;
ConfigType = HalpPCIConfigCycleType(BusNumber);
if (ConfigType == PciConfigType0) {
//
// Initialize PciAddr for a type 0 configuration cycle
//
//
// See if this is a nonexistant device on PCI Bus 0
//
if ( (1 << Slot.u.bits.DeviceNumber) & HalpNonExistentPciDeviceMask ) {
pPciAddr->u.AsULONG = INVALID_PCI_CONFIGURATION_ADDRESS;
return;
}
if (HalpIoArchitectureType == EV5_PROCESSOR_MODULE) {
pPciAddr->u.AsULONG = 1 << (3 + Slot.u.bits.DeviceNumber);
} else {
pPciAddr->u.AsULONG = 1 << (11 + Slot.u.bits.DeviceNumber);
}
pPciAddr->u.bits0.FunctionNumber = Slot.u.bits.FunctionNumber;
pPciAddr->u.bits0.Reserved1 = PciConfigType0;
if (HalpIoArchitectureType == EV4_PROCESSOR_MODULE) {
pPciAddr->u.AsULONG &= 0x01ffffff;
pPciAddr->u.AsULONG += (ULONG)HAL_MAKE_QVA(HalpPciConfig0BasePhysical);
if (Slot.u.bits.DeviceNumber >= 14 && Slot.u.bits.DeviceNumber <= 19) {
pPciAddr->u.AsULONG += (Slot.u.bits.DeviceNumber-13) << 25;
}
}
} else {
//
// See if this is a nonexistant PCI device on the otherside of the First PCI-PCI Bridge
//
if (BusNumber == 1 && (1 << Slot.u.bits.DeviceNumber) & HalpNonExistentPci1DeviceMask) {
pPciAddr->u.AsULONG = INVALID_PCI_CONFIGURATION_ADDRESS;
return;
}
//
// See if this is a nonexistant PCI device on the otherside of the Second PCI-PCI Bridge
//
if (BusNumber == HalpSecondPciBridgeBusNumber && (1 << Slot.u.bits.DeviceNumber) & HalpNonExistentPci2DeviceMask) {
pPciAddr->u.AsULONG = INVALID_PCI_CONFIGURATION_ADDRESS;
return;
}
//
// Initialize PciAddr for a type 1 configuration cycle
//
pPciAddr->u.AsULONG = 0;
if (HalpIoArchitectureType == EV4_PROCESSOR_MODULE) {
pPciAddr->u.AsULONG = (ULONG)HAL_MAKE_QVA(HalpPciConfig1BasePhysical);
}
pPciAddr->u.bits1.BusNumber = BusNumber;
pPciAddr->u.bits1.FunctionNumber = Slot.u.bits.FunctionNumber;
pPciAddr->u.bits1.DeviceNumber = Slot.u.bits.DeviceNumber;
pPciAddr->u.bits1.Reserved1 = PciConfigType1;
}
return;
}
ULONG READ_CONFIG_Ux(
IN PVOID ConfigurationAddress,
IN ULONG ConfigurationType,
IN ULONG Offset
)
{
switch(ConfigurationType) {
case PciConfigType0 :
return(HalpReadAbsoluteUlong((ULONG)(HalpPciConfig0BasePhysical >> 32),
(ULONG)HalpPciConfig0BasePhysical + ((ULONG)ConfigurationAddress << IO_BIT_SHIFT) + Offset));
case PciConfigType1 :
return(HalpReadAbsoluteUlong((ULONG)(HalpPciConfig1BasePhysical >> 32),
(ULONG)HalpPciConfig1BasePhysical + ((ULONG)ConfigurationAddress << IO_BIT_SHIFT) + Offset));
}
return(NO_PCI_DEVSEL_DATA_VALUE);
}
VOID WRITE_CONFIG_Ux(
IN PVOID ConfigurationAddress,
IN ULONG ConfigurationType,
IN ULONG Offset,
IN ULONG Value
)
{
switch(ConfigurationType) {
case PciConfigType0 :
HalpWriteAbsoluteUlong((ULONG)(HalpPciConfig0BasePhysical >> 32),
(ULONG)HalpPciConfig0BasePhysical + ((ULONG)ConfigurationAddress << IO_BIT_SHIFT) + Offset,
Value);
break;
case PciConfigType1 :
HalpWriteAbsoluteUlong((ULONG)(HalpPciConfig1BasePhysical >> 32),
(ULONG)HalpPciConfig1BasePhysical + ((ULONG)ConfigurationAddress << IO_BIT_SHIFT) + Offset,
Value);
break;
}
}
UCHAR
READ_CONFIG_UCHAR(
IN PVOID ConfigurationAddress,
IN ULONG ConfigurationType
)
{
if (((ULONG)ConfigurationAddress & 0xffffff00) == INVALID_PCI_CONFIGURATION_ADDRESS) {
return((UCHAR)NO_PCI_DEVSEL_DATA_VALUE);
}
if (HalpIoArchitectureType == EV5_PROCESSOR_MODULE) {
return((UCHAR)(READ_CONFIG_Ux(ConfigurationAddress,ConfigurationType,IO_BYTE_LEN) >> (8*((ULONG)ConfigurationAddress & 0x03))));
} else {
return(READ_REGISTER_UCHAR(ConfigurationAddress));
}
}
USHORT
READ_CONFIG_USHORT(
IN PVOID ConfigurationAddress,
IN ULONG ConfigurationType
)
{
if (((ULONG)ConfigurationAddress & 0xffffff00) == INVALID_PCI_CONFIGURATION_ADDRESS) {
return((USHORT)NO_PCI_DEVSEL_DATA_VALUE);
}
if (HalpIoArchitectureType == EV5_PROCESSOR_MODULE) {
return((USHORT)(READ_CONFIG_Ux(ConfigurationAddress,ConfigurationType,IO_WORD_LEN) >> (8*((ULONG)ConfigurationAddress & 0x03))));
} else {
return(READ_REGISTER_USHORT(ConfigurationAddress));
}
}
ULONG
READ_CONFIG_ULONG(
IN PVOID ConfigurationAddress,
IN ULONG ConfigurationType
)
{
if (((ULONG)ConfigurationAddress & 0xffffff00) == INVALID_PCI_CONFIGURATION_ADDRESS) {
return((ULONG)NO_PCI_DEVSEL_DATA_VALUE);
}
if (HalpIoArchitectureType == EV5_PROCESSOR_MODULE) {
return(READ_CONFIG_Ux(ConfigurationAddress,ConfigurationType,IO_LONG_LEN) >> (8*((ULONG)ConfigurationAddress & 0x03)));
} else {
return(READ_REGISTER_ULONG(ConfigurationAddress));
}
}
VOID
WRITE_CONFIG_UCHAR(
IN PVOID ConfigurationAddress,
IN UCHAR ConfigurationData,
IN ULONG ConfigurationType
)
{
if (((ULONG)ConfigurationAddress & 0xffffff00) != INVALID_PCI_CONFIGURATION_ADDRESS) {
if (HalpIoArchitectureType == EV5_PROCESSOR_MODULE) {
WRITE_CONFIG_Ux(ConfigurationAddress,ConfigurationType,IO_BYTE_LEN,(ULONG)ConfigurationData << (8*((ULONG)ConfigurationAddress & 0x03)));
} else {
WRITE_REGISTER_UCHAR(ConfigurationAddress,ConfigurationData);
}
}
}
VOID
WRITE_CONFIG_USHORT(
IN PVOID ConfigurationAddress,
IN USHORT ConfigurationData,
IN ULONG ConfigurationType
)
{
if (((ULONG)ConfigurationAddress & 0xffffff00) != INVALID_PCI_CONFIGURATION_ADDRESS) {
if (HalpIoArchitectureType == EV5_PROCESSOR_MODULE) {
WRITE_CONFIG_Ux(ConfigurationAddress,ConfigurationType,IO_WORD_LEN,(ULONG)ConfigurationData << (8*((ULONG)ConfigurationAddress & 0x03)));
} else {
WRITE_REGISTER_USHORT(ConfigurationAddress,ConfigurationData);
}
}
}
VOID
WRITE_CONFIG_ULONG(
IN PVOID ConfigurationAddress,
IN ULONG ConfigurationData,
IN ULONG ConfigurationType
)
{
if (((ULONG)ConfigurationAddress & 0xffffff00) != INVALID_PCI_CONFIGURATION_ADDRESS) {
if (HalpIoArchitectureType == EV5_PROCESSOR_MODULE) {
WRITE_CONFIG_Ux(ConfigurationAddress,ConfigurationType,IO_LONG_LEN,ConfigurationData << (8*((ULONG)ConfigurationAddress & 0x03)));
} else {
WRITE_REGISTER_ULONG(ConfigurationAddress,ConfigurationData);
}
}
}
ULONG HalpPciLowLevelConfigRead(
ULONG BusNumber,
ULONG DeviceNumber,
ULONG FunctionNumber,
ULONG Register
)
{
PCI_SLOT_NUMBER SlotNumber;
PCI_CFG_CYCLE_BITS PciCfg;
ULONG ConfigurationCycleType;
SlotNumber.u.AsULONG = 0;
SlotNumber.u.bits.DeviceNumber = DeviceNumber;
SlotNumber.u.bits.FunctionNumber = FunctionNumber;
HalpPCIConfigAddr(BusNumber,SlotNumber,&PciCfg);
ConfigurationCycleType = PciCfg.u.bits.Reserved1;
PciCfg.u.bits.Reserved1 = 0;
PciCfg.u.bits0.RegisterNumber = Register>>2;
return(READ_CONFIG_ULONG((PVOID)PciCfg.u.AsULONG,ConfigurationCycleType));
}