1*50dbebdaSmiod /* $OpenBSD: lom.c,v 1.29 2022/07/04 19:06:10 miod Exp $ */
22613757eSkettenis /*
35f2dcfb1Skettenis * Copyright (c) 2009 Mark Kettenis
42613757eSkettenis *
52613757eSkettenis * Permission to use, copy, modify, and distribute this software for any
62613757eSkettenis * purpose with or without fee is hereby granted, provided that the above
72613757eSkettenis * copyright notice and this permission notice appear in all copies.
82613757eSkettenis *
92613757eSkettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
102613757eSkettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
112613757eSkettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
122613757eSkettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
132613757eSkettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
142613757eSkettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
152613757eSkettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
162613757eSkettenis */
172613757eSkettenis
182613757eSkettenis #include <sys/param.h>
192613757eSkettenis #include <sys/device.h>
206801a748Skettenis #include <sys/kernel.h>
21fc69c4e1Skettenis #include <sys/proc.h>
222613757eSkettenis #include <sys/sensors.h>
232613757eSkettenis #include <sys/systm.h>
24877407b4Skettenis #include <sys/timeout.h>
252613757eSkettenis
262613757eSkettenis #include <machine/autoconf.h>
272613757eSkettenis #include <machine/openfirm.h>
282613757eSkettenis
292613757eSkettenis #include <sparc64/dev/ebusreg.h>
302613757eSkettenis #include <sparc64/dev/ebusvar.h>
312613757eSkettenis
322613757eSkettenis /*
3313d051d6Skettenis * LOMlite is a so far unidentified microcontroller.
3413d051d6Skettenis */
3513d051d6Skettenis #define LOM1_STATUS 0x00 /* R */
3613d051d6Skettenis #define LOM1_STATUS_BUSY 0x80
3713d051d6Skettenis #define LOM1_CMD 0x00 /* W */
3813d051d6Skettenis #define LOM1_DATA 0x01 /* R/W */
3913d051d6Skettenis
4013d051d6Skettenis /*
4113d051d6Skettenis * LOMlite2 is implemented as a H8/3437 microcontroller which has its
422613757eSkettenis * on-chip host interface hooked up to EBus.
432613757eSkettenis */
4413d051d6Skettenis #define LOM2_DATA 0x00 /* R/W */
4513d051d6Skettenis #define LOM2_CMD 0x01 /* W */
4613d051d6Skettenis #define LOM2_STATUS 0x01 /* R */
4713d051d6Skettenis #define LOM2_STATUS_OBF 0x01 /* Output Buffer Full */
4813d051d6Skettenis #define LOM2_STATUS_IBF 0x02 /* Input Buffer Full */
492613757eSkettenis
505f2dcfb1Skettenis #define LOM_IDX_CMD 0x00
515f2dcfb1Skettenis #define LOM_IDX_CMD_GENERIC 0x00
525f2dcfb1Skettenis #define LOM_IDX_CMD_TEMP 0x04
5302222f5cSkettenis #define LOM_IDX_CMD_FAN 0x05
545f2dcfb1Skettenis
552613757eSkettenis #define LOM_IDX_FW_REV 0x01 /* Firmware revision */
562613757eSkettenis
5702222f5cSkettenis #define LOM_IDX_FAN1 0x04 /* Fan speed */
5802222f5cSkettenis #define LOM_IDX_FAN2 0x05
5902222f5cSkettenis #define LOM_IDX_FAN3 0x06
6002222f5cSkettenis #define LOM_IDX_FAN4 0x07
6178eeb547Skettenis #define LOM_IDX_PSU1 0x08 /* PSU status */
6278eeb547Skettenis #define LOM_IDX_PSU2 0x09
6378eeb547Skettenis #define LOM_IDX_PSU3 0x0a
6478eeb547Skettenis #define LOM_PSU_INPUTA 0x01
6578eeb547Skettenis #define LOM_PSU_INPUTB 0x02
6678eeb547Skettenis #define LOM_PSU_OUTPUT 0x04
6778eeb547Skettenis #define LOM_PSU_PRESENT 0x08
6878eeb547Skettenis #define LOM_PSU_STANDBY 0x10
6902222f5cSkettenis
702613757eSkettenis #define LOM_IDX_TEMP1 0x18 /* Temperature */
7102222f5cSkettenis #define LOM_IDX_TEMP2 0x19
7202222f5cSkettenis #define LOM_IDX_TEMP3 0x1a
7302222f5cSkettenis #define LOM_IDX_TEMP4 0x1b
7402222f5cSkettenis #define LOM_IDX_TEMP5 0x1c
7502222f5cSkettenis #define LOM_IDX_TEMP6 0x1d
7602222f5cSkettenis #define LOM_IDX_TEMP7 0x1e
7702222f5cSkettenis #define LOM_IDX_TEMP8 0x1f
782613757eSkettenis
795f2dcfb1Skettenis #define LOM_IDX_LED1 0x25
805f2dcfb1Skettenis
815f2dcfb1Skettenis #define LOM_IDX_ALARM 0x30
82877407b4Skettenis #define LOM_IDX_WDOG_CTL 0x31
83877407b4Skettenis #define LOM_WDOG_ENABLE 0x01
84877407b4Skettenis #define LOM_WDOG_RESET 0x02
85877407b4Skettenis #define LOM_WDOG_AL3_WDOG 0x04
86877407b4Skettenis #define LOM_WDOG_AL3_FANPSU 0x08
87877407b4Skettenis #define LOM_IDX_WDOG_TIME 0x32
8813d051d6Skettenis #define LOM_WDOG_TIME_MAX 126
895f2dcfb1Skettenis
9013d051d6Skettenis #define LOM1_IDX_HOSTNAME1 0x33
9113d051d6Skettenis #define LOM1_IDX_HOSTNAME2 0x34
9213d051d6Skettenis #define LOM1_IDX_HOSTNAME3 0x35
9313d051d6Skettenis #define LOM1_IDX_HOSTNAME4 0x36
9413d051d6Skettenis #define LOM1_IDX_HOSTNAME5 0x37
9513d051d6Skettenis #define LOM1_IDX_HOSTNAME6 0x38
9613d051d6Skettenis #define LOM1_IDX_HOSTNAME7 0x39
9713d051d6Skettenis #define LOM1_IDX_HOSTNAME8 0x3a
9813d051d6Skettenis #define LOM1_IDX_HOSTNAME9 0x3b
9913d051d6Skettenis #define LOM1_IDX_HOSTNAME10 0x3c
10013d051d6Skettenis #define LOM1_IDX_HOSTNAME11 0x3d
10113d051d6Skettenis #define LOM1_IDX_HOSTNAME12 0x3e
10213d051d6Skettenis
10313d051d6Skettenis #define LOM2_IDX_HOSTNAMELEN 0x38
10413d051d6Skettenis #define LOM2_IDX_HOSTNAME 0x39
1056801a748Skettenis
10602222f5cSkettenis #define LOM_IDX_CONFIG 0x5d
10702222f5cSkettenis #define LOM_IDX_FAN1_CAL 0x5e
10802222f5cSkettenis #define LOM_IDX_FAN2_CAL 0x5f
10902222f5cSkettenis #define LOM_IDX_FAN3_CAL 0x60
11002222f5cSkettenis #define LOM_IDX_FAN4_CAL 0x61
11102222f5cSkettenis #define LOM_IDX_FAN1_LOW 0x62
11202222f5cSkettenis #define LOM_IDX_FAN2_LOW 0x63
11302222f5cSkettenis #define LOM_IDX_FAN3_LOW 0x64
11402222f5cSkettenis #define LOM_IDX_FAN4_LOW 0x65
11502222f5cSkettenis
11602222f5cSkettenis #define LOM_IDX_CONFIG2 0x66
11702222f5cSkettenis #define LOM_IDX_CONFIG3 0x67
11802222f5cSkettenis
1192613757eSkettenis #define LOM_IDX_PROBE55 0x7e /* Always returns 0x55 */
1202613757eSkettenis #define LOM_IDX_PROBEAA 0x7f /* Always returns 0xaa */
1212613757eSkettenis
1225e80de5eSkettenis #define LOM_IDX_WRITE 0x80
1235e80de5eSkettenis
1245f2dcfb1Skettenis #define LOM_IDX4_TEMP_NAME_START 0x40
1255f2dcfb1Skettenis #define LOM_IDX4_TEMP_NAME_END 0xff
1265f2dcfb1Skettenis
12702222f5cSkettenis #define LOM_IDX5_FAN_NAME_START 0x40
12802222f5cSkettenis #define LOM_IDX5_FAN_NAME_END 0xff
12902222f5cSkettenis
13002222f5cSkettenis #define LOM_MAX_FAN 4
13102222f5cSkettenis #define LOM_MAX_PSU 3
13202222f5cSkettenis #define LOM_MAX_TEMP 8
13302222f5cSkettenis
1345e80de5eSkettenis struct lom_cmd {
1355e80de5eSkettenis uint8_t lc_cmd;
1365e80de5eSkettenis uint8_t lc_data;
1375e80de5eSkettenis
1385e80de5eSkettenis TAILQ_ENTRY(lom_cmd) lc_next;
1395e80de5eSkettenis };
1405e80de5eSkettenis
1412613757eSkettenis struct lom_softc {
1422613757eSkettenis struct device sc_dev;
1432613757eSkettenis bus_space_tag_t sc_iot;
1442613757eSkettenis bus_space_handle_t sc_ioh;
1452613757eSkettenis
14613d051d6Skettenis int sc_type;
14713d051d6Skettenis #define LOM_LOMLITE 0
14813d051d6Skettenis #define LOM_LOMLITE2 2
1495f2dcfb1Skettenis int sc_space;
1505f2dcfb1Skettenis
15102222f5cSkettenis struct ksensor sc_fan[LOM_MAX_FAN];
15278eeb547Skettenis struct ksensor sc_psu[LOM_MAX_PSU];
15302222f5cSkettenis struct ksensor sc_temp[LOM_MAX_TEMP];
1542613757eSkettenis struct ksensordev sc_sensordev;
15502222f5cSkettenis
15602222f5cSkettenis int sc_num_fan;
15702222f5cSkettenis int sc_num_psu;
15802222f5cSkettenis int sc_num_temp;
15902222f5cSkettenis
16002222f5cSkettenis uint8_t sc_fan_cal[LOM_MAX_FAN];
16102222f5cSkettenis uint8_t sc_fan_low[LOM_MAX_FAN];
1626801a748Skettenis
1636801a748Skettenis char sc_hostname[MAXHOSTNAMELEN];
164877407b4Skettenis
165877407b4Skettenis struct timeout sc_wdog_to;
166877407b4Skettenis int sc_wdog_period;
1675223c73eSkettenis uint8_t sc_wdog_ctl;
1685e80de5eSkettenis struct lom_cmd sc_wdog_pat;
169fc69c4e1Skettenis
1705e80de5eSkettenis TAILQ_HEAD(, lom_cmd) sc_queue;
1715e80de5eSkettenis struct mutex sc_queue_mtx;
172fc69c4e1Skettenis struct timeout sc_state_to;
173fc69c4e1Skettenis int sc_state;
174fc69c4e1Skettenis #define LOM_STATE_IDLE 0
1755e80de5eSkettenis #define LOM_STATE_CMD 1
1765e80de5eSkettenis #define LOM_STATE_DATA 2
1775e80de5eSkettenis int sc_retry;
1782613757eSkettenis };
1792613757eSkettenis
1802613757eSkettenis int lom_match(struct device *, void *, void *);
1812613757eSkettenis void lom_attach(struct device *, struct device *, void *);
182c06fda6dSderaadt int lom_activate(struct device *, int);
1832613757eSkettenis
184eb7eaf8dSmpi const struct cfattach lom_ca = {
185c06fda6dSderaadt sizeof(struct lom_softc), lom_match, lom_attach,
186c06fda6dSderaadt NULL, lom_activate
1872613757eSkettenis };
1882613757eSkettenis
1892613757eSkettenis struct cfdriver lom_cd = {
1902613757eSkettenis NULL, "lom", DV_DULL
1912613757eSkettenis };
1922613757eSkettenis
1932613757eSkettenis int lom_read(struct lom_softc *, uint8_t, uint8_t *);
1942613757eSkettenis int lom_write(struct lom_softc *, uint8_t, uint8_t);
1955e80de5eSkettenis void lom_queue_cmd(struct lom_softc *, struct lom_cmd *);
196a4f1f624Skettenis void lom_dequeue_cmd(struct lom_softc *, struct lom_cmd *);
19713d051d6Skettenis int lom1_read(struct lom_softc *, uint8_t, uint8_t *);
19813d051d6Skettenis int lom1_write(struct lom_softc *, uint8_t, uint8_t);
1995e80de5eSkettenis int lom1_read_polled(struct lom_softc *, uint8_t, uint8_t *);
2005e80de5eSkettenis int lom1_write_polled(struct lom_softc *, uint8_t, uint8_t);
2015e80de5eSkettenis void lom1_queue_cmd(struct lom_softc *, struct lom_cmd *);
2025e80de5eSkettenis void lom1_process_queue(void *);
2035e80de5eSkettenis void lom1_process_queue_locked(struct lom_softc *);
20413d051d6Skettenis int lom2_read(struct lom_softc *, uint8_t, uint8_t *);
20513d051d6Skettenis int lom2_write(struct lom_softc *, uint8_t, uint8_t);
206d95b06c1Skettenis int lom2_read_polled(struct lom_softc *, uint8_t, uint8_t *);
207d95b06c1Skettenis int lom2_write_polled(struct lom_softc *, uint8_t, uint8_t);
2085e80de5eSkettenis void lom2_queue_cmd(struct lom_softc *, struct lom_cmd *);
209d95b06c1Skettenis int lom2_intr(void *);
2102613757eSkettenis
2115f2dcfb1Skettenis int lom_init_desc(struct lom_softc *sc);
2122613757eSkettenis void lom_refresh(void *);
21313d051d6Skettenis void lom1_write_hostname(struct lom_softc *);
21413d051d6Skettenis void lom2_write_hostname(struct lom_softc *);
2152613757eSkettenis
216877407b4Skettenis void lom_wdog_pat(void *);
217877407b4Skettenis int lom_wdog_cb(void *, int);
218877407b4Skettenis
219edd433c7Skettenis void lom_shutdown(void *);
220edd433c7Skettenis
2212613757eSkettenis int
lom_match(struct device * parent,void * match,void * aux)2222613757eSkettenis lom_match(struct device *parent, void *match, void *aux)
2232613757eSkettenis {
2242613757eSkettenis struct ebus_attach_args *ea = aux;
2252613757eSkettenis
226fc69c4e1Skettenis if (strcmp(ea->ea_name, "SUNW,lom") == 0 ||
227fc69c4e1Skettenis strcmp(ea->ea_name, "SUNW,lomh") == 0)
2282613757eSkettenis return (1);
2292613757eSkettenis
2302613757eSkettenis return (0);
2312613757eSkettenis }
2322613757eSkettenis
2332613757eSkettenis void
lom_attach(struct device * parent,struct device * self,void * aux)2342613757eSkettenis lom_attach(struct device *parent, struct device *self, void *aux)
2352613757eSkettenis {
2362613757eSkettenis struct lom_softc *sc = (void *)self;
2372613757eSkettenis struct ebus_attach_args *ea = aux;
23802222f5cSkettenis uint8_t reg, fw_rev, config, config2, config3;
23913d051d6Skettenis uint8_t cal, low;
24002222f5cSkettenis int i;
2412613757eSkettenis
242d95b06c1Skettenis if (strcmp(ea->ea_name, "SUNW,lomh") == 0) {
243d95b06c1Skettenis if (ea->ea_nintrs < 1) {
244d95b06c1Skettenis printf(": no interrupt\n");
245d95b06c1Skettenis return;
246d95b06c1Skettenis }
24713d051d6Skettenis sc->sc_type = LOM_LOMLITE2;
248d95b06c1Skettenis }
24913d051d6Skettenis
250d151cb6cSkettenis if (ebus_bus_map(ea->ea_iotag, 0,
2512613757eSkettenis EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
252d151cb6cSkettenis ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
253d151cb6cSkettenis sc->sc_iot = ea->ea_iotag;
254d151cb6cSkettenis } else if (ebus_bus_map(ea->ea_memtag, 0,
255d151cb6cSkettenis EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
256d151cb6cSkettenis ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
257d151cb6cSkettenis sc->sc_iot = ea->ea_memtag;
258d151cb6cSkettenis } else {
2592613757eSkettenis printf(": can't map register space\n");
2602613757eSkettenis return;
2612613757eSkettenis }
2622613757eSkettenis
26313d051d6Skettenis if (sc->sc_type < LOM_LOMLITE2) {
26413d051d6Skettenis /* XXX Magic */
26513d051d6Skettenis bus_space_read_1(sc->sc_iot, sc->sc_ioh, 0);
26613d051d6Skettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, 3, 0xca);
26713d051d6Skettenis }
26813d051d6Skettenis
2692613757eSkettenis if (lom_read(sc, LOM_IDX_PROBE55, ®) || reg != 0x55 ||
2702613757eSkettenis lom_read(sc, LOM_IDX_PROBEAA, ®) || reg != 0xaa ||
27102222f5cSkettenis lom_read(sc, LOM_IDX_FW_REV, &fw_rev) ||
27213d051d6Skettenis lom_read(sc, LOM_IDX_CONFIG, &config))
27302222f5cSkettenis {
2742613757eSkettenis printf(": not responding\n");
2752613757eSkettenis return;
2762613757eSkettenis }
2772613757eSkettenis
278d95b06c1Skettenis TAILQ_INIT(&sc->sc_queue);
279d95b06c1Skettenis mtx_init(&sc->sc_queue_mtx, IPL_BIO);
280d95b06c1Skettenis
28113d051d6Skettenis config2 = config3 = 0;
282d95b06c1Skettenis if (sc->sc_type < LOM_LOMLITE2) {
283d95b06c1Skettenis /*
284d95b06c1Skettenis * LOMlite doesn't do interrupts so we limp along on
285d95b06c1Skettenis * timeouts.
286d95b06c1Skettenis */
287d95b06c1Skettenis timeout_set(&sc->sc_state_to, lom1_process_queue, sc);
288d95b06c1Skettenis } else {
28913d051d6Skettenis lom_read(sc, LOM_IDX_CONFIG2, &config2);
29013d051d6Skettenis lom_read(sc, LOM_IDX_CONFIG3, &config3);
291d95b06c1Skettenis
292d95b06c1Skettenis bus_intr_establish(sc->sc_iot, ea->ea_intrs[0],
293d95b06c1Skettenis IPL_BIO, 0, lom2_intr, sc, self->dv_xname);
29413d051d6Skettenis }
29513d051d6Skettenis
29602222f5cSkettenis sc->sc_num_fan = min((config >> 5) & 0x7, LOM_MAX_FAN);
29702222f5cSkettenis sc->sc_num_psu = min((config >> 3) & 0x3, LOM_MAX_PSU);
29802222f5cSkettenis sc->sc_num_temp = min((config2 >> 4) & 0xf, LOM_MAX_TEMP);
29902222f5cSkettenis
30002222f5cSkettenis for (i = 0; i < sc->sc_num_fan; i++) {
30102222f5cSkettenis if (lom_read(sc, LOM_IDX_FAN1_CAL + i, &cal) ||
30202222f5cSkettenis lom_read(sc, LOM_IDX_FAN1_LOW + i, &low)) {
30302222f5cSkettenis printf(": can't read fan information\n");
30402222f5cSkettenis return;
30502222f5cSkettenis }
30602222f5cSkettenis sc->sc_fan_cal[i] = cal;
30702222f5cSkettenis sc->sc_fan_low[i] = low;
30802222f5cSkettenis }
30902222f5cSkettenis
3102613757eSkettenis /* Initialize sensor data. */
3112613757eSkettenis strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
3122613757eSkettenis sizeof(sc->sc_sensordev.xname));
31302222f5cSkettenis for (i = 0; i < sc->sc_num_fan; i++) {
31402222f5cSkettenis sc->sc_fan[i].type = SENSOR_FANRPM;
31502222f5cSkettenis sensor_attach(&sc->sc_sensordev, &sc->sc_fan[i]);
31613d051d6Skettenis snprintf(sc->sc_fan[i].desc, sizeof(sc->sc_fan[i].desc),
31713d051d6Skettenis "fan%d", i + 1);
31802222f5cSkettenis }
31978eeb547Skettenis for (i = 0; i < sc->sc_num_psu; i++) {
32078eeb547Skettenis sc->sc_psu[i].type = SENSOR_INDICATOR;
32178eeb547Skettenis sensor_attach(&sc->sc_sensordev, &sc->sc_psu[i]);
32278eeb547Skettenis snprintf(sc->sc_psu[i].desc, sizeof(sc->sc_psu[i].desc),
32378eeb547Skettenis "PSU%d", i + 1);
32478eeb547Skettenis }
32502222f5cSkettenis for (i = 0; i < sc->sc_num_temp; i++) {
32602222f5cSkettenis sc->sc_temp[i].type = SENSOR_TEMP;
32702222f5cSkettenis sensor_attach(&sc->sc_sensordev, &sc->sc_temp[i]);
32802222f5cSkettenis }
3295f2dcfb1Skettenis if (lom_init_desc(sc)) {
3305f2dcfb1Skettenis printf(": can't read sensor names\n");
3315f2dcfb1Skettenis return;
3325f2dcfb1Skettenis }
3332613757eSkettenis
3342613757eSkettenis if (sensor_task_register(sc, lom_refresh, 5) == NULL) {
3352613757eSkettenis printf(": unable to register update task\n");
3362613757eSkettenis return;
3372613757eSkettenis }
3382613757eSkettenis
3392613757eSkettenis sensordev_install(&sc->sc_sensordev);
3402613757eSkettenis
341877407b4Skettenis /*
342877407b4Skettenis * We configure the watchdog to turn on the fault LED when the
343877407b4Skettenis * watchdog timer expires. We run our own timeout to pat it
344877407b4Skettenis * such that this won't happen unless the kernel hangs. When
345877407b4Skettenis * the watchdog is explicitly configured using sysctl(8), we
346877407b4Skettenis * reconfigure it to reset the machine and let the standard
347877407b4Skettenis * watchdog(4) machinery take over.
348877407b4Skettenis */
349877407b4Skettenis lom_write(sc, LOM_IDX_WDOG_TIME, LOM_WDOG_TIME_MAX);
3505223c73eSkettenis lom_read(sc, LOM_IDX_WDOG_CTL, &sc->sc_wdog_ctl);
3515223c73eSkettenis sc->sc_wdog_ctl &= ~LOM_WDOG_RESET;
3525223c73eSkettenis sc->sc_wdog_ctl |= LOM_WDOG_ENABLE;
3535223c73eSkettenis lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl);
354877407b4Skettenis timeout_set(&sc->sc_wdog_to, lom_wdog_pat, sc);
355877407b4Skettenis timeout_add_sec(&sc->sc_wdog_to, LOM_WDOG_TIME_MAX / 2);
356877407b4Skettenis
3572bc62decSderaadt wdog_register(lom_wdog_cb, sc);
358877407b4Skettenis
359e6d8f4d1Skettenis printf(": %s rev %d.%d\n",
360e6d8f4d1Skettenis sc->sc_type < LOM_LOMLITE2 ? "LOMlite" : "LOMlite2",
361e6d8f4d1Skettenis fw_rev >> 4, fw_rev & 0x0f);
362c06fda6dSderaadt }
363edd433c7Skettenis
364c06fda6dSderaadt int
lom_activate(struct device * self,int act)365c06fda6dSderaadt lom_activate(struct device *self, int act)
366c06fda6dSderaadt {
367c06fda6dSderaadt int ret = 0;
368c06fda6dSderaadt
369c06fda6dSderaadt switch (act) {
370c06fda6dSderaadt case DVACT_POWERDOWN:
3713b06f262Smikeb wdog_shutdown(self);
372c06fda6dSderaadt lom_shutdown(self);
373c06fda6dSderaadt break;
374c06fda6dSderaadt }
375c06fda6dSderaadt
376c06fda6dSderaadt return (ret);
3772613757eSkettenis }
3782613757eSkettenis
3792613757eSkettenis int
lom_read(struct lom_softc * sc,uint8_t reg,uint8_t * val)3802613757eSkettenis lom_read(struct lom_softc *sc, uint8_t reg, uint8_t *val)
3812613757eSkettenis {
38213d051d6Skettenis if (sc->sc_type < LOM_LOMLITE2)
38313d051d6Skettenis return lom1_read(sc, reg, val);
38413d051d6Skettenis else
38513d051d6Skettenis return lom2_read(sc, reg, val);
3862613757eSkettenis }
3872613757eSkettenis
3885f2dcfb1Skettenis int
lom_write(struct lom_softc * sc,uint8_t reg,uint8_t val)3895f2dcfb1Skettenis lom_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
3905f2dcfb1Skettenis {
39113d051d6Skettenis if (sc->sc_type < LOM_LOMLITE2)
39213d051d6Skettenis return lom1_write(sc, reg, val);
39313d051d6Skettenis else
39413d051d6Skettenis return lom2_write(sc, reg, val);
39513d051d6Skettenis }
39613d051d6Skettenis
3975e80de5eSkettenis void
lom_queue_cmd(struct lom_softc * sc,struct lom_cmd * lc)3985e80de5eSkettenis lom_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
3995e80de5eSkettenis {
4005e80de5eSkettenis if (sc->sc_type < LOM_LOMLITE2)
4015e80de5eSkettenis return lom1_queue_cmd(sc, lc);
4025e80de5eSkettenis else
4035e80de5eSkettenis return lom2_queue_cmd(sc, lc);
4045e80de5eSkettenis }
4055e80de5eSkettenis
406a4f1f624Skettenis void
lom_dequeue_cmd(struct lom_softc * sc,struct lom_cmd * lc)407a4f1f624Skettenis lom_dequeue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
408a4f1f624Skettenis {
409d95b06c1Skettenis struct lom_cmd *lcp;
410d95b06c1Skettenis
411d95b06c1Skettenis mtx_enter(&sc->sc_queue_mtx);
412d95b06c1Skettenis TAILQ_FOREACH(lcp, &sc->sc_queue, lc_next) {
413d95b06c1Skettenis if (lcp == lc) {
414d95b06c1Skettenis TAILQ_REMOVE(&sc->sc_queue, lc, lc_next);
415d95b06c1Skettenis break;
416d95b06c1Skettenis }
417d95b06c1Skettenis }
418d95b06c1Skettenis mtx_leave(&sc->sc_queue_mtx);
419a4f1f624Skettenis }
420a4f1f624Skettenis
42113d051d6Skettenis int
lom1_read(struct lom_softc * sc,uint8_t reg,uint8_t * val)42213d051d6Skettenis lom1_read(struct lom_softc *sc, uint8_t reg, uint8_t *val)
42313d051d6Skettenis {
4245e80de5eSkettenis struct lom_cmd lc;
425fc69c4e1Skettenis int error;
426fc69c4e1Skettenis
427fc69c4e1Skettenis if (cold)
428fc69c4e1Skettenis return lom1_read_polled(sc, reg, val);
429fc69c4e1Skettenis
4305e80de5eSkettenis lc.lc_cmd = reg;
4315e80de5eSkettenis lc.lc_data = 0xff;
4325e80de5eSkettenis lom1_queue_cmd(sc, &lc);
433fc69c4e1Skettenis
434d6fc7890Scheloha error = tsleep_nsec(&lc, PZERO, "lomrd", SEC_TO_NSEC(1));
4355e80de5eSkettenis if (error)
436d95b06c1Skettenis lom_dequeue_cmd(sc, &lc);
437fc69c4e1Skettenis
4385e80de5eSkettenis *val = lc.lc_data;
4395e80de5eSkettenis
4405e80de5eSkettenis return (error);
4415e80de5eSkettenis }
4425e80de5eSkettenis
4435e80de5eSkettenis int
lom1_write(struct lom_softc * sc,uint8_t reg,uint8_t val)4445e80de5eSkettenis lom1_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
4455e80de5eSkettenis {
4465e80de5eSkettenis struct lom_cmd lc;
4475e80de5eSkettenis int error;
4485e80de5eSkettenis
4495e80de5eSkettenis if (cold)
4505e80de5eSkettenis return lom1_write_polled(sc, reg, val);
4515e80de5eSkettenis
4525e80de5eSkettenis lc.lc_cmd = reg | LOM_IDX_WRITE;
4535e80de5eSkettenis lc.lc_data = val;
4545e80de5eSkettenis lom1_queue_cmd(sc, &lc);
4555e80de5eSkettenis
456d6fc7890Scheloha error = tsleep_nsec(&lc, PZERO, "lomwr", SEC_TO_NSEC(2));
4575e80de5eSkettenis if (error)
458d95b06c1Skettenis lom_dequeue_cmd(sc, &lc);
459fc69c4e1Skettenis
460fc69c4e1Skettenis return (error);
461fc69c4e1Skettenis }
462fc69c4e1Skettenis
463fc69c4e1Skettenis int
lom1_read_polled(struct lom_softc * sc,uint8_t reg,uint8_t * val)464fc69c4e1Skettenis lom1_read_polled(struct lom_softc *sc, uint8_t reg, uint8_t *val)
465fc69c4e1Skettenis {
46613d051d6Skettenis uint8_t str;
46713d051d6Skettenis int i;
46813d051d6Skettenis
46913d051d6Skettenis /* Wait for input buffer to become available. */
4703c40421dSkettenis for (i = 30; i > 0; i--) {
47113d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
4723c40421dSkettenis delay(1000);
47313d051d6Skettenis if ((str & LOM1_STATUS_BUSY) == 0)
47413d051d6Skettenis break;
47513d051d6Skettenis }
47613d051d6Skettenis if (i == 0)
47713d051d6Skettenis return (ETIMEDOUT);
47813d051d6Skettenis
47913d051d6Skettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg);
48013d051d6Skettenis
48113d051d6Skettenis /* Wait until the microcontroller fills output buffer. */
4823c40421dSkettenis for (i = 30; i > 0; i--) {
48313d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
4843c40421dSkettenis delay(1000);
48513d051d6Skettenis if ((str & LOM1_STATUS_BUSY) == 0)
48613d051d6Skettenis break;
48713d051d6Skettenis }
48813d051d6Skettenis if (i == 0)
48913d051d6Skettenis return (ETIMEDOUT);
49013d051d6Skettenis
49113d051d6Skettenis *val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA);
49213d051d6Skettenis return (0);
49313d051d6Skettenis }
49413d051d6Skettenis
49513d051d6Skettenis int
lom1_write_polled(struct lom_softc * sc,uint8_t reg,uint8_t val)4965e80de5eSkettenis lom1_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val)
49713d051d6Skettenis {
49813d051d6Skettenis uint8_t str;
49913d051d6Skettenis int i;
50013d051d6Skettenis
50113d051d6Skettenis /* Wait for input buffer to become available. */
5023c40421dSkettenis for (i = 30; i > 0; i--) {
50313d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
5043c40421dSkettenis delay(1000);
50513d051d6Skettenis if ((str & LOM1_STATUS_BUSY) == 0)
50613d051d6Skettenis break;
50713d051d6Skettenis }
50813d051d6Skettenis if (i == 0)
50913d051d6Skettenis return (ETIMEDOUT);
51013d051d6Skettenis
5115e80de5eSkettenis reg |= LOM_IDX_WRITE;
5125e80de5eSkettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg);
51313d051d6Skettenis
51413d051d6Skettenis /* Wait until the microcontroller fills output buffer. */
5153c40421dSkettenis for (i = 30; i > 0; i--) {
51613d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
5173c40421dSkettenis delay(1000);
51813d051d6Skettenis if ((str & LOM1_STATUS_BUSY) == 0)
51913d051d6Skettenis break;
52013d051d6Skettenis }
52113d051d6Skettenis if (i == 0)
52213d051d6Skettenis return (ETIMEDOUT);
52313d051d6Skettenis
52413d051d6Skettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, val);
52513d051d6Skettenis
52613d051d6Skettenis return (0);
52713d051d6Skettenis }
52813d051d6Skettenis
529fc69c4e1Skettenis void
lom1_queue_cmd(struct lom_softc * sc,struct lom_cmd * lc)5305e80de5eSkettenis lom1_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
5315e80de5eSkettenis {
5325e80de5eSkettenis mtx_enter(&sc->sc_queue_mtx);
5335e80de5eSkettenis TAILQ_INSERT_TAIL(&sc->sc_queue, lc, lc_next);
5345e80de5eSkettenis if (sc->sc_state == LOM_STATE_IDLE) {
5355e80de5eSkettenis sc->sc_state = LOM_STATE_CMD;
5365e80de5eSkettenis lom1_process_queue_locked(sc);
5375e80de5eSkettenis }
5385e80de5eSkettenis mtx_leave(&sc->sc_queue_mtx);
5395e80de5eSkettenis }
5405e80de5eSkettenis
5415e80de5eSkettenis void
lom1_process_queue(void * arg)5425e80de5eSkettenis lom1_process_queue(void *arg)
543fc69c4e1Skettenis {
544fc69c4e1Skettenis struct lom_softc *sc = arg;
5455e80de5eSkettenis
5465e80de5eSkettenis mtx_enter(&sc->sc_queue_mtx);
5475e80de5eSkettenis lom1_process_queue_locked(sc);
5485e80de5eSkettenis mtx_leave(&sc->sc_queue_mtx);
5495e80de5eSkettenis }
5505e80de5eSkettenis
5515e80de5eSkettenis void
lom1_process_queue_locked(struct lom_softc * sc)5525e80de5eSkettenis lom1_process_queue_locked(struct lom_softc *sc)
5535e80de5eSkettenis {
5545e80de5eSkettenis struct lom_cmd *lc;
555fc69c4e1Skettenis uint8_t str;
556fc69c4e1Skettenis
5575e80de5eSkettenis lc = TAILQ_FIRST(&sc->sc_queue);
5588fe2a92fSkettenis if (lc == NULL) {
5598fe2a92fSkettenis sc->sc_state = LOM_STATE_IDLE;
5608fe2a92fSkettenis return;
5618fe2a92fSkettenis }
5625e80de5eSkettenis
563fc69c4e1Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
564fc69c4e1Skettenis if (str & LOM1_STATUS_BUSY) {
5658fe2a92fSkettenis if (sc->sc_retry++ < 30) {
5665e80de5eSkettenis timeout_add_msec(&sc->sc_state_to, 1);
567fc69c4e1Skettenis return;
568fc69c4e1Skettenis }
569fc69c4e1Skettenis
5708fe2a92fSkettenis /*
5718fe2a92fSkettenis * Looks like the microcontroller got wedged. Unwedge
5728fe2a92fSkettenis * it by writing this magic value. Give it some time
5738fe2a92fSkettenis * to recover.
5748fe2a92fSkettenis */
5758fe2a92fSkettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, 0xac);
5768fe2a92fSkettenis timeout_add_msec(&sc->sc_state_to, 1000);
5778fe2a92fSkettenis sc->sc_state = LOM_STATE_CMD;
5788fe2a92fSkettenis return;
5798fe2a92fSkettenis }
5808fe2a92fSkettenis
5815e80de5eSkettenis sc->sc_retry = 0;
5825e80de5eSkettenis
5835e80de5eSkettenis if (sc->sc_state == LOM_STATE_CMD) {
5845e80de5eSkettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, lc->lc_cmd);
5855e80de5eSkettenis sc->sc_state = LOM_STATE_DATA;
5865e80de5eSkettenis timeout_add_msec(&sc->sc_state_to, 250);
587fc69c4e1Skettenis return;
588fc69c4e1Skettenis }
589fc69c4e1Skettenis
5905e80de5eSkettenis KASSERT(sc->sc_state == LOM_STATE_DATA);
5915e80de5eSkettenis if ((lc->lc_cmd & LOM_IDX_WRITE) == 0)
5925e80de5eSkettenis lc->lc_data = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA);
5935e80de5eSkettenis else
5945e80de5eSkettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, lc->lc_data);
5955e80de5eSkettenis
5965e80de5eSkettenis TAILQ_REMOVE(&sc->sc_queue, lc, lc_next);
5975e80de5eSkettenis
5985e80de5eSkettenis wakeup(lc);
5995e80de5eSkettenis
6005e80de5eSkettenis if (!TAILQ_EMPTY(&sc->sc_queue)) {
6015e80de5eSkettenis sc->sc_state = LOM_STATE_CMD;
6025e80de5eSkettenis timeout_add_msec(&sc->sc_state_to, 1);
6035e80de5eSkettenis return;
6045e80de5eSkettenis }
6055e80de5eSkettenis
6065e80de5eSkettenis sc->sc_state = LOM_STATE_IDLE;
607fc69c4e1Skettenis }
608fc69c4e1Skettenis
60913d051d6Skettenis int
lom2_read(struct lom_softc * sc,uint8_t reg,uint8_t * val)61013d051d6Skettenis lom2_read(struct lom_softc *sc, uint8_t reg, uint8_t *val)
61113d051d6Skettenis {
612d95b06c1Skettenis struct lom_cmd lc;
613d95b06c1Skettenis int error;
614d95b06c1Skettenis
615d95b06c1Skettenis if (cold)
616d95b06c1Skettenis return lom2_read_polled(sc, reg, val);
617d95b06c1Skettenis
618d95b06c1Skettenis lc.lc_cmd = reg;
619d95b06c1Skettenis lc.lc_data = 0xff;
620d95b06c1Skettenis lom2_queue_cmd(sc, &lc);
621d95b06c1Skettenis
622d6fc7890Scheloha error = tsleep_nsec(&lc, PZERO, "lom2rd", SEC_TO_NSEC(1));
623d95b06c1Skettenis if (error)
624d7e63099Skettenis lom_dequeue_cmd(sc, &lc);
625d95b06c1Skettenis
626d95b06c1Skettenis *val = lc.lc_data;
627d95b06c1Skettenis
628d95b06c1Skettenis return (error);
629d95b06c1Skettenis }
630d95b06c1Skettenis
631d95b06c1Skettenis int
lom2_read_polled(struct lom_softc * sc,uint8_t reg,uint8_t * val)632d95b06c1Skettenis lom2_read_polled(struct lom_softc *sc, uint8_t reg, uint8_t *val)
633d95b06c1Skettenis {
6345f2dcfb1Skettenis uint8_t str;
6355f2dcfb1Skettenis int i;
6365f2dcfb1Skettenis
6375f2dcfb1Skettenis /* Wait for input buffer to become available. */
6385f2dcfb1Skettenis for (i = 1000; i > 0; i--) {
63913d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
6405f2dcfb1Skettenis delay(10);
64113d051d6Skettenis if ((str & LOM2_STATUS_IBF) == 0)
64213d051d6Skettenis break;
64313d051d6Skettenis }
64413d051d6Skettenis if (i == 0)
64513d051d6Skettenis return (ETIMEDOUT);
64613d051d6Skettenis
64713d051d6Skettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg);
64813d051d6Skettenis
64913d051d6Skettenis /* Wait until the microcontroller fills output buffer. */
65013d051d6Skettenis for (i = 1000; i > 0; i--) {
65113d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
65213d051d6Skettenis delay(10);
65313d051d6Skettenis if (str & LOM2_STATUS_OBF)
65413d051d6Skettenis break;
65513d051d6Skettenis }
65613d051d6Skettenis if (i == 0)
65713d051d6Skettenis return (ETIMEDOUT);
65813d051d6Skettenis
65913d051d6Skettenis *val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);
66013d051d6Skettenis return (0);
66113d051d6Skettenis }
66213d051d6Skettenis
66313d051d6Skettenis int
lom2_write(struct lom_softc * sc,uint8_t reg,uint8_t val)66413d051d6Skettenis lom2_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
66513d051d6Skettenis {
666d95b06c1Skettenis struct lom_cmd lc;
667d95b06c1Skettenis int error;
668d95b06c1Skettenis
669d95b06c1Skettenis if (cold)
670d95b06c1Skettenis return lom2_write_polled(sc, reg, val);
671d95b06c1Skettenis
672d95b06c1Skettenis lc.lc_cmd = reg | LOM_IDX_WRITE;
673d95b06c1Skettenis lc.lc_data = val;
674d95b06c1Skettenis lom2_queue_cmd(sc, &lc);
675d95b06c1Skettenis
676d6fc7890Scheloha error = tsleep_nsec(&lc, PZERO, "lom2wr", SEC_TO_NSEC(1));
677d95b06c1Skettenis if (error)
678d95b06c1Skettenis lom_dequeue_cmd(sc, &lc);
679d95b06c1Skettenis
680d95b06c1Skettenis return (error);
681d95b06c1Skettenis }
682d95b06c1Skettenis
683d95b06c1Skettenis int
lom2_write_polled(struct lom_softc * sc,uint8_t reg,uint8_t val)684d95b06c1Skettenis lom2_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val)
685d95b06c1Skettenis {
68613d051d6Skettenis uint8_t str;
68713d051d6Skettenis int i;
68813d051d6Skettenis
68913d051d6Skettenis /* Wait for input buffer to become available. */
69013d051d6Skettenis for (i = 1000; i > 0; i--) {
69113d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
69213d051d6Skettenis delay(10);
69313d051d6Skettenis if ((str & LOM2_STATUS_IBF) == 0)
6945f2dcfb1Skettenis break;
6955f2dcfb1Skettenis }
6965f2dcfb1Skettenis if (i == 0)
6975f2dcfb1Skettenis return (ETIMEDOUT);
6985f2dcfb1Skettenis
6995f2dcfb1Skettenis if (sc->sc_space == LOM_IDX_CMD_GENERIC && reg != LOM_IDX_CMD)
700d95b06c1Skettenis reg |= LOM_IDX_WRITE;
7015f2dcfb1Skettenis
70213d051d6Skettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg);
7035f2dcfb1Skettenis
7045f2dcfb1Skettenis /* Wait until the microcontroller fills output buffer. */
7055f2dcfb1Skettenis for (i = 1000; i > 0; i--) {
70613d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
7075f2dcfb1Skettenis delay(10);
70813d051d6Skettenis if (str & LOM2_STATUS_OBF)
7095f2dcfb1Skettenis break;
7105f2dcfb1Skettenis }
7115f2dcfb1Skettenis if (i == 0)
7125f2dcfb1Skettenis return (ETIMEDOUT);
7135f2dcfb1Skettenis
71413d051d6Skettenis bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);
7155f2dcfb1Skettenis
7165f2dcfb1Skettenis /* Wait for input buffer to become available. */
7175f2dcfb1Skettenis for (i = 1000; i > 0; i--) {
71813d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
7195f2dcfb1Skettenis delay(10);
72013d051d6Skettenis if ((str & LOM2_STATUS_IBF) == 0)
7215f2dcfb1Skettenis break;
7225f2dcfb1Skettenis }
7235f2dcfb1Skettenis if (i == 0)
7245f2dcfb1Skettenis return (ETIMEDOUT);
7255f2dcfb1Skettenis
72613d051d6Skettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA, val);
7275f2dcfb1Skettenis
7285f2dcfb1Skettenis /* Wait until the microcontroller fills output buffer. */
7295f2dcfb1Skettenis for (i = 1000; i > 0; i--) {
73013d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
7315f2dcfb1Skettenis delay(10);
73213d051d6Skettenis if (str & LOM2_STATUS_OBF)
7335f2dcfb1Skettenis break;
7345f2dcfb1Skettenis }
7355f2dcfb1Skettenis if (i == 0)
7365f2dcfb1Skettenis return (ETIMEDOUT);
7375f2dcfb1Skettenis
73813d051d6Skettenis bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);
7395f2dcfb1Skettenis
7405f2dcfb1Skettenis /* If we switched spaces, remember the one we're in now. */
7415f2dcfb1Skettenis if (reg == LOM_IDX_CMD)
7425f2dcfb1Skettenis sc->sc_space = val;
7435f2dcfb1Skettenis
7445f2dcfb1Skettenis return (0);
7455f2dcfb1Skettenis }
7465f2dcfb1Skettenis
7475e80de5eSkettenis void
lom2_queue_cmd(struct lom_softc * sc,struct lom_cmd * lc)7485e80de5eSkettenis lom2_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
7495e80de5eSkettenis {
750d95b06c1Skettenis uint8_t str;
751d95b06c1Skettenis
752d95b06c1Skettenis mtx_enter(&sc->sc_queue_mtx);
753d95b06c1Skettenis TAILQ_INSERT_TAIL(&sc->sc_queue, lc, lc_next);
754d95b06c1Skettenis if (sc->sc_state == LOM_STATE_IDLE) {
755d95b06c1Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
756d95b06c1Skettenis if ((str & LOM2_STATUS_IBF) == 0) {
757d95b06c1Skettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh,
758d95b06c1Skettenis LOM2_CMD, lc->lc_cmd);
759d95b06c1Skettenis sc->sc_state = LOM_STATE_DATA;
760d95b06c1Skettenis }
761d95b06c1Skettenis }
762d95b06c1Skettenis mtx_leave(&sc->sc_queue_mtx);
763d95b06c1Skettenis }
764d95b06c1Skettenis
765d95b06c1Skettenis int
lom2_intr(void * arg)766d95b06c1Skettenis lom2_intr(void *arg)
767d95b06c1Skettenis {
768d95b06c1Skettenis struct lom_softc *sc = arg;
769d95b06c1Skettenis struct lom_cmd *lc;
770d95b06c1Skettenis uint8_t str, obr;
771d95b06c1Skettenis
772d95b06c1Skettenis mtx_enter(&sc->sc_queue_mtx);
773d95b06c1Skettenis
774d95b06c1Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
775d95b06c1Skettenis obr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);
776d95b06c1Skettenis
777d95b06c1Skettenis lc = TAILQ_FIRST(&sc->sc_queue);
778d95b06c1Skettenis if (lc == NULL) {
779d95b06c1Skettenis mtx_leave(&sc->sc_queue_mtx);
780d95b06c1Skettenis return (0);
781d95b06c1Skettenis }
782d95b06c1Skettenis
783d95b06c1Skettenis if (lc->lc_cmd & LOM_IDX_WRITE) {
784d95b06c1Skettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh,
785d95b06c1Skettenis LOM2_DATA, lc->lc_data);
786d95b06c1Skettenis lc->lc_cmd &= ~LOM_IDX_WRITE;
787d95b06c1Skettenis mtx_leave(&sc->sc_queue_mtx);
788d95b06c1Skettenis return (1);
789d95b06c1Skettenis }
790d95b06c1Skettenis
791604a7870Sbluhm KASSERT(sc->sc_state == LOM_STATE_DATA);
792d95b06c1Skettenis lc->lc_data = obr;
793d95b06c1Skettenis
794d95b06c1Skettenis TAILQ_REMOVE(&sc->sc_queue, lc, lc_next);
795d95b06c1Skettenis
796d95b06c1Skettenis wakeup(lc);
797d95b06c1Skettenis
798d95b06c1Skettenis sc->sc_state = LOM_STATE_IDLE;
799d95b06c1Skettenis
800d95b06c1Skettenis if (!TAILQ_EMPTY(&sc->sc_queue)) {
801d95b06c1Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
802d95b06c1Skettenis if ((str & LOM2_STATUS_IBF) == 0) {
803d95b06c1Skettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh,
804d95b06c1Skettenis LOM2_CMD, lc->lc_cmd);
805d95b06c1Skettenis sc->sc_state = LOM_STATE_DATA;
806d95b06c1Skettenis }
807d95b06c1Skettenis }
808d95b06c1Skettenis
809d95b06c1Skettenis mtx_leave(&sc->sc_queue_mtx);
810d95b06c1Skettenis
811d95b06c1Skettenis return (1);
8125e80de5eSkettenis }
8135e80de5eSkettenis
8145f2dcfb1Skettenis int
lom_init_desc(struct lom_softc * sc)8155f2dcfb1Skettenis lom_init_desc(struct lom_softc *sc)
8165f2dcfb1Skettenis {
8175f2dcfb1Skettenis uint8_t val;
81802222f5cSkettenis int i, j, k;
81902222f5cSkettenis int error;
8205f2dcfb1Skettenis
82113d051d6Skettenis /* LOMlite doesn't provide sensor descriptions. */
82213d051d6Skettenis if (sc->sc_type < LOM_LOMLITE2)
82313d051d6Skettenis return (0);
82413d051d6Skettenis
82502222f5cSkettenis /*
82602222f5cSkettenis * Read temperature sensor names.
82702222f5cSkettenis */
8285f2dcfb1Skettenis error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_TEMP);
8295f2dcfb1Skettenis if (error)
8305f2dcfb1Skettenis return (error);
8315f2dcfb1Skettenis
83202222f5cSkettenis i = 0;
83302222f5cSkettenis j = 0;
83402222f5cSkettenis k = LOM_IDX4_TEMP_NAME_START;
83502222f5cSkettenis while (k <= LOM_IDX4_TEMP_NAME_END) {
83602222f5cSkettenis error = lom_read(sc, k++, &val);
8375f2dcfb1Skettenis if (error)
8385f2dcfb1Skettenis goto fail;
8395f2dcfb1Skettenis
8405f2dcfb1Skettenis if (val == 0xff)
8415f2dcfb1Skettenis break;
8425f2dcfb1Skettenis
84313d051d6Skettenis if (j < sizeof (sc->sc_temp[i].desc) - 1)
84413d051d6Skettenis sc->sc_temp[i].desc[j++] = val;
84513d051d6Skettenis
84602222f5cSkettenis if (val == '\0') {
8475f2dcfb1Skettenis i++;
84802222f5cSkettenis j = 0;
84902222f5cSkettenis if (i < sc->sc_num_temp)
85002222f5cSkettenis continue;
85102222f5cSkettenis
85202222f5cSkettenis break;
85302222f5cSkettenis }
85402222f5cSkettenis }
85502222f5cSkettenis
85602222f5cSkettenis /*
85702222f5cSkettenis * Read fan names.
85802222f5cSkettenis */
85902222f5cSkettenis error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_FAN);
86002222f5cSkettenis if (error)
86102222f5cSkettenis return (error);
86202222f5cSkettenis
86302222f5cSkettenis i = 0;
86402222f5cSkettenis j = 0;
86502222f5cSkettenis k = LOM_IDX5_FAN_NAME_START;
86602222f5cSkettenis while (k <= LOM_IDX5_FAN_NAME_END) {
86702222f5cSkettenis error = lom_read(sc, k++, &val);
86802222f5cSkettenis if (error)
86902222f5cSkettenis goto fail;
87002222f5cSkettenis
87102222f5cSkettenis if (val == 0xff)
87202222f5cSkettenis break;
87302222f5cSkettenis
87413d051d6Skettenis if (j < sizeof (sc->sc_fan[i].desc) - 1)
87513d051d6Skettenis sc->sc_fan[i].desc[j++] = val;
87613d051d6Skettenis
87702222f5cSkettenis if (val == '\0') {
87802222f5cSkettenis i++;
87902222f5cSkettenis j = 0;
88002222f5cSkettenis if (i < sc->sc_num_fan)
88102222f5cSkettenis continue;
88202222f5cSkettenis
88302222f5cSkettenis break;
88402222f5cSkettenis }
8855f2dcfb1Skettenis }
8865f2dcfb1Skettenis
8875f2dcfb1Skettenis fail:
8885f2dcfb1Skettenis lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_GENERIC);
8895f2dcfb1Skettenis return (error);
8905f2dcfb1Skettenis }
8915f2dcfb1Skettenis
8922613757eSkettenis void
lom_refresh(void * arg)8932613757eSkettenis lom_refresh(void *arg)
8942613757eSkettenis {
8952613757eSkettenis struct lom_softc *sc = arg;
8962613757eSkettenis uint8_t val;
89702222f5cSkettenis int i;
8982613757eSkettenis
89902222f5cSkettenis for (i = 0; i < sc->sc_num_fan; i++) {
90002222f5cSkettenis if (lom_read(sc, LOM_IDX_FAN1 + i, &val)) {
90102222f5cSkettenis sc->sc_fan[i].flags |= SENSOR_FINVALID;
90202222f5cSkettenis continue;
90302222f5cSkettenis }
90402222f5cSkettenis
90502222f5cSkettenis sc->sc_fan[i].value = (60 * sc->sc_fan_cal[i] * val) / 100;
906df54a7c0Skettenis if (val < sc->sc_fan_low[i])
907df54a7c0Skettenis sc->sc_fan[i].status = SENSOR_S_CRIT;
908df54a7c0Skettenis else
909df54a7c0Skettenis sc->sc_fan[i].status = SENSOR_S_OK;
91002222f5cSkettenis sc->sc_fan[i].flags &= ~SENSOR_FINVALID;
91102222f5cSkettenis }
9126801a748Skettenis
91378eeb547Skettenis for (i = 0; i < sc->sc_num_psu; i++) {
91478eeb547Skettenis if (lom_read(sc, LOM_IDX_PSU1 + i, &val) ||
91578eeb547Skettenis !ISSET(val, LOM_PSU_PRESENT)) {
91678eeb547Skettenis sc->sc_psu[i].flags |= SENSOR_FINVALID;
91778eeb547Skettenis continue;
91878eeb547Skettenis }
91978eeb547Skettenis
92078eeb547Skettenis if (val & LOM_PSU_STANDBY) {
92178eeb547Skettenis sc->sc_psu[i].value = 0;
92278eeb547Skettenis sc->sc_psu[i].status = SENSOR_S_UNSPEC;
92378eeb547Skettenis } else {
92478eeb547Skettenis sc->sc_psu[i].value = 1;
92578eeb547Skettenis if (ISSET(val, LOM_PSU_INPUTA) &&
92678eeb547Skettenis ISSET(val, LOM_PSU_INPUTB) &&
92778eeb547Skettenis ISSET(val, LOM_PSU_OUTPUT))
92878eeb547Skettenis sc->sc_psu[i].status = SENSOR_S_OK;
92978eeb547Skettenis else
93078eeb547Skettenis sc->sc_psu[i].status = SENSOR_S_CRIT;
93178eeb547Skettenis }
93278eeb547Skettenis sc->sc_psu[i].flags &= ~SENSOR_FINVALID;
93378eeb547Skettenis }
93478eeb547Skettenis
93578eeb547Skettenis for (i = 0; i < sc->sc_num_temp; i++) {
93678eeb547Skettenis if (lom_read(sc, LOM_IDX_TEMP1 + i, &val)) {
93778eeb547Skettenis sc->sc_temp[i].flags |= SENSOR_FINVALID;
93878eeb547Skettenis continue;
93978eeb547Skettenis }
94078eeb547Skettenis
94178eeb547Skettenis sc->sc_temp[i].value = val * 1000000 + 273150000;
94278eeb547Skettenis sc->sc_temp[i].flags &= ~SENSOR_FINVALID;
94378eeb547Skettenis }
94478eeb547Skettenis
9456801a748Skettenis /*
9466801a748Skettenis * If our hostname is set and differs from what's stored in
9476801a748Skettenis * the LOM, write the new hostname back to the LOM. Note that
9486801a748Skettenis * we include the terminating NUL when writing the hostname
949fc69c4e1Skettenis * back to the LOM, otherwise the LOM will print any trailing
9506801a748Skettenis * garbage.
9516801a748Skettenis */
9526801a748Skettenis if (hostnamelen > 0 &&
9536801a748Skettenis strncmp(sc->sc_hostname, hostname, sizeof(hostname)) != 0) {
95413d051d6Skettenis if (sc->sc_type < LOM_LOMLITE2)
95513d051d6Skettenis lom1_write_hostname(sc);
95613d051d6Skettenis else
95713d051d6Skettenis lom2_write_hostname(sc);
958*50dbebdaSmiod strlcpy(sc->sc_hostname, hostname, sizeof(sc->sc_hostname));
9596801a748Skettenis }
9602613757eSkettenis }
961877407b4Skettenis
962877407b4Skettenis void
lom1_write_hostname(struct lom_softc * sc)96313d051d6Skettenis lom1_write_hostname(struct lom_softc *sc)
96413d051d6Skettenis {
96549d60162Skettenis char name[(LOM1_IDX_HOSTNAME12 - LOM1_IDX_HOSTNAME1 + 1) + 1];
96613d051d6Skettenis char *p;
96713d051d6Skettenis int i;
96813d051d6Skettenis
96913d051d6Skettenis /*
97013d051d6Skettenis * LOMlite generally doesn't have enough space to store the
97113d051d6Skettenis * fully qualified hostname. If the hostname is too long,
97213d051d6Skettenis * strip off the domain name.
97313d051d6Skettenis */
97413d051d6Skettenis strlcpy(name, hostname, sizeof(name));
97549d60162Skettenis if (hostnamelen >= sizeof(name)) {
97613d051d6Skettenis p = strchr(name, '.');
97713d051d6Skettenis if (p)
97813d051d6Skettenis *p = '\0';
97913d051d6Skettenis }
98013d051d6Skettenis
98113d051d6Skettenis for (i = 0; i < strlen(name) + 1; i++)
9825e80de5eSkettenis if (lom_write(sc, LOM1_IDX_HOSTNAME1 + i, name[i]))
9835e80de5eSkettenis break;
98413d051d6Skettenis }
98513d051d6Skettenis
98613d051d6Skettenis void
lom2_write_hostname(struct lom_softc * sc)98713d051d6Skettenis lom2_write_hostname(struct lom_softc *sc)
98813d051d6Skettenis {
98913d051d6Skettenis int i;
99013d051d6Skettenis
99113d051d6Skettenis lom_write(sc, LOM2_IDX_HOSTNAMELEN, hostnamelen + 1);
99213d051d6Skettenis for (i = 0; i < hostnamelen + 1; i++)
99313d051d6Skettenis lom_write(sc, LOM2_IDX_HOSTNAME, hostname[i]);
99413d051d6Skettenis }
99513d051d6Skettenis
99613d051d6Skettenis void
lom_wdog_pat(void * arg)997877407b4Skettenis lom_wdog_pat(void *arg)
998877407b4Skettenis {
99956bd4c6bSkettenis struct lom_softc *sc = arg;
1000877407b4Skettenis
1001877407b4Skettenis /* Pat the dog. */
10025e80de5eSkettenis sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE;
10035e80de5eSkettenis sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl;
10045e80de5eSkettenis lom_queue_cmd(sc, &sc->sc_wdog_pat);
1005877407b4Skettenis
1006877407b4Skettenis timeout_add_sec(&sc->sc_wdog_to, LOM_WDOG_TIME_MAX / 2);
1007877407b4Skettenis }
1008877407b4Skettenis
1009877407b4Skettenis int
lom_wdog_cb(void * arg,int period)1010877407b4Skettenis lom_wdog_cb(void *arg, int period)
1011877407b4Skettenis {
1012877407b4Skettenis struct lom_softc *sc = arg;
1013877407b4Skettenis
1014fc69c4e1Skettenis if (period > LOM_WDOG_TIME_MAX)
1015fc69c4e1Skettenis period = LOM_WDOG_TIME_MAX;
1016877407b4Skettenis else if (period < 0)
1017877407b4Skettenis period = 0;
1018877407b4Skettenis
1019877407b4Skettenis if (period == 0) {
1020877407b4Skettenis if (sc->sc_wdog_period != 0) {
1021877407b4Skettenis /* Stop watchdog from resetting the machine. */
10225223c73eSkettenis sc->sc_wdog_ctl &= ~LOM_WDOG_RESET;
10235223c73eSkettenis lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl);
1024877407b4Skettenis
1025877407b4Skettenis lom_write(sc, LOM_IDX_WDOG_TIME, LOM_WDOG_TIME_MAX);
1026877407b4Skettenis timeout_add_sec(&sc->sc_wdog_to, LOM_WDOG_TIME_MAX / 2);
1027877407b4Skettenis }
1028877407b4Skettenis } else {
1029877407b4Skettenis if (sc->sc_wdog_period != period) {
1030877407b4Skettenis /* Set new timeout. */
1031877407b4Skettenis lom_write(sc, LOM_IDX_WDOG_TIME, period);
1032877407b4Skettenis }
1033877407b4Skettenis if (sc->sc_wdog_period == 0) {
1034877407b4Skettenis /* Make watchdog reset the machine. */
10355223c73eSkettenis sc->sc_wdog_ctl |= LOM_WDOG_RESET;
10365223c73eSkettenis lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl);
1037877407b4Skettenis
1038877407b4Skettenis timeout_del(&sc->sc_wdog_to);
1039877407b4Skettenis } else {
1040877407b4Skettenis /* Pat the dog. */
1041a4f1f624Skettenis lom_dequeue_cmd(sc, &sc->sc_wdog_pat);
10425e80de5eSkettenis sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE;
10435e80de5eSkettenis sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl;
10445e80de5eSkettenis lom_queue_cmd(sc, &sc->sc_wdog_pat);
1045877407b4Skettenis }
1046877407b4Skettenis }
1047877407b4Skettenis sc->sc_wdog_period = period;
1048877407b4Skettenis
1049877407b4Skettenis return (period);
1050877407b4Skettenis }
1051edd433c7Skettenis
1052edd433c7Skettenis void
lom_shutdown(void * arg)1053edd433c7Skettenis lom_shutdown(void *arg)
1054edd433c7Skettenis {
1055edd433c7Skettenis struct lom_softc *sc = arg;
1056edd433c7Skettenis
1057edd433c7Skettenis sc->sc_wdog_ctl &= ~LOM_WDOG_ENABLE;
1058edd433c7Skettenis lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl);
1059edd433c7Skettenis }
1060