bbc_envctrl.c 16 KB

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