xref: /illumos-gate/usr/src/uts/sun4/io/px/px_msi.c (revision fc256490)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55febcb4aSScott Carter, SD IOSW  * Common Development and Distribution License (the "License").
65febcb4aSScott Carter, SD IOSW  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*fc256490SJason Beloro  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * px_msi.c
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
327c478bd9Sstevel@tonic-gate #include <sys/conf.h>
337c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
347c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
357c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
367c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
377c478bd9Sstevel@tonic-gate #include <sys/disp.h>
387c478bd9Sstevel@tonic-gate #include <sys/stat.h>
397c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
407c478bd9Sstevel@tonic-gate #include <sys/pci_impl.h>
417c478bd9Sstevel@tonic-gate #include "px_obj.h"
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate static int px_msi_get_props(px_t *px_p);
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate  * msi_attach()
477c478bd9Sstevel@tonic-gate  */
487c478bd9Sstevel@tonic-gate int
px_msi_attach(px_t * px_p)497c478bd9Sstevel@tonic-gate px_msi_attach(px_t *px_p)
507c478bd9Sstevel@tonic-gate {
517c478bd9Sstevel@tonic-gate 	dev_info_t		*dip = px_p->px_dip;
527c478bd9Sstevel@tonic-gate 	px_msi_state_t		*msi_state_p = &px_p->px_ib_p->ib_msi_state;
535febcb4aSScott Carter, SD IOSW 	ddi_irm_pool_t		*irm_pool_p = NULL;
545febcb4aSScott Carter, SD IOSW 	ddi_irm_params_t	irm_params;
557c478bd9Sstevel@tonic-gate 	msinum_t		msi_num;
567c478bd9Sstevel@tonic-gate 	int			i, ret;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate 	DBG(DBG_MSIQ, dip, "px_msi_attach\n");
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate 	mutex_init(&msi_state_p->msi_mutex, NULL, MUTEX_DRIVER, NULL);
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	/*
637c478bd9Sstevel@tonic-gate 	 * Check for all MSI related properties and
647c478bd9Sstevel@tonic-gate 	 * save all information.
657c478bd9Sstevel@tonic-gate 	 */
667c478bd9Sstevel@tonic-gate 	if (px_msi_get_props(px_p) != DDI_SUCCESS) {
677c478bd9Sstevel@tonic-gate 		px_msi_detach(px_p);
687c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
697c478bd9Sstevel@tonic-gate 	}
707c478bd9Sstevel@tonic-gate 
71*fc256490SJason Beloro 	px_p->px_supp_intr_types |= (DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_MSIX);
72*fc256490SJason Beloro 
737c478bd9Sstevel@tonic-gate 	msi_state_p->msi_p = kmem_zalloc(msi_state_p->msi_cnt *
747c478bd9Sstevel@tonic-gate 	    sizeof (px_msi_t), KM_SLEEP);
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	for (i = 0, msi_num = msi_state_p->msi_1st_msinum;
775febcb4aSScott Carter, SD IOSW 	    i < msi_state_p->msi_cnt; i++, msi_num++) {
787c478bd9Sstevel@tonic-gate 		msi_state_p->msi_p[i].msi_msinum = msi_num;
797c478bd9Sstevel@tonic-gate 		msi_state_p->msi_p[i].msi_state = MSI_STATE_FREE;
807c478bd9Sstevel@tonic-gate 	}
817c478bd9Sstevel@tonic-gate 
825febcb4aSScott Carter, SD IOSW 	/*
835febcb4aSScott Carter, SD IOSW 	 * Create IRM pool to manage interrupt allocations.
845febcb4aSScott Carter, SD IOSW 	 */
855febcb4aSScott Carter, SD IOSW 	bzero(&irm_params, sizeof (ddi_irm_params_t));
865febcb4aSScott Carter, SD IOSW 	irm_params.iparams_types = msi_state_p->msi_type;
875febcb4aSScott Carter, SD IOSW 	irm_params.iparams_total = msi_state_p->msi_cnt;
885febcb4aSScott Carter, SD IOSW 	if (ndi_irm_create(dip, &irm_params, &irm_pool_p) == DDI_SUCCESS) {
895febcb4aSScott Carter, SD IOSW 		msi_state_p->msi_pool_p = irm_pool_p;
905febcb4aSScott Carter, SD IOSW 	} else {
915febcb4aSScott Carter, SD IOSW 		DBG(DBG_MSIQ, dip, "ndi_irm_create() failed\n");
925febcb4aSScott Carter, SD IOSW 	}
935febcb4aSScott Carter, SD IOSW 
947c478bd9Sstevel@tonic-gate 	if ((ret = px_lib_msi_init(dip)) != DDI_SUCCESS)
957c478bd9Sstevel@tonic-gate 		px_msi_detach(px_p);
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	return (ret);
987c478bd9Sstevel@tonic-gate }
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate /*
1027c478bd9Sstevel@tonic-gate  * msi_detach()
1037c478bd9Sstevel@tonic-gate  */
1047c478bd9Sstevel@tonic-gate void
px_msi_detach(px_t * px_p)1057c478bd9Sstevel@tonic-gate px_msi_detach(px_t *px_p)
1067c478bd9Sstevel@tonic-gate {
1077c478bd9Sstevel@tonic-gate 	dev_info_t	*dip = px_p->px_dip;
1087c478bd9Sstevel@tonic-gate 	px_msi_state_t	*msi_state_p = &px_p->px_ib_p->ib_msi_state;
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	DBG(DBG_MSIQ, dip, "px_msi_detach\n");
1117c478bd9Sstevel@tonic-gate 
11226947304SEvan Yan 	if (msi_state_p->msi_pool_p)
1135febcb4aSScott Carter, SD IOSW 		(void) ndi_irm_destroy(msi_state_p->msi_pool_p);
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	if (msi_state_p->msi_p) {
1167c478bd9Sstevel@tonic-gate 		kmem_free(msi_state_p->msi_p,
1177c478bd9Sstevel@tonic-gate 		    msi_state_p->msi_cnt * sizeof (px_msi_t));
1187c478bd9Sstevel@tonic-gate 	}
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	mutex_destroy(&msi_state_p->msi_mutex);
1217c478bd9Sstevel@tonic-gate 	bzero(&px_p->px_ib_p->ib_msi_state, sizeof (px_msi_state_t));
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * msi_alloc()
1277c478bd9Sstevel@tonic-gate  */
1287c478bd9Sstevel@tonic-gate /* ARGSUSED */
1297c478bd9Sstevel@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)1305febcb4aSScott Carter, SD IOSW px_msi_alloc(px_t *px_p, dev_info_t *rdip, int type, int inum, int msi_count,
1315febcb4aSScott Carter, SD IOSW     int flag, int *actual_msi_count_p)
1327c478bd9Sstevel@tonic-gate {
1337c478bd9Sstevel@tonic-gate 	px_msi_state_t	*msi_state_p = &px_p->px_ib_p->ib_msi_state;
1345febcb4aSScott Carter, SD IOSW 	int		first, count, i, n;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	DBG(DBG_A_MSIX, px_p->px_dip, "px_msi_alloc: rdip %s:%d "
1375febcb4aSScott Carter, SD IOSW 	    "type 0x%x inum 0x%x msi_count 0x%x\n", ddi_driver_name(rdip),
1385febcb4aSScott Carter, SD IOSW 	    ddi_get_instance(rdip), type, inum, msi_count);
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	mutex_enter(&msi_state_p->msi_mutex);
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	*actual_msi_count_p = 0;
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	/*
1455febcb4aSScott Carter, SD IOSW 	 * MSI interrupts are allocated as contiguous ranges at
1465febcb4aSScott Carter, SD IOSW 	 * power of 2 boundaries from the start of the MSI array.
1477c478bd9Sstevel@tonic-gate 	 */
1485febcb4aSScott Carter, SD IOSW 	if (type == DDI_INTR_TYPE_MSI) {
1495febcb4aSScott Carter, SD IOSW 
1505febcb4aSScott Carter, SD IOSW 		/* Search for a range of available interrupts */
1515febcb4aSScott Carter, SD IOSW 		for (count = msi_count; count; count >>= 1) {
1525febcb4aSScott Carter, SD IOSW 			for (first = 0; (first + count) < msi_state_p->msi_cnt;
1535febcb4aSScott Carter, SD IOSW 			    first += count) {
1545febcb4aSScott Carter, SD IOSW 				for (i = first; i < (first + count); i++) {
1555febcb4aSScott Carter, SD IOSW 					if (msi_state_p->msi_p[i].msi_state
1565febcb4aSScott Carter, SD IOSW 					    != MSI_STATE_FREE) {
1575febcb4aSScott Carter, SD IOSW 						break;
1585febcb4aSScott Carter, SD IOSW 					}
1595febcb4aSScott Carter, SD IOSW 				}
1605febcb4aSScott Carter, SD IOSW 				if (i == (first + count)) {
1615febcb4aSScott Carter, SD IOSW 					goto found_msi;
1625febcb4aSScott Carter, SD IOSW 				}
1635febcb4aSScott Carter, SD IOSW 			}
1645febcb4aSScott Carter, SD IOSW 			DBG(DBG_A_MSIX, px_p->px_dip, "px_msi_alloc: failed\n");
1655febcb4aSScott Carter, SD IOSW 			if (count > 1) {
1665febcb4aSScott Carter, SD IOSW 				DBG(DBG_A_MSIX, px_p->px_dip, "px_msi_alloc: "
1675febcb4aSScott Carter, SD IOSW 				    "Retry MSI allocation with new msi_count "
1685febcb4aSScott Carter, SD IOSW 				    "0x%x\n", count >> 1);
1695febcb4aSScott Carter, SD IOSW 			}
1707c478bd9Sstevel@tonic-gate 		}
1717c478bd9Sstevel@tonic-gate 
1725febcb4aSScott Carter, SD IOSW found_msi:
1735febcb4aSScott Carter, SD IOSW 		/* Set number of available interrupts */
1745febcb4aSScott Carter, SD IOSW 		*actual_msi_count_p = count;
1757c478bd9Sstevel@tonic-gate 
1765febcb4aSScott Carter, SD IOSW 		/* Check if successful, and enforce strict behavior */
1775febcb4aSScott Carter, SD IOSW 		if ((count == 0) ||
1785febcb4aSScott Carter, SD IOSW 		    ((flag == DDI_INTR_ALLOC_STRICT) && (count != msi_count))) {
1795febcb4aSScott Carter, SD IOSW 			mutex_exit(&msi_state_p->msi_mutex);
1805febcb4aSScott Carter, SD IOSW 			return (DDI_EAGAIN);
1817c478bd9Sstevel@tonic-gate 		}
1827c478bd9Sstevel@tonic-gate 
1835febcb4aSScott Carter, SD IOSW 		/* Allocate the interrupts */
1845febcb4aSScott Carter, SD IOSW 		for (i = first; i < (first + count); i++, inum++) {
1855febcb4aSScott Carter, SD IOSW 			msi_state_p->msi_p[i].msi_state = MSI_STATE_INUSE;
1865febcb4aSScott Carter, SD IOSW 			msi_state_p->msi_p[i].msi_dip = rdip;
1875febcb4aSScott Carter, SD IOSW 			msi_state_p->msi_p[i].msi_inum = inum;
1885febcb4aSScott Carter, SD IOSW 		}
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate 
1915febcb4aSScott Carter, SD IOSW 	/*
1925febcb4aSScott Carter, SD IOSW 	 * MSI-X interrupts are allocated from the end of the MSI
1935febcb4aSScott Carter, SD IOSW 	 * array.  There are no concerns about power of 2 boundaries
1945febcb4aSScott Carter, SD IOSW 	 * and the allocated interrupts do not have to be contiguous.
1955febcb4aSScott Carter, SD IOSW 	 */
1965febcb4aSScott Carter, SD IOSW 	if (type == DDI_INTR_TYPE_MSIX) {
1975febcb4aSScott Carter, SD IOSW 
1985febcb4aSScott Carter, SD IOSW 		/* Count available interrupts, up to count requested */
1995febcb4aSScott Carter, SD IOSW 		for (count = 0, i = (msi_state_p->msi_cnt - 1); i >= 0; i--) {
2005febcb4aSScott Carter, SD IOSW 			if (msi_state_p->msi_p[i].msi_state == MSI_STATE_FREE) {
2015febcb4aSScott Carter, SD IOSW 				if (count == 0)
2025febcb4aSScott Carter, SD IOSW 					first = i;
2035febcb4aSScott Carter, SD IOSW 				count++;
2045febcb4aSScott Carter, SD IOSW 				if (count == msi_count)
2055febcb4aSScott Carter, SD IOSW 					break;
2065febcb4aSScott Carter, SD IOSW 			}
2075febcb4aSScott Carter, SD IOSW 		}
2087c478bd9Sstevel@tonic-gate 
2095febcb4aSScott Carter, SD IOSW 		/* Set number of available interrupts */
2105febcb4aSScott Carter, SD IOSW 		*actual_msi_count_p = count;
2117c478bd9Sstevel@tonic-gate 
2125febcb4aSScott Carter, SD IOSW 		/* Check if successful, and enforce strict behavior */
2135febcb4aSScott Carter, SD IOSW 		if ((count == 0) ||
2145febcb4aSScott Carter, SD IOSW 		    ((flag == DDI_INTR_ALLOC_STRICT) && (count != msi_count))) {
2155febcb4aSScott Carter, SD IOSW 			mutex_exit(&msi_state_p->msi_mutex);
2165febcb4aSScott Carter, SD IOSW 			return (DDI_EAGAIN);
2175febcb4aSScott Carter, SD IOSW 		}
2187c478bd9Sstevel@tonic-gate 
2195febcb4aSScott Carter, SD IOSW 		/* Allocate the interrupts */
2205febcb4aSScott Carter, SD IOSW 		for (n = 0, i = first; n < count; i--) {
2215febcb4aSScott Carter, SD IOSW 			if (msi_state_p->msi_p[i].msi_state != MSI_STATE_FREE)
2225febcb4aSScott Carter, SD IOSW 				continue;
2235febcb4aSScott Carter, SD IOSW 			msi_state_p->msi_p[i].msi_state = MSI_STATE_INUSE;
2245febcb4aSScott Carter, SD IOSW 			msi_state_p->msi_p[i].msi_dip = rdip;
2255febcb4aSScott Carter, SD IOSW 			msi_state_p->msi_p[i].msi_inum = inum;
2265febcb4aSScott Carter, SD IOSW 			inum++;
2275febcb4aSScott Carter, SD IOSW 			n++;
2285febcb4aSScott Carter, SD IOSW 		}
2297c478bd9Sstevel@tonic-gate 	}
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	DBG(DBG_A_MSIX, px_p->px_dip, "px_msi_alloc: rdip %s:%d "
2327c478bd9Sstevel@tonic-gate 	    "msi_num 0x%x count 0x%x\n", ddi_driver_name(rdip),
2335febcb4aSScott Carter, SD IOSW 	    ddi_get_instance(rdip), first, count);
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	mutex_exit(&msi_state_p->msi_mutex);
2365febcb4aSScott Carter, SD IOSW 
2377c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2387c478bd9Sstevel@tonic-gate }
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate /*
2427c478bd9Sstevel@tonic-gate  * msi_free()
2437c478bd9Sstevel@tonic-gate  */
2447c478bd9Sstevel@tonic-gate int
px_msi_free(px_t * px_p,dev_info_t * rdip,int inum,int msi_count)2457c478bd9Sstevel@tonic-gate px_msi_free(px_t *px_p, dev_info_t *rdip, int inum, int msi_count)
2467c478bd9Sstevel@tonic-gate {
2477c478bd9Sstevel@tonic-gate 	px_msi_state_t	*msi_state_p = &px_p->px_ib_p->ib_msi_state;
2485febcb4aSScott Carter, SD IOSW 	int		i, n;
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	DBG(DBG_R_MSIX, px_p->px_dip, "px_msi_free: rdip 0x%p "
2517c478bd9Sstevel@tonic-gate 	    "inum 0x%x msi_count 0x%x\n", rdip, inum, msi_count);
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	mutex_enter(&msi_state_p->msi_mutex);
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	/*
2565febcb4aSScott Carter, SD IOSW 	 * Find and release the specified MSI/X numbers.
2575febcb4aSScott Carter, SD IOSW 	 *
2585febcb4aSScott Carter, SD IOSW 	 * Because the allocations are not always contiguous, perform
2595febcb4aSScott Carter, SD IOSW 	 * a full linear search of the MSI/X table looking for MSI/X
2605febcb4aSScott Carter, SD IOSW 	 * vectors owned by the device with inum values in the range
2615febcb4aSScott Carter, SD IOSW 	 * [inum .. (inum + msi_count - 1)].
2627c478bd9Sstevel@tonic-gate 	 */
2635febcb4aSScott Carter, SD IOSW 	for (i = 0, n = 0; (i < msi_state_p->msi_cnt) && (n < msi_count); i++) {
2645febcb4aSScott Carter, SD IOSW 		if ((msi_state_p->msi_p[i].msi_dip == rdip) &&
2655febcb4aSScott Carter, SD IOSW 		    (msi_state_p->msi_p[i].msi_inum >= inum) &&
2665febcb4aSScott Carter, SD IOSW 		    (msi_state_p->msi_p[i].msi_inum < (inum + msi_count))) {
2675febcb4aSScott Carter, SD IOSW 			msi_state_p->msi_p[i].msi_dip = NULL;
2685febcb4aSScott Carter, SD IOSW 			msi_state_p->msi_p[i].msi_inum = 0;
2695febcb4aSScott Carter, SD IOSW 			msi_state_p->msi_p[i].msi_msiq_id = 0;
2705febcb4aSScott Carter, SD IOSW 			msi_state_p->msi_p[i].msi_state = MSI_STATE_FREE;
2715febcb4aSScott Carter, SD IOSW 			n++;
2727c478bd9Sstevel@tonic-gate 		}
2737c478bd9Sstevel@tonic-gate 	}
2747c478bd9Sstevel@tonic-gate 
2755febcb4aSScott Carter, SD IOSW 	mutex_exit(&msi_state_p->msi_mutex);
2767c478bd9Sstevel@tonic-gate 
2775febcb4aSScott Carter, SD IOSW 	/* Fail if the MSI/X numbers were not found */
2785febcb4aSScott Carter, SD IOSW 	if (n < msi_count)
2795febcb4aSScott Carter, SD IOSW 		return (DDI_FAILURE);
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate /*
2857c478bd9Sstevel@tonic-gate  * msi_get_msinum()
2867c478bd9Sstevel@tonic-gate  */
2877c478bd9Sstevel@tonic-gate int
px_msi_get_msinum(px_t * px_p,dev_info_t * rdip,int inum,msinum_t * msi_num_p)2887c478bd9Sstevel@tonic-gate px_msi_get_msinum(px_t *px_p, dev_info_t *rdip, int inum, msinum_t *msi_num_p)
2897c478bd9Sstevel@tonic-gate {
2907c478bd9Sstevel@tonic-gate 	px_msi_state_t	*msi_state_p = &px_p->px_ib_p->ib_msi_state;
2917c478bd9Sstevel@tonic-gate 	int		i;
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	DBG(DBG_A_MSIX, px_p->px_dip, "px_msi_get_msinum: "
2947c478bd9Sstevel@tonic-gate 	    "rdip 0x%p inum 0x%x\n", rdip, inum);
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	mutex_enter(&msi_state_p->msi_mutex);
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	for (i = 0; i < msi_state_p->msi_cnt; i++) {
2997c478bd9Sstevel@tonic-gate 		if ((msi_state_p->msi_p[i].msi_inum == inum) &&
3007c478bd9Sstevel@tonic-gate 		    (msi_state_p->msi_p[i].msi_dip == rdip)) {
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 			*msi_num_p = msi_state_p->msi_p[i].msi_msinum;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 			DBG(DBG_A_MSIX, px_p->px_dip, "px_msi_get_msinum: "
3057c478bd9Sstevel@tonic-gate 			    "inum 0x%x msi 0x%x\n", inum, *msi_num_p);
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 			mutex_exit(&msi_state_p->msi_mutex);
3087c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
3097c478bd9Sstevel@tonic-gate 		}
3107c478bd9Sstevel@tonic-gate 	}
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	if (i >= msi_state_p->msi_cnt)
3137c478bd9Sstevel@tonic-gate 		DBG(DBG_A_MSIX, px_p->px_dip, "px_msi_get_msinum: "
3147c478bd9Sstevel@tonic-gate 		    "no msi for inum 0x%x\n", inum);
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	mutex_exit(&msi_state_p->msi_mutex);
3177c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
3187c478bd9Sstevel@tonic-gate }
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate /*
3217c478bd9Sstevel@tonic-gate  * px_msi_get_props()
3227c478bd9Sstevel@tonic-gate  */
3237c478bd9Sstevel@tonic-gate static int
px_msi_get_props(px_t * px_p)3247c478bd9Sstevel@tonic-gate px_msi_get_props(px_t *px_p)
3257c478bd9Sstevel@tonic-gate {
32626947304SEvan Yan 	dev_info_t	*dip = px_p->px_dip;
32726947304SEvan Yan 	px_msi_state_t	*msi_state_p = &px_p->px_ib_p->ib_msi_state;
32826947304SEvan Yan 	int		length = sizeof (int);
32926947304SEvan Yan 	int		*valuep = NULL;
33026947304SEvan Yan 	uint64_t	msi_addr_hi, msi_addr_lo;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	DBG(DBG_MSIQ, dip, "px_msi_get_props\n");
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	/* #msi */
3357c478bd9Sstevel@tonic-gate 	msi_state_p->msi_cnt = ddi_getprop(DDI_DEV_T_ANY, dip,
33626947304SEvan Yan 	    DDI_PROP_DONTPASS, "#msi", 0);
3377c478bd9Sstevel@tonic-gate 
33826947304SEvan Yan 	DBG(DBG_MSIQ, dip, "#msi=%d\n", msi_state_p->msi_cnt);
33926947304SEvan Yan 	if (msi_state_p->msi_cnt == 0)
34026947304SEvan Yan 		return (DDI_FAILURE);
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	/* msi-ranges: msi# field */
34326947304SEvan Yan 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_ALLOC,
34426947304SEvan Yan 	    DDI_PROP_DONTPASS, "msi-ranges", (caddr_t)&valuep, &length)
34526947304SEvan Yan 	    != DDI_PROP_SUCCESS)
34626947304SEvan Yan 		return (DDI_FAILURE);
3477c478bd9Sstevel@tonic-gate 
34826947304SEvan Yan 	msi_state_p->msi_1st_msinum = ((px_msi_ranges_t *)valuep)->msi_no;
34926947304SEvan Yan 	kmem_free(valuep, (size_t)length);
3507c478bd9Sstevel@tonic-gate 
35126947304SEvan Yan 	DBG(DBG_MSIQ, dip, "msi_1st_msinum=%d\n", msi_state_p->msi_1st_msinum);
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	/* msi-data-mask */
3547c478bd9Sstevel@tonic-gate 	msi_state_p->msi_data_mask = ddi_getprop(DDI_DEV_T_ANY, dip,
35526947304SEvan Yan 	    DDI_PROP_DONTPASS, "msi-data-mask", 0);
3567c478bd9Sstevel@tonic-gate 
35726947304SEvan Yan 	DBG(DBG_MSIQ, dip, "msi-data-mask=0x%x\n",
3587c478bd9Sstevel@tonic-gate 	    msi_state_p->msi_data_mask);
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	/* msi-data-width */
3617c478bd9Sstevel@tonic-gate 	msi_state_p->msi_data_width = ddi_getprop(DDI_DEV_T_ANY, dip,
36226947304SEvan Yan 	    DDI_PROP_DONTPASS, "msix-data-width", 0);
3637c478bd9Sstevel@tonic-gate 
36426947304SEvan Yan 	DBG(DBG_MSIQ, dip, "msix-data-width=%d\n",
3657c478bd9Sstevel@tonic-gate 	    msi_state_p->msi_data_width);
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	/*
3687c478bd9Sstevel@tonic-gate 	 * Assume MSI is always supported, but also check if MSIX is supported
3697c478bd9Sstevel@tonic-gate 	 */
3707c478bd9Sstevel@tonic-gate 	if (msi_state_p->msi_data_width) {
3717c478bd9Sstevel@tonic-gate 		msi_state_p->msi_type = DDI_INTR_TYPE_MSI;
3727c478bd9Sstevel@tonic-gate 		if (msi_state_p->msi_data_width == PX_MSIX_WIDTH)
3737c478bd9Sstevel@tonic-gate 			msi_state_p->msi_type |= DDI_INTR_TYPE_MSIX;
37426947304SEvan Yan 	} else {
3757c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3767c478bd9Sstevel@tonic-gate 	}
3777c478bd9Sstevel@tonic-gate 
37826947304SEvan Yan 	/* msi-address-ranges */
37926947304SEvan Yan 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_ALLOC,
38026947304SEvan Yan 	    DDI_PROP_DONTPASS, "msi-address-ranges", (caddr_t)&valuep, &length)
38126947304SEvan Yan 	    != DDI_PROP_SUCCESS)
3827c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3837c478bd9Sstevel@tonic-gate 
38426947304SEvan Yan 	msi_addr_hi = ((px_msi_address_ranges_t *)valuep)->msi_addr32_hi;
38526947304SEvan Yan 	msi_addr_lo = ((px_msi_address_ranges_t *)valuep)->msi_addr32_lo;
38626947304SEvan Yan 	msi_state_p->msi_addr32 = (msi_addr_hi << 32) | msi_addr_lo;
38726947304SEvan Yan 	msi_state_p->msi_addr32_len =
38826947304SEvan Yan 	    ((px_msi_address_ranges_t *)valuep)->msi_addr32_len;
3897c478bd9Sstevel@tonic-gate 
39026947304SEvan Yan 	msi_addr_hi = ((px_msi_address_ranges_t *)valuep)->msi_addr64_hi;
39126947304SEvan Yan 	msi_addr_lo = ((px_msi_address_ranges_t *)valuep)->msi_addr64_lo;
39226947304SEvan Yan 	msi_state_p->msi_addr64 = (msi_addr_hi << 32) | msi_addr_lo;
39326947304SEvan Yan 	msi_state_p->msi_addr64_len =
39426947304SEvan Yan 	    ((px_msi_address_ranges_t *)valuep)->msi_addr64_len;
3957c478bd9Sstevel@tonic-gate 
39626947304SEvan Yan 	DBG(DBG_MSIQ, dip, "msi_addr32=0x%llx\n", msi_state_p->msi_addr32);
39726947304SEvan Yan 	DBG(DBG_MSIQ, dip, "msi_addr64=0x%llx\n", msi_state_p->msi_addr64);
3987c478bd9Sstevel@tonic-gate 
39926947304SEvan Yan 	kmem_free(valuep, (size_t)length);
4007c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
4017c478bd9Sstevel@tonic-gate }
402