xref: /illumos-gate/usr/src/uts/sun4/io/px/px_tools.c (revision e214b19eaa16fec1fa60a97227778103f598336f)
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
pxtool_intr_info(dev_info_t * dip,void * arg,int mode)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
pxtool_get_intr(dev_info_t * dip,void * arg,int mode)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
pxtool_set_intr(dev_info_t * dip,void * arg,int mode)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
pxtool_intr(dev_info_t * dip,void * arg,int cmd,int mode)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
pxtool_validate_barnum_bdf(pcitool_reg_t * prg)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
pxtool_get_phys_addr(px_t * px_p,int space,uint64_t offset)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)
491*e214b19eSToomas Soome 		return ((uintptr_t)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
pxtool_get_bar(px_t * px_p,pcitool_reg_t * prg_p,uint64_t * bar_p,uint32_t * space_p)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
pxtool_dev_reg_ops(dev_info_t * dip,void * arg,int cmd,int mode)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
pxtool_init(dev_info_t * dip)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,
77626947304SEvan 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,
78226947304SEvan 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
pxtool_uninit(dev_info_t * dip)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