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>
38 #include <sys/sysctl.h>
40 #include <machine/intr.h>
41 #include <machine/pal.h>
42 #include <machine/sapicreg.h>
43 #include <machine/sapicvar.h>
45 static MALLOC_DEFINE(M_SAPIC, "sapic", "I/O SAPIC devices");
47 static int sysctl_machdep_apic(SYSCTL_HANDLER_ARGS);
49 SYSCTL_OID(_machdep, OID_AUTO, apic, CTLTYPE_STRING|CTLFLAG_RD,
50 NULL, 0, sysctl_machdep_apic, "A", "(x)APIC redirection table entries");
52 struct sapic *ia64_sapics[16]; /* XXX make this resizable */
55 u_int64_t ia64_lapic_address = PAL_PIB_DEFAULT_ADDR;
58 u_int64_t rte_vector :8;
59 u_int64_t rte_delivery_mode :3;
60 u_int64_t rte_destination_mode :1;
61 u_int64_t rte_delivery_status :1;
62 u_int64_t rte_polarity :1;
63 u_int64_t rte_rirr :1;
64 u_int64_t rte_trigger_mode :1;
65 u_int64_t rte_mask :1;
66 u_int64_t rte_flushen :1;
67 u_int64_t rte_reserved :30;
68 u_int64_t rte_destination_eid :8;
69 u_int64_t rte_destination_id :8;
73 sapic_lookup(u_int irq)
78 for (i = 0; i < ia64_sapic_count; i++) {
80 if (irq >= sa->sa_base && irq <= sa->sa_limit)
87 static __inline u_int32_t
88 sapic_read(struct sapic *sa, int which)
90 vm_offset_t reg = sa->sa_registers;
92 *(volatile u_int32_t *) (reg + SAPIC_IO_SELECT) = which;
94 return *(volatile u_int32_t *) (reg + SAPIC_IO_WINDOW);
98 sapic_write(struct sapic *sa, int which, u_int32_t value)
100 vm_offset_t reg = sa->sa_registers;
102 *(volatile u_int32_t *) (reg + SAPIC_IO_SELECT) = which;
104 *(volatile u_int32_t *) (reg + SAPIC_IO_WINDOW) = value;
109 sapic_read_rte(struct sapic *sa, int which, struct sapic_rte *rte)
111 u_int32_t *p = (u_int32_t *) rte;
113 p[0] = sapic_read(sa, SAPIC_RTE_BASE + 2 * which);
114 p[1] = sapic_read(sa, SAPIC_RTE_BASE + 2 * which + 1);
118 sapic_write_rte(struct sapic *sa, int which, struct sapic_rte *rte)
120 u_int32_t *p = (u_int32_t *) rte;
122 sapic_write(sa, SAPIC_RTE_BASE + 2 *which, p[0]);
123 sapic_write(sa, SAPIC_RTE_BASE + 2 *which + 1, p[1]);
127 sapic_config_intr(u_int irq, enum intr_trigger trig, enum intr_polarity pol)
129 struct sapic_rte rte;
132 sa = sapic_lookup(irq);
136 mtx_lock_spin(&sa->sa_mtx);
137 sapic_read_rte(sa, irq - sa->sa_base, &rte);
138 if (trig != INTR_TRIGGER_CONFORM)
139 rte.rte_trigger_mode = (trig == INTR_TRIGGER_EDGE) ?
140 SAPIC_TRIGGER_EDGE : SAPIC_TRIGGER_LEVEL;
142 rte.rte_trigger_mode = (irq < 16) ? SAPIC_TRIGGER_EDGE :
144 if (pol != INTR_POLARITY_CONFORM)
145 rte.rte_polarity = (pol == INTR_POLARITY_HIGH) ?
146 SAPIC_POLARITY_HIGH : SAPIC_POLARITY_LOW;
148 rte.rte_polarity = (irq < 16) ? SAPIC_POLARITY_HIGH :
150 sapic_write_rte(sa, irq - sa->sa_base, &rte);
151 mtx_unlock_spin(&sa->sa_mtx);
156 sapic_create(u_int id, u_int base, u_int64_t address)
158 struct sapic_rte rte;
162 sa = malloc(sizeof(struct sapic), M_SAPIC, M_ZERO | M_NOWAIT);
168 sa->sa_registers = IA64_PHYS_TO_RR6(address);
170 mtx_init(&sa->sa_mtx, "I/O SAPIC lock", NULL, MTX_SPIN);
172 max = (sapic_read(sa, SAPIC_VERSION) >> 16) & 0xff;
173 sa->sa_limit = base + max;
175 ia64_sapics[ia64_sapic_count++] = sa;
178 * Initialize all RTEs with a default trigger mode and polarity.
179 * This may be changed later by calling sapic_config_intr(). We
180 * mask all interrupts by default.
182 bzero(&rte, sizeof(rte));
184 for (i = base; i <= sa->sa_limit; i++) {
185 rte.rte_trigger_mode = (i < 16) ? SAPIC_TRIGGER_EDGE :
187 rte.rte_polarity = (i < 16) ? SAPIC_POLARITY_HIGH :
189 sapic_write_rte(sa, i - base, &rte);
196 sapic_enable(struct sapic *sa, u_int irq, u_int vector)
198 struct sapic_rte rte;
199 uint64_t lid = ia64_get_lid();
201 mtx_lock_spin(&sa->sa_mtx);
202 sapic_read_rte(sa, irq - sa->sa_base, &rte);
203 rte.rte_destination_id = (lid >> 24) & 255;
204 rte.rte_destination_eid = (lid >> 16) & 255;
205 rte.rte_delivery_mode = SAPIC_DELMODE_FIXED;
206 rte.rte_vector = vector;
208 sapic_write_rte(sa, irq - sa->sa_base, &rte);
209 mtx_unlock_spin(&sa->sa_mtx);
214 sapic_eoi(struct sapic *sa, u_int vector)
216 vm_offset_t reg = sa->sa_registers;
218 *(volatile u_int32_t *)(reg + SAPIC_APIC_EOI) = vector;
222 /* Expected to be called with interrupts disabled. */
224 sapic_mask(struct sapic *sa, u_int irq)
226 struct sapic_rte rte;
228 mtx_lock_spin(&sa->sa_mtx);
229 sapic_read_rte(sa, irq - sa->sa_base, &rte);
231 sapic_write_rte(sa, irq - sa->sa_base, &rte);
232 mtx_unlock_spin(&sa->sa_mtx);
235 /* Expected to be called with interrupts disabled. */
237 sapic_unmask(struct sapic *sa, u_int irq)
239 struct sapic_rte rte;
241 mtx_lock_spin(&sa->sa_mtx);
242 sapic_read_rte(sa, irq - sa->sa_base, &rte);
244 sapic_write_rte(sa, irq - sa->sa_base, &rte);
245 mtx_unlock_spin(&sa->sa_mtx);
249 sysctl_machdep_apic(SYSCTL_HANDLER_ARGS)
252 struct sapic_rte rte;
254 int apic, count, error, index, len;
256 len = sprintf(buf, "\n APIC Idx: Id,EId : RTE\n");
257 error = SYSCTL_OUT(req, buf, len);
261 for (apic = 0; apic < ia64_sapic_count; apic++) {
262 sa = ia64_sapics[apic];
263 count = sa->sa_limit - sa->sa_base + 1;
264 for (index = 0; index < count; index++) {
265 mtx_lock_spin(&sa->sa_mtx);
266 sapic_read_rte(sa, index, &rte);
267 mtx_unlock_spin(&sa->sa_mtx);
268 if (rte.rte_vector == 0)
271 " 0x%02x %3d: (%02x,%02x): %3d %d %d %s %s %s %s %s\n",
273 rte.rte_destination_id, rte.rte_destination_eid,
274 rte.rte_vector, rte.rte_delivery_mode,
275 rte.rte_destination_mode,
276 rte.rte_delivery_status ? "DS" : " ",
277 rte.rte_polarity ? "low-active " : "high-active",
278 rte.rte_rirr ? "RIRR" : " ",
279 rte.rte_trigger_mode ? "level" : "edge ",
280 rte.rte_flushen ? "F" : " ");
281 error = SYSCTL_OUT(req, buf, len);
295 sapic_print(struct sapic *sa, u_int irq)
297 struct sapic_rte rte;
299 db_printf("sapic=%u, irq=%u: ", sa->sa_id, irq);
300 sapic_read_rte(sa, irq - sa->sa_base, &rte);
301 db_printf("%3d %x->%x:%x %d %s %s %s %s %s %s\n", rte.rte_vector,
302 rte.rte_delivery_mode,
303 rte.rte_destination_id, rte.rte_destination_eid,
304 rte.rte_destination_mode,
305 rte.rte_delivery_status ? "DS" : " ",
306 rte.rte_polarity ? "low-active " : "high-active",
307 rte.rte_rirr ? "RIRR" : " ",
308 rte.rte_trigger_mode ? "level" : "edge ",
309 rte.rte_flushen ? "F" : " ",
310 rte.rte_mask ? "(masked)" : "");