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
apix_irm_init(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
apix_irm_chk_apix(void)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
apix_irm_intr_ops(dev_info_t * dip,ddi_intr_handle_impl_t * handle,psm_intr_op_t op,int * result)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
apix_irm_alloc_fixed(dev_info_t * dip,ddi_intr_handle_impl_t * handle,int * result)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
apix_irm_free_fixed(dev_info_t * dip,ddi_intr_handle_impl_t * handle,int * result)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
apix_irm_disable_intr(processorid_t id)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
apix_irm_enable_intr(processorid_t id)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