1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Driver for handling Serengeti I/O SRAM 31 * for Solaris <-> SC comm. 32 */ 33 34 #include <sys/types.h> 35 #include <sys/systm.h> 36 #include <sys/cpuvar.h> 37 #include <sys/dditypes.h> 38 #include <sys/sunndi.h> 39 #include <sys/param.h> 40 #include <sys/mutex.h> 41 #include <sys/sysmacros.h> 42 #include <sys/errno.h> 43 #include <sys/file.h> 44 #include <sys/kmem.h> 45 #include <sys/promif.h> 46 #include <sys/prom_plat.h> 47 #include <sys/sunddi.h> 48 #include <sys/ddi.h> 49 50 #include <sys/serengeti.h> 51 #include <sys/sgsbbc_priv.h> 52 #include <sys/sgsbbc_iosram_priv.h> 53 #include <sys/sgsbbc_mailbox_priv.h> 54 55 /* 56 * Local stuff 57 */ 58 static int iosram_rw(int, uint32_t, caddr_t, uint32_t, int); 59 static int iosram_convert_key(char *); 60 static int iosram_switch_intr(void); 61 static int tunnel_init(sbbc_softstate_t *, tunnel_t *); 62 static void tunnel_fini(tunnel_t *); 63 static void tunnel_commit(sbbc_softstate_t *, tunnel_t *); 64 static void clear_break(); 65 66 #define IOSRAM_GETB(tunnel, buf, sram, count) \ 67 ddi_rep_get8(tunnel->reg_handle, buf, sram, count, DDI_DEV_AUTOINCR) 68 69 #define IOSRAM_PUTB(tunnel, buf, sram, count) \ 70 ddi_rep_put8(tunnel->reg_handle, buf, sram, count, DDI_DEV_AUTOINCR) 71 72 #define IOSRAM_PUT(tunnel, sram, buf, size) \ 73 /* CSTYLED */ \ 74 ddi_put##size(tunnel->reg_handle, (uint##size##_t *)sram, \ 75 /* CSTYLED */ \ 76 *((uint##size##_t *)buf)) 77 78 #define IOSRAM_GET(tunnel, sram, buf, size) \ 79 /* CSTYLED */ \ 80 *(uint##size##_t *)buf = ddi_get##size(tunnel->reg_handle, \ 81 /* CSTYLED */ \ 82 (uint##size##_t *)sram) 83 84 /* 85 * sgsbbc_iosram_is_chosen(struct sbbc_softstate *softsp) 86 * 87 * Looks up "chosen" node property to 88 * determine if it is the chosen IOSRAM. 89 */ 90 int 91 sgsbbc_iosram_is_chosen(sbbc_softstate_t *softsp) 92 { 93 char pn[MAXNAMELEN]; 94 char chosen_iosram[MAXNAMELEN]; 95 int nodeid; 96 int chosen; 97 uint_t tunnel; 98 extern pnode_t chosen_nodeid; 99 100 ASSERT(chosen_nodeid); 101 102 nodeid = chosen_nodeid; 103 (void) prom_getprop(nodeid, "iosram", (caddr_t)&tunnel); 104 105 /* 106 * get the full OBP pathname of this node 107 */ 108 if (prom_phandle_to_path((phandle_t)tunnel, chosen_iosram, 109 sizeof (chosen_iosram)) < 0) { 110 cmn_err(CE_NOTE, "prom_phandle_to_path(%x) failed\n", tunnel); 111 return (0); 112 } 113 114 SGSBBC_DBG_ALL("sgsbbc_iosram(%d): prom_phandle_to_path(%x) is '%s'\n", 115 softsp->sbbc_instance, nodeid, chosen_iosram); 116 117 (void) ddi_pathname(softsp->dip, pn); 118 SGSBBC_DBG_ALL("sgsbbc_iosram(%d): ddi_pathname(%p) is '%s'\n", 119 softsp->sbbc_instance, softsp->dip, pn); 120 121 chosen = (strcmp(chosen_iosram, pn) == 0) ? 1 : 0; 122 SGSBBC_DBG_ALL("sgsbbc_iosram(%d): ... %s\n", softsp->sbbc_instance, 123 chosen? "MASTER" : "SLAVE"); 124 SGSBBC_DBG_ALL("sgsbbc_iosram(%d): ... %s\n", softsp->sbbc_instance, 125 (chosen ? "MASTER" : "SLAVE")); 126 127 return (chosen); 128 } 129 130 void 131 iosram_init() 132 { 133 int i; 134 135 if ((master_iosram = kmem_zalloc(sizeof (struct chosen_iosram), 136 KM_NOSLEEP)) == NULL) { 137 prom_printf("Can't allocate space for Chosen IOSRAM\n"); 138 panic("Can't allocate space for Chosen IOSRAM"); 139 } 140 141 if ((master_iosram->tunnel = kmem_zalloc(sizeof (tunnel_t), 142 KM_NOSLEEP)) == NULL) { 143 prom_printf("Can't allocate space for tunnel\n"); 144 panic("Can't allocate space for tunnel"); 145 } 146 147 master_iosram->iosram_sbbc = NULL; 148 149 for (i = 0; i < SBBC_MAX_KEYS; i++) { 150 master_iosram->tunnel->tunnel_keys[i].key = 0; 151 master_iosram->tunnel->tunnel_keys[i].base = NULL; 152 master_iosram->tunnel->tunnel_keys[i].size = 0; 153 } 154 155 for (i = 0; i < SBBC_MAX_INTRS; i++) 156 master_iosram->intrs[i].sbbc_handler = NULL; 157 158 mutex_init(&master_iosram->iosram_lock, NULL, MUTEX_DEFAULT, NULL); 159 rw_init(&master_iosram->tunnel_lock, NULL, RW_DEFAULT, NULL); 160 } 161 void 162 iosram_fini() 163 { 164 struct tunnel_key *tunnel; 165 int i; 166 167 rw_destroy(&master_iosram->tunnel_lock); 168 mutex_destroy(&master_iosram->iosram_lock); 169 170 /* 171 * destroy any tunnel maps 172 */ 173 for (i = 0; i < SBBC_MAX_KEYS; i++) { 174 tunnel = &master_iosram->tunnel->tunnel_keys[i]; 175 if (tunnel->base != NULL) { 176 ddi_regs_map_free(&tunnel->reg_handle); 177 tunnel->base = NULL; 178 } 179 } 180 181 kmem_free(master_iosram->tunnel, sizeof (tunnel_t)); 182 183 kmem_free(master_iosram, sizeof (struct chosen_iosram)); 184 185 master_iosram = NULL; 186 } 187 188 static void 189 check_iosram_ver(uint16_t version) 190 { 191 uint8_t max_ver = MAX_IOSRAM_TOC_VER; 192 uint8_t major_ver = 193 (version >> IOSRAM_TOC_VER_SHIFT) & IOSRAM_TOC_VER_MASK; 194 195 SGSBBC_DBG_ALL("IOSRAM TOC version: %d.%d\n", major_ver, 196 version & IOSRAM_TOC_VER_MASK); 197 SGSBBC_DBG_ALL("Max supported IOSRAM TOC version: %d\n", max_ver); 198 if (major_ver > max_ver) { 199 panic("Up-rev System Controller version.\n" 200 "You must restore an earlier revision of System " 201 "Controller firmware, or upgrade Solaris.\n" 202 "Please consult the System Controller release notice " 203 "for additional details."); 204 } 205 } 206 207 static void 208 tunnel_commit(sbbc_softstate_t *softsp, tunnel_t *new_tunnel) 209 { 210 ASSERT(MUTEX_HELD(&master_iosram->iosram_lock)); 211 212 master_iosram->iosram_sbbc = softsp; 213 master_iosram->tunnel = new_tunnel; 214 softsp->chosen = TRUE; 215 216 /* 217 * SBBC has pointer to interrupt handlers for simplicity 218 */ 219 softsp->intr_hdlrs = master_iosram->intrs; 220 } 221 222 static int 223 tunnel_init(sbbc_softstate_t *softsp, tunnel_t *new_tunnel) 224 { 225 struct iosram_toc *toc = NULL; 226 int i, key; 227 struct tunnel_key *tunnel; 228 ddi_acc_handle_t toc_handle; 229 struct ddi_device_acc_attr attr; 230 231 ASSERT(MUTEX_HELD(&master_iosram->iosram_lock)); 232 233 if ((softsp == (sbbc_softstate_t *)NULL) || 234 (new_tunnel == (tunnel_t *)NULL)) { 235 236 return (DDI_FAILURE); 237 } 238 239 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 240 attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 241 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 242 243 SGSBBC_DBG_ALL("map in the IOSRAM TOC at offset %x\n", 244 softsp->sram_toc); 245 246 /* 247 * First map in the TOC, then set up the tunnel 248 */ 249 if (ddi_regs_map_setup(softsp->dip, RNUM_SBBC_REGS, 250 (caddr_t *)&toc, 251 SBBC_SRAM_OFFSET + softsp->sram_toc, 252 sizeof (struct iosram_toc), 253 &attr, &toc_handle) != DDI_SUCCESS) { 254 cmn_err(CE_WARN, "sbbc%d: unable to map SRAM " 255 "registers", ddi_get_instance(softsp->dip)); 256 return (DDI_FAILURE); 257 } 258 SGSBBC_DBG_ALL("dip=%p mapped TOC %p\n", softsp->dip, toc); 259 260 check_iosram_ver(toc->iosram_version); 261 262 for (i = 0; i < toc->iosram_tagno; i++) { 263 key = iosram_convert_key(toc->iosram_keys[i].key); 264 if ((key > 0) && (key < SBBC_MAX_KEYS)) { 265 tunnel = &new_tunnel->tunnel_keys[key]; 266 tunnel->key = key; 267 tunnel->size = toc->iosram_keys[i].size; 268 /* 269 * map in the SRAM area using the offset 270 * from the base of SRAM + SRAM offset into 271 * the register property for the SBBC base 272 * address 273 */ 274 if (ddi_regs_map_setup(softsp->dip, RNUM_SBBC_REGS, 275 (caddr_t *)&tunnel->base, 276 SBBC_SRAM_OFFSET + toc->iosram_keys[i].offset, 277 toc->iosram_keys[i].size, &attr, 278 &tunnel->reg_handle) != DDI_SUCCESS) { 279 cmn_err(CE_WARN, "sbbc%d: unable to map SRAM " 280 "registers", ddi_get_instance(softsp->dip)); 281 return (DDI_FAILURE); 282 } 283 SGSBBC_DBG_ALL("%d: key %s size %d offset %x addr %p\n", 284 i, toc->iosram_keys[i].key, 285 toc->iosram_keys[i].size, 286 toc->iosram_keys[i].offset, 287 tunnel->base); 288 289 } 290 } 291 292 293 if (toc != NULL) { 294 ddi_regs_map_free(&toc_handle); 295 } 296 297 /* 298 * Set up the 'interrupt reason' SRAM pointers 299 * for the SBBC interrupt handler 300 */ 301 if (INVALID_KEY(new_tunnel, SBBC_SC_INTR_KEY)) { 302 /* 303 * Can't really do much if these are not here 304 */ 305 prom_printf("No Interrupt Reason Fields set by SC\n"); 306 cmn_err(CE_WARN, "No Interrupt Reason Fields set by SC"); 307 return (DDI_FAILURE); 308 } 309 310 return (DDI_SUCCESS); 311 } 312 313 /* 314 * Unmap a tunnel 315 */ 316 static void 317 tunnel_fini(tunnel_t *tunnel) 318 { 319 int i; 320 struct tunnel_key *tunnel_key; 321 322 /* 323 * Unmap the tunnel 324 */ 325 for (i = 0; i < SBBC_MAX_KEYS; i++) { 326 tunnel_key = &tunnel->tunnel_keys[i]; 327 if (tunnel_key->base != NULL) { 328 ddi_regs_map_free(&tunnel_key->reg_handle); 329 tunnel_key->base = NULL; 330 } 331 } 332 } 333 334 static void 335 clear_break() 336 { 337 struct tunnel_key tunnel_key; 338 uint32_t *intr_in_reason; 339 ddi_acc_handle_t intr_in_handle; 340 341 ASSERT(MUTEX_HELD(&master_iosram->iosram_lock)); 342 343 tunnel_key = master_iosram->tunnel->tunnel_keys[SBBC_SC_INTR_KEY]; 344 intr_in_reason = (uint32_t *)tunnel_key.base; 345 intr_in_handle = tunnel_key.reg_handle; 346 ddi_put32(intr_in_handle, intr_in_reason, 347 ddi_get32(intr_in_handle, intr_in_reason) & ~SBBC_CONSOLE_BRK); 348 } 349 350 int 351 iosram_tunnel_init(sbbc_softstate_t *softsp) 352 { 353 int rc; 354 355 ASSERT(master_iosram); 356 357 mutex_enter(&master_iosram->iosram_lock); 358 359 if ((rc = tunnel_init(softsp, master_iosram->tunnel)) == DDI_SUCCESS) { 360 tunnel_commit(softsp, master_iosram->tunnel); 361 clear_break(); 362 } 363 364 365 mutex_exit(&master_iosram->iosram_lock); 366 367 return (rc); 368 } 369 370 int 371 iosram_read(int key, uint32_t offset, caddr_t buf, uint32_t size) 372 { 373 return (iosram_rw(key, offset, buf, size, FREAD)); 374 } 375 376 int 377 iosram_write(int key, uint32_t offset, caddr_t buf, uint32_t size) 378 { 379 return (iosram_rw(key, offset, buf, size, FWRITE)); 380 } 381 382 383 static int 384 iosram_rw(int key, uint32_t offset, caddr_t buf, uint32_t size, int flag) 385 { 386 struct tunnel_key *tunnel; 387 caddr_t sram_src; 388 389 /* 390 * Return right away if there is nothing to read/write. 391 */ 392 if (size == 0) 393 return (0); 394 395 rw_enter(&master_iosram->tunnel_lock, RW_READER); 396 397 /* 398 * Key not matched ? 399 */ 400 if (INVALID_KEY(master_iosram->tunnel, key)) { 401 rw_exit(&master_iosram->tunnel_lock); 402 return (ENXIO); 403 } 404 405 tunnel = &master_iosram->tunnel->tunnel_keys[key]; 406 if ((offset + size) > tunnel->size) { 407 rw_exit(&master_iosram->tunnel_lock); 408 return (EFBIG); 409 } 410 411 sram_src = tunnel->base + offset; 412 413 /* 414 * Atomic reads/writes might be necessary for some clients. 415 * We assume that such clients could guarantee their buffers 416 * are aligned at the boundary of the request sizes. We also 417 * assume that the source/destination of such requests are 418 * aligned at the right boundaries in IOSRAM. If either 419 * condition fails, byte access is performed. 420 */ 421 if (flag == FREAD) { 422 switch (size) { 423 case sizeof (uint16_t): 424 case sizeof (uint32_t): 425 case sizeof (uint64_t): 426 if (IS_P2ALIGNED(sram_src, size) && 427 IS_P2ALIGNED(buf, size)) { 428 429 if (size == sizeof (uint16_t)) 430 IOSRAM_GET(tunnel, sram_src, buf, 16); 431 else if (size == sizeof (uint32_t)) 432 IOSRAM_GET(tunnel, sram_src, buf, 32); 433 else 434 IOSRAM_GET(tunnel, sram_src, buf, 64); 435 break; 436 } 437 /* FALLTHRU */ 438 default: 439 IOSRAM_GETB(tunnel, (uint8_t *)buf, 440 (uint8_t *)sram_src, (size_t)size); 441 break; 442 } 443 } else { 444 switch (size) { 445 case sizeof (uint16_t): 446 case sizeof (uint32_t): 447 case sizeof (uint64_t): 448 if (IS_P2ALIGNED(sram_src, size) && 449 IS_P2ALIGNED(buf, size)) { 450 451 if (size == sizeof (uint16_t)) 452 IOSRAM_PUT(tunnel, sram_src, buf, 16); 453 else if (size == sizeof (uint32_t)) 454 IOSRAM_PUT(tunnel, sram_src, buf, 32); 455 else 456 IOSRAM_PUT(tunnel, sram_src, buf, 64); 457 break; 458 } 459 /* FALLTHRU */ 460 default: 461 IOSRAM_PUTB(tunnel, (uint8_t *)buf, 462 (uint8_t *)sram_src, (size_t)size); 463 break; 464 } 465 } 466 467 rw_exit(&master_iosram->tunnel_lock); 468 return (0); 469 470 } 471 472 int 473 iosram_size(int key) 474 { 475 int size = -1; 476 477 rw_enter(&master_iosram->tunnel_lock, RW_READER); 478 479 /* 480 * Key not matched ? 481 */ 482 if (!INVALID_KEY(master_iosram->tunnel, key)) 483 size = master_iosram->tunnel->tunnel_keys[key].size; 484 485 rw_exit(&master_iosram->tunnel_lock); 486 487 return (size); 488 } 489 490 /* 491 * Generate an interrupt to the SC using the SBBC EPLD 492 * 493 * Note: intr_num can be multiple interrupts OR'ed together 494 */ 495 int 496 iosram_send_intr(uint32_t intr_num) 497 { 498 499 int rc = 0; 500 uint32_t intr_reason; 501 uint32_t intr_enabled; 502 503 /* 504 * Verify that we have already set up the master sbbc 505 */ 506 if (master_iosram == NULL) 507 return (ENXIO); 508 509 /* 510 * Grab the lock to prevent tunnel switch in the middle 511 * of sending an interrupt. 512 */ 513 mutex_enter(&master_iosram->iosram_lock); 514 515 if (master_iosram->iosram_sbbc == NULL) { 516 rc = ENXIO; 517 goto send_intr_exit; 518 } 519 520 if ((rc = sbbc_send_intr(master_iosram->iosram_sbbc, FALSE)) != 0) { 521 /* 522 * previous interrupts have not been cleared yet by the SC 523 */ 524 goto send_intr_exit; 525 } 526 527 /* 528 * Set a bit in the interrupt reason field 529 * call back into the sbbc handler to hit the EPLD 530 * 531 * First check the interrupts enabled by the SC 532 */ 533 if ((rc = iosram_read(SBBC_INTR_SC_ENABLED_KEY, 0, 534 (caddr_t)&intr_enabled, sizeof (intr_enabled))) != 0) { 535 536 goto send_intr_exit; 537 } 538 539 if ((intr_enabled & intr_num) != intr_num) { 540 /* 541 * at least one of the interrupts is 542 * not enabled by the SC 543 */ 544 rc = ENOTSUP; 545 goto send_intr_exit; 546 } 547 548 if ((rc = iosram_read(SBBC_INTR_SC_KEY, 0, 549 (caddr_t)&intr_reason, sizeof (intr_reason))) != 0) { 550 551 goto send_intr_exit; 552 } 553 554 if ((intr_reason & intr_num) == intr_num) { 555 /* 556 * All interrupts specified are already pending 557 */ 558 rc = EBUSY; 559 goto send_intr_exit; 560 } 561 562 intr_reason |= intr_num; 563 564 if ((rc = iosram_write(SBBC_INTR_SC_KEY, 0, 565 (caddr_t)&intr_reason, sizeof (intr_reason))) != 0) { 566 567 goto send_intr_exit; 568 } 569 570 /* 571 * Hit the EPLD interrupt bit 572 */ 573 574 rc = sbbc_send_intr(master_iosram->iosram_sbbc, TRUE); 575 576 send_intr_exit: 577 578 mutex_exit(&master_iosram->iosram_lock); 579 580 return (rc); 581 } 582 583 /* 584 * Register an interrupt handler 585 */ 586 int 587 iosram_reg_intr(uint32_t intr_num, sbbc_intrfunc_t intr_handler, 588 caddr_t arg, uint_t *state, kmutex_t *lock) 589 { 590 sbbc_softstate_t *softsp; 591 int rc = 0; 592 sbbc_intrs_t *intr; 593 int intr_no; 594 uint32_t intr_enabled; 595 596 /* 597 * Verify that we have already set up the master sbbc 598 */ 599 if (master_iosram == NULL) 600 return (ENXIO); 601 602 /* 603 * determine which bit is this intr_num for ? 604 */ 605 for (intr_no = 0; intr_no < SBBC_MAX_INTRS; intr_no++) { 606 if (intr_num == (1 << intr_no)) 607 break; 608 } 609 610 /* 611 * Check the parameters 612 */ 613 if ((intr_no < 0) || (intr_no >= SBBC_MAX_INTRS) || 614 (intr_handler == NULL) || (state == NULL) || 615 (lock == NULL)) 616 return (EINVAL); 617 618 mutex_enter(&master_iosram->iosram_lock); 619 620 if ((softsp = master_iosram->iosram_sbbc) == NULL) { 621 mutex_exit(&master_iosram->iosram_lock); 622 return (ENXIO); 623 } 624 625 mutex_enter(&softsp->sbbc_lock); 626 627 intr = &master_iosram->intrs[intr_no]; 628 629 if (intr->sbbc_handler != (sbbc_intrfunc_t)NULL) { 630 rc = EBUSY; 631 goto reg_intr_exit; 632 } 633 634 intr->sbbc_handler = intr_handler; 635 intr->sbbc_arg = (void *)arg; 636 intr->sbbc_intr_state = state; 637 intr->sbbc_intr_lock = lock; 638 intr->sbbc_intr_next = (sbbc_intrs_t *)NULL; 639 640 /* 641 * we need to make sure that the mutex is for 642 * an ADAPTIVE lock, so call mutex_init() again with 643 * the sbbc iblock cookie 644 */ 645 mutex_init(lock, NULL, MUTEX_DRIVER, 646 (void *)softsp->iblock); 647 648 if (ddi_add_softintr(softsp->dip, DDI_SOFTINT_HIGH, 649 &intr->sbbc_intr_id, NULL, NULL, 650 intr_handler, (caddr_t)arg) != DDI_SUCCESS) { 651 652 cmn_err(CE_WARN, "Can't add SBBC softint"); 653 rc = EAGAIN; 654 goto reg_intr_exit; 655 } 656 657 /* 658 * Set the bit in the Interrupts Enabled Field for this 659 * interrupt 660 */ 661 if ((rc = iosram_read(SBBC_SC_INTR_ENABLED_KEY, 0, 662 (caddr_t)&intr_enabled, sizeof (intr_enabled))) != 0) { 663 664 goto reg_intr_exit; 665 } 666 667 intr_enabled |= intr_num; 668 669 if ((rc = iosram_write(SBBC_SC_INTR_ENABLED_KEY, 0, 670 (caddr_t)&intr_enabled, sizeof (intr_enabled))) != 0) { 671 672 goto reg_intr_exit; 673 } 674 675 reg_intr_exit: 676 677 mutex_exit(&softsp->sbbc_lock); 678 mutex_exit(&master_iosram->iosram_lock); 679 680 return (rc); 681 } 682 683 /* 684 * Remove an interrupt handler 685 */ 686 int 687 iosram_unreg_intr(uint32_t intr_num) 688 { 689 sbbc_softstate_t *softsp; 690 int rc = 0; 691 sbbc_intrs_t *intr; 692 int intr_no; 693 uint32_t intr_enabled; 694 695 /* 696 * Verify that we have already set up the master sbbc 697 */ 698 if (master_iosram == NULL) 699 return (ENXIO); 700 701 /* 702 * determine which bit is this intr_num for ? 703 */ 704 for (intr_no = 0; intr_no < SBBC_MAX_INTRS; intr_no++) { 705 if (intr_num == (1 << intr_no)) 706 break; 707 } 708 709 if ((intr_no < 0) || (intr_no >= SBBC_MAX_INTRS)) 710 return (EINVAL); 711 712 mutex_enter(&master_iosram->iosram_lock); 713 714 if ((softsp = master_iosram->iosram_sbbc) == NULL) { 715 mutex_exit(&master_iosram->iosram_lock); 716 return (ENXIO); 717 } 718 719 mutex_enter(&softsp->sbbc_lock); 720 721 intr = &master_iosram->intrs[intr_no]; 722 723 /* 724 * No handler installed 725 */ 726 if (intr->sbbc_handler == (sbbc_intrfunc_t)NULL) { 727 rc = EINVAL; 728 goto unreg_intr_exit; 729 } 730 731 /* 732 * Unset the bit in the Interrupts Enabled Field for this 733 * interrupt 734 */ 735 if ((rc = iosram_read(SBBC_SC_INTR_ENABLED_KEY, 0, 736 (caddr_t)&intr_enabled, sizeof (intr_enabled))) != 0) { 737 738 goto unreg_intr_exit; 739 } 740 741 intr_enabled &= ~intr_num; 742 743 if ((rc = iosram_write(SBBC_SC_INTR_ENABLED_KEY, 0, 744 (caddr_t)&intr_enabled, sizeof (intr_enabled))) != 0) { 745 746 goto unreg_intr_exit; 747 } 748 749 /* 750 * If handler is running, wait until it's done. 751 * It won't get triggered again because we disabled it above. 752 * When we wait, drop sbbc_lock so other interrupt handlers 753 * can still run. 754 */ 755 for (; ; ) { 756 mutex_enter(intr->sbbc_intr_lock); 757 if (*(intr->sbbc_intr_state) != SBBC_INTR_IDLE) { 758 mutex_exit(intr->sbbc_intr_lock); 759 mutex_exit(&softsp->sbbc_lock); 760 delay(drv_usectohz(10000)); 761 mutex_enter(&softsp->sbbc_lock); 762 mutex_enter(intr->sbbc_intr_lock); 763 } else { 764 break; 765 } 766 mutex_exit(intr->sbbc_intr_lock); 767 } 768 769 if (intr->sbbc_intr_id) 770 ddi_remove_softintr(intr->sbbc_intr_id); 771 772 intr->sbbc_handler = (sbbc_intrfunc_t)NULL; 773 intr->sbbc_arg = (void *)NULL; 774 intr->sbbc_intr_id = 0; 775 intr->sbbc_intr_state = NULL; 776 intr->sbbc_intr_lock = (kmutex_t *)NULL; 777 intr->sbbc_intr_next = (sbbc_intrs_t *)NULL; 778 779 unreg_intr_exit: 780 781 mutex_exit(&softsp->sbbc_lock); 782 mutex_exit(&master_iosram->iosram_lock); 783 784 return (rc); 785 } 786 787 /* 788 * sgsbbc_iosram_switchfrom(softsp) 789 * Switch master tunnel away from the specified instance. 790 */ 791 int 792 sgsbbc_iosram_switchfrom(struct sbbc_softstate *softsp) 793 { 794 struct sbbc_softstate *sp; 795 int rv = DDI_FAILURE; 796 int new_instance; 797 798 /* 799 * Find the candidate target of tunnel from the linked list. 800 */ 801 mutex_enter(&chosen_lock); 802 ASSERT(sgsbbc_instances); 803 804 for (sp = sgsbbc_instances; sp != NULL; sp = sp->next) { 805 if (softsp == sp) 806 continue; 807 808 if (sp->sbbc_state & SBBC_STATE_DETACH) 809 continue; 810 break; 811 } 812 if (sp == NULL) { 813 /* at least one IOSRAM should be attached */ 814 rv = DDI_FAILURE; 815 } else { 816 /* Do the tunnel switch */ 817 new_instance = ddi_get_instance(sp->dip); 818 rv = iosram_switch_tunnel(new_instance); 819 if (rv == DDI_SUCCESS) { 820 /* reset the chosen_iosram back ref */ 821 sp->iosram = master_iosram; 822 } 823 } 824 mutex_exit(&chosen_lock); 825 return (rv); 826 } 827 828 829 /* 830 * Switch the tunnel to a different I/O board. 831 * At the moment, we will say that this is 832 * called with the instance of the SBBC to switch 833 * to. This will probably change, but as long as we 834 * can get a devinfo/softstate for the target SBBC it 835 * doesn't matter what the parameter is. 836 */ 837 int 838 iosram_switch_tunnel(int instance) 839 { 840 841 sbbc_softstate_t *to_softsp, *from_softsp; 842 dev_info_t *pdip; /* parent dip */ 843 tunnel_t *new_tunnel; /* new tunnel */ 844 int portid; 845 uint_t node; /* node id to pass to OBP */ 846 uint_t board; /* board number to pass to OBP */ 847 int rc = DDI_SUCCESS; 848 static fn_t f = "iosram_switch_tunnel"; 849 850 /* Check the firmware for tunnel switch support */ 851 if (prom_test("SUNW,switch-tunnel") != 0) { 852 cmn_err(CE_WARN, "Firmware does not support tunnel switch"); 853 return (DDI_FAILURE); 854 } 855 856 if ((master_iosram == NULL) || (master_mbox == NULL)) 857 return (DDI_FAILURE); 858 859 if (!(to_softsp = sbbc_get_soft_state(instance))) 860 return (DDI_FAILURE); 861 862 /* 863 * create the new tunnel 864 */ 865 if ((new_tunnel = kmem_zalloc(sizeof (tunnel_t), KM_NOSLEEP)) == NULL) { 866 cmn_err(CE_WARN, "Can't allocate space for new tunnel"); 867 return (DDI_FAILURE); 868 } 869 870 pdip = ddi_get_parent(to_softsp->dip); 871 if ((portid = ddi_getprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 872 "portid", -1)) < 0) { 873 874 SGSBBC_DBG_ALL("%s: couldn't get portid\n", f); 875 return (DDI_FAILURE); 876 } 877 878 /* 879 * Compute node id and board number from port id 880 */ 881 node = SG_PORTID_TO_NODEID(portid); 882 board = SG_IO_BD_PORTID_TO_BD_NUM(portid); 883 884 /* 885 * lock the chosen IOSRAM 886 */ 887 mutex_enter(&master_iosram->iosram_lock); 888 889 if (master_iosram->iosram_sbbc == NULL) { 890 mutex_exit(&master_iosram->iosram_lock); 891 return (DDI_FAILURE); 892 } 893 894 /* 895 * If the target SBBC has not mapped in its 896 * register address space, do it now 897 */ 898 mutex_enter(&to_softsp->sbbc_lock); 899 if (to_softsp->sbbc_regs == NULL) { 900 if (sbbc_map_regs(to_softsp) != DDI_SUCCESS) { 901 mutex_exit(&to_softsp->sbbc_lock); 902 mutex_exit(&master_iosram->iosram_lock); 903 return (DDI_FAILURE); 904 } 905 } 906 907 /* 908 * Get a pointer to the current sbbc 909 */ 910 from_softsp = master_iosram->iosram_sbbc; 911 912 mutex_enter(&from_softsp->sbbc_lock); 913 914 /* 915 * Disable interrupts from the SC now 916 */ 917 sbbc_disable_intr(from_softsp); 918 919 /* 920 * move SC interrupts to the new tunnel 921 */ 922 if ((rc = sbbc_add_intr(to_softsp)) == DDI_FAILURE) { 923 cmn_err(CE_WARN, "Failed to add new interrupt handler"); 924 } else if ((rc = tunnel_init(to_softsp, new_tunnel)) == DDI_FAILURE) { 925 cmn_err(CE_WARN, "Failed to initialize new tunnel"); 926 ddi_remove_intr(to_softsp->dip, 0, to_softsp->iblock); 927 } else { 928 rw_enter(&master_iosram->tunnel_lock, RW_WRITER); 929 930 /* 931 * If OBP switch is unsuccessful, abort the switch. 932 */ 933 if ((rc = prom_serengeti_tunnel_switch(node, board)) 934 != DDI_SUCCESS) { 935 936 /* 937 * Restart other CPUs. 938 */ 939 rw_exit(&master_iosram->tunnel_lock); 940 941 cmn_err(CE_WARN, "OBP failed to switch tunnel"); 942 943 /* 944 * Remove interrupt 945 */ 946 ddi_remove_intr(to_softsp->dip, 0, to_softsp->iblock); 947 948 /* 949 * Unmap new tunnel 950 */ 951 tunnel_fini(new_tunnel); 952 } else { 953 tunnel_t *orig_tunnel; 954 955 orig_tunnel = master_iosram->tunnel; 956 tunnel_commit(to_softsp, new_tunnel); 957 958 rw_exit(&master_iosram->tunnel_lock); 959 960 /* 961 * Remove interrupt from original softsp 962 */ 963 ddi_remove_intr(from_softsp->dip, 0, 964 from_softsp->iblock); 965 /* 966 * Unmap original tunnel 967 */ 968 tunnel_fini(orig_tunnel); 969 kmem_free(orig_tunnel, sizeof (tunnel_t)); 970 971 /* 972 * Move the softintrs to the new dip. 973 */ 974 (void) iosram_switch_intr(); 975 (void) sbbc_mbox_switch(to_softsp); 976 977 from_softsp->chosen = FALSE; 978 979 } 980 } 981 982 /* 983 * Enable interrupt. 984 */ 985 sbbc_enable_intr(master_iosram->iosram_sbbc); 986 987 /* 988 * Unlock and get out 989 */ 990 mutex_exit(&from_softsp->sbbc_lock); 991 mutex_exit(&to_softsp->sbbc_lock); 992 mutex_exit(&master_iosram->iosram_lock); 993 994 /* 995 * Call the interrupt handler directly in case 996 * we have missed an interrupt 997 */ 998 (void) sbbc_intr_handler(master_iosram->iosram_sbbc); 999 1000 if (rc != DDI_SUCCESS) { 1001 /* 1002 * Free up the new_tunnel 1003 */ 1004 kmem_free(new_tunnel, sizeof (tunnel_t)); 1005 cmn_err(CE_WARN, "Tunnel switch failed"); 1006 } 1007 1008 return (rc); 1009 1010 } 1011 1012 /* 1013 * convert an alphanumeric OBP key to 1014 * our defined numeric keys 1015 */ 1016 static int 1017 iosram_convert_key(char *toc_key) 1018 { 1019 1020 if (strcmp(toc_key, TOCKEY_DOMSTAT) == 0) 1021 return (SBBC_DOMAIN_KEY); 1022 if (strcmp(toc_key, TOCKEY_KEYSWPO) == 0) 1023 return (SBBC_KEYSWITCH_KEY); 1024 if (strcmp(toc_key, TOCKEY_TODDATA) == 0) 1025 return (SBBC_TOD_KEY); 1026 if (strcmp(toc_key, TOCKEY_SOLCONS) == 0) 1027 return (SBBC_CONSOLE_KEY); 1028 if (strcmp(toc_key, TOCKEY_SOLMBOX) == 0) 1029 return (SBBC_MAILBOX_KEY); 1030 if (strcmp(toc_key, TOCKEY_SOLSCIR) == 0) 1031 return (SBBC_INTR_SC_KEY); 1032 if (strcmp(toc_key, TOCKEY_SCSOLIR) == 0) 1033 return (SBBC_SC_INTR_KEY); 1034 if (strcmp(toc_key, TOCKEY_ENVINFO) == 0) 1035 return (SBBC_ENVCTRL_KEY); 1036 if (strcmp(toc_key, TOCKEY_SOLSCIE) == 0) 1037 return (SBBC_INTR_SC_ENABLED_KEY); 1038 if (strcmp(toc_key, TOCKEY_SCSOLIE) == 0) 1039 return (SBBC_SC_INTR_ENABLED_KEY); 1040 if (strcmp(toc_key, TOCKEY_SIGBLCK) == 0) 1041 return (SBBC_SIGBLCK_KEY); 1042 1043 /* Unknown key */ 1044 return (-1); 1045 } 1046 1047 /* 1048 * Move the software interrupts from the old dip to the new dip 1049 * when doing tunnel switch. 1050 */ 1051 static int 1052 iosram_switch_intr() 1053 { 1054 sbbc_intrs_t *intr; 1055 int intr_no; 1056 int rc = 0; 1057 1058 ASSERT(MUTEX_HELD(&master_iosram->iosram_lock)); 1059 1060 for (intr_no = 0; intr_no < SBBC_MAX_INTRS; intr_no++) { 1061 intr = &master_iosram->intrs[intr_no]; 1062 1063 if (intr->sbbc_intr_id) { 1064 ddi_remove_softintr(intr->sbbc_intr_id); 1065 1066 if (ddi_add_softintr(master_iosram->iosram_sbbc->dip, 1067 DDI_SOFTINT_HIGH, 1068 &intr->sbbc_intr_id, NULL, NULL, 1069 intr->sbbc_handler, intr->sbbc_arg) 1070 != DDI_SUCCESS) { 1071 1072 cmn_err(CE_WARN, "Can't add SBBC softint for " 1073 "interrupt %x", intr_no << 1); 1074 rc = EAGAIN; 1075 } 1076 } 1077 } 1078 1079 return (rc); 1080 } 1081