10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51991Sheppo * Common Development and Distribution License (the "License").
61991Sheppo * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
226105Skc28005 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate
270Sstevel@tonic-gate #include <sys/types.h>
280Sstevel@tonic-gate #include <sys/cmn_err.h>
290Sstevel@tonic-gate #include <sys/conf.h>
300Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
310Sstevel@tonic-gate #include <sys/autoconf.h>
320Sstevel@tonic-gate #include <sys/systm.h>
330Sstevel@tonic-gate #include <sys/modctl.h>
340Sstevel@tonic-gate #include <sys/ddi.h>
350Sstevel@tonic-gate #include <sys/sunddi.h>
360Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
370Sstevel@tonic-gate #include <sys/promif.h>
380Sstevel@tonic-gate #include <sys/machsystm.h>
390Sstevel@tonic-gate #include <sys/ddi_intr_impl.h>
400Sstevel@tonic-gate #include <sys/hypervisor_api.h>
410Sstevel@tonic-gate #include <sys/intr.h>
424423Sjb145095 #include <sys/hsvc.h>
430Sstevel@tonic-gate
440Sstevel@tonic-gate #define SUN4V_REG_SPEC2CFG_HDL(x) ((x >> 32) & ~(0xfull << 28))
450Sstevel@tonic-gate
460Sstevel@tonic-gate static kmutex_t vnex_id_lock;
470Sstevel@tonic-gate /*
480Sstevel@tonic-gate * Vnex name to pil map
490Sstevel@tonic-gate */
500Sstevel@tonic-gate typedef struct vnex_regspec {
510Sstevel@tonic-gate uint64_t physaddr;
520Sstevel@tonic-gate uint64_t size;
530Sstevel@tonic-gate } vnex_regspec_t;
540Sstevel@tonic-gate
550Sstevel@tonic-gate struct vnex_pil_map {
560Sstevel@tonic-gate caddr_t name;
570Sstevel@tonic-gate uint32_t pil;
580Sstevel@tonic-gate };
590Sstevel@tonic-gate
600Sstevel@tonic-gate /* vnex interrupt descriptor */
610Sstevel@tonic-gate typedef struct vnex_id {
620Sstevel@tonic-gate dev_info_t *vid_dip;
630Sstevel@tonic-gate uint32_t vid_ino;
640Sstevel@tonic-gate uint64_t vid_ihdl;
650Sstevel@tonic-gate uint_t (*vid_handler)();
660Sstevel@tonic-gate caddr_t vid_arg1;
670Sstevel@tonic-gate caddr_t vid_arg2;
680Sstevel@tonic-gate ddi_intr_handle_impl_t *vid_ddi_hdlp;
690Sstevel@tonic-gate uint64_t vid_cfg_hdl;
700Sstevel@tonic-gate struct vnex_id *vid_next;
710Sstevel@tonic-gate } vnex_id_t;
720Sstevel@tonic-gate
730Sstevel@tonic-gate /* vnex interrupt descriptor list */
740Sstevel@tonic-gate static vnex_id_t *vnex_id_list;
750Sstevel@tonic-gate
76444Sarao hrtime_t vnex_pending_timeout = 2ull * NANOSEC; /* 2 seconds in nanoseconds */
77444Sarao
780Sstevel@tonic-gate /*
790Sstevel@tonic-gate * vnex interrupt descriptor list manipulation functions
800Sstevel@tonic-gate */
810Sstevel@tonic-gate
820Sstevel@tonic-gate static vnex_id_t *vnex_locate_id(dev_info_t *dip, uint32_t ino);
830Sstevel@tonic-gate static vnex_id_t *vnex_alloc_id(dev_info_t *dip, uint32_t ino,
840Sstevel@tonic-gate uint64_t dhdl);
850Sstevel@tonic-gate static void vnex_add_id(vnex_id_t *vid_p);
860Sstevel@tonic-gate static void vnex_rem_id(vnex_id_t *vid_p);
870Sstevel@tonic-gate static void vnex_free_id(vnex_id_t *vid_p);
880Sstevel@tonic-gate
890Sstevel@tonic-gate uint_t vnex_intr_wrapper(caddr_t arg);
900Sstevel@tonic-gate
910Sstevel@tonic-gate static struct vnex_pil_map vnex_name_to_pil[] = {
920Sstevel@tonic-gate {"console", PIL_12},
930Sstevel@tonic-gate {"fma", PIL_5},
940Sstevel@tonic-gate {"echo", PIL_3},
950Sstevel@tonic-gate {"loop", PIL_3},
960Sstevel@tonic-gate {"sunmc", PIL_3},
970Sstevel@tonic-gate {"sunvts", PIL_3},
981991Sheppo {"explorer", PIL_3},
993156Sgirish {"ncp", PIL_8},
1003156Sgirish {"crypto", PIL_8}
1010Sstevel@tonic-gate };
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate #define VNEX_MAX_DEVS (sizeof (vnex_name_to_pil) / \
1040Sstevel@tonic-gate sizeof (struct vnex_pil_map))
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate /*
1070Sstevel@tonic-gate * Config information
1080Sstevel@tonic-gate */
1090Sstevel@tonic-gate static int vnex_intr_ops(dev_info_t *dip, dev_info_t *rdip,
1100Sstevel@tonic-gate ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate static int
1130Sstevel@tonic-gate vnex_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *);
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate static struct bus_ops vnex_bus_ops = {
1160Sstevel@tonic-gate BUSO_REV,
1170Sstevel@tonic-gate nullbusmap,
1180Sstevel@tonic-gate NULL, /* NO OP */
1190Sstevel@tonic-gate NULL, /* NO OP */
1200Sstevel@tonic-gate NULL, /* NO OP */
1210Sstevel@tonic-gate i_ddi_map_fault,
1220Sstevel@tonic-gate ddi_no_dma_map,
1230Sstevel@tonic-gate ddi_no_dma_allochdl,
1240Sstevel@tonic-gate NULL,
1250Sstevel@tonic-gate NULL,
1260Sstevel@tonic-gate NULL,
1270Sstevel@tonic-gate NULL,
1280Sstevel@tonic-gate NULL,
1290Sstevel@tonic-gate NULL,
1300Sstevel@tonic-gate vnex_ctl,
1310Sstevel@tonic-gate ddi_bus_prop_op,
1320Sstevel@tonic-gate NULL, /* (*bus_get_eventcookie)(); */
1330Sstevel@tonic-gate NULL, /* (*bus_add_eventcall)(); */
1340Sstevel@tonic-gate NULL, /* (*bus_remove_eventcall)(); */
1350Sstevel@tonic-gate NULL, /* (*bus_post_event)(); */
1360Sstevel@tonic-gate NULL, /* (*bus_intr_ctl)(); */
1370Sstevel@tonic-gate NULL, /* (*bus_config)(); */
1380Sstevel@tonic-gate NULL, /* (*bus_unconfig)(); */
1390Sstevel@tonic-gate NULL, /* (*bus_fm_init)(); */
1400Sstevel@tonic-gate NULL, /* (*bus_fm_fini)(); */
1410Sstevel@tonic-gate NULL, /* (*bus_fm_access_enter)(); */
1420Sstevel@tonic-gate NULL, /* (*bus_fm_access_fini)(); */
1430Sstevel@tonic-gate NULL, /* (*bus_power)(); */
1440Sstevel@tonic-gate vnex_intr_ops /* (*bus_intr_op)(); */
1450Sstevel@tonic-gate };
1460Sstevel@tonic-gate
147444Sarao static int vnex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
148444Sarao static int vnex_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
1490Sstevel@tonic-gate
1500Sstevel@tonic-gate static struct dev_ops pseudo_ops = {
1510Sstevel@tonic-gate DEVO_REV, /* devo_rev, */
1520Sstevel@tonic-gate 0, /* refcnt */
1530Sstevel@tonic-gate ddi_no_info, /* info */
1540Sstevel@tonic-gate nulldev, /* identify */
1550Sstevel@tonic-gate nulldev, /* probe */
1560Sstevel@tonic-gate vnex_attach, /* attach */
1570Sstevel@tonic-gate vnex_detach, /* detach */
1580Sstevel@tonic-gate nodev, /* reset */
1590Sstevel@tonic-gate (struct cb_ops *)0, /* driver operations */
160*7656SSherry.Moore@Sun.COM &vnex_bus_ops, /* bus operations */
161*7656SSherry.Moore@Sun.COM nulldev, /* power */
162*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */
1630Sstevel@tonic-gate };
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate /*
1660Sstevel@tonic-gate * Module linkage information for the kernel.
1670Sstevel@tonic-gate */
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate static struct modldrv modldrv = {
1700Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */
171*7656SSherry.Moore@Sun.COM "sun4v virtual-devices nexus driver",
1720Sstevel@tonic-gate &pseudo_ops, /* driver ops */
1730Sstevel@tonic-gate };
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate static struct modlinkage modlinkage = {
1760Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL
1770Sstevel@tonic-gate };
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate int
_init(void)1800Sstevel@tonic-gate _init(void)
1810Sstevel@tonic-gate {
1824423Sjb145095 uint64_t mjrnum;
1834423Sjb145095 uint64_t mnrnum;
1844423Sjb145095
1854423Sjb145095 /*
1864423Sjb145095 * Check HV intr group api versioning.
1874423Sjb145095 * This driver uses the old interrupt routines which are supported
1884423Sjb145095 * in old firmware in the CORE API group and in newer firmware in
1894423Sjb145095 * the INTR API group. Support for these calls will be dropped
1904423Sjb145095 * once the INTR API group major goes to 2.
1914423Sjb145095 */
1924423Sjb145095
1934423Sjb145095 if ((hsvc_version(HSVC_GROUP_INTR, &mjrnum, &mnrnum) == 0) &&
1944423Sjb145095 (mjrnum > 1)) {
1954423Sjb145095 cmn_err(CE_WARN, "niumx: unsupported intr api group: "
1964423Sjb145095 "maj:0x%lx, min:0x%lx", mjrnum, mnrnum);
1974423Sjb145095 return (ENOTSUP);
1984423Sjb145095 }
1994423Sjb145095
2000Sstevel@tonic-gate return (mod_install(&modlinkage));
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate int
_fini(void)2040Sstevel@tonic-gate _fini(void)
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate return (mod_remove(&modlinkage));
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2100Sstevel@tonic-gate _info(struct modinfo *modinfop)
2110Sstevel@tonic-gate {
2120Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
2130Sstevel@tonic-gate }
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate /*ARGSUSED*/
216444Sarao void
vnex_intr_dist(void * arg)217444Sarao vnex_intr_dist(void *arg)
218444Sarao {
219444Sarao vnex_id_t *vid_p;
220444Sarao uint32_t cpuid;
221444Sarao int intr_state;
222444Sarao hrtime_t start;
223444Sarao
224444Sarao mutex_enter(&vnex_id_lock);
225444Sarao
226444Sarao for (vid_p = vnex_id_list; vid_p != NULL;
227444Sarao vid_p = vid_p->vid_next) {
228444Sarao /*
229444Sarao * Don't do anything for disabled interrupts.
230444Sarao * vnex_enable_intr takes care of redistributing interrupts.
231444Sarao */
232444Sarao if ((hvio_intr_getvalid(vid_p->vid_ihdl,
233444Sarao &intr_state) == H_EOK) && (intr_state == HV_INTR_NOTVALID))
234444Sarao continue;
235444Sarao
236444Sarao cpuid = intr_dist_cpuid();
237444Sarao
238444Sarao (void) hvio_intr_setvalid(vid_p->vid_ihdl, HV_INTR_NOTVALID);
239444Sarao /*
240444Sarao * Make a best effort to wait for pending interrupts to finish.
241444Sarao * There is not much we can do if we timeout.
242444Sarao */
243444Sarao start = gethrtime();
244444Sarao while (!panicstr &&
245444Sarao (hvio_intr_getstate(vid_p->vid_ihdl, &intr_state) ==
246444Sarao H_EOK) && (intr_state == HV_INTR_DELIVERED_STATE)) {
247444Sarao if (gethrtime() - start > vnex_pending_timeout) {
248444Sarao cmn_err(CE_WARN, "vnex_intr_dist: %s%d "
249444Sarao "ino 0x%x pending: timedout\n",
250444Sarao ddi_driver_name(vid_p->vid_dip),
251444Sarao ddi_get_instance(vid_p->vid_dip),
252444Sarao vid_p->vid_ino);
253444Sarao break;
254444Sarao }
255444Sarao }
256444Sarao (void) hvio_intr_settarget(vid_p->vid_ihdl, cpuid);
257444Sarao (void) hvio_intr_setvalid(vid_p->vid_ihdl, HV_INTR_VALID);
258444Sarao }
259444Sarao mutex_exit(&vnex_id_lock);
260444Sarao }
261444Sarao
2620Sstevel@tonic-gate static int
vnex_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)263444Sarao vnex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2640Sstevel@tonic-gate {
2650Sstevel@tonic-gate switch (cmd) {
2660Sstevel@tonic-gate case DDI_ATTACH:
2670Sstevel@tonic-gate /*
2680Sstevel@tonic-gate * Intitialize interrupt descriptor list
2690Sstevel@tonic-gate * and mutex.
2700Sstevel@tonic-gate */
2710Sstevel@tonic-gate vnex_id_list = NULL;
2720Sstevel@tonic-gate mutex_init(&vnex_id_lock, NULL, MUTEX_DRIVER, NULL);
273444Sarao /*
274444Sarao * Add interrupt redistribution callback.
275444Sarao */
276444Sarao intr_dist_add(vnex_intr_dist, dip);
2770Sstevel@tonic-gate return (DDI_SUCCESS);
2780Sstevel@tonic-gate
2790Sstevel@tonic-gate case DDI_RESUME:
2800Sstevel@tonic-gate return (DDI_SUCCESS);
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate default:
2830Sstevel@tonic-gate return (DDI_FAILURE);
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate
2870Sstevel@tonic-gate /*ARGSUSED*/
2880Sstevel@tonic-gate static int
vnex_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)289444Sarao vnex_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2900Sstevel@tonic-gate {
2910Sstevel@tonic-gate switch (cmd) {
2920Sstevel@tonic-gate case DDI_DETACH:
2930Sstevel@tonic-gate return (DDI_FAILURE);
2940Sstevel@tonic-gate
2950Sstevel@tonic-gate case DDI_SUSPEND:
2960Sstevel@tonic-gate return (DDI_SUCCESS);
2970Sstevel@tonic-gate
2980Sstevel@tonic-gate default:
2990Sstevel@tonic-gate return (DDI_FAILURE);
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate static int
vnex_ctl(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)3040Sstevel@tonic-gate vnex_ctl(dev_info_t *dip, dev_info_t *rdip,
3050Sstevel@tonic-gate ddi_ctl_enum_t ctlop, void *arg, void *result)
3060Sstevel@tonic-gate {
3070Sstevel@tonic-gate char name[12]; /* enough for a decimal integer */
3080Sstevel@tonic-gate int reglen;
3090Sstevel@tonic-gate uint32_t *vnex_regspec;
3100Sstevel@tonic-gate
3110Sstevel@tonic-gate switch (ctlop) {
3120Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV:
3130Sstevel@tonic-gate if (rdip == NULL)
3140Sstevel@tonic-gate return (DDI_FAILURE);
3150Sstevel@tonic-gate cmn_err(CE_CONT, "?virtual-device: %s%d\n",
3160Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip));
3170Sstevel@tonic-gate return (DDI_SUCCESS);
3180Sstevel@tonic-gate
3190Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD:
3200Sstevel@tonic-gate {
3210Sstevel@tonic-gate dev_info_t *child = (dev_info_t *)arg;
3220Sstevel@tonic-gate
323506Scth if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
3240Sstevel@tonic-gate "reg", (caddr_t)&vnex_regspec, ®len) != DDI_SUCCESS)
3250Sstevel@tonic-gate return (DDI_FAILURE);
3260Sstevel@tonic-gate
3270Sstevel@tonic-gate (void) sprintf(name, "%x", *vnex_regspec);
3280Sstevel@tonic-gate ddi_set_name_addr(child, name);
3290Sstevel@tonic-gate ddi_set_parent_data(child, NULL);
3300Sstevel@tonic-gate kmem_free((caddr_t)vnex_regspec, reglen);
3310Sstevel@tonic-gate return (DDI_SUCCESS);
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD:
3360Sstevel@tonic-gate {
3370Sstevel@tonic-gate dev_info_t *child = (dev_info_t *)arg;
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate ddi_set_name_addr(child, NULL);
3400Sstevel@tonic-gate ddi_remove_minor_node(arg, NULL);
3410Sstevel@tonic-gate return (DDI_SUCCESS);
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate /*
3450Sstevel@tonic-gate * These ops correspond to functions that "shouldn't" be called
3460Sstevel@tonic-gate * by a pseudo driver. So we whinge when we're called.
3470Sstevel@tonic-gate */
3480Sstevel@tonic-gate case DDI_CTLOPS_DMAPMAPC:
3490Sstevel@tonic-gate case DDI_CTLOPS_REPORTINT:
3500Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE:
3510Sstevel@tonic-gate {
3520Sstevel@tonic-gate *((off_t *)result) = 0;
3530Sstevel@tonic-gate return (DDI_SUCCESS);
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate case DDI_CTLOPS_NREGS:
3560Sstevel@tonic-gate {
3576105Skc28005 dev_info_t *child = rdip;
358506Scth if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
3590Sstevel@tonic-gate "reg", (caddr_t)&vnex_regspec, ®len) != DDI_SUCCESS)
3600Sstevel@tonic-gate return (DDI_FAILURE);
3610Sstevel@tonic-gate *((uint_t *)result) = reglen / sizeof (uint32_t);
3620Sstevel@tonic-gate kmem_free((caddr_t)vnex_regspec, reglen);
3630Sstevel@tonic-gate return (DDI_SUCCESS);
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate case DDI_CTLOPS_SIDDEV:
3660Sstevel@tonic-gate case DDI_CTLOPS_SLAVEONLY:
3670Sstevel@tonic-gate case DDI_CTLOPS_AFFINITY:
3680Sstevel@tonic-gate case DDI_CTLOPS_IOMIN:
3690Sstevel@tonic-gate case DDI_CTLOPS_POKE:
3700Sstevel@tonic-gate case DDI_CTLOPS_PEEK:
3710Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n",
3726105Skc28005 ddi_get_name(dip), ddi_get_instance(dip),
3736105Skc28005 ctlop, ddi_get_name(rdip), ddi_get_instance(rdip));
3740Sstevel@tonic-gate return (DDI_FAILURE);
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate /*
3770Sstevel@tonic-gate * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
3780Sstevel@tonic-gate */
3790Sstevel@tonic-gate default:
3800Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, ctlop, arg, result));
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate }
3830Sstevel@tonic-gate
3840Sstevel@tonic-gate static int
vnex_get_pil(dev_info_t * rdip)3850Sstevel@tonic-gate vnex_get_pil(dev_info_t *rdip)
3860Sstevel@tonic-gate {
3870Sstevel@tonic-gate int i;
3880Sstevel@tonic-gate caddr_t name;
3890Sstevel@tonic-gate
3900Sstevel@tonic-gate name = ddi_node_name(rdip);
3910Sstevel@tonic-gate for (i = 0; i < VNEX_MAX_DEVS; i++) {
3920Sstevel@tonic-gate if (strcmp(vnex_name_to_pil[i].name,
3930Sstevel@tonic-gate name) == 0) {
3940Sstevel@tonic-gate return (vnex_name_to_pil[i].pil);
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate }
3970Sstevel@tonic-gate /*
3980Sstevel@tonic-gate * if not found pil is 0
3990Sstevel@tonic-gate */
4000Sstevel@tonic-gate return (0);
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate
4030Sstevel@tonic-gate static int
vnex_enable_intr(dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)4040Sstevel@tonic-gate vnex_enable_intr(dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp)
4050Sstevel@tonic-gate {
4060Sstevel@tonic-gate vnex_id_t *vid_p;
4070Sstevel@tonic-gate uint32_t cpuid;
4080Sstevel@tonic-gate
4090Sstevel@tonic-gate vid_p = vnex_locate_id(rdip, hdlp->ih_vector);
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate ASSERT(vid_p != NULL);
4120Sstevel@tonic-gate
4130Sstevel@tonic-gate cpuid = intr_dist_cpuid();
4140Sstevel@tonic-gate
4150Sstevel@tonic-gate if ((hvio_intr_settarget(vid_p->vid_ihdl, cpuid)) != H_EOK) {
4160Sstevel@tonic-gate return (DDI_FAILURE);
4170Sstevel@tonic-gate }
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate if (hvio_intr_setstate(vid_p->vid_ihdl, HV_INTR_IDLE_STATE) != H_EOK) {
4200Sstevel@tonic-gate return (DDI_FAILURE);
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate
4230Sstevel@tonic-gate if ((hvio_intr_setvalid(vid_p->vid_ihdl, HV_INTR_VALID)) != H_EOK) {
4240Sstevel@tonic-gate return (DDI_FAILURE);
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate return (DDI_SUCCESS);
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate
4300Sstevel@tonic-gate static int
vnex_disable_intr(dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)4310Sstevel@tonic-gate vnex_disable_intr(dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp)
4320Sstevel@tonic-gate {
4330Sstevel@tonic-gate vnex_id_t *vid_p;
4340Sstevel@tonic-gate
4350Sstevel@tonic-gate vid_p = vnex_locate_id(rdip, hdlp->ih_vector);
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate ASSERT(vid_p != NULL);
4380Sstevel@tonic-gate
4390Sstevel@tonic-gate if (hvio_intr_setvalid(vid_p->vid_ihdl, HV_INTR_NOTVALID) != H_EOK) {
4400Sstevel@tonic-gate return (DDI_FAILURE);
4410Sstevel@tonic-gate }
4420Sstevel@tonic-gate
4430Sstevel@tonic-gate return (DDI_SUCCESS);
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate
4461991Sheppo int
vnex_ino_to_inum(dev_info_t * dip,uint32_t ino)4471991Sheppo vnex_ino_to_inum(dev_info_t *dip, uint32_t ino)
4481991Sheppo {
4491991Sheppo vnex_id_t *vid_p;
4501991Sheppo ddi_intr_handle_impl_t *hdlp;
4511991Sheppo
4521991Sheppo if ((vid_p = vnex_locate_id(dip, ino)) == NULL)
4531991Sheppo return (-1);
4541991Sheppo else if ((hdlp = vid_p->vid_ddi_hdlp) == NULL)
4551991Sheppo return (-1);
4561991Sheppo else
4571991Sheppo return (hdlp->ih_inum);
4581991Sheppo }
4591991Sheppo
4600Sstevel@tonic-gate static int
vnex_add_intr(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)4610Sstevel@tonic-gate vnex_add_intr(dev_info_t *dip, dev_info_t *rdip,
4620Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp)
4630Sstevel@tonic-gate {
4640Sstevel@tonic-gate int reglen, ret = DDI_SUCCESS;
4650Sstevel@tonic-gate vnex_id_t *vid_p;
4660Sstevel@tonic-gate uint64_t cfg;
4670Sstevel@tonic-gate uint32_t ino;
4680Sstevel@tonic-gate uint64_t ihdl;
4690Sstevel@tonic-gate vnex_regspec_t *reg_p;
4700Sstevel@tonic-gate
471506Scth if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
4720Sstevel@tonic-gate DDI_PROP_DONTPASS, "reg", (caddr_t)®_p,
4730Sstevel@tonic-gate ®len) != DDI_SUCCESS) {
4740Sstevel@tonic-gate return (DDI_FAILURE);
4750Sstevel@tonic-gate }
4760Sstevel@tonic-gate
4770Sstevel@tonic-gate /*
4780Sstevel@tonic-gate * get the sun4v config handle for this device
4790Sstevel@tonic-gate */
4800Sstevel@tonic-gate
4810Sstevel@tonic-gate cfg = SUN4V_REG_SPEC2CFG_HDL(reg_p->physaddr);
482288Sarao kmem_free(reg_p, reglen);
4830Sstevel@tonic-gate ino = hdlp->ih_vector;
4840Sstevel@tonic-gate
4850Sstevel@tonic-gate /*
4860Sstevel@tonic-gate * call hv to get vihdl
4870Sstevel@tonic-gate */
4880Sstevel@tonic-gate if (hvio_intr_devino_to_sysino(cfg, ino, &ihdl) != H_EOK)
4890Sstevel@tonic-gate return (DDI_FAILURE);
4900Sstevel@tonic-gate
4910Sstevel@tonic-gate hdlp->ih_vector = ihdl;
4920Sstevel@tonic-gate /*
4930Sstevel@tonic-gate * Allocate a interrupt descriptor (id) with the
4940Sstevel@tonic-gate * the interrupt handler and append it to
4950Sstevel@tonic-gate * the id list.
4960Sstevel@tonic-gate */
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate vid_p = vnex_alloc_id(rdip, ino, cfg);
4990Sstevel@tonic-gate vid_p->vid_ihdl = ihdl;
5000Sstevel@tonic-gate vid_p->vid_handler = hdlp->ih_cb_func;
5010Sstevel@tonic-gate vid_p->vid_arg1 = hdlp->ih_cb_arg1;
5020Sstevel@tonic-gate vid_p->vid_arg2 = hdlp->ih_cb_arg2;
5030Sstevel@tonic-gate vid_p->vid_ddi_hdlp = hdlp;
5040Sstevel@tonic-gate
5050Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp,
5060Sstevel@tonic-gate (ddi_intr_handler_t *)vnex_intr_wrapper, (caddr_t)vid_p, NULL);
5070Sstevel@tonic-gate
5080Sstevel@tonic-gate if (hdlp->ih_pri == 0) {
5090Sstevel@tonic-gate hdlp->ih_pri = vnex_get_pil(rdip);
5100Sstevel@tonic-gate }
5110Sstevel@tonic-gate
5120Sstevel@tonic-gate ret = i_ddi_add_ivintr(hdlp);
5130Sstevel@tonic-gate if (ret != DDI_SUCCESS) {
5140Sstevel@tonic-gate return (ret);
5150Sstevel@tonic-gate }
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, vid_p->vid_handler,
5180Sstevel@tonic-gate vid_p->vid_arg1, vid_p->vid_arg2);
5190Sstevel@tonic-gate
5200Sstevel@tonic-gate return (ret);
5210Sstevel@tonic-gate }
5220Sstevel@tonic-gate
5230Sstevel@tonic-gate static int
vnex_remove_intr(dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)5240Sstevel@tonic-gate vnex_remove_intr(dev_info_t *rdip,
5250Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp)
5260Sstevel@tonic-gate {
5270Sstevel@tonic-gate vnex_id_t *vid_p;
5280Sstevel@tonic-gate uint32_t ino;
5290Sstevel@tonic-gate int ret = DDI_SUCCESS;
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate ino = hdlp->ih_vector;
5320Sstevel@tonic-gate vid_p = vnex_locate_id(rdip, ino);
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate hdlp->ih_vector = vid_p->vid_ihdl;
5350Sstevel@tonic-gate i_ddi_rem_ivintr(hdlp);
5360Sstevel@tonic-gate
5370Sstevel@tonic-gate vnex_free_id(vid_p);
5380Sstevel@tonic-gate
5390Sstevel@tonic-gate return (ret);
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate
5420Sstevel@tonic-gate static int
vnex_intr_ops(dev_info_t * dip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)5430Sstevel@tonic-gate vnex_intr_ops(dev_info_t *dip, dev_info_t *rdip,
5440Sstevel@tonic-gate ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result)
5450Sstevel@tonic-gate {
546693Sgovinda int ret = DDI_SUCCESS;
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate switch (intr_op) {
5490Sstevel@tonic-gate case DDI_INTROP_GETCAP:
550693Sgovinda *(int *)result = DDI_INTR_FLAG_LEVEL;
5510Sstevel@tonic-gate break;
5520Sstevel@tonic-gate case DDI_INTROP_ALLOC:
5530Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1;
5540Sstevel@tonic-gate break;
5550Sstevel@tonic-gate case DDI_INTROP_GETPRI:
556693Sgovinda *(int *)result = hdlp->ih_pri ?
557693Sgovinda hdlp->ih_pri : vnex_get_pil(rdip);
5580Sstevel@tonic-gate break;
5590Sstevel@tonic-gate case DDI_INTROP_FREE:
5600Sstevel@tonic-gate break;
5610Sstevel@tonic-gate case DDI_INTROP_SETPRI:
5620Sstevel@tonic-gate break;
5630Sstevel@tonic-gate case DDI_INTROP_ADDISR:
5640Sstevel@tonic-gate ret = vnex_add_intr(dip, rdip, hdlp);
5650Sstevel@tonic-gate break;
5660Sstevel@tonic-gate case DDI_INTROP_REMISR:
5670Sstevel@tonic-gate ret = vnex_remove_intr(rdip, hdlp);
5680Sstevel@tonic-gate break;
5690Sstevel@tonic-gate case DDI_INTROP_ENABLE:
5700Sstevel@tonic-gate ret = vnex_enable_intr(rdip, hdlp);
5710Sstevel@tonic-gate break;
5720Sstevel@tonic-gate case DDI_INTROP_DISABLE:
5730Sstevel@tonic-gate ret = vnex_disable_intr(rdip, hdlp);
5740Sstevel@tonic-gate break;
5750Sstevel@tonic-gate case DDI_INTROP_NINTRS:
5760Sstevel@tonic-gate case DDI_INTROP_NAVAIL:
5772580Sanish *(int *)result = i_ddi_get_intx_nintrs(rdip);
5780Sstevel@tonic-gate break;
5790Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES:
5802580Sanish *(int *)result = i_ddi_get_intx_nintrs(rdip) ?
5810Sstevel@tonic-gate DDI_INTR_TYPE_FIXED : 0;
5820Sstevel@tonic-gate break;
5830Sstevel@tonic-gate default:
5840Sstevel@tonic-gate ret = DDI_ENOTSUP;
5850Sstevel@tonic-gate break;
5860Sstevel@tonic-gate }
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate return (ret);
5890Sstevel@tonic-gate }
5900Sstevel@tonic-gate
5910Sstevel@tonic-gate vnex_id_t *
vnex_alloc_id(dev_info_t * dip,uint32_t ino,uint64_t dhdl)5920Sstevel@tonic-gate vnex_alloc_id(dev_info_t *dip, uint32_t ino, uint64_t dhdl)
5930Sstevel@tonic-gate {
5940Sstevel@tonic-gate vnex_id_t *vid_p = kmem_alloc(sizeof (vnex_id_t), KM_SLEEP);
5950Sstevel@tonic-gate
5960Sstevel@tonic-gate vid_p->vid_dip = dip;
5970Sstevel@tonic-gate vid_p->vid_ino = ino;
5980Sstevel@tonic-gate vid_p->vid_cfg_hdl = dhdl;
5990Sstevel@tonic-gate
6000Sstevel@tonic-gate mutex_enter(&vnex_id_lock);
6010Sstevel@tonic-gate vnex_add_id(vid_p);
6020Sstevel@tonic-gate mutex_exit(&vnex_id_lock);
6030Sstevel@tonic-gate
6040Sstevel@tonic-gate return (vid_p);
6050Sstevel@tonic-gate }
6060Sstevel@tonic-gate
6070Sstevel@tonic-gate vnex_id_t *
vnex_locate_id(dev_info_t * dip,uint32_t ino)6080Sstevel@tonic-gate vnex_locate_id(dev_info_t *dip, uint32_t ino)
6090Sstevel@tonic-gate {
6100Sstevel@tonic-gate vnex_id_t *vid_p;
6110Sstevel@tonic-gate
6120Sstevel@tonic-gate mutex_enter(&vnex_id_lock);
6130Sstevel@tonic-gate vid_p = vnex_id_list;
6140Sstevel@tonic-gate
6150Sstevel@tonic-gate while (vid_p != NULL) {
6160Sstevel@tonic-gate if (vid_p->vid_dip == dip && vid_p->vid_ino == ino) {
6170Sstevel@tonic-gate mutex_exit(&vnex_id_lock);
6180Sstevel@tonic-gate return (vid_p);
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate vid_p = vid_p->vid_next;
6210Sstevel@tonic-gate }
6220Sstevel@tonic-gate mutex_exit(&vnex_id_lock);
6230Sstevel@tonic-gate return (NULL);
6240Sstevel@tonic-gate }
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate static void
vnex_free_id(vnex_id_t * vid_p)6270Sstevel@tonic-gate vnex_free_id(vnex_id_t *vid_p)
6280Sstevel@tonic-gate {
6290Sstevel@tonic-gate mutex_enter(&vnex_id_lock);
6300Sstevel@tonic-gate vnex_rem_id(vid_p);
6310Sstevel@tonic-gate mutex_exit(&vnex_id_lock);
6320Sstevel@tonic-gate
6330Sstevel@tonic-gate kmem_free(vid_p, sizeof (*vid_p));
6340Sstevel@tonic-gate }
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate static void
vnex_rem_id(vnex_id_t * vid_p)6370Sstevel@tonic-gate vnex_rem_id(vnex_id_t *vid_p)
6380Sstevel@tonic-gate {
6391276Smf13430 vnex_id_t *prev_p = vnex_id_list;
6401276Smf13430
6411276Smf13430 if (vnex_id_list == NULL)
6421276Smf13430 cmn_err(CE_PANIC, "vnex: interrupt list empty");
6431276Smf13430
6441276Smf13430 if (vid_p == NULL)
6451276Smf13430 cmn_err(CE_PANIC, "vnex: no element to remove");
6461276Smf13430
6471276Smf13430 if (vnex_id_list == vid_p) {
6480Sstevel@tonic-gate vnex_id_list = vid_p->vid_next;
6490Sstevel@tonic-gate } else {
6501276Smf13430 while (prev_p != NULL && prev_p->vid_next != vid_p)
6511276Smf13430 prev_p = prev_p->vid_next;
6521276Smf13430
6531276Smf13430 if (prev_p == NULL)
6541276Smf13430 cmn_err(CE_PANIC, "vnex: element %p not in list",
6551276Smf13430 (void *) vid_p);
6561276Smf13430
6571276Smf13430 prev_p->vid_next = vid_p->vid_next;
6580Sstevel@tonic-gate }
6590Sstevel@tonic-gate }
6600Sstevel@tonic-gate
6610Sstevel@tonic-gate static void
vnex_add_id(vnex_id_t * vid_p)6620Sstevel@tonic-gate vnex_add_id(vnex_id_t *vid_p)
6630Sstevel@tonic-gate {
6640Sstevel@tonic-gate vid_p->vid_next = vnex_id_list;
6650Sstevel@tonic-gate vnex_id_list = vid_p;
6660Sstevel@tonic-gate }
6670Sstevel@tonic-gate
6680Sstevel@tonic-gate uint_t
vnex_intr_wrapper(caddr_t arg)6690Sstevel@tonic-gate vnex_intr_wrapper(caddr_t arg)
6700Sstevel@tonic-gate {
6710Sstevel@tonic-gate vnex_id_t *vid_p = (vnex_id_t *)arg;
6720Sstevel@tonic-gate int res;
6730Sstevel@tonic-gate uint_t (*handler)();
6740Sstevel@tonic-gate caddr_t handler_arg1;
6750Sstevel@tonic-gate caddr_t handler_arg2;
6760Sstevel@tonic-gate
6770Sstevel@tonic-gate handler = vid_p->vid_handler;
6780Sstevel@tonic-gate handler_arg1 = vid_p->vid_arg1;
6790Sstevel@tonic-gate handler_arg2 = vid_p->vid_arg2;
6800Sstevel@tonic-gate
6810Sstevel@tonic-gate res = (*handler)(handler_arg1, handler_arg2);
6820Sstevel@tonic-gate
6830Sstevel@tonic-gate (void) hvio_intr_setstate(vid_p->vid_ihdl, HV_INTR_IDLE_STATE);
6840Sstevel@tonic-gate
6850Sstevel@tonic-gate return (res);
6860Sstevel@tonic-gate }
687