1*7ff178cdSJimmy Vetayases /* 2*7ff178cdSJimmy Vetayases * CDDL HEADER START 3*7ff178cdSJimmy Vetayases * 4*7ff178cdSJimmy Vetayases * The contents of this file are subject to the terms of the 5*7ff178cdSJimmy Vetayases * Common Development and Distribution License (the "License"). 6*7ff178cdSJimmy Vetayases * You may not use this file except in compliance with the License. 7*7ff178cdSJimmy Vetayases * 8*7ff178cdSJimmy Vetayases * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*7ff178cdSJimmy Vetayases * or http://www.opensolaris.org/os/licensing. 10*7ff178cdSJimmy Vetayases * See the License for the specific language governing permissions 11*7ff178cdSJimmy Vetayases * and limitations under the License. 12*7ff178cdSJimmy Vetayases * 13*7ff178cdSJimmy Vetayases * When distributing Covered Code, include this CDDL HEADER in each 14*7ff178cdSJimmy Vetayases * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*7ff178cdSJimmy Vetayases * If applicable, add the following below this CDDL HEADER, with the 16*7ff178cdSJimmy Vetayases * fields enclosed by brackets "[]" replaced with your own identifying 17*7ff178cdSJimmy Vetayases * information: Portions Copyright [yyyy] [name of copyright owner] 18*7ff178cdSJimmy Vetayases * 19*7ff178cdSJimmy Vetayases * CDDL HEADER END 20*7ff178cdSJimmy Vetayases */ 21*7ff178cdSJimmy Vetayases 22*7ff178cdSJimmy Vetayases /* 23*7ff178cdSJimmy Vetayases * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24*7ff178cdSJimmy Vetayases */ 25*7ff178cdSJimmy Vetayases 26*7ff178cdSJimmy Vetayases #include <sys/mutex.h> 27*7ff178cdSJimmy Vetayases #include <sys/types.h> 28*7ff178cdSJimmy Vetayases #include <sys/time.h> 29*7ff178cdSJimmy Vetayases #include <sys/clock.h> 30*7ff178cdSJimmy Vetayases #include <sys/machlock.h> 31*7ff178cdSJimmy Vetayases #include <sys/smp_impldefs.h> 32*7ff178cdSJimmy Vetayases #include <sys/uadmin.h> 33*7ff178cdSJimmy Vetayases #include <sys/promif.h> 34*7ff178cdSJimmy Vetayases #include <sys/psm.h> 35*7ff178cdSJimmy Vetayases #include <sys/psm_common.h> 36*7ff178cdSJimmy Vetayases #include <sys/atomic.h> 37*7ff178cdSJimmy Vetayases #include <sys/apic.h> 38*7ff178cdSJimmy Vetayases #include <sys/archsystm.h> 39*7ff178cdSJimmy Vetayases #include <sys/mach_intr.h> 40*7ff178cdSJimmy Vetayases #include <sys/modctl.h> 41*7ff178cdSJimmy Vetayases #include <sys/sysmacros.h> 42*7ff178cdSJimmy Vetayases #include <sys/pci_intr_lib.h> 43*7ff178cdSJimmy Vetayases 44*7ff178cdSJimmy Vetayases 45*7ff178cdSJimmy Vetayases /* Multiple vector support for MSI */ 46*7ff178cdSJimmy Vetayases int apic_multi_msi_enable = 1; 47*7ff178cdSJimmy Vetayases 48*7ff178cdSJimmy Vetayases /* Multiple vector support for MSI-X */ 49*7ff178cdSJimmy Vetayases int apic_msix_enable = 1; 50*7ff178cdSJimmy Vetayases 51*7ff178cdSJimmy Vetayases /* 52*7ff178cdSJimmy Vetayases * check whether the system supports MSI 53*7ff178cdSJimmy Vetayases * 54*7ff178cdSJimmy Vetayases * If PCI-E capability is found, then this must be a PCI-E system. 55*7ff178cdSJimmy Vetayases * Since MSI is required for PCI-E system, it returns PSM_SUCCESS 56*7ff178cdSJimmy Vetayases * to indicate this system supports MSI. 57*7ff178cdSJimmy Vetayases */ 58*7ff178cdSJimmy Vetayases int 59*7ff178cdSJimmy Vetayases apic_check_msi_support() 60*7ff178cdSJimmy Vetayases { 61*7ff178cdSJimmy Vetayases dev_info_t *cdip; 62*7ff178cdSJimmy Vetayases char dev_type[16]; 63*7ff178cdSJimmy Vetayases int dev_len; 64*7ff178cdSJimmy Vetayases 65*7ff178cdSJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apic_check_msi_support:\n")); 66*7ff178cdSJimmy Vetayases 67*7ff178cdSJimmy Vetayases /* 68*7ff178cdSJimmy Vetayases * check whether the first level children of root_node have 69*7ff178cdSJimmy Vetayases * PCI-E capability 70*7ff178cdSJimmy Vetayases */ 71*7ff178cdSJimmy Vetayases for (cdip = ddi_get_child(ddi_root_node()); cdip != NULL; 72*7ff178cdSJimmy Vetayases cdip = ddi_get_next_sibling(cdip)) { 73*7ff178cdSJimmy Vetayases 74*7ff178cdSJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apic_check_msi_support: cdip: 0x%p," 75*7ff178cdSJimmy Vetayases " driver: %s, binding: %s, nodename: %s\n", (void *)cdip, 76*7ff178cdSJimmy Vetayases ddi_driver_name(cdip), ddi_binding_name(cdip), 77*7ff178cdSJimmy Vetayases ddi_node_name(cdip))); 78*7ff178cdSJimmy Vetayases dev_len = sizeof (dev_type); 79*7ff178cdSJimmy Vetayases if (ddi_getlongprop_buf(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 80*7ff178cdSJimmy Vetayases "device_type", (caddr_t)dev_type, &dev_len) 81*7ff178cdSJimmy Vetayases != DDI_PROP_SUCCESS) 82*7ff178cdSJimmy Vetayases continue; 83*7ff178cdSJimmy Vetayases if (strcmp(dev_type, "pciex") == 0) 84*7ff178cdSJimmy Vetayases return (PSM_SUCCESS); 85*7ff178cdSJimmy Vetayases } 86*7ff178cdSJimmy Vetayases 87*7ff178cdSJimmy Vetayases /* MSI is not supported on this system */ 88*7ff178cdSJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apic_check_msi_support: no 'pciex' " 89*7ff178cdSJimmy Vetayases "device_type found\n")); 90*7ff178cdSJimmy Vetayases return (PSM_FAILURE); 91*7ff178cdSJimmy Vetayases } 92*7ff178cdSJimmy Vetayases 93*7ff178cdSJimmy Vetayases 94*7ff178cdSJimmy Vetayases /* 95*7ff178cdSJimmy Vetayases * It finds the apic_irq_t associates with the dip, ispec and type. 96*7ff178cdSJimmy Vetayases */ 97*7ff178cdSJimmy Vetayases apic_irq_t * 98*7ff178cdSJimmy Vetayases apic_find_irq(dev_info_t *dip, struct intrspec *ispec, int type) 99*7ff178cdSJimmy Vetayases { 100*7ff178cdSJimmy Vetayases apic_irq_t *irqp; 101*7ff178cdSJimmy Vetayases int i; 102*7ff178cdSJimmy Vetayases 103*7ff178cdSJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apic_find_irq: dip=0x%p vec=0x%x " 104*7ff178cdSJimmy Vetayases "ipl=0x%x type=0x%x\n", (void *)dip, ispec->intrspec_vec, 105*7ff178cdSJimmy Vetayases ispec->intrspec_pri, type)); 106*7ff178cdSJimmy Vetayases 107*7ff178cdSJimmy Vetayases for (i = apic_min_device_irq; i <= apic_max_device_irq; i++) { 108*7ff178cdSJimmy Vetayases for (irqp = apic_irq_table[i]; irqp; irqp = irqp->airq_next) { 109*7ff178cdSJimmy Vetayases if ((irqp->airq_dip == dip) && 110*7ff178cdSJimmy Vetayases (irqp->airq_origirq == ispec->intrspec_vec) && 111*7ff178cdSJimmy Vetayases (irqp->airq_ipl == ispec->intrspec_pri)) { 112*7ff178cdSJimmy Vetayases if (type == DDI_INTR_TYPE_MSI) { 113*7ff178cdSJimmy Vetayases if (irqp->airq_mps_intr_index == 114*7ff178cdSJimmy Vetayases MSI_INDEX) 115*7ff178cdSJimmy Vetayases return (irqp); 116*7ff178cdSJimmy Vetayases } else if (type == DDI_INTR_TYPE_MSIX) { 117*7ff178cdSJimmy Vetayases if (irqp->airq_mps_intr_index == 118*7ff178cdSJimmy Vetayases MSIX_INDEX) 119*7ff178cdSJimmy Vetayases return (irqp); 120*7ff178cdSJimmy Vetayases } else 121*7ff178cdSJimmy Vetayases return (irqp); 122*7ff178cdSJimmy Vetayases } 123*7ff178cdSJimmy Vetayases } 124*7ff178cdSJimmy Vetayases } 125*7ff178cdSJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apic_find_irq: return NULL\n")); 126*7ff178cdSJimmy Vetayases return (NULL); 127*7ff178cdSJimmy Vetayases } 128*7ff178cdSJimmy Vetayases 129*7ff178cdSJimmy Vetayases 130*7ff178cdSJimmy Vetayases int 131*7ff178cdSJimmy Vetayases apic_get_vector_intr_info(int vecirq, apic_get_intr_t *intr_params_p) 132*7ff178cdSJimmy Vetayases { 133*7ff178cdSJimmy Vetayases struct autovec *av_dev; 134*7ff178cdSJimmy Vetayases uchar_t irqno; 135*7ff178cdSJimmy Vetayases int i; 136*7ff178cdSJimmy Vetayases apic_irq_t *irq_p; 137*7ff178cdSJimmy Vetayases 138*7ff178cdSJimmy Vetayases /* Sanity check the vector/irq argument. */ 139*7ff178cdSJimmy Vetayases ASSERT((vecirq >= 0) || (vecirq <= APIC_MAX_VECTOR)); 140*7ff178cdSJimmy Vetayases 141*7ff178cdSJimmy Vetayases mutex_enter(&airq_mutex); 142*7ff178cdSJimmy Vetayases 143*7ff178cdSJimmy Vetayases /* 144*7ff178cdSJimmy Vetayases * Convert the vecirq arg to an irq using vector_to_irq table 145*7ff178cdSJimmy Vetayases * if the arg is a vector. Pass thru if already an irq. 146*7ff178cdSJimmy Vetayases */ 147*7ff178cdSJimmy Vetayases if ((intr_params_p->avgi_req_flags & PSMGI_INTRBY_FLAGS) == 148*7ff178cdSJimmy Vetayases PSMGI_INTRBY_VEC) 149*7ff178cdSJimmy Vetayases irqno = apic_vector_to_irq[vecirq]; 150*7ff178cdSJimmy Vetayases else 151*7ff178cdSJimmy Vetayases irqno = vecirq; 152*7ff178cdSJimmy Vetayases 153*7ff178cdSJimmy Vetayases irq_p = apic_irq_table[irqno]; 154*7ff178cdSJimmy Vetayases 155*7ff178cdSJimmy Vetayases if ((irq_p == NULL) || 156*7ff178cdSJimmy Vetayases ((irq_p->airq_mps_intr_index != RESERVE_INDEX) && 157*7ff178cdSJimmy Vetayases ((irq_p->airq_temp_cpu == IRQ_UNBOUND) || 158*7ff178cdSJimmy Vetayases (irq_p->airq_temp_cpu == IRQ_UNINIT)))) { 159*7ff178cdSJimmy Vetayases mutex_exit(&airq_mutex); 160*7ff178cdSJimmy Vetayases return (PSM_FAILURE); 161*7ff178cdSJimmy Vetayases } 162*7ff178cdSJimmy Vetayases 163*7ff178cdSJimmy Vetayases if (intr_params_p->avgi_req_flags & PSMGI_REQ_CPUID) { 164*7ff178cdSJimmy Vetayases 165*7ff178cdSJimmy Vetayases /* Get the (temp) cpu from apic_irq table, indexed by irq. */ 166*7ff178cdSJimmy Vetayases intr_params_p->avgi_cpu_id = irq_p->airq_temp_cpu; 167*7ff178cdSJimmy Vetayases 168*7ff178cdSJimmy Vetayases /* Return user bound info for intrd. */ 169*7ff178cdSJimmy Vetayases if (intr_params_p->avgi_cpu_id & IRQ_USER_BOUND) { 170*7ff178cdSJimmy Vetayases intr_params_p->avgi_cpu_id &= ~IRQ_USER_BOUND; 171*7ff178cdSJimmy Vetayases intr_params_p->avgi_cpu_id |= PSMGI_CPU_USER_BOUND; 172*7ff178cdSJimmy Vetayases } 173*7ff178cdSJimmy Vetayases } 174*7ff178cdSJimmy Vetayases 175*7ff178cdSJimmy Vetayases if (intr_params_p->avgi_req_flags & PSMGI_REQ_VECTOR) 176*7ff178cdSJimmy Vetayases intr_params_p->avgi_vector = irq_p->airq_vector; 177*7ff178cdSJimmy Vetayases 178*7ff178cdSJimmy Vetayases if (intr_params_p->avgi_req_flags & 179*7ff178cdSJimmy Vetayases (PSMGI_REQ_NUM_DEVS | PSMGI_REQ_GET_DEVS)) 180*7ff178cdSJimmy Vetayases /* Get number of devices from apic_irq table shared field. */ 181*7ff178cdSJimmy Vetayases intr_params_p->avgi_num_devs = irq_p->airq_share; 182*7ff178cdSJimmy Vetayases 183*7ff178cdSJimmy Vetayases if (intr_params_p->avgi_req_flags & PSMGI_REQ_GET_DEVS) { 184*7ff178cdSJimmy Vetayases 185*7ff178cdSJimmy Vetayases intr_params_p->avgi_req_flags |= PSMGI_REQ_NUM_DEVS; 186*7ff178cdSJimmy Vetayases 187*7ff178cdSJimmy Vetayases /* Some devices have NULL dip. Don't count these. */ 188*7ff178cdSJimmy Vetayases if (intr_params_p->avgi_num_devs > 0) { 189*7ff178cdSJimmy Vetayases for (i = 0, av_dev = autovect[irqno].avh_link; 190*7ff178cdSJimmy Vetayases av_dev; av_dev = av_dev->av_link) 191*7ff178cdSJimmy Vetayases if (av_dev->av_vector && av_dev->av_dip) 192*7ff178cdSJimmy Vetayases i++; 193*7ff178cdSJimmy Vetayases intr_params_p->avgi_num_devs = 194*7ff178cdSJimmy Vetayases MIN(intr_params_p->avgi_num_devs, i); 195*7ff178cdSJimmy Vetayases } 196*7ff178cdSJimmy Vetayases 197*7ff178cdSJimmy Vetayases /* There are no viable dips to return. */ 198*7ff178cdSJimmy Vetayases if (intr_params_p->avgi_num_devs == 0) 199*7ff178cdSJimmy Vetayases intr_params_p->avgi_dip_list = NULL; 200*7ff178cdSJimmy Vetayases 201*7ff178cdSJimmy Vetayases else { /* Return list of dips */ 202*7ff178cdSJimmy Vetayases 203*7ff178cdSJimmy Vetayases /* Allocate space in array for that number of devs. */ 204*7ff178cdSJimmy Vetayases intr_params_p->avgi_dip_list = kmem_zalloc( 205*7ff178cdSJimmy Vetayases intr_params_p->avgi_num_devs * 206*7ff178cdSJimmy Vetayases sizeof (dev_info_t *), 207*7ff178cdSJimmy Vetayases KM_SLEEP); 208*7ff178cdSJimmy Vetayases 209*7ff178cdSJimmy Vetayases /* 210*7ff178cdSJimmy Vetayases * Loop through the device list of the autovec table 211*7ff178cdSJimmy Vetayases * filling in the dip array. 212*7ff178cdSJimmy Vetayases * 213*7ff178cdSJimmy Vetayases * Note that the autovect table may have some special 214*7ff178cdSJimmy Vetayases * entries which contain NULL dips. These will be 215*7ff178cdSJimmy Vetayases * ignored. 216*7ff178cdSJimmy Vetayases */ 217*7ff178cdSJimmy Vetayases for (i = 0, av_dev = autovect[irqno].avh_link; 218*7ff178cdSJimmy Vetayases av_dev; av_dev = av_dev->av_link) 219*7ff178cdSJimmy Vetayases if (av_dev->av_vector && av_dev->av_dip) 220*7ff178cdSJimmy Vetayases intr_params_p->avgi_dip_list[i++] = 221*7ff178cdSJimmy Vetayases av_dev->av_dip; 222*7ff178cdSJimmy Vetayases } 223*7ff178cdSJimmy Vetayases } 224*7ff178cdSJimmy Vetayases 225*7ff178cdSJimmy Vetayases mutex_exit(&airq_mutex); 226*7ff178cdSJimmy Vetayases 227*7ff178cdSJimmy Vetayases return (PSM_SUCCESS); 228*7ff178cdSJimmy Vetayases } 229*7ff178cdSJimmy Vetayases 230*7ff178cdSJimmy Vetayases 231*7ff178cdSJimmy Vetayases /* 232*7ff178cdSJimmy Vetayases * apic_pci_msi_enable_vector: 233*7ff178cdSJimmy Vetayases * Set the address/data fields in the MSI/X capability structure 234*7ff178cdSJimmy Vetayases * XXX: MSI-X support 235*7ff178cdSJimmy Vetayases */ 236*7ff178cdSJimmy Vetayases /* ARGSUSED */ 237*7ff178cdSJimmy Vetayases void 238*7ff178cdSJimmy Vetayases apic_pci_msi_enable_vector(apic_irq_t *irq_ptr, int type, int inum, int vector, 239*7ff178cdSJimmy Vetayases int count, int target_apic_id) 240*7ff178cdSJimmy Vetayases { 241*7ff178cdSJimmy Vetayases uint64_t msi_addr, msi_data; 242*7ff178cdSJimmy Vetayases ushort_t msi_ctrl; 243*7ff178cdSJimmy Vetayases dev_info_t *dip = irq_ptr->airq_dip; 244*7ff178cdSJimmy Vetayases int cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip); 245*7ff178cdSJimmy Vetayases ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(dip); 246*7ff178cdSJimmy Vetayases 247*7ff178cdSJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apic_pci_msi_enable_vector: dip=0x%p\n" 248*7ff178cdSJimmy Vetayases "\tdriver = %s, inum=0x%x vector=0x%x apicid=0x%x\n", (void *)dip, 249*7ff178cdSJimmy Vetayases ddi_driver_name(dip), inum, vector, target_apic_id)); 250*7ff178cdSJimmy Vetayases 251*7ff178cdSJimmy Vetayases ASSERT((handle != NULL) && (cap_ptr != 0)); 252*7ff178cdSJimmy Vetayases 253*7ff178cdSJimmy Vetayases /* MSI Address */ 254*7ff178cdSJimmy Vetayases msi_addr = (MSI_ADDR_HDR | 255*7ff178cdSJimmy Vetayases (target_apic_id << MSI_ADDR_DEST_SHIFT)); 256*7ff178cdSJimmy Vetayases msi_addr |= ((MSI_ADDR_RH_FIXED << MSI_ADDR_RH_SHIFT) | 257*7ff178cdSJimmy Vetayases (MSI_ADDR_DM_PHYSICAL << MSI_ADDR_DM_SHIFT)); 258*7ff178cdSJimmy Vetayases 259*7ff178cdSJimmy Vetayases /* MSI Data: MSI is edge triggered according to spec */ 260*7ff178cdSJimmy Vetayases msi_data = ((MSI_DATA_TM_EDGE << MSI_DATA_TM_SHIFT) | vector); 261*7ff178cdSJimmy Vetayases 262*7ff178cdSJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apic_pci_msi_enable_vector: addr=0x%lx " 263*7ff178cdSJimmy Vetayases "data=0x%lx\n", (long)msi_addr, (long)msi_data)); 264*7ff178cdSJimmy Vetayases 265*7ff178cdSJimmy Vetayases if (type == DDI_INTR_TYPE_MSI) { 266*7ff178cdSJimmy Vetayases msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL); 267*7ff178cdSJimmy Vetayases 268*7ff178cdSJimmy Vetayases /* Set the bits to inform how many MSIs are enabled */ 269*7ff178cdSJimmy Vetayases msi_ctrl |= ((highbit(count) -1) << PCI_MSI_MME_SHIFT); 270*7ff178cdSJimmy Vetayases pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl); 271*7ff178cdSJimmy Vetayases } 272*7ff178cdSJimmy Vetayases } 273*7ff178cdSJimmy Vetayases 274*7ff178cdSJimmy Vetayases 275*7ff178cdSJimmy Vetayases /* 276*7ff178cdSJimmy Vetayases * apic_pci_msi_disable_mode: 277*7ff178cdSJimmy Vetayases */ 278*7ff178cdSJimmy Vetayases void 279*7ff178cdSJimmy Vetayases apic_pci_msi_disable_mode(dev_info_t *rdip, int type) 280*7ff178cdSJimmy Vetayases { 281*7ff178cdSJimmy Vetayases ushort_t msi_ctrl; 282*7ff178cdSJimmy Vetayases int cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip); 283*7ff178cdSJimmy Vetayases ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(rdip); 284*7ff178cdSJimmy Vetayases 285*7ff178cdSJimmy Vetayases ASSERT((handle != NULL) && (cap_ptr != 0)); 286*7ff178cdSJimmy Vetayases 287*7ff178cdSJimmy Vetayases if (type == DDI_INTR_TYPE_MSI) { 288*7ff178cdSJimmy Vetayases msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL); 289*7ff178cdSJimmy Vetayases if (!(msi_ctrl & PCI_MSI_ENABLE_BIT)) 290*7ff178cdSJimmy Vetayases return; 291*7ff178cdSJimmy Vetayases 292*7ff178cdSJimmy Vetayases msi_ctrl &= ~PCI_MSI_ENABLE_BIT; /* MSI disable */ 293*7ff178cdSJimmy Vetayases pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl); 294*7ff178cdSJimmy Vetayases 295*7ff178cdSJimmy Vetayases } else if (type == DDI_INTR_TYPE_MSIX) { 296*7ff178cdSJimmy Vetayases msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSIX_CTRL); 297*7ff178cdSJimmy Vetayases if (msi_ctrl & PCI_MSIX_ENABLE_BIT) { 298*7ff178cdSJimmy Vetayases msi_ctrl &= ~PCI_MSIX_ENABLE_BIT; 299*7ff178cdSJimmy Vetayases pci_config_put16(handle, cap_ptr + PCI_MSIX_CTRL, 300*7ff178cdSJimmy Vetayases msi_ctrl); 301*7ff178cdSJimmy Vetayases } 302*7ff178cdSJimmy Vetayases } 303*7ff178cdSJimmy Vetayases } 304*7ff178cdSJimmy Vetayases 305*7ff178cdSJimmy Vetayases 306*7ff178cdSJimmy Vetayases /* 307*7ff178cdSJimmy Vetayases * apic_pci_msi_enable_mode: 308*7ff178cdSJimmy Vetayases */ 309*7ff178cdSJimmy Vetayases void 310*7ff178cdSJimmy Vetayases apic_pci_msi_enable_mode(dev_info_t *rdip, int type, int inum) 311*7ff178cdSJimmy Vetayases { 312*7ff178cdSJimmy Vetayases ushort_t msi_ctrl; 313*7ff178cdSJimmy Vetayases int cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip); 314*7ff178cdSJimmy Vetayases ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(rdip); 315*7ff178cdSJimmy Vetayases 316*7ff178cdSJimmy Vetayases ASSERT((handle != NULL) && (cap_ptr != 0)); 317*7ff178cdSJimmy Vetayases 318*7ff178cdSJimmy Vetayases if (type == DDI_INTR_TYPE_MSI) { 319*7ff178cdSJimmy Vetayases msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL); 320*7ff178cdSJimmy Vetayases if ((msi_ctrl & PCI_MSI_ENABLE_BIT)) 321*7ff178cdSJimmy Vetayases return; 322*7ff178cdSJimmy Vetayases 323*7ff178cdSJimmy Vetayases msi_ctrl |= PCI_MSI_ENABLE_BIT; 324*7ff178cdSJimmy Vetayases pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl); 325*7ff178cdSJimmy Vetayases 326*7ff178cdSJimmy Vetayases } else if (type == DDI_INTR_TYPE_MSIX) { 327*7ff178cdSJimmy Vetayases uintptr_t off; 328*7ff178cdSJimmy Vetayases uint32_t mask; 329*7ff178cdSJimmy Vetayases ddi_intr_msix_t *msix_p; 330*7ff178cdSJimmy Vetayases 331*7ff178cdSJimmy Vetayases msix_p = i_ddi_get_msix(rdip); 332*7ff178cdSJimmy Vetayases 333*7ff178cdSJimmy Vetayases ASSERT(msix_p != NULL); 334*7ff178cdSJimmy Vetayases 335*7ff178cdSJimmy Vetayases /* Offset into "inum"th entry in the MSI-X table & clear mask */ 336*7ff178cdSJimmy Vetayases off = (uintptr_t)msix_p->msix_tbl_addr + (inum * 337*7ff178cdSJimmy Vetayases PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET; 338*7ff178cdSJimmy Vetayases 339*7ff178cdSJimmy Vetayases mask = ddi_get32(msix_p->msix_tbl_hdl, (uint32_t *)off); 340*7ff178cdSJimmy Vetayases 341*7ff178cdSJimmy Vetayases ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, (mask & ~1)); 342*7ff178cdSJimmy Vetayases 343*7ff178cdSJimmy Vetayases msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSIX_CTRL); 344*7ff178cdSJimmy Vetayases 345*7ff178cdSJimmy Vetayases if (!(msi_ctrl & PCI_MSIX_ENABLE_BIT)) { 346*7ff178cdSJimmy Vetayases msi_ctrl |= PCI_MSIX_ENABLE_BIT; 347*7ff178cdSJimmy Vetayases pci_config_put16(handle, cap_ptr + PCI_MSIX_CTRL, 348*7ff178cdSJimmy Vetayases msi_ctrl); 349*7ff178cdSJimmy Vetayases } 350*7ff178cdSJimmy Vetayases } 351*7ff178cdSJimmy Vetayases } 352*7ff178cdSJimmy Vetayases 353*7ff178cdSJimmy Vetayases 354*7ff178cdSJimmy Vetayases /* 355*7ff178cdSJimmy Vetayases * We let the hypervisor deal with msi configutation 356*7ff178cdSJimmy Vetayases * so just stub this out. 357*7ff178cdSJimmy Vetayases */ 358*7ff178cdSJimmy Vetayases 359*7ff178cdSJimmy Vetayases /* ARGSUSED */ 360*7ff178cdSJimmy Vetayases void 361*7ff178cdSJimmy Vetayases apic_pci_msi_unconfigure(dev_info_t *rdip, int type, int inum) 362*7ff178cdSJimmy Vetayases { 363*7ff178cdSJimmy Vetayases } 364