1 /* $NetBSD: envmon_ebus.c,v 1.1 2026/09/07 07:35:13 jdc Exp $ */ 2 3 /*- 4 * Copyright (c) 2026 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Julian Coleman. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: envmon_ebus.c,v 1.1 2026/09/07 07:35:13 jdc Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/kernel.h> 37 #include <sys/device.h> 38 #include <sys/proc.h> 39 #include <sys/types.h> 40 41 #include <sys/bus.h> 42 #include <machine/autoconf.h> 43 44 #include <dev/ebus/ebusreg.h> 45 #include <dev/ebus/ebusvar.h> 46 47 #include <dev/led.h> 48 #include <dev/sysmon/sysmonvar.h> 49 50 #include <arch/sparc64/dev/envmon_ebusreg.h> 51 52 #define ENVMON_MACHINE_U25 0x19 53 #define ENVMON_MACHINE_U45 0x2d 54 #define ENVMON_MACHINE_V215 0xd7 55 #define ENVMON_MACHINE_V245 0xf5 56 57 #define ENVMON_PIC_MAX_TEMPS 1 58 #define ENVMON_PIC_WMIN_TEMP 273150000 /* 0C from Solaris */ 59 #define ENVMON_PIC_WMAX_TEMP 318150000 /* 45C from Solaris */ 60 #define ENVMON_PIC_CRIT_TEMP 338150000 /* 65C from Solaris */ 61 62 struct envmon_epic_fans { 63 const uint8_t reg; 64 const char *desc; 65 }; 66 static struct envmon_epic_fans envmon_epic_fans_table[] = { 67 { ENVMON_EPC_FAN_FT0_F0, "FT0.F0" }, 68 { ENVMON_EPC_FAN_FT1_F0, "FT1.F0" }, 69 { ENVMON_EPC_FAN_FT2_F0, "FT2.F0" }, 70 { ENVMON_EPC_FAN_FT3_F0, "FT3.F0" }, 71 { ENVMON_EPC_FAN_FT4_F0, "FT4.F0" }, 72 { ENVMON_EPC_FAN_FT5_F0, "FT5.F0" }, 73 { ENVMON_EPC_FAN_FT0_F1, "FT0.F1" }, 74 { ENVMON_EPC_FAN_FT1_F1, "FT1.F1" }, 75 { ENVMON_EPC_FAN_FT2_F1, "FT2.F1" }, 76 { ENVMON_EPC_FAN_FT3_F1, "FT3.F1" }, 77 { ENVMON_EPC_FAN_FT4_F1, "FT4.F1" }, 78 { ENVMON_EPC_FAN_FT5_F1, "FT5.F1" }, 79 }; 80 #define ENVMON_EPC_MAX_FANS (sizeof(envmon_epic_fans_table) / \ 81 sizeof(envmon_epic_fans_table[0])) 82 #define ENVMON_EPC_DIV_V245 5625 83 #define ENVMON_EPC_DIV_V215 11250 84 #define ENVMON_EPC_CRIT_SPEED_V245 2022 /* From ALOM */ 85 #define ENVMON_EPC_CRIT_SPEED_V215 5012 /* From ALOM */ 86 #define ENVMON_EPC_WMIN_TEMP 273150000 /* 0C from ALOM */ 87 #define ENVMON_EPC_WMAX_TEMP 318150000 /* 45C from ALOM */ 88 #define ENVMON_EPC_CRIT_TEMP 323150000 /* 50C from ALOM */ 89 #define ENVMON_EPC_VAL_TO_SPEED(div, val) ((div * 60) / val) 90 91 #define ENVMON_EPC_MAX_FAULTS 1 92 93 #define ENVMON_EPC_MAX_TEMPS 1 94 95 struct envmon_epic_ind { 96 uint8_t reg, set; 97 const char *desc; 98 }; 99 static struct envmon_epic_ind envmon_epic_inds_table[] = { 100 { ENVMON_EPC_KEYSW, ENVMON_EPC_KEYSW_NORM, "keyswitch normal/diag" }, 101 { ENVMON_EPC_KEYSW, ENVMON_EPC_KEYSW_LOCK, "keyswitch locked" }, 102 }; 103 104 #define ENVMON_EPC_MAX_INDS (sizeof(envmon_epic_inds_table) / \ 105 sizeof(envmon_epic_inds_table[0])) 106 107 struct envmon_epic_led { 108 uint8_t reg, v_on; 109 const char *desc; 110 }; 111 static struct envmon_epic_led envmon_epic_led_table[] = { 112 { ENVMON_EPC_LED6, ENVMON_EPC_LED6_LOC, "locator" }, 113 { ENVMON_EPC_LED6, ENVMON_EPC_LED6_SRV, "service" }, 114 { ENVMON_EPC_LED6, ENVMON_EPC_LED6_SRV_FSH, "service_flash" }, 115 { ENVMON_EPC_LED6, ENVMON_EPC_LED6_PWR, "power" }, 116 { ENVMON_EPC_LED6, ENVMON_EPC_LED6_TF_FLT, "top_fan_fault" }, 117 { ENVMON_EPC_LED6, ENVMON_EPC_LED6_TF_FLT_FSH, "top_fan_fault_flash" }, 118 { ENVMON_EPC_LED7, ENVMON_EPC_LED7_PSU, "psu_fault" }, 119 { ENVMON_EPC_LED7, ENVMON_EPC_LED7_PSU_FSH, "psu_fault_flash" }, 120 { ENVMON_EPC_LED7, ENVMON_EPC_LED7_CTEMP, "cpu_overtemp" }, 121 { ENVMON_EPC_LED7, ENVMON_EPC_LED7_CTEMP_FSH, "cpu_overtemp_flash" }, 122 }; 123 #define ENVMON_EPC_MAX_LEDS (sizeof(envmon_epic_led_table) / \ 124 sizeof(envmon_epic_led_table[0])) 125 126 #define ENVMON_EPC_MAX_SENSORS \ 127 (ENVMON_EPC_MAX_FANS + ENVMON_EPC_MAX_FAULTS + \ 128 ENVMON_EPC_MAX_TEMPS + ENVMON_EPC_MAX_INDS) 129 130 #define ENVMON_MAX_TEMPS \ 131 MAX(ENVMON_PIC_MAX_TEMPS, ENVMON_EPC_MAX_TEMPS) 132 #define ENVMON_MAX_SENSORS \ 133 MAX(ENVMON_PIC_MAX_TEMPS, ENVMON_EPC_MAX_SENSORS) 134 135 struct envmon_sc_fan { 136 uint8_t reg; 137 int cmin; 138 }; 139 140 struct envmon_sc_temp { 141 uint8_t reg; 142 int wmin, wmax, cmax; 143 }; 144 145 struct envmon_sc_ind { 146 uint8_t reg, set; 147 }; 148 struct envmon_sc_led { 149 void *cookie; 150 struct led_device *led; 151 uint8_t reg, v_on; 152 }; 153 154 struct envmon_softc { 155 device_t sc_dev; 156 157 bus_space_tag_t sc_bst; 158 bus_space_handle_t sc_bsh; 159 160 int sc_machine_type, sc_nfans; 161 struct envmon_sc_fan sc_fan[ENVMON_EPC_MAX_FANS]; 162 struct envmon_sc_temp sc_temp[ENVMON_MAX_TEMPS]; 163 struct envmon_sc_ind sc_ind[ENVMON_EPC_MAX_INDS]; 164 struct envmon_sc_led sc_led[ENVMON_EPC_MAX_LEDS]; 165 struct sysmon_envsys *sc_sme; 166 envsys_data_t sc_sensor[ENVMON_MAX_SENSORS]; 167 168 #ifdef ENVMON_DEBUG 169 #define ENVMON_MAX_REG 0x3d 170 uint8_t sc_reg[ENVMON_MAX_REG]; 171 #define ENVMON_TIMER 60 172 callout_t sc_timer; 173 #endif 174 }; 175 176 static int envmon_ebus_match(device_t, cfdata_t, void *); 177 static void envmon_ebus_attach(device_t, device_t, void *); 178 static void envmon_pic_attach(struct envmon_softc *, int); 179 static void envmon_epic_attach(struct envmon_softc *, int); 180 void envmon_pic_refresh(struct sysmon_envsys *, envsys_data_t *); 181 void envmon_epic_refresh(struct sysmon_envsys *, envsys_data_t *); 182 void envmon_epic_refresh_fan(struct envmon_softc *, envsys_data_t *); 183 void envmon_epic_refresh_fault(struct envmon_softc *, envsys_data_t *); 184 void envmon_refresh_temp(struct envmon_softc *, envsys_data_t *); 185 void envmon_epic_refresh_ind(struct envmon_softc *, envsys_data_t *); 186 void envmon_pic_get_limits(struct sysmon_envsys *, envsys_data_t *, 187 sysmon_envsys_lim_t *, uint32_t *); 188 void envmon_pic_set_limits(struct sysmon_envsys *, envsys_data_t *, 189 sysmon_envsys_lim_t *, uint32_t *); 190 void envmon_epic_get_limits(struct sysmon_envsys *, envsys_data_t *, 191 sysmon_envsys_lim_t *, uint32_t *); 192 void envmon_epic_set_limits(struct sysmon_envsys *, envsys_data_t *, 193 sysmon_envsys_lim_t *, uint32_t *); 194 static void envmon_epic_get_fan_limits(struct envmon_softc *, 195 envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *); 196 static void envmon_get_temp_limits(struct envmon_softc *, 197 envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *); 198 static void envmon_epic_set_fan_limits(struct envmon_softc *, 199 envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *); 200 static void envmon_set_temp_limits(struct envmon_softc *, 201 envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *); 202 int envmon_epic_get_led(void *); 203 void envmon_epic_set_led(void *, int); 204 #ifdef ENVMON_DEBUG 205 static void envmon_timeout(void *); 206 #endif 207 208 CFATTACH_DECL_NEW(envmon_ebus, sizeof(struct envmon_softc), 209 envmon_ebus_match, envmon_ebus_attach, NULL, NULL); 210 211 #define envmon_read(sc, reg) \ 212 bus_space_read_1(sc->sc_bst, sc->sc_bsh, reg) 213 #define envmon_write(sc, reg, val) \ 214 bus_space_write_1(sc->sc_bst, sc->sc_bsh, reg, val) 215 216 static int 217 envmon_ebus_match(device_t parent, cfdata_t cf, void *aux) 218 { 219 struct ebus_attach_args *ea = aux; 220 char *compat; 221 222 if (strcmp("env-monitor", ea->ea_name) != 0) 223 return 0; 224 225 compat = prom_getpropstring(ea->ea_node, "compatible"); 226 if (compat != NULL && (!strcmp(compat, "SUNW,ebus-pic16f747-env") || 227 !strcmp(compat, "epic"))) 228 return 1; 229 230 return 0; 231 } 232 233 static void 234 envmon_ebus_attach(device_t parent, device_t self, void *aux) 235 { 236 struct envmon_softc *sc = device_private(self); 237 struct ebus_attach_args *ea = aux; 238 char compat[32]; 239 int sz; 240 #ifdef ENVMON_DEBUG 241 uint8_t reg; 242 #endif 243 244 sc->sc_dev = self; 245 sc->sc_bst = ea->ea_bustag; 246 247 sz = ea->ea_reg[0].size; 248 249 if (bus_space_map(sc->sc_bst, 250 EBUS_ADDR_FROM_REG(&ea->ea_reg[0]), 251 sz, 0, 252 &sc->sc_bsh) != 0) { 253 aprint_error(": can't map register\n"); 254 return; 255 } 256 257 sc->sc_sme = sysmon_envsys_create(); 258 sc->sc_sme->sme_name = device_xname(self); 259 sc->sc_sme->sme_cookie = sc; 260 261 OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat)); 262 263 if (!strcmp(compat, "SUNW,ebus-pic16f747-env")) { 264 envmon_pic_attach(sc, ea->ea_node); 265 } 266 if (!strcmp(compat, "epic")) { 267 envmon_epic_attach(sc, ea->ea_node); 268 } 269 270 #ifdef ENVMON_DEBUG 271 for (reg = 0; reg < ENVMON_MAX_REG; reg++) { 272 envmon_write(sc, ENVMON_ADDR, reg); 273 sc->sc_reg[reg] = envmon_read(sc, ENVMON_DATA); 274 } 275 callout_init(&sc->sc_timer, CALLOUT_MPSAFE); 276 callout_reset(&sc->sc_timer, hz * ENVMON_TIMER, envmon_timeout, sc); 277 #endif 278 } 279 280 /* 281 * We only add the front panel temperature here. 282 * Other U45 sensors are handled by the ADT7462 driver. 283 */ 284 static void 285 envmon_pic_attach(struct envmon_softc *sc, int node) 286 { 287 int32_t vers; 288 289 vers = prom_getpropint(node, "version", 0); 290 aprint_normal(": pic16f747 (ver. %d)\n", vers); 291 292 if (!strcmp(machine_model, "SUNW,A70")) { 293 sc->sc_machine_type = ENVMON_MACHINE_U45; 294 } else if (!strcmp(machine_model, "SUNW,Ultra-25")) { 295 sc->sc_machine_type = ENVMON_MACHINE_U25; 296 } else { 297 aprint_error_dev(sc->sc_dev, "unsupported machine model\n"); 298 return; 299 } 300 301 sc->sc_sme->sme_refresh = envmon_pic_refresh; 302 sc->sc_sme->sme_get_limits = envmon_pic_get_limits; 303 sc->sc_sme->sme_set_limits = envmon_pic_set_limits; 304 305 strlcpy(sc->sc_sensor[0].desc, "Front_panel", 306 sizeof(sc->sc_sensor[0].desc)); 307 sc->sc_sensor[0].units = ENVSYS_STEMP; 308 sc->sc_sensor[0].state = ENVSYS_SINVALID; 309 sc->sc_sensor[0].flags = ENVSYS_FHAS_ENTROPY | ENVSYS_FMONLIMITS | 310 ENVSYS_FMONCRITICAL; 311 sc->sc_temp[0].reg = ENVMON_PIC_TEMP_FP; 312 sc->sc_temp[0].wmin = ENVMON_PIC_WMIN_TEMP; 313 sc->sc_temp[0].wmax = ENVMON_PIC_WMAX_TEMP; 314 sc->sc_temp[0].cmax = ENVMON_PIC_CRIT_TEMP; 315 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[0])) { 316 sysmon_envsys_destroy(sc->sc_sme); 317 sc->sc_sme = NULL; 318 aprint_error_dev(sc->sc_dev, 319 "unable to attach sensor to sysmon\n"); 320 return; 321 } 322 323 if (sysmon_envsys_register(sc->sc_sme)) { 324 aprint_error_dev(sc->sc_dev, 325 "unable to register with sysmon\n"); 326 sysmon_envsys_destroy(sc->sc_sme); 327 sc->sc_sme = NULL; 328 return; 329 } 330 331 return; 332 } 333 334 static void 335 envmon_epic_attach(struct envmon_softc *sc, int node) 336 { 337 const char *vers; 338 int cmin, i, j; 339 340 vers = prom_getpropstring(node, "version"); 341 aprint_normal(": epic (ver. %s)\n", vers); 342 343 /* Fans */ 344 if (!strcmp(machine_model, "SUNW,Sun-Fire-V245")) { 345 sc->sc_machine_type = ENVMON_MACHINE_V245; 346 sc->sc_nfans = 6; 347 cmin = ENVMON_EPC_CRIT_SPEED_V245; 348 } else if (!strcmp(machine_model, "SUNW,Sun-Fire-V215")) { 349 sc->sc_machine_type = ENVMON_MACHINE_V215; 350 sc->sc_nfans = 12; 351 cmin = ENVMON_EPC_CRIT_SPEED_V215; 352 } else { 353 aprint_error_dev(sc->sc_dev, "unsupported machine model\n"); 354 return; 355 } 356 357 sc->sc_sme->sme_refresh = envmon_epic_refresh; 358 sc->sc_sme->sme_get_limits = envmon_epic_get_limits; 359 sc->sc_sme->sme_set_limits = envmon_epic_set_limits; 360 361 for (i = 0; i < sc->sc_nfans; i++) { 362 strlcpy(sc->sc_sensor[i].desc, envmon_epic_fans_table[i].desc, 363 sizeof(sc->sc_sensor[i].desc)); 364 sc->sc_sensor[i].units = ENVSYS_SFANRPM; 365 sc->sc_sensor[i].state = ENVSYS_SINVALID; 366 sc->sc_sensor[i].flags = ENVSYS_FMONLIMITS | 367 ENVSYS_FMONCRITICAL; 368 sc->sc_fan[i].reg = envmon_epic_fans_table[i].reg; 369 sc->sc_fan[i].cmin = cmin; 370 if (sysmon_envsys_sensor_attach(sc->sc_sme, 371 &sc->sc_sensor[i])) { 372 sysmon_envsys_destroy(sc->sc_sme); 373 sc->sc_sme = NULL; 374 aprint_error_dev(sc->sc_dev, 375 "unable to attach sensor to sysmon\n"); 376 goto leds; 377 } 378 } 379 380 /* Fan fault */ 381 i = sc->sc_nfans; 382 strlcpy(sc->sc_sensor[i].desc, "fan fault", 383 sizeof(sc->sc_sensor[i].desc)); 384 sc->sc_sensor[i].units = ENVSYS_INTEGER; 385 sc->sc_sensor[i].state = ENVSYS_SINVALID; 386 sc->sc_sensor[i].flags = ENVSYS_FMONCRITICAL; 387 if (sysmon_envsys_sensor_attach( 388 sc->sc_sme, &sc->sc_sensor[i])) { 389 aprint_error_dev(sc->sc_dev, 390 "unable to attach fan fault at sysmon\n"); 391 goto leds; 392 } 393 i++; 394 395 /* Temperature */ 396 strlcpy(sc->sc_sensor[i].desc, "FIOB.T_AMB", 397 sizeof(sc->sc_sensor[i].desc)); 398 sc->sc_sensor[i].units = ENVSYS_STEMP; 399 sc->sc_sensor[i].state = ENVSYS_SINVALID; 400 sc->sc_sensor[i].flags = ENVSYS_FHAS_ENTROPY | ENVSYS_FMONLIMITS | 401 ENVSYS_FMONCRITICAL; 402 sc->sc_temp[0].reg = ENVMON_EPC_TEMP_FP; 403 sc->sc_temp[0].wmin = ENVMON_EPC_WMIN_TEMP; 404 sc->sc_temp[0].wmax = ENVMON_EPC_WMAX_TEMP; 405 sc->sc_temp[0].cmax = ENVMON_EPC_CRIT_TEMP; 406 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[i])) { 407 sysmon_envsys_destroy(sc->sc_sme); 408 sc->sc_sme = NULL; 409 aprint_error_dev(sc->sc_dev, 410 "unable to attach sensor to sysmon\n"); 411 goto leds; 412 } 413 i++; 414 415 /* Indicators */ 416 for (j = 0; j < ENVMON_EPC_MAX_INDS; j++, i++) { 417 strlcpy(sc->sc_sensor[i].desc, envmon_epic_inds_table[j].desc, 418 sizeof(sc->sc_sensor[i].desc)); 419 sc->sc_sensor[i].units = ENVSYS_INDICATOR; 420 sc->sc_sensor[i].state = ENVSYS_SINVALID; 421 sc->sc_ind[j].reg = envmon_epic_inds_table[j].reg; 422 sc->sc_ind[j].set = envmon_epic_inds_table[j].set; 423 if (sysmon_envsys_sensor_attach(sc->sc_sme, 424 &sc->sc_sensor[i])) { 425 sysmon_envsys_destroy(sc->sc_sme); 426 sc->sc_sme = NULL; 427 aprint_error_dev(sc->sc_dev, 428 "unable to attach sensor to sysmon\n"); 429 goto leds; 430 } 431 } 432 433 if (sysmon_envsys_register(sc->sc_sme)) { 434 aprint_error_dev(sc->sc_dev, 435 "unable to register with sysmon\n"); 436 sysmon_envsys_destroy(sc->sc_sme); 437 sc->sc_sme = NULL; 438 } 439 440 leds: 441 /* LED's */ 442 for (i = 0; i < ENVMON_EPC_MAX_LEDS; i++) { 443 sc->sc_led[i].cookie = sc; 444 sc->sc_led[i].reg = envmon_epic_led_table[i].reg; 445 sc->sc_led[i].v_on = envmon_epic_led_table[i].v_on; 446 led_attach(envmon_epic_led_table[i].desc, 447 &sc->sc_led[i], envmon_epic_get_led, envmon_epic_set_led); 448 } 449 450 return; 451 } 452 453 void 454 envmon_pic_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 455 { 456 struct envmon_softc *sc = sme->sme_cookie; 457 458 envmon_refresh_temp(sc, edata); 459 } 460 461 void 462 envmon_epic_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 463 { 464 struct envmon_softc *sc = sme->sme_cookie; 465 466 if (edata->sensor < sc->sc_nfans) 467 envmon_epic_refresh_fan(sc, edata); 468 else if (edata->sensor < sc->sc_nfans + ENVMON_EPC_MAX_FAULTS) 469 envmon_epic_refresh_fault(sc, edata); 470 else if (edata->sensor < 471 sc->sc_nfans + ENVMON_EPC_MAX_FAULTS + ENVMON_EPC_MAX_TEMPS) 472 envmon_refresh_temp(sc, edata); 473 else 474 envmon_epic_refresh_ind(sc, edata); 475 476 return; 477 } 478 479 void 480 envmon_epic_refresh_fan(struct envmon_softc *sc, envsys_data_t *edata) 481 { 482 uint8_t val; 483 int div; 484 485 if (sc->sc_machine_type == ENVMON_MACHINE_V245) 486 div = ENVMON_EPC_DIV_V245; 487 else 488 div = ENVMON_EPC_DIV_V215; 489 490 envmon_write(sc, ENVMON_ADDR, sc->sc_fan[edata->sensor].reg); 491 val = envmon_read(sc, ENVMON_DATA); 492 if (val == 0xff || val == 0x0) 493 edata->value_cur = 0; 494 else { 495 edata->value_cur = ENVMON_EPC_VAL_TO_SPEED(div, val); 496 } 497 if (edata->value_cur < sc->sc_fan[edata->sensor].cmin) 498 edata->state = ENVSYS_SCRITICAL; 499 else 500 edata->state = ENVSYS_SVALID; 501 } 502 503 void 504 envmon_epic_refresh_fault(struct envmon_softc *sc, envsys_data_t *edata) 505 { 506 uint8_t val; 507 int32_t which, total; 508 int i, j; 509 510 envmon_write(sc, ENVMON_ADDR, ENVMON_EPC_FAN_FLT); 511 val = envmon_read(sc, ENVMON_DATA); 512 513 total = 0; 514 if (val == ENVMON_EPC_FAN_FLT_NONE) { 515 edata->state = ENVSYS_SVALID; 516 } else { 517 edata->state = ENVSYS_SCRITICAL; 518 for (i = 0; i < ENVMON_EPC_NUM_FAN_FLTS; i++) { 519 if (!(val & __BIT(i))) { 520 which = 1; 521 for (j = 0; j < i; j++) 522 which *= 10; 523 total += which; 524 } 525 } 526 } 527 edata->value_cur = total; 528 } 529 530 void 531 envmon_refresh_temp(struct envmon_softc *sc, envsys_data_t *edata) 532 { 533 uint8_t val; 534 535 /* We currently only have 1 temperature sensor */ 536 envmon_write(sc, ENVMON_ADDR, sc->sc_temp[0].reg); 537 val = envmon_read(sc, ENVMON_DATA); 538 edata->value_cur = ENVMON_TEMP_BASE + val * 1000000; 539 if (edata->value_cur > sc->sc_temp[0].cmax) 540 edata->state = ENVSYS_SCRITICAL; 541 else 542 edata->state = ENVSYS_SVALID; 543 } 544 545 void 546 envmon_epic_refresh_ind(struct envmon_softc *sc, envsys_data_t *edata) 547 { 548 int ind = edata->sensor - 549 sc->sc_nfans - ENVMON_EPC_MAX_TEMPS - ENVMON_EPC_MAX_FAULTS; 550 uint8_t val; 551 552 envmon_write(sc, ENVMON_ADDR, sc->sc_ind[ind].reg); 553 val = envmon_read(sc, ENVMON_DATA); 554 555 if (val == sc->sc_ind[ind].set) 556 edata->value_cur = TRUE; 557 else 558 edata->value_cur = FALSE; 559 edata->state = ENVSYS_SVALID; 560 } 561 562 void 563 envmon_pic_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata, 564 sysmon_envsys_lim_t *limits, uint32_t *props) 565 { 566 struct envmon_softc *sc = sme->sme_cookie; 567 568 envmon_get_temp_limits(sc, edata, limits, props); 569 } 570 571 void 572 envmon_pic_set_limits(struct sysmon_envsys *sme, envsys_data_t *edata, 573 sysmon_envsys_lim_t *limits, uint32_t *props) 574 { 575 struct envmon_softc *sc = sme->sme_cookie; 576 577 envmon_set_temp_limits(sc, edata, limits, props); 578 } 579 580 void 581 envmon_epic_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata, 582 sysmon_envsys_lim_t *limits, uint32_t *props) 583 { 584 struct envmon_softc *sc = sme->sme_cookie; 585 586 if (edata->sensor < sc->sc_nfans) 587 envmon_epic_get_fan_limits(sc, edata, limits, props); 588 else if (edata->sensor < sc->sc_nfans + ENVMON_EPC_MAX_TEMPS) 589 envmon_get_temp_limits(sc, edata, limits, props); 590 } 591 592 void 593 envmon_epic_set_limits(struct sysmon_envsys *sme, envsys_data_t *edata, 594 sysmon_envsys_lim_t *limits, uint32_t *props) 595 { 596 struct envmon_softc *sc = sme->sme_cookie; 597 598 if (edata->sensor < sc->sc_nfans) 599 envmon_epic_set_fan_limits(sc, edata, limits, props); 600 else if (edata->sensor < sc->sc_nfans + ENVMON_EPC_MAX_TEMPS) 601 envmon_set_temp_limits(sc, edata, limits, props); 602 } 603 604 static void 605 envmon_epic_get_fan_limits(struct envmon_softc *sc, 606 envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props) 607 { 608 609 *props = PROP_CRITMIN; 610 limits->sel_critmin = sc->sc_fan[edata->sensor].cmin; 611 } 612 613 static void 614 envmon_get_temp_limits(struct envmon_softc *sc, 615 envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props) 616 { 617 618 *props = PROP_WARNMIN | PROP_WARNMAX | PROP_CRITMAX; 619 limits->sel_warnmin = sc->sc_temp[0].wmin; 620 limits->sel_warnmax = sc->sc_temp[0].wmax; 621 limits->sel_critmax = sc->sc_temp[0].cmax; 622 } 623 624 static void 625 envmon_epic_set_fan_limits(struct envmon_softc *sc, 626 envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props) 627 { 628 629 if (limits == NULL || *props & PROP_CRITMIN) { 630 if (limits == NULL) /* Restore defaults */ 631 switch (sc->sc_machine_type) { 632 case ENVMON_MACHINE_V215: 633 sc->sc_fan[edata->sensor].cmin = 634 ENVMON_EPC_CRIT_SPEED_V215; 635 break; 636 case ENVMON_MACHINE_V245: 637 sc->sc_fan[edata->sensor].cmin = 638 ENVMON_EPC_CRIT_SPEED_V245; 639 break; 640 } 641 else 642 sc->sc_fan[edata->sensor].cmin = limits->sel_critmin; 643 } 644 } 645 646 static void 647 envmon_set_temp_limits(struct envmon_softc *sc, 648 envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props) 649 { 650 651 if (limits == NULL || *props & PROP_CRITMAX) { 652 if (limits == NULL) /* Restore defaults */ 653 switch (sc->sc_machine_type) { 654 case ENVMON_MACHINE_U25: 655 case ENVMON_MACHINE_U45: 656 sc->sc_temp[0].cmax = 657 ENVMON_PIC_CRIT_TEMP; 658 break; 659 case ENVMON_MACHINE_V215: 660 case ENVMON_MACHINE_V245: 661 sc->sc_temp[0].cmax = 662 ENVMON_EPC_CRIT_TEMP; 663 break; 664 } 665 else 666 sc->sc_temp[edata->sensor].cmax = limits->sel_critmax; 667 } 668 669 if (limits == NULL || *props & PROP_WARNMAX) { 670 if (limits == NULL) /* Restore defaults */ 671 switch (sc->sc_machine_type) { 672 case ENVMON_MACHINE_U25: 673 case ENVMON_MACHINE_U45: 674 sc->sc_temp[0].wmax = 675 ENVMON_PIC_WMAX_TEMP; 676 break; 677 case ENVMON_MACHINE_V215: 678 case ENVMON_MACHINE_V245: 679 sc->sc_temp[0].wmax = 680 ENVMON_EPC_WMAX_TEMP; 681 break; 682 } 683 else 684 sc->sc_temp[edata->sensor].wmax = limits->sel_warnmax; 685 } 686 687 if (limits == NULL || *props & PROP_WARNMIN) { 688 if (limits == NULL) /* Restore defaults */ 689 switch (sc->sc_machine_type) { 690 case ENVMON_MACHINE_U25: 691 case ENVMON_MACHINE_U45: 692 sc->sc_temp[0].wmin = 693 ENVMON_PIC_WMIN_TEMP; 694 break; 695 case ENVMON_MACHINE_V215: 696 case ENVMON_MACHINE_V245: 697 sc->sc_temp[0].wmin = 698 ENVMON_EPC_WMIN_TEMP; 699 break; 700 } 701 else 702 sc->sc_temp[edata->sensor].wmin = limits->sel_warnmin; 703 } 704 705 } 706 707 int 708 envmon_epic_get_led(void *cookie) 709 { 710 struct envmon_sc_led *l = cookie; 711 struct envmon_softc *sc = l->cookie; 712 uint8_t val; 713 714 envmon_write(sc, ENVMON_ADDR, l->reg); 715 val = envmon_read(sc, ENVMON_DATA); 716 return ((val & l->v_on) == l->v_on); 717 } 718 719 void 720 envmon_epic_set_led(void *cookie, int val) 721 { 722 struct envmon_sc_led *l = cookie; 723 struct envmon_softc *sc = l->cookie; 724 uint8_t oldval, newval; 725 726 envmon_write(sc, ENVMON_ADDR, l->reg); 727 oldval = envmon_read(sc, ENVMON_DATA); 728 newval = oldval & ~(l->v_on); 729 newval |= val ? l->v_on : 0x0; 730 if (newval != oldval) { 731 envmon_write(sc, ENVMON_EPC_LED_MASK, l->v_on); 732 envmon_write(sc, ENVMON_ADDR, l->reg); 733 delay(10000); 734 envmon_write(sc, ENVMON_DATA, newval); 735 } 736 } 737 738 #ifdef ENVMON_DEBUG 739 static void 740 envmon_timeout(void *v) 741 { 742 struct envmon_softc *sc = v; 743 uint8_t reg, val; 744 745 for (reg = 0; reg < ENVMON_MAX_REG; reg++) { 746 envmon_write(sc, ENVMON_ADDR, reg); 747 val = envmon_read(sc, ENVMON_DATA); 748 if (val != sc->sc_reg[reg]) { 749 printf("%s: reg 0x%02x: 0x%02x > 0x%02x\n", 750 device_xname(sc->sc_dev), reg, 751 sc->sc_reg[reg], val); 752 sc->sc_reg[reg] = val; 753 } 754 } 755 callout_reset(&sc->sc_timer, hz * ENVMON_TIMER, envmon_timeout, sc); 756 } 757 #endif 758