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*11066Srafael.vanoni@sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 241708Sstevel * Use is subject to license terms. 251708Sstevel */ 261708Sstevel 271708Sstevel /* 281708Sstevel * IOSRAM leaf driver to SBBC nexus driver. This driver is used 291708Sstevel * by Starcat Domain SW to read/write from/to the IO sram. 301708Sstevel */ 311708Sstevel 321708Sstevel #include <sys/types.h> 331708Sstevel #include <sys/conf.h> 341708Sstevel #include <sys/ddi.h> 351708Sstevel #include <sys/sunddi.h> 361708Sstevel #include <sys/ddi_impldefs.h> 371708Sstevel #include <sys/obpdefs.h> 381708Sstevel #include <sys/promif.h> 391708Sstevel #include <sys/prom_plat.h> 401708Sstevel #include <sys/cmn_err.h> 411708Sstevel #include <sys/conf.h> /* req. by dev_ops flags MTSAFE etc. */ 421708Sstevel #include <sys/modctl.h> /* for modldrv */ 431708Sstevel #include <sys/stat.h> /* ddi_create_minor_node S_IFCHR */ 441708Sstevel #include <sys/errno.h> 451708Sstevel #include <sys/kmem.h> 461708Sstevel #include <sys/kstat.h> 471708Sstevel #include <sys/debug.h> 481708Sstevel 491708Sstevel #include <sys/axq.h> 501708Sstevel #include <sys/iosramreg.h> 511708Sstevel #include <sys/iosramio.h> 521708Sstevel #include <sys/iosramvar.h> 531708Sstevel 541708Sstevel 551708Sstevel #if defined(DEBUG) 561708Sstevel int iosram_debug = 0; 571708Sstevel static void iosram_dprintf(const char *fmt, ...); 581708Sstevel #define DPRINTF(level, arg) \ 591708Sstevel { if (iosram_debug >= level) iosram_dprintf arg; } 601708Sstevel #else /* !DEBUG */ 611708Sstevel #define DPRINTF(level, arg) 621708Sstevel #endif /* !DEBUG */ 631708Sstevel 641708Sstevel 651708Sstevel /* 661708Sstevel * IOSRAM module global state 671708Sstevel */ 681708Sstevel static void *iosramsoft_statep; /* IOSRAM state pointer */ 691708Sstevel static kmutex_t iosram_mutex; /* mutex lock */ 701708Sstevel 711708Sstevel static iosram_chunk_t *chunks = NULL; /* array of TOC entries */ 721708Sstevel static int nchunks = 0; /* # of TOC entries */ 731708Sstevel static iosram_chunk_t *iosram_hashtab[IOSRAM_HASHSZ]; /* key hash table */ 741708Sstevel 751708Sstevel static kcondvar_t iosram_tswitch_wait; /* tunnel switch wait cv */ 761708Sstevel static int iosram_tswitch_wakeup = 0; /* flag indicationg one or */ 771708Sstevel /* more threads waiting on */ 781708Sstevel /* iosram_tswitch_wait cv */ 791708Sstevel static int iosram_tswitch_active = 0; /* tunnel switch active flag */ 801708Sstevel static int iosram_tswitch_aborted = 0; /* tunnel switch abort flag */ 811708Sstevel static clock_t iosram_tswitch_tstamp = 0; /* lbolt of last tswitch end */ 821708Sstevel static kcondvar_t iosram_rw_wait; /* read/write wait cv */ 831708Sstevel static int iosram_rw_wakeup = 0; /* flag indicationg one or */ 841708Sstevel /* more threads waiting on */ 851708Sstevel /* iosram_rw_wait cv */ 861708Sstevel static int iosram_rw_active = 0; /* # threads accessing IOSRAM */ 871708Sstevel #if defined(DEBUG) 881708Sstevel static int iosram_rw_active_max = 0; 891708Sstevel #endif 901708Sstevel 911708Sstevel static struct iosramsoft *iosram_new_master = NULL; /* new tunnel target */ 921708Sstevel static struct iosramsoft *iosram_master = NULL; /* master tunnel */ 931708Sstevel static struct iosramsoft *iosram_instances = NULL; /* list of softstates */ 941708Sstevel 951708Sstevel static ddi_acc_handle_t iosram_handle = NULL; /* master IOSRAM map handle */ 961708Sstevel 971708Sstevel static void (*iosram_hdrchange_handler)() = NULL; 981708Sstevel 991708Sstevel #if IOSRAM_STATS 1001708Sstevel static struct iosram_stat iosram_stats; /* IOSRAM statistics */ 1011708Sstevel static void iosram_print_stats(); /* forward declaration */ 1021708Sstevel #endif /* IOSRAM_STATS */ 1031708Sstevel 1041708Sstevel 1051708Sstevel #if IOSRAM_LOG 1061708Sstevel kmutex_t iosram_log_mutex; 1071708Sstevel int iosram_log_level = 1; 1081708Sstevel int iosram_log_print = 0; /* print log when recorded */ 1091708Sstevel uint32_t iosram_logseq; 1101708Sstevel iosram_log_t iosram_logbuf[IOSRAM_MAXLOG]; 1111708Sstevel static void iosram_print_log(int cnt); /* forward declaration */ 1121708Sstevel #endif /* IOSRAM_LOG */ 1131708Sstevel 1141708Sstevel 1151708Sstevel /* driver entry point fn definitions */ 1161708Sstevel static int iosram_open(dev_t *, int, int, cred_t *); 1171708Sstevel static int iosram_close(dev_t, int, int, cred_t *); 1181708Sstevel static int iosram_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 1191708Sstevel 1201708Sstevel /* configuration entry point fn definitions */ 1211708Sstevel static int iosram_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 1221708Sstevel static int iosram_attach(dev_info_t *, ddi_attach_cmd_t); 1231708Sstevel static int iosram_detach(dev_info_t *, ddi_detach_cmd_t); 1241708Sstevel 1251708Sstevel 1261708Sstevel /* forward declaractions */ 1271708Sstevel static iosram_chunk_t *iosram_find_chunk(uint32_t key); 1281708Sstevel static void iosram_set_master(struct iosramsoft *softp); 1291708Sstevel static int iosram_is_chosen(struct iosramsoft *softp); 1301708Sstevel static int iosram_tunnel_capable(struct iosramsoft *softp); 1311708Sstevel static int iosram_read_toc(struct iosramsoft *softp); 1321708Sstevel static void iosram_init_hashtab(void); 1331708Sstevel static void iosram_update_addrs(struct iosramsoft *softp); 1341708Sstevel 1351708Sstevel static int iosram_setup_map(struct iosramsoft *softp); 1361708Sstevel static void iosram_remove_map(struct iosramsoft *softp); 1371708Sstevel static int iosram_add_intr(iosramsoft_t *); 1381708Sstevel static int iosram_remove_intr(iosramsoft_t *); 1391708Sstevel 1401708Sstevel static void iosram_add_instance(struct iosramsoft *softp); 1411708Sstevel static void iosram_remove_instance(int instance); 1421708Sstevel static int iosram_switch_tunnel(iosramsoft_t *softp); 1431708Sstevel static void iosram_abort_tswitch(); 1441708Sstevel 1451708Sstevel #if defined(DEBUG) 1461708Sstevel /* forward declaractions for debugging */ 1471708Sstevel static int iosram_get_keys(iosram_toc_entry_t *buf, uint32_t *len); 1481708Sstevel static void iosram_print_cback(); 1491708Sstevel static void iosram_print_state(int); 1501708Sstevel static void iosram_print_flags(); 1511708Sstevel #endif 1521708Sstevel 1531708Sstevel 1541708Sstevel 1551708Sstevel /* 1561708Sstevel * cb_ops 1571708Sstevel */ 1581708Sstevel static struct cb_ops iosram_cb_ops = { 1591708Sstevel iosram_open, /* cb_open */ 1601708Sstevel iosram_close, /* cb_close */ 1611708Sstevel nodev, /* cb_strategy */ 1621708Sstevel nodev, /* cb_print */ 1631708Sstevel nodev, /* cb_dump */ 1641708Sstevel nodev, /* cb_read */ 1651708Sstevel nodev, /* cb_write */ 1661708Sstevel iosram_ioctl, /* cb_ioctl */ 1671708Sstevel nodev, /* cb_devmap */ 1681708Sstevel nodev, /* cb_mmap */ 1691708Sstevel nodev, /* cb_segmap */ 1701708Sstevel nochpoll, /* cb_chpoll */ 1711708Sstevel ddi_prop_op, /* cb_prop_op */ 1721708Sstevel NULL, /* cb_stream */ 1731708Sstevel (int)(D_NEW | D_MP | D_HOTPLUG) /* cb_flag */ 1741708Sstevel }; 1751708Sstevel 1761708Sstevel /* 1771708Sstevel * Declare ops vectors for auto configuration. 1781708Sstevel */ 1791708Sstevel struct dev_ops iosram_ops = { 1801708Sstevel DEVO_REV, /* devo_rev */ 1811708Sstevel 0, /* devo_refcnt */ 1821708Sstevel iosram_getinfo, /* devo_getinfo */ 1831708Sstevel nulldev, /* devo_identify */ 1841708Sstevel nulldev, /* devo_probe */ 1851708Sstevel iosram_attach, /* devo_attach */ 1861708Sstevel iosram_detach, /* devo_detach */ 1871708Sstevel nodev, /* devo_reset */ 1881708Sstevel &iosram_cb_ops, /* devo_cb_ops */ 1891708Sstevel (struct bus_ops *)NULL, /* devo_bus_ops */ 1907656SSherry.Moore@Sun.COM nulldev, /* devo_power */ 1917656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */ 1921708Sstevel }; 1931708Sstevel 1941708Sstevel /* 1951708Sstevel * Loadable module support. 1961708Sstevel */ 1971708Sstevel extern struct mod_ops mod_driverops; 1981708Sstevel 1991708Sstevel static struct modldrv iosrammodldrv = { 2001708Sstevel &mod_driverops, /* type of module - driver */ 2017656SSherry.Moore@Sun.COM "IOSRAM Leaf driver", 2021708Sstevel &iosram_ops, 2031708Sstevel }; 2041708Sstevel 2051708Sstevel static struct modlinkage iosrammodlinkage = { 2061708Sstevel MODREV_1, 2071708Sstevel &iosrammodldrv, 2081708Sstevel NULL 2091708Sstevel }; 2101708Sstevel 2111708Sstevel 2121708Sstevel int 2131708Sstevel _init(void) 2141708Sstevel { 2151708Sstevel int error; 2161708Sstevel int i; 2171708Sstevel 2181708Sstevel mutex_init(&iosram_mutex, NULL, MUTEX_DRIVER, (void *)NULL); 2191708Sstevel cv_init(&iosram_tswitch_wait, NULL, CV_DRIVER, NULL); 2201708Sstevel cv_init(&iosram_rw_wait, NULL, CV_DRIVER, NULL); 2211708Sstevel #if defined(IOSRAM_LOG) 2221708Sstevel mutex_init(&iosram_log_mutex, NULL, MUTEX_DRIVER, (void *)NULL); 2231708Sstevel #endif 2241708Sstevel 2251708Sstevel DPRINTF(1, ("_init:IOSRAM\n")); 2261708Sstevel 2271708Sstevel for (i = 0; i < IOSRAM_HASHSZ; i++) { 2281708Sstevel iosram_hashtab[i] = NULL; 2291708Sstevel } 2301708Sstevel 2311708Sstevel if ((error = ddi_soft_state_init(&iosramsoft_statep, 2321708Sstevel sizeof (struct iosramsoft), 1)) != 0) { 2331708Sstevel goto failed; 2341708Sstevel } 2351708Sstevel if ((error = mod_install(&iosrammodlinkage)) != 0) { 2361708Sstevel ddi_soft_state_fini(&iosramsoft_statep); 2371708Sstevel goto failed; 2381708Sstevel } 2391708Sstevel 2401708Sstevel IOSRAMLOG(0, "_init:IOSRAM ... error:%d statep:%p\n", 2411708Sstevel error, iosramsoft_statep, NULL, NULL); 2421708Sstevel 2431708Sstevel return (error); 2441708Sstevel 2451708Sstevel failed: 2461708Sstevel cv_destroy(&iosram_tswitch_wait); 2471708Sstevel cv_destroy(&iosram_rw_wait); 2481708Sstevel mutex_destroy(&iosram_mutex); 2491708Sstevel #if defined(IOSRAM_LOG) 2501708Sstevel mutex_destroy(&iosram_log_mutex); 2511708Sstevel #endif 2521708Sstevel IOSRAMLOG(0, "_init:IOSRAM ... error:%d statep:%p\n", 2531708Sstevel error, iosramsoft_statep, NULL, NULL); 2541708Sstevel 2551708Sstevel return (error); 2561708Sstevel } 2571708Sstevel 2581708Sstevel 2591708Sstevel int 2601708Sstevel _fini(void) 2611708Sstevel { 2621708Sstevel #ifndef DEBUG 2631708Sstevel return (EBUSY); 2641708Sstevel #else /* !DEBUG */ 2651708Sstevel int error; 2661708Sstevel 2671708Sstevel if ((error = mod_remove(&iosrammodlinkage)) == 0) { 2681708Sstevel ddi_soft_state_fini(&iosramsoft_statep); 2691708Sstevel 2701708Sstevel cv_destroy(&iosram_tswitch_wait); 2711708Sstevel cv_destroy(&iosram_rw_wait); 2721708Sstevel mutex_destroy(&iosram_mutex); 2731708Sstevel #if defined(IOSRAM_LOG) 2741708Sstevel mutex_destroy(&iosram_log_mutex); 2751708Sstevel #endif 2761708Sstevel } 2771708Sstevel DPRINTF(1, ("_fini:IOSRAM error:%d\n", error)); 2781708Sstevel 2791708Sstevel return (error); 2801708Sstevel #endif /* !DEBUG */ 2811708Sstevel } 2821708Sstevel 2831708Sstevel 2841708Sstevel int 2851708Sstevel _info(struct modinfo *modinfop) 2861708Sstevel { 2871708Sstevel return (mod_info(&iosrammodlinkage, modinfop)); 2881708Sstevel } 2891708Sstevel 2901708Sstevel 2911708Sstevel static int 2921708Sstevel iosram_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2931708Sstevel { 2941708Sstevel int instance; 2951708Sstevel int propval; 2961708Sstevel int length; 2971708Sstevel char name[32]; 2981708Sstevel struct iosramsoft *softp; 2991708Sstevel 3001708Sstevel instance = ddi_get_instance(dip); 3011708Sstevel 3021708Sstevel DPRINTF(1, ("iosram(%d): attach dip:%p\n", instance)); 3031708Sstevel 3041708Sstevel IOSRAMLOG(1, "ATTACH: dip:%p instance %d ... start\n", 3051708Sstevel dip, instance, NULL, NULL); 3061708Sstevel switch (cmd) { 3071708Sstevel case DDI_ATTACH: 3081708Sstevel break; 3091708Sstevel case DDI_RESUME: 3101708Sstevel if (!(softp = ddi_get_soft_state(iosramsoft_statep, 3111708Sstevel instance))) { 3121708Sstevel return (DDI_FAILURE); 3131708Sstevel } 3141708Sstevel mutex_enter(&iosram_mutex); 3151708Sstevel mutex_enter(&softp->intr_mutex); 3161708Sstevel if (!softp->suspended) { 3171708Sstevel mutex_exit(&softp->intr_mutex); 3181708Sstevel mutex_exit(&iosram_mutex); 3191708Sstevel return (DDI_FAILURE); 3201708Sstevel } 3211708Sstevel softp->suspended = 0; 3221708Sstevel 3231708Sstevel /* 3241708Sstevel * enable SBBC interrupts if SBBC is mapped in 3251708Sstevel * restore the value saved during detach 3261708Sstevel */ 3271708Sstevel if (softp->sbbc_region) { 3281708Sstevel ddi_put32(softp->sbbc_handle, 3291708Sstevel &(softp->sbbc_region->int_enable.reg), 3301708Sstevel softp->int_enable_sav); 3311708Sstevel } 3321708Sstevel 3331708Sstevel /* 3341708Sstevel * Trigger soft interrupt handler to process any pending 3351708Sstevel * interrupts. 3361708Sstevel */ 3371708Sstevel if (softp->intr_pending && !softp->intr_busy && 3381708Sstevel (softp->softintr_id != NULL)) { 3391708Sstevel ddi_trigger_softintr(softp->softintr_id); 3401708Sstevel } 3411708Sstevel 3421708Sstevel mutex_exit(&softp->intr_mutex); 3431708Sstevel mutex_exit(&iosram_mutex); 3441708Sstevel 3451708Sstevel return (DDI_SUCCESS); 3461708Sstevel 3471708Sstevel default: 3481708Sstevel return (DDI_FAILURE); 3491708Sstevel } 3501708Sstevel 3511708Sstevel if (ddi_soft_state_zalloc(iosramsoft_statep, instance) != 0) { 3521708Sstevel return (DDI_FAILURE); 3531708Sstevel } 3541708Sstevel 3551708Sstevel if ((softp = ddi_get_soft_state(iosramsoft_statep, instance)) == NULL) { 3567656SSherry.Moore@Sun.COM return (DDI_FAILURE); 3571708Sstevel } 3581708Sstevel softp->dip = dip; 3591708Sstevel softp->instance = instance; 3601708Sstevel softp->sbbc_region = NULL; 3611708Sstevel 3621708Sstevel /* 3631708Sstevel * If this instance is not tunnel capable, we don't attach it. 3641708Sstevel */ 3651708Sstevel if (iosram_tunnel_capable(softp) == 0) { 3661708Sstevel DPRINTF(1, ("iosram(%d): not tunnel_capable\n", instance)); 3671708Sstevel IOSRAMLOG(1, "ATTACH(%d): not tunnel_capable\n", instance, NULL, 3681708Sstevel NULL, NULL); 3691708Sstevel goto attach_fail; 3701708Sstevel } 3711708Sstevel 3721708Sstevel /* 3731708Sstevel * Need to create an "interrupt-priorities" property to define the PIL 3741708Sstevel * to be used with the interrupt service routine. 3751708Sstevel */ 3761708Sstevel if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 3771708Sstevel "interrupt-priorities", &length) == DDI_PROP_NOT_FOUND) { 3781708Sstevel DPRINTF(1, ("iosram(%d): creating interrupt priority property", 3791708Sstevel instance)); 3801708Sstevel propval = IOSRAM_PIL; 3811708Sstevel if (ddi_prop_create(DDI_DEV_T_NONE, dip, 0, 3821708Sstevel "interrupt-priorities", (caddr_t)&propval, sizeof (propval)) 3831708Sstevel != DDI_PROP_SUCCESS) { 3841708Sstevel cmn_err(CE_WARN, 3851708Sstevel "iosram_attach: failed to create property"); 3861708Sstevel goto attach_fail; 3871708Sstevel } 3881708Sstevel } 3891708Sstevel 3901708Sstevel /* 3911708Sstevel * Get interrupts cookies and initialize per-instance mutexes 3921708Sstevel */ 3931708Sstevel if (ddi_get_iblock_cookie(softp->dip, 0, &softp->real_iblk) 3941708Sstevel != DDI_SUCCESS) { 3951708Sstevel IOSRAMLOG(1, "ATTACH(%d): cannot get soft intr cookie\n", 3961708Sstevel instance, NULL, NULL, NULL); 3971708Sstevel goto attach_fail; 3981708Sstevel } 3991708Sstevel mutex_init(&softp->intr_mutex, NULL, MUTEX_DRIVER, 4001708Sstevel (void *)softp->real_iblk); 4011708Sstevel 4021708Sstevel /* 4031708Sstevel * Add this instance to the iosram_instances list so that it can be used 4041708Sstevel * for tunnel in future. 4051708Sstevel */ 4061708Sstevel mutex_enter(&iosram_mutex); 4071708Sstevel softp->state = IOSRAM_STATE_INIT; 4081708Sstevel iosram_add_instance(softp); 4091708Sstevel 4101708Sstevel /* 4111708Sstevel * If this is the chosen IOSRAM and there is no master IOSRAM yet, then 4121708Sstevel * let's set this instance as the master. 4131708Sstevel */ 4141708Sstevel if (iosram_master == NULL && iosram_is_chosen(softp)) { 4151708Sstevel iosram_switch_tunnel(softp); 4161708Sstevel 4171708Sstevel /* 4181708Sstevel * XXX Do we need to panic if unable to setup master IOSRAM? 4191708Sstevel */ 4201708Sstevel if (iosram_master == NULL) { 4211708Sstevel cmn_err(CE_WARN, 4221708Sstevel "iosram(%d): can't setup master tunnel\n", 4231708Sstevel instance); 4241708Sstevel softp->state = 0; 4251708Sstevel iosram_remove_instance(softp->instance); 4261708Sstevel mutex_exit(&iosram_mutex); 4271708Sstevel mutex_destroy(&softp->intr_mutex); 4281708Sstevel goto attach_fail; 4291708Sstevel } 4301708Sstevel } 4311708Sstevel 4321708Sstevel mutex_exit(&iosram_mutex); 4331708Sstevel 4341708Sstevel /* 4351708Sstevel * Create minor node 4361708Sstevel */ 4371708Sstevel (void) sprintf(name, "iosram%d", instance); 4381708Sstevel if (ddi_create_minor_node(dip, name, S_IFCHR, instance, NULL, NULL) == 4391708Sstevel DDI_FAILURE) { 4401708Sstevel /* 4411708Sstevel * Minor node seems to be needed only for debugging purposes. 4421708Sstevel * Therefore, there is no need to fail this attach request. 4431708Sstevel * Simply print a message out. 4441708Sstevel */ 4451708Sstevel cmn_err(CE_NOTE, "!iosram(%d): can't create minor node\n", 4461708Sstevel instance); 4471708Sstevel } 4481708Sstevel ddi_report_dev(dip); 4491708Sstevel 4501708Sstevel DPRINTF(1, ("iosram_attach(%d): success.\n", instance)); 4511708Sstevel IOSRAMLOG(1, "ATTACH: dip:%p instance:%d ... success softp:%p\n", 4521708Sstevel dip, instance, softp, NULL); 4531708Sstevel 4541708Sstevel return (DDI_SUCCESS); 4551708Sstevel 4561708Sstevel attach_fail: 4571708Sstevel DPRINTF(1, ("iosram_attach(%d):failed.\n", instance)); 4581708Sstevel IOSRAMLOG(1, "ATTACH: dip:%p instance:%d ... failed.\n", 4591708Sstevel dip, instance, NULL, NULL); 4601708Sstevel 4611708Sstevel ddi_soft_state_free(iosramsoft_statep, instance); 4621708Sstevel return (DDI_FAILURE); 4631708Sstevel } 4641708Sstevel 4651708Sstevel 4661708Sstevel static int 4671708Sstevel iosram_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4681708Sstevel { 4691708Sstevel int instance; 4701708Sstevel struct iosramsoft *softp; 4711708Sstevel 4721708Sstevel instance = ddi_get_instance(dip); 4731708Sstevel if (!(softp = ddi_get_soft_state(iosramsoft_statep, instance))) { 4741708Sstevel return (DDI_FAILURE); 4751708Sstevel } 4761708Sstevel 4771708Sstevel IOSRAMLOG(1, "DETACH: dip:%p instance %d softp:%p\n", 4781708Sstevel dip, instance, softp, NULL); 4791708Sstevel 4801708Sstevel switch (cmd) { 4811708Sstevel case DDI_DETACH: 4821708Sstevel break; 4831708Sstevel case DDI_SUSPEND: 4841708Sstevel mutex_enter(&iosram_mutex); 4851708Sstevel mutex_enter(&softp->intr_mutex); 4861708Sstevel if (softp->suspended) { 4871708Sstevel mutex_exit(&softp->intr_mutex); 4881708Sstevel mutex_exit(&iosram_mutex); 4891708Sstevel return (DDI_FAILURE); 4901708Sstevel } 4911708Sstevel softp->suspended = 1; 4921708Sstevel /* 4931708Sstevel * Disable SBBC interrupts if SBBC is mapped in 4941708Sstevel */ 4951708Sstevel if (softp->sbbc_region) { 4961708Sstevel /* save current interrupt enable register */ 4971708Sstevel softp->int_enable_sav = ddi_get32(softp->sbbc_handle, 4981708Sstevel &(softp->sbbc_region->int_enable.reg)); 4991708Sstevel ddi_put32(softp->sbbc_handle, 5001708Sstevel &(softp->sbbc_region->int_enable.reg), 0x0); 5011708Sstevel } 5021708Sstevel mutex_exit(&softp->intr_mutex); 5031708Sstevel mutex_exit(&iosram_mutex); 5041708Sstevel return (DDI_SUCCESS); 5051708Sstevel 5061708Sstevel default: 5071708Sstevel return (DDI_FAILURE); 5081708Sstevel } 5091708Sstevel 5101708Sstevel 5111708Sstevel /* 5121708Sstevel * Indicate that this instance is being detached so that this instance 5131708Sstevel * does not become a target for tunnel switch in future. 5141708Sstevel */ 5151708Sstevel mutex_enter(&iosram_mutex); 5161708Sstevel softp->state |= IOSRAM_STATE_DETACH; 5171708Sstevel 5181708Sstevel /* 5191708Sstevel * If this instance is currently the master or the target of the tunnel 5201708Sstevel * switch, then we need to wait and switch tunnel, if necessary. 5211708Sstevel */ 5221708Sstevel if (iosram_master == softp || (softp->state & IOSRAM_STATE_TSWITCH)) { 5231708Sstevel mutex_exit(&iosram_mutex); 5241708Sstevel iosram_switchfrom(instance); 5251708Sstevel mutex_enter(&iosram_mutex); 5261708Sstevel } 5271708Sstevel 5281708Sstevel /* 5291708Sstevel * If the tunnel switch is in progress and we are the master or target 5301708Sstevel * of tunnel relocation, then we can't detach this instance right now. 5311708Sstevel */ 5321708Sstevel if (softp->state & IOSRAM_STATE_TSWITCH) { 5331708Sstevel softp->state &= ~IOSRAM_STATE_DETACH; 5341708Sstevel mutex_exit(&iosram_mutex); 5351708Sstevel return (DDI_FAILURE); 5361708Sstevel } 5371708Sstevel 5381708Sstevel /* 5391708Sstevel * We can't allow master IOSRAM to be detached as we won't be able to 5401708Sstevel * communicate otherwise. 5411708Sstevel */ 5421708Sstevel if (iosram_master == softp) { 5431708Sstevel softp->state &= ~IOSRAM_STATE_DETACH; 5441708Sstevel mutex_exit(&iosram_mutex); 5451708Sstevel return (DDI_FAILURE); 5461708Sstevel } 5471708Sstevel 5481708Sstevel /* 5491708Sstevel * Now remove our instance from the iosram_instances list. 5501708Sstevel */ 5511708Sstevel iosram_remove_instance(instance); 5521708Sstevel mutex_exit(&iosram_mutex); 5531708Sstevel 5541708Sstevel /* 5551708Sstevel * Instances should only ever be mapped if they are the master and/or 5561708Sstevel * participating in a tunnel switch. Neither should be the case here. 5571708Sstevel */ 5581708Sstevel ASSERT((softp->state & IOSRAM_STATE_MAPPED) == 0); 5591708Sstevel 5601708Sstevel /* 5611708Sstevel * Destroy per-instance mutexes 5621708Sstevel */ 5631708Sstevel mutex_destroy(&softp->intr_mutex); 5641708Sstevel 5651708Sstevel ddi_remove_minor_node(dip, NULL); 5661708Sstevel 5671708Sstevel /* 5681708Sstevel * Finally remove our soft state structure 5691708Sstevel */ 5701708Sstevel ddi_soft_state_free(iosramsoft_statep, instance); 5711708Sstevel 5721708Sstevel return (DDI_SUCCESS); 5731708Sstevel } 5741708Sstevel 5751708Sstevel 5761708Sstevel /* ARGSUSED0 */ 5771708Sstevel static int 5781708Sstevel iosram_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 5791708Sstevel void **result) 5801708Sstevel { 5811708Sstevel dev_t dev = (dev_t)arg; 5821708Sstevel struct iosramsoft *softp; 5831708Sstevel int instance, ret; 5841708Sstevel 5851708Sstevel instance = getminor(dev); 5861708Sstevel 5871708Sstevel IOSRAMLOG(2, "GETINFO: dip:%x instance %d dev:%x infocmd:%x\n", 5881708Sstevel dip, instance, dev, infocmd); 5891708Sstevel 5901708Sstevel switch (infocmd) { 5911708Sstevel case DDI_INFO_DEVT2DEVINFO: 5921708Sstevel softp = ddi_get_soft_state(iosramsoft_statep, instance); 5931708Sstevel if (softp == NULL) { 5941708Sstevel *result = NULL; 5951708Sstevel ret = DDI_FAILURE; 5961708Sstevel } else { 5971708Sstevel *result = softp->dip; 5981708Sstevel ret = DDI_SUCCESS; 5991708Sstevel } 6001708Sstevel break; 6011708Sstevel case DDI_INFO_DEVT2INSTANCE: 6021708Sstevel *result = (void *)(uintptr_t)instance; 6031708Sstevel ret = DDI_SUCCESS; 6041708Sstevel break; 6051708Sstevel default: 6061708Sstevel ret = DDI_FAILURE; 6071708Sstevel break; 6081708Sstevel } 6091708Sstevel 6101708Sstevel return (ret); 6111708Sstevel } 6121708Sstevel 6131708Sstevel 6141708Sstevel /*ARGSUSED1*/ 6151708Sstevel static int 6161708Sstevel iosram_open(dev_t *dev, int flag, int otype, cred_t *credp) 6171708Sstevel { 6181708Sstevel struct iosramsoft *softp; 6191708Sstevel int instance; 6201708Sstevel 6211708Sstevel instance = getminor(*dev); 6221708Sstevel softp = ddi_get_soft_state(iosramsoft_statep, instance); 6231708Sstevel 6241708Sstevel if (softp == NULL) { 6251708Sstevel return (ENXIO); 6261708Sstevel } 6271708Sstevel 6281708Sstevel IOSRAMLOG(1, "OPEN: dev:%p otype:%x ... instance:%d softp:%p\n", 6291708Sstevel *dev, otype, softp->instance, softp); 6301708Sstevel 6311708Sstevel return (0); 6321708Sstevel } 6331708Sstevel 6341708Sstevel 6351708Sstevel /*ARGSUSED1*/ 6361708Sstevel static int 6371708Sstevel iosram_close(dev_t dev, int flag, int otype, cred_t *credp) 6381708Sstevel { 6391708Sstevel struct iosramsoft *softp; 6401708Sstevel int instance; 6411708Sstevel 6421708Sstevel instance = getminor(dev); 6431708Sstevel softp = ddi_get_soft_state(iosramsoft_statep, instance); 6441708Sstevel if (softp == NULL) { 6451708Sstevel return (ENXIO); 6461708Sstevel } 6471708Sstevel 6481708Sstevel IOSRAMLOG(1, "CLOSE: dev:%p otype:%x ... instance:%d softp:%p\n", 6491708Sstevel dev, otype, softp->instance, softp); 6501708Sstevel 6511708Sstevel return (0); 6521708Sstevel } 6531708Sstevel 6541708Sstevel 6551708Sstevel int 6561708Sstevel iosram_rd(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr) 6571708Sstevel { 6581708Sstevel iosram_chunk_t *chunkp; 6591708Sstevel uint32_t chunk_len; 6601708Sstevel uint8_t *iosramp; 6611708Sstevel ddi_acc_handle_t handle; 6621708Sstevel int boff; 6631708Sstevel union { 6641708Sstevel uchar_t cbuf[UINT32SZ]; 6651708Sstevel uint32_t data; 6661708Sstevel } word; 6671708Sstevel 6681708Sstevel int error = 0; 6691708Sstevel uint8_t *buf = (uint8_t *)dptr; 6701708Sstevel 6711708Sstevel /* 6721708Sstevel * We try to read from the IOSRAM using double word or word access 6731708Sstevel * provided both "off" and "buf" are (or can be) double word or word 6741708Sstevel * aligned. Othewise, we try to align the "off" to a word boundary and 6751708Sstevel * then try to read data from the IOSRAM using word access, but store it 6761708Sstevel * into buf buffer using byte access. 6771708Sstevel * 6781708Sstevel * If the leading/trailing portion of the IOSRAM data is not word 6791708Sstevel * aligned, it will always be copied using byte access. 6801708Sstevel */ 6811708Sstevel IOSRAMLOG(1, "RD: key: 0x%x off:%x len:%x buf:%p\n", 6821708Sstevel key, off, len, buf); 6831708Sstevel 6841708Sstevel /* 6851708Sstevel * Acquire lock and look for the requested chunk. If it exists, make 6861708Sstevel * sure the requested read is within the chunk's bounds and no tunnel 6871708Sstevel * switch is active. 6881708Sstevel */ 6891708Sstevel mutex_enter(&iosram_mutex); 6901708Sstevel chunkp = iosram_find_chunk(key); 6911708Sstevel chunk_len = (chunkp != NULL) ? chunkp->toc_data.len : 0; 6921708Sstevel 6931708Sstevel if (iosram_master == NULL) { 6941708Sstevel error = EIO; 6951708Sstevel } else if (chunkp == NULL) { 6961708Sstevel error = EINVAL; 6971708Sstevel } else if ((off >= chunk_len) || (len > chunk_len) || 6981708Sstevel ((off + len) > chunk_len)) { 6991708Sstevel error = EMSGSIZE; 7001708Sstevel } else if (iosram_tswitch_active) { 7011708Sstevel error = EAGAIN; 7021708Sstevel } 7031708Sstevel 7041708Sstevel if (error) { 7051708Sstevel mutex_exit(&iosram_mutex); 7061708Sstevel return (error); 7071708Sstevel } 7081708Sstevel 7091708Sstevel /* 7101708Sstevel * Bump reference count to indicate #thread accessing IOSRAM and release 7111708Sstevel * the lock. 7121708Sstevel */ 7131708Sstevel iosram_rw_active++; 7141708Sstevel #if defined(DEBUG) 7151708Sstevel if (iosram_rw_active > iosram_rw_active_max) { 7161708Sstevel iosram_rw_active_max = iosram_rw_active; 7171708Sstevel } 7181708Sstevel #endif 7191708Sstevel mutex_exit(&iosram_mutex); 7201708Sstevel 7211708Sstevel IOSRAM_STAT(read); 7221708Sstevel IOSRAM_STAT_ADD(bread, len); 7231708Sstevel 7241708Sstevel /* Get starting address and map handle */ 7251708Sstevel iosramp = chunkp->basep + off; 7261708Sstevel handle = iosram_handle; 7271708Sstevel 7281708Sstevel /* 7291708Sstevel * Align the off to word boundary and then try reading/writing data 7301708Sstevel * using double word or word access. 7311708Sstevel */ 7321708Sstevel if ((boff = ((uintptr_t)iosramp & (UINT32SZ - 1))) != 0) { 7331708Sstevel int cnt = UINT32SZ - boff; 7341708Sstevel 7351708Sstevel if (cnt > len) { 7361708Sstevel cnt = len; 7371708Sstevel } 7381708Sstevel IOSRAMLOG(2, 7391708Sstevel "RD: align rep_get8(buf:%p sramp:%p cnt:%x) len:%x\n", 7401708Sstevel buf, iosramp, cnt, len); 7411708Sstevel ddi_rep_get8(handle, buf, iosramp, cnt, DDI_DEV_AUTOINCR); 7421708Sstevel buf += cnt; 7431708Sstevel iosramp += cnt; 7441708Sstevel len -= cnt; 7451708Sstevel } 7461708Sstevel 7471708Sstevel if ((len >= UINT64SZ) && 7481708Sstevel ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT64SZ - 1)) == 0)) { 7491708Sstevel /* 7501708Sstevel * Both source and destination are double word aligned 7511708Sstevel */ 7521708Sstevel int cnt = len/UINT64SZ; 7531708Sstevel 7541708Sstevel IOSRAMLOG(2, 7551708Sstevel "RD: rep_get64(buf:%p sramp:%p cnt:%x) len:%x\n", 7561708Sstevel buf, iosramp, cnt, len); 7571708Sstevel ddi_rep_get64(handle, (uint64_t *)buf, (uint64_t *)iosramp, 7581708Sstevel cnt, DDI_DEV_AUTOINCR); 7591708Sstevel iosramp += cnt * UINT64SZ; 7601708Sstevel buf += cnt * UINT64SZ; 7611708Sstevel len -= cnt * UINT64SZ; 7621708Sstevel 7631708Sstevel /* 7641708Sstevel * read remaining data using word and byte access 7651708Sstevel */ 7661708Sstevel if (len >= UINT32SZ) { 7671708Sstevel IOSRAMLOG(2, 7681708Sstevel "RD: get32(buf:%p sramp:%p) len:%x\n", 7691708Sstevel buf, iosramp, len, NULL); 7701708Sstevel *(uint32_t *)buf = ddi_get32(handle, 7711708Sstevel (uint32_t *)iosramp); 7721708Sstevel iosramp += UINT32SZ; 7731708Sstevel buf += UINT32SZ; 7741708Sstevel len -= UINT32SZ; 7751708Sstevel } 7761708Sstevel 7771708Sstevel if (len != 0) { 7787656SSherry.Moore@Sun.COM ddi_rep_get8(handle, buf, iosramp, len, 7797656SSherry.Moore@Sun.COM DDI_DEV_AUTOINCR); 7801708Sstevel } 7811708Sstevel } else if ((len >= UINT32SZ) && 7821708Sstevel ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT32SZ - 1)) == 0)) { 7831708Sstevel /* 7841708Sstevel * Both source and destination are word aligned 7851708Sstevel */ 7861708Sstevel int cnt = len/UINT32SZ; 7871708Sstevel 7881708Sstevel IOSRAMLOG(2, 7891708Sstevel "RD: rep_get32(buf:%p sramp:%p cnt:%x) len:%x\n", 7901708Sstevel buf, iosramp, cnt, len); 7911708Sstevel ddi_rep_get32(handle, (uint32_t *)buf, (uint32_t *)iosramp, 7921708Sstevel cnt, DDI_DEV_AUTOINCR); 7931708Sstevel iosramp += cnt * UINT32SZ; 7941708Sstevel buf += cnt * UINT32SZ; 7951708Sstevel len -= cnt * UINT32SZ; 7961708Sstevel 7971708Sstevel /* 7981708Sstevel * copy the remainder using byte access 7991708Sstevel */ 8001708Sstevel if (len != 0) { 8017656SSherry.Moore@Sun.COM ddi_rep_get8(handle, buf, iosramp, len, 8027656SSherry.Moore@Sun.COM DDI_DEV_AUTOINCR); 8031708Sstevel } 8041708Sstevel } else if (len != 0) { 8051708Sstevel /* 8061708Sstevel * We know that the "off" (i.e. iosramp) is at least word 8071708Sstevel * aligned. We need to read IOSRAM word at a time and copy it 8081708Sstevel * byte at a time. 8091708Sstevel */ 8101708Sstevel ASSERT(((uintptr_t)iosramp & (UINT32SZ - 1)) == 0); 8111708Sstevel 8121708Sstevel IOSRAMLOG(2, 8131708Sstevel "RD: unaligned get32(buf:%p sramp:%p) len:%x\n", 8141708Sstevel buf, iosramp, len, NULL); 8151708Sstevel for (; len >= UINT32SZ; len -= UINT32SZ, iosramp += UINT32SZ) { 8161708Sstevel word.data = ddi_get32(handle, (uint32_t *)iosramp); 8171708Sstevel *buf++ = word.cbuf[0]; 8181708Sstevel *buf++ = word.cbuf[1]; 8191708Sstevel *buf++ = word.cbuf[2]; 8201708Sstevel *buf++ = word.cbuf[3]; 8211708Sstevel } 8221708Sstevel 8231708Sstevel /* 8241708Sstevel * copy the remaining data using byte access 8251708Sstevel */ 8261708Sstevel if (len != 0) { 8271708Sstevel ddi_rep_get8(handle, buf, iosramp, len, 8281708Sstevel DDI_DEV_AUTOINCR); 8291708Sstevel } 8301708Sstevel } 8311708Sstevel 8321708Sstevel /* 8331708Sstevel * Reacquire mutex lock, decrement refcnt and if refcnt is 0 and any 8341708Sstevel * threads are waiting for r/w activity to complete, wake them up. 8351708Sstevel */ 8361708Sstevel mutex_enter(&iosram_mutex); 8371708Sstevel ASSERT(iosram_rw_active > 0); 8381708Sstevel 8391708Sstevel if ((--iosram_rw_active == 0) && iosram_rw_wakeup) { 8401708Sstevel iosram_rw_wakeup = 0; 8411708Sstevel cv_broadcast(&iosram_rw_wait); 8421708Sstevel } 8431708Sstevel mutex_exit(&iosram_mutex); 8441708Sstevel 8451708Sstevel return (error); 8461708Sstevel } 8471708Sstevel 8481708Sstevel 8491708Sstevel /* 8501708Sstevel * _iosram_write(key, off, len, dptr, force) 8511708Sstevel * Internal common routine to write to the IOSRAM. 8521708Sstevel */ 8531708Sstevel static int 8541708Sstevel _iosram_write(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr, int force) 8551708Sstevel { 8561708Sstevel iosram_chunk_t *chunkp; 8571708Sstevel uint32_t chunk_len; 8581708Sstevel uint8_t *iosramp; 8591708Sstevel ddi_acc_handle_t handle; 8601708Sstevel int boff; 8611708Sstevel union { 8621708Sstevel uint8_t cbuf[UINT32SZ]; 8631708Sstevel uint32_t data; 8641708Sstevel } word; 8651708Sstevel 8661708Sstevel int error = 0; 8671708Sstevel uint8_t *buf = (uint8_t *)dptr; 8681708Sstevel 8691708Sstevel /* 8701708Sstevel * We try to write to the IOSRAM using double word or word access 8711708Sstevel * provided both "off" and "buf" are (or can be) double word or word 8721708Sstevel * aligned. Othewise, we try to align the "off" to a word boundary and 8731708Sstevel * then try to write data to the IOSRAM using word access, but read data 8741708Sstevel * from the buf buffer using byte access. 8751708Sstevel * 8761708Sstevel * If the leading/trailing portion of the IOSRAM data is not word 8771708Sstevel * aligned, it will always be written using byte access. 8781708Sstevel */ 8791708Sstevel IOSRAMLOG(1, "WR: key: 0x%x off:%x len:%x buf:%p\n", 8801708Sstevel key, off, len, buf); 8811708Sstevel 8821708Sstevel /* 8831708Sstevel * Acquire lock and look for the requested chunk. If it exists, make 8841708Sstevel * sure the requested write is within the chunk's bounds and no tunnel 8851708Sstevel * switch is active. 8861708Sstevel */ 8871708Sstevel mutex_enter(&iosram_mutex); 8881708Sstevel chunkp = iosram_find_chunk(key); 8891708Sstevel chunk_len = (chunkp != NULL) ? chunkp->toc_data.len : 0; 8901708Sstevel 8911708Sstevel if (iosram_master == NULL) { 8921708Sstevel error = EIO; 8931708Sstevel } else if (chunkp == NULL) { 8941708Sstevel error = EINVAL; 8951708Sstevel } else if ((off >= chunk_len) || (len > chunk_len) || 8961708Sstevel ((off+len) > chunk_len)) { 8971708Sstevel error = EMSGSIZE; 8981708Sstevel } else if (iosram_tswitch_active && !force) { 8991708Sstevel error = EAGAIN; 9001708Sstevel } 9011708Sstevel 9021708Sstevel if (error) { 9031708Sstevel mutex_exit(&iosram_mutex); 9041708Sstevel return (error); 9051708Sstevel } 9061708Sstevel 9071708Sstevel /* 9081708Sstevel * If this is a forced write and there's a tunnel switch in progress, 9091708Sstevel * abort the switch. 9101708Sstevel */ 9111708Sstevel if (iosram_tswitch_active && force) { 9121708Sstevel cmn_err(CE_NOTE, "!iosram: Aborting tswitch on force_write"); 9131708Sstevel iosram_abort_tswitch(); 9141708Sstevel } 9151708Sstevel 9161708Sstevel /* 9171708Sstevel * Bump reference count to indicate #thread accessing IOSRAM 9181708Sstevel * and release the lock. 9191708Sstevel */ 9201708Sstevel iosram_rw_active++; 9211708Sstevel #if defined(DEBUG) 9221708Sstevel if (iosram_rw_active > iosram_rw_active_max) { 9231708Sstevel iosram_rw_active_max = iosram_rw_active; 9241708Sstevel } 9251708Sstevel #endif 9261708Sstevel mutex_exit(&iosram_mutex); 9271708Sstevel 9281708Sstevel 9291708Sstevel IOSRAM_STAT(write); 9301708Sstevel IOSRAM_STAT_ADD(bwrite, len); 9311708Sstevel 9321708Sstevel /* Get starting address and map handle */ 9331708Sstevel iosramp = chunkp->basep + off; 9341708Sstevel handle = iosram_handle; 9351708Sstevel 9361708Sstevel /* 9371708Sstevel * Align the off to word boundary and then try reading/writing 9381708Sstevel * data using double word or word access. 9391708Sstevel */ 9401708Sstevel if ((boff = ((uintptr_t)iosramp & (UINT32SZ - 1))) != 0) { 9411708Sstevel int cnt = UINT32SZ - boff; 9421708Sstevel 9431708Sstevel if (cnt > len) { 9441708Sstevel cnt = len; 9451708Sstevel } 9461708Sstevel IOSRAMLOG(2, 9471708Sstevel "WR: align rep_put8(buf:%p sramp:%p cnt:%x) len:%x\n", 9481708Sstevel buf, iosramp, cnt, len); 9491708Sstevel ddi_rep_put8(handle, buf, iosramp, cnt, DDI_DEV_AUTOINCR); 9501708Sstevel buf += cnt; 9511708Sstevel iosramp += cnt; 9521708Sstevel len -= cnt; 9531708Sstevel } 9541708Sstevel 9551708Sstevel if ((len >= UINT64SZ) && 9561708Sstevel ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT64SZ - 1)) == 0)) { 9571708Sstevel /* 9581708Sstevel * Both source and destination are double word aligned 9591708Sstevel */ 9601708Sstevel int cnt = len/UINT64SZ; 9611708Sstevel 9621708Sstevel IOSRAMLOG(2, 9631708Sstevel "WR: rep_put64(buf:%p sramp:%p cnt:%x) len:%x\n", 9641708Sstevel buf, iosramp, cnt, len); 9651708Sstevel ddi_rep_put64(handle, (uint64_t *)buf, (uint64_t *)iosramp, 9661708Sstevel cnt, DDI_DEV_AUTOINCR); 9671708Sstevel iosramp += cnt * UINT64SZ; 9681708Sstevel buf += cnt * UINT64SZ; 9691708Sstevel len -= cnt * UINT64SZ; 9701708Sstevel 9711708Sstevel /* 9721708Sstevel * Copy the remaining data using word & byte access 9731708Sstevel */ 9741708Sstevel if (len >= UINT32SZ) { 9751708Sstevel IOSRAMLOG(2, 9761708Sstevel "WR: put32(buf:%p sramp:%p) len:%x\n", buf, iosramp, 9771708Sstevel len, NULL); 9781708Sstevel ddi_put32(handle, (uint32_t *)iosramp, 9791708Sstevel *(uint32_t *)buf); 9801708Sstevel iosramp += UINT32SZ; 9811708Sstevel buf += UINT32SZ; 9821708Sstevel len -= UINT32SZ; 9831708Sstevel } 9841708Sstevel 9851708Sstevel if (len != 0) { 9861708Sstevel ddi_rep_put8(handle, buf, iosramp, len, 9871708Sstevel DDI_DEV_AUTOINCR); 9881708Sstevel } 9891708Sstevel } else if ((len >= UINT32SZ) && 9901708Sstevel ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT32SZ - 1)) == 0)) { 9911708Sstevel /* 9921708Sstevel * Both source and destination are word aligned 9931708Sstevel */ 9941708Sstevel int cnt = len/UINT32SZ; 9951708Sstevel 9961708Sstevel IOSRAMLOG(2, 9971708Sstevel "WR: rep_put32(buf:%p sramp:%p cnt:%x) len:%x\n", 9981708Sstevel buf, iosramp, cnt, len); 9991708Sstevel ddi_rep_put32(handle, (uint32_t *)buf, (uint32_t *)iosramp, 10001708Sstevel cnt, DDI_DEV_AUTOINCR); 10011708Sstevel iosramp += cnt * UINT32SZ; 10021708Sstevel buf += cnt * UINT32SZ; 10031708Sstevel len -= cnt * UINT32SZ; 10041708Sstevel 10051708Sstevel /* 10061708Sstevel * copy the remainder using byte access 10071708Sstevel */ 10081708Sstevel if (len != 0) { 10091708Sstevel ddi_rep_put8(handle, buf, iosramp, len, 10101708Sstevel DDI_DEV_AUTOINCR); 10111708Sstevel } 10121708Sstevel } else if (len != 0) { 10131708Sstevel /* 10141708Sstevel * We know that the "off" is at least word aligned. We 10151708Sstevel * need to read data from buf buffer byte at a time, and 10161708Sstevel * write it to the IOSRAM word at a time. 10171708Sstevel */ 10181708Sstevel 10191708Sstevel ASSERT(((uintptr_t)iosramp & (UINT32SZ - 1)) == 0); 10201708Sstevel 10211708Sstevel IOSRAMLOG(2, 10221708Sstevel "WR: unaligned put32(buf:%p sramp:%p) len:%x\n", 10231708Sstevel buf, iosramp, len, NULL); 10241708Sstevel for (; len >= UINT32SZ; len -= UINT32SZ, iosramp += UINT32SZ) { 10251708Sstevel word.cbuf[0] = *buf++; 10261708Sstevel word.cbuf[1] = *buf++; 10271708Sstevel word.cbuf[2] = *buf++; 10281708Sstevel word.cbuf[3] = *buf++; 10291708Sstevel ddi_put32(handle, (uint32_t *)iosramp, word.data); 10301708Sstevel } 10311708Sstevel 10321708Sstevel /* 10331708Sstevel * copy the remaining data using byte access 10341708Sstevel */ 10351708Sstevel if (len != 0) { 10361708Sstevel ddi_rep_put8(handle, buf, iosramp, 10371708Sstevel len, DDI_DEV_AUTOINCR); 10381708Sstevel } 10391708Sstevel } 10401708Sstevel 10411708Sstevel /* 10421708Sstevel * Reacquire mutex lock, decrement refcnt and if refcnt is 0 and 10431708Sstevel * any threads are waiting for r/w activity to complete, wake them up. 10441708Sstevel */ 10451708Sstevel mutex_enter(&iosram_mutex); 10461708Sstevel ASSERT(iosram_rw_active > 0); 10471708Sstevel 10481708Sstevel if ((--iosram_rw_active == 0) && iosram_rw_wakeup) { 10491708Sstevel iosram_rw_wakeup = 0; 10501708Sstevel cv_broadcast(&iosram_rw_wait); 10511708Sstevel } 10521708Sstevel mutex_exit(&iosram_mutex); 10531708Sstevel 10541708Sstevel return (error); 10551708Sstevel } 10561708Sstevel 10571708Sstevel 10581708Sstevel int 10591708Sstevel iosram_force_write(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr) 10601708Sstevel { 10611708Sstevel return (_iosram_write(key, off, len, dptr, 1 /* force */)); 10621708Sstevel } 10631708Sstevel 10641708Sstevel 10651708Sstevel int 10661708Sstevel iosram_wr(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr) 10671708Sstevel { 10681708Sstevel return (_iosram_write(key, off, len, dptr, 0)); 10691708Sstevel } 10701708Sstevel 10711708Sstevel 10721708Sstevel /* 10731708Sstevel * iosram_register(key, handler, arg) 10741708Sstevel * Register a handler and an arg for the specified chunk. This handler 10751708Sstevel * will be invoked when an interrupt is received from the other side and 10761708Sstevel * the int_pending flag for the corresponding key is marked 10771708Sstevel * IOSRAM_INT_TO_DOM. 10781708Sstevel */ 10791708Sstevel /* ARGSUSED */ 10801708Sstevel int 10811708Sstevel iosram_register(uint32_t key, void (*handler)(), void *arg) 10821708Sstevel { 10831708Sstevel struct iosram_chunk *chunkp; 10841708Sstevel int error = 0; 10851708Sstevel 10861708Sstevel /* 10871708Sstevel * Acquire lock and look for the requested chunk. If it exists, and no 10881708Sstevel * other callback is registered, proceed with the registration. 10891708Sstevel */ 10901708Sstevel mutex_enter(&iosram_mutex); 10911708Sstevel chunkp = iosram_find_chunk(key); 10921708Sstevel 10931708Sstevel if (iosram_master == NULL) { 10941708Sstevel error = EIO; 10951708Sstevel } else if (chunkp == NULL) { 10961708Sstevel error = EINVAL; 10971708Sstevel } else if (chunkp->cback.handler != NULL) { 10981708Sstevel error = EBUSY; 10991708Sstevel } else { 11001708Sstevel chunkp->cback.busy = 0; 11011708Sstevel chunkp->cback.unregister = 0; 11021708Sstevel chunkp->cback.handler = handler; 11031708Sstevel chunkp->cback.arg = arg; 11041708Sstevel } 11051708Sstevel mutex_exit(&iosram_mutex); 11061708Sstevel 11071708Sstevel IOSRAMLOG(1, "REG: key: 0x%x hdlr:%p arg:%p error:%d\n", 11081708Sstevel key, handler, arg, error); 11091708Sstevel 11101708Sstevel return (error); 11111708Sstevel } 11121708Sstevel 11131708Sstevel 11141708Sstevel /* 11151708Sstevel * iosram_unregister() 11161708Sstevel * Unregister handler associated with the specified chunk. 11171708Sstevel */ 11181708Sstevel int 11191708Sstevel iosram_unregister(uint32_t key) 11201708Sstevel { 11211708Sstevel struct iosram_chunk *chunkp; 11221708Sstevel int error = 0; 11231708Sstevel 11241708Sstevel /* 11251708Sstevel * Acquire lock and look for the requested chunk. If it exists and has 11261708Sstevel * a callback registered, unregister it. 11271708Sstevel */ 11281708Sstevel mutex_enter(&iosram_mutex); 11291708Sstevel chunkp = iosram_find_chunk(key); 11301708Sstevel 11311708Sstevel if (iosram_master == NULL) { 11321708Sstevel error = EIO; 11331708Sstevel } else if (chunkp == NULL) { 11341708Sstevel error = EINVAL; 11351708Sstevel } else if (chunkp->cback.busy) { 11361708Sstevel /* 11371708Sstevel * If the handler is already busy (being invoked), then we flag 11381708Sstevel * it so it will be unregistered after the invocation completes. 11391708Sstevel */ 11401708Sstevel DPRINTF(1, ("IOSRAM(%d): unregister: delaying unreg k:0x%08x\n", 11411708Sstevel iosram_master->instance, key)); 11421708Sstevel chunkp->cback.unregister = 1; 11431708Sstevel } else if (chunkp->cback.handler != NULL) { 11441708Sstevel chunkp->cback.handler = NULL; 11451708Sstevel chunkp->cback.arg = NULL; 11461708Sstevel } 11471708Sstevel mutex_exit(&iosram_mutex); 11481708Sstevel 11491708Sstevel IOSRAMLOG(1, "UNREG: key:%x error:%d\n", key, error, NULL, NULL); 11501708Sstevel return (error); 11511708Sstevel } 11521708Sstevel 11531708Sstevel 11541708Sstevel /* 11551708Sstevel * iosram_get_flag(): 11561708Sstevel * Get data_valid and/or int_pending flags associated with the 11571708Sstevel * specified key. 11581708Sstevel */ 11591708Sstevel int 11601708Sstevel iosram_get_flag(uint32_t key, uint8_t *data_valid, uint8_t *int_pending) 11611708Sstevel { 11621708Sstevel iosram_chunk_t *chunkp; 11631708Sstevel iosram_flags_t flags; 11641708Sstevel int error = 0; 11651708Sstevel 11661708Sstevel /* 11671708Sstevel * Acquire lock and look for the requested chunk. If it exists, and no 11681708Sstevel * tunnel switch is in progress, read the chunk's flags. 11691708Sstevel */ 11701708Sstevel mutex_enter(&iosram_mutex); 11711708Sstevel chunkp = iosram_find_chunk(key); 11721708Sstevel 11731708Sstevel if (iosram_master == NULL) { 11741708Sstevel error = EIO; 11751708Sstevel } else if (chunkp == NULL) { 11761708Sstevel error = EINVAL; 11771708Sstevel } else if (iosram_tswitch_active) { 11781708Sstevel error = EAGAIN; 11791708Sstevel } else { 11801708Sstevel IOSRAM_STAT(getflag); 11811708Sstevel 11821708Sstevel /* 11831708Sstevel * Read the flags 11841708Sstevel */ 11851708Sstevel ddi_rep_get8(iosram_handle, (uint8_t *)&flags, 11861708Sstevel (uint8_t *)(chunkp->flagsp), sizeof (iosram_flags_t), 11871708Sstevel DDI_DEV_AUTOINCR); 11881708Sstevel 11891708Sstevel /* 11901708Sstevel * Get each flag value that the caller is interested in. 11911708Sstevel */ 11921708Sstevel if (data_valid != NULL) { 11931708Sstevel *data_valid = flags.data_valid; 11941708Sstevel } 11951708Sstevel 11961708Sstevel if (int_pending != NULL) { 11971708Sstevel *int_pending = flags.int_pending; 11981708Sstevel } 11991708Sstevel } 12001708Sstevel mutex_exit(&iosram_mutex); 12011708Sstevel 12021708Sstevel IOSRAMLOG(1, "GetFlag key:%x data_valid:%x int_pending:%x error:%d\n", 12031708Sstevel key, flags.data_valid, flags.int_pending, error); 12041708Sstevel return (error); 12051708Sstevel } 12061708Sstevel 12071708Sstevel 12081708Sstevel /* 12091708Sstevel * iosram_set_flag(): 12101708Sstevel * Set data_valid and int_pending flags associated with the specified key. 12111708Sstevel */ 12121708Sstevel int 12131708Sstevel iosram_set_flag(uint32_t key, uint8_t data_valid, uint8_t int_pending) 12141708Sstevel { 12151708Sstevel iosram_chunk_t *chunkp; 12161708Sstevel iosram_flags_t flags; 12171708Sstevel int error = 0; 12181708Sstevel 12191708Sstevel /* 12201708Sstevel * Acquire lock and look for the requested chunk. If it exists, and no 12211708Sstevel * tunnel switch is in progress, write the chunk's flags. 12221708Sstevel */ 12231708Sstevel mutex_enter(&iosram_mutex); 12241708Sstevel chunkp = iosram_find_chunk(key); 12251708Sstevel 12261708Sstevel if (iosram_master == NULL) { 12271708Sstevel error = EIO; 12281708Sstevel } else if ((chunkp == NULL) || 12291708Sstevel ((data_valid != IOSRAM_DATA_INVALID) && 12301708Sstevel (data_valid != IOSRAM_DATA_VALID)) || 12311708Sstevel ((int_pending != IOSRAM_INT_NONE) && 12321708Sstevel (int_pending != IOSRAM_INT_TO_SSC) && 12331708Sstevel (int_pending != IOSRAM_INT_TO_DOM))) { 12341708Sstevel error = EINVAL; 12351708Sstevel } else if (iosram_tswitch_active) { 12361708Sstevel error = EAGAIN; 12371708Sstevel } else { 12381708Sstevel IOSRAM_STAT(setflag); 12391708Sstevel flags.data_valid = data_valid; 12401708Sstevel flags.int_pending = int_pending; 12411708Sstevel ddi_rep_put8(iosram_handle, (uint8_t *)&flags, 12421708Sstevel (uint8_t *)(chunkp->flagsp), sizeof (iosram_flags_t), 12431708Sstevel DDI_DEV_AUTOINCR); 12441708Sstevel } 12451708Sstevel mutex_exit(&iosram_mutex); 12461708Sstevel 12471708Sstevel IOSRAMLOG(1, "SetFlag key:%x data_valid:%x int_pending:%x error:%d\n", 12481708Sstevel key, flags.data_valid, flags.int_pending, error); 12491708Sstevel return (error); 12501708Sstevel } 12511708Sstevel 12521708Sstevel 12531708Sstevel /* 12541708Sstevel * iosram_ctrl() 12551708Sstevel * This function provides access to a variety of services not available 12561708Sstevel * through the basic API. 12571708Sstevel */ 12581708Sstevel int 12591708Sstevel iosram_ctrl(uint32_t key, uint32_t cmd, void *arg) 12601708Sstevel { 12611708Sstevel struct iosram_chunk *chunkp; 12621708Sstevel int error = 0; 12631708Sstevel 12641708Sstevel /* 12651708Sstevel * Acquire lock and do some argument sanity checking. 12661708Sstevel */ 12671708Sstevel mutex_enter(&iosram_mutex); 12681708Sstevel chunkp = iosram_find_chunk(key); 12691708Sstevel 12701708Sstevel if (iosram_master == NULL) { 12711708Sstevel error = EIO; 12721708Sstevel } else if (chunkp == NULL) { 12731708Sstevel error = EINVAL; 12741708Sstevel } 12751708Sstevel 12761708Sstevel if (error != 0) { 12771708Sstevel mutex_exit(&iosram_mutex); 12781708Sstevel return (error); 12791708Sstevel } 12801708Sstevel 12811708Sstevel /* 12821708Sstevel * Arguments seem okay so far, so process the command. 12831708Sstevel */ 12841708Sstevel switch (cmd) { 12851708Sstevel case IOSRAM_CMD_CHUNKLEN: 12861708Sstevel /* 12871708Sstevel * Return the length of the chunk indicated by the key. 12881708Sstevel */ 12891708Sstevel if (arg == NULL) { 12901708Sstevel error = EINVAL; 12911708Sstevel break; 12921708Sstevel } 12931708Sstevel 12941708Sstevel *(uint32_t *)arg = chunkp->toc_data.len; 12951708Sstevel break; 12961708Sstevel 12971708Sstevel default: 12981708Sstevel error = ENOTSUP; 12991708Sstevel break; 13001708Sstevel } 13011708Sstevel 13021708Sstevel mutex_exit(&iosram_mutex); 13031708Sstevel return (error); 13041708Sstevel } 13051708Sstevel 13061708Sstevel 13071708Sstevel /* 13081708Sstevel * iosram_hdr_ctrl() 13091708Sstevel * This function provides an interface for the Mailbox Protocol 13101708Sstevel * implementation to use when interacting with the IOSRAM header. 13111708Sstevel */ 13121708Sstevel int 13131708Sstevel iosram_hdr_ctrl(uint32_t cmd, void *arg) 13141708Sstevel { 13151708Sstevel int error = 0; 13161708Sstevel 13171708Sstevel /* 13181708Sstevel * Acquire lock and do some argument sanity checking. 13191708Sstevel */ 13201708Sstevel mutex_enter(&iosram_mutex); 13211708Sstevel 13221708Sstevel if (iosram_master == NULL) { 13231708Sstevel error = EIO; 13241708Sstevel } 13251708Sstevel 13261708Sstevel if (error != 0) { 13271708Sstevel mutex_exit(&iosram_mutex); 13281708Sstevel return (error); 13291708Sstevel } 13301708Sstevel 13311708Sstevel switch (cmd) { 13321708Sstevel case IOSRAM_HDRCMD_GET_SMS_MBOX_VER: 13331708Sstevel /* 13341708Sstevel * Return the value of the sms_mbox_version field. 13351708Sstevel */ 13361708Sstevel if (arg == NULL) { 13371708Sstevel error = EINVAL; 13381708Sstevel break; 13391708Sstevel } 13401708Sstevel 13411708Sstevel *(uint32_t *)arg = IOSRAM_GET_HDRFIELD32(iosram_master, 13421708Sstevel sms_mbox_version); 13431708Sstevel break; 13441708Sstevel 13451708Sstevel case IOSRAM_HDRCMD_SET_OS_MBOX_VER: 13461708Sstevel /* 13471708Sstevel * Set the value of the os_mbox_version field. 13481708Sstevel */ 13491708Sstevel IOSRAM_SET_HDRFIELD32(iosram_master, os_mbox_version, 13501708Sstevel (uint32_t)(uintptr_t)arg); 13511708Sstevel IOSRAM_SET_HDRFIELD32(iosram_master, os_change_mask, 13521708Sstevel IOSRAM_HDRFIELD_OS_MBOX_VER); 13531708Sstevel iosram_send_intr(); 13541708Sstevel break; 13551708Sstevel 13561708Sstevel case IOSRAM_HDRCMD_REG_CALLBACK: 13571708Sstevel iosram_hdrchange_handler = (void (*)())arg; 13581708Sstevel break; 13591708Sstevel 13601708Sstevel default: 13611708Sstevel error = ENOTSUP; 13621708Sstevel break; 13631708Sstevel } 13641708Sstevel 13651708Sstevel mutex_exit(&iosram_mutex); 13661708Sstevel return (error); 13671708Sstevel } 13681708Sstevel 13691708Sstevel 13701708Sstevel /* 13711708Sstevel * iosram_softintr() 13721708Sstevel * IOSRAM soft interrupt handler 13731708Sstevel */ 13741708Sstevel static uint_t 13751708Sstevel iosram_softintr(caddr_t arg) 13761708Sstevel { 13771708Sstevel uint32_t hdr_changes; 13781708Sstevel iosramsoft_t *softp = (iosramsoft_t *)arg; 13791708Sstevel iosram_chunk_t *chunkp; 13801708Sstevel void (*handler)(); 13811708Sstevel int i; 13821708Sstevel uint8_t flag; 13831708Sstevel 13841708Sstevel DPRINTF(1, ("iosram(%d): in iosram_softintr\n", softp->instance)); 13851708Sstevel 13861708Sstevel IOSRAMLOG(2, "SINTR arg/softp:%p pending:%d busy:%d\n", 13871708Sstevel arg, softp->intr_pending, softp->intr_busy, NULL); 13881708Sstevel 13891708Sstevel mutex_enter(&iosram_mutex); 13901708Sstevel mutex_enter(&softp->intr_mutex); 13911708Sstevel 13921708Sstevel /* 13931708Sstevel * Do not process interrupt if interrupt handler is already running or 13941708Sstevel * no interrupts are pending. 13951708Sstevel */ 13961708Sstevel if (softp->intr_busy || !softp->intr_pending) { 13971708Sstevel mutex_exit(&softp->intr_mutex); 13981708Sstevel mutex_exit(&iosram_mutex); 13991708Sstevel DPRINTF(1, ("IOSRAM(%d): softintr: busy=%d pending=%d\n", 14001708Sstevel softp->instance, softp->intr_busy, softp->intr_pending)); 14011708Sstevel return (softp->intr_pending ? DDI_INTR_CLAIMED : 14021708Sstevel DDI_INTR_UNCLAIMED); 14031708Sstevel } 14041708Sstevel 14051708Sstevel /* 14061708Sstevel * It's possible for the SC to send an interrupt on the new master 14071708Sstevel * before we are able to set our internal state. If so, we'll retrigger 14081708Sstevel * soft interrupt right after tunnel switch completion. 14091708Sstevel */ 14101708Sstevel if (softp->state & IOSRAM_STATE_TSWITCH) { 14111708Sstevel mutex_exit(&softp->intr_mutex); 14121708Sstevel mutex_exit(&iosram_mutex); 14131708Sstevel DPRINTF(1, ("IOSRAM(%d): softintr: doing switch " 14141708Sstevel "state=0x%x\n", softp->instance, softp->state)); 14151708Sstevel return (DDI_INTR_CLAIMED); 14161708Sstevel } 14171708Sstevel 14181708Sstevel /* 14191708Sstevel * Do not process interrupt if we are not the master. 14201708Sstevel */ 14211708Sstevel if (!(softp->state & IOSRAM_STATE_MASTER)) { 14221708Sstevel mutex_exit(&softp->intr_mutex); 14231708Sstevel mutex_exit(&iosram_mutex); 14241708Sstevel DPRINTF(1, ("IOSRAM(%d): softintr: no master state=0x%x\n ", 14251708Sstevel softp->instance, softp->state)); 14261708Sstevel return (DDI_INTR_CLAIMED); 14271708Sstevel } 14281708Sstevel 14291708Sstevel IOSRAM_STAT(sintr_recv); 14301708Sstevel 14311708Sstevel /* 14321708Sstevel * If the driver is suspended, then we should not process any 14331708Sstevel * interrupts. Instead, we trigger a soft interrupt when the driver 14341708Sstevel * resumes. 14351708Sstevel */ 14361708Sstevel if (softp->suspended) { 14371708Sstevel mutex_exit(&softp->intr_mutex); 14381708Sstevel mutex_exit(&iosram_mutex); 14391708Sstevel DPRINTF(1, ("IOSRAM(%d): softintr: suspended\n", 14401708Sstevel softp->instance)); 14411708Sstevel return (DDI_INTR_CLAIMED); 14421708Sstevel } 14431708Sstevel 14441708Sstevel /* 14451708Sstevel * Indicate that the IOSRAM interrupt handler is busy. Note that this 14461708Sstevel * includes incrementing the reader/writer count, since we don't want 14471708Sstevel * any tunnel switches to start up while we're processing callbacks. 14481708Sstevel */ 14491708Sstevel softp->intr_busy = 1; 14501708Sstevel iosram_rw_active++; 14511708Sstevel #if defined(DEBUG) 14521708Sstevel if (iosram_rw_active > iosram_rw_active_max) { 14531708Sstevel iosram_rw_active_max = iosram_rw_active; 14541708Sstevel } 14551708Sstevel #endif 14561708Sstevel 14571708Sstevel do { 14581708Sstevel DPRINTF(1, ("IOSRAM(%d): softintr: processing interrupt\n", 14591708Sstevel softp->instance)); 14601708Sstevel 14611708Sstevel softp->intr_pending = 0; 14621708Sstevel 14631708Sstevel mutex_exit(&softp->intr_mutex); 14641708Sstevel 14651708Sstevel /* 14661708Sstevel * Process changes to the IOSRAM header. 14671708Sstevel */ 14681708Sstevel hdr_changes = IOSRAM_GET_HDRFIELD32(iosram_master, 14691708Sstevel sms_change_mask); 14701708Sstevel if (hdr_changes != 0) { 14711708Sstevel int error; 14721708Sstevel 14731708Sstevel IOSRAM_SET_HDRFIELD32(iosram_master, sms_change_mask, 14741708Sstevel 0); 14751708Sstevel if (hdr_changes & IOSRAM_HDRFIELD_TOC_INDEX) { 14761708Sstevel /* 14771708Sstevel * XXX is it safe to temporarily release the 14781708Sstevel * iosram_mutex here? 14791708Sstevel */ 14801708Sstevel mutex_exit(&iosram_mutex); 14811708Sstevel error = iosram_read_toc(iosram_master); 14821708Sstevel mutex_enter(&iosram_mutex); 14831708Sstevel if (error) { 14841708Sstevel cmn_err(CE_WARN, "iosram_read_toc: new" 14851708Sstevel " TOC invalid; using old TOC."); 14861708Sstevel } 14871708Sstevel iosram_update_addrs(iosram_master); 14881708Sstevel } 14891708Sstevel 14901708Sstevel if (iosram_hdrchange_handler != NULL) { 14911708Sstevel mutex_exit(&iosram_mutex); 14921708Sstevel iosram_hdrchange_handler(); 14931708Sstevel mutex_enter(&iosram_mutex); 14941708Sstevel } 14951708Sstevel } 14961708Sstevel 14971708Sstevel /* 14981708Sstevel * Get data_valid/int_pending flags and generate a callback if 14991708Sstevel * applicable. For now, we read only those flags for which a 15001708Sstevel * callback has been registered. We can optimize reading of 15011708Sstevel * flags by reading them all at once and then process them 15021708Sstevel * later. 15031708Sstevel */ 15041708Sstevel for (i = 0, chunkp = chunks; i < nchunks; i++, 15051708Sstevel chunkp++) { 15061708Sstevel #if DEBUG 15071708Sstevel flag = ddi_get8(iosram_handle, 15081708Sstevel &(chunkp->flagsp->int_pending)); 15091708Sstevel DPRINTF(1, ("IOSRAM(%d): softintr chunk #%d " 15101708Sstevel "flag=0x%x handler=%p\n", 15111708Sstevel softp->instance, i, (int)flag, 15121708Sstevel chunkp->cback.handler)); 15131708Sstevel #endif 15141708Sstevel if ((handler = chunkp->cback.handler) == NULL) { 15151708Sstevel continue; 15161708Sstevel } 15171708Sstevel flag = ddi_get8(iosram_handle, 15181708Sstevel &(chunkp->flagsp->int_pending)); 15191708Sstevel if (flag == IOSRAM_INT_TO_DOM) { 15201708Sstevel DPRINTF(1, 15211708Sstevel ("IOSRAM(%d): softintr: invoking handler\n", 15221708Sstevel softp->instance)); 15231708Sstevel IOSRAMLOG(1, 15241708Sstevel "SINTR invoking hdlr:%p arg:%p index:%d\n", 15251708Sstevel handler, chunkp->cback.arg, i, NULL); 15261708Sstevel IOSRAM_STAT(callbacks); 15271708Sstevel 15281708Sstevel ddi_put8(iosram_handle, 15291708Sstevel &(chunkp->flagsp->int_pending), 15301708Sstevel IOSRAM_INT_NONE); 15311708Sstevel chunkp->cback.busy = 1; 15321708Sstevel mutex_exit(&iosram_mutex); 15331708Sstevel (*handler)(chunkp->cback.arg); 15341708Sstevel mutex_enter(&iosram_mutex); 15351708Sstevel chunkp->cback.busy = 0; 15361708Sstevel 15371708Sstevel /* 15381708Sstevel * If iosram_unregister was called while the 15391708Sstevel * callback was being invoked, complete the 15401708Sstevel * unregistration here. 15411708Sstevel */ 15421708Sstevel if (chunkp->cback.unregister) { 15431708Sstevel DPRINTF(1, ("IOSRAM(%d): softintr: " 15441708Sstevel "delayed unreg k:0x%08x\n", 15451708Sstevel softp->instance, 15461708Sstevel chunkp->toc_data.key)); 15471708Sstevel chunkp->cback.handler = NULL; 15481708Sstevel chunkp->cback.arg = NULL; 15491708Sstevel chunkp->cback.unregister = 0; 15501708Sstevel } 15511708Sstevel } 15521708Sstevel 15531708Sstevel /* 15541708Sstevel * If there's a tunnel switch waiting to run, give it 15551708Sstevel * higher priority than these callbacks by bailing out. 15561708Sstevel * They'll still be invoked on the new master iosram 15571708Sstevel * when the tunnel switch is done. 15581708Sstevel */ 15591708Sstevel if (iosram_tswitch_active) { 15601708Sstevel break; 15611708Sstevel } 15621708Sstevel } 15631708Sstevel 15641708Sstevel mutex_enter(&softp->intr_mutex); 15651708Sstevel 15661708Sstevel } while (softp->intr_pending && !softp->suspended && 15671708Sstevel !iosram_tswitch_active); 15681708Sstevel 15691708Sstevel /* 15701708Sstevel * Indicate IOSRAM interrupt handler is not BUSY any more 15711708Sstevel */ 15721708Sstevel softp->intr_busy = 0; 15731708Sstevel 15741708Sstevel ASSERT(iosram_rw_active > 0); 15751708Sstevel if ((--iosram_rw_active == 0) && iosram_rw_wakeup) { 15761708Sstevel iosram_rw_wakeup = 0; 15771708Sstevel cv_broadcast(&iosram_rw_wait); 15781708Sstevel } 15791708Sstevel 15801708Sstevel mutex_exit(&softp->intr_mutex); 15811708Sstevel mutex_exit(&iosram_mutex); 15821708Sstevel 15831708Sstevel DPRINTF(1, ("iosram(%d): softintr exit\n", softp->instance)); 15841708Sstevel 15851708Sstevel return (DDI_INTR_CLAIMED); 15861708Sstevel } 15871708Sstevel 15881708Sstevel 15891708Sstevel /* 15901708Sstevel * iosram_intr() 15911708Sstevel * IOSRAM real interrupt handler 15921708Sstevel */ 15931708Sstevel static uint_t 15941708Sstevel iosram_intr(caddr_t arg) 15951708Sstevel { 15961708Sstevel iosramsoft_t *softp = (iosramsoft_t *)arg; 15971708Sstevel int result = DDI_INTR_UNCLAIMED; 15981708Sstevel uint32_t int_status; 15991708Sstevel 16001708Sstevel DPRINTF(2, ("iosram(%d): in iosram_intr\n", softp->instance)); 16011708Sstevel 16021708Sstevel mutex_enter(&softp->intr_mutex); 16031708Sstevel 16041708Sstevel if (softp->sbbc_handle == NULL) { 16051708Sstevel /* 16061708Sstevel * The SBBC registers region is not mapped in. 16071708Sstevel * Set the interrupt pending flag here, and process the 16081708Sstevel * interrupt after the tunnel switch. 16091708Sstevel */ 16101708Sstevel DPRINTF(1, ("IOSRAM(%d): iosram_intr: SBBC not mapped\n", 16111708Sstevel softp->instance)); 16121708Sstevel softp->intr_pending = 1; 16131708Sstevel mutex_exit(&softp->intr_mutex); 16141708Sstevel return (DDI_INTR_UNCLAIMED); 16151708Sstevel } 16161708Sstevel 16171708Sstevel int_status = ddi_get32(softp->sbbc_handle, 16181708Sstevel &(softp->sbbc_region->int_status.reg)); 16191708Sstevel DPRINTF(1, ("iosram_intr: int_status = 0x%08x\n", int_status)); 16201708Sstevel 16211708Sstevel if (int_status & IOSRAM_SBBC_INT0) { 16221708Sstevel result = DDI_INTR_CLAIMED; 16231708Sstevel DPRINTF(1, ("iosram_intr: int0 detected!\n")); 16241708Sstevel } 16251708Sstevel 16261708Sstevel if (int_status & IOSRAM_SBBC_INT1) { 16271708Sstevel result = DDI_INTR_CLAIMED; 16281708Sstevel DPRINTF(1, ("iosram_intr: int1 detected!\n")); 16291708Sstevel } 16301708Sstevel 16311708Sstevel if (result == DDI_INTR_CLAIMED) { 16321708Sstevel ddi_put32(softp->sbbc_handle, 16331708Sstevel &(softp->sbbc_region->int_status.reg), int_status); 16341708Sstevel int_status = ddi_get32(softp->sbbc_handle, 16351708Sstevel &(softp->sbbc_region->int_status.reg)); 16361708Sstevel DPRINTF(1, ("iosram_intr: int_status = 0x%08x\n", 16371708Sstevel int_status)); 16381708Sstevel 16391708Sstevel softp->intr_pending = 1; 16401708Sstevel /* 16411708Sstevel * Trigger soft interrupt if not executing and 16421708Sstevel * not suspended. 16431708Sstevel */ 16441708Sstevel if (!softp->intr_busy && !softp->suspended && 16451708Sstevel (softp->softintr_id != NULL)) { 16461708Sstevel DPRINTF(1, ("iosram(%d): trigger softint\n", 16471708Sstevel softp->instance)); 16481708Sstevel ddi_trigger_softintr(softp->softintr_id); 16491708Sstevel } 16501708Sstevel } 16511708Sstevel 16521708Sstevel IOSRAM_STAT(intr_recv); 16531708Sstevel 16541708Sstevel mutex_exit(&softp->intr_mutex); 16551708Sstevel 16561708Sstevel IOSRAMLOG(2, "INTR arg/softp:%p pending:%d busy:%d\n", 16571708Sstevel arg, softp->intr_pending, softp->intr_busy, NULL); 16581708Sstevel DPRINTF(1, ("iosram(%d): iosram_intr exit\n", softp->instance)); 16591708Sstevel 16601708Sstevel return (result); 16611708Sstevel } 16621708Sstevel 16631708Sstevel 16641708Sstevel /* 16651708Sstevel * iosram_send_intr() 16661708Sstevel * Send an interrupt to the SSP side via AXQ driver 16671708Sstevel */ 16681708Sstevel int 16691708Sstevel iosram_send_intr() 16701708Sstevel { 16711708Sstevel IOSRAMLOG(1, "SendIntr called\n", NULL, NULL, NULL, NULL); 16721708Sstevel IOSRAM_STAT(intr_send); 16731708Sstevel DPRINTF(1, ("iosram iosram_send_intr invoked\n")); 16741708Sstevel 16751708Sstevel return (axq_cpu2ssc_intr(0)); 16761708Sstevel } 16771708Sstevel 16781708Sstevel 16791708Sstevel #if defined(DEBUG) 16801708Sstevel static void 16811708Sstevel iosram_dummy_cback(void *arg) 16821708Sstevel { 16831708Sstevel DPRINTF(1, ("iosram_dummy_cback invoked arg:%p\n", arg)); 16841708Sstevel } 16851708Sstevel #endif /* DEBUG */ 16861708Sstevel 16871708Sstevel 16881708Sstevel /*ARGSUSED1*/ 16891708Sstevel static int 16901708Sstevel iosram_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 16911708Sstevel int *rvalp) 16921708Sstevel { 16931708Sstevel struct iosramsoft *softp; 16941708Sstevel int error = DDI_SUCCESS; 16951708Sstevel 16961708Sstevel softp = ddi_get_soft_state(iosramsoft_statep, getminor(dev)); 16971708Sstevel if (softp == NULL) { 16981708Sstevel return (ENXIO); 16991708Sstevel } 17001708Sstevel IOSRAMLOG(1, "IOCTL: dev:%p cmd:%x arg:%p ... instance %d\n", 17011708Sstevel dev, cmd, arg, softp->instance); 17021708Sstevel 17031708Sstevel switch (cmd) { 17041708Sstevel #if defined(DEBUG) 17051708Sstevel case IOSRAM_GET_FLAG: 17067656SSherry.Moore@Sun.COM { 17071708Sstevel iosram_io_t req; 17081708Sstevel uint8_t data_valid, int_pending; 17091708Sstevel 17101708Sstevel if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) { 17111708Sstevel return (EFAULT); 17121708Sstevel } 17131708Sstevel 17141708Sstevel DPRINTF(2, ("IOSRAM_GET_FLAG(key:%x\n", req.key)); 17151708Sstevel 17161708Sstevel req.retval = iosram_get_flag(req.key, &data_valid, 17171708Sstevel &int_pending); 17181708Sstevel req.data_valid = (uint32_t)data_valid; 17191708Sstevel req.int_pending = (uint32_t)int_pending; 17201708Sstevel 17211708Sstevel if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) { 17221708Sstevel DPRINTF(1, 17231708Sstevel ("IOSRAM_GET_FLAG: can't copyout req.retval (%x)", 17241708Sstevel req.retval)); 17251708Sstevel error = EFAULT; 17261708Sstevel } 17271708Sstevel 17281708Sstevel return (error); 17297656SSherry.Moore@Sun.COM } 17301708Sstevel 17311708Sstevel case IOSRAM_SET_FLAG: 17327656SSherry.Moore@Sun.COM { 17331708Sstevel iosram_io_t req; 17341708Sstevel 17351708Sstevel if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) { 17361708Sstevel return (EFAULT); 17371708Sstevel } 17381708Sstevel 17391708Sstevel DPRINTF(2, ("IOSRAM_SET_FLAG(key:%x data_valid:%x " 17401708Sstevel "int_pending:%x\n", req.key, req.data_valid, 17411708Sstevel req.int_pending)); 17421708Sstevel 17431708Sstevel req.retval = iosram_set_flag(req.key, req.data_valid, 17441708Sstevel req.int_pending); 17451708Sstevel 17461708Sstevel if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) { 17471708Sstevel DPRINTF(1, ("IOSRAM_SET_FLAG: can't copyout req.retval" 17481708Sstevel " (%x)\n", req.retval)); 17491708Sstevel error = EFAULT; 17501708Sstevel } 17511708Sstevel 17521708Sstevel return (error); 17537656SSherry.Moore@Sun.COM } 17541708Sstevel 17551708Sstevel case IOSRAM_RD: 17567656SSherry.Moore@Sun.COM { 17571708Sstevel caddr_t bufp; 17581708Sstevel int len; 17591708Sstevel iosram_io_t req; 17601708Sstevel 17611708Sstevel if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) { 17621708Sstevel return (EFAULT); 17631708Sstevel } 17641708Sstevel 17651708Sstevel DPRINTF(2, ("IOSRAM_RD(k:%x o:%x len:%x bufp:%p\n", req.key, 17661708Sstevel req.off, req.len, (void *)(uintptr_t)req.bufp)); 17671708Sstevel 17681708Sstevel len = req.len; 17691708Sstevel bufp = kmem_alloc(len, KM_SLEEP); 17701708Sstevel 17711708Sstevel req.retval = iosram_rd(req.key, req.off, req.len, bufp); 17721708Sstevel 17731708Sstevel if (ddi_copyout(bufp, (void *)(uintptr_t)req.bufp, len, mode)) { 17741708Sstevel DPRINTF(1, ("IOSRAM_RD: copyout(%p, %p,%x,%x) failed\n", 17751708Sstevel bufp, (void *)(uintptr_t)req.bufp, len, mode)); 17761708Sstevel error = EFAULT; 17771708Sstevel } else if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) { 17781708Sstevel DPRINTF(1, ("IOSRAM_RD: can't copyout retval (%x)\n", 17791708Sstevel req.retval)); 17801708Sstevel error = EFAULT; 17811708Sstevel } 17821708Sstevel 17831708Sstevel kmem_free(bufp, len); 17841708Sstevel return (error); 17857656SSherry.Moore@Sun.COM } 17861708Sstevel 17871708Sstevel case IOSRAM_WR: 17887656SSherry.Moore@Sun.COM { 17891708Sstevel caddr_t bufp; 17901708Sstevel iosram_io_t req; 17911708Sstevel int len; 17921708Sstevel 17931708Sstevel if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) { 17941708Sstevel return (EFAULT); 17951708Sstevel } 17961708Sstevel 17971708Sstevel DPRINTF(2, ("IOSRAM_WR(k:%x o:%x len:%x bufp:%p\n", 17981708Sstevel req.key, req.off, req.len, req.bufp)); 17991708Sstevel len = req.len; 18001708Sstevel bufp = kmem_alloc(len, KM_SLEEP); 18011708Sstevel if (ddi_copyin((void *)(uintptr_t)req.bufp, bufp, len, mode)) { 18021708Sstevel error = EFAULT; 18031708Sstevel } else { 18041708Sstevel req.retval = iosram_wr(req.key, req.off, req.len, 18051708Sstevel bufp); 18061708Sstevel 18071708Sstevel if (ddi_copyout(&req, (void *)arg, sizeof (req), 18081708Sstevel mode)) { 18091708Sstevel error = EFAULT; 18101708Sstevel } 18111708Sstevel } 18121708Sstevel kmem_free(bufp, len); 18131708Sstevel return (error); 18147656SSherry.Moore@Sun.COM } 18151708Sstevel 18161708Sstevel case IOSRAM_TOC: 18177656SSherry.Moore@Sun.COM { 18181708Sstevel caddr_t bufp; 18191708Sstevel int len; 18201708Sstevel iosram_io_t req; 18211708Sstevel 18221708Sstevel if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) { 18231708Sstevel return (EFAULT); 18241708Sstevel } 18251708Sstevel 18261708Sstevel DPRINTF(2, ("IOSRAM_TOC (req.bufp:%x req.len:%x) \n", 18271708Sstevel req.bufp, req.len)); 18281708Sstevel 18291708Sstevel len = req.len; 18301708Sstevel bufp = kmem_alloc(len, KM_SLEEP); 18311708Sstevel 18321708Sstevel req.retval = iosram_get_keys((iosram_toc_entry_t *)bufp, 18331708Sstevel &req.len); 18341708Sstevel 18351708Sstevel if (ddi_copyout(bufp, (void *)(uintptr_t)req.bufp, req.len, 18361708Sstevel mode)) { 18371708Sstevel DPRINTF(1, 18381708Sstevel ("IOSRAM_TOC: copyout(%p, %p,%x,%x) failed\n", 18391708Sstevel bufp, (void *)(uintptr_t)req.bufp, req.len, mode)); 18401708Sstevel error = EFAULT; 18411708Sstevel } else if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) { 18421708Sstevel DPRINTF(1, ("IOSRAM_TOC: can't copyout retval (%x)\n", 18431708Sstevel req.retval)); 18441708Sstevel error = EFAULT; 18451708Sstevel } 18461708Sstevel kmem_free(bufp, len); 18471708Sstevel return (error); 18487656SSherry.Moore@Sun.COM } 18491708Sstevel 18501708Sstevel case IOSRAM_SEND_INTR: 18517656SSherry.Moore@Sun.COM { 18521708Sstevel DPRINTF(2, ("IOSRAM_SEND_INTR\n")); 18531708Sstevel 18541708Sstevel switch ((int)arg) { 18551708Sstevel case 0x11: 18561708Sstevel case 0x22: 18571708Sstevel case 0x44: 18581708Sstevel case 0x88: 18591708Sstevel ddi_put32(softp->sbbc_handle, 18601708Sstevel &(softp->sbbc_region->int_enable.reg), (int)arg); 18611708Sstevel DPRINTF(1, ("Wrote 0x%x to int_enable.reg\n", 18621708Sstevel (int)arg)); 18631708Sstevel break; 18641708Sstevel case 0xBB: 18651708Sstevel ddi_put32(softp->sbbc_handle, 18661708Sstevel &(softp->sbbc_region->p0_int_gen.reg), 1); 18671708Sstevel DPRINTF(1, ("Wrote 1 to p0_int_gen.reg\n")); 18681708Sstevel break; 18691708Sstevel default: 18701708Sstevel error = iosram_send_intr(); 18711708Sstevel } 18721708Sstevel 18731708Sstevel return (error); 18747656SSherry.Moore@Sun.COM } 18751708Sstevel 18761708Sstevel case IOSRAM_PRINT_CBACK: 18771708Sstevel iosram_print_cback(); 18781708Sstevel break; 18791708Sstevel 18801708Sstevel case IOSRAM_PRINT_STATE: 18811708Sstevel iosram_print_state((int)arg); 18821708Sstevel break; 18831708Sstevel 18841708Sstevel #if IOSRAM_STATS 18851708Sstevel case IOSRAM_PRINT_STATS: 18861708Sstevel iosram_print_stats(); 18871708Sstevel break; 18881708Sstevel #endif 18891708Sstevel 18901708Sstevel #if IOSRAM_LOG 18911708Sstevel case IOSRAM_PRINT_LOG: 18921708Sstevel iosram_print_log((int)arg); 18931708Sstevel break; 18941708Sstevel #endif 18951708Sstevel 18961708Sstevel case IOSRAM_TUNNEL_SWITCH: 18971708Sstevel error = iosram_switchfrom((int)arg); 18981708Sstevel break; 18991708Sstevel 19001708Sstevel case IOSRAM_PRINT_FLAGS: 19011708Sstevel iosram_print_flags(); 19021708Sstevel break; 19031708Sstevel 19041708Sstevel case IOSRAM_REG_CBACK: 19057656SSherry.Moore@Sun.COM { 19061708Sstevel iosram_io_t req; 19071708Sstevel 19081708Sstevel if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) { 19091708Sstevel return (EFAULT); 19101708Sstevel } 19111708Sstevel 19121708Sstevel DPRINTF(2, ("IOSRAM_REG_CBACK(k:%x)\n", req.key)); 19131708Sstevel 19141708Sstevel req.retval = iosram_register(req.key, iosram_dummy_cback, 19151708Sstevel (void *)(uintptr_t)req.key); 19161708Sstevel if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) { 19171708Sstevel error = EFAULT; 19181708Sstevel } 19191708Sstevel 19201708Sstevel return (error); 19217656SSherry.Moore@Sun.COM } 19221708Sstevel 19231708Sstevel case IOSRAM_UNREG_CBACK: 19247656SSherry.Moore@Sun.COM { 19251708Sstevel iosram_io_t req; 19261708Sstevel 19271708Sstevel if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) { 19281708Sstevel return (EFAULT); 19291708Sstevel } 19301708Sstevel 19311708Sstevel DPRINTF(2, ("IOSRAM_REG_CBACK(k:%x)\n", req.key)); 19321708Sstevel 19331708Sstevel req.retval = iosram_unregister(req.key); 19341708Sstevel if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) { 19351708Sstevel error = EFAULT; 19361708Sstevel } 19371708Sstevel 19381708Sstevel return (error); 19397656SSherry.Moore@Sun.COM } 19401708Sstevel 19411708Sstevel case IOSRAM_SEMA_ACQUIRE: 19421708Sstevel { 19431708Sstevel DPRINTF(1, ("IOSRAM_SEMA_ACQUIRE\n")); 19441708Sstevel error = iosram_sema_acquire(NULL); 19451708Sstevel return (error); 19461708Sstevel } 19471708Sstevel 19481708Sstevel case IOSRAM_SEMA_RELEASE: 19491708Sstevel { 19501708Sstevel DPRINTF(1, ("IOSRAM_SEMA_RELEASE\n")); 19511708Sstevel error = iosram_sema_release(); 19521708Sstevel return (error); 19531708Sstevel } 19541708Sstevel 19551708Sstevel #endif /* DEBUG */ 19561708Sstevel 19571708Sstevel default: 19581708Sstevel DPRINTF(1, ("iosram_ioctl: Illegal command %x\n", cmd)); 19591708Sstevel error = ENOTTY; 19601708Sstevel } 19611708Sstevel 19621708Sstevel return (error); 19631708Sstevel } 19641708Sstevel 19651708Sstevel 19661708Sstevel /* 19671708Sstevel * iosram_switch_tunnel(softp) 19681708Sstevel * Switch master tunnel to the specified instance 19691708Sstevel * Must be called while holding iosram_mutex 19701708Sstevel */ 19711708Sstevel /*ARGSUSED*/ 19721708Sstevel static int 19731708Sstevel iosram_switch_tunnel(iosramsoft_t *softp) 19741708Sstevel { 19751708Sstevel #ifdef DEBUG 19761708Sstevel int instance = softp->instance; 19771708Sstevel #endif 19781708Sstevel int error = 0; 19791708Sstevel iosramsoft_t *prev_master; 19801708Sstevel 19811708Sstevel ASSERT(mutex_owned(&iosram_mutex)); 19821708Sstevel 19831708Sstevel DPRINTF(1, ("tunnel switch new master:%p (%d) current master:%p (%d)\n", 19841708Sstevel softp, instance, iosram_master, 19851708Sstevel ((iosram_master) ? iosram_master->instance : -1))); 19861708Sstevel IOSRAMLOG(1, "TSWTCH: new_master:%p (%p) iosram_master:%p (%d)\n", 19871708Sstevel softp, instance, iosram_master, 19881708Sstevel ((iosram_master) ? iosram_master->instance : -1)); 19891708Sstevel 19901708Sstevel if (softp == NULL || (softp->state & IOSRAM_STATE_DETACH)) { 19911708Sstevel return (ENXIO); 19921708Sstevel } 19931708Sstevel if (iosram_master == softp) { 19941708Sstevel return (0); 19951708Sstevel } 19961708Sstevel 19971708Sstevel 19981708Sstevel /* 19991708Sstevel * We protect against the softp structure being deallocated by setting 20001708Sstevel * the IOSRAM_STATE_TSWITCH state flag. The detach routine will check 20011708Sstevel * for this flag and if set, it will wait for this flag to be reset or 20021708Sstevel * refuse the detach operation. 20031708Sstevel */ 20041708Sstevel iosram_new_master = softp; 20051708Sstevel softp->state |= IOSRAM_STATE_TSWITCH; 20061708Sstevel prev_master = iosram_master; 20071708Sstevel if (prev_master) { 20081708Sstevel prev_master->state |= IOSRAM_STATE_TSWITCH; 20091708Sstevel } 20101708Sstevel mutex_exit(&iosram_mutex); 20111708Sstevel 20121708Sstevel /* 20131708Sstevel * Map the target IOSRAM, read the TOC, and register interrupts if not 20141708Sstevel * already done. 20151708Sstevel */ 20161708Sstevel DPRINTF(1, ("iosram(%d): mapping IOSRAM and SBBC\n", 20171708Sstevel softp->instance)); 20181708Sstevel IOSRAMLOG(1, "TSWTCH: mapping instance:%d softp:%p\n", 20191708Sstevel instance, softp, NULL, NULL); 20201708Sstevel 20211708Sstevel if (iosram_setup_map(softp) != DDI_SUCCESS) { 20221708Sstevel error = ENXIO; 20231708Sstevel } else if ((chunks == NULL) && (iosram_read_toc(softp) != 0)) { 20241708Sstevel iosram_remove_map(softp); 20251708Sstevel error = EINVAL; 20261708Sstevel } else if (iosram_add_intr(softp) != DDI_SUCCESS) { 20271708Sstevel /* 20281708Sstevel * If there was no previous master, purge the TOC data that 20291708Sstevel * iosram_read_toc() created. 20301708Sstevel */ 20311708Sstevel if ((prev_master == NULL) && (chunks != NULL)) { 20321708Sstevel kmem_free(chunks, nchunks * sizeof (iosram_chunk_t)); 20331708Sstevel chunks = NULL; 20341708Sstevel nchunks = 0; 20351708Sstevel iosram_init_hashtab(); 20361708Sstevel } 20371708Sstevel iosram_remove_map(softp); 20381708Sstevel error = ENXIO; 20391708Sstevel } 20401708Sstevel 20411708Sstevel /* 20421708Sstevel * If we are asked to abort tunnel switch, do so now, before invoking 20431708Sstevel * the OBP callback. 20441708Sstevel */ 20451708Sstevel if (iosram_tswitch_aborted) { 20461708Sstevel 20471708Sstevel /* 20481708Sstevel * Once the tunnel switch is aborted, this thread should not 20491708Sstevel * resume. If it does, we simply log a message. We can't unmap 20501708Sstevel * the new master IOSRAM as it may be accessed in 20511708Sstevel * iosram_abort_tswitch(). It will be unmapped when it is 20521708Sstevel * detached. 20531708Sstevel */ 20541708Sstevel IOSRAMLOG(1, 20551708Sstevel "TSWTCH: aborted (pre OBP cback). Thread resumed.\n", 20561708Sstevel NULL, NULL, NULL, NULL); 20571708Sstevel error = EIO; 20581708Sstevel } 20591708Sstevel 20601708Sstevel if (error) { 20611708Sstevel IOSRAMLOG(1, 20621708Sstevel "TSWTCH: map failed instance:%d softp:%p error:%x\n", 20631708Sstevel instance, softp, error, NULL); 20641708Sstevel goto done; 20651708Sstevel } 20661708Sstevel 20671708Sstevel if (prev_master != NULL) { 20681708Sstevel int result; 20691708Sstevel 20701708Sstevel /* 20711708Sstevel * Now invoke the OBP interface to do the tunnel switch. 20721708Sstevel */ 20731708Sstevel result = prom_starcat_switch_tunnel(softp->portid, 20741708Sstevel OBP_TSWITCH_REQREPLY); 20751708Sstevel if (result != 0) { 20761708Sstevel error = EIO; 20771708Sstevel } 20781708Sstevel IOSRAMLOG(1, 20791708Sstevel "TSWTCH: OBP tswitch portid:%x result:%x error:%x\n", 20801708Sstevel softp->portid, result, error, NULL); 20811708Sstevel IOSRAM_STAT(tswitch); 20821708Sstevel iosram_tswitch_tstamp = ddi_get_lbolt(); 20831708Sstevel } 20841708Sstevel 20851708Sstevel mutex_enter(&iosram_mutex); 20861708Sstevel if (iosram_tswitch_aborted) { 20871708Sstevel /* 20881708Sstevel * Tunnel switch aborted. This thread should not resume. 20891708Sstevel * For now, we simply log a message, but don't unmap any 20901708Sstevel * IOSRAM at this stage as it may be accessed within the 20911708Sstevel * isoram_abort_tswitch(). The IOSRAM will be unmapped 20921708Sstevel * when that instance is detached. 20931708Sstevel */ 20941708Sstevel if (iosram_tswitch_aborted) { 20951708Sstevel IOSRAMLOG(1, 20961708Sstevel "TSWTCH: aborted (post OBP cback). Thread" 20971708Sstevel " resumed.\n", NULL, NULL, NULL, NULL); 20981708Sstevel error = EIO; 20991708Sstevel mutex_exit(&iosram_mutex); 21001708Sstevel } 21011708Sstevel } else if (error) { 21021708Sstevel /* 21031708Sstevel * Tunnel switch failed. Continue using previous tunnel. 21041708Sstevel * However, unmap new (target) IOSRAM. 21051708Sstevel */ 21061708Sstevel iosram_new_master = NULL; 21071708Sstevel mutex_exit(&iosram_mutex); 21081708Sstevel iosram_remove_intr(softp); 21091708Sstevel iosram_remove_map(softp); 21101708Sstevel } else { 21111708Sstevel /* 21121708Sstevel * Tunnel switch was successful. Set the new master. 21131708Sstevel * Also unmap old master IOSRAM and remove any interrupts 21141708Sstevel * associated with that. 21151708Sstevel * 21161708Sstevel * Note that a call to iosram_force_write() allows access 21171708Sstevel * to the IOSRAM while tunnel switch is in progress. That 21181708Sstevel * means we need to set the new master before unmapping 21191708Sstevel * the old master. 21201708Sstevel */ 21211708Sstevel iosram_set_master(softp); 21221708Sstevel iosram_new_master = NULL; 21231708Sstevel mutex_exit(&iosram_mutex); 21241708Sstevel 21251708Sstevel if (prev_master) { 21261708Sstevel IOSRAMLOG(1, "TSWTCH: unmapping prev_master:%p (%d)\n", 21271708Sstevel prev_master, prev_master->instance, NULL, NULL); 21281708Sstevel iosram_remove_intr(prev_master); 21291708Sstevel iosram_remove_map(prev_master); 21301708Sstevel } 21311708Sstevel } 21321708Sstevel 21331708Sstevel done: 21341708Sstevel mutex_enter(&iosram_mutex); 21351708Sstevel 21361708Sstevel /* 21371708Sstevel * Clear the tunnel switch flag on the source and destination 21381708Sstevel * instances. 21391708Sstevel */ 21401708Sstevel if (prev_master) { 21411708Sstevel prev_master->state &= ~IOSRAM_STATE_TSWITCH; 21421708Sstevel } 21431708Sstevel softp->state &= ~IOSRAM_STATE_TSWITCH; 21441708Sstevel 21451708Sstevel /* 21461708Sstevel * Since incoming interrupts could get lost during a tunnel switch, 21471708Sstevel * trigger a soft interrupt just in case. No harm other than a bit 21481708Sstevel * of wasted effort will be caused if no interrupts were dropped. 21491708Sstevel */ 21501708Sstevel mutex_enter(&softp->intr_mutex); 21511708Sstevel iosram_master->intr_pending = 1; 21521708Sstevel if ((iosram_master->softintr_id != NULL) && 21531708Sstevel (iosram_master->intr_busy == 0)) { 21541708Sstevel ddi_trigger_softintr(iosram_master->softintr_id); 21551708Sstevel } 21561708Sstevel mutex_exit(&softp->intr_mutex); 21571708Sstevel 21581708Sstevel IOSRAMLOG(1, "TSWTCH: done error:%d iosram_master:%p instance:%d\n", 21591708Sstevel error, iosram_master, 21601708Sstevel (iosram_master) ? iosram_master->instance : -1, NULL); 21611708Sstevel 21621708Sstevel return (error); 21631708Sstevel } 21641708Sstevel 21651708Sstevel 21661708Sstevel /* 21671708Sstevel * iosram_abort_tswitch() 21681708Sstevel * Must be called while holding iosram_mutex. 21691708Sstevel */ 21701708Sstevel static void 21711708Sstevel iosram_abort_tswitch() 21721708Sstevel { 21731708Sstevel uint32_t master_valid, new_master_valid; 21741708Sstevel 21751708Sstevel ASSERT(mutex_owned(&iosram_mutex)); 21761708Sstevel 21771708Sstevel if ((!iosram_tswitch_active) || iosram_tswitch_aborted) { 21781708Sstevel return; 21791708Sstevel } 21801708Sstevel 21811708Sstevel ASSERT(iosram_master != NULL); 21821708Sstevel 21831708Sstevel IOSRAMLOG(1, "ABORT: iosram_master:%p (%d) iosram_new_master:%p (%d)\n", 21841708Sstevel iosram_master, iosram_master->instance, iosram_new_master, 21851708Sstevel (iosram_new_master == NULL) ? -1 : iosram_new_master->instance); 21861708Sstevel 21871708Sstevel /* 21881708Sstevel * The first call to iosram_force_write() in the middle of tunnel switch 21891708Sstevel * will get here. We lookup IOSRAM VALID location and setup appropriate 21901708Sstevel * master, if one is still valid. We also set iosram_tswitch_aborted to 21911708Sstevel * prevent reentering this code and to catch if the OBP callback thread 21921708Sstevel * somehow resumes. 21931708Sstevel */ 21941708Sstevel iosram_tswitch_aborted = 1; 21951708Sstevel 21961708Sstevel if ((iosram_new_master == NULL) || 21971708Sstevel (iosram_new_master = iosram_master)) { 21981708Sstevel /* 21991708Sstevel * New master hasn't been selected yet, or OBP callback 22001708Sstevel * succeeded and we already selected new IOSRAM as master, but 22011708Sstevel * system crashed in the middle of unmapping previous master or 22021708Sstevel * cleaning up state. Use the existing master. 22031708Sstevel */ 22041708Sstevel ASSERT(iosram_master->iosramp != NULL); 22051708Sstevel ASSERT(IOSRAM_GET_HDRFIELD32(iosram_master, status) == 22061708Sstevel IOSRAM_VALID); 22071708Sstevel IOSRAMLOG(1, "ABORT: master (%d) already determined.\n", 22081708Sstevel iosram_master->instance, NULL, NULL, NULL); 22091708Sstevel 22101708Sstevel return; 22111708Sstevel } 22121708Sstevel 22131708Sstevel /* 22141708Sstevel * System crashed in the middle of tunnel switch and we know that the 22151708Sstevel * new target has not been marked master yet. That means, the old 22161708Sstevel * master should still be mapped. We need to abort the tunnel switch 22171708Sstevel * and setup a valid master, if possible, so that we can write to the 22181708Sstevel * IOSRAM. 22191708Sstevel * 22201708Sstevel * We select a new master based upon the IOSRAM header status fields in 22211708Sstevel * the previous master IOSRAM and the target IOSRAM as follows: 22221708Sstevel * 22231708Sstevel * iosram_master iosram-tswitch 22241708Sstevel * (Prev Master) (New Target) Decision 22251708Sstevel * --------------- --------------- ----------- 22261708Sstevel * VALID don't care prev master 22271708Sstevel * INTRANSIT INVALID prev master 22281708Sstevel * INTRANSIT INTRANSIT prev master 22291708Sstevel * INTRANSIT VALID new target 22301708Sstevel * INVALID INVALID shouldn't ever happen 22311708Sstevel * INVALID INTRANSIT shouldn't ever happen 22321708Sstevel * INVALID VALID new target 22331708Sstevel */ 22341708Sstevel 22351708Sstevel master_valid = (iosram_master->iosramp != NULL) ? 22361708Sstevel IOSRAM_GET_HDRFIELD32(iosram_master, status) : IOSRAM_INVALID; 22371708Sstevel new_master_valid = (iosram_new_master->iosramp != NULL) ? 22381708Sstevel IOSRAM_GET_HDRFIELD32(iosram_new_master, status) : IOSRAM_INVALID; 22391708Sstevel 22401708Sstevel if (master_valid == IOSRAM_VALID) { 22411708Sstevel /* EMPTY */ 22421708Sstevel /* 22431708Sstevel * OBP hasn't been called yet or, if it has, it hasn't started 22441708Sstevel * copying yet. Use the existing master. Note that the new 22451708Sstevel * master may not be mapped yet. 22461708Sstevel */ 22471708Sstevel IOSRAMLOG(1, "ABORT: prev master(%d) is VALID\n", 22481708Sstevel iosram_master->instance, NULL, NULL, NULL); 22491708Sstevel } else if (master_valid == IOSRAM_INTRANSIT) { 22501708Sstevel /* 22511708Sstevel * The system crashed after OBP started processing the tunnel 22521708Sstevel * switch but before the iosram driver determined that it was 22531708Sstevel * complete. Use the new master if it has been marked valid, 22541708Sstevel * meaning that OBP finished copying data to it, or the old 22551708Sstevel * master otherwise. 22561708Sstevel */ 22571708Sstevel IOSRAMLOG(1, "ABORT: prev master(%d) is INTRANSIT\n", 22581708Sstevel iosram_master->instance, NULL, NULL, NULL); 22591708Sstevel 22601708Sstevel if (new_master_valid == IOSRAM_VALID) { 22611708Sstevel iosram_set_master(iosram_new_master); 22621708Sstevel IOSRAMLOG(1, "ABORT: new master(%d) is VALID\n", 22631708Sstevel iosram_new_master->instance, NULL, NULL, 22641708Sstevel NULL); 22651708Sstevel } else { 22661708Sstevel prom_starcat_switch_tunnel(iosram_master->portid, 22671708Sstevel OBP_TSWITCH_NOREPLY); 22681708Sstevel 22691708Sstevel IOSRAMLOG(1, "ABORT: new master(%d) is INVALID\n", 22701708Sstevel iosram_new_master->instance, NULL, NULL, 22711708Sstevel NULL); 22721708Sstevel } 22731708Sstevel } else { 22741708Sstevel /* 22751708Sstevel * The system crashed after OBP marked the old master INVALID, 22761708Sstevel * which means the new master is the way to go. 22771708Sstevel */ 22781708Sstevel IOSRAMLOG(1, "ABORT: prev master(%d) is INVALID\n", 22791708Sstevel iosram_master->instance, NULL, NULL, NULL); 22801708Sstevel 22811708Sstevel ASSERT(new_master_valid == IOSRAM_VALID); 22821708Sstevel 22831708Sstevel iosram_set_master(iosram_new_master); 22841708Sstevel } 22851708Sstevel 22861708Sstevel IOSRAMLOG(1, "ABORT: Instance %d selected as master\n", 22877656SSherry.Moore@Sun.COM iosram_master->instance, NULL, NULL, NULL); 22881708Sstevel } 22891708Sstevel 22901708Sstevel 22911708Sstevel /* 22921708Sstevel * iosram_switchfrom(instance) 22931708Sstevel * Switch master tunnel away from the specified instance 22941708Sstevel */ 22951708Sstevel /*ARGSUSED*/ 22961708Sstevel int 22971708Sstevel iosram_switchfrom(int instance) 22981708Sstevel { 22991708Sstevel struct iosramsoft *softp; 23001708Sstevel int error = 0; 23011708Sstevel int count; 23021708Sstevel clock_t current_tstamp; 23031708Sstevel clock_t tstamp_interval; 23041708Sstevel struct iosramsoft *last_master = NULL; 23051708Sstevel static int last_master_instance = -1; 23061708Sstevel 23071708Sstevel IOSRAMLOG(1, "SwtchFrom: instance:%d iosram_master:%p (%d)\n", 23081708Sstevel instance, iosram_master, 23091708Sstevel ((iosram_master) ? iosram_master->instance : -1), NULL); 23101708Sstevel 23111708Sstevel mutex_enter(&iosram_mutex); 23121708Sstevel 23131708Sstevel /* 23141708Sstevel * Wait if another tunnel switch is in progress 23151708Sstevel */ 23161708Sstevel for (count = 0; iosram_tswitch_active && count < IOSRAM_TSWITCH_RETRY; 23171708Sstevel count++) { 23181708Sstevel iosram_tswitch_wakeup = 1; 23191708Sstevel cv_wait(&iosram_tswitch_wait, &iosram_mutex); 23201708Sstevel } 23211708Sstevel 23221708Sstevel if (iosram_tswitch_active) { 23231708Sstevel mutex_exit(&iosram_mutex); 23241708Sstevel return (EAGAIN); 23251708Sstevel } 23261708Sstevel 23271708Sstevel /* 23281708Sstevel * Check if the specified instance holds the tunnel. If not, 23291708Sstevel * then we are done. 23301708Sstevel */ 23311708Sstevel if ((iosram_master == NULL) || (iosram_master->instance != instance)) { 23321708Sstevel mutex_exit(&iosram_mutex); 23331708Sstevel return (0); 23341708Sstevel } 23351708Sstevel 23361708Sstevel /* 23371708Sstevel * Before beginning the tunnel switch process, wait for any outstanding 23381708Sstevel * read/write activity to complete. 23391708Sstevel */ 23401708Sstevel iosram_tswitch_active = 1; 23411708Sstevel while (iosram_rw_active) { 23421708Sstevel iosram_rw_wakeup = 1; 23431708Sstevel cv_wait(&iosram_rw_wait, &iosram_mutex); 23441708Sstevel } 23451708Sstevel 23461708Sstevel /* 23471708Sstevel * If a previous tunnel switch just completed, we have to make sure 23481708Sstevel * HWAD has enough time to find the new tunnel before we switch 23491708Sstevel * away from it. Otherwise, OBP's mailbox message to OSD will never 23501708Sstevel * get through. Just to be paranoid about synchronization of lbolt 23511708Sstevel * across different CPUs, make sure the current attempt isn't noted 23521708Sstevel * as starting _before_ the last tunnel switch completed. 23531708Sstevel */ 23541708Sstevel current_tstamp = ddi_get_lbolt(); 23551708Sstevel if (current_tstamp > iosram_tswitch_tstamp) { 23561708Sstevel tstamp_interval = current_tstamp - iosram_tswitch_tstamp; 23571708Sstevel } else { 23581708Sstevel tstamp_interval = 0; 23591708Sstevel } 23601708Sstevel if (drv_hztousec(tstamp_interval) < IOSRAM_TSWITCH_DELAY_US) { 23611708Sstevel mutex_exit(&iosram_mutex); 23621708Sstevel delay(drv_usectohz(IOSRAM_TSWITCH_DELAY_US) - tstamp_interval); 23631708Sstevel mutex_enter(&iosram_mutex); 23641708Sstevel } 23651708Sstevel 23661708Sstevel /* 23671708Sstevel * The specified instance holds the tunnel. We need to move it to some 23681708Sstevel * other IOSRAM. Try out all possible IOSRAMs listed in 23691708Sstevel * iosram_instances. For now, we always search from the first entry. 23701708Sstevel * In future, it may be desirable to start where we left off. 23711708Sstevel */ 23721708Sstevel for (softp = iosram_instances; softp != NULL; softp = softp->next) { 23731708Sstevel if (iosram_tswitch_aborted) { 23741708Sstevel break; 23751708Sstevel } 23761708Sstevel 23771708Sstevel /* we can't switch _to_ the instance we're switching _from_ */ 23781708Sstevel if (softp->instance == instance) { 23791708Sstevel continue; 23801708Sstevel } 23811708Sstevel 23821708Sstevel /* skip over instances being detached */ 23831708Sstevel if (softp->state & IOSRAM_STATE_DETACH) { 23841708Sstevel continue; 23851708Sstevel } 23861708Sstevel 23871708Sstevel /* 23881708Sstevel * Try to avoid reverting to the last instance we switched away 23891708Sstevel * from, as we expect that one to be detached eventually. Keep 23901708Sstevel * track of it, though, so we can go ahead and try switching to 23911708Sstevel * it if no other viable candidates are found. 23921708Sstevel */ 23931708Sstevel if (softp->instance == last_master_instance) { 23941708Sstevel last_master = softp; 23951708Sstevel continue; 23961708Sstevel } 23971708Sstevel 23981708Sstevel /* 23991708Sstevel * Do the tunnel switch. If successful, record the instance of 24001708Sstevel * the master we just left behind so we can try to avoid 24011708Sstevel * reverting to it next time. 24021708Sstevel */ 24031708Sstevel if (iosram_switch_tunnel(softp) == 0) { 24041708Sstevel last_master_instance = instance; 24051708Sstevel break; 24061708Sstevel } 24071708Sstevel } 24081708Sstevel 24091708Sstevel /* 24101708Sstevel * If we failed to switch the tunnel, but we skipped over an instance 24111708Sstevel * that had previously been switched out of because we expected it to be 24121708Sstevel * detached, go ahead and try it anyway (unless the tswitch was aborted 24131708Sstevel * or the instance we skipped is finally being detached). 24141708Sstevel */ 24151708Sstevel if ((softp == NULL) && (last_master != NULL) && 24161708Sstevel !iosram_tswitch_aborted && 24171708Sstevel !(last_master->state & IOSRAM_STATE_DETACH)) { 24181708Sstevel if (iosram_switch_tunnel(last_master) == 0) { 24191708Sstevel softp = last_master; 24201708Sstevel last_master_instance = instance; 24211708Sstevel } 24221708Sstevel } 24231708Sstevel 24241708Sstevel if ((softp == NULL) || (iosram_tswitch_aborted)) { 24251708Sstevel error = EIO; 24261708Sstevel } 24271708Sstevel 24281708Sstevel /* 24291708Sstevel * If there are additional tunnel switches queued up waiting for this 24301708Sstevel * one to complete, wake them up. 24311708Sstevel */ 24321708Sstevel if (iosram_tswitch_wakeup) { 24331708Sstevel iosram_tswitch_wakeup = 0; 24341708Sstevel cv_broadcast(&iosram_tswitch_wait); 24351708Sstevel } 24361708Sstevel iosram_tswitch_active = 0; 24371708Sstevel mutex_exit(&iosram_mutex); 24381708Sstevel return (error); 24391708Sstevel } 24401708Sstevel 24411708Sstevel 24421708Sstevel /* 24431708Sstevel * iosram_tunnel_capable(softp) 24441708Sstevel * Check if this IOSRAM instance is tunnel-capable by looing at 24451708Sstevel * "tunnel-capable" property. 24461708Sstevel */ 24471708Sstevel static int 24481708Sstevel iosram_tunnel_capable(struct iosramsoft *softp) 24491708Sstevel { 24501708Sstevel int proplen; 24511708Sstevel int tunnel_capable; 24521708Sstevel 24531708Sstevel /* 24541708Sstevel * Look up IOSRAM_TUNNELOK_PROP property, if any. 24551708Sstevel */ 24561708Sstevel proplen = sizeof (tunnel_capable); 24571708Sstevel if (ddi_getlongprop_buf(DDI_DEV_T_ANY, softp->dip, 24581708Sstevel DDI_PROP_DONTPASS, IOSRAM_TUNNELOK_PROP, (caddr_t)&tunnel_capable, 24591708Sstevel &proplen) != DDI_PROP_SUCCESS) { 24601708Sstevel tunnel_capable = 0; 24611708Sstevel } 24621708Sstevel return (tunnel_capable); 24631708Sstevel } 24641708Sstevel 24651708Sstevel 24661708Sstevel static int 24671708Sstevel iosram_sbbc_setup_map(struct iosramsoft *softp) 24681708Sstevel { 24691708Sstevel int rv; 24701708Sstevel struct ddi_device_acc_attr attr; 24711708Sstevel dev_info_t *dip = softp->dip; 24721708Sstevel uint32_t sema_val; 24731708Sstevel 24741708Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 24751708Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 24761708Sstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 24771708Sstevel 24781708Sstevel mutex_enter(&iosram_mutex); 24791708Sstevel mutex_enter(&softp->intr_mutex); 24801708Sstevel 24811708Sstevel /* 24821708Sstevel * Map SBBC region in 24831708Sstevel */ 24841708Sstevel if ((rv = ddi_regs_map_setup(dip, IOSRAM_SBBC_MAP_INDEX, 24851708Sstevel (caddr_t *)&softp->sbbc_region, 24861708Sstevel IOSRAM_SBBC_MAP_OFFSET, sizeof (iosram_sbbc_region_t), 24871708Sstevel &attr, &softp->sbbc_handle)) != DDI_SUCCESS) { 24881708Sstevel DPRINTF(1, ("Failed to map SBBC region.\n")); 24891708Sstevel mutex_exit(&softp->intr_mutex); 24901708Sstevel mutex_exit(&iosram_mutex); 24911708Sstevel return (rv); 24921708Sstevel } 24931708Sstevel 24941708Sstevel /* 24951708Sstevel * Disable SBBC interrupts. SBBC interrupts are enabled 24961708Sstevel * once the interrupt handler is registered. 24971708Sstevel */ 24981708Sstevel ddi_put32(softp->sbbc_handle, 24991708Sstevel &(softp->sbbc_region->int_enable.reg), 0x0); 25001708Sstevel 25011708Sstevel /* 25021708Sstevel * Clear hardware semaphore value if appropriate. 25031708Sstevel * When the first SBBC is mapped in by the IOSRAM driver, 25041708Sstevel * the value of the semaphore should be initialized only 25051708Sstevel * if it is not held by SMS. For subsequent SBBC's, the 25061708Sstevel * semaphore will be always initialized. 25071708Sstevel */ 25081708Sstevel sema_val = IOSRAM_SEMA_RD(softp); 25091708Sstevel 25101708Sstevel if (!iosram_master) { 25111708Sstevel /* the first SBBC is being mapped in */ 25121708Sstevel if (!(IOSRAM_SEMA_IS_HELD(sema_val) && 25131708Sstevel IOSRAM_SEMA_GET_IDX(sema_val) == IOSRAM_SEMA_SMS_IDX)) { 25141708Sstevel /* not held by SMS, we clear the semaphore */ 25151708Sstevel IOSRAM_SEMA_WR(softp, 0); 25161708Sstevel } 25171708Sstevel } else { 25181708Sstevel /* not the first SBBC, we clear the semaphore */ 25191708Sstevel IOSRAM_SEMA_WR(softp, 0); 25201708Sstevel } 25211708Sstevel 25221708Sstevel mutex_exit(&softp->intr_mutex); 25231708Sstevel mutex_exit(&iosram_mutex); 25241708Sstevel return (0); 25251708Sstevel } 25261708Sstevel 25271708Sstevel 25281708Sstevel static int 25291708Sstevel iosram_setup_map(struct iosramsoft *softp) 25301708Sstevel { 25311708Sstevel int instance = softp->instance; 25321708Sstevel dev_info_t *dip = softp->dip; 25331708Sstevel int portid; 25341708Sstevel int proplen; 25351708Sstevel caddr_t propvalue; 25361708Sstevel struct ddi_device_acc_attr attr; 25371708Sstevel 25381708Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 25391708Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 25401708Sstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 25411708Sstevel 25421708Sstevel /* 25431708Sstevel * Lookup IOSRAM_REG_PROP property to find out our IOSRAM length 25441708Sstevel */ 25451708Sstevel if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 25461708Sstevel DDI_PROP_DONTPASS, IOSRAM_REG_PROP, (caddr_t)&propvalue, 25471708Sstevel &proplen) != DDI_PROP_SUCCESS) { 25481708Sstevel cmn_err(CE_WARN, "iosram(%d): can't find register property.\n", 25491708Sstevel instance); 25501708Sstevel return (DDI_FAILURE); 25511708Sstevel } else { 25521708Sstevel iosram_reg_t *regprop = (iosram_reg_t *)propvalue; 25531708Sstevel 25541708Sstevel DPRINTF(1, ("SetupMap(%d): Got reg prop: %x %x %x\n", 25551708Sstevel instance, regprop->addr_hi, 25561708Sstevel regprop->addr_lo, regprop->size)); 25571708Sstevel 25581708Sstevel softp->iosramlen = regprop->size; 25591708Sstevel 25601708Sstevel kmem_free(propvalue, proplen); 25611708Sstevel } 25621708Sstevel DPRINTF(1, ("SetupMap(%d): IOSRAM length: 0x%x\n", instance, 25631708Sstevel softp->iosramlen)); 25641708Sstevel softp->handle = NULL; 25651708Sstevel 25661708Sstevel /* 25671708Sstevel * To minimize boot time, we map the entire IOSRAM as opposed to 25681708Sstevel * mapping individual chunk via ddi_regs_map_setup() call. 25691708Sstevel */ 25701708Sstevel if (ddi_regs_map_setup(dip, 0, (caddr_t *)&softp->iosramp, 25711708Sstevel 0x0, softp->iosramlen, &attr, &softp->handle) != DDI_SUCCESS) { 25721708Sstevel cmn_err(CE_WARN, "iosram(%d): failed to map IOSRAM len:%x\n", 25731708Sstevel instance, softp->iosramlen); 25741708Sstevel iosram_remove_map(softp); 25751708Sstevel return (DDI_FAILURE); 25761708Sstevel } 25771708Sstevel 25781708Sstevel /* 25791708Sstevel * Lookup PORTID property on my parent hierarchy 25801708Sstevel */ 25811708Sstevel proplen = sizeof (portid); 25821708Sstevel if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 25831708Sstevel 0, IOSRAM_PORTID_PROP, (caddr_t)&portid, 25841708Sstevel &proplen) != DDI_PROP_SUCCESS) { 25851708Sstevel cmn_err(CE_WARN, "iosram(%d): can't find portid property.\n", 25861708Sstevel instance); 25871708Sstevel iosram_remove_map(softp); 25881708Sstevel return (DDI_FAILURE); 25891708Sstevel } 25901708Sstevel softp->portid = portid; 25911708Sstevel 25921708Sstevel if (iosram_sbbc_setup_map(softp) != DDI_SUCCESS) { 25931708Sstevel cmn_err(CE_WARN, "iosram(%d): can't map SBBC region.\n", 25941708Sstevel instance); 25951708Sstevel iosram_remove_map(softp); 25961708Sstevel return (DDI_FAILURE); 25971708Sstevel } 25981708Sstevel 25991708Sstevel mutex_enter(&iosram_mutex); 26001708Sstevel softp->state |= IOSRAM_STATE_MAPPED; 26011708Sstevel mutex_exit(&iosram_mutex); 26021708Sstevel 26031708Sstevel return (DDI_SUCCESS); 26041708Sstevel } 26051708Sstevel 26061708Sstevel 26071708Sstevel static void 26081708Sstevel iosram_remove_map(struct iosramsoft *softp) 26091708Sstevel { 26101708Sstevel mutex_enter(&iosram_mutex); 26111708Sstevel 26121708Sstevel ASSERT((softp->state & IOSRAM_STATE_MASTER) == 0); 26131708Sstevel 26141708Sstevel if (softp->handle) { 26151708Sstevel ddi_regs_map_free(&softp->handle); 26161708Sstevel softp->handle = NULL; 26171708Sstevel } 26181708Sstevel softp->iosramp = NULL; 26191708Sstevel 26201708Sstevel /* 26211708Sstevel * Umap SBBC registers region. Shared with handler for SBBC 26221708Sstevel * interrupts, take intr_mutex. 26231708Sstevel */ 26241708Sstevel mutex_enter(&softp->intr_mutex); 26251708Sstevel if (softp->sbbc_region) { 26261708Sstevel ddi_regs_map_free(&softp->sbbc_handle); 26271708Sstevel softp->sbbc_region = NULL; 26281708Sstevel } 26291708Sstevel mutex_exit(&softp->intr_mutex); 26301708Sstevel 26311708Sstevel softp->state &= ~IOSRAM_STATE_MAPPED; 26321708Sstevel 26331708Sstevel mutex_exit(&iosram_mutex); 26341708Sstevel } 26351708Sstevel 26361708Sstevel 26371708Sstevel /* 26381708Sstevel * iosram_is_chosen(struct iosramsoft *softp) 26391708Sstevel * 26401708Sstevel * Looks up "chosen" node property to 26411708Sstevel * determine if it is the chosen IOSRAM. 26421708Sstevel */ 26431708Sstevel static int 26441708Sstevel iosram_is_chosen(struct iosramsoft *softp) 26451708Sstevel { 26461708Sstevel char chosen_iosram[MAXNAMELEN]; 26471708Sstevel char pn[MAXNAMELEN]; 26481708Sstevel int nodeid; 26491708Sstevel int chosen; 26501708Sstevel pnode_t dnode; 26511708Sstevel 26521708Sstevel /* 26531708Sstevel * Get /chosen node info. prom interface will handle errors. 26541708Sstevel */ 26551708Sstevel dnode = prom_chosennode(); 26561708Sstevel 26571708Sstevel /* 26581708Sstevel * Look for the "iosram" property on the chosen node with a prom 26591708Sstevel * interface as ddi_find_devinfo() couldn't be used (calls 26601708Sstevel * ddi_walk_devs() that creates one extra lock on the device tree). 26611708Sstevel */ 26621708Sstevel if (prom_getprop(dnode, IOSRAM_CHOSEN_PROP, (caddr_t)&nodeid) <= 0) { 26631708Sstevel /* 26641708Sstevel * Can't find IOSRAM_CHOSEN_PROP property under chosen node 26651708Sstevel */ 26661708Sstevel cmn_err(CE_WARN, 26671708Sstevel "iosram(%d): can't find chosen iosram property\n", 26681708Sstevel softp->instance); 26691708Sstevel return (0); 26701708Sstevel } 26711708Sstevel 26721708Sstevel DPRINTF(1, ("iosram(%d): Got '%x' for chosen '%s' property\n", 26731708Sstevel softp->instance, nodeid, IOSRAM_CHOSEN_PROP)); 26741708Sstevel 26751708Sstevel /* 26761708Sstevel * get the full OBP pathname of this node 26771708Sstevel */ 26781708Sstevel if (prom_phandle_to_path((phandle_t)nodeid, chosen_iosram, 26791708Sstevel sizeof (chosen_iosram)) < 0) { 26801708Sstevel cmn_err(CE_NOTE, "prom_phandle_to_path(%x) failed\n", nodeid); 26811708Sstevel return (0); 26821708Sstevel } 26831708Sstevel DPRINTF(1, ("iosram(%d): prom_phandle_to_path(%x) is '%s'\n", 26841708Sstevel softp->instance, nodeid, chosen_iosram)); 26851708Sstevel 26861708Sstevel (void) ddi_pathname(softp->dip, pn); 26871708Sstevel DPRINTF(1, ("iosram(%d): ddi_pathname(%p) is '%s'\n", 26881708Sstevel softp->instance, softp->dip, pn)); 26891708Sstevel 26901708Sstevel chosen = (strcmp(chosen_iosram, pn) == 0) ? 1 : 0; 26911708Sstevel DPRINTF(1, ("iosram(%d): ... %s\n", softp->instance, 26921708Sstevel chosen ? "MASTER" : "SLAVE")); 26931708Sstevel IOSRAMLOG(1, "iosram(%d): ... %s\n", softp->instance, 26941708Sstevel (chosen ? "MASTER" : "SLAVE"), NULL, NULL); 26951708Sstevel 26961708Sstevel return (chosen); 26971708Sstevel } 26981708Sstevel 26991708Sstevel 27001708Sstevel /* 27011708Sstevel * iosram_set_master(struct iosramsoft *softp) 27021708Sstevel * 27031708Sstevel * Set master tunnel to the specified IOSRAM 27041708Sstevel * Must be called while holding iosram_mutex. 27051708Sstevel */ 27061708Sstevel static void 27071708Sstevel iosram_set_master(struct iosramsoft *softp) 27081708Sstevel { 27091708Sstevel ASSERT(mutex_owned(&iosram_mutex)); 27101708Sstevel ASSERT(softp != NULL); 27111708Sstevel ASSERT(softp->state & IOSRAM_STATE_MAPPED); 27121708Sstevel ASSERT(IOSRAM_GET_HDRFIELD32(softp, status) == IOSRAM_VALID); 27131708Sstevel 27141708Sstevel /* 27151708Sstevel * Clear MASTER flag on any previous IOSRAM master, if any 27161708Sstevel */ 27171708Sstevel if (iosram_master && (iosram_master != softp)) { 27181708Sstevel iosram_master->state &= ~IOSRAM_STATE_MASTER; 27191708Sstevel } 27201708Sstevel 27211708Sstevel /* 27221708Sstevel * Setup new IOSRAM master 27231708Sstevel */ 27241708Sstevel iosram_update_addrs(softp); 27251708Sstevel iosram_handle = softp->handle; 27261708Sstevel softp->state |= IOSRAM_STATE_MASTER; 27271708Sstevel softp->tswitch_ok++; 27281708Sstevel iosram_master = softp; 27291708Sstevel 27301708Sstevel IOSRAMLOG(1, "SETMASTER: softp:%p instance:%d\n", softp, 27311708Sstevel softp->instance, NULL, NULL); 27321708Sstevel } 27331708Sstevel 27341708Sstevel 27351708Sstevel /* 27361708Sstevel * iosram_read_toc() 27371708Sstevel * 27381708Sstevel * Read the TOC from an IOSRAM instance that has been mapped in. 27391708Sstevel * If the TOC is flawed or the IOSRAM isn't valid, return an error. 27401708Sstevel */ 27411708Sstevel static int 27421708Sstevel iosram_read_toc(struct iosramsoft *softp) 27431708Sstevel { 27441708Sstevel int i; 27451708Sstevel int instance = softp->instance; 27461708Sstevel uint8_t *toc_entryp; 27471708Sstevel iosram_flags_t *flagsp = NULL; 27481708Sstevel int new_nchunks; 27491708Sstevel iosram_chunk_t *new_chunks; 27501708Sstevel iosram_chunk_t *chunkp; 27511708Sstevel iosram_chunk_t *old_chunkp; 27521708Sstevel iosram_toc_entry_t index; 27531708Sstevel 27541708Sstevel /* 27551708Sstevel * Never try to read the TOC out of an unmapped IOSRAM. 27561708Sstevel */ 27571708Sstevel ASSERT(softp->state & IOSRAM_STATE_MAPPED); 27581708Sstevel 27591708Sstevel mutex_enter(&iosram_mutex); 27601708Sstevel 27611708Sstevel /* 27621708Sstevel * Check to make sure this IOSRAM is marked valid. Return 27631708Sstevel * an error if it isn't. 27641708Sstevel */ 27651708Sstevel if (IOSRAM_GET_HDRFIELD32(softp, status) != IOSRAM_VALID) { 27661708Sstevel DPRINTF(1, ("iosram_read_toc(%d): IOSRAM not flagged valid\n", 27671708Sstevel instance)); 27681708Sstevel mutex_exit(&iosram_mutex); 27691708Sstevel return (EINVAL); 27701708Sstevel } 27711708Sstevel 27721708Sstevel /* 27731708Sstevel * Get the location of the TOC. 27741708Sstevel */ 27751708Sstevel toc_entryp = softp->iosramp + IOSRAM_GET_HDRFIELD32(softp, toc_offset); 27761708Sstevel 27771708Sstevel /* 27781708Sstevel * Read the index entry from the TOC and make sure it looks correct. 27791708Sstevel */ 27801708Sstevel ddi_rep_get8(softp->handle, (uint8_t *)&index, toc_entryp, 27811708Sstevel sizeof (iosram_toc_entry_t), DDI_DEV_AUTOINCR); 27821708Sstevel if ((index.key != IOSRAM_INDEX_KEY) || 27831708Sstevel (index.off != IOSRAM_INDEX_OFF)) { 27841708Sstevel cmn_err(CE_WARN, "iosram(%d): invalid TOC index.\n", instance); 27851708Sstevel mutex_exit(&iosram_mutex); 27861708Sstevel return (EINVAL); 27871708Sstevel } 27881708Sstevel 27891708Sstevel /* 27901708Sstevel * Allocate storage for the new chunks array and initialize it with data 27911708Sstevel * from the TOC and callback data from the corresponding old chunk, if 27921708Sstevel * it exists. 27931708Sstevel */ 27941708Sstevel new_nchunks = index.len - 1; 27951708Sstevel new_chunks = (iosram_chunk_t *)kmem_zalloc(new_nchunks * 27961708Sstevel sizeof (iosram_chunk_t), KM_SLEEP); 27971708Sstevel for (i = 0, chunkp = new_chunks; i < new_nchunks; i++, chunkp++) { 27981708Sstevel toc_entryp += sizeof (iosram_toc_entry_t); 27991708Sstevel ddi_rep_get8(softp->handle, (uint8_t *)&(chunkp->toc_data), 28001708Sstevel toc_entryp, sizeof (iosram_toc_entry_t), DDI_DEV_AUTOINCR); 28011708Sstevel chunkp->hash = NULL; 28021708Sstevel if ((chunkp->toc_data.off < softp->iosramlen) && 28031708Sstevel (chunkp->toc_data.len <= softp->iosramlen) && 28041708Sstevel ((chunkp->toc_data.off + chunkp->toc_data.len) <= 28051708Sstevel softp->iosramlen)) { 28061708Sstevel chunkp->basep = softp->iosramp + chunkp->toc_data.off; 28071708Sstevel DPRINTF(1, 28081708Sstevel ("iosram_read_toc(%d): k:%x o:%x l:%x p:%x\n", 28091708Sstevel instance, chunkp->toc_data.key, 28101708Sstevel chunkp->toc_data.off, chunkp->toc_data.len, 28111708Sstevel chunkp->basep)); 28121708Sstevel } else { 28131708Sstevel cmn_err(CE_WARN, "iosram(%d): TOC entry %d" 28141708Sstevel "out of range... off:%x len:%x\n", 28151708Sstevel instance, i + 1, chunkp->toc_data.off, 28161708Sstevel chunkp->toc_data.len); 28171708Sstevel kmem_free(new_chunks, new_nchunks * 28181708Sstevel sizeof (iosram_chunk_t)); 28191708Sstevel mutex_exit(&iosram_mutex); 28201708Sstevel return (EINVAL); 28211708Sstevel } 28221708Sstevel 28231708Sstevel /* 28241708Sstevel * Note the existence of the flags chunk, which is required in 28251708Sstevel * a correct TOC. 28261708Sstevel */ 28271708Sstevel if (chunkp->toc_data.key == IOSRAM_FLAGS_KEY) { 28281708Sstevel flagsp = (iosram_flags_t *)chunkp->basep; 28291708Sstevel } 28301708Sstevel 28311708Sstevel /* 28321708Sstevel * If there was an entry for this chunk in the old list, copy 28331708Sstevel * the callback data from old to new storage. 28341708Sstevel */ 28351708Sstevel if ((nchunks > 0) && 28361708Sstevel ((old_chunkp = iosram_find_chunk(chunkp->toc_data.key)) != 28371708Sstevel NULL)) { 28381708Sstevel bcopy(&(old_chunkp->cback), &(chunkp->cback), 28391708Sstevel sizeof (iosram_cback_t)); 28401708Sstevel } 28411708Sstevel } 28421708Sstevel /* 28431708Sstevel * The TOC is malformed if there is no entry for the flags chunk. 28441708Sstevel */ 28451708Sstevel if (flagsp == NULL) { 28461708Sstevel kmem_free(new_chunks, new_nchunks * sizeof (iosram_chunk_t)); 28471708Sstevel mutex_exit(&iosram_mutex); 28481708Sstevel return (EINVAL); 28491708Sstevel } 28501708Sstevel 28511708Sstevel /* 28521708Sstevel * Free any memory that is no longer needed and install the new data 28531708Sstevel * as current data. 28541708Sstevel */ 28551708Sstevel if (chunks != NULL) { 28561708Sstevel kmem_free(chunks, nchunks * sizeof (iosram_chunk_t)); 28571708Sstevel } 28581708Sstevel chunks = new_chunks; 28591708Sstevel nchunks = new_nchunks; 28601708Sstevel iosram_init_hashtab(); 28611708Sstevel 28621708Sstevel mutex_exit(&iosram_mutex); 28631708Sstevel return (0); 28641708Sstevel } 28651708Sstevel 28661708Sstevel 28671708Sstevel /* 28681708Sstevel * iosram_init_hashtab() 28691708Sstevel * 28701708Sstevel * Initialize the hash table and populate it with the IOSRAM 28711708Sstevel * chunks previously read from the TOC. The caller must hold the 28721708Sstevel * ioram_mutex lock. 28731708Sstevel */ 28741708Sstevel static void 28751708Sstevel iosram_init_hashtab(void) 28761708Sstevel { 28771708Sstevel int i, bucket; 28781708Sstevel iosram_chunk_t *chunkp; 28791708Sstevel 28801708Sstevel ASSERT(mutex_owned(&iosram_mutex)); 28811708Sstevel 28821708Sstevel for (i = 0; i < IOSRAM_HASHSZ; i++) { 28831708Sstevel iosram_hashtab[i] = NULL; 28841708Sstevel } 28851708Sstevel 28861708Sstevel if (chunks) { 28871708Sstevel for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) { 28881708Sstevel /* 28891708Sstevel * Hide the flags chunk by leaving it out of the hash 28901708Sstevel * table. 28911708Sstevel */ 28921708Sstevel if (chunkp->toc_data.key == IOSRAM_FLAGS_KEY) { 28931708Sstevel continue; 28941708Sstevel } 28951708Sstevel 28961708Sstevel /* 28971708Sstevel * Add the current chunk to the hash table. 28981708Sstevel */ 28991708Sstevel bucket = IOSRAM_HASH(chunkp->toc_data.key); 29001708Sstevel chunkp->hash = iosram_hashtab[bucket]; 29011708Sstevel iosram_hashtab[bucket] = chunkp; 29021708Sstevel } 29031708Sstevel } 29041708Sstevel } 29051708Sstevel 29061708Sstevel 29071708Sstevel /* 29081708Sstevel * iosram_update_addrs() 29091708Sstevel * 29101708Sstevel * Process the chunk list, updating each chunk's basep, which is a pointer 29111708Sstevel * to the beginning of the chunk's memory in kvaddr space. Record the 29121708Sstevel * basep value of the flags chunk to speed up flag access. The caller 29131708Sstevel * must hold the iosram_mutex lock. 29141708Sstevel */ 29151708Sstevel static void 29161708Sstevel iosram_update_addrs(struct iosramsoft *softp) 29171708Sstevel { 29181708Sstevel int i; 29191708Sstevel iosram_flags_t *flagsp; 29201708Sstevel iosram_chunk_t *chunkp; 29211708Sstevel 29221708Sstevel ASSERT(mutex_owned(&iosram_mutex)); 29231708Sstevel 29241708Sstevel /* 29251708Sstevel * First go through all of the chunks updating their base pointers and 29261708Sstevel * looking for the flags chunk. 29271708Sstevel */ 29281708Sstevel for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) { 29291708Sstevel chunkp->basep = softp->iosramp + chunkp->toc_data.off; 29301708Sstevel if (chunkp->toc_data.key == IOSRAM_FLAGS_KEY) { 29311708Sstevel flagsp = (iosram_flags_t *)(chunkp->basep); 29321708Sstevel DPRINTF(1, 29331708Sstevel ("iosram_update_addrs flags: o:0x%08x p:%p", 29341708Sstevel chunkp->toc_data.off, flagsp)); 29351708Sstevel } 29361708Sstevel } 29371708Sstevel 29381708Sstevel /* 29391708Sstevel * Now, go through and update each chunk's flags pointer. This can't be 29401708Sstevel * done in the first loop because we don't have the address of the flags 29411708Sstevel * chunk yet. 29421708Sstevel */ 29431708Sstevel for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) { 29441708Sstevel chunkp->flagsp = flagsp++; 29451708Sstevel DPRINTF(1, ("iosram_update_addrs: k:0x%x f:%p\n", 29461708Sstevel chunkp->toc_data.key, chunkp->flagsp)); 29471708Sstevel } 29481708Sstevel } 29491708Sstevel 29501708Sstevel /* 29511708Sstevel * iosram_find_chunk(key) 29521708Sstevel * 29531708Sstevel * Return a pointer to iosram_chunk structure corresponding to the 29541708Sstevel * "key" IOSRAM chunk. The caller must hold the iosram_mutex lock. 29551708Sstevel */ 29561708Sstevel static iosram_chunk_t * 29571708Sstevel iosram_find_chunk(uint32_t key) 29581708Sstevel { 29591708Sstevel iosram_chunk_t *chunkp; 29601708Sstevel int index = IOSRAM_HASH(key); 29611708Sstevel 29621708Sstevel ASSERT(mutex_owned(&iosram_mutex)); 29631708Sstevel 29641708Sstevel for (chunkp = iosram_hashtab[index]; chunkp; chunkp = chunkp->hash) { 29651708Sstevel if (chunkp->toc_data.key == key) { 29661708Sstevel break; 29671708Sstevel } 29681708Sstevel } 29691708Sstevel 29701708Sstevel return (chunkp); 29711708Sstevel } 29721708Sstevel 29731708Sstevel 29741708Sstevel /* 29751708Sstevel * iosram_add_intr(iosramsoft_t *) 29761708Sstevel */ 29771708Sstevel static int 29781708Sstevel iosram_add_intr(iosramsoft_t *softp) 29791708Sstevel { 29801708Sstevel IOSRAMLOG(2, "ADDINTR: softp:%p instance:%d\n", 29811708Sstevel softp, softp->instance, NULL, NULL); 29821708Sstevel 29831708Sstevel if (ddi_add_softintr(softp->dip, DDI_SOFTINT_MED, 29841708Sstevel &softp->softintr_id, &softp->soft_iblk, NULL, 29851708Sstevel iosram_softintr, (caddr_t)softp) != DDI_SUCCESS) { 29861708Sstevel cmn_err(CE_WARN, 29871708Sstevel "iosram(%d): Can't register softintr.\n", 29881708Sstevel softp->instance); 29891708Sstevel return (DDI_FAILURE); 29901708Sstevel } 29911708Sstevel 29921708Sstevel if (ddi_add_intr(softp->dip, 0, &softp->real_iblk, NULL, 29931708Sstevel iosram_intr, (caddr_t)softp) != DDI_SUCCESS) { 29941708Sstevel cmn_err(CE_WARN, 29951708Sstevel "iosram(%d): Can't register intr" 29961708Sstevel " handler.\n", softp->instance); 29971708Sstevel ddi_remove_softintr(softp->softintr_id); 29981708Sstevel return (DDI_FAILURE); 29991708Sstevel } 30001708Sstevel 30011708Sstevel /* 30021708Sstevel * Enable SBBC interrupts 30031708Sstevel */ 30041708Sstevel ddi_put32(softp->sbbc_handle, &(softp->sbbc_region->int_enable.reg), 30051708Sstevel IOSRAM_SBBC_INT0|IOSRAM_SBBC_INT1); 30061708Sstevel 30071708Sstevel return (DDI_SUCCESS); 30081708Sstevel } 30091708Sstevel 30101708Sstevel 30111708Sstevel /* 30121708Sstevel * iosram_remove_intr(iosramsoft_t *) 30131708Sstevel */ 30141708Sstevel static int 30151708Sstevel iosram_remove_intr(iosramsoft_t *softp) 30161708Sstevel { 30171708Sstevel IOSRAMLOG(2, "REMINTR: softp:%p instance:%d\n", 30181708Sstevel softp, softp->instance, NULL, NULL); 30191708Sstevel 30201708Sstevel /* 30211708Sstevel * Disable SBBC interrupts if SBBC is mapped in 30221708Sstevel */ 30231708Sstevel if (softp->sbbc_region) { 30241708Sstevel ddi_put32(softp->sbbc_handle, 30251708Sstevel &(softp->sbbc_region->int_enable.reg), 0); 30261708Sstevel } 30271708Sstevel 30281708Sstevel /* 30291708Sstevel * Remove SBBC interrupt handler 30301708Sstevel */ 30311708Sstevel ddi_remove_intr(softp->dip, 0, softp->real_iblk); 30321708Sstevel 30331708Sstevel /* 30341708Sstevel * Remove soft interrupt handler 30351708Sstevel */ 30361708Sstevel mutex_enter(&iosram_mutex); 30371708Sstevel if (softp->softintr_id != NULL) { 30381708Sstevel ddi_remove_softintr(softp->softintr_id); 30391708Sstevel softp->softintr_id = NULL; 30401708Sstevel } 30411708Sstevel mutex_exit(&iosram_mutex); 30421708Sstevel 30431708Sstevel return (0); 30441708Sstevel } 30451708Sstevel 30461708Sstevel 30471708Sstevel /* 30481708Sstevel * iosram_add_instance(iosramsoft_t *) 30491708Sstevel * Must be called while holding iosram_mutex 30501708Sstevel */ 30511708Sstevel static void 30521708Sstevel iosram_add_instance(iosramsoft_t *new_softp) 30531708Sstevel { 30541708Sstevel #ifdef DEBUG 30551708Sstevel int instance = new_softp->instance; 30561708Sstevel iosramsoft_t *softp; 30571708Sstevel #endif 30581708Sstevel 30591708Sstevel ASSERT(mutex_owned(&iosram_mutex)); 30601708Sstevel 30611708Sstevel #if defined(DEBUG) 30621708Sstevel /* Verify that this instance is not in the list */ 30631708Sstevel for (softp = iosram_instances; softp != NULL; softp = softp->next) { 30641708Sstevel ASSERT(softp->instance != instance); 30651708Sstevel } 30661708Sstevel #endif 30671708Sstevel 30681708Sstevel /* 30691708Sstevel * Add this instance to the list 30701708Sstevel */ 30711708Sstevel if (iosram_instances != NULL) { 30721708Sstevel iosram_instances->prev = new_softp; 30731708Sstevel } 30741708Sstevel new_softp->next = iosram_instances; 30751708Sstevel new_softp->prev = NULL; 30761708Sstevel iosram_instances = new_softp; 30771708Sstevel } 30781708Sstevel 30791708Sstevel 30801708Sstevel /* 30811708Sstevel * iosram_remove_instance(int instance) 30821708Sstevel * Must be called while holding iosram_mutex 30831708Sstevel */ 30841708Sstevel static void 30851708Sstevel iosram_remove_instance(int instance) 30861708Sstevel { 30871708Sstevel iosramsoft_t *softp; 30881708Sstevel 30891708Sstevel /* 30901708Sstevel * Remove specified instance from the iosram_instances list so that 30911708Sstevel * it can't be chosen for tunnel in future. 30921708Sstevel */ 30931708Sstevel ASSERT(mutex_owned(&iosram_mutex)); 30941708Sstevel 30951708Sstevel for (softp = iosram_instances; softp != NULL; softp = softp->next) { 30961708Sstevel if (softp->instance == instance) { 30971708Sstevel if (softp->next != NULL) { 30981708Sstevel softp->next->prev = softp->prev; 30991708Sstevel } 31001708Sstevel if (softp->prev != NULL) { 31011708Sstevel softp->prev->next = softp->next; 31021708Sstevel } 31031708Sstevel if (iosram_instances == softp) { 31041708Sstevel iosram_instances = softp->next; 31051708Sstevel } 31061708Sstevel 31071708Sstevel return; 31081708Sstevel } 31091708Sstevel } 31101708Sstevel } 31111708Sstevel 31121708Sstevel 31131708Sstevel /* 31141708Sstevel * iosram_sema_acquire: Acquire hardware semaphore. 31151708Sstevel * Return 0 if the semaphore could be acquired, or one of the following 31161708Sstevel * possible values: 31171708Sstevel * EAGAIN: there is a tunnel switch in progress 31181708Sstevel * EBUSY: the semaphore was already "held" 31191708Sstevel * ENXIO: an IO error occured (e.g. SBBC not mapped) 31201708Sstevel * If old_value is not NULL, the location it points to will be updated 31211708Sstevel * with the semaphore value read when attempting to acquire it. 31221708Sstevel */ 31231708Sstevel int 31241708Sstevel iosram_sema_acquire(uint32_t *old_value) 31251708Sstevel { 31261708Sstevel struct iosramsoft *softp; 31271708Sstevel int rv; 31281708Sstevel uint32_t sema_val; 31291708Sstevel 31301708Sstevel DPRINTF(2, ("IOSRAM: in iosram_sema_acquire\n")); 31311708Sstevel 31321708Sstevel mutex_enter(&iosram_mutex); 31331708Sstevel 31341708Sstevel /* 31351708Sstevel * Disallow access if there is a tunnel switch in progress. 31361708Sstevel */ 31371708Sstevel if (iosram_tswitch_active) { 31381708Sstevel mutex_exit(&iosram_mutex); 31391708Sstevel return (EAGAIN); 31401708Sstevel } 31411708Sstevel 31421708Sstevel /* 31431708Sstevel * Use current master IOSRAM for operation, fail if none is 31441708Sstevel * currently active. 31451708Sstevel */ 31461708Sstevel if ((softp = iosram_master) == NULL) { 31471708Sstevel mutex_exit(&iosram_mutex); 31481708Sstevel DPRINTF(1, ("IOSRAM: iosram_sema_acquire: no master\n")); 31491708Sstevel return (ENXIO); 31501708Sstevel } 31511708Sstevel 31521708Sstevel mutex_enter(&softp->intr_mutex); 31531708Sstevel 31541708Sstevel /* 31551708Sstevel * Fail if SBBC region has not been mapped. This shouldn't 31561708Sstevel * happen if we have a master IOSRAM, but we double-check. 31571708Sstevel */ 31581708Sstevel if (softp->sbbc_region == NULL) { 31591708Sstevel mutex_exit(&softp->intr_mutex); 31601708Sstevel mutex_exit(&iosram_mutex); 31611708Sstevel DPRINTF(1, ("IOSRAM(%d): iosram_sema_acquire: " 31621708Sstevel "SBBC not mapped\n", softp->instance)); 31631708Sstevel return (ENXIO); 31641708Sstevel } 31651708Sstevel 31661708Sstevel /* read semaphore value */ 31671708Sstevel sema_val = IOSRAM_SEMA_RD(softp); 31681708Sstevel if (old_value != NULL) 31691708Sstevel *old_value = sema_val; 31701708Sstevel 31711708Sstevel if (IOSRAM_SEMA_IS_HELD(sema_val)) { 31721708Sstevel /* semaphore was held by someone else */ 31731708Sstevel rv = EBUSY; 31741708Sstevel } else { 31751708Sstevel /* semaphore was not held, we just acquired it */ 31761708Sstevel rv = 0; 31771708Sstevel } 31781708Sstevel 31791708Sstevel mutex_exit(&softp->intr_mutex); 31801708Sstevel mutex_exit(&iosram_mutex); 31811708Sstevel 31821708Sstevel DPRINTF(1, ("IOSRAM(%d): iosram_sema_acquire: " 31831708Sstevel "old value=0x%x rv=%d\n", softp->instance, sema_val, rv)); 31841708Sstevel 31851708Sstevel return (rv); 31861708Sstevel } 31871708Sstevel 31881708Sstevel 31891708Sstevel /* 31901708Sstevel * iosram_sema_release: Release hardware semaphore. 31911708Sstevel * This function will "release" the hardware semaphore, and return 0 on 31921708Sstevel * success. If an error occured, one of the following values will be 31931708Sstevel * returned: 31941708Sstevel * EAGAIN: there is a tunnel switch in progress 31951708Sstevel * ENXIO: an IO error occured (e.g. SBBC not mapped) 31961708Sstevel */ 31971708Sstevel int 31981708Sstevel iosram_sema_release(void) 31991708Sstevel { 32001708Sstevel struct iosramsoft *softp; 32011708Sstevel 32021708Sstevel DPRINTF(2, ("IOSRAM: in iosram_sema_release\n")); 32031708Sstevel 32041708Sstevel mutex_enter(&iosram_mutex); 32051708Sstevel 32061708Sstevel /* 32071708Sstevel * Disallow access if there is a tunnel switch in progress. 32081708Sstevel */ 32091708Sstevel if (iosram_tswitch_active) { 32101708Sstevel mutex_exit(&iosram_mutex); 32111708Sstevel return (EAGAIN); 32121708Sstevel } 32131708Sstevel 32141708Sstevel /* 32151708Sstevel * Use current master IOSRAM for operation, fail if none is 32161708Sstevel * currently active. 32171708Sstevel */ 32181708Sstevel if ((softp = iosram_master) == NULL) { 32191708Sstevel mutex_exit(&iosram_mutex); 32201708Sstevel DPRINTF(1, ("IOSRAM: iosram_sema_release: no master\n")); 32211708Sstevel return (ENXIO); 32221708Sstevel } 32231708Sstevel 32241708Sstevel mutex_enter(&softp->intr_mutex); 32251708Sstevel 32261708Sstevel /* 32271708Sstevel * Fail if SBBC region has not been mapped in. This shouldn't 32281708Sstevel * happen if we have a master IOSRAM, but we double-check. 32291708Sstevel */ 32301708Sstevel if (softp->sbbc_region == NULL) { 32311708Sstevel mutex_exit(&softp->intr_mutex); 32321708Sstevel mutex_exit(&iosram_mutex); 32331708Sstevel DPRINTF(1, ("IOSRAM(%d): iosram_sema_release: " 32341708Sstevel "SBBC not mapped\n", softp->instance)); 32351708Sstevel return (ENXIO); 32361708Sstevel } 32371708Sstevel 32381708Sstevel /* Release semaphore by clearing our semaphore register */ 32391708Sstevel IOSRAM_SEMA_WR(softp, 0); 32401708Sstevel 32411708Sstevel mutex_exit(&softp->intr_mutex); 32421708Sstevel mutex_exit(&iosram_mutex); 32431708Sstevel 32441708Sstevel DPRINTF(1, ("IOSRAM(%d): iosram_sema_release: success\n", 32451708Sstevel softp->instance)); 32461708Sstevel 32471708Sstevel return (0); 32481708Sstevel } 32491708Sstevel 32501708Sstevel 32511708Sstevel #if defined(IOSRAM_LOG) 32521708Sstevel void 32531708Sstevel iosram_log(caddr_t fmt, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4) 32541708Sstevel { 32551708Sstevel uint32_t seq; 32561708Sstevel iosram_log_t *logp; 32571708Sstevel 32581708Sstevel mutex_enter(&iosram_log_mutex); 32591708Sstevel 32601708Sstevel seq = iosram_logseq++; 32611708Sstevel logp = &iosram_logbuf[seq % IOSRAM_MAXLOG]; 32621708Sstevel logp->seq = seq; 3263*11066Srafael.vanoni@sun.com logp->tstamp = ddi_get_lbolt(); 32641708Sstevel logp->fmt = fmt; 32651708Sstevel logp->arg1 = a1; 32661708Sstevel logp->arg2 = a2; 32671708Sstevel logp->arg3 = a3; 32681708Sstevel logp->arg4 = a4; 32691708Sstevel 32701708Sstevel mutex_exit(&iosram_log_mutex); 32711708Sstevel 32721708Sstevel if (iosram_log_print) { 32731708Sstevel cmn_err(CE_CONT, "#%x @%lx ", logp->seq, logp->tstamp); 32741708Sstevel if (logp->fmt) { 32751708Sstevel cmn_err(CE_CONT, logp->fmt, logp->arg1, logp->arg2, 32761708Sstevel logp->arg3, logp->arg4); 32771708Sstevel if (logp->fmt[strlen(logp->fmt)-1] != '\n') { 32781708Sstevel cmn_err(CE_CONT, "\n"); 32791708Sstevel } 32801708Sstevel } else { 32811708Sstevel cmn_err(CE_CONT, "fmt:%p args: %lx %lx %lx %lx\n", 32821708Sstevel logp->fmt, logp->arg1, logp->arg2, logp->arg3, 32831708Sstevel logp->arg4); 32841708Sstevel } 32851708Sstevel } 32861708Sstevel } 32871708Sstevel #endif /* IOSRAM_LOG */ 32881708Sstevel 32891708Sstevel 32901708Sstevel #if defined(DEBUG) 32911708Sstevel /* 32921708Sstevel * iosram_get_keys(buf, len) 32931708Sstevel * Return IOSRAM TOC in the specified buffer 32941708Sstevel */ 32951708Sstevel static int 32961708Sstevel iosram_get_keys(iosram_toc_entry_t *bufp, uint32_t *len) 32971708Sstevel { 32981708Sstevel struct iosram_chunk *chunkp; 32991708Sstevel int error = 0; 33001708Sstevel int i; 33011708Sstevel int cnt = (*len) / sizeof (iosram_toc_entry_t); 33021708Sstevel 33031708Sstevel IOSRAMLOG(2, "iosram_get_keys(bufp:%p *len:%x)\n", bufp, *len, NULL, 33041708Sstevel NULL); 33051708Sstevel 33061708Sstevel /* 33071708Sstevel * Copy data while holding the lock to prevent any data 33081708Sstevel * corruption or invalid pointer dereferencing. 33091708Sstevel */ 33101708Sstevel mutex_enter(&iosram_mutex); 33111708Sstevel 33121708Sstevel if (iosram_master == NULL) { 33131708Sstevel error = EIO; 33141708Sstevel } else { 33151708Sstevel for (i = 0, chunkp = chunks; i < nchunks && i < cnt; 33161708Sstevel i++, chunkp++) { 33171708Sstevel bufp[i].key = chunkp->toc_data.key; 33181708Sstevel bufp[i].off = chunkp->toc_data.off; 33191708Sstevel bufp[i].len = chunkp->toc_data.len; 33201708Sstevel bufp[i].unused = chunkp->toc_data.unused; 33211708Sstevel } 33221708Sstevel *len = i * sizeof (iosram_toc_entry_t); 33231708Sstevel } 33241708Sstevel 33251708Sstevel mutex_exit(&iosram_mutex); 33261708Sstevel return (error); 33271708Sstevel } 33281708Sstevel 33291708Sstevel 33301708Sstevel /* 33311708Sstevel * iosram_print_state(instance) 33321708Sstevel */ 33331708Sstevel static void 33341708Sstevel iosram_print_state(int instance) 33351708Sstevel { 33361708Sstevel struct iosramsoft *softp; 33371708Sstevel char pn[MAXNAMELEN]; 33381708Sstevel 33391708Sstevel if (instance < 0) { 33401708Sstevel softp = iosram_master; 33411708Sstevel } else { 33421708Sstevel softp = ddi_get_soft_state(iosramsoft_statep, instance); 33431708Sstevel } 33441708Sstevel 33451708Sstevel if (softp == NULL) { 33461708Sstevel cmn_err(CE_CONT, "iosram_print_state: Can't find instance %d\n", 33471708Sstevel instance); 33481708Sstevel return; 33491708Sstevel } 33501708Sstevel instance = softp->instance; 33511708Sstevel 33521708Sstevel mutex_enter(&iosram_mutex); 33531708Sstevel mutex_enter(&softp->intr_mutex); 33541708Sstevel 33551708Sstevel cmn_err(CE_CONT, "iosram_print_state(%d): ... %s\n", instance, 33561708Sstevel ((softp == iosram_master) ? "MASTER" : "SLAVE")); 33571708Sstevel 33581708Sstevel (void) ddi_pathname(softp->dip, pn); 33591708Sstevel cmn_err(CE_CONT, " pathname:%s\n", pn); 33601708Sstevel cmn_err(CE_CONT, " instance:%d portid:%d iosramlen:0x%x\n", 33611708Sstevel softp->instance, softp->portid, softp->iosramlen); 33621708Sstevel cmn_err(CE_CONT, " softp:%p handle:%p iosramp:%p\n", softp, 33631708Sstevel softp->handle, softp->iosramp); 33641708Sstevel cmn_err(CE_CONT, " state:0x%x tswitch_ok:%x tswitch_fail:%x\n", 33651708Sstevel softp->state, softp->tswitch_ok, softp->tswitch_fail); 33661708Sstevel cmn_err(CE_CONT, " softintr_id:%p intr_busy:%x intr_pending:%x\n", 33671708Sstevel softp->softintr_id, softp->intr_busy, softp->intr_pending); 33681708Sstevel 33691708Sstevel mutex_exit(&softp->intr_mutex); 33701708Sstevel mutex_exit(&iosram_mutex); 33711708Sstevel } 33721708Sstevel 33731708Sstevel 33741708Sstevel /* 33751708Sstevel * iosram_print_stats() 33761708Sstevel */ 33771708Sstevel static void 33781708Sstevel iosram_print_stats() 33791708Sstevel { 33801708Sstevel uint32_t calls; 33811708Sstevel 33821708Sstevel cmn_err(CE_CONT, "iosram_stats:\n"); 33831708Sstevel calls = iosram_stats.read; 33841708Sstevel cmn_err(CE_CONT, " read ... calls:%x bytes:%lx avg_sz:%x\n", 33851708Sstevel calls, iosram_stats.bread, 33861708Sstevel (uint32_t)((calls != 0) ? (iosram_stats.bread/calls) : 0)); 33871708Sstevel 33881708Sstevel calls = iosram_stats.write; 33891708Sstevel cmn_err(CE_CONT, " write ... calls:%x bytes:%lx avg_sz:%x\n", 33901708Sstevel calls, iosram_stats.bwrite, 33911708Sstevel (uint32_t)((calls != 0) ? (iosram_stats.bwrite/calls) : 0)); 33921708Sstevel 33931708Sstevel cmn_err(CE_CONT, " intr recv (real:%x soft:%x) sent:%x cback:%x\n", 33941708Sstevel iosram_stats.intr_recv, iosram_stats.sintr_recv, 33951708Sstevel iosram_stats.intr_send, iosram_stats.callbacks); 33961708Sstevel 33971708Sstevel cmn_err(CE_CONT, " tswitch: %x getflag:%x setflag:%x\n", 33981708Sstevel iosram_stats.tswitch, iosram_stats.getflag, 33991708Sstevel iosram_stats.setflag); 34001708Sstevel 34011708Sstevel cmn_err(CE_CONT, " iosram_rw_active_max: %x\n", iosram_rw_active_max); 34021708Sstevel } 34031708Sstevel 34041708Sstevel 34051708Sstevel static void 34061708Sstevel iosram_print_cback() 34071708Sstevel { 34081708Sstevel iosram_chunk_t *chunkp; 34091708Sstevel int i; 34101708Sstevel 34111708Sstevel /* 34121708Sstevel * Print callback handlers 34131708Sstevel */ 34141708Sstevel mutex_enter(&iosram_mutex); 34151708Sstevel 34161708Sstevel cmn_err(CE_CONT, "IOSRAM callbacks:\n"); 34171708Sstevel for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) { 34181708Sstevel if (chunkp->cback.handler) { 34191708Sstevel cmn_err(CE_CONT, " %2d: key:0x%x hdlr:%p arg:%p " 34201708Sstevel "busy:%d unreg:%d\n", i, chunkp->toc_data.key, 34211708Sstevel chunkp->cback.handler, chunkp->cback.arg, 34221708Sstevel chunkp->cback.busy, chunkp->cback.unregister); 34231708Sstevel } 34241708Sstevel } 34251708Sstevel mutex_exit(&iosram_mutex); 34261708Sstevel } 34271708Sstevel 34281708Sstevel 34291708Sstevel static void 34301708Sstevel iosram_print_flags() 34311708Sstevel { 34321708Sstevel int i; 34331708Sstevel uint32_t *keys; 34341708Sstevel iosram_flags_t *flags; 34351708Sstevel 34361708Sstevel mutex_enter(&iosram_mutex); 34371708Sstevel 34381708Sstevel if (iosram_master == NULL) { 34391708Sstevel mutex_exit(&iosram_mutex); 34401708Sstevel cmn_err(CE_CONT, "IOSRAM Flags: not accessible\n"); 34411708Sstevel return; 34421708Sstevel } 34431708Sstevel 34441708Sstevel keys = kmem_alloc(nchunks * sizeof (uint32_t), KM_SLEEP); 34451708Sstevel flags = kmem_alloc(nchunks * sizeof (iosram_flags_t), KM_SLEEP); 34461708Sstevel 34471708Sstevel for (i = 0; i < nchunks; i++) { 34481708Sstevel keys[i] = chunks[i].toc_data.key; 34491708Sstevel ddi_rep_get8(iosram_handle, (uint8_t *)&(flags[i]), 34501708Sstevel (uint8_t *)(chunks[i].flagsp), sizeof (iosram_flags_t), 34511708Sstevel DDI_DEV_AUTOINCR); 34521708Sstevel } 34531708Sstevel 34541708Sstevel mutex_exit(&iosram_mutex); 34551708Sstevel 34561708Sstevel cmn_err(CE_CONT, "IOSRAM Flags:\n"); 34571708Sstevel for (i = 0; i < nchunks; i++) { 34581708Sstevel cmn_err(CE_CONT, 34591708Sstevel " %2d: key: 0x%x data_valid:%x int_pending:%x\n", 34601708Sstevel i, keys[i], flags[i].data_valid, flags[i].int_pending); 34611708Sstevel } 34621708Sstevel 34631708Sstevel kmem_free(keys, nchunks * sizeof (uint32_t)); 34641708Sstevel kmem_free(flags, nchunks * sizeof (iosram_flags_t)); 34651708Sstevel } 34661708Sstevel 34671708Sstevel 34681708Sstevel /*PRINTFLIKE1*/ 34691708Sstevel static void 34701708Sstevel iosram_dprintf(const char *fmt, ...) 34711708Sstevel { 34721708Sstevel char msg_buf[256]; 34731708Sstevel va_list adx; 34741708Sstevel 34751708Sstevel va_start(adx, fmt); 34761708Sstevel vsprintf(msg_buf, fmt, adx); 34771708Sstevel va_end(adx); 34781708Sstevel 34791708Sstevel cmn_err(CE_CONT, "%s", msg_buf); 34801708Sstevel } 34811708Sstevel #endif /* DEBUG */ 34821708Sstevel 34831708Sstevel 34841708Sstevel #if IOSRAM_LOG 34851708Sstevel /* 34861708Sstevel * iosram_print_log(int cnt) 34871708Sstevel * Print last few entries of the IOSRAM log in reverse order 34881708Sstevel */ 34891708Sstevel static void 34901708Sstevel iosram_print_log(int cnt) 34911708Sstevel { 34921708Sstevel int i; 34931708Sstevel 34941708Sstevel if (cnt <= 0) { 34951708Sstevel cnt = 20; 34961708Sstevel } else if (cnt > IOSRAM_MAXLOG) { 34971708Sstevel cnt = IOSRAM_MAXLOG; 34981708Sstevel } 34991708Sstevel 35001708Sstevel 35011708Sstevel cmn_err(CE_CONT, 35021708Sstevel "\niosram_logseq: 0x%x lbolt: %lx iosram_log_level:%x\n", 3503*11066Srafael.vanoni@sun.com iosram_logseq, ddi_get_lbolt(), iosram_log_level); 35041708Sstevel cmn_err(CE_CONT, "iosram_logbuf: %p max entries:0x%x\n", 35051708Sstevel iosram_logbuf, IOSRAM_MAXLOG); 35061708Sstevel for (i = iosram_logseq; --i >= 0 && --cnt >= 0; ) { 35071708Sstevel iosram_log_t *logp; 35081708Sstevel 35091708Sstevel mutex_enter(&iosram_log_mutex); 35101708Sstevel 35111708Sstevel logp = &iosram_logbuf[i %IOSRAM_MAXLOG]; 35121708Sstevel cmn_err(CE_CONT, "#%x @%lx ", logp->seq, logp->tstamp); 35131708Sstevel 35141708Sstevel if (logp->fmt) { 35151708Sstevel cmn_err(CE_CONT, logp->fmt, logp->arg1, logp->arg2, 35161708Sstevel logp->arg3, logp->arg4); 35171708Sstevel if (logp->fmt[strlen(logp->fmt)-1] != '\n') { 35181708Sstevel cmn_err(CE_CONT, "\n"); 35191708Sstevel } 35201708Sstevel } else { 35211708Sstevel cmn_err(CE_CONT, "fmt:%p args: %lx %lx %lx %lx\n", 35221708Sstevel logp->fmt, logp->arg1, logp->arg2, 35231708Sstevel logp->arg3, logp->arg4); 35241708Sstevel } 35251708Sstevel 35261708Sstevel mutex_exit(&iosram_log_mutex); 35271708Sstevel } 35281708Sstevel } 35291708Sstevel #endif /* IOSRAM_LOG */ 3530