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