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