1 /* $NetBSD: ka6400.c,v 1.4 2002/10/02 16:02:35 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 * KA6400 specific CPU code. 35 */ 36 /* 37 * TODO: 38 * - Machine check code 39 * - Vector processor code 40 */ 41 42 #include "opt_multiprocessor.h" 43 44 #include <sys/param.h> 45 #include <sys/time.h> 46 #include <sys/kernel.h> 47 #include <sys/device.h> 48 #include <sys/systm.h> 49 #include <sys/conf.h> 50 51 #include <machine/ka670.h> 52 #include <machine/cpu.h> 53 #include <machine/mtpr.h> 54 #include <machine/nexus.h> 55 #include <machine/clock.h> 56 #include <machine/scb.h> 57 #include <machine/bus.h> 58 #include <machine/sid.h> 59 #include <machine/cca.h> 60 #include <machine/rpb.h> 61 62 #include <dev/xmi/xmireg.h> 63 #include <dev/xmi/xmivar.h> 64 65 #include "ioconf.h" 66 #include "locators.h" 67 68 static int *rssc; 69 struct cca *cca; 70 71 static int ka6400_match(struct device *, struct cfdata *, void *); 72 static void ka6400_attach(struct device *, struct device *, void*); 73 static void ka6400_memerr(void); 74 static void ka6400_conf(void); 75 static int ka6400_mchk(caddr_t); 76 static void ka6400_steal_pages(void); 77 #if defined(MULTIPROCESSOR) 78 static void ka6400_startslave(struct device *, struct cpu_info *); 79 static void ka6400_txrx(int, char *, int); 80 static void ka6400_sendstr(int, char *); 81 static void ka6400_sergeant(int); 82 static int rxchar(void); 83 static void ka6400_putc(int); 84 static void ka6400_cnintr(void); 85 cons_decl(gen); 86 #endif 87 88 struct cpu_dep ka6400_calls = { 89 ka6400_steal_pages, 90 ka6400_mchk, 91 ka6400_memerr, 92 ka6400_conf, 93 generic_clkread, 94 generic_clkwrite, 95 6, /* ~VUPS */ 96 16, /* SCB pages */ 97 0, 98 0, 99 0, 100 0, 101 0, 102 #if defined(MULTIPROCESSOR) 103 ka6400_startslave, 104 #endif 105 }; 106 107 struct ka6400_softc { 108 struct device sc_dev; 109 struct cpu_info *sc_ci; 110 int sc_nodeid; /* CPU node ID */ 111 }; 112 113 CFATTACH_DECL(cpu_xmi, sizeof(struct ka6400_softc), 114 ka6400_match, ka6400_attach, NULL, NULL); 115 116 static int 117 ka6400_match(struct device *parent, struct cfdata *cf, void *aux) 118 { 119 struct xmi_attach_args *xa = aux; 120 121 if (bus_space_read_2(xa->xa_iot, xa->xa_ioh, XMI_TYPE) != XMIDT_KA64) 122 return 0; 123 124 if (cf->cf_loc[XMICF_NODE] != XMICF_NODE_DEFAULT && 125 cf->cf_loc[XMICF_NODE] != xa->xa_nodenr) 126 return 0; 127 128 return 1; 129 } 130 131 static void 132 ka6400_attach(struct device *parent, struct device *self, void *aux) 133 { 134 struct ka6400_softc *sc = (void *)self; 135 struct xmi_attach_args *xa = aux; 136 int vp; 137 138 vp = (cca->cca_vecenab & (1 << xa->xa_nodenr)); 139 printf("\n%s: ka6400 (%s) rev %d%s\n", self->dv_xname, 140 mastercpu == xa->xa_nodenr ? "master" : "slave", 141 bus_space_read_4(xa->xa_iot, xa->xa_ioh, XMI_TYPE) >> 16, 142 (vp ? ", vector processor present" : "")); 143 144 sc->sc_nodeid = xa->xa_nodenr; 145 146 if (xa->xa_nodenr != mastercpu) { 147 #if defined(MULTIPROCESSOR) 148 sc->sc_ci = cpu_slavesetup(self); 149 v_putc = ka6400_putc; /* Need special console handling */ 150 #endif 151 return; 152 } 153 154 mtpr(0, PR_VPSR); /* Can't use vector processor */ 155 curcpu()->ci_dev = self; 156 } 157 158 void 159 ka6400_conf() 160 { 161 int mapaddr; 162 163 rssc = (void *)vax_map_physmem(RSSC_ADDR, 1); 164 mastercpu = rssc[RSSC_IPORT/4] & 15; 165 mapaddr = (cca ? (int)cca : rpb.cca_addr); 166 cca = (void *)vax_map_physmem(mapaddr, vax_btoc(sizeof(struct cca))); 167 } 168 169 /* 170 * MS62 support. 171 * This code should: 172 * 1: Be completed. 173 * 2: (eventually) move to dev/xmi/; it is used by Mips also. 174 */ 175 #define MEMRD(reg) bus_space_read_4(sc->sc_iot, sc->sc_ioh, (reg)) 176 #define MEMWR(reg, val) bus_space_write_4(sc->sc_iot, sc->sc_ioh, (reg), (val)) 177 178 #define MS62_TYPE 0 179 #define MS62_XBE 4 180 #define MS62_SEADR 16 181 #define MS62_CTL1 20 182 #define MS62_ECCERR 24 183 #define MS62_ECCEA 28 184 #define MS62_ILK0 32 185 #define MS62_ILK1 36 186 #define MS62_ILK2 40 187 #define MS62_ILK3 44 188 #define MS62_CTL2 48 189 190 static int ms6400_match(struct device *, struct cfdata *, void *); 191 static void ms6400_attach(struct device *, struct device *, void*); 192 193 struct mem_xmi_softc { 194 struct device sc_dev; 195 bus_space_tag_t sc_iot; 196 bus_space_handle_t sc_ioh; 197 }; 198 199 CFATTACH_DECL(mem_xmi, sizeof(struct mem_xmi_softc), 200 ms6400_match, ms6400_attach, NULL, NULL); 201 202 static int 203 ms6400_match(struct device *parent, struct cfdata *cf, void *aux) 204 { 205 struct xmi_attach_args *xa = aux; 206 207 if (bus_space_read_2(xa->xa_iot, xa->xa_ioh, XMI_TYPE) != XMIDT_MS62) 208 return 0; 209 210 if (cf->cf_loc[XMICF_NODE] != XMICF_NODE_DEFAULT && 211 cf->cf_loc[XMICF_NODE] != xa->xa_nodenr) 212 return 0; 213 214 return 1; 215 } 216 217 static void 218 ms6400_attach(struct device *parent, struct device *self, void *aux) 219 { 220 struct mem_xmi_softc *sc = (void *)self; 221 struct xmi_attach_args *xa = aux; 222 223 sc->sc_iot = xa->xa_iot; 224 sc->sc_ioh = xa->xa_ioh; 225 printf("\n%s: MS62, rev %d, size 32MB\n", self->dv_xname, 226 MEMRD(MS62_TYPE) >> 16); 227 } 228 229 static void 230 ka6400_memerr() 231 { 232 printf("ka6400_memerr\n"); 233 } 234 235 struct mc6400frame { 236 int mc64_summary; /* summary parameter */ 237 int mc64_va; /* va register */ 238 int mc64_vb; /* memory address */ 239 int mc64_sisr; /* status word */ 240 int mc64_state; /* error pc */ 241 int mc64_sc; /* micro pc */ 242 int mc64_pc; /* current pc */ 243 int mc64_psl; /* current psl */ 244 }; 245 246 static int 247 ka6400_mchk(caddr_t cmcf) 248 { 249 return (MCHK_PANIC); 250 } 251 252 #if defined(MULTIPROCESSOR) 253 #define RXBUF 80 254 static char rxbuf[RXBUF]; 255 static int got = 0, taken = 0; 256 static int expect = 0; 257 #endif 258 #if 0 259 /* 260 * Receive a character from logical console. 261 */ 262 static void 263 rxcdintr(void *arg) 264 { 265 int c = mfpr(PR_RXCD); 266 267 if (c == 0) 268 return; 269 270 #if defined(MULTIPROCESSOR) 271 if ((c & 0xff) == 0) { 272 if (curcpu()->ci_flags & CI_MASTERCPU) 273 ka6400_cnintr(); 274 return; 275 } 276 277 if (expect == ((c >> 8) & 0xf)) 278 rxbuf[got++] = c & 0xff; 279 280 if (got == RXBUF) 281 got = 0; 282 #endif 283 } 284 #endif 285 286 /* 287 * From ka670, which has the same cache structure. 288 */ 289 static void 290 ka6400_enable_cache(void) 291 { 292 mtpr(KA670_PCS_REFRESH, PR_PCSTS); /* disable primary cache */ 293 mtpr(mfpr(PR_PCSTS), PR_PCSTS); /* clear error flags */ 294 mtpr(8, PR_BCCTL); /* disable backup cache */ 295 mtpr(0, PR_BCFBTS); /* flush backup cache tag store */ 296 mtpr(0, PR_BCFPTS); /* flush primary cache tag store */ 297 mtpr(0x0e, PR_BCCTL); /* enable backup cache */ 298 mtpr(KA670_PCS_FLUSH | KA670_PCS_REFRESH, PR_PCSTS); /* flush primary cache */ 299 mtpr(KA670_PCS_ENABLE | KA670_PCS_REFRESH, PR_PCSTS); /* flush primary cache */ 300 } 301 302 void 303 ka6400_steal_pages(void) 304 { 305 int i, ncpu; 306 307 ka6400_enable_cache(); /* Turn on cache early */ 308 if (cca == 0) 309 cca = (void *)rpb.cca_addr; 310 /* Is there any way to get number of CPUs easier??? */ 311 for (i = ncpu = 0; i < cca->cca_maxcpu; i++) 312 if (cca->cca_console & (1 << i)) 313 ncpu++; 314 sprintf(cpu_model, "VAX 6000/4%x0", ncpu + 1); 315 } 316 317 318 #if defined(MULTIPROCESSOR) && 0 319 int 320 rxchar() 321 { 322 int ret; 323 324 if (got == taken) 325 return 0; 326 327 ret = rxbuf[taken++]; 328 if (taken == RXBUF) 329 taken = 0; 330 return ret; 331 } 332 333 static void 334 ka6400_startslave(struct device *dev, struct cpu_info *ci) 335 { 336 struct ka6400_softc *sc = (void *)dev; 337 int id = sc->sc_binid; 338 int i; 339 340 expect = sc->sc_binid; 341 /* First empty queue */ 342 for (i = 0; i < 10000; i++) 343 if (rxchar()) 344 i = 0; 345 ka6400_txrx(id, "\020", 0); /* Send ^P to get attention */ 346 ka6400_txrx(id, "I\r", 0); /* Init other end */ 347 ka6400_txrx(id, "D/I 4 %x\r", ci->ci_istack); /* Interrupt stack */ 348 ka6400_txrx(id, "D/I C %x\r", mfpr(PR_SBR)); /* SBR */ 349 ka6400_txrx(id, "D/I D %x\r", mfpr(PR_SLR)); /* SLR */ 350 ka6400_txrx(id, "D/I 10 %x\r", (int)ci->ci_pcb); /* PCB for idle proc */ 351 ka6400_txrx(id, "D/I 11 %x\r", mfpr(PR_SCBB)); /* SCB */ 352 ka6400_txrx(id, "D/I 38 %x\r", mfpr(PR_MAPEN)); /* Enable MM */ 353 ka6400_txrx(id, "S %x\r", (int)&tramp); /* Start! */ 354 expect = 0; 355 for (i = 0; i < 10000; i++) 356 if ((volatile)ci->ci_flags & CI_RUNNING) 357 break; 358 if (i == 10000) 359 printf("%s: (ID %d) failed starting??!!??\n", 360 dev->dv_xname, sc->sc_binid); 361 } 362 363 void 364 ka6400_txrx(int id, char *fmt, int arg) 365 { 366 char buf[20]; 367 368 sprintf(buf, fmt, arg); 369 ka6400_sendstr(id, buf); 370 ka6400_sergeant(id); 371 } 372 373 void 374 ka6400_sendstr(int id, char *buf) 375 { 376 register u_int utchr; /* Ends up in R11 with PCC */ 377 int ch, i; 378 379 while (*buf) { 380 utchr = *buf | id << 8; 381 382 /* 383 * It seems like mtpr to TXCD sets the V flag if it fails. 384 * Cannot check that flag in C... 385 */ 386 #ifdef __GNUC__ 387 asm("1:;mtpr %0,$92;bvs 1b" :: "g"(utchr)); 388 #else 389 asm("1:;mtpr r11,$92;bvs 1b"); 390 #endif 391 buf++; 392 i = 30000; 393 while ((ch = rxchar()) == 0 && --i) 394 ; 395 if (ch == 0) 396 continue; /* failed */ 397 } 398 } 399 400 void 401 ka6400_sergeant(int id) 402 { 403 int i, ch, nserg; 404 405 nserg = 0; 406 for (i = 0; i < 30000; i++) { 407 if ((ch = rxchar()) == 0) 408 continue; 409 if (ch == '>') 410 nserg++; 411 else 412 nserg = 0; 413 i = 0; 414 if (nserg == 3) 415 break; 416 } 417 /* What to do now??? */ 418 } 419 420 /* 421 * Write to master console. 422 * Need no locking here; done in the print functions. 423 */ 424 static volatile int ch = 0; 425 426 void 427 ka6400_putc(int c) 428 { 429 if (curcpu()->ci_flags & CI_MASTERCPU) { 430 gencnputc(0, c); 431 return; 432 } 433 ch = c; 434 mtpr(mastercpu << 8, PR_RXCD); /* Send IPI to mastercpu */ 435 while (ch != 0) 436 ; /* Wait for master to handle */ 437 } 438 439 /* 440 * Got character IPI. 441 */ 442 void 443 ka6400_cnintr() 444 { 445 if (ch != 0) 446 gencnputc(0, ch); 447 ch = 0; /* Release slavecpu */ 448 } 449 #endif 450