1*0151967cSmrg /* $NetBSD: crime.c,v 1.39 2021/04/26 17:07:17 mrg Exp $ */
24a45886cSsoren
34a45886cSsoren /*
423020fc3Ssekiya * Copyright (c) 2004 Christopher SEKIYA
54a45886cSsoren * Copyright (c) 2000 Soren S. Jorvang
64a45886cSsoren * All rights reserved.
74a45886cSsoren *
84a45886cSsoren * Redistribution and use in source and binary forms, with or without
94a45886cSsoren * modification, are permitted provided that the following conditions
104a45886cSsoren * are met:
114a45886cSsoren * 1. Redistributions of source code must retain the above copyright
124a45886cSsoren * notice, this list of conditions and the following disclaimer.
134a45886cSsoren * 2. Redistributions in binary form must reproduce the above copyright
144a45886cSsoren * notice, this list of conditions and the following disclaimer in the
154a45886cSsoren * documentation and/or other materials provided with the distribution.
164a45886cSsoren * 3. All advertising materials mentioning features or use of this software
174a45886cSsoren * must display the following acknowledgement:
184a45886cSsoren * This product includes software developed for the
1907147999Skeihan * NetBSD Project. See http://www.NetBSD.org/ for
204a45886cSsoren * information about NetBSD.
214a45886cSsoren * 4. The name of the author may not be used to endorse or promote products
224a45886cSsoren * derived from this software without specific prior written permission.
234a45886cSsoren *
244a45886cSsoren * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
254a45886cSsoren * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
264a45886cSsoren * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
274a45886cSsoren * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
284a45886cSsoren * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
294a45886cSsoren * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
304a45886cSsoren * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
314a45886cSsoren * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
324a45886cSsoren * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
334a45886cSsoren * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
344a45886cSsoren */
354a45886cSsoren
364a45886cSsoren /*
374a45886cSsoren * O2 CRIME
384a45886cSsoren */
394a45886cSsoren
40ed517291Slukem #include <sys/cdefs.h>
41*0151967cSmrg __KERNEL_RCSID(0, "$NetBSD: crime.c,v 1.39 2021/04/26 17:07:17 mrg Exp $");
42*0151967cSmrg
43*0151967cSmrg #include "opt_ddb.h"
44ed517291Slukem
454a45886cSsoren #include <sys/param.h>
464a45886cSsoren #include <sys/device.h>
474a45886cSsoren #include <sys/systm.h>
4823020fc3Ssekiya #include <sys/kernel.h>
49f0301095Syamt #include <sys/cpu.h>
504a45886cSsoren
514a45886cSsoren #include <machine/locore.h>
524a45886cSsoren #include <machine/autoconf.h>
53cf10107dSdyoung #include <sys/bus.h>
5441ba2b7cSsoren #include <machine/intr.h>
55af0e157bSthorpej #include <machine/machtype.h>
5658a060c7Ssekiya #include <machine/sysconf.h>
574a45886cSsoren
58b0cd3c80Stsutsui #include <sgimips/dev/crimevar.h>
594a45886cSsoren #include <sgimips/dev/crimereg.h>
6063b59c4dSsekiya #include <sgimips/mace/macevar.h>
614a45886cSsoren
62*0151967cSmrg #if defined(DDB)
63*0151967cSmrg #include <machine/db_machdep.h>
64*0151967cSmrg #endif
65*0151967cSmrg
664a45886cSsoren #include "locators.h"
674a45886cSsoren
68e1beb9f8Stsutsui #define DISABLE_CRIME_WATCHDOG
6969a102c0Sjmcneill
70f0b7a070Smacallan static int crime_match(device_t, struct cfdata *, void *);
71f0b7a070Smacallan static void crime_attach(device_t, device_t, void *);
7225bb3b0eSmrg static void crime_mem_reset(void);
7325bb3b0eSmrg static void crime_cpu_reset(void);
7425bb3b0eSmrg static void crime_bus_reset(void);
7523020fc3Ssekiya void crime_watchdog_reset(void);
7623020fc3Ssekiya void crime_watchdog_disable(void);
7723347d39Smatt void crime_intr(vaddr_t, uint32_t, uint32_t);
7823020fc3Ssekiya void *crime_intr_establish(int, int, int (*)(void *), void *);
794a45886cSsoren
8023020fc3Ssekiya static bus_space_tag_t crm_iot;
8123020fc3Ssekiya static bus_space_handle_t crm_ioh;
82b0cd3c80Stsutsui
83f0b7a070Smacallan CFATTACH_DECL_NEW(crime, sizeof(struct crime_softc),
8489bf5a8fSthorpej crime_match, crime_attach, NULL, NULL);
854a45886cSsoren
86c21021e6Srafal #define CRIME_NINTR 32 /* XXX */
87c21021e6Srafal
88c21021e6Srafal struct {
89c21021e6Srafal int (*func)(void *);
90c21021e6Srafal void *arg;
91c21021e6Srafal } crime[CRIME_NINTR];
92c21021e6Srafal
934a45886cSsoren static int
crime_match(device_t parent,struct cfdata * match,void * aux)94f0b7a070Smacallan crime_match(device_t parent, struct cfdata *match, void *aux)
954a45886cSsoren {
964a45886cSsoren
974a45886cSsoren /*
984a45886cSsoren * The CRIME is in the O2.
994a45886cSsoren */
100af0e157bSthorpej if (mach_type == MACH_SGI_IP32)
1014578c8e4Stsutsui return 1;
102af0e157bSthorpej
1034578c8e4Stsutsui return 0;
1044a45886cSsoren }
1054a45886cSsoren
1064a45886cSsoren static void
crime_attach(device_t parent,device_t self,void * aux)107f0b7a070Smacallan crime_attach(device_t parent, device_t self, void *aux)
1084a45886cSsoren {
1094a45886cSsoren struct mainbus_attach_args *ma = aux;
11023347d39Smatt struct cpu_info * const ci = curcpu();
111f0b7a070Smacallan struct crime_softc *sc = device_private(self);
1124578c8e4Stsutsui uint64_t crm_id;
1134578c8e4Stsutsui uint64_t baseline, endline;
1144578c8e4Stsutsui uint32_t startctr, endctr, cps;
1154a45886cSsoren
116*0151967cSmrg #if defined(DDB)
117*0151967cSmrg cpu_reset_address = crime_reboot;
118*0151967cSmrg #endif
119*0151967cSmrg
120f0b7a070Smacallan sc->sc_dev = self;
121eb488f67Smacallan crm_iot = normal_memt;
122b0cd3c80Stsutsui
123eb488f67Smacallan if (bus_space_map(crm_iot, ma->ma_addr, 0x1000,
12423020fc3Ssekiya BUS_SPACE_MAP_LINEAR, &crm_ioh))
1254578c8e4Stsutsui panic("%s: can't map I/O space", __func__);
126b0cd3c80Stsutsui
12723020fc3Ssekiya crm_id = bus_space_read_8(crm_iot, crm_ioh, CRIME_REV);
1284a45886cSsoren
129c21021e6Srafal aprint_naive(": system ASIC");
130c21021e6Srafal
13130d29f64Srafal switch ((crm_id & CRIME_ID_IDBITS) >> CRIME_ID_IDSHIFT) {
1320cff9e28Srafal case 0x0b:
1330cff9e28Srafal aprint_normal(": rev 1.5");
1340cff9e28Srafal break;
1350cff9e28Srafal
1360cff9e28Srafal case 0x0a:
1370cff9e28Srafal if ((crm_id >> 32) == 0)
1380cff9e28Srafal aprint_normal(": rev 1.1");
1390cff9e28Srafal else if ((crm_id >> 32) == 1)
1400cff9e28Srafal aprint_normal(": rev 1.3");
1414a45886cSsoren else
1420cff9e28Srafal aprint_normal(": rev 1.4");
1430cff9e28Srafal break;
1444a45886cSsoren
1450cff9e28Srafal case 0x00:
1460cff9e28Srafal aprint_normal(": Petty CRIME");
1470cff9e28Srafal break;
1480cff9e28Srafal
1490cff9e28Srafal default:
1500cff9e28Srafal aprint_normal(": Unknown CRIME");
1510cff9e28Srafal break;
1520cff9e28Srafal }
1530cff9e28Srafal
1544578c8e4Stsutsui aprint_normal(" (CRIME_ID: %" PRIu64 ")\n", crm_id);
155c21021e6Srafal
15623020fc3Ssekiya /* reset CRIME CPU & memory error registers */
15725bb3b0eSmrg crime_mem_reset();
15825bb3b0eSmrg crime_cpu_reset();
15923020fc3Ssekiya
160a311d7b2Stsutsui crime_watchdog_disable();
161a36263cdStsutsui
16284857998Stsutsui #define CRIME_TIMER_FREQ 66666666 /* crime clock is 66.7MHz */
16323020fc3Ssekiya
16484857998Stsutsui baseline = bus_space_read_8(crm_iot, crm_ioh, CRIME_TIME)
16584857998Stsutsui & CRIME_TIME_MASK;
16684857998Stsutsui startctr = mips3_cp0_count_read();
16723020fc3Ssekiya
16884857998Stsutsui /* read both cp0 and crime counters for 100ms */
16984857998Stsutsui do {
17084857998Stsutsui endline = bus_space_read_8(crm_iot, crm_ioh, CRIME_TIME)
17184857998Stsutsui & CRIME_TIME_MASK;
17284857998Stsutsui endctr = mips3_cp0_count_read();
17384857998Stsutsui } while (endline - baseline < (CRIME_TIMER_FREQ / 10));
17484857998Stsutsui
17584857998Stsutsui cps = (endctr - startctr) * 10;
17623347d39Smatt ci->ci_cpu_freq = cps;
17723347d39Smatt ci->ci_cctr_freq = cps;
17823347d39Smatt if (mips_options.mips_cpu_flags & CPU_MIPS_DOUBLE_COUNT)
17923347d39Smatt ci->ci_cpu_freq *= 2;
18023347d39Smatt ci->ci_cycles_per_hz = (cps + (hz / 2)) / hz;
18123347d39Smatt ci->ci_divisor_delay = (cps + (1000000 / 2)) / 1000000;
18223020fc3Ssekiya
183b0cd3c80Stsutsui /* Turn on memory error and crime error interrupts.
184b0cd3c80Stsutsui All others turned on as devices are registered. */
18523020fc3Ssekiya bus_space_write_8(crm_iot, crm_ioh, CRIME_INTMASK,
186b0cd3c80Stsutsui CRIME_INT_MEMERR |
187b0cd3c80Stsutsui CRIME_INT_CRMERR |
188b0cd3c80Stsutsui CRIME_INT_VICE |
189b0cd3c80Stsutsui CRIME_INT_VID_OUT |
190b0cd3c80Stsutsui CRIME_INT_VID_IN2 |
191b0cd3c80Stsutsui CRIME_INT_VID_IN1);
19223020fc3Ssekiya bus_space_write_8(crm_iot, crm_ioh, CRIME_INTSTAT, 0);
19323020fc3Ssekiya bus_space_write_8(crm_iot, crm_ioh, CRIME_SOFTINT, 0);
19423020fc3Ssekiya bus_space_write_8(crm_iot, crm_ioh, CRIME_HARDINT, 0);
19558a060c7Ssekiya
19623020fc3Ssekiya platform.bus_reset = crime_bus_reset;
19723020fc3Ssekiya platform.watchdog_reset = crime_watchdog_reset;
19823020fc3Ssekiya platform.watchdog_disable = crime_watchdog_disable;
19923020fc3Ssekiya platform.watchdog_enable = crime_watchdog_reset;
20023020fc3Ssekiya platform.intr_establish = crime_intr_establish;
20123020fc3Ssekiya platform.intr0 = crime_intr;
2024a45886cSsoren }
20341ba2b7cSsoren
20441ba2b7cSsoren /*
205c21021e6Srafal * XXX: sharing interrupts?
20641ba2b7cSsoren */
20741ba2b7cSsoren
20841ba2b7cSsoren void *
crime_intr_establish(int irq,int level,int (* func)(void *),void * arg)20923020fc3Ssekiya crime_intr_establish(int irq, int level, int (*func)(void *), void *arg)
21041ba2b7cSsoren {
2114578c8e4Stsutsui
2128590eac4Ssekiya if (irq < 16)
21363b59c4dSsekiya return mace_intr_establish(irq, level, func, arg);
21463b59c4dSsekiya
215c21021e6Srafal if (crime[irq].func != NULL)
216c21021e6Srafal return NULL; /* panic("Cannot share CRIME interrupts!"); */
21741ba2b7cSsoren
218c21021e6Srafal crime[irq].func = func;
219c21021e6Srafal crime[irq].arg = arg;
22041ba2b7cSsoren
221b0cd3c80Stsutsui crime_intr_mask(irq);
222b0cd3c80Stsutsui
223c21021e6Srafal return (void *)&crime[irq];
22441ba2b7cSsoren }
22541ba2b7cSsoren
2260cff9e28Srafal void
crime_intr(vaddr_t pc,uint32_t status,uint32_t ipending)22723347d39Smatt crime_intr(vaddr_t pc, uint32_t status, uint32_t ipending)
22841ba2b7cSsoren {
2294578c8e4Stsutsui uint64_t crime_intmask;
2304578c8e4Stsutsui uint64_t crime_intstat;
2314578c8e4Stsutsui uint64_t crime_ipending;
2324578c8e4Stsutsui uint64_t address, stat;
23341ba2b7cSsoren int i;
23441ba2b7cSsoren
23523020fc3Ssekiya crime_intmask = bus_space_read_8(crm_iot, crm_ioh, CRIME_INTMASK);
23623020fc3Ssekiya crime_intstat = bus_space_read_8(crm_iot, crm_ioh, CRIME_INTSTAT);
23723020fc3Ssekiya crime_ipending = (crime_intstat & crime_intmask);
23823020fc3Ssekiya
2398590eac4Ssekiya if (crime_ipending & 0xffff)
2408590eac4Ssekiya mace_intr(crime_ipending & 0xffff);
24123020fc3Ssekiya
24223020fc3Ssekiya if (crime_ipending & 0xffff0000) {
24323020fc3Ssekiya /*
24423020fc3Ssekiya * CRIME interrupts for CPU and memory errors
24523020fc3Ssekiya */
24623020fc3Ssekiya if (crime_ipending & CRIME_INT_MEMERR) {
2474578c8e4Stsutsui address = bus_space_read_8(crm_iot, crm_ioh,
2484578c8e4Stsutsui CRIME_MEM_ERROR_ADDR);
2494578c8e4Stsutsui stat = bus_space_read_8(crm_iot, crm_ioh,
2504578c8e4Stsutsui CRIME_MEM_ERROR_STAT);
2514578c8e4Stsutsui printf("crime: memory error address %" PRIu64
2524578c8e4Stsutsui " status %" PRIu64 "\n", address << 2, stat);
25325bb3b0eSmrg crime_mem_reset();
25423020fc3Ssekiya }
25523020fc3Ssekiya
25623020fc3Ssekiya if (crime_ipending & CRIME_INT_CRMERR) {
2574578c8e4Stsutsui stat = bus_space_read_8(crm_iot, crm_ioh,
2584578c8e4Stsutsui CRIME_CPU_ERROR_STAT);
25925bb3b0eSmrg address = bus_space_read_8(crm_iot, crm_ioh,
26025bb3b0eSmrg CRIME_CPU_ERROR_ADDR) << 2;
26125bb3b0eSmrg printf("crime: cpu error %" PRIu64 " at address %"
26225bb3b0eSmrg PRIu64 "\n", stat, address);
26325bb3b0eSmrg crime_cpu_reset();
26423020fc3Ssekiya }
26523020fc3Ssekiya }
26623020fc3Ssekiya
2671fcc2e99Sjmcneill crime_ipending &= ~0xffff;
26823020fc3Ssekiya
2694578c8e4Stsutsui if (crime_ipending) {
2701fcc2e99Sjmcneill for (i = 16; i < CRIME_NINTR; i++) {
2714578c8e4Stsutsui if ((crime_ipending & (1 << i)) &&
2724578c8e4Stsutsui crime[i].func != NULL)
27341ba2b7cSsoren (*crime[i].func)(crime[i].arg);
2740cff9e28Srafal }
27541ba2b7cSsoren }
2764578c8e4Stsutsui }
27741ba2b7cSsoren
278b0cd3c80Stsutsui void
crime_intr_mask(unsigned int intr)279b0cd3c80Stsutsui crime_intr_mask(unsigned int intr)
280b0cd3c80Stsutsui {
2814578c8e4Stsutsui uint64_t mask;
282b0cd3c80Stsutsui
28323020fc3Ssekiya mask = bus_space_read_8(crm_iot, crm_ioh, CRIME_INTMASK);
284b0cd3c80Stsutsui mask |= (1 << intr);
28523020fc3Ssekiya bus_space_write_8(crm_iot, crm_ioh, CRIME_INTMASK, mask);
286b0cd3c80Stsutsui }
28758a060c7Ssekiya
28858a060c7Ssekiya void
crime_intr_unmask(unsigned int intr)2898590eac4Ssekiya crime_intr_unmask(unsigned int intr)
2908590eac4Ssekiya {
2914578c8e4Stsutsui uint64_t mask;
2928590eac4Ssekiya
2938590eac4Ssekiya mask = bus_space_read_8(crm_iot, crm_ioh, CRIME_INTMASK);
2948590eac4Ssekiya mask &= ~(1 << intr);
2958590eac4Ssekiya bus_space_write_8(crm_iot, crm_ioh, CRIME_INTMASK, mask);
2968590eac4Ssekiya }
2978590eac4Ssekiya
2988590eac4Ssekiya void
crime_mem_reset(void)29925bb3b0eSmrg crime_mem_reset(void)
30025bb3b0eSmrg {
30125bb3b0eSmrg
30225bb3b0eSmrg bus_space_write_8(crm_iot, crm_ioh, CRIME_MEM_ERROR_STAT, 0);
30325bb3b0eSmrg }
30425bb3b0eSmrg
30525bb3b0eSmrg void
crime_cpu_reset(void)30625bb3b0eSmrg crime_cpu_reset(void)
30758a060c7Ssekiya {
3084578c8e4Stsutsui
30923020fc3Ssekiya bus_space_write_8(crm_iot, crm_ioh, CRIME_CPU_ERROR_STAT, 0);
31025bb3b0eSmrg }
31125bb3b0eSmrg
31225bb3b0eSmrg void
crime_bus_reset(void)31325bb3b0eSmrg crime_bus_reset(void)
31425bb3b0eSmrg {
31525bb3b0eSmrg
31625bb3b0eSmrg crime_mem_reset();
31725bb3b0eSmrg crime_cpu_reset();
31858a060c7Ssekiya }
31958a060c7Ssekiya
32023020fc3Ssekiya void
crime_watchdog_reset(void)32123020fc3Ssekiya crime_watchdog_reset(void)
32223020fc3Ssekiya {
3234578c8e4Stsutsui
324e1beb9f8Stsutsui #ifdef DISABLE_CRIME_WATCHDOG
32569a102c0Sjmcneill bus_space_write_8(crm_iot, crm_ioh, CRIME_WATCHDOG, 0);
32669a102c0Sjmcneill #else
32723020fc3Ssekiya /* enable watchdog timer, clear it */
32823020fc3Ssekiya bus_space_write_8(crm_iot, crm_ioh,
32923020fc3Ssekiya CRIME_CONTROL, CRIME_CONTROL_DOG_ENABLE);
33023020fc3Ssekiya bus_space_write_8(crm_iot, crm_ioh, CRIME_WATCHDOG, 0);
33169a102c0Sjmcneill #endif
33223020fc3Ssekiya }
33323020fc3Ssekiya
33423020fc3Ssekiya void
crime_watchdog_disable(void)33523020fc3Ssekiya crime_watchdog_disable(void)
33623020fc3Ssekiya {
3374578c8e4Stsutsui uint64_t reg;
33823020fc3Ssekiya
33923020fc3Ssekiya bus_space_write_8(crm_iot, crm_ioh, CRIME_WATCHDOG, 0);
34023020fc3Ssekiya reg = bus_space_read_8(crm_iot, crm_ioh, CRIME_CONTROL)
34123020fc3Ssekiya & ~CRIME_CONTROL_DOG_ENABLE;
34223020fc3Ssekiya bus_space_write_8(crm_iot, crm_ioh, CRIME_CONTROL, reg);
34323020fc3Ssekiya }
344c65071e6Smacallan
345c65071e6Smacallan void
crime_reboot(void)3464578c8e4Stsutsui crime_reboot(void)
347c65071e6Smacallan {
348c65071e6Smacallan
349c65071e6Smacallan bus_space_write_8(crm_iot, crm_ioh, CRIME_CONTROL,
350c65071e6Smacallan CRIME_CONTROL_HARD_RESET);
3514578c8e4Stsutsui for (;;)
3524578c8e4Stsutsui ;
353c65071e6Smacallan }
354