summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halflex/mips/pcisup.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/nthals/halflex/mips/pcisup.c')
-rw-r--r--private/ntos/nthals/halflex/mips/pcisup.c1008
1 files changed, 1008 insertions, 0 deletions
diff --git a/private/ntos/nthals/halflex/mips/pcisup.c b/private/ntos/nthals/halflex/mips/pcisup.c
new file mode 100644
index 000000000..117a85228
--- /dev/null
+++ b/private/ntos/nthals/halflex/mips/pcisup.c
@@ -0,0 +1,1008 @@
+/*++
+
+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 2-May-1995
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+#include "pci.h"
+#include "pcip.h"
+
+#define SP_VIRTUAL_BASE 0xffffa000
+
+#define INVALID_PCI_CONFIGURATION_ADDRESS (0x00000000)
+#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.
+// InterruptLine values between 0x10 and 0x20 are reserved
+// for PCI devices. InterruptLine values between 0x00 and 0x10 are reserved for ISA IRQs.
+//
+
+UCHAR Treb13InterruptLineToBit[0x11] = {0,1,2,3,8,9,10,11,12,12,12,12,12,12,4,5,12};
+UCHAR Treb13BitToInterruptLine[12] = {0x00,0x01,0x02,0x03,0x0e,0x0f,0x00,0x00,0x04,0x05,0x06,0x07};
+UCHAR Treb13InterruptLineToVirtualIsa[0x11] = {0,1,2,3,8,9,10,11,0,0,0,0,0,0,0,0,0};
+UCHAR Treb13VirtualIsaToInterruptLine[0x10] = {0x10,0x11,0x12,0x13,0,0,0,0,0x14,0x15,0x16,0x17,0,0,0,0};
+
+UCHAR Treb20InterruptLineToBit[0x11] = {3,1,2,8,9,10,0,5,11,12,12,12,12,12,12,12,12};
+UCHAR Treb20BitToInterruptLine[12] = {0x06,0x01,0x02,0x00,0x00,0x07,0x00,0x00,0x03,0x04,0x05,0x08};
+UCHAR Treb20InterruptLineToVirtualIsa[0x11] = {0,1,2,3,8,9,10,11,0,0,0,0,0,0,0,0,0};
+UCHAR Treb20VirtualIsaToInterruptLine[0x10] = {0x10,0x11,0x12,0x13,0,0,0,0,0x14,0x15,0x16,0x17,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;
+
+PVOID HalpAllocateIoMapping(
+ LONGLONG BaseAddress
+ )
+
+{
+ ENTRYLO HalpPte[2];
+ ULONG KdPortEntry;
+
+ //
+ // Map the PCI Configuration register into the system virtual address space by loading
+ // a TB entry.
+ //
+
+ HalpPte[0].PFN = (ULONG)(BaseAddress >> 12);
+ HalpPte[0].G = 1;
+ HalpPte[0].V = 1;
+ HalpPte[0].D = 1;
+
+ //
+ // Allocate a TB entry, set the uncached policy in the PTE that will
+ // map the serial controller, and initialize the second PTE.
+ //
+
+ KdPortEntry = HalpAllocateTbEntry();
+ HalpPte[0].C = UNCACHED_POLICY;
+
+ HalpPte[1].PFN = 0;
+ HalpPte[1].G = 1;
+ HalpPte[1].V = 0;
+ HalpPte[1].D = 0;
+ HalpPte[1].C = 0;
+
+ //
+ // Map the PCI Configuration register through a fixed TB entry.
+ //
+
+ KeFillFixedEntryTb((PHARDWARE_PTE)&HalpPte[0],
+ (PVOID)SP_VIRTUAL_BASE,
+ KdPortEntry);
+
+
+ return((PVOID)(SP_VIRTUAL_BASE + (ULONG)(BaseAddress & 0xfff)));
+}
+
+VOID HalpFreeIoMapping(
+ VOID
+ )
+
+{
+ HalpFreeTbEntry();
+}
+
+VOID
+HalpWritePciInterruptMask (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function writes the interrupt mask register for PCI interrupts.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ WRITE_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x00,HalpPciInterruptMask&0x0f);
+ WRITE_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x08,(HalpPciInterruptMask>>4)&0x0f);
+ WRITE_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x10,(HalpPciInterruptMask>>8)&0x0f);
+}
+
+ULONG
+HalpReadPciInterruptStatus (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function reads the interrupt status register for PCI interrupts.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The lower 12 bits contain the status of each interrupt line going to the PCI
+ interrupt controller.
+
+--*/
+
+{
+ return( (READ_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x00)<<0) & 0x00f |
+ (READ_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x08)<<4) & 0x030 |
+ (READ_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x10)<<8) & 0xf00 );
+}
+
+ULONG
+HalpGetMemoryMode (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the status of the MemoryMode bit that is embedded within
+ the PCI interrupt controller. The status of this bit must be preserved on all
+ writes to the PCI interrupt mask register.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ return( (READ_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x08) & 0x08) << 4 );
+}
+
+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.
+
+--*/
+
+{
+ if (Bit==6 || Bit==7 || Bit>=12) {
+ return;
+ }
+ HalpPciDeviceInterruptMask = HalpPciDeviceInterruptMask | (1<<Bit);
+ HalpPciInterruptMask = HalpPciInterruptMask | (1<<Bit);
+ HalpWritePciInterruptMask();
+}
+
+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.
+
+--*/
+
+{
+ if (Bit==6 || Bit==7 || Bit>=12) {
+ return;
+ }
+ HalpPciDeviceInterruptMask = HalpPciDeviceInterruptMask & ~(1<<Bit);
+ HalpPciInterruptMask = HalpPciInterruptMask & ~(1<<Bit);
+ HalpWritePciInterruptMask();
+}
+
+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]);
+}
+
+BOOLEAN
+HalpEisa0Dispatch(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt dispatcher for all ISA Bus #0 interrupts.
+
+Arguments:
+
+ Interrupt - Supplies a pointer to the interrupt object.
+
+ ServiceContext - not used.
+
+Return Value:
+
+ Returns the value returned from the second level routine.
+
+--*/
+
+{
+ return(HalpEisaDispatch(Interrupt,ServiceContext,0));
+}
+
+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;
+
+ //
+ // Get the active interrupt bits
+ //
+
+ PciInterruptStatus = HalpReadPciInterruptStatus();
+
+ //
+ // 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<12;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 = 0x15; 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 = 0x15; break; // Bus 1, Device 7, Int C
+ case 0x010404 : InterruptLine = 0x16; 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 = 0x16; 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;
+
+ //
+ // Initialize the EISA interrupt dispatcher and the PCI interrupt dispatcher
+ //
+
+ PCR->InterruptRoutine[UNIFLEX_PCI_DEVICE_LEVEL] = (PKINTERRUPT_ROUTINE)HalpPciDispatch;
+ PCR->InterruptRoutine[UNIFLEX_EISA_DEVICE_LEVEL] = (PKINTERRUPT_ROUTINE)HalpEisa0Dispatch;
+
+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 Gambit's PIC
+ //
+
+ HalpPciInterruptMask = HalpGetMemoryMode();
+ HalpPciInterruptMask |= (HalpEisaInterruptMask | HalpEisa1InterruptMask);
+ HalpWritePciInterruptMask();
+}
+
+VOID
+HalpDisableAllInterrupts(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function disables all external interrupt sources.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG VirtualAddress;
+
+ VirtualAddress = (ULONG)HalpAllocateIoMapping(HalpIsaIoBasePhysical);
+ WRITE_REGISTER_UCHAR(VirtualAddress+0x21,0xff);
+ WRITE_REGISTER_UCHAR(VirtualAddress+0xa1,0xff);
+ HalpFreeIoMapping();
+
+ if (HalpNumberOfIsaBusses > 1) {
+ VirtualAddress = (ULONG)HalpAllocateIoMapping(HalpIsa1IoBasePhysical);
+ WRITE_REGISTER_UCHAR(VirtualAddress+0x21,0xff);
+ WRITE_REGISTER_UCHAR(VirtualAddress+0xa1,0xff);
+ HalpFreeIoMapping();
+ }
+
+ VirtualAddress = (ULONG)HalpAllocateIoMapping(GAMBIT_PCI_INTERRUPT_BASE_PHYSICAL);
+
+ HalpPciInterruptMask = ((READ_REGISTER_ULONG(VirtualAddress+0x08) & 0x08) << 4);
+ WRITE_REGISTER_ULONG(VirtualAddress+0x00,HalpPciInterruptMask&0x0f);
+ WRITE_REGISTER_ULONG(VirtualAddress+0x08,(HalpPciInterruptMask>>4)&0x0f);
+ WRITE_REGISTER_ULONG(VirtualAddress+0x10,(HalpPciInterruptMask>>8)&0x0f);
+ HalpFreeIoMapping();
+
+ HalpPciDeviceInterruptMask = 0x0000;
+}
+
+ULONG HalpPciConfigStructuresInitialized = FALSE;
+PVOID HalpPciConfig0BaseAddress[0x20];
+PVOID HalpPciConfig1BaseAddress[0x100];
+
+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;
+
+ //
+ // If the Configuration Base Address tables have not been initialized, then
+ // initialize them to NULL.
+ //
+
+ if (HalpPciConfigStructuresInitialized == FALSE) {
+
+ ULONG i;
+
+ for(i=0;i<0x20;HalpPciConfig0BaseAddress[i++]=NULL);
+ for(i=0;i<0xff;HalpPciConfig1BaseAddress[i++]=NULL);
+ HalpPciConfigStructuresInitialized = TRUE;
+ }
+
+ 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 (HalpPciConfig0BaseAddress[Slot.u.bits.DeviceNumber] == NULL) {
+
+ PHYSICAL_ADDRESS physicalAddress;
+
+ physicalAddress.QuadPart = HalpPciConfig0BasePhysical;
+ physicalAddress.QuadPart += (1 << (11 + Slot.u.bits.DeviceNumber));
+ HalpPciConfig0BaseAddress[Slot.u.bits.DeviceNumber] = MmMapIoSpace(physicalAddress,0x800,FALSE);
+
+ //
+ // If the mapping failed, then the return value is INVALID_PCI_CONFIGURATION_ADDRESS.
+ // This will cause Config Reads to return 0xffffffff, and Config Writes to do nothing.
+ //
+
+ if (HalpPciConfig0BaseAddress[Slot.u.bits.DeviceNumber] == NULL) {
+ pPciAddr->u.AsULONG = INVALID_PCI_CONFIGURATION_ADDRESS;
+ return;
+ }
+
+ }
+ pPciAddr->u.AsULONG = (ULONG)HalpPciConfig0BaseAddress[Slot.u.bits.DeviceNumber];
+ pPciAddr->u.AsULONG += ((Slot.u.bits.FunctionNumber & 0x07) << 8);
+ pPciAddr->u.bits0.Reserved1 = PciConfigType0;
+
+#if DBG
+ DbgPrint("HalpPCIConfigAddr: Type 0 PCI Config Access @ %x\n", pPciAddr->u.AsULONG);
+#endif // DBG
+
+ } 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
+ //
+
+ if (HalpPciConfig1BaseAddress[BusNumber] == NULL) {
+
+ PHYSICAL_ADDRESS physicalAddress;
+
+ physicalAddress.QuadPart = HalpPciConfig1BasePhysical;
+ physicalAddress.QuadPart += ((BusNumber & 0xff) << 16);
+ HalpPciConfig1BaseAddress[BusNumber] = MmMapIoSpace(physicalAddress,0x10000,FALSE);
+
+ //
+ // If the mapping failed, then the return value is INVALID_PCI_CONFIGURATION_ADDRESS.
+ // This will cause Config Reads to return 0xffffffff, and Config Writes to do nothing.
+ //
+
+ if (HalpPciConfig1BaseAddress[BusNumber] == NULL) {
+ pPciAddr->u.AsULONG = INVALID_PCI_CONFIGURATION_ADDRESS;
+ return;
+ }
+
+ }
+ pPciAddr->u.AsULONG = (ULONG)HalpPciConfig1BaseAddress[BusNumber];
+ pPciAddr->u.AsULONG += ((Slot.u.bits.DeviceNumber & 0x1f) << 11);
+ pPciAddr->u.AsULONG += ((Slot.u.bits.FunctionNumber & 0x07) << 8);
+ pPciAddr->u.bits0.Reserved1 = PciConfigType1;
+
+#if DBG
+ DbgPrint("Type 1 PCI Config Access @ %x\n", pPciAddr->u.AsULONG);
+#endif // DBG
+
+ }
+
+ return;
+}
+
+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);
+ }
+ 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);
+ }
+ 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);
+ }
+ 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) {
+ 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) {
+ 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) {
+ WRITE_REGISTER_ULONG(ConfigurationAddress,ConfigurationData);
+ }
+}
+
+LONGLONG HalpMapPciConfigBaseAddress(
+ IN ULONG BusNumber,
+ IN ULONG DeviceNumber,
+ IN ULONG FunctionNumber,
+ IN ULONG Register
+ )
+
+{
+ LONGLONG BaseAddress;
+
+ if (BusNumber == 0) {
+ BaseAddress = HalpPciConfig0BasePhysical +
+ (1 << (11+(DeviceNumber & 0x1f))) +
+ ((FunctionNumber & 0x07) << 8) +
+ Register;
+ } else {
+ BaseAddress = HalpPciConfig1BasePhysical +
+ ((BusNumber & 0xff) << 16) +
+ ((DeviceNumber & 0x1f) << 11) +
+ ((FunctionNumber & 0x07) << 8) +
+ Register;
+ }
+ return(BaseAddress);
+}
+
+ULONG HalpPciLowLevelConfigRead(
+ IN ULONG BusNumber,
+ IN ULONG DeviceNumber,
+ IN ULONG FunctionNumber,
+ IN ULONG Register
+ )
+
+/*++
+
+Routine Description:
+
+ This function allocates the resources needed to perform a single PCI
+ configuration read cycle. The read data is returned. For a MIPS processor,
+ a single TLB entry is borrowed so that I/O reads and writes can be performed
+ to PCI configuration space.
+
+Return Value:
+
+ Data retuned by the PCI config cycle.
+
+--*/
+
+{
+ LONGLONG BaseAddress;
+ PVOID VirtualAddress;
+ ULONG ReturnValue;
+
+ BaseAddress = HalpMapPciConfigBaseAddress(BusNumber,DeviceNumber,FunctionNumber,Register&0xfc);
+ VirtualAddress = HalpAllocateIoMapping(BaseAddress);
+ ReturnValue = READ_REGISTER_ULONG(VirtualAddress);
+ HalpFreeIoMapping();
+ return(ReturnValue);
+}
+
+VOID HalpPostCard(UCHAR Value)
+
+{
+ LONGLONG BaseAddress;
+ PVOID VirtualAddress;
+
+ BaseAddress = HalpMapPciConfigBaseAddress(HalpIntel82378BusNumber,HalpIntel82378DeviceNumber,0,0x4f);
+ VirtualAddress = HalpAllocateIoMapping(BaseAddress);
+ WRITE_REGISTER_UCHAR(VirtualAddress,0xcf);
+ HalpFreeIoMapping();
+
+ VirtualAddress = HalpAllocateIoMapping(HalpIsaIoBasePhysical + 0x420);
+ Value = (Value & 0x7f) | (READ_REGISTER_UCHAR(VirtualAddress) & 0x80);
+ HalpFreeIoMapping();
+
+ VirtualAddress = HalpAllocateIoMapping(HalpIsaIoBasePhysical + 0xc00);
+ WRITE_REGISTER_UCHAR(VirtualAddress,Value);
+ HalpFreeIoMapping();
+
+ BaseAddress = HalpMapPciConfigBaseAddress(HalpIntel82378BusNumber,HalpIntel82378DeviceNumber,0,0x4f);
+ VirtualAddress = HalpAllocateIoMapping(BaseAddress);
+ WRITE_REGISTER_UCHAR(VirtualAddress,0x4f);
+ HalpFreeIoMapping();
+}