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
wdog_wr_cnt(unsigned char x)86 wdog_wr_cnt(unsigned char x)
87 {
88
89 SHREG_WTCNT_W = WTCNT_W_M | (unsigned short) x;
90 }
91
92 void
wdog_wr_csr(unsigned char x)93 wdog_wr_csr(unsigned char x)
94 {
95
96 SHREG_WTCSR_W = WTCSR_W_M | (unsigned short) x;
97 }
98
99 static int
wdogmatch(device_t parent,cfdata_t cfp,void * aux)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
wdogattach(device_t parent,device_t self,void * aux)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
wdogopen(dev_t dev,int flag,int mode,struct lwp * l)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
wdogclose(dev_t dev,int flag,int mode,struct lwp * l)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
wdogioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)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
wdogintr(void * arg)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