1500b1e78SAlan Adamson, SD OSSD /*
2500b1e78SAlan Adamson, SD OSSD  * CDDL HEADER START
3500b1e78SAlan Adamson, SD OSSD  *
4500b1e78SAlan Adamson, SD OSSD  * The contents of this file are subject to the terms of the
5500b1e78SAlan Adamson, SD OSSD  * Common Development and Distribution License (the "License").
6500b1e78SAlan Adamson, SD OSSD  * You may not use this file except in compliance with the License.
7500b1e78SAlan Adamson, SD OSSD  *
8500b1e78SAlan Adamson, SD OSSD  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9500b1e78SAlan Adamson, SD OSSD  * or http://www.opensolaris.org/os/licensing.
10500b1e78SAlan Adamson, SD OSSD  * See the License for the specific language governing permissions
11500b1e78SAlan Adamson, SD OSSD  * and limitations under the License.
12500b1e78SAlan Adamson, SD OSSD  *
13500b1e78SAlan Adamson, SD OSSD  * When distributing Covered Code, include this CDDL HEADER in each
14500b1e78SAlan Adamson, SD OSSD  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15500b1e78SAlan Adamson, SD OSSD  * If applicable, add the following below this CDDL HEADER, with the
16500b1e78SAlan Adamson, SD OSSD  * fields enclosed by brackets "[]" replaced with your own identifying
17500b1e78SAlan Adamson, SD OSSD  * information: Portions Copyright [yyyy] [name of copyright owner]
18500b1e78SAlan Adamson, SD OSSD  *
19500b1e78SAlan Adamson, SD OSSD  * CDDL HEADER END
20500b1e78SAlan Adamson, SD OSSD  */
21500b1e78SAlan Adamson, SD OSSD /*
22500b1e78SAlan Adamson, SD OSSD  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23500b1e78SAlan Adamson, SD OSSD  * Use is subject to license terms.
24500b1e78SAlan Adamson, SD OSSD  */
25500b1e78SAlan Adamson, SD OSSD 
26500b1e78SAlan Adamson, SD OSSD #include <sys/types.h>
27500b1e78SAlan Adamson, SD OSSD #include <sys/stat.h>
28500b1e78SAlan Adamson, SD OSSD #include <sys/cpuvar.h>
29500b1e78SAlan Adamson, SD OSSD #include <sys/conf.h>
30500b1e78SAlan Adamson, SD OSSD #include <sys/kmem.h>
31500b1e78SAlan Adamson, SD OSSD #include <sys/async.h>
32500b1e78SAlan Adamson, SD OSSD #include <sys/sysmacros.h>
33500b1e78SAlan Adamson, SD OSSD #include <sys/sunddi.h>
34500b1e78SAlan Adamson, SD OSSD #include <sys/sunndi.h>
35500b1e78SAlan Adamson, SD OSSD #include <sys/ddi_impldefs.h>
36500b1e78SAlan Adamson, SD OSSD #include <sys/open.h>
37500b1e78SAlan Adamson, SD OSSD #include <sys/errno.h>
38500b1e78SAlan Adamson, SD OSSD #include <sys/file.h>
39500b1e78SAlan Adamson, SD OSSD #include <sys/policy.h>
40500b1e78SAlan Adamson, SD OSSD #include <sys/pci_tools.h>
41500b1e78SAlan Adamson, SD OSSD #include <sys/pci_impl.h>
42500b1e78SAlan Adamson, SD OSSD #include <sys/hypervisor_api.h>
43500b1e78SAlan Adamson, SD OSSD #include <sys/hotplug/pci/pcihp.h>
44500b1e78SAlan Adamson, SD OSSD #include "niumx_var.h"
45500b1e78SAlan Adamson, SD OSSD 
46500b1e78SAlan Adamson, SD OSSD /*
47500b1e78SAlan Adamson, SD OSSD  * NIUMX PCITool interface
48500b1e78SAlan Adamson, SD OSSD  */
49500b1e78SAlan Adamson, SD OSSD /*LINTLIBRARY*/
50500b1e78SAlan Adamson, SD OSSD 
51500b1e78SAlan Adamson, SD OSSD static int niumx_open(dev_t *devp, int flags, int otyp, cred_t *credp);
52500b1e78SAlan Adamson, SD OSSD static int niumx_close(dev_t dev, int flags, int otyp, cred_t *credp);
53500b1e78SAlan Adamson, SD OSSD static int niumx_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
54500b1e78SAlan Adamson, SD OSSD 						cred_t *credp, int *rvalp);
55500b1e78SAlan Adamson, SD OSSD static int niumx_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
56500b1e78SAlan Adamson, SD OSSD     int flags, char *name, caddr_t valuep, int *lengthp);
57500b1e78SAlan Adamson, SD OSSD 
58500b1e78SAlan Adamson, SD OSSD struct cb_ops niumx_cb_ops = {
59500b1e78SAlan Adamson, SD OSSD 	niumx_open,			/* open */
60500b1e78SAlan Adamson, SD OSSD 	niumx_close,			/* close */
61500b1e78SAlan Adamson, SD OSSD 	nodev,				/* strategy */
62500b1e78SAlan Adamson, SD OSSD 	nodev,				/* print */
63500b1e78SAlan Adamson, SD OSSD 	nodev,				/* dump */
64500b1e78SAlan Adamson, SD OSSD 	nodev,				/* read */
65500b1e78SAlan Adamson, SD OSSD 	nodev,				/* write */
66500b1e78SAlan Adamson, SD OSSD 	niumx_ioctl,			/* ioctl */
67500b1e78SAlan Adamson, SD OSSD 	nodev,				/* devmap */
68500b1e78SAlan Adamson, SD OSSD 	nodev,				/* mmap */
69500b1e78SAlan Adamson, SD OSSD 	nodev,				/* segmap */
70500b1e78SAlan Adamson, SD OSSD 	nochpoll,			/* poll */
71500b1e78SAlan Adamson, SD OSSD 	niumx_prop_op,			/* cb_prop_op */
72500b1e78SAlan Adamson, SD OSSD 	NULL,				/* streamtab */
73500b1e78SAlan Adamson, SD OSSD 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
74500b1e78SAlan Adamson, SD OSSD 	CB_REV,				/* rev */
75500b1e78SAlan Adamson, SD OSSD 	nodev,				/* int (*cb_aread)() */
76500b1e78SAlan Adamson, SD OSSD 	nodev				/* int (*cb_awrite)() */
77500b1e78SAlan Adamson, SD OSSD };
78500b1e78SAlan Adamson, SD OSSD 
79500b1e78SAlan Adamson, SD OSSD static void niumxtool_fill_in_intr_devs(pcitool_intr_dev_t *dev,
80500b1e78SAlan Adamson, SD OSSD     char *driver_name, char *path_name, int instance);
81500b1e78SAlan Adamson, SD OSSD 
82500b1e78SAlan Adamson, SD OSSD static int niumxtool_intr(dev_info_t *dip, void *arg, int cmd, int mode);
83500b1e78SAlan Adamson, SD OSSD 
84500b1e78SAlan Adamson, SD OSSD int niumx_set_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino,
85500b1e78SAlan Adamson, SD OSSD     niucpuid_t cpu_id);
86500b1e78SAlan Adamson, SD OSSD 
87500b1e78SAlan Adamson, SD OSSD extern void *niumx_state;
88500b1e78SAlan Adamson, SD OSSD /* ARGSUSED3 */
89500b1e78SAlan Adamson, SD OSSD static int
niumx_open(dev_t * devp,int flags,int otyp,cred_t * credp)90500b1e78SAlan Adamson, SD OSSD niumx_open(dev_t *devp, int flags, int otyp, cred_t *credp)
91500b1e78SAlan Adamson, SD OSSD {
92500b1e78SAlan Adamson, SD OSSD 	niumx_devstate_t *niumxds_p;
93500b1e78SAlan Adamson, SD OSSD 	minor_t minor = getminor(*devp);
94500b1e78SAlan Adamson, SD OSSD 
95500b1e78SAlan Adamson, SD OSSD 	/*
96500b1e78SAlan Adamson, SD OSSD 	 * Make sure the open is for the right file type.
97500b1e78SAlan Adamson, SD OSSD 	 */
98500b1e78SAlan Adamson, SD OSSD 	if (otyp != OTYP_CHR)
99500b1e78SAlan Adamson, SD OSSD 		return (EINVAL);
100500b1e78SAlan Adamson, SD OSSD 
101500b1e78SAlan Adamson, SD OSSD 	/*
102500b1e78SAlan Adamson, SD OSSD 	 * Get the soft state structure for the device.
103500b1e78SAlan Adamson, SD OSSD 	 */
104500b1e78SAlan Adamson, SD OSSD 	niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
105500b1e78SAlan Adamson, SD OSSD 	    PCI_MINOR_NUM_TO_INSTANCE(minor));
106500b1e78SAlan Adamson, SD OSSD 	if (niumxds_p == NULL)
107500b1e78SAlan Adamson, SD OSSD 		return (ENXIO);
108500b1e78SAlan Adamson, SD OSSD 
109500b1e78SAlan Adamson, SD OSSD 	/*
110500b1e78SAlan Adamson, SD OSSD 	 * Handle the open by tracking the device state.
111500b1e78SAlan Adamson, SD OSSD 	 */
112500b1e78SAlan Adamson, SD OSSD 	mutex_enter(&niumxds_p->niumx_mutex);
113500b1e78SAlan Adamson, SD OSSD 	if (flags & FEXCL) {
114500b1e78SAlan Adamson, SD OSSD 		if (niumxds_p->niumx_soft_state != NIUMX_SOFT_STATE_CLOSED) {
115500b1e78SAlan Adamson, SD OSSD 			mutex_exit(&niumxds_p->niumx_mutex);
116500b1e78SAlan Adamson, SD OSSD 			return (EBUSY);
117500b1e78SAlan Adamson, SD OSSD 		}
118500b1e78SAlan Adamson, SD OSSD 		niumxds_p->niumx_soft_state = NIUMX_SOFT_STATE_OPEN_EXCL;
119500b1e78SAlan Adamson, SD OSSD 	} else {
120500b1e78SAlan Adamson, SD OSSD 		if (niumxds_p->niumx_soft_state == NIUMX_SOFT_STATE_OPEN_EXCL) {
121500b1e78SAlan Adamson, SD OSSD 			mutex_exit(&niumxds_p->niumx_mutex);
122500b1e78SAlan Adamson, SD OSSD 			return (EBUSY);
123500b1e78SAlan Adamson, SD OSSD 		}
124500b1e78SAlan Adamson, SD OSSD 		niumxds_p->niumx_soft_state = NIUMX_SOFT_STATE_OPEN;
125500b1e78SAlan Adamson, SD OSSD 	}
126500b1e78SAlan Adamson, SD OSSD 
127500b1e78SAlan Adamson, SD OSSD 	niumxds_p->niumx_open_count++;
128500b1e78SAlan Adamson, SD OSSD 	mutex_exit(&niumxds_p->niumx_mutex);
129500b1e78SAlan Adamson, SD OSSD 	return (0);
130500b1e78SAlan Adamson, SD OSSD }
131500b1e78SAlan Adamson, SD OSSD 
132500b1e78SAlan Adamson, SD OSSD /* ARGSUSED */
133500b1e78SAlan Adamson, SD OSSD static int
niumx_close(dev_t dev,int flags,int otyp,cred_t * credp)134500b1e78SAlan Adamson, SD OSSD niumx_close(dev_t dev, int flags, int otyp, cred_t *credp)
135500b1e78SAlan Adamson, SD OSSD {
136500b1e78SAlan Adamson, SD OSSD 	niumx_devstate_t *niumxds_p;
137500b1e78SAlan Adamson, SD OSSD 	minor_t minor = getminor(dev);
138500b1e78SAlan Adamson, SD OSSD 
139500b1e78SAlan Adamson, SD OSSD 	if (otyp != OTYP_CHR)
140500b1e78SAlan Adamson, SD OSSD 		return (EINVAL);
141500b1e78SAlan Adamson, SD OSSD 
142500b1e78SAlan Adamson, SD OSSD 	/*
143500b1e78SAlan Adamson, SD OSSD 	 * Get the soft state structure for the device.
144500b1e78SAlan Adamson, SD OSSD 	 */
145500b1e78SAlan Adamson, SD OSSD 	niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
146500b1e78SAlan Adamson, SD OSSD 	    PCI_MINOR_NUM_TO_INSTANCE(minor));
147500b1e78SAlan Adamson, SD OSSD 
148500b1e78SAlan Adamson, SD OSSD 	if (niumxds_p == NULL)
149500b1e78SAlan Adamson, SD OSSD 		return (ENXIO);
150500b1e78SAlan Adamson, SD OSSD 
151500b1e78SAlan Adamson, SD OSSD 	mutex_enter(&niumxds_p->niumx_mutex);
152500b1e78SAlan Adamson, SD OSSD 
153500b1e78SAlan Adamson, SD OSSD 	niumxds_p->niumx_soft_state = NIUMX_SOFT_STATE_CLOSED;
154500b1e78SAlan Adamson, SD OSSD 	niumxds_p->niumx_open_count = 0;
155500b1e78SAlan Adamson, SD OSSD 	mutex_exit(&niumxds_p->niumx_mutex);
156500b1e78SAlan Adamson, SD OSSD 	return (0);
157500b1e78SAlan Adamson, SD OSSD }
158500b1e78SAlan Adamson, SD OSSD 
159500b1e78SAlan Adamson, SD OSSD /* ARGSUSED */
160500b1e78SAlan Adamson, SD OSSD int
niumx_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)161500b1e78SAlan Adamson, SD OSSD niumx_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
162500b1e78SAlan Adamson, SD OSSD 	int *rvalp)
163500b1e78SAlan Adamson, SD OSSD {
164500b1e78SAlan Adamson, SD OSSD 	niumx_devstate_t *niumxds_p;
165500b1e78SAlan Adamson, SD OSSD 	dev_info_t *dip;
166500b1e78SAlan Adamson, SD OSSD 	int rv = DDI_SUCCESS;
167500b1e78SAlan Adamson, SD OSSD 	int minor = getminor(dev);
168500b1e78SAlan Adamson, SD OSSD 
169500b1e78SAlan Adamson, SD OSSD 	/*
170500b1e78SAlan Adamson, SD OSSD 	 * Get the soft state structure for the device.
171500b1e78SAlan Adamson, SD OSSD 	 */
172500b1e78SAlan Adamson, SD OSSD 	niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
173500b1e78SAlan Adamson, SD OSSD 	    PCI_MINOR_NUM_TO_INSTANCE(minor));
174500b1e78SAlan Adamson, SD OSSD 
175500b1e78SAlan Adamson, SD OSSD 	if (niumxds_p == NULL) {
176500b1e78SAlan Adamson, SD OSSD 		return (ENXIO);
177500b1e78SAlan Adamson, SD OSSD 	}
178500b1e78SAlan Adamson, SD OSSD 
179500b1e78SAlan Adamson, SD OSSD 	dip = niumxds_p->dip;
180500b1e78SAlan Adamson, SD OSSD 
181500b1e78SAlan Adamson, SD OSSD 	switch (minor & 0xff) {
182500b1e78SAlan Adamson, SD OSSD 
183500b1e78SAlan Adamson, SD OSSD 	/*
184500b1e78SAlan Adamson, SD OSSD 	 * PCI tools.
185500b1e78SAlan Adamson, SD OSSD 	 */
186500b1e78SAlan Adamson, SD OSSD 
187500b1e78SAlan Adamson, SD OSSD 	case PCI_TOOL_INTR_MINOR_NUM:
188500b1e78SAlan Adamson, SD OSSD 
189500b1e78SAlan Adamson, SD OSSD 		switch (cmd) {
190500b1e78SAlan Adamson, SD OSSD 		case PCITOOL_DEVICE_SET_INTR:
191500b1e78SAlan Adamson, SD OSSD 
192500b1e78SAlan Adamson, SD OSSD 			/* Require full privileges. */
193500b1e78SAlan Adamson, SD OSSD 			if (secpolicy_kmdb(credp)) {
194500b1e78SAlan Adamson, SD OSSD 				rv = EPERM;
195500b1e78SAlan Adamson, SD OSSD 				break;
196500b1e78SAlan Adamson, SD OSSD 			}
197500b1e78SAlan Adamson, SD OSSD 
198500b1e78SAlan Adamson, SD OSSD 		/*FALLTHRU*/
199500b1e78SAlan Adamson, SD OSSD 		/* These require no special privileges. */
200500b1e78SAlan Adamson, SD OSSD 		case PCITOOL_DEVICE_GET_INTR:
201500b1e78SAlan Adamson, SD OSSD 		case PCITOOL_SYSTEM_INTR_INFO:
202500b1e78SAlan Adamson, SD OSSD 			rv = niumxtool_intr(dip, (void *)arg, cmd, mode);
203500b1e78SAlan Adamson, SD OSSD 			break;
204500b1e78SAlan Adamson, SD OSSD 
205500b1e78SAlan Adamson, SD OSSD 		default:
206500b1e78SAlan Adamson, SD OSSD 			rv = ENOTTY;
207500b1e78SAlan Adamson, SD OSSD 		}
208500b1e78SAlan Adamson, SD OSSD 		return (rv);
209500b1e78SAlan Adamson, SD OSSD 
210500b1e78SAlan Adamson, SD OSSD 	default:
211500b1e78SAlan Adamson, SD OSSD 		break;
212500b1e78SAlan Adamson, SD OSSD 	}
213500b1e78SAlan Adamson, SD OSSD 	return (rv);
214500b1e78SAlan Adamson, SD OSSD }
215500b1e78SAlan Adamson, SD OSSD 
niumx_prop_op(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int flags,char * name,caddr_t valuep,int * lengthp)216500b1e78SAlan Adamson, SD OSSD static int niumx_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
217500b1e78SAlan Adamson, SD OSSD     int flags, char *name, caddr_t valuep, int *lengthp)
218500b1e78SAlan Adamson, SD OSSD {
219500b1e78SAlan Adamson, SD OSSD 	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
220500b1e78SAlan Adamson, SD OSSD }
221500b1e78SAlan Adamson, SD OSSD 
222500b1e78SAlan Adamson, SD OSSD int
niumxtool_init(dev_info_t * dip)223500b1e78SAlan Adamson, SD OSSD niumxtool_init(dev_info_t *dip)
224500b1e78SAlan Adamson, SD OSSD {
225500b1e78SAlan Adamson, SD OSSD 	int instance = ddi_get_instance(dip);
226500b1e78SAlan Adamson, SD OSSD 
227500b1e78SAlan Adamson, SD OSSD 	if (ddi_create_minor_node(dip, PCI_MINOR_INTR, S_IFCHR,
228500b1e78SAlan Adamson, SD OSSD 	    PCI_MINOR_NUM(instance, PCI_TOOL_INTR_MINOR_NUM),
229500b1e78SAlan Adamson, SD OSSD 	    DDI_NT_INTRCTL, 0) != DDI_SUCCESS) {
230500b1e78SAlan Adamson, SD OSSD 		ddi_remove_minor_node(dip, PCI_MINOR_REG);
231500b1e78SAlan Adamson, SD OSSD 		return (DDI_FAILURE);
232500b1e78SAlan Adamson, SD OSSD 	}
233500b1e78SAlan Adamson, SD OSSD 
234500b1e78SAlan Adamson, SD OSSD 	return (DDI_SUCCESS);
235500b1e78SAlan Adamson, SD OSSD }
236500b1e78SAlan Adamson, SD OSSD 
237500b1e78SAlan Adamson, SD OSSD void
niumxtool_uninit(dev_info_t * dip)238500b1e78SAlan Adamson, SD OSSD niumxtool_uninit(dev_info_t *dip)
239500b1e78SAlan Adamson, SD OSSD {
240500b1e78SAlan Adamson, SD OSSD 	ddi_remove_minor_node(dip, PCI_MINOR_INTR);
241500b1e78SAlan Adamson, SD OSSD }
242500b1e78SAlan Adamson, SD OSSD 
243500b1e78SAlan Adamson, SD OSSD static void
niumxtool_fill_in_intr_devs(pcitool_intr_dev_t * dev,char * driver_name,char * path_name,int instance)244500b1e78SAlan Adamson, SD OSSD niumxtool_fill_in_intr_devs(pcitool_intr_dev_t *dev, char *driver_name,
245500b1e78SAlan Adamson, SD OSSD     char *path_name, int instance)
246500b1e78SAlan Adamson, SD OSSD {
247*5963c4f9SRichard Lowe 	(void) strlcpy(dev->driver_name, driver_name, MAXMODCONFNAME);
248*5963c4f9SRichard Lowe 	(void) strlcpy(dev->path, path_name, MAXPATHLEN);
249500b1e78SAlan Adamson, SD OSSD 	dev->dev_inst = instance;
250500b1e78SAlan Adamson, SD OSSD }
251500b1e78SAlan Adamson, SD OSSD 
252500b1e78SAlan Adamson, SD OSSD /*ARGSUSED*/
253500b1e78SAlan Adamson, SD OSSD static int
niumxtool_intr_info(dev_info_t * dip,void * arg,int mode)254500b1e78SAlan Adamson, SD OSSD niumxtool_intr_info(dev_info_t *dip, void *arg, int mode)
255500b1e78SAlan Adamson, SD OSSD {
256500b1e78SAlan Adamson, SD OSSD 	pcitool_intr_info_t intr_info;
257500b1e78SAlan Adamson, SD OSSD 	int rval = DDI_SUCCESS;
258500b1e78SAlan Adamson, SD OSSD 
259500b1e78SAlan Adamson, SD OSSD 	/* If we need user_version, and to ret same user version as passed in */
260500b1e78SAlan Adamson, SD OSSD 	if (ddi_copyin(arg, &intr_info, sizeof (pcitool_intr_info_t), mode) !=
261500b1e78SAlan Adamson, SD OSSD 	    DDI_SUCCESS) {
262500b1e78SAlan Adamson, SD OSSD 		return (EFAULT);
263500b1e78SAlan Adamson, SD OSSD 	}
264500b1e78SAlan Adamson, SD OSSD 
265500b1e78SAlan Adamson, SD OSSD 	intr_info.ctlr_version = 0;	/* XXX how to get real version? */
266500b1e78SAlan Adamson, SD OSSD 	intr_info.ctlr_type = PCITOOL_CTLR_TYPE_RISC;
267500b1e78SAlan Adamson, SD OSSD 	if (intr_info.flags & PCITOOL_INTR_FLAG_GET_MSI)
268500b1e78SAlan Adamson, SD OSSD 		intr_info.num_intr = 0;
269500b1e78SAlan Adamson, SD OSSD 	else
270500b1e78SAlan Adamson, SD OSSD 		intr_info.num_intr = NIUMX_MAX_INTRS;
271500b1e78SAlan Adamson, SD OSSD 
272500b1e78SAlan Adamson, SD OSSD 	intr_info.drvr_version = PCITOOL_VERSION;
273500b1e78SAlan Adamson, SD OSSD 	if (ddi_copyout(&intr_info, arg, sizeof (pcitool_intr_info_t), mode) !=
274500b1e78SAlan Adamson, SD OSSD 	    DDI_SUCCESS) {
275500b1e78SAlan Adamson, SD OSSD 		rval = EFAULT;
276500b1e78SAlan Adamson, SD OSSD 	}
277500b1e78SAlan Adamson, SD OSSD 
278500b1e78SAlan Adamson, SD OSSD 	return (rval);
279500b1e78SAlan Adamson, SD OSSD }
280500b1e78SAlan Adamson, SD OSSD 
281500b1e78SAlan Adamson, SD OSSD 
282500b1e78SAlan Adamson, SD OSSD /*
283500b1e78SAlan Adamson, SD OSSD  * Get interrupt information for a given ino.
284500b1e78SAlan Adamson, SD OSSD  * Returns info only for inos mapped to devices.
285500b1e78SAlan Adamson, SD OSSD  *
286500b1e78SAlan Adamson, SD OSSD  * Returned info is valid only when iget.num_devs is returned > 0.
287500b1e78SAlan Adamson, SD OSSD  * If ino is not enabled or is not mapped to a device,
288500b1e78SAlan Adamson, SD OSSD  * iget.num_devs will be returned as = 0.
289500b1e78SAlan Adamson, SD OSSD  */
290500b1e78SAlan Adamson, SD OSSD /*ARGSUSED*/
291500b1e78SAlan Adamson, SD OSSD static int
niumxtool_get_intr(dev_info_t * dip,void * arg,int mode)292500b1e78SAlan Adamson, SD OSSD niumxtool_get_intr(dev_info_t *dip, void *arg, int mode)
293500b1e78SAlan Adamson, SD OSSD {
294500b1e78SAlan Adamson, SD OSSD 	/* Array part isn't used here, but oh well... */
295500b1e78SAlan Adamson, SD OSSD 	pcitool_intr_get_t partial_iget;
296500b1e78SAlan Adamson, SD OSSD 	pcitool_intr_get_t *iget_p = &partial_iget;
297500b1e78SAlan Adamson, SD OSSD 	int copyout_rval;
298500b1e78SAlan Adamson, SD OSSD 	niusysino_t sysino;
299500b1e78SAlan Adamson, SD OSSD 	niucpuid_t cpu_id;
300500b1e78SAlan Adamson, SD OSSD 	niumx_devstate_t *niumxds_p;
301500b1e78SAlan Adamson, SD OSSD 	dev_info_t *ih_dip;
302500b1e78SAlan Adamson, SD OSSD 	size_t	iget_kmem_alloc_size = 0;
303500b1e78SAlan Adamson, SD OSSD 	char pathname[MAXPATHLEN];
304500b1e78SAlan Adamson, SD OSSD 	int rval = EIO;
305500b1e78SAlan Adamson, SD OSSD 
306500b1e78SAlan Adamson, SD OSSD 	niumxds_p = (niumx_devstate_t *)
307500b1e78SAlan Adamson, SD OSSD 	    ddi_get_soft_state(niumx_state, ddi_get_instance(dip));
308500b1e78SAlan Adamson, SD OSSD 
309500b1e78SAlan Adamson, SD OSSD 	/* Read in just the header part, no array section. */
310500b1e78SAlan Adamson, SD OSSD 	if (ddi_copyin(arg, &partial_iget, PCITOOL_IGET_SIZE(0), mode) !=
311500b1e78SAlan Adamson, SD OSSD 	    DDI_SUCCESS)
312500b1e78SAlan Adamson, SD OSSD 		return (EFAULT);
313500b1e78SAlan Adamson, SD OSSD 
314500b1e78SAlan Adamson, SD OSSD 	iget_p->status = PCITOOL_IO_ERROR;
315500b1e78SAlan Adamson, SD OSSD 	iget_p->msi = (uint32_t)-1;
316500b1e78SAlan Adamson, SD OSSD 
317500b1e78SAlan Adamson, SD OSSD 	if (iget_p->flags & PCITOOL_INTR_FLAG_GET_MSI) {
318500b1e78SAlan Adamson, SD OSSD 		iget_p->status = PCITOOL_INVALID_MSI;
319500b1e78SAlan Adamson, SD OSSD 		rval = EINVAL;
320500b1e78SAlan Adamson, SD OSSD 		goto done_get_intr;
321500b1e78SAlan Adamson, SD OSSD 	}
322500b1e78SAlan Adamson, SD OSSD 
323500b1e78SAlan Adamson, SD OSSD 	/* Validate argument. */
324500b1e78SAlan Adamson, SD OSSD 	if (iget_p->ino > NIUMX_MAX_INTRS) {
325500b1e78SAlan Adamson, SD OSSD 		iget_p->status = PCITOOL_INVALID_INO;
326500b1e78SAlan Adamson, SD OSSD 		rval = EINVAL;
327500b1e78SAlan Adamson, SD OSSD 		goto done_get_intr;
328500b1e78SAlan Adamson, SD OSSD 	}
329500b1e78SAlan Adamson, SD OSSD 
330500b1e78SAlan Adamson, SD OSSD 	/* Caller wants device information returned. */
331500b1e78SAlan Adamson, SD OSSD 	if (iget_p->num_devs_ret > 0) {
332500b1e78SAlan Adamson, SD OSSD 		/*
333500b1e78SAlan Adamson, SD OSSD 		 * Allocate room.
334500b1e78SAlan Adamson, SD OSSD 		 * Note if num_devs == 0 iget_p remains pointing to
335500b1e78SAlan Adamson, SD OSSD 		 * partial_iget.
336500b1e78SAlan Adamson, SD OSSD 		 */
337500b1e78SAlan Adamson, SD OSSD 		iget_kmem_alloc_size = PCITOOL_IGET_SIZE(iget_p->num_devs_ret);
338500b1e78SAlan Adamson, SD OSSD 		iget_p = kmem_zalloc(iget_kmem_alloc_size, KM_SLEEP);
339500b1e78SAlan Adamson, SD OSSD 
340500b1e78SAlan Adamson, SD OSSD 		/* Read in whole structure to verify there's room. */
341500b1e78SAlan Adamson, SD OSSD 		if (ddi_copyin(arg, iget_p, iget_kmem_alloc_size, mode) !=
342500b1e78SAlan Adamson, SD OSSD 		    DDI_SUCCESS) {
343500b1e78SAlan Adamson, SD OSSD 
344500b1e78SAlan Adamson, SD OSSD 			/* Be consistent and just return EFAULT here. */
345500b1e78SAlan Adamson, SD OSSD 			kmem_free(iget_p, iget_kmem_alloc_size);
346500b1e78SAlan Adamson, SD OSSD 
347500b1e78SAlan Adamson, SD OSSD 			return (EFAULT);
348500b1e78SAlan Adamson, SD OSSD 		}
349500b1e78SAlan Adamson, SD OSSD 	}
350500b1e78SAlan Adamson, SD OSSD 
351500b1e78SAlan Adamson, SD OSSD 	sysino = niumxds_p->niumx_ihtable[iget_p->ino].ih_sysino;
352500b1e78SAlan Adamson, SD OSSD 	if (sysino == 0) {
353500b1e78SAlan Adamson, SD OSSD 		iget_p->status = PCITOOL_IO_ERROR;
354500b1e78SAlan Adamson, SD OSSD 		rval = EIO;
355500b1e78SAlan Adamson, SD OSSD 		goto done_get_intr;
356500b1e78SAlan Adamson, SD OSSD 	}
357500b1e78SAlan Adamson, SD OSSD 
358500b1e78SAlan Adamson, SD OSSD 	ih_dip = niumxds_p->niumx_ihtable[iget_p->ino].ih_dip;
359500b1e78SAlan Adamson, SD OSSD 
360500b1e78SAlan Adamson, SD OSSD 	ddi_pathname(ih_dip, pathname);
361500b1e78SAlan Adamson, SD OSSD 
362500b1e78SAlan Adamson, SD OSSD 	niumxtool_fill_in_intr_devs(&iget_p->dev[0],
363500b1e78SAlan Adamson, SD OSSD 	    (char *)ddi_driver_name(ih_dip),  pathname,
364500b1e78SAlan Adamson, SD OSSD 	    ddi_get_instance(ih_dip));
365500b1e78SAlan Adamson, SD OSSD 
366500b1e78SAlan Adamson, SD OSSD 	if (hvio_intr_gettarget(sysino, &cpu_id) != H_EOK) {
367500b1e78SAlan Adamson, SD OSSD 		iget_p->status = PCITOOL_IO_ERROR;
368500b1e78SAlan Adamson, SD OSSD 		rval = EIO;
369500b1e78SAlan Adamson, SD OSSD 		goto done_get_intr;
370500b1e78SAlan Adamson, SD OSSD 	}
371500b1e78SAlan Adamson, SD OSSD 	if (niumxds_p->niumx_ihtable[iget_p->ino].ih_cpuid != cpu_id) {
372500b1e78SAlan Adamson, SD OSSD 		cmn_err(CE_WARN, "CPU Does not match %x %x", cpu_id,
373500b1e78SAlan Adamson, SD OSSD 		    niumxds_p->niumx_ihtable[iget_p->ino].ih_cpuid);
374500b1e78SAlan Adamson, SD OSSD 		iget_p->status = PCITOOL_IO_ERROR;
375500b1e78SAlan Adamson, SD OSSD 		rval = EIO;
376500b1e78SAlan Adamson, SD OSSD 		goto done_get_intr;
377500b1e78SAlan Adamson, SD OSSD 	}
378500b1e78SAlan Adamson, SD OSSD 	iget_p->num_devs = 1;
379500b1e78SAlan Adamson, SD OSSD 	iget_p->cpu_id = niumxds_p->niumx_ihtable[iget_p->ino].ih_cpuid;
380500b1e78SAlan Adamson, SD OSSD 	iget_p->status = PCITOOL_SUCCESS;
381500b1e78SAlan Adamson, SD OSSD 	rval = DDI_SUCCESS;
382500b1e78SAlan Adamson, SD OSSD 
383500b1e78SAlan Adamson, SD OSSD done_get_intr:
384500b1e78SAlan Adamson, SD OSSD 	iget_p->drvr_version = PCITOOL_VERSION;
385500b1e78SAlan Adamson, SD OSSD 	copyout_rval =
386500b1e78SAlan Adamson, SD OSSD 	    ddi_copyout(iget_p, arg, PCITOOL_IGET_SIZE(iget_p->num_devs_ret),
387500b1e78SAlan Adamson, SD OSSD 	    mode);
388500b1e78SAlan Adamson, SD OSSD 
389500b1e78SAlan Adamson, SD OSSD 	if (iget_kmem_alloc_size > 0)
390500b1e78SAlan Adamson, SD OSSD 		kmem_free(iget_p, iget_kmem_alloc_size);
391500b1e78SAlan Adamson, SD OSSD 
392500b1e78SAlan Adamson, SD OSSD 	if (copyout_rval != DDI_SUCCESS)
393500b1e78SAlan Adamson, SD OSSD 		rval = EFAULT;
394500b1e78SAlan Adamson, SD OSSD 
395500b1e78SAlan Adamson, SD OSSD 	return (rval);
396500b1e78SAlan Adamson, SD OSSD }
397500b1e78SAlan Adamson, SD OSSD 
398500b1e78SAlan Adamson, SD OSSD 
399500b1e78SAlan Adamson, SD OSSD /*
400500b1e78SAlan Adamson, SD OSSD  * Associate a new CPU with a given ino.
401500b1e78SAlan Adamson, SD OSSD  *
402500b1e78SAlan Adamson, SD OSSD  * Operate only on inos which are already mapped to devices.
403500b1e78SAlan Adamson, SD OSSD  */
404500b1e78SAlan Adamson, SD OSSD static int
niumxtool_set_intr(dev_info_t * dip,void * arg,int mode)405500b1e78SAlan Adamson, SD OSSD niumxtool_set_intr(dev_info_t *dip, void *arg, int mode)
406500b1e78SAlan Adamson, SD OSSD {
407500b1e78SAlan Adamson, SD OSSD 	pcitool_intr_set_t iset;
408500b1e78SAlan Adamson, SD OSSD 	niucpuid_t old_cpu_id;
409500b1e78SAlan Adamson, SD OSSD 	int rval = EIO;
410500b1e78SAlan Adamson, SD OSSD 	int ret = DDI_SUCCESS;
411500b1e78SAlan Adamson, SD OSSD 	size_t copyinout_size;
412500b1e78SAlan Adamson, SD OSSD 	niumx_devstate_t *niumxds_p;
413500b1e78SAlan Adamson, SD OSSD 
414500b1e78SAlan Adamson, SD OSSD 	niumxds_p = (niumx_devstate_t *)
415500b1e78SAlan Adamson, SD OSSD 	    ddi_get_soft_state(niumx_state, ddi_get_instance(dip));
416500b1e78SAlan Adamson, SD OSSD 
417500b1e78SAlan Adamson, SD OSSD 	bzero(&iset, sizeof (pcitool_intr_set_t));
418500b1e78SAlan Adamson, SD OSSD 
419500b1e78SAlan Adamson, SD OSSD 	/* Version 1 of pcitool_intr_set_t doesn't have flags. */
420500b1e78SAlan Adamson, SD OSSD 	copyinout_size = (size_t)&iset.flags - (size_t)&iset;
421500b1e78SAlan Adamson, SD OSSD 
422500b1e78SAlan Adamson, SD OSSD 	if (ddi_copyin(arg, &iset, copyinout_size, mode) != DDI_SUCCESS)
423500b1e78SAlan Adamson, SD OSSD 		return (EFAULT);
424500b1e78SAlan Adamson, SD OSSD 
425500b1e78SAlan Adamson, SD OSSD 	switch (iset.user_version) {
426500b1e78SAlan Adamson, SD OSSD 	case PCITOOL_V1:
427500b1e78SAlan Adamson, SD OSSD 		break;
428500b1e78SAlan Adamson, SD OSSD 
429500b1e78SAlan Adamson, SD OSSD 	case PCITOOL_V2:
430500b1e78SAlan Adamson, SD OSSD 		copyinout_size = sizeof (pcitool_intr_set_t);
431500b1e78SAlan Adamson, SD OSSD 		if (ddi_copyin(arg, &iset, copyinout_size, mode) != DDI_SUCCESS)
432500b1e78SAlan Adamson, SD OSSD 			return (EFAULT);
433500b1e78SAlan Adamson, SD OSSD 		break;
434500b1e78SAlan Adamson, SD OSSD 
435500b1e78SAlan Adamson, SD OSSD 	default:
436500b1e78SAlan Adamson, SD OSSD 		iset.status = PCITOOL_OUT_OF_RANGE;
437500b1e78SAlan Adamson, SD OSSD 		rval = ENOTSUP;
438500b1e78SAlan Adamson, SD OSSD 		goto done_set_intr;
439500b1e78SAlan Adamson, SD OSSD 	}
440500b1e78SAlan Adamson, SD OSSD 
441500b1e78SAlan Adamson, SD OSSD 	if (iset.flags & PCITOOL_INTR_FLAG_SET_GROUP) {
442500b1e78SAlan Adamson, SD OSSD 		iset.status = PCITOOL_IO_ERROR;
443500b1e78SAlan Adamson, SD OSSD 		rval = ENOTSUP;
444500b1e78SAlan Adamson, SD OSSD 		goto done_set_intr;
445500b1e78SAlan Adamson, SD OSSD 	}
446500b1e78SAlan Adamson, SD OSSD 
447500b1e78SAlan Adamson, SD OSSD 	iset.status = PCITOOL_IO_ERROR;
448500b1e78SAlan Adamson, SD OSSD 
449500b1e78SAlan Adamson, SD OSSD 	iset.msi = (uint32_t)-1;
450500b1e78SAlan Adamson, SD OSSD 
451500b1e78SAlan Adamson, SD OSSD 	/* Validate input argument. */
452500b1e78SAlan Adamson, SD OSSD 	if (iset.ino > NIUMX_MAX_INTRS) {
453500b1e78SAlan Adamson, SD OSSD 		iset.status = PCITOOL_INVALID_INO;
454500b1e78SAlan Adamson, SD OSSD 		rval = EINVAL;
455500b1e78SAlan Adamson, SD OSSD 		goto done_set_intr;
456500b1e78SAlan Adamson, SD OSSD 	}
457500b1e78SAlan Adamson, SD OSSD 
458500b1e78SAlan Adamson, SD OSSD 	old_cpu_id = niumxds_p->niumx_ihtable[iset.ino].ih_cpuid;
459500b1e78SAlan Adamson, SD OSSD 
460500b1e78SAlan Adamson, SD OSSD 	if ((ret = niumx_set_intr_target(niumxds_p, iset.ino,
461500b1e78SAlan Adamson, SD OSSD 	    iset.cpu_id)) == DDI_SUCCESS) {
462500b1e78SAlan Adamson, SD OSSD 		iset.cpu_id = old_cpu_id;
463500b1e78SAlan Adamson, SD OSSD 		iset.status = PCITOOL_SUCCESS;
464500b1e78SAlan Adamson, SD OSSD 		rval = DDI_SUCCESS;
465500b1e78SAlan Adamson, SD OSSD 		goto done_set_intr;
466500b1e78SAlan Adamson, SD OSSD 	}
467500b1e78SAlan Adamson, SD OSSD 
468500b1e78SAlan Adamson, SD OSSD 	switch (ret) {
469500b1e78SAlan Adamson, SD OSSD 	case DDI_EPENDING:
470500b1e78SAlan Adamson, SD OSSD 		iset.status = PCITOOL_PENDING_INTRTIMEOUT;
471500b1e78SAlan Adamson, SD OSSD 		rval = ETIME;
472500b1e78SAlan Adamson, SD OSSD 		break;
473500b1e78SAlan Adamson, SD OSSD 	case DDI_EINVAL:
474500b1e78SAlan Adamson, SD OSSD 		iset.status = PCITOOL_INVALID_CPUID;
475500b1e78SAlan Adamson, SD OSSD 		rval = EINVAL;
476500b1e78SAlan Adamson, SD OSSD 		break;
477500b1e78SAlan Adamson, SD OSSD 	default:
478500b1e78SAlan Adamson, SD OSSD 		iset.status = PCITOOL_IO_ERROR;
479500b1e78SAlan Adamson, SD OSSD 		rval = EIO;
480500b1e78SAlan Adamson, SD OSSD 		break;
481500b1e78SAlan Adamson, SD OSSD 	}
482500b1e78SAlan Adamson, SD OSSD 
483500b1e78SAlan Adamson, SD OSSD done_set_intr:
484500b1e78SAlan Adamson, SD OSSD 	iset.drvr_version = PCITOOL_VERSION;
485500b1e78SAlan Adamson, SD OSSD 	if (ddi_copyout(&iset, arg, copyinout_size, mode) != DDI_SUCCESS)
486500b1e78SAlan Adamson, SD OSSD 		rval = EFAULT;
487500b1e78SAlan Adamson, SD OSSD 
488500b1e78SAlan Adamson, SD OSSD 	return (rval);
489500b1e78SAlan Adamson, SD OSSD }
490500b1e78SAlan Adamson, SD OSSD 
491500b1e78SAlan Adamson, SD OSSD 
492500b1e78SAlan Adamson, SD OSSD /* Main function for handling interrupt CPU binding requests and queries. */
493500b1e78SAlan Adamson, SD OSSD static int
niumxtool_intr(dev_info_t * dip,void * arg,int cmd,int mode)494500b1e78SAlan Adamson, SD OSSD niumxtool_intr(dev_info_t *dip, void *arg, int cmd, int mode)
495500b1e78SAlan Adamson, SD OSSD {
496500b1e78SAlan Adamson, SD OSSD 
497500b1e78SAlan Adamson, SD OSSD 	int rval = DDI_SUCCESS;
498500b1e78SAlan Adamson, SD OSSD 
499500b1e78SAlan Adamson, SD OSSD 	switch (cmd) {
500500b1e78SAlan Adamson, SD OSSD 
501500b1e78SAlan Adamson, SD OSSD 	/* Get system interrupt information. */
502500b1e78SAlan Adamson, SD OSSD 	case PCITOOL_SYSTEM_INTR_INFO:
503500b1e78SAlan Adamson, SD OSSD 		rval = niumxtool_intr_info(dip, arg, mode);
504500b1e78SAlan Adamson, SD OSSD 		break;
505500b1e78SAlan Adamson, SD OSSD 
506500b1e78SAlan Adamson, SD OSSD 	/* Get interrupt information for a given ino. */
507500b1e78SAlan Adamson, SD OSSD 	case PCITOOL_DEVICE_GET_INTR:
508500b1e78SAlan Adamson, SD OSSD 		rval = niumxtool_get_intr(dip, arg, mode);
509500b1e78SAlan Adamson, SD OSSD 		break;
510500b1e78SAlan Adamson, SD OSSD 
511500b1e78SAlan Adamson, SD OSSD 	/* Associate a new CPU with a given ino. */
512500b1e78SAlan Adamson, SD OSSD 	case PCITOOL_DEVICE_SET_INTR:
513500b1e78SAlan Adamson, SD OSSD 		rval = niumxtool_set_intr(dip, arg, mode);
514500b1e78SAlan Adamson, SD OSSD 		break;
515500b1e78SAlan Adamson, SD OSSD 
516500b1e78SAlan Adamson, SD OSSD 	default:
517500b1e78SAlan Adamson, SD OSSD 		rval = ENOTTY;
518500b1e78SAlan Adamson, SD OSSD 	}
519500b1e78SAlan Adamson, SD OSSD 
520500b1e78SAlan Adamson, SD OSSD 	return (rval);
521500b1e78SAlan Adamson, SD OSSD }
522