]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/ia64/ia64/sapic.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / ia64 / ia64 / sapic.c
1 /*-
2  * Copyright (c) 2001 Doug Rabson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include "opt_ddb.h"
30
31 #include <sys/param.h>
32 #include <sys/malloc.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36 #include <sys/lock.h>
37 #include <sys/mutex.h>
38 #include <sys/sysctl.h>
39
40 #include <machine/intr.h>
41 #include <machine/pal.h>
42 #include <machine/sapicreg.h>
43 #include <machine/sapicvar.h>
44
45 static MALLOC_DEFINE(M_SAPIC, "sapic", "I/O SAPIC devices");
46
47 static int sysctl_machdep_apic(SYSCTL_HANDLER_ARGS);
48
49 SYSCTL_OID(_machdep, OID_AUTO, apic, CTLTYPE_STRING|CTLFLAG_RD,
50     NULL, 0, sysctl_machdep_apic, "A", "(x)APIC redirection table entries");
51
52 struct sapic *ia64_sapics[16]; /* XXX make this resizable */
53 int ia64_sapic_count;
54
55 u_int64_t ia64_lapic_address = PAL_PIB_DEFAULT_ADDR;
56
57 struct sapic_rte {
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;
70 };
71
72 struct sapic *
73 sapic_lookup(u_int irq)
74 {
75         struct sapic *sa;
76         int i;
77
78         for (i = 0; i < ia64_sapic_count; i++) {
79                 sa = ia64_sapics[i];
80                 if (irq >= sa->sa_base && irq <= sa->sa_limit)
81                         return (sa);
82         }
83
84         return (NULL);
85 }
86
87 static __inline u_int32_t
88 sapic_read(struct sapic *sa, int which)
89 {
90         vm_offset_t reg = sa->sa_registers;
91
92         *(volatile u_int32_t *) (reg + SAPIC_IO_SELECT) = which;
93         ia64_mf();
94         return *(volatile u_int32_t *) (reg + SAPIC_IO_WINDOW);
95 }
96
97 static __inline void
98 sapic_write(struct sapic *sa, int which, u_int32_t value)
99 {
100         vm_offset_t reg = sa->sa_registers;
101
102         *(volatile u_int32_t *) (reg + SAPIC_IO_SELECT) = which;
103         ia64_mf();
104         *(volatile u_int32_t *) (reg + SAPIC_IO_WINDOW) = value;
105         ia64_mf();
106 }
107
108 static __inline void
109 sapic_read_rte(struct sapic *sa, int which, struct sapic_rte *rte)
110 {
111         u_int32_t *p = (u_int32_t *) rte;
112
113         p[0] = sapic_read(sa, SAPIC_RTE_BASE + 2 * which);
114         p[1] = sapic_read(sa, SAPIC_RTE_BASE + 2 * which + 1);
115 }
116
117 static __inline void
118 sapic_write_rte(struct sapic *sa, int which, struct sapic_rte *rte)
119 {
120         u_int32_t *p = (u_int32_t *) rte;
121
122         sapic_write(sa, SAPIC_RTE_BASE + 2 *which, p[0]);
123         sapic_write(sa, SAPIC_RTE_BASE + 2 *which + 1, p[1]);
124 }
125
126 int
127 sapic_config_intr(u_int irq, enum intr_trigger trig, enum intr_polarity pol)
128 {
129         struct sapic_rte rte;
130         struct sapic *sa;
131
132         sa = sapic_lookup(irq);
133         if (sa == NULL)
134                 return (EINVAL);
135
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;
141         else
142                 rte.rte_trigger_mode = (irq < 16) ? SAPIC_TRIGGER_EDGE :
143                     SAPIC_TRIGGER_LEVEL;
144         if (pol != INTR_POLARITY_CONFORM)
145                 rte.rte_polarity = (pol == INTR_POLARITY_HIGH) ?
146                     SAPIC_POLARITY_HIGH : SAPIC_POLARITY_LOW;
147         else
148                 rte.rte_polarity = (irq < 16) ? SAPIC_POLARITY_HIGH :
149                     SAPIC_POLARITY_LOW;
150         sapic_write_rte(sa, irq - sa->sa_base, &rte);
151         mtx_unlock_spin(&sa->sa_mtx);
152         return (0);
153 }
154
155 struct sapic *
156 sapic_create(u_int id, u_int base, u_int64_t address)
157 {
158         struct sapic_rte rte;
159         struct sapic *sa;
160         u_int i, max;
161
162         sa = malloc(sizeof(struct sapic), M_SAPIC, M_ZERO | M_NOWAIT);
163         if (sa == NULL)
164                 return (NULL);
165
166         sa->sa_id = id;
167         sa->sa_base = base;
168         sa->sa_registers = IA64_PHYS_TO_RR6(address);
169
170         mtx_init(&sa->sa_mtx, "I/O SAPIC lock", NULL, MTX_SPIN);
171
172         max = (sapic_read(sa, SAPIC_VERSION) >> 16) & 0xff;
173         sa->sa_limit = base + max;
174
175         ia64_sapics[ia64_sapic_count++] = sa;
176
177         /*
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.
181          */
182         bzero(&rte, sizeof(rte));
183         rte.rte_mask = 1;
184         for (i = base; i <= sa->sa_limit; i++) {
185                 rte.rte_trigger_mode = (i < 16) ? SAPIC_TRIGGER_EDGE :
186                     SAPIC_TRIGGER_LEVEL;
187                 rte.rte_polarity = (i < 16) ? SAPIC_POLARITY_HIGH :
188                     SAPIC_POLARITY_LOW;
189                 sapic_write_rte(sa, i - base, &rte);
190         }
191
192         return (sa);
193 }
194
195 int
196 sapic_enable(struct sapic *sa, u_int irq, u_int vector)
197 {
198         struct sapic_rte rte;
199         uint64_t lid = ia64_get_lid();
200
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_LOWPRI;
206         rte.rte_vector = vector;
207         rte.rte_mask = 0;
208         sapic_write_rte(sa, irq - sa->sa_base, &rte);
209         mtx_unlock_spin(&sa->sa_mtx);
210         return (0);
211 }
212
213 void
214 sapic_eoi(struct sapic *sa, u_int vector)
215 {
216         vm_offset_t reg = sa->sa_registers;
217
218         *(volatile u_int32_t *)(reg + SAPIC_APIC_EOI) = vector;
219         ia64_mf();
220 }
221
222 /* Expected to be called with interrupts disabled. */
223 void
224 sapic_mask(struct sapic *sa, u_int irq)
225 {
226         struct sapic_rte rte;
227
228         mtx_lock_spin(&sa->sa_mtx);
229         sapic_read_rte(sa, irq - sa->sa_base, &rte);
230         rte.rte_mask = 1;
231         sapic_write_rte(sa, irq - sa->sa_base, &rte);
232         mtx_unlock_spin(&sa->sa_mtx);
233 }
234
235 /* Expected to be called with interrupts disabled. */
236 void
237 sapic_unmask(struct sapic *sa, u_int irq)
238 {
239         struct sapic_rte rte;
240
241         mtx_lock_spin(&sa->sa_mtx);
242         sapic_read_rte(sa, irq - sa->sa_base, &rte);
243         rte.rte_mask = 0;
244         sapic_write_rte(sa, irq - sa->sa_base, &rte);
245         mtx_unlock_spin(&sa->sa_mtx);
246 }
247
248 static int
249 sysctl_machdep_apic(SYSCTL_HANDLER_ARGS)
250 {
251         char buf[80];
252         struct sapic_rte rte;
253         struct sapic *sa;
254         int apic, count, error, index, len;
255
256         len = sprintf(buf, "\n    APIC Idx: Id,EId : RTE\n");
257         error = SYSCTL_OUT(req, buf, len);
258         if (error)
259                 return (error);
260
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)
269                                 continue;
270                         len = sprintf(buf,
271     "    0x%02x %3d: (%02x,%02x): %3d %d %d %s %s %s %s %s\n",
272                             sa->sa_id, index,
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);
282                         if (error)
283                                 return (error);
284                 }
285         }
286
287         return (0);
288 }
289
290 #ifdef DDB
291
292 #include <ddb/ddb.h>
293
294 void
295 sapic_print(struct sapic *sa, u_int irq)
296 {
297         struct sapic_rte rte;
298
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)" : "");
311 }
312
313 #endif