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 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 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 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 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 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 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 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 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 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 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 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