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