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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)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
niumx_intr_dist(void * arg)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
niumx_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
niumx_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
niumx_fm_init_child(dev_info_t * dip,dev_info_t * cdip,int cap,ddi_iblock_cookie_t * ibc_p)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
niumx_map(dev_info_t * dip,dev_info_t * rdip,ddi_map_req_t * mp,off_t offset,off_t len,caddr_t * vaddrp)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
niumx_ctlops(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)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
niumx_name_child(dev_info_t * child,char * name,int namelen)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
niumx_initchild(dev_info_t * child)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
niumx_removechild(dev_info_t * dip)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
niumx_dma_allochdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_attr_t * attrp,int (* waitfp)(caddr_t),caddr_t arg,ddi_dma_handle_t * handlep)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
niumx_dma_freehdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)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
niumx_dma_bindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,ddi_dma_req_t * dmareq,ddi_dma_cookie_t * cookiep,uint_t * ccountp)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
niumx_dma_unbindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)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
niumx_intr_ops(dev_info_t * dip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)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
niumx_set_intr(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,int valid)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
niumx_get_intr_target(niumx_devstate_t * niumxds_p,niudevino_t ino,niucpuid_t * cpu_id)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
niumx_set_intr_target(niumx_devstate_t * niumxds_p,niudevino_t ino,niucpuid_t cpu_id)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
niumx_add_intr(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)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
niumx_rem_intr(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)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
niumx_intr_hdlr(void * arg)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
niumx_dbg(niumx_debug_bit_t bit,dev_info_t * dip,char * fmt,...)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