#ident "@(#) NEC xxcalstl.c 1.4 94/10/17 11:57:45" /*++ Copyright (c) 1991-1994 Microsoft Corporation Module Name: xxcalstl.c Abstract: This module implements the calibration of the stall execution HAL service, computes the count rate for the profile clock, and connects the clock and profile interrupts for a MIPS R3000 or R4000 system. Environment: Kernel mode only. Revision History: --*/ /* * Original source: Build Number 1.612 * * Modify for R98(MIPS/R4400) * *********************************************************************** * * S001 94.03/16-5/13 T.Samezima * * change HalpClockInterrupt0 vector * HalpProfileInterrupt vector * * add PROFILE interrupt control * * del interrupt clear * '#if defined(R3000)' with content * only '#if defined(R4000)' * *********************************************************************** * * S002 94.03/16-5/13 T.Samezima * * Chg Designate member of structures * * S003 94.08/22 N.Kugimoto * Chg Number 0 Bit Position is MSB (64Bit). So decremenet from 0x3f. */ #include "halp.h" #include "stdio.h" // // Put all code for HAL initialization in the INIT section. It will be // deallocated by memory management when phase 1 initialization is // completed. // #if defined(ALLOC_PRAGMA) #pragma alloc_text(INIT, HalpCalibrateStall) #pragma alloc_text(INIT, HalpStallInterrupt) #endif // // Define global data used to calibrate and stall processor execution. // ULONG HalpProfileCountRate; ULONG volatile HalpStallEnd; ULONG HalpStallScaleFactor; ULONG volatile HalpStallStart; BOOLEAN HalpCalibrateStall ( VOID ) /*++ Routine Description: This function calibrates the stall execution HAL service and connects the clock and profile interrupts to the appropriate NT service routines. N.B. This routine is only called during phase 1 initialization. Arguments: None. Return Value: A value of TRUE is returned if the calibration is successfully completed. Otherwise a value of FALSE is returned. --*/ { ULONG Index; KIRQL OldIrql; // // Use a range of scale factors from 50ns down to 10ns assuming a // five instruction stall loop. // for (Index = 50; Index > 0; Index -= 10) { // // Disable all interrupts and establish calibration parameters. // KeRaiseIrql(HIGH_LEVEL, &OldIrql); // // Set the scale factor, stall count, starting stall count, and // ending stall count values. // PCR->StallScaleFactor = 1000 / (Index * 5); PCR->StallExecutionCount = 0; HalpStallStart = 0; HalpStallEnd = 0; // // Enable interrupts and stall execution. // KeLowerIrql(OldIrql); // // Stall execution for (MAXIMUM_INCREMENT / 10) * 4 us. // KeStallExecutionProcessor((MAXIMUM_INCREMENT / 10) * 4); // // If both the starting and ending stall counts have been captured, // then break out of loop. // if ((HalpStallStart != 0) && (HalpStallEnd != 0)) { break; } } // // Compute the profile interrupt rate. // HalpProfileCountRate = HalpProfileCountRate * ((1000 * 1000 * 10) / MAXIMUM_INCREMENT); // // Compute the stall execution scale factor. // HalpStallScaleFactor = (HalpStallEnd - HalpStallStart + ((MAXIMUM_INCREMENT / 10) - 1)) / (MAXIMUM_INCREMENT / 10); if (HalpStallScaleFactor <= 0) { HalpStallScaleFactor = 1; } PCR->StallScaleFactor = HalpStallScaleFactor; // // Connect the real clock interrupt routine. // /* Start S001 */ PCR->InterruptRoutine[CLOCK_VECTOR] = HalpClockInterrupt0; /* End S001 */ // // Write the compare register and clear the count register, and // connect the profile interrupt. // HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT); /* Start S001 */ PCR->InterruptRoutine[PROFILE_VECTOR] = HalpProfileInterrupt; WRITE_REGISTER_ULONG( &(PMC_CONTROL1)->MKSR.Long, 0x3f-IPR_PROFILE_BIT_NO ); // S002 S003 WRITE_REGISTER_ULONG( &(PMC_CONTROL1)->TMCR2.Long, 0x3 ); // S002 /* End S001 */ return TRUE; } VOID KeStallExecutionProcessor ( IN ULONG MicroSeconds ) /*++ Routine Description: This function stalls 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. --*/ { ULONG Index; // // Use the stall scale factor to determine the number of iterations // the wait loop must be executed to stall the processor for the // specified number of microseconds. // Index = MicroSeconds * PCR->StallScaleFactor; do { PCR->StallExecutionCount += 1; Index -= 1; } while (Index > 0); return; } VOID HalpStallInterrupt ( VOID ) /*++ Routine Description: This function serves as the stall calibration interrupt service routine. It is executed in response to system clock interrupts during the initialization of the HAL layer. Arguments: None. Return Value: None. --*/ { // // If this is the very first interrupt, then wait for the second // interrupt before starting the timing interval. Else, if this // the second interrupt, then capture the starting stall count // and clear the count register on R4000 processors. Else, if this // is the third interrupt, then capture the ending stall count and // the ending count register on R4000 processors. Else, if this is // the fourth or subsequent interrupt, then simply dismiss it. // if ((HalpStallStart == 0) && (HalpStallEnd == 0)) { HalpStallEnd = 1; } else if ((HalpStallStart == 0) && (HalpStallEnd != 0)) { HalpStallStart = PCR->StallExecutionCount; HalpStallEnd = 0; HalpWriteCompareRegisterAndClear(0); } else if ((HalpStallStart != 0) && (HalpStallEnd == 0)) { HalpStallEnd = PCR->StallExecutionCount; HalpProfileCountRate = HalpWriteCompareRegisterAndClear(0); } return; }