From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/nthals/halalpha/28f008sa.c | 317 ++++ private/ntos/nthals/halalpha/29f040.c | 420 +++++ private/ntos/nthals/halalpha/adjust.c | 149 ++ private/ntos/nthals/halalpha/allstart.c | 55 + private/ntos/nthals/halalpha/alphaio.s | 1368 +++++++++++++++ private/ntos/nthals/halalpha/am29f400.c | 543 ++++++ private/ntos/nthals/halalpha/am29f400.h | 97 ++ private/ntos/nthals/halalpha/apecs.c | 337 ++++ private/ntos/nthals/halalpha/apecs.h | 647 +++++++ private/ntos/nthals/halalpha/apecserr.c | 1542 +++++++++++++++++ private/ntos/nthals/halalpha/apecsio.s | 701 ++++++++ private/ntos/nthals/halalpha/axintsup.c | 763 +++++++++ private/ntos/nthals/halalpha/bios.c | 105 ++ private/ntos/nthals/halalpha/cache.c | 225 +++ private/ntos/nthals/halalpha/cia.c | 769 +++++++++ private/ntos/nthals/halalpha/cia.h | 1141 +++++++++++++ private/ntos/nthals/halalpha/ciaaddr.c | 567 +++++++ private/ntos/nthals/halalpha/ciaerr.c | 1642 ++++++++++++++++++ private/ntos/nthals/halalpha/ciaio.s | 2820 +++++++++++++++++++++++++++++++ private/ntos/nthals/halalpha/ciamapio.c | 154 ++ private/ntos/nthals/halalpha/cmos8k.c | 246 +++ private/ntos/nthals/halalpha/cmos8k.h | 32 + private/ntos/nthals/halalpha/devintr.s | 71 + private/ntos/nthals/halalpha/ebsgdma.c | 2307 +++++++++++++++++++++++++ private/ntos/nthals/halalpha/ebsgdma.h | 180 ++ private/ntos/nthals/halalpha/eeprom8k.c | 391 +++++ private/ntos/nthals/halalpha/eisaprof.c | 517 ++++++ private/ntos/nthals/halalpha/eisasup.c | 1477 ++++++++++++++++ private/ntos/nthals/halalpha/environ.c | 952 +++++++++++ private/ntos/nthals/halalpha/environ.h | 167 ++ private/ntos/nthals/halalpha/errframe.h | 697 ++++++++ private/ntos/nthals/halalpha/errplat.h | 774 +++++++++ private/ntos/nthals/halalpha/ev4cache.c | 488 ++++++ private/ntos/nthals/halalpha/ev4int.c | 1013 +++++++++++ private/ntos/nthals/halalpha/ev4ints.s | 272 +++ private/ntos/nthals/halalpha/ev4mchk.c | 709 ++++++++ private/ntos/nthals/halalpha/ev4mem.s | 146 ++ private/ntos/nthals/halalpha/ev4parit.c | 336 ++++ private/ntos/nthals/halalpha/ev4prof.c | 591 +++++++ private/ntos/nthals/halalpha/ev5cache.c | 475 ++++++ private/ntos/nthals/halalpha/ev5int.c | 440 +++++ private/ntos/nthals/halalpha/ev5ints.s | 397 +++++ private/ntos/nthals/halalpha/ev5mchk.c | 677 ++++++++ private/ntos/nthals/halalpha/ev5mem.s | 231 +++ private/ntos/nthals/halalpha/ev5prof.c | 741 ++++++++ private/ntos/nthals/halalpha/flash8k.c | 323 ++++ private/ntos/nthals/halalpha/flash8k.h | 130 ++ private/ntos/nthals/halalpha/flashdrv.c | 23 + private/ntos/nthals/halalpha/fwreturn.c | 255 +++ private/ntos/nthals/halalpha/gru.h | 84 + private/ntos/nthals/halalpha/haldebug.c | 58 + private/ntos/nthals/halalpha/haldump.c | 83 + private/ntos/nthals/halalpha/halisa.h | 89 + private/ntos/nthals/halalpha/halp.h | 1095 ++++++++++++ private/ntos/nthals/halalpha/halpal.s | 276 +++ private/ntos/nthals/halalpha/halpcsl.h | 187 ++ private/ntos/nthals/halalpha/halprof.c | 179 ++ private/ntos/nthals/halalpha/halprof.h | 77 + private/ntos/nthals/halalpha/haltsup.s | 110 ++ private/ntos/nthals/halalpha/halvfont.h | 233 +++ private/ntos/nthals/halalpha/halvga.h | 72 + private/ntos/nthals/halalpha/idle.s | 62 + private/ntos/nthals/halalpha/info.c | 180 ++ private/ntos/nthals/halalpha/inithal.c | 1052 ++++++++++++ private/ntos/nthals/halalpha/intsup.s | 256 +++ private/ntos/nthals/halalpha/ioproc.c | 104 ++ private/ntos/nthals/halalpha/iousage.c | 527 ++++++ private/ntos/nthals/halalpha/iousage.h | 85 + private/ntos/nthals/halalpha/isaaddr.h | 75 + private/ntos/nthals/halalpha/lca4.c | 657 +++++++ private/ntos/nthals/halalpha/lca4.h | 669 ++++++++ private/ntos/nthals/halalpha/lca4err.c | 1153 +++++++++++++ private/ntos/nthals/halalpha/lcaioacc.s | 746 ++++++++ private/ntos/nthals/halalpha/memory.c | 575 +++++++ private/ntos/nthals/halalpha/nvenv.c | 533 ++++++ private/ntos/nthals/halalpha/nvram.c | 1452 ++++++++++++++++ private/ntos/nthals/halalpha/nvram.h | 215 +++ private/ntos/nthals/halalpha/pciesc.c | 477 ++++++ private/ntos/nthals/halalpha/pcip.h | 178 ++ private/ntos/nthals/halalpha/pcisio.c | 483 ++++++ private/ntos/nthals/halalpha/pcisup.c | 2453 +++++++++++++++++++++++++++ private/ntos/nthals/halalpha/pcrtc.c | 381 +++++ private/ntos/nthals/halalpha/pcrtc.h | 166 ++ private/ntos/nthals/halalpha/pcserial.c | 596 +++++++ private/ntos/nthals/halalpha/pcspeakr.c | 136 ++ private/ntos/nthals/halalpha/perf8254.c | 457 +++++ private/ntos/nthals/halalpha/perfcntr.c | 260 +++ private/ntos/nthals/halalpha/t2.c | 760 +++++++++ private/ntos/nthals/halalpha/t2.h | 550 ++++++ private/ntos/nthals/halalpha/vga.c | 608 +++++++ 90 files changed, 47809 insertions(+) create mode 100644 private/ntos/nthals/halalpha/28f008sa.c create mode 100644 private/ntos/nthals/halalpha/29f040.c create mode 100644 private/ntos/nthals/halalpha/adjust.c create mode 100644 private/ntos/nthals/halalpha/allstart.c create mode 100644 private/ntos/nthals/halalpha/alphaio.s create mode 100644 private/ntos/nthals/halalpha/am29f400.c create mode 100644 private/ntos/nthals/halalpha/am29f400.h create mode 100644 private/ntos/nthals/halalpha/apecs.c create mode 100644 private/ntos/nthals/halalpha/apecs.h create mode 100644 private/ntos/nthals/halalpha/apecserr.c create mode 100644 private/ntos/nthals/halalpha/apecsio.s create mode 100644 private/ntos/nthals/halalpha/axintsup.c create mode 100644 private/ntos/nthals/halalpha/bios.c create mode 100644 private/ntos/nthals/halalpha/cache.c create mode 100644 private/ntos/nthals/halalpha/cia.c create mode 100644 private/ntos/nthals/halalpha/cia.h create mode 100644 private/ntos/nthals/halalpha/ciaaddr.c create mode 100644 private/ntos/nthals/halalpha/ciaerr.c create mode 100644 private/ntos/nthals/halalpha/ciaio.s create mode 100644 private/ntos/nthals/halalpha/ciamapio.c create mode 100644 private/ntos/nthals/halalpha/cmos8k.c create mode 100644 private/ntos/nthals/halalpha/cmos8k.h create mode 100644 private/ntos/nthals/halalpha/devintr.s create mode 100644 private/ntos/nthals/halalpha/ebsgdma.c create mode 100644 private/ntos/nthals/halalpha/ebsgdma.h create mode 100644 private/ntos/nthals/halalpha/eeprom8k.c create mode 100644 private/ntos/nthals/halalpha/eisaprof.c create mode 100644 private/ntos/nthals/halalpha/eisasup.c create mode 100644 private/ntos/nthals/halalpha/environ.c create mode 100644 private/ntos/nthals/halalpha/environ.h create mode 100644 private/ntos/nthals/halalpha/errframe.h create mode 100644 private/ntos/nthals/halalpha/errplat.h create mode 100644 private/ntos/nthals/halalpha/ev4cache.c create mode 100644 private/ntos/nthals/halalpha/ev4int.c create mode 100644 private/ntos/nthals/halalpha/ev4ints.s create mode 100644 private/ntos/nthals/halalpha/ev4mchk.c create mode 100644 private/ntos/nthals/halalpha/ev4mem.s create mode 100644 private/ntos/nthals/halalpha/ev4parit.c create mode 100644 private/ntos/nthals/halalpha/ev4prof.c create mode 100644 private/ntos/nthals/halalpha/ev5cache.c create mode 100644 private/ntos/nthals/halalpha/ev5int.c create mode 100644 private/ntos/nthals/halalpha/ev5ints.s create mode 100644 private/ntos/nthals/halalpha/ev5mchk.c create mode 100644 private/ntos/nthals/halalpha/ev5mem.s create mode 100644 private/ntos/nthals/halalpha/ev5prof.c create mode 100644 private/ntos/nthals/halalpha/flash8k.c create mode 100644 private/ntos/nthals/halalpha/flash8k.h create mode 100644 private/ntos/nthals/halalpha/flashdrv.c create mode 100644 private/ntos/nthals/halalpha/fwreturn.c create mode 100644 private/ntos/nthals/halalpha/gru.h create mode 100644 private/ntos/nthals/halalpha/haldebug.c create mode 100644 private/ntos/nthals/halalpha/haldump.c create mode 100644 private/ntos/nthals/halalpha/halisa.h create mode 100644 private/ntos/nthals/halalpha/halp.h create mode 100644 private/ntos/nthals/halalpha/halpal.s create mode 100644 private/ntos/nthals/halalpha/halpcsl.h create mode 100644 private/ntos/nthals/halalpha/halprof.c create mode 100644 private/ntos/nthals/halalpha/halprof.h create mode 100644 private/ntos/nthals/halalpha/haltsup.s create mode 100644 private/ntos/nthals/halalpha/halvfont.h create mode 100644 private/ntos/nthals/halalpha/halvga.h create mode 100644 private/ntos/nthals/halalpha/idle.s create mode 100644 private/ntos/nthals/halalpha/info.c create mode 100644 private/ntos/nthals/halalpha/inithal.c create mode 100644 private/ntos/nthals/halalpha/intsup.s create mode 100644 private/ntos/nthals/halalpha/ioproc.c create mode 100644 private/ntos/nthals/halalpha/iousage.c create mode 100644 private/ntos/nthals/halalpha/iousage.h create mode 100644 private/ntos/nthals/halalpha/isaaddr.h create mode 100644 private/ntos/nthals/halalpha/lca4.c create mode 100644 private/ntos/nthals/halalpha/lca4.h create mode 100644 private/ntos/nthals/halalpha/lca4err.c create mode 100644 private/ntos/nthals/halalpha/lcaioacc.s create mode 100644 private/ntos/nthals/halalpha/memory.c create mode 100644 private/ntos/nthals/halalpha/nvenv.c create mode 100644 private/ntos/nthals/halalpha/nvram.c create mode 100644 private/ntos/nthals/halalpha/nvram.h create mode 100644 private/ntos/nthals/halalpha/pciesc.c create mode 100644 private/ntos/nthals/halalpha/pcip.h create mode 100644 private/ntos/nthals/halalpha/pcisio.c create mode 100644 private/ntos/nthals/halalpha/pcisup.c create mode 100644 private/ntos/nthals/halalpha/pcrtc.c create mode 100644 private/ntos/nthals/halalpha/pcrtc.h create mode 100644 private/ntos/nthals/halalpha/pcserial.c create mode 100644 private/ntos/nthals/halalpha/pcspeakr.c create mode 100644 private/ntos/nthals/halalpha/perf8254.c create mode 100644 private/ntos/nthals/halalpha/perfcntr.c create mode 100644 private/ntos/nthals/halalpha/t2.c create mode 100644 private/ntos/nthals/halalpha/t2.h create mode 100644 private/ntos/nthals/halalpha/vga.c (limited to 'private/ntos/nthals/halalpha') diff --git a/private/ntos/nthals/halalpha/28f008sa.c b/private/ntos/nthals/halalpha/28f008sa.c new file mode 100644 index 000000000..487a908d8 --- /dev/null +++ b/private/ntos/nthals/halalpha/28f008sa.c @@ -0,0 +1,317 @@ +#include "halp.h" +#include "arccodes.h" +#include "flash8k.h" + +#define I28F008SA_DEVICE_SIZE 0x100000 + +#define SET_READ_ARRAY 0xff +#define SET_BYTE_WRITE 0x40 +#define SET_ERASE_BLOCK 0x20 +#define CONFIRM_ERASE_BLOCK 0xd0 +#define READ_STATUS 0x70 +#define RESET_STATUS 0x50 +#define ID_REQUEST 0x90 + +#define MANUFACTURER_ID 0x89 +#define DEVICE_ID 0xa2 + +#define BLOCK_SIZE 0x10000 +#define BLANK_DATA 0xff + +#define TIMEOUT_VALUE 5000000 + +#define STATUS_READY 0x80 +#define STATUS_ERASE_SUSP 0x40 +#define STATUS_ERASE_ERR 0x20 +#define STATUS_WRITE_ERR 0x10 +#define STATUS_VPP_LOW 0x08 +#define STATUS_CMD_SEQ_ERR (STATUS_WRITE_ERR | STATUS_READ_ERR) + +// +// Local function prototypes +// +PFLASH_DRIVER +I28F008SA_Initialize( + IN PUCHAR NvRamPtr + ); + +ARC_STATUS +I28F008SA_SetReadMode( + IN PUCHAR Address + ); + +ARC_STATUS +I28F008SA_WriteByte( + IN PUCHAR Address, + IN UCHAR Data + ); + +ARC_STATUS +I28F008SA_EraseBlock( + IN PUCHAR Address + ); + +ARC_STATUS +I28F008SA_CheckStatus( + IN PUCHAR Address, + FLASH_OPERATIONS Operation + ); + +PUCHAR +I28F008SA_BlockAlign( + IN PUCHAR Address + ); + +UCHAR +I28F008SA_ReadByte( + IN PUCHAR Address + ); + +BOOLEAN +I28F008SA_OverwriteCheck( + IN UCHAR OldData, + IN UCHAR NewData + ); + +ULONG +I28F008SA_BlockSize( + IN PUCHAR Address + ); + +ULONG +I28F008SA_GetLastError( + VOID + ); + +static +VOID +I28F008SA_SetLastError( + ULONG FlashStatus + ); + +FLASH_DRIVER I28F008SA_DriverInformation = { + "Intel 28F008SA", + I28F008SA_SetReadMode, // SetReadModeFunction + I28F008SA_WriteByte, // WriteByteFunction + I28F008SA_EraseBlock, // EraseBlockFunction + I28F008SA_BlockAlign, // AlignBlockFunction + I28F008SA_ReadByte, // ReadByteFunction + I28F008SA_OverwriteCheck, // OverwriteCheckFunction + I28F008SA_BlockSize, // BlockSizeFunction + I28F008SA_GetLastError, // GetLastErrorFunction + I28F008SA_DEVICE_SIZE, // DeviceSize + BLANK_DATA // ErasedData + }; + +static ULONG I28F008SA_LastError; + +PFLASH_DRIVER +I28F008SA_Initialize( + IN PUCHAR NvRamPtr + ) +{ + PFLASH_DRIVER ReturnDriver = NULL; + UCHAR ManufacturerID; + UCHAR DeviceID; + + NvRamPtr = I28F008SA_BlockAlign(NvRamPtr); + + WRITE_CONFIG_RAM_DATA(NvRamPtr, ID_REQUEST); + + ManufacturerID = READ_CONFIG_RAM_DATA(NvRamPtr); + DeviceID = READ_CONFIG_RAM_DATA((PUCHAR)((ULONG)NvRamPtr + 1)); + + if ((ManufacturerID == MANUFACTURER_ID) && (DeviceID == DEVICE_ID)) { + I28F008SA_LastError = 0; + I28F008SA_SetReadMode(NvRamPtr); + ReturnDriver = &I28F008SA_DriverInformation; + } + + return ReturnDriver; +} + +ARC_STATUS +I28F008SA_SetReadMode( + IN PUCHAR NvRamPtr + ) +{ + WRITE_CONFIG_RAM_DATA(NvRamPtr, SET_READ_ARRAY); + HalpMb(); + + return ESUCCESS; +} + +ARC_STATUS +I28F008SA_WriteByte( + IN PUCHAR NvRamPtr, + IN UCHAR Data + ) +{ + ARC_STATUS ReturnStatus; + + I28F008SA_SetReadMode(NvRamPtr); + + WRITE_CONFIG_RAM_DATA(NvRamPtr, SET_BYTE_WRITE); + WRITE_CONFIG_RAM_DATA(NvRamPtr, Data); + + ReturnStatus = I28F008SA_CheckStatus(NvRamPtr, FlashByteWrite); + + I28F008SA_SetReadMode(NvRamPtr); + + return ReturnStatus; +} + +ARC_STATUS +I28F008SA_EraseBlock ( + IN PUCHAR NvRamPtr + ) +{ + ARC_STATUS ReturnStatus; + + WRITE_CONFIG_RAM_DATA(NvRamPtr, SET_ERASE_BLOCK); + WRITE_CONFIG_RAM_DATA(NvRamPtr, CONFIRM_ERASE_BLOCK); + + ReturnStatus = I28F008SA_CheckStatus(NvRamPtr, FlashEraseBlock); + + I28F008SA_SetReadMode(NvRamPtr); + + return ReturnStatus; +} + +ARC_STATUS +I28F008SA_CheckStatus ( + IN PUCHAR NvRamPtr, + IN FLASH_OPERATIONS Operation + ) +{ + ARC_STATUS ReturnStatus = EIO; + ULONG Timeout; + UCHAR FlashStatus; + + // + // Keep reading the status until the device is done with its + // current operation. + // + Timeout = TIMEOUT_VALUE; + do { + WRITE_CONFIG_RAM_DATA(NvRamPtr, READ_STATUS); + FlashStatus = READ_CONFIG_RAM_DATA(NvRamPtr); + KeStallExecutionProcessor(1); + Timeout--; + } while (((FlashStatus & 0x80) == 0) && (Timeout > 0)); + + // + // Check the status for the operation requested. + // + switch(Operation) { + case FlashByteWrite: + if ((FlashStatus & 0x18) == 0) { + ReturnStatus = ESUCCESS; + } else { + I28F008SA_SetLastError(FlashStatus & 0x18); + } + break; + case FlashEraseBlock: + if (((FlashStatus & 0x28) == 0) && ((FlashStatus & 0x30) != 0x30)) { + ReturnStatus = ESUCCESS; + } else { + I28F008SA_SetLastError(FlashStatus & 0x28); + } + break; + } + if ((FlashStatus & 0x80) == 0) { + ReturnStatus = EIO; + I28F008SA_SetLastError(0); + } + + // + // Clear the flash status register + // This is a silent operation. The status that gets returned is the + // status of the real operation as determined above. + // + WRITE_CONFIG_RAM_DATA(NvRamPtr, RESET_STATUS); + Timeout = TIMEOUT_VALUE; + do { + WRITE_CONFIG_RAM_DATA(NvRamPtr, READ_STATUS); + FlashStatus = READ_CONFIG_RAM_DATA(NvRamPtr); + KeStallExecutionProcessor(1); + Timeout--; + } while (((FlashStatus & 0x80) == 0) && (Timeout > 0)); + + return ReturnStatus; +} + +PUCHAR +I28F008SA_BlockAlign( + IN PUCHAR Address + ) +{ + return (PUCHAR)((ULONG)Address & ~(BLOCK_SIZE-1)); +} + +UCHAR +I28F008SA_ReadByte( + IN PUCHAR Address + ) +{ + return READ_CONFIG_RAM_DATA(Address); +} + +BOOLEAN +I28F008SA_OverwriteCheck( + IN UCHAR OldData, + IN UCHAR NewData + ) +/*++ + +Return Value: + + Zero if OldData can be overwritten with NewData. + Non-zero if device must be erased to write NewData. + +--*/ +{ + return (~OldData & NewData) ? FALSE : TRUE; +} + +ULONG +I28F008SA_BlockSize( + IN PUCHAR Address + ) +/*++ + +Return Value: + + The block size of the device. This is a constant because all + blocks in the 28f008sa are the same size. + +--*/ +{ + return BLOCK_SIZE; +} + +ULONG +I28F008SA_GetLastError( + VOID + ) +{ + return I28F008SA_LastError; +} + +static +VOID +I28F008SA_SetLastError( + ULONG FlashStatus + ) +{ + I28F008SA_LastError = ERROR_UNKNOWN; + if (FlashStatus == 0) + I28F008SA_LastError = ERROR_TIMEOUT; + if (FlashStatus & STATUS_WRITE_ERR) + I28F008SA_LastError = ERROR_WRITE_ERROR; + if (FlashStatus & STATUS_ERASE_ERR) + I28F008SA_LastError = ERROR_ERASE_ERROR; + if (FlashStatus & STATUS_VPP_LOW) + I28F008SA_LastError = ERROR_VPP_LOW; +} + diff --git a/private/ntos/nthals/halalpha/29f040.c b/private/ntos/nthals/halalpha/29f040.c new file mode 100644 index 000000000..331b32584 --- /dev/null +++ b/private/ntos/nthals/halalpha/29f040.c @@ -0,0 +1,420 @@ +/*++ + +File: 29f040.c + +Purpose: Firmware/HAL driver for AMD Am29F040 512kB flash device. + +--*/ + +#include "halp.h" +#include "arccodes.h" +#include "flash8k.h" + +#define Am29F040_DEVICE_SIZE 0x80000 +#define Am29F080_DEVICE_SIZE 0x100000 + +#define Am29F040_DEVICE_NAME "AMD Am29F040" +#define Am29F080_DEVICE_NAME "AMD Am29F080" + +#define COMMAND_OFFSET 0x5555 + +#define COMMAND_PREFIX_OFFSET1 (COMMAND_OFFSET) +#define COMMAND_PREFIX_COMMAND1 0xaa + +#define COMMAND_PREFIX_OFFSET2 0x2aaa +#define COMMAND_PREFIX_COMMAND2 0x55 + +#define SET_READ_ARRAY 0xf0 // write to COMMAND_ADDRESS +#define SET_BYTE_WRITE 0xa0 // write to COMMAND_ADDRESS +#define SET_ERASE 0x80 // write to COMMAND_ADDRESS +#define CONFIRM_ERASE_BLOCK 0x30 // write to the base address of the block +#define ID_REQUEST 0x90 // write to COMMAND_ADDRESS + +#define MANUFACTURER_ID 0x01 +#define Am29F040_DEVICE_ID 0xa4 +#define Am29F080_DEVICE_ID 0xd5 + +#define BLOCK_SIZE 0x10000 +#define BLANK_DATA 0xff + +#define TIMEOUT_VALUE 5000000 + +#define COMMAND_PREFIX(address) { \ + PUCHAR PrefixAddress1; \ + PUCHAR PrefixAddress2; \ + PrefixAddress1 = PrefixAddress2 = Am29F040_BlockAlign(address); \ + PrefixAddress1 = (PUCHAR)((ULONG)PrefixAddress1 + COMMAND_PREFIX_OFFSET1); \ + PrefixAddress2 = (PUCHAR)((ULONG)PrefixAddress2 + COMMAND_PREFIX_OFFSET2); \ + WRITE_CONFIG_RAM_DATA(PrefixAddress1, COMMAND_PREFIX_COMMAND1); \ + HalpMb(); \ + WRITE_CONFIG_RAM_DATA(PrefixAddress2, COMMAND_PREFIX_COMMAND2); \ + HalpMb(); \ + } + +#define COMMAND_ADDRESS(address) \ + ((PUCHAR)(((ULONG)(BLOCK_ALIGN(address)) + (COMMAND_OFFSET)))) + +#define BLOCK_ALIGN(address) \ + ((PUCHAR)((ULONG)(address) & ~(BLOCK_SIZE-1))) + +// +// Local function prototypes +// +PFLASH_DRIVER +Am29F040_Initialize( + IN PUCHAR NvRamPtr + ); + +ARC_STATUS +Am29F040_SetReadMode( + IN PUCHAR Address + ); + +ARC_STATUS +Am29F040_WriteByte( + IN PUCHAR Address, + IN UCHAR Data + ); + +ARC_STATUS +Am29F040_EraseBlock( + IN PUCHAR Address + ); + +ARC_STATUS +Am29F040_CheckStatus( + IN PUCHAR Address, + IN UCHAR Data, + IN FLASH_OPERATIONS Operation + ); + +PUCHAR +Am29F040_BlockAlign( + IN PUCHAR Address + ); + +UCHAR +Am29F040_ReadByte( + IN PUCHAR Address + ); + +BOOLEAN +Am29F040_OverwriteCheck( + IN UCHAR OldData, + IN UCHAR NewData + ); + +ULONG +Am29F040_BlockSize( + IN PUCHAR Address + ); + +ULONG +Am29F040_GetLastError( + VOID + ); + +static +VOID +Am29F040_SetLastError( + ULONG FlashStatus + ); + +FLASH_DRIVER Am29F040_DriverInformation = { + Am29F040_DEVICE_NAME, + Am29F040_SetReadMode, // SetReadModeFunction + Am29F040_WriteByte, // WriteByteFunction + Am29F040_EraseBlock, // EraseBlockFunction + Am29F040_BlockAlign, // AlignBlockFunction + Am29F040_ReadByte, // ReadByteFunction + Am29F040_OverwriteCheck, // OverwriteCheckFunction + Am29F040_BlockSize, // BlockSizeFunction + Am29F040_GetLastError, // GetLastErrorFunction + Am29F040_DEVICE_SIZE, // DeviceSize + BLANK_DATA // ErasedData + }; + +FLASH_DRIVER Am29F080_DriverInformation = { + Am29F080_DEVICE_NAME, + Am29F040_SetReadMode, // SetReadModeFunction + Am29F040_WriteByte, // WriteByteFunction + Am29F040_EraseBlock, // EraseBlockFunction + Am29F040_BlockAlign, // AlignBlockFunction + Am29F040_ReadByte, // ReadByteFunction + Am29F040_OverwriteCheck, // OverwriteCheckFunction + Am29F040_BlockSize, // BlockSizeFunction + Am29F040_GetLastError, // GetLastErrorFunction + Am29F080_DEVICE_SIZE, // DeviceSize + BLANK_DATA // ErasedData + }; + + +static ULONG Am29F040_LastError; + +PFLASH_DRIVER +Am29F040_Initialize( + IN PUCHAR NvRamPtr + ) +{ + PFLASH_DRIVER ReturnDriver = NULL; + UCHAR ManufacturerID; + UCHAR DeviceID; + + NvRamPtr = Am29F040_BlockAlign(NvRamPtr); + + COMMAND_PREFIX(NvRamPtr); + WRITE_CONFIG_RAM_DATA(COMMAND_ADDRESS(NvRamPtr), ID_REQUEST); + + ManufacturerID = READ_CONFIG_RAM_DATA(NvRamPtr); + DeviceID = READ_CONFIG_RAM_DATA((PUCHAR)((ULONG)NvRamPtr + 1)); + + if ((ManufacturerID == MANUFACTURER_ID) && + (DeviceID == Am29F040_DEVICE_ID)) { + + Am29F040_LastError = 0; + Am29F040_SetReadMode(NvRamPtr); + ReturnDriver = &Am29F040_DriverInformation; + } + + return ReturnDriver; +} + +PFLASH_DRIVER +Am29F080_Initialize( + IN PUCHAR NvRamPtr + ) +{ + PFLASH_DRIVER ReturnDriver = NULL; + UCHAR ManufacturerID; + UCHAR DeviceID; + + NvRamPtr = Am29F040_BlockAlign(NvRamPtr); + + COMMAND_PREFIX(NvRamPtr); + WRITE_CONFIG_RAM_DATA(COMMAND_ADDRESS(NvRamPtr), ID_REQUEST); + + ManufacturerID = READ_CONFIG_RAM_DATA(NvRamPtr); + DeviceID = READ_CONFIG_RAM_DATA((PUCHAR)((ULONG)NvRamPtr + 1)); + + if ((ManufacturerID == MANUFACTURER_ID) && + (DeviceID == Am29F080_DEVICE_ID)) { + + Am29F040_LastError = 0; + Am29F040_SetReadMode(NvRamPtr); + ReturnDriver = &Am29F080_DriverInformation; + } + + return ReturnDriver; +} + +ARC_STATUS +Am29F040_SetReadMode( + IN PUCHAR NvRamPtr + ) +{ + COMMAND_PREFIX(NvRamPtr); + WRITE_CONFIG_RAM_DATA(COMMAND_ADDRESS(NvRamPtr), SET_READ_ARRAY); + + return ESUCCESS; +} + +ARC_STATUS +Am29F040_WriteByte( + IN PUCHAR NvRamPtr, + IN UCHAR Data + ) +{ + ARC_STATUS ReturnStatus; + + Am29F040_SetReadMode(NvRamPtr); + + COMMAND_PREFIX(NvRamPtr); + WRITE_CONFIG_RAM_DATA(COMMAND_ADDRESS(NvRamPtr), SET_BYTE_WRITE); + WRITE_CONFIG_RAM_DATA(NvRamPtr, Data); + + ReturnStatus = Am29F040_CheckStatus(NvRamPtr, Data, FlashByteWrite); + + Am29F040_SetReadMode(NvRamPtr); + + return ReturnStatus; +} + +ARC_STATUS +Am29F040_EraseBlock ( + IN PUCHAR NvRamPtr + ) +{ + ARC_STATUS ReturnStatus; + + NvRamPtr = Am29F040_BlockAlign(NvRamPtr); + + COMMAND_PREFIX(NvRamPtr); + WRITE_CONFIG_RAM_DATA(COMMAND_ADDRESS(NvRamPtr), SET_ERASE); + COMMAND_PREFIX(NvRamPtr); + WRITE_CONFIG_RAM_DATA(COMMAND_ADDRESS(NvRamPtr), CONFIRM_ERASE_BLOCK); + + ReturnStatus = Am29F040_CheckStatus(NvRamPtr, 0xff, FlashEraseBlock); + + Am29F040_SetReadMode(NvRamPtr); + + return ReturnStatus; +} + +ARC_STATUS +Am29F040_CheckStatus ( + IN PUCHAR NvRamPtr, + IN UCHAR Data, + IN FLASH_OPERATIONS Operation + ) +{ + ARC_STATUS ReturnStatus = EIO; + BOOLEAN StopReading = FALSE; + UCHAR FlashStatus; + ULONG Timeout; + +#if 0 + // + // Keep reading the status until the device is done with its + // current operation. + // + do { + FlashStatus = READ_CONFIG_RAM_DATA(NvRamPtr); + if (FlashStatus & 0x20) { + StopReading = TRUE; + FlashStatus = READ_CONFIG_RAM_DATA(NvRamPtr); + } + } while (!StopReading && (((FlashStatus ^ Data) & 0x80) != 0)); + + if ((FlashStatus ^ Data) != 0) { + ReturnStatus = ESUCCESS; + } else { + ReturnStatus = EIO; + } + + return ReturnStatus; +#else + // + // If we are doing an erase command, check whether the erase command + // was accepted. This is supposed to happen within the first 100 usec. + // + + if (Operation == FlashEraseBlock) { + Timeout = TIMEOUT_VALUE; + + while (((READ_CONFIG_RAM_DATA(NvRamPtr) & 0x08) != 0x08) && + (Timeout > 0)) { + KeStallExecutionProcessor(1); + Timeout--; + } + + if (Timeout == 0) { + ReturnStatus = EIO; + Am29F040_SetLastError(0); + return ReturnStatus; + } + } + + // + // Now wait for the actual status + // + Timeout = TIMEOUT_VALUE; + do { + FlashStatus = READ_CONFIG_RAM_DATA(NvRamPtr); + + if (((FlashStatus ^ Data) & 0x80) == 0) { + ReturnStatus = ESUCCESS; + break; + } + + if (FlashStatus & 0x20) { + if (((READ_CONFIG_RAM_DATA(NvRamPtr) ^ Data) & 0x80) == 0) { + ReturnStatus = ESUCCESS; + break; + } else { + ReturnStatus = EIO; + Am29F040_SetLastError(Operation | 0x80000000); + break; + } + } + KeStallExecutionProcessor(1); + Timeout--; + } while (Timeout > 0); + + if (Timeout == 0) { + ReturnStatus = EIO; + Am29F040_SetLastError(0); + } + + return ReturnStatus; +#endif +} + +PUCHAR +Am29F040_BlockAlign( + IN PUCHAR Address + ) +{ + return BLOCK_ALIGN(Address); +} + +UCHAR +Am29F040_ReadByte( + IN PUCHAR Address + ) +{ + return READ_CONFIG_RAM_DATA(Address); +} + +BOOLEAN +Am29F040_OverwriteCheck( + IN UCHAR OldData, + IN UCHAR NewData + ) +/*++ + +Return Value: + + TRUE if OldData can be overwritten with NewData. + FALSE if OldData must be erased before writing NewData. + +--*/ +{ + return (~OldData & NewData) ? FALSE : TRUE; +} + +ULONG +Am29F040_BlockSize( + IN PUCHAR Address + ) +{ + return BLOCK_SIZE; +} + +ULONG +Am29F040_GetLastError( + VOID + ) +{ + return Am29F040_LastError; +} + +static +VOID +Am29F040_SetLastError( + ULONG FlashStatus + ) +{ + Am29F040_LastError = ERROR_UNKNOWN; + if (FlashStatus == 0) { + Am29F040_LastError = ERROR_TIMEOUT; + } else { + switch(FlashStatus & ~0x80000000) { + case FlashByteWrite: + Am29F040_LastError = ERROR_WRITE_ERROR; + break; + case FlashEraseBlock: + Am29F040_LastError = ERROR_ERASE_ERROR; + break; + } + } +} diff --git a/private/ntos/nthals/halalpha/adjust.c b/private/ntos/nthals/halalpha/adjust.c new file mode 100644 index 000000000..cc8aa4e84 --- /dev/null +++ b/private/ntos/nthals/halalpha/adjust.c @@ -0,0 +1,149 @@ +/*++ + + +Copyright (c) 1989 Microsoft Corporation +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + adjust.c + +Abstract: + + This module contains platform-independent slot resource adjust routines. + +Author: + + Eric Rehm 6-January-1994 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" + + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,HalpAdjustResourceListUpperLimits) +#endif + +VOID +HalpAdjustResourceListUpperLimits ( + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList, + IN LARGE_INTEGER MaximumPortAddress, + IN LARGE_INTEGER MaximumMemoryAddress, + IN ULONG MaximumInterruptVector, + IN ULONG MaximumDmaChannel + ) +/*++ + +Routine Description: + + Adjust a pResource list with respect to the upper bounds supplied. + (A resource is changed only if it execceds the maximum.) + +Arguments: + + pResouceList - Resource list to be checked. + + MaximumPortAddress - Maximum I/O port allowed. + + MaximumMemoryAddress - Maximum I/O memory address allowed. + + MaximumInterruptVector - Maximum interrupt vector allowed. + + MaximumDmaChannel - Maximum dma channel allowed. + +Return Value: + + None. + +--*/ +{ + PIO_RESOURCE_REQUIREMENTS_LIST CompleteList; + PIO_RESOURCE_LIST ResourceList; + PIO_RESOURCE_DESCRIPTOR Descriptor; + ULONG alt, cnt; + + + // + // Walk each ResourceList and shrink any values to system limits + // + + CompleteList = *pResourceList; + ResourceList = CompleteList->List; + + for (alt=0; alt < CompleteList->AlternativeLists; alt++) { + Descriptor = ResourceList->Descriptors; + for (cnt = ResourceList->Count; cnt; cnt--) { + + // + // Make sure descriptor limits fall within the + // CompleteList->InterfaceType & CompleteList->BusNumber. + // + // + + switch (Descriptor->Type) { + case CmResourceTypePort: + if (Descriptor->u.Port.MaximumAddress.QuadPart > + MaximumPortAddress.QuadPart) { + + Descriptor->u.Port.MaximumAddress = MaximumPortAddress; + } + + break; + + case CmResourceTypeInterrupt: + if (Descriptor->u.Interrupt.MaximumVector > + MaximumInterruptVector ) { + + Descriptor->u.Interrupt.MaximumVector = + MaximumInterruptVector; + } + break; + + case CmResourceTypeMemory: + if (Descriptor->u.Memory.MaximumAddress.QuadPart > + MaximumMemoryAddress.QuadPart) { + + Descriptor->u.Memory.MaximumAddress = + MaximumMemoryAddress; + } + break; + + case CmResourceTypeDma: + if (Descriptor->u.Dma.MaximumChannel > + MaximumDmaChannel ) { + + Descriptor->u.Dma.MaximumChannel = + MaximumDmaChannel; + } + break; + +#if DBG + default: + DbgPrint ("HalAdjustResourceList: Unkown resource type\n"); + break; +#endif + } + + // + // Next descriptor + // + Descriptor++; + } + + // + // Next Resource List + // + ResourceList = (PIO_RESOURCE_LIST) Descriptor; + } + +} + diff --git a/private/ntos/nthals/halalpha/allstart.c b/private/ntos/nthals/halalpha/allstart.c new file mode 100644 index 000000000..9bb5501bc --- /dev/null +++ b/private/ntos/nthals/halalpha/allstart.c @@ -0,0 +1,55 @@ +/*++ + +Copyright (c) 1994 Microsoft Corporation + +Module Name: + + allstart.c + +Abstract: + + + This module implements the platform specific operations that must be + performed after all processors have been started. + +Author: + + John Vert (jvert) 23-Jun-1994 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "halp.h" + +BOOLEAN +HalAllProcessorsStarted ( + VOID + ) + +/*++ + +Routine Description: + + This function executes platform specific operations that must be + performed after all processors have been started. It is called + for each processor in the host configuration. + +Arguments: + + None. + +Return Value: + + If platform specific operations are successful, then return TRUE. + Otherwise, return FALSE. + +--*/ + +{ + return TRUE; +} diff --git a/private/ntos/nthals/halalpha/alphaio.s b/private/ntos/nthals/halalpha/alphaio.s new file mode 100644 index 000000000..ce9dd652b --- /dev/null +++ b/private/ntos/nthals/halalpha/alphaio.s @@ -0,0 +1,1368 @@ +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + alphaio.s + + +Abstract: + + 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. + (We are using EV4 64-bit superpage mode.) + +Author: + + Joe Notarangelo 25-Oct-1993 + +Environment: + + Executes in kernel mode. + +Revision History: + + 12-Jul-1994 - Eric Rehm - Added dense space I/O + + 27-July-1994 - Sameer Dekate + + Make a common file for all machines and optimize Read/Write + register buffer routines. Made a common routine with different + entry points for READ & WRITE_REGISTER_BUFFER routines + +--*/ + +#include "chipset.h" +#include "halalpha.h" + + + + SBTTL( "Read I/O byte" ) +//++ +// +// UCHAR +// READ_REGISTER_UCHAR( +// IN PVOID RegisterQva +// ) +// +// Routine Description: +// +// Reads a byte location in PCI bus memory or 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_REGISTER_UCHAR) + + ALTERNATE_ENTRY(READ_PORT_UCHAR) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 3, t3 // get byte we need if eisa + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // t0 contains VA<33:0> + ldiq t4, -0x4000 // 0xffff ffff ffff c000 + sll t4, 28, t4 // 0xffff fc00 0000 0000 + or t0, t4, t0 // superpage mode + + mb + ldl v0, (t0) // get the longword + extbl v0, t3, v0 // get correct byte if eisa + + ret zero, (ra) // return + +// +// Dense space access: QVA is an offset into dense space +// + +2: + and a0, 3, t3 // get byte we need + zap a0, 0xf0, a0 // clear <63:32> + bic a0, 3, a0 // clear <1:0> to get aligned longword + + ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE + or a0, t0, a0 // superpage mode: add offset to base + + ldl v0, (a0) // get the longword + extbl v0, t3, v0 // get correct byte + + ret zero, (ra) // return + + .end READ_REGISTER_UCHAR + + + SBTTL( "Read I/O word(16 bits)" ) +//++ +// +// USHORT +// READ_REGISTER_USHORT( +// IN PVOID RegisterQva +// ) +// +// Routine Description: +// +// Reads a word location in PCI bus memory or I/O space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of the I/O word to read. +// +// Return Value: +// +// v0 - Returns the value read from I/O space. +// +//-- + + LEAF_ENTRY(READ_REGISTER_USHORT) + + ALTERNATE_ENTRY(READ_PORT_USHORT) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 3, t3 // get word + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + or t0, t4, t0 // superpage mode + + or t0, IO_WORD_LEN, t0 // or in the byte enables + + mb + ldl v0, (t0) // get the longword + extwl v0,t3,v0 // get the correct word + + ret zero, (ra) // return + +// +// Dense space access: QVA is an offset into dense space +// + +2: + and a0, 3, t3 // get word we need + zap a0, 0xf0, a0 // clear <63:32> + bic a0, 3, a0 // clear <1:0> to get aligned longword + + ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE + or a0,t0, a0 // superpage mode: add offset to base + + ldl v0, (a0) // get the longword + extwl v0, t3, v0 // get correct word + + ret zero, (ra) // return + + .end READ_REGISTER_USHORT + + + SBTTL( "Read I/O longword(32 bits)" ) +//++ +// +// ULONG +// READ_REGISTER_ULONG( +// IN PVOID RegisterQva +// ) +// +// Routine Description: +// +// Reads a longword location in PCI bus memory or I/O space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of the I/O longword to read. +// +// Return Value: +// +// v0 - Returns the value read from I/O space. +// +//-- + + LEAF_ENTRY(READ_REGISTER_ULONG) + + ALTERNATE_ENTRY(READ_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, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + or t0, t4, t0 // superpage mode + + or t0, IO_LONG_LEN, t0 // or in the byte enables + + mb + ldl v0, (t0) // read the longword + + ret zero, (ra) // return + +// +// Dense space access: QVA is an offset into dense space +// + +2: + zap a0, 0xf0, a0 // clear <63:32> + + ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE + or a0, t0, a0 // superpage mode: add offset to base + + ldl v0, (a0) // get the longword + + ret zero, (ra) // return + + .end READ_REGISTER_ULONG + + SBTTL( "Write I/O byte" ) +//++ +// +// VOID +// WRITE_REGISTER_UCHAR( +// IN PVOID RegisterQva, +// IN UCHAR Value +// ) +// +// Routine Description: +// +// Writes a byte location in PCI bus memory or I/O space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of the I/O byte to write. +// +// Value(a1) - Supplies the value written to I/O space. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(WRITE_REGISTER_UCHAR) + + ALTERNATE_ENTRY(WRITE_PORT_UCHAR) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 3, t3 // get byte we need if eisa + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // t0 contains VA<33:0> + ldiq t4, -0x4000 // + sll t4, 28, t4 // + or t0, t4, t0 // superpage mode + + insbl a1,t3,t4 // put the byte in the correct position + stl t4, (t0) // write the byte + mb // order the write + + ret zero, (ra) // return + +// +// Dense space access: QVA is an offset into dense space +// + +2: + and a0, 3, t3 // get byte we need if eisa + zap a0, 0xf0, a0 // clear <63:32> + bic a0, 3, a0 // clear <1:0> to get aligned longword + + ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE + or a0, t0, a0 // superpage mode: add offset to base + + ldl t1, (a0) // get the long + mskbl t1, t3, t1 // mask the proper byte + insbl a1, t3, t2 // put byte into position + bis t1, t2, t1 // merge byte in result + stl t1, (a0) // store the result + mb // order the write + + ret zero, (ra) // return + + .end WRITE_REGISTER_UCHAR + + + SBTTL( "Write I/O word (16 bits)" ) +//++ +// +// VOID +// WRITE_REGISTER_USHORT( +// IN PVOID RegisterQva, +// IN USHORT Value +// ) +// +// Routine Description: +// +// Writes a word location in PCI bus memory or I/O space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of the I/O word to write. +// +// Value(a1) - Supplies the value written to I/O space. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(WRITE_REGISTER_USHORT) + + ALTERNATE_ENTRY(WRITE_PORT_USHORT) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 3, t3 // get word + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + or t0, t4, t0 // superpage mode + + or t0, IO_WORD_LEN, t0 // or in the byte enables + + inswl a1,t3,t2 // put the word in the correct place + stl t2, (t0) // write the word + mb // order the write + + ret zero, (ra) // return + +// +// Dense space access: QVA is an offset into dense space +// + +2: + and a0, 3, t3 // get byte we need if eisa + zap a0, 0xf0, a0 // clear <63:32> + bic a0, 3, a0 // clear <1:0> to get aligned longword + + ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE + or a0, t0, a0 // superpage mode: add offset to base + + ldl t1, (a0) // get the long + mskwl t1, t3, t1 // mask the proper word + inswl a1, t3, t2 // put word into position + bis t1, t2, t1 // merge in result + stl t1, (a0) // store the result + mb // order the write + + ret zero, (ra) // return + + .end WRITE_REGISTER_USHORT + + + SBTTL( "Write I/O longword (32 bits)" ) +//++ +// +// VOID +// WRITE_REGISTER_ULONG( +// IN PVOID RegisterQva, +// IN ULONG Value +// ) +// +// Routine Description: +// +// Writes a longword location in PCI bus memory or I/O space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of the I/O longword to write. +// +// Value(a1) - Supplies the value written to I/O space. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(WRITE_REGISTER_ULONG) + + ALTERNATE_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, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + or t0, t4, t0 // superpage mode + + or t0, IO_LONG_LEN, t0 // or in the byte enables + + stl a1, (t0) // write the longword + mb // order the write + + ret zero, (ra) // return + +// +// Dense space access: QVA is an offset into dense space +// + +2: + zap a0, 0xf0, a0 // clear <63:32> + ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE + or a0, t0, a0 // superpage mode: add offset to base + + stl a1, (a0) // store the longword + mb // order the write + + ret zero, (ra) // return + + .end WRITE_REGISTER_ULONG + + +//++ +// +// 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, 3, t3 // get byte we need if eisa + 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 // t0 contains VA<33:0> + ldiq t4, -0x4000 // t4=ffff ffff ffff c000 + sll t4, 28, t4 // t4=ffff fc00 0000 0000 + or t0, t4, t0 // superpage mode + + beq a2, 3f // if count==0 return +2: + 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 + bne a2, 2b // while count != 0 +3: + ret zero, (ra) // return + + .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, 3, t3 // get word we need + 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 // t0 contains VA<33:0> + ldiq t4, -0x4000 // t4=ffff ffff ffff c000 + sll t4, 28, t4 // t4=ffff fc00 0000 0000 + or t0, t4, t0 // superpage mode + or t0, IO_WORD_LEN, t0 // or in the byte enables + + beq a2, 3f // if count==0 return +2: + 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 + bne a2, 2b // while count != 0 +3: + ret zero, (ra) // return + + .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) + + 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 // t0 contains VA<33:0> + + ldiq t4, -0x4000 // t4=ffff ffff ffff c000 + sll t4, 28, t4 // t4=ffff fc00 0000 0000 + or t0, t4, t0 // superpage mode + or t0, IO_LONG_LEN, t0 // or in the byte enables + + beq a2, 3f // if count==0 return +2: + 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 + bne a2, 2b // while count != 0 +3: + ret zero, (ra) // return + + .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, 3, t3 // get byte we need if eisa + 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 // t0 contains VA<33:0> + ldiq t4, -0x4000 // t4=ffff ffff ffff c000 + sll t4, 28, t4 // t4=ffff fc00 0000 0000 + or t0, t4, t0 // superpage mode + + beq a2, 3f // if count==0 return +2: + 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 + bne a2, 2b // while count != 0 + +3: + ret zero, (ra) // return + + .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, 3, t3 // get word we need + 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 // t0 contains VA<33:0> + ldiq t4, -0x4000 // t4=ffff ffff ffff c000 + sll t4, 28, t4 // t4=ffff fc00 0000 0000 + or t0, t4, t0 // superpage mode + or t0, IO_WORD_LEN, t0 // or in the byte enables + + beq a2, 3f // if count==0 return +2: + 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 writes off chip + bne a2, 2b // while count != 0 + +3: + ret zero, (ra) // return + + .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) + + 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 // t0 contains VA<33:0> + ldiq t4, -0x4000 // t4=ffff ffff ffff c000 + sll t4, 28, t4 // t4=ffff fc00 0000 0000 + or t0, t4, t0 // superpage mode + or t0, IO_LONG_LEN, t0 // or in the byte enables + + beq a2, 3f // if count==0 return +2: + ldl t1, 0(a1) // a1 must be longword aligned + subl a2, 1, a2 // decrement count + stl t1, 0(t0) // store to port + mb // push writes off chip + addl a1, 4, a1 // increment buffer + bne a2, 2b // while count != 0 + +3: + ret zero, (ra) // return + + .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 +// + ldil t8, 1 // DENSE FLAG + zap a0, 0xf0, a0 // clear <63:32> + ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE + 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: + ldil t8, 0 // SPARSE FLAG + 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 // t0 contains VA<33:0> + ldiq t4, -0x4000 // 0xffff ffff ffff c000 + sll t4, 28, t4 // 0xffff fc00 0000 0000 + 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) + beq t8, 11f // if not DENSE goto 11f + bic t0, 3, t9 // clear bits <1:0> of src + ldl v0, 0(t9) // get the longword + br zero, 12f +11: + ldl v0, 0(t0) // get the longword +12: + 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: + 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: + beq t8, 51f // if not DENSE goto 51f + bic t0, 3, t9 // clear bits <1:0> of src + ldl v0, 0(t9) // get the longword + br zero, 52f +51: + ldl v0, 0(t0) // get the longword +52: + 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) + beq t8, 81f // if not DENSE goto 81f + bic t0, 3, t9 // clear bits <1:0> of src + ldl v0, 0(t9) // get the longword + br zero, 82f +81: + ldl v0, 0(t0) // get the longword +82: + 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 + // + 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 + 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: + beq t8, 121f // if not DENSE goto 121f + bic t0, 3, t9 // clear bits <1:0> of src + ldl v0, 0(t9) // get the longword + br zero, 122f +121: + ldl v0, 0(t0) // get the longword +122: + 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> + ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE + 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> + bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + ldiq t4, -0x4000 // 0xffff ffff ffff c000 + sll t4, 28, t4 // 0xffff fc00 0000 0000 + 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 + + diff --git a/private/ntos/nthals/halalpha/am29f400.c b/private/ntos/nthals/halalpha/am29f400.c new file mode 100644 index 000000000..319583a84 --- /dev/null +++ b/private/ntos/nthals/halalpha/am29f400.c @@ -0,0 +1,543 @@ +/*++ + +Copyright (c) 1995 Digital Equipment Corporation + +Module Name: + + am29f400.c + +Abstract: + + This module contains the platform independent code to access the AMD + flash ROM part AM29F400. + +Author: + + Wim Colgate, 5/12/95 + +Environment: + + Firmware/Kernel mode + +Revision History: + +--*/ + +#include "halp.h" +#include "arccodes.h" +#include +#include "flashbus.h" +#include "am29f400.h" + +// +// External prototypes +// + +VOID pWriteFlashByte( + IN ULONG FlashOffset, + IN UCHAR Data + ); + +UCHAR pReadFlashByte( + IN ULONG FlashOffset + ); + +// +// Local function prototypes +// + +PFLASH_DRIVER +Am29F400_Initialize( + IN ULONG FlashOffset + ); + +ARC_STATUS +Am29F400_SetReadMode( + IN PUCHAR FlashOffset + ); + +ARC_STATUS +Am29F400_WriteByte( + IN PUCHAR FlashOffset, + IN UCHAR Data + ); + +ARC_STATUS +Am29F400_EraseSector( + IN PUCHAR FlashOffset + ); + +ARC_STATUS +Am29F400_CheckStatus( + IN PUCHAR FlashOffset, + IN FLASH_OPERATIONS Operation, + IN UCHAR OptionalData + ); + +PUCHAR +Am29F400_SectorAlign( + IN PUCHAR FlashOffset + ); + +UCHAR +Am29F400_ReadByte( + IN PUCHAR FlashOffset + ); + +BOOLEAN +Am29F400_OverwriteCheck( + IN UCHAR OldData, + IN UCHAR NewData + ); + +ULONG +Am29F400_SectorSize( + IN PUCHAR FlashOffset + ); + +FLASH_DRIVER Am29F400_DriverInformation = { + "AMD Am29F400", + Am29F400_SetReadMode, // SetReadModeFunction + Am29F400_WriteByte, // WriteByteFunction + Am29F400_EraseSector, // EraseSectorFunction + Am29F400_SectorAlign, // AlignSectorFunction + Am29F400_ReadByte, // ReadByteFunction + Am29F400_OverwriteCheck, // OverwriteCheckFunction + Am29F400_SectorSize, // SectorSizeFunction +// NULL, // Get last error + Am29F400_DEVICE_SIZE, // DeviceSize + Am29F400_ERASED_DATA // What an erased data looks like + }; + +// +// This variable tells us which bank of 8K 'nvram' are we using +// The LX3 nvram is actually two separate 8K sections of the FLASH ROM. +// One living at 0x4000, the other at 0x6000. +// +// This is NOT a QVA (which will is aliased by HalpCMOSBase in common +// code. Rather it is an offset within the FLASH ROM where the NVRAM lives. +// + +extern PVOID HalpCMOSRamBase; +ULONG Am29F400NVRAMBase; + + +static UCHAR am29F400_GetSectorNumber( + IN PUCHAR FlashOffset + ) +/*++ + +Routine Description: + + This routine figures out which sector number we are in (for use in + clearing the sector...) + +Arguments: + + FlashOffset - offset within the flash ROM. + +Return Value: + + The sector number within the range of the offset. + +--*/ +{ + ULONG Offset = (ULONG)FlashOffset; + + if (Offset < SECTOR_1_BASE) { + return 0; + } else if (Offset < SECTOR_2_BASE) { + return 1; + } else if (Offset < SECTOR_3_BASE) { + return 2; + } else if (Offset < SECTOR_4_BASE) { + return 3; + } else { + + // + // All other sectors are 0x10000, 0x20000, etc, so shift right by 64K, + // Then add the preceding section offset's + // + + return (UCHAR)((Offset >> 16) + 3); + } + + return 0; + +} + + +PFLASH_DRIVER +Am29F400_Initialize( + IN ULONG FlashOffset + ) +/*++ + +Routine Description: + + This routine spanks the FLASH ROM with the auto select command, which + allows us to make sure that the device is what we think it is. + +Arguments: + + FlashOffset - offset within the flash ROM. + +Return Value: + + NULL for no driver, or the address of the FLASH_DRIVER structure for + this driver. + +--*/ +{ + PFLASH_DRIVER ReturnDriver = NULL; + UCHAR ManufacturerID; + UCHAR DeviceID; + UCHAR temp; + + Am29F400_SetReadMode((PUCHAR)SECTOR_2_BASE); // first 8K section (NVRAM) + + HalpStallExecution(50); // wkc -- GACK! what a bogus part + + pWriteFlashByte(COMMAND_ADDR1, COMMAND_DATA1); + pWriteFlashByte(COMMAND_ADDR2, COMMAND_DATA2); + pWriteFlashByte(COMMAND_ADDR3, COMMAND_DATA3_AUTOSELECT); + + // + // Get manufacturer and device ID. Note spec says device ID lives + // at byte 1, but empirical evidence says it is at byte 2. + // + + ManufacturerID = Am29F400_ReadByte((PUCHAR)0x00); + DeviceID = Am29F400_ReadByte((PUCHAR)0x02); + +#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG) + DbgPrint("Manufacturer ID (expect 0x1) %x\n", ManufacturerID); + DbgPrint("Device ID (expect 0xab) %x\n", DeviceID); +#endif + + if ((ManufacturerID == MANUFACTURER_ID) && (DeviceID == DEVICE_ID)) { + Am29F400_SetReadMode(0x0); + Am29F400_SetReadMode((PUCHAR)SECTOR_2_BASE); + + // wkcfix -- check which NVRAM section we should use. + // currently use the first one setup in the HalpMapIoSpace() routine. + + Am29F400NVRAMBase = (ULONG)HalpCMOSRamBase; + ReturnDriver = &Am29F400_DriverInformation; + } + +#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG) + if (ReturnDriver == NULL) { + DbgPrint("FLASH part unknown; AMD Am29F400 not loaded\n"); + } +#endif + + return ReturnDriver; +} + + +ARC_STATUS +Am29F400_SetReadMode( + IN PUCHAR FlashOffset + ) +/*++ + +Routine Description: + + This routine spanks the FLASH ROM with the read reset routine. + +Arguments: + + FlashOffset - offset within the flash ROM -- but not used. + +Return Value: + + The value of the check status routine (EIO or ESUCCESS) + +--*/ +{ + + pWriteFlashByte((ULONG)FlashOffset, COMMAND_READ_RESET); + + return ESUCCESS; +} + + +ARC_STATUS +Am29F400_WriteByte( + IN PUCHAR FlashOffset, + IN UCHAR Data + ) +/*++ + +Routine Description: + + This routine spanks the FLASH ROM with the program command, then calls + the check status routine -- then resets the device to read. + +Arguments: + + FlashOffset - offset within the flash ROM. + Data - the data byte to write. + +Return Value: + + The value of the check status routine (EIO or ESUCCESS) + +--*/ +{ + ARC_STATUS ReturnStatus; + + pWriteFlashByte(COMMAND_ADDR1, COMMAND_DATA1); + pWriteFlashByte(COMMAND_ADDR2, COMMAND_DATA2); + pWriteFlashByte(COMMAND_ADDR3, COMMAND_DATA3_PROGRAM); + + ASSERT((FlashOffset >= (PUCHAR)0x4000) && (FlashOffset < (PUCHAR)0x8000)); + + pWriteFlashByte((ULONG)FlashOffset, Data); + + ReturnStatus = Am29F400_CheckStatus(FlashOffset, FlashByteWrite, Data); + + Am29F400_SetReadMode(FlashOffset); + + return ReturnStatus; +} + + +ARC_STATUS +Am29F400_EraseSector( + IN PUCHAR FlashOffset + ) +/*++ + +Routine Description: + + This routine spanks the FLASH ROM with the erase sector command, then calls + the check status routine + +Arguments: + + FlashOffset - offset within the flash ROM. + +Return Value: + + The value of the check status routine (EIO or ESUCCESS) + +--*/ +{ + ARC_STATUS ReturnStatus; + UCHAR ReadBack; + ULONG Count = MAX_FLASH_READ_ATTEMPTS; + + Am29F400_SetReadMode(FlashOffset); + + pWriteFlashByte(COMMAND_ADDR1, COMMAND_DATA1); + pWriteFlashByte(COMMAND_ADDR2, COMMAND_DATA2); + pWriteFlashByte(COMMAND_ADDR3, COMMAND_DATA3); + pWriteFlashByte(COMMAND_ADDR4, COMMAND_DATA4); + pWriteFlashByte(COMMAND_ADDR5, COMMAND_DATA5); + pWriteFlashByte((ULONG)FlashOffset, COMMAND_DATA6_SECTOR_ERASE); + + HalpStallExecution(80); // short stall for erase command to take + + ReturnStatus = Am29F400_CheckStatus(FlashOffset, + FlashEraseSector, + 0xff); + + Am29F400_SetReadMode(FlashOffset); + + return ReturnStatus; + +} + + +ARC_STATUS +Am29F400_CheckStatus ( + IN PUCHAR FlashOffset, + IN FLASH_OPERATIONS Operation, + IN UCHAR OptionalData + ) +/*++ + +Routine Description: + + This routine checks the status of the flashbus operation. The operation + may be specific, so different actions may be taken. + +Arguments: + + FlashOffset - offset within the flash ROM. + Opertaion - the operation performed on the FlashOffset. + OptionalData - an optional data value that may be needed for verification. + +Return Value: + + EIO for faiure + ESUCCESS for success + +--*/ +{ + ARC_STATUS ReturnStatus = EIO; + UCHAR FlashRead; + ULONG Count = 0; + ULONG DataOK = FALSE; + + while ((DataOK == FALSE) && (Count < MAX_FLASH_READ_ATTEMPTS)) { + + FlashRead = Am29F400_ReadByte(FlashOffset); + + // + // Both FlashByteWrite & FlashEraseBlock checks use polling + // algorithm found on page 1-131 of the AMD part specification + // + + if ((FlashRead & 0x80) == (OptionalData & 0x80)) { + DataOK = TRUE; + } else if (FlashRead & 0x20) { + FlashRead = Am29F400_ReadByte(FlashOffset); + if ((FlashRead & 0x80) == (OptionalData & 0x80)) { + DataOK = TRUE; + } else { + break; + } + } + Count++; + } + + if (DataOK == TRUE) { + ReturnStatus = ESUCCESS; + } + + return ReturnStatus; +} + + +PUCHAR +Am29F400_SectorAlign( + IN PUCHAR FlashOffset + ) +/*++ + +Routine Description: + + This routine returns the base offset that the current offset within + a sector of the flash ROM. + +Arguments: + + FlashOffset - offset within the flash ROM. + +Return Value: + + The base offset of the current sector -- as defined by the FlashOffset. + +--*/ +{ + ULONG Offset = (ULONG)FlashOffset; + + if (Offset < SECTOR_2_BASE) { + return (PUCHAR)SECTOR_1_BASE; + } else if (Offset < SECTOR_3_BASE) { + return (PUCHAR)SECTOR_2_BASE; + } else if (Offset < SECTOR_4_BASE) { + return (PUCHAR)SECTOR_3_BASE; + } else if (Offset < SECTOR_5_BASE) { + return (PUCHAR)SECTOR_4_BASE; + } else { + return (PUCHAR)(ULONG)(Offset & ~(SECTOR_5_SIZE-1)); + } +} + + +UCHAR +Am29F400_ReadByte( + IN PUCHAR FlashOffset + ) +/*++ + +Routine Description: + + This routine spanks the FLASH ROM with the read command, then calls + the read flash bus function. + +Arguments: + + FlashOffset - offset within the flash ROM. + + +Return Value: + + The character at the appropriate location. + +--*/ +{ + UCHAR ReturnVal; + + // + // Assume Read mode is on + // + + ReturnVal = pReadFlashByte((ULONG)FlashOffset); + + return ReturnVal; +} + + +BOOLEAN +Am29F400_OverwriteCheck( + IN UCHAR OldData, + IN UCHAR NewData + ) +/*++ + +Routine Description: + + This routine returns if we can safely overwrite an existing data + with new data. Flash Rom's can go from 1-->1, 1-->0 and 0-->0, but + cannot go from 0-->1. + +Return Value: + + + TRUE if we can safely overwrite + FALSE if we cannot safely overwrite + +--*/ +{ + return ((NewData & ~OldData) == 0) ? TRUE: FALSE; +} + + +ULONG +Am29F400_SectorSize( + IN PUCHAR FlashOffset + ) +/*++ + +Routine Description: + + This routine returns the size of the sector that the offset is within. + +Arguments: + + FlashOffset - offset within the flash ROM. + + +Return Value: + + The block size of the sector. + +--*/ +{ + if (FlashOffset < (PUCHAR)SECTOR_2_BASE) { + return SECTOR_1_SIZE; + } else if (FlashOffset < (PUCHAR)SECTOR_3_BASE) { + return SECTOR_2_SIZE; + } else if (FlashOffset < (PUCHAR)SECTOR_4_BASE) { + return SECTOR_3_SIZE; + } else if (FlashOffset < (PUCHAR)SECTOR_5_BASE) { + return SECTOR_4_SIZE; + } else { + return SECTOR_5_SIZE; + } +} diff --git a/private/ntos/nthals/halalpha/am29f400.h b/private/ntos/nthals/halalpha/am29f400.h new file mode 100644 index 000000000..61e3f1774 --- /dev/null +++ b/private/ntos/nthals/halalpha/am29f400.h @@ -0,0 +1,97 @@ +#ifndef _AM29F400_H_ +#define _AM29F400_H_ + +// +// The AMD is a full 1/2 megabyte broken into the following sectors: +// +// 0x00000 .. 0x03fff -- > Section 1 // SROM +// 0x04000 .. 0x05fff -- > Section 2 // NVRAM_0 +// 0x06000 .. 0x07fff -- > Section 3 // NVRAM_1 +// 0x08000 .. 0x0ffff -- > Section 4 // DROM +// 0x10000 .. 0x1ffff -- > Section 5 // ARC starts here +// 0x20000 .. 0x2ffff -- > Section 6 +// 0x30000 .. 0x3ffff -- > Section 7 +// 0x40000 .. 0x4ffff -- > Section 8 +// 0x50000 .. 0x5ffff -- > Section 8 +// 0x60000 .. 0x6ffff -- > Section 9 +// 0x70000 .. 0x7ffff -- > Section 10 + +// +// Name the blocks +// + +#define SECTOR_1_BASE 0x0 +#define SECTOR_2_BASE 0x4000 +#define SECTOR_3_BASE 0x6000 +#define SECTOR_4_BASE 0x8000 +#define SECTOR_5_BASE 0x10000 + +#define SECTOR_1_SIZE (SECTOR_2_BASE - SECTOR_1_BASE) +#define SECTOR_2_SIZE (SECTOR_3_BASE - SECTOR_2_BASE) +#define SECTOR_3_SIZE (SECTOR_4_BASE - SECTOR_3_BASE) +#define SECTOR_4_SIZE (SECTOR_5_BASE - SECTOR_4_BASE) +#define SECTOR_5_SIZE 0x10000 +#define ARC_SECTOR_SIZE SECTOR_5_SIZE + +// +// The largest addressable offset +// + +#define Am29F400_DEVICE_SIZE 0x7ffff + +// +// What an erased data byte looks like +// + +#define Am29F400_ERASED_DATA 0xff + +// +// The command writing sequence for read/auto select/write +// + +#define COMMAND_READ_RESET 0xf0 + +#define COMMAND_ADDR1 0xaaaa +#define COMMAND_DATA1 0xaa + +#define COMMAND_ADDR2 0x5555 +#define COMMAND_DATA2 0x55 + +#define COMMAND_ADDR3 0xaaaa +#define COMMAND_DATA3_READ 0xf0 // then {addr,data} +#define COMMAND_DATA3_AUTOSELECT 0x90 +#define COMMAND_DATA3_PROGRAM 0xA0 // then {addr,data} +#define COMMAND_DATA3 0x80 // for the additional ops + +// +// and additional bus cyles for chip and sector erase +// + +#define COMMAND_ADDR4 0xaaaa +#define COMMAND_DATA4 0xaa + +#define COMMAND_ADDR5 0x5555 +#define COMMAND_DATA5 0x55 + +// for SECTOR ERASE, the addr is the sector number +#define COMMAND_DATA6_SECTOR_ERASE 0x30 + +#define COMMAND_ADDR6 0xaaaa +#define COMMAND_DATA6_CHIP_ERASE 0x10 + +// +// This is the Am29F400 made by AMD +// + +#define MANUFACTURER_ID 0x01 +#define DEVICE_ID 0xab + +// +// Max attempts +// + +#define MAX_FLASH_READ_ATTEMPTS 0x800000 + +#include "pflash.h" + +#endif // _AM29F400_H_ diff --git a/private/ntos/nthals/halalpha/apecs.c b/private/ntos/nthals/halalpha/apecs.c new file mode 100644 index 000000000..7c5a5918a --- /dev/null +++ b/private/ntos/nthals/halalpha/apecs.c @@ -0,0 +1,337 @@ +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + apecs.c + +Abstract: + + This module implements functions that are specific to the APECS + chip-set. + +Author: + + Joe Notarangelo 18-Oct-1993 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" +#include "apecs.h" + +VOID +DumpEpic( + VOID + ); + +// +// Globals +// + +// +// Parity checking is a tri-state variable, unknown == all f's. Which means +// Keep checking disabled until we can determine what we want to set it to, +// which then means 1 or 0. +// + +extern ULONG HalDisablePCIParityChecking; + + +VOID +HalpApecsInitializeSfwWindow( + PWINDOW_CONTROL_REGISTERS WindowRegisters, + APECS_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 ApecsIsaWindow: + + WindowRegisters->WindowBase = (PVOID)ISA_DMA_WINDOW_BASE; + WindowRegisters->WindowSize = ISA_DMA_WINDOW_SIZE; + WindowRegisters->TranslatedBaseRegister = + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->TranslatedBase1Register; + WindowRegisters->WindowBaseRegister = + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciBase1Register; + WindowRegisters->WindowMaskRegister = + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciMask1Register; + WindowRegisters->WindowTbiaRegister = + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->TbiaRegister; + + break; + + case ApecsMasterWindow: + + WindowRegisters->WindowBase = (PVOID)MASTER_DMA_WINDOW_BASE; + WindowRegisters->WindowSize = MASTER_DMA_WINDOW_SIZE; + WindowRegisters->TranslatedBaseRegister = + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->TranslatedBase2Register; + WindowRegisters->WindowBaseRegister = + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciBase2Register; + WindowRegisters->WindowMaskRegister = + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciMask2Register; + WindowRegisters->WindowTbiaRegister = + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->TbiaRegister; + + break; + + default: + +#if DBG + + DbgPrint( "ApecsInitializeSfwWindow: Bad Window Number = %x\n", + WindowNumber ); + +#endif //DBG + + break; + + } + + return; +} + + +VOID +HalpApecsProgramDmaWindow( + 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. + +--*/ +{ + EPIC_ECSR Ecsr; + EPIC_PCIBASE PciBase; + EPIC_PCIMASK PciMask; + EPIC_TBASE TBase; + PVOID RegisterQva; + + PciBase.Reserved = 0; + PciBase.Wenr = 1; + PciBase.Sgen = 1; + PciBase.BaseValue = (ULONG)(WindowRegisters->WindowBase) >> 20; + + PciMask.Reserved = 0; + PciMask.MaskValue = (WindowRegisters->WindowSize >> 20) - 1; + + TBase.Reserved = 0; + TBase.TBase = (ULONG)(MapRegisterBase) >> 10; + +#if DBG + + // + // Dump the EPIC registers. + // + + DumpEpic(); + +#endif //DBG + + // + // Clear the window base, temporarily disabling transactions to this + // DMA window. + // + + WRITE_EPIC_REGISTER( WindowRegisters->WindowBaseRegister, (ULONG)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_EPIC_REGISTER( WindowRegisters->TranslatedBaseRegister, + *(PULONG)&TBase ); + + WRITE_EPIC_REGISTER( WindowRegisters->WindowMaskRegister, + *(PULONG)&PciMask ); + + WRITE_EPIC_REGISTER( WindowRegisters->WindowBaseRegister, + *(PULONG)&PciBase ); + + // + // Invalidate any translations that might have existed for this window. + // + + WRITE_EPIC_REGISTER( WindowRegisters->WindowTbiaRegister, 0 ); + + // + // Enable the translation buffer inside of the EPIC. + // + + RtlZeroMemory( &Ecsr, sizeof(EPIC_ECSR) ); + Ecsr.Tenb = 1; + + // + // Tri state parity checking - keep disabled if not determined + // yet. otherwise, Whack the PCI parity disable bit with the stored + // value + // + + if (HalDisablePCIParityChecking == 0xffffffff) { + Ecsr.Dpec = 1; + } else { + Ecsr.Dpec = HalDisablePCIParityChecking; + } + +#if HALDBG + if (HalDisablePCIParityChecking == 0) { + DbgPrint("apecs: PCI Parity Checking ON\n"); + } else if (HalDisablePCIParityChecking == 1) { + DbgPrint("apecs: PCI Parity Checking OFF\n"); + } else { + DbgPrint("apecs: PCI Parity Checking OFF - not set by ARC yet\n"); + } +#endif + + RegisterQva = + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister; + WRITE_EPIC_REGISTER( RegisterQva, + *(PULONG)&Ecsr ); + +#if DBG + + // + // Dump the EPIC registers. + // + + DumpEpic(); + +#endif //DBG + + return; +} + +ULONG +READ_EPIC_REGISTER( + PVOID + ); + +#if DBG + +VOID +DumpEpic( + VOID + ) +/*++ + +Routine Description: + + Read the interesting EPIC registers and print them to the debug port. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + PVOID RegisterQva; + ULONG Value; + + DbgPrint( "Dumping the EPIC registers\n" ); + + RegisterQva = + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister; + Value = READ_EPIC_REGISTER( RegisterQva ); + DbgPrint( "ECSR = %x\n", Value ); + + RegisterQva = + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->TranslatedBase1Register; + Value = READ_EPIC_REGISTER( RegisterQva ); + DbgPrint( "TBASE1 = %x\n", Value ); + + RegisterQva = + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->TranslatedBase2Register; + Value = READ_EPIC_REGISTER( RegisterQva ); + DbgPrint( "TBASE2 = %x\n", Value ); + + RegisterQva = &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciBase1Register; + Value = READ_EPIC_REGISTER( RegisterQva ); + DbgPrint( "PCIBASE1 = %x\n", Value ); + + RegisterQva = &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciBase2Register; + Value = READ_EPIC_REGISTER( RegisterQva ); + DbgPrint( "PCIBASE2 = %x\n", Value ); + + RegisterQva = &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciMask1Register; + Value = READ_EPIC_REGISTER( RegisterQva ); + DbgPrint( "PCIMASK1 = %x\n", Value ); + + RegisterQva = &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciMask2Register; + Value = READ_EPIC_REGISTER( RegisterQva ); + DbgPrint( "PCIMASK2 = %x\n", Value ); + + RegisterQva = &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->Haxr0; + Value = READ_EPIC_REGISTER( RegisterQva ); + DbgPrint( "HAXR0 = %x\n", Value ); + + RegisterQva = &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->Haxr1; + Value = READ_EPIC_REGISTER( RegisterQva ); + DbgPrint( "HAXR1 = %x\n", Value ); + + RegisterQva = &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->Haxr2; + Value = READ_EPIC_REGISTER( RegisterQva ); + DbgPrint( "HAXR2 = %x\n", Value ); + + DbgPrint( "--end EPIC dump\n\n" ); + + return; + +} + +#endif //DBG diff --git a/private/ntos/nthals/halalpha/apecs.h b/private/ntos/nthals/halalpha/apecs.h new file mode 100644 index 000000000..97b24809d --- /dev/null +++ b/private/ntos/nthals/halalpha/apecs.h @@ -0,0 +1,647 @@ +/*++ + +Copyright (c) 1993, 1996 Digital Equipment Corporation + +Module Name: + + apecs.h + +Abstract: + + This file defines the structures and definitions common to all + APECS-based platforms. + +Author: + + Joe Notarangelo 12-Oct-1993 + +Environment: + + Kernel mode + +Revision History: + + Chao Chen 31-Aug-1995 Fix the broken Comanche register data structure. + Gene Morgan 27-Feb-1996 Add missing Comanche register defns + +--*/ + +#ifndef _APECSH_ +#define _APECSH_ + + +// +// Define QVA constants for APECS. +// + +#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 size of I/O and memory space for APECS +// + +#define PCI_MAX_IO_ADDRESS 0xFFFFFF // 16 Mb of IO Space + +#define PCI_MAX_SPARSE_MEMORY_ADDRESS ((128*1024*1024) - 1) +#define PCI_MIN_DENSE_MEMORY_ADDRESS PCI_MAX_SPARSE_MEMORY_ADDRESS + 1 +#define PCI_MAX_DENSE_MEMORY_ADDRESS (0xa0000000 -1) // 2.5 Gb + +// +// Constant used by dense space I/O routines +// + +#define PCI_DENSE_BASE_PHYSICAL_SUPERPAGE 0xfffffc0300000000 + +#if !defined(_LANGUAGE_ASSEMBLY) + +// +// 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) >> IO_BIT_SHIFT) ) ) + + +// +// Define physical address spaces for APECS. +// + +#define APECS_COMANCHE_BASE_PHYSICAL ((ULONGLONG)0x180000000) +#define APECS_EPIC_BASE_PHYSICAL ((ULONGLONG)0x1A0000000) +#define APECS_PCI_INTACK_BASE_PHYSICAL ((ULONGLONG)0x1B0000000) +#define APECS_PCI_IO_BASE_PHYSICAL ((ULONGLONG)0x1C0000000) +#define APECS_PCI_CONFIG_BASE_PHYSICAL ((ULONGLONG)0x1E0000000) +#define APECS_PCI_MEMORY_BASE_PHYSICAL ((ULONGLONG)0x200000000) +#define APECS_PCI_DENSE_BASE_PHYSICAL ((ULONGLONG)0x300000000) + +#define APECS_PCI_CONFIG_BASE_QVA (HAL_MAKE_QVA(APECS_PCI_CONFIG_BASE_PHYSICAL)) + +#define EPIC_HAXR1_BASE_PHYSICAL ((ULONGLONG)0x1A00001A0) +#define EPIC_HAXR2_BASE_PHYSICAL ((ULONGLONG)0x1A00001C0) +#define EPIC_HAXR1_QVA (HAL_MAKE_QVA(EPIC_HAXR1_BASE_PHYSICAL)) +#define EPIC_HAXR2_QVA (HAL_MAKE_QVA(EPIC_HAXR2_BASE_PHYSICAL)) + + +// +// Define COMANCHE CSRs. +// + + +#define APECS_COMANCHE_BASE_QVA (HAL_MAKE_QVA(APECS_COMANCHE_BASE_PHYSICAL)) + +// +// N.B. The structure below defines the address offsets of the control +// registers when used with the base QVA. It does NOT define the +// size or structure of the individual registers. +// + +typedef struct _COMANCHE_CSRS{ + UCHAR GeneralControlRegister; + UCHAR Reserved; + UCHAR ErrorAndDiagnosticStatusRegister; + UCHAR TagEnableRegister; + UCHAR ErrorLowAddressRegister; + UCHAR ErrorHighAddressRegister; + UCHAR Ldx_lLowAddressRegister; + UCHAR Ldx_lHighAddressRegister; + UCHAR Reserved1[8]; + UCHAR GlobalTimingRegister; + UCHAR RefreshTimingRegister; + UCHAR VideoFramePointerRegister; + UCHAR PresenceDetectLowDataRegister; + UCHAR PresenceDetectHighDataRegister; + UCHAR Reserved2[43]; + UCHAR Bank0BaseAddressRegister; + UCHAR Bank1BaseAddressRegister; + UCHAR Bank2BaseAddressRegister; + UCHAR Bank3BaseAddressRegister; + UCHAR Bank4BaseAddressRegister; + UCHAR Bank5BaseAddressRegister; + UCHAR Bank6BaseAddressRegister; + UCHAR Bank7BaseAddressRegister; + UCHAR Bank8BaseAddressRegister; + UCHAR Reserved3[7]; + UCHAR Bank0ConfigurationRegister; + UCHAR Bank1ConfigurationRegister; + UCHAR Bank2ConfigurationRegister; + UCHAR Bank3ConfigurationRegister; + UCHAR Bank4ConfigurationRegister; + UCHAR Bank5ConfigurationRegister; + UCHAR Bank6ConfigurationRegister; + UCHAR Bank7ConfigurationRegister; + UCHAR Bank8ConfigurationRegister; + UCHAR Reserved4[7]; + UCHAR Bank0TimingRegisterA; + UCHAR Bank1TimingRegisterA; + UCHAR Bank2TimingRegisterA; + UCHAR Bank3TimingRegisterA; + UCHAR Bank4TimingRegisterA; + UCHAR Bank5TimingRegisterA; + UCHAR Bank6TimingRegisterA; + UCHAR Bank7TimingRegisterA; + UCHAR Bank8TimingRegisterA; + UCHAR Reserved5[7]; + UCHAR Bank0TimingRegisterB; + UCHAR Bank1TimingRegisterB; + UCHAR Bank2TimingRegisterB; + UCHAR Bank3TimingRegisterB; + UCHAR Bank4TimingRegisterB; + UCHAR Bank5TimingRegisterB; + UCHAR Bank6TimingRegisterB; + UCHAR Bank7TimingRegisterB; + UCHAR Bank8TimingRegisterB; +} COMANCHE_CSRS, *PCOMANCHE_CSRS; + +// +// Define formats of useful COMANCHE registers. +// + +// +// Error Diagnostic and Status Register +// +typedef union _COMANCHE_EDSR{ + struct{ + ULONG Losterr: 1; + ULONG Bctaperr: 1; + ULONG Bctcperr: 1; + ULONG Nxmerr: 1; + ULONG Dmacause: 1; + ULONG Viccause: 1; + ULONG Creqcause: 3; + ULONG Reserved: 4; + ULONG Pass2: 1; + ULONG Ldxllock: 1; + ULONG Wrpend: 1; + }; + ULONG all; +} COMANCHE_EDSR, *PCOMANCHE_EDSR; + +// +// General Control Register +// +typedef union _COMANCHE_GCR { + struct { + ULONG Reserved1: 1; + ULONG Sysarb: 2; + ULONG Reserved2: 1; + ULONG Widemem: 1; + ULONG Bcen: 1; + ULONG Bcnoalloc: 1; + ULONG Bclongwr: 1; + ULONG Bcigntflag: 1; + ULONG Bcfrctflag: 1; + ULONG Bcfrcd: 1; + ULONG Bcfrcz: 1; + ULONG Bcfrcp: 1; + ULONG Bcbadap: 1; + ULONG Reserved3: 2; + }; + ULONG all; +} COMANCHE_GCR, *PCOMANCHE_GCR; + +// +// Tag Enable Register +// +typedef union _COMANCHE_TER { + struct { + ULONG Tagen: 16; // Bit zero is reserved and MBZ + }; + ULONG all; +} COMANCHE_TER, *PCOMANCHE_TER; + +// +// Bank Base Address Register [0..8] +// +typedef union _COMANCHE_BASE_ADDRESS_REGISTER { + struct { + ULONG Reserved: 5; + ULONG BaseAdr: 11; + }; + ULONG all; +} COMANCHE_BASE_ADDRESS_REGISTER, *PCOMANCHE_BASE_ADDRESS_REGISTER; + +// +// Bank Configuration Register [0..8] +// +typedef union _COMANCHE_BANK_CONFIGURATION_REGISTER { + struct { + ULONG SetValid: 1; + ULONG SetSize: 4; + ULONG SetSubEna: 1; + ULONG SetColSel: 3; + ULONG Reserved: 7; + }; + ULONG all; +}COMANCHE_BANK_CONFIGURATION_REGISTER, *PCOMANCHE_BANK_CONFIGURATION_REGISTER; + + +// +// Define EPIC CSRs. +// + + +#define APECS_EPIC_BASE_QVA (HAL_MAKE_QVA(APECS_EPIC_BASE_PHYSICAL)) + +// +// N.B. The structure below defines the address offsets of the control +// registers when used with the base QVA. It does NOT define the +// size or structure of the individual registers. +// + +typedef struct _EPIC_CSRS{ + UCHAR EpicControlAndStatusRegister; + UCHAR SysbusErrorAddressRegister; + UCHAR PciErrorAddressRegister; + UCHAR DummyRegister1; + UCHAR DummyRegister2; + UCHAR DummyRegister3; + UCHAR TranslatedBase1Register; + UCHAR TranslatedBase2Register; + UCHAR PciBase1Register; + UCHAR PciBase2Register; + UCHAR PciMask1Register; + UCHAR PciMask2Register; + UCHAR Haxr0; + UCHAR Haxr1; + UCHAR Haxr2; + UCHAR DummyRegister4; + UCHAR TlbTag0Register; + UCHAR TlbTag1Register; + UCHAR TlbTag2Register; + UCHAR TlbTag3Register; + UCHAR TlbTag4Register; + UCHAR TlbTag5Register; + UCHAR TlbTag6Register; + UCHAR TlbTag7Register; + UCHAR TlbData0Register; + UCHAR TlbData1Register; + UCHAR TlbData2Register; + UCHAR TlbData3Register; + UCHAR TlbData4Register; + UCHAR TlbData5Register; + UCHAR TlbData6Register; + UCHAR TlbData7Register; + UCHAR TbiaRegister; +} EPIC_CSRS, *PEPIC_CSRS; + +// +// Define formats of useful EPIC registers. Note that P1 is a vestige, +// and direct access for P2 definitions are the default. +// + +typedef union _EPIC_ECSR{ + + struct{ + ULONG Tenb: 1; + ULONG Prst: 1; + ULONG Penb: 1; + ULONG Dcei: 1; + ULONG Rsvd1: 1; + ULONG Iort: 1; + ULONG Lost: 1; + ULONG Rdwr: 1; + ULONG Ddpe: 1; + ULONG Iope: 1; + ULONG Tabt: 1; + ULONG Ndev: 1; + ULONG Cmrd: 1; + ULONG Umrd: 1; + ULONG Iptl: 1; + ULONG Merr: 1; + ULONG DisRdByp: 2; + ULONG Rsvd2: 14; + } P1; + struct{ + ULONG Tenb: 1; + ULONG Rsvd1: 1; + ULONG Penb: 1; + ULONG Dcei: 1; + ULONG Dpec: 1; + ULONG Iort: 1; + ULONG Lost: 1; + ULONG Rsvd2: 1; + ULONG Ddpe: 1; + ULONG Iope: 1; + ULONG Tabt: 1; + ULONG Ndev: 1; + ULONG Cmrd: 1; + ULONG Umrd: 1; + ULONG Iptl: 1; + ULONG Merr: 1; + ULONG DisRdByp: 2; + ULONG Pcmd: 4; + ULONG Rsvd3: 9; + ULONG Pass2: 1; + }; + ULONG all; +} EPIC_ECSR, *PEPIC_ECSR; + +typedef struct _EPIC_PCIMASK{ + ULONG Reserved: 20; + ULONG MaskValue: 12; +} EPIC_PCIMASK, *PEPIC_PCIMASK; + +typedef struct _EPIC_PCIBASE{ + ULONG Reserved: 18; + ULONG Sgen: 1; + ULONG Wenr: 1; + ULONG BaseValue: 12; +} EPIC_PCIBASE, *PEPIC_PCIBASE; + +typedef struct _EPIC_TBASE{ + ULONG Reserved: 9; + ULONG TBase: 23; +} EPIC_TBASE, *PEPIC_TBASE; + + +// +// DMA Window Values. +// +// The APECs 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 _APECS_WINDOW_NUMBER{ + ApecsIsaWindow, + ApecsMasterWindow +} APECS_WINDOW_NUMBER, *PAPECS_WINDOW_NUMBER; + +// +// Define APECS Window Control routines. +// + +VOID +HalpApecsInitializeSfwWindow( + PWINDOW_CONTROL_REGISTERS WindowRegisters, + APECS_WINDOW_NUMBER WindowNumber + ); + +VOID +HalpApecsProgramDmaWindow( + PWINDOW_CONTROL_REGISTERS WindowRegisters, + PVOID MapRegisterBase + ); + + +// +// 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 ) \ + HalpApecsInitializeSfwWindow( (WR), ApecsIsaWindow ); + + +// +// VOID +// INITIALIZE_MASTER_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_MASTER_DMA_CONTROL( WR ) \ + HalpApecsInitializeSfwWindow( (WR), ApecsMasterWindow ); + + +// +// 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 ) \ + HalpApecsProgramDmaWindow( (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 ) \ + WRITE_EPIC_REGISTER( \ + ((PWINDOW_CONTROL_REGISTERS)WR)->WindowTbiaRegister, 0 ); + + +// +// 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; + +// +// APECS-specific functions. +// + +VOID +WRITE_COMANCHE_REGISTER( + IN PVOID RegisterQva, + IN ULONG Value + ); + +ULONG +READ_COMANCHE_REGISTER( + IN PVOID RegisterQva + ); + +VOID +WRITE_EPIC_REGISTER( + IN PVOID RegisterQva, + IN ULONG Value + ); + +ULONG +READ_EPIC_REGISTER( + IN PVOID RegisterQva + ); + +#endif //!_LANGUAGE_ASSEMBLY + +#endif //_APECSH_ diff --git a/private/ntos/nthals/halalpha/apecserr.c b/private/ntos/nthals/halalpha/apecserr.c new file mode 100644 index 000000000..5464a8936 --- /dev/null +++ b/private/ntos/nthals/halalpha/apecserr.c @@ -0,0 +1,1542 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + apecserr.c + +Abstract: + + This module implements error handling (machine checks and error + interrupts) for machines based on the APECS chip-set. + +Author: + + Joe Notarangelo 14-Feb-1994 + +Environment: + + Kernel mode only. + +Revision History: + + Chao Chen 31-Aug-1995 Added in ECC correctable error handling. + + Balakumar.N 26-Sep-1995 added Uncorrectable Error Logging code and + merged Chao's changes to handle correctable error. + +--*/ + +#include "halp.h" +#include "apecs.h" +#include "stdio.h" + +// +// Declare the extern variable UncorrectableError declared in +// inithal.c. +// +extern PERROR_FRAME PUncorrectableError; + +// +// Define the context structure for use by interrupt service routines. +// + +typedef BOOLEAN (*PSECOND_LEVEL_DISPATCH)( + PKINTERRUPT InterruptObject, + PVOID ServiceContext + ); + + +VOID +HalpSetMachineCheckEnables( + IN BOOLEAN DisableMachineChecks, + IN BOOLEAN DisableProcessorCorrectables, + IN BOOLEAN DisableSystemCorrectables + ); + +VOID +HalpApecsReportFatalError( + VOID + ); + +ULONG +HalpSimm( + ULONGLONG Address + ); + +VOID +HalpApecsCorrectableError( + VOID + ); + +VOID +HalpApecsConfig( + PAPECS_CONFIGURATION Config + ); + +// jnfix - temp count +ULONG CorrectedMemoryReads = 0; +#define MAX_ERROR_STRING 128 + +extern ULONG HalDisablePCIParityChecking; + + +VOID +HalpInitializeMachineChecks( + IN BOOLEAN ReportCorrectableErrors + ) +/*++ + +Routine Description: + + This routine initializes machine check handling for an APECS-based + system by clearing all pending errors in the COMANCHE and EPIC 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. + +--*/ +{ + ULONG Dummy; + EPIC_ECSR Ecsr; + COMANCHE_EDSR Edsr; + + // + // Clear the lost error bit in the Comanche EDSR. + // + + Edsr.all = 0; + Edsr.Losterr = 1; + WRITE_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorAndDiagnosticStatusRegister, + Edsr.all ); + + // + // Unlock the other error bits of the EDSR by reading the error address + // registers. + // + + Dummy = READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorHighAddressRegister + ); + + Dummy = READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorLowAddressRegister + ); + + // + // Clear all of the error bits in the Epic ECSR. Set correctable error + // reporting as requested. + // + + Ecsr.all = READ_EPIC_REGISTER( + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister ); + + // + // For the common registers, simply set them - common in that the P1 + // definition matches the P2 definition (same structure offset). + // + + Ecsr.Merr = 1; + Ecsr.Iptl = 1; + Ecsr.Umrd = 1; + Ecsr.Cmrd = 1; + Ecsr.Ndev = 1; + Ecsr.Tabt = 1; + Ecsr.Iope = 1; + Ecsr.Ddpe = 1; + Ecsr.Lost = 1; + Ecsr.Iort = 1; + + if( ReportCorrectableErrors == TRUE ){ + Ecsr.Dcei = 0; + } else { + Ecsr.Dcei = 1; + } + + if (HalDisablePCIParityChecking == 0xffffffff) { + Ecsr.Dpec = 1; + } else { + Ecsr.Dpec = HalDisablePCIParityChecking; + } +#if HALDBG + if (HalDisablePCIParityChecking == 0) { + DbgPrint("apecserr: PCI Parity Checking ON\n"); + } else if (HalDisablePCIParityChecking == 1) { + DbgPrint("apecserr: PCI Parity Checking OFF\n"); + } else { + DbgPrint("apecserr: PCI Parity Checking OFF - not set by ARC yet\n"); + } +#endif + + WRITE_EPIC_REGISTER( + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister, + Ecsr.all ); + + // + // Set the machine check enables with the EV4. + // + + if( ReportCorrectableErrors == TRUE ){ + HalpSetMachineCheckEnables( FALSE, FALSE, FALSE ); + } else { + HalpSetMachineCheckEnables( FALSE, TRUE, TRUE ); + } + + return; + +} + +VOID +HalpReadApecsErrorRegisters( + VOID + ) +{ + COMANCHE_EDSR Edsr; + EPIC_ECSR Ecsr; + ULONG ErrorAddress; + ULONG ErrorHighAddress; + ULONG ErrorLowAddress; + ULONG Pear; + ULONG Sear; + ULONG SystemErrorAddress; + PAPECS_UNCORRECTABLE_FRAME apecserr = NULL; + + if(PUncorrectableError){ + apecserr = (PAPECS_UNCORRECTABLE_FRAME) + PUncorrectableError->UncorrectableFrame.RawSystemInformation; + } + + if(apecserr) + HalpApecsConfig( &apecserr->Configuration); + + // + // Read both of the error registers. It is possible that more + // than one error was reported simulataneously. + // + + Edsr.all = READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorAndDiagnosticStatusRegister ); + + Ecsr.all = READ_EPIC_REGISTER( + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister ); + + + // + // Read all of the relevant error address registers. + // + + ErrorLowAddress = READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorLowAddressRegister ); + + ErrorHighAddress = READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorHighAddressRegister); + + ErrorAddress = ((ULONG)(ErrorHighAddress) << 21) + + ((ULONG)(ErrorLowAddress) << 5); + + Sear = READ_EPIC_REGISTER( + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->SysbusErrorAddressRegister ); + + SystemErrorAddress = (ULONG)(Sear) << 2; + + Pear = READ_EPIC_REGISTER( + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciErrorAddressRegister ); + + // + // Fill in the Apecs uncorrectbale frame + // + if(apecserr) + apecserr->ComancheEdsr = Edsr.all; + + if( PUncorrectableError && + ( (Edsr.Bctaperr == 1) || + (Edsr.Bctcperr == 1) || + (Edsr.Nxmerr == 1) ) ) { + PUncorrectableError->UncorrectableFrame.PhysicalAddress = + ErrorAddress; + PUncorrectableError->UncorrectableFrame.Flags. + PhysicalAddressValid = 1; + + PUncorrectableError->UncorrectableFrame.Flags.AddressSpace = + MEMORY_SPACE; + PUncorrectableError->UncorrectableFrame.Flags. + MemoryErrorSource = SYSTEM_MEMORY; + } + + if(apecserr) + apecserr->EpicEcsr = Ecsr.all; + + if( PUncorrectableError && + ( (Ecsr.Merr == 1) || + (Ecsr.Umrd == 1) ) ) { + + PUncorrectableError->UncorrectableFrame.PhysicalAddress = + SystemErrorAddress; + PUncorrectableError->UncorrectableFrame.Flags. + PhysicalAddressValid = 1; + + PUncorrectableError->UncorrectableFrame.Flags.AddressSpace = + MEMORY_SPACE; + PUncorrectableError->UncorrectableFrame.Flags. + MemoryErrorSource = SYSTEM_MEMORY; + } + + if( PUncorrectableError && + ( (Ecsr.Ndev == 1) || + (Ecsr.Tabt == 1) || + (Ecsr.Iope == 1) || + (Ecsr.Ddpe == 1) || + (Ecsr.Iptl == 1) || + (Ecsr.Iort == 1) ) ){ + + PUncorrectableError->UncorrectableFrame.PhysicalAddress = + Pear; + PUncorrectableError->UncorrectableFrame.Flags. + PhysicalAddressValid = 1; + + PUncorrectableError->UncorrectableFrame.Flags.AddressSpace = + IO_SPACE; + PUncorrectableError->UncorrectableFrame.Flags. + MemoryErrorSource = 0; + } + + if(apecserr){ + apecserr->EpicPciErrAddr = Pear; + apecserr->EpicSysErrAddr = SystemErrorAddress; + apecserr->ComancheErrAddr = ErrorAddress; + } + + return; + +} + + +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 APECS 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. + +--*/ +{ + COMANCHE_EDSR Edsr; + EPIC_ECSR Ecsr; + + PAPECS_UNCORRECTABLE_FRAME apecserr = NULL; + + // + // Check if there are any memory errors pending in the Comanche. + // + // A lost error, tag parity, tag control or non-existent memory + // error indicates a non-dismissable error. + // + + HalpReadApecsErrorRegisters(); + + if(PUncorrectableError) + apecserr = (PAPECS_UNCORRECTABLE_FRAME) + PUncorrectableError->UncorrectableFrame.RawSystemInformation; + + if(apecserr == NULL){ + Edsr.all = READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))-> + ErrorAndDiagnosticStatusRegister ); + + Ecsr.all = READ_EPIC_REGISTER( + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))-> + EpicControlAndStatusRegister ); + + } + else { + + Edsr.all = apecserr->ComancheEdsr; + + Ecsr.all = apecserr->EpicEcsr; + } + + if( (Edsr.Losterr == 1) || + (Edsr.Bctaperr == 1) || + (Edsr.Bctcperr == 1) || + (Edsr.Nxmerr == 1) ){ + + goto FatalError; + + } + + // + // Check if there are any non-recoverable I/O errors. + // + // Memory errors, invalid page table lookups, uncorrectable + // memory errors, target aborts, io parity errors, dma parity + // errors, lost errors, and retry timeouts are all considered + // non-dismissable errors. + // + + if( (Ecsr.Merr == 1) || + (Ecsr.Iptl == 1) || + (Ecsr.Umrd == 1) || + (Ecsr.Tabt == 1) || + (Ecsr.Iope == 1) || + (Ecsr.Ddpe == 1) || + (Ecsr.Iort == 1) ){ + + goto FatalError; + + } + + // + // A Pass1 APECS chip bug will erroneously report a lost operation, + // so, if a Pass1 chip, then ignore the error. + // + + if ( (Ecsr.Lost == 1) && (Ecsr.Pass2 == 1)) { + goto FatalError; + } + + // + // Check for a PCI configuration read error. An error is a + // candidate if the I/O controller has signalled a NoDevice error. + // + + if( Ecsr.Ndev == 1 ){ + + // + // 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 faulting instruction or the instruction + // previous to the faulting instruction must be a load with v0 as + // the destination register. If this condition is met then simply + // update v0 in the register set and return. However, be careful + // not to re-execute the load. + // + // jnfix - add condition to check if Rb contains the superpage + // address for config space? + + ALPHA_INSTRUCTION FaultingInstruction; + BOOLEAN PreviousInstruction = FALSE; + BOOLEAN WasLost = (Ecsr.Lost == 1 ? TRUE : FALSE); + + FaultingInstruction.Long = *(PULONG)((ULONG)TrapFrame->Fir); + if( (FaultingInstruction.Memory.Ra != V0_REG) || + (FaultingInstruction.Memory.Opcode != LDL_OP) ){ + + // + // Faulting instruction did not match, try the previous + // instruction. + // + + PreviousInstruction = TRUE; + + FaultingInstruction.Long = *(PULONG)((ULONG)TrapFrame->Fir - 4); + if( (FaultingInstruction.Memory.Ra != V0_REG) || + (FaultingInstruction.Memory.Opcode != LDL_OP) ){ + + // + // No match, we can't fix this up. + // + + goto FatalError; + } + } + + // + // 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; + + // + // If the faulting instruction was the load the restart execution + // at the instruction after the load. + // + + if( PreviousInstruction == FALSE ){ + TrapFrame->Fir += 4; + } + + // + // Clear the error condition in the ECSR. + // + + Ecsr.all = READ_EPIC_REGISTER( + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister); + + Ecsr.Ndev = 1; + Ecsr.Dcei = 1; + + if (WasLost) { + Ecsr.Lost = 1; + } + + WRITE_EPIC_REGISTER( + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister, + Ecsr.all ); + + return TRUE; + + } //endif Ecsr.Ndev == 1 + + + // + // Handle any ECC correctable errors. + // + + if( Ecsr.Cmrd ) { + + // + // Handle the error and then clear the error bit. + // + + HalpApecsCorrectableError(); + Ecsr.Cmrd = 0; + Ecsr.Lost = 0; + + // + // If there are no other outstanding errors, then return. + // + + if ( Ecsr.all ) + return TRUE; + } + + // + // A Pass1 APECS chip bug will erroneously report a lost operation, + // so, if a Pass1 chip, then ignore the error. + // + + if ( (Ecsr.Lost == 1) && (Ecsr.Pass2 == 1)) { + goto FatalError; + } + + // + // The system is not well and cannot continue reliable execution. + // Print some useful messages and return FALSE to indicate that the error + // was not handled. + // + +FatalError: + + if(PUncorrectableError) { + PUncorrectableError->UncorrectableFrame.Flags.SystemInformationValid = + 1; + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + sprintf(PUncorrectableError->UncorrectableFrame.ErrorString, + "Uncorrectable Error From Apecs Chipset Detected"); + } + + HalpApecsReportFatalError(); + + return FALSE; + +} + + +VOID +HalpApecsErrorInterrupt( + VOID + ) +/*++ + +Routine Description: + + This routine is entered as a result of an error interrupt on the + APECS chipset. This function determines if the error is fatal + or recoverable and if recoverable performs the recovery and + error logging. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + COMANCHE_EDSR Edsr; + EPIC_ECSR Ecsr; + PAPECS_UNCORRECTABLE_FRAME apecserr = NULL; + + HalpReadApecsErrorRegisters(); + + if(PUncorrectableError) + apecserr = (PAPECS_UNCORRECTABLE_FRAME) + PUncorrectableError->UncorrectableFrame.RawSystemInformation; + + if(apecserr == NULL){ + Edsr.all = READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))-> + ErrorAndDiagnosticStatusRegister ); + + Ecsr.all = READ_EPIC_REGISTER( + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))-> + EpicControlAndStatusRegister ); + + } + else { + + Edsr.all = apecserr->ComancheEdsr; + + Ecsr.all = apecserr->EpicEcsr; + } + + // + // Any error from the COMANCHE represents a fatal condition. + // + + if( (Edsr.Losterr == 1) || + (Edsr.Bctaperr == 1) || + (Edsr.Bctcperr == 1) || + (Edsr.Nxmerr == 1) ){ + + goto FatalErrorInterrupt; + + } + + // + // Almost any error from the EPIC is also fatal. The only exception + // is the correctable memory read error. Any other error is fatal. + // + + if( (Ecsr.Merr == 1) || + (Ecsr.Iptl == 1) || + (Ecsr.Umrd == 1) || + (Ecsr.Tabt == 1) || + (Ecsr.Ndev == 1) || + (Ecsr.Iope == 1) || + (Ecsr.Ddpe == 1) || + (Ecsr.Iort == 1) ){ + + goto FatalErrorInterrupt; + + } + + // + // A Pass1 APECS chip bug will erroneously report a lost operation, + // so, if a Pass1 chip, then ignore the error. + // + + if ( (Ecsr.Lost == 1) && (Ecsr.Pass2 == 1)) { + goto FatalErrorInterrupt; + } + + // + // The error may be correctable. If the correctable error bit is + // set in the ECSR then log the error and clear the condition. + // + + if( Ecsr.Cmrd == 1 ){ + + ULONG Sear; + ULONGLONG SystemErrorAddress; + + CorrectedMemoryReads += 1; + + Sear = READ_EPIC_REGISTER( + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->SysbusErrorAddressRegister ); + + SystemErrorAddress = (ULONGLONG)(Sear) << 2; + + //jnfix - temporary debug logging only +#if (DBG) || (HALDBG) + + if( (CorrectedMemoryReads % 32) == 0 ){ + DbgPrint( "APECS: CorrectedMemoryReads = %d, Address = 0x%Lx\n", + CorrectedMemoryReads, + SystemErrorAddress ); + } + +#endif //DBG || HALDBG + + // + // Clear the error condition. + // + + WRITE_EPIC_REGISTER( + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister, + Ecsr.all + ); + + return; + + } //endif Ecsr.Cmrd == 1 + +// +// The interrupt indicates a fatal system error. +// Display information about the error and shutdown the machine. +// + +FatalErrorInterrupt: + + HalpApecsReportFatalError(); + +//jnfix - add some of the address registers? +// +// Add the address of the error frame as 4th parameter. +// + KeBugCheckEx( DATA_BUS_ERROR, + Edsr.all, + Ecsr.all, + 0, + (ULONG)PUncorrectableError ); + + +} + + +VOID +HalpApecsReportFatalError( + VOID + ) +/*++ + +Routine Description: + + This function reports and interprets a fatal hardware error on + the APECS chipset. The COMANCHE Error and Diagnostic Status Register + and the EPIC Error and Status Register are read to determine how + to interpret the error. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + COMANCHE_EDSR Edsr; + EPIC_ECSR Ecsr; + ULONGLONG ErrorAddress; + ULONG ErrorHighAddress; + ULONG ErrorLowAddress; + ULONG Pear; + ULONG Sear; + ULONGLONG SystemErrorAddress; + UCHAR OutBuffer[MAX_ERROR_STRING]; + PAPECS_UNCORRECTABLE_FRAME apecserr = NULL; + PEXTENDED_ERROR PExtErr = NULL; + + // + // Begin the error output by acquiring ownership of the display + // and printing the dreaded banner. + // + + HalAcquireDisplayOwnership(NULL); + + HalDisplayString( "\nFatal system hardware error.\n\n" ); + + // + // Extract register values to report from Error Frame. + // + if(PUncorrectableError){ + apecserr = (PAPECS_UNCORRECTABLE_FRAME) + PUncorrectableError->UncorrectableFrame.RawSystemInformation; + PExtErr = &PUncorrectableError->UncorrectableFrame.ErrorInformation; + } + + if(apecserr == NULL){ + Edsr.all = READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))-> + ErrorAndDiagnosticStatusRegister ); + + Ecsr.all = READ_EPIC_REGISTER( + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))-> + EpicControlAndStatusRegister ); + + ErrorLowAddress = READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorLowAddressRegister ); + + ErrorHighAddress = READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorHighAddressRegister); + + ErrorAddress = ((ULONGLONG)(ErrorHighAddress) << 21) + + ((ULONGLONG)(ErrorLowAddress) << 5); + + Sear = READ_EPIC_REGISTER( + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->SysbusErrorAddressRegister ); + + SystemErrorAddress = (ULONGLONG)(Sear) << 2; + + Pear = READ_EPIC_REGISTER( + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciErrorAddressRegister ); + + } + else { + + Edsr.all = apecserr->ComancheEdsr; + + Ecsr.all = apecserr->EpicEcsr; + + Pear = apecserr->EpicPciErrAddr; + SystemErrorAddress = apecserr->EpicSysErrAddr; + ErrorAddress = apecserr->ComancheErrAddr; + } + + + + // + // Interpret any errors from the COMANCHE EDSR. + // + + sprintf( OutBuffer, "Comanche EDSR = 0x%x\n", Edsr.all ); + HalDisplayString( OutBuffer ); + + if( Edsr.Bctaperr == 1 ){ + + if(PExtErr){ + PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid = + 1; + + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + sprintf(PUncorrectableError->UncorrectableFrame.ErrorString, + "B-Cache Tag Address Parity Error"); + + PUncorrectableError->UncorrectableFrame.Flags.MemoryErrorSource = + SYSTEM_CACHE; + // + // At present the HalpSimm routine doesn't do anything + // it expected to be fixed in the near future. + // + PExtErr->CacheError.Flags.CacheSimmValid = 1; + PExtErr->CacheError.CacheSimm = HalpSimm(ErrorAddress); + HalpGetProcessorInfo(&PExtErr->CacheError.ProcessorInfo); + if( Edsr.Dmacause == 1 ){ + PExtErr->CacheError.TransferType = BUS_DMA_OP; + } + if( Edsr.Viccause == 1 ){ + PExtErr->CacheError.TransferType = VICTIM_WRITE; + } + + } + + sprintf( OutBuffer, + "Bcache Tag Address Parity Error, Address: %Lx, SIMM = %d\n", + ErrorAddress, HalpSimm(ErrorAddress) ); + + HalDisplayString( OutBuffer ); + + } + + if( Edsr.Bctcperr == 1 ){ + + if(PExtErr){ + PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid = + 1; + + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + sprintf(PUncorrectableError->UncorrectableFrame.ErrorString, + "B-Cache Tag Control Parity Error"); + + PUncorrectableError->UncorrectableFrame.Flags.MemoryErrorSource = + SYSTEM_CACHE; + // + // At present the HalpSimm routine doesn't do anything + // it is expected to be fixed in the near future. + // + PExtErr->CacheError.Flags.CacheSimmValid = 1; + PExtErr->CacheError.CacheSimm = HalpSimm(ErrorAddress); + HalpGetProcessorInfo(&PExtErr->CacheError.ProcessorInfo); + if( Edsr.Dmacause == 1 ){ + PExtErr->CacheError.TransferType = BUS_DMA_OP; + } + if( Edsr.Viccause == 1 ){ + PExtErr->CacheError.TransferType = VICTIM_WRITE; + } + + + } + + + sprintf( OutBuffer, + "Bcache Tag Control Parity Error, Address: %Lx, SIMM = %d\n", + ErrorAddress, HalpSimm(ErrorAddress) ); + + HalDisplayString( OutBuffer ); + + } + + if( Edsr.Nxmerr == 1 ){ + + if(PExtErr){ + PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid = + 1; + + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + sprintf(PUncorrectableError->UncorrectableFrame.ErrorString, + "Non-existent memory error"); + + PUncorrectableError->UncorrectableFrame.Flags.MemoryErrorSource = + SYSTEM_MEMORY; + // + // At present the HalpSimm routine doesn't do anything + // it expected to be fixed in the near future. + // + PExtErr->MemoryError.Flags.MemorySimmValid = 1; + PExtErr->MemoryError.MemorySimm = HalpSimm(ErrorAddress); + HalpGetProcessorInfo(&PExtErr->MemoryError.ProcessorInfo); + if( Edsr.Dmacause == 1 ){ + PExtErr->MemoryError.TransferType = BUS_DMA_OP; + } + if( Edsr.Viccause == 1 ){ + PExtErr->MemoryError.TransferType = VICTIM_WRITE; + } + + + } + + sprintf( OutBuffer, + "Non-existent memory error, Address: %Lx\n", + ErrorAddress ); + + HalDisplayString( OutBuffer ); + + } + + if( (Edsr.Bctaperr == 1) || (Edsr.Bctcperr == 1) || + (Edsr.Nxmerr == 1) ){ + + if( Edsr.Dmacause == 1 ){ + HalDisplayString( "Error caused on DMA.\n" ); + } + + if( Edsr.Viccause == 1 ){ + HalDisplayString( "Victim write caused error.\n" ); + } + + } + + if( Edsr.Losterr == 1 ){ + HalDisplayString( "Multiple Cache/Memory errors.\n" ); + } + + // + // Interpret any errors from the EPIC Ecsr. + // + + sprintf( OutBuffer, "EPIC ECSR = 0x%lx\n", Ecsr.all ); + HalDisplayString( OutBuffer ); + + if( Ecsr.Iort == 1 ){ + + if(PExtErr){ + PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid = + 1; + + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + sprintf(PUncorrectableError->UncorrectableFrame.ErrorString, + "PCI Retry timeout error"); + PExtErr->IoError.Interface = PCIBus; + + // + // Since APECS supports only one PCI Bus we will simply set + // the busnumber to 0. + // + PExtErr->IoError.BusNumber = 0; + + } + + sprintf( OutBuffer, + "PCI Retry timeout error, PCI Address: 0x%x\n", + Pear ); + HalDisplayString( OutBuffer ); + + } + + if( Ecsr.Ddpe == 1 ){ + + if(PExtErr){ + PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid = + 1; + + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + sprintf(PUncorrectableError->UncorrectableFrame.ErrorString, + "DMA Data Parity Error"); + PExtErr->IoError.Interface = PCIBus; + + // + // Since APECS supports only one PCI Bus we will simply set + // the busnumber to 0. + // + PExtErr->IoError.BusNumber = 0; + + } + sprintf( OutBuffer, + "DMA Data Parity Error at PCI Address: 0x%x\n", + Pear ); + HalDisplayString( OutBuffer ); + + } + + if( Ecsr.Iope == 1 ){ + + if(PExtErr){ + PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid = + 1; + + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + sprintf(PUncorrectableError->UncorrectableFrame.ErrorString, + "I/O Data Parity Error"); + PExtErr->IoError.Interface = PCIBus; + + // + // Since APECS supports only one PCI Bus we will simply set + // the busnumber to 0. + // + PExtErr->IoError.BusNumber = 0; + + } + sprintf( OutBuffer, + "I/O Data Parity Error at PCI Address: 0x%x\n", + Pear ); + HalDisplayString( OutBuffer ); + + } + + if( Ecsr.Tabt == 1 ){ + + if(PExtErr){ + PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid = + 1; + + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + sprintf(PUncorrectableError->UncorrectableFrame.ErrorString, + "Target Abort Error"); + PExtErr->IoError.Interface = PCIBus; + + // + // Since APECS supports only one PCI Bus we will simply set + // the busnumber to 0. + // + PExtErr->IoError.BusNumber = 0; + + } + sprintf( OutBuffer, + "Target Abort Error at PCI Address: 0x%x\n", + Pear ); + HalDisplayString( OutBuffer ); + + } + + if( Ecsr.Ndev == 1 ){ + + if(PExtErr){ + PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid = + 1; + + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + sprintf(PUncorrectableError->UncorrectableFrame.ErrorString, + "No Device Error"); + PExtErr->IoError.Interface = PCIBus; + + // + // Since APECS supports only one PCI Bus we will simply set + // the busnumber to 0. + // + PExtErr->IoError.BusNumber = 0; + + } + sprintf( OutBuffer, + "No Device Error at PCI Address: 0x%x\n", + Pear ); + HalDisplayString( OutBuffer ); + + } + + if( Ecsr.Iptl == 1 ){ + + if(PExtErr){ + PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid = + 1; + + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + sprintf(PUncorrectableError->UncorrectableFrame.ErrorString, + "Invalid Page Table Lookup"); + PExtErr->IoError.Interface = PCIBus; + + // + // Since APECS supports only one PCI Bus we will simply set + // the busnumber to 0. + // + PExtErr->IoError.BusNumber = 0; + + } + sprintf( OutBuffer, + "Invalid Page Table Lookup at PCI Address: 0x%x\n", + Pear ); + HalDisplayString( OutBuffer ); + + } + + if( Ecsr.Umrd == 1 ){ + + if(PExtErr){ + PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid = + 1; + + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + sprintf(PUncorrectableError->UncorrectableFrame.ErrorString, + "memory read error"); + + PUncorrectableError->UncorrectableFrame.Flags.MemoryErrorSource = + SYSTEM_MEMORY; + // + // At present the HalpSimm routine doesn't do anything + // it expected to be fixed in the near future. + // + PExtErr->MemoryError.Flags.MemorySimmValid = 1; + PExtErr->MemoryError.MemorySimm = HalpSimm(ErrorAddress); + HalpGetProcessorInfo(&PExtErr->MemoryError.ProcessorInfo); + + + } + sprintf( OutBuffer, + "Uncorrectable memory read error, System Address: 0x%Lx\n", + SystemErrorAddress ); + HalDisplayString( OutBuffer ); + + } + + + if( Ecsr.Merr == 1 ){ + + sprintf( OutBuffer, + "Memory error, System Address: 0x%Lx\n", + SystemErrorAddress ); + HalDisplayString( OutBuffer ); + + } + + if( Ecsr.Lost == 1 ){ + HalDisplayString( "Multiple I/O errors detected.\n" ); + } + + return; + +} + +ULONG +HalpSimm( + ULONGLONG Address + ) +/*++ + +Routine Description: + + Return the number of the SIMM corresponding to the supplied physical + address. + +Arguments: + + Address - Supplies the physical address of a byte in memory. + +Return Value: + + The number of the SIMM that contains the byte of physical memory is + returned. If the Address does not fit within a SIMM or the SIMM number + cannot be determined 0xffffffff is returned. + +--*/ +{ + +//jnfix - see if this can be determined exclusively from memory registers +//jnfix - or is this platform-dependent + + return( 0xffffffff ); + +} + + +VOID +HalpApecsCorrectableError( + VOID + ) +/*++ + +Routine Description: + + Handle ECC correctable errors from the APECS. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + static ERROR_FRAME Frame; + static APECS_CORRECTABLE_FRAME ApecsFrame; + + ERROR_FRAME TempFrame; + PCORRECTABLE_ERROR CorrPtr; + PBOOLEAN ErrorlogBusy; + PULONG DispatchCode; + PKINTERRUPT InterruptObject; + PKSPIN_LOCK ErrorlogSpinLock; + EPIC_ECSR Ecsr; + ULONG Sear; + ULONGLONG SystemErrorAddress; + + // + // Read the Epic control and status register. + // + + Ecsr.all = READ_EPIC_REGISTER( + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister ); + + // + // Get the system address. Note, bits 2-4 of the address not available. + // + + Sear = READ_EPIC_REGISTER( + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->SysbusErrorAddressRegister ); + + SystemErrorAddress = (ULONGLONG)Sear << 2; + +#if (DBG) || (HALDBG) + + if( (CorrectedMemoryReads % 32) == 0 ){ + DbgPrint("APECS: CorrectedMemoryReads = %d, Address = 0x%Lx\n", + CorrectedMemoryReads, + SystemErrorAddress ); + } + +#endif + + // + // Get the interrupt object. + // + + DispatchCode = (PULONG)(PCR->InterruptRoutine[CORRECTABLE_VECTOR]); + InterruptObject = CONTAINING_RECORD(DispatchCode, + KINTERRUPT, + DispatchCode); + + // + // Set various pointers so we can use them later. + // + + CorrPtr = &TempFrame.CorrectableFrame; + ErrorlogBusy = (PBOOLEAN)((PUCHAR)InterruptObject->ServiceContext + + sizeof(PERROR_FRAME)); + ErrorlogSpinLock = (PKSPIN_LOCK)((PUCHAR)ErrorlogBusy + sizeof(PBOOLEAN)); + + // + // Update the number of correctable errors. + // + + CorrectedMemoryReads += 1; + + // + // Clear the data structures that we will use. + // + + RtlZeroMemory(&TempFrame, sizeof(ERROR_FRAME)); + + // + // Fill in the error frame information. + // + + TempFrame.Signature = ERROR_FRAME_SIGNATURE; + TempFrame.FrameType = CorrectableFrame; + TempFrame.VersionNumber = ERROR_FRAME_VERSION; + TempFrame.SequenceNumber = CorrectedMemoryReads; + TempFrame.PerformanceCounterValue = + KeQueryPerformanceCounter(NULL).QuadPart; + + // + // Check for lost error. + // + + if( Ecsr.Lost ) { + + // + // Since the error registers are locked from a previous error, + // we don't know where the error came from. Mark everything + // as UNIDENTIFIED. + // + + CorrPtr->Flags.LostCorrectable = 1; + CorrPtr->Flags.LostAddressSpace = UNIDENTIFIED; + CorrPtr->Flags.LostMemoryErrorSource = UNIDENTIFIED; + } + + // + // Either a DMA read or DMA TLB read ECC error. We can't tell + // since the EPIC chip doesn't provid enough information. Just + // log everything as a DMA ECC error. + // + + CorrPtr->Flags.AddressSpace = MEMORY_SPACE; + CorrPtr->Flags.ExtendedErrorValid = 1; + CorrPtr->Flags.MemoryErrorSource = SYSTEM_MEMORY; + CorrPtr->ErrorInformation.MemoryError.TransferType = BUS_DMA_READ; + + // + // Get the physical address where the error occurred. + // + + CorrPtr->Flags.PhysicalAddressValid = 1; + CorrPtr->PhysicalAddress = SystemErrorAddress; + + // + // Scrub the error if it's any type of memory error. + // + + if (CorrPtr->Flags.AddressSpace == MEMORY_SPACE && + CorrPtr->Flags.PhysicalAddressValid ) + CorrPtr->Flags.ScrubError = 1; + + // + // Acquire the spinlock. + // + + KiAcquireSpinLock(ErrorlogSpinLock); + + // + // Check to see if an errorlog operation is in progress already. + // + + if (!*ErrorlogBusy) { + + // + // The error is expected to be a corrected ECC error on a DMA or + // Scatter/Gather TLB read. Read the error registers relevant + // to this error. + // + + ApecsFrame.EpicEcsr = Ecsr.all; + + ApecsFrame.EpicSysErrAddr = Sear; + + // + // Read the CIA configuration registers for logging information. + // + + ApecsFrame.Configuration.ApecsRev = Ecsr.Pass2; + HalpApecsConfig( &ApecsFrame.Configuration ); + + // + // Set the raw system information. + // + + CorrPtr->RawSystemInformationLength = sizeof(APECS_CORRECTABLE_FRAME); + CorrPtr->RawSystemInformation = &ApecsFrame; + + // + // Set the raw processor information. Disregard at the moment. + // + + CorrPtr->RawProcessorInformationLength = 0; + + // + // Set reporting processor information. Disregard at the moment. + // + + CorrPtr->Flags.ProcessorInformationValid = 0; + + // + // Set system information. Disregard at the moment. + // + + CorrPtr->Flags.SystemInformationValid = 0; + + // + // Copy the information that we need to log. + // + + RtlCopyMemory(&Frame, + &TempFrame, + sizeof(ERROR_FRAME)); + + // + // Put frame into ISR service context. + // + + *(PERROR_FRAME *)InterruptObject->ServiceContext = &Frame; + + } else { + + // + // An errorlog operation is in progress already. We will + // set various lost bits and then get out without doing + // an actual errorloging call. + // + + Frame.CorrectableFrame.Flags.LostCorrectable = TRUE; + Frame.CorrectableFrame.Flags.LostAddressSpace = + TempFrame.CorrectableFrame.Flags.AddressSpace; + Frame.CorrectableFrame.Flags.LostMemoryErrorSource = + TempFrame.CorrectableFrame.Flags.MemoryErrorSource; + } + + // + // Release the spinlock. + // + + KiReleaseSpinLock(ErrorlogSpinLock); + + // + // 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 lost and correctable error bit. + // + + if (Ecsr.Lost) { + + Ecsr.all = 0; + Ecsr.Cmrd = 1; + Ecsr.Lost = 1; + + } else { + + Ecsr.all = 0; + Ecsr.Cmrd = 1; + } + + WRITE_EPIC_REGISTER( + &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister, + Ecsr.all); + + return; +} + + +VOID +HalpApecsConfig( + PAPECS_CONFIGURATION Config + ) +/*++ + +Routine Description: + + Reads in the configuration registers from the Comanche chip. + +Arguments: + + Pointer to the configuration frame. + +Return Value: + + None. + +--*/ +{ + // + // Read in all the registers. + // + + Config->CGcr = + READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->GeneralControlRegister + ); + + Config->CTer = + READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->TagEnableRegister + ); + + Config->CGtr = + READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->GlobalTimingRegister + ); + + Config->CRtr = + READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->RefreshTimingRegister + ); + + Config->CBank0 = + READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank0ConfigurationRegister + ); + + Config->CBank1 = + READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank1ConfigurationRegister + ); + + Config->CBank2 = + READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank2ConfigurationRegister + ); + + Config->CBank3 = + READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank3ConfigurationRegister + ); + + Config->CBank4 = + READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank4ConfigurationRegister + ); + + Config->CBank5 = + READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank5ConfigurationRegister + ); + + Config->CBank6 = + READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank6ConfigurationRegister + ); + + Config->CBank7 = + READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank7ConfigurationRegister + ); + + Config->CBank8 = + READ_COMANCHE_REGISTER( + &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank8ConfigurationRegister + ); +} diff --git a/private/ntos/nthals/halalpha/apecsio.s b/private/ntos/nthals/halalpha/apecsio.s new file mode 100644 index 000000000..9ae932d10 --- /dev/null +++ b/private/ntos/nthals/halalpha/apecsio.s @@ -0,0 +1,701 @@ + +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + apecsio.s + + +Abstract: + + This contains assembler code routines for the Alpha AXP Eval Board eb64+. + + 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. + (We are using EV4 64-bit superpage mode.) + +Author: + + Joe Notarangelo 25-Oct-1993 + +Environment: + + Executes in kernel mode. + +Revision History: + + Sameer Dekate 28-July-1994 + + Made a common file alphaio.s for machine independent routines. + + +--*/ + +#include "apecs.h" +#include "halalpha.h" + + + + SBTTL( "Write Control Register" ) +//++ +// +// VOID +// WRITE_EPIC_REGISTER( +// IN PVOID RegisterQva, +// IN ULONG Value +// ) +// +// Routine Description: +// +// Write a control register in the APECS memory or PCI controller +// (COMANCHE and EPIC respectively). +// +// Arguments: +// +// RegisterQva(a0) - QVA of control register to be written. +// +// Value(a1) - Longword value to be written to the control register. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(WRITE_EPIC_REGISTER) + + ALTERNATE_ENTRY(WRITE_COMANCHE_REGISTER) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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, 5, t0 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + or t0, t4, t0 // superpage mode + + .set volatile + + stl a1, (t0) // write the longword + ldl t4, (t0) // read the the longword, to force + // consistency (EPIC chip bug). + mb // order the write + .set novolatile + + ret zero, (ra) // return + +2: // flag bad QVAs + BREAK_DEBUG_STOP // take a breakpoint + ret zero, (ra) // return + + .end WRITE_EPIC_REGISTER + + + SBTTL( "Read Control Register" ) +//++ +// +// ULONG +// READ_EPIC_REGISTER( +// IN PVOID RegisterQva +// ) +// +// Routine Description: +// +// Read a control register in the APECS memory or PCI controller +// (COMANCHE and EPIC respectively). +// +// Arguments: +// +// RegisterQva(a0) - QVA of control register to be written. +// +// Return Value: +// +// v0 - Return the value read from the control register. +// +//-- + + LEAF_ENTRY(READ_EPIC_REGISTER) + + ALTERNATE_ENTRY(READ_COMANCHE_REGISTER) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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, 5, t0 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + or t0, t4, t0 // superpage mode + + ldl v0, (t0) // read the register + + ret zero, (ra) // return + +2: // flag bad QVAs + BREAK_DEBUG_STOP // take a breakpoint + + ret zero, (ra) // return + + .end READ_EPIC_REGISTER + + +// +// Values and structures used to access configuration space. +// + +// +// Define the QVA for the Configuration Cycle Type register within the +// IOC. Physical Address = 1 A000 01C0 +// + +#define EPIC_HAXR2_QVA (0xad00000e) + +// +// Define the configuration routines stack frame. +// + + .struct 0 +CfgRa: .space 8 // return address +CfgA0: .space 8 // saved ConfigurationAddress +CfgA1: .space 8 // saved ConfigurationData/CycleType +CfgA2: .space 8 // saved ConfigurationCycleType +CfgFrameLength: + + +//++ +// +// 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) +// +//-- + + NESTED_ENTRY( READ_CONFIG_UCHAR, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Merge the configuration cycle type into the HAXR2 register within +// the EPIC. +// + + stq a0, CfgA0(sp) // save configuration space address + stq a1, CfgA1(sp) // save configuration cycle type + + ldil a0, EPIC_HAXR2_QVA // address of HAXR2 + bsr ra, READ_EPIC_REGISTER // read current value + + ldq a1, CfgA1(sp) // restore configuration cycle type + bic v0, 0x3, t0 // clear config cycle type field + bis a1, t0, a1 // merge config cycle type + ldil a0, EPIC_HAXR2_QVA // address of HAXR2 + bsr ra, WRITE_EPIC_REGISTER // write updated HAXR2 + +// +// Perform the read from configuration space after restoring the +// configuration space address. +// + + ldq a0, CfgA0(sp) // restore configuration space address + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 0x3, t3 // capture byte lane + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + bis t0, t4, t0 // superpage mode + + bis t0, IO_BYTE_LEN, t0 // or in the byte enables + + ldl v0, (t0) // read the longword + extbl v0, t3, v0 // return byte from requested lane + // also, consume loaded value to cause + // a pipeline stall +2: // + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + ret zero, (ra) // return + + .end READ_CONFIG_UCHAR + +//++ +// +// VOID +// WRITE_CONFIG_UCHAR( +// ULONG ConfigurationAddress, +// UCHAR ConfigurationData, +// ULONG ConfigurationCycleType +// ) +// +// Routine Description: +// +// Read an unsigned byte from PCI configuration space. +// +// Arguments: +// +// ConfigurationAddress(a0) - Supplies the QVA to write. +// +// 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. +// +//-- + + NESTED_ENTRY( WRITE_CONFIG_UCHAR, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Merge the configuration cycle type into the HAXR2 register within +// the EPIC. +// + + stq a0, CfgA0(sp) // save configuration space address + stq a1, CfgA1(sp) // save configuration data + stq a2, CfgA2(sp) // save configuration cycle type + + ldil a0, EPIC_HAXR2_QVA // address of HAXR2 + bsr ra, READ_EPIC_REGISTER // read current value + + ldq a1, CfgA2(sp) // restore configuration cycle type + bic v0, 0x3, t0 // clear config cycle type field + bis a1, t0, a1 // merge config cycle type + ldil a0, EPIC_HAXR2_QVA // address of HAXR2 + bsr ra, WRITE_EPIC_REGISTER // write updated HAXR2 + +// +// Perform the read from configuration space after restoring the +// configuration space address and data. +// + + ldq a0, CfgA0(sp) // restore configuration space address + ldq a1, CfgA1(sp) // restore configuration data + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 0x3, t3 // capture byte lane + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + bis t0, t4, t0 // superpage mode + + bis t0, IO_BYTE_LEN, t0 // or in the byte length indicator + + insbl a1, t3, t4 // put byte in the appropriate lane + stl t4, (t0) // write the configuration byte + mb // synchronize + +2: // + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + ret zero, (ra) // return + + .end WRITE_CONFIG_UCHAR + +//++ +// +// ULONG +// READ_CONFIG_USHORT( +// ULONG ConfigurationAddress, +// ULONG ConfigurationCycleType +// ) +// +// Routine Description: +// +// Read a longword from PCI configuration space. +// +// Arguments: +// +// ConfigurationAddress(a0) - Supplies the QVA of quadword 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) +//-- + + NESTED_ENTRY( READ_CONFIG_USHORT, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Merge the configuration cycle type into the HAXR2 register within +// the EPIC. +// + + stq a0, CfgA0(sp) // save configuration space address + stq a1, CfgA1(sp) // save configuration cycle type + + ldil a0, EPIC_HAXR2_QVA // address of HAXR2 + bsr ra, READ_EPIC_REGISTER // read current value + + ldq a1, CfgA1(sp) // restore configuration cycle type + bic v0, 0x3, t0 // clear config cycle type field + bis a1, t0, a1 // merge config cycle type + ldil a0, EPIC_HAXR2_QVA // address of HAXR2 + bsr ra, WRITE_EPIC_REGISTER // write updated HAXR2 + +// +// Perform the read from configuration space after restoring the +// configuration space address. +// + + ldq a0, CfgA0(sp) // restore configuration space address + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 0x3, t3 // capture word offset + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + bis t0, t4, t0 // superpage mode + + bis t0, IO_WORD_LEN, t0 // or in the byte enables + + ldl v0, (t0) // read the longword + extwl v0, t3, v0 // return word from requested lanes + // also, consume loaded value to cause + // a pipeline stall +2: // + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + ret zero, (ra) // return + + .end READ_CONFIG_USHORT + +//++ +// +// VOID +// WRITE_CONFIG_USHORT( +// ULONG ConfigurationAddress, +// USHORT ConfigurationData, +// ULONG ConfigurationCycleType +// ) +// +// Routine Description: +// +// Read a longword from PCI configuration space. +// +// Arguments: +// +// ConfigurationAddress(a0) - Supplies the QVA to write. +// +// 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. +// +//-- + + NESTED_ENTRY( WRITE_CONFIG_USHORT, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Merge the configuration cycle type into the HAXR2 register within +// the EPIC. +// + + stq a0, CfgA0(sp) // save configuration space address + stq a1, CfgA1(sp) // save configuration data + stq a2, CfgA2(sp) // save configuration cycle type + + ldil a0, EPIC_HAXR2_QVA // address of HAXR2 + bsr ra, READ_EPIC_REGISTER // read current value + + ldq a1, CfgA2(sp) // restore configuration cycle type + bic v0, 0x3, t0 // clear config cycle type field + bis a1, t0, a1 // merge config cycle type + ldil a0, EPIC_HAXR2_QVA // address of HAXR2 + bsr ra, WRITE_EPIC_REGISTER // write updated HAXR2 + +// +// Perform the read from configuration space after restoring the +// configuration space address and data. +// + + ldq a0, CfgA0(sp) // restore configuration space address + ldq a1, CfgA1(sp) // restore configuration data + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 0x3, t3 // capture word offset + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + bis t0, t4, t0 // superpage mode + + bis t0, IO_WORD_LEN, t0 // or in the byte enables + + inswl a1, t3, t4 // put data to appropriate lane + stl t4, (t0) // read the longword + mb // synchronize +2: // + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + 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 quadword 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) +//-- + + NESTED_ENTRY( READ_CONFIG_ULONG, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Merge the configuration cycle type into the HAXR2 register within +// the EPIC. +// + + stq a0, CfgA0(sp) // save configuration space address + stq a1, CfgA1(sp) // save configuration cycle type + + ldil a0, EPIC_HAXR2_QVA // address of HAXR2 + bsr ra, READ_EPIC_REGISTER // read current value + + ldq a1, CfgA1(sp) // restore configuration cycle type + bic v0, 0x3, t0 // clear config cycle type field + bis a1, t0, a1 // merge config cycle type + ldil a0, EPIC_HAXR2_QVA // address of HAXR2 + bsr ra, WRITE_EPIC_REGISTER // write updated HAXR2 + +// +// Perform the read from configuration space after restoring the +// configuration space address. +// + + ldq a0, CfgA0(sp) // restore configuration space address + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + or t0, t4, t0 // superpage mode + + or t0, IO_LONG_LEN, t0 // or in the byte enables + + ldl v0, (t0) // read the longword + bis v0, zero, t1 // consume loaded value to cause + // a pipeline stall +2: // + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + 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 to write. +// +// 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. +// +//-- + + NESTED_ENTRY( WRITE_CONFIG_ULONG, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Merge the configuration cycle type into the HAXR2 register within +// the EPIC. +// + + stq a0, CfgA0(sp) // save configuration space address + stq a1, CfgA1(sp) // save configuration data + stq a2, CfgA2(sp) // save configuration cycle type + + ldil a0, EPIC_HAXR2_QVA // address of HAXR2 + bsr ra, READ_EPIC_REGISTER // read current value + + ldq a1, CfgA2(sp) // restore configuration cycle type + bic v0, 0x3, t0 // clear config cycle type field + bis a1, t0, a1 // merge config cycle type + ldil a0, EPIC_HAXR2_QVA // address of HAXR2 + bsr ra, WRITE_EPIC_REGISTER // write updated HAXR2 + +// +// Perform the read from configuration space after restoring the +// configuration space address and data. +// + + ldq a0, CfgA0(sp) // restore configuration space address + ldq a1, CfgA1(sp) // restore configuration data + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + bis t0, t4, t0 // superpage mode + + bis t0, IO_LONG_LEN, t0 // or in the byte enables + + stl a1, (t0) // write the longword + mb // synchronize +2: // + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + ret zero, (ra) // return + + .end WRITE_CONFIG_ULONG diff --git a/private/ntos/nthals/halalpha/axintsup.c b/private/ntos/nthals/halalpha/axintsup.c new file mode 100644 index 000000000..031241f5d --- /dev/null +++ b/private/ntos/nthals/halalpha/axintsup.c @@ -0,0 +1,763 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + eisasup.c + +Abstract: + + The module provides the EISA bus support for Alpha systems. + +Author: + + Jeff Havens (jhavens) 19-Jun-1991 + Miche Baker-Harvey (miche) 13-May-1992 + Jeff McLeman (DEC) 1-Jun-1992 + +Revision History: + + 11-Mar-1993 Joe Mitchell (DEC) + Added support for NMI interrupts: Added interrupt service routine + HalHandleNMI. Added code to HalpCreateEisaStructures to initialize + NMI interrupts. + + 22-Jul-1992 Jeff McLeman (mcleman) + Removed eisa xfer routines, since this is done in JXHWSUP + + 02-Jul-92 Jeff McLeman (mcleman) + Removed alphadma.h header file. This file was not needed since + the DMA structure is described in the eisa header. Also add + a note describing eisa references in this module. + + 13-May-92 Stole file jxebsup.c and converted for Alpha/Jensen + + +--*/ + + +#include "halp.h" +#include "eisa.h" + +// +// Define the context structure for use by the interrupt routine. +// + +typedef BOOLEAN (*PSECONDARY_DISPATCH)( + PVOID InterruptRoutine, + PKTRAP_FRAME TrapFrame + ); + +// +// Declare the interupt structure and spinlock for the intermediate EISA +// interrupt dispachter. +// + +KINTERRUPT HalpEisaInterrupt; + +/* [jrm 3/8/93] Add support for NMI interrupts */ + +// +// 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; + +UCHAR EisaNMIMsg[] = "NMI: Eisa IOCHKERR board x\n"; + +// +// The following function is called when an EISA NMI occurs. +// + +BOOLEAN +HalHandleNMI( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + +// +// Define save area for EISA interrupt mask registers and level\edge control +// registers. +// + +UCHAR HalpEisaInterrupt1Mask; +UCHAR HalpEisaInterrupt2Mask; +UCHAR HalpEisaInterrupt1Level; +UCHAR HalpEisaInterrupt2Level; + + +BOOLEAN +HalpInitializeEisaInterrupts ( +//HalpCreateEisaStructures ( + VOID + ) + +/*++ + +Routine Description: + + This routine initializes the structures necessary for EISA operations + and connects the intermediate interrupt dispatcher. It also initializes the + EISA interrupt controller. + +Arguments: + + None. + +Return Value: + + If the second level interrupt dispatcher is connected, then a value of + TRUE is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + + UCHAR DataByte; + KIRQL oldIrql; + + // + // Initialize the EISA 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 + ); + + // + // Enable Software-Generated NMI interrupts by setting bit 1 of port 0x461. + // + + DataByte = 0x02; + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl, + DataByte + ); + + // + // Initialize the EISA interrupt dispatcher for EISA I/O interrupts. + // + + KeInitializeInterrupt( &HalpEisaInterrupt, + HalpEisaInterruptHandler, + (PVOID) HalpEisaIntAckBase, + (PKSPIN_LOCK)NULL, + PIC_VECTOR, + EISA_DEVICE_LEVEL, + EISA_DEVICE_LEVEL, + LevelSensitive, + TRUE, + 0, + FALSE + ); + + if (!KeConnectInterrupt( &HalpEisaInterrupt )) { + + return(FALSE); + } + + // + // Raise the IRQL while the EISA interrupt controller is initalized. + // + + KeRaiseIrql(EISA_DEVICE_LEVEL, &oldIrql); + + + // + // Initialize the EISA interrupt controller. There are two cascaded + // interrupt controllers, each of which must initialized with 4 initialize + // 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 iterrupt 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 thrid initialization control word set the controls for slave mode. + // The master ICW3 uses bit position and the slave ICW3 uses a numberic. + // + + 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 = ~(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; + + // + // Restore IRQL level. + // + + KeLowerIrql(oldIrql); + + // + // Initialize the 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); +} + +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 EISA + controller. + + This service routine should be connected as follows: + + KeInitializeInterrupt(&Interrupt, HalpEisaDispatch, + EISA_VIRTUAL_BASE, + (PKSPIN_LOCK)NULL, EISA_LEVEL, EISA_LEVEL, EISA_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 interruptVector; + PKPRCB Prcb; + BOOLEAN returnValue; + USHORT PCRInOffset; + UCHAR Int1Isr; + UCHAR Int2Isr; + + // + // Acknowledge the Interrupt controller and receive the returned + // interrupt vector. + // + + interruptVector = HalpAcknowledgeEisaInterrupt(ServiceContext); + + + if ((interruptVector & 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; + + } + + + } + + // + // Dispatch to the secondary interrupt service routine. + // + PCRInOffset = interruptVector + EISA_VECTORS; + + + returnValue = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[PCRInOffset])( + PCR->InterruptRoutine[PCRInOffset], + TrapFrame + ); + + // + // Dismiss the interrupt in the EISA interrupt controllers. + // + + // + // If this is a cascaded interrupt then the interrupt must be dismissed in + // both controlles. + // + + if (interruptVector & 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); + +} + +VOID +HalpDisableEisaInterrupt( + IN ULONG Vector + ) + +/*++ + +Routine Description: + + This function Disables the EISA bus specified EISA bus interrupt. + +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 in 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 bus specified EISA bus interrupt and sets + the level/edge register to the requested value. + +Arguments: + + Vector - Supplies the vector of the ESIA 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 +HalHandleNMI( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ) +/*++ + +Routine Description: + + This function is called when an EISA NMI occurs. It print 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; + UCHAR EisaPort; + ULONG port; + ULONG AddressSpace = 1; // 1 = I/O address space + BOOLEAN Status; + PHYSICAL_ADDRESS BusAddress; + PHYSICAL_ADDRESS TranslatedAddress; + + 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"); + } + + // + // This is an Eisa machine, check for extnded nmi information... + // + + StatusByte = READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl); + + if (StatusByte & 0x80) { + HalDisplayString ("NMI: Fail-safe timer\n"); + } + + if (StatusByte & 0x40) { + HalDisplayString ("NMI: Bus Timeout\n"); + } + + if (StatusByte & 0x20) { + HalDisplayString ("NMI: Software NMI generated\n"); + } + + // + // Look for any Eisa expansion board. See if it asserted NMI. + // + + BusAddress.HighPart = 0; + + for (EisaPort = 0; EisaPort <= 0xf; EisaPort++) + { + BusAddress.LowPart = (EisaPort << 12) + 0xC80; + + Status = HalTranslateBusAddress(Eisa, // InterfaceType + 0, // BusNumber + BusAddress, + &AddressSpace, // 1=I/O address space + &TranslatedAddress); // QVA + if (Status == FALSE) + { + UCHAR pbuf[80]; + sprintf(pbuf, + "Unable to translate bus address %x for EISA slot %d\n", + BusAddress.LowPart, EisaPort); + HalDisplayString(pbuf); + KeBugCheck(NMI_HARDWARE_FAILURE); + } + + port = TranslatedAddress.LowPart; + + WRITE_PORT_UCHAR ((PUCHAR) port, 0xff); + StatusByte = READ_PORT_UCHAR ((PUCHAR) port); + + if ((StatusByte & 0x80) == 0) { + // + // Found valid Eisa board, Check to see if it's + // if IOCHKERR is asserted. + // + + StatusByte = READ_PORT_UCHAR ((PUCHAR) port+4); + if (StatusByte & 0x2) { + EisaNMIMsg[25] = (EisaPort > 9 ? 'A'-10 : '0') + EisaPort; + HalDisplayString (EisaNMIMsg); + } + } + } + +#if 0 + // Reset NMI interrupts (for debugging purposes only). + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl, 0x00); + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl, 0x02); +#endif + + KeBugCheck(NMI_HARDWARE_FAILURE); + return(TRUE); +} diff --git a/private/ntos/nthals/halalpha/bios.c b/private/ntos/nthals/halalpha/bios.c new file mode 100644 index 000000000..52b5dc898 --- /dev/null +++ b/private/ntos/nthals/halalpha/bios.c @@ -0,0 +1,105 @@ +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + bios.c + +Abstract: + + This module implements ROM BIOS call support for Alpha AXP NT. + +Author: + + Eric Rehm (rehm@zso.dec.com) 9-December-1993 + + +Revision History: + +--*/ + +#include "halp.h" +#include "arccodes.h" +#include "alpharef.h" +#include "fwcallbk.h" + + +// +// Static data. +// +// none. + + +BOOLEAN +HalCallBios ( + IN ULONG BiosCommand, + IN OUT PULONG pEax, + IN OUT PULONG pEbx, + IN OUT PULONG pEcx, + IN OUT PULONG pEdx, + IN OUT PULONG pEsi, + IN OUT PULONG pEdi, + IN OUT PULONG pEbp + ) + +/*++ + +Routine Description: + + This function invokes specified ROM BIOS code by executing + "INT BiosCommand." A callback to the i386 emulator loaded by + the firmware accomplishes this task. This function always + returns success reguardless of the result of the BIOS call. + + +Arguments: + + BiosCommand - specifies which ROM BIOS function to invoke. + + BiosArguments - specifies a pointer to the context which will be used + to invoke ROM BIOS. + +Return Value: + + TRUE if function succees, FALSE otherwise. + +--*/ +{ + + X86_BIOS_ARGUMENTS context; + + context.Edi = *pEdi; + context.Esi = *pEsi; + context.Eax = *pEax; + context.Ebx = *pEbx; + context.Ecx = *pEcx; + context.Edx = *pEdx; + context.Ebp = *pEbp; + + // + // Now call the firmware to actually perform the int 10 operation. + // + + VenCallBios(BiosCommand, &context); + + // + // fill in struct with any return values from the context + // + + *pEdi = context.Edi; + *pEsi = context.Esi; + *pEax = context.Eax; + *pEbx = context.Ebx; + *pEcx = context.Ecx; + *pEdx = context.Edx; + *pEbp = context.Ebp; + + + // + // Indicate success + // + + return TRUE; +} + diff --git a/private/ntos/nthals/halalpha/cache.c b/private/ntos/nthals/halalpha/cache.c new file mode 100644 index 000000000..c9d997f70 --- /dev/null +++ b/private/ntos/nthals/halalpha/cache.c @@ -0,0 +1,225 @@ +/*++ + +Copyright (c) 1996 Digital Equipment Corporation + +Module Name: + + cache.c + +Abstract: + + Provides routine to compute the backup cache size + +Author: + + Bala Nagarajan 5-Jan-1996 + Adopted from Mark Baxter's user level code. + +Environment: + + Phase 0 initialization only + Also Called from the firmware. + +--*/ + +#include "halp.h" + + + +#define __1KB (1024) +#define __128KB (128 * 1024) + +#define THRESHOLD_RPCC_PERCENT 120 // percent value + +static +ULONG +HalpTimeTheBufferAccess( + PUCHAR DataBuffer, + ULONG NumberOfAccess, + ULONG CacheSizeLimit, + ULONG CacheStride + ) +/*++ + +Routine Description : + + This function times the main loop that the HalpGetBCacheSize uses. + This is a separate function because we want to time the + access accurately with exactly one load in the loop. + +Arguments: + + DataBuffer - Start address of the buffer. + + NumberOfAccess - Total Nubmer of Access that needs to be made + + CacheSizeLimit - The Current Cache size that is being checked + + CacheStride - The stride value to access the buffer. + +Return Value: + + The time taken to access the buffer with specified number of access. + +--*/ +{ + ULONG MemoryLocation; + ULONG CacheSizeMask; + ULONG startRpcc; + ULONG endRpcc; + + for(MemoryLocation = 0; MemoryLocation < CacheSizeLimit ; + MemoryLocation += CacheStride){ + *(volatile ULONG * const)(&DataBuffer[MemoryLocation]) ; + } + + CacheSizeMask = CacheSizeLimit - 1; + + startRpcc = __RCC(); + for ( MemoryLocation = 0; + NumberOfAccess > 0; + NumberOfAccess--, MemoryLocation += CacheStride) { + *(volatile LONG *)&(DataBuffer[MemoryLocation & CacheSizeMask] ); + } + endRpcc = __RCC(); + + return (endRpcc - startRpcc); + +} + + +ULONG +HalpGetBCacheSize( + ULONGLONG ContiguousPhysicalMemorySize + ) +/*++ + +Routine Description: + + This function computes the size of the direct mapped backup cache. + + This code checks for cache sizes from 128KB to the physical memory + size in steps of multiple of 2. In systems that has no cache or cache + larger than physical memory (!!) this algorithm will report the cache + size to be Zero. Since the cache size + is now being used only for the Secondary Page Coloring mechanism, and + since page coloring mechanism does not make any sense in a machine + without a direct mapped backup cache, the size of the cache does not + really affect system performance in any way. + [Note: Page Coloring Mechanism is used to reduce cache conflicts + between adjacent pages of a process in a direct mapped backup cache.] + In case where the cache is larger than memory itself (!!!! How often + have you encountered such a machine??), I think the entire page + coloring mechanism can break. Because you now have more colors + than total number of pages, meaning, there are some colors which + has no pages. + +Arguments: + + ContiguousPhysicalMemorySize - The size of the physical memory. + +Return Value: + + The size of the Backup cache in Bytes. + +--*/ +{ + ULONG CacheSizeLimit = 128*__1KB; + ULONG NumberOfAccess; + ULONG CacheStride = 32*__1KB ; + ULONG CacheSize; + ULONG BaseLineElapsedRpcc; + ULONG ThresholdRpcc; + ULONG CurSizeElapsedRpcc; + PUCHAR DataBuffer; + + + // + // Set DataBuffer to point to KSEG0 + // + DataBuffer = (PUCHAR) KSEG0_BASE; + + // + // Compute the number of access we will make for each buffer + // size. Assume that for the largest buffer size we will make + // only one pass. + // NOTE: hopefully the division will limit the number of access to + // within a ULONG. + // + + NumberOfAccess = (ULONG)(ContiguousPhysicalMemorySize/CacheStride); + +#if DBG + DbgPrint("HalpGetBCacheSize: Memory Size = %lu Bytes, " + "Number of Access = %lu\n", + ContiguousPhysicalMemorySize, NumberOfAccess); +#endif + // + // Compute the baseline Rpcc. + // We touch only every cachestride(32KB) memory locations. + // We do this because we want to make sure that the entire set + // of the 3-way set associative on chip 96KB secondary cache gets + // filled in. This also means that we need to make the lower limit + // on the Bcache to be something greater than the OnChip + // secondary cache. + // First we touch all the locations to bring them into the + // cache before computing the baseline + // + + BaseLineElapsedRpcc = HalpTimeTheBufferAccess(DataBuffer, + NumberOfAccess, + CacheSizeLimit, CacheStride); + + // + // Compute the threshold Rpcc to equal to 120% of the baseline + // Rpcc + // + ThresholdRpcc = (BaseLineElapsedRpcc * THRESHOLD_RPCC_PERCENT) / 100; + + while(CacheSizeLimit <= ContiguousPhysicalMemorySize){ + + CurSizeElapsedRpcc = HalpTimeTheBufferAccess(DataBuffer, NumberOfAccess, + CacheSizeLimit, CacheStride); + +#if DBG + DbgPrint("HalpGetBCacheSize: Size = %3ld%s" + " ElapsedRpcc = %7lu Threshold = %7lu\n", + (( CacheSizeLimit < __1MB) ? + ( CacheSizeLimit/__1KB) : + ( CacheSizeLimit /__1MB) ), + (( CacheSizeLimit < __1MB) ? + "KB" : "MB" ), + CurSizeElapsedRpcc, + ThresholdRpcc + ); +#endif + + // + // if the current elapsed Rpcc is greater than threshold rpcc + // + if(CurSizeElapsedRpcc > ThresholdRpcc ){ + break; + } + CacheSize = CacheSizeLimit; + + CacheSizeLimit *= 2; + } + + // + // In the following case the chance that this is a cacheless machine + // is very high, so we will return CacheSize to be Zero. + // + if(CacheSizeLimit >= ContiguousPhysicalMemorySize) + CacheSize = 0; + +#if DBG + DbgPrint("HalpGetBCacheSize: Cache Size = %lu Bytes\n", + CacheSize); +#endif + + // + // return cache size in number of bytes. + // + return (CacheSize); +} + diff --git a/private/ntos/nthals/halalpha/cia.c b/private/ntos/nthals/halalpha/cia.c new file mode 100644 index 000000000..cfdc6ce52 --- /dev/null +++ b/private/ntos/nthals/halalpha/cia.c @@ -0,0 +1,769 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + cia.c + +Abstract: + + This module implements functions that are specific to the CIA ASIC. + The CIA ASIC is a control ASIC for cache, memory, and PCI on EV5-based + systems. + +Author: + + Joe Notarangelo 26-Jul-1994 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" +#include "cia.h" + +BOOLEAN CiaInitialized = FALSE; + +// +// The revision of the CIA. Software visible differences exist between +// passes of the CIA. The revision is determined once at the start of +// run-time and used in places where the software must diverge. +// + +ULONG HalpCiaRevision = CIA_REVISION_1; + + +VOID +HalpInitializeCia( + PLOADER_PARAMETER_BLOCK LoaderBlock + ) +/*++ + +Routine Description: + + Initialize the CIA. + +Arguments: + + LoaderBlock - Supplies a pointer to the loader parameter block. + +Return Value: + + None. + +--*/ +{ + CIA_CONFIG CiaConfig; + CIA_CONTROL CiaControl; + CIA_ERR CiaError; + CIA_WBASE Wbase; + CIA_TBASE Tbase; + CIA_WMASK Wmask; + CIA_TBIA Tbia; + + // + // Read the CIA revision. + // + // N.B. The revision must be read assuming pass 1 CIA. + // + // N.B. The revision must be determined before reading PCI configuration. + // + + HalpCiaRevision = + READ_CIA_REGISTER( + &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaRevision ); + +#if HALDBG + + DbgPrint( "Cia Revision = 0x%x\n", HalpCiaRevision ); + +#endif //HALDBG + + // + // Initialize CIA Control. + // + + CiaControl.all = + READ_CIA_REGISTER( + &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCtrl ); + + // + // Set CIA to optimal setting according to Paul Lemmon. + // + + CiaControl.PciEn = 1; + CiaControl.PciLockEn = 0; + CiaControl.PciLoopEn = 1; + CiaControl.FstBbEn = 0; + CiaControl.PciMstEn = 1; + CiaControl.PciMemEn = 1; + + // + // Specifically disable PCI parity checking so firmware would work. + // Parity can be re-enabled later by the HAL for the OS. + // + + CiaControl.AddrPeEn = 0; + CiaControl.PerrEn = 0; + + CiaControl.FillErrEn = 1; + CiaControl.MchkErrEn = 1; + CiaControl.EccChkEn = 1; + CiaControl.AssertIdleBc = 0; + CiaControl.ConIdleBc = 1; + CiaControl.CsrIoaBypass = 0; + CiaControl.IoFlushReqEn = 0; + CiaControl.CpuFlushReqEn = 0; + CiaControl.ArbEv5En = 0; + + // + // Old revisions of CIA should have ArbLink off since it doesn't work. + // + + if (HalpCiaRevision < CIA_REVISION_3) { + + CiaControl.EnArbLink = 0; + } else { + + CiaControl.EnArbLink = 1; + } + + CiaControl.RdType = 0; + CiaControl.RlType = 1; + CiaControl.RmType = 2; + CiaControl.EnDmaRdPerf = 0; + + WRITE_CIA_REGISTER( &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCtrl, + CiaControl.all ); + + // + // Initialize CIA Config. Turn on the performance enhancement features of + // CIA2. No-op for rev 1 CIA. + // + + CiaConfig.all = + READ_CIA_REGISTER( + &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCnfg ); + + CiaConfig.IoaBwen = 0; + CiaConfig.PciDwen = 1; + + WRITE_CIA_REGISTER( &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCnfg, + CiaConfig.all ); + + // + // Disable all of the scatter/gather windows. + // + + Wbase.all = 0; + Wbase.Wen = 0; + + WRITE_CIA_REGISTER( &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase0, + Wbase.all ); + + WRITE_CIA_REGISTER( &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase1, + Wbase.all ); + + WRITE_CIA_REGISTER( &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase2, + Wbase.all ); + + WRITE_CIA_REGISTER( &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase3, + Wbase.all ); + + // + // Invalidate all of the TLB Entries: + // + + Tbia.all = 0; + Tbia.InvalidateType = InvalidateAll; + + // + // Perform the invalidation. + // + + WRITE_CIA_REGISTER( &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbia, + Tbia.all ); + + // + // Clear any pending error bits in the CIA_ERR register: + // + + CiaError.all = 0; // Clear all bits + + CiaError.CorErr = 1; // Correctable error + CiaError.UnCorErr = 1; // Uncorrectable error + CiaError.CpuPe = 1; // Ev5 bus parity error + CiaError.MemNem = 1; // Nonexistent memory error + CiaError.PciSerr = 1; // PCI bus serr detected + CiaError.PciPerr = 1; // PCI bus perr detected + CiaError.PciAddrPe = 1; // PCI bus address parity error + CiaError.RcvdMasAbt = 1; // Pci Master Abort + CiaError.RcvdTarAbt = 1; // Pci Target Abort + CiaError.PaPteInv = 1; // Invalid Pte + CiaError.FromWrtErr = 1; // Invalid write to flash rom + CiaError.IoaTimeout = 1; // Io Timeout occurred + CiaError.LostCorErr = 1; // Lost correctable error + CiaError.LostUnCorErr = 1; // Lost uncorrectable error + CiaError.LostCpuPe = 1; // Lost Ev5 bus parity error + CiaError.LostMemNem = 1; // Lost Nonexistent memory error + CiaError.LostPciPerr = 1; // Lost PCI bus perr detected + CiaError.LostPciAddrPe = 1; // Lost PCI bus address parity error + CiaError.LostRcvdMasAbt = 1; // Lost Pci Master Abort + CiaError.LostRcvdTarAbt = 1; // Lost Pci Target Abort + CiaError.LostPaPteInv = 1; // Lost Invalid Pte + CiaError.LostFromWrtErr = 1; // Lost Invalid write to flash rom + CiaError.LostIoaTimeout = 1; // Lost Io Timeout occurred + CiaError.ErrValid = 1; // Self explanatory + + WRITE_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr, + CiaError.all + ); + + +#if defined(CIA_PASS1) + + { + + ULONG Allocated; + PTRANSLATION_ENTRY MapRegister; + ULONG MaxPhysicalAddress; + ULONG NumberOfPages; + BOOLEAN __64KAlignment; + ULONG i; + + + // + // Create a special scatter/gather window to use for diagnostic + // DMAs that we can use to insure that the TLB is flushed of any + // other entries. + // + + // + // Allocate a page of memory to hold the scatter/gather entries. + // + + Allocated = HalpAllocPhysicalMemory( LoaderBlock, + MaxPhysicalAddress = __1GB - 1, + NumberOfPages = 1, + __64KAlignment = TRUE ); // FALSE ); + + // + // Make the first 32 entries in the new table valid, point them + // to the first 32 pages in memory. + // + + MapRegister = (PTRANSLATION_ENTRY)(Allocated | KSEG0_BASE); + + for( i=0; i < 32; i++ ){ + + ULONG Pfn = 0x700000 >> PAGE_SHIFT; + + HAL_MAKE_VALID_TRANSLATION( MapRegister, Pfn ); + MapRegister += 1; + + Pfn += 1; + + } + + // + // Enable window 3 for the diagnostic dmas to the special scatter/gather + // table. Base of the window in PCI space is 32MB, size of the window + // is 1MB. + // + + Wbase.all = 0; + Wbase.Wen = 1; + Wbase.SgEn = 1; + Wbase.Wbase = (ULONG)(__1MB * 32) >> 20; + + Wmask.all = 0; + Wmask.Wmask = 0; + + Tbase.all = 0; + Tbase.Tbase = (ULONG)(Allocated) >> 10; + + WRITE_CIA_REGISTER( &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbase3, + Tbase.all ); + + WRITE_CIA_REGISTER( &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wmask3, + Wmask.all ); + + WRITE_CIA_REGISTER( &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase3, + Wbase.all ); + + } + + +#endif //CIA_PASS1 + + CiaInitialized = TRUE; + +} + + +VOID +HalpCiaInitializeSfwWindow( + PWINDOW_CONTROL_REGISTERS WindowRegisters, + CIA_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 CiaIsaWindow: + + WindowRegisters->WindowBase = (PVOID)ISA_DMA_WINDOW_BASE; + WindowRegisters->WindowSize = ISA_DMA_WINDOW_SIZE; + WindowRegisters->TranslatedBaseRegister = + &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbase1; + WindowRegisters->WindowBaseRegister = + &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase1; + WindowRegisters->WindowMaskRegister = + &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wmask1; + WindowRegisters->WindowTbiaRegister = + &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbia; + + break; + + case CiaMasterWindow: + + WindowRegisters->WindowBase = (PVOID)MASTER_DMA_WINDOW_BASE; + WindowRegisters->WindowSize = MASTER_DMA_WINDOW_SIZE; + WindowRegisters->TranslatedBaseRegister = + &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbase0; + WindowRegisters->WindowBaseRegister = + &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase0; + WindowRegisters->WindowMaskRegister = + &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wmask0; + WindowRegisters->WindowTbiaRegister = + &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbia; + + break; + + default: + +#if HALDBG + + DbgPrint( "CiaInitializeSfwWindow: Bad Window Number = %x\n", + WindowNumber ); + +#endif //HALDBG + + break; + + } + + return; +} + + +VOID +HalpCiaProgramDmaWindow( + 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. + +--*/ +{ + CIA_WBASE Wbase; + CIA_TBASE Tbase; + CIA_WMASK Wmask; + + // + // 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; + + // + // Dump the CIA registers. + // + +#if HALDBG + + DumpCia( CiaScatterGatherRegisters ); + +#endif //HALDBG + + // + // Clear the window base, temporarily disabling transactions to this + // DMA window. + // + + WRITE_CIA_REGISTER( 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_CIA_REGISTER( WindowRegisters->TranslatedBaseRegister, + Tbase.all ); + + WRITE_CIA_REGISTER( WindowRegisters->WindowMaskRegister, + Wmask.all ); + + WRITE_CIA_REGISTER( WindowRegisters->WindowBaseRegister, + Wbase.all ); + + // + // Flush the volatile entries in the CIA's scatter/gather Tlb. + // + + HalpCiaInvalidateTlb( WindowRegisters, InvalidateVolatile ); + + // + // Dump the CIA registers. + // + +#if HALDBG + + DumpCia( CiaScatterGatherRegisters | CiaGeneralRegisters ); + +#endif //HALDBG + + return; +} + + +VOID +HalpCiaInvalidateTlb( + PWINDOW_CONTROL_REGISTERS WindowRegisters, + CIA_INVALIDATE_TYPE InvalidateType + ) +/*++ + +Routine Description: + + Invalidate the DMA Scatter/Gather TLB in the CIA. The TLB is invalidated + whenever the scatter/gather translation entries are modified. + +Arguments: + + WindowRegisters - Supplies a pointer to the software window register + control structure. + + InvalidateType - Supplies the type of invalidate the caller requires. + +Return Value: + + None. + +--*/ +{ + + // + // Perform the invalidation based on the pass of the CIA. + // + + if( HalpCiaRevision == CIA_REVISION_1 ){ + + ULONG LoopbackAddress; + ULONG i; + + // + // Perform 8 reads to PCI Dense space through the special loopback + // scatter/gather window to invalidate each entry in the CIA TLB. + // Each TLB fill prefetches 4 entries so our 8 reads must each be + // 32K bytes apart. + // + + LoopbackAddress = __1MB * 32; + + HalpMb(); + + for( i=0; i < 8; i++ ){ + + ULONG dummy; + + dummy = READ_REGISTER_ULONG( (PULONG)LoopbackAddress ); + + LoopbackAddress += __1K * 32; + + } + + HalpMb(); + + } else { + + CIA_TBIA Tbia; + + // + // Set the invalidate as specified by the flush type. + // + + Tbia.all = 0; + Tbia.InvalidateType = InvalidateType; + + // + // Perform the invalidation. + // + + WRITE_CIA_REGISTER( WindowRegisters->WindowTbiaRegister, Tbia.all ); + + } //end if( HalpCiaRevision == CIA_REVISION_1 ) + +} + + +#if HALDBG + +VOID +DumpCia( + CIA_REGISTER_CLASS RegistersToDump + ) +/*++ + +Routine Description: + + Read the interesting Cia registers and print them to the debug port. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + PVOID RegisterQva; + ULONG Value; + + DbgPrint( "CIA Register Dump: \n" ); + + // + // Dump the CIA General Control registers. + // + + if( (RegistersToDump & CiaGeneralRegisters) != 0 ){ + + RegisterQva = &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaRevision; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "CiaRevision = 0x%x\n", Value ); + + RegisterQva = &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->PciLat; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "PciLat = 0x%x\n", Value ); + + RegisterQva = &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCtrl; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "CiaCtrl = 0x%x\n", Value ); + + RegisterQva = &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCnfg; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "CiaCnfg = 0x%x\n", Value ); + + RegisterQva = &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->HaeMem; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "HaeMem = 0x%x\n", Value ); + + RegisterQva = &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->HaeIo; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "HaeIo = 0x%x\n", Value ); + + RegisterQva = &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->ConfigType; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "ConfigType = 0x%x\n", Value ); + + RegisterQva = &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CackEn; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "CackEn = 0x%x\n", Value ); + + } + + // + // Dump the CIA Error registers. + // + + if( (RegistersToDump & CiaErrorRegisters) != 0 ){ + + RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CpuErr0; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "CpuErr0 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CpuErr1; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "CpuErr1 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "CiaErr = 0x%x\n", Value ); + + RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaStat; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "CiaStat = 0x%x\n", Value ); + + RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->ErrMask; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "ErrMask = 0x%x\n", Value ); + + RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaSyn; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "CiaSyn = 0x%x\n", Value ); + + RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->MemErr0; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "MemErr0 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->MemErr1; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "MemErr1 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr0; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "PciErr0 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr1; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "PciErr1 = 0x%x\n", Value ); + + } + + // + // Dump the PCI Scatter/Gather registers. + // + + if( (RegistersToDump & CiaScatterGatherRegisters) != 0 ){ + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbia; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "Tbia = 0x%x\n", Value ); + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase0; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "Wbase0 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wmask0; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "Wmask0 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbase0; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "Tbase0 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase1; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "Wbase1 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wmask1; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "Wmask1 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbase1; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "Tbase1 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase2; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "Wbase2 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wmask2; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "Wmask2 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbase2; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "Tbase2 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase3; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "Wbase3 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wmask3; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "Wmask3 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbase3; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "Tbase3 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Dac; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "Dac = 0x%x\n", Value ); + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->LtbTag0; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "LtbTag0 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->LtbTag1; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "LtbTag1 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->LtbTag2; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "LtbTag2 = 0x%x\n", Value ); + + RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->LtbTag3; + Value = READ_CIA_REGISTER( RegisterQva ); + DbgPrint( "LtbTag3 = 0x%x\n", Value ); + } + + + DbgPrint( "--end CIA Register dump\n\n" ); + + return; + +} + +#endif //HALDBG + diff --git a/private/ntos/nthals/halalpha/cia.h b/private/ntos/nthals/halalpha/cia.h new file mode 100644 index 000000000..510b02c96 --- /dev/null +++ b/private/ntos/nthals/halalpha/cia.h @@ -0,0 +1,1141 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + cia.h + +Abstract: + + This file defines the structures and definitions for the CIA ASIC. + +Author: + + Steve Brooks 30-Jun-1994 + Joe Notarangelo 30-Jun-1994 + +Environment: + + Kernel mode + +Revision History: + + Chao Chen 31-Aug-1995 Add in new data structures for misc cia registers. + +--*/ + +#ifndef _CIAH_ +#define _CIAH_ + + +// +// CIA Revision definitions. +// + +#define CIA_REVISION_1 (0) +#define CIA_REVISION_2 (1) +#define CIA_REVISION_3 (2) + + +// +// 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 size of I/O and memory space for the CIA. +// Assume that the HAE==0. +// + +#define PCI_MAX_IO_ADDRESS (__64MB - 1) // I/O: 0 - 64MB +#define PCI_MAX_SPARSE_MEMORY_ADDRESS (__512MB - 1) // Mem: 0 - 512MB +#define PCI_MIN_DENSE_MEMORY_ADDRESS PCI_MAX_SPARSE_MEMORY_ADDRESS + 1 +#define PCI_MAX_DENSE_MEMORY_ADDRESS (__2GB + __512MB - 1) // Dense: .5 - 2.5 Gb + +// +// Defines for cia correctable errors. +// + +#define CIA_IO_WRITE_ECC 0x2 +#define CIA_DMA_READ_ECC 0x6 +#define CIA_DMA_WRITE_ECC 0x7 +#define CIA_IO_READ_ECC 0xb +#define CIA_PROCESSOR_CACHE_ECC 0x2 +#define CIA_SYSTEM_CACHE_ECC 0x3 + +#if !defined(_LANGUAGE_ASSEMBLY) + +#define CIA_QVA_PHYSICAL_BASE ((ULONGLONG)0x8400000000) + +// +// 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 - CIA_QVA_PHYSICAL_BASE) >> IO_BIT_SHIFT) ) ) + + +// +// Define physical address space for CIA. +// + +#define CIA_PCI_SPARSE_MEMORY_PHYSICAL ((ULONGLONG)0x8400000000) +#define CIA_PCI_SPARSE_IO_PHYSICAL ((ULONGLONG)0x8580000000) +#define CIA_PCI_DENSE_MEMORY_PHYSICAL ((ULONGLONG)0x8600000000) +#define CIA_PCI_CONFIGURATION_PHYSICAL ((ULONGLONG)0x8700000000) +#define CIA_PCI_INTACK_PHYSICAL ((ULONGLONG)0x8720000000) +#define CIA_MAIN_CSRS_PHYSICAL ((ULONGLONG)0x8740000000) + +#define CIA_PCI_CONFIG_BASE_QVA (HAL_MAKE_QVA(CIA_PCI_CONFIGURATION_PHYSICAL)) +#define CIA_PCI_SPARSE_IO_QVA (HAL_MAKE_QVA(CIA_PCI_SPARSE_IO_PHYSICAL)) +#define CIA_PCI_SPARSE_MEMORY_QVA (HAL_MAKE_QVA(CIA_PCI_SPARSE_MEMORY_PHYSICAL)) +#define CIA_PCI_INTACK_QVA (HAL_MAKE_QVA(CIA_PCI_INTACK_PHYSICAL)) + +// +// Define the classes of CIA registers. +// + +typedef enum _CIA_REGISTER_CLASS{ + CiaGeneralRegisters = 0x1, + CiaErrorRegisters = 0x2, + CiaScatterGatherRegisters = 0x4, + CiaAllRegisters = 0xffffffff +} CIA_REGISTER_CLASS, *PCIA_REGISTER_CLASS; + +// +// Define the structures to access the CIA general csrs. +// + +#define CIA_GENERAL_CSRS_PHYSICAL ((ULONGLONG)0x8740000080) +#define CIA_GENERAL_CSRS_QVA HAL_MAKE_QVA(CIA_GENERAL_CSRS_PHYSICAL) + +typedef struct _CIA_GENERAL_CSRS{ + UCHAR CiaRevision; // (80) PCI Revision + UCHAR Filler1; // (a0) + UCHAR PciLat; // (c0) PCI Latency + UCHAR Filler2; // (e0) + UCHAR CiaCtrl; // (100) CIA control + UCHAR Filler3[1]; // (120) + UCHAR CiaCnfg; // (140) CIA config + UCHAR Filler4[21]; // (160 - 3e0) + UCHAR HaeMem; // (400) Host address extension, sparse memory + UCHAR Filler5; // (420) + UCHAR HaeIo; // (440) Host address extension, space i/o + UCHAR Filler6; // (460) + UCHAR ConfigType; // (480) Configuration register + UCHAR Filler7[11]; // (4a0 - 5e0) + UCHAR CackEn; // (600) CIA Acknowledgement +} CIA_GENERAL_CSRS, *PCIA_GENERAL_CSRS; + +extern ULONG HalpCiaRevision; // global containing CIA revision id + +typedef union _CIA_REVISION{ + struct{ + ULONG CiaRev: 8; // CIA Revision Id + ULONG Reserved: 24; // + }; + ULONG all; +} CIA_REVISION, *PCIA_REVISION; + +typedef union _CIA_PCI_LAT{ + struct{ + ULONG Reserved0: 8; // + ULONG Latency: 8; // PCI Master Latency timer (in PCI clocks) + ULONG Reserved1: 16; // + }; + ULONG all; +} CIA_PCI_LAT, *PCIA_PCI_LAT; + +typedef union _CIA_CONTROL{ + struct{ + ULONG PciEn: 1; // PCI Reset Enable + ULONG PciLockEn: 1; // Enables PCI locking of CIA + ULONG PciLoopEn: 1; // Enables CIA as a target + ULONG FstBbEn: 1; // Enables fast back to back PCI + ULONG PciMstEn: 1; // Enables initiating PCI transactions + ULONG PciMemEn: 1; // Enables CIA response to PCI transactions + ULONG PciReq64: 1; // Enables initiating 64-bit PCI + ULONG PciAck64: 1; // Enables accepting 64-bit PCI transactions + ULONG AddrPeEn: 1; // Enables PCI address parity checking + ULONG PerrEn: 1; // Enables PCI data parity checking + ULONG FillErrEn: 1; // Enables fill error assertion + ULONG MchkErrEn: 1; // Enables machine check error assertion + ULONG EccChkEn: 1; // Enables ECC error checking + ULONG AssertIdleBc: 1; // ???? + ULONG ConIdleBc: 1; // ???? + ULONG CsrIoaBypass: 1; // Allow CIA to bypass I/O address queue + ULONG IoFlushReqEn: 1; // Enables CIA to accept flush requests + ULONG CpuFlushReqEn: 1; // Enables CIA to accept CPU flush requests + ULONG ArbEv5En: 1; // Enables EV5 bypass path to memory and io + ULONG EnArbLink: 1; // Enable CPU memory reads to link + ULONG RdType: 2; // Controls memory pre-fetch algorithm + ULONG Reserved1: 2; // + ULONG RlType: 2; // Controls memory line pre-fetch algorithm + ULONG Reserved2: 2; // + ULONG RmType: 2; // Controls memory multiple pre-fetch + ULONG Reserved3: 1; // + ULONG EnDmaRdPerf: 1; // ???? + }; + ULONG all; +} CIA_CONTROL, *PCIA_CONTROL; + + +typedef union _CIA_CONFIG{ + struct{ + ULONG IoaBwen: 1; // EV56 byte/word I/O access enable + ULONG Reserved0: 3; + ULONG PciMwen: 1; // PCI target monster window enable + ULONG PciDwen: 1; // 2nd PCI target DMA write buffer enable + ULONG Reserved1: 2; + ULONG PciWlen: 1; // CIA link consecutive writes into a + ULONG Reserved2: 23; // single PCI transaction. + }; + ULONG all; +} CIA_CONFIG, *PCIA_CONFIG; + +typedef union _CIA_HAE_MEM{ + struct{ + ULONG Reserved0: 2; // + ULONG Region3: 6; // sets HAE for region 3 + ULONG Reserved1: 3; // + ULONG Region2: 5; // sets HAE for region 2 + ULONG Reserved: 13; // + ULONG Region1: 3; // sets HAE for region 1 + }; + ULONG all; +} CIA_HAE_MEM, *PCIA_HAE_MEM; + +typedef union _CIA_HAE_IO{ + struct{ + ULONG Reserved0: 25; // + ULONG HaeIo: 7; // sets HAE for i/o space + }; + ULONG all; +} CIA_HAE_IO, *PCIA_HAE_IO; + +typedef union _CIA_CONFIG_TYPE{ + struct{ + ULONG Cfg: 2; // PCI<10> config address + ULONG Reserved0: 30; // + }; + ULONG all; +} CIA_CONFIG_TYPE, *PCIA_CONFIG_TYPE; + +typedef union _CIA_CACK_EN{ + struct{ + ULONG CackEn: 4; // Controls CIA acks to EV5 + ULONG Reserved0: 28; // + }; + ULONG all; +} CIA_CACK_EN, *PCIA_CACK_EN; + + +// +// Define the structures and definitions for the CIA diagnostic registers. +// + +#define CIA_DIAG_CSRS_PHYSICAL ((ULONGLONG)0x8740002000) +#define CIA_DIAG_CSRS_QVA HAL_MAKE_QVA(CIA_DIAG_CSRS_PHYSICAL) + +typedef struct _CIA_DIAG_CSRS{ + UCHAR CiaDiag; // (2000) Diagnostic Control register + UCHAR Filler[127]; // (2020-2fe0) + UCHAR DiagCheck; // (3000) Diagnostic Check register + +} CIA_DIAG_CSRS, *PCIA_DIAG_CSRS; + +typedef union _CIA_DIAG { + struct{ + ULONG FromWrtEn: 1; // Flash ROM write enable bit + ULONG UseCheck: 1; // use known ecc pattern for writes + ULONG Reserved0: 26; // + ULONG FpePci: 2; // Force bad parity to PCI bus (if != 0) + ULONG Reserved1: 1; // + ULONG FpeToEv5: 1; // Force bad parity to the EV5 bus + }; + ULONG all; + +} CIA_DIAG, *PCIA_DIAG; + +typedef union _CIA_DIAG_CHECK { + struct{ + ULONG DiagCheck: 8; // ECC pattern to use when UseCheck bit set + ULONG Reserved: 24; + }; + ULONG all; + +} CIA_DIAG_CHECK, *PCIA_DIAG_CHECK; + +// +// Define the structures and definitions for the CIA performance registers. +// + +typedef union _CIA_PERF_MONITOR{ + struct{ + ULONG LowCount: 16; // Low Counter Value + ULONG HighCount: 16; // High Counter Value + }; + ULONG all; +} CIA_PERF_MONITOR, *PCIA_PERF_MONITOR; + +typedef union _CIA_PERF_CONTROL{ + struct{ + ULONG LowSelect: 8; // Low Counter - event to count + ULONG Reserved1: 5; // + ULONG LowCountClear: 1; // Clear low counter value + ULONG LowErrStop: 1; // Stop low counter + ULONG LowCountStart: 1; // Start low counter + ULONG HighSelect: 8; // High Counter - event to count + ULONG Reserved2: 5; // + ULONG HighCountClear: 1; // Clear high counter value + ULONG HighErrStop: 1; // Stop high counter + ULONG HighCountStart: 1; // Start high counter + }; + ULONG all; +} CIA_PERF_CONTROL, *PCIA_PERF_CONTROL; + +typedef enum _CIA_PERF_SELECTS{ + CiaUseHigh32 = 0x00, + CiaClockCycles = 0x01, + CiaRefreshCycles = 0x02, + CiaEv5CmdAcks = 0x10, + CiaEv5Reads = 0x11, + CiaEv5ReadMiss = 0x12, + CiaEv5ReadMissModify = 0x13, + CiaEv5BcacheVictimAcks = 0x14, + CiaEv5LockAcks = 0x15, + CiaEv5MbAcks = 0x16, + CiaEv5Fetch = 0x17, + CiaEv5WriteBlocks = 0x18, + CiaEv5MemoryCmds = 0x20, + CiaEv5IoCmds = 0x21, + CiaEv5IoReadCmds = 0x22, + CiaEv5IoWriteCmds = 0x23, + CiaSystemCommands = 0x24, + CiaEv5SystemReads = 0x25, + CiaEv5SystemFlushes = 0x26, + CiaReceivedNoAck = 0x27, + CiaReceivedScacheAck = 0x28, + CiaReceivedBcacheAck = 0x29, + CiaDmaReadsTotal = 0x30, + CiaDmaReads = 0x31, + CiaDmaReadLines = 0x32, + CiaDmaReadMultiples = 0x33, + CiaDmaWritesTotal = 0x34, + CiaDmaWrites = 0x35, + CiaDmaWriteInvalidates = 0x36, + CiaDmaDualAddressCycles = 0x37, + CiaDmaCycleRetries = 0x38, + CiaIoCycleRetries = 0x39, + CiaPciLocks = 0x40, + CiaEv5LockAccesses = 0x41, + CiaDmaVictimHit = 0x42, + CiaRefillTlb = 0x50, + CiaSingleBitEccErrors = 0x60 +} CIA_PERF_SELECTORS, *PCIA_PERF_SELECTORS; + + +// +// Define the structures and definitions for the CIA error registers. +// + + +#define CIA_ERROR_CSRS_PHYSICAL ((ULONGLONG)0x8740008000) +#define CIA_ERROR_CSRS_QVA HAL_MAKE_QVA(CIA_ERROR_CSRS_PHYSICAL) + +typedef struct _CIA_ERROR_CSRS{ + UCHAR CpuErr0; // (8000) CPU errors + UCHAR Filler0; // (8020) + UCHAR CpuErr1; // (8040) CPU errors + UCHAR Filler1[13]; // (8060 - 81e0) + UCHAR CiaErr; // (8200) Cia errors + UCHAR Filler2; // (8020) + UCHAR CiaStat; // (8240) Cia error status + UCHAR Filler3; // (8060) + UCHAR ErrMask; // (8280) Masks off specified errors + UCHAR Filler4[3]; // (82a0 - 82e0) + UCHAR CiaSyn; // (8300) CIA error syndrome + UCHAR Filler5[7]; // (8320 - 83e0) + UCHAR MemErr0; // (8400) Memory errors + UCHAR Filler6; // (8420) + UCHAR MemErr1; // (8440) Memory errors + UCHAR Filler7[29]; // (8460 - 87e0) + UCHAR PciErr0; // (8800) PCI errors + UCHAR Filler8; // (8820) + UCHAR PciErr1; // (8840) PCI errors + UCHAR Filler9; // (8860) + UCHAR PciErr2; // (8880) PCI errors +} CIA_ERROR_CSRS, *PCIA_ERROR_CSRS; + +typedef union _CIA_CPU_ERR0{ + struct{ + ULONG Reserved: 4; // + ULONG Addr: 28; // CPU addresss bus contents on EV5 error + }; + ULONG all; +} CIA_CPU_ERR0, *PCIA_CPU_ERR0; + +typedef union _CIA_CPU_ERR1{ + struct{ + ULONG Addr34_32: 3; // address bits 34-32 + ULONG Reserved0: 4; // + ULONG Addr39: 1; // address bit 39 + ULONG Cmd: 4; // Cpu address command bus value + ULONG Int4Valid: 4; // Contains Int4 valid bits from CPU bus + ULONG Reserved1: 5; // + ULONG AddrCmdPar: 1; // Contains CPU bus parity bit + ULONG Reserved2: 8; // + ULONG Fpe_2_Ev5: 1; // ???? + ULONG CpuPe: 1; // Indicates CPU interface detected parity + }; + ULONG all; +} CIA_CPU_ERR1, *PCIA_CPU_ERR1; + +typedef union _CIA_ERR{ + struct{ + ULONG CorErr: 1; // Correctable error + ULONG UnCorErr: 1; // Uncorrectable error + ULONG CpuPe: 1; // Ev5 bus parity error + ULONG MemNem: 1; // Nonexistent memory error + ULONG PciSerr: 1; // PCI bus serr detected + ULONG PciPerr: 1; // PCI bus perr detected + ULONG PciAddrPe: 1; // PCI bus address parity error + ULONG RcvdMasAbt: 1; // Pci Master Abort + ULONG RcvdTarAbt: 1; // Pci Target Abort + ULONG PaPteInv: 1; // Invalid Pte + ULONG FromWrtErr: 1; // Invalid write to flash rom + ULONG IoaTimeout: 1; // Io Timeout occurred + ULONG Reserved0: 4; // + ULONG LostCorErr: 1; // Lost correctable error + ULONG LostUnCorErr: 1; // Lost uncorrectable error + ULONG LostCpuPe: 1; // Lost Ev5 bus parity error + ULONG LostMemNem: 1; // Lost Nonexistent memory error + ULONG Reserved1: 1; // + ULONG LostPciPerr: 1; // Lost PCI bus perr detected + ULONG LostPciAddrPe: 1; // Lost PCI bus address parity error + ULONG LostRcvdMasAbt: 1; // Lost Pci Master Abort + ULONG LostRcvdTarAbt: 1; // Lost Pci Target Abort + ULONG LostPaPteInv: 1; // Lost Invalid Pte + ULONG LostFromWrtErr: 1; // Lost Invalid write to flash rom + ULONG LostIoaTimeout: 1; // Lost Io Timeout occurred + ULONG Reserved2: 3; // + ULONG ErrValid: 1; // Self explanatory + }; + ULONG all; +} CIA_ERR, *PCIA_ERR; + +#define CIA_ERR_FATAL_MASK 0x00000ffe +#define CIA_ERR_LOST_MASK 0x0fff0000 + +typedef union _CIA_STAT{ + struct{ + ULONG PciStatus: 2; // Pci Status + ULONG Reserved0: 1; // + ULONG MemSource: 1; // 0=ev5 1=Pci + ULONG IoaValid: 4; // Valid bits for Io command address queue + ULONG CpuQueue: 3; // Valid bits for Cpu command address queue + ULONG TlbMiss: 1; // Tlb Miss refill in progress + ULONG DmSt: 4; // state machine values + ULONG PaCpuRes: 2; // Ev5 response for DMA + ULONG Reserved1: 14; // + }; + ULONG all; +} CIA_STAT, *PCIA_STAT; + + +typedef union _CIA_ERR_MASK{ + struct{ + ULONG CorErr: 1; // Enable Correctable error + ULONG UnCorErr: 1; // Enable Uncorrectable error + ULONG CpuPe: 1; // Enable Ev5 bus parity error + ULONG MemNem: 1; // Enable Nonexistent memory error + ULONG PciSerr: 1; // Enable PCI bus serr detected + ULONG PciPerr: 1; // Enable PCI bus perr detected + ULONG PciAddrPe: 1; // Enable PCI bus address parity error + ULONG RcvdMasAbt: 1; // Enable Pci Master Abort + ULONG RcvdTarAbt: 1; // Enable Pci Target Abort + ULONG PaPteInv: 1; // Enable Invalid Pte + ULONG FromWrtErr: 1; // Enable Invalid write to flash rom + ULONG IoaTimeout: 1; // Enable Io Timeout occurred + ULONG Reserved0: 20; // + }; + ULONG all; +} CIA_ERR_MASK, *PCIA_ERR_MASK; + +typedef union _CIA_SYN{ + struct{ + ULONG EccSyndrome: 8; // Ecc syndrome + ULONG Reserved0: 24; // + }; + ULONG all; +} CIA_SYN, *PCIA_SYN; + +typedef union _CIA_MEM_ERR0{ + struct{ + ULONG Reserved0: 4; // + ULONG Addr31_4: 28; // Memory port address bits + }; + ULONG all; +} CIA_MEM_ERR0, *PCIA_MEM_ERR0; + +typedef union _CIA_MEM_ERR1{ + struct{ + ULONG Addr33_32: 2; // memory port address bits + ULONG Reserved0: 5; // + ULONG Addr39: 1; // Address bit 39 + ULONG MemPortCmd: 4; // Memory port command + ULONG MemPortMask: 4; // Mask bits when error occurred + ULONG SeqSt: 4; // Memory sequencer state + ULONG MemPortSrc: 1; // 0=cpu, 1=dma + ULONG Reserved1: 3; // + ULONG SetSel: 5; // Indicates active memory set + ULONG Reserved2: 3; // + }; + ULONG all; +} CIA_MEM_ERR1, *PCIA_MEM_ERR1; + +typedef union _CIA_PCI_ERR0{ + struct{ + ULONG Cmd: 4; // Pci command + ULONG LockState: 1; // Indicates CIA locked + ULONG DacCycle: 1; // indicates PCI dual address cycle + ULONG Reserved0: 2; // + ULONG Window: 4; // Selected DMA window + ULONG Reserved1: 4; // + ULONG MasterState: 4; // State of PCI master + ULONG TargetState: 3; // State of PCI target + ULONG Reserved2: 9; // + }; + ULONG all; +} CIA_PCI_ERR0, *PCIA_PCI_ERR0; + +typedef struct _CIA_PCI_ERR1{ + ULONG PciAddress; // Pci Address +} CIA_PCI_ERR1, *PCIA_PCI_ERR1; + +typedef struct _CIA_PCI_ERR2{ + ULONG PciAddress; // Pci Address +} CIA_PCI_ERR2, *PCIA_PCI_ERR2; + +// +// Define the structures and definitions for the CIA memory registers. +// + +#define CIA_MEMORY_CSRS_PHYSICAL ((ULONGLONG)0x8750000000) +#define CIA_MEMORY_CSRS_QVA HAL_MAKE_QVA(CIA_MEMORY_CSRS_PHYSICAL) + +typedef struct _CIA_MEMORY_CSRS{ + UCHAR Mcr; // (0000) MCR register + UCHAR Filler0[47]; // (0020 - 05e0) + UCHAR Mba0; // (0600) Mba0 register + UCHAR Filler1[3]; // (0620 - 0660) + UCHAR Mba2; // (0680) Mba2 register + UCHAR Filler2[3]; // (06a0 - 06e0) + UCHAR Mba4; // (0700) Mba4 register + UCHAR Filler3[3]; // (0720 - 0760) + UCHAR Mba6; // (0780) Mba6 register + UCHAR Filler4[3]; // (07a0 - 07e0) + UCHAR Mba8; // (0800) Mba8 register + UCHAR Filler5[3]; // (0820 - 0860) + UCHAR MbaA; // (0880) MbaA register + UCHAR Filler6[3]; // (08a0 - 08e0) + UCHAR MbaC; // (0900) MbaC register + UCHAR Filler7[3]; // (0920 - 960) + UCHAR MbaE; // (0980) MbaE register + UCHAR Filler8[8]; // (0a00 - ae0) + UCHAR Tmg0; // (0b00) Tmg0 register + UCHAR Filer9; // (0b20) + UCHAR Tmg1; // (0b40) Tmg1 register + UCHAR Filer10; // (0b60) + UCHAR Tmg2; // (0b80) Tmg2 register +} CIA_MEMORY_CSRS, *PCIA_MEMORY_CSRS; + +// +// Define structures and definitions for Memory control registers: +// + +typedef union _CIA_MCR{ + struct{ + ULONG MemSize: 1; // Memory path width (256 vs. 128) + ULONG Reserved1: 3; // + ULONG CacheSize: 3; // Bcache size + ULONG Reserved2: 1; // + ULONG RefRate: 10; // Memory refresh rate + ULONG RefBurst: 2; // Refresh configuration + ULONG TmgR0: 2; // Row address setup control + ULONG LongCbrCas: 1; // CAS pulse width + ULONG Reserved3: 3; // + ULONG DelayIdleBc: 2; // ?? + ULONG Reserved4: 1; // + ULONG EarlyIdleBc: 1; // ?? + ULONG Reserved5: 2; // + }; + ULONG all; +} CIA_MCR, *PCIA_MCR; + +typedef union _CIA_MBA{ + struct{ + ULONG MbaS0Valid: 1; // Indiates side 0 of bank is valid + ULONG MbaRowType: 2; // Row and column configuration + ULONG Reserved1: 1; // + ULONG MbaMask: 5; // Comparision Mask + ULONG Reserved2: 6; // + ULONG MbaS1Valid: 1; // Indicates side 1 of bank is valid + ULONG MbaPattern: 10; // Address decode pattern + ULONG Reserved3: 2; // + ULONG MbaTiming: 2; // TMGx CSR select + ULONG Reserved4: 2; // + }; + ULONG all; +} CIA_MBA, *PCIA_MBA; + +typedef union _CIA_TMG{ + struct{ + ULONG TmgR1: 2; // Read starting, data delay + ULONG TmgR2: 2; // Row address hold + ULONG TmgR3: 2; // Read cycle time + ULONG TmgR4: 2; // Read, CAS assertion delay + ULONG TmgR5: 2; // Read, CAS pulse width + ULONG TmgR6: 2; // Read, column address hold + ULONG TmgW1: 2; // Write, data delay + ULONG TmgW4: 3; // Write, CAS assertion delay + ULONG TmgPre: 1; // RAS precharge delay + ULONG TmgV3: 2; // Write, cycle time + ULONG TmgV4: 3; // Linked victim, CAS assertion delay + ULONG Reserved1: 1; // + ULONG TmgV5: 2; // Victim/Write, CAS pulse width + ULONG TmgV6: 2; // Victim/Write, Column address hold + ULONG TmgRv: 2; // Read to victim start delay + ULONG TmgRdDelay: 2; // Read data delay + }; + ULONG all; +} CIA_TMG, *PCIA_TMG; + +// +// Define structures and definitions for Scatter/Gather control registers: +// + +#define CIA_SCATTER_GATHER_CSRS_PHYSICAL ((ULONGLONG)0x8760000100) +#define CIA_SG_CSRS_QVA (HAL_MAKE_QVA(CIA_SCATTER_GATHER_CSRS_PHYSICAL)) + +typedef struct _CIA_SG_CSRS{ + UCHAR Tbia; // (100) Translation buffer invalidate all + UCHAR Filler0[23]; // (120-3e0) + UCHAR Wbase0; // (400) Base address, DMA window 0 + UCHAR Filler1; // (420) + UCHAR Wmask0; // (440) Mask Register, DMA window 0 + UCHAR Filler2; // (460) + UCHAR Tbase0; // (480) Translation Base, DMA window 0 + UCHAR Filler3[3]; // (4a0 - 4e0) + UCHAR Wbase1; // (500) Base address, DMA window 1 + UCHAR Filler4; // (520) + UCHAR Wmask1; // (540) Mask Register, DMA window 1 + UCHAR Filler5; // (560) + UCHAR Tbase1; // (580) Translation Base, DMA window 1 + UCHAR Filler6[3]; // (5a0 - 5e0) + UCHAR Wbase2; // (600) Base address, DMA window 2 + UCHAR Filler7; // (620) + UCHAR Wmask2; // (640) Mask Register, DMA window 2 + UCHAR Filler8; // (660) + UCHAR Tbase2; // (680) Translation Base, DMA window 2 + UCHAR Filler9[3]; // (6a0 - 6e0) + UCHAR Wbase3; // (700) Base address, DMA window 3 + UCHAR Filler10; // (720) + UCHAR Wmask3; // (740) Mask Register, DMA window 3 + UCHAR Filler11; // (760) + UCHAR Tbase3; // (780) Translation Base, DMA window 3 + UCHAR Filler12; // (7a0) + UCHAR Dac; // (7c0) Window DAC Base + UCHAR Filler13; // (7e0) + UCHAR LtbTag0; // (800) Lockable Translation Buffer Tag 0 + UCHAR Filler14; // (820) + UCHAR LtbTag1; // (840) Lockable Translation Buffer Tag 1 + UCHAR Filler15; // (860) + UCHAR LtbTag2; // (880) Lockable Translation Buffer Tag 2 + UCHAR Filler16; // (8a0) + UCHAR LtbTag3; // (8c0) Lockable Translation Buffer Tag 3 + UCHAR Filler17; // (8e0) + UCHAR TbTag0; // (900) Translation Buffer Tag 0 + UCHAR Filler18; // (920) + UCHAR TbTag1; // (940) Translation Buffer Tag 1 + UCHAR Filler19; // (960) + UCHAR TbTag2; // (980) Translation Buffer Tag 2 + UCHAR Filler20; // (9a0) + UCHAR TbTag3; // (9c0) Translation Buffer Tag 3 + UCHAR Filler21; // (9e0) + UCHAR Tb0Page0; // (1000) Translation Buffer 0 Page 0 + UCHAR Filler22; // (1020) + UCHAR Tb0Page1; // (1040) Translation Buffer 0 Page 1 + UCHAR Filler23; // (1060) + UCHAR Tb0Page2; // (1080) Translation Buffer 0 Page 2 + UCHAR Filler24; // (10a0) + UCHAR Tb0Page3; // (10c0) Translation Buffer 0 Page 3 + UCHAR Filler25; // (10e0) + UCHAR Tb1Page0; // (1100) Translation Buffer 1 Page 0 + UCHAR Filler26; // (1120) + UCHAR Tb1Page1; // (1140) Translation Buffer 1 Page 1 + UCHAR Filler27; // (1160) + UCHAR Tb1Page2; // (1180) Translation Buffer 1 Page 2 + UCHAR Filler28; // (11a0) + UCHAR Tb1Page3; // (11c0) Translation Buffer 1 Page 3 + UCHAR Filler29; // (11e0) + UCHAR Tb2Page0; // (1200) Translation Buffer 2 Page 0 + UCHAR Filler30; // (1220) + UCHAR Tb2Page1; // (1240) Translation Buffer 2 Page 1 + UCHAR Filler31; // (1260) + UCHAR Tb2Page2; // (1280) Translation Buffer 2 Page 2 + UCHAR Filler32; // (12a0) + UCHAR Tb2Page3; // (12c0) Translation Buffer 2 Page 3 + UCHAR Filler33; // (12e0) + UCHAR Tb3Page0; // (1300) Translation Buffer 3 Page 0 + UCHAR Filler34; // (1320) + UCHAR Tb3Page1; // (1340) Translation Buffer 3 Page 1 + UCHAR Filler35; // (1360) + UCHAR Tb3Page2; // (1380) Translation Buffer 3 Page 2 + UCHAR Filler36; // (13a0) + UCHAR Tb3Page3; // (13c0) Translation Buffer 3 Page 3 + UCHAR Filler37; // (13e0) + UCHAR Tb4Page0; // (1400) Translation Buffer 4 Page 0 + UCHAR Filler38; // (1420) + UCHAR Tb4Page1; // (1440) Translation Buffer 4 Page 1 + UCHAR Filler39; // (1460) + UCHAR Tb4Page2; // (1480) Translation Buffer 4 Page 2 + UCHAR Filler40; // (14a0) + UCHAR Tb4Page3; // (14c0) Translation Buffer 4 Page 3 + UCHAR Filler41; // (14e0) + UCHAR Tb5Page0; // (1500) Translation Buffer 5 Page 0 + UCHAR Filler42; // (1520) + UCHAR Tb5Page1; // (1540) Translation Buffer 5 Page 1 + UCHAR Filler43; // (1560) + UCHAR Tb5Page2; // (1580) Translation Buffer 5 Page 2 + UCHAR Filler44; // (15a0) + UCHAR Tb5Page3; // (15c0) Translation Buffer 5 Page 3 + UCHAR Filler45; // (15e0) + UCHAR Tb6Page0; // (1600) Translation Buffer 6 Page 0 + UCHAR Filler46; // (1620) + UCHAR Tb6Page1; // (1640) Translation Buffer 6 Page 1 + UCHAR Filler47; // (1660) + UCHAR Tb6Page2; // (1680) Translation Buffer 6 Page 2 + UCHAR Filler48; // (16a0) + UCHAR Tb6Page3; // (16c0) Translation Buffer 6 Page 3 + UCHAR Filler49; // (16e0) + UCHAR Tb7Page0; // (1700) Translation Buffer 7 Page 0 + UCHAR Filler50; // (1720 + UCHAR Tb7Page1; // (1740) Translation Buffer 7 Page 1 + UCHAR Filler51; // (1760) + UCHAR Tb7Page2; // (1780) Translation Buffer 7 Page 2 + UCHAR Filler52; // (17a0) + UCHAR Tb7Page3; // (17c0) Translation Buffer 7 Page 3 + +} CIA_SG_CSRS, *PCIA_SG_CSRS; + + +typedef union _CIA_TBIA{ + struct{ + ULONG InvalidateType: 2; // Type of invalidation + ULONG Reserved0: 30; // + }; + ULONG all; +} CIA_TBIA, *PCIA_TBIA; + +typedef union _CIA_WBASE{ + struct{ + ULONG Wen: 1; // Window enable + ULONG SgEn: 1; // Scatter Gather enable + ULONG MemcsEn: 1; // Memory Cs Enable + ULONG DacEn: 1; // DAC Enable + ULONG Reserved0: 16; // + ULONG Wbase: 12; // Base address of DMA window + }; + ULONG all; +} CIA_WBASE, *PCIA_WBASE; + +typedef union _CIA_WMASK{ + struct{ + ULONG Reserved0: 20; // + ULONG Wmask: 12; // Window mask + }; + ULONG all; +} CIA_WMASK, *PCIA_WMASK; + +typedef union _CIA_TBASE{ + struct{ + ULONG Reserved0: 8; // + ULONG Tbase: 24; // Translation base address + }; + ULONG all; +} CIA_TBASE, *PCIA_TBASE; + +typedef union _CIA_LTB_TAG{ + struct{ + ULONG Valid: 1; + ULONG Locked: 1; + ULONG Dac: 1; + ULONG Reserved0: 12; + ULONG TbTag: 17; + }; + ULONG all; +} CIA_LTB_TAG, *PCIA_LTB_TAG; + +typedef union _CIA_TB_TAG{ + struct{ + ULONG Valid: 1; + ULONG Reserved0: 1; + ULONG Dac: 1; + ULONG Reserved1: 12; + ULONG TbTag: 17; + }; + ULONG all; +} CIA_TB_TAG, *PCIA_TB_TAG; + + +// +// DMA Window Values. +// +// The CIA 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 _CIA_WINDOW_NUMBER{ + CiaIsaWindow, + CiaMasterWindow +} CIA_WINDOW_NUMBER, *PCIA_WINDOW_NUMBER; + +// +// Define the types of invalidates that can be performed by the CIA. +// + +typedef enum _CIA_INVALIDATE_TYPE{ + InvalidateNoop = 0x0, + InvalidateLocked = 0x1, + InvalidateVolatile = 0x2, + InvalidateAll = 0x3 +} CIA_INVALIDATE_TYPE, *PCIA_INVALIDATE_TYPE; + +// +// Define CIA Window Control routines. +// + +VOID +HalpCiaInitializeSfwWindow( + PWINDOW_CONTROL_REGISTERS WindowRegisters, + CIA_WINDOW_NUMBER WindowNumber + ); + +VOID +HalpCiaProgramDmaWindow( + PWINDOW_CONTROL_REGISTERS WindowRegisters, + PVOID MapRegisterBase + ); + +VOID +HalpCiaInvalidateTlb( + PWINDOW_CONTROL_REGISTERS WindowRegisters, + CIA_INVALIDATE_TYPE InvalidateType + ); + +VOID +WRITE_CIA_REGISTER( + PVOID, + ULONGLONG + ); + +ULONG +READ_CIA_REGISTER( + PVOID + ); + +VOID +WRITE_GRU_REGISTER( + PVOID, + ULONGLONG + ); + +ULONG +READ_GRU_REGISTER( + PVOID + ); + +ULONG +INTERRUPT_ACKNOWLEDGE( + PVOID + ); + +BOOLEAN +HalpCiaUncorrectableError( + VOID + ); + +VOID +HalpCiaReportFatalError( + VOID + ); + +BOOLEAN +HalpCiaMachineCheck( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN PKTRAP_FRAME TrapFrame + ); + +VOID +HalpInitializeCia( + PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +VOID +HalpInitializeCiaMachineChecks( + IN BOOLEAN ReportCorrectableErrors, + IN BOOLEAN PciParityChecking + ); + +#if HALDBG + +VOID +DumpCia( + CIA_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 ) \ + HalpCiaInitializeSfwWindow( (WR), CiaIsaWindow ); + + +// +// VOID +// INITIALIZE_MASTER_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_MASTER_DMA_CONTROL( WR ) \ + HalpCiaInitializeSfwWindow( (WR), CiaMasterWindow ); + + +// +// 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 ) \ + HalpCiaProgramDmaWindow( (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 ) \ + HalpCiaInvalidateTlb( (WR), InvalidateAll ); + + +// +// 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 //_CIAH_ diff --git a/private/ntos/nthals/halalpha/ciaaddr.c b/private/ntos/nthals/halalpha/ciaaddr.c new file mode 100644 index 000000000..52d53a696 --- /dev/null +++ b/private/ntos/nthals/halalpha/ciaaddr.c @@ -0,0 +1,567 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + ciaaddr.c + +Abstract: + + This module contains the platform dependent code to create bus addreses + and QVAs for the Alcor system. + +Author: + + Joe Notarangelo 30-Jun-1994 + Steve Brooks 30-Jun-1994 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" +#include "eisa.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 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 call HalCreateQva 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). + + 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 + 34 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. + + + +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; + + PVOID va = 0; // note, this is used for a placeholder + + // + // The buses available on Alcor are EISA and PCI. + // We support any translations for ISA devices as well, + // since they can plug into EISA slots just fine. + // + + if (InterfaceType != Isa && + InterfaceType != Eisa && + InterfaceType != PCIBus) { + + // + // Not on this system; return nothing. + // + + *AddressSpace = 0; + TranslatedAddress->LowPart = 0; + return(FALSE); + + } + + // + // 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 PCIBus: { + + 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 the PCI bus address + // + + TranslatedAddress->LowPart = 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 + + case Eisa: + + break; + + } // switch( InterfaceType ) + + // + // Start with the base physical address and add the + // bus address by converting it to the physical address. + // + + TranslatedAddress->QuadPart = CIA_PCI_SPARSE_MEMORY_PHYSICAL; + TranslatedAddress->QuadPart += + ((ULONGLONG)BusAddress.LowPart << IO_BIT_SHIFT); + + // + // Now call HalCreateQva. This will create a QVA + // that we'll return to the caller. Then we will implicitly set + // AddressSpace to a 1. The caller then will not call MmMapIoSpace + // and will use the address we return as a VA. + // + + TranslatedAddress->LowPart = (ULONG)HalCreateQva( + *TranslatedAddress, + va); + TranslatedAddress->HighPart = 0; // clear high longword for QVA + + *AddressSpace = 1; // don't let the user call + // MmMapIoSpace + return(TRUE); + + case BusIo: + + // + // The address is in PCI I/O space, kernel mode. + // + + switch( InterfaceType ) { + + 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 PCIBus: + + // + // PCI IO space is always below 64MB (26 Bits) BusAddress + // If the address cannot be mapped, just return FALSE. + // + + if( BusAddress.LowPart >= __64MB ){ + + *AddressSpace = 0; + TranslatedAddress->LowPart = 0; + return(FALSE); + + } + + break; + + case Eisa: + + break; + + } // switch( InterfaceType ) + + // + // Start with the base physical address and add the + // bus address by converting it to the physical address. + // + + TranslatedAddress->QuadPart = CIA_PCI_SPARSE_IO_PHYSICAL; + TranslatedAddress->QuadPart += + ((ULONGLONG)BusAddress.LowPart << IO_BIT_SHIFT); + + // + // Now call HalCreateQva. This will create a QVA + // that we'll return to the caller. Then we will implicitly set + // AddressSpace to a 1. The caller then will not call MmMapIoSpace + // and will use the address we return as a VA. + + TranslatedAddress->LowPart = (ULONG)HalCreateQva( + *TranslatedAddress, + va); + TranslatedAddress->HighPart = 0; // clear high longword for QVA + + *AddressSpace = 1; // make sure user doesn't call + // MmMapIoSpace. + return(TRUE); + + 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 = CIA_PCI_SPARSE_MEMORY_PHYSICAL; + TranslatedAddress->QuadPart |= EV5_USER_IO_ADDRESS_SPACE; + TranslatedAddress->QuadPart += (BusAddress.LowPart << IO_BIT_SHIFT); + + *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 = CIA_PCI_SPARSE_IO_PHYSICAL; + TranslatedAddress->QuadPart |= EV5_USER_IO_ADDRESS_SPACE; + TranslatedAddress->QuadPart += (BusAddress.LowPart << IO_BIT_SHIFT); + + *AddressSpace = 0; // Let the user call MmMapIoSpace + + return(TRUE); + + case KernelPciDenseMemory: + case UserPciDenseMemory: + + // + // 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 = CIA_PCI_DENSE_MEMORY_PHYSICAL; + TranslatedAddress->QuadPart |= EV5_USER_IO_ADDRESS_SPACE; + TranslatedAddress->QuadPart += BusAddress.LowPart; + + *AddressSpace = 0; // Let the user call MmMapIoSpace + + 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 called two ways. First, from HalTranslateBusAddress, + if the caller is going to run in kernel mode and use superpages. + The second way is if the user is going to access in user mode. + MmMapIoSpace or ZwViewMapOfSection will call this. + + If the input parameter VA is zero, then we assume super page and build + a QUASI virtual address that is only usable by calling the hal I/O + access routines. + + 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 a sparse 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; + + if( (PA.QuadPart >= CIA_PCI_DENSE_MEMORY_PHYSICAL) && + (PA.QuadPart <= (CIA_PCI_DENSE_MEMORY_PHYSICAL + + PCI_MAX_DENSE_MEMORY_ADDRESS)) ){ + + // + // Kernel-mode physical dense address, return VA. + // + + return(VA); + + } else if( (PA.QuadPart >= + (CIA_PCI_DENSE_MEMORY_PHYSICAL | EV5_USER_IO_ADDRESS_SPACE) ) && + (PA.QuadPart < + (CIA_PCI_DENSE_MEMORY_PHYSICAL | EV5_USER_IO_ADDRESS_SPACE + + PCI_MAX_DENSE_MEMORY_ADDRESS) ) ){ + + // + // User-mode physical dense address, return VA. + // + + return(VA); + + } else { + + // + // The physical address is within one of the sparse I/O spaces. + // + + if (VA == 0) { + + PhysicalOffset.QuadPart = PA.QuadPart - CIA_QVA_PHYSICAL_BASE; + qva = (PVOID)(PhysicalOffset.QuadPart >> IO_BIT_SHIFT); + } else { + + qva = (PVOID)((ULONG)VA >> IO_BIT_SHIFT); + } + + qva = (PVOID)((ULONG)qva | QVA_ENABLE); + + 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 Alcor we support three bus types: + // + // Isa + // Eisa + // PCIBus + // + + switch (InterfaceType ){ + + case Isa: + case Eisa: + case PCIBus: + + // + // Support PCI Dense space: check to see if it's really + // a 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/halalpha/ciaerr.c b/private/ntos/nthals/halalpha/ciaerr.c new file mode 100644 index 000000000..ef984011e --- /dev/null +++ b/private/ntos/nthals/halalpha/ciaerr.c @@ -0,0 +1,1642 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + ciaerr.c + +Abstract: + + This module implements error handling functions for the CIA ASIC. + +Author: + + Joe Notarangelo 26-Jul-1994 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" +#include "cia.h" +#include "stdio.h" + +// +// Externals and globals. +// + +// +// Declare the extern variable UncorrectableError declared in +// inithal.c. +// +extern PERROR_FRAME PUncorrectableError; + +extern ULONG HalDisablePCIParityChecking; +ULONG CiaCorrectedErrors = 0; + +// +// Define the context structure for use by interrupt service routines. +// + +typedef BOOLEAN (*PSECOND_LEVEL_DISPATCH)( + PKINTERRUPT InterruptObject, + PVOID ServiceContext + ); + +// +// Function prototypes. +// + +VOID +HalpSetMachineCheckEnables( + IN BOOLEAN DisableMachineChecks, + IN BOOLEAN DisableProcessorCorrectables, + IN BOOLEAN DisableSystemCorrectables + ); + +VOID +HalpUpdateMces( + IN BOOLEAN ClearMachineCheck, + IN BOOLEAN ClearCorrectableError + ); + +// +// 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 non-zero value indicates that a Master Abort is expected. +// + +ULONG HalpMasterAbortExpected = 0; + + +VOID +HalpInitializeCiaMachineChecks( + IN BOOLEAN ReportCorrectableErrors, + IN BOOLEAN PciParityChecking + ) +/*++ + +Routine Description: + + This routine initializes machine check handling for a CIA-based + system by clearing all pending errors in the CIA 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. + +--*/ +{ + CIA_CONTROL CiaControl; + CIA_ERR CiaError; + CIA_ERR_MASK CiaErrMask; + + // + // Clear any pending error bits in the CIA_ERR register: + // + + CiaError.all = 0; // Clear all bits + + CiaError.CorErr = 1; // Correctable error + CiaError.UnCorErr = 1; // Uncorrectable error + CiaError.CpuPe = 1; // Ev5 bus parity error + CiaError.MemNem = 1; // Nonexistent memory error + CiaError.PciSerr = 1; // PCI bus serr detected + CiaError.PciPerr = 1; // PCI bus perr detected + CiaError.PciAddrPe = 1; // PCI bus address parity error + CiaError.RcvdMasAbt = 1; // Pci Master Abort + CiaError.RcvdTarAbt = 1; // Pci Target Abort + CiaError.PaPteInv = 1; // Invalid Pte + CiaError.FromWrtErr = 1; // Invalid write to flash rom + CiaError.IoaTimeout = 1; // Io Timeout occurred + CiaError.LostCorErr = 1; // Lost correctable error + CiaError.LostUnCorErr = 1; // Lost uncorrectable error + CiaError.LostCpuPe = 1; // Lost Ev5 bus parity error + CiaError.LostMemNem = 1; // Lost Nonexistent memory error + CiaError.LostPciPerr = 1; // Lost PCI bus perr detected + CiaError.LostPciAddrPe = 1; // Lost PCI bus address parity error + CiaError.LostRcvdMasAbt = 1; // Lost Pci Master Abort + CiaError.LostRcvdTarAbt = 1; // Lost Pci Target Abort + CiaError.LostPaPteInv = 1; // Lost Invalid Pte + CiaError.LostFromWrtErr = 1; // Lost Invalid write to flash rom + CiaError.LostIoaTimeout = 1; // Lost Io Timeout occurred + CiaError.ErrValid = 1; // Self explanatory + + WRITE_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr, + CiaError.all + ); + + // + // Set the Mask Bits in the CIA_MASK register: + // + + CiaErrMask.all = 0; // Clear all bits + + CiaErrMask.UnCorErr = 1; // Enable Uncorrectable error + CiaErrMask.CpuPe = 1; // Enable Ev5 bus parity error + CiaErrMask.MemNem = 1; // Enable Nonexistent memory error + CiaErrMask.PciSerr = 1; // Enable PCI bus serr detected + CiaErrMask.RcvdMasAbt = 1; // Enable Pci Master Abort + CiaErrMask.RcvdTarAbt = 1; // Enable Pci Target Abort + CiaErrMask.PaPteInv = 1; // Enable Invalid Pte + CiaErrMask.FromWrtErr = 1; // Enable Invalid write to flash rom + CiaErrMask.IoaTimeout = 1; // Enable Io Timeout occurred + + // + // Determine PCI parity checking. + // + + CiaControl.all = READ_CIA_REGISTER( + &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCtrl ); + + if (PciParityChecking == FALSE) { + + CiaControl.AddrPeEn = 0; // Disable PCI address parity checking + CiaControl.PerrEn = 0; // Disable PCI data parity checking + + CiaErrMask.PciPerr = 0; // Disable PCI bus perr detected + CiaErrMask.PciAddrPe = 0; // Disable PCI bus address parity error + + } else { + + CiaControl.AddrPeEn = PciParityChecking; + CiaControl.PerrEn = PciParityChecking; + + CiaErrMask.PciPerr = PciParityChecking; + CiaErrMask.PciAddrPe = PciParityChecking; + + } + + CiaErrMask.CorErr = (ReportCorrectableErrors == TRUE); + + WRITE_CIA_REGISTER( &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCtrl, + CiaControl.all + ); + + WRITE_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->ErrMask, + CiaErrMask.all + ); + + // + // 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 +HalpCiaUncorrectableError( + VOID + ) +/*++ + +Routine Description: + + Read the CIA 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. + +--*/ +{ + CIA_ERR CiaError; + + + CiaError.all = READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr ); + + // + // If no error is valid then an uncorrectable error was not detected. + // + + if( CiaError.ErrValid == 0 ){ + return FALSE; + } + + // + // Check each of the individual uncorrectable error bits, if any is set + // then return TRUE. + // + + if( (CiaError.UnCorErr == 1) || + (CiaError.CpuPe == 1) || + (CiaError.MemNem == 1) || + (CiaError.PciSerr == 1) || + (CiaError.PciPerr == 1) || + (CiaError.PciAddrPe == 1) || + (CiaError.RcvdMasAbt == 1) || + (CiaError.RcvdTarAbt == 1) || + (CiaError.PaPteInv == 1) || + (CiaError.FromWrtErr == 1) || + (CiaError.IoaTimeout == 1) ){ + + return TRUE; + + } + + // + // None of the uncorrectable error conditions were detected. + // + + return FALSE; + +} + + +VOID +HalpBuildCiaConfigurationFrame( + PCIA_CONFIGURATION pConfiguration + ) +{ + pConfiguration->CiaRev = READ_CIA_REGISTER( + &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaRevision ); + + pConfiguration->CiaCtrl = READ_CIA_REGISTER( + &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCtrl ); + + pConfiguration->Mcr = READ_CIA_REGISTER( + &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Mcr ); + + pConfiguration->Mba0 = READ_CIA_REGISTER( + &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Mba0 ); + + pConfiguration->Mba2 = READ_CIA_REGISTER( + &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Mba2 ); + + pConfiguration->Mba4 = READ_CIA_REGISTER( + &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Mba4 ); + + pConfiguration->Mba6 = READ_CIA_REGISTER( + &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Mba6 ); + + pConfiguration->Mba8 = READ_CIA_REGISTER( + &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Mba8 ); + + pConfiguration->MbaA = READ_CIA_REGISTER( + &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->MbaA ); + + pConfiguration->MbaC = READ_CIA_REGISTER( + &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->MbaC ); + + pConfiguration->MbaE = READ_CIA_REGISTER( + &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->MbaE ); + + pConfiguration->Tmg0 = READ_CIA_REGISTER( + &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Tmg0 ); + + pConfiguration->Tmg1 = READ_CIA_REGISTER( + &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Tmg1 ); + + pConfiguration->Tmg2 = READ_CIA_REGISTER( + &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Tmg2 ); + +} + + +VOID +HalpCiaReportFatalError( + VOID + ) +/*++ + +Routine Description: + + This function reports and interprets a fatal hardware error + detected by the CIA chipset. It is assumed that HalGetDisplayOwnership() + has been called prior to this function. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + UCHAR OutBuffer[ MAX_ERROR_STRING ]; + CIA_ERR CiaError; + CIA_STAT CiaStat; + CIA_SYN CiaSyn; + CIA_CONTROL CiaControl; + CIA_MEM_ERR0 MemErr0; + CIA_MEM_ERR1 MemErr1; + CIA_PCI_ERR0 PciErr0; + CIA_PCI_ERR1 PciErr1; + CIA_PCI_ERR2 PciErr2; + CIA_CPU_ERR0 CpuErr0; + CIA_CPU_ERR1 CpuErr1; + + PUNCORRECTABLE_ERROR uncorr = NULL; + PCIA_UNCORRECTABLE_FRAME ciauncorr = NULL; + PEXTENDED_ERROR PExtErr; + + // + // We will Build the uncorrectable error frame as we read + // the registers to report the error to the blue screen. + // We generate the extended error frame as we generate + // extended messages to print to the screen. + // + + if(PUncorrectableError){ + uncorr = (PUNCORRECTABLE_ERROR) + &PUncorrectableError->UncorrectableFrame; + ciauncorr = (PCIA_UNCORRECTABLE_FRAME) + PUncorrectableError->UncorrectableFrame.RawSystemInformation; + PExtErr = &PUncorrectableError->UncorrectableFrame.ErrorInformation; + } + if(uncorr){ + uncorr->Flags.ProcessorInformationValid = 1; + HalpGetProcessorInfo(&uncorr->ReportingProcessor); + } + + if(ciauncorr) + HalpBuildCiaConfigurationFrame(&ciauncorr->Configuration); + // + // Read the CIA Error register and decode its contents: + // + + CiaError.all = (ULONG)READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr + ); + + if(ciauncorr) + ciauncorr->CiaErr = CiaError.all ; + + // + // Read the rest of the error registers and then unlock them by + // writing to CIA_ERR + // + + CiaStat.all = (ULONG)READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaStat + ); + + + CiaSyn.all = (ULONG)READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaSyn + ); + + + MemErr0.all = (ULONG)READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->MemErr0 + ); + + + MemErr1.all = (ULONG)READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->MemErr1 + ); + + + PciErr0.all = (ULONG)READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr0 + ); + + + PciErr1.PciAddress = (ULONG)READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr1 + ); + + PciErr2.PciAddress = (ULONG)READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr2 + ); + + CpuErr0.all = (ULONG)READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CpuErr0 + ); + + + CpuErr1.all = (ULONG)READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CpuErr1 + ); + + CiaControl.all = READ_CIA_REGISTER( + &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCtrl); + + if(ciauncorr){ + ciauncorr->CiaStat = CiaStat.all; + ciauncorr->CiaSyn = CiaSyn.all; + ciauncorr->MemErr0 = MemErr0.all; + ciauncorr->MemErr1 = MemErr1.all; + ciauncorr->PciErr0 = PciErr0.all; + ciauncorr->PciErr1 = PciErr1.PciAddress; + + ciauncorr->PciErr2 = (ULONG)READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr2 + ); + ciauncorr->CpuErr0 = CpuErr0.all; + + ciauncorr->CpuErr1 = CpuErr1.all; + + ciauncorr->ErrMask = (ULONG)READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->ErrMask + ); + + } + + WRITE_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr, + CiaError.all + ); + + + sprintf( OutBuffer, "CIA_CTRL : %08x\n", CiaControl.all ); + HalDisplayString( OutBuffer ); + DbgPrint( OutBuffer ); + + sprintf( OutBuffer, "CIA_ERR : %08x\n", CiaError.all ); + HalDisplayString( OutBuffer ); + DbgPrint( OutBuffer ); + + sprintf( OutBuffer, "CIA_STAT : %08x\n", CiaStat.all ); + HalDisplayString( OutBuffer ); + DbgPrint( OutBuffer ); + + sprintf( OutBuffer, "CIA_SYN : %08x\n", CiaSyn.all ); + HalDisplayString( OutBuffer ); + DbgPrint( OutBuffer ); + + sprintf( OutBuffer, "PCI_ERR0 : %08x\n", PciErr0.all ); + HalDisplayString( OutBuffer ); + DbgPrint( OutBuffer ); + + sprintf( OutBuffer, "PCI_ERR1 : %08x\n", PciErr1.PciAddress ); + HalDisplayString( OutBuffer ); + DbgPrint( OutBuffer ); + + sprintf( OutBuffer, "PCI_ERR2 : %08x\n", PciErr2.PciAddress ); + HalDisplayString( OutBuffer ); + DbgPrint( OutBuffer ); + + sprintf( OutBuffer, "CPU_ERR0 : %08x\n", CpuErr0.all ); + HalDisplayString( OutBuffer ); + DbgPrint( OutBuffer ); + + sprintf( OutBuffer, "CPU_ERR1 : %08x\n", CpuErr1.all ); + HalDisplayString( OutBuffer ); + DbgPrint( OutBuffer ); + + sprintf( OutBuffer, "MEM_ERR0 : %08x\n", MemErr0.all ); + HalDisplayString( OutBuffer ); + DbgPrint( OutBuffer ); + + sprintf( OutBuffer, "MEM_ERR1 : %08x\n", MemErr1.all ); + HalDisplayString( OutBuffer ); + DbgPrint( OutBuffer ); + + // + // If no valid error then no interpretation. + // + + if ( CiaError.ErrValid == 0 ){ + + return; // No CIA error detected + + } + + // + // Interpret any detected errors: + // + + if ( CiaError.UnCorErr == 1 ){ + + sprintf( OutBuffer, + "CIA Uncorrectable ECC error, Addr=%x%x, Cmd=%x\n", + CpuErr1.Addr34_32, // bits 34:32 + CpuErr0.Addr, // bits 31:4 + CpuErr1.Cmd + ); + if(uncorr){ + uncorr->Flags.ErrorStringValid = 1; + strcpy( uncorr->ErrorString, OutBuffer); + } + + } else if ( CiaError.CpuPe == 1 ){ + + sprintf( OutBuffer, + "EV5 bus parity error, Addr=%x%x, Cmd=%x\n", + CpuErr1.Addr34_32, // bits 34:32 + CpuErr0.Addr, // bits 31:4 + CpuErr1.Cmd + ); + if(uncorr){ + uncorr->Flags.ErrorStringValid = 1; + strcpy( uncorr->ErrorString, OutBuffer); + } + + } else if ( CiaError.MemNem == 1 ){ + + sprintf( OutBuffer, + "CIA Access to non-existent memory, Source=%s, Addr=%x%x\n", + MemErr1.MemPortSrc == 1 ? "DMA" : "CPU", + MemErr1.MemPortSrc == 1 ? 0 : MemErr1.Addr33_32, + MemErr1.MemPortSrc == 1 ? PciErr1.PciAddress : MemErr0.Addr31_4 + ); + if(uncorr){ + uncorr->Flags.ErrorStringValid = 1; + strcpy( uncorr->ErrorString, OutBuffer); + } + + } else if ( CiaError.PciSerr == 1 ){ + + sprintf( OutBuffer, + "PCI bus SERR detected, Cmd=%x, Window=%d, Addr=%x\n", + PciErr0.Cmd, + PciErr0.Window, + PciErr1.PciAddress + ); + + if(uncorr){ + uncorr->Flags.ErrorStringValid = 1; + strcpy( uncorr->ErrorString, OutBuffer); + uncorr->Flags.AddressSpace = IO_SPACE; + uncorr->Flags.PhysicalAddressValid = 1; + uncorr->PhysicalAddress = PciErr1.PciAddress; + + uncorr->Flags.ExtendedErrorValid = 1; + PExtErr->IoError.Interface = PCIBus; + PExtErr->IoError.BusNumber = 0; + PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress; + } + + } else if ( CiaError.PciPerr == 1 ){ + + sprintf( OutBuffer, + "PCI bus Data Parity error, Cmd=%x, Window=%d, Addr=%x\n", + PciErr0.Cmd, + PciErr0.Window, + PciErr1.PciAddress + ); + + if(uncorr){ + uncorr->Flags.ErrorStringValid = 1; + strcpy( uncorr->ErrorString, OutBuffer); + uncorr->Flags.AddressSpace = IO_SPACE; + uncorr->Flags.PhysicalAddressValid = 1; + uncorr->PhysicalAddress = PciErr1.PciAddress; + + uncorr->Flags.ExtendedErrorValid = 1; + PExtErr->IoError.Interface = PCIBus; + PExtErr->IoError.BusNumber = 0; + PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress; + } + + } else if ( CiaError.PciAddrPe == 1 ){ + + sprintf( OutBuffer, + "Pci bus Address Parity error, Cmd=%x, Window=%x, Addr=%x\n", + PciErr0.Cmd, + PciErr0.Window, + PciErr1.PciAddress + ); + if(uncorr){ + uncorr->Flags.ErrorStringValid = 1; + strcpy( uncorr->ErrorString, OutBuffer); + uncorr->Flags.AddressSpace = IO_SPACE; + uncorr->Flags.PhysicalAddressValid = 1; + uncorr->PhysicalAddress = PciErr1.PciAddress; + + uncorr->Flags.ExtendedErrorValid = 1; + PExtErr->IoError.Interface = PCIBus; + PExtErr->IoError.BusNumber = 0; + PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress; + } + + } else if ( CiaError.RcvdMasAbt == 1 ){ + + sprintf( OutBuffer, + "PCI Master abort occurred, Cmd=%x, Window=%x, Addr=%x\n", + PciErr0.Cmd, + PciErr0.Window, + PciErr1.PciAddress + ); + if(uncorr){ + uncorr->Flags.ErrorStringValid = 1; + strcpy( uncorr->ErrorString, OutBuffer); + uncorr->Flags.AddressSpace = IO_SPACE; + uncorr->Flags.PhysicalAddressValid = 1; + uncorr->PhysicalAddress = PciErr1.PciAddress; + + uncorr->Flags.ExtendedErrorValid = 1; + PExtErr->IoError.Interface = PCIBus; + PExtErr->IoError.BusNumber = 0; + PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress; + } + + } else if ( CiaError.RcvdTarAbt == 1 ){ + + sprintf( OutBuffer, + "PCI Target abort occurred, Cmd=%x, Window=%x, Addr=%x\n", + PciErr0.Cmd, + PciErr0.Window, + PciErr1.PciAddress + ); + if(uncorr){ + uncorr->Flags.ErrorStringValid = 1; + strcpy( uncorr->ErrorString, OutBuffer); + uncorr->Flags.AddressSpace = IO_SPACE; + uncorr->Flags.PhysicalAddressValid = 1; + uncorr->PhysicalAddress = PciErr1.PciAddress; + + uncorr->Flags.ExtendedErrorValid = 1; + PExtErr->IoError.Interface = PCIBus; + PExtErr->IoError.BusNumber = 0; + PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress; + } + + } else if ( CiaError.PaPteInv == 1 ){ + + sprintf( OutBuffer, + "Invalid Scatter/Gather PTE, Cmd=%x, Window=%x, Addr=%x\n", + PciErr0.Cmd, + PciErr0.Window, + PciErr1.PciAddress + ); + if(uncorr){ + uncorr->Flags.ErrorStringValid = 1; + strcpy( uncorr->ErrorString, OutBuffer); + uncorr->Flags.AddressSpace = IO_SPACE; + uncorr->Flags.PhysicalAddressValid = 1; + uncorr->PhysicalAddress = PciErr1.PciAddress; + + uncorr->Flags.ExtendedErrorValid = 1; + PExtErr->IoError.Interface = PCIBus; + PExtErr->IoError.BusNumber = 0; + PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress; + } + + } else if ( CiaError.FromWrtErr == 1 ){ + + sprintf( OutBuffer, + "Write to Flash ROM with FROM_WRT_EN clear" + ); + if(uncorr){ + uncorr->Flags.ErrorStringValid = 1; + strcpy( uncorr->ErrorString, OutBuffer); + } + + } else if ( CiaError.IoaTimeout == 1){ + + sprintf( OutBuffer, + "PCI bus I/O timeout occurred, Cmd=%x, Window=%x, Addr=%x\n", + PciErr0.Cmd, + PciErr0.Window, + PciErr1.PciAddress + ); + if(uncorr){ + uncorr->Flags.ErrorStringValid = 1; + strcpy( uncorr->ErrorString, OutBuffer); + uncorr->Flags.AddressSpace = IO_SPACE; + uncorr->Flags.PhysicalAddressValid = 1; + uncorr->PhysicalAddress = PciErr1.PciAddress; + + uncorr->Flags.ExtendedErrorValid = 1; + PExtErr->IoError.Interface = PCIBus; + PExtErr->IoError.BusNumber = 0; + PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress; + } + } + + + // + // Output the detected error message: + // + + HalDisplayString( "\n" ); + HalDisplayString( OutBuffer ); + +#if HALDBG + DbgPrint( OutBuffer ); +#endif + + + // + // Check for lost errors and output message if any occurred: + // + + if ( (CiaError.all & CIA_ERR_LOST_MASK) != 0 ){ + + HalDisplayString("\nCIA Lost errors were detected\n\n"); + } + + return; // Fatal error detected +} + + +BOOLEAN +HalpCiaMachineCheck( + 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 CIA 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. + +--*/ +{ + CIA_ERR CiaError; + + // + // Read the CIA error register to determine the source of the + // error. + // + + CiaError.all = READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr ); + +#if HALDBG + + DbgPrint( "Cia Mchk: 0x%x\n", CiaError.all ); + +#endif //HALDBG + + // + // Check that an error is valid. If it is not this is a pretty + // weird fatal condition. + // + + if( CiaError.ErrValid == 0 ){ + DbgPrint( "Error reported but error valid = 0, CiaErr = 0x%x\n", + CiaError.all ); + goto FatalError; + } + + // + // Check for any uncorrectable error other than a master abort + // on a PCI transaction. Any of these other errors indicate a + // fatal condition. + // + + if( (CiaError.UnCorErr == 1) || // Uncorrectable error + (CiaError.CpuPe == 1) || // Ev5 bus parity error + (CiaError.MemNem == 1) || // Nonexistent memory error + (CiaError.PciSerr == 1) || // PCI bus serr detected + (CiaError.PciPerr == 1) || // PCI bus perr detected + (CiaError.PciAddrPe == 1) || // PCI bus address parity error + (CiaError.RcvdTarAbt == 1) || // Pci Target Abort + (CiaError.PaPteInv == 1) || // Invalid Pte + (CiaError.FromWrtErr == 1) || // Invalid write to flash rom + (CiaError.IoaTimeout == 1) || // Io Timeout occurred + (CiaError.LostUnCorErr == 1) || // Lost uncorrectable error + (CiaError.LostCpuPe == 1) || // Lost Ev5 bus parity error + (CiaError.LostMemNem == 1) || // Lost Nonexistent memory error + (CiaError.LostPciPerr == 1) || // Lost PCI bus perr detected + (CiaError.LostPciAddrPe == 1) || // Lost PCI address parity error + (CiaError.LostRcvdMasAbt == 1) || // Lost Pci Master Abort + (CiaError.LostRcvdTarAbt == 1) || // Lost Pci Target Abort + (CiaError.LostPaPteInv == 1) || // Lost Invalid Pte + (CiaError.LostFromWrtErr == 1) || // Lost Invalid write to flash rom + (CiaError.LostIoaTimeout == 1) // Lost Io Timeout occurred + ){ + DbgPrint( "Explicit fatal error, CiaErr = 0x%x\n", + CiaError.all ); + goto FatalError; + } + + // + // Check for a PCI configuration read error. The CIA experiences + // a master abort on a read to a non-existent PCI slot. + // + + if( (CiaError.RcvdMasAbt == 1) && (HalpMasterAbortExpected != 0) ){ + + // + // 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 of 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; + BOOLEAN PreviousInstruction = FALSE; + + 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 the error condition in CIA_ERR. + // + + CiaError.all = 0; + CiaError.RcvdMasAbt = 1; + CiaError.ErrValid = 1; + WRITE_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr, + CiaError.all ); + + return TRUE; + + } //end if( (CiaError.RcvdMasAbt == 1) && (HalpMasterAbortExpected != 0) ) + + DbgPrint( "Unexpected master abort\n" ); + +// +// The system is not well and cannot continue reliable execution. +// Print some useful messages and return FALSE to indicate that the error +// was not handled. +// + +FatalError: + + DbgPrint( "Handling fatal error\n" ); + + // + // Clear the error condition in the MCES register. + // + + HalpUpdateMces( TRUE, TRUE ); + + // + // Proceed to display the error. + // + + HalAcquireDisplayOwnership(NULL); + + // + // Display the dreaded banner. + // + + HalDisplayString( "\nFatal system hardware error.\n\n" ); + + + HalpCiaReportFatalError(); + + return( FALSE ); + +} + +BOOLEAN +HalpTranslateSynToEcc( + PULONG Syndrome + ) +/*++ + +Routine Description: + + Translate a syndrome code to ECC error bit code. + +Arguments: + + Syndrome - pointer to the syndrome. + +Return Value: + + True if a data bit is in error. False otherwise. + +--*/ +{ + static UCHAR SynToEccTable[0xff] = {0, }; + static BOOLEAN SynToEccTableInitialized = FALSE; + ULONG Temp; + + // + // Initialize the table. + // + + if (!SynToEccTableInitialized) { + + SynToEccTableInitialized = TRUE; + + // + // Fill in the table. + // + + SynToEccTable[0x01] = 0; + SynToEccTable[0x02] = 1; + SynToEccTable[0x04] = 2; + SynToEccTable[0x08] = 3; + SynToEccTable[0x10] = 4; + SynToEccTable[0x20] = 5; + SynToEccTable[0x40] = 6; + SynToEccTable[0x80] = 7; + SynToEccTable[0xce] = 0; + SynToEccTable[0xcb] = 1; + SynToEccTable[0xd3] = 2; + SynToEccTable[0xd5] = 3; + SynToEccTable[0xd6] = 4; + SynToEccTable[0xd9] = 5; + SynToEccTable[0xda] = 6; + SynToEccTable[0xdc] = 7; + SynToEccTable[0x23] = 8; + SynToEccTable[0x25] = 9; + SynToEccTable[0x26] = 10; + SynToEccTable[0x29] = 11; + SynToEccTable[0x2a] = 12; + SynToEccTable[0x2c] = 13; + SynToEccTable[0x31] = 14; + SynToEccTable[0x34] = 15; + SynToEccTable[0x0e] = 16; + SynToEccTable[0x0b] = 17; + SynToEccTable[0x13] = 18; + SynToEccTable[0x15] = 19; + SynToEccTable[0x16] = 20; + SynToEccTable[0x19] = 21; + SynToEccTable[0x1a] = 22; + SynToEccTable[0x1c] = 23; + SynToEccTable[0xe3] = 24; + SynToEccTable[0xe5] = 25; + SynToEccTable[0xe6] = 26; + SynToEccTable[0xe9] = 27; + SynToEccTable[0xea] = 28; + SynToEccTable[0xec] = 29; + SynToEccTable[0xf1] = 30; + SynToEccTable[0xf4] = 31; + SynToEccTable[0x4f] = 32; + SynToEccTable[0x4a] = 33; + SynToEccTable[0x52] = 34; + SynToEccTable[0x54] = 35; + SynToEccTable[0x57] = 36; + SynToEccTable[0x58] = 37; + SynToEccTable[0x5b] = 38; + SynToEccTable[0x5d] = 39; + SynToEccTable[0xa2] = 40; + SynToEccTable[0xa4] = 41; + SynToEccTable[0xa7] = 42; + SynToEccTable[0xa8] = 43; + SynToEccTable[0xab] = 44; + SynToEccTable[0xad] = 45; + SynToEccTable[0xb0] = 46; + SynToEccTable[0xb5] = 47; + SynToEccTable[0x8f] = 48; + SynToEccTable[0x8a] = 49; + SynToEccTable[0x92] = 50; + SynToEccTable[0x94] = 51; + SynToEccTable[0x97] = 52; + SynToEccTable[0x98] = 53; + SynToEccTable[0x9b] = 54; + SynToEccTable[0x9d] = 55; + SynToEccTable[0x62] = 56; + SynToEccTable[0x64] = 57; + SynToEccTable[0x67] = 58; + SynToEccTable[0x68] = 59; + SynToEccTable[0x6b] = 60; + SynToEccTable[0x6d] = 61; + SynToEccTable[0x70] = 62; + SynToEccTable[0x75] = 63; + } + + // + // Tranlate the syndrome code. + // + + Temp = *Syndrome; + *Syndrome = SynToEccTable[Temp]; + + // + // Is it a data bit or a check bit in error? + // + + if (Temp == 0x01 || Temp == 0x02 || Temp == 0x04 || Temp == 0x08 || + Temp == 0x10 || Temp == 0x20 || Temp == 0x40 || Temp == 0x80) { + + return FALSE; + + } else { + + return TRUE; + } +} + + + +VOID +HalpCiaErrorInterrupt( + VOID + ) +/*++ + +Routine Description: + + Handle a CIA correctable error interrupt. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + static ERROR_FRAME Frame; + static CIA_CORRECTABLE_FRAME AlcorFrame; + + ERROR_FRAME TempFrame; + PCORRECTABLE_ERROR CorrPtr; + PBOOLEAN ErrorlogBusy; + PULONG DispatchCode; + ULONG Syndrome; + PKINTERRUPT InterruptObject; + PKSPIN_LOCK ErrorlogSpinLock; + + CIA_ERR CiaError; + CIA_STAT CiaStat; + CIA_SYN CiaSyn; + CIA_MEM_ERR0 MemErr0; + CIA_MEM_ERR1 MemErr1; + CIA_PCI_ERR0 PciErr0; + CIA_PCI_ERR1 PciErr1; + CIA_PCI_ERR2 PciErr2; + + // + // 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. + // + + CiaError.all = READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr ); + + // + // Check if an error is latched into the CIA. + // + + if( CiaError.ErrValid == 0 ){ + +#if HALDBG + + DbgPrint( "Cia error interrupt without valid CIA error\n" ); + +#endif //HALDBG + + return; + } + + // + // Check for the correctable error bit. + // + + if( CiaError.CorErr == 0 ){ + +#if HALDBG + + DbgPrint( "Cia error interrupt without correctable error indicated\n" ); + +#endif //HALDBG + + } + + // + // Real error, get the interrupt object. + // + + DispatchCode = (PULONG)(PCR->InterruptRoutine[CORRECTABLE_VECTOR]); + InterruptObject = CONTAINING_RECORD(DispatchCode, + KINTERRUPT, + DispatchCode); + + // + // Set various pointers so we can use them later. + // + + CorrPtr = &TempFrame.CorrectableFrame; + 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, sizeof(ERROR_FRAME)); + + // + // Increment the number of CIA correctable errors. + // + + CiaCorrectedErrors += 1; + + CiaStat.all = READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaStat ); + + CiaSyn.all = READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaSyn ); + + MemErr0.all = READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->MemErr0 ); + + MemErr1.all = READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->MemErr1 ); + + PciErr0.all = READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr0 ); + + PciErr1.PciAddress = READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr1 ); + + PciErr2.PciAddress = READ_CIA_REGISTER( + &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr2 ); + + + // + // Print a correctable error message to the debugger. + // + +#if HALDBG + DbgPrint( "CIA Correctable Error Number %d, state follows: \n", + CiaCorrectedErrors ); + DbgPrint( "\tCIA_ERR : 0x%x\n", CiaError.all ); + DbgPrint( "\tCIA_STAT: 0x%x\n", CiaStat.all ); + DbgPrint( "\tCIA_SYN : 0x%x\n", CiaSyn.all ); + DbgPrint( "\tCIA_MEM0: 0x%x\n", MemErr0.all ); + DbgPrint( "\tCIA_MEM1: 0x%x\n", MemErr1.all ); + DbgPrint( "\tPCI_ERR0: 0x%x\n", PciErr0.all ); +#endif //HALDBG + + // + // Fill in the error frame information. + // + + TempFrame.Signature = ERROR_FRAME_SIGNATURE; + TempFrame.FrameType = CorrectableFrame; + TempFrame.VersionNumber = ERROR_FRAME_VERSION; + TempFrame.SequenceNumber = CiaCorrectedErrors; + TempFrame.PerformanceCounterValue = + KeQueryPerformanceCounter(NULL).QuadPart; + + // + // Check for lost error. + // + + if( CiaError.LostCorErr ) { + + // + // Since the error registers are locked from a previous error, + // we don't know where the error came from. Mark everything + // as UNIDENTIFIED. + // + + CorrPtr->Flags.LostCorrectable = 1; + CorrPtr->Flags.LostAddressSpace = UNIDENTIFIED; + CorrPtr->Flags.LostMemoryErrorSource = UNIDENTIFIED; + } + + // + // Set error bit error masks. + // + + CorrPtr->Flags.ErrorBitMasksValid = 1; + Syndrome = CiaSyn.all; + + if ( HalpTranslateSynToEcc(&Syndrome) ) + CorrPtr->DataBitErrorMask = 1 << Syndrome; + else + CorrPtr->CheckBitErrorMask = 1 << Syndrome; + + // + // Determine error type. + // + switch (CiaStat.DmSt) { + + case CIA_IO_WRITE_ECC: + + // + // I/O write ECC error occurred. + // + + CorrPtr->Flags.AddressSpace = IO_SPACE; + + CorrPtr->Flags.ExtendedErrorValid = 1; + CorrPtr->ErrorInformation.IoError.Interface = PCIBus; + CorrPtr->ErrorInformation.IoError.BusNumber = 0; + CorrPtr->ErrorInformation.IoError.BusAddress.LowPart= PciErr1.PciAddress; + CorrPtr->ErrorInformation.IoError.TransferType = BUS_IO_WRITE; + break; + + case CIA_DMA_READ_ECC: + + CorrPtr->Flags.AddressSpace = MEMORY_SPACE; + CorrPtr->Flags.ExtendedErrorValid = 1; + + // + // Where did the error come from? + // + + if ( CiaStat.PaCpuRes == CIA_PROCESSOR_CACHE_ECC ) { + + // + // Correctable error comes from processor cache. + // + + CorrPtr->Flags.MemoryErrorSource = PROCESSOR_CACHE; + + // + // DMA read or TLB miss error occurred. + // + + if ( CiaStat.TlbMiss ) + CorrPtr->ErrorInformation.CacheError.TransferType = TLB_MISS_READ; + else + CorrPtr->ErrorInformation.CacheError.TransferType = BUS_DMA_READ; + + } else if ( CiaStat.PaCpuRes == CIA_SYSTEM_CACHE_ECC ) { + + // + // Correctable error comes from system cache. + // + + CorrPtr->Flags.MemoryErrorSource = SYSTEM_CACHE; + + // + // DMA read or TLB miss error occurred. + // + + if ( CiaStat.TlbMiss ) + CorrPtr->ErrorInformation.CacheError.TransferType = TLB_MISS_READ; + else + CorrPtr->ErrorInformation.CacheError.TransferType = BUS_DMA_READ; + + } else { + + // + // Correctable error comes from system memory. + // + + CorrPtr->Flags.MemoryErrorSource = SYSTEM_MEMORY; + + // + // DMA read or TLB miss error occurred. + // + + if ( CiaStat.TlbMiss ) + CorrPtr->ErrorInformation.MemoryError.TransferType = TLB_MISS_READ; + else + CorrPtr->ErrorInformation.MemoryError.TransferType = BUS_DMA_READ; + } + + break; + + case CIA_DMA_WRITE_ECC: + + CorrPtr->Flags.AddressSpace = MEMORY_SPACE; + CorrPtr->Flags.ExtendedErrorValid = 1; + + // + // Where did the error come from? + // + + if ( CiaStat.PaCpuRes == CIA_PROCESSOR_CACHE_ECC ) { + + // + // Correctable error comes from processor cache. + // + + CorrPtr->Flags.MemoryErrorSource = PROCESSOR_CACHE; + + // + // DMA write or TLB miss error occurred. + // + + if ( CiaStat.TlbMiss ) + CorrPtr->ErrorInformation.CacheError.TransferType = TLB_MISS_WRITE; + else + CorrPtr->ErrorInformation.CacheError.TransferType = BUS_DMA_WRITE; + + } else if ( CiaStat.PaCpuRes == CIA_SYSTEM_CACHE_ECC ) { + + // + // Correctable error comes from system cache. + // + + CorrPtr->Flags.MemoryErrorSource = SYSTEM_CACHE; + + // + // DMA write or TLB miss error occurred. + // + + if ( CiaStat.TlbMiss ) + CorrPtr->ErrorInformation.CacheError.TransferType = TLB_MISS_WRITE; + else + CorrPtr->ErrorInformation.CacheError.TransferType = BUS_DMA_WRITE; + + } else { + + // + // Correctable error comes from system memory. + // + + CorrPtr->Flags.MemoryErrorSource = SYSTEM_MEMORY; + + // + // DMA write or TLB miss error occurred. + // + + if ( CiaStat.TlbMiss ) + CorrPtr->ErrorInformation.MemoryError.TransferType = TLB_MISS_WRITE; + else + CorrPtr->ErrorInformation.MemoryError.TransferType = BUS_DMA_WRITE; + + // + // + } + + break; + + case CIA_IO_READ_ECC: + + // + // I/O read ECC error occurred. + // + + CorrPtr->Flags.AddressSpace = IO_SPACE; + + CorrPtr->Flags.ExtendedErrorValid = 1; + CorrPtr->ErrorInformation.IoError.Interface = PCIBus; + CorrPtr->ErrorInformation.IoError.BusNumber = 0; + CorrPtr->ErrorInformation.IoError.BusAddress.LowPart= PciErr1.PciAddress; + CorrPtr->ErrorInformation.IoError.TransferType = BUS_IO_READ; + break; + + default: + + // + // Something strange happened. Don't know where the error occurred. + // + + CorrPtr->Flags.AddressSpace = UNIDENTIFIED; + break; + } + + // + // Get the physical address where the error occurred. + // + + CorrPtr->Flags.PhysicalAddressValid = 1; + CorrPtr->PhysicalAddress = (MemErr1.all & 0xff) << 32; + CorrPtr->PhysicalAddress |= MemErr0.all; + + // + // Get bits 7:0 of the address from the PCI address. + // + + CorrPtr->PhysicalAddress |= PciErr1.PciAddress & 0xff; + + // + // Scrub the error if it's any type of memory error. + // + + if ( CorrPtr->Flags.AddressSpace == MEMORY_SPACE && + CorrPtr->Flags.PhysicalAddressValid ) + CorrPtr->Flags.ScrubError = 1; + + // + // Acquire the spinlock. + // + + KiAcquireSpinLock(ErrorlogSpinLock); + + // + // Check to see if an errorlog operation is in progress already. + // + + if (!*ErrorlogBusy) { + + // + // 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. + // + + AlcorFrame.CiaErr = CiaError.all; + + AlcorFrame.CiaStat = CiaStat.all; + + AlcorFrame.CiaSyn = CiaSyn.all; + + AlcorFrame.MemErr0 = MemErr0.all; + + AlcorFrame.MemErr1 = MemErr1.all; + + AlcorFrame.PciErr0 = PciErr0.all; + + AlcorFrame.PciErr1 = PciErr1.PciAddress; + + AlcorFrame.PciErr2 = PciErr2.PciAddress; + + // + // Read the CIA configuration registers for logging information. + // + + AlcorFrame.Configuration.CiaRev = + READ_CIA_REGISTER( &((PCIA_GENERAL_CSRS) + (CIA_GENERAL_CSRS_QVA))->CiaRevision ); + + AlcorFrame.Configuration.CiaCtrl = + READ_CIA_REGISTER( &((PCIA_GENERAL_CSRS) + (CIA_GENERAL_CSRS_QVA))->CiaCtrl ); + + AlcorFrame.Configuration.Mcr = + READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS) + (CIA_MEMORY_CSRS_QVA))->Mcr ); + + AlcorFrame.Configuration.Mba0 = + READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS) + (CIA_MEMORY_CSRS_QVA))->Mba0 ); + + AlcorFrame.Configuration.Mba2 = + READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS) + (CIA_MEMORY_CSRS_QVA))->Mba2 ); + + AlcorFrame.Configuration.Mba4 = + READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS) + (CIA_MEMORY_CSRS_QVA))->Mba4 ); + + AlcorFrame.Configuration.Mba6 = + READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS) + (CIA_MEMORY_CSRS_QVA))->Mba6 ); + + AlcorFrame.Configuration.Mba8 = + READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS) + (CIA_MEMORY_CSRS_QVA))->Mba8 ); + + AlcorFrame.Configuration.MbaA = + READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS) + (CIA_MEMORY_CSRS_QVA))->MbaA ); + + AlcorFrame.Configuration.MbaC = + READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS) + (CIA_MEMORY_CSRS_QVA))->MbaC ); + + AlcorFrame.Configuration.MbaE = + READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS) + (CIA_MEMORY_CSRS_QVA))->MbaE ); + + AlcorFrame.Configuration.Tmg0 = + READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS) + (CIA_MEMORY_CSRS_QVA))->Tmg0 ); + + AlcorFrame.Configuration.Tmg1 = + READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS) + (CIA_MEMORY_CSRS_QVA))->Tmg1 ); + + AlcorFrame.Configuration.Tmg2 = + READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS) + (CIA_MEMORY_CSRS_QVA))->Tmg2 ); + + AlcorFrame.Configuration.CacheCnfg = + PCR->SecondLevelCacheSize; + + // + // Set the raw system information. + // + + CorrPtr->RawSystemInformationLength = sizeof(CIA_CORRECTABLE_FRAME); + CorrPtr->RawSystemInformation = &AlcorFrame; + + // + // Set the raw processor information. Disregard at the moment. + // + + CorrPtr->RawProcessorInformationLength = 0; + + // + // Set reporting processor information. Disregard at the moment. + // + + CorrPtr->Flags.ProcessorInformationValid = 0; + + // + // Set system information. Disregard at the moment. + // + + CorrPtr->Flags.SystemInformationValid = 0; + + // + // Copy the information that we need to log. + // + + RtlCopyMemory(&Frame, + &TempFrame, + sizeof(ERROR_FRAME)); + + // + // Put frame into ISR service context. + // + + *(PERROR_FRAME *)InterruptObject->ServiceContext = &Frame; + + } else { + + // + // An errorlog operation is in progress already. We will + // set various lost bits and then get out without doing + // an actual errorloging call. + // + + Frame.CorrectableFrame.Flags.LostCorrectable = TRUE; + Frame.CorrectableFrame.Flags.LostAddressSpace = + TempFrame.CorrectableFrame.Flags.AddressSpace; + Frame.CorrectableFrame.Flags.LostMemoryErrorSource = + TempFrame.CorrectableFrame.Flags.MemoryErrorSource; + } + + // + // Release the spinlock. + // + + KiReleaseSpinLock(ErrorlogSpinLock); + + // + // 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 the corrected error status bit and return to continue + // execution. + // + + CiaError.all = 0; + CiaError.CorErr = 1; + WRITE_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr, + CiaError.all ); + + return; + +} diff --git a/private/ntos/nthals/halalpha/ciaio.s b/private/ntos/nthals/halalpha/ciaio.s new file mode 100644 index 000000000..073a25ea6 --- /dev/null +++ b/private/ntos/nthals/halalpha/ciaio.s @@ -0,0 +1,2820 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + ciaio.s + +Abstract: + + This module implements the I/O access routines for the CIA ASIC. + + 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: + + Steve Brooks 1-Jul-1994 + Joe Notarangelo 1-Jul-1994 + +Environment: + + Executes in kernel mode. + +Revision History: + + +--*/ + +#include "cia.h" +#include "halalpha.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. +// + +#define CIA_DENSE_MEM_SVA -0x37a0 // negative of 0xc860 +#define CIA_SPARSE_MEM_SVA -0x3800 // negative of 0xc800 +#define CIA_SPARSE_IO_SVA -0x37a8 // negative of 0xc858 +#define CIA_PCI_CONFIG_SVA -0x3790 // negative of 0xc870 +#define CIA_REGISTER_SVA -0x3790 // negative of 0xc870 +#define CIA_PCI_INTACK_SVA -0x378e // negative of 0xc872 + + + 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> + bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff c800 + sll t4, 28, t4 // 0xffff fc80 0000 0000 + or t0, t4, t0 // superpage mode + + 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 + lda t0, CIA_DENSE_MEM_SVA(zero) // 0xffff ffff ffff c860 + sll t0, 28, t0 // 0xffff fc86 0000 0000 + bis t0, a0, t0 // 0xffff fc86 xxxx xxxx + 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> + bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff c858 0000 + sll t4, 28, t4 // 0xffff fc85 8000 0000 + or t0, t4, t0 // superpage mode + + 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> + bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff c800 + sll t4, 28, t4 // 0xffff fc80 0000 0000 + bis t0, t4, t0 // superpage mode + + bis t0, IO_WORD_LEN, t0 // set size to short + + 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 + lda t0, CIA_DENSE_MEM_SVA(zero) // 0xffff ffff ffff c860 + sll t0, 28, t0 // 0xffff fc86 0000 0000 + bis t0, a0, t0 // 0xffff fc86 xxxx xxxx + 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> + bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858 + sll t4, 28, t4 // 0xffff fc85 8000 0000 + bis t0, t4, t0 // superpage mode + + bis t0, IO_WORD_LEN, t0 // set size to short + + 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> + bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff c800 + sll t4, 28, t4 // 0xffff fc80 0000 0000 + bis t0, t4, t0 // superpage mode + + bis t0, IO_LONG_LEN, t0 // set size to long + + mb // ensure all writes are visible + ldl v0, (t0) // get the longword + + ret zero, (ra) // return + +// +// Dense space access. +// + +10: + zap a0, 0xf0, a0 // clear <63:32> + lda t0, CIA_DENSE_MEM_SVA(zero) // 0xffff ffff ffff c860 + sll t0, 28, t0 // 0xffff fc86 0000 0000 + bis t0, a0, t0 // 0xffff fc86 xxxx xxxx + ldl v0, 0(t0) // read from dense space + + 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> + bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c800 + sll t4, 28, t4 // 0xffff fc80 0000 0000 + bis t0, t4, t0 // superpage mode + + bis t0, IO_LONG_LEN, t0 // set size to short + + 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> + bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff c800 + sll t4, 28, t4 // 0xffff fc80 0000 0000 + 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 + lda t0, CIA_DENSE_MEM_SVA(zero) // 0xffff ffff ffff c860 + sll t0, 28, t0 // 0xffff fc86 0000 0000 + bis t0, a0, t0 // 0xffff fc86 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> + bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858 + sll t4, 28, t4 // 0xffff fc85 8000 0000 + 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> + bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff c800 + sll t4, 28, t4 // 0xffff fc80 0000 0000 + or t0, t4, t0 // superpage mode + + bis 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 + lda t0, CIA_DENSE_MEM_SVA(zero) // 0xffff ffff ffff c860 + sll t0, 28, t0 // 0xffff fc86 0000 0000 + bis t0, a0, t0 // 0xffff fc86 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> + bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858 + sll t4, 28, t4 // 0xffff fc85 8000 0000 + or t0, t4, t0 // superpage mode + + bis 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> + bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff c800 + sll t4, 28, t4 // 0xffff fc80 0000 0000 + or t0, t4, t0 // superpage mode + + bis 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> + lda t0, CIA_DENSE_MEM_SVA(zero) // 0xffff ffff ffff c860 + sll t0, 28, t0 // 0xffff fc86 0000 0000 + bis t0, a0, t0 // 0xffff fc86 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> + bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858 + sll t4, 28, t4 // 0xffff fc85 8000 0000 + or t0, t4, t0 // superpage mode + + bis 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 CIA Register" ) +//++ +// +// VOID +// WRITE_CIA_REGISTER( +// IN PVOID RegisterQva, +// IN ULONG Value +// ) +// +// Routine Description: +// +// Write a CIA 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 CIA CSRS exceed the 34 bit +// capacity of the QVAs, the QVA values of the CIA CSRS specify +// the offset of the QVAs from the CIA CSR base address (87.4000.0000) +//-- + + LEAF_ENTRY(WRITE_CIA_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, 5, t0 // + lda t4, CIA_REGISTER_SVA(zero) // 0xffff ffff ffff c870 + sll t4, 28, t4 // 0xffff fc87 0000 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_CIA_REGISTER + + + SBTTL( "Read Control Register" ) +//++ +// +// ULONG +// READ_CIA_REGISTER( +// IN PVOID RegisterQva +// ) +// +// Routine Description: +// +// Read a CIA 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_CIA_REGISTER) + + ALTERNATE_ENTRY(READ_GRU_REGISTER) + +// +// Generate the superpage address of the requested CIA 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, 5, t0 // + lda t4, CIA_REGISTER_SVA(zero) // 0xffff ffff ffff c870 + sll t4, 28, t4 // 0xffff fc87 0000 0000 + or t0, t4, t0 // superpage mode + +// +// Read the CIA revision saved in a global variable. +// + + lda t1, HalpCiaRevision // get revision id global address + ldl t1, 0(t1) // get revision id + bne t1, 10f // if ne, not pass 1 CIA + +// +// Pass 1 CIA required the following work-around to avoid IBOX timeout +// errors. +// + + ldil t5, 100 // iterations to wait for istream + // prefetches to settle + +1: + subl t5, 1, t5 // decrement wait count + bgt t5, 2f // continue wait until count = 0 + + mb // wait for write buffer + ldl v0, (t0) // read the register + bis v0, zero, v0 // wait for read to complete + +2: + bgt t5, 1b // if gt, still waiting + + ret zero, (ra) // return + +// +// Perform the read of the requested CIA register and return. +// + +10: + ldl v0, (t0) // read the register + + ret zero, (ra) // return + +// +// The requested CIA 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_CIA_REGISTER + + + 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> + bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858 + sll t4, 28, t4 // 0xffff fc85 8000 0000 + 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> + + bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858 + sll t4, 28, t4 // 0xffff fc85 8000 0000 + 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> + + bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + + lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858 + sll t4, 28, t4 // 0xffff fc85 8000 0000 + 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> + + bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858 + sll t4, 28, t4 // 0xffff fc85 8000 0000 + 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> + + bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858 + sll t4, 28, t4 // 0xffff fc85 8000 0000 + 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> + + bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858 + sll t4, 28, t4 // 0xffff fc85 8000 0000 + 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 +// + ldil t8, 1 // DENSE FLAG + zap a0, 0xf0, a0 // clear <63:32> + lda t0, CIA_DENSE_MEM_SVA(zero) // 0xffff ffff ffff c860 + sll t0, 28, t0 // 0xffff fc86 0000 0000 + 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: + ldil t8, 0 // SPARSE FLAG + 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 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff c800 + sll t4, 28, t4 // 0xffff fc80 0000 0000 + 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) + beq t8, 11f // if not DENSE goto 11f + bic t0, 3, t9 // clear bits <1:0> of src + ldl v0, 0(t9) // get the longword + br zero, 12f +11: + ldl v0, 0(t0) // get the longword +12: + 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: + 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: + beq t8, 51f // if not DENSE goto 51f + bic t0, 3, t9 // clear bits <1:0> of src + ldl v0, 0(t9) // get the longword + br zero, 52f +51: + ldl v0, 0(t0) // get the longword +52: + 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) + beq t8, 81f // if not DENSE goto 81f + bic t0, 3, t9 // clear bits <1:0> of src + ldl v0, 0(t9) // get the longword + br zero, 82f +81: + ldl v0, 0(t0) // get the longword +82: + 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 + // + 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 + 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: + beq t8, 121f // if not DENSE goto 121f + bic t0, 3, t9 // clear bits <1:0> of src + ldl v0, 0(t9) // get the longword + br zero, 122f +121: + ldl v0, 0(t0) // get the longword +122: + 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> + lda t0, CIA_DENSE_MEM_SVA(zero) // 0xffff ffff ffff c860 + sll t0, 28, t0 // 0xffff fc86 0000 0000 + 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> + bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0> + lda t4, CIA_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff c800 + sll t4, 28, t4 // 0xffff fc80 0000 0000 + 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 + + +// +// Values and structures used to access configuration space. +// + +// +// Define the QVA for the CIA Configuration Cycle Type register +// +// Physical address is 87 4000 0480. The QVA specifies the offset from +// the base of the CIA CSRS (87.4000.0000) since the physical address of +// the CSRS exceeds the capacity of a QVA. +// + +#define CIA_CFG_QVA (0xba000024) +#define CIA_ERR_QVA (0xba000410) + +// +// Define the configuration routines stack frame. +// + + .struct 0 +CfgRa: .space 8 // return address +CfgA0: .space 8 // saved ConfigurationAddress +CfgA1: .space 8 // saved ConfigurationData/CycleType +CfgA2: .space 8 // saved ConfigurationCycleType +CfgFrameLength: + + +//++ +// +// 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) +// +//-- + + NESTED_ENTRY( READ_CONFIG_UCHAR, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Write the configuration cycle type (a1) into the CIA CFG register +// + + stq a0, CfgA0(sp) // save configuration space address + + ldil a0, CIA_CFG_QVA // offset of CIA CFG register + bsr ra, WRITE_CIA_REGISTER // write the cycle type + +// +// Set the flag indicating that a PCI master abort may be expected by +// the machine check handler. +// + lda t0, HalpMasterAbortExpected // get address of flag + bis zero, 1, t1 // get a non-zero flag value + DISABLE_INTERRUPTS // sequence cannot be interrupted + stl t1, 0(t0) // store the non-zero flag + mb // order the write + +// +// Perform the read from configuration space after restoring the +// configuration space address. +// + + ldq a0, CfgA0(sp) // restore configuration space address + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 0x3, t3 // capture 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> + bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // + lda t4, CIA_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c870 + sll t4, 28, t4 // 0xffff fc87 0000 0000 + bis t0, t4, t0 // superpage mode + + bis t0, IO_BYTE_LEN, t0 // or in the byte enables + + .set noreorder // cannot reorder these instructions + + ldl v0, (t0) // 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 + +// +// If this is not a pass 1 CIA then skip the work-around code. +// + + lda t1, HalpCiaRevision // get address of CIA revision + ldl t1, 0(t1) // load CIA revision + bne t1, 10f // if ne, not pass 1 + +// +// CIA Pass 1 will not machine check if no device exists. Instead we must +// check the CIA error register that indicates a master abort occurred. +// + + bis v0, zero, t10 // save v0, special calling std + + ldil a0, CIA_ERR_QVA // offset of CIA_ERR register + bsr ra, READ_CIA_REGISTER // read error register + + srl v0, 31, t0 // get error valid bit + bis t10, zero, v0 // restore read value + blbc t0, 10f // if lbc, no error use read data + + ldil a0, CIA_ERR_QVA // offset of CIA_ERR register + ldil a1, -1 // clear all bits mask + bsr ra, WRITE_CIA_REGISTER // clear pending errors + + ldil v0, -1 // show no device present + extbl v0, 0, v0 // return 0xff + +// +// Set the flag indicating that a PCI master abort is not expected. +// + +10: + lda t0, HalpMasterAbortExpected // get address of flag + stl zero, 0(t0) // clear flag + ENABLE_INTERRUPTS // re-enable interrupts + +// +// Restore the frame and return. +// + + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + 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 to write. +// +// 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. +// +//-- + + NESTED_ENTRY( WRITE_CONFIG_UCHAR, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Write the configuration cycle type to the CIA CFG register +// + + stq a0, CfgA0(sp) // save configuration space address + stq a1, CfgA1(sp) // save configuration data + + bis a2, a2, a1 // put the cycle type in a1 + ldil a0, CIA_CFG_QVA // offset of CIA CFG register + bsr ra, WRITE_CIA_REGISTER // write cycle type to CFG + +// +// Perform the read from configuration space after restoring the +// configuration space address and data. +// + + ldq a0, CfgA0(sp) // restore configuration space address + ldq a1, CfgA1(sp) // restore configuration data + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 0x3, t3 // capture 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> + bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct + sll a0, IO_BIT_SHIFT, t0 // + lda t4, CIA_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c870 + sll t4, 28, t4 // 0xffff fc87 0000 0000 + bis t0, t4, t0 // superpage mode + + bis t0, IO_BYTE_LEN, t0 // or in the byte length indicator + + insbl a1, t3, t4 // put byte in the appropriate lane + stl t4, (t0) // write the configuration byte + mb // synchronize + +10: // + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + 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 quadword 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) +//-- + + NESTED_ENTRY( READ_CONFIG_USHORT, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Write the configuration cycle type (in a1) into the CIA CFG register +// + + stq a0, CfgA0(sp) // save configuration space address + + ldil a0, CIA_CFG_QVA // offset of CFG register + bsr ra, WRITE_CIA_REGISTER // write cycle type to CFG register + +// +// Set the flag indicating that a PCI master abort may be expected by +// the machine check handler. +// + lda t0, HalpMasterAbortExpected // get address of flag + bis zero, 1, t1 // get a non-zero flag value + DISABLE_INTERRUPTS // sequence cannot be interrupted + stl t1, 0(t0) // store the non-zero flag + mb // order the write + +// +// Perform the read from configuration space after restoring the +// configuration space address. +// + + ldq a0, CfgA0(sp) // restore configuration space address + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 0x3, t3 // capture word offset + 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, CIA_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c870 + sll t4, 28, t4 // 0xffff fc87 0000 0000 + bis t0, t4, t0 // superpage mode + + bis t0, IO_WORD_LEN, t0 // or in the byte enables + + .set noreorder // cannot reorder these instructions + + ldl v0, (t0) // 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 + +// +// If this is not a pass 1 CIA then skip the work-around code. +// + + lda t1, HalpCiaRevision // get address of CIA revision + ldl t1, 0(t1) // load CIA revision + bne t1, 10f // if ne, not pass 1 + +// +// CIA Pass 1 will not machine check if no device exists. Instead we must check +// the CIA error register that indicates a master abort occurred. +// + + bis v0, zero, t10 // save v0, special calling std + + ldil a0, CIA_ERR_QVA // offset of CIA_ERR register + bsr ra, READ_CIA_REGISTER // read error register + + srl v0, 31, t0 // get error valid bit + bis t10, zero, v0 // restore read value + blbc t0, 10f // if lbc, no error use read data + + ldil a0, CIA_ERR_QVA // offset of CIA_ERR register + ldil a1, -1 // clear all bits mask + bsr ra, WRITE_CIA_REGISTER // clear pending errors + + ldil v0, -1 // show no device present + extwl v0, 0, v0 // return 0xffff + +// +// Set the flag indicating that a PCI master abort is not expected. +// + +10: + lda t0, HalpMasterAbortExpected // get address of flag + stl zero, 0(t0) // clear flag + ENABLE_INTERRUPTS // re-enable interrupts + +// +// Restore the frame and return. +// + + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + ret zero, (ra) // return + + .end READ_CONFIG_USHORT + +//++ +// +// VOID +// WRITE_CONFIG_USHORT( +// ULONG ConfigurationAddress, +// USHORT ConfigurationData, +// ULONG ConfigurationCycleType +// ) +// +// Routine Description: +// +// Write a short to PCI configuration space. +// +// Arguments: +// +// ConfigurationAddress(a0) - Supplies the QVA to write. +// +// 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. +// +//-- + + NESTED_ENTRY( WRITE_CONFIG_USHORT, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Write the configuration cycle type (a2) into the CFG register +// + + stq a0, CfgA0(sp) // save configuration space address + stq a1, CfgA1(sp) // save configuration data + + bis a2, a2, a1 // put the cycle type in a1 + ldil a0, CIA_CFG_QVA // offset of CFG register + bsr ra, WRITE_CIA_REGISTER // write config type to CFG + +// +// Perform the write to configuration space after restoring the +// configuration space address and data. +// + + ldq a0, CfgA0(sp) // restore configuration space address + ldq a1, CfgA1(sp) // restore configuration data + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 0x3, t3 // capture word offset + 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, CIA_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c870 + sll t4, 28, t4 // 0xffff fc87 0000 0000 + bis t0, t4, t0 // superpage mode + + bis t0, IO_WORD_LEN, t0 // or in the byte enables + + inswl a1, t3, t4 // put data to appropriate lane + stl t4, (t0) // read the longword + mb // synchronize +10: // + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + 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 quadword 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) +//-- + + NESTED_ENTRY( READ_CONFIG_ULONG, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Write the configuration cycle type (a1) to the CIA CFG register +// + + stq a0, CfgA0(sp) // save configuration space address + + ldil a0, CIA_CFG_QVA // offset of CIA CFG register + bsr ra, WRITE_CIA_REGISTER // write cycle type to CFG + +// +// Set the flag indicating that a PCI master abort may be expected by +// the machine check handler. +// + lda t0, HalpMasterAbortExpected // get address of flag + bis zero, 1, t1 // get a non-zero flag value + DISABLE_INTERRUPTS // sequence cannot be interrupted + stl t1, 0(t0) // store the non-zero flag + mb // order the write + +// +// Perform the read from configuration space after restoring the +// configuration space address. +// + + ldq a0, CfgA0(sp) // restore configuration space address + + 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, CIA_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c870 + sll t4, 28, t4 // 0xffff fc87 0000 0000 + or t0, t4, t0 // superpage mode + + or t0, IO_LONG_LEN, t0 // or in the byte enables + + .set noreorder // cannot reorder these instructions + + ldl v0, (t0) // read the longword + mb // stall the pipe waiting for mchk + mb // + + .set reorder // reordering can begin again + +// +// If this is not a pass 1 CIA then skip the work-around code. +// + + lda t1, HalpCiaRevision // get address of CIA revision + ldl t1, 0(t1) // load CIA revision + bne t1, 10f // if ne, not pass 1 + +// +// CIA Pass 1 will not machine check if no device exists. Instead we must check +// the CIA error register that indicates a master abort occurred. +// + + bis v0, zero, t10 // save v0, special calling std + + ldil a0, CIA_ERR_QVA // offset of CIA_ERR register + bsr ra, READ_CIA_REGISTER // read error register + + srl v0, 31, t0 // get error valid bit + bis t10, zero, v0 // restore read value + blbc t0, 10f // if lbc, no error use read data + + ldil a0, CIA_ERR_QVA // offset of CIA_ERR register + ldil a1, -1 // clear all bits mask + bsr ra, WRITE_CIA_REGISTER // clear pending errors + + ldil v0, -1 // show no device present + +// +// Set the flag indicating that a PCI master abort is not expected. +// + +10: + lda t0, HalpMasterAbortExpected // get address of flag + stl zero, 0(t0) // clear flag + ENABLE_INTERRUPTS // re-enable interrupts + +// +// Restore the frame and return. +// + + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + 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 to write. +// +// 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. +// +//-- + + NESTED_ENTRY( WRITE_CONFIG_ULONG, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Write the configuration cycle type to the CIA CFG register +// + + stq a0, CfgA0(sp) // save configuration space address + stq a1, CfgA1(sp) // save configuration data + + ldil a0, CIA_CFG_QVA // offset of CIA CFG register + bis a2, a2, a1 // cycle type in a1 + bsr ra, WRITE_CIA_REGISTER // write cycle type to CFG + +// +// Perform the read from configuration space after restoring the +// configuration space address and data. +// + + ldq a0, CfgA0(sp) // restore configuration space address + ldq a1, CfgA1(sp) // restore configuration data + + 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, CIA_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c870 + sll t4, 28, t4 // 0xffff fc87 0000 0000 + bis t0, t4, t0 // superpage mode + + bis t0, IO_LONG_LEN, t0 // or in the byte enables + + stl a1, (t0) // write the longword + mb // synchronize +10: // + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + ret zero, (ra) // return + + .end WRITE_CONFIG_ULONG + + +//++ +// +// ULONG +// INTERRUPT_ACKNOWLEDGE( +// VOID +// ) +// +// Routine Description: +// +// Perform an interrupt acknowledge cycle on the PCI bus. +// +// Arguments: +// +// None. +// +// Return Value: +// +// (v0) Returns the vector returned by the interrupt acknowledge +// read. +// +//-- + + LEAF_ENTRY( INTERRUPT_ACKNOWLEDGE ) + + lda t0, CIA_PCI_INTACK_SVA(zero) // 0xffff ffff ffff c872 + sll t0, 28, t0 // 0xffff fc87 2000 0000 + + ldl v0, 0(t0) // perform intack, get vector + + ret zero, (ra) // return + + .end INTERRUPT_ACKNOWLEDGE + + +//++ +// +// VOID +// CIA_INVALIDATE_TLB( +// VOID +// ) +// +// Routine Description: +// +// Invalidate the TLB for the CIA scatter/gather. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + +//jnfix - big warnings - this is a special work-around for CIA invalidate bug +//jnfix - the 3rd DMA window is set up so that by convention with this code +//jnfix - offset 0x10 within the firware PAL is overwritten + +#define CIA_TBIA_SVA -0x378a // negative of 0xc876 +#define CIA_DIAG_SVA -0x3794 // negative of 0xc86c + + LEAF_ENTRY( CIA_INVALIDATE_TLB ) + + ldil t0, 0x100 // get stall count + + lda t1, CIA_TBIA_SVA(zero) // 0xffff ffff ffff c876 + sll t1, 28, t1 // 0xffff fc87 6000 0000 + lda t1, 0x100(t1) // 0xffff fc87 6000 0100 + + lda t2, CIA_DIAG_SVA(zero) // 0xffff ffff ffff c86c + sll t2, 28, t2 // 0xffff fc86 c000 0000 + lda t2, 0x10(t2) // 0xffff fc86 c000 0010 + + lda t3, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858 + sll t3, 28, t3 // 0xffff fc85 8000 0000 + lda t4, 0x70(zero) // get port 0x70 + sll t4, 5, t4 // shift into position + bis t3, t4, t3 // merge in port address + + ldil t4, 0x3 // get tlb invalidate value + + DISABLE_INTERRUPTS // sequence cannot be interrupted + +10: + subq t0, 1, t0 // decrement stall count + bgt t0, 20f // if gt, continue stall + + mb // clear write buffer + + stl zero, 0(t3) // do i/o write + wmb // issue wmb + + stl zero, 0(t2) // issue diagnostic write + wmb // issue wmb + + stl t4, 0(t1) // issue invalidate + mb // flush write buffer + +20: + bgt t0, 10b // continue stall loop + + ENABLE_INTERRUPTS // re-enable interrupts + + ret zero, (ra) // return + + .end CIA_INVALIDATE_TLB + diff --git a/private/ntos/nthals/halalpha/ciamapio.c b/private/ntos/nthals/halalpha/ciamapio.c new file mode 100644 index 000000000..6174c7ba0 --- /dev/null +++ b/private/ntos/nthals/halalpha/ciamapio.c @@ -0,0 +1,154 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + ciamapio.c + +Abstract: + + This module contains the functions to map HAL-accessed I/O addresses + on CIA-based systems. + +Author: + + Joe Notarangelo 30-Jun-1994 + Steve Brooks 30-Jun-1994 + +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 a Alcor 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( CIA_PCI_SPARSE_IO_PHYSICAL ); + + HalpEisaControlBase = PciIoSpaceBase; + HalpEisaIntAckBase = HAL_MAKE_QVA( CIA_PCI_INTACK_PHYSICAL ); + + // + // 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; + + } + + // + // Return the QVAs for read and write access. + // + + PortQva = (ULONG)HAL_MAKE_QVA(CIA_PCI_SPARSE_IO_PHYSICAL) + ComPortAddress; + + *ReadQva = PortQva; + *WriteQva = PortQva; + + return ComPortAddress; + +} diff --git a/private/ntos/nthals/halalpha/cmos8k.c b/private/ntos/nthals/halalpha/cmos8k.c new file mode 100644 index 000000000..6de80feb1 --- /dev/null +++ b/private/ntos/nthals/halalpha/cmos8k.c @@ -0,0 +1,246 @@ +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + xxnvram.c + +Abstract: + + This module implements the device-specific routines necessary to + Read and Write the Non Volatile RAM containing the system environment + variables. The routines implemented here are: + + HalpReadNVRamBuffer() - copy data from NVRAM into memory + HalpWriteNVRamBuffer() - write memory data to NVRAM + HalpCopyNVRamBuffer() - move data within the NVRAM + +Author: + + Steve Brooks 5-Oct 93 + + +Revision History: + + +--*/ + + +#include "halp.h" +#include "cmos8k.h" + +#include "arccodes.h" + +// +// Local function prototypes. +// + +ARC_STATUS +HalpReadNVRamBuffer ( + OUT PCHAR DataPtr, + IN PCHAR NvRamPtr, + IN ULONG Length + ); + +ARC_STATUS +HalpWriteNVRamBuffer ( + IN PCHAR NvRamPtr, + IN PCHAR DataPtr, + IN ULONG Length + ); + +ARC_STATUS +HalpCopyNVRamBuffer ( + IN PCHAR NvDestPtr, + IN PCHAR NvSrcPtr, + IN ULONG Length + ); + +#ifdef AXP_FIRMWARE + +#pragma alloc_text(DISTEXT, HalpReadNVRamBuffer ) +#pragma alloc_text(DISTEXT, HalpWriteNVRamBuffer ) +#pragma alloc_text(DISTEXT, HalpCopyNVRamBuffer ) + +#endif + + +// +// +// +ARC_STATUS HalpReadNVRamBuffer ( + OUT PCHAR DataPtr, + IN PCHAR NvRamPtr, + IN ULONG Length ) + +/*++ + +Routine Description: + + This routine Reads data from the NVRam into main memory + +Arguments: + + DataPtr - Pointer to memory location to receive data + NvRamPtr - Pointer (qva) to NVRam location to read data from + Length - Number of bytes of data to transfer + +Return Value: + + ESUCCESS if the operation succeeds. + +--*/ +{ + ULONG PageSelect, ByteSelect; + + PageSelect = (NvRamPtr - (PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT; + ByteSelect = (NvRamPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK; + + WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect); + while ( Length -- ) + { + *DataPtr++ = READ_CONFIG_RAM_DATA(NvRamPtr); + NvRamPtr ++; + + ByteSelect = (ByteSelect + 1) & CONFIG_RAM_BYTE_MASK; + if (ByteSelect == 0) + { + PageSelect++; + WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect); + } + } + + return(ESUCCESS); +} + +// +// +// +ARC_STATUS HalpWriteNVRamBuffer ( + IN PCHAR NvRamPtr, + IN PCHAR DataPtr, + IN ULONG Length ) + +/*++ + +Routine Description: + + This routine Writes data from memory into the NVRam + +Arguments: + + NvRamPtr - Pointer (qva) to NVRam location to write data into + DataPtr - Pointer to memory location of data to be written + Length - Number of bytes of data to transfer + +Return Value: + + ESUCCESS if the operation succeeds. + +--*/ +{ + ULONG PageSelect, ByteSelect; + + PageSelect = (NvRamPtr - (PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT; + ByteSelect = (NvRamPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK; + + WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect); + while ( Length -- ) + { + WRITE_CONFIG_RAM_DATA(NvRamPtr, *DataPtr); + NvRamPtr ++; + DataPtr ++; + + ByteSelect = (ByteSelect + 1) & CONFIG_RAM_BYTE_MASK; + if (ByteSelect == 0) + { + PageSelect++; + WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect); + } + } + + return(ESUCCESS); +} + +// +// +// +ARC_STATUS HalpCopyNVRamBuffer ( + IN PCHAR NvDestPtr, + IN PCHAR NvSrcPtr, + IN ULONG Length ) +/*++ + +Routine Description: + + This routine copies data between two locations within the NVRam. It is + the callers responsibility to assure that the destination region does not + overlap the src region i.e. if the regions overlap, NvSrcPtr > NvDestPtr. + +Arguments: + + NvDestPtr - Pointer (qva) to NVRam location to write data into + NvSrcPtr - Pointer (qva) to NVRam location of data to copy + Length - Number of bytes of data to transfer + +Return Value: + + ESUCCESS if the operation succeeds. + +--*/ + +{ + ULONG PageSelect0, ByteSelect0; // Src Pointer Page & offset + ULONG PageSelect1, ByteSelect1; // Dest Pointer Page & offset + + + PageSelect0 = (NvSrcPtr - (PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT; + ByteSelect0 = (NvSrcPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK; + + PageSelect1 = (NvDestPtr-(PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT; + ByteSelect1 = (NvDestPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK; + + WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect0); + while ( Length -- ) + { + UCHAR AChar; + + // + // Check the Page select for the src pointer, and write the + // select register if necessary: + // + if (ByteSelect0 == 0) + { + PageSelect0++; + } + if ( PageSelect0 != PageSelect1 ) + { + WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect0); + } + + AChar = READ_CONFIG_RAM_DATA(NvSrcPtr); + ByteSelect0 = (ByteSelect0 + 1) & CONFIG_RAM_BYTE_MASK; + + // + // Check the page select for the dest pointer, and write + // the select register if necessary: + // + if (ByteSelect1 == 0) + { + PageSelect1++; + } + if ( PageSelect1 != PageSelect0 ) + { + WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect1); + } + + WRITE_CONFIG_RAM_DATA(NvDestPtr, AChar); + ByteSelect1 = (ByteSelect1 + 1) & CONFIG_RAM_BYTE_MASK; + + NvSrcPtr ++; + NvDestPtr ++; + } + + return(ESUCCESS); +} diff --git a/private/ntos/nthals/halalpha/cmos8k.h b/private/ntos/nthals/halalpha/cmos8k.h new file mode 100644 index 000000000..192730a32 --- /dev/null +++ b/private/ntos/nthals/halalpha/cmos8k.h @@ -0,0 +1,32 @@ +// +// Non-volatile ram layout. +// + +// +// The value of HalpCMOSRamBase must be set at initialization +// + +#define CONFIG_RAM_PAGE_SELECT ((PUCHAR)HalpCMOSRamBase + 0x0400) +#define CONFIG_RAM_PAGE_COUNT 32 +#define CONFIG_RAM_PAGE_SIZE 256 +#define CONFIG_RAM_PAGE_MASK ((CONFIG_RAM_PAGE_COUNT - 1) << 8) +#define CONFIG_RAM_PAGE_SHIFT 8 +#define CONFIG_RAM_BYTE_MASK (CONFIG_RAM_PAGE_SIZE - 1) + + +// To address any byte of the CMOS 8K configuration RAM, the PAGE select +// address bits from from I/O register at CONFIG_RAM_PAGE_SELECT are +// OR'd with the lower address bits. Use the following macro to write +// the page select register: + +#define WRITE_CONFIG_RAM_PAGE_SELECT(page) \ + WRITE_PORT_UCHAR((PUCHAR)CONFIG_RAM_PAGE_SELECT, \ + (UCHAR)(page & (CONFIG_RAM_PAGE_COUNT - 1))) + +#define WRITE_CONFIG_RAM_DATA(boffset,data) \ + WRITE_PORT_UCHAR((PUCHAR)((ULONG)(HalpCMOSRamBase) | \ + ((ULONG)boffset & CONFIG_RAM_BYTE_MASK)), (data & 0xff)) + +#define READ_CONFIG_RAM_DATA(boffset) \ + READ_PORT_UCHAR((PUCHAR)((ULONG)(HalpCMOSRamBase) | \ + ((ULONG)boffset & CONFIG_RAM_BYTE_MASK))) diff --git a/private/ntos/nthals/halalpha/devintr.s b/private/ntos/nthals/halalpha/devintr.s new file mode 100644 index 000000000..63c17df5a --- /dev/null +++ b/private/ntos/nthals/halalpha/devintr.s @@ -0,0 +1,71 @@ +// TITLE("First Level Device Interrupt Handlers") +//++ +// +// Copyright (c) 1994 Digital Equipment Corporation +// +// Module Name: +// +// devintr.s +// +// Abstract: +// +// This module implements first level device interrupt handlers for +// systems that need to capture the trap frame for interrupt handling. +// +// Author: +// +// Joe Notarangelo 19-Sep-1994 +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +//-- + +#include "halalpha.h" + + SBTTL("Device Interrupt") +//++ +// +// VOID +// HalpDeviceInterrupt( +// IN PKINTERRUPT Interrupt, +// IN PVOID ServiceContext +// ) +// +// Routine Description: +// +// This function is executed as the result of a device interrupt. +// The function is responsible for capturing the trap frame and calling +// the system-specific device interrupt dispatcher. +// +// N.B. This function exists only to capture the trap frame and forward +// the interrupt to HalpDeviceDispatch. +// +// Arguments: +// +// Interrupt (a0) - Supplies a pointer to the interrupt object. +// +// ServiceContext (a1) - Supplies a pointer to the service context for +// Sable interrupts. +// +// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for +// the interrupt. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpDeviceInterrupt) + + bis fp, zero, a2 // capture trap frame as argument + br zero, HalpDeviceDispatch // dispatch the interrupt + + ret zero, (ra) // will never get here + + .end HalpDeviceInterrupt + diff --git a/private/ntos/nthals/halalpha/ebsgdma.c b/private/ntos/nthals/halalpha/ebsgdma.c new file mode 100644 index 000000000..e50fe05bb --- /dev/null +++ b/private/ntos/nthals/halalpha/ebsgdma.c @@ -0,0 +1,2307 @@ +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + ebsgdma.c + +Abstract: + + This module contains the hardware dependent routines to support + Io Adapters, Map Registers, and Common buffers for Scatter/Gather + Eisa/Isa bus Alpha AXP systems. The systems supported must include + support for 2 scatter/gather windows. Originally, this module will + support APECS- and LCA-based systems. + +Author: + + Joe Notarangelo 11-Oct-1993 + +Environment: + + Kernel mode + +Revision History: + + Dick Bissen (DEC) 01-Nov-1993 + Forced scatter/gather tables to be aligned with table size + + Joe Notarangelo 24-Nov-1993 + Do not program DMA controllers for ISA masters in IoMapTransfer and + IoFlushAdapterBuffers. Previous code did so if the device was an + Isa device without regard to whether or not it was a master device. + + Joe Notarangelo 02-Feb-1994 + Various bug fixes. Don't adjust mapRegister in IoMapTransfer and + IoFlushAdapterBuffers. Fix alignment adjustment code for Isa + machines. Initialize map registers to zero. Initialize bitmap + for map allocations by calling RtlClearAllBits. Add debugging + prints to fit new module haldebug.c + +--*/ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" + + +// +// There are 2 map register adapters that are created to control access +// to each of the 2 mapping windows that exist for APECS and LCA. +// +// The first adapter (IsaMapAdapter) controls access to the first mapping +// windows which maps 8MB : 16MB-1 in bus space. The window is chosen +// to be as large as possible and must be below 16MB to support ISA +// bus masters and the standard EISA/ISA dma controllers. +// +// The second adapter (MasterMapAdapter) controls access to the second +// mapping windows which maps a large region in bus space that may +// begin above 16MB. This window is used for bus masters that are not +// constrained by the ISA 24-bit limit. +// + +PMAP_REGISTER_ADAPTER HalpIsaMapAdapter = NULL; +PMAP_REGISTER_ADAPTER HalpMasterMapAdapter = NULL; + +// +// Pointer to superpage address memory for map registers. +// + +PTRANSLATION_ENTRY HalpIsaMapRegisterBase = NULL; +PTRANSLATION_ENTRY HalpMasterMapRegisterBase = NULL; + +// +// Control structures for each of the map register windows. +// + +WINDOW_CONTROL_REGISTERS HalpIsaWindowControl; +WINDOW_CONTROL_REGISTERS HalpMasterWindowControl; + + + +// +// Local function prototypes. +// + +IO_ALLOCATION_ACTION +HalpAllocationRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID MapRegisterBase, + IN PVOID Context + ); + +PMAP_REGISTER_ADAPTER +HalpAllocateMapAdapter( + IN PWINDOW_CONTROL_REGISTERS WindowRegisters, + IN HAL_ADAPTER_TYPE AdapterType, + IN PTRANSLATION_ENTRY MapRegisterBase + ); + +PADAPTER_OBJECT +HalpAllocateAdapter( + VOID + ); + +BOOLEAN +HalpAllocateMapRegisters( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG NumberOfMapRegisters, + IN BOOLEAN MapAdapterLocked + ); + +BOOLEAN +HalpCreateDmaStructures ( + PLOADER_PARAMETER_BLOCK LoaderBlock + ) + +/*++ + +Routine Description: + + This routine initializes the structures necessary for DMA operations. + Specifically, this routine allocates the physical pages to be used + to contain the scatter/gather entries for all DMA. + +Arguments: + + None. + +Return Value: + + TRUE is returned. + +--*/ + +{ + ULONG Allocated; + ULONG ByteSize; + ULONG MaxPhysicalAddress; + + // + // Initialize the window control structures for each of the 2 + // DMA windows. + // + + INITIALIZE_ISA_DMA_CONTROL( &HalpIsaWindowControl ); + INITIALIZE_MASTER_DMA_CONTROL( &HalpMasterWindowControl ); + + // + // Insure that the maximum address allocated will guarantee that the + // entirety of each allocation can be accessed via the 32-bit superpage. + // + + MaxPhysicalAddress = __1GB - 1; + + // + // Allocate the pages to contain the scatter/gather entries for the + // ISA DMA region (logical address range 8MB: 16MB-1). + // + + ByteSize = ((HalpIsaWindowControl.WindowSize / PAGE_SIZE) * + sizeof(TRANSLATION_ENTRY)) + PAGE_SIZE-1; + + // + // Memory allocation for the Isa scatter/gather table will always + // align on a 8K boundry. + // + + Allocated = HalpAllocPhysicalMemory( LoaderBlock, + MaxPhysicalAddress, + ByteSize >> PAGE_SHIFT, + FALSE ); + + ASSERT( Allocated != 0 ); + + HalpIsaMapRegisterBase = (PTRANSLATION_ENTRY)(Allocated | KSEG0_BASE); + + RtlZeroMemory( HalpIsaMapRegisterBase, + (ByteSize >> PAGE_SHIFT) << PAGE_SHIFT ); + + // + // Allocate the pages to contain the scatter/gather entries for the + // bus master DMA region. Allocation of scatter/gather tables MUST + // be aligned based on the size of the scatter/gather table (16k). + // + + ByteSize = ((HalpMasterWindowControl.WindowSize / PAGE_SIZE) * + sizeof(TRANSLATION_ENTRY)) + PAGE_SIZE-1; + + // + // Allocated on an aligned 64k boundry will ensure table alignment + // on a 16K boundry for a 16MB window size. + // + + Allocated = HalpAllocPhysicalMemory( LoaderBlock, + MaxPhysicalAddress, + ByteSize >> PAGE_SHIFT, + TRUE ); + + ASSERT( Allocated != 0 ); + + HalpMasterMapRegisterBase = (PTRANSLATION_ENTRY)(Allocated | KSEG0_BASE); + + RtlZeroMemory( HalpMasterMapRegisterBase, + (ByteSize >> PAGE_SHIFT) << PAGE_SHIFT ); + + // + // Perform any Eisa/Isa initialization. + // + + HalpEisaInitializeDma(); + + // + // Program the DMA windows to reflect the translations. + // + + INITIALIZE_DMA_WINDOW( &HalpMasterWindowControl, + (PVOID)( (ULONG)HalpMasterMapRegisterBase & + ~KSEG0_BASE ) ); + + INITIALIZE_DMA_WINDOW( &HalpIsaWindowControl, + (PVOID)( (ULONG)HalpIsaMapRegisterBase & + ~KSEG0_BASE ) ); + + return TRUE; +} + +PADAPTER_OBJECT +HalGetAdapter( + IN PDEVICE_DESCRIPTION DeviceDescription, + IN OUT PULONG NumberOfMapRegisters + ) + +/*++ + +Routine Description: + + This function returns the appropriate adapter object for the device defined + in the device description structure. Eisa/Isa bus types and all master + devices are supported for the system. + +Arguments: + + DeviceDescription - Supplies a description of the deivce. + + NumberOfMapRegisters - Returns the maximum number of map registers which + may be allocated by the device driver. + +Return Value: + + A pointer to the requested adapter object or NULL if an adapter could not + be created. + +--*/ + +{ + ULONG MaximumMapRegistersPerChannel; + PADAPTER_OBJECT adapterObject; + PBUS_HANDLER BusHandler; + PPCIPBUSDATA PciBusData; + + // + // Make sure this is the correct version. + // + + if (DeviceDescription->Version > DEVICE_DESCRIPTION_VERSION1) { + + return(NULL); + + } + + // + // If the device is not a bus master, then it must be an ISA, EISA + // or PCI device on hardware bus 0. PCI devices on hardware busses + // other than 0 cannot support slave DMA devices because the DMAC + // needed to support slave DMA is part of the ISA/EISA bridge, (which + // is located on h/w bus 0). + // + + if( DeviceDescription->Master != TRUE ){ + + // + // This device requires slave DMA h/w support. Determine which + // type of device it is. + // + + switch( DeviceDescription->InterfaceType ){ + + case Isa: + case Eisa: + + // + // The ISA/EISA bridge implements the DMA controller logic + // needed to support slave DMA. + // + + break; + + case PCIBus: + + // + // Get the bus handler for the PCI bus. + // + + BusHandler = HaliHandlerForBus( + PCIBus, + DeviceDescription->BusNumber + ); + + // + // If a bus handler does not exist, then there is a s/w bug + // somewhere. Just return failure. + // + + if( BusHandler == NULL ){ + + return NULL; + + } + + // + // Get a pointer to the PCI private bus data for this bus. + // The h/w bus number is located therein. + // + + PciBusData = (PPCIPBUSDATA)BusHandler->BusData; + + // + // The DMA controller we use to support slave DMA is located + // on the ISA/EISA bridge in h/w bus 0. If this PCI bus is + // not located on h/w bus 0, return failure. + // + + if( PciBusData->HwBusNumber != 0 ){ + + return NULL; + + } + + break; + + default: + + // + // We only support ISA, EISA and PCI slave DMA. + // + + return NULL; + + } + + } + + // + // Create an EISA adapter if this device is an ISA device + // or is not a master device. + // + + if( (DeviceDescription->Master != TRUE) || + (DeviceDescription->InterfaceType == Isa ) ){ + + // + // Allocate the Isa Map Register Adapter if it has not + // already been allocated. + // + + if( HalpIsaMapAdapter == NULL ){ + HalpIsaMapAdapter = HalpAllocateMapAdapter( + &HalpIsaWindowControl, + IsaAdapter, + HalpIsaMapRegisterBase ); + if( HalpIsaMapAdapter == NULL ){ + return NULL; + } + } + + adapterObject = HalpAllocateEisaAdapter( + DeviceDescription, + NumberOfMapRegisters ); + + if( adapterObject == NULL ){ + return NULL; + } + + adapterObject->Type = IsaAdapter; + adapterObject->MapAdapter = HalpIsaMapAdapter; + adapterObject->MapRegisterBase = NULL; + adapterObject->NumberOfMapRegisters = 0; + + } else { + + // + // Allocate the master map register adapter if it has not + // already been allocated. + // + + if( HalpMasterMapAdapter == NULL ){ + HalpMasterMapAdapter = HalpAllocateMapAdapter( + &HalpMasterWindowControl, + BusMasterAdapter, + HalpMasterMapRegisterBase ); + if( HalpMasterMapAdapter == NULL ){ + return NULL; + } + } + + // + // Allocate an adapter for this master device. + // + + adapterObject = HalpAllocateAdapter(); + + if( adapterObject == NULL ){ + return NULL; + } + + // + // Initialize the adapter object. + // + + adapterObject->Type = BusMasterAdapter; + adapterObject->MasterDevice = TRUE; + adapterObject->MapAdapter = HalpMasterMapAdapter; + adapterObject->MapRegisterBase = NULL; + adapterObject->NumberOfMapRegisters = 0; + + // + // Calculate maximum number of map registers for this adapter. + // + + if (NumberOfMapRegisters != NULL) { + + // + // Return number of map registers requested based on the maximum + // transfer length. + // + + *NumberOfMapRegisters = BYTES_TO_PAGES( + DeviceDescription->MaximumLength ) + 1; + + // + // Limit the number of map registers to no more than 1/4 of all + // of the map registers available for this DMA window. + // + + MaximumMapRegistersPerChannel = + (HalpMasterMapAdapter->WindowSize >> PAGE_SHIFT) / 4; + if( *NumberOfMapRegisters > MaximumMapRegistersPerChannel ){ + *NumberOfMapRegisters = MaximumMapRegistersPerChannel; + } + + adapterObject->MapRegistersPerChannel = *NumberOfMapRegisters; + + } else { + + adapterObject->MapRegistersPerChannel = 0; + + } + } + + return(adapterObject); +} + +PMAP_REGISTER_ADAPTER +HalpAllocateMapAdapter( + IN PWINDOW_CONTROL_REGISTERS WindowRegisters, + IN HAL_ADAPTER_TYPE AdapterType, + IN PTRANSLATION_ENTRY MapRegisterBase + ) +/*++ + +Routine Description: + + This routine allocates and initializes the structure for the bus + master map register adapter. + +Arguments: + + WindowRegisters - Supplies a pointer to the software window control + registers that describes the DMA window associated + with this map adapter. + + AdapterType - Supplies the type of the adapter. + + MapRegisterBase - Supplies the starting virtual address of the map + registers for this adapter. + +Return Value: + + Returns the pointer to the allocated and initialized map + adapter if allocation was successful, NULL otherwise. + +--*/ + +{ + ULONG NumberMapRegisters; + ULONG Size; + PMAP_REGISTER_ADAPTER mapAdapter; + + Size = sizeof(MAP_REGISTER_ADAPTER); + + NumberMapRegisters = WindowRegisters->WindowSize / PAGE_SIZE; + + // + // Add size of bitmap. Size of bitmap is the number of bytes required, + // computed by dividing map registers by 8 (>>3) and then rounding up + // to the nearest value divisible by 4. + // + + Size += sizeof(RTL_BITMAP) + (( ((NumberMapRegisters+7) >> 3) + 3) & ~3); + + // + // Allocate the map register adapter. + // + + mapAdapter = ExAllocatePool( NonPagedPool, Size ); + + if( mapAdapter == NULL ){ + return NULL; + } + + // + // Initialize the fields within the map adapter structure. + // + + mapAdapter->Type = AdapterType; + + KeInitializeSpinLock( &mapAdapter->SpinLock ); + InitializeListHead( &mapAdapter->RegisterWaitQueue ); + + mapAdapter->MapRegisterBase = MapRegisterBase; + mapAdapter->NumberOfMapRegisters = NumberMapRegisters; + mapAdapter->MapRegisterAllocation = (PRTL_BITMAP)(mapAdapter + 1); + RtlInitializeBitMap( mapAdapter->MapRegisterAllocation, + (PULONG)((PCHAR)(mapAdapter->MapRegisterAllocation) + + sizeof(RTL_BITMAP)), + NumberMapRegisters ); + RtlClearAllBits( mapAdapter->MapRegisterAllocation ); + + + mapAdapter->WindowBase = WindowRegisters->WindowBase; + mapAdapter->WindowSize = WindowRegisters->WindowSize; + + mapAdapter->WindowControl = WindowRegisters; + + return mapAdapter; +} + +NTSTATUS +HalAllocateAdapterChannel( + IN PADAPTER_OBJECT AdapterObject, + IN PWAIT_CONTEXT_BLOCK Wcb, + IN ULONG NumberOfMapRegisters, + IN PDRIVER_CONTROL ExecutionRoutine + ) +/*++ + +Routine Description: + + This routine allocates the adapter channel specified by the adapter object. + This is accomplished by placing the device object of the driver that wants + to allocate the adapter on the adapter's queue. If the queue is already + "busy", then the adapter has already been allocated, so the device object + is simply placed onto the queue and waits until the adapter becomes free. + + Once the adapter becomes free (or if it already is), then the driver's + execution routine is invoked. + + Also, a number of map registers may be allocated to the driver by specifying + a non-zero value for NumberOfMapRegisters. Then the map register must be + allocated from the master adapter. Once there are a sufficient number of + map registers available, then the execution routine is called and the + base address of the allocated map registers in the adapter is also passed + to the driver's execution routine. + +Arguments: + + AdapterObject - Pointer to the adapter control object to allocate to the + driver. + + Wcb - Supplies a wait context block for saving the allocation parameters. + The DeviceObject, CurrentIrp and DeviceContext should be initalized. + + NumberOfMapRegisters - The number of map registers that are to be allocated + from the channel, if any. + + ExecutionRoutine - The address of the driver's execution routine that is + invoked once the adapter channel (and possibly map registers) have been + allocated. + +Return Value: + + Returns STATUS_SUCESS unless too many map registers are requested. + +Notes: + + Note that this routine MUST be invoked at DISPATCH_LEVEL or above. + +--*/ + +{ + IO_ALLOCATION_ACTION Action; + BOOLEAN Busy = FALSE; + PMAP_REGISTER_ADAPTER MapAdapter; + + // + // Begin by obtaining a pointer to the map register adapter associated + // with this request. + // + + MapAdapter = AdapterObject->MapAdapter; + + DebugPrint( (HALDBG_MAPREG, + "\nHalAllocateAdapter, Adapter=%x, MapA=%x, Maps=%x\n", + AdapterObject, MapAdapter, NumberOfMapRegisters) ); + + // + // Initialize the device object's wait context block in case this device + // must wait before being able to allocate the adapter. + // + + Wcb->DeviceRoutine = ExecutionRoutine; + Wcb->NumberOfMapRegisters = NumberOfMapRegisters; + + // + // Allocate the adapter object for this particular device. If the + // adapter cannot be allocated because it has already been allocated + // to another device, then return to the caller now; otherwise, + // continue. + // + + if (!KeInsertDeviceQueue( &AdapterObject->ChannelWaitQueue, + &Wcb->WaitQueueEntry )) { + + // + // The adapter was not busy so it has been allocated. Now check + // to see whether this driver wishes to allocate any map registers. + // If so, then queue the device object to the master adapter queue + // to wait for them to become available. If the driver wants map + // registers, ensure that this adapter has enough total map registers + // to satisfy the request. + // + + AdapterObject->CurrentWcb = Wcb; + AdapterObject->NumberOfMapRegisters = Wcb->NumberOfMapRegisters; + + if (NumberOfMapRegisters != 0) { + + // + // Validate that the requested number of map registers is + // within the maximum limit. + // + + if (NumberOfMapRegisters > MapAdapter->NumberOfMapRegisters) { + AdapterObject->NumberOfMapRegisters = 0; + IoFreeAdapterChannel(AdapterObject); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + Busy = HalpAllocateMapRegisters( AdapterObject, + NumberOfMapRegisters, + FALSE ); + + } + + // + // If there were either enough map registers available or no map + // registers needed to be allocated, invoke the driver's execution + // routine now. + // + + if (Busy == FALSE) { + + Action = ExecutionRoutine( Wcb->DeviceObject, + Wcb->CurrentIrp, + AdapterObject->MapRegisterBase, + Wcb->DeviceContext + ); + + // + // If the driver wishes to keep the map registers then set the + // number allocated to zero and set the action to deallocate + // object. + // + + if (Action == DeallocateObjectKeepRegisters) { + AdapterObject->NumberOfMapRegisters = 0; + Action = DeallocateObject; + } + + // + // If the driver would like to have the adapter deallocated, + // then deallocate any map registers allocated and then release + // the adapter object. + // + + if (Action == DeallocateObject) { + IoFreeAdapterChannel( AdapterObject ); + } + + } else { + + DebugPrint( (HALDBG_MAPREG, + "No map registers available, Adapter= %x, Maps= %x\n", + AdapterObject, NumberOfMapRegisters) ); + + } + + } else { + + DebugPrint( (HALDBG_MAPREG, + "Device Queue is busy, AdapterObject = %x\n", + AdapterObject) ); + + } + + return(STATUS_SUCCESS); + +} + +BOOLEAN +HalpAllocateMapRegisters( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG NumberOfMapRegisters, + IN BOOLEAN MapAdapterLocked + ) +/*++ + +Routine Description: + + Allocate the requested number of contiguous map registers from + the Map adapter. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object for which the + map registers are to be allocated. + + NumberOfMapRegisters - Supplies the number of map registers to allocate. + + MapAdapterLocked - Supplies a boolean which indicates if the map adapter + for the AdapterObject is already locked. + +Return Value: + + The value returned indicates if the map registers are busy. + The value FALSE is returned if the map registers were allocated. + Otherwise, the Adapter is put on the register wait queue for its + associated map adapter and TRUE is returned. + +--*/ +{ + ULONG AllocationMask; + BOOLEAN Busy = FALSE; + ULONG ExtentBegin; + ULONG HintIndex; + KIRQL Irql; + ULONG MapRegisterIndex; + PMAP_REGISTER_ADAPTER mapAdapter; + + // + // Some devices do DMA prefetch. This is bad since it will cause certain + // chipsets to generate a PFN error because a map register has not been + // allocated and validated. To fix this, we'll put in a hack. We'll + // allocate one extra map register and map it to some junk page to avoid + // this nasty problem. + // + + NumberOfMapRegisters += 1; + + // + // Acquire a pointer to the map adapter that contains the map registers + // for the adapter. + // + + mapAdapter = AdapterObject->MapAdapter; + + // + // Lock the map register bit map and the adapter queue in the + // master adapter object. + // + + if( MapAdapterLocked == FALSE ){ + KeAcquireSpinLock( &mapAdapter->SpinLock, &Irql ); + } + + MapRegisterIndex = MAXULONG; + + if (IsListEmpty( &mapAdapter->RegisterWaitQueue)) { + + // + // If this is an Isa machine and the requested DMA is for an + // Isa device then we must be careful that the DMA does not cross + // a 64K boundary on the bus. + // + + if( (HalpBusType == MACHINE_TYPE_ISA) && + (mapAdapter->Type == IsaAdapter) ){ + + ASSERT( (NumberOfMapRegisters * PAGE_SIZE) <= __64K ); + + // + // This is an Isa allocation, guarantee that the allocation + // of map registers will not span a 64K boundary. We do this by + // looking for a contiguous allocation of: + // NumberOfMapRegisters * 2 - 1 + // Any allocation of this size will guarantee that: + // (a) The allocation fits before the next 64K boundary or + // (b) The allocation can be made on the next 64K boundary. + // + // N.B. - This algorithm depends on RtlFindClear* to find + // the first available extent of cleared bits. + // + + ExtentBegin = RtlFindClearBits( + mapAdapter->MapRegisterAllocation, + NumberOfMapRegisters + 7, + 0 ); + + if( ExtentBegin != -1 ){ + + // + // Compute the hint index. If ExtentBegin + NumberOfMaps + // does not cross a 64K boundary then ExtentBegin will be + // the hint index. Otherwise, align the hint to the next + // 64K boundary above ExtentBegin. + // + + AllocationMask = (__64K >> PAGE_SHIFT) - 1; + HintIndex = (ExtentBegin+AllocationMask) & ~AllocationMask; + + MapRegisterIndex = RtlFindClearBitsAndSet( + mapAdapter->MapRegisterAllocation, + NumberOfMapRegisters, + HintIndex ); + + } + + + } else { + + // + // This allocation is not subject to the Isa 64K restriction. + // + + ExtentBegin = RtlFindClearBits( + mapAdapter->MapRegisterAllocation, + NumberOfMapRegisters + 7, + 0 ); + + AllocationMask = (__64K >> PAGE_SHIFT) - 1; + + HintIndex = (ExtentBegin + AllocationMask) & ~AllocationMask; + + MapRegisterIndex = RtlFindClearBitsAndSet( + mapAdapter->MapRegisterAllocation, + NumberOfMapRegisters, + HintIndex ); + + } //endif HalpBusType == MACHINE_TYPE_ISA + + } //endif IsListEmpty + + if (MapRegisterIndex == MAXULONG) { + + // + // There were not enough free map registers. Queue this request + // on the map adapter where it will wait until some registers + // are deallocated. + // + + InsertTailList( &mapAdapter->RegisterWaitQueue, + &AdapterObject->AdapterQueue ); + Busy = TRUE; + + } + + // + // Unlock the map adapter (unless locked by the caller). + // + + if( MapAdapterLocked == FALSE ){ + KeReleaseSpinLock( &mapAdapter->SpinLock, Irql ); + } + + // + // If map registers were allocated, return the index of the first + // map register in the contiguous extent. + // + + if( Busy == FALSE ){ + AdapterObject->MapRegisterBase = + (PVOID) ((PTRANSLATION_ENTRY) mapAdapter->MapRegisterBase + + MapRegisterIndex); + } + + return Busy; + +} + +PADAPTER_OBJECT +HalpAllocateAdapter( + VOID + ) +/*++ + +Routine Description: + + This routine allocates and initializes an adapter object to represent an + adapter or a DMA controller on the system. + +Arguments: + + None. + +Return Value: + + The function value is a pointer to the allocated adapter object. + +--*/ + +{ + + PADAPTER_OBJECT AdapterObject; + OBJECT_ATTRIBUTES ObjectAttributes; + ULONG Size; + HANDLE Handle; + NTSTATUS Status; + + // + // Begin by initializing the object attributes structure to be used when + // creating the adapter object. + // + + InitializeObjectAttributes( &ObjectAttributes, + NULL, + OBJ_PERMANENT, + (HANDLE) NULL, + (PSECURITY_DESCRIPTOR) NULL + ); + + Size = sizeof( ADAPTER_OBJECT ); + + // + // Now create the adapter object. + // + + Status = ObCreateObject( KernelMode, + *((POBJECT_TYPE *)IoAdapterObjectType), + &ObjectAttributes, + KernelMode, + (PVOID) NULL, + Size, + 0, + 0, + (PVOID *)&AdapterObject ); + + // + // Reference the object. + // + + if (NT_SUCCESS(Status)) { + + Status = ObReferenceObjectByPointer( + AdapterObject, + FILE_READ_DATA | FILE_WRITE_DATA, + *IoAdapterObjectType, + KernelMode + ); + + } + + // + // If the adapter object was successfully created, then attempt to insert + // it into the the object table. + // + + if (NT_SUCCESS( Status )) { + + Status = ObInsertObject( AdapterObject, + NULL, + FILE_READ_DATA | FILE_WRITE_DATA, + 0, + (PVOID *) NULL, + &Handle ); + + if (NT_SUCCESS( Status )) { + + ZwClose(Handle); + + // + // Initialize the adapter object itself. + // + + AdapterObject->Type = IO_TYPE_ADAPTER; + AdapterObject->Size = (USHORT) Size; + + // + // Initialize the channel wait queue for this + // adapter. + // + + KeInitializeDeviceQueue( &AdapterObject->ChannelWaitQueue ); + + } else { + + // + // An error was incurred for some reason. Set the return value + // to NULL. + // + + AdapterObject = (PADAPTER_OBJECT) NULL; + } + + } else { + + AdapterObject = (PADAPTER_OBJECT) NULL; + + } + + return AdapterObject; + +} + + + +PVOID +HalAllocateCrashDumpRegisters( + IN PADAPTER_OBJECT AdapterObject, + IN PULONG NumberOfMapRegisters + ) +/*++ + +Routine Description: + + This routine is called during the crash dump disk driver's initialization + to allocate a number map registers permanently. + +Arguments: + + AdapterObject - Pointer to the adapter control object to allocate to the + driver. + NumberOfMapRegisters - Number of map registers requested and updated to + show number actually allocated. + +Return Value: + + Returns a pointer to the allocated map register base. + +--*/ + +{ + ULONG AllocationMask; + PMAP_REGISTER_ADAPTER MapAdapter; + ULONG HintIndex; + ULONG MapRegisterIndex; + ULONG ExtentBegin; + + // + // Begin by obtaining a pointer to the map adapter associated with this + // request. + // + + MapAdapter = AdapterObject->MapAdapter; + + // + // Ensure that this adapter has enough total map registers to satisfy + // the request. + // + + if (*NumberOfMapRegisters > MapAdapter->NumberOfMapRegisters) { + AdapterObject->NumberOfMapRegisters = 0; + return NULL; + } + + MapRegisterIndex = (ULONG)-1; + + // + // If this is an Isa machine and the requested DMA is for an + // Isa device then we must be areful that the DMA does not cross + // a 64K boundary on the bus. + // + + if( (HalpBusType == MACHINE_TYPE_ISA) && + (MapAdapter->Type == IsaAdapter) ){ + + // + // This is an Isa allocation, guarantee that the allocation + // of map registers will not span a 64K boundary. We do this by + // looking for a consiguous allocation of: + // NumberOfMapRegisters * 2 - 1 + // Any allocation of this size will guarantee that: + // (a) The allocation fitst before the next 64K boundary or + // (b) The allocation can be made on the next 64K boundary. + // + // N.B. - This algorithm depends on RtlFindClear* to find + // the first available extent of cleared bits. + // + + ExtentBegin = RtlFindClearBits( + MapAdapter->MapRegisterAllocation, + (*NumberOfMapRegisters * 2) - 1, + 0 ); + if( ExtentBegin != -1){ + + // + // Compute the hint index. If ExtentBegin + NumberOfMaps + // does not cross a 64K boundary then ExtentBegin will be + // the hint index. Otherwise, align the hint to the next + // 64K boundary above ExtentBegin. + // + + AllocationMask = (__64K >> PAGE_SHIFT) - 1; + HintIndex = ExtentBegin; + + if( (ExtentBegin + *NumberOfMapRegisters) > + ((ExtentBegin + AllocationMask) & ~AllocationMask) ){ + + // + // Allocation would have spanned a 64K boundary. + // Round up to next 64K boundary. + // + + HintIndex = (ExtentBegin+AllocationMask) & ~AllocationMask; + + } + + MapRegisterIndex = RtlFindClearBitsAndSet( + MapAdapter->MapRegisterAllocation, + *NumberOfMapRegisters, + HintIndex ); + + } + + } else { + + // + // This allocation is not subject to the Isa 64K restriction. + // + + HintIndex = 0; + + MapRegisterIndex = RtlFindClearBitsAndSet( + MapAdapter->MapRegisterAllocation, + *NumberOfMapRegisters, + 0 ); + + } + + if (MapRegisterIndex == (ULONG)-1) { + + // + // Not enough free map registers were found, so they were busy + // being used by the system when it crashed. Force the appropriate + // number to be "allocated" at the base by simply overjamming the + // bits and return the base map register as the start. + // + + RtlSetBits( + MapAdapter->MapRegisterAllocation, + HintIndex, + *NumberOfMapRegisters + ); + MapRegisterIndex = HintIndex; + + } + + // + // Calculate the map register base from the allocated map + // register and base of the master adapter object. + // + + AdapterObject->MapRegisterBase = (PVOID) ((PTRANSLATION_ENTRY) MapAdapter->MapRegisterBase + MapRegisterIndex); + + return AdapterObject->MapRegisterBase; +} + + + +VOID +IoFreeMapRegisters( + PADAPTER_OBJECT AdapterObject, + PVOID MapRegisterBase, + ULONG NumberOfMapRegisters + ) +/*++ + +Routine Description: + + This routine deallocates the map registers for the adapter. If there are + any queued adapter waiting for an attempt is made to allocate the next + entry. + +Arguments: + + AdapterObject - The adapter object to where the map register should be + returned. + + MapRegisterBase - The map register base of the registers to be deallocated. + + NumberOfMapRegisters - The number of registers to be deallocated. + +Return Value: + + None + +--+*/ + +{ + IO_ALLOCATION_ACTION Action; + BOOLEAN Busy = FALSE; + KIRQL Irql; + LONG MapRegisterIndex; + PLIST_ENTRY Packet; + PWAIT_CONTEXT_BLOCK Wcb; + PMAP_REGISTER_ADAPTER mapAdapter; + + + // + // Deallocate the extra map register that we originally allocated to fix + // the DMA prefetch problem. + // + + NumberOfMapRegisters += 1; + + // + // Begin by getting the address of the map register adapter. + // + + mapAdapter = AdapterObject->MapAdapter; + + DebugPrint( (HALDBG_MAPREG, + "IoFreeMapRegisters, Adapter=%x, MapA=%x, Maps=%x\n", + AdapterObject, mapAdapter, NumberOfMapRegisters) ); + + MapRegisterIndex = (PTRANSLATION_ENTRY) MapRegisterBase - + (PTRANSLATION_ENTRY) mapAdapter->MapRegisterBase; + + // + // Acquire the map adapter spinlock which locks the adapter queue and the + // bit map for the map registers. + // + + KeAcquireSpinLock(&mapAdapter->SpinLock, &Irql); + + // + // Return the registers to the bit map. + // + + RtlClearBits( mapAdapter->MapRegisterAllocation, + MapRegisterIndex, + NumberOfMapRegisters + ); + + // + // Process any requests waiting for map registers in the adapter queue. + // Requests are processed until a request cannot be satisfied or until + // there are no more requests in the queue. + // + + while(TRUE) { + + if ( IsListEmpty(&mapAdapter->RegisterWaitQueue) ){ + break; + } + + Packet = RemoveHeadList( &mapAdapter->RegisterWaitQueue ); + AdapterObject = CONTAINING_RECORD( Packet, + ADAPTER_OBJECT, + AdapterQueue + ); + DebugPrint( (HALDBG_MAPREG, + "IoFreeMaps, waking Adapter=%x\n", AdapterObject) ); + + Wcb = AdapterObject->CurrentWcb; + + // + // Attempt to allocate the map registers. + // + + Busy = HalpAllocateMapRegisters( AdapterObject, + Wcb->NumberOfMapRegisters, + TRUE ); + + if( Busy == TRUE ){ + DebugPrint( (HALDBG_MAPREG, + "IoFreeMaps, Not enough maps, Adapter=%x, Maps=%x\n", + AdapterObject, Wcb->NumberOfMapRegisters) ); + break; + } + + KeReleaseSpinLock( &mapAdapter->SpinLock, Irql ); + + // + // Invoke the driver's execution routine now. + // + + Action = Wcb->DeviceRoutine( Wcb->DeviceObject, + Wcb->CurrentIrp, + AdapterObject->MapRegisterBase, + Wcb->DeviceContext ); + + // + // If the driver wishes to keep the map registers then set the number + // allocated to zero and set the action to deallocate object. + // + + if (Action == DeallocateObjectKeepRegisters) { + AdapterObject->NumberOfMapRegisters = 0; + Action = DeallocateObject; + } + + // + // If the driver would like to have the adapter deallocated, + // then deallocate any map registers allocated and then release + // the adapter object. + // + + if (Action == DeallocateObject) { + + // + // The map registers are deallocated here rather than in + // IoFreeAdapterChannel. This limits the number of times + // this routine can be called recursively possibly overflowing + // the stack. The worst case occurs if there is a pending + // request for the adapter that uses map registers and whos + // excution routine decallocates the adapter. In that case if + // there are no requests in the map adapter queue, then + // IoFreeMapRegisters will get called again. + // + + if (AdapterObject->NumberOfMapRegisters != 0) { + + // + // Deallocate the map registers and clear the count so that + // IoFreeAdapterChannel will not deallocate them again. + // + + KeAcquireSpinLock( &mapAdapter->SpinLock, &Irql ); + + MapRegisterIndex = + (PTRANSLATION_ENTRY)AdapterObject->MapRegisterBase - + (PTRANSLATION_ENTRY)mapAdapter->MapRegisterBase; + + RtlClearBits( mapAdapter->MapRegisterAllocation, + MapRegisterIndex, + AdapterObject->NumberOfMapRegisters + ); + + AdapterObject->NumberOfMapRegisters = 0; + + KeReleaseSpinLock( &mapAdapter->SpinLock, Irql ); + + } + + IoFreeAdapterChannel( AdapterObject ); + } + + KeAcquireSpinLock( &mapAdapter->SpinLock, &Irql ); + + } + + KeReleaseSpinLock( &mapAdapter->SpinLock, Irql ); +} + +VOID +IoFreeAdapterChannel( + IN PADAPTER_OBJECT AdapterObject + ) + +/*++ + +Routine Description: + + This routine is invoked to deallocate the specified adapter object. + Any map registers that were allocated are also automatically deallocated. + No checks are made to ensure that the adapter is really allocated to + a device object. However, if it is not, then kernel will bugcheck. + + If another device is waiting in the queue to allocate the adapter object + it will be pulled from the queue and its execution routine will be + invoked. + +Arguments: + + AdapterObject - Pointer to the adapter object to be deallocated. + +Return Value: + + None. + +--*/ + +{ + PKDEVICE_QUEUE_ENTRY Packet; + PMAP_REGISTER_ADAPTER mapAdapter; + BOOLEAN Busy = FALSE; + IO_ALLOCATION_ACTION Action; + PWAIT_CONTEXT_BLOCK Wcb; + KIRQL Irql; + LONG MapRegisterNumber; + + // + // Begin by getting the address of the map register adapter. + // + + mapAdapter = AdapterObject->MapAdapter; + + DebugPrint( (HALDBG_MAPREG, + "IoFreeChannel, Adapter=%x, MapAdapter=%x\n", + AdapterObject, mapAdapter) ); + + // + // Pull requests of the adapter's device wait queue as long as the + // adapter is free and there are sufficient map registers available. + // + + while( TRUE ){ + + // + // Begin by checking to see whether there are any map registers that + // need to be deallocated. If so, then deallocate them now. + // + + if (AdapterObject->NumberOfMapRegisters != 0) { + IoFreeMapRegisters( AdapterObject, + AdapterObject->MapRegisterBase, + AdapterObject->NumberOfMapRegisters + ); + } + + // + // Simply remove the next entry from the adapter's device wait queue. + // If one was successfully removed, allocate any map registers that it + // requires and invoke its execution routine. + // + + Packet = KeRemoveDeviceQueue( &AdapterObject->ChannelWaitQueue ); + if (Packet == NULL) { + + // + // There are no more requests break out of the loop. + // + + break; + } + + Wcb = CONTAINING_RECORD( Packet, + WAIT_CONTEXT_BLOCK, + WaitQueueEntry ); + + AdapterObject->CurrentWcb = Wcb; + AdapterObject->NumberOfMapRegisters = Wcb->NumberOfMapRegisters; + + DebugPrint( (HALDBG_MAPREG, + "IoFreeChannel, waking for Maps=%x\n", + Wcb->NumberOfMapRegisters) ); + + // + // Check to see whether this driver wishes to allocate any map + // registers. If so, then queue the device object to the master + // adapter queue to wait for them to become available. If the driver + // wants map registers, ensure that this adapter has enough total + // map registers to satisfy the request. + // + + if (Wcb->NumberOfMapRegisters != 0) { + + Busy = HalpAllocateMapRegisters( AdapterObject, + Wcb->NumberOfMapRegisters, + FALSE ); + + } + + // + // If there were either enough map registers available or no map + // registers needed to be allocated, invoke the driver's execution + // routine now. + // + + if (Busy == FALSE) { + + AdapterObject->CurrentWcb = Wcb; + Action = Wcb->DeviceRoutine( Wcb->DeviceObject, + Wcb->CurrentIrp, + AdapterObject->MapRegisterBase, + Wcb->DeviceContext ); + + // + // If the execution routine would like to have the adapter + // deallocated, then release the adapter object. + // + + if (Action == KeepObject) { + + // + // This request wants to keep the channel a while so break + // out of the loop. + // + + break; + } + + // + // If the driver wants to keep the map registers then set the + // number allocated to 0. This keeps the deallocation routine + // from deallocating them. + // + + if (Action == DeallocateObjectKeepRegisters) { + AdapterObject->NumberOfMapRegisters = 0; + } + + } else { + + // + // This request did not get the requested number of map registers so + // out of the loop. + // + + DebugPrint( (HALDBG_MAPREG, + "IoFreeChannel, not enough maps, Adapter=%x, Maps=%x\n", + AdapterObject, Wcb->NumberOfMapRegisters) ); + + break; + } + } +} + +PHYSICAL_ADDRESS +IoMapTransfer( + IN PADAPTER_OBJECT AdapterObject, + IN PMDL Mdl, + IN PVOID MapRegisterBase, + IN PVOID CurrentVa, + IN OUT PULONG Length, + IN BOOLEAN WriteToDevice + ) + +/*++ + +Routine Description: + + This routine is invoked to set up the map registers in the DMA controller + to allow a transfer to or from a device. + +Arguments: + + AdapterObject - Pointer to the adapter object representing the DMA + controller channel that has been allocated. + + Mdl - Pointer to the MDL that describes the pages of memory that are + being read or written. + + MapRegisterBase - The address of the base map register that has been + allocated to the device driver for use in mapping the transfer. + + CurrentVa - Current virtual address in the buffer described by the MDL + that the transfer is being done to or from. + + Length - Supplies the length of the transfer. This determines the + number of map registers that need to be written to map the transfer. + Returns the length of the transfer which was actually mapped. + + WriteToDevice - Boolean value that indicates whether this is a write + to the device from memory (TRUE), or vice versa. + +Return Value: + + Returns the logical address to be used by bus masters. + +N.B. - The MapRegisterBase must point to the mapping intended for + the start virtual address of the Mdl. + +--*/ + +{ + ULONG NumberOfPages; + ULONG Offset; + PULONG PageFrameNumber; + ULONG i; + PMAP_REGISTER_ADAPTER mapAdapter; + PTRANSLATION_ENTRY mapRegister; + PHYSICAL_ADDRESS ReturnAddress; + + DebugPrint( (HALDBG_IOMT, + "\nIoMT: CurrentVA = %x, Length = %x, WriteToDevice = %x\n", + CurrentVa, *Length, WriteToDevice ) ); + + // + // Determine the Map Register Adapter. + // + + mapAdapter = NULL; + + if( AdapterObject == NULL ){ + + // + // The caller did not supply the adapter object, we will determine + // the map adapter by matching the MapRegisterBase to the ranges + // allocated for each map adapter. + // + + if( (HalpIsaMapAdapter != NULL) && + (MapRegisterBase >= HalpIsaMapAdapter->MapRegisterBase) && + ((PTRANSLATION_ENTRY)MapRegisterBase < + (PTRANSLATION_ENTRY)HalpIsaMapAdapter->MapRegisterBase + + HalpIsaMapAdapter->NumberOfMapRegisters ) ){ + + mapAdapter = HalpIsaMapAdapter; + + } + + if( (HalpMasterMapAdapter != NULL) && + (MapRegisterBase >= HalpMasterMapAdapter->MapRegisterBase) && + ((PTRANSLATION_ENTRY)MapRegisterBase < + (PTRANSLATION_ENTRY)HalpMasterMapAdapter->MapRegisterBase + + HalpMasterMapAdapter->NumberOfMapRegisters ) ){ + + mapAdapter = HalpMasterMapAdapter; + + } + + } else { + + // + // The adapter object has been provided and will always have + // a pointer to the map adapter. + // + + mapAdapter = AdapterObject->MapAdapter; + + } + + ASSERT( mapAdapter != NULL ); + + // + // Begin by determining where in the buffer this portion of the operation + // is taking place. + // + + Offset = BYTE_OFFSET( (PCHAR)CurrentVa - (PCHAR)Mdl->StartVa ); + DebugPrint( (HALDBG_IOMT, "Offset (1) = %x\n", Offset ) ); + + // + // Compute number of pages that this transfer spans. + // + + NumberOfPages = (Offset + *Length + PAGE_SIZE - 1) >> PAGE_SHIFT; + DebugPrint( (HALDBG_IOMT, "NumberOfPages = %x\n", NumberOfPages ) ); + + // + // Compute a pointer to the page frame of the starting page of the transfer. + // + + PageFrameNumber = (PULONG) (Mdl + 1); + PageFrameNumber += ( ((PCHAR) CurrentVa - (PCHAR) Mdl->StartVa) + >> PAGE_SHIFT ); + + // + // Compute a pointer to the map register that maps the starting page of + // the transfer. + // + + mapRegister = MapRegisterBase; + + // + // For each page, establish the mapping in the scatter/gather tables. + // + + for (i = 0; i < NumberOfPages; i++) { + HAL_MAKE_VALID_TRANSLATION( mapRegister, *PageFrameNumber ); + DebugPrint( (HALDBG_IOMT, + "Validate: *PageFrameNumber = %x, mapRegister = %x\n", + *PageFrameNumber, mapRegister ) ); + PageFrameNumber += 1; + mapRegister += 1; + } + + // + // If the operation is a write to device (transfer from memory to device), + // we will validate the extra map register so we don't generate a PFN + // error due to DMA prefetch by some devices. + // + + if (WriteToDevice) { + PageFrameNumber -= 1; + HAL_MAKE_VALID_TRANSLATION( mapRegister, *PageFrameNumber ); + } + + // + // Synchronize the scatter/gather entry writes with any subsequent writes + // to the device. + // + + HalpMb(); //jnfix - create HalpWmb(); + + // + // Invalidate any cached translations in the DMA window. + // + + INVALIDATE_DMA_TRANSLATIONS( mapAdapter->WindowControl ); + + // + // Set the offset to point to the map register plus the offset. + // + + Offset += ((PTRANSLATION_ENTRY) MapRegisterBase - + (PTRANSLATION_ENTRY) mapAdapter->MapRegisterBase) << PAGE_SHIFT; + + Offset += (ULONG)mapAdapter->WindowBase; + DebugPrint( (HALDBG_IOMT, "Offset(3) = %x\n", Offset ) ); + + if( (AdapterObject != NULL) && + (AdapterObject->Type == IsaAdapter) && + (AdapterObject->MasterDevice != TRUE) ){ + + // + // Start the EISA DMA controller. + // + + HalpMapEisaTransfer( + AdapterObject, + Offset, + *Length, + WriteToDevice + ); + + } + + ReturnAddress.QuadPart = Offset; + return(ReturnAddress); +} + + +BOOLEAN +IoFlushAdapterBuffers( + IN PADAPTER_OBJECT AdapterObject, + IN PMDL Mdl, + IN PVOID MapRegisterBase, + IN PVOID CurrentVa, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) + +/*++ + +Routine Description: + + This routine flushes the DMA adapter object buffers and clears the + enable flag which aborts the dma. + +Arguments: + + AdapterObject - Pointer to the adapter object representing the DMA + controller channel. + + Mdl - A pointer to a Memory Descriptor List (MDL) that maps the locked-down + buffer to/from which the I/O occured. + + MapRegisterBase - A pointer to the base of the map registers in the adapter + or DMA controller. + + CurrentVa - The current virtual address in the buffer described the the Mdl + where the I/O operation occurred. + + Length - Supplies the length of the transfer. + + WriteToDevice - Supplies a BOOLEAN value that indicates the direction of + the data transfer was to the device. + +Return Value: + + TRUE - If the transfer was successful. + + FALSE - If there was an error in the transfer. + +--*/ + +{ + ULONG NumberOfPages; + ULONG Offset; + BOOLEAN Result; + ULONG i; + PMAP_REGISTER_ADAPTER mapAdapter; + PTRANSLATION_ENTRY mapRegister; + + DebugPrint( (HALDBG_IOMT, + "\nIoFlush: CurrentVA = %x, Length = %x, WriteToDevice = %x\n", + CurrentVa, Length, WriteToDevice ) ); + + // + // Determine the Map Register Adapter. + // + + mapAdapter = NULL; + + if( AdapterObject == NULL ){ + + // + // The caller did not supply the adapter object, we will determine + // the map adapter by matching the MapRegisterBase to the ranges + // allocated for each map adapter. + // + + if( (HalpIsaMapAdapter != NULL) && + (MapRegisterBase >= HalpIsaMapAdapter->MapRegisterBase) && + ((PTRANSLATION_ENTRY)MapRegisterBase < + (PTRANSLATION_ENTRY)HalpIsaMapAdapter->MapRegisterBase + + HalpIsaMapAdapter->NumberOfMapRegisters ) ){ + + mapAdapter = HalpIsaMapAdapter; + + } + + if( (HalpMasterMapAdapter != NULL) && + (MapRegisterBase >= HalpMasterMapAdapter->MapRegisterBase) && + ((PTRANSLATION_ENTRY)MapRegisterBase < + (PTRANSLATION_ENTRY)HalpMasterMapAdapter->MapRegisterBase + + HalpMasterMapAdapter->NumberOfMapRegisters ) ){ + + mapAdapter = HalpMasterMapAdapter; + + } + + } else { + + // + // The adapter object has been provided and will always have + // a pointer to the map adapter. + // + + mapAdapter = AdapterObject->MapAdapter; + + } + + // + // Set the result of the flush to success. + // + + Result = TRUE; + + // + // If this is an Isa compatiable adapter or an adapter that uses + // the ISA/EISA Dma controllers then use the standard routines + // to clear the Dma controller. + // + + if( (AdapterObject != NULL) && + (AdapterObject->Type == IsaAdapter) && + (AdapterObject->MasterDevice != TRUE) ){ + + Result = HalpFlushEisaAdapter( AdapterObject, + Mdl, + MapRegisterBase, + CurrentVa, + Length, + WriteToDevice ); + } + + // + // The Mdl->StartVa must point to a page boundary. + // + + ASSERT( ( (ULONG)Mdl->StartVa & (PAGE_SIZE-1) ) == 0 ); + + // + // Compute the starting offset of the transfer. + // + + Offset = BYTE_OFFSET( (PCHAR)CurrentVa - (PCHAR)Mdl->StartVa ); + + // + // Compute the number of pages that this transfer spanned. + // + + NumberOfPages = (Offset + Length + PAGE_SIZE-1) >> PAGE_SHIFT; + + // + // Compute a pointer to the first translation entry that mapped this + // transfer. + // + + mapRegister = (PTRANSLATION_ENTRY)MapRegisterBase; + + // + // Mark each translation as invalid. + // + + for( i=0; i < NumberOfPages; i++ ){ + HAL_INVALIDATE_TRANSLATION( mapRegister ); + DebugPrint( (HALDBG_IOMT, + "Invalidate mapRegister = %x, PageFrame=%x\n", + mapRegister, (PTRANSLATION_ENTRY)mapRegister->Pfn) ); + mapRegister += 1; + } + + if( WriteToDevice ){ + HAL_INVALIDATE_TRANSLATION( mapRegister ); + } + + // + // Invalidate any cached translations in the DMA window. + // + + INVALIDATE_DMA_TRANSLATIONS( mapAdapter->WindowControl ); + + // + // Synchronize the updated translations with any subsequent device + // accesses. + // Also, synchronize any reads of the newly written DMA data by + // ensuring this processors view of memory is coherent. + // jnfix - actually this second task must be handled by HalFlushIoBuffers + // + + HalpMb(); + + return Result; + +} + +ULONG +HalReadDmaCounter( + IN PADAPTER_OBJECT AdapterObject + ) +/*++ + +Routine Description: + + This function reads the DMA counter and returns the number of bytes left + to be transfered. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object to be read. + +Return Value: + + Returns the number of bytes still be be transfered. + +--*/ + +{ + + // + // If this is an Isa compatiable adapter or an adapter that uses + // the ISA/EISA Dma controllers then use the standard routines + // to return the Dma count. + // + + if( AdapterObject->Type == IsaAdapter ){ + + return HalpReadEisaDmaCounter( AdapterObject ); + + } + + return 0; + +} + + +PVOID +HalAllocateCommonBuffer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Length, + OUT PPHYSICAL_ADDRESS LogicalAddress, + IN BOOLEAN CacheEnabled + ) +/*++ + +Routine Description: + + This function allocates the memory for a common buffer and maps so that it + can be accessed by a master device and the CPU. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object used by this + device. + + Length - Supplies the length of the common buffer to be allocated. + + LogicalAddress - Returns the logical address of the common buffer. + + CacheEnable - Indicates whether the memeory is cached or not. + +Return Value: + + Returns the virtual address of the common buffer. If the buffer cannot be + allocated then NULL is returned. + +--*/ + +{ + PVOID virtualAddress; + PVOID mapRegisterBase; + ULONG numberOfMapRegisters; + ULONG mappedLength; + WAIT_CONTEXT_BLOCK wcb; + KEVENT allocationEvent; + NTSTATUS status; + PMDL mdl; + KIRQL irql; + PHYSICAL_ADDRESS MaxPhysicalAddress; + + numberOfMapRegisters = BYTES_TO_PAGES(Length); + + // + // Allocate the actual buffer and limit its physical address + // below 1GB. The 1GB limitation guarantees that the buffer will + // be accessible via 32-bit superpage. + // + + MaxPhysicalAddress.HighPart = 0; + MaxPhysicalAddress.LowPart = __1GB - 1; + virtualAddress = MmAllocateContiguousMemory( Length, MaxPhysicalAddress ); + + if (virtualAddress == NULL) { + + return(virtualAddress); + + } + + // + // Initialize an event. + // + + KeInitializeEvent( &allocationEvent, NotificationEvent, FALSE); + + // + // Initialize the wait context block. Use the device object to indicate + // where the map register base should be stored. + // + + wcb.DeviceObject = &mapRegisterBase; + wcb.CurrentIrp = NULL; + wcb.DeviceContext = &allocationEvent; + + // + // Allocate the adapter and the map registers. + // + + KeRaiseIrql(DISPATCH_LEVEL, &irql); + + status = HalAllocateAdapterChannel( + AdapterObject, + &wcb, + numberOfMapRegisters, + HalpAllocationRoutine + ); + + KeLowerIrql(irql); + + if (!NT_SUCCESS(status)) { + + // + // Cleanup and return NULL. + // + + MmFreeContiguousMemory( virtualAddress ); + return(NULL); + + } + + // + // Wait for the map registers to be allocated. + // + + status = KeWaitForSingleObject( + &allocationEvent, + Executive, + KernelMode, + FALSE, + NULL + ); + + if (!NT_SUCCESS(status)) { + + // + // Cleanup and return NULL. + // + + MmFreeContiguousMemory( virtualAddress ); + return(NULL); + + } + + // + // Create an mdl to use with call to I/O map transfer. + // + + mdl = IoAllocateMdl( + virtualAddress, + Length, + FALSE, + FALSE, + NULL + ); + + MmBuildMdlForNonPagedPool(mdl); + + // + // Map the transfer so that the controller can access the memory. + // + + mappedLength = Length; + *LogicalAddress = IoMapTransfer( + NULL, + mdl, + mapRegisterBase, + virtualAddress, + &mappedLength, + TRUE + ); + + IoFreeMdl(mdl); + + if (mappedLength < Length) { + + // + // Cleanup and indicate that the allocation failed. + // + + HalFreeCommonBuffer( + AdapterObject, + Length, + *LogicalAddress, + virtualAddress, + FALSE + ); + + return(NULL); + } + + // + // The allocation completed successfully. + // + + return(virtualAddress); + +} + +VOID +HalFreeCommonBuffer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Length, + IN PHYSICAL_ADDRESS LogicalAddress, + IN PVOID VirtualAddress, + IN BOOLEAN CacheEnabled + ) +/*++ + +Routine Description: + + This function frees a common buffer and all of the resouces it uses. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object used by this + device. + + Length - Supplies the length of the common buffer. This should be the same + value used for the allocation of the buffer. + + LogicalAddress - Supplies the logical address of the common buffer. This + must be the same value return by HalAllocateCommonBuffer. + + VirtualAddress - Supplies the virtual address of the common buffer. This + must be the same value return by HalAllocateCommonBuffer. + + CacheEnable - Indicates whether the memeory is cached or not. + +Return Value: + + None + +--*/ + +{ + PMAP_REGISTER_ADAPTER mapAdapter; + PTRANSLATION_ENTRY mapRegisterBase; + ULONG mapRegisterIndex; + ULONG numberOfMapRegisters; + + mapAdapter = AdapterObject->MapAdapter; + + // + // Calculate the number of map registers, the map register index and + // the map register base. + // + + numberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES( VirtualAddress, + Length ); + mapRegisterIndex = (LogicalAddress.LowPart - (ULONG)mapAdapter->WindowBase) + >> PAGE_SHIFT; + + mapRegisterBase = (PTRANSLATION_ENTRY) mapAdapter->MapRegisterBase + + mapRegisterIndex; + + // + // Free the map registers. + // + + IoFreeMapRegisters( + AdapterObject, + (PVOID) mapRegisterBase, + numberOfMapRegisters + ); + + // + // Free the memory for the common buffer. + // + + MmFreeContiguousMemory( VirtualAddress ); + + return; + +} + + +BOOLEAN +HalFlushCommonBuffer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Length, + IN PHYSICAL_ADDRESS LogicalAddress, + IN PVOID VirtualAddress + ) +/*++ + +Routine Description: + + This function is called to flush any hardware adapter buffers when the + driver needs to read data written by an I/O master device to a common + buffer. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object used by this + device. + + Length - Supplies the length of the common buffer. This should be the same + value used for the allocation of the buffer. + + LogicalAddress - Supplies the logical address of the common buffer. This + must be the same value return by HalAllocateCommonBuffer. + + VirtualAddress - Supplies the virtual address of the common buffer. This + must be the same value return by HalAllocateCommonBuffer. + +Return Value: + + Returns TRUE if no errors were detected; otherwise, FALSE is return. + +--*/ + +{ + + return(TRUE); + +} + +IO_ALLOCATION_ACTION +HalpAllocationRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID MapRegisterBase, + IN PVOID Context + ) + +/*++ + +Routine Description: + + This function is called by HalAllocateAdapterChannel when sufficent resources + are available to the driver. This routine saves the MapRegisterBase, + and set the event pointed to by the context parameter. + +Arguments: + + DeviceObject - Supplies a pointer where the map register base should be + stored. + + Irp - Unused. + + MapRegisterBase - Supplied by the Io subsystem for use in IoMapTransfer. + + Context - Supplies a pointer to an event which is set to indicate the + AdapterObject has been allocated. + +Return Value: + + DeallocateObjectKeepRegisters - Indicates the adapter should be freed + and mapregisters should remain allocated after return. + +--*/ + +{ + + UNREFERENCED_PARAMETER(Irp); + + *((PVOID *) DeviceObject) = MapRegisterBase; + + (VOID) KeSetEvent( (PKEVENT) Context, 0L, FALSE ); + + return(DeallocateObjectKeepRegisters); +} diff --git a/private/ntos/nthals/halalpha/ebsgdma.h b/private/ntos/nthals/halalpha/ebsgdma.h new file mode 100644 index 000000000..2548b8134 --- /dev/null +++ b/private/ntos/nthals/halalpha/ebsgdma.h @@ -0,0 +1,180 @@ +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + ebsgdma.h + +Abstract: + + This file defines the data structures for scatter/gather DMA + support for Eisa/Isa bus systems. + +Author: + + Joe Notarangelo 12-Oct-1993 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#ifndef _EBSGDMA_ +#define _EBSGDMA_ + +#include "eisa.h" + + +// +// Define the structures for Io Adapters. +// + +typedef enum _HAL_ADAPTER_TYPE{ + IsaAdapter, + BusMasterAdapter +} HAL_ADAPTER_TYPE, *PHAL_ADAPTER_TYPE; + +typedef struct _MAP_REGISTER_ADAPTER{ + + // + // The type of the map register adapter. + // + + HAL_ADAPTER_TYPE Type; + + // + // Access control for allocating map registers. + // The SpinLock guarantees exclusive access to this adapter. + // The RegisterWaitQueue is a list of adapters waiting for + // map registers. The spinlock is also used to grant exclusive + // access to other resources which may be shared by the adapters + // that have this map adapter in common (in particular, access to the + // DMA controller hardware in Eisa/Isa machines). + // + + KSPIN_LOCK SpinLock; + LIST_ENTRY RegisterWaitQueue; + + // + // MapRegisterBase is the base address of the scatter/gather entry + // array. NumberOfMapRegisters is the number of scatter/gather entries + // allocated for this adapter. MapRegisterAllocation points to the + // allocation bitmap for the scatter/gather entry array. + // + + PVOID MapRegisterBase; + ULONG NumberOfMapRegisters; + PRTL_BITMAP MapRegisterAllocation; + + // + // WindowBase is the base bus address of the DMA window controlled + // by this adapter. WindowSize is the size of the window in bytes. + // + + PVOID WindowBase; + ULONG WindowSize; + + // + // WindowControl is a pointer to the window control registers + // structure that defines the QVAs of the window registers. + // + + PVOID WindowControl; + +} MAP_REGISTER_ADAPTER, *PMAP_REGISTER_ADAPTER; + + +typedef struct _ADAPTER_OBJECT{ + + // + // Object header fields, type and size. + /// + + CSHORT ObjectType; + CSHORT Size; + + // + // The type of the adapter, either an adapter that requires Isa + // support or an adapter that does not. + // + + HAL_ADAPTER_TYPE Type; + + // + // Pointer to the adapter that controls the map registers for this + // adapter. + // + + PMAP_REGISTER_ADAPTER MapAdapter; + + // + // Indicate if this is a master device or not. + // + + BOOLEAN MasterDevice; + + // + // The maximum map registers for this adapter. + // + + ULONG MapRegistersPerChannel; + + // + // The map registers currently allocated to this adapter, the base + // address and the number. The number will be the number desired for + // allocation if this adapter is waiting on the map adapters queue. + // + + PVOID MapRegisterBase; + ULONG NumberOfMapRegisters; + + // + // The device queue for waiters trying to all allocate this adapter. + // + + KDEVICE_QUEUE ChannelWaitQueue; + + // + // The wait context block of the driver that has currently allocated + // the adapter. + // + + struct _WAIT_CONTEXT_BLOCK *CurrentWcb; + + // + // The list entry used when this adapter is queue to a map adapter, + // waiting for map registers. + // + + LIST_ENTRY AdapterQueue; + + // + // Values describing the programming of a DMA channel for this + // adapter. The values describe the programming for a standard PC + // DMA controller. + // + // AdapterBaseVa - pointer to base address of DMA controller. + // AdapterNumber - the number of the DMA controller. + // ChannelNumber - the DMA channel number used by the adapter. + // AdapterMode - the mode used to program the DMA channel. + // ExtendedMode - the value used to program extended mode for the channel. + // SingleMaskPort - port address for unmasking the DMA controller. + // PagePort - port address of the page register for the DMA channel. + // + + PVOID AdapterBaseVa; + UCHAR AdapterNumber; + UCHAR ChannelNumber; + UCHAR AdapterMode; + DMA_EXTENDED_MODE ExtendedMode; + PUCHAR PagePort; + BOOLEAN Width16Bits; + +} ADAPTER_OBJECT; + +#endif //_EBSGDMA_ diff --git a/private/ntos/nthals/halalpha/eeprom8k.c b/private/ntos/nthals/halalpha/eeprom8k.c new file mode 100644 index 000000000..c4e73260f --- /dev/null +++ b/private/ntos/nthals/halalpha/eeprom8k.c @@ -0,0 +1,391 @@ +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + eeprom8k.c + +Abstract: + + This module implements the device-specific routines necessary to + Read and Write the Electrically Eraseable Programmable Read Only + Memory (EEPROM) containing the system environment variables. Note + that this module is used in exclusion of CMOS NVram support for the + same variables. + + This module assumes that a standard PC NVRAM interface to the EEPROM + is being provided (for example the one provide by the Intel ESC + chip). This interface gives a 256 byte NVRAM page window into the + device. The current NVRAM page is selected through a page select + register. + + Parts support by this module include: + + Xicor X2864A + + The routines implemented here are: + + HalpReadNVRamBuffer() - copy data from NVRAM into memory + HalpWriteNVRamBuffer() - write memory data to NVRAM + HalpCopyNVRamBuffer() - move data within the NVRAM + +Author: + + Steve Brooks 5-Oct 93 + + +Revision History: + + Steve Jenness 10-Nov 93 + Joe Notarangelo 10-Nov 93 + Matthew Buchman 09-May 96 Stall instead of polling for Write complete. + Scott Lee 23-Sept-96 Use original write algorithm and add a check + for the last write. + +--*/ + + +#include "halp.h" +#include "cmos8k.h" // This is ok for eeprom8k.c + +#include "arccodes.h" + +#ifdef HAL_DBG +ULONG EepromDebug = 0; +#define EepromDbgPrint(x) if (EepromDebug) DbgPrint(x) +#else +#define EepromDbgPrint(x) +#endif //HAL_DBG + +// +// Routine prototypes. +// + +ARC_STATUS +HalpReadNVRamBuffer ( + OUT PCHAR DataPtr, + IN PCHAR NvRamPtr, + IN ULONG Length + ); + +ARC_STATUS +HalpWriteNVRamBuffer ( + IN PCHAR NvRamPtr, + IN PCHAR DataPtr, + IN ULONG Length + ); + +ARC_STATUS +HalpCopyNVRamBuffer ( + IN PCHAR NvDestPtr, + IN PCHAR NvSrcPtr, + IN ULONG Length + ); + + + +ARC_STATUS +HalpReadNVRamBuffer ( + OUT PCHAR DataPtr, + IN PCHAR NvRamPtr, + IN ULONG Length + ) + +/*++ + +Routine Description: + + This routine reads data from the EEPROM into main memory. + +Arguments: + + DataPtr - Pointer to memory location to receive data + NvRamPtr - Pointer (qva) to EEPROM location to read data from + Length - Number of bytes of data to transfer + +Return Value: + + ESUCCESS if the operation succeeds. + +--*/ +{ + ULONG PageSelect, ByteSelect; + + PageSelect = (NvRamPtr - (PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT; + ByteSelect = (NvRamPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK; + + WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect); + while ( Length -- ) + { + *DataPtr++ = READ_CONFIG_RAM_DATA(NvRamPtr); + NvRamPtr ++; + + ByteSelect = (ByteSelect + 1) & CONFIG_RAM_BYTE_MASK; + if (ByteSelect == 0) + { + PageSelect++; + WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect); + } + } + + return(ESUCCESS); +} + +ARC_STATUS +HalpWriteNVRamBuffer ( + IN PCHAR NvRamPtr, + IN PCHAR DataPtr, + IN ULONG Length + ) + +/*++ + +Routine Description: + + This routine Writes data from memory into the EEPROM. EEPROM page + mode write is used. + + N.B. - This routine could have problems if interrupts are enabled + and the writing time between two bytes is over 20uSec. + + N.B. - The ESC provides the NVRAM interface on 256 + byte NVRAM pages. The EEPROM internally uses 16byte pages for + grouped programming. A EEPROM 16byte page commits (programs into + the EEPROM) in the same amount of time as a single byte does. + A EEPROM page has to be committed before switching to another + page. This is true if only 1 byte is written or all 16. + + N.B. - This routine assumes that the base address of the 256 byte + page buffer is on a 256 byte boundary. + + N.B. - With the increase in processor speed and compiler technology, + we seem to violate a time increment that must occur between + Writes followed by Reads. This results in invaliding the + last write of the page. By first waiting the amount of a + write cycle, (specified in the Data Sheet as 5ms) after the last + write before reading, we don't run into this problem. + + N.B. - The last write algorithm used did not worked with the 120 nsec part. + We have reverted back to the original algorithm and added a + modification. On the last write, if it is on a 256 byte page + boundary, do not increment and write the page select. Doing so will + cause the verification of the last write to fail. + +Arguments: + + NvRamPtr - Pointer (qva) to EEPROM location to write data into + DataPtr - Pointer to memory location of data to be written + Length - Number of bytes of data to transfer + +Return Value: + + ESUCCESS if the operation succeeds. + +--*/ +{ + ULONG PageSelect; + +#define EEPROM_PAGE_SIZE 16 +#define EEPROM_OFFSET_MASK 0xF + + ULONG EepromPageDataValid = FALSE; + UCHAR EepromPageData[EEPROM_PAGE_SIZE]; + ULONG EepromPageOffset = 0; + + BOOLEAN ByteWritten = FALSE; + PCHAR LastWrittenByteAddress; + ULONG LastWrittenByteValue; + + // + // Calculate which NVRAM 256 byte page to select first. + // + + PageSelect = (NvRamPtr - (PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT; + WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect); + + // + // Loop until no more data to write. + // + + while ( (Length --) != 0) { + + // + // If the current page of EEPROM data hasn't been read from the + // device, do so now. The whole EEPROM page is read at once so + // that it doesn't interfere with the EEPROM programming timeout. + // + + if (EepromPageDataValid == FALSE) { + PCHAR TmpNvRamPtr = NvRamPtr; + + EepromPageOffset = (ULONG)NvRamPtr & EEPROM_OFFSET_MASK; + + while (EepromPageOffset < EEPROM_PAGE_SIZE) { + EepromPageData[EepromPageOffset++] = + READ_CONFIG_RAM_DATA(TmpNvRamPtr); + TmpNvRamPtr++; + } + + EepromPageDataValid = TRUE; + EepromPageOffset = (ULONG)NvRamPtr & EEPROM_OFFSET_MASK; + } + + // + // If the EEPROM data matches the data to be written, short-circuit + // the write. This potentially saves lots of time. + // If the data is different, write it and remember that a byte + // was written for the NOT-DATA polling done later. + // + + if (EepromPageData[EepromPageOffset] != *DataPtr) { + + WRITE_CONFIG_RAM_DATA(NvRamPtr, *DataPtr); + ByteWritten = TRUE; + LastWrittenByteValue = *DataPtr; + LastWrittenByteAddress = NvRamPtr; + + EepromDbgPrint( "." ); + } else { + EepromDbgPrint( "o" ); + } + + EepromPageOffset ++; + NvRamPtr ++; + DataPtr ++; + + // + // If we're stepping into the next EEPROM 16 byte page first make + // sure that the data for the previous page has been programmed. + // Invalidate the current EEPROM page data buffer so that the next + // page will be read in (for the short-circuit above). + // + + if (EepromPageOffset >= EEPROM_PAGE_SIZE) { + if (ByteWritten == TRUE) { + while((READ_CONFIG_RAM_DATA(LastWrittenByteAddress) & 0xff) != + (UCHAR)(LastWrittenByteValue & 0xff)); + ByteWritten = FALSE; + } + EepromPageDataValid = FALSE; + } + + // + // If we are stepping into the next NVRAM 256 byte page, switch + // the NVRAM page select. Don't step into the next page on the + // last write, however. + // + + if ((Length != 0) && + (((ULONG)NvRamPtr & CONFIG_RAM_BYTE_MASK) == 0 ) ) { + PageSelect++; + WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect); + } + } + + // + // Poll until the last byte written is programmed into the EEPROM. + // + + if (ByteWritten == TRUE) { + while((READ_CONFIG_RAM_DATA(LastWrittenByteAddress) & 0xff) != + (UCHAR)(LastWrittenByteValue & 0xff)); + } + + return(ESUCCESS); +} + +ARC_STATUS +HalpCopyNVRamBuffer ( + IN PCHAR NvDestPtr, + IN PCHAR NvSrcPtr, + IN ULONG Length + ) + +/*++ + +Routine Description: + + This routine copies data between two locations within the EEPROM. It is + the callers responsibility to assure that the destination region does not + overlap the src region i.e. if the regions overlap, NvSrcPtr > NvDestPtr. + + This routine does not use page mode access since we're unsure that + we can guarantee the 20uSec inter-byte timing required during a + page write. Currently, each byte is written and then checked for + commit into the EEPROM. + + N.B. - This routine has not been optimized like HalpWriteNVRamBuffer. + + N.B. - This routine doesn't appear to be used anywhere in either the + firmware, the HAL, or the kernel. It might not work. + +Arguments: + + NvDestPtr - Pointer (qva) to NVRam location to write data into + NvSrcPtr - Pointer (qva) to NVRam location of data to copy + Length - Number of bytes of data to transfer + +Return Value: + + ESUCCESS if the operation succeeds. + +--*/ + +{ + ULONG PageSelect0, ByteSelect0; // Src Pointer Page & offset + ULONG PageSelect1, ByteSelect1; // Dest Pointer Page & offset + + + PageSelect0 = (NvSrcPtr - (PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT; + ByteSelect0 = (NvSrcPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK; + + PageSelect1 = (NvDestPtr-(PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT; + ByteSelect1 = (NvDestPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK; + + WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect0); + while ( Length -- ) + { + UCHAR AChar; + + // + // Check the Page select for the src pointer, and write the + // select register if necessary: + // + if (ByteSelect0 == 0) + { + PageSelect0++; + } + if ( PageSelect0 != PageSelect1 ) + { + WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect0); + } + + AChar = READ_CONFIG_RAM_DATA(NvSrcPtr); + ByteSelect0 = (ByteSelect0 + 1) & CONFIG_RAM_BYTE_MASK; + + // + // Check the page select for the dest pointer, and write + // the select register if necessary: + // + if (ByteSelect1 == 0) + { + PageSelect1++; + } + if ( PageSelect1 != PageSelect0 ) + { + WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect1); + } + + WRITE_CONFIG_RAM_DATA(NvDestPtr, AChar); + + while ( READ_CONFIG_RAM_DATA(NvDestPtr) != AChar ) + ; + ByteSelect1 = (ByteSelect1 + 1) & CONFIG_RAM_BYTE_MASK; + + NvSrcPtr ++; + NvDestPtr ++; + } + + return(ESUCCESS); +} diff --git a/private/ntos/nthals/halalpha/eisaprof.c b/private/ntos/nthals/halalpha/eisaprof.c new file mode 100644 index 000000000..71350f4f6 --- /dev/null +++ b/private/ntos/nthals/halalpha/eisaprof.c @@ -0,0 +1,517 @@ +/*++ + +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + eisaprof.c + +Abstract: + + This module handles the Profile Counter and all Profile counter functions + for the standard EISA interval timer. + +Author: + + Jeff McLeman (mcleman) 05-June-1992 + +Environment: + + Kernel mode + +Revision History: + + + Rod Gamache [DEC] 9-Mar-1993 + Fix profile clock. + + +--*/ + +#include "halp.h" +#include "eisa.h" +#include "halprof.h" + +// +// Define global data. +// + +// +// Values used for Profile Clock +// + +// Convert the interval to rollover count for 8254 timer. Since +// the 8254 counts down a 16 bit value at the clock rate of 1.193 MHZ, +// the computation is: +// +// RolloverCount = (Interval * 0.0000001) * (1193 * 1000000) +// = Interval * .1193 +// = Interval * 1193 / 10000 + +#define PROFILE_INTERVAL 1193 +#define PROFILE_INTERVALS_PER_100NS 10000/1193 +#define MIN_PROFILE_TICKS 4 +#define MAX_PROFILE_TICKS 0x10000 // 16 bit counter (zero is max) + +// +// Since the profile timer interrupts at a frequency of 1.193 MHZ, we +// have .1193 intervals each 100ns. So we need a more reasonable value. +// If we compute the timer based on 1600ns intervals, we get 16 * .1193 or +// about 1.9 ticks per 16 intervals. +// +// We round this to 2 ticks per 1600ns intervals. +// + +#define PROFILE_TIMER_1600NS_TICKS 2 + +// +// Default Profile Interval to be about 1ms. +// + +ULONG HalpProfileInterval = PROFILE_TIMER_1600NS_TICKS * PROFILE_INTERVALS_PER_100NS * 10000 / 16; // ~1ms + +// +// Default Number of Profile Clock Ticks per sample +// + +ULONG HalpNumberOfTicks = 1; + +// +// Define the profile interrupt object. +// + +PKINTERRUPT HalpProfileInterruptObject; + +// +// Declare profile interrupt handler. +// + +BOOLEAN +HalpProfileInterrupt( + PKSERVICE_ROUTINE InterruptRoutine, + PVOID ServiceContext, + PKTRAP_FRAME TrapFrame + ); + +// +// Function prototypes. +// + +BOOLEAN +HalQueryProfileInterval( + IN KPROFILE_SOURCE Source + ); + +NTSTATUS +HalSetProfileSourceInterval( + IN KPROFILE_SOURCE ProfileSource, + IN OUT ULONG *Interval + ); + +// +// Function definitions. +// + + +NTSTATUS +HalpProfileSourceInformation ( + OUT PVOID Buffer, + IN ULONG BufferLength, + OUT PULONG ReturnedLength + ) +/*++ + +Routine Description: + + Returns the HAL_PROFILE_SOURCE_INFORMATION for this processor. + +Arguments: + + Buffer - output buffer + BufferLength - length of buffer on input + ReturnedLength - The length of data returned + +Return Value: + + STATUS_SUCCESS + STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize + currently needed. + +--*/ +{ + PHAL_PROFILE_SOURCE_INFORMATION SourceInfo; + NTSTATUS Status; + + + if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INFORMATION)) { + Status = STATUS_INFO_LENGTH_MISMATCH; + return Status; + } + + SourceInfo = (PHAL_PROFILE_SOURCE_INFORMATION)Buffer; + SourceInfo->Supported = HalQueryProfileInterval(SourceInfo->Source); + + if (SourceInfo->Supported) { + SourceInfo->Interval = HalpProfileInterval * HalpNumberOfTicks; + } + + Status = STATUS_SUCCESS; + return Status; +} + + +NTSTATUS +HalpProfileSourceInterval ( + OUT PVOID Buffer, + IN ULONG BufferLength + ) +/*++ + +Routine Description: + + Returns the HAL_PROFILE_SOURCE_INTERVAL for this processor. + +Arguments: + + Buffer - output buffer + BufferLength - length of buffer on input + +Return Value: + + STATUS_SUCCESS + STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize + currently needed. + +--*/ +{ + PHAL_PROFILE_SOURCE_INTERVAL Interval; + NTSTATUS Status; + + + if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INTERVAL)) { + Status = STATUS_INFO_LENGTH_MISMATCH; + return Status; + } + + Interval = (PHAL_PROFILE_SOURCE_INTERVAL)Buffer; + Status = HalSetProfileSourceInterval(Interval->Source, + &Interval->Interval); + return Status; +} + + +VOID +HalpInitializeProfiler( + VOID + ) +/*++ + +Routine Description: + + Initialize the profiler by setting initial values and connecting + the profile interrupt. + +Arguments: + + InterfaceType - Supplies the interface type of the bus on which the + profiler will be connected. + + BusNumber - Supplies the number of the bus on which the profiler will + be connected. + + BusInterruptLevel - Supplies the bus interrupt level to connect the + profile interrupt. + +Return Value: + + None. + +--*/ +{ + KAFFINITY Affinity; + KIRQL Irql; + ULONG Vector; + + // + // Get the interrupt vector and synchronization Irql. + // + + Vector = HalGetInterruptVector( Eisa, + 0, + 0, + 0, + &Irql, + &Affinity ); + + IoConnectInterrupt( &HalpProfileInterruptObject, + (PKSERVICE_ROUTINE)HalpProfileInterrupt, + NULL, + NULL, + Vector, + Irql, + Irql, + Latched, + FALSE, + Affinity, + FALSE ); + + return; +} + + +BOOLEAN +HalpProfileInterrupt( + PKSERVICE_ROUTINE InterruptRoutine, + PVOID ServiceContext, + PKTRAP_FRAME TrapFrame + ) +/*++ + +Routine Description: + + This routine is entered as a result of an interrupt generated by + the profile timer. Its function is to acknowlege the interrupt and + transfer control to the standard system routine to update the + system profile time. + +Arguments: + + InterruptRoutine - not used. + + ServiceContext - not used. + + TrapFrame - Supplies a pointer to the trap frame for the profile interrupt. + +Returned Value: + + None + +--*/ +{ + + // + // See if profiling is active + // + + if ( HAL_PCR->ProfileCount ) { + + // + // Check to see if the interval has expired + // If it has then call the kernel routine for profile + // and reset the count, else return. + + + if ( !(--HAL_PCR->ProfileCount) ) { + + KeProfileInterrupt( TrapFrame ); + HAL_PCR->ProfileCount = HalpNumberOfTicks; + + } + } + + return TRUE; + +} + + +BOOLEAN +HalQueryProfileInterval( + IN KPROFILE_SOURCE ProfileSource + ) + +/*++ + +Routine Description: + + Given a profile source, returns whether or not that source is + supported. + +Arguments: + + Source - Supplies the profile source + +Return Value: + + TRUE - Profile source is supported + + FALSE - Profile source is not supported + +--*/ + +{ + if (ProfileSource == ProfileTime) + return(TRUE); + else + return(FALSE); +} + + +NTSTATUS +HalSetProfileSourceInterval( + IN KPROFILE_SOURCE ProfileSource, + IN OUT ULONG *Interval + ) + +/*++ + +Routine Description: + + Sets the profile interval for a specified profile source + +Arguments: + + ProfileSource - Supplies the profile source + + Interval - Supplies the specified profile interval + Returns the actual profile interval + +Return Value: + + NTSTATUS + +--*/ + +{ + if (ProfileSource != ProfileTime) + return(STATUS_NOT_IMPLEMENTED); + + // + // Set the interval. + // + + *Interval = HalSetProfileInterval(*Interval); + + // + // We're done. + // + + return(STATUS_SUCCESS); +} + + +ULONG +HalSetProfileInterval ( + IN ULONG Interval + ) + +/*++ + +Routine Description: + + This routine sets the profile interrupt interval. + +Arguments: + + Interval - Supplies the desired profile interval in 100ns units. + +Return Value: + + The actual profile interval. + +--*/ + +{ + + HalpProfileInterval = (Interval/16) * PROFILE_TIMER_1600NS_TICKS; + + HalpProfileInterval = ( HalpProfileInterval < MIN_PROFILE_TICKS ) ? + MIN_PROFILE_TICKS : HalpProfileInterval; + + return HalpProfileInterval * PROFILE_INTERVALS_PER_100NS; +} + + +VOID +HalStartProfileInterrupt ( + KPROFILE_SOURCE ProfileSource + ) + +/*++ + +Routine Description: + + This routine turns on the profile interrupt. + + N.B. This routine must be called at PROCLK_LEVEL while holding the + profile lock. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + + if (ProfileSource != ProfileTime) + return; + + // + // Assume that we only need 1 clock tick before we collect data + // + + HalpNumberOfTicks = 1; + + if ( HalpProfileInterval > MAX_PROFILE_TICKS ) { + + HalpNumberOfTicks = HalpProfileInterval / (MAX_PROFILE_TICKS / 4); + HalpNumberOfTicks = 4 * HalpNumberOfTicks; + HalpProfileInterval = MAX_PROFILE_TICKS / 4; + + } + + // + // Set current profile count and interval. + // + + HAL_PCR->ProfileCount = HalpNumberOfTicks; + + PIC_PROFILER_ON(HalpProfileInterval); + + return; +} + + +VOID +HalStopProfileInterrupt ( + KPROFILE_SOURCE ProfileSource + ) + +/*++ + +Routine Description: + + This routine turns off the profile interrupt. + + N.B. This routine must be called at PROCLK_LEVEL while holding the + profile lock. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + + if (ProfileSource != ProfileTime) + return; + + // + // Clear the current profile count and turn off the profiler timer. + // + + HAL_PCR->ProfileCount = 0; + + PIC_PROFILER_OFF(); + + return; +} diff --git a/private/ntos/nthals/halalpha/eisasup.c b/private/ntos/nthals/halalpha/eisasup.c new file mode 100644 index 000000000..4f907fa1d --- /dev/null +++ b/private/ntos/nthals/halalpha/eisasup.c @@ -0,0 +1,1477 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + eisasup.c + +Abstract: + + The module provides the platform-independent + EISA bus support for Alpha systems. + +Author: + + Jeff Havens (jhavens) 19-Jun-1991 + Miche Baker-Harvey (miche) 13-May-1992 + Jeff McLeman (DEC) 1-Jun-1992 + +Revision History: + + +--*/ + + +#include "halp.h" +#include "eisa.h" + + +// +// Define save area for ESIA adapter objects. +// + +PADAPTER_OBJECT HalpEisaAdapter[8]; + +// +// This value indicates if Eisa DMA is supported on this system. +// + +BOOLEAN HalpEisaDma; + + +VOID +HalpEisaInitializeDma( + VOID + ) +/*++ + +Routine Description: + + Initialize DMA support for Eisa/Isa systems. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + UCHAR DataByte; + + // + // Determine if Eisa DMA is supported. + // + + HalpEisaDma = FALSE; + + WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort.Channel2, 0x55); + DataByte = READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort.Channel2); + + if (DataByte == 0x55) { + HalpEisaDma = TRUE; + } +} + + +PADAPTER_OBJECT +HalpAllocateEisaAdapter( + IN PDEVICE_DESCRIPTION DeviceDescriptor, + OUT PULONG NumberOfMapRegisters + ) + +/*++ + +Routine Description: + + This function returns the appropriate adapter object for the device defined + in the device description structure. This code works for Isa and Eisa + systems. + +Arguments: + + DeviceDescriptor - Supplies a description of the device. + + NumberOfMapRegisters - Returns the maximum number of map registers which + may be allocated by the device driver. + +Return Value: + + A pointer to the requested adapter object or NULL if an adapter could not + be created. + +--*/ + +{ + PADAPTER_OBJECT adapterObject; + PVOID adapterBaseVa; + ULONG channelNumber; + ULONG controllerNumber; + DMA_EXTENDED_MODE extendedMode; + UCHAR adapterMode; + ULONG numberOfMapRegisters; + BOOLEAN useChannel; + ULONG maximumLength; + UCHAR DataByte; + + useChannel = TRUE; + + // + // Support for ISA local bus machines: + // If the driver is a Master but really does not want a channel since it + // is using the local bus DMA, just don't use an ISA channel. + // + + if (DeviceDescriptor->InterfaceType == Isa && + DeviceDescriptor->DmaChannel > 7) { + + useChannel = FALSE; + } + + // + // Limit the maximum length to 2 GB this is done so that the BYTES_TO_PAGES + // macro works correctly. + // + + maximumLength = DeviceDescriptor->MaximumLength & 0x7fffffff; + + // + // Channel 4 cannot be used since it is used for chaining. Return null if + // it is requested. + // + + if (DeviceDescriptor->DmaChannel == 4 && useChannel) { + return(NULL); + } + + // + // Determine the number of map registers required based on the maximum + // transfer length. Limit the maximum transfer to 64K. + // + +#define MAXIMUM_ISA_MAP_REGISTER (__64K >> PAGE_SHIFT) + + numberOfMapRegisters = BYTES_TO_PAGES(maximumLength) + 1; + numberOfMapRegisters = numberOfMapRegisters > MAXIMUM_ISA_MAP_REGISTER ? + MAXIMUM_ISA_MAP_REGISTER : numberOfMapRegisters; + + // + // Set the channel number number. + // + + channelNumber = DeviceDescriptor->DmaChannel & 0x03; + + // + // Set the adapter base address to the Base address register and controller + // number. + // + + if (!(DeviceDescriptor->DmaChannel & 0x04)) { + + controllerNumber = 1; + adapterBaseVa = (PVOID) &((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort; + + } else { + + controllerNumber = 2; + adapterBaseVa = &((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort; + + } + + // + // Determine if a new adapter object is necessary. If so then allocate it. + // + + if (useChannel && HalpEisaAdapter[DeviceDescriptor->DmaChannel] != NULL) { + + adapterObject = HalpEisaAdapter[DeviceDescriptor->DmaChannel]; + + if (numberOfMapRegisters > adapterObject->MapRegistersPerChannel) { + adapterObject->MapRegistersPerChannel = numberOfMapRegisters; + } + + } else { + + // + // Allocate an adapter object. + // + + adapterObject = HalpAllocateAdapter(); + + if (adapterObject == NULL) { + return(NULL); + } + + if (useChannel == TRUE) { + HalpEisaAdapter[DeviceDescriptor->DmaChannel] = adapterObject; + } + + // + // Set the maximum number of map registers for this channel bus on + // the number requested and the type of device. + // + + adapterObject->MapRegistersPerChannel = numberOfMapRegisters; + + // + // Establish the base va used to program the DMA controller. + // + + adapterObject->AdapterBaseVa = adapterBaseVa; + + } + + *NumberOfMapRegisters = adapterObject->MapRegistersPerChannel; + + if (DeviceDescriptor->Master) { + adapterObject->MasterDevice = TRUE; + } else { + adapterObject->MasterDevice = FALSE; + } + + // + // If the channel number is not used then we are finished. The rest of + // the work deals with channels. + // + + if (useChannel == FALSE) { + return(adapterObject); + } + + // + // Setup the pointers to all the random registers. + // + + adapterObject->ChannelNumber = (UCHAR) channelNumber; + + if (controllerNumber == 1) { + + switch ((UCHAR)channelNumber) { + + case 0: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel0; + break; + + case 1: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel1; + break; + + case 2: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel2; + break; + + case 3: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel3; + break; + } + + // + // Set the adapter number. + // + + adapterObject->AdapterNumber = 1; + + // + // Save the extended mode register address. + // + + adapterBaseVa = + &((PEISA_CONTROL) HalpEisaControlBase)->Dma1ExtendedModePort; + + } else { + + switch (channelNumber) { + case 1: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel5; + break; + + case 2: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel6; + break; + + case 3: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel7; + break; + } + + // + // Set the adapter number. + // + + adapterObject->AdapterNumber = 2; + + // + // Save the extended mode register address. + // + adapterBaseVa = + &((PEISA_CONTROL) HalpEisaControlBase)->Dma2ExtendedModePort; + + } + + + adapterObject->Width16Bits = FALSE; + + if (HalpEisaDma) { + + // + // Initialzie the extended mode port. + // + + *((PUCHAR) &extendedMode) = 0; + extendedMode.ChannelNumber = (UCHAR)channelNumber; + + switch (DeviceDescriptor->DmaSpeed) { + case Compatible: + extendedMode.TimingMode = COMPATIBLITY_TIMING; + break; + + case TypeA: + extendedMode.TimingMode = TYPE_A_TIMING; + break; + + case TypeB: + extendedMode.TimingMode = TYPE_B_TIMING; + break; + + case TypeC: + extendedMode.TimingMode = BURST_TIMING; + break; + + default: + ObDereferenceObject( adapterObject ); + return(NULL); + + } + + switch (DeviceDescriptor->DmaWidth) { + case Width8Bits: + extendedMode.TransferSize = BY_BYTE_8_BITS; + break; + + case Width16Bits: + extendedMode.TransferSize = BY_BYTE_16_BITS; + + // + // Note Width16bits should not be set here because there is no need + // to shift the address and the transfer count. + // + + break; + + case Width32Bits: + extendedMode.TransferSize = BY_BYTE_32_BITS; + break; + + default: + ObDereferenceObject( adapterObject ); + return(NULL); + + } + + // + // Save the extended mode in the adapter. + // Then write the extended mode value for this channel. + // + + adapterObject->ExtendedMode = *((PDMA_EXTENDED_MODE)&extendedMode); + + WRITE_PORT_UCHAR( adapterBaseVa, *((PUCHAR) &extendedMode)); + + } else if (DeviceDescriptor->Master == FALSE) { + + + switch (DeviceDescriptor->DmaWidth) { + case Width8Bits: + + // + // The channel must use controller 1. + // + + if (controllerNumber != 1) { + ObDereferenceObject( adapterObject ); + return(NULL); + } + + break; + + case Width16Bits: + + // + // The channel must use controller 2. + // + + if (controllerNumber != 2) { + ObDereferenceObject( adapterObject ); + return(NULL); + } + + adapterObject->Width16Bits = TRUE; + break; + + default: + ObDereferenceObject( adapterObject ); + return(NULL); + + } + } + + // + // Initialize the adapter mode register value to the correct parameters, + // and save them in the adapter object. + // + + adapterMode = 0; + ((PDMA_EISA_MODE) &adapterMode)->Channel = adapterObject->ChannelNumber; + + if (DeviceDescriptor->Master) { + + ((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE; + + // + // Set the mode, and enable the request. + // + + if (adapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = adapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode ); + + // + // Unmask the DMA channel. + // + + WRITE_PORT_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber) + ); + + } else { + + // + // This request is for DMA controller 1 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = adapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode ); + + // + // Unmask the DMA channel. + // + + WRITE_PORT_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber) + ); + + } + + } else if (DeviceDescriptor->DemandMode) { + + ((PDMA_EISA_MODE) &adapterMode)->RequestMode = DEMAND_REQUEST_MODE; + + } else { + + ((PDMA_EISA_MODE) &adapterMode)->RequestMode = SINGLE_REQUEST_MODE; + + } + + if (DeviceDescriptor->AutoInitialize) { + + ((PDMA_EISA_MODE) &adapterMode)->AutoInitialize = 1; + + } + + adapterObject->AdapterMode = adapterMode; + + return(adapterObject); +} + +BOOLEAN +HalpMapEisaTransfer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG LogicalAddress, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) + +/*++ + +Routine Description: + + This routine is invoked to perform the actual programming of the + DMA controllers to perform a transfer for Eisa/Isa systems. + +Arguments: + + AdapterObject - Pointer to the adapter object representing the DMA + controller channel that has been allocated. + + Mdl - Pointer to the MDL that describes the pages of memory that are + being read or written. + + MapRegisterBase - The address of the base map register that has been + allocated to the device driver for use in mapping the transfer. + + CurrentVa - Current virtual address in the buffer described by the MDL + that the transfer is being done to or from. + + Length - Supplies the length of the transfer. This determines the + number of map registers that need to be written to map the transfer. + Returns the length of the transfer which was actually mapped. + + WriteToDevice - Boolean value that indicates whether this is a write + to the device from memory (TRUE), or vice versa. + + LogicalAddress - Supplies the logical address of the transfer. + +Return Value: + + Returns a boolean identifying if the operation was successful. + +--*/ + +{ + KIRQL Irql; + UCHAR adapterMode; + PUCHAR bytePointer; + UCHAR dataByte; + ULONG logicalAddress; + ULONG transferLength; + + logicalAddress = LogicalAddress; + transferLength = Length; + + // + // Determine the mode based on the transfer direction. + // + + adapterMode = AdapterObject->AdapterMode; + ((PDMA_EISA_MODE) &adapterMode)->TransferType = (UCHAR) (WriteToDevice ? + WRITE_TRANSFER : READ_TRANSFER); + + bytePointer = (PUCHAR) &logicalAddress; + + // + // Check to see if this request is for a master I/O card. + // + +//jnfix - this code not in Jensen + if( ((PDMA_EISA_MODE)&adapterMode)->RequestMode == CASCADE_REQUEST_MODE) { + + // + // Set the mode, disable the request and return. + // + + if( AdapterObject->AdapterNumber == 1 ){ + + // + // Request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); + + // + // Unmask the DMA channel. + // + + WRITE_REGISTER_UCHAR( &dmaControl->SingleMask, + (UCHAR)(DMA_CLEARMASK | AdapterObject->ChannelNumber) ); + + } else { + + // + // Request is for DMA controller 2 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); + + // + // Unmask the DMA channel. + // + + WRITE_REGISTER_UCHAR( &dmaControl->SingleMask, + (UCHAR)(DMA_CLEARMASK | AdapterObject->ChannelNumber) ); + + } + + return TRUE; + + } + + if (AdapterObject->Width16Bits) { + + // + // If this is a 16 bit transfer then adjust the length and the address + // for the 16 bit DMA mode. + // + + transferLength >>= 1; + + } + + // + // Grab the spinlock for the system DMA controller. + // + + KeAcquireSpinLock( &AdapterObject->MapAdapter->SpinLock, &Irql ); + + // + // Determine the controller number based on the Adapter number. + // + + if (AdapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode ); + + WRITE_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + bytePointer[0] + ); + + WRITE_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + bytePointer[1] + ); + + WRITE_PORT_UCHAR( + ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) + + (ULONG)AdapterObject->PagePort, + bytePointer[2] + ); + + if (HalpEisaDma) { + + // + // Write the high page register with zero value. This enable a + // special mode which allows ties the page register and base + // count into a single 24 bit address register. + // + + WRITE_PORT_UCHAR( + ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) + + (ULONG)AdapterObject->PagePort, + 0 + ); + } + + // + // Notify DMA chip of the length to transfer. + // + + WRITE_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((transferLength - 1) & 0xff) + ); + + WRITE_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((transferLength - 1) >> 8) + ); + + + // + // Set the DMA chip to read or write mode; and unmask it. + // + + WRITE_PORT_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber) + ); + + } else { + + // + // This request is for DMA controller 2 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode ); + + WRITE_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + bytePointer[0] + ); + + WRITE_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + bytePointer[1] + ); + + WRITE_PORT_UCHAR( + ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) + + (ULONG)AdapterObject->PagePort, + bytePointer[2] + ); + + if (HalpEisaDma) { + + // + // Write the high page register with zero value. This enable + // a special mode which allows ties the page register and base + // count into a single 24 bit address register. + // + + WRITE_PORT_UCHAR( + ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) + + (ULONG)AdapterObject->PagePort, + 0 + ); + } + + // + // Notify DMA chip of the length to transfer. + // + + WRITE_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((transferLength - 1) & 0xff) + ); + + WRITE_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((transferLength - 1) >> 8) + ); + + + // + // Set the DMA chip to read or write mode; and unmask it. + // + + WRITE_PORT_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber) + ); + + } + + KeReleaseSpinLock (&AdapterObject->MapAdapter->SpinLock, Irql); + + return TRUE; +} + + +BOOLEAN +HalpFlushEisaAdapter( + IN PADAPTER_OBJECT AdapterObject, + IN PMDL Mdl, + IN PVOID MapRegisterBase, + IN PVOID CurrentVa, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) + +/*++ + +Routine Description: + + This routine flushes the DMA adapter object buffers. For EISA systems + its clears the enable flag which aborts the dma. + +Arguments: + + AdapterObject - Pointer to the adapter object representing the DMA + controller channel. + + Mdl - A pointer to a Memory Descriptor List (MDL) that maps the locked-down + buffer to/from which the I/O occured. + + MapRegisterBase - A pointer to the base of the map registers in the adapter + or DMA controller. + + CurrentVa - The current virtual address in the buffer described the the Mdl + where the I/O operation occurred. + + Length - Supplies the length of the transfer. + + WriteToDevice - Supplies a BOOLEAN value that indicates the direction of + the data transfer was to the device. + +Return Value: + + TRUE - If the transfer was successful. + + FALSE - If there was an error in the transfer. + +--*/ +{ + + BOOLEAN masterDevice; + KIRQL Irql; + + masterDevice = AdapterObject->MasterDevice; + + KeAcquireSpinLock( &AdapterObject->MapAdapter->SpinLock, &Irql ); + + // + // If this is a slave device, then stop the DMA controller. + // + + if (masterDevice == FALSE) { + + // + // Mask the DMA request line so that DMA requests cannot occur. + // + + if (AdapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber) + ); + + } else { + + // + // This request is for DMA controller 2 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber) + ); + + } + + } + + KeReleaseSpinLock( &AdapterObject->MapAdapter->SpinLock, Irql ); + + return TRUE; + +} + +ULONG +HalpReadEisaDmaCounter( + IN PADAPTER_OBJECT AdapterObject + ) +/*++ + +Routine Description: + + This function reads the DMA counter and returns the number of bytes left + to be transfered. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object to be read. + +Return Value: + + Returns the number of bytes still be be transfered. + +--*/ + +{ + + ULONG count; + ULONG high; + KIRQL Irql; + + // + // Grab the spinlock for the system DMA controller. + // + + KeAcquireSpinLock( &AdapterObject->MapAdapter->SpinLock, &Irql ); + + // + // Determine the controller number based on the Adapter number. + // + + if (AdapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + + // + // Initialize count to a value which will not match. + // + + count = 0xFFFF00; + + // + // Loop until the same high byte is read twice. + // + + do { + + high = count; + + WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + // + // Read the current DMA count. + // + + count = READ_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount + ); + + count |= READ_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount + ) << 8; + + } while ((count & 0xFFFF00) != (high & 0xFFFF00)); + + } else { + + // + // This request is for DMA controller 2 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + // + // Initialize count to a value which will not match. + // + + count = 0xFFFF00; + + // + // Loop until the same high byte is read twice. + // + + do { + + high = count; + + WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + // + // Read the current DMA count. + // + + count = READ_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount + ); + + count |= READ_PORT_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount + ) << 8; + + } while ((count & 0xFFFF00) != (high & 0xFFFF00)); + + + } + + // + // Release the spinlock for the system DMA controller. + // + + KeReleaseSpinLock( &AdapterObject->MapAdapter->SpinLock, Irql ); + + // + // The DMA counter has a bias of one and can only be 16 bit long. + // + + count = (count + 1) & 0xFFFF; + + // + // If this is a 16 bit dma the multiply the count by 2. + // + + if (AdapterObject->Width16Bits) { + + count *= 2; + + } + + return(count); + +} + +#if !defined(AXP_FIRMWARE) + +ULONG +HalpGetEisaData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ) +/*++ + +Routine Description: + + The function returns the Eisa bus data for a slot or address. + +Arguments: + + + BusHandler - Registered BUSHANDLER for the target configuration space + + RootHandler - Registered BUSHANDLER for the orginating HalGetBusData + request. + + Buffer - Supplies the space to store the data. + + Offset - Supplies the offset into data to begin access. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + +--*/ +{ + OBJECT_ATTRIBUTES ObjectAttributes; + OBJECT_ATTRIBUTES BusObjectAttributes; + PWSTR EisaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\EisaAdapter"; + PWSTR ConfigData = L"Configuration Data"; + ANSI_STRING TmpString; + ULONG BusNumber; + UCHAR BusString[] = "00"; + UNICODE_STRING RootName, BusName; + UNICODE_STRING ConfigDataName; + NTSTATUS NtStatus; + PKEY_VALUE_FULL_INFORMATION ValueInformation; + PCM_FULL_RESOURCE_DESCRIPTOR Descriptor; + PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResource; + PCM_EISA_SLOT_INFORMATION SlotInformation; + ULONG PartialCount; + ULONG TotalDataSize, SlotDataSize; + HANDLE EisaHandle, BusHandle; + ULONG BytesWritten, BytesNeeded; + PUCHAR KeyValueBuffer; + ULONG i; + ULONG DataLength = 0; + PUCHAR DataBuffer = Buffer; + BOOLEAN Found = FALSE; + + UNREFERENCED_PARAMETER( RootHandler ); + + RtlInitUnicodeString( + &RootName, + EisaPath + ); + + InitializeObjectAttributes( + &ObjectAttributes, + &RootName, + OBJ_CASE_INSENSITIVE, + (HANDLE)NULL, + NULL + ); + + // + // Open the EISA root + // + + NtStatus = ZwOpenKey( + &EisaHandle, + KEY_READ, + &ObjectAttributes + ); + + if (!NT_SUCCESS(NtStatus)) { +#if DBG + DbgPrint("HAL: Open Status = %x\n",NtStatus); +#endif + return(0); + } + + // + // Init bus number path + // + + BusNumber = BusHandler->BusNumber; + + if (BusNumber > 99) { + return (0); + } + + if (BusNumber > 9) { + BusString[0] += (UCHAR) (BusNumber/10); + BusString[1] += (UCHAR) (BusNumber % 10); + } else { + BusString[0] += (UCHAR) BusNumber; + BusString[1] = '\0'; + } + + RtlInitAnsiString( + &TmpString, + BusString + ); + + RtlAnsiStringToUnicodeString( + &BusName, + &TmpString, + TRUE + ); + + + InitializeObjectAttributes( + &BusObjectAttributes, + &BusName, + OBJ_CASE_INSENSITIVE, + (HANDLE)EisaHandle, + NULL + ); + + // + // Open the EISA root + Bus Number + // + + NtStatus = ZwOpenKey( + &BusHandle, + KEY_READ, + &BusObjectAttributes + ); + + if (!NT_SUCCESS(NtStatus)) { +#if DBG + DbgPrint("HAL: Opening Bus Number: Status = %x\n",NtStatus); +#endif + return(0); + } + + // + // opening the configuration data. This first call tells us how + // much memory we need to allocate + // + + RtlInitUnicodeString( + &ConfigDataName, + ConfigData + ); + + // + // This should fail. We need to make this call so we can + // get the actual size of the buffer to allocate. + // + + ValueInformation = (PKEY_VALUE_FULL_INFORMATION) &i; + NtStatus = ZwQueryValueKey( + BusHandle, + &ConfigDataName, + KeyValueFullInformation, + ValueInformation, + 0, + &BytesNeeded + ); + + KeyValueBuffer = ExAllocatePool( + NonPagedPool, + BytesNeeded + ); + + if (KeyValueBuffer == NULL) { +#if DBG + DbgPrint("HAL: Cannot allocate Key Value Buffer\n"); +#endif + ZwClose(BusHandle); + return(0); + } + + ValueInformation = (PKEY_VALUE_FULL_INFORMATION)KeyValueBuffer; + + NtStatus = ZwQueryValueKey( + BusHandle, + &ConfigDataName, + KeyValueFullInformation, + ValueInformation, + BytesNeeded, + &BytesWritten + ); + + + ZwClose(BusHandle); + + if (!NT_SUCCESS(NtStatus) || ValueInformation->DataLength == 0) { +#if DBG + DbgPrint("HAL: Query Config Data: Status = %x\n",NtStatus); +#endif + ExFreePool(KeyValueBuffer); + return(0); + } + + + // + // We get back a Full Resource Descriptor List + // + + Descriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)ValueInformation + + ValueInformation->DataOffset); + + PartialResource = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) + &(Descriptor->PartialResourceList.PartialDescriptors); + PartialCount = Descriptor->PartialResourceList.Count; + + for (i = 0; i < PartialCount; i++) { + + // + // Do each partial Resource + // + + switch (PartialResource->Type) { + case CmResourceTypeNull: + case CmResourceTypePort: + case CmResourceTypeInterrupt: + case CmResourceTypeMemory: + case CmResourceTypeDma: + + // + // We dont care about these. + // + + PartialResource++; + + break; + + case CmResourceTypeDeviceSpecific: + + // + // Bingo! + // + + TotalDataSize = PartialResource->u.DeviceSpecificData.DataSize; + + SlotInformation = (PCM_EISA_SLOT_INFORMATION) + ((PUCHAR)PartialResource + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); + + while (((LONG)TotalDataSize) > 0) { + + if (SlotInformation->ReturnCode == EISA_EMPTY_SLOT) { + + SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION); + + } else { + + SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION) + + SlotInformation->NumberFunctions * + sizeof(CM_EISA_FUNCTION_INFORMATION); + } + + if (SlotDataSize > TotalDataSize) { + + // + // Something is wrong again + // + + ExFreePool(KeyValueBuffer); + return(0); + + } + + if (SlotNumber != 0) { + + SlotNumber--; + + SlotInformation = (PCM_EISA_SLOT_INFORMATION) + ((PUCHAR)SlotInformation + SlotDataSize); + + TotalDataSize -= SlotDataSize; + + continue; + + } + + // + // This is our slot + // + + Found = TRUE; + break; + + } + + // + // End loop + // + + i = PartialCount; + + break; + + default: + +#if DBG + DbgPrint("Bad Data in registry!\n"); +#endif + + ExFreePool(KeyValueBuffer); + return(0); + + } + + } + + if (Found) { + + i = Length + Offset; + if (i > SlotDataSize) { + i = SlotDataSize; + } + + DataLength = i - Offset; + RtlMoveMemory (Buffer, ((PUCHAR)SlotInformation + Offset), DataLength); + + } + + ExFreePool(KeyValueBuffer); + return DataLength; +} + + +NTSTATUS +HalpAdjustEisaResourceList ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ) +/*++ + +Routine Description: + + The function adjusts pResourceList to keep it in the bounds of the EISA bus + resources. + +Arguments: + + BusHandler - Registered BUSHANDLER for the target configuration space + + RootHandler - Register BUSHANDLER for the orginating HalAdjustResourceList request. + + pResourceList - Supplies the PIO_RESOURCE_REQUIREMENTS_LIST to be checked. + +Return Value: + + STATUS_SUCCESS + +--*/ +{ + LARGE_INTEGER li64k, li4g; + + li64k.QuadPart = 0xffff; + li4g.QuadPart = 0xffffffff; + + HalpAdjustResourceListUpperLimits ( + pResourceList, + li64k, // Bus supports up to I/O port 0xFFFF + li4g, // Bus supports up to memory 0xFFFFFFFF + 15, // Bus supports up to 15 IRQs + 7 // Bus supports up to Dma channel 7 + ); + + return STATUS_SUCCESS; +} + +NTSTATUS +HalpAdjustIsaResourceList ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ) +/*++ + +Routine Description: + + The function adjusts pResourceList to keep it in the bounds of ISA bus + resources. + +Arguments: + + BusHandler - Registered BUSHANDLER for the target configuration space + + RootHandler - Register BUSHANDLER for the orginating HalAdjustResourceList request. + + pResourceList - Supplies the PIO_RESOURCE_REQUIREMENTS_LIST to be checked. + +Return Value: + + STATUS_SUCCESS + +--*/ +{ + LARGE_INTEGER li64k, limem; + + li64k.QuadPart = 0xffff; + limem.QuadPart = 0xffffff; + + HalpAdjustResourceListUpperLimits ( + pResourceList, + li64k, // Bus supports up to I/O port 0xFFFF + limem, // Bus supports up to memory 0xFFFFFF + 15, // Bus supports up to 15 IRQs + 7 // Bus supports up to Dma channel 7 + ); + + return STATUS_SUCCESS; +} +#endif // AXP_FIRMWARE diff --git a/private/ntos/nthals/halalpha/environ.c b/private/ntos/nthals/halalpha/environ.c new file mode 100644 index 000000000..3831214a5 --- /dev/null +++ b/private/ntos/nthals/halalpha/environ.c @@ -0,0 +1,952 @@ +//smjfix - This code needs to be made MP safe if it isn't being called +// by MP safe code. +//jwlfix - It's currently being called by the kernel (ex, actually) in +// an MP-safe fashion, and by config during phase 1 (?) of +// bootstrapping the system. + +/*++ + +Copyright (c) 1991 Microsoft Corporation +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + environ.c + +Abstract: + + This module implements the ARC firmware Environment Variable functions as + described in the Advanced Risc Computing Specification (Revision 1.00), + section 3.3.3.11. + +Author: + + David M. Robinson (davidro) 13-June-1991 + + +Revision History: + + James Livingston 94.05.17 + + Fix a coding error that caused NVRAM to get trashed in the attempt + to update a nearly full environment variable space. + + Steve Jenness 93.12.20 + + The firmware still requires the naked checksum set and check + routines. Add them back in under the AXP_FIRMWARE conditional + until the jxenvir.c in the firmware and the environ.c files + are rationalized. + + Steve Jenness. 93.12.17 + + Reduce the reads and writes to the NVRAM part. Some parts are + slow to access (especially on writes). Do NVRAM access only when + really necessary. Remove use of HalpCopyNVRamBuffer because it is + too difficult to make generically fast (put more intelligence + in higher code instead). + + Steve Brooks. 6-Oct 1993 remove all platform and device specific references + + These routines have been restructured to be platform and device + independant. All calls access the NVRAM via the calls + HalpReadNVRamBuffer, HalpWriteNVRamBuffer, and HalpCopyNVRamBuffer + + Jeff McLeman (DEC) 31-Jul-1992 modify for Jensen + +--*/ + +#include "halp.h" +#include "environ.h" + +#include "arccodes.h" + +// +// Static data. +// + +UCHAR Environment[LENGTH_OF_ENVIRONMENT]; +ULONG EnvironmentChecksum; +BOOLEAN EnvironmentValid = FALSE; + +UCHAR OutputString[MAXIMUM_ENVIRONMENT_VALUE]; +PCONFIGURATION Configuration; + +// +// Routine prototypes. +// + +ARC_STATUS +HalpReadAndChecksumEnvironment ( + ); + +ARC_STATUS +HalpWriteAndChecksumEnvironment ( + ); + +ARC_STATUS +HalGetEnvironmentVariable ( + IN PCHAR Variable, + IN USHORT length, + OUT PCHAR Buffer + ); + +ARC_STATUS +HalSetEnvironmentVariable ( + IN PCHAR Variable, + IN PCHAR Value + ); + +ARC_STATUS +HalpFindEnvironmentVariable ( + IN PCHAR Variable, + OUT PULONG VariableIndex, + OUT PULONG ValueIndex + ); + +#if defined(AXP_FIRMWARE) + +ARC_STATUS +HalpEnvironmentCheckChecksum ( + VOID + ); + +ARC_STATUS +HalpEnvironmentSetChecksum ( + VOID + ); + +#endif //AXP_FIRMWARE + +#ifdef AXP_FIRMWARE + +#pragma alloc_text(DISTEXT, HalpReadAndChecksumEnvironment ) +#pragma alloc_text(DISTEXT, HalpWriteAndChecksumEnvironment ) +#pragma alloc_text(DISTEXT, HalGetEnvironmentVariable ) +#pragma alloc_text(DISTEXT, HalSetEnvironmentVariable ) +#pragma alloc_text(DISTEXT, HalpFindEnvironmentVariable ) +#pragma alloc_text(DISTEXT, HalpEnvironmentCheckChecksum ) +#pragma alloc_text(DISTEXT, HalpEnvironmentSetChecksum ) + +#endif // AXP_FIRMWARE + + +ARC_STATUS +HalpReadAndChecksumEnvironment( + ) + +/*++ + +Routine Description: + + This routine reads the part of the NVRAM containing the environment + variables into a memory buffer. It checksums the data as read. + +Arguments: + + None. + +Return Value: + + ESUCCESS - checksum is good. + EIO - checksum is bad. + +--*/ + +{ + PUCHAR BufChar; + ULONG Index; + ULONG Checksum1, Checksum2; + +#ifndef EISA_PLATFORM + UCHAR Nvram[LENGTH_OF_ENVIRONMENT+16]; +#endif // EISA_PLATFORM + + // + // Read checksum of environment data from the NVRAM. + // For non eisa machines we have only one checksum for the whole nvram. + // And it is stored in Checksum + // + + HalpReadNVRamBuffer( + (PUCHAR)&Checksum2, +#ifdef EISA_PLATFORM + &((PNV_CONFIGURATION)NVRAM_CONFIGURATION)->Checksum2[0], +#else // EISA_PLATFORM + &((PNV_CONFIGURATION)NVRAM_CONFIGURATION)->Checksum[0], +#endif // EISA_PLATFORM + 4); + + // + // If the environment data stored in the buffer is already valid, + // short-circuit the NVRAM read. + // + + if (EnvironmentValid == TRUE) { + if (Checksum2 == EnvironmentChecksum) { + return ESUCCESS; + } + } + +#ifdef EISA_PLATFORM + // + // Read the NVRAM environment data into the buffer. + // + + HalpReadNVRamBuffer( + &Environment[0], + &((PNV_CONFIGURATION)NVRAM_CONFIGURATION)->Environment[0], + LENGTH_OF_ENVIRONMENT); + + // + // Form checksum of data read from NVRAM. + // + + BufChar = &Environment[0]; + Checksum1 = 0; + for ( Index = 0 ; Index < LENGTH_OF_ENVIRONMENT; Index++ ) { + Checksum1 += *BufChar++; + } + + if (Checksum1 != Checksum2) { + return EIO; + } else { + EnvironmentValid = TRUE; + EnvironmentChecksum = Checksum1; + return ESUCCESS; + } +#else // EISA_PLATFORM + + // + // Read the NVRAM into Nvram. + // + + HalpReadNVRamBuffer( &Nvram[0], + NVRAM_CONFIGURATION, + LENGTH_OF_ENVIRONMENT + 16 ); + + // + // Form checksum of data read from NVRAM. + // + + BufChar = &Nvram[0]; + Checksum1 = 0; + for ( Index = 0 ; Index < LENGTH_OF_ENVIRONMENT+16; Index++ ) { + Checksum1 += *BufChar++; + } + + if (Checksum1 != Checksum2) { + return EIO; + } else { + EnvironmentValid = TRUE; + EnvironmentChecksum = Checksum1; + + // + // Nvram checksum was ok. Save the read Environment part of NVRAM + // in global Environment[]. + // + BufChar = &Environment[0]; + for( Index = 16; Index < LENGTH_OF_ENVIRONMENT+16; Index++ ) { + *BufChar++ = Nvram[Index]; + } + + return ESUCCESS; + } +#endif // EISA_PLATFORM +} + + +ARC_STATUS +HalpWriteAndChecksumEnvironment ( + ) + +/*++ + +Routine Description: + + This routine writes the environment data back to the NVRAM, calculates + a new checksum, and stores the checksum. + + N.B. - For this method of rewriting the environment variables to be + effective (minimal NVRAM access and quick overall), the + HalpWriteNVRamBuffer is assumed to do block access and to + suppress writes it doesn't need to do. + + N.B. - To allow the HalpWriteNVRamBuffer to suppress writes, the new data + should have as many bytes in common with the current NVRAM + contents as possible. For example, the environment variables + should not be reordered unless needed. + +Arguments: + + None. + +Return Value: + + ESUCCESS - NVRAM write succeeded. + EIO - NVRAM write failed. + +--*/ + +{ + ULONG Index; + ULONG Checksum; + KIRQL OldIrql; + PUCHAR BufChar; + + KeRaiseIrql(DEVICE_LEVEL, &OldIrql); + + // + // Form checksum from new NVRAM data. + // + + Checksum = 0; + + BufChar = &Environment[0]; + for ( Index = 0 ; Index < LENGTH_OF_ENVIRONMENT; Index++ ) { + Checksum += *BufChar++; + } + +#ifndef EISA_PLATFORM + { + UCHAR TempBuffer[16]; + HalpReadNVRamBuffer( TempBuffer, (PUCHAR)NVRAM_CONFIGURATION, 16 ); + for ( Index = 0 ; Index < 16; Index++ ) { + Checksum += TempBuffer[ Index ]; + } + } +#endif // !EISA_PLATFORM + + // + // Write environment variables to NVRAM. + // + + HalpWriteNVRamBuffer( + &((PNV_CONFIGURATION)NVRAM_CONFIGURATION)->Environment[0], + &Environment[0], + LENGTH_OF_ENVIRONMENT); + + // + // Write environment checksum. + // + + HalpWriteNVRamBuffer( +#ifdef EISA_PLATFORM + &((PNV_CONFIGURATION)NVRAM_CONFIGURATION)->Checksum2[0], +#else // EISA_PLATFORM + &((PNV_CONFIGURATION)NVRAM_CONFIGURATION)->Checksum[0], +#endif // EISA_PLATFORM + (PUCHAR)&Checksum, + 4); + + EnvironmentChecksum = Checksum; + EnvironmentValid = TRUE; + + KeLowerIrql(OldIrql); + + return ESUCCESS; +} + + +ARC_STATUS +HalGetEnvironmentVariable ( + IN PCHAR Variable, + IN USHORT length, + OUT PCHAR Buffer + ) + +/*++ + +Routine Description: + + This routine searches (not case sensitive) the non-volatile ram for + Variable, and if found returns a pointer to a zero terminated string that + contains the value, otherwise a NULL pointer is returned. + + +Arguments: + + Variable - Supplies a zero terminated string containing an environment + variable. + Length - Supplies the length of the value buffer in bytes + + Buffer - Supplies a pointer to a buffer that will recieve the + environment variable. + +Return Value: + + ESUCCESS - Buffer contains the zero terminated string value of Variable. + ENOENT - The variable doesn't exist in the environment. + ENOMEM - The variable exists, but the value is longer than Length. + +--*/ + +{ + PUCHAR NvChars; + ULONG VariableIndex; + ULONG ValueIndex; + ULONG Index; + ARC_STATUS Status; + KIRQL OldIrql; + + // + // Raise IRQL to synchronize + // + + KeRaiseIrql(DEVICE_LEVEL, &OldIrql); + + // + // If checksum is wrong, or the variable can't be found, return NULL. + // + + if ((HalpReadAndChecksumEnvironment() != ESUCCESS) || + (HalpFindEnvironmentVariable(Variable, + &VariableIndex, + &ValueIndex) != ESUCCESS)) { + Status = ENOENT; + } else { + + // + // Copy value to an output string, break on zero terminator + // or string max. + // + + NvChars = &Environment[ValueIndex]; + for ( Index = 0 ; Index < length ; Index += 1 ) { + if ( (*Buffer++ = *NvChars++) == 0 ) { + break; + } + } + + if (Index == length) { + Status = ENOMEM; + } else { + Status = ESUCCESS; + } + } + + // + // Lower IRQL back to where it was + // + + KeLowerIrql(OldIrql); + + return Status; +} + + +ARC_STATUS +HalSetEnvironmentVariable ( + IN PCHAR Variable, + IN PCHAR Value + ) + +/*++ + +Routine Description: + + This routine sets Variable (not case sensitive) to Value. + +Arguments: + + Variable - Supplies a zero terminated string containing an environment + variable. + + Value - Supplies a zero terminated string containing an environment + variable value. + +Return Value: + + ESUCCESS - The set completed successfully + ENOSPC - No space in NVRAM for set operation. + EIO - Invalid Checksum. + +--*/ + +{ + ULONG VariableIndex; + ULONG ValueIndex; + PUCHAR TopOfEnvironment; + PCHAR String; + PUCHAR NvChars; + LONG Count; + CHAR Char; + KIRQL OldIrql; + + // + // Raise Irql to Synchronize + // + + KeRaiseIrql(DEVICE_LEVEL, &OldIrql); + + // + // If checksum is wrong, return EIO; + // + + if (HalpReadAndChecksumEnvironment() != ESUCCESS) { + KeLowerIrql(OldIrql); + return EIO; + } + +// +//smjfix - examine the boundary condition where the environment space +// is exactly filled. + + // + // Determine the top of the environment space by looking for the first + // non-null character from the top. + // + + TopOfEnvironment = &Environment[LENGTH_OF_ENVIRONMENT-1]; + + do { + Char = *TopOfEnvironment; + + } while ( Char == 0 && (--TopOfEnvironment > Environment) ); + + // + // Adjust TopOfEnvironment to the first new character, unless environment + // space is empty, or the environment is exactly full. In the latter + // case, the new value MUST fit into the space taken by the old. + // + + if (TopOfEnvironment != Environment + && TopOfEnvironment < &Environment[LENGTH_OF_ENVIRONMENT-2]) { + TopOfEnvironment += 2; + } + + // + // Handle the case where the content of the NVRAM has been corrupted + // such that the last character in the environment is non-zero. + // + + Count = &Environment[LENGTH_OF_ENVIRONMENT-1] - TopOfEnvironment; + if (Count < 0) { + KeLowerIrql(OldIrql); + return ENOSPC; + } + + + // + // Check to see if the variable already has a value. + // + + if (HalpFindEnvironmentVariable(Variable, &VariableIndex, &ValueIndex) + == ESUCCESS) { + ULONG SizeOfValue = strlen(Value); + + if (SizeOfValue == strlen(&Environment[ValueIndex])) { + + // + // Overwrite the current variable in place. + // + + RtlMoveMemory(&Environment[ValueIndex], + Value, + SizeOfValue); + // + // Suppress the append of the variable to the end of the + // environment variable data. + // + + *Value = 0; + + } else { + + // + // Count free space, starting with the free area at the top and + // adding the old variable value. + // + + for ( NvChars = &Environment[ValueIndex]; + NvChars <= TopOfEnvironment; + NvChars++ ) { + + Char = *NvChars; + if ( Char == 0 ) + break; + Count++; + } + + // + // Determine if free area is large enough to handle new value, if + // not return error. + // + + for ( String = Value ; *String != 0 ; String++ ) { + if (Count-- == 0) { + KeLowerIrql(OldIrql); + return ENOSPC; + } + } + + // + // Move ValueIndex to the end of the value and compress strings. + // + + do { + Char = Environment[ValueIndex++]; + } while( Char != 0 ); + + Count = TopOfEnvironment - &Environment[ValueIndex]; + RtlMoveMemory(&Environment[VariableIndex], + &Environment[ValueIndex], + Count); + + // + // Adjust new top of environment. + // + + TopOfEnvironment = &Environment[VariableIndex+Count]; + + // + // Zero to the end. + // + + Count = &Environment[LENGTH_OF_ENVIRONMENT] - TopOfEnvironment; + Char = 0; + while ( Count -- ) { + TopOfEnvironment[Count] = Char; + } + } + + } else { + + // + // Variable is new. + // + + // + // Determine if free area is large enough to handle new value, if not + // return error. + // + + // + // From the length of free space subtract new variable's length, + // Value's length and 2 chars, one for the '=' sign and one of the + // null terminator. + // + + Count -= ( strlen(Variable) + strlen(Value) + 2 ); + + // + // Check if there is space to fit the new variable. + // + + if (Count < 0) { + KeLowerIrql(OldIrql); + return ENOSPC; + } + + } + + // + // If Value is not zero, append the new variable and value. + // + + if (*Value != 0) { + + // + // Write new variable, converting to upper case. + // + while ( *Variable != 0 ) { + + Char = ((*Variable >= 'a') && (*Variable <= 'z') ? + (*Variable - 'a' + 'A') : *Variable); + + *TopOfEnvironment = Char; + + Variable ++; + TopOfEnvironment ++; + } + + // + // Write equal sign. + // + + Char = '='; + *TopOfEnvironment++ = Char; + + // + // Write new value. + // + + for ( Count = 0; Value[Count] != 0; Count ++ ) + ; + + RtlMoveMemory(&TopOfEnvironment[0], Value, Count); + + } + + // + // Write the environment variables out to NVRAM and checksum it. + // + + if (HalpWriteAndChecksumEnvironment() != ESUCCESS) { + KeLowerIrql(OldIrql); + return EIO; + } + + // + // Lower Irql back to where it was + // + + KeLowerIrql(OldIrql); + + + return ESUCCESS; + +} + +ARC_STATUS +HalpFindEnvironmentVariable ( + IN PCHAR Variable, + OUT PULONG VariableIndex, + OUT PULONG ValueIndex + ) + +/*++ + +Routine Description: + + This routine searches (not case sensitive) the supplied NVRAM image + for the given Variable. + +Arguments: + + Variable - Supplies a zero terminated string containing an environment + variable. + VariableIndex - Returned byte offset into Environment of the + Variable if found. + ValueIndex - Returned byte offset into Environment of the + value of the Variable if found. + +Return Value: + + ESUCCESS - Variable found and indicies returned. + ENOENT - Variable not found. + +--*/ + +{ + PUCHAR String; + UCHAR Char; + ULONG Index; + + // + // If Variable is null, return immediately. + // + + if (*Variable == 0) { + return ENOENT; + } + + Index = 0; + + while (TRUE) { + + // + // Set string to beginning of Variable. + // + + String = Variable; + *VariableIndex = Index; + + // + // Search until the end of NVRAM. + // + + while ( Index < LENGTH_OF_ENVIRONMENT ) { + + // + // Convert to uppercase and break if mismatch. + // + + Char = Environment[Index]; + + if ( Char != ((*String >= 'a') && (*String <= 'z') ? + (*String - 'a' + 'A') : *String) ) { + break; + } + + String++; + Index++; + } + + if ( Index == LENGTH_OF_ENVIRONMENT ) + return ENOENT; + + // + // Check to see if we're at the end of the string and the variable, + // which means a match. + // + + Char = Environment[Index]; + if ((*String == 0) && (Char == '=')) { + *ValueIndex = ++Index; + return ESUCCESS; + } + + // + // Move index to the start of the next variable. + // + + do { + Char = Environment[Index++]; + + if (Index >= LENGTH_OF_ENVIRONMENT) { + return ENOENT; + } + + } while (Char != 0); + + } +} + +#if defined(AXP_FIRMWARE) + +ARC_STATUS +HalpEnvironmentCheckChecksum ( + VOID + ) + +/*++ + +Routine Description: + + This routine checks the environment area checksum. + + +Arguments: + + None. + +Return Value: + + If the checksum is good, ESUCCESS is returned, otherwise EIO is returned. + +--*/ + +{ + PUCHAR NvChars; + UCHAR Char; + PNV_CONFIGURATION NvConfiguration; + ULONG Index; + ULONG Checksum1, Checksum2; + BOOLEAN AllZeroBytes; + + NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION; + + // + // Form checksum from NVRAM data. + // + + Checksum1 = 0; + AllZeroBytes = TRUE; + NvChars = (PUCHAR)&NvConfiguration->Environment[0]; + + for ( Index = 0 ; Index < LENGTH_OF_ENVIRONMENT; Index++ ) { + + HalpReadNVRamBuffer(&Char,NvChars++,1); + Checksum1 += Char; + if (Char != 0) { + AllZeroBytes = FALSE; + } + } + + // + // Reconstitute checksum and return error if no compare. + // + +#ifdef EISA_PLATFORM + HalpReadNVRamBuffer((PCHAR)&Checksum2,&NvConfiguration->Checksum2[0],4); +#else // EISA_PLATFORM + HalpReadNVRamBuffer((PCHAR)&Checksum2,&NvConfiguration->Checksum[0],4); +#endif // EISA_PLATFORM + + // + // We return an error condition if the Checksum does not match the sum + // of all the protected bytes, *or* if all the protected bytes are zero. + // The latter check covers the condition of a completely zeroed NVRAM; + // such a condition would appear to have a valid checksum. + // + // We do not use a better checksum algorithm because the pain of + // orchestrating a change in the existing SRM consoles (which read our + // stored Nvram information for various purposes) has been deemed to be + // too high. + // + + if ((Checksum1 != Checksum2) || (AllZeroBytes == TRUE)) { + return EIO; + } else { + return ESUCCESS; + } +} + + +ARC_STATUS +HalpEnvironmentSetChecksum ( + VOID + ) + +/*++ + +Routine Description: + + This routine sets the environment area checksum. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + PUCHAR NvChars; + UCHAR Char; + PNV_CONFIGURATION NvConfiguration; + ULONG Index; + ULONG Checksum; + KIRQL OldIrql; + + NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION; + + // + // Form checksum from NVRAM data. + // + + Checksum = 0; + NvChars = (PUCHAR)&NvConfiguration->Environment[0]; + + KeRaiseIrql(DEVICE_LEVEL, &OldIrql); + + for ( Index = 0 ; Index < LENGTH_OF_ENVIRONMENT; Index++ ) { + HalpReadNVRamBuffer(&Char, NvChars ++, 1); + Checksum += Char; + } + + KeLowerIrql(OldIrql); + + // + // Write environment checksum. + // + + if ( +#ifdef EISA_PLATFORM + HalpWriteNVRamBuffer((PCHAR)NvConfiguration->Checksum2, (PCHAR)&Checksum, 4) +#else // EISA_PLATFORM + HalpWriteNVRamBuffer((PCHAR)NvConfiguration->Checksum, (PCHAR)&Checksum, 4) +#endif // EISA_PLATFORM + != ESUCCESS ) { + return EIO; + } else { + return ESUCCESS; + + } +} + +#endif //AXP_FIRMWARE diff --git a/private/ntos/nthals/halalpha/environ.h b/private/ntos/nthals/halalpha/environ.h new file mode 100644 index 000000000..8a1abc91c --- /dev/null +++ b/private/ntos/nthals/halalpha/environ.h @@ -0,0 +1,167 @@ +/*++ + +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + environ.h + +Abstract: + + This module contains definitions for environment variable support + under the HAL. (Parts taken from J. Derosa's FWP.H) + +Author: + + Jeff McLeman (DEC) 17-Sep-1992 + +Revision History: + +--*/ + + + +// +// Define the private configuration packet structure, which contains a +// configuration component as well as pointers to the component's parent, +// peer, child, and configuration data. +// + +typedef struct _CONFIGURATION_PACKET { + CONFIGURATION_COMPONENT Component; + struct _CONFIGURATION_PACKET *Parent; + struct _CONFIGURATION_PACKET *Peer; + struct _CONFIGURATION_PACKET *Child; + PVOID ConfigurationData; +} CONFIGURATION_PACKET, *PCONFIGURATION_PACKET; + +// +// The compressed configuration packet structure used to store configuration +// data in NVRAM. +// + +typedef struct _COMPRESSED_CONFIGURATION_PACKET { + UCHAR Parent; + UCHAR Class; + UCHAR Type; + UCHAR Flags; + ULONG Key; + UCHAR Version; + UCHAR Revision; + USHORT ConfigurationDataLength; + USHORT Identifier; + USHORT ConfigurationData; +} COMPRESSED_CONFIGURATION_PACKET, *PCOMPRESSED_CONFIGURATION_PACKET; + +// +// Defines for Identifier index. +// + +#define NO_CONFIGURATION_IDENTIFIER 0xFFFF + +#ifdef EISA_PLATFORM +// +// Defines for the non-volatile configuration tables. +// + +#define NV_NUMBER_OF_ENTRIES 40 +#define NV_LENGTH_OF_IDENTIFIER (1024 - (NV_NUMBER_OF_ENTRIES * 16) - 8) +#define NV_LENGTH_OF_DATA (2048 -16) +#define LENGTH_OF_ENVIRONMENT 1024 +#define LENGTH_OF_EISA_DATA 2044 + +#define MAXIMUM_ENVIRONMENT_VALUE 256 +#define MAX_NUMBER_OF_ENVIRONMENT_VARIABLES 40 + +// +// The non-volatile configuration table structure. +// + +typedef struct _NV_CONFIGURATION { + COMPRESSED_CONFIGURATION_PACKET Packet[NV_NUMBER_OF_ENTRIES]; // 0 to 640-4 + UCHAR Identifier[NV_LENGTH_OF_IDENTIFIER]; // 640 to (1K - 8 - 4) + ULONG Monitor; // 1K-8 + ULONG Floppy; // 1K-4 + ULONG Floppy2; // 1K + ULONG KeyboardType; // 1K+4 + UCHAR Data[NV_LENGTH_OF_DATA]; // Unused space 1K+8 to 3K-8-4 + UCHAR Checksum1[4]; // Data checksum 3K-8 + UCHAR Environment[LENGTH_OF_ENVIRONMENT]; // Env Variables 3K-4 to 4K-4-4 + UCHAR Checksum2[4]; // Env checksum 4K-4 + UCHAR EisaData[LENGTH_OF_EISA_DATA]; // Eisa Data (4K to 6K-4) + UCHAR Checksum3[4]; // EisaData checksum +} NV_CONFIGURATION, *PNV_CONFIGURATION; + +// +// Defines for the volatile configuration tables. +// smd - Increased the number of entries, length of Identifier and length +// of data. +// + +#define NUMBER_OF_ENTRIES 200 +#define LENGTH_OF_IDENTIFIER (3*1024) +#define LENGTH_OF_DATA 2048 + +// +// The volatile configuration table structure. +// + +typedef struct _CONFIGURATION { + CONFIGURATION_PACKET Packet[NUMBER_OF_ENTRIES]; + UCHAR Identifier[LENGTH_OF_IDENTIFIER]; + UCHAR Data[LENGTH_OF_DATA]; + UCHAR EisaData[LENGTH_OF_EISA_DATA]; +} CONFIGURATION, *PCONFIGURATION; + +#else // EISA_PLATFORM + +// +// Defines for the Non-Volatile configuration tables. +// +// SMD - We have reduced the size of the NVRAM from 6K to 3K +// If needed we could take a few bytes from ENVIRONMENT +// since there is tons of empty space there. +// + +#define LENGTH_OF_ENVIRONMENT ((3*1024) - 16 - 4) + +#define MAXIMUM_ENVIRONMENT_VALUE 256 +#define MAXIMUM_NUMBER_OF_ENVIRONMENT_VARIABLES 28 +#define MAX_NUMBER_OF_ENVIRONMENT_VARIABLES 28 +// +// The non-volatile configuration table structure. +// + +typedef struct _NV_CONFIGURATION { + ULONG Monitor; //0 + ULONG Floppy; //4 + ULONG Floppy2; //8 + ULONG KeyboardType; //12 + UCHAR Environment[LENGTH_OF_ENVIRONMENT]; //16 to (3K-4) + UCHAR Checksum[4]; +} NV_CONFIGURATION, *PNV_CONFIGURATION; + +// +// Defines for the Volatile configuration tables. +// + +#define NUMBER_OF_ENTRIES 40 +#define LENGTH_OF_IDENTIFIER (1024 - (NUMBER_OF_ENTRIES * 16)) +#define LENGTH_OF_DATA 2048 + +// +// The volatile configuration table structure. +// + +typedef struct _CONFIGURATION { + CONFIGURATION_PACKET Packet[NUMBER_OF_ENTRIES]; + UCHAR Identifier[LENGTH_OF_IDENTIFIER]; + UCHAR Data[LENGTH_OF_DATA]; +} CONFIGURATION, *PCONFIGURATION; + +#endif // EISA_PLATFORM + +// +// The value of HalpCMOSRamBase must be set at initialization: +// +#define NVRAM_CONFIGURATION HalpCMOSRamBase diff --git a/private/ntos/nthals/halalpha/errframe.h b/private/ntos/nthals/halalpha/errframe.h new file mode 100644 index 000000000..ced43eb08 --- /dev/null +++ b/private/ntos/nthals/halalpha/errframe.h @@ -0,0 +1,697 @@ +/*++ + +Copyright (c) 1995,1996 Digital Equipment Corporation + +Module Name: + + errframe.h + +Abstract: + + Definitions for both the correctable and uncorrectable error + frames. + +Author: + + Joe Notarangelo 10-Mar-1995 + Chao Chen 24-Apr-1995 + +Environment: + + Kernel mode only. + +Revision History: + +0.1 28-Feb-1995 Joe Notarangelo Initial version. + +0.2 10-Mar-1995 Joe Notarangelo Incorporate initial review comments from + 6-Mar-95 review with: C. Chen, S. Jenness, + Bala, E. Rehm. + +0.3 24-Apr-1995 Chao Chen Made into .h file for inclusion by other + modules. + +0.4 16-Apr-1996 Gene Morgan Add fields to SystemError struct for PSU, + Wachdog events. + +--*/ + +#ifndef ERRFRAME_H +#define ERRFRAME_H + +#include "errplat.h" + +/* + * + * Common defines. + * + */ + +#define ERROR_FRAME_VERSION 0x1 + +#define UNIDENTIFIED 0x0 +#define MEMORY_SPACE 0x1 +#define IO_SPACE 0x2 +#define PROCESSOR_CACHE 0x2 +#define SYSTEM_CACHE 0x3 +#define PROCESSOR_MEMORY 0x4 +#define SYSTEM_MEMORY 0x5 + +#define CACHE_ERROR_MASK 0x2 +#define MEMORY_ERROR_MASK 0x4 + +#define BUS_DMA_READ 0x1 +#define BUS_DMA_WRITE 0x2 +#define BUS_DMA_OP 0x3 +#define BUS_IO_READ 0x4 +#define BUS_IO_WRITE 0x5 +#define BUS_IO_OP 0x6 +#define TLB_MISS_READ 0x7 +#define TLB_MISS_WRITE 0x8 +#define VICTIM_WRITE 0x9 + +#define MAX_UNCORRERR_STRLEN 128 + +#define ERROR_FRAME_SIGNATURE 0xE22F2F2A // ERRORFRA R=2 (18%16) + +/* + * + * Definitions for the correctable error frame. + * + */ + +// +// Correctable Error Flags +// + +typedef struct _CORRECTABLE_FLAGS{ + + // + // Address space + // Unidentified: 00 + // Memory Space: 01 + // I/O Space: 10 + // Reserved: 11 + // + + ULONGLONG AddressSpace: 2; + + // + // Error Interpretation Validity. + // + + ULONGLONG ServerManagementInformationValid: 1; + ULONGLONG PhysicalAddressValid: 1; + ULONGLONG ErrorBitMasksValid: 1; + ULONGLONG ExtendedErrorValid: 1; + ULONGLONG ProcessorInformationValid: 1; + ULONGLONG SystemInformationValid: 1; + + // + // Memory Space Error Source: + // + // Unidentified: 000 + // ProcessorCache: 010 + // SystemCache: 011 + // ProcessorMemory: 100 + // SystemMemory: 101 + // + + ULONGLONG MemoryErrorSource: 4; + + // + // Driver Actions. + // + + ULONGLONG ScrubError: 1; + + // + // Lost errors. + // + + ULONGLONG LostCorrectable: 1; + ULONGLONG LostAddressSpace: 2; + ULONGLONG LostMemoryErrorSource: 4; + +} CORRECTABLE_FLAGS, *PCORRECTABLE_FLAGS; + + // + // Description of CORRECTABLE_FLAG structure: + // + // AddressSpace + // + // Identifies the system address space that was the source of the + // correctable error. + // + // PhysicalAddressValid + // + // Indicates if the physical address in the CORRECTABLE_ERROR + // structure is valid. A value of 1 indicates the physical address + // is valid, a value of 0 indicates the physical address is not + // valid. + // + // ErrorBitMasksValid + // + // Indicates if the error bit mask fields in the CORRECTABLE_ERROR + // structure are valid. A value of 1 indicates the DataBitErrorMask + // and the CheckBitErrorMask are valid, a value of 0 indicates they + // are not valid. + // + // ExtendedErrorValid + // + // Indicates if the extended error information structure in the + // CORRECTABLE_ERROR structure is valid. A value of 1 indicates the + // extended error information structure is valid, a value of 0 + // indicates that it is not. + // + // ProcessorInformationValid + // + // Indicates if the raw processor information pointer in the + // CORRECTABLE_ERROR structure is valid. A value of 1 indicates the + // processor information is valid, a value of 0 indicates it is not. + // + // SystemInformationValid + // + // Indicates if the raw system information pointer in the + // CORRECTABLE_ERROR structure is valid. A value of 1 indicates the + // system information is valid, a value of 0 indicates it is not. + // + // ServerManagementInformationValid + // + // Indicates that the server management information in the extended + // error information structure is valid. The server management + // information relays information about failed fans or high + // temperature in the system. + // + // + // MemoryErrorSource + // + // Identifies the source of a memory error as either main error + // or cache for either a system or processor. + // + // ScrubError + // + // Instructs the driver to scrub the correctable error. If the + // value is 1 the driver should scrub the error, if the value is + // 0 the driver must not scrub the error. + // + // LostCorrectable + // + // Identifies if a lost correctable error has been reported. A + // lost error is an error that reported by the hardware while + // correctable error handling for a previous error was in progress. + // A value of 1 indicates that a correctable error report was lost. + // + // LostAddressSpace + // + // Identifies the system address space that was the source of the + // correctable error. Valid only if LostCorrectable == 1. + // + // LostMemoryErrorSource + // + // Identifies the source of a memory error as either main error + // or cache for either a system or processor. Valid only if + // LostCorrectable == 1. + // + +// +// Processor information. +// + +typedef struct _PROCESSOR_INFO{ + + ULONG ProcessorType; + ULONG ProcessorRevision; + ULONG PhysicalProcessorNumber; + ULONG LogicalProcessorNumber; + +} PROCESSOR_INFO, *PPROCESSOR_INFO; + + // + // Description of PROCESSOR_INFO structure: + // + // ProcessorType + // + // Identifies the type of processor running on the system + // (eg. 21064, 21066, 21164). Note that the type of processor + // is expected to be consistent across the system for MP machines. + // + // ProcessorRevision + // + // Identifies the revision number of the processor running on + // the system. Note that the revision is expected to be consistent + // across the system for MP machines. + // + // PhysicalProcessorNumber + // + // The physical processor number as numbered in the hardware + // specifications. + // + // LogicalProcessorNumber + // + // The logical processor number assigned to the processor by NT. + // + +// +// System Information. +// + +typedef struct _SYSTEM_INFORMATION{ + + UCHAR SystemType[8]; + ULONG ClockSpeed; + ULONG OsRevisionId; + ULONG PalMajorVersion; + ULONG PalMinorVersion; + UCHAR FirmwareRevisionId[16]; + ULONG SystemVariant; + ULONG SystemRevision; + UCHAR SystemSerialNumber[16]; + ULONG ModuleVariant; + ULONG ModuleRevision; + ULONG ModuleSerialNumber; +} SYSTEM_INFORMATION, *PSYSTEM_INFORMATION; + + // + // Description of SYSTEM_INFORMATION structure: + // + // SystemType + // + // Identifies the type of system that reported the error + // (eg. "Sable", "Gamma"). The actual format and value of the + // SystemType string is system-specific. + // + // OsRevisionId + // + // A numeric value that identifies the OS revision executing + // on the system that reported the fault. + // + // PalRevisionId + // + // A numeric value that identifies the pal revision executing + // on the system that reported the fault. + // + // FirmwareRevisionId + // + // A numeric value that identifies the firmware revision executing + // on the system that reported the fault. + // + // SystemVariant + // + // A numeric value used to distinguish variants of the same system + // type. The values and their interpretation are system_specific. + // + // SystemRevision + // + // A numeric value used to distinguish revisions of the same system + // type. The values and their interpretation are system_specific. + // + // + +// +// Extended Error Information. +// + +typedef union _EXTENDED_ERROR{ + + struct{ + struct{ + ULONG CacheLevelValid: 1; + ULONG CacheBoardValid: 1; + ULONG CacheSimmValid: 1; + } Flags; + PROCESSOR_INFO ProcessorInfo; + ULONG CacheLevel; + ULONG CacheBoardNumber; + ULONG CacheSimm; + ULONG TransferType; + ULONG Reserved; + } CacheError; + + struct{ + struct{ + ULONG MemoryBoardValid: 1; + ULONG MemorySimmValid: 1; + } Flags; + PROCESSOR_INFO ProcessorInfo; + ULONG MemoryBoard; + ULONG MemorySimm; + ULONG TransferType; + ULONG Reserved[2]; + } MemoryError; + + struct{ + INTERFACE_TYPE Interface; + ULONG BusNumber; + PHYSICAL_ADDRESS BusAddress; + ULONG TransferType; + ULONG Reserved[5]; + } IoError; + + struct{ + struct{ + ULONG FanNumberValid: 1; + ULONG TempSensorNumberValid: 1; + ULONG PowerSupplyNumberValid: 1; + ULONG WatchDogExpiredValid: 1; + } Flags; + ULONG FanNumber; + ULONG TempSensorNumber; + ULONG PowerSupplyNumber; + ULONG WatchdogExpiration; + ULONG Reserved[5]; + } SystemError; + +} EXTENDED_ERROR, *PEXTENDED_ERROR; + + // + // Description of EXTENDED_ERROR union: + // + // The EXTENDED_ERROR union has different interpretation depending + // upon the AddressSpace and MemoryErrorSource fields of the + // CORRECTABLE_FLAGS structure according to the following table: + // + // 1. AddressSpace=MemorySpace + // MemoryErrorSource = 01x use CacheError structure + // + // 2. AddressSpace=MemorySpace + // MemoryErrorSource = 10x use MemoryError structure + // + // 3. AddressSpace=IoSpace use IoError + // + // 4. AddressSpace=Unidentified use SystemError + // MemoryErrorSource = 0x0 (note: ServerManagementInformationValid + // should be set) + // + // + // CacheError.Flags + // + // Identifies which fields of the CacheError structure are valid. + // CacheLevelValid = 1 indicates CacheLevel is valid. + // CacheBoardValid = 1 indicates CacheBoardNumber is valid. + // CacheSimmValid = 1 indicates CacheSimm is valid. + // + // CacheError.ProcessorInfo + // + // Identifies the processor associated with the error. Most + // frequently will identify the processor that experienced and + // reported the error. However, it is possible that the processor + // that is reporting has experienced the error from another + // processor's cache. This field is valid only if the + // MemoryErrorSource = 010 . + // + // CacheError.CacheLevel + // + // Identifies the level of the cache that caused the error. Primary + // caches are Level 1, Secondary are Level 2, etc.. This field + // only valid if CacheError.Flags.CacheLevelValid == 1. + // + // CacheError.CacheBoardNumber + // + // Identifies the board number of the cache that caused the error. + // This field only valid if + // CacheError.Flags.CacheBoardNumberValid == 1. + // + // CacheError.CacheSimm + // + // Identifies the Cache Simm that caused the error. + // This field only valid if CacheError.Flags.CacheSimmValid == 1. + // + // + // MemoryError.Flags + // + // Identifies which fields of the CacheError structure are valid. + // CacheLevelValid = 1 indicates CacheLevel is valid. + // CacheBoardValid = 1 indicates CacheBoardNumber is valid. + // CacheSimmValid = 1 indicates CacheSimm is valid. + // + // MemoryError.ProcessorInfo + // + // Identifies the processor associated with the error. Most + // frequently will identify the processor that experienced and + // reported the error. However, it is possible that the processor + // that is reporting has experienced the error from another + // processor's cache. This field is valid only if the + // MemoryErrorSource = 010 . + // + // MemoryError.MemoryBoardNumber + // + // Identifies the board number of the cache that caused the error. + // This field only valid if MemoryError.Flags.MemoryBoardValid == 1. + // + // MemoryError.MemorySimm + // + // Identifies the memory SIMM that caused the error. + // This field only valid if MemoryError.Flags.MemorySimmValid == 1. + // + // + // IoError.Interface + // + // Identifies the bus interface type (eg. PCI) of the bus that caused + // the correctable error. + // + // IoError.BusNumber + // + // Identifies the bus number of the bus that caused the correctable + // error. + // + // IoError.BusAddress + // + // Identifies the bus address of the bus that caused the correctable + // error. + // + +// +// Correctable Error Frame. +// + +typedef struct _CORRECTABLE_ERROR{ + + CORRECTABLE_FLAGS Flags; + ULONGLONG PhysicalAddress; + ULONGLONG DataBitErrorMask; + ULONGLONG CheckBitErrorMask; + EXTENDED_ERROR ErrorInformation; + PROCESSOR_INFO ReportingProcessor; + SYSTEM_INFORMATION System; + ULONG RawProcessorInformationLength; + PVOID RawProcessorInformation; + ULONG RawSystemInformationLength; + PVOID RawSystemInformation; + ULONG Reserved; + +} CORRECTABLE_ERROR, *PCORRECTABLE_ERROR; + + // + // Description of CORRECTABLE_ERROR structure: + // + // Flags + // + // The flags describe the various aspects of the error report. The + // CORRECTABLE_FLAGS structure is described below. + // + // PhysicalAddress + // + // The physical CPU address of the quadword that caused the correctable + // error report. This value is optional, its validiity is indicated + // in the Flags. + // + // DataBitErrorMask + // + // A mask that describes which data bits in the corrected word were + // in error. A value of one in the mask indicates that the + // corresponding bit in the data word were in error. + // + // CheckBitErrorMask + // + // A mask that describes which check bits in the corrected word were + // in error. A value of one in the mask indicates that the + // corresponding bit in the check bits were in error. + // + // ErrorInformation + // + // A structure that desribes interpretation of the error. The values + // in the structure are optional, the EXTENDED_ERROR structure is + // described below. + // + // ReportingProcessor + // + // A structure that describes the processor type on the system and + // the processor that reported the error. PROCESSOR_INFO structure + // is described below. + // + // RawProcessorInformationLength + // + // The length of the raw processor error information structure in + // bytes. + // + // RawProcessorInformation + // + // A pointer to the raw processor error information structure. The + // definition of the structure is processor-specific. The definitions + // for the known processors is defined in Appendix A below. + // + // System + // + // A structure that describes the type of system for which the + // error was reported. SYSTEM_INFORMATION structure is described below. + // + // RawSystemInformationLength + // + // The length of the raw processor error information structure in + // bytes. + // + // RawSystemInformation + // + // A pointer to the raw system error information structure. The + // definition of the structure is system/ASIC-specific. The + // definitions for the known systems/ASICs is defined in Appendix B. + // + // + + +/* + * + * Definitions for the uncorrectable error frame. + * + */ + +// +// Uncorrectable Error Flags. +// + +typedef struct _UNCORRECTABLE_FLAGS{ + + // + // Address space + // Unidentified: 00 + // Memory Space: 01 + // I/O Space: 10 + // Reserved: 11 + // + + ULONGLONG AddressSpace: 2; + + // + // Error Interpretation Validity. + // + + ULONGLONG ErrorStringValid: 1; + ULONGLONG PhysicalAddressValid: 1; + ULONGLONG ErrorBitMasksValid: 1; + ULONGLONG ExtendedErrorValid: 1; + ULONGLONG ProcessorInformationValid: 1; + ULONGLONG SystemInformationValid: 1; + + // + // Memory Space Error Source: + // + // Unidentified: 000 + // ProcessorCache: 010 + // SystemCache: 011 + // ProcessorMemory: 100 + // SystemMemory: 101 + // + + ULONGLONG MemoryErrorSource: 4; + +} UNCORRECTABLE_FLAGS, *PUNCORRECTABLE_FLAGS; + + // + // The extended error information, processor information and system + // information structures are identical for correctable and uncorrectable + // errors. The rules for printing the failing FRU are also identical + // to the rules for the correctable errors. + // + +// +// Uncorrectable Error Frame. +// + +typedef struct _UNCORRECTABLE_ERROR{ + + UNCORRECTABLE_FLAGS Flags; + CHAR ErrorString[MAX_UNCORRERR_STRLEN]; + ULONGLONG PhysicalAddress; + ULONGLONG DataBitErrorMask; + ULONGLONG CheckBitErrorMask; + EXTENDED_ERROR ErrorInformation; + PROCESSOR_INFO ReportingProcessor; + SYSTEM_INFORMATION System; + ULONG RawProcessorInformationLength; + PVOID RawProcessorInformation; + ULONG RawSystemInformationLength; + PVOID RawSystemInformation; + ULONG Reserved; + +} UNCORRECTABLE_ERROR, *PUNCORRECTABLE_ERROR; + + +/* + * + * Generic definitions for the error frame. + * + */ + +// +// Generic error frame. +// + +typedef enum _FRAME_TYPE{ + CorrectableFrame, + UncorrectableFrame +} FRAME_TYPE, *PFRAME_TYPE; + +typedef struct _ERROR_FRAME{ + + ULONG Signature; // Needed to make sure that the buffer is infact + // an error frame. + ULONG LengthOfEntireErrorFrame; + FRAME_TYPE FrameType; + ULONG VersionNumber; + ULONG SequenceNumber; + ULONGLONG PerformanceCounterValue; + + union { + CORRECTABLE_ERROR CorrectableFrame; + UNCORRECTABLE_ERROR UncorrectableFrame; + }; + +} ERROR_FRAME, *PERROR_FRAME; + + // + // Description of the generic error frame structure: + // + // FrameType + // + // Specify which frame type we have. Either correctable or + // uncorrectable. + // + // VersionNumber + // + // Defines the version of the error structure. Current version + // number = 1. + // + // SequenceNumber + // + // A number that identifies a particular error frame. + // + // PerformanceCounterValue + // + // The value of the system performance counter when the error was + // reported. The value is determined during error processing by the + // HAL and so may be captured significantly after the hardware + // detected the error. The value cannot be used for fine grained + // timing of when errors occurred but can be used for coarse grained + // timing and approximate timing. + // + // CorrectableFrame + // + // Shared common area for a correctable frame. + // + // UncorrectableFrame + // + // Shared common area for an uncorrectable frame. + // + +#endif //ERRFRAME_H diff --git a/private/ntos/nthals/halalpha/errplat.h b/private/ntos/nthals/halalpha/errplat.h new file mode 100644 index 000000000..99133ed2c --- /dev/null +++ b/private/ntos/nthals/halalpha/errplat.h @@ -0,0 +1,774 @@ +/*++ + +Copyright (c) 1995 Digital Equipment Corporation + +Module Name: + + errplat.h + +Abstract: + + Definitions for the platform specific correctable and uncorrectable error + frames for processors and systems. + +Author: + + Joe Notarangelo 10-Mar-1995 + Chao Chen 24-Apr-1995 + +Environment: + + Kernel mode only. + +Revision History: + +0.1 28-Feb-1995 Joe Notarangelo Initial version. + +0.2 10-Mar-1995 Joe Notarangelo Incorporate initial review comments from + 6-Mar-95 review with: C. Chen, S. Jenness, + Bala, E. Rehm. + +0.3 24-Apr-1995 Chao Chen Made into .h file for inclusion by other + modules. + +0.4 Jun-July-1995 Bala Nagarajan Added Uncorrectable Error frames for + APECS, SABLE, GAMMA etc. +--*/ +#ifndef ERRPLAT_H +#define ERRPLAT_H + +/* + * + * Processor specific definitions for error frame. + * + */ + +// +// EV5: +// + +// +// Processor information structure for processor detected correctable read +// on the EV5. +// + +typedef struct PROCESSOR_EV5_CORRECTABLE{ + ULONGLONG EiAddr; + ULONGLONG FillSyn; + ULONGLONG EiStat; + ULONGLONG BcConfig; + ULONGLONG BcControl; +} PROCESSOR_EV5_CORRECTABLE, *PPROCESSOR_EV5_CORRECTABLE; + +// +// Processor information structure for processor-detected uncorrectable errors +// on the EV5. +// + +typedef struct PROCESSOR_EV5_UNCORRECTABLE{ + ULONGLONG IcPerrStat; + ULONGLONG DcPerrStat; + ULONGLONG ScStat; + ULONGLONG ScAddr; + ULONGLONG EiStat; + ULONGLONG BcTagAddr; + ULONGLONG EiAddr; + ULONGLONG FillSyn; + ULONGLONG BcConfig; + ULONGLONG BcControl; +} PROCESSOR_EV5_UNCORRECTABLE, *PPROCESSOR_EV5_UNCORRECTABLE; + + +// +// EV4(5): +// + +// +// Processor information structure for processor detected correctable read +// on the EV4(5). +// + +typedef struct PROCESSOR_EV4_CORRECTABLE{ + ULONGLONG BiuStat; + ULONGLONG BiuAddr; + ULONGLONG AboxCtl; + ULONGLONG BiuCtl; + ULONGLONG CStat; // a.k.a. DcStat for EV4 +} PROCESSOR_EV4_CORRECTABLE, *PPROCESSOR_EV4_CORRECTABLE; + +// +// Processor information structure for processor detected uncorrectable errors +// on the EV4(5). +// + +typedef struct PROCESSOR_EV4_UNCORRECTABLE{ + ULONGLONG BiuStat; + ULONGLONG BiuAddr; + ULONGLONG AboxCtl; + ULONGLONG BiuCtl; + ULONGLONG CStat; // a.k.a. DcStat for EV4 + ULONGLONG BcTag; + ULONGLONG FillAddr; + ULONGLONG FillSyndrome; +} PROCESSOR_EV4_UNCORRECTABLE, *PPROCESSOR_EV4_UNCORRECTABLE; + + +// +// LCA: +// + +// +// Processor information structure for processor detected correctable read +// on the LCA. +// + +typedef struct PROCESSOR_LCA_CORRECTABLE{ + ULONG VersionNumber; // Version Number of this structure not the LCA. + ULONGLONG Esr; + ULONGLONG Ear; + ULONGLONG AboxCtl; + ULONG BankConfig0; + ULONG BankConfig1; + ULONG BankConfig2; + ULONG BankConfig3; + ULONG BankMask0; + ULONG BankMask1; + ULONG BankMask2; + ULONG BankMask3; + ULONG Car; + ULONG Gtr; +} PROCESSOR_LCA_CORRECTABLE, *PPROCESSOR_LCA_CORRECTABLE; + +// +// Processor information structure for processor detected uncorrectable errors +// on the LCA. +// + +typedef struct PROCESSOR_LCA_UNCORRECTABLE{ + ULONG VersionNumber; // Version Number of this structure not the LCA. + ULONGLONG CStat; // a.k.a. DcStat for LCA4 + ULONGLONG Esr; + ULONGLONG Ear; + ULONGLONG IocStat0; + ULONGLONG IocStat1; + ULONGLONG AboxCtl; + ULONGLONG MmCsr; + ULONGLONG BankConfig0; + ULONGLONG BankConfig1; + ULONGLONG BankConfig2; + ULONGLONG BankConfig3; + ULONGLONG BankMask0; + ULONGLONG BankMask1; + ULONGLONG BankMask2; + ULONGLONG BankMask3; + ULONGLONG Car; + ULONGLONG Gtr; +} PROCESSOR_LCA_UNCORRECTABLE, *PPROCESSOR_LCA_UNCORRECTABLE; + +// +// The generic raw processor frame. +// + +typedef union _RAW_PROCESSOR_FRAME{ + + PROCESSOR_EV5_CORRECTABLE Ev5Correctable; + PROCESSOR_EV5_UNCORRECTABLE Ev5Uncorrectable; + PROCESSOR_EV4_CORRECTABLE Ev4Correctable; + PROCESSOR_EV4_UNCORRECTABLE Ev4Uncorrectable; + PROCESSOR_LCA_CORRECTABLE LcaCorrectable; + PROCESSOR_LCA_UNCORRECTABLE LcaUncorrectable; + +} RAW_PROCESSOR_FRAME, *PRAW_PROCESSOR_FRAME; + +/* + * + * System specific definitions for error frame. + * + */ + +// +// Cia: +// + +// +// Cia configuration information +// + +typedef struct _CIA_CONFIGURATION{ + + ULONG CiaRev; + ULONG CiaCtrl; + ULONG Mcr; + ULONG Mba0; + ULONG Mba2; + ULONG Mba4; + ULONG Mba6; + ULONG Mba8; + ULONG MbaA; + ULONG MbaC; + ULONG MbaE; + ULONG Tmg0; + ULONG Tmg1; + ULONG Tmg2; + ULONG CacheCnfg; + ULONG Scr; + +} CIA_CONFIGURATION, *PCIA_CONFIGURATION; + +// +// Cia system detected correctable. +// + +typedef struct _CIA_CORRECTABLE_FRAME{ + ULONG VersionNumber; // Version Number of this structure. + ULONG CiaErr; + ULONG CiaStat; + ULONG CiaSyn; + ULONG MemErr0; + ULONG MemErr1; + ULONG PciErr0; + ULONG PciErr1; + ULONG PciErr2; + CIA_CONFIGURATION Configuration; + +} CIA_CORRECTABLE_FRAME, *PCIA_CORRECTABLE_FRAME; + + // + // Note: it appears that the only correctable errors that are detected + // are: + // + // a. ECC on DMA Read (memory or cache) + // b. ECC on S/G TLB fill for DMA Read (memory or cache) + // c. ECC on DMA Write (probably CIA) + // d. ECC on S/G TLB fill for DMA write (memory or cache) (no PA?) + // e. I/O Write (ASIC problem) (no PA) + // + +// +// Cia System-detected Uncorrectable Error +// + +typedef struct _CIA_UNCORRECTABLE_FRAME{ + ULONG VersionNumber; // Version Number of this structure. + ULONG CiaErr; + ULONG ErrMask; + ULONG CiaStat; + ULONG CiaSyn; + ULONG CpuErr0; + ULONG CpuErr1; + ULONG MemErr0; + ULONG MemErr1; + ULONG PciErr0; + ULONG PciErr1; + ULONG PciErr2; + CIA_CONFIGURATION Configuration; + +} CIA_UNCORRECTABLE_FRAME, *PCIA_UNCORRECTABLE_FRAME; + +// +// Apecs: +// + +// +// Apecs Configuration Information +// + +typedef struct _APECS_CONFIGURATION { + ULONG ApecsRev; + ULONG CGcr; // General Control register + ULONG CTer; // Tag Enable Register + ULONG CGtr; // Global Timer Register + ULONG CRtr; // refresh Timer register + ULONG CBank0; // Bank Configuration registers. + ULONG CBank1; + ULONG CBank2; + ULONG CBank3; + ULONG CBank4; + ULONG CBank5; + ULONG CBank6; + ULONG CBank7; + ULONG CBank8; + +} APECS_CONFIGURATION, *PAPECS_CONFIGURATION; + +// +// Apecs based system-detected Correctable Error +// + +typedef struct _APECS_CORRECTABLE_FRAME{ + ULONG VersionNumber; // Version Number of this structure not the APECS. + ULONG EpicEcsr; + ULONG EpicSysErrAddr; + APECS_CONFIGURATION Configuration; + +} APECS_CORRECTABLE_FRAME, *PAPECS_CORRECTABLE_FRAME; + + // + // Note: it appears that the only correctable errors that are detected + // are: + // + // a. ECC on DMA Read (memory) + // b. ECC on S/G TLB fill for DMA Read (memory) + // + +// +// Apecs based system-detected Uncorrectable Error +// + +typedef struct _APECS_UNCORRECTABLE_FRAME{ + ULONG VersionNumber; // Version Number of this structure not the APECS. + ULONG EpicEcsr; + ULONG ComancheEdsr; + ULONG EpicPciErrAddr; + ULONG EpicSysErrAddr; + ULONG ComancheErrAddr; + APECS_CONFIGURATION Configuration; + +} APECS_UNCORRECTABLE_FRAME, *PAPECS_UNCORRECTABLE_FRAME; + + +// +// T2, T3, T4 Chipset error frame. +// + +typedef struct _TX_ERROR_FRAME { + ULONGLONG Cerr1; // CBUS Error Register 1 + ULONGLONG Cerr2; // CBUS Error Register 2 + ULONGLONG Cerr3; // CBUS Error Register 3 + ULONGLONG Perr1; // PCI Error Register 1 + ULONGLONG Perr2; // PCI Error Register 2 +} TX_ERROR_FRAME, *PTX_ERROR_FRAME; + + +// +// Sable CPU Module configuration information. +// + +typedef struct _SABLE_CPU_CONFIGURATION { + ULONGLONG Cbctl; + ULONGLONG Pmbx; + ULONGLONG C4rev; +} SABLE_CPU_CONFIGURATION, *PSABLE_CPU_CONFIGURATION; + +// +// Sable Memory Module configuration information. +// + +typedef struct _SABLE_MEMORY_CONFIGURATION { + ULONGLONG Conifg; // CSR 3 + ULONGLONG EdcCtl; // Error detection/correction control register + ULONGLONG StreamBfrCtl; + ULONGLONG RefreshCtl; + ULONGLONG CrdFilterCtl; +} SABLE_MEMORY_CONFIGURATION, *PSABLE_MEMORY_CONFIGURATION; + + +// +// Sable System Configuration +// + +typedef struct _SABLE_CONFIGURATION { + ULONG T2Revision; // Revision number of the T2 chipset. + ULONG NumberOfCpus; // Number of CPUs in the system. + ULONG NumberOfMemModules; // Number of memory modules in the system. + ULONGLONG T2IoCsr; + SABLE_CPU_CONFIGURATION CpuConfigs[4]; // 4 is the max CPU's + SABLE_MEMORY_CONFIGURATION MemConfigs[4]; // Maximum of 4 memory modules. +} SABLE_CONFIGURATION, *PSABLE_CONFIGURATION; + +// +// Sable CPU-module Error Information +// + +typedef struct _SABLE_CPU_ERROR { + + union { + struct { + ULONGLONG Bcue; // BCacheUncorrectableError + ULONGLONG Bcuea; // BCacheUncorrectableErrorAddress + } Uncorrectable; + + struct { + ULONGLONG Bcce; // BCacheCorrectableError + ULONGLONG Bccea; // BCacheCorrectableErrorAddress + } Correctable; + }; + ULONGLONG Dter; // Duplicate Tag Error Register + ULONGLONG Cberr; // CBUS2 Error (System Bus Error) + ULONGLONG Cbeal; // system bus error address register low. + ULONGLONG Cbeah; // system bus error address register high. +} SABLE_CPU_ERROR, *PSABLE_CPU_ERROR; + +typedef struct _SABLE_MEMORY_ERROR { + + ULONGLONG MemError; // CSR0 of memory module + ULONGLONG EdcStatus1; + ULONGLONG EdcStatus2; + +} SABLE_MEMORY_ERROR, *PSABLE_MEMORY_ERROR; + +// +// Sable Correctable and Uncorrectable Error Frame. +// + +typedef struct _SABLE_ERROR_FRAME { + + SABLE_CPU_ERROR CpuError[4]; + SABLE_MEMORY_ERROR MemError[4]; + TX_ERROR_FRAME IoChipsetError; + SABLE_CONFIGURATION Configuration; +} SABLE_UNCORRECTABLE_FRAME, *PSABLE_UNCORRECTABLE_FRAME, + SABLE_CORRECTABLE_FRAME, *PSABLE_CORRECTABLE_FRAME; + + + +// +// Gamma CPU Module configuration information. +// + +typedef struct _GAMMA_CPU_CONFIGURATION { + ULONGLONG Cbctl; // Cbus2 Control Register. + ULONGLONG Dtctr; // Duplicate Tag control register. + ULONGLONG Creg; // Rattler Control Register. +} GAMMA_CPU_CONFIGURATION, *PGAMMA_CPU_CONFIGURATION; + + +// +// Gamma System Configuration +// + +typedef struct _GAMMA_CONFIGURATION { + ULONG T2Revision; // Revision number of the T2 chipset. + ULONG NumberOfCpus; // Number of CPUs in the system. + ULONG NumberOfMemModules; // Number of memory modules in the system. + ULONGLONG T2IoCsr; + GAMMA_CPU_CONFIGURATION CpuConfigs[4]; // 4 is the max CPU's + SABLE_MEMORY_CONFIGURATION MemConfigs[4]; // Maximum of 4 memory modules. +} GAMMA_CONFIGURATION, *PGAMMA_CONFIGURATION; + +// +// Gamma CPU-module Error Information +// + +typedef struct _GAMMA_CPU_ERROR { + ULONGLONG Esreg; // Error Summary + union { + struct { + ULONGLONG Evbuer; // EVB Uncorrectable Error + ULONGLONG Evbuear; // EVB Uncorrectable Error Address + } Uncorrectable; + + struct { + ULONGLONG Evbcer; // EVB Correctable Error + ULONGLONG Evbcear; // EVB Correctable error address + } Correctable; + }; + ULONGLONG Vear; // Victim Error Address + // valid only if bit 5 or bit 37 + // of Evbuer is set. + + ULONGLONG Dter; // Duplicate Tag Error Register + ULONGLONG Cberr; // CBUS2 Error (System Bus Error) + ULONGLONG Cbeal; // system bus error address register low. + ULONGLONG Cbeah; // system bus error address register high. +} GAMMA_CPU_ERROR, *PGAMMA_CPU_ERROR; + + +// +// Gamma Correctable and Uncorrectable Error Frame. +// + +typedef struct _GAMMA_ERROR_FRAME { + + GAMMA_CPU_ERROR CpuError[4]; + SABLE_MEMORY_ERROR MemError[4]; + TX_ERROR_FRAME IoChipsetError; + GAMMA_CONFIGURATION Configuration; +} GAMMA_UNCORRECTABLE_FRAME, *PGAMMA_UNCORRECTABLE_FRAME, + GAMMA_CORRECTABLE_FRAME, *PGAMMA_CORRECTABLE_FRAME; + + +// +// Rawhide Error Frame Definitions +// + +// +// CPU Daughter Card (CUD) Header +// + +typedef struct _RAWHIDE_CUD_HEADER { // As Per Rawhide SPM + ULONG ActiveCpus; // (0x00) + ULONG HwRevision; // (0x04) + UCHAR SystemSN[10]; // (0x08-0x11) Same as FRU System Serial Number + UCHAR Reserved2[6]; // (0x12-0x17) + UCHAR ModuleSN[10]; // (0x18-0x21) Module (processor) S/N, if available + USHORT ModType; // (0x22) + ULONG Reserved3; // (0x24) + ULONG DisabledResources; // (0x28) + UCHAR SystemRev[4]; // (0x2c) Same as FRU System Revision Level? +} RAWHIDE_CUD_HEADER, *PRAWHIDE_CUD_HEADER; + + + +// +// 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; + +// +// 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 BaseAddress; // (0x00) + ULONG WhoAmI; // (0x08) + IOD_ERROR_FRAME_VALID_BITS ValidBits; // (0x0c) + ULONG PciRevision; // (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; + + +// +// 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 _RAWHIDE_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; +} RAWHIDE_ERROR_SUBPACKET_FLAGS, *PRAWHIDE_ERROR_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 union _RAWHIDE_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; +} RAWHIDE_MEMORY_SIZE, *PRAWHIDE_MEMORY_SIZE; + + +// +// System Managment Frame +// + +typedef struct _RAWHIDE_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 _RAWHIDE_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; +} RAWHIDE_SYSTEM_ENVIRONMENT, *PRAWHIDE_SYSTEM_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 Correctable (Soft) Error Frame +// Rawhide Uncorrectable (Hard) Error Frame +// + +#define RAWHIDE_UNCORRECTABLE_FRAME_REVISION 0x10 // V1.0 +#define RAWHIDE_CORRECTABLE_FRAME_REVISION 0x10 // V1.0 + +typedef struct _RAWHIDE_UNCORRECTABLE_FRAME { + ULONG Revision; // (0x00) + ULONG WhoAmI; // (0x04) + RAWHIDE_ERROR_SUBPACKET_FLAGS ErrorSubpacketFlags; // (0x08) + RAWHIDE_CUD_HEADER CudHeader; // (0x10-0x4f) + MC_BUS_SNAPSHOT McBusSnapshot; // (0x50-0x5f) + + // + // Uncorrectable Error Frame will have: + // a) two (Dodge) or four (Durango) IOD_ERROR_FRAMEs (0x60 - ???) + // + // b) Optional Error Subpackets as per ErrorSubpacketFlags + // + +} RAWHIDE_UNCORRECTABLE_FRAME, *PRAWHIDE_UNCORRECTABLE_FRAME; + +typedef struct _RAWHIDE_CORRECTABLE_FRAME { + ULONG Revision; // (0x00) + ULONG WhoAmI; // (0x04) + RAWHIDE_ERROR_SUBPACKET_FLAGS ErrorSubpacketFlags; // (0x08) + RAWHIDE_CUD_HEADER CudHeader; // (0x10-0x4f) + IOD_ERROR_FRAME IodErrorFrame; // (0x50-0xaf) + + // + // Correctable Error will always have only + // one IOD in the McBusSnapshot, that of the IOD with + // the correctable error. + // + +} RAWHIDE_CORRECTABLE_FRAME, *PRAWHIDE_CORRECTABLE_FRAME; + + +#endif //ERRPLAT_H diff --git a/private/ntos/nthals/halalpha/ev4cache.c b/private/ntos/nthals/halalpha/ev4cache.c new file mode 100644 index 000000000..506dd581f --- /dev/null +++ b/private/ntos/nthals/halalpha/ev4cache.c @@ -0,0 +1,488 @@ +/*++ + +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + ev4cache.c + +Abstract: + + This file contains the routines for managing the caches on machines + based on the DECchip 21064 microprocessor. + + EV4 has primary I and D caches of 8KB each, both write-through. + Any systems based on EV4 are expected to have an external backup cache + which is write-back, but it is also coherent with all DMA operations. The + primary caches are shadowed by the backup, and on a write hit, the + primary data (but not instruction) cache is invalidated. + Consequently, the routines to flush,sweep,purge,etc the data + stream are nops on EV4, but the corresponding routines for the + Istream must ensure that we cannot hit in the primary I cache + after a DMA operation. + + EV4 has a write buffer which contains 4 32-byte entries, which + must be flushable before DMA operations. The MB instruction is + used to accomplish this. + + There is no coloring support on EV4, so Color operations are + null. Zero page is unsupported because it has no users. Copy + page is not special because we lack coloring. + + We had to make a philosophical decision about what interfaces to + support in this file. (Almost) none of the interfaces defined in + the HAL spec are actually supported in either the i386 or MIPS + code. The i386 stream has almost no cache support at all. The + Mips stream has cache support, but most routines also refer to + coloring. Should we use the Spec'ed interfaces, or the Mips + interfaces? I have elected the Mips interfaces because they are + in use, and we are stealing much of the Mips code which expects + these interfaces. Besides, the only change we might make is to + remove the coloring arguments, but they may be used on Alpha + machines at some future date. + +Author: + + Miche Baker-Harvey (miche) 29-May-1992 + +Revision History: + + + 13-Jul-1992 Jeff McLeman (mcleman) + use HalpMb to do a memory barrier. Also, alter code and use super + pages to pass to rtl memory routines. + + 10-Jul-1992 Jeff McLeman (mcleman) + use HalpImb to call pal. + + 06-Jul-1992 Jeff McLeman (mcleman) + Move routine KeFlushDcache into this module. + Use only one memory barrier in the KeFlushWriteBuffer + routine. This is because the PAL for the EVx will + make sure the proper write ordering is done in PAL mode. + +--*/ + // Include files + +#include "halp.h" + + + +VOID +HalFlushDcache ( + IN BOOLEAN AllProcessors + ); + +// +// Cache and write buffer flush functions. +// + + +VOID +HalChangeColorPage ( + IN PVOID NewColor, + IN PVOID OldColor, + IN ULONG PageFrame + ) +/*++ + +Routine Description: + + This function changes the color of a page if the old and new colors + do not match. DECchip 21064-based machines do not have page coloring, and + therefore, this function performs no operation. + +Arguments: + + NewColor - Supplies the page aligned virtual address of the + new color of the page to change. + + OldColor - Supplies the page aligned virtual address of the + old color of the page to change. + + pageFrame - Supplies the page frame number of the page that + is changed. + +Return Value: + + None. + +--*/ +{ + return; +} + +VOID +HalFlushDcachePage ( + IN PVOID Color, + IN ULONG PageFrame, + IN ULONG Length + ) +/*++ + +Routine Description: + + This function flushes (invalidates) up to a page of data from the + data cache. + +Arguments: + + Color - Supplies the starting virtual address and color of the + data that is flushed. + PageFrame - Supplies the page frame number of the page that + is flushed. + + Length - Supplies the length of the region in the page that is + flushed. + +Return Value: + + None. + +--*/ +{ + return; +} + +VOID +HalFlushIoBuffers ( + IN PMDL Mdl, + IN BOOLEAN ReadOperation, + IN BOOLEAN DmaOperation + ) +/*++ +Routine Description: + + This function flushes the I/O buffer specified by the memory descriptor + list from the data cache on the current processor. + +Arguments: + + Mdl - Supplies a pointer to a memory descriptor list that describes the + I/O buffer location. + + ReadOperation - Supplies a boolean value that determines whether the I/O + operation is a read into memory. + + DmaOperation - Supplies a boolean value that determines whether the I/O + operation is a DMA operation. + +Return Value: + + None. + +--*/ +{ + // + // The Dcache coherency is maintained in hardware. The Icache coherency + // is maintained by invalidating the istream on page read operations. + // + HalpMb(); // synchronize this processors view of memory + if (ReadOperation) { + HalpMb(); // not issued until previous mb completes + if (Mdl->MdlFlags & MDL_IO_PAGE_READ) { + + // + // The operation is a page read, thus the istream must + // be flushed. + // + HalpImb(); + } + } +} + +VOID +HalPurgeDcachePage ( + IN PVOID Color, + IN ULONG PageFrame, + IN ULONG Length + ) +/*++ +Routine Description: + + This function purges (invalidates) up to a page of data from the + data cache. + +Arguments: + + Color - Supplies the starting virtual address and color of the + data that is purged. + + PageFrame - Supplies the page frame number of the page that + is purged. + + Length - Supplies the length of the region in the page that is + purged. + +Return Value: + + None. + +--*/ +{ + return; +} + + +VOID +HalPurgeIcachePage ( + IN PVOID Color, + IN ULONG PageFrame, + IN ULONG Length + ) +/*++ + +Routine Description: + + This function purges (invalidates) up to a page fo data from the + instruction cache. + +Arguments: + + Color - Supplies the starting virtual address and color of the + data that is purged. + + PageFrame - Supplies the page frame number of the page that + is purged. + + Length - Supplies the length of the region in the page that is + purged. + +Return Value: + + None. + +--*/ +{ + // + // The call to HalpImb calls PAL to flush the Icache, which ensures that + // any stale hits will be invalidated + // + HalpImb; +} + +VOID +HalSweepDcache ( + VOID + ) +/*++ + +Routine Description: + + This function sweeps (invalidates) the entire data cache. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + return; +} + +VOID +HalSweepDcacheRange ( + IN PVOID BaseAddress, + IN ULONG Length + ) +/*++ + +Routine Description: + + This function flushes the specified range of addresses from the data + cache on the current processor. + +Arguments: + + BaseAddress - Supplies the starting physical address of a range of + physical addresses that are to be flushed from the data cache. + + Length - Supplies the length of the range of physical addresses + that are to be flushed from the data cache. + +Return Value: + + None. + +--*/ +{ + return; +} + +VOID +HalSweepIcache ( + VOID + ) +/*++ + +Routine Description: + + This function sweeps (invalidates) the entire instruction cache. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + // + // The call to HalpImb calls PAL to flush the Icache, which ensures that + // any stale hits will be invalidated + // + HalpImb; + return; +} + +VOID +HalSweepIcacheRange ( + IN PVOID BaseAddress, + IN ULONG Length + ) +/*++ + +Routine Description: + + This function flushes the specified range of addresses from the + instruction cache on the current processor. + +Arguments: + + BaseAddress - Supplies the starting physical address of a range of + physical addresses that are to be flushed from the instruction cache. + + Length - Supplies the length of the range of physical addresses + that are to be flushed from the instruction cache. + +Return Value: + + None. + +--*/ +{ + // + // The call to HalpImb calls PAL to flush the Icache, which ensures that + // any stale hits will be invalidated + // + HalpImb; + +} + +VOID +KeFlushWriteBuffer ( + VOID + ) + +{ + // + // We flush the write buffer by doing a series of memory + // barrier operations. It still isn't clear if we need + // to do two/four of them to flush the buffer, or if one + // to order the writes is suffcient + // + + HalpMb; + return; +} + +VOID +KeFlushDcache ( + IN BOOLEAN AllProcessors, + IN PVOID BaseAddress OPTIONAL, + IN ULONG Length + ) + +/*++ + +Routine Description: + + This function flushes the data cache on all processors that are currently + running threads which are children of the current process or flushes the + data cache on all processors in the host configuration. + +Arguments: + + AllProcessors - Supplies a boolean value that determines which data + caches are flushed. + +Return Value: + + None. + +--*/ + +{ + UNREFERENCED_PARAMETER(BaseAddress); + UNREFERENCED_PARAMETER(Length); + + HalFlushDcache(AllProcessors); + return; +} + +VOID +HalFlushDcache ( + IN BOOLEAN AllProcessors + ) + +/*++ + +Routine Description: + + This function flushes the data cache on all processors that are currently + running threads which are children of the current process or flushes the + data cache on all processors in the host configuration. + +Arguments: + + AllProcessors - Supplies a boolean value that determines which data + caches are flushed. + +Return Value: + + None. + +--*/ + +{ + + // + // Sweep (index/writeback/invalidate) the data cache. + // + + HalSweepDcache(); + return; +} + +ULONG +HalGetDmaAlignmentRequirement ( + VOID + ) + +/*++ + +Routine Description: + + This function returns the alignment requirements for DMA transfers on + host system. + +Arguments: + + None. + +Return Value: + + The DMA alignment requirement is returned as the fucntion value. + +--*/ + +{ + + return 8; +} diff --git a/private/ntos/nthals/halalpha/ev4int.c b/private/ntos/nthals/halalpha/ev4int.c new file mode 100644 index 000000000..71a4c9dd1 --- /dev/null +++ b/private/ntos/nthals/halalpha/ev4int.c @@ -0,0 +1,1013 @@ +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + ev4int.c + +Abstract: + + This module implements the support routines to enable/disable DECchip + 21064-specific interrupts. + +Author: + + Joe Notarangelo 27-Sep-1993 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" +#include "axp21064.h" + +VOID +HalpUpdate21064PriorityTable( + VOID + ); + +VOID +HalpCachePcrValues( + VOID + ); + + + +VOID +HalpInitialize21064Interrupts( + VOID + ) +/*++ + +Routine Description: + + This routine initializes the data structures for the 21064 + interrupt enable/disable routines. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + ULONG Index; + EV4Irq Irq; + + // + // Initialize each entry in the Irq Status Table. + // + + for( Irq=Irq0; IrqIrqStatusTable[Irq].Enabled = FALSE; + HAL_PCR->IrqStatusTable[Irq].Irql = PASSIVE_LEVEL; + HAL_PCR->IrqStatusTable[Irq].Vector = PASSIVE_VECTOR; + HAL_PCR->IrqStatusTable[Irq].Priority = 0; + } + + HalpUpdate21064PriorityTable(); + + // + // Write IrqlMask table entries for the Software Subtable. + // + + Index = IRQLMASK_SFW_SUBTABLE_21064; + + PCR->IrqlMask[Index].IrqlTableIndex = PASSIVE_LEVEL; + PCR->IrqlMask[Index].IDTIndex = PASSIVE_VECTOR; + Index += 1; + + PCR->IrqlMask[Index].IrqlTableIndex = APC_LEVEL; + PCR->IrqlMask[Index].IDTIndex = APC_VECTOR; + Index += 1; + + PCR->IrqlMask[Index].IrqlTableIndex = DISPATCH_LEVEL; + PCR->IrqlMask[Index].IDTIndex = DISPATCH_VECTOR; + Index += 1; + + PCR->IrqlMask[Index].IrqlTableIndex = DISPATCH_LEVEL; + PCR->IrqlMask[Index].IDTIndex = DISPATCH_VECTOR; + + // + // Write the IrqlMask table entries for the Performance Counter Subtable. + // + + Index = IRQLMASK_PC_SUBTABLE_21064; + + PCR->IrqlMask[Index].IrqlTableIndex = PASSIVE_LEVEL; + PCR->IrqlMask[Index].IDTIndex = PASSIVE_VECTOR; + Index += 1; + + PCR->IrqlMask[Index].IrqlTableIndex = PROFILE_LEVEL; + PCR->IrqlMask[Index].IDTIndex = PC0_VECTOR; + Index += 1; + + PCR->IrqlMask[Index].IrqlTableIndex = PROFILE_LEVEL; + PCR->IrqlMask[Index].IDTIndex = PC1_VECTOR; + Index += 1; + + PCR->IrqlMask[Index].IrqlTableIndex = PROFILE_LEVEL; + PCR->IrqlMask[Index].IDTIndex = PC1_VECTOR; + + return; + +} + +VOID +HalpUpdate21064PriorityTable( + VOID + ) +/*++ + +Routine Description: + + This function updates the Irql Mask Table in the PCR of the current + processor. It is called whenever an interrupt is enabled or disabled. + The source of the data used to update the table is the global + IrqStatusTable. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + ULONG InterruptMask; + EV4Irq Irq; + KIRQL Irql; + ULONG IrqlMaskIndex; + UCHAR Priority; + ULONG Vector; + + // + // Cycle through each entry of the interrupt mask table for the + // hardware entries. For each entry, compute the highest priority + // entry that could be asserted for the mask entry and is enabled. + // The priority is determined first by Irql level, higher Irql + // indicates higher priority, and then, if there are multiple + // enabled, asserted interrupts of the same Irql, by a relative + // priority that was assigned by the caller when the interrupt + // was enabled. + // + + for( InterruptMask=0; + InterruptMask < IRQLMASK_HDW_SUBTABLE_21064_ENTRIES; + InterruptMask++ ){ + + Vector = PASSIVE_VECTOR; + Irql = PASSIVE_LEVEL; + Priority = 0; + + // + // Check if each Irq is asserted and enabled for this interrupt + // mask. + // + + for( Irq=Irq0; IrqIrqStatusTable[Irq].Enabled == TRUE) && + (HAL_PCR->IrqStatusTable[Irq].Irql >= Irql) ){ + + // + // If the new Irq has a higher Irql than the highest + // currently selected or has a higher relative priority + // then this is the Irq to be selected if this mask + // pattern is selected. + // + + if( (HAL_PCR->IrqStatusTable[Irq].Irql > Irql) || + (HAL_PCR->IrqStatusTable[Irq].Priority > Priority) ){ + + Irql = HAL_PCR->IrqStatusTable[Irq].Irql; + Priority = HAL_PCR->IrqStatusTable[Irq].Priority; + Vector = HAL_PCR->IrqStatusTable[Irq].Vector; + + } + + } + } + + IrqlMaskIndex = IRQLMASK_HDW_SUBTABLE_21064 + InterruptMask; + PCR->IrqlMask[IrqlMaskIndex].IrqlTableIndex = Irql; + PCR->IrqlMask[IrqlMaskIndex].IDTIndex = (USHORT)Vector; + } +} + +VOID +HalpDisable21064HardwareInterrupt( + IN ULONG Irq + ) +/*++ + +Routine Description: + + This routine disables the interrupt connected to the specified Irq + pin on the 21064. + +Arguments: + + Irq - Supplies the number of the Irq pin for the interrupt that is disabled. + +Return Value: + + None. + +--*/ +{ + + KIRQL IrqlIndex; + PIETEntry_21064 IetEntry; + KIRQL OldIrql; + + // + // Raise IRQL to the highest level. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + IetEntry = (PIETEntry_21064)(&PCR->IrqlTable); + IrqlIndex = PASSIVE_LEVEL; + + // + // Update the enable table for all the Irqls such that the interrupt + // is disabled. + // + + while( IrqlIndex <= HIGH_LEVEL ){ + + switch( Irq ){ + + case Irq0: + + IetEntry[IrqlIndex].Irq0Enable = 0; + break; + + case Irq1: + + IetEntry[IrqlIndex].Irq1Enable = 0; + break; + + case Irq2: + + IetEntry[IrqlIndex].Irq2Enable = 0; + break; + + case Irq3: + + IetEntry[IrqlIndex].Irq3Enable = 0; + break; + + case Irq4: + + IetEntry[IrqlIndex].Irq4Enable = 0; + break; + + case Irq5: + + IetEntry[IrqlIndex].Irq5Enable = 0; + break; + + + } //end switch( Irq ) + + IrqlIndex++; + + } //end while IrqlIndex <= HIGH_LEVEL + + // + // Update the Irq status table and reflect the changes in the + // PCR IrqlMask table. + // + + HAL_PCR->IrqStatusTable[Irq].Enabled = FALSE; + + // + // Alert the PAL that the enable table has changed so that it can + // reload the new values. + // + + HalpCachePcrValues(); + + // + // Lower IRQL to the previous level. + // + + KeLowerIrql(OldIrql); + return; + +} + + +VOID +HalpDisable21064SoftwareInterrupt( + IN KIRQL Irql + ) +/*++ + +Routine Description: + + This routine disables the indicated software interrupt level. + +Arguments: + + Irql - Supplies the software interrupt level to disable (APC_LEVEL or + DISPATCH_LEVEL). + +Return Value: + + None. + +--*/ +{ + + PIETEntry_21064 IetEntry; + KIRQL OldIrql; + + // + // Raise IRQL to the highest level. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + IetEntry = (PIETEntry_21064)(&PCR->IrqlTable); + + switch( Irql ){ + + // + // APC Interrupt level. + // + + case APC_LEVEL: + + IetEntry[PASSIVE_LEVEL].ApcEnable = 0; + break; + + // + // DPC Interrupt level. + // + + case DISPATCH_LEVEL: + + IetEntry[PASSIVE_LEVEL].DispatchEnable = 0; + IetEntry[APC_LEVEL].DispatchEnable = 0; + break; + + // + // Unrecognized software interrupt level. + // + + default: + + NOTHING; + +#if HALDBG + + DbgPrint( "HalpDisable21064SoftwareInterrupt, Bad software level= %x\n", + Irql ); + +#endif //HALDBG + + } + + // + // Alert the PAL that the enable table has changed so that it can + // reload the new values. + // + + HalpCachePcrValues(); + + // + // Lower IRQL to the previous level. + // + + KeLowerIrql(OldIrql); + return; +} + + +VOID +HalpDisable21064PerformanceInterrupt( + IN ULONG Vector + ) +/*++ + +Routine Description: + + This routine disables the specified performance counter interrupt. + +Arguments: + + Vector - Supplies the interrupt vector number of the performance counter + interrupt which is disabled. + +Return Value: + + None. + +--*/ +{ + + KIRQL IrqlIndex; + PIETEntry_21064 IetEntry; + KIRQL OldIrql; + + // + // Raise IRQL to the highest level. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + IetEntry = (PIETEntry_21064)(&PCR->IrqlTable); + IrqlIndex = PASSIVE_LEVEL; + + // + // Update the enable table for all the Irqls such that the interrupt + // is disabled. + // + + while( IrqlIndex <= HIGH_LEVEL ){ + + switch( Vector ){ + + case PC0_VECTOR: + case PC0_SECONDARY_VECTOR: + + IetEntry[IrqlIndex].PerformanceCounter0Enable = 0; + break; + + case PC1_VECTOR: + case PC1_SECONDARY_VECTOR: + + IetEntry[IrqlIndex].PerformanceCounter1Enable = 0; + break; + + + } //end switch( Vector ) + + IrqlIndex++; + + } //end while IrqlIndex <= HIGH_LEVEL + + // + // Alert the PAL that the enable table has changed so that it can + // reload the new values. + // + + HalpCachePcrValues(); + + // + // Lower IRQL to the previous level. + // + + KeLowerIrql(OldIrql); + return; +} + +VOID +HalpDisable21064CorrectableInterrupt( + VOID + ) +/*++ + +Routine Description: + + This routine disables the correctable read error interrupt. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + + KIRQL IrqlIndex; + PIETEntry_21064 IetEntry; + KIRQL OldIrql; + + // + // Raise IRQL to the highest level. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + IetEntry = (PIETEntry_21064)(&PCR->IrqlTable); + IrqlIndex = PASSIVE_LEVEL; + + // + // Update the enable table for all the Irqls such that the interrupt + // is disabled. + // + + while( IrqlIndex <= HIGH_LEVEL ){ + + IetEntry[IrqlIndex].CorrectableReadEnable = 0; + + IrqlIndex++; + + } //end while IrqlIndex <= HIGH_LEVEL + + // + // Alert the PAL that the enable table has changed so that it can + // reload the new values. + // + + HalpCachePcrValues(); + + // + // Lower IRQL to the previous level. + // + + KeLowerIrql(OldIrql); + return; +} + +VOID +HalpEnable21064HardwareInterrupt ( + IN ULONG Irq, + IN KIRQL Irql, + IN ULONG Vector, + IN UCHAR Priority + ) + +/*++ + +Routine Description: + + This routine enables the specified system interrupt. + +Arguments: + + Irq - Supplies the IRQ pin number of the interrupt that is enabled. + + Irql - Supplies the Irql of the interrupting source. + + Vector - Supplies the interrupt vector for the enabled interrupt. + + Priority - Supplies the relative priority of the interrupt in comparison + with other Irqs of the same Irql. + +Return Value: + + None. + +--*/ + +{ + + KIRQL IrqlIndex; + PIETEntry_21064 IetEntry; + KIRQL OldIrql; + + // + // Raise IRQL to the highest level. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + + IetEntry = (PIETEntry_21064)(&PCR->IrqlTable); + IrqlIndex = PASSIVE_LEVEL; + + // + // Update the enable table for each Irql that the interrupt should + // be enabled. + // + + while( IrqlIndex < Irql ){ + + switch( Irq ){ + + case Irq0: + + IetEntry[IrqlIndex].Irq0Enable = 1; + break; + + case Irq1: + + IetEntry[IrqlIndex].Irq1Enable = 1; + break; + + case Irq2: + + IetEntry[IrqlIndex].Irq2Enable = 1; + break; + + case Irq3: + + IetEntry[IrqlIndex].Irq3Enable = 1; + break; + + case Irq4: + + IetEntry[IrqlIndex].Irq4Enable = 1; + break; + + case Irq5: + + IetEntry[IrqlIndex].Irq5Enable = 1; + break; + + } // end switch( Vector ) + + IrqlIndex++; + + } //end while IrqlIndex < Irql + + // + // Populate the interrupt status table and then update the Irql Mask + // table. + // + + HAL_PCR->IrqStatusTable[Irq].Enabled = TRUE; + HAL_PCR->IrqStatusTable[Irq].Vector = Vector; + HAL_PCR->IrqStatusTable[Irq].Irql = Irql; + HAL_PCR->IrqStatusTable[Irq].Priority = Priority; + + HalpUpdate21064PriorityTable(); + + // + // Alert the PAL that the enable table has changed so that it can + // reload the new values. + // + + HalpCachePcrValues(); + + // + // Lower IRQL to the previous level. + // + + KeLowerIrql(OldIrql); + return; +} + + +VOID +HalpEnable21064SoftwareInterrupt( + IN KIRQL Irql + ) +/*++ + +Routine Description: + + This routine enables the indicated software interrupt level. + +Arguments: + + Irql - Supplies the software interrupt level to enable (APC_LEVEL or + DISPATCH_LEVEL). + +Return Value: + + None. + +--*/ +{ + + PIETEntry_21064 IetEntry; + KIRQL OldIrql; + + // + // Raise IRQL to the highest level. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + IetEntry = (PIETEntry_21064)(&PCR->IrqlTable); + + switch( Irql ){ + + // + // APC Interrupt level. + // + + case APC_LEVEL: + + IetEntry[PASSIVE_LEVEL].ApcEnable = 1; + break; + + // + // DPC Interrupt level. + // + + case DISPATCH_LEVEL: + + IetEntry[PASSIVE_LEVEL].DispatchEnable = 1; + IetEntry[APC_LEVEL].DispatchEnable = 1; + break; + + // + // Unrecognized software interrupt level. + // + + default: + + NOTHING; + +#if HALDBG + + DbgPrint( "HalpEnable21064SoftwareInterrupt, Bad software level= %x\n", + Irql ); + +#endif //HALDBG + + } + + // + // Alert the PAL that the enable table has changed so that it can + // reload the new values. + // + + HalpCachePcrValues(); + + // + // Lower IRQL to the previous level. + // + + KeLowerIrql(OldIrql); + return; + +} + + +VOID +HalpEnable21064PerformanceInterrupt ( + IN ULONG Vector, + IN KIRQL Irql + ) + +/*++ + +Routine Description: + + This routine enables the specified performance counter interrupt. + +Arguments: + + Vector - Supplies the vector of the performance counter interrupt that is + enabled. + + Irql - Supplies the Irql of the performance counter interrupt. + +Return Value: + + None. + +--*/ + +{ + + KIRQL IrqlIndex; + PIETEntry_21064 IetEntry; + KIRQL OldIrql; + + // + // Raise IRQL to the highest level. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + + IetEntry = (PIETEntry_21064)(&PCR->IrqlTable); + IrqlIndex = PASSIVE_LEVEL; + + // + // Update the enable table for each Irql that the interrupt should + // be enabled. + // + + while( IrqlIndex < Irql ){ + + switch( Vector ){ + + case PC0_VECTOR: + case PC0_SECONDARY_VECTOR: + + IetEntry[IrqlIndex].PerformanceCounter0Enable = 1; + break; + + case PC1_VECTOR: + case PC1_SECONDARY_VECTOR: + + IetEntry[IrqlIndex].PerformanceCounter1Enable = 1; + break; + + } // end switch( Vector ) + + IrqlIndex++; + + } //end while IrqlIndex < Irql + + // + // Alert the PAL that the enable table has changed so that it can + // reload the new values. + // + + HalpCachePcrValues(); + + // + // Lower IRQL to the previous level. + // + + KeLowerIrql(OldIrql); + return; +} + +VOID +HalpEnable21064CorrectableInterrupt ( + IN KIRQL Irql + ) + +/*++ + +Routine Description: + + This routine enables the correctable read error interrupt. + +Arguments: + + Irql - Supplies the Irql of the correctable read error interrupt. + +Return Value: + + None. + +--*/ + +{ + + KIRQL IrqlIndex; + PIETEntry_21064 IetEntry; + KIRQL OldIrql; + + // + // Raise IRQL to the highest level. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + + IetEntry = (PIETEntry_21064)(&PCR->IrqlTable); + IrqlIndex = PASSIVE_LEVEL; + + // + // Update the enable table for each Irql that the interrupt should + // be enabled. + // + + while( IrqlIndex < Irql ){ + + IetEntry[IrqlIndex].CorrectableReadEnable = 1; + + IrqlIndex++; + + } //end while IrqlIndex < Irql + + // + // Alert the PAL that the enable table has changed so that it can + // reload the new values. + // + + HalpCachePcrValues(); + + // + // Lower IRQL to the previous level. + // + + KeLowerIrql(OldIrql); + return; +} + + +ULONG +HalpGet21064PerformanceVector( + IN ULONG BusInterruptLevel, + OUT PKIRQL Irql + ) + +/*++ + +Routine Description: + + This function returns the system interrupt vector and IRQL level + corresponding to the specified performance counter interrupt. + +Arguments: + + BusInterruptLevel - Supplies the performance counter number. + + Irql - Returns the system request priority. + +Return Value: + + Returns the system interrupt vector corresponding to the specified device. + +--*/ + +{ + + // + // Handle the special internal bus defined for the processor itself + // and used to control the performance counters in the 21064. + // + + *Irql = PROFILE_LEVEL; + + switch( BusInterruptLevel ){ + + // + // Performance Counter 0 + // + + case 0: + + return PC0_SECONDARY_VECTOR; + + // + // Performance Counter 1 + // + + case 1: + + return PC1_SECONDARY_VECTOR; + + } //end switch( BusInterruptLevel ) + + // + // Unrecognized. + // + + *Irql = 0; + return 0; + +} + + +ULONG +HalpGet21064CorrectableVector( + IN ULONG BusInterruptLevel, + OUT PKIRQL Irql + ) + +/*++ + +Routine Description: + + This function returns the system interrupt vector and IRQL level + corresponding to the specified correctable interrupt. + +Arguments: + + BusInterruptLevel - Supplies the performance counter number. + + Irql - Returns the system request priority. + +Return Value: + + Returns the system interrupt vector corresponding to the specified device. + +--*/ + +{ + // + // Get the correctable interrupt vector. + // + + if (BusInterruptLevel == 5) { + + // + // Correctable error interrupt was sucessfully recognized. + // + + *Irql = DEVICE_LEVEL; + return CORRECTABLE_VECTOR; + + + } else { + + // + // Unrecognized. + // + + *Irql = 0; + return 0; + } +} + diff --git a/private/ntos/nthals/halalpha/ev4ints.s b/private/ntos/nthals/halalpha/ev4ints.s new file mode 100644 index 000000000..aaa06db87 --- /dev/null +++ b/private/ntos/nthals/halalpha/ev4ints.s @@ -0,0 +1,272 @@ +//++ +// +// Copyright (c) 1994 Microsoft Corporation +// +// Module Name: +// +// ev4ints.s +// +// Abstract: +// +// This module implements EV4-specific interrupt handlers. +// (the performance counters) +// +// Author: +// +// John Vert (jvert) 15-Nov-1994 +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +//-- +#include "halalpha.h" + +#define PC0_SECONDARY_VECTOR 11 +#define PC1_SECONDARY_VECTOR 13 +#define PcProfileCount0 PcHalReserved+8 +#define PcProfileCount1 PcProfileCount0+4 +#define PcProfileCountReload0 PcProfileCount1+4 +#define PcProfileCountReload1 PcProfileCountReload0+4 + + .struct 0 + .space 8 // reserved for alignment +PrRa: .space 8 // space for return address +PrFrameLength: // + + SBTTL("Performance Counter 0 Interrupt") +//++ +// +// VOID +// HalpPerformanceCounter0Interrupt +// ) +// +// Routine Description: +// +// This function is executed as the result of an interrupt from the +// internal microprocessor performance counter 0. The interrupt +// may be used to signal the completion of a profile event. +// If profiling is current active, the function determines if the +// profile interval has expired and if so dispatches to the standard +// system routine to update the system profile time. If profiling +// is not active then the function performs a secondary dispatch for +// performance counter 0. +// +// Arguments: +// +// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for +// the interrupt. +// +// Return Value: +// +// TRUE is returned. +// +//-- + + NESTED_ENTRY(HalpPerformanceCounter0Interrupt, PrFrameLength, zero ) + + lda sp, -PrFrameLength(sp) // allocate a stack frame + stq ra, PrRa(sp) // save the return address + + PROLOGUE_END // + + call_pal rdpcr // v0 = pcr base address + + ldl t0, PcProfileCount0(v0) // capture the current profile count + beq t0, 20f // if eq, profiling not active + +// +// Profiling is active. Decrement the interval count and if it has +// reached zero then call the kernel profile routine. +// + + subl t0, 1, t0 // decrement the interval count + bne t0, 10f // if ne, interval has not expired + +// +// The profile interval has expired. Reset the profile interval count +// and process the profile interrupt. +// + + ldl t0, PcProfileCountReload0(v0) // get the new tick count + stl t0, PcProfileCount0(v0) // reset the profile interval count + + ldl a1, HalpProfileSource0 + bis fp, zero, a0 // pass trap frame pointer + ldl t1, __imp_KeProfileInterruptWithSource + jsr ra, (t1) // process the profile interrupt + + br zero, 40f // common return + +// +// The profile interval has not expired. Update the decremented count. +// + +10: + stl t0, PcProfileCount0(v0) // update profile interval count + br zero, 40f // common return + +// +// Profiling is not active. Therefore, this interrupt was caused by +// a performance counter driver. Deliver a secondary dispatch. +// + +20: + + ldil a0, PC0_SECONDARY_VECTOR // get IDT vector for secondary + s4addl a0, v0, a0 // a0 = PCR + IDT index + ldl a0, PcInterruptRoutine(a0) // get service routine address + jsr ra, (a0) // call interrupt service routine + +// +// Setup for return. +// + +40: + ldil v0, TRUE // set return value = TRUE + ldq ra, PrRa(sp) // restore return address + lda sp, PrFrameLength(sp) // deallocate the stack frame + ret zero, (ra) // return + + .end HalpPerformanceCounter0Interrupt + + + SBTTL("Performance Counter 1 Interrupt") +//++ +// +// VOID +// HalpPerformanceCounter1Interrupt +// ) +// +// Routine Description: +// +// This function is executed as the result of an interrupt from the +// internal microprocessor performance counter 1. The interrupt +// may be used to signal the completion of a profile event. +// If profiling is current active, the function determines if the +// profile interval has expired and if so dispatches to the standard +// system routine to update the system profile time. If profiling +// is not active then the function performs a secondary dispatch for +// performance counter 1. +// +// Arguments: +// +// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for +// the interrupt. +// +// Return Value: +// +// TRUE is returned. +// +//-- + + NESTED_ENTRY(HalpPerformanceCounter1Interrupt, PrFrameLength, zero ) + + lda sp, -PrFrameLength(sp) // allocate a stack frame + stq ra, PrRa(sp) // save the return address + + PROLOGUE_END // + + call_pal rdpcr // v0 = pcr base address + + ldl t0, PcProfileCount1(v0) // capture the current profile count + beq t0, 20f // if eq, profiling not active + +// +// Profiling is active. Decrement the interval count and if it has +// reached zero then call the kernel profile routine. +// + + subl t0, 1, t0 // decrement the interval count + bne t0, 10f // if ne, interval has not expired + +// +// The profile interval has expired. Reset the profile interval count +// and process the profile interrupt. +// + + ldl t0, PcProfileCountReload1(v0) // get the new tick count + stl t0, PcProfileCount1(v0) // reset the profile interval count + + ldl a1, HalpProfileSource1 + bis fp, zero, a0 // pass trap frame pointer + ldl t1, __imp_KeProfileInterruptWithSource + jsr ra, (t1) // process the profile interrupt + + br zero, 40f // common return + +// +// The profile interval has not expired. Update the decremented count. +// + +10: + stl t0, PcProfileCount1(v0) // update profile interval count + br zero, 40f // common return + +// +// Profiling is not active. Therefore, this interrupt was caused by +// a performance counter driver. Deliver a secondary dispatch. +// + +20: + + ldil a0, PC1_SECONDARY_VECTOR // get IDT vector for secondary + s4addl a0, v0, a0 // a0 = PCR + IDT index + ldl a0, PcInterruptRoutine(a0) // get service routine address + jsr ra, (a0) // call interrupt service routine + +// +// Setup for return. +// + +40: + ldil v0, TRUE // set return value = TRUE + ldq ra, PrRa(sp) // restore return address + lda sp, PrFrameLength(sp) // deallocate the stack frame + ret zero, (ra) // return + + .end HalpPerformanceCounter1Interrupt + +//++ +// +// VOID +// HalpWritePerformanceCounter( +// IN ULONG PerformanceCounter, +// IN BOOLEAN Enable, +// IN ULONG MuxControl OPTIONAL, +// IN ULONG EventCount OPTIONAL +// ) +// +// Routine Description: +// +// Write the specified microprocessor internal performance counter. +// +// Arguments: +// +// PerformanceCounter(a0) - Supplies the number of the performance counter +// to write. +// +// Enable(a1) - Supplies a boolean that indicates if the performance +// counter should be enabled or disabled. +// +// MuxControl(a2) - Supplies the mux control value which selects which +// type of event to count when the counter is enabled. +// +// EventCount(a3) - Supplies the event interval when the counter is +// enabled. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpWritePerformanceCounter) + + call_pal wrperfmon // write the counter + + ret zero, (ra) // return + + .end HalpWritePerformanceCounter diff --git a/private/ntos/nthals/halalpha/ev4mchk.c b/private/ntos/nthals/halalpha/ev4mchk.c new file mode 100644 index 000000000..57fe29312 --- /dev/null +++ b/private/ntos/nthals/halalpha/ev4mchk.c @@ -0,0 +1,709 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + ev4mchk.c + +Abstract: + + This module implements generalized machine check handling for + platforms based on the DECchip 21064 (EV4) microprocessor. + +Author: + + Joe Notarangelo 14-Feb-1994 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "halp.h" +#include "axp21064.h" +#include "stdio.h" + + +// +// Declare the extern variable UncorrectableError declared in +// inithal.c. +// +extern PERROR_FRAME PUncorrectableError; + +VOID +HalpDisplayLogout21064( + IN PLOGOUT_FRAME_21064 LogoutFrame ); + +BOOLEAN +HalpPlatformMachineCheck( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN PKTRAP_FRAME TrapFrame + ); + +VOID +HalpUpdateMces( + IN BOOLEAN ClearMachineCheck, + IN BOOLEAN ClearCorrectableError + ); + +// +// MAX_RETRYABLE_ERRORS is the number of times to retry machine checks before +// just giving up. +// + +#define MAX_RETRYABLE_ERRORS 32 + +// +// System-wide controls for machine check reporting. +// + +ProcessorCorrectableDisable = FALSE; +SystemCorrectableDisable = FALSE; +MachineCheckDisable = FALSE; + +// +//jnfix - temporary counts +// + +ULONG CorrectableErrors = 0; +ULONG RetryableErrors = 0; + +VOID +HalpSetMachineCheckEnables( + IN BOOLEAN DisableMachineChecks, + IN BOOLEAN DisableProcessorCorrectables, + IN BOOLEAN DisableSystemCorrectables + ) +/*++ + +Routine Description: + + This function sets the enables that define which machine check + errors will be signaled by the processor. + + N.B. - The system has the capability to ignore all machine checks + by indicating DisableMachineChecks = TRUE. This is intended + for debugging purposes on broken hardware. If you disable + this you will get no machine check no matter what error the + system/processor detects. Consider the consequences. + +Arguments: + + DisableMachineChecks - Supplies a boolean which indicates if all + machine checks should be disabled and not + reported. (see note above). + + DisableProcessorCorrectables - Supplies a boolean which indicates if + processor correctable error reporting + should be disabled. + DisableSystemCorrectables - Supplies a boolean which indicates if + system correctable error reporting + should be disabled. + +Return Value: + + None. + +--*/ +{ + + + ProcessorCorrectableDisable = DisableProcessorCorrectables; + SystemCorrectableDisable = DisableSystemCorrectables; + MachineCheckDisable = DisableMachineChecks; + + HalpUpdateMces( FALSE, FALSE ); + + return; +} + +VOID +HalpUpdateMces( + IN BOOLEAN ClearMachineCheck, + IN BOOLEAN ClearCorrectableError + ) +/*++ + +Routine Description: + + This function updates the state of the MCES internal processor + register. + +Arguments: + + ClearMachineCheck - Supplies a boolean that indicates if the machine + check indicator in the MCES should be cleared. + + ClearCorrectableError - Supplies a boolean that indicates if the + correctable error indicators in the MCES should + be cleared. + +Return Value: + + None. + +--*/ +{ + MCES Mces; + + Mces.MachineCheck = ClearMachineCheck; + Mces.SystemCorrectable = ClearCorrectableError; + Mces.ProcessorCorrectable = ClearCorrectableError; + Mces.DisableProcessorCorrectable = ProcessorCorrectableDisable; + Mces.DisableSystemCorrectable = SystemCorrectableDisable; + Mces.DisableMachineChecks = MachineCheckDisable; + + HalpWriteMces( Mces ); + +} + + +BOOLEAN +HalMachineCheck ( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN PKTRAP_FRAME TrapFrame + ) +/*++ + +Routine Description: + + This function fields machine check for 21064-based machines with + parity memory protection. + +Arguments: + + ExceptionRecord - Supplies a pointer to the exception record for the + machine check. Included in the exception information + is the pointer to the logout frame. + + ExceptionFrame - Supplies a pointer to the kernel exception frame. + + TrapFrame - Supplies a pointer to the kernel trap frame. + +Return Value: + + A value of TRUE is returned if the machine check has been + handled by the HAL. If it has been handled then execution may + resume at the faulting address. Otherwise, a value of FALSE + is returned. + + N.B. - under some circumstances this routine may not return at + all. + +--*/ + +{ + + PBIU_STAT_21064 BiuStat; + BOOLEAN Handled; + PLOGOUT_FRAME_21064 LogoutFrame; + PMCHK_STATUS MachineCheckStatus; + MCES Mces; + BOOLEAN UnhandledPlatformError = FALSE; + + PUNCORRECTABLE_ERROR uncorrerr = NULL; + PPROCESSOR_EV4_UNCORRECTABLE ev4uncorr = NULL; + + + // + // This is a parity machine. If we receive a machine check it + // is uncorrectable. We will print the logout frame and then we + // will bugcheck. + // + // However, we will first check that the machine check is not + // marked as correctable. If the machine check is correctable it uses + // a differently formatted logout frame. We will ignore the frame + // for any machine check marked as correctable since it is an impossible + // condition on a parity machine. + // + + MachineCheckStatus = + (PMCHK_STATUS)&ExceptionRecord->ExceptionInformation[0]; + + // + // Handle any processor correctable errors. + // + + if( MachineCheckStatus->Correctable == 1 ){ + + // + // Log the error. + // + //jnfix - temporary code + // simply assume this was a fill ecc correctable for now, print + // a debug message periodically + + CORRECTABLE_FRAME_21064 *CorrectableFrame; + + CorrectableFrame = + (CORRECTABLE_FRAME_21064 *)ExceptionRecord->ExceptionInformation[1]; + + CorrectableErrors += 1; + +#if (DBG) || (HALDBG) + + if( (CorrectableErrors % 32) == 0 ){ + DbgPrint( "Correctable errors = %d, Error Address = 0x%016Lx\n", + CorrectableFrame->FillAddr ); + } + +#endif //DBG || HALDBG + + // + // Acknowledge receipt of the correctable error by clearing + // the error in the MCES register. + // + + HalpUpdateMces( FALSE, TRUE ); + + return TRUE; + } + + // + // Handle any retryable errors. + // + + if( MachineCheckStatus->Retryable == 1 ){ + + // + // Increment the number of retryable machine checks. + // + + RetryableErrors += 1; + +#if (DBG) || (HALDBG) + + DbgPrint( "HAL Retryable Errors = %d\n", RetryableErrors ); + +#endif //DBG || HALDBG + + // + // We'll retry MAX_RETRYABLE_ERRORS times and then give up. We + // do this to avoid infinite retry loops. + // + + if( RetryableErrors <= MAX_RETRYABLE_ERRORS ){ + + // + // Acknowledge receipt of the retryable machine check. + // + + HalpUpdateMces( TRUE, TRUE ); + + return TRUE; + } + } + + // + // Capture the logout frame pointer. + // + + LogoutFrame = + (PLOGOUT_FRAME_21064)ExceptionRecord->ExceptionInformation[1]; + + if(PUncorrectableError) { + + // + // Fill in the processor specific uncorrectable error frame + // + uncorrerr = (PUNCORRECTABLE_ERROR) + &PUncorrectableError->UncorrectableFrame; + + // + // first fill in some generic processor Information. + // For the Current (Reporting) Processor. + // + HalpGetProcessorInfo(&uncorrerr->ReportingProcessor); + uncorrerr->Flags.ProcessorInformationValid = 1; + + ev4uncorr = (PPROCESSOR_EV4_UNCORRECTABLE) + uncorrerr->RawProcessorInformation; + } + if(ev4uncorr) { + + ev4uncorr->BiuStat = ((ULONGLONG)LogoutFrame->BiuStat.all.HighPart << + 32) | LogoutFrame->BiuStat.all.LowPart; + + ev4uncorr->BiuAddr = ((ULONGLONG)LogoutFrame->BiuAddr.HighPart << 32) | + LogoutFrame->BiuAddr.LowPart; + + ev4uncorr->AboxCtl = ((ULONGLONG)LogoutFrame->AboxCtl.all.HighPart << + 32) | LogoutFrame->AboxCtl.all.LowPart; + + ev4uncorr->BiuCtl = ((ULONGLONG)LogoutFrame->BiuCtl.HighPart << 32) | + LogoutFrame->BiuCtl.LowPart; + + ev4uncorr->CStat = ((ULONGLONG)LogoutFrame->DcStat.all.HighPart << + 32) | LogoutFrame->DcStat.all.LowPart; + + ev4uncorr->BcTag = ((ULONGLONG)LogoutFrame->BcTag.all.HighPart << + 32 ) | LogoutFrame->BcTag.all.LowPart; + + ev4uncorr->FillAddr = ((ULONGLONG)LogoutFrame->FillAddr.HighPart << + 32) | LogoutFrame->FillAddr.LowPart; + + ev4uncorr->FillSyndrome = + ((ULONGLONG)LogoutFrame->FillSyndrome.all.HighPart << 32) | + LogoutFrame->FillSyndrome.all.LowPart; + } + + // + // Check for any hard errors that cannot be dismissed. + // They are: + // Tag parity error + // Tag control parity error + // Multiple external errors + // Fill ECC error + // Fill parity error + // Multiple fill errors + // + + BiuStat = (PBIU_STAT_21064)&LogoutFrame->BiuStat; + + if( (BiuStat->bits.BcTperr == 1) || + (BiuStat->bits.BcTcperr == 1) || + (BiuStat->bits.Fatal1 == 1) || + (BiuStat->bits.FillEcc == 1) || + (BiuStat->bits.FillDperr == 1) || + (BiuStat->bits.Fatal2 == 1) ) { + + // + // set the flag to indicate that the processor information is valid. + // + uncorrerr->Flags.ProcessorInformationValid = 1; + uncorrerr->Flags.ErrorStringValid = 1; + sprintf(uncorrerr->ErrorString,"Uncorrectable Error From " + "Processor Detected"); + + // + // A serious, uncorrectable error has occured, under no circumstances + // can it be simply dismissed. + // + + goto FatalError; + + } + +//jnfix - dcache parity error checking for EV45? + + // + // It is possible that the system has experienced a hard error and + // that nonetheless the error is recoverable. This is a system-specific + // decision - allow it to be handled as such. + // + + UnhandledPlatformError = TRUE; + if( (Handled = HalpPlatformMachineCheck( + ExceptionRecord, + ExceptionFrame, + TrapFrame )) == TRUE ){ + + // + // The system-specific code has handled the error. Dismiss + // the error and continue execution. + // + + HalpUpdateMces( TRUE, TRUE ); + + return TRUE; + + } + +// +// The system has experienced a fatal error that cannot be corrected. +// Print any possible relevant information and crash the system. +// +// N.B. - In the future some of these fatal errors could be potential +// recovered. Example, a user process gets a fatal error on one +// of its pages - we kill the user process, mark the page as bad +// and continue executing. +// + +FatalError: + + // + // Begin the error output if this is a processor error. If this is + // an unhandled platform error than that code is responsible for + // beginning the error output. + // + + if( UnhandledPlatformError == FALSE ){ + + // + // Acquire ownership of the display. This is done here in case we take + // a machine check before the display has been taken away from the HAL. + // When the HAL begins displaying strings after it has lost the + // display ownership then the HAL will be careful not to scroll + // information off of the screen. + // + + HalAcquireDisplayOwnership(NULL); + + // + // Display the dreaded banner. + // + + HalDisplayString( "\nFatal system hardware error.\n\n" ); + + } + + // + // Display the EV4 logout frame. + // + + HalpDisplayLogout21064( LogoutFrame ); + + // + // Bugcheck to dump the rest of the machine state, this will help + // if the machine check is software-related. + // + + KeBugCheckEx( DATA_BUS_ERROR, + (ULONG)MachineCheckStatus->Correctable, + (ULONG)MachineCheckStatus->Retryable, + (ULONG)0, + (ULONG)PUncorrectableError ); + +} + +#define MAX_ERROR_STRING 100 + +VOID +HalpDisplayLogout21064 ( + IN PLOGOUT_FRAME_21064 LogoutFrame + ) + +/*++ + +Routine Description: + + This function displays the logout frame for a 21064. + +Arguments: + + LogoutFrame - Supplies a pointer to the logout frame generated + by the 21064. +Return Value: + + None. + +--*/ + +{ + UCHAR OutBuffer[ MAX_ERROR_STRING ]; + ULONG Index; + PKPRCB Prcb; + extern HalpLogicalToPhysicalProcessor[HAL_MAXIMUM_PROCESSOR+1]; + + sprintf( OutBuffer, "BIU_STAT : %016Lx BIU_ADDR: %016Lx\n", + BIUSTAT_ALL_21064( LogoutFrame->BiuStat ), + LogoutFrame->BiuAddr.QuadPart ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "FILL_ADDR: %016Lx FILL_SYN: %016Lx\n", + LogoutFrame->FillAddr.QuadPart, + FILLSYNDROME_ALL_21064(LogoutFrame->FillSyndrome) ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "DC_STAT : %016Lx BC_TAG : %016Lx\n", + DCSTAT_ALL_21064(LogoutFrame->DcStat), + BCTAG_ALL_21064(LogoutFrame->BcTag) ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "ICCSR : %016Lx ABOX_CTL: %016Lx EXC_SUM: %016Lx\n", + ICCSR_ALL_21064(LogoutFrame->Iccsr), + ABOXCTL_ALL_21064(LogoutFrame->AboxCtl), + EXCSUM_ALL_21064(LogoutFrame->ExcSum) ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "EXC_ADDR : %016Lx VA : %016Lx MM_CSR : %016Lx\n", + LogoutFrame->ExcAddr.QuadPart, + LogoutFrame->Va.QuadPart, + MMCSR_ALL_21064(LogoutFrame->MmCsr) ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "HIRR : %016Lx HIER : %016Lx PS : %016Lx\n", + IRR_ALL_21064(LogoutFrame->Hirr), + IER_ALL_21064(LogoutFrame->Hier), + PS_ALL_21064(LogoutFrame->Ps) ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "Waiting 15 seconds...\n"); + HalDisplayString( OutBuffer ); + + for( Index=0; Index<1500; Index++) + KeStallExecutionProcessor( 10000 ); // ~15 second delay + + sprintf( OutBuffer, "PAL_BASE : %016Lx \n", + LogoutFrame->PalBase.QuadPart ); + HalDisplayString( OutBuffer ); + + // + // Print out interpretation of the error. + // + + // + // First print the processor on which we saw the error + // + + Prcb = PCR->Prcb; + sprintf( OutBuffer, "Error on processor number: %d\n", + HalpLogicalToPhysicalProcessor[Prcb->Number] ); + HalDisplayString( OutBuffer ); + + // + // If we got a Data Cache Parity Error print a message on screen. + // + + if( DCSTAT_DCPARITY_ERROR_21064(LogoutFrame->DcStat) ){ + sprintf( OutBuffer, "Data Cache Parity Error.\n" ); + HalDisplayString( OutBuffer ); + } + + // + // Check for tag control parity error. + // + + if( BIUSTAT_TCPERR_21064(LogoutFrame->BiuStat) == 1 ){ + + sprintf( OutBuffer, + "Tag control parity error, Tag control: P: %1x D: %1x S: %1x V: %1x\n", + BCTAG_TAGCTLP_21064( LogoutFrame->BcTag ), + BCTAG_TAGCTLD_21064( LogoutFrame->BcTag ), + BCTAG_TAGCTLS_21064( LogoutFrame->BcTag ), + BCTAG_TAGCTLV_21064( LogoutFrame->BcTag ) ); + + HalDisplayString( OutBuffer ); + + } + + // + // Check for tag parity error. + // + + if( BIUSTAT_TPERR_21064(LogoutFrame->BiuStat) == 1 ){ + + sprintf( OutBuffer, + "Tag parity error, Tag: %x Parity: %1x\n", + BCTAG_TAG_21064(LogoutFrame->BcTag), + BCTAG_TAGP_21064(LogoutFrame->BcTag) ); + + HalDisplayString( OutBuffer ); + + } + + // + // Check for hard error. + // + + if( BIUSTAT_HERR_21064(LogoutFrame->BiuStat) == 1 ){ + + sprintf( OutBuffer, "Hard error acknowledge: BIU CMD: %x PA: %16Lx\n", + BIUSTAT_CMD_21064(LogoutFrame->BiuStat), + LogoutFrame->BiuAddr.QuadPart ); + + HalDisplayString( OutBuffer ); + + } + + // + // Check for soft error. + // + + if( BIUSTAT_SERR_21064(LogoutFrame->BiuStat) == 1 ){ + + sprintf( OutBuffer, "Soft error acknowledge: BIU CMD: %x PA: %16Lx\n", + BIUSTAT_CMD_21064(LogoutFrame->BiuStat), + LogoutFrame->BiuAddr.QuadPart ); + + HalDisplayString( OutBuffer ); + + } + + + // + // Check for fill ECC errors. + // + + if( BIUSTAT_FILLECC_21064(LogoutFrame->BiuStat) == 1 ){ + + sprintf( OutBuffer, "ECC error: %s\n", + (BIUSTAT_FILLIRD_21064(LogoutFrame->BiuStat) ? + "Icache Fill" : "Dcache Fill") ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, + "PA: %16Lx Quadword: %x Longword0: %x Longword1: %x\n", + LogoutFrame->FillAddr.QuadPart, + BIUSTAT_FILLQW_21064(LogoutFrame->BiuStat), + FILLSYNDROME_LO_21064(LogoutFrame->FillSyndrome), + FILLSYNDROME_HI_21064(LogoutFrame->FillSyndrome) ); + + HalDisplayString( OutBuffer ); + + } + + // + // Check for fill Parity errors. + // + + if( BIUSTAT_FILLDPERR_21064(LogoutFrame->BiuStat) == 1 ){ + + sprintf( OutBuffer, "Parity error: %s\n", + (BIUSTAT_FILLIRD_21064(LogoutFrame->BiuStat) ? + "Icache Fill" : "Dcache Fill") ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, + "PA: %16Lx Quadword: %x Longword0: %x Longword1: %x\n", + LogoutFrame->FillAddr.QuadPart, + BIUSTAT_FILLQW_21064(LogoutFrame->BiuStat), + FILLSYNDROME_LO_21064(LogoutFrame->FillSyndrome), + FILLSYNDROME_HI_21064(LogoutFrame->FillSyndrome) ); + + HalDisplayString( OutBuffer ); + + } + + // + // Check for multiple hard errors. + // + + if( BIUSTAT_FATAL1_21064(LogoutFrame->BiuStat) == 1 ){ + + HalDisplayString( "Multiple external/tag errors detected.\n" ); + + } + + // + // Check for multiple fill errors. + // + + if( BIUSTAT_FATAL2_21064(LogoutFrame->BiuStat) == 1 ){ + + HalDisplayString( "Multiple fill errors detected.\n" ); + + } + + + // + // return to caller + // + + return; +} + diff --git a/private/ntos/nthals/halalpha/ev4mem.s b/private/ntos/nthals/halalpha/ev4mem.s new file mode 100644 index 000000000..ab6815a91 --- /dev/null +++ b/private/ntos/nthals/halalpha/ev4mem.s @@ -0,0 +1,146 @@ +// TITLE("EV4 Memory Operations") +//++ +// +// Copyright (c) 1994 Digital Equipment Corporation +// +// Module Name: +// +// ev4mem.s +// +// Abstract: +// +// This module implements EV4 memory operations that require assembly +// language. +// +// Author: +// +// Joe Notarangelo 1-Jun-1994 +// +// Environment: +// +// HAL, Kernel mode only. +// +// Revision History: +// +//-- + +#include "ksalpha.h" + + +//++ +// +// VOID +// HalZeroPage ( +// IN PVOID NewColor, +// IN PVOID OldColor, +// IN ULONG PageFrame +// ) +// +// Routine Description: +// +// This function zeros a page of memory. +// +// Arguments: +// +// NewColor (a0) - Supplies the page aligned virtual address of the +// new color of the page that is zeroed. +// +// OldColor (a1) - Supplies the page aligned virtual address of the +// old color of the page that is zeroed. +// +// PageFrame (a2) - Supplies the page frame number of the page that +// is zeroed. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalZeroPage) + + .set noreorder // hand scheduled + +#define ZERO_BLOCK_SIZE (256) +#define ZERO_LOOPS (PAGE_SIZE/ZERO_BLOCK_SIZE) + +// +// Map the page via the 43-bit super-page on EV4. +// + + ldiq t0, -0x4000 // 0xffff ffff ffff c000 + sll a2, PAGE_SHIFT, t1 // physical address of page + + sll t0, 28, t0 // 0xffff fc00 0000 0000 + ldil t2, ZERO_LOOPS // set count of loops to run + + bis t0, t1, t0 // set super-page enable + physical + bis zero, zero, zero // for branch alignment + +// +// Zero the page in a loop, zeroing 256 bytes per iteration. This number +// was chosen to tradeoff loop overhead versus the overhead of fetching +// Icache blocks. +// + +10: + stq zero, 0x00(t0) // + subl t2, 1, t2 // decrement the loop count + + stq zero, 0x08(t0) // + stt f31, 0x10(t0) // + + stq zero, 0x18(t0) // + stt f31, 0x20(t0) // + + stq zero, 0x28(t0) // + stt f31, 0x30(t0) // + + stq zero, 0x38(t0) // + stt f31, 0x40(t0) // + + stq zero, 0x48(t0) // + stt f31, 0x50(t0) // + + stq zero, 0x58(t0) // + stt f31, 0x60(t0) // + + stq zero, 0x68(t0) // + stt f31, 0x70(t0) // + + stq zero, 0x78(t0) // + stt f31, 0x80(t0) // + + stq zero, 0x88(t0) // + stt f31, 0x90(t0) // + + stq zero, 0x98(t0) // + stt f31, 0xa0(t0) // + + stq zero, 0xa8(t0) // + stt f31, 0xb0(t0) // + + bis t0, zero, t1 // copy base register + stq zero, 0xb8(t0) // + + stq zero, 0xc0(t0) // + stt f31, 0xc8(t0) // + + stq zero, 0xd0(t0) // + stt f31, 0xd8(t0) // + + stq zero, 0xe0(t0) // + lda t0, 0x100(t0) // increment to next block + + stq zero, 0xe8(t1) // + stt f31, 0xf0(t1) // + + stt f31, 0xf8(t1) // use stt for dual issue with bne + bne t2, 10b // while count > 0 + + ret zero, (ra) // return + + + .set reorder // + + .end HalZeroPage diff --git a/private/ntos/nthals/halalpha/ev4parit.c b/private/ntos/nthals/halalpha/ev4parit.c new file mode 100644 index 000000000..bd9527680 --- /dev/null +++ b/private/ntos/nthals/halalpha/ev4parit.c @@ -0,0 +1,336 @@ +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + ev4parit.c + +Abstract: + + This module implements machine check handling for machines with + parity memory protection that are based on the DECchip 21064 + microprocessor. + +Author: + + Joe Notarangelo 11-Feb-1993 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "halp.h" +#include "axp21064.h" + +VOID +HalpDisplayLogout21064( PLOGOUT_FRAME_21064 LogoutFrame ); + + +BOOLEAN +HalMachineCheck ( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN PKTRAP_FRAME TrapFrame + ) +/*++ + +Routine Description: + + This function fields machine check for 21064-based machines with + parity memory protection. + +Arguments: + + ExceptionRecord - Supplies a pointer to the exception record for the + machine check. Included in the exception information + is the pointer to the logout frame. + + ExceptionFrame - Supplies a pointer to the kernel exception frame. + + TrapFrame - Supplies a pointer to the kernel trap frame. + +Return Value: + + A value of TRUE is returned if the machine check has been + handled by the HAL. If it has been handled then execution may + resume at the faulting address. Otherwise, a value of FALSE + is returned. + + N.B. - under some circumstances this routine may not return at + all. + +--*/ + +{ + + PMCHK_STATUS MachineCheckStatus; + + // + // This is a parity machine. If we receive a machine check it + // is uncorrectable. We will print the logout frame and then we + // will bugcheck. + // + // However, we will first check that the machine check is not + // marked as correctable. If the machine check is correctable it uses + // a differently formatted logout frame. We will ignore the frame + // for any machine check marked as correctable since it is an impossible + // condition on a parity machine. + // + + MachineCheckStatus = + (PMCHK_STATUS)&ExceptionRecord->ExceptionInformation[0]; + + if( MachineCheckStatus->Correctable == 0 ){ + + HalpDisplayLogout21064( + (PLOGOUT_FRAME_21064)(ExceptionRecord->ExceptionInformation[1]) + ); + + } + + // + // Bugcheck to dump the rest of the machine state, this will help + // if the machine check is software-related. + // + + KeBugCheckEx( DATA_BUS_ERROR, + (ULONG)MachineCheckStatus->Correctable, + (ULONG)MachineCheckStatus->Retryable, + 0, + 0 ); + +} + + +#define MAX_ERROR_STRING 100 + +VOID +HalpDisplayLogout21064 ( + IN PLOGOUT_FRAME_21064 LogoutFrame + ) + +/*++ + +Routine Description: + + This function displays the logout frame for a 21064. + +Arguments: + + LogoutFrame - Supplies a pointer to the logout frame generated + by the 21064. +Return Value: + + None. + +--*/ + +{ + UCHAR OutBuffer[ MAX_ERROR_STRING ]; + + // + // Acquire ownership of the display. This is done here in case we take + // a machine check before the display has been taken away from the HAL. + // When the HAL begins displaying strings after it has lost the + // display ownership then the HAL will be careful not to scroll information + // off of the screen. + // + + HalAcquireDisplayOwnership(NULL); + + // + // Display the machine state via the logout frame. + // + + HalDisplayString( "\nFatal system hardware error.\n\n" ); + + + sprintf( OutBuffer, "BIU_STAT : %016Lx BIU_ADDR: %016Lx\n", + BIUSTAT_ALL_21064( LogoutFrame->BiuStat ), + LogoutFrame->BiuAddr.QuadPart ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "FILL_ADDR: %016Lx FILL_SYN: %016Lx\n", + LogoutFrame->FillAddr.QuadPart, + FILLSYNDROME_ALL_21064(LogoutFrame->FillSyndrome) ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "DC_STAT : %016Lx BC_TAG : %016Lx\n", + DCSTAT_ALL_21064(LogoutFrame->DcStat), + BCTAG_ALL_21064(LogoutFrame->BcTag) ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "ICCSR : %016Lx ABOX_CTL: %016Lx EXC_SUM: %016Lx\n", + ICCSR_ALL_21064(LogoutFrame->Iccsr), + ABOXCTL_ALL_21064(LogoutFrame->AboxCtl), + EXCSUM_ALL_21064(LogoutFrame->ExcSum) ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "EXC_ADDR : %016Lx VA : %016Lx MM_CSR : %016Lx\n", + LogoutFrame->ExcAddr.QuadPart, + LogoutFrame->Va.QuadPart, + MMCSR_ALL_21064(LogoutFrame->MmCsr) ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "HIRR : %016Lx HIER : %016Lx PS : %016Lx\n", + IRR_ALL_21064(LogoutFrame->Hirr), + IER_ALL_21064(LogoutFrame->Hier), + PS_ALL_21064(LogoutFrame->Ps) ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "PAL_BASE : %016Lx \n", + LogoutFrame->PalBase.QuadPart ); + HalDisplayString( OutBuffer ); + + // + // Print out interpretation of the error. + // + + + HalDisplayString( "\n" ); + + // + // Check for tag control parity error. + // + + if( BIUSTAT_TCPERR_21064(LogoutFrame->BiuStat) == 1 ){ + + sprintf( OutBuffer, + "Tag control parity error, Tag control: P: %1x D: %1x S: %1x V: %1x\n", + BCTAG_TAGCTLP_21064( LogoutFrame->BcTag ), + BCTAG_TAGCTLD_21064( LogoutFrame->BcTag ), + BCTAG_TAGCTLS_21064( LogoutFrame->BcTag ), + BCTAG_TAGCTLV_21064( LogoutFrame->BcTag ) ); + + HalDisplayString( OutBuffer ); + + } + + // + // Check for tag parity error. + // + + if( BIUSTAT_TPERR_21064(LogoutFrame->BiuStat) == 1 ){ + + sprintf( OutBuffer, + "Tag parity error, Tag: 0b%17b Parity: %1x\n", + BCTAG_TAG_21064(LogoutFrame->BcTag), + BCTAG_TAGP_21064(LogoutFrame->BcTag) ); + + HalDisplayString( OutBuffer ); + + } + + // + // Check for hard error. + // + + if( BIUSTAT_HERR_21064(LogoutFrame->BiuStat) == 1 ){ + + sprintf( OutBuffer, "Hard error acknowledge: BIU CMD: %x PA: %16Lx\n", + BIUSTAT_CMD_21064(LogoutFrame->BiuStat), + LogoutFrame->BiuAddr.QuadPart ); + + HalDisplayString( OutBuffer ); + + } + + // + // Check for soft error. + // + + if( BIUSTAT_SERR_21064(LogoutFrame->BiuStat) == 1 ){ + + sprintf( OutBuffer, "Soft error acknowledge: BIU CMD: %x PA: %16Lx\n", + BIUSTAT_CMD_21064(LogoutFrame->BiuStat), + LogoutFrame->BiuAddr.QuadPart ); + + HalDisplayString( OutBuffer ); + + } + + + // + // Check for fill ECC errors. + // + + if( BIUSTAT_FILLECC_21064(LogoutFrame->BiuStat) == 1 ){ + + sprintf( OutBuffer, "ECC error: %s\n", + (BIUSTAT_FILLIRD_21064(LogoutFrame->BiuStat) ? + "Icache Fill" : "Dcache Fill") ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, + "PA: %16Lx Quadword: %x Longword0: %x Longword1: %x\n", + LogoutFrame->FillAddr.QuadPart, + BIUSTAT_FILLQW_21064(LogoutFrame->BiuStat), + FILLSYNDROME_LO_21064(LogoutFrame->FillSyndrome), + FILLSYNDROME_HI_21064(LogoutFrame->FillSyndrome) ); + + HalDisplayString( OutBuffer ); + + } + + // + // Check for fill Parity errors. + // + + if( BIUSTAT_FILLDPERR_21064(LogoutFrame->BiuStat) == 1 ){ + + sprintf( OutBuffer, "Parity error: %s\n", + (BIUSTAT_FILLIRD_21064(LogoutFrame->BiuStat) ? + "Icache Fill" : "Dcache Fill") ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, + "PA: %16Lx Quadword: %x Longword0: %x Longword1: %x\n", + LogoutFrame->FillAddr.QuadPart, + BIUSTAT_FILLQW_21064(LogoutFrame->BiuStat), + FILLSYNDROME_LO_21064(LogoutFrame->FillSyndrome), + FILLSYNDROME_HI_21064(LogoutFrame->FillSyndrome) ); + + HalDisplayString( OutBuffer ); + + } + + // + // Check for multiple hard errors. + // + + if( BIUSTAT_FATAL1_21064(LogoutFrame->BiuStat) == 1 ){ + + HalDisplayString( "Multiple external/tag errors detected.\n" ); + + } + + // + // Check for multiple fill errors. + // + + if( BIUSTAT_FATAL2_21064(LogoutFrame->BiuStat) == 1 ){ + + HalDisplayString( "Multiple fill errors detected.\n" ); + + } + + + // + // return to caller + // + + return; +} diff --git a/private/ntos/nthals/halalpha/ev4prof.c b/private/ntos/nthals/halalpha/ev4prof.c new file mode 100644 index 000000000..513187b0d --- /dev/null +++ b/private/ntos/nthals/halalpha/ev4prof.c @@ -0,0 +1,591 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + ev4prof.c + +Abstract: + + This module implements the Profile Counter using the performance + counters within the EV4 core. This module is appropriate for all + machines based on microprocessors using the EV4 core. + + N.B. - This module assumes that all processors in a multiprocessor + system are running the microprocessor at the same clock speed. + +Author: + + Joe Notarangelo 22-Feb-1994 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" +#include "axp21064.h" + + +// +// Define space in the HAL-reserved part of the PCR structure for each +// performance counter's interval count +// +// Note that ev4ints.s depends on these positions in the PCR. +// +#define PCRProfileCount ((PULONG)(HAL_PCR->ProfileCount.ProfileCount)) +#define PCRProfileCountReload ((PULONG)(&HAL_PCR->ProfileCount.ProfileCountReload)) + + +// +// Define the currently selected profile source for each counter +// +KPROFILE_SOURCE HalpProfileSource0; +KPROFILE_SOURCE HalpProfileSource1; + +#define INTERVAL_DELTA (10) + +// +// Define the mapping between possible profile sources and the +// CPU-specific settings. +// +typedef struct _HALP_PROFILE_MAPPING { + BOOLEAN Supported; + ULONG MuxControl; + ULONG Counter; + ULONG EventCount; + ULONG NumberOfTicks; +} HALP_PROFILE_MAPPING, *PHALP_PROFILE_MAPPING; + +HALP_PROFILE_MAPPING HalpProfileMapping[ProfileMaximum] = + { + {TRUE, Ev4TotalCycles, Ev4PerformanceCounter0, Ev4CountEvents2xx12, 10}, + {FALSE, 0, 0, 0, 0}, + {TRUE, Ev4TotalIssues, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10}, + {TRUE, Ev4PipelineDry, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10}, + {TRUE, Ev4LoadInstruction, Ev4PerformanceCounter0, Ev4CountEvents2xx12, 10}, + {TRUE, Ev4PipelineFrozen, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10}, + {TRUE, Ev4BranchInstructions, Ev4PerformanceCounter0, Ev4CountEvents2xx12, 10}, + {TRUE, Ev4TotalNonIssues, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10}, + {TRUE, Ev4DcacheMiss, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10}, + {TRUE, Ev4IcacheMiss, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10}, + {FALSE, 0, 0, 0, 0}, + {TRUE, Ev4BranchMispredicts, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10}, + {TRUE, Ev4StoreInstructions, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10}, + {TRUE, Ev4FPInstructions, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10}, + {TRUE, Ev4IntegerOperate, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10}, + {TRUE, Ev4DualIssues, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10}, + {FALSE, 0, 0, 0, 0}, + {FALSE, 0, 0, 0, 0}, + {TRUE, Ev4PalMode, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10}, + {TRUE, Ev4TotalCycles, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10}, + {FALSE, 0, 0, 0, 0}, + {FALSE, 0, 0, 0, 0} + }; + +BOOLEAN +HalQueryProfileInterval( + IN KPROFILE_SOURCE Source + ); + +NTSTATUS +HalSetProfileSourceInterval( + IN KPROFILE_SOURCE ProfileSource, + IN OUT ULONG *Interval + ); + + + +NTSTATUS +HalpProfileSourceInformation ( + OUT PVOID Buffer, + IN ULONG BufferLength, + OUT PULONG ReturnedLength + ) +/*++ + +Routine Description: + + Returns the HAL_PROFILE_SOURCE_INFORMATION for this processor. + +Arguments: + + Buffer - output buffer + BufferLength - length of buffer on input + ReturnedLength - The length of data returned + +Return Value: + + STATUS_SUCCESS + STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize + currently needed. + +--*/ +{ + PHAL_PROFILE_SOURCE_INFORMATION SourceInfo; + NTSTATUS Status; + + + if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INFORMATION)) { + Status = STATUS_INFO_LENGTH_MISMATCH; + return Status; + } + + SourceInfo = (PHAL_PROFILE_SOURCE_INFORMATION)Buffer; + SourceInfo->Supported = HalQueryProfileInterval(SourceInfo->Source); + + if (SourceInfo->Supported) { + SourceInfo->Interval = + HalpProfileMapping[SourceInfo->Source].EventCount * + HalpProfileMapping[SourceInfo->Source].NumberOfTicks; + if (SourceInfo->Source == ProfileTotalIssues) { + // + // Convert total issues/2 back into total issues + // + SourceInfo->Interval = SourceInfo->Interval * 2; + } + } + + Status = STATUS_SUCCESS; + return Status; +} + +NTSTATUS +HalpProfileSourceInterval ( + OUT PVOID Buffer, + IN ULONG BufferLength + ) +/*++ + +Routine Description: + + Returns the HAL_PROFILE_SOURCE_INTERVAL for this processor. + +Arguments: + + Buffer - output buffer + BufferLength - length of buffer on input + +Return Value: + + STATUS_SUCCESS + STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize + currently needed. + +--*/ +{ + PHAL_PROFILE_SOURCE_INTERVAL Interval; + NTSTATUS Status; + + + if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INTERVAL)) { + Status = STATUS_INFO_LENGTH_MISMATCH; + return Status; + } + + Interval = (PHAL_PROFILE_SOURCE_INTERVAL)Buffer; + Status = HalSetProfileSourceInterval(Interval->Source, + &Interval->Interval); + return Status; +} + +VOID +HalpInitializeProfiler( + VOID + ) +/*++ + +Routine Description: + + This routine is called during initialization to initialize profiling + for each processor in the system. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + PKINTERRUPT InterruptObject; + KIRQL Irql; + PKPRCB Prcb = PCR->Prcb; + ULONG Vector; + + // + // Establish the profile interrupt as the interrupt handler for + // all performance counter interrupts. + // + + PCR->InterruptRoutine[PC0_VECTOR] = HalpPerformanceCounter0Interrupt; + PCR->InterruptRoutine[PC1_VECTOR] = HalpPerformanceCounter1Interrupt; + + return; + +} + + +BOOLEAN +HalQueryProfileInterval( + IN KPROFILE_SOURCE Source + ) + +/*++ + +Routine Description: + + Given a profile source, returns whether or not that source is + supported. + +Arguments: + + Source - Supplies the profile source + +Return Value: + + TRUE - Profile source is supported + + FALSE - Profile source is not supported + +--*/ + +{ + if (Source > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) { + return(FALSE); + } + + return(HalpProfileMapping[Source].Supported); +} + + +NTSTATUS +HalSetProfileSourceInterval( + IN KPROFILE_SOURCE ProfileSource, + IN OUT ULONG *Interval + ) + +/*++ + +Routine Description: + + Sets the profile interval for a specified profile source + +Arguments: + + ProfileSource - Supplies the profile source + + Interval - Supplies the specified profile interval + Returns the actual profile interval + +Return Value: + + NTSTATUS + +--*/ + +{ + ULONG FastTickPeriod; + ULONG SlowTickPeriod; + ULONG TickPeriod; + ULONGLONG CountEvents; + ULONG FastCountEvents; + ULONG SlowCountEvents; + ULONGLONG TempInterval; + + if (!HalQueryProfileInterval(ProfileSource)) { + return(STATUS_NOT_IMPLEMENTED); + } + + if (ProfileSource == ProfileTime) { + + // + // Convert the clock tick period (in 100ns units ) into + // a cycle count period + // + + CountEvents = ((ULONGLONG)(*Interval) * 100000) / PCR->CycleClockPeriod; + } else if (ProfileSource == ProfileTotalIssues) { + + // + // Convert the total issue events into the wonky + // total issues/2 form implemented by EV4. + // + + CountEvents = (ULONGLONG)(*Interval / 2); + } else { + CountEvents = (ULONGLONG)*Interval; + } + + if (HalpProfileMapping[ProfileSource].Counter == Ev4PerformanceCounter1) { + FastCountEvents = Ev4CountEvents2xx8; + SlowCountEvents = Ev4CountEvents2xx12; + } else { + FastCountEvents = Ev4CountEvents2xx12; + SlowCountEvents = Ev4CountEvents2xx16; + } + + // + // Limit the interval to the smallest interval we can time. + // + if (CountEvents < FastCountEvents) { + CountEvents = (ULONGLONG)FastCountEvents; + } + + // + // Assume we will use the fast event count + // + HalpProfileMapping[ProfileSource].EventCount = FastCountEvents; + HalpProfileMapping[ProfileSource].NumberOfTicks = + (ULONG)((CountEvents + FastCountEvents - 1) / FastCountEvents); + + // + // See if we can successfully use the slower period. If the requested + // interval is greater than the slower tick period and the difference + // between the requested interval and the interval that we can deliver + // with the slower clock is acceptable, then use the slower clock. + // We define an acceptable difference as a difference of less than + // INTERVAL_DELTA of the requested interval. + // + if (CountEvents > SlowCountEvents) { + ULONG NewInterval; + + NewInterval = (ULONG)(((CountEvents + SlowCountEvents-1) / + SlowCountEvents) * SlowCountEvents); + if (((NewInterval - CountEvents) * 100 / CountEvents) < INTERVAL_DELTA) { + HalpProfileMapping[ProfileSource].EventCount = SlowCountEvents; + HalpProfileMapping[ProfileSource].NumberOfTicks = NewInterval / SlowCountEvents; + } + } + + *Interval = HalpProfileMapping[ProfileSource].EventCount * + HalpProfileMapping[ProfileSource].NumberOfTicks; + + if (ProfileSource == ProfileTime) { + // + // Convert cycle count back into 100ns clock ticks + // + // Use 64-bit integer to prevent overflow. + // + TempInterval = (ULONGLONG)(*Interval) * (ULONGLONG)(PCR->CycleClockPeriod); + *Interval = (ULONG)(TempInterval / 100000); + } else if (ProfileSource == ProfileTotalIssues) { + // + // Convert issues/2 count back into issues + // + TempInterval = (ULONGLONG)(*Interval) * 2; + *Interval = (ULONG)TempInterval; + } + return(STATUS_SUCCESS); +} + + +ULONG +HalSetProfileInterval ( + IN ULONG Interval + ) + +/*++ + +Routine Description: + + This routine sets the profile interrupt interval. + +Arguments: + + Interval - Supplies the desired profile interval in 100ns units. + +Return Value: + + The actual profile interval. + +--*/ + +{ + ULONG NewInterval; + + NewInterval = Interval; + HalSetProfileSourceInterval(ProfileTime, &NewInterval); + return(NewInterval); +} + + + +VOID +HalStartProfileInterrupt ( + KPROFILE_SOURCE ProfileSource + ) + +/*++ + +Routine Description: + + This routine turns on the profile interrupt. + + N.B. This routine must be called at PROCLK_LEVEL while holding the + profile lock. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + ULONG PerformanceCounter; + ULONG MuxControl; + ULONG EventCount; + + // + // Check input to see if we are turning on a source that is + // supported. If it is unsupported, just return. + // + + if ((ProfileSource > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) || + (!HalpProfileMapping[ProfileSource].Supported)) { + return; + } + + // + // Set the performance counter within the processor to begin + // counting total cycles. + // + PerformanceCounter = HalpProfileMapping[ProfileSource].Counter; + MuxControl = HalpProfileMapping[ProfileSource].MuxControl; + + if (PerformanceCounter == Ev4PerformanceCounter0) { + + HalpProfileSource0 = ProfileSource; + EventCount = (HalpProfileMapping[ProfileSource].EventCount == Ev4CountEvents2xx12) ? + Ev4EventCountHigh : + Ev4EventCountLow; + HalpWritePerformanceCounter( PerformanceCounter, + TRUE, + MuxControl, + EventCount ); + + PCRProfileCountReload[0] = HalpProfileMapping[ProfileSource].NumberOfTicks; + PCRProfileCount[0] = HalpProfileMapping[ProfileSource].NumberOfTicks; + + // + // Enable the performance counter interrupt. + // + + HalEnableSystemInterrupt ( PC0_VECTOR, + PROFILE_LEVEL, + LevelSensitive ); + + + } else { + + HalpProfileSource1 = ProfileSource; + EventCount = (HalpProfileMapping[ProfileSource].EventCount == Ev4CountEvents2xx12) ? + Ev4EventCountLow : + Ev4EventCountHigh; + HalpWritePerformanceCounter( PerformanceCounter, + TRUE, + MuxControl, + EventCount ); + + PCRProfileCountReload[1] = HalpProfileMapping[ProfileSource].NumberOfTicks; + PCRProfileCount[1] = HalpProfileMapping[ProfileSource].NumberOfTicks; + + // + // Enable the performance counter interrupt. + // + + HalEnableSystemInterrupt ( PC1_VECTOR, + PROFILE_LEVEL, + LevelSensitive ); + } + + return; +} + + +VOID +HalStopProfileInterrupt ( + KPROFILE_SOURCE ProfileSource + ) + +/*++ + +Routine Description: + + This routine turns off the profile interrupt. + + N.B. This routine must be called at PROCLK_LEVEL while holding the + profile lock. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + ULONG PerformanceCounter; + ULONG Vector; + + // + // Check input to see if we are turning off a source that is + // supported. If it is unsupported, just return. + // + + if ((ProfileSource > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) || + (!HalpProfileMapping[ProfileSource].Supported)) { + return; + } + + // + // Stop the performance counter from interrupting. + // + + PerformanceCounter = HalpProfileMapping[ProfileSource].Counter; + HalpWritePerformanceCounter( PerformanceCounter, + FALSE, + 0, + 0 ); + + // + // Disable the performance counter interrupt. + // + if (PerformanceCounter == Ev4PerformanceCounter0) { + HalDisableSystemInterrupt( PC0_VECTOR, PROFILE_LEVEL ); + + // + // Clear the current profile count. Can't clear value in PCR + // since a profile interrupt could be pending or in progress + // so clear the reload counter. + // + + PCRProfileCountReload[0] = 0; + } else { + HalDisableSystemInterrupt( PC1_VECTOR, PROFILE_LEVEL ); + + // + // Clear the current profile count. Can't clear value in PCR + // since a profile interrupt could be pending or in progress + // so clear the reload counter. + // + + PCRProfileCountReload[0] = 0; + } + + return; +} + diff --git a/private/ntos/nthals/halalpha/ev5cache.c b/private/ntos/nthals/halalpha/ev5cache.c new file mode 100644 index 000000000..2ab2e09bf --- /dev/null +++ b/private/ntos/nthals/halalpha/ev5cache.c @@ -0,0 +1,475 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + ev5cache.c + +Abstract: + + This file contains the routines for managing the caches on machines + based on the DECchip 21164 microprocessor (aka EV5). + + EV5 has primary I and D caches of 8KB each, Dcache is write-through. + EV5 also contains a 96K, 3-way set associative, write-back secondary cache. + Many EV5 systems will also have an external 3rd level backup cache. + The data caches (internal and external) must be kept coherent by the + hardware. Instruction cache coherency is maintained by software. + + EV5 has a write buffer which contains 6 32-byte entries, which + must be flushable before DMA operations. The MB instruction is + used to accomplish this. + + There is no coloring support on EV5, so Color operations are + null. Zero page is implemented in ev5mem.s Copy page is not + special because we lack coloring. + +Author: + + Miche Baker-Harvey (miche) 29-May-1992 (EV4 version) + Steve Brooks 30-Jun-1994 (EV5 version) + Joe Notarangelo 30-Jun-1994 (EV5 version) + +Revision History: + +--*/ + +#include "halp.h" + + + +VOID +HalFlushDcache ( + IN BOOLEAN AllProcessors + ); + + +// +// Cache and write buffer flush functions. +// + + +VOID +HalChangeColorPage ( + IN PVOID NewColor, + IN PVOID OldColor, + IN ULONG PageFrame + ) +/*++ + +Routine Description: + + This function changes the color of a page if the old and new colors + do not match. DECchip 21064-based machines do not have page coloring, and + therefore, this function performs no operation. + +Arguments: + + NewColor - Supplies the page aligned virtual address of the + new color of the page to change. + + OldColor - Supplies the page aligned virtual address of the + old color of the page to change. + + pageFrame - Supplies the page frame number of the page that + is changed. + +Return Value: + + None. + +--*/ +{ + return; +} + + +VOID +HalFlushDcachePage ( + IN PVOID Color, + IN ULONG PageFrame, + IN ULONG Length + ) +/*++ + +Routine Description: + + This function flushes (invalidates) up to a page of data from the + data cache. + +Arguments: + + Color - Supplies the starting virtual address and color of the + data that is flushed. + PageFrame - Supplies the page frame number of the page that + is flushed. + + Length - Supplies the length of the region in the page that is + flushed. + +Return Value: + + None. + +--*/ +{ + return; +} + + +VOID +HalFlushIoBuffers ( + IN PMDL Mdl, + IN BOOLEAN ReadOperation, + IN BOOLEAN DmaOperation + ) +/*++ + +Routine Description: + + This function flushes the I/O buffer specified by the memory descriptor + list from the data cache on the current processor. + +Arguments: + + Mdl - Supplies a pointer to a memory descriptor list that describes the + I/O buffer location. + + ReadOperation - Supplies a boolean value that determines whether the I/O + operation is a read into memory. + + DmaOperation - Supplies a boolean value that determines whether the I/O + operation is a DMA operation. + +Return Value: + + None. + +--*/ +{ + // + // The Dcache coherency is maintained in hardware. The Icache coherency + // is maintained by invalidating the istream on page read operations. + // + HalpMb(); // synchronize this processors view of memory + if (ReadOperation) { + HalpMb(); // not issued until previous mb completes + if (Mdl->MdlFlags & MDL_IO_PAGE_READ) { + + // + // The operation is a page read, thus the istream must + // be flushed. + // + HalpImb(); + } + } +} + +VOID +HalPurgeDcachePage ( + IN PVOID Color, + IN ULONG PageFrame, + IN ULONG Length + ) +/*++ +Routine Description: + + This function purges (invalidates) up to a page of data from the + data cache. + +Arguments: + + Color - Supplies the starting virtual address and color of the + data that is purged. + + PageFrame - Supplies the page frame number of the page that + is purged. + + Length - Supplies the length of the region in the page that is + purged. + +Return Value: + + None. + +--*/ +{ + return; +} + + +VOID +HalPurgeIcachePage ( + IN PVOID Color, + IN ULONG PageFrame, + IN ULONG Length + ) +/*++ + +Routine Description: + + This function purges (invalidates) up to a page fo data from the + instruction cache. + +Arguments: + + Color - Supplies the starting virtual address and color of the + data that is purged. + + PageFrame - Supplies the page frame number of the page that + is purged. + + Length - Supplies the length of the region in the page that is + purged. + +Return Value: + + None. + +--*/ +{ + // + // The call to HalpImb calls PAL to flush the Icache, which ensures that + // any stale hits will be invalidated + // + + HalpImb(); +} + + +VOID +HalSweepDcache ( + VOID + ) +/*++ + +Routine Description: + + This function sweeps (invalidates) the entire data cache. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + return; +} + + +VOID +HalSweepDcacheRange ( + IN PVOID BaseAddress, + IN ULONG Length + ) +/*++ + +Routine Description: + + This function flushes the specified range of addresses from the data + cache on the current processor. + +Arguments: + + BaseAddress - Supplies the starting physical address of a range of + physical addresses that are to be flushed from the data cache. + + Length - Supplies the length of the range of physical addresses + that are to be flushed from the data cache. + +Return Value: + + None. + +--*/ +{ + return; +} + + +VOID +HalSweepIcache ( + VOID + ) +/*++ + +Routine Description: + + This function sweeps (invalidates) the entire instruction cache. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + // + // The call to HalpImb calls PAL to flush the Icache, which ensures that + // any stale hits will be invalidated + // + + HalpImb(); + return; +} + + +VOID +HalSweepIcacheRange ( + IN PVOID BaseAddress, + IN ULONG Length + ) +/*++ + +Routine Description: + + This function flushes the specified range of addresses from the + instruction cache on the current processor. + +Arguments: + + BaseAddress - Supplies the starting physical address of a range of + physical addresses that are to be flushed from the instruction cache. + + Length - Supplies the length of the range of physical addresses + that are to be flushed from the instruction cache. + +Return Value: + + None. + +--*/ +{ + + // + // The call to HalpImb calls PAL to flush the Icache, which ensures that + // any stale hits will be invalidated + // + + HalpImb; + +} + + +VOID +KeFlushWriteBuffer ( + VOID + ) + +{ + // + // We flush the write buffer by doing a series of memory + // barrier operations, the flush method is specific to the 21164. + // + + HalpMb(); + HalpMb(); + + return; +} + + +VOID +KeFlushDcache ( + IN BOOLEAN AllProcessors, + IN PVOID BaseAddress OPTIONAL, + IN ULONG Length + ) + +/*++ + +Routine Description: + + This function flushes the data cache on all processors that are currently + running threads which are children of the current process or flushes the + data cache on all processors in the host configuration. + +Arguments: + + AllProcessors - Supplies a boolean value that determines which data + caches are flushed. + +Return Value: + + None. + +--*/ + +{ + UNREFERENCED_PARAMETER(BaseAddress); + UNREFERENCED_PARAMETER(Length); + + HalFlushDcache(AllProcessors); + return; +} + + +VOID +HalFlushDcache ( + IN BOOLEAN AllProcessors + ) + +/*++ + +Routine Description: + + This function flushes the data cache on all processors that are currently + running threads which are children of the current process or flushes the + data cache on all processors in the host configuration. + +Arguments: + + AllProcessors - Supplies a boolean value that determines which data + caches are flushed. + +Return Value: + + None. + +--*/ + +{ + + // + // Sweep (index/writeback/invalidate) the data cache. + // + + HalSweepDcache(); + return; +} + + +ULONG +HalGetDmaAlignmentRequirement ( + VOID + ) + +/*++ + +Routine Description: + + This function returns the alignment requirements for DMA transfers on + host system. + +Arguments: + + None. + +Return Value: + + The DMA alignment requirement is returned as the fucntion value. + +--*/ + +{ + + return 8; +} diff --git a/private/ntos/nthals/halalpha/ev5int.c b/private/ntos/nthals/halalpha/ev5int.c new file mode 100644 index 000000000..3fa1eec25 --- /dev/null +++ b/private/ntos/nthals/halalpha/ev5int.c @@ -0,0 +1,440 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + ev5int.c + +Abstract: + + This module implements the support routines to control DECchip 21164 + interrupts. + +Author: + + Joe Notarangelo 20-Jul-1994 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" +#include "axp21164.h" + +// +// Function prototype. +// + +VOID +HalpCachePcrValues( + ULONG InterruptMask + ); + + +VOID +HalpInitialize21164Interrupts( + VOID + ) +/*++ + +Routine Description: + + This routine initializes the data structures for the 21164 + interrupt routines. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + PIMSK_21164 InterruptMask; + PBOOLEAN InterruptsStarted; + + // + // Set up the standard correspondence of NT IRQLs to EV5 IPLs. + // It is possible that some machines may need a different correspondence + // then the one below - HALs that change this table do so at their + // own risk. + // + // NT IRQL EV5 IPL + // ------- ------- + // PASSIVE_LEVEL 0 + // APC_LEVEL 1 + // DISPATCH_LEVEL 2 + // DEVICE_LEVEL 20 + // DEVICE_HIGH_LEVEL 21 + // CLOCK_LEVEL 22 + // IPI_LEVEL 23 + // HIGH_LEVEL 31 + // + + PCR->IrqlTable[PASSIVE_LEVEL] = EV5_IPL0; + PCR->IrqlTable[APC_LEVEL] = EV5_IPL1; + PCR->IrqlTable[DISPATCH_LEVEL] = EV5_IPL2; + PCR->IrqlTable[DEVICE_LEVEL] = EV5_IPL20; + PCR->IrqlTable[DEVICE_HIGH_LEVEL] = EV5_IPL21; + PCR->IrqlTable[CLOCK_LEVEL] = EV5_IPL22; + PCR->IrqlTable[IPI_LEVEL] = EV5_IPL23; + PCR->IrqlTable[HIGH_LEVEL] = EV5_IPL31; + + // + // Define the default set of disables (masks) for the EV5 interrupt + // pins INT0 - INT3. All interrupts are enabled by default and may + // be disabled by the interface: HalpDisable21164HardwareInterrupt(). + // + + InterruptMask = (PIMSK_21164)(&PCR->IrqlMask[0]); + + InterruptMask->all = 0; + + // + // Indicate that interrupts have not been started yet. + // + + InterruptsStarted = (PBOOLEAN)(&PCR->IrqlMask[1]); + *InterruptsStarted = FALSE; + + return; + +} + + +VOID +HalpStart21164Interrupts( + VOID + ) +/*++ + +Routine Description: + + This function starts interrupt dispatching on the current 21164. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + PIMSK_21164 InterruptMask; + PBOOLEAN InterruptsStarted; + + // + // Issue the initpcr call pal to alert the PALcode that it can + // begin taking interrupts, pass the disable mask for the hardware + // interrupts. + // + + InterruptMask = (PIMSK_21164)(&PCR->IrqlMask); + HalpCachePcrValues( InterruptMask->all ); + + // + // Indicate that interrupts have been started yet. + // + + InterruptsStarted = (PBOOLEAN)(&PCR->IrqlMask[1]); + *InterruptsStarted = TRUE; + + return; +} + + +#if 0 // used ?? + +VOID +HalpEnable21164HardwareInterrupt( + IN ULONG Irq + ) +/*++ + +Routine Description: + + Clear the mask value for the desired Irq pin so that interrupts + are enabled from that pin. + +Arguments: + + Irq - Supplies the interrupt pin number to be enabled. + +Return Value: + + None. + +--*/ +{ + PIMSK_21164 InterruptMask; + PBOOLEAN InterruptsStarted; + KIRQL OldIrql; + + // + // Raise Irql to HIGH_LEVEL to prevent any interrupts. + // + + KeRaiseIrql( HIGH_LEVEL, &OldIrql ); + + // + // Clear the mask value for the desired Irq pin. + // + + InterruptMask = (PIMSK_21164)(&PCR->IrqlMask); + + switch( Irq ){ + + case Irq0: + + InterruptMask->Irq0Mask = 0; + break; + + case Irq1: + + InterruptMask->Irq1Mask = 0; + break; + + case Irq2: + + InterruptMask->Irq2Mask = 0; + break; + + case Irq3: + + InterruptMask->Irq3Mask = 0; + break; + + } //end switch (Irq) + + // + // Set the new masks in the PALcode. + // + + InterruptsStarted = (PBOOLEAN)(&PCR->IrqlMask[1]); + if( *InterruptsStarted == TRUE ){ + HalpCachePcrValues( InterruptMask->all ); + } + + // + // Lower Irql to the previous level and return. + // + + KeLowerIrql( OldIrql ); + return; + +} + + +VOID +HalpDisable21164HardwareInterrupt( + IN ULONG Irq + ) +/*++ + +Routine Description: + + Set the mask value for the desired Irq pin so that interrupts + are disabled from that pin. + +Arguments: + + Irq - Supplies the interrupt pin number to be disabled. + +Return Value: + + None. + +--*/ +{ + PIMSK_21164 InterruptMask; + PBOOLEAN InterruptsStarted; + KIRQL OldIrql; + + // + // Raise Irql to HIGH_LEVEL to prevent any interrupts. + // + + KeRaiseIrql( HIGH_LEVEL, &OldIrql ); + + // + // Set the mask value for the desired Irq pin. + // + + InterruptMask = (PIMSK_21164)(&PCR->IrqlMask); + + switch( Irq ){ + + case Irq0: + + InterruptMask->Irq0Mask = 1; + break; + + case Irq1: + + InterruptMask->Irq1Mask = 1; + break; + + case Irq2: + + InterruptMask->Irq2Mask = 1; + break; + + case Irq3: + + InterruptMask->Irq3Mask = 1; + break; + + } //end switch (Irq) + + // + // Set the new masks in the PALcode, if interrupts have been started. + // + + InterruptsStarted = (PBOOLEAN)(&PCR->IrqlMask[1]); + if( *InterruptsStarted == TRUE ){ + HalpCachePcrValues( InterruptMask->all ); + } + + // + // Lower Irql to the previous level and return. + // + + KeLowerIrql( OldIrql ); + return; + +} + +#endif // Used ?? + + +ULONG +HalpGet21164PerformanceVector( + IN ULONG BusInterruptLevel, + OUT PKIRQL Irql + ) + +/*++ + +Routine Description: + + This function returns the system interrupt vector and IRQL level + corresponding to the specified performance counter interrupt. + +Arguments: + + BusInterruptLevel - Supplies the performance counter number. + + Irql - Returns the system request priority. + +Return Value: + + Returns the system interrupt vector corresponding to the specified device. + +--*/ + +{ + + // + // Handle the special internal bus defined for the processor itself + // and used to control the performance counters in the 21164. + // + + *Irql = PROFILE_LEVEL; + + switch( BusInterruptLevel ){ + + // + // Performance Counter 0 + // + + case 0: + + return PC0_SECONDARY_VECTOR; + + // + // Performance Counter 1 + // + + case 1: + + return PC1_SECONDARY_VECTOR; + + // + // Performance Counter 2 + // + + case 2: + + return PC2_SECONDARY_VECTOR; + + } //end switch( BusInterruptLevel ) + + // + // Unrecognized. + // + + *Irql = 0; + return 0; + +} + +ULONG +HalpGet21164CorrectableVector( + IN ULONG BusInterruptLevel, + OUT PKIRQL Irql + ) + +/*++ + +Routine Description: + + This function returns the system interrupt vector and IRQL level + corresponding to the specified correctable interrupt. + +Arguments: + + BusInterruptLevel - Supplies the performance counter number. + + Irql - Returns the system request priority. + +Return Value: + + Returns the system interrupt vector corresponding to the specified device. + +--*/ + +{ + // + // Get the correctable interrupt vector. + // + + if (BusInterruptLevel == 5) { + + // + // Correctable error interrupt was sucessfully recognized. + // + + *Irql = DEVICE_HIGH_LEVEL; + return CORRECTABLE_VECTOR; + + + } else { + + // + // Unrecognized. + // + + *Irql = 0; + return 0; + } +} + diff --git a/private/ntos/nthals/halalpha/ev5ints.s b/private/ntos/nthals/halalpha/ev5ints.s new file mode 100644 index 000000000..1970c83fe --- /dev/null +++ b/private/ntos/nthals/halalpha/ev5ints.s @@ -0,0 +1,397 @@ +//++ +// +// Copyright (c) 1994 Microsoft Corporation +// +// Module Name: +// +// ev5ints.s +// +// Abstract: +// +// This module implements EV5-specific interrupt handlers. +// (the performance counters) +// +// Author: +// +// John Vert (jvert) 15-Nov-1994 +// Steve Brooks 14-Feb-1994 (modified from ev4ints.s) +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +//-- +#include "halalpha.h" + +#define PC0_SECONDARY_VECTOR 11 +#define PC1_SECONDARY_VECTOR 13 +#define PC2_SECONDARY_VECTOR 16 // SjBfix. This is actually PC3_VECTOR +#define PcProfileCount0 PcHalReserved+20 +#define PcProfileCount1 PcProfileCount0+4 +#define PcProfileCount2 PcProfileCount1+4 +#define PcProfileCountReload0 PcProfileCount2+4 +#define PcProfileCountReload1 PcProfileCountReload0+4 +#define PcProfileCountReload2 PcProfileCountReload1+4 + + .struct 0 + .space 8 // reserved for alignment +PrRa: .space 8 // space for return address +PrFrameLength: // + + SBTTL("Performance Counter 0 Interrupt") +//++ +// +// VOID +// HalpPerformanceCounter0Interrupt +// ) +// +// Routine Description: +// +// This function is executed as the result of an interrupt from the +// internal microprocessor performance counter 0. The interrupt +// may be used to signal the completion of a profile event. +// If profiling is current active, the function determines if the +// profile interval has expired and if so dispatches to the standard +// system routine to update the system profile time. If profiling +// is not active then the function performs a secondary dispatch for +// performance counter 0. +// +// Arguments: +// +// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for +// the interrupt. +// +// Return Value: +// +// TRUE is returned. +// +//-- + + NESTED_ENTRY(HalpPerformanceCounter0Interrupt, PrFrameLength, zero ) + + lda sp, -PrFrameLength(sp) // allocate a stack frame + stq ra, PrRa(sp) // save the return address + + PROLOGUE_END // + + call_pal rdpcr // v0 = pcr base address + + ldl t0, PcProfileCount0(v0) // capture the current profile count + beq t0, 20f // if eq, profiling not active + +// +// Profiling is active. Decrement the interval count and if it has +// reached zero then call the kernel profile routine. +// + + subl t0, 1, t0 // decrement the interval count + bne t0, 10f // if ne, interval has not expired + +// +// The profile interval has expired. Reset the profile interval count +// and process the profile interrupt. +// + + ldl t0, PcProfileCountReload0(v0) // get the new tick count + stl t0, PcProfileCount0(v0) // reset the profile interval count + + ldl a1, HalpProfileSource0 + bis fp, zero, a0 // pass trap frame pointer + ldl t1, __imp_KeProfileInterruptWithSource + jsr ra, (t1) // process the profile interrupt + + br zero, 40f // common return + +// +// The profile interval has not expired. Update the decremented count. +// + +10: + stl t0, PcProfileCount0(v0) // update profile interval count + br zero, 40f // common return + +// +// Profiling is not active. Therefore, this interrupt was caused by +// a performance counter driver. Deliver a secondary dispatch. +// + +20: + + ldil a0, PC0_SECONDARY_VECTOR // get IDT vector for secondary + s4addl a0, v0, a0 // a0 = PCR + IDT index + ldl a0, PcInterruptRoutine(a0) // get service routine address + jsr ra, (a0) // call interrupt service routine + +// +// Setup for return. +// + +40: + ldil v0, TRUE // set return value = TRUE + ldq ra, PrRa(sp) // restore return address + lda sp, PrFrameLength(sp) // deallocate the stack frame + ret zero, (ra) // return + + .end HalpPerformanceCounter0Interrupt + + + SBTTL("Performance Counter 1 Interrupt") +//++ +// +// VOID +// HalpPerformanceCounter1Interrupt +// ) +// +// Routine Description: +// +// This function is executed as the result of an interrupt from the +// internal microprocessor performance counter 1. The interrupt +// may be used to signal the completion of a profile event. +// If profiling is current active, the function determines if the +// profile interval has expired and if so dispatches to the standard +// system routine to update the system profile time. If profiling +// is not active then the function performs a secondary dispatch for +// performance counter 1. +// +// Arguments: +// +// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for +// the interrupt. +// +// Return Value: +// +// TRUE is returned. +// +//-- + + NESTED_ENTRY(HalpPerformanceCounter1Interrupt, PrFrameLength, zero ) + + lda sp, -PrFrameLength(sp) // allocate a stack frame + stq ra, PrRa(sp) // save the return address + + PROLOGUE_END // + + call_pal rdpcr // v0 = pcr base address + + ldl t0, PcProfileCount1(v0) // capture the current profile count + beq t0, 20f // if eq, profiling not active + +// +// Profiling is active. Decrement the interval count and if it has +// reached zero then call the kernel profile routine. +// + + subl t0, 1, t0 // decrement the interval count + bne t0, 10f // if ne, interval has not expired + +// +// The profile interval has expired. Reset the profile interval count +// and process the profile interrupt. +// + + ldl t0, PcProfileCountReload1(v0) // get the new tick count + stl t0, PcProfileCount1(v0) // reset the profile interval count + + ldl a1, HalpProfileSource1 + bis fp, zero, a0 // pass trap frame pointer + ldl t1, __imp_KeProfileInterruptWithSource + jsr ra, (t1) // process the profile interrupt + + br zero, 40f // common return + +// +// The profile interval has not expired. Update the decremented count. +// + +10: + stl t0, PcProfileCount1(v0) // update profile interval count + br zero, 40f // common return + +// +// Profiling is not active. Therefore, this interrupt was caused by +// a performance counter driver. Deliver a secondary dispatch. +// + +20: + + ldil a0, PC1_SECONDARY_VECTOR // get IDT vector for secondary + s4addl a0, v0, a0 // a0 = PCR + IDT index + ldl a0, PcInterruptRoutine(a0) // get service routine address + jsr ra, (a0) // call interrupt service routine + +// +// Setup for return. +// + +40: + ldil v0, TRUE // set return value = TRUE + ldq ra, PrRa(sp) // restore return address + lda sp, PrFrameLength(sp) // deallocate the stack frame + ret zero, (ra) // return + + .end HalpPerformanceCounter1Interrupt + + SBTTL("Performance Counter 2 Interrupt") +//++ +// +// VOID +// HalpPerformanceCounter2Interrupt +// ) +// +// Routine Description: +// +// This function is executed as the result of an interrupt from the +// internal microprocessor performance counter 2. The interrupt +// may be used to signal the completion of a profile event. +// If profiling is current active, the function determines if the +// profile interval has expired and if so dispatches to the standard +// system routine to update the system profile time. If profiling +// is not active then the function performs a secondary dispatch for +// performance counter 2. +// +// Arguments: +// +// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for +// the interrupt. +// +// Return Value: +// +// TRUE is returned. +// +//-- + + NESTED_ENTRY(HalpPerformanceCounter2Interrupt, PrFrameLength, zero ) + + lda sp, -PrFrameLength(sp) // allocate a stack frame + stq ra, PrRa(sp) // save the return address + + PROLOGUE_END // + + call_pal rdpcr // v0 = pcr base address + + ldl t0, PcProfileCount2(v0) // capture the current profile count + beq t0, 20f // if eq, profiling not active + +// +// Profiling is active. Decrement the interval count and if it has +// reached zero then call the kernel profile routine. +// + + subl t0, 1, t0 // decrement the interval count + bne t0, 10f // if ne, interval has not expired + +// +// The profile interval has expired. Reset the profile interval count +// and process the profile interrupt. +// + + ldl t0, PcProfileCountReload2(v0) // get the new tick count + stl t0, PcProfileCount2(v0) // reset the profile interval count + + ldl a1, HalpProfileSource2 + bis fp, zero, a0 // pass trap frame pointer + ldl t1, __imp_KeProfileInterruptWithSource + jsr ra, (t1) // process the profile interrupt + + br zero, 40f // common return + +// +// The profile interval has not expired. Update the decremented count. +// + +10: + stl t0, PcProfileCount2(v0) // update profile interval count + br zero, 40f // common return + +// +// Profiling is not active. Therefore, this interrupt was caused by +// a performance counter driver. Deliver a secondary dispatch. +// + +20: + + ldil a0, PC2_SECONDARY_VECTOR // get IDT vector for secondary + s4addl a0, v0, a0 // a0 = PCR + IDT index + ldl a0, PcInterruptRoutine(a0) // get service routine address + jsr ra, (a0) // call interrupt service routine + +// +// Setup for return. +// + +40: + ldil v0, TRUE // set return value = TRUE + ldq ra, PrRa(sp) // restore return address + lda sp, PrFrameLength(sp) // deallocate the stack frame + ret zero, (ra) // return + + .end HalpPerformanceCounter2Interrupt + +//++ +// +// ULONGLONG +// HalpRead21164PerformanceCounter( +// VOID +// ) +// +// Routine Description: +// +// Read the processor performance counter register +// +// Arguments: +// +// None. +// +// Return Value: +// +// The current value of the performance counter register. +// +//-- + + LEAF_ENTRY(HalpRead21164PerformanceCounter) + + bis zero, 1, a1 // indicate read operation + call_pal wrperfmon // read the performance counter + + ret zero, (ra) // return to caller + + .end HalpRead21164PerformanceCounter + + +//++ +// +// VOID +// HalpWrite21164PerformanceCounter( +// ULONGLONG PmCtr +// ULONG CboxMux1 +// ULONG CboxMux2 +// ) +// +// Routine Description: +// +// Write the processor performance counter register +// +// Arguments: +// +// PmCtr(a0) - value to be written to the performance counter +// CboxMux1(a1) - value to be written to Cbox mux 1 select (optional) +// CboxMux2(a2) - value to be written to Cbox mux 2 select (optional) +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpWrite21164PerformanceCounter) + + bis zero, a2, a3 // move arguments up + bis zero, a1, a2 // + bis zero, zero, a1 // indicate write operation + call_pal wrperfmon // write the performance counter + + ret zero, (ra) + + .end HalpWrite21164PerformanceCounter diff --git a/private/ntos/nthals/halalpha/ev5mchk.c b/private/ntos/nthals/halalpha/ev5mchk.c new file mode 100644 index 000000000..400c2a95c --- /dev/null +++ b/private/ntos/nthals/halalpha/ev5mchk.c @@ -0,0 +1,677 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + ev5mchk.c + +Abstract: + + This module implements generalized machine check handling for + platforms based on the DECchip 21164 (EV5) microprocessor. + +Author: + + Joe Notarangelo 30-Jun-1994 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "halp.h" +#include "axp21164.h" +#include "stdio.h" + + +// +// Declare the extern variable UncorrectableError declared in +// inithal.c. +// +extern PERROR_FRAME PUncorrectableError; + + +VOID +HalpDisplayLogout21164( + IN PLOGOUT_FRAME_21164 LogoutFrame ); + +BOOLEAN +HalpPlatformMachineCheck( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN PKTRAP_FRAME TrapFrame + ); + +VOID +HalpUpdateMces( + IN BOOLEAN ClearMachineCheck, + IN BOOLEAN ClearCorrectableError + ); + +// +// System-wide controls for machine check reporting. +// + +ProcessorCorrectableDisable = FALSE; +SystemCorrectableDisable = FALSE; +MachineCheckDisable = FALSE; + +// +// Error counts. +// + +ULONG CorrectableErrors = 0; +ULONG RetryableErrors = 0; + +VOID +HalpSetMachineCheckEnables( + IN BOOLEAN DisableMachineChecks, + IN BOOLEAN DisableProcessorCorrectables, + IN BOOLEAN DisableSystemCorrectables + ) +/*++ + +Routine Description: + + This function sets the enables that define which machine check + errors will be signaled by the processor. + + N.B. - The system has the capability to ignore all machine checks + by indicating DisableMachineChecks = TRUE. This is intended + for debugging purposes on broken hardware. If you disable + this you will get no machine check no matter what error the + system/processor detects. Consider the consequences. + +Arguments: + + DisableMachineChecks - Supplies a boolean which indicates if all + machine checks should be disabled and not + reported. (see note above). + + DisableProcessorCorrectables - Supplies a boolean which indicates if + processor correctable error reporting + should be disabled. + DisableSystemCorrectables - Supplies a boolean which indicates if + system correctable error reporting + should be disabled. + +Return Value: + + None. + +--*/ +{ + + + ProcessorCorrectableDisable = DisableProcessorCorrectables; + SystemCorrectableDisable = DisableSystemCorrectables; + MachineCheckDisable = DisableMachineChecks; + + HalpUpdateMces( FALSE, FALSE ); + + return; +} + +VOID +HalpUpdateMces( + IN BOOLEAN ClearMachineCheck, + IN BOOLEAN ClearCorrectableError + ) +/*++ + +Routine Description: + + This function updates the state of the MCES internal processor + register. + +Arguments: + + ClearMachineCheck - Supplies a boolean that indicates if the machine + check indicator in the MCES should be cleared. + + ClearCorrectableError - Supplies a boolean that indicates if the + correctable error indicators in the MCES should + be cleared. + +Return Value: + + None. + +--*/ +{ + MCES Mces; + + Mces.MachineCheck = ClearMachineCheck; + Mces.SystemCorrectable = ClearCorrectableError; + Mces.ProcessorCorrectable = ClearCorrectableError; + Mces.DisableProcessorCorrectable = ProcessorCorrectableDisable; + Mces.DisableSystemCorrectable = SystemCorrectableDisable; + Mces.DisableMachineChecks = MachineCheckDisable; + + HalpWriteMces( Mces ); + +} + + +BOOLEAN +HalMachineCheck ( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN PKTRAP_FRAME TrapFrame + ) +/*++ + +Routine Description: + + This function fields machine check for 21164-based machines. + +Arguments: + + ExceptionRecord - Supplies a pointer to the exception record for the + machine check. Included in the exception information + is the pointer to the logout frame. + + ExceptionFrame - Supplies a pointer to the kernel exception frame. + + TrapFrame - Supplies a pointer to the kernel trap frame. + +Return Value: + + A value of TRUE is returned if the machine check has been + handled by the HAL. If it has been handled then execution may + resume at the faulting address. Otherwise, a value of FALSE + is returned. + + N.B. - Under some circumstances this routine may not return at + all. + +--*/ + +{ + + BOOLEAN Handled; + PLOGOUT_FRAME_21164 LogoutFrame; + PMCHK_STATUS MachineCheckStatus; + MCES Mces; + PICPERR_STAT_21164 icPerrStat; + PDC_PERR_STAT_21164 dcPerrStat; + PSC_STAT_21164 scStat; + PEI_STAT_21164 eiStat; + BOOLEAN UnhandledPlatformError = FALSE; + + PUNCORRECTABLE_ERROR uncorrerr = NULL; + PPROCESSOR_EV5_UNCORRECTABLE ev5uncorr = NULL; + + // + // Check for retryable errors. These are usually I-stream parity + // errors, which may be retried following a cache flush (the cache + // flush is handled by the PAL). + // + + MachineCheckStatus = + (PMCHK_STATUS)&ExceptionRecord->ExceptionInformation[0]; + + // + // Handle any retryable errors. + // + + if( MachineCheckStatus->Retryable == 1 ){ + + // + // Log the error. + // + + RetryableErrors += 1; + +#if (DBG) || (HALDBG) + + if( (RetryableErrors % 32) == 0 ){ + DbgPrint( "HAL Retryable Errors = %d\n", RetryableErrors ); + } + +#endif //DBG || HALDBG + + // + // Acknowledge receipt of the retryable machine check. + // + + HalpUpdateMces( TRUE, TRUE ); + + return TRUE; + + } + + // + // Capture the logout frame pointer. + // + + LogoutFrame = + (PLOGOUT_FRAME_21164)ExceptionRecord->ExceptionInformation[1]; + + // + // Check for any hard errors that cannot be dismissed. + // They are: + // Tag parity error + // Tag control parity error + // Multiple external errors + // Fill ECC error + // Fill parity error + // Multiple fill errors + // + + icPerrStat = (PICPERR_STAT_21164)&LogoutFrame->IcPerrStat; + dcPerrStat = (PDC_PERR_STAT_21164)&LogoutFrame->DcPerrStat; + scStat = (PSC_STAT_21164)&LogoutFrame->ScStat; + eiStat = (PEI_STAT_21164)&LogoutFrame->EiStat; + + if(PUncorrectableError) { + // + // Fill in the processor specific uncorrectable error frame + // + uncorrerr = (PUNCORRECTABLE_ERROR) + &PUncorrectableError->UncorrectableFrame; + + // + // first fill in some generic processor Information. + // For the Current (Reporting) Processor. + // + HalpGetProcessorInfo(&uncorrerr->ReportingProcessor); + uncorrerr->Flags.ProcessorInformationValid = 1; + + ev5uncorr = (PPROCESSOR_EV5_UNCORRECTABLE) + uncorrerr->RawProcessorInformation; + } + if(ev5uncorr){ + ev5uncorr->IcPerrStat = LogoutFrame->IcPerrStat.all; + ev5uncorr->DcPerrStat = LogoutFrame->DcPerrStat.all; + ev5uncorr->ScStat = LogoutFrame->ScStat.all; + ev5uncorr->ScAddr = LogoutFrame->ScAddr.all; + ev5uncorr->EiStat = LogoutFrame->EiStat.all; + ev5uncorr->BcTagAddr = LogoutFrame->BcTagAddr.all; + ev5uncorr->EiAddr = LogoutFrame->EiAddr.all; + ev5uncorr->FillSyn = LogoutFrame->FillSyn.all; + ev5uncorr->BcConfig = LogoutFrame->BcConfig.all; + ev5uncorr->BcControl = LogoutFrame->BcControl.all; + } + +// +// SjBfix. The External parity error checking is disabled due to bug +// Rattler chipset on Gamma which causes the parity error on +// machine checks due to reads to PCI config space. (fixed in pass 2) +// + + if ( icPerrStat->Dpe == 1 || icPerrStat->Tpe == 1 || + icPerrStat->Tmr == 1 || dcPerrStat->Lock == 1 || + scStat->ScTperr == 1 || scStat->ScDperr == 1 || + eiStat->BcTperr == 1 || eiStat->BcTcperr == 1 || +// eiStat->UncEccErr == 1 || eiStat->EiParErr == 1 || + eiStat->SeoHrdErr == 1 || scStat->ScScndErr == 1 ){ + + // + // A serious, uncorrectable error has occured, under no circumstances + // can it be simply dismissed. + // + + goto FatalError; + + } + + // + // It is possible that the system has experienced a hard error and + // that nonetheless the error is recoverable. This is a system-specific + // decision - allow it to be handled as such. + // + + UnhandledPlatformError = TRUE; + if( (Handled = HalpPlatformMachineCheck( + ExceptionRecord, + ExceptionFrame, + TrapFrame )) == TRUE ){ + + // + // The system-specific code has handled the error. Dismiss + // the error and continue execution. + // + + HalpUpdateMces( TRUE, TRUE ); + + return TRUE; + + } + +// +// The system has experienced a fatal error that cannot be corrected. +// Print any possible relevant information and crash the system. +// +// N.B. - In the future some of these fatal errors could be potential +// recovered. Example, a user process gets a fatal error on one +// of its pages - we kill the user process, mark the page as bad +// and continue executing. +// + +FatalError: + + uncorrerr->Flags.ErrorStringValid = 1; + sprintf(uncorrerr->ErrorString,"Uncorrectable Error From " + "Processor Detected"); + // + // Begin the error output if this is a processor error. If this is + // an unhandled platform error than that code is responsible for + // beginning the error output. + // + + if( UnhandledPlatformError == FALSE ){ + + // + // Acquire ownership of the display. This is done here in case we take + // a machine check before the display has been taken away from the HAL. + // When the HAL begins displaying strings after it has lost the + // display ownership then the HAL will be careful not to scroll + // information off of the screen. + // + + HalAcquireDisplayOwnership(NULL); + + // + // Display the dreaded banner. + // + + HalDisplayString( "\nFatal system hardware error.\n\n" ); + + } + + // + // Display the EV5 logout frame. + // + + HalpDisplayLogout21164( LogoutFrame ); + + // + // Bugcheck to dump the rest of the machine state, this will help + // if the machine check is software-related. + // + + KeBugCheckEx( DATA_BUS_ERROR, + (ULONG)MachineCheckStatus->Correctable, + (ULONG)MachineCheckStatus->Retryable, + 0, + (ULONG)PUncorrectableError ); + +} + +#define MAX_ERROR_STRING 100 + +VOID +HalpDisplayLogout21164 ( + IN PLOGOUT_FRAME_21164 LogoutFrame + ) + +/*++ + +Routine Description: + + This function displays the logout frame for a 21164. + +Arguments: + + LogoutFrame - Supplies a pointer to the logout frame generated + by the 21164. +Return Value: + + None. + +--*/ + +{ + UCHAR OutBuffer[ MAX_ERROR_STRING ]; + + sprintf( OutBuffer, "ICSR : %016Lx ICPERR_STAT : %016Lx\n", + LogoutFrame->Icsr.all, LogoutFrame->IcPerrStat.all ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "MM_STAT : %016Lx DC_PERR_STAT : %016Lx\n", + LogoutFrame->MmStat.all, + LogoutFrame->DcPerrStat.all ); + + HalDisplayString( OutBuffer ); + + + sprintf( OutBuffer, "PS : %016Lx VA : %016Lx VA_FORM : %016Lx\n", + LogoutFrame->Ps, + LogoutFrame->Va, + LogoutFrame->VaForm ); + + HalDisplayString( OutBuffer ); + + + sprintf( OutBuffer, "ISR : %016Lx IPL : %016Lx INTID : %016Lx\n", + LogoutFrame->Isr.all, + LogoutFrame->Ipl, + LogoutFrame->IntId ); + + HalDisplayString( OutBuffer ); + + + sprintf( OutBuffer, "SC_STAT : %016Lx SC_CTL : %016Lx SC_ADDR : %016Lx\n", + LogoutFrame->ScStat.all, + LogoutFrame->ScCtl.all, + LogoutFrame->ScAddr.all ); + + HalDisplayString( OutBuffer ); + + + sprintf( OutBuffer, "EI_STAT : %016Lx EI_ADDR : %016Lx\n", + LogoutFrame->EiStat.all, LogoutFrame->EiAddr.all ); + + HalDisplayString( OutBuffer ); + + + sprintf( OutBuffer, "BC_TAG_ADDR : %016Lx FILL_SYN : %016Lx\n", + LogoutFrame->BcTagAddr.all, LogoutFrame->FillSyn.all ); + + + HalDisplayString( OutBuffer ); + + + sprintf( OutBuffer, "BC_CONTROL : %016Lx BC_CONFIG : %016Lx\n", + LogoutFrame->BcControl.all, LogoutFrame->BcConfig.all ); + + HalDisplayString( OutBuffer ); + + + sprintf( OutBuffer, "EXC_ADDR : %016Lx PAL_BASE : %016Lx\n", + LogoutFrame->ExcAddr, LogoutFrame->PalBase ); + + HalDisplayString( OutBuffer ); + + // + // Print out interpretation of the error. + // + + HalDisplayString( "\n" ); + + // + // Check for tag parity error. + // + + if ( LogoutFrame->IcPerrStat.Dpe == 1 || + LogoutFrame->IcPerrStat.Tpe == 1 ){ + + // + // Note: The excAddr may contain the address of the instruction + // the caused the parity error but it is not guaranteed: + // + sprintf( OutBuffer, "Icache %s parity error, Addr: %x\n", + LogoutFrame->IcPerrStat.Dpe ? "Data" : "Tag", + LogoutFrame->ExcAddr ); + + HalDisplayString( OutBuffer ); + + } else if ( LogoutFrame->DcPerrStat.Lock == 1 ){ + + sprintf( OutBuffer, "Dcache %s parity error, Addr: %x\n", + LogoutFrame->DcPerrStat.Dp0 || LogoutFrame->DcPerrStat.Dp1 ? + "Data" : "Tag", + LogoutFrame->Va ); + + HalDisplayString( OutBuffer ); + + } else if ( LogoutFrame->ScStat.ScTperr != 0 ) { + + sprintf( OutBuffer, + "Scache Tag parity error, Addr: %x Tag: %x Cmd: %x\n", + LogoutFrame->ScAddr.ScAddr, + LogoutFrame->ScStat.ScTperr, + LogoutFrame->ScStat.CboxCmd); + + HalDisplayString( OutBuffer ); + + + } else if ( LogoutFrame->ScStat.ScDperr != 0 ) { + + sprintf( OutBuffer, + "Scache Data parity error, Addr: %x Tag: %x Cmd: %x\n", + LogoutFrame->ScAddr.ScAddr, + LogoutFrame->ScStat.ScDperr, + LogoutFrame->ScStat.CboxCmd); + + HalDisplayString( OutBuffer ); + + + } else if ( LogoutFrame->EiStat.BcTperr == 1 || + LogoutFrame->EiStat.BcTcperr == 1 ){ + + sprintf( OutBuffer, + "Bcache Tag Parity error, Addr: %x Tag: %x\n", + LogoutFrame->EiAddr.EiAddr, + LogoutFrame->BcTagAddr.Tag1); + + HalDisplayString( OutBuffer ); + + } + + // + // Check for timeout reset error: + // + + if ( LogoutFrame->IcPerrStat.Tmr == 1 ){ + + sprintf( OutBuffer, "Timeout Reset Error\n" ); + + HalDisplayString( OutBuffer ); + } + + // + // Check for fill ECC errors. + // + + if( LogoutFrame->EiStat.UncEccErr == 1 ){ + + sprintf( OutBuffer, "Uncorrectable ECC error: %s\n", + LogoutFrame->EiStat.FilIrd ? "Icache Fill" : "Dcache Fill" ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, + "PA: %16Lx Longword0: %x Longword1: %x\n", + LogoutFrame->EiAddr.EiAddr, + LogoutFrame->FillSyn.Lo, + LogoutFrame->FillSyn.Hi ); + + HalDisplayString( OutBuffer ); + + } + + // + // Check for address/command parity error + // + + if( LogoutFrame->EiStat.EiParErr == 1 ){ + + sprintf( OutBuffer, "Address/Command parity error, Addr=%x\n", + LogoutFrame->EiAddr.EiAddr ); + + HalDisplayString( OutBuffer ); + + } + + // + // Check for multiple hard errors. + // + + if ( LogoutFrame->ScStat.ScScndErr == 1 ){ + + HalDisplayString( "Multiple Scache parity errors detected.\n" ); + } + + if( LogoutFrame->EiStat.SeoHrdErr == 1 ){ + + HalDisplayString( "Multiple external/tag errors detected.\n" ); + + } + + return; +} + + +BOOLEAN +Halp21164CorrectedErrorInterrupt ( + VOID + ) + +/*++ + +Routine Description: + + This is the interrupt handler for the 21164 processor corrected error + interrupt. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + // + // Handle any processor correctable errors. + // + + + // + // Log the error. + // + // simply assume this was a fill ecc correctable for now, print + // a debug message periodically + + CorrectableErrors += 1; + +#if 0 //jnfix +#if (DBG) || (HALDBG) + + if( (CorrectableErrors % 32) == 0 ){ + DbgPrint( "Correctable errors = %d\n", CorrectableErrors ); + } + +#endif //DBG || HALDBG +#endif //0 jnfix + + // + // Acknowledge receipt of the correctable error by clearing + // the error in the MCES register. + // + + HalpUpdateMces( FALSE, TRUE ); + + return TRUE; + +} diff --git a/private/ntos/nthals/halalpha/ev5mem.s b/private/ntos/nthals/halalpha/ev5mem.s new file mode 100644 index 000000000..bd82d7f52 --- /dev/null +++ b/private/ntos/nthals/halalpha/ev5mem.s @@ -0,0 +1,231 @@ +// TITLE("EV5 Memory Operations") +//++ +// +// Copyright (c) 1994 Digital Equipment Corporation +// +// Module Name: +// +// ev5mem.s +// +// Abstract: +// +// This module implements EV5 memory operations that require assembly +// language. +// +// Author: +// +// Joe Notarangelo 30-Jun-1994 +// +// Environment: +// +// HAL, Kernel mode only. +// +// Revision History: +// +//-- + +#include "ksalpha.h" + + +//++ +// +// VOID +// HalZeroPage ( +// IN PVOID NewColor, +// IN PVOID OldColor, +// IN ULONG PageFrame +// ) +// +// Routine Description: +// +// This function zeros a page of memory. +// +// Arguments: +// +// NewColor (a0) - Supplies the page aligned virtual address of the +// new color of the page that is zeroed. +// +// OldColor (a1) - Supplies the page aligned virtual address of the +// old color of the page that is zeroed. +// +// PageFrame (a2) - Supplies the page frame number of the page that +// is zeroed. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalZeroPage) + + .set noreorder // hand scheduled + +#define ZERO_BLOCK_SIZE (256) +#define ZERO_LOOPS (PAGE_SIZE/ZERO_BLOCK_SIZE) + +// +// Map the page via the 43-bit super-page on EV5. +// + + ldiq t0, -0x4000 // 0xffff ffff ffff c000 + sll a2, PAGE_SHIFT, t1 // physical address of page + + sll t0, 28, t0 // 0xffff fc00 0000 0000 + ldil t2, ZERO_LOOPS // set count of loops to run + + bis t0, t1, t0 // set super-page enable + physical + br zero, 10f // start the zeroing + +// +// Zero the page in a loop, zeroing 256 bytes per iteration. This number +// was chosen to tradeoff loop overhead versus the overhead of fetching +// Icache blocks. +// + + .align 4 // align as branch target +10: + stq zero, 0x00(t0) // + subl t2, 1, t2 // decrement the loop count + + stq zero, 0x08(t0) // + stq zero, 0x10(t0) // + + stq zero, 0x18(t0) // + stq zero, 0x20(t0) // + + stq zero, 0x28(t0) // + stq zero, 0x30(t0) // + + stq zero, 0x38(t0) // + stq zero, 0x40(t0) // + + stq zero, 0x48(t0) // + stq zero, 0x50(t0) // + + stq zero, 0x58(t0) // + stq zero, 0x60(t0) // + + stq zero, 0x68(t0) // + stq zero, 0x70(t0) // + + stq zero, 0x78(t0) // + stq zero, 0x80(t0) // + + stq zero, 0x88(t0) // + stq zero, 0x90(t0) // + + stq zero, 0x98(t0) // + stq zero, 0xa0(t0) // + + stq zero, 0xa8(t0) // + stq zero, 0xb0(t0) // + + stq zero, 0xb8(t0) // + bis t0, zero, t1 // copy base register + + stq zero, 0xc0(t0) // + stq zero, 0xc8(t0) // + + stq zero, 0xd0(t0) // + stq zero, 0xd8(t0) // + + stq zero, 0xe0(t0) // + lda t0, 0x100(t0) // increment to next block + + stq zero, 0xe8(t1) // + stq zero, 0xf0(t1) // + + stq zero, 0xf8(t1) // use stt for dual issue with bne + bne t2, 10b // while count > 0 + + ret zero, (ra) // return + + + .set reorder // + + .end HalZeroPage + +//++ +// +// ULONGLONG +// EV5_READ_PHYSICAL ( +// IN ULONGLONG Physical +// ) +// +// Routine Description: +// +// This function reads a 64 bit value from the specified physical address +// The intended use of this function is to read the EV-5 C-Box registers, +// which reside in uncached memory space. +// +// Arguments: +// +// Physical (a0) - Supplies the physical address from which to read +// +// Return Value: +// +// v0 - 64 bit value read from the specified physical address +// +//-- + + LEAF_ENTRY(READ_EV5_PHYSICAL) + +// +// Create superpage address: +// + ldiq t0, -0x4000 // 0xffff ffff ffff c000 + sll t0, 28, t0 // 0xffff fc00 0000 0000 + + bis a0, t0, t0 + ldq v0, 0(t0) // get the quadword + + ret zero, (ra) + + .end READ_EV5_PHYSICAL + + +//++ +// +// VOID +// WRITE_EV5_PHYSICAL ( +// IN ULONGLONG Physical, +// IN ULONGLONG Value +// ) +// +// Routine Description: +// +// This function writes a 64 bit value to the specified physical address. +// The intended use of this function is to write the EV-5 C-Box registers, +// which reside in uncached memory space. +// +// Arguments: +// +// Physical (a0) - Supplies the physical address to write +// +// Value (a1) - Supplies the value to write +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(WRITE_EV5_PHYSICAL) + +// +// Create superpage address: +// + ldiq t0, -0x4000 // 0xffff ffff ffff c000 + sll t0, 28, t0 // 0xffff fc00 0000 0000 + + bis a0, t0, t0 + stq a1, 0(t0) // write the value + mb // order the write + mb // for sure, for sure + + ret zero, (ra) + + .end WRITE_EV5_PHYSICAL + + diff --git a/private/ntos/nthals/halalpha/ev5prof.c b/private/ntos/nthals/halalpha/ev5prof.c new file mode 100644 index 000000000..d5bab69aa --- /dev/null +++ b/private/ntos/nthals/halalpha/ev5prof.c @@ -0,0 +1,741 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + ev5prof.c + +Abstract: + + This module implements the Profile Counter using the performance + counters within the EV5 core. This module is appropriate for all + machines based on microprocessors using the EV5 core. + + N.B. - This module assumes that all processors in a multiprocessor + system are running the microprocessor at the same clock speed. + +Author: + + Steve Brooks 14-Feb-1995 (adapted from ev4prof.c) + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" +#include "axp21164.h" + + +// +// Define space in the HAL-reserved part of the PCR structure for each +// performance counter's interval count +// +// Note that ev5ints.s depends on these positions in the PCR. +// +#define PCRProfileCount ((PULONG)(HAL_PCR->ProfileCount.ProfileCount)) +#define PCRProfileCountReload ((PULONG)(&HAL_PCR->ProfileCount.ProfileCountReload)) + + +// +// Define the currently selected profile source for each counter +// +KPROFILE_SOURCE HalpProfileSource0; +KPROFILE_SOURCE HalpProfileSource1; +KPROFILE_SOURCE HalpProfileSource2; + +#define INTERVAL_DELTA (10) + +// +// Define the mapping between possible profile sources and the +// CPU-specific settings. +// +typedef struct _HALP_PROFILE_MAPPING { + BOOLEAN Supported; + ULONG MuxControl; + ULONG Counter; + ULONG EventCount; + ULONG NumberOfTicks; +} HALP_PROFILE_MAPPING, *PHALP_PROFILE_MAPPING; + +HALP_PROFILE_MAPPING HalpProfileMapping[ProfileMaximum] = +{ + {TRUE, Ev5Cycles, Ev5PerformanceCounter0, Ev5CountEvents2xx16, 10}, + {FALSE, 0,0,0,0}, + {TRUE, Ev5Instructions, Ev5PerformanceCounter0, Ev5CountEvents2xx16, 10}, + {TRUE, Ev5PipeDry, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10}, + {TRUE, Ev5LoadsIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10}, + {FALSE, 0,0,0,0}, + {TRUE, Ev5AllFlowIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10}, + {TRUE, Ev5NonIssue, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10}, + {TRUE, Ev5DcacheLDMisses, Ev5PerformanceCounter2, Ev5CountEvents2xx14, 10}, + {TRUE, Ev5IcacheRFBMisses, Ev5PerformanceCounter2, Ev5CountEvents2xx14, 10}, + {FALSE, 0,0,0,0}, + {TRUE, Ev5BRMispredicts, Ev5PerformanceCounter2, Ev5CountEvents2xx14, 10}, + {TRUE, Ev5StoresIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10}, + {TRUE, Ev5FPOpsIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10}, + {TRUE, Ev5IntOpsIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10}, + {TRUE, Ev5DualIssue, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10}, + {TRUE, Ev5TripleIssue, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10}, + {TRUE, Ev5QuadIssue, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10}, + {FALSE, 0,0,0,0}, + {TRUE, Ev5Cycles, Ev5PerformanceCounter0, Ev5CountEvents2xx16, 10}, + {TRUE, Ev5IcacheIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10}, + {TRUE, Ev5DcacheAccesses,Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10}, + {TRUE, Ev5MBStallCycles, Ev5PerformanceCounter2, Ev5CountEvents2xx14, 10}, + {TRUE, Ev5LDxLInstIssued,Ev5PerformanceCounter2, Ev5CountEvents2xx14, 10} +}; + +BOOLEAN +HalQueryProfileInterval( + IN KPROFILE_SOURCE Source + ); + +NTSTATUS +HalSetProfileSourceInterval( + IN KPROFILE_SOURCE ProfileSource, + IN OUT ULONG *Interval + ); + +VOID +HalpUpdatePerformanceCounter( + IN ULONG PerformanceCounter, + IN ULONG MuxControl, + IN ULONG EventCount + ); + + +NTSTATUS +HalpProfileSourceInformation ( + OUT PVOID Buffer, + IN ULONG BufferLength, + OUT PULONG ReturnedLength + ) +/*++ + +Routine Description: + + Returns the HAL_PROFILE_SOURCE_INFORMATION for this processor. + +Arguments: + + Buffer - output buffer + BufferLength - length of buffer on input + ReturnedLength - The length of data returned + +Return Value: + + STATUS_SUCCESS + STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize + currently needed. + +--*/ +{ + PHAL_PROFILE_SOURCE_INFORMATION SourceInfo; + NTSTATUS Status; + + + if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INFORMATION)) { + Status = STATUS_INFO_LENGTH_MISMATCH; + return Status; + } + + SourceInfo = (PHAL_PROFILE_SOURCE_INFORMATION)Buffer; + SourceInfo->Supported = HalQueryProfileInterval(SourceInfo->Source); + + if (SourceInfo->Supported) { + SourceInfo->Interval = + HalpProfileMapping[SourceInfo->Source].EventCount * + HalpProfileMapping[SourceInfo->Source].NumberOfTicks; + } + + Status = STATUS_SUCCESS; + return Status; +} + +NTSTATUS +HalpProfileSourceInterval ( + OUT PVOID Buffer, + IN ULONG BufferLength + ) +/*++ + +Routine Description: + + Returns the HAL_PROFILE_SOURCE_INTERVAL for this processor. + +Arguments: + + Buffer - output buffer + BufferLength - length of buffer on input + +Return Value: + + STATUS_SUCCESS + STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize + currently needed. + +--*/ +{ + PHAL_PROFILE_SOURCE_INTERVAL Interval; + NTSTATUS Status; + + + if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INTERVAL)) { + Status = STATUS_INFO_LENGTH_MISMATCH; + return Status; + } + + Interval = (PHAL_PROFILE_SOURCE_INTERVAL)Buffer; + Status = HalSetProfileSourceInterval(Interval->Source, + &Interval->Interval); + return Status; +} + +VOID +HalpInitializeProfiler( + VOID + ) +/*++ + +Routine Description: + + This routine is called during initialization to initialize profiling + for each processor in the system. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + + // + // Establish the profile interrupt as the interrupt handler for + // all performance counter interrupts. + // + + PCR->InterruptRoutine[PC0_VECTOR] = HalpPerformanceCounter0Interrupt; + PCR->InterruptRoutine[PC1_VECTOR] = HalpPerformanceCounter1Interrupt; + PCR->InterruptRoutine[PC2_VECTOR] = HalpPerformanceCounter2Interrupt; + + return; + +} + + +BOOLEAN +HalQueryProfileInterval( + IN KPROFILE_SOURCE Source + ) + +/*++ + +Routine Description: + + Given a profile source, returns whether or not that source is + supported. + +Arguments: + + Source - Supplies the profile source + +Return Value: + + TRUE - Profile source is supported + + FALSE - Profile source is not supported + +--*/ + +{ + if (Source > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) { + return(FALSE); + } + + return(HalpProfileMapping[Source].Supported); +} + + +NTSTATUS +HalSetProfileSourceInterval( + IN KPROFILE_SOURCE ProfileSource, + IN OUT ULONG *Interval + ) + +/*++ + +Routine Description: + + Sets the profile interval for a specified profile source + +Arguments: + + ProfileSource - Supplies the profile source + + Interval - Supplies the specified profile interval + Returns the actual profile interval + +Return Value: + + NTSTATUS + +--*/ + +{ + ULONG FastTickPeriod; + ULONG SlowTickPeriod; + ULONG TickPeriod; + ULONG FastCountEvents; + ULONG SlowCountEvents; + ULONGLONG CountEvents; + ULONGLONG TempInterval; + + if (!HalQueryProfileInterval(ProfileSource)) { + return(STATUS_NOT_IMPLEMENTED); + } + + if (ProfileSource == ProfileTime) { + + // + // Convert the clock tick period (in 100ns units ) into + // a cycle count period + // + + CountEvents = ((ULONGLONG)(*Interval) * 100000) / PCR->CycleClockPeriod; + } else { + CountEvents = (ULONGLONG)*Interval; + } + + FastCountEvents = Ev5CountEvents2xx8; + SlowCountEvents = Ev5CountEvents2xx16; + + if (HalpProfileMapping[ProfileSource].Counter == Ev5PerformanceCounter0) { + FastCountEvents = Ev5CountEvents2xx16; + } + else if (HalpProfileMapping[ProfileSource].Counter == Ev5PerformanceCounter2) { + SlowCountEvents = Ev5CountEvents2xx14; + } + + // + // Limit the interval to the smallest interval we can time. + // + if (CountEvents < FastCountEvents) { + CountEvents = (ULONGLONG)FastCountEvents; + } + + // + // Assume we will use the fast event count + // + HalpProfileMapping[ProfileSource].EventCount = FastCountEvents; + HalpProfileMapping[ProfileSource].NumberOfTicks = + (ULONG)((CountEvents + FastCountEvents - 1) / FastCountEvents); + + // + // See if we can successfully use the slower period. If the requested + // interval is greater than the slower tick period and the difference + // between the requested interval and the interval that we can deliver + // with the slower clock is acceptable, then use the slower clock. + // We define an acceptable difference as a difference of less than + // INTERVAL_DELTA of the requested interval. + // + if (CountEvents > SlowCountEvents) { + ULONG NewInterval; + + NewInterval = (ULONG)(((CountEvents + SlowCountEvents-1) / + SlowCountEvents) * SlowCountEvents); + if (((NewInterval - CountEvents) * 100 / CountEvents) < INTERVAL_DELTA) { + HalpProfileMapping[ProfileSource].EventCount = SlowCountEvents; + HalpProfileMapping[ProfileSource].NumberOfTicks = NewInterval / SlowCountEvents; + } + } + + *Interval = HalpProfileMapping[ProfileSource].EventCount * + HalpProfileMapping[ProfileSource].NumberOfTicks; + + if (ProfileSource == ProfileTime) { + // + // Convert cycle count back into 100ns clock ticks + // + // Use 64-bit integer to prevent overflow. + // + TempInterval = (ULONGLONG)(*Interval) * (ULONGLONG)(PCR->CycleClockPeriod); + *Interval = (ULONG)(TempInterval / 100000); + } + return(STATUS_SUCCESS); +} + + +ULONG +HalSetProfileInterval ( + IN ULONG Interval + ) + +/*++ + +Routine Description: + + This routine sets the profile interrupt interval. + +Arguments: + + Interval - Supplies the desired profile interval in 100ns units. + +Return Value: + + The actual profile interval. + +--*/ + +{ + ULONG NewInterval; + + NewInterval = Interval; + HalSetProfileSourceInterval(ProfileTime, &NewInterval); + return(NewInterval); +} + + + +VOID +HalStartProfileInterrupt ( + KPROFILE_SOURCE ProfileSource + ) + +/*++ + +Routine Description: + + This routine turns on the profile interrupt. + + N.B. This routine must be called at PROCLK_LEVEL while holding the + profile lock. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + ULONG PerformanceCounter; + ULONG MuxControl; + ULONG EventCount; + + // + // Check input to see if we are turning on a source that is + // supported. If it is unsupported, just return. + // + + if ((ProfileSource > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) || + (!HalpProfileMapping[ProfileSource].Supported)) { + return; + } + + // + // Set the performance counter within the processor to begin + // counting total cycles. + // + PerformanceCounter = HalpProfileMapping[ProfileSource].Counter; + MuxControl = HalpProfileMapping[ProfileSource].MuxControl; + + if (PerformanceCounter == Ev5PerformanceCounter0) { + + EventCount = (HalpProfileMapping[ProfileSource].EventCount == + Ev5CountEvents2xx16) ? Ev5EventCountLow + : Ev5EventCountHigh; + + HalpProfileSource0 = ProfileSource; + HalpUpdatePerformanceCounter( PerformanceCounter, + MuxControl, + EventCount ); + + PCRProfileCountReload[0] = HalpProfileMapping[ProfileSource].NumberOfTicks; + PCRProfileCount[0] = HalpProfileMapping[ProfileSource].NumberOfTicks; + + // + // Enable the performance counter interrupt. + // + + HalEnableSystemInterrupt ( PC0_VECTOR, + PROFILE_LEVEL, + LevelSensitive ); + + + } else if (PerformanceCounter == Ev5PerformanceCounter1) { + + EventCount = (HalpProfileMapping[ProfileSource].EventCount == + Ev5CountEvents2xx16) ? Ev5EventCountLow + : Ev5EventCountHigh; + + HalpProfileSource1 = ProfileSource; + HalpUpdatePerformanceCounter( PerformanceCounter, + MuxControl, + EventCount ); + + PCRProfileCountReload[1] = HalpProfileMapping[ProfileSource].NumberOfTicks; + PCRProfileCount[1] = HalpProfileMapping[ProfileSource].NumberOfTicks; + + // + // Enable the performance counter interrupt. + // + + HalEnableSystemInterrupt ( PC1_VECTOR, + PROFILE_LEVEL, + LevelSensitive ); + + } else if (PerformanceCounter == Ev5PerformanceCounter2) { + + EventCount = (HalpProfileMapping[ProfileSource].EventCount == + Ev5CountEvents2xx14) ? Ev5EventCountLow + : Ev5EventCountHigh; + + HalpProfileSource2 = ProfileSource; + HalpUpdatePerformanceCounter( PerformanceCounter, + MuxControl, + EventCount ); + + PCRProfileCountReload[2] = HalpProfileMapping[ProfileSource].NumberOfTicks; + PCRProfileCount[2] = HalpProfileMapping[ProfileSource].NumberOfTicks; + + // + // Enable the performance counter interrupt. + // + + HalEnableSystemInterrupt ( PC2_VECTOR, + PROFILE_LEVEL, + LevelSensitive ); + } + + return; +} + + +VOID +HalStopProfileInterrupt ( + KPROFILE_SOURCE ProfileSource + ) + +/*++ + +Routine Description: + + This routine turns off the profile interrupt. + + N.B. This routine must be called at PROCLK_LEVEL while holding the + profile lock. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + ULONG PerformanceCounter; + ULONG Vector; + + // + // Check input to see if we are turning off a source that is + // supported. If it is unsupported, just return. + // + + if ((ProfileSource > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) || + (!HalpProfileMapping[ProfileSource].Supported)) { + return; + } + + // + // Stop the performance counter from interrupting. + // + + PerformanceCounter = HalpProfileMapping[ProfileSource].Counter; + HalpUpdatePerformanceCounter( PerformanceCounter, + 0, + Ev5CounterDisable ); + + // + // Disable the performance counter interrupt. + // + if (PerformanceCounter == Ev5PerformanceCounter0) { + + HalDisableSystemInterrupt( PC0_VECTOR, PROFILE_LEVEL ); + + // + // Clear the current profile count. Can't clear value in PCR + // since a profile interrupt could be pending or in progress + // so clear the reload counter. + // + + PCRProfileCountReload[0] = 0; + + } else if (PerformanceCounter == Ev5PerformanceCounter1) { + + HalDisableSystemInterrupt( PC1_VECTOR, PROFILE_LEVEL ); + + // + // Clear the current profile count. Can't clear value in PCR + // since a profile interrupt could be pending or in progress + // so clear the reload counter. + // + + PCRProfileCountReload[1] = 0; + + } else if (PerformanceCounter == Ev5PerformanceCounter2) { + + HalDisableSystemInterrupt( PC2_VECTOR, PROFILE_LEVEL ); + + // + // Clear the current profile count. Can't clear value in PCR + // since a profile interrupt could be pending or in progress + // so clear the reload counter. + // + + PCRProfileCountReload[2] = 0; + } + + return; +} + + +VOID +HalpUpdatePerformanceCounter( + IN ULONG PerformanceCounter, + IN ULONG MuxControl, + IN ULONG EventCount + ) +//++ +// +// Routine Description: +// +// Write the specified microprocessor internal performance counter. +// +// Arguments: +// +// PerformanceCounter(a0) - Supplies the number of the performance counter +// to write. +// +// MuxControl(a2) - Supplies the mux control value which selects which +// type of event to count when the counter is enabled. +// +// EventCount(a3) - Supplies the event interval when the counter is +// enabled. +// +// Return Value: +// +// None. +// +//-- + +{ + PMCTR_21164 PmCtr; // the performance counter register + ULONG CboxMux1 = 0; // CBOX select 1 mux value + ULONG CboxMux2 = 0; // CBOX select 2 mux value + + PmCtr.all = HalpRead21164PerformanceCounter(); + + // + // Check for special values first: + // + + if ( MuxControl >= Ev5PcSpecial ) { + + switch( MuxControl ) { + + // + // Count JsrRet Issued + // + + case Ev5JsrRetIssued: + + PmCtr.Ctl1 = EventCount; + PmCtr.Sel1 = Ev5FlowChangeInst; + PmCtr.Sel2 = Ev5PCMispredicts; + break; + + // + // Count CondBr Issued + // + + case Ev5CondBrIssued: + + PmCtr.Ctl1 = EventCount; + PmCtr.Sel1 = Ev5FlowChangeInst; + PmCtr.Sel2 = Ev5BRMispredicts; + break; + + // + // Count all flow change inst Issued + // + + case Ev5AllFlowIssued: + + PmCtr.Ctl1 = EventCount; + PmCtr.Sel1 = Ev5FlowChangeInst; + + if ( (PmCtr.Sel2 == Ev5PCMispredicts) || + (PmCtr.Sel2 == Ev5BRMispredicts)) { + + PmCtr.Sel2 = Ev5LongStalls; + + } + break; + + // + // Must be an Scache counter. Select the appropriate counter + // in Sel1 or Sel2, and pass the CBOX mux value to WritePerfCounter + // + + default: + + if ( MuxControl <= Ev5ScSystemCmdReq ) { + + PmCtr.Ctl1 = EventCount; + PmCtr.Sel1 = Ev5CBOXInput1; + CboxMux1 = MuxControl - Ev5ScMux1; + + } else if ( MuxControl <= Ev5ScSysReadReq ) { + + PmCtr.Ctl2 = EventCount; + PmCtr.Sel2 = Ev5CBOXInput2; + CboxMux2 = MuxControl - Ev5ScMux2; + + } + + } // switch + + } else if ( PerformanceCounter == Ev5PerformanceCounter0 ) { + + PmCtr.Ctl0 = EventCount; + PmCtr.Sel0 = MuxControl; + + } else if ( PerformanceCounter == Ev5PerformanceCounter1 ) { + + PmCtr.Ctl1 = EventCount; + PmCtr.Sel1 = MuxControl; + + } else if ( PerformanceCounter == Ev5PerformanceCounter2 ) { + + PmCtr.Ctl2 = EventCount; + PmCtr.Sel2 = MuxControl; + + } + + HalpWrite21164PerformanceCounter(PmCtr.all, CboxMux1, CboxMux2); +} diff --git a/private/ntos/nthals/halalpha/flash8k.c b/private/ntos/nthals/halalpha/flash8k.c new file mode 100644 index 000000000..96d198845 --- /dev/null +++ b/private/ntos/nthals/halalpha/flash8k.c @@ -0,0 +1,323 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + flash8k.c + +Abstract: + + This module implements the flash-specific, device-independent routines + necessary to Read and Write the flash ROM containing the system environment + variables. The routines implemented here are: + + HalpReadNVRamBuffer() - copy data from Flash into memory + HalpWriteNVRamBuffer() - write memory data to Flash + HalpCopyNVRamBuffer() - stubbed for compatibility with NVRAM + +Author: + + Steve Brooks 5-Oct 93 + + +Revision History: + + +--*/ + + +#include "halp.h" +#include "flash8k.h" + +#include "arccodes.h" + +// +// Variables: +// +// PFLASH_DRIVER HalpFlashDriver +// Pointer to the device-specific flash driver. +// +PFLASH_DRIVER HalpFlashDriver = NULL; + +// +// Flash Drivers +// +// Each platform which uses this module must define FlashDriverList as an +// array of pointers to the initialize functions of any flash drivers for +// which the flash device might be used for the environment in the system. +// +extern PFLASH_DRIVER (*FlashDriverList[])(PUCHAR); + + +#ifdef AXP_FIRMWARE + +#pragma alloc_text(DISTEXT, HalpReadNVRamBuffer ) +#pragma alloc_text(DISTEXT, HalpWriteNVRamBuffer ) +#pragma alloc_text(DISTEXT, HalpCopyNVRamBuffer ) +#pragma alloc_text(DISTEXT, HalpInitializeFlashDriver ) + +#endif + +ARC_STATUS HalpReadNVRamBuffer ( + OUT PCHAR DataPtr, + IN PCHAR NvRamPtr, + IN ULONG Length ) + +/*++ + +Routine Description: + + This routine Reads data from the NVRam into main memory + +Arguments: + + DataPtr - Pointer to memory location to receive data + NvRamPtr - Pointer (qva) to NVRam location to read data from + Length - Number of bytes of data to transfer + +Return Value: + + ESUCCESS if the operation succeeds. + ENODEV if no flash driver is loaded + +--*/ +{ + // + // If there is no flash driver, return an error. + // + if ((HalpFlashDriver == NULL) && + ((HalpFlashDriver = HalpInitializeFlashDriver(NvRamPtr)) == NULL)) { + + return ENODEV; + } + + // + // Read from the flash. + // + while(Length--) { + *DataPtr = HalpFlash8kReadByte(NvRamPtr); + DataPtr++; + NvRamPtr++; + } + + return ESUCCESS; +} + +// +// +// +ARC_STATUS +HalpWriteNVRamBuffer ( + IN PCHAR NvRamPtr, + IN PCHAR DataPtr, + IN ULONG Length ) + +/*++ + +Routine Description: + + This routine Writes data from memory into the NVRam + +Arguments: + + NvRamPtr - Pointer (qva) to NVRam location to write data into + DataPtr - Pointer to memory location of data to be written + Length - Number of bytes of data to transfer + +Return Value: + + ESUCCESS if the operation succeeds. + ENODEV if no flash driver is loaded + EIO if a device error was detected + +--*/ +{ + ARC_STATUS ReturnStatus = ESUCCESS; + UCHAR NeedToErase = FALSE; + UCHAR Byte; + ULONG Index; + ULONG Address; + + // + // If there is no flash driver, return an error. + // + if ((HalpFlashDriver == NULL) && + ((HalpFlashDriver = HalpInitializeFlashDriver(NvRamPtr)) == NULL)) { + + return ENODEV; + } + + // + // Try to do the udate without erasing the flash block if possible. + // We don't write bytes which agree with the current contents of the + // flash. If the byte to be written is not the same as what is already + // in the flash, write it if the new byte can overwrite the old byte. + // On the first byte that cannot be overwritten, abort this loop with + // NeedToErase == TRUE and fall through to the failsafe case below. + // + NeedToErase = FALSE; + for(Index = Length; + !NeedToErase && (ReturnStatus == ESUCCESS) && Index--;) { + + Address = (ULONG)NvRamPtr + Index; + if (((Byte = HalpFlash8kReadByte((PUCHAR)Address)) != + (UCHAR)DataPtr[Index])) { + + if (HalpFlash8kOverwriteCheck(Byte, (UCHAR)DataPtr[Index])) { + ReturnStatus = HalpFlash8kWriteByte(Address, DataPtr[Index]); + } else { +#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG) + DbgPrint("Need to erase flash because byte at %08x (%02x) ", + Address, Byte); + DbgPrint("Cannot be written with %02x\r\n", + (UCHAR)DataPtr[Index]); +#endif + + NeedToErase = TRUE; + } + } + } + + if (NeedToErase) { + ULONG BlockSize; + ULONG BlockBase; + ULONG DataBase; + PUCHAR pShadow = NULL; + + // + // We need to erase the flash block in order to write some of the + // requested data. We take the safe approach of copy the entire + // flash block into memory (we don't know what else is there), modify + // the copy in memory, erase the flash block, and write the entire + // block. + // + + DataBase = (ULONG)NvRamPtr & ~(ULONG)HalpCMOSRamBase; + BlockBase = (ULONG)HalpFlash8kBlockAlign(NvRamPtr); + BlockSize = HalpFlash8kBlockSize(BlockBase); + + pShadow = ExAllocatePool(NonPagedPool, BlockSize); + + if (pShadow != NULL) { + for(Index = 0; Index < BlockSize; Index++) { + pShadow[Index] = HalpFlash8kReadByte(BlockBase + Index); + } + + for(Index = 0; Index < Length; Index++) { + pShadow[DataBase + Index] = DataPtr[Index]; + } + + ReturnStatus = HalpFlash8kEraseBlock(BlockBase); + + for(Index = 0; + (Index < BlockSize) && (ReturnStatus == ESUCCESS); + Index++) { + + if (pShadow[Index] != HalpFlashDriver->ErasedData) { + ReturnStatus = HalpFlash8kWriteByte(BlockBase + Index, + pShadow[Index]); + } + } + + ExFreePool(pShadow); + } else { +#if defined(ALPHA_KDHOOKS) || defined(HALDBG) + DbgPrint("HalpWriteNVRamBuffer: Could not allocate shadow...\r\n"); +#endif + ReturnStatus = ENOMEM; + } + } + + HalpFlash8kSetReadMode(NvRamPtr); + return ReturnStatus; +} + +// +// +// +ARC_STATUS HalpCopyNVRamBuffer ( + IN PCHAR NvDestPtr, + IN PCHAR NvSrcPtr, + IN ULONG Length ) +/*++ + +Routine Description: + + This routine is not supported. + +Arguments: + + NvDestPtr - Pointer (qva) to NVRam location to write data into + NvSrcPtr - Pointer (qva) to NVRam location of data to copy + Length - Number of bytes of data to transfer + +Return Value: + + ENODEV if no flash driver is loaded + EIO if a flash driver is loaded + +--*/ + +{ + // + // If there is no flash driver, return an error. + // + if (HalpFlashDriver == NULL) { + return ENODEV; + } + + return EIO; +} + +PFLASH_DRIVER +HalpInitializeFlashDriver( + IN PCHAR NvRamPtr + ) +/*++ + +Routine Description: + + This routine attempts to recognize the flash device present in the + system by calling each known flash driver's Initialize() function + with the address passed in. The Initialize() functions will each + return NULL if they do not recognize the flash device at the specified + address and a pointer to a FLASH_DRIVER structure if the device is + recognized. This routine looks until it either recognizes a flash device + or runs out of known flash devices. + +Arguments: + + NvRamPtr - a pointer to an address within the flash device + +Return Value: + + A pointer to the FLASH_DRIVER structure of the driver which corresponds + to the flash device in the system. NULL if no known flash device was + recognized. + +--*/ +{ + PFLASH_DRIVER FlashDriver = NULL; + ULONG DriverNumber; + + for(DriverNumber=0; FlashDriverList[DriverNumber] != NULL; DriverNumber++) { + FlashDriver = FlashDriverList[DriverNumber](NvRamPtr); + if (FlashDriver != NULL) { + break; + } + } + +#ifdef ALPHA_FW_SERDEB + if (FlashDriver != NULL) { + SerFwPrint("Flash device found at %08x: %s\r\n", + NvRamPtr, + FlashDriver->DeviceName); + } else { + SerFwPrint("ERROR: No flash device found at %08x\r\n", NvRamPtr); + } +#endif + + return FlashDriver; +} + diff --git a/private/ntos/nthals/halalpha/flash8k.h b/private/ntos/nthals/halalpha/flash8k.h new file mode 100644 index 000000000..32a5f18f2 --- /dev/null +++ b/private/ntos/nthals/halalpha/flash8k.h @@ -0,0 +1,130 @@ +// flash8k.h + +#ifndef _FLASH8K_H_ +#define _FLASH8K_H_ + +#ifdef FLASH8K_INCLUDE_FILES +#include "halp.h" +#include "arccodes.h" +#endif //FLASH8K_DONT_INCLUDE_FILES + +// +// The value of HalpCMOSRamBase must be set at initialization +// + +typedef enum _FLASH_OPERATIONS { + FlashByteWrite, + FlashEraseBlock +} FLASH_OPERATIONS, *PFLASH_OPERATIONS; + +typedef struct _FLASH_DRIVER { + PCHAR DeviceName; + ARC_STATUS (*SetReadModeFunction)(PUCHAR address); + ARC_STATUS (*WriteByteFunction)(PUCHAR address, UCHAR data); + ARC_STATUS (*EraseBlockFunction)(PUCHAR address); + PUCHAR (*BlockAlignFunction)(PUCHAR address); + UCHAR (*ReadByteFunction)(PUCHAR address); + BOOLEAN (*OverwriteCheckFunction)(UCHAR olddata, UCHAR newdata); + ULONG (*BlockSizeFunction)(PUCHAR address); + ULONG (*GetLastErrorFunction)(VOID); + ULONG DeviceSize; + UCHAR ErasedData; +} FLASH_DRIVER, *PFLASH_DRIVER; + +extern PFLASH_DRIVER HalpFlashDriver; + +#define WRITE_CONFIG_RAM_DATA(boffset,data) \ + WRITE_REGISTER_UCHAR((PUCHAR)(boffset),((data) & 0xff)) + +#define READ_CONFIG_RAM_DATA(boffset) \ + READ_REGISTER_UCHAR((PUCHAR)(boffset)) + + +PFLASH_DRIVER +HalpInitializeFlashDriver( + IN PCHAR NvRamPtr + ); + +ARC_STATUS +HalpReadNVRamBuffer ( + OUT PCHAR DataPtr, + IN PCHAR NvRamPtr, + IN ULONG Length + ); + +ARC_STATUS +HalpWriteNVRamBuffer ( + IN PCHAR NvRamPtr, + IN PCHAR DataPtr, + IN ULONG Length + ); + +ARC_STATUS +HalpCopyNVRamBuffer ( + IN PCHAR NvDestPtr, + IN PCHAR NvSrcPtr, + IN ULONG Length + ); + + +// +// The following macros define the HalpFlash8k*() functions in terms +// of the FlashDriver variable. FlashDriver points to a structure +// containing information about the currently active flash driver. +// Information in the structure pointed to by FlashDriver includes +// functions within the driver to perform all device-dependent operations. +// + +#define HalpFlash8kSetReadMode(boffset) \ + HalpFlashDriver->SetReadModeFunction( \ + (PUCHAR)((ULONG)(HalpCMOSRamBase) | \ + (ULONG)(boffset))) + +#define HalpFlash8kReadByte(boffset) \ + HalpFlashDriver->ReadByteFunction( \ + (PUCHAR)((ULONG)(HalpCMOSRamBase) | \ + (ULONG)(boffset))) + +#define HalpFlash8kWriteByte(boffset, data) \ + HalpFlashDriver->WriteByteFunction( \ + (PUCHAR)((ULONG)(HalpCMOSRamBase) | \ + (ULONG)(boffset)), ((data) & 0xff)) + +#define HalpFlash8kOverwriteCheck(olddata, newdata) \ + HalpFlashDriver->OverwriteCheckFunction( \ + (olddata) & 0xff, (newdata) & 0xff) + +#define HalpFlash8kEraseBlock(boffset) \ + HalpFlashDriver->EraseBlockFunction( \ + (PUCHAR)((ULONG)(HalpCMOSRamBase) | \ + (ULONG)(boffset))) + +#define HalpFlash8kBlockAlign(boffset) \ + HalpFlashDriver->BlockAlignFunction( \ + (PUCHAR)((ULONG)(HalpCMOSRamBase) | \ + (ULONG)(boffset))) + +#define HalpFlash8kBlockSize(boffset) \ + HalpFlashDriver->BlockSizeFunction( \ + (PUCHAR)((ULONG)(HalpCMOSRamBase) | \ + (ULONG)(boffset))) + +#define HalpFlash8kCheckStatus(boffset, operation) \ + HalpFlashDriver->CheckStatusFunction( \ + (PUCHAR)((ULONG)(HalpCMOSRamBase) | \ + (ULONG)(boffset)), (operation)) + +#define HalpFlash8kGetLastError() \ + HalpFlashDriver->GetLastErrorFunction() + + +// +// Error codes for GetLastError() +// +#define ERROR_VPP_LOW 1L +#define ERROR_ERASE_ERROR 2L +#define ERROR_WRITE_ERROR 3L +#define ERROR_TIMEOUT 4L +#define ERROR_UNKNOWN 127L + +#endif // _FLASH8K_H_ diff --git a/private/ntos/nthals/halalpha/flashdrv.c b/private/ntos/nthals/halalpha/flashdrv.c new file mode 100644 index 000000000..6c87efecd --- /dev/null +++ b/private/ntos/nthals/halalpha/flashdrv.c @@ -0,0 +1,23 @@ +// +// Flash Drivers +// +// extern declarations of each known flash driver's Initialize() funcion +// are needed here for addition into the list of known drivers. +// +// FlashDriverList is an array of driver Initialize() functions used to +// identify the flash device present in the system. The last entry +// in FlashDriverList must be NULL. +// +#include "halp.h" +#include "flash8k.h" + +extern PFLASH_DRIVER I28F008SA_Initialize(PUCHAR); +extern PFLASH_DRIVER Am29F080_Initialize(PUCHAR); +extern PFLASH_DRIVER Am29F040_Initialize(PUCHAR); + +PFLASH_DRIVER (*FlashDriverList[])(PUCHAR) = { + I28F008SA_Initialize, + Am29F080_Initialize, + Am29F040_Initialize, + NULL}; + diff --git a/private/ntos/nthals/halalpha/fwreturn.c b/private/ntos/nthals/halalpha/fwreturn.c new file mode 100644 index 000000000..bf11d8c27 --- /dev/null +++ b/private/ntos/nthals/halalpha/fwreturn.c @@ -0,0 +1,255 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + fwreturn.c + +Abstract: + + This module implements the HAL return to firmware function. + + Stolen wholesale from s3return.c in ../mips. + Assumes that the firmware entry vector defined in the HAL spec has + been set up and is reachable through the System Parameter Block. + +Author: + + David N. Cutler (davec) 21-Aug-1991 + Miche Baker-Harvey (miche) 4-Jun-1992 + +Revision History: + + 14-Dec-1993 Joe Notarangelo + Add MP support, use reboot encoding to return to firmware + +--*/ + +#include "halp.h" + +#if !defined(NT_UP) + + +VOID // #definition of KiIpiSendPacket +KiIpiSendPacket( // not in ntmp.h. Define here + IN KAFFINITY TargetProcessors, + IN PKIPI_WORKER WorkerFunction, + IN PVOID Parameter1, + IN PVOID Parameter2, + IN PVOID Parameter3 + ); +#endif + +VOID +HalpResetHAERegisters( + VOID + ); + +VOID +HalpShutdownSystem( + ULONG HaltReasonCode + ); + + +VOID +HalReturnToFirmware( + IN FIRMWARE_REENTRY Routine + ) + +/*++ + +Routine Description: + + This function returns control to the specified firmware routine. + +Arguments: + + Routine - Supplies a value indicating which firmware routine to invoke. + +Return Value: + + Does not return. + +Revision History: + + 09-Jul-1992 Jeff McLeman (mcleman) + In all cases, except for ArcEnterInteractiveMode, invoke a + halt to restart the firmware. (Enter PAL) + 04-Mar-1993 Joe Mitchell (DEC) + Invoke a routine to call halt in ALL cases. Before calling this routine, + pass a value to the firmware indicating the desired function via + the Restart Block save area. + +--*/ + +{ + + // + // Case on the type of return. + // + + switch (Routine) + { + case HalHaltRoutine: + HalpShutdownSystem( AXP_HALT_REASON_POWEROFF ); + break; + case HalPowerDownRoutine: + HalpShutdownSystem( AXP_HALT_REASON_POWERFAIL ); + break; + case HalRestartRoutine: + HalpShutdownSystem( AXP_HALT_REASON_RESTART ); + break; + case HalRebootRoutine: + HalpShutdownSystem( AXP_HALT_REASON_REBOOT ); + break; + case HalInteractiveModeRoutine: + HalpShutdownSystem( AXP_HALT_REASON_HALT ); + break; + default: + HalDisplayString("Unknown ARCS restart function.\n"); + DbgBreakPoint(); + } + + /* NOTREACHED */ + HalDisplayString("Illegal return from ARCS restart function.\n"); + DbgBreakPoint(); +} + +VOID +HalpShutdownSystem( + ULONG HaltReasonCode + ) +/*++ + +Routine Description: + + This function causes a system shutdown so that each processor in + the system will return to the firmware. A processor returns to + the firmware by executing the reboot call pal function. + +Arguments: + + HaltReasonCode - Supplies the reason code for the halt. + +Return Value: + + None. + +--*/ +{ + PRESTART_BLOCK RestartBlock; // Boot Master Restart Block +#if !defined(NT_UP) + KAFFINITY TargetProcessors; + KIRQL OldIrql; + PKPRCB Prcb = PCR->Prcb; + ULONG Wait; +#endif + + // + // Reset video using NT driver's HwResetHw routine + // + + HalpVideoReboot(); + + // + // Reset the HAE Registers to 0 + // + + HalpResetHAERegisters(); + + // + // Write the halt reason code into the restart block of the + // boot master processor. + // + + RestartBlock = SYSTEM_BLOCK->RestartBlock; + if( RestartBlock != NULL ){ + RestartBlock->u.Alpha.HaltReason = HaltReasonCode; + } + +#if !defined(NT_UP) + +#define REBOOT_WAIT_LIMIT (5 * 1000) // loop count for 5 second wait + + // + // Raise Irql to block all interrupts except errors and IPIs. + // + + KeRaiseIrql( CLOCK_LEVEL, &OldIrql ); + + // + // Send an IPI to each processor. + // + TargetProcessors = HalpActiveProcessors; + TargetProcessors &= ~Prcb->SetMember; + +#if HALDBG + + DbgPrint( "HalpShutdown: TargetProcessors = %x, Active = %x\n", + TargetProcessors, HalpActiveProcessors ); + +#endif //HALDBG + + + KiIpiSendPacket( TargetProcessors, + (PKIPI_WORKER) HalpReboot, + NULL, + NULL, + NULL ); + + + // + // If the current processor is the primary, it must reboot and handle + // the firmware restart. If a secondary processor is executing this + // shutdown, then it waits to verify that the primary has shutdown so + // that the restart can be performed. If the primary doesn't reach the + // firmware, the system is toasted and a message is printed. + // + if ( Prcb->Number == HAL_PRIMARY_PROCESSOR ) + { + HalpReboot; // Never to return + } + + // + // Wait until the primary processor has rebooted and signalled that + // it has returned to the firmware by indicating that the processor + // is not started in the BootStatus of its restart block. (ProcessorStart=0) + // However, put a timeout on the check in case the primary processor + // is currently wedged (it may not be able to receive the IPI). + // + + Wait = 0; + while( RestartBlock->BootStatus.ProcessorStart == 0 && + Wait < REBOOT_WAIT_LIMIT ) { + // + // The Primary processor is still running. Stall for a while + // and increment the wait count. + // + + KeStallExecutionProcessor( 1000 ); // 1000000 ); + Wait ++; + + } //end while( Wait < REBOOT_WAIT_LIMIT ) + + + // + // if the wait timed out print messages to alert the user. + // + if ( Wait >= REBOOT_WAIT_LIMIT ) + { + HalDisplayString( "The Primary Processor was not shutdown.\n" ); + HalDisplayString( "Power off your system before restarting.\n" ); + } + +#endif //!NT_UP + + // + // Reboot this processor. + // + + HalpReboot(); + +} + diff --git a/private/ntos/nthals/halalpha/gru.h b/private/ntos/nthals/halalpha/gru.h new file mode 100644 index 000000000..f1cbe1067 --- /dev/null +++ b/private/ntos/nthals/halalpha/gru.h @@ -0,0 +1,84 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + gru.h + +Abstract: + + This file defines the structures and definitions for the GRU ASIC. + +Author: + + Steve Brooks 7-July-1994 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#ifndef _GRUH_ +#define _GRUH_ + +// +// Define locations of the GRU ASIC registers +// + +#define GRU_CSRS_PHYSICAL ((ULONGLONG)0x8780000000) +#define GRU_CSRS_QVA HAL_MAKE_QVA(GRU_CSRS_PHYSICAL) + +#define GRU_CACHECNFG_CSRS_PHYSICAL ((ULONGLONG)0x8780000200) +#define GRU_CACHECNFG_CSRS_QVA HAL_MAKE_QVA(GRU_CSRS_PHYSICAL) + +// +// Define various masks for the GRU registers +// + +#define GRU_ENABLE_EISA_INT 0x80000000 +#define GRU_SET_LEVEL_INT 0x00000000 +#define GRU_SET_LOW_INT 0x8F000000 +#define GRU_PCI_MASK_INT 0x000FFFFF +#define GRU_EISA_MASK_INT 0x80000000 + +// +// Define GRU Interrupt register access structure: +// + +typedef struct _GRU_INTERRUPT_CSRS{ + UCHAR IntReq; // (00) Interrupt Request Register + UCHAR Filler1; // (20) + UCHAR IntMask; // (40) Interrupt Mask Register + UCHAR Filler2; // (60) + UCHAR IntEdge; // (80) Edge/Level Interrupt Select + UCHAR Filler3; // (a0) + UCHAR IntHiLo; // (c0) Active High/Low select register + UCHAR Filler4; // (e0) + UCHAR IntClear; // (100) Interrupt Clear register +} GRU_INTERRUPT_CSRS, *PGRU_INTERRUPT_CSRS; + +// +// Define GRU cache register structure. +// + +typedef union _GRU_CACHECNFG{ + struct{ + ULONG Reserved0 : 4; // + ULONG ClockDivisor: 4; // Clock divisor for EV5. + ULONG Reserved1 : 3; // + ULONG CacheSpeed : 2; // SRAM cache access time. + ULONG CacheSize : 3; // SRAM cache size. + ULONG Mmb0Config : 4; // Presence and type of MMB0. + ULONG Reserved2 : 4; // + ULONG Mmb1Config : 4; // Presence and type of MMB1. + ULONG Reserved3 : 4; // + }; + ULONG all; +} GRU_CACHECNFG, *PGRU_CACHECNFG; + +#endif // _GRUH_ diff --git a/private/ntos/nthals/halalpha/haldebug.c b/private/ntos/nthals/halalpha/haldebug.c new file mode 100644 index 000000000..543354e72 --- /dev/null +++ b/private/ntos/nthals/halalpha/haldebug.c @@ -0,0 +1,58 @@ +#if HALDBG + +/*++ + +Copyright (c) 1993-1994 Digital Equipment Corporation + +Module Name: + + haldebug.c + +Abstract: + + This module contains debugging code for the HAL. + +Author: + + Steve Jenness 09-Nov-1993 + Joe Notarangelo 28-Jan-1994 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" + + +#include +#include + +ULONG HalDebugMask = 0; +UCHAR HalDebugBuffer[512]; + +VOID +HalDebugPrint( + ULONG DebugPrintMask, + PCCHAR DebugMessage, + ... + ) +{ + va_list ap; + va_start(ap, DebugMessage); + + if( (DebugPrintMask & HalDebugMask) != 0 ) + { + vsprintf(HalDebugBuffer, DebugMessage, ap); + DbgPrint(HalDebugBuffer); + } + + va_end(ap); +} + +#endif // HALDBG + diff --git a/private/ntos/nthals/halalpha/haldump.c b/private/ntos/nthals/halalpha/haldump.c new file mode 100644 index 000000000..2b95e24d8 --- /dev/null +++ b/private/ntos/nthals/halalpha/haldump.c @@ -0,0 +1,83 @@ +#ifdef HAL_DBG + +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + haldump.c + +Abstract: + + This module is used to dump blocks of data during debugging and unit + testing. + +Author: + + Steve Jenness 93.12.17 + + +Revision History: + +--*/ + +#include "halp.h" + +VOID +HalpDumpBlock ( + IN PUCHAR Buffer, + IN LONG BufferLength + ) + +/*++ + +Routine Description: + + This routine dumps a block of data to the debugger. + +Arguments: + + Buffer - Pointer to data to be dumped. + BufferLength - Number of bytes to be dumped. + +Return Value: + + None. + +--*/ + +{ + ULONG Offset = 0; + ULONG ByteCount = 0; + UCHAR CharBuffer[17]; + PUCHAR CharPtr; + + CharBuffer[16] = 0; + while (BufferLength > 0) { + DbgPrint(" %08x: ", Offset); + CharPtr = &CharBuffer[0]; + + DbgPrint(" %02x %02x %02x %02x %02x %02x %02x %02x", + Buffer[0], Buffer[1], Buffer[2], Buffer[3], + Buffer[4], Buffer[5], Buffer[6], Buffer[7]); + DbgPrint(" %02x %02x %02x %02x %02x %02x %02x %02x", + Buffer[8], Buffer[9], Buffer[10], Buffer[11], + Buffer[11], Buffer[13], Buffer[14], Buffer[15]); + do { + if ((*Buffer >= 0x20) && (*Buffer <= 0x7e)) { + *CharPtr++ = *Buffer++; + } else { + *CharPtr++ = '.'; + Buffer++; + } + Offset++; + } while ((Offset & 0xf) != 0); + + DbgPrint(" %s\n", &CharBuffer[0]); + Offset += 16; + BufferLength -= 16; + } +} + +#endif //HAL_DBG diff --git a/private/ntos/nthals/halalpha/halisa.h b/private/ntos/nthals/halalpha/halisa.h new file mode 100644 index 000000000..2ebe313ae --- /dev/null +++ b/private/ntos/nthals/halalpha/halisa.h @@ -0,0 +1,89 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) 1991 Microsoft Corporation +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + halisa.h + +Abstract: + + This header file defines the private Hardware Architecture Layer (HAL) + EISA/ISA specific interfaces, defines and structures. + +Author: + + Jeff Havens (jhavens) 20-Jun-91 + Jeff McLeman (mcleman) 01-Jun-1992 + +Revision History: + + 17-Jul-1992 Jeff McLeman (mcleman) + Remove adapter object structure from here. + + 01-Jun-1992 Jeff McLeman + modify for Jensen EISA/ISA + +--*/ + +#ifndef _HALISA_ +#define _HALISA_ + + +// +// The MAXIMUM_MAP_BUFFER_SIZE defines the maximum map buffers which the system +// will allocate for devices which require phyically contigous buffers. +// + +#define MAXIMUM_MAP_BUFFER_SIZE 0x40000 + +// +// Define the initial buffer allocation size for a map buffers for systems with +// no memory which has a physical address greater than MAXIMUM_PHYSICAL_ADDRESS. +// + +#define INITIAL_MAP_BUFFER_SMALL_SIZE 0x10000 + +// +// Define the initial buffer allocation size for a map buffers for systems with +// no memory which has a physical address greater than MAXIMUM_PHYSICAL_ADDRESS. +// + +#define INITIAL_MAP_BUFFER_LARGE_SIZE 0x30000 + +// +// Define the incremental buffer allocation for a map buffers. +// + +#define INCREMENT_MAP_BUFFER_SIZE 0x10000 + +// +// Define the maximum number of map registers that can be requested at one time +// if actual map registers are required for the transfer. +// + +#define __64K (0x10000) +#define MAXIMUM_ISA_MAP_REGISTER (__64K >> PAGE_SHIFT) + +// +// Define the maximum physical address which can be handled by an Isa card. +// + +#define __16MB (0x1000000) +#define MAXIMUM_ISA_PHYSICAL_ADDRESS (__16MB) + +// +// Define the scatter/gather flag for the Map Register Base. +// + +#define NO_SCATTER_GATHER 0x00000001 + +// +// Define the copy buffer flag for the index. +// + +#define COPY_BUFFER 0XFFFFFFFF + + +#endif // _HALISA_ diff --git a/private/ntos/nthals/halalpha/halp.h b/private/ntos/nthals/halalpha/halp.h new file mode 100644 index 000000000..c36428a82 --- /dev/null +++ b/private/ntos/nthals/halalpha/halp.h @@ -0,0 +1,1095 @@ +/*++ BUILD Version: 0003 // Increment this if a change has global effects + +Copyright (c) 1991 Microsoft Corporation +Copyright (c) 1992,1993 Digital Equipment Corporation + +Module Name: + + halp.h + +Abstract: + + This header file defines the private Hardware Architecture Layer (HAL) + interfaces. + +Author: + + David N. Cutler (davec) 25-Apr-1991 + Miche Baker-Harvey (miche) 22-Apr-1992 + + +Revision History: + + 09-Jul-1992 Jeff McLeman (mcleman) + If processor is an Alpha, include XXHALP.C for Alpha. + + 24-Sep-1993 Joe Notarangelo + Incorporate definitions from xxhalp.h and jxhalp.h. + Restructure so that related modules are together. + + 5-Jan-1994 Eric Rehm + Incorport support for PCI and IoAssignResources. + +--*/ + +#ifndef _HALP_ +#define _HALP_ + +#include "nthal.h" +#include "hal.h" +#include "pci.h" +#include "errframe.h" + + +// +// Declare HAL spinlocks. +// + +extern KSPIN_LOCK HalpBeepLock; +extern KSPIN_LOCK HalpDisplayAdapterLock; +extern KSPIN_LOCK HalpSystemInterruptLock; + +// +// Define external references. +// + +extern ULONG HalpClockFrequency; +extern ULONG HalpClockMegaHertz; + +extern ULONG HalpProfileCountRate; + +extern PADAPTER_OBJECT MasterAdapterObject; + +extern BOOLEAN LessThan16Mb; + +extern KAFFINITY HalpActiveProcessors; + +// +// Map buffer prameters. These are initialized in HalInitSystem +// + +extern PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress; +extern ULONG HalpMapBufferSize; + +extern ULONG HalpBusType; + +// +// Define global data used to relate PCI devices to their interrupt +// vector. +// + +extern ULONG *HalpPCIPinToLineTable; + +// +// Define global data used to locate the EISA control space and the realtime +// clock registers. +// + +extern PVOID HalpEisaControlBase; +extern PVOID HalpEisaIntAckBase; +extern PVOID HalpCMOSRamBase; +extern PVOID HalpRtcAddressPort; +extern PVOID HalpRtcDataPort; + +extern POBJECT_TYPE *IoAdapterObjectType; + +// +// Determine if a virtual address is really a physical address. +// + +#define HALP_IS_PHYSICAL_ADDRESS(Va) \ + ((((ULONG)Va >= KSEG0_BASE) && ((ULONG)Va < KSEG2_BASE)) ? TRUE : FALSE) + +// +// Define the different address spaces. +// + +typedef enum _ADDRESS_SPACE_TYPE{ + BusMemory=0, + BusIo = 1, + UserBusMemory = 2, + UserBusIo = 3, + KernelPciDenseMemory = 4, + UserPciDenseMemory = 6, +} ADDRESS_SPACE_TYPE, *PADDRESS_SPACE_TYPE; + +// +// Prototype for Memory Size determination routine +// +ULONGLONG +HalpGetMemorySize( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +ULONGLONG +HalpGetContiguousMemorySize( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +// +// Prototype for BCache Size determination routine +// +ULONG +HalpGetBCacheSize( + ULONGLONG ContiguousMemorySize + ); + +// +// Define initialization routine prototypes. +// + +BOOLEAN +HalpCreateDmaStructures ( + PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +VOID +HalpEstablishErrorHandler( + VOID + ); + +VOID +HalpInitializeClockInterrupts( + VOID + ); + +VOID +HalpInitializeProfiler( + VOID + ); + +BOOLEAN +HalpInitializeDisplay ( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +BOOLEAN +HalpInitializeInterrupts ( + VOID + ); + +VOID +HalpInitializeMachineDependent( + IN ULONG Phase, + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +BOOLEAN +HalpMapIoSpace ( + VOID + ); + +ULONG +HalpMapDebugPort ( + IN ULONG ComPort, + OUT PULONG ReadQva, + OUT PULONG WriteQva + ); + +VOID +HalpSetTimeIncrement( + VOID + ); + +VOID +HalpParseLoaderBlock( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +VOID +HalpInitializeProcessorParameters( + VOID + ); + +// +// Error Frame Initialization and Support Routines +// +VOID +HalpAllocateUncorrectableFrame( + VOID + ); + +VOID +HalpGetMachineDependentErrorFrameSizes( + PULONG RawProcessorSize, + PULONG RawSystemInfoSize + ); + +VOID +HalpInitializeUncorrectableErrorFrame ( + VOID + ); + +VOID +HalpGetProcessorInfo( + PPROCESSOR_INFO pProcessorInfo + ); + +VOID +HalpGetSystemInfo( + SYSTEM_INFORMATION *SystemInfo + ); + +// +// Define profiler function prototypes. +// + +NTSTATUS +HalpProfileSourceInformation ( + OUT PVOID Buffer, + IN ULONG BufferLength, + OUT PULONG ReturnedLength + ); + +NTSTATUS +HalpProfileSourceInterval ( + OUT PVOID Buffer, + IN ULONG BufferLength + ); + + +// +// Define interrupt function prototypes. +// + +VOID +HalpProgramIntervalTimer( + IN ULONG RateSelect + ); + +VOID +HalpClockInterrupt ( + VOID + ); + +VOID +HalpSecondaryClockInterrupt ( + VOID + ); + +VOID +HalpIpiInterruptHandler ( + VOID + ); + +BOOLEAN +HalpDmaDispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + +VOID +HalpPerformanceCounter0Interrupt ( + VOID + ); + +VOID +HalpPerformanceCounter1Interrupt ( + VOID + ); + +VOID +HalpPerformanceCounter2Interrupt ( + VOID + ); + +VOID +HalpStallInterrupt ( + VOID + ); + +VOID +HalpVideoReboot( + VOID + ); + +// +// Define microprocessor-specific function prototypes and structures. +// + +// +// 21064 (EV4) processor family. +// + +typedef enum _EV4Irq{ + Irq0 = 0, + Irq1 = 1, + Irq2 = 2, + Irq3 = 3, + Irq4 = 4, + Irq5 = 5, + MaximumIrq +} EV4Irq, *PEV4Irq; + +typedef struct _EV4IrqStatus{ + ULONG Vector; + BOOLEAN Enabled; + KIRQL Irql; + UCHAR Priority; +} EV4IrqStatus, *PEV4IrqStatus; + +typedef struct _EV4ProfileCount { + ULONG ProfileCount[2]; + ULONG ProfileCountReload[2]; +} EV4ProfileCount, *PEV4ProfileCount; + +VOID +HalpInitialize21064Interrupts( + VOID + ); + +VOID +HalpDisable21064HardwareInterrupt( + IN ULONG Irq + ); + +VOID +HalpDisable21064SoftwareInterrupt( + IN KIRQL Irql + ); + +VOID +HalpDisable21064PerformanceInterrupt( + IN ULONG Vector + ); + +VOID +HalpEnable21064HardwareInterrupt( + IN ULONG Irq, + IN KIRQL Irql, + IN ULONG Vector, + IN UCHAR Priority + ); + +VOID +HalpEnable21064SoftwareInterrupt( + IN KIRQL Irql + ); + +VOID +HalpInitialize21064Interrupts( + VOID + ); + +VOID +HalpEnable21064PerformanceInterrupt( + IN ULONG Vector, + IN KIRQL Irql + ); + +ULONG +HalpGet21064PerformanceVector( + IN ULONG BusInterruptLevel, + OUT PKIRQL Irql + ); + +ULONG +HalpGet21064CorrectableVector( + IN ULONG BusInterruptLevel, + OUT PKIRQL Irql + ); + +// +// 21164 processor family. +// + +#ifdef EV5 + +typedef struct _EV5ProfileCount { + ULONG ProfileCount[3]; + ULONG ProfileCountReload[3]; +} EV5ProfileCount, *PEV5ProfileCount; + +VOID +HalpInitialize21164Interrupts( + VOID + ); + +VOID +HalpStart21164Interrupts( + VOID + ); + +ULONG +HalpGet21164PerformanceVector( + IN ULONG BusInterruptLevel, + OUT PKIRQL Irql + ); + +ULONGLONG +HalpRead21164PerformanceCounter( + VOID + ); + +VOID +HalpWrite21164PerformanceCounter( + ULONGLONG PmCtr, + ULONG CBOXMux1, + ULONG CBOXMux2 + ); + +ULONG +HalpGet21164CorrectableVector( + IN ULONG BusInterruptLevel, + OUT PKIRQL Irql + ); + +#endif // EV5 specific definitions + +// +// Define the context structure for use by interrupt service routines. +// + +typedef BOOLEAN (*PSECONDARY_DISPATCH)( + PVOID InterruptRoutine, + PKTRAP_FRAME TrapFrame + ); + +// +// Define memory utility function prototypes. +// + +ULONG +HalpAllocPhysicalMemory( + IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN ULONG MaxPhysicalAddress, + IN ULONG NumberOfPages, + IN BOOLEAN bAlignOn64k + ); + +PVOID +HalpMapPhysicalMemory( + IN PVOID PhysicalAddress, + IN ULONG NumberOfPages + ); + +PVOID +HalpRemapVirtualAddress( + IN PVOID VirtualAddress, + IN PVOID PhysicalAddress + ); + +#if HALDBG + +VOID +HalpDumpMemoryDescriptors( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +#endif + +// +// Low-level routine interfaces. +// + +VOID +HalpReboot( + VOID + ); + +VOID +HalpImb( + VOID + ); + +VOID +HalpMb( + VOID + ); + +ULONG +HalpRpcc( + VOID + ); + +MCES +HalpReadMces( + VOID + ); + +MCES +HalpWriteMces( + IN MCES Mces + ); + +VOID +HalpWritePerformanceCounter( + IN ULONG PerformanceCounter, + IN BOOLEAN Enable, + IN ULONG MuxControl OPTIONAL, + IN ULONG EventCount OPTIONAL + ); + +// +// Define synonym for KeStallExecutionProcessor. +// + +#define HalpStallExecution KeStallExecutionProcessor + +// +// Define Bus Handler support function prototypes. +// + + +VOID +HalpRegisterInternalBusHandlers ( + VOID + ); + +ULONG +HalpGetSystemInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); + +BOOLEAN +HalpTranslateSystemBusAddress( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress + ); + + +VOID +HalpAdjustResourceListUpperLimits ( + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList, + IN LARGE_INTEGER MaximumPortAddress, + IN LARGE_INTEGER MaximumMemoryAddress, + IN ULONG MaximumInterruptVector, + IN ULONG MaximumDmaChannel + ); + +// +// Define SIO support function prototypes. +// + +VOID +HalpInitializeSioInterrupts( + VOID + ); + +VOID +HalpEnableSioInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ); + +VOID +HalpDisableSioInterrupt( + IN ULONG Vector + ); + +BOOLEAN +HalpSioDispatch( + VOID + ); + +// +// Define EISA support function prototypes. +// + +BOOLEAN +HalpInitializeEisaInterrupts( + VOID + ); + +VOID +HalpEnableEisaInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ); + +VOID +HalpDisableEisaInterrupt( + IN ULONG Vector + ); + +BOOLEAN +HalpEisaDispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PKTRAP_FRAME TrapFrame + ); + +BOOLEAN +HalpEisaInterruptHandler( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + +VOID +HalpEisaInitializeDma( + VOID + ); + +PADAPTER_OBJECT +HalpAllocateAdapter( + VOID + ); + +PADAPTER_OBJECT +HalpAllocateEisaAdapter( + IN PDEVICE_DESCRIPTION DeviceDescription, + OUT PULONG NumberOfMapRegisters + ); + +BOOLEAN +HalpMapEisaTransfer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG LogicalAddress, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ); + +BOOLEAN +HalpFlushEisaAdapter( + IN PADAPTER_OBJECT AdapterObject, + IN PMDL Mdl, + IN PVOID MapRegisterBase, + IN PVOID CurrentVa, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ); + +ULONG +HalpReadEisaDmaCounter( + IN PADAPTER_OBJECT AdapterObject + ); + + +ULONG +HalpGetEisaData( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +NTSTATUS +HalpAdjustEisaResourceList ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ); + +NTSTATUS +HalpAdjustIsaResourceList ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ); + +// +// Define PCI support function prototypes. +// + +VOID +HalpInitializePCIBus ( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +PBUS_HANDLER +HalpAllocateAndInitPCIBusHandler ( + IN ULONG BusNo, + IN ULONG HwBusNo, + IN BOOLEAN BusIsAcrossPPB, + IN ULONG PPBBusNumber, + IN PCI_SLOT_NUMBER PPBSlotNumber + ); + +VOID +HalpRegisterPCIInstallHandler( + IN PINSTALL_BUS_HANDLER MachineSpecificPCIInstallHandler +); + +NTSTATUS +HalpDefaultPCIInstallHandler( + IN PBUS_HANDLER Bus + ); + +VOID +HalpDeterminePCIDevicesPresent( + IN PBUS_HANDLER Bus +); + +BOOLEAN +HalpInitializePCIInterrupts( + VOID + ); + +VOID +HalpEnablePCIInterrupt( + IN ULONG Vector + ); + +VOID +HalpDisablePCIInterrupt( + IN ULONG Vector + ); + +BOOLEAN +HalpPCIInterruptHandler( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + + +// +// Environment variable support +// + +ARC_STATUS +HalpReadNVRamBuffer( + OUT PCHAR DataPtr, + IN PCHAR NvRamPtr, + IN ULONG Length + ); + +ARC_STATUS +HalpWriteNVRamBuffer( + IN PCHAR NvRamPtr, + IN PCHAR DataPtr, + IN ULONG Length + ); + +ARC_STATUS +HalpCopyNVRamBuffer( + IN PCHAR NvDestPtr, + IN PCHAR NvSrcPtr, + IN ULONG Length + ); + +#if defined(TAGGED_NVRAM) + +// +// NVRAM API +// + +UCHAR +HalpGetNVRamUchar( + IN ULONG Offset + ); + +VOID +HalpSetNVRamUchar( + IN ULONG Offset, + IN UCHAR Data + ); + +USHORT +HalpGetNVRamUshort( + IN ULONG Offset + ); + +VOID +HalpSetNVRamUshort( + IN ULONG Offset, + IN USHORT Data + ); + +ULONG +HalpGetNVRamUlong( + IN ULONG Offset + ); + +VOID +HalpSetNVRamUlong( + IN ULONG Offset, + IN ULONG Data + ); + +VOID +HalpMoveMemoryToNVRam( + IN ULONG Offset, + IN PVOID Data, + IN ULONG Length + ); + +VOID +HalpMoveNVRamToMemory( + IN PVOID Data, + IN ULONG Offset, + IN ULONG Length + ); + +VOID +HalpMoveNVRamToNVRam( + IN ULONG Destination, + IN ULONG Source, + IN ULONG Length + ); + +ULONG +HalpGetNVRamStringLength( + IN ULONG Offset + ); + +VOID +HalpMoveMemoryStringToNVRam( + IN ULONG Offset, + IN PCHAR Data + ); + +VOID +HalpMoveNVRamStringToMemory( + IN PUCHAR Data, + IN ULONG Offset + ); + +VOID +HalpZeroNVRam( + IN ULONG Offset, + IN ULONG Length + ); + +ULONG +HalpComputeNVRamChecksum( + IN ULONG Offset, + IN ULONG Length + ); + +BOOLEAN +HalpIsNVRamRegion0Valid( + VOID + ); + +BOOLEAN +HalpSynchronizeNVRamRegion0( + IN BOOLEAN RecomputeChecksum + ); + +BOOLEAN +HalpInitializeNVRamRegion0( + IN BOOLEAN Synchronize + ); + +ULONG +HalpGetNVRamFwConfigOffset( + VOID + ); + +ULONG +HalpGetNVRamFwConfigLength( + VOID + ); + +ULONG +HalpGetNVRamLanguageOffset( + VOID + ); + +ULONG +HalpGetNVRamLanguageLength( + VOID + ); + +ULONG +HalpGetNVRamEnvironmentOffset( + VOID + ); + +ULONG +HalpGetNVRamEnvironmentLength( + VOID + ); + +#if defined(EISA_PLATFORM) + +BOOLEAN +HalpIsNVRamRegion1Valid( + VOID + ); + +BOOLEAN +HalpSynchronizeNVRamRegion1( + IN BOOLEAN RecomputeChecksum + ); + +BOOLEAN +HalpInitializeNVRamRegion1( + IN BOOLEAN Synchronize + ); + +#endif // EISA_PLATFORM + +#endif // TAGGED_NVRAM + +// +// Error handling function prototype. +// + +typedef +BOOLEAN +KBUS_ERROR_ROUTINE( + IN struct _EXCEPTION_RECORD *ExceptionRecord, + IN struct _KEXCEPTION_FRAME *ExceptionFrame, + IN struct _KTRAP_FRAME *TrapFrame + ); + +KBUS_ERROR_ROUTINE HalMachineCheck; + +VOID +HalpInitializeMachineChecks( + IN BOOLEAN ReportCorrectableErrors + ); + +// +// Low-level I/O function prototypes. +// + +VOID +HalpAcknowledgeClockInterrupt( + VOID + ); + +UCHAR +HalpAcknowledgeEisaInterrupt( + IN PVOID ServiceContext + ); + +UCHAR +HalpReadClockRegister( + IN UCHAR Register + ); + +VOID +HalpWriteClockRegister( + IN UCHAR Register, + IN UCHAR Value + ); + +UCHAR +READ_CONFIG_UCHAR( + IN PVOID ConfigurationAddress, + IN ULONG ConfigurationType + ); + +USHORT +READ_CONFIG_USHORT( + IN PVOID ConfigurationAddress, + IN ULONG ConfigurationType + ); + +ULONG +READ_CONFIG_ULONG( + IN PVOID ConfigurationAddress, + IN ULONG ConfigurationType + ); + +VOID +WRITE_CONFIG_UCHAR( + IN PVOID ConfigurationAddress, + IN UCHAR ConfigurationData, + IN ULONG ConfigurationType + ); + +VOID +WRITE_CONFIG_USHORT( + IN PVOID ConfigurationAddress, + IN USHORT ConfigurationData, + IN ULONG ConfigurationType + ); + +VOID +WRITE_CONFIG_ULONG( + IN PVOID ConfigurationAddress, + IN ULONG ConfigurationData, + IN ULONG ConfigurationType + ); + +// +// Define the I/O superpage enable VA base. +// + +#define SUPERPAGE_ENABLE ((ULONGLONG)0xfffffc0000000000) + +// +// Numeric constants used in the HAL. +// + +#define __1K (0x400) +#define __2K (0x800) +#define __4K (0x1000) +#define __8K (0x2000) +#define __16K (0x4000) +#define __32K (0x8000) +#define __64K (0x10000) +#define __128K (0x20000) +#define __256K (0x40000) +#define __512K (0x80000) +#define __1MB (0x100000) +#define __2MB (0x200000) +#define __4MB (0x400000) +#define __8MB (0x800000) +#define __16MB (0x1000000) +#define __32MB (0x2000000) +#define __64MB (0x4000000) +#define __128MB (0x8000000) +#define __256MB (0x10000000) +#define __512MB (0x20000000) +#define __1GB (0x40000000) +#define __2GB (0x80000000) + +// +// CPU mask values. Used to interpret cpu bitmap values. +// +#define HAL_CPU0_MASK ((ULONG)0x1) +#define HAL_CPU1_MASK ((ULONG)0x2) +#define HAL_CPU2_MASK ((ULONG)0x4) +#define HAL_CPU3_MASK ((ULONG)0x8) + +// +// HAL Debugging Support. +// + +#if HALDBG + +#define DebugPrint(x) HalDebugPrint x + +VOID +HalDebugPrint( + ULONG DebugPrintLevel, + PCCHAR DebugMessage, + ... + ); + +#else //HALDBG + +#define DebugPrint(x) + +#endif //HALDBG + +// +// Define HAL debugging masks. +// + +// +// Trace IoMapTransfer, IoFlushAdapterBuffers +// + +#define HALDBG_IOMT (0x1) + +// +// Trace Map Register allocations and frees +// + +#define HALDBG_MAPREG (0x2) + +// +// Include machine-dependent definitions. +// +// N.B. - Each platform that includes this file must have a machdep.h +// include file in its private directory. +// + +#include + +#endif // _HALP_ diff --git a/private/ntos/nthals/halalpha/halpal.s b/private/ntos/nthals/halalpha/halpal.s new file mode 100644 index 000000000..d34a29084 --- /dev/null +++ b/private/ntos/nthals/halalpha/halpal.s @@ -0,0 +1,276 @@ +// TITLE("Alpha PAL funtions for HAL") +//++ +// +// Copyright (c) 1992 Digital Equipment Corporation +// Copyright (c) 1993 Digital Equipment Corporation +// +// Module Name: +// +// halpal.s +// +// Abstract: +// +// This module implements routines to call PAL functions +// from the Hal. +// +// +// Author: +// +// Jeff McLeman (mcleman) 09-Jul-1992 +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +// 13-Jul-1992 Jeff McLeman (mcleman) +// add HalpMb to functions. +// +// 14-Dec-1993 Joe Notarangelo +// use new encoding to return to firmware: HalpReboot instead of +// HalpHalt +//-- + +#include "halalpha.h" + +//++ +// +// VOID +// HalpReboot( +// ) +// +// Routine Description: +// +// This function merely calls the PAL to reboot the Alpha processor. +// This is used to restart the console firmware. (Note, MIPS does +// not have a HALT instruction, so there had to be a mechanism to +// restart the firware. Alpha merely reboots, which causes a jump +// to firmware PAL, which restarts the firmware.) +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpReboot) + + REBOOT // call the PAL to reboot + + .end HalpReboot + +//++ +// +// VOID +// HalpSwppal( +// ) +// +// Routine Description: +// +// This function merely calls the PAL to issue a SWPPAL +// on the Alpha processor... +// +// Arguments: +// +// a0 The physical address to do the Swappal to. +// a1 -- a5 Any other arguments to the PALcode. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSwppal) + + SWPPAL // call the PAL to do a swap_pal + + ret zero,(ra) + + .end HalpSwppal + + +//++ +// +// VOID +// HalpImb( +// ) +// +// Routine Description: +// +// This function merely calls the PAL to issue an Instruction +// Memory Barrier on the Alpha processor.. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpImb) + + IMB // call the PAL to do an IMB + + ret zero,(ra) + + .end HalpImb + + +//++ +// +// VOID +// HalpMb( +// ) +// +// Routine Description: +// +// This function merely calls the PAL to issue a general +// Memory Barrier on the Alpha processor.. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpMb) + + mb // memory barrier + + ret zero, (ra) + + .end HalpMb + +//++ +// +// VOID +// HalpCachePcrValues( +// ) +// +// Routine Description: +// +// This function merely calls the PAL to cache values in the +// PCR for faster access. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpCachePcrValues) + + CACHE_PCR_VALUES // call the palcode + + ret zero,(ra) + + .end HalpCachePcrValues +//++ +// +// ULONG +// HalpRpcc( +// ) +// +// Routine Description: +// +// This function executes the RPCC (read processor cycle counter) +// instruction. +// +// Arguments: +// +// None. +// +// Return Value: +// +// The low-order 32 bits of the processor cycle counter is returned +// as the function value. +// N.B. At 125 MHz this counter wraps about every 30 seconds. It is +// the caller's responsibility to deal with overflow or wraparound. +// +//-- + + LEAF_ENTRY(HalpRpcc) + + rpcc v0 // get rpcc value + addl v0, zero, v0 // extend + + ret zero, (ra) // return + + .end HalpRpcc + + +//++ +// +// MCES +// HalpReadMces( +// VOID +// ) +// +// Routine Description: +// +// Read the state of the MCES (Machine Check Error Summary) +// internal processor register. +// +// Arguments: +// +// None. +// +// Return Value: +// +// v0 - Current MCES value. +//-- + + LEAF_ENTRY(HalpReadMces) + + GET_MACHINE_CHECK_ERROR_SUMMARY // v0 = current value + + ret zero, (ra) // return + + .end HalpReadMces + + +//++ +// +// MCES +// HalpWriteMces( +// IN MCES Mces +// ) +// +// Routine Description: +// +// Update the current value of the MCES internal processor register. +// +// Arguments: +// +// Mces(a0) - Supplies the new value for the MCES register. +// +// Return Value: +// +// v0 - Previous MCES value. +// +//-- + + LEAF_ENTRY(HalpWriteMces) + + WRITE_MACHINE_CHECK_ERROR_SUMMARY // v0 = previous value + + ret zero, (ra) // return + + .end HalpWriteMces diff --git a/private/ntos/nthals/halalpha/halpcsl.h b/private/ntos/nthals/halalpha/halpcsl.h new file mode 100644 index 000000000..21b7d49df --- /dev/null +++ b/private/ntos/nthals/halalpha/halpcsl.h @@ -0,0 +1,187 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) 1991 Microsoft Corporation +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + halpcsl.h + +Abstract: + + This header file includes the definitions for standard PC serial + port UARTs. + + Stolen from jazzserp.h, which is a slightly different chip- + it has a 16 byte fifo - we are just double buffered. + +Author: + + David N. Cutler (davec) 28-Apr-1991 + Miche Baker-Harvey (miche) 01-June-1992 + + +Revision History: + +--*/ + +#ifndef _HALPCSL_ +#define _HALPCSL_ + + +// +// Define base port numbers for serial lines inside the combo chip +// + +#define COMA_PORT_BASE 0x3f8 +#define COMB_PORT_BASE 0x2f8 + + +// +// Define serial port read registers structure. +// + +typedef struct _SP_READ_REGISTERS { + UCHAR ReceiveBuffer; + UCHAR InterruptEnable; + UCHAR InterruptId; + UCHAR LineControl; + UCHAR ModemControl; + UCHAR LineStatus; + UCHAR ModemStatus; + UCHAR ScratchPad; +} SP_READ_REGISTERS, *PSP_READ_REGISTERS; + +// +// Define define serial port write registers structure. +// + +typedef struct _SP_WRITE_REGISTERS { + UCHAR TransmitBuffer; + UCHAR InterruptEnable; + UCHAR FifoControl; + UCHAR LineControl; + UCHAR ModemControl; + UCHAR Reserved1; + UCHAR ModemStatus; + UCHAR ScratchPad; +} SP_WRITE_REGISTERS, *PSP_WRITE_REGISTERS; + +// +// Define serial port interrupt enable register structure. +// + +typedef struct _SP_INTERRUPT_ENABLE { + UCHAR ReceiveEnable : 1; + UCHAR TransmitEnable : 1; + UCHAR LineStatusEnable : 1; + UCHAR ModemStatusEnable : 1; + UCHAR Reserved1 : 4; +} SP_INTERRUPT_ENABLE, *PSP_INTERRUPT_ENABLE; + +// +// Define serial port interrupt id register structure. +// + +typedef struct _SP_INTERRUPT_ID { + UCHAR InterruptPending : 1; + UCHAR Identification : 3; + UCHAR Reserved1 : 2; + UCHAR FifoEnabled : 2; // always read as 0 +} SP_INTERRUPT_ID, *PSP_INTERRUPT_ID; + +// +// Define serial port fifo control register structure. +// This register is here for software compatibility, but there is +// no FIFO on the 16C452 +// + +typedef struct _SP_FIFO_CONTROL { + UCHAR FifoEnable : 1; + UCHAR ReceiveFifoReset : 1; + UCHAR TransmitFifoReset : 1; + UCHAR DmaModeSelect : 1; + UCHAR Reserved1 : 2; + UCHAR ReceiveFifoLevel : 2; +} SP_FIFO_CONTROL, *PSP_FIFO_CONTROL; + +// +// Define serial port line control register structure. +// + +typedef struct _SP_LINE_CONTROL { + UCHAR CharacterSize : 2; + UCHAR StopBits : 1; + UCHAR ParityEnable : 1; + UCHAR EvenParity : 1; + UCHAR StickParity : 1; + UCHAR SetBreak : 1; + UCHAR DivisorLatch : 1; +} SP_LINE_CONTROL, *PSP_LINE_CONTROL; + +// +// Line status register character size definitions. +// + +#define FIVE_BITS 0x0 // five bits per character +#define SIX_BITS 0x1 // six bits per character +#define SEVEN_BITS 0x2 // seven bits per character +#define EIGHT_BITS 0x3 // eight bits per character + +// +// Line speed divisor definition. We get our baud rate clock +// from the 82C106. +// + +#define BAUD_RATE_2400 48 // divisor for 2400 baud +#define BAUD_RATE_4800 24 // divisor for 4800 baud +#define BAUD_RATE_9600 12 // divisor for 9600 baud +#define BAUD_RATE_19200 6 // divisor for 19200 baud +#define BAUD_RATE_38400 3 // divisor for 38400 baud +#define BAUD_RATE_57600 2 // divisor for 57600 baud +#define BAUD_RATE_115200 1 // divisor for 115200 baud + +// +// Define serial port modem control register structure. +// + +typedef struct _SP_MODEM_CONTROL { + UCHAR DataTerminalReady : 1; + UCHAR RequestToSend : 1; + UCHAR Reserved1 : 1; + UCHAR Interrupt : 1; + UCHAR loopBack : 1; + UCHAR Reserved2 : 3; +} SP_MODEM_CONTROL, *PSP_MODEM_CONTROL; + +// +// Define serial port line status register structure. +// + +typedef struct _SP_LINE_STATUS { + UCHAR DataReady : 1; + UCHAR OverrunError : 1; + UCHAR ParityError : 1; + UCHAR FramingError : 1; + UCHAR BreakIndicator : 1; + UCHAR TransmitHoldingEmpty : 1; + UCHAR TransmitEmpty : 1; + UCHAR ReceiveFifoError : 1; +} SP_LINE_STATUS, *PSP_LINE_STATUS; + +// +// Define serial port modem status register structure. +// + +typedef struct _SP_MODEM_STATUS { + UCHAR DeltaClearToSend : 1; + UCHAR DeltaDataSetReady : 1; + UCHAR TrailingRingIndicator : 1; + UCHAR DeltaReceiveDetect : 1; + UCHAR ClearToSend : 1; + UCHAR DataSetReady : 1; + UCHAR RingIndicator : 1; + UCHAR ReceiveDetect : 1; +} SP_MODEM_STATUS, *PSP_MODEM_STATUS; + +#endif // _HALPCSL_ diff --git a/private/ntos/nthals/halalpha/halprof.c b/private/ntos/nthals/halalpha/halprof.c new file mode 100644 index 000000000..62235fc7c --- /dev/null +++ b/private/ntos/nthals/halalpha/halprof.c @@ -0,0 +1,179 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + halprof.c + +Abstract: + + This module implements the high level Profile Counter interface. + + N.B. - This module assumes that all processors in a multiprocessor + system are running the microprocessor at the same clock speed. + +Author: + + Steve Brooks 14-Feb-1995 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" + + +NTSTATUS +HalpProfileSourceInformation ( + OUT PVOID Buffer, + IN ULONG BufferLength, + OUT PULONG ReturnedLength + ) +/*++ + +Routine Description: + + Returns the HAL_PROFILE_SOURCE_INFORMATION for this processor. + +Arguments: + + Buffer - output buffer + BufferLength - length of buffer on input + ReturnedLength - The length of data returned + +Return Value: + + STATUS_SUCCESS + STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize + currently needed. + +--*/ +{ + PHAL_PROFILE_SOURCE_INFORMATION SourceInfo; + NTSTATUS Status; + + + if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INFORMATION)) { + Status = STATUS_INFO_LENGTH_MISMATCH; + return Status; + } + + SourceInfo = (PHAL_PROFILE_SOURCE_INFORMATION)Buffer; + SourceInfo->Supported = HalQueryProfileInterval(SourceInfo->Source); + + if (SourceInfo->Supported) { + SourceInfo->Interval = + HalpProfileMapping[SourceInfo->Source].EventCount * + HalpProfileMapping[SourceInfo->Source].NumberOfTicks; + } + + Status = STATUS_SUCCESS; + return Status; +} + +NTSTATUS +HalpProfileSourceInterval ( + OUT PVOID Buffer, + IN ULONG BufferLength + ) +/*++ + +Routine Description: + + Returns the HAL_PROFILE_SOURCE_INTERVAL for this processor. + +Arguments: + + Buffer - output buffer + BufferLength - length of buffer on input + +Return Value: + + STATUS_SUCCESS + STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize + currently needed. + +--*/ +{ + PHAL_PROFILE_SOURCE_INTERVAL Interval; + NTSTATUS Status; + + + if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INTERVAL)) { + Status = STATUS_INFO_LENGTH_MISMATCH; + return Status; + } + + Interval = (PHAL_PROFILE_SOURCE_INTERVAL)Buffer; + Status = HalSetProfileSourceInterval(Interval->Source, + &Interval->Interval); + return Status; +} + +BOOLEAN +HalQueryProfileInterval( + IN KPROFILE_SOURCE Source + ) + +/*++ + +Routine Description: + + Given a profile source, returns whether or not that source is + supported. + +Arguments: + + Source - Supplies the profile source + +Return Value: + + TRUE - Profile source is supported + + FALSE - Profile source is not supported + +--*/ + +{ + if (Source >= ProfileMaximum) { + return(FALSE); + } + + return(HalpProfileMapping[Source].Supported); +} + +ULONG +HalSetProfileInterval ( + IN ULONG Interval + ) + +/*++ + +Routine Description: + + This routine sets the profile interrupt interval. + +Arguments: + + Interval - Supplies the desired profile interval in 100ns units. + +Return Value: + + The actual profile interval. + +--*/ + +{ + ULONG NewInterval; + + NewInterval = Interval; + HalSetProfileSourceInterval(ProfileTime, &NewInterval); + return(NewInterval); +} + + diff --git a/private/ntos/nthals/halalpha/halprof.h b/private/ntos/nthals/halalpha/halprof.h new file mode 100644 index 000000000..bb02e1ff0 --- /dev/null +++ b/private/ntos/nthals/halalpha/halprof.h @@ -0,0 +1,77 @@ +/*++ + +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + halprof.h + +Abstract: + + This header file defines profile counter hardware in the + 82357 PIC chip. + +Author: + + Jeff McLeman (mcleman) 5-June-1992 + +Revision History: + +--*/ + +#ifndef _HALPROF_ +#define _HALPROF_ + + +// +// Define the timer values for the Profiler +// + +#define PIC_BINARY 0 +#define PIC_BCD 1 + +#define PIC_MODE0 0x00 // xxxx000x +#define PIC_MODE1 0x02 // xxxx001x +#define PIC_MODE2 0x04 // xxxx010x +#define PIC_MODE3 0x06 // xxxx011x +#define PIC_MODE4 0x08 // xxxx100x +#define PIC_MODE5 0x0A // xxxx101x + +#define PIC_CLC 0x00 // xx00xxxx +#define PIC_RWLSBO 0x10 // xx01xxxx +#define PIC_RWMSBO 0x20 // xx10xxxx +#define PIC_RWLSBMSB 0x30 // xx11xxxx + +#define PIC_SC0 0x00 // 00xxxxxx +#define PIC_SC1 0x40 // 01xxxxxx +#define PIC_SC2 0x80 // 10xxxxxx +#define PIC_RBC 0xC0 // 11xxxxxx + + +#define PIC_SCALE_FACTOR 10 * 1000 // # of microsecond units times 10. + +// +// Define a macro to set and enable the system profiler timer. +// Note that the interval 'c' is in 100nS units. +// Note that also the interval is incremented AFTER it is scaled. +// This is due to the fact that the timer counts down to 1 in mode 2 +// + +#define PIC_PROFILER_ON(c)\ + WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->CommandMode1,\ + (UCHAR)(PIC_BINARY | PIC_MODE2 | PIC_RWLSBMSB | PIC_SC0));\ + WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->Timer1,\ + (UCHAR)((c) & 0xff) );\ + WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->Timer1,\ + (UCHAR)(((c)>> 8) & 0xff) ) + +// +// Define a macro to shut down the profiler +// + +#define PIC_PROFILER_OFF()\ + WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->CommandMode1,\ + (ULONG)(PIC_BINARY | PIC_MODE4 | PIC_RWLSBMSB | PIC_SC0)) + + +#endif // _HALPROF_ diff --git a/private/ntos/nthals/halalpha/haltsup.s b/private/ntos/nthals/halalpha/haltsup.s new file mode 100644 index 000000000..0fa6c8d0e --- /dev/null +++ b/private/ntos/nthals/halalpha/haltsup.s @@ -0,0 +1,110 @@ +// TITLE("Halt Interrupt Support") +//++ +// +// Copyright (c) 1992 Digital Equipment Corporation +// Copyright (c) 1993 Digital Equipment Corporation +// +// Module Name: +// +// haltsup.s +// +// Abstract: +// +// This module implements the code necessary to field halt button +// interrupts. +// +// Author: +// +// Joe Notarangelo 18-Dec-1992 +// +// Environment: +// +// Kernel mode only, IRQL halt synchronization level. +// +// Revision History: +// +//-- + +#if !(DBG) + +// +// Boolean value that controls whether to break or not for a halt button +// interrupt on a free build. The default value is zero and must be set +// in the debugger to a non-zero value to trigger the breakpoint action +// when the halt button is pressed. +// + + .data + + .globl HalpHaltButtonBreak +HalpHaltButtonBreak: + .long 0 : 1 + +#endif //!DBG + + +#include "halalpha.h" + + SBTTL("Halt Interrupt Support") +//++ +// +// Routine Description: +// +// This routine is entered as the result of a halt interrupt caused by +// a human pushing the halt switch on the system box. This routine is +// connected directly into the IDT. The halt interrupt is mechanical and +// does not require an interrupt acknowledge. +// +// Arguments: +// +// s6/fp - Supplies a pointer to a trap frame. +// +// Return Value: +// +// None. +// +//-- + + .struct 0 +HaltRa: .space 8 // saved return address + .space 8 // fill for alignment +HaltFrameLength: + + NESTED_ENTRY(HalpHaltInterrupt, ExceptionFrameLength, zero) + + lda sp, -HaltFrameLength(sp) // allocate stack frame + stq ra, HaltRa(sp) // save ra + + PROLOGUE_END + + +#if DBG + +// +// Always stop in the debugger if this is a checked build. +// + + BREAK_DEBUG_STOP // stop in the debugger + +#else + +// +// If this is a free build then check the variable HalpHaltButtonBreak, +// if it is non-zero then take the breakpoint, otherwise ignore it. +// + + lda t0, HalpHaltButtonBreak // get the address of the boolean + ldl t0, 0(t0) // read the boolean + beq t0, 10f // if eq, don't stop + + BREAK_DEBUG_STOP // stop in the debugger + +10: + +#endif //DBG + + ldq ra, HaltRa(sp) // save ra + lda sp, HaltFrameLength(sp) // deallocate stack frame + ret zero, (ra) // interrupt is dismissed + + .end HalpHaltInterrupt diff --git a/private/ntos/nthals/halalpha/halvfont.h b/private/ntos/nthals/halalpha/halvfont.h new file mode 100644 index 000000000..df634a336 --- /dev/null +++ b/private/ntos/nthals/halalpha/halvfont.h @@ -0,0 +1,233 @@ +/* + +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + halvfont.h + +Abstract: + + 8x16 pixel fonts for the VGA video boot driver. Stolen from + David Conroy's Beta-machine fonts. + + + +Author: + + John DeRosa 5/7/1992 + + + +Revision History: + + Jeff McLeman (DEC) 28-Jul-1992 + Stole from FW to use with HAL and renamed to header file + +*/ + + +/* + * ASCII characters 0x20 -- 0x7f (space -- del). Each byte is one + * scan line, and each character is 2 rows. + */ + +unsigned char vga8x16undef[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + +unsigned char vga8x16chars[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0xFF, 0xFF, 0x66, 0x66, + 0xFF, 0xFF, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x3E, 0x7E, 0x60, 0x60, 0x7C, 0x3E, + 0x06, 0x06, 0x7E, 0x7C, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x6C, 0x0C, 0x18, 0x18, + 0x30, 0x36, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x7C, 0x6C, 0x6C, 0x38, 0x38, 0x70, 0x70, + 0xDE, 0xDE, 0xCC, 0xCC, 0xFE, 0x76, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x0C, 0x1C, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x1C, 0x0C, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x30, 0x38, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x38, 0x30, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x3C, 0x3C, 0xFF, 0xFF, + 0x3C, 0x3C, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x7E, 0x7E, + 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x30, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x06, 0x06, 0x0C, 0x0C, 0x18, + 0x18, 0x30, 0x30, 0x60, 0x60, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x6E, + 0x76, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x38, 0x38, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x0C, 0x0C, + 0x18, 0x18, 0x30, 0x30, 0x7E, 0x7E, 0x00, 0x00, + 0x00, 0x00, 0x7E, 0x7E, 0x0C, 0x0C, 0x18, 0x18, + 0x0C, 0x0C, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x0C, 0x0C, 0x1C, 0x1C, 0x3C, 0x3C, + 0x6C, 0x6C, 0x7E, 0x7E, 0x0C, 0x0C, 0x00, 0x00, + 0x00, 0x00, 0x7E, 0x7E, 0x60, 0x60, 0x7C, 0x7E, + 0x06, 0x06, 0x06, 0x66, 0x7E, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x1C, 0x3C, 0x70, 0x60, 0x60, 0x7C, + 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x7E, 0x7E, 0x06, 0x06, 0x0C, 0x0C, + 0x18, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x3C, 0x3C, + 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x3E, + 0x06, 0x06, 0x06, 0x0E, 0x3C, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x30, 0x20, + 0x00, 0x00, 0x00, 0x0E, 0x1C, 0x38, 0x70, 0xE0, + 0x70, 0x38, 0x1C, 0x0E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x00, 0x00, + 0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xE0, 0x70, 0x38, 0x1C, 0x0E, + 0x1C, 0x38, 0x70, 0xE0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x0C, 0x0C, + 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x7C, 0xE6, 0xC2, 0xDA, 0xD6, + 0xD6, 0xDC, 0xC0, 0xE2, 0x7E, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x66, 0x66, 0x66, + 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x7E, 0x66, 0x66, 0x7E, 0x7C, + 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x60, 0x60, + 0x60, 0x60, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x7C, 0x6E, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x6E, 0x7C, 0x78, 0x00, 0x00, + 0x00, 0x00, 0x7E, 0x7E, 0x60, 0x60, 0x7C, 0x7C, + 0x60, 0x60, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, + 0x00, 0x00, 0x7E, 0x7E, 0x60, 0x60, 0x7C, 0x7C, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x3E, 0x7E, 0x60, 0x60, 0x6E, 0x6E, + 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7E, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, + 0x00, 0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xD8, 0xD8, 0xF0, 0xF0, + 0xD8, 0xD8, 0xCC, 0xCC, 0xC6, 0xC6, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, + 0x60, 0x60, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xEE, 0xEE, 0xFE, 0xD6, + 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x76, 0x76, 0x7E, + 0x7E, 0x6E, 0x6E, 0x66, 0x66, 0x66, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x7E, 0x66, 0x66, 0x66, 0x66, + 0x7E, 0x7C, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x6A, 0x7C, 0x36, 0x00, 0x00, + 0x00, 0x00, 0xF8, 0xFC, 0xCC, 0xCC, 0xCC, 0xFC, + 0xF8, 0xD8, 0xCC, 0xCC, 0xC6, 0xC6, 0x00, 0x00, + 0x00, 0x00, 0x3E, 0x7E, 0x60, 0x60, 0x70, 0x38, + 0x1C, 0x0E, 0x06, 0x06, 0x7E, 0x7C, 0x00, 0x00, + 0x00, 0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, + 0xD6, 0xFE, 0xFE, 0xEE, 0xC6, 0x82, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x18, + 0x18, 0x3C, 0x3C, 0x66, 0x66, 0x66, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x7E, 0x7E, 0x0C, 0x0C, 0x18, 0x18, + 0x30, 0x30, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, + 0x00, 0x00, 0x1E, 0x1E, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1E, 0x1E, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x60, 0x60, 0x30, 0x30, 0x18, + 0x18, 0x0C, 0x0C, 0x06, 0x06, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x78, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x78, 0x78, 0x00, 0x00, + 0x00, 0x10, 0x10, 0x38, 0x38, 0x6C, 0x6C, 0xC6, + 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, + 0x40, 0x60, 0x70, 0x38, 0x1C, 0x0C, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x3E, 0x06, + 0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x60, 0x60, 0x7C, 0x7E, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0x60, + 0x60, 0x60, 0x60, 0x60, 0x7E, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x06, 0x06, 0x3E, 0x7E, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66, + 0x66, 0x7E, 0x60, 0x60, 0x7E, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x0E, 0x1E, 0x18, 0x18, 0x7E, 0x7E, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0x66, + 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x7E, 0x7C, + 0x00, 0x00, 0x60, 0x60, 0x60, 0x7C, 0x7E, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x38, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x7C, 0x78, + 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xCC, 0xDC, 0xF8, + 0xF0, 0xF8, 0xD8, 0xCC, 0xCE, 0xC6, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, + 0xD6, 0xD6, 0xD6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x7E, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x60, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x7E, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0x60, + 0x70, 0x3C, 0x0E, 0x06, 0x7E, 0x7C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x7E, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1E, 0x0E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xD6, + 0xD6, 0xFE, 0xFE, 0xEE, 0xC6, 0x82, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3C, + 0x3C, 0x18, 0x3C, 0x3C, 0x66, 0x66, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x7E, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x0C, + 0x18, 0x18, 0x30, 0x30, 0x7E, 0x7E, 0x00, 0x00, + 0x00, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x38, 0xF0, + 0xF0, 0x38, 0x18, 0x18, 0x18, 0x18, 0x0E, 0x00, + 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x00, 0xE0, 0x30, 0x30, 0x30, 0x30, 0x38, 0x1E, + 0x1E, 0x38, 0x30, 0x30, 0x30, 0x30, 0xE0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0xF2, 0xBE, + 0x9C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; diff --git a/private/ntos/nthals/halalpha/halvga.h b/private/ntos/nthals/halalpha/halvga.h new file mode 100644 index 000000000..c393d49c7 --- /dev/null +++ b/private/ntos/nthals/halalpha/halvga.h @@ -0,0 +1,72 @@ +/* + +Copyright (c) 1992, 1993, 1994 Digital Equipment Corporation + +Module Name: + + halvga.h + + +Abstract: + + Defines registers for standard VGA alphanumeric color mode video. + (graphics, bw mode are not defined.) + + Addresses are based on the VGA video ISA base address. + + +Author: + + John DeRosa 4/30/92 + + +Revision History: + + 17-Feb-1994 Eric Rehm + Remove all references to VGA. HAL display routines are + now device-independent. + +*/ + +#ifndef _HALVGA_ +#define _HALVGA_ + +// +// Define special character values for device-indpendent control functions. +// + +#define ASCII_NUL 0x00 +#define ASCII_BEL 0x07 +#define ASCII_BS 0x08 +#define ASCII_HT 0x09 +#define ASCII_LF 0x0A +#define ASCII_VT 0x0B +#define ASCII_FF 0x0C +#define ASCII_CR 0x0D +#define ASCII_CSI 0x9B +#define ASCII_ESC 0x1B +#define ASCII_SYSRQ 0x80 + +// +// Define colors, HI = High Intensity +// +// + +#define FW_COLOR_BLACK 0x00 +#define FW_COLOR_RED 0x01 +#define FW_COLOR_GREEN 0x02 +#define FW_COLOR_YELLOW 0x03 +#define FW_COLOR_BLUE 0x04 +#define FW_COLOR_MAGENTA 0x05 +#define FW_COLOR_CYAN 0x06 +#define FW_COLOR_WHITE 0x07 +#define FW_COLOR_HI_BLACK 0x08 +#define FW_COLOR_HI_RED 0x09 +#define FW_COLOR_HI_GREEN 0x0A +#define FW_COLOR_HI_YELLOW 0x0B +#define FW_COLOR_HI_BLUE 0x0C +#define FW_COLOR_HI_MAGENTA 0x0D +#define FW_COLOR_HI_CYAN 0x0E +#define FW_COLOR_HI_WHITE 0x0F + +#endif // _HALVGA_ diff --git a/private/ntos/nthals/halalpha/idle.s b/private/ntos/nthals/halalpha/idle.s new file mode 100644 index 000000000..0d53d7aed --- /dev/null +++ b/private/ntos/nthals/halalpha/idle.s @@ -0,0 +1,62 @@ +// TITLE("Processor Idle Support") +//++ +// +// Copyright (c) 1992 Digital Equipment Corporation +// Copyright (c) 1993 Digital Equipment Corporation +// +// Module Name: +// +// idle.s +// +// Abstract: +// +// This module implements the HalProcessorIdle interface +// +// Author: +// +// John Vert (jvert) 11-May-1994 +// +// Environment: +// +// Revision History: +// +//-- +#include "halalpha.h" + + + SBTTL("Processor Idle") +//++ +// +// VOID +// HalProcessorIdle( +// VOID +// ) +// +// Routine Description: +// +// This function is called when the current processor is idle with +// interrupts disabled. There is no thread active and there are no +// DPCs to process. Therefore, power can be switched to a standby +// mode until the the next interrupt occurs on the current processor. +// +// N.B. This routine is entered with interrupts disabled. This routine +// must do any power management enabling necessary, enable interrupts, +// then either return or wait for an interrupt. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalProcessorIdle) + + ENABLE_INTERRUPTS // no power management, just + // enable interrupts and return + ret zero, (ra) + + .end HalProcessorIdle diff --git a/private/ntos/nthals/halalpha/info.c b/private/ntos/nthals/halalpha/info.c new file mode 100644 index 000000000..141ceff53 --- /dev/null +++ b/private/ntos/nthals/halalpha/info.c @@ -0,0 +1,180 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + info.c + +Abstract: + +Author: + + Ken Reneris (kenr) 08-Aug-1994 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + + +#include "halp.h" + +#ifdef _PNP_POWER_ +HAL_CALLBACKS HalCallback; +#endif // _PNP_POWER_ + +// +// External references +// + +extern WINDOW_CONTROL_REGISTERS HalpIsaWindowControl; +extern WINDOW_CONTROL_REGISTERS HalpMasterWindowControl; + + + +NTSTATUS +HalpQueryInstalledBusInformation ( + OUT PVOID Buffer, + IN ULONG BufferLength, + OUT PULONG ReturnedLength + ); + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,HaliQuerySystemInformation) +#pragma alloc_text(PAGE,HaliSetSystemInformation) +#endif + + +NTSTATUS +HaliQuerySystemInformation( + IN HAL_QUERY_INFORMATION_CLASS InformationClass, + IN ULONG BufferSize, + IN OUT PVOID Buffer, + OUT PULONG ReturnedLength + ) +/*++ + +Routine Description: + + The function returns system-wide information controlled by the HAL for a + variety of classes. + +Arguments: + + InformationClass - Information class of the request. + + BufferSize - Size of buffer supplied by the caller. + + Buffer - Supplies the space to store the data and pass additional info. + + ReturnedLength - Supplies a count in bytes of the amount of data returned. + +Return Value: + + STATUS_SUCCESS or error. + +--*/ +{ + NTSTATUS Status; + PULONG mapRegisters; + + switch (InformationClass) { + case HalInstalledBusInformation: + Status = HalpQueryInstalledBusInformation ( + Buffer, + BufferSize, + ReturnedLength + ); + break; + + case HalProfileSourceInformation: + Status = HalpProfileSourceInformation ( + Buffer, + BufferSize, + ReturnedLength); + break; + + case HalMapRegisterInformation: + mapRegisters = (PULONG)Buffer; + if ( BufferSize < 4 ) { + Status = STATUS_BUFFER_TOO_SMALL; + } else { + switch ( *(PULONG)Buffer ) { + case Isa: + *mapRegisters = HalpIsaWindowControl.WindowSize / PAGE_SIZE; + *ReturnedLength = 4; + Status = STATUS_SUCCESS; + break; + + case Eisa: + case PCIBus: + *mapRegisters = HalpMasterWindowControl.WindowSize / PAGE_SIZE; + *ReturnedLength = 4; + Status = STATUS_SUCCESS; + break; + + default: + Status = STATUS_INVALID_PARAMETER; + break; + } + } + break; + + default: + Status = STATUS_INVALID_LEVEL; + break; + } + + return(Status); +} + +NTSTATUS +HaliSetSystemInformation ( + IN HAL_SET_INFORMATION_CLASS InformationClass, + IN ULONG BufferSize, + IN PVOID Buffer + ) +/*++ + +Routine Description: + + The function allows setting of various fields return by + HalQuerySystemInformation. + +Arguments: + + InformationClass - Information class of the request. + + BufferSize - Size of buffer supplied by the caller. + + Buffer - Supplies the data to be set. + +Return Value: + + STATUS_SUCCESS or error. + +--*/ +{ + NTSTATUS Status; + + switch (InformationClass) { + + case HalProfileSourceInterval: + Status = HalpProfileSourceInterval ( + Buffer, + BufferSize); + break; + + default: + Status = STATUS_INVALID_LEVEL; + break; + } + + return Status; +} diff --git a/private/ntos/nthals/halalpha/inithal.c b/private/ntos/nthals/halalpha/inithal.c new file mode 100644 index 000000000..a3bc08c7a --- /dev/null +++ b/private/ntos/nthals/halalpha/inithal.c @@ -0,0 +1,1052 @@ +/*++ + +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" +#include "eisa.h" + + +// +// Declare the extern variable UncorrectableError declared in +// inithal.c. +// +PERROR_FRAME PUncorrectableError; + +// +// 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. +// + +ULONG 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 +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; + + Prcb = PCR->Prcb; + + // + // 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); + + // + // Fill in handlers for APIs which this HAL supports + // + + HalQuerySystemInformation = HaliQuerySystemInformation; + HalSetSystemInformation = HaliSetSystemInformation; + + // + // Phase 0 initialization. + // + + HalpSetTimeIncrement(); + HalpMapIoSpace(); + HalpEstablishErrorHandler(); + HalpInitializeDisplay(LoaderBlock); + HalpInitializeMachineDependent( Phase, LoaderBlock ); + HalpCreateDmaStructures(LoaderBlock); + HalpInitializeInterrupts(); + HalpVerifyPrcbVersion(); + + // + // Set the processor active in the HAL active processor mask. + // + + HalpActiveProcessors = 1 << Prcb->Number; + + // + // Initialize the logical to physical processor mapping + // for the primary processor. + // + HalpLogicalToPhysicalProcessor[0] = HAL_PRIMARY_PROCESSOR; + + return TRUE; + + } else { + +#if HALDBG + + DbgPrint( "HAL/HalInitSystem: Phase = %d\n", Phase ); + DbgBreakPoint(); + +#endif //HALDBG + + // + // Phase 1 initialization. + // + + HalpInitializeClockInterrupts(); + HalpInitializeMachineDependent( Phase, LoaderBlock ); + + // + // Allocate memory for the uncorrectable frame + // + + HalpAllocateUncorrectableFrame(); + + // + // Initialize the Buffer for Uncorrectable Error. + // + + HalpInitializeUncorrectableErrorFrame(); + + return TRUE; + + } + } + + // + // Perform necessary processor-specific initialization for + // secondary processors. Phase is ignored as this will be called + // only once on each secondary processor. + // + + HalpMapIoSpace(); + HalpInitializeInterrupts(); + HalpInitializeMachineDependent( Phase, LoaderBlock ); + + // + // 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 + 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 = + HalpLogicalToPhysicalProcessor[Prcb->Number]; + 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. + +--*/ + +{ +//jnfix - for mp systems if processor != 0 then init PALcode? +//either here or in next module? + 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 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 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. + // + + if( NextRestartBlock->BootStatus.ProcessorReady == FALSE ){ + + PhysicalNumber += 1; + + } else { + + // + // 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; + + HalpLogicalToPhysicalProcessor[LogicalNumber] = PhysicalNumber; + + return TRUE; + + } else { + + // + // Ensure that the logical to physical mapping has been + // established for this processor. + // + + HalpLogicalToPhysicalProcessor[LogicalNumber] = PhysicalNumber; + + } + + 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 DBG + DbgPrint( + "Frequency = %d\nMegaHertz = %d\n", + HalpClockFrequency, + HalpClockMegaHertz + ); +#endif + + +} + + + + +#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/halalpha/intsup.s b/private/ntos/nthals/halalpha/intsup.s new file mode 100644 index 000000000..40d484db4 --- /dev/null +++ b/private/ntos/nthals/halalpha/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, HalpAcknowledgeClockInterrupt // ack the interrupt + +// +// 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, 10f + + stl zero, HalpNextRateSelect // Set NextRateSelect to 0 + bsr ra, HalpProgramIntervalTimer // Program timer with new rate select + + ldl t0, HalpNewTimeIncrement + stl t0, HalpNextTimeIncrement // Set HalpNextTimeIncrement to HalpNewTimeIncrement + +// +// Call to handle performance counter wrap. +// +10: + 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 + ldl t0, __imp_DbgBreakPointWithStatus + lda a0, DBG_STATUS_CONTROL_C + jsr ra, (t0) // send status to debugger + + BREAK_BREAKIN // execute breakin breakpoint + +30: + +#endif //DEVL + +// +// Return to the caller. +// + + 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, HalpAcknowledgeClockInterrupt // ack the interrupt + +// +// Call the kernel to update the run time. +// + + 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. +// + + 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/halalpha/ioproc.c b/private/ntos/nthals/halalpha/ioproc.c new file mode 100644 index 000000000..ec0ee051d --- /dev/null +++ b/private/ntos/nthals/halalpha/ioproc.c @@ -0,0 +1,104 @@ +/*++ + +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,HalReportResourceUsage) +#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 +HalReportResourceUsage ( + VOID + ) +{ + INTERFACE_TYPE interfacetype; + ANSI_STRING AHalName; + UNICODE_STRING UHalName; + + switch (HalpBusType) { + case MACHINE_TYPE_ISA: interfacetype = Isa; break; + case MACHINE_TYPE_EISA: interfacetype = Eisa; break; +#if 0 + case MACHINE_TYPE_MCA: interfacetype = MicroChannel; break; +#endif // 0 + default: interfacetype = Internal; break; + } + + RtlInitAnsiString (&AHalName, HalName); + RtlAnsiStringToUnicodeString (&UHalName, &AHalName, TRUE); + HalpReportResourceUsage ( + &UHalName, // descriptive name + interfacetype // device space interface type + ); + + RtlFreeUnicodeString (&UHalName); +} + + +VOID +HalpInitOtherBuses ( + VOID + ) +{ + // no other internal buses supported +} diff --git a/private/ntos/nthals/halalpha/iousage.c b/private/ntos/nthals/halalpha/iousage.c new file mode 100644 index 000000000..b1f9ce006 --- /dev/null +++ b/private/ntos/nthals/halalpha/iousage.c @@ -0,0 +1,527 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + iousage.c + +Abstract: + +Author: + + Ken Reneris (kenr) + +Environment: + + Kernel mode only. + +Revision History: + + Added to Alpha (Avanti Hals) (Sameer Dekate) 5-4-94 + +--*/ + +#include "halp.h" +#include "iousage.h" + +// +// Define constants for system IDTs +// + +#define MAXIMUM_IDTVECTOR 0xff +#define MAXIMUM_PRIMARY_VECTOR 0xff +#define PRIMARY_VECTOR_BASE 0x30 // 0-2f are x86 trap vectors + +// +// Array to remember hal's IDT usage +// + +KAFFINITY HalpActiveProcessors; + +// +// From usage.c +// + +ADDRESS_USAGE *HalpAddressUsageList; + +// +// IDT vector usage info +// + +IDTUsage HalpIDTUsage[MAXIMUM_IDTVECTOR]; + +VOID +HalpGetResourceSortValue ( + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR pRCurLoc, + OUT PULONG sortscale, + OUT PLARGE_INTEGER sortvalue + ); + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpEnableInterruptHandler) +#pragma alloc_text(INIT,HalpRegisterVector) +#pragma alloc_text(INIT,HalpGetResourceSortValue) +#pragma alloc_text(INIT,HalpReportResourceUsage) +#endif + + +VOID +HalpEnableInterruptHandler ( + IN UCHAR ReportFlags, + IN ULONG BusInterruptVector, + IN ULONG SystemInterruptVector, + IN KIRQL SystemIrql, + IN VOID (*HalInterruptServiceRoutine)(VOID), + IN KINTERRUPT_MODE InterruptMode + ) +/*++ + +Routine Description: + + This function connects & registers an IDT vectors usage by the HAL. + +Arguments: + +Return Value: + +--*/ +{ + // + // Remember which vector the hal is connecting so it can be reported + // later on + // + HalpRegisterVector (ReportFlags, BusInterruptVector, SystemInterruptVector, SystemIrql); + + + // + // Connect the IDT and enable the vector now + // + +#if 0 + KiSetHandlerAddressToIDT(SystemInterruptVector, HalInterruptServiceRoutine); +#endif //0 + HalEnableSystemInterrupt(SystemInterruptVector, SystemIrql, InterruptMode); +} + + +VOID +HalpRegisterVector ( + IN UCHAR ReportFlags, + IN ULONG BusInterruptVector, + IN ULONG SystemInterruptVector, + IN KIRQL SystemIrql + ) +/*++ + +Routine Description: + + This registers an IDT vectors usage by the HAL. + +Arguments: + +Return Value: + +--*/ +{ +#if DBG + // There are only 0ff IDT entries... + ASSERT (SystemInterruptVector <= MAXIMUM_IDTVECTOR && + BusInterruptVector <= MAXIMUM_IDTVECTOR); +#endif + + // + // Remember which vector the hal is connecting so it can be reported + // later on + // + + HalpIDTUsage[SystemInterruptVector].Flags = ReportFlags; + HalpIDTUsage[SystemInterruptVector].Irql = SystemIrql; + HalpIDTUsage[SystemInterruptVector].BusReleativeVector = (UCHAR) BusInterruptVector; +} + + +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; + + default: + *sortscale = 4; + sortvalue->QuadPart = 0; + break; + } +} + + +VOID +HalpReportResourceUsage ( + IN PUNICODE_STRING HalName, + IN INTERFACE_TYPE DeviceInterfaceToUse + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + 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; + UCHAR pass, reporton; + INTERFACE_TYPE interfacetype; + ULONG CurrentIDT, CurrentElement; + ADDRESS_USAGE *CurrentAddress; + LARGE_INTEGER curvalue, sortvalue; + PHYSICAL_ADDRESS TempAddress; + + // + // 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; + + // + // Make sure all vectors 00-2f are reserved + // 00-1E reserved by Intel + // 1F reserved by Intel for APIC (apc priority level) + // 20-2e reserved by Microsoft + // 2f reserved by Microsoft for APIC (dpc priority level) + // + + for(i=0; i < PRIMARY_VECTOR_BASE; i++) { + if (!(HalpIDTUsage[i].Flags & IDTOwned)) { + HalpIDTUsage[i].Flags = InternalUsage; + HalpIDTUsage[i].BusReleativeVector = (UCHAR) i; + } + } + + for(pass=0; pass < 3; pass++) { + + switch(pass) { + + case 0: { +#if DBG +DbgPrint("Device LIST...\n"); +#endif // DBG + // + // First pass - build resource lists for resources reported + // reported against device usage. + // + + reporton = DeviceUsage & ~IDTOwned; + interfacetype = DeviceInterfaceToUse; + break; + } + + case 1: { +#if DBG +DbgPrint("Internal LIST...\n"); +#endif // DBG + // + // Second pass = build reousce lists for resources reported + // as internal usage. + // + + reporton = InternalUsage & ~IDTOwned; + interfacetype = Internal; + break; + } + + case 2: { +#if DBG +DbgPrint("PCI LIST...\n"); +#endif // DBG + // + // Third pass = build reousce lists for resources reported + // as PCI usage. + // + + reporton = PCIUsage & ~IDTOwned; + interfacetype = PCIBus; + break; + } + } + + CurrentIDT = 0; + CurrentElement = 0; + CurrentAddress = HalpAddressUsageList; + + for (; ;) { + if (CurrentIDT <= MAXIMUM_IDTVECTOR) { + // + // Check to see if CurrentIDT needs to be reported + // + + if (!(HalpIDTUsage[CurrentIDT].Flags & reporton)) { + // Don't report on this one + CurrentIDT++; + continue; + } + + // + // Report CurrentIDT resource + // + + RPartialDesc.Type = CmResourceTypeInterrupt; + RPartialDesc.ShareDisposition = CmResourceShareDriverExclusive; + RPartialDesc.Flags = + HalpIDTUsage[CurrentIDT].Flags & InterruptLatched ? + CM_RESOURCE_INTERRUPT_LATCHED : + CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + RPartialDesc.u.Interrupt.Vector = HalpIDTUsage[CurrentIDT].BusReleativeVector; + RPartialDesc.u.Interrupt.Level = HalpIDTUsage[CurrentIDT].BusReleativeVector; + RPartialDesc.u.Interrupt.Affinity = HalpActiveProcessors; + + RtlCopyMemory (&TPartialDesc, &RPartialDesc, sizeof TPartialDesc); + TPartialDesc.u.Interrupt.Vector = CurrentIDT; + TPartialDesc.u.Interrupt.Level = HalpIDTUsage[CurrentIDT].Irql; + + CurrentIDT++; + + } else { + + // + // Check to see if CurrentAddress needs to be reported + // + + if (!CurrentAddress) { + break; // No addresses left + } + + if (!(CurrentAddress->Flags & reporton)) { + // Don't report on this list + CurrentElement = 0; + CurrentAddress = CurrentAddress->Next; + continue; + } + + if (!CurrentAddress->Element[CurrentElement].Length) { + // End of current list, go to next list + CurrentElement = 0; + CurrentAddress = CurrentAddress->Next; + continue; + } + + // + // Report CurrentAddress + // + + RPartialDesc.Type = (UCHAR) CurrentAddress->Type; + RPartialDesc.ShareDisposition = CmResourceShareDriverExclusive; + + if (RPartialDesc.Type == CmResourceTypePort) { + i = 1; // address space port + RPartialDesc.Flags = CM_RESOURCE_PORT_IO; + } else { + i = 0; // address space memory + RPartialDesc.Flags = CM_RESOURCE_MEMORY_READ_WRITE; + } + + // Notice: assuming u.Memory and u.Port have the same layout + RPartialDesc.u.Memory.Start.HighPart = 0; + RPartialDesc.u.Memory.Start.LowPart = + CurrentAddress->Element[CurrentElement].Start; + + RPartialDesc.u.Memory.Length = + CurrentAddress->Element[CurrentElement].Length; + +#if DBG +DbgPrint("Start=0x%x Lenght=0x%x\n", RPartialDesc.u.Memory.Start.LowPart, RPartialDesc.u.Memory.Length); +#endif // DBG + + // translated address = Raw address + RtlCopyMemory (&TPartialDesc, &RPartialDesc, sizeof TPartialDesc); + HalTranslateBusAddress ( + interfacetype, // device bus or internal + 0, // bus number + RPartialDesc.u.Memory.Start, // source address + &i, // address space + &TempAddress ); // aligned translated address + + TPartialDesc.u.Memory.Start = TempAddress; // TPartialDesc is pack(4) + +#if DBG +DbgPrint("TRANSLATED ADDRESS Start=0x%x Lenght=0x%x\n", TPartialDesc.u.Memory.Start.LowPart, TPartialDesc.u.Memory.Length); +#endif // DBG + + if (RPartialDesc.Type == CmResourceTypePort && i == 0) { + TPartialDesc.Flags = CM_RESOURCE_PORT_MEMORY; + } + + CurrentElement++; + } + + // + // Include the current resource in the HALs list + // + + if (pRFullDesc->InterfaceType != interfacetype) { + // + // 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 = interfacetype; + pTFullDesc->InterfaceType = interfacetype; + + pRPartList = &pRFullDesc->PartialResourceList; + pTPartList = &pTFullDesc->PartialResourceList; + + // + // Bump current location pointers up + // + pRCurLoc = pRFullDesc->PartialResourceList.PartialDescriptors; + pTCurLoc = pTFullDesc->PartialResourceList.PartialDescriptors; + } + + + pRPartList->Count++; + pTPartList->Count++; + RtlCopyMemory (pRCurLoc, &RPartialDesc, sizeof RPartialDesc); + RtlCopyMemory (pTCurLoc, &TPartialDesc, sizeof TPartialDesc); + + pRCurLoc++; + pTCurLoc++; + } + } + + 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); +} diff --git a/private/ntos/nthals/halalpha/iousage.h b/private/ntos/nthals/halalpha/iousage.h new file mode 100644 index 000000000..8a128d56e --- /dev/null +++ b/private/ntos/nthals/halalpha/iousage.h @@ -0,0 +1,85 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation +Copyright (c) 1992,1993 Digital Equipment Corporation + +Module Name: + + iousage.h + +Abstract: + + This header file defines the iousage definitions + +Author: + + Sameer Dekate 5-3-1994 + + +Revision History: + + Most pieces have be stolen from Microsofts halp.h + +--*/ + +// +// External Function Prototypes +// + +VOID +HalpEnableInterruptHandler ( + IN UCHAR ReportFlags, + IN ULONG BusInterruptVector, + IN ULONG SystemInterruptVector, + IN KIRQL SystemIrql, + IN VOID (*HalInterruptServiceRoutine)(VOID), + IN KINTERRUPT_MODE InterruptMode + ); + +VOID +HalpRegisterVector ( + IN UCHAR ReportFlags, + IN ULONG BusInterruptVector, + IN ULONG SystemInterruptVector, + IN KIRQL SystemIrql + ); + +VOID +HalpReportResourceUsage ( + IN PUNICODE_STRING HalName, + IN INTERFACE_TYPE DeviceInterfaceToUse + ); +// +// Resource usage information +// + +#pragma pack(1) +typedef struct { + UCHAR Flags; + KIRQL Irql; + UCHAR BusReleativeVector; +} IDTUsage; + +typedef struct _HalAddressUsage{ + struct _HalAddressUsage *Next; + CM_RESOURCE_TYPE Type; // Port or Memory + UCHAR Flags; // same as IDTUsage.Flags + struct { + ULONG Start; + ULONG Length; + } Element[]; +} ADDRESS_USAGE; +#pragma pack() + +#define IDTOwned 0x01 // IDT is not available for others +#define InterruptLatched 0x02 // Level or Latched +#define InternalUsage 0x11 // Report usage on internal bus +#define DeviceUsage 0x21 // Report usage on device bus +#define PCIUsage 0x41 // Report usage on PCI bus + +extern IDTUsage HalpIDTUsage[]; +extern ADDRESS_USAGE *HalpAddressUsageList; + +#define HalpRegisterAddressUsage(a) \ + (a)->Next = HalpAddressUsageList, HalpAddressUsageList = (a); + diff --git a/private/ntos/nthals/halalpha/isaaddr.h b/private/ntos/nthals/halalpha/isaaddr.h new file mode 100644 index 000000000..832a48d49 --- /dev/null +++ b/private/ntos/nthals/halalpha/isaaddr.h @@ -0,0 +1,75 @@ +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + isaaddr.h + +Abstract: + + This module defines the standard device addresses on the ISA/EISA bus. + +Author: + + Joe Notarangelo 22-Oct-1993 + +Revision History: + + +--*/ + +#ifndef _ISAADDR_ +#define _ISAADDR_ + +// +// Standard VGA video adapter offsets +// + +#define VIDEO_MEMORY_OFFSET 0xb8000 +#define VIDEO_FONT_MEMORY_OFFSET 0xa0000 + +// +// Define the base port address for the PC standard floppy. +// + +#define FLOPPY_ISA_PORT_ADDRESS 0x3f0 + +// +// Define the base port address for the PC standard keyboard and mouse. +// + +#define KEYBOARD_ISA_PORT_ADDRESS 0x060 +#define MOUSE_ISA_PORT_ADDRESS 0x060 +#define KBD_ISA_OUTPUT_BUFFER_PORT 0x060 +#define KBD_ISA_STATUS_PORT 0x064 + +// +// Define the base port address for the PC standard parallel port. +// + +#define PARALLEL_ISA_PORT_ADDRESS 0x3bc + +// +// Define the base port addresses for the PC standard serial lines. +// + +#define COM1_ISA_PORT_ADDRESS 0x3f8 +#define COM2_ISA_PORT_ADDRESS 0x2f8 + +// +// Define the port addresses for the PC standard real time clock. +// + +#define RTC_ISA_ADDRESS_PORT 0x070 +#define RTC_ISA_DATA_PORT 0x071 +#define RTC_ALT_ISA_ADDRESS_PORT 0x170 +#define RTC_ALT_ISA_DATA_PORT 0x171 + +// +// Define the base port address for the PC standard 8K CMOS RAM. +// + +#define CMOS_ISA_PORT_ADDRESS 0x800 + +#endif // _ISAADDR_ diff --git a/private/ntos/nthals/halalpha/lca4.c b/private/ntos/nthals/halalpha/lca4.c new file mode 100644 index 000000000..64e28dba4 --- /dev/null +++ b/private/ntos/nthals/halalpha/lca4.c @@ -0,0 +1,657 @@ +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + lca4.c + +Abstract: + + This module implements functions that are specific to the LCA4 + microprocessor. + +Author: + + Joe Notarangelo 20-Oct-1993 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" +#include "lca4.h" +#include "axp21066.h" + +#ifndef AXP_FIRMWARE +VOID +DumpIoc( + VOID + ); +#endif + +// +// Globals +// + +// +// Parity checking is a tri-state variable, unknown == all f's. Which means +// Keep checking disabled until we can determine what we want to set it to, +// which then means 1 or 0. +// + +extern ULONG HalDisablePCIParityChecking; + +#ifdef AXP_FIRMWARE + +// +// Put these functions in the discardable text section. +// + +// +// Local function prototypes +// + +ULONG +HalpDetermineLca4Revision( + VOID + ); + +VOID +HalpLca4MapAddressSpaces( + VOID + ); + +ULONG +HalpLca4Revision( + VOID + ); + +ULONGLONG +HalpLca4IocTbTagPhysical( + VOID + ); + +ULONGLONG +HalpLca4PciIntAckPhysical( + VOID + ); + +ULONGLONG +HalpLca4PciIoPhysical( + VOID + ); + +ULONGLONG +HalpLca4PciDensePhysical( + VOID + ); + +#pragma alloc_text(DISTEXT, HalpDetermineLca4Revision) +#pragma alloc_text(DISTEXT, HalpLca4MapAddressSpaces) +#pragma alloc_text(DISTEXT, HalpLca4Revision) +#pragma alloc_text(DISTEXT, HalpLca4IocTbTagPhysical) +#pragma alloc_text(DISTEXT, HalpLca4PciIntAckPhysical) +#pragma alloc_text(DISTEXT, HalpLca4PciIoPhysical) +#pragma alloc_text(DISTEXT, HalpLca4PciDensePhysical) + +#endif // AXP_FIRMWARE + + +ULONG +HalpDetermineLca4Revision( + VOID + ) +/*++ + +Routine Description: + + Determine the revision of the LCA4 processor we are currently executing. + +Arguments: + + None. + +Return Value: + + Return the recognized revision of the LCA4 processor executing. + +--*/ +{ + CAR_21066 Car; + ULONG Revision; + + // + // Pass 1 and Pass 2 LCA processors can be distinguished by the + // PWR bit of the Cache Register (CAR). For Pass 1 the bit is RAZ + // while for Pass 2 the bit is read/write. + // + // Read the current value of the CAR. If it is 1, then we know that + // it is Pass 2. Else, set the PWR bit and write it back. + // Then read CAR again. If PWR is still set then we are executing on + // Pass 2. Don't forget to reset the PWR bit before finishing. + // + + Car.all.QuadPart = READ_MEMC_REGISTER( + &((PLCA4_MEMC_CSRS)(0))->CacheControl ); + + if( Car.Pwr == 1 ) { + + Revision = Lca4Pass2; + + } else { + + Car.Pwr = 1; + + WRITE_MEMC_REGISTER( &((PLCA4_MEMC_CSRS)(0))->CacheControl, + Car.all.QuadPart ); + + Car.all.QuadPart = READ_MEMC_REGISTER( + &((PLCA4_MEMC_CSRS)(0))->CacheControl ); + + if( Car.Pwr == 1 ){ + Revision = Lca4Pass2; + } else { + Revision = Lca4Pass1; + } + + Car.Pwr = 0; + + WRITE_MEMC_REGISTER( &((PLCA4_MEMC_CSRS)(0))->CacheControl, + Car.all.QuadPart ); + + } + + + return Revision; + +} + +// +// Define the Revision variable for LCA4. +// + +ULONG Lca4Revision; + +// +// Define the Physical Address space variables for LCA4. +// + +ULONGLONG Lca4IocTbTagPhysical; +ULONGLONG Lca4PciIntAckPhysical; +ULONGLONG Lca4PciIoPhysical; +ULONGLONG Lca4PciDensePhysical; + + +VOID +HalpLca4MapAddressSpaces( + VOID + ) +/*++ + +Routine Description: + + Map the address spaces of the LCA4 dependent upon which revision + of the chip is executing. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + Lca4Revision = HalpDetermineLca4Revision(); + + switch (Lca4Revision){ + + // + // Pass 1 LCA4 + // + + case Lca4Pass1: + + Lca4IocTbTagPhysical = LCA4_PASS1_IOC_TBTAG_PHYSICAL; + Lca4PciIntAckPhysical = LCA4_PASS1_PCI_INTACK_BASE_PHYSICAL; + Lca4PciIoPhysical = LCA4_PASS1_PCI_IO_BASE_PHYSICAL; + Lca4PciDensePhysical = 0; + + break; + + // + // Pass 2 LCA4 + // + + case Lca4Pass2: + + Lca4IocTbTagPhysical = LCA4_PASS2_IOC_TBTAG_PHYSICAL; + Lca4PciIntAckPhysical = LCA4_PASS2_PCI_INTACK_BASE_PHYSICAL; + Lca4PciIoPhysical = LCA4_PASS2_PCI_IO_BASE_PHYSICAL; + Lca4PciDensePhysical = LCA4_PASS2_PCI_DENSE_BASE_PHYSICAL; + + break; + +#if (DBG) || (HALDBG) + + default: + + DbgPrint( "Unrecognized LCA4 Revision = %x (execution is hopeless)\n", + Lca4Revision ); + DbgBreakPoint(); + +#endif //DBG || HALDBG + + } + + return; + +} + +// +// The following routines could be in-lined (it that were supported) or +// made into macros to save space (time isn't any issue with these values). +// To do so the variables above would have to be exported. +// + +ULONG +HalpLca4Revision( + VOID + ) +/*++ + +Routine Description: + + Return the version of the LCA4 processor. + +Arguments: + + None. + +Return Value: + + The version of the LCA4 processor. + +--*/ +{ + + return Lca4Revision; + +} + +ULONGLONG +HalpLca4IocTbTagPhysical( + VOID + ) +/*++ + +Routine Description: + + Return the base address of the IOC TB Tag registers on the currently + executing LCA4 processor. + +Arguments: + + None. + +Return Value: + + The base physical address of the IOC TB Tag registers. + +--*/ +{ + + return Lca4IocTbTagPhysical; + +} + + +ULONGLONG +HalpLca4PciIntAckPhysical( + VOID + ) +/*++ + +Routine Description: + + Return the base physical address of PCI Interrupt Acknowledge space + on the currently executing LCA4 processor. + +Arguments: + + None. + +Return Value: + + The base physical address of PCI Interrupt Acknowledge. + +--*/ +{ + + return Lca4PciIntAckPhysical; + +} + +ULONGLONG +HalpLca4PciIoPhysical( + VOID + ) +/*++ + +Routine Description: + + Return the base physical address of PCI I/O space on the currently + executing LCA4 processor. + +Arguments: + + None. + +Return Value: + + The base physical address of PCI I/O space. + +--*/ +{ + + return Lca4PciIoPhysical; + +} + +ULONGLONG +HalpLca4PciDensePhysical( + VOID + ) +/*++ + +Routine Description: + + Return the base physical address of PCI Dense Memory space on the + currently executing LCA4 processor. + +Arguments: + + None. + +Return Value: + + The base physical address of PCI Dense Memory space. + +--*/ +{ + + return Lca4PciDensePhysical; + +} + +#if !defined(AXP_FIRMWARE) + + +VOID +HalpLca4InitializeSfwWindow( + PWINDOW_CONTROL_REGISTERS WindowRegisters, + LCA4_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 Lca4IsaWindow: + + WindowRegisters->WindowBase = (PVOID)ISA_DMA_WINDOW_BASE; + WindowRegisters->WindowSize = ISA_DMA_WINDOW_SIZE; + WindowRegisters->TranslatedBaseRegister = + &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->TranslatedBase0; + WindowRegisters->WindowBaseRegister = + &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->WindowBase0; + WindowRegisters->WindowMaskRegister = + &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->WindowMask0; + WindowRegisters->WindowTbiaRegister = + &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->Tbia; + + break; + + // + // The Master DMA Window. + // + + case Lca4MasterWindow: + + WindowRegisters->WindowBase = (PVOID)MASTER_DMA_WINDOW_BASE; + WindowRegisters->WindowSize = MASTER_DMA_WINDOW_SIZE; + WindowRegisters->TranslatedBaseRegister = + &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->TranslatedBase1; + WindowRegisters->WindowBaseRegister = + &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->WindowBase1; + WindowRegisters->WindowMaskRegister = + &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->WindowMask1; + WindowRegisters->WindowTbiaRegister = + &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->Tbia; + + break; + + default: + +#if DBG + + DbgPrint( "Lca4InitializeSfwWindow: Bad Window Number = %x\n", + WindowNumber ); + +#endif //DBG + + break; + + } + + return; +} + + +VOID +HalpLca4ProgramDmaWindow( + 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. + +--*/ +{ + LCA4_IOC_WMASK WindowMask; + LCA4_IOC_WBASE WindowBase; + LCA4_IOC_TBEN TbEnable; + LCA4_IOC_PCIPD PciPD; + LCA4_IOC_TBASE TranslatedBase; + + PVOID RegisterQva; + + WindowBase.Reserved1 = 0; + WindowBase.Reserved2 = 0; + WindowBase.Sg = 1; + WindowBase.Wen = 1; + WindowBase.BaseValue = (ULONG)(WindowRegisters->WindowBase) >> 20; + + WindowMask.Reserved1 = 0; + WindowMask.Reserved = 0; + WindowMask.MaskValue = (WindowRegisters->WindowSize >> 20) - 1; + + TranslatedBase.Reserved1 = 0; + TranslatedBase.Reserved = 0; + TranslatedBase.TBase = (ULONG)(MapRegisterBase) >> 10; + +#if DBG + + // + // Dump the EPIC registers. + // + + DumpIoc(); + +#endif //DBG + + // + // Clear the window base, temporarily disabling transactions to this + // DMA window. + // + + WRITE_IOC_REGISTER( WindowRegisters->WindowBaseRegister, (ULONGLONG)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_IOC_REGISTER( WindowRegisters->TranslatedBaseRegister, + *(PULONGLONG)&TranslatedBase ); + + WRITE_IOC_REGISTER( WindowRegisters->WindowMaskRegister, + *(PULONGLONG)&WindowMask ); + + WRITE_IOC_REGISTER( WindowRegisters->WindowBaseRegister, + *(PULONGLONG)&WindowBase ); + + // + // Invalidate any translations that might have existed for this window. + // + + WRITE_IOC_REGISTER( WindowRegisters->WindowTbiaRegister, (ULONGLONG)0 ); + + // + // Enable the translation buffer inside of the IOC. + // + + RtlZeroMemory( &TbEnable, sizeof(LCA4_IOC_TBEN) ); + TbEnable.Ten = 1; + + WRITE_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->TbEnable, + *(PULONGLONG)&TbEnable ); + + // + // Tri state parity checking - keep disabled if not determined + // yet. otherwise, Whack the PCI parity disable bit with the stored + // value + // + + RtlZeroMemory( &PciPD, sizeof(LCA4_IOC_PCIPD) ); + + if (HalDisablePCIParityChecking == 0xffffffff) { + PciPD.Par = 1; + } else { + PciPD.Par = HalDisablePCIParityChecking; + } + + WRITE_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->PciParityDisable, + *(PULONGLONG)&PciPD ); + +#if DBG + + // + // Dump the IOC registers. + // + + DumpIoc(); + +#endif //DBG + + return; +} + +ULONGLONG +READ_IOC_REGISTER( + PVOID + ); + +#if DBG + +VOID +DumpIoc( + VOID + ) +/*++ + +Routine Description: + + Read the interesting IOC registers and print them to the debug port. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + PVOID RegisterQva; + ULONGLONG Value; + + DbgPrint( "Dumping the IOC registers\n" ); + + RegisterQva = + &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0; + Value = READ_IOC_REGISTER( RegisterQva ); + DbgPrint( "IOSTAT[0] = %Lx\n", Value ); + + RegisterQva = + &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat1; + Value = READ_IOC_REGISTER( RegisterQva ); + DbgPrint( "IOSTAT[1] = %Lx\n", Value ); + + DbgPrint( "--end IOC dump\n\n" ); + + return; + +} + +#endif //DBG + +#endif //!AXP_FIRMWARE diff --git a/private/ntos/nthals/halalpha/lca4.h b/private/ntos/nthals/halalpha/lca4.h new file mode 100644 index 000000000..0fd7ab02f --- /dev/null +++ b/private/ntos/nthals/halalpha/lca4.h @@ -0,0 +1,669 @@ +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + lca4.h + +Abstract: + + This file defines the structures and definitions common to all + LCA4-based platforms (Low Cost Alpha in Hudson CMOS 4). + +Author: + + Joe Notarangelo 20-Oct-1993 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#ifndef _LCA4H_ +#define _LCA4H_ + + +// +// Define QVA constants for LCA4. +// + +#if !defined(QVA_ENABLE) + +#define QVA_ENABLE (0xa0000000) // Identify VA as QVA + +#endif //QVA_ENABLE + +#define QVA_SELECTORS (0xE0000000) // Identify QVA bits + +#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 size of I/O and memory space for LCA4 +// + +#define PCI_MAX_IO_ADDRESS 0xFFFFFF // 16 Mb of IO Space + +// +// Due we have 128MB total sparse space, of which some of it are holes +// + +#define PCI_MAX_SPARSE_MEMORY_ADDRESS ((128*1024*1024) - 1) +#define PCI_MIN_DENSE_MEMORY_ADDRESS PCI_MAX_SPARSE_MEMORY_ADDRESS + 1 // 128 Mb +#define PCI_MAX_DENSE_MEMORY_ADDRESS (0xa0000000 -1) // 2.5 Gb + +// +// Constant used by dense space I/O routines +// + +#define PCI_DENSE_BASE_PHYSICAL_SUPERPAGE 0xfffffc0300000000 + + +// +// Protect the assembly language code from C definitions. +// + +#if !defined(_LANGUAGE_ASSEMBLY) + +// +// 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 >> IO_BIT_SHIFT) ) ) + + +// +// Define the different supported passes of the LCA4 processor. +// + +typedef enum _LCA4_REVISIONS{ + Lca4Pass1 = 1, + Lca4Pass2 = 2 +}LCA4_REVISIONS, *PLCA4_REVISIONS; + +// +// Define physical address spaces for LCA4. +// + +#define LCA4_MEMC_BASE_PHYSICAL ((ULONGLONG)0x120000000) +#define LCA4_IOC_BASE_PHYSICAL ((ULONGLONG)0x180000000) +#define LCA4_PCI_MEMORY_BASE_PHYSICAL ((ULONGLONG)0x200000000) +#define LCA4_PCI_CONFIG_BASE_PHYSICAL ((ULONGLONG)0x1E0000000) + +#define LCA4_PASS1_IOC_TBTAG_PHYSICAL ((ULONGLONG)0x181000000) +#define LCA4_PASS1_PCI_INTACK_BASE_PHYSICAL ((ULONGLONG)0x1C0000000) +#define LCA4_PASS1_PCI_IO_BASE_PHYSICAL ((ULONGLONG)0x300000000) + +#define LCA4_PASS2_IOC_TBTAG_PHYSICAL ((ULONGLONG)0x181000000) +#define LCA4_PASS2_PCI_INTACK_BASE_PHYSICAL ((ULONGLONG)0x1A0000000) +#define LCA4_PASS2_PCI_IO_BASE_PHYSICAL ((ULONGLONG)0x1C0000000) +#define LCA4_PASS2_PCI_DENSE_BASE_PHYSICAL ((ULONGLONG)0x300000000) + + +// +// Define the Memory Controller CSRs. +// + + +#define LCA4_MEMC_BASE_QVA (HAL_MAKE_QVA(LCA4_MEMC_BASE_PHYSICAL)) + +// +// N.B. The structure below defines the offsets of the registers within +// the memory controller. These are "real" address offsets, not +// QVA offsets. Unfortunately, since these offsets represent "real" +// quadword addresses, they cannot be used as QVAs. Therefore, +// the routines to read and write the memory controller will take +// the base QVA and an offset as 2 address parameters, rather than +// using a single address parameter. This is inconvenient but +// manageable. +// + +typedef struct _LCA4_MEMC_CSRS{ + ULONGLONG BankConfiguration0; + ULONGLONG BankConfiguration1; + ULONGLONG BankConfiguration2; + ULONGLONG BankConfiguration3; + ULONGLONG BankMask0; + ULONGLONG BankMask1; + ULONGLONG BankMask2; + ULONGLONG BankMask3; + ULONGLONG BankTiming0; + ULONGLONG BankTiming1; + ULONGLONG BankTiming2; + ULONGLONG BankTiming3; + ULONGLONG GlobalTiming; + ULONGLONG ErrorStatus; + ULONGLONG ErrorAddress; + ULONGLONG CacheControl; + ULONGLONG VideoGraphicsControl; + ULONGLONG PlaneMask; + ULONGLONG Foreground; +} LCA4_MEMC_CSRS, *PLCA4_MEMC_CSRS; + + +// +// Define IO Controller CSRs. +// + +#define LCA4_IOC_BASE_QVA (HAL_MAKE_QVA(LCA4_IOC_BASE_PHYSICAL)) +#define LCA4_IOC_TBTAG_QVA (HAL_MAKE_QVA(LCA4_IOC_TBTAG_PHYSICAL)) + +// +// N.B. The structures below defines the address offsets of the control +// registers when used with the base QVA. It does NOT define the +// size or structure of the individual registers. +// + +typedef struct _LCA4_IOC_CSRS{ + UCHAR HostAddressExtension; + UCHAR ConfigurationCycleType; + UCHAR IocStat0; + UCHAR IocStat1; + UCHAR Tbia; + UCHAR TbEnable; + UCHAR PciSoftReset; + UCHAR PciParityDisable; + UCHAR WindowBase0; + UCHAR WindowBase1; + UCHAR WindowMask0; + UCHAR WindowMask1; + UCHAR TranslatedBase0; + UCHAR TranslatedBase1; +} LCA4_IOC_CSRS, *PLCA4_IOC_CSRS; + +#define LCA4_IOC_TB_ENTRIES (8) + +typedef struct _LCA4_IOC_TBTAGS{ + UCHAR IocTbTag[LCA4_IOC_TB_ENTRIES]; +} LCA4_IOC_TBTAGS, *PLCA4_IOC_TBTAGS; + +// +// Define formats of useful IOC registers. +// + +typedef struct _LCA4_IOC_HAE{ + ULONG Reserved1: 27; + ULONG Hae: 5; + ULONG Reserved; +} LCA4_IOC_HAE, *PLCA4_IOC_HAE; + +typedef struct _LCA4_IOC_CCT{ + ULONG CfgAd: 2; + ULONG Reserved1: 30; + ULONG Reserved; +} LCA4_IOC_CCT, *PLCA4_IOC_CCT; + +typedef struct _LCA4_IOC_TBEN{ + ULONG Reserved1: 7; + ULONG Ten: 1; + ULONG Reserved2: 24; + ULONG Reserved; +} LCA4_IOC_TBEN, *PLCA4_IOC_TBEN; + +typedef struct _LCA4_IOC_PCISR{ + ULONG Reserved1: 6; + ULONG Rst: 1; + ULONG Reserved2: 25; + ULONG Reserved; +} LCA4_IOC_PCISR, *PLCA4_IOC_PCISR; + +typedef struct _LCA4_IOC_PCIPD{ + ULONG Reserved1: 5; + ULONG Par: 1; + ULONG Reserved2: 26; + ULONG Reserved; +} LCA4_IOC_PCIPD, *PLCA4_IOC_PCIPD; + +typedef struct _LCA4_IOC_STAT0{ + ULONG Cmd: 4; + ULONG Err: 1; + ULONG Lost: 1; + ULONG THit: 1; + ULONG TRef: 1; + ULONG Code: 3; + ULONG Reserved1: 2; + ULONG Pnbr: 19; + ULONG Reserved; +} LCA4_IOC_STAT0, *PLCA4_IOC_STAT0; + +typedef enum _LCA4_IOC_STAT0_CODE{ + IocErrorRetryLimit = 0x0, + IocErrorNoDevice = 0x1, + IocErrorBadDataParity = 0x2, + IocErrorTargetAbort = 0x3, + IocErrorBadAddressParity = 0x4, + IocErrorPageTableReadError = 0x5, + IocErrorInvalidPage = 0x6, + IocErrorDataError = 0x7, + MaximumIocError +} LCA4_IOC_STAT0_CODE, *PLCA4_IOC_STAT0_CODE; + +typedef struct _LCA4_IOC_STAT1{ + ULONG Addr; + ULONG Reserved; +} LCA4_IO_STAT1, *PLCA4_IO_STAT1; + +typedef struct _LCA4_IOC_WMASK{ + ULONG Reserved1: 20; + ULONG MaskValue: 12; + ULONG Reserved; +} LCA4_IOC_WMASK, *PLCA4_IOC_WMASK; + +typedef struct _LCA4_IOC_WBASE{ + ULONG Reserved1: 20; + ULONG BaseValue: 12; + ULONG Sg: 1; + ULONG Wen: 1; + ULONG Reserved2: 30; +} LCA4_IOC_WBASE, *PLCA4_IOC_WBASE; + +typedef struct _LCA4_IOC_TBASE{ + ULONG Reserved1: 10; + ULONG TBase: 22; + ULONG Reserved; +} LCA4_IOC_TBASE, *PLCA4_IOC_TBASE; + +typedef struct _LCA4_IOC_TBTAG{ + ULONG Reserved1: 13; + ULONG TbTag: 19; + ULONG Reserved; +} LCA4_IOC_TBTAG, *PLCA4_IOC_TBTAG; + +typedef struct _LCA4_IOC_CTRL{ + ULONG CfgAd: 2; + ULONG Reserved1: 2; + ULONG Cerr: 1; + ULONG Clost: 1; + ULONG Rst: 1; + ULONG Ten: 1; + ULONG Reserved2: 19; + ULONG Hae: 5; + ULONG Reserved; +} LCA4_IOC_CTRL, *PLCA4_IOC_CTRL; + +// +// Define formats of useful Memory Controller registers. +// + +typedef struct _LCA4_MEMC_ESR{ + ULONG Eav: 1; + ULONG Cee: 1; + ULONG Uee: 1; + ULONG Wre: 1; + ULONG Sor: 1; + ULONG Reserved1: 2; + ULONG Cte: 1; + ULONG Reserved2: 1; + ULONG Mse: 1; + ULONG Mhe: 1; + ULONG Ice: 1; + ULONG Nxm: 1; + ULONG Reserved3: 19; + ULONG Reserved; +} LCA4_MEMC_ESR, *PLCA4_MEMC_ESR; + + +// +// Define PCI Config Space QVA +// + +#define LCA4_PCI_CONFIG_BASE_QVA (HAL_MAKE_QVA(LCA4_PCI_CONFIG_BASE_PHYSICAL)) + +#if !defined(AXP_FIRMWARE) + + +// +// DMA Window Values. +// +// The LCA4 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 _LCA4_WINDOW_NUMBER{ + Lca4IsaWindow, + Lca4MasterWindow +} LCA4_WINDOW_NUMBER, *PLCA4_WINDOW_NUMBER; + +// +// Define LCA4 Window Control routines. +// + +VOID +HalpLca4InitializeSfwWindow( + PWINDOW_CONTROL_REGISTERS WindowRegisters, + LCA4_WINDOW_NUMBER WindowNumber + ); + +VOID +HalpLca4ProgramDmaWindow( + PWINDOW_CONTROL_REGISTERS WindowRegisters, + PVOID MapRegisterBase + ); + + +// +// 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 ) \ + HalpLca4InitializeSfwWindow( (WR), Lca4IsaWindow ); + + +// +// VOID +// INITIALIZE_MASTER_DMA_CONTROL( +// PWINDOW_CONTROL_REGISTERS WindowRegisters +// ) +// +// Routine Description: +// +// Initialize the DMA Control software window registers for the Master +// DMA window. +// +// Arguments: +// +// WindowRegisters - Supplies a pointer to the software window control. +// +// Return Value: +// +// None. +// + +#define INITIALIZE_MASTER_DMA_CONTROL( WR ) \ + HalpLca4InitializeSfwWindow( (WR), Lca4MasterWindow ); + + +// +// 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 ) \ + HalpLca4ProgramDmaWindow( (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 ) \ + WRITE_IOC_REGISTER( \ + ((PWINDOW_CONTROL_REGISTERS)WR)->WindowTbiaRegister, 0 ); + + +// +// 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; + +// +// Define the per-processor data structures allocated in the PCR +// for each LCA4 processor. +// + +typedef struct _LCA4_PCR{ + ULONGLONG HalpCycleCount; // 64-bit per-processor cycle count + EV4ProfileCount ProfileCount; // Profile counter state, do not move + EV4IrqStatus IrqStatusTable[MaximumIrq]; // Irq status table +} LCA4_PCR, *PLCA4_PCR; + +#define HAL_PCR ( (PLCA4_PCR)(&(PCR->HalReserved)) ) + +#endif //!AXP_FIRMWARE + + +// +// Define LCA4-specific function prototypes. +// + +ULONG +HalpDetermineLca4Revision( + VOID + ); + +VOID +HalpLca4MapAddressSpaces( + VOID + ); + +ULONGLONG +HalpLca4IocTbTagPhysical( + VOID + ); + +ULONGLONG +HalpLca4PciIntAckPhysical( + VOID + ); + +ULONGLONG +HalpLca4PciIoPhysical( + VOID + ); + +ULONGLONG +HalpLca4PciDensePhysical( + VOID + ); + +ULONG +HalpLca4Revision( + VOID + ); + +VOID +WRITE_MEMC_REGISTER( + IN PVOID RegisterOffset, + IN ULONGLONG Value + ); + +ULONGLONG +READ_MEMC_REGISTER( + IN PVOID RegisterOffset + ); + +VOID +WRITE_IOC_REGISTER( + IN PVOID RegisterQva, + IN ULONGLONG Value + ); + +ULONGLONG +READ_IOC_REGISTER( + IN PVOID RegisterQva + ); + +VOID +HalpClearAllErrors( + IN BOOLEAN EnableCorrectableErrors + ); + + + +// +// Define primary (and only) CPU for an LCA system +// + +#define HAL_PRIMARY_PROCESSOR (0) +#define HAL_MAXIMUM_PROCESSOR (0) + +#endif //!_LANGUAGE_ASSEMBLY + +#endif //_LCA4H_ + diff --git a/private/ntos/nthals/halalpha/lca4err.c b/private/ntos/nthals/halalpha/lca4err.c new file mode 100644 index 000000000..edf050f1e --- /dev/null +++ b/private/ntos/nthals/halalpha/lca4err.c @@ -0,0 +1,1153 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + lca4err.c + +Abstract: + + This module implements error handling (machine checks and error + interrupts) for machines based on the DECchip 21066 + microprocessor. + +Author: + + Joe Notarangelo 8-Feb-1994 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "halp.h" +#include "axp21066.h" +#include "lca4.h" +#include "stdio.h" + +// +// Declare the extern variable UncorrectableError declared in +// inithal.c. +// +extern PERROR_FRAME PUncorrectableError; + +// +// MAX_RETRYABLE_ERRORS is the number of times to retry machine checks before +// just giving up. +// + +#define MAX_RETRYABLE_ERRORS 32 + +// +//jnfix - temporary counts +// + +ULONG CorrectableErrors = 0; +ULONG RetryableErrors = 0; + + +VOID +HalpDisplayLogout21066 ( + IN ESR_21066 Esr, + IN IOC_STAT0_21066 IoStat0, + IN PLOGOUT_FRAME_21066 LogoutFrame + ); + +VOID +HalpClearMachineCheck( + VOID + ); + +ULONG +HalpBankError( + ULONG PhysicalAddress, + PLOGOUT_FRAME_21066 LogoutFrame + ); + +//jnfix - should be exported from platform-specific +ULONG +HalpSimmError( + ULONG PhysicalAddress, + PLOGOUT_FRAME_21066 LogoutFrame + ); + + +VOID +HalpClearAllErrors( + IN BOOLEAN SignalMemoryCorrectables + ) +/*++ + +Routine Description: + + This routine clears all of the error bits in the LCA4 memory + controller and I/O controller. + +Arguments: + + SignalMemoryCorrectables - Supplies a boolean value which specifies + if correctable error reporting should be + enabled in the memory controller. + +Return Value: + + None. + +--*/ +{ + + ESR_21066 ErrorStatus; + IOC_STAT0_21066 IoStat0; + + // + // The error status bits of the ESR are all write one to clear. + // Clear the value and then set all of the error bits. Then set + // correctable enable according to specified input. + // + + ErrorStatus.all.QuadPart = (ULONGLONG)0; + + ErrorStatus.Eav = 1; + ErrorStatus.Cee = 1; + ErrorStatus.Uee = 1; + ErrorStatus.Cte = 1; + ErrorStatus.Mse = 1; + ErrorStatus.Mhe = 1; + ErrorStatus.Nxm = 1; + + if( SignalMemoryCorrectables == TRUE ){ + ErrorStatus.Ice = 0; + } else { + ErrorStatus.Ice = 1; + } + + WRITE_MEMC_REGISTER( &((PLCA4_MEMC_CSRS)(0))->ErrorStatus, + ErrorStatus.all.QuadPart ); + + // + // The ERR and LOST bits of the IO_STAT0 are write one to clear. + // + + IoStat0.all.QuadPart = (ULONGLONG)0; + + IoStat0.Err = 1; + IoStat0.Lost = 1; + + WRITE_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0, + IoStat0.all.QuadPart ); + + return; + +} + +VOID +HalpBuildLCAUncorrectableErrorFrame( + VOID + ) +{ + PPROCESSOR_LCA_UNCORRECTABLE LcaUncorrerr = NULL; + PEXTENDED_ERROR PExtErr; + EAR_21066 Ear; + + if(PUncorrectableError){ + LcaUncorrerr = (PPROCESSOR_LCA_UNCORRECTABLE) + PUncorrectableError->UncorrectableFrame.RawProcessorInformation; + + // + // first fill in some generic processor Information. + // For the Current (Reporting) Processor. + // + HalpGetProcessorInfo( + &PUncorrectableError->UncorrectableFrame.ReportingProcessor); + PUncorrectableError-> + UncorrectableFrame.Flags.ProcessorInformationValid = 1; + + + PExtErr = &PUncorrectableError->UncorrectableFrame.ErrorInformation; + } + + if(LcaUncorrerr) { + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + sprintf(PUncorrectableError->UncorrectableFrame.ErrorString, + "Uncorrectable Error From " + "LCA4 Detected"); + LcaUncorrerr->IocStat0 = (ULONGLONG) + READ_IOC_REGISTER(&((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0); + + LcaUncorrerr->IocStat1 = (ULONGLONG) + READ_IOC_REGISTER(&((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat1); + + LcaUncorrerr->Esr = (ULONGLONG) + READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->ErrorStatus); + + Ear.all.QuadPart = LcaUncorrerr->Ear = (ULONGLONG) + READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->ErrorAddress); + + PUncorrectableError->UncorrectableFrame.Flags.PhysicalAddressValid = 1; + PUncorrectableError->UncorrectableFrame.PhysicalAddress = + Ear.ErrorAddress; + + LcaUncorrerr->BankConfig0 = + READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankConfiguration0); + + LcaUncorrerr->BankConfig1 = + READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankConfiguration1); + + LcaUncorrerr->BankConfig2 = + READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankConfiguration2); + + LcaUncorrerr->BankConfig3 = + READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankConfiguration3); + + LcaUncorrerr->BankMask0 = + READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankMask0); + + LcaUncorrerr->BankMask1 = + READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankMask1); + + LcaUncorrerr->BankMask2 = + READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankMask2); + + LcaUncorrerr->BankMask3 = + READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankMask3); + + LcaUncorrerr->Car = + READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->CacheControl); + + LcaUncorrerr->Gtr = + READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->GlobalTiming); + } +} + + +BOOLEAN +HalMachineCheck ( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN PKTRAP_FRAME TrapFrame + ) +/*++ + +Routine Description: + + This function fields machine checks for 21066-based machines. + + The following errors may be the cause of the machine check: + + (a) Uncorrectable Dcache error + (b) Uncorrectable Load from Memory Controller + (c) Uncorrectable Load from I/O Controller + (d) Non-existent device in PCI Configuration Space (I/O Controller) + (e) Retryable Icache parity error + +Arguments: + + ExceptionRecord - Supplies a pointer to the exception record for the + machine check. Included in the exception information + is the pointer to the logout frame. + + ExceptionFrame - Supplies a pointer to the kernel exception frame. + + TrapFrame - Supplies a pointer to the kernel trap frame. + +Return Value: + + A value of TRUE is returned if the machine check has been + handled by the HAL. If it has been handled then execution may + resume at the faulting address. Otherwise, a value of FALSE + is returned. + + N.B. - When a fatal error is recognized this routine does not + return at all. + +--*/ + +{ + + PMCHK_STATUS MachineCheckStatus; + ESR_21066 ErrorStatus; + IOC_STAT0_21066 IoStat0; + PPROCESSOR_LCA_UNCORRECTABLE LcaUncorrerr = NULL; + + MachineCheckStatus = + (PMCHK_STATUS)&ExceptionRecord->ExceptionInformation[0]; + + // + // Print an error message if a correctable machine check is signalled. + // Correctable machine checks are not possible on the 21066. + // + + if( MachineCheckStatus->Correctable == 1 ){ + +#if DBG + + DbgPrint( "Illegal correctable error for LCA4\n" ); + +#endif //DBG + + } + + // + // If the machine check is retryable then log the error and + // and restart the operation. + // + + if( MachineCheckStatus->Retryable == 1 ){ + + // + // jnfix Log the error, interface undefined. + // + + // + // Increment the number of retryable machine checks. + // + + RetryableErrors += 1; + + +#if (DBG) || (HALDBG) + + DbgPrint( "HAL Retryable Errors = %d\n", RetryableErrors ); + // if( (RetryableErrors % 32) == 0 ){ + // DbgPrint( "HAL Retryable Errors = %d\n", RetryableErrors ); + // } + +#endif //DBG || HALDBG + + + // + // We'll retry MAX_RETRYABLE_ERRORS times and then give up. We + // do this to avoid infinite retry loops. + // + + if( RetryableErrors > MAX_RETRYABLE_ERRORS ){ + + // + // Acknowledge receipt of the retryable machine check. + // + DbgPrint("Got too many Retryable Errors errors\n"); + } + + // + // Clear the machine check in the MCES register. + // + + HalpClearMachineCheck(); + + // + // Attempt to retry the operation. + // + + return TRUE; + + } + + // + // The machine check is uncorrectable according to the processor. + // Read the error registers in the Memory and I/O Controller. + // If the operation was a read to PCI configuration space and no + // device is the error then we will fix up the operation and continue, + // otherwise the machine has taken a fatal error. + // + +//jnfix - code here to check for dcache parity error? + + + ErrorStatus.all.QuadPart = + READ_MEMC_REGISTER( + &((PLCA4_MEMC_CSRS)(0))->ErrorStatus ); + + IoStat0.all.QuadPart = + READ_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0 ); + + // + // If any of the following errors are indicated in the memory controller + // then process a fatal error: + // Uncorrectable Error + // Cache Tag Error + // Multiple Hard Errors + // Non-existent Memory + // + + if( (ErrorStatus.Uee == 1) || + (ErrorStatus.Cte == 1) || + (ErrorStatus.Mhe == 1) || + (ErrorStatus.Nxm == 1) ){ + + goto FatalError; + + } + + // + // Check for a PCI configuration read error. An error is a + // candidate if the I/O controller has signalled an error, there + // are no lost errors and the error was a no device error on the PCI. + // + + if( (IoStat0.Err == 1) && (IoStat0.Code == IocErrorNoDevice) && + (IoStat0.Lost == 0) ){ + + // + // 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 faulting instruction or the instruction + // previous to the faulting instruction must be a load with v0 as + // the destination register. If this condition is met then simply + // update v0 in the register set and return. However, be careful + // not to re-execute the load. + // + // jnfix - add condition to check if Rb contains the superpage + // address for config space? + + ALPHA_INSTRUCTION FaultingInstruction; + BOOLEAN PreviousInstruction = FALSE; + + FaultingInstruction.Long = *(PULONG)((ULONG)TrapFrame->Fir); + if( (FaultingInstruction.Memory.Ra != V0_REG) || + (FaultingInstruction.Memory.Opcode != LDL_OP) ){ + + // + // Faulting instruction did not match, try the previous + // instruction. + // + + PreviousInstruction = TRUE; + + FaultingInstruction.Long = *(PULONG)((ULONG)TrapFrame->Fir - 4); + if( (FaultingInstruction.Memory.Ra != V0_REG) || + (FaultingInstruction.Memory.Opcode != LDL_OP) ){ + + // + // No match, we can't fix this up. + // + + goto FatalError; + } + } + + // + // 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 the machine check condition in the processor. + // + + HalpClearMachineCheck(); + + // + // Clear the error condition in the io controller. + // The Err bit is write one to clear. + // + + IoStat0.all.QuadPart = (ULONGLONG)0; + IoStat0.Err = 1; + WRITE_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0, + IoStat0.all.QuadPart ); + + // + // If the faulting instruction was the load the restart execution + // at the instruction after the load. + // + + if( PreviousInstruction == FALSE ){ + TrapFrame->Fir += 4; + } + + return TRUE; + + } //end if (IoStat0.Err == 1) && (IoStat0.Code == IocErrorNoDevice) ){ + + +// +// The system is not well and cannot continue reliable execution. +// Print some useful messages and shutdown the machine. +// + +FatalError: + + HalpBuildLCAUncorrectableErrorFrame(); + + if(PUncorrectableError){ + LcaUncorrerr = (PPROCESSOR_LCA_UNCORRECTABLE) + PUncorrectableError->UncorrectableFrame.RawProcessorInformation; + + LcaUncorrerr->AboxCtl = (ULONGLONG) + ((PLOGOUT_FRAME_21066) + (ExceptionRecord->ExceptionInformation[1] ))->AboxCtl.all.QuadPart; + + LcaUncorrerr->CStat = (ULONGLONG) + ((PLOGOUT_FRAME_21066) + (ExceptionRecord->ExceptionInformation[1] ))->DcStat.all.QuadPart; + + LcaUncorrerr->MmCsr = (ULONGLONG) + ((PLOGOUT_FRAME_21066) + (ExceptionRecord->ExceptionInformation[1] ))->MmCsr.all.QuadPart; + } + + // + // Display the logout frame. + // + + HalpDisplayLogout21066( + ErrorStatus, + IoStat0, + (PLOGOUT_FRAME_21066)(ExceptionRecord->ExceptionInformation[1]) ); + + // + // + // Bugcheck to dump the rest of the machine state, this will help + // if the machine check is software-related. + // + + KeBugCheckEx( DATA_BUS_ERROR, + (ULONG)MachineCheckStatus->Correctable, + (ULONG)MachineCheckStatus->Retryable, + 0, + (ULONG)PUncorrectableError ); + +} + +VOID +HalpClearMachineCheck( + VOID + ) +/*++ + +Routine Description: + + Clear the machine check which is currently pending. Clearing the + pending machine check bit will allow us to take machine checks in + the future without detecting a double machine check condition. + The machine check pending bit must be cleared in the MCES register + within the PALcode. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + MCES MachineCheckSummary; + + MachineCheckSummary.MachineCheck = 1; + MachineCheckSummary.SystemCorrectable = 0; + MachineCheckSummary.ProcessorCorrectable = 0; + MachineCheckSummary.DisableProcessorCorrectable = 0; + MachineCheckSummary.DisableSystemCorrectable = 0; + MachineCheckSummary.DisableMachineChecks = 0; + + HalpWriteMces( MachineCheckSummary ); + + return; + +} + +#define MAX_ERROR_STRING 100 + +VOID +HalpDisplayLogout21066 ( + IN ESR_21066 Esr, + IN IOC_STAT0_21066 IoStat0, + IN PLOGOUT_FRAME_21066 LogoutFrame + ) +/*++ + +Routine Description: + + This function displays the logout frame for a 21066. + +Arguments: + + Esr - Supplies the value of the memory controller error status register. + + IoStat0 - Supplies the value of the i/o controller status register 0. + + LogoutFrame - Supplies a pointer to the logout frame generated + by the 21066. +Return Value: + + None. + +--*/ + +{ + UCHAR OutBuffer[ MAX_ERROR_STRING ]; + EAR_21066 Ear; + CAR_21066 Car; + IOC_STAT1_21066 IoStat1; + ULONG Index; + PKPRCB Prcb; + extern HalpLogicalToPhysicalProcessor[HAL_MAXIMUM_PROCESSOR+1]; + PCHAR parityErrString = NULL; + PEXTENDED_ERROR exterr; + + + if(PUncorrectableError) { + exterr = &PUncorrectableError->UncorrectableFrame.ErrorInformation; + parityErrString = PUncorrectableError->UncorrectableFrame.ErrorString; + } + + + // + // Capture other useful registers, EAR, CAR, and IO_STAT1. + // + + Ear.all.QuadPart = + READ_MEMC_REGISTER( + &((PLCA4_MEMC_CSRS)(0))->ErrorAddress ); + + Car.all.QuadPart = + READ_MEMC_REGISTER( + &((PLCA4_MEMC_CSRS)(0))->CacheControl ); + + IoStat1.all.QuadPart = + READ_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat1); + + // + // Acquire ownership of the display. This is done here in case we take + // a machine check before the display has been taken away from the HAL. + // When the HAL begins displaying strings after it has lost the + // display ownership then the HAL will be careful not to scroll information + // off of the screen. + // + + HalAcquireDisplayOwnership(NULL); + + // + // Display the machine state via the logout frame. + // + + HalDisplayString( "\nFatal system hardware error.\n\n" ); + + + sprintf( OutBuffer, "MEMC_ESR: %16Lx MEMC_EAR: %16Lx CAR: %16Lx\n", + Esr.all.QuadPart, + Ear.all.QuadPart, + Car.all.QuadPart ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "IO_STAT0: %16Lx IO_STAT1: %16Lx\n", + IoStat0.all.QuadPart, + IoStat1.all.QuadPart ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "ICCSR : %016Lx ABOX_CTL: %016Lx DC_STAT: %016Lx\n", + ICCSR_ALL_21064(LogoutFrame->Iccsr), + ABOXCTL_ALL_21064(LogoutFrame->AboxCtl), + DCSTAT_ALL_21064(LogoutFrame->DcStat) ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "EXC_ADDR : %016Lx VA : %016Lx MM_CSR : %016Lx\n", + LogoutFrame->ExcAddr.QuadPart, + LogoutFrame->Va.QuadPart, + MMCSR_ALL_21064(LogoutFrame->MmCsr) ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "HIRR : %016Lx HIER : %016Lx PS : %016Lx\n", + IRR_ALL_21064(LogoutFrame->Hirr), + IER_ALL_21064(LogoutFrame->Hier), + PS_ALL_21064(LogoutFrame->Ps) ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "PAL_BASE : %016Lx \n", + LogoutFrame->PalBase.QuadPart ); + + HalDisplayString( OutBuffer ); + + sprintf( OutBuffer, "Waiting 15 seconds...\n"); + HalDisplayString( OutBuffer ); + + for( Index=0; Index<1500; Index++) + KeStallExecutionProcessor( 10000 ); // ~15 second delay + + // + // Print out interpretation of the error. + // + + // + // First print the processor on which we saw the error + // + + Prcb = PCR->Prcb; + sprintf( OutBuffer, "Error on processor number: %d\n", + HalpLogicalToPhysicalProcessor[Prcb->Number] ); + HalDisplayString( OutBuffer ); + + // + // If we got a Data Cache Parity Error print a message on screen. + // + + if( DCSTAT_DCPARITY_ERROR_21064(LogoutFrame->DcStat) ){ + + PUncorrectableError->UncorrectableFrame.Flags.AddressSpace = + MEMORY_SPACE; + PUncorrectableError->UncorrectableFrame.Flags. + MemoryErrorSource = PROCESSOR_CACHE; + PUncorrectableError->UncorrectableFrame.Flags. + ExtendedErrorValid = 1; + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + sprintf( parityErrString, + "Data Cache Parity Error.\n"); + HalpGetProcessorInfo(&exterr->CacheError.ProcessorInfo); + + sprintf( OutBuffer, "Data Cache Parity Error.\n" ); + HalDisplayString( OutBuffer ); + } + + // + // Check for uncorrectable error. + // + + if( Esr.Uee == 1 ){ + + if( Esr.Sor == 0 ){ + + // + // Uncorrectable error from cache. + // + PUncorrectableError->UncorrectableFrame.Flags.AddressSpace = + MEMORY_SPACE; + PUncorrectableError->UncorrectableFrame.Flags. + MemoryErrorSource = PROCESSOR_CACHE; + PUncorrectableError->UncorrectableFrame.Flags. + ExtendedErrorValid = 1; + HalpGetProcessorInfo(&exterr->CacheError.ProcessorInfo); + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + + sprintf( parityErrString, + "Uncorrectable error from cache on %s, Tag: 0x%x\n", + Esr.Wre ? "write" : "read", + Car.Tag ); + HalDisplayString( parityErrString ); + + } else { + + // + // Uncorrectable error from memory. + // + PUncorrectableError->UncorrectableFrame.Flags.AddressSpace = + MEMORY_SPACE; + PUncorrectableError->UncorrectableFrame.Flags. + MemoryErrorSource = SYSTEM_MEMORY; + PUncorrectableError->UncorrectableFrame.Flags. + ExtendedErrorValid = 1; + HalpGetProcessorInfo(&exterr->MemoryError.ProcessorInfo); + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + + sprintf( parityErrString, + "Uncorrectable error from memory on %s\n", + Esr.Wre ? "write" : "read" ); + HalDisplayString( parityErrString ); + + PUncorrectableError->UncorrectableFrame.Flags. + PhysicalAddressValid = 1; + PUncorrectableError->UncorrectableFrame.PhysicalAddress = + Ear.ErrorAddress; + + exterr->MemoryError.Flags.MemorySimmValid = 1; + exterr->MemoryError.MemorySimm = + HalpSimmError( Ear.ErrorAddress, LogoutFrame ); + + sprintf( OutBuffer, + "Physical Address: 0x%x, Bank: %d, SIMM: %d\n", + Ear.ErrorAddress, + HalpBankError( Ear.ErrorAddress, LogoutFrame ), + HalpSimmError( Ear.ErrorAddress, LogoutFrame ) ); + HalDisplayString( OutBuffer ); + + } //end if( Esr.Sor == 0 ) + + } //end if( Esr.Uee == 1 ) + + // + // Check for cache tag errors. + // + + if( Esr.Cte == 1 ){ + PUncorrectableError->UncorrectableFrame.Flags.AddressSpace = + MEMORY_SPACE; + PUncorrectableError->UncorrectableFrame.Flags. + MemoryErrorSource = PROCESSOR_CACHE; + PUncorrectableError->UncorrectableFrame.Flags. + ExtendedErrorValid = 1; + HalpGetProcessorInfo(&exterr->CacheError.ProcessorInfo); + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + + + sprintf( parityErrString, + "Cache Tag Error, Tag: 0x%x, Hit: %d\n", + Car.Tag, Car.Hit ); + HalDisplayString( parityErrString ); + + } + + // + // Check for non-existent memory error. + // + + if( Esr.Nxm == 1 ){ + + PUncorrectableError->UncorrectableFrame.Flags.AddressSpace = + MEMORY_SPACE; + PUncorrectableError->UncorrectableFrame.Flags. + MemoryErrorSource = SYSTEM_MEMORY; + PUncorrectableError->UncorrectableFrame.Flags. + ExtendedErrorValid = 1; + HalpGetProcessorInfo(&exterr->MemoryError.ProcessorInfo); + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + + sprintf( parityErrString, + "Non-existent memory accessed\n" ); + sprintf( OutBuffer, + "Non-existent memory accessed, Physical Address: 0x%x.\n", + Ear.ErrorAddress ); + HalDisplayString( OutBuffer ); + + } + + // + // Check for multiple hard errors. + // + + if( Esr.Mhe == 1 ){ + PUncorrectableError->UncorrectableFrame.Flags.AddressSpace = + MEMORY_SPACE; + PUncorrectableError->UncorrectableFrame.Flags. + MemoryErrorSource = SYSTEM_MEMORY; + PUncorrectableError->UncorrectableFrame.Flags. + ExtendedErrorValid = 1; + HalpGetProcessorInfo(&exterr->MemoryError.ProcessorInfo); + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + + sprintf( parityErrString, + "Multiple hard errors detected\n" ); + + sprintf( OutBuffer, + "Multiple hard errors detected.\n" ); + HalDisplayString( OutBuffer ); + + } + + // + // If an I/O Error was pending print the interpretation. + // + + if( IoStat0.Err == 1 ){ + PUncorrectableError->UncorrectableFrame.Flags.AddressSpace = + IO_SPACE; + PUncorrectableError->UncorrectableFrame.Flags. + ExtendedErrorValid = 1; + exterr->IoError.Interface = PCIBus; + exterr->IoError.BusNumber = 0; + exterr->IoError.BusAddress.QuadPart = IoStat1.Address; + PUncorrectableError->UncorrectableFrame.Flags.PhysicalAddressValid = + 1; + PUncorrectableError->UncorrectableFrame.PhysicalAddress = + IoStat1.Address; + PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1; + + + switch( IoStat0.Code ){ + + // + // Retry Limit. + // + + case IocErrorRetryLimit: + sprintf(parityErrString, + "Retry Limit Error, PCI Cmd 0x%x\n", + IoStat0.Cmd ); + + sprintf( OutBuffer, + "Retry Limit Error, PCI Address 0x%x PCI Cmd 0x%x\n", + IoStat1.Address, + IoStat0.Cmd ); + break; + + // + // No device error. + // + + case IocErrorNoDevice: + sprintf(parityErrString, + "No Device Error, PCI Cmd 0x%x\n", + IoStat0.Cmd ); + + + sprintf( OutBuffer, + "No Device Error, PCI Address 0x%x PCI Cmd 0x%x\n", + IoStat1.Address, + IoStat0.Cmd ); + break; + + // + // Bad data parity. + // + + case IocErrorBadDataParity: + sprintf(parityErrString, + "Bad Data Parity Error, PCI Cmd 0x%x\n", + IoStat0.Cmd ); + + + sprintf( OutBuffer, + "Bad Data Parity Error, PCI Address 0x%x PCI Cmd 0x%x\n", + IoStat1.Address, + IoStat0.Cmd ); + break; + + // + // Target abort. + // + + case IocErrorTargetAbort: + sprintf(parityErrString, + "Target Abort, PCI Cmd 0x%x\n", + IoStat0.Cmd ); + + + sprintf( OutBuffer, + "Target Abort, PCI Address 0x%x PCI Cmd 0x%x\n", + IoStat1.Address, + IoStat0.Cmd ); + break; + + // + // Bad address parity. + // + + case IocErrorBadAddressParity: + sprintf(parityErrString, + "Bad Address Parity, PCI Cmd 0x%x\n", + IoStat0.Cmd ); + + + sprintf( OutBuffer, + "Bad Address Parity, PCI Address 0x%x PCI Cmd 0x%x\n", + IoStat1.Address, + IoStat0.Cmd ); + break; + + // + // Page Table Read Error. + // + + case IocErrorPageTableReadError: + sprintf(parityErrString, + "Page Table Read Error, PCI Cmd 0x%x\n", + IoStat0.Cmd ); + + + sprintf( OutBuffer, + "Page Table Read Error, PCI Pfn 0x%x PCI Cmd 0x%x\n", + IoStat0.PageNumber, + IoStat0.Cmd ); + break; + + // + // Invalid page. + // + + case IocErrorInvalidPage: + sprintf(parityErrString, + "Invalid Page Error, PCI Cmd 0x%x\n", + IoStat0.Cmd ); + + + sprintf( OutBuffer, + "Invalid Page Error, PCI Pfn 0x%x PCI Cmd 0x%x\n", + IoStat0.PageNumber, + IoStat0.Cmd ); + break; + + // + // Data error. + // + + case IocErrorDataError: + + sprintf(parityErrString, + "Data Error, PCI Cmd 0x%x\n", + IoStat0.Cmd ); + + sprintf( OutBuffer, + "Data Error, PCI Address 0x%x PCI Cmd 0x%x\n", + IoStat1.Address, + IoStat0.Cmd ); + break; + + // + // Unrecognized error code. + // + + default: + + sprintf(parityErrString, + "Unrecognized I/O Error.\n" ); + + sprintf( OutBuffer, "Unrecognized I/O Error.\n" ); + break; + + } //end switch (IoStat0.Code) + + HalDisplayString( OutBuffer ); + + if( IoStat0.Lost == 1 ){ + sprintf(parityErrString, + "Additional I/O errors were lost.\n" ); + + HalDisplayString( "Additional I/O errors were lost.\n" ); + } + + } //end if( IoStat0.Err == 1 ) + + // + // return to caller + // + + return; + +} + + +ULONG +HalpBankError( + ULONG PhysicalAddress, + PLOGOUT_FRAME_21066 LogoutFrame + ) +/*++ + +Routine Description: + + Return the bank of memory that the physical address fails within. + +Arguments: + + PhysicalAddress - Supplies the physical address to locate. + + LogoutFrame - Supplies a pointer to the logout frame that contains the + bank configuration information. + +Return Value: + + Returns the number of the bank that contains the physical address. + Returns 0xffffffff if the physical address is not contained within any of + the banks. + +--*/ +{ + + ULONG Bank; + + for( Bank=0; Bank < MEMORY_BANKS_21066; Bank++ ){ + + // + // If the bank is valid and the physical address is within the + // bank then we have found the correct bank. + // + + if( (LogoutFrame->BankConfig[Bank].Bav == 1) && + ((PhysicalAddress >> 20) & + (~LogoutFrame->BankMask[Bank].BankAddressMask)) == + LogoutFrame->BankConfig[Bank].BankBase ){ + + return Bank; + + } + + } + + // + // Did not find a bank which contains physical address. + // + + return (0xffffffff); + +} + +//jnfix - this should be move to platform-specific +//jnfix - and made real depending upon how memory is configured +//jnfix - this current code is a simple guess which provides a model + +ULONG +HalpSimmError( + ULONG PhysicalAddress, + PLOGOUT_FRAME_21066 LogoutFrame + ) +/*++ + +Routine Description: + + Return the SIMM number that the physical address fails within. + +Arguments: + + PhysicalAddress - Supplies the physical address to locate. + + LogoutFrame - Supplies a pointer to the logout frame that contains the + bank configuration information. + +Return Value: + + Returns the number of the SIMM that contains the physical address. + Returns 0xffffffffif the physical address is not contained within any of + the SIMMs. + +--*/ +{ + ULONG Bank; + ULONG Simm; + + for( Bank=0; Bank < MEMORY_BANKS_21066; Bank++ ){ + + // + // If the bank is valid and the physical address is within the + // bank then we have found the correct bank. + // + + if( (LogoutFrame->BankConfig[Bank].Bav == 1) && + ((PhysicalAddress >> 20) & + (~LogoutFrame->BankMask[Bank].BankAddressMask)) == + LogoutFrame->BankConfig[Bank].BankBase ){ + + // + // Assume that each bank contains 2 SIMMs and that they are + // numbered 0..N. We need to determine which SIMM within the + // bank. We will guess that the SIMMs are 32-bits wide and + // that the low 32-bits are in the low SIMM while the high + // 32-bits are in the high SIMM. So addresses 0..3 are low + // and 4..7 are high. + // + + Simm = Bank * 2; + if( PhysicalAddress & 4 ) Simm += 1; + return Simm; + + } + + } + + // + // Did not find a bank which contains physical address. + // + + return (0xffffffff); + +} diff --git a/private/ntos/nthals/halalpha/lcaioacc.s b/private/ntos/nthals/halalpha/lcaioacc.s new file mode 100644 index 000000000..8d6f98760 --- /dev/null +++ b/private/ntos/nthals/halalpha/lcaioacc.s @@ -0,0 +1,746 @@ + +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + lcaioacc.s + + +Abstract: + + This module implements the low-level I/O access routines for the + DECchip 21066 microprocessor (a.k.a. Low Cost Alpha or LCA). + + 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. + (We are using the 43-bit superpage mode.) + + +Author: + + Jeff Mcleman (mcleman) 13-Jan-1993 + + +Environment: + + Executes in kernel mode. + +Revision History: + + 9-Mar-1993 - Bruce Butts - replaced hardcoded constants with + IO_BIT_SHIFT, IO_xxxx_LEN, and IO_xxxx_OFFSET + values defined in mrgndef.h. Commented out several + unused defines. + + 3-Mar-1993 - Jeff McLeman - Bring up to rev. + + 28-July-1994 - Sameer Dekate - + + Made a common file alphaio.s for machine independent IO routines. + + +--*/ + + +#include "lca4.h" +#include "halalpha.h" + + + + SBTTL( "Write I/O control register" ) +//++ +// +// VOID +// WRITE_IOC_REGISTER( +// QVA RegisterQva, +// ULONGLONG Value +// ) +// +// Routine Description: +// +// Writes a quadword location to LCA IOC register space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of register to be written. +// Value(a1) - Supplies the quadword to be written. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(WRITE_IOC_REGISTER) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + or t0, t4, t0 // superpage mode + stq a1, (t0) // write the longword + mb // order the write + ret zero, (ra) // return + +2: + stq a1, (a0) // store the longword + ret zero, (ra) // return + + .end WRITE_IOC_REGISTER + + + +#define LCA4_MEMC_BASE_PHYSICAL 0x120000000 + + SBTTL( "Write memory control register" ) +//++ +// +// VOID +// WRITE_MEMC_REGISTER( +// ULONG RegisterOffset, +// ULONGLONG Value +// ) +// +// Routine Description: +// +// Writes a quadword location to LCA MEMC register space. +// +// Arguments: +// +// RegisterOffset(a0) - Supplies the offset of the memory controller +// register within memory controller physical space. +// Value(a1) - Supplies the quadword to be written. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(WRITE_MEMC_REGISTER) + + ldiq t0, LCA4_MEMC_BASE_PHYSICAL // get memory cntlr physical address + + ldiq t4, -0x4000 // create superpage mask + sll t4, 28, t4 // 0xffff fc00 0000 0000 + + bis t0, t4, t0 // get superpage address of mem ctlr + bis t0, a0, t0 // add offset of specified register + + stq a1, (t0) // write the longword + mb // order the write + ret zero, (ra) // return + + .end WRITE_MEMC_REGISTER + + + + SBTTL( "Read I/O control register" ) +//++ +// +// ULONGLONG +// READ_IOC_REGISTER( +// QVA RegisterQva +// ) +// +// Routine Description: +// +// Read a quadword location from LCA IOC register space. +// +// Arguments: +// +// RegisterQva(a0) - Supplies the QVA of register to be read. +// +// Return Value: +// +// v0 - Return the value read from the controller register. +// +//-- + + LEAF_ENTRY(READ_IOC_REGISTER) + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + or t0, t4, t0 // superpage mode + ldq v0, (t0) // read the quadword + + ret zero, (ra) // return + +2: + ldq v0, (a0) // read the quadword + ret zero, (ra) // return + + .end READ_IOC_REGISTER + + + + SBTTL( "Read memory control register" ) +//++ +// +// ULONGLONG +// READ_MEMC_REGISTER( +// ULONG RegisterOffset, +// ) +// +// Routine Description: +// +// Read a quadword location from LCA MEMC register space. +// +// Arguments: +// +// RegisterOffset(a0) - Supplies the offset of the memory controller +// register within memory controller physical space. +// +// Return Value: +// +// v0 - Return the value read from the controller register. +// +//-- + + LEAF_ENTRY(READ_MEMC_REGISTER) + + ldiq t0, LCA4_MEMC_BASE_PHYSICAL // get memory cntlr physical address + + ldiq t4, -0x4000 // create superpage mask + sll t4, 28, t4 // 0xffff fc00 0000 0000 + + bis t0, t4, t0 // get superpage address of mem ctlr + bis t0, a0, t0 // add offset of specified register + + ldq v0, (t0) // read the quadword + ret zero, (ra) // return + + .end READ_MEMC_REGISTER + + +// +// Values and structures used to access configuration space. +// + +// +// Define the QVA for the Configuration Cycle Type register within the +// IOC. +// + +#define IOC_CONFIG_CYCLE_TYPE_QVA (0xac000001) + +// +// Define the configuration routines stack frame. +// + + .struct 0 +CfgRa: .space 8 // return address +CfgA0: .space 8 // saved ConfigurationAddress +CfgA1: .space 8 // saved ConfigurationData + .space 8 // padding for 16 byte alignment +CfgFrameLength: + + +//++ +// +// 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) +// +//-- + + NESTED_ENTRY( READ_CONFIG_UCHAR, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Write the cycle type into the ConfigurationCycleType register in +// the IOC. +// + + stq a0, CfgA0(sp) // save configuration space address + + ldil a0, IOC_CONFIG_CYCLE_TYPE_QVA // address of cycle type register + bsr ra, WRITE_IOC_REGISTER // update the configuration cycle type + +// +// Perform the read from configuration space after restoring the +// configuration space address. +// + + ldq a0, CfgA0(sp) // restore configuration space address + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 0x3, t3 // capture byte lane + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + bis t0, t4, t0 // superpage mode + + bis t0, IO_BYTE_LEN, t0 // or in the byte enables + + ldl v0, (t0) // read the longword + extbl v0, t3, v0 // return the byte from the right lane + // also, consume loaded value to cause + // a pipeline stall +2: // + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + 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 to write. +// +// 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. +// +//-- + + NESTED_ENTRY( WRITE_CONFIG_UCHAR, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Write the cycle type into the ConfigurationCycleType register in +// the IOC. +// + + stq a0, CfgA0(sp) // save configuration space address + stq a1, CfgA1(sp) // save configuration data + + ldil a0, IOC_CONFIG_CYCLE_TYPE_QVA // address of cycle type register + bis a2, zero, a1 // set cycle type + + bsr ra, WRITE_IOC_REGISTER // update the configuration cycle type + +// +// Perform the write to configuration space after restoring the +// configuration space address and data. +// + + ldq a0, CfgA0(sp) // restore configuration space address + ldq a1, CfgA1(sp) // restore configuration data + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 0x3, t3 // capture byte lane + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + bis t0, t4, t0 // superpage mode + + bis t0, IO_BYTE_LEN, t0 // or in the byte length indicator + + insbl a1, t3, t4 // put byte in the appropriate lane + stl t4, (t0) // write the configuration byte + mb // synchronize + +2: // + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + 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 quadword 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) +//-- + + NESTED_ENTRY( READ_CONFIG_USHORT, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Write the cycle type into the ConfigurationCycleType register in +// the IOC. +// + + stq a0, CfgA0(sp) // save configuration space address + + ldil a0, IOC_CONFIG_CYCLE_TYPE_QVA // address of cycle type register + bsr ra, WRITE_IOC_REGISTER // update the configuration cycle type + +// +// Perform the read from configuration space after restoring the +// configuration space address. +// + + ldq a0, CfgA0(sp) // restore configuration space address + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 0x3, t3 // capture word offset + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + bis t0, t4, t0 // superpage mode + + bis t0, IO_WORD_LEN, t0 // or in the byte enables + + ldl v0, (t0) // read the longword + extwl v0, t3, v0 // return word from requested lanes + // also, consume loaded value to cause + // a pipeline stall +2: // + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + ret zero, (ra) // return + + .end READ_CONFIG_USHORT + +//++ +// +// VOID +// WRITE_CONFIG_USHORT( +// ULONG ConfigurationAddress, +// USHORT ConfigurationData, +// ULONG ConfigurationCycleType +// ) +// +// Routine Description: +// +// Write a short to PCI configuration space. +// +// Arguments: +// +// ConfigurationAddress(a0) - Supplies the QVA to write. +// +// 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. +// +//-- + + NESTED_ENTRY( WRITE_CONFIG_USHORT, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Write the cycle type into the ConfigurationCycleType register in +// the IOC. +// + + stq a0, CfgA0(sp) // save configuration space address + stq a1, CfgA1(sp) // save configuration data + + ldil a0, IOC_CONFIG_CYCLE_TYPE_QVA // address of cycle type register + bis a2, zero, a1 // set configuration cycle type + + bsr ra, WRITE_IOC_REGISTER // update the configuration cycle type + +// +// Perform the write to configuration space after restoring the +// configuration space address and data. +// + + ldq a0, CfgA0(sp) // restore configuration space address + ldq a1, CfgA1(sp) // restore configuration data + + and a0, QVA_SELECTORS, t1 // get qva selector bits + and a0, 0x3, t3 // capture word offset + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + bis t0, t4, t0 // superpage mode + + bis t0, IO_WORD_LEN, t0 // or in the byte enables + + inswl a1, t3, t4 // put data to appropriate lane + stl t4, (t0) // write the longword + mb // synchronize +2: // + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + 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 quadword 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) +//-- + + NESTED_ENTRY( READ_CONFIG_ULONG, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Write the cycle type into the ConfigurationCycleType register in +// the IOC. +// + + stq a0, CfgA0(sp) // save configuration space address + + ldil a0, IOC_CONFIG_CYCLE_TYPE_QVA // address of cycle type register + bsr ra, WRITE_IOC_REGISTER // update the configuration cycle type + +// +// Perform the read from configuration space after restoring the +// configuration space address. +// + + ldq a0, CfgA0(sp) // restore configuration space address + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + or t0, t4, t0 // superpage mode + + or t0, IO_LONG_LEN, t0 // or in the byte enables + + ldl v0, (t0) // read the longword + bis v0, zero, t1 // consume loaded value to cause + // a pipeline stall +2: // + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + ret zero, (ra) // return + + .end READ_CONFIG_ULONG + + +//++ +// +// VOID +// WRITE_CONFIG_ULONG( +// ULONG ConfigurationAddress, +// ULONG ConfigurationData, +// ULONG ConfigurationCycleType +// ) +// +// Routine Description: +// +// Write a longword to PCI configuration space. +// +// Arguments: +// +// ConfigurationAddress(a0) - Supplies the QVA to write. +// +// 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. +// +//-- + + NESTED_ENTRY( WRITE_CONFIG_ULONG, CfgFrameLength, zero ) + + lda sp, -CfgFrameLength(sp) // allocate stack frame + stq ra, CfgRa(sp) // save return address + + PROLOGUE_END // end prologue + +// +// Write the cycle type into the ConfigurationCycleType register in +// the IOC. +// + + stq a0, CfgA0(sp) // save configuration space address + stq a1, CfgA1(sp) // save configuration data + + ldil a0, IOC_CONFIG_CYCLE_TYPE_QVA // address of cycle type register + bis a2, zero, a1 // set configuration cycle type + + bsr ra, WRITE_IOC_REGISTER // update the configuration cycle type + +// +// Perform the write to configuration space after restoring the +// configuration space address and data. +// + + ldq a0, CfgA0(sp) // restore configuration space address + ldq a1, CfgA1(sp) // restore configuration data + + and a0, QVA_SELECTORS, t1 // get qva selector bits + xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors + bne t1, 2f // 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 // + ldiq t4, -0x4000 // + sll t4, 28, t4 // + bis t0, t4, t0 // superpage mode + + bis t0, IO_LONG_LEN, t0 // or in the byte enables + + stl a1, (t0) // write the longword + mb // synchronize +2: // + ldq ra, CfgRa(sp) // restore return address + lda sp, CfgFrameLength(sp) // deallocate stack frame + ret zero, (ra) // return + + .end WRITE_CONFIG_ULONG diff --git a/private/ntos/nthals/halalpha/memory.c b/private/ntos/nthals/halalpha/memory.c new file mode 100644 index 000000000..306b9be61 --- /dev/null +++ b/private/ntos/nthals/halalpha/memory.c @@ -0,0 +1,575 @@ +/*++ + +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + memory.c + +Abstract: + + Provides routines to allow tha HAL to map physical memory + +Author: + + Jeff McLeman (DEC) 11-June-1992 + +Revision History: + + Joe Notarangelo 20-Oct-1993 + - Fix bug where physical address was rounded up without referencing + AlignmentOffset, resulting in an incorrect physical address + - Remove magic numbers + - Create a routine to dump all of the descriptors to the debugger + +Environment: + + Phase 0 initialization only + +--*/ + +#include "halp.h" + +#define __1KB (1024) + +MEMORY_ALLOCATION_DESCRIPTOR HalpExtraAllocationDescriptor; + + + +ULONG +HalpAllocPhysicalMemory( + IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN ULONG MaxPhysicalAddress, + IN ULONG NoPages, + IN BOOLEAN AlignOn64k + ) +/*++ + +Routine Description: + + Carves out N pages of physical memory from the memory descriptor + list in the desired location. This function is to be called only + during phase zero initialization. (ie, before the kernel's memory + management system is running) + +Arguments: + + LoaderBlock - Supplies a pointer to the loader parameter block which + contains the system memory descriptors. + + MaxPhysicalAddress - Supplies the maximum address below which the memory + must be allocated. + + NoPages - Supplies the number of pages to allocate. + + AlignOn64k - Supplies a boolean that specifies if the requested memory + allocation must start on a 64K boundary. + +Return Value: + + The pyhsical address or NULL if the memory could not be obtained. + +--*/ +{ + ULONG AlignmentMask; + ULONG AlignmentOffset; + PMEMORY_ALLOCATION_DESCRIPTOR BestFitDescriptor; + ULONG BestFitAlignmentOffset; + PMEMORY_ALLOCATION_DESCRIPTOR Descriptor; + PLIST_ENTRY NextMd; + ULONG MaxPageAddress; + ULONG PhysicalAddress; + + MaxPageAddress = MaxPhysicalAddress >> PAGE_SHIFT; + + AlignmentMask = (__64K >> PAGE_SHIFT) - 1; + + BestFitDescriptor = NULL; + BestFitAlignmentOffset = AlignmentMask + 1; + + // + // Scan the memory allocation descriptors for an eligible descriptor from + // which we can allocate the requested block of memory. + // + + NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; + while (NextMd != &LoaderBlock->MemoryDescriptorListHead) { + Descriptor = CONTAINING_RECORD(NextMd, + MEMORY_ALLOCATION_DESCRIPTOR, + ListEntry); + + if( AlignOn64k ){ + + AlignmentOffset = + ((Descriptor->BasePage + AlignmentMask) & ~AlignmentMask) - + Descriptor->BasePage; + + } else { + + AlignmentOffset = 0; + + } + + // + // Search for a block of memory which is contains a memory chunk + // that is greater than size pages, and has a physical address less + // than MAXIMUM_PHYSICAL_ADDRESS. + // + + if ((Descriptor->MemoryType == LoaderFree || + Descriptor->MemoryType == MemoryFirmwareTemporary) && + (Descriptor->PageCount >= NoPages + AlignmentOffset) && + (Descriptor->BasePage + NoPages + AlignmentOffset < + MaxPageAddress) ) + { + + // + // Check for a perfect fit where we need not split the descriptor + // because AlignmentOffset == 0. No need to search further if + // there is a perfect fit. + // + + if( AlignmentOffset == 0 ){ + BestFitDescriptor = Descriptor; + BestFitAlignmentOffset = AlignmentOffset; + break; + } + + // + // If not a perfect fit check for the best fit so far. + // + + if( AlignmentOffset < BestFitAlignmentOffset ){ + BestFitDescriptor = Descriptor; + BestFitAlignmentOffset = AlignmentOffset; + } + + } + + NextMd = NextMd->Flink; + } + + // + // Verify that we have found an eligible descriptor. + // + + ASSERT( BestFitDescriptor != NULL ); + + if( BestFitDescriptor == NULL ){ + return (ULONG)NULL; + } + + // + // Compute the physical address of the memory block we have found. + // + + PhysicalAddress = (BestFitDescriptor->BasePage + BestFitAlignmentOffset) + << PAGE_SHIFT; + // + // Adjust the memory descriptors to account for the memory we have + // allocated. + // + + if (BestFitAlignmentOffset == 0) { + + BestFitDescriptor->BasePage += NoPages; + BestFitDescriptor->PageCount -= NoPages; + + if (BestFitDescriptor->PageCount == 0) { + + // + // The whole block was allocated, + // Remove the entry from the list completely. + // + + RemoveEntryList(&BestFitDescriptor->ListEntry); + + } + + } else { + + // + // The descriptor will be split into 3 pieces, the beginning + // segment up to our allocation, our allocation, and the trailing + // segment. We have one spare memory descriptor to handle this + // case, use it if it is not already used otherwise preserve as + // much memory as possible. + // + + if( (BestFitDescriptor->PageCount - NoPages - BestFitAlignmentOffset) + == 0 ){ + + // + // The third segment is empty, use the original descriptor to + // map the first segment. + // + + BestFitDescriptor->PageCount -= NoPages; + + } else { + + if( HalpExtraAllocationDescriptor.PageCount == 0 ){ + + // + // The extra descriptor can be used to map the third segment. + // + + HalpExtraAllocationDescriptor.PageCount = + BestFitDescriptor->PageCount - NoPages - + BestFitAlignmentOffset; + + HalpExtraAllocationDescriptor.BasePage = + BestFitDescriptor->BasePage + NoPages + + BestFitAlignmentOffset; + + HalpExtraAllocationDescriptor.MemoryType = MemoryFree; + + InsertTailList( + &BestFitDescriptor->ListEntry, + &HalpExtraAllocationDescriptor.ListEntry ); + + // + // Use the original descriptor to map the first segment. + // + + BestFitDescriptor->PageCount = BestFitAlignmentOffset; + + } else { + + // + // We need to split the original descriptor into 3 segments + // but we've already used the spare descriptor. Use the + // original descriptor to map the largest segment. + // + + ULONG WastedPages; + + if( (BestFitDescriptor->PageCount - BestFitAlignmentOffset - + NoPages) > BestFitAlignmentOffset ){ + + WastedPages = BestFitAlignmentOffset; + + // + // Map the third segment using the original descriptor. + // + + BestFitDescriptor->BasePage += BestFitAlignmentOffset + + NoPages; + BestFitDescriptor->PageCount -= BestFitAlignmentOffset + + NoPages; + + } else { + + WastedPages = BestFitDescriptor->PageCount - + BestFitAlignmentOffset - NoPages; + + // + // Map the first segment using the original descriptor. + // + + BestFitDescriptor->PageCount = BestFitAlignmentOffset; + + } //end if( (BestFitDescriptor->PageCount - BestFitAlignm ... + + // + // Report that we have had to waste pages. + // + + DbgPrint( "HalpAllocPhysicalMemory: wasting %d pages\n", + WastedPages ); + + } //end if( HalpExtraAllocationDescriptor.PageCount == 0 ) + + } //end if( (BestFitDescriptor->PageCount - NoPages - BestFitAlign ... + + } //end if (BestFitAlignmentOffset == 0) + + + return PhysicalAddress; +} + +ULONGLONG +HalpGetMemorySize( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) +/*++ + +Routine Description: + + Computes the size of the memory from the descriptor list. + +Arguments: + + LoaderBlock - Supplies a pointer to the loader parameter block. + + +Return Value: + + Size of Memory in Bytes. + +--*/ +{ + PMEMORY_ALLOCATION_DESCRIPTOR Descriptor; + PLIST_ENTRY NextMd; + ULONG PageCounts = 0; + + // + // Scan the memory allocation descriptors and + // compute the Total pagecount + // + + NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; + while (NextMd != &LoaderBlock->MemoryDescriptorListHead) { + + Descriptor = CONTAINING_RECORD(NextMd, + MEMORY_ALLOCATION_DESCRIPTOR, + ListEntry); + + // + // ignore bad memory descriptors. + // + if(Descriptor->MemoryType != LoaderBad){ + PageCounts += Descriptor->PageCount; + } + + + NextMd = NextMd->Flink; + } + + return (PageCounts << PAGE_SHIFT) ; + +} + +TYPE_OF_MEMORY +HalpGetMemoryType ( + IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN ULONG PageAddress, + OUT PULONG EndPageAddressInDesc + ) + +/*++ + +Routine Description: + + This routine checks to see how the specified address is mapped. + +Arguments: + + LoaderBlock - Supplies a pointer to the loader parameter block. + + PageAddress - The page address of memory to probe. + +Return Value: + + The memory type of the specified address, if it is mapped. If the + address is not mapped, then LoaderMaximum is returned. + +--*/ + +{ + PMEMORY_ALLOCATION_DESCRIPTOR Descriptor; + PLIST_ENTRY NextMd; + ULONG PageCounts = 0; + TYPE_OF_MEMORY MemoryType = LoaderMaximum; + + NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; + while (NextMd != &LoaderBlock->MemoryDescriptorListHead) { + + Descriptor = CONTAINING_RECORD(NextMd, + MEMORY_ALLOCATION_DESCRIPTOR, + ListEntry); + + if ((PageAddress >= Descriptor->BasePage) && + (PageAddress < + Descriptor->BasePage + Descriptor->PageCount)) { + + MemoryType = Descriptor->MemoryType; + *EndPageAddressInDesc = Descriptor->BasePage + + Descriptor->PageCount - 1; + break; // we found the descriptor. + } + + NextMd = NextMd->Flink; + } + return MemoryType; +} + + +ULONGLONG +HalpGetContiguousMemorySize( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) +/*++ + +Routine Description: + + Computes the size of initial contiguous memory from the + descriptor list. Contiguous memory means, that there is + no hole or Bad memory in this range. + +Arguments: + + LoaderBlock - Supplies a pointer to the loader parameter block. + + +Return Value: + + Size of Memory in Bytes. + +--*/ +{ + PMEMORY_ALLOCATION_DESCRIPTOR Descriptor; + PLIST_ENTRY NextMd; + ULONG PageCounts = 0; + TYPE_OF_MEMORY MemoryType; + ULONG EndPageAddressInDesc = 0; + + // + // Start from Page Address 0 and go until we hit a page + // with no descriptor or Bad Descriptor. + // + + MemoryType = HalpGetMemoryType(LoaderBlock, + PageCounts, + &EndPageAddressInDesc + ); + while(MemoryType != LoaderMaximum && MemoryType != LoaderBad){ + PageCounts = EndPageAddressInDesc + 1; + MemoryType = HalpGetMemoryType(LoaderBlock, + PageCounts, + &EndPageAddressInDesc + ); + } + + return (PageCounts << PAGE_SHIFT) ; + +} + + +#if HALDBG + + +VOID +HalpDumpMemoryDescriptors( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) +/*++ + +Routine Description: + + Print the contents of the memory descriptors built by the + firmware and OS loader and passed through to the kernel. + This routine is intended as a sanity check that the descriptors + have been prepared properly and that no memory has been wasted. + +Arguments: + + LoaderBlock - Supplies a pointer to the loader parameter block. + + +Return Value: + + None. + +--*/ +{ + PMEMORY_ALLOCATION_DESCRIPTOR Descriptor; + PLIST_ENTRY NextMd; + ULONG PageCounts[LoaderMaximum]; + PCHAR MemoryTypeStrings[] = { + "ExceptionBlock", + "SystemBlock", + "Free", + "Bad", + "LoadedProgram", + "FirmwareTemporary", + "FirmwarePermanent", + "OsloaderHeap", + "OsloaderStack", + "SystemCode", + "HalCode", + "BootDriver", + "ConsoleInDriver", + "ConsoleOutDriver", + "StartupDpcStack", + "StartupKernelStack", + "StartupPanicStack", + "StartupPcrPage", + "StartupPdrPage", + "RegistryData", + "MemoryData", + "NlsData", + "SpecialMemory" + }; + ULONG i; + + // + // Clear the summary information structure. + // + + RtlZeroMemory( PageCounts, sizeof(ULONG) * LoaderMaximum ); + + // + // Scan the memory allocation descriptors print each descriptor and + // collect summary information. + // + + NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; + while (NextMd != &LoaderBlock->MemoryDescriptorListHead) { + + Descriptor = CONTAINING_RECORD(NextMd, + MEMORY_ALLOCATION_DESCRIPTOR, + ListEntry); + + if( (Descriptor->MemoryType >= LoaderExceptionBlock) && + (Descriptor->MemoryType < LoaderMaximum) ) + { + + PageCounts[Descriptor->MemoryType] += Descriptor->PageCount; + DbgPrint( "%08x: %08x Type = %s\n", + (Descriptor->BasePage << PAGE_SHIFT) | KSEG0_BASE, + ( ( (Descriptor->BasePage + Descriptor->PageCount) + << PAGE_SHIFT) - 1) | KSEG0_BASE, + MemoryTypeStrings[Descriptor->MemoryType] ); + + + } else { + + DbgPrint( "%08x: %08x Unrecognized Memory Type = %x\n", + (Descriptor->BasePage << PAGE_SHIFT) | KSEG0_BASE, + ( ( (Descriptor->BasePage + Descriptor->PageCount) + << PAGE_SHIFT) - 1) | KSEG0_BASE, + Descriptor->MemoryType ); + + DbgPrint( "Unrecognized memory type\n" ); + + } + + NextMd = NextMd->Flink; + } + + + // + // Print the summary information. + // + + for( i=LoaderExceptionBlock; i= 'a') && (*String <= 'z') ? + (*String - 'a' + 'A') : *String) ) { + break; + } + + String++; + Index++; + } + + if ( Index == EnvironmentLength ) + return ENOENT; + + // + // Check to see if we're at the end of the string and the variable, + // which means a match. + // + + Char = HalpGetNVRamUchar(EnvironmentOffset + Index); + if ((*String == 0) && (Char == '=')) { + *ValueIndex = EnvironmentOffset + ++Index; + return ESUCCESS; + } + + // + // Move index to the start of the next variable. + // + + do { + Char = HalpGetNVRamUchar(EnvironmentOffset + Index++); + + if (Index >= EnvironmentLength) { + return ENOENT; + } + + } while (Char != 0); + + } +} + +ARC_STATUS +HalGetEnvironmentVariable ( + IN PCHAR Variable, + IN USHORT length, + OUT PCHAR Buffer + ) + +/*++ + +Routine Description: + + This routine searches (not case sensitive) the non-volatile ram for + Variable, and if found returns a pointer to a zero terminated string that + contains the value, otherwise a NULL pointer is returned. + + +Arguments: + + Variable - Supplies a zero terminated string containing an environment + variable. + Length - Supplies the length of the value buffer in bytes + + Buffer - Supplies a pointer to a buffer that will recieve the + environment variable. + +Return Value: + + ESUCCESS - Buffer contains the zero terminated string value of Variable. + ENOENT - The variable doesn't exist in the environment. + ENOMEM - The variable exists, but the value is longer than Length. + +--*/ + +{ + ULONG NvChars; + ULONG VariableIndex; + ULONG ValueIndex; + ULONG Index; + ARC_STATUS Status; + + // + // If checksum is wrong, or the variable can't be found, return NULL. + // + + if ((!HalpIsNVRamRegion0Valid()) || + (HalpFindEnvironmentVariable(Variable, + &VariableIndex, + &ValueIndex) != ESUCCESS)) { + Status = ENOENT; + } else { + + // + // Copy value to an output string, break on zero terminator + // or string max. + // + + NvChars = ValueIndex; + for ( Index = 0 ; Index < length ; Index += 1 ) { + if ( (*Buffer++ = HalpGetNVRamUchar(NvChars++)) == 0 ) { + break; + } + } + + if (Index == length) { + Status = ENOMEM; + } else { + Status = ESUCCESS; + } + } + + return Status; +} + + +ARC_STATUS +HalSetEnvironmentVariable ( + IN PCHAR Variable, + IN PCHAR Value + ) + +/*++ + +Routine Description: + + This routine sets Variable (not case sensitive) to Value. + +Arguments: + + Variable - Supplies a zero terminated string containing an environment + variable. + + Value - Supplies a zero terminated string containing an environment + variable value. + +Return Value: + + ESUCCESS - The set completed successfully + ENOSPC - No space in NVRAM for set operation. + EIO - Invalid Checksum. + +--*/ + +{ + ULONG EnvironmentOffset; + ULONG EnvironmentLength; + ULONG VariableIndex; + ULONG ValueIndex; + ULONG TopOfEnvironment; + PCHAR String; + ULONG NvChars; + LONG Count; + CHAR Char; + + // + // If checksum is wrong, return EIO; + // + + if (!HalpIsNVRamRegion0Valid()) { + return EIO; + } + + // + // Get the offset and length of the environment in NVRAM. + // + + EnvironmentOffset = HalpGetNVRamEnvironmentOffset(); + EnvironmentLength = HalpGetNVRamEnvironmentLength(); + +// +//smjfix - examine the boundary condition where the environment space +// is exactly filled. + + // + // Determine the top of the environment space by looking for the first + // non-null character from the top. + // + + TopOfEnvironment = EnvironmentOffset + EnvironmentLength - 1; + + do { + Char = HalpGetNVRamUchar(TopOfEnvironment); + + } while ( Char == 0 && (--TopOfEnvironment > EnvironmentOffset) ); + + // + // Adjust TopOfEnvironment to the first new character, unless environment + // space is empty, or the environment is exactly full. In the latter + // case, the new value MUST fit into the space taken by the old. + // + + if (TopOfEnvironment != EnvironmentOffset && + TopOfEnvironment < EnvironmentOffset + EnvironmentLength - 2) { + TopOfEnvironment += 2; + } + + // + // Handle the case where the content of the NVRAM has been corrupted + // such that the last character in the environment is non-zero. + // + + Count = (EnvironmentOffset + EnvironmentLength - 1) - TopOfEnvironment; + if (Count < 0) { + return ENOSPC; + } + + + // + // Check to see if the variable already has a value. + // + + if (HalpFindEnvironmentVariable(Variable, &VariableIndex, &ValueIndex) + == ESUCCESS) { + ULONG SizeOfValue = strlen(Value); + + if (SizeOfValue == HalpGetNVRamStringLength(ValueIndex)) { + + // + // Overwrite the current variable in place. + // + + HalpMoveMemoryToNVRam(ValueIndex, Value, SizeOfValue); + + // + // Suppress the append of the variable to the end of the + // environment variable data. + // + + *Value = 0; + + } else { + + // + // Count free space, starting with the free area at the top and + // adding the old variable value. + // + + for ( NvChars = ValueIndex; + NvChars <= TopOfEnvironment; + NvChars++ ) { + + Char = HalpGetNVRamUchar(NvChars); + if ( Char == 0 ) + break; + Count++; + } + + // + // Determine if free area is large enough to handle new value, if + // not return error. + // + + for ( String = Value ; *String != 0 ; String++ ) { + if (Count-- == 0) { + return ENOSPC; + } + } + + // + // Move ValueIndex to the end of the value and compress strings. + // + + do { + Char = HalpGetNVRamUchar(ValueIndex++); + } while( Char != 0 ); + + Count = TopOfEnvironment - ValueIndex; + + HalpMoveNVRamToNVRam(VariableIndex, ValueIndex, Count); + + // + // Adjust new top of environment. + // + + TopOfEnvironment = VariableIndex+Count; + + // + // Zero to the end. + // + + Count = EnvironmentOffset + EnvironmentLength - TopOfEnvironment; + Char = 0; + while ( Count -- ) { + HalpSetNVRamUchar(TopOfEnvironment + Count, Char); + } + } + + } else { + + // + // Variable is new. + // + + // + // Determine if free area is large enough to handle new value, if not + // return error. + // + + // + // From the length of free space subtract new variable's length, + // Value's length and 2 chars, one for the '=' sign and one of the + // null terminator. + // + + Count -= ( strlen(Variable) + strlen(Value) + 2 ); + + // + // Check if there is space to fit the new variable. + // + + if (Count < 0) { + return ENOSPC; + } + + } + + // + // If Value is not zero, append the new variable and value. + // + + if (*Value != 0) { + + // + // Write new variable, converting to upper case. + // + while ( *Variable != 0 ) { + + Char = ((*Variable >= 'a') && (*Variable <= 'z') ? + (*Variable - 'a' + 'A') : *Variable); + + HalpSetNVRamUchar(TopOfEnvironment, Char); + + Variable ++; + TopOfEnvironment ++; + } + + // + // Write equal sign. + // + + Char = '='; + HalpSetNVRamUchar(TopOfEnvironment++, Char); + + // + // Write new value. + // + + for ( Count = 0; Value[Count] != 0; Count ++ ) + ; + + HalpMoveMemoryToNVRam(TopOfEnvironment, Value, Count); + + } + + // + // Write the environment variables out to NVRAM and checksum it. + // + + if (HalpSynchronizeNVRamRegion0(TRUE)) { + return ESUCCESS; + } else { + return EIO; + } +} + +#endif // TAGGED_NVRAM diff --git a/private/ntos/nthals/halalpha/nvram.c b/private/ntos/nthals/halalpha/nvram.c new file mode 100644 index 000000000..7bb392148 --- /dev/null +++ b/private/ntos/nthals/halalpha/nvram.c @@ -0,0 +1,1452 @@ +/*++ + +Copyright (c) 1994, 1995 Digital Equipment Corporation + +Module Name: + + nvram.c + +Abstract: + + This module implements the new non-volatile RAM API. The new API + supports a cache interface and is layered on top of the old + Halp*NVRamBuffer() abstraction. + +Author: + + Dave Richards 12-Jan-1995 + +Environment: + + Executes in kernel mode. + +Revision History: + +--*/ + +#include "arccodes.h" +#include "halp.h" +#include "nvram.h" + +// +// Global data structures. +// + +BOOLEAN HalpNVRamCacheIsValid = FALSE; +BOOLEAN HalpNVRamRegion0IsValid; +BOOLEAN HalpNVRamRegion1IsValid; +UCHAR HalpNVRamCache[NVR_LENGTH]; +BOOLEAN HalpNVRamCacheIsDirty; +ULONG HalpNVRamCacheDirtyLo = NVR_LENGTH - 1; +ULONG HalpNVRamCacheDirtyHi = 0; + +BOOLEAN +HalpIsNVRamCacheValid( + VOID + ) +/*++ + +Routine Description: + + This function fills the NVRAM cache (if the current contents are + not valid). + + This function should not be called outside this module. + +Arguments: + + None. + +Return Value: + + A boolean value indicating whether the cache represents the contents + of NVRAM. + +--*/ +{ + ARC_STATUS Status; + + // + // If the NVRAM cache is valid, return success. + // + + if (HalpNVRamCacheIsValid) { + return TRUE; + } + + // + // Read the NVRAM contents into the cache. + // + + Status = HalpReadNVRamBuffer( + HalpNVRamCache, + HalpCMOSRamBase, + NVR_LENGTH + ); + + // + // If we were unable to fill the cache, return failure. + // + + if (Status != ESUCCESS) { + return FALSE; + } + + // + // The cache is valid. + // + + HalpNVRamCacheIsValid = TRUE; + + // + // The cache is clean. + // + + HalpNVRamCacheIsDirty = FALSE; + HalpNVRamCacheDirtyLo = NVR_LENGTH - 1; + HalpNVRamCacheDirtyHi = 0; + + // + // The validity of regions 0 and 1 is not known. + // + + HalpNVRamRegion0IsValid = FALSE; + HalpNVRamRegion1IsValid = FALSE; + + // + // Return success. + // + + return TRUE; +} + +BOOLEAN +HalpSynchronizeNVRamCache( + VOID + ) +/*++ + +Routine Description: + + This function flushes the cache to NVRAM. + + This function should not be called outside this module. + +Arguments: + + None. + +Return Value: + + A boolean value indicating whether the contents of the NVRAM cache + were written to NVRAM. + +--*/ +{ + ULONG Lo; + ULONG Hi; + ARC_STATUS Status; + + // + // If the cache is clean, return success. + // + + if (!HalpNVRamCacheIsDirty) { + return TRUE; + } + + // + // Write the dirty portion of the cache back to NVRAM. + // + + Lo = HalpNVRamCacheDirtyLo; + Hi = HalpNVRamCacheDirtyHi; + + Status = HalpWriteNVRamBuffer( + (UCHAR *)HalpCMOSRamBase + Lo, + &HalpNVRamCache[Lo], + Hi - Lo + 1 + ); + + // + // If we were unable to flush the cache, return failure. + // + + if (Status != ESUCCESS) { + + // + // The cache and NVRAM are no longer synchronized! + // + + HalpNVRamCacheIsValid = FALSE; + + return FALSE; + } + + // + // The cache is valid. + // + + HalpNVRamCacheIsValid = TRUE; + + // + // The cache is clean. + // + + HalpNVRamCacheIsDirty = FALSE; + HalpNVRamCacheDirtyLo = NVR_LENGTH - 1; + HalpNVRamCacheDirtyHi = 0; + + // + // Return success. + // + + return TRUE; +} + +VOID +HalpMarkNVRamCacheDirty( + IN ULONG Offset, + IN ULONG Length + ) +/*++ + +Routine Description: + + This function marks the NVRAM cache region between Offset and + Offset + Length - 1 as dirty. + + This function should not be called outside this module. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + ULONG Lo; + ULONG Hi; + + // + // Compute the new lower and upper bounds. + // + + Lo = Offset; + Hi = Offset + Length - 1; + + if (Lo < HalpNVRamCacheDirtyLo) { + HalpNVRamCacheDirtyLo = Lo; + } + + if (Hi > HalpNVRamCacheDirtyHi) { + HalpNVRamCacheDirtyHi = Hi; + } + + // + // The cache is dirty. + // + + HalpNVRamCacheIsDirty = TRUE; +} + +UCHAR +HalpGetNVRamUchar( + IN ULONG Offset + ) +/*++ + +Routine Description: + + This function reads a byte from the NVRAM cache. + +Arguments: + + The offset in NVRAM. + +Return Value: + + The byte read from the NVRAM cache. + +--*/ +{ + // + // Read a byte. + // + + return HalpNVRamCache[Offset]; +} + +VOID +HalpSetNVRamUchar( + IN ULONG Offset, + IN UCHAR Data + ) +/*++ + +Routine Description: + + This function writes a byte to the NVRAM cache. + +Arguments: + + Offset - The offset in NVRAM. + + Data - The byte written. + +Return Value: + + None. + +--*/ +{ + // + // Write a byte. + // + + HalpNVRamCache[Offset] = Data; + + // + // Mark the cache as dirty. + // + + HalpMarkNVRamCacheDirty(Offset, sizeof (UCHAR)); +} + +USHORT +HalpGetNVRamUshort( + IN ULONG Offset + ) +/*++ + +Routine Description: + + This function reads a word from the NVRAM cache. + +Arguments: + + The offset in NVRAM. + +Return Value: + + The word read from the NVRAM cache. + +--*/ +{ + USHORT Data; + + // + // Read a short. + // + + RtlMoveMemory(&Data, &HalpNVRamCache[Offset], sizeof (USHORT)); + + return Data; +} + +VOID +HalpSetNVRamUshort( + IN ULONG Offset, + IN USHORT Data + ) +/*++ + +Routine Description: + + This function writes a word to the NVRAM cache. + +Arguments: + + Offset - The offset in NVRAM. + + Data - The word written. + +Return Value: + + None. + +--*/ +{ + // + // Write a short. + // + + RtlMoveMemory(&HalpNVRamCache[Offset], &Data, sizeof (USHORT)); + + // + // Mark the cache as dirty. + // + + HalpMarkNVRamCacheDirty(Offset, sizeof (USHORT)); +} + +ULONG +HalpGetNVRamUlong( + IN ULONG Offset + ) +/*++ + +Routine Description: + + This function reads a longword from the NVRAM cache. + +Arguments: + + The offset in NVRAM. + +Return Value: + + The longword read from the NVRAM cache. + +--*/ +{ + ULONG Data; + + // + // Read a long. + // + + RtlMoveMemory(&Data, &HalpNVRamCache[Offset], sizeof (ULONG)); + + return Data; +} + +VOID +HalpSetNVRamUlong( + IN ULONG Offset, + IN ULONG Data + ) +/*++ + +Routine Description: + + This function writes a longword to the NVRAM cache. + +Arguments: + + Offset - The offset in NVRAM. + + Data - The longword written. + +Return Value: + + None. + +--*/ +{ + // + // Write a long. + // + + RtlMoveMemory(&HalpNVRamCache[Offset], &Data, sizeof (ULONG)); + + // + // Mark the cache as dirty. + // + + HalpMarkNVRamCacheDirty(Offset, sizeof (ULONG)); +} + +VOID +HalpMoveMemoryToNVRam( + IN ULONG Offset, + IN PVOID Data, + IN ULONG Length + ) +/*++ + +Routine Description: + + This function copies a region of memory to the NVRAM cache. + +Arguments: + + Offset - The offset in NVRAM (destination). + + Data - A memory pointer (source). + + Length - The length of the region to copy. + +Return Value: + + None. + +--*/ +{ + // + // Move memory to the NVRAM cache. + // + + RtlMoveMemory(&HalpNVRamCache[Offset], Data, Length); + + // + // Mark the cache as dirty. + // + + HalpMarkNVRamCacheDirty(Offset, Length); +} + +VOID +HalpMoveNVRamToMemory( + IN PVOID Data, + IN ULONG Offset, + IN ULONG Length + ) +/*++ + +Routine Description: + + This function copies a portion of the NVRAM cache to memory. + +Arguments: + + Data - A memory pointer (destination). + + Offset - The offset in NVRAM (source). + + Length - The length of the region to copy. + +Return Value: + + None. + +--*/ +{ + // + // Move memory from the NVRAM cache. + // + + RtlMoveMemory(Data, &HalpNVRamCache[Offset], Length); +} + +VOID +HalpMoveNVRamToNVRam( + IN ULONG Destination, + IN ULONG Source, + IN ULONG Length + ) +/*++ + +Routine Description: + + This function copies a one region of the NVRAM cache to another. + +Arguments: + + Destination - An offset in NVRAM. + + Source - An offset in NVRAM. + + Length - The length of the region to copy. + +Return Value: + +--*/ +{ + // + // Move memory within the NVRAM cache. + // + + RtlMoveMemory( + &HalpNVRamCache[Destination], + &HalpNVRamCache[Source], + Length + ); + + // + // Mark the cache as dirty. + // + + HalpMarkNVRamCacheDirty(Destination, Length); +} + +ULONG +HalpGetNVRamStringLength( + IN ULONG Offset + ) +/*++ + +Routine Description: + + This function returns the length of a '\0'-terminated string in + the NVRAM cache. + +Arguments: + + Offset - A pointer to the beginning of the string in NVRAM. + +Return Value: + + An integer value representing the length of the string. + +--*/ +{ + // + // Return the length of a string in the NVRAM cache. + // + + return strlen(&HalpNVRamCache[Offset]); +} + +VOID +HalpMoveMemoryStringToNVRam( + IN ULONG Offset, + IN PCHAR Data + ) +/*++ + +Routine Description: + + This function copies a string to the NVRAM cache. + +Arguments: + + Offset - The offset in NVRAM. + + Data - A pointer to the beginning of the string in memory. + +Return Value: + + None. + +--*/ +{ + ULONG Length; + + // + // Compute the length of the string. + // + + Length = strlen(Data); + + // + // Move string to NVRAM. + // + + HalpMoveMemoryToNVRam(Offset, Data, Length + 1); +} + +VOID +HalpMoveNVRamStringToMemory( + IN PUCHAR Data, + IN ULONG Offset + ) +/*++ + +Routine Description: + + This function copies a string from the NVRAM cache to memory. + +Arguments: + + Data - A pointer in memory. + + Offset - An offset in NVRAM to the string to copy. + +Return Value: + + None. + +--*/ +{ + ULONG Length; + + // + // Compute the length of the string. + // + + Length = HalpGetNVRamStringLength(Offset); + + // + // Move string to memory. + // + + HalpMoveNVRamToMemory(Data, Offset, Length + 1); +} + +VOID +HalpZeroNVRam( + IN ULONG Offset, + IN ULONG Length + ) +/*++ + +Routine Description: + + This function zeroes the contents of a region in the NVRAM cache. + +Arguments: + + Offset - The offset in NVRAM of the region to zero. + + Length - The length of the region to zero. + +Return Value: + +--*/ +{ + // + // Zero the NVRAM cache. + // + + RtlZeroMemory(&HalpNVRamCache[Offset], Length); + + // + // Mark the cache as dirty. + // + + HalpMarkNVRamCacheDirty(Offset, Length); +} + +ULONG +HalpComputeNVRamChecksum( + IN ULONG Offset, + IN ULONG Length + ) +/*++ + +Routine Description: + + This function computes the checksum for a region in the NVRAM cache. + +Arguments: + + Offset - An offset in NVRAM. + + Length - The length of the region to checksum. + +Return Value: + + The 32-bit checksum of the region. + +--*/ +{ + ULONG Checksum; + ULONG Index; + + // + // Compute the checksum. + // + + Checksum = 0; + + for (Index = 0; Index < Length; Index++) { + Checksum = (Checksum << 1) + HalpGetNVRamUchar(Offset++) + + (Checksum >> 31 & 0x1); + } + + return ~Checksum; +} + +BOOLEAN +HalpIsNVRamRegion0Valid( + VOID + ) +/*++ + +Routine Description: + + This function fills the NVRAM cache (if necessary) and ascertains + whether the contents of region 0 of the NVRAM are valid. It verifies + that the signature, version and checksum are valid. + +Arguments: + + None. + +Return Value: + + A boolean value indicating whether the contents of the region are valid. + +--*/ +{ + ULONG Signature; + UCHAR Version; + ULONG Checksum1; + ULONG Checksum2; + + // + // If the contents of the NVRAM cache are invalid, return failure. + // + + if (!HalpIsNVRamCacheValid()) { + return FALSE; + } + + // + // If region 0 is valid, return success. + // + + if (HalpNVRamRegion0IsValid) { + return TRUE; + } + + // + // If the signature is invalid, return failure. + // + + Signature = HalpGetNVRamUlong( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, Signature) + ); + + if (Signature != NVR_REGION0_SIGNATURE) { + return FALSE; + } + + // + // If the version is invalid, return failure. + // + + Version = HalpGetNVRamUchar( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, Version) + ); + + if (Version == 0) { + return FALSE; + } + + // + // If the checksum is invalid, return failure. + // + + Checksum1 = HalpComputeNVRamChecksum( + NVR_REGION0_OFFSET, + FIELD_OFFSET(NVR_REGION0, Checksum) + ); + + Checksum2 = HalpGetNVRamUlong( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, Checksum) + ); + + if (Checksum1 != Checksum2) { + return FALSE; + } + + // + // Region 0 is valid. + // + + HalpNVRamRegion0IsValid = TRUE; + + // + // Return success. + // + + return TRUE; +} + +BOOLEAN +HalpSynchronizeNVRamRegion0( + IN BOOLEAN RecomputeChecksum + ) +/*++ + +Routine Description: + + This function writes the contents of the NVRAM cache region 0 + back to NVRAM and optionally updates the checksum field. + +Arguments: + + RecomputeChecksum - Update the checksum? + +Return Value: + + A boolean value indicating whether the NVRAM was correctly updated. + +--*/ +{ + ULONG Checksum; + + // + // If we are unable to synchronize the NVRAM cache, return failure. + // + + if (!HalpSynchronizeNVRamCache()) { + return FALSE; + } + + // + // If we do not need to re-compute the checksum, return success. + // + + if (!RecomputeChecksum) { + return TRUE; + } + + // + // Re-compute the checksum and store it in NVRAM. + // + + Checksum = HalpComputeNVRamChecksum( + NVR_REGION0_OFFSET, + FIELD_OFFSET(NVR_REGION0, Checksum) + ); + + HalpSetNVRamUlong( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, Checksum), + Checksum + ); + + // + // Synchronize the NVRAM cache. + // + + return HalpSynchronizeNVRamCache(); +} + +BOOLEAN +HalpInitializeNVRamRegion0( + BOOLEAN Synchronize + ) +/*++ + +Routine Description: + + This function initializes the contents of region 0. + +Arguments: + + None. + +Return Value: + + A boolean value indicating whether the NVRAM was properly initialized. + +--*/ +{ + ULONG Checksum; + + // + // Zero the contents of region 0. + // + + HalpZeroNVRam(NVR_REGION0_OFFSET, NVR_REGION0_LENGTH); + + // + // Initialize the signature. + // + + HalpSetNVRamUlong( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, Signature), + NVR_REGION0_SIGNATURE + ); + + // + // Initialize the version. + // + + HalpSetNVRamUchar( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, Version), + NVR_REGION0_VERSION + ); + + // + // Initialize the directory. + // + + HalpSetNVRamUchar( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, DirectoryEntries), + NVR_REGION0_DIR_SIZE + ); + + HalpSetNVRamUshort( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, Directory[NVR_REGION0_DIR_FW_CONFIG]), + (USHORT)FIELD_OFFSET(NVR_REGION0, Opaque[0]) + ); + + HalpSetNVRamUshort( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, Directory[NVR_REGION0_DIR_LANGUAGE]), + FIELD_OFFSET(NVR_REGION0, Opaque[0]) + + NVR_FW_CONFIG_LENGTH + ); + + HalpSetNVRamUshort( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, Directory[NVR_REGION0_DIR_ENVIRONMENT]), + FIELD_OFFSET(NVR_REGION0, Opaque[0]) + + NVR_FW_CONFIG_LENGTH + + NVR_LANGUAGE_LENGTH + ); + + HalpSetNVRamUshort( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, Directory[NVR_REGION0_DIR_END]), + FIELD_OFFSET(NVR_REGION0, Checksum) + ); + + // + // Re-compute the checksum and store it in NVRAM. + // + + Checksum = HalpComputeNVRamChecksum( + NVR_REGION0_OFFSET, + FIELD_OFFSET(NVR_REGION0, Checksum) + ); + + HalpSetNVRamUlong( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, Checksum), + Checksum + ); + + // + // Synchronize the cache and NVRAM. + // + + if (Synchronize) { + return HalpSynchronizeNVRamRegion0(TRUE); + } +} + +ULONG +HalpGetNVRamFwConfigOffset( + VOID + ) +/*++ + +Routine Description: + + This function returns the NVRAM offset of the firmware configuration + section in NVRAM. + +Arguments: + + None. + +Return Value: + + The offset in NVRAM of the firmware configuration section. + +--*/ +{ + // + // Return the firmware configuration offset. + // + + return HalpGetNVRamUshort( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, + Directory[NVR_REGION0_DIR_FW_CONFIG]) + ); +} + +ULONG +HalpGetNVRamFwConfigLength( + VOID + ) +/*++ + +Routine Description: + + This function returns the length of the firmware configuration + section of NVRAM. + +Arguments: + + None. + +Return Value: + + The length of the firmware configuration section. + +--*/ +{ + // + // Return the firmware configuration length. + // + + return HalpGetNVRamUshort( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, + Directory[NVR_REGION0_DIR_FW_CONFIG + 1]) + ) - + HalpGetNVRamUshort( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, + Directory[NVR_REGION0_DIR_FW_CONFIG]) + ); +} + +ULONG +HalpGetNVRamLanguageOffset( + VOID + ) +/*++ + +Routine Description: + + This function returns the NVRAM offset of the language section. + +Arguments: + + None. + +Return Value: + + The NVRAM offset of the language section. + +--*/ +{ + // + // Return the language offset. + // + + return HalpGetNVRamUshort( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, + Directory[NVR_REGION0_DIR_LANGUAGE]) + ); +} + +ULONG +HalpGetNVRamLanguageLength( + VOID + ) +/*++ + +Routine Description: + + This function returns the length of the language section in NVRAM. + +Arguments: + + None. + +Return Value: + + The length of the language section. + +--*/ +{ + // + // Return the language length. + // + + return HalpGetNVRamUshort( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, + Directory[NVR_REGION0_DIR_LANGUAGE + 1]) + ) - + HalpGetNVRamUshort( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, + Directory[NVR_REGION0_DIR_LANGUAGE]) + ); +} + +ULONG +HalpGetNVRamEnvironmentOffset( + VOID + ) +/*++ + +Routine Description: + + This function returns the NVRAM offset of the environment section. + +Arguments: + + None. + +Return Value: + + The NVRAM offset of the environment section. + +--*/ +{ + // + // Return the environment offset; + // + + return HalpGetNVRamUshort( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, + Directory[NVR_REGION0_DIR_ENVIRONMENT]) + ); +} + +ULONG +HalpGetNVRamEnvironmentLength( + VOID + ) +/*++ + +Routine Description: + + This function returns the length of the environment section. + +Arguments: + + None. + +Return Value: + + The length of the environment section in NVRAM. + +--*/ +{ + // + // Return the environment length. + // + + return HalpGetNVRamUshort( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, + Directory[NVR_REGION0_DIR_ENVIRONMENT + 1]) + ) - + HalpGetNVRamUshort( + NVR_REGION0_OFFSET + + FIELD_OFFSET(NVR_REGION0, + Directory[NVR_REGION0_DIR_ENVIRONMENT]) + ); +} + +#if defined(EISA_PLATFORM) + +BOOLEAN +HalpIsNVRamRegion1Valid( + VOID + ) +/*++ + +Routine Description: + + This function fills the NVRAM cache (if necessary) and ascertains + whether the contents of region 1 of the NVRAM are valid. It verifies + that the signature, version and checksum are valid. + +Arguments: + + None. + +Return Value: + + A boolean value indicating whether the contents of the region are valid. + +--*/ +{ + ULONG Signature; + UCHAR Version; + ULONG Checksum1; + ULONG Checksum2; + + // + // If the contents of the NVRAM cache are invalid, return failure. + // + + if (!HalpIsNVRamCacheValid()) { + return FALSE; + } + + // + // If region 1 is valid, return success. + // + + if (HalpNVRamRegion1IsValid) { + return TRUE; + } + + // + // If the signature is invalid, return failure. + // + + Signature = HalpGetNVRamUlong( + NVR_REGION1_OFFSET + + FIELD_OFFSET(NVR_REGION1, Signature) + ); + + if (Signature != NVR_REGION1_SIGNATURE) { + return FALSE; + } + + // + // If the version is invalid, return failure. + // + + Version = HalpGetNVRamUchar( + NVR_REGION1_OFFSET + + FIELD_OFFSET(NVR_REGION1, Version) + ); + + if (Version == 0) { + return FALSE; + } + + // + // If the checksum is invalid, return failure. + // + + Checksum1 = HalpComputeNVRamChecksum( + NVR_REGION1_OFFSET, + FIELD_OFFSET(NVR_REGION1, Checksum) + ); + + Checksum2 = HalpGetNVRamUlong( + NVR_REGION1_OFFSET + + FIELD_OFFSET(NVR_REGION1, Checksum) + ); + + if (Checksum1 != Checksum2) { + return FALSE; + } + + // + // Region 1 is valid. + // + + HalpNVRamRegion1IsValid = TRUE; + + // + // Return success. + // + + return TRUE; +} + +BOOLEAN +HalpSynchronizeNVRamRegion1( + IN BOOLEAN RecomputeChecksum + ) +/*++ + +Routine Description: + + This function writes the contents of the NVRAM cache region 1 + back to NVRAM and optionally updates the checksum field. + +Arguments: + + RecomputeChecksum - Update the checksum? + +Return Value: + + A boolean value indicating whether the NVRAM was correctly updated. + +--*/ +{ + ULONG Checksum; + + // + // If we are unable to synchronize the NVRAM cache, return failure. + // + + if (!HalpSynchronizeNVRamCache()) { + return FALSE; + } + + // + // If we do not need to re-compute the checksum, return success. + // + + if (!RecomputeChecksum) { + return TRUE; + } + + // + // Re-compute the checksum and store it in NVRAM. + // + + Checksum = HalpComputeNVRamChecksum( + NVR_REGION1_OFFSET, + FIELD_OFFSET(NVR_REGION1, Checksum) + ); + + HalpSetNVRamUlong( + NVR_REGION1_OFFSET + + FIELD_OFFSET(NVR_REGION1, Checksum), + Checksum + ); + + // + // Synchronize the NVRAM cache. + // + + return HalpSynchronizeNVRamCache(); +} + +BOOLEAN +HalpInitializeNVRamRegion1( + BOOLEAN Synchronize + ) +/*++ + +Routine Description: + + This function initializes the contents of region 1. + +Arguments: + + None. + +Return Value: + + A boolean value indicating whether the NVRAM was properly initialized. + +--*/ +{ + ULONG Checksum; + + // + // Zero the contents of region 1. + // + + HalpZeroNVRam(NVR_REGION1_OFFSET, NVR_REGION1_LENGTH); + + // + // Initialize the signature. + // + + HalpSetNVRamUlong( + NVR_REGION1_OFFSET + + FIELD_OFFSET(NVR_REGION1, Signature), + NVR_REGION1_SIGNATURE + ); + + // + // Initialize the version. + // + + HalpSetNVRamUchar( + NVR_REGION1_OFFSET + + FIELD_OFFSET(NVR_REGION1, Version), + NVR_REGION1_VERSION + ); + + // + // Re-compute the checksum and store it in NVRAM. + // + + Checksum = HalpComputeNVRamChecksum( + NVR_REGION1_OFFSET, + FIELD_OFFSET(NVR_REGION1, Checksum) + ); + + HalpSetNVRamUlong( + NVR_REGION1_OFFSET + + FIELD_OFFSET(NVR_REGION1, Checksum), + Checksum + ); + + // + // Synchronize the cache and NVRAM. + // + + if (Synchronize) { + return HalpSynchronizeNVRamRegion1(TRUE); + } +} + +#endif // EISA_PLATFORM diff --git a/private/ntos/nthals/halalpha/nvram.h b/private/ntos/nthals/halalpha/nvram.h new file mode 100644 index 000000000..6126a4b38 --- /dev/null +++ b/private/ntos/nthals/halalpha/nvram.h @@ -0,0 +1,215 @@ +/*++ + +Copyright (c) 1994, 1995 Digital Equipment Corporation + +Module Name: + + nvram.h + +Abstract: + + This module declares the NVRAM data structures. + +Author: + + Dave Richards 12-Jan-1995 + +Revision History: + +--*/ + +#ifndef _NVRAM_H_ +#define _NVRAM_H_ + +// +// NVRAM Region 0 definitions. +// + +#define NVR_REGION0_OFFSET FIELD_OFFSET(NVRAM, Region0) +#define NVR_REGION0_LENGTH (3 * 1024) +#define NVR_REGION0_SIGNATURE 0x06201993 +#define NVR_REGION0_VERSION 1 + +// +// NVRAM Region 0 Directory definitions. +// + +#define NVR_REGION0_DIR_FW_CONFIG 0 +#define NVR_REGION0_DIR_LANGUAGE 1 +#define NVR_REGION0_DIR_ENVIRONMENT 2 +#define NVR_REGION0_DIR_END 3 +#define NVR_REGION0_DIR_SIZE 4 + +// +// NVRAM Region 0 structure. +// + +#define NVR_REGION0_OPAQUE_LENGTH \ + NVR_REGION0_LENGTH - \ + (sizeof (ULONG) /* Signature */ + \ + sizeof (UCHAR) /* Version */ + \ + sizeof (UCHAR) /* DirectoryEntries */ + \ + sizeof (USHORT) * NVR_REGION0_DIR_SIZE /* Directory */ + \ + sizeof (ULONG)) /* Checksum */ + +typedef struct { + ULONG Signature; + UCHAR Version; + UCHAR DirectoryEntries; + USHORT Directory[NVR_REGION0_DIR_SIZE]; + UCHAR Opaque[NVR_REGION0_OPAQUE_LENGTH]; + ULONG Checksum; +} NVR_REGION0, *PNVR_REGION0; + +// +// NVRAM Region 0 Section 0 structure. (Firmware configuration) +// + +#define NVR_FW_CONFIG_LENGTH sizeof (NVR_FW_CONFIG) + +typedef struct { + ULONG Monitor; + ULONG Floppy; + ULONG Floppy2; + ULONG KeyboardType; +} NVR_FW_CONFIG, *PNVR_FW_CONFIG; + +// +// NVRAM Region 0 Section 1 structure. (Language configuration) +// + +#define MAXIMUM_LANGUAGE_PATH 128 +#define NVR_LANGUAGE_LENGTH sizeof (NVR_LANGUAGE) + +typedef struct { + CHAR Path[MAXIMUM_LANGUAGE_PATH]; + LONG Id; + LONG Source; + LONG Spare1; + LONG Spare2; +} NVR_LANGUAGE, *PNVR_LANGUAGE; + +// +// NVRAM Region 0 Section 2 definitions. (Environment) +// + +#define MAXIMUM_ENVIRONMENT_VALUE 256 +#define MAX_NUMBER_OF_ENVIRONMENT_VARIABLES 28 + +// +// NVRAM Region 1 definitions. +// + +#define NVR_REGION1_OFFSET FIELD_OFFSET(NVRAM, Region1) +#define NVR_REGION1_LENGTH (3 * 1024) +#define NVR_REGION1_SIGNATURE 0x865D8546 +#define NVR_REGION1_VERSION 1 + +// +// EISA NVRAM Definitions +// + +#if defined(EISA_PLATFORM) + +// +// Defines for Identifier index. +// + +#define NO_CONFIGURATION_IDENTIFIER 0xFFFF + +// +// Defines for the region 1 table sizes. +// + +#define NV_NUMBER_OF_ENTRIES 33 +#define NV_LENGTH_OF_IDENTIFIER 496 +#define LENGTH_OF_EISA_DATA 2032 + +// +// The compressed configuration packet structure used to store configuration +// data in NVRAM. +// + +typedef struct _COMPRESSED_CONFIGURATION_PACKET { + UCHAR Parent; + UCHAR Class; + UCHAR Type; + UCHAR Flags; + ULONG Key; + UCHAR Version; + UCHAR Revision; + USHORT ConfigurationDataLength; + USHORT Identifier; + USHORT ConfigurationData; +} COMPRESSED_CONFIGURATION_PACKET, *PCOMPRESSED_CONFIGURATION_PACKET; + +#endif // EISA_PLATFORM + +// +// Region 1 structure. +// + +typedef struct { + +#if defined(EISA_PLATFORM) + + // + // EISA configuration information. + // + + ULONG Signature; + UCHAR Version; + UCHAR CompressedPacketSize; + UCHAR IdentifierSize; + UCHAR EisaDataSize; + COMPRESSED_CONFIGURATION_PACKET + Packet[NV_NUMBER_OF_ENTRIES]; + UCHAR Identifier[NV_LENGTH_OF_IDENTIFIER]; + UCHAR EisaData[LENGTH_OF_EISA_DATA]; + ULONG Spare; + ULONG Checksum; + +#else + + // + // Reserved for the SRM Console. + // + + UCHAR Opaque[NVR_REGION1_LENGTH]; + +#endif + +} NVR_REGION1, *PNVR_REGION1; + +// +// NVRAM Region 2 definitions. +// + +#define NVR_REGION2_OFFSET FIELD_OFFSET(NVRAM, Region2) +#define NVR_REGION2_LENGTH (2 * 1024) + +// +// NVRAM Region 2 structure. +// + +typedef struct { + UCHAR Opaque[NVR_REGION2_LENGTH]; +} NVR_REGION2, *PNVR_REGION2; + +// +// NVRAM definitions. +// + +#define NVR_LENGTH sizeof (NVRAM) + +// +// NVRAM structure. +// + +typedef struct { + NVR_REGION0 Region0; + NVR_REGION1 Region1; + NVR_REGION2 Region2; +} NVRAM, *PNVRAM; + +#endif diff --git a/private/ntos/nthals/halalpha/pciesc.c b/private/ntos/nthals/halalpha/pciesc.c new file mode 100644 index 000000000..9a54e38ec --- /dev/null +++ b/private/ntos/nthals/halalpha/pciesc.c @@ -0,0 +1,477 @@ +/*++ + +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" + +// +// 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; + + // + // 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; + + returnValue = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[PCRInOffset])( + PCR->InterruptRoutine[PCRInOffset], + TrapFrame + ); + + // + // 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/halalpha/pcip.h b/private/ntos/nthals/halalpha/pcip.h new file mode 100644 index 000000000..8cd3f6cc4 --- /dev/null +++ b/private/ntos/nthals/halalpha/pcip.h @@ -0,0 +1,178 @@ +/*++ BUILD Version: 0000 Increment this if a change has global effects + +Copyright (c) 1994 Microsoft Corporation +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + pcip.h + +Abstract: + + This header file defines the private PCI bus HAL interfaces and + data types. + +Author: + + Eric Rehm (rehm) 14-August-1994 + +Revision History: + + 14-Jul-1994 (rehm) + Original + + 5-Dec-1994 (rehm) + Added DevicePresent bitmap and PlatformSpecificData pointer to PCIBUSDATA + data type. + +--*/ + +#ifndef _PCIPH_ +#define _PCIPH_ + +// +// Hal specific PCI bus structures +// + +#define PCI_CONFIG_TYPE(PciData) ((PciData)->HeaderType & ~PCI_MULTIFUNCTION) + +#define PCI_MAX_BUSSES 256 + +#define PciBitIndex(Dev,Fnc) (Fnc*32 + Dev) + +// +// Define PCI configuration cycle types. +// +typedef enum _PCI_CONFIGURATION_TYPES { + PciConfigTypeInvalid = -1, + PciConfigType0 = 0, + PciConfigType1 = 1 +} PCI_CONFIGURATION_TYPES, *PPCI_CONFIGURATION_TYPES; + +typedef struct _PCI_CFG_CYCLE_BITS { + union { + struct { + ULONG Reserved1:2; + ULONG Reserved2:30; + } bits; // Generic Config Cycle + + struct { + ULONG Reserved1:2; + ULONG RegisterNumber:6; + ULONG FunctionNumber:3; + ULONG Idsel:21; + } bits0; // Type0 Config Cycle + + struct { + ULONG Reserved1:2; + ULONG RegisterNumber:6; + ULONG FunctionNumber:3; + ULONG DeviceNumber:5; + ULONG BusNumber:8; + ULONG Reserved2:7; + ULONG Enable:1; + } bits1; // Type 1 Config Cycle + + ULONG AsULONG; + } u; +} PCI_CFG_CYCLE_BITS, *PPCI_CFG_CYCLE_BITS; + +// +// Define PCI cycle/command types. +// + +typedef enum _PCI_COMMAND_TYPES{ + PciCommandInterruptAcknowledge = 0x0, + PciCommandSpecialCycle = 0x1, + PciCommandIoRead = 0x2, + PciCommandIoWrite = 0x3, + PciCommandMemoryRead = 0x6, + PciCommandMemoryWrite = 0x7, + PciCommandConfigurationRead = 0xa, + PciCommandConfigurationWrite = 0xb, + PciCommandMemoryReadMultiple = 0xc, + PciCommandDualAddressCycle = 0xd, + PciCommandMemoryReadLine = 0xe, + PciCommandMemoryWriteAndInvalidate = 0xf, + MaximumPciCommand +} PCI_COMMAND_TYPES, *PPCI_COMMAND_TYPES; + +// +// PCI platform-specific functions +// + + +PCI_CONFIGURATION_TYPES +HalpPCIConfigCycleType ( + IN PBUS_HANDLER BusHandler + ); + +VOID +HalpPCIConfigAddr ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + PPCI_CFG_CYCLE_BITS pPciAddr + ); + + +// +// Define PCI configuration cycle types. +// + +typedef enum _PCI_TYPE0_CONFIG_TYPE { + PciConfigType0AsIdsel, + PciConfigType0AsDeviceNumber +} PCI_TYPE0_CONFIG_TYPE, *PPCI_TYPE0_CONFIG_TYPE; + + +typedef struct tagPCIPBUSDATA { + + // + // NT Defined PCI data + // + + PCIBUSDATA CommonData; + + // + // Common alpha hal specific data + // + + PVOID ConfigBaseQva; + PCI_TYPE0_CONFIG_TYPE PciType0ConfigType; + ULONG HwBusNumber; + BOOLEAN BusIsAcrossPPB; + + RTL_BITMAP DevicePresent; + ULONG DevicePresentBits[PCI_MAX_DEVICES * PCI_MAX_FUNCTION / 32]; + + ULONG MaxDevice; + + ULONG PPBBusNumber; + PCI_SLOT_NUMBER PPBSlotNumber; + + // + // Platform-specific storage + // + + PVOID PlatformSpecificData; + +} PCIPBUSDATA, *PPCIPBUSDATA; + +// +// The following structure is used to communicate PCI bus information +// between the ARC firmware and HAL. This structure is passed as +// configuration information on the PCI multifunction adapter nodes of the +// ARC configuration tree. +// + +typedef struct _ARC_PCI_CONFIGURATION { + ULONG Version; + ULONG BusNumber; + ULONG HwBusNumber; + BOOLEAN BusIsAcrossPPB; + ULONG DevicePresentBits[PCI_MAX_DEVICES * PCI_MAX_FUNCTION / 32]; +} ARC_PCI_CONFIGURATION, *PARC_PCI_CONFIGURATION; + +#define ARC_PCI_CONFIGURATION_VERSION 1 + +#endif // _PCIPH_ diff --git a/private/ntos/nthals/halalpha/pcisio.c b/private/ntos/nthals/halalpha/pcisio.c new file mode 100644 index 000000000..76021c879 --- /dev/null +++ b/private/ntos/nthals/halalpha/pcisio.c @@ -0,0 +1,483 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation +Copyright (c) 1992, 1993, 1994 Digital Equipment Corporation + +Module Name: + + pic8259.c + +Abstract: + + The module provides the interrupt support for the PCI SIO + programmable interrupt controller. + + +Author: + + Eric Rehm (DEC) 4-Feburary-1994 + +Revision History: + + +--*/ + +#include "halp.h" +#include "eisa.h" + +// +// Import save area for SIO interrupt mask registers. +// + +UCHAR HalpSioInterrupt1Mask; +UCHAR HalpSioInterrupt2Mask; +UCHAR HalpSioInterrupt1Level; +UCHAR HalpSioInterrupt2Level; + +// +// Define the context structure for use by interrupt service routines. +// + +typedef BOOLEAN (*PSECOND_LEVEL_DISPATCH)( + PKINTERRUPT InterruptObject + ); + + +VOID +HalpInitializeSioInterrupts ( + VOID + ) + +/*++ + +Routine Description: + + This routine initializes the standard dual 8259 programmable interrupt + controller. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + UCHAR DataByte; + + // + // Initialize the SIO interrupt controller. There are two cascaded + // interrupt controllers, each of which must initialized with 4 initialize + // 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 iterrupt 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 thrid initialization control word set the controls for slave mode. + // The master ICW3 uses bit position and the slave ICW3 uses a numberic. + // + + 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. + // + + HalpSioInterrupt1Mask = (UCHAR)(~(1 << SLAVE_IRQL_LEVEL)); + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1, + HalpSioInterrupt1Mask + ); + + HalpSioInterrupt2Mask = 0xFF; + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1, + HalpSioInterrupt2Mask + ); + + + // + // Initialize the edge/level register masks to 0 which is the default + // edge sensitive value. + // + + HalpSioInterrupt1Level = 0; + HalpSioInterrupt2Level = 0; + + return; + +} + +VOID +HalpDisableSioInterrupt( + IN ULONG Vector + ) + +/*++ + +Routine Description: + + This function Disables the SIO bus specified SIO bus interrupt. + +Arguments: + + Vector - Supplies the vector of the ESIA interrupt that is Disabled. + +Return Value: + + None. + +--*/ + +{ + + // + // Calculate the SIO interrupt vector. + // + + Vector -= ISA_VECTORS; + + // + // Determine if this vector is for interrupt controller 1 or 2. + // + + if (Vector & 0x08) { + + // + // The interrupt is in controller 2. + // + + Vector &= 0x7; + + HalpSioInterrupt2Mask |= (UCHAR) 1 << Vector; + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1, + HalpSioInterrupt2Mask + ); + + } else { + + // + // The interrupt is in controller 1. + // + + Vector &= 0x7; + + // + // never disable IRQL2, it is the slave interrupt + // + + if (Vector != SLAVE_IRQL_LEVEL) { + HalpSioInterrupt1Mask |= (ULONG) 1 << Vector; + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1, + HalpSioInterrupt1Mask + ); + } + + } + +} + +VOID +HalpEnableSioInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ) + +/*++ + +Routine Description: + + This function enables the SIO bus specified SIO bus interrupt. +Arguments: + + Vector - Supplies the vector of the SIO interrupt that is enabled. + + InterruptMode - Supplies the mode of the interrupt; LevelSensitive or + Latched. + +Return Value: + + None. + +--*/ + +{ + + // + // Calculate the SIO interrupt vector. + // + + Vector -= ISA_VECTORS; + + // + // Determine if this vector is for interrupt controller 1 or 2. + // + + if (Vector & 0x08) { + + // + // The interrupt is in controller 2. + // + + Vector &= 0x7; + + HalpSioInterrupt2Mask &= (UCHAR) ~(1 << Vector); + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1, + HalpSioInterrupt2Mask + ); + + // + // Set the level/edge control register. + // + + if (InterruptMode == LevelSensitive) { + + HalpSioInterrupt2Level |= (UCHAR) (1 << Vector); + + } else { + + HalpSioInterrupt2Level &= (UCHAR) ~(1 << Vector); + + } + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2EdgeLevel, + HalpSioInterrupt2Level + ); + + } else { + + // + // The interrupt is in controller 1. + // + + Vector &= 0x7; + + HalpSioInterrupt1Mask &= (UCHAR) ~(1 << Vector); + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1, + HalpSioInterrupt1Mask + ); + + // + // Set the level/edge control register. + // + + if (InterruptMode == LevelSensitive) { + + HalpSioInterrupt1Level |= (UCHAR) (1 << Vector); + + } else { + + HalpSioInterrupt1Level &= (UCHAR) ~(1 << Vector); + + } + + WRITE_PORT_UCHAR( + &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1EdgeLevel, + HalpSioInterrupt1Level + ); + } + +} + +BOOLEAN +HalpSioDispatch( + VOID + ) +/*++ + +Routine Description: + + This routine is entered as the result of an interrupt being generated + via the vector that is directly connected to an interrupt object that + describes the SIO device interrupts. Its function is to call the second + level interrupt dispatch routine and acknowledge the interrupt at the SIO + controller. + +Arguments: + + None. + +Return Value: + + Returns the value returned from the second level routine. + +--*/ +{ + UCHAR ISAVector; + PKPRCB Prcb; + BOOLEAN returnValue; + USHORT PCRInOffset; + UCHAR Int1Isr; + UCHAR Int2Isr; + PULONG DispatchCode; + PKINTERRUPT InterruptObject; + + // + // Acknowledge the Interrupt controller and receive the returned + // interrupt vector. + // + + ISAVector = READ_PORT_UCHAR(HalpEisaIntAckBase); + + + if ((ISAVector & 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 = ISAVector + ISA_VECTORS; + DispatchCode = (PULONG)PCR->InterruptRoutine[PCRInOffset]; + InterruptObject = CONTAINING_RECORD(DispatchCode, + KINTERRUPT, + DispatchCode); + + returnValue = ((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)(InterruptObject); + + // + // Dismiss the interrupt in the SIO interrupt controllers. + // + + // + // If this is a cascaded interrupt then the interrupt must be dismissed in + // both controlles. + // + + if (ISAVector & 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/halalpha/pcisup.c b/private/ntos/nthals/halalpha/pcisup.c new file mode 100644 index 000000000..34147cc91 --- /dev/null +++ b/private/ntos/nthals/halalpha/pcisup.c @@ -0,0 +1,2453 @@ +/*++ + + +Copyright (c) 1989 Microsoft Corporation +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + pcisup.c + +Abstract: + + Platform-independent PCI bus routines + +Author: + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" + +typedef ULONG (*FncConfigIO) ( + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +typedef struct { + FncConfigIO ConfigRead[3]; + FncConfigIO ConfigWrite[3]; +} CONFIG_HANDLER, *PCONFIG_HANDLER; + + +// +// Define PCI slot validity +// +typedef enum _VALID_SLOT { + InvalidBus = 0, + InvalidSlot, + ValidSlot +} VALID_SLOT; + +// +// Local prototypes for routines supporting PCI bus handler routines +// + +ULONG +HalpGetPCIData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +ULONG +HalpSetPCIData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ); + + +NTSTATUS +HalpAdjustPCIResourceList ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ); + + +NTSTATUS +HalpAssignPCISlotResources ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName OPTIONAL, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN ULONG Slot, + IN OUT PCM_RESOURCE_LIST *pAllocatedResources + ); + +VOID +HalpReadPCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +VOID +HalpWritePCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +VALID_SLOT +HalpValidPCISlot ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot + ); + +VOID +HalpPCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length, + IN FncConfigIO *ConfigIO + ); + +ULONG HalpPCIReadUlong ( + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIReadUchar ( + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIReadUshort ( + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUlong ( + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUchar ( + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUshort ( + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +VOID +HalpPCILine2PinNop ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PPCI_COMMON_CONFIG PciNewData, + IN PPCI_COMMON_CONFIG PciOldData + ); + +VOID +HalpPCIPin2LineNop ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PPCI_COMMON_CONFIG PciData + ); + +#if DBG +BOOLEAN +HalpValidPCIAddr( + IN PBUS_HANDLER BusHandler, + IN PHYSICAL_ADDRESS BAddr, + IN ULONG Length, + IN ULONG AddressSpace + ); +#endif + +// +// Local prototypes of functions that are not built for Alpha AXP firmware +// + +NTSTATUS +HalpAssignPCISlotResources ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName OPTIONAL, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN ULONG Slot, + IN OUT PCM_RESOURCE_LIST *pAllocatedResources + ); + +#if DBG +VOID +HalpTestPci ( + ULONG + ); +#endif + +// +// Pragmas to assign functions to different kinds of pages. +// + +#if !defined(AXP_FIRMWARE) +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpInitializePCIBus) +#pragma alloc_text(INIT,HalpAllocateAndInitPCIBusHandler) +#pragma alloc_text(INIT,HalpRegisterPCIInstallHandler ) +#pragma alloc_text(INIT,HalpDefaultPCIInstallHandler ) +#pragma alloc_text(INIT,HalpDeterminePCIDevicesPresent ) +#pragma alloc_text(PAGE,HalpAssignPCISlotResources) +#pragma alloc_text(PAGE,HalpAdjustPCIResourceList) +#endif // ALLOC_PRAGMA +#endif // !defined(AXP_FIRMWARE) + +#ifdef AXP_FIRMWARE + +#define ExFreePool(PoolData) + +#pragma alloc_text(DISTEXT, HalpInitializePCIBus ) +#pragma alloc_text(DISTEXT, HalpAllocateAndInitPCIBusHandler) +#pragma alloc_text(DISTEXT, HalpRegisterPCIInstallHandler ) +#pragma alloc_text(DISTEXT, HalpDefaultPCIInstallHandler ) +#pragma alloc_text(DISTEXT, HalpDeterminePCIDevicesPresent ) +#pragma alloc_text(DISTEXT, HalpGetPCIData ) +#pragma alloc_text(DISTEXT, HalpSetPCIData ) +#pragma alloc_text(DISTEXT, HalpReadPCIConfig ) +#pragma alloc_text(DISTEXT, HalpWritePCIConfig ) +#pragma alloc_text(DISTEXT, HalpValidPCISlot ) +#if DBG +#pragma alloc_text(DISTEXT, HalpValidPCIAddr ) +#endif +#pragma alloc_text(DISTEXT, HalpPCIConfig ) +#pragma alloc_text(DISTEXT, HalpPCIReadUchar ) +#pragma alloc_text(DISTEXT, HalpPCIReadUshort ) +#pragma alloc_text(DISTEXT, HalpPCIReadUlong ) +#pragma alloc_text(DISTEXT, HalpPCIWriteUchar ) +#pragma alloc_text(DISTEXT, HalpPCIWriteUshort ) +#pragma alloc_text(DISTEXT, HalpPCIWriteUlong ) +#pragma alloc_text(DISTEXT, HalpAssignPCISlotResources) +#pragma alloc_text(DISTEXT, HalpAdjustPCIResourceList) + +#endif // AXP_FIRMWARE + + +// +// Globals +// + +KSPIN_LOCK HalpPCIConfigLock; +BOOLEAN PCIInitialized = FALSE; +ULONG PCIMaxLocalDevice; +ULONG PCIMaxDevice; +ULONG PCIMaxBus; +PINSTALL_BUS_HANDLER PCIInstallHandler = HalpDefaultPCIInstallHandler; + +CONFIG_HANDLER PCIConfigHandlers = { + { + HalpPCIReadUlong, // 0 + HalpPCIReadUchar, // 1 + HalpPCIReadUshort // 2 + }, + { + HalpPCIWriteUlong, // 0 + HalpPCIWriteUchar, // 1 + HalpPCIWriteUshort // 2 + } +}; +UCHAR PCIDeref[4][4] = { {0,1,2,2},{1,1,1,1},{2,1,2,2},{1,1,1,1} }; + +WCHAR rgzMultiFunctionAdapter[] = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter"; +WCHAR rgzConfigurationData[] = L"Configuration Data"; +WCHAR rgzIdentifier[] = L"Identifier"; +WCHAR rgzPCIIndetifier[] = L"PCI"; + +#define Is64BitBaseAddress(a) \ + (((a & PCI_ADDRESS_IO_SPACE) == 0) && \ + ((a & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)) + +#if !defined(AXP_FIRMWARE) + +VOID +HalpRegisterPciBus( + IN PCONFIGURATION_COMPONENT Component, + IN PVOID ConfigurationData + ) +/*++ + +Routine Description: + + This function uses information obtained from the ARC configuration + tree to create PCI bus handlers. If configuration data was passed + with the PCI component, then that information is used to create the + bus handler. Otherwise, we use a priori knowledge (and bus scanning) + to generate the bus handler data. This function supports firmware + that both provide and do not provide configuration data payloads. + +Arguments: + + Component - The ARC configuration component for this bus. + + ConfigurationData - The configuration data payload (or NULL). + +Return Value: + + None. + +--*/ +{ + BOOLEAN ConfigurationDataPresent; + ARC_PCI_CONFIGURATION ArcPciConfiguration; + ULONG BusNumber; + ULONG HwBusNumber; + BOOLEAN BusIsAcrossPPB; + PBUS_HANDLER BusHandler; + PPCIPBUSDATA BusData; + RTL_BITMAP DevicePresent; + PCI_SLOT_NUMBER SlotNumber; + ULONG DeviceNumber; + ULONG FunctionNumber; + PCI_COMMON_CONFIG CommonConfig; + PCI_SLOT_NUMBER Dummy; + + memset(&Dummy, 0, sizeof(PCI_SLOT_NUMBER) ); + + // + // Ascertain whether the ARC firmware provided configuration data as part + // of the multi-function adapter component. + // + + ConfigurationDataPresent = Component->ConfigurationDataLength != 0; + + // + // If configuration data was provided use it to allocate and initialize + // the handler for this bus. Otherwise, use a priori knowledge to + // generate reasonable values. + // + + if (ConfigurationDataPresent) { + + // + // 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; + + // + // Despite its name, PCIMaxBus is really the number of busses present + // in the system. + // + + if (PCIMaxBus < BusNumber + 1) { + PCIMaxBus = BusNumber + 1; + } + + } else { + + // + // PCIMaxBus keeps a running count of the number of busses seen up + // to this point. Use the current value as the bus number and advance + // the counter. Set HwBusNumber and BusIsAcrossPPB to reasonable + // values. + // + + BusNumber = PCIMaxBus++; + HwBusNumber = 0; + BusIsAcrossPPB = BusNumber != 0; + + } + + // + // Allocate and initialize the handler for this bus. N.B. device-present + // checking is disabled at this point. We will enable it below. + // + + BusHandler = HalpAllocateAndInitPCIBusHandler( + BusNumber, + HwBusNumber, + BusIsAcrossPPB, + 0, // MS here + Dummy // MS here + ); + + // + // Get a pointer to the bus-specific data. + // + + BusData = (PPCIPBUSDATA)BusHandler->BusData; + + // + // Compute the device-present bitmap for this bus. If configuration + // data is present then the bitmap has been pre-computed for us by the + // firmware. In this case, use the bitmap provided. otherwise, we + // have to do the work now of generating the bitmap. + // + + if (ConfigurationDataPresent) { + + // + // Initialize the device-present bitmap for this bus. + // + + RtlInitializeBitMap( + &BusData->DevicePresent, + BusData->DevicePresentBits, + PCI_MAX_DEVICES * PCI_MAX_FUNCTION + ); + + // + // The firmware has already computed the device-present bitmap for + // us. Copy the bitmap from the configuration data. + // + + RtlCopyMemory( + BusData->DevicePresentBits, + ArcPciConfiguration.DevicePresentBits, + sizeof (BusData->DevicePresentBits) + ); + + + } else { + + // + // Initialize a bitmap which we will use to accumulate the results + // of the device-present scan. N.B. Device-present checking is + // currently disabled. + // + + RtlInitializeBitMap( + &DevicePresent, + BusData->DevicePresentBits, + PCI_MAX_DEVICES * PCI_MAX_FUNCTION + ); + + RtlClearBits( + &DevicePresent, + 0, + PCI_MAX_DEVICES * PCI_MAX_FUNCTION + ); + + // + // Initialize the slot number. + // + + SlotNumber.u.AsULONG = 0; + + // + // Loop through each device number. + // + + for (DeviceNumber = 0; + DeviceNumber < PCI_MAX_DEVICES; + DeviceNumber++) { + + 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; + } + + // + // Set a bit indicating a device is present. + // + + RtlSetBits( + &DevicePresent, + PciBitIndex(DeviceNumber, FunctionNumber), + 1 + ); + + // + // If this is not a multi-function device, then terminate + // the function number loop. + // + + if ((CommonConfig.HeaderType & PCI_MULTIFUNCTION) == 0) { + break; + } + } + } + + // + // Enable device-present checking. + // + + BusData->DevicePresent = DevicePresent; + } +} + +#endif + +#if !defined(AXP_FIRMWARE) + +VOID +HalpQueryPciBusConfiguration( + IN PCONFIGURATION_COMPONENT_DATA Root + ) +/*++ + +Routine Description: + + This function loops through each multi-function adapter component + in the ARC configuration tree and calls HalpRegisterPciBus() to create + a bus handler for it. + +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, register a bus handler for it. + // + + if (_stricmp(Adapter->ComponentEntry.Identifier, "PCI") == 0) { + HalpRegisterPciBus( + &Adapter->ComponentEntry, + Adapter->ConfigurationData + ); + } + } +} + +#endif + +VOID +HalpInitializePCIBus( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) +/*++ + +Routine Description: + + The function intializes global PCI bus state from the registry. + + The Arc firmware is responsible for building configuration information + about the number of PCI buses on the system and nature (local vs. secondary + - across a PCI-PCI bridge) of the each bus. + + The maximum virtual slot number on the local (type 0 config cycle) + PCI bus is registered here, based on the machine dependent define + PCI_MAX_LOCAL_DEVICE. This state is carried in PCIMaxLocalDevice. + + The maximum number of virtual slots on a secondary bus is fixed by the + PCI Specification and is represented by PCI_MAX_DEVICES. This + state is held in PCIMaxDevice. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + // + // Only initialize the PCI subsystem once. + // + + if (PCIInitialized) { + return; + } + + // + // Initialize PCI subsystem variables. + // + +#ifdef AXP_FIRMWARE + PCIMaxBus = PCI_MAX_BUSSES; +#else + PCIMaxBus = 0; +#endif + PCIMaxLocalDevice = PCI_MAX_LOCAL_DEVICE; + PCIMaxDevice = PCI_MAX_DEVICES - 1; + + // + // Initialize the PCI configuration spinlock. + // + + KeInitializeSpinLock(&HalpPCIConfigLock); + +#if !AXP_FIRMWARE + + // + // Consult the ARC configuration tree and register bus handlers for + // all PCI multi-function adapter nodes. + // + + HalpQueryPciBusConfiguration(LoaderBlock->ConfigurationRoot); + +#endif + + // + // The PCI subsystem has been initialized. + // + + PCIInitialized = TRUE; +} + +PBUS_HANDLER +HalpAllocateAndInitPCIBusHandler ( + IN ULONG BusNo, + IN ULONG HwBusNo, + IN BOOLEAN BusIsAcrossPPB, + IN ULONG PPBBusNumber, + IN PCI_SLOT_NUMBER PPBSlotNumber + ) +{ + PBUS_HANDLER Bus; + PPCIPBUSDATA BusData; + + HaliRegisterBusHandler ( + PCIBus, // Interface type + PCIConfiguration, // Has this configuration space + BusNo, // Bus Number + Internal, // child of this bus + 0, // and number + sizeof (PCIPBUSDATA), // sizeof bus specific buffer + PCIInstallHandler, // PCI install handler + &Bus); // Bushandler return + + BusData = (PPCIPBUSDATA) Bus->BusData; + BusData->HwBusNumber = HwBusNo; + BusData->BusIsAcrossPPB = BusIsAcrossPPB; + BusData->PPBBusNumber = PPBBusNumber; + BusData->PPBSlotNumber = PPBSlotNumber; + + return Bus; +} + +NTSTATUS +HalpDefaultPCIInstallHandler( + IN PBUS_HANDLER Bus + ) +{ + PPCIPBUSDATA BusData; + + + // + // Fill in PCI handlers + // + + Bus->GetBusData = (PGETSETBUSDATA) HalpGetPCIData; + Bus->SetBusData = (PGETSETBUSDATA) HalpSetPCIData; + Bus->AdjustResourceList = (PADJUSTRESOURCELIST) HalpAdjustPCIResourceList; + Bus->AssignSlotResources = (PASSIGNSLOTRESOURCES) HalpAssignPCISlotResources; + + BusData = (PPCIPBUSDATA) Bus->BusData; + + // + // Fill in common PCI data + // + + BusData->CommonData.Tag = PCI_DATA_TAG; + BusData->CommonData.Version = PCI_DATA_VERSION; + BusData->CommonData.ReadConfig = (PciReadWriteConfig)HalpReadPCIConfig; + BusData->CommonData.WriteConfig = (PciReadWriteConfig)HalpWritePCIConfig; + BusData->CommonData.Pin2Line = (PciPin2Line)HalpPCIPin2LineNop; + BusData->CommonData.Line2Pin = (PciLine2Pin)HalpPCILine2PinNop; + + + // set defaults + // + // ecrfix - if we knew more about the PCI bus at this + // point (e.g., local vs. across bridge, PCI config + // space base QVA, APECS vs. Sable T2/T4 vs. LCA4 vs. ??? config + // cycle type 0 mechanism), we could put this info into + // the "BusData" structure. The nice thing about this is + // that we could eliminate the platform-dependent module + // PCIBUS.C. + // + + BusData->MaxDevice = PCI_MAX_DEVICES - 1; // not currently used anywhere + + return STATUS_SUCCESS; +} + +VOID +HalpRegisterPCIInstallHandler( + IN PINSTALL_BUS_HANDLER MachineSpecificPCIInstallHandler +) +/*++ + +Routine Description: + + The function register's a machine-specific PCI Install Handler. + This allows a specific platform to override the default PCI install + handler, DefaultPCIInstallHandler(). + +Arguments: + + MachineSpecificPCIInstallHandler - Function that provides machine + specific PCI Bus Handler setup. + +Return Value: + + None. + + +--*/ +{ + PCIInstallHandler = MachineSpecificPCIInstallHandler; + + return; +} + +ULONG +HalpGetPCIData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) +/*++ + +Routine Description: + + The function returns the PCI bus data for a device. + +Arguments: + + BusHandler - Registered BUS_HANDLER for the target configuration space + + RootHandler - Register BUS_HANDLER for the orginating HalGetBusData request. + + VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word) + + Buffer - Supplies the space to store the data. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + + If this PCI slot has never been set, then the configuration information + returned is zeroed. + + +--*/ +{ + PPCI_COMMON_CONFIG PciData; + UCHAR iBuffer[PCI_COMMON_HDR_LENGTH]; + ULONG Len; + PCI_SLOT_NUMBER PciSlot; + + + if (Length > sizeof (PCI_COMMON_CONFIG)) { + Length = sizeof (PCI_COMMON_CONFIG); + } + + Len = 0; + PciData = (PPCI_COMMON_CONFIG) iBuffer; + PciSlot = *((PPCI_SLOT_NUMBER) &Slot); + + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The user did not request any data from the common + // header. Verify the PCI device exists, then continue + // in the device specific area. + // + + HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, sizeof(ULONG)); + + // + // Check for invalid slot + // + + if (PciData->VendorID == PCI_INVALID_VENDORID) { + return 0; + } + + } else { + + // + // Caller requested at least some data within the + // common header. Read the whole header, effect the + // fields we need to and then copy the user's requested + // bytes from the header + // + + // + // Read this PCI devices slot data + // + + Len = PCI_COMMON_HDR_LENGTH; + HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, Len); + + // + // Check for invalid slot + // + + if (PciData->VendorID == PCI_INVALID_VENDORID) { + PciData->VendorID = PCI_INVALID_VENDORID; + Len = 2; // only return invalid id + } + + // + // Copy whatever data overlaps into the callers buffer + // + + if (Len < Offset) { + // no data at caller's buffer + return 0; + } + + Len -= Offset; + if (Len > Length) { + Len = Length; + } + + RtlMoveMemory(Buffer, iBuffer + Offset, Len); + + Offset += Len; + Buffer += Len; + Length -= Len; + } + + if (Length) { + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The remaining Buffer comes from the Device Specific + // area - put on the kitten gloves and read from it. + // + // Specific read/writes to the PCI device specific area + // are guarenteed: + // + // Not to read/write any byte outside the area specified + // by the caller. (this may cause WORD or BYTE references + // to the area in order to read the non-dword aligned + // ends of the request) + // + // To use a WORD access if the requested length is exactly + // a WORD long. + // + // To use a BYTE access if the requested length is exactly + // a BYTE long. + // + + HalpReadPCIConfig (BusHandler, PciSlot, Buffer, Offset, Length); + Len += Length; + } + } + + return Len; +} + +ULONG +HalpSetPCIData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) +/*++ + +Routine Description: + + The function returns the Pci bus data for a device. + +Arguments: + + BusHandler - Registered BUS_HANDLER for the target configuration space + + RootHandler - Register BUS_HANDLER for the orginating HalSetBusData request. + + VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word) + + Buffer - Supplies the space to store the data. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + +--*/ +{ + PPCI_COMMON_CONFIG PciData, PciData2; + UCHAR iBuffer[PCI_COMMON_HDR_LENGTH]; + UCHAR iBuffer2[PCI_COMMON_HDR_LENGTH]; + ULONG Len; + PCI_SLOT_NUMBER PciSlot; + + + if (Length > sizeof (PCI_COMMON_CONFIG)) { + Length = sizeof (PCI_COMMON_CONFIG); + } + + + Len = 0; + PciData = (PPCI_COMMON_CONFIG) iBuffer; + PciData2 = (PPCI_COMMON_CONFIG) iBuffer2; + PciSlot = *((PPCI_SLOT_NUMBER) &Slot); + + + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The user did not request any data from the common + // header. Verify the PCI device exists, then continue in + // the device specific area. + // + + HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, sizeof(ULONG)); + + if (PciData->VendorID == PCI_INVALID_VENDORID || + PciData->VendorID == 0x00) { + return 0; + } + + } else { + + // + // Caller requested to set at least some data within the + // common header. + // + + Len = PCI_COMMON_HDR_LENGTH; + HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, Len); + if (PciData->VendorID == PCI_INVALID_VENDORID || + PciData->VendorID == 0x00) { + + // no device + return 0; + } + + // + // Copy COMMON_HDR values to buffer2, then overlay callers changes. + // + + RtlMoveMemory (iBuffer2, iBuffer, Len); + + Len -= Offset; + if (Len > Length) { + Len = Length; + } + + RtlMoveMemory (iBuffer2+Offset, Buffer, Len); + +#if DBG + // + // Verify R/O fields haven't changed + // + if (PciData2->VendorID != PciData->VendorID || + PciData2->DeviceID != PciData->DeviceID || + PciData2->RevisionID != PciData->RevisionID || + PciData2->ProgIf != PciData->ProgIf || + PciData2->SubClass != PciData->SubClass || + PciData2->BaseClass != PciData->BaseClass || + PciData2->HeaderType != PciData->HeaderType || + PciData2->BaseClass != PciData->BaseClass || + PciData2->u.type0.MinimumGrant != PciData->u.type0.MinimumGrant || + PciData2->u.type0.MaximumLatency != PciData->u.type0.MaximumLatency) { + DbgPrint ("PCI SetBusData: Read-Only configation value changed\n"); + DbgBreakPoint (); + } +#endif // DBG + // + // Set new PCI configuration + // + + HalpWritePCIConfig (BusHandler, PciSlot, iBuffer2+Offset, Offset, Len); + + Offset += Len; + Buffer += Len; + Length -= Len; + } + + if (Length) { + + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The remaining Buffer comes from the Device Specific + // area - put on the kitten gloves and write it + // + // Specific read/writes to the PCI device specific area + // are guarenteed: + // + // Not to read/write any byte outside the area specified + // by the caller. (this may cause WORD or BYTE references + // to the area in order to read the non-dword aligned + // ends of the request) + // + // To use a WORD access if the requested length is exactly + // a WORD long. + // + // To use a BYTE access if the requested length is exactly + // a BYTE long. + // + + HalpWritePCIConfig (BusHandler, PciSlot, Buffer, Offset, Length); + Len += Length; + } + } + + return Len; +} + +VOID +HalpPCILine2PinNop ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PPCI_COMMON_CONFIG PciNewData, + IN PPCI_COMMON_CONFIG PciOldData + ) +{ + // line-pin mappings not needed on alpha machines + return ; +} + +VOID +HalpPCIPin2LineNop ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PPCI_COMMON_CONFIG PciData + ) +{ + // line-pin mappings not needed on alpha machines + return ; +} + +VOID +HalpReadPCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ) +{ +#if 0 + if (!HalpValidPCISlot (BusHandler, Slot)) { + // + // Invalid SlotID return no data + // + + RtlFillMemory (Buffer, Length, (UCHAR) -1); + return ; + } + + HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length, + PCIConfigHandlers.ConfigRead); +#endif // 0 + + // + // Read the slot, if it's valid. + // Otherwise, return an Invalid VendorId for a invalid slot on an existing bus + // or a null (zero) buffer if we have a non-existant bus. + // + + switch (HalpValidPCISlot (BusHandler, Slot)) + { + + case ValidSlot: + + HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length, + PCIConfigHandlers.ConfigRead); + break; + + case InvalidSlot: + + // + // Invalid SlotID return no data (Invalid Slot ID = 0xFFFF) + // + + RtlFillMemory (Buffer, Length, (UCHAR) -1); + break ; + + case InvalidBus: + + // + // Invalid Bus, return return no data + // + + RtlFillMemory (Buffer, Length, (UCHAR) 0); + break ; + } + + return; + +} + +VOID +HalpWritePCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ) +{ + + if (HalpValidPCISlot (BusHandler, Slot) != ValidSlot) { + // + // Invalid SlotID do nothing + // + return ; + } + + HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length, + PCIConfigHandlers.ConfigWrite); +} + +VALID_SLOT +HalpValidPCISlot ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot + ) +{ + ULONG BusNumber; + PPCIPBUSDATA BusData; + PCI_SLOT_NUMBER Slot2; + PCI_CONFIGURATION_TYPES PciConfigType; + UCHAR HeaderType; + ULONG i, bit; + + BusNumber = BusHandler->BusNumber; + BusData = (PPCIPBUSDATA) BusHandler->BusData; + + if (Slot.u.bits.Reserved != 0) { + return FALSE; + } + + // + // If the initial device probe has been completed and no device + // is present for this slot then simply return invalid slot. + // + + bit = PciBitIndex(Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber); + + if( ( (BusData->DevicePresent).Buffer != NULL) && + !RtlCheckBit(&BusData->DevicePresent, bit) ) { + + return InvalidSlot; + } + + + // + // Get the config cycle type for the proposed bus. + // (PciConfigTypeInvalid indicates a non-existent bus.) + // + + PciConfigType = HalpPCIConfigCycleType(BusHandler); + + // + // The number of devices allowed on a local PCI bus may be different + // than that across a PCI-PCI bridge. + // + + switch(PciConfigType) { + case PciConfigType0: + + if (Slot.u.bits.DeviceNumber > PCIMaxLocalDevice) { +#if HALDBG + DbgPrint("Invalid local PCI Slot %x\n", Slot.u.bits.DeviceNumber); +#endif + return InvalidSlot; + } + break; + + case PciConfigType1: + + if (Slot.u.bits.DeviceNumber > PCIMaxDevice) { +#if HALDBG + DbgPrint("Invalid remote PCI Slot %x\n", Slot.u.bits.DeviceNumber); +#endif + return InvalidSlot; + } + break; + + case PciConfigTypeInvalid: + +#if HALDBG + DbgPrint("Invalid PCI Bus %x\n", BusNumber); +#endif + return InvalidBus; + break; + + } + + // + // Check function number + // + + if (Slot.u.bits.FunctionNumber == 0) { + return ValidSlot; + } + + // + // Non zero function numbers are only supported if the + // device has the PCI_MULTIFUNCTION bit set in it's header + // + + i = Slot.u.bits.DeviceNumber; + + // + // Read DeviceNumber, Function zero, to determine if the + // PCI supports multifunction devices + // + + Slot2 = Slot; + Slot2.u.bits.FunctionNumber = 0; + + HalpReadPCIConfig ( + BusHandler, + Slot2, + &HeaderType, + FIELD_OFFSET (PCI_COMMON_CONFIG, HeaderType), + sizeof (UCHAR) + ); + + if (!(HeaderType & PCI_MULTIFUNCTION) || (HeaderType == 0xFF)) { + // this device doesn't exists or doesn't support MULTIFUNCTION types + return InvalidSlot; + } + + return ValidSlot; +} + +VOID +HalpPCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length, + IN FncConfigIO *ConfigIO + ) +{ + KIRQL OldIrql; + ULONG i; + PCI_CFG_CYCLE_BITS PciAddr; + ULONG BusNumber; + + // + // Setup platform-dependent state for configuration space access + // + + HalpPCIConfigAddr(BusHandler, Slot, &PciAddr); + + // + // Synchronize with PCI config space + // + + KeAcquireSpinLock (&HalpPCIConfigLock, &OldIrql); + + // + // Do the I/O to PCI configuration space + // + + while (Length) { + i = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)]; + i = ConfigIO[i] (&PciAddr, Buffer, Offset); + + Offset += i; + Buffer += i; + Length -= i; + } + + // + // Release spinlock + // + + KeReleaseSpinLock (&HalpPCIConfigLock, OldIrql); + + return; +} + +ULONG +HalpPCIReadUchar ( + IN PPCI_CFG_CYCLE_BITS PciCfg, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG ConfigurationCycleType; + + // + // The configuration cycle type is extracted from bits[1:0] of PciCfg. + // + // Since an LCA4 register generates the configuration cycle type + // on the PCI bus, and because Offset bits[1:0] are used to + // generate the PCI byte enables (C/BE[3:0]), clear PciCfg bits [1:0] + // out before adding in Offset. + // + + ConfigurationCycleType = PciCfg->u.bits.Reserved1; + PciCfg->u.bits.Reserved1 = 0; + + *Buffer = READ_CONFIG_UCHAR ((PUCHAR) (PciCfg->u.AsULONG + Offset), + ConfigurationCycleType); + + // + // Reset state to preserve config cycle type across calls + // + + PciCfg->u.bits.Reserved1 = ConfigurationCycleType; + + return sizeof (UCHAR); +} + +ULONG +HalpPCIReadUshort ( + IN PPCI_CFG_CYCLE_BITS PciCfg, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG ConfigurationCycleType; + + ConfigurationCycleType = PciCfg->u.bits.Reserved1; + PciCfg->u.bits.Reserved1 = 0; + + *((PUSHORT) Buffer) = READ_CONFIG_USHORT ((PUSHORT) (PciCfg->u.AsULONG + Offset), + ConfigurationCycleType); + // + // Reset state to preserve config cycle type across calls + // + + PciCfg->u.bits.Reserved1 = ConfigurationCycleType; + + return sizeof (USHORT); +} + +ULONG +HalpPCIReadUlong ( + IN PPCI_CFG_CYCLE_BITS PciCfg, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG ConfigurationCycleType; + + ConfigurationCycleType = PciCfg->u.bits.Reserved1; + PciCfg->u.bits.Reserved1 = 0; + + *((PULONG) Buffer) = READ_CONFIG_ULONG ((PULONG) (PciCfg->u.AsULONG + Offset), + ConfigurationCycleType); + // + // Reset state to preserve config cycle type across calls + // + + PciCfg->u.bits.Reserved1 = ConfigurationCycleType; + + return sizeof (ULONG); +} + + +ULONG +HalpPCIWriteUchar ( + IN PPCI_CFG_CYCLE_BITS PciCfg, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG ConfigurationCycleType; + + ConfigurationCycleType = PciCfg->u.bits.Reserved1; + PciCfg->u.bits.Reserved1 = 0; + + WRITE_CONFIG_UCHAR ((PUCHAR) (PciCfg->u.AsULONG + Offset), *Buffer, + ConfigurationCycleType); + // + // Reset state to preserve config cycle type across calls + // + + PciCfg->u.bits.Reserved1 = ConfigurationCycleType; + + return sizeof (UCHAR); +} + +ULONG +HalpPCIWriteUshort ( + IN PPCI_CFG_CYCLE_BITS PciCfg, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG ConfigurationCycleType; + + ConfigurationCycleType = PciCfg->u.bits.Reserved1; + PciCfg->u.bits.Reserved1 = 0; + + WRITE_CONFIG_USHORT ((PUSHORT) (PciCfg->u.AsULONG + Offset), *((PUSHORT) Buffer), + ConfigurationCycleType); + // + // Reset state to preserve config cycle type across calls + // + + PciCfg->u.bits.Reserved1 = ConfigurationCycleType; + + return sizeof (USHORT); +} + +ULONG +HalpPCIWriteUlong ( + IN PPCI_CFG_CYCLE_BITS PciCfg, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG ConfigurationCycleType; + + ConfigurationCycleType = PciCfg->u.bits.Reserved1; + PciCfg->u.bits.Reserved1 = 0; + + WRITE_CONFIG_ULONG ((PULONG) (PciCfg->u.AsULONG + Offset), *((PULONG) Buffer), + ConfigurationCycleType); + // + // Reset state to preserve config cycle type across calls + // + + PciCfg->u.bits.Reserved1 = ConfigurationCycleType; + + return sizeof (ULONG); +} + +#if DBG + +BOOLEAN +HalpValidPCIAddr( + IN PBUS_HANDLER BusHandler, + IN PHYSICAL_ADDRESS BAddr, + IN ULONG Length, + IN ULONG AddressSpace) +/*++ + +Routine Description: + + Checks to see that the begining and ending 64 bit PCI bus addresses + of the 32 bit range of length Length are supported on the system. + +Arguments: + + BAddr - the 64 bit starting address + + Length - a 32 bit length + + AddressSpace - is this I/O (1) or memory space (0) + +Return Value: + + TRUE or FALSE + +--*/ +{ + PHYSICAL_ADDRESS EAddr, TBAddr, TEAddr; + LARGE_INTEGER LiILen; + ULONG inIoSpace, inIoSpace2; + BOOLEAN flag, flag2; + ULONG BusNumber; + + BusNumber = BusHandler->BusNumber; + + // + // Translated address to system global setting and verify + // resource is available. + // + // Note that this code will need to be changed to support + // 64 bit PCI bus addresses. + // + + LiILen.QuadPart = (ULONG)(Length - 1); // Inclusive length + EAddr.QuadPart = BAddr.QuadPart + LiILen.QuadPart; + + inIoSpace = inIoSpace2 = AddressSpace; + + flag = HalTranslateBusAddress ( PCIBus, + BusNumber, + BAddr, + &inIoSpace, + &TBAddr + ); + + flag2 = HalTranslateBusAddress (PCIBus, + BusNumber, + EAddr, + &inIoSpace2, + &TEAddr + ); + + if (flag == FALSE || flag2 == FALSE || inIoSpace != inIoSpace2) { + + // + // HalAdjustResourceList should ensure that the returned range + // for the bus is within the bus limits and no translation + // within those limits should ever fail + // + + DbgPrint ("HalpValidPCIAddr: Error return for HalTranslateBusAddress %x.%x:%x %x.%x:%x\n", + BAddr.HighPart, BAddr.LowPart, flag, + EAddr.HighPart, EAddr.LowPart, flag2); + return FALSE; + } + + return TRUE; +} + +#endif + + +NTSTATUS +HalpAssignPCISlotResources ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName OPTIONAL, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN ULONG Slot, + IN OUT PCM_RESOURCE_LIST *pAllocatedResources + ) +/*++ + +Routine Description: + + Reads the targeted device to determine the firmwaire-assigned resources. + Calls IoReportResources to report/confirm them. + Returns the assignments to the caller. + +Arguments: + +Return Value: + + STATUS_SUCCESS or error + +--*/ +{ + NTSTATUS status; + PUCHAR WorkingPool; + PPCI_COMMON_CONFIG PciData, PciOrigData; + PCI_SLOT_NUMBER PciSlot; + + PCM_RESOURCE_LIST CmRes; + PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc; + PHYSICAL_ADDRESS BAddr; + ULONG addr; + ULONG Command; + ULONG cnt, len; + BOOLEAN conflict; + + ULONG i, j, m, length, holdvalue; + ULONG BusNumber; + + BusNumber = BusHandler->BusNumber; + + *pAllocatedResources = NULL; + PciSlot = *((PPCI_SLOT_NUMBER) &Slot); + + // + // Allocate some pool for working space + // + + i = sizeof (CM_RESOURCE_LIST) + + sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2) + + PCI_COMMON_HDR_LENGTH * 2; + + WorkingPool = (PUCHAR) ExAllocatePool (PagedPool, i); + if (!WorkingPool) { + return STATUS_NO_MEMORY; + } + + // + // Zero initialize pool, and get pointers into memory - here we allocate + // a single chunk of memory and partition it into three pieces, pointed + // to by three separate pointers. + // + + RtlZeroMemory (WorkingPool, i); + CmRes = (PCM_RESOURCE_LIST) WorkingPool; + PciData = (PPCI_COMMON_CONFIG)(WorkingPool + i - PCI_COMMON_HDR_LENGTH * 2); + PciOrigData = (PPCI_COMMON_CONFIG)(WorkingPool + i - PCI_COMMON_HDR_LENGTH); + + // + // Read the PCI device configuration + // + + HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); + if (PciData->VendorID == PCI_INVALID_VENDORID || // empty slot + PciData->VendorID == 0x00) { // non-existant bus + ExFreePool (WorkingPool); + return STATUS_NO_SUCH_DEVICE; + } + + // + // Make a copy of the devices current settings + // + + RtlMoveMemory (PciOrigData, PciData, PCI_COMMON_HDR_LENGTH); + + // + // Set resources to all bits on to see what type of resources + // are required. + // + + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + PciData->u.type0.BaseAddresses[j] = 0xFFFFFFFF; + } + + PciData->u.type0.ROMBaseAddress = 0xFFFFFFFF; + + PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE); + PciData->u.type0.ROMBaseAddress &= ~PCI_ROMADDRESS_ENABLED; + HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); + HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); + + // + // Build an CM_RESOURCE_LIST for the PCI device to report resources + // to IoReportResourceUsage. + // + // This code does *not* use IoAssignoResources, as the PCI + // address space resources have been previously assigned by the ARC firmware + // + + CmRes->Count = 1; + CmRes->List[0].InterfaceType = PCIBus; + CmRes->List[0].BusNumber = BusNumber; + + CmRes->List[0].PartialResourceList.Count = 0; + + // + // Set current CM_RESOURCE_LIST version and revision + // + + CmRes->List[0].PartialResourceList.Version = 0; + CmRes->List[0].PartialResourceList.Revision = 0; + + CmDesc = CmRes->List[0].PartialResourceList.PartialDescriptors; + +#if DBG + DbgPrint ("HalAssignSlotResources: Resource List V%d.%d for slot %x:\n", + CmRes->List[0].PartialResourceList.Version, + CmRes->List[0].PartialResourceList.Revision, + Slot); + +#endif + + // + // Interrupt resource + // + + if (PciData->u.type0.InterruptPin) { + + CmDesc->Type = CmResourceTypeInterrupt; + CmDesc->ShareDisposition = CmResourceShareShared; + CmDesc->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + + CmDesc->u.Interrupt.Level = PciData->u.type0.InterruptLine; + CmDesc->u.Interrupt.Vector = PciData->u.type0.InterruptLine; + +#if DBG + DbgPrint (" INT Level %x, Vector %x\n", + CmDesc->u.Interrupt.Level, CmDesc->u.Interrupt.Vector ); +#endif + + CmRes->List[0].PartialResourceList.Count++; + CmDesc++; + } + + // + // Add a memory or port resoruce for each PCI resource + // (Compute the ROM address as well. Just append it to the Base + // Address table.) + // + + holdvalue = PciData->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES]; + PciData->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES] = + PciData->u.type0.ROMBaseAddress & ~PCI_ADDRESS_IO_SPACE; + + Command = PciOrigData->Command; + for (j=0; j < PCI_TYPE0_ADDRESSES + 1; j++) { + if (PciData->u.type0.BaseAddresses[j]) { + addr = i = PciData->u.type0.BaseAddresses[j]; + + // + // calculate the length necessary - note there is more complicated + // code in the x86 HAL that probably isn't necessary + // + + length = ~(i & ~((i & 1) ? 3 : 15)) + 1; + + // + // I/O space resource + // + + if (addr & PCI_ADDRESS_IO_SPACE) { + + CmDesc->Type = CmResourceTypePort; + CmDesc->ShareDisposition = CmResourceShareDeviceExclusive; + CmDesc->Flags = CM_RESOURCE_PORT_IO; + + BAddr.LowPart = PciOrigData->u.type0.BaseAddresses[j] & ~3; + BAddr.HighPart = 0; + +#if DBG + HalpValidPCIAddr(BusHandler, BAddr, length, 1); // I/O space +#endif + + CmDesc->u.Port.Start = BAddr; + CmDesc->u.Port.Length = length; + Command |= PCI_ENABLE_IO_SPACE; +#if DBG + DbgPrint (" IO Start %x:%08x, Len %x\n", + CmDesc->u.Port.Start.HighPart, CmDesc->u.Port.Start.LowPart, + CmDesc->u.Port.Length ); +#endif + // + // Memory space resource + // + + } else { + + CmDesc->Type = CmResourceTypeMemory; + CmDesc->ShareDisposition = CmResourceShareDeviceExclusive; + + if (j == PCI_TYPE0_ADDRESSES) { + // this is a ROM address + if ((PciOrigData->u.type0.ROMBaseAddress & PCI_ROMADDRESS_ENABLED) == 0) { + // + // Ignore expansion ROMs which are not enabled by + // the firmware/ROM BIOS. + // + + continue; + } + CmDesc->Flags = CM_RESOURCE_MEMORY_READ_ONLY; + BAddr.LowPart = PciOrigData->u.type0.ROMBaseAddress & + ~PCI_ROMADDRESS_ENABLED; + BAddr.HighPart = 0; + } else { + // this is a memory space base address + CmDesc->Flags = CM_RESOURCE_MEMORY_READ_WRITE; + BAddr.LowPart = PciOrigData->u.type0.BaseAddresses[j] & ~15; + BAddr.HighPart = 0; + } + +#if DBG + HalpValidPCIAddr(BusHandler, BAddr, length, 0); // Memory space +#endif + + CmDesc->u.Memory.Start = BAddr; + CmDesc->u.Memory.Length = length; +#if DBG + DbgPrint (" MEM Start %x:%08x, Len %x\n", + CmDesc->u.Memory.Start.HighPart, CmDesc->u.Memory.Start.LowPart, + CmDesc->u.Memory.Length ); +#endif + } + + CmRes->List[0].PartialResourceList.Count++; + CmDesc++; + + if (Is64BitBaseAddress(addr)) { + // skip upper half of 64 bit address since we + // only supports 32 bits PCI addresses for now. + j++; + } + } + } + + // + // Setup the resource list. + // Count only the acquired resources. + // + + *pAllocatedResources = CmRes; + cnt = CmRes->List[0].PartialResourceList.Count; + len = sizeof (CM_RESOURCE_LIST) + + cnt * sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR); + +#if DBG + DbgPrint("HalAssignSlotResources: Acq. Resourses = %d (len %x list %x\n)", + cnt, len, *pAllocatedResources); +#endif + + // + // Report the IO resource assignments + // + + if (!DeviceObject) { + status = IoReportResourceUsage ( + DriverClassName, + DriverObject, // DriverObject + *pAllocatedResources, // DriverList + len, // DriverListSize + DeviceObject, // DeviceObject + NULL, // DeviceList + 0, // DeviceListSize + FALSE, // override conflict + &conflict // conflicted detected + ); + } else { + status = IoReportResourceUsage ( + DriverClassName, + DriverObject, // DriverObject + NULL, // DriverList + 0, // DriverListSize + DeviceObject, + *pAllocatedResources, // DeviceList + len, // DeviceListSize + FALSE, // override conflict + &conflict // conflicted detected + ); + } + + if (NT_SUCCESS(status) && conflict) { + + // + // IopReportResourceUsage saw a conflict? + // + +#if DBG + DbgPrint("HalAssignSlotResources: IoAssignResources detected a conflict: %x\n", + status); +#endif + status = STATUS_CONFLICTING_ADDRESSES; + goto CleanUp; + } + + if (!NT_SUCCESS(status)) { +#if DBG + DbgPrint("HalAssignSlotResources: IoAssignResources failed: %x\n", status); +#endif + goto CleanUp; + } + + // + // Restore orginial data, turning on the appropiate decodes + // + +#if DBG + DbgPrint ("HalAssignSlotResources: IoReportResourseUsage succeeded\n"); +#endif + + // enable IO & Memory decodes + + PciOrigData->Command |= (USHORT) Command; + + HalpWritePCIConfig ( + BusHandler, + PciSlot, + PciOrigData, + 0, + PCI_COMMON_HDR_LENGTH + ); + +#if DBG + DbgPrint ("HalAssignSlotResources: PCI Config Space updated with Command = %x\n", + Command); +#endif + +CleanUp: + if (!NT_SUCCESS(status)) { + + // + // Failure, if there are any allocated resources free them + // + + i = 0; + if (*pAllocatedResources) { + + if (!DeviceObject) { + status = IoReportResourceUsage ( + DriverClassName, + DriverObject, // DriverObject + (PCM_RESOURCE_LIST) &i, // DriverList + sizeof (i), // DriverListSize + DeviceObject, + NULL, // DeviceList + 0, // DeviceListSize + FALSE, // override conflict + &conflict // conflicted detected + ); + } else { + status = IoReportResourceUsage ( + DriverClassName, + DriverObject, // DriverObject + NULL, // DriverList + 0, // DriverListSize + DeviceObject, + (PCM_RESOURCE_LIST) &i, // DeviceList + sizeof (i), // DeviceListSize + FALSE, // override conflict + &conflict // conflicted detected + ); + } + + ExFreePool (*pAllocatedResources); + *pAllocatedResources = NULL; + } + + // + // Restore the device settings as we found them, enable memory + // and io decode after setting base addresses + // + + HalpWritePCIConfig ( + BusHandler, + PciSlot, + PciOrigData, + FIELD_OFFSET (PCI_COMMON_CONFIG, Status), + PCI_COMMON_HDR_LENGTH - FIELD_OFFSET (PCI_COMMON_CONFIG, Status) + ); + + HalpWritePCIConfig ( + BusHandler, + PciSlot, + PciOrigData, + 0, + FIELD_OFFSET (PCI_COMMON_CONFIG, Status) + ); + } + + return status; +} + + +NTSTATUS +HalpAdjustPCIResourceList ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ) +/*++ + +Routine Description: + + The function adjusts a PCI pResourceList and forces it to match the + pre-configured values in PCI configuration space for this device. + +Arguments: + + BusHandler - Registered BUS_HANDLER for the target configuration space + + RootHandler - Register BUS_HANDLER for the orginating HalAdjustResourceList request. + + pResourceList - Supplies the PIO_RESOURCE_REQUIREMENTS_LIST to be checked. + +Return Value: + + STATUS_SUCCESS + +--*/ +{ + UCHAR buffer[PCI_COMMON_HDR_LENGTH]; + PCI_SLOT_NUMBER PciSlot; + PPCI_COMMON_CONFIG PciData; + PIO_RESOURCE_REQUIREMENTS_LIST CompleteList; + PIO_RESOURCE_LIST ResourceList; + PIO_RESOURCE_DESCRIPTOR Descriptor; + ULONG alt, cnt, bcnt; + ULONG MemoryBaseAddress, RomIndex; + PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1]; + + // + // Fix any requested resources for this device to be the + // value set in PCI configuration space for this device. + // + + // + // Get PCI common configuration space for this slot + // + + PciSlot = *((PPCI_SLOT_NUMBER) &(*pResourceList)->SlotNumber), + PciData = (PPCI_COMMON_CONFIG) buffer; + + HalGetBusData ( + PCIConfiguration, + BusHandler->BusNumber, + PciSlot.u.AsULONG, + PciData, + PCI_COMMON_HDR_LENGTH + ); + + if (PciData->VendorID == PCI_INVALID_VENDORID) { + return STATUS_UNSUCCESSFUL; + } + + // + // Copy base addresses based on configuration data type + // + + switch (PCI_CONFIG_TYPE(PciData)) { + case 0 : + for (bcnt=0; bcnt < PCI_TYPE0_ADDRESSES; bcnt++) { + BaseAddress[bcnt] = &PciData->u.type0.BaseAddresses[bcnt]; + } + BaseAddress[bcnt] = &PciData->u.type0.ROMBaseAddress; + RomIndex = bcnt; + break; + case 1: + for (bcnt=0; bcnt < PCI_TYPE1_ADDRESSES; bcnt++) { + BaseAddress[bcnt] = &PciData->u.type1.BaseAddresses[bcnt]; + } + BaseAddress[bcnt] = &PciData->u.type0.ROMBaseAddress; + RomIndex = bcnt; + break; + + default: + return STATUS_NO_SUCH_DEVICE; + } + + // + // Walk each ResourceList and confine resources + // to preconfigured settings. + // + + CompleteList = *pResourceList; + ResourceList = CompleteList->List; + ResourceList->Version = 1; + ResourceList->Revision = 1; + + for (alt=0; alt < CompleteList->AlternativeLists; alt++) { + Descriptor = ResourceList->Descriptors; + + // + // For each alternative list, reset to review entire + // set of Base Address registers + // + // We assume that the order of resource descriptors for + // each alternative list matches the order of the + // PCI configuration space base address registers + // + + bcnt = 0; + + for (cnt = ResourceList->Count; cnt; cnt--) { + + // + // Limit desctiptor to to preconfigured setting + // held in the InterruptLine register. + // + + switch (Descriptor->Type) { + case CmResourceTypeInterrupt: + + // + // Confine interrupt vector to preconfigured setting. + // + + Descriptor->u.Interrupt.MinimumVector = PciData->u.type0.InterruptLine; + Descriptor->u.Interrupt.MaximumVector = PciData->u.type0.InterruptLine; + break; + + case CmResourceTypePort: + + // + // Assure that requested descriptor is valid + // + + if (bcnt > RomIndex) { + return STATUS_INVALID_PARAMETER; + } + + // + // Confine to preconfigured setting. + // + + Descriptor->u.Port.MinimumAddress.QuadPart = + *BaseAddress[bcnt++] & ~0x3; + + Descriptor->u.Port.MaximumAddress.QuadPart = + Descriptor->u.Port.MinimumAddress.QuadPart + + Descriptor->u.Port.Length - 1; + +#if HALDBG + DbgPrint("AdjustPCIResourceList\nPort: MinimumAddress set to %x\n", + Descriptor->u.Port.MinimumAddress.QuadPart); + + DbgPrint(" MaximumAddress set to %x\n", + Descriptor->u.Port.MaximumAddress.QuadPart); +#endif + + break; + + case CmResourceTypeMemory: + + // + // Assure that requested descriptor is valid + // + + if (bcnt > RomIndex) { + return STATUS_INVALID_PARAMETER; + } + + // + // Confine to preconfigured setting. + // + + MemoryBaseAddress = *BaseAddress[bcnt]; + + if (bcnt == RomIndex) { + Descriptor->u.Memory.MinimumAddress.QuadPart = + *BaseAddress[bcnt++] & ~PCI_ROMADDRESS_ENABLED; + } else { + Descriptor->u.Memory.MinimumAddress.QuadPart = + *BaseAddress[bcnt++] & ~0xF; + } + + Descriptor->u.Memory.MaximumAddress.QuadPart = + Descriptor->u.Memory.MinimumAddress.QuadPart + + Descriptor->u.Memory.Length - 1; + + if (Is64BitBaseAddress(MemoryBaseAddress)) { + // skip upper half of 64 bit address since we + // only supports 32 bits PCI addresses for now. + bcnt++; + } + + +#if HALDBG + DbgPrint("AdjustPCIResourceList\nMemory: MinimumAddress set to %x\n", + Descriptor->u.Memory.MinimumAddress.QuadPart); + + DbgPrint(" MaximumAddress set to %x\n", + Descriptor->u.Memory.MaximumAddress.QuadPart); +#endif + break; + + case CmResourceTypeDma: + break; + + default: + return STATUS_INVALID_PARAMETER; + } + + // + // Next descriptor + // + Descriptor++; + } + + // + // Next Resource List + // + ResourceList = (PIO_RESOURCE_LIST) Descriptor; + } + return STATUS_SUCCESS; +} + + +#define TEST_PCI 1 + +#if DBG && TEST_PCI + +VOID HalpTestPci (ULONG flag2) +{ + PCI_SLOT_NUMBER SlotNumber; + PCI_COMMON_CONFIG PciData, OrigData; + ULONG i, f, j, k, bus; + BOOLEAN flag; + + if (!flag2) { + return ; + } + + DbgBreakPoint (); + SlotNumber.u.bits.Reserved = 0; + + // + // Read every possible PCI Device/Function and display it's + // default info. + // + // (note this destories it's current settings) + // + + flag = TRUE; + for (bus = 0; flag; bus++) { + + for (i = 0; i < 32; i++) { + SlotNumber.u.bits.DeviceNumber = i; + + for (f = 0; f < 8; f++) { + SlotNumber.u.bits.FunctionNumber = f; + + + j = HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + if (j == 0) { + // out of buses + flag = FALSE; + break; + } + + if (j < PCI_COMMON_HDR_LENGTH) { + continue; + } + + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + 1 + ); + + HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + memcpy (&OrigData, &PciData, sizeof PciData); + + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + PciData.u.type0.BaseAddresses[j] = 0xFFFFFFFF; + } + + PciData.u.type0.ROMBaseAddress = 0xFFFFFFFF; + + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + DbgPrint ("PCI Bus %d Slot %2d %2d ID:%04lx-%04lx Rev:%04lx", + bus, i, f, PciData.VendorID, PciData.DeviceID, + PciData.RevisionID); + + if (PciData.u.type0.InterruptPin) { + DbgPrint (" IntPin:%x", PciData.u.type0.InterruptPin); + } + + if (PciData.u.type0.InterruptLine) { + DbgPrint (" IntLine:%x", PciData.u.type0.InterruptLine); + } + + if (PciData.u.type0.ROMBaseAddress) { + DbgPrint (" ROM:%08lx", PciData.u.type0.ROMBaseAddress); + } + + DbgPrint ("\n ProgIf:%04x SubClass:%04x BaseClass:%04lx\n", + PciData.ProgIf, PciData.SubClass, PciData.BaseClass); + + k = 0; + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + if (PciData.u.type0.BaseAddresses[j]) { + DbgPrint (" Ad%d:%08lx", j, PciData.u.type0.BaseAddresses[j]); + k = 1; + } + } + + if (PciData.u.type0.ROMBaseAddress == 0xC08001) { + + PciData.u.type0.ROMBaseAddress = 0xC00001; + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + DbgPrint ("\n Bogus rom address, edit yields:%08lx", + PciData.u.type0.ROMBaseAddress); + } + if (k) { + DbgPrint ("\n"); + } + + if (PciData.VendorID == 0x8086) { + // dump complete buffer + DbgPrint ("Command %x, Status %x, BIST %x\n", + PciData.Command, PciData.Status, + PciData.BIST + ); + + DbgPrint ("CacheLineSz %x, LatencyTimer %x", + PciData.CacheLineSize, PciData.LatencyTimer + ); + + for (j=0; j < 192; j++) { + if ((j & 0xf) == 0) { + DbgPrint ("\n%02x: ", j + 0x40); + } + DbgPrint ("%02x ", PciData.DeviceSpecific[j]); + } + DbgPrint ("\n"); + } + + // + // now print original data + // + + if (OrigData.u.type0.ROMBaseAddress) { + DbgPrint (" oROM:%08lx", OrigData.u.type0.ROMBaseAddress); + } + + DbgPrint ("\n"); + k = 0; + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + if (OrigData.u.type0.BaseAddresses[j]) { + DbgPrint (" oAd%d:%08lx", j, OrigData.u.type0.BaseAddresses[j]); + k = 1; + } + } + + // + // Restore original settings + // + + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &OrigData, + sizeof (PciData) + ); + + // + // Next + // + + if (k) { + DbgPrint ("\n\n"); + } + } + } + + } + DbgBreakPoint(); +} + +#endif // DBG && TEST_PCI diff --git a/private/ntos/nthals/halalpha/pcrtc.c b/private/ntos/nthals/halalpha/pcrtc.c new file mode 100644 index 000000000..6e8bd954a --- /dev/null +++ b/private/ntos/nthals/halalpha/pcrtc.c @@ -0,0 +1,381 @@ +/*++ + +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; +} + + +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 ); +} diff --git a/private/ntos/nthals/halalpha/pcrtc.h b/private/ntos/nthals/halalpha/pcrtc.h new file mode 100644 index 000000000..bff457f05 --- /dev/null +++ b/private/ntos/nthals/halalpha/pcrtc.h @@ -0,0 +1,166 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + pcrtc.h + +Abstract: + + This module is the header file that describes hardware structure + for the standard compatible PC Toy clock. + +Author: + + David N. Cutler (davec) 3-May-1991 + Jeff McLeman (mcleman) 4-Jun-1992 + +Revision History: + + 13-Jul-1992 Jeff McLeman + Add port offsets for use with VTI access routines. + + 4-Jun-1992 Jeff McLeman + Adapt module to Jensen specific + +--*/ + +#ifndef _PCRTC_ +#define _PCRTC_ + +// +// Define Realtime Clock register numbers. +// + +#define RTC_SECOND 0 // second of minute [0..59] +#define RTC_SECOND_ALARM 1 // seconds to alarm +#define RTC_MINUTE 2 // minute of hour [0..59] +#define RTC_MINUTE_ALARM 3 // minutes to alarm +#define RTC_HOUR 4 // hour of day [0..23] +#define RTC_HOUR_ALARM 5 // hours to alarm +#define RTC_DAY_OF_WEEK 6 // day of week [1..7] +#define RTC_DAY_OF_MONTH 7 // day of month [1..31] +#define RTC_MONTH 8 // month of year [1..12] +#define RTC_YEAR 9 // year [00..99] +#define RTC_CONTROL_REGISTERA 10 // control register A +#define RTC_CONTROL_REGISTERB 11 // control register B +#define RTC_CONTROL_REGISTERC 12 // control register C +#define RTC_CONTROL_REGISTERD 13 // control register D +#define RTC_REGNUMBER_RTC_CR1 0x6A // control register 1 + +#ifndef _LANGUAGE_ASSEMBLY + +// +// Definitions for NT area of NVRAM +// +typedef struct _RTC_RAM_NT_FLAGS_0 { + UCHAR ConfigurationBit : 1; // Serial line console only + UCHAR Fill : 6; + UCHAR AutoRunECU : 1; // Go directly to ECU +} RTC_RAM_NT_FLAGS_0, *PRTC_RAM_NT_FLAGS_0; + +#define RTC_RAM_NT_FLAGS_0_RUNARCAPP (0x80) +#define RTC_RAM_NT_FLAGS_0_RESERVED (0x7E) +#define RTC_RAM_NT_FLAGS_0_USECOM1FORIO (0x01) + +// +// Values for RTC_RAM_CONSOLE_SELECTION +// + +#define RTC_RAM_CONSOLE_SELECTION_NT 1 +#define RTC_RAM_CONSOLE_SELECTION_VMS 2 +#define RTC_RAM_CONSOLE_SELECTION_OSF 3 + +// +// Define Control Register A structure. +// + +typedef struct _RTC_CONTROL_REGISTER_A { + UCHAR RateSelect : 4; + UCHAR TimebaseDivisor : 3; + UCHAR UpdateInProgress : 1; +} RTC_CONTROL_REGISTER_A, *PRTC_CONTROL_REGISTER_A; + +// +// Define Control Register B structure. +// + +typedef struct _RTC_CONTROL_REGISTER_B { + UCHAR DayLightSavingsEnable : 1; + UCHAR HoursFormat : 1; + UCHAR DataMode : 1; + UCHAR SquareWaveEnable : 1; + UCHAR UpdateInterruptEnable : 1; + UCHAR AlarmInterruptEnable : 1; + UCHAR TimerInterruptEnable : 1; + UCHAR SetTime : 1; +} RTC_CONTROL_REGISTER_B, *PRTC_CONTROL_REGISTER_B; + +// +// Define Control Register C structure. +// + +typedef struct _RTC_CONTROL_REGISTER_C { + UCHAR Fill : 4; + UCHAR UpdateInterruptFlag : 1; + UCHAR AlarmInterruptFlag : 1; + UCHAR TimeInterruptFlag : 1; + UCHAR InterruptRequest : 1; +} RTC_CONTROL_REGISTER_C, *PRTC_CONTROL_REGISTER_C; + +// +// Define Control Register D structure. +// + +typedef struct _RTC_CONTROL_REGISTER_D { + UCHAR Fill : 7; + UCHAR ValidTime : 1; +} RTC_CONTROL_REGISTER_D, *PRTC_CONTROL_REGISTER_D; + +// +// Common routine for programming the interval timer +// +VOID +HalpProgramIntervalTimer( + IN ULONG RateSelect + ); + +#endif // _LANGUAGE_ASSEMBLY + +// +// Define initialization values for Jensen interval timer +// There are four different rates that are used under NT +// (see page 9-8 of KN121 System Module Programmer's Reference) +// +// .976562 ms +// 1.953125 ms +// 3.90625 ms +// 7.8125 ms +// +#define RTC_TIMEBASE_DIVISOR 0x02 + +#define RTC_RATE_SELECT1 6 +#define RTC_RATE_SELECT2 7 +#define RTC_RATE_SELECT3 8 +#define RTC_RATE_SELECT4 9 + +// +// note that rates 1-3 have some rounding error, +// since they are not expressible in even 100ns units +// + +#define RTC_PERIOD_IN_CLUNKS1 9766 +#define RTC_PERIOD_IN_CLUNKS2 19531 +#define RTC_PERIOD_IN_CLUNKS3 39063 +#define RTC_PERIOD_IN_CLUNKS4 78125 + +// +// Defaults +// +#define MINIMUM_INCREMENT RTC_PERIOD_IN_CLUNKS1 +#define MAXIMUM_INCREMENT RTC_PERIOD_IN_CLUNKS4 +#define MAXIMUM_RATE_SELECT RTC_RATE_SELECT4 + +#endif // _PCRTC_ diff --git a/private/ntos/nthals/halalpha/pcserial.c b/private/ntos/nthals/halalpha/pcserial.c new file mode 100644 index 000000000..6d22448a6 --- /dev/null +++ b/private/ntos/nthals/halalpha/pcserial.c @@ -0,0 +1,596 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + pcserial.c + +Abstract: + + This module implements the code that provides communication between + the kernel debugger stub and the kernel debugger via a standard + PC serial UART. + + Stolen from ../mips/jxport.c + +Author: + + Miche Baker-Harvey (miche) 01-June-1992 + Jeff McLeman [DEC] 02-Feb-1993 + +Environment: + + Kernel mode + +Revision History: + + Joe Notarangelo 21-Jun-1992 + update to use super-page access to serial port so we aren't depend + on translation code, this will allow us to debug the translation + code, use serial line 2 + + +--*/ + + +#include "halp.h" +#include "halpcsl.h" + + +// +// BUGBUG Temporarily, we use counter to do the timeout +// + +#define TIMEOUT_COUNT 1024*512 + +// +// BUGBUG Temp until we have a configuration manager. +// +PUCHAR KdComPortInUse = NULL; +BOOLEAN KdUseModemControl = FALSE; +// +// Define serial port read and write addresses. +// +PSP_READ_REGISTERS SP_READ; +PSP_WRITE_REGISTERS SP_WRITE; + +// +// Define forward referenced prototypes. +// + +SP_LINE_STATUS +KdReadLsr ( + IN BOOLEAN WaitReason + ); + +// +// Define baud rate divisor to be used on the debugger port. +// + +UCHAR HalpBaudRateDivisor = 0; + + +ULONG +HalpGetByte ( + IN PUCHAR Input, + IN BOOLEAN Wait + ) + +/*++ + +Routine Description: + + This routine gets a byte from the serial port used by the kernel debugger. + + N.B. It is assumed that the IRQL has been raised to the highest level, + and necessary multiprocessor synchronization has been performed + before this routine is called. + +Arguments: + + Input - Supplies a pointer to a variable that receives the input data + byte. + +Return Value: + + CP_GET_SUCCESS is returned if a byte is successfully read from the + kernel debugger line. + CP_GET_ERROR is returned if error encountered during reading. + CP_GET_NODATA is returned if timeout. + +--*/ +{ + SP_LINE_STATUS LsrByte; + UCHAR DataByte; + ULONG TimeoutCount; + + // + // Attempt to read a byte from the debugger port until a byte is + // available or until a timeout occurs. + // + + TimeoutCount = Wait ? TIMEOUT_COUNT : 1; + do { + TimeoutCount -= 1; + + // + // Wait until data is available in the receive buffer. + // + + KeStallExecutionProcessor(1); + LsrByte = KdReadLsr(TRUE); + if (LsrByte.DataReady == 0) { + continue; + } + + // + // Read input byte and store in callers buffer. + // + + *Input = READ_PORT_UCHAR(&SP_READ->ReceiveBuffer); + + // + // If using modem controls, then skip any incoming data while + // ReceiveData not set. + // + + if (KdUseModemControl) { + DataByte = READ_PORT_UCHAR(&SP_READ->ModemStatus); + if ( ((PSP_MODEM_STATUS)&DataByte)->ReceiveDetect == 0) { + continue; + } + } + + // + // Return function value as the not of the error indicators. + // + + if (LsrByte.ParityError || + LsrByte.FramingError || + LsrByte.OverrunError || + LsrByte.BreakIndicator) { + return CP_GET_ERROR; + } + + return CP_GET_SUCCESS; + } while(TimeoutCount != 0); + + return CP_GET_NODATA; + +} + +BOOLEAN +KdPortInitialize ( + PDEBUG_PARAMETERS DebugParameters, + PLOADER_PARAMETER_BLOCK LoaderBlock, + BOOLEAN Initialize + ) + +/*++ + +Routine Description: + + This routine initializes the serial port used by the kernel debugger + and must be called during system initialization. + + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + + PCONFIGURATION_COMPONENT_DATA ConfigurationEntry; + UCHAR DataByte; + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; + PCM_SERIAL_DEVICE_DATA DeviceData; + PCM_PARTIAL_RESOURCE_LIST List; + ULONG MatchKey; + ULONG BaudClock; + ULONG BaudRate; + ULONG Remainder; + + + // + // Find the configuration information for the first serial port. + // + + if (LoaderBlock != NULL) { + MatchKey = 0; + ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot, + ControllerClass, + SerialController, + &MatchKey); + + } else { + ConfigurationEntry = NULL; + } + + if (DebugParameters->BaudRate != 0) { + BaudRate = DebugParameters->BaudRate; + } else { + BaudRate = 19200; + } + // + // If the serial configuration entry was not found or the frequency + // specified is not supported, then default the baud rate divisor to + // six, which is 19.2Kbps. Otherwise, set the baud rate divisor + // to the correct value for 19.2 baud communication. + // + + BaudClock = 1843200; + + if (ConfigurationEntry != NULL) { + List = (PCM_PARTIAL_RESOURCE_LIST)ConfigurationEntry->ConfigurationData; + Descriptor = &List->PartialDescriptors[List->Count]; + DeviceData = (PCM_SERIAL_DEVICE_DATA)Descriptor; + if ((DeviceData->BaudClock == 1843200) || + (DeviceData->BaudClock == 4233600) || + (DeviceData->BaudClock == 8000000)) { + BaudClock = DeviceData->BaudClock; + } + } + + HalpBaudRateDivisor = (UCHAR)(BaudClock / (BaudRate*16)); + + // + // round up + // + Remainder = BaudClock % (BaudRate*16); + if ((Remainder*2) > BaudClock) { + HalpBaudRateDivisor++; + } + + // + // If the debugger is not being enabled, then return. + // + + if (Initialize == FALSE) { + return TRUE; + } + + // + // Establish pointers to serial line register structures + // + + KdComPortInUse = (PUCHAR)HalpMapDebugPort( + DebugParameters->CommunicationPort, + (PULONG)&SP_READ, + (PULONG)&SP_WRITE ); + + // + // Clear the divisor latch, clear all interrupt enables, and reset and + // disable the FIFO's. + // + + WRITE_PORT_UCHAR( &SP_WRITE->LineControl, 0x0 ); + WRITE_PORT_UCHAR( &SP_WRITE->InterruptEnable, 0x0 ); + + + // We shouldn't have to do anything with the FIFO here - + + // + // Set the divisor latch and set the baud rate to 19200 baud. + // + // Note: the references to TransmitBuffer and InterruptEnable are + // actually the Divisor Latch LSB and MSB registers respectively + DataByte = 0; + ((PSP_LINE_CONTROL)(&DataByte))->DivisorLatch = 1; + WRITE_PORT_UCHAR(&SP_WRITE->LineControl, DataByte); + WRITE_PORT_UCHAR(&SP_WRITE->TransmitBuffer, HalpBaudRateDivisor); + WRITE_PORT_UCHAR(&SP_WRITE->InterruptEnable, 0x0); + + // + // Clear the divisor latch and set the character size to eight bits + // with one stop bit and no parity checking. + // + + DataByte = 0; + ((PSP_LINE_CONTROL)(&DataByte))->CharacterSize = EIGHT_BITS; + WRITE_PORT_UCHAR(&SP_WRITE->LineControl, DataByte); + + // + // Set data terminal ready and request to send. + // + + DataByte = 0; + ((PSP_MODEM_CONTROL)(&DataByte))->DataTerminalReady = 1; + ((PSP_MODEM_CONTROL)(&DataByte))->RequestToSend = 1; + WRITE_PORT_UCHAR(&SP_WRITE->ModemControl, DataByte); + + return TRUE; + +} + +ULONG +KdPortGetByte ( + OUT PUCHAR Input + ) + +/*++ + +Routine Description: + + This routine gets a byte from the serial port used by the kernel + debugger. + + N.B. It is assumed that the IRQL has been raised to the highest + level, and necessary multiprocessor synchronization has been + performed before this routine is called. + +Arguments: + + Input - Supplies a pointer to a variable that receives the input + data byte. + +Return Value: + + CP_GET_SUCCESS is returned if a byte is successfully read from the + kernel debugger line. + + CP_GET_ERROR is returned if an error is encountered during reading. + + CP_GET_NODATA is returned if timeout occurs. + +--*/ + +{ + + return HalpGetByte(Input, TRUE); +} + +ULONG +KdPortPollByte ( + OUT PUCHAR Input + ) + +/*++ + +Routine Description: + + This routine gets a byte from the serial port used by the kernel + debugger iff a byte is available. + + N.B. It is assumed that the IRQL has been raised to the highest + level, and necessary multiprocessor synchronization has been + performed before this routine is called. + +Arguments: + + Input - Supplies a pointer to a variable that receives the input + data byte. + +Return Value: + + CP_GET_SUCCESS is returned if a byte is successfully read from the + kernel debugger line. + + CP_GET_ERROR is returned if an error encountered during reading. + + CP_GET_NODATA is returned if timeout occurs. + +--*/ + +{ + + ULONG Status; + + // + // Save port status, map the serial controller, get byte from the + // debugger port is one is avaliable, restore port status, unmap + // the serial controller, and return the operation status. + // + + KdPortSave(); + Status = HalpGetByte(Input, FALSE); + KdPortRestore(); + return Status; +} + +VOID +KdPortPutByte ( + IN UCHAR Output + ) + +/*++ + +Routine Description: + + This routine puts a byte to the serial port used by the kernel debugger. + + N.B. It is assumed that the IRQL has been raised to the highest level, + and necessary multiprocessor synchronization has been performed + before this routine is called. + +Arguments: + + Output - Supplies the output data byte. + +Return Value: + + None. + +--*/ + +{ + UCHAR DataByte; + + if (KdUseModemControl) { + // + // Modem control, make sure DSR, CTS and CD are all set before + // sending any data. + // + + for (; ;) { + DataByte = READ_PORT_UCHAR(&SP_READ->ModemStatus); + if ( ((PSP_MODEM_STATUS)&DataByte)->ClearToSend && + ((PSP_MODEM_STATUS)&DataByte)->DataSetReady && + ((PSP_MODEM_STATUS)&DataByte)->ReceiveDetect ) { + break; + } + + KdReadLsr(FALSE); + } + } + + // + // Wait for transmit ready. + // + + while (KdReadLsr(FALSE).TransmitHoldingEmpty == 0 ); + + // + // Wait for data set ready. + // + +// do { +// LsrByte = READ_PORT_UCHAR(&SP_READ->ModemStatus); +// } while (((PSP_MODEM_STATUS)(&LsrByte))->DataSetReady == 0); + + // + // Transmit data. + // + + WRITE_PORT_UCHAR(&SP_WRITE->TransmitBuffer, Output); + return; + +} + +VOID +KdPortRestore ( + VOID + ) + +/*++ + +Routine Description: + + This routine restores the state of the serial port after the kernel + debugger has been active. + + N.B. This routine performs no function on the Jazz system. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + + return; +} + +VOID +KdPortSave ( + VOID + ) + +/*++ + +Routine Description: + + This routine saves the state of the serial port and initializes the port + for use by the kernel debugger. + + N.B. This routine performs no function on the Jazz system. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + + return; +} + + +SP_LINE_STATUS +KdReadLsr ( + IN BOOLEAN WaitReason + ) + +/*++ + +Routine Description: + + Returns current line status. + + If status which is being waited for is ready, then the function + checks the current modem status and causes a possible display update + of the current statuses. + +Arguments: + + WaitReason - Suuplies a boolean value that determines whether the line + status is required for a receive or transmit. + +Return Value: + + The current line status is returned as the function value. + +--*/ + +{ + + static UCHAR RingFlag = 0; + UCHAR DataLsr, DataMsr; + + // + // Get the line status for a receive or a transmit. + // + + DataLsr = READ_PORT_UCHAR(&SP_READ->LineStatus); + if (WaitReason) { + + // + // Get line status for receive data. + // + + if (((PSP_LINE_STATUS)&DataLsr)->DataReady) { + return *((PSP_LINE_STATUS)&DataLsr); + } + + } else { + + // + // Get line status for transmit empty. + // + + if (((PSP_LINE_STATUS)&DataLsr)->TransmitEmpty) { + return *((PSP_LINE_STATUS)&DataLsr); + } + } + + DataMsr = READ_PORT_UCHAR(&SP_READ->ModemStatus); + RingFlag |= ((PSP_MODEM_STATUS)&DataMsr)->RingIndicator ? 1 : 2; + if (RingFlag == 3) { + + // + // The ring indicate line has toggled, use modem control from + // now on. + // + + KdUseModemControl = TRUE; + } + + return *((PSP_LINE_STATUS) &DataLsr); +} diff --git a/private/ntos/nthals/halalpha/pcspeakr.c b/private/ntos/nthals/halalpha/pcspeakr.c new file mode 100644 index 000000000..912a87b2a --- /dev/null +++ b/private/ntos/nthals/halalpha/pcspeakr.c @@ -0,0 +1,136 @@ +/*++ + +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + pcspeakr.c + +Abstract: + + This module implements the HAL speaker "beep" routines for the + Alpha system that use the standard PC speaker driven by an interval + timer. + +Author: + + Jeff McLeman (mcleman) 23-Jun-1992 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" +#include "eisa.h" + + +BOOLEAN +HalMakeBeep( + IN ULONG Frequency + ) + +/*++ + +Routine Description: + + This function sets the frequency of the speaker, causing it to sound a + tone. The tone will sound until the speaker is explicitly turned off, + so the driver is responsible for controlling the duration of the tone. + +Arguments: + + Frequency - Supplies the frequency of the desired tone. A frequency of + 0 means the speaker should be shut off. + +Return Value: + + TRUE - Operation was successful (frequency within range or zero). + FALSE - Operation was unsuccessful (frequency was out of range). + Current tone (if any) is unchanged. + +--*/ + +{ + KIRQL oldIrql; + NMI_STATUS NmiStatus; + PEISA_CONTROL controlBase; + TIMER_CONTROL timerControl; + ULONG newCount; + + controlBase = HalpEisaControlBase; + + // + // Raise the IRQL to dispatch level and acquire the beep spinlock. + // + + KeAcquireSpinLock(&HalpBeepLock, &oldIrql); + + // + // Stop the speaker. + // + + *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus); + + NmiStatus.SpeakerGate = 0; + NmiStatus.SpeakerData = 0; + + WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus)); + + if (Frequency == 0) { + KeReleaseSpinLock(&HalpBeepLock, oldIrql); + return(TRUE); + } + + // + // Calculate the new counter value. + // + + newCount = TIMER_CLOCK_IN / Frequency; + + // + // The new count must be less than 16 bits in value. + // + + if (newCount >= 0x10000) { + KeReleaseSpinLock(&HalpBeepLock, oldIrql); + return(FALSE); + } + + // + // Set the speaker timer to the correct mode. + // + + timerControl.BcdMode = 0; + timerControl.Mode = TM_SQUARE_WAVE; + timerControl.SelectByte = SB_LSB_THEN_MSB; + timerControl.SelectCounter = SELECT_COUNTER_2; + + WRITE_PORT_UCHAR(&controlBase->CommandMode1, *((PUCHAR) &timerControl)); + + // + // Set the speaker timer to the correct mode. + // + + WRITE_PORT_UCHAR(&controlBase->SpeakerTone, (UCHAR)newCount); + WRITE_PORT_UCHAR(&controlBase->SpeakerTone, (UCHAR)(newCount >> 8)); + + // + // Start the speaker. + // + + NmiStatus.SpeakerGate = 1; + NmiStatus.SpeakerData = 1; + + WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus)); + + // + // Release the beep spinlock and restore the IRQL. + // + + KeReleaseSpinLock(&HalpBeepLock, oldIrql); + return(TRUE); +} diff --git a/private/ntos/nthals/halalpha/perf8254.c b/private/ntos/nthals/halalpha/perf8254.c new file mode 100644 index 000000000..7a2160408 --- /dev/null +++ b/private/ntos/nthals/halalpha/perf8254.c @@ -0,0 +1,457 @@ +/*++ + +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + perf82454.c + +Abstract: + + This module implements the interfaces that access the system + performance counter and the calibrated stall for systems that + use an external 8254 timer chip to implement the performance counter. + This module is suitable for use in multiprocessor systems. + +Author: + + Joe Notarangelo 14-Mar-1994 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" +#include "eisa.h" + +// +// Declare the global that contains the current value of the performance +// counter. +// + +ULONG HalpLastTimer; +ULONGLONG HalpTimerWrapCount; + +// +// Declare globals used to control the access to and initialization of +// the performance counter. +// + +BOOLEAN HalpPerformanceCounterInitialized = FALSE; +ULONG HalpPerformanceCounterFrequency; +KSPIN_LOCK HalpPerformanceCounterSpinLock; + +#define TIMER_START_VALUE (0xffff) + +// +// Define local routine prototypes. +// + +VOID +HalpStartTimer( + VOID + ); + +ULONG +HalpReadTimerValue( + VOID + ); + +VOID +HalCalibratePerformanceCounter ( + IN volatile PLONG Number + ) + +/*++ + +Routine Description: + + This routine is responsible for synchronizing the performance + counter across all processors in the system configuration. + For an 8254-based performance counter all that is necessary is that + the counter be initialized. + +Arguments: + + Number - Supplies a pointer to count of the number of processors in + the configuration. + +Return Value: + + None. + +--*/ + +{ + PKPRCB Prcb = PCR->Prcb; + + // + // If this isn't the primary processor, then return. + // + + if( Prcb->Number != HAL_PRIMARY_PROCESSOR ){ + return; + } + + // + // If the counter has already been initialized then simply return. + // + + if( HalpPerformanceCounterInitialized == TRUE ){ + return; + } + + // + // Initialize the spinlock for controlling access to the counter. + // + + KeInitializeSpinLock( &HalpPerformanceCounterSpinLock ); + + // + // Set the frequency of the counter. + // + + HalpPerformanceCounterFrequency = TIMER_CLOCK_IN; + + // + // Initialize the wrap count. + // + + HalpTimerWrapCount = 0; + + // + // Initialize the counter and start it. + // + + HalpStartTimer(); + + HalpLastTimer = HalpReadTimerValue(); + + // + // Mark the counter as initialized. + // + + HalpPerformanceCounterInitialized = TRUE; + +} + + +LARGE_INTEGER +KeQueryPerformanceCounter ( + OUT PLARGE_INTEGER Frequency OPTIONAL + ) + +/*++ + +Routine Description: + + This routine returns the current performance counter value and the + performance counter frequency. + +Arguments: + + Frequency - Supplies an optional pointer to a variable which receives + the performance counter frequency in Hertz. + +Return Value: + + The current performance counter value is returned as the function + value. + +--*/ + +{ + + LARGE_INTEGER LocalPerformanceCount; + KIRQL OldIrql; + ULONG TimerValue; + + // + // Return 0 if the performance counter has not been initialized yet. + // + + if( HalpPerformanceCounterInitialized == FALSE ){ + LocalPerformanceCount.QuadPart = 0; + return LocalPerformanceCount; + } + + // + // Synchronize the calculation of the performance counter with the + // clock routine executing on the boot processor. + // + + KeRaiseIrql( CLOCK_LEVEL, &OldIrql ); + KiAcquireSpinLock( &HalpPerformanceCounterSpinLock ); + + // + // Read the current value of the timer count. + // + + TimerValue = HalpReadTimerValue(); + + // + // If the timer is greater than the last timer value then the timer + // has wrapped since the last time we have read it. + // + + if( TimerValue > HalpLastTimer ){ + + HalpTimerWrapCount += (1 << 15); + } + + HalpLastTimer = TimerValue; + + LocalPerformanceCount.QuadPart = HalpTimerWrapCount + + (TIMER_START_VALUE - TimerValue)/2; + + // + // Once the value is calculated synchronization is no longer + // required. + // + + KiReleaseSpinLock( &HalpPerformanceCounterSpinLock ); + KeLowerIrql( OldIrql ); + + // + // If the frequency parameter is specified, then return the frequency + // of the 8254 counter. + // + + if (ARGUMENT_PRESENT(Frequency) != FALSE) { + Frequency->LowPart = HalpPerformanceCounterFrequency; + Frequency->HighPart = 0; + } + + // + // Return the calculated performance count. + // + + return LocalPerformanceCount; + +} + + +VOID +HalpCheckPerformanceCounter( + VOID + ) +/*++ + +Routine Description: + + This function is called every system clock interrupt in order to + check for wrap of the performance counter. The function must handle + a wrap if it is detected. + + N.B. - This function must be called at CLOCK_LEVEL. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + + ULONG TimerValue; + + // + // Synchronize the performance counter check with any possible + // readers. + // + + KiAcquireSpinLock( &HalpPerformanceCounterSpinLock ); + + // + // Read the current value of the timer count. + // + + TimerValue = HalpReadTimerValue(); + + // + // If the timer is greater than the last timer value then the timer + // has wrapped since the last time we have read it. + // + + if( TimerValue > HalpLastTimer ){ + + HalpTimerWrapCount += (1 << 15); + } + + HalpLastTimer = TimerValue; + + KiReleaseSpinLock( &HalpPerformanceCounterSpinLock ); + + return; + +} + + +VOID +KeStallExecutionProcessor ( + IN ULONG MicroSeconds + ) + +/*++ + +Routine Description: + + This function stalll execution of the current processor for the specified + number of microseconds. + +Arguments: + + MicroSeconds - Supplies the number of microseconds that execution is to + be stalled. + +Return Value: + + None. + +--*/ + +{ + + LONG StallCyclesRemaining; // signed value + ULONG PreviousRpcc, CurrentRpcc; + + // + // Get the value of the RPCC as soon as we enter + // + + PreviousRpcc = HalpRpcc(); + + // + // Compute the number of cycles to stall + // + + StallCyclesRemaining = MicroSeconds * HalpClockMegaHertz; + + // + // Wait while there are stall cycles remaining. + // The accuracy of this routine is limited by the + // length of this while loop. + // + + while (StallCyclesRemaining > 0) { + + CurrentRpcc = HalpRpcc(); + + // + // The subtraction always works because the Rpcc + // is a wrapping long-word. If it wraps, we still + // get the positive number we want. + // + + StallCyclesRemaining -= (CurrentRpcc - PreviousRpcc); + + // + // remember this RPCC value + // + + PreviousRpcc = CurrentRpcc; + } + +} + + +VOID +HalpStartTimer( + VOID + ) +/*++ + +Routine Description: + + Start the timer used to maintain the performance count. The timer used + is counter 0 in timer 1 - it is an 8254-compatible timer. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + TIMER_CONTROL TimerControl; + + // + // Set the timer for counter 0 in binary mode. Write the counter + // with the LSB then MSB of the TIMER_START_VALUE. + // + + TimerControl.BcdMode = 0; + TimerControl.Mode = TM_SQUARE_WAVE; + TimerControl.SelectByte = SB_LSB_THEN_MSB; + TimerControl.SelectCounter = SELECT_COUNTER_0; + + WRITE_PORT_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->CommandMode1, + *(PUCHAR)&TimerControl ); + + WRITE_PORT_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->Timer1, + TIMER_START_VALUE & 0xff ); + + WRITE_PORT_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->Timer1, + (TIMER_START_VALUE >> 8) & 0xff ); + + + return; + +} + + +ULONG +HalpReadTimerValue( + VOID + ) +/*++ + +Routine Description: + + Read the current value from the timer used to maintain the performance + count. The timer used is counter 0 in timer - it is an 8254-compatible + timer. + +Arguments: + + None. + +Return Value: + + The current count value of the timer is returned. + +--*/ +{ + UCHAR Lsb; + UCHAR Msb; + TIMER_CONTROL TimerControl; + + // + // Set the counter for a latched read, read it Lsb then Msb. + // + + TimerControl.BcdMode = 0; + TimerControl.Mode = 0; + TimerControl.SelectByte = SB_COUNTER_LATCH; + TimerControl.SelectCounter = SELECT_COUNTER_0; + + WRITE_PORT_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->CommandMode1, + *(PUCHAR)&TimerControl ); + + Lsb = READ_PORT_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->Timer1 ); + + Msb = READ_PORT_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->Timer1 ); + + return (ULONG)( (Msb << 8) | Lsb ); + +} diff --git a/private/ntos/nthals/halalpha/perfcntr.c b/private/ntos/nthals/halalpha/perfcntr.c new file mode 100644 index 000000000..6e1791443 --- /dev/null +++ b/private/ntos/nthals/halalpha/perfcntr.c @@ -0,0 +1,260 @@ +/*++ + +Copyright (c) 1992, 1993 Digital Equipment Corporation + +Module Name: + + perfcntr.c + +Abstract: + + This module implements the interfaces that access the system + performance counter and the calibrated stall. The functions implemented + in this module are suitable for uniprocessor systems only. + +Author: + + Jeff McLeman (mcleman) 05-June-1992 + +Environment: + + Kernel mode + +Revision History: + + + Rod Gamache [DEC] 9-Mar-1993 + Fix profile clock. + + +--*/ + +#include "halp.h" +#include "eisa.h" + +// +// Define and initialize the 64-bit count of total system cycles used +// as the performance counter. +// + +ULONGLONG HalpCycleCount = 0; + + +LARGE_INTEGER +KeQueryPerformanceCounter ( + OUT PLARGE_INTEGER Frequency OPTIONAL + ) + +/*++ + +Routine Description: + + This routine returns the current performance counter value and the + performance counter frequency. + +Arguments: + + Frequency - Supplies an optional pointer to a variable which receives + the performance counter frequency in Hertz. + +Return Value: + + The current performance counter value is returned as the function + value. + +--*/ + +{ + + LARGE_INTEGER LocalRpccTime; + ULONG RpccValue; + + // + // Obtain the current value of the processor cycle counter and adjust + // the upper 32 bits if a roll-over occurred since the last time the + // Rpcc value was checked (at least oncce per clock interrupt). This + // code may be interrupted so we must fetch HalpRpccTimec atomically. + // + + *(PULONGLONG)&LocalRpccTime = HalpCycleCount; + RpccValue = HalpRpcc(); + if (RpccValue < LocalRpccTime.LowPart) { + LocalRpccTime.HighPart += 1; + } + LocalRpccTime.LowPart = RpccValue; + + + // + // If the frequency parameter is specified, then return the performance + // counter frequency as the current system time frequency. + // + + if (ARGUMENT_PRESENT(Frequency) != FALSE) { + Frequency->LowPart = HalpClockFrequency; + Frequency->HighPart = 0; + } + + // + // Return the current processor cycle counter as the function value. + // + + return LocalRpccTime; +} + + +VOID +HalCalibratePerformanceCounter ( + IN volatile PLONG Number + ) + +/*++ + +Routine Description: + + This routine resets the performance counter value for the current + processor to zero. The reset is done such that the resulting value + is closely synchronized with other processors in the configuration. + +Arguments: + + Number - Supplies a pointer to count of the number of processors in + the configuration. + +Return Value: + + None. + +--*/ + +{ + + // + // ****** Warning ****** + // + // This is a stub routine. It should clear the current value of the + // performance counter. It is really only needed in an MP system where, + // close, but not exact synchronization of the performance counters + // are needed. See MIPS code in halfxs\mips\j4prof.c for a method of + // synchronizing. + // + + return; +} + + +VOID +HalpCheckPerformanceCounter( + VOID + ) +/*++ + +Routine Description: + + This function is called every system clock interrupt in order to + check for wrap of the performance counter. The function must handle + a wrap if it is detected. + + N.B. - This function must be called at CLOCK_LEVEL. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + + LARGE_INTEGER LocalRpccTime; + ULONG RpccValue; + + // + // Update the low part of the performance counter directly from the + // rpcc count. Check for wrap of the rpcc count, if wrap has occurred + // then increment the high part of the performance counter. + // + + LocalRpccTime.QuadPart = HalpCycleCount; + RpccValue = HalpRpcc(); + + if (RpccValue < LocalRpccTime.LowPart) { + LocalRpccTime.HighPart += 1; + } + + LocalRpccTime.LowPart = RpccValue; + + HalpCycleCount = LocalRpccTime.QuadPart; + + return; + +} + + +VOID +KeStallExecutionProcessor ( + IN ULONG Microseconds + ) + +/*++ + +Routine Description: + + This function stalll execution of the current processor for the specified + number of microseconds. + +Arguments: + + Microseconds - Supplies the number of microseconds to stall. + +Return Value: + + None. + +--*/ + +{ + + LONG StallCyclesRemaining; // signed value + ULONG PreviousRpcc, CurrentRpcc; + + // + // Get the value of the RPCC as soon as we enter + // + + PreviousRpcc = HalpRpcc(); + + // + // Compute the number of cycles to stall + // + + StallCyclesRemaining = Microseconds * HalpClockMegaHertz; + + // + // Wait while there are stall cycles remaining. + // The accuracy of this routine is limited by the + // length of this while loop. + // + + while (StallCyclesRemaining > 0) { + + CurrentRpcc = HalpRpcc(); + + // + // The subtraction always works because the Rpcc + // is a wrapping long-word. If it wraps, we still + // get the positive number we want. + // + + StallCyclesRemaining -= (CurrentRpcc - PreviousRpcc); + + // + // remember this RPCC value + // + + PreviousRpcc = CurrentRpcc; + } + +} + diff --git a/private/ntos/nthals/halalpha/t2.c b/private/ntos/nthals/halalpha/t2.c new file mode 100644 index 000000000..19ada2b78 --- /dev/null +++ b/private/ntos/nthals/halalpha/t2.c @@ -0,0 +1,760 @@ +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + t2.c + +Abstract: + + This module implements functions that are specific to the T2 chip. + The T2 chip is a system support chip that bridges between the + CBUS2 and the PCI bus. + +Author: + + Joe Notarangelo 18-Oct-1993 + Steve Jenness 18-Oct-1993 + +Environment: + + Kernel mode + +Revision History: + + Steve Brooks 30-Dec-1994 + + Remove sable specific references and move to common halalpha directory + +--*/ + +#include "halp.h" + +extern ULONG HalDisablePCIParityChecking; + +#ifdef HALDBG + +ULONG T2Debug; + +VOID +DumpT2( + VOID + ); + +VOID +DumpT4( + VOID + ); + +#define DebugDumpT2(DebugPrintLevel) \ + if (DebugPrintLevel <= T2Debug) \ + DumpT2() + +#else //HALDBG + +#define DebugDumpT2(a) + +#endif //HALDBG + +VOID +HalpT2InitializeSfwWindow( + PWINDOW_CONTROL_REGISTERS WindowRegisters, + T2_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 T2IsaWindow: + + WindowRegisters->WindowBase = (PVOID)ISA_DMA_WINDOW_BASE; + WindowRegisters->WindowSize = ISA_DMA_WINDOW_SIZE; + + WindowRegisters->TranslatedBaseRegister[0] = + &((PT2_CSRS)(T2_CSRS_QVA))->Tbase1; + WindowRegisters->WindowBaseRegister[0] = + &((PT2_CSRS)(T2_CSRS_QVA))->Wbase1; + WindowRegisters->WindowMaskRegister[0] = + &((PT2_CSRS)(T2_CSRS_QVA))->Wmask1; + WindowRegisters->WindowTbiaRegister[0] = + &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr; + + WindowRegisters->TranslatedBaseRegister[1] = NULL; + WindowRegisters->WindowBaseRegister[1] = NULL; + WindowRegisters->WindowMaskRegister[1] = NULL; + WindowRegisters->WindowTbiaRegister[1] = NULL; + + break; + + case T2MasterWindow: + + WindowRegisters->WindowBase = (PVOID)MASTER_DMA_WINDOW_BASE; + WindowRegisters->WindowSize = MASTER_DMA_WINDOW_SIZE; + + WindowRegisters->TranslatedBaseRegister[0] = + &((PT2_CSRS)(T2_CSRS_QVA))->Tbase2; + WindowRegisters->WindowBaseRegister[0] = + &((PT2_CSRS)(T2_CSRS_QVA))->Wbase2; + WindowRegisters->WindowMaskRegister[0] = + &((PT2_CSRS)(T2_CSRS_QVA))->Wmask2; + WindowRegisters->WindowTbiaRegister[0] = + &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr; + + WindowRegisters->TranslatedBaseRegister[1] = + &((PT2_CSRS)(T4_CSRS_QVA))->Tbase2; + WindowRegisters->WindowBaseRegister[1] = + &((PT2_CSRS)(T4_CSRS_QVA))->Wbase2; + WindowRegisters->WindowMaskRegister[1] = + &((PT2_CSRS)(T4_CSRS_QVA))->Wmask2; + WindowRegisters->WindowTbiaRegister[1] = + &((PT2_CSRS)(T4_CSRS_QVA))->Iocsr; + + + break; + + default: + +#if HALDBG + + DbgPrint( "T2InitializeSfwWindow: Bad Window Number = %x\n", + WindowNumber ); + +#endif //HALDBG + + break; + + } + + return; +} + + +VOID +HalpT2ProgramDmaWindow( + 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. + +--*/ +{ + T2_WBASE PciBase; + T2_WMASK PciMask; + T2_TBASE Tbase; + + PciBase.all = 0; + PciBase.EnablePciWindow = 1; + PciBase.EnableScatterGather = 1; + PciBase.PciWindowStartAddress = (ULONG)(WindowRegisters->WindowBase) >> 20; + PciBase.PciWindowEndAddress = + ((ULONG)(WindowRegisters->WindowBase) + + WindowRegisters->WindowSize - 1) >> 20; + + PciMask.all = 0; + PciMask.PciWindowMask = (WindowRegisters->WindowSize >> 20) - 1; + + Tbase.all = 0; + Tbase.TranslatedBaseAddress = (ULONG)(MapRegisterBase) >> 10; + + // + // Dump the T2 registers. + // + + DebugDumpT2(5); + + // + // Clear the window base, temporarily disabling transactions to this + // DMA window. + // + + WRITE_T2_REGISTER( WindowRegisters->WindowBaseRegister[0], (ULONGLONG)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_T2_REGISTER( WindowRegisters->TranslatedBaseRegister[0], + *(PULONGLONG)&Tbase ); + + WRITE_T2_REGISTER( WindowRegisters->WindowMaskRegister[0], + *(PULONGLONG)&PciMask ); + + WRITE_T2_REGISTER( WindowRegisters->WindowBaseRegister[0], + *(PULONGLONG)&PciBase ); + +// smjfix - Turn on Hole 1 and 2 to make access to +// Eisa memory space work. This is currently used to +// to allow access to the Qvision frame buffer at 4Mbytes. +// Note that the StartAddress and EndAddress need to be +// shifted by 1 bit (in contrast to the T2 spec). +// Currently memory devices on Sable have to be 0-16Mbytes or +// above 2Gbytes. + + { + T2_HBASE Hbase; + + Hbase.all = 0; + Hbase.HoleStartAddress = 0x40 << 1; // 4 Mbytes + Hbase.HoleEndAddress = 0x4f << 1; // 5 Mbytes - 1 + Hbase.Hole1Enable = 1; + Hbase.Hole2Enable = 1; + + WRITE_T2_REGISTER( &((PT2_CSRS)(T2_CSRS_QVA))->Hbase, + *(PULONGLONG)&Hbase ); + } + +#if defined(XIO_PASS1) || defined(XIO_PASS2) + + // + // If the external I/O module is present and this is *not* the ISA + // DMA window, initialize the T4 similarly. + // + + if( HalpXioPresent && WindowRegisters->WindowBaseRegister[1] != NULL ) { + +#if HALDBG + DumpT4(); +#endif + + // + // Clear the window base, temporarily disabling transactions to this + // DMA window. + // + + WRITE_T2_REGISTER( WindowRegisters->WindowBaseRegister[1], + (ULONGLONG)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_T2_REGISTER( WindowRegisters->TranslatedBaseRegister[1], + *(PULONGLONG)&Tbase ); + + WRITE_T2_REGISTER( WindowRegisters->WindowMaskRegister[1], + *(PULONGLONG)&PciMask ); + + WRITE_T2_REGISTER( WindowRegisters->WindowBaseRegister[1], + *(PULONGLONG)&PciBase ); + + // + // The external I/O module does not have a co-resident EISA/ISA + // bus, therefore, no holes are necessary. + // + + WRITE_T2_REGISTER( &((PT2_CSRS)(T4_CSRS_QVA))->Hbase, + (ULONGLONG)0 ); + +#if HALDBG + DumpT4(); +#endif + } + +#endif + + // + // Flush and enable the translation buffer inside of the T2. + // Since the TLB is maintained by bus snooping, this should be the + // only time a flush is needed. + // + + + { + ULONGLONG Value; + T2_IOCSR Iocsr; + + Value = READ_T2_REGISTER(&((PT2_CSRS)(T2_CSRS_QVA))->Iocsr); + Iocsr = *(PT2_IOCSR)&Value; + Iocsr.EnableTlb = 0; + Iocsr.FlushTlb = 1; + + WRITE_T2_REGISTER( &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr, + *(PULONGLONG)&Iocsr ); + + Iocsr.EnableTlb = 1; + Iocsr.FlushTlb = 0; + + WRITE_T2_REGISTER( &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr, + *(PULONGLONG)&Iocsr ); + +#if defined(XIO_PASS1) || defined(XIO_PASS2) + + if( HalpXioPresent ) { + + Value = READ_T2_REGISTER(&((PT2_CSRS)(T4_CSRS_QVA))->Iocsr); + Iocsr = *(PT2_IOCSR)&Value; + Iocsr.EnableTlb = 0; + Iocsr.FlushTlb = 1; + + WRITE_T2_REGISTER( &((PT2_CSRS)(T4_CSRS_QVA))->Iocsr, + *(PULONGLONG)&Iocsr ); + + Iocsr.EnableTlb = 0; + Iocsr.FlushTlb = 0; + + WRITE_T2_REGISTER( &((PT2_CSRS)(T4_CSRS_QVA))->Iocsr, + *(PULONGLONG)&Iocsr ); + +#if HALDBG + DumpT4(); +#endif + } + +#endif + + } + + // + // Dump the T2 registers. + // + + DebugDumpT2(5); + + return; +} + +VOID +HalpT2InvalidateTLB( + PWINDOW_CONTROL_REGISTERS WindowRegisters + ) +/*++ + +Routine Description: + + Invalidate the DMA Scatter/Gather TLB in the T2. This routine + is called when initializing the window registers. It is *not* + called by HAL_INVALIDATE_TRANSLATIONS because invalidating the + TLB when DMAs are in progress doesn't work on the T2. + + There is a single TLB in the T2; the WindowRegisters argument is + ignored. + +Arguments: + + WindowRegisters - Supplies a pointer to the software window register + control structure. + +Return Value: + + None. + +--*/ +{ + ULONGLONG Value; + T2_IOCSR Iocsr; + +#if 0 + + // Pass2 appears to be broken also. + +#ifndef T2PASS1ONLY + + // + // If the T2 is a Pass2 or later, flush and enable the TLB. + // + + Value = READ_T2_REGISTER(&((PT2_CSRS)(T2_CSRS_QVA))->Iocsr); + Iocsr = *(PT2_IOCSR)&Value; + + if (Iocsr.T2RevisionNumber != 0) { + + Iocsr.FlushTlb = 1; + WRITE_T2_REGISTER( &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr, + *(PULONGLONG)&Iocsr ); + + Iocsr.EnableTlb = 1; + Iocsr.FlushTlb = 0; + WRITE_T2_REGISTER( &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr, + *(PULONGLONG)&Iocsr ); + } + +#if defined(XIO_PASS1) || defined(XIO_PASS2) + + // + // Invalidate the T4's TLB... + // + + if( HalpXioPresent ){ + + Value = READ_T2_REGISTER(&((PT2_CSRS)(T4_CSRS_QVA))->Iocsr); + Iocsr = *(PT2_IOCSR)&Value; + + Iocsr.FlushTlb = 1; + WRITE_T2_REGISTER( &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr, + *(PULONGLONG)&Iocsr ); + + Iocsr.EnableTlb = 0; + Iocsr.FlushTlb = 0; + WRITE_T2_REGISTER( &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr, + *(PULONGLONG)&Iocsr ); + + } + +#endif + +#endif //T2PASS1ONLY +#endif //0 +} + +#if HALDBG + +VOID +DumpT2( + VOID + ) +/*++ + +Routine Description: + + Read the interesting T2 registers and print them to the debug port. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + PVOID RegisterQva; + PVOID TestQva; + ULONGLONG Value; + ULONG LongValue; + T2_TDR Tdr; + +// DbgPrint( "Dumping the T2 registers, " ); + +#if 0 +// +// This code tests whether the windows and holes allow access to +// the address in I/O memory space set in PhysicalAddress. +// See also the companion code at the end of this routine. +// + { + ULONG AddressSpace; + PHYSICAL_ADDRESS PhysicalAddress; + + AddressSpace = 0; + PhysicalAddress.LowPart = 0xD0000; // DE422 +// PhysicalAddress.LowPart = 0x2200000; // 34Mbytes +// PhysicalAddress.LowPart = 0x0400000; // 4Mbytes + PhysicalAddress.HighPart = 0; + HalTranslateBusAddress( Isa, 0, PhysicalAddress, &AddressSpace, &TestQva ); + + LongValue = READ_REGISTER_ULONG( TestQva ); + DbgPrint( "TestQva = %lx, Value = %x, writing 0xa5a5a5a5..\n", + TestQva, LongValue ); + LongValue = 0xa5a5a5a5; + WRITE_REGISTER_ULONG( TestQva, LongValue ); + LongValue = READ_REGISTER_ULONG( TestQva ); + DbgPrint( "TestQva = %lx, Value = %x\n", TestQva, LongValue ); + } +#endif // 0 + +#if 0 + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Iocsr = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Ivrpr; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Ivrpr = %Lx\n", Value ); + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Hae0_1; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Hae0_1 = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Hae0_2; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Hae0_2 = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Hbase; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Hbase = %Lx\n", Value ); + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Wbase1; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Wbase1 = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Wmask1; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Wmask1 = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tbase1; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Tbase1 = %Lx\n", Value ); + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Wbase2; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Wbase2 = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Wmask2; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Wmask2 = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tbase2; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Tbase2 = %Lx\n", Value ); + +#endif // 0 + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tdr0; + Value = READ_T2_REGISTER( RegisterQva ); + Tdr = *(PT2_TDR)&Value; + DbgPrint( "Tdr0 PFN=%x, V=%x, Tag=%x, ", Tdr.Pfn, Tdr.Valid, Tdr.Tag ); + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tdr1; + Value = READ_T2_REGISTER( RegisterQva ); + Tdr = *(PT2_TDR)&Value; + DbgPrint( "Tdr1 PFN=%x, V=%x, Tag=%x\n", Tdr.Pfn, Tdr.Valid, Tdr.Tag ); + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tdr2; + Value = READ_T2_REGISTER( RegisterQva ); + Tdr = *(PT2_TDR)&Value; + DbgPrint( "Tdr2 PFN=%x, V=%x, Tag=%x, ", Tdr.Pfn, Tdr.Valid, Tdr.Tag ); + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tdr3; + Value = READ_T2_REGISTER( RegisterQva ); + Tdr = *(PT2_TDR)&Value; + DbgPrint( "Tdr3 PFN=%x, V=%x, Tag=%x\n", Tdr.Pfn, Tdr.Valid, Tdr.Tag ); + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tdr4; + Value = READ_T2_REGISTER( RegisterQva ); + Tdr = *(PT2_TDR)&Value; + DbgPrint( "Tdr4 PFN=%x, V=%x, Tag=%x, ", Tdr.Pfn, Tdr.Valid, Tdr.Tag ); + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tdr5; + Value = READ_T2_REGISTER( RegisterQva ); + Tdr = *(PT2_TDR)&Value; + DbgPrint( "Tdr5 PFN=%x, V=%x, Tag=%x\n", Tdr.Pfn, Tdr.Valid, Tdr.Tag ); + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tdr6; + Value = READ_T2_REGISTER( RegisterQva ); + Tdr = *(PT2_TDR)&Value; + DbgPrint( "Tdr6 PFN=%x, V=%x, Tag=%x, ", Tdr.Pfn, Tdr.Valid, Tdr.Tag ); + + RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tdr7; + Value = READ_T2_REGISTER( RegisterQva ); + Tdr = *(PT2_TDR)&Value; + DbgPrint( "Tdr7 PFN=%x, V=%x, Tag=%x\n", Tdr.Pfn, Tdr.Valid, Tdr.Tag ); + +#if 0 + LongValue = READ_REGISTER_ULONG( TestQva ); + DbgPrint( "TestQva = %lx, Value = %x, writing 0xc3c3c3c3..\n", + TestQva, LongValue ); + LongValue = 0xc3c3c3c3; + WRITE_REGISTER_ULONG( TestQva, LongValue ); + LongValue = READ_REGISTER_ULONG( TestQva ); + DbgPrint( "TestQva = %lx, Value = %x\n", TestQva, LongValue ); +#endif // 0 + +// DbgPrint( "--end T2 dump\n\n" ); + + return; + +} + +#endif //HALDBG + +#if HALDBG && defined(XIO_PASS1) || defined(XIO_PASS2) + +VOID +DumpT4( + VOID + ) +/*++ + +Routine Description: + + Read the interesting T2 registers and print them to the debug port. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + PVOID RegisterQva; + ULONGLONG Value; + ULONG LongValue; + T2_TDR Tdr; + + if( !HalpXioPresent ){ + DbgPrint( "XIO module not present.\n" ); + return; + } + + DbgPrint( "Dumping the T4 registers:\n" ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Iocsr; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Iocsr = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Ivrpr; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Ivrpr = %Lx\n", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Hae0_1; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Hae0_1 = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Hae0_2; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Hae0_2 = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Hae0_3; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Hae0_3 = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Hae0_4; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Hae0_4 = %Lx\n", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Hbase; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Hbase = %Lx\n", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Wbase1; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Wbase1 = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Wmask1; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Wmask1 = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tbase1; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Tbase1 = %Lx\n", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Wbase2; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Wbase2 = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Wmask2; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Wmask2 = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tbase2; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Tbase2 = %Lx\n", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Wbase3; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Wbase3 = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Wmask3; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Wmask3 = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tbase3; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Tbase3 = %Lx\n", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Wbase4; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Wbase4 = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Wmask4; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Wmask4 = %Lx, ", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tbase4; + Value = READ_T2_REGISTER( RegisterQva ); + DbgPrint( "Tbase4 = %Lx\n", Value ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tdr0; + Value = READ_T2_REGISTER( RegisterQva ); + Tdr = *(PT2_TDR)&Value; + DbgPrint( "Tdr0 PFN=%x, V=%x, Tag=%x, ", Tdr.Pfn, Tdr.Valid, Tdr.Tag ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tdr1; + Value = READ_T2_REGISTER( RegisterQva ); + Tdr = *(PT2_TDR)&Value; + DbgPrint( "Tdr1 PFN=%x, V=%x, Tag=%x\n", Tdr.Pfn, Tdr.Valid, Tdr.Tag ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tdr2; + Value = READ_T2_REGISTER( RegisterQva ); + Tdr = *(PT2_TDR)&Value; + DbgPrint( "Tdr2 PFN=%x, V=%x, Tag=%x, ", Tdr.Pfn, Tdr.Valid, Tdr.Tag ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tdr3; + Value = READ_T2_REGISTER( RegisterQva ); + Tdr = *(PT2_TDR)&Value; + DbgPrint( "Tdr3 PFN=%x, V=%x, Tag=%x\n", Tdr.Pfn, Tdr.Valid, Tdr.Tag ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tdr4; + Value = READ_T2_REGISTER( RegisterQva ); + Tdr = *(PT2_TDR)&Value; + DbgPrint( "Tdr4 PFN=%x, V=%x, Tag=%x, ", Tdr.Pfn, Tdr.Valid, Tdr.Tag ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tdr5; + Value = READ_T2_REGISTER( RegisterQva ); + Tdr = *(PT2_TDR)&Value; + DbgPrint( "Tdr5 PFN=%x, V=%x, Tag=%x\n", Tdr.Pfn, Tdr.Valid, Tdr.Tag ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tdr6; + Value = READ_T2_REGISTER( RegisterQva ); + Tdr = *(PT2_TDR)&Value; + DbgPrint( "Tdr6 PFN=%x, V=%x, Tag=%x, ", Tdr.Pfn, Tdr.Valid, Tdr.Tag ); + + RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tdr7; + Value = READ_T2_REGISTER( RegisterQva ); + Tdr = *(PT2_TDR)&Value; + DbgPrint( "Tdr7 PFN=%x, V=%x, Tag=%x\n", Tdr.Pfn, Tdr.Valid, Tdr.Tag ); + + DbgPrint( "--end T4 dump\n\n" ); +} + +#endif //HALDBG diff --git a/private/ntos/nthals/halalpha/t2.h b/private/ntos/nthals/halalpha/t2.h new file mode 100644 index 000000000..40b0c5136 --- /dev/null +++ b/private/ntos/nthals/halalpha/t2.h @@ -0,0 +1,550 @@ +/*++ + +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + t2.h + +Abstract: + + This file defines the structures and definitions describing the + T2 chipset + +Author: + + Steve Brooks 28-Dec 1994 + +Environment: + + Kernel mode + +Revision History: + + Extracted from sable.h to be platform independent for sable, gamma & lynx + +--*/ + +#ifndef _T2H_ +#define _T2H_ + +// +// N.B. The structure below defines the address offsets of the control +// registers when used with the base QVA. It does NOT define the +// size or structure of the individual registers. +// + + +typedef struct _T2_CSRS { + UCHAR Iocsr; // I/O Control/Status Register + UCHAR Cerr1; // CBUS Error Register 1 + UCHAR Cerr2; // CBUS Error Register 2 + UCHAR Cerr3; // CBUS Error Register 3 + UCHAR Perr1; // PCI Error Register 1 + UCHAR Perr2; // PCI Error Register 2 + UCHAR Pscr; // PCI Special Cycle Register + UCHAR Hae0_1; // High Address Extension Register 1 + UCHAR Hae0_2; // High Address Extension Register 2 + UCHAR Hbase; // PCI Hole Base Register + UCHAR Wbase1; // Window Base Register 1 + UCHAR Wmask1; // Window Mask Register 1 + UCHAR Tbase1; // Translated Base Register 1 + UCHAR Wbase2; // Window Base Register 2 + UCHAR Wmask2; // Window Mask Register 2 + UCHAR Tbase2; // Translated Base Register 2 + UCHAR Tlbbr; // TLB Bypass Register + UCHAR Ivrpr; // IVR Passive Release Register + UCHAR Hae0_3; // High Address Extension Register 3 + UCHAR Hae0_4; // High Address Extension Register 4 + UCHAR Wbase3; // Window Base Register 3 (T3/T4) + UCHAR Wmask3; // Window Mask Register 3 (T3/T4) + UCHAR Tbase3; // Translated Base Register 3 (T3/T4) + UCHAR filler0; + UCHAR Tdr0; // TLB Data Register 0 + UCHAR Tdr1; // TLB Data Register 1 + UCHAR Tdr2; // TLB Data Register 2 + UCHAR Tdr3; // TLB Data Register 3 + UCHAR Tdr4; // TLB Data Register 4 + UCHAR Tdr5; // TLB Data Register 5 + UCHAR Tdr6; // TLB Data Register 6 + UCHAR Tdr7; // TLB Data Register 7 + UCHAR Wbase4; // Window Base Register 4 (T3/T4) + UCHAR Wmask4; // Window Mask Register 4 (T3/T4) + UCHAR Tbase4; // Translated Base Register 4 (T3/T4) + UCHAR Air; // Address Indirection Register (T3/T4) + UCHAR Var; // Vector Access Register (T3/T4) + UCHAR Dir; // Data Indirection Register (T3/T4) + UCHAR Ice; // IC Enable Register (T3/T4) +} T2_CSRS, *PT2_CSRS; + +// +// Define formats of useful T2 registers. +// + +typedef union _T2_IOCSR { + struct { + ULONG EnableReadIoReq: 1; // 00 - P2 Defunct, MBZ + ULONG EnableLoopBack: 1; // 01 + ULONG EnableStateMachineVisibility: 1; // 02 + ULONG PciDriveBadParity: 1; // 03 + ULONG Mba0: 1; // 04 + ULONG Mba1: 1; // 05 + ULONG PciInterrupt: 1; // 06 + ULONG EnableTlbErrorCheck: 1; // 07 + ULONG EnableCxAckCheckForDma: 1; // 08 + ULONG EnableDenseWrap: 1; // 09 + ULONG CbusEnableExclusiveExchange: 1; // 10 + ULONG Pci64Enable: 1; // 11 + ULONG CbusCAWriteWrongParity0: 1; // 12 + ULONG CbusCAWriteWrongParity2: 1; // 13 + ULONG CbusCADataWriteWrongParityEven: 1; // 14 + ULONG Mba5: 1; // 15 + ULONG Mba6: 1; // 16 - P2 Power Supply Error + ULONG Mba7: 1; // 17 + ULONG Mba2: 1; // 18 + ULONG Mba3: 1; // 19 + ULONG PciDmaWriteWrongParityHW1: 1; // 20 + ULONG PciDmaWriteWrongParityHW0: 1; // 21 + ULONG PciBusReset: 1; // 22 + ULONG PciInterfaceReset: 1; // 23 + ULONG EnableCbusErrorInterrupt: 1; // 24 + ULONG EnablePciMemorySpace: 1; // 25 + ULONG EnableTlb: 1; // 26 + ULONG EnableHogMode: 1; // 27 + ULONG FlushTlb: 1; // 28 + ULONG EnableCbusParityCheck: 1; // 29 + ULONG CbusInterfaceReset: 1; // 30 + ULONG EnablePciLock: 1; // 31 + ULONG EnableCbusBackToBackCycle: 1; // 32 + ULONG T2RevisionNumber: 3; // 33 + ULONG StateMachineVisibilitySelect: 3; // 36 + ULONG Mba4: 1; // 39 + ULONG EnablePassiveRelease: 1; // 40 + ULONG EnablePciRdp64: 1; // 41 (T4) + ULONG EnablePciAp64: 1; // 42 (T4) + ULONG EnablePciWdp64: 1; // 43 (T4) + ULONG CbusCAWriteWrongParity1: 1; // 44 + ULONG CbusCAWriteWrongParity3: 1; // 45 + ULONG CbusCADataWriteWrongParityOdd: 1; // 46 + ULONG T2T4Status: 1; // 47 + ULONG EnablePpc1: 1; // 48 (T3/T4) + ULONG EnablePpc2: 1; // 49 (T3/T4) + ULONG EnablePciStall: 1; // 50 (T3/T4) + ULONG Mbz0: 1; // 51 + ULONG PciReadMultiple: 1; // 52 + ULONG PciWriteMultiple: 1; // 53 + ULONG ForcePciRdpeDetect: 1; // 54 + ULONG ForcePciApeDetect: 1; // 55 + ULONG ForcePciWdpeDetect: 1; // 56 + ULONG EnablePciNmi: 1; // 57 + ULONG EnablePciDti: 1; // 58 + ULONG EnablePciSerr: 1; // 59 + ULONG EnablePciPerr: 1; // 60 + ULONG EnablePciRdp: 1; // 61 + ULONG EnablePciAp: 1; // 62 + ULONG EnablePciWdp: 1; // 63 + }; + ULONGLONG all; +} T2_IOCSR, *PT2_IOCSR; + +typedef union _T2_CERR1 { + struct { + ULONG UncorrectableReadError: 1; // 00 + ULONG NoAcknowledgeError: 1; // 01 + ULONG CommandAddressParityError: 1; // 02 + ULONG MissedCommandAddressParity: 1; // 03 + ULONG ResponderWriteDataParityError: 1; // 04 + ULONG MissedRspWriteDataParityError: 1; // 05 + ULONG ReadDataParityError: 1; // 06 + ULONG MissedReadDataParityError: 1; // 07 + ULONG CaParityErrorLw0: 1; // 08 + ULONG CaParityErrorLw2: 1; // 09 + ULONG DataParityErrorLw0: 1; // 10 + ULONG DataParityErrorLw2: 1; // 11 + ULONG DataParityErrorLw4: 1; // 12 + ULONG DataParityErrorLw6: 1; // 13 + ULONG Reserved1: 2; // 14-15 + ULONG CmdrWriteDataParityError: 1; // 16 + ULONG BusSynchronizationError: 1; // 17 + ULONG InvalidPfnError: 1; // 18 + ULONG Mbz0: 13; // 19-31 + ULONG Mbz1: 8; // 32-39 + ULONG CaParityErrorLw1: 1; // 40 + ULONG CaParityErrorLw3: 1; // 41 + ULONG DataParityErrorLw1: 1; // 42 + ULONG DataParityErrorLw3: 1; // 43 + ULONG DataParityErrorLw5: 1; // 44 + ULONG DataParityErrorLw7: 1; // 45 + ULONG Mbz2: 18; // 46-63 + }; + ULONGLONG all; +} T2_CERR1, *PT2_CERR1; + +typedef ULONGLONG T2_CERR2; +typedef ULONGLONG T2_CERR3; + +typedef union _T2_PERR1 { + struct { + ULONG WriteDataParityError: 1; // 00 + ULONG AddressParityError: 1; // 01 + ULONG ReadDataParityError: 1; // 02 + ULONG ParityError: 1; // 03 + ULONG SystemError: 1; // 04 + ULONG DeviceTimeoutError: 1; // 05 + ULONG NonMaskableInterrupt: 1; // 06 + ULONG PpcSizeError: 1; // 07 (T3/T4) + ULONG WriteDataParityError64: 1; // 08 (T3/T4) + ULONG AddressParityError64: 1; // 09 (T3/T4) + ULONG ReadDataParityError64: 1; // 10 (T3/T4) + ULONG TargetAbort: 1; // 11 (T3/T4) + ULONG Mbz0: 4; // 12-15 + ULONG ForceReadDataParityError64: 1; // 16 (T3/T4) + ULONG ForceAddressParityError64: 1; // 17 (T3/T4) + ULONG ForceWriteDataParityError64: 1; // 18 (T3/T4) + ULONG DetectTargetAbort: 1; // 19 (T3/T4) + ULONG Reserved1: 12; // 20-31 + ULONG Reserved; // 32-63 + }; + ULONGLONG all; +} T2_PERR1, *PT2_PERR1; + +typedef union _T2_PERR2 { + struct { + ULONG ErrorAddress; // 00 + ULONG PciCommand: 4; // 32 + ULONG Reserved: 28; // 36-63 + }; + ULONGLONG all; +} T2_PERR2, *PT2_PERR2; + +typedef struct _T2_WBASE { + union { + struct { + ULONG PciWindowEndAddress: 12; // 00 + ULONG Reserved0: 5; // 12 + ULONG EnablePeerToPeer: 1; // 17 + ULONG EnableScatterGather: 1; // 18 + ULONG EnablePciWindow: 1; // 19 + ULONG PciWindowStartAddress: 12; // 20 + ULONG Reserved; // 32-63 + }; + ULONGLONG all; + }; +} T2_WBASE, *PT2_WBASE; + +typedef struct _T2_WMASK { + union { + struct { + ULONG Reserved0: 20; // 00 + ULONG PciWindowMask: 11; // 20 + ULONG Reserved1: 1; // 31 + ULONG Reserved; // 32-63 + }; + ULONGLONG all; + }; +} T2_WMASK, *PT2_WMASK; + +typedef struct _T2_TBASE { + union { + struct { + ULONG Reserved0: 9; // 00 + ULONG TranslatedBaseAddress: 22; // 09 + ULONG Reserved1: 1; // 31 + ULONG Reserved; // 32-63 + }; + ULONGLONG all; + }; +} T2_TBASE, *PT2_TBASE; + +typedef struct _T2_HBASE { + union { + struct { + ULONG HoleEndAddress: 9; // 00 + ULONG Reserved1: 4; // 09 + ULONG Hole1Enable: 1; // 13 + ULONG Hole2Enable: 1; // 14 + ULONG HoleStartAddress: 9; // 15 + ULONG Reserved2: 8; // 24 + ULONG Reserved3; // 32-63 + }; + ULONGLONG all; + }; +} T2_HBASE, *PT2_HBASE; + +typedef struct _T2_TDR { + ULONG Tag: 30; // 00 + ULONG Reserved1: 2; // 30 + ULONG Valid: 1; // 32 + ULONG Pfn: 18; // 33 + ULONG Reserved2: 13; // 51 +} T2_TDR, *PT2_TDR; + +typedef union _T2_VAR { // T3/T4 Vector Address Register + struct { + ULONGLONG Vector: 6; // 00-05 + ULONGLONG Eisa: 1; // 06 + ULONGLONG PassiveRelease: 1; // 07 + ULONGLONG Reserved: 56; // 08-63 + }; + ULONGLONG all; +} T2_VAR, *PT2_VAR; + +typedef union _T2_ICE { // T3/T4 ICIC Enable Register + struct { + ULONGLONG EisaFlushAddress: 24; // 00-23 + ULONGLONG IcEnable: 1; // 24 + ULONGLONG HalfSpeedEnable: 1; // 25 + ULONGLONG Reserved: 38; // 26-63 + }; + ULONGLONG all; +} T2_ICE, *PT2_ICE; + +// +// DMA Window Values. +// +// The T2 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[2]; + PVOID WindowBaseRegister[2]; + PVOID WindowMaskRegister[2]; + PVOID WindowTbiaRegister[2]; +} WINDOW_CONTROL_REGISTERS, *PWINDOW_CONTROL_REGISTERS; + +// +// Define types of windows. +// + +typedef enum _T2_WINDOW_NUMBER { + T2IsaWindow, + T2MasterWindow +} T2_WINDOW_NUMBER, *PT2_WINDOW_NUMBER; + +// +// Define T2 Window Control routines. +// + +VOID +HalpT2InitializeSfwWindow( + PWINDOW_CONTROL_REGISTERS WindowRegisters, + T2_WINDOW_NUMBER WindowNumber + ); + +VOID +HalpT2ProgramDmaWindow( + PWINDOW_CONTROL_REGISTERS WindowRegisters, + PVOID MapRegisterBase + ); + +VOID +HalpT2InvalidateTLB( + PWINDOW_CONTROL_REGISTERS WindowRegisters + ); + +VOID +WRITE_T2_REGISTER( + PVOID, + ULONGLONG + ); + +ULONGLONG +READ_T2_REGISTER( + PVOID + ); + + +// +// 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 ) \ + HalpT2InitializeSfwWindow( (WR), T2IsaWindow ); + + +// +// VOID +// INITIALIZE_MASTER_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_MASTER_DMA_CONTROL( WR ) \ + HalpT2InitializeSfwWindow( (WR), T2MasterWindow ); + + +// +// 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 ) \ + HalpT2ProgramDmaWindow( (WR), (MRB) ); + + +// +// VOID +// INVALIDATE_DMA_TRANSLATIONS( +// PWINDOW_CONTROL_REGISTERS WindowRegisters +// ) +// +// Routine Description: +// +// Invalidate all of the cached translations for a DMA window. +// This function does not need to do any action on the T2 chip +// because the T2 snoops the bus and keeps the translations coherent +// via hardware. +// +// Arguments: +// +// WindowRegisters - Supplies a pointer to the software window control +// registers. +// +// Return Value: +// +// None. +// + +#define INVALIDATE_DMA_TRANSLATIONS( 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 // T2H diff --git a/private/ntos/nthals/halalpha/vga.c b/private/ntos/nthals/halalpha/vga.c new file mode 100644 index 000000000..c8b10394f --- /dev/null +++ b/private/ntos/nthals/halalpha/vga.c @@ -0,0 +1,608 @@ +/*++ + +Copyright (c) 1992, 1993, 1994 Digital Equipment Corporation + +Module Name: + + vga.c + +Abstract: + + This module implements device-independent HAL display initialization and + output routines for Alpha systems. + + It was stolen from a combination of the jxdisp.c routine in the firmware + directory, written by John DeRosa, and the jxdisp.c routines in the MIPS + HAL directory. + +Author: + + Miche Baker-Harvey (miche) 10-Jun-1992 + +Environment: + + Kernel mode + +Revision History: + + 12-July-1994 Eric Rehm + Support RESET_DISPLAY_PARAMETERS callback registered during + HalAcquireDisplayOwnership. This callback is supplied by + the Video Miniport driver's HwResetHw entry in the HW_INITIALIZATION_DATA + structure. + + 17-Feb-1994 Eric Rehm + Rewrite ouput routines to be device-independent through callback + to firmware VenPrint routine. + + 30-Dec-1993 Joe Notarangelo + Eliminate the video initialization code that was compiled only + when VIDEO_CALLBACK_IMPLEMENTED is not defined. It is now a + requirement that the firmware implement the callback. + + 04-Mar-1993 Joe Mitchell (DEC) + Modify HalpScrollDisplay to pause after displaying each screenful of + information during a bugcheck. + Modify InitializeVGA to call the firmware to init the video display + rather than doing the initialization itself. + + 10-Aug-1992 Jeff McLeman (DEC) + Put in debug fixes. + + 22-Jul-1992 Jeff McLeman (mcleman) + Remove inline asm(MB)s , because Hal access routines manage + read/write ordering. + +--*/ + +// +// Need some include files here +#include "halp.h" +#include "arc.h" +#include "halvga.h" +#include "fwcallbk.h" +#include "stdio.h" + +// +// Define forward referenced procedure prototypes. +// + +VOID +HalpDisplayCharacter ( + IN UCHAR Character + ); + +VOID +HalpSetLoc ( + ); + +BOOLEAN +InitializeDisplay ( + ); + +BOOLEAN +HalpInitializeDisplay ( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +VOID +HalpScrollDisplay( + VOID + ); + +VOID +HalpFlushKeyboardBuffer ( + VOID + ); + +VOID +HalpWaitForKeyPress ( + VOID + ); +typedef +ULONG +(*PFW_INITIALIZE_VIDEO_CALLBACK) ( + OUT ULONG AlphaVideoType + ); + + +// +// Define static data. +// + +BOOLEAN HalpDisplayInitialized = FALSE; +BOOLEAN HalpDisplayOwnedByHal; +ULONG HalpColumn; +ULONG HalpRow; +PUCHAR HalpDestination; +ULONG HalpForegroundColor; +ULONG HalpBackgroundColor; +ULONG DisplayWidth; +ULONG DisplayHeight; +ULONG MaxRow; +ULONG MaxColumn; + +#define CONTROL_SEQUENCE_MAX_PARAMETER 10 +ULONG Parameter[CONTROL_SEQUENCE_MAX_PARAMETER]; + +PHAL_RESET_DISPLAY_PARAMETERS HalpResetDisplayParameters; + +// +// Declare externally defined data. +// +// none. + + +BOOLEAN +HalpInitializeDisplay ( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) + +/*++ + +Routine Description: + + This routine initializes and clears the display. + + This is called during phase 0 of the Hal initialization. + +Arguments: + + LoaderBlock - Supplies a pointer to the loader parameter block. + +Return Value: + + If the initialization is successfully completed, than a value of TRUE + is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + + // + // Initialize static data. + // + + HalpColumn = 0; + HalpRow = 0; + + // + // Initialize the display controller. + // + + if (InitializeDisplay() == TRUE) { + + // + // Mark the display as successfully initialized. + // + + HalpDisplayInitialized = TRUE; + + return TRUE; + } + + return FALSE; +} + +BOOLEAN +InitializeDisplay ( + ) + +/*++ + +Routine Description: + + This routine initializes and clears the display. + + It is initialized to: alphanumeric mode, 16 colors fore & background, + 8x16 pixel fonts, 80x25 characters, 640 x 400 display. + This is not ARC compliant (no underline, no monochrome support) + but its good enough for now and can be enhanced later. (For booting, + the ARC spec is overkill anyway.) + + +Arguments: + + None. + +Return Value: + + If the video was initialized, TRUE is returned, otherwise FALSE + +--*/ + +{ + ULONG UnusedParameter; + PARC_DISPLAY_STATUS DisplayStatus; + char String[16]; + + // + // Initialize static data. + // + + HalpForegroundColor = FW_COLOR_HI_WHITE; + HalpBackgroundColor = FW_COLOR_BLUE; + + DisplayStatus = ArcGetDisplayStatus(ARC_CONSOLE_OUTPUT); + DisplayWidth = DisplayStatus->CursorMaxXPosition; + DisplayHeight = DisplayStatus->CursorMaxYPosition; + + MaxRow = DisplayHeight -1; + MaxColumn = DisplayWidth -1; + + // + // [ecr] Call the video driver to intialize the video display, + // if it has supplied a reset routine. + // + + if (HalpResetDisplayParameters) { + HalpDisplayOwnedByHal = HalpResetDisplayParameters(MaxColumn+1, MaxRow+1); + } + + // + // [jrm] Call the firmware to initialize the video display. + // + + VenVideoDisplayInitialize(&UnusedParameter); + + // + // Initialize the current display column, row, and ownership values. + // + + HalpDisplayOwnedByHal = TRUE; + + // + // Set the video memory to blue. + // + + sprintf(String, "%c%dm%c%2J", ASCII_CSI, HalpBackgroundColor+40, + ASCII_CSI); + VenPrint(String); + + + return TRUE; +} + +VOID +HalAcquireDisplayOwnership ( + IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters + ) + +/*++ + +Routine Description: + + This routine switches ownership of the display away from the HAL to + the system display driver. It is called when the system has reached + a point during bootstrap where it is self supporting and can output + its own messages. Once ownership has passed to the system display + driver any attempts to output messages using HalDisplayString must + result in ownership of the display reverting to the HAL and the + display hardware reinitialized for use by the HAL. + +Arguments: + + ResetDisplayParameters - if non-NULL the address of a function + the hal can call to reset the video card. The function returns + TRUE if the display was reset. + +Return Value: + + None. + +--*/ + +{ + + // + // Set HAL ownership of the display to false. + // + + HalpDisplayOwnedByHal = FALSE; + HalpResetDisplayParameters=ResetDisplayParameters; + + // + // Reset the display to begin in the upper left corner. + // + + HalpColumn = 0; + HalpRow = 0; + + return; +} + +VOID +HalpVideoReboot( + VOID + ) +{ + + if (HalpResetDisplayParameters && !HalpDisplayOwnedByHal) { + + // + // Video work-around. The video driver has a reset function, + // call it before resetting the system in case the bios doesn't + // know how to reset the display's video mode. + // +#if HALDBG + DbgPrint("HalpVideoReboot: calling HalpResetDisplayParameters (%x,%x)\n", + MaxColumn+1, MaxRow+1); +#endif + + HalpResetDisplayParameters(MaxColumn+1, MaxRow+1); + } +} + +VOID +HalDisplayString ( + PUCHAR String + ) + +/*++ + +Routine Description: + + This routine displays a character string on the display screen. + +Arguments: + + String - Supplies a pointer to the characters that are to be displayed. + +Return Value: + + None. + +--*/ + +{ + KIRQL OldIrql; + + // + // Note that the MIPS version of this routine goes through mapping + // the device into the users space; since we have reserved the top + // PDE in system space, we dont have to do this - its always mapped. + // + + // + // Check if the display has already been successfully initialized. + // If it has not then we cannot print on the display. + // + + if( HalpDisplayInitialized != TRUE ){ + +#if (DBG) || (HALDBG) + + DbgPrint( "HDS: %s\n", String ); + +#endif //DBG || HALDBG + + return; + + } + + // + // Raise the IRQL to dispatch level and acquire the display adapter lock. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + KiAcquireSpinLock(&HalpDisplayAdapterLock); + + // + // If ownership of the display has been switched to the system display + // driver, then reinitialize the display controller and revert ownership + // to the HAL. + // + + if (HalpDisplayOwnedByHal == FALSE) { + InitializeDisplay(); + } + + while (*String) + { + switch (*String) + { + case '\n': + if (HalpRow == MaxRow-1-1) { + HalpScrollDisplay(); + } else { + ++HalpRow; + } + HalpColumn = 0; + break; + + case '\b': + if(HalpColumn != 0) { + --HalpColumn; + } + break; + + case '\r': + HalpColumn = 0; + break; + + default: + if (HalpColumn > MaxColumn) + { + if (HalpRow == MaxRow-1-1) { + HalpScrollDisplay(); + } else { + ++HalpRow; + } + HalpColumn = 0; + } + HalpDisplayCharacter(*String); + HalpColumn++; + } + ++String; + } + + // + // Release the display adapter lock and restore the IRQL. + // + + KiReleaseSpinLock(&HalpDisplayAdapterLock); + KeLowerIrql(OldIrql); + + return; +} + +VOID +HalQueryDisplayParameters ( + OUT PULONG WidthInCharacters, + OUT PULONG HeightInLines, + OUT PULONG CursorColumn, + OUT PULONG CursorRow + ) + +/*++ + +Routine Description: + + This routine return information about the display area and current + cursor position. + +Arguments: + + WidthInCharacter - Supplies a pointer to a varible that receives + the width of the display area in characters. + + HeightInLines - Supplies a pointer to a variable that receives the + height of the display area in lines. + + CursorColumn - Supplies a pointer to a variable that receives the + current display column position. + + CursorRow - Supplies a pointer to a variable that receives the + current display row position. + +Return Value: + + None. + +--*/ + +{ + + // + // Set the display parameter values and return. + // + + *WidthInCharacters = DisplayWidth; + *HeightInLines = DisplayHeight; + *CursorColumn = HalpColumn; + *CursorRow = HalpRow; + return; +} + +VOID +HalSetDisplayParameters ( + IN ULONG CursorColumn, + IN ULONG CursorRow + ) + +/*++ + +Routine Description: + + This routine set the current cursor position on the display area. + +Arguments: + + CursorColumn - Supplies the new display column position. + + CursorRow - Supplies a the new display row position. + +Return Value: + + None. + +--*/ + +{ + + // + // Set the display parameter values and return. + // + + if (CursorColumn > DisplayWidth) { + CursorColumn = DisplayWidth; + } + + if (CursorRow > DisplayHeight) { + CursorRow = DisplayHeight; + } + + HalpColumn = CursorColumn; + HalpRow = CursorRow; + return; +} + +VOID +HalpDisplayCharacter ( + IN UCHAR Character + ) + +/*++ + +Routine Description: + + This routine displays a character at the current x and y positions in + the frame buffer. + + +Arguments: + + Character - Supplies a character to be displayed. + +Return Value: + + None. + +--*/ + +{ + char String[16]; + + sprintf(String, "%c%d;%dH%c%d;%dm%c", + ASCII_CSI, HalpRow+1, HalpColumn+1, + ASCII_CSI, HalpForegroundColor+30, HalpBackgroundColor+40, + Character); + VenPrint(String); + +} + + +VOID +HalpScrollDisplay ( + VOID + ) + +/*++ + +Routine Description: + + This routine scrolls the display up one line. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + + char String[16]; + + // + // Force a FwScrollDisplay by positioning FwRow off the + // bottom of the screen and then doing a line feed. + // + + sprintf(String, "%c%dB%c", ASCII_CSI, 255, ASCII_LF); + VenPrint(String); + +} -- cgit v1.2.3