xref: /netbsd/sys/arch/sgimips/dev/crime.c (revision 11aa4c2b)
1 /*	$NetBSD: crime.c,v 1.39 2021/04/26 17:07:17 mrg Exp $	*/
2 
3 /*
4  * Copyright (c) 2004 Christopher SEKIYA
5  * Copyright (c) 2000 Soren S. Jorvang
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *          This product includes software developed for the
19  *          NetBSD Project.  See http://www.NetBSD.org/ for
20  *          information about NetBSD.
21  * 4. The name of the author may not be used to endorse or promote products
22  *    derived from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 /*
37  * O2 CRIME
38  */
39 
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: crime.c,v 1.39 2021/04/26 17:07:17 mrg Exp $");
42 
43 #include "opt_ddb.h"
44 
45 #include <sys/param.h>
46 #include <sys/device.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/cpu.h>
50 
51 #include <machine/locore.h>
52 #include <machine/autoconf.h>
53 #include <sys/bus.h>
54 #include <machine/intr.h>
55 #include <machine/machtype.h>
56 #include <machine/sysconf.h>
57 
58 #include <sgimips/dev/crimevar.h>
59 #include <sgimips/dev/crimereg.h>
60 #include <sgimips/mace/macevar.h>
61 
62 #if defined(DDB)
63 #include <machine/db_machdep.h>
64 #endif
65 
66 #include "locators.h"
67 
68 #define DISABLE_CRIME_WATCHDOG
69 
70 static int	crime_match(device_t, struct cfdata *, void *);
71 static void	crime_attach(device_t, device_t, void *);
72 static void	crime_mem_reset(void);
73 static void	crime_cpu_reset(void);
74 static void	crime_bus_reset(void);
75 void		crime_watchdog_reset(void);
76 void		crime_watchdog_disable(void);
77 void		crime_intr(vaddr_t, uint32_t, uint32_t);
78 void		*crime_intr_establish(int, int, int (*)(void *), void *);
79 
80 static bus_space_tag_t crm_iot;
81 static bus_space_handle_t crm_ioh;
82 
83 CFATTACH_DECL_NEW(crime, sizeof(struct crime_softc),
84     crime_match, crime_attach, NULL, NULL);
85 
86 #define CRIME_NINTR 32 	/* XXX */
87 
88 struct {
89 	int	(*func)(void *);
90 	void	*arg;
91 } crime[CRIME_NINTR];
92 
93 static int
crime_match(device_t parent,struct cfdata * match,void * aux)94 crime_match(device_t parent, struct cfdata *match, void *aux)
95 {
96 
97 	/*
98 	 * The CRIME is in the O2.
99 	 */
100 	if (mach_type == MACH_SGI_IP32)
101 		return 1;
102 
103 	return 0;
104 }
105 
106 static void
crime_attach(device_t parent,device_t self,void * aux)107 crime_attach(device_t parent, device_t self, void *aux)
108 {
109 	struct mainbus_attach_args *ma = aux;
110 	struct cpu_info * const ci = curcpu();
111 	struct crime_softc *sc = device_private(self);
112 	uint64_t crm_id;
113 	uint64_t baseline, endline;
114 	uint32_t startctr, endctr, cps;
115 
116 #if defined(DDB)
117 	cpu_reset_address = crime_reboot;
118 #endif
119 
120 	sc->sc_dev = self;
121 	crm_iot = normal_memt;
122 
123 	if (bus_space_map(crm_iot, ma->ma_addr, 0x1000,
124 	    BUS_SPACE_MAP_LINEAR, &crm_ioh))
125 		panic("%s: can't map I/O space", __func__);
126 
127 	crm_id = bus_space_read_8(crm_iot, crm_ioh, CRIME_REV);
128 
129 	aprint_naive(": system ASIC");
130 
131 	switch ((crm_id & CRIME_ID_IDBITS) >> CRIME_ID_IDSHIFT) {
132 	case 0x0b:
133 		aprint_normal(": rev 1.5");
134 		break;
135 
136 	case 0x0a:
137 		if ((crm_id >> 32) == 0)
138 			aprint_normal(": rev 1.1");
139 		else if ((crm_id >> 32) == 1)
140 			aprint_normal(": rev 1.3");
141 		else
142 			aprint_normal(": rev 1.4");
143 		break;
144 
145 	case 0x00:
146 		aprint_normal(": Petty CRIME");
147 		break;
148 
149 	default:
150 		aprint_normal(": Unknown CRIME");
151 		break;
152 	}
153 
154 	aprint_normal(" (CRIME_ID: %" PRIu64 ")\n", crm_id);
155 
156 	/* reset CRIME CPU & memory error registers */
157 	crime_mem_reset();
158 	crime_cpu_reset();
159 
160 	crime_watchdog_disable();
161 
162 #define CRIME_TIMER_FREQ	66666666	/* crime clock is 66.7MHz */
163 
164 	baseline = bus_space_read_8(crm_iot, crm_ioh, CRIME_TIME)
165 	    & CRIME_TIME_MASK;
166 	startctr = mips3_cp0_count_read();
167 
168 	/* read both cp0 and crime counters for 100ms */
169 	do {
170 		endline = bus_space_read_8(crm_iot, crm_ioh, CRIME_TIME)
171 		    & CRIME_TIME_MASK;
172 		endctr = mips3_cp0_count_read();
173 	} while (endline - baseline < (CRIME_TIMER_FREQ / 10));
174 
175 	cps = (endctr - startctr) * 10;
176 	ci->ci_cpu_freq = cps;
177 	ci->ci_cctr_freq = cps;
178 	if (mips_options.mips_cpu_flags & CPU_MIPS_DOUBLE_COUNT)
179 		ci->ci_cpu_freq *= 2;
180 	ci->ci_cycles_per_hz = (cps + (hz / 2)) / hz;
181 	ci->ci_divisor_delay = (cps + (1000000 / 2)) / 1000000;
182 
183 	/* Turn on memory error and crime error interrupts.
184 	   All others turned on as devices are registered. */
185 	bus_space_write_8(crm_iot, crm_ioh, CRIME_INTMASK,
186 	    CRIME_INT_MEMERR |
187 	    CRIME_INT_CRMERR |
188 	    CRIME_INT_VICE |
189 	    CRIME_INT_VID_OUT |
190 	    CRIME_INT_VID_IN2 |
191 	    CRIME_INT_VID_IN1);
192 	bus_space_write_8(crm_iot, crm_ioh, CRIME_INTSTAT, 0);
193 	bus_space_write_8(crm_iot, crm_ioh, CRIME_SOFTINT, 0);
194 	bus_space_write_8(crm_iot, crm_ioh, CRIME_HARDINT, 0);
195 
196 	platform.bus_reset = crime_bus_reset;
197 	platform.watchdog_reset = crime_watchdog_reset;
198 	platform.watchdog_disable = crime_watchdog_disable;
199 	platform.watchdog_enable = crime_watchdog_reset;
200 	platform.intr_establish = crime_intr_establish;
201 	platform.intr0 = crime_intr;
202 }
203 
204 /*
205  * XXX: sharing interrupts?
206  */
207 
208 void *
crime_intr_establish(int irq,int level,int (* func)(void *),void * arg)209 crime_intr_establish(int irq, int level, int (*func)(void *), void *arg)
210 {
211 
212 	if (irq < 16)
213 		return mace_intr_establish(irq, level, func, arg);
214 
215 	if (crime[irq].func != NULL)
216 		return NULL;	/* panic("Cannot share CRIME interrupts!"); */
217 
218 	crime[irq].func = func;
219 	crime[irq].arg = arg;
220 
221 	crime_intr_mask(irq);
222 
223 	return (void *)&crime[irq];
224 }
225 
226 void
crime_intr(vaddr_t pc,uint32_t status,uint32_t ipending)227 crime_intr(vaddr_t pc, uint32_t status, uint32_t ipending)
228 {
229 	uint64_t crime_intmask;
230 	uint64_t crime_intstat;
231 	uint64_t crime_ipending;
232 	uint64_t address, stat;
233 	int i;
234 
235 	crime_intmask = bus_space_read_8(crm_iot, crm_ioh, CRIME_INTMASK);
236 	crime_intstat = bus_space_read_8(crm_iot, crm_ioh, CRIME_INTSTAT);
237 	crime_ipending = (crime_intstat & crime_intmask);
238 
239 	if (crime_ipending & 0xffff)
240 		mace_intr(crime_ipending & 0xffff);
241 
242 	if (crime_ipending & 0xffff0000) {
243 	/*
244 	 * CRIME interrupts for CPU and memory errors
245 	 */
246 		if (crime_ipending & CRIME_INT_MEMERR) {
247 			address = bus_space_read_8(crm_iot, crm_ioh,
248 			    CRIME_MEM_ERROR_ADDR);
249 			stat = bus_space_read_8(crm_iot, crm_ioh,
250 			    CRIME_MEM_ERROR_STAT);
251 			printf("crime: memory error address %" PRIu64
252 			    " status %" PRIu64 "\n", address << 2, stat);
253 			crime_mem_reset();
254 		}
255 
256 		if (crime_ipending & CRIME_INT_CRMERR) {
257 			stat = bus_space_read_8(crm_iot, crm_ioh,
258 			    CRIME_CPU_ERROR_STAT);
259 			address = bus_space_read_8(crm_iot, crm_ioh,
260 			    CRIME_CPU_ERROR_ADDR) << 2;
261 			printf("crime: cpu error %" PRIu64 " at address %"
262 			       PRIu64 "\n", stat, address);
263 			crime_cpu_reset();
264 		}
265 	}
266 
267 	crime_ipending &= ~0xffff;
268 
269 	if (crime_ipending) {
270 		for (i = 16; i < CRIME_NINTR; i++) {
271 			if ((crime_ipending & (1 << i)) &&
272 			    crime[i].func != NULL)
273 				(*crime[i].func)(crime[i].arg);
274 		}
275 	}
276 }
277 
278 void
crime_intr_mask(unsigned int intr)279 crime_intr_mask(unsigned int intr)
280 {
281 	uint64_t mask;
282 
283 	mask = bus_space_read_8(crm_iot, crm_ioh, CRIME_INTMASK);
284 	mask |= (1 << intr);
285 	bus_space_write_8(crm_iot, crm_ioh, CRIME_INTMASK, mask);
286 }
287 
288 void
crime_intr_unmask(unsigned int intr)289 crime_intr_unmask(unsigned int intr)
290 {
291 	uint64_t mask;
292 
293 	mask = bus_space_read_8(crm_iot, crm_ioh, CRIME_INTMASK);
294 	mask &= ~(1 << intr);
295 	bus_space_write_8(crm_iot, crm_ioh, CRIME_INTMASK, mask);
296 }
297 
298 void
crime_mem_reset(void)299 crime_mem_reset(void)
300 {
301 
302 	bus_space_write_8(crm_iot, crm_ioh, CRIME_MEM_ERROR_STAT, 0);
303 }
304 
305 void
crime_cpu_reset(void)306 crime_cpu_reset(void)
307 {
308 
309 	bus_space_write_8(crm_iot, crm_ioh, CRIME_CPU_ERROR_STAT, 0);
310 }
311 
312 void
crime_bus_reset(void)313 crime_bus_reset(void)
314 {
315 
316 	crime_mem_reset();
317 	crime_cpu_reset();
318 }
319 
320 void
crime_watchdog_reset(void)321 crime_watchdog_reset(void)
322 {
323 
324 #ifdef DISABLE_CRIME_WATCHDOG
325 	bus_space_write_8(crm_iot, crm_ioh, CRIME_WATCHDOG, 0);
326 #else
327 	/* enable watchdog timer, clear it */
328 	bus_space_write_8(crm_iot, crm_ioh,
329 		CRIME_CONTROL, CRIME_CONTROL_DOG_ENABLE);
330 	bus_space_write_8(crm_iot, crm_ioh, CRIME_WATCHDOG, 0);
331 #endif
332 }
333 
334 void
crime_watchdog_disable(void)335 crime_watchdog_disable(void)
336 {
337 	uint64_t reg;
338 
339 	bus_space_write_8(crm_iot, crm_ioh, CRIME_WATCHDOG, 0);
340 	reg = bus_space_read_8(crm_iot, crm_ioh, CRIME_CONTROL)
341 	    & ~CRIME_CONTROL_DOG_ENABLE;
342 	bus_space_write_8(crm_iot, crm_ioh, CRIME_CONTROL, reg);
343 }
344 
345 void
crime_reboot(void)346 crime_reboot(void)
347 {
348 
349 	bus_space_write_8(crm_iot, crm_ioh,  CRIME_CONTROL,
350 	    CRIME_CONTROL_HARD_RESET);
351 	for (;;)
352 		;
353 }
354