169cd775fSschwartz /* 269cd775fSschwartz * CDDL HEADER START 369cd775fSschwartz * 469cd775fSschwartz * The contents of this file are subject to the terms of the 525cf1a30Sjl139090 * Common Development and Distribution License (the "License"). 625cf1a30Sjl139090 * You may not use this file except in compliance with the License. 769cd775fSschwartz * 869cd775fSschwartz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 969cd775fSschwartz * or http://www.opensolaris.org/os/licensing. 1069cd775fSschwartz * See the License for the specific language governing permissions 1169cd775fSschwartz * and limitations under the License. 1269cd775fSschwartz * 1369cd775fSschwartz * When distributing Covered Code, include this CDDL HEADER in each 1469cd775fSschwartz * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1569cd775fSschwartz * If applicable, add the following below this CDDL HEADER, with the 1669cd775fSschwartz * fields enclosed by brackets "[]" replaced with your own identifying 1769cd775fSschwartz * information: Portions Copyright [yyyy] [name of copyright owner] 1869cd775fSschwartz * 1969cd775fSschwartz * CDDL HEADER END 2069cd775fSschwartz */ 2169cd775fSschwartz /* 2209b1eac2SEvan Yan * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2369cd775fSschwartz * Use is subject to license terms. 2469cd775fSschwartz */ 2569cd775fSschwartz 2669cd775fSschwartz #include <sys/types.h> 2769cd775fSschwartz #include <sys/stat.h> 2869cd775fSschwartz #include <sys/cpuvar.h> 2969cd775fSschwartz #include <sys/kmem.h> 3069cd775fSschwartz #include <sys/sunddi.h> 3169cd775fSschwartz #include "px_obj.h" 3269cd775fSschwartz #include <sys/pci_tools.h> 33d4476ccbSschwartz #include "px_tools_ext.h" 3469cd775fSschwartz #include "px_tools_var.h" 3569cd775fSschwartz 3669cd775fSschwartz /* 3769cd775fSschwartz * PCI Space definitions. 3869cd775fSschwartz */ 3969cd775fSschwartz #define PCI_CONFIG_SPACE (PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) 4069cd775fSschwartz #define PCI_IO_SPACE (PCI_REG_ADDR_G(PCI_ADDR_IO)) 4169cd775fSschwartz #define PCI_MEM32_SPACE (PCI_REG_ADDR_G(PCI_ADDR_MEM32)) 4269cd775fSschwartz #define PCI_MEM64_SPACE (PCI_REG_ADDR_G(PCI_ADDR_MEM64)) 4369cd775fSschwartz 4469cd775fSschwartz /* 4569cd775fSschwartz * Config space range for a device. IEEE 1275 spec defines for PCI. 4669cd775fSschwartz * Space for PCI-express is multiplied by PX_PCI_BDF_OFFSET_DELTA 4769cd775fSschwartz */ 4869cd775fSschwartz #define DEV_CFG_SPACE_SIZE \ 4969cd775fSschwartz (1 << (PCI_REG_FUNC_SHIFT + PX_PCI_BDF_OFFSET_DELTA)) 5069cd775fSschwartz 5169cd775fSschwartz /* 5269cd775fSschwartz * Offsets of BARS in config space. First entry of 0 means config space. 5369cd775fSschwartz * Entries here correlate to pcitool_bars_t enumerated type. 5469cd775fSschwartz */ 5569cd775fSschwartz uint8_t pci_bars[] = { 5669cd775fSschwartz 0x0, 5769cd775fSschwartz PCI_CONF_BASE0, 5869cd775fSschwartz PCI_CONF_BASE1, 5969cd775fSschwartz PCI_CONF_BASE2, 6069cd775fSschwartz PCI_CONF_BASE3, 6169cd775fSschwartz PCI_CONF_BASE4, 6269cd775fSschwartz PCI_CONF_BASE5, 6369cd775fSschwartz PCI_CONF_ROM 6469cd775fSschwartz }; 6569cd775fSschwartz 6669cd775fSschwartz int pci_num_bars = sizeof (pci_bars) / sizeof (pci_bars[0]); 6769cd775fSschwartz 6869cd775fSschwartz 692917a9c9Sschwartz /*ARGSUSED*/ 7069cd775fSschwartz static int 712917a9c9Sschwartz pxtool_intr_info(dev_info_t *dip, void *arg, int mode) 7269cd775fSschwartz { 7309b1eac2SEvan Yan px_t *px_p = DIP_TO_STATE(dip); 7409b1eac2SEvan Yan px_msi_state_t *msi_state_p = &px_p->px_ib_p->ib_msi_state; 752917a9c9Sschwartz pcitool_intr_info_t intr_info; 762917a9c9Sschwartz int rval = SUCCESS; 772917a9c9Sschwartz 782917a9c9Sschwartz /* If we need user_version, and to ret same user version as passed in */ 792917a9c9Sschwartz if (ddi_copyin(arg, &intr_info, sizeof (pcitool_intr_info_t), mode) != 802917a9c9Sschwartz DDI_SUCCESS) { 8169cd775fSschwartz return (EFAULT); 8269cd775fSschwartz } 832917a9c9Sschwartz 842917a9c9Sschwartz intr_info.ctlr_version = 0; /* XXX how to get real version? */ 852917a9c9Sschwartz intr_info.ctlr_type = PCITOOL_CTLR_TYPE_RISC; 8609b1eac2SEvan Yan if (intr_info.flags & PCITOOL_INTR_FLAG_GET_MSI) 8709b1eac2SEvan Yan intr_info.num_intr = msi_state_p->msi_cnt; 8809b1eac2SEvan Yan else 892917a9c9Sschwartz intr_info.num_intr = pxtool_num_inos; 902917a9c9Sschwartz 912917a9c9Sschwartz intr_info.drvr_version = PCITOOL_VERSION; 922917a9c9Sschwartz if (ddi_copyout(&intr_info, arg, sizeof (pcitool_intr_info_t), mode) != 932917a9c9Sschwartz DDI_SUCCESS) { 942917a9c9Sschwartz rval = EFAULT; 952917a9c9Sschwartz } 962917a9c9Sschwartz 972917a9c9Sschwartz return (rval); 982917a9c9Sschwartz } 992917a9c9Sschwartz 1002917a9c9Sschwartz 10169cd775fSschwartz /* 10269cd775fSschwartz * Get interrupt information for a given ino. 10369cd775fSschwartz * Returns info only for inos mapped to devices. 10469cd775fSschwartz * 10569cd775fSschwartz * Returned info is valid only when iget.num_devs is returned > 0. 10669cd775fSschwartz * If ino is not enabled or is not mapped to a device, 10769cd775fSschwartz * iget.num_devs will be returned as = 0. 10869cd775fSschwartz */ 10969cd775fSschwartz /*ARGSUSED*/ 11069cd775fSschwartz static int 11169cd775fSschwartz pxtool_get_intr(dev_info_t *dip, void *arg, int mode) 11269cd775fSschwartz { 11369cd775fSschwartz /* Array part isn't used here, but oh well... */ 11469cd775fSschwartz pcitool_intr_get_t partial_iget; 11509b1eac2SEvan Yan pcitool_intr_get_t *iget = &partial_iget; 11669cd775fSschwartz int copyout_rval; 11769cd775fSschwartz sysino_t sysino; 11869cd775fSschwartz intr_valid_state_t intr_valid_state; 11969cd775fSschwartz cpuid_t old_cpu_id; 12069cd775fSschwartz px_t *px_p = DIP_TO_STATE(dip); 12169cd775fSschwartz size_t iget_kmem_alloc_size = 0; 12209b1eac2SEvan Yan int rval = EIO; 12369cd775fSschwartz 12469cd775fSschwartz /* Read in just the header part, no array section. */ 12569cd775fSschwartz if (ddi_copyin(arg, &partial_iget, PCITOOL_IGET_SIZE(0), mode) != 12669cd775fSschwartz DDI_SUCCESS) 12769cd775fSschwartz return (EFAULT); 12869cd775fSschwartz 12909b1eac2SEvan Yan iget->status = PCITOOL_IO_ERROR; 13069cd775fSschwartz 13109b1eac2SEvan Yan if (iget->flags & PCITOOL_INTR_FLAG_GET_MSI) { 13209b1eac2SEvan Yan px_msi_state_t *msi_state_p = &px_p->px_ib_p->ib_msi_state; 13309b1eac2SEvan Yan pci_msi_valid_state_t msi_state; 13409b1eac2SEvan Yan msiqid_t msiq_id; 13509b1eac2SEvan Yan 13609b1eac2SEvan Yan if ((iget->msi < msi_state_p->msi_1st_msinum) || 13709b1eac2SEvan Yan (iget->msi >= (msi_state_p->msi_1st_msinum + 13809b1eac2SEvan Yan msi_state_p->msi_cnt))) { 13909b1eac2SEvan Yan iget->status = PCITOOL_INVALID_MSI; 14069cd775fSschwartz rval = EINVAL; 14109b1eac2SEvan Yan goto done_get_intr; 14209b1eac2SEvan Yan } 14309b1eac2SEvan Yan 14409b1eac2SEvan Yan if ((px_lib_msi_getvalid(dip, iget->msi, 14509b1eac2SEvan Yan &msi_state) != DDI_SUCCESS) || 14609b1eac2SEvan Yan (msi_state != PCI_MSI_VALID)) 14709b1eac2SEvan Yan goto done_get_intr; 14809b1eac2SEvan Yan 14909b1eac2SEvan Yan if (px_lib_msi_getmsiq(dip, iget->msi, 15009b1eac2SEvan Yan &msiq_id) != DDI_SUCCESS) 15109b1eac2SEvan Yan goto done_get_intr; 15209b1eac2SEvan Yan 15309b1eac2SEvan Yan iget->ino = px_msiqid_to_devino(px_p, msiq_id); 15409b1eac2SEvan Yan } else { 15509b1eac2SEvan Yan iget->msi = (uint32_t)-1; 15609b1eac2SEvan Yan } 15769cd775fSschwartz 15869cd775fSschwartz /* Validate argument. */ 15909b1eac2SEvan Yan if (iget->ino > pxtool_num_inos) { 16009b1eac2SEvan Yan iget->status = PCITOOL_INVALID_INO; 16109b1eac2SEvan Yan rval = EINVAL; 16269cd775fSschwartz goto done_get_intr; 16369cd775fSschwartz } 16469cd775fSschwartz 16569cd775fSschwartz /* Caller wants device information returned. */ 16609b1eac2SEvan Yan if (iget->num_devs_ret > 0) { 16769cd775fSschwartz /* 16869cd775fSschwartz * Allocate room. 16969cd775fSschwartz * Note if num_devs == 0 iget remains pointing to 17069cd775fSschwartz * partial_iget. 17169cd775fSschwartz */ 17209b1eac2SEvan Yan iget_kmem_alloc_size = PCITOOL_IGET_SIZE(iget->num_devs_ret); 17309b1eac2SEvan Yan iget = kmem_zalloc(iget_kmem_alloc_size, KM_SLEEP); 17469cd775fSschwartz 17569cd775fSschwartz /* Read in whole structure to verify there's room. */ 17669cd775fSschwartz if (ddi_copyin(arg, iget, iget_kmem_alloc_size, mode) != 17769cd775fSschwartz SUCCESS) { 17869cd775fSschwartz 17969cd775fSschwartz /* Be consistent and just return EFAULT here. */ 18069cd775fSschwartz kmem_free(iget, iget_kmem_alloc_size); 18169cd775fSschwartz 18269cd775fSschwartz return (EFAULT); 18369cd775fSschwartz } 18469cd775fSschwartz } 18569cd775fSschwartz 18669cd775fSschwartz /* Convert leaf-wide intr to system-wide intr */ 18709b1eac2SEvan Yan if (px_lib_intr_devino_to_sysino(dip, iget->ino, &sysino) != 18809b1eac2SEvan Yan DDI_SUCCESS) { 18969cd775fSschwartz iget->status = PCITOOL_IO_ERROR; 19069cd775fSschwartz rval = EIO; 19169cd775fSschwartz goto done_get_intr; 19269cd775fSschwartz } 19369cd775fSschwartz 19469cd775fSschwartz /* Operate only on inos which are already enabled. */ 19509b1eac2SEvan Yan if (px_lib_intr_getvalid(dip, sysino, &intr_valid_state) != 19609b1eac2SEvan Yan DDI_SUCCESS) { 19769cd775fSschwartz iget->status = PCITOOL_IO_ERROR; 19869cd775fSschwartz rval = EIO; 19969cd775fSschwartz goto done_get_intr; 20069cd775fSschwartz } 20169cd775fSschwartz 20269cd775fSschwartz /* 20369cd775fSschwartz * Consider all valid inos: those mapped to the root complex itself 20469cd775fSschwartz * as well as those mapped to devices. 20569cd775fSschwartz */ 20669cd775fSschwartz if (intr_valid_state == INTR_VALID) { 20769cd775fSschwartz /* 208b0fc0e77Sgovinda * The following looks up the px_ino and returns 20969cd775fSschwartz * info of devices mapped to this ino. 21069cd775fSschwartz */ 21109b1eac2SEvan Yan iget->num_devs = pxtool_ib_get_ino_devs(px_p, iget->ino, 21209b1eac2SEvan Yan iget->msi, &iget->num_devs_ret, iget->dev); 21369cd775fSschwartz 21409b1eac2SEvan Yan if (px_ib_get_intr_target(px_p, iget->ino, 21509b1eac2SEvan Yan &old_cpu_id) != DDI_SUCCESS) { 21669cd775fSschwartz iget->status = PCITOOL_IO_ERROR; 21769cd775fSschwartz rval = EIO; 21869cd775fSschwartz goto done_get_intr; 21969cd775fSschwartz } 22009b1eac2SEvan Yan 22169cd775fSschwartz iget->cpu_id = old_cpu_id; 22269cd775fSschwartz } 22369cd775fSschwartz 22469cd775fSschwartz iget->status = PCITOOL_SUCCESS; 22569cd775fSschwartz rval = SUCCESS; 22669cd775fSschwartz 22769cd775fSschwartz done_get_intr: 2282917a9c9Sschwartz iget->drvr_version = PCITOOL_VERSION; 22969cd775fSschwartz copyout_rval = 23009b1eac2SEvan Yan ddi_copyout(iget, arg, PCITOOL_IGET_SIZE(iget->num_devs_ret), mode); 23169cd775fSschwartz 23269cd775fSschwartz if (iget_kmem_alloc_size > 0) 23369cd775fSschwartz kmem_free(iget, iget_kmem_alloc_size); 23469cd775fSschwartz 23569cd775fSschwartz if (copyout_rval != DDI_SUCCESS) 23669cd775fSschwartz rval = EFAULT; 23769cd775fSschwartz 23869cd775fSschwartz return (rval); 23969cd775fSschwartz } 24069cd775fSschwartz 24169cd775fSschwartz 24269cd775fSschwartz /* 24369cd775fSschwartz * Associate a new CPU with a given ino. 24469cd775fSschwartz * 24569cd775fSschwartz * Operate only on inos which are already mapped to devices. 24669cd775fSschwartz */ 24769cd775fSschwartz static int 24869cd775fSschwartz pxtool_set_intr(dev_info_t *dip, void *arg, int mode) 24969cd775fSschwartz { 25069cd775fSschwartz pcitool_intr_set_t iset; 25169cd775fSschwartz cpuid_t old_cpu_id; 25269cd775fSschwartz sysino_t sysino; 25309b1eac2SEvan Yan intr_valid_state_t intr_valid_state; 25469cd775fSschwartz px_t *px_p = DIP_TO_STATE(dip); 25509b1eac2SEvan Yan msiqid_t msiq_id; 25609b1eac2SEvan Yan int rval = EIO; 25709b1eac2SEvan Yan int ret = DDI_SUCCESS; 2582917a9c9Sschwartz size_t copyinout_size; 25969cd775fSschwartz 2602917a9c9Sschwartz bzero(&iset, sizeof (pcitool_intr_set_t)); 2612917a9c9Sschwartz 2622917a9c9Sschwartz /* Version 1 of pcitool_intr_set_t doesn't have flags. */ 2632917a9c9Sschwartz copyinout_size = (size_t)&iset.flags - (size_t)&iset; 2642917a9c9Sschwartz 2652917a9c9Sschwartz if (ddi_copyin(arg, &iset, copyinout_size, mode) != DDI_SUCCESS) 26669cd775fSschwartz return (EFAULT); 26769cd775fSschwartz 2682917a9c9Sschwartz switch (iset.user_version) { 2692917a9c9Sschwartz case PCITOOL_V1: 2702917a9c9Sschwartz break; 2712917a9c9Sschwartz 2722917a9c9Sschwartz case PCITOOL_V2: 2732917a9c9Sschwartz copyinout_size = sizeof (pcitool_intr_set_t); 2742917a9c9Sschwartz if (ddi_copyin(arg, &iset, copyinout_size, mode) != DDI_SUCCESS) 2752917a9c9Sschwartz return (EFAULT); 2762917a9c9Sschwartz break; 2772917a9c9Sschwartz 2782917a9c9Sschwartz default: 2792917a9c9Sschwartz iset.status = PCITOOL_OUT_OF_RANGE; 2802917a9c9Sschwartz rval = ENOTSUP; 2812917a9c9Sschwartz goto done_set_intr; 2822917a9c9Sschwartz } 2832917a9c9Sschwartz 28409b1eac2SEvan Yan if (iset.flags & PCITOOL_INTR_FLAG_SET_GROUP) { 2852917a9c9Sschwartz iset.status = PCITOOL_IO_ERROR; 2862917a9c9Sschwartz rval = ENOTSUP; 2872917a9c9Sschwartz goto done_set_intr; 2882917a9c9Sschwartz } 2892917a9c9Sschwartz 29009b1eac2SEvan Yan iset.status = PCITOOL_IO_ERROR; 29169cd775fSschwartz 29209b1eac2SEvan Yan if (iset.flags & PCITOOL_INTR_FLAG_SET_MSI) { 29309b1eac2SEvan Yan px_msi_state_t *msi_state_p = &px_p->px_ib_p->ib_msi_state; 29409b1eac2SEvan Yan pci_msi_valid_state_t msi_state; 29509b1eac2SEvan Yan 29609b1eac2SEvan Yan if ((iset.msi < msi_state_p->msi_1st_msinum) || 29709b1eac2SEvan Yan (iset.msi >= (msi_state_p->msi_1st_msinum + 29809b1eac2SEvan Yan msi_state_p->msi_cnt))) { 29909b1eac2SEvan Yan iset.status = PCITOOL_INVALID_MSI; 30009b1eac2SEvan Yan rval = EINVAL; 30109b1eac2SEvan Yan goto done_set_intr; 30209b1eac2SEvan Yan } 30309b1eac2SEvan Yan 30409b1eac2SEvan Yan if ((px_lib_msi_getvalid(dip, iset.msi, 30509b1eac2SEvan Yan &msi_state) != DDI_SUCCESS) || 30609b1eac2SEvan Yan (msi_state != PCI_MSI_VALID)) 30769cd775fSschwartz goto done_set_intr; 30869cd775fSschwartz 30909b1eac2SEvan Yan if (px_lib_msi_getmsiq(dip, iset.msi, 31009b1eac2SEvan Yan &msiq_id) != DDI_SUCCESS) 31109b1eac2SEvan Yan goto done_set_intr; 31209b1eac2SEvan Yan 31309b1eac2SEvan Yan iset.ino = px_msiqid_to_devino(px_p, msiq_id); 31409b1eac2SEvan Yan } else { 31509b1eac2SEvan Yan iset.msi = (uint32_t)-1; 31609b1eac2SEvan Yan } 31709b1eac2SEvan Yan 31809b1eac2SEvan Yan /* Validate input argument. */ 31909b1eac2SEvan Yan if (iset.ino > pxtool_num_inos) { 32009b1eac2SEvan Yan iset.status = PCITOOL_INVALID_INO; 32109b1eac2SEvan Yan rval = EINVAL; 32209b1eac2SEvan Yan goto done_set_intr; 32309b1eac2SEvan Yan } 32409b1eac2SEvan Yan 32509b1eac2SEvan Yan /* Convert leaf-wide intr to system-wide intr */ 32609b1eac2SEvan Yan if (px_lib_intr_devino_to_sysino(dip, iset.ino, &sysino) != 32709b1eac2SEvan Yan DDI_SUCCESS) 32809b1eac2SEvan Yan goto done_set_intr; 32909b1eac2SEvan Yan 33009b1eac2SEvan Yan /* Operate only on inos which are already enabled. */ 33109b1eac2SEvan Yan if ((px_lib_intr_getvalid(dip, sysino, &intr_valid_state) != 33209b1eac2SEvan Yan DDI_SUCCESS) || (intr_valid_state == INTR_NOTVALID)) 33369cd775fSschwartz goto done_set_intr; 33469cd775fSschwartz 33569cd775fSschwartz /* 33609b1eac2SEvan Yan * Consider all valid inos: those mapped to the root complex itself 33709b1eac2SEvan Yan * as well as those mapped to devices. 33869cd775fSschwartz */ 33909b1eac2SEvan Yan if (px_lib_intr_gettarget(dip, sysino, &old_cpu_id) != DDI_SUCCESS) 34069cd775fSschwartz goto done_set_intr; 34169cd775fSschwartz 34209b1eac2SEvan Yan if (iset.flags & PCITOOL_INTR_FLAG_SET_MSI) { 34309b1eac2SEvan Yan ddi_intr_handle_impl_t hdle; 34409b1eac2SEvan Yan 34509b1eac2SEvan Yan bzero(&hdle, sizeof (ddi_intr_handle_impl_t)); 34609b1eac2SEvan Yan if (pxtool_ib_get_msi_info(px_p, iset.ino, iset.msi, 34709b1eac2SEvan Yan &hdle) != DDI_SUCCESS) { 34809b1eac2SEvan Yan iset.status = PCITOOL_INVALID_MSI; 34909b1eac2SEvan Yan rval = EINVAL; 35069cd775fSschwartz goto done_set_intr; 35109b1eac2SEvan Yan } 35269cd775fSschwartz 35309b1eac2SEvan Yan if ((ret = px_ib_set_msix_target(px_p, &hdle, iset.msi, 35409b1eac2SEvan Yan iset.cpu_id)) == DDI_SUCCESS) { 35509b1eac2SEvan Yan (void) px_lib_msi_getmsiq(dip, iset.msi, &msiq_id); 35609b1eac2SEvan Yan iset.ino = px_msiqid_to_devino(px_p, msiq_id); 35769cd775fSschwartz iset.cpu_id = old_cpu_id; 35869cd775fSschwartz iset.status = PCITOOL_SUCCESS; 35969cd775fSschwartz rval = SUCCESS; 36009b1eac2SEvan Yan goto done_set_intr; 36109b1eac2SEvan Yan } 36209b1eac2SEvan Yan } else { 36309b1eac2SEvan Yan if ((ret = px_ib_set_intr_target(px_p, iset.ino, 36409b1eac2SEvan Yan iset.cpu_id)) == DDI_SUCCESS) { 36509b1eac2SEvan Yan iset.cpu_id = old_cpu_id; 36609b1eac2SEvan Yan iset.status = PCITOOL_SUCCESS; 36709b1eac2SEvan Yan rval = SUCCESS; 36809b1eac2SEvan Yan goto done_set_intr; 36909b1eac2SEvan Yan } 37009b1eac2SEvan Yan } 37169cd775fSschwartz 37209b1eac2SEvan Yan switch (ret) { 37309b1eac2SEvan Yan case DDI_EPENDING: 37409b1eac2SEvan Yan iset.status = PCITOOL_PENDING_INTRTIMEOUT; 37509b1eac2SEvan Yan rval = ETIME; 37609b1eac2SEvan Yan break; 37709b1eac2SEvan Yan case DDI_EINVAL: 37869cd775fSschwartz iset.status = PCITOOL_INVALID_CPUID; 37969cd775fSschwartz rval = EINVAL; 38009b1eac2SEvan Yan break; 38109b1eac2SEvan Yan default: 38209b1eac2SEvan Yan iset.status = PCITOOL_IO_ERROR; 38309b1eac2SEvan Yan rval = EIO; 38409b1eac2SEvan Yan break; 38569cd775fSschwartz } 38669cd775fSschwartz 38769cd775fSschwartz done_set_intr: 3882917a9c9Sschwartz iset.drvr_version = PCITOOL_VERSION; 3892917a9c9Sschwartz if (ddi_copyout(&iset, arg, copyinout_size, mode) != DDI_SUCCESS) 39069cd775fSschwartz rval = EFAULT; 39169cd775fSschwartz 39269cd775fSschwartz return (rval); 39369cd775fSschwartz } 39469cd775fSschwartz 39569cd775fSschwartz 39669cd775fSschwartz /* Main function for handling interrupt CPU binding requests and queries. */ 39769cd775fSschwartz int 39869cd775fSschwartz pxtool_intr(dev_info_t *dip, void *arg, int cmd, int mode) 39969cd775fSschwartz { 40069cd775fSschwartz int rval = SUCCESS; 40169cd775fSschwartz 40269cd775fSschwartz switch (cmd) { 40369cd775fSschwartz 4042917a9c9Sschwartz /* Get system interrupt information. */ 4052917a9c9Sschwartz case PCITOOL_SYSTEM_INTR_INFO: 4062917a9c9Sschwartz rval = pxtool_intr_info(dip, arg, mode); 40769cd775fSschwartz break; 40869cd775fSschwartz 40969cd775fSschwartz /* Get interrupt information for a given ino. */ 41069cd775fSschwartz case PCITOOL_DEVICE_GET_INTR: 41169cd775fSschwartz rval = pxtool_get_intr(dip, arg, mode); 41269cd775fSschwartz break; 41369cd775fSschwartz 41469cd775fSschwartz /* Associate a new CPU with a given ino. */ 41569cd775fSschwartz case PCITOOL_DEVICE_SET_INTR: 41669cd775fSschwartz rval = pxtool_set_intr(dip, arg, mode); 41769cd775fSschwartz break; 41869cd775fSschwartz 41969cd775fSschwartz default: 42069cd775fSschwartz rval = ENOTTY; 42169cd775fSschwartz } 42269cd775fSschwartz 42369cd775fSschwartz return (rval); 42469cd775fSschwartz } 42569cd775fSschwartz 42669cd775fSschwartz 42769cd775fSschwartz static int 42869cd775fSschwartz pxtool_validate_barnum_bdf(pcitool_reg_t *prg) 42969cd775fSschwartz { 43069cd775fSschwartz int rval = SUCCESS; 43169cd775fSschwartz 43269cd775fSschwartz if (prg->barnum >= (sizeof (pci_bars) / sizeof (pci_bars[0]))) { 43369cd775fSschwartz prg->status = PCITOOL_OUT_OF_RANGE; 43469cd775fSschwartz rval = EINVAL; 43569cd775fSschwartz 43669cd775fSschwartz /* Validate address arguments of bus / dev / func */ 43769cd775fSschwartz } else if (((prg->bus_no & 43869cd775fSschwartz (PCI_REG_BUS_M >> PCI_REG_BUS_SHIFT)) != prg->bus_no) || 43969cd775fSschwartz ((prg->dev_no & 44069cd775fSschwartz (PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT)) != prg->dev_no) || 44169cd775fSschwartz ((prg->func_no & 44269cd775fSschwartz (PCI_REG_FUNC_M >> PCI_REG_FUNC_SHIFT)) != prg->func_no)) { 44369cd775fSschwartz prg->status = PCITOOL_INVALID_ADDRESS; 44469cd775fSschwartz rval = EINVAL; 44569cd775fSschwartz } 44669cd775fSschwartz 44769cd775fSschwartz return (rval); 44869cd775fSschwartz } 44969cd775fSschwartz 450dabea0dbSschwartz /* 451dabea0dbSschwartz * px_p defines which leaf, space defines which space in that leaf, offset 452dabea0dbSschwartz * defines the offset within the specified space. 453dabea0dbSschwartz * 454dabea0dbSschwartz * This returns the physical address of the corresponding location. 455dabea0dbSschwartz */ 456dabea0dbSschwartz static uintptr_t 457dabea0dbSschwartz pxtool_get_phys_addr(px_t *px_p, int space, uint64_t offset) 458dabea0dbSschwartz { 459dabea0dbSschwartz uint64_t range_base; 460dabea0dbSschwartz int rval; 461d3533785Sschwartz pci_regspec_t dev_regspec; 462d3533785Sschwartz struct regspec xlated_regspec; 463dabea0dbSschwartz dev_info_t *dip = px_p->px_dip; 464dabea0dbSschwartz 465dabea0dbSschwartz /* 466dabea0dbSschwartz * Assume that requested entity is small enough to be on the same page. 467dabea0dbSschwartz * PCItool checks alignment so that this will be true for single 468dabea0dbSschwartz * accesses. 469dabea0dbSschwartz */ 470d3533785Sschwartz dev_regspec.pci_phys_hi = space << PCI_REG_ADDR_SHIFT; 471d3533785Sschwartz if (space == PCI_CONFIG_SPACE) { 472d3533785Sschwartz dev_regspec.pci_phys_hi += 473d3533785Sschwartz (offset & (PCI_REG_BDFR_M ^ PCI_REG_REG_M)); 474d3533785Sschwartz dev_regspec.pci_phys_low = offset & PCI_REG_REG_M; 475d84bdf75Segillett dev_regspec.pci_phys_mid = 0; /* Not used */ 476d3533785Sschwartz } else { 477d3533785Sschwartz dev_regspec.pci_phys_mid = offset >> 32; 478d3533785Sschwartz dev_regspec.pci_phys_low = offset & 0xffffffff; 479d3533785Sschwartz } 480d3533785Sschwartz dev_regspec.pci_size_hi = 0; /* Not used. */ 481d3533785Sschwartz 482d3533785Sschwartz /* Note: object is guaranteed to be within a page. */ 483d3533785Sschwartz dev_regspec.pci_size_low = 4; 484d3533785Sschwartz 485d3533785Sschwartz rval = px_xlate_reg(px_p, &dev_regspec, &xlated_regspec); 486d3533785Sschwartz 487dabea0dbSschwartz DBG(DBG_TOOLS, dip, 488d3533785Sschwartz "space:0x%d, offset:0x%" PRIx64 "\n", space, offset); 489dabea0dbSschwartz 490dabea0dbSschwartz if (rval != DDI_SUCCESS) 491dabea0dbSschwartz return (NULL); 492d3533785Sschwartz 493d3533785Sschwartz /* Bustype here returns the high order address bits. */ 494d3533785Sschwartz xlated_regspec.regspec_bustype &= px_get_rng_parent_hi_mask(px_p); 495d3533785Sschwartz 496d3533785Sschwartz range_base = (((uint64_t)xlated_regspec.regspec_bustype) << 32) + 497d3533785Sschwartz xlated_regspec.regspec_addr; 498d3533785Sschwartz DBG(DBG_TOOLS, dip, 499d3533785Sschwartz "regspec: hi:0x%x, lo:0x%x, sz:0x%x, range base:0x%" PRIx64 "\n", 500d3533785Sschwartz xlated_regspec.regspec_bustype, xlated_regspec.regspec_addr, 501d3533785Sschwartz xlated_regspec.regspec_size, range_base); 502d3533785Sschwartz 503d3533785Sschwartz return ((uintptr_t)range_base); 504dabea0dbSschwartz } 505dabea0dbSschwartz 506dabea0dbSschwartz 50769cd775fSschwartz static int 508dabea0dbSschwartz pxtool_get_bar(px_t *px_p, pcitool_reg_t *prg_p, uint64_t *bar_p, 509dabea0dbSschwartz uint32_t *space_p) 51069cd775fSschwartz { 51169cd775fSschwartz int rval; 512dabea0dbSschwartz uint64_t off_in_space; 51369cd775fSschwartz pcitool_reg_t cfg_prg = *prg_p; /* Make local copy. */ 51469cd775fSschwartz dev_info_t *dip = px_p->px_dip; 51569cd775fSschwartz 51669cd775fSschwartz *space_p = PCI_MEM32_SPACE; 51769cd775fSschwartz *bar_p = 0; 51869cd775fSschwartz 51969cd775fSschwartz /* 52069cd775fSschwartz * Translate BAR number into offset of the BAR in 52169cd775fSschwartz * the device's config space. 52269cd775fSschwartz */ 52369cd775fSschwartz cfg_prg.acc_attr = 52469cd775fSschwartz PCITOOL_ACC_ATTR_SIZE_4 | PCITOOL_ACC_ATTR_ENDN_LTL; 52569cd775fSschwartz 526dabea0dbSschwartz /* 527dabea0dbSschwartz * Note: sun4u acc function uses phys_addr which includes offset. 528dabea0dbSschwartz * sun4v acc function doesn't use phys_addr but uses cfg_prg.offset. 529dabea0dbSschwartz */ 530dabea0dbSschwartz cfg_prg.offset = PCI_BAR_OFFSET((*prg_p)); 531d3533785Sschwartz off_in_space = PX_GET_BDF(prg_p) + cfg_prg.offset; 532dabea0dbSschwartz cfg_prg.phys_addr = pxtool_get_phys_addr(px_p, PCI_CONFIG_SPACE, 533dabea0dbSschwartz off_in_space); 534dabea0dbSschwartz 535dabea0dbSschwartz DBG(DBG_TOOLS, dip, 536dabea0dbSschwartz "off_in_space:0x%" PRIx64 ", phys_addr:0x%" PRIx64 ", barnum:%d\n", 537dabea0dbSschwartz off_in_space, cfg_prg.phys_addr, cfg_prg.barnum); 53869cd775fSschwartz 53969cd775fSschwartz /* 54069cd775fSschwartz * Get Bus Address Register (BAR) from config space. 54169cd775fSschwartz * cfg_prg.offset is the offset into config space of the 54269cd775fSschwartz * BAR desired. prg_p->status is modified on error. 54369cd775fSschwartz */ 544dabea0dbSschwartz rval = pxtool_pcicfg_access(px_p, &cfg_prg, bar_p, PX_ISREAD); 54569cd775fSschwartz 54669cd775fSschwartz if (rval != SUCCESS) { 54769cd775fSschwartz prg_p->status = cfg_prg.status; 54869cd775fSschwartz return (rval); 54969cd775fSschwartz } 55069cd775fSschwartz 55169cd775fSschwartz DBG(DBG_TOOLS, dip, "bar returned is 0x%" PRIx64 "\n", *bar_p); 55269cd775fSschwartz 55369cd775fSschwartz /* 55469cd775fSschwartz * BAR has bits saying this space is IO space, unless 55569cd775fSschwartz * this is the ROM address register. 55669cd775fSschwartz */ 55769cd775fSschwartz if (((PCI_BASE_SPACE_M & *bar_p) == PCI_BASE_SPACE_IO) && 55869cd775fSschwartz (cfg_prg.offset != PCI_CONF_ROM)) { 55969cd775fSschwartz *space_p = PCI_IO_SPACE; 56069cd775fSschwartz *bar_p &= PCI_BASE_IO_ADDR_M; 56169cd775fSschwartz 56269cd775fSschwartz /* 56369cd775fSschwartz * BAR has bits saying this space is 64 bit memory 56469cd775fSschwartz * space, unless this is the ROM address register. 56569cd775fSschwartz * 56669cd775fSschwartz * The 64 bit address stored in two BAR cells is not 56769cd775fSschwartz * necessarily aligned on an 8-byte boundary. 56869cd775fSschwartz * Need to keep the first 4 bytes read, 56969cd775fSschwartz * and do a separate read of the high 4 bytes. 57069cd775fSschwartz */ 57169cd775fSschwartz } else if ((PCI_BASE_TYPE_ALL & *bar_p) && 57269cd775fSschwartz (cfg_prg.offset != PCI_CONF_ROM)) { 57369cd775fSschwartz 57469cd775fSschwartz uint32_t low_bytes = (uint32_t)(*bar_p & ~PCI_BASE_TYPE_ALL); 57569cd775fSschwartz 57669cd775fSschwartz /* Don't try to read the next 4 bytes past the end of BARs. */ 57769cd775fSschwartz if (cfg_prg.offset >= PCI_CONF_BASE5) { 57869cd775fSschwartz prg_p->status = PCITOOL_OUT_OF_RANGE; 57969cd775fSschwartz return (EIO); 58069cd775fSschwartz } 58169cd775fSschwartz 58269cd775fSschwartz /* Access device. prg_p->status is modified on error. */ 58369cd775fSschwartz cfg_prg.phys_addr += sizeof (uint32_t); 58469cd775fSschwartz cfg_prg.offset += sizeof (uint32_t); 58569cd775fSschwartz 586dabea0dbSschwartz rval = pxtool_pcicfg_access(px_p, &cfg_prg, bar_p, PX_ISREAD); 58769cd775fSschwartz if (rval != SUCCESS) { 58869cd775fSschwartz prg_p->status = cfg_prg.status; 58969cd775fSschwartz return (rval); 59069cd775fSschwartz } 59169cd775fSschwartz 59269cd775fSschwartz /* 59369cd775fSschwartz * Honor the 64 bit BAR as such, only when the upper 32 bits 59469cd775fSschwartz * store a non-zero value. 59569cd775fSschwartz */ 59669cd775fSschwartz if (*bar_p) { 59769cd775fSschwartz *space_p = PCI_MEM64_SPACE; 59869cd775fSschwartz *bar_p = (*bar_p << 32) | low_bytes; 59969cd775fSschwartz } else 60069cd775fSschwartz *bar_p = low_bytes; 60169cd775fSschwartz 60269cd775fSschwartz } else if (cfg_prg.offset == PCI_CONF_ROM) { /* ROM requested */ 60369cd775fSschwartz 60469cd775fSschwartz /* 60569cd775fSschwartz * ROM enabled. Filter ROM enable bit from the BAR. 60669cd775fSschwartz * Treat as Mem32 henceforth. 60769cd775fSschwartz */ 60869cd775fSschwartz if (!(*bar_p & PCI_BASE_ROM_ENABLE)) 60969cd775fSschwartz *bar_p ^= PCI_BASE_ROM_ENABLE; 61069cd775fSschwartz 61169cd775fSschwartz else { /* ROM disabled. */ 61269cd775fSschwartz prg_p->status = PCITOOL_ROM_DISABLED; 61369cd775fSschwartz return (EIO); 61469cd775fSschwartz } 61569cd775fSschwartz } 61669cd775fSschwartz 61769cd775fSschwartz /* Accept a bar of 0 only for IO space. */ 61869cd775fSschwartz if ((*space_p != PCI_IO_SPACE) && (!(*bar_p))) { 61969cd775fSschwartz prg_p->status = PCITOOL_INVALID_ADDRESS; 62069cd775fSschwartz return (EINVAL); 62169cd775fSschwartz } 62269cd775fSschwartz 62369cd775fSschwartz return (SUCCESS); 62469cd775fSschwartz } 62569cd775fSschwartz 62669cd775fSschwartz 62769cd775fSschwartz /* Perform register accesses on PCI leaf devices. */ 62869cd775fSschwartz int 62969cd775fSschwartz pxtool_dev_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode) 63069cd775fSschwartz { 63169cd775fSschwartz pcitool_reg_t prg; 63269cd775fSschwartz uint64_t bar; 63369cd775fSschwartz uint32_t space; 634dabea0dbSschwartz uint64_t off_in_space; 63569cd775fSschwartz boolean_t write_flag = B_FALSE; 63669cd775fSschwartz px_t *px_p = DIP_TO_STATE(dip); 63769cd775fSschwartz int rval = 0; 63869cd775fSschwartz 63969cd775fSschwartz if (cmd == PCITOOL_DEVICE_SET_REG) 64069cd775fSschwartz write_flag = B_TRUE; 64169cd775fSschwartz 64269cd775fSschwartz DBG(DBG_TOOLS, dip, "pxtool_dev_reg_ops set/get reg\n"); 64369cd775fSschwartz if (ddi_copyin(arg, &prg, sizeof (pcitool_reg_t), 64469cd775fSschwartz mode) != DDI_SUCCESS) { 64569cd775fSschwartz DBG(DBG_TOOLS, dip, "Error reading arguments\n"); 64669cd775fSschwartz return (EFAULT); 64769cd775fSschwartz } 64869cd775fSschwartz 64969cd775fSschwartz if ((rval = pxtool_dev_reg_ops_platchk(dip, &prg)) != SUCCESS) { 65069cd775fSschwartz goto done_reg; 65169cd775fSschwartz } 65269cd775fSschwartz 65369cd775fSschwartz DBG(DBG_TOOLS, dip, "raw bus:0x%x, dev:0x%x, func:0x%x\n", 65469cd775fSschwartz prg.bus_no, prg.dev_no, prg.func_no); 65569cd775fSschwartz DBG(DBG_TOOLS, dip, "barnum:0x%x, offset:0x%" PRIx64 ", acc:0x%x\n", 65669cd775fSschwartz prg.barnum, prg.offset, prg.acc_attr); 65769cd775fSschwartz 65869cd775fSschwartz if ((rval = pxtool_validate_barnum_bdf(&prg)) != SUCCESS) 65969cd775fSschwartz goto done_reg; 66069cd775fSschwartz 66169cd775fSschwartz if (prg.barnum == 0) { /* Proper config space desired. */ 66269cd775fSschwartz 663dabea0dbSschwartz /* Enforce offset limits. */ 664dabea0dbSschwartz if (prg.offset >= DEV_CFG_SPACE_SIZE) { 665dabea0dbSschwartz DBG(DBG_TOOLS, dip, 666dabea0dbSschwartz "Config space offset 0x%" PRIx64 " out of range\n", 667dabea0dbSschwartz prg.offset); 668dabea0dbSschwartz prg.status = PCITOOL_OUT_OF_RANGE; 669dabea0dbSschwartz rval = EINVAL; 670dabea0dbSschwartz goto done_reg; 671dabea0dbSschwartz } 672dabea0dbSschwartz 673dabea0dbSschwartz /* 674dabea0dbSschwartz * For sun4v, config space base won't be known. 675dabea0dbSschwartz * pxtool_get_phys_addr will return zero. 676dabea0dbSschwartz * Note that for sun4v, phys_addr isn't 677dabea0dbSschwartz * used for making config space accesses. 678dabea0dbSschwartz * 679dabea0dbSschwartz * For sun4u, assume that phys_addr will come back valid. 680dabea0dbSschwartz */ 681d3533785Sschwartz /* 682d3533785Sschwartz * Accessed entity is assumed small enough to be on one page. 683d3533785Sschwartz * 684d3533785Sschwartz * Since config space is less than a page and is aligned to 685d3533785Sschwartz * 0x1000, a device's entire config space will be on a single 686d3533785Sschwartz * page. Pass the device's base config space address here, 687d3533785Sschwartz * then add the offset within that space later. This works 688d3533785Sschwartz * around an issue in px_xlate_reg (called by 689d3533785Sschwartz * pxtool_get_phys_addr) which accepts only a 256 byte 690d3533785Sschwartz * range within a device. 691d3533785Sschwartz */ 692d3533785Sschwartz off_in_space = PX_GET_BDF(&prg); 693d3533785Sschwartz prg.phys_addr = 694d3533785Sschwartz pxtool_get_phys_addr(px_p, PCI_CONFIG_SPACE, off_in_space); 695d3533785Sschwartz prg.phys_addr += prg.offset; 69669cd775fSschwartz 69769cd775fSschwartz DBG(DBG_TOOLS, dip, 698dabea0dbSschwartz "off_in_space:0x%" PRIx64 ", phys_addr:0x%" PRIx64 ", " 699dabea0dbSschwartz "end:%s\n", off_in_space, prg.phys_addr, 70069cd775fSschwartz PCITOOL_ACC_IS_BIG_ENDIAN(prg.acc_attr) ? "big":"ltl"); 70169cd775fSschwartz 70269cd775fSschwartz /* 70369cd775fSschwartz * Access device. pr.status is modified. 70469cd775fSschwartz * BDF is assumed valid at this point. 70569cd775fSschwartz */ 706dabea0dbSschwartz rval = pxtool_pcicfg_access(px_p, &prg, &prg.data, write_flag); 70769cd775fSschwartz goto done_reg; 70869cd775fSschwartz } 70969cd775fSschwartz 71069cd775fSschwartz /* IO/ MEM/ MEM64 space. */ 71169cd775fSschwartz 712dabea0dbSschwartz if ((rval = pxtool_get_bar(px_p, &prg, &bar, &space)) != SUCCESS) 71369cd775fSschwartz goto done_reg; 71469cd775fSschwartz 715dabea0dbSschwartz switch (space) { 716dabea0dbSschwartz case PCI_MEM32_SPACE: 71769cd775fSschwartz 71869cd775fSschwartz DBG(DBG_TOOLS, dip, "32 bit mem space\n"); 71969cd775fSschwartz 72069cd775fSschwartz /* Can't write to ROM */ 72169cd775fSschwartz if ((PCI_BAR_OFFSET(prg) == PCI_CONF_ROM) && (write_flag)) { 72269cd775fSschwartz prg.status = PCITOOL_ROM_WRITE; 72369cd775fSschwartz rval = EIO; 72469cd775fSschwartz goto done_reg; 72569cd775fSschwartz } 726dabea0dbSschwartz break; 72769cd775fSschwartz 728dabea0dbSschwartz case PCI_IO_SPACE: 729dabea0dbSschwartz DBG(DBG_TOOLS, dip, "IO space\n"); 730dabea0dbSschwartz break; 731dabea0dbSschwartz 732dabea0dbSschwartz case PCI_MEM64_SPACE: 733dabea0dbSschwartz DBG(DBG_TOOLS, dip, 734dabea0dbSschwartz "64 bit mem space. 64-bit bar is 0x%" PRIx64 "\n", bar); 735dabea0dbSschwartz break; 736dabea0dbSschwartz 737dabea0dbSschwartz default: 738dabea0dbSschwartz DBG(DBG_TOOLS, dip, "Unknown space!\n"); 739dabea0dbSschwartz prg.status = PCITOOL_IO_ERROR; 740dabea0dbSschwartz rval = EIO; 741dabea0dbSschwartz goto done_reg; 74269cd775fSschwartz } 74369cd775fSschwartz 74469cd775fSschwartz /* 745dabea0dbSschwartz * Common code for all IO/MEM range spaces. 746dabea0dbSschwartz * 74769cd775fSschwartz * Use offset provided by caller to index into desired space. 74869cd775fSschwartz * Note that prg.status is modified on error. 74969cd775fSschwartz */ 750dabea0dbSschwartz off_in_space = bar + prg.offset; 751dabea0dbSschwartz prg.phys_addr = pxtool_get_phys_addr(px_p, space, off_in_space); 75269cd775fSschwartz 753dabea0dbSschwartz DBG(DBG_TOOLS, dip, 754dabea0dbSschwartz "addr in bar:0x%" PRIx64 ", offset:0x%" PRIx64 ", " 755dabea0dbSschwartz "phys_addr:0x%" PRIx64 "\n", bar, prg.offset, prg.phys_addr); 756dabea0dbSschwartz 757dabea0dbSschwartz rval = pxtool_pciiomem_access(px_p, &prg, &prg.data, write_flag); 75869cd775fSschwartz 75969cd775fSschwartz done_reg: 7602917a9c9Sschwartz prg.drvr_version = PCITOOL_VERSION; 76169cd775fSschwartz if (ddi_copyout(&prg, arg, sizeof (pcitool_reg_t), 76269cd775fSschwartz mode) != DDI_SUCCESS) { 76369cd775fSschwartz DBG(DBG_TOOLS, dip, "Error returning arguments.\n"); 76469cd775fSschwartz rval = EFAULT; 76569cd775fSschwartz } 76669cd775fSschwartz return (rval); 76769cd775fSschwartz } 76869cd775fSschwartz 76969cd775fSschwartz 77069cd775fSschwartz int 77169cd775fSschwartz pxtool_init(dev_info_t *dip) 77269cd775fSschwartz { 77369cd775fSschwartz int instance = ddi_get_instance(dip); 77469cd775fSschwartz 77569cd775fSschwartz if (ddi_create_minor_node(dip, PCI_MINOR_REG, S_IFCHR, 776*26947304SEvan Yan PCI_MINOR_NUM(instance, PCI_TOOL_REG_MINOR_NUM), 77769cd775fSschwartz DDI_NT_REGACC, 0) != DDI_SUCCESS) { 77869cd775fSschwartz return (DDI_FAILURE); 77969cd775fSschwartz } 78069cd775fSschwartz 78169cd775fSschwartz if (ddi_create_minor_node(dip, PCI_MINOR_INTR, S_IFCHR, 782*26947304SEvan Yan PCI_MINOR_NUM(instance, PCI_TOOL_INTR_MINOR_NUM), 78369cd775fSschwartz DDI_NT_INTRCTL, 0) != DDI_SUCCESS) { 78469cd775fSschwartz ddi_remove_minor_node(dip, PCI_MINOR_REG); 78569cd775fSschwartz return (DDI_FAILURE); 78669cd775fSschwartz } 78769cd775fSschwartz 78869cd775fSschwartz return (DDI_SUCCESS); 78969cd775fSschwartz } 79069cd775fSschwartz 79169cd775fSschwartz 79269cd775fSschwartz void 79369cd775fSschwartz pxtool_uninit(dev_info_t *dip) 79469cd775fSschwartz { 79569cd775fSschwartz ddi_remove_minor_node(dip, PCI_MINOR_REG); 79669cd775fSschwartz ddi_remove_minor_node(dip, PCI_MINOR_INTR); 79769cd775fSschwartz } 798