1 /* $NetBSD: ka6400.c,v 1.21 2022/03/03 06:28:26 riastradh Exp $ */ 2 3 /* 4 * Copyright (c) 2000 Ludd, University of Lule}, Sweden. 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 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 /* 28 * KA6400 specific CPU code. 29 */ 30 /* 31 * TODO: 32 * - Machine check code 33 * - Vector processor code 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: ka6400.c,v 1.21 2022/03/03 06:28:26 riastradh Exp $"); 38 39 #include "opt_multiprocessor.h" 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/bus.h> 44 #include <sys/cpu.h> 45 #include <sys/device.h> 46 #include <sys/kernel.h> 47 #include <sys/time.h> 48 49 #include <machine/ka670.h> 50 #include <machine/nexus.h> 51 #include <machine/clock.h> 52 #include <machine/scb.h> 53 #include <machine/sid.h> 54 #include <machine/cca.h> 55 #include <machine/rpb.h> 56 57 #include <dev/xmi/xmireg.h> 58 #include <dev/xmi/xmivar.h> 59 60 #include "ioconf.h" 61 #include "locators.h" 62 63 static int *rssc; 64 struct cca *cca; 65 int mastercpu; 66 67 static int ka6400_match(device_t , cfdata_t, void *); 68 static void ka6400_attach(device_t , device_t , void*); 69 static void ka6400_memerr(void); 70 static void ka6400_conf(void); 71 static int ka6400_mchk(void *); 72 static void ka6400_steal_pages(void); 73 74 static const char * const ka6400_devs[] = { "xmi", NULL }; 75 76 const struct cpu_dep ka6400_calls = { 77 .cpu_steal_pages = ka6400_steal_pages, 78 .cpu_mchk = ka6400_mchk, 79 .cpu_memerr = ka6400_memerr, 80 .cpu_conf = ka6400_conf, 81 .cpu_gettime = generic_gettime, 82 .cpu_settime = generic_settime, 83 .cpu_vups = 12, /* ~VUPS */ 84 .cpu_scbsz = 16, /* SCB pages */ 85 }; 86 87 #if defined(MULTIPROCESSOR) 88 static void ka6400_startslave(struct cpu_info *); 89 static void ka6400_txrx(int, const char *, ...) __printflike(2, 3); 90 static void ka6400_sendstr(int, const char *); 91 static void ka6400_sergeant(int); 92 static int rxchar(void); 93 static void ka6400_putc(int); 94 static void ka6400_cnintr(void); 95 96 #include <dev/cons.h> 97 #include <vax/vax/gencons.h> 98 cons_decl(gen); 99 100 const struct cpu_mp_dep ka6400_mp_calls = { 101 .cpu_startslave = ka6400_startslave, 102 .cpu_cnintr = ka6400_cnintr, 103 }; 104 #endif 105 106 CFATTACH_DECL_NEW(cpu_xmi, 0, 107 ka6400_match, ka6400_attach, NULL, NULL); 108 109 static int 110 ka6400_match(device_t parent, cfdata_t cf, void *aux) 111 { 112 struct xmi_attach_args * const xa = aux; 113 114 if (bus_space_read_2(xa->xa_iot, xa->xa_ioh, XMI_TYPE) != XMIDT_KA64) 115 return 0; 116 117 if (cf->cf_loc[XMICF_NODE] != XMICF_NODE_DEFAULT && 118 cf->cf_loc[XMICF_NODE] != xa->xa_nodenr) 119 return 0; 120 121 return 1; 122 } 123 124 static void 125 ka6400_attach(device_t parent, device_t self, void *aux) 126 { 127 struct cpu_info *ci; 128 struct xmi_attach_args * const xa = aux; 129 int vp; 130 131 vp = (cca->cca_vecenab & (1 << xa->xa_nodenr)); 132 aprint_normal("\n"); 133 aprint_normal_dev(self, "KA6400 (%s) rev %d%s\n", 134 mastercpu == xa->xa_nodenr ? "master" : "slave", 135 bus_space_read_4(xa->xa_iot, xa->xa_ioh, XMI_TYPE) >> 16, 136 (vp ? ", vector processor present" : "")); 137 138 if (xa->xa_nodenr != mastercpu) { 139 #if defined(MULTIPROCESSOR) 140 v_putc = ka6400_putc; /* Need special console handling */ 141 cpu_slavesetup(self, xa->xa_nodenr); 142 #endif 143 return; 144 } 145 146 mtpr(0, PR_VPSR); /* Can't use vector processor */ 147 148 ci = curcpu(); 149 device_set_private(self, ci); 150 ci->ci_dev = self; 151 ci->ci_cpuid = device_unit(self); 152 ci->ci_slotid = xa->xa_nodenr; 153 } 154 155 void 156 ka6400_conf(void) 157 { 158 int mapaddr; 159 160 rssc = (void *)vax_map_physmem(RSSC_ADDR, 1); 161 mastercpu = rssc[RSSC_IPORT/4] & 15; 162 mapaddr = (cca ? (int)cca : rpb.cca_addr); 163 cca = (void *)vax_map_physmem(mapaddr, vax_btoc(sizeof(struct cca))); 164 } 165 166 /* 167 * MS62 support. 168 * This code should: 169 * 1: Be completed. 170 * 2: (eventually) move to dev/xmi/; it is used by Mips also. 171 */ 172 #define MEMRD(reg) bus_space_read_4(sc->sc_iot, sc->sc_ioh, (reg)) 173 #define MEMWR(reg, val) bus_space_write_4(sc->sc_iot, sc->sc_ioh, (reg), (val)) 174 175 #define MS62_TYPE 0 176 #define MS62_XBE 4 177 #define MS62_SEADR 16 178 #define MS62_CTL1 20 179 #define MS62_ECCERR 24 180 #define MS62_ECCEA 28 181 #define MS62_ILK0 32 182 #define MS62_ILK1 36 183 #define MS62_ILK2 40 184 #define MS62_ILK3 44 185 #define MS62_CTL2 48 186 187 static int ms6400_match(device_t , cfdata_t, void *); 188 static void ms6400_attach(device_t , device_t , void*); 189 190 struct mem_xmi_softc { 191 device_t sc_dev; 192 bus_space_tag_t sc_iot; 193 bus_space_handle_t sc_ioh; 194 }; 195 196 CFATTACH_DECL_NEW(mem_xmi, sizeof(struct mem_xmi_softc), 197 ms6400_match, ms6400_attach, NULL, NULL); 198 199 static int 200 ms6400_match(device_t parent, cfdata_t cf, void *aux) 201 { 202 struct xmi_attach_args * const xa = aux; 203 204 if (bus_space_read_2(xa->xa_iot, xa->xa_ioh, XMI_TYPE) != XMIDT_MS62) 205 return 0; 206 207 if (cf->cf_loc[XMICF_NODE] != XMICF_NODE_DEFAULT && 208 cf->cf_loc[XMICF_NODE] != xa->xa_nodenr) 209 return 0; 210 211 return 1; 212 } 213 214 static void 215 ms6400_attach(device_t parent, device_t self, void *aux) 216 { 217 struct mem_xmi_softc * const sc = device_private(self); 218 struct xmi_attach_args * const xa = aux; 219 220 sc->sc_dev = self; 221 sc->sc_iot = xa->xa_iot; 222 sc->sc_ioh = xa->xa_ioh; 223 aprint_normal(": MS62, rev %d, size 32MB\n", MEMRD(MS62_TYPE) >> 16); 224 } 225 226 static void 227 ka6400_memerr(void) 228 { 229 printf("ka6400_memerr\n"); 230 } 231 232 struct mc6400frame { 233 int mc64_summary; /* summary parameter */ 234 int mc64_va; /* va register */ 235 int mc64_vb; /* memory address */ 236 int mc64_sisr; /* status word */ 237 int mc64_state; /* error pc */ 238 int mc64_sc; /* micro pc */ 239 int mc64_pc; /* current pc */ 240 int mc64_psl; /* current psl */ 241 }; 242 243 static int 244 ka6400_mchk(void *cmcf) 245 { 246 return (MCHK_PANIC); 247 } 248 249 #if defined(MULTIPROCESSOR) 250 #define RXBUF 80 251 static char rxbuf[RXBUF]; 252 static int got = 0, taken = 0; 253 static int expect = 0; 254 #endif 255 #if 0 256 /* 257 * Receive a character from logical console. 258 */ 259 static void 260 rxcdintr(void *arg) 261 { 262 int c = mfpr(PR_RXCD); 263 264 if (c == 0) 265 return; 266 267 #if defined(MULTIPROCESSOR) 268 if ((c & 0xff) == 0) { 269 if (curcpu()->ci_flags & CI_MASTERCPU) 270 ka6400_cnintr(); 271 return; 272 } 273 274 if (expect == ((c >> 8) & 0xf)) 275 rxbuf[got++] = c & 0xff; 276 277 if (got == RXBUF) 278 got = 0; 279 #endif 280 } 281 #endif 282 283 /* 284 * From ka670, which has the same cache structure. 285 */ 286 static void 287 ka6400_enable_cache(void) 288 { 289 mtpr(KA670_PCS_REFRESH, PR_PCSTS); /* disable primary cache */ 290 mtpr(mfpr(PR_PCSTS), PR_PCSTS); /* clear error flags */ 291 mtpr(8, PR_BCCTL); /* disable backup cache */ 292 mtpr(0, PR_BCFBTS); /* flush backup cache tag store */ 293 mtpr(0, PR_BCFPTS); /* flush primary cache tag store */ 294 mtpr(0x0e, PR_BCCTL); /* enable backup cache */ 295 mtpr(KA670_PCS_FLUSH | KA670_PCS_REFRESH, PR_PCSTS); /* flush primary cache */ 296 mtpr(KA670_PCS_ENABLE | KA670_PCS_REFRESH, PR_PCSTS); /* flush primary cache */ 297 } 298 299 void 300 ka6400_steal_pages(void) 301 { 302 int i, ncpus; 303 304 ka6400_enable_cache(); /* Turn on cache early */ 305 if (cca == 0) 306 cca = (void *)rpb.cca_addr; 307 /* Is there any way to get number of CPUs easier??? */ 308 for (i = ncpus = 0; i < cca->cca_maxcpu; i++) 309 if (cca->cca_console & (1 << i)) 310 ncpus++; 311 cpu_setmodel("VAX 6000/4%x0", ncpus + 1); 312 } 313 314 315 #if defined(MULTIPROCESSOR) 316 int 317 rxchar(void) 318 { 319 int ret; 320 321 if (got == taken) 322 return 0; 323 324 ret = rxbuf[taken++]; 325 if (taken == RXBUF) 326 taken = 0; 327 return ret; 328 } 329 330 static void 331 ka6400_startslave(struct cpu_info *ci) 332 { 333 const struct pcb *pcb = lwp_getpcb(ci->ci_onproc); 334 const int id = ci->ci_slotid; 335 int i; 336 337 expect = id; 338 /* First empty queue */ 339 for (i = 0; i < 10000; i++) 340 if (rxchar()) 341 i = 0; 342 ka6400_txrx(id, "\020"); /* Send ^P to get attention */ 343 ka6400_txrx(id, "I\r"); /* Init other end */ 344 ka6400_txrx(id, "D/I 4 %x\r", ci->ci_istack); /* Interrupt stack */ 345 ka6400_txrx(id, "D/I C %x\r", mfpr(PR_SBR)); /* SBR */ 346 ka6400_txrx(id, "D/I D %x\r", mfpr(PR_SLR)); /* SLR */ 347 ka6400_txrx(id, "D/I 10 %x\r", pcb->pcb_paddr); /* PCB for idle proc */ 348 ka6400_txrx(id, "D/I 11 %x\r", mfpr(PR_SCBB)); /* SCB */ 349 ka6400_txrx(id, "D/I 38 %x\r", mfpr(PR_MAPEN)); /* Enable MM */ 350 ka6400_txrx(id, "S %x\r", (int)&vax_mp_tramp); /* Start! */ 351 expect = 0; 352 for (i = 0; i < 10000; i++) 353 if (ci->ci_flags & CI_RUNNING) 354 break; 355 if (i == 10000) 356 aprint_error_dev(ci->ci_dev, "(ID %d) failed starting!\n", id); 357 } 358 359 void 360 ka6400_txrx(int id, const char *fmt, ...) 361 { 362 char buf[20]; 363 va_list ap; 364 365 va_start(ap, fmt); 366 vsnprintf(buf, sizeof(buf), fmt, ap); 367 va_end(ap); 368 369 ka6400_sendstr(id, buf); 370 ka6400_sergeant(id); 371 } 372 373 void 374 ka6400_sendstr(int id, const char *buf) 375 { 376 u_int utchr; 377 int ch, i; 378 379 while (*buf) { 380 utchr = *buf | id << 8; 381 382 /* 383 * It seems like mtpr to TXCD sets the V flag if it fails. 384 * Cannot check that flag in C... 385 */ 386 __asm("1:;mtpr %0,$92;bvs 1b" :: "g"(utchr)); 387 buf++; 388 i = 30000; 389 while ((ch = rxchar()) == 0 && --i) 390 ; 391 if (ch == 0) 392 continue; /* failed */ 393 } 394 } 395 396 void 397 ka6400_sergeant(int id) 398 { 399 int i, ch, nserg; 400 401 nserg = 0; 402 for (i = 0; i < 30000; i++) { 403 if ((ch = rxchar()) == 0) 404 continue; 405 if (ch == '>') 406 nserg++; 407 else 408 nserg = 0; 409 i = 0; 410 if (nserg == 3) 411 break; 412 } 413 /* What to do now??? */ 414 } 415 416 /* 417 * Write to master console. 418 * Need no locking here; done in the print functions. 419 */ 420 static volatile int ch = 0; 421 422 void 423 ka6400_putc(int c) 424 { 425 if (curcpu()->ci_flags & CI_MASTERCPU) { 426 gencnputc(0, c); 427 return; 428 } 429 ch = c; 430 mtpr(mastercpu << 8, PR_RXCD); /* Send IPI to mastercpu */ 431 while (ch != 0) 432 ; /* Wait for master to handle */ 433 } 434 435 /* 436 * Got character IPI. 437 */ 438 void 439 ka6400_cnintr(void) 440 { 441 if (ch != 0) 442 gencnputc(0, ch); 443 ch = 0; /* Release slavecpu */ 444 } 445 #endif 446