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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 /* 29 * PCI SBBC Device Driver that provides interfaces into 30 * EPLD and IO-SRAM 31 * 32 */ 33 #include <sys/types.h> 34 #include <sys/param.h> 35 #include <sys/errno.h> 36 #include <sys/file.h> 37 #include <sys/cmn_err.h> 38 #include <sys/stropts.h> 39 #include <sys/kmem.h> 40 #include <sys/sunndi.h> 41 #include <sys/conf.h> /* req. by dev_ops flags MTSAFE etc. */ 42 #include <sys/modctl.h> /* for modldrv */ 43 #include <sys/promif.h> 44 #include <sys/stat.h> 45 #include <sys/ddi.h> 46 47 #include <sys/serengeti.h> 48 #include <sys/sgsbbc_priv.h> 49 #include <sys/sgsbbc_iosram_priv.h> 50 #include <sys/sgsbbc_mailbox_priv.h> 51 52 #ifdef DEBUG 53 /* debug flag */ 54 uint_t sgsbbc_debug = 0; 55 #endif /* DEBUG */ 56 57 /* driver entry point fn definitions */ 58 static int sbbc_attach(dev_info_t *, ddi_attach_cmd_t); 59 static int sbbc_detach(dev_info_t *, ddi_detach_cmd_t); 60 61 /* 62 * SBBC soft state hook 63 */ 64 static void *sbbcp; 65 66 /* 67 * Chosen IOSRAM 68 */ 69 struct chosen_iosram *master_iosram = NULL; 70 71 /* 72 * define new iosram's sbbc and liked list of sbbc. 73 */ 74 struct sbbc_softstate *sgsbbc_instances = NULL; 75 76 /* 77 * At attach time, check if the device is the 'chosen' node 78 * if it is, set up the IOSRAM Solaris<->SC Comm tunnel 79 * Its like 'Highlander' - there can be only one ! 80 */ 81 static int master_chosen = FALSE; 82 kmutex_t chosen_lock; 83 84 /* 85 * Local variable to save intr_in_enabled when the driver is suspended 86 */ 87 static uint32_t intr_in_enabled; 88 89 /* 90 * Local declarations 91 */ 92 static void softsp_init(sbbc_softstate_t *, dev_info_t *); 93 static void sbbc_chosen_init(sbbc_softstate_t *); 94 static void sbbc_add_instance(sbbc_softstate_t *); 95 static void sbbc_remove_instance(sbbc_softstate_t *); 96 static int sbbc_find_dip(dev_info_t *, void *); 97 static void sbbc_unmap_regs(sbbc_softstate_t *); 98 99 /* 100 * ops stuff. 101 */ 102 static struct cb_ops sbbc_cb_ops = { 103 nodev, /* cb_open */ 104 nodev, /* cb_close */ 105 nodev, /* cb_strategy */ 106 nodev, /* cb_print */ 107 nodev, /* cb_dump */ 108 nodev, /* cb_read */ 109 nodev, /* cb_write */ 110 nodev, /* cb_ioctl */ 111 nodev, /* cb_devmap */ 112 nodev, /* cb_mmap */ 113 nodev, /* cb_segmap */ 114 nochpoll, /* cb_chpoll */ 115 ddi_prop_op, /* cb_prop_op */ 116 NULL, /* cb_stream */ 117 D_NEW | D_MP /* cb_flag */ 118 }; 119 120 /* 121 * Declare ops vectors for auto configuration. 122 */ 123 struct dev_ops sbbc_ops = { 124 DEVO_REV, /* devo_rev */ 125 0, /* devo_refcnt */ 126 ddi_getinfo_1to1, /* devo_getinfo */ 127 nulldev, /* devo_identify */ 128 nulldev, /* devo_probe */ 129 sbbc_attach, /* devo_attach */ 130 sbbc_detach, /* devo_detach */ 131 nodev, /* devo_reset */ 132 &sbbc_cb_ops, /* devo_cb_ops */ 133 (struct bus_ops *)NULL, /* devo_bus_ops */ 134 nulldev, /* devo_power */ 135 ddi_quiesce_not_supported, /* devo_quiesce */ 136 }; 137 138 /* 139 * Loadable module support. 140 */ 141 extern struct mod_ops mod_driverops; 142 143 static struct modldrv modldrv = { 144 &mod_driverops, /* type of module - driver */ 145 "PCI SBBC", 146 &sbbc_ops, 147 }; 148 149 static struct modlinkage modlinkage = { 150 MODREV_1, 151 (void *)&modldrv, 152 NULL 153 }; 154 155 int 156 _init(void) 157 { 158 int error; 159 160 if ((error = ddi_soft_state_init(&sbbcp, 161 sizeof (sbbc_softstate_t), 1)) != 0) 162 return (error); 163 164 if ((error = mod_install(&modlinkage)) != 0) { 165 ddi_soft_state_fini(&sbbcp); 166 return (error); 167 } 168 169 /* 170 * Initialise the global 'chosen' IOSRAM mutex 171 */ 172 mutex_init(&chosen_lock, NULL, MUTEX_DEFAULT, NULL); 173 174 /* 175 * Initialise the iosram driver 176 */ 177 iosram_init(); 178 179 /* 180 * Initialize the mailbox 181 */ 182 sbbc_mbox_init(); 183 184 return (error); 185 186 } 187 188 int 189 _fini(void) 190 { 191 int error; 192 193 if ((error = mod_remove(&modlinkage)) == 0) 194 ddi_soft_state_fini(&sbbcp); 195 196 master_chosen = FALSE; 197 198 mutex_destroy(&chosen_lock); 199 200 /* 201 * remove the mailbox 202 */ 203 sbbc_mbox_fini(); 204 205 /* 206 * remove the iosram driver 207 */ 208 iosram_fini(); 209 210 return (error); 211 } 212 213 int 214 _info(struct modinfo *modinfop) 215 { 216 return (mod_info(&modlinkage, modinfop)); 217 } 218 219 static int 220 sbbc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 221 { 222 int instance; 223 sbbc_softstate_t *softsp; 224 uint32_t *pci_intr_enable_reg; 225 int len; 226 #ifdef DEBUG 227 char name[8]; 228 #endif /* DEBUG */ 229 230 instance = ddi_get_instance(devi); 231 232 switch (cmd) { 233 case DDI_ATTACH: 234 235 if (ddi_soft_state_zalloc(sbbcp, instance) != 0) 236 return (DDI_FAILURE); 237 238 softsp = ddi_get_soft_state(sbbcp, instance); 239 softsp->sbbc_instance = instance; 240 241 /* 242 * Set the dip in the soft state 243 * And get interrupt cookies and initialize the 244 * per instance mutex. 245 */ 246 softsp_init(softsp, devi); 247 248 249 /* 250 * Verify that an 'interrupts' property exists for 251 * this device. If not, this instance will be ignored. 252 */ 253 if (ddi_getproplen(DDI_DEV_T_ANY, softsp->dip, 254 DDI_PROP_DONTPASS, "interrupts", 255 &len) != DDI_PROP_SUCCESS) { 256 SBBC_ERR1(CE_WARN, "No 'interrupts' property for the " 257 "SBBC instance %d\n", instance); 258 return (DDI_FAILURE); 259 } 260 /* 261 * Add this instance to the sbbc chosen iosram list 262 * so that it can be used for tunnel switch. 263 */ 264 mutex_enter(&chosen_lock); 265 softsp->sbbc_state = SBBC_STATE_INIT; 266 sbbc_add_instance(softsp); 267 268 /* 269 * If this is the chosen IOSRAM and there is no master IOSRAM 270 * yet, then let's set this instance as the master. 271 * if there is a master alreay due to the previous tunnel switch 272 * then keep as is even though this is the chosen. 273 */ 274 if (sgsbbc_iosram_is_chosen(softsp)) { 275 ASSERT(master_iosram); 276 softsp->iosram = master_iosram; 277 master_iosram->sgsbbc = softsp; 278 279 /* Do 'chosen' init only */ 280 sbbc_chosen_init(softsp); 281 } 282 283 mutex_exit(&chosen_lock); 284 #ifdef DEBUG 285 (void) sprintf(name, "sbbc%d", instance); 286 287 if (ddi_create_minor_node(devi, name, S_IFCHR, instance, 288 NULL, NULL) == DDI_FAILURE) { 289 mutex_destroy(&softsp->sbbc_lock); 290 ddi_remove_minor_node(devi, NULL); 291 ddi_soft_state_free(sbbcp, instance); 292 return (DDI_FAILURE); 293 } 294 #endif /* DEBUG */ 295 296 ddi_report_dev(devi); 297 298 return (DDI_SUCCESS); 299 300 case DDI_RESUME: 301 302 if (!(softsp = ddi_get_soft_state(sbbcp, instance))) 303 return (DDI_FAILURE); 304 305 mutex_enter(&softsp->sbbc_lock); 306 if ((softsp->suspended == TRUE) && (softsp->chosen == TRUE)) { 307 /* 308 * Enable Interrupts now, turn on both INT#A lines 309 */ 310 pci_intr_enable_reg = (uint32_t *) 311 ((char *)softsp->sbbc_regs + 312 SBBC_PCI_INT_ENABLE); 313 314 ddi_put32(softsp->sbbc_reg_handle1, 315 pci_intr_enable_reg, 316 (uint32_t)SBBC_PCI_ENABLE_INT_A); 317 318 /* 319 * Reset intr_in_enabled to the original value 320 * so the SC can send us interrupt. 321 */ 322 if (iosram_write(SBBC_SC_INTR_ENABLED_KEY, 323 0, (caddr_t)&intr_in_enabled, 324 sizeof (intr_in_enabled))) { 325 326 mutex_exit(&softsp->sbbc_lock); 327 return (DDI_FAILURE); 328 } 329 } 330 softsp->suspended = FALSE; 331 332 mutex_exit(&softsp->sbbc_lock); 333 334 return (DDI_SUCCESS); 335 336 default: 337 return (DDI_FAILURE); 338 } 339 } 340 341 static int 342 sbbc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 343 { 344 sbbc_softstate_t *softsp; 345 int instance; 346 uint32_t *pci_intr_enable_reg; 347 int rc = DDI_SUCCESS; 348 349 instance = ddi_get_instance(devi); 350 351 if (!(softsp = ddi_get_soft_state(sbbcp, instance))) 352 return (DDI_FAILURE); 353 354 switch (cmd) { 355 case DDI_DETACH: 356 mutex_enter(&chosen_lock); 357 softsp->sbbc_state |= SBBC_STATE_DETACH; 358 mutex_exit(&chosen_lock); 359 360 /* only tunnel switch the instance with iosram chosen */ 361 if (softsp->chosen == TRUE) { 362 if (sgsbbc_iosram_switchfrom(softsp) == DDI_FAILURE) { 363 SBBC_ERR(CE_WARN, "Cannot unconfigure: " 364 "tunnel switch failed\n"); 365 return (DDI_FAILURE); 366 } 367 } 368 369 /* Adjust linked list */ 370 mutex_enter(&chosen_lock); 371 sbbc_remove_instance(softsp); 372 mutex_exit(&chosen_lock); 373 374 sbbc_unmap_regs(softsp); 375 mutex_destroy(&softsp->sbbc_lock); 376 ddi_soft_state_free(sbbcp, instance); 377 378 return (DDI_SUCCESS); 379 380 case DDI_SUSPEND: 381 382 mutex_enter(&softsp->sbbc_lock); 383 384 if ((softsp->suspended == FALSE) && (softsp->chosen == TRUE)) { 385 uint32_t tmp_intr_enabled = 0; 386 387 /* 388 * Disable Interrupts now, turn OFF both INT#A lines 389 */ 390 pci_intr_enable_reg = (uint32_t *) 391 ((char *)softsp->sbbc_regs + 392 SBBC_PCI_INT_ENABLE); 393 394 ddi_put32(softsp->sbbc_reg_handle1, 395 pci_intr_enable_reg, 0); 396 397 /* 398 * Set intr_in_enabled to 0 so the SC won't send 399 * us interrupt. 400 */ 401 rc = iosram_read(SBBC_SC_INTR_ENABLED_KEY, 402 0, (caddr_t)&intr_in_enabled, 403 sizeof (intr_in_enabled)); 404 405 if (rc) { 406 mutex_exit(&softsp->sbbc_lock); 407 return (DDI_FAILURE); 408 } 409 410 rc = iosram_write(SBBC_SC_INTR_ENABLED_KEY, 411 0, (caddr_t)&tmp_intr_enabled, 412 sizeof (tmp_intr_enabled)); 413 414 if (rc) { 415 mutex_exit(&softsp->sbbc_lock); 416 return (DDI_FAILURE); 417 } 418 } 419 softsp->suspended = TRUE; 420 421 mutex_exit(&softsp->sbbc_lock); 422 423 return (DDI_SUCCESS); 424 425 default: 426 return (DDI_FAILURE); 427 } 428 429 } 430 431 static void 432 softsp_init(sbbc_softstate_t *softsp, dev_info_t *devi) 433 { 434 softsp->dip = devi; 435 436 /* 437 * XXXX 438 * ddi_get_iblock_cookie() here because we need 439 * to initialise the mutex regardless of whether 440 * or not this SBBC will eventually 441 * register an interrupt handler 442 */ 443 444 (void) ddi_get_iblock_cookie(devi, 0, &softsp->iblock); 445 446 mutex_init(&softsp->sbbc_lock, NULL, MUTEX_DRIVER, 447 (void *)softsp->iblock); 448 449 softsp->suspended = FALSE; 450 softsp->chosen = FALSE; 451 } 452 453 static int 454 sbbc_find_dip(dev_info_t *dip, void *arg) 455 { 456 char *node_name; 457 sbbc_find_dip_t *dip_struct = (sbbc_find_dip_t *)arg; 458 char status[OBP_MAXPROPNAME]; 459 460 /* 461 * Need to find a node named "bootbus-controller" that is neither 462 * disabled nor failed. If a node is not ok, there will be an 463 * OBP status property. Therefore, we will look for a node 464 * without the status property. 465 */ 466 node_name = ddi_node_name(dip); 467 if (strcmp(node_name, "bootbus-controller") == 0 && DDI_CF2(dip) && 468 (prom_getprop(ddi_get_nodeid(dip), 469 "status", (caddr_t)status) == -1) && 470 (prom_getprop(ddi_get_nodeid(ddi_get_parent(dip)), 471 "status", (caddr_t)status) == -1)) { 472 473 if (dip != dip_struct->cur_dip) { 474 dip_struct->new_dip = (void *)dip; 475 return (DDI_WALK_TERMINATE); 476 } 477 } 478 479 return (DDI_WALK_CONTINUE); 480 } 481 482 /* 483 * SBBC Interrupt Handler 484 * 485 * Check the SBBC Port Interrupt Status 486 * register to verify that its our interrupt. 487 * If yes, clear the register. 488 * 489 * Then read the 'interrupt reason' field from SRAM, 490 * this triggers the appropriate soft_intr handler 491 */ 492 uint_t 493 sbbc_intr_handler(caddr_t arg) 494 { 495 sbbc_softstate_t *softsp = (sbbc_softstate_t *)arg; 496 uint32_t *port_int_reg; 497 volatile uint32_t port_int_status; 498 volatile uint32_t intr_reason; 499 uint32_t intr_enabled; 500 sbbc_intrs_t *intr; 501 int i, intr_mask; 502 struct tunnel_key tunnel_key; 503 ddi_acc_handle_t intr_in_handle; 504 uint32_t *intr_in_reason; 505 506 if (softsp == (sbbc_softstate_t *)NULL) { 507 508 return (DDI_INTR_UNCLAIMED); 509 } 510 511 mutex_enter(&softsp->sbbc_lock); 512 513 if (softsp->port_int_regs == NULL) { 514 mutex_exit(&softsp->sbbc_lock); 515 return (DDI_INTR_UNCLAIMED); 516 } 517 518 /* 519 * Normally if port_int_status is 0, we assume it is not 520 * our interrupt. However, we don't want to miss the 521 * ones that come in during tunnel switch. Therefore, 522 * we always check the interrupt reason bits in IOSRAM 523 * to be sure. 524 */ 525 port_int_reg = softsp->port_int_regs; 526 527 port_int_status = ddi_get32(softsp->sbbc_reg_handle1, port_int_reg); 528 529 /* 530 * Generate a softint for each interrupt 531 * bit set in the intr_in_reason field in SRAM 532 * that has a corresponding bit set in the 533 * intr_in_enabled field in SRAM 534 */ 535 536 if (iosram_read(SBBC_SC_INTR_ENABLED_KEY, 0, 537 (caddr_t)&intr_enabled, sizeof (intr_enabled))) { 538 539 goto intr_handler_exit; 540 } 541 542 tunnel_key = master_iosram->tunnel->tunnel_keys[SBBC_SC_INTR_KEY]; 543 intr_in_reason = (uint32_t *)tunnel_key.base; 544 intr_in_handle = tunnel_key.reg_handle; 545 546 intr_reason = ddi_get32(intr_in_handle, intr_in_reason); 547 548 SGSBBC_DBG_INTR(CE_CONT, "intr_reason = %x\n", intr_reason); 549 550 intr_reason &= intr_enabled; 551 552 for (i = 0; i < SBBC_MAX_INTRS; i++) { 553 intr_mask = (1 << i); 554 if (intr_reason & intr_mask) { 555 intr = &softsp->intr_hdlrs[i]; 556 if ((intr != NULL) && 557 (intr->sbbc_intr_id != 0)) { 558 /* 559 * XXXX 560 * The model we agree with a handler 561 * is that they run until they have 562 * exhausted all work. To avoid 563 * triggering them again, they pass 564 * a state flag and lock when registering. 565 * We check the flag, if they are idle, 566 * we trigger. 567 * The interrupt handler should so 568 * intr_func() 569 * mutex_enter(sbbc_intr_lock); 570 * sbbc_intr_state = RUNNING; 571 * mutex_exit(sbbc_intr_lock); 572 * .......... 573 * .......... 574 * .......... 575 * mutex_enter(sbbc_intr_lock); 576 * sbbc_intr_state = IDLE; 577 * mutex_exit(sbbc_intr_lock); 578 * 579 * XXXX 580 */ 581 mutex_enter(intr->sbbc_intr_lock); 582 if (*(intr->sbbc_intr_state) == 583 SBBC_INTR_IDLE) { 584 mutex_exit(intr->sbbc_intr_lock); 585 ddi_trigger_softintr( 586 intr->sbbc_intr_id); 587 } else { 588 /* 589 * The handler is running 590 */ 591 mutex_exit(intr->sbbc_intr_lock); 592 } 593 intr_reason &= ~intr_mask; 594 /* 595 * Clear the corresponding reason bit in SRAM 596 * 597 * Since there is no interlocking between 598 * Solaris and the SC when writing to SRAM, 599 * it is possible for the SC to set another 600 * bit in the interrupt reason field while 601 * we are handling the current interrupt. 602 * To minimize the window in which an 603 * additional bit can be set, reading 604 * and writing the interrupt reason 605 * in SRAM must be as close as possible. 606 */ 607 ddi_put32(intr_in_handle, intr_in_reason, 608 ddi_get32(intr_in_handle, 609 intr_in_reason) & ~intr_mask); 610 } 611 } 612 if (intr_reason == 0) /* No more interrupts to be processed */ 613 break; 614 } 615 616 /* 617 * Clear the Interrupt Status Register (RW1C) 618 */ 619 ddi_put32(softsp->sbbc_reg_handle1, port_int_reg, port_int_status); 620 621 port_int_status = ddi_get32(softsp->sbbc_reg_handle1, port_int_reg); 622 623 intr_handler_exit: 624 625 mutex_exit(&softsp->sbbc_lock); 626 627 return (DDI_INTR_CLAIMED); 628 629 } 630 631 /* 632 * If we don't already have a master SBBC selected, 633 * get the <sbbc> property from the /chosen node. If 634 * the pathname matches, this is the master SBBC and 635 * we set up the console/TOD SRAM mapping here. 636 */ 637 static void 638 sbbc_chosen_init(sbbc_softstate_t *softsp) 639 { 640 char master_sbbc[MAXNAMELEN]; 641 char pn[MAXNAMELEN]; 642 int nodeid, len; 643 pnode_t dnode; 644 645 if (master_chosen != FALSE) { 646 /* 647 * We've got one already 648 */ 649 return; 650 } 651 652 /* 653 * Get /chosen node info. prom interface will handle errors. 654 */ 655 dnode = prom_chosennode(); 656 657 /* 658 * Look for the "iosram" property on the chosen node with a prom 659 * interface as ddi_find_devinfo() couldn't be used (calls 660 * ddi_walk_devs() that creates one extra lock on the device tree). 661 */ 662 if (prom_getprop(dnode, IOSRAM_CHOSEN_PROP, (caddr_t)&nodeid) <= 0) { 663 /* 664 * No I/O Board SBBC set up as console, what to do ? 665 */ 666 SBBC_ERR(CE_PANIC, "No SBBC found for Console/TOD \n"); 667 } 668 669 if (prom_getprop(dnode, IOSRAM_TOC_PROP, 670 (caddr_t)&softsp->sram_toc) <= 0) { 671 /* 672 * SRAM TOC Offset defaults to 0 673 */ 674 SBBC_ERR(CE_WARN, "No SBBC TOC Offset found\n"); 675 softsp->sram_toc = 0; 676 } 677 678 /* 679 * get the full OBP pathname of this node 680 */ 681 if (prom_phandle_to_path((phandle_t)nodeid, master_sbbc, 682 sizeof (master_sbbc)) < 0) { 683 684 SBBC_ERR1(CE_PANIC, "prom_phandle_to_path(%d) failed\n", 685 nodeid); 686 } 687 SGSBBC_DBG_ALL("chosen pathname : %s\n", master_sbbc); 688 SGSBBC_DBG_ALL("device pathname : %s\n", ddi_pathname(softsp->dip, pn)); 689 if (strcmp(master_sbbc, ddi_pathname(softsp->dip, pn)) == 0) { 690 691 /* 692 * map in the SBBC regs 693 */ 694 695 if (sbbc_map_regs(softsp) != DDI_SUCCESS) { 696 SBBC_ERR(CE_PANIC, "Can't map the SBBC regs \n"); 697 } 698 /* 699 * Only the 'chosen' node is used for iosram_read()/_write() 700 * Must initialise the tunnel before the console/tod 701 * 702 */ 703 if (iosram_tunnel_init(softsp) == DDI_FAILURE) { 704 SBBC_ERR(CE_PANIC, "Can't create the SRAM <-> SC " 705 "comm. tunnel \n"); 706 } 707 708 master_chosen = TRUE; 709 710 /* 711 * Verify that an 'interrupts' property 712 * exists for this device 713 */ 714 715 if (ddi_getproplen(DDI_DEV_T_ANY, softsp->dip, 716 DDI_PROP_DONTPASS, "interrupts", 717 &len) != DDI_PROP_SUCCESS) { 718 719 SBBC_ERR(CE_PANIC, "No 'interrupts' property for the " 720 "'chosen' SBBC \n"); 721 } 722 723 /* 724 * add the interrupt handler 725 * NB 726 * should this be a high-level interrupt ? 727 * NB 728 */ 729 if (sbbc_add_intr(softsp) == DDI_FAILURE) { 730 SBBC_ERR(CE_PANIC, "Can't add interrupt handler for " 731 "'chosen' SBBC \n"); 732 } 733 734 sbbc_enable_intr(softsp); 735 736 /* 737 * Create the mailbox 738 */ 739 if (sbbc_mbox_create(softsp) != 0) { 740 cmn_err(CE_WARN, "No IOSRAM MailBox created!\n"); 741 } 742 743 } 744 } 745 /* 746 * sbbc_add_instance 747 * Must be called to hold chosen_lock. 748 */ 749 static void 750 sbbc_add_instance(sbbc_softstate_t *softsp) 751 { 752 #ifdef DEBUG 753 struct sbbc_softstate *sp; 754 #endif 755 756 ASSERT(mutex_owned(&chosen_lock)); 757 758 #if defined(DEBUG) 759 /* Verify that this instance is not in the list yet */ 760 for (sp = sgsbbc_instances; sp != NULL; sp = sp->next) { 761 ASSERT(sp != softsp); 762 } 763 #endif 764 765 /* 766 * Add this instance to the front of the list. 767 */ 768 if (sgsbbc_instances != NULL) { 769 sgsbbc_instances->prev = softsp; 770 } 771 772 softsp->next = sgsbbc_instances; 773 softsp->prev = NULL; 774 sgsbbc_instances = softsp; 775 } 776 777 static void 778 sbbc_remove_instance(sbbc_softstate_t *softsp) 779 { 780 struct sbbc_softstate *sp; 781 782 for (sp = sgsbbc_instances; sp != NULL; sp = sp->next) { 783 if (sp == softsp) { 784 if (sp->next != NULL) { 785 sp->next->prev = sp->prev; 786 } 787 if (sp->prev != NULL) { 788 sp->prev->next = sp->next; 789 } 790 if (sgsbbc_instances == softsp) { 791 sgsbbc_instances = sp->next; 792 } 793 break; 794 } 795 } 796 } 797 798 /* 799 * Generate an SBBC interrupt to the SC 800 * Called from iosram_send_intr() 801 * 802 * send_intr == 0, check if EPLD register clear 803 * for sync'ing SC/OS 804 * send_intr == 1, send the interrupt 805 */ 806 int 807 sbbc_send_intr(sbbc_softstate_t *softsp, int send_intr) 808 { 809 810 uchar_t *epld_int; 811 volatile uchar_t epld_status; 812 813 ASSERT(MUTEX_HELD(&master_iosram->iosram_lock)); 814 815 if ((softsp == (sbbc_softstate_t *)NULL) || 816 (softsp->epld_regs == (struct sbbc_epld_regs *)NULL)) 817 return (ENXIO); 818 819 /* 820 * Check the L1 EPLD Interrupt register. If the 821 * interrupt bit is set, theres an interrupt outstanding 822 * (we assume) so return (EBUSY). 823 */ 824 825 epld_int = &softsp->epld_regs->epld_reg[EPLD_INTERRUPT]; 826 827 epld_status = ddi_get8(softsp->sbbc_reg_handle2, epld_int); 828 829 if (epld_status & INTERRUPT_ON) 830 return (EBUSY); 831 832 if (send_intr == TRUE) 833 ddi_put8(softsp->sbbc_reg_handle2, epld_int, 834 (epld_status | INTERRUPT_ON)); 835 836 return (0); 837 } 838 839 /* 840 * Map SBBC Internal registers 841 * 842 * The call to function should be protected by 843 * chosen_lock or master_iosram->iosram_lock 844 * to make sure a tunnel switch will not occur 845 * in a middle of mapping. 846 */ 847 int 848 sbbc_map_regs(sbbc_softstate_t *softsp) 849 { 850 struct ddi_device_acc_attr attr; 851 852 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 853 attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 854 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 855 856 /* 857 * Map in register set 1, Common Device Regs 858 * SBCC offset 0x0 859 */ 860 if (ddi_regs_map_setup(softsp->dip, RNUM_SBBC_REGS, 861 (caddr_t *)&softsp->sbbc_regs, 862 SBBC_REGS_OFFSET, SBBC_REGS_SIZE, 863 &attr, &softsp->sbbc_reg_handle1) != DDI_SUCCESS) { 864 865 cmn_err(CE_WARN, "sbbc%d: unable to map interrupt " 866 "registers", ddi_get_instance(softsp->dip)); 867 return (DDI_FAILURE); 868 } 869 /* 870 * Map in using register set 1, EPLD 871 * SBCC offset 0xe000 872 */ 873 if (ddi_regs_map_setup(softsp->dip, RNUM_SBBC_REGS, 874 (caddr_t *)&softsp->epld_regs, 875 SBBC_EPLD_OFFSET, SBBC_EPLD_SIZE, 876 &attr, &softsp->sbbc_reg_handle2) != DDI_SUCCESS) { 877 878 cmn_err(CE_WARN, "sbbc%d: unable to map EPLD " 879 "registers", ddi_get_instance(softsp->dip)); 880 return (DDI_FAILURE); 881 } 882 883 /* 884 * Set up pointers for registers 885 */ 886 softsp->port_int_regs = (uint32_t *)((char *)softsp->sbbc_regs + 887 SBBC_PCI_INT_STATUS); 888 889 map_regs_exit: 890 return (DDI_SUCCESS); 891 } 892 893 894 /* 895 * Unmap SBBC Internal registers 896 */ 897 static void 898 sbbc_unmap_regs(sbbc_softstate_t *softsp) 899 { 900 if (softsp == NULL) 901 return; 902 903 mutex_enter(&master_iosram->iosram_lock); 904 905 if (softsp->sbbc_regs) { 906 ddi_regs_map_free(&softsp->sbbc_reg_handle1); 907 softsp->sbbc_regs = NULL; 908 softsp->port_int_regs = NULL; 909 } 910 911 if (softsp->epld_regs) { 912 ddi_regs_map_free(&softsp->sbbc_reg_handle2); 913 softsp->epld_regs = NULL; 914 } 915 916 mutex_exit(&master_iosram->iosram_lock); 917 918 return; 919 920 } 921 /* 922 * This is here to allow the IOSRAM driver get the softstate 923 * for a chosen node when doing a tunnel switch. Just enables 924 * us to avoid exporting the sbbcp softstate hook 925 */ 926 sbbc_softstate_t * 927 sbbc_get_soft_state(int instance) 928 { 929 return (ddi_get_soft_state(sbbcp, instance)); 930 } 931 932 /* 933 * Add interrupt handlers 934 */ 935 int 936 sbbc_add_intr(sbbc_softstate_t *softsp) 937 { 938 int rc = DDI_SUCCESS; 939 940 /* 941 * map in the SBBC interrupts 942 * Note that the iblock_cookie was initialised 943 * in the 'attach' routine 944 */ 945 946 if (ddi_add_intr(softsp->dip, 0, &softsp->iblock, 947 &softsp->idevice, sbbc_intr_handler, 948 (caddr_t)softsp) != DDI_SUCCESS) { 949 950 cmn_err(CE_WARN, "Can't register SBBC " 951 " interrupt handler\n"); 952 rc = DDI_FAILURE; 953 } 954 955 return (rc); 956 } 957 958 void 959 sbbc_enable_intr(sbbc_softstate_t *softsp) 960 { 961 uint32_t *pci_intr_enable_reg; 962 963 /* 964 * Enable Interrupts now, turn on both INT#A lines 965 */ 966 pci_intr_enable_reg = (uint32_t *)((char *)softsp->sbbc_regs + 967 SBBC_PCI_INT_ENABLE); 968 ddi_put32(softsp->sbbc_reg_handle1, pci_intr_enable_reg, 969 (uint32_t)SBBC_PCI_ENABLE_INT_A); 970 } 971 972 void 973 sbbc_disable_intr(sbbc_softstate_t *softsp) 974 { 975 uint32_t *pci_intr_enable_reg; 976 977 /* 978 * Disable Interrupts now, turn off both INT#A lines 979 */ 980 pci_intr_enable_reg = (uint32_t *)((char *)softsp->sbbc_regs + 981 SBBC_PCI_INT_ENABLE); 982 ddi_put32(softsp->sbbc_reg_handle1, pci_intr_enable_reg, 0); 983 } 984