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