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