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