1 /* $NetBSD: wdog.c,v 1.19 2023/12/20 15:34:45 thorpej Exp $ */ 2 3 /*- 4 * Copyright (C) 2000 SAITOH Masanobu. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: wdog.c,v 1.19 2023/12/20 15:34:45 thorpej Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/buf.h> 34 #include <sys/systm.h> 35 #include <sys/kernel.h> 36 #include <sys/uio.h> 37 #include <sys/device.h> 38 #include <sys/fcntl.h> 39 #include <sys/ioctl.h> 40 #include <sys/proc.h> 41 #include <sys/syslog.h> 42 #include <sys/conf.h> 43 44 #include <machine/cpu.h> 45 #include <machine/intr.h> 46 47 #include <sh3/frame.h> 48 #include <sh3/wdtreg.h> 49 #include <sh3/wdogvar.h> 50 #include <sh3/exception.h> 51 52 struct wdog_softc { 53 device_t sc_dev; 54 int flags; 55 }; 56 57 static int wdogmatch(device_t, cfdata_t, void *); 58 static void wdogattach(device_t, device_t, void *); 59 static int wdogintr(void *); 60 61 CFATTACH_DECL_NEW(wdog, sizeof(struct wdog_softc), 62 wdogmatch, wdogattach, NULL, NULL); 63 64 extern struct cfdriver wdog_cd; 65 66 dev_type_open(wdogopen); 67 dev_type_close(wdogclose); 68 dev_type_ioctl(wdogioctl); 69 70 const struct cdevsw wdog_cdevsw = { 71 .d_open = wdogopen, 72 .d_close = wdogclose, 73 .d_read = noread, 74 .d_write = nowrite, 75 .d_ioctl = wdogioctl, 76 .d_stop = nostop, 77 .d_tty = notty, 78 .d_poll = nopoll, 79 .d_mmap = nommap, 80 .d_kqfilter = nokqfilter, 81 .d_discard = nodiscard, 82 .d_flag = 0 83 }; 84 85 void 86 wdog_wr_cnt(unsigned char x) 87 { 88 89 SHREG_WTCNT_W = WTCNT_W_M | (unsigned short) x; 90 } 91 92 void 93 wdog_wr_csr(unsigned char x) 94 { 95 96 SHREG_WTCSR_W = WTCSR_W_M | (unsigned short) x; 97 } 98 99 static int 100 wdogmatch(device_t parent, cfdata_t cfp, void *aux) 101 { 102 103 if (strcmp(cfp->cf_name, "wdog")) 104 return (0); 105 106 return (1); 107 } 108 109 /* 110 * functions for probeing. 111 */ 112 /* ARGSUSED */ 113 static void 114 wdogattach(device_t parent, device_t self, void *aux) 115 { 116 struct wdog_softc *sc; 117 118 sc = device_private(self); 119 sc->sc_dev = self; 120 121 aprint_naive("\n"); 122 aprint_normal(": internal watchdog timer\n"); 123 124 wdog_wr_csr(WTCSR_WT | WTCSR_CKS_4096); /* default to wt mode */ 125 126 intc_intr_establish(SH_INTEVT_WDT_ITI, IST_LEVEL, IPL_SOFTCLOCK, 127 wdogintr, 0); 128 } 129 130 /*ARGSUSED*/ 131 int 132 wdogopen(dev_t dev, int flag, int mode, struct lwp *l) 133 { 134 struct wdog_softc *sc; 135 136 sc = device_lookup_private(&wdog_cd, minor(dev)); 137 if (sc == NULL) 138 return (ENXIO); 139 140 if (sc->flags & WDOGF_OPEN) 141 return (EBUSY); 142 sc->flags |= WDOGF_OPEN; 143 return (0); 144 } 145 146 /*ARGSUSED*/ 147 int 148 wdogclose(dev_t dev, int flag, int mode, struct lwp *l) 149 { 150 struct wdog_softc *sc; 151 152 sc = device_lookup_private(&wdog_cd, minor(dev)); 153 154 if (sc->flags & WDOGF_OPEN) 155 sc->flags = 0; 156 157 return (0); 158 } 159 160 extern unsigned int maxwdog; 161 162 /*ARGSUSED*/ 163 int 164 wdogioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 165 { 166 int error = 0; 167 int request; 168 169 switch (cmd) { 170 case SIOWDOGSETMODE: 171 request = *(int *)data; 172 173 switch (request) { 174 case WDOGM_RESET: 175 wdog_wr_csr(SHREG_WTCSR_R | WTCSR_WT); 176 break; 177 case WDOGM_INTR: 178 wdog_wr_csr(SHREG_WTCSR_R & ~WTCSR_WT); 179 break; 180 default: 181 error = EINVAL; 182 break; 183 } 184 break; 185 case SIORESETWDOG: 186 wdog_wr_cnt(0); /* reset to zero */ 187 break; 188 case SIOSTARTWDOG: 189 wdog_wr_csr(WTCSR_WT | WTCSR_CKS_4096); 190 wdog_wr_cnt(0); /* reset to zero */ 191 wdog_wr_csr(SHREG_WTCSR_R | WTCSR_TME); /* start!!! */ 192 break; 193 case SIOSTOPWDOG: 194 wdog_wr_csr(SHREG_WTCSR_R & ~WTCSR_TME); /* stop */ 195 break; 196 case SIOSETWDOG: 197 request = *(int *)data; 198 199 if (request > 2) { 200 error = EINVAL; 201 break; 202 } 203 break; 204 default: 205 error = EINVAL; 206 break; 207 } 208 209 return (error); 210 } 211 212 int 213 wdogintr(void *arg) 214 { 215 struct trapframe *frame = arg; 216 217 wdog_wr_csr(SHREG_WTCSR_R & ~WTCSR_IOVF); /* clear overflow bit */ 218 wdog_wr_cnt(0); /* reset to zero */ 219 printf("wdog trapped: spc = %x\n", frame->tf_spc); 220 221 return (0); 222 } 223