xref: /netbsd-src/sys/arch/hppa/dev/power.c (revision 539ffff036fad071a314e6f126af9163662b6872)
1*539ffff0Sskrll /*	$NetBSD: power.c,v 1.3 2019/04/15 20:40:37 skrll Exp $	*/
26d3ceb1dSskrll 
36d3ceb1dSskrll /*
46d3ceb1dSskrll  * Copyright (c) 2004 Jochen Kunz.
56d3ceb1dSskrll  * All rights reserved.
66d3ceb1dSskrll  *
76d3ceb1dSskrll  * Redistribution and use in source and binary forms, with or without
86d3ceb1dSskrll  * modification, are permitted provided that the following conditions
96d3ceb1dSskrll  * are met:
106d3ceb1dSskrll  * 1. Redistributions of source code must retain the above copyright
116d3ceb1dSskrll  *    notice, this list of conditions and the following disclaimer.
126d3ceb1dSskrll  * 2. Redistributions in binary form must reproduce the above copyright
136d3ceb1dSskrll  *    notice, this list of conditions and the following disclaimer in the
146d3ceb1dSskrll  *    documentation and/or other materials provided with the distribution.
156d3ceb1dSskrll  * 3. The name of Jochen Kunz may not be used to endorse or promote
166d3ceb1dSskrll  *    products derived from this software without specific prior
176d3ceb1dSskrll  *    written permission.
186d3ceb1dSskrll  *
196d3ceb1dSskrll  * THIS SOFTWARE IS PROVIDED BY JOCHEN KUNZ
206d3ceb1dSskrll  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
216d3ceb1dSskrll  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
226d3ceb1dSskrll  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL JOCHEN KUNZ
236d3ceb1dSskrll  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
246d3ceb1dSskrll  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
256d3ceb1dSskrll  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
266d3ceb1dSskrll  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
276d3ceb1dSskrll  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
286d3ceb1dSskrll  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
296d3ceb1dSskrll  * POSSIBILITY OF SUCH DAMAGE.
306d3ceb1dSskrll  */
316d3ceb1dSskrll 
326d3ceb1dSskrll /*	$OpenBSD: power.c,v 1.5 2004/06/11 12:53:09 mickey Exp $	*/
336d3ceb1dSskrll 
346d3ceb1dSskrll /*
356d3ceb1dSskrll  * Copyright (c) 2003 Michael Shalayeff
366d3ceb1dSskrll  * All rights reserved.
376d3ceb1dSskrll  *
386d3ceb1dSskrll  * Redistribution and use in source and binary forms, with or without
396d3ceb1dSskrll  * modification, are permitted provided that the following conditions
406d3ceb1dSskrll  * are met:
416d3ceb1dSskrll  * 1. Redistributions of source code must retain the above copyright
426d3ceb1dSskrll  *    notice, this list of conditions and the following disclaimer.
436d3ceb1dSskrll  * 2. Redistributions in binary form must reproduce the above copyright
446d3ceb1dSskrll  *    notice, this list of conditions and the following disclaimer in the
456d3ceb1dSskrll  *    documentation and/or other materials provided with the distribution.
466d3ceb1dSskrll  *
476d3ceb1dSskrll  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
486d3ceb1dSskrll  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
496d3ceb1dSskrll  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
506d3ceb1dSskrll  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
516d3ceb1dSskrll  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
526d3ceb1dSskrll  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
536d3ceb1dSskrll  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
546d3ceb1dSskrll  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
556d3ceb1dSskrll  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
566d3ceb1dSskrll  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
576d3ceb1dSskrll  * THE POSSIBILITY OF SUCH DAMAGE.
586d3ceb1dSskrll  */
596d3ceb1dSskrll 
606d3ceb1dSskrll #include <sys/param.h>
616d3ceb1dSskrll #include <sys/kernel.h>
626d3ceb1dSskrll #include <sys/systm.h>
636d3ceb1dSskrll #include <sys/reboot.h>
646d3ceb1dSskrll #include <sys/device.h>
656d3ceb1dSskrll #include <sys/sysctl.h>
666d3ceb1dSskrll #include <sys/kmem.h>
676d3ceb1dSskrll 
686d3ceb1dSskrll #include <machine/reg.h>
696d3ceb1dSskrll #include <machine/pdc.h>
706d3ceb1dSskrll #include <machine/autoconf.h>
716d3ceb1dSskrll 
726d3ceb1dSskrll #include <hppa/dev/cpudevs.h>
736d3ceb1dSskrll 
746d3ceb1dSskrll #include <dev/sysmon/sysmon_taskq.h>
756d3ceb1dSskrll #include <dev/sysmon/sysmonvar.h>
766d3ceb1dSskrll 
776d3ceb1dSskrll /* Enable / disable control over the power switch. */
786d3ceb1dSskrll #define	PWR_SW_CTRL_DISABLE	0
796d3ceb1dSskrll #define	PWR_SW_CTRL_ENABLE	1
806d3ceb1dSskrll #define	PWR_SW_CTRL_LOCK	2
816d3ceb1dSskrll #define	PWR_SW_CTRL_MAX		PWR_SW_CTRL_LOCK
826d3ceb1dSskrll 
836d3ceb1dSskrll struct power_softc {
846d3ceb1dSskrll 	device_t sc_dev;
856d3ceb1dSskrll 	bus_space_tag_t sc_bst;
866d3ceb1dSskrll 	bus_space_handle_t sc_bsh;
876d3ceb1dSskrll 
886d3ceb1dSskrll 	void (*sc_kicker)(void *);
896d3ceb1dSskrll 
906d3ceb1dSskrll 	struct callout sc_callout;
916d3ceb1dSskrll 	int sc_timeout;
926d3ceb1dSskrll 
936d3ceb1dSskrll 	int sc_dr_cnt;
946d3ceb1dSskrll };
956d3ceb1dSskrll 
966d3ceb1dSskrll int	powermatch(device_t, cfdata_t, void *);
976d3ceb1dSskrll void	powerattach(device_t, device_t, void *);
986d3ceb1dSskrll 
996d3ceb1dSskrll CFATTACH_DECL_NEW(power, sizeof(struct power_softc),
1006d3ceb1dSskrll     powermatch, powerattach, NULL, NULL);
1016d3ceb1dSskrll 
1026d3ceb1dSskrll static struct pdc_power_info pdc_power_info;
1036d3ceb1dSskrll static bool pswitch_on;			/* power switch */
1046d3ceb1dSskrll static int pwr_sw_control;
1056d3ceb1dSskrll static const char *pwr_sw_control_str[] = {"disabled", "enabled", "locked"};
1066d3ceb1dSskrll static struct sysmon_pswitch *pwr_sw_sysmon;
1076d3ceb1dSskrll 
1086d3ceb1dSskrll static int pwr_sw_sysctl_state(SYSCTLFN_PROTO);
1096d3ceb1dSskrll static int pwr_sw_sysctl_ctrl(SYSCTLFN_PROTO);
1106d3ceb1dSskrll static void pwr_sw_sysmon_cb(void *);
1116d3ceb1dSskrll static void pwr_sw_ctrl(int);
1126d3ceb1dSskrll static int pwr_sw_init(struct power_softc *);
1136d3ceb1dSskrll 
1146d3ceb1dSskrll void power_thread_dr(void *v);
1156d3ceb1dSskrll void power_thread_reg(void *v);
1166d3ceb1dSskrll void power_cold_hook_reg(int);
1176d3ceb1dSskrll 
1186d3ceb1dSskrll int
powermatch(device_t parent,cfdata_t cf,void * aux)1196d3ceb1dSskrll powermatch(device_t parent, cfdata_t cf, void *aux)
1206d3ceb1dSskrll {
1216d3ceb1dSskrll 	struct confargs *ca = aux;
1226d3ceb1dSskrll 
1236d3ceb1dSskrll 	if (cf->cf_unit > 0 && !strcmp(ca->ca_name, "power"))
1246d3ceb1dSskrll 		return (0);
1256d3ceb1dSskrll 
1266d3ceb1dSskrll 	return (1);
1276d3ceb1dSskrll }
1286d3ceb1dSskrll 
1296d3ceb1dSskrll void
powerattach(device_t parent,device_t self,void * aux)1306d3ceb1dSskrll powerattach(device_t parent, device_t self, void *aux)
1316d3ceb1dSskrll {
1326d3ceb1dSskrll 	struct power_softc *sc = device_private(self);
1336d3ceb1dSskrll 	struct confargs *ca = aux;
1346d3ceb1dSskrll 	int err;
1356d3ceb1dSskrll 
1366d3ceb1dSskrll 	sc->sc_dev = self;
1376d3ceb1dSskrll 	sc->sc_kicker = NULL;
1386d3ceb1dSskrll 
1396d3ceb1dSskrll 	err = pdcproc_soft_power_info(&pdc_power_info);
1406d3ceb1dSskrll 
1416d3ceb1dSskrll 	if (!err)
1426d3ceb1dSskrll 		ca->ca_hpa = pdc_power_info.addr;
1436d3ceb1dSskrll 
1446d3ceb1dSskrll 	switch (cpu_modelno) {
1456d3ceb1dSskrll 	case HPPA_BOARD_HP712_60:
1466d3ceb1dSskrll 	case HPPA_BOARD_HP712_80:
1476d3ceb1dSskrll 	case HPPA_BOARD_HP712_100:
1486d3ceb1dSskrll 	case HPPA_BOARD_HP712_120:
1496d3ceb1dSskrll 		sc->sc_kicker = power_thread_dr;
1506d3ceb1dSskrll 
1516d3ceb1dSskrll 		/* Diag Reg. needs software dampening, poll at 0.2 Hz.*/
1526d3ceb1dSskrll 		sc->sc_timeout = hz / 5;
1536d3ceb1dSskrll 
1546d3ceb1dSskrll 		aprint_normal(": DR25\n");
1556d3ceb1dSskrll 		break;
1566d3ceb1dSskrll 
1576d3ceb1dSskrll 	default:
1586d3ceb1dSskrll 		if (ca->ca_hpa) {
1596d3ceb1dSskrll 			sc->sc_bst = ca->ca_iot;
1606d3ceb1dSskrll 			if (bus_space_map(sc->sc_bst, ca->ca_hpa, 4, 0,
1616d3ceb1dSskrll 			    &sc->sc_bsh) != 0)
1626d3ceb1dSskrll 				aprint_error_dev(self,
1636d3ceb1dSskrll 				    "Can't map power switch status reg.\n");
1646d3ceb1dSskrll 
1656d3ceb1dSskrll 			cold_hook = power_cold_hook_reg;
1666d3ceb1dSskrll 			sc->sc_kicker = power_thread_reg;
1676d3ceb1dSskrll 
1686d3ceb1dSskrll 			/* Power Reg. is hardware dampened, poll at 1 Hz. */
1696d3ceb1dSskrll 			sc->sc_timeout = hz;
1706d3ceb1dSskrll 
1716d3ceb1dSskrll 			aprint_normal("\n");
1726d3ceb1dSskrll 		} else
1736d3ceb1dSskrll 			aprint_normal(": not available\n");
1746d3ceb1dSskrll 		break;
1756d3ceb1dSskrll 	}
1766d3ceb1dSskrll 
1776d3ceb1dSskrll 	if (sc->sc_kicker) {
1786d3ceb1dSskrll 		if (pwr_sw_init(sc))
1796d3ceb1dSskrll 			return;
1806d3ceb1dSskrll 
1816d3ceb1dSskrll 		pswitch_on = true;
1826d3ceb1dSskrll 		pwr_sw_control = PWR_SW_CTRL_ENABLE;
1836d3ceb1dSskrll 	}
1846d3ceb1dSskrll }
1856d3ceb1dSskrll 
1866d3ceb1dSskrll /*
1876d3ceb1dSskrll  * If the power switch is turned off we schedule a sysmon task
1886d3ceb1dSskrll  * to register that event for this power switch device.
1896d3ceb1dSskrll  */
1906d3ceb1dSskrll static void
check_pwr_state(struct power_softc * sc)1916d3ceb1dSskrll check_pwr_state(struct power_softc *sc)
1926d3ceb1dSskrll {
1936d3ceb1dSskrll 	if (pswitch_on == false && pwr_sw_control != PWR_SW_CTRL_LOCK)
1946d3ceb1dSskrll 		sysmon_task_queue_sched(0, pwr_sw_sysmon_cb, NULL);
1956d3ceb1dSskrll 	else
1966d3ceb1dSskrll 		callout_reset(&sc->sc_callout, sc->sc_timeout,
1976d3ceb1dSskrll 		    sc->sc_kicker, sc);
1986d3ceb1dSskrll }
1996d3ceb1dSskrll 
2006d3ceb1dSskrll void
power_thread_dr(void * v)2016d3ceb1dSskrll power_thread_dr(void *v)
2026d3ceb1dSskrll {
2036d3ceb1dSskrll 	struct power_softc *sc = v;
2046d3ceb1dSskrll 	uint32_t r;
2056d3ceb1dSskrll 
2066d3ceb1dSskrll 	/* Get Power Fail status from CPU Diagnose Register 25 */
2076d3ceb1dSskrll 	mfcpu(25, r);
2086d3ceb1dSskrll 
2096d3ceb1dSskrll 	/*
2106d3ceb1dSskrll 	 * On power failure, the hardware clears bit DR25_PCXL_POWFAIL
2116d3ceb1dSskrll 	 * in CPU Diagnose Register 25.
2126d3ceb1dSskrll 	 */
2136d3ceb1dSskrll 	if (r & (1 << DR25_PCXL_POWFAIL))
2146d3ceb1dSskrll 		sc->sc_dr_cnt = 0;
2156d3ceb1dSskrll 	else
2166d3ceb1dSskrll 		sc->sc_dr_cnt++;
2176d3ceb1dSskrll 
2186d3ceb1dSskrll 	/*
2196d3ceb1dSskrll 	 * the bit is undampened straight wire from the power
2206d3ceb1dSskrll 	 * switch and thus we have do dampen it ourselves.
2216d3ceb1dSskrll 	 */
2226d3ceb1dSskrll 	if (sc->sc_dr_cnt == sc->sc_timeout)
2236d3ceb1dSskrll 		pswitch_on = false;
2246d3ceb1dSskrll 	else
2256d3ceb1dSskrll 		pswitch_on = true;
2266d3ceb1dSskrll 
2276d3ceb1dSskrll 	check_pwr_state(sc);
2286d3ceb1dSskrll }
2296d3ceb1dSskrll 
2306d3ceb1dSskrll void
power_thread_reg(void * v)2316d3ceb1dSskrll power_thread_reg(void *v)
2326d3ceb1dSskrll {
2336d3ceb1dSskrll 	struct power_softc *sc = v;
2346d3ceb1dSskrll 	uint32_t r;
2356d3ceb1dSskrll 
2366d3ceb1dSskrll 	r = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 0);
2376d3ceb1dSskrll 
2386d3ceb1dSskrll 	if (!(r & 1))
2396d3ceb1dSskrll 		pswitch_on = false;
2406d3ceb1dSskrll 	else
2416d3ceb1dSskrll 		pswitch_on = true;
2426d3ceb1dSskrll 
2436d3ceb1dSskrll 	check_pwr_state(sc);
2446d3ceb1dSskrll }
2456d3ceb1dSskrll 
2466d3ceb1dSskrll void
power_cold_hook_reg(int on)2476d3ceb1dSskrll power_cold_hook_reg(int on)
2486d3ceb1dSskrll {
2496d3ceb1dSskrll 	int error;
2506d3ceb1dSskrll 
2516d3ceb1dSskrll 	error = pdcproc_soft_power_enable(on == HPPA_COLD_HOT);
2526d3ceb1dSskrll 	if (error)
2536d3ceb1dSskrll 		aprint_error("PDC_SOFT_POWER_ENABLE failed (%d)\n", error);
2546d3ceb1dSskrll }
2556d3ceb1dSskrll 
2566d3ceb1dSskrll static int
pwr_sw_init(struct power_softc * sc)2576d3ceb1dSskrll pwr_sw_init(struct power_softc *sc)
2586d3ceb1dSskrll {
2596d3ceb1dSskrll 	struct sysctllog *sysctl_log = NULL;
2606d3ceb1dSskrll 	const struct sysctlnode *pwr_sw_node;
2616d3ceb1dSskrll 	const char *errmsg;
2626d3ceb1dSskrll 	int error = EINVAL;
2636d3ceb1dSskrll 
2646d3ceb1dSskrll 	/*
2656d3ceb1dSskrll 	 * Ensure that we are on a PCX-L / PA7100LC CPU if it is a
2666d3ceb1dSskrll 	 * 712 style machine.
2676d3ceb1dSskrll 	 */
2686d3ceb1dSskrll 	if (pdc_power_info.addr == 0 && hppa_cpu_info->hci_cputype != hpcxl) {
2696d3ceb1dSskrll 		aprint_error_dev(sc->sc_dev, "No soft power available.\n");
2706d3ceb1dSskrll 		return error;
2716d3ceb1dSskrll 	}
2726d3ceb1dSskrll 
2736d3ceb1dSskrll 	errmsg = "Can't create sysctl machdep.power_switch (or children)\n";
2746d3ceb1dSskrll 	error = sysctl_createv(&sysctl_log, 0, NULL, NULL, 0,
2756d3ceb1dSskrll 	    CTLTYPE_NODE, "machdep", NULL, NULL, 0, NULL, 0,
2766d3ceb1dSskrll 	    CTL_MACHDEP, CTL_EOL);
2776d3ceb1dSskrll 
2786d3ceb1dSskrll 	if (error)
2796d3ceb1dSskrll 		goto err_sysctl;
2806d3ceb1dSskrll 
2816d3ceb1dSskrll 	error = sysctl_createv(&sysctl_log, 0, NULL, &pwr_sw_node, 0,
2826d3ceb1dSskrll 	    CTLTYPE_NODE, "power_switch", NULL, NULL, 0, NULL, 0,
2836d3ceb1dSskrll 	    CTL_MACHDEP, CTL_CREATE, CTL_EOL);
2846d3ceb1dSskrll 
2856d3ceb1dSskrll 	if (error)
2866d3ceb1dSskrll 		goto err_sysctl;
2876d3ceb1dSskrll 
2886d3ceb1dSskrll 	error = sysctl_createv(&sysctl_log, 0, NULL, NULL,
2896d3ceb1dSskrll 	    CTLFLAG_READONLY, CTLTYPE_STRING, "state", NULL,
2906d3ceb1dSskrll 	    pwr_sw_sysctl_state, 0, NULL, 16,
2916d3ceb1dSskrll 	    CTL_MACHDEP, pwr_sw_node->sysctl_num, CTL_CREATE, CTL_EOL);
2926d3ceb1dSskrll 
2936d3ceb1dSskrll 	if (error)
2946d3ceb1dSskrll 		goto err_sysctl;
2956d3ceb1dSskrll 
2966d3ceb1dSskrll 	error = sysctl_createv(&sysctl_log, 0, NULL, NULL,
2976d3ceb1dSskrll 	    CTLFLAG_READWRITE, CTLTYPE_STRING, "control", NULL,
2986d3ceb1dSskrll 	    pwr_sw_sysctl_ctrl, 0, NULL, 16,
2996d3ceb1dSskrll 	    CTL_MACHDEP, pwr_sw_node->sysctl_num, CTL_CREATE, CTL_EOL);
3006d3ceb1dSskrll 
3016d3ceb1dSskrll 	if (error)
3026d3ceb1dSskrll 		goto err_sysctl;
3036d3ceb1dSskrll 
3046d3ceb1dSskrll 	errmsg = "Can't alloc sysmon power switch.\n";
3056d3ceb1dSskrll 	pwr_sw_sysmon = kmem_zalloc(sizeof(*pwr_sw_sysmon), KM_SLEEP);
3066d3ceb1dSskrll 	errmsg = "Can't register power switch with sysmon.\n";
3076d3ceb1dSskrll 	sysmon_task_queue_init();
3086d3ceb1dSskrll 	pwr_sw_sysmon->smpsw_name = "power switch";
3096d3ceb1dSskrll 	pwr_sw_sysmon->smpsw_type = PSWITCH_TYPE_POWER;
3106d3ceb1dSskrll 	error = sysmon_pswitch_register(pwr_sw_sysmon);
3116d3ceb1dSskrll 
3126d3ceb1dSskrll 	if (error)
3136d3ceb1dSskrll 		goto err_sysmon;
3146d3ceb1dSskrll 
3156d3ceb1dSskrll 	callout_init(&sc->sc_callout, 0);
3166d3ceb1dSskrll 	callout_reset(&sc->sc_callout, sc->sc_timeout, sc->sc_kicker, sc);
3176d3ceb1dSskrll 
3186d3ceb1dSskrll 	return error;
3196d3ceb1dSskrll 
3206d3ceb1dSskrll err_sysmon:
3216d3ceb1dSskrll 	kmem_free(pwr_sw_sysmon, sizeof(*pwr_sw_sysmon));
3226d3ceb1dSskrll 
3236d3ceb1dSskrll err_sysctl:
3246d3ceb1dSskrll 	sysctl_teardown(&sysctl_log);
3256d3ceb1dSskrll 
3266d3ceb1dSskrll 	aprint_error_dev(sc->sc_dev, errmsg);
3276d3ceb1dSskrll 
3286d3ceb1dSskrll 	return error;
3296d3ceb1dSskrll }
3306d3ceb1dSskrll 
3316d3ceb1dSskrll static void
pwr_sw_sysmon_cb(void * not_used)3326d3ceb1dSskrll pwr_sw_sysmon_cb(void *not_used)
3336d3ceb1dSskrll {
3346d3ceb1dSskrll 	sysmon_pswitch_event(pwr_sw_sysmon, PSWITCH_EVENT_PRESSED);
3356d3ceb1dSskrll }
3366d3ceb1dSskrll 
3376d3ceb1dSskrll static void
pwr_sw_ctrl(int enable)3386d3ceb1dSskrll pwr_sw_ctrl(int enable)
3396d3ceb1dSskrll {
3406d3ceb1dSskrll 	int on;
3416d3ceb1dSskrll 
3426d3ceb1dSskrll #ifdef DEBUG
3436d3ceb1dSskrll 	printf("pwr_sw_control=%d enable=%d\n", pwr_sw_control, enable);
3446d3ceb1dSskrll #endif /* DEBUG */
3456d3ceb1dSskrll 
3466d3ceb1dSskrll 	if (cold_hook == NULL)
3476d3ceb1dSskrll 		return;
3486d3ceb1dSskrll 
3496d3ceb1dSskrll 	switch(enable) {
3506d3ceb1dSskrll 	case PWR_SW_CTRL_DISABLE:
3516d3ceb1dSskrll 		on = HPPA_COLD_OFF;
3526d3ceb1dSskrll 		break;
3536d3ceb1dSskrll 	case PWR_SW_CTRL_ENABLE:
3546d3ceb1dSskrll 	case PWR_SW_CTRL_LOCK:
3556d3ceb1dSskrll 		on = HPPA_COLD_HOT;
3566d3ceb1dSskrll 		break;
3576d3ceb1dSskrll 	default:
3586d3ceb1dSskrll 		panic("invalid power state in pwr_sw_control: %d", enable);
3596d3ceb1dSskrll 	}
3606d3ceb1dSskrll 
3616d3ceb1dSskrll 	pwr_sw_control = enable;
3626d3ceb1dSskrll 
3636d3ceb1dSskrll 	if (cold_hook)
3646d3ceb1dSskrll 		(*cold_hook)(on);
3656d3ceb1dSskrll }
3666d3ceb1dSskrll 
3676d3ceb1dSskrll int
pwr_sw_sysctl_state(SYSCTLFN_ARGS)3686d3ceb1dSskrll pwr_sw_sysctl_state(SYSCTLFN_ARGS)
3696d3ceb1dSskrll {
3706d3ceb1dSskrll 	struct sysctlnode node;
3716d3ceb1dSskrll 	const char *status;
3726d3ceb1dSskrll 
3736d3ceb1dSskrll 	if (pswitch_on == true)
3746d3ceb1dSskrll 		status = "on";
3756d3ceb1dSskrll 	else
3766d3ceb1dSskrll 		status = "off";
3776d3ceb1dSskrll 
3786d3ceb1dSskrll 	node = *rnode;
3796d3ceb1dSskrll 	node.sysctl_data = __UNCONST(status);
3806d3ceb1dSskrll 	return sysctl_lookup(SYSCTLFN_CALL(&node));
3816d3ceb1dSskrll }
3826d3ceb1dSskrll 
3836d3ceb1dSskrll int
pwr_sw_sysctl_ctrl(SYSCTLFN_ARGS)3846d3ceb1dSskrll pwr_sw_sysctl_ctrl(SYSCTLFN_ARGS)
3856d3ceb1dSskrll {
3866d3ceb1dSskrll 	struct sysctlnode node;
3876d3ceb1dSskrll 	int i, error;
3886d3ceb1dSskrll 	char val[16];
3896d3ceb1dSskrll 
3906d3ceb1dSskrll 	node = *rnode;
3916d3ceb1dSskrll 	strcpy(val, pwr_sw_control_str[pwr_sw_control]);
3926d3ceb1dSskrll 
3936d3ceb1dSskrll 	node.sysctl_data = val;
3946d3ceb1dSskrll 
3956d3ceb1dSskrll 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
3966d3ceb1dSskrll 
3976d3ceb1dSskrll 	if (error || newp == NULL)
3986d3ceb1dSskrll 		return error;
3996d3ceb1dSskrll 
4006d3ceb1dSskrll 	for (i = 0; i <= PWR_SW_CTRL_MAX; i++)
4016d3ceb1dSskrll 		if (strcmp(val, pwr_sw_control_str[i]) == 0) {
4026d3ceb1dSskrll 			pwr_sw_ctrl(i);
4036d3ceb1dSskrll 			return 0;
4046d3ceb1dSskrll 		}
4056d3ceb1dSskrll 
4066d3ceb1dSskrll 	return EINVAL;
4076d3ceb1dSskrll }
408