bbc_envctrl.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. /* $Id: bbc_envctrl.c,v 1.4 2001/04/06 16:48:08 davem Exp $
  2. * bbc_envctrl.c: UltraSPARC-III environment control driver.
  3. *
  4. * Copyright (C) 2001 David S. Miller (davem@redhat.com)
  5. */
  6. #include <linux/kthread.h>
  7. #include <linux/delay.h>
  8. #include <linux/kmod.h>
  9. #include <asm/oplib.h>
  10. #include <asm/ebus.h>
  11. #include "bbc_i2c.h"
  12. #include "max1617.h"
  13. #undef ENVCTRL_TRACE
  14. /* WARNING: Making changes to this driver is very dangerous.
  15. * If you misprogram the sensor chips they can
  16. * cut the power on you instantly.
  17. */
  18. /* Two temperature sensors exist in the SunBLADE-1000 enclosure.
  19. * Both are implemented using max1617 i2c devices. Each max1617
  20. * monitors 2 temperatures, one for one of the cpu dies and the other
  21. * for the ambient temperature.
  22. *
  23. * The max1617 is capable of being programmed with power-off
  24. * temperature values, one low limit and one high limit. These
  25. * can be controlled independently for the cpu or ambient temperature.
  26. * If a limit is violated, the power is simply shut off. The frequency
  27. * with which the max1617 does temperature sampling can be controlled
  28. * as well.
  29. *
  30. * Three fans exist inside the machine, all three are controlled with
  31. * an i2c digital to analog converter. There is a fan directed at the
  32. * two processor slots, another for the rest of the enclosure, and the
  33. * third is for the power supply. The first two fans may be speed
  34. * controlled by changing the voltage fed to them. The third fan may
  35. * only be completely off or on. The third fan is meant to only be
  36. * disabled/enabled when entering/exiting the lowest power-saving
  37. * mode of the machine.
  38. *
  39. * An environmental control kernel thread periodically monitors all
  40. * temperature sensors. Based upon the samples it will adjust the
  41. * fan speeds to try and keep the system within a certain temperature
  42. * range (the goal being to make the fans as quiet as possible without
  43. * allowing the system to get too hot).
  44. *
  45. * If the temperature begins to rise/fall outside of the acceptable
  46. * operating range, a periodic warning will be sent to the kernel log.
  47. * The fans will be put on full blast to attempt to deal with this
  48. * situation. After exceeding the acceptable operating range by a
  49. * certain threshold, the kernel thread will shut down the system.
  50. * Here, the thread is attempting to shut the machine down cleanly
  51. * before the hardware based power-off event is triggered.
  52. */
  53. /* These settings are in Celsius. We use these defaults only
  54. * if we cannot interrogate the cpu-fru SEEPROM.
  55. */
  56. struct temp_limits {
  57. s8 high_pwroff, high_shutdown, high_warn;
  58. s8 low_warn, low_shutdown, low_pwroff;
  59. };
  60. static struct temp_limits cpu_temp_limits[2] = {
  61. { 100, 85, 80, 5, -5, -10 },
  62. { 100, 85, 80, 5, -5, -10 },
  63. };
  64. static struct temp_limits amb_temp_limits[2] = {
  65. { 65, 55, 40, 5, -5, -10 },
  66. { 65, 55, 40, 5, -5, -10 },
  67. };
  68. enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX };
  69. struct bbc_cpu_temperature {
  70. struct bbc_cpu_temperature *next;
  71. struct bbc_i2c_client *client;
  72. int index;
  73. /* Current readings, and history. */
  74. s8 curr_cpu_temp;
  75. s8 curr_amb_temp;
  76. s8 prev_cpu_temp;
  77. s8 prev_amb_temp;
  78. s8 avg_cpu_temp;
  79. s8 avg_amb_temp;
  80. int sample_tick;
  81. enum fan_action fan_todo[2];
  82. #define FAN_AMBIENT 0
  83. #define FAN_CPU 1
  84. };
  85. struct bbc_cpu_temperature *all_bbc_temps;
  86. struct bbc_fan_control {
  87. struct bbc_fan_control *next;
  88. struct bbc_i2c_client *client;
  89. int index;
  90. int psupply_fan_on;
  91. int cpu_fan_speed;
  92. int system_fan_speed;
  93. };
  94. struct bbc_fan_control *all_bbc_fans;
  95. #define CPU_FAN_REG 0xf0
  96. #define SYS_FAN_REG 0xf2
  97. #define PSUPPLY_FAN_REG 0xf4
  98. #define FAN_SPEED_MIN 0x0c
  99. #define FAN_SPEED_MAX 0x3f
  100. #define PSUPPLY_FAN_ON 0x1f
  101. #define PSUPPLY_FAN_OFF 0x00
  102. static void set_fan_speeds(struct bbc_fan_control *fp)
  103. {
  104. /* Put temperatures into range so we don't mis-program
  105. * the hardware.
  106. */
  107. if (fp->cpu_fan_speed < FAN_SPEED_MIN)
  108. fp->cpu_fan_speed = FAN_SPEED_MIN;
  109. if (fp->cpu_fan_speed > FAN_SPEED_MAX)
  110. fp->cpu_fan_speed = FAN_SPEED_MAX;
  111. if (fp->system_fan_speed < FAN_SPEED_MIN)
  112. fp->system_fan_speed = FAN_SPEED_MIN;
  113. if (fp->system_fan_speed > FAN_SPEED_MAX)
  114. fp->system_fan_speed = FAN_SPEED_MAX;
  115. #ifdef ENVCTRL_TRACE
  116. printk("fan%d: Changed fan speed to cpu(%02x) sys(%02x)\n",
  117. fp->index,
  118. fp->cpu_fan_speed, fp->system_fan_speed);
  119. #endif
  120. bbc_i2c_writeb(fp->client, fp->cpu_fan_speed, CPU_FAN_REG);
  121. bbc_i2c_writeb(fp->client, fp->system_fan_speed, SYS_FAN_REG);
  122. bbc_i2c_writeb(fp->client,
  123. (fp->psupply_fan_on ?
  124. PSUPPLY_FAN_ON : PSUPPLY_FAN_OFF),
  125. PSUPPLY_FAN_REG);
  126. }
  127. static void get_current_temps(struct bbc_cpu_temperature *tp)
  128. {
  129. tp->prev_amb_temp = tp->curr_amb_temp;
  130. bbc_i2c_readb(tp->client,
  131. (unsigned char *) &tp->curr_amb_temp,
  132. MAX1617_AMB_TEMP);
  133. tp->prev_cpu_temp = tp->curr_cpu_temp;
  134. bbc_i2c_readb(tp->client,
  135. (unsigned char *) &tp->curr_cpu_temp,
  136. MAX1617_CPU_TEMP);
  137. #ifdef ENVCTRL_TRACE
  138. printk("temp%d: cpu(%d C) amb(%d C)\n",
  139. tp->index,
  140. (int) tp->curr_cpu_temp, (int) tp->curr_amb_temp);
  141. #endif
  142. }
  143. static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp)
  144. {
  145. static int shutting_down = 0;
  146. static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
  147. char *argv[] = { "/sbin/shutdown", "-h", "now", NULL };
  148. char *type = "???";
  149. s8 val = -1;
  150. if (shutting_down != 0)
  151. return;
  152. if (tp->curr_amb_temp >= amb_temp_limits[tp->index].high_shutdown ||
  153. tp->curr_amb_temp < amb_temp_limits[tp->index].low_shutdown) {
  154. type = "ambient";
  155. val = tp->curr_amb_temp;
  156. } else if (tp->curr_cpu_temp >= cpu_temp_limits[tp->index].high_shutdown ||
  157. tp->curr_cpu_temp < cpu_temp_limits[tp->index].low_shutdown) {
  158. type = "CPU";
  159. val = tp->curr_cpu_temp;
  160. }
  161. printk(KERN_CRIT "temp%d: Outside of safe %s "
  162. "operating temperature, %d C.\n",
  163. tp->index, type, val);
  164. printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n");
  165. shutting_down = 1;
  166. if (call_usermodehelper("/sbin/shutdown", argv, envp, 0) < 0)
  167. printk(KERN_CRIT "envctrl: shutdown execution failed\n");
  168. }
  169. #define WARN_INTERVAL (30 * HZ)
  170. static void analyze_ambient_temp(struct bbc_cpu_temperature *tp, unsigned long *last_warn, int tick)
  171. {
  172. int ret = 0;
  173. if (time_after(jiffies, (*last_warn + WARN_INTERVAL))) {
  174. if (tp->curr_amb_temp >=
  175. amb_temp_limits[tp->index].high_warn) {
  176. printk(KERN_WARNING "temp%d: "
  177. "Above safe ambient operating temperature, %d C.\n",
  178. tp->index, (int) tp->curr_amb_temp);
  179. ret = 1;
  180. } else if (tp->curr_amb_temp <
  181. amb_temp_limits[tp->index].low_warn) {
  182. printk(KERN_WARNING "temp%d: "
  183. "Below safe ambient operating temperature, %d C.\n",
  184. tp->index, (int) tp->curr_amb_temp);
  185. ret = 1;
  186. }
  187. if (ret)
  188. *last_warn = jiffies;
  189. } else if (tp->curr_amb_temp >= amb_temp_limits[tp->index].high_warn ||
  190. tp->curr_amb_temp < amb_temp_limits[tp->index].low_warn)
  191. ret = 1;
  192. /* Now check the shutdown limits. */
  193. if (tp->curr_amb_temp >= amb_temp_limits[tp->index].high_shutdown ||
  194. tp->curr_amb_temp < amb_temp_limits[tp->index].low_shutdown) {
  195. do_envctrl_shutdown(tp);
  196. ret = 1;
  197. }
  198. if (ret) {
  199. tp->fan_todo[FAN_AMBIENT] = FAN_FULLBLAST;
  200. } else if ((tick & (8 - 1)) == 0) {
  201. s8 amb_goal_hi = amb_temp_limits[tp->index].high_warn - 10;
  202. s8 amb_goal_lo;
  203. amb_goal_lo = amb_goal_hi - 3;
  204. /* We do not try to avoid 'too cold' events. Basically we
  205. * only try to deal with over-heating and fan noise reduction.
  206. */
  207. if (tp->avg_amb_temp < amb_goal_hi) {
  208. if (tp->avg_amb_temp >= amb_goal_lo)
  209. tp->fan_todo[FAN_AMBIENT] = FAN_SAME;
  210. else
  211. tp->fan_todo[FAN_AMBIENT] = FAN_SLOWER;
  212. } else {
  213. tp->fan_todo[FAN_AMBIENT] = FAN_FASTER;
  214. }
  215. } else {
  216. tp->fan_todo[FAN_AMBIENT] = FAN_SAME;
  217. }
  218. }
  219. static void analyze_cpu_temp(struct bbc_cpu_temperature *tp, unsigned long *last_warn, int tick)
  220. {
  221. int ret = 0;
  222. if (time_after(jiffies, (*last_warn + WARN_INTERVAL))) {
  223. if (tp->curr_cpu_temp >=
  224. cpu_temp_limits[tp->index].high_warn) {
  225. printk(KERN_WARNING "temp%d: "
  226. "Above safe CPU operating temperature, %d C.\n",
  227. tp->index, (int) tp->curr_cpu_temp);
  228. ret = 1;
  229. } else if (tp->curr_cpu_temp <
  230. cpu_temp_limits[tp->index].low_warn) {
  231. printk(KERN_WARNING "temp%d: "
  232. "Below safe CPU operating temperature, %d C.\n",
  233. tp->index, (int) tp->curr_cpu_temp);
  234. ret = 1;
  235. }
  236. if (ret)
  237. *last_warn = jiffies;
  238. } else if (tp->curr_cpu_temp >= cpu_temp_limits[tp->index].high_warn ||
  239. tp->curr_cpu_temp < cpu_temp_limits[tp->index].low_warn)
  240. ret = 1;
  241. /* Now check the shutdown limits. */
  242. if (tp->curr_cpu_temp >= cpu_temp_limits[tp->index].high_shutdown ||
  243. tp->curr_cpu_temp < cpu_temp_limits[tp->index].low_shutdown) {
  244. do_envctrl_shutdown(tp);
  245. ret = 1;
  246. }
  247. if (ret) {
  248. tp->fan_todo[FAN_CPU] = FAN_FULLBLAST;
  249. } else if ((tick & (8 - 1)) == 0) {
  250. s8 cpu_goal_hi = cpu_temp_limits[tp->index].high_warn - 10;
  251. s8 cpu_goal_lo;
  252. cpu_goal_lo = cpu_goal_hi - 3;
  253. /* We do not try to avoid 'too cold' events. Basically we
  254. * only try to deal with over-heating and fan noise reduction.
  255. */
  256. if (tp->avg_cpu_temp < cpu_goal_hi) {
  257. if (tp->avg_cpu_temp >= cpu_goal_lo)
  258. tp->fan_todo[FAN_CPU] = FAN_SAME;
  259. else
  260. tp->fan_todo[FAN_CPU] = FAN_SLOWER;
  261. } else {
  262. tp->fan_todo[FAN_CPU] = FAN_FASTER;
  263. }
  264. } else {
  265. tp->fan_todo[FAN_CPU] = FAN_SAME;
  266. }
  267. }
  268. static void analyze_temps(struct bbc_cpu_temperature *tp, unsigned long *last_warn)
  269. {
  270. tp->avg_amb_temp = (s8)((int)((int)tp->avg_amb_temp + (int)tp->curr_amb_temp) / 2);
  271. tp->avg_cpu_temp = (s8)((int)((int)tp->avg_cpu_temp + (int)tp->curr_cpu_temp) / 2);
  272. analyze_ambient_temp(tp, last_warn, tp->sample_tick);
  273. analyze_cpu_temp(tp, last_warn, tp->sample_tick);
  274. tp->sample_tick++;
  275. }
  276. static enum fan_action prioritize_fan_action(int which_fan)
  277. {
  278. struct bbc_cpu_temperature *tp;
  279. enum fan_action decision = FAN_STATE_MAX;
  280. /* Basically, prioritize what the temperature sensors
  281. * recommend we do, and perform that action on all the
  282. * fans.
  283. */
  284. for (tp = all_bbc_temps; tp; tp = tp->next) {
  285. if (tp->fan_todo[which_fan] == FAN_FULLBLAST) {
  286. decision = FAN_FULLBLAST;
  287. break;
  288. }
  289. if (tp->fan_todo[which_fan] == FAN_SAME &&
  290. decision != FAN_FASTER)
  291. decision = FAN_SAME;
  292. else if (tp->fan_todo[which_fan] == FAN_FASTER)
  293. decision = FAN_FASTER;
  294. else if (decision != FAN_FASTER &&
  295. decision != FAN_SAME &&
  296. tp->fan_todo[which_fan] == FAN_SLOWER)
  297. decision = FAN_SLOWER;
  298. }
  299. if (decision == FAN_STATE_MAX)
  300. decision = FAN_SAME;
  301. return decision;
  302. }
  303. static int maybe_new_ambient_fan_speed(struct bbc_fan_control *fp)
  304. {
  305. enum fan_action decision = prioritize_fan_action(FAN_AMBIENT);
  306. int ret;
  307. if (decision == FAN_SAME)
  308. return 0;
  309. ret = 1;
  310. if (decision == FAN_FULLBLAST) {
  311. if (fp->system_fan_speed >= FAN_SPEED_MAX)
  312. ret = 0;
  313. else
  314. fp->system_fan_speed = FAN_SPEED_MAX;
  315. } else {
  316. if (decision == FAN_FASTER) {
  317. if (fp->system_fan_speed >= FAN_SPEED_MAX)
  318. ret = 0;
  319. else
  320. fp->system_fan_speed += 2;
  321. } else {
  322. int orig_speed = fp->system_fan_speed;
  323. if (orig_speed <= FAN_SPEED_MIN ||
  324. orig_speed <= (fp->cpu_fan_speed - 3))
  325. ret = 0;
  326. else
  327. fp->system_fan_speed -= 1;
  328. }
  329. }
  330. return ret;
  331. }
  332. static int maybe_new_cpu_fan_speed(struct bbc_fan_control *fp)
  333. {
  334. enum fan_action decision = prioritize_fan_action(FAN_CPU);
  335. int ret;
  336. if (decision == FAN_SAME)
  337. return 0;
  338. ret = 1;
  339. if (decision == FAN_FULLBLAST) {
  340. if (fp->cpu_fan_speed >= FAN_SPEED_MAX)
  341. ret = 0;
  342. else
  343. fp->cpu_fan_speed = FAN_SPEED_MAX;
  344. } else {
  345. if (decision == FAN_FASTER) {
  346. if (fp->cpu_fan_speed >= FAN_SPEED_MAX)
  347. ret = 0;
  348. else {
  349. fp->cpu_fan_speed += 2;
  350. if (fp->system_fan_speed <
  351. (fp->cpu_fan_speed - 3))
  352. fp->system_fan_speed =
  353. fp->cpu_fan_speed - 3;
  354. }
  355. } else {
  356. if (fp->cpu_fan_speed <= FAN_SPEED_MIN)
  357. ret = 0;
  358. else
  359. fp->cpu_fan_speed -= 1;
  360. }
  361. }
  362. return ret;
  363. }
  364. static void maybe_new_fan_speeds(struct bbc_fan_control *fp)
  365. {
  366. int new;
  367. new = maybe_new_ambient_fan_speed(fp);
  368. new |= maybe_new_cpu_fan_speed(fp);
  369. if (new)
  370. set_fan_speeds(fp);
  371. }
  372. static void fans_full_blast(void)
  373. {
  374. struct bbc_fan_control *fp;
  375. /* Since we will not be monitoring things anymore, put
  376. * the fans on full blast.
  377. */
  378. for (fp = all_bbc_fans; fp; fp = fp->next) {
  379. fp->cpu_fan_speed = FAN_SPEED_MAX;
  380. fp->system_fan_speed = FAN_SPEED_MAX;
  381. fp->psupply_fan_on = 1;
  382. set_fan_speeds(fp);
  383. }
  384. }
  385. #define POLL_INTERVAL (5 * 1000)
  386. static unsigned long last_warning_jiffies;
  387. static struct task_struct *kenvctrld_task;
  388. static int kenvctrld(void *__unused)
  389. {
  390. printk(KERN_INFO "bbc_envctrl: kenvctrld starting...\n");
  391. last_warning_jiffies = jiffies - WARN_INTERVAL;
  392. for (;;) {
  393. struct bbc_cpu_temperature *tp;
  394. struct bbc_fan_control *fp;
  395. msleep_interruptible(POLL_INTERVAL);
  396. if (kthread_should_stop())
  397. break;
  398. for (tp = all_bbc_temps; tp; tp = tp->next) {
  399. get_current_temps(tp);
  400. analyze_temps(tp, &last_warning_jiffies);
  401. }
  402. for (fp = all_bbc_fans; fp; fp = fp->next)
  403. maybe_new_fan_speeds(fp);
  404. }
  405. printk(KERN_INFO "bbc_envctrl: kenvctrld exiting...\n");
  406. fans_full_blast();
  407. return 0;
  408. }
  409. static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx)
  410. {
  411. struct bbc_cpu_temperature *tp = kmalloc(sizeof(*tp), GFP_KERNEL);
  412. if (!tp)
  413. return;
  414. memset(tp, 0, sizeof(*tp));
  415. tp->client = bbc_i2c_attach(echild);
  416. if (!tp->client) {
  417. kfree(tp);
  418. return;
  419. }
  420. tp->index = temp_idx;
  421. {
  422. struct bbc_cpu_temperature **tpp = &all_bbc_temps;
  423. while (*tpp)
  424. tpp = &((*tpp)->next);
  425. tp->next = NULL;
  426. *tpp = tp;
  427. }
  428. /* Tell it to convert once every 5 seconds, clear all cfg
  429. * bits.
  430. */
  431. bbc_i2c_writeb(tp->client, 0x00, MAX1617_WR_CFG_BYTE);
  432. bbc_i2c_writeb(tp->client, 0x02, MAX1617_WR_CVRATE_BYTE);
  433. /* Program the hard temperature limits into the chip. */
  434. bbc_i2c_writeb(tp->client, amb_temp_limits[tp->index].high_pwroff,
  435. MAX1617_WR_AMB_HIGHLIM);
  436. bbc_i2c_writeb(tp->client, amb_temp_limits[tp->index].low_pwroff,
  437. MAX1617_WR_AMB_LOWLIM);
  438. bbc_i2c_writeb(tp->client, cpu_temp_limits[tp->index].high_pwroff,
  439. MAX1617_WR_CPU_HIGHLIM);
  440. bbc_i2c_writeb(tp->client, cpu_temp_limits[tp->index].low_pwroff,
  441. MAX1617_WR_CPU_LOWLIM);
  442. get_current_temps(tp);
  443. tp->prev_cpu_temp = tp->avg_cpu_temp = tp->curr_cpu_temp;
  444. tp->prev_amb_temp = tp->avg_amb_temp = tp->curr_amb_temp;
  445. tp->fan_todo[FAN_AMBIENT] = FAN_SAME;
  446. tp->fan_todo[FAN_CPU] = FAN_SAME;
  447. }
  448. static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
  449. {
  450. struct bbc_fan_control *fp = kmalloc(sizeof(*fp), GFP_KERNEL);
  451. if (!fp)
  452. return;
  453. memset(fp, 0, sizeof(*fp));
  454. fp->client = bbc_i2c_attach(echild);
  455. if (!fp->client) {
  456. kfree(fp);
  457. return;
  458. }
  459. fp->index = fan_idx;
  460. {
  461. struct bbc_fan_control **fpp = &all_bbc_fans;
  462. while (*fpp)
  463. fpp = &((*fpp)->next);
  464. fp->next = NULL;
  465. *fpp = fp;
  466. }
  467. /* The i2c device controlling the fans is write-only.
  468. * So the only way to keep track of the current power
  469. * level fed to the fans is via software. Choose half
  470. * power for cpu/system and 'on' fo the powersupply fan
  471. * and set it now.
  472. */
  473. fp->psupply_fan_on = 1;
  474. fp->cpu_fan_speed = (FAN_SPEED_MAX - FAN_SPEED_MIN) / 2;
  475. fp->cpu_fan_speed += FAN_SPEED_MIN;
  476. fp->system_fan_speed = (FAN_SPEED_MAX - FAN_SPEED_MIN) / 2;
  477. fp->system_fan_speed += FAN_SPEED_MIN;
  478. set_fan_speeds(fp);
  479. }
  480. int bbc_envctrl_init(void)
  481. {
  482. struct linux_ebus_child *echild;
  483. int temp_index = 0;
  484. int fan_index = 0;
  485. int devidx = 0;
  486. while ((echild = bbc_i2c_getdev(devidx++)) != NULL) {
  487. if (!strcmp(echild->prom_node->name, "temperature"))
  488. attach_one_temp(echild, temp_index++);
  489. if (!strcmp(echild->prom_node->name, "fan-control"))
  490. attach_one_fan(echild, fan_index++);
  491. }
  492. if (temp_index != 0 && fan_index != 0) {
  493. kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld");
  494. if (IS_ERR(kenvctrld_task))
  495. return PTR_ERR(kenvctrld_task);
  496. }
  497. return 0;
  498. }
  499. static void destroy_one_temp(struct bbc_cpu_temperature *tp)
  500. {
  501. bbc_i2c_detach(tp->client);
  502. kfree(tp);
  503. }
  504. static void destroy_one_fan(struct bbc_fan_control *fp)
  505. {
  506. bbc_i2c_detach(fp->client);
  507. kfree(fp);
  508. }
  509. void bbc_envctrl_cleanup(void)
  510. {
  511. struct bbc_cpu_temperature *tp;
  512. struct bbc_fan_control *fp;
  513. kthread_stop(kenvctrld_task);
  514. tp = all_bbc_temps;
  515. while (tp != NULL) {
  516. struct bbc_cpu_temperature *next = tp->next;
  517. destroy_one_temp(tp);
  518. tp = next;
  519. }
  520. all_bbc_temps = NULL;
  521. fp = all_bbc_fans;
  522. while (fp != NULL) {
  523. struct bbc_fan_control *next = fp->next;
  524. destroy_one_fan(fp);
  525. fp = next;
  526. }
  527. all_bbc_fans = NULL;
  528. }