Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

253 lines
5.1 KiB

  1. /*++
  2. Module Name:
  3. mpclockc.c
  4. Abstract:
  5. Author:
  6. Ron Mosgrove - Intel
  7. Environment:
  8. Kernel mode
  9. Revision History:
  10. --*/
  11. #include "halp.h"
  12. //
  13. // Define global data used to communicate new clock rates to the clock
  14. // interrupt service routine.
  15. //
  16. struct RtcTimeIncStruc {
  17. ULONG RTCRegisterA; // The RTC register A value for this rate
  18. ULONG RateIn100ns; // This rate in multiples of 100ns
  19. ULONG RateAdjustmentNs; // Error Correction (in ns)
  20. ULONG RateAdjustmentCnt; // Error Correction (as a fraction of 256)
  21. ULONG IpiRate; // IPI Rate Count (as a fraction of 256)
  22. };
  23. //
  24. // The adjustment is expressed in terms of a fraction of 256 so that
  25. // the ISR can easily determine when a 100ns slice needs to be subtracted
  26. // from the count passed to the kernel without any expensive operations
  27. //
  28. // Using 256 as a base means that anytime the count becomes greater
  29. // than 256 the time slice must be incremented, the overflow can then
  30. // be cleared by AND'ing the value with 0xff
  31. //
  32. #define AVAILABLE_INCREMENTS 5
  33. struct RtcTimeIncStruc HalpRtcTimeIncrements[AVAILABLE_INCREMENTS] = {
  34. {0x026, 9766, 38, 96, /* 3/8 of 256 */ 16},
  35. {0x027, 19532, 75, 192, /* 3/4 of 256 */ 32},
  36. {0x028, 39063, 50, 128, /* 1/2 of 256 */ 64},
  37. {0x029, 78125, 0, 0, 128},
  38. {0x02a, 156250, 0, 0, 256}
  39. };
  40. ULONG HalpInitialClockRateIndex = AVAILABLE_INCREMENTS-1;
  41. extern ULONG HalpCurrentRTCRegisterA;
  42. extern ULONG HalpCurrentClockRateIn100ns;
  43. extern ULONG HalpCurrentClockRateAdjustment;
  44. extern ULONG HalpCurrentIpiRate;
  45. extern ULONG HalpNextMSRate;
  46. extern ULONG HalpClockWork;
  47. extern BOOLEAN HalpClockSetMSRate;
  48. VOID
  49. HalpSetInitialClockRate (
  50. VOID
  51. );
  52. VOID
  53. HalpInitializeTimerResolution (
  54. ULONG Rate
  55. );
  56. #ifdef ALLOC_PRAGMA
  57. #pragma alloc_text(PAGELK, HalpSetInitialClockRate)
  58. #pragma alloc_text(INIT, HalpInitializeTimerResolution)
  59. #endif
  60. VOID
  61. HalpInitializeTimerResolution (
  62. ULONG Rate
  63. )
  64. /*++
  65. Routine Description:
  66. This function is called to initialize the timer resolution to be
  67. something other then the default. The rate is set to the closest
  68. supported setting below the requested rate.
  69. Arguments:
  70. Rate - in 100ns units
  71. Return Value:
  72. None
  73. --*/
  74. {
  75. ULONG i, s;
  76. //
  77. // Find the table index of the rate to use
  78. //
  79. for (i=1; i < AVAILABLE_INCREMENTS; i++) {
  80. if (HalpRtcTimeIncrements[i].RateIn100ns > Rate) {
  81. break;
  82. }
  83. }
  84. HalpInitialClockRateIndex = i - 1;
  85. //
  86. // Scale IpiRate according to max TimeIncr rate which can be used
  87. //
  88. s = AVAILABLE_INCREMENTS - HalpInitialClockRateIndex - 1;
  89. for (i=0; i < AVAILABLE_INCREMENTS; i++) {
  90. HalpRtcTimeIncrements[i].IpiRate <<= s;
  91. }
  92. }
  93. VOID
  94. HalpSetInitialClockRate (
  95. VOID
  96. )
  97. /*++
  98. Routine Description:
  99. This function is called to set the initial clock interrupt rate
  100. Arguments:
  101. None
  102. Return Value:
  103. None
  104. --*/
  105. {
  106. extern ULONG HalpNextMSRate;
  107. //
  108. // On ACPI timer machines, we need to init an index into the
  109. // milisecond(s) array used by pmtimerc.c's Piix4 workaround
  110. //
  111. #ifdef ACPI_HAL
  112. #ifdef NT_UP
  113. extern ULONG HalpCurrentMSRateTableIndex;
  114. HalpCurrentMSRateTableIndex = (1 << HalpInitialClockRateIndex) - 1;
  115. //
  116. // The Piix4 upper bound table ends at 15ms (index 14), so we'll have
  117. // to map our 15.6ms entry to it as a special case
  118. //
  119. if (HalpCurrentMSRateTableIndex == 0xF) {
  120. HalpCurrentMSRateTableIndex--;
  121. }
  122. #endif
  123. #endif
  124. HalpNextMSRate = HalpInitialClockRateIndex;
  125. HalpCurrentClockRateIn100ns =
  126. HalpRtcTimeIncrements[HalpNextMSRate].RateIn100ns;
  127. HalpCurrentClockRateAdjustment =
  128. HalpRtcTimeIncrements[HalpNextMSRate].RateAdjustmentCnt;
  129. HalpCurrentRTCRegisterA =
  130. HalpRtcTimeIncrements[HalpNextMSRate].RTCRegisterA;
  131. HalpCurrentIpiRate =
  132. HalpRtcTimeIncrements[HalpNextMSRate].IpiRate;
  133. HalpClockWork = 0;
  134. KeSetTimeIncrement (
  135. HalpRtcTimeIncrements[HalpNextMSRate].RateIn100ns,
  136. HalpRtcTimeIncrements[0].RateIn100ns
  137. );
  138. }
  139. #ifdef MMTIMER
  140. ULONG
  141. HalpAcpiTimerSetTimeIncrement(
  142. IN ULONG DesiredIncrement
  143. )
  144. #else
  145. ULONG
  146. HalSetTimeIncrement (
  147. IN ULONG DesiredIncrement
  148. )
  149. #endif
  150. /*++
  151. Routine Description:
  152. This function is called to set the clock interrupt rate to the frequency
  153. required by the specified time increment value.
  154. Arguments:
  155. DesiredIncrement - Supplies desired number of 100ns units between clock
  156. interrupts.
  157. Return Value:
  158. The actual time increment in 100ns units.
  159. --*/
  160. {
  161. ULONG i;
  162. KIRQL OldIrql;
  163. //
  164. // Set the new clock interrupt parameters, return the new time increment value.
  165. //
  166. for (i=1; i < HalpInitialClockRateIndex; i++) {
  167. if (HalpRtcTimeIncrements[i].RateIn100ns > DesiredIncrement) {
  168. i = i - 1;
  169. break;
  170. }
  171. }
  172. OldIrql = KfRaiseIrql(HIGH_LEVEL);
  173. HalpNextMSRate = i + 1;
  174. HalpClockSetMSRate = TRUE;
  175. KfLowerIrql (OldIrql);
  176. return (HalpRtcTimeIncrements[i].RateIn100ns);
  177. }