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