NT4/private/ntos/nthals/halraw/alpha/iod.c
2020-09-30 17:12:29 +02:00

1468 lines
37 KiB
C
Raw Blame History

This file contains invisible Unicode characters

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

/*++
Copyright (c) 1995 Digital Equipment Corporation
Module Name:
iod.c
Abstract:
This module implements functions that are specific to the IOD ASIC.
The IOD ASIC is a control ASIC for PCI on EV5-based Rawhide
systems.
Author:
Eric Rehm 12-Apr-1995
Environment:
Kernel mode
Revision History:
--*/
#include "halp.h"
#include "rawhide.h"
BOOLEAN IodInitialized = FALSE;
MC_DEVICE_MASK HalpIodMask = 0x0;
MC_DEVICE_MASK HalpCpuMask = 0x0;
MC_DEVICE_MASK HalpGcdMask = 0x0;
//
// Declare the IOD interrupt vector table and global pointer
// Due to the fact that the MC_DEVICE_ID specifies the 64
// byte offset into this global table, we must allocate
// full table for all
//
PIOD_POSTED_INTERRUPT HalpIodPostedInterrupts;
//
// Declare the PCI logical to physical mapping structure
//
MC_DEVICE_ID HalpIodLogicalToPhysical[RAWHIDE_MAXIMUM_PCI_BUS];
//
// The revision of the IOD. Software visible differences may exist between
// passes of the IOD. The revision is determined once at the start of
// run-time and used in places where the software must diverge.
//
IOD_PCI_REVISION HalpIodRevision;
//
// Declare routines local to this module
//
VOID
HalpInitializeBitMap (
IN PRTL_BITMAP BitMapHeader,
IN PULONG BitMapBuffer,
IN ULONG SizeOfBitMap
);
VOID
HalpInitializeIodMappingTable(
MC_DEVICE_ID McDeviceId,
ULONG PciBusNumber,
va_list Arguments
)
/*++
Routine Description:
This enumeration routine initialize the IOD logical to physical
mapping table. The Logical IOD number is via a static variable
that is incremented for each invokation of this routine.
Arguments:
McDeviceId - IOD device id to be mapped.
PciBusNumber - Logical PCI Bus number (unused).
Arguments - variable arguments. None for this routine.
Return Values:
None:
--*/
{
HalpIodLogicalToPhysical[PciBusNumber].all = 0;
HalpIodLogicalToPhysical[PciBusNumber].Gid = McDeviceId.Gid;
HalpIodLogicalToPhysical[PciBusNumber].Mid = McDeviceId.Mid;
#if HALDBG
DbgPrint("HalpIodLogicalToPhysical[%d] = %x\n",
PciBusNumber,
HalpIodLogicalToPhysical[PciBusNumber]);
#endif // HALDBG
}
VOID
HalpInitializeIodVectorTable(
VOID
)
/*++
Routine Description:
Initialize the global pointer to the IOD vector table.
Arguments:
None.
Return Value:
None.
--*/
{
//
// Allocate the Global Iod vector table.
//
// mdbfix - we only need 4K, but require a page aligned
// address due to the fact that IOD uses target CPU's
// MC_DEVICE_ID as bits <11,6> of the vector table address
// in memory. So we allocate a PAGE more to guarantee
// a page aligned address.
//
HalpIodPostedInterrupts =
ExAllocatePool(
NonPagedPool,
__4K + __8K
);
#if HALDBG
DbgPrint("HalpIodPostedInterrupts = 0x%x\n", HalpIodPostedInterrupts);
#endif
if (HalpIodPostedInterrupts == NULL) {
DbgBreakPoint();
}
}
VOID
HalpInitializeIod(
MC_DEVICE_ID McDeviceId,
ULONG PciBusNumber,
va_list Arguments
)
/*++
Routine Description:
This enumeration routine initializes the corresponding IOD.
Arguments:
McDeviceId - Supplies the MC Bus Device ID of the IOD to be intialized
PciBusNumber - Logical PCI Bus number (unused).
Arguments - Variable arguments including:
1) LoaderBlock - Supplies a pointer to the loader parameter block.
Return Value:
None.
--*/
{
IOD_CAP_CONTROL IodCapControl;
IOD_CAP_ERR IodCapError;
IOD_WBASE Wbase;
IOD_TBASE Tbase;
IOD_WMASK Wmask;
IOD_TBIA Tbia;
IOD_MDPA_STAT IodMdpaStat;
IOD_MDPB_STAT IodMdpbStat;
IOD_MDPA_DIAG IodMdpaDiag;
IOD_MDPB_DIAG IodMdpbDiag;
PLOADER_PARAMETER_BLOCK LoaderBlock;
//
// Initialize parameters
//
// mdbfix - this is not used
// LoaderBlock = va_arg(Arguments, PLOADER_PARAMETER_BLOCK);
//
// Read the IOD revision.
//
HalpIodRevision.all =
READ_IOD_REGISTER_NEW(
McDeviceId,
&((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->PciRevision );
#if HALDBG
DbgPrint( "Entry - HalpInitializeIod\n\n");
DbgPrint( "IOD (%x,%x) Revision: \n", McDeviceId.Gid, McDeviceId.Mid);
DbgPrint( "\tCAP = 0x%x\n", HalpIodRevision.CapRev );
DbgPrint( "\tHorse = 0x%x\n", HalpIodRevision.HorseRev );
DbgPrint( "\tSaddle = 0x%x\n", HalpIodRevision.SaddleRev );
DbgPrint( "\tSaddle Type = 0x%x\n", HalpIodRevision.SaddleType );
DbgPrint( "\tEISA Present = 0x%x\n", HalpIodRevision.EisaPresent );
DbgPrint( "\tPCI Class, Subclass = 0x%0.2x%0.2x\n",
HalpIodRevision.BaseClass, HalpIodRevision.SubClass );
#endif //HALDBG
//
// Initialize IOD Control. Currently, take the initial values
// set by the Extended SROM.
//
IodCapControl.all =
READ_IOD_REGISTER_NEW(
McDeviceId,
&((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->CapCtrl );
#if HALDBG
DbgPrint( "Read Iod CAP Control = 0x%0.4x\n", IodCapControl.all );
#endif //HALDBG
#ifdef RISP //ecrfix
//
// For RISP, initialized as per Rawhide S/W Programmers Manual
//
IodCapControl.DlyRdEn = 1;
IodCapControl.PciMemEn = 1;
IodCapControl.PciReq64 = 1;
IodCapControl.PciAck64 = 1;
IodCapControl.PciAddrPe= 1;
IodCapControl.McCmdAddrPe= 1;
IodCapControl.McNxmEn = 1;
IodCapControl.McBusMonEn= 1;
IodCapControl.PendNum = 11; // 12 - [ (0 * 2) + 1 + (0 * 2)]
IodCapControl.RdType = 2;
IodCapControl.RlType = 2;
IodCapControl.RmType = 2;
IodCapControl.PartialWrEn = 0;
IodCapControl.ArbMode = 0;
WRITE_IOD_REGISTER_NEW( McDeviceId,
&((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->CapCtrl,
IodCapControl.all );
#if HALDBG
IodCapControl.all =
READ_IOD_REGISTER_NEW( McDeviceId,
&((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->CapCtrl );
DbgPrint( "Read Iod CAP Control = 0x%0.4x\n (after sets)", IodCapControl.all );
#endif //HALDBG
#endif //RISP
//
// Disable all of the scatter/gather windows.
//
Wbase.all = 0;
Wbase.Wen = 0;
WRITE_IOD_REGISTER_NEW( McDeviceId,
&((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->W0base,
Wbase.all );
WRITE_IOD_REGISTER_NEW( McDeviceId,
&((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->W1base,
Wbase.all );
WRITE_IOD_REGISTER_NEW( McDeviceId,
&((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->W2base,
Wbase.all );
WRITE_IOD_REGISTER_NEW( McDeviceId,
&((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->W3base,
Wbase.all );
//
// Invalidate all of the TLB Entries.
//
Tbia.all = 0;
//
// Perform the invalidation.
//
WRITE_IOD_REGISTER_NEW( McDeviceId,
&((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->Tbia,
Tbia.all );
//
// Clear any pending error bits in the IOD_CAP_ERR register:
//
IodCapError.all = 0; // Clear all bits
IodCapError.Perr = 1; // PCI bus perr detected
IodCapError.Serr = 1; // PCI bus serr detected
IodCapError.Mab = 1; // PCI bus master abort detected
IodCapError.PteInv = 1; // Invalid Pte
IodCapError.PioOvfl = 1; // Pio Ovfl
IodCapError.LostMcErr = 1; // Lost error
IodCapError.McAddrPerr = 1; // MC bus comd/addr parity error
IodCapError.Nxm = 1; // MC bus Non-existent memory error
IodCapError.CrdA = 1; // Correctable ECC error on MDPA
IodCapError.CrdB = 1; // Correctable ECC error on MDPB
IodCapError.RdsA = 1; // Uncorrectable ECC error on MDPA
IodCapError.RdsA = 1; // Uncorrectable ECC error on MDPA
WRITE_IOD_REGISTER_NEW( McDeviceId,
&((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->CapErr,
IodCapError.all );
//
// Clear any ECC error syndrome bits in the IOD_MDPA/B_SYN registers:
//
IodMdpaStat.all = 0;
IodMdpaStat.Crd = 1; // Correctable ECC error (also clears Rds bit)
IodMdpbStat.all = 0;
IodMdpbStat.Crd = 1; // Correctable ECC error (also clears Rds bit)
WRITE_IOD_REGISTER_NEW( McDeviceId,
&((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpaStat,
IodMdpaStat.all );
WRITE_IOD_REGISTER_NEW( McDeviceId,
&((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpbStat,
IodMdpbStat.all );
#if 0 // CAP/MDP Bug
IodMdpaStat.all =
READ_IOD_REGISTER_NEW( McDeviceId,
&((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpaStat );
DbgPrint( "MDPA (%x,%x) Revision = 0x%x\n",
McDeviceId.Gid, McDeviceId.Mid, IodMdpaStat.MdpaRev);
IodMdpaStat.all =
READ_IOD_REGISTER_NEW( McDeviceId,
&((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpbStat );
DbgPrint( "MDPB (%x,%x) Revision = 0x%x\n",
McDeviceId.Gid, McDeviceId.Mid, IodMdpbStat.MdpbRev);
#endif
//
// Initialize MDP Diagnostic Checking. Currently just take the
// initial values set by the Extended SROM. Do both Mdpa and Mdpb.
//
#if 0 // CAP/MDP Bug
IodMdpaDiag.all =
READ_IOD_REGISTER_NEW( McDeviceId,
&((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpaDiag );
DbgPrint( "Read Iod MDPA Diag = 0x%0.4x\n", IodMdpaDiag.all );
IodMdpbDiag.all =
READ_IOD_REGISTER_NEW( McDeviceId,
&((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpbDiag );
DbgPrint( "Read Iod MDPB Diag = 0x%0.4x\n", IodMdpbDiag.all );
#endif
#if defined(AXP_FIRMWARE)
//
// Disable MCI bus interrupts
//
WRITE_IOD_REGISTER_NEW(
McDeviceId,
&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntCtrl,
(IOD_INT_CTL_DISABLE_IO_INT | IOD_INT_CTL_DISABLE_VECT_WRITE)
);
//
// Clear interrupt request register (New for CAP Rev2.3)
//
WRITE_IOD_REGISTER_NEW(
McDeviceId,
&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntReq,
IodIntMask
);
//
// Clear all pending interrupts for this IOD
//
WRITE_IOD_REGISTER_NEW(
McDeviceId,
&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntAck0,
0x0
);
//
// Clear all pending EISA interrupts for IOD 0
//
if ( (McDeviceId.Gid == GidPrimary) && (McDeviceId.Mid == MidPci0) ) {
INTERRUPT_ACKNOWLEDGE((PVOID)IOD_PCI0_IACK_QVA);
}
//
// Write the target register.
//
WRITE_IOD_REGISTER_NEW(
McDeviceId,
&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntTarg,
(GidPrimary << 9)|(MidCpu1 << 6)|
(GidPrimary << 3)|(MidCpu0)
);
//
// Initialize the mask bits for target 0 and 1
//
WRITE_IOD_REGISTER_NEW(
McDeviceId,
(PVOID)&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntMask0,
0
);
WRITE_IOD_REGISTER_NEW(
McDeviceId,
(PVOID)&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntMask1,
0
);
#endif //if defined(AXP_FIRMWARE)
IodInitialized = TRUE;
}
VOID
HalpClearAllIods(
IOD_CAP_ERR IodCapErrMask
)
/*++
Routine Description:
Clears specified CapErr bits on all IODs.
Arguments:
IodCapErrMask - Mask of bits to be cleared in each IOD_CAP_ERR.
Return Value:
None.
--*/
{
MC_ENUM_CONTEXT mcCtx;
ULONG numIods;
BOOLEAN bfoundIod;
IOD_CAP_ERR IodCapErr;
//
// Clear all the error conditions in CAP_ERR on all IODs
// (Note - on 2 Mb Cached CPU, LostMcErr may also be set, so
// clear everything to be fer-sure, fer-sure.)
//
numIods = HalpMcBusEnumStart ( HalpIodMask, &mcCtx );
//
// Clear all errors on all IODs.
//
while ( bfoundIod = HalpMcBusEnum( &mcCtx ) ) {
//
// Read it
//
IodCapErr.all = READ_IOD_REGISTER_NEW( mcCtx.McDeviceId,
&((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->CapErr );
//
// Mask it.
//
IodCapErr.all &= IodCapErrMask.all;
//
// If there is anything to clear, then do it.
//
if (IodCapErr.all != 0) {
WRITE_IOD_REGISTER_NEW( mcCtx.McDeviceId,
&((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->CapErr,
IodCapErr.all );
}
}
}
VOID
HalpInitializeIodVectorCSRs(
MC_DEVICE_ID McDeviceId,
ULONG PciBusNumber,
va_list Arguments
)
/*++
Routine Description:
This enumeration routine initializes Interrupt Vector Table CSRS
for the corresponding IOD.
The address used by an IOD during interrupt vector writes
is:
39 38 32 31 12 11 6 5 2 1 0
| | | | | | | | | | |
===================================================================
|0 | INT_ADDR_EXT | INT_ADDR_LO | TARGET ID | PCI BUS OFFSET | 00 |
===================================================================
Where:
INT_ADDR_EXT = 0 since our table resides in KSEG0_BASE.
INT_ADDR_LO = upper 20 bits (4K Page Addr) of Table Physical Address
TARGET_ID = MC_DEVICE_ID of Target CPU obtained from INT_TARG(0|1)
PCI_BUS_OFFSET = Logical PCI bus number used as an offset into vector
table by the interrupting IOD.
The assignment of PCI_BUS_OFFSET is based on the PCI bus number static
variable. This number is incremented with each invokation of this routine.
Arguments:
McDeviceId - Supplies the MC Bus Device ID of the IOD to be intialized
PciBusNumber - Logical PCI Bus number (unused).
Arguments - Variable Arguments. None for this routine.
Return Value:
None.
--*/
{
IOD_INT_ADDR IodIntAddr;
IOD_INT_ADDR_EXT IodIntAddrExt;
IOD_INT_CONTROL IodIntControl;
//
// Initialize the Interrupt Vector Table Address register
// for this IOD.
//
IodIntAddr.all =
READ_IOD_REGISTER_NEW(
McDeviceId,
&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntAddr );
IodIntAddr.Reserved1 = 0; // MBZ
IodIntAddr.PciOffset = PciBusNumber; // Logical IOD #
IodIntAddr.Reserved2 = 0; // MBZ
IodIntAddr.IntAddrLo = ((ULONG)HalpIodPostedInterrupts / __4K);
//
// Mask off the KSEG0_BASE to convert this to a physical
// address.
//
IodIntAddr.all &= ~KSEG0_BASE;
WRITE_IOD_REGISTER_NEW( McDeviceId,
&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntAddr,
IodIntAddr.all );
//
// Initialize the interrupt vector table Address Extension
// register to zero since our address resides in KSEG0_BASE.
//
IodIntAddrExt.all =
READ_IOD_REGISTER_NEW(
McDeviceId,
&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntAddrExt );
IodIntAddrExt.all = 0;
WRITE_IOD_REGISTER_NEW( McDeviceId,
&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntAddrExt,
IodIntAddrExt.all );
}
VOID
HalpIodInitializeSfwWindow(
// ecrfix MC_DEVICE_ID McDeviceId,
PWINDOW_CONTROL_REGISTERS WindowRegisters,
IOD_WINDOW_NUMBER WindowNumber
)
/*++
Routine Description:
Initialize the DMA Control software window registers for the specified
DMA Window.
Arguments:
WindowRegisters - Supplies a pointer to the software window control.
WindowNumber - Supplies the window number initialized. (0 = Isa Dma
Window, 1 = Master Dma Window).
Return Value:
None.
--*/
{
switch( WindowNumber ){
//
// The ISA DMA Window.
//
case IodIsaWindow:
WindowRegisters->WindowBase = (PVOID)ISA_DMA_WINDOW_BASE;
WindowRegisters->WindowSize = ISA_DMA_WINDOW_SIZE;
WindowRegisters->TranslatedBaseRegister =
&((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->T1base;
WindowRegisters->WindowBaseRegister =
&((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->W1base;
WindowRegisters->WindowMaskRegister =
&((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->W1mask;
WindowRegisters->WindowTbiaRegister =
&((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->Tbia;
break;
case IodMasterWindow:
WindowRegisters->WindowBase = (PVOID)MASTER_DMA_WINDOW_BASE;
WindowRegisters->WindowSize = MASTER_DMA_WINDOW_SIZE;
WindowRegisters->TranslatedBaseRegister =
&((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->T0base;
WindowRegisters->WindowBaseRegister =
&((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->W0base;
WindowRegisters->WindowMaskRegister =
&((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->W0mask;
WindowRegisters->WindowTbiaRegister =
&((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->Tbia;
break;
default:
#if HALDBG
DbgPrint( "IodInitializeSfwWindow: Bad Window Number = %x\n",
WindowNumber );
#endif //HALDBG
break;
}
return;
}
VOID
HalpIodProgramDmaWindow(
PWINDOW_CONTROL_REGISTERS WindowRegisters,
PVOID MapRegisterBase
)
/*++
Routine Description:
Program the control windows in the hardware so that DMA can be started
to the DMA window.
Arguments:
WindowRegisters - Supplies a pointer to the software window register
control structure.
MapRegisterBase - Supplies the logical address of the scatter/gather
array in system memory.
Return Value:
None.
--*/
{
IOD_WBASE Wbase;
IOD_TBASE Tbase;
IOD_WMASK Wmask;
IOD_TBIA Tbia;
MC_ENUM_CONTEXT mcCtx;
MC_DEVICE_ID McDeviceId;
//
// Program the windows as specified by the caller.
//
Wbase.all = 0;
Wbase.Wen = 1;
Wbase.SgEn = 1;
Wbase.Wbase = (ULONG)(WindowRegisters->WindowBase) >> 20;
Wmask.all = 0;
Wmask.Wmask = (WindowRegisters->WindowSize >> 20) - 1;
Tbase.all = 0;
Tbase.Tbase = (ULONG)MapRegisterBase >> 10;
Tbia.all = 0;
//
// Dump the IOD registers.
//
#if HALDBG
// DumpAllIods( IodScatterGatherRegisters );
#endif //HALDBG
//
// Loop through all of the Iods
//
// ecrfix - is it OK to do it one at a time this way?
//
HalpMcBusEnumStart( HalpIodMask, &mcCtx );
while ( HalpMcBusEnum ( &mcCtx ) ) {
McDeviceId = mcCtx.McDeviceId;
//
// Clear the window base, temporarily disabling transactions to this
// DMA window.
//
WRITE_IOD_REGISTER_NEW( McDeviceId,
WindowRegisters->WindowBaseRegister, 0 );
//
// Now program the window by writing the translated base, then the size
// of the window in the mask register and finally the window base,
// enabling both the window and scatter gather.
//
WRITE_IOD_REGISTER_NEW( McDeviceId,
WindowRegisters->TranslatedBaseRegister,
Tbase.all );
WRITE_IOD_REGISTER_NEW( McDeviceId,
WindowRegisters->WindowMaskRegister,
Wmask.all );
WRITE_IOD_REGISTER_NEW( McDeviceId,
WindowRegisters->WindowBaseRegister,
Wbase.all );
//
// Flush the volatile entries in this IOD's scatter/gather Tlb.
//
WRITE_IOD_REGISTER_NEW( McDeviceId,
WindowRegisters->WindowTbiaRegister,
Tbia.all );
}
// ecrfix - we did it above. HalpIodInvalidateTlb( WindowRegisters );
//
// Dump the IOD registers.
//
#if HALDBG
// DumpAllIods( IodScatterGatherRegisters | IodGeneralRegisters );
#endif //HALDBG
return;
}
ULONG
HalpMcBusEnumStart(
MC_DEVICE_MASK McDeviceMask,
PMC_ENUM_CONTEXT McContext
)
/*++
Routine Description:
Given a particular MC Bus device mask:
* Set up state so that subsequent MC Bus devices can be enumerated
by calling HalpMcBusEnum( McContext ).
* Return the first MC_DEVICE_ID in that mask via McContext.
(ECRFIX: IFDEF out for now!)
N.B. The search will start with GID = 7, i.e., McDeviceMask<56>
because the primary GID is 7.
Arguments:
McDeviceMask - Supplies a bitfield of MC Bus devices to be enumerated.
McContext - A structure that contains the MC_DEVICE_ID to be enumerated
and associated enumerator state.
Return Value:
Number of MC Bus devices to be enumerated.
--*/
{
ULONG count;
//
// Intialize the bitmap from the McDeviceMask.
// (Make a copy so that McDeviceMask is preserved for the caller.)
//
McContext->tempMask = McDeviceMask;
// RtlInitializeBitMap(&McContext->McDeviceBitmap,
HalpInitializeBitMap(&McContext->McDeviceBitmap,
(PULONG) &McContext->tempMask,
sizeof(MC_DEVICE_MASK) * 8);
//
// Count the number of device to be enuerated
//
count = HalpNumberOfSetBits (&McContext->McDeviceBitmap);
//
// Start looking at GID = 7.
//
McContext->nextBit = GidPrimary * 8;
#if 0
//
// Find the first MC Bus device to be enumerated.
//
McContext->nextBit = HalpFindSetBitsAndClear (&McContext->McDeviceBitmap,
1,
McContext->nextBit);
//
// Convert first non-zero bit found to MC_DEVICE_ID
//
McContext->McDeviceId.all = 0;
McContext->McDeviceId.Gid = McContext->nextBit / 8;
McContext->McDeviceId.Mid = McContext->nextBit % 8;
#endif
return ( count );
}
BOOLEAN
HalpMcBusEnum(
PMC_ENUM_CONTEXT McContext
)
/*++
Routine Description:
Enumerate MC Bus devices until none are left
Arguments:
McContext - A structure that contains the MC_DEVICE_ID to be enumerated
and associated enumerator state.
Return Value:
TRUE, unless there were no more MC Bus devices to be enumerated,
in which case, returns FALSE.
--*/
{
//
// Find the next MC Bus device.
//
McContext->nextBit = HalpFindSetBitsAndClear (&McContext->McDeviceBitmap,
1,
McContext->nextBit);
if ( McContext->nextBit != 0xffffffff) {
//
// Convert the non-zero bit found to MC_DEVICE_ID
//
McContext->McDeviceId.all = 0;
McContext->McDeviceId.Gid = McContext->nextBit / 8;
McContext->McDeviceId.Mid = McContext->nextBit % 8;
//
// Since we just set nextBit to zero, we can start the
// next search one bit higher. This will speed up the
// next call to HalpMcBusEnum.
//
McContext->nextBit++;
return ( TRUE );
} else {
return ( FALSE) ;
}
}
VOID
HalpMcBusEnumAndCall(
MC_DEVICE_MASK McDeviceMask,
PMC_ENUM_ROUTINE McBusEnumRoutine,
...
)
/*++
Routine Description:
Execute the Call routine for all devices in the MC device mask.
This routine provides a general method to enumerate an MC_DEVICE_MASK
and execute a caller-supplied routine for each device. A logical
device number and variable arguments are passed to the routine.
Arguments:
McDeviceMask - Supplies a bitfield of MC Bus devices to be enumerated.
McBusEnumRoutine - Routine that is called for each MC Bus device.
... - Variable arguments passed by the caller.
Return Value:
None.
--*/
{
MC_ENUM_CONTEXT mcCtx;
ULONG numIods;
ULONG LogicalDeviceNumber = 0;
va_list Arguments;
//
// Intialize enumerator.
//
numIods = HalpMcBusEnumStart ( McDeviceMask, &mcCtx );
//
// Execute routine for each device.
//
while ( HalpMcBusEnum( &mcCtx ) ) {
va_start(Arguments, McBusEnumRoutine);
McBusEnumRoutine( mcCtx.McDeviceId, LogicalDeviceNumber++, Arguments );
va_end(Arguments);
}
}
ULONG
HalpReadWhoAmI(
VOID
)
/*++
Routine Description:
Read the WHOAMI register.
Arguments:
None.
Return Value:
The value of the WHOAMI.
--*/
{
MC_DEVICE_ID McDeviceId;
IOD_WHOAMI IodWhoAmI;
//
// Initialize Id for IOD 0.
//
McDeviceId.all = 0;
McDeviceId.Gid = GidPrimary;
McDeviceId.Mid = MidPci0;
return (
READ_IOD_REGISTER_NEW(
McDeviceId,
&((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->WhoAmI )
);
}
VOID
HalpIodInvalidateTlb(
PWINDOW_CONTROL_REGISTERS WindowRegisters
)
/*++
Routine Description:
Invalidate the DMA Scatter/Gather TLB in all the IODs.
The TLB is invalidated whenever the scatter/gather translation
entries are modified.
Arguments:
WindowRegisters - Supplies a pointer to the software window register
control structure.
Return Value:
None.
--*/
{
//
// Perform the S/G TLB invalidation
//
IOD_TBIA Tbia;
MC_ENUM_CONTEXT mcCtx;
Tbia.all = 0;
HalpMcBusEnumStart(HalpIodMask, &mcCtx);
while ( HalpMcBusEnum( &mcCtx ) ) {
WRITE_IOD_REGISTER_NEW( mcCtx.McDeviceId,
WindowRegisters->WindowTbiaRegister,
Tbia.all );
}
}
#if HALDBG || DUMPIODS
IOD_REGISTER_CLASS DumpIodFlag = AllRegisters;
VOID
DumpAllIods(
IOD_REGISTER_CLASS RegistersToDump
)
/*++
Routine Description:
Read the interesting Iod registers and print them to the debug port.
Arguments:
McDeviceId - Supplies the MC Bus Device ID of the IOD to be dumped
Return Value:
None.
--*/
{
MC_ENUM_CONTEXT mcCtx;
ULONG NumIods;
DbgPrint( "Dump All IODs: \n" );
NumIods = HalpMcBusEnumStart(HalpIodMask, &mcCtx);
DbgPrint( "Dump All IODs: (%d IODs)\n", NumIods );
while ( HalpMcBusEnum( &mcCtx ) ) {
DumpIod( mcCtx.McDeviceId,
RegistersToDump );
}
}
VOID
DumpIod(
MC_DEVICE_ID McDeviceId,
IOD_REGISTER_CLASS RegistersToDump
)
/*++
Routine Description:
Read the interesting Iod registers and print them to the debug port.
Arguments:
McDeviceId - Supplies the MC Bus Device ID of the IOD to be dumped
Return Value:
None.
--*/
{
PVOID RegisterQva;
ULONG Value;
DbgPrint( "IOD (%x, %x) Register Dump: \n", McDeviceId.Gid, McDeviceId.Mid );
//
// Dump the IOD General Control registers.
//
if( (RegistersToDump & IodGeneralRegisters) != 0 ){
RegisterQva = &((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->PciRevision;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "IodRevision = 0x%x\n", Value );
RegisterQva = &((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->WhoAmI;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "WhoAmI = 0x%x\n", Value );
RegisterQva = &((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->PciLat;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "PciLat = 0x%x\n", Value );
RegisterQva = &((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->CapCtrl;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "IodCtrl = 0x%x\n", Value );
RegisterQva = &((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->HaeMem;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "HaeMem = 0x%x\n", Value );
RegisterQva = &((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->HaeIo;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "HaeIo = 0x%x\n", Value );
#if 0 // ecrfix - don't read this on PCI0 - creates an IACK cycle
// on the EISA bus. Don't read this on PCI1,2,3, because
// (apparently), it doesn't exist there.
RegisterQva = &((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->IackSc;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "IackSc = 0x%x\n", Value );
#endif
}
//
// Dump the IOD Interrupt registers.
//
if( (RegistersToDump & IodInterruptRegisters) != 0 ){
RegisterQva = &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntCtrl;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "IntCtrl = 0x%x\n", Value );
RegisterQva = &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntReq;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "IntReq = 0x%x\n", Value );
RegisterQva = &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntTarg;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "IntTarg = 0x%x\n", Value );
RegisterQva = &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntAddr;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "IntAddr = 0x%x\n", Value );
RegisterQva = &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntAddrExt;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "IntAddrExt = 0x%x\n", Value );
RegisterQva = &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntMask0;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "IntMask0 = 0x%x\n", Value );
RegisterQva = &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntMask1;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "IntMask1 = 0x%x\n", Value );
}
//
// Dump the IOD Diagnostic registers.
//
if( (RegistersToDump & IodDiagnosticRegisters) != 0 ){
RegisterQva = &((PIOD_DIAG_CSRS)(IOD_DIAG_CSRS_QVA))->CapDiag;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "CapDiag = 0x%x\n", Value );
RegisterQva = &((PIOD_DIAG_CSRS)(IOD_DIAG_CSRS_QVA))->Scratch;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "Scratch = 0x%x\n", Value );
}
//
// Dump the IOD Error registers.
//
if( (RegistersToDump & IodErrorRegisters) != 0 ){
RegisterQva = &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->McErr0;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "MCErr0 = 0x%x\n", Value );
RegisterQva = &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->McErr1;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "MCErr1 = 0x%x\n", Value );
RegisterQva = &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->CapErr;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "CapErr = 0x%x\n", Value );
RegisterQva = &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->PciErr1;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "PciErr1 = 0x%x\n", Value );
#if 0 // CAP/MDP Bug
RegisterQva = &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpaStat;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "MdpaStat = 0x%x\n", Value );
RegisterQva = &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpaSyn;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "MdpaSyn = 0x%x\n", Value );
RegisterQva = &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpaDiag;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "MdpaDiag = 0x%x\n", Value );
RegisterQva = &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpbStat;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "MdpbStat = 0x%x\n", Value );
RegisterQva = &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpbSyn;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "MdpbSyn = 0x%x\n", Value );
RegisterQva = &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpbDiag;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "MdpbDiag = 0x%x\n", Value );
#endif
}
//
// Dump the PCI Scatter/Gather registers.
//
if( (RegistersToDump & IodScatterGatherRegisters) != 0 ){
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->Tbia;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "Tbia = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->Hbase;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "Hbase = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->W0base;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "W0base = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->W0mask;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "W0mask = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->T0base;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "T0base = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->W1base;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "W1base = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->W1mask;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "W1mask = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->T1base;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "T1base = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->W2base;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "W2base = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->W2mask;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "W2mask = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->T2base;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "T2base = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->W3base;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "W3base = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->W3mask;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "W3mask = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->T3base;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "T3base = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->Wdac;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "Wdac = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->TbTag0;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "TbTag0 = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->TbTag1;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "TbTag1 = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->TbTag2;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "TbTag2 = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->TbTag3;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "TbTag3 = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->TbTag4;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "TbTag4 = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->TbTag5;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "TbTag5 = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->TbTag6;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "TbTag6 = 0x%x\n", Value );
RegisterQva = &((PIOD_SG_CSRS)(IOD_SG_CSRS_QVA))->TbTag7;
Value = READ_IOD_REGISTER_NEW( McDeviceId, RegisterQva );
DbgPrint( "TbTag7 = 0x%x\n", Value );
}
//
// Dump the IOD Reset register.
//
if( (RegistersToDump & IodResetRegister) != 0 ){
RegisterQva = (PIOD_ELCR1)((ULONG)HalpEisaControlBase + 27);
Value = (ULONG) READ_PORT_UCHAR( (PUCHAR) RegisterQva );
DbgPrint( "ELCR2 = 0x%x\n", Value );
}
DbgPrint( "--end IOD Register dump\n\n" );
return;
}
#endif //HALDBG || DUMPIODS