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