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 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 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 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 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 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 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