Module Name: src Committed By: bouyer Date: Sat Nov 28 15:55:14 UTC 2009
Modified Files: src/share/man/man4/man4.sparc64 [netbsd-5]: lom.4 src/sys/arch/sparc64/dev [netbsd-5]: lom.c Log Message: Pull up following revision(s) (requested by nakayama in ticket #1151): share/man/man4/man4.sparc64/lom.4: revision 1.3 sys/arch/sparc64/dev/lom.c: revision 1.2, 1.3 Merge changes between revision 1.16 and 1.19 of OpenBSD with shutdownhook_establish(9) to pmf(9) conversion: - LOMlite seems to get wedged from time to time; add some code to unwedge it. - Make sure we don't insert and entry into the list of pending commends twice. - Establish a shutdown hook to disable the watchdog timer to prevent watchdog triggers after the kernel has been halted. - Handle LOMlite2 in an interrupt-driven way; avoids using delay(9) once the machine is up and running. Add support for monitoring Fault LED and Alarms status. To generate a diff of this commit: cvs rdiff -u -r1.2.2.2 -r1.2.2.3 src/share/man/man4/man4.sparc64/lom.4 cvs rdiff -u -r1.1.2.2 -r1.1.2.3 src/sys/arch/sparc64/dev/lom.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/share/man/man4/man4.sparc64/lom.4 diff -u src/share/man/man4/man4.sparc64/lom.4:1.2.2.2 src/share/man/man4/man4.sparc64/lom.4:1.2.2.3 --- src/share/man/man4/man4.sparc64/lom.4:1.2.2.2 Fri Oct 16 11:56:10 2009 +++ src/share/man/man4/man4.sparc64/lom.4 Sat Nov 28 15:55:14 2009 @@ -1,4 +1,4 @@ -.\" $NetBSD: lom.4,v 1.2.2.2 2009/10/16 11:56:10 sborrill Exp $ +.\" $NetBSD: lom.4,v 1.2.2.3 2009/11/28 15:55:14 bouyer Exp $ .\" $OpenBSD: lom.4,v 1.4 2009/09/23 22:08:07 kettenis Exp $ .\" .\" Copyright (c) 2009 Mark Kettenis <kette...@openbsd.org> @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd October 2, 2009 +.Dd November 28, 2009 .Dt LOM 4 sparc64 .Os .Sh NAME @@ -29,8 +29,8 @@ driver provides support for the LOMlite lights out management module found on Sun Netra t1 systems and the LOMlite2 module found on Sun Fire V100/V120 and Sun Netra T1/X1 systems. -Temperature readings, PSU status and fan status provided by the LOM -are made available through the +Fault LED and alarms status, temperature readings, PSU status and +fan status provided by the LOM are made available through the .Xr envstat 8 interface. The integrated watchdog timer can be configured through the Index: src/sys/arch/sparc64/dev/lom.c diff -u src/sys/arch/sparc64/dev/lom.c:1.1.2.2 src/sys/arch/sparc64/dev/lom.c:1.1.2.3 --- src/sys/arch/sparc64/dev/lom.c:1.1.2.2 Fri Oct 16 11:56:11 2009 +++ src/sys/arch/sparc64/dev/lom.c Sat Nov 28 15:55:14 2009 @@ -1,5 +1,5 @@ -/* $NetBSD: lom.c,v 1.1.2.2 2009/10/16 11:56:11 sborrill Exp $ */ -/* $OpenBSD: lom.c,v 1.15 2009/09/27 18:08:42 kettenis Exp $ */ +/* $NetBSD: lom.c,v 1.1.2.3 2009/11/28 15:55:14 bouyer Exp $ */ +/* $OpenBSD: lom.c,v 1.19 2009/11/10 22:26:48 kettenis Exp $ */ /* * Copyright (c) 2009 Mark Kettenis * @@ -17,7 +17,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: lom.c,v 1.1.2.2 2009/10/16 11:56:11 sborrill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: lom.c,v 1.1.2.3 2009/11/28 15:55:14 bouyer Exp $"); #include <sys/param.h> #include <sys/device.h> @@ -83,6 +83,10 @@ #define LOM_IDX_LED1 0x25 #define LOM_IDX_ALARM 0x30 +#define LOM_ALARM_1 0x01 +#define LOM_ALARM_2 0x02 +#define LOM_ALARM_3 0x04 +#define LOM_ALARM_FAULT 0xf0 #define LOM_IDX_WDOG_CTL 0x31 #define LOM_WDOG_ENABLE 0x01 #define LOM_WDOG_RESET 0x02 @@ -131,6 +135,7 @@ #define LOM_IDX5_FAN_NAME_START 0x40 #define LOM_IDX5_FAN_NAME_END 0xff +#define LOM_MAX_ALARM 4 #define LOM_MAX_FAN 4 #define LOM_MAX_PSU 3 #define LOM_MAX_TEMP 8 @@ -153,10 +158,12 @@ int sc_space; struct sysmon_envsys *sc_sme; + envsys_data_t sc_alarm[LOM_MAX_ALARM]; envsys_data_t sc_fan[LOM_MAX_FAN]; envsys_data_t sc_psu[LOM_MAX_PSU]; envsys_data_t sc_temp[LOM_MAX_TEMP]; + int sc_num_alarm; int sc_num_fan; int sc_num_psu; int sc_num_temp; @@ -190,17 +197,20 @@ static int lom_read(struct lom_softc *, uint8_t, uint8_t *); static int lom_write(struct lom_softc *, uint8_t, uint8_t); static void lom_queue_cmd(struct lom_softc *, struct lom_cmd *); +static void lom_dequeue_cmd(struct lom_softc *, struct lom_cmd *); static int lom1_read(struct lom_softc *, uint8_t, uint8_t *); static int lom1_write(struct lom_softc *, uint8_t, uint8_t); static int lom1_read_polled(struct lom_softc *, uint8_t, uint8_t *); static int lom1_write_polled(struct lom_softc *, uint8_t, uint8_t); static void lom1_queue_cmd(struct lom_softc *, struct lom_cmd *); -static void lom1_dequeue_cmd(struct lom_softc *, struct lom_cmd *); static void lom1_process_queue(void *); static void lom1_process_queue_locked(struct lom_softc *); static int lom2_read(struct lom_softc *, uint8_t, uint8_t *); static int lom2_write(struct lom_softc *, uint8_t, uint8_t); +static int lom2_read_polled(struct lom_softc *, uint8_t, uint8_t *); +static int lom2_write_polled(struct lom_softc *, uint8_t, uint8_t); static void lom2_queue_cmd(struct lom_softc *, struct lom_cmd *); +static int lom2_intr(void *); static int lom_init_desc(struct lom_softc *); static void lom_refresh(struct sysmon_envsys *, envsys_data_t *); @@ -210,6 +220,8 @@ static int lom_wdog_tickle(struct sysmon_wdog *); static int lom_wdog_setmode(struct sysmon_wdog *); +static bool lom_shutdown(device_t, int); + static int lom_match(device_t parent, cfdata_t match, void *aux) { @@ -231,8 +243,13 @@ uint8_t cal, low; int i; - if (strcmp(ea->ea_name, "SUNW,lomh") == 0) + if (strcmp(ea->ea_name, "SUNW,lomh") == 0) { + if (ea->ea_nintr < 1) { + aprint_error(": no interrupt\n"); + return; + } sc->sc_type = LOM_LOMLITE2; + } sc->sc_dev = self; sc->sc_iot = ea->ea_bustag; @@ -246,11 +263,6 @@ /* XXX Magic */ (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, 0); bus_space_write_1(sc->sc_iot, sc->sc_ioh, 3, 0xca); - - TAILQ_INIT(&sc->sc_queue); - mutex_init(&sc->sc_queue_mtx, MUTEX_DEFAULT, IPL_VM); - callout_init(&sc->sc_state_to, 0); - callout_setfunc(&sc->sc_state_to, lom1_process_queue, sc); } if (lom_read(sc, LOM_IDX_PROBE55, ®) || reg != 0x55 || @@ -266,12 +278,26 @@ sc->sc_type < LOM_LOMLITE2 ? "LOMlite" : "LOMlite2", fw_rev >> 4, fw_rev & 0x0f); + TAILQ_INIT(&sc->sc_queue); + mutex_init(&sc->sc_queue_mtx, MUTEX_DEFAULT, IPL_BIO); + config2 = config3 = 0; - if (sc->sc_type >= LOM_LOMLITE2) { + if (sc->sc_type < LOM_LOMLITE2) { + /* + * LOMlite doesn't do interrupts so we limp along on + * timeouts. + */ + callout_init(&sc->sc_state_to, 0); + callout_setfunc(&sc->sc_state_to, lom1_process_queue, sc); + } else { lom_read(sc, LOM_IDX_CONFIG2, &config2); lom_read(sc, LOM_IDX_CONFIG3, &config3); + + bus_intr_establish(sc->sc_iot, ea->ea_intr[0], + IPL_BIO, lom2_intr, sc); } + sc->sc_num_alarm = LOM_MAX_ALARM; sc->sc_num_fan = min((config >> 5) & 0x7, LOM_MAX_FAN); sc->sc_num_psu = min((config >> 3) & 0x3, LOM_MAX_PSU); sc->sc_num_temp = min((config2 >> 4) & 0xf, LOM_MAX_TEMP); @@ -291,6 +317,16 @@ /* Initialize sensor data. */ sc->sc_sme = sysmon_envsys_create(); + for (i = 0; i < sc->sc_num_alarm; i++) { + sc->sc_alarm[i].units = ENVSYS_INDICATOR; + snprintf(sc->sc_alarm[i].desc, sizeof(sc->sc_alarm[i].desc), + i == 0 ? "Fault LED" : "Alarm%d", i); + if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_alarm[i])) { + sysmon_envsys_destroy(sc->sc_sme); + aprint_error_dev(self, "can't attach alarm sensor\n"); + return; + } + } for (i = 0; i < sc->sc_num_fan; i++) { sc->sc_fan[i].units = ENVSYS_SFANRPM; snprintf(sc->sc_fan[i].desc, sizeof(sc->sc_fan[i].desc), @@ -357,6 +393,9 @@ } aprint_verbose_dev(self, "Watchdog timer configured.\n"); + + if (!pmf_device_register1(self, NULL, NULL, lom_shutdown)) + aprint_error_dev(self, "unable to register power handler\n"); } static int @@ -386,6 +425,21 @@ return lom2_queue_cmd(sc, lc); } +static void +lom_dequeue_cmd(struct lom_softc *sc, struct lom_cmd *lc) +{ + struct lom_cmd *lcp; + + mutex_enter(&sc->sc_queue_mtx); + TAILQ_FOREACH(lcp, &sc->sc_queue, lc_next) { + if (lcp == lc) { + TAILQ_REMOVE(&sc->sc_queue, lc, lc_next); + break; + } + } + mutex_exit(&sc->sc_queue_mtx); +} + static int lom1_read(struct lom_softc *sc, uint8_t reg, uint8_t *val) { @@ -401,7 +455,7 @@ error = tsleep(&lc, PZERO, "lomrd", hz); if (error) - lom1_dequeue_cmd(sc, &lc); + lom_dequeue_cmd(sc, &lc); *val = lc.lc_data; @@ -409,7 +463,7 @@ } static int -lom1_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val) +lom1_write(struct lom_softc *sc, uint8_t reg, uint8_t val) { struct lom_cmd lc; int error; @@ -421,9 +475,9 @@ lc.lc_data = val; lom1_queue_cmd(sc, &lc); - error = tsleep(&lc, PZERO, "lomwr", hz); + error = tsleep(&lc, PZERO, "lomwr", 2 * hz); if (error) - lom1_dequeue_cmd(sc, &lc); + lom_dequeue_cmd(sc, &lc); return (error); } @@ -461,7 +515,7 @@ } static int -lom1_write(struct lom_softc *sc, uint8_t reg, uint8_t val) +lom1_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val) { uint8_t str; int i; @@ -507,21 +561,6 @@ } static void -lom1_dequeue_cmd(struct lom_softc *sc, struct lom_cmd *lc) -{ - struct lom_cmd *lcp; - - mutex_enter(&sc->sc_queue_mtx); - TAILQ_FOREACH(lcp, &sc->sc_queue, lc_next) { - if (lcp == lc) { - TAILQ_REMOVE(&sc->sc_queue, lc, lc_next); - break; - } - } - mutex_exit(&sc->sc_queue_mtx); -} - -static void lom1_process_queue(void *arg) { struct lom_softc *sc = arg; @@ -538,13 +577,26 @@ uint8_t str; lc = TAILQ_FIRST(&sc->sc_queue); - KASSERT(lc != NULL); + if (lc == NULL) { + sc->sc_state = LOM_STATE_IDLE; + return; + } str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); if (str & LOM1_STATUS_BUSY) { - if (sc->sc_retry++ > 30) + if (sc->sc_retry++ < 30) { + callout_schedule(&sc->sc_state_to, mstohz(1)); return; - callout_schedule(&sc->sc_state_to, mstohz(1)); + } + + /* + * Looks like the microcontroller got wedged. Unwedge + * it by writing this magic value. Give it some time + * to recover. + */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, 0xac); + callout_schedule(&sc->sc_state_to, mstohz(1000)); + sc->sc_state = LOM_STATE_CMD; return; } @@ -579,6 +631,28 @@ static int lom2_read(struct lom_softc *sc, uint8_t reg, uint8_t *val) { + struct lom_cmd lc; + int error; + + if (cold) + return lom2_read_polled(sc, reg, val); + + lc.lc_cmd = reg; + lc.lc_data = 0xff; + lom2_queue_cmd(sc, &lc); + + error = tsleep(&lc, PZERO, "lom2rd", hz); + if (error) + aprint_error_dev(sc->sc_dev, "lom2_read failed\n"); + + *val = lc.lc_data; + + return (error); +} + +static int +lom2_read_polled(struct lom_softc *sc, uint8_t reg, uint8_t *val) +{ uint8_t str; int i; @@ -611,6 +685,26 @@ static int lom2_write(struct lom_softc *sc, uint8_t reg, uint8_t val) { + struct lom_cmd lc; + int error; + + if (cold) + return lom2_write_polled(sc, reg, val); + + lc.lc_cmd = reg | LOM_IDX_WRITE; + lc.lc_data = val; + lom2_queue_cmd(sc, &lc); + + error = tsleep(&lc, PZERO, "lom2wr", hz); + if (error) + lom_dequeue_cmd(sc, &lc); + + return (error); +} + +static int +lom2_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val) +{ uint8_t str; int i; @@ -625,7 +719,7 @@ return (ETIMEDOUT); if (sc->sc_space == LOM_IDX_CMD_GENERIC && reg != LOM_IDX_CMD) - reg |= 0x80; + reg |= LOM_IDX_WRITE; bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg); @@ -675,8 +769,68 @@ static void lom2_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc) { - KASSERT(lc->lc_cmd & LOM_IDX_WRITE); - lom2_write(sc, lc->lc_cmd, lc->lc_data); + uint8_t str; + + mutex_enter(&sc->sc_queue_mtx); + TAILQ_INSERT_TAIL(&sc->sc_queue, lc, lc_next); + if (sc->sc_state == LOM_STATE_IDLE) { + str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); + if ((str & LOM2_STATUS_IBF) == 0) { + bus_space_write_1(sc->sc_iot, sc->sc_ioh, + LOM2_CMD, lc->lc_cmd); + sc->sc_state = LOM_STATE_DATA; + } + } + mutex_exit(&sc->sc_queue_mtx); +} + +static int +lom2_intr(void *arg) +{ + struct lom_softc *sc = arg; + struct lom_cmd *lc; + uint8_t str, obr; + + mutex_enter(&sc->sc_queue_mtx); + + str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); + obr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA); + + lc = TAILQ_FIRST(&sc->sc_queue); + if (lc == NULL) { + mutex_exit(&sc->sc_queue_mtx); + return (0); + } + + if (lc->lc_cmd & LOM_IDX_WRITE) { + bus_space_write_1(sc->sc_iot, sc->sc_ioh, + LOM2_DATA, lc->lc_data); + lc->lc_cmd &= ~LOM_IDX_WRITE; + mutex_exit(&sc->sc_queue_mtx); + return (1); + } + + KASSERT(sc->sc_state = LOM_STATE_DATA); + lc->lc_data = obr; + + TAILQ_REMOVE(&sc->sc_queue, lc, lc_next); + + wakeup(lc); + + sc->sc_state = LOM_STATE_IDLE; + + if (!TAILQ_EMPTY(&sc->sc_queue)) { + str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); + if ((str & LOM2_STATUS_IBF) == 0) { + bus_space_write_1(sc->sc_iot, sc->sc_ioh, + LOM2_CMD, lc->lc_cmd); + sc->sc_state = LOM_STATE_DATA; + } + } + + mutex_exit(&sc->sc_queue_mtx); + + return (1); } static int @@ -764,6 +918,27 @@ uint8_t val; int i; + if (lom_read(sc, LOM_IDX_ALARM, &val)) { + for (i = 0; i < sc->sc_num_alarm; i++) + sc->sc_alarm[i].state = ENVSYS_SINVALID; + } else { + /* Fault LED */ + if ((val & LOM_ALARM_FAULT) == LOM_ALARM_FAULT) + sc->sc_alarm[0].value_cur = 0; + else + sc->sc_alarm[0].value_cur = 1; + sc->sc_alarm[0].state = ENVSYS_SVALID; + + /* Alarms */ + for (i = 1; i < sc->sc_num_alarm; i++) { + if ((val & (LOM_ALARM_1 << (i - 1))) == 0) + sc->sc_alarm[i].value_cur = 0; + else + sc->sc_alarm[i].value_cur = 1; + sc->sc_alarm[i].state = ENVSYS_SVALID; + } + } + for (i = 0; i < sc->sc_num_fan; i++) { if (lom_read(sc, LOM_IDX_FAN1 + i, &val)) { sc->sc_fan[i].state = ENVSYS_SINVALID; @@ -890,6 +1065,7 @@ lom_write(sc, LOM_IDX_WDOG_TIME, smw->smw_period); /* enable watchdog */ + lom_dequeue_cmd(sc, &sc->sc_wdog_pat); sc->sc_wdog_ctl |= LOM_WDOG_ENABLE|LOM_WDOG_RESET; sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE; sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl; @@ -898,3 +1074,13 @@ return 0; } + +static bool +lom_shutdown(device_t dev, int how) +{ + struct lom_softc *sc = device_private(dev); + + sc->sc_wdog_ctl &= ~LOM_WDOG_ENABLE; + lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl); + return true; +}