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;
777c478bd9Sstevel@tonic-gate 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
1445febcb4aSScott Carter, SD IOSW /*
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.
1475febcb4aSScott Carter, SD IOSW */
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 }
1705febcb4aSScott Carter, SD IOSW }
1715febcb4aSScott Carter, SD IOSW
1725febcb4aSScott Carter, SD IOSW found_msi:
1735febcb4aSScott Carter, SD IOSW /* Set number of available interrupts */
1745febcb4aSScott Carter, SD IOSW *actual_msi_count_p = count;
1755febcb4aSScott Carter, SD IOSW
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);
1815febcb4aSScott Carter, SD IOSW }
1825febcb4aSScott Carter, SD IOSW
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 }
1895febcb4aSScott Carter, SD IOSW }
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate /*
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.
1957c478bd9Sstevel@tonic-gate */
1965febcb4aSScott Carter, SD IOSW if (type == DDI_INTR_TYPE_MSIX) {
1977c478bd9Sstevel@tonic-gate
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;
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate }
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))) {
2157c478bd9Sstevel@tonic-gate mutex_exit(&msi_state_p->msi_mutex);
2165febcb4aSScott Carter, SD IOSW return (DDI_EAGAIN);
2177c478bd9Sstevel@tonic-gate }
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
2757c478bd9Sstevel@tonic-gate mutex_exit(&msi_state_p->msi_mutex);
2765febcb4aSScott Carter, SD IOSW
2775febcb4aSScott Carter, SD IOSW /* Fail if the MSI/X numbers were not found */
2785febcb4aSScott Carter, SD IOSW if (n < msi_count)
2797c478bd9Sstevel@tonic-gate 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 {
3267c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip;
3277c478bd9Sstevel@tonic-gate px_msi_state_t *msi_state_p = &px_p->px_ib_p->ib_msi_state;
3287c478bd9Sstevel@tonic-gate int length = sizeof (int);
3297c478bd9Sstevel@tonic-gate int *valuep = NULL;
3307c478bd9Sstevel@tonic-gate 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;
3497c478bd9Sstevel@tonic-gate 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 {
37526947304SEvan Yan return (DDI_FAILURE);
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate
3787c478bd9Sstevel@tonic-gate /* 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)
38226947304SEvan Yan 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;
3877c478bd9Sstevel@tonic-gate msi_state_p->msi_addr32_len =
3887c478bd9Sstevel@tonic-gate ((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;
3937c478bd9Sstevel@tonic-gate msi_state_p->msi_addr64_len =
3947c478bd9Sstevel@tonic-gate ((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);
39826947304SEvan Yan
3997c478bd9Sstevel@tonic-gate kmem_free(valuep, (size_t)length);
4007c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
4017c478bd9Sstevel@tonic-gate }
402