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