xref: /titanic_52/usr/src/uts/i86pc/io/apix/apix_irm.c (revision 7ff178cd8db129d385d3177eb20744d3b6efc59b)
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