diff options
Diffstat (limited to 'private/ntos/nthals/halraw')
71 files changed, 24152 insertions, 0 deletions
diff --git a/private/ntos/nthals/halraw/alpha/adjust.c b/private/ntos/nthals/halraw/alpha/adjust.c new file mode 100644 index 000000000..47c267fb8 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/adjust.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\adjust.c" + diff --git a/private/ntos/nthals/halraw/alpha/allstart.c b/private/ntos/nthals/halraw/alpha/allstart.c new file mode 100644 index 000000000..42f70b7ca --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/allstart.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\allstart.c" + diff --git a/private/ntos/nthals/halraw/alpha/as4000.h b/private/ntos/nthals/halraw/alpha/as4000.h new file mode 100644 index 000000000..9e66de6da --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/as4000.h @@ -0,0 +1,62 @@ +/*++ + +Copyright (c) 1996 Digital Equipment Corporation + +Module Name: + + as4000.h + +Abstract: + + This file defines the AS4000 internal bus interrupts for Windows NT 3.51 + +Author: + + Matthew Buchman 18 March 1996 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#ifndef _AS4000_ +#define _AS4000_ + +/*++ + + Value added drivers for the AS4000 running Windows NT 3.51 can take + advantage of interrupts for the Correctable Error and the I2c Bus. + These interrupts are made visible to device drivers on the "Internal" + bus. A device driver may connect one of these interrupts via a call to + HalGetInterruptVector(). The bus interrupt level/vector are defined + below for the Correctable Error, I2c Bus, and I2c Controller interrupts. + + For example, to connect the I2c bus interrupt vector: + + HalGetInterruptVector( + Internal, + 0, + AS4000I2cBusInterruptVector, + AS4000I2cBusInterruptVector, + &Irql, + &Affinity + ); + + See the Windows NT Network Developers CD for more information on + the steps necessary to connect an interrupt service routine for + kernel mode device drivers. + +-*/ + +enum _AS4000_INTERNAL_BUS_INTERRUPT_LEVEL { + + AS4000SoftErrInterruptLevel, // Correctable Error + AS4000I2cCtrlInterruptLevel, // I2C Controller + AS4000I2cBusInterruptLevel // I2C Bus + +}; + +#endif // _AS4000_ diff --git a/private/ntos/nthals/halraw/alpha/bios.c b/private/ntos/nthals/halraw/alpha/bios.c new file mode 100644 index 000000000..3a9d3aa50 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/bios.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\bios.c" + diff --git a/private/ntos/nthals/halraw/alpha/bitmap.c b/private/ntos/nthals/halraw/alpha/bitmap.c new file mode 100644 index 000000000..6f01b6908 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/bitmap.c @@ -0,0 +1,3007 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + BitMap.c + +Abstract: + + Implementation of the bit map routines for the NT rtl. + + Bit numbers within the bit map are zero based. The first is numbered + zero. + + The bit map routines keep track of the number of bits clear or set by + subtracting or adding the number of bits operated on as bit ranges + are cleared or set; individual bit states are not tested. + This means that if a range of bits is set, + it is assumed that the total range is currently clear. + +Author: + + Gary Kimura (GaryKi) & Lou Perazzoli (LouP) 29-Jan-1990 + +Revision History: + + Eric Rehm 9-Nov-1995 - Rename to Rtl to Halp for use in Rawhide HAL + +--*/ + +// #include "ntrtlp.h" + +#include "halp.h" +#include "rawhide.h" + +#define RightShiftUlong(E1,E2) ((E2) < 32 ? (E1) >> (E2) : 0) +#define LeftShiftUlong(E1,E2) ((E2) < 32 ? (E1) << (E2) : 0) + +// +// Macro that tells how many contiguous bits are set (i.e., 1) in +// a byte +// + +#define HalppBitSetAnywhere( Byte ) HalppBitsClearAnywhere[ (~(Byte) & 0xFF) ] + + +// +// Macro that tells how many contiguous LOW order bits are set +// (i.e., 1) in a byte +// + +#define HalppBitsSetLow( Byte ) HalppBitsClearLow[ (~(Byte) & 0xFF) ] + + +// +// Macro that tells how many contiguous HIGH order bits are set +// (i.e., 1) in a byte +// + +#define HalppBitsSetHigh( Byte ) HalppBitsClearHigh[ (~(Byte) & 0xFF) ] + + +// +// Macro that tells how many set bits (i.e., 1) there are in a byte +// + +#define HalppBitsSetTotal( Byte ) HalppBitsClearTotal[ (~(Byte) & 0xFF) ] + + +#if DBG +VOID +HalpDumpBitMap ( + PRTL_BITMAP BitMap + ) +{ + ULONG i; + BOOLEAN AllZeros, AllOnes; + + DbgPrint(" BitMap:%08lx", BitMap); + + KdPrint((" (%08x)", BitMap->SizeOfBitMap)); + KdPrint((" %08lx\n", BitMap->Buffer)); + + AllZeros = FALSE; + AllOnes = FALSE; + + for (i = 0; i < ((BitMap->SizeOfBitMap + 31) / 32); i += 1) { + + if (BitMap->Buffer[i] == 0) { + + if (AllZeros) { + + NOTHING; + + } else { + + DbgPrint("%4d:", i); + DbgPrint(" %08lx\n", BitMap->Buffer[i]); + } + + AllZeros = TRUE; + + } else if (BitMap->Buffer[i] == 0xFFFFFFFF) { + + if (AllOnes) { + + NOTHING; + + } else { + + DbgPrint("%4d:", i); + DbgPrint(" %08lx\n", BitMap->Buffer[i]); + } + + AllOnes = TRUE; + + } else { + + AllZeros = FALSE; + AllOnes = FALSE; + + DbgPrint("%4d:", i); + DbgPrint(" %08lx\n", BitMap->Buffer[i]); + } + } +} + +#endif + + +// +// There are three macros to make reading the bytes in a bitmap easier. +// + +#define GET_BYTE_DECLARATIONS() \ + PUCHAR _CURRENT_POSITION; + +#define GET_BYTE_INITIALIZATION(RTL_BITMAP,BYTE_INDEX) { \ + _CURRENT_POSITION = &((PUCHAR)((RTL_BITMAP)->Buffer))[BYTE_INDEX]; \ +} + +#define GET_BYTE(THIS_BYTE) ( \ + THIS_BYTE = *(_CURRENT_POSITION++) \ +) + + +// +// Lookup table that tells how many contiguous bits are clear (i.e., 0) in +// a byte +// + +CCHAR HalppBitsClearAnywhere[] = + { 8,7,6,6,5,5,5,5,4,4,4,4,4,4,4,4, + 4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 5,4,3,3,2,2,2,2,3,2,2,2,2,2,2,2, + 4,3,2,2,2,2,2,2,3,2,2,2,2,2,2,2, + 6,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2, + 4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,1, + 5,4,3,3,2,2,2,2,3,2,1,1,2,1,1,1, + 4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,1, + 7,6,5,5,4,4,4,4,3,3,3,3,3,3,3,3, + 4,3,2,2,2,2,2,2,3,2,2,2,2,2,2,2, + 5,4,3,3,2,2,2,2,3,2,1,1,2,1,1,1, + 4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,1, + 6,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2, + 4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,1, + 5,4,3,3,2,2,2,2,3,2,1,1,2,1,1,1, + 4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,0 }; + +// +// Lookup table that tells how many contiguous LOW order bits are clear +// (i.e., 0) in a byte +// + +CCHAR HalppBitsClearLow[] = + { 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 }; + +// +// Lookup table that tells how many contiguous HIGH order bits are clear +// (i.e., 0) in a byte +// + +CCHAR HalppBitsClearHigh[] = + { 8,7,6,6,5,5,5,5,4,4,4,4,4,4,4,4, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + +// +// Lookup table that tells how many clear bits (i.e., 0) there are in a byte +// + +CCHAR HalppBitsClearTotal[] = + { 8,7,7,6,7,6,6,5,7,6,6,5,6,5,5,4, + 7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3, + 7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3, + 6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2, + 7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3, + 6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2, + 6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2, + 5,4,4,3,4,3,3,2,4,3,3,2,3,2,2,1, + 7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3, + 6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2, + 6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2, + 5,4,4,3,4,3,3,2,4,3,3,2,3,2,2,1, + 6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2, + 5,4,4,3,4,3,3,2,4,3,3,2,3,2,2,1, + 5,4,4,3,4,3,3,2,4,3,3,2,3,2,2,1, + 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 }; + +// +// Bit Mask for clearing and setting bits within bytes +// + +static UCHAR FillMask[] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF }; + +static UCHAR ZeroMask[] = { 0xFF, 0xFE, 0xFC, 0xF8, 0xf0, 0xe0, 0xc0, 0x80, 0x00 }; + + +VOID +HalpInitializeBitMap ( + IN PRTL_BITMAP BitMapHeader, + IN PULONG BitMapBuffer, + IN ULONG SizeOfBitMap + ) + +/*++ + +Routine Description: + + This procedure initializes a bit map. + +Arguments: + + BitMapHeader - Supplies a pointer to the BitMap Header to initialize + + BitMapBuffer - Supplies a pointer to the buffer that is to serve as the + BitMap. This must be an a multiple number of longwords in size. + + SizeOfBitMap - Supplies the number of bits required in the Bit Map. + +Return Value: + + None. + +--*/ + +{ + //RTL_PAGED_CODE(); + + // + // Initialize the BitMap header. + // + + BitMapHeader->SizeOfBitMap = SizeOfBitMap; + BitMapHeader->Buffer = BitMapBuffer; + + // + // And return to our caller + // + + //DbgPrint("InitializeBitMap"); DumpBitMap(BitMapHeader); + return; +} + + +VOID +HalpClearAllBits ( + IN PRTL_BITMAP BitMapHeader + ) + +/*++ + +Routine Description: + + This procedure clears all bits in the specified Bit Map. + +Arguments: + + BitMapHeader - Supplies a pointer to the previously initialized BitMap + +Return Value: + + None. + +--*/ + +{ + // + // Clear all the bits + // + + RtlZeroMemory( BitMapHeader->Buffer, + ((BitMapHeader->SizeOfBitMap + 31) / 32) * 4 + ); + + // + // And return to our caller + // + + //DbgPrint("ClearAllBits"); DumpBitMap(BitMapHeader); + return; +} + + +VOID +HalpSetAllBits ( + IN PRTL_BITMAP BitMapHeader + ) + +/*++ + +Routine Description: + + This procedure sets all bits in the specified Bit Map. + +Arguments: + + BitMapHeader - Supplies a pointer to the previously initialized BitMap + +Return Value: + + None. + +--*/ + +{ + // + // Set all the bits + // + + RtlFillMemoryUlong( BitMapHeader->Buffer, + ((BitMapHeader->SizeOfBitMap + 31) / 32) * 4, + 0xffffffff + ); + + // + // And return to our caller + // + + //DbgPrint("SetAllBits"); DumpBitMap(BitMapHeader); + return; +} + + +ULONG +HalpFindClearBits ( + IN PRTL_BITMAP BitMapHeader, + IN ULONG NumberToFind, + IN ULONG HintIndex + ) + +/*++ + +Routine Description: + + This procedure searches the specified bit map for the specified + contiguous region of clear bits. If a run is not found from the + hint to the end of the bitmap, we will search again from the + beginning of the bitmap. + +Arguments: + + BitMapHeader - Supplies a pointer to the previously initialized BitMap. + + NumberToFind - Supplies the size of the contiguous region to find. + + HintIndex - Supplies the index (zero based) of where we should start + the search from within the bitmap. + +Return Value: + + ULONG - Receives the starting index (zero based) of the contiguous + region of clear bits found. If not such a region cannot be found + a -1 (i.e. 0xffffffff) is returned. + +--*/ + +{ + ULONG SizeOfBitMap; + ULONG SizeInBytes; + + ULONG HintBit; + ULONG MainLoopIndex; + + GET_BYTE_DECLARATIONS(); + + // + // To make the loops in our test run faster we'll extract the + // fields from the bitmap header + // + + SizeOfBitMap = BitMapHeader->SizeOfBitMap; + SizeInBytes = (SizeOfBitMap + 7) / 8; + + // + // Set any unused bits in the last byte so we won't count them. We do + // this by first checking if there is any odd bits in the last byte. + // + + if ((SizeOfBitMap % 8) != 0) { + + // + // The last byte has some odd bits so we'll set the high unused + // bits in the last byte to 1's + // + + ((PUCHAR)BitMapHeader->Buffer)[SizeInBytes - 1] |= + ZeroMask[SizeOfBitMap % 8]; + } + + // + // Calculate from the hint index where the hint byte is and set ourselves + // up to read the hint on the next call to GET_BYTE. To make the + // algorithm run fast we'll only honor hints down to the byte level of + // granularity. There is a possibility that we'll need to execute + // our main logic twice. Once to test from the hint byte to the end of + // the bitmap and the other to test from the start of the bitmap. First + // we need to make sure the Hint Index is within range. + // + + if (HintIndex >= SizeOfBitMap) { + + HintIndex = 0; + } + + HintBit = HintIndex % 8; + + for (MainLoopIndex = 0; MainLoopIndex < 2; MainLoopIndex += 1) { + + ULONG StartByteIndex; + ULONG EndByteIndex; + + UCHAR CurrentByte; + + // + // Check for the first time through the main loop, which indicates + // that we are going to start our search at our hint byte + // + + if (MainLoopIndex == 0) { + + StartByteIndex = HintIndex / 8; + EndByteIndex = SizeInBytes; + + // + // This is the second time through the loop, make sure there is + // actually something to check before the hint byte + // + + } else if (HintIndex != 0) { + + // + // The end index for the second time around is based on the + // number of bits we need to find. We need to use this inorder + // to take the case where the preceding byte to the hint byte + // is the start of our run, and the run includes the hint byte + // and some following bytes, based on the number of bits needed + // The computation is to take the number of bits needed minus + // 2 divided by 8 and then add 2. This will take in to account + // the worst possible case where we have one bit hanging off + // of each end byte, and all intervening bytes are all zero. + // + + if (NumberToFind < 2) { + + EndByteIndex = 0; + + } else { + + EndByteIndex = (HintIndex / 8) + ((NumberToFind - 2) / 8) + 2; + + // + // Make sure we don't overrun the end of the bitmap + // + + if (EndByteIndex > SizeInBytes) { + + EndByteIndex = SizeInBytes; + } + } + + HintIndex = 0; + HintBit = 0; + StartByteIndex = 0; + + // + // Otherwise we already did a complete loop through the bitmap + // so we should simply return -1 to say nothing was found + // + + } else { + + return 0xffffffff; + } + + // + // Set ourselves up to get the next byte + // + + GET_BYTE_INITIALIZATION(BitMapHeader, StartByteIndex); + + // + // Get the first byte, and set any bits before the hint bit. + // + + GET_BYTE( CurrentByte ); + + CurrentByte |= FillMask[HintBit]; + + // + // If the number of bits can only fit in 1 or 2 bytes (i.e., 9 bits or + // less) we do the following test case. + // + + if (NumberToFind <= 9) { + + ULONG CurrentBitIndex; + UCHAR PreviousByte; + + PreviousByte = 0xff; + + // + // Examine all the bytes within our test range searching + // for a fit + // + + CurrentBitIndex = StartByteIndex * 8; + + while (TRUE) { + + // + // If this is the first itteration of the loop, mask Current + // byte with the real hint. + // + + // + // The current byte does not satisfy our requirements so we'll + // check the previous and current byte together to see if + // we'll fit. To check uses the high part of the previous + // byte and low part of the current byte. + // + + if (((ULONG)HalppBitsClearHigh[PreviousByte] + + (ULONG)HalppBitsClearLow[CurrentByte]) >= NumberToFind) { + + ULONG StartingIndex; + + // + // It all fits in these two bytes, so we can compute + // the starting index. This is done by taking the + // index of the current byte (bit 0) and subtracting the + // number of bits its takes to get to the first cleared + // high bit. + // + + StartingIndex = CurrentBitIndex - + (LONG)HalppBitsClearHigh[PreviousByte]; + + // + // Now make sure the total size isn't beyond the bitmap + // + + if ((StartingIndex + NumberToFind) <= SizeOfBitMap) { + + return StartingIndex; + } + } + + // + // Check to see if a single byte will satisfy the requirement + // + + if ((ULONG)HalppBitsClearAnywhere[CurrentByte] >= NumberToFind) { + + UCHAR BitMask; + ULONG i; + + // + // It all fits in a single byte, so calculate the bit + // number. We do this by taking a mask of the appropriate + // size and shifting it over until it fits. It fits when + // we can bitwise-and the current byte with the bitmask + // and get a zero back. + // + + BitMask = FillMask[ NumberToFind ]; + for (i = 0; (BitMask & CurrentByte) != 0; i += 1) { + + BitMask <<= 1; + } + + // + // return to our caller the located bit index, and the + // number that we found. + // + + return CurrentBitIndex + i; + } + + // + // For the next iteration through our loop we need to make + // the current byte into the previous byte, and go to the + // top of the loop again. + // + + PreviousByte = CurrentByte; + + // + // Increment our Bit Index, and either exit, or get the + // next byte. + // + + CurrentBitIndex += 8; + + if ( CurrentBitIndex < EndByteIndex * 8 ) { + + GET_BYTE( CurrentByte ); + + } else { + + break; + } + + } // end loop CurrentBitIndex + + // + // The number to find is greater than 9 but if it is less than 15 + // then we know it can be satisfied with at most 2 bytes, or 3 bytes + // if the middle byte (of the 3) is all zeros. + // + + } else if (NumberToFind < 15) { + + ULONG CurrentBitIndex; + + UCHAR PreviousPreviousByte; + UCHAR PreviousByte; + + PreviousPreviousByte = 0xff; + PreviousByte = 0xff; + + // + // Examine all the bytes within our test range searching + // for a fit + // + + CurrentBitIndex = StartByteIndex * 8; + + while (TRUE) { + + // + // Check to see if the Previous byte and current byte + // together satisfy the request. + // + + if (((ULONG)HalppBitsClearHigh[PreviousByte] + + (ULONG)HalppBitsClearLow[CurrentByte]) >= NumberToFind) { + + ULONG StartingIndex; + + // + // It all fits in these two bytes, so we can compute + // the starting index. This is done by taking the + // index of the current byte (bit 0) and subtracting the + // number of bits its takes to get to the first cleared + // high bit. + // + + StartingIndex = CurrentBitIndex - + (LONG)HalppBitsClearHigh[PreviousByte]; + + // + // Now make sure the total size isn't beyond the bitmap + // + + if ((StartingIndex + NumberToFind) <= SizeOfBitMap) { + + return StartingIndex; + } + } + + // + // if the previous byte is all zeros then maybe the + // request can be satisfied using the Previous Previous Byte + // Previous Byte, and the Current Byte. + // + + if ((PreviousByte == 0) + + && + + (((ULONG)HalppBitsClearHigh[PreviousPreviousByte] + 8 + + (ULONG)HalppBitsClearLow[CurrentByte]) >= NumberToFind)) { + + ULONG StartingIndex; + + // + // It all fits in these three bytes, so we can compute + // the starting index. This is done by taking the + // index of the previous byte (bit 0) and subtracting + // the number of bits its takes to get to the first + // cleared high bit. + // + + StartingIndex = (CurrentBitIndex - 8) - + (LONG)HalppBitsClearHigh[PreviousPreviousByte]; + + // + // Now make sure the total size isn't beyond the bitmap + // + + if ((StartingIndex + NumberToFind) <= SizeOfBitMap) { + + return StartingIndex; + } + } + + // + // For the next iteration through our loop we need to make + // the current byte into the previous byte, the previous + // byte into the previous previous byte, and go to the + // top of the loop again. + // + + PreviousPreviousByte = PreviousByte; + PreviousByte = CurrentByte; + + // + // Increment our Bit Index, and either exit, or get the + // next byte. + // + + CurrentBitIndex += 8; + + if ( CurrentBitIndex < EndByteIndex * 8 ) { + + GET_BYTE( CurrentByte ); + + } else { + + break; + } + + } // end loop CurrentBitIndex + + // + // The number to find is greater than or equal to 15. This request + // has to have at least one byte of all zeros to be satisfied + // + + } else { + + ULONG CurrentByteIndex; + + ULONG ZeroBytesNeeded; + ULONG ZeroBytesFound; + + UCHAR StartOfRunByte; + LONG StartOfRunIndex; + + // + // First precalculate how many zero bytes we're going to need + // + + ZeroBytesNeeded = (NumberToFind - 7) / 8; + + // + // Indicate for the first time through our loop that we haven't + // found a zero byte yet, and indicate that the start of the + // run is the byte just before the start byte index + // + + ZeroBytesFound = 0; + StartOfRunByte = 0xff; + StartOfRunIndex = StartByteIndex - 1; + + // + // Examine all the bytes in our test range searching for a fit + // + + CurrentByteIndex = StartByteIndex; + + while (TRUE) { + + // + // If the number of zero bytes fits our minimum requirements + // then we can do the additional test to see if we + // actually found a fit + // + + if ((ZeroBytesFound >= ZeroBytesNeeded) + + && + + ((ULONG)HalppBitsClearHigh[StartOfRunByte] + ZeroBytesFound*8 + + (ULONG)HalppBitsClearLow[CurrentByte]) >= NumberToFind) { + + ULONG StartingIndex; + + // + // It all fits in these bytes, so we can compute + // the starting index. This is done by taking the + // StartOfRunIndex times 8 and adding the number of bits + // it takes to get to the first cleared high bit. + // + + StartingIndex = (StartOfRunIndex * 8) + + (8 - (LONG)HalppBitsClearHigh[StartOfRunByte]); + + // + // Now make sure the total size isn't beyond the bitmap + // + + if ((StartingIndex + NumberToFind) <= SizeOfBitMap) { + + return StartingIndex; + } + } + + // + // Check to see if the byte is zero and increment + // the number of zero bytes found + // + + if (CurrentByte == 0) { + + ZeroBytesFound += 1; + + // + // The byte isn't a zero so we need to start over again + // looking for zero bytes. + // + + } else { + + ZeroBytesFound = 0; + StartOfRunByte = CurrentByte; + StartOfRunIndex = CurrentByteIndex; + } + + // + // Increment our Byte Index, and either exit, or get the + // next byte. + // + + CurrentByteIndex += 1; + + if ( CurrentByteIndex < EndByteIndex ) { + + GET_BYTE( CurrentByte ); + + } else { + + break; + } + + } // end loop CurrentByteIndex + } + } + + // + // We never found a fit so we'll return -1 + // + + return 0xffffffff; +} + + +ULONG +HalpFindSetBits ( + IN PRTL_BITMAP BitMapHeader, + IN ULONG NumberToFind, + IN ULONG HintIndex + ) + +/*++ + +Routine Description: + + This procedure searches the specified bit map for the specified + contiguous region of set bits. + +Arguments: + + BitMapHeader - Supplies a pointer to the previously initialized BitMap. + + NumberToFind - Supplies the size of the contiguous region to find. + + HintIndex - Supplies the index (zero based) of where we should start + the search from within the bitmap. + +Return Value: + + ULONG - Receives the starting index (zero based) of the contiguous + region of set bits found. If such a region cannot be found then + a -1 (i.e., 0xffffffff) is returned. + +--*/ + +{ + ULONG SizeOfBitMap; + ULONG SizeInBytes; + + ULONG HintByte; + + ULONG MainLoopIndex; + + GET_BYTE_DECLARATIONS(); + + // + // To make the loops in our test run faster we'll extract the + // fields from the bitmap header + // + + SizeOfBitMap = BitMapHeader->SizeOfBitMap; + SizeInBytes = (SizeOfBitMap + 7) / 8; + + // + // Set any unused bits in the last byte so we won't count them. We do + // this by first checking if there is any odd bits in the last byte. + // + + if ((SizeOfBitMap % 8) != 0) { + + // + // The last byte has some odd bits so we'll set the high unused + // bits in the last byte to 0's + // + + ((PUCHAR)BitMapHeader->Buffer)[SizeInBytes - 1] &= + FillMask[SizeOfBitMap % 8]; + } + + // + // Calculate from the hint index where the hint byte is and set ourselves + // up to read the hint on the next call to GET_BYTE. To make the + // algorithm run fast we'll only honor hints down to the byte level of + // granularity. There is a possibility that we'll need to execute + // our main logic twice. Once to test from the hint byte to the end of + // the bitmap and the other to test from the start of the bitmap. First + // we need to make sure the Hint Index is within range. + // + + if (HintIndex >= SizeOfBitMap) { + + HintIndex = 0; + } + + HintByte = HintIndex / 8; + + for (MainLoopIndex = 0; MainLoopIndex < 2; MainLoopIndex += 1) { + + ULONG StartByteIndex; + ULONG EndByteIndex; + + // + // Check for the first time through the main loop, which indicates + // that we are going to start our search at our hint byte + // + + if (MainLoopIndex == 0) { + + StartByteIndex = HintByte; + EndByteIndex = SizeInBytes; + + // + // This is the second time through the loop, make sure there is + // actually something to check before the hint byte + // + + } else if (HintByte != 0) { + + StartByteIndex = 0; + + // + // The end index for the second time around is based on the + // number of bits we need to find. We need to use this inorder + // to take the case where the preceding byte to the hint byte + // is the start of our run, and the run includes the hint byte + // and some following bytes, based on the number of bits needed + // The computation is to take the number of bits needed minus + // 2 divided by 8 and then add 2. This will take in to account + // the worst possible case where we have one bit hanging off + // of each end byte, and all intervening bytes are all zero. + // We only need to add one in the following equation because + // HintByte is already counted. + // + + if (NumberToFind < 2) { + + EndByteIndex = HintByte; + + } else { + + EndByteIndex = HintByte + ((NumberToFind - 2) / 8) + 1; + + // + // Make sure we don't overrun the end of the bitmap + // + + if (EndByteIndex > SizeInBytes) { + + EndByteIndex = SizeInBytes; + } + } + + // + // Otherwise we already did a complete loop through the bitmap + // so we should simply return -1 to say nothing was found + // + + } else { + + return 0xffffffff; + + } + + // + // Set ourselves up to get the next byte + // + + GET_BYTE_INITIALIZATION(BitMapHeader, StartByteIndex); + + // + // If the number of bits can only fit in 1 or 2 bytes (i.e., 9 bits or + // less) we do the following test case. + // + + if (NumberToFind <= 9) { + + ULONG CurrentBitIndex; + + UCHAR PreviousByte; + UCHAR CurrentByte; + + PreviousByte = 0x00; + + // + // Examine all the bytes within our test range searching + // for a fit + // + + for (CurrentBitIndex = StartByteIndex * 8; + CurrentBitIndex < EndByteIndex * 8; + CurrentBitIndex += 8) { + + // + // Get the current byte + // + + GET_BYTE( CurrentByte ); + + // + // Check to see if a single byte will satisfy the requirement + // + + if ((ULONG)HalppBitSetAnywhere(CurrentByte) >= NumberToFind) { + + UCHAR BitMask; + ULONG i; + + // + // It all fits in a single byte, so calculate the bit + // number. We do this by taking a mask of the appropriate + // size and shifting it over until it fits. It fits when + // we can bitwise-and the current byte with the bit mask + // and get back the bit mask. + // + + BitMask = FillMask[ NumberToFind ]; + for (i = 0; (BitMask & CurrentByte) != BitMask; i += 1) { + + BitMask <<= 1; + } + + // + // return to our caller the located bit index, and the + // number that we found. + // + + return CurrentBitIndex + i; + } + + // + // The current byte does not satisfy our requirements so we'll + // check the previous and current byte together to see if + // we'll fit. To check uses the high part of the previous + // byte and low part of the current byte. + // + + if (((ULONG)HalppBitsSetHigh(PreviousByte) + + (ULONG)HalppBitsSetLow(CurrentByte)) >= NumberToFind) { + + ULONG StartingIndex; + + // + // It all fits in these two bytes, so we can compute + // the starting index. This is done by taking the + // index of the current byte (bit 0) and subtracting the + // number of bits its takes to get to the first set + // high bit. + // + + StartingIndex = CurrentBitIndex - + (LONG)HalppBitsSetHigh(PreviousByte); + + // + // Now make sure the total size isn't beyond the bitmap + // + + if ((StartingIndex + NumberToFind) <= SizeOfBitMap) { + + return StartingIndex; + } + } + + // + // For the next iteration through our loop we need to make + // the current byte into the previous byte, and go to the + // top of the loop again. + // + + PreviousByte = CurrentByte; + + } // end loop CurrentBitIndex + + // + // The number to find is greater than 9 but if it is less than 15 + // then we know it can be satisfied with at most 2 bytes, or 3 bytes + // if the middle byte (of the 3) is all ones. + // + + } else if (NumberToFind < 15) { + + ULONG CurrentBitIndex; + + UCHAR PreviousPreviousByte; + UCHAR PreviousByte; + UCHAR CurrentByte; + + PreviousPreviousByte = 0x00; + PreviousByte = 0x00; + + // + // Examine all the bytes within our test range searching + // for a fit + // + + for (CurrentBitIndex = StartByteIndex * 8; + CurrentBitIndex < EndByteIndex * 8; + CurrentBitIndex += 8) { + + // + // Get the current byte + // + + GET_BYTE( CurrentByte ); + + // + // Check to see if the Previous byte and current byte + // together satisfy the request. + // + + if (((ULONG)HalppBitsSetHigh(PreviousByte) + + (ULONG)HalppBitsSetLow(CurrentByte)) >= NumberToFind) { + + ULONG StartingIndex; + + // + // It all fits in these two bytes, so we can compute + // the starting index. This is done by taking the + // index of the current byte (bit 0) and subtracting the + // number of bits its takes to get to the first set + // high bit. + // + + StartingIndex = CurrentBitIndex - + (LONG)HalppBitsSetHigh(PreviousByte); + + // + // Now make sure the total size isn't beyond the bitmap + // + + if ((StartingIndex + NumberToFind) <= SizeOfBitMap) { + + return StartingIndex; + } + } + + // + // if the previous byte is all ones then maybe the + // request can be satisfied using the Previous Previous Byte + // Previous Byte, and the Current Byte. + // + + if ((PreviousByte == 0xff) + + && + + (((ULONG)HalppBitsSetHigh(PreviousPreviousByte) + 8 + + (ULONG)HalppBitsSetLow(CurrentByte)) >= NumberToFind)) { + + ULONG StartingIndex; + + // + // It all fits in these three bytes, so we can compute + // the starting index. This is done by taking the + // index of the previous byte (bit 0) and subtracting + // the number of bits its takes to get to the first + // set high bit. + // + + StartingIndex = (CurrentBitIndex - 8) - + (LONG)HalppBitsSetHigh(PreviousPreviousByte); + + // + // Now make sure the total size isn't beyond the bitmap + // + + if ((StartingIndex + NumberToFind) <= SizeOfBitMap) { + + return StartingIndex; + } + } + + // + // For the next iteration through our loop we need to make + // the current byte into the previous byte, the previous + // byte into the previous previous byte, and go to the + // top of the loop again. + // + + PreviousPreviousByte = PreviousByte; + PreviousByte = CurrentByte; + + } // end loop CurrentBitIndex + + // + // The number to find is greater than or equal to 15. This request + // has to have at least one byte of all ones to be satisfied + // + + } else { + + ULONG CurrentByteIndex; + + UCHAR CurrentByte; + + ULONG OneBytesNeeded; + ULONG OneBytesFound; + + UCHAR StartOfRunByte; + LONG StartOfRunIndex; + + // + // First precalculate how many one bytes we're going to need + // + + OneBytesNeeded = (NumberToFind - 7) / 8; + + // + // Indicate for the first time through our loop that we haven't + // found a one byte yet, and indicate that the start of the + // run is the byte just before the start byte index + // + + OneBytesFound = 0; + StartOfRunByte = 0x00; + StartOfRunIndex = StartByteIndex - 1; + + // + // Examine all the bytes in our test range searching for a fit + // + + for (CurrentByteIndex = StartByteIndex; + CurrentByteIndex < EndByteIndex; + CurrentByteIndex += 1) { + + // + // Get the current byte + // + + GET_BYTE( CurrentByte ); + + // + // If the number of zero bytes fits our minimum requirements + // then we can do the additional test to see if we + // actually found a fit + // + + if ((OneBytesFound >= OneBytesNeeded) + + && + + ((ULONG)HalppBitsSetHigh(StartOfRunByte) + OneBytesFound*8 + + (ULONG)HalppBitsSetLow(CurrentByte)) >= NumberToFind) { + + ULONG StartingIndex; + + // + // It all fits in these bytes, so we can compute + // the starting index. This is done by taking the + // StartOfRunIndex times 8 and adding the number of bits + // it takes to get to the first set high bit. + // + + StartingIndex = (StartOfRunIndex * 8) + + (8 - (LONG)HalppBitsSetHigh(StartOfRunByte)); + + // + // Now make sure the total size isn't beyond the bitmap + // + + if ((StartingIndex + NumberToFind) <= SizeOfBitMap) { + + return StartingIndex; + } + } + + // + // Check to see if the byte is all ones and increment + // the number of one bytes found + // + + if (CurrentByte == 0xff) { + + OneBytesFound += 1; + + // + // The byte isn't all ones so we need to start over again + // looking for one bytes. + // + + } else { + + OneBytesFound = 0; + StartOfRunByte = CurrentByte; + StartOfRunIndex = CurrentByteIndex; + } + + } // end loop CurrentByteIndex + } + } + + // + // We never found a fit so we'll return -1 + // + + return 0xffffffff; +} + + +ULONG +HalpFindClearBitsAndSet ( + IN PRTL_BITMAP BitMapHeader, + IN ULONG NumberToFind, + IN ULONG HintIndex + ) + +/*++ + +Routine Description: + + This procedure searches the specified bit map for the specified + contiguous region of clear bits, sets the bits and returns the + number of bits found, and the starting bit number which was clear + then set. + +Arguments: + + BitMapHeader - Supplies a pointer to the previously initialized BitMap. + + NumberToFind - Supplies the size of the contiguous region to find. + + HintIndex - Supplies the index (zero based) of where we should start + the search from within the bitmap. + +Return Value: + + ULONG - Receives the starting index (zero based) of the contiguous + region found. If such a region cannot be located a -1 (i.e., + 0xffffffff) is returned. + +--*/ + +{ + ULONG StartingIndex; + + // + // First look for a run of clear bits that equals the size requested + // + + StartingIndex = HalpFindClearBits( BitMapHeader, + NumberToFind, + HintIndex ); + + //DbgPrint("FindClearBits %08lx, ", NumberToFind); + //DbgPrint("%08lx", StartingIndex); + //DumpBitMap(BitMapHeader); + + if (StartingIndex != 0xffffffff) { + + // + // We found a large enough run of clear bits so now set them + // + + HalpSetBits( BitMapHeader, StartingIndex, NumberToFind ); + } + + // + // And return to our caller + // + + return StartingIndex; + +} + + +ULONG +HalpFindSetBitsAndClear ( + IN PRTL_BITMAP BitMapHeader, + IN ULONG NumberToFind, + IN ULONG HintIndex + ) + +/*++ + +Routine Description: + + This procedure searches the specified bit map for the specified + contiguous region of set bits, clears the bits and returns the + number of bits found and the starting bit number which was set then + clear. + +Arguments: + + BitMapHeader - Supplies a pointer to the previously initialized BitMap. + + NumberToFind - Supplies the size of the contiguous region to find. + + HintIndex - Supplies the index (zero based) of where we should start + the search from within the bitmap. + +Return Value: + + ULONG - Receives the starting index (zero based) of the contiguous + region found. If such a region cannot be located a -1 (i.e., + 0xffffffff) is returned. + + +--*/ + +{ + ULONG StartingIndex; + + // + // First look for a run of set bits that equals the size requested + // + + if ((StartingIndex = HalpFindSetBits( BitMapHeader, + NumberToFind, + HintIndex )) != 0xffffffff) { + + // + // We found a large enough run of set bits so now clear them + // + + HalpClearBits( BitMapHeader, StartingIndex, NumberToFind ); + } + + // + // And return to our caller + // + + return StartingIndex; +} + + +VOID +HalpClearBits ( + IN PRTL_BITMAP BitMapHeader, + IN ULONG StartingIndex, + IN ULONG NumberToClear + ) + +/*++ + +Routine Description: + + This procedure clears the specified range of bits within the + specified bit map. + +Arguments: + + BitMapHeader - Supplies a pointer to the previously initialized Bit Map. + + StartingIndex - Supplies the index (zero based) of the first bit to clear. + + NumberToClear - Supplies the number of bits to clear. + +Return Value: + + None. + +--*/ + +{ + ULONG BitOffset; + PULONG CurrentLong; + + //DbgPrint("ClearBits %08lx, ", NumberToClear); + //DbgPrint("%08lx", StartingIndex); + + ASSERT( StartingIndex + NumberToClear <= BitMapHeader->SizeOfBitMap ); + + // + // Special case the situation where the number of bits to clear is + // zero. Turn this into a noop. + // + + if (NumberToClear == 0) { + + return; + } + + BitOffset = StartingIndex % 32; + + // + // Get a pointer to the first longword that needs to be zeroed out + // + + CurrentLong = &BitMapHeader->Buffer[ StartingIndex / 32 ]; + + // + // Check if we can only need to clear out one longword. + // + + if ((BitOffset + NumberToClear) <= 32) { + + // + // To build a mask of bits to clear we shift left to get the number + // of bits we're clearing and then shift right to put it in position. + // We'll typecast the right shift to ULONG to make sure it doesn't + // do a sign extend. + // + + *CurrentLong &= ~LeftShiftUlong(RightShiftUlong(((ULONG)0xFFFFFFFF),(32 - NumberToClear)), + BitOffset); + + // + // And return to our caller + // + + //DumpBitMap(BitMapHeader); + + return; + } + + // + // We can clear out to the end of the first longword so we'll + // do that right now. + // + + *CurrentLong &= ~LeftShiftUlong(0xFFFFFFFF, BitOffset); + + // + // And indicate what the next longword to clear is and how many + // bits are left to clear + // + + CurrentLong += 1; + NumberToClear -= 32 - BitOffset; + + // + // The bit position is now long aligned, so we can continue + // clearing longwords until the number to clear is less than 32 + // + + while (NumberToClear >= 32) { + + *CurrentLong = 0; + CurrentLong += 1; + NumberToClear -= 32; + } + + // + // And now we can clear the remaining bits, if there are any, in the + // last longword + // + + if (NumberToClear > 0) { + + *CurrentLong &= LeftShiftUlong(0xFFFFFFFF, NumberToClear); + } + + // + // And return to our caller + // + + //DumpBitMap(BitMapHeader); + + return; +} + +VOID +HalpSetBits ( + IN PRTL_BITMAP BitMapHeader, + IN ULONG StartingIndex, + IN ULONG NumberToSet + ) + +/*++ + +Routine Description: + + This procedure sets the specified range of bits within the + specified bit map. + +Arguments: + + BitMapHeader - Supplies a pointer to the previously initialied BitMap. + + StartingIndex - Supplies the index (zero based) of the first bit to set. + + NumberToSet - Supplies the number of bits to set. + +Return Value: + + None. + +--*/ +{ + ULONG BitOffset; + PULONG CurrentLong; + + //DbgPrint("SetBits %08lx, ", NumberToSet); + //DbgPrint("%08lx", StartingIndex); + + ASSERT( StartingIndex + NumberToSet <= BitMapHeader->SizeOfBitMap ); + + // + // Special case the situation where the number of bits to set is + // zero. Turn this into a noop. + // + + if (NumberToSet == 0) { + + return; + } + + BitOffset = StartingIndex % 32; + + // + // Get a pointer to the first longword that needs to be set + // + + CurrentLong = &BitMapHeader->Buffer[ StartingIndex / 32 ]; + + // + // Check if we can only need to set one longword. + // + + if ((BitOffset + NumberToSet) <= 32) { + + // + // To build a mask of bits to set we shift left to get the number + // of bits we're setting and then shift right to put it in position. + // We'll typecast the right shift to ULONG to make sure it doesn't + // do a sign extend. + // + + *CurrentLong |= LeftShiftUlong(RightShiftUlong(((ULONG)0xFFFFFFFF),(32 - NumberToSet)), + BitOffset); + + // + // And return to our caller + // + + //DumpBitMap(BitMapHeader); + + return; + } + + // + // We can set bits out to the end of the first longword so we'll + // do that right now. + // + + *CurrentLong |= LeftShiftUlong(0xFFFFFFFF, BitOffset); + + // + // And indicate what the next longword to set is and how many + // bits are left to set + // + + CurrentLong += 1; + NumberToSet -= 32 - BitOffset; + + // + // The bit position is now long aligned, so we can continue + // setting longwords until the number to set is less than 32 + // + + while (NumberToSet >= 32) { + + *CurrentLong = 0xffffffff; + CurrentLong += 1; + NumberToSet -= 32; + } + + // + // And now we can set the remaining bits, if there are any, in the + // last longword + // + + if (NumberToSet > 0) { + + *CurrentLong |= ~LeftShiftUlong(0xFFFFFFFF, NumberToSet); + } + + // + // And return to our caller + // + + //DumpBitMap(BitMapHeader); + + return; +} + + +ULONG +HalpFindLongestRunClear ( + IN PRTL_BITMAP BitMapHeader, + OUT PULONG StartingIndex + ) + +/*++ + +Routine Description: + + This procedure finds the largest contiguous range of clear bits + within the specified bit map. + +Arguments: + + BitMapHeader - Supplies a pointer to the previously initialized BitMap. + + StartingIndex - Receives the index (zero based) of the first run + equal to the longest run of clear bits in the BitMap. + +Return Value: + + ULONG - Receives the number of bits contained in the largest contiguous + run of clear bits. + +--*/ + +{ + ULONG SizeOfBitMap; + ULONG SizeInBytes; + + ULONG LongestRunSize; + ULONG LongestRunIndex; + + ULONG CurrentRunSize; + ULONG CurrentRunIndex; + ULONG CurrentByteIndex; + UCHAR CurrentByte; + + GET_BYTE_DECLARATIONS(); + + // + // Reference the bitmap header to make the loop run faster + // + + SizeOfBitMap = BitMapHeader->SizeOfBitMap; + SizeInBytes = (SizeOfBitMap + 7) / 8; + + // + // Set any unused bits in the last byte so we won't count them. We do + // this by first checking if there is any odd bits in the last byte. + // + + if ((SizeOfBitMap % 8) != 0) { + + // + // The last byte has some odd bits so we'll set the high unused + // bits in the last byte to 1's + // + + ((PUCHAR)BitMapHeader->Buffer)[SizeInBytes - 1] |= + ZeroMask[SizeOfBitMap % 8]; + } + + // + // Set it up so we can the use GET_BYTE macro + // + + GET_BYTE_INITIALIZATION( BitMapHeader, 0); + + // + // Set our longest and current run variables + // + + LongestRunSize = 0; + LongestRunIndex = 0; + + CurrentRunSize = 0; + CurrentRunIndex = 0; + + // + // Examine every byte in the BitMap + // + + for (CurrentByteIndex = 0; + CurrentByteIndex < SizeInBytes; + CurrentByteIndex += 1) { + + GET_BYTE( CurrentByte ); + + // + // If the current byte is not all zeros we need to + // (1) check if the current run is big enough to supercede the + // longest run, and (2) check if the current byte inside of + // itself can supercede the longest run, and (3) start a new + // current run + // + + if (CurrentByte != 0x00) { + + UCHAR Temp; + + // + // Compute the final size of the current run + // + + CurrentRunSize += HalppBitsClearLow[CurrentByte]; + + // + // Check if the current run is larger than the longest run that + // we've found so far + // + + if (CurrentRunSize > LongestRunSize) { + + LongestRunSize = CurrentRunSize; + LongestRunIndex = CurrentRunIndex; + } + + // + // The next run starts with the remaining clear bits in the + // current byte. We set this up before we check inside the + // current byte for a longer run, because the latter test + // might require extra work. + // + + CurrentRunSize = HalppBitsClearHigh[ CurrentByte ]; + CurrentRunIndex = (CurrentByteIndex * 8) + (8 - CurrentRunSize); + + // + // Check if the current byte contains a run inside of it that + // is both greater than the longest run size, and the current + // run size. But we'll only both with this test if the + // longest run size, and current run size are both less than 8. + // + + if ((LongestRunSize < 8) && (CurrentRunSize < 8) && + ((ULONG)(Temp = HalppBitsClearAnywhere[CurrentByte]) > LongestRunSize) && + ((ULONG)Temp > CurrentRunSize)) { + + UCHAR BitMask; + ULONG i; + + // + // Somewhere in the current byte is a run longer than the + // longest run, or the current run. All we need to do now + // is find the index for this new longest run. + // + + BitMask = FillMask[ Temp ]; + + for (i = 0; (BitMask & CurrentByte) != 0; i += 1) { + + BitMask <<= 1; + } + + LongestRunIndex = (CurrentByteIndex * 8) + i; + LongestRunSize = Temp; + } + + // + // Otherwise the current byte is all zeros and + // we simply continue with the current run + // + + } else { + + CurrentRunSize += 8; + } + } + + // + // See if we finished looking over the bitmap with an open current + // run that is longer than the longest saved run + // + + if (CurrentRunSize > LongestRunSize) { + + LongestRunSize = CurrentRunSize; + LongestRunIndex = CurrentRunIndex; + } + + // + // Set our output variables and return to our caller + // + + *StartingIndex = LongestRunIndex; + return LongestRunSize; +} + + +ULONG +HalpFindLongestRunSet ( + IN PRTL_BITMAP BitMapHeader, + OUT PULONG StartingIndex + ) + +/*++ + +Routine Description: + + This procedure finds the largest contiguous range of set bits + within the specified bit map. + +Arguments: + + BitMapHeader - Supplies a pointer to the previously initialized BitMap. + + StartingIndex - Receives the index (zero based) of the first run + equal to the longest run of set bits in the BitMap. + +Return Value: + + ULONG - Receives the number of bits contained in the largest contiguous + run of set bits. + +--*/ + +{ + ULONG SizeOfBitMap; + ULONG SizeInBytes; + + ULONG LongestRunSize; + ULONG LongestRunIndex; + + ULONG CurrentRunSize; + ULONG CurrentRunIndex; + ULONG CurrentByteIndex; + UCHAR CurrentByte; + + GET_BYTE_DECLARATIONS(); + + // + // Reference the bitmap header to make the loop run faster + // + + SizeOfBitMap = BitMapHeader->SizeOfBitMap; + SizeInBytes = (SizeOfBitMap + 7) / 8; + + // + // Set any unused bits in the last byte so we won't count them. We do + // this by first checking if there is any odd bits in the last byte. + // + + if ((SizeOfBitMap % 8) != 0) { + + // + // The last byte has some odd bits so we'll set the high unused + // bits in the last byte to 0's + // + + ((PUCHAR)BitMapHeader->Buffer)[SizeInBytes - 1] &= + FillMask[SizeOfBitMap % 8]; + } + + // + // Set it up so we can the use GET_BYTE macro + // + + GET_BYTE_INITIALIZATION( BitMapHeader, 0); + + // + // Set our longest and current run variables + // + + LongestRunSize = 0; + LongestRunIndex = 0; + + CurrentRunSize = 0; + CurrentRunIndex = 0; + + // + // Examine every byte in the BitMap + // + + for (CurrentByteIndex = 0; + CurrentByteIndex < SizeInBytes; + CurrentByteIndex += 1) { + + GET_BYTE( CurrentByte ); + + // + // If the current byte is not all ones we need to + // (1) check if the current run is big enough to supercede the + // longest run, and (2) check if the current byte inside of + // itself can supercede the longest run, and (3) start a new + // current run + // + + if (CurrentByte != 0xff) { + + UCHAR Temp; + + // + // Compute the final size of the current run + // + + CurrentRunSize += HalppBitsSetLow(CurrentByte); + + // + // Check if the current run is larger than the longest run that + // we've found so far + // + + if (CurrentRunSize > LongestRunSize) { + + LongestRunSize = CurrentRunSize; + LongestRunIndex = CurrentRunIndex; + } + + // + // The next run starts with the remaining set bits in the + // current byte. We set this up before we check inside the + // current byte for a longer run, because the latter test + // might require extra work. + // + + CurrentRunSize = HalppBitsSetHigh( CurrentByte ); + CurrentRunIndex = (CurrentByteIndex * 8) + (8 - CurrentRunSize); + + // + // Check if the current byte contains a run inside of it that + // is both greater than the longest run size, and the current + // run size. But we'll only both with this test if the + // longest run size, and current run size are both less than 8. + // + + if ((LongestRunSize < 8) && (CurrentRunSize < 8) && + ((ULONG)(Temp = HalppBitSetAnywhere(CurrentByte)) > LongestRunSize) && + ((ULONG)Temp > CurrentRunSize)) { + + UCHAR BitMask; + ULONG i; + + // + // Somewhere in the current byte is a run longer than the + // longest run, or the current run. All we need to do now + // is find the index for this new longest run. + // + + BitMask = FillMask[ Temp ]; + + for (i = 0; (BitMask & CurrentByte) != BitMask; i += 1) { + + BitMask <<= 1; + } + + LongestRunIndex = (CurrentByteIndex * 8) + i; + LongestRunSize = Temp; + } + + // + // Otherwise the current byte is all ones and + // we simply continue with the current run + // + + } else { + + CurrentRunSize += 8; + } + } + + // + // See if we finished looking over the bitmap with an open current + // run that is longer than the longest saved run + // + + if (CurrentRunSize > LongestRunSize) { + + LongestRunSize = CurrentRunSize; + LongestRunIndex = CurrentRunIndex; + } + + // + // Set our output variables and return to our caller + // + + *StartingIndex = LongestRunIndex; + return LongestRunSize; +} + + +ULONG +HalpFindFirstRunClear ( + IN PRTL_BITMAP BitMapHeader, + OUT PULONG StartingIndex + ) + +/*++ + +Routine Description: + + This procedure finds the first contiguous range of clear bits + within the specified bit map. + +Arguments: + + BitMapHeader - Supplies a pointer to the previously initialized BitMap. + + StartingIndex - Receives the index (zero based) of the first run + equal to the longest run of clear bits in the BitMap. + +Return Value: + + ULONG - Receives the number of bits contained in the first contiguous + run of clear bits. + +--*/ + +{ + ULONG SizeOfBitMap; + ULONG SizeInBytes; + + ULONG CurrentRunSize; + ULONG CurrentRunIndex; + ULONG CurrentByteIndex; + UCHAR CurrentByte; + + GET_BYTE_DECLARATIONS(); + + // + // Reference the bitmap header to make the loop run faster + // + + SizeOfBitMap = BitMapHeader->SizeOfBitMap; + SizeInBytes = (SizeOfBitMap + 7) / 8; + + // + // Set any unused bits in the last byte so we won't count them. We do + // this by first checking if there is any odd bits in the last byte. + // + + if ((SizeOfBitMap % 8) != 0) { + + // + // The last byte has some odd bits so we'll set the high unused + // bits in the last byte to 1's + // + + ((PUCHAR)BitMapHeader->Buffer)[SizeInBytes - 1] |= + ZeroMask[SizeOfBitMap % 8]; + + } + + // + // Set it up so we can the use GET_BYTE macro + // + + GET_BYTE_INITIALIZATION( BitMapHeader, 0); + + // + // Set our current run variables + // + + CurrentRunSize = 0; + CurrentRunIndex = 0xffffffff; + + // + // Examine every byte in the BitMap. We'll also break out of this + // loop if ever we finish off a run. + // + + for (CurrentByteIndex = 0; + CurrentByteIndex < SizeInBytes; + CurrentByteIndex += 1) { + + GET_BYTE( CurrentByte ); + + // + // If the current byte is all ones and the run size is zero then + // skip over this byte because we haven't found the start of a + // run yet. + // + + if ((CurrentByte == 0xff) && (CurrentRunSize == 0)) { + + NOTHING; + + // + // See if the current byte is all zeros, because if it is then + // we simply continue with the current run + // + + } else if (CurrentByte == 0x00) { + + CurrentRunSize += 8; + + if (CurrentRunIndex == 0xffffffff) { + + CurrentRunIndex = (CurrentByteIndex * 8); + } + + // + // Otherwise the current byte is not all zeros, so we need to + // (1) check if we have a current run, or (2) check if the + // current byte inside of itself is a run, or (3) start a + // current run. + // + // Check if we have a current run, we do that by checking + // if the low bits are clear. + // + + } else if (CurrentRunSize != 0) { + + CurrentRunSize += HalppBitsClearLow[CurrentByte]; + break; + + // + // Check if we have an internal run, we do that by checking + // if the high bits are not clear. This check actually cheats + // a bit in that the current byte might have an inside run + // but we'll skip over it because we can start a run at the + // end of the byte. + // + + } else if (HalppBitsClearHigh[CurrentByte] == 0) { + + UCHAR BitMask; + ULONG i; + + ASSERT( HalppBitsClearAnywhere[CurrentByte] != 0 ); + + CurrentRunSize = HalppBitsClearAnywhere[CurrentByte]; + + // + // Somewhere in the current byte is a run. All we need to do now + // is find the index for this new run. + // + + BitMask = FillMask[ CurrentRunSize ]; + + for (i = 0; (BitMask & CurrentByte) != 0; i += 1) { + + BitMask <<= 1; + } + + CurrentRunIndex = (CurrentByteIndex * 8) + i; + break; + + // + // Otherwise we start a new current run. It starts with the + // remaining clear bits in the current byte. + // + + } else { + + CurrentRunSize = HalppBitsClearHigh[ CurrentByte ]; + CurrentRunIndex = (CurrentByteIndex * 8) + (8 - CurrentRunSize); + } + } + + // + // Set our output variables and return to our caller + // + + *StartingIndex = CurrentRunIndex; + return CurrentRunSize; +} + + +ULONG +HalpFindFirstRunSet ( + IN PRTL_BITMAP BitMapHeader, + OUT PULONG StartingIndex + ) + +/*++ + +Routine Description: + + This procedure finds the first contiguous range of set bits + within the specified bit map. + +Arguments: + + BitMapHeader - Supplies a pointer to the previously initialized BitMap. + + StartingIndex - Receives the index (zero based) of the first run + equal to the longest run of set bits in the BitMap. + +Return Value: + + ULONG - Receives the number of bits contained in the largest contiguous + run of set bits. + +--*/ + +{ + ULONG SizeOfBitMap; + ULONG SizeInBytes; + + ULONG CurrentRunSize; + ULONG CurrentRunIndex; + ULONG CurrentByteIndex; + UCHAR CurrentByte; + + GET_BYTE_DECLARATIONS(); + + // + // Reference the bitmap header to make the loop run faster + // + + SizeOfBitMap = BitMapHeader->SizeOfBitMap; + SizeInBytes = (SizeOfBitMap + 7) / 8; + + // + // Set any unused bits in the last byte so we won't count them. We do + // this by first checking if there is any odd bits in the last byte. + // + + if ((SizeOfBitMap % 8) != 0) { + + // + // The last byte has some odd bits so we'll set the high unused + // bits in the last byte to 0's + // + + ((PUCHAR)BitMapHeader->Buffer)[SizeInBytes - 1] &= + FillMask[SizeOfBitMap % 8]; + } + + // + // Set it up so we can the use GET_BYTE macro + // + + GET_BYTE_INITIALIZATION( BitMapHeader, 0); + + // + // Set our current run variables + // + + CurrentRunSize = 0; + CurrentRunIndex = 0xffffffff; + + // + // Examine every byte in the BitMap. We'll also break out of this + // loop if ever we finish off a run. + // + + for (CurrentByteIndex = 0; + CurrentByteIndex < SizeInBytes; + CurrentByteIndex += 1) { + + GET_BYTE( CurrentByte ); + + // + // If the current byte is all zeros and the run size is zero then + // skip over this byte because we haven't found the start of a + // run yet. + // + + if ((CurrentByte == 0x00) && (CurrentRunSize == 0)) { + + NOTHING; + + // + // See if the current byte is all ones, because if it is then + // we simply continue with the current run + // + + } else if (CurrentByte == 0xff) { + + CurrentRunSize += 8; + + if (CurrentRunIndex == 0xffffffff) { + + CurrentRunIndex = (CurrentByteIndex * 8); + } + + // + // Otherwise the current byte is not all ones, so we need to + // (1) check if we have the current run, or (2) check if the + // current byte inside of itself is a run, or (3) start a + // current run. + // + // Check if we have a current run, we do that by checking + // if the low bits are set. + // + + } else if (CurrentRunSize != 0) { + + CurrentRunSize += HalppBitsSetLow(CurrentByte); + break; + + // + // Check if we have an internal run, we do that by checking + // if the high bits are not set. This check actually cheats + // a bit in that the current byte might have an inside run + // but we'll skip over it because we can start a run at the + // end of the byte. + // + + } else if (HalppBitsSetHigh(CurrentByte) == 0) { + + UCHAR BitMask; + ULONG i; + + ASSERT( HalppBitSetAnywhere(CurrentByte) != 0 ); + + CurrentRunSize = HalppBitSetAnywhere(CurrentByte); + + // + // Somewhere in the current byte is a run. All we need to do now + // is find the index for this new run. + // + + BitMask = FillMask[ CurrentRunSize ]; + + for (i = 0; (BitMask & CurrentByte) != BitMask; i += 1) { + + BitMask <<= 1; + } + + CurrentRunIndex = (CurrentByteIndex * 8) + i; + break; + + // + // Otherwise we start a new current run. It starts with the + // remaining set bits in the current byte. + // + + } else { + + CurrentRunSize = HalppBitsSetHigh( CurrentByte ); + CurrentRunIndex = (CurrentByteIndex * 8) + (8 - CurrentRunSize); + } + } + + // + // Set our output variables and return to our caller + // + + *StartingIndex = CurrentRunIndex; + return CurrentRunSize; +} + + +ULONG +HalpNumberOfClearBits ( + IN PRTL_BITMAP BitMapHeader + ) + +/*++ + +Routine Description: + + This procedure counts and returns the number of clears bits within + the specified bitmap. + +Arguments: + + BitMapHeader - Supplies a pointer to the previously initialized bitmap. + +Return Value: + + ULONG - The total number of clear bits in the bitmap + +--*/ + +{ + ULONG SizeOfBitMap; + ULONG SizeInBytes; + + ULONG i; + UCHAR CurrentByte; + + ULONG TotalClear; + + GET_BYTE_DECLARATIONS(); + + // + // Reference the bitmap header to make the loop run faster + // + + SizeOfBitMap = BitMapHeader->SizeOfBitMap; + SizeInBytes = (SizeOfBitMap + 7) / 8; + + // + // Set any unused bits in the last byte so we don't count them. We + // do this by first checking if there are any odd bits in the last byte + // + + if ((SizeOfBitMap % 8) != 0) { + + // + // The last byte has some odd bits so we'll set the high unused + // bits in the last byte to 1's + // + + ((PUCHAR)BitMapHeader->Buffer)[SizeInBytes - 1] |= + ZeroMask[SizeOfBitMap % 8]; + } + + // + // Set if up so we can use the GET_BYTE macro + // + + GET_BYTE_INITIALIZATION( BitMapHeader, 0 ); + + // + // Examine every byte in the bitmap + // + + TotalClear = 0; + for (i = 0; i < SizeInBytes; i += 1) { + + GET_BYTE( CurrentByte ); + + TotalClear += HalppBitsClearTotal[CurrentByte]; + } + + return TotalClear; +} + + +ULONG +HalpNumberOfSetBits ( + IN PRTL_BITMAP BitMapHeader + ) + +/*++ + +Routine Description: + + This procedure counts and returns the number of set bits within + the specified bitmap. + +Arguments: + + BitMapHeader - Supplies a pointer to the previously initialized bitmap. + +Return Value: + + ULONG - The total number of set bits in the bitmap + +--*/ + +{ + ULONG SizeOfBitMap; + ULONG SizeInBytes; + + ULONG i; + UCHAR CurrentByte; + + ULONG TotalSet; + + GET_BYTE_DECLARATIONS(); + + // + // Reference the bitmap header to make the loop run faster + // + + SizeOfBitMap = BitMapHeader->SizeOfBitMap; + SizeInBytes = (SizeOfBitMap + 7) / 8; + + // + // Clear any unused bits in the last byte so we don't count them. We + // do this by first checking if there are any odd bits in the last byte + // + + if ((SizeOfBitMap % 8) != 0) { + + // + // The last byte has some odd bits so we'll set the high unused + // bits in the last byte to 0's + // + + ((PUCHAR)BitMapHeader->Buffer)[SizeInBytes - 1] &= + FillMask[SizeOfBitMap % 8]; + } + + // + // Set if up so we can use the GET_BYTE macro + // + + GET_BYTE_INITIALIZATION( BitMapHeader, 0 ); + + // + // Examine every byte in the bitmap + // + + TotalSet = 0; + for (i = 0; i < SizeInBytes; i += 1) { + + GET_BYTE( CurrentByte ); + + TotalSet += HalppBitsSetTotal(CurrentByte); + } + + return TotalSet; +} + + +BOOLEAN +HalpAreBitsClear ( + IN PRTL_BITMAP BitMapHeader, + IN ULONG StartingIndex, + IN ULONG Length + ) + +/*++ + +Routine Description: + + This procedure determines if the range of specified bits are all clear. + +Arguments: + + BitMapHeader - Supplies a pointer to the previously initialized bitmap. + + StartingIndex - Supplies the starting bit index to examine + + Length - Supplies the number of bits to examine + +Return Value: + + BOOLEAN - TRUE if the specified bits in the bitmap are all clear, and + FALSE if any are set or if the range is outside the bitmap or if + Length is zero. + +--*/ + +{ + ULONG SizeOfBitMap; + ULONG SizeInBytes; + + ULONG EndingIndex; + + ULONG StartingByte; + ULONG EndingByte; + + ULONG StartingOffset; + ULONG EndingOffset; + + ULONG i; + UCHAR Byte; + + GET_BYTE_DECLARATIONS(); + + // + // To make the loops in our test run faster we'll extract the fields + // from the bitmap header + // + + SizeOfBitMap = BitMapHeader->SizeOfBitMap; + SizeInBytes = (SizeOfBitMap + 7) / 8; + + // + // First make sure that the specified range is contained within the + // bitmap, and the length is not zero. + // + + if ((StartingIndex + Length > SizeOfBitMap) || (Length == 0)) { + + return FALSE; + } + + // + // Compute the ending index, starting and ending byte, and the starting + // and ending offset within each byte + // + + EndingIndex = StartingIndex + Length - 1; + + StartingByte = StartingIndex / 8; + EndingByte = EndingIndex / 8; + + StartingOffset = StartingIndex % 8; + EndingOffset = EndingIndex % 8; + + // + // Set ourselves up to get the next byte + // + + GET_BYTE_INITIALIZATION( BitMapHeader, StartingByte ); + + // + // Special case the situation where the starting byte and ending + // byte are one in the same + // + + if (StartingByte == EndingByte) { + + // + // Get the single byte we are to look at + // + + GET_BYTE( Byte ); + + // + // Now we compute the mask of bits we're after and then AND it with + // the byte. If it is zero then the bits in question are all clear + // otherwise at least one of them is set. + // + + if ((ZeroMask[StartingOffset] & FillMask[EndingOffset+1] & Byte) == 0) { + + return TRUE; + + } else { + + return FALSE; + } + + } else { + + // + // Get the first byte that we're after, and then + // compute the mask of bits we're after for the first byte then + // AND it with the byte itself. + // + + GET_BYTE( Byte ); + + if ((ZeroMask[StartingOffset] & Byte) != 0) { + + return FALSE; + } + + // + // Now for every whole byte inbetween read in the byte, + // and make sure it is all zeros + // + + for (i = StartingByte+1; i < EndingByte; i += 1) { + + GET_BYTE( Byte ); + + if (Byte != 0) { + + return FALSE; + } + } + + // + // Get the last byte we're after, and then + // compute the mask of bits we're after for the last byte then + // AND it with the byte itself. + // + + GET_BYTE( Byte ); + + if ((FillMask[EndingOffset+1] & Byte) != 0) { + + return FALSE; + } + } + + return TRUE; +} + + +BOOLEAN +HalpAreBitsSet ( + IN PRTL_BITMAP BitMapHeader, + IN ULONG StartingIndex, + IN ULONG Length + ) + +/*++ + +Routine Description: + + This procedure determines if the range of specified bits are all set. + +Arguments: + + BitMapHeader - Supplies a pointer to the previously initialized bitmap. + + StartingIndex - Supplies the starting bit index to examine + + Length - Supplies the number of bits to examine + +Return Value: + + BOOLEAN - TRUE if the specified bits in the bitmap are all set, and + FALSE if any are clear or if the range is outside the bitmap or if + Length is zero. + +--*/ + +{ + ULONG SizeOfBitMap; + ULONG SizeInBytes; + + ULONG EndingIndex; + + ULONG StartingByte; + ULONG EndingByte; + + ULONG StartingOffset; + ULONG EndingOffset; + + ULONG i; + UCHAR Byte; + + GET_BYTE_DECLARATIONS(); + + // + // To make the loops in our test run faster we'll extract the fields + // from the bitmap header + // + + SizeOfBitMap = BitMapHeader->SizeOfBitMap; + SizeInBytes = (SizeOfBitMap + 7) / 8; + + // + // First make sure that the specified range is contained within the + // bitmap, and the length is not zero. + // + + if ((StartingIndex + Length > SizeOfBitMap) || (Length == 0)) { + + return FALSE; + } + + // + // Compute the ending index, starting and ending byte, and the starting + // and ending offset within each byte + // + + EndingIndex = StartingIndex + Length - 1; + + StartingByte = StartingIndex / 8; + EndingByte = EndingIndex / 8; + + StartingOffset = StartingIndex % 8; + EndingOffset = EndingIndex % 8; + + // + // Set ourselves up to get the next byte + // + + GET_BYTE_INITIALIZATION( BitMapHeader, StartingByte ); + + // + // Special case the situation where the starting byte and ending + // byte are one in the same + // + + if (StartingByte == EndingByte) { + + // + // Get the single byte we are to look at + // + + GET_BYTE( Byte ); + + // + // Now we compute the mask of bits we're after and then AND it with + // the complement of the byte If it is zero then the bits in question + // are all clear otherwise at least one of them is clear. + // + + if ((ZeroMask[StartingOffset] & FillMask[EndingOffset+1] & ~Byte) == 0) { + + return TRUE; + + } else { + + return FALSE; + } + + } else { + + // + // Get the first byte that we're after, and then + // compute the mask of bits we're after for the first byte then + // AND it with the complement of the byte itself. + // + + GET_BYTE( Byte ); + + if ((ZeroMask[StartingOffset] & ~Byte) != 0) { + + return FALSE; + } + + // + // Now for every whole byte inbetween read in the byte, + // and make sure it is all ones + // + + for (i = StartingByte+1; i < EndingByte; i += 1) { + + GET_BYTE( Byte ); + + if (Byte != 0xff) { + + return FALSE; + } + } + + // + // Get the last byte we're after, and then + // compute the mask of bits we're after for the last byte then + // AND it with the complement of the byte itself. + // + + GET_BYTE( Byte ); + + if ((FillMask[EndingOffset+1] & ~Byte) != 0) { + + return FALSE; + } + } + + return TRUE; +} + + +//ULONG +//HalpCheckBit ( +// IN PRTL_BITMAP BitMapHeader, +// IN ULONG BitPosition +// ) +// +///*++ +// +//Routine Description: +// +// This procedure returns the state of the specified bit within the +// specified bit map. +// +//Arguments: +// +// BitMapHeader - Supplies a pointer to the previously initialized BitMap. +// +// BitPosition - Supplies the bit number of which to return the state. +// +//Return Value: +// +// ULONG - The state of the specified bit. +// +//--*/ +// +//{ +// ULONG results; +// +// results = ((BitMapHeader->Buffer[BitPosition / 32]) >> (BitPosition % 32)) & 0x00000001; +// +// //DbgPrint("CheckBit %08lx", BitPosition); +// //DbgPrint(" %08lx", results); +// //DumpBitMap(BitMapHeader); +// +// return results; +//} + diff --git a/private/ntos/nthals/halraw/alpha/bitmap.h b/private/ntos/nthals/halraw/alpha/bitmap.h new file mode 100644 index 000000000..744f8544e --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/bitmap.h @@ -0,0 +1,252 @@ +/*++ + +Copyright (c) 1989-1993 Microsoft Corporation +Copyright (c) 1995 Digital Equipment Corporation + +Module Name: + + bitmap.h + +Abstract: + + + ecrfix - (non-paged) copy of Rtl bitmap routines in HAL + + Later: only include routines we really use, or come up with + a different solution. + + This file defines the structures and definitions registers on a + Rawhide I/O Daughter card. These register reside on the CAP chip, + MDP chips, and flash ROM. + + +Author: + + Eric Rehm 17-Nov-1995 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#ifndef _BITMAPH_ +#define _BITMAPH_ + +// +// The following routine initializes a new bitmap. It does not alter the +// data currently in the bitmap. This routine must be called before +// any other bitmap routine/macro. +// + + +NTSYSAPI +VOID +NTAPI +RtlFillMemoryUlong ( + PVOID Destination, + ULONG Length, + ULONG Pattern + ); + +VOID +HalpInitializeBitMap ( + PRTL_BITMAP BitMapHeader, + PULONG BitMapBuffer, + ULONG SizeOfBitMap + ); + +// +// The following two routines either clear or set all of the bits +// in a bitmap. +// + + +VOID +HalpClearAllBits ( + PRTL_BITMAP BitMapHeader + ); + + +VOID +HalpSetAllBits ( + PRTL_BITMAP BitMapHeader + ); + +// +// The following two routines locate a contiguous region of either +// clear or set bits within the bitmap. The region will be at least +// as large as the number specified, and the search of the bitmap will +// begin at the specified hint index (which is a bit index within the +// bitmap, zero based). The return value is the bit index of the located +// region (zero based) or -1 (i.e., 0xffffffff) if such a region cannot +// be located +// + + +ULONG +HalpFindClearBits ( + PRTL_BITMAP BitMapHeader, + ULONG NumberToFind, + ULONG HintIndex + ); + + +ULONG +HalpFindSetBits ( + PRTL_BITMAP BitMapHeader, + ULONG NumberToFind, + ULONG HintIndex + ); + +// +// The following two routines locate a contiguous region of either +// clear or set bits within the bitmap and either set or clear the bits +// within the located region. The region will be as large as the number +// specified, and the search for the region will begin at the specified +// hint index (which is a bit index within the bitmap, zero based). The +// return value is the bit index of the located region (zero based) or +// -1 (i.e., 0xffffffff) if such a region cannot be located. If a region +// cannot be located then the setting/clearing of the bitmap is not performed. +// + + +ULONG +HalpFindClearBitsAndSet ( + PRTL_BITMAP BitMapHeader, + ULONG NumberToFind, + ULONG HintIndex + ); + + +ULONG +HalpFindSetBitsAndClear ( + PRTL_BITMAP BitMapHeader, + ULONG NumberToFind, + ULONG HintIndex + ); + +// +// The following two routines clear or set bits within a specified region +// of the bitmap. The starting index is zero based. +// + + +VOID +HalpClearBits ( + PRTL_BITMAP BitMapHeader, + ULONG StartingIndex, + ULONG NumberToClear + ); + + +VOID +HalpSetBits ( + PRTL_BITMAP BitMapHeader, + ULONG StartingIndex, + ULONG NumberToSet + ); + +// +// The following two routines locate the longest contiguous region of +// clear or set bits within the bitmap. The returned starting index value +// denotes the first contiguous region located satisfying our requirements +// The return value is the length (in bits) of the longest region found. +// + + +ULONG +HalpFindLongestRunClear ( + PRTL_BITMAP BitMapHeader, + PULONG StartingIndex + ); + + +ULONG +HalpFindLongestRunSet ( + PRTL_BITMAP BitMapHeader, + PULONG StartingIndex + ); + +// +// The following two routines locate the first contiguous region of +// clear or set bits within the bitmap. The returned starting index value +// denotes the first contiguous region located satisfying our requirements +// The return value is the length (in bits) of the region found. +// + + +ULONG +HalpFindFirstRunClear ( + PRTL_BITMAP BitMapHeader, + PULONG StartingIndex + ); + + +ULONG +HalpFindFirstRunSet ( + PRTL_BITMAP BitMapHeader, + PULONG StartingIndex + ); + +// +// The following macro returns the value of the bit stored within the +// bitmap at the specified location. If the bit is set a value of 1 is +// returned otherwise a value of 0 is returned. +// +// ULONG +// HalpCheckBit ( +// PRTL_BITMAP BitMapHeader, +// ULONG BitPosition +// ); +// +// +// To implement CheckBit the macro retrieves the longword containing the +// bit in question, shifts the longword to get the bit in question into the +// low order bit position and masks out all other bits. +// + +#define HalpCheckBit(BMH,BP) ((((BMH)->Buffer[(BP) / 32]) >> ((BP) % 32)) & 0x1) + +// +// The following two procedures return to the caller the total number of +// clear or set bits within the specified bitmap. +// + + +ULONG +HalpNumberOfClearBits ( + PRTL_BITMAP BitMapHeader + ); + + +ULONG +HalpNumberOfSetBits ( + PRTL_BITMAP BitMapHeader + ); + +// +// The following two procedures return to the caller a boolean value +// indicating if the specified range of bits are all clear or set. +// + + +BOOLEAN +HalpAreBitsClear ( + PRTL_BITMAP BitMapHeader, + ULONG StartingIndex, + ULONG Length + ); + + +BOOLEAN +HalpAreBitsSet ( + PRTL_BITMAP BitMapHeader, + ULONG StartingIndex, + ULONG Length + ); + +#endif //_BITMAPH_ diff --git a/private/ntos/nthals/halraw/alpha/busdata.c b/private/ntos/nthals/halraw/alpha/busdata.c new file mode 100644 index 000000000..2c56e0c0e --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/busdata.c @@ -0,0 +1,137 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation +Copyright (c) 1995 Digital Equipment Corporation + +Module Name: + + busdata.c + +Abstract: + + This module contains get/set bus data routines. + +Author: + + Darryl E. Havens (darrylh) 11-Apr-1990 + Eric Rehm 13-Apr-1995 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" + +// +// External Function Prototypes +// + +ULONG +HalpNoBusData ( + IN PVOID BusHandler, + IN PVOID RootHandler, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpRegisterInternalBusHandlers) +#endif + + +VOID +HalpRegisterInternalBusHandlers ( + VOID + ) +/*++ + +Routine Description: + + This function registers the bushandlers for buses on the system + that will always be present on the system. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + PBUS_HANDLER Bus; + + // + // Initalize BusHandler data before registering any handlers + // + + HalpInitBusHandler (); + + // + // Build the processor internal bus 0 + // + + HaliRegisterBusHandler (ProcessorInternal, // Bus Type + -1, // No config space + 0, // Bus Number + -1, // No parent bus type + 0, // No parent bus number + 0, // No extension data + NULL, // No install handler + &Bus); // Bushandler return + + Bus->GetInterruptVector = HalpGetSystemInterruptVector; + + // + // Build internal-bus 0, or system level bus + // + + HaliRegisterBusHandler (Internal, // Bus Type + -1, // No config space + 0, // Bus Number + -1, // No parent bus type + 0, // No parent bus number + 0, // No extension data + NULL, // No install handler + &Bus); // Bushandler return + + Bus->GetInterruptVector = HalpGetSystemInterruptVector; + Bus->TranslateBusAddress = HalpTranslateSystemBusAddress; + + // + // Build Isa/Eisa bus #0 + // + + HaliRegisterBusHandler (Eisa, // Bus Type + EisaConfiguration, // Config space type + 0, // Internal bus #0 + Internal, // Parent bus type + 0, // Parent bus number + 0, // No extension data + NULL, // No install handler + &Bus); // Bushandler return + + Bus->GetBusData = HalpGetEisaData; + Bus->AdjustResourceList = HalpAdjustEisaResourceList; + + HaliRegisterBusHandler (Isa, // Bus Type + -1, // No config space + 0, // Internal bus #0 + Eisa, // Parent bus type + 0, // Parent bus number + 0, // No extension data + NULL, // No install handler + &Bus); // Bushandler returne + + Bus->GetBusData = HalpNoBusData; + Bus->AdjustResourceList = HalpAdjustIsaResourceList; + +} + diff --git a/private/ntos/nthals/halraw/alpha/cache.c b/private/ntos/nthals/halraw/alpha/cache.c new file mode 100644 index 000000000..561528477 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/cache.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\cache.c" + diff --git a/private/ntos/nthals/halraw/alpha/devintr.s b/private/ntos/nthals/halraw/alpha/devintr.s new file mode 100644 index 000000000..d861febd2 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/devintr.s @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\devintr.s" + diff --git a/private/ntos/nthals/halraw/alpha/drivesup.c b/private/ntos/nthals/halraw/alpha/drivesup.c new file mode 100644 index 000000000..38259e5f4 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/drivesup.c @@ -0,0 +1,7 @@ +// +// This file simply includes the common sources from the current HAL +// directory. When the structure is finally changed, the real file should +// be in this directory. +// + +#include "..\drivesup.c" diff --git a/private/ntos/nthals/halraw/alpha/ebsgdma.c b/private/ntos/nthals/halraw/alpha/ebsgdma.c new file mode 100644 index 000000000..f2f033fad --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/ebsgdma.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\ebsgdma.c" + diff --git a/private/ntos/nthals/halraw/alpha/eeprom8k.c b/private/ntos/nthals/halraw/alpha/eeprom8k.c new file mode 100644 index 000000000..c03d04c0d --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/eeprom8k.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\eeprom8k.c" + diff --git a/private/ntos/nthals/halraw/alpha/eisaprof.c b/private/ntos/nthals/halraw/alpha/eisaprof.c new file mode 100644 index 000000000..1fbc6426e --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/eisaprof.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\eisaprof.c" + diff --git a/private/ntos/nthals/halraw/alpha/eisasup.c b/private/ntos/nthals/halraw/alpha/eisasup.c new file mode 100644 index 000000000..0d46ef3e4 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/eisasup.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\eisasup.c" + diff --git a/private/ntos/nthals/halraw/alpha/ev5cache.c b/private/ntos/nthals/halraw/alpha/ev5cache.c new file mode 100644 index 000000000..cd83f7451 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/ev5cache.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\ev5cache.c" + diff --git a/private/ntos/nthals/halraw/alpha/ev5int.c b/private/ntos/nthals/halraw/alpha/ev5int.c new file mode 100644 index 000000000..23727330f --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/ev5int.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\ev5int.c" + diff --git a/private/ntos/nthals/halraw/alpha/ev5ints.s b/private/ntos/nthals/halraw/alpha/ev5ints.s new file mode 100644 index 000000000..66852f382 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/ev5ints.s @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\ev5ints.s" + diff --git a/private/ntos/nthals/halraw/alpha/ev5mchk.c b/private/ntos/nthals/halraw/alpha/ev5mchk.c new file mode 100644 index 000000000..0bedd3dfc --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/ev5mchk.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\ev5mchk.c" + diff --git a/private/ntos/nthals/halraw/alpha/ev5mem.s b/private/ntos/nthals/halraw/alpha/ev5mem.s new file mode 100644 index 000000000..dcad6563c --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/ev5mem.s @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\ev5mem.s" + diff --git a/private/ntos/nthals/halraw/alpha/ev5prof.c b/private/ntos/nthals/halraw/alpha/ev5prof.c new file mode 100644 index 000000000..839438fd9 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/ev5prof.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\ev5prof.c" + diff --git a/private/ntos/nthals/halraw/alpha/fwreturn.c b/private/ntos/nthals/halraw/alpha/fwreturn.c new file mode 100644 index 000000000..65ae88cb8 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/fwreturn.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\fwreturn.c" + diff --git a/private/ntos/nthals/halraw/alpha/haldebug.c b/private/ntos/nthals/halraw/alpha/haldebug.c new file mode 100644 index 000000000..ce91863ec --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/haldebug.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\haldebug.c" + diff --git a/private/ntos/nthals/halraw/alpha/halpal.s b/private/ntos/nthals/halraw/alpha/halpal.s new file mode 100644 index 000000000..fc89f8370 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/halpal.s @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\halpal.s" + diff --git a/private/ntos/nthals/halraw/alpha/haltsup.s b/private/ntos/nthals/halraw/alpha/haltsup.s new file mode 100644 index 000000000..b8a697144 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/haltsup.s @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\haltsup.s" + diff --git a/private/ntos/nthals/halraw/alpha/idle.s b/private/ntos/nthals/halraw/alpha/idle.s new file mode 100644 index 000000000..f517bab2f --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/idle.s @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\idle.s" + diff --git a/private/ntos/nthals/halraw/alpha/info.c b/private/ntos/nthals/halraw/alpha/info.c new file mode 100644 index 000000000..22aef63a3 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/info.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\info.c" + diff --git a/private/ntos/nthals/halraw/alpha/inithal.c b/private/ntos/nthals/halraw/alpha/inithal.c new file mode 100644 index 000000000..47f0a5b17 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/inithal.c @@ -0,0 +1,1126 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + inithal.c + +Abstract: + + + This module implements the initialization of the system dependent + functions that define the Hardware Architecture Layer (HAL) for an + Alpha machine + +Author: + + David N. Cutler (davec) 25-Apr-1991 + Miche Baker-Harvey (miche) 18-May-1992 + +Environment: + + Kernel mode only. + +Revision History: + + 28-Jul-1992 Jeff McLeman (mcleman) + Add code to allocate a mapping buffer for buffered DMA + + 14-Jul-1992 Jeff McLeman (mcleman) + Add call to HalpCachePcrValues, which will call the PALcode to + cache values of the PCR that need fast access. + + 10-Jul-1992 Jeff McLeman (mcleman) + Remove reference to initializing the fixed TB entries, since Alpha + does not have fixed TB entries. + + 24-Sep-1993 Joe Notarangelo + Restructured to make this module platform-independent. + +--*/ + +#include "halp.h" + +// +// Declare the extern variable UncorrectableError declared in +// inithal.c. +// + +PERROR_FRAME PUncorrectableError = NULL; + +// +// external +// + +ULONG HalDisablePCIParityChecking = 0xffffffff; + +// +// Define HAL spinlocks. +// + +KSPIN_LOCK HalpBeepLock; +KSPIN_LOCK HalpDisplayAdapterLock; +KSPIN_LOCK HalpSystemInterruptLock; + +// +// Mask of all of the processors that are currently active. +// + +KAFFINITY HalpActiveProcessors; + +// +// Mapping of the logical processor numbers to the physical processors. +// + +HALP_PROCESSOR_ID HalpLogicalToPhysicalProcessor[HAL_MAXIMUM_PROCESSOR+1]; + +ULONG AlreadySet = 0; + +// +// HalpClockFrequency is the processor cycle counter frequency in units +// of cycles per second (Hertz). It is a large number (e.g., 125,000,000) +// but will still fit in a ULONG. +// +// HalpClockMegaHertz is the processor cycle counter frequency in units +// of megahertz. It is a small number (e.g., 125) and is also the number +// of cycles per microsecond. The assumption here is that clock rates will +// always be an integral number of megahertz. +// +// Having the frequency available in both units avoids multiplications, or +// especially divisions in time critical code. +// + +ULONG HalpClockFrequency; +ULONG HalpClockMegaHertz = DEFAULT_PROCESSOR_FREQUENCY_MHZ; + +ULONGLONG HalpContiguousPhysicalMemorySize; + +// +// Use the square wave mode of the PIT to measure the processor +// speed. The timer has a frequency of 1.193MHz. We want a +// square wave with a period of 50ms so we must initialize the +// pit with a count of: +// 50ms*1.193MHz = 59650 cycles +// + +#define TIMER_REF_VALUE 59650 + +VOID +HalpEarlyInitializeMachineDependent( + IN ULONG Phase, + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + + +VOID +HalpVerifyPrcbVersion( + VOID + ); + +VOID +HalpRecurseLoaderBlock( + IN PCONFIGURATION_COMPONENT_DATA CurrentEntry + ); + +ULONG +HalpQuerySystemFrequency( + ULONG SampleTime + ); + +VOID +HalpAllocateUncorrectableFrame( + VOID + ); + +BOOLEAN +HalInitSystem ( + IN ULONG Phase, + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) + +/*++ + +Routine Description: + + This function initializes the Hardware Architecture Layer (HAL) for an + Alpha system. + +Arguments: + + Phase - Supplies the initialization phase (zero or one). + + LoaderBlock - Supplies a pointer to a loader parameter block. + +Return Value: + + A value of TRUE is returned is the initialization was successfully + complete. Otherwise a value of FALSE is returend. + +--*/ + +{ + PKPRCB Prcb; + ULONG BuildType = 0; + MC_DEVICE_ID McDevid; + IOD_WHOAMI IodWhoAmI; + Prcb = PCR->Prcb; + +#if HALDBG + DbgPrint( "HAL/HalInitSystem: entered, Processor = %d\n", PCR->Number ); +#endif + // + // Perform initialization for the primary processor. + // + + if( Prcb->Number == HAL_PRIMARY_PROCESSOR ){ + + if (Phase == 0) { + +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Phase = %d\n", Phase ); + DbgBreakPoint(); + HalpDumpMemoryDescriptors( LoaderBlock ); +#endif //HALDBG + + // + // Get the memory Size. + // + + HalpContiguousPhysicalMemorySize = + HalpGetContiguousMemorySize( LoaderBlock ); + + // + // Set second level cache size + // NOTE: Although we set the PCR with the right cache size this + // could be overridden by setting the Registry key + // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet + // \Control\Session Manager + // \Memory Management\SecondLevelDataCache. + // + // If the secondlevel cache size is 0 or 512KB then it is + // possible that the firmware is an old one. In which case + // we determine the cache size here. If the value is anything + // other than these then it is a new firmware and probably + // reporting the correct cache size hence use this value. + // + + if(LoaderBlock->u.Alpha.SecondLevelDcacheSize == 0 || + LoaderBlock->u.Alpha.SecondLevelDcacheSize == 512*__1K){ + PCR->SecondLevelCacheSize = HalpGetBCacheSize( + HalpContiguousPhysicalMemorySize + ); + } else { + PCR->SecondLevelCacheSize = + LoaderBlock->u.Alpha.SecondLevelDcacheSize; + } + + // + // Initialize HAL spinlocks. + // + + KeInitializeSpinLock(&HalpBeepLock); + KeInitializeSpinLock(&HalpDisplayAdapterLock); + KeInitializeSpinLock(&HalpSystemInterruptLock); + + // + // Phase 0 initialization. + // + +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Phase = %d Callouts\n", Phase ); + DbgPrint( "HAL/HalInitSystem: Early Machine Init\n"); +#endif //HALDBG + HalpEarlyInitializeMachineDependent( Phase, LoaderBlock ); + +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Set Time Increment\n"); +#endif //HALDBG + HalpSetTimeIncrement(); +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Map IO Space\n"); +#endif //HALDBG + HalpMapIoSpace(); +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Create DMA Structures\n"); +#endif //HALDBG + HalpCreateDmaStructures(LoaderBlock); +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Establish Error Handler\n"); +#endif //HALDBG + HalpEstablishErrorHandler(); +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Init Display\n"); +#endif //HALDBG + HalpInitializeDisplay(LoaderBlock); +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Init Machine Dependent\n"); +#endif //HALDBG + HalpInitializeMachineDependent( Phase, LoaderBlock ); +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Init Interrupts\n"); +#endif //HALDBG + HalpInitializeInterrupts(); +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Verify Prcb Version\n"); +#endif //HALDBG + HalpVerifyPrcbVersion(); + + // + // Set the processor active in the HAL active processor mask. + // + + HalpActiveProcessors = 1 << Prcb->Number; + +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Phase = %d complete\n", Phase ); +#endif //HALDBG + return TRUE; + + } else { + +#if HALDBG + + DbgPrint( "HAL/HalInitSystem: Phase = %d\n", Phase ); + DbgBreakPoint(); + +#endif //HALDBG + + // + // Phase 1 initialization. + // + +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Phase = %d Callouts\n", Phase ); + DbgPrint( "HAL/HalInitSystem: Init Clock Interrupts\n"); +#endif //HALDBG + HalpInitializeClockInterrupts(); + +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Init Machine Dependent\n"); +#endif //HALDBG + HalpInitializeMachineDependent( Phase, LoaderBlock ); + + // + // Allocate memory for the uncorrectable frame + // + + HalpAllocateUncorrectableFrame(); + + // + // Initialize the Buffer for Uncorrectable Error. + // + + HalpInitializeUncorrectableErrorFrame(); + +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Phase = %d Complete\n", Phase ); +#endif //HALDBG + return TRUE; + + } + } + + // + // Perform necessary processor-specific initialization for + // secondary processors. Phase is ignored as this will be called + // only once on each secondary processor. + // + +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Map IO Space\n"); +#endif //HALDBG + + HalpMapIoSpace(); + +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Initialize Interrupts\n"); +#endif //HALDBG + + HalpInitializeInterrupts(); + +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Initialize Machine Dependent\n"); +#endif //HALDBG + + HalpInitializeMachineDependent( Phase, LoaderBlock ); + +#if HALDBG + DbgPrint( "HAL/HalInitSystem: Set Active Processor Mask\n"); +#endif //HALDBG + + // + // Set the processor active in the HAL active processor mask. + // + + HalpActiveProcessors |= 1 << Prcb->Number; + +#if HALDBG + + DbgPrint( "Secondary %d is alive\n", Prcb->Number ); + +#endif //HALDBG + + return TRUE; +} + +VOID +HalpAllocateUncorrectableFrame( + VOID + ) +/*++ + +Routine Description: + + This function is called after the Phase1 Machine Dependent initialization. + It must be called only after Phase1 machine-dependent initialization. + This function allocates the necessary amountof memory for storing the + uncorrectable error frame. This function makes a call to a machine- + dependent function 'HalpGetMachineDependentErrorFrameSizes' for + getting the size of the Processor Specific and System Specific error + frame size. The machine-dependent code will know the size of these + frames after the machine-dependent Phase1 initialization. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + ULONG RawProcessorFrameSize; + ULONG RawSystemFrameSize; + ULONG EntireErrorFrameSize; + + // + // First get the machine-dependent error frame sizes. + // + HalpGetMachineDependentErrorFrameSizes( + &RawProcessorFrameSize, + &RawSystemFrameSize); + + // + // Compute the total size of the error frame + // + EntireErrorFrameSize = sizeof(ERROR_FRAME) + RawProcessorFrameSize + + RawSystemFrameSize; + + // + // Allocate space to store the error frame. + // Not sure if it is OK to use ExAllocatePool at this instant. + // We will give this a try if it doesn't work What do we do??!! + // + + PUncorrectableError = ExAllocatePool(NonPagedPool, + EntireErrorFrameSize); + if(PUncorrectableError == NULL) { + return; + } + + PUncorrectableError->LengthOfEntireErrorFrame = EntireErrorFrameSize; + + // + // if the size is not equal to zero then set the RawInformation pointers + // to point to the right place. If not set the pointer to NULL and set + // size to 0. + // + + // + // make Raw processor info to point right after the error frame. + // + if(RawProcessorFrameSize) { + PUncorrectableError->UncorrectableFrame.RawProcessorInformation = + (PVOID)((PUCHAR)(&PUncorrectableError->UncorrectableFrame) + sizeof(ERROR_FRAME) ); + PUncorrectableError->UncorrectableFrame.RawProcessorInformationLength = + RawProcessorFrameSize; + } + else{ + PUncorrectableError->UncorrectableFrame.RawProcessorInformation = + NULL; + PUncorrectableError->UncorrectableFrame.RawProcessorInformationLength = + 0; + } + if(RawSystemFrameSize){ + PUncorrectableError->UncorrectableFrame.RawSystemInformation = + (PVOID)((PUCHAR)PUncorrectableError->UncorrectableFrame. + RawProcessorInformation + RawProcessorFrameSize); + PUncorrectableError->UncorrectableFrame.RawSystemInformationLength = + RawSystemFrameSize; + } + else{ + PUncorrectableError->UncorrectableFrame.RawSystemInformation = + NULL; + PUncorrectableError->UncorrectableFrame.RawSystemInformationLength = + 0; + } +} + +VOID +HalpGetProcessorInfo( + PPROCESSOR_INFO pProcessorInfo + ) +/*++ + +Routine Description: + + Collects the Processor Information and fills in the buffer. + +Arguments: + + pProcessorInfo - Pointer to the PROCESSOR_INFO structure into which + the processor information will be filled in. + +Return Value: + + None. + +--*/ +{ + PKPRCB Prcb; + + pProcessorInfo->ProcessorType = PCR->ProcessorType; + pProcessorInfo->ProcessorRevision = PCR->ProcessorRevision; + + Prcb = PCR->Prcb; + pProcessorInfo->LogicalProcessorNumber = Prcb->Number; + pProcessorInfo->PhysicalProcessorNumber = + (ULONG) (MCDEVID_TO_PHYS_CPU( + HalpLogicalToPhysicalProcessor[Prcb->Number].all) + ); + return; +} + +VOID +HalInitializeProcessor ( + IN ULONG Number + ) + +/*++ + +Routine Description: + + This function is called early in the initialization of the kernel + to perform platform dependent initialization for each processor + before the HAL Is fully functional. + + N.B. When this routine is called, the PCR is present but is not + fully initialized. + +Arguments: + + Number - Supplies the number of the processor to initialize. + +Return Value: + + None. + +--*/ + +{ + return; +} + +BOOLEAN +HalStartNextProcessor ( + IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN PKPROCESSOR_STATE ProcessorState + ) + +/*++ + +Routine Description: + + This function is called to start the next processor. + +Arguments: + + LoaderBlock - Supplies a pointer to the loader parameter block. + + ProcessorState - Supplies a pointer to the processor state to be + used to start the processor. + +Return Value: + + If a processor is successfully started, then a value of TRUE is + returned. Otherwise a value of FALSE is returned. If a value of + TRUE is returned, then the logical processor number is stored + in the processor control block specified by the loader block. + +--*/ + +{ + ULONG LogicalNumber; + PRESTART_BLOCK NextRestartBlock; + ULONG PhysicalNumber; + PKPRCB Prcb; + +#if !defined(NT_UP) + +#if 0 //HALDBG + DbgPrint("HalStartNextProcessor: enter\n"); +#endif + + // + // If the address of the first restart parameter block is NULL, then + // the host system is a uniprocessor system running with old firmware. + // Otherwise, the host system may be a multiprocessor system if more + // than one restart block is present. + // + // N.B. The first restart parameter block must be for the boot master + // and must represent logical processor 0. + // + + NextRestartBlock = SYSTEM_BLOCK->RestartBlock; + if (NextRestartBlock == NULL) { + return FALSE; + } + + // + // Scan the restart parameter blocks for a processor that is ready, + // but not running. If a processor is found, then fill in the restart + // processor state, set the logical processor number, and set start + // in the boot status. + // + + LogicalNumber = 0; + PhysicalNumber = 0; + do { + + if( NextRestartBlock->BootStatus.ProcessorReady == FALSE ){ + +#if 0 //HALDBG + DbgPrint( + "HalStartNextProcessor: Processor %d not ready\n", + PhysicalNumber + ); +#endif + PhysicalNumber += 1; + + } else { + + + // + // If the processor is not ready then we assume that it is not + // present. We must increment the physical processor number but + // the logical processor number does not changed. + // + + // + // Check if this processor has already been started. + // If it has not then start it now. + // + + if( NextRestartBlock->BootStatus.ProcessorStart == FALSE ){ + + RtlZeroMemory( &NextRestartBlock->u.Alpha, + sizeof(ALPHA_RESTART_STATE)); + NextRestartBlock->u.Alpha.IntA0 = + ProcessorState->ContextFrame.IntA0; + NextRestartBlock->u.Alpha.IntSp = + ProcessorState->ContextFrame.IntSp; + NextRestartBlock->u.Alpha.ReiRestartAddress = + (ULONG) ProcessorState->ContextFrame.Fir; + Prcb = (PKPRCB)(LoaderBlock->Prcb); + Prcb->Number = (CCHAR)LogicalNumber; + Prcb->RestartBlock = NextRestartBlock; + NextRestartBlock->BootStatus.ProcessorStart = 1; + + HalpInitializeProcessorMapping( + LogicalNumber, + PhysicalNumber, + LoaderBlock + ); + + return TRUE; + + } else { + + // + // Ensure that the logical to physical mapping has been + // established for this processor. + // + + HalpInitializeProcessorMapping( + LogicalNumber, + PhysicalNumber, + LoaderBlock + ); + + } + + LogicalNumber += 1; + PhysicalNumber += 1; + } + + NextRestartBlock = NextRestartBlock->NextRestartBlock; + + } while (NextRestartBlock != NULL); + +#endif // !defined(NT_UP) + + return FALSE; +} + +VOID +HalpVerifyPrcbVersion( + VOID + ) +/*++ + +Routine Description: + + This function verifies that the HAL matches the kernel. If there + is a mismatch the HAL bugchecks the system. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + + PKPRCB Prcb; + + // + // Verify Prcb major version number, and build options are + // all conforming to this binary image + // + + Prcb = KeGetCurrentPrcb(); + +#if DBG + if (!(Prcb->BuildType & PRCB_BUILD_DEBUG)) { + // This checked hal requires a checked kernel + KeBugCheckEx (MISMATCHED_HAL, 2, Prcb->BuildType, PRCB_BUILD_DEBUG, 0); + } +#else + if (Prcb->BuildType & PRCB_BUILD_DEBUG) { + // This free hal requires a free kernel + KeBugCheckEx (MISMATCHED_HAL, 2, Prcb->BuildType, 0, 0); + } +#endif +#ifndef NT_UP + if (Prcb->BuildType & PRCB_BUILD_UNIPROCESSOR) { + // This MP hal requires an MP kernel + KeBugCheckEx (MISMATCHED_HAL, 2, Prcb->BuildType, 0, 0); + } +#endif + if (Prcb->MajorVersion != PRCB_MAJOR_VERSION) { + KeBugCheckEx (MISMATCHED_HAL, + 1, Prcb->MajorVersion, PRCB_MAJOR_VERSION, 0); + } + + +} + + +VOID +HalpParseLoaderBlock( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) +{ + + if (LoaderBlock == NULL) { + return; + } + + HalpRecurseLoaderBlock( (PCONFIGURATION_COMPONENT_DATA) + LoaderBlock->ConfigurationRoot); +} + + + +VOID +HalpRecurseLoaderBlock( + IN PCONFIGURATION_COMPONENT_DATA CurrentEntry + ) +/*++ + +Routine Description: + + This routine parses the loader parameter block looking for the PCI + node. Once found, used to determine if PCI parity checking should be + enabled or disabled. Set the default to not disable checking. + +Arguments: + + CurrentEntry - Supplies a pointer to a loader configuration + tree or subtree. + +Return Value: + + None. + +--*/ +{ + + PCONFIGURATION_COMPONENT Component; + PWSTR NameString; + + // + // Quick out + // + + if (AlreadySet) { + return; + } + + if (CurrentEntry) { + Component = &CurrentEntry->ComponentEntry; + + if (Component->Class == AdapterClass && + Component->Type == MultiFunctionAdapter) { + + if (strcmp(Component->Identifier, "PCI") == 0) { + HalDisablePCIParityChecking = Component->Flags.ConsoleOut; + AlreadySet = TRUE; +#if HALDBG + DbgPrint("ARC tree sets PCI parity checking to %s\n", + HalDisablePCIParityChecking ? "OFF" : "ON"); +#endif + return; + } + } + + // + // Process all the Siblings of current entry + // + + HalpRecurseLoaderBlock(CurrentEntry->Sibling); + + // + // Process all the Childeren of current entry + // + + HalpRecurseLoaderBlock(CurrentEntry->Child); + + } +} + + +ULONG +HalpQuerySystemFrequency( + ULONG SampleTime + ) +/*++ + +Routine Description: + + This routine returns the speed at which the system is running in hertz. + The system frequency is calculated by counting the number of processor + cycles that occur during 500ms, using the Programmable Interval Timer + (PIT) as the reference time. The PIT is used to generate a square + wave with a 50ms Period. We use the Speaker counter since we can + enable and disable the count from software. The output of the + speaker is obtained from the SIO NmiStatus register. + +Arguments: + + None. + +Return Value: + + The system frequency in Hertz. + +--*/ +{ + TIMER_CONTROL TimerControlSetup; + TIMER_CONTROL TimerControlReadStatus; + TIMER_STATUS TimerStatus; + NMI_STATUS NmiStatus; + PEISA_CONTROL controlBase; + ULONGLONG Count1; + ULONGLONG Count2; + ULONG NumberOfIntervals; + ULONG SquareWaveState = 0; + +// mdbfix - move this into eisa.h one day +#define SB_READ_STATUS_ONLY 2 + + controlBase = HalpEisaControlBase; + + // + // Disable the speaker counter. + // + + *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus); + + NmiStatus.SpeakerGate = 0; + NmiStatus.SpeakerData = 0; + + // these are MBZ when writing to NMIMISC + NmiStatus.RefreshToggle = 0; + NmiStatus.SpeakerTimer = 0; + NmiStatus.IochkNmi = 0; + + WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus)); + + // + // Number of Square Wave transitions to count. + // at 50ms period, count the number of 25ms + // square wave transitions for a sample reference + // time to against which we measure processor cycle count. + // + + NumberOfIntervals = (SampleTime/50) * 2; + + // + // Set the timer for counter 0 in binary mode, square wave output + // + + TimerControlSetup.BcdMode = 0; + TimerControlSetup.Mode = TM_SQUARE_WAVE; + TimerControlSetup.SelectByte = SB_LSB_THEN_MSB; + TimerControlSetup.SelectCounter = SELECT_COUNTER_2; + + // + // Set the counter for a latched read of the status. + // We will poll the PIT for the state of the square + // wave output. + // + + TimerControlReadStatus.BcdMode = 0; + TimerControlReadStatus.Mode = (1 << SELECT_COUNTER_2); + TimerControlReadStatus.SelectByte = SB_READ_STATUS_ONLY; + TimerControlReadStatus.SelectCounter = SELECT_READ_BACK; + + + // + // Write the count value LSB and MSB for a 50ms clock period + // + + WRITE_PORT_UCHAR( &controlBase->CommandMode1, + *(PUCHAR)&TimerControlSetup ); + + WRITE_PORT_UCHAR( &controlBase->SpeakerTone, + TIMER_REF_VALUE & 0xff ); + + WRITE_PORT_UCHAR( &controlBase->SpeakerTone, + (TIMER_REF_VALUE >> 8) & 0xff ); + + // + // Enable the speaker counter but disable the SPKR output signal. + // + + *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus); + + NmiStatus.SpeakerGate = 1; + NmiStatus.SpeakerData = 0; + + // these are MBZ when writing to NMIMISC + NmiStatus.RefreshToggle = 0; + NmiStatus.SpeakerTimer = 0; + NmiStatus.IochkNmi = 0; + + WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus)); + + // + // Synchronize with the counter before taking the first + // sample of the Processor Cycle Count (PCC). Since we + // are using the Square Wave Mode, wait until the next + // state change and then observe half a cycle before + // sampling. + // + + // + // observe the low transition of the square wave output. + // + do { + + *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus); + + } while (NmiStatus.SpeakerTimer != SquareWaveState); + + SquareWaveState ^= 1; + + // + // observe the next transition of the square wave output and then + // take the first cycle counter sample. + // + do { + + *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus); + + } while (NmiStatus.SpeakerTimer != SquareWaveState); + + Count1 = __RCC(); + + // + // Wait for the 500ms time period to pass and then take the + // second sample of the PCC. For a 50ms period, we have to + // observe eight wave transitions (25ms each). + // + + do { + + SquareWaveState ^= 1; + + // + // wait for wave transition + // + do { + + *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus); + + } while (NmiStatus.SpeakerTimer != SquareWaveState); + + } while (--NumberOfIntervals); + + Count2 = __RCC(); + + // + // Disable the speaker counter. + // + + *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus); + + NmiStatus.SpeakerGate = 0; + NmiStatus.SpeakerData = 0; + + WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus)); + + // + // Calculate the Hz by the number of processor cycles + // elapsed during 1s. + // + // Hz = PCC/SampleTime * 1000ms/s + // = PCC * (1000/SampleTime) + // + + // did the counter wrap? if so add 2^32 + if (Count1 > Count2) { + + Count2 += (ULONGLONG)(1 << 32); + + } + + return ( ((ULONG) (Count2 - Count1)) *(((ULONG)1000)/SampleTime)); +} + + +VOID +HalpInitializeProcessorParameters( + VOID + ) +/*++ + +Routine Description: + + This routine initalize the processor counter parameters + HalpClockFrequency and HalpClockMegaHertz based on the + estimated CPU speed. A 1s reference time is used for + the estimation. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + + HalpClockFrequency = HalpQuerySystemFrequency(1000); + HalpClockMegaHertz = (HalpClockFrequency + 500000)/ 1000000; + +#if HALDBG + DbgPrint( + "Frequency = %d\nMegaHertz = %d\n", + HalpClockFrequency, + HalpClockMegaHertz + ); +#endif //HALDBG + +} + + + + +#if 0 +VOID +HalpGatherPerformanceParameterStats( + VOID + ) + +/*++ + +Routine Description: + + This routine gathers statistics on the method for + estimating the system frequency. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + ULONG Index; + ULONG Hertz[32]; + ULONGLONG Mean = 0; + ULONGLONG Variance = 0; + ULONGLONG TempHertz; + + // + // take 32 samples of estimated CPU speed, + // calculating the mean in the process. + // + DbgPrint("Sample\tFrequency\tMegaHertz\n\n"); + + for (Index = 0; Index < 32; Index++) { + Hertz[Index] = HalpQuerySystemFrequency(500); + Mean += Hertz[Index]; + + DbgPrint( + "%d\t%d\t%d\n", + Index, + Hertz[Index], + (ULONG)((Hertz[Index] + 500000)/1000000) + ); + + } + + // + // calculate the mean + // + + Mean /= 32; + + // + // calculate the variance + // + for (Index = 0; Index < 32; Index++) { + TempHertz = (Mean > Hertz[Index])? + (Mean - Hertz[Index]) : (Hertz[Index] - Mean); + TempHertz = TempHertz*TempHertz; + Variance += TempHertz; + } + + Variance /= 32; + + DbgPrint("\nResults\n\n"); + DbgPrint( + "Mean = %d\nVariance = %d\nMegaHertz (derived) = %d\n", + Mean, + Variance, + (Mean + 500000)/ 1000000 + ); + +} +#endif + diff --git a/private/ntos/nthals/halraw/alpha/intsup.s b/private/ntos/nthals/halraw/alpha/intsup.s new file mode 100644 index 000000000..fa1669189 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/intsup.s @@ -0,0 +1,256 @@ +//++ +// +// Copyright (c) 1993 Digital Equipment Corporation +// +// Module Name: +// +// intsup.s +// +// Abstract: +// +// This module implements first level interrupt handlers. +// +// Author: +// +// Joe Notarangelo 08-Jul-1993 +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +// 24-Sep-93 Joe Notarangelo +// Make this module platform-independent. +//-- + +#include "halalpha.h" + + SBTTL("System Clock Interrupt") +//++ +// +// VOID +// HalpClockInterrupt( +// ) +// +// Routine Description: +// +// This function is executed for each interval timer interrupt on +// the primary processor. The routine is responsible for acknowledging the +// interrupt and calling the kernel to update the system time. +// In addition, this routine checks for breakins from the kernel debugger +// and maintains the 64 bit performance counter based upon the +// processor cycle counter. +// +// Arguments: +// +// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for +// the interrupt. +// +// Return Value: +// +// None. +// +//-- + + .struct 0 + .space 8 // filler for octaword alignment +CiRa: .space 8 // space for return address +CiFrameLength: // + + NESTED_ENTRY(HalpClockInterrupt, CiFrameLength, zero ) + + lda sp, -CiFrameLength(sp) // allocate stack frame + stq ra, CiRa(sp) // save return address + + PROLOGUE_END + +// +// Acknowledge the clock interrupt. +// + + bsr ra, HalpAcknowledgeRawhideClockInterrupt // ack the interrupt + beq v0, 30f // Roll over? No: return + +// +// Yes: Call the kernel to update the system time. +// + + ldl a1, HalpCurrentTimeIncrement // Get current time increment + bis fp, zero, a0 // a0 = pointer to trap frame + ldl t0, __imp_KeUpdateSystemTime + jsr ra, (t0) // call kernel + +// ldl t0, HalpNextTimeIncrement // Get next time increment +// stl t0, HalpCurrentTimeIncrement // Set CurrentTimeIncrement to NextTimeIncrement + + ldl a0, HalpNextRateSelect // Get NextIntervalCount. If 0, no change required + beq a0, 20f + + stl zero, HalpNextRateSelect // Set NextRateSelect to 0 + bsr ra, HalpProgramIntervalTimer // Program timer with new rate select + + ldl t0, HalpNewTimeIncrement + stl t0, HalpCurrentTimeIncrement // Set HalpNextTimeIncrement to HalpNewTimeIncrement +// stl t0, HalpNextTimeIncrement // Set HalpNextTimeIncrement to HalpNewTimeIncrement + +// +// Call to handle performance counter wrap. +// +20: + bsr ra, HalpCheckPerformanceCounter // check for perf. counter wrap + +#if DEVL + +// +// Check for a breakin request from the kernel debugger. +// + + ldl t0, __imp_KdPollBreakIn + jsr ra, (t0) // check for breakin requested + beq v0, 30f // if eq[false], no breakin + BREAK_BREAKIN // execute breakin breakpoint + +30: + +#endif //DEVL + +// +// Return to the caller. +// +30: + ldq ra, CiRa(sp) // restore return address + lda sp, CiFrameLength(sp) // deallocate stack frame + ret zero, (ra) // return to caller + + .end HalpClockInterrupt + + +#ifndef NT_UP + + SBTTL("Secondary Processor Clock Interrupt") +//++ +// +// VOID +// HalpSecondaryClockInterrupt( +// ) +// +// Routine Description: +// +// This function is executed for each interval timer interrupt on +// the current secondary processor. The routine is responsible for +// acknowledging the interrupt and calling the kernel to update the +// run time for the current processor. +// In addition, this routine checks for breakins from the kernel debugger +// and maintains the 64 bit performance counter based upon the +// processor cycle counter. +// +// Arguments: +// +// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for +// the interrupt. +// +// Return Value: +// +// None. +// +//-- + + + NESTED_ENTRY(HalpSecondaryClockInterrupt, CiFrameLength, zero ) + + lda sp, -CiFrameLength(sp) // allocate stack frame + stq ra, CiRa(sp) // save return address + + PROLOGUE_END + +// +// Acknowledge the clock interrupt. +// + + bsr ra, HalpAcknowledgeRawhideClockInterrupt // ack the interrupt + beq v0, 40f // Roll over? No: return + +// +// Call the kernel to update the run time. +// +10: + bis fp, zero, a0 // a0 = pointer to trap frame + ldl t0, __imp_KeUpdateRunTime + jsr ra, (t0) // call kernel + +#if DEVL + +// +// Check for a breakin request from the kernel debugger. +// + + ldl t0, __imp_KdPollBreakIn + jsr ra, (t0) // check for breakin requested + beq v0, 30f // if eq[false], no breakin + BREAK_BREAKIN // execute breakin breakpoint + +30: + +#endif //DEVL + +// +// Return to the caller. +// +40: + ldq ra, CiRa(sp) // restore return address + lda sp, CiFrameLength(sp) // deallocate stack frame + ret zero, (ra) // return to caller + + .end HalpSecondaryClockInterrupt + + SBTTL("Interprocessor Interrupt") +//++ +// +// VOID +// HalpIpiInterruptHandler +// ) +// +// Routine Description: +// +// This function is executed as the result of an interprocessor +// interrupt asserted on the current processor. This function is +// responsible for acknowledging the interrupt and dispatching to +// the kernel for processing. +// +// Arguments: +// +// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for +// the interrupt. +// +// Return Value: +// +// None. +// +//-- + + .struct 0 + .space 8 // filler for octaword alignment +IpiRa: .space 8 // space for return address +IpiFrameLength: // + + NESTED_ENTRY(HalpIpiInterruptHandler, IpiFrameLength, zero ) + + lda sp, -IpiFrameLength(sp) // allocate stack frame + stq ra, IpiRa(sp) // save return address + + PROLOGUE_END + + bsr ra, HalpAcknowledgeIpiInterrupt // acknowledge interrupt + + ldl t0, __imp_KeIpiInterrupt + jsr ra, (t0) // call kernel to process + + ldq ra, IpiRa(sp) // restore return address + ret zero, (ra) // return + + .end HalpIpiInterruptHandler + + +#endif //NT_UP + diff --git a/private/ntos/nthals/halraw/alpha/iod.c b/private/ntos/nthals/halraw/alpha/iod.c new file mode 100644 index 000000000..c04d46a85 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/iod.c @@ -0,0 +1,1467 @@ +/*++ + +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 + diff --git a/private/ntos/nthals/halraw/alpha/iod.h b/private/ntos/nthals/halraw/alpha/iod.h new file mode 100644 index 000000000..6aee89719 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/iod.h @@ -0,0 +1,1669 @@ +/*++ + +Copyright (c) 1995 Digital Equipment Corporation + +Module Name: + + iod.h + +Abstract: + + This file defines the structures and definitions registers on a + Rawhide I/O Daughter card. These register reside on the CAP chip, + MDP chips, and flash ROM. + + +Author: + + Eric Rehm 16-Feb-1995 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#ifndef _IODH_ +#define _IODH_ + + +// +// IOD Revision definitions. +// + +#define IOD_REVISION_1 (0) +#define IOD_REVISION_2 (1) + +// +// Define QVA constants. +// + +#if !defined(QVA_ENABLE) + +#define QVA_ENABLE (0xA0000000) // Identify VA as a QVA + +#endif //QVA_ENABLE + +#define QVA_SELECTORS (0xE0000000) // QVA identification mask + +#define IO_BIT_SHIFT 0x05 // Bits to shift QVA + +#define IO_BYTE_OFFSET 0x20 // Offset to next byte +#define IO_SHORT_OFFSET 0x40 // Offset to next short +#define IO_LONG_OFFSET 0x80 // Offset to next long + +#define IO_BYTE_LEN 0x00 // Byte length +#define IO_WORD_LEN 0x08 // Word length +#define IO_TRIBYTE_LEN 0x10 // TriByte length +#define IO_LONG_LEN 0x18 // Longword length + +#define IOD_SPARSE_SELECTORS (0x18000000) // BusNumber is encoded in QVA<28:27> +#define IOD_SPARSE_ENABLE (0xB8000000) // QVA_SELECTORS|IOD_SPARSE_SELECTORS +#define IOD_SPARSE_BUS_SHIFT 0x06 // Bits to shift BusNumber into MID + +#define IOD_DENSE_SELECTORS (0xC0000000) // BusNumber is encoded in QVA<31:30> +#define IOD_DENSE_ENABLE (0xC0000000) // Same as IOD_DENSE_SELECTORS +#define IOD_DENSE_BUS_SHIFT 0x03 // Bits to shift BusNumber into MID + +// +// Define size of I/O and memory space for the CIA. +// Assume that the HAE==0. +// + +#define PCI_MAX_IO_ADDRESS (__32MB - 1) // I/O: 0 - 32MB +#define PCI_MAX_SPARSE_MEMORY_ADDRESS (__128MB - 1) // Mem: 0 - 128MB +#define PCI_MIN_DENSE_MEMORY_ADDRESS PCI_MAX_SPARSE_MEMORY_ADDRESS + 1 +#define PCI_MAX_DENSE_MEMORY_ADDRESS (__1GB - 1) // Dense: 128 Mb - 1.0 Gb + +#if !defined(_LANGUAGE_ASSEMBLY) + +#define GID_TO_PHYS_ADDR( GID ) ((ULONGLONG)(((GID & 0x7) << 36)) +#define MCDEVID_FROM_PHYS_ADDR( PA ) ( (ULONG)(((PA) >> 33) & 0x3f) ) +#if 0 +#define MCDEVID_TO_PHYS_ADDR( MCDEVID ) \ + ((ULONGLONG)((ULONGLONG)(MCDEVID & 0x3F ) << 33 )) +#else +#define MCDEVID_TO_PHYS_ADDR( MCDEVID ) \ + ((ULONGLONG)((ULONGLONG)(MCDEVID & 0x07 ) << 33 )) +#endif +#define MCDEVID_TO_PHYS_CPU( MCDEVID ) \ + ( (((MCDEVID) & 0x07) < 4) ? \ + (((MCDEVID) & 0x07) - 2) : \ + (((MCDEVID) & 0x07) - 4) ) +#define PHYS_ADDR_TO_OFFSET( PA ) ( (PA) & ( (ULONGLONG) 0x1FFFFFFFF) ) +#define IOD_QVA_PHYSICAL_BASE ((ULONGLONG)0xf800000000) + + +// +// QVA +// HAL_MAKE_QVA( +// ULONGLONG PhysicalAddress +// ) +// +// Routine Description: +// +// This macro returns the Qva for a physical address in system space. +// +// Arguments: +// +// PhysicalAddress - Supplies a 64-bit physical address. +// +// Return Value: +// +// The Qva associated with the physical address. +// + +#define HAL_MAKE_QVA(PA) \ + ( (PVOID)( QVA_ENABLE | \ + (ULONG)( (PA - IOD_QVA_PHYSICAL_BASE) >> IO_BIT_SHIFT) ) ) + +// +// QVA +// HAL_MAKE_IOD_SPARSE_QVA( +// ULONG BusNumber, +// ULONG BusAddress +// ) +// +// Routine Description: +// +// This macro returns the Qva for a physical address in sparse I/O +// or sparse memory space. +// +// Arguments: +// +// BusNumber - Supplies a bus number between 0-3. +// BusAddress - Supplies a 32-bit PCI bus address. +// +// Return Value: +// +// The Qva associated with bus number and bus address. +// HAL I/O access routines can use this to constrct the +// correct physical address for the accesss. +// + +#define HAL_MAKE_IOD_SPARSE_QVA(BUS_NUMBER, BA) \ + ( (PVOID)( QVA_ENABLE | (BUS_NUMBER << 27) | ((ULONG) BA) ) ) + + +// +// QVA +// HAL_MAKE_IOD_DENSE_QVA( +// ULONG BusNumber, +// ULONG BusAddress +// ) +// +// Routine Description: +// +// This macro returns the Qva for a physical address in dense +// memory space space. +// +// Arguments: +// +// BusNumber - Supplies a bus number between 0-3. +// BusAddress - Supplies a 32-bit PCI bus address. +// +// Return Value: +// +// The Qva associated with bus number and bus address. +// HAL I/O access routines can use this to constrct the +// correct physical address for the accesss. +// + +#define HAL_MAKE_IOD_DENSE_QVA(BUS_NUMBER, BA) \ + ( (PVOID)( (BUS_NUMBER << 30) | ((ULONG) BA) ) ) + + + + +// +// Define GID/MIDs for IIP and PIO flavors of MC Bus +// + +#define IOD_DODGE_GID 0x7 +#define IOD_DURANGO_GID IOD_DODGE_GID + +#define IOD_GCD_MID 0x0 +#define IOD_MEM_MID 0x1 +#define IOD_CPU0_MID 0x2 +#define IOD_CPU1_MID 0x3 +#define IOD_PCI0_MID 0x4 +#define IOD_PCI1_MID 0x5 +#define IOD_CPU2_MID 0x6 +#define IOD_PCI2_MID IOD_CPU2_MID +#define IOD_CPU3_MID 0x7 +#define IOD PCI3_MID IOD_CPU3_MID + +// +// QVA +// HAL_MAKE_NEW_QVA( +// ULONGLONG PhysicalAddress +// ) +// +// Routine Description: +// +// This macro returns the Qva for a physical address in system space. +// +// Arguments: +// +// PhysicalAddress - Supplies a 64-bit physical address. +// +// Return Value: +// +// The Qva associated with the physical address. +// + +#define HAL_MAKE_NEW_QVA(PA) \ + ( (PVOID)( QVA_ENABLE | (ULONG)( (PA) >> IO_BIT_SHIFT) ) ) + +// +// Define IO space offsets for generic rawhide +// + +#define IOD_IO_SPACE_START ((ULONGLONG)0x8000000000) + +// +// These offsets are from IOD_IO_SPACE_START +// + +#define IOD_GCD_CSRS_OFFSET ((ULONGLONG)0x0000000000) +#define IOD_MEMORY_CSRS_OFFSET ((ULONGLONG)0x0200000000) + +#define IOD_CPU_IP_INTR_OFFSET ((ULONGLONG)0x0010000000) +#define IOD_CPU_NODE_HALT_OFFSET ((ULONGLONG)0x0070000000) +#define IOD_CPU_INTTIM_ACK_OFFSET ((ULONGLONG)0x0100000000) +#define IOD_CPU_IO_INTR_OFFSET ((ULONGLONG)0x00f0000000) +#define IOD_CPU_IP_ACK_OFFSET ((ULONGLONG)0x0110000000) +#define IOD_CPU_MCHK_ACK_OFFSET ((ULONGLONG)0x0130000000) +#define IOD_CPU_DTAG_EN_0_OFFSET ((ULONGLONG)0x0140000000) +#define IOD_CPU_DTAG_EN_1_OFFSET ((ULONGLONG)0x0150000000) +#define IOD_CPU_HALT_ACK_OFFSET ((ULONGLONG)0x0170000000) + +#define IOD_SPARSE_MEM_OFFSET ((ULONGLONG)0x0000000000) +#define IOD_DENSE_MEM_OFFSET ((ULONGLONG)0x0100000000) +#define IOD_SPARSE_IO_OFFSET ((ULONGLONG)0x0180000000) +#define IOD_SPARSE_CONFIG_OFFSET ((ULONGLONG)0x01c0000000) +#define IOD_SPARSE_CSR_OFFSET ((ULONGLONG)0x01e0000000) + +// +// Generic Rawhide I/O Address Computation macros +// + +#define IOD_GCD_CSRS_QVA \ + (HAL_MAKE_NEW_QVA(IOD_GCD_CSRS_OFFSET)) + +#define IOD_MEMORY_CSRS_QVA \ + (HAL_MAKE_NEW_QVA(IOD_MEMORY_CSRS_OFFSET)) + +#define IOD_CPU_IP_INTR_QVA \ + (HAL_MAKE_NEW_QVA(IOD_CPU_IP_INTR_OFFSET)) + +#define IOD_CPU_NODE_HALT_QVA \ + (HAL_MAKE_NEW_QVA(IOD_CPU_NODE_HALT_OFFSET)) + +#define IOD_CPU_IO_INTR_QVA \ + (HAL_MAKE_NEW_QVA(IOD_CPU_IO_INTR_OFFSET)) + +#define IOD_CPU_INTTIM_ACK_QVA \ + (HAL_MAKE_NEW_QVA(IOD_CPU_INTTIM_ACK_OFFSET)) + +#define IOD_CPU_IP_ACK_QVA \ + (HAL_MAKE_NEW_QVA(IOD_CPU_IP_ACK_OFFSET)) + +#define IOD_CPU_MCHK_ACK_QVA \ + (HAL_MAKE_NEW_QVA(IOD_CPU_MCHK_ACK_OFFSET)) + +#define IOD_CPU_DTAG_EN_0_QVA \ + (HAL_MAKE_NEW_QVA(IOD_CPU_DTAG_EN_0_OFFSET)) + +#define IOD_CPU_DTAG_EN_1_QVA \ + (HAL_MAKE_NEW_QVA(IOD_CPU_DTAG_EN_1_OFFSET)) + +#define IOD_CPU_HALT_ACK_QVA \ + (HAL_MAKE_NEW_QVA(IOD_CPU_HALT_ACK_OFFSET)) + +#define IOD_SPARSE_MEM_QVA \ + (HAL_MAKE_NEW_QVA(IOD_SPARSE_MEM_OFFSET )) + +#define IOD_DENSE_MEM_QVA \ + (HAL_MAKE_NEW_QVA(IOD_DENSE_MEM_OFFSET )) + +#define IOD_SPARSE_IO_QVA \ + (HAL_MAKE_NEW_QVA(IOD_SPARSE_IO_OFFSET )) + +#define IOD_SPARSE_CONFIG_QVA \ + (HAL_MAKE_NEW_QVA(IOD_SPARSE_CONFIG_OFFSET )) + +#define IOD_SPARSE_CSR_QVA \ + (HAL_MAKE_NEW_QVA(IOD_SPARSE_CSR_OFFSET )) + +#define IOD_GENERAL_CSRS_QVA IOD_SPARSE_CSR_QVA + +#define IOD_PCI_IACK_QVA \ + (HAL_MAKE_NEW_QVA(IOD_SPARSE_CSR_OFFSET + 0x480)) + +#define IOD_INT_CSRS_QVA \ + (HAL_MAKE_NEW_QVA(IOD_SPARSE_CSR_OFFSET + 0x500)) + +#define IOD_DIAG_CSRS_QVA \ + (HAL_MAKE_NEW_QVA(IOD_SPARSE_CSR_OFFSET + 0x700)) + +#define IOD_ERROR_CSRS_QVA \ + (HAL_MAKE_NEW_QVA(IOD_SPARSE_CSR_OFFSET + 0x800)) + +#define IOD_SG_CSRS_QVA \ + (HAL_MAKE_NEW_QVA(IOD_SPARSE_CSR_OFFSET + 0x1300)) + +// +// Define physical address space for 1 CPU at GID=7, MID=1, +// and XSone IOD. // ecrfix +// + +#define IOD_GCD_CSRS_PHYSICAL ((ULONGLONG)0xf000000000) +#define IOD_MEMORY_CSRS_PHYSICAL ((ULONGLONG)0xf200000000) + +#define IOD_CPU0_IO_INTR_PHYSICAL ((ULONGLONG)0xf400000000) +#define IOD_CPU0_IP_INTR_PHYSICAL ((ULONGLONG)0xf510000000) +#define IOD_CPU0_NODE_HALT_PHYSICAL ((ULONGLONG)0xf520000000) + +// +// PCI Bus 0 +// + +// old ecrfix #define IOD_PCI0_DENSE_MEMORY_PHYSICAL ((ULONGLONG)0xf800000000) +// old ecrfix #define IOD_PCI0_SPARSE_MEMORY_PHYSICAL ((ULONGLONG)0xf900000000) +#define IOD_PCI0_SPARSE_MEMORY_PHYSICAL ((ULONGLONG)0xf800000000) +#define IOD_PCI0_DENSE_MEMORY_PHYSICAL ((ULONGLONG)0xf900000000) +#define IOD_PCI0_SPARSE_IO_PHYSICAL ((ULONGLONG)0xf980000000) +#define IOD_PCI0_CONFIGURATION_PHYSICAL ((ULONGLONG)0xf9C0000000) +#define IOD_MAIN0_CSRS_PHYSICAL ((ULONGLONG)0xf9E0000000) + +#define IOD_PCI0_CONFIG_BASE_QVA (HAL_MAKE_QVA(IOD_PCI0_CONFIGURATION_PHYSICAL)) +#define IOD_PCI0_SPARSE_IO_QVA (HAL_MAKE_QVA(IOD_PCI0_SPARSE_IO_PHYSICAL)) +#define IOD_PCI0_SPARSE_MEMORY_QVA (HAL_MAKE_QVA(IOD_PCI0_SPARSE_MEMORY_PHYSICAL)) + +#define IOD_GENERAL0_CSRS_PHYSICAL ((ULONGLONG)IOD_MAIN0_CSRS_PHYSICAL) +#define IOD_GENERAL0_CSRS_QVA HAL_MAKE_QVA(IOD_GENERAL0_CSRS_PHYSICAL) + +#define IOD_PCI0_IACK_PHYSICAL ((ULONGLONG)IOD_MAIN0_CSRS_PHYSICAL+0x480) +#define IOD_PCI0_IACK_QVA HAL_MAKE_QVA(IOD_PCI0_IACK_PHYSICAL) + +#define IOD_INT0_CSRS_PHYSICAL ((ULONGLONG)IOD_MAIN0_CSRS_PHYSICAL+0x500) +#define IOD_INT0_CSRS_QVA HAL_MAKE_QVA(IOD_INT0_CSRS_PHYSICAL) +#define IOD_DIAG0_CSRS_PHYSICAL ((ULONGLONG)IOD_MAIN0_CSRS_PHYSICAL+0x700) +#define IOD_DIAG0_CSRS_QVA HAL_MAKE_QVA(IOD_DIAG0_CSRS_PHYSICAL) + +#define IOD_ERROR0_CSRS_PHYSICAL ((ULONGLONG)IOD_MAIN0_CSRS_PHYSICAL+0x800) +#define IOD_ERROR0_CSRS_QVA HAL_MAKE_QVA(IOD_ERROR0_CSRS_PHYSICAL) + +#define IOD_SCATTER_GATHER0_CSRS_PHYSICAL ((ULONGLONG)IOD_MAIN0_CSRS_PHYSICAL+0x1300) +#define IOD_SG0_CSRS_QVA (HAL_MAKE_QVA(IOD_SCATTER_GATHER0_CSRS_PHYSICAL)) + +// +// PCI Bus 1 +// + +#define IOD_PCI1_SPARSE_MEMORY_PHYSICAL ((ULONGLONG)0xfa00000000) +#define IOD_PCI1_DENSE_MEMORY_PHYSICAL ((ULONGLONG)0xfb00000000) +#define IOD_PCI1_SPARSE_IO_PHYSICAL ((ULONGLONG)0xfb80000000) +#define IOD_PCI1_CONFIGURATION_PHYSICAL ((ULONGLONG)0xfbC0000000) +#define IOD_MAIN1_CSRS_PHYSICAL ((ULONGLONG)0xfbE0000000) + +#define IOD_PCI1_CONFIG_BASE_QVA (HAL_MAKE_QVA(IOD_PCI1_CONFIGURATION_PHYSICAL)) +#define IOD_PCI1_SPARSE_IO_QVA (HAL_MAKE_QVA(IOD_PCI1_SPARSE_IO_PHYSICAL)) +#define IOD_PCI1_SPARSE_MEMORY_QVA (HAL_MAKE_QVA(IOD_PCI1_SPARSE_MEMORY_PHYSICAL)) + +#define IOD_GENERAL1_CSRS_PHYSICAL ((ULONGLONG)IOD_MAIN1_CSRS_PHYSICAL) +#define IOD_GENERAL1_CSRS_QVA HAL_MAKE_QVA(IOD_GENERAL1_CSRS_PHYSICAL) + +#define IOD_INT1_CSRS_PHYSICAL ((ULONGLONG)IOD_MAIN1_CSRS_PHYSICAL+0x500) +#define IOD_INT1_CSRS_QVA HAL_MAKE_QVA(IOD_INT1_CSRS_PHYSICAL) + +#define IOD_DIAG1_CSRS_PHYSICAL ((ULONGLONG)IOD_MAIN1_CSRS_PHYSICAL+0x700) +#define IOD_DIAG1_CSRS_QVA HAL_MAKE_QVA(IOD_DIAG1_CSRS_PHYSICAL) + +#define IOD_ERROR1_CSRS_PHYSICAL ((ULONGLONG)IOD_MAIN1_CSRS_PHYSICAL+0x800) +#define IOD_ERROR1_CSRS_QVA HAL_MAKE_QVA(IOD_ERROR1_CSRS_PHYSICAL) + +#define IOD_SCATTER_GATHER1_CSRS_PHYSICAL ((ULONGLONG)IOD_MAIN1_CSRS_PHYSICAL+0x1300) +#define IOD_SG_CSRS1_QVA (HAL_MAKE_QVA(IOD_SCATTER_GATHER1_CSRS_PHYSICAL)) + +// +// Define the classes of IOD registers. +// + +typedef enum _IOD_REGISTER_CLASS{ + IodGeneralRegisters = 0x1, + IodInterruptRegisters = 0x2, + IodDiagnosticRegisters = 0x3, + IodErrorRegisters = 0x4, + IodScatterGatherRegisters = 0x5, + IodFlashRomRegisters = 0x6, + IodResetRegister = 0x7, + AllRegisters = 0xffffffff +} IOD_REGISTER_CLASS, *PIOD_REGISTER_CLASS; + +// +// Define the MC bus global id's +// + +typedef enum _MC_GLOBAL_ID{ + GidPrimary = 0x7 +} MC_GLOBAL_ID, *PMC_GLOBAL_ID; + +// +// Define the MC bus module id's +// + +typedef enum _MC_MODULE_ID{ + MidGcd = 0x0, + MidMem = 0x1, + MidCpu0 = 0x2, + MidCpu1 = 0x3, + MidPci0 = 0x4, + MidPci1 = 0x5, + MidCpu2 = 0x6, // Dodge, IIP Motherboard + MidCpu3 = 0x7, // Dodge, IIP Motherboard + MidPci2 = 0x6, // Durango, PIO Motherboard + MidPci3 = 0x7 // Durango, PIO Motherboard +} MC_MODULE_ID, *PMC_MODULE_ID; + +// +// Define the MC device id type +// + +typedef union _MC_DEVICE_ID{ + struct{ + ULONG Mid: 3; // <2:0> Module Id + ULONG Gid: 3; // <5:3> Global Id + ULONG Reserved0: 26; // + }; + ULONG all; // <5:0> MC Bus Device Id +} MC_DEVICE_ID, *PMC_DEVICE_ID; + +extern MC_DEVICE_ID HalpIodLogicalToPhysical[]; + +// +// Define the MC bus enumeration types +// + +typedef ULONGLONG MC_DEVICE_MASK; + +extern MC_DEVICE_MASK HalpIodMask; +extern MC_DEVICE_MASK HalpCpuMask; +extern MC_DEVICE_MASK HalpGcdMask; + +// +// Define the number of IOD's and CPU's in the system +// + +extern ULONG HalpNumberOfIods; +extern ULONG HalpNumberOfCpus; + +typedef struct _MC_ENUM_CONTEXT { + RTL_BITMAP McDeviceBitmap; // Device mask being enumerated + MC_DEVICE_MASK tempMask; // Bitmap storage + ULONG nextBit; // Hint to speed up enumeration + // N.B. this is the only public member of this structure: + MC_DEVICE_ID McDeviceId; // Currently enumerated McDeviceID +} MC_ENUM_CONTEXT, *PMC_ENUM_CONTEXT; + +// +// The Bus enumeration routine is called from HalpMcBusEnumAndCall() +// to perform operations on an enumerated device mask. +// + +typedef +VOID (*PMC_ENUM_ROUTINE) ( + MC_DEVICE_ID McDeviceId, + ULONG PciBusNumber, + va_list McEnumBusArgs + ); + +// +// Define expected machine check data type +// + +typedef struct _IOD_EXPECTED_ERROR { + ULONG Number; // Processor Number + ULONGLONG Addr; // SuperPage mode address causing Fill_Error +} IOD_EXPECTED_ERROR, *PIOD_EXPECTED_ERROR; + +#define MASTER_ABORT_NOT_EXPECTED 0xffffffff + +// +// Define the format of the posted interrupt written that the +// bridge writes to system memory. +// + +typedef union _IOD_POSTED_INTERRUPT { + + struct{ + ULONG Pci: 16; // <15:0> PCI interrupt State + ULONG Eisa: 1; // <17> Eisa/NCR810 interrupt state + ULONG I2cCtrl: 1; // <17> 8254 I2C Controller (PCI 0 Only) + ULONG I2cBus: 1; // <18> 8254 I2C Bus: (PCI 0 Only) + ULONG Reserved0: 2; // <20:19> + ULONG Nmi: 1; // <21> 8259 Eisa NMI + ULONG SoftErr: 1; // <22> Soft (correctable) error interrupt + ULONG HardErr: 1; // <23> Hard error interrupt + ULONG Target: 1; // <24> Target device number (0,1) + ULONG McDevId: 6; // PCI source of interrupt + ULONG Valid: 1; // Device interrupt pending/serviced + } ; + struct{ + ULONG IntReq: 24; // <23:0> InterruptState + } ; + ULONG all; + +} IOD_POSTED_INTERRUPT, *PIOD_POSTED_INTERRUPT; + +extern PIOD_POSTED_INTERRUPT HalpIodPostedInterrupts; + +// +// Address of vector table in memory +// + +typedef union _IOD_POSTED_INTERRUPT_ADDR { + struct{ + ULONG BusVectorOffset: 2; // QuadWord per vector entry + ULONG PciBusOffset: 4; // PCI bus offset into CPU area + ULONG CpuOffset: 6; // 64K area per CPU + ULONG Base4KPage: 20; // 4K page address of table + }; + ULONG all; + +} IOD_POSTED_INTERRUPT_ADDR, PIOD_POSTED_INTERRUPT_ADDR; + + +#define Ncr810 Eisa + +// +// Define the structures to access the IOD general CSRs. +// + +typedef struct _IOD_GENERAL_CSRS{ + UCHAR PciRevision; // (000) PCI Revision + UCHAR Filler1; // (020) + UCHAR WhoAmI; // (040) WhoAmI + UCHAR Filler2; // (060) + UCHAR PciLat; // (080) PCI Latency + UCHAR Filler3[3]; // (0a0 - 0e0) + UCHAR CapCtrl; // (100) CAP control (MC-PCI Bridge Command) + UCHAR Filler4[15]; // (120 - 2e0) + UCHAR PerfMon; // (300) Performance Monitor Counter + UCHAR Filler5; // (320) + UCHAR PerfCon; // (340) Peformance Monitor Ctrl Register + UCHAR Filler6[5]; // (360 - 3e0) + UCHAR HaeMem; // (400) Host address extension, sparse memory + UCHAR Filler7; // (420) + UCHAR HaeIo; // (440) Host address extension, space i/o + UCHAR Filler8; // (460) + UCHAR IackSc; // (480) Interrup Acknowledge / Special Cycle + UCHAR Filler9; // (4A0) + UCHAR HaeDense; // (4C0) Host address extension, dense memory +} IOD_GENERAL_CSRS, *PIOD_GENERAL_CSRS; + +typedef union _IOD_PCI_REVISION{ + struct{ + ULONG CapRev: 4; // <3:0> CAP Revision Id + ULONG HorseRev: 4; // <7:4> Horse Revision Id + ULONG SaddleRev: 4; // <11:8> Saddle Revision Id + ULONG SaddleType: 3; // <14:12> Type Id + ULONG EisaPresent: 1; // <15> Set if EISA bus present + ULONG SubClass: 8; // <23:16> PCI Host bus bridge sub class + ULONG BaseClass: 8; // <3:124> PCI Host bus bridge base class + }; + ULONG all; +} IOD_PCI_REVISION, *PIOD_PCI_REVISION; + +extern ULONG HalpIodPciRevision; // global containing IOD PCI revision id + +typedef union _IOD_WHOAMI{ + struct{ + ULONG Devid: 6; // <5:0> MC Bus Device Id + ULONG CpuInfo: 8; // <13:6> Data Bits + ULONG Reserved0: 18; // <31:14> MBZ + }; + MC_DEVICE_ID McDevId; // <5:0> MC Bus Device Id + ULONG all; +} IOD_WHOAMI, *PIOD_WHOAMI; + +#define CACHED_CPU_FILL_ERROR 0x80 // CpuInfo Data Bits +#define CACHED_CPU_DTAG_PARITY_ERROR 0x40 // CpuInfo Data Bits + +typedef union _IOD_PCI_LAT{ + struct{ + ULONG Reserved0: 8; // <7:0> + ULONG Latency: 8; // <15:8> PCI Master Latency timer (in PCI clocks) + ULONG Reserved1: 16; // <31:16> + }; + ULONG all; +} IOD_PCI_LAT, *PIOD_PCI_LAT; + +typedef union _IOD_CAP_CONTROL{ + struct{ + ULONG Led: 1; // <0> Selftest passed LED + ULONG Reserved0: 3; // <3:1> + ULONG DlyRdEn: 1; // <4> Enables PCI delayed read protocol ( > 16 clks) + ULONG PciMemEn: 1; // <5> Enables Bridge response to PCI transactions + ULONG PciReq64: 1; // <6> Enables request for 64-bit PCI transactions + ULONG PciAck64: 1; // <7> Enables accepting 64-bit PCI transactions + ULONG PciAddrPe: 1; // <8> Enables PCI address parity checking & SERR# + ULONG McCmdAddrPe: 1; // <9> Enables Check MC bus CMD / Address Parity + ULONG McNxmEn: 1; // <10> Enables Check MC bus NXM on IO space reads + ULONG McBusMonEn: 1; // <11> Enables Check MC bus errors when a bystander + ULONG Reserved1: 4; // <15:12> + ULONG PendNum: 4; // <19:16> Write Pend Number Threshold + ULONG RdType: 2; // <21:20> Memory Read Prefetch Type + ULONG RlType: 2; // <23:22> Memory Read Line Prefetch Type + ULONG RmType: 2; // <25:24> Memory Read Multiple Prefetch Type + ULONG PartialWrEn: 1; // <26> Partial Write Enable + ULONG Reserved3: 3; // <29:27> + ULONG ArbMode: 2; // <31:30> PCI Arbitration Mode + }; + ULONG all; +} IOD_CAP_CONTROL, *PIOD_CAP_CONTROL; + +typedef enum _IOD_READ_PREFETCH_TYPE{ + IodPrefetchShort = 0x00, + IodPrefetchMedium = 0x01, + IodPrefetchLong = 0x02, + IodPrefetchReserved = 0x03 +} IOD_READ_PREFETCH_TYPE, *PIOD_READ_PREFETCH_TYPE; + +typedef enum _IOD_PCI_ARB_MODE{ + IodArbBridgePriority = 0x00, + IodArbRoundRobin = 0x01, + IodArbModRoundRobin = 0x02, + IodArbReserved = 0x03 +} IOD_PCI_ARB_MODE, *PIOD_PCI_ARB_MODE; + +typedef union _IOD_PERF_MON{ + struct{ + ULONG Counter: 24; // <23:0> + ULONG Reserved0: 8; // <31:24> sets HAE for sparse memory space + }; + ULONG all; +} IOD_PERF_MON, *PIOD_PERF_MON; + +typedef union _IOD_PERF_CON{ + struct{ + ULONG CntFrame: 1; // <0> 0 = count PCI Frame#, 1 = cnt TLB miss + ULONG Reserved0: 31; // <31:1> + }; + ULONG all; +} IOD_PERF_CON, *PIOD_PERF_CON; + +typedef enum _IOD_PERF_COUNTER_MODE{ + IodPerfMonPciFrame = 0x0, + IodPerfMonTlbMiss = 0x1 +} IOD_PERF_COUNTER_MODE, *PIOD_PERF_COUNTER_MODE; + +typedef union _IOD_HAE_MEM{ + struct{ + ULONG Reserved0: 26; // <25:0> + ULONG HaeMem: 6; // <31:26> sets HAE for sparse memory space + }; + ULONG all; +} IOD_HAE_MEM, *PIOD_HAE_MEM; + +typedef union _IOD_HAE_IO{ + struct{ + ULONG Reserved0: 25; // <24:0> + ULONG HaeIo: 7; // <31:25> sets HAE for sparse i/o space + }; + ULONG all; +} IOD_HAE_IO, *PIOD_HAE_IO; + +typedef union _IOD_IACK_SC{ + struct{ + ULONG Message: 16; // <15:0> Encoded Message + ULONG MessageEx: 16; // <31:16> Message Dependent + }; + ULONG all; +} IOD_IACK_SC, *PIOD_IACK_SC; + +// +// Define the structures and definitions for the IOD interrupt registers. +// + +typedef struct _IOD_INT_CSRS{ + UCHAR IntCtrl; // (500) Interrupt Control + UCHAR Filler1; // (520) + UCHAR IntReq; // (540) Interrupt Request + UCHAR Filler2; // (560) + UCHAR IntTarg; // (580) Interrupt Target Devices + UCHAR Filler3; // (5a0) + UCHAR IntAddr; // (5c0) Interrupt Target Address + UCHAR Filler4; // (5e0) + UCHAR IntAddrExt; // (600) Interrupt Target Address Extension + UCHAR Filler5; // (620) + UCHAR IntMask0; // (640) Interrupt Mask 0 + UCHAR Filler6; // (660) + UCHAR IntMask1; // (680) Interrupt Mask 1 + UCHAR Filler7[0x8001c3]; // (6a0 - 10003ea0) + UCHAR IntAck0; // (10003f00) Interrupt Target 0 Acknowledge + UCHAR Filler8; // (10003f20) + UCHAR IntAck1; // (10003f40) Interrupt Target 1 Acknowledge +} IOD_INT_CSRS, *PIOD_INT_CSRS; + +// +// 16 PCI vectors per IOD +// + +#define IOD_PCI_VECTORS 0x10 + +typedef union _IOD_INT_CONTROL{ + struct{ + ULONG EnInt: 1; // <0> Enable MC Bus IO interrupt transactions + ULONG EnIntNum: 1; // <1> Enable MC Bus interrupt number write + ULONG Reserved: 4; // <31:2> + }; + ULONG all; +} IOD_INT_CONTROL, *PIOD_INT_CONTROL; + +#define IOD_INT_CTL_ENABLE_IO_INT 0x1 +#define IOD_INT_CTL_DISABLE_IO_INT 0x0 +#define IOD_INT_CTL_ENABLE_VECT_WRITE 0x2 +#define IOD_INT_CTL_DISABLE_VECT_WRITE 0x0 + + +typedef union _IOD_INT_REQUEST{ + struct{ + ULONG IntReq: 22; // <21:0> Interrupt State + ULONG SoftErr: 1; // <22> Soft (correctable) error interrupt + ULONG HardErr: 1; // <23> Hard error interrupt + ULONG Reserved: 8; // <31:24> + }; + ULONG all; +} IOD_INT_REQUEST, *PIOD_INT_REQUEST; + +typedef union _IOD_INT_TARGET_DEVICE{ + struct{ + ULONG Int0TargDevId: 6; // <5:0> Interrupt Target 0 McDevid + ULONG Int1TargDevId: 6; // <11:6> Interrupt Target 1 McDevid + ULONG Reserved: 20; // <31:12> MBZ + }; + ULONG all; +} IOD_INT_TARGET_DEVICE, *PIOD_INT_TARGET_DEVICE; + +#define IOD_MAX_INT_TARG 2 + +typedef union _IOD_INT_ADDR{ + struct{ + ULONG Reserved1: 2; // <1:0> MBZ + ULONG PciOffset: 4; // <5:2> PCI Offset + ULONG Reserved2: 6; // <11:6> MBZ + ULONG IntAddrLo: 20; // <31:12> Page address of interrupt target + }; + ULONG all; +} IOD_INT_ADDR, *PIOD_INT_ADDR; + +typedef union _IOD_INT_ADDR_EXT{ + struct{ + ULONG IntAddrExt: 7; // <6:0> Upper bits of interrupt target address + ULONG Reserved: 25; // <31:7> MBZ + }; + ULONG all; +} IOD_INT_ADDR_EXT, *PIOD_INT_ADDR_EXT; + + +// +// IOD_INT_MASK applies to IntMask0 and IntMask1 +// + +typedef union _IOD_INT_MASK{ + struct{ + ULONG IntMask: 24; // <23:0> Interrupt Mask + ULONG Reserved: 8; // <31:24> + }; + struct{ + ULONG IntA0: 1; // <0> PCI Slot 0 + ULONG IntB0: 1; + ULONG IntC0: 1; + ULONG IntD0: 1; + ULONG IntA1: 1; // <4> PCI Slot 1 + ULONG IntB1: 1; + ULONG IntC1: 1; + ULONG IntD1: 1; + ULONG IntA2: 1; // <8> PCI Slot 2 + ULONG IntB2: 1; + ULONG IntC2: 1; + ULONG IntD2: 1; + ULONG IntA3: 1; // <12> PCI Slot 3 + ULONG IntB3: 1; + ULONG IntC3: 1; + ULONG IntD3: 1; + ULONG EisaInt: 1; // <16> 8259 Eisa IRQ's (PCI 0), NCR810 SCSI (PCI 1) + ULONG I2cCtrl: 1; // <17> 8254 I2C Controller (PCI 0 Only) + ULONG I2cBus: 1; // <18> 8254 I2C Bus: Pwr, Fan, etc. (PCI 0 Only) + ULONG Reserved0: 2; // <20:19> + ULONG Nmi: 1; // <21> 8259 Eisa NMI + ULONG SoftErr: 1; // <22> Soft Error from CAP Chip + ULONG HardErr: 1; // <23> Hard Error from CAP Chip + ULONG Reserved1 :8; // <31:24> + }; + ULONG all; +} IOD_INT_MASK, *PIOD_INT_MASK; + +typedef enum _IOD_MASK_DEFS{ + IodPci0IntMask = (1 << 0), + IodPci1IntMask = (1 << 1), + IodPci2IntMask = (1 << 2), + IodPci3IntMask = (1 << 3), + IodPci4IntMask = (1 << 4), + IodPci5IntMask = (1 << 5), + IodPci6IntMask = (1 << 6), + IodPci7IntMask = (1 << 7), + IodPci8IntMask = (1 << 8), + IodPci9IntMask = (1 << 9), + IodPci10IntMask = (1 << 10), + IodPci11IntMask = (1 << 11), + IodPci12IntMask = (1 << 12), + IodPci13IntMask = (1 << 13), + IodPci14IntMask = (1 << 14), + IodPci15IntMask = (1 << 15), + IodEisaIntMask = (1 << 16), + IodScsiIntMask = (1 << 16), + IodI2cCtrlIntMask = (1 << 17), + IodI2cBusIntMask = (1 << 18), + IodEisaNmiIntMask = (1 << 21), + IodSoftErrIntMask = (1 << 22), + IodHardErrIntMask = (1 << 23), + + IodIntMask = 0x03ffffff, + IodPciIntMask = 0x0000ffff, + IodIntDisableMask = 0x00000000, + +} IOD_MASK_DEFS, *PIOD_MASK_DEFS; + + +// +// IOD_INT_ACK applies to IntAck0 and IntAck1 +// + +typedef union _IOD_INT_ACK{ + struct{ + ULONG Reserved: 32; // <31:0> Reserved + }; + ULONG all; +} IOD_INT_ACK, *PIOD_INT_ACK; + + + +// +// Define the structures and definitions for the IOD diagnostic registers. +// + +typedef struct _IOD_DIAG_CSRS{ + UCHAR CapDiag; // (700) CAP Diagnostic Control register + UCHAR Filler1; // (720) + UCHAR Scratch; // (740) General Purpose Scratch register + UCHAR Filler2; // (760) + UCHAR ScratchAlias; // (780) General Purpose Scratch register alias + UCHAR Filler3; // (7a0) + UCHAR TopOfMem; // (7c0) Top of Memory +} IOD_DIAG_CSRS, *PIOD_DIAG_CSRS; + +typedef union _IOD_CAP_DIAG { + struct{ + ULONG PciReset: 1; // <0> Reset PCI (must be cleared with 100 us) + ULONG Reserved0: 30; // <29:1> + ULONG ForceMcAddrPe: 1; // <30> Force bad parity to MC bus (one-shot) + ULONG ForcePciAddrPe: 1;// <31> Force bad parity to PCI bus (one-shot) + }; + ULONG all; +} IOD_CAP_DIAG, *PIOD_CAP_DIAG; + + +// +// Define the structures and definitions for the IOD error symptom registers. +// + +typedef struct _IOD_ERROR_CSRS{ + UCHAR McErr0; // (800) MC Error Information Register 0 + UCHAR Filler0; // (820) + UCHAR McErr1; // (840) MC Error Information Register 1 + UCHAR Filler1; // (860) + UCHAR CapErr; // (880) CAP Error Register + UCHAR Filler2[61]; // (8a0-1020) + UCHAR PciErr1; // (1040) PCI error - failing address + UCHAR Filler3[381]; // (1060-3fe0) + UCHAR MdpaStat; // (4000) MDPA Status Register + UCHAR Filler4; // (4020) + UCHAR MdpaSyn; // (4040) MDPA Error Syndrome register + UCHAR Filler5; // (4060) + UCHAR MdpaDiag; // (4080) MDPA Diagnostic Check Register + UCHAR Filler6[507]; // (40a0-7fe0) + UCHAR MdpbStat; // (8000) MDPB Status Register + UCHAR Filler7; // (8020) + UCHAR MdpbSyn; // (8040) MDPB Error Syndrome register + UCHAR Filler8; // (8060) + UCHAR MdpbDiag; // (8080) MDPB Diagnostic Check Register +} IOD_ERROR_CSRS, *PIOD_ERROR_CSRS; + +typedef union _IOD_MC_ERR0{ + struct{ + ULONG Addr: 32; // <31:0> address bits 31-4 of current MC bus error + }; + ULONG all; +} IOD_MC_ERR0, *PIOD_MC_ERR0; + +typedef union _IOD_MC_ERR1{ + struct{ + ULONG Addr39_32: 8; // <7:0> address bits 39-32 of current MC bus error + ULONG McCmd: 6; // <13:8> MC Bus command active at time of error + ULONG DevId: 6; // <19:14> Gid,Mid of bus master at time of error + ULONG Dirty: 1; // <20> Set if MC Bus Read/Dirty transaction + ULONG Reserved0: 10; // <30:21> + ULONG Valid: 1; // <31> OR of CAP_ERR<30:23), McErr0 and McErr1 valid + }; + ULONG all; +} IOD_MC_ERR1, *PIOD_MC_ERR1; + +typedef union _IOD_CAP_ERR{ + struct{ + ULONG Perr: 1; // <0> PCI bus PERR# observed by bridge + ULONG Serr: 1; // <1> PCI bus SERR# observed by bridge + ULONG Mab: 1; // <2> PCI target abort observed by bridge + ULONG PteInv: 1; // <3> Invalid Pte + + ULONG PciErrValid: 1; // <4> (RO) PCI Error Valid - Logical OR of <3:0> + ULONG Reserved0: 18; // <22:5> + ULONG PioOvfl: 1; // <23> CAP buffer full, transaction lost + + ULONG LostMcErr: 1; // <24> Lost uncorrectable MC error + ULONG McAddrPerr: 1; // <25> MC Bus command/address parity error + ULONG Nxm: 1; // <26> Nonexistent MC Bus address error + ULONG CrdA: 1; // <27> Correctable ECC error detected by MDPA + + ULONG CrdB: 1; // <28> Correctable ECC error detected by MDPB + ULONG RdsA: 1; // <29> Uncorrectable ECC error detected by MDPA + ULONG RdsB: 1; // <30> Uncorrectable ECC error detected by MDPB + ULONG McErrValid: 1; // <31> (RO) MC Error Valid - Logical OR of <30:23> + }; + ULONG all; +} IOD_CAP_ERR, *PIOD_CAP_ERR; + +typedef struct _IOD_PCI_ERR1{ + ULONG PciAddress; // (RO) <31:0> PCI Address +} IOD_PCI_ERR1, *PIOD_PCI_ERR1; + +typedef union _IOD_MDPA_STAT{ + struct{ + ULONG MdpaRev: 4; // <3:0> MDP chip revision level + ULONG Reserved: 26; // <29:4> + ULONG Crd: 1; // <30> MdpaSyn contains correctable error syndrome + ULONG Rds: 1; // <31> MdpaSyn contains uncorrectable error syndrome + }; + ULONG all; +} IOD_MDPA_STAT, *PIOD_MDPA_STAT; + +typedef union _IOD_MDPB_STAT{ + struct{ + ULONG MdpbRev: 4; // <3:0> MDP chip revision level + ULONG Reserved: 26; // <29:4> + ULONG Crd: 1; // <30> MdpaSyn contains correctable error syndrome + ULONG Rds: 1; // <31> MdpaSyn contains uncorrectable error syndrome + }; + ULONG all; +} IOD_MDPB_STAT, *PIOD_MDPB_STAT; + +typedef union _IOD_MDPA_SYN{ + struct{ + ULONG EccSyndrome0: 8; // <8:0> Cycle 0 ECC Syndrome + ULONG EccSyndrome1: 8; // <15:9> Cycle 1 ECC Syndrome + ULONG EccSyndrome2: 8; // <23:16> Cycle 2 ECC Syndrome + ULONG EccSyndrome3: 8; // <31:24> Cycle 3 ECC Syndrome + }; + ULONG all; +} IOD_MDPA_SYN, *PIOD_MDPA_SYN; + +typedef union _IOD_MDPB_SYN{ + struct{ + ULONG EccSyndrome0: 8; // <8:0> Cycle 0 ECC Syndrome + ULONG EccSyndrome1: 8; // <15:9> Cycle 1 ECC Syndrome + ULONG EccSyndrome2: 8; // <23:16> Cycle 2 ECC Syndrome + ULONG EccSyndrome3: 8; // <31:24> Cycle 3 ECC Syndrome + }; + ULONG all; +} IOD_MDPB_SYN, *PIOD_MDPB_SYN; + +typedef union _IOD_MDPA_DIAG{ + struct{ + ULONG DiagCheck: 8; // <7:0> Data for ECC in diag DMA writes + ULONG Reserved: 20; // <27:8> + ULONG EccCkEn: 1; // <28> Enable ECC check + ULONG ParCkEn: 1; // <29> Enable PCI data parity check + ULONG FpePciLo: 1; // <30> Force bad PCI parity on low 32 bits of data + ULONG UseDiagCheck: 1; // <31> DMA write cycles to mem use DiagCheck as ECC + }; + ULONG all; +} IOD_MDPA_DIAG, *PIOD_MDPA_DIAG; + +typedef union _IOD_MDPB_DIAG{ + struct{ + ULONG DiagCheck: 8; // <7:0> Data for ECC in diag DMA writes + ULONG Reserved: 20; // <27:8> + ULONG EccCkEn: 1; // <28> Enable ECC check + ULONG ParCkEn: 1; // <29> Enable PCI data parity check + ULONG FpePciHi: 1; // <30> Force bad PCI parity on high 32 bits of data + ULONG UseDiagCheck: 1; // <31> DMA write cycles to mem use DiagCheck as ECC + }; + ULONG all; +} IOD_MDPB_DIAG, *PIOD_MDPB_DIAG; + +// +// Define I/O CSRs specific to the Rawhide IOD +// + +#if 0 +typedef union _IOD_ELCR1{ + struct{ + ULONG From0Rdy: 1; // <0> (RO) Primary flash ROM ready to accept cmds + ULONG From1Rdy: 1; // <1> (RO) Secondary flash ROM ready to accept cmds + ULONG FsafeWrProt: 1; // <2> (RO) Fail Safe Write Protect (if set) + ULONG AvpPresent: 1; // <3> (RO) Programming jumper inserted (if set) + ULONG From1Sel: 1; // <4> Selects secondary flash ROM + ULONG FromAddr: 3; // <7:5> Selects 64Kb flash ROM range + }; + ULONG all; +} IOD_ELCR1, *PIOD_ELCR1; +#else +typedef union _IOD_ELCR1{ + struct{ + ULONG From0Rdy: 1; // <0> (RO) Primary flash ROM ready to accept cmds + ULONG From1Rdy: 1; // <1> (RO) Secondary flash ROM ready to accept cmds + ULONG AvpPresent: 1; // <2> (RO) Programming jumper inserted (if set) + ULONG FromSel: 1; // <3> (RW) Selects secondary flash ROM + ULONG FromAddr: 4; // <7:4> (RW) Selects 64Kb flash ROM range + }; + ULONG all; +} IOD_ELCR1, *PIOD_ELCR1; +#endif + +typedef union _IOD_ELCR2{ + struct{ + ULONG SfwResetReq: 1; // <0> (WO) System-wide reset to Power Control Module + ULONG SfwReset: 1; // <1> (RO) Most recent reset was via SfwResetReq + ULONG CapReset: 1; // <2> (RO) Most recent reset was from CAP chip + ULONG OcpReset: 1; // <3> (RO) Most recent reset was via OCP reset swtch + ULONG RsmReset: 1; // <4> (RO) Most recent reset was via RSM module + ULONG Reserved0: 3; // <7:5> + }; + ULONG all; +} IOD_ELCR2, *PIOD_ELCR2; + + +// +// Define structures and definitions for Scatter/Gather control registers: +// + +typedef struct _IOD_SG_CSRS{ + UCHAR Tbia; // (1300) Translation buffer invalidate all + UCHAR Filler; // (1320) + UCHAR Hbase; // (1340) PC Hole Compatibility Register + UCHAR Filler0[5]; // (1360-13e0) + UCHAR W0base; // (1400) Base address, DMA window 0 + UCHAR Filler1; // (1420) + UCHAR W0mask; // (1440) Mask Register, DMA window 0 + UCHAR Filler2; // (1460) + UCHAR T0base; // (1480) Translation Base, DMA window 0 + UCHAR Filler3[3]; // (14a0 - 14e0) + UCHAR W1base; // (1500) Base address, DMA window 1 + UCHAR Filler4; // (1520) + UCHAR W1mask; // (1540) Mask Register, DMA window 1 + UCHAR Filler5; // (1560) + UCHAR T1base; // (1580) Translation Base, DMA window 1 + UCHAR Filler6[3]; // (15a0 - 15e0) + UCHAR W2base; // (1600) Base address, DMA window 2 + UCHAR Filler7; // (1620) + UCHAR W2mask; // (1640) Mask Register, DMA window 2 + UCHAR Filler8; // (1660) + UCHAR T2base; // (1680) Translation Base, DMA window 2 + UCHAR Filler9[3]; // (16a0 - 16e0) + UCHAR W3base; // (1700) Base address, DMA window 3 + UCHAR Filler10; // (1720) + UCHAR W3mask; // (1740) Mask Register, DMA window 3 + UCHAR Filler11; // (1760) + UCHAR T3base; // (1780) Translation Base, DMA window 3 + UCHAR Filler12; // (17a0) + UCHAR Wdac; // (17c0) Window DAC Base + UCHAR Filler13; // (17e0) + UCHAR TbTag0; // (1800) Translation Buffer Tag 0 + UCHAR Filler14; // (1820) + UCHAR TbTag1; // (1840) Translation Buffer Tag 1 + UCHAR Filler15; // (1860) + UCHAR TbTag2; // (1880) Translation Buffer Tag 2 + UCHAR Filler16; // (18a0) + UCHAR TbTag3; // (18c0) Translation Buffer Tag 3 + UCHAR Filler17; // (18e0) + UCHAR TbTag4; // (1900) Translation Buffer Tag 4 + UCHAR Filler18; // (1920) + UCHAR TbTag5; // (1940) Translation Buffer Tag 5 + UCHAR Filler19; // (1960) + UCHAR TbTag6; // (1980) Translation Buffer Tag 6 + UCHAR Filler20; // (19a0) + UCHAR TbTag7; // (19c0) Translation Buffer Tag 7 + UCHAR Filler21; // (19e0) + UCHAR Tb0Page0; // (2000) Translation Buffer 0 Page 0 + UCHAR Filler22; // (2020) + UCHAR Tb0Page1; // (2040) Translation Buffer 0 Page 1 + UCHAR Filler23; // (2060) + UCHAR Tb0Page2; // (2080) Translation Buffer 0 Page 2 + UCHAR Filler24; // (20a0) + UCHAR Tb0Page3; // (20c0) Translation Buffer 0 Page 3 + UCHAR Filler25; // (20e0) + UCHAR Tb1Page0; // (2100) Translation Buffer 1 Page 0 + UCHAR Filler26; // (2120) + UCHAR Tb1Page1; // (2140) Translation Buffer 1 Page 1 + UCHAR Filler27; // (2160) + UCHAR Tb1Page2; // (2180) Translation Buffer 1 Page 2 + UCHAR Filler28; // (21a0) + UCHAR Tb1Page3; // (21c0) Translation Buffer 1 Page 3 + UCHAR Filler29; // (21e0) + UCHAR Tb2Page0; // (2200) Translation Buffer 2 Page 0 + UCHAR Filler30; // (2220) + UCHAR Tb2Page1; // (2240) Translation Buffer 2 Page 1 + UCHAR Filler31; // (2260) + UCHAR Tb2Page2; // (2280) Translation Buffer 2 Page 2 + UCHAR Filler32; // (22a0) + UCHAR Tb2Page3; // (22c0) Translation Buffer 2 Page 3 + UCHAR Filler33; // (22e0) + UCHAR Tb3Page0; // (2300) Translation Buffer 3 Page 0 + UCHAR Filler34; // (2320) + UCHAR Tb3Page1; // (2340) Translation Buffer 3 Page 1 + UCHAR Filler35; // (2360) + UCHAR Tb3Page2; // (2380) Translation Buffer 3 Page 2 + UCHAR Filler36; // (23a0) + UCHAR Tb3Page3; // (23c0) Translation Buffer 3 Page 3 + UCHAR Filler37; // (23e0) + UCHAR Tb4Page0; // (2400) Translation Buffer 4 Page 0 + UCHAR Filler38; // (2420) + UCHAR Tb4Page1; // (2440) Translation Buffer 4 Page 1 + UCHAR Filler39; // (2460) + UCHAR Tb4Page2; // (2480) Translation Buffer 4 Page 2 + UCHAR Filler40; // (24a0) + UCHAR Tb4Page3; // (24c0) Translation Buffer 4 Page 3 + UCHAR Filler41; // (24e0) + UCHAR Tb5Page0; // (2500) Translation Buffer 5 Page 0 + UCHAR Filler42; // (2520) + UCHAR Tb5Page1; // (2540) Translation Buffer 5 Page 1 + UCHAR Filler43; // (2560) + UCHAR Tb5Page2; // (2580) Translation Buffer 5 Page 2 + UCHAR Filler44; // (25a0) + UCHAR Tb5Page3; // (25c0) Translation Buffer 5 Page 3 + UCHAR Filler45; // (25e0) + UCHAR Tb6Page0; // (2600) Translation Buffer 6 Page 0 + UCHAR Filler46; // (2620) + UCHAR Tb6Page1; // (2640) Translation Buffer 6 Page 1 + UCHAR Filler47; // (2660) + UCHAR Tb6Page2; // (2680) Translation Buffer 6 Page 2 + UCHAR Filler48; // (26a0) + UCHAR Tb6Page3; // (26c0) Translation Buffer 6 Page 3 + UCHAR Filler49; // (26e0) + UCHAR Tb7Page0; // (2700) Translation Buffer 7 Page 0 + UCHAR Filler50; // (2720 + UCHAR Tb7Page1; // (2740) Translation Buffer 7 Page 1 + UCHAR Filler51; // (2760) + UCHAR Tb7Page2; // (2780) Translation Buffer 7 Page 2 + UCHAR Filler52; // (27a0) + UCHAR Tb7Page3; // (27c0) Translation Buffer 7 Page 3 + +} IOD_SG_CSRS, *PIOD_SG_CSRS; + + +typedef union _IOD_TBIA{ + struct{ + ULONG Reserved0: 32; // <31:0> Don't care + }; + ULONG all; +} IOD_TBIA, *PIOD_TBIA; + +typedef union _IOD_HBASE{ + struct{ + ULONG Hbound: 9; // <8:0> PC compatibility hole upper bound + ULONG Reserved0: 4; // <12:9> + ULONG PcHe1: 1; // <13> Fixed hole (512 Kb - 1 Mb) enable + ULONG PcHe2: 1; // <14> Moveable hole (Hbase - Hbound) enable + ULONG Hbase: 9; // <23:15> PC compatibility hole lower bound + ULONG Reserved1: 8; // <31:24> + }; + ULONG all; +} IOD_HBASE, *PIOD_HBASE; + +typedef union _IOD_WBASE{ + struct{ + ULONG Wen: 1; // <0> Window enable + ULONG SgEn: 1; // <1> Scatter Gather enable + ULONG Reserved: 1; // <2> + ULONG DacEn: 1; // <3> DAC Enable (W3base only) + ULONG Reserved0: 16; // <19:4> + ULONG Wbase: 12; // <31:20> Base address of DMA window, bits <31:20> + }; + ULONG all; +} IOD_WBASE, *PIOD_WBASE; + +typedef union _IOD_WMASK{ + struct{ + ULONG Reserved0: 20; // <19:0> + ULONG Wmask: 12; // <31:20> Window mask + }; + ULONG all; +} IOD_WMASK, *PIOD_WMASK; + +typedef union _IOD_TBASE{ + struct{ + ULONG Reserved0: 2; // <1:0> + ULONG Tbase: 30; // <31:2> Translation base address, bits <39:10> + }; + ULONG all; +} IOD_TBASE, *PIOD_TBASE; + +typedef union _IOD_WDAC{ + struct{ + ULONG Wdac: 8; // <7:0> Bbase addr of DAC DMA window 3, bits <39:32> + ULONG Reserved0: 24; // <31:8> + }; + ULONG all; +} IOD_WDAC, *PIOD_WDAC; + +typedef union _IOD_TB_TAG{ + struct{ + ULONG Valid: 1; // <0> SG TB tag is valid + ULONG Reserved0: 1; // <1> + ULONG Dac: 1; // <2> SG TB tag corresponds to a 64-bit (DAC) addr + ULONG Reserved1: 12; // <14:3> + ULONG TbTag: 17; // <31:15> SG TB tag itself + }; + ULONG all; +} IOD_TB_TAG, *PIOD_TB_TAG; + +typedef union _IOD_TB_PAGE{ + struct{ + ULONG Valid: 1; // <0> SG Page address is valid + ULONG PageAddr: 27; // <27:1> SG TB Page address + ULONG Reserved1: 12; // <31:28> + }; + ULONG all; +} IOD_TB_PAGE, *PIOD_TB_PAGE; + + +// +// DMA Window Values. +// +// The IOD will be initialized to allow 2 DMA windows. +// The first window will be for the use of of ISA devices and DMA slaves +// and therefore must have logical addresses below 16MB. +// The second window will be for bus masters (non-ISA) and so may be +// above 16MB. +// +// The arrangement of the windows will be as follows: +// +// Window Logical Start Address Window Size +// ------ --------------------- ----------- +// Isa 8MB 8MB +// Master 16MB 16MB +// + +#define ISA_DMA_WINDOW_BASE (__8MB) +#define ISA_DMA_WINDOW_SIZE (__8MB) + +#define MASTER_DMA_WINDOW_BASE (__16MB) +#define MASTER_DMA_WINDOW_SIZE (__16MB) + +// +// Define the software control registers for a DMA window. +// + +typedef struct _WINDOW_CONTROL_REGISTERS{ + PVOID WindowBase; + ULONG WindowSize; + PVOID TranslatedBaseRegister; + PVOID WindowBaseRegister; + PVOID WindowMaskRegister; + PVOID WindowTbiaRegister; +} WINDOW_CONTROL_REGISTERS, *PWINDOW_CONTROL_REGISTERS; + +// +// Define types of windows. +// + +typedef enum _IOD_WINDOW_NUMBER{ + IodIsaWindow, + IodMasterWindow +} IOD_WINDOW_NUMBER, *PIOD_WINDOW_NUMBER; + +// +// Define IOD Window Control routines. +// + +VOID +HalpIodInitializeSfwWindow( + PWINDOW_CONTROL_REGISTERS WindowRegisters, + IOD_WINDOW_NUMBER WindowNumber + ); + +VOID +HalpIodProgramDmaWindow( + PWINDOW_CONTROL_REGISTERS WindowRegisters, + PVOID MapRegisterBase + ); + +VOID +HalpIodInvalidateTlb( + PWINDOW_CONTROL_REGISTERS WindowRegisters + ); + +PKPCR +HalpRdPcr( + VOID + ); + +// +// Define IOD CSR Routines +// + +VOID +WRITE_IOD_REGISTER( + PVOID, + ULONG + ); + +ULONG +READ_IOD_REGISTER( + PVOID + ); + +VOID +WRITE_IOD_REGISTER_NEW( + MC_DEVICE_ID, + PVOID, + ULONG + ); + +ULONG +READ_IOD_REGISTER_NEW( + MC_DEVICE_ID, + PVOID + ); + +// +// Define IOD interrupt request/acknowledge routines +// + +ULONG +INTERRUPT_ACKNOWLEDGE( + PVOID + ); + +VOID +IOD_INTERRUPT_ACKNOWLEDGE( + MC_DEVICE_ID McDeviceId, + ULONG Target + ); + +VOID +CPU_CLOCK_ACKNOWLEDGE( + MC_DEVICE_ID McDeviceId + ); + +VOID +IP_INTERRUPT_REQUEST( + MC_DEVICE_ID McDeviceId + ); + +VOID +IP_INTERRUPT_ACKNOWLEDGE( + MC_DEVICE_ID McDeviceId + ); + +// +// Define MC Bus emumerator routines +// + + +ULONG +HalpMcBusEnumStart( + MC_DEVICE_MASK McDeviceMask, + PMC_ENUM_CONTEXT McContext + ); + +BOOLEAN +HalpMcBusEnum( + PMC_ENUM_CONTEXT McContext + ); + +VOID +HalpMcBusEnumAndCall( + MC_DEVICE_MASK McDeviceMask, + PMC_ENUM_ROUTINE McBusEnumRoutine, + ... + ); + +// +// Define other IOD routines +// + +ULONG +HalpReadWhoAmI( + VOID + ); + +VOID +HalpInitializeIodVectorTable( + VOID + ); + +VOID +HalpInitializeIodMappingTable( + MC_DEVICE_ID McDeviceId, + ULONG PciBusNumber, + va_list Arguments + ); + +BOOLEAN +HalpIodUncorrectableError( + PMC_DEVICE_ID pMcDeviceId + ); + +VOID +HalpIodReportFatalError( + MC_DEVICE_ID McDevid + ); + +BOOLEAN +HalpIodMachineCheck( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN PKTRAP_FRAME TrapFrame + ); + +VOID +HalpInitializeIod( + MC_DEVICE_ID McDeviceId, + ULONG PciBusNumber, + va_list Arguments + ); + +VOID +HalpInitializeIodVectorCSRs( + MC_DEVICE_ID McDeviceId, + ULONG PciBusNumber, + va_list Arguments + ); + +VOID +HalpInitializeIodMachineChecks( + IN BOOLEAN ReportCorrectableErrors, + IN BOOLEAN PciParityChecking + ); + +VOID +HalpIodSoftErrorInterrupt( + VOID + ); + +VOID +HalpIodHardErrorInterrupt( + VOID + ); + +VOID +HalpClearAllIods( + IOD_CAP_ERR IodCapErrMask +); + +#define ALL_CAP_ERRORS 0xffffffff + + +#if HALDBG || defined(DUMPIODS) + +VOID +DumpIod( + MC_DEVICE_ID DevId, + IOD_REGISTER_CLASS RegistersToDump + ); + +VOID +DumpAllIods( + IOD_REGISTER_CLASS RegistersToDump + ); + +#endif //HALDBG + + +// +// VOID +// INITIALIZE_ISA_DMA_CONTROL( +// PWINDOW_CONTROL_REGISTERS WindowRegisters +// ) +// +// Routine Description: +// +// Initialize the DMA Control software window registers for the ISA +// DMA window. +// +// Arguments: +// +// WindowRegisters - Supplies a pointer to the software window control. +// +// Return Value: +// +// None. +// + +#define INITIALIZE_ISA_DMA_CONTROL( WR ) \ + HalpIodInitializeSfwWindow( (WR), IodIsaWindow ); + + +// +// VOID +// INITIALIZE_MASTER_DMA_CONTROL( +// PWINDOW_CONTROL_REGISTERS WindowRegisters +// ) +// +// Routine Description: +// +// Initialize the DMA Control software window registers for the PCI +// DMA window. +// +// Arguments: +// +// WindowRegisters - Supplies a pointer to the software window control. +// +// Return Value: +// +// None. +// + +#define INITIALIZE_MASTER_DMA_CONTROL( WR ) \ + HalpIodInitializeSfwWindow( (WR), IodMasterWindow ); + + +// +// VOID +// INITIALIZE_DMA_WINDOW( +// PWINDOW_CONTROL_REGISTERS WindowRegisters, +// PTRANSLATION_ENTRY MapRegisterBase +// ) +// +// Routine Description: +// +// Program the control windows 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. +// + +#define INITIALIZE_DMA_WINDOW( WR, MRB ) \ + HalpIodProgramDmaWindow( (WR), (MRB) ); + + +// +// VOID +// INVALIDATE_DMA_TRANSLATIONS( +// PWINDOW_CONTROL_REGISTERS WindowRegisters +// ) +// +// Routine Description: +// +// Invalidate all of the cached translations for a DMA window. +// +// +// Arguments: +// +// WindowRegisters - Supplies a pointer to the software window control +// registers. +// +// Return Value: +// +// None. +// + +#define INVALIDATE_DMA_TRANSLATIONS( WR ) \ + HalpIodInvalidateTlb( (WR) ); + + +// +// Define the format of a translation entry aka a scatter/gather entry +// or map register. +// + +typedef struct _TRANSLATION_ENTRY{ + ULONG Valid: 1; + ULONG Pfn: 31; + ULONG Reserved; +} TRANSLATION_ENTRY, *PTRANSLATION_ENTRY; + + + +// +// VOID +// HAL_MAKE_VALID_TRANSLATION( +// PTRANSLATION_ENTRY Entry, +// ULONG PageFrameNumber +// ) +// +// Routine Description: +// +// Make the scatter/gather entry pointed to by Entry valid with +// a translation to the page indicated by PageFrameNumber. +// +// Arguments: +// +// Entry - Supplies a pointer to the translation entry to make valid. +// +// PageFrameNumber - Supplies the page frame of the valid translation. +// +// Return Value: +// +// None. +// + +#define HAL_MAKE_VALID_TRANSLATION( ENTRY, PFN ) \ + { \ + (ENTRY)->Valid = 1; \ + (ENTRY)->Pfn = PFN; \ + (ENTRY)->Reserved = 0; \ + } + + +// +// VOID +// HAL_INVALIDATE_TRANSLATION( +// PTRANSLATION_ENTRY Entry +// ) +// +// Routine Description: +// +// Invalidate the translation indicated by Entry. +// +// Arguments: +// +// Entry - Supplies a pointer to the translation to be invalidated. +// +// Return Value: +// +// None. +// + +#define HAL_INVALIDATE_TRANSLATION( ENTRY ) \ + (ENTRY)->Valid = 0; + +#endif //!_LANGUAGE_ASSEMBLY + +#endif //_IODH_ diff --git a/private/ntos/nthals/halraw/alpha/iodaddr.c b/private/ntos/nthals/halraw/alpha/iodaddr.c new file mode 100644 index 000000000..d0a2958f3 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/iodaddr.c @@ -0,0 +1,731 @@ +/*++ + +Copyright (c) 1993-1995 Digital Equipment Corporation + +Module Name: + + iodaddr.c + +Abstract: + + This module contains the platform dependent code to create bus addreses + and QVAs for the Rawhide system. + +Author: + + Eric Rehm 10-Apr-1995 + +Environment: + + Kernel mode + +Revision History: + + + +--*/ + +#include "halp.h" +#include "eisa.h" +#include "pci.h" +#include "pcip.h" + +typedef PVOID QUASI_VIRTUAL_ADDRESS; + +QUASI_VIRTUAL_ADDRESS +HalCreateQva( + IN PHYSICAL_ADDRESS PA, + IN PVOID VA + ); + + +BOOLEAN +HalpTranslateSystemBusAddress( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress + ) + +/*++ + +Routine Description: + + This function returns the system physical address for a specified I/O bus + address. The return value is suitable for use in a subsequent call to + MmMapIoSpace. + +Arguments: + + BusHandler - Registered BUSHANDLER for the target configuration space + Supplies the bus handler (bus no, interface type). + + RootHandler - Registered BUSHANDLER for the orginating + HalTranslateBusAddress request. + + BusAddress - Supplies the bus relative address. + + AddressSpace - Supplies the address space number for the device: 0 for + memory and 1 for I/O space. If the desired access mode is user mode, + then bit 1 must be TRUE. + + TranslatedAddress - Supplies a pointer to return the translated address + + +Notes: + + This is a variation of what began in the MIPS code. The intel code often + assumes that if an address is in I/O space, the bottom 32 bits of the + physical address can be used "like" a virtual address, and are returned + to the user. This doesn't work on Alpha and MIPS machines where physical + addresses can be larger than 32 bits. + + Since we are using superpage addresses for I/O on Alpha, we can do + almost what is done on intel. If AddressSpace is equal to 0 or 1, then + we assume the user is doing kernel I/O and we use the macro + HAL_MAKE_IOD_SPARSE_QVA to build a Quasi Virtual address and return + that to the caller. We then set AddressSpace to a 1, so that the caller + will not call MmMapIoSpace. The Caller will use the low 32 bits of the + physical address we return as the VA. (Which we built a QVA in). + + Note that KernelPciDenseMemory *is* mapped via MmMapIoSpace. + + If the caller wants to access EISA I/O or Memory through user mode, then + the caller must set bit 1 in AddressSpace to a 1 (AddressSpace=2 or 3, + depending on whether EISA I/O or Memory), then the caller is returned the + 40 bit Physical address. The caller will then call MmMapIoSpace, or + ZwMapViewOfSection which in turn calls HalCreateQva to build a QVA out + of a VA mapped through the page tables. + + **** Note **** + + The QVA in user mode can only be used via the user-mode access macros. + +Rawhide notes: + + QVA's on Rawhide encode a BusNumber and an offset on that bus, i.e., + the physical address is not directly coded in the QVA. The actual + superpage physical address is constructed at the time of access. + + Sparse QVA space from A000.0000 - C000.0000 is separate for I/O + and memory space. For example, sparse memory address 0 on BusNumber + 0 has QVA = A000.0000 and sparse I/O address 0 on BusNumber 0 also + has QVA = A000.0000. The user of a QVA must know what they're + doing, and properly call the correct access routine for the + address space that they desire. + + Finally, sparse and dense memory QVA's must coexist with the + same memory access routines (READ/WRITE_REGISTER_*). Since + Rawhide has 4 I/O buses, supporting 4 * 1 Gb dense spaces + + 4 * 128 Mb sparse spaces is not possible using a 32 bit QVA. + Therefore, we arbitrarily "short sheet" the dense address space + of BusNumber 2 to 512 Mb to make room for the sparse space QVAs. + +Return Value: + + A return value of TRUE indicates that a system physical address + corresponding to the supplied bus relative address and bus address + number has been returned in TranslatedAddress. + + A return value of FALSE occurs if the translation for the address was + not possible + +--*/ + +{ + INTERFACE_TYPE InterfaceType = BusHandler->InterfaceType; + ULONG BusNumber = BusHandler->BusNumber; + MC_DEVICE_ID McDeviceId; + PPCIPBUSDATA BusData; + ULONG HwBusNumber; + + + PVOID va = 0; // note, this is used for a placeholder + + // + // Check InterfaceType: + // The only buses available on Rawhide are an EISA bus and a PCI bus. + // We support any translations for EISA devices as well, though + // if they are true EISA devices they won't even be able to plug into + // the connectors! + // + + if ( (InterfaceType != Isa) && + (InterfaceType != Eisa) && + (InterfaceType != PCIBus) ) { + + // + // Not on this system return nothing. + // + +#if HALDBG + DbgPrint( "HalTBA: Unhandled interface type = %x\n", InterfaceType ); +#endif //HALDBG + + *AddressSpace = 0; + TranslatedAddress->LowPart = 0; + return(FALSE); + } + + // + // Next, generate the IOD number (HwBusNumber). + // + // If it's ISA or EISA, BusNumber and HwBusNumber = 0. + // If it's PCI, we get HwBusNumber from PCI-specific bus data. + // + + HwBusNumber = 0; // Isa, Eisa + if (InterfaceType == PCIBus ) { + + // + // Get a pointer to the PCIBus-specific data. + // + + BusData = (PPCIPBUSDATA)BusHandler->BusData; + + // + // In particular, what root PCI bus (IOD) are we on? + // + + HwBusNumber = BusData->HwBusNumber; + } + + // + // Build MC Bus device id for this bus using HwBusNumber. + // Currently, only the Primary Global Id (0x7) is supported. + // + + McDeviceId.all = 0; + McDeviceId.Gid = GidPrimary; + McDeviceId.Mid = MidPci0 + HwBusNumber; + + // + // Determine the address based on whether the bus address is in I/O space + // or bus memory space. + // + + switch ( (ADDRESS_SPACE_TYPE)(*AddressSpace) ) { + + case BusMemory: { + + // + // The address is in PCI memory space, kernel mode. + // + + switch( InterfaceType ) { + + case Isa: { + + // + // Can't go above 16MB (24 Bits) for Isa Buses + // + if( BusAddress.LowPart >= __16MB ){ + + *AddressSpace = 0; + TranslatedAddress->LowPart = 0; + return(FALSE); + + } + + break; + + } // case Isa + + case Eisa: + + // + // Eisa is the same as PCI, with respect to kernel mode + // sparse and dense space memory support, i.e., its a full 32 bit space, + // supports dense memory access. + // + + case PCIBus: { + + // + // Don't allow accesses to PCI/EISA addresses below + // 1 Mb on root buses other than PCI-0. + // +#if 1 // ecrfix - needed for WINT3.51 !!! + if ( BusAddress.LowPart < __1MB && + HwBusNumber > 0 ) { +#if HALDBG + DbgPrint ("Unsupported PCI-%d (ISA legacy) address %x:%x\n", + HwBusNumber, + BusAddress.HighPart, + BusAddress.LowPart); +#endif + *AddressSpace = 0; + TranslatedAddress->LowPart = 0; + return(FALSE); + + } +#endif + + // + // Check legal PCI bus address ranges + // + + if ( BusAddress.LowPart > PCI_MAX_DENSE_MEMORY_ADDRESS ) { + + // + // Unsupported dense PCI bus address. + // +#if HALDBG + DbgPrint ("Unsupported PCI address %x:%x\n", + BusAddress.HighPart, + BusAddress.LowPart); +#endif + *AddressSpace = 0; + TranslatedAddress->LowPart = 0; + return(FALSE); + } + else if( BusAddress.LowPart >= PCI_MIN_DENSE_MEMORY_ADDRESS && + BusAddress.LowPart <= PCI_MAX_DENSE_MEMORY_ADDRESS ) { + +#if HALDBG + DbgPrint ("Translating PCI kernel dense address %x:%x\n", + BusAddress.HighPart, + BusAddress.LowPart); +#endif + // + // Bus Address is in dense PCI memory space + // + + // + // QVA, as such, is simply PCI bus address offset + // from the base dense memory address for that bus. + // The bus number is encoded in bits <31:30>. + // + + TranslatedAddress->LowPart = (ULONG) + HAL_MAKE_IOD_DENSE_QVA(HwBusNumber, BusAddress.LowPart); + + // + // clear high longword for QVA + // + + TranslatedAddress->HighPart = 0; + + // + // dont let the user call MmMapIoSpace + // + + *AddressSpace = 1; + + return (TRUE); + + + } + + // + // Bus Address is in sparse PCI memory space + // + + +#if HALDBG + DbgPrint ("Translating PCI kernel sparse address %x:%x\n", + BusAddress.HighPart, + BusAddress.LowPart); +#endif + + break; + } // case PCIBus + + } // switch( InterfaceType ) + + // + // Now create the QVA from the HwBusNumber and BusAddress. + // + // Unlike many other Alpha platfroms, the QVA is *not* an + // encoding of the physical address. The full physical address + // will can be constructed at the time of the I/O access with the + // information encoded here in the QVA: HwBusNumber and BusAddress. + // (The bus number is encoded in bits <28:27> of the QVA.) + // + + TranslatedAddress->LowPart = (ULONG) + HAL_MAKE_IOD_SPARSE_QVA(HwBusNumber, BusAddress.LowPart); + + // + // clear high longword for QVA + // + + TranslatedAddress->HighPart = 0; + + // + // don't let the user call MmMapIoSpace + // + + *AddressSpace = 1; + + return(TRUE); + + } // case BusMemory + + case BusIo: { + + // + // The address is in PCI I/O space, kernel mode. + // + switch( InterfaceType ) { + + case Eisa: + + // + // Eisa is the same as ISA, with respect to kernel mode + // sparse I/O space support, i.e., it is a 16 bit sparse + // space. + // + + case Isa: { + // + // Can't go above 64KB (16 Bits) for Isa Buses + // + if( BusAddress.LowPart >= __64K ){ + + *AddressSpace = 0; + TranslatedAddress->LowPart = 0; + return(FALSE); + + } + break; + } // case Isa + + case PCIBus: { + + // + // PCI IO space is always below 32MB (25 Bits) BusAddress + // If the address cannot be mapped, just return FALSE. + // + + if( BusAddress.LowPart >= __32MB ){ + + *AddressSpace = 0; + TranslatedAddress->LowPart = 0; + return(FALSE); + + } + // + // if the BusAddress.LowPart is > 64K then we use the HAER2 + // register. + // + break; + } // case PCIBus + + } // switch( InterfaceType ) + + // + // Now create the QVA from the HwBusNumber and BusAddress. + // + // Unlike many other Alpha platfroms, the QVA is *not* an + // encoding of the physical address. The full physical address + // will can be constructed at the time of the I/O access with the + // information encoded here in the QVA: HwBusNumber and BusAddress. + // (The bus number is encoded in bits <28:27> of the QVA.) + // + + TranslatedAddress->LowPart = (ULONG) + HAL_MAKE_IOD_SPARSE_QVA(HwBusNumber, BusAddress.LowPart); + + // + // clear high longword for QVA + // + + TranslatedAddress->HighPart = 0; + + // + // don't let the user call MmMapIoSpace + // + + *AddressSpace = 1; + + + return(TRUE); + + } // case BusIo + + case UserBusMemory: { + + // + // The address is in PCI memory space, user mode. + // + + // + // Start with the base physical address and add the + // bus address by converting it to the physical address. + // + + TranslatedAddress->QuadPart = IOD_SPARSE_MEM_OFFSET; + TranslatedAddress->QuadPart |= MCDEVID_TO_PHYS_ADDR( McDeviceId.all ); + TranslatedAddress->QuadPart |= EV5_USER_IO_ADDRESS_SPACE; + TranslatedAddress->QuadPart += (((ULONGLONG)BusAddress.LowPart) << IO_BIT_SHIFT); + +#if HALDBG + DbgPrint ("Translating PCI user mem sparse address %x:%x to %x:%x\n", + BusAddress.HighPart, + BusAddress.LowPart, + TranslatedAddress->HighPart, + TranslatedAddress->LowPart); +#endif + + *AddressSpace = 0; // Let the user call MmMapIoSpace + + return(TRUE); + + } + + case UserBusIo: { + + // + // The address is in PCI I/O space, user mode. + // + + // + // Start with the base physical address and add the + // bus address by converting it to the physical address. + // + + TranslatedAddress->QuadPart = IOD_SPARSE_IO_OFFSET; + TranslatedAddress->QuadPart |= MCDEVID_TO_PHYS_ADDR( McDeviceId.all ); + TranslatedAddress->QuadPart |= EV5_USER_IO_ADDRESS_SPACE; + TranslatedAddress->QuadPart += (((ULONGLONG)BusAddress.LowPart) << IO_BIT_SHIFT); + +#if HALDBG + DbgPrint ("Translating PCI user I/O sparse address %x:%x to %x:%x\n", + BusAddress.HighPart, + BusAddress.LowPart, + TranslatedAddress->HighPart, + TranslatedAddress->LowPart); +#endif + + + *AddressSpace = 0; // Make sure user can call + // MmMapIoSpace. + + return(TRUE); + + } + + case KernelPciDenseMemory: + case UserPciDenseMemory: + { + + // + // The address is in PCI dense memory space, user mode. + // + + // + // Start with the base physical address and add the + // bus address by converting it to the physical address. + // + + TranslatedAddress->QuadPart = IOD_DENSE_MEM_OFFSET; + TranslatedAddress->QuadPart |= MCDEVID_TO_PHYS_ADDR( McDeviceId.all ); + TranslatedAddress->QuadPart |= EV5_USER_IO_ADDRESS_SPACE; + TranslatedAddress->QuadPart += BusAddress.LowPart; + + *AddressSpace = 0; // Let the user call MmMapIoSpace + +#if HALDBG + DbgPrint("HTBA: UserPciDenseMemory %x to %x;%x\n", + BusAddress.LowPart, + TranslatedAddress->HighPart, + TranslatedAddress->LowPart); +#endif // HALDBG + + return(TRUE); + + } + + default: { + + // + // Unsupported address space. + // + + *AddressSpace = 0; + TranslatedAddress->LowPart = 0; + return(FALSE); + + } + } + + +} + +PVOID +HalCreateQva( + IN PHYSICAL_ADDRESS PA, + IN PVOID VA + ) + +/*++ + +Routine Description: + + This function is only available to a caller constructing a QVA + as a result of a page table mapping via ZwMapViewOfSection or + MmMapIoSpace. + + N.B. HalTranslateBusAddress, or other HAL routines MUST NOT + CALL THIS ROUTINE. This is because on Rawhide, a kernel-mode + dense or sparse superpage QVA cannot be contructed without + knowledge of the BusNumber, which is not passed into this routine. + + If the input parameter VA is zero, then we assume the caller + was incorrectly attempting to create a super page and build + a QUASI virtual address, and results in an error. + + If the input parameter VA is non-zero, we assume the user has either + called MmMapIoSpace or ZwMapViewOfSection and will use the user mode + access macros. + + If the PA is not an I/O space address (PCI I/O, PCI Memory), + then return the VA as the QVA. + +Arguments: + + PA - the physical address generated by HalTranslateBusAddress + + VA - the virtual address returned by MmMapIoSpace + +Return Value: + + The returned value is a quasi virtual address in that it can be + added to and subtracted from, but it cannot be used to access the + bus directly. The top bits are set so that we can trap invalid + accesses in the memory management subsystem. All access should be + done through the Hal Access Routines in *ioacc.s if it was a superpage + kernel mode access. If it is usermode, then the user mode access + macros must be used. + +--*/ +{ + + PHYSICAL_ADDRESS PhysicalOffset; + PVOID qva; + + PhysicalOffset.QuadPart = PHYS_ADDR_TO_OFFSET( PA.QuadPart ); + +#if HALDBG + DbgPrint("HalCreateQva: PhysicalOffset = %x;%x\n", + PhysicalOffset.HighPart, + PhysicalOffset.LowPart); +#endif + + + if (VA == 0) { + + // + // Error - HalCreateQva should not be called to create + // a superpage QVA. + // + +#if HALDBG + + DbgPrint( "HalCreateQva: Should not be called to create a superpage QVA from %x:%x\n", PA.HighPart, PA.LowPart ); + DbgBreakPoint(); + +#endif //HALDBG + + return (VA); + + } else if( (PhysicalOffset.QuadPart >= IOD_DENSE_MEM_OFFSET) && + (PhysicalOffset.QuadPart <= (IOD_DENSE_MEM_OFFSET + + PCI_MAX_DENSE_MEMORY_ADDRESS)) ){ + + // + // Physical dense address, return VA. + // + +#if HALDBG + DbgPrint("HalCreateQva: User Mode Dense QVA = VA = %x\n", VA); +#endif + return(VA); + + } else { + + // + // The physical address is within one of the sparse I/O spaces. + // + + qva = (PVOID)((ULONG)VA >> IO_BIT_SHIFT); + + qva = (PVOID)((ULONG)qva | QVA_ENABLE); + +#if HALDBG + DbgPrint("HalCreateQva: User Mode Sparse QVA = %x\n", qva); +#endif + return(qva); + } +} + +PVOID +HalDereferenceQva( + PVOID Qva, + INTERFACE_TYPE InterfaceType, + ULONG BusNumber + ) +/*++ + +Routine Description: + + This function performs the inverse of the HalCreateQva for I/O addresses + that are memory-mapped (i.e. the quasi-virtual address was created from + a virtual address rather than a physical address). + +Arguments: + + Qva - Supplies the quasi-virtual address to be converted back to a + virtual address. + + InterfaceType - Supplies the interface type of the bus to which the + Qva pertains. + + BusNumber - Supplies the bus number of the bus to which the Qva pertains. + +Return Value: + + The Virtual Address from which the quasi-address was originally created + is returned. + +--*/ +{ + + + // + // For Sable we have three supported bus types: + // + // Isa + // Eisa + // PCIBus + // + + switch (InterfaceType ){ + + case Isa: + case Eisa: + case PCIBus: + + // + // Support dense space: check to see if it's really + // a sparse space QVA. + // + + if ( ((ULONG) Qva & QVA_SELECTORS) == QVA_ENABLE ) { + return( (PVOID)( (ULONG)Qva << IO_BIT_SHIFT ) ); + } else { + return (Qva); + } + break; + + default: + + return NULL; + + } + + +} + diff --git a/private/ntos/nthals/halraw/alpha/ioderr.c b/private/ntos/nthals/halraw/alpha/ioderr.c new file mode 100644 index 000000000..f0038b5e5 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/ioderr.c @@ -0,0 +1,2304 @@ +/*++ + +Copyright (c) 1995 Digital Equipment Corporation + +Module Name: + + ioderr.c + +Abstract: + + This module implements error handling functions for the Rawhide + IOD (CAP and MDP ASICs). + +Author: + + Eric Rehm 13-Apr-1995 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" +//#include "iod.h" +#include "rawhide.h" +#include "stdio.h" + +// +// Externals and globals. +// + +extern PERROR_FRAME PUncorrectableError; +extern ULONG HalDisablePCIParityChecking; +ULONG IodCorrectedErrors = 0; + +// +// Define the context structure for use by interrupt service routines. +// + +typedef BOOLEAN (*PSECOND_LEVEL_DISPATCH)( + PKINTERRUPT InterruptObject, + PVOID ServiceContext + ); + +// +// The Soft Error interrupt is always turned on for Rawhide. When a +// Soft Error interrupt occurs, HalpIodSoftErrorInterrupt() must +// be called to reset the error condition on the offending IOD to +// insure system integrity. +// +// A Correctable Error Driver might also connect to the Soft Error interrupt +// via the Internal Bus interface. When a Soft Error interrupt occurs, +// we determine if it is also necessary to dispatch an ISR for the +// Correctable Error Driver via a boolean. +// + +BOOLEAN HalpLogCorrectableErrors = FALSE; + +// +// Keep the first time we read the WhoAmI register +// since it does not always read the same the second time. +// +// Zero value indicates that we haven't read WhoAmI yet and that +// this global variable is not valid. +// +// (On machine checks that we dismiss, we must remember to +// to reset this to zero.) +// + +IOD_WHOAMI HalpIodWhoAmIOnError = { 0 }; + +// +// Function prototypes. +// + +VOID +HalpSetMachineCheckEnables( + IN BOOLEAN DisableMachineChecks, + IN BOOLEAN DisableProcessorCorrectables, + IN BOOLEAN DisableSystemCorrectables + ); + +VOID +HalpUpdateMces( + IN BOOLEAN ClearMachineCheck, + IN BOOLEAN ClearCorrectableError + ); + +// +// Function prototypes for routines not visible outside this module +// + +VOID +HalpBuildIodErrorFrame( + MC_DEVICE_ID McDeviceId, + PIOD_ERROR_FRAME IodErrorFrame + ); + +BOOLEAN +bFindIodError( + PMC_DEVICE_ID pMcDeviceId, + PIOD_CAP_ERR pIodCapErr +); + +BOOLEAN +bHandleFatalIodError( + MC_DEVICE_ID McDeviceId, + BOOLEAN bMachineCheck + ); + +BOOLEAN +bHandleIsaError( + MC_DEVICE_ID pMcDeviceId, + IOD_CAP_ERR IodCapErr +); + +VOID +HalpErrorFrameString( + PUNCORRECTABLE_ERROR uncorr, + PUCHAR OutBuffer + ); + +ULONG +BuildActiveCpus ( + VOID + ); + +// +// Allocate a flag that indicates when a PCI Master Abort is expected. +// PCI Master Aborts are signaled on configuration reads to non-existent +// PCI slots. A cardinal value (0-128) indicates that a Master Abort is expected. +// A value of 0xffffffff indicates that a Master Abort is *not* expected. +// + +IOD_EXPECTED_ERROR HalpMasterAbortExpected = {MASTER_ABORT_NOT_EXPECTED, 0x0}; + + +VOID +HalpInitializeIodMachineChecks( + IN BOOLEAN ReportCorrectableErrors, + IN BOOLEAN PciParityChecking + ) +/*++ + +Routine Description: + + This routine initializes machine check handling for a IOD-based + system by clearing all pending errors in the IOD registers and + enabling correctable errors according to the callers specification. + +Arguments: + + ReportCorrectableErrors - Supplies a boolean value which specifies + if correctable error reporting should be + enabled. + +Return Value: + + None. + +--*/ +{ + IOD_CAP_CONTROL IodCapControl; + IOD_CAP_ERR IodCapError; + IOD_MDPA_DIAG IodMdpaDiag; + IOD_MDPB_DIAG IodMdpbDiag; + IOD_INT_MASK IodIntMask; + + MC_DEVICE_ID McDeviceId; + MC_ENUM_CONTEXT mcCtx; + ULONG numIods; + BOOLEAN bfoundIod; + + // + // 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; // 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 + + // + // Intialize enumerator. + // + + numIods = HalpMcBusEnumStart ( HalpIodMask, &mcCtx ); + + // + // Intialize each Iod + // + + while ( bfoundIod = HalpMcBusEnum( &mcCtx ) ) { + + McDeviceId = mcCtx.McDeviceId; + + // + // Initialize IOD_CAP_ERR + // + + WRITE_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->CapErr, + IodCapError.all ); + + // + // Set the Iod error enable bits in the IOD_CAP_CTRL and + // IOD_MDPA/B_DIAG registers. The configuration bits in the IOD + // will be left as set by the Extended SROM, with the few + // exceptions documented below. + // + + IodCapControl.all = READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->CapCtrl ); + +#if 0 // CAP/MDP Bug + IodMdpaDiag.all = + READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpaDiag ); + + IodMdpbDiag.all = + READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpbDiag ); +#else + + // + // Clear Mdp Diagnotic Check Registers.... + // + + IodMdpaDiag.all = 0; + IodMdpbDiag.all = 0; + + // + // Enable ECC checking on all MC Bus transactions + // + + IodMdpaDiag.EccCkEn = 1; + IodMdpbDiag.EccCkEn = 1; + +#endif + + // + // Disable/enable PCI parity checking as requested + // + + if (PciParityChecking == FALSE) { + + IodCapControl.PciAddrPe= 0; // Do *not* check PCI address parity + IodMdpaDiag.ParCkEn = 0; // Do *not* check PCI data parity + IodMdpbDiag.ParCkEn = 0; // Do *not* check PCI data parity + + } else { + + IodCapControl.PciAddrPe= PciParityChecking; + IodMdpaDiag.ParCkEn = PciParityChecking; + IodMdpbDiag.ParCkEn = PciParityChecking; + + } + + + // + // Disable McBus NXM's + // + // (If enabled, accesses to non-existent McBus device will cause an + // EV5 fill error. Non existant CSRs will return all 0s most of the time + // and not fill error.) + // + + IodCapControl.McNxmEn = 0; + + // + // Disable monitoring of McBus bystander errors. + // + // That means the IOD will not capture the failing address in the event of + // an MC bus NXM. It has no effect on what the IOD does in the event of a + // PCI NXM (which causes a Master Abort). + // + // Regardless of how McBusMonEn PCI PERR, SERR, MAB, and PTE_INV + // will only show up in IOD CAP_ERR of the participant in the transaction. + // + // If McBusMonEn is set, there can be a difference between the bystander CAP_ERR + // state and the participant CAP_ERR state (as per Sam Duncan, 5/3/95) + // shows up in an unlikely situation: + // "Cache single bit or double bit error: read is dirty in a cache + // and the fill has an ecc error, don't want to indite a memory for this + // (very unlikely) error." + // Thus, we choose not to be able to correctly detect this situation in + // order to make machine check and error handling easier, i.e., we + // always only need to clear only one IOD's CAP_ERROR. + // + + IodCapControl.McBusMonEn= 0; + + + WRITE_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->CapCtrl, + IodCapControl.all ); + + WRITE_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpaDiag, + IodMdpaDiag.all ); + + WRITE_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpbDiag, + IodMdpbDiag.all ); + + + // + // Soft and Hard Error handling + // + // ecrfix - IntMask0 on Bus 0 only. + + IodIntMask.all = READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntMask0 ); + + IodIntMask.SoftErr = (ReportCorrectableErrors == TRUE); + IodIntMask.HardErr = 0; // ecrfix - Mask Hard Errors for now + + WRITE_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntMask0, + IodIntMask.all ); + + } // while ( HalpMcBusEnum ( &mcCtx ) ) + + // + // Set the machine check enables within the EV5. + // + + if( ReportCorrectableErrors == TRUE ){ + HalpSetMachineCheckEnables( FALSE, FALSE, FALSE ); + } else { + HalpSetMachineCheckEnables( FALSE, TRUE, TRUE ); + } + + return; + +} + +#define MAX_ERROR_STRING 128 + + +BOOLEAN +HalpIodUncorrectableError( + PMC_DEVICE_ID pMcDeviceId + ) +/*++ + +Routine Description: + + Read the IOD error register and determine if an uncorrectable error + is latched in the error bits. + +Arguments: + + None. + +Return Value: + + TRUE is returned if an uncorrectable error has been detected. FALSE + is returned otherwise. + +--*/ +{ + UCHAR OutBuffer[ MAX_ERROR_STRING ]; + IOD_WHOAMI IodWhoAmI; + IOD_CAP_ERR IodCapErr; + + // + // Check for a duplicate tag parity error on this (in the Smalltalk + // sense) processor. + // + + IodWhoAmI.all = HalpReadWhoAmI(); + HalpIodWhoAmIOnError.all = IodWhoAmI.all; + + if ( IodWhoAmI.CpuInfo & CACHED_CPU_DTAG_PARITY_ERROR ) { + + pMcDeviceId->all = IodWhoAmI.Devid; + + return TRUE; + + } else { + + // + // None of the uncorrectable error conditions were detected. + // + + return FALSE; + } + +} + +VOID +HalpBuildIodErrorFrame( + MC_DEVICE_ID McDeviceId, + PIOD_ERROR_FRAME IodErrorFrame + ) +/*++ + +Routine Description: + + This function reports and interprets a fatal hardware error + detected by the IOD chipset. It is assumed that HalGetDisplayOwnership() + has been called prior to this function. + +Arguments: + + McDevid - Supplies the MC Bus Device ID of the IOD + IodErrorFrame - Supplies a pointer to an IOD_ERROR_FRAME + +Return Value: + + None. + +--*/ +{ + // + // Clear it first, since caller may reuse the IodErrorFrame + // + + RtlZeroMemory(IodErrorFrame, sizeof(IOD_ERROR_FRAME)); + + // + // Everything is valid + // + + IodErrorFrame->ValidBits.all = 0xffffffff; // all valid + + + // + // Read the General registers + // + + IodErrorFrame->BaseAddress = IOD_IO_SPACE_START | + IOD_SPARSE_CSR_OFFSET | + MCDEVID_TO_PHYS_ADDR(McDeviceId.all); + + IodErrorFrame->WhoAmI = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->WhoAmI + ); + + IodErrorFrame->PciRevision = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->PciRevision + ); + + IodErrorFrame->CapCtrl = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->CapCtrl + ); + + IodErrorFrame->HaeMem = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->HaeMem + ); + + IodErrorFrame->HaeIo = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->HaeIo + ); + + // + // Read Interrupt Control and Status Registers + // + + IodErrorFrame->IntCtrl = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntCtrl + ); + + IodErrorFrame->IntReq = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntReq + ); + + IodErrorFrame->IntMask0 = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntMask0 + ); + + IodErrorFrame->IntMask1 = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntMask1 + ); + + // + // Read the rest of the error registers and then unlock them by + // writing to CAP_ERR + // + + IodErrorFrame->CapErr = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->CapErr + ); + + IodErrorFrame->PciErr1 = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->PciErr1 + ); + + IodErrorFrame->McErr0 = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->McErr0 + ); + + IodErrorFrame->McErr1 = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->McErr1 + ); +#if 0 // CAP/MDP Bug + IodErrorFrame->MdpaStat = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpaStat + ); + + IodErrorFrame->MdpaSyn = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpaSyn + ); + + IodErrorFrame->MdpbStat = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpbStat + ); + + IodErrorFrame->MdpbSyn = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpbSyn + ); +#else + + // + // CAP/MDP Bug - these registers are not valid. + // + + IodErrorFrame->ValidBits.MdpaStatValid = 0; + IodErrorFrame->ValidBits.MdpbStatValid = 0; + IodErrorFrame->ValidBits.MdpaSynValid = 0; + IodErrorFrame->ValidBits.MdpbSynValid = 0; + +#endif // CAP/MDP Bug + +} + +VOID +HalpIodReportFatalError( + MC_DEVICE_ID ErrorMcDeviceId + ) +/*++ + +Routine Description: + + This function reports and interprets a fatal hardware error + detected by the IOD chipset. It is assumed that HalGetDisplayOwnership() + has been called prior to this function. + +Arguments: + + ErrorMcDeviceId - Supplies the MC Bus Device ID of the IOD + where the error was found + + - In the case of a Duplicate Tag Parity Error, supplies + the CPU that took the error. Note, in this case + the ErrorMcDeviceId will never match a IOD McDeviceId. + No MC Bus snapshot is present in this case. + +Return Value: + + None. + +--*/ +{ + UCHAR OutBuffer[ MAX_ERROR_STRING ]; + IOD_ERROR_FRAME IodErrorFrame, *pCurrentIodErrorFrame; + MC_ENUM_CONTEXT mcCtx; + MC_DEVICE_ID McDeviceId; + ULONG numIods; + BOOLEAN bfoundIod; + + PUNCORRECTABLE_ERROR uncorr = NULL; + PRAWHIDE_UNCORRECTABLE_FRAME rawerr = NULL; + PEXTENDED_ERROR PExtErr; + + // + // Do we have an uncorrectable error frame? + // + + if (PUncorrectableError) { + uncorr = (PUNCORRECTABLE_ERROR) + &PUncorrectableError->UncorrectableFrame; + rawerr = (PRAWHIDE_UNCORRECTABLE_FRAME) + PUncorrectableError->UncorrectableFrame.RawSystemInformation; + PExtErr = &PUncorrectableError->UncorrectableFrame.ErrorInformation; + } + + // + // Validate the ProcessorInfo portion of the Error Frame. + // + + if (uncorr) { + uncorr->Flags.ProcessorInformationValid = 1; + HalpGetProcessorInfo(&uncorr->ReportingProcessor); + + // + // Initialize our "error string accumulator" + // + + HalpErrorFrameString( uncorr, NULL ); + + } + + // + // Validate the Rawhide Uncorrectable Frame + // (Common RCUD Header was already set up.) + // + + if (rawerr) { + rawerr->Revision = RAWHIDE_UNCORRECTABLE_FRAME_REVISION; + rawerr->WhoAmI = HalpIodWhoAmIOnError.all; + rawerr->ErrorSubpacketFlags.all = 0; + rawerr->CudHeader.ActiveCpus = BuildActiveCpus(); + + } + + // + // Handle cached CPU duplicate tag parity error. + // (Note that a DTAG parity error implies that we don't + // take an MC Bus Snapshot. + // + + if ( HalpIodWhoAmIOnError.CpuInfo & CACHED_CPU_DTAG_PARITY_ERROR ) { + + sprintf( OutBuffer, "Duplicate Tag Parity Error on CPU %x\n", + MCDEVID_TO_PHYS_CPU(HalpIodWhoAmIOnError.McDevId.all) ); + + HalDisplayString( OutBuffer ); +#if HALDBG + DbgPrint( "Duplicate Tag Parity Error on CPU (%d, %d)\n", + HalpIodWhoAmIOnError.McDevId.Gid, HalpIodWhoAmIOnError.McDevId.Mid); +#endif + HalpErrorFrameString( uncorr, OutBuffer ); + + // + // OK. This is tedious: + // * Error is in memory space and is the system (external) cache. + // * And we know this is the L3 cache. + // * And we'll subvert the "CacheBoard" to squirrel away the + // Cached CPU Revision Info and Cache size. + // + + uncorr->Flags.AddressSpace = MEMORY_SPACE; + uncorr->Flags.ExtendedErrorValid = 1; + uncorr->Flags.MemoryErrorSource = SYSTEM_CACHE; + PExtErr->CacheError.Flags.CacheLevelValid = 1; + PExtErr->CacheError.Flags.CacheBoardValid = 1; + PExtErr->CacheError.Flags.CacheSimmValid = 0; + PExtErr->CacheError.CacheLevel = 3; + PExtErr->CacheError.CacheBoardNumber = HalpIodWhoAmIOnError.CpuInfo; + + return; + } + + // + // Handle cached CPU fill error. + // Since this could be caused by an MC Bus or PCI error, + // we continue to create an MC Bus snapshot. + // + + if ( HalpIodWhoAmIOnError.CpuInfo & CACHED_CPU_FILL_ERROR ) { + + sprintf( OutBuffer, "Fill Error on CPU %x\n", + MCDEVID_TO_PHYS_CPU(HalpIodWhoAmIOnError.McDevId.all) ); + + HalDisplayString( OutBuffer ); +#if HALDBG + DbgPrint( "Fill Error on CPU (%d, %d)\n", + HalpIodWhoAmIOnError.McDevId.Gid, HalpIodWhoAmIOnError.McDevId.Mid); +#endif + HalpErrorFrameString( uncorr, OutBuffer ); + + // + // * WhoAmI tells us Addr<38:33> of reference causing error. + // * However, PciErr1 and/or McErr0/McErr1 give us more bits, + // so the data entered here my get overwritten later. + // + + uncorr->Flags.PhysicalAddressValid = 1; + uncorr->PhysicalAddress = + ( ((ULONGLONG)(HalpIodWhoAmIOnError.CpuInfo & 0x3f)) << 33 ); + + } + + // + // Validate the MCBusSnapshot header. + // + + if (rawerr) { + rawerr->ErrorSubpacketFlags.McBusPresent = 1; + rawerr->McBusSnapshot.ReportingCpuBaseAddr = + IOD_IO_SPACE_START | + MCDEVID_TO_PHYS_ADDR( HalpIodWhoAmIOnError.Devid ); + pCurrentIodErrorFrame = (PIOD_ERROR_FRAME) (rawerr + 1); + } + + // + // Intialize enumerator. + // + + numIods = HalpMcBusEnumStart ( HalpIodMask, &mcCtx ); + ASSERT( numIods == HalpNumberOfIods); + + // + // Gather data from each Iod + // + + while ( bfoundIod = HalpMcBusEnum( &mcCtx ) ) { + + McDeviceId.all = mcCtx.McDeviceId.all; + + HalpBuildIodErrorFrame( McDeviceId, &IodErrorFrame ); + + // + // Fill in IOD_ERROR_FRAME portion of the RAWHIDE_UNCORRECTABLE_FRAME + // + + if (rawerr) { + + RtlCopyMemory( pCurrentIodErrorFrame, + &IodErrorFrame, + sizeof(IOD_ERROR_FRAME)); + + pCurrentIodErrorFrame++; + } + + // + // If this is the IOD where we found the error + // a. clear the error + // b. complete the uncorrectable error frame processing + // c. Display an interpretation of the error to the screen + // + + if (ErrorMcDeviceId.all == McDeviceId.all) { + + // ecrfix Put below into HalpInterpretIodError(McDeviceId, IodErrorFrame) ??? + IOD_WHOAMI IodWhoAmI; + IOD_CAP_CONTROL IodCapCtrl; + IOD_CAP_ERR IodCapErr; + IOD_PCI_ERR1 IodPciErr1; + IOD_MC_ERR0 IodMcErr0; + IOD_MC_ERR1 IodMcErr1; + IOD_MDPA_STAT IodMdpaStat; + IOD_MDPB_STAT IodMdpbStat; + ULONG HwBusNumber = ErrorMcDeviceId.Mid & 0x3; + + // + // Copy error frame variables in locals for bitfield access + // + + IodWhoAmI.all = IodErrorFrame.WhoAmI; + IodCapCtrl.all = IodErrorFrame.CapCtrl; + IodCapErr.all = IodErrorFrame.CapErr; + IodPciErr1.PciAddress = IodErrorFrame.PciErr1; + IodMcErr0.all = IodErrorFrame.McErr0; + IodMcErr1.all = IodErrorFrame.McErr1; + + #if 0 // CAP/MDP Bug + IodMdpaStat.all = IodErrorFrame.MdpaStat; + IodMdpbStat.all = IodErrorFrame.MdpbStat; + IodMdpaSyn.all = IodErrorFrame.MdpaSyn; + IodMdpbSyn.all = IodErrorFrame.MdpbSyn; + #else + IodMdpaStat.all = 0xffffffff; + IodMdpbStat.all = 0xffffffff; + #endif // CAP/MDP Bug + + + + // + // Clear state in MDPA and MDPB before clearing CAP_ERR + // + + + WRITE_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpaStat, + IodErrorFrame.MdpaStat + ); + + WRITE_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->MdpbStat, + IodErrorFrame.MdpbStat + ); + + WRITE_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->CapErr, + IodErrorFrame.CapErr + ); + + sprintf( OutBuffer, + "IOD MC_DEVICE_ID : (%x, %x) CAP_CTRL : %08x CAP_ERR : %08x\n", + McDeviceId.Gid, McDeviceId.Mid, + IodCapCtrl.all, + IodCapErr.all ); + + HalDisplayString( OutBuffer ); +#if HALDBG + DbgPrint( OutBuffer ); +#endif + + sprintf( OutBuffer, + "PCI_ERR1 %08x MC_ERR0 : %08x MC_ERR1 : %08x\n", + IodPciErr1.PciAddress, + IodMcErr0.all, + IodMcErr1.all ); + + HalDisplayString( OutBuffer ); +#if HALDBG + DbgPrint( OutBuffer ); +#endif + + #if 0 // CAP/MDP Bug + sprintf( OutBuffer, + "MDPA_STAT : %08x MDPA_SYN : %08x MDPB_STAT : %08x MDPB_SYN : %08x\n", + IodMdpaStat.all, + IodMdpaSyn.all, + IodMdpbStat.all, + IodMdpbSyn.all ); + HalDisplayString( OutBuffer ); +#if HALDBG + DbgPrint( OutBuffer ); +#endif + #endif + + // + // If no valid error then no interpretation. + // + + if (( IodCapErr.PciErrValid == 0 ) && ( IodCapErr.McErrValid == 0 ) ){ + + return; // No IOD error detected + + } + + // + // Interpret any detected errors: + // + + if (IodCapErr.McErrValid == 1) { + + if ( IodMcErr1.Dirty != 1 ) { + sprintf( OutBuffer, + "MC Bus Error, Bus Master=(%x,%x)\n", + + ( ( IodMcErr1.DevId & 0x38) >> 3 ), + ( IodMcErr1.DevId & 0x07) + ); + } else { + + sprintf( OutBuffer, + "MC bus error on a read/dirty transaction\n" + ); + } + + + // + // Output the detected error message: + // + + HalDisplayString( OutBuffer ); +#if HALDBG + DbgPrint( OutBuffer ); +#endif + HalpErrorFrameString( uncorr, OutBuffer); + + + sprintf( OutBuffer, + "IOD Addr=%x%x, Cmd=%x\n", + IodMcErr1.Addr39_32, // bits 39:32 + IodMcErr0.Addr, // bits 31:4 + IodMcErr1.McCmd + ); + + // + // Output the detected error message: + // + + HalDisplayString( OutBuffer ); +#if HALDBG + DbgPrint( OutBuffer ); +#endif + HalpErrorFrameString( uncorr, OutBuffer); + + // + // Interpret specific MC bus error + // + + uncorr->Flags.PhysicalAddressValid = 1; + uncorr->PhysicalAddress = ( + (((ULONGLONG)IodMcErr1.Addr39_32) << 32) | + ((ULONGLONG)IodMcErr0.Addr) ); + + // + // McAddr<39> indicates whether this was a + // memory or I/O transaction. + // + + if ( (IodMcErr1.Addr39_32 & 0x80) == 1) { + uncorr->Flags.AddressSpace = IO_SPACE; + } else { + uncorr->Flags.AddressSpace = MEMORY_SPACE; + } + + if ( IodCapErr.PioOvfl == 1 ){ + + sprintf( OutBuffer, + "IOD PIO Overflow, PendNumb=%x\n", + IodCapCtrl.PendNum + ); + + } else if ( IodCapErr.McAddrPerr == 1 ){ + + sprintf( OutBuffer, + "MC bus parity error\n" + ); + + } else if ( IodCapErr.Nxm == 1 ){ + + sprintf( OutBuffer, + "MC bus NXM\n" + ); + + } else if ( IodCapErr.CrdA == 1 ){ + + sprintf( OutBuffer, + "IOD Correctable ECC error in MDPA\n" + ); + + } else if ( IodCapErr.CrdB == 1 ){ + + sprintf( OutBuffer, + "IOD Correctable ECC error in MDPB\n" + ); + + } else if ( IodCapErr.RdsA == 1 ){ + + sprintf( OutBuffer, + "IOD Uncorrectable ECC error in MDPA\n" + ); + + } else if ( IodCapErr.RdsB == 1 ){ + + sprintf( OutBuffer, + "IOD Uncorrectable ECC error in MDPB\n" + ); + + } + + // + // Output the detected error message: + // + + HalDisplayString( OutBuffer ); +#if HALDBG + DbgPrint( OutBuffer ); +#endif + HalpErrorFrameString( uncorr, OutBuffer); + + } + + if ( IodCapErr.PciErrValid == 1 ){ + + // + // Interpret specific PCI bus error + // + + uncorr->Flags.AddressSpace = IO_SPACE; + uncorr->Flags.PhysicalAddressValid = 1; + uncorr->PhysicalAddress = IOD_IO_SPACE_START | + MCDEVID_TO_PHYS_ADDR(IodWhoAmI.McDevId.all) | + IodPciErr1.PciAddress << IO_BIT_SHIFT; + + uncorr->Flags.ExtendedErrorValid = 1; + PExtErr->IoError.Interface = PCIBus; + PExtErr->IoError.BusNumber = HwBusNumber; + PExtErr->IoError.BusAddress.LowPart = IodPciErr1.PciAddress; + + if ( IodCapErr.Perr == 1 ){ + sprintf( OutBuffer, + "PERR detected on PCI-%d, Addr=%x\n", + HwBusNumber, + IodPciErr1.PciAddress + ); + + } else if ( IodCapErr.Serr == 1 ){ + + sprintf( OutBuffer, + "SERR detected on PCI-%d, Addr=%x\n", + HwBusNumber, + IodPciErr1.PciAddress + ); + + } else if ( IodCapErr.Mab == 1 ){ + + sprintf( OutBuffer, + "Master Abort on PCI-%d, Addr=%x\n", + HwBusNumber, + IodPciErr1.PciAddress + ); + + } else if ( IodCapErr.PteInv == 1 ){ + + sprintf( OutBuffer, + "Invalid Scatter/Gather PTE on PCI-%d, Addr=%x\n", + HwBusNumber, + IodPciErr1.PciAddress + ); + } + + // + // Output the detected error message: + // + + HalDisplayString( OutBuffer ); +#if HALDBG + DbgPrint( OutBuffer ); +#endif + HalpErrorFrameString( uncorr, OutBuffer); + + } + + // + // Check for lost errors and output message if any occurred: + // + + if ( IodCapErr.LostMcErr == 1 ){ + HalDisplayString("IOD Lost errors were detected\n"); +#if HALDBG + DbgPrint("IOD Lost errors were detected\n"); +#endif + HalpErrorFrameString(uncorr, "IOD Lost errors were detected\n"); + } + + } // if (ErrorMcDeviceID == McDeviceId) + + } // while (bfoundIod = HalpMcBusEnum) + + return; // Fatal error detected +} + + +BOOLEAN +HalpIodMachineCheck( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN PKTRAP_FRAME TrapFrame + ) +/*++ + +Routine Description: + + This routine is given control when an hard error is acknowledged + by the IOD chipset. The routine is given the chance to + correct and dismiss the error. + +Arguments: + + ExceptionRecord - Supplies a pointer to the exception record generated + at the point of the exception. + + ExceptionFrame - Supplies a pointer to the exception frame generated + at the point of the exception. + + TrapFrame - Supplies a pointer to the trap frame generated + at the point of the exception. + +Return Value: + + TRUE is returned if the machine check has been handled and dismissed - + indicating that execution can continue. FALSE is return otherwise. + +--*/ +{ + IOD_CAP_ERR IodCapErr; + IOD_CAP_ERR IodCapErrMask; + IOD_MC_ERR1 IodMcErr1; + IOD_WHOAMI IodWhoAmI; + MC_DEVICE_ID McDeviceId; + BOOLEAN ExpectedMchk; + BOOLEAN ExpectedMcAddrPerr; + BOOLEAN PciMemReadMchk; + BOOLEAN bfoundIod; + + // + // We don't expect a machine check yet... + // + + ExpectedMchk = FALSE; + ExpectedMcAddrPerr = FALSE; + + // + // Make sure any error due to 2Mb/4Mb Cached CUD bug is latched. + // + // At this point, WhoAmI may indicate the symptoms of a fill_error + // and CUD cache size is not available. We'll read it again when + // we need to know the Cache size. However, we save he here so we + // can figure out if this was a fill error or not. + // + + HalpIodWhoAmIOnError.all = HalpReadWhoAmI(); + + // + // Where do we look for the error symptoms? + // + // 1. If we expected this machine check, then we know which + // IOD to check. + // 2. If we didn't expect this machine check, find the IOD that + // generated the error. + // + + // + // For an expected machine check, HalpMasterAbortExpected will + // contain the processor number and address of a PCI config + // space read. CAP_ERR will indicate a MasterAbort. + // + + if( HalpMasterAbortExpected.Number == (ULONG)KeGetCurrentProcessorNumber() ) { + + // + // Determine expected IOD from the address of the PCI config read + // + + McDeviceId.all = MCDEVID_FROM_PHYS_ADDR(HalpMasterAbortExpected.Addr); + + // + // Now get the Bcache size information. + // + + IodWhoAmI.all = READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->WhoAmI); + + // + // + // Make sure there is a Master abort on this IOD + // + + IodCapErr.all = READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->CapErr ); + + + if( IodCapErr.Mab == 1 ) { + ExpectedMchk = TRUE; + + // + // If 2Mb or 4 Mb cached CUD, and we may get an MCbus address parity + // error with MC command signature in MC_ERR1 equal to zero (cached + // CPU idle transaction). Also dismiss this error that's the result + // of the cached 2Mb/4Mb cached CPU VCTY bug. + // + + IodMcErr1.all = READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->McErr1 ); + + if ((IodWhoAmI.CpuInfo & 0x7) && // Cached CPU? + IodCapErr.McAddrPerr && // McAddrPerr? + (IodMcErr1.McCmd == 0) ) { // McCmd is zero? + + ExpectedMcAddrPerr = TRUE; // All yes, then dismiss it! + } + } + +#if HALDBG + DbgPrint( "Expected Mchk (Mab) on IOD (%x, %x), Processor number %x\n", + McDeviceId.Gid, + McDeviceId.Mid, + HalpMasterAbortExpected.Number); +#endif //HALDBG + } + + // + // If this isn't the machine check we expected, then + // we must find the IOD that took the error. + // + + if (!ExpectedMchk) { + + bfoundIod = bFindIodError( &McDeviceId, &IodCapErr ); + + // + // Check that we found an IOD that has a valid PCI or MC error. + // If it is not this is a pretty weird (fatal???) condition. + // For now, we'll just go return TRUE. + // + // ecrfix - should we check the error interrupts? probably not... + // + + if( !bfoundIod ) { + +#if HALDBG + DbgPrint( "HalpIodMachineCheck called but no PCI or MC error found\n"); +#endif + return (TRUE); + } + + +#if 0 // HALDBG + DbgPrint( "Unexpected Mchk on IOD (%x, %x)\n", + McDeviceId.Gid, + McDeviceId.Mid ); +#endif //HALDBG + + // + // Case: Uexpected Master Abort, e.g. a PCI memory or I/O space read to + // legacy ISA space (0 - 1 Mb) on PCI-1,2,3. + // + + if ( bHandleIsaError( McDeviceId, IodCapErr) ) { + return TRUE; + } + + } + + // + // Case: PCI or MC Bus error other than master abort + // + // At this point we have either: + // (a) an expected PCI Master Abort (ExpectedMchk == TRUE), or + // (b) an unexpected PCI or MC Bus error. + // + // However, it's possible that we have *both* (a) AND (b). + // So, even if ExpectedMch == TRUE, check for other PCI or MC Bus + // errors. Any of these other errors indicate a + // fatal condition. + // + + if( (IodCapErr.Perr == 1) || // PCI bus perr detected + (IodCapErr.Serr == 1) || // PCI bus serr detected + (IodCapErr.PteInv == 1) || // Invalid Pte + (IodCapErr.PioOvfl == 1) || // Pio Ovfl + + // + // Cached CUD with 2 Mb and 4 Mb Cache may also assert an MCAddrPerr + // or Nxm upon a config space read. Lost Error bit will also be set. + // + // + + ( (IodCapErr.LostMcErr == 1) && !ExpectedMcAddrPerr) || + // Lost error + ( (IodCapErr.McAddrPerr == 1) && !ExpectedMcAddrPerr ) || + // MC bus comd/addr parity error + + + ( (IodCapErr.Nxm == 1) && !ExpectedMcAddrPerr ) || + // Non-existent memory error + (IodCapErr.CrdA == 1) || // Correctable ECC error on MDPA + (IodCapErr.CrdB == 1) || // Correctable ECC error on MDPB + (IodCapErr.RdsA == 1) || // Uncorrectable ECC error on MDPA + (IodCapErr.RdsA == 1) // Uncorrectable ECC error on MDPA + + ){ + return ( bHandleFatalIodError(McDeviceId, TRUE) ); + } + + // + // At this point, we have either an expected or unexpected Master + // abort. There are three cases: + // 1. Expected MAB from a PCI config space read that must be handled + // 2. Unexpected MAB from a PCI memory or I/O space read in ISA legacy + // space that can be handled. + // 3. Unexpected MAB. Don't handle or fix up this error condition. + // (Really take the machine check.) + // + + // + // Case 1: Expected Master Abort, e.g. a PCI configuration read error. + // + + if ( (IodCapErr.Mab == 1) && ExpectedMchk ){ + + // + // Here's how a PCI config space read to an empty slot will transpire: + // + // READ_CONFIG_Usize indicates the issuing CPU and address in + // HalpMasterAbortExpected.Number and HalpMasterAbortExpected.Addr. + // + // PCI config space read will case a MC Bus FILL_ERROR on the issuing CPU + // FILL_ERROR causes a machine check. + // + // The targeted MC-PCI bus bridge will set CAP_ERR<MasterAbort> bit. + // + // So far, the error looks like a PCI configuration space read + // that accessed a device that does not exist. In order to fix + // this up we expect that the original faulting instruction must + // be a load with v0 as the destination register. Unfortunately, + // machine checks are not precise exceptions so we may have exectued + // many instructions since the faulting load. For EV5 a pair of + // memory barrier instructions following the load will stall the pipe + // waiting for load completion before the second memory barrier can + // be issued. Therefore, we expect the exception PC to point to either + // the load instruction or one of the two memory barriers. We will + // assume that if the exception pc is not an mb that instead it + // points to the load that machine checked. We must be careful to + // not reexectute the load. + // + + ALPHA_INSTRUCTION FaultingInstruction; + + + FaultingInstruction.Long = *(PULONG)((ULONG)TrapFrame->Fir); + if( FaultingInstruction.Memory.Opcode != MEMSPC_OP ){ + + // + // Exception pc does not point to a memory barrier, return + // to the instruction after the exception pc. + // + + TrapFrame->Fir += 4; + + } + + // + // The error has matched all of our conditions. Fix it up by + // writing the value 0xffffffff into the destination of the load. + // + + TrapFrame->IntV0 = (ULONGLONG)0xffffffffffffffff; + + // + // Clear all error conditions in CAP_ERR. + // (McAddrPerr, LostMcErr, Mab) + // +#if 0 + WRITE_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->CapErr, + IodCapErr.all ); +#else + IodCapErrMask.all = ALL_CAP_ERRORS; + HalpClearAllIods( IodCapErrMask ); +#endif + + // + // Clear the hard error interrupt. + // ecrfix - For now, the Hard error interrupt is masked, so + // we don't have to clear it. + // + + return TRUE; + + } +#if 0 + // + // Case 2: Uexpected Master Abort, e.g. a PCI memory or I/O space read to + // legacy ISA space (0 - 1 Mb) on PCI-1,2,3. + // + + if ( bHandleIsaError( McDeviceId, IodCapErr) ) { + return TRUE; + } +#endif + // + // Case 3: Unexpected Master abort. + // (Or anything I might have missed.... ) + // + +#if (DBG) || (HALDBG) + DbgPrint( "Unexpected PCI master abort\n" ); +#endif + + return ( bHandleFatalIodError(McDeviceId, TRUE) ); + +} + + +#define ENTIRE_FRAME_SIZE (sizeof(ERROR_FRAME) + sizeof(RAWHIDE_CORRECTABLE_FRAME)) +VOID +HalpIodSoftErrorInterrupt( + VOID + ) +/*++ + +Routine Description: + + Handle a IOD soft (correctable) error interrupt. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + BOOLEAN bfoundIod; + MC_DEVICE_ID McDeviceId; + + static UCHAR Frame[ENTIRE_FRAME_SIZE]; + static PERROR_FRAME pFrame; + static RAWHIDE_CORRECTABLE_FRAME RawhideFrame; + static BOOLEAN RawhideFrameInitialized = FALSE; + + UCHAR TempFrame[ENTIRE_FRAME_SIZE]; + PERROR_FRAME pTempFrame; + PCORRECTABLE_ERROR pCorr; + PRAWHIDE_CORRECTABLE_FRAME pRawCorr; + + PBOOLEAN ErrorlogBusy; + PULONG DispatchCode; + PKINTERRUPT InterruptObject; + PKSPIN_LOCK ErrorlogSpinLock; + PRAWHIDE_UNCORRECTABLE_FRAME rawerr; + + IOD_CAP_ERR IodCapErr; + IOD_MDPA_STAT IodMdpaStat; + IOD_MDPA_STAT IodMdpbStat; + IOD_MC_ERR0 IodMcErr0; + IOD_MC_ERR1 IodMcErr1; + + KIRQL Irql; + +#if 0 // CAP/MDP Bug + IOD_MDPA_SYN IodMdpaSyn; + IOD_MDPB_SYN IodMdpbSyn; +#endif + + +//ecrfix - later we should log the error, throttle the logging and turn off +// correctable error reporting if the frequency is too high + + // + // The error is expected to be a corrected ECC error on a DMA or + // Scatter/Gather TLB read/write. Read the error registers relevant + // to this error. + // + + // + // Find the IOD that latched the error. + // + + bfoundIod = bFindIodError( &McDeviceId, &IodCapErr ); + +#ifdef FORCE_CORRECTABLE_ERROR + IodCapErr.all = 0x88000000; + bfoundIod = 1; +#endif // FORCE_CORRECTABLE_ERROR + + // + // Check that we found an IOD that has a valid PCI or MC error. + // If it is not this is a pretty weird (fatal???) condition. + // For now, we'll just go return TRUE. + // + + if( !bfoundIod ) { + +#if 0 //HALDBG + DbgPrint( "HalpIodSoftErrorInterrupt: no PCI or MC error found.\n"); +#endif + return; + } + + // + // Check if an error is latched into the IOD. If not, goodbye. + // + + if( IodCapErr.McErrValid == 0 ){ + +#if HALDBG + DbgPrint( "Iod soft error interrupt without valid MC error\n" ); +#endif //HALDBG + + return; + } + + // + // Check for the correctable error bit. + // + + if( (IodCapErr.CrdA == 0) && (IodCapErr.CrdB == 0) ){ + +#if HALDBG + DbgPrint( "Iod soft error interrupt without correctable error indicated in CapErr\n" ); +#endif //HALDBG + + } + + + // + // Increment the number of IOD correctable errors. + // + + IodCorrectedErrors += 1; + + // + // Read the rest of the error registers + // + + IodMcErr0.all = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR0_CSRS_QVA))->McErr0 + ); + + IodMcErr1.all = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR0_CSRS_QVA))->McErr1 + ); +#ifdef FORCE_CORRECTABLE_ERROR + IodMcErr0.all = 0x00bebad0; + IodMcErr1.all = 0x800f3f00; +#endif // FORCE_CORRECTABLE_ERROR + +#if 0 // CAP/MDP Bug + IodMdpaStat.all = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR0_CSRS_QVA))->MdpaStat + ); + + IodMdpaSyn.all = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR0_CSRS_QVA))->MdpaSyn + ); + + IodMdpbStat.all = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR0_CSRS_QVA))->MdpbStat + ); + + IodMdpbSyn.all = (ULONG)READ_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR0_CSRS_QVA))->MdpbSyn + ); +#endif + + +#if HALDBG + + // + // Print a correctable error message to the debugger. + // + + DbgPrint( "IOD Correctable Error Number %d, state follows: \n", + IodCorrectedErrors ); + DbgPrint( "\tIOD_CAP_ERR: 0x%x\n", IodCapErr.all ); + DbgPrint( "\tIOD_MC_ERR0: 0x%x\n", IodMcErr0.all ); + DbgPrint( "\tIOD_MC_ERR1: 0x%x\n", IodMcErr1.all ); +// DbgPrint( "\tIOD_MDPA_STAT: 0x%x\n", IodMdpaStat.all ); +// DbgPrint( "\tIOD_MDPA_SYN: 0x%x\n", IodMdpaSyn.all ); +// DbgPrint( "\tIOD_MDPB_STAT: 0x%x\n", IodMdpbStat.all ); +// DbgPrint( "\tIOD_MDPB_SYN: 0x%x\n", IodMdpbSyn.all ); + +#endif //HALDBG + + // + // Fill in the Correctable Error frame only if we've connected + // to the Correctable Error interrupt. + // + + if (HalpLogCorrectableErrors) { + + // + // Real error, get the interrupt object. + // + + DispatchCode = (PULONG)PCR->InterruptRoutine[RawhideSoftErrVector]; + InterruptObject = CONTAINING_RECORD( + DispatchCode, + KINTERRUPT, + DispatchCode + ); + + // + // Set various pointers so we can use them later. + // + + pFrame = (PERROR_FRAME) Frame; + pTempFrame = (PERROR_FRAME) TempFrame; + pCorr = (PCORRECTABLE_ERROR) &pTempFrame->CorrectableFrame; + pRawCorr = (PRAWHIDE_CORRECTABLE_FRAME) (TempFrame + + sizeof(ERROR_FRAME) ); + + ErrorlogBusy = (PBOOLEAN)((PUCHAR)InterruptObject->ServiceContext + + sizeof(PERROR_FRAME)); + ErrorlogSpinLock = (PKSPIN_LOCK)((PUCHAR)ErrorlogBusy + sizeof(PBOOLEAN)); + + // + // Clear the data structures that we will use. + // + + RtlZeroMemory(&TempFrame, ENTIRE_FRAME_SIZE); + + // + // Fill in the error frame information. + // + + pTempFrame->Signature = ERROR_FRAME_SIGNATURE; + pTempFrame->LengthOfEntireErrorFrame = ENTIRE_FRAME_SIZE; + pTempFrame->FrameType = CorrectableFrame; + pTempFrame->VersionNumber = ERROR_FRAME_VERSION; + pTempFrame->SequenceNumber = IodCorrectedErrors; + pTempFrame->PerformanceCounterValue = + KeQueryPerformanceCounter(NULL).QuadPart; + + // + // Check for lost error. + // + + if( IodCapErr.LostMcErr ) { + + // + // Since the error registers are locked from a previous error, + // we do not know where the error came from. Mark everything + // as UNIDENTIFIED. + // + + pCorr->Flags.LostCorrectable = 1; + pCorr->Flags.LostAddressSpace = UNIDENTIFIED; + pCorr->Flags.LostMemoryErrorSource = UNIDENTIFIED; + } + + pCorr->Flags.ErrorBitMasksValid = 0; + + // + // Determine error type. + // + + if (IodMcErr1.Addr39_32 & 0x80) { + + // + // I/O ECC error occurred. + // + + pCorr->Flags.AddressSpace = IO_SPACE; + pCorr->Flags.ExtendedErrorValid = 1; + pCorr->ErrorInformation.IoError.Interface = PCIBus; + pCorr->ErrorInformation.IoError.BusNumber = IodMcErr1.DevId & 0x3; + + // We never alloc PCI address higher than 1 Gb for any PCI + // address space (sparse mem, dense mem, sparse I/O), so this + // trick works. + + pCorr->ErrorInformation.IoError.BusAddress.LowPart = + ((IodMcErr0.Addr & 0x3FFFFFFF) >> IO_BIT_SHIFT); + + // The code below is not strictly correct. Based on the MC Bus + // spec, p.32, we can roughly say that McCmd<3> tells us whether + // there was a write or read transaction on the bus. If I looked + // at the spec harder, I might be able to distinguish a PIO op + // from a DMA operation. + + pCorr->ErrorInformation.IoError.TransferType + = ((IodMcErr1.McCmd & 0x8) ? BUS_IO_READ : BUS_IO_WRITE); + + } else { + + // + // Memory ECC error occurred. + // + + pCorr->Flags.AddressSpace = MEMORY_SPACE; + + } + + // + // Get the physical address where the error occurred. + // + + if (IodMcErr1.Valid) { + pCorr->Flags.PhysicalAddressValid = 1; + pCorr->PhysicalAddress = + ((ULONGLONG) (IodMcErr1.Addr39_32)) << 32; + pCorr->PhysicalAddress |= IodMcErr0.all; + } + + // + // Scrub the error if it's any type of memory error. + // + + if ( pCorr->Flags.AddressSpace == MEMORY_SPACE && + pCorr->Flags.PhysicalAddressValid ) { + pCorr->Flags.ScrubError = 1; + } + + // + // Acquire the spinlock. + // + + KeAcquireSpinLock(ErrorlogSpinLock, &Irql ); + + // + // Check to see if an errorlog operation is in progress already. + // + + if (!*ErrorlogBusy) { + + // + // Set reporting processor information. Disregard at the moment. + // + + pCorr->Flags.ProcessorInformationValid = 0; + + // + // Copy the SYSTEM_INFORMATION from the uncorrectable frame + // + + pCorr->System = PUncorrectableError->UncorrectableFrame.System; + + // + // + // Set raw system information flag. + // + + pCorr->Flags.SystemInformationValid = 1; + + // + // Do the Rawhide-specific stuff here + // + + pRawCorr->Revision = RAWHIDE_CORRECTABLE_FRAME_REVISION; + + // + // Copy the CUD header from the uncorrectable frame + // + + rawerr = (PRAWHIDE_UNCORRECTABLE_FRAME) + PUncorrectableError->UncorrectableFrame.RawSystemInformation; + if (rawerr) { + pRawCorr->CudHeader = rawerr->CudHeader; + } + + // + // Fill in the rest of the dynamic portion of the + // correctable frame. + // + + pRawCorr->CudHeader.ActiveCpus = BuildActiveCpus(); + pRawCorr->ErrorSubpacketFlags.all = 0; + pRawCorr->ErrorSubpacketFlags.IodSubpacketPresent = 1; + pRawCorr->WhoAmI = HalpReadWhoAmI(); + HalpBuildIodErrorFrame( McDeviceId, &(pRawCorr->IodErrorFrame) ); + + // + // Copy the information that we need to log. + // + + RtlCopyMemory(&Frame, + &TempFrame, + ENTIRE_FRAME_SIZE); + + pFrame->CorrectableFrame.RawSystemInformation = + (PVOID)((PUCHAR)pFrame + sizeof(ERROR_FRAME) ); + + pFrame->CorrectableFrame.RawSystemInformationLength = + sizeof(RAWHIDE_CORRECTABLE_FRAME); + + + // + // Put frame into ISR service context. + // + + *(PERROR_FRAME *)InterruptObject->ServiceContext = pFrame; + + } else { + + // + // An errorlog operation is in progress already. We will + // set various lost bits and then get out without doing + // an actual errorloging call. + // + + pFrame->CorrectableFrame.Flags.LostCorrectable = TRUE; + pFrame->CorrectableFrame.Flags.LostAddressSpace = + pTempFrame->CorrectableFrame.Flags.AddressSpace; + pFrame->CorrectableFrame.Flags.LostMemoryErrorSource = + pTempFrame->CorrectableFrame.Flags.MemoryErrorSource; + } + + // + // Release the spinlock. + // + + KeReleaseSpinLock(ErrorlogSpinLock, Irql ); + + // + // Dispatch to the secondary correctable interrupt service routine. + // The assumption here is that if this interrupt ever happens, then + // some driver enabled it, and the driver should have the ISR connected. + // + + ((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)( + InterruptObject, + InterruptObject->ServiceContext + ); + + } + + + + // + // Clear state in MDPA and MDPB before clearing CAP_ERR + // + + IodCapErr.all = 0; + IodCapErr.CrdA = 1; + IodCapErr.CrdB = 1; + IodMdpaStat.all = 0xffffffff; + IodMdpbStat.all = 0xffffffff; + + 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))->MdpaStat, + IodMdpbStat.all + ); + + WRITE_IOD_REGISTER_NEW( McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->CapErr, + IodCapErr.all + ); + + return; + +} + +VOID +HalpIodHardErrorInterrupt( + VOID + ) +/*++ + +Routine Description: + + Handle a IOD hard (uncorrectable) error interrupt. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + BOOLEAN bfoundIod; + MC_DEVICE_ID McDeviceId; + IOD_CAP_ERR IodCapErr; + IOD_WHOAMI IodWhoAmI; + KIRQL OldIrql; + + + // + // Raise IRQL to the highest level. + // Prevents us from taking other hard error interrupts + // during this one. + // + // Also, acquire a spin lock to keep entry + // to this code serialized. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + KiAcquireSpinLock(&HalpSystemInterruptLock); + + // + // Find the IOD that latched the error. + // + + bfoundIod = bFindIodError( &McDeviceId, &IodCapErr ); + + // + // Check that we found an IOD that has a valid PCI or MC error. + // If it is not this is a pretty weird (fatal???) condition. + // For now, we'll just return. + // + + if( !bfoundIod ) { + +#if 0 // HALDBG + DbgPrint( "HalpIodHardErrorInterrupt: no PCI or MC error found.\n"); +#endif + // + // Lower IRQL to the previous level. + // + + KiReleaseSpinLock(&HalpSystemInterruptLock); + KeLowerIrql(OldIrql); + return; + } + +#if 1 // ecrfix + // + // See if this was an ISA legacy space access + // on PCI-1,2,3. If so, dismiss this interrupt. + // + + if ( bHandleIsaError( McDeviceId, IodCapErr) ) { + + // + // Lower IRQL to the previous level. + // + + KiReleaseSpinLock(&HalpSystemInterruptLock); + KeLowerIrql(OldIrql); + return; + } +#endif + +#if HALDBG + DbgPrint( "Hard Error Found on IOD (%x, %x)\n", + McDeviceId.Gid, + McDeviceId.Mid ); +#endif //HALDBG + + // + // Save IodWhoAmI + // + + IodWhoAmI.all = HalpReadWhoAmI(); + HalpIodWhoAmIOnError.all = IodWhoAmI.all; + + // + // Handle the Fatal Error + // + + bHandleFatalIodError( McDeviceId, FALSE ); + + KeBugCheckEx( DATA_BUS_ERROR, + 0xbeadfeed, //ecrfix - quick error interrupt id + McDeviceId.all, + 0, + (ULONG) PUncorrectableError ); + + +} + +BOOLEAN +bHandleFatalIodError( + MC_DEVICE_ID McDeviceId, + BOOLEAN bMachineCheck + ) +/*++ + +Routine Description: + + Handles the epilogue of a fatal IOD unccorrectable error + from either a machine check or IOD hard error interrupt. + +Arguments: + + McDeviceId - IOD on which the error was found + + bMachineCheck - TRUE if we're handling a fatal machine check + FALSE if we're handling a fatal hard error interrupt + +Return Value: + + TRUE is returned if the IOD error has been handled and dismissed - + indicating that execution can continue. FALSE is return otherwise. + +--*/ +{ + +#if HALDBG + if (bMachineCheck ) { + DbgPrint( "Handling fatal error - machine check\n" ); + } else { + DbgPrint( "Handling fatal error - hard error interrupt\n" ); + } +#endif + + // + // Clear the error condition in the MCES register. + // + // ecrfix - the way this is written, this will be done on hard + // error interrupts too (where there has been *no* machine check). + // I hope it will be benign in this case.... + // + + HalpUpdateMces( TRUE, TRUE ); + + // + // Proceed to display the error. + // + + HalAcquireDisplayOwnership(NULL); + + // + // Display the dreaded banner. + // + + HalDisplayString( "\nFatal system hardware error.\n" ); + +#ifdef DUMPIODS + DumpAllIods(AllRegisters); +#endif + + + HalpIodReportFatalError( McDeviceId ); + + return( FALSE ); + +} + +BOOLEAN +bFindIodError( + PMC_DEVICE_ID pMcDeviceId, + PIOD_CAP_ERR pIodCapErr +) +/*++ + +Routine Description: + + Determines which IOD has an error latched in it. + +Arguments: + + None. + +Return Value: + + TRUE if an IOD was found with an error latched in CAP_ERR. + FALSE otherwise. + +--*/ +{ + MC_ENUM_CONTEXT mcCtx; + ULONG numIods; + BOOLEAN bfoundIod; + IOD_CAP_ERR IodCapErr; + + + // + // Intialize enumerator. + // + + numIods = HalpMcBusEnumStart ( HalpIodMask, &mcCtx ); + +#if 0 // HALDBG + DbgPrint( "FindIodError: Searching: %d Iods: ", numIods); +#endif // HALDBG + + // + // Search each Iod and look for a PCI or McBus error. + // + + while ( bfoundIod = HalpMcBusEnum( &mcCtx ) ) { + + // + // Read the IOD error register to determine the source of the + // error. + // + +#if 0 //HALDBG + DbgPrint( "(%d, %d) ", mcCtx.McDeviceId.Gid, mcCtx.McDeviceId.Mid); +#endif // HALDBG + + IodCapErr.all = READ_IOD_REGISTER_NEW( mcCtx.McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->CapErr ); + + if( (IodCapErr.PciErrValid != 0) || (IodCapErr.McErrValid != 0) ){ + break; + } + } + +#if 0 // HALDBG + if (bfoundIod) { + DbgPrint( "Found!\n"); + } else { + DbgPrint( "Error Not Found!\n"); + } +#endif // HALDBG + + // + // Return the McDeviceId and CapErr register contents + // of the first IOD that has an error. + // + + *pMcDeviceId = mcCtx.McDeviceId; + pIodCapErr->all = IodCapErr.all; + + return (bfoundIod); +} + +BOOLEAN +bHandleIsaError( + MC_DEVICE_ID McDeviceId, + IOD_CAP_ERR IodCapErrIn +) +/*++ + +Routine Description: + + Gives PCI-1,2,3 ISA legacy semantics for I/O and memory accesses. + +Arguments: + + None. + +Return Value: + + TRUE if the error was handled. + FALSE otherwise. + +--*/ +{ + + MC_ENUM_CONTEXT mcCtx; + MC_DEVICE_ID McDeviceIdWithMab; + ULONG numIods; + BOOLEAN bfoundIod; + IOD_CAP_ERR IodCapErr; + IOD_CAP_ERR IodCapErrMask; + + + // + // Find an IOD that has Mab set. If we do not find one, then + // we don't have this error. + // + + + numIods = HalpMcBusEnumStart ( HalpIodMask, &mcCtx ); + + // + // Search each Iod and look for a PCI or McBus error. + // + + while ( bfoundIod = HalpMcBusEnum( &mcCtx ) ) { + + // + // Read the IOD error register to determine who has Mab set + // + + IodCapErr.all = READ_IOD_REGISTER_NEW( mcCtx.McDeviceId, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->CapErr ); + + if( (IodCapErr.PciErrValid == 1) && + (IodCapErr.Perr == 0) && + (IodCapErr.Serr == 0) && + (IodCapErr.Mab == 1) && + (IodCapErr.PteInv == 0) ) { + break; + } + } + + // + // If we didn't find an IOD with Mab set, then do not handle this error. + // + + if (!bfoundIod) { + return FALSE; + } + + // + // Save the McDevice Id of the offending IOD + // + + McDeviceIdWithMab.all = mcCtx.McDeviceId.all; + + // + // This must be on a bus other than PCI0 for us to handle this error + // (PCI0 reads to non-existent ISA addresses will be fixed by by the + // PCI-EISA bridge. Thus we'll never get here on PCI0 unless there + // really is an error.) + // + + if ( McDeviceIdWithMab.Mid != MidPci0 ) { + + + IOD_PCI_ERR1 IodPciErr1; + + // + // Get the PCI address of the transaction that caused the MAB + // + + IodPciErr1.PciAddress = + (ULONG) READ_IOD_REGISTER_NEW( McDeviceIdWithMab, + &((PIOD_ERROR_CSRS)(IOD_ERROR_CSRS_QVA))->PciErr1 ); + + + // + // To be handled as an ISA legacy memory or I/O space read, the + // FaultingPciAddress must be in the range 0-1 Mb + // + + if( IodPciErr1.PciAddress < __1MB ) { + + // + // The error has matched all of our conditions. Assume that + // V0 has already been set to 0xffffffff. (This is a contract + // with the HAL access routines in iodio.s.) + // + + IodCapErrMask.all = ALL_CAP_ERRORS; + HalpClearAllIods( IodCapErrMask ); + + return TRUE; + + } + +#if HALDBG + DbgPrint( "Failed checking for legacy ISA read:\n"); + DbgPrint( "PciErr1 : %08x\n", IodPciErr1.PciAddress ); +#endif //HALDBG + + } + + // + // We have a PCI Mab on PCI0. Do not handle this error. + // + + return FALSE; + + } + +VOID +HalpErrorFrameString( + PUNCORRECTABLE_ERROR uncorr, + PUCHAR OutBuffer + ) +/*++ + +Routine Description: + + Append an Error message to the Uncorrectable Error Frame + string + +Arguments: + + uncorr - Pointer to the UNCORRECTABLE_ERROR frame. + + OutBuffer - message to be appended. + (If null, no string is appended, and pCurrentString + is reset to NULL). + + +Return Value: + + none. + +--*/ +{ + ULONG len; + static PCHAR pCurrentString = NULL; + + // + // If OutBuffer is NULL, reset pointer and flag + // + + if (OutBuffer == NULL) { + pCurrentString = NULL; + if (uncorr) uncorr->Flags.ErrorStringValid = 0; + return; + } + + // + // Uncorrectable frame valid? + // + + if (uncorr) { + + // + // On first error message: + // * Init pCurrentString to beginning of ErrorString + // * Set valid flag + // + + if (pCurrentString == NULL) { + pCurrentString = uncorr->ErrorString; + uncorr->Flags.ErrorStringValid = 1; + } + + // + // Append OutBuffer to ErrorString + // + + len = strlen(OutBuffer); + strncpy(pCurrentString, + OutBuffer, + len); + + // + // Zero-terminate the error string. + // + + pCurrentString += len; + *pCurrentString = 0; + + } +} + +ULONG +BuildActiveCpus ( + VOID + ) +{ + ULONG ActiveLogicalProcessors = HalpActiveProcessors; + ULONG ActivePhysicalCpus = 0; + ULONG i; + + // + // Make a physical processor mask from the logical processor mask + // + + for (i = 0; i < HalpNumberOfCpus; i++, ActiveLogicalProcessors >> 1) { + if (ActiveLogicalProcessors & 0x1) { + ActivePhysicalCpus |= (1 << (ULONG) (MCDEVID_TO_PHYS_CPU( + HalpLogicalToPhysicalProcessor[i].all))); + } + } + + return (ActivePhysicalCpus); + +} diff --git a/private/ntos/nthals/halraw/alpha/iodio.s b/private/ntos/nthals/halraw/alpha/iodio.s new file mode 100644 index 000000000..6edc5f9d0 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/iodio.s @@ -0,0 +1,2997 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + iodio.s + +Abstract: + + This module implements the I/O access routines for the IOD + (CAP/MDP) ASICs. + + The module contains the functions to turn quasi virtual + addresses into an Alpha superpage virtual address + and then read or write based on the request. + +Author: + + Eric Rehm 10-Apr-1995 + + +Environment: + + Executes in kernel mode. + +Revision History: + + +--*/ + +#include "halalpha.h" +#include "iod.h" + + +// +// Superpage VAs +// +// The following constants are used to construct the physical addresses +// used to access i/o space. +// +// assembler BUGBUG: +// +// The following values are hacks to get around the intelligent +// Alpha assemblers. Instead of sign extending 16 bit quantities greater +// than 32K-1, the assembler generates a ldah/lda pair to load exactly +// the sixteen bit quantity specified, without sign extending. +// +// By specifying the quantity as a negative number, the assembler allows +// a single lda instruction, with sign extension. +// + + +// +// ecrfix - these definitions are good for PCI 0 (GID = 7, MID = 4) ONLY!!! +// + + +#define IOD_SPARSE_MEM_SVA -0x3080 // negative of 0xcf80 +#define IOD_DENSE_MEM_SVA -0x3070 // negative of 0xcf90 +#define IOD_SPARSE_IO_SVA -0x3068 // negative of 0xcf98 +#define IOD_REGISTER_SVA -0x3062 // negative of 0xcf9E + +// +// These definitions are based on GID=0, MID=0 and can be used +// to construct an superpage address for any (GID, MID). +// + +#define IOD_PCI0_REGISTER_SVA -0x3062 // negative of 0xcf9E +#define IOD_REGISTER_NEW_SVA -0x3800 // negative of 0xc800 +#define IOD_IP_INTR_SVA -0x37ff // negative of 0xc801 (to CUD only) +#define IOD_INTTIM_SVA -0x37f0 // negative of 0xc810 (to CUD only) +#define IOD_IP_ACK_SVA -0x37ef // negative of 0xc811 (to CUD only) +#define IOD_MCHK_ACK_SVA -0x37ee // negative of 0xc812 (to CUD only) +#define IOD_HALT_ACK_SVA -0x37e9 // negative of 0xc817 (to CUD only) +#define IOD_PCI_CONFIG_SVA -0x37e4 // negative of 0xc81C +#define IOD_INT_ACK_SVA -0x37e1 // negative of 0xc81F + +#define IOD_TARGET0_OFFSET 0x3f00 +#define IOD_TARGET1_OFFSET 0x3f40 + +#define MabNumber 0 // offset of HalpMasterAbortExpected.Number +#define MabAddr 8 // offset of HalpMasterAbortExpected.Addr +#define MASTER_ABORT_NOT_EXPECTED 0xffffffff + +#define GET_PROCESSOR_CONTROL_BLOCK_BASE \ + call_pal rdpcr; \ + ldl v0, PcPrcb(v0) + + + SBTTL( "Return PCR address for current processor" ) +//++ +// +// PVOID +// HalpRdPcr( +// ) +// +// Routine Description: +// +// Calls PAL to obtain PCR for current processor +// +// Arguments: +// +// None +// +// Return Value: +// +// v0 - Address of PCR +// +//-- + + LEAF_ENTRY(HalpRdPcr) + + + call_pal rdpcr; // CallPal to read PCR + ret zero, (ra) // return + + .end HalpRdPcr + + + + SBTTL( "Read byte from PCI memory" ) +//++ +// +// UCHAR +// READ_REGISTER_UCHAR( +// IN PVOID RegisterQva +// ) +// +// Routine Description: +// +// Reads a byte location in PCI bus sparse memory space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of the I/O byte to read. +// +// Return Value: +// +// v0 - Returns the value read from I/O space. +// +//-- + + LEAF_ENTRY(READ_REGISTER_UCHAR) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 3, t3 // get byte lane + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 10f // if ne, iff failed + +// +// Sparse space access. +// + + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff cf80 + sll t4, 28, t4 // 0xffff fcf8 0000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + bis zero, 0xffffffff,v0 // ecrfix + + ldl v0, (t0) // get the longword + extbl v0, t3, v0 // get correct byte if eisa + + ret zero, (ra) // return + +// +// Dense space access. +// + +10: + zap a0, 0xf0, a0 // clear <63:32> + and a0, 3, t3 // capture byte offset + bic a0, 3, a0 // clear byte offset + and a0, IOD_DENSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_DENSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_DENSE_ENABLE, a0 // clear QVA fields <31:30> + lda t0, IOD_DENSE_MEM_SVA(zero) // 0xffff ffff ffff cf90 + sll t0, 28, t0 // 0xffff fcf9 0000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, a0, t0 // 0xffff fcf9 xxxx xxxx + bis zero, 0xffffffff,v0 // ecrfix + mb // ensure all writes are visible + ldl v0, 0(t0) // read from dense space + extbl v0, t3, v0 // extract appropriate byte + + ret zero, (ra) // return + + .end READ_REGISTER_UCHAR + + + + SBTTL( "Read byte from PCI sparse i/o" ) +//++ +// +// UCHAR +// READ_PORT_UCHAR( +// IN PVOID RegisterQva +// ) +// +// Routine Description: +// +// Reads a byte location in PCI bus sparse i/o space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of the I/O byte to read. +// +// Return Value: +// +// v0 - Returns the value read from I/O space. +// +//-- + + LEAF_ENTRY(READ_PORT_UCHAR) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 3, t3 // get byte lane + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 10f // if ne, iff failed + + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff cf98 0000 + sll t4, 28, t4 // 0xffff fcf9 8000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + bis zero, 0xffffffff,v0 // ecrfix + + mb // ensure all writes are visible + ldl v0, (t0) // get the longword + extbl v0, t3, v0 // get correct byte if eisa + + ret zero, (ra) // return + +// +// Illegal access, did not use a QVA. +// + +10: + +#if DBG + + BREAK_DEBUG_STOP // take a breakpoint + +#endif //DBG + + ldil v0, 0xffffffff // return fixed value + + ret zero, (ra) // return to caller + + .end READ_PORT_UCHAR + + + SBTTL( "Read short from PCI memory" ) +//++ +// +// UCHAR +// READ_REGISTER_USHORT( +// IN PVOID RegisterQva +// ) +// +// Routine Description: +// +// Reads a short location in PCI bus sparse memory space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of the memory short to read. +// +// Return Value: +// +// v0 - Returns the value read from PCI memory. +// +//-- + + LEAF_ENTRY(READ_REGISTER_USHORT) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 3, t3 // get short lane + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 10f // if ne, iff failed + +// +// Sparse space access. +// + + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff cf80 + sll t4, 28, t4 // 0xffff fcf8 0000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + + or t0, IO_WORD_LEN, t0 // set size to short + bis zero, 0xffffffff,v0 // ecrfix + + mb // ensure all writes are visible + ldl v0, (t0) // get the longword + extwl v0, t3, v0 // get correct byte if eisa + + ret zero, (ra) // return + +// +// Dense space access. +// + +10: + zap a0, 0xf0, a0 // clear <63:32> + and a0, 3, t3 // capture byte offset + bic a0, 3, a0 // clear byte offset + and a0, IOD_DENSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_DENSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_DENSE_ENABLE, a0 // clear QVA fields <31:30> + lda t0, IOD_DENSE_MEM_SVA(zero) // 0xffff ffff ffff cf90 + sll t0, 28, t0 // 0xffff fcf9 0000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, a0, t0 // 0xffff fcf9 xxxx xxxx + bis zero, 0xffffffff,v0 // ecrfix + ldl v0, 0(t0) // read from dense space + extwl v0, t3, v0 // extract appropriate word + + ret zero, (ra) // return + + .end READ_REGISTER_USHORT + + + SBTTL( "Read short from PCI sparse I/O" ) +//++ +// +// UCHAR +// READ_PORT_USHORT( +// IN PVOID RegisterQva +// ) +// +// Routine Description: +// +// Reads a short location in PCI bus sparse i/o space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of the i/o short to read. +// +// Return Value: +// +// v0 - Returns the value read from PCI I/O. +// +//-- + + LEAF_ENTRY(READ_PORT_USHORT) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 3, t3 // get short lane + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 10f // if ne, iff failed + + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98 + sll t4, 28, t4 // 0xffff fcf9 8000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + + or t0, IO_WORD_LEN, t0 // set size to short + bis zero, 0xffffffff,v0 // ecrfix + + mb // ensure all writes are visible + ldl v0, (t0) // get the longword + extwl v0, t3, v0 // get correct byte if eisa + + ret zero, (ra) // return + +// +// Illegal access, did not use a QVA. +// + +10: + +#if DBG + + BREAK_DEBUG_STOP // take a breakpoint + +#endif //DBG + + ldil v0, 0xffffffff // return fixed value + + ret zero, (ra) // return to caller + + .end READ_PORT_USHORT + + + SBTTL( "Read long from PCI memory" ) +//++ +// +// UCHAR +// READ_REGISTER_ULONG( +// IN PVOID RegisterQva +// ) +// +// Routine Description: +// +// Reads a long location in PCI bus sparse memory space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of the memory long to read. +// +// Return Value: +// +// v0 - Returns the value read from PCI memory. +// +//-- + + LEAF_ENTRY(READ_REGISTER_ULONG) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 10f // if ne, iff failed + +// +// Sparse space access. +// + + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff cf80 + sll t4, 28, t4 // 0xffff fcf8 0000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + + or t0, IO_LONG_LEN, t0 // set size to long + + mb // ensure all writes are visible + bis zero, 0xffffffff,v0 // ecrfix + ldl v0, (t0) // get the longword +#if 0 //mdbfix support Canonical ULONG form + extll v0, 0, v0 // if NXM, make exception more precise +#endif + + ret zero, (ra) // return + +// +// Dense space access. +// + +10: + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_DENSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_DENSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_DENSE_ENABLE, a0 // clear QVA fields <31:30> + lda t0, IOD_DENSE_MEM_SVA(zero) // 0xffff ffff ffff cf90 + sll t0, 28, t0 // 0xffff fcf9 0000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, a0, t0 // 0xffff fcf9 xxxx xxxx + bis zero, 0xffffffff,v0 // ecrfix + ldl v0, 0(t0) // read from dense space +#if 0 //mdbfix support Canonical ULONG form + extll v0, 0, v0 // if NXM, make exception more precise +#endif + + ret zero, (ra) // return + + .end READ_REGISTER_ULONG + + + SBTTL( "Read long from PCI sparse I/O" ) +//++ +// +// UCHAR +// READ_PORT_ULONG( +// IN PVOID RegisterQva +// ) +// +// Routine Description: +// +// Reads a long location in PCI bus sparse i/o space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of the i/o long to read. +// +// Return Value: +// +// v0 - Returns the value read from PCI I/O. +// +//-- + + LEAF_ENTRY(READ_PORT_ULONG) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 3, t3 // get short lane + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 10f // if ne, iff failed + + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf80 + sll t4, 28, t4 // 0xffff fcf8 0000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + + or t0, IO_LONG_LEN, t0 // set size to short + + bis zero, 0xffffffff,v0 // ecrfix + + mb // ensure all writes are visible + ldl v0, (t0) // get the longword + + ret zero, (ra) // return + +// +// Illegal access, did not use a QVA. +// + +10: + +#if DBG + + BREAK_DEBUG_STOP // take a breakpoint + +#endif //DBG + + ldil v0, 0xffffffff // return fixed value + + ret zero, (ra) // return to caller + + .end READ_PORT_ULONG + + + SBTTL( "Write byte to PCI memory" ) +//++ +// +// VOID +// WRITE_REGISTER_UCHAR( +// IN PVOID RegisterQva +// IN UCHAR Value +// ) +// +// Routine Description: +// +// Write a byte location to PCI bus sparse memory space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of the memory byte to write. +// +// Value(a1) - Supplies the value written to I/O space. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(WRITE_REGISTER_UCHAR) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 3, t3 // get byte lane + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 10f // if ne, iff failed + +// +// Sparse space access. +// + + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff cf80 + sll t4, 28, t4 // 0xffff fcf8 0000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + + insbl a1, t3, v0 // insert to proper byte lane + stl v0, (t0) // store the longword + mb // order the write + + ret zero, (ra) // return + +// +// Dense space access. +// + +10: + zap a0, 0xf0, a0 // clear <63:32> + bic a0, 3, a0 // clear byte offset + and a0, IOD_DENSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_DENSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_DENSE_ENABLE, a0 // clear QVA fields <31:30> + lda t0, IOD_DENSE_MEM_SVA(zero) // 0xffff ffff ffff cf90 + sll t0, 28, t0 // 0xffff fcf9 0000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, a0, t0 // 0xffff fcf9 xxxx xxxx + + ldl t1, (t0) // get the long + mskbl t1, t3, t1 // mask the proper byte + + + insbl a1, t3, a1 // insert to appropriate byte lane + bis a1, t1, a1 // merge byte in result + stl a1, (t0) // write to dense space + mb // order subsequent reads/writes + + ret zero, (ra) // return + + .end WRITE_REGISTER_UCHAR + + + SBTTL( "Write byte to PCI sparse i/o" ) +//++ +// +// VOID +// WRITE_PORT_UCHAR( +// IN PVOID RegisterQva +// IN UCHAR Value +// ) +// +// Routine Description: +// +// Write a byte location to PCI bus sparse memory space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of the memory byte to write. +// +// Value(a1) - Supplies the value written to I/O space. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(WRITE_PORT_UCHAR) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 3, t3 // get byte lane + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 10f // if ne, iff failed + + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98 + sll t4, 28, t4 // 0xffff fcf9 8000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + + insbl a1, t3, v0 // insert to proper byte lane + stl v0, (t0) // store the longword + mb // order the write + + ret zero, (ra) // return + +// +// Illegal access, did not use a QVA. +// + +10: + +#if DBG + + BREAK_DEBUG_STOP // take a breakpoint + +#endif //DBG + + ret zero, (ra) // return to caller + + .end WRITE_PORT_UCHAR + + + SBTTL( "Write short to PCI memory" ) +//++ +// +// VOID +// WRITE_REGISTER_USHORT( +// IN PVOID RegisterQva +// IN UCHAR Value +// ) +// +// Routine Description: +// +// Write a short to PCI bus sparse memory space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of the memory short to write. +// +// Value(a1) - Supplies the value written to I/O space. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(WRITE_REGISTER_USHORT) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 3, t3 // get short lane + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 10f // if ne, iff failed + +// +// Sparse space access. +// + + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff cf80 + sll t4, 28, t4 // 0xffff fcf8 0000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + + or t0, IO_WORD_LEN, t0 // set size to short + + inswl a1, t3, v0 // insert to proper short lane + stl v0, (t0) // store the longword + mb // order the write + + ret zero, (ra) // return + +// +// Dense space access. +// + +10: + zap a0, 0xf0, a0 // clear <63:32> + bic a0, 3, a0 // clear byte offset + and a0, IOD_DENSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_DENSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_DENSE_ENABLE, a0 // clear QVA fields <31:30> + lda t0, IOD_DENSE_MEM_SVA(zero) // 0xffff ffff ffff cf90 + sll t0, 28, t0 // 0xffff fcf9 0000 0000 + or t0, t2, t0 // add BusNum in MID field + bis t0, a0, t0 // 0xffff fcf9 xxxx xxxx + ldl t1, (t0) // get the long + mskwl t1, t3, t1 // mask the proper word + inswl a1, t3, a1 // insert to appropriate short lane + bis a1, t1, a1 // merge in result + stl a1, (t0) // write to dense space + mb // order subsequent reads/writes + + ret zero, (ra) // return + + .end WRITE_REGISTER_USHORT + + + SBTTL( "Write short to PCI sparse i/o" ) +//++ +// +// VOID +// WRITE_PORT_USHORT( +// IN PVOID RegisterQva +// IN UCHAR Value +// ) +// +// Routine Description: +// +// Write a byte location to PCI bus sparse memory space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of the memory byte to write. +// +// Value(a1) - Supplies the value written to I/O space. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(WRITE_PORT_USHORT) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 3, t3 // get short lane + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 10f // if ne, iff failed + + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98 + sll t4, 28, t4 // 0xffff fcf9 8000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + + or t0, IO_WORD_LEN, t0 // set size to short + + inswl a1, t3, v0 // insert to proper short lane + stl v0, (t0) // store the longword + mb // order the write + + ret zero, (ra) // return + +// +// Illegal access, did not use a QVA. +// + +10: + +#if DBG + + BREAK_DEBUG_STOP // take a breakpoint + +#endif //DBG + + ret zero, (ra) // return to caller + + .end WRITE_PORT_USHORT + + + + SBTTL( "Write long to PCI memory" ) +//++ +// +// VOID +// WRITE_REGISTER_ULONG( +// IN PVOID RegisterQva +// IN UCHAR Value +// ) +// +// Routine Description: +// +// Write a long to PCI bus sparse memory space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of the memory long to write. +// +// Value(a1) - Supplies the value written to I/O space. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(WRITE_REGISTER_ULONG) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 10f // if ne, iff failed + +// +// Sparse space access. +// + + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff cf80 + sll t4, 28, t4 // 0xffff fcf8 0000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + + or t0, IO_LONG_LEN, t0 // set size to long + + stl a1, (t0) // store the longword + mb // order the write + + ret zero, (ra) // return + +// +// Dense space access. +// + +10: + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_DENSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_DENSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_DENSE_ENABLE, a0 // clear QVA fields <31:30> + lda t0, IOD_DENSE_MEM_SVA(zero) // 0xffff ffff ffff cf90 + sll t0, 28, t0 // 0xffff fcf9 0000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, a0, t0 // 0xffff fcf9 xxxx xxxx + stl a1, 0(t0) // write to dense space + mb // order subsequent reads/writes + + ret zero, (ra) // return + + .end WRITE_REGISTER_ULONG + + + SBTTL( "Write long to PCI sparse i/o" ) +//++ +// +// VOID +// WRITE_PORT_ULONG( +// IN PVOID RegisterQva +// IN UCHAR Value +// ) +// +// Routine Description: +// +// Write a long to PCI bus sparse memory space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of the I/O long to write. +// +// Value(a1) - Supplies the value written to I/O space. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(WRITE_PORT_ULONG) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 10f // if ne, iff failed + + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98 + sll t4, 28, t4 // 0xffff fcf9 8000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + + or t0, IO_LONG_LEN, t0 // set size to long + + stl a1, (t0) // store the longword + mb // order the write + + ret zero, (ra) // return + +// +// Illegal access, did not use a QVA. +// + +10: + +#if DBG + + BREAK_DEBUG_STOP // take a breakpoint + +#endif //DBG + + ret zero, (ra) // return to caller + + .end WRITE_PORT_ULONG + + + SBTTL( "Write IOD Register" ) +//++ +// +// VOID +// WRITE_IOD_REGISTER( +// IN PVOID RegisterQva, +// IN ULONG Value +// ) +// +// Routine Description: +// +// Write an IOD control register. +// +// Arguments: +// +// RegisterQva(a0) - QVA of control register to be written. +// +// Value(a1) - Longword value to be written to the control register. +// +// Return Value: +// +// None. +// +// N.B. Since the physical address of the IOD CSRS exceed the 34 bit +// capacity of the QVAs, the QVA values of the IOD CSRS specify +// the offset of the QVAs from the IOD CSR base address (89.e000.0000) +//-- + + LEAF_ENTRY(WRITE_IOD_REGISTER) + + ALTERNATE_ENTRY(WRITE_GRU_REGISTER) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 10f // if ne, iff failed + + zap a0, 0xf0, a0 // clear <63:32> + bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // + lda t4, IOD_REGISTER_SVA(zero) // 0xffff ffff ffff cf9e + sll t4, 28, t4 // 0xffff fcf9 e000 0000 + or t0, t4, t0 // superpage mode + stl a1, (t0) // write the longword + mb // order the write + ret zero, (ra) // return + +10: + BREAK_DEBUG_STOP // take a breakpoint + ret zero, (ra) // return + + .end WRITE_IOD_REGISTER + + + SBTTL( "Read IOD Register" ) +//++ +// +// ULONG +// READ_IOD_REGISTER( +// IN PVOID RegisterQva +// ) +// +// Routine Description: +// +// Read an IOD Control register +// +// Arguments: +// +// RegisterQva(a0) - QVA of control register to be written. +// +// Return Value: +// +// v0 - Return the value read from the control register. +// +//-- + + LEAF_ENTRY(READ_IOD_REGISTER) + +// +// Generate the superpage address of the requested IOD register. +// + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 20f // if ne, iff failed + + zap a0, 0xf0, a0 // clear <63:32> + bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // + lda t4, IOD_REGISTER_SVA(zero) // 0xffff ffff ffff cf9e + sll t4, 28, t4 // 0xffff fcf9 e000 0000 + or t0, t4, t0 // superpage mode + +// +// Perform the read of the requested IOD register and return. +// + + ldl v0, (t0) // read the register + + ret zero, (ra) // return + +// +// The requested IOD register address is bogus. Stop in the debugger so +// we can find the culprit. +// + +20: // flag bad QVAs + BREAK_DEBUG_STOP // take a breakpoint + + ret zero, (ra) // return + + .end READ_IOD_REGISTER + + + SBTTL( "Write IOD Register_New" ) +//++ +// +// VOID +// WRITE_IOD_REGISTER_NEW( +// IN ULONG McDevid +// IN PVOID RegisterQva, +// IN ULONG Value +// ) +// +// Routine Description: +// +// Write a IOD control register. +// +// Arguments: +// +// McDevid(a0) - MC Bus Device ID of this IOD +// +// RegisterQva(a1) - Qva of control register to be written. +// N.B. RegisterQva *does not* specifiy which IOD to write to. +// That's why we pass in McDevid +// +// Value(a2) - Longword value to be written to the control register. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(WRITE_IOD_REGISTER_NEW) + +// +// Generate the superpage address of the requested IOD register. +// + + // Args are actually byte values: + and a1, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 10f // if ne, iff failed + + zap a1, 0xf0, a1 // clear <63:32> + bic a1, QVA_ENABLE, a1 // clear QVA fields so shift is correct + sll a1, IO_BIT_SHIFT, t4 // shift RegisterOffset into position + + extbl a0, zero, a0 // McDevId + + lda t0, IOD_REGISTER_NEW_SVA(zero) // 0xffff ffff ffff c800 + sll a0, 5, t1 // shift McDevId into position + bis t0, t1, t0 // create SVA for this IOD + sll t0, 28, t0 // 0xffff fcXX 0000 0000 + + or t0, t4, t0 // superpage mode + stl a2, (t0) // write the longword + mb // order the write + ret zero, (ra) // return + +// +// The requested IOD register address is bogus. Stop in the debugger so +// we can find the culprit. +// + +10: + BREAK_DEBUG_STOP // take a breakpoint + ret zero, (ra) // return + + .end WRITE_IOD_REGISTER_NEW + + + SBTTL( "Read IOD Register_NEW" ) +//++ +// +// ULONG +// READ_IOD_REGISTER_NEW( +// IN ULONG McDevid +// IN ULONG RegisterOffset +// ) +// +// Routine Description: +// +// Read an IOD Control register +// +// Arguments: +// +// McDevid(a0) - MC Bus Device ID of this IOD. +// +// RegisterQva(a1) - QVA of control register to be read. +// +// Return Value: +// +// v0 - Return the value read from the control register. +// +//-- + + LEAF_ENTRY(READ_IOD_REGISTER_NEW) + +// +// Generate the superpage address of the requested IOD register. +// + + and a1, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 10f // if ne, iff failed + + zap a1, 0xf0, a1 // clear <63:32> + bic a1, QVA_ENABLE, a1 // clear QVA fields so shift is correct + sll a1, IO_BIT_SHIFT, t4 // shift RegisterQva into position + + extbl a0, zero, a0 // McDevId + + lda t0, IOD_REGISTER_NEW_SVA(zero) // 0xffff ffff ffff c800 + sll a0, 5, t1 // shift McDevId into position + bis t0, t1, t0 // create SVA for this IOD + sll t0, 28, t0 // 0xffff fcXX 0000 0000 + + or t0, t4, t0 // superpage mode + +// +// Perform the read of the requested IOD register and return. +// + + ldl v0, (t0) // read the register + + ret zero, (ra) // return + +// +// The requested IOD register address is bogus. Stop in the debugger so +// we can find the culprit. +// + +10: + BREAK_DEBUG_STOP // take a breakpoint + ret zero, (ra) // return + + .end READ_IOD_REGISTER_NEW + + + SBTTL( "Read Buffer from Port Space in Uchars") +//++ +// +// VOID +// READ_PORT_BUFFER_UCHAR( +// IN PVOID PortQva, +// IN PUCHAR Buffer, +// IN ULONG Count +// ) +// +// Routine Description: +// +// Read multiple bytes from the specified port address into the +// destination buffer. +// +// Arguments: +// +// PortQva(a0) - Supplies the QVA of the port to read. +// +// Buffer(a1) - Supplies a pointer to the buffer to fill with +// the data read from the port. +// +// Count(a2) - Supplies the number of bytes to read. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(READ_PORT_BUFFER_UCHAR) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 30f // if ne, iff failed + + and a0, 3, t3 // get byte we need if eisa + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98 + sll t4, 28, t4 // 0xffff fcf9 8000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + +10: beq a2, 20f // while count > 0 + + ldl v0, (t0) // get the longword + subl a2, 1, a2 // decrement count + extbl v0,t3,v0 // get the correct byte + stb v0,(a1) // cheat and let the assembler do it + addl a1, 1, a1 // next byte in buffer + br zero, 10b // end while +20: + ret zero, (ra) // return + +// +// Illegal access, did not use a QVA. +// + +30: + +#if DBG + + BREAK_DEBUG_STOP // take a breakpoint + +#endif //DBG + + ldil v0, 0xffffffff // return fixed value + + ret zero, (ra) // return to caller + + .end READ_PORT_BUFFER_UCHAR + + + SBTTL( "Read Buffer from Port Space in Ushorts") +//++ +// +// VOID +// READ_PORT_BUFFER_USHORT( +// IN PVOID PortQva, +// IN PUSHORT Buffer, +// IN ULONG Count +// ) +// +// Routine Description: +// +// Read multiple words from the specified port address into the +// destination buffer. +// +// Arguments: +// +// PortQva(a0) - Supplies the QVA of the port to read. +// +// Buffer(a1) - Supplies a pointer to the buffer to fill with +// the data read from the port. +// +// Count(a2) - Supplies the number of words to read. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(READ_PORT_BUFFER_USHORT) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 30f // if ne, iff failed + + and a0, 3, t3 // get word we need + zap a0, 0xf0, a0 // clear <63:32> + + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98 + sll t4, 28, t4 // 0xffff fcf9 8000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + or t0, IO_WORD_LEN, t0 // or in the byte enables + +10: beq a2, 20f // while count > 0 + + ldl v0, (t0) // get the longword + subl a2, 1, a2 // decrement count + extwl v0,t3,v0 // get the correct word + stw v0,(a1) // cheat and let the assembler do it + addl a1, 2, a1 // next word in buffer + br zero, 10b // end while +20: + ret zero, (ra) // return + +// +// Illegal access, did not use a QVA. +// + +30: + +#if DBG + + BREAK_DEBUG_STOP // take a breakpoint + +#endif //DBG + + ldil v0, 0xffffffff // return fixed value + + ret zero, (ra) // return to caller + + .end READ_PORT_BUFFER_USHORT + + SBTTL( "Read Buffer from Port Space in Ulongs") +//++ +// +// VOID +// READ_PORT_BUFFER_ULONG( +// IN PVOID PortQva, +// IN PULONG Buffer, +// IN ULONG Count +// ) +// +// Routine Description: +// +// Read multiple longwords from the specified port address into the +// destination buffer. +// +// Arguments: +// +// PortQva(a0) - Supplies the QVA of the port to read. +// +// Buffer(a1) - Supplies a pointer to the buffer to fill with +// the data read from the port. +// +// Count(a2) - Supplies the number of longwords to read. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(READ_PORT_BUFFER_ULONG) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 30f // if ne, iff failed + + zap a0, 0xf0, a0 // clear <63:32> + + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + + lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98 + sll t4, 28, t4 // 0xffff fcf9 8000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + or t0, IO_LONG_LEN, t0 // or in the byte enables + +10: beq a2, 20f // while count > 0 + + ldl v0, (t0) // get the longword + subl a2, 1, a2 // decrement count + stl v0,(a1) // cheat and let the assembler do it + addl a1, 4, a1 // next word in buffer + br zero, 10b // end while +20: + ret zero, (ra) // return + +// +// Illegal access, did not use a QVA. +// + +30: + +#if DBG + + BREAK_DEBUG_STOP // take a breakpoint + +#endif //DBG + + ldil v0, 0xffffffff // return fixed value + + ret zero, (ra) // return to caller + + .end READ_PORT_BUFFER_ULONG + + + SBTTL( "Write Buffer to Port Space in Uchars") +//++ +// +// VOID +// WRITE_PORT_BUFFER_UCHAR( +// IN PVOID PortQva, +// IN PUCHAR Buffer, +// IN ULONG Count +// ) +// +// Routine Description: +// +// Write multiple bytes from the source buffer to the specified port +// address. +// +// Arguments: +// +// PortQva(a0) - Supplies the QVA of the port to write. +// +// Buffer(a1) - Supplies a pointer to the buffer containing the data +// to write to the port. +// +// Count(a2) - Supplies the number of bytes to write. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(WRITE_PORT_BUFFER_UCHAR) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 30f // if ne, iff failed + + and a0, 3, t3 // get byte we need if eisa + zap a0, 0xf0, a0 // clear <63:32> + + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98 + sll t4, 28, t4 // 0xffff fcf9 8000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + +10: beq a2, 20f // copy while a2 > 0 + + ldq_u t1, 0(a1) // get quad surrounding byte + subl a2, 1, a2 // decrement count + extbl t1, a1, t1 // extract appropriate byte + addl a1, 1, a1 // increment buffer pointer + insbl t1, t3, t1 // put byte to appropriate lane + stl t1, 0(t0) // store to port + mb // push writes off chip + br zero, 10b // end while + +20: + ret zero, (ra) // return + +// +// Illegal access, did not use a QVA. +// + +30: + +#if DBG + + BREAK_DEBUG_STOP // take a breakpoint + +#endif //DBG + + ret zero, (ra) // return to caller + + + .end WRITE_PORT_BUFFER_UCHAR + + SBTTL( "Write Buffer to Port Space in Ushorts") +//++ +// +// VOID +// WRITE_PORT_BUFFER_USHORT( +// IN PVOID PortQva, +// IN PSHORT Buffer, +// IN ULONG Count +// ) +// +// Routine Description: +// +// Write multiple words from the source buffer to the specified port +// address. +// +// Arguments: +// +// PortQva(a0) - Supplies the QVA of the port to write. +// +// Buffer(a1) - Supplies a pointer to the buffer containing the data +// to write to the port. +// +// Count(a2) - Supplies the number of words to write. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(WRITE_PORT_BUFFER_USHORT) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 30f // if ne, iff failed + + and a0, 3, t3 // get word we need + zap a0, 0xf0, a0 // clear <63:32> + + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98 + sll t4, 28, t4 // 0xffff fcf9 8000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + or t0, IO_WORD_LEN, t0 // or in the byte enables + +10: beq a2, 20f // copy while a2 > 0 + + ldq_u t1, 0(a1) // get quad surrounding word + subl a2, 1, a2 // decrement count + extwl t1, a1, t1 // extract appropriate word + addl a1, 2, a1 // increment buffer pointer + inswl t1, t3, t1 // put word in appropriate lane + stl t1, 0(t0) // store to port + mb // push the write off the chip + br zero, 10b // end while + +20: + ret zero, (ra) // return + +// +// Illegal access, did not use a QVA. +// + +30: + +#if DBG + + BREAK_DEBUG_STOP // take a breakpoint + +#endif //DBG + + ret zero, (ra) // return to caller + + .end WRITE_PORT_BUFFER_USHORT + + + SBTTL( "Write Buffer to Port Space in Ulongs") +//++ +// +// VOID +// WRITE_PORT_BUFFER_ULONG( +// IN PVOID PortQva, +// IN PULONG Buffer, +// IN ULONG Count +// ) +// +// Routine Description: +// +// Write multiple longwords from the source buffer to the specified port +// address. +// +// Arguments: +// +// PortQva(a0) - Supplies the QVA of the port to write. +// +// Buffer(a1) - Supplies a pointer to the buffer containing the data +// to write to the port. +// +// Count(a2) - Supplies the number of longwords to write. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(WRITE_PORT_BUFFER_ULONG) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 30f // if ne, iff failed + + zap a0, 0xf0, a0 // clear <63:32> + + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98 + sll t4, 28, t4 // 0xffff fcf9 8000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + or t0, IO_LONG_LEN, t0 // or in the byte enables + +10: beq a2, 20f // copy while a2 > 0 + + ldl t1, 0(a1) // a1 must be longword aligned + subl a2, 1, a2 // decrement count + stl t1, 0(t0) // store to port + mb // push write off the chip + addl a1, 4, a1 // increment buffer + br zero, 10b // end while + +20: + ret zero, (ra) // return + +// +// Illegal access, did not use a QVA. +// + +30: + +#if DBG + + BREAK_DEBUG_STOP // take a breakpoint + +#endif //DBG + + ret zero, (ra) // return to caller + + .end WRITE_PORT_BUFFER_ULONG + + + SBTTL( "Read Buffer from PCI Memory Space in Uchars") +//++ +// +// VOID +// READ_REGISTER_BUFFER_UXXXXX( +// IN PVOID RegisterQva, +// IN PUCHAR Buffer, +// IN ULONG Count +// ) +// +// Routine Description: +// +// Copies a buffer from PCI Memory Space to an in-memory buffer. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the starting QVA of the memory space buffer. +// +// Buffer(a1) - Supplies a pointer to the in-memory buffer to receive +// the copied data. +// +// Count(a2) - Supplies the number of bytes, words or longwords to write. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(READ_REGISTER_BUFFER_ULONG) + + sll a2, 1, a2 // convert number of longs to words + + ALTERNATE_ENTRY(READ_REGISTER_BUFFER_USHORT) + + + sll a2, 1, a2 // convert number of words to chars + + ALTERNATE_ENTRY(READ_REGISTER_BUFFER_UCHAR) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + beq t1, 1f // if (eq) go do sparse space + +// +// Dense space access: QVA is an offset into dense space +// Set IO address in t0 +// + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_DENSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_DENSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_DENSE_ENABLE, a0 // clear QVA fields <31:30> + lda t0, IOD_DENSE_MEM_SVA(zero) // 0xffff ffff ffff cf90 + sll t0, 28, t0 // 0xffff fcf9 0000 0000 + or t0, t2, t0 // add BusNum in MID field + or a0, t0, t0 // superpage mode: add offset to base + + ldil a3, 1 // Offset to next byte + ldil a4, 4 // Offset to next long + ldil a5, 0 // LONG LEN ENABLE + + br zero 2f // go do the actual transfer + +// +// Sparse memory +// Set IO address in t0 +// + +1: + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff cf80 + sll t4, 28, t4 // 0xffff fcf8 0000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + + ldil a3, IO_BYTE_OFFSET // Offset to next byte + ldil a4, IO_LONG_OFFSET // Offset to next long + ldil a5, IO_LONG_LEN // LONG LEN ENABLE + +// +// Do the ACTUAL TRANSFER +// a2 = count in characters +// + +2: + beq a2, 60f // if count == 0 goto 60f (return) + +// +// Check alignment of src and destn +// + + and a0, 3, t3 // source alignment = t3 + and a1, 3, t2 // destination alignment = t2 + xor t2, t3, t4 // t4 = t2 xor t3 + bne t4, 70f // if (t4!=0) do unaligned copy + // else do byte copies till alignment + + beq t3, 20f // if t3==0 go do long word copies + // else do byte copies till alignment + +// +// Src and Destn are not longword aligned but have same alignment +// (sympathetically aligned) copy till alignment +// + +10: + beq a2, 60f // if count == 0 goto 60f (return) + + bis zero, 0xffffffff,v0 // ecrfix + ldl v0, 0(t0) // get the longword + subl a2, 1, a2 // decrement count + extbl v0, t3,v0 // get the correct byte + stb v0, (a1) // cheat and let the assembler do it + addq t0, a3, t0 // next I/O address + addl a1, 1, a1 // next byte in buffer + addl t3, 1, t3 // next byte in lane + and t3, 3, t3 // longword lanes + bne t3, 10b // while unaligned + +// +// Src and Destn have same alignment and are longword aligned +// + +20: + srl a2, 2, t3 // t3= #longwords to move + beq t3, 40f // if #longwords == 0 goto 40f + or t0, a5, t0 // We will now do LONG READS + +30: + bis zero, 0xffffffff,v0 // ecrfix + ldl v0, 0(t0) // get the longword + subl t3, 1, t3 // decrement long word count + stl v0, (a1) // store the longword at destn + addq t0, a4, t0 // next I/O address + addl a1, 4, a1 // next longword in buffer + bne t3, 30b // while #longwords > 0 + +// +// Do byte copies of remaining data uncopied +// + bic t0, a5, t0 // We will now do BYTE READS +40: + and a2, 3, a2 // remaining Bytes to copy + beq a2, 60f // if count == 0 goto 60f + +50: + bis zero, 0xffffffff,v0 // ecrfix + ldl v0, 0(t0) // get the longword + subl a2, 1, a2 // decrement count + extbl v0, t3,v0 // get the correct byte + stb v0, (a1) // cheat and let the assembler do it + addl a1, 1, a1 // next byte in buffer + addq t0, a3, t0 // next I/O address + addl t3, 1, t3 // next byte in lane + and t3, 3, t3 // longword lanes + bne a2, 50b // while count > 0 + +60: + ret zero, (ra) // return + + +// +// source IO alignment != destination memory alignment +// move enough bytes to longword align the IO source +// then move 32bit (longwords) storing unaligned into memory +// then move residual bytes +// +// Align src IO addresses; unaligned destn memory +// + +70: + beq t3, 90f // branch if source is long aligned +// +// Move bytes until IO src is at a longword boundary or bytes exhausted +// + +80: + beq a2, 130f // if count == 0 goto 130f (return) + + bis zero, 0xffffffff,v0 // ecrfix + ldl v0, 0(t0) // get the longword + subl a2, 1, a2 // decrement count + extbl v0, t3,v0 // get the correct byte + stb v0, (a1) // cheat and let the assembler do it + addl a1, 1, a1 // next byte in buffer + addq t0, a3, t0 // next I/O address + addl t3, 1, t3 // next byte in lane + and t3, 3, t3 // longword lanes + bne t3, 80b // while unaligned + +// +// aligned IO source, unaligned memory destination +// + +90: + srl a2, 3, t3 // quadwords to move + beq t3, 110f // if no quads finish with bytes copies + + or t0, a5, t0 // We will now do LONG READS + +100: + // + // Decoding for Comment: + // S= sign, X= overwritten byte, V= Valid byte,assume destn align a1= 2 + // + bis zero, 0xffffffff,t1 // ecrfix + ldl t1, 0(t0) // load LW 0 from IO src SSSS 4321 + ldq_u t4, 0(a1) // load destn merge XXVV VVVV + ldq_u t5, 7(a1) // load destn next merge VVXX XXXX + subl t3, 1, t3 // decrement quadwords to move + + addq t0, a4, t0 // add LONG OFFSET to t0 + bis zero, 0xffffffff,t2 // ecrfix + ldl t2, 0(t0) // load LW 1 from IO src SSSS 8765 + + mskql t4, a1, t4 // mask low LW for merge 00VV VVVV + mskqh t5, a1, t5 // mask high LW for merge VV00 0000 + + zap t1, 0xf0, t1 // clear high LW for long 0 0000 4321 + sll t2, 32, t2 // get long 1 to high longword 8765 0000 + bis t1, t2, t1 // merge read quadword together8765 4321 + + addq t0, a4, t0 // increment to next long + + insql t1, a1, t6 // position low QW for merge 2100 0000 + insqh t1, a1, t7 // position high QW for merge 0087 6543 + + bis t4, t6, t4 // merge new data, low QW 21VV VVVV + bis t5, t7, t5 // merge new data, high QW VV87 6543 + + stq_u t5, 7(a1) // write high quadword + stq_u t4, 0(a1) // write low quadword + + lda a1, 8(a1) // increment memory pointer + bne t3, 100b // while quadwords to move + +// +// Do byte copies of the remaining data not yet copied +// + bic t0, a5, t0 // We will now do BYTE READS +110: + and a2, 7, a2 // remaining bytes to copy + beq a2, 130f // if count == 0 goto 130f (return) + +120: + bis zero, 0xffffffff,v0 // ecrfix + ldl v0, 0(t0) // get the longword + subl a2, 1, a2 // decrement count + extbl v0, t3,v0 // get the correct byte + stb v0, (a1) // cheat and let the assembler do it + addl a1, 1, a1 // next byte in buffer + addq t0, a3, t0 // next I/O address + addl t3, 1, t3 // next byte in lane + and t3, 3, t3 // longword lanes + bne a2, 120b // while count != 0 + +130: + ret zero, (ra) // return + + .end READ_REGISTER_BUFFER_ULONG // end for UCHAR & USHORT + + + SBTTL( "Write Buffer to PCI Memory Space in Uchars") +//++ +// +// VOID +// WRITE_REGISTER_BUFFER_UXXXXX( +// IN PVOID RegisterQva, +// IN PUCHAR Buffer, +// IN ULONG Count +// ) +// +// Routine Description: +// +// Copies an in-memory buffer to a PCI Memory Space buffer. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the starting QVA of the memory space buffer. +// +// Buffer(a1) - Supplies a pointer to the in-memory source buffer. +// +// Count(a2) - Supplies the number of bytes, words to longwords to write. +// +// Return Value: +// +// None. +// +//-- + LEAF_ENTRY(WRITE_REGISTER_BUFFER_ULONG) + + sll a2, 1, a2 // convert number of longs to words + + ALTERNATE_ENTRY(WRITE_REGISTER_BUFFER_USHORT) + + sll a2, 1, a2 // convert number of words to chars + + ALTERNATE_ENTRY(WRITE_REGISTER_BUFFER_UCHAR) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + beq t1, 1f // if (eq) go do sparse space + +// +// Dense space access: QVA is an offset into dense space +// Set IO address in t0 +// + + ldil t7, 1 // DENSE FLAG + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_DENSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_DENSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_DENSE_ENABLE, a0 // clear QVA fields <31:30> + lda t0, IOD_DENSE_MEM_SVA(zero) // 0xffff ffff ffff cf90 + sll t0, 28, t0 // 0xffff fcf9 0000 0000 + or t0, t2, t0 // add BusNum in MID field + or a0, t0, t0 // superpage mode: add offset to base + + ldil a3, 1 // Offset to next byte + ldil a4, 4 // Offset to next long + ldil a5, 0 // LONG LEN ENABLE + + br zero, 2f // go do the actual transfer + +// +// Sparse Space +// Set IO address in t0 +// + +1: + ldil t7, 0 // SPARSE FLAG + zap a0, 0xf0, a0 // clear <63:32> + and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA + sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position + + bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27> + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, IOD_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff cf80 + sll t4, 28, t4 // 0xffff fcf8 0000 0000 + or t0, t2, t0 // add BusNum in MID field + or t0, t4, t0 // superpage mode + + ldil a3, IO_BYTE_OFFSET // Offset to next byte + ldil a4, IO_LONG_OFFSET // Offset to next long + ldil a5, IO_LONG_LEN // LONG LEN ENABLE + +// +// Do the ACTUAL TRANSFER +// a2 = count in characters +// + +2: + beq a2, 60f // if count == 0 goto 60f (return) + +// +// Check alignment of src and destn +// + and a0, 3, t3 // destn alignment = t3 + and a1, 3, t2 // src alignment = t2 + xor t2, t3, t4 // t4 = t2 xor t3 + bne t4, 70f // if (t4!=0) do unaligned copy + // else do byte copies till alignment + + beq t3, 20f // if t3==0 go do longword copies + // else do byte copies till alignment + +// +// Src and Destn are not longword aligned but have same alignment +// (sympathetically aligned) copy till alignment +// + +10: + beq a2, 60f // if count == 0 goto 60f (return) + + ldq_u t1, 0(a1) // get quad surrounding byte + subl a2, 1, a2 // decrement count + extbl t1, a1, t1 // extract appropriate byte + addl a1, 1, a1 // increment buffer pointer + insbl t1, t3, t1 // get proper lane + + beq t7, 11f // if not DENSE goto 11f + +// +// Read\modify\write for DENSE space I/O +// + bic t0, 3, t9 // clear bits <1:0> of dest + ldl t10, 0(t9) // read dest long + mskbl t10, t3, t10 // poke out the byte we will write + bis t10, t1, t1 // merge in our byte + stl t1, 0(t9) // commit it + + br zero, 12f + +// +// We're in SPARSE space, so simply perform the write +// +11: + stl t1, 0(t0) // store byte to buffer (BYTE ENABLED) +12: + addq t0, a3, t0 // increment I/O buffer + addl t3, 1, t3 // increment bytelane + and t3, 3, t3 // longwords only + bne t3, 10b // loop while not long aligned + +// +// Src and Destn have same alignment and are longword aligned +// + +20: + srl a2, 2, t3 // t3= #longwords to move + beq t3, 40f // if #longwords == 0 goto 40f + or t0, a5, t0 // We will now do LONG WRITE + +30: + ldl t1, 0(a1) // get the longword + addl a1, 4, a1 // increment buffer pointer + subl t3, 1, t3 // decrement #longwords by 1 + stl t1, 0(t0) // store long to buffer + addq t0, a4, t0 // increment I/O buffer + bne t3, 30b // while #longwords > 0 + +// +// Do byte copies of remaining data uncopied +// + bic t0, a5, t0 // Stop doing LONG WRITE + +40: + and a2, 3, a2 // remaining Bytes to copy + beq a2, 60f // if count == 0 goto 60f (return) + +50: + ldq_u t1, 0(a1) // get quad surrounding byte + subl a2, 1, a2 // decrement count + extbl t1, a1, t1 // extract appropriate byte + addl a1, 1, a1 // increment buffer pointer + insbl t1, t3, t1 // get proper lane + + beq t7, 51f // if not DENSE goto 51f + +// +// Read\modify\write for DENSE space I/O +// + bic t0, 3, t9 // clear bits <1:0> of dest + ldl t10, 0(t9) // read dest long + mskbl t10, t3, t10 // poke out the byte we will write + bis t10, t1, t1 // merge in our byte + stl t1, 0(t9) // commit it + + br zero, 52f + +// +// We're in SPARSE space, so simply perform the write +// +51: + stl t1, 0(t0) // store to buffer +52: + addq t0, a3, t0 // increment I/O buffer + addl t3, 1, t3 // increment bytelane + and t3, 3, t3 // longwords only + bne a2, 50b // while count != 0 + +60: + mb // push writes off chip + ret zero, (ra) // return + +// +// destn IO alignment != Src memory alignment +// move enough bytes to longword align the IO destn +// then move 32bit (longwords) reading unaligned data from memory +// then move residual bytes +// + +70: + beq t3, 90f // branch if destn is long aligned + +// +// Move bytes until IO destn is at a longword boundary or bytes exhausted +// + +80: + beq a2, 130f // if count == 0 goto 130f (return) + + ldq_u t1, 0(a1) // get quad surrounding byte + extbl t1, a1, t1 // extract appropriate byte + insbl t1, t3, t1 // get proper lane + + beq t7, 81f // if not DENSE goto 81f + +// +// Read\modify\write for DENSE space I/O +// + bic t0, 3, t9 // clear bits <1:0> of dest + ldl t10, 0(t9) // read dest long + mskbl t10, t3, t10 // poke out the byte we will write + bis t10, t1, t1 // merge in our byte + stl t1, 0(t9) // commit it + + br zero, 82f + +// +// We're in SPARSE space, so simply perform the write +// +81: + stl t1, 0(t0) // store byte to buffer (BYTE ENABLED) +82: + subl a2, 1, a2 // decrement count + addl a1, 1, a1 // increment buffer pointer + addq t0, a3, t0 // increment I/O buffer + addl t3, 1, t3 // increment bytelane + and t3, 3, t3 // longwords only + bne t3, 80b // loop if not long aligned + +// +// aligned IO destn, unaligned memory src +// + +90: + srl a2, 3, t3 // t3 = quadwords to move + beq t3, 110f // if no quads finish with bytes copies + + or t0, a5, t0 // We will now do LONG WRITES + +100: + ldq_u t1, 0(a1) // load low source quadword + ldq_u t2, 7(a1) // load high source quadword + extql t1, a1, t1 // extract low portion of quadword + extqh t2, a1, t2 // extract high portion of quadword + or t1, t2, t1 // merge to get the source quadword + stl t1, 0(t0) // store the long word (LONG ENABLED) + + lda a1, 8(a1) // next source quadword + srl t1, 32, t1 // get high longword into position + subl t3, 1, t3 // decrement number of quadwords to move + addq t0, a4, t0 // add LONG OFFSET to t0 + stl t1, (t0) // store the second long word + + addq t0, a4, t0 // increment to next dest. long + bne t3, 100b // while quadwords to move +// +// Do byte copies of the remaining data not yet copied +// + bic t0, a5, t0 // We will now do BYTE WRITES +110: + and a2, 7, a2 // remaining Bytes to copy + beq a2, 130f // if count == 0 goto 130f (return) + +120: + ldq_u t1, 0(a1) // get quad surrounding byte + subl a2, 1, a2 // decrement count + extbl t1, a1, t1 // extract appropriate byte + addl a1, 1, a1 // increment buffer pointer + insbl t1, t3, t1 // get proper lane + + beq t7, 121f // if not DENSE goto 122f + +// +// Read\modify\write for DENSE space I/O +// + bic t0, 3, t9 // clear bits <1:0> of dest + ldl t10, 0(t9) // read dest long + mskbl t10, t3, t10 // poke out the byte we will write + bis t10, t1, t1 // merge in our byte + stl t1, 0(t9) // commit it + + br zero, 122f + +// +// We're in SPARSE space, so simply perform the write +// +121: + stl t1, 0(t0) // store byte to buffer (BYTE ENABLED) +122: + addq t0, a3, t0 // increment I/O buffer + addl t3, 1, t3 // increment bytelane + and t3, 3, t3 // longwords only + bne a2, 120b // while count != 0 + +130: + mb // push writes off chip + ret zero, (ra) // return + + .end WRITE_REGISTER_BUFFER_ULONG // end for UCHAR & USHORT + + +#if 0 //ecrfix +// +// Values and structures used to access configuration space. +// + +// +// Define the configuration routines stack frame. +// + + .struct 0 +CfgRa: .space 8 // return address +CfgA0: .space 8 // saved McDevid +CfgA1: .space 8 // saved BusNumber +CfgA2: .space 8 // saved SlotNumber +CfgA3: .space 8 // saved Offset +CfgA4: .space 8 // padding for 16 byte alignment +CfgFrameLength: + +#endif + +//++ +// +// ULONG +// READ_CONFIG_UCHAR( +// ULONG ConfigurationAddress, +// ULONG ConfigurationCycleType +// ) +// +// Routine Description: +// +// Read an unsigned byte from PCI configuration space. +// +// Arguments: +// +// ConfigurationAddress(a0) - Supplies the QVA of configuration to be read. +// +// ConfigurationCycleType(a1) - Supplies the type of the configuration cycle. +// +// Return Value: +// +// (v0) Returns the value of configuration space at the specified location. +// +// N.B. - This routine follows a protocol for reading from PCI configuration +// space that allows the HAL or firmware to fixup and continue +// execution if no device exists at the configuration target address. +// The protocol requires 2 rules: +// (1) The configuration space load must use a destination register +// of v0 +// (2) The instruction immediately following the configuration space +// load must use v0 as an operand (it must consume the value +// returned by the load) +// +//-- + + LEAF_ENTRY( READ_CONFIG_UCHAR ) + +// +// Set the flag indicating the number of the processor upon which a PCI master abort +// may be expected by the machine check handler. +// + +#if !defined(AXP_FIRMWARE) + GET_PROCESSOR_CONTROL_BLOCK_BASE // v0 = prcb base address + ldl t0, PbNumber(v0) // capture current processor number +#else + bis zero,zero,t0 // Force processor zero in fw +#endif + extbl t0, 0, t0 // PbNumber is of type CCHAR + lda t4, HalpMasterAbortExpected // get address of flag + stl t0, MabNumber(t4) // save current processor number + +// +// Perform the read from configuration space after restoring the +// configuration space address. +// + + lda t7, IOD_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c81c + sll t7, 28, t7 // 0xffff fc81 c000 0000 + + extbl a0, 0x3, t0 // Extract McDevId from ConfigAddress + sll t0, 33, t0 // shift McDevId into position @ bit 33 + bis t7, t0, t7 // superpage mode + + and a0, 0x3, t3 // capture byte lane + zapnot a0, 0x7, a0 // Clear McDevid from ConfigAddress + sll a0, IO_BIT_SHIFT, t1 // Shift the rest into position + bis t7, t1, t7 // + + bis t7, IO_BYTE_LEN, t7 // or in the byte enables + stq t7, MabAddr(t4) // save current access address + + .set noreorder // cannot reorder these instructions + + mb // order the writes + ldl v0, (t7) // read the longword + mb // stall the pipe waiting for mchk + mb // + extbl v0, t3, v0 // return byte from requested lane + + .set reorder // reordering can begin again + + lda t5, MASTER_ABORT_NOT_EXPECTED(zero) + stl t5, MabNumber(t4) // "clear" flag + + ret zero, (ra) // return + + .end READ_CONFIG_UCHAR + +//++ +// +// VOID +// WRITE_CONFIG_UCHAR( +// ULONG ConfigurationAddress, +// UCHAR ConfigurationData, +// ULONG ConfigurationCycleType +// ) +// +// Routine Description: +// +// Write an unsigned byte to PCI configuration space. +// +// Arguments: +// +// ConfigurationAddress(a0) - Supplies the QVA of configuration to be read. +// +// ConfigurationData(a1) - Supplies the data to be written. +// +// ConfigurationCycleType(a2) - Supplies the type of the configuration cycle. +// +// Return Value: +// +// None. +// +// N.B. - The configuration address must exist within the address space +// allocated to an existing PCI device. Otherwise, the access +// below will initiate an unrecoverable machine check. +// +//-- + + LEAF_ENTRY( WRITE_CONFIG_UCHAR ) + +// +// Perform the write to configuration space +// + + lda t7, IOD_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c81c + sll t7, 28, t7 // 0xffff fc81 c000 0000 + + extbl a0, 0x3, t0 // Extract McDevId from ConfigAddress + sll t0, 33, t0 // shift McDevId into position @ bit 33 + bis t7, t0, t7 // superpage mode + + and a0, 0x3, t3 // capture byte lane + zapnot a0, 0x7, a0 // Clear McDevid from ConfigAddress + sll a0, IO_BIT_SHIFT, t1 // Shift the rest into position + bis t7, t1, t7 // + + bis t7, IO_BYTE_LEN, t7 // or in the byte enables + + insbl a1, t3, t4 // put byte in the appropriate lane + stl t4, (t7) // write the configuration byte + mb // synchronize + + ret zero, (ra) // return + + .end WRITE_CONFIG_UCHAR + +//++ +// +// ULONG +// READ_CONFIG_USHORT( +// ULONG ConfigurationAddress, +// ULONG ConfigurationCycleType +// ) +// +// Routine Description: +// +// Read a short from PCI configuration space. +// +// Arguments: +// +// ConfigurationAddress(a0) - Supplies the QVA of configuration to be read. +// +// ConfigurationCycleType(a1) - Supplies the type of the configuration cycle. +// +// Return Value: +// +// (v0) Returns the value of configuration space at the specified location. +// +// N.B. - This routine follows a protocol for reading from PCI configuration +// space that allows the HAL or firmware to fixup and continue +// execution if no device exists at the configuration target address. +// The protocol requires 2 rules: +// (1) The configuration space load must use a destination register +// of v0 +// (2) The instruction immediately following the configuration space +// load must use v0 as an operand (it must consume the value +// returned by the load) +//-- + + LEAF_ENTRY( READ_CONFIG_USHORT ) + +// +// Set the flag indicating the number of the processor upon which a PCI master abort +// may be expected by the machine check handler. +// + +#if !defined(AXP_FIRMWARE) + GET_PROCESSOR_CONTROL_BLOCK_BASE // v0 = prcb base address + ldl t0, PbNumber(v0) // capture current processor number +#else + bis zero,zero,t0 // Force processor zero in fw +#endif + extbl t0, 0, t0 // PbNumber is of type CCHAR + lda t4, HalpMasterAbortExpected // get address of flag + stl t0, MabNumber(t4) // save current processor number + +// +// Perform the read from configuration space. +// + lda t7, IOD_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c81c + sll t7, 28, t7 // 0xffff fc81 c000 0000 + + extbl a0, 0x3, t0 // Extract McDevId from ConfigAddress + sll t0, 33, t0 // shift McDevId into position @ bit 33 + bis t7, t0, t7 // superpage mode + + and a0, 0x3, t3 // capture word offset + zapnot a0, 0x7,a0 // Clear McDevid from ConfigAddress + sll a0, IO_BIT_SHIFT, t1 // Shift the rest into position + bis t7, t1, t7 // + + bis t7, IO_WORD_LEN, t7 // or in the byte enables + stq t7, MabAddr(t4) // save current access address + + .set noreorder // cannot reorder these instructions + + mb // order the write + ldl v0, (t7) // read the longword + mb // stall the pipe waiting for mchk + mb // + extwl v0, t3, v0 // return word from requested lanes + + .set reorder // reordering can begin again + + lda t5, MASTER_ABORT_NOT_EXPECTED(zero) + stl t5, MabNumber(t4) // "clear" flag + + ret zero, (ra) // return + + .end READ_CONFIG_USHORT + +//++ +// +// VOID +// WRITE_CONFIG_USHORT( +// ULONG ConfigurationAddress, +// UCHAR ConfigurationData, +// ULONG ConfigurationCycleType +// ) +// +// Routine Description: +// +// Write a short to PCI configuration space. +// +// Arguments: +// +// ConfigurationAddress(a0) - Supplies the QVA of configuration to be read. +// +// ConfigurationData(a1) - Supplies the data to be written. +// +// ConfigurationCycleType(a2) - Supplies the type of the configuration cycle. +// +// Return Value: +// +// (v0) Returns the value of configuration space at the specified location. +// +// N.B. - The configuration address must exist within the address space +// allocated to an existing PCI device. Otherwise, the access +// below will initiate an unrecoverable machine check. +// +//-- + + LEAF_ENTRY( WRITE_CONFIG_USHORT ) + +// +// Perform the write to configuration space. +// + + lda t7, IOD_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c81c + sll t7, 28, t7 // 0xffff fc81 c000 0000 + + extbl a0, 0x3, t0 // Extract McDevId from ConfigAddress + sll t0, 33, t0 // shift McDevId into position @ bit 33 + bis t7, t0, t7 // superpage mode + + and a0, 0x3, t3 // capture word offset + zapnot a0, 0x7,a0 // Clear McDevid from ConfigAddress + sll a0, IO_BIT_SHIFT, t1 // Shift the rest into position + bis t7, t1, t7 // + + bis t7, IO_WORD_LEN, t7 // or in the byte enables + + inswl a1, t3, t4 // put byte in the appropriate lane + stl t4, (t7) // write the configuration byte + mb // synchronize + + ret zero, (ra) // return + + .end WRITE_CONFIG_USHORT + +//++ +// +// ULONG +// READ_CONFIG_ULONG( +// ULONG ConfigurationAddress, +// ULONG ConfigurationCycleType +// ) +// +// Routine Description: +// +// Read a longword from PCI configuration space. +// +// Arguments: +// +// ConfigurationAddress(a0) - Supplies the QVA of configuration to be read. +// +// ConfigurationCycleType(a1) - Supplies the type of the configuration cycle. +// +// Return Value: +// +// (v0) Returns the value of configuration space at the specified location. +// +// N.B. - This routine follows a protocol for reading from PCI configuration +// space that allows the HAL or firmware to fixup and continue +// execution if no device exists at the configuration target address. +// The protocol requires 2 rules: +// (1) The configuration space load must use a destination register +// of v0 +// (2) The instruction immediately following the configuration space +// load must use v0 as an operand (it must consume the value +// returned by the load) +//-- + + LEAF_ENTRY( READ_CONFIG_ULONG ) + +// +// Set the flag indicating the number of the processor upon which a PCI master abort +// may be expected by the machine check handler. +// + +#if !defined(AXP_FIRMWARE) + GET_PROCESSOR_CONTROL_BLOCK_BASE // v0 = prcb base address + ldl t0, PbNumber(v0) // capture current processor number +#else + bis zero,zero,t0 // Force processor zero in fw +#endif + extbl t0, 0, t0 // PbNumber is of type CCHAR + lda t4, HalpMasterAbortExpected // get address of flag + stl t0, MabNumber(t4) // save current processor number + +// +// Perform the read from configuration space. +// + lda t7, IOD_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c81c + sll t7, 28, t7 // 0xffff fc81 c000 0000 + + extbl a0, 0x3, t0 // Extract McDevId from ConfigAddress + sll t0, 33, t0 // shift McDevId into position @ bit 33 + bis t7, t0, t7 // superpage mode + + zapnot a0, 0x7, a0 // Clear McDevid from ConfigAddress + sll a0, IO_BIT_SHIFT, t1 // Shift the rest into position + bis t7, t1, t7 // + + bis t7, IO_LONG_LEN, t7 // or in the byte enables + stq t7, MabAddr(t4) // save current access address + + .set noreorder // cannot reorder these instructions + + mb // order the writes + ldl v0, (t7) // read the longword + mb // stall the pipe waiting for mchk + mb // + + .set reorder // reordering can begin again + + lda t5, MASTER_ABORT_NOT_EXPECTED(zero) + stl t5, MabNumber(t4) // "clear" flag + + ret zero, (ra) // return + + .end READ_CONFIG_ULONG + + +//++ +// +// VOID +// WRITE_CONFIG_ULONG( +// ULONG ConfigurationAddress, +// ULONG ConfigurationData, +// ULONG ConfigurationCycleType +// ) +// +// Routine Description: +// +// Read a longword from PCI configuration space. +// +// Arguments: +// +// ConfigurationAddress(a0) - Supplies the QVA of configuration to be read. +// +// ConfigurationData(a1) - Supplies the data to be written. +// +// ConfigurationCycleType(a2) - Supplies the type of the configuration cycle. +// +// Return Value: +// +// (v0) Returns the value of configuration space at the specified location. +// +// N.B. - The configuration address must exist within the address space +// allocated to an existing PCI device. Otherwise, the access +// below will initiate an unrecoverable machine check. +// +//-- + + LEAF_ENTRY( WRITE_CONFIG_ULONG ) + +// +// Perform the write to configuration space. +// + + lda t7, IOD_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c81c + sll t7, 28, t7 // 0xffff fc81 c000 0000 + + extbl a0, 0x3, t0 // Extract McDevId from ConfigAddress + sll t0, 33, t0 // shift McDevId into position @ bit 33 + bis t7, t0, t7 // superpage mode + + zapnot a0, 0x7, a0 // Clear McDevid from ConfigAddress + sll a0, IO_BIT_SHIFT, t1 // Shift the rest into position + bis t7, t1, t7 // + + bis t7, IO_LONG_LEN, t7 // or in the byte enables + + stl a1, (t7) // write the longword + mb // synchronize + + ret zero, (ra) // return + + .end WRITE_CONFIG_ULONG + +//++ +// +// ULONG +// INTERRUPT_ACKNOWLEDGE( +// VOID +// ) +// +// Routine Description: +// +// Perform an interrupt acknowledge cycle on PCI bus 0 +// +// +// Arguments: +// +// None. +// +// Return Value: +// +// (v0) Returns the vector returned by the interrupt acknowledge +// read. +// +//-- + + + LEAF_ENTRY( INTERRUPT_ACKNOWLEDGE ) + + lda t0, IOD_PCI0_REGISTER_SVA(zero) // 0xffff ffff ffff cf9e + sll t0, 28, t0 // 0xffff fcf9 e000 0000 + lda t0, 0x480(t0) // 0xffff fcf9 e000 0480 + + ldl v0, 0(t0) // perform PCI0 IACK, get vector + + ret zero, (ra) // return + + .end INTERRUPT_ACKNOWLEDGE + + SBTTL( "IOD Interrupt Acknowledge" ) +//++ +// +// VOID +// IOD_INTERRUPT_ACKNOWEDGE +// IN ULONG McDeviceId, +// IN ULONG Target +// ) +// +// Routine Description: +// +// Perform an IOD interrupt acknowledge to the selected +// interrupt target. +// +// Arguments: +// +// McDeviceId(a0) - MC Bus Device ID of the IOD to acknowledge +// +// Target(a1) - Which one of two interrupt targets generated +// the interrupt. Must be 0 or 1. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(IOD_INTERRUPT_ACKNOWLEDGE) + +// +// Generate the superpage address of the requested IOD INT_ACK register +// + mb + + extbl a0, zero, a0 // McDevId + + sll a1, 6, a1 // Which target? + lda t4, IOD_TARGET0_OFFSET // If target = 0, offset = 0x3f00 + bis a1, t4, t4 // If target = 1, offset = 0x3f40 + + lda t0, IOD_INT_ACK_SVA(zero) //0xffff ffff ffff c81f + sll a0, 5, t1 // 0x0000000mc 0000 0000 McDeviceId + bis t0, t1, t0 // 0xffff fc81 f000 0000 + sll t0, 28, t0 // 0xffff fcXX f000 0000 + + or t0, t4, t0 // 0xffff fcXX f000 3f00/3f40 + stl zero, (t0) // write the longword + mb // order the write + mb // SPECIAL 2nd MB for Rawhide + + ret zero, (ra) // return + + .end IOD_INTERRUPT_ACKNOWLEDGE + + + SBTTL( "CPU Clock Interrupt Acknowledge" ) +//++ +// +// VOID +// CPU_CLOCK_ACKNOWEDGE +// IN ULONG McDeviceId +// ) +// +// Routine Description: +// +// Perform an clock (interval timer) interrupt acknowledge to the +// selected CPU. +// +// Arguments: +// +// McDevid(a0) - MC Bus Device ID of the CPU to acknowledge. +// +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(CPU_CLOCK_ACKNOWLEDGE) + +// +// Generate the superpage address of the requested CUD's INTTIM_ACK register +// + + + extbl a0, zero, a0 // McDeviceId + + lda t0, IOD_INTTIM_SVA(zero) //0xffff ffff ffff c810 + sll a0, 5, t1 // 0x0000000mc 0000 0000 McDeviceId + bis t0, t1, t0 // 0xffff fc81 0000 0000 + sll t0, 28, t0 // 0xffff fcXX 0000 0000 + + stl zero, (t0) // write the longword + mb // order the write + mb // SPECIAL 2nd MB for Rawhide + + ret zero, (ra) // return + + .end CPU_CLOCK_ACKNOWLEDGE + + + + SBTTL( "Interprocessor Interrupt Request" ) +//++ +// +// VOID +// IP_INTERRUPT_REQUEST +// IN ULONG McDeviceId +// ) +// +// Routine Description: +// +// Perform an inteprocessor interrupt request to the +// selected CPU. +// +// Arguments: +// +// McDevid(a0) - MC Bus Device ID of the CPU to send an IPI request. +// +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(IP_INTERRUPT_REQUEST) + +// +// Generate the superpage address of the requested CUD's IP_INTR register +// + + + extbl a0, zero, a0 // McDeviceId + + lda t0, IOD_IP_INTR_SVA(zero) // 0xffff ffff ffff c801 + sll a0, 5, t1 // 0x0000000mc 0000 0000 McDeviceId + bis t0, t1, t0 // 0xffff fc80 1000 0000 + sll t0, 28, t0 // 0xffff fcXX 1000 0000 + + stl zero, (t0) // write the longword + mb // order the write + mb // SPECIAL 2nd MB for Rawhide + + ret zero, (ra) // return + + .end IP_INTERRUPT_REQUEST + + + SBTTL( "Interprocessor Interrupt Acknowledge" ) +//++ +// +// VOID +// IP_INTERRUPT_ACKNOWEDGE +// IN ULONG McDeviceId +// ) +// +// Routine Description: +// +// Perform an inteprocessor interrupt acknowledge to the +// selected CPU. +// +// Arguments: +// +// McDevid(a0) - MC Bus Device ID of the CPU to send an IPI acknowledge. +// +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(IP_INTERRUPT_ACKNOWLEDGE) + +// +// Generate the superpage address of the requested CUD's IP_ACK register +// + + + extbl a0, zero, a0 // McDeviceId + + lda t0, IOD_IP_ACK_SVA(zero) // 0xffff ffff ffff c811 + sll a0, 5, t1 // 0x0000000mc 0000 0000 McDeviceId + bis t0, t1, t0 // 0xffff fc81 1000 0000 + sll t0, 28, t0 // 0xffff fcXX 1000 0000 + + stl zero, (t0) // write the longword + mb // order the write + mb // SPECIAL 2nd MB for Rawhide + + ret zero, (ra) // return + + .end IP_INTERRUPT_ACKNOWLEDGE diff --git a/private/ntos/nthals/halraw/alpha/iodmapio.c b/private/ntos/nthals/halraw/alpha/iodmapio.c new file mode 100644 index 000000000..2970fb955 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/iodmapio.c @@ -0,0 +1,163 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + iodmapio.c + +Abstract: + + This module contains the functions to map HAL-accessed I/O addresses + on IOD-based systems. + +Author: + + Eric Rehm 26-Apr-1995 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" +#include "isaaddr.h" + +// +// Define global data used to locate the EISA control space. +// + +PVOID HalpEisaControlBase; +PVOID HalpEisaIntAckBase; +PVOID HalpPciIrQva; +PVOID HalpPciImrQva; +PVOID HalpCMOSRamBase; + + +BOOLEAN +HalpMapIoSpace ( + VOID + ) + +/*++ + +Routine Description: + + This routine maps the HAL I/O space for an IOD-based system using + the Quasi VA mechanism. + +Arguments: + + None. + +Return Value: + + If the initialization is successfully completed, than a value of TRUE + is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + PVOID PciIoSpaceBase; + + // + // Map base addresses in QVA space. + // + +// PciIoSpaceBase = HAL_MAKE_QVA( IOD_PCI0_SPARSE_IO_PHYSICAL ); + + // + // IoSpace Base for PCI 0 is a bus address 0. + // + + PciIoSpaceBase = HAL_MAKE_IOD_SPARSE_QVA( 0, 0 ); + + HalpEisaControlBase = PciIoSpaceBase; + +// ecrfix - not needed? HalpEisaIntAckBase = HAL_MAKE_IOD_SPARSE_QVA(0, 0); + + // + // Map CMOS RAM address. + // + + HalpCMOSRamBase = (PVOID)((ULONG)PciIoSpaceBase + CMOS_ISA_PORT_ADDRESS); + + // + // Map the real-time clock registers. + // + + HalpRtcAddressPort = (PVOID)((ULONG)PciIoSpaceBase + RTC_ISA_ADDRESS_PORT); + HalpRtcDataPort = (PVOID)((ULONG)PciIoSpaceBase + RTC_ISA_DATA_PORT); + + return TRUE; + +} + +ULONG +HalpMapDebugPort( + IN ULONG ComPort, + OUT PULONG ReadQva, + OUT PULONG WriteQva + ) +/*++ + +Routine Description: + + This routine maps the debug com port so that the kernel debugger + may function - if called it is called very earlier in the boot sequence. + +Arguments: + + ComPort - Supplies the number of the com port to use as the debug port. + + ReadQva - Receives the QVA used to access the read registers of the debug + port. + + WriteQva - Receives the QVA used to access the write registers of the + debug port. + +Return Value: + + Returns the base bus address of the device used as the debug port. + +--*/ +{ + ULONG ComPortAddress; + ULONG PortQva; + + // + // Compute the port address, based on the desired com port. + // + + switch( ComPort ){ + + case 1: + + ComPortAddress = COM1_ISA_PORT_ADDRESS; + break; + + case 2: + default: + + ComPortAddress = COM2_ISA_PORT_ADDRESS; + + } + + // + // COM ports are on PCI bus 0. + // Return the QVAs for read and write access. + // + + PortQva = (ULONG)HAL_MAKE_IOD_SPARSE_QVA( 0, 0 ) + ComPortAddress; + + *ReadQva = PortQva; + *WriteQva = PortQva; + + return ComPortAddress; + +} + + diff --git a/private/ntos/nthals/halraw/alpha/ioproc.c b/private/ntos/nthals/halraw/alpha/ioproc.c new file mode 100644 index 000000000..8789e513c --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/ioproc.c @@ -0,0 +1,75 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + ioproc.c + +Abstract: + + Stub functions for UP hals. + +Author: + + Ken Reneris (kenr) 22-Jan-1991 + +Environment: + + Kernel mode only. + +Revision History: + + Added to Avanti Hals (Sameer Dekate) 04-May-1994 + +--*/ + +#include "halp.h" +#include "iousage.h" + +UCHAR HalName[] = "Alpha Compatible PCI/Eisa/Isa HAL"; + +BOOLEAN +HalpInitMP ( + IN ULONG Phase, + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +VOID HalpInitializePciBuses (VOID); +VOID HalpInitOtherBuses (VOID); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpInitMP) +#pragma alloc_text(INIT,HalStartNextProcessor) +#pragma alloc_text(INIT,HalpInitOtherBuses) +#endif + + + +BOOLEAN +HalpInitMP ( + IN ULONG Phase, + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) +{ + return TRUE; + // do nothing +} + + +VOID +HalpResetAllProcessors ( + VOID + ) +{ + // Just return, that will invoke the standard PC reboot code +} + + +VOID +HalpInitOtherBuses ( + VOID + ) +{ + // no other internal buses supported +} diff --git a/private/ntos/nthals/halraw/alpha/iousage.c b/private/ntos/nthals/halraw/alpha/iousage.c new file mode 100644 index 000000000..6ac8f6f4e --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/iousage.c @@ -0,0 +1,647 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + iousage.c + +Abstract: + +Author: + + Ken Reneris (kenr) + +Environment: + + Kernel mode only. + +Revision History: + + Chao Chen 1-25-1995 + +--*/ + +#include "halp.h" +#include "iousage.h" + +// +// Externals. +// + +extern KAFFINITY HalpActiveProcessors; + +// +// Private resource list. +// + +static PBUS_USAGE HalpBusUsageList = NULL; +static PRESOURCE_USAGE HalpResourceUsageList = NULL; + +// +// Default HAL name. +// + +#define MAX_NAME_LENGTH 256 +UCHAR HalRegisteredName[MAX_NAME_LENGTH] = "Alpha Compatible PCI/EISA/ISA HAL"; + +// +// Function prototype. +// + +VOID +HalpReportResourceUsage ( + IN PUNICODE_STRING HalName + ); + +VOID +HalpGetResourceSortValue ( + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR pRCurLoc, + OUT PULONG sortscale, + OUT PLARGE_INTEGER sortvalue + ); + +// +// Pragma stuff. +// + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpRegisterHalName) +#pragma alloc_text(INIT,HalpRegisterBusUsage) +#pragma alloc_text(INIT,HalpRegisterResourceUsage) +#pragma alloc_text(INIT,HalReportResourceUsage) +#pragma alloc_text(INIT,HalpReportResourceUsage) +#pragma alloc_text(INIT,HalpGetResourceSortValue) +#endif + +// +// Function definitions. +// + + +VOID +HalpRegisterHalName( + IN PUCHAR NewHalName + ) +/*++ + +Routine Description: + + Allow the HAL to register a name string. + +Arguments: + + HalName - Supplies a pointer to the HAL name to register. + +Return Value: + + None. + +--*/ +{ + + strncpy( HalRegisteredName, NewHalName, MAX_NAME_LENGTH ); + return; +} + + + +VOID +HalpRegisterBusUsage ( + IN INTERFACE_TYPE BusType + ) +/*++ + +Routine Description: + + Register the different bus types in the system. + +Arguments: + + BusType - bus type that requires registering. + +Return Value: + + None. + +--*/ +{ + PBUS_USAGE Temp; + + // + // Allocate the buffer to store the bus information. + // + + Temp = (PBUS_USAGE)ExAllocatePool(NonPagedPool, sizeof(BUS_USAGE)); + + // + // Save the bus type. + // + + Temp->BusType = BusType; + + // + // Add the bus type to the head of the list. + // + + Temp->Next = HalpBusUsageList; + HalpBusUsageList = Temp; +} + + + +VOID +HalpRegisterResourceUsage ( + IN PRESOURCE_USAGE Resource + ) +/*++ + +Routine Description: + + Register the resources used internally by the HAL to the I/O system. + +Arguments: + + Resource - resource that requires registering. + +Return Value: + + None. + +--*/ +{ + PRESOURCE_USAGE Temp; + + // + // Allocate the buffer to store the resource information. + // + + Temp = (PRESOURCE_USAGE)ExAllocatePool(NonPagedPool, sizeof(RESOURCE_USAGE)); + + // + // Copy the resource to the buffer we allocated. + // + + RtlCopyMemory(Temp, Resource, sizeof(RESOURCE_USAGE)); + + // + // Add the resource to the head of the resource list. + // + + Temp->Next = HalpResourceUsageList; + HalpResourceUsageList = Temp; +} + + + +VOID +HalReportResourceUsage ( + VOID + ) +/*++ + +Routine Description: + + Report the resources used internally by the HAL to the I/O system. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + ANSI_STRING AHalName; + UNICODE_STRING UHalName; + + // + // Convert the string. + // + + RtlInitAnsiString (&AHalName, HalRegisteredName); + RtlAnsiStringToUnicodeString (&UHalName, &AHalName, TRUE); + + // + // Report the resources registered as in use by the HAL. + // + + HalpReportResourceUsage(&UHalName); + + RtlFreeUnicodeString(&UHalName); +} + + + +VOID +HalpGetResourceSortValue ( + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR pRCurLoc, + OUT PULONG sortscale, + OUT PLARGE_INTEGER sortvalue + ) +/*++ + +Routine Description: + + Used by HalpReportResourceUsage in order to properly sort + partial_resource_descriptors. + +Arguments: + + pRCurLoc - resource descriptor + +Return Value: + + sortscale - scaling of resource descriptor for sorting + sortvalue - value to sort on + + +--*/ +{ + + switch (pRCurLoc->Type) { + case CmResourceTypeInterrupt: + *sortscale = 0; + sortvalue->QuadPart = pRCurLoc->u.Interrupt.Level; + break; + + case CmResourceTypePort: + *sortscale = 1; + *sortvalue = pRCurLoc->u.Port.Start; + break; + + case CmResourceTypeMemory: + *sortscale = 2; + *sortvalue = pRCurLoc->u.Memory.Start; + break; + + case CmResourceTypeDma: + *sortscale = 3; + sortvalue->QuadPart = pRCurLoc->u.Dma.Channel; + break; + + default: + *sortscale = 4; + sortvalue->QuadPart = 0; + break; + } +} + + + +VOID +HalpReportResourceUsage ( + IN PUNICODE_STRING HalName + ) +/*++ + +Routine Description: + + This routine registers the resources for the hal. + +Arguments: + + HalName - the name of the hal to be registered. + +Return Value: + + None. + +--*/ +{ + PCM_RESOURCE_LIST RawResourceList, TranslatedResourceList; + PCM_FULL_RESOURCE_DESCRIPTOR pRFullDesc, pTFullDesc; + PCM_PARTIAL_RESOURCE_LIST pRPartList, pTPartList; + PCM_PARTIAL_RESOURCE_DESCRIPTOR pRCurLoc, pTCurLoc; + PCM_PARTIAL_RESOURCE_DESCRIPTOR pRSortLoc, pTSortLoc; + CM_PARTIAL_RESOURCE_DESCRIPTOR RPartialDesc, TPartialDesc; + ULONG i, j, k, ListSize, Count; + ULONG curscale, sortscale; + LARGE_INTEGER curvalue, sortvalue; + PHYSICAL_ADDRESS PhyAddress; + PBUS_USAGE CurrentBus; + PRESOURCE_USAGE CurrentResource; + + // + // Allocate some space to build the resource structure. + // + + RawResourceList= + (PCM_RESOURCE_LIST)ExAllocatePool(NonPagedPool, PAGE_SIZE*2); + TranslatedResourceList= + (PCM_RESOURCE_LIST)ExAllocatePool(NonPagedPool, PAGE_SIZE*2); + + // + // This functions assumes unset fields are zero. + // + + RtlZeroMemory (RawResourceList, PAGE_SIZE*2); + RtlZeroMemory (TranslatedResourceList, PAGE_SIZE*2); + + // + // Initialize the lists + // + + RawResourceList->List[0].InterfaceType = (INTERFACE_TYPE) -1; + pRFullDesc = RawResourceList->List; + pRCurLoc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) RawResourceList->List; + pTCurLoc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) TranslatedResourceList->List; + + // + // Report all the HAL resources. + // + + CurrentBus = HalpBusUsageList; + + while (CurrentBus) { + + // + // Start at the head of the resource list for each bus type. + // + + CurrentResource = HalpResourceUsageList; + + while (CurrentResource) { + + // + // Register the resources for a particular bus. + // + + if (CurrentBus->BusType == CurrentResource->BusType) { + + switch (CurrentResource->ResourceType) { + + case CmResourceTypeInterrupt: + + // + // Process interrupt resources. + // + + RPartialDesc.Type = CmResourceTypeInterrupt; + RPartialDesc.ShareDisposition = CmResourceShareDriverExclusive; + + if (CurrentResource->u.InterruptMode == Latched) + RPartialDesc.Flags = CM_RESOURCE_INTERRUPT_LATCHED; + else + RPartialDesc.Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + + RPartialDesc.u.Interrupt.Vector = + CurrentResource->u.BusInterruptVector; + RPartialDesc.u.Interrupt.Level = + CurrentResource->u.BusInterruptVector; + RPartialDesc.u.Interrupt.Affinity = HalpActiveProcessors; + + RtlCopyMemory(&TPartialDesc, &RPartialDesc, sizeof(TPartialDesc)); + TPartialDesc.u.Interrupt.Vector = + CurrentResource->u.SystemInterruptVector; + TPartialDesc.u.Interrupt.Level = + CurrentResource->u.SystemIrql; + + break; + + case CmResourceTypePort: + case CmResourceTypeMemory: + + // + // Process port and memory resources. + // + + RPartialDesc.Type = CurrentResource->ResourceType; + RPartialDesc.ShareDisposition = CmResourceShareDriverExclusive; + + if (RPartialDesc.Type == CmResourceTypePort) { + + // + // In IO space. + // + + i = 1; + RPartialDesc.Flags = CM_RESOURCE_PORT_IO; + + } else { + + // + // In memory space. + // + + i = 0; + RPartialDesc.Flags = CM_RESOURCE_MEMORY_READ_WRITE; + } + + // + // Notice: assume u.Memory and u.Port have the same layout. + // + + RPartialDesc.u.Memory.Start.HighPart = 0; + RPartialDesc.u.Memory.Start.LowPart = CurrentResource->u.Start; + RPartialDesc.u.Memory.Length = CurrentResource->u.Length; + + RtlCopyMemory(&TPartialDesc, &RPartialDesc, sizeof(TPartialDesc)); + + // + // Translate the address. + // + + HalTranslateBusAddress(CurrentResource->BusType, + CurrentResource->BusNumber, + RPartialDesc.u.Memory.Start, + &i, + &PhyAddress ); + + TPartialDesc.u.Memory.Start = PhyAddress; + + if ((RPartialDesc.Type == CmResourceTypePort) && (i == 0)) + TPartialDesc.Flags = CM_RESOURCE_PORT_MEMORY; + + break; + + case CmResourceTypeDma: + + // + // Process dma resources. + // + + RPartialDesc.Type = CmResourceTypeDma; + RPartialDesc.ShareDisposition = CmResourceShareDriverExclusive; + + RPartialDesc.u.Dma.Channel = CurrentResource->u.DmaChannel; + RPartialDesc.u.Dma.Port = CurrentResource->u.DmaPort; + + RtlCopyMemory(&TPartialDesc, &RPartialDesc, sizeof(TPartialDesc)); + TPartialDesc.u.Dma.Channel = CurrentResource->u.DmaChannel; + TPartialDesc.u.Dma.Port = CurrentResource->u.DmaPort; + + break; + + default: + + // + // Got a resource we don't know. Bail out! + // + + goto NextResource; + } + + // + // Include the current resource in the HAL list. + // + + if (pRFullDesc->InterfaceType != CurrentBus->BusType) { + + // + // Interface type changed, add another full section + // + + RawResourceList->Count++; + TranslatedResourceList->Count++; + + pRFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)pRCurLoc; + pTFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)pTCurLoc; + + pRFullDesc->InterfaceType = CurrentBus->BusType; + pTFullDesc->InterfaceType = CurrentBus->BusType; + + pRPartList = &pRFullDesc->PartialResourceList; + pTPartList = &pTFullDesc->PartialResourceList; + + // + // Bump current location pointers up + // + + pRCurLoc = pRFullDesc->PartialResourceList.PartialDescriptors; + pTCurLoc = pTFullDesc->PartialResourceList.PartialDescriptors; + } + + // + // Add current resource in. + // + + pRPartList->Count++; + pTPartList->Count++; + RtlCopyMemory(pRCurLoc, &RPartialDesc, sizeof(RPartialDesc)); + RtlCopyMemory(pTCurLoc, &TPartialDesc, sizeof(TPartialDesc)); + + pRCurLoc++; + pTCurLoc++; + } + + // + // Finished with this resource, move to the next one. + // + + NextResource: + CurrentResource = CurrentResource->Next; + } + + // + // Finished with this bus, move to the next one. + // + + CurrentBus = CurrentBus->Next; + } + + // + // Do the actual reporting. + // + + ListSize = (ULONG)(((PUCHAR)pRCurLoc) - ((PUCHAR)RawResourceList)); + + // + // The HAL's resource usage structures have been built + // Sort the partial lists based on the Raw resource values. + // + + pRFullDesc = RawResourceList->List; + pTFullDesc = TranslatedResourceList->List; + + for (i=0; i < RawResourceList->Count; i++) { + + pRCurLoc = pRFullDesc->PartialResourceList.PartialDescriptors; + pTCurLoc = pTFullDesc->PartialResourceList.PartialDescriptors; + Count = pRFullDesc->PartialResourceList.Count; + + for (j=0; j < Count; j++) { + HalpGetResourceSortValue (pRCurLoc, &curscale, &curvalue); + + pRSortLoc = pRCurLoc; + pTSortLoc = pTCurLoc; + + for (k=j; k < Count; k++) { + HalpGetResourceSortValue (pRSortLoc, &sortscale, &sortvalue); + + if (sortscale < curscale || + (sortscale == curscale && + (sortvalue.QuadPart < curvalue.QuadPart)) ){ + + // + // Swap the elements. + // + + RtlCopyMemory (&RPartialDesc, pRCurLoc, sizeof RPartialDesc); + RtlCopyMemory (pRCurLoc, pRSortLoc, sizeof RPartialDesc); + RtlCopyMemory (pRSortLoc, &RPartialDesc, sizeof RPartialDesc); + + // + // Swap translated descriptor as well. + // + + RtlCopyMemory (&TPartialDesc, pTCurLoc, sizeof TPartialDesc); + RtlCopyMemory (pTCurLoc, pTSortLoc, sizeof TPartialDesc); + RtlCopyMemory (pTSortLoc, &TPartialDesc, sizeof TPartialDesc); + + // + // Get new curscale & curvalue. + // + + HalpGetResourceSortValue (pRCurLoc, &curscale, &curvalue); + } + + pRSortLoc++; + pTSortLoc++; + } + + pRCurLoc++; + pTCurLoc++; + } + + pRFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) pRCurLoc; + pTFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) pTCurLoc; + } + + // + // Inform the IO system of our resources. + // + + IoReportHalResourceUsage(HalName, + RawResourceList, + TranslatedResourceList, + ListSize); + + ExFreePool (RawResourceList); + ExFreePool (TranslatedResourceList); + + // + // Free all registered buses. + // + + while (HalpBusUsageList) { + + CurrentBus = HalpBusUsageList; + HalpBusUsageList = HalpBusUsageList->Next; + ExFreePool(CurrentBus); + } + + // + // Free all registered resources. + // + + while (HalpResourceUsageList) { + + CurrentResource = HalpResourceUsageList; + HalpResourceUsageList = HalpResourceUsageList->Next; + ExFreePool(CurrentResource); + } +} + diff --git a/private/ntos/nthals/halraw/alpha/iousage.h b/private/ntos/nthals/halraw/alpha/iousage.h new file mode 100644 index 000000000..b54cd179a --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/iousage.h @@ -0,0 +1,107 @@ +/*++ + +Copyright (c) 1993-1995 Microsoft Corporation +Copyright (c) 1993-1995 Digital Equipment Corporation + +Module Name: + + iousage.h + +Abstract: + + This header file defines the iousage definitions + +Author: + + Sameer Dekate 5-3-1994 + + +Revision History: + + Chao Chen 1-25-1995 + +--*/ + +// +// Resource usage information +// + +// +// Bus usage information. +// + +typedef struct _HalBusUsage{ + INTERFACE_TYPE BusType; + struct _HalBusUsage *Next; +} BUS_USAGE, *PBUS_USAGE; + +// +// Address usage information. +// + +typedef struct _HalResourceUsage { + + // + // Common elements. + // + + INTERFACE_TYPE BusType; + ULONG BusNumber; + CM_RESOURCE_TYPE ResourceType; + struct _HalResourceUsage *Next; + + // + // Resource type specific. + // + + union { + + // + // Address usage. + // + + struct { + ULONG Start; + ULONG Length; + }; + + // + // Vector type specific. + // + + struct { + KINTERRUPT_MODE InterruptMode; + ULONG BusInterruptVector; + ULONG SystemInterruptVector; + KIRQL SystemIrql; + }; + + // + // Dma type specific. + // + + struct { + ULONG DmaChannel; + ULONG DmaPort; + }; + } u; +} RESOURCE_USAGE, *PRESOURCE_USAGE; + +// +// Functions to report HAL's resource usage. +// + +VOID +HalpRegisterHalName( + IN PUCHAR HalName + ); + +VOID +HalpRegisterBusUsage ( + IN INTERFACE_TYPE BusType + ); + +VOID +HalpRegisterResourceUsage ( + IN PRESOURCE_USAGE Resource + ); diff --git a/private/ntos/nthals/halraw/alpha/machdep.h b/private/ntos/nthals/halraw/alpha/machdep.h new file mode 100644 index 000000000..d45f00988 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/machdep.h @@ -0,0 +1,42 @@ +/*++ + +Copyright (c) 1993,1995 Digital Equipment Corporation + +Module Name: + + machdep.h + +Abstract: + + This file includes the platform-dependent include files used to + build the HAL. + +Author: + + Joe Notarangelo 01-Dec-1993 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#ifndef _MACHDEP_ +#define _MACHDEP_ + +// +// Include Rawhide platform-specific definitions. +// + +#include "rawhide.h" + +// +// Include scatter/gather definitions. +// + +#include "ebsgdma.h" + +#endif //_MACHDEP_ diff --git a/private/ntos/nthals/halraw/alpha/memory.c b/private/ntos/nthals/halraw/alpha/memory.c new file mode 100644 index 000000000..76b1eb7df --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/memory.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\memory.c" + diff --git a/private/ntos/nthals/halraw/alpha/nvenv.c b/private/ntos/nthals/halraw/alpha/nvenv.c new file mode 100644 index 000000000..8a8dfdeb5 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/nvenv.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\nvenv.c" + diff --git a/private/ntos/nthals/halraw/alpha/nvram.c b/private/ntos/nthals/halraw/alpha/nvram.c new file mode 100644 index 000000000..6fd93ab46 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/nvram.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\nvram.c" + diff --git a/private/ntos/nthals/halraw/alpha/pcibus.c b/private/ntos/nthals/halraw/alpha/pcibus.c new file mode 100644 index 000000000..80a22247b --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/pcibus.c @@ -0,0 +1,146 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation, Digital Equipment Corporation + + +Module Name: + + pcibus.c + +Abstract: + + Platform-specific PCI bus routines + +Author: + + Eric Rehm 6-June-1995 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" +#include "machdep.h" + + +extern ULONG PCIMaxBus; + + + +PCI_CONFIGURATION_TYPES +HalpPCIConfigCycleType ( + IN PBUS_HANDLER BusHandler + ) +{ + PCI_CONFIGURATION_TYPES ConfigType; + ULONG BusNumber = BusHandler->BusNumber; + PPCIPBUSDATA BusData; + BOOLEAN BusIsAcrossPPB; + + // + // Get a pointer to the bus-specific data. + // + + BusData = (PPCIPBUSDATA)BusHandler->BusData; + + // + // Get the flag that tells use whether this is + // a root bus or not. + // + + BusIsAcrossPPB = BusData->BusIsAcrossPPB; + + // + // Valid Config cycles for Bus # < PCIMaxBus + // + // Then, Type 1 config cycles only when bus is across + // a PPB. + // + + if (BusNumber < PCIMaxBus) { + ConfigType = PciConfigType0; + if (BusIsAcrossPPB == TRUE) + { + ConfigType = PciConfigType1; + } + } else { + ConfigType = PciConfigTypeInvalid; + } + +#if HALDBG + DbgPrint("BusNumber %d BusIsAcrossPPB %d ConfigType %d\n", + BusNumber, BusIsAcrossPPB, ConfigType); +#endif + + return ConfigType; + +} + + +VOID +HalpPCIConfigAddr ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + PPCI_CFG_CYCLE_BITS pPciAddr + ) +{ + PCI_CONFIGURATION_TYPES ConfigType; + MC_DEVICE_ID McDevid; + ULONG BusNumber = BusHandler->BusNumber; + PPCIPBUSDATA BusData; + + ConfigType = HalpPCIConfigCycleType(BusHandler); + + // + // Get a pointer to the bus-specific data. + // + + BusData = (PPCIPBUSDATA)BusHandler->BusData; + +#if HALDBG + + DbgPrint( "PCI Config Access: Bus = %d, Device = %d, BusIsAcrossPPB %d ConfigType = %d\n", + BusNumber, Slot.u.bits.DeviceNumber, BusData->BusIsAcrossPPB, ConfigType ); + +#endif //HALDBG + + // + // From the root bus number (a.k.a. HwBusNumber), get + // the MC_DEVICE_ID of the IOD that we're attempting to access. + // + + McDevid = HalpIodLogicalToPhysical[BusData->HwBusNumber]; + + // + // If this is an access to an PCI device on a root bus, + // then we want to generate a Type 0 config cycle. To do this + // on Rawhide, you must set BusNumber to zero. + // + // We know that an access is destined to a root bus when + // when the bus being accessed is *not* across a PPB. + // + + if (BusData->BusIsAcrossPPB == FALSE) { + BusNumber = 0; + } + + + // + // Initialize PciAddr for a PCI type 1 configuration cycle + // + + pPciAddr->u.AsULONG = McDevid.all << 24; + pPciAddr->u.bits1.BusNumber = BusNumber; + pPciAddr->u.bits1.DeviceNumber = Slot.u.bits.DeviceNumber; + pPciAddr->u.bits1.FunctionNumber = Slot.u.bits.FunctionNumber; + pPciAddr->u.bits1.Reserved1 = PciConfigType1; // don't care! + + + return; +} diff --git a/private/ntos/nthals/halraw/alpha/pciesc.c b/private/ntos/nthals/halraw/alpha/pciesc.c new file mode 100644 index 000000000..ef14f3c15 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/pciesc.c @@ -0,0 +1,489 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation +Copyright (c) 1992, 1993, 1994 Digital Equipment Corporation + +Module Name: + + pciesc.c + +Abstract: + + The module provides the interrupt support for the PCI ESC's + cascaded 82c59 programmable interrupt controllers. + +Author: + + Eric Rehm (DEC) 4-Feburary-1994 + +Revision History: + + James Livingston 29-Apr-1994 + Adapted from pcisio.c module for Intel 82374EB (ESC). + +--*/ + +#include "halp.h" +#include "eisa.h" + +// +// Define the context structure for use by interrupt service routines. +// + +typedef BOOLEAN (*PSECOND_LEVEL_DISPATCH)( + PKINTERRUPT InterruptObject + ); + +// +// Import save area for ESC interrupt mask registers. +// + +UCHAR HalpEisaInterrupt1Mask; +UCHAR HalpEisaInterrupt2Mask; +UCHAR HalpEisaInterrupt1Level; +UCHAR HalpEisaInterrupt2Level; + + +BOOLEAN +HalpInitializeEisaInterrupts ( + VOID + ) + +/*++ + +Routine Description: + + This routine initializes the standard dual 82c59 programmable interrupt + controller. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + UCHAR DataByte; + + // + // Initialize the ESC interrupt controller. There are two cascaded + // interrupt controllers, each of which must be initialized with 4 + // control words. + // + + DataByte = 0; + ((PINITIALIZATION_COMMAND_1) &DataByte)->Icw4Needed = 1; + ((PINITIALIZATION_COMMAND_1) &DataByte)->InitializationFlag = 1; + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0, + DataByte + ); + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0, + DataByte + ); + + // + // The second intitialization control word sets the interrupt vector to + // 0-15. + // + + DataByte = 0; + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1, + DataByte + ); + + DataByte = 0x08; + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1, + DataByte + ); + + // + // The third initialization control word sets the controls for slave mode. + // The master ICW3 uses bit position and the slave ICW3 uses a numeric. + // + + DataByte = 1 << SLAVE_IRQL_LEVEL; + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1, + DataByte + ); + + DataByte = SLAVE_IRQL_LEVEL; + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1, + DataByte + ); + + // + // The fourth initialization control word is used to specify normal + // end-of-interrupt mode and not special-fully-nested mode. + // + + DataByte = 0; + ((PINITIALIZATION_COMMAND_4) &DataByte)->I80x86Mode = 1; + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1, + DataByte + ); + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1, + DataByte + ); + + + // + // Disable all of the interrupts except the slave. + // + + HalpEisaInterrupt1Mask = (UCHAR)(~(1 << SLAVE_IRQL_LEVEL)); + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1, + HalpEisaInterrupt1Mask + ); + + HalpEisaInterrupt2Mask = 0xFF; + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1, + HalpEisaInterrupt2Mask + ); + + + // + // Initialize the edge/level register masks to 0, which is the default + // edge-sensitive value. + // + + HalpEisaInterrupt1Level = 0; + HalpEisaInterrupt2Level = 0; + + return (TRUE); +} + +VOID +HalpDisableEisaInterrupt( + IN ULONG Vector + ) + +/*++ + +Routine Description: + + This function Disables the EISA interrupt specified by Vector. + +Arguments: + + Vector - Supplies the vector of the ESIA interrupt that is Disabled. + +Return Value: + + None. + +--*/ + +{ + // + // Calculate the EISA interrupt vector. + // + + Vector -= EISA_VECTORS; + + // + // Determine if this vector is for interrupt controller 1 or 2. + // + + if (Vector & 0x08) { + + // + // The interrupt is for controller 2. + // + + Vector &= 0x7; + + HalpEisaInterrupt2Mask |= (UCHAR) 1 << Vector; + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1, + HalpEisaInterrupt2Mask + ); + + } else { + + // + // The interrupt is in controller 1. + // + + Vector &= 0x7; + + // + // never disable IRQL2; it is the slave interrupt + // + + if (Vector != SLAVE_IRQL_LEVEL) { + HalpEisaInterrupt1Mask |= (ULONG) 1 << Vector; + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1, + HalpEisaInterrupt1Mask + ); + } + } +} + +VOID +HalpEnableEisaInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ) + +/*++ + +Routine Description: + + This function enables the EISA interrupt specified by Vector. +Arguments: + + Vector - Supplies the vector of the EISA interrupt that is enabled. + + InterruptMode - Supplies the mode of the interrupt; LevelSensitive or + Latched. + +Return Value: + + None. + +--*/ + +{ + // + // Calculate the EISA interrupt vector. + // + + Vector -= EISA_VECTORS; + + // + // Determine if this vector is for interrupt controller 1 or 2. + // + + if (Vector & 0x08) { + + // + // The interrupt is in controller 2. + // + + Vector &= 0x7; + + HalpEisaInterrupt2Mask &= (UCHAR) ~(1 << Vector); + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1, + HalpEisaInterrupt2Mask + ); + + // + // Set the level/edge control register. + // + + if (InterruptMode == LevelSensitive) { + + HalpEisaInterrupt2Level |= (UCHAR) (1 << Vector); + + } else { + + HalpEisaInterrupt2Level &= (UCHAR) ~(1 << Vector); + + } + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2EdgeLevel, + HalpEisaInterrupt2Level + ); + + } else { + + // + // The interrupt is in controller 1. + // + + Vector &= 0x7; + + HalpEisaInterrupt1Mask &= (UCHAR) ~(1 << Vector); + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1, + HalpEisaInterrupt1Mask + ); + + // + // Set the level/edge control register. + // + + if (InterruptMode == LevelSensitive) { + + HalpEisaInterrupt1Level |= (UCHAR) (1 << Vector); + + } else { + + HalpEisaInterrupt1Level &= (UCHAR) ~(1 << Vector); + + } + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1EdgeLevel, + HalpEisaInterrupt1Level + ); + } +} + +BOOLEAN +HalpEisaDispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PKTRAP_FRAME TrapFrame + ) +/*++ + +Routine Description: + + This routine is entered as the result of an interrupt being generated + via the vector that is connected to an interrupt object that describes + the EISA device interrupts. Its function is to call the second-level + interrupt dispatch routine and acknowledge the interrupt at the ESC + controller. + + This service routine could be connected as follows: + + KeInitializeInterrupt(&Interrupt, HalpDispatch, + EISA_VIRTUAL_BASE, + (PKSPIN_LOCK)NULL, ISA_LEVEL, ISA_LEVEL, ISA_LEVEL, + LevelSensitive, TRUE, 0, FALSE); + KeConnectInterrupt(&Interrupt); + +Arguments: + + Interrupt - Supplies a pointer to the interrupt object. + + ServiceContext - Supplies a pointer to the EISA interrupt acknowledge + register. + + TrapFrame - Supplies a pointer to the trap frame for this interrupt. + +Return Value: + + Returns the value returned from the second level routine. + +--*/ +{ + UCHAR EISAVector; + PKPRCB Prcb; + BOOLEAN returnValue; + USHORT PCRInOffset; + UCHAR Int1Isr; + UCHAR Int2Isr; + PULONG DispatchCode; + PKINTERRUPT InterruptObject; + + // + // Acknowledge the Interrupt controller and receive the returned + // interrupt vector. + // + + EISAVector = HalpAcknowledgeEisaInterrupt(ServiceContext); + + + if ((EISAVector & 0x07) == 0x07) { + + // + // Check for a passive release by looking at the inservice register. + // If there is a real IRQL7 interrupt, just go along normally. If there + // is not, then it is a passive release. So just dismiss it. + // + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0, + 0x0B + ); + + Int1Isr = READ_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0); + + // + // do second controller + // + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0, + 0x0B + ); + + Int2Isr = READ_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0); + + + if (!(Int2Isr & 0x80) && !(Int1Isr & 0x80)) { + + // + // Clear the master controller to clear situation + // + + if (!(Int2Isr & 0x80)) { + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0, + NONSPECIFIC_END_OF_INTERRUPT + ); + + } + + return FALSE; // ecrfix - now returns a value + + } + } + + // + // Dispatch to the secondary interrupt service routine. + // + + PCRInOffset = EISAVector + EISA_VECTORS; + DispatchCode = (PULONG)PCR->InterruptRoutine[PCRInOffset]; + InterruptObject = CONTAINING_RECORD(DispatchCode, + KINTERRUPT, + DispatchCode); + + returnValue = ((PSECOND_LEVEL_DISPATCH) + InterruptObject->DispatchAddress)(InterruptObject); + + // + // Dismiss the interrupt in the ESC interrupt controllers. + // + + // + // If this is a cascaded interrupt then the interrupt must be dismissed in + // both controlles. + // + + if (EISAVector & 0x08) { + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0, + NONSPECIFIC_END_OF_INTERRUPT + ); + } + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0, + NONSPECIFIC_END_OF_INTERRUPT + ); + + return(returnValue); +} diff --git a/private/ntos/nthals/halraw/alpha/pcisup.c b/private/ntos/nthals/halraw/alpha/pcisup.c new file mode 100644 index 000000000..360919f42 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/pcisup.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\pcisup.c" + diff --git a/private/ntos/nthals/halraw/alpha/pcrtc.c b/private/ntos/nthals/halraw/alpha/pcrtc.c new file mode 100644 index 000000000..b5006ddf7 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/pcrtc.c @@ -0,0 +1,383 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + pcrtc.c + +Abstract: + + This module implements the HAL set/query realtime clock routines for + the standard pc-compatible real time clock use on Alpha AXP systems. + +Author: + + David N. Cutler (davec) 5-May-1991 + Jeff McLeman (mcleman) 3-Jun-1992 + +Environment: + + Kernel mode + +Revision History: + + 13-Jul-1992 Jeff McLeman + use VTI access routines to access clock + + 3-June-1992 Jeff McLeman + Adapt this module into a Jensen specific module + +--*/ + +#include "halp.h" +#include "pcrtc.h" + +// +// Local function prototypes. +// + +BOOLEAN +HalQueryRealTimeClock ( + OUT PTIME_FIELDS TimeFields + ); + +BOOLEAN +HalSetRealTimeClock ( + IN PTIME_FIELDS TimeFields + ); + +UCHAR +HalpReadClockRegister ( + UCHAR Register + ); + +VOID +HalpWriteClockRegister ( + UCHAR Register, + UCHAR Value + ); + +#ifdef AXP_FIRMWARE + +// +// Put these functions in the discardable text section. +// + +#pragma alloc_text(DISTEXT, HalQueryRealTimeClock ) +#pragma alloc_text(DISTEXT, HalSetRealTimeClock ) +#pragma alloc_text(DISTEXT, HalpReadClockRegister ) +#pragma alloc_text(DISTEXT, HalpWriteClockRegister ) + +#endif // AXP_FIRMWARE + +// +// Define globals used to map the realtime clock address and data ports. +// + +PVOID HalpRtcAddressPort = NULL; +PVOID HalpRtcDataPort = NULL; + + +BOOLEAN +HalQueryRealTimeClock ( + OUT PTIME_FIELDS TimeFields + ) + +/*++ + +Routine Description: + + This routine queries the realtime clock. + + N.B. This routine assumes that the caller has provided any required + synchronization to query the realtime clock information. + +Arguments: + + TimeFields - Supplies a pointer to a time structure that receives + the realtime clock information. + +Return Value: + + If the power to the realtime clock has not failed, then the time + values are read from the realtime clock and a value of TRUE is + returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + + UCHAR DataByte; + BOOLEAN Status; + KIRQL OldIrql; + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + // + // If the realtime clock battery is still functioning, then read + // the realtime clock values, and return a function value of TRUE. + // Otherwise, return a function value of FALSE. + // + + DataByte = HalpReadClockRegister(RTC_CONTROL_REGISTERD); + if (((PRTC_CONTROL_REGISTER_D)(&DataByte))->ValidTime == 1) { + + // + // Wait until the realtime clock is not being updated. + // + + do { + DataByte = HalpReadClockRegister(RTC_CONTROL_REGISTERA); + } while (((PRTC_CONTROL_REGISTER_A)(&DataByte))->UpdateInProgress == 1); + + // + // Read the realtime clock values. + // + + TimeFields->Year = 1980 + (CSHORT)HalpReadClockRegister(RTC_YEAR); + TimeFields->Month = (CSHORT)HalpReadClockRegister(RTC_MONTH); + TimeFields->Day = (CSHORT)HalpReadClockRegister(RTC_DAY_OF_MONTH); + TimeFields->Weekday = (CSHORT)HalpReadClockRegister(RTC_DAY_OF_WEEK) - 1; + TimeFields->Hour = (CSHORT)HalpReadClockRegister(RTC_HOUR); + TimeFields->Minute = (CSHORT)HalpReadClockRegister(RTC_MINUTE); + TimeFields->Second = (CSHORT)HalpReadClockRegister(RTC_SECOND); + TimeFields->Milliseconds = 0; + Status = TRUE; + + } else { + Status = FALSE; + } + + KeLowerIrql(OldIrql); + return(Status); +} + +BOOLEAN +HalSetRealTimeClock ( + IN PTIME_FIELDS TimeFields + ) + +/*++ + +Routine Description: + + This routine sets the realtime clock. + + N.B. This routine is required to provide any synchronization necessary + to set the realtime clock information. + +Arguments: + + TimeFields - Supplies a pointer to a time structure that specifies the + realtime clock information. + +Return Value: + + If the power to the realtime clock has not failed, then the time + values are written to the realtime clock and a value of TRUE is + returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + KIRQL OldIrql; + + UCHAR DataByte; + + // + // If the realtime clock battery is still functioning, then write + // the realtime clock values, and return a function value of TRUE. + // Otherwise, return a function value of FALSE. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + DataByte = HalpReadClockRegister(RTC_CONTROL_REGISTERD); + if (((PRTC_CONTROL_REGISTER_D)(&DataByte))->ValidTime == 1) { + + // + // Set the realtime clock control to set the time. + // + + DataByte = 0; + ((PRTC_CONTROL_REGISTER_B)(&DataByte))->HoursFormat = 1; + ((PRTC_CONTROL_REGISTER_B)(&DataByte))->DataMode = 1; + ((PRTC_CONTROL_REGISTER_B)(&DataByte))->SetTime = 1; + +#ifdef RTC_SQE + + // + // If the platform requires it, make sure that the Square + // Wave output of the RTC is turned on. + // + + ((PRTC_CONTROL_REGISTER_B)(&DataByte))->SquareWaveEnable = 1; + +#endif //RTC_SQE + + HalpWriteClockRegister(RTC_CONTROL_REGISTERB, DataByte); + + // + // Write the realtime clock values. + // + + HalpWriteClockRegister(RTC_YEAR, (UCHAR)(TimeFields->Year - 1980)); + HalpWriteClockRegister(RTC_MONTH, (UCHAR)TimeFields->Month); + HalpWriteClockRegister(RTC_DAY_OF_MONTH, (UCHAR)TimeFields->Day); + HalpWriteClockRegister(RTC_DAY_OF_WEEK, (UCHAR)(TimeFields->Weekday + 1)); + HalpWriteClockRegister(RTC_HOUR, (UCHAR)TimeFields->Hour); + HalpWriteClockRegister(RTC_MINUTE, (UCHAR)TimeFields->Minute); + HalpWriteClockRegister(RTC_SECOND, (UCHAR)TimeFields->Second); + + // + // Set the realtime clock control to update the time. + // (Make sure periodic interrupt is enabled) + // + + ((PRTC_CONTROL_REGISTER_B)(&DataByte))->SetTime = 0; + ((PRTC_CONTROL_REGISTER_B)(&DataByte))->TimerInterruptEnable = 1; + HalpWriteClockRegister(RTC_CONTROL_REGISTERB, DataByte); + KeLowerIrql(OldIrql); + return TRUE; + + } else { + KeLowerIrql(OldIrql); + return FALSE; + } +} + + +UCHAR +HalpReadClockRegister ( + UCHAR Register + ) + +/*++ + +Routine Description: + + This routine reads the specified realtime clock register. + +Arguments: + + Register - Supplies the number of the register whose value is read. + +Return Value: + + The value of the register is returned as the function value. + +--*/ + +{ + // + // Read the realtime clock register value. + // + + WRITE_PORT_UCHAR( HalpRtcAddressPort, Register ); + + return READ_PORT_UCHAR( HalpRtcDataPort ); +} + +VOID +HalpWriteClockRegister ( + UCHAR Register, + UCHAR Value + ) + +/*++ + +Routine Description: + + This routine writes the specified value to the specified realtime + clock register. + +Arguments: + + Register - Supplies the number of the register whose value is written. + + Value - Supplies the value that is written to the specified register. + +Return Value: + + None + +--*/ + +{ + // + // Write the realtime clock register value. + // + + WRITE_PORT_UCHAR( HalpRtcAddressPort, Register ); + + WRITE_PORT_UCHAR( HalpRtcDataPort, Value ); + + return; +} + + +#if 0 // ecrfix - should not be in this common routine!!!! +VOID +HalpProgramIntervalTimer( + IN ULONG RateSelect + ) + +/*++ + +Routine Description: + + This function is called to program the interval timer. It is used during + Phase 1 initialization to start the heartbeat timer. It also used by + the clock interrupt interrupt routine to change the hearbeat timer rate + when a call to HalSetTimeIncrement has been made in the previous time slice. + + On Sable the periodic interrupt comes from the square ware output of + the Dallas 1489A RTC on the Standard I/O board. Each processor + receives this clock phase shifted by at least 90 degrees from all + other processors. The periodic interrupt from the RTC is not used and + thus doesn't need to be enabled or acknowledged. Each processor has + its own clock interrupt latch that is cleared locally. This routine is + not used for Sable platforms. + + Because of the phase shifting among the processors, the clock is + half the rate given to the RTC. So, the RTC is programmed twice + as fast as on a system that takes the RTC periodic interrupt in + directly. + +Arguments: + + RateSelect - Supplies rate select to be placed in the clock. + +Return Value: + + None. + +--*/ + +{ + UCHAR DataByte; + + // + // Set the new rate + // + DataByte = 0; + ((PRTC_CONTROL_REGISTER_A)(&DataByte))->RateSelect = (UCHAR)RateSelect; + ((PRTC_CONTROL_REGISTER_A)(&DataByte))->TimebaseDivisor = RTC_TIMEBASE_DIVISOR; + HalpWriteClockRegister( RTC_CONTROL_REGISTERA, DataByte ); + + // + // Set the correct mode + // + DataByte = 0; +#if defined(RTC_SQE) + ((PRTC_CONTROL_REGISTER_B)(&DataByte))->SquareWaveEnable = 1; +#else + ((PRTC_CONTROL_REGISTER_B)(&DataByte))->TimerInterruptEnable = 1; +#endif + + ((PRTC_CONTROL_REGISTER_B)(&DataByte))->HoursFormat = 1; + ((PRTC_CONTROL_REGISTER_B)(&DataByte))->DataMode = 1; + HalpWriteClockRegister( RTC_CONTROL_REGISTERB, DataByte ); +} +#endif diff --git a/private/ntos/nthals/halraw/alpha/pcserial.c b/private/ntos/nthals/halraw/alpha/pcserial.c new file mode 100644 index 000000000..a2f159c48 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/pcserial.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\pcserial.c" + diff --git a/private/ntos/nthals/halraw/alpha/pcspeakr.c b/private/ntos/nthals/halraw/alpha/pcspeakr.c new file mode 100644 index 000000000..807b6f324 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/pcspeakr.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\pcspeakr.c" + diff --git a/private/ntos/nthals/halraw/alpha/perf8254.c b/private/ntos/nthals/halraw/alpha/perf8254.c new file mode 100644 index 000000000..5fade7e42 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/perf8254.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\perf8254.c" + diff --git a/private/ntos/nthals/halraw/alpha/pintolin.h b/private/ntos/nthals/halraw/alpha/pintolin.h new file mode 100644 index 000000000..44cc02593 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/pintolin.h @@ -0,0 +1,214 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + pintolin.h + +Abstract: + + This file includes the platform-dependent Pin To Line Tables + +Author: + + Steve Brooks 6-July 1994 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +// +// These tables represent the mapping from slot number and interrupt pin +// into a PCI Interrupt Vector. +// +// Formally, these mappings can be expressed as: +// +// PCIPinToLine: +// SlotNumber.DeviceNumber x InterruptPin -> InterruptLine +// +// LineToVector: +// InterruptLine -> InterruptVector +// +// VectorToIRRBit: +// InterruptVector -> InterruptRequestRegisterBit +// +// VectorToIMRBit: +// InterruptVector -> InterruptMaskRegisterBit +// +// SlotNumberToIDSEL: +// SlotNumber.DeviceNumber -> IDSEL +// +// subject to following invariants (predicates must always be true): +// +// Slot.DeviceNumber in {0,...,15} +// +// InterruptPin in {1, 2, 3, 4} +// +// InterruptRequestRegisterBit in {0,...,15} +// +// InterruptMaskRegisterBit in {0,...,15} +// +// PCIPinToLine(SlotNumber.DeviceNumber, InterruptPin) = +// PCIPinToLineTable[SlotNumber.DeviceNumber, InterruptPin] +// (Table-lookup function initialized below) +// +// LineToVector(InterruptLine) = PCI_VECTORS + InterruptLine +// +// VectorToIRRBit(InterruptVector) = InterruptVector - 1 +// +// VectorToIMRBit(InterruptVector) [see below] +// +// SlotNumberToIDSEL(SlotNumber.DeviceNumber) = (1 << (Slot.DeviceNumber+11)) +// +// where: +// +// SlotNumber.DeviceNumber: +// Alpha AXP Platforms receive interrupts on local PCI buses only, which +// are limited to 16 devices (PCI AD[11]-AD[26]). (We loose AD[27]-AD[31] +// since PCI Config space is a sparse space, requiring a five-bit shift.) +// +// InterruptPin: +// Each virtual slot has up to four interrupt pins INTA#, INTB#, INTC#, INTD#, +// as per the PCI Spec. V2.0, Section 2.2.6. (FYI, only multifunction devices +// use INTB#, INTC#, INTD#.) +// +// PCI configuration space indicates which interrupt pin a device will use +// in the InterruptPin register, which has the values: +// +// INTA# = 1, INTB#=2, INTC#=3, INTD# = 4 +// +// Note that there may be up to 8 functions/device on a PCI multifunction +// device plugged into the option slots, e.g., Slot #0. +// Each function has it's own PCI configuration space, addressed +// by the SlotNumber.FunctionNumber field, and will identify which +// interrput pin of the four it will use in it's own InterruptPin register. +// +// If the option is a PCI-PCI bridge, interrupts across the bridge will +// somehow be combined to appear on some combination of the four +// interrupt pins that the bridge plugs into. +// +// InterruptLine: +// This PCI Configuration register, unlike x86 PC's, is maintained by +// software and represents offset into PCI interrupt vectors. +// Whenever HalGetBusData or HalGetBusDataByOffset is called, +// HalpPCIPinToLine() computes the correct InterruptLine register value +// by using the HalpPCIPinToLineTable mapping. +// +// InterruptRequestRegisterBit: +// 0xff is used to mark an invalid IRR bit, hence an invalid request +// for a vector. Also, note that the 16 bits of the EB66 IRR must +// be access as two 8-bit reads. +// +// InterruptMaskRegisterBit: +// On EB66, the PinToLine table may also be find the to write the +// InterruptMaskRegister. Formally, we can express this invariant as +// +// VectorToIMRBit(InterrruptVector) = InterruptVector - 1 +// +// +// IDSEL: +// For accessing PCI configuration space on a local PCI bus (as opposed +// to over a PCI-PCI bridge), type 0 configuration cycles must be generated. +// In this case, the IDSEL pin of the device to be accessed is tied to one +// of the PCI Address lines AD[11] - AD[26]. (The function field in the +// PCI address is used should we be accessing a multifunction device.) +// Anyway, virtual slot 0 represents the device with IDSEL = AD[11], and +// so on. +// + +// +// Interrupt Vector Table Mapping for Rawhide. +// +// Alcor PCI interrupts are mapped to arbitrary interrupt numbers +// in the table below. The values are a 1-1 map of the bit numbers +// in the Alcor PCI interrupt register that are connected to PCI +// devices. N.B.: there are two other interrupts in this register, +// but they are not connected to I/O devices, so they're not +// represented in the table. +// +// Limit init table to 5 entries, which is the +// MAX_PCI_LOCAL_DEVICE. +// +// We won't ever try to set an InterruptLine register of a slot +// greater than Virtual slot 5 = PCI_AD[16]. +// +// ecrfix - I don't do this, but I might.... +// N.B. - Have biased the bus interrupt vectors/levels for PCI to start +// at 0x11 so they are disjoint from EISA levels +// + +// +// Offset the pin-to-line entries by an offset of 0x20 so interrupt +// vectors reported by WinXXX will be unique. +// + +enum _RAWHIDE_PIN_TO_LINE { + RawhideNcr810PinToLine = (RawhidePinToLineOffset + 0x11) +}; + +ULONG *HalpPCIPinToLineTable; + +ULONG RawhidePCIPinToLineTable[][4]= +{ + // + // Virtual Slot 0 = PCI_AD[11] + // + + { 0xff, // Pin 1 + 0xff, // Pin 2 + 0xff, // Pin 3 + 0xff }, // Pin 4 + + // + // Virtual Slot 1 = PCI_AD[12] EISA/NCR810 + // + + { RawhidePinToLineOffset + 0x11, // Pin 1 + 0xff, // Pin 2 + 0xff, // Pin 3 + 0xff }, // Pin 4 + + // + // Virtual Slot 2 = PCI_AD[13] Slot #0 + // + + { RawhidePinToLineOffset + 0x01, // Pin 1 + RawhidePinToLineOffset + 0x02, // Pin 2 + RawhidePinToLineOffset + 0x03, // Pin 3 + RawhidePinToLineOffset + 0x04 },// Pin 4 + + // + // Virtual Slot 3 = PCI_AD[14] Slot #1 + // + + { RawhidePinToLineOffset + 0x05, // Pin 1 + RawhidePinToLineOffset + 0x06, // Pin 2 + RawhidePinToLineOffset + 0x07, // Pin 3 + RawhidePinToLineOffset + 0x08 },// Pin 4 + + // + // Virtual Slot 4 = PCI_AD[15] Slot #2 + // + + { RawhidePinToLineOffset + 0x09, // Pin 1 + RawhidePinToLineOffset + 0x0a, // Pin 2 + RawhidePinToLineOffset + 0x0b, // Pin 3 + RawhidePinToLineOffset + 0x0c },// Pin 4 + + // + // Virtual Slot 5 = PCI_AD[16] Slot #3 + // + + { RawhidePinToLineOffset + 0x0d, // Pin 1 + RawhidePinToLineOffset + 0x0e, // Pin 2 + RawhidePinToLineOffset + 0x0f, // Pin 3 + RawhidePinToLineOffset + 0x10 } // Pin 4 +}; + diff --git a/private/ntos/nthals/halraw/alpha/rawerr.c b/private/ntos/nthals/halraw/alpha/rawerr.c new file mode 100644 index 000000000..b30d9b19e --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/rawerr.c @@ -0,0 +1,154 @@ +/*++ + +Copyright (c) 1995 Digital Equipment Corporation + +Module Name: + + rawerr.c + +Abstract: + + This module implements error handling (machine checks and error + interrupts) for the Rawhide platform. + +Author: + + Eric Rehm 13-Apr-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "halp.h" +#include "rawhide.h" + +// +// Declare the extern variables. +// + +extern PERROR_FRAME PUncorrectableError; + +// +// Function prototypes. +// + +VOID +HalpSetMachineCheckEnables( + IN BOOLEAN DisableMachineChecks, + IN BOOLEAN DisableProcessorCorrectables, + IN BOOLEAN DisableSystemCorrectables + ); + +BOOLEAN +HalHandleNMI( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + + +VOID +HalpCacheErrorInterrupt( + VOID + ) +/*++ + +Routine Description: + + This routine is the interrupt handler for a Rawhide machine check interrupt + The function calls HalpIodReportFatalError() + +Arguments: + + None. + +Return Value: + + None. If a Fatal Error is detected the system is crashed. + +--*/ +{ + MC_DEVICE_ID McDeviceId; + + HalAcquireDisplayOwnership(NULL); + + // + // Display the dreaded banner. + // + + HalDisplayString( "\nFatal system hardware error.\n\n" ); + + // + // If this is a IOD uncorrectable error then report the error and + // crash the system. + // + + if( HalpIodUncorrectableError( &McDeviceId ) == TRUE ){ + + HalpIodReportFatalError( McDeviceId); + + KeBugCheckEx( DATA_BUS_ERROR, + 0xfacefeed, //jnfix - quick error interrupt id + McDeviceId.all, + 0, + (ULONG) PUncorrectableError ); + + } + + // + // It was not a IOD uncorrectable error, therefore this must be an + // NMI interrupt. + // + + HalHandleNMI( NULL, NULL ); + + return; // never + +} + + +BOOLEAN +HalpPlatformMachineCheck( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN PKTRAP_FRAME TrapFrame + ) +/*++ + +Routine Description: + + This routine is given control when an hard error is acknowledged + by the IOD chipset. The routine is given the chance to + correct and dismiss the error. + +Arguments: + + ExceptionRecord - Supplies a pointer to the exception record generated + at the point of the exception. + + ExceptionFrame - Supplies a pointer to the exception frame generated + at the point of the exception. + + TrapFrame - Supplies a pointer to the trap frame generated + at the point of the exception. + +Return Value: + + TRUE is returned if the machine check has been handled and dismissed - + indicating that execution can continue. FALSE is return otherwise. + +--*/ +{ + + // + // All machine check handling on Rawhide is determined by the IOD. + // + + return( HalpIodMachineCheck( ExceptionRecord, + ExceptionFrame, + TrapFrame ) ); + +} diff --git a/private/ntos/nthals/halraw/alpha/rawerror.h b/private/ntos/nthals/halraw/alpha/rawerror.h new file mode 100644 index 000000000..dd2d38787 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/rawerror.h @@ -0,0 +1,301 @@ +/*++ + +Copyright (c) 1995 Digital Equipment Corporation + +Module Name: + + rawerror.h + +Abstract: + + This file defines the structures and definitions of correctable and + uncorrectable Rawhide error frames, as well as various optional + subpackets, snapshots, and frames. + +Author: + + Eric Rehm 20-June-1995 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#ifndef _RAWERRORH_ +#define _RAWERRORH_ + +// +// Error Frame Revision definitions. +// + +#define UNCORRECTABLE_REVISION_1 (0) +#define UNCORRECTABLE_REVISION_2 (1) +#define CORRECTABLE_FRAME_REVISION_1 (0) +#define CORRECTABLE_FRAME_REVISION_2 (1) + + +// +// CPU Daughter Card (CUD) Header +// + +// #pragma pack(1) +typedef struct _CUD_HEADER { // As Per Rawhide SPM + ULONG Reserved0[4]; // (0x00-0x0c) + ULONG ActiveCpus; // (0x10) + ULONG Reserved1; // (0x14) + UCHAR SystemSN[10]; // (0x18-0x21) Same as FRU System Serial Number + UCHAR Reserved2[6]; // (0x22-0x27) + UCHAR ProcessorSN[10]; // (0x28-0x31) Module (processor) S/N, if available + USHORT ModType; // (0x32) + ULONG Reserved3; // (0x34) + ULONG DisabledResources; // (0x38) + ULONG SystemRev; // (0x3c) Same as FRY System Revision Level? +} CUD_HEADER, *PCUD_HEADER; + + + +// +// IOD Error Frame +// +// N.B. Used in Uncorrectable *and* correctable error frames for +// information on the IOD that recevied the machine check. +// It is uses as well in MC Bus snapshot (for each IOD) and Iod Register +// Subpacket. +// As far as I'm concerned, they IOD information is the same in each case. +// We can use the ValidBits field to optionally disable irrelevant +// fields. +// + +typedef struct _IOD_ERROR_FRAME { + ULONGLONG IodBaseAddr; // (0x00) + ULONG WhoAmI; // (0x08) - (Reserved in Rawhide SPM) + ULONG ValidBits; // (0x0c) + ULONG PciRev; // (0x10) + ULONG CapCtrl; // (0x14) + ULONG HaeMem; // (0x18) + ULONG HaeIo; // (0x1c) + ULONG IntCtrl; // (0x20) + ULONG IntReq; // (0x24) + ULONG IntMask0; // (0x28) + ULONG IntMask1; // (0x2c) + ULONG McErr0; // (0x30) + ULONG McErr1; // (0x34) + ULONG CapErr; // (0x38) + ULONG Reserved0; // (0x3c) + ULONG PciErr1; // (0x40) + ULONG MdpaStat; // (0x44) + ULONG MdpaSyn; // (0x48) + ULONG MdpbStat; // (0x4c) + ULONG MdpbSyn; // (0x50) + ULONG Reserved1[3]; // (0x54-0x5f) +} IOD_ERROR_FRAME, *PIOD_ERROR_FRAME; + +// +// IOD Error Frame Valid Bits +// +// Corresponds to bitfields of ValidBits in the Iod Error Frame +// + +typedef union _IOD_ERROR_FRAME_VALID_BITS { + struct { + ULONG IodBaseAddrValid: 1; // <0> + ULONG WhoAmIValid: 1; // <1> + ULONG PciRevValid: 1; // <2> + ULONG CapCtrlValid: 1; // <3> + ULONG HaeMemValid: 1; // <4> + ULONG HaeIoValid: 1; // <5> + ULONG IntCtrlValid: 1; // <6> + ULONG IntReqValid: 1; // <7> + ULONG IntMask0Valid: 1; // <8> + ULONG IntMask1Valid: 1; // <9> + ULONG McErr0Valid: 1; // <10> + ULONG McErr1Valid: 1; // <11> + ULONG CapErrValid: 1; // <12> + ULONG PciErr1Valid: 1; // <13> + ULONG MdpaStatValid: 1; // <14> + ULONG MdpaSynValid: 1; // <15> + ULONG MdpbStatValid: 1; // <16> + ULONG MdpbSynValid: 1; // <17> + }; + ULONG all; +} IOD_ERROR_FRAME_VALID_BITS, *PIOD_ERROR_FRAME_VALID_BITS; + +// +// Optional Snapshots for which headers or frames are defined below: +// PCI Bus Snapshot +// MC Bus Snapshot +// Memory Size Frame +// System Managment Frame +// ESC Frame +// + +// +// Flags indicating which of the optional snapshots or frames are present +// in a correctable or uncorrectable error frame +// + +typedef union _ERROR_SUBPACKET_FLAGS { + struct { + ULONGLONG Reserved0: 10; // <0:9> Reserved + ULONGLONG SysEnvPresent : 1; // <10> + ULONGLONG MemSizePreset : 1; // <11> + ULONGLONG Reserved1: 8; // <12:19> Reserved + ULONGLONG McBusPresent: 1; // <20> + ULONGLONG GcdBusPresent: 1; // <21> + ULONGLONG Reserved2: 8; // <22:29> Reserved + ULONGLONG IodSubpacketPresent: 1; // <30> + ULONGLONG PciSnapshotPresent: 1; // <31> + ULONGLONG EscSubpacketPresent: 1; // <32> + ULONGLONG Reserved3: 7; // <33:39> Reserved + ULONGLONG Iod2SubpacketPresent: 1; // <40> ??? + ULONGLONG Pci2SnapshotPresent: 1; // <41> ??? + }; + ULONGLONG all; +} ERROR_SUBPACKET_FLAGS, *PERROR_SUBPACKET_FLAGS; + + +// +// PCI Bus Snapshot Header +// +// Header is followed PCI_COMMON_CONFIG packets (256 bytes each) for each PCI +// device present in the system. Therefore, +// Length = sizeof (PCI_BUS_SNAPSHOT) + NumberOfNodes*sizeof(PCI_COMMON_CONFIG) +// +// N.B. PCI_COMMON_CONFIG is defined \nt\private\ntos\inc\pci.h +// + + +typedef struct _PCI_BUS_SNAPSHOT { + ULONG Length; // (0x00) + USHORT BusNumber; // (0x04) + USHORT NumberOfNodes; // (0x06) + // + // NumberOfNodes packets follow (0x08) + // +} PCI_BUS_SNAPSHOT, *PPCI_BUS_SNAPSHOT; + + + +// +// MC Bus Snapshot Header +// +// Header is followed a IOD_ERROR_FRAME for each IOD on the system; +// Therefore, +// Length = sizeof (MC_BUS_SNAPSHOT) + NumberOfIods*sizeof(IOD_ERROR_FRAME) +// + +typedef struct _MC_BUS_SNAPSHOT { + ULONG Length; // (0x00) + ULONG NumberOfIods; // (0x04) + ULONGLONG ReportingCpuBaseAddr; // (0x08) + // + // NumberOfIods packets follow (0x10) + // +} MC_BUS_SNAPSHOT, *PMC_BUS_SNAPSHOT; + + +// +// Memory Size Frame +// + +typedef struct _MEMORY_SIZE_FRAME { + ULONGLONG MemorySize; // (0x00) +} MEMORY_SIZE_FRAME, *PMEMORY_SIZE_FRAME; + +typedef union _MEMORY_SIZE { + struct { + ULONGLONG MemorySize0: 8; // <0:7> + ULONGLONG MemorySize1: 8; // <8:15> + ULONGLONG MemorySize2: 8; // <16:23> + ULONGLONG MemorySize3: 8; // <24:31> + ULONGLONG Reserved: 24; // <32:55> + ULONGLONG MemorySize0Valid: 1; // <56> + ULONGLONG MemorySize1Valid: 1; // <57> + ULONGLONG MemorySize2Valid: 1; // <58> + ULONGLONG MemorySize3Valid: 1; // <59> + }; + ULONGLONG all; +} MEMORY_SIZE, *PMEMORY_SIZE; + + +// +// System Managment Frame +// + +typedef struct _SYSTEM_MANAGEMENT_FRAME { + ULONGLONG SystemEnvironment; // (0x00) + ULONG Elcr2; // (0x08) (see IOD_ELCR2 in iod.h) + ULONG Reserved0; // (0x0c) +} SYSTEM_MANAGEMENT_FRAME, *PSYSTEM_MANAGEMENT_FRAME; + +typedef union _SYSTEM_ENVIRONMENT { + struct { + ULONGLONG FanFailReg: 8; // <0:7> I2C Fain Fail Register + ULONGLONG SensorReg1: 8; // <8:15> I2C Sensor Register 1 + ULONGLONG OpcControl: 8; // <16:23> I2C OPC Control + ULONGLONG SensorReg2: 8; // <24:31> I2C Sensor Register 2 + ULONGLONG Reserved: 24; // <32:55> I2C Sensor Register 1 + ULONGLONG FanFailValid: 1; // <56> + ULONGLONG SensorReg1Valid: 1; // <57> + ULONGLONG OpcControlValid: 1; // <58> + ULONGLONG SensorReg2Valid: 1; // <59> + }; + ULONGLONG all; +} SYSTEM_ENVIRONMENT, *PSYSTEM_ENVIRONMENT; + + +// +// ESC Frame +// +// This isn't just and ESC frame. EISA Id information is also contained herein. +// +// N.B. "index" refers to an indexed config ESC register accessed at index/data +// ports 0x22/0x23. +// + + +typedef struct _ESC_FRAME { + UCHAR Id[4]; // (0x00) "ESC\0" + ULONG ByteCount; // (0x04) ??? + UCHAR EscId; // (0x08) ESC ID Register (index 0x02) + UCHAR Filler0[7]; // (0x09-0x0f) + UCHAR Rid; // (0x0c) Revision Id (index 0x08) + UCHAR Filler1[3]; // (0x0d-0x0f) + UCHAR ModeSel; // (0x10) Mode Select Reg (index 0x40) + UCHAR Filler2[3]; // (0x11-0x13) + UCHAR EisaId[4]; // (0x14-0x17) EisaId of devices in EISA Slots + UCHAR SgRba; // (0x18) S-G Reloate Base Addr Reg (index 57) + UCHAR Filler3[3]; // (0x19-0x1b) + UCHAR Pirq[4]; // (0x1c-0x1f) PIRQ Route Ctrl (index 0x60-0x63) + UCHAR NmiSc; // (0x20) NMI Status & Ctrl (port 0x61) + UCHAR Filler4[3]; // (0x21-0x23) + UCHAR NmiEsc; // (0x24) NMI Ext. Status & Ctrl (port 0x461) + UCHAR Filler5[3]; // (0x25-0x27) + UCHAR LEisaMg; // (0x28) Last EISA Master Granted (port 0x464) + UCHAR Filler6[3]; // (0x29-0x2b) +} ESC_FRAME, *PESC_FRAME; + + +// +// Rawhide Uncorrectable (Hard) Error Frame +// Rawhide Correctable (Soft) Error Frame +// + +typedef union _RAWHIDE_CORRECTABLE_FRAME { + ULONG Revision; // (0x00) + ULONG Reserved0; // (0x04) + ULONGLONG ErrorSubpacketFlags; // (0x08) + CUD_HEADER CudHeader; // (0x10-0x4f) + IOD_ERROR_FRAME IodErrorFrame; // (0x50-0xaf) + // + // Optional Error Subpackets // (0xb0) + // as per ErrorSubpackFlags + // +} RAWHIDE_CORRECTABLE_FRAME, *PRAWHIDE_CORRECTABLE_FRAME, + RAWHIDE_UNCORRECTABLE_FRAME, *PRAWHIDE_UNCORRECTABLE_FRAME; + +#endif // _RAWERRORH_ diff --git a/private/ntos/nthals/halraw/alpha/rawhide.h b/private/ntos/nthals/halraw/alpha/rawhide.h new file mode 100644 index 000000000..9d237a01e --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/rawhide.h @@ -0,0 +1,349 @@ +/*++ + +Copyright (c) 1995 Digital Equipment Corporation + +Module Name: + + rawhide.h + +Abstract: + + This file contains definitions specific to the Rawhide platform + +Author: + + Eric Rehm 16-Feb-1995 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#ifndef _RAWHIDEH_ +#define _RAWHIDEH_ + +// +// Include definitions for the components that make up Alcor. +// + +#include "axp21164.h" // 21164 (EV5) microprocessor definitions +#include "stdarg.h" // VarArgs support +#include "iod.h" // CAP/MDP controller definitions +#include "rwintbal.h" // Interrupt Balancing definitions +#include "rwref.h" // Interrupt Vector Layout +#include "bitmap.h" // Local copy of RTL bitmap routines + +#define CACHE_BLOCK_SIZE 0x40 // 64 byte cache line size + +// +// Define number of PCI, EISA, and combo slots +// +// ecrfix - this is only good for PCI0 +// + +#define NUMBER_EISA_SLOTS 3 +#define NUMBER_PCI_SLOTS 4 +#define NUMBER_COMBO_SLOTS 1 + +// +// Define the data and csr ports for the I2C bus and OCP. +// + +#define I2C_INTERFACE_DATA_PORT 0x530 +#define I2C_INTERFACE_CSR_PORT 0x531 +#define I2C_INTERFACE_LENGTH 0x2 +#define I2C_INTERFACE_MASK 0x1 + +// +// Define the index and data ports for the NS Super IO chip. +// + +#define SUPERIO_INDEX_PORT 0x398 +#define SUPERIO_DATA_PORT 0x399 +#define SUPERIO_PORT_LENGTH 0x2 + +// +// Define the csr ports for Rawhide-specific Reset and Flash control +// + +#define RAWHIDE_RESET_PORT 0x26 +#define RAWHIDE_FLASH_CONTROL_PORT 0x27 + +// +// PCI bus address values: +// + +#define PCI_MAX_LOCAL_DEVICE 5 +#define PCI_MAX_INTERRUPT_VECTOR (MAXIMUM_PCI_VECTOR - PCI_VECTORS) + +// +// PCI bus interrupt vector base value +// + +#define RawhidePinToLineOffset 0x20 + +// +// Define the platform processor id type +// + +typedef MC_DEVICE_ID HALP_PROCESSOR_ID, *PHALP_PROCESSOR_ID; + +extern HALP_PROCESSOR_ID HalpLogicalToPhysicalProcessor[]; + +// +// Define numbers and names of cpus. +// + +#define RAWHIDE_PRIMARY_PROCESSOR ((ULONG) 0x0) +#define RAWHIDE_MAXIMUM_PROCESSOR ((ULONG) 0x3) + +#define HAL_PRIMARY_PROCESSOR (RAWHIDE_PRIMARY_PROCESSOR) +#define HAL_MAXIMUM_PROCESSOR (RAWHIDE_MAXIMUM_PROCESSOR) + +// +// Define maximum number of MC-PCI bus bridges +// + +#define RAWHIDE_MAXIMUM_PCI_BUS ((ULONG) 0x10) + +// +// NCR810 SCSI device on PCI bus 1 +// + +#define RAWHIDE_SCSI_PCI_BUS ((ULONG) 0x01) + +// +// Define default processor frequency. +// + +#define DEFAULT_PROCESSOR_FREQUENCY_MHZ (250) + +// +// Define Rawhide-specific routines that are really macros for performance. +// + +#define HalpAcknowledgeEisaInterrupt(x) (UCHAR) (INTERRUPT_ACKNOWLEDGE(x)) + +#if !defined (_LANGUAGE_ASSEMBLY) +// +// Define the per-processor data structures allocated in the PCR. +// + +typedef struct _RAWHIDE_PCR{ + ULONGLONG HalpCycleCount; // 64-bit per-processor cycle count + ULONGLONG IpirSva; // Superpage VA of per-perocessor IPIR CSR + PVOID CpuCsrsQva; // Qva of per-cpu csrs + EV5ProfileCount ProfileCount; // Profile counter state + PIOD_POSTED_INTERRUPT PostedInterrupts; // per-cpu area in vector table + } RAWHIDE_PCR, *PRAWHIDE_PCR; + +#define HAL_PCR ( (PRAWHIDE_PCR)(&(PCR->HalReserved)) ) + +// +// Rawhide Memory information. +// + +typedef enum _RAWHIDE_MEMORY_TYPE { + RawhideMemoryFree, // Good memory + RawhideMemoryHole, // Hole memory + RawhideMemoryBad, // Bad memory + RawhideMemoryMaximum +} RAWHIDE_MEMORY_TYPE; + + +typedef struct _RAWHIDE_MEMORY_DESCRIPTOR { + RAWHIDE_MEMORY_TYPE MemoryType; // From above + ULONG BasePage; // Base page number + ULONG PageCount; // Number of pages in this descriptor + ULONG bTested; // TRUE if memory has been tested +} RAWHIDE_MEMORY_DESCRIPTOR, *PRAWHIDE_MEMORY_DESCRIPTOR; + + +// +// Rawhide Resource Configuration Subpackets +// +// N.B. Only the System Platform Configuration Subpacket is defined +// + +// +// Echo data structure constructed for SRM FRU table +// +// N.B. Minimum value length is 4. +// + +#define TAG_INVALID 0 +#define TAG_ISO_LATIN1 1 +#define TAG_QUOTED 2 +#define TAG_BINARY 3 +#define TAG_UNICODE 4 +#define TAG_RESERVED 5 + +typedef struct _TLV { + USHORT Tag; // Code describing data type of field + USHORT Length; // Length of Value field in bytes (>=4) + ULONG Value; // Beginning of data +} TLV, *PTLV; + +// +// System Platform Configuration Subpacket +// + +#define SYSTEM_CONFIGURATION_SUBPACKET_CLASS 1 +#define SYSTEM_PLATFORM_SUBPACKET_TYPE 1 + +// +// System Platform Configuration Subpacket +// (As per Russ McManus Config & FRU Table doc, but no Environement Variables.) +// +// N.B., the length of this subpacket is variable due to TLV type fields. +// Total length of the subpacket is available in the Length field. +// +// Any field that is invalid will have TLV.Tag = 0. +// + +#if 0 +typedef struct _RAWHIDE_SYSTEM_CONFIGURATION { + USHORT Length; // (0x00) Total length of subpacket + USHORT Class; // (0x02) Subpacket class + USHORT Type; // (0x04) Subpacket type + USHORT Reserved; // (0x06) + TLV SystemManufacturer; // (0x08) System Manufacturer (string) + TLV SystemModel; // (....) Model Name (string) + TLV SystemSerialNumber; // (....) SystemSerialNumber (string) + TLV SystemRevisionLevel; // (....) SystemRevisionLevel (string) + TLV SystemVariation; // (....) SystemVariation + TLV ConsoleTypeRev; // (....) SRM Console Rev (string) +} RAWHIDE_SYSTEM_CONFIGURATION, *PRAWHIDE_SYSTEM_CONFIGURATION; +#endif + +// +// System Platform Configuration Subpacket +// +// (If you prefer something simpler....) + +typedef struct _RAWHIDE_SYSTEM_CONFIGURATION { + ULONG ValidBits; // (0x00) Valid fields below + UCHAR SystemManufacturer[80]; // (0x04) System Manufacturer (string) + UCHAR SystemModel[80]; // (0x54) Model Name (string) + UCHAR SystemSerialNumber[16]; // (0xA4) SystemSerialNumber (string) + UCHAR SystemRevisionLevel[4]; // (0xB4) SystemRevisionLevel (string) + UCHAR SystemVariation[80]; // (0xB8) SystemVariation + UCHAR ConsoleTypeRev[80]; // (0x108) SRM Console Rev (string) +} RAWHIDE_SYSTEM_CONFIGURATION, *PRAWHIDE_SYSTEM_CONFIGURATION; + +typedef union _RAWHIDE_SYSTEM_CONFIG_VALID_BITS { + struct { + ULONG SystemManufacturerValid: 1; // <0> + ULONG SystemModelValid: 1; // <1> + ULONG SystemSerialNumberValid: 1; // <2> + ULONG SystemRevisionLevel: 1; // <3> + ULONG SystemVariationValid: 1; // <4> + ULONG ConsoleTypeRevValid: 1; // <5> + }; + ULONG all; +} RAWHIDE_SYSTEM_CONFIG_VALID_BITS, *PRAWHIDE_SYSTEM_CONFIG_VALID_BITS; + + +// +// Define up to 64 Rawhide flags. +// + +typedef union _RAWHIDE_FLAGS { + struct { + ULONGLONG CpuMaskValid: 1; // <0> + ULONGLONG GcdMaskValid: 1; // <1> + ULONGLONG IodMaskValid: 1; // <2> + ULONGLONG SystemConfigValid: 1; // <3> + ULONGLONG MemoryDescriptorValid: 1; // <4> + }; + ULONGLONG all; +} RAWHIDE_FLAGS, *PRAWHIDE_FLAGS; + +// +// Define data structure for Rawhide machine dependent data +// + +typedef struct _RAWHIDE_SYSTEM_CLASS_DATA { + ULONG Length; // (0x00) Length of Rawhide spec. data + ULONG Version; // (0x04) Initially 0x1 + RAWHIDE_FLAGS Flags; // (0x08) + ULONGLONG CpuMask; // (0x10) <GID*8+MID> set if CPU presnt + ULONGLONG GcdMask; // (0x18) <GID*8+MID> set if GCD presnt + ULONGLONG IodMask; // (0x20) <GID*8+MID> set if IOD presnt + RAWHIDE_SYSTEM_CONFIGURATION SystemConfig; // (0x28) System config info + ULONG MemoryDescriptorCount; // (...)Number of memory descriptors + RAWHIDE_MEMORY_DESCRIPTOR MemoryDescriptor[1]; // (...) Array of descriptors +} RAWHIDE_SYSTEM_CLASS_DATA, *PRAWHIDE_SYSTEM_CLASS_DATA; + +// +// Rawhide interval timer data structure +// + +typedef struct _CLOCK_TABLE { + ULONG RollOver; + ULONG TimeIncr; +} CLOCK_TABLE, *PCLOCK_TABLE; + +#define NUM_CLOCK_RATES 4 +#define MAXIMUM_CLOCK_INCREMENT (NUM_CLOCK_RATES) +#define MINIMUM_CLOCK_INCREMENT 1 + +// +// Rawhide interrupt routine prototypes. +// + +BOOLEAN +HalpAcknowledgeRawhideClockInterrupt( + VOID + ); + +ULONG +HalpGetRawhidePciInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); + +ULONG +HalpGetRawhideEisaInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); + +ULONG +HalpGetRawhideInternalInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); + +VOID +HalpInitializeProcessorMapping( + IN ULONG LogicalProcessor, + IN ULONG PhysicalProcessor, + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +VOID +HalpInitializeSystemClassData( + ULONG Phase, + PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +#endif // !defined (_LANGUAGE_ASSEMBLY) + +#endif //_RAWHIDEH_ diff --git a/private/ntos/nthals/halraw/alpha/rwclock.c b/private/ntos/nthals/halraw/alpha/rwclock.c new file mode 100644 index 000000000..69a27aa27 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/rwclock.c @@ -0,0 +1,308 @@ +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + rwclock.c + +Abstract: + + This module implements the code necessary to field and process the + interval clock interrupt. + + +Author: + + Eric Rehm 1-Dec-1995 + +Environment: + + Kernel mode only. + +Revision History: + + +--*/ + +#include "halp.h" +#include "rawhide.h" + +// +// Define global data used to communicate new clock rates to the clock +// interrupt service routine. +// + +ULONG HalpCurrentTimeIncrement; +ULONG HalpNewTimeIncrement; + +ULONG HalpNextRateSelect; + +ULONG HalpCurrentRollOver[RAWHIDE_MAXIMUM_PROCESSOR+1]; +ULONG HalpNextRollOver; + +// +// The Rawhide Interval Timer has an accuracy of 100 ppm: +// Nominal: 833.3333 us +// Min: 833.41668 us +// Max: 833.25001 us +// +// The following clock table values indicated the number of actual +// clock interrupts we should take before we tell the system the time +// has changed (a.k.a "RollOver count"). Each RollOver count has +// and associated time increment = INT(RollOver * 833.3333 * 10) +// that is in units of 100 us. +// +// RollOver Time Nominal Error +// Count Increment MS (ms/day) + +CLOCK_TABLE +HalpRollOverTable[NUM_CLOCK_RATES] = + { {2, 16667}, // 1.667 ms + {3, 25000}, // 2.5 ms +0.864 + {6, 50000}, // 5.0 ms +1.728 + {9, 75000} // 7.5 ms +2.592 + +// {12, 100000}, // 10.0 ms +3.456 +// {15, 125000}, // 12.5 ms +4.320 +// {18, 150000} // 15.0 ms +5.184 +// debug {1, 8334} // .8333 ms +287.7 + + }; + +BOOLEAN +HalpAcknowledgeRawhideClockInterrupt( + VOID + ) +/*++ + +Routine Description: + + Acknowledge the clock interrupt from the interval timer. The interval + timer for Rawhide comes from an onboard oscillator, divided down + by the processor. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + MC_DEVICE_ID McDeviceId; + PKPRCB Prcb; + + + // + // Avoid a WhoAmI register read by using the PCR + // + + Prcb = PCR->Prcb; + McDeviceId.all = HalpLogicalToPhysicalProcessor[Prcb->Number].all; + + // + // Acknownledge the clock interrupt by writing to our own + // clock interrupt acknowledge. + // + + CPU_CLOCK_ACKNOWLEDGE( McDeviceId ); + + // + // Has the roll-over counter expired for this processor's clock? + // + + if ( (--HalpCurrentRollOver[Prcb->Number]) == 0 ) { + + // + // Yes. Reset count to latest RollOver count and + // tell caller to do something. + // + + HalpCurrentRollOver[Prcb->Number] = HalpNextRollOver; + return TRUE; + } + + // + // No. Tell caller to do nothing. + // + + return FALSE; + + +} + + +VOID +HalpProgramIntervalTimer( + IN ULONG RateSelect + ) + +/*++ + +Routine Description: + + This function is called to program the interval timer. It is used during + Phase 1 initialization to start the heartbeat timer. It also used by + the clock interrupt routine to change the hearbeat timer rate when a call + to HalSetTimeIncrement has been made in the previous time slice. + +Arguments: + + RateSelect - Supplies rate select to be placed in the clock. + +Return Value: + + None. + +--*/ + +{ + + ULONG i; + + // + // Set the new rate via the global "next" roll-over count. + // + // When each processor's private roll-over counter + // (HalpCurrentRollOver[i]) expires, it will be reset to the + // this global "next" roll-over count; + // + +#if HALDBG + DbgPrint( "HalpProgramIntervalTimer: Set to new rate %d, RollOver %d\n", + RateSelect, + HalpRollOverTable[RateSelect-1].RollOver ); +#endif // HALDBG + + HalpNextRollOver = HalpRollOverTable[RateSelect-1].RollOver; +} + + +VOID +HalpSetTimeIncrement( + VOID + ) +/*++ + +Routine Description: + + This routine is responsible for setting the time increment for an EV5 + based machine via a call into the kernel. This routine is + only called by the primary processor. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + ULONG i; + + // + // Set the time increment value. + // + + + HalpCurrentTimeIncrement + = HalpRollOverTable[MAXIMUM_CLOCK_INCREMENT-1].TimeIncr; + + + for (i = 0; i <= RAWHIDE_MAXIMUM_PROCESSOR; i++) { + HalpCurrentRollOver[i] = + HalpRollOverTable[MAXIMUM_CLOCK_INCREMENT-1].RollOver; + } + + HalpNextRollOver = + HalpRollOverTable[MAXIMUM_CLOCK_INCREMENT-1].RollOver; + + HalpNextRateSelect = 0; + + KeSetTimeIncrement( HalpRollOverTable[MAXIMUM_CLOCK_INCREMENT-1].TimeIncr, + HalpRollOverTable[MINIMUM_CLOCK_INCREMENT-1].TimeIncr); + +} + +ULONG +HalSetTimeIncrement ( + IN ULONG DesiredIncrement + ) + +/*++ + +Routine Description: + + This function is called to set the clock interrupt rate to the frequency + required by the specified time increment value. + +Arguments: + + DesiredIncrement - Supplies desired number of 100ns units between clock + interrupts. + +Return Value: + + The actual time increment in 100ns units. + +--*/ + +{ + KIRQL OldIrql; + ULONG rate; + ULONG BestIndex; + + // + // Raise IRQL to the highest level, set the new clock interrupt + // parameters, lower IRQl, and return the new time increment value. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + // + // Find the allowed increment that is less than or equal to + // the desired increment. + // + + for (rate = 1; rate < NUM_CLOCK_RATES; rate++) { + if (DesiredIncrement < HalpRollOverTable[rate].TimeIncr) { + break; + } + } + + BestIndex = rate - 1; + +#if HALDBG + DbgPrint( + "HalSetTimeIncrement: Desired %d, BestIndex: %d TimeIncr %d RollOver %d \n", + DesiredIncrement, + BestIndex, + HalpRollOverTable[BestIndex].TimeIncr, + HalpRollOverTable[BestIndex].RollOver + ); +#endif // HALDBG + + // + // Set the new time increment and the rate select (RollOverTable index) + // that will be used on the next tick of each processor's "soft" + // clock counter (HalpCurrentRollOver[i]). + // + + HalpNewTimeIncrement = HalpRollOverTable[BestIndex].TimeIncr; + HalpNextRateSelect = BestIndex + 1; + + + KeLowerIrql(OldIrql); + + return HalpNewTimeIncrement; + +} + + + + diff --git a/private/ntos/nthals/halraw/alpha/rwinitnt.c b/private/ntos/nthals/halraw/alpha/rwinitnt.c new file mode 100644 index 000000000..3ea569e93 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/rwinitnt.c @@ -0,0 +1,1324 @@ +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + rwinitnt.c + +Abstract: + + + This module implements the platform-specific initialization for + a Rawhide system. + +Author: + + Eric Rehm 4-May-1994 + +Environment: + + Kernel mode only. + +Revision History: + + +--*/ + +#include "halp.h" +#include "rawhide.h" +#include "iousage.h" +#include "stdio.h" + +// Includes for Error Logging + +#include "fwcallbk.h" // To get firmware revisions +#include <ntverp.h> // To O/S build number +#include "errframe.h" // Error Frame Definitions + +// +// Define extern global buffer for the Uncorrectable Error Frame. +// + +extern PERROR_FRAME PUncorrectableError; + +extern IOD_REGISTER_CLASS DumpIodFlag; + + +// +// Define the Product Naming data. +// + +PCHAR HalpFamilyName = "AlphaServer"; +PCHAR HalpProductName = "4000"; +ULONG HalpProcessorNumber = 5; + +#define MAX_INIT_MSG (80) + +PRAWHIDE_SYSTEM_CLASS_DATA HalpSystemClassData; +ULONG HalpNumberOfIods; +ULONG HalpNumberOfCpus; + + +// +// Define the bus type, this value allows us to distinguish between +// EISA and ISA systems. We're only interested in distinguishing +// between just those two buses. +// + +ULONG HalpBusType = MACHINE_TYPE_EISA; + +// +// Define external references. +// + +extern ULONG HalDisablePCIParityChecking; + +// +// Function prototypes. +// + +VOID +HalpInitializeProcessorParameters( + VOID + ); + +BOOLEAN +HalpInitializeRawhideInterrupts ( + VOID + ); + +VOID +HalpParseLoaderBlock( + PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +VOID +HalpRegisterPlatformResources( + PUCHAR HalName + ); + +#if HALDBG +VOID +HalpDumpSystemClassData( + PRAWHIDE_SYSTEM_CLASS_DATA SystemClassData +); +#endif // HALDBG + + +// +// Irql mask and tables +// +// irql 0 - passive +// irql 1 - sfw apc level +// irql 2 - sfw dispatch level +// irql 3 - device low +// irql 4 - device high +// irql 5 - interval clock +// irql 6 - not used +// irql 7 - error, mchk, nmi, performance counters +// +// + +// +// The hardware interrupt pins are used as follows for Rawhide +// +// IRQ0 = Reserved (unused) +// IRQ1 = IOD Interrupts (PCI, ESC, and CAP interrupts) +// IRQ2 = Interval Clock +// IRQ3 = IP Interrupt +// SYS_MCH_CHK_IRQ = Duplicate TAG parity error (cached CUD only) +// MCH_HLT_IRQ = Halt button or CPU halt +// + + +BOOLEAN +HalpInitializeInterrupts ( + VOID + ) + +/*++ + +Routine Description: + + This function initializes interrupts for an Alcor system. + +Arguments: + + None. + +Return Value: + + A value of TRUE is returned if the initialization is successfully + completed. Otherwise a value of FALSE is returned. + +--*/ + +{ + extern ULONG Halp21164CorrectedErrorInterrupt(); + extern VOID HalpCacheErrorInterrupt(); + extern ULONG HalpDeviceInterrupt(); +#if !defined(NT_UP) + extern VOID HalpIpiInterruptHandler(); +#endif //NT_UP + extern ULONG HalpHaltInterrupt(); + PKPRCB Prcb; + ULONG Vector; + + Prcb = PCR->Prcb; + + // + // Initialize interrupt handling for the primary processor and + // any system-wide interrupt initialization. + // + + if( Prcb->Number == HAL_PRIMARY_PROCESSOR ){ + +#if HALDBG + DbgPrint("HalpInitializeInterrupts: Primary Processor\n"); +#endif // HALDBG + // + // Initialize HAL processor parameters based on estimated CPU speed. + // This must be done before HalpStallExecution is called. Compute integral + // megahertz first to avoid rounding errors due to imprecise cycle clock + // period values. + // + +#if HALDBG + DbgPrint("HalpInitializeInterrupts: Init Processor Params\n"); +#endif // HALDBG + HalpInitializeProcessorParameters(); + + // + // Start the periodic interrupt from the RTC + // + +#if HALDBG + DbgPrint("HalpInitializeInterrupts: Program Interval Timer\n"); +#endif // HALDBG + HalpProgramIntervalTimer(MAXIMUM_CLOCK_INCREMENT); + + // + // Initialize Rawhide interrupts. + // + +#if HALDBG + DbgPrint("HalpInitializeInterrupts: Init Rawhide Interrupts\n"); +#endif // HALDBG + HalpInitializeRawhideInterrupts(); + + // + // Initialize the EV5 (21164) interrupts. + // + +#if HALDBG + DbgPrint("HalpInitializeInterrupts: Init 21164 Interrupts\n"); +#endif // HALDBG + HalpInitialize21164Interrupts(); + +#if HALDBG + DbgPrint("HalpInitializeInterrupts: Init IDT entries\n"); +#endif // HALDBG +#if 0 + PCR->InterruptRoutine[EV5_IRQ0_VECTOR] = // IRQ0 is unused on Rawhide + (PKINTERRUPT_ROUTINE) NULL; +#endif + + PCR->InterruptRoutine[EV5_IRQ1_VECTOR] = // IOD Interrupt + (PKINTERRUPT_ROUTINE)HalpDeviceInterrupt; + + PCR->InterruptRoutine[EV5_IRQ2_VECTOR] = // Interval Timer Interrupt + (PKINTERRUPT_ROUTINE)HalpClockInterrupt; + +#if !defined(NT_UP) + PCR->InterruptRoutine[EV5_IRQ3_VECTOR] = // IP Interrupt + (PKINTERRUPT_ROUTINE)HalpIpiInterruptHandler; +#endif //NT_UP + + PCR->InterruptRoutine[EV5_HALT_VECTOR] = // Halt button, CPU halt + (PKINTERRUPT_ROUTINE)HalpHaltInterrupt; + + PCR->InterruptRoutine[EV5_MCHK_VECTOR] = // Duplicate TAG Parity Error + (PKINTERRUPT_ROUTINE)HalpCacheErrorInterrupt; // (cached CUD only). + +#if HALDBG + DbgPrint("HalpInitializeInterrupts: Start 21164 Interrupts\n"); +#endif // HALDBG + HalpStart21164Interrupts(); + +#if HALDBG + DumpAllIods(DumpIodFlag & IodInterruptRegisters); + + DbgPrint("HalpInitializeInterrupts: Primary Processor Complete\n"); +#endif // HALDBG + + } else { + +#if !defined(NT_UP) +#if HALDBG + DbgPrint("HalpInitializeInterrupts: Secondary Processor\n"); +#endif // HALDBG + + // + + // + // Initialize the EV5 (21164) interrupts. + // + + HalpInitialize21164Interrupts(); + +#if 0 + PCR->InterruptRoutine[EV5_IRQ0_VECTOR] = // IRQ0 is unused on Rawhide + (PKINTERRUPT_ROUTINE) NULL; +#endif + + PCR->InterruptRoutine[EV5_IRQ1_VECTOR] = // IOD Interrupt + (PKINTERRUPT_ROUTINE)HalpDeviceInterrupt; + + PCR->InterruptRoutine[EV5_IRQ2_VECTOR] = // Interval Timer Interrupt + (PKINTERRUPT_ROUTINE)HalpSecondaryClockInterrupt; + + PCR->InterruptRoutine[EV5_IRQ3_VECTOR] = // IP Interrupt + (PKINTERRUPT_ROUTINE)HalpIpiInterruptHandler; + + PCR->InterruptRoutine[EV5_HALT_VECTOR] = // Halt button, CPU halt + (PKINTERRUPT_ROUTINE)HalpHaltInterrupt; + + PCR->InterruptRoutine[EV5_MCHK_VECTOR] = // Duplicate TAG Parity Error + (PKINTERRUPT_ROUTINE)HalpCacheErrorInterrupt; // (cached CUD only). + + HalpStart21164Interrupts(); +#endif //NT_UP + } + + return TRUE; + +} + + + + +VOID +HalpInitializeClockInterrupts( + VOID + ) + +/*++ + +Routine Description: + + This function is called during phase 1 initialization to complete + the initialization of clock interrupts. For EV4, this function + connects the true clock interrupt handler and initializes the values + required to handle profile interrupts. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ +#if 0 +// mdbfix - who references this? + // + // Compute the profile interrupt rate. + // + + HalpProfileCountRate = ((1000 * 1000 * 10) / KeQueryTimeIncrement()); +#endif + + // + // Set the time increment value and connect the real clock interrupt + // routine. + // + + PCR->InterruptRoutine[EV5_IRQ2_VECTOR] = HalpClockInterrupt; + + return; +} + + +VOID +HalpEstablishErrorHandler( + VOID + ) +/*++ + +Routine Description: + + This routine performs the initialization necessary for the HAL to + begin servicing machine checks. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + BOOLEAN PciParityChecking; + BOOLEAN ReportCorrectables; + + // + // Connect the machine check handler via the PCR. + // + + PCR->MachineCheckError = HalMachineCheck; + + HalpInitializeIodMachineChecks( ReportCorrectables = FALSE, + PciParityChecking = FALSE ); + + return; +} + + +VOID +HalpInitializeSystemClassData( + ULONG Phase, + PLOADER_PARAMETER_BLOCK LoaderBlock + ) +/*++ + +Routine Description: + + Initialize the Rawhide configuration masks passed in the ARC tree. + For phase 0, only initialize the hardware masks. Wait until phase 1, + (after memory manager started) to allocate and save. + +Arguments: + + LoaderBlock - Supplies a pointer to the loader parameter block. + +Return Value: + + None. + +--*/ +{ + PCONFIGURATION_COMPONENT_DATA ConfigComponent; + PRAWHIDE_SYSTEM_CLASS_DATA SystemClassData; + MC_ENUM_CONTEXT mcCtx; + + ConfigComponent = KeFindConfigurationEntry( + LoaderBlock->ConfigurationRoot, + SystemClass, // Class + ArcSystem, // Type + 0 + ); + + // + // Check for errors + // + + if ( (ConfigComponent == NULL) || + (ConfigComponent->ConfigurationData == NULL) ) { + +#if HALDBG + DbgPrint ("HalpInitializeSystemClassData: Configuration Data Missing\n"); + DbgBreakPoint (); +#endif // HALDBG + } + + + SystemClassData = (PRAWHIDE_SYSTEM_CLASS_DATA) + ConfigComponent->ConfigurationData; + + if (Phase == 0) { + +#if HALDBG + HalpDumpSystemClassData(SystemClassData); +#endif + + // + // Initialize the rawhide configuration masks + // + + HalpIodMask = SystemClassData->IodMask; + HalpCpuMask = SystemClassData->CpuMask; + HalpGcdMask = SystemClassData->GcdMask; + + HalpNumberOfIods = HalpMcBusEnumStart(HalpIodMask, &mcCtx); + HalpNumberOfCpus = HalpMcBusEnumStart(HalpCpuMask, &mcCtx); + + } else { + + // + // Allocate memory and save + // + + HalpSystemClassData = (PRAWHIDE_SYSTEM_CLASS_DATA) + ExAllocatePool(NonPagedPool, SystemClassData->Length); + + RtlMoveMemory( + HalpSystemClassData, + ConfigComponent->ConfigurationData, + SystemClassData->Length + ); + } + +} + +#if HALDBG +VOID +HalpDumpSystemClassData( + PRAWHIDE_SYSTEM_CLASS_DATA SystemClassData + ) +{ + +#define ONE_MB 1024 + + ULONG entry; + ULONGLONG TotalMemorySize; + ULONGLONG FreeMemorySize; + ULONGLONG BadMemorySize; + ULONGLONG EntrySizeInBytes; + + // + // Print out machine dependent data for debug + // + + DbgPrint("System Class Data:\r\n"); + DbgPrint("Length: %x\n", SystemClassData->Length); + DbgPrint("Version: %x\n", SystemClassData->Version); + DbgPrint("Flags: %8.8x %8.8x\n", SystemClassData->Flags.all >> 32, + SystemClassData->Flags); + DbgPrint("CpuMask: %8.8x %8.8x\n", SystemClassData->CpuMask >> 32, + SystemClassData->CpuMask); + DbgPrint("GcdMask: %8.8x %8.8x\n", SystemClassData->GcdMask >> 32, + SystemClassData->GcdMask); + DbgPrint("IodMask: %8.8x %8.8x\n", SystemClassData->IodMask >> 32, + SystemClassData->IodMask); + DbgPrint("System Configuration:\n"); + DbgPrint("\tValidBits: %x\n", SystemClassData->SystemConfig.ValidBits); + + DbgPrint("\tSystemManufacturer: %s\r\n", + SystemClassData->SystemConfig.SystemManufacturer); + + DbgPrint("\tSystemModel: %s\r\n", + SystemClassData->SystemConfig.SystemModel); + + DbgPrint("\tSystemSerialNumber: %s\r\n", + SystemClassData->SystemConfig.SystemSerialNumber); + + DbgPrint("\tSystemRevisionLevel: %s\r\n", + SystemClassData->SystemConfig.SystemRevisionLevel); + + DbgPrint("\tSystemVariation: %s\r\n", + SystemClassData->SystemConfig.SystemVariation); + + DbgPrint("\tSystemConsoleTypeRev: %s\r\n", + SystemClassData->SystemConfig.ConsoleTypeRev); + + DbgPrint("MemoryDescriptor is: %s\r\n", + (SystemClassData->Flags.MemoryDescriptorValid ? + "Valid" : "Invalid")); + DbgPrint("MemoryDescriptorCount: %d\r\n", + SystemClassData->MemoryDescriptorCount); + + DbgPrint("MemoryDescriptor is: %s\n", + (SystemClassData->Flags.MemoryDescriptorValid ? + "Valid" : "Invalid")); + DbgPrint("MemoryDescriptorCount: %d\n", SystemClassData->MemoryDescriptorCount); + + DbgPrint("Descriptor\tMemoryType\tBasePage\tPageCount\tSize\tTested?\n"); + + TotalMemorySize = 0; + FreeMemorySize = 0; + BadMemorySize = 0; + + for (entry = 0; entry < SystemClassData->MemoryDescriptorCount; entry++) { + + EntrySizeInBytes = + (SystemClassData->MemoryDescriptor[entry].PageCount) << PAGE_SHIFT; + + DbgPrint("[%d]\t\t%d\t\t%x\t\t%8x\t%4d Mb %x\n", + entry, + SystemClassData->MemoryDescriptor[entry].MemoryType, + SystemClassData->MemoryDescriptor[entry].BasePage, + SystemClassData->MemoryDescriptor[entry].PageCount, + (EntrySizeInBytes / ONE_MB), + SystemClassData->MemoryDescriptor[entry].bTested + ); + + // + // Total up free (good memory) entries + // + + if (SystemClassData->MemoryDescriptor[entry].MemoryType + == RawhideMemoryFree) { + FreeMemorySize += EntrySizeInBytes; + } + + // + // Total up hole (bad memory) entries + // Remember them so that they can be removed later. + // + + if (SystemClassData->MemoryDescriptor[entry].MemoryType + == RawhideMemoryBad) { + + // + // N.B. If this is the last descriptor, and it's a hole + // (bad memory), then ignore it. + // + + if (entry == (SystemClassData->MemoryDescriptorCount - 1)) { + break; + } + + BadMemorySize += EntrySizeInBytes; + + } + + // + // Total up all entries, except a trailing hole + // + + TotalMemorySize += EntrySizeInBytes; + + + } + + DbgPrint("Total Size:\t\t\t\t\t%8x\t%4d Mb\n\n", + (TotalMemorySize >> PAGE_SHIFT), + (TotalMemorySize / ONE_MB)); + DbgPrint("Free Memory Size:\t\t\t\t%8x\t%4d Mb\n", + (FreeMemorySize >> PAGE_SHIFT), + (FreeMemorySize / ONE_MB)); + DbgPrint("Bad Memory Size:\t\t\t\t%8x\t%4d Mb\n", + (BadMemorySize >> PAGE_SHIFT), + (BadMemorySize / ONE_MB)); + +} +#endif // HALDBG + + +VOID +HalpEarlyInitializeMachineDependent( + IN ULONG Phase, + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) +/*++ + +Routine Description: + + This function performs any critical Platform-specific initialization based on + the current phase on initialization. + +Arguments: + + Phase - Supplies an indicator for phase of initialization, phase 0 or + phase 1. + + LoaderBlock - supplies a pointer to the loader block. + +Return Value: + + None. + +--*/ +{ + + if( Phase == 0 ){ + + // + // Phase 0 Initialization. + // + + // + // Initialize the Rawhide hardware configuration masks from the + // SRM Machine Dependent Data passed in the Configuration Tree. + // + + HalpInitializeSystemClassData(Phase, LoaderBlock); + + } else { + + // + // Phase 1 Initialization. + // + + } + + return; + +} + + +VOID +HalpInitializeMachineDependent( + IN ULONG Phase, + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) +/*++ + +Routine Description: + + This function performs any Platform-specific initialization based on + the current phase on initialization. + +Arguments: + + Phase - Supplies an indicator for phase of initialization, phase 0 or + phase 1. + + LoaderBlock - supplies a pointer to the loader block. + +Return Value: + + None. + +--*/ +{ + ULONG BusIrql; + ULONG BusNumber; + UCHAR MsgBuffer[MAX_INIT_MSG]; + BOOLEAN ReportCorrectables; + BOOLEAN PciParityChecking; + PKPRCB Prcb; + PRAWHIDE_PCR pRawhidePcr; + IOD_POSTED_INTERRUPT_ADDR PostingTable; + IOD_WHOAMI IodWhoAmI; + + Prcb = PCR->Prcb; + +#if HALDBG + DbgPrint("HalpInitializeMachineDependent: Phase = %d\n", Phase); +#endif // HALDBG + + if( Prcb->Number == HAL_PRIMARY_PROCESSOR) { + + if( Phase == 0 ){ + + + // + // Phase 0 Initialization. + // + + // + // Parse the Loader Parameter block looking for PCI entry to determine + // if PCI parity should be disabled + // + +#if HALDBG + DbgPrint("HalpInitializeMachineDependent: Parse Loader Block\n"); +#endif // HALDBG + HalpParseLoaderBlock( LoaderBlock ); + + // + // Establish the error handler, to reflect the PCI parity checking. + // + +#if HALDBG + DbgPrint("HalpInitializeMachineDependent: \n"); +#endif // HALDBG + if( HalDisablePCIParityChecking != 0 ){ + PciParityChecking = FALSE; + } else { + PciParityChecking = TRUE; + } + +#if HALDBG + DbgPrint("HalpInitializeMachineDependent: Init Iod Machine Checks\n"); +#endif // HALDBG + HalpInitializeIodMachineChecks( ReportCorrectables = TRUE, + PciParityChecking ); + + // + // Initialize the IOD mapping table, assigning logical + // numbers to all IOD's. This logical number cooresponds + // to the HwBusNumber found in PCIPBUSDATA. + // + +#if HALDBG + DbgPrint("HalpInitializeMachineDependent: Init Iod Mapping Table\n"); +#endif // HALDBG + HalpMcBusEnumAndCall(HalpIodMask, HalpInitializeIodMappingTable); + + // + // Initialize the logical to physical processor mapping + // for the primary processor. + // + +#if HALDBG + DbgPrint("HalpInitializeMachineDependent: Init HalpLogicalToPhysicalProcesor\n"); +#endif // HALDBG + + HalpInitializeProcessorMapping( + HAL_PRIMARY_PROCESSOR, + HAL_PRIMARY_PROCESSOR, + LoaderBlock + ); + +#if HALDBG + DbgPrint("HalpInitializeMachineDependent: Phase %d complete\n", Phase); +#endif // HALDBG + } else { + + // + // Phase 1 Initialization. + // + + // + // Save the Machine Dependent Data now that Memory Manager started. + // + +#if HALDBG + DbgPrint("HalpInitializeMachineDependent: Init System Class Data\n"); +#endif // HALDBG + HalpInitializeSystemClassData(Phase, LoaderBlock); + + // + // Initialize the existing bus handlers. + // + +#if HALDBG + DbgPrint("HalpInitializeMachineDependent: Register Internal Bus Handlers\n"); +#endif // HALDBG + HalpRegisterInternalBusHandlers(); + + // + // Initialize PCI Bus. + // + +#if HALDBG + DbgPrint("HalpInitializeMachineDependent: Init PCI Bus\n"); +#endif // HALDBG + HalpInitializePCIBus(LoaderBlock); + + // + // Initialize the IOD vector table + // + +#if HALDBG + DbgPrint("HalpInitializeMachineDependent: Init Iod Vector Table\n"); +#endif // HALDBG + HalpInitializeIodVectorTable(); + + // + // Initialize the IOD interrupt vector table CSR's + // + +#if HALDBG + DbgPrint("HalpInitializeMachineDependent: Init Iod Vector CSRs\n"); +#endif // HALDBG + HalpMcBusEnumAndCall(HalpIodMask, HalpInitializeIodVectorCSRs); + + // + // Generate pointer to the CPU's area in the IOD vector table + // + + PostingTable.all = 0; + PostingTable.Base4KPage = ((ULONG)HalpIodPostedInterrupts / __4K); + PostingTable.CpuOffset = + HalpLogicalToPhysicalProcessor[PCR->Number].all; + + HAL_PCR->PostedInterrupts = + (PIOD_POSTED_INTERRUPT)PostingTable.all; + + // + // Initialize the IOD and CPU interrupt Vector table + // + + HalpInitializeVectorBalanceData(); + + // + // Initialize the CPU vector entry for this processor + // + + HalpInitializeCpuVectorData(PCR->Number); + + // + // Assign the primary processors vectors + // + + HalpAssignPrimaryProcessorVectors(&HalpIodVectorDataHead); + + // + // Initialize profiler. + // + +#if HALDBG + DbgPrint("HalpInitializeMachineDependent: Init Profiler\n"); +#endif // HALDBG + HalpInitializeProfiler(); + +#if HALDBG + DbgPrint("HalpInitializeMachineDependent: Print Version Message\n"); +#endif // HALDBG + // + // Print a message with version number. + // + + sprintf( MsgBuffer, + "Digital Equipment Corporation %s %s %d/%d\n", + HalpFamilyName, + HalpProductName, + HalpProcessorNumber, + HalpClockMegaHertz ); + + HalDisplayString( MsgBuffer ); + + // + // Register the name of the HAL. + // + + sprintf( MsgBuffer, + "%s %s %d/%d PCI/EISA HAL", + HalpFamilyName, + HalpProductName, + HalpProcessorNumber, + HalpClockMegaHertz ); + +#if HALDBG + DbgPrint("HalpInitializeMachineDependent: Register Platform Resources\n"); +#endif // HALDBG + HalpRegisterPlatformResources( MsgBuffer ); + +#if HALDBG + DbgPrint("HalpInitializeMachineDependent: Phase %d Complete\n", Phase); +#endif // HALDBG + } + + } else { + + // + // Connect the machine check handler via the PCR. The machine check + // handler for Rawhide is the default EV4 parity-mode handler. Note + // that this was done in HalpEstablishErrorHandler() for the + // primary processor. + // + + PCR->MachineCheckError = HalMachineCheck; + + // + // Generate pointer to the CPU's area in the IOD vector table + // + + PostingTable.all = 0; + PostingTable.Base4KPage = ((ULONG)HalpIodPostedInterrupts / __4K); + PostingTable.CpuOffset = HalpLogicalToPhysicalProcessor[PCR->Number].all; + + HAL_PCR->PostedInterrupts = (PIOD_POSTED_INTERRUPT)PostingTable.all; + + // + // Initialize profiler on this secondary processor. + // + + HalpInitializeProfiler(); + + // + // Initialize the CPU vector entry for this processor + // + + HalpInitializeCpuVectorData(PCR->Number); + + } + + return; + +} + + +VOID +HalpInitializeProcessorMapping( + IN ULONG LogicalProcessor, + IN ULONG PhysicalProcessor, + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) +/*++ + +Routine Description: + + This function initializes the logical to physical processor mapping + entry in the processor mapping table. The physical mapping is passed + by ARC FW via the configuration tree. + +Arguments: + + LogicalProcessor - logical processor number. + + PhysicalProcessor - restart block number. + + LoaderBlock - supplies a pointer to the loader block. + +Return Value: + + None. + +--*/ + + +{ + PCONFIGURATION_COMPONENT_DATA CpuConfigComponent; + PHALP_PROCESSOR_ID HalpProcessorId; + + // + // If the processor is not ready then we assume that it is not + // present. We must increment the physical processor number but + // the logical processor number does not changed. + // + + // + // Get a pointer to the configuration entry for this processor. + // The configuration data will contain the processors MC device ID. + // + + CpuConfigComponent = KeFindConfigurationEntry( + LoaderBlock->ConfigurationRoot, + ProcessorClass, + CentralProcessor, + &PhysicalProcessor + ); + + // + // Check for errors. + // + + if ( (CpuConfigComponent == NULL) || + (CpuConfigComponent->ConfigurationData == NULL) ) { + +#if 0 //HALDBG + DbgPrint ("HalStartNextProcessor: Configuration Data Missing\n"); +#endif //HALDBG + // What to do now? + DbgBreakPoint (); + } + + // + // Obtain a pointer to the processor Id from the configuration data. + // + + HalpProcessorId = + ((PHALP_PROCESSOR_ID)CpuConfigComponent->ConfigurationData); + + // + // Initialize the table entry for this processor. + // + + HalpLogicalToPhysicalProcessor[LogicalProcessor].all = HalpProcessorId->all; + +} + +VOID +HalpRegisterPlatformResources( + PUCHAR HalName + ) +/*++ + +Routine Description: + + Register I/O resources used by the HAL. + +Arguments: + + HalName - Supplies a pointer to the name for the HAL. + +Return Value: + + None. + +--*/ +{ + RESOURCE_USAGE Resource; + + // + // Register the buses. + // + + HalpRegisterBusUsage(Internal); + HalpRegisterBusUsage(Eisa); + HalpRegisterBusUsage(Isa); + HalpRegisterBusUsage(PCIBus); + + // + // Register the name of the HAL. + // + + HalpRegisterHalName( HalName ); + + // + // Register the interrupt vector used for the cascaded interrupt + // on the 8254s. + // + + Resource.BusType = Isa; + Resource.BusNumber = 0; + Resource.ResourceType = CmResourceTypeInterrupt; + Resource.u.InterruptMode = Latched; + Resource.u.BusInterruptVector = 2; + Resource.u.SystemInterruptVector = 2; + Resource.u.SystemIrql = 2; + HalpRegisterResourceUsage(&Resource); + + // + // Register machine specific io/memory addresses. + // + + Resource.BusType = Isa; + Resource.BusNumber = 0; + Resource.ResourceType = CmResourceTypePort; + +#if 0 + Resource.u.Start = I2C_INTERFACE_DATA_PORT; + Resource.u.Length = I2C_INTERFACE_LENGTH; + HalpRegisterResourceUsage(&Resource); +#endif + + Resource.u.Start = SUPERIO_INDEX_PORT; + Resource.u.Length = SUPERIO_PORT_LENGTH; + HalpRegisterResourceUsage(&Resource); + + // + // Register the DMA channel used for the cascade. + // + + Resource.BusType = Isa; + Resource.BusNumber = 0; + Resource.ResourceType = CmResourceTypeDma; + Resource.u.DmaChannel = 0x4; + Resource.u.DmaPort = 0x0; + HalpRegisterResourceUsage(&Resource); +} + + +// +//jnfix +// +// This routine is bogus and does not apply to Alcor and the call should be +// ripped out of fwreturn (or at least changed to something that is more +// abstract). +// + +VOID +HalpResetHAERegisters( + VOID + ) +{ + return; +} + +VOID +HalpGetMachineDependentErrorFrameSizes( + PULONG RawProcessorSize, + PULONG RawSystemInfoSize + ) +/*++ + +Routine Description: + + This function returns the size of the system specific structures. + + +Arguments: + + RawProcessorSize - Pointer to a buffer that will receive the + size of the processor specific error information buffer. + + RawSystemInfoSize - Pointer to a buffer that will receive the + size of the system specific error information buffer. + +Return Value: + + none + +--*/ +{ + *RawProcessorSize = sizeof(PROCESSOR_EV5_UNCORRECTABLE); + *RawSystemInfoSize = sizeof(RAWHIDE_UNCORRECTABLE_FRAME) + + HalpNumberOfIods * sizeof(IOD_ERROR_FRAME); + + // + // ecrfix - will have to figure out something else for + // PCI, ESC snapshots and System Mgmt Frame. + // + + return; +} + +VOID +HalpGetSystemInfo(SYSTEM_INFORMATION *SystemInfo) +/*++ + +Routine Description: + + This function fills in the System information. + + +Arguments: + + SystemInfo - Pointer to the SYSTEM_INFORMATION buffer that needs + to be filled in. + +Return Value: + + none + +--*/ +{ + char systemtype[] = "Rawhide"; + EXTENDED_SYSTEM_INFORMATION FwExtSysInfo; + + + VenReturnExtendedSystemInformation(&FwExtSysInfo); + + RtlCopyMemory(SystemInfo->FirmwareRevisionId, + FwExtSysInfo.FirmwareVersion, + 16); + + + RtlCopyMemory(SystemInfo->SystemType, systemtype, 8); + + SystemInfo->ClockSpeed = + ((1000 * 1000) + (PCR->CycleClockPeriod >> 1)) / PCR->CycleClockPeriod; + + SystemInfo->SystemRevision = PCR->SystemRevision; + +// RtlCopyMemory(SystemInfo->SystemSerialNumber, +// PCR->SystemSerialNumber, +// 16); + + SystemInfo->SystemVariant = PCR->SystemVariant; + + + SystemInfo->PalMajorVersion = PCR->PalMajorVersion; + SystemInfo->PalMinorVersion = PCR->PalMinorVersion; + + SystemInfo->OsRevisionId = VER_PRODUCTBUILD; + + // + // For now fill in dummy values. + // + SystemInfo->ModuleVariant = 1UL; + SystemInfo->ModuleRevision = 1UL; + SystemInfo->ModuleSerialNumber = 0; + + return; +} + + +VOID +HalpInitializeUncorrectableErrorFrame ( + VOID + ) +/*++ + +Routine Description: + + This function Allocates an Uncorrectable Error frame for this + system and initializes the frame with certain constant/global + values. + + This is routine called during machine dependent system + Initialization. + +Arguments: + + none + +Return Value: + + none + +--*/ +{ + PRAWHIDE_UNCORRECTABLE_FRAME rawerr; + + // + // If the Uncorrectable error buffer is not set then simply return + // + + if(PUncorrectableError == NULL) + return; + + PUncorrectableError->Signature = ERROR_FRAME_SIGNATURE; + + PUncorrectableError->FrameType = UncorrectableFrame; + + // + // ERROR_FRAME_VERSION is define in errframe.h and will + // change as and when there is a change in the errframe.h. + // This Version number helps the service, that reads this + // information from the dumpfile, to check if it knows about + // this frmae version type to decode. If it doesn't know, it + // will dump the entire frame to the EventLog with a message + // "Error Frame Version Mismatch". + // + + PUncorrectableError->VersionNumber = ERROR_FRAME_VERSION; + + // + // The sequence number will always be 1 for Uncorrectable errors. + // + + PUncorrectableError->SequenceNumber = 1; + + // + // The PerformanceCounterValue field is not used for Uncorrectable + // errors. + // + + PUncorrectableError->PerformanceCounterValue = 0; + + // + // We will fill in the UncorrectableFrame.SystemInfo here. + // + HalpGetSystemInfo(&PUncorrectableError->UncorrectableFrame.System); + + PUncorrectableError->UncorrectableFrame.Flags.SystemInformationValid = 1; + + // + // Fill in Common RCUD Header + // + + rawerr = (PRAWHIDE_UNCORRECTABLE_FRAME) + PUncorrectableError->UncorrectableFrame.RawSystemInformation; + + strncpy( PUncorrectableError->UncorrectableFrame.System.SystemSerialNumber, + HalpSystemClassData->SystemConfig.SystemSerialNumber, 10); + + strncpy( rawerr->CudHeader.SystemSN, + HalpSystemClassData->SystemConfig.SystemSerialNumber, 10); + + strncpy( rawerr->CudHeader.SystemRev, + HalpSystemClassData->SystemConfig.SystemRevisionLevel, 4); + + // Jam the SRM console revision in the Module SN + + strncpy( rawerr->CudHeader.ModuleSN, + HalpSystemClassData->SystemConfig.ConsoleTypeRev, 9); + rawerr->CudHeader.ModuleSN[9] = '\0'; + + // Jam the first 5 chars of System Model (4x00, etc.) in a reserved field + + strncpy( rawerr->CudHeader.Reserved2, + HalpSystemClassData->SystemConfig.SystemModel, 5); + rawerr->CudHeader.Reserved2[5] = '\0'; + + // + // The following RCUD header data is not valid for Windows NT. + // + + rawerr->CudHeader.HwRevision = 0; + rawerr->CudHeader.ModType = 0; + rawerr->CudHeader.DisabledResources = 0; + + // + // Fill in MC Bus Snapshot header + // + + rawerr->McBusSnapshot.Length = sizeof(MC_BUS_SNAPSHOT) + + HalpNumberOfIods * sizeof(IOD_ERROR_FRAME); + + rawerr->McBusSnapshot.NumberOfIods = HalpNumberOfIods; + + return; +} diff --git a/private/ntos/nthals/halraw/alpha/rwintbal.c b/private/ntos/nthals/halraw/alpha/rwintbal.c new file mode 100644 index 000000000..f32f533b1 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/rwintbal.c @@ -0,0 +1,1762 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + rwintbal.c + +Abstract: + + The module provides support for distributing interrupt load among + processors for Rawhide systems. + +Author: + + Matthew Buchman (DEC) 29-November-1995 + +Revision History: + +--*/ + + +#include "halp.h" +#include "pci.h" +#include "pcip.h" +#include "rawhide.h" +#include "pcrtc.h" + +// +// The enable mask for all interrupts sourced from the IOD (all device +// interrupts, and all from PCI). A "1" indicates the interrupt is enabled. +// + +extern PULONG *HalpIodInterruptMask; + +// +// Declare IOD and CPU affinity tables +// + +LIST_ENTRY HalpIodVectorDataHead; +LIST_ENTRY HalpCpuVectorDataHead; + +PIOD_VECTOR_DATA HalpIodVectorData; +PCPU_VECTOR_DATA HalpCpuVectorData; + + +// +// The number of target CPUS, mainly for performance comparison of +// one processor vs. distributed interrupt load +// + +#if 1 +ULONG HalpNumberOfTargetCpus = IOD_MAX_INT_TARG; +#else +ULONG HalpNumberOfTargetCpus = 1; +#endif + + + +PVOID +HalpFindWeightedEntry( + PLIST_ENTRY ListHead, + WEIGHTED_SEARCH_CRITERIA SearchCriteria + ) +/*++ + +Routine Description: + + This routine searches a WEIGHTED list searching for the maximum + or minimum weight, depending on the SearchCriteria. A WEIGHTED + list entry overlays the generic LIST_ENTRY provided by NT. This + allows us to use the generic LIST_ENTRY routines for list + manipulation. To treat this as an ordered list, we must traverse + this list by hand to find the maximum element. + + The entry matching the search criteria is removed from the list + as a side effect. + +Arguments: + + ListHead - a pointer the list head. + + SearchCriteria - either FindMaxEntry or FindMinEntry + +Return Value: + + Return a pointer to the maximum element or NULL for + an empty list. + +--*/ +{ + PLIST_ENTRY NextEntry; + PLIST_ENTRY CurrentMaxMinEntry; + PWEIGHTED_LIST_ENTRY WeightedEntry; + LONG CurrentMaxMinWeight; + + + // + // Handle the empty list case + // + + if (IsListEmpty(ListHead)) { + return (NULL); + } + + // + // Traverse this list looking for the maximum weight + // + + for ( + NextEntry = ListHead->Flink, + CurrentMaxMinEntry = NULL; + + NextEntry != ListHead; + + NextEntry = NextEntry->Flink + + ) { + + // + // The WEIGHTED_LIST_ENTRY overlays the LIST_ENTRY + // + + WeightedEntry = (PWEIGHTED_LIST_ENTRY)NextEntry; + + if (CurrentMaxMinEntry == NULL) { + + CurrentMaxMinEntry = NextEntry; + CurrentMaxMinWeight = WeightedEntry->Weight; + + } else { + + if (SearchCriteria == FindMaxWeight) { + + if (WeightedEntry->Weight > CurrentMaxMinWeight) { + CurrentMaxMinEntry = NextEntry; + CurrentMaxMinWeight = WeightedEntry->Weight; + } + + } else { + + if (WeightedEntry->Weight < CurrentMaxMinWeight) { + CurrentMaxMinEntry = NextEntry; + CurrentMaxMinWeight = WeightedEntry->Weight; + } + + } + } + } + + // + // Remove the maximum from the list + // + + RemoveEntryList(CurrentMaxMinEntry); + + return ((PVOID)CurrentMaxMinEntry); +} + +// mdbfix - delete these routines later! +#if 0 + +// +// Declare the lower-level routine used to read PCI config space +// + +VOID +HalpReadPCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + + +VOID +HalpFindPciBusVectors( + IN PCONFIGURATION_COMPONENT Component, + IN PVOID ConfigurationData + ) + +/*++ + +Routine Description: + + This routine finds all device interrupt vectors for the PCI bus + handler obtained from the configuration tree and sets the + corresponding bits in the VectorPresent bitmap for the IOD. + +Arguments: + + Component - The ARC configuration component for this bus. + + ConfigurationData - The configuration data payload (or NULL). + +Return Value: + + None. + +--*/ +{ + ARC_PCI_CONFIGURATION ArcPciConfiguration; + ULONG BusNumber; + ULONG HwBusNumber; + BOOLEAN BusIsAcrossPPB; + PBUS_HANDLER BusHandler; + PPCIPBUSDATA BusData; + PCIPBUSDATA BusContext; + RTL_BITMAP DevicePresent; + PCI_SLOT_NUMBER SlotNumber; + PIOD_VECTOR_DATA IodIoVectors; + ULONG DeviceNumber; + ULONG NextDevice; + ULONG FunctionNumber; + ULONG InterruptLine; + PCI_COMMON_CONFIG CommonConfig; + + // + // Copy the configuration data from the component. + // + + RtlCopyMemory( + &ArcPciConfiguration, + ConfigurationData, + sizeof (ARC_PCI_CONFIGURATION) + ); + + // + // Use the values provided. + // + + BusNumber = ArcPciConfiguration.BusNumber; + HwBusNumber = ArcPciConfiguration.HwBusNumber; + BusIsAcrossPPB = ArcPciConfiguration.BusIsAcrossPPB; + IodIoVectors = HalpIodVectorData + HwBusNumber; + + // + // Initialize the BusNumber for this IOD now. + // We might want to use it later to obtain the bus handler + // + + IodIoVectors->BusNumber = BusNumber; + + // + // Allocate and initialize the handler for this bus. N.B. device-present + // checking is disabled at this point. We will enable it below. + // + + BusHandler = HaliHandlerForBus( + PCIBus, + BusNumber + ); + + // + // Get a pointer to the bus-specific data. + // + + BusData = (PPCIPBUSDATA)BusHandler->BusData; + + // + // Use the device-present bitmap for this bus to query configuration + // Space for InterruptLine values. + // + + // + // Initialize the device-present bitmap for this bus. + // + + HalpInitializeBitMap( + &BusContext.DevicePresent, + BusContext.DevicePresentBits, + PCI_MAX_DEVICES * PCI_MAX_FUNCTION + ); + + // + // Copy the bitmap from the bus handler. + // + + RtlCopyMemory( + &BusContext.DevicePresentBits, + &BusData->DevicePresentBits, + sizeof (BusData->DevicePresentBits) + ); + + + // + // Starting with device 0, scan the device present + // bitmap. + // + + DeviceNumber = 0; + + while ( (DeviceNumber = + HalpFindSetBitsAndClear( + &BusContext.DevicePresent, + 1, + DeviceNumber + ) ) != -1 ) { + + // + // Initialize the slot number. + // + + SlotNumber.u.AsULONG = 0; + SlotNumber.u.bits.DeviceNumber = DeviceNumber; + + // + // Loop through each function number. + // + + for (FunctionNumber = 0; + FunctionNumber < PCI_MAX_FUNCTION; + FunctionNumber++) { + + SlotNumber.u.bits.FunctionNumber = FunctionNumber; + + // + // Read the common configuration header. + // + + HalpReadPCIConfig( + BusHandler, + SlotNumber, + &CommonConfig, + 0, + PCI_COMMON_HDR_LENGTH + ); + + // + // If the Vendor ID is invalid, then no device is present + // at this device/function number. + // + + if (CommonConfig.VendorID == PCI_INVALID_VENDORID) { + if (FunctionNumber == 0) { + break; + } + continue; + } + + // + // Obtain the vector assigned to this Device:Function + // during PCI configuration. + // + + if (CommonConfig.u.type0.InterruptLine) { + + // + // Obtain vector and normalize + // + + InterruptLine =CommonConfig.u.type0.InterruptLine; + InterruptLine -= (RawhidePinToLineOffset + 1); + + // + // Determine if this is a shared vector + // + + if ( HalpAreBitsSet( + &IodIoVectors->VectorPresent[0], + InterruptLine, + 1 + ) == TRUE ) { + + // + // Indicate vector is shared in bitmap + // + + HalpSetBits( + &IodIoVectors->SharedVector[0], + InterruptLine, + 1 + ); + + HalpDumpBitMap(&IodIoVectors->SharedVector[0]); + + } else { + + // + // Indicate device is present in bitmap + // + + HalpSetBits( + &IodIoVectors->VectorPresent[0], + InterruptLine, + 1 + ); + + HalpDumpBitMap(&IodIoVectors->VectorPresent[0]); + + } + + // + // Increment the weight + // + + IodIoVectors->ListEntry.Weight++; + + } // if (CommonConfig.InterruptLine) + + // + // If this is not a multi-function device, then terminate + // the function number loop. + // + + if ((CommonConfig.HeaderType & PCI_MULTIFUNCTION) == 0) { + break; + } + + } // for (FunctionNumber...) + + } // while (DeviceNumber != -1) +} + + +VOID +HalpFindAllPciVectors( + IN PCONFIGURATION_COMPONENT_DATA Root + ) +/*++ + +Routine Description: + + This function loops through each multi-function adapter component + in the ARC configuration tree and calls HalpFindPciBusVectors() + searching for device vectors. + +Arguments: + + Root - The root of the ARC configuration tree. + +Return Value: + + None. + +--*/ +{ + ULONG Key; + PCONFIGURATION_COMPONENT_DATA Adapter; + + // + // Loop through each multi-function adapter component in the ARC + // configuration tree. + // + + for (Key = 0; TRUE; Key++) { + + // + // Get a pointer to the component data. + // + + Adapter = KeFindConfigurationEntry( + Root, + AdapterClass, + MultiFunctionAdapter, + &Key + ); + + // + // If there are no more multi-function adapters in the ARC + // configuration tree, then we're done. + // + + if (Adapter == NULL) { + break; + } + + // + // Ascertain whether this is a PCI multi-function adapter component. + // If so, find the device vectors. + // + + if (stricmp(Adapter->ComponentEntry.Identifier, "PCI") == 0) { + HalpFindPciBusVectors( + &Adapter->ComponentEntry, + Adapter->ConfigurationData + ); + } + } +} + + +VOID +HalpBalanceVectorLoadForIod( + PIOD_VECTOR_DATA IodVectorData + ) +/*++ + +Routine Description: + + Balance the vector load for the given IOD among the + CPU pair. The basic algorithm is: + + 1. Find a device present from the bitmap. + 2. Choose the CPUwith the minimum vector load. + 3. Assign the device vector from (1) to this CPU + and update the CPU's vector load (weight) by 1. + 4. If the vector is shared (multiple devices + connect), update the CPU's vector load by 1. + While this does not accurately reflect the + actual vector's sharing the device, it will + due for algorithmic simplicity. + 5. Update the CPU's IOD service mask. + 6. repeat for all vectors. + + +Arguments: + + IodListHead - head of temporary IOD vector info list. + +Return Value: + + None. + +--*/ +{ + RTL_BITMAP VectorPresent; + ULONG VectorPresentBits; + ULONG IRRBitNumber; + ULONG InterruptBit; + + HalpInitializeBitMap( + &VectorPresent, + (PULONG)&VectorPresentBits, + 32 + ); + + // + // Copy the device present bitmap from the IOD information. + // + + RtlCopyMemory( + &VectorPresentBits, + &IodVectorData->VectorPresentBits[0], + sizeof (IodVectorData->VectorPresentBits[0]) + ); + + // + // Now that we have a copy of all device vectors for this + // IOD, clear the device present bitmap for target 0. + // This was only being used as temporary storage. + // + + HalpClearAllBits(&IodVectorData->VectorPresent[0]); + + // + // Start with the first IRR bit. + // + + IRRBitNumber = 0; + + // + // Find the next Device present. + // Remember that this bitmap actually represents + // the interrupt vector assigned to devices. + // + + while (( IRRBitNumber = + HalpFindSetBitsAndClear( + &VectorPresent, + 1, + IRRBitNumber) ) != -1 ) { + + InterruptBit = (1 << IRRBitNumber); + + // + // Assign the vector for this IOD + // + + HalpAssignInterruptForIod(IodVectorData, InterruptBit); + + } + +} + + +VOID +HalpBalanceIoVectorLoad( + PLIST_ENTRY IodListHead + ) +/*++ + +Routine Description: + + Balance the vector load among the set of processors. + The basic algorithm is: + + 1. Find an IOD to process: + + From the IOD set, find the IOD with the maximum + number of vectors, and permanantly remove this + IOD from the set. + + 2. Find a CPU pair that will act as targets for + the selected IOD interrupts: + + a. From the CPU set, find the first CPU with the + minimum number of vectors assigned and temporarily + remove this CPU from the CPU set. + + b. From the CPU set, find the second CPU with the + minimum number of vectors assigned and temporarily + remove this CPU from the CPU set. + + 3. Call HalpBalanceIodVectorLoad to divide the IOD + vectors among the two CPU's. + + 5. Add the CPU's back the the CPU set. This makes them + available for selection during the next iteration. + + 6. Repeat until the IOD set is empty. + +Arguments: + + IodListHead - head of temporary IOD vector info list. + +Return Value: + + None. + +--*/ +{ + PIOD_VECTOR_DATA IodVectorData; + + // + // Balance the vector load for each IOD, + // assigning vector affinity in the process + // + + while (!IsListEmpty(IodListHead)) { + + // + // Find the IOD with the maximum number of + // vectors. It is removed from the list as + // a side effect. + // + + IodVectorData = (PIOD_VECTOR_DATA) + HalpFindWeightedEntry(IodListHead, FindMaxWeight); + + // + // Assign the interrupt vector affinity for this IOD + // + + HalpBalanceVectorLoadForIod( + IodVectorData + ); + + // + // Add this to the global list of IOD's. + // Use shortcut to obtain LIST_ENTRY. + // + + InsertHeadList( + &HalpIodVectorDataHead, + &IodVectorData->ListEntry.ListEntry + ); + + } + +} + + +VOID +HalpInitializeIoVectorAffinity( + PLOADER_PARAMETER_BLOCK LoaderBlock + ) +/*++ + +Routine Description: + + The IOD and CPU vector information tables are used balance the + interrupt load from all IOD's among the set of available CPU's. + + Allocate and initialize the IOD and CPU vector information tables, + pre-assign vectors for EISA, I2c, SoftErr, and HardErr, and + call HalpIoVectorLoad() to assign IOD vectors to CPU's. + +Arguments: + + LoaderParameterBlock - supplies a pointer to the loader block. + +Return Value: + + None. + +--*/ +{ + MC_DEVICE_MASK IodMask = HalpIodMask; + MC_DEVICE_MASK CpuMask = HalpCpuMask; + PIOD_VECTOR_DATA IodVectorData; + PCPU_VECTOR_DATA CpuVectorData; + LIST_ENTRY IodListHead; + ULONG LogicalNumber; + ULONG Target; + + // + // Allocate the IOD device affinity table. + // + + HalpIodVectorData = (PIOD_VECTOR_DATA) + ExAllocatePool( + NonPagedPool, + sizeof(IOD_VECTOR_DATA)* HalpNumberOfIods + ); + + RtlZeroMemory( + HalpIodVectorData, + sizeof(IOD_VECTOR_DATA)*HalpNumberOfIods + ); + + // + // Initialize the IOD vector affinity list. + // + + InitializeListHead(&HalpIodVectorDataHead); + InitializeListHead(&IodListHead); + + for ( LogicalNumber = 0, IodVectorData = HalpIodVectorData; + LogicalNumber < HalpNumberOfIods; + LogicalNumber++, IodVectorData++ ) { + + + // + // Initialize bitmaps for each target. + + for (Target = 0; Target < IOD_MAX_INT_TARG; Target++) { + + // + // The VectorBitmap represents the devices on this IOD + // that been assigned vectors and to which target the + // vectors have been assigned. + // + + + HalpInitializeBitMap( + &IodVectorData->VectorPresent[Target] , + (PULONG)&IodVectorData->VectorPresentBits[Target], + 32 + ); + + // + // The SharedBitmap represents vectors that are shared + // by devices on this IOD. It is used to make decisions + // on which target to assign vectors. + // + + HalpInitializeBitMap( + &IodVectorData->SharedVector[Target], + (PULONG)&IodVectorData->SharedVectorBits[Target], + 32 + ); + + } + + // + // Assign the device number. This cooresponds to the logical + // IOD number. + // + + IodVectorData->HwBusNumber = LogicalNumber; + + // + // Add this IOD to temporary list. The IOD will be added + // to permanent list after it is processed. + // + + InsertTailList( + &IodListHead, + &IodVectorData->ListEntry.ListEntry + ); + + } + + // + // Allocate the CPU IO device affinity table. + // + + HalpCpuVectorData = (PCPU_VECTOR_DATA) + ExAllocatePool( + NonPagedPool, + sizeof(CPU_VECTOR_DATA) * HalpNumberOfCpus + ); + + RtlZeroMemory( + HalpCpuVectorData, + sizeof(CPU_VECTOR_DATA)*HalpNumberOfCpus + ); + + // + // Initialize the CPU vector affinity list. + // + + InitializeListHead(&HalpCpuVectorDataHead); + + for ( LogicalNumber = 0, CpuVectorData = HalpCpuVectorData; + LogicalNumber < HalpNumberOfCpus; + LogicalNumber++, CpuVectorData++ ) { + + // + // Assign the device number. This cooresponds to the logical + // CPU number. + // + + CpuVectorData->LogicalNumber = LogicalNumber; + CpuVectorData->McDeviceId.Gid = GidPrimary; + + switch (LogicalNumber) { + + case 0: + + CpuVectorData->McDeviceId.Mid = MidCpu1; + break; + + case 1: + + CpuVectorData->McDeviceId.Mid = MidCpu1; + break; + + case 2: + + CpuVectorData->McDeviceId.Mid = MidCpu2; + break; + + case 3: + + CpuVectorData->McDeviceId.Mid = MidCpu3; + break; + + } + // + // Insert this CPU into the list + // + + InsertTailList( + &HalpCpuVectorDataHead, + &CpuVectorData->ListEntry.ListEntry + ); + + } + + // + // Find all PCI Iod Vectors. + // + + HalpFindAllPciVectors(LoaderBlock->ConfigurationRoot); + + // + // Preassign error vectors for all IOD's as well as EISA, EISANMI + // and I2c vectors to the primary processor. + // + + HalpAssignPrimaryProcessorVectors(&IodListHead); + + // + // Balance the IO vector load among the CPU's + // + + HalpBalanceIoVectorLoad(&IodListHead); + +#if HALDBG + + HalpDumpIoVectorAffinity(); + +#endif + +} + + +VOID +HalpAssignIodInterrupts( + MC_DEVICE_ID McDeviceId, + ULONG PciBusNumber, + va_list Arguments + ) + +/*++ + +Routine Description: + + This enumeration routine assigns the Rawhide interrupts for the + corresponding IOD and sets up the target CPU's. The interrupts + are initialized with the values determined by + HalpInitializeIoVectorAffinity() + + Interrupts were previously routed to the primary processor + by HalpInitializeIodInterrupts. Now that All processors are + started, we must reassign HardErr, Eisa, and EisaNMI interrupts. + + The logical bus is assigned from the static variable PciBusNumber, which is + incremented with each invokation. + +Arguments: + + McDeviceId - Supplies the MC Bus Device ID of the IOD to be intialized + + PciBusNumber - Logical (Hardware) bus number. + + Arguments - Variable Arguments. None for this routine. + +Return Value: + + None. + +--*/ + +{ + PIOD_VECTOR_DATA IodVectorData; + IOD_INT_MASK IntMask; + IOD_INT_TARGET_DEVICE IntTarg; + PVOID IntMaskQva; + ULONG Target; + + IodVectorData = HalpIodVectorData + PciBusNumber; + + // + // 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) + ); + + // + // Initialize the target register base on assigned values + // + + IntTarg.Int0TargDevId = (ULONG)IodVectorData->IntTarg[0].all; + IntTarg.Int1TargDevId = (ULONG)IodVectorData->IntTarg[1].all; + + // + // Write the target register. + // + + WRITE_IOD_REGISTER_NEW( + McDeviceId, + &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntTarg, + IntTarg.all + ); + + // + // Write the mask bits for target 0 and 1 + // + + for (Target = 0; Target < IOD_MAX_INT_TARG; Target++) { + + // + // Obtain the target IRR QVA + // + + if (Target) { + + IntMaskQva = (PVOID)&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntMask1; + + } else { + + IntMaskQva = (PVOID)&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntMask0; + + } + IntMask.all = IodVectorData->IntMask[Target].all; + + WRITE_IOD_REGISTER_NEW( + McDeviceId, + IntMaskQva, + IntMask.all + ); + + } + + // + // Enable Interrupts. + // + + WRITE_IOD_REGISTER_NEW( + McDeviceId, + &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntCtrl, + IOD_INT_CTL_ENABLE_IO_INT + ); + +} + +#endif // STATIC BALANCE + + +VOID +HalpInitializeVectorBalanceData( + VOID + ) +/*++ + +Routine Description: + + The IOD and CPU vector information tables are used balance the + interrupt load from all IOD's among the set of available CPU's. + + Allocate and initialize the IOD and CPU vector information tables, + pre-assign vectors for EISA, I2c, SoftErr, and HardErr, and + call HalpIoVectorLoad() to assign IOD vectors to CPU's. + +Arguments: + + LoaderParameterBlock - supplies a pointer to the loader block. + +Return Value: + + None. + +--*/ +{ + MC_DEVICE_MASK IodMask = HalpIodMask; + MC_DEVICE_MASK CpuMask = HalpCpuMask; + PIOD_VECTOR_DATA IodVectorData; + ULONG LogicalNumber; + ULONG Target; + + // + // Allocate the IOD device affinity table. + // + + HalpIodVectorData = (PIOD_VECTOR_DATA) + ExAllocatePool( + NonPagedPool, + sizeof(IOD_VECTOR_DATA)* HalpNumberOfIods + ); + + RtlZeroMemory( + HalpIodVectorData, + sizeof(IOD_VECTOR_DATA)*HalpNumberOfIods + ); + + // + // Initialize the IOD vector affinity list. + // + + InitializeListHead(&HalpIodVectorDataHead); + + for ( LogicalNumber = 0, IodVectorData = HalpIodVectorData; + LogicalNumber < HalpNumberOfIods; + LogicalNumber++, IodVectorData++ ) { + + // + // Assign the device number. This cooresponds to the logical + // IOD number. + // + + IodVectorData->HwBusNumber = LogicalNumber; + + // + // Add this IOD to temporary list. The IOD will be added + // to permanent list after it is processed. + // + + InsertTailList( + &HalpIodVectorDataHead, + &IodVectorData->ListEntry.ListEntry + ); + + } + + // + // Allocate the CPU vector data table for the maximum + // processor configuration. + // + + HalpCpuVectorData = (PCPU_VECTOR_DATA) + ExAllocatePool( + NonPagedPool, + sizeof(CPU_VECTOR_DATA)*HalpNumberOfCpus + ); + + RtlZeroMemory( + HalpCpuVectorData, + sizeof(CPU_VECTOR_DATA)*HalpNumberOfCpus + ); + + // + // Initialize the CPU vector affinity list. + // CPU's will add their entry later. + // + + InitializeListHead(&HalpCpuVectorDataHead); + +} + + +VOID +HalpInitializeCpuVectorData( + ULONG LogicalCpu + ) +/*++ + +Routine Description: + + Allocate and initialize the CPU vector entry for this logical + CPU and add it to the global list, + +Arguments: + + LogicalCpu - Logical CPU number assigned by HalStartNextProcessor(). + +Return Value: + + None. + +--*/ +{ + MC_DEVICE_MASK CpuMask = HalpCpuMask; + PCPU_VECTOR_DATA CpuVectorData; + ULONG Target; + + // + // Use the logical processor number to offset into in the + // global CPU table. + // + + CpuVectorData = HalpCpuVectorData + LogicalCpu; + + // + // Initalize CPU vector data fields + // + + CpuVectorData->LogicalNumber = LogicalCpu; + + // + // Insert into global list + // + + InsertTailList( + &HalpCpuVectorDataHead, + &CpuVectorData->ListEntry.ListEntry + ); + +#if HALDBG + DbgPrint( + "Initialized vector data for CPU %d (%d, %d)\n", + CpuVectorData->LogicalNumber, + HalpLogicalToPhysicalProcessor[LogicalCpu].Gid, + HalpLogicalToPhysicalProcessor[LogicalCpu].Mid + ); +#endif + +} + + +VOID +HalpAssignPrimaryProcessorVectors( + PLIST_ENTRY IodListHead + ) +/*++ + +Routine Description: + + Assign primary processor vectors. This includes the following: + + HardErr + SoftErr + Eisa + EisaNMI + I2cBus + I2cCtrl + + By having the primary processor handle the error vectors, we + prevent hard errors from being serviced by multiple + processors. + +Arguments: + + IodListHead - head of temporary IOD vector info list. + +Return Value: + + None. + +--*/ +{ + PLIST_ENTRY ListEntry; + PIOD_VECTOR_DATA IodVectorData; + PCPU_VECTOR_DATA PrimaryCpuVectorData; + MC_DEVICE_ID McDeviceId; + ULONG Target; + + // + // Obtain the vector data structure for the primary processor + // + + PrimaryCpuVectorData = HalpCpuVectorData; + + // + // Assign the hard and soft error interrupt for each IOD + // to the primary processor + // + + for ( ListEntry = IodListHead->Flink; + ListEntry != IodListHead; + ListEntry = ListEntry->Flink ) { + + // + // Obtain the IOD vector data. + // + + IodVectorData = (PIOD_VECTOR_DATA)ListEntry; + + McDeviceId = HalpIodLogicalToPhysical[IodVectorData->HwBusNumber]; + +#if HALDBG + DbgPrint( + "Assign IOD (%d, %d) Target 0 to Primary Processor\n", + McDeviceId.Gid, + McDeviceId.Mid + ); +#endif + + // + // Assign the Target 0 CPU for this IOD + // + + IodVectorData->TargetCpu[0] = PrimaryCpuVectorData; + + // + // Assign the SoftErr and HardErr interrupts to each IOD + // + + IodVectorData->IntMask[0].all |= (1 << IodHardErrIrrBit); + IodVectorData->IntMask[0].all |= (1 << IodSoftErrIrrBit); + + +#if HALDBG + DbgPrint( + "Assign IOD (%d, %d) HardError to Target 0, CPU 0\n", + McDeviceId.Gid, + McDeviceId.Mid + ); +#endif + + // + // Assign the Eisa, EisaNMI, and I2C interrupts for PCI bus 0 + // to the primary processor. + // + + if (IodVectorData->HwBusNumber == 0) { + + IodVectorData->IntMask[0].all |= (1 << IodEisaIrrBit); +// mdbfix - I2c not enabled +// IodVectorData->IntMask[0].all |= (1 << IodI2cBusIrrBit); +// IodVectorData->IntMask[0].all |= (1 << IodI2cCtrlIrrBit); + IodVectorData->IntMask[0].all |= (1 << IodEisaNmiIrrBit); + +#if HALDBG + DbgPrint( + "Assign IOD (%d, %d) EISA & EISANMI to Target 0, CPU 0\n", + McDeviceId.Gid, + McDeviceId.Mid + ); +#endif + +// mdbfix - +#if 0 + // + // Weight this Processor for EISA vectors KBD, MOUSE, etc. + // + + PrimaryCpuVectorData->ListEntry.Weight++; +#endif + } + + // + // Initialize the affinity mask, target, and CPU vector link + // + + IodVectorData->Affinity[0] |= 1; + + IodVectorData->IntTarg[0] = + HalpLogicalToPhysicalProcessor[HAL_PRIMARY_PROCESSOR]; + + IodVectorData->TargetCpu[0] = PrimaryCpuVectorData; + + } + +} + + +ULONG +HalpAssignInterruptForIod( + PIOD_VECTOR_DATA IodVectorData, + ULONG InterruptBit + ) +/*++ + +Routine Description: + +Arguments: + + IodVectorData - IOD to assign interrupt + + InterruptBit - Interrupt bit in the IRR to set + +Return Value: + + Return the logical CPU number assigned the interrupt + +--*/ + +{ + PCPU_VECTOR_DATA TargetCpu; + MC_DEVICE_ID McDeviceId; + IOD_INT_TARGET_DEVICE IntTarg; + ULONG Target; + ULONG LogicalCpu; + + McDeviceId = HalpIodLogicalToPhysical[IodVectorData->HwBusNumber]; + +#if HALDBG + + DbgPrint( + "Assigning IOD (%d, %d) Interrupt 0x%x\n", + McDeviceId.Gid, + McDeviceId.Mid, + InterruptBit + ); +#endif + + // + // If both of the target CPU's have not been assigned, + // assign them now. + // + + if ( !IodVectorData->TargetCpu[0] || !IodVectorData->TargetCpu[1] ) { + + + for (Target = 0; Target < HalpNumberOfTargetCpus; Target++) { + + if ((TargetCpu = IodVectorData->TargetCpu[Target]) == NULL) { + + TargetCpu = (PCPU_VECTOR_DATA) + HalpFindWeightedEntry( + &HalpCpuVectorDataHead, + FindMinWeight + ); + + // + // Handle for UP and second target not assigned + // + + if (TargetCpu == NULL) { + + break; + + } + +#if HALDBG + DbgPrint( + "IOD (%d, %d) Target %d assigned to CPU %d\n", + McDeviceId.Gid, + McDeviceId.Mid, + Target, + TargetCpu->LogicalNumber + ); +#endif + + LogicalCpu = TargetCpu->LogicalNumber; + + // + // Initialize the affinity mask, target, and CPU vector link + // + + IodVectorData->Affinity[Target] |= (1 << LogicalCpu); + IodVectorData->IntTarg[Target] = + HalpLogicalToPhysicalProcessor[LogicalCpu]; + IodVectorData->TargetCpu[Target] = TargetCpu; + + // + // Initialize the MC_DEVICE_ID for this target. + // + + + // + // Read the target register. + // + + IntTarg.all = READ_IOD_REGISTER_NEW( + McDeviceId, + &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntTarg + ); + + + // + // Obtain the Target assigned by Vector Balancing + // + + if (Target) { + + IntTarg.Int1TargDevId = (ULONG) + IodVectorData->IntTarg[Target].all; + + } else { + + IntTarg.Int1TargDevId = (ULONG) + IodVectorData->IntTarg[Target].all; + + } + + // + // Write the target register. + // + + WRITE_IOD_REGISTER_NEW( + McDeviceId, + &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntTarg, + IntTarg.all + ); + + } else { + + // + // Remove this entry from the list before assigning + // the next CPU + // + + RemoveEntryList(&TargetCpu->ListEntry.ListEntry); + + } + } + + // + // Add the CPU's back to the global list. + // + + for (Target = 0; Target < HalpNumberOfTargetCpus; Target++) { + + if (IodVectorData->TargetCpu[Target]) { + + InsertTailList( + &HalpCpuVectorDataHead, + &IodVectorData->TargetCpu[Target]->ListEntry.ListEntry + ); + + } + } + + } + + // + // Determine if the vector has already been assigned a target. + // If so, return the target cpu that is was assigned to. + // If not Choose the CPU with the minimum weight. The weight + // is an indication of how many PCI vectors have already been + // assigned to a CPU. + // + + if ( (IodVectorData->TargetCpu[0] != NULL) && + (IodVectorData->IntMask[0].all & InterruptBit) ) { + + Target = 0; + + } else if ( (IodVectorData->TargetCpu[1] != NULL) && + (IodVectorData->IntMask[1].all & InterruptBit) ) { + + Target = 1; + + } else if ( !IodVectorData->TargetCpu[1] ) { + + // + // If the second target CPU was not assigned, + // this is a UP system so choose target 0. + // + + Target = 0; + + } else if ( IodVectorData->TargetCpu[0]->ListEntry.Weight < + IodVectorData->TargetCpu[1]->ListEntry.Weight ) { + + // + // Target 0 currently has a lower interrupt load + // + + Target = 0; + + } else { + + // + // Target 1 currently has a lower interrupt load + // + + Target = 1; + + } + + TargetCpu = IodVectorData->TargetCpu[Target]; + LogicalCpu = TargetCpu->LogicalNumber; + +#if HALDBG + DbgPrint( + "Assign IOD (%d, %d) Interrupt 0x%x to Target %d, CPU %d\n", + McDeviceId.Gid, + McDeviceId.Mid, + InterruptBit, + Target, + TargetCpu->LogicalNumber + ); + +#endif + + // + // Enable this vector in the IOD Interrupt Mask + // This value is written later to the IntReq register + // + + IodVectorData->IntMask[Target].all |= InterruptBit; + + // + // Update the weight of the target CPU. + // + + TargetCpu->ListEntry.Weight++; + + return (LogicalCpu); + +} + +#if HALDBG +// +// Declare the lower-level routine used to read PCI config space +// + +VOID +HalpReadPCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + + +VOID +HalpDumpIoVectorAffinity( + VOID + ) +/*++ + +Routine Description: + + Dump IO vector Affinity Assignment +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + + + PIOD_VECTOR_DATA IodVectorData; + PCPU_VECTOR_DATA CpuVectorData; + MC_DEVICE_ID McDeviceId; + MC_ENUM_CONTEXT mcCtx; + PCI_COMMON_CONFIG CommonConfig; + PBUS_HANDLER BusHandler; + PPCIPBUSDATA BusData; + PCIPBUSDATA BusContext; + RTL_BITMAP DevicePresent; + PCI_SLOT_NUMBER SlotNumber; + PLIST_ENTRY NextEntry; + ULONG HwBusNumber; + ULONG BusNumber; + ULONG DeviceNumber; + ULONG FunctionNumber; + ULONG Target; + + + DbgPrint("Dump IOD VECTOR DATA\n\n"); + + // + // Traverse Iod Vector Data List + // + + for ( + NextEntry = HalpIodVectorDataHead.Flink; + NextEntry != &HalpIodVectorDataHead; + NextEntry = NextEntry->Flink + ) { + + + IodVectorData = (PIOD_VECTOR_DATA) NextEntry; + HwBusNumber = IodVectorData->HwBusNumber; + BusNumber = IodVectorData->BusNumber; + McDeviceId = HalpIodLogicalToPhysical[HwBusNumber]; + + DbgPrint( + "\n\nIod: Logical %d, Physical (%d, %d)\n\n", + HwBusNumber, + McDeviceId.Gid, + McDeviceId.Mid + ); + + + BusHandler = HaliHandlerForBus(PCIBus,BusNumber); + + // + // Get a pointer to the bus-specific data. + // + + BusData = (PPCIPBUSDATA)BusHandler->BusData; + + // + // Use the device-present bitmap for this bus to query configuration + // Space for InterruptLine values. + // + + // + // Initialize the device-present bitmap for this bus. + // + + HalpInitializeBitMap( + &BusContext.DevicePresent, + BusContext.DevicePresentBits, + PCI_MAX_DEVICES * PCI_MAX_FUNCTION + ); + + // + // Copy the bitmap from the bus handler. + // + + RtlCopyMemory( + &BusContext.DevicePresentBits, + &BusData->DevicePresentBits, + sizeof (BusData->DevicePresentBits) + ); + + + // + // Starting with device 0, scan the device present + // bitmap. + // + + DeviceNumber = 0; + + DbgPrint("Devices Present on Bus:\n\n"); + + while ( (DeviceNumber = + HalpFindSetBitsAndClear( + &BusContext.DevicePresent, + 1, + DeviceNumber + ) ) != -1 ) { + + DbgPrint("Device Number %d\n", DeviceNumber); + + // + // Initialize the slot number. + // + + SlotNumber.u.AsULONG = 0; + SlotNumber.u.bits.DeviceNumber = DeviceNumber; + + // + // Loop through each function number. + // + + for (FunctionNumber = 0; + FunctionNumber < PCI_MAX_FUNCTION; + FunctionNumber++) { + + SlotNumber.u.bits.FunctionNumber = FunctionNumber; + + // + // Read the common configuration header. + // + + HalpReadPCIConfig( + BusHandler, + SlotNumber, + &CommonConfig, + 0, + PCI_COMMON_HDR_LENGTH + ); + + // + // If the Vendor ID is invalid, then no device is present + // at this device/function number. + // + + if (CommonConfig.VendorID == PCI_INVALID_VENDORID) { + if (FunctionNumber == 0) { + break; + } + continue; + } + + DbgPrint( + "Device %d, Function %d\n", + DeviceNumber, + FunctionNumber + ); + + DbgPrint( + "VendorId 0x%x, InterruptLine 0x%x\n", + CommonConfig.VendorID, + CommonConfig.u.type0.InterruptLine + ); + + // + // If this is not a multi-function device, then terminate + // the function number loop. + // + + if ((CommonConfig.HeaderType & PCI_MULTIFUNCTION) == 0) { + break; + } + + } // for (FunctionNumber...) + + } // while (DeviceNumber) + + + DbgPrint("\nIOD Targets:\n\n"); + + for (Target = 0; Target < IOD_MAX_INT_TARG; Target++) { + + DbgPrint( + "DevId: (%d, %d), Mask: 0x%x\n", + IodVectorData->IntTarg[Target].Gid, + IodVectorData->IntTarg[Target].Mid, + IodVectorData->IntMask[Target].all + ); + + } + + } //for (IodVectorData) + + DbgPrint("\nDump CPU VECTOR DATA\n\n"); + + for ( + NextEntry = HalpCpuVectorDataHead.Flink; + NextEntry != &HalpCpuVectorDataHead; + NextEntry = NextEntry->Flink + ) { + + + CpuVectorData = (PCPU_VECTOR_DATA) NextEntry; + McDeviceId = + HalpLogicalToPhysicalProcessor[CpuVectorData->LogicalNumber]; + + DbgPrint( + "Cpu: Logical %d Physical (%d,%d)\n", + CpuVectorData->LogicalNumber, + McDeviceId.Gid, + McDeviceId.Mid + ); + + } + +} + +#endif // HALDBG diff --git a/private/ntos/nthals/halraw/alpha/rwintbal.h b/private/ntos/nthals/halraw/alpha/rwintbal.h new file mode 100644 index 000000000..ba3d5fb0a --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/rwintbal.h @@ -0,0 +1,200 @@ +/*++ + +Copyright (c) 1995 Digital Equipment Corporation + +Module Name: + + rwintbal.h + +Abstract: + + This file contains definitions specific to the Rawhide platform + +Author: + + Matthew Buchman 29-Nov-1995 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#ifndef _RWINTBALH_ +#define _RWINTBALH_ + +#if !defined (_LANGUAGE_ASSEMBLY) + +// +// Define the structures for assigning vector affinity +// + +// +// Generic weighted list. The weight field is used by the +// affinity assignment algorithm when selecting IOD and CPU's +// + +typedef struct _WEIGHTED_LIST_ENTRY { + LIST_ENTRY ListEntry; + LONG Weight; +} WEIGHTED_LIST_ENTRY, *PWEIGHTED_LIST_ENTRY; + +// +// Search Criteria enum for MAX/MIN search +// + +typedef enum _WEIGHTED_SEARCH_CRITERIA { + FindMaxWeight, + FindMinWeight +} WEIGHTED_SEARCH_CRITERIA, *PWEIGHTED_SEARC_CRITERIA; + +// +// Define CPU vector information structure. +// + +typedef struct _CPU_VECTOR_DATA { + + WEIGHTED_LIST_ENTRY ListEntry; // Generic list + ULONG LogicalNumber; // Logical Id for this CPU + +} CPU_VECTOR_DATA, *PCPU_VECTOR_DATA; + +// +// Define IOD vector data structure. This structure +// contains information on devices present on an IOD, their +// vectors, and shadow registers for IntReq and IntTarg +// + +typedef struct _IOD_VECTOR_DATA { + + WEIGHTED_LIST_ENTRY ListEntry; // Generic list + + PCPU_VECTOR_DATA TargetCpu[2]; // Target CPU vector data + + RTL_BITMAP VectorPresent[2]; // IOD device vectors present + RTL_BITMAP SharedVector[2]; // IOD device vectors shared + ULONG VectorPresentBits[2]; // bitmap storage + ULONG SharedVectorBits[2]; // bitmap storage + ULONG BusNumber; // Logical bus number for this IOD + ULONG HwBusNumber; // Physical bus number for this IOD + ULONG Affinity[2]; // Vector AFFINITY for targets 0/1 + IOD_INT_MASK IntMask[2]; // Shadow of IOD IntMaskX + MC_DEVICE_ID IntTarg[2]; // Shadow of IOD IntTargX + +} IOD_VECTOR_DATA, *PIOD_VECTOR_DATA; + + +typedef enum _IOD_IRR_BITS{ + + IodPci0IrrBit = 0, + IodPci1IrrBit = 1, + IodPci2IrrBit = 2, + IodPci3IrrBit = 3, + IodPci4IrrBit = 4, + IodPci5IrrBit = 5, + IodPci6IrrBit = 6, + IodPci7IrrBit = 7, + IodPci8IrrBit = 8, + IodPci9IrrBit = 9, + IodPci10IrrBit = 10, + IodPci11IrrBit = 11, + IodPci12IrrBit = 12, + IodPci13IrrBit = 13, + IodPci14IrrBit = 14, + IodPci15IrrBit = 15, + IodEisaIrrBit = 16, + IodScsiIrrBit = 16, + IodI2cCtrlIrrBit = 17, + IodI2cBusIrrBit = 18, + IodEisaNmiIrrBit = 21, + IodSoftErrIrrBit = 22, + IodHardErrIrrBit = 23 + +} IOD_IRR_BITS, *PIOD_IRR_BITS; + +extern PIOD_VECTOR_DATA HalpIodVectorData; +extern PCPU_VECTOR_DATA HalpCpuVectorData; + +extern MC_DEVICE_ID HalpProcessorMcDeviceId[]; + +extern LIST_ENTRY HalpIodVectorDataHead; +extern LIST_ENTRY HalpCpuVectorDataHead; + +// +// Weighted list manipulation routines +// + +PWEIGHTED_LIST_ENTRY +HalpFindWeightedList( + PLIST_ENTRY ListHead, + WEIGHTED_SEARCH_CRITERIA SearchCriteria + ); + + +// +// Rawhide interrupt routine prototypes. +// + +#if 0 +VOID +HalpFindAllPciVectors( + IN PCONFIGURATION_COMPONENT_DATA Root + ); + +VOID +HalpFindPciBusVectors( + IN PCONFIGURATION_COMPONENT Component, + IN PVOID ConfigurationData + ); + +VOID +HalpInitializeIoVectorAffinity( + PLOADER_PARAMETER_BLOCK AFFINITYerBlock + ); + +VOID +HalpBalanceIoVectorLoad( + PLIST_ENTRY pIodListHead + ); + +VOID +HalpBalanceVectorLoadForIod( + PIOD_VECTOR_DATA IodVectorData + ); + +#endif + +VOID +HalpInitializeVectorBalanceData( + VOID + ); + +VOID +HalpInitializeCpuVectorData( + ULONG LogicalCpu + ); + +VOID +HalpAssignPrimaryProcessorVectors( + PLIST_ENTRY + ); + +ULONG +HalpAssignInterruptForIod( + PIOD_VECTOR_DATA IodVectorData, + ULONG InterruptVector + ); + +#ifdef HALDBG +VOID +HalpDumpIoVectorAffinity( + VOID + ); +#endif + +#endif // !defined (_LANGUAGE_ASSEMBLY) + +#endif //_RWINTBALH_ diff --git a/private/ntos/nthals/halraw/alpha/rwintsup.c b/private/ntos/nthals/halraw/alpha/rwintsup.c new file mode 100644 index 000000000..53f546dc3 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/rwintsup.c @@ -0,0 +1,2364 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + rwintsup.c + +Abstract: + + The module provides the interrupt support for Rawhide systems. + +Author: + + Eric Rehm (DEC) 29-December-1993 + +Revision History: + + Eric Rehm (DEC) 26-July-1994 + Adapted from Alcor module for Rawhide. + +--*/ + + +#include "halp.h" +#include "pci.h" +#include "pcip.h" +#include "eisa.h" +#include "ebsgdma.h" +#include "rawhide.h" +#include "pintolin.h" + +extern IOD_REGISTER_CLASS DumpIodFlag; + +// +// Declare the interrupt structures and spinlocks for the intermediate +// interrupt dispatchers. +// + +KINTERRUPT HalpPciInterrupt; +KINTERRUPT HalpEisaInterrupt; + +extern BOOLEAN HalpLogCorrectableErrors; + +// +// The enable mask for all interrupts sourced from the IOD (all device +// interrupts, and all from PCI). A "1" indicates the interrupt is enabled. +// + +ULONG HalpIodInterruptMask[RAWHIDE_MAXIMUM_PCI_BUS][2] = {0}; + +// +// Define the context structure for use by interrupt service routines. +// + +typedef BOOLEAN (*PSECOND_LEVEL_DISPATCH)( + PKINTERRUPT InterruptObject, + PVOID ServiceContext, + PKTRAP_FRAME TrapFrame + ); + +// +// Declare the interrupt handler for the EISA bus. The interrupt dispatch +// routine, HalpEisaDispatch, is called from this handler. +// + +BOOLEAN +HalpEisaInterruptHandler( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + +// +// The following is the interrupt object used for DMA controller interrupts. +// DMA controller interrupts occur when a memory parity error occurs or a +// programming error occurs to the DMA controller. +// + +KINTERRUPT HalpEisaNmiInterrupt; + +// +// The following function initializes NMI handling. +// + +VOID +HalpInitializeNMI( + VOID + ); + +// +// The following function is called when an EISA NMI occurs. +// + +BOOLEAN +HalHandleNMI( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + +// +// The following functions handle the PCI interrupts. +// + +VOID +HalpInitializeIodInterrupts( + MC_DEVICE_ID McDeviceId, + ULONG PciBusNumber, + va_list Arguments + ); + +VOID +HalpDisablePciInterrupt( + IN ULONG Vector + ); + +VOID +HalpEnablePciInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ); + +BOOLEAN +HalpDeviceDispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PKTRAP_FRAME TrapFrame + ); + +// +// Private prototypes + +VOID +HalpRawhideDecodePciVector( + IN ULONG PciVector, + OUT PULONG PciBusNumber, + OUT PULONG InterruptLine + ); + + +ULONG +HalpGetRawhidePciInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ) + +/*++ + +Routine Description: + + This function returns the system interrupt vector and IRQL level + corresponding to the specified PCI bus interrupt level and/or vector. + PCI vectors for rawhide are allocated starting with vector 0x40. + Vectors are assigned using the BusInterruptVector and the HwBusNumber. + One execption to this is NCR810 SCSI on PCI bus 1, which is always + allocated vector 0x32. + + The HwBusNumber is encoded in the PCI vector by allocating vectors + in blocks of 16 (each IOD supports 16 PCI vectors) as shown below. + + RawhidePciVectors: + 0x40 |-------------------| + | PCI 0 vectors | + |-------------------| + 0x50 | PCI 1 vectors | + |-------------------| + . + . + PCI interrupt routines may use the vector assigned to obtain the + PCI bus number and IRR bit as follows. + + PciBus = (Vector - RawhidePciVectors) / 0x10 + IrrBitShift = (Vector - RawhidePciVectors) % 0x10 + +Arguments: + + BusHandler - Supplies a pointer to the bus handler of the bus that + needs a system interrupt vector. + + RootHandler - Supplies a pointer to the bus handler of the root + bus for the bus represented by BusHandler. + + BusInterruptLevel - Supplies the bus-specific interrupt level. + + BusInterruptVector - Supplies the bus-specific interrupt vector + assigned to the device during PCI configuration + using the Pin-to-line table. + + Irql - Returns the system request priority. + + Affinity - Returns the affinity for the requested vector + +Return Value: + + Returns the system interrupt vector corresponding to the PCI device. + +--*/ + +{ + MC_DEVICE_ID McDeviceId; + IOD_INT_MASK IntMask; + IOD_INT_TARGET_DEVICE IntTarg; + PIOD_VECTOR_DATA IodVectorData; + PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData; + ULONG LogicalProcessor; + ULONG TargetCpu; + ULONG MaskBit; + ULONG PciVector; + ULONG PciBusNumber; + ULONG InterruptLine; + + // + // NCR 810 on Bus 1 is a special case + // + + if ( (BusInterruptVector == RawhideNcr810PinToLine) && + (BusData->HwBusNumber == 1) ) { + + PciVector = RawhideScsiVector; + + } else { + +#if HALDBG + DbgPrint( + "HalpGetRawhidePciInterruptVector: Bus %d\n", + BusData->HwBusNumber + ); +#endif + // + // Build the rawhide vector. + // + + PciVector = RawhidePciVectors; + PciVector += (BusData->HwBusNumber << 4); + + // + // BusInterruptVectors are numbered 1-16, so + // subtract one to convert to table offset. + // + + PciVector += (BusInterruptVector - 1); + + // + // Rawhide Pin2Line table entries contain an arbitrary offset + // so that PCI InterruptLine values don't appear to conflict + // with EISA/ISA vectors reported by WINMSD. + // + + PciVector -= RawhidePinToLineOffset; + + } + + // + // Decode the PCI bus number and interrupt line from the Vector + // + + HalpRawhideDecodePciVector(PciVector, &PciBusNumber, &InterruptLine); + +#if HALDBG + DbgPrint( + "Vector 0x%x maps to PCI %d, InterruptLine %d\n", + PciVector, + PciBusNumber, + InterruptLine + ); +#endif + + // + // Determine which IOD this interrupt is assigned to + // and obtain the IOD's geographic address. + // + + McDeviceId = HalpIodLogicalToPhysical[PciBusNumber]; + + // + // Determine the IRR bit + // + + MaskBit = (ULONG) 1<< InterruptLine; + + // + // Obtain the IOD vector table entry + // + + IodVectorData = HalpIodVectorData + PciBusNumber; + + // + // Assign this vector to a CPU. This will update the target + // mask for this IOD as a side effect. + // + + TargetCpu = HalpAssignInterruptForIod(IodVectorData, MaskBit); + +#if HALDBG + DbgPrint("HalpGetRawhidePCIVector: CPU %d\n", TargetCpu); +#endif + + // + // Assign affinity for all processors. This will cause + // the kernel to add an IDT entry for all processors. + // This is necessary if we are going to dynamically + // reassign the interrupt to a different processor at + // a later time. + // + + *Irql = DEVICE_HIGH_LEVEL; + *Affinity = (1 << TargetCpu); + +#if HALDBG + DbgPrint( + "HalpGetRawhidePCIVector: vector 0x%x, Iqrl 0x%x, Affinity 0x%x\n", + PciVector, + *Irql, + *Affinity + ); +#endif + + return ( PciVector ); + +} + + +ULONG +HalpGetRawhideEisaInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ) + +/*++ + +Routine Description: + + This function returns the system interrupt vector and IRQL level + corresponding to the specified Eisa/Isa interrupt level and/or vector. + Eisa vectors for rawhide are allocated starting at vector 0x20. + Vectors are assigned using the BusInterruptLevel. + +Arguments: + + BusHandler - Supplies a pointer to the bus handler of the bus that + needs a system interrupt vector. + + RootHandler - Supplies a pointer to the bus handler of the root + bus for the bus represented by BusHandler. + + BusInterruptLevel - Supplies the bus-specific interrupt level. + + BusInterruptVector - Supplies the bus-specific interrupt vector. + + Irql - Returns the system request priority. + + Affinity - Returns the affinity for the requested vector + +Return Value: + + Returns the system interrupt vector corresponding to the specified device. + +--*/ +{ + ULONG EisaVector; + PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData; + + // + // Build the Eisa/Isa vector + // + + EisaVector = RawhideEisaVectors; + EisaVector += BusInterruptLevel; + + // + // Assign affinity for all processors. This will cause + // the kernel to add an IDT entry for all processors. + // This is necessary if we are going to dynamically + // reassign the interrupt to a different processor at + // a later time. + // + + *Irql = DEVICE_HIGH_LEVEL; + *Affinity = (1 << HAL_PRIMARY_PROCESSOR); + + return ( EisaVector ); +} + + +ULONG +HalpGetRawhideInternalInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ) + +/*++ + +Routine Description: + + This function returns the system interrupt vector and IRQL level + corresponding to the specified Internal Bus interrupt level. + Vectors are assigned using the BusInterruptLevel. + +Arguments: + + BusHandler - Supplies a pointer to the bus handler of the bus that + needs a system interrupt vector. + + RootHandler - Supplies a pointer to the bus handler of the root + bus for the bus represented by BusHandler. + + BusInterruptLevel - Supplies the bus-specific interrupt level. + + BusInterruptVector - Supplies the bus-specific interrupt vector. + + Irql - Returns the system request priority. + + Affinity - Returns the affinity for the requested vector + +Return Value: + + Returns the system interrupt vector corresponding to the specified device. + +--*/ +{ + PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData; + PIOD_VECTOR_DATA IodVectorData; + ULONG InternalVector; + ULONG TargetCpu; + ULONG MaskBit; + + // + // Build the Eisa/Isa vector + // + + InternalVector = RawhideInternalBusVectors; + InternalVector += BusInterruptLevel; + + // + // The Soft Error has already been assigned + // to the primary processor. + // + + if (InternalVector == RawhideSoftErrVector) { + + TargetCpu = HAL_PRIMARY_PROCESSOR; + + } + + // + // The only other Internal device support by + // Rawhide is the I2c bus. This reside on PCI0. + // + + else { + + // + // Map the vector to an interrupt line. + // + + switch (InternalVector) { + + case RawhideI2cCtrlVector: + + MaskBit = IodI2cCtrlIntMask; + break; + + case RawhideI2cBusVector: + + MaskBit = IodI2cBusIntMask; + break; + + } + + // + // Obtain PCI0 vector data + // + + IodVectorData = HalpIodVectorData; + + // + // Assign this vector to a CPU. This will update the target + // mask for this IOD as a side effect. + // + + TargetCpu = HalpAssignInterruptForIod(IodVectorData, MaskBit); + +#if HALDBG + DbgPrint("HalpGetRawhideInternalVector: CPU %d\n", TargetCpu); +#endif + + } + + // + // Assign the vector affinity. + // + + *Irql = DEVICE_HIGH_LEVEL; + *Affinity = (1 << TargetCpu); + +#if HALDBG + DbgPrint( + "HalpGetRawhideInternalVector: vector 0x%x, Iqrl 0x%x, Affinity 0x%x\n", + InternalVector, + *Irql, + *Affinity + ); +#endif + + return ( InternalVector ); +} + + +BOOLEAN +HalpInitializeRawhideInterrupts ( + VOID + ) +/*++ + +Routine Description: + + This routine initializes the structures necessary for EISA & PCI operations + and connects the intermediate interrupt dispatchers. It also initializes + the EISA interrupt controller; the Rawhide ESC's interrupt controller is + compatible with the EISA interrupt contoller used on Jensen. + +Arguments: + + None. + +Return Value: + + If the second level interrupt dispatchers are connected, then a value of + TRUE is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + KIRQL oldIrql; + + // + // Initialize the EISA NMI interrupt. + // + + HalpInitializeNMI(); + + (PVOID) HalpPCIPinToLineTable = (PVOID) RawhidePCIPinToLineTable; + + // + // Intitialize interrupt controller + // + + KeRaiseIrql(DEVICE_HIGH_LEVEL, &oldIrql); + + // + // Initialize the ESC's PICs for EISA interrupts. + // + + HalpInitializeEisaInterrupts(); + + // + // Initialize the interrupt request masks for all IOD's + // + + HalpMcBusEnumAndCall(HalpIodMask, HalpInitializeIodInterrupts); + + +#if HALDBG + DumpAllIods(DumpIodFlag); +#endif + // + // Restore the IRQL. + // + + KeLowerIrql(oldIrql); + + // + // Initialize the EISA DMA mode registers to a default value. + // Disable all of the DMA channels except channel 4 which is the + // cascade of channels 0-3. + // + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort.AllMask, + 0x0F + ); + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort.AllMask, + 0x0E + ); + + return(TRUE); +} + + +VOID +HalpInitializeNMI( + VOID + ) +/*++ + +Routine Description: + + This function is called to intialize ESC NMI interrupts. + Rawhide uses the Axp legacy ESC NMI vector. + +Arguments: + + None. + +Return Value: + + None. +--*/ +{ + UCHAR DataByte; + MC_DEVICE_ID McDeviceId; + IOD_INT_MASK IodIntMask; + + // + // Initialize the ESC NMI interrupt. + // + + KeInitializeInterrupt( &HalpEisaNmiInterrupt, + HalHandleNMI, + NULL, + NULL, + EISA_NMI_VECTOR, + EISA_NMI_LEVEL, + EISA_NMI_LEVEL, + LevelSensitive, + FALSE, + 0, + FALSE + ); + + // + // Don't fail if the interrupt cannot be connected. + // + + KeConnectInterrupt( &HalpEisaNmiInterrupt ); + + // + // Clear the Eisa NMI disable bit. This bit is the high order of the + // NMI enable register. + // + + DataByte = 0; + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable, + DataByte + ); + +} + + +BOOLEAN +HalHandleNMI( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ) +/*++ + +Routine Description: + + This function is called when an EISA NMI occurs. It prints the + appropriate status information and bugchecks. + +Arguments: + + Interrupt - Supplies a pointer to the interrupt object + + ServiceContext - Bug number to call bugcheck with. + +Return Value: + + Returns TRUE. + +--*/ +{ + UCHAR StatusByte; + + StatusByte = + READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus); + + if (StatusByte & 0x80) { + HalDisplayString ("NMI: Parity Check / Parity Error\n"); + } + + if (StatusByte & 0x40) { + HalDisplayString ("NMI: Channel Check / IOCHK\n"); + } + + KeBugCheck(NMI_HARDWARE_FAILURE); + return(TRUE); +} + + +VOID +HalpInitializeIodInterrupts( + MC_DEVICE_ID McDeviceId, + ULONG PciBusNumber, + va_list Arguments + ) + +/*++ + +Routine Description: + + This enumeration routine is called during Phase 0 to assign the + Rawhide Error interrupts for the corresponding IOD to the Primary CPU. + The interrupts + are initialized as follows: + + PCI - disabled + HardErr - DISABLED!!! //ecrfix enabled + SoftErr - disabled + Eisa - enabled (Bus 0 only) + EisaNmi - enabled (Bus 0 only) + I2c - disabled (Bus 0 only) + + The logical bus is assigned from the static variable PciBusNumber, which is + incremented with each invokation. + +Arguments: + + McDeviceId - Supplies the MC Bus Device ID of the IOD to be intialized + + PciBusNumber - Logical (Hardware) PCI Bus number. + + Arguments - Variable Arguments. None for this routine. + +Return Value: + + None. + +--*/ + +{ + IOD_INT_MASK IntMask; + PVOID IntMaskQva; + ULONG Target; + + // + // 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 all pending interrupts for this IOD + // + + WRITE_IOD_REGISTER_NEW( + McDeviceId, + &((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntAck0, + 0x0 + ); + + // + // 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 EISA interrupts for IOD 0 + // + + if (PciBusNumber == 0) { + + INTERRUPT_ACKNOWLEDGE((PVOID)IOD_PCI0_IACK_QVA); + + } + + + // mdbfix - For now, target0 = CPU0, target1 = CPU1 + // + // Write the target register. + // + + WRITE_IOD_REGISTER_NEW( + McDeviceId, + &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntTarg, + HalpLogicalToPhysicalProcessor[0].all + ); + + // + // Write the mask bits for target 0 and 1 + // + + for (Target = 0; Target < 2; Target++) { + + // + // Obtain the target IRR QVA + // + + if (Target) { + + IntMaskQva = (PVOID)&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntMask1; + + } else { + + IntMaskQva = (PVOID)&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntMask0; + + } + + IntMask.all = READ_IOD_REGISTER_NEW( + McDeviceId, + IntMaskQva + ); + + // + // Initialize HardErr for all buses, but Eisa and EisaNmi + // only for Bus 0 + // + + if (PciBusNumber == 0) { + + IntMask.all = + IodHardErrIntMask | IodSoftErrIntMask | + IodEisaIntMask |IodEisaNmiIntMask; + + } else { + + IntMask.all = IodHardErrIntMask | IodSoftErrIntMask; + + } + + if (Target ) { + + IntMask.all = 0; + + } + + WRITE_IOD_REGISTER_NEW( + McDeviceId, + IntMaskQva, + IntMask.all + ); + + HalpIodInterruptMask[PciBusNumber][Target] = IntMask.all; + } + + // + // Enable Interrupts. + // + + WRITE_IOD_REGISTER_NEW( + McDeviceId, + &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntCtrl, + (IOD_INT_CTL_ENABLE_IO_INT | IOD_INT_CTL_ENABLE_VECT_WRITE) + ); +} + + +VOID +HalpRawhideDecodePciVector( + IN ULONG PciVector, + OUT PULONG PciBusNumber, + OUT PULONG InterruptLine + ) + +/*++ + +Routine Description: + + This decodes a PCI vector to obtain the PCI hardware bus number + and the InterruptLine. + +Arguments: + + PciVector - Supplies the vector of the PCI interrupt that is disabled. + + PciBusNumber - IOD number encoded in vector + + InterruptLine - IRR interrupt bit number encoded in vector + +Return Value: + + The PCI bus number and interrupt line are returned. + +--*/ + +{ + // + // Special case for NCR810 vector + // + + if (PciVector == RawhideScsiVector) { + + *PciBusNumber = RAWHIDE_SCSI_PCI_BUS; + *InterruptLine = IodScsiIrrBit; + + } else { + + // + // Extract the Pci bus number and Interrupt line from the vector + // + + PciVector -= RawhidePciVectors; + *PciBusNumber = PciVector / IOD_PCI_VECTORS; + *InterruptLine = PciVector % IOD_PCI_VECTORS; + + } +} + + +VOID +HalpDisablePciInterrupt( + IN ULONG Vector + ) + +/*++ + +Routine Description: + + This function disables the PCI interrupt specified by Vector. + +Arguments: + + Vector - Supplies the vector of the PCI interrupt that is disabled. + +Return Value: + + None. + +--*/ + +{ + MC_DEVICE_ID McDeviceId; + IOD_INT_MASK IntMask; + PIOD_VECTOR_DATA IodVectorData; + PVOID IntMaskQva; + ULONG PciBusNumber; + ULONG InterruptLine; + ULONG MaskBit; + ULONG Target = 0; + + // + // Decode the PCI bus number and interrupt line from the vector + // + + HalpRawhideDecodePciVector(Vector, &PciBusNumber, &InterruptLine); + + // + // Determine which IOD this interrupt is assigned to + // and obtain the IOD's geographic address. + // + + McDeviceId = HalpIodLogicalToPhysical[PciBusNumber]; + + // + // Determine the IRR bit + // + + MaskBit = ~(1 << InterruptLine); + + // + // Obtain the IOD vector table entry + // + + IodVectorData = HalpIodVectorData + PciBusNumber; + + // + // Determine the target CPU for this vector and + // obtain the cooresponding IntMask QVA + // + + if (IodVectorData->IntMask[0].all & MaskBit) { + + Target = 0; + IntMaskQva = (PVOID)&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntMask0; + + } else if (IodVectorData->IntMask[1].all & MaskBit) { + + Target = 1; + IntMaskQva = (PVOID)&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntMask1; + + } else { + +#if HALDBG + DbgPrint("HalpDisablePciInterrupt: Vector not assigned target\n"); +#endif + return; + + } + +#if HALDBG + DbgPrint("HalpDisablePciInterrupt: Target %d\n", Target); +#endif + + // + // Unassign this vector in the IOD vector data + // + + IodVectorData->IntMask[Target].all &= MaskBit; + + // + // Decrement CPU vector weight + // + + IodVectorData->TargetCpu[Target]->ListEntry.Weight--; + + // + // Get the current state of the interrupt mask register, then clear + // the bit corresponding to the adjusted value of Vector to zero, + // to disable that PCI interrupt. + // + + IntMask.all = READ_IOD_REGISTER_NEW( + McDeviceId, + IntMaskQva + ); + +#if HALDBG + DbgPrint("HalpDisablePCIVector: IntMask(before) 0x%x\n", IntMask); +#endif + + IntMask.all &= MaskBit; + + WRITE_IOD_REGISTER_NEW( + McDeviceId, + IntMaskQva, + IntMask.all + ); + +#if HALDBG + IntMask.all = READ_IOD_REGISTER_NEW( + McDeviceId, + IntMaskQva + ); + + DbgPrint("HalpDisablePCIVector: IntMask(after) 0x%x\n", IntMask); +#endif + + // + // Turn off this interrupt in the software mask + // + + HalpIodInterruptMask[PciBusNumber][Target] &= MaskBit; + +} + + +VOID +HalpEnablePciInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ) + +/*++ + +Routine Description: + + This function enables the PCI interrupt specified by Vector. +Arguments: + + Vector - Supplies the vector of the PCI interrupt that is enabled. + + InterruptMode - Supplies the mode of the interrupt; LevelSensitive or + Latched (ignored for Rawhide PCI interrupts; they're always levels). + +Return Value: + + None. + +--*/ + +{ + MC_DEVICE_ID McDeviceId; + IOD_INT_MASK IntMask; + IOD_INT_TARGET_DEVICE IntTarg; + PIOD_VECTOR_DATA IodVectorData; + PVOID IntMaskQva; + ULONG PciBusNumber; + ULONG InterruptLine; + ULONG MaskBit; + ULONG Affinity; + ULONG Target = 0; + + +#if HALDBG + DbgPrint( + "HalpEnablePciInterrupt: Vector 0x%x, Mode 0x%x\n", + Vector, + InterruptMode + ); +#endif + + // + // The kernel will call this routine on the processor + // who will receive the interrupt + // + + Affinity = ( 1 << PCR->Prcb->Number); + + // + // Decode the PCI bus number and interrupt line from the Vector + // + + HalpRawhideDecodePciVector(Vector, &PciBusNumber, &InterruptLine); + +#if HALDBG + DbgPrint( + "Vector 0x%x maps to PCI %d, InterruptLine %d\n", + Vector, + PciBusNumber, + InterruptLine + ); +#endif + + // + // Determine which IOD this interrupt is assigned to + // and obtain the IOD's geographic address. + // + + McDeviceId = HalpIodLogicalToPhysical[PciBusNumber]; + + // + // Determine the IRR bit + // + + MaskBit = (ULONG) 1<< InterruptLine; + + // + // Obtain the IOD vector table entry + // + + IodVectorData = HalpIodVectorData + PciBusNumber; + + // + // Obtain the Target CPU + // + + + if (IodVectorData->Affinity[0] == Affinity) { + + Target = 0; + IntMaskQva = (PVOID)&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntMask0; + + } else { + + Target = 1; + IntMaskQva = (PVOID)&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntMask1; + + } + + // + // Handle the case where another device shares this interrupt line. + // + + if ( HalpIodInterruptMask[PciBusNumber][Target] & MaskBit) { + +#if HALDBG + DbgPrint("Vector 0x%x already assigned\n", Vector); +#endif + + return; + + } + + // + // Get the current state of the interrupt mask register, then set + // the bit corresponding to the adjusted value of Vector to zero, + // to enable that PCI interrupt. + // + + IntMask.all = READ_IOD_REGISTER_NEW( + McDeviceId, + IntMaskQva + ); + +#if HALDBG + DbgPrint("HalpEnablePCIVector: IntMask(before) 0x%x\n", IntMask); +#endif + + IntMask.all |= MaskBit; + + WRITE_IOD_REGISTER_NEW( + McDeviceId, + IntMaskQva, + IntMask.all + ); + +#if HALDBG + IntMask.all = READ_IOD_REGISTER_NEW( + McDeviceId, + IntMaskQva + ); + + DbgPrint("HalpEnablePCIVector: IntMask(after) 0x%x\n", IntMask); +#endif + +#if HALDBG + DumpAllIods(DumpIodFlag & IodInterruptRegisters); +#endif + + HalpIodInterruptMask[PciBusNumber][Target] |= MaskBit; + +#if HALDBG + DbgPrint( + "HalpEnablePCIVector: Software Mask 0x%x\n", + HalpIodInterruptMask[PciBusNumber][Target] + ); +#endif +} + + +VOID +HalpDisableInternalInterrupt( + IN ULONG Vector + ) + +/*++ + +Routine Description: + + This function disables the Internal Bus interrupt specified by Vector. + +Arguments: + + Vector - Supplies the vector of the Internal Bus interrupt to disabled. + +Return Value: + + None. + +--*/ + +{ + MC_DEVICE_ID McDeviceId; + IOD_INT_MASK IntMask; + PIOD_VECTOR_DATA IodVectorData; + PVOID IntMaskQva; + ULONG PciBusNumber; + ULONG InterruptLine; + ULONG MaskBit; + ULONG Target = 0; + + // + // Do not physically disable the Soft Error Vector because + // the HAL Correctable Error Handler must execute when + // a Soft Error occurs for system integrity. + // + + if (Vector == RawhideSoftErrVector) { + + HalpLogCorrectableErrors = FALSE; + return; + + } + + // + // Map the vector to an interrupt line. + // + + switch (Vector) { + + case RawhideI2cCtrlVector: + + // + // I2C ctrl interrupt on PCI0 + // + + PciBusNumber = 0; + + MaskBit = IodI2cCtrlIntMask; + + break; + + + case RawhideI2cBusVector: + + // + // I2C bus interrupt on PCI0 + // + + PciBusNumber = 0; + + MaskBit = IodI2cBusIntMask; + break; + + + default: + return; + + } + + // + // Obtain the IOD geographic address for the PCI bus. + // + + McDeviceId = HalpIodLogicalToPhysical[PciBusNumber]; + + // + // Obtain the IOD vector data for the PCI bus. + // + + IodVectorData = HalpIodVectorData + PciBusNumber; + + // + // Determine the target CPU for this vector and + // obtain the cooresponding IntMask QVA + // + + if (IodVectorData->IntMask[0].all & MaskBit) { + + Target = 0; + IntMaskQva = (PVOID)&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntMask0; + + } else if (IodVectorData->IntMask[1].all & MaskBit) { + + Target = 1; + IntMaskQva = (PVOID)&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntMask1; + + } else { + +#if HALDBG + DbgPrint("HalpDisablePciInterrupt: Vector not assigned target\n"); +#endif + return; + + } + +#if HALDBG + DbgPrint("HalpDisableInteralInterrupt: Target %d\n", Target); +#endif + + // + // Unassign this vector in the IOD vector data + // + + IodVectorData->IntMask[Target].all &= ~MaskBit; + + // + // Decrement CPU vector weight + // + + IodVectorData->TargetCpu[Target]->ListEntry.Weight--; + + // + // Get the current state of the interrupt mask register, then clear + // the bit corresponding to the adjusted value of Vector to zero, + // to disable that PCI interrupt. + // + + IntMask.all = READ_IOD_REGISTER_NEW( + McDeviceId, + IntMaskQva + ); + +#if HALDBG + DbgPrint("HalpEnablePCIVector: IntMask(before) 0x%x\n", IntMask); +#endif + + IntMask.all &= ~MaskBit; + + WRITE_IOD_REGISTER_NEW( + McDeviceId, + IntMaskQva, + IntMask.all + ); + +#if HALDBG + IntMask.all = READ_IOD_REGISTER_NEW( + McDeviceId, + IntMaskQva + ); + + DbgPrint("HalpEnablePCIVector: IntMask(after) 0x%x\n", IntMask); +#endif + + // + // Turn off this interrupt in the software mask + // + + HalpIodInterruptMask[PciBusNumber][Target] &= ~MaskBit; + +} + + +VOID +HalpEnableInternalInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ) + +/*++ + +Routine Description: + + This function enables the Internal Bus interrupt specified by Vector. +Arguments: + + Vector - Supplies the vector of the Internal Bus interrupt that is enabled. + + InterruptMode - Ignored. Rawhide device interrupts level sensitive. + +Return Value: + + None. + +--*/ + +{ + MC_DEVICE_ID McDeviceId; + IOD_INT_MASK IntMask; + IOD_INT_TARGET_DEVICE IntTarg; + PIOD_VECTOR_DATA IodVectorData; + PVOID IntMaskQva; + ULONG PciBusNumber; + ULONG InterruptLine; + ULONG MaskBit; + ULONG Affinity; + ULONG Target = 0; + + + // + // Do not physically disable the Soft Error Vector because + // the HAL Correctable Error Handler must execute when + // a Soft Error occurs for system integrity. + // + + if (Vector == RawhideSoftErrVector) { + + HalpLogCorrectableErrors = TRUE; + return; + + } + + // + // The kernel will call this routine on the processor + // who will receive the interrupt + // + + Affinity = ( 1 << PCR->Prcb->Number); + + // + // Map the vector to an interrupt line. + // + + switch (Vector) { + + case RawhideI2cCtrlVector: + + // + // I2C ctrl interrupt on PCI0 + // + + PciBusNumber = 0; + + MaskBit = IodI2cCtrlIntMask; + + break; + + case RawhideI2cBusVector: + + // + // I2C ctrl interrupt on PCI0 + // + + PciBusNumber = 0; + + MaskBit = IodI2cBusIntMask; + + break; + + + default: + return; + + } + +#if HALDBG + DbgPrint( + "HalpEnableInternalInterrupt: Vector 0x%x, Mode 0x%x\n", + Vector, + InterruptMode + ); +#endif + + +#if HALDBG + DbgPrint( + "Vector 0x%x maps to PCI %d, InterruptLine %d\n", + Vector, + 0, + MaskBit + ); +#endif + + // + // Obtain the IOD geographic address for the PCI bus. + // + + McDeviceId = HalpIodLogicalToPhysical[PciBusNumber]; + + // + // Obtain the IOD vector table entry for the PCI bus. + // + + IodVectorData = HalpIodVectorData + PciBusNumber; + + // + // Determine the target CPU for this vector and + // obtain the cooresponding IntMask QVA + // + + if (IodVectorData->Affinity[0] == Affinity) { + + Target = 0; + IntMaskQva = (PVOID)&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntMask0; + + } else { + + Target = 1; + IntMaskQva = (PVOID)&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntMask1; + + } + + // + // Get the current state of the interrupt mask register, then set + // the bit corresponding to the adjusted value of Vector to zero, + // to enable that PCI interrupt. + // + + IntMask.all = READ_IOD_REGISTER_NEW( + McDeviceId, + IntMaskQva + ); + +#if HALDBG + DbgPrint("HalpEnableInternalVector: IntMask(before) 0x%x\n", IntMask); +#endif + + IntMask.all |= MaskBit; + + WRITE_IOD_REGISTER_NEW( + McDeviceId, + IntMaskQva, + IntMask.all + ); + +#if HALDBG + IntMask.all = READ_IOD_REGISTER_NEW( + McDeviceId, + IntMaskQva + ); + + DbgPrint("HalpEnableInternalVector: IntMask(after) 0x%x\n", IntMask); +#endif + +#if HALDBG + DumpAllIods(DumpIodFlag & IodInterruptRegisters); +#endif + + HalpIodInterruptMask[PciBusNumber][Target] |= MaskBit; + +#if HALDBG + DbgPrint( + "HalpEnableInternalVector: Software Mask 0x%x\n", + HalpIodInterruptMask[PciBusNumber][Target] + ); +#endif +} + + +#if HALDBG +ULONG DeviceDispatchFlag = 0; + +#define DispatchPrint(_X_)\ +{ \ + if (DeviceDispatchFlag) DbgPrint _X_; \ +} \ + +#else + +#define DispatchPrint(_X_) + +#endif + +#ifdef FORCE_CORRECTABLE_ERROR +ULONG DispatchSoftError = 0; +#endif // FORCE_CORRECTABLE_ERROR + + +#ifndef POSTED + + +BOOLEAN +HalpDeviceDispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PKTRAP_FRAME TrapFrame + ) +/*++ + +Routine Description: + + This routine is entered as the result of an interrupt being generated + via the vector that is connected to an interrupt object associated with + the PCI device interrupts. Its function is to call the second-level + interrupt dispatch routine. + +Arguments: + + Interrupt - Supplies a pointer to the interrupt object. + + ServiceContext - Supplies a pointer to the PCI interrupt register. + + TrapFrame - Supplies a pointer to the trap frame for this interrupt. + +Return Value: + + Returns the value returned from the second level routine. + +--*/ +{ + PULONG DispatchCode; + PKINTERRUPT InterruptObject; + IOD_POSTED_INTERRUPT IntReq; + MC_ENUM_CONTEXT mcCtx; + ULONG PciIdtIndex; + ULONG VectorShift; + ULONG PciBusNumber; + ULONG Target = 0; + volatile IOD_PCI_REVISION IodRevision; + + DispatchPrint(("HalpDeviceDispatch: enter\n")); + + // + // Intialize enumerator. + // + + HalpMcBusEnumStart ( HalpIodMask, &mcCtx ); + + // + // Handle interrupts for each IOD as follows. + // + // 1. read interrupt request register for IOD + // 2. process pending EISA interrupt. + // 3. process all pending PCI interrupts. + // 4. acknowledge the interrupts serviced. + // 5. start over with next IOD. + // + + PciBusNumber = 0; + + while ( HalpMcBusEnum( &mcCtx ) ) { + + // + // Read in the interrupt register. + // + + IntReq.all = READ_IOD_REGISTER_NEW( + mcCtx.McDeviceId, + &((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntReq); + + DispatchPrint(( + "HalpDeviceDispatch: IOD 0x%x, IRR 0x%x\n", + mcCtx.McDeviceId.all, + IntReq.all + )); + + // mdbfix - is this really necessary? + // + // Consider only those interrupts which are currently enabled. + // + +#if HALDBG + if ( IntReq.all != + (IntReq.all & HalpIodInterruptMask[PciBusNumber][Target]) ) { + + DispatchPrint(( + "HalpDeviceDispatch: IOD (%d, %d), IRR Unmasked 0x%x != IRR Masked 0x%x\n", + mcCtx.McDeviceId.Gid, + mcCtx.McDeviceId.Mid, + IntReq.all, + (IntReq.all & HalpIodInterruptMask[PciBusNumber][Target]) + )); + } +#endif + + IntReq.all &= HalpIodInterruptMask[PciBusNumber][Target]; + + DispatchPrint(( + "HalpDeviceDispatch: IRR masked 0x%x\n", + IntReq.all + )); + + // + // If no interrupts pending, do not + // send INT ACK and skip to next bus. + // + + if (IntReq.all == 0) { + PciBusNumber++; + continue; + } + + // + // Handle Error Interrupts + // + + if (IntReq.HardErr ) { + + // + // Handle hard error interrupt + // +#if HALDBG + DispatchPrint(( + "Hard Error Interrupt on IOD (%d, %d)\n", + mcCtx.McDeviceId.Gid, + mcCtx.McDeviceId.Mid + )); +#endif // HALDBG + + HalpIodHardErrorInterrupt(); + + } + + if ( IntReq.SoftErr ) { + + // + // Dispatch Event logging interrupt. + // + +#if HALDBG + DispatchPrint(( + "Soft Error Interrupt on IOD (%d, %d)\n", + mcCtx.McDeviceId.Gid, + mcCtx.McDeviceId.Mid + )); +#endif // HALDBG + +#if 1 +// mdbfix - until an error log driver exists to connect the +// soft error interrupt, explicitly call the ISR. + + HalpIodSoftErrorInterrupt(); + +#else + DispatchCode = + (PULONG)PCR->InterruptRoutine[RawhideSoftErrVector]; + + InterruptObject = CONTAINING_RECORD( + DispatchCode, + KINTERRUPT, + DispatchCode + ); + + ((PSECOND_LEVEL_DISPATCH) + InterruptObject->DispatchAddress)( + InterruptObject, + InterruptObject->ServiceContext, + TrapFrame + ); +#endif + } + + // + // Process PCI interrupts. + // + + if ( IntReq.Pci ) { + + DispatchPrint(( + "HalpDeviceDispatch: PCI interrupt\n", IntReq.all + )); + + // + // Initialize IDT offset to PCI vectors and obtain + // the vector table section for this PCI bus + // + + PciIdtIndex = RawhidePciVectors + (PciBusNumber << 4); + + VectorShift = IntReq.Pci; + + while (VectorShift) { + + if ( VectorShift & 0x1 ) { + + DispatchPrint(( + "HalpDeviceDispatch: Dispatch PCI IDT Index %d\n", + PciIdtIndex + )); + + + // + // Map the Interrupt Request Register bit to a vector + // + + + DispatchCode = (PULONG)PCR->InterruptRoutine[PciIdtIndex]; + InterruptObject = CONTAINING_RECORD( + DispatchCode, + KINTERRUPT, + DispatchCode + ); + + ((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)( + InterruptObject, + InterruptObject->ServiceContext, + TrapFrame + ); + + } + + // + // Try next vector + // + + PciIdtIndex++; + VectorShift = VectorShift >> 1; + + } //end while(VectorShift); + + } //end if(IntReq.Pci); + + // + // Handle bus 0 specific interrupts + // + + if ( PciBusNumber == 0 ) { + + if ( IntReq.Eisa ) { + + // + // EISA interrupt. Call HalpEisaDispatch. + // + + HalpEisaDispatch( + Interrupt, + (PVOID)IOD_PCI0_IACK_QVA, + TrapFrame + ); + + } + + if (IntReq.I2cBus) { + + // + // I2c Bus Vector + // + + DispatchCode = + (PULONG)PCR->InterruptRoutine[RawhideI2cBusVector] ; + InterruptObject = CONTAINING_RECORD( + DispatchCode, + KINTERRUPT, + DispatchCode + ); + + ((PSECOND_LEVEL_DISPATCH) + InterruptObject->DispatchAddress)( + InterruptObject, + InterruptObject->ServiceContext, + TrapFrame + ); + } + + if (IntReq.I2cCtrl) { + + // + // I2c Controller Vector + // + + DispatchCode = + (PULONG)PCR->InterruptRoutine[RawhideI2cCtrlVector] ; + InterruptObject = CONTAINING_RECORD( + DispatchCode, + KINTERRUPT, + DispatchCode + ); + + ((PSECOND_LEVEL_DISPATCH) + InterruptObject->DispatchAddress)( + InterruptObject, + InterruptObject->ServiceContext, + TrapFrame + ); + } + + } + + // + // Handle NCR810 for PCI bus 1 + // + + if ( ( PciBusNumber == 1 ) && ( IntReq.Ncr810 ) ) { + + + DispatchCode = (PULONG)PCR->InterruptRoutine[RawhideScsiVector]; + InterruptObject = CONTAINING_RECORD( DispatchCode, + KINTERRUPT, + DispatchCode ); + + ((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)( + InterruptObject, + InterruptObject->ServiceContext, + TrapFrame ); + } + + + // + // Acknowledge after All pending interrupts serviced for this IOD + // for UP interrupt scheme, all Interrupts routed to targe 0. + // + + WRITE_IOD_REGISTER_NEW( + mcCtx.McDeviceId, + &((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntAck0, + 0x0 + ); + + // + // ecrfix - Read the IOD revision to force the write. + // + + IodRevision.all = + READ_IOD_REGISTER_NEW( + mcCtx.McDeviceId, + &((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->PciRevision ); + + + // + // Next PCI bus number + // + + PciBusNumber++; + + } //end while (HalpMcBusEnum()) + + return TRUE; + +} + +#else // POSTED + + +BOOLEAN +HalpDeviceDispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PKTRAP_FRAME TrapFrame + ) +/*++ + +Routine Description: + + This routine is entered as the result of an interrupt being generated + via the vector that is connected to an interrupt object associated with + the PCI device interrupts. Its function is to call the second-level + interrupt dispatch routine. + +Arguments: + + Interrupt - Supplies a pointer to the interrupt object. + + ServiceContext - Supplies a pointer to the PCI interrupt register. + + TrapFrame - Supplies a pointer to the trap frame for this interrupt. + +Return Value: + + Returns the value returned from the second level routine. + +--*/ +{ + PULONG DispatchCode; + PKINTERRUPT InterruptObject; + PIOD_POSTED_INTERRUPT PostedInterrupts; + IOD_POSTED_INTERRUPT IntReq; + MC_DEVICE_ID McDeviceId; + PKPRCB Prcb; + PVOID IodAckQva; + ULONG PciIdtIndex; + ULONG VectorShift; + ULONG PciBusNumber; + ULONG Target = 0; + volatile IOD_PCI_REVISION IodRevision; + + Prcb = PCR->Prcb; + PciIdtIndex = RawhidePciVectors; + + + // + // Obtain the processor area in IOD vector table + // and the IOD service mask. + // + + PostedInterrupts = (PIOD_POSTED_INTERRUPT) HAL_PCR->PostedInterrupts; + + DispatchPrint(( + "DeviceDispatch: enter, IodVectorTable 0x%x\n", + PostedInterrupts + )); + + + // + // Handle interrupts for each IOD as follows. + // + // 1. read the interrupt vector table entry. + // 2. process pending EISA interrupt. + // 3. process all pending PCI interrupts. + // 4. acknowledge the interrupts serviced. + // 5. start over with next IOD. + // + + + for ( PciBusNumber = 0; + PciBusNumber < HalpNumberOfIods; + PciBusNumber++, PostedInterrupts++) { + + DispatchPrint(( + "DeviceDispatch: IntReq: 0x%x\n\tTarget: %d\n\tDevice: (%d, %d)", + PostedInterrupts->IntReq, + PostedInterrupts->Target, + (PostedInterrupts->McDevId >> 0x3) & 0x7, + PostedInterrupts->McDevId & 0x7 + )); + + // + // Perform a passive release. + // + + if (PostedInterrupts->Valid && (PostedInterrupts->IntReq == 0) ) { + + IntReq.all = PostedInterrupts->IntReq; + McDeviceId.all = PostedInterrupts->McDevId; + + Target = PostedInterrupts->Target; + + // + // Invalidate this entry to prevent the next device interrupt + // dispatch from using stale information. We must do this + // before the ACK, which allows the IOD to post. + // + + PostedInterrupts->all = 0; + + IOD_INTERRUPT_ACKNOWLEDGE(McDeviceId, Target); + + // + // Skip to check next vector + // + + continue; + + } + + if (PostedInterrupts->Valid && PostedInterrupts->IntReq) { + + DispatchPrint(( + "DeviceDispatch: Interrupt(s) Pending on PCI bus %d\n", + PciBusNumber + )); + + + IntReq.all = PostedInterrupts->IntReq; + McDeviceId.all = PostedInterrupts->McDevId; + + Target = PostedInterrupts->Target; + + DispatchPrint(( + "DeviceDispatch: IodVectorTable\n\tIntReq: 0x%x\n\tTarget: %d\n\tDevice: (%d, %d)", + PostedInterrupts->IntReq, + PostedInterrupts->Target, + McDeviceId.Gid, + McDeviceId.Mid + )); + + // + // Consider only those interrupts which are currently enabled. + // + + IntReq.all &= HalpIodInterruptMask[PciBusNumber][Target]; + + DispatchPrint(( + "DeviceDispatch: IntReq (masked) 0x%x\n", + IntReq.all + )); + + // + // Handle Error Interrupts + // + + if (IntReq.HardErr ) { + + // + // Handle hard error interrupt + // + + DispatchPrint(( + "Hard Error Interrupt on IOD (%d, %d)\n", + McDeviceId.Gid, + McDeviceId.Mid + )); + + HalpIodHardErrorInterrupt(); + + } + + if ( IntReq.SoftErr ) { + + // + // Dispatch Event logging interrupt. + // + + DispatchPrint(( + "Soft Error Interrupt on IOD (%d, %d)\n", + McDeviceId.Gid, + McDeviceId.Mid + )); + + HalpIodSoftErrorInterrupt(); + + } + +#ifdef FORCE_CORRECTABLE_ERROR + if ( (PCR->Number == HAL_PRIMARY_PROCESSOR) && + DispatchSoftError ) { + DispatchSoftError = 0; + HalpIodSoftErrorInterrupt(); + } +#endif // FORCE_CORRECTABLE_ERROR + + // + // Process PCI interrupts. + // + + if ( IntReq.Pci ) { + + DispatchPrint(( + "HalpDeviceDispatch: PCI interrupt\n", IntReq.all + )); + + // + // Initialize IDT offset to PCI vectors and obtain + // the vector table section for this PCI bus + // + + PciIdtIndex = RawhidePciVectors + (PciBusNumber << 4); + + VectorShift = IntReq.Pci; + + while (VectorShift) { + + if ( VectorShift & 0x1 ) { + + DispatchPrint(( + "HalpDeviceDispatch: Dispatch PCI IDT Index %d\n", + PciIdtIndex + )); + + + // + // Map the Interrupt Request Register bit to a vector + // + + + DispatchCode = (PULONG)PCR->InterruptRoutine[PciIdtIndex]; + InterruptObject = CONTAINING_RECORD( + DispatchCode, + KINTERRUPT, + DispatchCode + ); + + ((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)( + InterruptObject, + InterruptObject->ServiceContext, + TrapFrame + ); + + } + + // + // Try next vector + // + + PciIdtIndex++; + VectorShift = VectorShift >> 1; + + } //end while(VectorShift); + + } //end if(IntReq.Pci); + + // + // Handle bus 0 specific interrupts + // + + if ( PciBusNumber == 0 ) { + + if ( IntReq.Eisa ) { + + // + // EISA interrupt. Call HalpEisaDispatch. + // + + HalpEisaDispatch( + Interrupt, + (PVOID)IOD_PCI0_IACK_QVA, + TrapFrame + ); + + } + + // + // Handle I2c Bus Vector + // + + if (IntReq.I2cBus) { + + + DispatchCode = + (PULONG)PCR->InterruptRoutine[RawhideI2cBusVector] ; + InterruptObject = CONTAINING_RECORD( + DispatchCode, + KINTERRUPT, + DispatchCode + ); + + ((PSECOND_LEVEL_DISPATCH) + InterruptObject->DispatchAddress)( + InterruptObject, + InterruptObject->ServiceContext, + TrapFrame + ); + } + + // + // Handle I2c Controller Vector + // + + if (IntReq.I2cCtrl) { + + DispatchCode = + (PULONG)PCR->InterruptRoutine[RawhideI2cCtrlVector] ; + InterruptObject = CONTAINING_RECORD( + DispatchCode, + KINTERRUPT, + DispatchCode + ); + + ((PSECOND_LEVEL_DISPATCH) + InterruptObject->DispatchAddress)( + InterruptObject, + InterruptObject->ServiceContext, + TrapFrame + ); + } + + } + + // + // Handle NCR810 for PCI bus 1 + // + + if ( ( PciBusNumber == 1 ) && ( IntReq.Ncr810 ) ) { + + + DispatchCode = (PULONG)PCR->InterruptRoutine[RawhideScsiVector]; + InterruptObject = CONTAINING_RECORD( DispatchCode, + KINTERRUPT, + DispatchCode ); + + ((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)( + InterruptObject, + InterruptObject->ServiceContext, + TrapFrame ); + } + + // + // Invalidate this entry to prevent the next device interrupt + // dispatch from using stale information. We must do this + // before the ACK, which allows the IOD to post. + // + + PostedInterrupts->all = 0; + + // + // Acknowledge the interrupt + // + + IOD_INTERRUPT_ACKNOWLEDGE(McDeviceId, Target); + + } //end if (PostedInterrupts.Valid && PostedInterrupts.IntReq) + + + } //end for + + return TRUE; + +} + +#endif //POSTED + + +VOID +HalpAcknowledgeIpiInterrupt( + VOID + ) +/*++ + +Routine Description: + + Acknowledge the interprocessor interrupt on the current processor. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + PIOD_GENERAL_CSRS IodGeneralCsrs; + IOD_WHOAMI IodWhoAmI; + MC_ENUM_CONTEXT mcCtx; + MC_DEVICE_ID McDeviceId; + volatile IOD_PCI_REVISION IodRevision; + + PKPRCB Prcb; + + + // + // Avoid a WhoAmI register read by using the PCR + // + + Prcb = PCR->Prcb; + McDeviceId.all = HalpLogicalToPhysicalProcessor[Prcb->Number].all; + + // + // Acknownledge the ip interrupt by writing to our own + // ip interrupt acknowledge. + // + + IP_INTERRUPT_ACKNOWLEDGE( McDeviceId ); + + return; + +} diff --git a/private/ntos/nthals/halraw/alpha/rwref.h b/private/ntos/nthals/halraw/alpha/rwref.h new file mode 100644 index 000000000..1b691e0e0 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/rwref.h @@ -0,0 +1,109 @@ +/*++ + +Copyright (c) 1995 Digital Equipment Corporation + +Module Name: + + rwref.h + +Abstract: + + This file defines the structures and definitions of the Rawhide + interrupt architecture. + +Author: + + Matthew Buchman 18 Sept 1995 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#ifndef _RAWREFH_ +#define _RAWREFH_ + +#if !defined(_LANGUAGE_ASSEMBLY) + +// +// Layout of platform usable portion of vector table +// + +enum _RAWHIDE_INTERRUPT_VECTORS { + + // + // 16 Eisa/Isa vectors starting at vector 32. + // + + RawhideEisaVectors = EISA_VECTORS, // Eisa base vector + RawhideIsaVectors = ISA_VECTORS, // Isa base vector + + RawhideMaxEisaVector = MAXIMUM_EISA_VECTOR, // Maximum Eisa/Isa vector + + // + // All buses, except bus 1, have 16 PCI vectors + // PciVector = 16*BusNumber + PinToLine(Slot, Interrupt) + // + + RawhidePciVectors = PCI_VECTORS, + + RawhidePci0Vectors = PCI_VECTORS, // PCI bus 0 + RawhidePci1Vectors = (PCI_VECTORS + 0x10), // PCI bus 1 + RawhidePci2Vectors = (PCI_VECTORS + 0x20), // PCI bus 2 + RawhidePci3Vectors = (PCI_VECTORS + 0x30), // PCI bus 3 + + // One special case for PCI vectors is NCR810 Scsi on bus 1 + // whereas MAXIMUM_PCI_VECTOR is unused on other platforms, + // we use it for this special case. + + RawhideScsiVector = MAXIMUM_PCI_VECTOR, // NCR810 SCSI, bus 1 + + RawhideMaxPciVector = MAXIMUM_PCI_VECTOR, // Max Rawhide PCI vector + + // + // Miscellaneous + // + + + RawhideHardErrVector, // IOD Hard Error + + // + // Internal Bus Vectors + // + + RawhideInternalBusVectors, + + RawhideSoftErrVector = RawhideInternalBusVectors, // IOD Soft Error + + RawhideI2cCtrlVector, // I^2C Controller, bus 0 + RawhideI2cBusVector, // I^2C vector, bus 0 + + RawhideMaxInternalBusVector + +}; + +#define IOD_PCI_VECTORS 0x10 + +// +// Internal Bus interrupt line values +// +// These line values allow device drivers to connect +// to interrupts for the Correctable, I2C Bus, and I2C +// controller interrupts. These interrupts are connected +// via the internal bus for NT 3.51 +// + +enum _RAWHIDE_INTERNAL_BUS_INTERRUPT_LINE { + + RawhideSoftErrInterruptLine, // IOD Soft Error + RawhideI2cCtrlInterruptLine, // I^2C Controller, bus 0 + RawhideI2cBusInterruptLine // I^2C vector, bus 0 + +}; + +#endif // _LANGUAGE_ASSEMBLY + +#endif // _RAWREFH_ diff --git a/private/ntos/nthals/halraw/alpha/rwsysint.c b/private/ntos/nthals/halraw/alpha/rwsysint.c new file mode 100644 index 000000000..f3450c747 --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/rwsysint.c @@ -0,0 +1,501 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + alsysint.c + +Abstract: + + This module implements the HAL enable/disable system interrupt, and + request interprocessor interrupt routines for the Alcor system. + +Author: + + Joe Notarangelo 20-Jul-1994 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" +#include "rawhide.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,HalpGetSystemInterruptVector) +#endif + + +// +// Function prototype +// + +VOID +HalpDisablePciInterrupt( + IN ULONG Vector + ); + +VOID +HalpEnablePciInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ); + +VOID +HalpDisableInternalInterrupt( + IN ULONG Vector + ); + +VOID +HalpEnableInternalInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ); + + +VOID +HalDisableSystemInterrupt ( + IN ULONG Vector, + IN KIRQL Irql + ) + +/*++ + +Routine Description: + + This routine disables the specified system interrupt. + +Arguments: + + Vector - Supplies the vector of the system interrupt that is disabled. + + Irql - Supplies the IRQL of the interrupting source. + +Return Value: + + None. + +--*/ + +{ + + KIRQL OldIrql; + + // + // Raise IRQL to the highest level. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + // + // If the vector number is within the range of the EISA interrupts, then + // disable the EISA interrrupt. + // + + if (Vector >= EISA_VECTORS && + Vector < MAXIMUM_EISA_VECTOR && + Irql == DEVICE_HIGH_LEVEL) { + HalpDisableEisaInterrupt(Vector); + } + + // + // If the vector number is within the range of the PCI interrupts, then + // disable the PCI interrrupt. Remember that, unlike other platforms, + // MAXIMUM_PCI_VECTOR is assigned rather than used as a place holder. + // + + if (Vector >= RawhidePciVectors && + Vector < RawhideMaxPciVector && + Irql == DEVICE_HIGH_LEVEL) { + HalpDisablePciInterrupt(Vector); + } + + // + // If the vector number is within the range of the Intenal bus + // interrupts, then disable the interrupt. + // + + if (Vector >= RawhideInternalBusVectors && + Vector <= RawhideMaxInternalBusVector && + Irql == DEVICE_HIGH_LEVEL ) { + HalpDisableInternalInterrupt(Vector); + } + + // + // If the vector is a performance counter vector we will ignore + // the enable - the performance counters are enabled directly by + // the wrperfmon callpal. Wrperfmon must be controlled directly + // by the driver. + // + + switch (Vector) { + + case PC0_VECTOR: + case PC1_VECTOR: + case PC2_VECTOR: + + break; + + } //end switch Vector + + // + // Lower IRQL to the previous level. + // + + KeLowerIrql(OldIrql); + return; +} + + +BOOLEAN +HalEnableSystemInterrupt ( + IN ULONG Vector, + IN KIRQL Irql, + IN KINTERRUPT_MODE InterruptMode + ) + +/*++ + +Routine Description: + + This routine enables the specified system interrupt. + +Arguments: + + Vector - Supplies the vector of the system interrupt that is enabled. + + Irql - Supplies the IRQL of the interrupting source. + + InterruptMode - Supplies the mode of the interrupt; LevelSensitive or + Latched. + +Return Value: + + TRUE if the system interrupt was enabled + +--*/ + +{ + BOOLEAN Enabled = FALSE; + KIRQL OldIrql; + +#if 0 // ecrfix + DbgPrint( + "HalEnableSystemInterrupt: Vector 0x%x, Irql 0x%x, InterruptMode 0x%x\n", + Vector, + Irql, + InterruptMode + ); +#endif + + // + // Raise IRQL to the highest level. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + // + // If the vector number is within the range of the EISA interrupts, then + // enable the EISA interrrupt and set the Level/Edge register. + // + + if (Vector >= EISA_VECTORS && + Vector < MAXIMUM_EISA_VECTOR && + Irql == DEVICE_HIGH_LEVEL) { + +#if 0 // ecrfix + DbgPrint("HalEnableSystemInterrupt: Eisa Vector\n"); +#endif + HalpEnableEisaInterrupt( Vector, InterruptMode ); + Enabled = TRUE; + } + + // + // If the vector number is within the range of the PCI interrupts, then + // enable the PCI interrrupt. Remember, unlike other platforms, + // MAXIMUM_PCI_VECTOR is assigned rather than used as a place holder. + // + + else if (Vector >= RawhidePciVectors && + Vector <= RawhideMaxPciVector && + Irql == DEVICE_HIGH_LEVEL) { + +#if 0 // ecrfix + DbgPrint("HalEnableSystemInterrupt: Pci Vector\n"); +#endif + HalpEnablePciInterrupt( Vector, InterruptMode ); + Enabled = TRUE; + } + + // + // If the vector number is within the range of the Intenal bus + // interrupts. + // + + if (Vector >= RawhideInternalBusVectors && + Vector < RawhideMaxInternalBusVector && + Irql == DEVICE_HIGH_LEVEL ) { + +#if 0 // ecrfix + DbgPrint("HalEnableSystemInterrupt: Internal Vector\n"); +#endif + HalpEnableInternalInterrupt( Vector, InterruptMode ); + Enabled = TRUE; + } + + // + // If the vector is a performance counter vector we will ignore + // the enable - the performance counters are enabled directly by + // the wrperfmon callpal. Wrperfmon must be controlled directly + // by the driver. + // + + switch (Vector) { + + case PC0_VECTOR: + case PC1_VECTOR: + case PC2_VECTOR: + + Enabled = TRUE; + break; + + } //end switch Vector + + // + // Lower IRQL to the previous level. + // + + KeLowerIrql(OldIrql); +#if 0 // ecrfix + DbgPrint("HalEnableSystemInterrupt: Enabled = %s\n", Enabled?"TRUE":"FALSE"); +#endif + + return Enabled; + +} + + +ULONG +HalpGetSystemInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ) + +/*++ + +Routine Description: + + This function returns the system interrupt vector and IRQL level + corresponding to the specified bus interrupt level and/or vector. The + system interrupt vector and IRQL are suitable for use in a subsequent + call to KeInitializeInterrupt. + + We only use InterfaceType and BusInterruptLevel. BusInterruptVector + for EISA and ISA are the same as the InterruptLevel, so ignore. + +Arguments: + + BusHandler - Supplies a pointer to the bus handler of the bus that + needs a system interrupt vector. + + RootHandler - Supplies a pointer to the bus handler of the root + bus for the bus represented by BusHandler. + + BusInterruptLevel - Supplies the bus-specific interrupt level. + + BusInterruptVector - Supplies the bus-specific interrupt vector. + + Irql - Returns the system request priority. + + Affinity - Returns the affinity for the requested vector + +Return Value: + + Returns the system interrupt vector corresponding to the specified device. + +--*/ + +{ + INTERFACE_TYPE InterfaceType = BusHandler->InterfaceType; + ULONG BusNumber = BusHandler->BusNumber; + ULONG Vector; + +#if HALDBG + DbgPrint("HalpGetSystemInterruptVector: Vector 0x%x\n", BusInterruptVector); +#endif + + // + // Handle the special internal bus defined for the processor itself + // and used to control the performance counters in the 21064. + // + + if( InterfaceType == ProcessorInternal ) { + + Vector = HalpGet21164PerformanceVector( BusInterruptLevel, Irql ); + + if( Vector != 0 ){ + + // + // Success + // + + *Affinity = HalpActiveProcessors; + return Vector; + + } else { + + // + // Unrecognized processor interrupt. + // + + *Irql = 0; + *Affinity = 0; + return 0; + + } + + } + + // + // Rawhide uses the Internal bus to make system management interupts + // visible to device drivers. The devices defined for the internal + // bus for Rawhide are the Correctable Error and the I2C Bus. + // + + if( (InterfaceType == Internal) ) { + + +#if HALDBG + DbgPrint("HalpGetSystemInterruptVector: Internal Vector\n"); +#endif + + return HalpGetRawhideInternalInterruptVector( + BusHandler, + RootHandler, + BusInterruptLevel, + BusInterruptVector, + Irql, + Affinity + ); + + } + + // + // Handle Isa/Eisa bus devices. + // + // N.B. The bus interrupt level is the actual E/ISA signal name for + // option boards while the bus interrupt level is the actual + // interrupt vector number for internal devices. + // + + if( (InterfaceType == Isa) || + (InterfaceType == Eisa) ){ + +#if HALDBG + DbgPrint("HalpGetSystemInterruptVector: Eisa Vector\n"); +#endif + + return HalpGetRawhideEisaInterruptVector( + BusHandler, + RootHandler, + BusInterruptLevel, + BusInterruptVector, + Irql, + Affinity + ); + + } + + if( (InterfaceType == PCIBus) ) { +#if HALDBG + DbgPrint( + "HalpGetSystemInterruptVector: PCIBUS, level 0x%x, vector 0x%x\n", + BusInterruptLevel, + BusInterruptVector + ); +#endif + + return HalpGetRawhidePciInterruptVector( + BusHandler, + RootHandler, + BusInterruptLevel, + BusInterruptVector, + Irql, + Affinity + ); + } + + + // + // Not an interface supported on Alpha systems + // + + *Irql = 0; + *Affinity = 0; + return(0); +} + + +VOID +HalRequestIpi ( + IN ULONG Mask + ) +/*++ + +Routine Description: + + This routine requests an interprocessor interrupt on a set of processors. + +Arguments: + + Mask - Supplies the set of processors that are sent an interprocessor + interrupt. + +Return Value: + + None. + +--*/ + +{ + + MC_DEVICE_ID McDeviceId; + ULONG LogicalCpu; + + // + // Scan the mask for logical CPU numbers + // + + for (LogicalCpu=0; LogicalCpu< (HAL_MAXIMUM_PROCESSOR+1); LogicalCpu++) { + + // + // The Logical to Geographic ID was saved + // in HalStartNextProcessor + // + + if (Mask & 0x1) { + + McDeviceId.all = HalpLogicalToPhysicalProcessor[LogicalCpu].all; + + // + // Send the IP interrupt by writing to the + // IP interrupt for the Device Id. + // + + IP_INTERRUPT_REQUEST( McDeviceId ); + } + + Mask = Mask >> 1; + } + + return; +} diff --git a/private/ntos/nthals/halraw/alpha/vga.c b/private/ntos/nthals/halraw/alpha/vga.c new file mode 100644 index 000000000..764c585af --- /dev/null +++ b/private/ntos/nthals/halraw/alpha/vga.c @@ -0,0 +1,7 @@ +// +// This file simply includes the source file from the common Alpha +// HAL directory. +// + +#include "..\halalpha\vga.c" + diff --git a/private/ntos/nthals/halraw/bushnd.c b/private/ntos/nthals/halraw/bushnd.c new file mode 100644 index 000000000..a1e648dc1 --- /dev/null +++ b/private/ntos/nthals/halraw/bushnd.c @@ -0,0 +1,7 @@ +// +// This file simply includes the common sources from the current HAL +// directory. When the structure is finally changed, the real file should +// be in this directory. +// + +#include "..\bushnd.c" diff --git a/private/ntos/nthals/halraw/dirs b/private/ntos/nthals/halraw/dirs new file mode 100644 index 000000000..a2a38f0fd --- /dev/null +++ b/private/ntos/nthals/halraw/dirs @@ -0,0 +1,24 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dirs. + +Abstract: + + This file specifies the subdirectories of the current directory that + contain component makefiles. + + +Author: + + +NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl + +!ENDIF + +DIRS=up + +OPTIONAL_DIRS=mp diff --git a/private/ntos/nthals/halraw/drivesup.c b/private/ntos/nthals/halraw/drivesup.c new file mode 100644 index 000000000..38259e5f4 --- /dev/null +++ b/private/ntos/nthals/halraw/drivesup.c @@ -0,0 +1,7 @@ +// +// This file simply includes the common sources from the current HAL +// directory. When the structure is finally changed, the real file should +// be in this directory. +// + +#include "..\drivesup.c" diff --git a/private/ntos/nthals/halraw/hal.rc b/private/ntos/nthals/halraw/hal.rc new file mode 100644 index 000000000..3cba4ad89 --- /dev/null +++ b/private/ntos/nthals/halraw/hal.rc @@ -0,0 +1,11 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Hardware Abstraction Layer DLL" +#define VER_INTERNALNAME_STR "hal.dll" + +#include "common.ver" + diff --git a/private/ntos/nthals/halraw/hal.src b/private/ntos/nthals/halraw/hal.src new file mode 100644 index 000000000..da778bb9d --- /dev/null +++ b/private/ntos/nthals/halraw/hal.src @@ -0,0 +1,7 @@ +// +// This file simply includes the common sources from the current HAL +// directory. When the structure is finally changed, the real file should +// be in this directory. +// + +#include "..\hal.src" diff --git a/private/ntos/nthals/halraw/mp/makefile b/private/ntos/nthals/halraw/mp/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/nthals/halraw/mp/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/ntos/nthals/halraw/mp/makefile.inc b/private/ntos/nthals/halraw/mp/makefile.inc new file mode 100644 index 000000000..a434415d9 --- /dev/null +++ b/private/ntos/nthals/halraw/mp/makefile.inc @@ -0,0 +1,5 @@ +obj\alpha\hal.def: ..\..\hal.src + rcpp -P -f ..\..\hal.src -DALPHA=1 $(C_DEFINES) -g obj\alpha\hal.def + +$(TARGETPATH)\alpha\hal.lib: $(TARGETPATH)\alpha\halrawmp.lib + copy $** $@ diff --git a/private/ntos/nthals/halraw/mp/sources b/private/ntos/nthals/halraw/mp/sources new file mode 100644 index 000000000..18f050720 --- /dev/null +++ b/private/ntos/nthals/halraw/mp/sources @@ -0,0 +1,109 @@ +!IF 0 + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + David N. Cutler (davec) 12-Apr-1993 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=ntos +MINORCOMP=hal + +TARGETNAME=halrawmp +TARGETPATH=$(BASEDIR)\public\sdk\lib + +ALPHA_WARNING_LEVEL=-W3 -WX +C_DEFINES=-DEV5 -DAXPRAW -DEISA_PLATFORM -DTAGGED_NVRAM -DPOSTED + +NT_UP=0 + +!IF $(ALPHA) + +TARGETTYPE=HAL + +!ELSE + +TARGETTYPE=DRIVER + +!ENDIF + +INCLUDES=..\alpha;..\..\..\inc;..\..\..\ke;..\..\..\io;..\..\..\fw\alpha;..\..\..\fastfat;..\..\halalpha;..\..\halraw\alpha + +SOURCES= + +ALPHA_SOURCES=..\hal.rc \ + ..\alpha\bushnd.c \ + ..\drivesup.c \ + ..\alpha\adjust.c \ + ..\alpha\allstart.c \ + ..\alpha\bios.c \ + ..\alpha\bitmap.c \ + ..\alpha\cache.c \ + ..\alpha\devintr.s \ + ..\alpha\ebsgdma.c \ + ..\alpha\eeprom8k.c \ + ..\alpha\eisasup.c \ + ..\alpha\ev5cache.c \ + ..\alpha\ev5int.c \ + ..\alpha\ev5mchk.c \ + ..\alpha\ev5mem.s \ + ..\alpha\ev5prof.c \ + ..\alpha\ev5ints.s \ + ..\alpha\fwreturn.c \ + ..\alpha\haldebug.c \ + ..\alpha\halpal.s \ + ..\alpha\haltsup.s \ + ..\alpha\idle.s \ + ..\alpha\info.c \ + ..\alpha\inithal.c \ + ..\alpha\intsup.s \ + ..\alpha\iousage.c \ + ..\alpha\ioproc.c \ + ..\alpha\memory.c \ + ..\alpha\nvenv.c \ + ..\alpha\nvram.c \ + ..\alpha\pciesc.c \ + ..\alpha\pcisup.c \ + ..\alpha\pcrtc.c \ + ..\alpha\pcserial.c \ + ..\alpha\pcspeakr.c \ + ..\alpha\perf8254.c \ + ..\alpha\vga.c \ + ..\alpha\busdata.c \ + ..\alpha\pcibus.c \ + ..\alpha\iod.c \ + ..\alpha\iodaddr.c \ + ..\alpha\ioderr.c \ + ..\alpha\iodio.s \ + ..\alpha\iodmapio.c \ + ..\alpha\rawerr.c \ + ..\alpha\rwclock.c \ + ..\alpha\rwinitnt.c \ + ..\alpha\rwintbal.c \ + ..\alpha\rwintsup.c \ + ..\alpha\rwsysint.c + +DLLDEF=obj\*\hal.def + +!IF $(ALPHA) + +NTTARGETFILES=$(TARGETPATH)\alpha\hal.lib \ + $(TARGETPATH)\alpha\hal.dll + +!ENDIF diff --git a/private/ntos/nthals/halraw/up/makefile b/private/ntos/nthals/halraw/up/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/nthals/halraw/up/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/ntos/nthals/halraw/up/makefile.inc b/private/ntos/nthals/halraw/up/makefile.inc new file mode 100644 index 000000000..e06ce5247 --- /dev/null +++ b/private/ntos/nthals/halraw/up/makefile.inc @@ -0,0 +1,5 @@ +obj\alpha\hal.def: ..\..\hal.src + rcpp -P -f ..\..\hal.src -DALPHA=1 $(C_DEFINES) -g obj\alpha\hal.def + +$(TARGETPATH)\alpha\hal.lib: $(TARGETPATH)\alpha\halrawup.lib + copy $** $@ diff --git a/private/ntos/nthals/halraw/up/sources b/private/ntos/nthals/halraw/up/sources new file mode 100644 index 000000000..0caeb41eb --- /dev/null +++ b/private/ntos/nthals/halraw/up/sources @@ -0,0 +1,109 @@ +!IF 0 + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + David N. Cutler (davec) 12-Apr-1993 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=ntos +MINORCOMP=hal + +TARGETNAME=halrawup +TARGETPATH=$(BASEDIR)\public\sdk\lib + +ALPHA_WARNING_LEVEL=-W3 -WX +C_DEFINES=-DEV5 -DAXPRAW -DEISA_PLATFORM -DTAGGED_NVRAM -DPOSTED + +NT_UP=1 + +!IF $(ALPHA) + +TARGETTYPE=HAL + +!ELSE + +TARGETTYPE=DRIVER + +!ENDIF + +INCLUDES=..\alpha;..\..\..\inc;..\..\..\ke;..\..\..\io;..\..\..\fw\alpha;..\..\..\fastfat;..\..\halalpha;..\..\halraw\alpha + +SOURCES= + +ALPHA_SOURCES=..\hal.rc \ + ..\alpha\bushnd.c \ + ..\drivesup.c \ + ..\alpha\adjust.c \ + ..\alpha\allstart.c \ + ..\alpha\bios.c \ + ..\alpha\bitmap.c \ + ..\alpha\cache.c \ + ..\alpha\devintr.s \ + ..\alpha\ebsgdma.c \ + ..\alpha\eeprom8k.c \ + ..\alpha\eisasup.c \ + ..\alpha\ev5cache.c \ + ..\alpha\ev5int.c \ + ..\alpha\ev5mchk.c \ + ..\alpha\ev5mem.s \ + ..\alpha\ev5prof.c \ + ..\alpha\ev5ints.s \ + ..\alpha\fwreturn.c \ + ..\alpha\haldebug.c \ + ..\alpha\halpal.s \ + ..\alpha\haltsup.s \ + ..\alpha\idle.s \ + ..\alpha\info.c \ + ..\alpha\inithal.c \ + ..\alpha\intsup.s \ + ..\alpha\iousage.c \ + ..\alpha\ioproc.c \ + ..\alpha\memory.c \ + ..\alpha\nvenv.c \ + ..\alpha\nvram.c \ + ..\alpha\pciesc.c \ + ..\alpha\pcisup.c \ + ..\alpha\pcrtc.c \ + ..\alpha\pcserial.c \ + ..\alpha\pcspeakr.c \ + ..\alpha\perf8254.c \ + ..\alpha\vga.c \ + ..\alpha\busdata.c \ + ..\alpha\pcibus.c \ + ..\alpha\iod.c \ + ..\alpha\iodaddr.c \ + ..\alpha\ioderr.c \ + ..\alpha\iodio.s \ + ..\alpha\iodmapio.c \ + ..\alpha\rawerr.c \ + ..\alpha\rwclock.c \ + ..\alpha\rwinitnt.c \ + ..\alpha\rwintbal.c \ + ..\alpha\rwintsup.c \ + ..\alpha\rwsysint.c + +DLLDEF=obj\*\hal.def + +!IF $(ALPHA) + +NTTARGETFILES=$(TARGETPATH)\alpha\hal.lib \ + $(TARGETPATH)\alpha\hal.dll + +!ENDIF |