Leaked source code of windows server 2003
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.

1333 lines
36 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. thermal.c
  5. Abstract:
  6. This module interfaces the policy manager a thermal zone device
  7. Author:
  8. Ken Reneris (kenr) 17-Jan-1997
  9. Revision History:
  10. --*/
  11. #include "pop.h"
  12. #include "stdio.h" // for sprintf
  13. VOID
  14. PopThermalZoneCleanup (
  15. IN PDEVICE_OBJECT DeviceObject,
  16. IN PIRP Irp,
  17. IN PVOID Context
  18. );
  19. PUCHAR
  20. PopTemperatureString (
  21. OUT PUCHAR TempString,
  22. IN ULONG TenthsKelvin
  23. );
  24. #ifdef ALLOC_PRAGMA
  25. #pragma alloc_text(PAGE, PopThermalDeviceHandler)
  26. #endif
  27. PUCHAR
  28. PopTemperatureString (
  29. OUT PUCHAR TempString,
  30. IN ULONG TenthsKelvin
  31. )
  32. {
  33. #if DBG
  34. ULONG k, c, f;
  35. k = TenthsKelvin;
  36. if (k < 2732) {
  37. c = 2732 - k;
  38. f = c * 9 / 5 + 320;
  39. #if 0
  40. sprintf(TempString, "%d.%dk, -%d.%dc, -%d.%df",
  41. k / 10, k % 10,
  42. c / 10, c % 10,
  43. f / 10, f % 10
  44. );
  45. #else
  46. sprintf((PCHAR) TempString, "%d.%dK", k / 10, k % 10);
  47. #endif
  48. } else {
  49. c = k - 2732;
  50. f = c * 9 / 5 + 320;
  51. #if 0
  52. sprintf (TempString, "%d.%dk, %d.%dc, %d.%df",
  53. k / 10, k % 10,
  54. c / 10, c % 10,
  55. f / 10, f % 10
  56. );
  57. #else
  58. sprintf((PCHAR) TempString, "%d.%dK", k / 10, k % 10);
  59. #endif
  60. }
  61. return TempString;
  62. #else
  63. UNREFERENCED_PARAMETER (TempString);
  64. UNREFERENCED_PARAMETER (TenthsKelvin);
  65. return (PUCHAR)"";
  66. #endif
  67. }
  68. PUCHAR
  69. PopTimeString(
  70. OUT PUCHAR TimeString,
  71. IN ULONGLONG CurrentTime
  72. )
  73. {
  74. #if DBG
  75. LARGE_INTEGER curTime;
  76. TIME_FIELDS exCurTime;
  77. curTime.QuadPart = CurrentTime;
  78. RtlTimeToTimeFields( &curTime, &exCurTime );
  79. sprintf(
  80. (PCHAR) TimeString,
  81. "%d:%02d:%02d.%03d",
  82. exCurTime.Hour,
  83. exCurTime.Minute,
  84. exCurTime.Second,
  85. exCurTime.Milliseconds
  86. );
  87. return TimeString;
  88. #else
  89. UNREFERENCED_PARAMETER (TimeString);
  90. UNREFERENCED_PARAMETER (CurrentTime);
  91. return (PUCHAR)"";
  92. #endif
  93. }
  94. VOID
  95. PopThermalUpdateThrottle(
  96. IN PPOP_THERMAL_ZONE ThermalZone,
  97. IN ULONGLONG CurrentTime
  98. )
  99. /*++
  100. Routine Description:
  101. This routine is called to recalculate the throttle value of the
  102. thermal zone
  103. This function is not re-entrant. Each ThermalZone can only be in this
  104. code exactly once
  105. Arguments:
  106. ThermalZone - The structure for which the throttle value should be
  107. recalculated
  108. CurrentTime - The time at which the kernel handler was invoked
  109. Return Value:
  110. None
  111. --*/
  112. {
  113. BOOLEAN doThrottle = FALSE;
  114. KIRQL oldIrql;
  115. LONG part1;
  116. LONG part2;
  117. LONG throttleDelta;
  118. LONG currentThrottle = 0;
  119. LONG minThrottle;
  120. LONG minThrottle2;
  121. PKPRCB prcb;
  122. UCHAR t[40];
  123. #if DBG
  124. UCHAR s[40];
  125. #endif
  126. //
  127. // If there are no processor throttling capablities, this function does
  128. // nothing useful. The same applies if the thermal zone does not belong
  129. // to a processor
  130. //
  131. if (!ThermalZone->Info.Processors) {
  132. return;
  133. }
  134. //
  135. // Make sure that we have the time in a format that we can print it out
  136. // Note that by using the time that was passed in (instead of fetching
  137. // again), we make sure that the printouts always read the same thing
  138. //
  139. PopTimeString(t, CurrentTime );
  140. //
  141. // Make sure to run on the context of the appropriate processor
  142. //
  143. KeSetSystemAffinityThread( ThermalZone->Info.Processors );
  144. //
  145. // Make sure to raise IRQL so that we can synchronize
  146. //
  147. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  148. //
  149. // Is there any support for throttling on this processor?
  150. //
  151. prcb = KeGetCurrentPrcb();
  152. if ((prcb->PowerState.Flags & PSTATE_SUPPORTS_THROTTLE) == 0) {
  153. KeLowerIrql( oldIrql );
  154. KeRevertToUserAffinityThread();
  155. return;
  156. }
  157. //
  158. // Do these calculations now, while its safe
  159. //
  160. minThrottle2 = (LONG) (PopPolicy->MinThrottle * PO_TZ_THROTTLE_SCALE);
  161. minThrottle = prcb->PowerState.ProcessorMinThrottle * PO_TZ_THROTTLE_SCALE;
  162. //
  163. // No longer need to lock with the processor
  164. //
  165. KeLowerIrql( oldIrql );
  166. KeRevertToUserAffinityThread();
  167. //
  168. // If Temperature isn't above the passive trip point, stop passive cooling
  169. //
  170. if (ThermalZone->Info.CurrentTemperature < ThermalZone->Info.PassiveTripPoint) {
  171. //
  172. // If we aren't already throttling, then there isn't much to do
  173. //
  174. if (!(ThermalZone->Flags & PO_TZ_THROTTLING) ) {
  175. return;
  176. }
  177. //
  178. // Make sure that we wait long enough...
  179. //
  180. if ( (CurrentTime - ThermalZone->LastTime) < ThermalZone->SampleRate) {
  181. return;
  182. }
  183. //
  184. // We were throttling, so now we must stop
  185. //
  186. doThrottle = FALSE;
  187. currentThrottle = PO_TZ_NO_THROTTLE;
  188. PoPrint(
  189. PO_THERM,
  190. ("Thermal - Zone %p - %s - ending throttle #1\n",
  191. ThermalZone, t
  192. ) );
  193. //
  194. // Remove Thermal Throttle Flag since we are done throttling
  195. //
  196. KeSetSystemAffinityThread(ThermalZone->Info.Processors);
  197. KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
  198. prcb = KeGetCurrentPrcb();
  199. RtlInterlockedClearBits(&prcb->PowerState.Flags, PSTATE_THERMAL_THROTTLE_APPLIED);
  200. //
  201. // Set up timer to fire now that we have completed our thermal event.
  202. //
  203. PopSetTimer(&prcb->PowerState, prcb->PowerState.CurrentThrottle);
  204. KeLowerIrql(oldIrql);
  205. KeRevertToUserAffinityThread();
  206. goto PopThermalUpdateThrottleExit;
  207. }
  208. //
  209. // Are we already throttling?
  210. //
  211. if (!(ThermalZone->Flags & PO_TZ_THROTTLING) ) {
  212. //
  213. // Throttling is not enabled, but the thermal zone has exceeded
  214. // it's passive cooling point. We need to start throttling
  215. //
  216. doThrottle = TRUE;
  217. currentThrottle = PO_TZ_NO_THROTTLE;
  218. ASSERT(
  219. ThermalZone->Info.SamplingPeriod &&
  220. ThermalZone->Info.SamplingPeriod < 4096
  221. );
  222. ThermalZone->SampleRate = 1000000 * ThermalZone->Info.SamplingPeriod;
  223. ThermalZone->LastTime = 0;
  224. ThermalZone->LastTemp = ThermalZone->Info.PassiveTripPoint;
  225. PoPrint(
  226. PO_THERM,
  227. ("Thermal - Zone %p - %s - starting to throttle\n",
  228. ThermalZone, t
  229. ) );
  230. //
  231. // Set Thermal Throttle Flag since we are now throttling
  232. //
  233. KeSetSystemAffinityThread(ThermalZone->Info.Processors);
  234. KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
  235. prcb = KeGetCurrentPrcb();
  236. RtlInterlockedSetBits(&prcb->PowerState.Flags, PSTATE_THERMAL_THROTTLE_APPLIED);
  237. KeLowerIrql(oldIrql);
  238. KeRevertToUserAffinityThread();
  239. } else if ( (CurrentTime - ThermalZone->LastTime) < ThermalZone->SampleRate) {
  240. //
  241. // The sample period has not yet expired, so wait until it has
  242. //
  243. return;
  244. } else {
  245. //
  246. // We need to get the current throttle value since our calculations
  247. // will use it
  248. //
  249. // It is not necessary to synchronize access to this variable since
  250. // the flags are not also being accessed at the same time.
  251. //
  252. // KeAcquireSpinLock( &PopThermalLock, &oldIrql );
  253. currentThrottle = ThermalZone->Throttle;
  254. // KeReleaseSpinLock( &PopThermalLock, oldIrql );
  255. }
  256. //
  257. // Compute throttle adjustment
  258. //
  259. part1 = ThermalZone->Info.CurrentTemperature - ThermalZone->LastTemp;
  260. part2 = ThermalZone->Info.CurrentTemperature - ThermalZone->Info.PassiveTripPoint;
  261. throttleDelta =
  262. ThermalZone->Info.ThermalConstant1 * part1 +
  263. ThermalZone->Info.ThermalConstant2 * part2;
  264. PoPrint(
  265. PO_THERM,
  266. ("Thermal - Zone %p - %s - LastTemp %s ThrottleDelta = %d.%d%%\n",
  267. ThermalZone, t,
  268. PopTemperatureString(s, ThermalZone->LastTemp),
  269. (throttleDelta / 10),
  270. (throttleDelta % 10)
  271. ) );
  272. //
  273. // Only apply the throttle adjustment if it is in the same
  274. // direction as the tempature motion.
  275. //
  276. if ( (part1 ^ throttleDelta) >= 0) {
  277. currentThrottle -= throttleDelta;
  278. #if DBG
  279. PoPrint(
  280. PO_THERM,
  281. ("Thermal - Zone %p - %s - Subtracting delta from throttle\n",
  282. ThermalZone, t)
  283. );
  284. } else {
  285. PoPrint(
  286. PO_THERM,
  287. ("Thermal - Zone %p - %s - TempDelta (%d.%d) ^ (%d.%d) < 0)\n",
  288. ThermalZone, t, (part1 / 10), (part1 % 10),
  289. (throttleDelta / 10), (throttleDelta % 10) )
  290. );
  291. #endif
  292. }
  293. //
  294. // If throttle is over 100% then we're done throttling
  295. //
  296. if (currentThrottle > PO_TZ_NO_THROTTLE) {
  297. currentThrottle = PO_TZ_NO_THROTTLE;
  298. doThrottle = FALSE;
  299. PoPrint(
  300. PO_THERM,
  301. ("Thermal - Zone %p - %s - ending throttle #2\n",
  302. ThermalZone, t)
  303. );
  304. } else {
  305. //
  306. // Show the world what the two mininums are
  307. //
  308. PoPrint(
  309. PO_THERM,
  310. ("Thermal - Zone %p - %s - Min #1 %d.%d Min #2 %d.%d \n",
  311. ThermalZone, t,
  312. (minThrottle / 10), (minThrottle % 10),
  313. (minThrottle2 / 10), (minThrottle2 % 10)
  314. ) );
  315. if (currentThrottle < minThrottle) {
  316. currentThrottle = minThrottle;
  317. }
  318. //
  319. // Remember to start throttling
  320. //
  321. doThrottle = TRUE;
  322. }
  323. PopThermalUpdateThrottleExit:
  324. //
  325. // Do this at the end
  326. //
  327. ThermalZone->LastTemp = ThermalZone->Info.CurrentTemperature;
  328. ThermalZone->LastTime = CurrentTime;
  329. //
  330. // At this point, we will set and remember the value that we calculated
  331. // in the above function
  332. //
  333. KeAcquireSpinLock( &PopThermalLock, &oldIrql);
  334. if (doThrottle) {
  335. ThermalZone->Flags |= PO_TZ_THROTTLING;
  336. ThermalZone->Throttle = currentThrottle;
  337. } else {
  338. ThermalZone->Flags &= ~PO_TZ_THROTTLING;
  339. ThermalZone->Throttle = PO_TZ_NO_THROTTLE;
  340. }
  341. //
  342. // Apply thermal zone throttles to all effected processors
  343. //
  344. PoPrint(
  345. PO_THERM,
  346. ("Thermal - Zone %p - %s - throttle set to %d.%d\n",
  347. ThermalZone, t,
  348. (ThermalZone->Throttle / 10),
  349. (ThermalZone->Throttle % 10)
  350. )
  351. );
  352. KeReleaseSpinLock( &PopThermalLock, oldIrql );
  353. //
  354. // Make sure to apply the new throttle
  355. //
  356. PopApplyThermalThrottle ();
  357. //
  358. // Done
  359. //
  360. return;
  361. }
  362. VOID
  363. PopThermalDeviceHandler (
  364. IN PDEVICE_OBJECT DeviceObject,
  365. IN PIRP Irp,
  366. IN PVOID Context
  367. )
  368. /*++
  369. Routine Description:
  370. N.B. PopPolicyLock must be held.
  371. Arguments:
  372. DeviceObject - DeviceObject of the switch device
  373. Irp - Irp which has completed
  374. Context - type of switch device
  375. Return Value:
  376. None.
  377. --*/
  378. {
  379. BOOLEAN sendActiveIrp = FALSE;
  380. PIO_STACK_LOCATION irpSp;
  381. PPOP_THERMAL_ZONE thermalZone;
  382. LARGE_INTEGER dueTime;
  383. ULONGLONG currentTime;
  384. ULONG activePoint;
  385. #if DBG
  386. ULONG i;
  387. UCHAR s[40];
  388. #endif
  389. UCHAR t[40];
  390. ASSERT_POLICY_LOCK_OWNED();
  391. irpSp = IoGetCurrentIrpStackLocation(Irp);
  392. thermalZone = (PPOP_THERMAL_ZONE) Context;
  393. currentTime = KeQueryInterruptTime ();
  394. PopTimeString(t, currentTime );
  395. //
  396. // Irp had an error. See if the thermal zone is being removed
  397. //
  398. if (Irp->IoStatus.Status == STATUS_NO_SUCH_DEVICE) {
  399. //
  400. // Thermal zone device has disappeared, clean up
  401. //
  402. thermalZone->State = PO_TZ_NO_STATE;
  403. thermalZone->Flags |= PO_TZ_CLEANUP;
  404. //
  405. // Pass it to the DPC function to ensure the timer & dpc are idle
  406. //
  407. PoPrint(
  408. PO_THERM,
  409. ("Thermal - Zone %p - %s - going away\n",
  410. thermalZone, t)
  411. );
  412. dueTime.QuadPart = -1;
  413. KeSetTimer (&thermalZone->PassiveTimer, dueTime, &thermalZone->PassiveDpc);
  414. //
  415. // Do not issue next IRP
  416. //
  417. return
  418. ;
  419. }
  420. //
  421. // If irp completed with success, handle it
  422. //
  423. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  424. switch (thermalZone->State) {
  425. case PO_TZ_READ_STATE:
  426. //
  427. // Read of thermal information has completed.
  428. //
  429. PoPrint(
  430. PO_THERM,
  431. ("Thermal - Zone %p - %s\n Current Temp: %s",
  432. thermalZone, t,
  433. PopTemperatureString(s, thermalZone->Info.CurrentTemperature)
  434. ) );
  435. PoPrint(
  436. PO_THERM,
  437. (" Critical Trip: %s",
  438. PopTemperatureString(s, thermalZone->Info.CriticalTripPoint)
  439. ) );
  440. PoPrint(
  441. PO_THERM,
  442. (" Passive Trip: %s\n",
  443. PopTemperatureString(s, thermalZone->Info.PassiveTripPoint)
  444. ) );
  445. #if DBG
  446. for ( i=0; i < thermalZone->Info.ActiveTripPointCount; i++) {
  447. PoPrint(
  448. PO_THERM,
  449. (" Active Trip %d: %s\n",
  450. i,
  451. PopTemperatureString(s, thermalZone->Info.ActiveTripPoint[i])
  452. ) );
  453. }
  454. #endif
  455. //
  456. // Update the throttle
  457. //
  458. PopThermalUpdateThrottle( thermalZone, currentTime );
  459. //
  460. // Check for change in active cooling
  461. //
  462. for (activePoint = 0; activePoint < thermalZone->Info.ActiveTripPointCount; activePoint++) {
  463. if (thermalZone->Info.CurrentTemperature >= thermalZone->Info.ActiveTripPoint[activePoint]) {
  464. break;
  465. }
  466. }
  467. if (activePoint != thermalZone->ActivePoint) {
  468. PoPrint(
  469. PO_THERM,
  470. ("Thermal - Zone %p - %s - Pending Coooling Point is %x\n",
  471. thermalZone, t, activePoint)
  472. );
  473. thermalZone->PendingActivePoint = (UCHAR) activePoint;
  474. sendActiveIrp = TRUE;
  475. }
  476. //
  477. // Check for critical trip point
  478. //
  479. if (thermalZone->Info.CurrentTemperature > thermalZone->Info.CriticalTripPoint) {
  480. PoPrint(
  481. PO_THERM | PO_ERROR,
  482. ("Thermal - Zone %p - %s - Above critical (%x %x)\n",
  483. thermalZone, t,
  484. thermalZone->Info.CurrentTemperature,
  485. thermalZone->Info.CriticalTripPoint
  486. ));
  487. PopCriticalShutdown (PolicyDeviceThermalZone);
  488. }
  489. break;
  490. case PO_TZ_SET_MODE:
  491. //
  492. // Thermal zone cooling mode was successfully set
  493. //
  494. thermalZone->Mode = thermalZone->PendingMode;
  495. PoPrint(
  496. PO_THERM,
  497. ("Thermal - Zone %p - %s - cooling mode set to %x\n",
  498. thermalZone, t, thermalZone->Mode)
  499. );
  500. //
  501. // We want to force a resend of the Active Trip Point irp since
  502. // there is a situation where the ACPI driver decides that as a
  503. // matter of policy, it will not actually turn on fans if the
  504. // system is in passive cooling mode. If we go back to active
  505. // mode, then we want to turn the fans on. The same holds true
  506. // if the fans are running and we transition to passive mode.
  507. //
  508. sendActiveIrp = TRUE;
  509. break;
  510. case PO_TZ_SET_ACTIVE:
  511. thermalZone->ActivePoint = thermalZone->PendingActivePoint;
  512. PoPrint(
  513. PO_THERM,
  514. ("Thermal - Zone %p - %s - active cooling point set to %x\n",
  515. thermalZone, t, thermalZone->ActivePoint)
  516. );
  517. break;
  518. default:
  519. PopInternalAddToDumpFile( Irp, sizeof(IRP), DeviceObject, NULL, NULL, NULL );
  520. KeBugCheckEx( INTERNAL_POWER_ERROR,
  521. 0x500,
  522. POP_THERMAL,
  523. (ULONG_PTR)Irp,
  524. (ULONG_PTR)DeviceObject );
  525. }
  526. #if DBG
  527. } else if (Irp->IoStatus.Status != STATUS_DEVICE_NOT_CONNECTED &&
  528. Irp->IoStatus.Status != STATUS_CANCELLED) {
  529. //
  530. // Unexpected error
  531. //
  532. PoPrint(
  533. PO_ERROR,
  534. ("Thermal - Zone - %p - %s - unexpected error %x\n",
  535. thermalZone, t, Irp->IoStatus.Status));
  536. #endif
  537. }
  538. //
  539. // Determine type of irp to send zone
  540. //
  541. irpSp = IoGetNextIrpStackLocation(Irp);
  542. if (sendActiveIrp) {
  543. //
  544. // Thermal zone active cooling point not current
  545. //
  546. thermalZone->State = PO_TZ_SET_ACTIVE;
  547. irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_RUN_ACTIVE_COOLING_METHOD;
  548. irpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(ULONG);
  549. irpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
  550. Irp->AssociatedIrp.SystemBuffer = &thermalZone->PendingActivePoint;
  551. PoPrint(
  552. PO_THERM,
  553. ("Thermal - Zone %p - %s Sending Run Cooling Method: %x\n",
  554. thermalZone, t, thermalZone->PendingActivePoint)
  555. );
  556. } else if (thermalZone->Mode != PopCoolingMode) {
  557. //
  558. // Thermal zone cooling mode does not match system cooling mode.
  559. //
  560. thermalZone->State = PO_TZ_SET_MODE;
  561. thermalZone->PendingMode = (UCHAR) PopCoolingMode;
  562. irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_THERMAL_SET_COOLING_POLICY;
  563. irpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(thermalZone->PendingMode);
  564. irpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
  565. Irp->AssociatedIrp.SystemBuffer = &thermalZone->PendingMode;
  566. PoPrint(
  567. PO_THERM,
  568. ("Thermal - Zone %p - %s - Sending Set Cooling Policy: %x\n",
  569. thermalZone, t, thermalZone->PendingMode)
  570. );
  571. } else {
  572. //
  573. // Issue query to get tempture of thermal zone
  574. //
  575. thermalZone->State = PO_TZ_READ_STATE;
  576. if (thermalZone->Flags & PO_TZ_THROTTLING && thermalZone->SampleRate) {
  577. //
  578. // Compute time for next read
  579. //
  580. dueTime.QuadPart = thermalZone->LastTime + thermalZone->SampleRate;
  581. if (dueTime.QuadPart > (LONGLONG) currentTime) {
  582. #if DBG
  583. PoPrint(
  584. PO_THERM,
  585. ("Thermal - Zone %x - %s waituntil",
  586. thermalZone, t) );
  587. PoPrint(
  588. PO_THERM,
  589. (" %s (%d sec)\n",
  590. PopTimeString(t, dueTime.QuadPart),
  591. ( (thermalZone->SampleRate ) / (US2TIME * US2SEC) ) )
  592. );
  593. PopTimeString(t, currentTime);
  594. #endif
  595. //
  596. // Set timer for duration of wait
  597. //
  598. dueTime.QuadPart = currentTime - dueTime.QuadPart;
  599. KeSetTimer (&thermalZone->PassiveTimer, dueTime, &thermalZone->PassiveDpc);
  600. } else {
  601. //
  602. // Perform non-blocking IRP query information to get the Temperature now
  603. //
  604. thermalZone->Info.ThermalStamp = 0;
  605. }
  606. }
  607. irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_THERMAL_QUERY_INFORMATION;
  608. irpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(thermalZone->Info);
  609. irpSp->Parameters.DeviceIoControl.OutputBufferLength = sizeof(thermalZone->Info);
  610. Irp->AssociatedIrp.SystemBuffer = &thermalZone->Info;
  611. PoPrint(
  612. PO_THERM,
  613. ("Thermal - Zone %p - %s - Sending Query Temp - ThermalStamp = %x\n",
  614. thermalZone, t, thermalZone->Info.ThermalStamp) );
  615. }
  616. //
  617. // Send irp to driver
  618. //
  619. IoSetCompletionRoutine (Irp, PopCompletePolicyIrp, NULL, TRUE, TRUE, TRUE);
  620. IoCallDriver (DeviceObject, Irp);
  621. }
  622. VOID
  623. PopThermalZoneCleanup (
  624. IN PDEVICE_OBJECT DeviceObject,
  625. IN PIRP Irp,
  626. IN PVOID Context
  627. )
  628. {
  629. KIRQL oldIrql;
  630. PPOP_THERMAL_ZONE thermalZone;
  631. ASSERT_POLICY_LOCK_OWNED();
  632. thermalZone = (PPOP_THERMAL_ZONE) Context;
  633. //
  634. // Acquire the Spinlock required to delete the thermal zone
  635. //
  636. KeAcquireSpinLock( &PopThermalLock, &oldIrql );
  637. //
  638. // Delete thermal zone from the linked list of thermal zones
  639. //
  640. RemoveEntryList (&thermalZone->Link);
  641. //
  642. // Remember what the irp associated with the thermal zone was
  643. //
  644. Irp = thermalZone->Irp;
  645. //
  646. // Make sure to cleanup the entry, so that any further reference is
  647. // bogus
  648. //
  649. #if DBG
  650. RtlZeroMemory( thermalZone, sizeof(POP_THERMAL_ZONE) );
  651. #endif
  652. //
  653. // Release the spinlock that was protecting the thermal zone
  654. //
  655. KeReleaseSpinLock( &PopThermalLock, oldIrql );
  656. //
  657. // Free the Irp that we had associated with it...
  658. //
  659. IoFreeIrp (Irp);
  660. //
  661. // Free the reference we had to the device object
  662. //
  663. ObDereferenceObject (DeviceObject);
  664. //
  665. // Finally, free the memory associated with the thermal zone
  666. //
  667. ExFreePool (thermalZone);
  668. }
  669. VOID
  670. PopThermalZoneDpc (
  671. IN struct _KDPC *Dpc,
  672. IN PVOID DeferredContext,
  673. IN PVOID SystemArgument1,
  674. IN PVOID SystemArgument2
  675. )
  676. /*++
  677. Routine Description:
  678. Timer dpc used to unblock pending read of thermal zone Temperature
  679. in order to get the Temperature now
  680. Arguments:
  681. DeferredConext - ThermalZone
  682. Return Value:
  683. None.
  684. --*/
  685. {
  686. PPOP_THERMAL_ZONE thermalZone;
  687. PIO_STACK_LOCATION irpSp;
  688. #if DBG
  689. ULONGLONG currentTime;
  690. UCHAR t[40];
  691. currentTime = KeQueryInterruptTime();
  692. PopTimeString(t, currentTime);
  693. #endif
  694. UNREFERENCED_PARAMETER (Dpc);
  695. UNREFERENCED_PARAMETER (SystemArgument1);
  696. UNREFERENCED_PARAMETER (SystemArgument2);
  697. thermalZone = (PPOP_THERMAL_ZONE) DeferredContext;
  698. //
  699. // If cleanup is set queue the thread zone to be cleaned up
  700. //
  701. if (thermalZone->Flags & PO_TZ_CLEANUP) {
  702. //
  703. // The irp is idle, use it to queue the request to the cleanup procedure
  704. //
  705. irpSp = IoGetCurrentIrpStackLocation(thermalZone->Irp);
  706. irpSp += 1; // get previous location
  707. irpSp->Parameters.Others.Argument3 = (PVOID) PopThermalZoneCleanup;
  708. PopCompletePolicyIrp (NULL, thermalZone->Irp, NULL);
  709. }
  710. //
  711. // Time to read current Temperature to adjust passive cooling throttle.
  712. // If the current state is reading, then cancel it to either to the
  713. // Temperature now or to issue a non-blocking thermal read state
  714. //
  715. if (thermalZone->State == PO_TZ_READ_STATE) {
  716. #if DBG
  717. PoPrint(
  718. PO_THERM,
  719. ("Thermal - Zone %p - %s - Cancel Irp %p\n",
  720. thermalZone, t, thermalZone->Irp)
  721. );
  722. #endif
  723. IoCancelIrp (thermalZone->Irp);
  724. #if DBG
  725. } else {
  726. PoPrint(
  727. PO_THERM,
  728. ("Thermal - Zone %p - %s - In state %08lx\n",
  729. thermalZone, t, thermalZone->State )
  730. );
  731. #endif
  732. }
  733. }
  734. VOID
  735. PopApplyThermalThrottle (
  736. VOID
  737. )
  738. /*++
  739. Routine Description:
  740. Computes each processors best possible speed as dictated by thermal
  741. restrants. Will also examine the thermal settings to determine if
  742. the cooling mode should be adjusted.
  743. Arguments:
  744. Return Value:
  745. None.
  746. --*/
  747. {
  748. KAFFINITY processors;
  749. KAFFINITY currentAffinity;
  750. KAFFINITY thermalProcessors;
  751. KIRQL oldIrql;
  752. PLIST_ENTRY link;
  753. PPOP_THERMAL_ZONE thermalZone;
  754. PPROCESSOR_POWER_STATE pState;
  755. UCHAR thermalLimit;
  756. UCHAR thermalLimitIndex;
  757. UCHAR forcedLimit;
  758. UCHAR forcedLimitIndex;
  759. UCHAR limit;
  760. UCHAR index;
  761. ULONG thermalThrottle;
  762. ULONG forcedThrottle;
  763. ULONG mode;
  764. ULONG processorNumber;
  765. #if DBG
  766. ULONGLONG currentTime;
  767. UCHAR t[40];
  768. currentTime = KeQueryInterruptTime();
  769. PopTimeString(t, currentTime);
  770. #endif
  771. ASSERT_POLICY_LOCK_OWNED();
  772. //
  773. // If the system doesn't have processor throttle capabilities then
  774. // don't bother
  775. //
  776. if (!PopCapabilities.ProcessorThrottle) {
  777. return ;
  778. }
  779. #if 0
  780. //
  781. // Compute overthrottled into thermal zone throttle units
  782. //
  783. MinThrottle = PopPolicy->MinThrottle * PO_TZ_THROTTLE_SCALE;
  784. #endif
  785. //
  786. // Make sure to hold the spinlock for find the LCD. We don't actually
  787. // use the lock to walk the list, but we need it to reference the
  788. // Throttle Value
  789. //
  790. KeAcquireSpinLock( &PopThermalLock, &oldIrql );
  791. //
  792. // Get the LCD of the thermal zones
  793. //
  794. thermalThrottle = PO_TZ_NO_THROTTLE;
  795. thermalProcessors = 0;
  796. for (link = PopThermal.Flink; link != &PopThermal; link = link->Flink) {
  797. thermalZone = CONTAINING_RECORD (link, POP_THERMAL_ZONE, Link);
  798. //
  799. // Handle zones which are throttling
  800. //
  801. if (thermalZone->Flags & PO_TZ_THROTTLING) {
  802. //
  803. // Include processors for this zone
  804. //
  805. thermalProcessors |= thermalZone->Info.Processors;
  806. //
  807. // If zone is less then current thermal throttle, lower it
  808. //
  809. if ((ULONG) thermalZone->Throttle < thermalThrottle) {
  810. thermalThrottle = thermalZone->Throttle;
  811. }
  812. //
  813. // Until I can get the user guys to add a thermal tab such that
  814. // the OverThrottle policy becomes configurable by the user,
  815. // always putting the system to sleep on an overthrottle is a bad
  816. // idea. Note that there is some code in PopThermalDeviceHandler
  817. // that will have to be changed when the following is uncommented
  818. //
  819. #if 0
  820. //
  821. // Check if zone has overthrottled the system
  822. //
  823. if ((ULONG) thermalZone->Throttle < MinThrottle) {
  824. #if DBG
  825. PoPrint(
  826. PO_THERM | PO_ERROR,
  827. ("Thermal - Zone %p - %s - overthrottled (%x %x)\n",
  828. thermalZone, t, thermalZone->Throttle, MinThrottle)
  829. );
  830. #endif
  831. //
  832. // If we are going to do an S1-Critical standby, then we
  833. // will return immediately and not try to throttle the
  834. // CPU
  835. //
  836. PopSetPowerAction (
  837. &thermalZone->OverThrottled,
  838. 0,
  839. &PopPolicy->OverThrottled,
  840. PowerSystemSleeping1,
  841. SubstituteLightestOverallDownwardBounded
  842. );
  843. return;
  844. } else {
  845. //
  846. // Zone is not overthrottled, make sure trigger is clear
  847. //
  848. thermalZone->OverThrottled.Flags &= ~(PO_TRG_USER | PO_TRG_SYSTEM);
  849. }
  850. #endif
  851. }
  852. }
  853. //
  854. // Done with the lock
  855. //
  856. KeReleaseSpinLock( &PopThermalLock, oldIrql );
  857. #if DBG
  858. PoPrint(
  859. PO_THERM,
  860. ("PopApplyThermalThrottle - %s - Thermal throttle = %d.%d\n",
  861. t, (thermalThrottle / 10), (thermalThrottle % 10) )
  862. );
  863. #endif
  864. //
  865. // Use Min of thermal throttle and forced system throttle
  866. //
  867. forcedThrottle = PopGetThrottle() * PO_TZ_THROTTLE_SCALE;
  868. if (thermalThrottle > forcedThrottle) {
  869. thermalThrottle = forcedThrottle;
  870. #if DBG
  871. PoPrint(
  872. PO_THERM,
  873. ("PopApplyThermalThrottle - %s - Set to Forced throttle = %d.%d\n",
  874. t, (thermalThrottle / 10), (thermalThrottle % 10) )
  875. );
  876. #endif
  877. }
  878. //
  879. // Check active vs. passive cooling
  880. //
  881. if (thermalThrottle <= (ULONG) PopPolicy->FanThrottleTolerance * PO_TZ_THROTTLE_SCALE) {
  882. //
  883. // Throttle is below tolerance, we should be in active cooling
  884. //
  885. mode = PO_TZ_ACTIVE;
  886. } else {
  887. //
  888. // Throttle is above tolerance. If optimize for power is set then
  889. // use passive cooling else use active cooling
  890. //
  891. mode = PopPolicy->OptimizeForPower ? PO_TZ_PASSIVE : PO_TZ_ACTIVE;
  892. }
  893. //
  894. // If current cooling mode is not correct, update it
  895. //
  896. if (mode != PopCoolingMode) {
  897. #if DBG
  898. ULONG fanTolerance = (ULONG) PopPolicy->FanThrottleTolerance * PO_TZ_THROTTLE_SCALE;
  899. PoPrint(
  900. PO_THERM,
  901. ("PopApplyThermalThrottle - %s - Throttle (%d.%d) %s FanTolerance (%d.%d)\n",
  902. t, (thermalThrottle / 10), (thermalThrottle % 10),
  903. (thermalThrottle <= fanTolerance ? "<=" : ">"),
  904. (fanTolerance / 10), (fanTolerance % 10) )
  905. );
  906. PoPrint(
  907. PO_THERM,
  908. ("PopApplyThermalThrottle - %s - OptimizeForPower is %s\n",
  909. t, (PopPolicy->OptimizeForPower ? "True" : "False") )
  910. );
  911. PoPrint(
  912. PO_THERM,
  913. ("PopApplyThermalThrottle - %s - Changing cooling mode to %s\n",
  914. t, (mode == PO_TZ_ACTIVE ? "Active" : "Passive") )
  915. );
  916. #endif
  917. PopCoolingMode = mode;
  918. //
  919. // We are going to touch the Thermal list --- make sure that we hold
  920. // the correct lock
  921. //
  922. KeAcquireSpinLock(&PopThermalLock, &oldIrql );
  923. //
  924. // Cancel any blocked thermal reads in order to send set mode irps
  925. //
  926. for (link = PopThermal.Flink; link != &PopThermal; link = link->Flink) {
  927. thermalZone = CONTAINING_RECORD (link, POP_THERMAL_ZONE, Link);
  928. if (thermalZone->State == PO_TZ_READ_STATE) {
  929. IoCancelIrp (thermalZone->Irp);
  930. }
  931. }
  932. //
  933. // Done with the thermal lock
  934. //
  935. KeReleaseSpinLock(& PopThermalLock, oldIrql );
  936. }
  937. //
  938. // Set limit on effected processors
  939. //
  940. processorNumber = 0;
  941. currentAffinity = 1;
  942. processors = KeActiveProcessors;
  943. do {
  944. if (!(processors & currentAffinity)) {
  945. currentAffinity <<= 1;
  946. continue;
  947. }
  948. processors &= ~currentAffinity;
  949. //
  950. // We must run on the target processor
  951. //
  952. KeSetSystemAffinityThread(currentAffinity);
  953. //
  954. // We need to be running at DISPATCH_LEVEL to access the
  955. // structures referenced within the pState...
  956. //
  957. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  958. pState = &(KeGetCurrentPrcb()->PowerState);
  959. //
  960. // Does this processor support throttling?
  961. //
  962. if ((pState->Flags & PSTATE_SUPPORTS_THROTTLE) == 0) {
  963. //
  964. // No, then we don't care about it...
  965. //
  966. currentAffinity <<= 1;
  967. KeLowerIrql( oldIrql );
  968. continue;
  969. }
  970. //
  971. // Convert throttles to processor buck size. We need to
  972. // do this in the context of the target processor to make
  973. // sure that we get the correct set of perf levels
  974. //
  975. PopRoundThrottle(
  976. (UCHAR)(thermalThrottle/PO_TZ_THROTTLE_SCALE),
  977. &thermalLimit,
  978. NULL,
  979. &thermalLimitIndex,
  980. NULL
  981. );
  982. PopRoundThrottle(
  983. (UCHAR)(forcedThrottle/PO_TZ_THROTTLE_SCALE),
  984. &forcedLimit,
  985. NULL,
  986. &forcedLimitIndex,
  987. NULL
  988. );
  989. #if DBG
  990. PoPrint(
  991. PO_THROTTLE,
  992. ("PopApplyThermalThrottle - %s - Thermal throttle = %d.%d -> Limit = %d\n",
  993. t, (thermalThrottle / 10), (thermalThrottle % 10),
  994. thermalLimit
  995. )
  996. );
  997. PoPrint(
  998. PO_THROTTLE,
  999. ("PopApplyThermalThrottle - %s - Forced throttle = %d.%d -> Limit = %d\n",
  1000. t, (forcedThrottle / 10), (forcedThrottle % 10),
  1001. forcedLimit
  1002. )
  1003. );
  1004. #endif
  1005. //
  1006. // Figure out which one we are going to use...
  1007. //
  1008. limit = (thermalProcessors & currentAffinity) ?
  1009. thermalLimit : forcedLimit;
  1010. index = (thermalProcessors & currentAffinity) ?
  1011. thermalLimitIndex : forcedLimitIndex;
  1012. //
  1013. // Done with current affinity mask
  1014. //
  1015. currentAffinity <<= 1;
  1016. //
  1017. // Check processor limits for to see if value is okay
  1018. //
  1019. if (limit > pState->ProcessorMaxThrottle) {
  1020. #if DBG
  1021. PoPrint(
  1022. PO_THROTTLE,
  1023. ("PopApplyThermalThrottle - %s - Limit (%d) > MaxThrottle (%d)\n",
  1024. t, limit, pState->ProcessorMaxThrottle)
  1025. );
  1026. #endif
  1027. limit = pState->ProcessorMaxThrottle;
  1028. } else if (limit < pState->ProcessorMinThrottle) {
  1029. #if DBG
  1030. PoPrint(
  1031. PO_THROTTLE,
  1032. ("PopApplyThermalThrottle - %s - Limit (%d) < MinThrottle (%d)\n",
  1033. t, limit, pState->ProcessorMinThrottle)
  1034. );
  1035. #endif
  1036. limit = pState->ProcessorMinThrottle;
  1037. }
  1038. //
  1039. // Update the limit (if required...)
  1040. //
  1041. if (pState->ThermalThrottleLimit != limit) {
  1042. pState->ThermalThrottleLimit = limit;
  1043. pState->ThermalThrottleIndex = index;
  1044. #if DBG
  1045. PoPrint(
  1046. PO_THROTTLE,
  1047. ("PopApplyThermalThrottle - %s - New Limit (%d) Index (%d)\n",
  1048. t, limit, index)
  1049. );
  1050. #endif
  1051. }
  1052. //
  1053. // Rever back to our previous IRQL
  1054. //
  1055. KeLowerIrql( oldIrql );
  1056. } while (processors);
  1057. //
  1058. // We should revert back to the proper affinity
  1059. //
  1060. KeRevertToUserAffinityThread();
  1061. //
  1062. // Apply thermal throttles if necessary. Note we always do this
  1063. // whether or not the limits were changed. This routine also gets
  1064. // called whenever the system transitions from AC to DC, and that
  1065. // may also require a throttle update due to dynamic throttling.
  1066. //
  1067. PopUpdateAllThrottles();
  1068. }