2 * Copyright (c) 2001 Doug Rabson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/param.h>
32 #include <sys/malloc.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
37 #include <sys/mutex.h>
39 #include <sys/sysctl.h>
41 #include <machine/intr.h>
42 #include <machine/pal.h>
48 * Offsets from the SAPIC base in memory. Most registers are accessed
49 * by indexing using the SAPIC_IO_SELECT register.
51 #define SAPIC_IO_SELECT 0x00
52 #define SAPIC_IO_WINDOW 0x10
53 #define SAPIC_APIC_EOI 0x40
59 #define SAPIC_VERSION 0x01
60 #define SAPIC_ARBITRATION_ID 0x02
61 #define SAPIC_RTE_BASE 0x10
63 /* Interrupt polarity. */
64 #define SAPIC_POLARITY_HIGH 0
65 #define SAPIC_POLARITY_LOW 1
67 /* Interrupt trigger. */
68 #define SAPIC_TRIGGER_EDGE 0
69 #define SAPIC_TRIGGER_LEVEL 1
71 /* Interrupt delivery mode. */
72 #define SAPIC_DELMODE_FIXED 0
73 #define SAPIC_DELMODE_LOWPRI 1
74 #define SAPIC_DELMODE_PMI 2
75 #define SAPIC_DELMODE_NMI 4
76 #define SAPIC_DELMODE_INIT 5
77 #define SAPIC_DELMODE_EXTINT 7
81 uint64_t sa_registers; /* virtual address of sapic */
82 u_int sa_id; /* I/O SAPIC Id */
83 u_int sa_base; /* ACPI vector base */
84 u_int sa_limit; /* last ACPI vector handled here */
88 uint64_t rte_vector :8;
89 uint64_t rte_delivery_mode :3;
90 uint64_t rte_destination_mode :1;
91 uint64_t rte_delivery_status :1;
92 uint64_t rte_polarity :1;
94 uint64_t rte_trigger_mode :1;
96 uint64_t rte_flushen :1;
97 uint64_t rte_reserved :30;
98 uint64_t rte_destination_eid :8;
99 uint64_t rte_destination_id :8;
102 static MALLOC_DEFINE(M_SAPIC, "sapic", "I/O SAPIC devices");
104 struct sapic *ia64_sapics[16]; /* XXX make this resizable */
105 int ia64_sapic_count;
107 static int sysctl_machdep_apic(SYSCTL_HANDLER_ARGS);
109 SYSCTL_OID(_machdep, OID_AUTO, apic, CTLTYPE_STRING|CTLFLAG_RD,
110 NULL, 0, sysctl_machdep_apic, "A", "(x)APIC redirection table entries");
112 static __inline uint32_t
113 sapic_read(struct sapic *sa, int which)
117 ia64_st4((void *)(sa->sa_registers + SAPIC_IO_SELECT), which);
119 value = ia64_ld4((void *)(sa->sa_registers + SAPIC_IO_WINDOW));
124 sapic_write(struct sapic *sa, int which, uint32_t value)
127 ia64_st4((void *)(sa->sa_registers + SAPIC_IO_SELECT), which);
129 ia64_st4((void *)(sa->sa_registers + SAPIC_IO_WINDOW), value);
134 sapic_read_rte(struct sapic *sa, int which, struct sapic_rte *rte)
136 uint32_t *p = (uint32_t *) rte;
138 p[0] = sapic_read(sa, SAPIC_RTE_BASE + 2 * which);
139 p[1] = sapic_read(sa, SAPIC_RTE_BASE + 2 * which + 1);
143 sapic_write_rte(struct sapic *sa, int which, struct sapic_rte *rte)
145 uint32_t *p = (uint32_t *) rte;
147 sapic_write(sa, SAPIC_RTE_BASE + 2 * which, p[0]);
148 sapic_write(sa, SAPIC_RTE_BASE + 2 * which + 1, p[1]);
152 sapic_lookup(u_int irq, u_int *vecp)
154 struct sapic_rte rte;
158 for (i = 0; i < ia64_sapic_count; i++) {
160 if (irq >= sa->sa_base && irq <= sa->sa_limit) {
162 mtx_lock_spin(&sa->sa_mtx);
163 sapic_read_rte(sa, irq - sa->sa_base, &rte);
164 mtx_unlock_spin(&sa->sa_mtx);
165 *vecp = rte.rte_vector;
176 sapic_bind_intr(u_int irq, struct pcpu *pc)
178 struct sapic_rte rte;
181 sa = sapic_lookup(irq, NULL);
185 mtx_lock_spin(&sa->sa_mtx);
186 sapic_read_rte(sa, irq - sa->sa_base, &rte);
187 rte.rte_destination_id = (pc->pc_md.lid >> 24) & 255;
188 rte.rte_destination_eid = (pc->pc_md.lid >> 16) & 255;
189 rte.rte_delivery_mode = SAPIC_DELMODE_FIXED;
190 sapic_write_rte(sa, irq - sa->sa_base, &rte);
191 mtx_unlock_spin(&sa->sa_mtx);
196 sapic_config_intr(u_int irq, enum intr_trigger trig, enum intr_polarity pol)
198 struct sapic_rte rte;
201 sa = sapic_lookup(irq, NULL);
205 mtx_lock_spin(&sa->sa_mtx);
206 sapic_read_rte(sa, irq - sa->sa_base, &rte);
207 if (trig != INTR_TRIGGER_CONFORM)
208 rte.rte_trigger_mode = (trig == INTR_TRIGGER_EDGE) ?
209 SAPIC_TRIGGER_EDGE : SAPIC_TRIGGER_LEVEL;
211 rte.rte_trigger_mode = (irq < 16) ? SAPIC_TRIGGER_EDGE :
213 if (pol != INTR_POLARITY_CONFORM)
214 rte.rte_polarity = (pol == INTR_POLARITY_HIGH) ?
215 SAPIC_POLARITY_HIGH : SAPIC_POLARITY_LOW;
217 rte.rte_polarity = (irq < 16) ? SAPIC_POLARITY_HIGH :
219 sapic_write_rte(sa, irq - sa->sa_base, &rte);
220 mtx_unlock_spin(&sa->sa_mtx);
225 sapic_create(u_int id, u_int base, uint64_t address)
227 struct sapic_rte rte;
231 sa = malloc(sizeof(struct sapic), M_SAPIC, M_ZERO | M_NOWAIT);
237 sa->sa_registers = (uintptr_t)pmap_mapdev(address, 1048576);
239 mtx_init(&sa->sa_mtx, "I/O SAPIC lock", NULL, MTX_SPIN);
241 max = (sapic_read(sa, SAPIC_VERSION) >> 16) & 0xff;
242 sa->sa_limit = base + max;
244 ia64_sapics[ia64_sapic_count++] = sa;
247 * Initialize all RTEs with a default trigger mode and polarity.
248 * This may be changed later by calling sapic_config_intr(). We
249 * mask all interrupts by default.
251 bzero(&rte, sizeof(rte));
253 for (i = base; i <= sa->sa_limit; i++) {
254 rte.rte_trigger_mode = (i < 16) ? SAPIC_TRIGGER_EDGE :
256 rte.rte_polarity = (i < 16) ? SAPIC_POLARITY_HIGH :
258 sapic_write_rte(sa, i - base, &rte);
265 sapic_enable(struct sapic *sa, u_int irq, u_int vector)
267 struct sapic_rte rte;
268 uint64_t lid = ia64_get_lid();
270 mtx_lock_spin(&sa->sa_mtx);
271 sapic_read_rte(sa, irq - sa->sa_base, &rte);
272 rte.rte_destination_id = (lid >> 24) & 255;
273 rte.rte_destination_eid = (lid >> 16) & 255;
274 rte.rte_delivery_mode = SAPIC_DELMODE_FIXED;
275 rte.rte_vector = vector;
277 sapic_write_rte(sa, irq - sa->sa_base, &rte);
278 mtx_unlock_spin(&sa->sa_mtx);
283 sapic_eoi(struct sapic *sa, u_int vector)
286 ia64_st4((void *)(sa->sa_registers + SAPIC_APIC_EOI), vector);
290 /* Expected to be called with interrupts disabled. */
292 sapic_mask(struct sapic *sa, u_int irq)
294 struct sapic_rte rte;
296 mtx_lock_spin(&sa->sa_mtx);
297 sapic_read_rte(sa, irq - sa->sa_base, &rte);
299 sapic_write_rte(sa, irq - sa->sa_base, &rte);
300 mtx_unlock_spin(&sa->sa_mtx);
303 /* Expected to be called with interrupts disabled. */
305 sapic_unmask(struct sapic *sa, u_int irq)
307 struct sapic_rte rte;
309 mtx_lock_spin(&sa->sa_mtx);
310 sapic_read_rte(sa, irq - sa->sa_base, &rte);
312 sapic_write_rte(sa, irq - sa->sa_base, &rte);
313 mtx_unlock_spin(&sa->sa_mtx);
317 sysctl_machdep_apic(SYSCTL_HANDLER_ARGS)
320 struct sapic_rte rte;
322 int apic, count, error, index, len;
324 len = sprintf(buf, "\n APIC Idx: Id,EId : RTE\n");
325 error = SYSCTL_OUT(req, buf, len);
329 for (apic = 0; apic < ia64_sapic_count; apic++) {
330 sa = ia64_sapics[apic];
331 count = sa->sa_limit - sa->sa_base + 1;
332 for (index = 0; index < count; index++) {
333 mtx_lock_spin(&sa->sa_mtx);
334 sapic_read_rte(sa, index, &rte);
335 mtx_unlock_spin(&sa->sa_mtx);
336 if (rte.rte_vector == 0)
339 " 0x%02x %3d: (%02x,%02x): %3d %d %d %s %s %s %s %s\n",
341 rte.rte_destination_id, rte.rte_destination_eid,
342 rte.rte_vector, rte.rte_delivery_mode,
343 rte.rte_destination_mode,
344 rte.rte_delivery_status ? "DS" : " ",
345 rte.rte_polarity ? "low-active " : "high-active",
346 rte.rte_rirr ? "RIRR" : " ",
347 rte.rte_trigger_mode ? "level" : "edge ",
348 rte.rte_flushen ? "F" : " ");
349 error = SYSCTL_OUT(req, buf, len);
363 sapic_print(struct sapic *sa, u_int irq)
365 struct sapic_rte rte;
367 db_printf("sapic=%u, irq=%u: ", sa->sa_id, irq);
368 sapic_read_rte(sa, irq - sa->sa_base, &rte);
369 db_printf("%3d %x->%x:%x %d %s %s %s %s %s %s\n", rte.rte_vector,
370 rte.rte_delivery_mode,
371 rte.rte_destination_id, rte.rte_destination_eid,
372 rte.rte_destination_mode,
373 rte.rte_delivery_status ? "DS" : " ",
374 rte.rte_polarity ? "low-active " : "high-active",
375 rte.rte_rirr ? "RIRR" : " ",
376 rte.rte_trigger_mode ? "level" : "edge ",
377 rte.rte_flushen ? "F" : " ",
378 rte.rte_mask ? "(masked)" : "");