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.

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