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