1/*	$NetBSD: ka650.c,v 1.39 2024/02/21 23:23:06 andvar Exp $	*/
2/*
3 * Copyright (c) 1988 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Mt. Xinu.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *	@(#)ka650.c	7.7 (Berkeley) 12/16/90
34 */
35
36/*
37 * vax650-specific code.
38 */
39
40#include <sys/cdefs.h>
41__KERNEL_RCSID(0, "$NetBSD: ka650.c,v 1.39 2024/02/21 23:23:06 andvar Exp $");
42
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/cpu.h>
46#include <sys/device.h>
47#include <sys/kernel.h>
48#include <sys/time.h>
49
50#include <machine/ka650.h>
51#include <machine/clock.h>
52#include <machine/sid.h>
53
54struct	ka650_merr *ka650merr_ptr;
55struct	ka650_cbd *ka650cbd_ptr;
56struct	ka650_ssc *ka650ssc_ptr;
57struct	ka650_ipcr *ka650ipcr_ptr;
58int	*KA650_CACHE_ptr;
59
60#define	CACHEOFF	0
61#define	CACHEON		1
62
63static	void	ka650setcache(int);
64static	void	ka650_halt(void);
65static	void	ka650_reboot(int);
66static	void    ka650_conf(void);
67static	void    ka650_memerr(void);
68static	int     ka650_mchk(void *);
69static	void	ka650_attach_cpu(device_t);
70
71static const char * const ka650_devs[] = { "cpu", "lance", "uba", NULL };
72
73const struct cpu_dep ka650_calls = {
74	.cpu_mchk	= ka650_mchk,
75	.cpu_memerr	= ka650_memerr,
76	.cpu_conf	= ka650_conf,
77	.cpu_gettime	= generic_gettime,
78	.cpu_settime	= generic_settime,
79	.cpu_vups	= 4,      /* ~VUPS */
80	.cpu_scbsz	= 2,	/* SCB pages */
81	.cpu_halt	= ka650_halt,
82	.cpu_reboot	= ka650_reboot,
83	.cpu_devs	= ka650_devs,
84	.cpu_attach_cpu	= ka650_attach_cpu,
85	.cpu_flags	= CPU_RAISEIPL,	/* Needed for the LANCE chip */
86};
87
88/*
89 * ka650_conf() is called by cpu_attach to do the cpu_specific setup.
90 */
91void
92ka650_conf(void)
93{
94
95	/*
96	 * MicroVAX III: We map in memory error registers,
97	 * cache control registers, SSC registers,
98	 * interprocessor registers and cache diag space.
99	 */
100	ka650merr_ptr = (void *)vax_map_physmem(KA650_MERR, 1);
101	ka650cbd_ptr = (void *)vax_map_physmem(KA650_CBD, 1);
102	ka650ssc_ptr = (void *)vax_map_physmem(KA650_SSC, 3);
103	ka650ipcr_ptr = (void *)vax_map_physmem(KA650_IPCR, 1);
104	KA650_CACHE_ptr = (void *)vax_map_physmem(KA650_CACHE,
105	    (KA650_CACHESIZE/VAX_NBPG));
106
107	ka650setcache(CACHEON);
108	if (ctob(physmem) > ka650merr_ptr->merr_qbmbr) {
109		printf("physmem(0x%"PRIxPSIZE") > qbmbr(0x%x)\n",
110		    ctob(physmem), (int)ka650merr_ptr->merr_qbmbr);
111		panic("qbus map unprotected");
112	}
113	if (mfpr(PR_TODR) == 0)
114		mtpr(1, PR_TODR);
115}
116
117void
118ka650_attach_cpu(device_t self)
119{
120	int syssub = GETSYSSUBT(vax_siedata);
121
122	aprint_normal(": KA6%d%d, CVAX microcode rev %d Firmware rev %d\n",
123	    syssub == VAX_SIE_KA640 ? 4 : 5,
124	    syssub == VAX_SIE_KA655 ? 5 : 0,
125	    (vax_cpudata & 0xff), GETFRMREV(vax_siedata));
126}
127
128void
129ka650_memerr(void)
130{
131	printf("memory err!\n");
132#if 0 /* XXX Fix this */
133	char *cp = NULL;
134	int m;
135	extern u_int cache2tag;
136
137	if (ka650cbd.cbd_cacr & CACR_CPE) {
138		printf("cache 2 tag parity error: ");
139		if (time.tv_sec - cache2tag < 7) {
140			ka650setcache(CACHEOFF);
141			printf("cacheing disabled\n");
142		} else {
143			cache2tag = time.tv_sec;
144			printf("flushing cache\n");
145			ka650setcache(CACHEON);
146		}
147	}
148	m = ka650merr.merr_errstat;
149	ka650merr.merr_errstat = MEM_EMASK;
150	if (m & MEM_CDAL) {
151		cp = "Bus Parity";
152	} else if (m & MEM_RDS) {
153		cp = "Hard ECC";
154	} else if (m & MEM_CRD) {
155		cp = "Soft ECC";
156	}
157	if (cp) {
158		printf("%sMemory %s Error: page 0x%x\n",
159			(m & MEM_DMA) ? "DMA " : "", cp,
160			(m & MEM_PAGE) >> MEM_PAGESHFT);
161	}
162#endif
163}
164
165#define NMC650	15
166const char * const mc650[] = {
167	0,			"FPA proto err",	"FPA resv inst",
168	"FPA Ill Stat 2",	"FPA Ill Stat 1",	"PTE in P0, TB miss",
169	"PTE in P1, TB miss",	"PTE in P0, Mod",	"PTE in P1, Mod",
170	"Illegal intr IPL",	"MOVC state error",	"bus read error",
171	"SCB read error",	"bus write error",	"PCB write error"
172};
173u_int	cache1tag;
174u_int	cache1data;
175u_int	cdalerr;
176u_int	cache2tag;
177
178struct mc650frame {
179	int	mc65_bcnt;		/* byte count == 0xc */
180	int	mc65_summary;		/* summary parameter */
181	int	mc65_mrvaddr;		/* most recent vad */
182	int	mc65_istate1;		/* internal state */
183	int	mc65_istate2;		/* internal state */
184	int	mc65_pc;		/* trapped pc */
185	int	mc65_psl;		/* trapped psl */
186};
187
188int
189ka650_mchk(void *cmcf)
190{
191	struct mc650frame *mcf = (struct mc650frame *)cmcf;
192	u_int type = mcf->mc65_summary;
193	u_int i;
194	char sbuf[256];
195
196	printf("machine check %x", type);
197	if (type >= 0x80 && type <= 0x83)
198		type -= (0x80 + 11);
199	if (type < NMC650 && mc650[type])
200		printf(": %s", mc650[type]);
201	printf("\n\tvap %x istate1 %x istate2 %x pc %x psl %x\n",
202	    mcf->mc65_mrvaddr, mcf->mc65_istate1, mcf->mc65_istate2,
203	    mcf->mc65_pc, mcf->mc65_psl);
204	snprintb(sbuf, sizeof(sbuf), DMASER_BITS, ka650merr_ptr->merr_dser);
205	printf("dmaser=%s qbear=0x%x dmaear=0x%x\n", sbuf,
206	    (int)ka650merr_ptr->merr_qbear,
207	    (int)ka650merr_ptr->merr_dear);
208	ka650merr_ptr->merr_dser = DSER_CLEAR;
209
210	i = mfpr(PR_CAER);
211	mtpr(CAER_MCC | CAER_DAT | CAER_TAG, PR_CAER);
212	if (i & CAER_MCC) {
213		printf("cache 1 ");
214		if (i & CAER_DAT) {
215			printf("data");
216			i = cache1data;
217			cache1data = time_second;
218		}
219		if (i & CAER_TAG) {
220			printf("tag");
221			i = cache1tag;
222			cache1tag = time_second;
223		}
224	} else if ((i & CAER_MCD) || (ka650merr_ptr->merr_errstat & MEM_CDAL)) {
225		printf("CDAL");
226		i = cdalerr;
227		cdalerr = time_second;
228	}
229	if (time_second - i < 7) {
230		ka650setcache(CACHEOFF);
231		printf(" parity error:	cacheing disabled\n");
232	} else {
233		printf(" parity error:	flushing cache\n");
234		ka650setcache(CACHEON);
235	}
236	/*
237	 * May be able to recover if type is 1-4, 0x80 or 0x81, but
238	 * only if FPD is set in the saved PSL, or bit VCR in Istate2
239	 * is clear.
240	 */
241	if ((type > 0 && type < 5) || type == 11 || type == 12) {
242		if ((mcf->mc65_psl & PSL_FPD)
243		    || !(mcf->mc65_istate2 & IS2_VCR)) {
244			ka650_memerr();
245			return 0;
246		}
247	}
248	return -1;
249}
250
251/*
252 * Make sure both caches are off and not in diagnostic mode.  Clear the
253 * 2nd level cache (by writing to each quadword entry), then enable it.
254 * Enable 1st level cache too.
255 */
256void
257ka650setcache(int state)
258{
259	int syssub = GETSYSSUBT(vax_siedata);
260	int i;
261
262	/*
263	 * Before doing anything, disable the cache.
264	 */
265	mtpr(0, PR_CADR);
266	if (syssub != VAX_SIE_KA640)
267		ka650cbd_ptr->cbd_cacr = CACR_CPE;
268
269	/*
270	 * Check what we want to do, enable or disable.
271	 */
272	if (state == CACHEON) {
273		mtpr(CADR_SEN2 | CADR_SEN1 | CADR_CENI | CADR_CEND, PR_CADR);
274		if (syssub != VAX_SIE_KA640) {
275			for (i = 0;
276			    i < (KA650_CACHESIZE / sizeof(KA650_CACHE_ptr[0]));
277			    i += 2)
278				KA650_CACHE_ptr[i] = 0;
279			ka650cbd_ptr->cbd_cacr = CACR_CEN;
280		}
281	}
282}
283
284void
285ka650_halt(void)
286{
287	ka650ssc_ptr->ssc_cpmbx = CPMB650_DOTHIS | CPMB650_HALT;
288	__asm("halt");
289}
290
291void
292ka650_reboot(int arg)
293{
294	ka650ssc_ptr->ssc_cpmbx = CPMB650_DOTHIS | CPMB650_REBOOT;
295}
296