1 /* $NetBSD: ka88.c,v 1.20 2019/12/01 15:34:46 ad 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 * KA88 specific CPU code. 29 */ 30 /* 31 * TODO: 32 * - Machine check code 33 */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: ka88.c,v 1.20 2019/12/01 15:34:46 ad Exp $"); 37 38 #include "opt_multiprocessor.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/bus.h> 43 #include <sys/cpu.h> 44 #include <sys/device.h> 45 #include <sys/kernel.h> 46 #include <sys/malloc.h> 47 #include <sys/lwp.h> 48 49 #include <machine/nexus.h> 50 #include <machine/clock.h> 51 #include <machine/scb.h> 52 #include <machine/sid.h> 53 #include <machine/rpb.h> 54 #include <machine/ka88.h> 55 56 #include <dev/cons.h> 57 #include <vax/vax/gencons.h> 58 59 #include "ioconf.h" 60 #include "locators.h" 61 62 static void ka88_memerr(void); 63 static void ka88_conf(void); 64 static int ka88_mchk(void *); 65 static void ka88_steal_pages(void); 66 static int ka88_gettime(volatile struct timeval *); 67 static void ka88_settime(volatile struct timeval *); 68 static void ka88_badaddr(void); 69 70 static long *ka88_mcl; 71 static int mastercpu; 72 73 static const char * const ka88_devs[] = { "nmi", NULL }; 74 75 const struct cpu_dep ka88_calls = { 76 .cpu_steal_pages = ka88_steal_pages, 77 .cpu_mchk = ka88_mchk, 78 .cpu_memerr = ka88_memerr, 79 .cpu_conf = ka88_conf, 80 .cpu_gettime = ka88_gettime, 81 .cpu_settime = ka88_settime, 82 .cpu_vups = 6, /* ~VUPS */ 83 .cpu_scbsz = 64, /* SCB pages */ 84 .cpu_devs = ka88_devs, 85 .cpu_badaddr = ka88_badaddr, 86 }; 87 88 #if defined(MULTIPROCESSOR) 89 static void ka88_startslave(struct cpu_info *); 90 static void ka88_txrx(int, const char *, ...) __printflike(2, 3); 91 static void ka88_sendstr(int, const char *); 92 static void ka88_sergeant(int); 93 static int rxchar(void); 94 static void ka88_putc(int); 95 static void ka88_cnintr(void); 96 cons_decl(gen); 97 98 const struct cpu_mp_dep ka88_mp_calls = { 99 .cpu_startslave = ka88_startslave, 100 .cpu_cnintr = ka88_cnintr, 101 }; 102 #endif 103 104 static void 105 ka88_conf(void) 106 { 107 ka88_mcl = (void *)vax_map_physmem(0x3e000000, 1); 108 printf("Serial number %d, rev %d\n", 109 mfpr(PR_SID) & 65535, (mfpr(PR_SID) >> 16) & 127); 110 #ifdef MULTIPROCESSOR 111 mp_dep_call = &ka88_mp_calls; 112 #endif 113 } 114 115 static int 116 ka88_cpu_match(device_t parent, cfdata_t cf, void *aux) 117 { 118 struct nmi_attach_args * const na = aux; 119 120 if (cf->cf_loc[NMICF_SLOT] != NMICF_SLOT_DEFAULT && 121 cf->cf_loc[NMICF_SLOT] != na->na_slot) 122 return 0; 123 if (na->na_slot >= 20) 124 return 1; 125 return 0; 126 } 127 128 static void 129 ka88_cpu_attach(device_t parent, device_t self, void *aux) 130 { 131 struct cpu_info *ci; 132 struct nmi_attach_args * const na = aux; 133 const char *ms, *lr; 134 const bool master = (na->na_slot == mastercpu); 135 136 if (((ka88_confdata & KA88_LEFTPRIM) && master) || 137 ((ka88_confdata & KA88_LEFTPRIM) == 0 && !master)) 138 lr = "left"; 139 else 140 lr = "right"; 141 ms = (master ? "master" : "slave"); 142 143 aprint_normal(": KA88 %s %s\n", lr, ms); 144 if (!master) { 145 #if defined(MULTIPROCESSOR) 146 v_putc = ka88_putc; /* Need special console handling */ 147 cpu_slavesetup(self, na->na_slot); 148 #endif 149 return; 150 } 151 ci = curcpu(); 152 self->dv_private = ci; 153 ci->ci_dev = self; 154 ci->ci_cpuid = device_unit(self); 155 ci->ci_slotid = na->na_slot; 156 } 157 158 CFATTACH_DECL_NEW(cpu_nmi, 0, 159 ka88_cpu_match, ka88_cpu_attach, NULL, NULL); 160 161 struct mem_nmi_softc { 162 device_t sc_dev; 163 bus_space_tag_t sc_iot; 164 bus_space_handle_t sc_ioh; 165 }; 166 167 static int 168 ms88_match(device_t parent, cfdata_t cf, void *aux) 169 { 170 struct nmi_attach_args * const na = aux; 171 172 if (cf->cf_loc[NMICF_SLOT] != NMICF_SLOT_DEFAULT && 173 cf->cf_loc[NMICF_SLOT] != na->na_slot) 174 return 0; 175 if (na->na_slot != 10) 176 return 0; 177 return 1; 178 } 179 180 static void 181 ms88_attach(device_t parent, device_t self, void *aux) 182 { 183 struct nmi_attach_args * const na = aux; 184 struct mem_nmi_softc * const sc = device_private(self); 185 186 aprint_normal("\n"); 187 188 sc->sc_dev = self; 189 sc->sc_iot = na->na_iot; 190 } 191 192 CFATTACH_DECL_NEW(mem_nmi, sizeof(struct mem_nmi_softc), 193 ms88_match, ms88_attach, NULL, NULL); 194 195 static void 196 ka88_badaddr(void) 197 { 198 volatile int hej; 199 /* 200 * This is some magic to clear the NMI faults, described 201 * in section 7.9 in the VAX 8800 System Maintenance Guide. 202 */ 203 hej = ka88_mcl[5]; 204 hej = ka88_mcl[0]; 205 ka88_mcl[0] = 0x04000000; 206 mtpr(1, 0x88); 207 } 208 209 static void 210 ka88_memerr(void) 211 { 212 printf("ka88_memerr\n"); 213 } 214 215 struct mc88frame { 216 int mc64_summary; /* summary parameter */ 217 int mc64_va; /* va register */ 218 int mc64_vb; /* memory address */ 219 int mc64_sisr; /* status word */ 220 int mc64_state; /* error pc */ 221 int mc64_sc; /* micro pc */ 222 int mc64_pc; /* current pc */ 223 int mc64_psl; /* current psl */ 224 }; 225 226 static int 227 ka88_mchk(void *cmcf) 228 { 229 return (MCHK_PANIC); 230 } 231 232 #if defined(MULTIPROCESSOR) 233 #define RXBUF 80 234 static char rxbuf[RXBUF]; 235 static int got = 0, taken = 0; 236 static int expect = 0; 237 #endif 238 #if 0 239 /* 240 * Receive a character from logical console. 241 */ 242 static void 243 rxcdintr(void *arg) 244 { 245 int c = mfpr(PR_RXCD); 246 247 if (c == 0) 248 return; 249 250 #if defined(MULTIPROCESSOR) 251 if ((c & 0xff) == 0) { 252 if (curcpu()->ci_flags & CI_MASTERCPU) 253 ka88_cnintr(); 254 return; 255 } 256 257 if (expect == ((c >> 8) & 0xf)) 258 rxbuf[got++] = c & 0xff; 259 260 if (got == RXBUF) 261 got = 0; 262 #endif 263 } 264 #endif 265 266 static void 267 tocons(int val) 268 { 269 int s = splhigh(); 270 271 while ((mfpr(PR_TXCS) & GC_RDY) == 0) /* Wait until xmit ready */ 272 ; 273 mtpr(val, PR_TXDB); /* xmit character */ 274 splx(s); 275 } 276 277 static int 278 fromcons(int func) 279 { 280 int ret, s = splhigh(); 281 282 while (1) { 283 while ((mfpr(PR_RXCS) & GC_DON) == 0) 284 ; 285 ret = mfpr(PR_RXDB); 286 if ((ret & 0xf00) == func) 287 break; 288 } 289 splx(s); 290 return ret; 291 } 292 293 static int 294 ka88_gettime(volatile struct timeval *tvp) 295 { 296 union {u_int ret;u_char r[4];} u; 297 int i, s = splhigh(); 298 299 tocons(KA88_COMM|KA88_TOYREAD); 300 for (i = 0; i < 4; i++) { 301 u.r[i] = fromcons(KA88_TOY) & 255; 302 } 303 splx(s); 304 tvp->tv_sec = u.ret; 305 return 0; 306 } 307 308 static void 309 ka88_settime(volatile struct timeval *tvp) 310 { 311 union {u_int ret;u_char r[4];} u; 312 int i, s = splhigh(); 313 314 u.ret = tvp->tv_sec - yeartonum(numtoyear(tvp->tv_sec)); 315 tocons(KA88_COMM|KA88_TOYWRITE); 316 for (i = 0; i < 4; i++) 317 tocons(KA88_TOY|u.r[i]); 318 splx(s); 319 } 320 321 void 322 ka88_steal_pages(void) 323 { 324 char c = '0', d = '0'; 325 mtpr(1, PR_COR); /* Cache on */ 326 tocons(KA88_COMM|KA88_GETCONF); 327 ka88_confdata = fromcons(KA88_CONFDATA); 328 ka88_confdata = mfpr(PR_RXDB); 329 mastercpu = 20; 330 if (vax_cputype == VAX_TYP_8NN) { 331 if (ka88_confdata & KA88_SMALL) { 332 c = '5'; 333 if (ka88_confdata & KA88_SLOW) { 334 vax_boardtype = VAX_BTYP_8500; 335 d = '3'; 336 } else { 337 vax_boardtype = VAX_BTYP_8550; 338 d = '5'; 339 } 340 } else if (ka88_confdata & KA88_SINGLE) { 341 vax_boardtype = VAX_BTYP_8700; 342 c = '7'; 343 } 344 } 345 cpu_setmodel("VAX 88%c%c", c, d); 346 } 347 348 349 #if defined(MULTIPROCESSOR) 350 int 351 rxchar(void) 352 { 353 int ret; 354 355 if (got == taken) 356 return 0; 357 358 ret = rxbuf[taken++]; 359 if (taken == RXBUF) 360 taken = 0; 361 return ret; 362 } 363 364 static void 365 ka88_startslave(struct cpu_info *ci) 366 { 367 const struct pcb *pcb = lwp_getpcb(ci->ci_onproc); 368 const int id = ci->ci_slotid; 369 int i; 370 371 expect = id; 372 /* First empty queue */ 373 for (i = 0; i < 10000; i++) 374 if (rxchar()) 375 i = 0; 376 ka88_txrx(id, "\020"); /* Send ^P to get attention */ 377 ka88_txrx(id, "I\r"); /* Init other end */ 378 ka88_txrx(id, "D/I 4 %x\r", ci->ci_istack); /* Interrupt stack */ 379 ka88_txrx(id, "D/I C %x\r", mfpr(PR_SBR)); /* SBR */ 380 ka88_txrx(id, "D/I D %x\r", mfpr(PR_SLR)); /* SLR */ 381 ka88_txrx(id, "D/I 10 %x\r", pcb->pcb_paddr); /* PCB for idle proc */ 382 ka88_txrx(id, "D/I 11 %x\r", mfpr(PR_SCBB)); /* SCB */ 383 ka88_txrx(id, "D/I 38 %x\r", mfpr(PR_MAPEN)); /* Enable MM */ 384 ka88_txrx(id, "S %x\r", (int)&vax_mp_tramp); /* Start! */ 385 expect = 0; 386 for (i = 0; i < 10000; i++) 387 if (ci->ci_flags & CI_RUNNING) 388 break; 389 if (i == 10000) 390 aprint_error_dev(ci->ci_dev, "(ID %d) failed starting!!\n", id); 391 } 392 393 static void 394 ka88_txrx(int id, const char *fmt, ...) 395 { 396 char buf[20]; 397 va_list ap; 398 399 va_start(ap, fmt); 400 vsnprintf(buf, sizeof(buf), fmt, ap); 401 va_end(ap); 402 ka88_sendstr(id, buf); 403 ka88_sergeant(id); 404 } 405 406 void 407 ka88_sendstr(int id, const char *buf) 408 { 409 u_int utchr; /* Ends up in R11 with PCC */ 410 int ch, i; 411 412 while (*buf) { 413 utchr = *buf | id << 8; 414 415 /* 416 * It seems like mtpr to TXCD sets the V flag if it fails. 417 * Cannot check that flag in C... 418 */ 419 #ifdef __GNUC__ 420 __asm("1:;mtpr %0,$92;bvs 1b" :: "g"(utchr)); 421 #else 422 __asm("1:;mtpr r11,$92;bvs 1b"); 423 #endif 424 buf++; 425 i = 30000; 426 while ((ch = rxchar()) == 0 && --i) 427 ; 428 if (ch == 0) 429 continue; /* failed */ 430 } 431 } 432 433 void 434 ka88_sergeant(int id) 435 { 436 int i, ch, nserg; 437 438 nserg = 0; 439 for (i = 0; i < 30000; i++) { 440 if ((ch = rxchar()) == 0) 441 continue; 442 if (ch == '>') 443 nserg++; 444 else 445 nserg = 0; 446 i = 0; 447 if (nserg == 3) 448 break; 449 } 450 /* What to do now??? */ 451 } 452 453 /* 454 * Write to master console. 455 * Need no locking here; done in the print functions. 456 */ 457 static volatile int ch = 0; 458 459 void 460 ka88_putc(int c) 461 { 462 if (curcpu()->ci_flags & CI_MASTERCPU) { 463 gencnputc(0, c); 464 return; 465 } 466 ch = c; 467 mtpr(mastercpu << 8, PR_RXCD); /* Send IPI to mastercpu */ 468 while (ch != 0) 469 ; /* Wait for master to handle */ 470 } 471 472 /* 473 * Got character IPI. 474 */ 475 void 476 ka88_cnintr(void) 477 { 478 if (ch != 0) 479 gencnputc(0, ch); 480 ch = 0; /* Release slavecpu */ 481 } 482 #endif 483