xref: /onnv-gate/usr/src/uts/sun4/io/px/px_msi.c (revision 11596:e9010337bcd3)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
58561SScott.Carter@Sun.COM  * Common Development and Distribution License (the "License").
68561SScott.Carter@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*11596SJason.Beloro@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * px_msi.c
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <sys/kmem.h>
320Sstevel@tonic-gate #include <sys/conf.h>
330Sstevel@tonic-gate #include <sys/ddi.h>
340Sstevel@tonic-gate #include <sys/sunddi.h>
350Sstevel@tonic-gate #include <sys/sunndi.h>
360Sstevel@tonic-gate #include <sys/modctl.h>
370Sstevel@tonic-gate #include <sys/disp.h>
380Sstevel@tonic-gate #include <sys/stat.h>
390Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
400Sstevel@tonic-gate #include <sys/pci_impl.h>
410Sstevel@tonic-gate #include "px_obj.h"
420Sstevel@tonic-gate 
430Sstevel@tonic-gate static int px_msi_get_props(px_t *px_p);
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate  * msi_attach()
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate int
px_msi_attach(px_t * px_p)490Sstevel@tonic-gate px_msi_attach(px_t *px_p)
500Sstevel@tonic-gate {
510Sstevel@tonic-gate 	dev_info_t		*dip = px_p->px_dip;
520Sstevel@tonic-gate 	px_msi_state_t		*msi_state_p = &px_p->px_ib_p->ib_msi_state;
538561SScott.Carter@Sun.COM 	ddi_irm_pool_t		*irm_pool_p = NULL;
548561SScott.Carter@Sun.COM 	ddi_irm_params_t	irm_params;
550Sstevel@tonic-gate 	msinum_t		msi_num;
560Sstevel@tonic-gate 	int			i, ret;
570Sstevel@tonic-gate 
580Sstevel@tonic-gate 	DBG(DBG_MSIQ, dip, "px_msi_attach\n");
590Sstevel@tonic-gate 
600Sstevel@tonic-gate 	mutex_init(&msi_state_p->msi_mutex, NULL, MUTEX_DRIVER, NULL);
610Sstevel@tonic-gate 
620Sstevel@tonic-gate 	/*
630Sstevel@tonic-gate 	 * Check for all MSI related properties and
640Sstevel@tonic-gate 	 * save all information.
650Sstevel@tonic-gate 	 */
660Sstevel@tonic-gate 	if (px_msi_get_props(px_p) != DDI_SUCCESS) {
670Sstevel@tonic-gate 		px_msi_detach(px_p);
680Sstevel@tonic-gate 		return (DDI_FAILURE);
690Sstevel@tonic-gate 	}
700Sstevel@tonic-gate 
71*11596SJason.Beloro@Sun.COM 	px_p->px_supp_intr_types |= (DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_MSIX);
72*11596SJason.Beloro@Sun.COM 
730Sstevel@tonic-gate 	msi_state_p->msi_p = kmem_zalloc(msi_state_p->msi_cnt *
740Sstevel@tonic-gate 	    sizeof (px_msi_t), KM_SLEEP);
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	for (i = 0, msi_num = msi_state_p->msi_1st_msinum;
778561SScott.Carter@Sun.COM 	    i < msi_state_p->msi_cnt; i++, msi_num++) {
780Sstevel@tonic-gate 		msi_state_p->msi_p[i].msi_msinum = msi_num;
790Sstevel@tonic-gate 		msi_state_p->msi_p[i].msi_state = MSI_STATE_FREE;
800Sstevel@tonic-gate 	}
810Sstevel@tonic-gate 
828561SScott.Carter@Sun.COM 	/*
838561SScott.Carter@Sun.COM 	 * Create IRM pool to manage interrupt allocations.
848561SScott.Carter@Sun.COM 	 */
858561SScott.Carter@Sun.COM 	bzero(&irm_params, sizeof (ddi_irm_params_t));
868561SScott.Carter@Sun.COM 	irm_params.iparams_types = msi_state_p->msi_type;
878561SScott.Carter@Sun.COM 	irm_params.iparams_total = msi_state_p->msi_cnt;
888561SScott.Carter@Sun.COM 	if (ndi_irm_create(dip, &irm_params, &irm_pool_p) == DDI_SUCCESS) {
898561SScott.Carter@Sun.COM 		msi_state_p->msi_pool_p = irm_pool_p;
908561SScott.Carter@Sun.COM 	} else {
918561SScott.Carter@Sun.COM 		DBG(DBG_MSIQ, dip, "ndi_irm_create() failed\n");
928561SScott.Carter@Sun.COM 	}
938561SScott.Carter@Sun.COM 
940Sstevel@tonic-gate 	if ((ret = px_lib_msi_init(dip)) != DDI_SUCCESS)
950Sstevel@tonic-gate 		px_msi_detach(px_p);
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 	return (ret);
980Sstevel@tonic-gate }
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate /*
1020Sstevel@tonic-gate  * msi_detach()
1030Sstevel@tonic-gate  */
1040Sstevel@tonic-gate void
px_msi_detach(px_t * px_p)1050Sstevel@tonic-gate px_msi_detach(px_t *px_p)
1060Sstevel@tonic-gate {
1070Sstevel@tonic-gate 	dev_info_t	*dip = px_p->px_dip;
1080Sstevel@tonic-gate 	px_msi_state_t	*msi_state_p = &px_p->px_ib_p->ib_msi_state;
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	DBG(DBG_MSIQ, dip, "px_msi_detach\n");
1110Sstevel@tonic-gate 
11210923SEvan.Yan@Sun.COM 	if (msi_state_p->msi_pool_p)
1138561SScott.Carter@Sun.COM 		(void) ndi_irm_destroy(msi_state_p->msi_pool_p);
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	if (msi_state_p->msi_p) {
1160Sstevel@tonic-gate 		kmem_free(msi_state_p->msi_p,
1170Sstevel@tonic-gate 		    msi_state_p->msi_cnt * sizeof (px_msi_t));
1180Sstevel@tonic-gate 	}
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	mutex_destroy(&msi_state_p->msi_mutex);
1210Sstevel@tonic-gate 	bzero(&px_p->px_ib_p->ib_msi_state, sizeof (px_msi_state_t));
1220Sstevel@tonic-gate }
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate /*
1260Sstevel@tonic-gate  * msi_alloc()
1270Sstevel@tonic-gate  */
1280Sstevel@tonic-gate /* ARGSUSED */
1290Sstevel@tonic-gate int
px_msi_alloc(px_t * px_p,dev_info_t * rdip,int type,int inum,int msi_count,int flag,int * actual_msi_count_p)1308561SScott.Carter@Sun.COM px_msi_alloc(px_t *px_p, dev_info_t *rdip, int type, int inum, int msi_count,
1318561SScott.Carter@Sun.COM     int flag, int *actual_msi_count_p)
1320Sstevel@tonic-gate {
1330Sstevel@tonic-gate 	px_msi_state_t	*msi_state_p = &px_p->px_ib_p->ib_msi_state;
1348561SScott.Carter@Sun.COM 	int		first, count, i, n;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	DBG(DBG_A_MSIX, px_p->px_dip, "px_msi_alloc: rdip %s:%d "
1378561SScott.Carter@Sun.COM 	    "type 0x%x inum 0x%x msi_count 0x%x\n", ddi_driver_name(rdip),
1388561SScott.Carter@Sun.COM 	    ddi_get_instance(rdip), type, inum, msi_count);
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 	mutex_enter(&msi_state_p->msi_mutex);
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	*actual_msi_count_p = 0;
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	/*
1458561SScott.Carter@Sun.COM 	 * MSI interrupts are allocated as contiguous ranges at
1468561SScott.Carter@Sun.COM 	 * power of 2 boundaries from the start of the MSI array.
1470Sstevel@tonic-gate 	 */
1488561SScott.Carter@Sun.COM 	if (type == DDI_INTR_TYPE_MSI) {
1490Sstevel@tonic-gate 
1508561SScott.Carter@Sun.COM 		/* Search for a range of available interrupts */
1518561SScott.Carter@Sun.COM 		for (count = msi_count; count; count >>= 1) {
1528561SScott.Carter@Sun.COM 			for (first = 0; (first + count) < msi_state_p->msi_cnt;
1538561SScott.Carter@Sun.COM 			    first += count) {
1548561SScott.Carter@Sun.COM 				for (i = first; i < (first + count); i++) {
1558561SScott.Carter@Sun.COM 					if (msi_state_p->msi_p[i].msi_state
1568561SScott.Carter@Sun.COM 					    != MSI_STATE_FREE) {
1578561SScott.Carter@Sun.COM 						break;
1588561SScott.Carter@Sun.COM 					}
1598561SScott.Carter@Sun.COM 				}
1608561SScott.Carter@Sun.COM 				if (i == (first + count)) {
1618561SScott.Carter@Sun.COM 					goto found_msi;
1628561SScott.Carter@Sun.COM 				}
1638561SScott.Carter@Sun.COM 			}
1648561SScott.Carter@Sun.COM 			DBG(DBG_A_MSIX, px_p->px_dip, "px_msi_alloc: failed\n");
1658561SScott.Carter@Sun.COM 			if (count > 1) {
1668561SScott.Carter@Sun.COM 				DBG(DBG_A_MSIX, px_p->px_dip, "px_msi_alloc: "
1678561SScott.Carter@Sun.COM 				    "Retry MSI allocation with new msi_count "
1688561SScott.Carter@Sun.COM 				    "0x%x\n", count >> 1);
1698561SScott.Carter@Sun.COM 			}
1708561SScott.Carter@Sun.COM 		}
1718561SScott.Carter@Sun.COM 
1728561SScott.Carter@Sun.COM found_msi:
1738561SScott.Carter@Sun.COM 		/* Set number of available interrupts */
1748561SScott.Carter@Sun.COM 		*actual_msi_count_p = count;
1758561SScott.Carter@Sun.COM 
1768561SScott.Carter@Sun.COM 		/* Check if successful, and enforce strict behavior */
1778561SScott.Carter@Sun.COM 		if ((count == 0) ||
1788561SScott.Carter@Sun.COM 		    ((flag == DDI_INTR_ALLOC_STRICT) && (count != msi_count))) {
1798561SScott.Carter@Sun.COM 			mutex_exit(&msi_state_p->msi_mutex);
1808561SScott.Carter@Sun.COM 			return (DDI_EAGAIN);
1818561SScott.Carter@Sun.COM 		}
1828561SScott.Carter@Sun.COM 
1838561SScott.Carter@Sun.COM 		/* Allocate the interrupts */
1848561SScott.Carter@Sun.COM 		for (i = first; i < (first + count); i++, inum++) {
1858561SScott.Carter@Sun.COM 			msi_state_p->msi_p[i].msi_state = MSI_STATE_INUSE;
1868561SScott.Carter@Sun.COM 			msi_state_p->msi_p[i].msi_dip = rdip;
1878561SScott.Carter@Sun.COM 			msi_state_p->msi_p[i].msi_inum = inum;
1880Sstevel@tonic-gate 		}
1890Sstevel@tonic-gate 	}
1900Sstevel@tonic-gate 
1918561SScott.Carter@Sun.COM 	/*
1928561SScott.Carter@Sun.COM 	 * MSI-X interrupts are allocated from the end of the MSI
1938561SScott.Carter@Sun.COM 	 * array.  There are no concerns about power of 2 boundaries
1948561SScott.Carter@Sun.COM 	 * and the allocated interrupts do not have to be contiguous.
1958561SScott.Carter@Sun.COM 	 */
1968561SScott.Carter@Sun.COM 	if (type == DDI_INTR_TYPE_MSIX) {
1970Sstevel@tonic-gate 
1988561SScott.Carter@Sun.COM 		/* Count available interrupts, up to count requested */
1998561SScott.Carter@Sun.COM 		for (count = 0, i = (msi_state_p->msi_cnt - 1); i >= 0; i--) {
2008561SScott.Carter@Sun.COM 			if (msi_state_p->msi_p[i].msi_state == MSI_STATE_FREE) {
2018561SScott.Carter@Sun.COM 				if (count == 0)
2028561SScott.Carter@Sun.COM 					first = i;
2038561SScott.Carter@Sun.COM 				count++;
2048561SScott.Carter@Sun.COM 				if (count == msi_count)
2058561SScott.Carter@Sun.COM 					break;
2068561SScott.Carter@Sun.COM 			}
2070Sstevel@tonic-gate 		}
2080Sstevel@tonic-gate 
2098561SScott.Carter@Sun.COM 		/* Set number of available interrupts */
2108561SScott.Carter@Sun.COM 		*actual_msi_count_p = count;
2110Sstevel@tonic-gate 
2128561SScott.Carter@Sun.COM 		/* Check if successful, and enforce strict behavior */
2138561SScott.Carter@Sun.COM 		if ((count == 0) ||
2148561SScott.Carter@Sun.COM 		    ((flag == DDI_INTR_ALLOC_STRICT) && (count != msi_count))) {
2158561SScott.Carter@Sun.COM 			mutex_exit(&msi_state_p->msi_mutex);
2168561SScott.Carter@Sun.COM 			return (DDI_EAGAIN);
2178561SScott.Carter@Sun.COM 		}
2180Sstevel@tonic-gate 
2198561SScott.Carter@Sun.COM 		/* Allocate the interrupts */
2208561SScott.Carter@Sun.COM 		for (n = 0, i = first; n < count; i--) {
2218561SScott.Carter@Sun.COM 			if (msi_state_p->msi_p[i].msi_state != MSI_STATE_FREE)
2228561SScott.Carter@Sun.COM 				continue;
2238561SScott.Carter@Sun.COM 			msi_state_p->msi_p[i].msi_state = MSI_STATE_INUSE;
2248561SScott.Carter@Sun.COM 			msi_state_p->msi_p[i].msi_dip = rdip;
2258561SScott.Carter@Sun.COM 			msi_state_p->msi_p[i].msi_inum = inum;
2268561SScott.Carter@Sun.COM 			inum++;
2278561SScott.Carter@Sun.COM 			n++;
2288561SScott.Carter@Sun.COM 		}
2290Sstevel@tonic-gate 	}
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	DBG(DBG_A_MSIX, px_p->px_dip, "px_msi_alloc: rdip %s:%d "
2320Sstevel@tonic-gate 	    "msi_num 0x%x count 0x%x\n", ddi_driver_name(rdip),
2338561SScott.Carter@Sun.COM 	    ddi_get_instance(rdip), first, count);
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	mutex_exit(&msi_state_p->msi_mutex);
2368561SScott.Carter@Sun.COM 
2370Sstevel@tonic-gate 	return (DDI_SUCCESS);
2380Sstevel@tonic-gate }
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate /*
2420Sstevel@tonic-gate  * msi_free()
2430Sstevel@tonic-gate  */
2440Sstevel@tonic-gate int
px_msi_free(px_t * px_p,dev_info_t * rdip,int inum,int msi_count)2450Sstevel@tonic-gate px_msi_free(px_t *px_p, dev_info_t *rdip, int inum, int msi_count)
2460Sstevel@tonic-gate {
2470Sstevel@tonic-gate 	px_msi_state_t	*msi_state_p = &px_p->px_ib_p->ib_msi_state;
2488561SScott.Carter@Sun.COM 	int		i, n;
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	DBG(DBG_R_MSIX, px_p->px_dip, "px_msi_free: rdip 0x%p "
2510Sstevel@tonic-gate 	    "inum 0x%x msi_count 0x%x\n", rdip, inum, msi_count);
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	mutex_enter(&msi_state_p->msi_mutex);
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	/*
2568561SScott.Carter@Sun.COM 	 * Find and release the specified MSI/X numbers.
2578561SScott.Carter@Sun.COM 	 *
2588561SScott.Carter@Sun.COM 	 * Because the allocations are not always contiguous, perform
2598561SScott.Carter@Sun.COM 	 * a full linear search of the MSI/X table looking for MSI/X
2608561SScott.Carter@Sun.COM 	 * vectors owned by the device with inum values in the range
2618561SScott.Carter@Sun.COM 	 * [inum .. (inum + msi_count - 1)].
2620Sstevel@tonic-gate 	 */
2638561SScott.Carter@Sun.COM 	for (i = 0, n = 0; (i < msi_state_p->msi_cnt) && (n < msi_count); i++) {
2648561SScott.Carter@Sun.COM 		if ((msi_state_p->msi_p[i].msi_dip == rdip) &&
2658561SScott.Carter@Sun.COM 		    (msi_state_p->msi_p[i].msi_inum >= inum) &&
2668561SScott.Carter@Sun.COM 		    (msi_state_p->msi_p[i].msi_inum < (inum + msi_count))) {
2678561SScott.Carter@Sun.COM 			msi_state_p->msi_p[i].msi_dip = NULL;
2688561SScott.Carter@Sun.COM 			msi_state_p->msi_p[i].msi_inum = 0;
2698561SScott.Carter@Sun.COM 			msi_state_p->msi_p[i].msi_msiq_id = 0;
2708561SScott.Carter@Sun.COM 			msi_state_p->msi_p[i].msi_state = MSI_STATE_FREE;
2718561SScott.Carter@Sun.COM 			n++;
2720Sstevel@tonic-gate 		}
2730Sstevel@tonic-gate 	}
2740Sstevel@tonic-gate 
2758561SScott.Carter@Sun.COM 	mutex_exit(&msi_state_p->msi_mutex);
2760Sstevel@tonic-gate 
2778561SScott.Carter@Sun.COM 	/* Fail if the MSI/X numbers were not found */
2788561SScott.Carter@Sun.COM 	if (n < msi_count)
2798561SScott.Carter@Sun.COM 		return (DDI_FAILURE);
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	return (DDI_SUCCESS);
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate /*
2850Sstevel@tonic-gate  * msi_get_msinum()
2860Sstevel@tonic-gate  */
2870Sstevel@tonic-gate int
px_msi_get_msinum(px_t * px_p,dev_info_t * rdip,int inum,msinum_t * msi_num_p)2880Sstevel@tonic-gate px_msi_get_msinum(px_t *px_p, dev_info_t *rdip, int inum, msinum_t *msi_num_p)
2890Sstevel@tonic-gate {
2900Sstevel@tonic-gate 	px_msi_state_t	*msi_state_p = &px_p->px_ib_p->ib_msi_state;
2910Sstevel@tonic-gate 	int		i;
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	DBG(DBG_A_MSIX, px_p->px_dip, "px_msi_get_msinum: "
2940Sstevel@tonic-gate 	    "rdip 0x%p inum 0x%x\n", rdip, inum);
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	mutex_enter(&msi_state_p->msi_mutex);
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	for (i = 0; i < msi_state_p->msi_cnt; i++) {
2990Sstevel@tonic-gate 		if ((msi_state_p->msi_p[i].msi_inum == inum) &&
3000Sstevel@tonic-gate 		    (msi_state_p->msi_p[i].msi_dip == rdip)) {
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 			*msi_num_p = msi_state_p->msi_p[i].msi_msinum;
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 			DBG(DBG_A_MSIX, px_p->px_dip, "px_msi_get_msinum: "
3050Sstevel@tonic-gate 			    "inum 0x%x msi 0x%x\n", inum, *msi_num_p);
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 			mutex_exit(&msi_state_p->msi_mutex);
3080Sstevel@tonic-gate 			return (DDI_SUCCESS);
3090Sstevel@tonic-gate 		}
3100Sstevel@tonic-gate 	}
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	if (i >= msi_state_p->msi_cnt)
3130Sstevel@tonic-gate 		DBG(DBG_A_MSIX, px_p->px_dip, "px_msi_get_msinum: "
3140Sstevel@tonic-gate 		    "no msi for inum 0x%x\n", inum);
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	mutex_exit(&msi_state_p->msi_mutex);
3170Sstevel@tonic-gate 	return (DDI_FAILURE);
3180Sstevel@tonic-gate }
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate /*
3210Sstevel@tonic-gate  * px_msi_get_props()
3220Sstevel@tonic-gate  */
3230Sstevel@tonic-gate static int
px_msi_get_props(px_t * px_p)3240Sstevel@tonic-gate px_msi_get_props(px_t *px_p)
3250Sstevel@tonic-gate {
32610923SEvan.Yan@Sun.COM 	dev_info_t	*dip = px_p->px_dip;
32710923SEvan.Yan@Sun.COM 	px_msi_state_t	*msi_state_p = &px_p->px_ib_p->ib_msi_state;
32810923SEvan.Yan@Sun.COM 	int		length = sizeof (int);
32910923SEvan.Yan@Sun.COM 	int		*valuep = NULL;
33010923SEvan.Yan@Sun.COM 	uint64_t	msi_addr_hi, msi_addr_lo;
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	DBG(DBG_MSIQ, dip, "px_msi_get_props\n");
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	/* #msi */
3350Sstevel@tonic-gate 	msi_state_p->msi_cnt = ddi_getprop(DDI_DEV_T_ANY, dip,
33610923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "#msi", 0);
3370Sstevel@tonic-gate 
33810923SEvan.Yan@Sun.COM 	DBG(DBG_MSIQ, dip, "#msi=%d\n", msi_state_p->msi_cnt);
33910923SEvan.Yan@Sun.COM 	if (msi_state_p->msi_cnt == 0)
34010923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	/* msi-ranges: msi# field */
34310923SEvan.Yan@Sun.COM 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_ALLOC,
34410923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "msi-ranges", (caddr_t)&valuep, &length)
34510923SEvan.Yan@Sun.COM 	    != DDI_PROP_SUCCESS)
34610923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
3470Sstevel@tonic-gate 
34810923SEvan.Yan@Sun.COM 	msi_state_p->msi_1st_msinum = ((px_msi_ranges_t *)valuep)->msi_no;
34910923SEvan.Yan@Sun.COM 	kmem_free(valuep, (size_t)length);
3500Sstevel@tonic-gate 
35110923SEvan.Yan@Sun.COM 	DBG(DBG_MSIQ, dip, "msi_1st_msinum=%d\n", msi_state_p->msi_1st_msinum);
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	/* msi-data-mask */
3540Sstevel@tonic-gate 	msi_state_p->msi_data_mask = ddi_getprop(DDI_DEV_T_ANY, dip,
35510923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "msi-data-mask", 0);
3560Sstevel@tonic-gate 
35710923SEvan.Yan@Sun.COM 	DBG(DBG_MSIQ, dip, "msi-data-mask=0x%x\n",
3580Sstevel@tonic-gate 	    msi_state_p->msi_data_mask);
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	/* msi-data-width */
3610Sstevel@tonic-gate 	msi_state_p->msi_data_width = ddi_getprop(DDI_DEV_T_ANY, dip,
36210923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "msix-data-width", 0);
3630Sstevel@tonic-gate 
36410923SEvan.Yan@Sun.COM 	DBG(DBG_MSIQ, dip, "msix-data-width=%d\n",
3650Sstevel@tonic-gate 	    msi_state_p->msi_data_width);
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	/*
3680Sstevel@tonic-gate 	 * Assume MSI is always supported, but also check if MSIX is supported
3690Sstevel@tonic-gate 	 */
3700Sstevel@tonic-gate 	if (msi_state_p->msi_data_width) {
3710Sstevel@tonic-gate 		msi_state_p->msi_type = DDI_INTR_TYPE_MSI;
3720Sstevel@tonic-gate 		if (msi_state_p->msi_data_width == PX_MSIX_WIDTH)
3730Sstevel@tonic-gate 			msi_state_p->msi_type |= DDI_INTR_TYPE_MSIX;
37410923SEvan.Yan@Sun.COM 	} else {
37510923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
3760Sstevel@tonic-gate 	}
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	/* msi-address-ranges */
37910923SEvan.Yan@Sun.COM 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_ALLOC,
38010923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "msi-address-ranges", (caddr_t)&valuep, &length)
38110923SEvan.Yan@Sun.COM 	    != DDI_PROP_SUCCESS)
38210923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
3830Sstevel@tonic-gate 
38410923SEvan.Yan@Sun.COM 	msi_addr_hi = ((px_msi_address_ranges_t *)valuep)->msi_addr32_hi;
38510923SEvan.Yan@Sun.COM 	msi_addr_lo = ((px_msi_address_ranges_t *)valuep)->msi_addr32_lo;
38610923SEvan.Yan@Sun.COM 	msi_state_p->msi_addr32 = (msi_addr_hi << 32) | msi_addr_lo;
38710923SEvan.Yan@Sun.COM 	msi_state_p->msi_addr32_len =
38810923SEvan.Yan@Sun.COM 	    ((px_msi_address_ranges_t *)valuep)->msi_addr32_len;
3890Sstevel@tonic-gate 
39010923SEvan.Yan@Sun.COM 	msi_addr_hi = ((px_msi_address_ranges_t *)valuep)->msi_addr64_hi;
39110923SEvan.Yan@Sun.COM 	msi_addr_lo = ((px_msi_address_ranges_t *)valuep)->msi_addr64_lo;
39210923SEvan.Yan@Sun.COM 	msi_state_p->msi_addr64 = (msi_addr_hi << 32) | msi_addr_lo;
39310923SEvan.Yan@Sun.COM 	msi_state_p->msi_addr64_len =
39410923SEvan.Yan@Sun.COM 	    ((px_msi_address_ranges_t *)valuep)->msi_addr64_len;
3950Sstevel@tonic-gate 
39610923SEvan.Yan@Sun.COM 	DBG(DBG_MSIQ, dip, "msi_addr32=0x%llx\n", msi_state_p->msi_addr32);
39710923SEvan.Yan@Sun.COM 	DBG(DBG_MSIQ, dip, "msi_addr64=0x%llx\n", msi_state_p->msi_addr64);
3980Sstevel@tonic-gate 
39910923SEvan.Yan@Sun.COM 	kmem_free(valuep, (size_t)length);
4000Sstevel@tonic-gate 	return (DDI_SUCCESS);
4010Sstevel@tonic-gate }
402