/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <sys/sysmacros.h>
#include <sys/ddi_impldefs.h>
#include <sys/psm_types.h>
#include <sys/smp_impldefs.h>
#include <sys/processor.h>
#include <sys/apix_irm_impl.h>
/* global variable for static default limit for non-IRM drivers */
extern int ddi_msix_alloc_limit;
/* Extern declarations */
psm_intr_op_t, int *);
/*
* Global variables for IRM pool configuration:
*
* (1) apix_system_max_vectors -- this would limit the maximum
* number of interrupt vectors that will be made avilable
* to the device drivers. The default value (-1) indicates
* that all the available vectors could be used.
*
* (2) apix_irm_cpu_factor -- This would specify the number of CPUs that
* should be excluded from the global IRM pool of interrupt vectors.
* By default this would be zero, so vectors from all the CPUs
* present will be factored into the IRM pool.
*
* (3) apix_irm_reserve_fixed_vectors -- This would specify the number
* of vectors that should be reserved for FIXED type interrupts and
* exclude them from the IRM pool. The value can be one of the
* following:
* 0 - no reservation (default)
* <n> - a positive number for the reserved cache
* -1 - reserve the maximum needed
*
* (4) apix_irm_free_fixed_vectors -- This flag specifies if the
* vectors for FIXED type should be freed and added back
* to the IRM pool when ddi_intr_free() is called. The default
* is to add it back to the pool.
*/
int apix_irm_cpu_factor = 0;
int apix_irm_reserve_fixed_vectors = 0;
/* info from APIX module for IRM configuration */
int apix_irm_cpu_factor_available = 0;
int apix_irm_max_cpus = 0;
int apix_irm_cpus_used = 0;
extern int ncpus;
static int apix_irm_chk_apix();
/*
* Initilaize IRM pool for APIC interrupts if the PSM module
* is of APIX type. This should be called only after PSM module
* is loaded and APIC interrupt system is initialized.
*/
void
apix_irm_init(void)
{
int total_avail_vectors;
int cpus_used;
int cache_size;
/* nothing to do if IRM is disabled */
if (!irm_enable)
return;
/*
* Use root devinfo node to associate the IRM pool with it
* as the pool is global to the system.
*/
dip = ddi_root_node();
/*
* Check if PSM module is initialized and it is APIX
* module (which supports IRM functionality).
*/
/* not an APIX module */
"apix_irm_init: APIX module not present"));
return;
}
/*
* Now, determine the IRM pool parameters based on the
* info from APIX module and global config variables.
*/
/*
* apix_ncpus shows all the CPUs present in the
* system but not all of them may have been enabled
* (i.e. mp_startup() may not have been called yet).
* So, use ncpus for IRM pool creation.
*/
/* apply the CPU factor if possible */
if ((apix_irm_cpu_factor > 0) &&
} else {
}
"apix_irm_init: %d CPUs used for IRM pool size", cpus_used));
if (total_avail_vectors <= 0) {
/* can not determine pool size */
"apix_irm_init: can not determine pool size"));
return;
}
/* adjust the pool size as per the global config variable */
if ((apix_system_max_vectors > 0) &&
/* pre-reserve vectors (i.e. local cache) for FIXED type if needed */
if (apix_irm_reserve_fixed_vectors != 0) {
if ((cache_size == -1) ||
}
if (total_avail_vectors <= 0) {
"apix_irm_init: invalid config parameters!"));
return;
}
/* IRM pool is used only for MSI/X interrupts */
&apix_irm_pool_p) == NDI_SUCCESS) {
/*
* re-direct psm_intr_ops to intercept FIXED
* interrupt allocation requests.
*/
/*
* re-direct psm_enable_intr()/psm_disable_intr() to
*/
/*
* Set default alloc limit for non-IRM drivers
* to DDI_MIN_MSIX_ALLOC (currently defined as 8).
*
* NOTE: This is done here so that the limit of 8 vectors
* is applicable only with APIX module. For the old pcplusmp
* implementation, the current default of 2 (i.e
* DDI_DEFAULT_MSIX_ALLOC) is retained.
*/
} else {
"apix_irm_init: ndi_irm_create() failed"));
}
}
/*
* Check if the PSM module is "APIX" type which supports IRM feature.
* Returns 0 if it is not an APIX module.
*/
static int
apix_irm_chk_apix(void)
{
if (!psm_intr_ops)
return (0);
NULL)) != PSM_SUCCESS) {
/* unknown type; assume not an APIX module */
return (0);
}
return (1);
else
return (0);
}
/*
* This function intercepts PSM_INTR_OP_* requests to deal with
* IRM pool maintainance for FIXED type interrupts. The following
* commands are intercepted and the rest are simply passed back to
* the original psm_intr_ops function:
* PSM_INTR_OP_ALLOC_VECTORS
* PSM_INTR_OP_FREE_VECTORS
* Return value is either PSM_SUCCESS or PSM_FAILURE.
*/
int
{
switch (op) {
else
break;
case PSM_INTR_OP_FREE_VECTORS:
else
break;
default:
break;
}
/* pass the request to APIX */
}
/*
* Allocate a FIXED type interrupt. The procedure for this
* operation is as follows:
*
* 1) Check if this IRQ is shared (i.e. IRQ is already mapped
* and a vector has been already allocated). If so, then no
* new vector is needed and simply pass the request to APIX
* and return.
* 2) Check the local cache pool for an available vector. If
* the cache is not empty then take it from there and simply
* pass the request to APIX and return.
* 3) Otherwise, get a vector from the IRM pool by reducing the
* pool size by 1. If it is successful then pass the
* request to APIX module. Otherwise return PSM_FAILURE.
*/
int
int *result)
{
int vector;
int ret;
/*
* Check if this IRQ has been mapped (i.e. shared IRQ case)
* by doing PSM_INTR_OP_XLATE_VECTOR.
*/
&vector);
if (ret == PSM_SUCCESS) {
"apix_irm_alloc_fixed: dip %p (%s) xlated vector 0x%x",
/* (1) mapping already exists; pass the request to PSM */
}
/* check the local cache for an available vector */
if (apix_irm_cache_size) { /* cache is not empty */
/* (2) use the vector from the local cache */
}
/* (3) get a vector from the IRM pool */
NDI_SUCCESS) {
/* update the pool size info */
}
return (PSM_FAILURE);
}
/*
* Free up the FIXED type interrupt.
*
* 1) If it is a shared vector then simply pass the request to
* APIX and return.
* 2) Otherwise, if apix_irm_free_fixed_vector is not set then add the
* vector back to the IRM pool. Otherwise, keep it in the local cache.
*/
int
int *result)
{
int shared;
int ret;
/* check if it is a shared vector */
/* (1) it is a shared vector; simply pass the request */
}
if (ret == PSM_SUCCESS) {
if (apix_irm_free_fixed_vector) {
/* (2) add the vector back to IRM pool */
"dip %p (%s) resize pool from %x to %x\n",
new_pool_size) == NDI_SUCCESS) {
/* update the pool size info */
} else {
"apix_irm_free_fixed: failed to add"
" a vector to IRM pool");
}
} else {
/* keep the vector in the local cache */
apix_irm_cache_size += 1;
}
}
return (ret);
}
/*
* Disable the CPU for interrupts. It is assumed that this is called to
* that CPU. For IRM perspective, the interrupt vectors on this
* CPU are to be excluded for any allocations.
*
* If APIX module is successful in migrating all the vectors
* from this CPU then reduce the IRM pool size to exclude the
* interrupt vectors for that CPU.
*/
int
{
return ((*psm_disable_intr_saved)(id));
/*
* Don't remove the CPU from the IRM pool if we have CPU factor
* available.
*/
if ((apix_irm_cpu_factor > 0) && (apix_irm_cpu_factor_available > 0)) {
} else {
/* can't disable if there is only one CPU used */
if (apix_irm_cpus_used == 1) {
return (PSM_FAILURE);
}
/* Calculate the new size for the IRM pool */
/* Apply the max. limit */
if (apix_system_max_vectors > 0) {
}
if (new_pool_size == 0) {
"apix_system_max_vectors = %d",
return (PSM_FAILURE);
}
/* remove the CPU from the IRM pool */
new_pool_size) != NDI_SUCCESS) {
"apix_irm_disable_intr: failed to resize"
" the IRM pool"));
return (PSM_FAILURE);
}
/* update the pool size info */
}
/* decrement the CPU count used by IRM pool */
}
/*
* Now, disable the CPU for interrupts.
*/
"apix_irm_disable_intr: failed to disable CPU interrupts"
" for CPU#%d", id));
return (PSM_FAILURE);
}
/* decrement the CPU count enabled for interrupts */
return (PSM_SUCCESS);
}
/*
* Enable the CPU for interrupts. It is assumed that this function is
* to it. If successful, add available vectors for that CPU to the IRM
* pool if apix_irm_cpu_factor is already satisfied.
*/
void
{
(*psm_enable_intr_saved)(id);
return;
}
/* enable the CPU for interrupts */
(*psm_enable_intr_saved)(id);
/* increment the number of CPUs enabled for interrupts */
/*
* Check if the apix_irm_cpu_factor is satisfied before.
* If satisfied, add the CPU to IRM pool.
*/
if ((apix_irm_cpu_factor > 0) &&
/*
* Don't add the CPU to the IRM pool. Just update
* the available CPU factor.
*/
return;
}
/*
* Add the CPU to the IRM pool.
*/
/* increment the CPU count used by IRM */
/* Calculate the new pool size */
/* Apply the max. limit */
if (apix_system_max_vectors > 0) {
}
/* no change to pool size */
return;
}
"with irm_params.iparams_total %d",
return;
}
/* update the pool size info */
}