| @@ -1,327 +1,418 @@ | | | @@ -1,327 +1,418 @@ |
1 | /* $NetBSD: pci_intr_machdep.c,v 1.19 2011/04/04 20:37:55 dyoung Exp $ */ | | 1 | /* $NetBSD: pci_intr_machdep.c,v 1.20 2011/08/01 11:08:03 drochner Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1997, 1998, 2009 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1997, 1998, 2009 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, | | 8 | * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, |
9 | * NASA Ames Research Center. | | 9 | * NASA Ames Research Center. |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. | | 15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. Redistributions in binary form must reproduce the above copyright | | 16 | * 2. Redistributions in binary form must reproduce the above copyright |
17 | * notice, this list of conditions and the following disclaimer in the | | 17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. | | 18 | * documentation and/or other materials provided with the distribution. |
19 | * | | 19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. | | 30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | /* | | 33 | /* |
34 | * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. | | 34 | * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. |
35 | * Copyright (c) 1994 Charles M. Hannum. All rights reserved. | | 35 | * Copyright (c) 1994 Charles M. Hannum. All rights reserved. |
36 | * | | 36 | * |
37 | * Redistribution and use in source and binary forms, with or without | | 37 | * Redistribution and use in source and binary forms, with or without |
38 | * modification, are permitted provided that the following conditions | | 38 | * modification, are permitted provided that the following conditions |
39 | * are met: | | 39 | * are met: |
40 | * 1. Redistributions of source code must retain the above copyright | | 40 | * 1. Redistributions of source code must retain the above copyright |
41 | * notice, this list of conditions and the following disclaimer. | | 41 | * notice, this list of conditions and the following disclaimer. |
42 | * 2. Redistributions in binary form must reproduce the above copyright | | 42 | * 2. Redistributions in binary form must reproduce the above copyright |
43 | * notice, this list of conditions and the following disclaimer in the | | 43 | * notice, this list of conditions and the following disclaimer in the |
44 | * documentation and/or other materials provided with the distribution. | | 44 | * documentation and/or other materials provided with the distribution. |
45 | * 3. All advertising materials mentioning features or use of this software | | 45 | * 3. All advertising materials mentioning features or use of this software |
46 | * must display the following acknowledgement: | | 46 | * must display the following acknowledgement: |
47 | * This product includes software developed by Charles M. Hannum. | | 47 | * This product includes software developed by Charles M. Hannum. |
48 | * 4. The name of the author may not be used to endorse or promote products | | 48 | * 4. The name of the author may not be used to endorse or promote products |
49 | * derived from this software without specific prior written permission. | | 49 | * derived from this software without specific prior written permission. |
50 | * | | 50 | * |
51 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 51 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
52 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 52 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
53 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 53 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
54 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 54 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
55 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 55 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
56 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 56 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | | 59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
60 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 60 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
61 | */ | | 61 | */ |
62 | | | 62 | |
63 | /* | | 63 | /* |
64 | * Machine-specific functions for PCI autoconfiguration. | | 64 | * Machine-specific functions for PCI autoconfiguration. |
65 | * | | 65 | * |
66 | * On PCs, there are two methods of generating PCI configuration cycles. | | 66 | * On PCs, there are two methods of generating PCI configuration cycles. |
67 | * We try to detect the appropriate mechanism for this machine and set | | 67 | * We try to detect the appropriate mechanism for this machine and set |
68 | * up a few function pointers to access the correct method directly. | | 68 | * up a few function pointers to access the correct method directly. |
69 | * | | 69 | * |
70 | * The configuration method can be hard-coded in the config file by | | 70 | * The configuration method can be hard-coded in the config file by |
71 | * using `options PCI_CONF_MODE=N', where `N' is the configuration mode | | 71 | * using `options PCI_CONF_MODE=N', where `N' is the configuration mode |
72 | * as defined section 3.6.4.1, `Generating Configuration Cycles'. | | 72 | * as defined section 3.6.4.1, `Generating Configuration Cycles'. |
73 | */ | | 73 | */ |
74 | | | 74 | |
75 | #include <sys/cdefs.h> | | 75 | #include <sys/cdefs.h> |
76 | __KERNEL_RCSID(0, "$NetBSD: pci_intr_machdep.c,v 1.19 2011/04/04 20:37:55 dyoung Exp $"); | | 76 | __KERNEL_RCSID(0, "$NetBSD: pci_intr_machdep.c,v 1.20 2011/08/01 11:08:03 drochner Exp $"); |
77 | | | 77 | |
78 | #include <sys/types.h> | | 78 | #include <sys/types.h> |
79 | #include <sys/param.h> | | 79 | #include <sys/param.h> |
80 | #include <sys/time.h> | | 80 | #include <sys/time.h> |
81 | #include <sys/systm.h> | | 81 | #include <sys/systm.h> |
82 | #include <sys/errno.h> | | 82 | #include <sys/errno.h> |
83 | #include <sys/device.h> | | 83 | #include <sys/device.h> |
84 | #include <sys/intr.h> | | 84 | #include <sys/intr.h> |
| | | 85 | #include <sys/malloc.h> |
85 | | | 86 | |
86 | #include <dev/pci/pcivar.h> | | 87 | #include <dev/pci/pcivar.h> |
87 | | | 88 | |
88 | #include "ioapic.h" | | 89 | #include "ioapic.h" |
89 | #include "eisa.h" | | 90 | #include "eisa.h" |
90 | #include "acpica.h" | | 91 | #include "acpica.h" |
91 | #include "opt_mpbios.h" | | 92 | #include "opt_mpbios.h" |
92 | #include "opt_acpi.h" | | 93 | #include "opt_acpi.h" |
93 | | | 94 | |
94 | #if NIOAPIC > 0 || NACPICA > 0 | | 95 | #if NIOAPIC > 0 || NACPICA > 0 |
95 | #include <machine/i82093var.h> | | 96 | #include <machine/i82093var.h> |
96 | #include <machine/mpconfig.h> | | 97 | #include <machine/mpconfig.h> |
97 | #include <machine/mpbiosvar.h> | | 98 | #include <machine/mpbiosvar.h> |
98 | #include <machine/pic.h> | | 99 | #include <machine/pic.h> |
99 | #endif | | 100 | #endif |
100 | | | 101 | |
101 | #ifdef MPBIOS | | 102 | #ifdef MPBIOS |
102 | #include <machine/mpbiosvar.h> | | 103 | #include <machine/mpbiosvar.h> |
103 | #endif | | 104 | #endif |
104 | | | 105 | |
105 | #if NACPICA > 0 | | 106 | #if NACPICA > 0 |
106 | #include <machine/mpacpi.h> | | 107 | #include <machine/mpacpi.h> |
107 | #endif | | 108 | #endif |
108 | | | 109 | |
109 | #define MPSAFE_MASK 0x80000000 | | 110 | #define MPSAFE_MASK 0x80000000 |
110 | | | 111 | |
111 | int | | 112 | int |
112 | pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp) | | 113 | pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp) |
113 | { | | 114 | { |
114 | int pin = pa->pa_intrpin; | | 115 | int pin = pa->pa_intrpin; |
115 | int line = pa->pa_intrline; | | 116 | int line = pa->pa_intrline; |
116 | pci_chipset_tag_t pc; | | 117 | pci_chipset_tag_t pc; |
117 | #if NIOAPIC > 0 || NACPICA > 0 | | 118 | #if NIOAPIC > 0 || NACPICA > 0 |
118 | int rawpin = pa->pa_rawintrpin; | | 119 | int rawpin = pa->pa_rawintrpin; |
119 | int bus, dev, func; | | 120 | int bus, dev, func; |
120 | #endif | | 121 | #endif |
121 | | | 122 | |
122 | if ((pc = pa->pa_pc) != NULL) { | | 123 | if ((pc = pa->pa_pc) != NULL) { |
123 | if ((pc->pc_present & PCI_OVERRIDE_INTR_MAP) != 0) | | 124 | if ((pc->pc_present & PCI_OVERRIDE_INTR_MAP) != 0) |
124 | return (*pc->pc_ov->ov_intr_map)(pc->pc_ctx, pa, ihp); | | 125 | return (*pc->pc_ov->ov_intr_map)(pc->pc_ctx, pa, ihp); |
125 | if (pc->pc_super != NULL) { | | 126 | if (pc->pc_super != NULL) { |
126 | struct pci_attach_args paclone = *pa; | | 127 | struct pci_attach_args paclone = *pa; |
127 | paclone.pa_pc = pc->pc_super; | | 128 | paclone.pa_pc = pc->pc_super; |
128 | return pci_intr_map(&paclone, ihp); | | 129 | return pci_intr_map(&paclone, ihp); |
129 | } | | 130 | } |
130 | } | | 131 | } |
131 | | | 132 | |
132 | if (pin == 0) { | | 133 | if (pin == 0) { |
133 | /* No IRQ used. */ | | 134 | /* No IRQ used. */ |
134 | goto bad; | | 135 | goto bad; |
135 | } | | 136 | } |
136 | | | 137 | |
137 | *ihp = 0; | | 138 | *ihp = 0; |
138 | | | 139 | |
139 | if (pin > PCI_INTERRUPT_PIN_MAX) { | | 140 | if (pin > PCI_INTERRUPT_PIN_MAX) { |
140 | aprint_normal("pci_intr_map: bad interrupt pin %d\n", pin); | | 141 | aprint_normal("pci_intr_map: bad interrupt pin %d\n", pin); |
141 | goto bad; | | 142 | goto bad; |
142 | } | | 143 | } |
143 | | | 144 | |
144 | #if NIOAPIC > 0 || NACPICA > 0 | | 145 | #if NIOAPIC > 0 || NACPICA > 0 |
145 | pci_decompose_tag(pc, pa->pa_tag, &bus, &dev, &func); | | 146 | pci_decompose_tag(pc, pa->pa_tag, &bus, &dev, &func); |
146 | if (mp_busses != NULL) { | | 147 | if (mp_busses != NULL) { |
147 | if (intr_find_mpmapping(bus, (dev<<2)|(rawpin-1), ihp) == 0) { | | 148 | if (intr_find_mpmapping(bus, (dev<<2)|(rawpin-1), ihp) == 0) { |
148 | if ((*ihp & 0xff) == 0) | | 149 | if ((*ihp & 0xff) == 0) |
149 | *ihp |= line; | | 150 | *ihp |= line; |
150 | return 0; | | 151 | return 0; |
151 | } | | 152 | } |
152 | /* | | 153 | /* |
153 | * No explicit PCI mapping found. This is not fatal, | | 154 | * No explicit PCI mapping found. This is not fatal, |
154 | * we'll try the ISA (or possibly EISA) mappings next. | | 155 | * we'll try the ISA (or possibly EISA) mappings next. |
155 | */ | | 156 | */ |
156 | } | | 157 | } |
157 | #endif | | 158 | #endif |
158 | | | 159 | |
159 | /* | | 160 | /* |
160 | * Section 6.2.4, `Miscellaneous Functions', says that 255 means | | 161 | * Section 6.2.4, `Miscellaneous Functions', says that 255 means |
161 | * `unknown' or `no connection' on a PC. We assume that a device with | | 162 | * `unknown' or `no connection' on a PC. We assume that a device with |
162 | * `no connection' either doesn't have an interrupt (in which case the | | 163 | * `no connection' either doesn't have an interrupt (in which case the |
163 | * pin number should be 0, and would have been noticed above), or | | 164 | * pin number should be 0, and would have been noticed above), or |
164 | * wasn't configured by the BIOS (in which case we punt, since there's | | 165 | * wasn't configured by the BIOS (in which case we punt, since there's |
165 | * no real way we can know how the interrupt lines are mapped in the | | 166 | * no real way we can know how the interrupt lines are mapped in the |
166 | * hardware). | | 167 | * hardware). |
167 | * | | 168 | * |
168 | * XXX | | 169 | * XXX |
169 | * Since IRQ 0 is only used by the clock, and we can't actually be sure | | 170 | * Since IRQ 0 is only used by the clock, and we can't actually be sure |
170 | * that the BIOS did its job, we also recognize that as meaning that | | 171 | * that the BIOS did its job, we also recognize that as meaning that |
171 | * the BIOS has not configured the device. | | 172 | * the BIOS has not configured the device. |
172 | */ | | 173 | */ |
173 | if (line == 0 || line == X86_PCI_INTERRUPT_LINE_NO_CONNECTION) { | | 174 | if (line == 0 || line == X86_PCI_INTERRUPT_LINE_NO_CONNECTION) { |
174 | aprint_normal("pci_intr_map: no mapping for pin %c (line=%02x)\n", | | 175 | aprint_normal("pci_intr_map: no mapping for pin %c (line=%02x)\n", |
175 | '@' + pin, line); | | 176 | '@' + pin, line); |
176 | goto bad; | | 177 | goto bad; |
177 | } else { | | 178 | } else { |
178 | if (line >= NUM_LEGACY_IRQS) { | | 179 | if (line >= NUM_LEGACY_IRQS) { |
179 | aprint_normal("pci_intr_map: bad interrupt line %d\n", line); | | 180 | aprint_normal("pci_intr_map: bad interrupt line %d\n", line); |
180 | goto bad; | | 181 | goto bad; |
181 | } | | 182 | } |
182 | if (line == 2) { | | 183 | if (line == 2) { |
183 | aprint_normal("pci_intr_map: changed line 2 to line 9\n"); | | 184 | aprint_normal("pci_intr_map: changed line 2 to line 9\n"); |
184 | line = 9; | | 185 | line = 9; |
185 | } | | 186 | } |
186 | } | | 187 | } |
187 | #if NIOAPIC > 0 || NACPICA > 0 | | 188 | #if NIOAPIC > 0 || NACPICA > 0 |
188 | if (mp_busses != NULL) { | | 189 | if (mp_busses != NULL) { |
189 | if (intr_find_mpmapping(mp_isa_bus, line, ihp) == 0) { | | 190 | if (intr_find_mpmapping(mp_isa_bus, line, ihp) == 0) { |
190 | if ((*ihp & 0xff) == 0) | | 191 | if ((*ihp & 0xff) == 0) |
191 | *ihp |= line; | | 192 | *ihp |= line; |
192 | return 0; | | 193 | return 0; |
193 | } | | 194 | } |
194 | #if NEISA > 0 | | 195 | #if NEISA > 0 |
195 | if (intr_find_mpmapping(mp_eisa_bus, line, ihp) == 0) { | | 196 | if (intr_find_mpmapping(mp_eisa_bus, line, ihp) == 0) { |
196 | if ((*ihp & 0xff) == 0) | | 197 | if ((*ihp & 0xff) == 0) |
197 | *ihp |= line; | | 198 | *ihp |= line; |
198 | return 0; | | 199 | return 0; |
199 | } | | 200 | } |
200 | #endif | | 201 | #endif |
201 | aprint_normal("pci_intr_map: bus %d dev %d func %d pin %d; line %d\n", | | 202 | aprint_normal("pci_intr_map: bus %d dev %d func %d pin %d; line %d\n", |
202 | bus, dev, func, pin, line); | | 203 | bus, dev, func, pin, line); |
203 | aprint_normal("pci_intr_map: no MP mapping found\n"); | | 204 | aprint_normal("pci_intr_map: no MP mapping found\n"); |
204 | } | | 205 | } |
205 | #endif | | 206 | #endif |
206 | | | 207 | |
207 | *ihp = line; | | 208 | *ihp = line; |
208 | return 0; | | 209 | return 0; |
209 | | | 210 | |
210 | bad: | | 211 | bad: |
211 | *ihp = -1; | | 212 | *ihp = -1; |
212 | return 1; | | 213 | return 1; |
213 | } | | 214 | } |
214 | | | 215 | |
215 | const char * | | 216 | const char * |
216 | pci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih) | | 217 | pci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih) |
217 | { | | 218 | { |
218 | | | 219 | |
219 | if (pc != NULL) { | | 220 | if (pc != NULL) { |
220 | if ((pc->pc_present & PCI_OVERRIDE_INTR_STRING) != 0) | | 221 | if ((pc->pc_present & PCI_OVERRIDE_INTR_STRING) != 0) |
221 | return (*pc->pc_ov->ov_intr_string)(pc->pc_ctx, pc, ih); | | 222 | return (*pc->pc_ov->ov_intr_string)(pc->pc_ctx, pc, ih); |
222 | if (pc->pc_super != NULL) | | 223 | if (pc->pc_super != NULL) |
223 | return pci_intr_string(pc->pc_super, ih); | | 224 | return pci_intr_string(pc->pc_super, ih); |
224 | } | | 225 | } |
225 | | | 226 | |
226 | return intr_string(ih & ~MPSAFE_MASK); | | 227 | return intr_string(ih & ~MPSAFE_MASK); |
227 | } | | 228 | } |
228 | | | 229 | |
229 | | | 230 | |
230 | const struct evcnt * | | 231 | const struct evcnt * |
231 | pci_intr_evcnt(pci_chipset_tag_t pc, pci_intr_handle_t ih) | | 232 | pci_intr_evcnt(pci_chipset_tag_t pc, pci_intr_handle_t ih) |
232 | { | | 233 | { |
233 | | | 234 | |
234 | if (pc != NULL) { | | 235 | if (pc != NULL) { |
235 | if ((pc->pc_present & PCI_OVERRIDE_INTR_EVCNT) != 0) | | 236 | if ((pc->pc_present & PCI_OVERRIDE_INTR_EVCNT) != 0) |
236 | return (*pc->pc_ov->ov_intr_evcnt)(pc->pc_ctx, pc, ih); | | 237 | return (*pc->pc_ov->ov_intr_evcnt)(pc->pc_ctx, pc, ih); |
237 | if (pc->pc_super != NULL) | | 238 | if (pc->pc_super != NULL) |
238 | return pci_intr_evcnt(pc->pc_super, ih); | | 239 | return pci_intr_evcnt(pc->pc_super, ih); |
239 | } | | 240 | } |
240 | | | 241 | |
241 | /* XXX for now, no evcnt parent reported */ | | 242 | /* XXX for now, no evcnt parent reported */ |
242 | return NULL; | | 243 | return NULL; |
243 | } | | 244 | } |
244 | | | 245 | |
245 | int | | 246 | int |
246 | pci_intr_setattr(pci_chipset_tag_t pc, pci_intr_handle_t *ih, | | 247 | pci_intr_setattr(pci_chipset_tag_t pc, pci_intr_handle_t *ih, |
247 | int attr, uint64_t data) | | 248 | int attr, uint64_t data) |
248 | { | | 249 | { |
249 | | | 250 | |
250 | switch (attr) { | | 251 | switch (attr) { |
251 | case PCI_INTR_MPSAFE: | | 252 | case PCI_INTR_MPSAFE: |
252 | if (data) { | | 253 | if (data) { |
253 | *ih |= MPSAFE_MASK; | | 254 | *ih |= MPSAFE_MASK; |
254 | } else { | | 255 | } else { |
255 | *ih &= ~MPSAFE_MASK; | | 256 | *ih &= ~MPSAFE_MASK; |
256 | } | | 257 | } |
257 | /* XXX Set live if already mapped. */ | | 258 | /* XXX Set live if already mapped. */ |
258 | return 0; | | 259 | return 0; |
259 | default: | | 260 | default: |
260 | return ENODEV; | | 261 | return ENODEV; |
261 | } | | 262 | } |
262 | } | | 263 | } |
263 | | | 264 | |
264 | void * | | 265 | void * |
265 | pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, | | 266 | pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, |
266 | int level, int (*func)(void *), void *arg) | | 267 | int level, int (*func)(void *), void *arg) |
267 | { | | 268 | { |
268 | int pin, irq; | | 269 | int pin, irq; |
269 | struct pic *pic; | | 270 | struct pic *pic; |
270 | #if NIOAPIC > 0 | | 271 | #if NIOAPIC > 0 |
271 | struct ioapic_softc *ioapic; | | 272 | struct ioapic_softc *ioapic; |
272 | #endif | | 273 | #endif |
273 | bool mpsafe; | | 274 | bool mpsafe; |
274 | | | 275 | |
275 | if (pc != NULL) { | | 276 | if (pc != NULL) { |
276 | if ((pc->pc_present & PCI_OVERRIDE_INTR_ESTABLISH) != 0) { | | 277 | if ((pc->pc_present & PCI_OVERRIDE_INTR_ESTABLISH) != 0) { |
277 | return (*pc->pc_ov->ov_intr_establish)(pc->pc_ctx, | | 278 | return (*pc->pc_ov->ov_intr_establish)(pc->pc_ctx, |
278 | pc, ih, level, func, arg); | | 279 | pc, ih, level, func, arg); |
279 | } | | 280 | } |
280 | if (pc->pc_super != NULL) { | | 281 | if (pc->pc_super != NULL) { |
281 | return pci_intr_establish(pc->pc_super, ih, level, func, | | 282 | return pci_intr_establish(pc->pc_super, ih, level, func, |
282 | arg); | | 283 | arg); |
283 | } | | 284 | } |
284 | } | | 285 | } |
285 | | | 286 | |
286 | pic = &i8259_pic; | | 287 | pic = &i8259_pic; |
287 | pin = irq = (ih & ~MPSAFE_MASK); | | 288 | pin = irq = (ih & ~MPSAFE_MASK); |
288 | mpsafe = ((ih & MPSAFE_MASK) != 0); | | 289 | mpsafe = ((ih & MPSAFE_MASK) != 0); |
289 | | | 290 | |
290 | #if NIOAPIC > 0 | | 291 | #if NIOAPIC > 0 |
291 | if (ih & APIC_INT_VIA_APIC) { | | 292 | if (ih & APIC_INT_VIA_APIC) { |
292 | ioapic = ioapic_find(APIC_IRQ_APIC(ih)); | | 293 | ioapic = ioapic_find(APIC_IRQ_APIC(ih)); |
293 | if (ioapic == NULL) { | | 294 | if (ioapic == NULL) { |
294 | aprint_normal("pci_intr_establish: bad ioapic %d\n", | | 295 | aprint_normal("pci_intr_establish: bad ioapic %d\n", |
295 | APIC_IRQ_APIC(ih)); | | 296 | APIC_IRQ_APIC(ih)); |
296 | return NULL; | | 297 | return NULL; |
297 | } | | 298 | } |
298 | pic = &ioapic->sc_pic; | | 299 | pic = &ioapic->sc_pic; |
299 | pin = APIC_IRQ_PIN(ih); | | 300 | pin = APIC_IRQ_PIN(ih); |
300 | irq = APIC_IRQ_LEGACY_IRQ(ih); | | 301 | irq = APIC_IRQ_LEGACY_IRQ(ih); |
301 | if (irq < 0 || irq >= NUM_LEGACY_IRQS) | | 302 | if (irq < 0 || irq >= NUM_LEGACY_IRQS) |
302 | irq = -1; | | 303 | irq = -1; |
303 | } | | 304 | } |
304 | #endif | | 305 | #endif |
305 | | | 306 | |
306 | return intr_establish(irq, pic, pin, IST_LEVEL, level, func, arg, | | 307 | return intr_establish(irq, pic, pin, IST_LEVEL, level, func, arg, |
307 | mpsafe); | | 308 | mpsafe); |
308 | } | | 309 | } |
309 | | | 310 | |
310 | void | | 311 | void |
311 | pci_intr_disestablish(pci_chipset_tag_t pc, void *cookie) | | 312 | pci_intr_disestablish(pci_chipset_tag_t pc, void *cookie) |
312 | { | | 313 | { |
313 | | | 314 | |
314 | if (pc != NULL) { | | 315 | if (pc != NULL) { |
315 | if ((pc->pc_present & PCI_OVERRIDE_INTR_ESTABLISH) != 0) { | | 316 | if ((pc->pc_present & PCI_OVERRIDE_INTR_ESTABLISH) != 0) { |
316 | (*pc->pc_ov->ov_intr_disestablish)(pc->pc_ctx, | | 317 | (*pc->pc_ov->ov_intr_disestablish)(pc->pc_ctx, |
317 | pc, cookie); | | 318 | pc, cookie); |
318 | return; | | 319 | return; |
319 | } | | 320 | } |
320 | if (pc->pc_super != NULL) { | | 321 | if (pc->pc_super != NULL) { |
321 | pci_intr_disestablish(pc->pc_super, cookie); | | 322 | pci_intr_disestablish(pc->pc_super, cookie); |
322 | return; | | 323 | return; |
323 | } | | 324 | } |
324 | } | | 325 | } |
325 | | | 326 | |
326 | intr_disestablish(cookie); | | 327 | intr_disestablish(cookie); |
327 | } | | 328 | } |
| | | 329 | |
| | | 330 | #if NIOAPIC > 0 |
| | | 331 | /* |
| | | 332 | * experimental support for MSI, does support a single vector, |
| | | 333 | * no MSI-X, 8-bit APIC IDs |
| | | 334 | * (while it doesn't need the ioapic technically, it borrows |
| | | 335 | * from its kernel support) |
| | | 336 | */ |
| | | 337 | |
| | | 338 | /* dummies, needed by common intr_establish code */ |
| | | 339 | static void |
| | | 340 | msipic_hwmask(struct pic *pic, int pin) |
| | | 341 | { |
| | | 342 | } |
| | | 343 | static void |
| | | 344 | msipic_addroute(struct pic *pic, struct cpu_info *ci, |
| | | 345 | int pin, int vec, int type) |
| | | 346 | { |
| | | 347 | } |
| | | 348 | |
| | | 349 | static struct pic msi_pic = { |
| | | 350 | .pic_name = "msi", |
| | | 351 | .pic_type = PIC_SOFT, |
| | | 352 | .pic_vecbase = 0, |
| | | 353 | .pic_apicid = 0, |
| | | 354 | .pic_lock = __SIMPLELOCK_UNLOCKED, |
| | | 355 | .pic_hwmask = msipic_hwmask, |
| | | 356 | .pic_hwunmask = msipic_hwmask, |
| | | 357 | .pic_addroute = msipic_addroute, |
| | | 358 | .pic_delroute = msipic_addroute, |
| | | 359 | .pic_edge_stubs = ioapic_edge_stubs, |
| | | 360 | }; |
| | | 361 | |
| | | 362 | struct msi_hdl { |
| | | 363 | struct intrhand *ih; |
| | | 364 | pci_chipset_tag_t pc; |
| | | 365 | pcitag_t tag; |
| | | 366 | int co; |
| | | 367 | }; |
| | | 368 | |
| | | 369 | void * |
| | | 370 | pci_msi_establish(struct pci_attach_args *pa, int level, |
| | | 371 | int (*func)(void *), void *arg) |
| | | 372 | { |
| | | 373 | int co; |
| | | 374 | void *ih; |
| | | 375 | struct msi_hdl *msih; |
| | | 376 | struct cpu_info *ci; |
| | | 377 | struct intrsource *s; |
| | | 378 | u_int32_t cr; |
| | | 379 | |
| | | 380 | if (!pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_MSI, &co, 0)) |
| | | 381 | return NULL; |
| | | 382 | |
| | | 383 | ih = intr_establish(-1, &msi_pic, -1, IST_EDGE, level, |
| | | 384 | func, arg, 0); |
| | | 385 | if (!ih) |
| | | 386 | return NULL; |
| | | 387 | |
| | | 388 | msih = malloc(sizeof(*msih), M_DEVBUF, M_WAITOK); |
| | | 389 | msih->ih = ih; |
| | | 390 | msih->pc = pa->pa_pc; |
| | | 391 | msih->tag = pa->pa_tag; |
| | | 392 | msih->co = co; |
| | | 393 | |
| | | 394 | ci = msih->ih->ih_cpu; |
| | | 395 | s = ci->ci_isources[msih->ih->ih_slot]; |
| | | 396 | cr = pci_conf_read(pa->pa_pc, pa->pa_tag, co); |
| | | 397 | pci_conf_write(pa->pa_pc, pa->pa_tag, co + 4, |
| | | 398 | 0xfee00000 | ci->ci_cpuid << 12); |
| | | 399 | if (cr & 0x800000) { |
| | | 400 | pci_conf_write(pa->pa_pc, pa->pa_tag, co + 8, 0); |
| | | 401 | pci_conf_write(pa->pa_pc, pa->pa_tag, co + 12, |
| | | 402 | s->is_idtvec | 0x4000); |
| | | 403 | } else |
| | | 404 | pci_conf_write(pa->pa_pc, pa->pa_tag, co + 8, |
| | | 405 | s->is_idtvec | 0x4000); |
| | | 406 | pci_conf_write(pa->pa_pc, pa->pa_tag, co, 0x10000); |
| | | 407 | return ih; |
| | | 408 | } |
| | | 409 | |
| | | 410 | void |
| | | 411 | pci_msi_disestablish(void *ih) |
| | | 412 | { |
| | | 413 | struct msi_hdl *msih = ih; |
| | | 414 | |
| | | 415 | pci_conf_write(msih->pc, msih->tag, msih->co, 0); |
| | | 416 | intr_disestablish(msih->ih); |
| | | 417 | } |
| | | 418 | #endif |