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