144961713Sgirish /* 244961713Sgirish * CDDL HEADER START 344961713Sgirish * 444961713Sgirish * The contents of this file are subject to the terms of the 544961713Sgirish * Common Development and Distribution License (the "License"). 644961713Sgirish * You may not use this file except in compliance with the License. 744961713Sgirish * 844961713Sgirish * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 944961713Sgirish * or http://www.opensolaris.org/os/licensing. 1044961713Sgirish * See the License for the specific language governing permissions 1144961713Sgirish * and limitations under the License. 1244961713Sgirish * 1344961713Sgirish * When distributing Covered Code, include this CDDL HEADER in each 1444961713Sgirish * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1544961713Sgirish * If applicable, add the following below this CDDL HEADER, with the 1644961713Sgirish * fields enclosed by brackets "[]" replaced with your own identifying 1744961713Sgirish * information: Portions Copyright [yyyy] [name of copyright owner] 1844961713Sgirish * 1944961713Sgirish * CDDL HEADER END 2044961713Sgirish */ 2144961713Sgirish /* 22*657f87deSgongtian zhao - Sun Microsystems - Beijing China * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 2344961713Sgirish */ 2444961713Sgirish 2544961713Sgirish 2644961713Sgirish /* 2744961713Sgirish * Niagara2 Network Interface Unit (NIU) Nexus Driver 2844961713Sgirish */ 2944961713Sgirish 3044961713Sgirish #include <sys/conf.h> 3144961713Sgirish #include <sys/modctl.h> 3244961713Sgirish #include <sys/ddi_impldefs.h> 3344961713Sgirish #include <sys/ddi_subrdefs.h> 3444961713Sgirish #include <sys/ddi.h> 3544961713Sgirish #include <sys/sunndi.h> 3644961713Sgirish #include <sys/sunddi.h> 3744961713Sgirish #include <sys/open.h> 3844961713Sgirish #include <sys/stat.h> 3944961713Sgirish #include <sys/file.h> 4044961713Sgirish #include <sys/machsystm.h> 4144961713Sgirish #include <sys/hsvc.h> 4244961713Sgirish #include <sys/sdt.h> 4344961713Sgirish #include <sys/hypervisor_api.h> 44500b1e78SAlan Adamson, SD OSSD #include <sys/cpuvar.h> 4544961713Sgirish #include "niumx_var.h" 4644961713Sgirish 478fca0570Sjf137018 static int niumx_fm_init_child(dev_info_t *, dev_info_t *, int, 488fca0570Sjf137018 ddi_iblock_cookie_t *); 4944961713Sgirish static int niumx_intr_ops(dev_info_t *dip, dev_info_t *rdip, 5044961713Sgirish ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result); 5144961713Sgirish static int niumx_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 5244961713Sgirish static int niumx_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 5344961713Sgirish static int niumx_set_intr(dev_info_t *dip, dev_info_t *rdip, 5444961713Sgirish ddi_intr_handle_impl_t *hdlp, int valid); 5544961713Sgirish static int niumx_add_intr(dev_info_t *dip, dev_info_t *rdip, 5644961713Sgirish ddi_intr_handle_impl_t *hdlp); 5744961713Sgirish static int niumx_rem_intr(dev_info_t *dip, dev_info_t *rdip, 5844961713Sgirish ddi_intr_handle_impl_t *hdlp); 5944961713Sgirish static uint_t niumx_intr_hdlr(void *arg); 6044961713Sgirish static int niumx_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 6144961713Sgirish off_t offset, off_t len, caddr_t *addrp); 6244961713Sgirish static int niumx_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, 6344961713Sgirish ddi_dma_attr_t *attrp, 6444961713Sgirish int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep); 6544961713Sgirish static int niumx_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, 6644961713Sgirish ddi_dma_handle_t handlep); 6744961713Sgirish static int niumx_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 6844961713Sgirish ddi_dma_handle_t handle, ddi_dma_req_t *dmareq, 6944961713Sgirish ddi_dma_cookie_t *cookiep, uint_t *ccountp); 7044961713Sgirish static int niumx_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, 7144961713Sgirish ddi_dma_handle_t handle); 7244961713Sgirish static int niumx_ctlops(dev_info_t *dip, dev_info_t *rdip, 7344961713Sgirish ddi_ctl_enum_t op, void *arg, void *result); 7444961713Sgirish 75500b1e78SAlan Adamson, SD OSSD int niumxtool_init(dev_info_t *dip); 762de7adabSAlan Adamson, SD OSSD void niumxtool_uninit(dev_info_t *dip); 77500b1e78SAlan Adamson, SD OSSD 78500b1e78SAlan Adamson, SD OSSD int niumx_get_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino, 79500b1e78SAlan Adamson, SD OSSD niucpuid_t *cpu_id); 80500b1e78SAlan Adamson, SD OSSD int niumx_set_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino, 81500b1e78SAlan Adamson, SD OSSD niucpuid_t cpu_id); 82500b1e78SAlan Adamson, SD OSSD 8344961713Sgirish static struct bus_ops niumx_bus_ops = { 8444961713Sgirish BUSO_REV, 8544961713Sgirish niumx_map, 8644961713Sgirish 0, 8744961713Sgirish 0, 8844961713Sgirish 0, 8944961713Sgirish i_ddi_map_fault, 9044961713Sgirish 0, 9144961713Sgirish niumx_dma_allochdl, 9244961713Sgirish niumx_dma_freehdl, 9344961713Sgirish niumx_dma_bindhdl, 9444961713Sgirish niumx_dma_unbindhdl, 9544961713Sgirish 0, 9644961713Sgirish 0, 9744961713Sgirish 0, 9844961713Sgirish niumx_ctlops, 9944961713Sgirish ddi_bus_prop_op, 10044961713Sgirish 0, /* (*bus_get_eventcookie)(); */ 10144961713Sgirish 0, /* (*bus_add_eventcall)(); */ 10244961713Sgirish 0, /* (*bus_remove_eventcall)(); */ 10344961713Sgirish 0, /* (*bus_post_event)(); */ 10444961713Sgirish 0, /* (*bus_intr_ctl)(); */ 10544961713Sgirish 0, /* (*bus_config)(); */ 10644961713Sgirish 0, /* (*bus_unconfig)(); */ 1078fca0570Sjf137018 niumx_fm_init_child, /* (*bus_fm_init)(); */ 10844961713Sgirish 0, /* (*bus_fm_fini)(); */ 10944961713Sgirish 0, /* (*bus_enter)() */ 11044961713Sgirish 0, /* (*bus_exit)() */ 11144961713Sgirish 0, /* (*bus_power)() */ 11244961713Sgirish niumx_intr_ops /* (*bus_intr_op)(); */ 11344961713Sgirish }; 11444961713Sgirish 115500b1e78SAlan Adamson, SD OSSD extern struct cb_ops niumx_cb_ops; 116500b1e78SAlan Adamson, SD OSSD 11744961713Sgirish static struct dev_ops niumx_ops = { 11844961713Sgirish DEVO_REV, /* devo_rev */ 11944961713Sgirish 0, /* refcnt */ 12044961713Sgirish ddi_no_info, /* info */ 12144961713Sgirish nulldev, /* identify */ 12244961713Sgirish 0, /* probe */ 12344961713Sgirish niumx_attach, /* attach */ 12444961713Sgirish niumx_detach, /* detach */ 12544961713Sgirish nulldev, /* reset */ 126500b1e78SAlan Adamson, SD OSSD &niumx_cb_ops, /* driver operations */ 12744961713Sgirish &niumx_bus_ops, /* bus operations */ 12819397407SSherry Moore 0, /* power */ 12919397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */ 13044961713Sgirish }; 13144961713Sgirish 13244961713Sgirish /* Module linkage information for the kernel. */ 13344961713Sgirish static struct modldrv modldrv = { 13444961713Sgirish &mod_driverops, /* Type of module */ 13519397407SSherry Moore "NIU Nexus Driver", 13644961713Sgirish &niumx_ops, /* driver ops */ 13744961713Sgirish }; 13844961713Sgirish 13944961713Sgirish static struct modlinkage modlinkage = { 14044961713Sgirish MODREV_1, 14144961713Sgirish (void *)&modldrv, 14244961713Sgirish NULL 14344961713Sgirish }; 14444961713Sgirish 145500b1e78SAlan Adamson, SD OSSD void *niumx_state; 14644961713Sgirish 14744961713Sgirish /* 14844961713Sgirish * forward function declarations: 14944961713Sgirish */ 15044961713Sgirish static void niumx_removechild(dev_info_t *); 15144961713Sgirish static int niumx_initchild(dev_info_t *child); 15244961713Sgirish 15344961713Sgirish int 15444961713Sgirish _init(void) 15544961713Sgirish { 15644961713Sgirish int e; 157d66f8315Sjb145095 uint64_t mjrnum; 158d66f8315Sjb145095 uint64_t mnrnum; 159d66f8315Sjb145095 160d66f8315Sjb145095 /* 161d66f8315Sjb145095 * Check HV intr group api versioning. 162d66f8315Sjb145095 * This driver uses the old interrupt routines which are supported 163d66f8315Sjb145095 * in old firmware in the CORE API group and in newer firmware in 164d66f8315Sjb145095 * the INTR API group. Support for these calls will be dropped 165d66f8315Sjb145095 * once the INTR API group major goes to 2. 166d66f8315Sjb145095 */ 167d66f8315Sjb145095 if ((hsvc_version(HSVC_GROUP_INTR, &mjrnum, &mnrnum) == 0) && 168d66f8315Sjb145095 (mjrnum > NIUMX_INTR_MAJOR_VER)) { 169d66f8315Sjb145095 cmn_err(CE_WARN, "niumx: unsupported intr api group: " 170d66f8315Sjb145095 "maj:0x%lx, min:0x%lx", mjrnum, mnrnum); 171d66f8315Sjb145095 return (ENOTSUP); 172d66f8315Sjb145095 } 173d66f8315Sjb145095 17444961713Sgirish if ((e = ddi_soft_state_init(&niumx_state, sizeof (niumx_devstate_t), 17544961713Sgirish 1)) == 0 && (e = mod_install(&modlinkage)) != 0) 17644961713Sgirish ddi_soft_state_fini(&niumx_state); 17744961713Sgirish return (e); 17844961713Sgirish } 17944961713Sgirish 18044961713Sgirish int 18144961713Sgirish _fini(void) 18244961713Sgirish { 18344961713Sgirish int e; 18444961713Sgirish if ((e = mod_remove(&modlinkage)) == 0) 18544961713Sgirish ddi_soft_state_fini(&niumx_state); 18644961713Sgirish return (e); 18744961713Sgirish } 18844961713Sgirish 18944961713Sgirish int 19044961713Sgirish _info(struct modinfo *modinfop) 19144961713Sgirish { 19244961713Sgirish return (mod_info(&modlinkage, modinfop)); 19344961713Sgirish } 19444961713Sgirish 195c165966dSjf137018 196c165966dSjf137018 hrtime_t niumx_intr_timeout = 2ull * NANOSEC; /* 2 seconds in nanoseconds */ 197c165966dSjf137018 1983266dff7Sjf137018 void 1993266dff7Sjf137018 niumx_intr_dist(void *arg) 2003266dff7Sjf137018 { 2014df55fdeSJanie Lu niumx_devstate_t *niumxds_p = (niumx_devstate_t *)arg; 2024df55fdeSJanie Lu kmutex_t *lock_p = &niumxds_p->niumx_mutex; 203e778ae44SRaghuram Kothakota int i; 2044df55fdeSJanie Lu niumx_ih_t *ih_p = niumxds_p->niumx_ihtable; 2053266dff7Sjf137018 206500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_A_INTX, NULL, "niumx_intr_dist entered\n"); 2073266dff7Sjf137018 mutex_enter(lock_p); 208e778ae44SRaghuram Kothakota for (i = 0; i < NIUMX_MAX_INTRS; i++, ih_p++) { 209500b1e78SAlan Adamson, SD OSSD niusysino_t sysino = ih_p->ih_sysino; 210500b1e78SAlan Adamson, SD OSSD niucpuid_t cpuid; 211500b1e78SAlan Adamson, SD OSSD int state; 212c165966dSjf137018 hrtime_t start; 213c165966dSjf137018 dev_info_t *dip = ih_p->ih_dip; 214500b1e78SAlan Adamson, SD OSSD 215500b1e78SAlan Adamson, SD OSSD if (!sysino || (cpuid = intr_dist_cpuid()) == ih_p->ih_cpuid) 2163266dff7Sjf137018 continue; 2173266dff7Sjf137018 2183266dff7Sjf137018 (void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID); 219c165966dSjf137018 220c165966dSjf137018 /* check for pending interrupts, busy wait if so */ 221c165966dSjf137018 for (start = gethrtime(); !panicstr && 222c165966dSjf137018 (hvio_intr_getstate(sysino, &state) == H_EOK) && 223c165966dSjf137018 (state == HV_INTR_DELIVERED_STATE); /* */) { 224c165966dSjf137018 if (gethrtime() - start > niumx_intr_timeout) { 225c165966dSjf137018 cmn_err(CE_WARN, "%s%d: niumx_intr_dist: " 226c165966dSjf137018 "pending interrupt (%x,%lx) timedout\n", 227c165966dSjf137018 ddi_driver_name(dip), ddi_get_instance(dip), 228c165966dSjf137018 ih_p->ih_inum, sysino); 229c165966dSjf137018 (void) hvio_intr_setstate(sysino, 230c165966dSjf137018 HV_INTR_IDLE_STATE); 231c165966dSjf137018 break; 232c165966dSjf137018 } 233c165966dSjf137018 } 2343266dff7Sjf137018 (void) hvio_intr_settarget(sysino, cpuid); 235500b1e78SAlan Adamson, SD OSSD 236500b1e78SAlan Adamson, SD OSSD if (ih_p->ih_state == HV_INTR_VALID) 2373266dff7Sjf137018 (void) hvio_intr_setvalid(sysino, HV_INTR_VALID); 238500b1e78SAlan Adamson, SD OSSD else 239500b1e78SAlan Adamson, SD OSSD (void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID); 240500b1e78SAlan Adamson, SD OSSD 2413266dff7Sjf137018 ih_p->ih_cpuid = cpuid; 2423266dff7Sjf137018 } 2433266dff7Sjf137018 mutex_exit(lock_p); 2443266dff7Sjf137018 } 24544961713Sgirish 24644961713Sgirish static int 24744961713Sgirish niumx_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 24844961713Sgirish { 24944961713Sgirish int instance = ddi_get_instance(dip); 25044961713Sgirish niumx_devstate_t *niumxds_p; /* devstate pointer */ 25144961713Sgirish niu_regspec_t *reg_p; 252500b1e78SAlan Adamson, SD OSSD niumx_ih_t *ih_p; 25344961713Sgirish uint_t reglen; 254500b1e78SAlan Adamson, SD OSSD int i, ret = DDI_SUCCESS; 25544961713Sgirish 25644961713Sgirish switch (cmd) { 25744961713Sgirish case DDI_ATTACH: 25844961713Sgirish if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 25944961713Sgirish DDI_PROP_DONTPASS, "reg", (int **)®_p, ®len) 26044961713Sgirish != DDI_PROP_SUCCESS) { 261500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_ATTACH, dip, "reg lookup failed\n"); 26244961713Sgirish ret = DDI_FAILURE; 26344961713Sgirish goto done; 26444961713Sgirish } 26544961713Sgirish 26644961713Sgirish /* 26744961713Sgirish * Allocate and get soft state structure. 26844961713Sgirish */ 26944961713Sgirish if (ddi_soft_state_zalloc(niumx_state, instance) 27044961713Sgirish != DDI_SUCCESS) { 27144961713Sgirish ret = DDI_FAILURE; 27244961713Sgirish goto prop_free; 27344961713Sgirish } 27444961713Sgirish niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state, 27544961713Sgirish instance); 27644961713Sgirish niumxds_p->dip = dip; 277500b1e78SAlan Adamson, SD OSSD niumxds_p->niumx_open_count = 0; 27844961713Sgirish mutex_init(&niumxds_p->niumx_mutex, NULL, MUTEX_DRIVER, NULL); 27944961713Sgirish 280500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_ATTACH, dip, "soft state alloc'd instance = %d, " 28144961713Sgirish "niumxds_p = %p\n", instance, niumxds_p); 28244961713Sgirish 28344961713Sgirish /* hv devhdl: low 28-bit of 1st "reg" entry's addr.hi */ 284500b1e78SAlan Adamson, SD OSSD niumxds_p->niumx_dev_hdl = (niudevhandle_t)(reg_p->addr_high & 28544961713Sgirish NIUMX_DEVHDLE_MASK); 28644961713Sgirish 287500b1e78SAlan Adamson, SD OSSD ih_p = niumxds_p->niumx_ihtable; 288500b1e78SAlan Adamson, SD OSSD for (i = 0; i < NIUMX_MAX_INTRS; i++, ih_p++) { 289500b1e78SAlan Adamson, SD OSSD ih_p->ih_sysino = 0; 290500b1e78SAlan Adamson, SD OSSD ih_p->ih_state = HV_INTR_NOTVALID; 291500b1e78SAlan Adamson, SD OSSD } 292500b1e78SAlan Adamson, SD OSSD 2933266dff7Sjf137018 /* add interrupt redistribution callback */ 2944df55fdeSJanie Lu intr_dist_add(niumx_intr_dist, niumxds_p); 2953266dff7Sjf137018 2968fca0570Sjf137018 niumxds_p->niumx_fm_cap = DDI_FM_EREPORT_CAPABLE; 29714ea4bb7Ssd77468 29814ea4bb7Ssd77468 ddi_fm_init(niumxds_p->dip, &niumxds_p->niumx_fm_cap, 29914ea4bb7Ssd77468 &niumxds_p->niumx_fm_ibc); 30014ea4bb7Ssd77468 301500b1e78SAlan Adamson, SD OSSD if (niumxtool_init(dip) != DDI_SUCCESS) { 302500b1e78SAlan Adamson, SD OSSD ret = DDI_FAILURE; 303500b1e78SAlan Adamson, SD OSSD goto cleanup; 304500b1e78SAlan Adamson, SD OSSD } 305500b1e78SAlan Adamson, SD OSSD 30644961713Sgirish ret = DDI_SUCCESS; 30744961713Sgirish goto prop_free; 30844961713Sgirish cleanup: 30944961713Sgirish mutex_destroy(&niumxds_p->niumx_mutex); 31044961713Sgirish ddi_soft_state_free(niumx_state, ddi_get_instance(dip)); 31144961713Sgirish prop_free: 31244961713Sgirish ddi_prop_free(reg_p); 31344961713Sgirish done: 31444961713Sgirish return (ret); 31544961713Sgirish 31644961713Sgirish case DDI_RESUME: 31744961713Sgirish default: 31844961713Sgirish break; 31944961713Sgirish } 32044961713Sgirish return (ret); 32144961713Sgirish } 32244961713Sgirish 32344961713Sgirish static int 32444961713Sgirish niumx_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 32544961713Sgirish { 32644961713Sgirish niumx_devstate_t *niumxds_p; 32744961713Sgirish 32844961713Sgirish switch (cmd) { 32944961713Sgirish case DDI_DETACH: 33044961713Sgirish 33144961713Sgirish niumxds_p = (niumx_devstate_t *) 33244961713Sgirish ddi_get_soft_state(niumx_state, ddi_get_instance(dip)); 33344961713Sgirish 3344df55fdeSJanie Lu intr_dist_rem(niumx_intr_dist, niumxds_p); 33514ea4bb7Ssd77468 ddi_fm_fini(dip); 336500b1e78SAlan Adamson, SD OSSD niumxtool_uninit(dip); 33744961713Sgirish mutex_destroy(&niumxds_p->niumx_mutex); 33844961713Sgirish ddi_soft_state_free(niumx_state, ddi_get_instance(dip)); 33944961713Sgirish return (DDI_SUCCESS); 34044961713Sgirish 34144961713Sgirish case DDI_SUSPEND: 34244961713Sgirish default: 34344961713Sgirish break; 34444961713Sgirish } 34544961713Sgirish return (DDI_FAILURE); 34644961713Sgirish } 34744961713Sgirish 3488fca0570Sjf137018 3498fca0570Sjf137018 /* 3508fca0570Sjf137018 * Function used to initialize FMA for our children nodes. Called 3518fca0570Sjf137018 * through pci busops when child node calls ddi_fm_init. 3528fca0570Sjf137018 */ 3538fca0570Sjf137018 /*ARGSUSED*/ 3548fca0570Sjf137018 int 3558fca0570Sjf137018 niumx_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap, 3568fca0570Sjf137018 ddi_iblock_cookie_t *ibc_p) 3578fca0570Sjf137018 { 358500b1e78SAlan Adamson, SD OSSD niumx_devstate_t *niumxds_p = NIUMX_DIP_TO_STATE(dip); 3598fca0570Sjf137018 3608fca0570Sjf137018 ASSERT(ibc_p != NULL); 3618fca0570Sjf137018 *ibc_p = niumxds_p->niumx_fm_ibc; 3628fca0570Sjf137018 3638fca0570Sjf137018 return (niumxds_p->niumx_fm_cap); 3648fca0570Sjf137018 } 3658fca0570Sjf137018 3668fca0570Sjf137018 36744961713Sgirish /*ARGSUSED*/ 36844961713Sgirish int 36944961713Sgirish niumx_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 37044961713Sgirish off_t offset, off_t len, caddr_t *vaddrp) 37144961713Sgirish { 37244961713Sgirish struct regspec p_regspec; 37344961713Sgirish ddi_map_req_t p_mapreq; 37444961713Sgirish niu_regspec_t *reg_p; 37544961713Sgirish int i, rn = mp->map_obj.rnumber, reglen, rnglen, rngnum, ret; 37644961713Sgirish niumx_ranges_t *rng_p; 37744961713Sgirish 37844961713Sgirish uint32_t reg_begin, rng_begin; 37944961713Sgirish 380500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_MAP, dip, "%s%d: mapping %s%d reg %d\n", 381500b1e78SAlan Adamson, SD OSSD NIUMX_NAMEINST(dip), NIUMX_NAMEINST(rdip), rn); 38244961713Sgirish 38344961713Sgirish if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 38444961713Sgirish "reg", (caddr_t)®_p, ®len) != DDI_SUCCESS) 38544961713Sgirish return (DDI_FAILURE); 38644961713Sgirish 38744961713Sgirish if (rn < 0 || (rn >= reglen / sizeof (niu_regspec_t))) { 388500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_MAP, dip, "rnumber out of range: %d\n", rn); 38944961713Sgirish kmem_free(reg_p, reglen); 39044961713Sgirish return (DDI_ME_RNUMBER_RANGE); 39144961713Sgirish } 39244961713Sgirish 39344961713Sgirish /* build regspec up for parent */ 39444961713Sgirish p_mapreq = *mp; /* dup the whole structure */ 39544961713Sgirish p_mapreq.map_type = DDI_MT_REGSPEC; 39644961713Sgirish p_mapreq.map_obj.rp = &p_regspec; 39744961713Sgirish 39844961713Sgirish if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", 39944961713Sgirish (caddr_t)&rng_p, &rnglen) != DDI_SUCCESS) { 400500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_MAP, dip, "%s%d: no ranges property\n", 40144961713Sgirish ddi_driver_name(dip), ddi_get_instance(dip)); 40244961713Sgirish kmem_free(reg_p, reglen); 40344961713Sgirish return (DDI_FAILURE); 40444961713Sgirish } 40544961713Sgirish 40644961713Sgirish /* locate matching ranges record */ 40744961713Sgirish rngnum = rnglen / sizeof (niumx_ranges_t); 40844961713Sgirish for (i = 0, reg_p += rn; i < rngnum; rng_p++, i++) { 40944961713Sgirish if (reg_p->addr_high == rng_p->child_hi) 41044961713Sgirish break; 41144961713Sgirish } 41244961713Sgirish 41344961713Sgirish if (i >= rngnum) { 414500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_MAP, dip, "ranges record for reg[%d] " 415500b1e78SAlan Adamson, SD OSSD "not found.\n", rn); 41644961713Sgirish ret = DDI_ME_REGSPEC_RANGE; 41744961713Sgirish goto err; 41844961713Sgirish } 41944961713Sgirish 42044961713Sgirish /* 42144961713Sgirish * validate request has matching bus type and within 4G 42244961713Sgirish * limit by comparing addr.hi of "ranges" and child "reg". 42344961713Sgirish */ 42444961713Sgirish 42544961713Sgirish ASSERT(reg_p->size_high == 0); 42644961713Sgirish 42744961713Sgirish rng_begin = rng_p->child_lo; 42844961713Sgirish reg_begin = reg_p->addr_low; 42944961713Sgirish /* check to verify reg bounds are within rng bounds */ 43044961713Sgirish if (reg_begin < rng_begin || (reg_begin + (reg_p->size_low - 1)) > 43144961713Sgirish (rng_begin + (rng_p->size_lo - 1))) { 432500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_MAP, dip, "size out of range for reg[%d].\n", rn); 43344961713Sgirish ret = DDI_ME_REGSPEC_RANGE; 43444961713Sgirish goto err; 43544961713Sgirish } 43644961713Sgirish 43744961713Sgirish p_regspec.regspec_bustype = rng_p->parent_hi; 43844961713Sgirish p_regspec.regspec_addr = reg_begin - rng_begin + rng_p->parent_lo; 43944961713Sgirish p_regspec.regspec_size = reg_p->size_low; 440500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_MAP, dip, "regspec:bus,addr,size = (%x,%x,%x)\n", 44144961713Sgirish p_regspec.regspec_bustype, p_regspec.regspec_addr, 44244961713Sgirish p_regspec.regspec_size); 44344961713Sgirish ret = ddi_map(dip, &p_mapreq, 0, 0, vaddrp); 444500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_MAP, dip, "niumx_map: ret %d.\n", ret); 44544961713Sgirish err: 44644961713Sgirish kmem_free(rng_p - i, rnglen); 44744961713Sgirish kmem_free(reg_p - rn, reglen); 44844961713Sgirish return (ret); 44944961713Sgirish } 45044961713Sgirish 45144961713Sgirish /* 45244961713Sgirish * niumx_ctlops 45344961713Sgirish */ 45444961713Sgirish int 45544961713Sgirish niumx_ctlops(dev_info_t *dip, dev_info_t *rdip, 45644961713Sgirish ddi_ctl_enum_t ctlop, void *arg, void *result) 45744961713Sgirish { 45844961713Sgirish niu_regspec_t *reg_p; 45944961713Sgirish int reglen, totreg; 46044961713Sgirish 461500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_CTLOPS, dip, "niumx_ctlops ctlop=%d.\n", ctlop); 46244961713Sgirish if (rdip == (dev_info_t *)0) 46344961713Sgirish return (DDI_FAILURE); 46444961713Sgirish 46544961713Sgirish switch (ctlop) { 46644961713Sgirish case DDI_CTLOPS_REPORTDEV: 46744961713Sgirish cmn_err(CE_NOTE, "device: %s@%s, %s%d\n", 46844961713Sgirish ddi_node_name(rdip), ddi_get_name_addr(rdip), 469500b1e78SAlan Adamson, SD OSSD NIUMX_NAMEINST(rdip)); 47044961713Sgirish return (DDI_SUCCESS); 47144961713Sgirish 47244961713Sgirish case DDI_CTLOPS_INITCHILD: 47344961713Sgirish return (niumx_initchild((dev_info_t *)arg)); 47444961713Sgirish 47544961713Sgirish case DDI_CTLOPS_UNINITCHILD: 47644961713Sgirish niumx_removechild((dev_info_t *)arg); 47744961713Sgirish return (DDI_SUCCESS); 47844961713Sgirish 47944961713Sgirish case DDI_CTLOPS_REGSIZE: 48044961713Sgirish case DDI_CTLOPS_NREGS: 48144961713Sgirish /* fall through */ 48244961713Sgirish break; 48344961713Sgirish default: 484500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_CTLOPS, dip, "just pass to ddi_cltops.\n"); 48544961713Sgirish return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 48644961713Sgirish } 48744961713Sgirish 48844961713Sgirish /* REGSIZE/NREGS */ 48944961713Sgirish 49044961713Sgirish *(int *)result = 0; 49144961713Sgirish 49244961713Sgirish if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS | 493adf6c93bSjf137018 DDI_PROP_CANSLEEP, "reg", (caddr_t)®_p, ®len) != DDI_SUCCESS) 49444961713Sgirish return (DDI_FAILURE); 49544961713Sgirish 49644961713Sgirish totreg = reglen / sizeof (niu_regspec_t); 49744961713Sgirish if (ctlop == DDI_CTLOPS_NREGS) { 498500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_CTLOPS, (dev_info_t *)dip, 499500b1e78SAlan Adamson, SD OSSD "niumx_ctlops NREGS=%d.\n", totreg); 50044961713Sgirish *(int *)result = totreg; 50144961713Sgirish } else if (ctlop == DDI_CTLOPS_REGSIZE) { 50244961713Sgirish int rn; 50344961713Sgirish rn = *(int *)arg; 50444961713Sgirish if (rn >= totreg) { 50544961713Sgirish kmem_free(reg_p, reglen); 50644961713Sgirish return (DDI_FAILURE); 50744961713Sgirish } 50844961713Sgirish *(off_t *)result = (reg_p + rn)->size_low; 509500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_CTLOPS, (dev_info_t *)dip, 510500b1e78SAlan Adamson, SD OSSD "rn = %d, REGSIZE=%x.\n", rn, *(off_t *)result); 51144961713Sgirish } 51244961713Sgirish 51344961713Sgirish kmem_free(reg_p, reglen); 51444961713Sgirish return (DDI_SUCCESS); 51544961713Sgirish } 51644961713Sgirish 517adf6c93bSjf137018 /* 518adf6c93bSjf137018 * niumx_name_child 519adf6c93bSjf137018 * 520adf6c93bSjf137018 * This function is called from init_child to name a node. It is 521adf6c93bSjf137018 * also passed as a callback for node merging functions. 522adf6c93bSjf137018 * 523adf6c93bSjf137018 * return value: DDI_SUCCESS, DDI_FAILURE 524adf6c93bSjf137018 */ 525adf6c93bSjf137018 static int 526adf6c93bSjf137018 niumx_name_child(dev_info_t *child, char *name, int namelen) 527adf6c93bSjf137018 { 528adf6c93bSjf137018 niu_regspec_t *r; 529adf6c93bSjf137018 uint_t n; 530adf6c93bSjf137018 531500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_CHK_MOD, (dev_info_t *)child, "==> niumx_name_child\n"); 532adf6c93bSjf137018 533adf6c93bSjf137018 if (ndi_dev_is_persistent_node(child) == 0) { 534adf6c93bSjf137018 char **unit_addr; 535adf6c93bSjf137018 536adf6c93bSjf137018 /* name .conf nodes by "unit-address" property */ 537adf6c93bSjf137018 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 538adf6c93bSjf137018 DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) != 539adf6c93bSjf137018 DDI_PROP_SUCCESS) { 540adf6c93bSjf137018 cmn_err(CE_WARN, "cannot name node from %s.conf", 541adf6c93bSjf137018 ddi_driver_name(child)); 542adf6c93bSjf137018 return (DDI_FAILURE); 543adf6c93bSjf137018 } 544adf6c93bSjf137018 if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 545adf6c93bSjf137018 cmn_err(CE_WARN, "unit-address property in %s.conf" 546adf6c93bSjf137018 " not well-formed", ddi_driver_name(child)); 547adf6c93bSjf137018 ddi_prop_free(unit_addr); 548adf6c93bSjf137018 return (DDI_FAILURE); 549adf6c93bSjf137018 } 550adf6c93bSjf137018 551adf6c93bSjf137018 (void) snprintf(name, namelen, "%s", *unit_addr); 552adf6c93bSjf137018 ddi_prop_free(unit_addr); 553adf6c93bSjf137018 return (DDI_SUCCESS); 554adf6c93bSjf137018 } 555adf6c93bSjf137018 556adf6c93bSjf137018 /* name hardware nodes by "reg" property */ 557adf6c93bSjf137018 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 558adf6c93bSjf137018 "reg", (int **)&r, &n) != DDI_SUCCESS) { 559adf6c93bSjf137018 cmn_err(CE_WARN, "reg property not well-formed"); 560adf6c93bSjf137018 return (DDI_FAILURE); 561adf6c93bSjf137018 } 562678453a8Sspeer (void) snprintf(name, namelen, "%x", (r[0].addr_high)); 563adf6c93bSjf137018 ddi_prop_free(r); 564adf6c93bSjf137018 return (DDI_SUCCESS); 565adf6c93bSjf137018 } 566adf6c93bSjf137018 56744961713Sgirish static int 56844961713Sgirish niumx_initchild(dev_info_t *child) 56944961713Sgirish { 57044961713Sgirish char name[MAXNAMELEN]; 571adf6c93bSjf137018 572500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_CHK_MOD, (dev_info_t *)child, "==> niumx_initchild\n"); 573adf6c93bSjf137018 /* 574adf6c93bSjf137018 * Non-peristent nodes indicate a prototype node with per-instance 575adf6c93bSjf137018 * properties to be merged into the real h/w device node. 576adf6c93bSjf137018 */ 577adf6c93bSjf137018 if (ndi_dev_is_persistent_node(child) == 0) { 57844961713Sgirish niu_regspec_t *r; 57944961713Sgirish uint_t n; 58044961713Sgirish 581adf6c93bSjf137018 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, 582adf6c93bSjf137018 DDI_PROP_DONTPASS, "reg", (int **)&r, &n) == 583adf6c93bSjf137018 DDI_SUCCESS) { 584adf6c93bSjf137018 cmn_err(CE_WARN, 585adf6c93bSjf137018 "cannot merge prototype from %s.conf", 586adf6c93bSjf137018 ddi_driver_name(child)); 587adf6c93bSjf137018 ddi_prop_free(r); 588adf6c93bSjf137018 return (DDI_NOT_WELL_FORMED); 589adf6c93bSjf137018 } 590adf6c93bSjf137018 591adf6c93bSjf137018 if (niumx_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS) 592adf6c93bSjf137018 return (DDI_NOT_WELL_FORMED); 593adf6c93bSjf137018 594adf6c93bSjf137018 ddi_set_name_addr(child, name); 595adf6c93bSjf137018 ddi_set_parent_data(child, NULL); 596adf6c93bSjf137018 597adf6c93bSjf137018 /* 598adf6c93bSjf137018 * Try to merge the properties from this prototype 599adf6c93bSjf137018 * node into real h/w nodes. 600adf6c93bSjf137018 */ 601adf6c93bSjf137018 if (ndi_merge_node(child, niumx_name_child) == DDI_SUCCESS) { 602adf6c93bSjf137018 /* 603adf6c93bSjf137018 * Merged ok - return failure to remove the node. 604adf6c93bSjf137018 */ 605adf6c93bSjf137018 ddi_set_name_addr(child, NULL); 60644961713Sgirish return (DDI_FAILURE); 60744961713Sgirish } 608adf6c93bSjf137018 609adf6c93bSjf137018 /* 610adf6c93bSjf137018 * The child was not merged into a h/w node, 611adf6c93bSjf137018 * but there's not much we can do with it other 612adf6c93bSjf137018 * than return failure to cause the node to be removed. 613adf6c93bSjf137018 */ 614adf6c93bSjf137018 cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged", 615adf6c93bSjf137018 ddi_driver_name(child), ddi_get_name_addr(child), 616adf6c93bSjf137018 ddi_driver_name(child)); 617adf6c93bSjf137018 ddi_set_name_addr(child, NULL); 618adf6c93bSjf137018 return (DDI_NOT_WELL_FORMED); 619adf6c93bSjf137018 } 620adf6c93bSjf137018 621adf6c93bSjf137018 /* 622adf6c93bSjf137018 * Initialize real h/w nodes 623adf6c93bSjf137018 */ 624adf6c93bSjf137018 if (niumx_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS) 625adf6c93bSjf137018 return (DDI_FAILURE); 626adf6c93bSjf137018 62744961713Sgirish ddi_set_name_addr(child, name); 62844961713Sgirish return (DDI_SUCCESS); 62944961713Sgirish } 63044961713Sgirish 63144961713Sgirish static void 63244961713Sgirish niumx_removechild(dev_info_t *dip) 63344961713Sgirish { 63444961713Sgirish ddi_set_name_addr(dip, NULL); 63544961713Sgirish ddi_remove_minor_node(dip, NULL); 63644961713Sgirish impl_rem_dev_props(dip); 63744961713Sgirish } 63844961713Sgirish 63944961713Sgirish 64044961713Sgirish 64144961713Sgirish /* 64244961713Sgirish * bus dma alloc handle entry point: 64344961713Sgirish */ 64444961713Sgirish /*ARGSUSED*/ 64544961713Sgirish int 64644961713Sgirish niumx_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attrp, 64744961713Sgirish int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep) 64844961713Sgirish { 64944961713Sgirish ddi_dma_impl_t *mp; 65044961713Sgirish int sleep = (waitfp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 65144961713Sgirish 652500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_DMA_ALLOCH, dip, "rdip=%s%d\n", NIUMX_NAMEINST(rdip)); 65344961713Sgirish 65444961713Sgirish if (attrp->dma_attr_version != DMA_ATTR_V0) { 655500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_DMA_ALLOCH, 656500b1e78SAlan Adamson, SD OSSD (dev_info_t *)dip, "DDI_DMA_BADATTR\n"); 65744961713Sgirish return (DDI_DMA_BADATTR); 65844961713Sgirish } 65944961713Sgirish 66044961713Sgirish /* Caution: we don't use zalloc to enhance performance! */ 66144961713Sgirish if ((mp = kmem_alloc(sizeof (ddi_dma_impl_t), sleep)) == 0) { 662500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_DMA_ALLOCH, dip, "can't alloc ddi_dma_impl_t\n"); 66344961713Sgirish return (DDI_FAILURE); 66444961713Sgirish } 66544961713Sgirish mp->dmai_rdip = rdip; 66644961713Sgirish mp->dmai_pfnlst = NULL; 66744961713Sgirish mp->dmai_cookie = NULL; 66844961713Sgirish mp->dmai_fault = 0; 66944961713Sgirish mp->dmai_fault_check = NULL; 67044961713Sgirish mp->dmai_fault_notify = NULL; 67144961713Sgirish 67244961713Sgirish mp->dmai_attr = *attrp; /* set requestors attr info */ 67344961713Sgirish 674500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_DMA_ALLOCH, dip, "mp=%p\n", mp); 67544961713Sgirish 67644961713Sgirish *handlep = (ddi_dma_handle_t)mp; 67744961713Sgirish return (DDI_SUCCESS); 67844961713Sgirish } 67944961713Sgirish 68044961713Sgirish 68144961713Sgirish /* 68244961713Sgirish * bus dma free handle entry point: 68344961713Sgirish */ 68444961713Sgirish /*ARGSUSED*/ 68544961713Sgirish int 68644961713Sgirish niumx_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle) 68744961713Sgirish { 68844961713Sgirish ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 68944961713Sgirish 69044961713Sgirish if (mp->dmai_cookie) 69144961713Sgirish kmem_free(mp->dmai_cookie, sizeof (ddi_dma_cookie_t)); 69244961713Sgirish kmem_free(mp, sizeof (ddi_dma_impl_t)); 69344961713Sgirish 69444961713Sgirish return (DDI_SUCCESS); 69544961713Sgirish } 69644961713Sgirish 69744961713Sgirish 69844961713Sgirish /* 69944961713Sgirish * bus dma bind handle entry point: 70044961713Sgirish * 70144961713Sgirish * check/enforce DMA type, setup pfn0 and some other key pieces 70244961713Sgirish * of this dma request. 70344961713Sgirish * Note: this only works with DMA_OTYP_VADDR, and makes use of the known 70444961713Sgirish * fact that only contiguous memory blocks will be passed in. 70544961713Sgirish * Therefore only one cookie will ever be returned. 70644961713Sgirish * 70744961713Sgirish * return values: 70844961713Sgirish * DDI_DMA_NOMAPPING - can't get valid pfn0, or bad dma type 70944961713Sgirish * DDI_DMA_NORESOURCES 71044961713Sgirish * DDI_SUCCESS 71144961713Sgirish * 71244961713Sgirish * dma handle members affected (set on exit): 71344961713Sgirish * mp->dmai_object - dmareq->dmar_object 71444961713Sgirish * mp->dmai_rflags - dmareq->dmar_flags 71544961713Sgirish * mp->dmai_pfn0 - 1st page pfn (if va/size pair and not shadow) 71644961713Sgirish * mp->dmai_roffset - initialized to starting page offset 71744961713Sgirish * mp->dmai_size - # of total pages of entire object 71844961713Sgirish * mp->dmai_cookie - new cookie alloc'd 71944961713Sgirish */ 72044961713Sgirish /*ARGSUSED*/ 72144961713Sgirish int 72244961713Sgirish niumx_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 72344961713Sgirish ddi_dma_handle_t handle, ddi_dma_req_t *dmareq, 72444961713Sgirish ddi_dma_cookie_t *cookiep, uint_t *ccountp) 72544961713Sgirish { 72644961713Sgirish int (*waitfp)(caddr_t) = dmareq->dmar_fp; 72744961713Sgirish ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 72844961713Sgirish ddi_dma_obj_t *dobj_p = &dmareq->dmar_object; 72944961713Sgirish uint32_t offset; 73044961713Sgirish pfn_t pfn0; 73144961713Sgirish int ret; 73244961713Sgirish 733500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_DMA_BINDH, dip, "rdip=%s%d mp=%p dmareq=%p\n", 734500b1e78SAlan Adamson, SD OSSD NIUMX_NAMEINST(rdip), mp, dmareq); 73544961713Sgirish 73644961713Sgirish /* first check dma type */ 73744961713Sgirish mp->dmai_rflags = dmareq->dmar_flags & DMP_DDIFLAGS | DMP_NOSYNC; 73844961713Sgirish switch (dobj_p->dmao_type) { 73944961713Sgirish case DMA_OTYP_VADDR: { 74044961713Sgirish caddr_t vaddr = dobj_p->dmao_obj.virt_obj.v_addr; 74144961713Sgirish struct as *as_p = dobj_p->dmao_obj.virt_obj.v_as; 74244961713Sgirish struct hat *hat_p = as_p ? as_p->a_hat : kas.a_hat; 74344961713Sgirish offset = (ulong_t)vaddr & NIUMX_PAGE_OFFSET; 74444961713Sgirish pfn0 = hat_getpfnum(hat_p, vaddr); 74544961713Sgirish } 74644961713Sgirish break; 74744961713Sgirish 74844961713Sgirish case DMA_OTYP_BUFVADDR: 74944961713Sgirish case DMA_OTYP_PAGES: 75044961713Sgirish case DMA_OTYP_PADDR: 75144961713Sgirish default: 75244961713Sgirish cmn_err(CE_WARN, "%s%d requested unsupported dma type %x", 753500b1e78SAlan Adamson, SD OSSD NIUMX_NAMEINST(mp->dmai_rdip), dobj_p->dmao_type); 75444961713Sgirish ret = DDI_DMA_NOMAPPING; 75544961713Sgirish goto err; 75644961713Sgirish } 75744961713Sgirish if (pfn0 == PFN_INVALID) { 75844961713Sgirish cmn_err(CE_WARN, "%s%d: invalid pfn0 for DMA object %p", 759500b1e78SAlan Adamson, SD OSSD NIUMX_NAMEINST(dip), (void *)dobj_p); 76044961713Sgirish ret = DDI_DMA_NOMAPPING; 76144961713Sgirish goto err; 76244961713Sgirish } 76344961713Sgirish mp->dmai_object = *dobj_p; /* whole object */ 76444961713Sgirish mp->dmai_pfn0 = (void *)pfn0; /* cache pfn0 */ 76544961713Sgirish mp->dmai_roffset = offset; /* pg0 offset */ 76644961713Sgirish mp->dmai_mapping = mp->dmai_roffset | NIUMX_PTOB(pfn0); 76744961713Sgirish mp->dmai_size = mp->dmai_object.dmao_size; 76844961713Sgirish 769500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_DMA_BINDH, dip, "check pfn: mp=%p pfn0=%x\n", 77044961713Sgirish mp, mp->dmai_pfn0); 77144961713Sgirish if (!(mp->dmai_cookie = kmem_zalloc(sizeof (ddi_dma_cookie_t), 77244961713Sgirish waitfp == DDI_DMA_SLEEP ? KM_SLEEP : KM_NOSLEEP))) { 77344961713Sgirish ret = DDI_DMA_NORESOURCES; 77444961713Sgirish goto err; 77544961713Sgirish } 77644961713Sgirish mp->dmai_cookie->dmac_laddress = mp->dmai_mapping; 77744961713Sgirish mp->dmai_cookie->dmac_size = mp->dmai_size; 77844961713Sgirish *ccountp = 1; 77944961713Sgirish *cookiep = *mp->dmai_cookie; 780500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_DMA_BINDH, dip, "cookie %" PRIx64 "+%x, count=%d\n", 78144961713Sgirish cookiep->dmac_address, cookiep->dmac_size, *ccountp); 78244961713Sgirish return (DDI_DMA_MAPPED); 78344961713Sgirish 78444961713Sgirish err: 785500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_DMA_BINDH, (dev_info_t *)dip, 78644961713Sgirish "niumx_dma_bindhdl error ret=%d\n", ret); 78744961713Sgirish return (ret); 78844961713Sgirish } 78944961713Sgirish 79044961713Sgirish /* 79144961713Sgirish * bus dma unbind handle entry point: 79244961713Sgirish */ 79344961713Sgirish /*ARGSUSED*/ 79444961713Sgirish int 79544961713Sgirish niumx_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle) 79644961713Sgirish { 79744961713Sgirish ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 79844961713Sgirish 799500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_DMA_UNBINDH, dip, "rdip=%s%d, mp=%p\n", 80044961713Sgirish ddi_driver_name(rdip), ddi_get_instance(rdip), handle); 80144961713Sgirish if (mp->dmai_cookie) { 80244961713Sgirish kmem_free(mp->dmai_cookie, sizeof (ddi_dma_cookie_t)); 80344961713Sgirish mp->dmai_cookie = NULL; 80444961713Sgirish } 80544961713Sgirish 80644961713Sgirish return (DDI_SUCCESS); 80744961713Sgirish } 80844961713Sgirish 80944961713Sgirish /*ARGSUSED*/ 81044961713Sgirish int 81144961713Sgirish niumx_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 81244961713Sgirish ddi_intr_handle_impl_t *hdlp, void *result) 81344961713Sgirish { 81444961713Sgirish 81544961713Sgirish int ret = DDI_SUCCESS; 81644961713Sgirish 817500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_INTROPS, dip, "niumx_intr_ops: dip=%p rdip=%p intr_op=%x " 81844961713Sgirish "handle=%p\n", dip, rdip, intr_op, hdlp); 81944961713Sgirish 82044961713Sgirish switch (intr_op) { 82144961713Sgirish 82244961713Sgirish case DDI_INTROP_SUPPORTED_TYPES: 82344961713Sgirish *(int *)result = DDI_INTR_TYPE_FIXED; 82444961713Sgirish break; 82544961713Sgirish case DDI_INTROP_GETCAP: 826*657f87deSgongtian zhao - Sun Microsystems - Beijing China *(int *)result = DDI_INTR_FLAG_LEVEL; 82744961713Sgirish break; 82844961713Sgirish case DDI_INTROP_SETCAP: 82944961713Sgirish ret = DDI_ENOTSUP; 83044961713Sgirish break; 83144961713Sgirish case DDI_INTROP_ALLOC: 83244961713Sgirish /* scratch1 = count, # of intrs from DDI framework */ 83344961713Sgirish *(int *)result = hdlp->ih_scratch1; 83444961713Sgirish break; 83544961713Sgirish case DDI_INTROP_FREE: 83644961713Sgirish /* Do we need to do anything here? */ 83744961713Sgirish break; 83844961713Sgirish case DDI_INTROP_GETPRI: 83944961713Sgirish *(int *)result = NIUMX_DEFAULT_PIL; 84044961713Sgirish break; 84144961713Sgirish case DDI_INTROP_SETPRI: 84244961713Sgirish ret = DDI_ENOTSUP; 84344961713Sgirish break; 84444961713Sgirish case DDI_INTROP_ADDISR: 84544961713Sgirish ret = niumx_add_intr(dip, rdip, hdlp); 84644961713Sgirish break; 84744961713Sgirish case DDI_INTROP_REMISR: 84844961713Sgirish ret = niumx_rem_intr(dip, rdip, hdlp); 84944961713Sgirish break; 85044961713Sgirish case DDI_INTROP_ENABLE: 85144961713Sgirish ret = niumx_set_intr(dip, rdip, hdlp, HV_INTR_VALID); 85244961713Sgirish break; 85344961713Sgirish case DDI_INTROP_DISABLE: 85444961713Sgirish ret = niumx_set_intr(dip, rdip, hdlp, HV_INTR_NOTVALID); 85544961713Sgirish break; 85644961713Sgirish case DDI_INTROP_SETMASK: 85744961713Sgirish ret = DDI_ENOTSUP; 85844961713Sgirish break; 85944961713Sgirish case DDI_INTROP_CLRMASK: 86044961713Sgirish ret = DDI_ENOTSUP; 86144961713Sgirish break; 86244961713Sgirish case DDI_INTROP_GETPENDING: 86344961713Sgirish ret = DDI_ENOTSUP; 86444961713Sgirish break; 86544961713Sgirish case DDI_INTROP_NINTRS: 86644961713Sgirish case DDI_INTROP_NAVAIL: { 867500b1e78SAlan Adamson, SD OSSD niudevino_t *inos_p; 86844961713Sgirish int inoslen; 869500b1e78SAlan Adamson, SD OSSD 87044961713Sgirish if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 87144961713Sgirish "interrupts", (caddr_t)&inos_p, &inoslen) 87244961713Sgirish != DDI_SUCCESS) { 87344961713Sgirish ret = DDI_FAILURE; 87444961713Sgirish break; 87544961713Sgirish } 87644961713Sgirish *(int *)result = inoslen / sizeof (uint32_t); 87744961713Sgirish kmem_free(inos_p, inoslen); 87844961713Sgirish } 87944961713Sgirish break; 880500b1e78SAlan Adamson, SD OSSD case DDI_INTROP_GETTARGET: { 881500b1e78SAlan Adamson, SD OSSD niumx_devstate_t *niumxds_p; 882500b1e78SAlan Adamson, SD OSSD 883500b1e78SAlan Adamson, SD OSSD niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state, 884500b1e78SAlan Adamson, SD OSSD ddi_get_instance(dip)); 885500b1e78SAlan Adamson, SD OSSD 886500b1e78SAlan Adamson, SD OSSD ret = niumx_get_intr_target(niumxds_p, hdlp->ih_vector, 887500b1e78SAlan Adamson, SD OSSD (niucpuid_t *)result); 888500b1e78SAlan Adamson, SD OSSD 889500b1e78SAlan Adamson, SD OSSD } 890500b1e78SAlan Adamson, SD OSSD break; 891500b1e78SAlan Adamson, SD OSSD case DDI_INTROP_SETTARGET: { 892500b1e78SAlan Adamson, SD OSSD niumx_devstate_t *niumxds_p; 893500b1e78SAlan Adamson, SD OSSD 894500b1e78SAlan Adamson, SD OSSD niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state, 895500b1e78SAlan Adamson, SD OSSD ddi_get_instance(dip)); 896500b1e78SAlan Adamson, SD OSSD 897500b1e78SAlan Adamson, SD OSSD ret = niumx_set_intr_target(niumxds_p, hdlp->ih_vector, 898500b1e78SAlan Adamson, SD OSSD *(niucpuid_t *)result); 899500b1e78SAlan Adamson, SD OSSD 900500b1e78SAlan Adamson, SD OSSD } 901500b1e78SAlan Adamson, SD OSSD break; 90244961713Sgirish default: 90344961713Sgirish ret = DDI_ENOTSUP; 90444961713Sgirish break; 90544961713Sgirish } 90644961713Sgirish 907500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_INTROPS, dip, "niumx_intr_ops: ret=%d\n", ret); 90844961713Sgirish return (ret); 90944961713Sgirish } 91044961713Sgirish 91144961713Sgirish int 91244961713Sgirish niumx_set_intr(dev_info_t *dip, dev_info_t *rdip, 91344961713Sgirish ddi_intr_handle_impl_t *hdlp, int valid) 91444961713Sgirish { 91544961713Sgirish niumx_ih_t *ih_p; 916500b1e78SAlan Adamson, SD OSSD int ret = DDI_SUCCESS; 91744961713Sgirish uint64_t hvret; 9184df55fdeSJanie Lu niumx_devstate_t *niumxds_p; /* devstate pointer */ 9194df55fdeSJanie Lu int instance = ddi_get_instance(dip); 9204df55fdeSJanie Lu 9214df55fdeSJanie Lu niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state, 9224df55fdeSJanie Lu instance); 92344961713Sgirish 92444961713Sgirish ASSERT(hdlp->ih_inum < NIUMX_MAX_INTRS); 92544961713Sgirish 926500b1e78SAlan Adamson, SD OSSD ih_p = niumxds_p->niumx_ihtable + hdlp->ih_vector; 9274df55fdeSJanie Lu 928500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_A_INTX, dip, 929500b1e78SAlan Adamson, SD OSSD "niumx_set_intr: rdip=%s%d, valid=%d %s (%x,%x)\n", 930500b1e78SAlan Adamson, SD OSSD NIUMX_NAMEINST(rdip), valid, valid ? "enabling" : "disabling", 9318fca0570Sjf137018 ih_p->ih_inum, ih_p->ih_sysino); 93244961713Sgirish 933cb343a2eSspeer if (valid == HV_INTR_VALID) 934cb343a2eSspeer (void) hvio_intr_setstate(ih_p->ih_sysino, HV_INTR_IDLE_STATE); 93544961713Sgirish if ((hvret = hvio_intr_setvalid(ih_p->ih_sysino, valid)) 93644961713Sgirish != H_EOK) { 937500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_A_INTX, dip, 938500b1e78SAlan Adamson, SD OSSD "hvio_intr_setvalid failed, ret 0x%x\n", hvret); 93944961713Sgirish ret = DDI_FAILURE; 940500b1e78SAlan Adamson, SD OSSD } else 941500b1e78SAlan Adamson, SD OSSD ih_p->ih_state = valid; 942500b1e78SAlan Adamson, SD OSSD 94344961713Sgirish return (ret); 94444961713Sgirish } 94544961713Sgirish 946500b1e78SAlan Adamson, SD OSSD int 947500b1e78SAlan Adamson, SD OSSD niumx_get_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino, 948500b1e78SAlan Adamson, SD OSSD niucpuid_t *cpu_id) 949500b1e78SAlan Adamson, SD OSSD { 950500b1e78SAlan Adamson, SD OSSD niumx_ih_t *ih_p; 951500b1e78SAlan Adamson, SD OSSD niusysino_t sysino; 952500b1e78SAlan Adamson, SD OSSD int rval = DDI_SUCCESS; 953500b1e78SAlan Adamson, SD OSSD 954500b1e78SAlan Adamson, SD OSSD ih_p = niumxds_p->niumx_ihtable + ino; 955500b1e78SAlan Adamson, SD OSSD 956500b1e78SAlan Adamson, SD OSSD sysino = ih_p->ih_sysino; 957500b1e78SAlan Adamson, SD OSSD 958500b1e78SAlan Adamson, SD OSSD if (sysino == 0) { 959500b1e78SAlan Adamson, SD OSSD rval = EINVAL; 960500b1e78SAlan Adamson, SD OSSD goto done; 961500b1e78SAlan Adamson, SD OSSD } 962500b1e78SAlan Adamson, SD OSSD 963500b1e78SAlan Adamson, SD OSSD if (hvio_intr_gettarget(sysino, cpu_id) != H_EOK) { 964500b1e78SAlan Adamson, SD OSSD rval = EINVAL; 965500b1e78SAlan Adamson, SD OSSD goto done; 966500b1e78SAlan Adamson, SD OSSD } 967500b1e78SAlan Adamson, SD OSSD 968500b1e78SAlan Adamson, SD OSSD if (ih_p->ih_cpuid != *cpu_id) 969500b1e78SAlan Adamson, SD OSSD rval = EIO; 970500b1e78SAlan Adamson, SD OSSD 971500b1e78SAlan Adamson, SD OSSD done: 972500b1e78SAlan Adamson, SD OSSD return (rval); 973500b1e78SAlan Adamson, SD OSSD } 974500b1e78SAlan Adamson, SD OSSD 975500b1e78SAlan Adamson, SD OSSD int 976500b1e78SAlan Adamson, SD OSSD niumx_set_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino, 977500b1e78SAlan Adamson, SD OSSD niucpuid_t cpu_id) 978500b1e78SAlan Adamson, SD OSSD { 979500b1e78SAlan Adamson, SD OSSD dev_info_t *dip = niumxds_p->dip; 980500b1e78SAlan Adamson, SD OSSD niumx_ih_t *ih_p; 981500b1e78SAlan Adamson, SD OSSD niucpuid_t old_cpu_id; 982500b1e78SAlan Adamson, SD OSSD niusysino_t sysino; 983500b1e78SAlan Adamson, SD OSSD int ret = DDI_SUCCESS; 984500b1e78SAlan Adamson, SD OSSD int state; 985500b1e78SAlan Adamson, SD OSSD hrtime_t start; 986500b1e78SAlan Adamson, SD OSSD extern const int _ncpu; 987500b1e78SAlan Adamson, SD OSSD extern cpu_t *cpu[]; 988500b1e78SAlan Adamson, SD OSSD 989500b1e78SAlan Adamson, SD OSSD mutex_enter(&cpu_lock); 990500b1e78SAlan Adamson, SD OSSD 991500b1e78SAlan Adamson, SD OSSD ih_p = niumxds_p->niumx_ihtable + ino; 992500b1e78SAlan Adamson, SD OSSD 993500b1e78SAlan Adamson, SD OSSD sysino = ih_p->ih_sysino; 994500b1e78SAlan Adamson, SD OSSD if (sysino == 0) { 995500b1e78SAlan Adamson, SD OSSD ret = EINVAL; 996500b1e78SAlan Adamson, SD OSSD goto done; 997500b1e78SAlan Adamson, SD OSSD } 998500b1e78SAlan Adamson, SD OSSD 999500b1e78SAlan Adamson, SD OSSD if (hvio_intr_gettarget(sysino, &old_cpu_id) != H_EOK) { 1000500b1e78SAlan Adamson, SD OSSD ret = EINVAL; 1001500b1e78SAlan Adamson, SD OSSD goto done; 1002500b1e78SAlan Adamson, SD OSSD } 1003500b1e78SAlan Adamson, SD OSSD if ((cpu_id < _ncpu) && (cpu[cpu_id] && cpu_is_online(cpu[cpu_id]))) { 1004500b1e78SAlan Adamson, SD OSSD if (cpu_id == old_cpu_id) 1005500b1e78SAlan Adamson, SD OSSD goto done; 1006500b1e78SAlan Adamson, SD OSSD 1007500b1e78SAlan Adamson, SD OSSD /* check for pending interrupts, busy wait if so */ 1008500b1e78SAlan Adamson, SD OSSD for (start = gethrtime(); !panicstr && 1009500b1e78SAlan Adamson, SD OSSD (hvio_intr_getstate(sysino, &state) == H_EOK) && 1010500b1e78SAlan Adamson, SD OSSD (state == HV_INTR_DELIVERED_STATE); /* */) { 1011500b1e78SAlan Adamson, SD OSSD if (gethrtime() - start > niumx_intr_timeout) { 1012500b1e78SAlan Adamson, SD OSSD cmn_err(CE_WARN, "%s%d: niumx_intr_dist: " 1013500b1e78SAlan Adamson, SD OSSD "pending interrupt (%x,%lx) timedout\n", 1014500b1e78SAlan Adamson, SD OSSD ddi_driver_name(dip), ddi_get_instance(dip), 1015500b1e78SAlan Adamson, SD OSSD ih_p->ih_inum, sysino); 1016500b1e78SAlan Adamson, SD OSSD (void) hvio_intr_setstate(sysino, 1017500b1e78SAlan Adamson, SD OSSD HV_INTR_IDLE_STATE); 1018500b1e78SAlan Adamson, SD OSSD break; 1019500b1e78SAlan Adamson, SD OSSD } 1020500b1e78SAlan Adamson, SD OSSD } 1021500b1e78SAlan Adamson, SD OSSD (void) hvio_intr_settarget(sysino, cpu_id); 1022500b1e78SAlan Adamson, SD OSSD if (ih_p->ih_state == HV_INTR_VALID) 1023500b1e78SAlan Adamson, SD OSSD (void) hvio_intr_setvalid(sysino, HV_INTR_VALID); 1024500b1e78SAlan Adamson, SD OSSD else 1025500b1e78SAlan Adamson, SD OSSD (void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID); 1026500b1e78SAlan Adamson, SD OSSD ih_p->ih_cpuid = cpu_id; 1027500b1e78SAlan Adamson, SD OSSD } else { 1028500b1e78SAlan Adamson, SD OSSD ret = DDI_EINVAL; 1029500b1e78SAlan Adamson, SD OSSD } 1030500b1e78SAlan Adamson, SD OSSD 1031500b1e78SAlan Adamson, SD OSSD done: 1032500b1e78SAlan Adamson, SD OSSD mutex_exit(&cpu_lock); 1033500b1e78SAlan Adamson, SD OSSD return (ret); 1034500b1e78SAlan Adamson, SD OSSD } 103544961713Sgirish 103644961713Sgirish 103744961713Sgirish /* 103844961713Sgirish * niumx_add_intr: 103944961713Sgirish * 1040e778ae44SRaghuram Kothakota * This function is called to register interrupts. 104144961713Sgirish */ 104244961713Sgirish int 104344961713Sgirish niumx_add_intr(dev_info_t *dip, dev_info_t *rdip, 104444961713Sgirish ddi_intr_handle_impl_t *hdlp) 104544961713Sgirish { 104644961713Sgirish niumx_ih_t *ih_p; 1047500b1e78SAlan Adamson, SD OSSD int ret = DDI_SUCCESS; 104844961713Sgirish uint64_t hvret; 1049500b1e78SAlan Adamson, SD OSSD niusysino_t sysino; 10504df55fdeSJanie Lu niumx_devstate_t *niumxds_p; /* devstate pointer */ 10514df55fdeSJanie Lu int instance = ddi_get_instance(dip); 10524df55fdeSJanie Lu 10534df55fdeSJanie Lu niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state, 10544df55fdeSJanie Lu instance); 105544961713Sgirish 105644961713Sgirish /* get new ino */ 105744961713Sgirish if (hdlp->ih_inum >= NIUMX_MAX_INTRS) { 1058500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_INTR, dip, "error: inum %d out of range\n", 105944961713Sgirish hdlp->ih_inum); 106044961713Sgirish ret = DDI_FAILURE; 106144961713Sgirish goto done; 106244961713Sgirish } 1063500b1e78SAlan Adamson, SD OSSD 1064500b1e78SAlan Adamson, SD OSSD ih_p = niumxds_p->niumx_ihtable + hdlp->ih_vector; 1065500b1e78SAlan Adamson, SD OSSD 1066500b1e78SAlan Adamson, SD OSSD if ((hvret = hvio_intr_devino_to_sysino(NIUMX_DIP_TO_HANDLE(dip), 1067500b1e78SAlan Adamson, SD OSSD hdlp->ih_vector, &sysino)) != H_EOK) { 1068500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_INTR, dip, "hvio_intr_devino_to_sysino failed, " 106944961713Sgirish "ret 0x%x\n", hvret); 107044961713Sgirish ret = DDI_FAILURE; 107144961713Sgirish goto done; 107244961713Sgirish } 107344961713Sgirish ih_p->ih_sysino = sysino; 1074500b1e78SAlan Adamson, SD OSSD ih_p->ih_dip = rdip; 107544961713Sgirish ih_p->ih_inum = hdlp->ih_inum; 107644961713Sgirish ih_p->ih_hdlr = hdlp->ih_cb_func; 107744961713Sgirish ih_p->ih_arg1 = hdlp->ih_cb_arg1; 107844961713Sgirish ih_p->ih_arg2 = hdlp->ih_cb_arg2; 107944961713Sgirish 1080500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_A_INTX, dip, "niumx_add_intr: rdip=%s%d inum=0x%x " 1081500b1e78SAlan Adamson, SD OSSD "handler=%p arg1=%p arg2=%p, new ih_p = %p\n", NIUMX_NAMEINST(rdip), 108244961713Sgirish hdlp->ih_inum, hdlp->ih_cb_func, hdlp->ih_cb_arg1, 108344961713Sgirish hdlp->ih_cb_arg2, ih_p); 108444961713Sgirish 108544961713Sgirish if (hdlp->ih_pri == 0) 108644961713Sgirish hdlp->ih_pri = NIUMX_DEFAULT_PIL; 108744961713Sgirish 1088500b1e78SAlan Adamson, SD OSSD ih_p->ih_pri = hdlp->ih_pri; 1089500b1e78SAlan Adamson, SD OSSD 1090500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_A_INTX, dip, "for ino %x adding (%x,%x)\n", 1091500b1e78SAlan Adamson, SD OSSD hdlp->ih_vector, ih_p->ih_inum, ih_p->ih_sysino); 1092500b1e78SAlan Adamson, SD OSSD 109344961713Sgirish /* Save sysino value in hdlp */ 109444961713Sgirish hdlp->ih_vector = ih_p->ih_sysino; 109544961713Sgirish 109644961713Sgirish /* swap in our handler & arg */ 109744961713Sgirish DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, (ddi_intr_handler_t *)niumx_intr_hdlr, 109844961713Sgirish (void *)ih_p, NULL); 109944961713Sgirish 110044961713Sgirish ret = i_ddi_add_ivintr(hdlp); 110144961713Sgirish 110244961713Sgirish /* Restore orig. interrupt handler & args in handle. */ 110344961713Sgirish DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_hdlr, ih_p->ih_arg1, 110444961713Sgirish ih_p->ih_arg2); 110544961713Sgirish 110644961713Sgirish if (ret != DDI_SUCCESS) { 1107500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_A_INTX, dip, "i_ddi_add_ivintr error ret=%x\n", 1108500b1e78SAlan Adamson, SD OSSD ret); 110944961713Sgirish goto done; 111044961713Sgirish } 111144961713Sgirish 111244961713Sgirish /* select cpu, saving it for removal */ 111344961713Sgirish ih_p->ih_cpuid = intr_dist_cpuid(); 111444961713Sgirish 111544961713Sgirish if ((hvret = hvio_intr_settarget(ih_p->ih_sysino, ih_p->ih_cpuid)) 111644961713Sgirish != H_EOK) { 1117500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_A_INTX, dip, 1118500b1e78SAlan Adamson, SD OSSD "hvio_intr_settarget failed, ret 0x%x\n", hvret); 111944961713Sgirish ret = DDI_FAILURE; 112044961713Sgirish } 112144961713Sgirish done: 1122500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_A_INTX, dip, "done, ret = %d, ih_p 0x%p, hdlp 0x%p\n", 1123500b1e78SAlan Adamson, SD OSSD ih_p, hdlp, ret); 112444961713Sgirish return (ret); 112544961713Sgirish } 112644961713Sgirish 112744961713Sgirish /* 112844961713Sgirish * niumx_rem_intr: 112944961713Sgirish * 113044961713Sgirish * This function is called to unregister interrupts. 113144961713Sgirish */ 1132500b1e78SAlan Adamson, SD OSSD /*ARGSUSED*/ 113344961713Sgirish int 113444961713Sgirish niumx_rem_intr(dev_info_t *dip, dev_info_t *rdip, 113544961713Sgirish ddi_intr_handle_impl_t *hdlp) 113644961713Sgirish { 113744961713Sgirish niumx_ih_t *ih_p; 1138500b1e78SAlan Adamson, SD OSSD int ret = DDI_SUCCESS, state; 1139c165966dSjf137018 hrtime_t start; 1140500b1e78SAlan Adamson, SD OSSD niusysino_t sysino; 11414df55fdeSJanie Lu niumx_devstate_t *niumxds_p; /* devstate pointer */ 11424df55fdeSJanie Lu int instance = ddi_get_instance(dip); 11434df55fdeSJanie Lu 11444df55fdeSJanie Lu niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state, 11454df55fdeSJanie Lu instance); 114644961713Sgirish 114744961713Sgirish ASSERT(hdlp->ih_inum < NIUMX_MAX_INTRS); 114844961713Sgirish 1149500b1e78SAlan Adamson, SD OSSD ih_p = niumxds_p->niumx_ihtable + hdlp->ih_vector; 1150500b1e78SAlan Adamson, SD OSSD 1151c165966dSjf137018 sysino = ih_p->ih_sysino; 1152500b1e78SAlan Adamson, SD OSSD DBG(NIUMX_DBG_R_INTX, dip, "removing (%x,%x)\n", ih_p->ih_inum, sysino); 115344961713Sgirish 1154c165966dSjf137018 (void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID); 1155c165966dSjf137018 1156c165966dSjf137018 /* check for pending interrupts, busy wait if so */ 1157c165966dSjf137018 for (start = gethrtime(); !panicstr && 1158c165966dSjf137018 (hvio_intr_getstate(sysino, &state) == H_EOK) && 1159c165966dSjf137018 (state == HV_INTR_DELIVERED_STATE); /* */) { 1160c165966dSjf137018 if (gethrtime() - start > niumx_intr_timeout) { 1161c165966dSjf137018 cmn_err(CE_WARN, "%s%d: niumx_intr_dist: " 1162c165966dSjf137018 "pending interrupt (%x,%lx) timedout\n", 1163c165966dSjf137018 ddi_driver_name(dip), ddi_get_instance(dip), 1164c165966dSjf137018 ih_p->ih_inum, sysino); 116544961713Sgirish ret = DDI_FAILURE; 1166500b1e78SAlan Adamson, SD OSSD goto fail; 116744961713Sgirish } 1168c165966dSjf137018 } 116944961713Sgirish 1170678453a8Sspeer ih_p->ih_sysino = 0; 1171678453a8Sspeer 1172c165966dSjf137018 hdlp->ih_vector = (uint32_t)sysino; 117344961713Sgirish if (hdlp->ih_vector != NULL) i_ddi_rem_ivintr(hdlp); 117444961713Sgirish 1175500b1e78SAlan Adamson, SD OSSD fail: 117644961713Sgirish return (ret); 117744961713Sgirish } 117844961713Sgirish 117944961713Sgirish /* 118044961713Sgirish * niumx_intr_hdlr (our interrupt handler) 118144961713Sgirish */ 118244961713Sgirish uint_t 118344961713Sgirish niumx_intr_hdlr(void *arg) 118444961713Sgirish { 118544961713Sgirish niumx_ih_t *ih_p = (niumx_ih_t *)arg; 118644961713Sgirish uint_t r; 118744961713Sgirish 118844961713Sgirish DTRACE_PROBE4(interrupt__start, dev_info_t, ih_p->ih_dip, void *, 118944961713Sgirish ih_p->ih_hdlr, caddr_t, ih_p->ih_arg1, caddr_t, ih_p->ih_arg2); 119044961713Sgirish 119144961713Sgirish r = (*ih_p->ih_hdlr)(ih_p->ih_arg1, ih_p->ih_arg2); 119244961713Sgirish 119344961713Sgirish DTRACE_PROBE4(interrupt__complete, dev_info_t, ih_p->ih_dip, void *, 119444961713Sgirish ih_p->ih_hdlr, caddr_t, ih_p->ih_arg1, int, r); 1195cb343a2eSspeer 1196cb343a2eSspeer (void) hvio_intr_setstate(ih_p->ih_sysino, HV_INTR_IDLE_STATE); 119744961713Sgirish return (r); 119844961713Sgirish } 119944961713Sgirish 120044961713Sgirish #ifdef DEBUG 120144961713Sgirish uint64_t niumx_debug_flags = 0; 120244961713Sgirish 120344961713Sgirish static char *niumx_debug_sym [] = { /* same sequence as niumx_debug_bit */ 120444961713Sgirish /* 0 */ "attach", 120544961713Sgirish /* 1 */ "map", 120644961713Sgirish /* 2 */ "nex-ctlops", 120744961713Sgirish /* 3 */ "introps", 120844961713Sgirish /* 4 */ "intr-add", 120944961713Sgirish /* 5 */ "intr-rem", 121044961713Sgirish /* 6 */ "intr", 121144961713Sgirish /* 7 */ "dma-alloc", 121244961713Sgirish /* 8 */ "dma-bind", 121344961713Sgirish /* 9 */ "dma-unbind", 121444961713Sgirish /* 10 */ "chk-dma-mode" 121544961713Sgirish }; 121644961713Sgirish 121744961713Sgirish /*ARGSUSED*/ 121844961713Sgirish void 121944961713Sgirish niumx_dbg(niumx_debug_bit_t bit, dev_info_t *dip, char *fmt, ...) 122044961713Sgirish { 122144961713Sgirish va_list ap; 122244961713Sgirish char msgbuf[1024]; 122344961713Sgirish 122444961713Sgirish if (!(1ull << bit & niumx_debug_flags)) 122544961713Sgirish return; 122644961713Sgirish va_start(ap, fmt); 122744961713Sgirish (void) vsprintf(msgbuf, fmt, ap); 122844961713Sgirish va_end(ap); 122944961713Sgirish cmn_err(CE_NOTE, "%s: %s", niumx_debug_sym[bit], msgbuf); 123044961713Sgirish } 123144961713Sgirish 123244961713Sgirish #endif /* DEBUG */ 1233