| @@ -1,360 +1,355 @@ | | | @@ -1,360 +1,355 @@ |
1 | /* $NetBSD: apic.c,v 1.4 2009/11/29 10:30:07 skrll Exp $ */ | | 1 | /* $NetBSD: apic.c,v 1.5 2009/12/03 11:54:09 skrll Exp $ */ |
2 | | | 2 | |
3 | /* $OpenBSD: apic.c,v 1.7 2007/10/06 23:50:54 krw Exp $ */ | | 3 | /* $OpenBSD: apic.c,v 1.7 2007/10/06 23:50:54 krw Exp $ */ |
4 | | | 4 | |
5 | /* | | 5 | /* |
6 | * Copyright (c) 2005 Michael Shalayeff | | 6 | * Copyright (c) 2005 Michael Shalayeff |
7 | * Copyright (c) 2007 Mark Kettenis | | 7 | * Copyright (c) 2007 Mark Kettenis |
8 | * All rights reserved. | | 8 | * All rights reserved. |
9 | * | | 9 | * |
10 | * Permission to use, copy, modify, and distribute this software for any | | 10 | * Permission to use, copy, modify, and distribute this software for any |
11 | * purpose with or without fee is hereby granted, provided that the above | | 11 | * purpose with or without fee is hereby granted, provided that the above |
12 | * copyright notice and this permission notice appear in all copies. | | 12 | * copyright notice and this permission notice appear in all copies. |
13 | * | | 13 | * |
14 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 14 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
15 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 15 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
16 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 16 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
17 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 17 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
18 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN | | 18 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN |
19 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | | 19 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT |
20 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ | | 20 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
21 | | | 21 | |
22 | #include <sys/param.h> | | 22 | #include <sys/param.h> |
23 | #include <sys/systm.h> | | 23 | #include <sys/systm.h> |
24 | #include <sys/device.h> | | 24 | #include <sys/device.h> |
25 | #include <sys/malloc.h> | | 25 | #include <sys/malloc.h> |
26 | | | 26 | |
27 | #include <machine/autoconf.h> | | 27 | #include <machine/autoconf.h> |
28 | #include <machine/pdc.h> | | 28 | #include <machine/pdc.h> |
29 | #include <machine/intr.h> | | 29 | #include <machine/intr.h> |
30 | | | 30 | |
31 | #include <hp700/hp700/intr.h> | | 31 | #include <hp700/hp700/intr.h> |
32 | | | 32 | |
33 | #include <dev/pci/pcireg.h> | | 33 | #include <dev/pci/pcireg.h> |
34 | #include <dev/pci/pcivar.h> | | 34 | #include <dev/pci/pcivar.h> |
35 | #include <dev/pci/pcidevs.h> | | 35 | #include <dev/pci/pcidevs.h> |
36 | | | 36 | |
37 | #include <hp700/dev/elroyreg.h> | | 37 | #include <hp700/dev/elroyreg.h> |
38 | #include <hp700/dev/elroyvar.h> | | 38 | #include <hp700/dev/elroyvar.h> |
39 | | | 39 | |
40 | #define APIC_INT_LINE_MASK 0x0000ff00 | | 40 | #define APIC_INT_LINE_MASK 0x0000ff00 |
41 | #define APIC_INT_LINE_SHIFT 8 | | 41 | #define APIC_INT_LINE_SHIFT 8 |
42 | #define APIC_INT_IRQ_MASK 0x0000001f | | 42 | #define APIC_INT_IRQ_MASK 0x0000001f |
43 | | | 43 | |
44 | #define APIC_INT_LINE(x) (((x) & APIC_INT_LINE_MASK) >> APIC_INT_LINE_SHIFT) | | 44 | #define APIC_INT_LINE(x) (((x) & APIC_INT_LINE_MASK) >> APIC_INT_LINE_SHIFT) |
45 | #define APIC_INT_IRQ(x) ((x) & APIC_INT_IRQ_MASK) | | 45 | #define APIC_INT_IRQ(x) ((x) & APIC_INT_IRQ_MASK) |
46 | | | 46 | |
47 | /* | | 47 | /* |
48 | * Interrupt types match the Intel MP Specification. | | 48 | * Interrupt types match the Intel MP Specification. |
49 | */ | | 49 | */ |
50 | | | 50 | |
51 | #define MPS_INTPO_DEF 0 | | 51 | #define MPS_INTPO_DEF 0 |
52 | #define MPS_INTPO_ACTHI 1 | | 52 | #define MPS_INTPO_ACTHI 1 |
53 | #define MPS_INTPO_ACTLO 3 | | 53 | #define MPS_INTPO_ACTLO 3 |
54 | #define MPS_INTPO_SHIFT 0 | | 54 | #define MPS_INTPO_SHIFT 0 |
55 | #define MPS_INTPO_MASK 3 | | 55 | #define MPS_INTPO_MASK 3 |
56 | | | 56 | |
57 | #define MPS_INTTR_DEF 0 | | 57 | #define MPS_INTTR_DEF 0 |
58 | #define MPS_INTTR_EDGE 1 | | 58 | #define MPS_INTTR_EDGE 1 |
59 | #define MPS_INTTR_LEVEL 3 | | 59 | #define MPS_INTTR_LEVEL 3 |
60 | #define MPS_INTTR_SHIFT 2 | | 60 | #define MPS_INTTR_SHIFT 2 |
61 | #define MPS_INTTR_MASK 3 | | 61 | #define MPS_INTTR_MASK 3 |
62 | | | 62 | |
63 | #define MPS_INT(p,t) \ | | 63 | #define MPS_INT(p,t) \ |
64 | ((((p) & MPS_INTPO_MASK) << MPS_INTPO_SHIFT) | \ | | 64 | ((((p) & MPS_INTPO_MASK) << MPS_INTPO_SHIFT) | \ |
65 | (((t) & MPS_INTTR_MASK) << MPS_INTTR_SHIFT)) | | 65 | (((t) & MPS_INTTR_MASK) << MPS_INTTR_SHIFT)) |
66 | | | 66 | |
67 | struct apic_iv { | | 67 | struct apic_iv { |
68 | struct elroy_softc *sc; | | 68 | struct elroy_softc *sc; |
69 | pci_intr_handle_t ih; | | 69 | pci_intr_handle_t ih; |
70 | int (*handler)(void *); | | 70 | int (*handler)(void *); |
71 | void *arg; | | 71 | void *arg; |
72 | struct apic_iv *next; | | 72 | struct apic_iv *next; |
73 | struct evcnt *cnt; | | 73 | struct evcnt *cnt; |
74 | }; | | 74 | }; |
75 | | | 75 | |
76 | struct apic_iv *apic_intr_list[CPU_NINTS]; | | 76 | struct apic_iv *apic_intr_list[CPU_NINTS]; |
77 | | | 77 | |
78 | void apic_write(volatile struct elroy_regs *, uint32_t, uint32_t); | | 78 | void apic_write(volatile struct elroy_regs *, uint32_t, uint32_t); |
79 | uint32_t apic_read(volatile struct elroy_regs *, uint32_t reg); | | 79 | uint32_t apic_read(volatile struct elroy_regs *, uint32_t reg); |
80 | | | 80 | |
81 | void apic_get_int_tbl(struct elroy_softc *); | | 81 | void apic_get_int_tbl(struct elroy_softc *); |
82 | uint32_t apic_get_int_ent0(struct elroy_softc *, int); | | 82 | uint32_t apic_get_int_ent0(struct elroy_softc *, int); |
83 | #ifdef DEBUG | | 83 | #ifdef DEBUG |
84 | void apic_dump(struct elroy_softc *); | | 84 | void apic_dump(struct elroy_softc *); |
85 | #endif | | 85 | #endif |
86 | | | 86 | |
87 | void | | 87 | void |
88 | apic_write(volatile struct elroy_regs *r, uint32_t reg, uint32_t val) | | 88 | apic_write(volatile struct elroy_regs *r, uint32_t reg, uint32_t val) |
89 | { | | 89 | { |
90 | elroy_write32(&r->apic_addr, htole32(reg)); | | 90 | elroy_write32(&r->apic_addr, htole32(reg)); |
91 | elroy_write32(&r->apic_data, htole32(val)); | | 91 | elroy_write32(&r->apic_data, htole32(val)); |
92 | elroy_read32(&r->apic_data); | | 92 | elroy_read32(&r->apic_data); |
93 | } | | 93 | } |
94 | | | 94 | |
95 | uint32_t | | 95 | uint32_t |
96 | apic_read(volatile struct elroy_regs *r, uint32_t reg) | | 96 | apic_read(volatile struct elroy_regs *r, uint32_t reg) |
97 | { | | 97 | { |
98 | elroy_write32(&r->apic_addr, htole32(reg)); | | 98 | elroy_write32(&r->apic_addr, htole32(reg)); |
99 | return le32toh(elroy_read32(&r->apic_data)); | | 99 | return le32toh(elroy_read32(&r->apic_data)); |
100 | } | | 100 | } |
101 | | | 101 | |
102 | void | | 102 | void |
103 | apic_attach(struct elroy_softc *sc) | | 103 | apic_attach(struct elroy_softc *sc) |
104 | { | | 104 | { |
105 | volatile struct elroy_regs *r = sc->sc_regs; | | 105 | volatile struct elroy_regs *r = sc->sc_regs; |
106 | uint32_t data; | | 106 | uint32_t data; |
107 | | | 107 | |
108 | data = apic_read(r, APIC_VERSION); | | 108 | data = apic_read(r, APIC_VERSION); |
109 | sc->sc_nints = (data & APIC_VERSION_NENT) >> APIC_VERSION_NENT_SHIFT; | | 109 | sc->sc_nints = (data & APIC_VERSION_NENT) >> APIC_VERSION_NENT_SHIFT; |
110 | aprint_normal(" APIC ver %x, %d pins", | | 110 | aprint_normal(" APIC ver %x, %d pins", |
111 | data & APIC_VERSION_MASK, sc->sc_nints); | | 111 | data & APIC_VERSION_MASK, sc->sc_nints); |
112 | | | 112 | |
113 | sc->sc_irq = malloc(sc->sc_nints * sizeof(int), M_DEVBUF, | | 113 | sc->sc_irq = malloc(sc->sc_nints * sizeof(int), M_DEVBUF, |
114 | M_NOWAIT | M_ZERO); | | 114 | M_NOWAIT | M_ZERO); |
115 | if (sc->sc_irq == NULL) | | 115 | if (sc->sc_irq == NULL) |
116 | panic("apic_attach: can't allocate irq table\n"); | | 116 | panic("apic_attach: can't allocate irq table\n"); |
117 | | | 117 | |
118 | apic_get_int_tbl(sc); | | 118 | apic_get_int_tbl(sc); |
119 | | | 119 | |
120 | #ifdef DEBUG | | 120 | #ifdef DEBUG |
121 | apic_dump(sc); | | 121 | apic_dump(sc); |
122 | #endif | | 122 | #endif |
123 | } | | 123 | } |
124 | | | 124 | |
125 | int | | 125 | int |
126 | apic_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) | | 126 | apic_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) |
127 | { | | 127 | { |
128 | struct elroy_softc *sc = pa->pa_pc->_cookie; | | 128 | struct elroy_softc *sc = pa->pa_pc->_cookie; |
129 | pci_chipset_tag_t pc = pa->pa_pc; | | 129 | pci_chipset_tag_t pc = pa->pa_pc; |
130 | pcitag_t tag = pa->pa_tag; | | 130 | pcitag_t tag = pa->pa_tag; |
131 | pcireg_t reg; | | 131 | pcireg_t reg; |
132 | int line; | | 132 | int line; |
133 | | | 133 | |
134 | reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); | | 134 | reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); |
135 | #ifdef DEBUG | | 135 | #ifdef DEBUG |
136 | printf(" pin=%d line=%d ", PCI_INTERRUPT_PIN(reg), | | 136 | printf(" pin=%d line=%d ", PCI_INTERRUPT_PIN(reg), |
137 | PCI_INTERRUPT_LINE(reg)); | | 137 | PCI_INTERRUPT_LINE(reg)); |
138 | #endif | | 138 | #endif |
139 | line = PCI_INTERRUPT_LINE(reg); | | 139 | line = PCI_INTERRUPT_LINE(reg); |
140 | if (sc->sc_irq[line] == 0) | | 140 | if (sc->sc_irq[line] == 0) |
141 | sc->sc_irq[line] = hp700_intr_allocate_bit(&int_reg_cpu);; | | 141 | sc->sc_irq[line] = hp700_intr_allocate_bit(&int_reg_cpu);; |
142 | *ihp = (line << APIC_INT_LINE_SHIFT) | sc->sc_irq[line]; | | 142 | *ihp = (line << APIC_INT_LINE_SHIFT) | sc->sc_irq[line]; |
143 | return (APIC_INT_IRQ(*ihp) == 0); | | 143 | return (APIC_INT_IRQ(*ihp) == 0); |
144 | } | | 144 | } |
145 | | | 145 | |
146 | const char * | | 146 | const char * |
147 | apic_intr_string(void *v, pci_intr_handle_t ih) | | 147 | apic_intr_string(void *v, pci_intr_handle_t ih) |
148 | { | | 148 | { |
149 | static char buf[32]; | | 149 | static char buf[32]; |
150 | | | 150 | |
151 | snprintf(buf, sizeof(buf), "line %ld irq %ld", | | 151 | snprintf(buf, sizeof(buf), "line %ld irq %ld", |
152 | APIC_INT_LINE(ih), APIC_INT_IRQ(ih)); | | 152 | APIC_INT_LINE(ih), APIC_INT_IRQ(ih)); |
153 | | | 153 | |
154 | return (buf); | | 154 | return (buf); |
155 | } | | 155 | } |
156 | | | 156 | |
157 | void * | | 157 | void * |
158 | apic_intr_establish(void *v, pci_intr_handle_t ih, | | 158 | apic_intr_establish(void *v, pci_intr_handle_t ih, |
159 | int pri, int (*handler)(void *), void *arg) | | 159 | int pri, int (*handler)(void *), void *arg) |
160 | { | | 160 | { |
161 | struct elroy_softc *sc = v; | | 161 | struct elroy_softc *sc = v; |
162 | volatile struct elroy_regs *r = sc->sc_regs; | | 162 | volatile struct elroy_regs *r = sc->sc_regs; |
163 | hppa_hpa_t hpa = cpu_gethpa(0); | | 163 | hppa_hpa_t hpa = cpu_gethpa(0); |
164 | struct evcnt *cnt; | | 164 | struct evcnt *cnt; |
165 | struct apic_iv *aiv, *biv; | | 165 | struct apic_iv *aiv, *biv; |
166 | void *iv; | | 166 | void *iv; |
167 | int irq = APIC_INT_IRQ(ih); | | 167 | int irq = APIC_INT_IRQ(ih); |
168 | int line = APIC_INT_LINE(ih); | | 168 | int line = APIC_INT_LINE(ih); |
169 | uint32_t ent0; | | 169 | uint32_t ent0; |
170 | | | 170 | |
171 | /* no mapping or bogus */ | | 171 | /* no mapping or bogus */ |
172 | if (irq <= 0 || irq > 31) | | 172 | if (irq <= 0 || irq > 31) |
173 | return (NULL); | | 173 | return (NULL); |
174 | | | 174 | |
175 | aiv = malloc(sizeof(struct apic_iv), M_DEVBUF, M_NOWAIT); | | 175 | aiv = malloc(sizeof(struct apic_iv), M_DEVBUF, M_NOWAIT); |
176 | if (aiv == NULL) | | 176 | if (aiv == NULL) |
177 | return NULL; | | 177 | return NULL; |
178 | | | 178 | |
179 | aiv->sc = sc; | | 179 | aiv->sc = sc; |
180 | aiv->ih = ih; | | 180 | aiv->ih = ih; |
181 | aiv->handler = handler; | | 181 | aiv->handler = handler; |
182 | aiv->arg = arg; | | 182 | aiv->arg = arg; |
183 | aiv->next = NULL; | | 183 | aiv->next = NULL; |
184 | aiv->cnt = NULL; | | 184 | aiv->cnt = NULL; |
185 | if (apic_intr_list[irq]) { | | 185 | if (apic_intr_list[irq]) { |
186 | cnt = malloc(sizeof(struct evcnt), M_DEVBUF, M_NOWAIT); | | 186 | cnt = malloc(sizeof(struct evcnt), M_DEVBUF, M_NOWAIT); |
187 | if (cnt == NULL) { | | 187 | if (cnt == NULL) { |
188 | free(aiv, M_DEVBUF); | | 188 | free(aiv, M_DEVBUF); |
189 | return NULL; | | 189 | return NULL; |
190 | } | | 190 | } |
191 | | | 191 | |
192 | evcnt_attach_dynamic(cnt, EVCNT_TYPE_INTR, NULL, | | 192 | evcnt_attach_dynamic(cnt, EVCNT_TYPE_INTR, NULL, |
193 | device_xname(sc->sc_dv), "irq" /* XXXNH */); | | 193 | device_xname(sc->sc_dv), "irq" /* XXXNH */); |
194 | biv = apic_intr_list[irq]; | | 194 | biv = apic_intr_list[irq]; |
195 | while (biv->next) | | 195 | while (biv->next) |
196 | biv = biv->next; | | 196 | biv = biv->next; |
197 | biv->next = aiv; | | 197 | biv->next = aiv; |
198 | aiv->cnt = cnt; | | 198 | aiv->cnt = cnt; |
199 | return arg; | | 199 | return arg; |
200 | } | | 200 | } |
201 | | | 201 | |
202 | if ((iv = hp700_intr_establish(sc->sc_dv, pri, apic_intr, | | 202 | if ((iv = hp700_intr_establish(sc->sc_dv, pri, apic_intr, |
203 | aiv, &int_reg_cpu, irq))) { | | 203 | aiv, &int_reg_cpu, irq))) { |
204 | ent0 = (31 - irq) & APIC_ENT0_VEC; | | 204 | ent0 = (31 - irq) & APIC_ENT0_VEC; |
205 | ent0 |= apic_get_int_ent0(sc, line); | | 205 | ent0 |= apic_get_int_ent0(sc, line); |
206 | #if 0 | | 206 | #if 0 |
207 | if (cold) { | | 207 | if (cold) { |
208 | sc->sc_imr |= (1 << irq); | | 208 | sc->sc_imr |= (1 << irq); |
209 | ent0 |= APIC_ENT0_MASK; | | 209 | ent0 |= APIC_ENT0_MASK; |
210 | } | | 210 | } |
211 | #endif | | 211 | #endif |
212 | apic_write(sc->sc_regs, APIC_ENT0(line), APIC_ENT0_MASK); | | 212 | apic_write(sc->sc_regs, APIC_ENT0(line), APIC_ENT0_MASK); |
213 | apic_write(sc->sc_regs, APIC_ENT1(line), | | 213 | apic_write(sc->sc_regs, APIC_ENT1(line), |
214 | ((hpa & 0x0ff00000) >> 4) | ((hpa & 0x000ff000) << 12)); | | 214 | ((hpa & 0x0ff00000) >> 4) | ((hpa & 0x000ff000) << 12)); |
215 | apic_write(sc->sc_regs, APIC_ENT0(line), ent0); | | 215 | apic_write(sc->sc_regs, APIC_ENT0(line), ent0); |
216 | | | 216 | |
217 | /* Signal EOI. */ | | 217 | /* Signal EOI. */ |
218 | elroy_write32(&r->apic_eoi, | | 218 | elroy_write32(&r->apic_eoi, |
219 | htole32((31 - irq) & APIC_ENT0_VEC)); | | 219 | htole32((31 - irq) & APIC_ENT0_VEC)); |
220 | | | 220 | |
221 | apic_intr_list[irq] = aiv; | | 221 | apic_intr_list[irq] = aiv; |
222 | } | | 222 | } |
223 | | | 223 | |
224 | return (arg); | | 224 | return (arg); |
225 | } | | 225 | } |
226 | | | 226 | |
227 | void | | 227 | void |
228 | apic_intr_disestablish(void *v, void *cookie) | | 228 | apic_intr_disestablish(void *v, void *cookie) |
229 | { | | 229 | { |
230 | } | | 230 | } |
231 | | | 231 | |
232 | int | | 232 | int |
233 | apic_intr(void *v) | | 233 | apic_intr(void *v) |
234 | { | | 234 | { |
235 | struct apic_iv *iv = v; | | 235 | struct apic_iv *iv = v; |
236 | struct elroy_softc *sc = iv->sc; | | 236 | struct elroy_softc *sc = iv->sc; |
237 | volatile struct elroy_regs *r = sc->sc_regs; | | 237 | volatile struct elroy_regs *r = sc->sc_regs; |
238 | int claimed = 0; | | 238 | int claimed = 0; |
239 | | | 239 | |
240 | while (iv) { | | 240 | while (iv) { |
241 | if (iv->handler(iv->arg)) { | | 241 | if (iv->handler(iv->arg)) { |
242 | if (iv->cnt) | | 242 | if (iv->cnt) |
243 | iv->cnt->ev_count++; | | 243 | iv->cnt->ev_count++; |
244 | /* Signal EOI. */ | | 244 | /* Signal EOI. */ |
245 | elroy_write32(&r->apic_eoi, | | 245 | elroy_write32(&r->apic_eoi, |
246 | htole32((31 - APIC_INT_IRQ(iv->ih)) & APIC_ENT0_VEC)); | | 246 | htole32((31 - APIC_INT_IRQ(iv->ih)) & APIC_ENT0_VEC)); |
247 | claimed = 1; | | 247 | claimed = 1; |
248 | } | | 248 | } |
249 | iv = iv->next; | | 249 | iv = iv->next; |
250 | } | | 250 | } |
251 | | | 251 | |
252 | return (claimed); | | 252 | return (claimed); |
253 | } | | 253 | } |
254 | | | 254 | |
255 | /* Maximum number of supported interrupt routing entries. */ | | 255 | /* Maximum number of supported interrupt routing entries. */ |
256 | #define MAX_INT_TBL_SZ 16 | | 256 | #define MAX_INT_TBL_SZ 16 |
257 | | | 257 | |
258 | void | | 258 | void |
259 | apic_get_int_tbl(struct elroy_softc *sc) | | 259 | apic_get_int_tbl(struct elroy_softc *sc) |
260 | { | | 260 | { |
261 | struct pdc_pat_io_num int_tbl_sz PDC_ALIGNMENT; | | 261 | static struct pdc_pat_io_num int_tbl_sz PDC_ALIGNMENT; |
262 | struct pdc_pat_pci_rt int_tbl[MAX_INT_TBL_SZ] PDC_ALIGNMENT; | | 262 | static struct pdc_pat_pci_rt int_tbl[MAX_INT_TBL_SZ] PDC_ALIGNMENT; |
263 | size_t size; | | 263 | size_t size; |
264 | | | 264 | |
265 | /* | | | |
266 | * XXX int_tbl should not be allocated on the stack, but we need a | | | |
267 | * 1:1 mapping, and malloc doesn't provide that. | | | |
268 | */ | | | |
269 | | | | |
270 | if (pdc_call((iodcio_t)pdc, 0, PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SZ, | | 265 | if (pdc_call((iodcio_t)pdc, 0, PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SZ, |
271 | &int_tbl_sz, 0, 0, 0, 0, 0)) | | 266 | &int_tbl_sz, 0, 0, 0, 0, 0)) |
272 | return; | | 267 | return; |
273 | | | 268 | |
274 | if (int_tbl_sz.num > MAX_INT_TBL_SZ) | | 269 | if (int_tbl_sz.num > MAX_INT_TBL_SZ) |
275 | panic("interrupt routing table too big (%d entries)", | | 270 | panic("interrupt routing table too big (%d entries)", |
276 | int_tbl_sz.num); | | 271 | int_tbl_sz.num); |
277 | | | 272 | |
278 | size = int_tbl_sz.num * sizeof(struct pdc_pat_pci_rt); | | 273 | size = int_tbl_sz.num * sizeof(struct pdc_pat_pci_rt); |
279 | sc->sc_int_tbl_sz = int_tbl_sz.num; | | 274 | sc->sc_int_tbl_sz = int_tbl_sz.num; |
280 | sc->sc_int_tbl = malloc(size, M_DEVBUF, M_NOWAIT); | | 275 | sc->sc_int_tbl = malloc(size, M_DEVBUF, M_NOWAIT); |
281 | if (sc->sc_int_tbl == NULL) | | 276 | if (sc->sc_int_tbl == NULL) |
282 | return; | | 277 | return; |
283 | | | 278 | |
284 | if (pdc_call((iodcio_t)pdc, 0, PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL, | | 279 | if (pdc_call((iodcio_t)pdc, 0, PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL, |
285 | &int_tbl_sz, 0, &int_tbl, 0, 0, 0)) | | 280 | &int_tbl_sz, 0, &int_tbl, 0, 0, 0)) |
286 | return; | | 281 | return; |
287 | | | 282 | |
288 | memcpy(sc->sc_int_tbl, int_tbl, size); | | 283 | memcpy(sc->sc_int_tbl, int_tbl, size); |
289 | } | | 284 | } |
290 | | | 285 | |
291 | uint32_t | | 286 | uint32_t |
292 | apic_get_int_ent0(struct elroy_softc *sc, int line) | | 287 | apic_get_int_ent0(struct elroy_softc *sc, int line) |
293 | { | | 288 | { |
294 | volatile struct elroy_regs *r = sc->sc_regs; | | 289 | volatile struct elroy_regs *r = sc->sc_regs; |
295 | int trigger = MPS_INT(MPS_INTPO_DEF, MPS_INTTR_DEF); | | 290 | int trigger = MPS_INT(MPS_INTPO_DEF, MPS_INTTR_DEF); |
296 | uint32_t ent0 = APIC_ENT0_LOW | APIC_ENT0_LEV; | | 291 | uint32_t ent0 = APIC_ENT0_LOW | APIC_ENT0_LEV; |
297 | int bus, mpspo, mpstr; | | 292 | int bus, mpspo, mpstr; |
298 | int i; | | 293 | int i; |
299 | | | 294 | |
300 | bus = le32toh(elroy_read32(&r->busnum)) & 0xff; | | 295 | bus = le32toh(elroy_read32(&r->busnum)) & 0xff; |
301 | for (i = 0; i < sc->sc_int_tbl_sz; i++) { | | 296 | for (i = 0; i < sc->sc_int_tbl_sz; i++) { |
302 | if (bus == sc->sc_int_tbl[i].bus && | | 297 | if (bus == sc->sc_int_tbl[i].bus && |
303 | line == sc->sc_int_tbl[i].line) | | 298 | line == sc->sc_int_tbl[i].line) |
304 | trigger = sc->sc_int_tbl[i].trigger; | | 299 | trigger = sc->sc_int_tbl[i].trigger; |
305 | } | | 300 | } |
306 | | | 301 | |
307 | mpspo = (trigger >> MPS_INTPO_SHIFT) & MPS_INTPO_MASK; | | 302 | mpspo = (trigger >> MPS_INTPO_SHIFT) & MPS_INTPO_MASK; |
308 | mpstr = (trigger >> MPS_INTTR_SHIFT) & MPS_INTTR_MASK; | | 303 | mpstr = (trigger >> MPS_INTTR_SHIFT) & MPS_INTTR_MASK; |
309 | | | 304 | |
310 | switch (mpspo) { | | 305 | switch (mpspo) { |
311 | case MPS_INTPO_DEF: | | 306 | case MPS_INTPO_DEF: |
312 | break; | | 307 | break; |
313 | case MPS_INTPO_ACTHI: | | 308 | case MPS_INTPO_ACTHI: |
314 | ent0 &= ~APIC_ENT0_LOW; | | 309 | ent0 &= ~APIC_ENT0_LOW; |
315 | break; | | 310 | break; |
316 | case MPS_INTPO_ACTLO: | | 311 | case MPS_INTPO_ACTLO: |
317 | ent0 |= APIC_ENT0_LOW; | | 312 | ent0 |= APIC_ENT0_LOW; |
318 | break; | | 313 | break; |
319 | default: | | 314 | default: |
320 | panic("unknown MPS interrupt polarity %d", mpspo); | | 315 | panic("unknown MPS interrupt polarity %d", mpspo); |
321 | } | | 316 | } |
322 | | | 317 | |
323 | switch(mpstr) { | | 318 | switch(mpstr) { |
324 | case MPS_INTTR_DEF: | | 319 | case MPS_INTTR_DEF: |
325 | break; | | 320 | break; |
326 | case MPS_INTTR_LEVEL: | | 321 | case MPS_INTTR_LEVEL: |
327 | ent0 |= APIC_ENT0_LEV; | | 322 | ent0 |= APIC_ENT0_LEV; |
328 | break; | | 323 | break; |
329 | case MPS_INTTR_EDGE: | | 324 | case MPS_INTTR_EDGE: |
330 | ent0 &= ~APIC_ENT0_LEV; | | 325 | ent0 &= ~APIC_ENT0_LEV; |
331 | break; | | 326 | break; |
332 | default: | | 327 | default: |
333 | panic("unknown MPS interrupt trigger %d", mpstr); | | 328 | panic("unknown MPS interrupt trigger %d", mpstr); |
334 | } | | 329 | } |
335 | | | 330 | |
336 | return ent0; | | 331 | return ent0; |
337 | } | | 332 | } |
338 | | | 333 | |
339 | #ifdef DEBUG | | 334 | #ifdef DEBUG |
340 | void | | 335 | void |
341 | apic_dump(struct elroy_softc *sc) | | 336 | apic_dump(struct elroy_softc *sc) |
342 | { | | 337 | { |
343 | int i; | | 338 | int i; |
344 | | | 339 | |
345 | for (i = 0; i < sc->sc_nints; i++) | | 340 | for (i = 0; i < sc->sc_nints; i++) |
346 | printf("0x%04x 0x%04x\n", apic_read(sc->sc_regs, APIC_ENT0(i)), | | 341 | printf("0x%04x 0x%04x\n", apic_read(sc->sc_regs, APIC_ENT0(i)), |
347 | apic_read(sc->sc_regs, APIC_ENT1(i))); | | 342 | apic_read(sc->sc_regs, APIC_ENT1(i))); |
348 | | | 343 | |
349 | for (i = 0; i < sc->sc_int_tbl_sz; i++) { | | 344 | for (i = 0; i < sc->sc_int_tbl_sz; i++) { |
350 | printf("type=%x ", sc->sc_int_tbl[i].type); | | 345 | printf("type=%x ", sc->sc_int_tbl[i].type); |
351 | printf("len=%d ", sc->sc_int_tbl[i].len); | | 346 | printf("len=%d ", sc->sc_int_tbl[i].len); |
352 | printf("itype=%d ", sc->sc_int_tbl[i].itype); | | 347 | printf("itype=%d ", sc->sc_int_tbl[i].itype); |
353 | printf("trigger=%x ", sc->sc_int_tbl[i].trigger); | | 348 | printf("trigger=%x ", sc->sc_int_tbl[i].trigger); |
354 | printf("pin=%x ", sc->sc_int_tbl[i].pin); | | 349 | printf("pin=%x ", sc->sc_int_tbl[i].pin); |
355 | printf("bus=%d ", sc->sc_int_tbl[i].bus); | | 350 | printf("bus=%d ", sc->sc_int_tbl[i].bus); |
356 | printf("line=%d ", sc->sc_int_tbl[i].line); | | 351 | printf("line=%d ", sc->sc_int_tbl[i].line); |
357 | printf("addr=%llx\n", sc->sc_int_tbl[i].addr); | | 352 | printf("addr=%llx\n", sc->sc_int_tbl[i].addr); |
358 | } | | 353 | } |
359 | } | | 354 | } |
360 | #endif | | 355 | #endif |