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