1*7ff178cdSJimmy Vetayases /* 2*7ff178cdSJimmy Vetayases * CDDL HEADER START 3*7ff178cdSJimmy Vetayases * 4*7ff178cdSJimmy Vetayases * The contents of this file are subject to the terms of the 5*7ff178cdSJimmy Vetayases * Common Development and Distribution License (the "License"). 6*7ff178cdSJimmy Vetayases * You may not use this file except in compliance with the License. 7*7ff178cdSJimmy Vetayases * 8*7ff178cdSJimmy Vetayases * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*7ff178cdSJimmy Vetayases * or http://www.opensolaris.org/os/licensing. 10*7ff178cdSJimmy Vetayases * See the License for the specific language governing permissions 11*7ff178cdSJimmy Vetayases * and limitations under the License. 12*7ff178cdSJimmy Vetayases * 13*7ff178cdSJimmy Vetayases * When distributing Covered Code, include this CDDL HEADER in each 14*7ff178cdSJimmy Vetayases * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*7ff178cdSJimmy Vetayases * If applicable, add the following below this CDDL HEADER, with the 16*7ff178cdSJimmy Vetayases * fields enclosed by brackets "[]" replaced with your own identifying 17*7ff178cdSJimmy Vetayases * information: Portions Copyright [yyyy] [name of copyright owner] 18*7ff178cdSJimmy Vetayases * 19*7ff178cdSJimmy Vetayases * CDDL HEADER END 20*7ff178cdSJimmy Vetayases */ 21*7ff178cdSJimmy Vetayases 22*7ff178cdSJimmy Vetayases /* 23*7ff178cdSJimmy Vetayases * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24*7ff178cdSJimmy Vetayases */ 25*7ff178cdSJimmy Vetayases 26*7ff178cdSJimmy Vetayases #include <sys/types.h> 27*7ff178cdSJimmy Vetayases #include <sys/sysmacros.h> 28*7ff178cdSJimmy Vetayases #include <sys/ddi.h> 29*7ff178cdSJimmy Vetayases #include <sys/sunndi.h> 30*7ff178cdSJimmy Vetayases #include <sys/ddi_impldefs.h> 31*7ff178cdSJimmy Vetayases #include <sys/psm_types.h> 32*7ff178cdSJimmy Vetayases #include <sys/smp_impldefs.h> 33*7ff178cdSJimmy Vetayases #include <sys/apic.h> 34*7ff178cdSJimmy Vetayases #include <sys/processor.h> 35*7ff178cdSJimmy Vetayases #include <sys/apix_irm_impl.h> 36*7ff178cdSJimmy Vetayases 37*7ff178cdSJimmy Vetayases /* global variable for static default limit for non-IRM drivers */ 38*7ff178cdSJimmy Vetayases extern int ddi_msix_alloc_limit; 39*7ff178cdSJimmy Vetayases 40*7ff178cdSJimmy Vetayases /* Extern declarations */ 41*7ff178cdSJimmy Vetayases extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *, 42*7ff178cdSJimmy Vetayases psm_intr_op_t, int *); 43*7ff178cdSJimmy Vetayases 44*7ff178cdSJimmy Vetayases /* 45*7ff178cdSJimmy Vetayases * Global variables for IRM pool configuration: 46*7ff178cdSJimmy Vetayases * 47*7ff178cdSJimmy Vetayases * (1) apix_system_max_vectors -- this would limit the maximum 48*7ff178cdSJimmy Vetayases * number of interrupt vectors that will be made avilable 49*7ff178cdSJimmy Vetayases * to the device drivers. The default value (-1) indicates 50*7ff178cdSJimmy Vetayases * that all the available vectors could be used. 51*7ff178cdSJimmy Vetayases * 52*7ff178cdSJimmy Vetayases * (2) apix_irm_cpu_factor -- This would specify the number of CPUs that 53*7ff178cdSJimmy Vetayases * should be excluded from the global IRM pool of interrupt vectors. 54*7ff178cdSJimmy Vetayases * By default this would be zero, so vectors from all the CPUs 55*7ff178cdSJimmy Vetayases * present will be factored into the IRM pool. 56*7ff178cdSJimmy Vetayases * 57*7ff178cdSJimmy Vetayases * (3) apix_irm_reserve_fixed_vectors -- This would specify the number 58*7ff178cdSJimmy Vetayases * of vectors that should be reserved for FIXED type interrupts and 59*7ff178cdSJimmy Vetayases * exclude them from the IRM pool. The value can be one of the 60*7ff178cdSJimmy Vetayases * following: 61*7ff178cdSJimmy Vetayases * 0 - no reservation (default) 62*7ff178cdSJimmy Vetayases * <n> - a positive number for the reserved cache 63*7ff178cdSJimmy Vetayases * -1 - reserve the maximum needed 64*7ff178cdSJimmy Vetayases * 65*7ff178cdSJimmy Vetayases * (4) apix_irm_free_fixed_vectors -- This flag specifies if the 66*7ff178cdSJimmy Vetayases * vectors for FIXED type should be freed and added back 67*7ff178cdSJimmy Vetayases * to the IRM pool when ddi_intr_free() is called. The default 68*7ff178cdSJimmy Vetayases * is to add it back to the pool. 69*7ff178cdSJimmy Vetayases */ 70*7ff178cdSJimmy Vetayases int apix_system_max_vectors = -1; 71*7ff178cdSJimmy Vetayases int apix_irm_cpu_factor = 0; 72*7ff178cdSJimmy Vetayases int apix_irm_reserve_fixed_vectors = 0; 73*7ff178cdSJimmy Vetayases int apix_irm_free_fixed_vector = 1; 74*7ff178cdSJimmy Vetayases 75*7ff178cdSJimmy Vetayases /* info from APIX module for IRM configuration */ 76*7ff178cdSJimmy Vetayases apix_irm_info_t apix_irminfo; 77*7ff178cdSJimmy Vetayases 78*7ff178cdSJimmy Vetayases kmutex_t apix_irm_lock; /* global mutex for apix_irm_* data */ 79*7ff178cdSJimmy Vetayases ddi_irm_params_t apix_irm_params; /* IRM pool info */ 80*7ff178cdSJimmy Vetayases int apix_irm_cache_size = 0; /* local cache for FIXED type requests */ 81*7ff178cdSJimmy Vetayases int apix_irm_cpu_factor_available = 0; 82*7ff178cdSJimmy Vetayases int apix_irm_max_cpus = 0; 83*7ff178cdSJimmy Vetayases int apix_irm_cpus_used = 0; 84*7ff178cdSJimmy Vetayases int apix_irm_fixed_intr_vectors_used; 85*7ff178cdSJimmy Vetayases 86*7ff178cdSJimmy Vetayases extern int ncpus; 87*7ff178cdSJimmy Vetayases 88*7ff178cdSJimmy Vetayases /* local data/functions */ 89*7ff178cdSJimmy Vetayases static int apix_irm_chk_apix(); 90*7ff178cdSJimmy Vetayases int apix_irm_intr_ops(dev_info_t *dip, ddi_intr_handle_impl_t *handle, 91*7ff178cdSJimmy Vetayases psm_intr_op_t op, int *result); 92*7ff178cdSJimmy Vetayases int apix_irm_disable_intr(processorid_t); 93*7ff178cdSJimmy Vetayases void apix_irm_enable_intr(processorid_t); 94*7ff178cdSJimmy Vetayases int (*psm_intr_ops_saved)(dev_info_t *dip, ddi_intr_handle_impl_t *handle, 95*7ff178cdSJimmy Vetayases psm_intr_op_t op, int *result) = NULL; 96*7ff178cdSJimmy Vetayases int (*psm_disable_intr_saved)(processorid_t) = NULL; 97*7ff178cdSJimmy Vetayases void (*psm_enable_intr_saved)(processorid_t) = NULL; 98*7ff178cdSJimmy Vetayases int apix_irm_alloc_fixed(dev_info_t *, ddi_intr_handle_impl_t *, int *); 99*7ff178cdSJimmy Vetayases int apix_irm_free_fixed(dev_info_t *, ddi_intr_handle_impl_t *, int *); 100*7ff178cdSJimmy Vetayases 101*7ff178cdSJimmy Vetayases /* 102*7ff178cdSJimmy Vetayases * Initilaize IRM pool for APIC interrupts if the PSM module 103*7ff178cdSJimmy Vetayases * is of APIX type. This should be called only after PSM module 104*7ff178cdSJimmy Vetayases * is loaded and APIC interrupt system is initialized. 105*7ff178cdSJimmy Vetayases */ 106*7ff178cdSJimmy Vetayases void 107*7ff178cdSJimmy Vetayases apix_irm_init(void) 108*7ff178cdSJimmy Vetayases { 109*7ff178cdSJimmy Vetayases dev_info_t *dip; 110*7ff178cdSJimmy Vetayases int total_avail_vectors; 111*7ff178cdSJimmy Vetayases int cpus_used; 112*7ff178cdSJimmy Vetayases int cache_size; 113*7ff178cdSJimmy Vetayases 114*7ff178cdSJimmy Vetayases /* nothing to do if IRM is disabled */ 115*7ff178cdSJimmy Vetayases if (!irm_enable) 116*7ff178cdSJimmy Vetayases return; 117*7ff178cdSJimmy Vetayases 118*7ff178cdSJimmy Vetayases /* 119*7ff178cdSJimmy Vetayases * Use root devinfo node to associate the IRM pool with it 120*7ff178cdSJimmy Vetayases * as the pool is global to the system. 121*7ff178cdSJimmy Vetayases */ 122*7ff178cdSJimmy Vetayases dip = ddi_root_node(); 123*7ff178cdSJimmy Vetayases 124*7ff178cdSJimmy Vetayases /* 125*7ff178cdSJimmy Vetayases * Check if PSM module is initialized and it is APIX 126*7ff178cdSJimmy Vetayases * module (which supports IRM functionality). 127*7ff178cdSJimmy Vetayases */ 128*7ff178cdSJimmy Vetayases if ((psm_intr_ops == NULL) || !apix_irm_chk_apix()) { 129*7ff178cdSJimmy Vetayases /* not an APIX module */ 130*7ff178cdSJimmy Vetayases APIX_IRM_DEBUG((CE_CONT, 131*7ff178cdSJimmy Vetayases "apix_irm_init: APIX module not present")); 132*7ff178cdSJimmy Vetayases return; 133*7ff178cdSJimmy Vetayases } 134*7ff178cdSJimmy Vetayases 135*7ff178cdSJimmy Vetayases /* 136*7ff178cdSJimmy Vetayases * Now, determine the IRM pool parameters based on the 137*7ff178cdSJimmy Vetayases * info from APIX module and global config variables. 138*7ff178cdSJimmy Vetayases */ 139*7ff178cdSJimmy Vetayases 140*7ff178cdSJimmy Vetayases /* 141*7ff178cdSJimmy Vetayases * apix_ncpus shows all the CPUs present in the 142*7ff178cdSJimmy Vetayases * system but not all of them may have been enabled 143*7ff178cdSJimmy Vetayases * (i.e. mp_startup() may not have been called yet). 144*7ff178cdSJimmy Vetayases * So, use ncpus for IRM pool creation. 145*7ff178cdSJimmy Vetayases */ 146*7ff178cdSJimmy Vetayases if (apix_irminfo.apix_ncpus > ncpus) 147*7ff178cdSJimmy Vetayases apix_irminfo.apix_ncpus = ncpus; 148*7ff178cdSJimmy Vetayases 149*7ff178cdSJimmy Vetayases /* apply the CPU factor if possible */ 150*7ff178cdSJimmy Vetayases if ((apix_irm_cpu_factor > 0) && 151*7ff178cdSJimmy Vetayases (apix_irminfo.apix_ncpus > apix_irm_cpu_factor)) { 152*7ff178cdSJimmy Vetayases cpus_used = apix_irminfo.apix_ncpus - apix_irm_cpu_factor; 153*7ff178cdSJimmy Vetayases apix_irm_cpu_factor_available = apix_irm_cpu_factor; 154*7ff178cdSJimmy Vetayases } else { 155*7ff178cdSJimmy Vetayases cpus_used = apix_irminfo.apix_ncpus; 156*7ff178cdSJimmy Vetayases } 157*7ff178cdSJimmy Vetayases apix_irm_cpus_used = apix_irm_max_cpus = cpus_used; 158*7ff178cdSJimmy Vetayases 159*7ff178cdSJimmy Vetayases APIX_IRM_DEBUG((CE_CONT, 160*7ff178cdSJimmy Vetayases "apix_irm_init: %d CPUs used for IRM pool size", cpus_used)); 161*7ff178cdSJimmy Vetayases 162*7ff178cdSJimmy Vetayases total_avail_vectors = cpus_used * apix_irminfo.apix_per_cpu_vectors - 163*7ff178cdSJimmy Vetayases apix_irminfo.apix_vectors_allocated; 164*7ff178cdSJimmy Vetayases 165*7ff178cdSJimmy Vetayases apix_irm_fixed_intr_vectors_used = apix_irminfo.apix_vectors_allocated; 166*7ff178cdSJimmy Vetayases 167*7ff178cdSJimmy Vetayases if (total_avail_vectors <= 0) { 168*7ff178cdSJimmy Vetayases /* can not determine pool size */ 169*7ff178cdSJimmy Vetayases APIX_IRM_DEBUG((CE_NOTE, 170*7ff178cdSJimmy Vetayases "apix_irm_init: can not determine pool size")); 171*7ff178cdSJimmy Vetayases return; 172*7ff178cdSJimmy Vetayases } 173*7ff178cdSJimmy Vetayases 174*7ff178cdSJimmy Vetayases /* adjust the pool size as per the global config variable */ 175*7ff178cdSJimmy Vetayases if ((apix_system_max_vectors > 0) && 176*7ff178cdSJimmy Vetayases (apix_system_max_vectors < total_avail_vectors)) 177*7ff178cdSJimmy Vetayases total_avail_vectors = apix_system_max_vectors; 178*7ff178cdSJimmy Vetayases 179*7ff178cdSJimmy Vetayases /* pre-reserve vectors (i.e. local cache) for FIXED type if needed */ 180*7ff178cdSJimmy Vetayases if (apix_irm_reserve_fixed_vectors != 0) { 181*7ff178cdSJimmy Vetayases cache_size = apix_irm_reserve_fixed_vectors; 182*7ff178cdSJimmy Vetayases if ((cache_size == -1) || 183*7ff178cdSJimmy Vetayases (cache_size > apix_irminfo.apix_ioapic_max_vectors)) 184*7ff178cdSJimmy Vetayases cache_size = apix_irminfo.apix_ioapic_max_vectors; 185*7ff178cdSJimmy Vetayases total_avail_vectors -= cache_size; 186*7ff178cdSJimmy Vetayases apix_irm_cache_size = cache_size; 187*7ff178cdSJimmy Vetayases } 188*7ff178cdSJimmy Vetayases 189*7ff178cdSJimmy Vetayases if (total_avail_vectors <= 0) { 190*7ff178cdSJimmy Vetayases APIX_IRM_DEBUG((CE_NOTE, 191*7ff178cdSJimmy Vetayases "apix_irm_init: invalid config parameters!")); 192*7ff178cdSJimmy Vetayases return; 193*7ff178cdSJimmy Vetayases } 194*7ff178cdSJimmy Vetayases 195*7ff178cdSJimmy Vetayases /* IRM pool is used only for MSI/X interrupts */ 196*7ff178cdSJimmy Vetayases apix_irm_params.iparams_types = DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_MSIX; 197*7ff178cdSJimmy Vetayases apix_irm_params.iparams_total = total_avail_vectors; 198*7ff178cdSJimmy Vetayases 199*7ff178cdSJimmy Vetayases if (ndi_irm_create(dip, &apix_irm_params, 200*7ff178cdSJimmy Vetayases &apix_irm_pool_p) == NDI_SUCCESS) { 201*7ff178cdSJimmy Vetayases /* 202*7ff178cdSJimmy Vetayases * re-direct psm_intr_ops to intercept FIXED 203*7ff178cdSJimmy Vetayases * interrupt allocation requests. 204*7ff178cdSJimmy Vetayases */ 205*7ff178cdSJimmy Vetayases psm_intr_ops_saved = psm_intr_ops; 206*7ff178cdSJimmy Vetayases psm_intr_ops = apix_irm_intr_ops; 207*7ff178cdSJimmy Vetayases /* 208*7ff178cdSJimmy Vetayases * re-direct psm_enable_intr()/psm_disable_intr() to 209*7ff178cdSJimmy Vetayases * intercept CPU offline/online requests. 210*7ff178cdSJimmy Vetayases */ 211*7ff178cdSJimmy Vetayases psm_disable_intr_saved = psm_disable_intr; 212*7ff178cdSJimmy Vetayases psm_enable_intr_saved = psm_enable_intr; 213*7ff178cdSJimmy Vetayases psm_enable_intr = apix_irm_enable_intr; 214*7ff178cdSJimmy Vetayases psm_disable_intr = apix_irm_disable_intr; 215*7ff178cdSJimmy Vetayases 216*7ff178cdSJimmy Vetayases mutex_init(&apix_irm_lock, NULL, MUTEX_DRIVER, NULL); 217*7ff178cdSJimmy Vetayases 218*7ff178cdSJimmy Vetayases /* 219*7ff178cdSJimmy Vetayases * Set default alloc limit for non-IRM drivers 220*7ff178cdSJimmy Vetayases * to DDI_MIN_MSIX_ALLOC (currently defined as 8). 221*7ff178cdSJimmy Vetayases * 222*7ff178cdSJimmy Vetayases * NOTE: This is done here so that the limit of 8 vectors 223*7ff178cdSJimmy Vetayases * is applicable only with APIX module. For the old pcplusmp 224*7ff178cdSJimmy Vetayases * implementation, the current default of 2 (i.e 225*7ff178cdSJimmy Vetayases * DDI_DEFAULT_MSIX_ALLOC) is retained. 226*7ff178cdSJimmy Vetayases */ 227*7ff178cdSJimmy Vetayases if (ddi_msix_alloc_limit < DDI_MIN_MSIX_ALLOC) 228*7ff178cdSJimmy Vetayases ddi_msix_alloc_limit = DDI_MIN_MSIX_ALLOC; 229*7ff178cdSJimmy Vetayases } else { 230*7ff178cdSJimmy Vetayases APIX_IRM_DEBUG((CE_NOTE, 231*7ff178cdSJimmy Vetayases "apix_irm_init: ndi_irm_create() failed")); 232*7ff178cdSJimmy Vetayases apix_irm_pool_p = NULL; 233*7ff178cdSJimmy Vetayases } 234*7ff178cdSJimmy Vetayases } 235*7ff178cdSJimmy Vetayases 236*7ff178cdSJimmy Vetayases /* 237*7ff178cdSJimmy Vetayases * Check if the PSM module is "APIX" type which supports IRM feature. 238*7ff178cdSJimmy Vetayases * Returns 0 if it is not an APIX module. 239*7ff178cdSJimmy Vetayases */ 240*7ff178cdSJimmy Vetayases static int 241*7ff178cdSJimmy Vetayases apix_irm_chk_apix(void) 242*7ff178cdSJimmy Vetayases { 243*7ff178cdSJimmy Vetayases ddi_intr_handle_impl_t info_hdl; 244*7ff178cdSJimmy Vetayases apic_get_type_t type_info; 245*7ff178cdSJimmy Vetayases 246*7ff178cdSJimmy Vetayases if (!psm_intr_ops) 247*7ff178cdSJimmy Vetayases return (0); 248*7ff178cdSJimmy Vetayases 249*7ff178cdSJimmy Vetayases bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t)); 250*7ff178cdSJimmy Vetayases info_hdl.ih_private = &type_info; 251*7ff178cdSJimmy Vetayases if (((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, 252*7ff178cdSJimmy Vetayases NULL)) != PSM_SUCCESS) { 253*7ff178cdSJimmy Vetayases /* unknown type; assume not an APIX module */ 254*7ff178cdSJimmy Vetayases return (0); 255*7ff178cdSJimmy Vetayases } 256*7ff178cdSJimmy Vetayases if (strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) 257*7ff178cdSJimmy Vetayases return (1); 258*7ff178cdSJimmy Vetayases else 259*7ff178cdSJimmy Vetayases return (0); 260*7ff178cdSJimmy Vetayases } 261*7ff178cdSJimmy Vetayases 262*7ff178cdSJimmy Vetayases /* 263*7ff178cdSJimmy Vetayases * This function intercepts PSM_INTR_OP_* requests to deal with 264*7ff178cdSJimmy Vetayases * IRM pool maintainance for FIXED type interrupts. The following 265*7ff178cdSJimmy Vetayases * commands are intercepted and the rest are simply passed back to 266*7ff178cdSJimmy Vetayases * the original psm_intr_ops function: 267*7ff178cdSJimmy Vetayases * PSM_INTR_OP_ALLOC_VECTORS 268*7ff178cdSJimmy Vetayases * PSM_INTR_OP_FREE_VECTORS 269*7ff178cdSJimmy Vetayases * Return value is either PSM_SUCCESS or PSM_FAILURE. 270*7ff178cdSJimmy Vetayases */ 271*7ff178cdSJimmy Vetayases int 272*7ff178cdSJimmy Vetayases apix_irm_intr_ops(dev_info_t *dip, ddi_intr_handle_impl_t *handle, 273*7ff178cdSJimmy Vetayases psm_intr_op_t op, int *result) 274*7ff178cdSJimmy Vetayases { 275*7ff178cdSJimmy Vetayases switch (op) { 276*7ff178cdSJimmy Vetayases case PSM_INTR_OP_ALLOC_VECTORS: 277*7ff178cdSJimmy Vetayases if (handle->ih_type == DDI_INTR_TYPE_FIXED) 278*7ff178cdSJimmy Vetayases return (apix_irm_alloc_fixed(dip, handle, result)); 279*7ff178cdSJimmy Vetayases else 280*7ff178cdSJimmy Vetayases break; 281*7ff178cdSJimmy Vetayases case PSM_INTR_OP_FREE_VECTORS: 282*7ff178cdSJimmy Vetayases if (handle->ih_type == DDI_INTR_TYPE_FIXED) 283*7ff178cdSJimmy Vetayases return (apix_irm_free_fixed(dip, handle, result)); 284*7ff178cdSJimmy Vetayases else 285*7ff178cdSJimmy Vetayases break; 286*7ff178cdSJimmy Vetayases default: 287*7ff178cdSJimmy Vetayases break; 288*7ff178cdSJimmy Vetayases } 289*7ff178cdSJimmy Vetayases 290*7ff178cdSJimmy Vetayases /* pass the request to APIX */ 291*7ff178cdSJimmy Vetayases return ((*psm_intr_ops_saved)(dip, handle, op, result)); 292*7ff178cdSJimmy Vetayases } 293*7ff178cdSJimmy Vetayases 294*7ff178cdSJimmy Vetayases /* 295*7ff178cdSJimmy Vetayases * Allocate a FIXED type interrupt. The procedure for this 296*7ff178cdSJimmy Vetayases * operation is as follows: 297*7ff178cdSJimmy Vetayases * 298*7ff178cdSJimmy Vetayases * 1) Check if this IRQ is shared (i.e. IRQ is already mapped 299*7ff178cdSJimmy Vetayases * and a vector has been already allocated). If so, then no 300*7ff178cdSJimmy Vetayases * new vector is needed and simply pass the request to APIX 301*7ff178cdSJimmy Vetayases * and return. 302*7ff178cdSJimmy Vetayases * 2) Check the local cache pool for an available vector. If 303*7ff178cdSJimmy Vetayases * the cache is not empty then take it from there and simply 304*7ff178cdSJimmy Vetayases * pass the request to APIX and return. 305*7ff178cdSJimmy Vetayases * 3) Otherwise, get a vector from the IRM pool by reducing the 306*7ff178cdSJimmy Vetayases * pool size by 1. If it is successful then pass the 307*7ff178cdSJimmy Vetayases * request to APIX module. Otherwise return PSM_FAILURE. 308*7ff178cdSJimmy Vetayases */ 309*7ff178cdSJimmy Vetayases int 310*7ff178cdSJimmy Vetayases apix_irm_alloc_fixed(dev_info_t *dip, ddi_intr_handle_impl_t *handle, 311*7ff178cdSJimmy Vetayases int *result) 312*7ff178cdSJimmy Vetayases { 313*7ff178cdSJimmy Vetayases int vector; 314*7ff178cdSJimmy Vetayases uint_t new_pool_size; 315*7ff178cdSJimmy Vetayases int ret; 316*7ff178cdSJimmy Vetayases 317*7ff178cdSJimmy Vetayases /* 318*7ff178cdSJimmy Vetayases * Check if this IRQ has been mapped (i.e. shared IRQ case) 319*7ff178cdSJimmy Vetayases * by doing PSM_INTR_OP_XLATE_VECTOR. 320*7ff178cdSJimmy Vetayases */ 321*7ff178cdSJimmy Vetayases ret = (*psm_intr_ops_saved)(dip, handle, PSM_INTR_OP_XLATE_VECTOR, 322*7ff178cdSJimmy Vetayases &vector); 323*7ff178cdSJimmy Vetayases if (ret == PSM_SUCCESS) { 324*7ff178cdSJimmy Vetayases APIX_IRM_DEBUG((CE_CONT, 325*7ff178cdSJimmy Vetayases "apix_irm_alloc_fixed: dip %p (%s) xlated vector 0x%x", 326*7ff178cdSJimmy Vetayases (void *)dip, ddi_driver_name(dip), vector)); 327*7ff178cdSJimmy Vetayases /* (1) mapping already exists; pass the request to PSM */ 328*7ff178cdSJimmy Vetayases return ((*psm_intr_ops_saved)(dip, handle, 329*7ff178cdSJimmy Vetayases PSM_INTR_OP_ALLOC_VECTORS, result)); 330*7ff178cdSJimmy Vetayases } 331*7ff178cdSJimmy Vetayases 332*7ff178cdSJimmy Vetayases /* check the local cache for an available vector */ 333*7ff178cdSJimmy Vetayases mutex_enter(&apix_irm_lock); 334*7ff178cdSJimmy Vetayases if (apix_irm_cache_size) { /* cache is not empty */ 335*7ff178cdSJimmy Vetayases --apix_irm_cache_size; 336*7ff178cdSJimmy Vetayases apix_irm_fixed_intr_vectors_used++; 337*7ff178cdSJimmy Vetayases mutex_exit(&apix_irm_lock); 338*7ff178cdSJimmy Vetayases /* (2) use the vector from the local cache */ 339*7ff178cdSJimmy Vetayases return ((*psm_intr_ops_saved)(dip, handle, 340*7ff178cdSJimmy Vetayases PSM_INTR_OP_ALLOC_VECTORS, result)); 341*7ff178cdSJimmy Vetayases } 342*7ff178cdSJimmy Vetayases 343*7ff178cdSJimmy Vetayases /* (3) get a vector from the IRM pool */ 344*7ff178cdSJimmy Vetayases 345*7ff178cdSJimmy Vetayases new_pool_size = apix_irm_params.iparams_total - 1; 346*7ff178cdSJimmy Vetayases 347*7ff178cdSJimmy Vetayases APIX_IRM_DEBUG((CE_CONT, "apix_irm_alloc_fixed: dip %p (%s) resize pool" 348*7ff178cdSJimmy Vetayases " from %x to %x\n", (void *)dip, ddi_driver_name(dip), 349*7ff178cdSJimmy Vetayases apix_irm_pool_p->ipool_totsz, new_pool_size)); 350*7ff178cdSJimmy Vetayases 351*7ff178cdSJimmy Vetayases if (ndi_irm_resize_pool(apix_irm_pool_p, new_pool_size) == 352*7ff178cdSJimmy Vetayases NDI_SUCCESS) { 353*7ff178cdSJimmy Vetayases /* update the pool size info */ 354*7ff178cdSJimmy Vetayases apix_irm_params.iparams_total = new_pool_size; 355*7ff178cdSJimmy Vetayases apix_irm_fixed_intr_vectors_used++; 356*7ff178cdSJimmy Vetayases mutex_exit(&apix_irm_lock); 357*7ff178cdSJimmy Vetayases return ((*psm_intr_ops_saved)(dip, handle, 358*7ff178cdSJimmy Vetayases PSM_INTR_OP_ALLOC_VECTORS, result)); 359*7ff178cdSJimmy Vetayases } 360*7ff178cdSJimmy Vetayases 361*7ff178cdSJimmy Vetayases mutex_exit(&apix_irm_lock); 362*7ff178cdSJimmy Vetayases 363*7ff178cdSJimmy Vetayases return (PSM_FAILURE); 364*7ff178cdSJimmy Vetayases } 365*7ff178cdSJimmy Vetayases 366*7ff178cdSJimmy Vetayases /* 367*7ff178cdSJimmy Vetayases * Free up the FIXED type interrupt. 368*7ff178cdSJimmy Vetayases * 369*7ff178cdSJimmy Vetayases * 1) If it is a shared vector then simply pass the request to 370*7ff178cdSJimmy Vetayases * APIX and return. 371*7ff178cdSJimmy Vetayases * 2) Otherwise, if apix_irm_free_fixed_vector is not set then add the 372*7ff178cdSJimmy Vetayases * vector back to the IRM pool. Otherwise, keep it in the local cache. 373*7ff178cdSJimmy Vetayases */ 374*7ff178cdSJimmy Vetayases int 375*7ff178cdSJimmy Vetayases apix_irm_free_fixed(dev_info_t *dip, ddi_intr_handle_impl_t *handle, 376*7ff178cdSJimmy Vetayases int *result) 377*7ff178cdSJimmy Vetayases { 378*7ff178cdSJimmy Vetayases int shared; 379*7ff178cdSJimmy Vetayases int ret; 380*7ff178cdSJimmy Vetayases uint_t new_pool_size; 381*7ff178cdSJimmy Vetayases 382*7ff178cdSJimmy Vetayases /* check if it is a shared vector */ 383*7ff178cdSJimmy Vetayases ret = (*psm_intr_ops_saved)(dip, handle, 384*7ff178cdSJimmy Vetayases PSM_INTR_OP_GET_SHARED, &shared); 385*7ff178cdSJimmy Vetayases 386*7ff178cdSJimmy Vetayases if ((ret == PSM_SUCCESS) && (shared > 0)) { 387*7ff178cdSJimmy Vetayases /* (1) it is a shared vector; simply pass the request */ 388*7ff178cdSJimmy Vetayases APIX_IRM_DEBUG((CE_CONT, "apix_irm_free_fixed: dip %p (%s) " 389*7ff178cdSJimmy Vetayases "shared %d\n", (void *)dip, ddi_driver_name(dip), shared)); 390*7ff178cdSJimmy Vetayases return ((*psm_intr_ops_saved)(dip, handle, 391*7ff178cdSJimmy Vetayases PSM_INTR_OP_FREE_VECTORS, result)); 392*7ff178cdSJimmy Vetayases } 393*7ff178cdSJimmy Vetayases 394*7ff178cdSJimmy Vetayases ret = (*psm_intr_ops_saved)(dip, handle, 395*7ff178cdSJimmy Vetayases PSM_INTR_OP_FREE_VECTORS, result); 396*7ff178cdSJimmy Vetayases 397*7ff178cdSJimmy Vetayases if (ret == PSM_SUCCESS) { 398*7ff178cdSJimmy Vetayases mutex_enter(&apix_irm_lock); 399*7ff178cdSJimmy Vetayases if (apix_irm_free_fixed_vector) { 400*7ff178cdSJimmy Vetayases /* (2) add the vector back to IRM pool */ 401*7ff178cdSJimmy Vetayases new_pool_size = apix_irm_params.iparams_total + 1; 402*7ff178cdSJimmy Vetayases APIX_IRM_DEBUG((CE_CONT, "apix_irm_free_fixed: " 403*7ff178cdSJimmy Vetayases "dip %p (%s) resize pool from %x to %x\n", 404*7ff178cdSJimmy Vetayases (void *)dip, ddi_driver_name(dip), 405*7ff178cdSJimmy Vetayases apix_irm_pool_p->ipool_totsz, new_pool_size)); 406*7ff178cdSJimmy Vetayases if (ndi_irm_resize_pool(apix_irm_pool_p, 407*7ff178cdSJimmy Vetayases new_pool_size) == NDI_SUCCESS) { 408*7ff178cdSJimmy Vetayases /* update the pool size info */ 409*7ff178cdSJimmy Vetayases apix_irm_params.iparams_total = new_pool_size; 410*7ff178cdSJimmy Vetayases } else { 411*7ff178cdSJimmy Vetayases cmn_err(CE_NOTE, 412*7ff178cdSJimmy Vetayases "apix_irm_free_fixed: failed to add" 413*7ff178cdSJimmy Vetayases " a vector to IRM pool"); 414*7ff178cdSJimmy Vetayases } 415*7ff178cdSJimmy Vetayases } else { 416*7ff178cdSJimmy Vetayases /* keep the vector in the local cache */ 417*7ff178cdSJimmy Vetayases apix_irm_cache_size += 1; 418*7ff178cdSJimmy Vetayases } 419*7ff178cdSJimmy Vetayases apix_irm_fixed_intr_vectors_used--; 420*7ff178cdSJimmy Vetayases mutex_exit(&apix_irm_lock); 421*7ff178cdSJimmy Vetayases } 422*7ff178cdSJimmy Vetayases 423*7ff178cdSJimmy Vetayases return (ret); 424*7ff178cdSJimmy Vetayases } 425*7ff178cdSJimmy Vetayases 426*7ff178cdSJimmy Vetayases /* 427*7ff178cdSJimmy Vetayases * Disable the CPU for interrupts. It is assumed that this is called to 428*7ff178cdSJimmy Vetayases * offline/disable the CPU so that no interrupts are allocated on 429*7ff178cdSJimmy Vetayases * that CPU. For IRM perspective, the interrupt vectors on this 430*7ff178cdSJimmy Vetayases * CPU are to be excluded for any allocations. 431*7ff178cdSJimmy Vetayases * 432*7ff178cdSJimmy Vetayases * If APIX module is successful in migrating all the vectors 433*7ff178cdSJimmy Vetayases * from this CPU then reduce the IRM pool size to exclude the 434*7ff178cdSJimmy Vetayases * interrupt vectors for that CPU. 435*7ff178cdSJimmy Vetayases */ 436*7ff178cdSJimmy Vetayases int 437*7ff178cdSJimmy Vetayases apix_irm_disable_intr(processorid_t id) 438*7ff178cdSJimmy Vetayases { 439*7ff178cdSJimmy Vetayases uint_t new_pool_size; 440*7ff178cdSJimmy Vetayases 441*7ff178cdSJimmy Vetayases /* Interrupt disabling for Suspend/Resume */ 442*7ff178cdSJimmy Vetayases if (apic_cpus[id].aci_status & APIC_CPU_SUSPEND) 443*7ff178cdSJimmy Vetayases return ((*psm_disable_intr_saved)(id)); 444*7ff178cdSJimmy Vetayases 445*7ff178cdSJimmy Vetayases mutex_enter(&apix_irm_lock); 446*7ff178cdSJimmy Vetayases /* 447*7ff178cdSJimmy Vetayases * Don't remove the CPU from the IRM pool if we have CPU factor 448*7ff178cdSJimmy Vetayases * available. 449*7ff178cdSJimmy Vetayases */ 450*7ff178cdSJimmy Vetayases if ((apix_irm_cpu_factor > 0) && (apix_irm_cpu_factor_available > 0)) { 451*7ff178cdSJimmy Vetayases apix_irm_cpu_factor_available--; 452*7ff178cdSJimmy Vetayases } else { 453*7ff178cdSJimmy Vetayases /* can't disable if there is only one CPU used */ 454*7ff178cdSJimmy Vetayases if (apix_irm_cpus_used == 1) { 455*7ff178cdSJimmy Vetayases mutex_exit(&apix_irm_lock); 456*7ff178cdSJimmy Vetayases return (PSM_FAILURE); 457*7ff178cdSJimmy Vetayases } 458*7ff178cdSJimmy Vetayases /* Calculate the new size for the IRM pool */ 459*7ff178cdSJimmy Vetayases new_pool_size = apix_irm_params.iparams_total - 460*7ff178cdSJimmy Vetayases apix_irminfo.apix_per_cpu_vectors; 461*7ff178cdSJimmy Vetayases 462*7ff178cdSJimmy Vetayases /* Apply the max. limit */ 463*7ff178cdSJimmy Vetayases if (apix_system_max_vectors > 0) { 464*7ff178cdSJimmy Vetayases uint_t max; 465*7ff178cdSJimmy Vetayases 466*7ff178cdSJimmy Vetayases max = apix_system_max_vectors - 467*7ff178cdSJimmy Vetayases apix_irm_fixed_intr_vectors_used - 468*7ff178cdSJimmy Vetayases apix_irm_cache_size; 469*7ff178cdSJimmy Vetayases 470*7ff178cdSJimmy Vetayases new_pool_size = MIN(new_pool_size, max); 471*7ff178cdSJimmy Vetayases } 472*7ff178cdSJimmy Vetayases 473*7ff178cdSJimmy Vetayases if (new_pool_size == 0) { 474*7ff178cdSJimmy Vetayases cmn_err(CE_WARN, "Invalid pool size 0 with " 475*7ff178cdSJimmy Vetayases "apix_system_max_vectors = %d", 476*7ff178cdSJimmy Vetayases apix_system_max_vectors); 477*7ff178cdSJimmy Vetayases mutex_exit(&apix_irm_lock); 478*7ff178cdSJimmy Vetayases return (PSM_FAILURE); 479*7ff178cdSJimmy Vetayases } 480*7ff178cdSJimmy Vetayases 481*7ff178cdSJimmy Vetayases if (new_pool_size != apix_irm_params.iparams_total) { 482*7ff178cdSJimmy Vetayases /* remove the CPU from the IRM pool */ 483*7ff178cdSJimmy Vetayases if (ndi_irm_resize_pool(apix_irm_pool_p, 484*7ff178cdSJimmy Vetayases new_pool_size) != NDI_SUCCESS) { 485*7ff178cdSJimmy Vetayases mutex_exit(&apix_irm_lock); 486*7ff178cdSJimmy Vetayases APIX_IRM_DEBUG((CE_NOTE, 487*7ff178cdSJimmy Vetayases "apix_irm_disable_intr: failed to resize" 488*7ff178cdSJimmy Vetayases " the IRM pool")); 489*7ff178cdSJimmy Vetayases return (PSM_FAILURE); 490*7ff178cdSJimmy Vetayases } 491*7ff178cdSJimmy Vetayases /* update the pool size info */ 492*7ff178cdSJimmy Vetayases apix_irm_params.iparams_total = new_pool_size; 493*7ff178cdSJimmy Vetayases } 494*7ff178cdSJimmy Vetayases 495*7ff178cdSJimmy Vetayases /* decrement the CPU count used by IRM pool */ 496*7ff178cdSJimmy Vetayases apix_irm_cpus_used--; 497*7ff178cdSJimmy Vetayases } 498*7ff178cdSJimmy Vetayases 499*7ff178cdSJimmy Vetayases /* 500*7ff178cdSJimmy Vetayases * Now, disable the CPU for interrupts. 501*7ff178cdSJimmy Vetayases */ 502*7ff178cdSJimmy Vetayases if ((*psm_disable_intr_saved)(id) != PSM_SUCCESS) { 503*7ff178cdSJimmy Vetayases APIX_IRM_DEBUG((CE_NOTE, 504*7ff178cdSJimmy Vetayases "apix_irm_disable_intr: failed to disable CPU interrupts" 505*7ff178cdSJimmy Vetayases " for CPU#%d", id)); 506*7ff178cdSJimmy Vetayases mutex_exit(&apix_irm_lock); 507*7ff178cdSJimmy Vetayases return (PSM_FAILURE); 508*7ff178cdSJimmy Vetayases } 509*7ff178cdSJimmy Vetayases /* decrement the CPU count enabled for interrupts */ 510*7ff178cdSJimmy Vetayases apix_irm_max_cpus--; 511*7ff178cdSJimmy Vetayases mutex_exit(&apix_irm_lock); 512*7ff178cdSJimmy Vetayases return (PSM_SUCCESS); 513*7ff178cdSJimmy Vetayases } 514*7ff178cdSJimmy Vetayases 515*7ff178cdSJimmy Vetayases /* 516*7ff178cdSJimmy Vetayases * Enable the CPU for interrupts. It is assumed that this function is 517*7ff178cdSJimmy Vetayases * called to enable/online the CPU so that interrupts could be assigned 518*7ff178cdSJimmy Vetayases * to it. If successful, add available vectors for that CPU to the IRM 519*7ff178cdSJimmy Vetayases * pool if apix_irm_cpu_factor is already satisfied. 520*7ff178cdSJimmy Vetayases */ 521*7ff178cdSJimmy Vetayases void 522*7ff178cdSJimmy Vetayases apix_irm_enable_intr(processorid_t id) 523*7ff178cdSJimmy Vetayases { 524*7ff178cdSJimmy Vetayases uint_t new_pool_size; 525*7ff178cdSJimmy Vetayases 526*7ff178cdSJimmy Vetayases /* Interrupt enabling for Suspend/Resume */ 527*7ff178cdSJimmy Vetayases if (apic_cpus[id].aci_status & APIC_CPU_SUSPEND) { 528*7ff178cdSJimmy Vetayases (*psm_enable_intr_saved)(id); 529*7ff178cdSJimmy Vetayases return; 530*7ff178cdSJimmy Vetayases } 531*7ff178cdSJimmy Vetayases 532*7ff178cdSJimmy Vetayases mutex_enter(&apix_irm_lock); 533*7ff178cdSJimmy Vetayases 534*7ff178cdSJimmy Vetayases /* enable the CPU for interrupts */ 535*7ff178cdSJimmy Vetayases (*psm_enable_intr_saved)(id); 536*7ff178cdSJimmy Vetayases 537*7ff178cdSJimmy Vetayases /* increment the number of CPUs enabled for interrupts */ 538*7ff178cdSJimmy Vetayases apix_irm_max_cpus++; 539*7ff178cdSJimmy Vetayases 540*7ff178cdSJimmy Vetayases ASSERT(apix_irminfo.apix_per_cpu_vectors > 0); 541*7ff178cdSJimmy Vetayases 542*7ff178cdSJimmy Vetayases /* 543*7ff178cdSJimmy Vetayases * Check if the apix_irm_cpu_factor is satisfied before. 544*7ff178cdSJimmy Vetayases * If satisfied, add the CPU to IRM pool. 545*7ff178cdSJimmy Vetayases */ 546*7ff178cdSJimmy Vetayases if ((apix_irm_cpu_factor > 0) && 547*7ff178cdSJimmy Vetayases (apix_irm_cpu_factor_available < apix_irm_cpu_factor)) { 548*7ff178cdSJimmy Vetayases /* 549*7ff178cdSJimmy Vetayases * Don't add the CPU to the IRM pool. Just update 550*7ff178cdSJimmy Vetayases * the available CPU factor. 551*7ff178cdSJimmy Vetayases */ 552*7ff178cdSJimmy Vetayases apix_irm_cpu_factor_available++; 553*7ff178cdSJimmy Vetayases mutex_exit(&apix_irm_lock); 554*7ff178cdSJimmy Vetayases return; 555*7ff178cdSJimmy Vetayases } 556*7ff178cdSJimmy Vetayases 557*7ff178cdSJimmy Vetayases /* 558*7ff178cdSJimmy Vetayases * Add the CPU to the IRM pool. 559*7ff178cdSJimmy Vetayases */ 560*7ff178cdSJimmy Vetayases 561*7ff178cdSJimmy Vetayases /* increment the CPU count used by IRM */ 562*7ff178cdSJimmy Vetayases apix_irm_cpus_used++; 563*7ff178cdSJimmy Vetayases 564*7ff178cdSJimmy Vetayases /* Calculate the new pool size */ 565*7ff178cdSJimmy Vetayases new_pool_size = apix_irm_params.iparams_total + 566*7ff178cdSJimmy Vetayases apix_irminfo.apix_per_cpu_vectors; 567*7ff178cdSJimmy Vetayases 568*7ff178cdSJimmy Vetayases /* Apply the max. limit */ 569*7ff178cdSJimmy Vetayases if (apix_system_max_vectors > 0) { 570*7ff178cdSJimmy Vetayases uint_t max; 571*7ff178cdSJimmy Vetayases 572*7ff178cdSJimmy Vetayases max = apix_system_max_vectors - 573*7ff178cdSJimmy Vetayases apix_irm_fixed_intr_vectors_used - 574*7ff178cdSJimmy Vetayases apix_irm_cache_size; 575*7ff178cdSJimmy Vetayases 576*7ff178cdSJimmy Vetayases new_pool_size = MIN(new_pool_size, max); 577*7ff178cdSJimmy Vetayases } 578*7ff178cdSJimmy Vetayases if (new_pool_size == apix_irm_params.iparams_total) { 579*7ff178cdSJimmy Vetayases /* no change to pool size */ 580*7ff178cdSJimmy Vetayases mutex_exit(&apix_irm_lock); 581*7ff178cdSJimmy Vetayases return; 582*7ff178cdSJimmy Vetayases } 583*7ff178cdSJimmy Vetayases if (new_pool_size < apix_irm_params.iparams_total) { 584*7ff178cdSJimmy Vetayases cmn_err(CE_WARN, "new_pool_size %d is inconsistent " 585*7ff178cdSJimmy Vetayases "with irm_params.iparams_total %d", 586*7ff178cdSJimmy Vetayases new_pool_size, apix_irm_params.iparams_total); 587*7ff178cdSJimmy Vetayases mutex_exit(&apix_irm_lock); 588*7ff178cdSJimmy Vetayases return; 589*7ff178cdSJimmy Vetayases } 590*7ff178cdSJimmy Vetayases 591*7ff178cdSJimmy Vetayases (void) ndi_irm_resize_pool(apix_irm_pool_p, new_pool_size); 592*7ff178cdSJimmy Vetayases 593*7ff178cdSJimmy Vetayases /* update the pool size info */ 594*7ff178cdSJimmy Vetayases apix_irm_params.iparams_total = new_pool_size; 595*7ff178cdSJimmy Vetayases 596*7ff178cdSJimmy Vetayases mutex_exit(&apix_irm_lock); 597*7ff178cdSJimmy Vetayases } 598