xref: /onnv-gate/usr/src/uts/sun4/io/ivintr.c (revision 2973)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*2973Sgovinda  * Common Development and Distribution License (the "License").
6*2973Sgovinda  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*2973Sgovinda  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * Interrupt Vector Table Configuration
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
32*2973Sgovinda #include <sys/types.h>
330Sstevel@tonic-gate #include <sys/cpuvar.h>
340Sstevel@tonic-gate #include <sys/ivintr.h>
350Sstevel@tonic-gate #include <sys/intreg.h>
360Sstevel@tonic-gate #include <sys/cmn_err.h>
370Sstevel@tonic-gate #include <sys/privregs.h>
380Sstevel@tonic-gate #include <sys/sunddi.h>
390Sstevel@tonic-gate 
40*2973Sgovinda /*
41*2973Sgovinda  * Allocate an Interrupt Vector Table and some interrupt vector data structures
42*2973Sgovinda  * for the reserved pool as part of the startup code. First try to allocate an
43*2973Sgovinda  * interrupt vector data structure from the reserved pool, otherwise allocate it
44*2973Sgovinda  * using kmem cache method.
45*2973Sgovinda  */
46*2973Sgovinda static	kmutex_t intr_vec_mutex;	/* Protect interrupt vector table */
470Sstevel@tonic-gate 
480Sstevel@tonic-gate /*
49*2973Sgovinda  * Global softint linked list - used by softint mdb dcmd.
500Sstevel@tonic-gate  */
51*2973Sgovinda static	kmutex_t softint_mutex;		/* Protect global softint linked list */
52*2973Sgovinda intr_vec_t	*softint_list = NULL;
53*2973Sgovinda 
54*2973Sgovinda /* Reserved pool for interrupt allocation */
55*2973Sgovinda intr_vec_t	*intr_vec_pool = NULL;	/* For HW and single target SW intrs */
56*2973Sgovinda intr_vecx_t	*intr_vecx_pool = NULL;	/* For multi target SW intrs */
57*2973Sgovinda 
58*2973Sgovinda /* Kmem cache handle for interrupt allocation */
59*2973Sgovinda kmem_cache_t	*intr_vec_cache = NULL;	/* For HW and single target SW intrs */
600Sstevel@tonic-gate 
610Sstevel@tonic-gate /*
62*2973Sgovinda  * init_ivintr() - Initialize an Interrupt Vector Table.
630Sstevel@tonic-gate  */
64*2973Sgovinda void
65*2973Sgovinda init_ivintr()
66*2973Sgovinda {
67*2973Sgovinda 	mutex_init(&intr_vec_mutex, NULL, MUTEX_DRIVER, NULL);
68*2973Sgovinda 	mutex_init(&softint_mutex, NULL, MUTEX_DRIVER, NULL);
69*2973Sgovinda 
70*2973Sgovinda 	/*
71*2973Sgovinda 	 * Initialize the reserved interrupt vector data structure pools
72*2973Sgovinda 	 * used for hardware and software interrupts.
73*2973Sgovinda 	 */
74*2973Sgovinda 	intr_vec_pool = (intr_vec_t *)((caddr_t)intr_vec_table +
75*2973Sgovinda 	    (MAXIVNUM * sizeof (intr_vec_t *)));
76*2973Sgovinda 	intr_vecx_pool = (intr_vecx_t *)((caddr_t)intr_vec_pool +
77*2973Sgovinda 	    (MAX_RSVD_IV * sizeof (intr_vec_t)));
78*2973Sgovinda 
79*2973Sgovinda 	bzero(intr_vec_table, MAXIVNUM * sizeof (intr_vec_t *));
80*2973Sgovinda 	bzero(intr_vec_pool, MAX_RSVD_IV * sizeof (intr_vec_t));
81*2973Sgovinda 	bzero(intr_vecx_pool, MAX_RSVD_IVX * sizeof (intr_vecx_t));
82*2973Sgovinda }
830Sstevel@tonic-gate 
840Sstevel@tonic-gate /*
85*2973Sgovinda  * fini_ivintr() - Uninitialize an Interrupt Vector Table.
860Sstevel@tonic-gate  */
87*2973Sgovinda void
88*2973Sgovinda fini_ivintr()
89*2973Sgovinda {
90*2973Sgovinda 	if (intr_vec_cache)
91*2973Sgovinda 		kmem_cache_destroy(intr_vec_cache);
92*2973Sgovinda 
93*2973Sgovinda 	mutex_destroy(&intr_vec_mutex);
94*2973Sgovinda 	mutex_destroy(&softint_mutex);
95*2973Sgovinda }
960Sstevel@tonic-gate 
970Sstevel@tonic-gate /*
98*2973Sgovinda  * iv_alloc() - Allocate an interrupt vector data structure.
99*2973Sgovinda  *
100*2973Sgovinda  * This function allocates an interrupt vector data structure for hardware
101*2973Sgovinda  * and single or multi target software interrupts either from the reserved
102*2973Sgovinda  * pool or using kmem cache method.
1030Sstevel@tonic-gate  */
104*2973Sgovinda static intr_vec_t *
105*2973Sgovinda iv_alloc(softint_type_t type)
106*2973Sgovinda {
107*2973Sgovinda 	intr_vec_t	*iv_p;
108*2973Sgovinda 	int		i, count;
109*2973Sgovinda 
110*2973Sgovinda 	count = (type == SOFTINT_MT) ? MAX_RSVD_IVX : MAX_RSVD_IV;
111*2973Sgovinda 
112*2973Sgovinda 	/*
113*2973Sgovinda 	 * First try to allocate an interrupt vector data structure from the
114*2973Sgovinda 	 * reserved pool, otherwise allocate it using kmem_cache_alloc().
115*2973Sgovinda 	 */
116*2973Sgovinda 	for (i = 0; i < count; i++) {
117*2973Sgovinda 		iv_p = (type == SOFTINT_MT) ?
118*2973Sgovinda 		    (intr_vec_t *)&intr_vecx_pool[i] : &intr_vec_pool[i];
1190Sstevel@tonic-gate 
120*2973Sgovinda 		if (iv_p->iv_pil == 0)
121*2973Sgovinda 			break;
122*2973Sgovinda 	}
123*2973Sgovinda 
124*2973Sgovinda 	if (i < count)
125*2973Sgovinda 		return (iv_p);
126*2973Sgovinda 
127*2973Sgovinda 	if (type == SOFTINT_MT)
128*2973Sgovinda 		cmn_err(CE_PANIC, "iv_alloc: exceeded number of multi "
129*2973Sgovinda 		    "target software interrupts, %d", MAX_RSVD_IVX);
130*2973Sgovinda 
131*2973Sgovinda 	/*
132*2973Sgovinda 	 * If the interrupt vector data structure reserved pool is already
133*2973Sgovinda 	 * exhausted, then allocate an interrupt vector data structure using
134*2973Sgovinda 	 * kmem_cache_alloc(), but only for the hardware and single software
135*2973Sgovinda 	 * interrupts. Create a kmem cache for the interrupt allocation,
136*2973Sgovinda 	 * if it is not already available.
137*2973Sgovinda 	 */
138*2973Sgovinda 	if (intr_vec_cache == NULL)
139*2973Sgovinda 		intr_vec_cache = kmem_cache_create("intr_vec_cache",
140*2973Sgovinda 		    sizeof (intr_vec_t), 64, NULL, NULL, NULL, NULL, NULL, 0);
141*2973Sgovinda 
142*2973Sgovinda 	iv_p = kmem_cache_alloc(intr_vec_cache, KM_SLEEP);
143*2973Sgovinda 	bzero(iv_p, sizeof (intr_vec_t));
144*2973Sgovinda 
145*2973Sgovinda 	iv_p->iv_flags =  IV_CACHE_ALLOC;
146*2973Sgovinda 	return (iv_p);
147*2973Sgovinda }
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate /*
150*2973Sgovinda  * iv_free() - Free an interrupt vector data structure.
1510Sstevel@tonic-gate  */
152*2973Sgovinda static void
153*2973Sgovinda iv_free(intr_vec_t *iv_p)
1540Sstevel@tonic-gate {
155*2973Sgovinda 	if (iv_p->iv_flags & IV_CACHE_ALLOC) {
156*2973Sgovinda 		ASSERT(!(iv_p->iv_flags & IV_SOFTINT_MT));
157*2973Sgovinda 		kmem_cache_free(intr_vec_cache, iv_p);
1580Sstevel@tonic-gate 	} else {
159*2973Sgovinda 		(iv_p->iv_flags & IV_SOFTINT_MT) ?
160*2973Sgovinda 		    bzero(iv_p, sizeof (intr_vecx_t)) :
161*2973Sgovinda 		    bzero(iv_p, sizeof (intr_vec_t));
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate /*
166*2973Sgovinda  * add_ivintr() - Add an interrupt handler to the system
1670Sstevel@tonic-gate  */
1680Sstevel@tonic-gate int
1690Sstevel@tonic-gate add_ivintr(uint_t inum, uint_t pil, intrfunc intr_handler,
170*2973Sgovinda     caddr_t intr_arg1, caddr_t intr_arg2, caddr_t intr_payload)
1710Sstevel@tonic-gate {
172*2973Sgovinda 	intr_vec_t	*iv_p, *new_iv_p;
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	if (inum >= MAXIVNUM || pil > PIL_MAX)
1750Sstevel@tonic-gate 		return (EINVAL);
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	ASSERT((uintptr_t)intr_handler > KERNELBASE);
178*2973Sgovinda 
1790Sstevel@tonic-gate 	/* Make sure the payload buffer address is 64 bit aligned */
1800Sstevel@tonic-gate 	VERIFY(((uint64_t)intr_payload & 0x7) == 0);
1810Sstevel@tonic-gate 
182*2973Sgovinda 	new_iv_p = iv_alloc(SOFTINT_ST);
183*2973Sgovinda 	mutex_enter(&intr_vec_mutex);
184*2973Sgovinda 
185*2973Sgovinda 	for (iv_p = (intr_vec_t *)intr_vec_table[inum];
186*2973Sgovinda 	    iv_p; iv_p = iv_p->iv_vec_next) {
187*2973Sgovinda 		if (iv_p->iv_pil == pil) {
188*2973Sgovinda 			mutex_exit(&intr_vec_mutex);
189*2973Sgovinda 			iv_free(new_iv_p);
190*2973Sgovinda 			return (EINVAL);
191*2973Sgovinda 		}
192*2973Sgovinda 	}
1930Sstevel@tonic-gate 
194*2973Sgovinda 	ASSERT(iv_p == NULL);
1950Sstevel@tonic-gate 
196*2973Sgovinda 	new_iv_p->iv_handler = intr_handler;
197*2973Sgovinda 	new_iv_p->iv_arg1 = intr_arg1;
198*2973Sgovinda 	new_iv_p->iv_arg2 = intr_arg2;
199*2973Sgovinda 	new_iv_p->iv_payload_buf = intr_payload;
200*2973Sgovinda 	new_iv_p->iv_pil = (ushort_t)pil;
201*2973Sgovinda 	new_iv_p->iv_inum = inum;
202*2973Sgovinda 
203*2973Sgovinda 	new_iv_p->iv_vec_next = (intr_vec_t *)intr_vec_table[inum];
204*2973Sgovinda 	intr_vec_table[inum] = (uint64_t)new_iv_p;
205*2973Sgovinda 
206*2973Sgovinda 	mutex_exit(&intr_vec_mutex);
2070Sstevel@tonic-gate 	return (0);
2080Sstevel@tonic-gate }
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate /*
211*2973Sgovinda  * rem_ivintr() - Remove an interrupt handler from the system
2120Sstevel@tonic-gate  */
213*2973Sgovinda int
214*2973Sgovinda rem_ivintr(uint_t inum, uint_t pil)
2150Sstevel@tonic-gate {
216*2973Sgovinda 	intr_vec_t	*iv_p, *prev_iv_p;
2170Sstevel@tonic-gate 
218*2973Sgovinda 	if (inum >= MAXIVNUM || pil > PIL_MAX)
219*2973Sgovinda 		return (EINVAL);
2200Sstevel@tonic-gate 
221*2973Sgovinda 	mutex_enter(&intr_vec_mutex);
2220Sstevel@tonic-gate 
223*2973Sgovinda 	for (iv_p = prev_iv_p = (intr_vec_t *)intr_vec_table[inum];
224*2973Sgovinda 	    iv_p; prev_iv_p = iv_p, iv_p = iv_p->iv_vec_next)
225*2973Sgovinda 		if (iv_p->iv_pil == pil)
226*2973Sgovinda 			break;
227*2973Sgovinda 
228*2973Sgovinda 	if (iv_p == NULL) {
229*2973Sgovinda 		mutex_exit(&intr_vec_mutex);
230*2973Sgovinda 		return (EIO);
2310Sstevel@tonic-gate 	}
2320Sstevel@tonic-gate 
233*2973Sgovinda 	ASSERT(iv_p->iv_pil_next == NULL);
234*2973Sgovinda 
235*2973Sgovinda 	if (prev_iv_p == iv_p)
236*2973Sgovinda 		intr_vec_table[inum] = (uint64_t)iv_p->iv_vec_next;
237*2973Sgovinda 	else
238*2973Sgovinda 		prev_iv_p->iv_vec_next = iv_p->iv_vec_next;
239*2973Sgovinda 
240*2973Sgovinda 	mutex_exit(&intr_vec_mutex);
241*2973Sgovinda 
242*2973Sgovinda 	iv_free(iv_p);
243*2973Sgovinda 	return (0);
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate /*
2470Sstevel@tonic-gate  * add_softintr() - add a software interrupt handler to the system
2480Sstevel@tonic-gate  */
249*2973Sgovinda uint64_t
250*2973Sgovinda add_softintr(uint_t pil, softintrfunc intr_handler, caddr_t intr_arg1,
251*2973Sgovinda     softint_type_t type)
2520Sstevel@tonic-gate {
253*2973Sgovinda 	intr_vec_t	*iv_p;
2540Sstevel@tonic-gate 
255*2973Sgovinda 	if (pil > PIL_MAX)
256*2973Sgovinda 		return (NULL);
257*2973Sgovinda 
258*2973Sgovinda 	iv_p = iv_alloc(type);
2590Sstevel@tonic-gate 
260*2973Sgovinda 	iv_p->iv_handler = (intrfunc)intr_handler;
261*2973Sgovinda 	iv_p->iv_arg1 = intr_arg1;
262*2973Sgovinda 	iv_p->iv_pil = (ushort_t)pil;
263*2973Sgovinda 	if (type == SOFTINT_MT)
264*2973Sgovinda 		iv_p->iv_flags |=  IV_SOFTINT_MT;
2650Sstevel@tonic-gate 
266*2973Sgovinda 	mutex_enter(&softint_mutex);
267*2973Sgovinda 	if (softint_list)
268*2973Sgovinda 		iv_p->iv_vec_next = softint_list;
269*2973Sgovinda 	softint_list = iv_p;
270*2973Sgovinda 	mutex_exit(&softint_mutex);
2710Sstevel@tonic-gate 
272*2973Sgovinda 	return ((uint64_t)iv_p);
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate /*
2760Sstevel@tonic-gate  * rem_softintr() - remove a software interrupt handler from the system
2770Sstevel@tonic-gate  */
278*2973Sgovinda int
279*2973Sgovinda rem_softintr(uint64_t softint_id)
2800Sstevel@tonic-gate {
281*2973Sgovinda 	intr_vec_t	*iv_p = (intr_vec_t *)softint_id;
282*2973Sgovinda 
283*2973Sgovinda 	ASSERT(iv_p != NULL);
284*2973Sgovinda 
285*2973Sgovinda 	if (iv_p->iv_flags & IV_SOFTINT_PEND)
286*2973Sgovinda 		return (EIO);
287*2973Sgovinda 
288*2973Sgovinda 	ASSERT(iv_p->iv_pil_next == NULL);
2890Sstevel@tonic-gate 
290*2973Sgovinda 	mutex_enter(&softint_mutex);
291*2973Sgovinda 	if (softint_list == iv_p) {
292*2973Sgovinda 		softint_list = iv_p->iv_vec_next;
293*2973Sgovinda 	} else {
294*2973Sgovinda 		intr_vec_t	*list = softint_list;
295*2973Sgovinda 
296*2973Sgovinda 		while (list && (list->iv_vec_next != iv_p))
297*2973Sgovinda 			list = list->iv_vec_next;
298*2973Sgovinda 
299*2973Sgovinda 		list->iv_vec_next = iv_p->iv_vec_next;
300*2973Sgovinda 	}
301*2973Sgovinda 	mutex_exit(&softint_mutex);
302*2973Sgovinda 
303*2973Sgovinda 	iv_free(iv_p);
304*2973Sgovinda 	return (0);
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate 
307*2973Sgovinda /*
308*2973Sgovinda  * update_softint_arg2() - Update softint arg2.
309*2973Sgovinda  *
310*2973Sgovinda  * NOTE: Do not grab any mutex in this function since it may get called
311*2973Sgovinda  *	 from the high-level interrupt context.
312*2973Sgovinda  */
3130Sstevel@tonic-gate int
314*2973Sgovinda update_softint_arg2(uint64_t softint_id, caddr_t intr_arg2)
3150Sstevel@tonic-gate {
316*2973Sgovinda 	intr_vec_t	*iv_p = (intr_vec_t *)softint_id;
3170Sstevel@tonic-gate 
318*2973Sgovinda 	ASSERT(iv_p != NULL);
3190Sstevel@tonic-gate 
320*2973Sgovinda 	if (iv_p->iv_flags & IV_SOFTINT_PEND)
321*2973Sgovinda 		return (EIO);
3220Sstevel@tonic-gate 
323*2973Sgovinda 	iv_p->iv_arg2 = intr_arg2;
324*2973Sgovinda 	return (0);
3250Sstevel@tonic-gate }
3260Sstevel@tonic-gate 
327*2973Sgovinda /*
328*2973Sgovinda  * update_softint_pri() - Update softint priority.
329*2973Sgovinda  */
3300Sstevel@tonic-gate int
331*2973Sgovinda update_softint_pri(uint64_t softint_id, uint_t pil)
3320Sstevel@tonic-gate {
333*2973Sgovinda 	intr_vec_t	*iv_p = (intr_vec_t *)softint_id;
3340Sstevel@tonic-gate 
335*2973Sgovinda 	ASSERT(iv_p != NULL);
3360Sstevel@tonic-gate 
337*2973Sgovinda 	if (pil > PIL_MAX)
338*2973Sgovinda 		return (EINVAL);
339*2973Sgovinda 
340*2973Sgovinda 	iv_p->iv_pil = pil;
341*2973Sgovinda 	return (0);
3420Sstevel@tonic-gate }
343