xref: /illumos-gate/usr/src/uts/i86pc/sys/apix.h (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2017 Joyent, Inc.
24  */
25 
26 #ifndef __SYS_APIX_APIX_H
27 #define	__SYS_APIX_APIX_H
28 
29 #include <sys/note.h>
30 #include <sys/avintr.h>
31 #include <sys/traptrace.h>
32 #include <sys/apic.h>
33 #include <sys/apic_common.h>
34 #include <sys/apic_timer.h>
35 
36 #ifdef	__cplusplus
37 extern	"C" {
38 #endif
39 
40 #ifdef	DEBUG
41 #ifndef	TRAPTRACE
42 #define	TRAPTRACE
43 #endif
44 #endif
45 
46 #define	APIX_NAME		"apix"
47 
48 #define	APIX_NVECTOR		256	/* max number of per-cpu vectors */
49 #define	APIX_NIRQ		256	/* maximum number of IRQs */
50 #define	APIX_INVALID_VECT	0	/* invalid vector */
51 
52 /* vector type */
53 #define	APIX_TYPE_FIXED	DDI_INTR_TYPE_FIXED	/* 1 */
54 #define	APIX_TYPE_MSI		DDI_INTR_TYPE_MSI	/* 2 */
55 #define	APIX_TYPE_MSIX	DDI_INTR_TYPE_MSIX	/* 4 */
56 #define	APIX_TYPE_IPI		8
57 
58 /* vector states */
59 enum {
60 	APIX_STATE_FREED = 0,
61 	APIX_STATE_OBSOLETED,	/* 1 */
62 	APIX_STATE_ALLOCED,	/* 2 */
63 	APIX_STATE_ENABLED,	/* 3 */
64 	APIX_STATE_DISABLED	/* 4 */
65 };
66 #define	IS_VECT_FREE(p)		\
67 	(((p) == NULL) || ((p)->v_state == APIX_STATE_FREED))
68 #define	IS_VECT_OBSOL(p)	\
69 	(((p) != NULL) && ((p)->v_state == APIX_STATE_OBSOLETED))
70 #define	IS_VECT_ENABLED(p)	\
71 	(((p) != NULL) && ((p)->v_state == APIX_STATE_ENABLED))
72 
73 /* flags */
74 #define	APIX_VECT_USER_BOUND	0x1
75 #define	APIX_VECT_MASKABLE	0x2
76 
77 /*
78  * Number of interrupt vectors reserved by software on each LOCAL APIC:
79  *	1. Dtrace
80  *	2. int80
81  *	3. system-call
82  *	4. fast-trap
83  *	5. apix-reserved
84  */
85 #define	APIX_SW_RESERVED_VECTORS	5
86 
87 /*
88  * Macros to help deal with shared interrupts and to differentiate
89  * between vector and irq number when passing arguments to interfaces
90  * xxx_avintr()
91  */
92 #define	APIX_VIRTVEC_VECMASK		0xff
93 #define	APIX_VIRTVEC_FLAG		0x80000000
94 #define	APIX_VIRTVECTOR(cpuid, v)	\
95 	(APIX_VIRTVEC_FLAG | ((cpuid) << 8) | (v))
96 #define	APIX_IS_VIRTVEC(vv)		\
97 	((vv) & APIX_VIRTVEC_FLAG)
98 #define	APIX_VIRTVEC_VECTOR(vv)	\
99 	(((uchar_t)(vv)) & APIX_VIRTVEC_VECMASK)
100 #define	APIX_VIRTVEC_CPU(vv)		\
101 	(((uint32_t)(vv) & ~APIX_VIRTVEC_FLAG) >> 8)
102 
103 struct apix_dev_vector;
104 typedef struct apix_vector {
105 	ushort_t		v_state;
106 	ushort_t		v_type;	/* interrupt type */
107 	processorid_t		v_cpuid;	/* current target cpu */
108 	uchar_t			v_vector;	/* vector */
109 	uchar_t			v_share;	/* intrs at this vector */
110 	int			v_inum;	/* irq for fixed, inum for msi/x */
111 	uint_t			v_flags;
112 	processorid_t		v_bound_cpuid;	/* binding cpu */
113 	uint_t			v_busy;	/* How frequently did clock */
114 					/* find us in this */
115 	uint_t			v_pri;	/* maximum priority */
116 	struct autovec		*v_autovect;	/* ISR linked list */
117 	void			*v_intrmap_private; /* intr remap data */
118 	struct apix_dev_vector *v_devp;	/* pointer to device */
119 	struct apix_vector	*v_next; /* next on per-cpu obosoletes chain */
120 } apix_vector_t;
121 
122 typedef struct apix_impl {
123 	processorid_t		x_cpuid;	/* cpu number */
124 
125 	uint16_t		x_intr_pending;	/* pending intr by IPL */
126 	/* pointer to head of interrupt pending list */
127 	struct autovec		*x_intr_head[PIL_MAX + 1];
128 	/* pointer to tail of interrupt pending list */
129 	struct autovec		*x_intr_tail[PIL_MAX + 1];
130 
131 	apix_vector_t		*x_obsoletes;	/* obosoleted vectors */
132 	apix_vector_t		*x_vectbl[APIX_NVECTOR]; /* vector table */
133 
134 	lock_t			x_lock;
135 } apix_impl_t;
136 
137 #define	HILEVEL_PENDING(cpu)	\
138 	(apixs[(cpu)->cpu_id]->x_intr_pending & CPU_INTR_ACTV_HIGH_LEVEL_MASK)
139 #define	LOWLEVEL_PENDING(cpu)	\
140 	(apixs[(cpu)->cpu_id]->x_intr_pending & ~CPU_INTR_ACTV_HIGH_LEVEL_MASK)
141 #define	IS_HILEVEL_RUNNING(cpu)	\
142 	(((ushort_t)((cpu)->intr_actv)) & CPU_INTR_ACTV_HIGH_LEVEL_MASK)
143 #define	IS_LOWLEVEL_RUNNING(cpu)	\
144 	(((ushort_t)((cpu)->intr_actv)) & ~CPU_INTR_ACTV_HIGH_LEVEL_MASK)
145 
146 #define	INTR_PENDING(apixp, ipl)			\
147 	((ipl) <= LOCK_LEVEL ?				\
148 	((apixp)->x_intr_pending & (1 << (ipl))) :	\
149 	((apixp)->x_intr_pending >> (LOCK_LEVEL + 1)))
150 
151 /*
152  * We need a way to find allocated vector for a device. One option
153  * is to maintain a mapping table in pcplusmp. Another option would
154  * be to record vector or irq with interrupt handler hdlp->ih_vector or
155  * hdlp->ih_irq.
156  * Second option requires interface changes, such as, a new interface
157  * for  noticing vector changes caused by interrupt re-targeting.
158  * Currently we choose the first option cause it doesn't require
159  * new interfaces.
160  */
161 typedef struct apix_dev_vector {
162 	dev_info_t		*dv_dip;
163 	int			dv_inum;	/* interrupt number */
164 	int			dv_type;	/* interrupt type */
165 	apix_vector_t		*dv_vector;	/* vector */
166 	struct apix_dev_vector *dv_next;	/* per major chain */
167 } apix_dev_vector_t;
168 
169 extern lock_t apix_lock;
170 extern apix_impl_t *apixs[];
171 extern int apix_nipis;
172 extern int apix_cpu_nvectors;
173 extern apix_dev_vector_t **apix_dev_vector;
174 extern processorid_t *apix_major_to_cpu;
175 extern kmutex_t apix_mutex;
176 
177 #define	xv_vector(cpu, v)	apixs[(cpu)]->x_vectbl[(v)]
178 #define	xv_intrmap_private(cpu, v)	(xv_vector(cpu, v))->v_intrmap_private
179 
180 #define	APIX_IPI_MAX		APIC_MAX_VECTOR
181 #define	APIX_IPI_MIN		(APIX_NVECTOR - apix_nipis)
182 #define	APIX_AVINTR_MIN	0x20
183 #define	APIX_NAVINTR		\
184 	(apix_cpu_nvectors - apix_nipis - APIX_AVINTR_MIN)
185 #define	APIX_AVINTR_MAX	\
186 	((APIX_NAVINTR <= 0) ? 0 : \
187 	(((APIX_AVINTR_MIN + APIX_NAVINTR) > APIX_IPI_MIN) ? \
188 	(APIX_IPI_MIN - 2) : \
189 	(APIX_AVINTR_MIN + APIX_NAVINTR - 2)))
190 #define	APIX_RESV_VECTOR	(APIX_AVINTR_MAX + 1)
191 
192 #define	IS_VALID_AVINTR(v)		\
193 	((v) >= APIX_AVINTR_MIN && (v) <= APIX_AVINTR_MAX)
194 
195 #define	APIX_ENTER_CPU_LOCK(cpuid)	lock_set(&apixs[(cpuid)]->x_lock)
196 #define	APIX_LEAVE_CPU_LOCK(cpuid)	lock_clear(&apixs[(cpuid)]->x_lock)
197 #define	APIX_CPU_LOCK_HELD(cpuid)	LOCK_HELD(&apixs[(cpuid)]->x_lock)
198 
199 /* Get dip for msi/x */
200 #define	APIX_GET_DIP(v)		\
201 	((v)->v_devp->dv_dip)
202 
203 /*
204  * For irq
205  */
206 extern apic_irq_t *apic_irq_table[APIC_MAX_VECTOR+1];
207 #define	IS_IRQ_FREE(p)		\
208 	((p) == NULL || ((p)->airq_mps_intr_index == FREE_INDEX))
209 
210 #define	UNREFERENCED_1PARAMETER(_p)		_NOTE(ARGUNUSED(_p))
211 #define	UNREFERENCED_3PARAMETER(_p, _q, _r)	_NOTE(ARGUNUSED(_p, _q, _r))
212 
213 /*
214  * From mp_platform_common.c
215  */
216 extern int apic_intr_policy;
217 extern iflag_t apic_sci_flags;
218 extern int apic_hpet_vect;
219 extern iflag_t apic_hpet_flags;
220 extern int	apic_redist_cpu_skip;
221 extern int	apic_num_imbalance;
222 extern int	apic_num_rebind;
223 extern struct apic_io_intr *apic_io_intrp;
224 extern int	apic_use_acpi_madt_only;
225 extern uint32_t	eisa_level_intr_mask;
226 extern int	apic_pci_bus_total;
227 extern uchar_t	apic_single_pci_busid;
228 
229 extern ACPI_MADT_INTERRUPT_OVERRIDE *acpi_isop;
230 extern int acpi_iso_cnt;
231 
232 extern int	apic_defconf;
233 extern int	apic_irq_translate;
234 
235 extern int apic_max_reps_clear_pending;
236 
237 extern int apic_probe_common(char *modname);
238 extern uchar_t acpi_find_ioapic(int irq);
239 extern int apic_find_bus_id(int bustype);
240 extern int apic_find_intin(uchar_t ioapic, uchar_t intin);
241 extern struct apic_io_intr *apic_find_io_intr_w_busid(int irqno, int busid);
242 extern int apic_acpi_translate_pci_irq(dev_info_t *dip, int busid, int devid,
243     int ipin, int *pci_irqp, iflag_t *intr_flagp);
244 extern int apic_handle_pci_pci_bridge(dev_info_t *idip, int child_devno,
245     int child_ipin, struct apic_io_intr **intrp);
246 extern void apic_record_rdt_entry(apic_irq_t *irqptr, int irq);
247 
248 /*
249  * apix_intr.c
250  */
251 extern void apix_do_interrupt(struct regs *rp, trap_trace_rec_t *ttp);
252 
253 /*
254  * apix_utils.c
255  */
256 
257 typedef struct apix_rebind_info {
258 	int		i_go;	/* if rebinding op is in progress */
259 	uint_t		i_pri;
260 	processorid_t	i_old_cpuid;
261 	struct autovec	*i_old_av;
262 	processorid_t	i_new_cpuid;
263 	struct autovec	*i_new_av;
264 } apix_rebind_info_t;
265 
266 extern struct apix_rebind_info apix_rebindinfo;
267 
268 #define	APIX_SET_REBIND_INFO(_ovp, _nvp)\
269 	if (((_ovp)->v_flags & APIX_VECT_MASKABLE) == 0) {\
270 		apix_rebindinfo.i_pri = (_ovp)->v_pri;\
271 		apix_rebindinfo.i_old_cpuid = (_ovp)->v_cpuid;\
272 		apix_rebindinfo.i_old_av = (_ovp)->v_autovect;\
273 		apix_rebindinfo.i_new_cpuid = (_nvp)->v_cpuid;\
274 		apix_rebindinfo.i_new_av = (_nvp)->v_autovect;\
275 		apix_rebindinfo.i_go = 1;\
276 	}
277 
278 #define	APIX_CLR_REBIND_INFO() \
279 	apix_rebindinfo.i_go = 0
280 
281 #define	APIX_IS_FAKE_INTR(_vector)\
282 	(apix_rebindinfo.i_go && (_vector) == APIX_RESV_VECTOR)
283 
284 #define	APIX_DO_FAKE_INTR(_cpu, _vector)\
285 	if (APIX_IS_FAKE_INTR(_vector)) {\
286 		struct autovec *tp = NULL;\
287 		if ((_cpu) == apix_rebindinfo.i_old_cpuid)\
288 			tp = apix_rebindinfo.i_old_av;\
289 		else if ((_cpu) == apix_rebindinfo.i_new_cpuid)\
290 			tp = apix_rebindinfo.i_new_av;\
291 		ASSERT(tp != NULL);\
292 		if (tp->av_vector != NULL &&\
293 		    (tp->av_flags & AV_PENTRY_PEND) == 0) {\
294 			tp->av_flags |= AV_PENTRY_PEND;\
295 			apix_insert_pending_av(apixs[(_cpu)], tp,\
296 			    tp->av_prilevel);\
297 			apixs[(_cpu)]->x_intr_pending |=\
298 			    (1 << tp->av_prilevel);\
299 		}\
300 	}
301 
302 extern int apix_add_avintr(void *intr_id, int ipl, avfunc xxintr, char *name,
303     int vector, caddr_t arg1, caddr_t arg2, uint64_t *ticksp, dev_info_t *dip);
304 extern void apix_rem_avintr(void *intr_id, int ipl, avfunc xxintr,
305     int virt_vect);
306 
307 extern uint32_t apix_bind_cpu_locked(dev_info_t *dip);
308 extern apix_vector_t *apix_rebind(apix_vector_t *vecp, processorid_t tocpu,
309     int count);
310 
311 extern uchar_t apix_alloc_ipi(int ipl);
312 extern apix_vector_t *apix_alloc_intx(dev_info_t *dip, int inum, int irqno);
313 extern int apix_alloc_msi(dev_info_t *dip, int inum, int count, int behavior);
314 extern int apix_alloc_msix(dev_info_t *dip, int inum, int count, int behavior);
315 extern void apix_free_vectors(dev_info_t *dip, int inum, int count, int type);
316 extern void apix_enable_vector(apix_vector_t *vecp);
317 extern void apix_disable_vector(apix_vector_t *vecp);
318 extern int apix_obsolete_vector(apix_vector_t *vecp);
319 extern int apix_find_cont_vector_oncpu(uint32_t cpuid, int count);
320 
321 extern void apix_set_dev_map(apix_vector_t *vecp, dev_info_t *dip, int inum);
322 extern apix_vector_t *apix_get_dev_map(dev_info_t *dip, int inum, int type);
323 extern apix_vector_t *apix_setup_io_intr(apix_vector_t *vecp);
324 extern void ioapix_init_intr(int mask_apic);
325 extern int apix_get_min_dev_inum(dev_info_t *dip, int type);
326 extern int apix_get_max_dev_inum(dev_info_t *dip, int type);
327 
328 /*
329  * apix.c
330  */
331 extern int apix_addspl(int virtvec, int ipl, int min_ipl, int max_ipl);
332 extern int apix_delspl(int virtvec, int ipl, int min_ipl, int max_ipl);
333 extern void apix_intx_set_vector(int irqno, uint32_t cpuid, uchar_t vector);
334 extern apix_vector_t *apix_intx_get_vector(int irqno);
335 extern void apix_intx_enable(int irqno);
336 extern void apix_intx_disable(int irqno);
337 extern void apix_intx_free(int irqno);
338 extern int apix_intx_rebind(int irqno, processorid_t cpuid, uchar_t vector);
339 extern apix_vector_t *apix_set_cpu(apix_vector_t *vecp, int new_cpu,
340     int *result);
341 extern apix_vector_t *apix_grp_set_cpu(apix_vector_t *vecp, int new_cpu,
342     int *result);
343 extern void apix_level_intr_pre_eoi(int irq);
344 extern void apix_level_intr_post_dispatch(int irq);
345 
346 #ifdef	__cplusplus
347 }
348 #endif
349 
350 #endif	/* __SYS_APIX_APIX_H */
351