11708Sstevel /*
21708Sstevel * CDDL HEADER START
31708Sstevel *
41708Sstevel * The contents of this file are subject to the terms of the
51708Sstevel * Common Development and Distribution License (the "License").
61708Sstevel * You may not use this file except in compliance with the License.
71708Sstevel *
81708Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel * or http://www.opensolaris.org/os/licensing.
101708Sstevel * See the License for the specific language governing permissions
111708Sstevel * and limitations under the License.
121708Sstevel *
131708Sstevel * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel *
191708Sstevel * CDDL HEADER END
201708Sstevel */
211708Sstevel
221708Sstevel /*
23*11311SSurya.Prakki@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
241708Sstevel * Use is subject to license terms.
251708Sstevel */
261708Sstevel
271708Sstevel /*
281708Sstevel * Driver for handling Serengeti I/O SRAM
291708Sstevel * for Solaris <-> SC comm.
301708Sstevel */
311708Sstevel
321708Sstevel #include <sys/types.h>
331708Sstevel #include <sys/systm.h>
341708Sstevel #include <sys/cpuvar.h>
351708Sstevel #include <sys/dditypes.h>
361708Sstevel #include <sys/sunndi.h>
371708Sstevel #include <sys/param.h>
381708Sstevel #include <sys/mutex.h>
391708Sstevel #include <sys/sysmacros.h>
401708Sstevel #include <sys/errno.h>
411708Sstevel #include <sys/file.h>
421708Sstevel #include <sys/kmem.h>
431708Sstevel #include <sys/promif.h>
441708Sstevel #include <sys/prom_plat.h>
451708Sstevel #include <sys/sunddi.h>
461708Sstevel #include <sys/ddi.h>
471708Sstevel
481708Sstevel #include <sys/serengeti.h>
491708Sstevel #include <sys/sgsbbc_priv.h>
501708Sstevel #include <sys/sgsbbc_iosram_priv.h>
511708Sstevel #include <sys/sgsbbc_mailbox_priv.h>
521708Sstevel
531708Sstevel /*
541708Sstevel * Local stuff
551708Sstevel */
561708Sstevel static int iosram_rw(int, uint32_t, caddr_t, uint32_t, int);
571708Sstevel static int iosram_convert_key(char *);
581708Sstevel static int iosram_switch_intr(void);
591708Sstevel static int tunnel_init(sbbc_softstate_t *, tunnel_t *);
601708Sstevel static void tunnel_fini(tunnel_t *);
611708Sstevel static void tunnel_commit(sbbc_softstate_t *, tunnel_t *);
621708Sstevel static void clear_break();
631708Sstevel
641708Sstevel #define IOSRAM_GETB(tunnel, buf, sram, count) \
651708Sstevel ddi_rep_get8(tunnel->reg_handle, buf, sram, count, DDI_DEV_AUTOINCR)
661708Sstevel
671708Sstevel #define IOSRAM_PUTB(tunnel, buf, sram, count) \
681708Sstevel ddi_rep_put8(tunnel->reg_handle, buf, sram, count, DDI_DEV_AUTOINCR)
691708Sstevel
701708Sstevel #define IOSRAM_PUT(tunnel, sram, buf, size) \
711708Sstevel /* CSTYLED */ \
721708Sstevel ddi_put##size(tunnel->reg_handle, (uint##size##_t *)sram, \
731708Sstevel /* CSTYLED */ \
741708Sstevel *((uint##size##_t *)buf))
751708Sstevel
761708Sstevel #define IOSRAM_GET(tunnel, sram, buf, size) \
771708Sstevel /* CSTYLED */ \
781708Sstevel *(uint##size##_t *)buf = ddi_get##size(tunnel->reg_handle, \
791708Sstevel /* CSTYLED */ \
801708Sstevel (uint##size##_t *)sram)
811708Sstevel
821708Sstevel /*
831708Sstevel * sgsbbc_iosram_is_chosen(struct sbbc_softstate *softsp)
841708Sstevel *
851708Sstevel * Looks up "chosen" node property to
861708Sstevel * determine if it is the chosen IOSRAM.
871708Sstevel */
881708Sstevel int
sgsbbc_iosram_is_chosen(sbbc_softstate_t * softsp)891708Sstevel sgsbbc_iosram_is_chosen(sbbc_softstate_t *softsp)
901708Sstevel {
911708Sstevel char pn[MAXNAMELEN];
921708Sstevel char chosen_iosram[MAXNAMELEN];
931708Sstevel int nodeid;
941708Sstevel int chosen;
951708Sstevel uint_t tunnel;
961708Sstevel extern pnode_t chosen_nodeid;
971708Sstevel
981708Sstevel ASSERT(chosen_nodeid);
991708Sstevel
1001708Sstevel nodeid = chosen_nodeid;
1011708Sstevel (void) prom_getprop(nodeid, "iosram", (caddr_t)&tunnel);
1021708Sstevel
1031708Sstevel /*
1041708Sstevel * get the full OBP pathname of this node
1051708Sstevel */
1061708Sstevel if (prom_phandle_to_path((phandle_t)tunnel, chosen_iosram,
1071708Sstevel sizeof (chosen_iosram)) < 0) {
1081708Sstevel cmn_err(CE_NOTE, "prom_phandle_to_path(%x) failed\n", tunnel);
1091708Sstevel return (0);
1101708Sstevel }
1111708Sstevel
1121708Sstevel SGSBBC_DBG_ALL("sgsbbc_iosram(%d): prom_phandle_to_path(%x) is '%s'\n",
1131708Sstevel softsp->sbbc_instance, nodeid, chosen_iosram);
1141708Sstevel
1151708Sstevel (void) ddi_pathname(softsp->dip, pn);
1161708Sstevel SGSBBC_DBG_ALL("sgsbbc_iosram(%d): ddi_pathname(%p) is '%s'\n",
117*11311SSurya.Prakki@Sun.COM softsp->sbbc_instance, (void *)softsp->dip, pn);
1181708Sstevel
1191708Sstevel chosen = (strcmp(chosen_iosram, pn) == 0) ? 1 : 0;
1201708Sstevel SGSBBC_DBG_ALL("sgsbbc_iosram(%d): ... %s\n", softsp->sbbc_instance,
121*11311SSurya.Prakki@Sun.COM chosen? "MASTER" : "SLAVE");
1221708Sstevel SGSBBC_DBG_ALL("sgsbbc_iosram(%d): ... %s\n", softsp->sbbc_instance,
123*11311SSurya.Prakki@Sun.COM (chosen ? "MASTER" : "SLAVE"));
1241708Sstevel
1251708Sstevel return (chosen);
1261708Sstevel }
1271708Sstevel
1281708Sstevel void
iosram_init()1291708Sstevel iosram_init()
1301708Sstevel {
1311708Sstevel int i;
1321708Sstevel
1331708Sstevel if ((master_iosram = kmem_zalloc(sizeof (struct chosen_iosram),
1341708Sstevel KM_NOSLEEP)) == NULL) {
1351708Sstevel prom_printf("Can't allocate space for Chosen IOSRAM\n");
1361708Sstevel panic("Can't allocate space for Chosen IOSRAM");
1371708Sstevel }
1381708Sstevel
1391708Sstevel if ((master_iosram->tunnel = kmem_zalloc(sizeof (tunnel_t),
1401708Sstevel KM_NOSLEEP)) == NULL) {
1411708Sstevel prom_printf("Can't allocate space for tunnel\n");
1421708Sstevel panic("Can't allocate space for tunnel");
1431708Sstevel }
1441708Sstevel
1451708Sstevel master_iosram->iosram_sbbc = NULL;
1461708Sstevel
1471708Sstevel for (i = 0; i < SBBC_MAX_KEYS; i++) {
1481708Sstevel master_iosram->tunnel->tunnel_keys[i].key = 0;
1491708Sstevel master_iosram->tunnel->tunnel_keys[i].base = NULL;
1501708Sstevel master_iosram->tunnel->tunnel_keys[i].size = 0;
1511708Sstevel }
1521708Sstevel
1531708Sstevel for (i = 0; i < SBBC_MAX_INTRS; i++)
1541708Sstevel master_iosram->intrs[i].sbbc_handler = NULL;
1551708Sstevel
1561708Sstevel mutex_init(&master_iosram->iosram_lock, NULL, MUTEX_DEFAULT, NULL);
1571708Sstevel rw_init(&master_iosram->tunnel_lock, NULL, RW_DEFAULT, NULL);
1581708Sstevel }
1591708Sstevel void
iosram_fini()1601708Sstevel iosram_fini()
1611708Sstevel {
1621708Sstevel struct tunnel_key *tunnel;
1631708Sstevel int i;
1641708Sstevel
1651708Sstevel rw_destroy(&master_iosram->tunnel_lock);
1661708Sstevel mutex_destroy(&master_iosram->iosram_lock);
1671708Sstevel
1681708Sstevel /*
1691708Sstevel * destroy any tunnel maps
1701708Sstevel */
1711708Sstevel for (i = 0; i < SBBC_MAX_KEYS; i++) {
1721708Sstevel tunnel = &master_iosram->tunnel->tunnel_keys[i];
1731708Sstevel if (tunnel->base != NULL) {
1741708Sstevel ddi_regs_map_free(&tunnel->reg_handle);
1751708Sstevel tunnel->base = NULL;
1761708Sstevel }
1771708Sstevel }
1781708Sstevel
1791708Sstevel kmem_free(master_iosram->tunnel, sizeof (tunnel_t));
1801708Sstevel
1811708Sstevel kmem_free(master_iosram, sizeof (struct chosen_iosram));
1821708Sstevel
1831708Sstevel master_iosram = NULL;
1841708Sstevel }
1851708Sstevel
1861708Sstevel static void
check_iosram_ver(uint16_t version)1871708Sstevel check_iosram_ver(uint16_t version)
1881708Sstevel {
1891708Sstevel uint8_t max_ver = MAX_IOSRAM_TOC_VER;
1901708Sstevel uint8_t major_ver =
1911708Sstevel (version >> IOSRAM_TOC_VER_SHIFT) & IOSRAM_TOC_VER_MASK;
1921708Sstevel
1931708Sstevel SGSBBC_DBG_ALL("IOSRAM TOC version: %d.%d\n", major_ver,
1941708Sstevel version & IOSRAM_TOC_VER_MASK);
1951708Sstevel SGSBBC_DBG_ALL("Max supported IOSRAM TOC version: %d\n", max_ver);
1961708Sstevel if (major_ver > max_ver) {
1971708Sstevel panic("Up-rev System Controller version.\n"
1981708Sstevel "You must restore an earlier revision of System "
1991708Sstevel "Controller firmware, or upgrade Solaris.\n"
2001708Sstevel "Please consult the System Controller release notice "
2011708Sstevel "for additional details.");
2021708Sstevel }
2031708Sstevel }
2041708Sstevel
2051708Sstevel static void
tunnel_commit(sbbc_softstate_t * softsp,tunnel_t * new_tunnel)2061708Sstevel tunnel_commit(sbbc_softstate_t *softsp, tunnel_t *new_tunnel)
2071708Sstevel {
2081708Sstevel ASSERT(MUTEX_HELD(&master_iosram->iosram_lock));
2091708Sstevel
2101708Sstevel master_iosram->iosram_sbbc = softsp;
2111708Sstevel master_iosram->tunnel = new_tunnel;
2121708Sstevel softsp->chosen = TRUE;
2131708Sstevel
2141708Sstevel /*
2151708Sstevel * SBBC has pointer to interrupt handlers for simplicity
2161708Sstevel */
2171708Sstevel softsp->intr_hdlrs = master_iosram->intrs;
2181708Sstevel }
2191708Sstevel
2201708Sstevel static int
tunnel_init(sbbc_softstate_t * softsp,tunnel_t * new_tunnel)2211708Sstevel tunnel_init(sbbc_softstate_t *softsp, tunnel_t *new_tunnel)
2221708Sstevel {
2231708Sstevel struct iosram_toc *toc = NULL;
2241708Sstevel int i, key;
2251708Sstevel struct tunnel_key *tunnel;
2261708Sstevel ddi_acc_handle_t toc_handle;
2271708Sstevel struct ddi_device_acc_attr attr;
2281708Sstevel
2291708Sstevel ASSERT(MUTEX_HELD(&master_iosram->iosram_lock));
2301708Sstevel
2311708Sstevel if ((softsp == (sbbc_softstate_t *)NULL) ||
2321708Sstevel (new_tunnel == (tunnel_t *)NULL)) {
2331708Sstevel
2341708Sstevel return (DDI_FAILURE);
2351708Sstevel }
2361708Sstevel
2371708Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
2381708Sstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
2391708Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
2401708Sstevel
2411708Sstevel SGSBBC_DBG_ALL("map in the IOSRAM TOC at offset %x\n",
2421708Sstevel softsp->sram_toc);
2431708Sstevel
2441708Sstevel /*
2451708Sstevel * First map in the TOC, then set up the tunnel
2461708Sstevel */
2471708Sstevel if (ddi_regs_map_setup(softsp->dip, RNUM_SBBC_REGS,
2481708Sstevel (caddr_t *)&toc,
2491708Sstevel SBBC_SRAM_OFFSET + softsp->sram_toc,
2501708Sstevel sizeof (struct iosram_toc),
2511708Sstevel &attr, &toc_handle) != DDI_SUCCESS) {
2521708Sstevel cmn_err(CE_WARN, "sbbc%d: unable to map SRAM "
2531708Sstevel "registers", ddi_get_instance(softsp->dip));
2541708Sstevel return (DDI_FAILURE);
2551708Sstevel }
256*11311SSurya.Prakki@Sun.COM SGSBBC_DBG_ALL("dip=%p mapped TOC %p\n", (void *)softsp->dip,
257*11311SSurya.Prakki@Sun.COM (void *)toc);
2581708Sstevel
2591708Sstevel check_iosram_ver(toc->iosram_version);
2601708Sstevel
2611708Sstevel for (i = 0; i < toc->iosram_tagno; i++) {
2621708Sstevel key = iosram_convert_key(toc->iosram_keys[i].key);
2631708Sstevel if ((key > 0) && (key < SBBC_MAX_KEYS)) {
2641708Sstevel tunnel = &new_tunnel->tunnel_keys[key];
2651708Sstevel tunnel->key = key;
2661708Sstevel tunnel->size = toc->iosram_keys[i].size;
2671708Sstevel /*
2681708Sstevel * map in the SRAM area using the offset
2691708Sstevel * from the base of SRAM + SRAM offset into
2701708Sstevel * the register property for the SBBC base
2711708Sstevel * address
2721708Sstevel */
2731708Sstevel if (ddi_regs_map_setup(softsp->dip, RNUM_SBBC_REGS,
2741708Sstevel (caddr_t *)&tunnel->base,
2751708Sstevel SBBC_SRAM_OFFSET + toc->iosram_keys[i].offset,
2761708Sstevel toc->iosram_keys[i].size, &attr,
2771708Sstevel &tunnel->reg_handle) != DDI_SUCCESS) {
2781708Sstevel cmn_err(CE_WARN, "sbbc%d: unable to map SRAM "
2791708Sstevel "registers", ddi_get_instance(softsp->dip));
2801708Sstevel return (DDI_FAILURE);
2811708Sstevel }
2821708Sstevel SGSBBC_DBG_ALL("%d: key %s size %d offset %x addr %p\n",
283*11311SSurya.Prakki@Sun.COM i, toc->iosram_keys[i].key,
284*11311SSurya.Prakki@Sun.COM toc->iosram_keys[i].size,
285*11311SSurya.Prakki@Sun.COM toc->iosram_keys[i].offset,
286*11311SSurya.Prakki@Sun.COM (void *)tunnel->base);
2871708Sstevel
2881708Sstevel }
2891708Sstevel }
2901708Sstevel
2911708Sstevel
2921708Sstevel if (toc != NULL) {
2931708Sstevel ddi_regs_map_free(&toc_handle);
2941708Sstevel }
2951708Sstevel
2961708Sstevel /*
2971708Sstevel * Set up the 'interrupt reason' SRAM pointers
2981708Sstevel * for the SBBC interrupt handler
2991708Sstevel */
3001708Sstevel if (INVALID_KEY(new_tunnel, SBBC_SC_INTR_KEY)) {
3011708Sstevel /*
3021708Sstevel * Can't really do much if these are not here
3031708Sstevel */
3041708Sstevel prom_printf("No Interrupt Reason Fields set by SC\n");
3051708Sstevel cmn_err(CE_WARN, "No Interrupt Reason Fields set by SC");
3061708Sstevel return (DDI_FAILURE);
3071708Sstevel }
3081708Sstevel
3091708Sstevel return (DDI_SUCCESS);
3101708Sstevel }
3111708Sstevel
3121708Sstevel /*
3131708Sstevel * Unmap a tunnel
3141708Sstevel */
3151708Sstevel static void
tunnel_fini(tunnel_t * tunnel)3161708Sstevel tunnel_fini(tunnel_t *tunnel)
3171708Sstevel {
3181708Sstevel int i;
3191708Sstevel struct tunnel_key *tunnel_key;
3201708Sstevel
3211708Sstevel /*
3221708Sstevel * Unmap the tunnel
3231708Sstevel */
3241708Sstevel for (i = 0; i < SBBC_MAX_KEYS; i++) {
3251708Sstevel tunnel_key = &tunnel->tunnel_keys[i];
3261708Sstevel if (tunnel_key->base != NULL) {
3271708Sstevel ddi_regs_map_free(&tunnel_key->reg_handle);
3281708Sstevel tunnel_key->base = NULL;
3291708Sstevel }
3301708Sstevel }
3311708Sstevel }
3321708Sstevel
3331708Sstevel static void
clear_break()3341708Sstevel clear_break()
3351708Sstevel {
3361708Sstevel struct tunnel_key tunnel_key;
3371708Sstevel uint32_t *intr_in_reason;
3381708Sstevel ddi_acc_handle_t intr_in_handle;
3391708Sstevel
3401708Sstevel ASSERT(MUTEX_HELD(&master_iosram->iosram_lock));
3411708Sstevel
3421708Sstevel tunnel_key = master_iosram->tunnel->tunnel_keys[SBBC_SC_INTR_KEY];
3431708Sstevel intr_in_reason = (uint32_t *)tunnel_key.base;
3441708Sstevel intr_in_handle = tunnel_key.reg_handle;
3451708Sstevel ddi_put32(intr_in_handle, intr_in_reason,
3461708Sstevel ddi_get32(intr_in_handle, intr_in_reason) & ~SBBC_CONSOLE_BRK);
3471708Sstevel }
3481708Sstevel
3491708Sstevel int
iosram_tunnel_init(sbbc_softstate_t * softsp)3501708Sstevel iosram_tunnel_init(sbbc_softstate_t *softsp)
3511708Sstevel {
3521708Sstevel int rc;
3531708Sstevel
3541708Sstevel ASSERT(master_iosram);
3551708Sstevel
3561708Sstevel mutex_enter(&master_iosram->iosram_lock);
3571708Sstevel
3581708Sstevel if ((rc = tunnel_init(softsp, master_iosram->tunnel)) == DDI_SUCCESS) {
3591708Sstevel tunnel_commit(softsp, master_iosram->tunnel);
3601708Sstevel clear_break();
3611708Sstevel }
3621708Sstevel
3631708Sstevel
3641708Sstevel mutex_exit(&master_iosram->iosram_lock);
3651708Sstevel
3661708Sstevel return (rc);
3671708Sstevel }
3681708Sstevel
3691708Sstevel int
iosram_read(int key,uint32_t offset,caddr_t buf,uint32_t size)3701708Sstevel iosram_read(int key, uint32_t offset, caddr_t buf, uint32_t size)
3711708Sstevel {
3721708Sstevel return (iosram_rw(key, offset, buf, size, FREAD));
3731708Sstevel }
3741708Sstevel
3751708Sstevel int
iosram_write(int key,uint32_t offset,caddr_t buf,uint32_t size)3761708Sstevel iosram_write(int key, uint32_t offset, caddr_t buf, uint32_t size)
3771708Sstevel {
3781708Sstevel return (iosram_rw(key, offset, buf, size, FWRITE));
3791708Sstevel }
3801708Sstevel
3811708Sstevel
3821708Sstevel static int
iosram_rw(int key,uint32_t offset,caddr_t buf,uint32_t size,int flag)3831708Sstevel iosram_rw(int key, uint32_t offset, caddr_t buf, uint32_t size, int flag)
3841708Sstevel {
3851708Sstevel struct tunnel_key *tunnel;
3861708Sstevel caddr_t sram_src;
3871708Sstevel
3881708Sstevel /*
3891708Sstevel * Return right away if there is nothing to read/write.
3901708Sstevel */
3911708Sstevel if (size == 0)
3921708Sstevel return (0);
3931708Sstevel
3941708Sstevel rw_enter(&master_iosram->tunnel_lock, RW_READER);
3951708Sstevel
3961708Sstevel /*
3971708Sstevel * Key not matched ?
3981708Sstevel */
3991708Sstevel if (INVALID_KEY(master_iosram->tunnel, key)) {
4001708Sstevel rw_exit(&master_iosram->tunnel_lock);
4011708Sstevel return (ENXIO);
4021708Sstevel }
4031708Sstevel
4041708Sstevel tunnel = &master_iosram->tunnel->tunnel_keys[key];
4051708Sstevel if ((offset + size) > tunnel->size) {
4061708Sstevel rw_exit(&master_iosram->tunnel_lock);
4071708Sstevel return (EFBIG);
4081708Sstevel }
4091708Sstevel
4101708Sstevel sram_src = tunnel->base + offset;
4111708Sstevel
4121708Sstevel /*
4131708Sstevel * Atomic reads/writes might be necessary for some clients.
4141708Sstevel * We assume that such clients could guarantee their buffers
4151708Sstevel * are aligned at the boundary of the request sizes. We also
4161708Sstevel * assume that the source/destination of such requests are
4171708Sstevel * aligned at the right boundaries in IOSRAM. If either
4181708Sstevel * condition fails, byte access is performed.
4191708Sstevel */
4201708Sstevel if (flag == FREAD) {
4211708Sstevel switch (size) {
4221708Sstevel case sizeof (uint16_t):
4231708Sstevel case sizeof (uint32_t):
4241708Sstevel case sizeof (uint64_t):
4251708Sstevel if (IS_P2ALIGNED(sram_src, size) &&
4261708Sstevel IS_P2ALIGNED(buf, size)) {
4271708Sstevel
4281708Sstevel if (size == sizeof (uint16_t))
4291708Sstevel IOSRAM_GET(tunnel, sram_src, buf, 16);
4301708Sstevel else if (size == sizeof (uint32_t))
4311708Sstevel IOSRAM_GET(tunnel, sram_src, buf, 32);
4321708Sstevel else
4331708Sstevel IOSRAM_GET(tunnel, sram_src, buf, 64);
4341708Sstevel break;
4351708Sstevel }
4361708Sstevel /* FALLTHRU */
4371708Sstevel default:
4381708Sstevel IOSRAM_GETB(tunnel, (uint8_t *)buf,
4391708Sstevel (uint8_t *)sram_src, (size_t)size);
4401708Sstevel break;
4411708Sstevel }
4421708Sstevel } else {
4431708Sstevel switch (size) {
4441708Sstevel case sizeof (uint16_t):
4451708Sstevel case sizeof (uint32_t):
4461708Sstevel case sizeof (uint64_t):
4471708Sstevel if (IS_P2ALIGNED(sram_src, size) &&
4481708Sstevel IS_P2ALIGNED(buf, size)) {
4491708Sstevel
4501708Sstevel if (size == sizeof (uint16_t))
4511708Sstevel IOSRAM_PUT(tunnel, sram_src, buf, 16);
4521708Sstevel else if (size == sizeof (uint32_t))
4531708Sstevel IOSRAM_PUT(tunnel, sram_src, buf, 32);
4541708Sstevel else
4551708Sstevel IOSRAM_PUT(tunnel, sram_src, buf, 64);
4561708Sstevel break;
4571708Sstevel }
4581708Sstevel /* FALLTHRU */
4591708Sstevel default:
4601708Sstevel IOSRAM_PUTB(tunnel, (uint8_t *)buf,
4611708Sstevel (uint8_t *)sram_src, (size_t)size);
4621708Sstevel break;
4631708Sstevel }
4641708Sstevel }
4651708Sstevel
4661708Sstevel rw_exit(&master_iosram->tunnel_lock);
4671708Sstevel return (0);
4681708Sstevel
4691708Sstevel }
4701708Sstevel
4711708Sstevel int
iosram_size(int key)4721708Sstevel iosram_size(int key)
4731708Sstevel {
4741708Sstevel int size = -1;
4751708Sstevel
4761708Sstevel rw_enter(&master_iosram->tunnel_lock, RW_READER);
4771708Sstevel
4781708Sstevel /*
4791708Sstevel * Key not matched ?
4801708Sstevel */
4811708Sstevel if (!INVALID_KEY(master_iosram->tunnel, key))
4821708Sstevel size = master_iosram->tunnel->tunnel_keys[key].size;
4831708Sstevel
4841708Sstevel rw_exit(&master_iosram->tunnel_lock);
4851708Sstevel
4861708Sstevel return (size);
4871708Sstevel }
4881708Sstevel
4891708Sstevel /*
4901708Sstevel * Generate an interrupt to the SC using the SBBC EPLD
4911708Sstevel *
4921708Sstevel * Note: intr_num can be multiple interrupts OR'ed together
4931708Sstevel */
4941708Sstevel int
iosram_send_intr(uint32_t intr_num)4951708Sstevel iosram_send_intr(uint32_t intr_num)
4961708Sstevel {
4971708Sstevel
4981708Sstevel int rc = 0;
4991708Sstevel uint32_t intr_reason;
5001708Sstevel uint32_t intr_enabled;
5011708Sstevel
5021708Sstevel /*
5031708Sstevel * Verify that we have already set up the master sbbc
5041708Sstevel */
5051708Sstevel if (master_iosram == NULL)
5061708Sstevel return (ENXIO);
5071708Sstevel
5081708Sstevel /*
5091708Sstevel * Grab the lock to prevent tunnel switch in the middle
5101708Sstevel * of sending an interrupt.
5111708Sstevel */
5121708Sstevel mutex_enter(&master_iosram->iosram_lock);
5131708Sstevel
5141708Sstevel if (master_iosram->iosram_sbbc == NULL) {
5151708Sstevel rc = ENXIO;
5161708Sstevel goto send_intr_exit;
5171708Sstevel }
5181708Sstevel
5191708Sstevel if ((rc = sbbc_send_intr(master_iosram->iosram_sbbc, FALSE)) != 0) {
5201708Sstevel /*
5211708Sstevel * previous interrupts have not been cleared yet by the SC
5221708Sstevel */
5231708Sstevel goto send_intr_exit;
5241708Sstevel }
5251708Sstevel
5261708Sstevel /*
5271708Sstevel * Set a bit in the interrupt reason field
5281708Sstevel * call back into the sbbc handler to hit the EPLD
5291708Sstevel *
5301708Sstevel * First check the interrupts enabled by the SC
5311708Sstevel */
5321708Sstevel if ((rc = iosram_read(SBBC_INTR_SC_ENABLED_KEY, 0,
5331708Sstevel (caddr_t)&intr_enabled, sizeof (intr_enabled))) != 0) {
5341708Sstevel
5351708Sstevel goto send_intr_exit;
5361708Sstevel }
5371708Sstevel
5381708Sstevel if ((intr_enabled & intr_num) != intr_num) {
5391708Sstevel /*
5401708Sstevel * at least one of the interrupts is
5411708Sstevel * not enabled by the SC
5421708Sstevel */
5431708Sstevel rc = ENOTSUP;
5441708Sstevel goto send_intr_exit;
5451708Sstevel }
5461708Sstevel
5471708Sstevel if ((rc = iosram_read(SBBC_INTR_SC_KEY, 0,
5481708Sstevel (caddr_t)&intr_reason, sizeof (intr_reason))) != 0) {
5491708Sstevel
5501708Sstevel goto send_intr_exit;
5511708Sstevel }
5521708Sstevel
5531708Sstevel if ((intr_reason & intr_num) == intr_num) {
5541708Sstevel /*
5551708Sstevel * All interrupts specified are already pending
5561708Sstevel */
5571708Sstevel rc = EBUSY;
5581708Sstevel goto send_intr_exit;
5591708Sstevel }
5601708Sstevel
5611708Sstevel intr_reason |= intr_num;
5621708Sstevel
5631708Sstevel if ((rc = iosram_write(SBBC_INTR_SC_KEY, 0,
5641708Sstevel (caddr_t)&intr_reason, sizeof (intr_reason))) != 0) {
5651708Sstevel
5661708Sstevel goto send_intr_exit;
5671708Sstevel }
5681708Sstevel
5691708Sstevel /*
5701708Sstevel * Hit the EPLD interrupt bit
5711708Sstevel */
5721708Sstevel
5731708Sstevel rc = sbbc_send_intr(master_iosram->iosram_sbbc, TRUE);
5741708Sstevel
5751708Sstevel send_intr_exit:
5761708Sstevel
5771708Sstevel mutex_exit(&master_iosram->iosram_lock);
5781708Sstevel
5791708Sstevel return (rc);
5801708Sstevel }
5811708Sstevel
5821708Sstevel /*
5831708Sstevel * Register an interrupt handler
5841708Sstevel */
5851708Sstevel int
iosram_reg_intr(uint32_t intr_num,sbbc_intrfunc_t intr_handler,caddr_t arg,uint_t * state,kmutex_t * lock)5861708Sstevel iosram_reg_intr(uint32_t intr_num, sbbc_intrfunc_t intr_handler,
5871708Sstevel caddr_t arg, uint_t *state, kmutex_t *lock)
5881708Sstevel {
5891708Sstevel sbbc_softstate_t *softsp;
5901708Sstevel int rc = 0;
5911708Sstevel sbbc_intrs_t *intr;
5921708Sstevel int intr_no;
5931708Sstevel uint32_t intr_enabled;
5941708Sstevel
5951708Sstevel /*
5961708Sstevel * Verify that we have already set up the master sbbc
5971708Sstevel */
5981708Sstevel if (master_iosram == NULL)
5991708Sstevel return (ENXIO);
6001708Sstevel
6011708Sstevel /*
6021708Sstevel * determine which bit is this intr_num for ?
6031708Sstevel */
6041708Sstevel for (intr_no = 0; intr_no < SBBC_MAX_INTRS; intr_no++) {
6051708Sstevel if (intr_num == (1 << intr_no))
6061708Sstevel break;
6071708Sstevel }
6081708Sstevel
6091708Sstevel /*
6101708Sstevel * Check the parameters
6111708Sstevel */
6121708Sstevel if ((intr_no < 0) || (intr_no >= SBBC_MAX_INTRS) ||
6131708Sstevel (intr_handler == NULL) || (state == NULL) ||
6141708Sstevel (lock == NULL))
6151708Sstevel return (EINVAL);
6161708Sstevel
6171708Sstevel mutex_enter(&master_iosram->iosram_lock);
6181708Sstevel
6191708Sstevel if ((softsp = master_iosram->iosram_sbbc) == NULL) {
6201708Sstevel mutex_exit(&master_iosram->iosram_lock);
6211708Sstevel return (ENXIO);
6221708Sstevel }
6231708Sstevel
6241708Sstevel mutex_enter(&softsp->sbbc_lock);
6251708Sstevel
6261708Sstevel intr = &master_iosram->intrs[intr_no];
6271708Sstevel
6281708Sstevel if (intr->sbbc_handler != (sbbc_intrfunc_t)NULL) {
6291708Sstevel rc = EBUSY;
6301708Sstevel goto reg_intr_exit;
6311708Sstevel }
6321708Sstevel
6331708Sstevel intr->sbbc_handler = intr_handler;
6341708Sstevel intr->sbbc_arg = (void *)arg;
6351708Sstevel intr->sbbc_intr_state = state;
6361708Sstevel intr->sbbc_intr_lock = lock;
6371708Sstevel intr->sbbc_intr_next = (sbbc_intrs_t *)NULL;
6381708Sstevel
6391708Sstevel /*
6401708Sstevel * we need to make sure that the mutex is for
6411708Sstevel * an ADAPTIVE lock, so call mutex_init() again with
6421708Sstevel * the sbbc iblock cookie
6431708Sstevel */
6441708Sstevel mutex_init(lock, NULL, MUTEX_DRIVER,
6451708Sstevel (void *)softsp->iblock);
6461708Sstevel
6471708Sstevel if (ddi_add_softintr(softsp->dip, DDI_SOFTINT_HIGH,
6481708Sstevel &intr->sbbc_intr_id, NULL, NULL,
6491708Sstevel intr_handler, (caddr_t)arg) != DDI_SUCCESS) {
6501708Sstevel
6511708Sstevel cmn_err(CE_WARN, "Can't add SBBC softint");
6521708Sstevel rc = EAGAIN;
6531708Sstevel goto reg_intr_exit;
6541708Sstevel }
6551708Sstevel
6561708Sstevel /*
6571708Sstevel * Set the bit in the Interrupts Enabled Field for this
6581708Sstevel * interrupt
6591708Sstevel */
6601708Sstevel if ((rc = iosram_read(SBBC_SC_INTR_ENABLED_KEY, 0,
6611708Sstevel (caddr_t)&intr_enabled, sizeof (intr_enabled))) != 0) {
6621708Sstevel
6631708Sstevel goto reg_intr_exit;
6641708Sstevel }
6651708Sstevel
6661708Sstevel intr_enabled |= intr_num;
6671708Sstevel
6681708Sstevel if ((rc = iosram_write(SBBC_SC_INTR_ENABLED_KEY, 0,
6691708Sstevel (caddr_t)&intr_enabled, sizeof (intr_enabled))) != 0) {
6701708Sstevel
6711708Sstevel goto reg_intr_exit;
6721708Sstevel }
6731708Sstevel
6741708Sstevel reg_intr_exit:
6751708Sstevel
6761708Sstevel mutex_exit(&softsp->sbbc_lock);
6771708Sstevel mutex_exit(&master_iosram->iosram_lock);
6781708Sstevel
6791708Sstevel return (rc);
6801708Sstevel }
6811708Sstevel
6821708Sstevel /*
6831708Sstevel * Remove an interrupt handler
6841708Sstevel */
6851708Sstevel int
iosram_unreg_intr(uint32_t intr_num)6861708Sstevel iosram_unreg_intr(uint32_t intr_num)
6871708Sstevel {
6881708Sstevel sbbc_softstate_t *softsp;
6891708Sstevel int rc = 0;
6901708Sstevel sbbc_intrs_t *intr;
6911708Sstevel int intr_no;
6921708Sstevel uint32_t intr_enabled;
6931708Sstevel
6941708Sstevel /*
6951708Sstevel * Verify that we have already set up the master sbbc
6961708Sstevel */
6971708Sstevel if (master_iosram == NULL)
6981708Sstevel return (ENXIO);
6991708Sstevel
7001708Sstevel /*
7011708Sstevel * determine which bit is this intr_num for ?
7021708Sstevel */
7031708Sstevel for (intr_no = 0; intr_no < SBBC_MAX_INTRS; intr_no++) {
7041708Sstevel if (intr_num == (1 << intr_no))
7051708Sstevel break;
7061708Sstevel }
7071708Sstevel
7081708Sstevel if ((intr_no < 0) || (intr_no >= SBBC_MAX_INTRS))
7091708Sstevel return (EINVAL);
7101708Sstevel
7111708Sstevel mutex_enter(&master_iosram->iosram_lock);
7121708Sstevel
7131708Sstevel if ((softsp = master_iosram->iosram_sbbc) == NULL) {
7141708Sstevel mutex_exit(&master_iosram->iosram_lock);
7151708Sstevel return (ENXIO);
7161708Sstevel }
7171708Sstevel
7181708Sstevel mutex_enter(&softsp->sbbc_lock);
7191708Sstevel
7201708Sstevel intr = &master_iosram->intrs[intr_no];
7211708Sstevel
7221708Sstevel /*
7231708Sstevel * No handler installed
7241708Sstevel */
7251708Sstevel if (intr->sbbc_handler == (sbbc_intrfunc_t)NULL) {
7261708Sstevel rc = EINVAL;
7271708Sstevel goto unreg_intr_exit;
7281708Sstevel }
7291708Sstevel
7301708Sstevel /*
7311708Sstevel * Unset the bit in the Interrupts Enabled Field for this
7321708Sstevel * interrupt
7331708Sstevel */
7341708Sstevel if ((rc = iosram_read(SBBC_SC_INTR_ENABLED_KEY, 0,
7351708Sstevel (caddr_t)&intr_enabled, sizeof (intr_enabled))) != 0) {
7361708Sstevel
7371708Sstevel goto unreg_intr_exit;
7381708Sstevel }
7391708Sstevel
7401708Sstevel intr_enabled &= ~intr_num;
7411708Sstevel
7421708Sstevel if ((rc = iosram_write(SBBC_SC_INTR_ENABLED_KEY, 0,
7431708Sstevel (caddr_t)&intr_enabled, sizeof (intr_enabled))) != 0) {
7441708Sstevel
7451708Sstevel goto unreg_intr_exit;
7461708Sstevel }
7471708Sstevel
7481708Sstevel /*
7491708Sstevel * If handler is running, wait until it's done.
7501708Sstevel * It won't get triggered again because we disabled it above.
7511708Sstevel * When we wait, drop sbbc_lock so other interrupt handlers
7521708Sstevel * can still run.
7531708Sstevel */
7541708Sstevel for (; ; ) {
7551708Sstevel mutex_enter(intr->sbbc_intr_lock);
7561708Sstevel if (*(intr->sbbc_intr_state) != SBBC_INTR_IDLE) {
7571708Sstevel mutex_exit(intr->sbbc_intr_lock);
7581708Sstevel mutex_exit(&softsp->sbbc_lock);
7591708Sstevel delay(drv_usectohz(10000));
7601708Sstevel mutex_enter(&softsp->sbbc_lock);
7611708Sstevel mutex_enter(intr->sbbc_intr_lock);
7621708Sstevel } else {
7631708Sstevel break;
7641708Sstevel }
7651708Sstevel mutex_exit(intr->sbbc_intr_lock);
7661708Sstevel }
7671708Sstevel
7681708Sstevel if (intr->sbbc_intr_id)
7691708Sstevel ddi_remove_softintr(intr->sbbc_intr_id);
7701708Sstevel
7711708Sstevel intr->sbbc_handler = (sbbc_intrfunc_t)NULL;
7721708Sstevel intr->sbbc_arg = (void *)NULL;
7731708Sstevel intr->sbbc_intr_id = 0;
7741708Sstevel intr->sbbc_intr_state = NULL;
7751708Sstevel intr->sbbc_intr_lock = (kmutex_t *)NULL;
7761708Sstevel intr->sbbc_intr_next = (sbbc_intrs_t *)NULL;
7771708Sstevel
7781708Sstevel unreg_intr_exit:
7791708Sstevel
7801708Sstevel mutex_exit(&softsp->sbbc_lock);
7811708Sstevel mutex_exit(&master_iosram->iosram_lock);
7821708Sstevel
7831708Sstevel return (rc);
7841708Sstevel }
7851708Sstevel
7861708Sstevel /*
7871708Sstevel * sgsbbc_iosram_switchfrom(softsp)
7881708Sstevel * Switch master tunnel away from the specified instance.
7891708Sstevel */
7901708Sstevel int
sgsbbc_iosram_switchfrom(struct sbbc_softstate * softsp)7911708Sstevel sgsbbc_iosram_switchfrom(struct sbbc_softstate *softsp)
7921708Sstevel {
7931708Sstevel struct sbbc_softstate *sp;
7941708Sstevel int rv = DDI_FAILURE;
7951708Sstevel int new_instance;
7961708Sstevel
7971708Sstevel /*
7981708Sstevel * Find the candidate target of tunnel from the linked list.
7991708Sstevel */
8001708Sstevel mutex_enter(&chosen_lock);
8011708Sstevel ASSERT(sgsbbc_instances);
8021708Sstevel
8031708Sstevel for (sp = sgsbbc_instances; sp != NULL; sp = sp->next) {
8041708Sstevel if (softsp == sp)
8051708Sstevel continue;
8061708Sstevel
8071708Sstevel if (sp->sbbc_state & SBBC_STATE_DETACH)
8081708Sstevel continue;
8091708Sstevel break;
8101708Sstevel }
8111708Sstevel if (sp == NULL) {
8121708Sstevel /* at least one IOSRAM should be attached */
8131708Sstevel rv = DDI_FAILURE;
8141708Sstevel } else {
8151708Sstevel /* Do the tunnel switch */
8161708Sstevel new_instance = ddi_get_instance(sp->dip);
8171708Sstevel rv = iosram_switch_tunnel(new_instance);
8181708Sstevel if (rv == DDI_SUCCESS) {
8191708Sstevel /* reset the chosen_iosram back ref */
8201708Sstevel sp->iosram = master_iosram;
8211708Sstevel }
8221708Sstevel }
8231708Sstevel mutex_exit(&chosen_lock);
8241708Sstevel return (rv);
8251708Sstevel }
8261708Sstevel
8271708Sstevel
8281708Sstevel /*
8291708Sstevel * Switch the tunnel to a different I/O board.
8301708Sstevel * At the moment, we will say that this is
8311708Sstevel * called with the instance of the SBBC to switch
8321708Sstevel * to. This will probably change, but as long as we
8331708Sstevel * can get a devinfo/softstate for the target SBBC it
8341708Sstevel * doesn't matter what the parameter is.
8351708Sstevel */
8361708Sstevel int
iosram_switch_tunnel(int instance)8371708Sstevel iosram_switch_tunnel(int instance)
8381708Sstevel {
8391708Sstevel
8401708Sstevel sbbc_softstate_t *to_softsp, *from_softsp;
8411708Sstevel dev_info_t *pdip; /* parent dip */
8421708Sstevel tunnel_t *new_tunnel; /* new tunnel */
8431708Sstevel int portid;
8441708Sstevel uint_t node; /* node id to pass to OBP */
8451708Sstevel uint_t board; /* board number to pass to OBP */
8461708Sstevel int rc = DDI_SUCCESS;
8471708Sstevel static fn_t f = "iosram_switch_tunnel";
8481708Sstevel
8491708Sstevel /* Check the firmware for tunnel switch support */
8501708Sstevel if (prom_test("SUNW,switch-tunnel") != 0) {
8511708Sstevel cmn_err(CE_WARN, "Firmware does not support tunnel switch");
8521708Sstevel return (DDI_FAILURE);
8531708Sstevel }
8541708Sstevel
8551708Sstevel if ((master_iosram == NULL) || (master_mbox == NULL))
8561708Sstevel return (DDI_FAILURE);
8571708Sstevel
8581708Sstevel if (!(to_softsp = sbbc_get_soft_state(instance)))
8591708Sstevel return (DDI_FAILURE);
8601708Sstevel
8611708Sstevel /*
8621708Sstevel * create the new tunnel
8631708Sstevel */
8641708Sstevel if ((new_tunnel = kmem_zalloc(sizeof (tunnel_t), KM_NOSLEEP)) == NULL) {
8651708Sstevel cmn_err(CE_WARN, "Can't allocate space for new tunnel");
8661708Sstevel return (DDI_FAILURE);
8671708Sstevel }
8681708Sstevel
8691708Sstevel pdip = ddi_get_parent(to_softsp->dip);
8701708Sstevel if ((portid = ddi_getprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
8711708Sstevel "portid", -1)) < 0) {
8721708Sstevel
8731708Sstevel SGSBBC_DBG_ALL("%s: couldn't get portid\n", f);
8741708Sstevel return (DDI_FAILURE);
8751708Sstevel }
8761708Sstevel
8771708Sstevel /*
8781708Sstevel * Compute node id and board number from port id
8791708Sstevel */
8801708Sstevel node = SG_PORTID_TO_NODEID(portid);
8811708Sstevel board = SG_IO_BD_PORTID_TO_BD_NUM(portid);
8821708Sstevel
8831708Sstevel /*
8841708Sstevel * lock the chosen IOSRAM
8851708Sstevel */
8861708Sstevel mutex_enter(&master_iosram->iosram_lock);
8871708Sstevel
8881708Sstevel if (master_iosram->iosram_sbbc == NULL) {
8891708Sstevel mutex_exit(&master_iosram->iosram_lock);
8901708Sstevel return (DDI_FAILURE);
8911708Sstevel }
8921708Sstevel
8931708Sstevel /*
8941708Sstevel * If the target SBBC has not mapped in its
8951708Sstevel * register address space, do it now
8961708Sstevel */
8971708Sstevel mutex_enter(&to_softsp->sbbc_lock);
8981708Sstevel if (to_softsp->sbbc_regs == NULL) {
8991708Sstevel if (sbbc_map_regs(to_softsp) != DDI_SUCCESS) {
9001708Sstevel mutex_exit(&to_softsp->sbbc_lock);
9011708Sstevel mutex_exit(&master_iosram->iosram_lock);
9021708Sstevel return (DDI_FAILURE);
9031708Sstevel }
9041708Sstevel }
9051708Sstevel
9061708Sstevel /*
9071708Sstevel * Get a pointer to the current sbbc
9081708Sstevel */
9091708Sstevel from_softsp = master_iosram->iosram_sbbc;
9101708Sstevel
9111708Sstevel mutex_enter(&from_softsp->sbbc_lock);
9121708Sstevel
9131708Sstevel /*
9141708Sstevel * Disable interrupts from the SC now
9151708Sstevel */
9161708Sstevel sbbc_disable_intr(from_softsp);
9171708Sstevel
9181708Sstevel /*
9191708Sstevel * move SC interrupts to the new tunnel
9201708Sstevel */
9211708Sstevel if ((rc = sbbc_add_intr(to_softsp)) == DDI_FAILURE) {
9221708Sstevel cmn_err(CE_WARN, "Failed to add new interrupt handler");
9231708Sstevel } else if ((rc = tunnel_init(to_softsp, new_tunnel)) == DDI_FAILURE) {
9241708Sstevel cmn_err(CE_WARN, "Failed to initialize new tunnel");
9251708Sstevel ddi_remove_intr(to_softsp->dip, 0, to_softsp->iblock);
9261708Sstevel } else {
9271708Sstevel rw_enter(&master_iosram->tunnel_lock, RW_WRITER);
9281708Sstevel
9291708Sstevel /*
9301708Sstevel * If OBP switch is unsuccessful, abort the switch.
9311708Sstevel */
9321708Sstevel if ((rc = prom_serengeti_tunnel_switch(node, board))
9331708Sstevel != DDI_SUCCESS) {
9341708Sstevel
9351708Sstevel /*
9361708Sstevel * Restart other CPUs.
9371708Sstevel */
9381708Sstevel rw_exit(&master_iosram->tunnel_lock);
9391708Sstevel
9401708Sstevel cmn_err(CE_WARN, "OBP failed to switch tunnel");
9411708Sstevel
9421708Sstevel /*
9431708Sstevel * Remove interrupt
9441708Sstevel */
9451708Sstevel ddi_remove_intr(to_softsp->dip, 0, to_softsp->iblock);
9461708Sstevel
9471708Sstevel /*
9481708Sstevel * Unmap new tunnel
9491708Sstevel */
9501708Sstevel tunnel_fini(new_tunnel);
9511708Sstevel } else {
9521708Sstevel tunnel_t *orig_tunnel;
9531708Sstevel
9541708Sstevel orig_tunnel = master_iosram->tunnel;
9551708Sstevel tunnel_commit(to_softsp, new_tunnel);
9561708Sstevel
9571708Sstevel rw_exit(&master_iosram->tunnel_lock);
9581708Sstevel
9591708Sstevel /*
9601708Sstevel * Remove interrupt from original softsp
9611708Sstevel */
9621708Sstevel ddi_remove_intr(from_softsp->dip, 0,
9631708Sstevel from_softsp->iblock);
9641708Sstevel /*
9651708Sstevel * Unmap original tunnel
9661708Sstevel */
9671708Sstevel tunnel_fini(orig_tunnel);
9681708Sstevel kmem_free(orig_tunnel, sizeof (tunnel_t));
9691708Sstevel
9701708Sstevel /*
9711708Sstevel * Move the softintrs to the new dip.
9721708Sstevel */
9731708Sstevel (void) iosram_switch_intr();
9741708Sstevel (void) sbbc_mbox_switch(to_softsp);
9751708Sstevel
9761708Sstevel from_softsp->chosen = FALSE;
9771708Sstevel
9781708Sstevel }
9791708Sstevel }
9801708Sstevel
9811708Sstevel /*
9821708Sstevel * Enable interrupt.
9831708Sstevel */
9841708Sstevel sbbc_enable_intr(master_iosram->iosram_sbbc);
9851708Sstevel
9861708Sstevel /*
9871708Sstevel * Unlock and get out
9881708Sstevel */
9891708Sstevel mutex_exit(&from_softsp->sbbc_lock);
9901708Sstevel mutex_exit(&to_softsp->sbbc_lock);
9911708Sstevel mutex_exit(&master_iosram->iosram_lock);
9921708Sstevel
9931708Sstevel /*
9941708Sstevel * Call the interrupt handler directly in case
9951708Sstevel * we have missed an interrupt
9961708Sstevel */
997*11311SSurya.Prakki@Sun.COM (void) sbbc_intr_handler((caddr_t)master_iosram->iosram_sbbc);
9981708Sstevel
9991708Sstevel if (rc != DDI_SUCCESS) {
10001708Sstevel /*
10011708Sstevel * Free up the new_tunnel
10021708Sstevel */
10031708Sstevel kmem_free(new_tunnel, sizeof (tunnel_t));
10041708Sstevel cmn_err(CE_WARN, "Tunnel switch failed");
10051708Sstevel }
10061708Sstevel
10071708Sstevel return (rc);
10081708Sstevel
10091708Sstevel }
10101708Sstevel
10111708Sstevel /*
10121708Sstevel * convert an alphanumeric OBP key to
10131708Sstevel * our defined numeric keys
10141708Sstevel */
10151708Sstevel static int
iosram_convert_key(char * toc_key)10161708Sstevel iosram_convert_key(char *toc_key)
10171708Sstevel {
10181708Sstevel
10191708Sstevel if (strcmp(toc_key, TOCKEY_DOMSTAT) == 0)
10201708Sstevel return (SBBC_DOMAIN_KEY);
10211708Sstevel if (strcmp(toc_key, TOCKEY_KEYSWPO) == 0)
10221708Sstevel return (SBBC_KEYSWITCH_KEY);
10231708Sstevel if (strcmp(toc_key, TOCKEY_TODDATA) == 0)
10241708Sstevel return (SBBC_TOD_KEY);
10251708Sstevel if (strcmp(toc_key, TOCKEY_SOLCONS) == 0)
10261708Sstevel return (SBBC_CONSOLE_KEY);
10271708Sstevel if (strcmp(toc_key, TOCKEY_SOLMBOX) == 0)
10281708Sstevel return (SBBC_MAILBOX_KEY);
10291708Sstevel if (strcmp(toc_key, TOCKEY_SOLSCIR) == 0)
10301708Sstevel return (SBBC_INTR_SC_KEY);
10311708Sstevel if (strcmp(toc_key, TOCKEY_SCSOLIR) == 0)
10321708Sstevel return (SBBC_SC_INTR_KEY);
10331708Sstevel if (strcmp(toc_key, TOCKEY_ENVINFO) == 0)
10341708Sstevel return (SBBC_ENVCTRL_KEY);
10351708Sstevel if (strcmp(toc_key, TOCKEY_SOLSCIE) == 0)
10361708Sstevel return (SBBC_INTR_SC_ENABLED_KEY);
10371708Sstevel if (strcmp(toc_key, TOCKEY_SCSOLIE) == 0)
10381708Sstevel return (SBBC_SC_INTR_ENABLED_KEY);
10391708Sstevel if (strcmp(toc_key, TOCKEY_SIGBLCK) == 0)
10401708Sstevel return (SBBC_SIGBLCK_KEY);
10411708Sstevel
10421708Sstevel /* Unknown key */
10431708Sstevel return (-1);
10441708Sstevel }
10451708Sstevel
10461708Sstevel /*
10471708Sstevel * Move the software interrupts from the old dip to the new dip
10481708Sstevel * when doing tunnel switch.
10491708Sstevel */
10501708Sstevel static int
iosram_switch_intr()10511708Sstevel iosram_switch_intr()
10521708Sstevel {
10531708Sstevel sbbc_intrs_t *intr;
10541708Sstevel int intr_no;
10551708Sstevel int rc = 0;
10561708Sstevel
10571708Sstevel ASSERT(MUTEX_HELD(&master_iosram->iosram_lock));
10581708Sstevel
10591708Sstevel for (intr_no = 0; intr_no < SBBC_MAX_INTRS; intr_no++) {
10601708Sstevel intr = &master_iosram->intrs[intr_no];
10611708Sstevel
10621708Sstevel if (intr->sbbc_intr_id) {
10631708Sstevel ddi_remove_softintr(intr->sbbc_intr_id);
10641708Sstevel
10651708Sstevel if (ddi_add_softintr(master_iosram->iosram_sbbc->dip,
10661708Sstevel DDI_SOFTINT_HIGH,
10671708Sstevel &intr->sbbc_intr_id, NULL, NULL,
10681708Sstevel intr->sbbc_handler, intr->sbbc_arg)
10691708Sstevel != DDI_SUCCESS) {
10701708Sstevel
10711708Sstevel cmn_err(CE_WARN, "Can't add SBBC softint for "
10721708Sstevel "interrupt %x", intr_no << 1);
10731708Sstevel rc = EAGAIN;
10741708Sstevel }
10751708Sstevel }
10761708Sstevel }
10771708Sstevel
10781708Sstevel return (rc);
10791708Sstevel }
1080