1*12683SJimmy.Vetayases@oracle.com /* 2*12683SJimmy.Vetayases@oracle.com * CDDL HEADER START 3*12683SJimmy.Vetayases@oracle.com * 4*12683SJimmy.Vetayases@oracle.com * The contents of this file are subject to the terms of the 5*12683SJimmy.Vetayases@oracle.com * Common Development and Distribution License (the "License"). 6*12683SJimmy.Vetayases@oracle.com * You may not use this file except in compliance with the License. 7*12683SJimmy.Vetayases@oracle.com * 8*12683SJimmy.Vetayases@oracle.com * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*12683SJimmy.Vetayases@oracle.com * or http://www.opensolaris.org/os/licensing. 10*12683SJimmy.Vetayases@oracle.com * See the License for the specific language governing permissions 11*12683SJimmy.Vetayases@oracle.com * and limitations under the License. 12*12683SJimmy.Vetayases@oracle.com * 13*12683SJimmy.Vetayases@oracle.com * When distributing Covered Code, include this CDDL HEADER in each 14*12683SJimmy.Vetayases@oracle.com * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*12683SJimmy.Vetayases@oracle.com * If applicable, add the following below this CDDL HEADER, with the 16*12683SJimmy.Vetayases@oracle.com * fields enclosed by brackets "[]" replaced with your own identifying 17*12683SJimmy.Vetayases@oracle.com * information: Portions Copyright [yyyy] [name of copyright owner] 18*12683SJimmy.Vetayases@oracle.com * 19*12683SJimmy.Vetayases@oracle.com * CDDL HEADER END 20*12683SJimmy.Vetayases@oracle.com */ 21*12683SJimmy.Vetayases@oracle.com 22*12683SJimmy.Vetayases@oracle.com /* 23*12683SJimmy.Vetayases@oracle.com * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24*12683SJimmy.Vetayases@oracle.com */ 25*12683SJimmy.Vetayases@oracle.com /* 26*12683SJimmy.Vetayases@oracle.com * Copyright (c) 2010, Intel Corporation. 27*12683SJimmy.Vetayases@oracle.com * All rights reserved. 28*12683SJimmy.Vetayases@oracle.com */ 29*12683SJimmy.Vetayases@oracle.com 30*12683SJimmy.Vetayases@oracle.com #include <sys/processor.h> 31*12683SJimmy.Vetayases@oracle.com #include <sys/time.h> 32*12683SJimmy.Vetayases@oracle.com #include <sys/psm.h> 33*12683SJimmy.Vetayases@oracle.com #include <sys/smp_impldefs.h> 34*12683SJimmy.Vetayases@oracle.com #include <sys/cram.h> 35*12683SJimmy.Vetayases@oracle.com #include <sys/acpi/acpi.h> 36*12683SJimmy.Vetayases@oracle.com #include <sys/acpica.h> 37*12683SJimmy.Vetayases@oracle.com #include <sys/psm_common.h> 38*12683SJimmy.Vetayases@oracle.com #include <sys/pit.h> 39*12683SJimmy.Vetayases@oracle.com #include <sys/ddi.h> 40*12683SJimmy.Vetayases@oracle.com #include <sys/sunddi.h> 41*12683SJimmy.Vetayases@oracle.com #include <sys/ddi_impldefs.h> 42*12683SJimmy.Vetayases@oracle.com #include <sys/pci.h> 43*12683SJimmy.Vetayases@oracle.com #include <sys/promif.h> 44*12683SJimmy.Vetayases@oracle.com #include <sys/x86_archext.h> 45*12683SJimmy.Vetayases@oracle.com #include <sys/cpc_impl.h> 46*12683SJimmy.Vetayases@oracle.com #include <sys/uadmin.h> 47*12683SJimmy.Vetayases@oracle.com #include <sys/panic.h> 48*12683SJimmy.Vetayases@oracle.com #include <sys/debug.h> 49*12683SJimmy.Vetayases@oracle.com #include <sys/archsystm.h> 50*12683SJimmy.Vetayases@oracle.com #include <sys/trap.h> 51*12683SJimmy.Vetayases@oracle.com #include <sys/machsystm.h> 52*12683SJimmy.Vetayases@oracle.com #include <sys/sysmacros.h> 53*12683SJimmy.Vetayases@oracle.com #include <sys/cpuvar.h> 54*12683SJimmy.Vetayases@oracle.com #include <sys/rm_platter.h> 55*12683SJimmy.Vetayases@oracle.com #include <sys/privregs.h> 56*12683SJimmy.Vetayases@oracle.com #include <sys/note.h> 57*12683SJimmy.Vetayases@oracle.com #include <sys/pci_intr_lib.h> 58*12683SJimmy.Vetayases@oracle.com #include <sys/spl.h> 59*12683SJimmy.Vetayases@oracle.com #include <sys/clock.h> 60*12683SJimmy.Vetayases@oracle.com #include <sys/dditypes.h> 61*12683SJimmy.Vetayases@oracle.com #include <sys/sunddi.h> 62*12683SJimmy.Vetayases@oracle.com #include <sys/x_call.h> 63*12683SJimmy.Vetayases@oracle.com #include <sys/reboot.h> 64*12683SJimmy.Vetayases@oracle.com #include <sys/apix.h> 65*12683SJimmy.Vetayases@oracle.com 66*12683SJimmy.Vetayases@oracle.com static int apix_get_avail_vector_oncpu(uint32_t, int, int); 67*12683SJimmy.Vetayases@oracle.com static apix_vector_t *apix_init_vector(processorid_t, uchar_t); 68*12683SJimmy.Vetayases@oracle.com static void apix_cleanup_vector(apix_vector_t *); 69*12683SJimmy.Vetayases@oracle.com static void apix_insert_av(apix_vector_t *, void *, avfunc, caddr_t, caddr_t, 70*12683SJimmy.Vetayases@oracle.com uint64_t *, int, dev_info_t *); 71*12683SJimmy.Vetayases@oracle.com static void apix_remove_av(apix_vector_t *, struct autovec *); 72*12683SJimmy.Vetayases@oracle.com static void apix_clear_dev_map(dev_info_t *, int, int); 73*12683SJimmy.Vetayases@oracle.com static boolean_t apix_is_cpu_enabled(processorid_t); 74*12683SJimmy.Vetayases@oracle.com static void apix_wait_till_seen(processorid_t, int); 75*12683SJimmy.Vetayases@oracle.com 76*12683SJimmy.Vetayases@oracle.com #define GET_INTR_INUM(ihdlp) \ 77*12683SJimmy.Vetayases@oracle.com (((ihdlp) != NULL) ? ((ddi_intr_handle_impl_t *)(ihdlp))->ih_inum : 0) 78*12683SJimmy.Vetayases@oracle.com 79*12683SJimmy.Vetayases@oracle.com apix_rebind_info_t apix_rebindinfo = {0, 0, 0, NULL, 0, NULL}; 80*12683SJimmy.Vetayases@oracle.com 81*12683SJimmy.Vetayases@oracle.com /* 82*12683SJimmy.Vetayases@oracle.com * Allocate IPI 83*12683SJimmy.Vetayases@oracle.com * 84*12683SJimmy.Vetayases@oracle.com * Return vector number or 0 on error 85*12683SJimmy.Vetayases@oracle.com */ 86*12683SJimmy.Vetayases@oracle.com uchar_t 87*12683SJimmy.Vetayases@oracle.com apix_alloc_ipi(int ipl) 88*12683SJimmy.Vetayases@oracle.com { 89*12683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 90*12683SJimmy.Vetayases@oracle.com uchar_t vector; 91*12683SJimmy.Vetayases@oracle.com int cpun; 92*12683SJimmy.Vetayases@oracle.com int nproc; 93*12683SJimmy.Vetayases@oracle.com 94*12683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(0); 95*12683SJimmy.Vetayases@oracle.com 96*12683SJimmy.Vetayases@oracle.com vector = apix_get_avail_vector_oncpu(0, APIX_IPI_MIN, APIX_IPI_MAX); 97*12683SJimmy.Vetayases@oracle.com if (vector == 0) { 98*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(0); 99*12683SJimmy.Vetayases@oracle.com cmn_err(CE_WARN, "apix: no available IPI\n"); 100*12683SJimmy.Vetayases@oracle.com apic_error |= APIC_ERR_GET_IPIVECT_FAIL; 101*12683SJimmy.Vetayases@oracle.com return (0); 102*12683SJimmy.Vetayases@oracle.com } 103*12683SJimmy.Vetayases@oracle.com 104*12683SJimmy.Vetayases@oracle.com nproc = max(apic_nproc, apic_max_nproc); 105*12683SJimmy.Vetayases@oracle.com for (cpun = 0; cpun < nproc; cpun++) { 106*12683SJimmy.Vetayases@oracle.com vecp = xv_vector(cpun, vector); 107*12683SJimmy.Vetayases@oracle.com if (vecp == NULL) { 108*12683SJimmy.Vetayases@oracle.com vecp = kmem_zalloc(sizeof (apix_vector_t), KM_NOSLEEP); 109*12683SJimmy.Vetayases@oracle.com if (vecp == NULL) { 110*12683SJimmy.Vetayases@oracle.com cmn_err(CE_WARN, "apix: No memory for ipi"); 111*12683SJimmy.Vetayases@oracle.com goto fail; 112*12683SJimmy.Vetayases@oracle.com } 113*12683SJimmy.Vetayases@oracle.com xv_vector(cpun, vector) = vecp; 114*12683SJimmy.Vetayases@oracle.com } 115*12683SJimmy.Vetayases@oracle.com vecp->v_state = APIX_STATE_ALLOCED; 116*12683SJimmy.Vetayases@oracle.com vecp->v_type = APIX_TYPE_IPI; 117*12683SJimmy.Vetayases@oracle.com vecp->v_cpuid = vecp->v_bound_cpuid = cpun; 118*12683SJimmy.Vetayases@oracle.com vecp->v_vector = vector; 119*12683SJimmy.Vetayases@oracle.com vecp->v_pri = ipl; 120*12683SJimmy.Vetayases@oracle.com } 121*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(0); 122*12683SJimmy.Vetayases@oracle.com return (vector); 123*12683SJimmy.Vetayases@oracle.com 124*12683SJimmy.Vetayases@oracle.com fail: 125*12683SJimmy.Vetayases@oracle.com while (--cpun >= 0) 126*12683SJimmy.Vetayases@oracle.com apix_cleanup_vector(xv_vector(cpun, vector)); 127*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(0); 128*12683SJimmy.Vetayases@oracle.com return (0); 129*12683SJimmy.Vetayases@oracle.com } 130*12683SJimmy.Vetayases@oracle.com 131*12683SJimmy.Vetayases@oracle.com /* 132*12683SJimmy.Vetayases@oracle.com * Add IPI service routine 133*12683SJimmy.Vetayases@oracle.com */ 134*12683SJimmy.Vetayases@oracle.com static int 135*12683SJimmy.Vetayases@oracle.com apix_add_ipi(int ipl, avfunc xxintr, char *name, int vector, 136*12683SJimmy.Vetayases@oracle.com caddr_t arg1, caddr_t arg2) 137*12683SJimmy.Vetayases@oracle.com { 138*12683SJimmy.Vetayases@oracle.com int cpun; 139*12683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 140*12683SJimmy.Vetayases@oracle.com int nproc; 141*12683SJimmy.Vetayases@oracle.com 142*12683SJimmy.Vetayases@oracle.com ASSERT(vector >= APIX_IPI_MIN && vector <= APIX_IPI_MAX); 143*12683SJimmy.Vetayases@oracle.com 144*12683SJimmy.Vetayases@oracle.com nproc = max(apic_nproc, apic_max_nproc); 145*12683SJimmy.Vetayases@oracle.com for (cpun = 0; cpun < nproc; cpun++) { 146*12683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(cpun); 147*12683SJimmy.Vetayases@oracle.com vecp = xv_vector(cpun, vector); 148*12683SJimmy.Vetayases@oracle.com apix_insert_av(vecp, NULL, xxintr, arg1, arg2, NULL, ipl, NULL); 149*12683SJimmy.Vetayases@oracle.com vecp->v_state = APIX_STATE_ENABLED; 150*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpun); 151*12683SJimmy.Vetayases@oracle.com } 152*12683SJimmy.Vetayases@oracle.com 153*12683SJimmy.Vetayases@oracle.com APIC_VERBOSE(IPI, (CE_CONT, "apix: add ipi for %s, vector %x " 154*12683SJimmy.Vetayases@oracle.com "ipl %x\n", name, vector, ipl)); 155*12683SJimmy.Vetayases@oracle.com 156*12683SJimmy.Vetayases@oracle.com return (1); 157*12683SJimmy.Vetayases@oracle.com } 158*12683SJimmy.Vetayases@oracle.com 159*12683SJimmy.Vetayases@oracle.com /* 160*12683SJimmy.Vetayases@oracle.com * Find and return first free vector in range (start, end) 161*12683SJimmy.Vetayases@oracle.com */ 162*12683SJimmy.Vetayases@oracle.com static int 163*12683SJimmy.Vetayases@oracle.com apix_get_avail_vector_oncpu(uint32_t cpuid, int start, int end) 164*12683SJimmy.Vetayases@oracle.com { 165*12683SJimmy.Vetayases@oracle.com int i; 166*12683SJimmy.Vetayases@oracle.com apix_impl_t *apixp = apixs[cpuid]; 167*12683SJimmy.Vetayases@oracle.com 168*12683SJimmy.Vetayases@oracle.com for (i = start; i <= end; i++) { 169*12683SJimmy.Vetayases@oracle.com if (APIC_CHECK_RESERVE_VECTORS(i)) 170*12683SJimmy.Vetayases@oracle.com continue; 171*12683SJimmy.Vetayases@oracle.com if (IS_VECT_FREE(apixp->x_vectbl[i])) 172*12683SJimmy.Vetayases@oracle.com return (i); 173*12683SJimmy.Vetayases@oracle.com } 174*12683SJimmy.Vetayases@oracle.com 175*12683SJimmy.Vetayases@oracle.com return (0); 176*12683SJimmy.Vetayases@oracle.com } 177*12683SJimmy.Vetayases@oracle.com 178*12683SJimmy.Vetayases@oracle.com /* 179*12683SJimmy.Vetayases@oracle.com * Allocate a vector on specified cpu 180*12683SJimmy.Vetayases@oracle.com * 181*12683SJimmy.Vetayases@oracle.com * Return NULL on error 182*12683SJimmy.Vetayases@oracle.com */ 183*12683SJimmy.Vetayases@oracle.com static apix_vector_t * 184*12683SJimmy.Vetayases@oracle.com apix_alloc_vector_oncpu(uint32_t cpuid, dev_info_t *dip, int inum, int type) 185*12683SJimmy.Vetayases@oracle.com { 186*12683SJimmy.Vetayases@oracle.com processorid_t tocpu = cpuid & ~IRQ_USER_BOUND; 187*12683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 188*12683SJimmy.Vetayases@oracle.com int vector; 189*12683SJimmy.Vetayases@oracle.com 190*12683SJimmy.Vetayases@oracle.com ASSERT(APIX_CPU_LOCK_HELD(tocpu)); 191*12683SJimmy.Vetayases@oracle.com 192*12683SJimmy.Vetayases@oracle.com /* find free vector */ 193*12683SJimmy.Vetayases@oracle.com vector = apix_get_avail_vector_oncpu(tocpu, APIX_AVINTR_MIN, 194*12683SJimmy.Vetayases@oracle.com APIX_AVINTR_MAX); 195*12683SJimmy.Vetayases@oracle.com if (vector == 0) 196*12683SJimmy.Vetayases@oracle.com return (NULL); 197*12683SJimmy.Vetayases@oracle.com 198*12683SJimmy.Vetayases@oracle.com vecp = apix_init_vector(tocpu, vector); 199*12683SJimmy.Vetayases@oracle.com vecp->v_type = (ushort_t)type; 200*12683SJimmy.Vetayases@oracle.com vecp->v_inum = inum; 201*12683SJimmy.Vetayases@oracle.com vecp->v_flags = (cpuid & IRQ_USER_BOUND) ? APIX_VECT_USER_BOUND : 0; 202*12683SJimmy.Vetayases@oracle.com 203*12683SJimmy.Vetayases@oracle.com if (dip != NULL) 204*12683SJimmy.Vetayases@oracle.com apix_set_dev_map(vecp, dip, inum); 205*12683SJimmy.Vetayases@oracle.com 206*12683SJimmy.Vetayases@oracle.com return (vecp); 207*12683SJimmy.Vetayases@oracle.com } 208*12683SJimmy.Vetayases@oracle.com 209*12683SJimmy.Vetayases@oracle.com /* 210*12683SJimmy.Vetayases@oracle.com * Allocates "count" contiguous MSI vectors starting at the proper alignment. 211*12683SJimmy.Vetayases@oracle.com * Caller needs to make sure that count has to be power of 2 and should not 212*12683SJimmy.Vetayases@oracle.com * be < 1. 213*12683SJimmy.Vetayases@oracle.com * 214*12683SJimmy.Vetayases@oracle.com * Return first vector number 215*12683SJimmy.Vetayases@oracle.com */ 216*12683SJimmy.Vetayases@oracle.com apix_vector_t * 217*12683SJimmy.Vetayases@oracle.com apix_alloc_nvectors_oncpu(uint32_t cpuid, dev_info_t *dip, int inum, 218*12683SJimmy.Vetayases@oracle.com int count, int type) 219*12683SJimmy.Vetayases@oracle.com { 220*12683SJimmy.Vetayases@oracle.com int i, msibits, start = 0, navail = 0; 221*12683SJimmy.Vetayases@oracle.com apix_vector_t *vecp, *startp = NULL; 222*12683SJimmy.Vetayases@oracle.com processorid_t tocpu = cpuid & ~IRQ_USER_BOUND; 223*12683SJimmy.Vetayases@oracle.com uint_t flags; 224*12683SJimmy.Vetayases@oracle.com 225*12683SJimmy.Vetayases@oracle.com ASSERT(APIX_CPU_LOCK_HELD(tocpu)); 226*12683SJimmy.Vetayases@oracle.com 227*12683SJimmy.Vetayases@oracle.com /* 228*12683SJimmy.Vetayases@oracle.com * msibits is the no. of lower order message data bits for the 229*12683SJimmy.Vetayases@oracle.com * allocated MSI vectors and is used to calculate the aligned 230*12683SJimmy.Vetayases@oracle.com * starting vector 231*12683SJimmy.Vetayases@oracle.com */ 232*12683SJimmy.Vetayases@oracle.com msibits = count - 1; 233*12683SJimmy.Vetayases@oracle.com 234*12683SJimmy.Vetayases@oracle.com /* It has to be contiguous */ 235*12683SJimmy.Vetayases@oracle.com for (i = APIX_AVINTR_MIN; i <= APIX_AVINTR_MAX; i++) { 236*12683SJimmy.Vetayases@oracle.com if (!IS_VECT_FREE(xv_vector(tocpu, i))) 237*12683SJimmy.Vetayases@oracle.com continue; 238*12683SJimmy.Vetayases@oracle.com 239*12683SJimmy.Vetayases@oracle.com /* 240*12683SJimmy.Vetayases@oracle.com * starting vector has to be aligned accordingly for 241*12683SJimmy.Vetayases@oracle.com * multiple MSIs 242*12683SJimmy.Vetayases@oracle.com */ 243*12683SJimmy.Vetayases@oracle.com if (msibits) 244*12683SJimmy.Vetayases@oracle.com i = (i + msibits) & ~msibits; 245*12683SJimmy.Vetayases@oracle.com 246*12683SJimmy.Vetayases@oracle.com for (navail = 0, start = i; i <= APIX_AVINTR_MAX; i++) { 247*12683SJimmy.Vetayases@oracle.com if (!IS_VECT_FREE(xv_vector(tocpu, i))) 248*12683SJimmy.Vetayases@oracle.com break; 249*12683SJimmy.Vetayases@oracle.com if (APIC_CHECK_RESERVE_VECTORS(i)) 250*12683SJimmy.Vetayases@oracle.com break; 251*12683SJimmy.Vetayases@oracle.com if (++navail == count) 252*12683SJimmy.Vetayases@oracle.com goto done; 253*12683SJimmy.Vetayases@oracle.com } 254*12683SJimmy.Vetayases@oracle.com } 255*12683SJimmy.Vetayases@oracle.com 256*12683SJimmy.Vetayases@oracle.com return (NULL); 257*12683SJimmy.Vetayases@oracle.com 258*12683SJimmy.Vetayases@oracle.com done: 259*12683SJimmy.Vetayases@oracle.com flags = (cpuid & IRQ_USER_BOUND) ? APIX_VECT_USER_BOUND : 0; 260*12683SJimmy.Vetayases@oracle.com 261*12683SJimmy.Vetayases@oracle.com for (i = 0; i < count; i++) { 262*12683SJimmy.Vetayases@oracle.com if ((vecp = apix_init_vector(tocpu, start + i)) == NULL) 263*12683SJimmy.Vetayases@oracle.com goto fail; 264*12683SJimmy.Vetayases@oracle.com 265*12683SJimmy.Vetayases@oracle.com vecp->v_type = (ushort_t)type; 266*12683SJimmy.Vetayases@oracle.com vecp->v_inum = inum + i; 267*12683SJimmy.Vetayases@oracle.com vecp->v_flags = flags; 268*12683SJimmy.Vetayases@oracle.com 269*12683SJimmy.Vetayases@oracle.com if (dip != NULL) 270*12683SJimmy.Vetayases@oracle.com apix_set_dev_map(vecp, dip, inum + i); 271*12683SJimmy.Vetayases@oracle.com 272*12683SJimmy.Vetayases@oracle.com if (i == 0) 273*12683SJimmy.Vetayases@oracle.com startp = vecp; 274*12683SJimmy.Vetayases@oracle.com } 275*12683SJimmy.Vetayases@oracle.com 276*12683SJimmy.Vetayases@oracle.com return (startp); 277*12683SJimmy.Vetayases@oracle.com 278*12683SJimmy.Vetayases@oracle.com fail: 279*12683SJimmy.Vetayases@oracle.com while (i-- > 0) { /* Free allocated vectors */ 280*12683SJimmy.Vetayases@oracle.com vecp = xv_vector(tocpu, start + i); 281*12683SJimmy.Vetayases@oracle.com apix_clear_dev_map(dip, inum + i, type); 282*12683SJimmy.Vetayases@oracle.com apix_cleanup_vector(vecp); 283*12683SJimmy.Vetayases@oracle.com } 284*12683SJimmy.Vetayases@oracle.com return (NULL); 285*12683SJimmy.Vetayases@oracle.com } 286*12683SJimmy.Vetayases@oracle.com 287*12683SJimmy.Vetayases@oracle.com #define APIX_WRITE_MSI_DATA(_hdl, _cap, _ctrl, _v)\ 288*12683SJimmy.Vetayases@oracle.com do {\ 289*12683SJimmy.Vetayases@oracle.com if ((_ctrl) & PCI_MSI_64BIT_MASK)\ 290*12683SJimmy.Vetayases@oracle.com pci_config_put16((_hdl), (_cap) + PCI_MSI_64BIT_DATA, (_v));\ 291*12683SJimmy.Vetayases@oracle.com else\ 292*12683SJimmy.Vetayases@oracle.com pci_config_put16((_hdl), (_cap) + PCI_MSI_32BIT_DATA, (_v));\ 293*12683SJimmy.Vetayases@oracle.com _NOTE(CONSTCOND)} while (0) 294*12683SJimmy.Vetayases@oracle.com 295*12683SJimmy.Vetayases@oracle.com static void 296*12683SJimmy.Vetayases@oracle.com apix_pci_msi_enable_vector(apix_vector_t *vecp, dev_info_t *dip, int type, 297*12683SJimmy.Vetayases@oracle.com int inum, int count, uchar_t vector, int target_apic_id) 298*12683SJimmy.Vetayases@oracle.com { 299*12683SJimmy.Vetayases@oracle.com uint64_t msi_addr, msi_data; 300*12683SJimmy.Vetayases@oracle.com ushort_t msi_ctrl; 301*12683SJimmy.Vetayases@oracle.com int i, cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip); 302*12683SJimmy.Vetayases@oracle.com ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(dip); 303*12683SJimmy.Vetayases@oracle.com msi_regs_t msi_regs; 304*12683SJimmy.Vetayases@oracle.com void *intrmap_tbl[PCI_MSI_MAX_INTRS]; 305*12683SJimmy.Vetayases@oracle.com 306*12683SJimmy.Vetayases@oracle.com DDI_INTR_IMPLDBG((CE_CONT, "apix_pci_msi_enable_vector: dip=0x%p\n" 307*12683SJimmy.Vetayases@oracle.com "\tdriver = %s, inum=0x%x vector=0x%x apicid=0x%x\n", (void *)dip, 308*12683SJimmy.Vetayases@oracle.com ddi_driver_name(dip), inum, vector, target_apic_id)); 309*12683SJimmy.Vetayases@oracle.com 310*12683SJimmy.Vetayases@oracle.com ASSERT((handle != NULL) && (cap_ptr != 0)); 311*12683SJimmy.Vetayases@oracle.com 312*12683SJimmy.Vetayases@oracle.com msi_regs.mr_data = vector; 313*12683SJimmy.Vetayases@oracle.com msi_regs.mr_addr = target_apic_id; 314*12683SJimmy.Vetayases@oracle.com 315*12683SJimmy.Vetayases@oracle.com intrmap_tbl[0] = vecp->v_intrmap_private; 316*12683SJimmy.Vetayases@oracle.com apic_vt_ops->apic_intrmap_alloc_entry(intrmap_tbl, dip, type, 317*12683SJimmy.Vetayases@oracle.com count, 0xff); 318*12683SJimmy.Vetayases@oracle.com for (i = 0; i < count; i++) 319*12683SJimmy.Vetayases@oracle.com xv_intrmap_private(vecp->v_cpuid, vector + i) = intrmap_tbl[i]; 320*12683SJimmy.Vetayases@oracle.com 321*12683SJimmy.Vetayases@oracle.com apic_vt_ops->apic_intrmap_map_entry(vecp->v_intrmap_private, 322*12683SJimmy.Vetayases@oracle.com (void *)&msi_regs, type, count); 323*12683SJimmy.Vetayases@oracle.com apic_vt_ops->apic_intrmap_record_msi(vecp->v_intrmap_private, 324*12683SJimmy.Vetayases@oracle.com &msi_regs); 325*12683SJimmy.Vetayases@oracle.com 326*12683SJimmy.Vetayases@oracle.com /* MSI Address */ 327*12683SJimmy.Vetayases@oracle.com msi_addr = msi_regs.mr_addr; 328*12683SJimmy.Vetayases@oracle.com 329*12683SJimmy.Vetayases@oracle.com /* MSI Data: MSI is edge triggered according to spec */ 330*12683SJimmy.Vetayases@oracle.com msi_data = msi_regs.mr_data; 331*12683SJimmy.Vetayases@oracle.com 332*12683SJimmy.Vetayases@oracle.com DDI_INTR_IMPLDBG((CE_CONT, "apix_pci_msi_enable_vector: addr=0x%lx " 333*12683SJimmy.Vetayases@oracle.com "data=0x%lx\n", (long)msi_addr, (long)msi_data)); 334*12683SJimmy.Vetayases@oracle.com 335*12683SJimmy.Vetayases@oracle.com if (type == APIX_TYPE_MSI) { 336*12683SJimmy.Vetayases@oracle.com msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL); 337*12683SJimmy.Vetayases@oracle.com 338*12683SJimmy.Vetayases@oracle.com /* Set the bits to inform how many MSIs are enabled */ 339*12683SJimmy.Vetayases@oracle.com msi_ctrl |= ((highbit(count) - 1) << PCI_MSI_MME_SHIFT); 340*12683SJimmy.Vetayases@oracle.com pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl); 341*12683SJimmy.Vetayases@oracle.com 342*12683SJimmy.Vetayases@oracle.com if ((vecp->v_flags & APIX_VECT_MASKABLE) == 0) 343*12683SJimmy.Vetayases@oracle.com APIX_WRITE_MSI_DATA(handle, cap_ptr, msi_ctrl, 344*12683SJimmy.Vetayases@oracle.com APIX_RESV_VECTOR); 345*12683SJimmy.Vetayases@oracle.com 346*12683SJimmy.Vetayases@oracle.com pci_config_put32(handle, 347*12683SJimmy.Vetayases@oracle.com cap_ptr + PCI_MSI_ADDR_OFFSET, msi_addr); 348*12683SJimmy.Vetayases@oracle.com if (msi_ctrl & PCI_MSI_64BIT_MASK) 349*12683SJimmy.Vetayases@oracle.com pci_config_put32(handle, 350*12683SJimmy.Vetayases@oracle.com cap_ptr + PCI_MSI_ADDR_OFFSET + 4, msi_addr >> 32); 351*12683SJimmy.Vetayases@oracle.com 352*12683SJimmy.Vetayases@oracle.com APIX_WRITE_MSI_DATA(handle, cap_ptr, msi_ctrl, msi_data); 353*12683SJimmy.Vetayases@oracle.com } else if (type == APIX_TYPE_MSIX) { 354*12683SJimmy.Vetayases@oracle.com uintptr_t off; 355*12683SJimmy.Vetayases@oracle.com ddi_intr_msix_t *msix_p = i_ddi_get_msix(dip); 356*12683SJimmy.Vetayases@oracle.com 357*12683SJimmy.Vetayases@oracle.com /* Offset into the "inum"th entry in the MSI-X table */ 358*12683SJimmy.Vetayases@oracle.com off = (uintptr_t)msix_p->msix_tbl_addr + 359*12683SJimmy.Vetayases@oracle.com (inum * PCI_MSIX_VECTOR_SIZE); 360*12683SJimmy.Vetayases@oracle.com 361*12683SJimmy.Vetayases@oracle.com ddi_put32(msix_p->msix_tbl_hdl, 362*12683SJimmy.Vetayases@oracle.com (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), msi_data); 363*12683SJimmy.Vetayases@oracle.com ddi_put64(msix_p->msix_tbl_hdl, 364*12683SJimmy.Vetayases@oracle.com (uint64_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET), msi_addr); 365*12683SJimmy.Vetayases@oracle.com } 366*12683SJimmy.Vetayases@oracle.com } 367*12683SJimmy.Vetayases@oracle.com 368*12683SJimmy.Vetayases@oracle.com static void 369*12683SJimmy.Vetayases@oracle.com apix_pci_msi_enable_mode(dev_info_t *dip, int type, int inum) 370*12683SJimmy.Vetayases@oracle.com { 371*12683SJimmy.Vetayases@oracle.com ushort_t msi_ctrl; 372*12683SJimmy.Vetayases@oracle.com int cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip); 373*12683SJimmy.Vetayases@oracle.com ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(dip); 374*12683SJimmy.Vetayases@oracle.com 375*12683SJimmy.Vetayases@oracle.com ASSERT((handle != NULL) && (cap_ptr != 0)); 376*12683SJimmy.Vetayases@oracle.com 377*12683SJimmy.Vetayases@oracle.com if (type == APIX_TYPE_MSI) { 378*12683SJimmy.Vetayases@oracle.com msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL); 379*12683SJimmy.Vetayases@oracle.com if ((msi_ctrl & PCI_MSI_ENABLE_BIT)) 380*12683SJimmy.Vetayases@oracle.com return; 381*12683SJimmy.Vetayases@oracle.com 382*12683SJimmy.Vetayases@oracle.com msi_ctrl |= PCI_MSI_ENABLE_BIT; 383*12683SJimmy.Vetayases@oracle.com pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl); 384*12683SJimmy.Vetayases@oracle.com 385*12683SJimmy.Vetayases@oracle.com } else if (type == DDI_INTR_TYPE_MSIX) { 386*12683SJimmy.Vetayases@oracle.com uintptr_t off; 387*12683SJimmy.Vetayases@oracle.com uint32_t mask; 388*12683SJimmy.Vetayases@oracle.com ddi_intr_msix_t *msix_p; 389*12683SJimmy.Vetayases@oracle.com 390*12683SJimmy.Vetayases@oracle.com msix_p = i_ddi_get_msix(dip); 391*12683SJimmy.Vetayases@oracle.com 392*12683SJimmy.Vetayases@oracle.com /* Offset into "inum"th entry in the MSI-X table & clear mask */ 393*12683SJimmy.Vetayases@oracle.com off = (uintptr_t)msix_p->msix_tbl_addr + (inum * 394*12683SJimmy.Vetayases@oracle.com PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET; 395*12683SJimmy.Vetayases@oracle.com 396*12683SJimmy.Vetayases@oracle.com mask = ddi_get32(msix_p->msix_tbl_hdl, (uint32_t *)off); 397*12683SJimmy.Vetayases@oracle.com 398*12683SJimmy.Vetayases@oracle.com ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, (mask & ~1)); 399*12683SJimmy.Vetayases@oracle.com 400*12683SJimmy.Vetayases@oracle.com msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSIX_CTRL); 401*12683SJimmy.Vetayases@oracle.com 402*12683SJimmy.Vetayases@oracle.com if (!(msi_ctrl & PCI_MSIX_ENABLE_BIT)) { 403*12683SJimmy.Vetayases@oracle.com msi_ctrl |= PCI_MSIX_ENABLE_BIT; 404*12683SJimmy.Vetayases@oracle.com pci_config_put16(handle, cap_ptr + PCI_MSIX_CTRL, 405*12683SJimmy.Vetayases@oracle.com msi_ctrl); 406*12683SJimmy.Vetayases@oracle.com } 407*12683SJimmy.Vetayases@oracle.com } 408*12683SJimmy.Vetayases@oracle.com } 409*12683SJimmy.Vetayases@oracle.com 410*12683SJimmy.Vetayases@oracle.com /* 411*12683SJimmy.Vetayases@oracle.com * Setup interrupt, pogramming IO-APIC or MSI/X address/data. 412*12683SJimmy.Vetayases@oracle.com */ 413*12683SJimmy.Vetayases@oracle.com void 414*12683SJimmy.Vetayases@oracle.com apix_enable_vector(apix_vector_t *vecp) 415*12683SJimmy.Vetayases@oracle.com { 416*12683SJimmy.Vetayases@oracle.com int tocpu = vecp->v_cpuid, type = vecp->v_type; 417*12683SJimmy.Vetayases@oracle.com apic_cpus_info_t *cpu_infop; 418*12683SJimmy.Vetayases@oracle.com ulong_t iflag; 419*12683SJimmy.Vetayases@oracle.com 420*12683SJimmy.Vetayases@oracle.com ASSERT(tocpu < apic_nproc); 421*12683SJimmy.Vetayases@oracle.com 422*12683SJimmy.Vetayases@oracle.com cpu_infop = &apic_cpus[tocpu]; 423*12683SJimmy.Vetayases@oracle.com if (vecp->v_flags & APIX_VECT_USER_BOUND) 424*12683SJimmy.Vetayases@oracle.com cpu_infop->aci_bound++; 425*12683SJimmy.Vetayases@oracle.com else 426*12683SJimmy.Vetayases@oracle.com cpu_infop->aci_temp_bound++; 427*12683SJimmy.Vetayases@oracle.com 428*12683SJimmy.Vetayases@oracle.com iflag = intr_clear(); 429*12683SJimmy.Vetayases@oracle.com lock_set(&apic_ioapic_lock); 430*12683SJimmy.Vetayases@oracle.com 431*12683SJimmy.Vetayases@oracle.com if (!DDI_INTR_IS_MSI_OR_MSIX(type)) { /* fixed */ 432*12683SJimmy.Vetayases@oracle.com apix_intx_enable(vecp->v_inum); 433*12683SJimmy.Vetayases@oracle.com } else { 434*12683SJimmy.Vetayases@oracle.com int inum = vecp->v_inum; 435*12683SJimmy.Vetayases@oracle.com dev_info_t *dip = APIX_GET_DIP(vecp); 436*12683SJimmy.Vetayases@oracle.com int count = i_ddi_intr_get_current_nintrs(dip); 437*12683SJimmy.Vetayases@oracle.com 438*12683SJimmy.Vetayases@oracle.com if (type == APIX_TYPE_MSI) { /* MSI */ 439*12683SJimmy.Vetayases@oracle.com if (inum == apix_get_max_dev_inum(dip, type)) { 440*12683SJimmy.Vetayases@oracle.com /* last one */ 441*12683SJimmy.Vetayases@oracle.com uchar_t start_inum = inum + 1 - count; 442*12683SJimmy.Vetayases@oracle.com uchar_t start_vect = vecp->v_vector + 1 - count; 443*12683SJimmy.Vetayases@oracle.com apix_vector_t *start_vecp = 444*12683SJimmy.Vetayases@oracle.com xv_vector(vecp->v_cpuid, start_vect); 445*12683SJimmy.Vetayases@oracle.com 446*12683SJimmy.Vetayases@oracle.com APIC_VERBOSE(INTR, (CE_CONT, "apix: call " 447*12683SJimmy.Vetayases@oracle.com "apix_pci_msi_enable_vector\n")); 448*12683SJimmy.Vetayases@oracle.com apix_pci_msi_enable_vector(start_vecp, dip, 449*12683SJimmy.Vetayases@oracle.com type, start_inum, count, start_vect, 450*12683SJimmy.Vetayases@oracle.com cpu_infop->aci_local_id); 451*12683SJimmy.Vetayases@oracle.com 452*12683SJimmy.Vetayases@oracle.com APIC_VERBOSE(INTR, (CE_CONT, "apix: call " 453*12683SJimmy.Vetayases@oracle.com "apix_pci_msi_enable_mode\n")); 454*12683SJimmy.Vetayases@oracle.com apix_pci_msi_enable_mode(dip, type, inum); 455*12683SJimmy.Vetayases@oracle.com } 456*12683SJimmy.Vetayases@oracle.com } else { /* MSI-X */ 457*12683SJimmy.Vetayases@oracle.com apix_pci_msi_enable_vector(vecp, dip, 458*12683SJimmy.Vetayases@oracle.com type, inum, 1, vecp->v_vector, 459*12683SJimmy.Vetayases@oracle.com cpu_infop->aci_local_id); 460*12683SJimmy.Vetayases@oracle.com apix_pci_msi_enable_mode(dip, type, inum); 461*12683SJimmy.Vetayases@oracle.com } 462*12683SJimmy.Vetayases@oracle.com } 463*12683SJimmy.Vetayases@oracle.com vecp->v_state = APIX_STATE_ENABLED; 464*12683SJimmy.Vetayases@oracle.com apic_redist_cpu_skip &= ~(1 << tocpu); 465*12683SJimmy.Vetayases@oracle.com 466*12683SJimmy.Vetayases@oracle.com lock_clear(&apic_ioapic_lock); 467*12683SJimmy.Vetayases@oracle.com intr_restore(iflag); 468*12683SJimmy.Vetayases@oracle.com } 469*12683SJimmy.Vetayases@oracle.com 470*12683SJimmy.Vetayases@oracle.com /* 471*12683SJimmy.Vetayases@oracle.com * Disable the interrupt 472*12683SJimmy.Vetayases@oracle.com */ 473*12683SJimmy.Vetayases@oracle.com void 474*12683SJimmy.Vetayases@oracle.com apix_disable_vector(apix_vector_t *vecp) 475*12683SJimmy.Vetayases@oracle.com { 476*12683SJimmy.Vetayases@oracle.com struct autovec *avp = vecp->v_autovect; 477*12683SJimmy.Vetayases@oracle.com ulong_t iflag; 478*12683SJimmy.Vetayases@oracle.com 479*12683SJimmy.Vetayases@oracle.com ASSERT(avp != NULL); 480*12683SJimmy.Vetayases@oracle.com 481*12683SJimmy.Vetayases@oracle.com iflag = intr_clear(); 482*12683SJimmy.Vetayases@oracle.com lock_set(&apic_ioapic_lock); 483*12683SJimmy.Vetayases@oracle.com 484*12683SJimmy.Vetayases@oracle.com switch (vecp->v_type) { 485*12683SJimmy.Vetayases@oracle.com case APIX_TYPE_MSI: 486*12683SJimmy.Vetayases@oracle.com ASSERT(avp->av_vector != NULL && avp->av_dip != NULL); 487*12683SJimmy.Vetayases@oracle.com /* 488*12683SJimmy.Vetayases@oracle.com * Disable the MSI vector 489*12683SJimmy.Vetayases@oracle.com * Make sure we only disable on the last 490*12683SJimmy.Vetayases@oracle.com * of the multi-MSI support 491*12683SJimmy.Vetayases@oracle.com */ 492*12683SJimmy.Vetayases@oracle.com if (i_ddi_intr_get_current_nenables(avp->av_dip) == 1) { 493*12683SJimmy.Vetayases@oracle.com apic_pci_msi_disable_mode(avp->av_dip, 494*12683SJimmy.Vetayases@oracle.com DDI_INTR_TYPE_MSI); 495*12683SJimmy.Vetayases@oracle.com } 496*12683SJimmy.Vetayases@oracle.com break; 497*12683SJimmy.Vetayases@oracle.com case APIX_TYPE_MSIX: 498*12683SJimmy.Vetayases@oracle.com ASSERT(avp->av_vector != NULL && avp->av_dip != NULL); 499*12683SJimmy.Vetayases@oracle.com /* 500*12683SJimmy.Vetayases@oracle.com * Disable the MSI-X vector 501*12683SJimmy.Vetayases@oracle.com * needs to clear its mask and addr/data for each MSI-X 502*12683SJimmy.Vetayases@oracle.com */ 503*12683SJimmy.Vetayases@oracle.com apic_pci_msi_unconfigure(avp->av_dip, DDI_INTR_TYPE_MSIX, 504*12683SJimmy.Vetayases@oracle.com vecp->v_inum); 505*12683SJimmy.Vetayases@oracle.com /* 506*12683SJimmy.Vetayases@oracle.com * Make sure we only disable on the last MSI-X 507*12683SJimmy.Vetayases@oracle.com */ 508*12683SJimmy.Vetayases@oracle.com if (i_ddi_intr_get_current_nenables(avp->av_dip) == 1) { 509*12683SJimmy.Vetayases@oracle.com apic_pci_msi_disable_mode(avp->av_dip, 510*12683SJimmy.Vetayases@oracle.com DDI_INTR_TYPE_MSIX); 511*12683SJimmy.Vetayases@oracle.com } 512*12683SJimmy.Vetayases@oracle.com break; 513*12683SJimmy.Vetayases@oracle.com default: 514*12683SJimmy.Vetayases@oracle.com apix_intx_disable(vecp->v_inum); 515*12683SJimmy.Vetayases@oracle.com break; 516*12683SJimmy.Vetayases@oracle.com } 517*12683SJimmy.Vetayases@oracle.com 518*12683SJimmy.Vetayases@oracle.com if (!(apic_cpus[vecp->v_cpuid].aci_status & APIC_CPU_SUSPEND)) 519*12683SJimmy.Vetayases@oracle.com vecp->v_state = APIX_STATE_DISABLED; 520*12683SJimmy.Vetayases@oracle.com apic_vt_ops->apic_intrmap_free_entry(&vecp->v_intrmap_private); 521*12683SJimmy.Vetayases@oracle.com vecp->v_intrmap_private = NULL; 522*12683SJimmy.Vetayases@oracle.com 523*12683SJimmy.Vetayases@oracle.com lock_clear(&apic_ioapic_lock); 524*12683SJimmy.Vetayases@oracle.com intr_restore(iflag); 525*12683SJimmy.Vetayases@oracle.com } 526*12683SJimmy.Vetayases@oracle.com 527*12683SJimmy.Vetayases@oracle.com /* 528*12683SJimmy.Vetayases@oracle.com * Mark vector as obsoleted or freed. The vector is marked 529*12683SJimmy.Vetayases@oracle.com * obsoleted if there are pending requests on it. Otherwise, 530*12683SJimmy.Vetayases@oracle.com * free the vector. The obsoleted vectors get freed after 531*12683SJimmy.Vetayases@oracle.com * being serviced. 532*12683SJimmy.Vetayases@oracle.com * 533*12683SJimmy.Vetayases@oracle.com * Return 1 on being obosoleted and 0 on being freed. 534*12683SJimmy.Vetayases@oracle.com */ 535*12683SJimmy.Vetayases@oracle.com #define INTR_BUSY(_avp)\ 536*12683SJimmy.Vetayases@oracle.com ((((volatile ushort_t)(_avp)->av_flags) &\ 537*12683SJimmy.Vetayases@oracle.com (AV_PENTRY_PEND | AV_PENTRY_ONPROC)) != 0) 538*12683SJimmy.Vetayases@oracle.com #define LOCAL_WITH_INTR_DISABLED(_cpuid)\ 539*12683SJimmy.Vetayases@oracle.com ((_cpuid) == psm_get_cpu_id() && !interrupts_enabled()) 540*12683SJimmy.Vetayases@oracle.com static uint64_t dummy_tick; 541*12683SJimmy.Vetayases@oracle.com 542*12683SJimmy.Vetayases@oracle.com int 543*12683SJimmy.Vetayases@oracle.com apix_obsolete_vector(apix_vector_t *vecp) 544*12683SJimmy.Vetayases@oracle.com { 545*12683SJimmy.Vetayases@oracle.com struct autovec *avp = vecp->v_autovect; 546*12683SJimmy.Vetayases@oracle.com int repeats, tries, ipl, busy = 0, cpuid = vecp->v_cpuid; 547*12683SJimmy.Vetayases@oracle.com apix_impl_t *apixp = apixs[cpuid]; 548*12683SJimmy.Vetayases@oracle.com 549*12683SJimmy.Vetayases@oracle.com ASSERT(APIX_CPU_LOCK_HELD(cpuid)); 550*12683SJimmy.Vetayases@oracle.com 551*12683SJimmy.Vetayases@oracle.com for (avp = vecp->v_autovect; avp != NULL; avp = avp->av_link) { 552*12683SJimmy.Vetayases@oracle.com if (avp->av_vector == NULL) 553*12683SJimmy.Vetayases@oracle.com continue; 554*12683SJimmy.Vetayases@oracle.com 555*12683SJimmy.Vetayases@oracle.com if (LOCAL_WITH_INTR_DISABLED(cpuid)) { 556*12683SJimmy.Vetayases@oracle.com int bit, index, irr; 557*12683SJimmy.Vetayases@oracle.com 558*12683SJimmy.Vetayases@oracle.com if (INTR_BUSY(avp)) { 559*12683SJimmy.Vetayases@oracle.com busy++; 560*12683SJimmy.Vetayases@oracle.com continue; 561*12683SJimmy.Vetayases@oracle.com } 562*12683SJimmy.Vetayases@oracle.com 563*12683SJimmy.Vetayases@oracle.com /* check IRR for pending interrupts */ 564*12683SJimmy.Vetayases@oracle.com index = vecp->v_vector / 32; 565*12683SJimmy.Vetayases@oracle.com bit = vecp->v_vector % 32; 566*12683SJimmy.Vetayases@oracle.com irr = apic_reg_ops->apic_read(APIC_IRR_REG + index); 567*12683SJimmy.Vetayases@oracle.com if ((irr & (1 << bit)) != 0) 568*12683SJimmy.Vetayases@oracle.com busy++; 569*12683SJimmy.Vetayases@oracle.com 570*12683SJimmy.Vetayases@oracle.com if (!busy) 571*12683SJimmy.Vetayases@oracle.com apix_remove_av(vecp, avp); 572*12683SJimmy.Vetayases@oracle.com 573*12683SJimmy.Vetayases@oracle.com continue; 574*12683SJimmy.Vetayases@oracle.com } 575*12683SJimmy.Vetayases@oracle.com 576*12683SJimmy.Vetayases@oracle.com repeats = 0; 577*12683SJimmy.Vetayases@oracle.com do { 578*12683SJimmy.Vetayases@oracle.com repeats++; 579*12683SJimmy.Vetayases@oracle.com for (tries = 0; tries < apic_max_reps_clear_pending; 580*12683SJimmy.Vetayases@oracle.com tries++) 581*12683SJimmy.Vetayases@oracle.com if (!INTR_BUSY(avp)) 582*12683SJimmy.Vetayases@oracle.com break; 583*12683SJimmy.Vetayases@oracle.com } while (INTR_BUSY(avp) && 584*12683SJimmy.Vetayases@oracle.com (repeats < apic_max_reps_clear_pending)); 585*12683SJimmy.Vetayases@oracle.com 586*12683SJimmy.Vetayases@oracle.com if (INTR_BUSY(avp)) 587*12683SJimmy.Vetayases@oracle.com busy++; 588*12683SJimmy.Vetayases@oracle.com else { 589*12683SJimmy.Vetayases@oracle.com /* 590*12683SJimmy.Vetayases@oracle.com * Interrupt is not in pending list or being serviced. 591*12683SJimmy.Vetayases@oracle.com * However it might be cached in Local APIC's IRR 592*12683SJimmy.Vetayases@oracle.com * register. It's impossible to check another CPU's 593*12683SJimmy.Vetayases@oracle.com * IRR register. Then wait till lower levels finish 594*12683SJimmy.Vetayases@oracle.com * running. 595*12683SJimmy.Vetayases@oracle.com */ 596*12683SJimmy.Vetayases@oracle.com for (ipl = 1; ipl < MIN(LOCK_LEVEL, vecp->v_pri); ipl++) 597*12683SJimmy.Vetayases@oracle.com apix_wait_till_seen(cpuid, ipl); 598*12683SJimmy.Vetayases@oracle.com if (INTR_BUSY(avp)) 599*12683SJimmy.Vetayases@oracle.com busy++; 600*12683SJimmy.Vetayases@oracle.com } 601*12683SJimmy.Vetayases@oracle.com 602*12683SJimmy.Vetayases@oracle.com if (!busy) 603*12683SJimmy.Vetayases@oracle.com apix_remove_av(vecp, avp); 604*12683SJimmy.Vetayases@oracle.com } 605*12683SJimmy.Vetayases@oracle.com 606*12683SJimmy.Vetayases@oracle.com if (busy) { 607*12683SJimmy.Vetayases@oracle.com apix_vector_t *tp = apixp->x_obsoletes; 608*12683SJimmy.Vetayases@oracle.com 609*12683SJimmy.Vetayases@oracle.com if (vecp->v_state == APIX_STATE_OBSOLETED) 610*12683SJimmy.Vetayases@oracle.com return (1); 611*12683SJimmy.Vetayases@oracle.com 612*12683SJimmy.Vetayases@oracle.com vecp->v_state = APIX_STATE_OBSOLETED; 613*12683SJimmy.Vetayases@oracle.com vecp->v_next = NULL; 614*12683SJimmy.Vetayases@oracle.com if (tp == NULL) 615*12683SJimmy.Vetayases@oracle.com apixp->x_obsoletes = vecp; 616*12683SJimmy.Vetayases@oracle.com else { 617*12683SJimmy.Vetayases@oracle.com while (tp->v_next != NULL) 618*12683SJimmy.Vetayases@oracle.com tp = tp->v_next; 619*12683SJimmy.Vetayases@oracle.com tp->v_next = vecp; 620*12683SJimmy.Vetayases@oracle.com } 621*12683SJimmy.Vetayases@oracle.com return (1); 622*12683SJimmy.Vetayases@oracle.com } 623*12683SJimmy.Vetayases@oracle.com 624*12683SJimmy.Vetayases@oracle.com /* interrupt is not busy */ 625*12683SJimmy.Vetayases@oracle.com if (vecp->v_state == APIX_STATE_OBSOLETED) { 626*12683SJimmy.Vetayases@oracle.com /* remove from obsoleted list */ 627*12683SJimmy.Vetayases@oracle.com apixp->x_obsoletes = vecp->v_next; 628*12683SJimmy.Vetayases@oracle.com vecp->v_next = NULL; 629*12683SJimmy.Vetayases@oracle.com } 630*12683SJimmy.Vetayases@oracle.com apix_cleanup_vector(vecp); 631*12683SJimmy.Vetayases@oracle.com return (0); 632*12683SJimmy.Vetayases@oracle.com } 633*12683SJimmy.Vetayases@oracle.com 634*12683SJimmy.Vetayases@oracle.com /* 635*12683SJimmy.Vetayases@oracle.com * Duplicate number of continuous vectors to specified target vectors. 636*12683SJimmy.Vetayases@oracle.com */ 637*12683SJimmy.Vetayases@oracle.com static void 638*12683SJimmy.Vetayases@oracle.com apix_dup_vectors(apix_vector_t *oldp, apix_vector_t *newp, int count) 639*12683SJimmy.Vetayases@oracle.com { 640*12683SJimmy.Vetayases@oracle.com struct autovec *avp; 641*12683SJimmy.Vetayases@oracle.com apix_vector_t *fromp, *top; 642*12683SJimmy.Vetayases@oracle.com processorid_t oldcpu = oldp->v_cpuid, newcpu = newp->v_cpuid; 643*12683SJimmy.Vetayases@oracle.com uchar_t oldvec = oldp->v_vector, newvec = newp->v_vector; 644*12683SJimmy.Vetayases@oracle.com int i, inum; 645*12683SJimmy.Vetayases@oracle.com 646*12683SJimmy.Vetayases@oracle.com ASSERT(oldp->v_type != APIX_TYPE_IPI); 647*12683SJimmy.Vetayases@oracle.com 648*12683SJimmy.Vetayases@oracle.com for (i = 0; i < count; i++) { 649*12683SJimmy.Vetayases@oracle.com fromp = xv_vector(oldcpu, oldvec + i); 650*12683SJimmy.Vetayases@oracle.com top = xv_vector(newcpu, newvec + i); 651*12683SJimmy.Vetayases@oracle.com ASSERT(fromp != NULL && top != NULL); 652*12683SJimmy.Vetayases@oracle.com 653*12683SJimmy.Vetayases@oracle.com /* copy over original one */ 654*12683SJimmy.Vetayases@oracle.com top->v_state = fromp->v_state; 655*12683SJimmy.Vetayases@oracle.com top->v_type = fromp->v_type; 656*12683SJimmy.Vetayases@oracle.com top->v_bound_cpuid = fromp->v_bound_cpuid; 657*12683SJimmy.Vetayases@oracle.com top->v_inum = fromp->v_inum; 658*12683SJimmy.Vetayases@oracle.com top->v_flags = fromp->v_flags; 659*12683SJimmy.Vetayases@oracle.com top->v_intrmap_private = fromp->v_intrmap_private; 660*12683SJimmy.Vetayases@oracle.com 661*12683SJimmy.Vetayases@oracle.com for (avp = fromp->v_autovect; avp != NULL; avp = avp->av_link) { 662*12683SJimmy.Vetayases@oracle.com if (avp->av_vector == NULL) 663*12683SJimmy.Vetayases@oracle.com continue; 664*12683SJimmy.Vetayases@oracle.com 665*12683SJimmy.Vetayases@oracle.com apix_insert_av(top, avp->av_intr_id, avp->av_vector, 666*12683SJimmy.Vetayases@oracle.com avp->av_intarg1, avp->av_intarg2, avp->av_ticksp, 667*12683SJimmy.Vetayases@oracle.com avp->av_prilevel, avp->av_dip); 668*12683SJimmy.Vetayases@oracle.com 669*12683SJimmy.Vetayases@oracle.com if (fromp->v_type == APIX_TYPE_FIXED && 670*12683SJimmy.Vetayases@oracle.com avp->av_dip != NULL) { 671*12683SJimmy.Vetayases@oracle.com inum = GET_INTR_INUM(avp->av_intr_id); 672*12683SJimmy.Vetayases@oracle.com apix_set_dev_map(top, avp->av_dip, inum); 673*12683SJimmy.Vetayases@oracle.com } 674*12683SJimmy.Vetayases@oracle.com } 675*12683SJimmy.Vetayases@oracle.com 676*12683SJimmy.Vetayases@oracle.com if (DDI_INTR_IS_MSI_OR_MSIX(fromp->v_type) && 677*12683SJimmy.Vetayases@oracle.com fromp->v_devp != NULL) 678*12683SJimmy.Vetayases@oracle.com apix_set_dev_map(top, fromp->v_devp->dv_dip, 679*12683SJimmy.Vetayases@oracle.com fromp->v_devp->dv_inum); 680*12683SJimmy.Vetayases@oracle.com } 681*12683SJimmy.Vetayases@oracle.com } 682*12683SJimmy.Vetayases@oracle.com 683*12683SJimmy.Vetayases@oracle.com static apix_vector_t * 684*12683SJimmy.Vetayases@oracle.com apix_init_vector(processorid_t cpuid, uchar_t vector) 685*12683SJimmy.Vetayases@oracle.com { 686*12683SJimmy.Vetayases@oracle.com apix_impl_t *apixp = apixs[cpuid]; 687*12683SJimmy.Vetayases@oracle.com apix_vector_t *vecp = apixp->x_vectbl[vector]; 688*12683SJimmy.Vetayases@oracle.com 689*12683SJimmy.Vetayases@oracle.com ASSERT(IS_VECT_FREE(vecp)); 690*12683SJimmy.Vetayases@oracle.com 691*12683SJimmy.Vetayases@oracle.com if (vecp == NULL) { 692*12683SJimmy.Vetayases@oracle.com vecp = kmem_zalloc(sizeof (apix_vector_t), KM_NOSLEEP); 693*12683SJimmy.Vetayases@oracle.com if (vecp == NULL) { 694*12683SJimmy.Vetayases@oracle.com cmn_err(CE_WARN, "apix: no memory to allocate vector"); 695*12683SJimmy.Vetayases@oracle.com return (NULL); 696*12683SJimmy.Vetayases@oracle.com } 697*12683SJimmy.Vetayases@oracle.com apixp->x_vectbl[vector] = vecp; 698*12683SJimmy.Vetayases@oracle.com } 699*12683SJimmy.Vetayases@oracle.com vecp->v_state = APIX_STATE_ALLOCED; 700*12683SJimmy.Vetayases@oracle.com vecp->v_cpuid = vecp->v_bound_cpuid = cpuid; 701*12683SJimmy.Vetayases@oracle.com vecp->v_vector = vector; 702*12683SJimmy.Vetayases@oracle.com 703*12683SJimmy.Vetayases@oracle.com return (vecp); 704*12683SJimmy.Vetayases@oracle.com } 705*12683SJimmy.Vetayases@oracle.com 706*12683SJimmy.Vetayases@oracle.com static void 707*12683SJimmy.Vetayases@oracle.com apix_cleanup_vector(apix_vector_t *vecp) 708*12683SJimmy.Vetayases@oracle.com { 709*12683SJimmy.Vetayases@oracle.com ASSERT(vecp->v_share == 0); 710*12683SJimmy.Vetayases@oracle.com vecp->v_bound_cpuid = IRQ_UNINIT; 711*12683SJimmy.Vetayases@oracle.com vecp->v_state = APIX_STATE_FREED; 712*12683SJimmy.Vetayases@oracle.com vecp->v_type = 0; 713*12683SJimmy.Vetayases@oracle.com vecp->v_flags = 0; 714*12683SJimmy.Vetayases@oracle.com vecp->v_busy = 0; 715*12683SJimmy.Vetayases@oracle.com } 716*12683SJimmy.Vetayases@oracle.com 717*12683SJimmy.Vetayases@oracle.com static void 718*12683SJimmy.Vetayases@oracle.com apix_dprint_vector(apix_vector_t *vecp, dev_info_t *dip, int count) 719*12683SJimmy.Vetayases@oracle.com { 720*12683SJimmy.Vetayases@oracle.com #ifdef DEBUG 721*12683SJimmy.Vetayases@oracle.com major_t major; 722*12683SJimmy.Vetayases@oracle.com char *name, *drv_name; 723*12683SJimmy.Vetayases@oracle.com int instance, len, t_len; 724*12683SJimmy.Vetayases@oracle.com char mesg[1024] = "apix: "; 725*12683SJimmy.Vetayases@oracle.com 726*12683SJimmy.Vetayases@oracle.com t_len = sizeof (mesg); 727*12683SJimmy.Vetayases@oracle.com len = strlen(mesg); 728*12683SJimmy.Vetayases@oracle.com if (dip != NULL) { 729*12683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 730*12683SJimmy.Vetayases@oracle.com major = ddi_name_to_major(name); 731*12683SJimmy.Vetayases@oracle.com drv_name = ddi_major_to_name(major); 732*12683SJimmy.Vetayases@oracle.com instance = ddi_get_instance(dip); 733*12683SJimmy.Vetayases@oracle.com (void) snprintf(mesg + len, t_len - len, "%s (%s) instance %d ", 734*12683SJimmy.Vetayases@oracle.com name, drv_name, instance); 735*12683SJimmy.Vetayases@oracle.com } 736*12683SJimmy.Vetayases@oracle.com len = strlen(mesg); 737*12683SJimmy.Vetayases@oracle.com 738*12683SJimmy.Vetayases@oracle.com switch (vecp->v_type) { 739*12683SJimmy.Vetayases@oracle.com case APIX_TYPE_FIXED: 740*12683SJimmy.Vetayases@oracle.com (void) snprintf(mesg + len, t_len - len, "irqno %d", 741*12683SJimmy.Vetayases@oracle.com vecp->v_inum); 742*12683SJimmy.Vetayases@oracle.com break; 743*12683SJimmy.Vetayases@oracle.com case APIX_TYPE_MSI: 744*12683SJimmy.Vetayases@oracle.com (void) snprintf(mesg + len, t_len - len, 745*12683SJimmy.Vetayases@oracle.com "msi inum %d (count %d)", vecp->v_inum, count); 746*12683SJimmy.Vetayases@oracle.com break; 747*12683SJimmy.Vetayases@oracle.com case APIX_TYPE_MSIX: 748*12683SJimmy.Vetayases@oracle.com (void) snprintf(mesg + len, t_len - len, "msi-x inum %d", 749*12683SJimmy.Vetayases@oracle.com vecp->v_inum); 750*12683SJimmy.Vetayases@oracle.com break; 751*12683SJimmy.Vetayases@oracle.com default: 752*12683SJimmy.Vetayases@oracle.com break; 753*12683SJimmy.Vetayases@oracle.com 754*12683SJimmy.Vetayases@oracle.com } 755*12683SJimmy.Vetayases@oracle.com 756*12683SJimmy.Vetayases@oracle.com APIC_VERBOSE(ALLOC, (CE_CONT, "%s allocated with vector 0x%x on " 757*12683SJimmy.Vetayases@oracle.com "cpu %d\n", mesg, vecp->v_vector, vecp->v_cpuid)); 758*12683SJimmy.Vetayases@oracle.com #endif /* DEBUG */ 759*12683SJimmy.Vetayases@oracle.com } 760*12683SJimmy.Vetayases@oracle.com 761*12683SJimmy.Vetayases@oracle.com /* 762*12683SJimmy.Vetayases@oracle.com * Operations on avintr 763*12683SJimmy.Vetayases@oracle.com */ 764*12683SJimmy.Vetayases@oracle.com 765*12683SJimmy.Vetayases@oracle.com #define INIT_AUTOVEC(p, intr_id, f, arg1, arg2, ticksp, ipl, dip) \ 766*12683SJimmy.Vetayases@oracle.com do { \ 767*12683SJimmy.Vetayases@oracle.com (p)->av_intr_id = intr_id; \ 768*12683SJimmy.Vetayases@oracle.com (p)->av_vector = f; \ 769*12683SJimmy.Vetayases@oracle.com (p)->av_intarg1 = arg1; \ 770*12683SJimmy.Vetayases@oracle.com (p)->av_intarg2 = arg2; \ 771*12683SJimmy.Vetayases@oracle.com (p)->av_ticksp = ticksp; \ 772*12683SJimmy.Vetayases@oracle.com (p)->av_prilevel = ipl; \ 773*12683SJimmy.Vetayases@oracle.com (p)->av_dip = dip; \ 774*12683SJimmy.Vetayases@oracle.com (p)->av_flags = 0; \ 775*12683SJimmy.Vetayases@oracle.com _NOTE(CONSTCOND)} while (0) 776*12683SJimmy.Vetayases@oracle.com 777*12683SJimmy.Vetayases@oracle.com /* 778*12683SJimmy.Vetayases@oracle.com * Insert an interrupt service routine into chain by its priority from 779*12683SJimmy.Vetayases@oracle.com * high to low 780*12683SJimmy.Vetayases@oracle.com */ 781*12683SJimmy.Vetayases@oracle.com static void 782*12683SJimmy.Vetayases@oracle.com apix_insert_av(apix_vector_t *vecp, void *intr_id, avfunc f, caddr_t arg1, 783*12683SJimmy.Vetayases@oracle.com caddr_t arg2, uint64_t *ticksp, int ipl, dev_info_t *dip) 784*12683SJimmy.Vetayases@oracle.com { 785*12683SJimmy.Vetayases@oracle.com struct autovec *p, *prep, *mem; 786*12683SJimmy.Vetayases@oracle.com 787*12683SJimmy.Vetayases@oracle.com APIC_VERBOSE(INTR, (CE_CONT, "apix_insert_av: dip %p, vector 0x%x, " 788*12683SJimmy.Vetayases@oracle.com "cpu %d\n", (void *)dip, vecp->v_vector, vecp->v_cpuid)); 789*12683SJimmy.Vetayases@oracle.com 790*12683SJimmy.Vetayases@oracle.com mem = kmem_zalloc(sizeof (struct autovec), KM_SLEEP); 791*12683SJimmy.Vetayases@oracle.com INIT_AUTOVEC(mem, intr_id, f, arg1, arg2, ticksp, ipl, dip); 792*12683SJimmy.Vetayases@oracle.com if (vecp->v_type == APIX_TYPE_FIXED && apic_level_intr[vecp->v_inum]) 793*12683SJimmy.Vetayases@oracle.com mem->av_flags |= AV_PENTRY_LEVEL; 794*12683SJimmy.Vetayases@oracle.com 795*12683SJimmy.Vetayases@oracle.com vecp->v_share++; 796*12683SJimmy.Vetayases@oracle.com vecp->v_pri = (ipl > vecp->v_pri) ? ipl : vecp->v_pri; 797*12683SJimmy.Vetayases@oracle.com if (vecp->v_autovect == NULL) { /* Nothing on list - put it at head */ 798*12683SJimmy.Vetayases@oracle.com vecp->v_autovect = mem; 799*12683SJimmy.Vetayases@oracle.com return; 800*12683SJimmy.Vetayases@oracle.com } 801*12683SJimmy.Vetayases@oracle.com 802*12683SJimmy.Vetayases@oracle.com if (DDI_INTR_IS_MSI_OR_MSIX(vecp->v_type)) { /* MSI/X */ 803*12683SJimmy.Vetayases@oracle.com ASSERT(vecp->v_share == 1); /* No sharing for MSI/X */ 804*12683SJimmy.Vetayases@oracle.com 805*12683SJimmy.Vetayases@oracle.com INIT_AUTOVEC(vecp->v_autovect, intr_id, f, arg1, arg2, ticksp, 806*12683SJimmy.Vetayases@oracle.com ipl, dip); 807*12683SJimmy.Vetayases@oracle.com prep = vecp->v_autovect->av_link; 808*12683SJimmy.Vetayases@oracle.com vecp->v_autovect->av_link = NULL; 809*12683SJimmy.Vetayases@oracle.com 810*12683SJimmy.Vetayases@oracle.com /* Free the following autovect chain */ 811*12683SJimmy.Vetayases@oracle.com while (prep != NULL) { 812*12683SJimmy.Vetayases@oracle.com ASSERT(prep->av_vector == NULL); 813*12683SJimmy.Vetayases@oracle.com 814*12683SJimmy.Vetayases@oracle.com p = prep; 815*12683SJimmy.Vetayases@oracle.com prep = prep->av_link; 816*12683SJimmy.Vetayases@oracle.com kmem_free(p, sizeof (struct autovec)); 817*12683SJimmy.Vetayases@oracle.com } 818*12683SJimmy.Vetayases@oracle.com 819*12683SJimmy.Vetayases@oracle.com kmem_free(mem, sizeof (struct autovec)); 820*12683SJimmy.Vetayases@oracle.com return; 821*12683SJimmy.Vetayases@oracle.com } 822*12683SJimmy.Vetayases@oracle.com 823*12683SJimmy.Vetayases@oracle.com /* find where it goes in list */ 824*12683SJimmy.Vetayases@oracle.com prep = NULL; 825*12683SJimmy.Vetayases@oracle.com for (p = vecp->v_autovect; p != NULL; p = p->av_link) { 826*12683SJimmy.Vetayases@oracle.com if (p->av_vector && p->av_prilevel <= ipl) 827*12683SJimmy.Vetayases@oracle.com break; 828*12683SJimmy.Vetayases@oracle.com prep = p; 829*12683SJimmy.Vetayases@oracle.com } 830*12683SJimmy.Vetayases@oracle.com if (prep != NULL) { 831*12683SJimmy.Vetayases@oracle.com if (prep->av_vector == NULL) { /* freed struct available */ 832*12683SJimmy.Vetayases@oracle.com INIT_AUTOVEC(prep, intr_id, f, arg1, arg2, 833*12683SJimmy.Vetayases@oracle.com ticksp, ipl, dip); 834*12683SJimmy.Vetayases@oracle.com prep->av_flags = mem->av_flags; 835*12683SJimmy.Vetayases@oracle.com kmem_free(mem, sizeof (struct autovec)); 836*12683SJimmy.Vetayases@oracle.com return; 837*12683SJimmy.Vetayases@oracle.com } 838*12683SJimmy.Vetayases@oracle.com 839*12683SJimmy.Vetayases@oracle.com mem->av_link = prep->av_link; 840*12683SJimmy.Vetayases@oracle.com prep->av_link = mem; 841*12683SJimmy.Vetayases@oracle.com } else { 842*12683SJimmy.Vetayases@oracle.com /* insert new intpt at beginning of chain */ 843*12683SJimmy.Vetayases@oracle.com mem->av_link = vecp->v_autovect; 844*12683SJimmy.Vetayases@oracle.com vecp->v_autovect = mem; 845*12683SJimmy.Vetayases@oracle.com } 846*12683SJimmy.Vetayases@oracle.com } 847*12683SJimmy.Vetayases@oracle.com 848*12683SJimmy.Vetayases@oracle.com /* 849*12683SJimmy.Vetayases@oracle.com * After having made a change to an autovector list, wait until we have 850*12683SJimmy.Vetayases@oracle.com * seen specified cpu not executing an interrupt at that level--so we 851*12683SJimmy.Vetayases@oracle.com * know our change has taken effect completely (no old state in registers, 852*12683SJimmy.Vetayases@oracle.com * etc). 853*12683SJimmy.Vetayases@oracle.com */ 854*12683SJimmy.Vetayases@oracle.com #define APIX_CPU_ENABLED(_cp) \ 855*12683SJimmy.Vetayases@oracle.com (quiesce_active == 0 && \ 856*12683SJimmy.Vetayases@oracle.com (((_cp)->cpu_flags & (CPU_QUIESCED|CPU_OFFLINE)) == 0)) 857*12683SJimmy.Vetayases@oracle.com 858*12683SJimmy.Vetayases@oracle.com static void 859*12683SJimmy.Vetayases@oracle.com apix_wait_till_seen(processorid_t cpuid, int ipl) 860*12683SJimmy.Vetayases@oracle.com { 861*12683SJimmy.Vetayases@oracle.com struct cpu *cp = cpu[cpuid]; 862*12683SJimmy.Vetayases@oracle.com 863*12683SJimmy.Vetayases@oracle.com if (cp == NULL || LOCAL_WITH_INTR_DISABLED(cpuid)) 864*12683SJimmy.Vetayases@oracle.com return; 865*12683SJimmy.Vetayases@oracle.com 866*12683SJimmy.Vetayases@oracle.com /* 867*12683SJimmy.Vetayases@oracle.com * Don't wait if the CPU is quiesced or offlined. This can happen 868*12683SJimmy.Vetayases@oracle.com * when a CPU is running pause thread but hardware triggered an 869*12683SJimmy.Vetayases@oracle.com * interrupt and the interrupt gets queued. 870*12683SJimmy.Vetayases@oracle.com */ 871*12683SJimmy.Vetayases@oracle.com for (;;) { 872*12683SJimmy.Vetayases@oracle.com if (!INTR_ACTIVE((volatile struct cpu *)cpu[cpuid], ipl) && 873*12683SJimmy.Vetayases@oracle.com (!APIX_CPU_ENABLED(cp) || 874*12683SJimmy.Vetayases@oracle.com !INTR_PENDING((volatile apix_impl_t *)apixs[cpuid], ipl))) 875*12683SJimmy.Vetayases@oracle.com return; 876*12683SJimmy.Vetayases@oracle.com } 877*12683SJimmy.Vetayases@oracle.com } 878*12683SJimmy.Vetayases@oracle.com 879*12683SJimmy.Vetayases@oracle.com static void 880*12683SJimmy.Vetayases@oracle.com apix_remove_av(apix_vector_t *vecp, struct autovec *target) 881*12683SJimmy.Vetayases@oracle.com { 882*12683SJimmy.Vetayases@oracle.com int hi_pri = 0; 883*12683SJimmy.Vetayases@oracle.com struct autovec *p; 884*12683SJimmy.Vetayases@oracle.com 885*12683SJimmy.Vetayases@oracle.com if (target == NULL) 886*12683SJimmy.Vetayases@oracle.com return; 887*12683SJimmy.Vetayases@oracle.com 888*12683SJimmy.Vetayases@oracle.com APIC_VERBOSE(INTR, (CE_CONT, "apix_remove_av: dip %p, vector 0x%x, " 889*12683SJimmy.Vetayases@oracle.com "cpu %d\n", (void *)target->av_dip, vecp->v_vector, vecp->v_cpuid)); 890*12683SJimmy.Vetayases@oracle.com 891*12683SJimmy.Vetayases@oracle.com for (p = vecp->v_autovect; p; p = p->av_link) { 892*12683SJimmy.Vetayases@oracle.com if (p == target || p->av_vector == NULL) 893*12683SJimmy.Vetayases@oracle.com continue; 894*12683SJimmy.Vetayases@oracle.com hi_pri = (p->av_prilevel > hi_pri) ? p->av_prilevel : hi_pri; 895*12683SJimmy.Vetayases@oracle.com } 896*12683SJimmy.Vetayases@oracle.com 897*12683SJimmy.Vetayases@oracle.com vecp->v_share--; 898*12683SJimmy.Vetayases@oracle.com vecp->v_pri = hi_pri; 899*12683SJimmy.Vetayases@oracle.com 900*12683SJimmy.Vetayases@oracle.com /* 901*12683SJimmy.Vetayases@oracle.com * This drops the handler from the chain, it can no longer be called. 902*12683SJimmy.Vetayases@oracle.com * However, there is no guarantee that the handler is not currently 903*12683SJimmy.Vetayases@oracle.com * still executing. 904*12683SJimmy.Vetayases@oracle.com */ 905*12683SJimmy.Vetayases@oracle.com target->av_vector = NULL; 906*12683SJimmy.Vetayases@oracle.com /* 907*12683SJimmy.Vetayases@oracle.com * There is a race where we could be just about to pick up the ticksp 908*12683SJimmy.Vetayases@oracle.com * pointer to increment it after returning from the service routine 909*12683SJimmy.Vetayases@oracle.com * in av_dispatch_autovect. Rather than NULL it out let's just point 910*12683SJimmy.Vetayases@oracle.com * it off to something safe so that any final tick update attempt 911*12683SJimmy.Vetayases@oracle.com * won't fault. 912*12683SJimmy.Vetayases@oracle.com */ 913*12683SJimmy.Vetayases@oracle.com target->av_ticksp = &dummy_tick; 914*12683SJimmy.Vetayases@oracle.com apix_wait_till_seen(vecp->v_cpuid, target->av_prilevel); 915*12683SJimmy.Vetayases@oracle.com } 916*12683SJimmy.Vetayases@oracle.com 917*12683SJimmy.Vetayases@oracle.com static struct autovec * 918*12683SJimmy.Vetayases@oracle.com apix_find_av(apix_vector_t *vecp, void *intr_id, avfunc f) 919*12683SJimmy.Vetayases@oracle.com { 920*12683SJimmy.Vetayases@oracle.com struct autovec *p; 921*12683SJimmy.Vetayases@oracle.com 922*12683SJimmy.Vetayases@oracle.com for (p = vecp->v_autovect; p; p = p->av_link) { 923*12683SJimmy.Vetayases@oracle.com if ((p->av_vector == f) && (p->av_intr_id == intr_id)) { 924*12683SJimmy.Vetayases@oracle.com /* found the handler */ 925*12683SJimmy.Vetayases@oracle.com return (p); 926*12683SJimmy.Vetayases@oracle.com } 927*12683SJimmy.Vetayases@oracle.com } 928*12683SJimmy.Vetayases@oracle.com 929*12683SJimmy.Vetayases@oracle.com return (NULL); 930*12683SJimmy.Vetayases@oracle.com } 931*12683SJimmy.Vetayases@oracle.com 932*12683SJimmy.Vetayases@oracle.com static apix_vector_t * 933*12683SJimmy.Vetayases@oracle.com apix_find_vector_by_avintr(void *intr_id, avfunc f) 934*12683SJimmy.Vetayases@oracle.com { 935*12683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 936*12683SJimmy.Vetayases@oracle.com processorid_t n; 937*12683SJimmy.Vetayases@oracle.com uchar_t v; 938*12683SJimmy.Vetayases@oracle.com 939*12683SJimmy.Vetayases@oracle.com for (n = 0; n < apic_nproc; n++) { 940*12683SJimmy.Vetayases@oracle.com if (!apix_is_cpu_enabled(n)) 941*12683SJimmy.Vetayases@oracle.com continue; 942*12683SJimmy.Vetayases@oracle.com 943*12683SJimmy.Vetayases@oracle.com for (v = APIX_AVINTR_MIN; v <= APIX_AVINTR_MIN; v++) { 944*12683SJimmy.Vetayases@oracle.com vecp = xv_vector(n, v); 945*12683SJimmy.Vetayases@oracle.com if (vecp == NULL || 946*12683SJimmy.Vetayases@oracle.com vecp->v_state <= APIX_STATE_OBSOLETED) 947*12683SJimmy.Vetayases@oracle.com continue; 948*12683SJimmy.Vetayases@oracle.com 949*12683SJimmy.Vetayases@oracle.com if (apix_find_av(vecp, intr_id, f) != NULL) 950*12683SJimmy.Vetayases@oracle.com return (vecp); 951*12683SJimmy.Vetayases@oracle.com } 952*12683SJimmy.Vetayases@oracle.com } 953*12683SJimmy.Vetayases@oracle.com 954*12683SJimmy.Vetayases@oracle.com return (NULL); 955*12683SJimmy.Vetayases@oracle.com } 956*12683SJimmy.Vetayases@oracle.com 957*12683SJimmy.Vetayases@oracle.com /* 958*12683SJimmy.Vetayases@oracle.com * Add interrupt service routine. 959*12683SJimmy.Vetayases@oracle.com * 960*12683SJimmy.Vetayases@oracle.com * For legacy interrupts (HPET timer, ACPI SCI), the vector is actually 961*12683SJimmy.Vetayases@oracle.com * IRQ no. A vector is then allocated. Otherwise, the vector is already 962*12683SJimmy.Vetayases@oracle.com * allocated. The input argument virt_vect is virtual vector of format 963*12683SJimmy.Vetayases@oracle.com * APIX_VIRTVEC_VECTOR(cpuid, vector). 964*12683SJimmy.Vetayases@oracle.com * 965*12683SJimmy.Vetayases@oracle.com * Return 1 on success, 0 on failure. 966*12683SJimmy.Vetayases@oracle.com */ 967*12683SJimmy.Vetayases@oracle.com int 968*12683SJimmy.Vetayases@oracle.com apix_add_avintr(void *intr_id, int ipl, avfunc xxintr, char *name, 969*12683SJimmy.Vetayases@oracle.com int virt_vect, caddr_t arg1, caddr_t arg2, uint64_t *ticksp, 970*12683SJimmy.Vetayases@oracle.com dev_info_t *dip) 971*12683SJimmy.Vetayases@oracle.com { 972*12683SJimmy.Vetayases@oracle.com int cpuid; 973*12683SJimmy.Vetayases@oracle.com uchar_t v = (uchar_t)APIX_VIRTVEC_VECTOR(virt_vect); 974*12683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 975*12683SJimmy.Vetayases@oracle.com 976*12683SJimmy.Vetayases@oracle.com if (xxintr == NULL) { 977*12683SJimmy.Vetayases@oracle.com cmn_err(CE_WARN, "Attempt to add null for %s " 978*12683SJimmy.Vetayases@oracle.com "on vector 0x%x,0x%x", name, 979*12683SJimmy.Vetayases@oracle.com APIX_VIRTVEC_CPU(virt_vect), 980*12683SJimmy.Vetayases@oracle.com APIX_VIRTVEC_VECTOR(virt_vect)); 981*12683SJimmy.Vetayases@oracle.com return (0); 982*12683SJimmy.Vetayases@oracle.com } 983*12683SJimmy.Vetayases@oracle.com 984*12683SJimmy.Vetayases@oracle.com if (v >= APIX_IPI_MIN) /* IPIs */ 985*12683SJimmy.Vetayases@oracle.com return (apix_add_ipi(ipl, xxintr, name, v, arg1, arg2)); 986*12683SJimmy.Vetayases@oracle.com 987*12683SJimmy.Vetayases@oracle.com if (!APIX_IS_VIRTVEC(virt_vect)) { /* got irq */ 988*12683SJimmy.Vetayases@oracle.com int irqno = virt_vect; 989*12683SJimmy.Vetayases@oracle.com int inum = GET_INTR_INUM(intr_id); 990*12683SJimmy.Vetayases@oracle.com 991*12683SJimmy.Vetayases@oracle.com /* 992*12683SJimmy.Vetayases@oracle.com * Senarios include: 993*12683SJimmy.Vetayases@oracle.com * a. add_avintr() is called before irqp initialized (legacy) 994*12683SJimmy.Vetayases@oracle.com * b. irqp is initialized, vector is not allocated (fixed) 995*12683SJimmy.Vetayases@oracle.com * c. irqp is initialized, vector is allocated (fixed & shared) 996*12683SJimmy.Vetayases@oracle.com */ 997*12683SJimmy.Vetayases@oracle.com if ((vecp = apix_alloc_intx(dip, inum, irqno)) == NULL) 998*12683SJimmy.Vetayases@oracle.com return (0); 999*12683SJimmy.Vetayases@oracle.com 1000*12683SJimmy.Vetayases@oracle.com cpuid = vecp->v_cpuid; 1001*12683SJimmy.Vetayases@oracle.com v = vecp->v_vector; 1002*12683SJimmy.Vetayases@oracle.com virt_vect = APIX_VIRTVECTOR(cpuid, v); 1003*12683SJimmy.Vetayases@oracle.com } else { /* got virtual vector */ 1004*12683SJimmy.Vetayases@oracle.com cpuid = APIX_VIRTVEC_CPU(virt_vect); 1005*12683SJimmy.Vetayases@oracle.com vecp = xv_vector(cpuid, v); 1006*12683SJimmy.Vetayases@oracle.com ASSERT(vecp != NULL); 1007*12683SJimmy.Vetayases@oracle.com } 1008*12683SJimmy.Vetayases@oracle.com 1009*12683SJimmy.Vetayases@oracle.com lock_set(&apix_lock); 1010*12683SJimmy.Vetayases@oracle.com if (vecp->v_state <= APIX_STATE_OBSOLETED) { 1011*12683SJimmy.Vetayases@oracle.com vecp = NULL; 1012*12683SJimmy.Vetayases@oracle.com 1013*12683SJimmy.Vetayases@oracle.com /* 1014*12683SJimmy.Vetayases@oracle.com * Basically the allocated but not enabled interrupts 1015*12683SJimmy.Vetayases@oracle.com * will not get re-targeted. But MSIs in allocated state 1016*12683SJimmy.Vetayases@oracle.com * could be re-targeted due to group re-targeting. 1017*12683SJimmy.Vetayases@oracle.com */ 1018*12683SJimmy.Vetayases@oracle.com if (intr_id != NULL && dip != NULL) { 1019*12683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *hdlp = intr_id; 1020*12683SJimmy.Vetayases@oracle.com vecp = apix_get_dev_map(dip, hdlp->ih_inum, 1021*12683SJimmy.Vetayases@oracle.com hdlp->ih_type); 1022*12683SJimmy.Vetayases@oracle.com ASSERT(vecp->v_state == APIX_STATE_ALLOCED); 1023*12683SJimmy.Vetayases@oracle.com } 1024*12683SJimmy.Vetayases@oracle.com if (vecp == NULL) { 1025*12683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 1026*12683SJimmy.Vetayases@oracle.com cmn_err(CE_WARN, "Invalid interrupt 0x%x,0x%x " 1027*12683SJimmy.Vetayases@oracle.com " for %p to add", cpuid, v, intr_id); 1028*12683SJimmy.Vetayases@oracle.com return (0); 1029*12683SJimmy.Vetayases@oracle.com } 1030*12683SJimmy.Vetayases@oracle.com cpuid = vecp->v_cpuid; 1031*12683SJimmy.Vetayases@oracle.com virt_vect = APIX_VIRTVECTOR(cpuid, vecp->v_vector); 1032*12683SJimmy.Vetayases@oracle.com } 1033*12683SJimmy.Vetayases@oracle.com 1034*12683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(cpuid); 1035*12683SJimmy.Vetayases@oracle.com apix_insert_av(vecp, intr_id, xxintr, arg1, arg2, ticksp, ipl, dip); 1036*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 1037*12683SJimmy.Vetayases@oracle.com 1038*12683SJimmy.Vetayases@oracle.com (void) apix_addspl(virt_vect, ipl, 0, 0); 1039*12683SJimmy.Vetayases@oracle.com 1040*12683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 1041*12683SJimmy.Vetayases@oracle.com 1042*12683SJimmy.Vetayases@oracle.com return (1); 1043*12683SJimmy.Vetayases@oracle.com } 1044*12683SJimmy.Vetayases@oracle.com 1045*12683SJimmy.Vetayases@oracle.com /* 1046*12683SJimmy.Vetayases@oracle.com * Remove avintr 1047*12683SJimmy.Vetayases@oracle.com * 1048*12683SJimmy.Vetayases@oracle.com * For fixed, if it's the last one of shared interrupts, free the vector. 1049*12683SJimmy.Vetayases@oracle.com * For msi/x, only disable the interrupt but not free the vector, which 1050*12683SJimmy.Vetayases@oracle.com * is freed by PSM_XXX_FREE_XXX. 1051*12683SJimmy.Vetayases@oracle.com */ 1052*12683SJimmy.Vetayases@oracle.com void 1053*12683SJimmy.Vetayases@oracle.com apix_rem_avintr(void *intr_id, int ipl, avfunc xxintr, int virt_vect) 1054*12683SJimmy.Vetayases@oracle.com { 1055*12683SJimmy.Vetayases@oracle.com avfunc f; 1056*12683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 1057*12683SJimmy.Vetayases@oracle.com struct autovec *avp; 1058*12683SJimmy.Vetayases@oracle.com processorid_t cpuid; 1059*12683SJimmy.Vetayases@oracle.com 1060*12683SJimmy.Vetayases@oracle.com if ((f = xxintr) == NULL) 1061*12683SJimmy.Vetayases@oracle.com return; 1062*12683SJimmy.Vetayases@oracle.com 1063*12683SJimmy.Vetayases@oracle.com lock_set(&apix_lock); 1064*12683SJimmy.Vetayases@oracle.com 1065*12683SJimmy.Vetayases@oracle.com if (!APIX_IS_VIRTVEC(virt_vect)) { /* got irq */ 1066*12683SJimmy.Vetayases@oracle.com vecp = apix_intx_get_vector(virt_vect); 1067*12683SJimmy.Vetayases@oracle.com virt_vect = APIX_VIRTVECTOR(vecp->v_cpuid, vecp->v_vector); 1068*12683SJimmy.Vetayases@oracle.com } else /* got virtual vector */ 1069*12683SJimmy.Vetayases@oracle.com vecp = xv_vector(APIX_VIRTVEC_CPU(virt_vect), 1070*12683SJimmy.Vetayases@oracle.com APIX_VIRTVEC_VECTOR(virt_vect)); 1071*12683SJimmy.Vetayases@oracle.com 1072*12683SJimmy.Vetayases@oracle.com if (vecp == NULL) { 1073*12683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 1074*12683SJimmy.Vetayases@oracle.com cmn_err(CE_CONT, "Invalid interrupt 0x%x,0x%x to remove", 1075*12683SJimmy.Vetayases@oracle.com APIX_VIRTVEC_CPU(virt_vect), 1076*12683SJimmy.Vetayases@oracle.com APIX_VIRTVEC_VECTOR(virt_vect)); 1077*12683SJimmy.Vetayases@oracle.com return; 1078*12683SJimmy.Vetayases@oracle.com } 1079*12683SJimmy.Vetayases@oracle.com 1080*12683SJimmy.Vetayases@oracle.com if (vecp->v_state <= APIX_STATE_OBSOLETED || 1081*12683SJimmy.Vetayases@oracle.com ((avp = apix_find_av(vecp, intr_id, f)) == NULL)) { 1082*12683SJimmy.Vetayases@oracle.com /* 1083*12683SJimmy.Vetayases@oracle.com * It's possible that the interrupt is rebound to a 1084*12683SJimmy.Vetayases@oracle.com * different cpu before rem_avintr() is called. Search 1085*12683SJimmy.Vetayases@oracle.com * through all vectors once it happens. 1086*12683SJimmy.Vetayases@oracle.com */ 1087*12683SJimmy.Vetayases@oracle.com if ((vecp = apix_find_vector_by_avintr(intr_id, f)) 1088*12683SJimmy.Vetayases@oracle.com == NULL) { 1089*12683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 1090*12683SJimmy.Vetayases@oracle.com cmn_err(CE_CONT, "Unknown interrupt 0x%x,0x%x " 1091*12683SJimmy.Vetayases@oracle.com "for %p to remove", APIX_VIRTVEC_CPU(virt_vect), 1092*12683SJimmy.Vetayases@oracle.com APIX_VIRTVEC_VECTOR(virt_vect), intr_id); 1093*12683SJimmy.Vetayases@oracle.com return; 1094*12683SJimmy.Vetayases@oracle.com } 1095*12683SJimmy.Vetayases@oracle.com virt_vect = APIX_VIRTVECTOR(vecp->v_cpuid, vecp->v_vector); 1096*12683SJimmy.Vetayases@oracle.com avp = apix_find_av(vecp, intr_id, f); 1097*12683SJimmy.Vetayases@oracle.com } 1098*12683SJimmy.Vetayases@oracle.com cpuid = vecp->v_cpuid; 1099*12683SJimmy.Vetayases@oracle.com 1100*12683SJimmy.Vetayases@oracle.com /* disable interrupt */ 1101*12683SJimmy.Vetayases@oracle.com (void) apix_delspl(virt_vect, ipl, 0, 0); 1102*12683SJimmy.Vetayases@oracle.com 1103*12683SJimmy.Vetayases@oracle.com /* remove ISR entry */ 1104*12683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(cpuid); 1105*12683SJimmy.Vetayases@oracle.com apix_remove_av(vecp, avp); 1106*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 1107*12683SJimmy.Vetayases@oracle.com 1108*12683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 1109*12683SJimmy.Vetayases@oracle.com } 1110*12683SJimmy.Vetayases@oracle.com 1111*12683SJimmy.Vetayases@oracle.com /* 1112*12683SJimmy.Vetayases@oracle.com * Device to vector mapping table 1113*12683SJimmy.Vetayases@oracle.com */ 1114*12683SJimmy.Vetayases@oracle.com 1115*12683SJimmy.Vetayases@oracle.com static void 1116*12683SJimmy.Vetayases@oracle.com apix_clear_dev_map(dev_info_t *dip, int inum, int type) 1117*12683SJimmy.Vetayases@oracle.com { 1118*12683SJimmy.Vetayases@oracle.com char *name; 1119*12683SJimmy.Vetayases@oracle.com major_t major; 1120*12683SJimmy.Vetayases@oracle.com apix_dev_vector_t *dvp, *prev = NULL; 1121*12683SJimmy.Vetayases@oracle.com int found = 0; 1122*12683SJimmy.Vetayases@oracle.com 1123*12683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 1124*12683SJimmy.Vetayases@oracle.com major = ddi_name_to_major(name); 1125*12683SJimmy.Vetayases@oracle.com 1126*12683SJimmy.Vetayases@oracle.com mutex_enter(&apix_mutex); 1127*12683SJimmy.Vetayases@oracle.com 1128*12683SJimmy.Vetayases@oracle.com for (dvp = apix_dev_vector[major]; dvp != NULL; 1129*12683SJimmy.Vetayases@oracle.com prev = dvp, dvp = dvp->dv_next) { 1130*12683SJimmy.Vetayases@oracle.com if (dvp->dv_dip == dip && dvp->dv_inum == inum && 1131*12683SJimmy.Vetayases@oracle.com dvp->dv_type == type) { 1132*12683SJimmy.Vetayases@oracle.com found++; 1133*12683SJimmy.Vetayases@oracle.com break; 1134*12683SJimmy.Vetayases@oracle.com } 1135*12683SJimmy.Vetayases@oracle.com } 1136*12683SJimmy.Vetayases@oracle.com 1137*12683SJimmy.Vetayases@oracle.com if (!found) { 1138*12683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 1139*12683SJimmy.Vetayases@oracle.com return; 1140*12683SJimmy.Vetayases@oracle.com } 1141*12683SJimmy.Vetayases@oracle.com 1142*12683SJimmy.Vetayases@oracle.com if (prev != NULL) 1143*12683SJimmy.Vetayases@oracle.com prev->dv_next = dvp->dv_next; 1144*12683SJimmy.Vetayases@oracle.com 1145*12683SJimmy.Vetayases@oracle.com if (apix_dev_vector[major] == dvp) 1146*12683SJimmy.Vetayases@oracle.com apix_dev_vector[major] = dvp->dv_next; 1147*12683SJimmy.Vetayases@oracle.com 1148*12683SJimmy.Vetayases@oracle.com dvp->dv_vector->v_devp = NULL; 1149*12683SJimmy.Vetayases@oracle.com 1150*12683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 1151*12683SJimmy.Vetayases@oracle.com 1152*12683SJimmy.Vetayases@oracle.com kmem_free(dvp, sizeof (apix_dev_vector_t)); 1153*12683SJimmy.Vetayases@oracle.com } 1154*12683SJimmy.Vetayases@oracle.com 1155*12683SJimmy.Vetayases@oracle.com void 1156*12683SJimmy.Vetayases@oracle.com apix_set_dev_map(apix_vector_t *vecp, dev_info_t *dip, int inum) 1157*12683SJimmy.Vetayases@oracle.com { 1158*12683SJimmy.Vetayases@oracle.com apix_dev_vector_t *dvp; 1159*12683SJimmy.Vetayases@oracle.com char *name; 1160*12683SJimmy.Vetayases@oracle.com major_t major; 1161*12683SJimmy.Vetayases@oracle.com uint32_t found = 0; 1162*12683SJimmy.Vetayases@oracle.com 1163*12683SJimmy.Vetayases@oracle.com ASSERT(dip != NULL); 1164*12683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 1165*12683SJimmy.Vetayases@oracle.com major = ddi_name_to_major(name); 1166*12683SJimmy.Vetayases@oracle.com 1167*12683SJimmy.Vetayases@oracle.com mutex_enter(&apix_mutex); 1168*12683SJimmy.Vetayases@oracle.com 1169*12683SJimmy.Vetayases@oracle.com for (dvp = apix_dev_vector[major]; dvp != NULL; 1170*12683SJimmy.Vetayases@oracle.com dvp = dvp->dv_next) { 1171*12683SJimmy.Vetayases@oracle.com if (dvp->dv_dip == dip && dvp->dv_inum == inum && 1172*12683SJimmy.Vetayases@oracle.com dvp->dv_type == vecp->v_type) { 1173*12683SJimmy.Vetayases@oracle.com found++; 1174*12683SJimmy.Vetayases@oracle.com break; 1175*12683SJimmy.Vetayases@oracle.com } 1176*12683SJimmy.Vetayases@oracle.com } 1177*12683SJimmy.Vetayases@oracle.com 1178*12683SJimmy.Vetayases@oracle.com if (found == 0) { /* not found */ 1179*12683SJimmy.Vetayases@oracle.com dvp = kmem_zalloc(sizeof (apix_dev_vector_t), KM_SLEEP); 1180*12683SJimmy.Vetayases@oracle.com dvp->dv_dip = dip; 1181*12683SJimmy.Vetayases@oracle.com dvp->dv_inum = inum; 1182*12683SJimmy.Vetayases@oracle.com dvp->dv_type = vecp->v_type; 1183*12683SJimmy.Vetayases@oracle.com 1184*12683SJimmy.Vetayases@oracle.com dvp->dv_next = apix_dev_vector[major]; 1185*12683SJimmy.Vetayases@oracle.com apix_dev_vector[major] = dvp; 1186*12683SJimmy.Vetayases@oracle.com } 1187*12683SJimmy.Vetayases@oracle.com dvp->dv_vector = vecp; 1188*12683SJimmy.Vetayases@oracle.com vecp->v_devp = dvp; 1189*12683SJimmy.Vetayases@oracle.com 1190*12683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 1191*12683SJimmy.Vetayases@oracle.com 1192*12683SJimmy.Vetayases@oracle.com DDI_INTR_IMPLDBG((CE_CONT, "apix_set_dev_map: dip=0x%p " 1193*12683SJimmy.Vetayases@oracle.com "inum=0x%x vector=0x%x/0x%x\n", 1194*12683SJimmy.Vetayases@oracle.com (void *)dip, inum, vecp->v_cpuid, vecp->v_vector)); 1195*12683SJimmy.Vetayases@oracle.com } 1196*12683SJimmy.Vetayases@oracle.com 1197*12683SJimmy.Vetayases@oracle.com apix_vector_t * 1198*12683SJimmy.Vetayases@oracle.com apix_get_dev_map(dev_info_t *dip, int inum, int type) 1199*12683SJimmy.Vetayases@oracle.com { 1200*12683SJimmy.Vetayases@oracle.com char *name; 1201*12683SJimmy.Vetayases@oracle.com major_t major; 1202*12683SJimmy.Vetayases@oracle.com apix_dev_vector_t *dvp; 1203*12683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 1204*12683SJimmy.Vetayases@oracle.com 1205*12683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 1206*12683SJimmy.Vetayases@oracle.com if ((major = ddi_name_to_major(name)) == DDI_MAJOR_T_NONE) 1207*12683SJimmy.Vetayases@oracle.com return (NULL); 1208*12683SJimmy.Vetayases@oracle.com 1209*12683SJimmy.Vetayases@oracle.com mutex_enter(&apix_mutex); 1210*12683SJimmy.Vetayases@oracle.com for (dvp = apix_dev_vector[major]; dvp != NULL; 1211*12683SJimmy.Vetayases@oracle.com dvp = dvp->dv_next) { 1212*12683SJimmy.Vetayases@oracle.com if (dvp->dv_dip == dip && dvp->dv_inum == inum && 1213*12683SJimmy.Vetayases@oracle.com dvp->dv_type == type) { 1214*12683SJimmy.Vetayases@oracle.com vecp = dvp->dv_vector; 1215*12683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 1216*12683SJimmy.Vetayases@oracle.com return (vecp); 1217*12683SJimmy.Vetayases@oracle.com } 1218*12683SJimmy.Vetayases@oracle.com } 1219*12683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 1220*12683SJimmy.Vetayases@oracle.com 1221*12683SJimmy.Vetayases@oracle.com return (NULL); 1222*12683SJimmy.Vetayases@oracle.com } 1223*12683SJimmy.Vetayases@oracle.com 1224*12683SJimmy.Vetayases@oracle.com /* 1225*12683SJimmy.Vetayases@oracle.com * Get minimum inum for specified device, used for MSI 1226*12683SJimmy.Vetayases@oracle.com */ 1227*12683SJimmy.Vetayases@oracle.com int 1228*12683SJimmy.Vetayases@oracle.com apix_get_min_dev_inum(dev_info_t *dip, int type) 1229*12683SJimmy.Vetayases@oracle.com { 1230*12683SJimmy.Vetayases@oracle.com char *name; 1231*12683SJimmy.Vetayases@oracle.com major_t major; 1232*12683SJimmy.Vetayases@oracle.com apix_dev_vector_t *dvp; 1233*12683SJimmy.Vetayases@oracle.com int inum = -1; 1234*12683SJimmy.Vetayases@oracle.com 1235*12683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 1236*12683SJimmy.Vetayases@oracle.com major = ddi_name_to_major(name); 1237*12683SJimmy.Vetayases@oracle.com 1238*12683SJimmy.Vetayases@oracle.com mutex_enter(&apix_mutex); 1239*12683SJimmy.Vetayases@oracle.com for (dvp = apix_dev_vector[major]; dvp != NULL; 1240*12683SJimmy.Vetayases@oracle.com dvp = dvp->dv_next) { 1241*12683SJimmy.Vetayases@oracle.com if (dvp->dv_dip == dip && dvp->dv_type == type) { 1242*12683SJimmy.Vetayases@oracle.com if (inum == -1) 1243*12683SJimmy.Vetayases@oracle.com inum = dvp->dv_inum; 1244*12683SJimmy.Vetayases@oracle.com else 1245*12683SJimmy.Vetayases@oracle.com inum = (dvp->dv_inum < inum) ? 1246*12683SJimmy.Vetayases@oracle.com dvp->dv_inum : inum; 1247*12683SJimmy.Vetayases@oracle.com } 1248*12683SJimmy.Vetayases@oracle.com } 1249*12683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 1250*12683SJimmy.Vetayases@oracle.com 1251*12683SJimmy.Vetayases@oracle.com return (inum); 1252*12683SJimmy.Vetayases@oracle.com } 1253*12683SJimmy.Vetayases@oracle.com 1254*12683SJimmy.Vetayases@oracle.com int 1255*12683SJimmy.Vetayases@oracle.com apix_get_max_dev_inum(dev_info_t *dip, int type) 1256*12683SJimmy.Vetayases@oracle.com { 1257*12683SJimmy.Vetayases@oracle.com char *name; 1258*12683SJimmy.Vetayases@oracle.com major_t major; 1259*12683SJimmy.Vetayases@oracle.com apix_dev_vector_t *dvp; 1260*12683SJimmy.Vetayases@oracle.com int inum = -1; 1261*12683SJimmy.Vetayases@oracle.com 1262*12683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 1263*12683SJimmy.Vetayases@oracle.com major = ddi_name_to_major(name); 1264*12683SJimmy.Vetayases@oracle.com 1265*12683SJimmy.Vetayases@oracle.com mutex_enter(&apix_mutex); 1266*12683SJimmy.Vetayases@oracle.com for (dvp = apix_dev_vector[major]; dvp != NULL; 1267*12683SJimmy.Vetayases@oracle.com dvp = dvp->dv_next) { 1268*12683SJimmy.Vetayases@oracle.com if (dvp->dv_dip == dip && dvp->dv_type == type) { 1269*12683SJimmy.Vetayases@oracle.com if (inum == -1) 1270*12683SJimmy.Vetayases@oracle.com inum = dvp->dv_inum; 1271*12683SJimmy.Vetayases@oracle.com else 1272*12683SJimmy.Vetayases@oracle.com inum = (dvp->dv_inum > inum) ? 1273*12683SJimmy.Vetayases@oracle.com dvp->dv_inum : inum; 1274*12683SJimmy.Vetayases@oracle.com } 1275*12683SJimmy.Vetayases@oracle.com } 1276*12683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 1277*12683SJimmy.Vetayases@oracle.com 1278*12683SJimmy.Vetayases@oracle.com return (inum); 1279*12683SJimmy.Vetayases@oracle.com } 1280*12683SJimmy.Vetayases@oracle.com 1281*12683SJimmy.Vetayases@oracle.com /* 1282*12683SJimmy.Vetayases@oracle.com * Major to cpu binding, for INTR_ROUND_ROBIN_WITH_AFFINITY cpu 1283*12683SJimmy.Vetayases@oracle.com * binding policy 1284*12683SJimmy.Vetayases@oracle.com */ 1285*12683SJimmy.Vetayases@oracle.com 1286*12683SJimmy.Vetayases@oracle.com static uint32_t 1287*12683SJimmy.Vetayases@oracle.com apix_get_dev_binding(dev_info_t *dip) 1288*12683SJimmy.Vetayases@oracle.com { 1289*12683SJimmy.Vetayases@oracle.com major_t major; 1290*12683SJimmy.Vetayases@oracle.com char *name; 1291*12683SJimmy.Vetayases@oracle.com uint32_t cpu = IRQ_UNINIT; 1292*12683SJimmy.Vetayases@oracle.com 1293*12683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 1294*12683SJimmy.Vetayases@oracle.com major = ddi_name_to_major(name); 1295*12683SJimmy.Vetayases@oracle.com if (major < devcnt) { 1296*12683SJimmy.Vetayases@oracle.com mutex_enter(&apix_mutex); 1297*12683SJimmy.Vetayases@oracle.com cpu = apix_major_to_cpu[major]; 1298*12683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 1299*12683SJimmy.Vetayases@oracle.com } 1300*12683SJimmy.Vetayases@oracle.com 1301*12683SJimmy.Vetayases@oracle.com return (cpu); 1302*12683SJimmy.Vetayases@oracle.com } 1303*12683SJimmy.Vetayases@oracle.com 1304*12683SJimmy.Vetayases@oracle.com static void 1305*12683SJimmy.Vetayases@oracle.com apix_set_dev_binding(dev_info_t *dip, uint32_t cpu) 1306*12683SJimmy.Vetayases@oracle.com { 1307*12683SJimmy.Vetayases@oracle.com major_t major; 1308*12683SJimmy.Vetayases@oracle.com char *name; 1309*12683SJimmy.Vetayases@oracle.com 1310*12683SJimmy.Vetayases@oracle.com /* setup major to cpu mapping */ 1311*12683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 1312*12683SJimmy.Vetayases@oracle.com major = ddi_name_to_major(name); 1313*12683SJimmy.Vetayases@oracle.com if (apix_major_to_cpu[major] == IRQ_UNINIT) { 1314*12683SJimmy.Vetayases@oracle.com mutex_enter(&apix_mutex); 1315*12683SJimmy.Vetayases@oracle.com apix_major_to_cpu[major] = cpu; 1316*12683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 1317*12683SJimmy.Vetayases@oracle.com } 1318*12683SJimmy.Vetayases@oracle.com } 1319*12683SJimmy.Vetayases@oracle.com 1320*12683SJimmy.Vetayases@oracle.com /* 1321*12683SJimmy.Vetayases@oracle.com * return the cpu to which this intr should be bound. 1322*12683SJimmy.Vetayases@oracle.com * Check properties or any other mechanism to see if user wants it 1323*12683SJimmy.Vetayases@oracle.com * bound to a specific CPU. If so, return the cpu id with high bit set. 1324*12683SJimmy.Vetayases@oracle.com * If not, use the policy to choose a cpu and return the id. 1325*12683SJimmy.Vetayases@oracle.com */ 1326*12683SJimmy.Vetayases@oracle.com uint32_t 1327*12683SJimmy.Vetayases@oracle.com apix_bind_cpu(dev_info_t *dip) 1328*12683SJimmy.Vetayases@oracle.com { 1329*12683SJimmy.Vetayases@oracle.com int instance, instno, prop_len, bind_cpu, count; 1330*12683SJimmy.Vetayases@oracle.com uint_t i, rc; 1331*12683SJimmy.Vetayases@oracle.com major_t major; 1332*12683SJimmy.Vetayases@oracle.com char *name, *drv_name, *prop_val, *cptr; 1333*12683SJimmy.Vetayases@oracle.com char prop_name[32]; 1334*12683SJimmy.Vetayases@oracle.com 1335*12683SJimmy.Vetayases@oracle.com lock_set(&apix_lock); 1336*12683SJimmy.Vetayases@oracle.com 1337*12683SJimmy.Vetayases@oracle.com if (apic_intr_policy == INTR_LOWEST_PRIORITY) { 1338*12683SJimmy.Vetayases@oracle.com cmn_err(CE_WARN, "apix: unsupported interrupt binding policy " 1339*12683SJimmy.Vetayases@oracle.com "LOWEST PRIORITY, use ROUND ROBIN instead"); 1340*12683SJimmy.Vetayases@oracle.com apic_intr_policy = INTR_ROUND_ROBIN; 1341*12683SJimmy.Vetayases@oracle.com } 1342*12683SJimmy.Vetayases@oracle.com 1343*12683SJimmy.Vetayases@oracle.com if (apic_nproc == 1) { 1344*12683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 1345*12683SJimmy.Vetayases@oracle.com return (0); 1346*12683SJimmy.Vetayases@oracle.com } 1347*12683SJimmy.Vetayases@oracle.com 1348*12683SJimmy.Vetayases@oracle.com drv_name = NULL; 1349*12683SJimmy.Vetayases@oracle.com rc = DDI_PROP_NOT_FOUND; 1350*12683SJimmy.Vetayases@oracle.com major = (major_t)-1; 1351*12683SJimmy.Vetayases@oracle.com if (dip != NULL) { 1352*12683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 1353*12683SJimmy.Vetayases@oracle.com major = ddi_name_to_major(name); 1354*12683SJimmy.Vetayases@oracle.com drv_name = ddi_major_to_name(major); 1355*12683SJimmy.Vetayases@oracle.com instance = ddi_get_instance(dip); 1356*12683SJimmy.Vetayases@oracle.com if (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) { 1357*12683SJimmy.Vetayases@oracle.com bind_cpu = apix_get_dev_binding(dip); 1358*12683SJimmy.Vetayases@oracle.com if (bind_cpu != IRQ_UNINIT) { 1359*12683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 1360*12683SJimmy.Vetayases@oracle.com return (bind_cpu); 1361*12683SJimmy.Vetayases@oracle.com } 1362*12683SJimmy.Vetayases@oracle.com } 1363*12683SJimmy.Vetayases@oracle.com /* 1364*12683SJimmy.Vetayases@oracle.com * search for "drvname"_intpt_bind_cpus property first, the 1365*12683SJimmy.Vetayases@oracle.com * syntax of the property should be "a[,b,c,...]" where 1366*12683SJimmy.Vetayases@oracle.com * instance 0 binds to cpu a, instance 1 binds to cpu b, 1367*12683SJimmy.Vetayases@oracle.com * instance 3 binds to cpu c... 1368*12683SJimmy.Vetayases@oracle.com * ddi_getlongprop() will search /option first, then / 1369*12683SJimmy.Vetayases@oracle.com * if "drvname"_intpt_bind_cpus doesn't exist, then find 1370*12683SJimmy.Vetayases@oracle.com * intpt_bind_cpus property. The syntax is the same, and 1371*12683SJimmy.Vetayases@oracle.com * it applies to all the devices if its "drvname" specific 1372*12683SJimmy.Vetayases@oracle.com * property doesn't exist 1373*12683SJimmy.Vetayases@oracle.com */ 1374*12683SJimmy.Vetayases@oracle.com (void) strcpy(prop_name, drv_name); 1375*12683SJimmy.Vetayases@oracle.com (void) strcat(prop_name, "_intpt_bind_cpus"); 1376*12683SJimmy.Vetayases@oracle.com rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, prop_name, 1377*12683SJimmy.Vetayases@oracle.com (caddr_t)&prop_val, &prop_len); 1378*12683SJimmy.Vetayases@oracle.com if (rc != DDI_PROP_SUCCESS) { 1379*12683SJimmy.Vetayases@oracle.com rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, 1380*12683SJimmy.Vetayases@oracle.com "intpt_bind_cpus", (caddr_t)&prop_val, &prop_len); 1381*12683SJimmy.Vetayases@oracle.com } 1382*12683SJimmy.Vetayases@oracle.com } 1383*12683SJimmy.Vetayases@oracle.com if (rc == DDI_PROP_SUCCESS) { 1384*12683SJimmy.Vetayases@oracle.com for (i = count = 0; i < (prop_len - 1); i++) 1385*12683SJimmy.Vetayases@oracle.com if (prop_val[i] == ',') 1386*12683SJimmy.Vetayases@oracle.com count++; 1387*12683SJimmy.Vetayases@oracle.com if (prop_val[i-1] != ',') 1388*12683SJimmy.Vetayases@oracle.com count++; 1389*12683SJimmy.Vetayases@oracle.com /* 1390*12683SJimmy.Vetayases@oracle.com * if somehow the binding instances defined in the 1391*12683SJimmy.Vetayases@oracle.com * property are not enough for this instno., then 1392*12683SJimmy.Vetayases@oracle.com * reuse the pattern for the next instance until 1393*12683SJimmy.Vetayases@oracle.com * it reaches the requested instno 1394*12683SJimmy.Vetayases@oracle.com */ 1395*12683SJimmy.Vetayases@oracle.com instno = instance % count; 1396*12683SJimmy.Vetayases@oracle.com i = 0; 1397*12683SJimmy.Vetayases@oracle.com cptr = prop_val; 1398*12683SJimmy.Vetayases@oracle.com while (i < instno) 1399*12683SJimmy.Vetayases@oracle.com if (*cptr++ == ',') 1400*12683SJimmy.Vetayases@oracle.com i++; 1401*12683SJimmy.Vetayases@oracle.com bind_cpu = stoi(&cptr); 1402*12683SJimmy.Vetayases@oracle.com kmem_free(prop_val, prop_len); 1403*12683SJimmy.Vetayases@oracle.com /* if specific cpu is bogus, then default to cpu 0 */ 1404*12683SJimmy.Vetayases@oracle.com if (bind_cpu >= apic_nproc) { 1405*12683SJimmy.Vetayases@oracle.com cmn_err(CE_WARN, "apix: %s=%s: CPU %d not present", 1406*12683SJimmy.Vetayases@oracle.com prop_name, prop_val, bind_cpu); 1407*12683SJimmy.Vetayases@oracle.com bind_cpu = 0; 1408*12683SJimmy.Vetayases@oracle.com } else { 1409*12683SJimmy.Vetayases@oracle.com /* indicate that we are bound at user request */ 1410*12683SJimmy.Vetayases@oracle.com bind_cpu |= IRQ_USER_BOUND; 1411*12683SJimmy.Vetayases@oracle.com } 1412*12683SJimmy.Vetayases@oracle.com /* 1413*12683SJimmy.Vetayases@oracle.com * no need to check apic_cpus[].aci_status, if specific cpu is 1414*12683SJimmy.Vetayases@oracle.com * not up, then post_cpu_start will handle it. 1415*12683SJimmy.Vetayases@oracle.com */ 1416*12683SJimmy.Vetayases@oracle.com } else { 1417*12683SJimmy.Vetayases@oracle.com bind_cpu = apic_get_next_bind_cpu(); 1418*12683SJimmy.Vetayases@oracle.com } 1419*12683SJimmy.Vetayases@oracle.com 1420*12683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 1421*12683SJimmy.Vetayases@oracle.com 1422*12683SJimmy.Vetayases@oracle.com return ((uint32_t)bind_cpu); 1423*12683SJimmy.Vetayases@oracle.com } 1424*12683SJimmy.Vetayases@oracle.com 1425*12683SJimmy.Vetayases@oracle.com static boolean_t 1426*12683SJimmy.Vetayases@oracle.com apix_is_cpu_enabled(processorid_t cpuid) 1427*12683SJimmy.Vetayases@oracle.com { 1428*12683SJimmy.Vetayases@oracle.com apic_cpus_info_t *cpu_infop; 1429*12683SJimmy.Vetayases@oracle.com 1430*12683SJimmy.Vetayases@oracle.com cpu_infop = &apic_cpus[cpuid]; 1431*12683SJimmy.Vetayases@oracle.com 1432*12683SJimmy.Vetayases@oracle.com if ((cpu_infop->aci_status & APIC_CPU_INTR_ENABLE) == 0) 1433*12683SJimmy.Vetayases@oracle.com return (B_FALSE); 1434*12683SJimmy.Vetayases@oracle.com 1435*12683SJimmy.Vetayases@oracle.com return (B_TRUE); 1436*12683SJimmy.Vetayases@oracle.com } 1437*12683SJimmy.Vetayases@oracle.com 1438*12683SJimmy.Vetayases@oracle.com /* 1439*12683SJimmy.Vetayases@oracle.com * Must be called with apix_lock held. This function can be 1440*12683SJimmy.Vetayases@oracle.com * called from above lock level by apix_intr_redistribute(). 1441*12683SJimmy.Vetayases@oracle.com * 1442*12683SJimmy.Vetayases@oracle.com * Arguments: 1443*12683SJimmy.Vetayases@oracle.com * vecp : Vector to be rebound 1444*12683SJimmy.Vetayases@oracle.com * tocpu : Target cpu. IRQ_UNINIT means target is vecp->v_cpuid. 1445*12683SJimmy.Vetayases@oracle.com * count : Number of continuous vectors 1446*12683SJimmy.Vetayases@oracle.com * 1447*12683SJimmy.Vetayases@oracle.com * Return new vector being bound to 1448*12683SJimmy.Vetayases@oracle.com */ 1449*12683SJimmy.Vetayases@oracle.com apix_vector_t * 1450*12683SJimmy.Vetayases@oracle.com apix_rebind(apix_vector_t *vecp, processorid_t newcpu, int count) 1451*12683SJimmy.Vetayases@oracle.com { 1452*12683SJimmy.Vetayases@oracle.com apix_vector_t *newp, *oldp; 1453*12683SJimmy.Vetayases@oracle.com processorid_t oldcpu = vecp->v_cpuid; 1454*12683SJimmy.Vetayases@oracle.com uchar_t newvec, oldvec = vecp->v_vector; 1455*12683SJimmy.Vetayases@oracle.com int i; 1456*12683SJimmy.Vetayases@oracle.com 1457*12683SJimmy.Vetayases@oracle.com ASSERT(LOCK_HELD(&apix_lock) && count > 0); 1458*12683SJimmy.Vetayases@oracle.com 1459*12683SJimmy.Vetayases@oracle.com if (!apix_is_cpu_enabled(newcpu)) 1460*12683SJimmy.Vetayases@oracle.com return (NULL); 1461*12683SJimmy.Vetayases@oracle.com 1462*12683SJimmy.Vetayases@oracle.com if (vecp->v_cpuid == newcpu) /* rebind to the same cpu */ 1463*12683SJimmy.Vetayases@oracle.com return (vecp); 1464*12683SJimmy.Vetayases@oracle.com 1465*12683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(oldcpu); 1466*12683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(newcpu); 1467*12683SJimmy.Vetayases@oracle.com 1468*12683SJimmy.Vetayases@oracle.com /* allocate vector */ 1469*12683SJimmy.Vetayases@oracle.com if (count == 1) 1470*12683SJimmy.Vetayases@oracle.com newp = apix_alloc_vector_oncpu(newcpu, NULL, 0, vecp->v_type); 1471*12683SJimmy.Vetayases@oracle.com else { 1472*12683SJimmy.Vetayases@oracle.com ASSERT(vecp->v_type == APIX_TYPE_MSI); 1473*12683SJimmy.Vetayases@oracle.com newp = apix_alloc_nvectors_oncpu(newcpu, NULL, 0, count, 1474*12683SJimmy.Vetayases@oracle.com vecp->v_type); 1475*12683SJimmy.Vetayases@oracle.com } 1476*12683SJimmy.Vetayases@oracle.com if (newp == NULL) { 1477*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(newcpu); 1478*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(oldcpu); 1479*12683SJimmy.Vetayases@oracle.com return (NULL); 1480*12683SJimmy.Vetayases@oracle.com } 1481*12683SJimmy.Vetayases@oracle.com 1482*12683SJimmy.Vetayases@oracle.com newvec = newp->v_vector; 1483*12683SJimmy.Vetayases@oracle.com apix_dup_vectors(vecp, newp, count); 1484*12683SJimmy.Vetayases@oracle.com 1485*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(newcpu); 1486*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(oldcpu); 1487*12683SJimmy.Vetayases@oracle.com 1488*12683SJimmy.Vetayases@oracle.com if (!DDI_INTR_IS_MSI_OR_MSIX(vecp->v_type)) { 1489*12683SJimmy.Vetayases@oracle.com ASSERT(count == 1); 1490*12683SJimmy.Vetayases@oracle.com if (apix_intx_rebind(vecp->v_inum, newcpu, newvec) != 0) { 1491*12683SJimmy.Vetayases@oracle.com struct autovec *avp; 1492*12683SJimmy.Vetayases@oracle.com int inum; 1493*12683SJimmy.Vetayases@oracle.com 1494*12683SJimmy.Vetayases@oracle.com /* undo duplication */ 1495*12683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(oldcpu); 1496*12683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(newcpu); 1497*12683SJimmy.Vetayases@oracle.com for (avp = newp->v_autovect; avp != NULL; 1498*12683SJimmy.Vetayases@oracle.com avp = avp->av_link) { 1499*12683SJimmy.Vetayases@oracle.com if (avp->av_dip != NULL) { 1500*12683SJimmy.Vetayases@oracle.com inum = GET_INTR_INUM(avp->av_intr_id); 1501*12683SJimmy.Vetayases@oracle.com apix_set_dev_map(vecp, avp->av_dip, 1502*12683SJimmy.Vetayases@oracle.com inum); 1503*12683SJimmy.Vetayases@oracle.com } 1504*12683SJimmy.Vetayases@oracle.com apix_remove_av(newp, avp); 1505*12683SJimmy.Vetayases@oracle.com } 1506*12683SJimmy.Vetayases@oracle.com apix_cleanup_vector(newp); 1507*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(newcpu); 1508*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(oldcpu); 1509*12683SJimmy.Vetayases@oracle.com APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind fixed " 1510*12683SJimmy.Vetayases@oracle.com "interrupt 0x%x to cpu %d failed\n", 1511*12683SJimmy.Vetayases@oracle.com vecp->v_inum, newcpu)); 1512*12683SJimmy.Vetayases@oracle.com return (NULL); 1513*12683SJimmy.Vetayases@oracle.com } 1514*12683SJimmy.Vetayases@oracle.com 1515*12683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(oldcpu); 1516*12683SJimmy.Vetayases@oracle.com (void) apix_obsolete_vector(vecp); 1517*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(oldcpu); 1518*12683SJimmy.Vetayases@oracle.com APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind fixed interrupt" 1519*12683SJimmy.Vetayases@oracle.com " 0x%x/0x%x to 0x%x/0x%x\n", 1520*12683SJimmy.Vetayases@oracle.com oldcpu, oldvec, newcpu, newvec)); 1521*12683SJimmy.Vetayases@oracle.com return (newp); 1522*12683SJimmy.Vetayases@oracle.com } 1523*12683SJimmy.Vetayases@oracle.com 1524*12683SJimmy.Vetayases@oracle.com for (i = 0; i < count; i++) { 1525*12683SJimmy.Vetayases@oracle.com oldp = xv_vector(oldcpu, oldvec + i); 1526*12683SJimmy.Vetayases@oracle.com newp = xv_vector(newcpu, newvec + i); 1527*12683SJimmy.Vetayases@oracle.com 1528*12683SJimmy.Vetayases@oracle.com if (newp->v_share > 0) { 1529*12683SJimmy.Vetayases@oracle.com APIX_SET_REBIND_INFO(oldp, newp); 1530*12683SJimmy.Vetayases@oracle.com 1531*12683SJimmy.Vetayases@oracle.com apix_enable_vector(newp); 1532*12683SJimmy.Vetayases@oracle.com 1533*12683SJimmy.Vetayases@oracle.com APIX_CLR_REBIND_INFO(); 1534*12683SJimmy.Vetayases@oracle.com } 1535*12683SJimmy.Vetayases@oracle.com 1536*12683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(oldcpu); 1537*12683SJimmy.Vetayases@oracle.com (void) apix_obsolete_vector(oldp); 1538*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(oldcpu); 1539*12683SJimmy.Vetayases@oracle.com } 1540*12683SJimmy.Vetayases@oracle.com APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind vector 0x%x/0x%x " 1541*12683SJimmy.Vetayases@oracle.com "to 0x%x/0x%x, count=%d\n", 1542*12683SJimmy.Vetayases@oracle.com oldcpu, oldvec, newcpu, newvec, count)); 1543*12683SJimmy.Vetayases@oracle.com 1544*12683SJimmy.Vetayases@oracle.com return (xv_vector(newcpu, newvec)); 1545*12683SJimmy.Vetayases@oracle.com } 1546*12683SJimmy.Vetayases@oracle.com 1547*12683SJimmy.Vetayases@oracle.com /* 1548*12683SJimmy.Vetayases@oracle.com * Senarios include: 1549*12683SJimmy.Vetayases@oracle.com * a. add_avintr() is called before irqp initialized (legacy) 1550*12683SJimmy.Vetayases@oracle.com * b. irqp is initialized, vector is not allocated (fixed interrupts) 1551*12683SJimmy.Vetayases@oracle.com * c. irqp is initialized, vector is allocated (shared interrupts) 1552*12683SJimmy.Vetayases@oracle.com */ 1553*12683SJimmy.Vetayases@oracle.com apix_vector_t * 1554*12683SJimmy.Vetayases@oracle.com apix_alloc_intx(dev_info_t *dip, int inum, int irqno) 1555*12683SJimmy.Vetayases@oracle.com { 1556*12683SJimmy.Vetayases@oracle.com apic_irq_t *irqp; 1557*12683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 1558*12683SJimmy.Vetayases@oracle.com 1559*12683SJimmy.Vetayases@oracle.com /* 1560*12683SJimmy.Vetayases@oracle.com * Allocate IRQ. Caller is later responsible for the 1561*12683SJimmy.Vetayases@oracle.com * initialization 1562*12683SJimmy.Vetayases@oracle.com */ 1563*12683SJimmy.Vetayases@oracle.com mutex_enter(&airq_mutex); 1564*12683SJimmy.Vetayases@oracle.com if ((irqp = apic_irq_table[irqno]) == NULL) { 1565*12683SJimmy.Vetayases@oracle.com /* allocate irq */ 1566*12683SJimmy.Vetayases@oracle.com irqp = kmem_zalloc(sizeof (apic_irq_t), KM_SLEEP); 1567*12683SJimmy.Vetayases@oracle.com irqp->airq_mps_intr_index = FREE_INDEX; 1568*12683SJimmy.Vetayases@oracle.com apic_irq_table[irqno] = irqp; 1569*12683SJimmy.Vetayases@oracle.com } 1570*12683SJimmy.Vetayases@oracle.com if (irqp->airq_mps_intr_index == FREE_INDEX) { 1571*12683SJimmy.Vetayases@oracle.com irqp->airq_mps_intr_index = DEFAULT_INDEX; 1572*12683SJimmy.Vetayases@oracle.com irqp->airq_cpu = IRQ_UNINIT; 1573*12683SJimmy.Vetayases@oracle.com irqp->airq_origirq = (uchar_t)irqno; 1574*12683SJimmy.Vetayases@oracle.com } 1575*12683SJimmy.Vetayases@oracle.com 1576*12683SJimmy.Vetayases@oracle.com mutex_exit(&airq_mutex); 1577*12683SJimmy.Vetayases@oracle.com 1578*12683SJimmy.Vetayases@oracle.com /* 1579*12683SJimmy.Vetayases@oracle.com * allocate vector 1580*12683SJimmy.Vetayases@oracle.com */ 1581*12683SJimmy.Vetayases@oracle.com if (irqp->airq_cpu == IRQ_UNINIT) { 1582*12683SJimmy.Vetayases@oracle.com uint32_t bindcpu, cpuid; 1583*12683SJimmy.Vetayases@oracle.com 1584*12683SJimmy.Vetayases@oracle.com /* select cpu by system policy */ 1585*12683SJimmy.Vetayases@oracle.com bindcpu = apix_bind_cpu(dip); 1586*12683SJimmy.Vetayases@oracle.com cpuid = bindcpu & ~IRQ_USER_BOUND; 1587*12683SJimmy.Vetayases@oracle.com 1588*12683SJimmy.Vetayases@oracle.com /* allocate vector */ 1589*12683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(cpuid); 1590*12683SJimmy.Vetayases@oracle.com 1591*12683SJimmy.Vetayases@oracle.com if ((vecp = apix_alloc_vector_oncpu(bindcpu, dip, inum, 1592*12683SJimmy.Vetayases@oracle.com APIX_TYPE_FIXED)) == NULL) { 1593*12683SJimmy.Vetayases@oracle.com cmn_err(CE_WARN, "No interrupt vector for irq %x", 1594*12683SJimmy.Vetayases@oracle.com irqno); 1595*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 1596*12683SJimmy.Vetayases@oracle.com return (NULL); 1597*12683SJimmy.Vetayases@oracle.com } 1598*12683SJimmy.Vetayases@oracle.com vecp->v_inum = irqno; 1599*12683SJimmy.Vetayases@oracle.com vecp->v_flags |= APIX_VECT_MASKABLE; 1600*12683SJimmy.Vetayases@oracle.com 1601*12683SJimmy.Vetayases@oracle.com apix_intx_set_vector(irqno, vecp->v_cpuid, vecp->v_vector); 1602*12683SJimmy.Vetayases@oracle.com 1603*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 1604*12683SJimmy.Vetayases@oracle.com } else { 1605*12683SJimmy.Vetayases@oracle.com vecp = xv_vector(irqp->airq_cpu, irqp->airq_vector); 1606*12683SJimmy.Vetayases@oracle.com ASSERT(!IS_VECT_FREE(vecp)); 1607*12683SJimmy.Vetayases@oracle.com 1608*12683SJimmy.Vetayases@oracle.com if (dip != NULL) 1609*12683SJimmy.Vetayases@oracle.com apix_set_dev_map(vecp, dip, inum); 1610*12683SJimmy.Vetayases@oracle.com } 1611*12683SJimmy.Vetayases@oracle.com 1612*12683SJimmy.Vetayases@oracle.com if ((dip != NULL) && 1613*12683SJimmy.Vetayases@oracle.com (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) && 1614*12683SJimmy.Vetayases@oracle.com ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0)) 1615*12683SJimmy.Vetayases@oracle.com apix_set_dev_binding(dip, vecp->v_cpuid); 1616*12683SJimmy.Vetayases@oracle.com 1617*12683SJimmy.Vetayases@oracle.com apix_dprint_vector(vecp, dip, 1); 1618*12683SJimmy.Vetayases@oracle.com 1619*12683SJimmy.Vetayases@oracle.com return (vecp); 1620*12683SJimmy.Vetayases@oracle.com } 1621*12683SJimmy.Vetayases@oracle.com 1622*12683SJimmy.Vetayases@oracle.com int 1623*12683SJimmy.Vetayases@oracle.com apix_alloc_msi(dev_info_t *dip, int inum, int count, int behavior) 1624*12683SJimmy.Vetayases@oracle.com { 1625*12683SJimmy.Vetayases@oracle.com int i, cap_ptr, rcount = count; 1626*12683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 1627*12683SJimmy.Vetayases@oracle.com processorid_t bindcpu, cpuid; 1628*12683SJimmy.Vetayases@oracle.com ushort_t msi_ctrl; 1629*12683SJimmy.Vetayases@oracle.com ddi_acc_handle_t handle; 1630*12683SJimmy.Vetayases@oracle.com 1631*12683SJimmy.Vetayases@oracle.com DDI_INTR_IMPLDBG((CE_CONT, "apix_alloc_msi_vectors: dip=0x%p " 1632*12683SJimmy.Vetayases@oracle.com "inum=0x%x count=0x%x behavior=%d\n", 1633*12683SJimmy.Vetayases@oracle.com (void *)dip, inum, count, behavior)); 1634*12683SJimmy.Vetayases@oracle.com 1635*12683SJimmy.Vetayases@oracle.com if (count > 1) { 1636*12683SJimmy.Vetayases@oracle.com if (behavior == DDI_INTR_ALLOC_STRICT && 1637*12683SJimmy.Vetayases@oracle.com apic_multi_msi_enable == 0) 1638*12683SJimmy.Vetayases@oracle.com return (0); 1639*12683SJimmy.Vetayases@oracle.com if (apic_multi_msi_enable == 0) 1640*12683SJimmy.Vetayases@oracle.com count = 1; 1641*12683SJimmy.Vetayases@oracle.com } 1642*12683SJimmy.Vetayases@oracle.com 1643*12683SJimmy.Vetayases@oracle.com /* Check whether it supports per-vector masking */ 1644*12683SJimmy.Vetayases@oracle.com cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip); 1645*12683SJimmy.Vetayases@oracle.com handle = i_ddi_get_pci_config_handle(dip); 1646*12683SJimmy.Vetayases@oracle.com msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL); 1647*12683SJimmy.Vetayases@oracle.com 1648*12683SJimmy.Vetayases@oracle.com /* bind to cpu */ 1649*12683SJimmy.Vetayases@oracle.com bindcpu = apix_bind_cpu(dip); 1650*12683SJimmy.Vetayases@oracle.com cpuid = bindcpu & ~IRQ_USER_BOUND; 1651*12683SJimmy.Vetayases@oracle.com 1652*12683SJimmy.Vetayases@oracle.com /* if not ISP2, then round it down */ 1653*12683SJimmy.Vetayases@oracle.com if (!ISP2(rcount)) 1654*12683SJimmy.Vetayases@oracle.com rcount = 1 << (highbit(rcount) - 1); 1655*12683SJimmy.Vetayases@oracle.com 1656*12683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(cpuid); 1657*12683SJimmy.Vetayases@oracle.com for (vecp = NULL; rcount > 0; rcount >>= 1) { 1658*12683SJimmy.Vetayases@oracle.com vecp = apix_alloc_nvectors_oncpu(bindcpu, dip, inum, rcount, 1659*12683SJimmy.Vetayases@oracle.com APIX_TYPE_MSI); 1660*12683SJimmy.Vetayases@oracle.com if (vecp != NULL || behavior == DDI_INTR_ALLOC_STRICT) 1661*12683SJimmy.Vetayases@oracle.com break; 1662*12683SJimmy.Vetayases@oracle.com } 1663*12683SJimmy.Vetayases@oracle.com for (i = 0; vecp && i < rcount; i++) 1664*12683SJimmy.Vetayases@oracle.com xv_vector(vecp->v_cpuid, vecp->v_vector + i)->v_flags |= 1665*12683SJimmy.Vetayases@oracle.com (msi_ctrl & PCI_MSI_PVM_MASK) ? APIX_VECT_MASKABLE : 0; 1666*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 1667*12683SJimmy.Vetayases@oracle.com if (vecp == NULL) { 1668*12683SJimmy.Vetayases@oracle.com APIC_VERBOSE(INTR, (CE_CONT, 1669*12683SJimmy.Vetayases@oracle.com "apix_alloc_msi: no %d cont vectors found on cpu 0x%x\n", 1670*12683SJimmy.Vetayases@oracle.com count, bindcpu)); 1671*12683SJimmy.Vetayases@oracle.com return (0); 1672*12683SJimmy.Vetayases@oracle.com } 1673*12683SJimmy.Vetayases@oracle.com 1674*12683SJimmy.Vetayases@oracle.com /* major to cpu binding */ 1675*12683SJimmy.Vetayases@oracle.com if ((apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) && 1676*12683SJimmy.Vetayases@oracle.com ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0)) 1677*12683SJimmy.Vetayases@oracle.com apix_set_dev_binding(dip, vecp->v_cpuid); 1678*12683SJimmy.Vetayases@oracle.com 1679*12683SJimmy.Vetayases@oracle.com apix_dprint_vector(vecp, dip, rcount); 1680*12683SJimmy.Vetayases@oracle.com 1681*12683SJimmy.Vetayases@oracle.com return (rcount); 1682*12683SJimmy.Vetayases@oracle.com } 1683*12683SJimmy.Vetayases@oracle.com 1684*12683SJimmy.Vetayases@oracle.com int 1685*12683SJimmy.Vetayases@oracle.com apix_alloc_msix(dev_info_t *dip, int inum, int count, int behavior) 1686*12683SJimmy.Vetayases@oracle.com { 1687*12683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 1688*12683SJimmy.Vetayases@oracle.com processorid_t bindcpu, cpuid; 1689*12683SJimmy.Vetayases@oracle.com int i; 1690*12683SJimmy.Vetayases@oracle.com 1691*12683SJimmy.Vetayases@oracle.com for (i = 0; i < count; i++) { 1692*12683SJimmy.Vetayases@oracle.com /* select cpu by system policy */ 1693*12683SJimmy.Vetayases@oracle.com bindcpu = apix_bind_cpu(dip); 1694*12683SJimmy.Vetayases@oracle.com cpuid = bindcpu & ~IRQ_USER_BOUND; 1695*12683SJimmy.Vetayases@oracle.com 1696*12683SJimmy.Vetayases@oracle.com /* allocate vector */ 1697*12683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(cpuid); 1698*12683SJimmy.Vetayases@oracle.com if ((vecp = apix_alloc_vector_oncpu(bindcpu, dip, inum + i, 1699*12683SJimmy.Vetayases@oracle.com APIX_TYPE_MSIX)) == NULL) { 1700*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 1701*12683SJimmy.Vetayases@oracle.com APIC_VERBOSE(INTR, (CE_CONT, "apix_alloc_msix: " 1702*12683SJimmy.Vetayases@oracle.com "allocate msix for device dip=%p, inum=%d on" 1703*12683SJimmy.Vetayases@oracle.com " cpu %d failed", (void *)dip, inum + i, bindcpu)); 1704*12683SJimmy.Vetayases@oracle.com break; 1705*12683SJimmy.Vetayases@oracle.com } 1706*12683SJimmy.Vetayases@oracle.com vecp->v_flags |= APIX_VECT_MASKABLE; 1707*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 1708*12683SJimmy.Vetayases@oracle.com 1709*12683SJimmy.Vetayases@oracle.com /* major to cpu mapping */ 1710*12683SJimmy.Vetayases@oracle.com if ((i == 0) && 1711*12683SJimmy.Vetayases@oracle.com (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) && 1712*12683SJimmy.Vetayases@oracle.com ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0)) 1713*12683SJimmy.Vetayases@oracle.com apix_set_dev_binding(dip, vecp->v_cpuid); 1714*12683SJimmy.Vetayases@oracle.com 1715*12683SJimmy.Vetayases@oracle.com apix_dprint_vector(vecp, dip, 1); 1716*12683SJimmy.Vetayases@oracle.com } 1717*12683SJimmy.Vetayases@oracle.com 1718*12683SJimmy.Vetayases@oracle.com if (i < count && behavior == DDI_INTR_ALLOC_STRICT) { 1719*12683SJimmy.Vetayases@oracle.com APIC_VERBOSE(INTR, (CE_WARN, "apix_alloc_msix: " 1720*12683SJimmy.Vetayases@oracle.com "strictly allocate %d vectors failed, got %d\n", 1721*12683SJimmy.Vetayases@oracle.com count, i)); 1722*12683SJimmy.Vetayases@oracle.com apix_free_vectors(dip, inum, i, APIX_TYPE_MSIX); 1723*12683SJimmy.Vetayases@oracle.com i = 0; 1724*12683SJimmy.Vetayases@oracle.com } 1725*12683SJimmy.Vetayases@oracle.com 1726*12683SJimmy.Vetayases@oracle.com return (i); 1727*12683SJimmy.Vetayases@oracle.com } 1728*12683SJimmy.Vetayases@oracle.com 1729*12683SJimmy.Vetayases@oracle.com /* 1730*12683SJimmy.Vetayases@oracle.com * A rollback free for vectors allocated by apix_alloc_xxx(). 1731*12683SJimmy.Vetayases@oracle.com */ 1732*12683SJimmy.Vetayases@oracle.com void 1733*12683SJimmy.Vetayases@oracle.com apix_free_vectors(dev_info_t *dip, int inum, int count, int type) 1734*12683SJimmy.Vetayases@oracle.com { 1735*12683SJimmy.Vetayases@oracle.com int i, cpuid; 1736*12683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 1737*12683SJimmy.Vetayases@oracle.com 1738*12683SJimmy.Vetayases@oracle.com DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: dip: %p inum: %x " 1739*12683SJimmy.Vetayases@oracle.com "count: %x type: %x\n", 1740*12683SJimmy.Vetayases@oracle.com (void *)dip, inum, count, type)); 1741*12683SJimmy.Vetayases@oracle.com 1742*12683SJimmy.Vetayases@oracle.com lock_set(&apix_lock); 1743*12683SJimmy.Vetayases@oracle.com 1744*12683SJimmy.Vetayases@oracle.com for (i = 0; i < count; i++, inum++) { 1745*12683SJimmy.Vetayases@oracle.com if ((vecp = apix_get_dev_map(dip, inum, type)) == NULL) { 1746*12683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 1747*12683SJimmy.Vetayases@oracle.com DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: " 1748*12683SJimmy.Vetayases@oracle.com "dip=0x%p inum=0x%x type=0x%x apix_find_intr() " 1749*12683SJimmy.Vetayases@oracle.com "failed\n", (void *)dip, inum, type)); 1750*12683SJimmy.Vetayases@oracle.com continue; 1751*12683SJimmy.Vetayases@oracle.com } 1752*12683SJimmy.Vetayases@oracle.com 1753*12683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(vecp->v_cpuid); 1754*12683SJimmy.Vetayases@oracle.com cpuid = vecp->v_cpuid; 1755*12683SJimmy.Vetayases@oracle.com 1756*12683SJimmy.Vetayases@oracle.com DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: " 1757*12683SJimmy.Vetayases@oracle.com "dip=0x%p inum=0x%x type=0x%x vector 0x%x (share %d)\n", 1758*12683SJimmy.Vetayases@oracle.com (void *)dip, inum, type, vecp->v_vector, vecp->v_share)); 1759*12683SJimmy.Vetayases@oracle.com 1760*12683SJimmy.Vetayases@oracle.com /* tear down device interrupt to vector mapping */ 1761*12683SJimmy.Vetayases@oracle.com apix_clear_dev_map(dip, inum, type); 1762*12683SJimmy.Vetayases@oracle.com 1763*12683SJimmy.Vetayases@oracle.com if (vecp->v_type == APIX_TYPE_FIXED) { 1764*12683SJimmy.Vetayases@oracle.com if (vecp->v_share > 0) { /* share IRQ line */ 1765*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 1766*12683SJimmy.Vetayases@oracle.com continue; 1767*12683SJimmy.Vetayases@oracle.com } 1768*12683SJimmy.Vetayases@oracle.com 1769*12683SJimmy.Vetayases@oracle.com /* Free apic_irq_table entry */ 1770*12683SJimmy.Vetayases@oracle.com apix_intx_free(vecp->v_inum); 1771*12683SJimmy.Vetayases@oracle.com } 1772*12683SJimmy.Vetayases@oracle.com 1773*12683SJimmy.Vetayases@oracle.com /* free vector */ 1774*12683SJimmy.Vetayases@oracle.com apix_cleanup_vector(vecp); 1775*12683SJimmy.Vetayases@oracle.com 1776*12683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 1777*12683SJimmy.Vetayases@oracle.com } 1778*12683SJimmy.Vetayases@oracle.com 1779*12683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 1780*12683SJimmy.Vetayases@oracle.com } 1781*12683SJimmy.Vetayases@oracle.com 1782*12683SJimmy.Vetayases@oracle.com /* 1783*12683SJimmy.Vetayases@oracle.com * Must be called with apix_lock held 1784*12683SJimmy.Vetayases@oracle.com */ 1785*12683SJimmy.Vetayases@oracle.com apix_vector_t * 1786*12683SJimmy.Vetayases@oracle.com apix_setup_io_intr(apix_vector_t *vecp) 1787*12683SJimmy.Vetayases@oracle.com { 1788*12683SJimmy.Vetayases@oracle.com processorid_t bindcpu; 1789*12683SJimmy.Vetayases@oracle.com int ret; 1790*12683SJimmy.Vetayases@oracle.com 1791*12683SJimmy.Vetayases@oracle.com ASSERT(LOCK_HELD(&apix_lock)); 1792*12683SJimmy.Vetayases@oracle.com 1793*12683SJimmy.Vetayases@oracle.com /* 1794*12683SJimmy.Vetayases@oracle.com * Interrupts are enabled on the CPU, programme IOAPIC RDT 1795*12683SJimmy.Vetayases@oracle.com * entry or MSI/X address/data to enable the interrupt. 1796*12683SJimmy.Vetayases@oracle.com */ 1797*12683SJimmy.Vetayases@oracle.com if (apix_is_cpu_enabled(vecp->v_cpuid)) { 1798*12683SJimmy.Vetayases@oracle.com apix_enable_vector(vecp); 1799*12683SJimmy.Vetayases@oracle.com return (vecp); 1800*12683SJimmy.Vetayases@oracle.com } 1801*12683SJimmy.Vetayases@oracle.com 1802*12683SJimmy.Vetayases@oracle.com /* 1803*12683SJimmy.Vetayases@oracle.com * CPU is not up or interrupts are disabled. Fall back to the 1804*12683SJimmy.Vetayases@oracle.com * first avialable CPU. 1805*12683SJimmy.Vetayases@oracle.com */ 1806*12683SJimmy.Vetayases@oracle.com bindcpu = apic_find_cpu(APIC_CPU_INTR_ENABLE); 1807*12683SJimmy.Vetayases@oracle.com 1808*12683SJimmy.Vetayases@oracle.com if (vecp->v_type == APIX_TYPE_MSI) 1809*12683SJimmy.Vetayases@oracle.com return (apix_grp_set_cpu(vecp, bindcpu, &ret)); 1810*12683SJimmy.Vetayases@oracle.com 1811*12683SJimmy.Vetayases@oracle.com return (apix_set_cpu(vecp, bindcpu, &ret)); 1812*12683SJimmy.Vetayases@oracle.com } 1813*12683SJimmy.Vetayases@oracle.com 1814*12683SJimmy.Vetayases@oracle.com /* 1815*12683SJimmy.Vetayases@oracle.com * For interrupts which call add_avintr() before apic is initialized. 1816*12683SJimmy.Vetayases@oracle.com * ioapix_setup_intr() will 1817*12683SJimmy.Vetayases@oracle.com * - allocate vector 1818*12683SJimmy.Vetayases@oracle.com * - copy over ISR 1819*12683SJimmy.Vetayases@oracle.com */ 1820*12683SJimmy.Vetayases@oracle.com static void 1821*12683SJimmy.Vetayases@oracle.com ioapix_setup_intr(int irqno, iflag_t *flagp) 1822*12683SJimmy.Vetayases@oracle.com { 1823*12683SJimmy.Vetayases@oracle.com extern struct av_head autovect[]; 1824*12683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 1825*12683SJimmy.Vetayases@oracle.com apic_irq_t *irqp; 1826*12683SJimmy.Vetayases@oracle.com uchar_t ioapicindex, ipin; 1827*12683SJimmy.Vetayases@oracle.com ulong_t iflag; 1828*12683SJimmy.Vetayases@oracle.com struct autovec *avp; 1829*12683SJimmy.Vetayases@oracle.com 1830*12683SJimmy.Vetayases@oracle.com irqp = apic_irq_table[irqno]; 1831*12683SJimmy.Vetayases@oracle.com ioapicindex = acpi_find_ioapic(irqno); 1832*12683SJimmy.Vetayases@oracle.com ASSERT(ioapicindex != 0xFF); 1833*12683SJimmy.Vetayases@oracle.com ipin = irqno - apic_io_vectbase[ioapicindex]; 1834*12683SJimmy.Vetayases@oracle.com 1835*12683SJimmy.Vetayases@oracle.com if ((irqp != NULL) && (irqp->airq_mps_intr_index == ACPI_INDEX)) { 1836*12683SJimmy.Vetayases@oracle.com ASSERT(irqp->airq_intin_no == ipin && 1837*12683SJimmy.Vetayases@oracle.com irqp->airq_ioapicindex == ioapicindex); 1838*12683SJimmy.Vetayases@oracle.com vecp = xv_vector(irqp->airq_cpu, irqp->airq_vector); 1839*12683SJimmy.Vetayases@oracle.com ASSERT(!IS_VECT_FREE(vecp)); 1840*12683SJimmy.Vetayases@oracle.com } else { 1841*12683SJimmy.Vetayases@oracle.com vecp = apix_alloc_intx(NULL, 0, irqno); 1842*12683SJimmy.Vetayases@oracle.com 1843*12683SJimmy.Vetayases@oracle.com irqp = apic_irq_table[irqno]; 1844*12683SJimmy.Vetayases@oracle.com irqp->airq_mps_intr_index = ACPI_INDEX; 1845*12683SJimmy.Vetayases@oracle.com irqp->airq_ioapicindex = ioapicindex; 1846*12683SJimmy.Vetayases@oracle.com irqp->airq_intin_no = ipin; 1847*12683SJimmy.Vetayases@oracle.com irqp->airq_iflag = *flagp; 1848*12683SJimmy.Vetayases@oracle.com irqp->airq_share++; 1849*12683SJimmy.Vetayases@oracle.com apic_record_rdt_entry(irqp, irqno); 1850*12683SJimmy.Vetayases@oracle.com } 1851*12683SJimmy.Vetayases@oracle.com 1852*12683SJimmy.Vetayases@oracle.com /* copy over autovect */ 1853*12683SJimmy.Vetayases@oracle.com for (avp = autovect[irqno].avh_link; avp; avp = avp->av_link) 1854*12683SJimmy.Vetayases@oracle.com apix_insert_av(vecp, avp->av_intr_id, avp->av_vector, 1855*12683SJimmy.Vetayases@oracle.com avp->av_intarg1, avp->av_intarg2, avp->av_ticksp, 1856*12683SJimmy.Vetayases@oracle.com avp->av_prilevel, avp->av_dip); 1857*12683SJimmy.Vetayases@oracle.com 1858*12683SJimmy.Vetayases@oracle.com /* Program I/O APIC */ 1859*12683SJimmy.Vetayases@oracle.com iflag = intr_clear(); 1860*12683SJimmy.Vetayases@oracle.com lock_set(&apix_lock); 1861*12683SJimmy.Vetayases@oracle.com 1862*12683SJimmy.Vetayases@oracle.com (void) apix_setup_io_intr(vecp); 1863*12683SJimmy.Vetayases@oracle.com 1864*12683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 1865*12683SJimmy.Vetayases@oracle.com intr_restore(iflag); 1866*12683SJimmy.Vetayases@oracle.com 1867*12683SJimmy.Vetayases@oracle.com APIC_VERBOSE_IOAPIC((CE_CONT, "apix: setup ioapic, irqno %x " 1868*12683SJimmy.Vetayases@oracle.com "(ioapic %x, ipin %x) is bound to cpu %x, vector %x\n", 1869*12683SJimmy.Vetayases@oracle.com irqno, ioapicindex, ipin, irqp->airq_cpu, irqp->airq_vector)); 1870*12683SJimmy.Vetayases@oracle.com } 1871*12683SJimmy.Vetayases@oracle.com 1872*12683SJimmy.Vetayases@oracle.com void 1873*12683SJimmy.Vetayases@oracle.com ioapix_init_intr(int mask_apic) 1874*12683SJimmy.Vetayases@oracle.com { 1875*12683SJimmy.Vetayases@oracle.com int ioapicindex; 1876*12683SJimmy.Vetayases@oracle.com int i, j; 1877*12683SJimmy.Vetayases@oracle.com 1878*12683SJimmy.Vetayases@oracle.com /* mask interrupt vectors */ 1879*12683SJimmy.Vetayases@oracle.com for (j = 0; j < apic_io_max && mask_apic; j++) { 1880*12683SJimmy.Vetayases@oracle.com int intin_max; 1881*12683SJimmy.Vetayases@oracle.com 1882*12683SJimmy.Vetayases@oracle.com ioapicindex = j; 1883*12683SJimmy.Vetayases@oracle.com /* Bits 23-16 define the maximum redirection entries */ 1884*12683SJimmy.Vetayases@oracle.com intin_max = (ioapic_read(ioapicindex, APIC_VERS_CMD) >> 16) 1885*12683SJimmy.Vetayases@oracle.com & 0xff; 1886*12683SJimmy.Vetayases@oracle.com for (i = 0; i <= intin_max; i++) 1887*12683SJimmy.Vetayases@oracle.com ioapic_write(ioapicindex, APIC_RDT_CMD + 2 * i, 1888*12683SJimmy.Vetayases@oracle.com AV_MASK); 1889*12683SJimmy.Vetayases@oracle.com } 1890*12683SJimmy.Vetayases@oracle.com 1891*12683SJimmy.Vetayases@oracle.com /* 1892*12683SJimmy.Vetayases@oracle.com * Hack alert: deal with ACPI SCI interrupt chicken/egg here 1893*12683SJimmy.Vetayases@oracle.com */ 1894*12683SJimmy.Vetayases@oracle.com if (apic_sci_vect > 0) 1895*12683SJimmy.Vetayases@oracle.com ioapix_setup_intr(apic_sci_vect, &apic_sci_flags); 1896*12683SJimmy.Vetayases@oracle.com 1897*12683SJimmy.Vetayases@oracle.com /* 1898*12683SJimmy.Vetayases@oracle.com * Hack alert: deal with ACPI HPET interrupt chicken/egg here. 1899*12683SJimmy.Vetayases@oracle.com */ 1900*12683SJimmy.Vetayases@oracle.com if (apic_hpet_vect > 0) 1901*12683SJimmy.Vetayases@oracle.com ioapix_setup_intr(apic_hpet_vect, &apic_hpet_flags); 1902*12683SJimmy.Vetayases@oracle.com } 1903