File: | arch/amd64/pci/pci_machdep.c |
Warning: | line 608, column 11 The left operand of '==' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: pci_machdep.c,v 1.77 2021/03/11 11:16:55 jsg Exp $ */ | |||
2 | /* $NetBSD: pci_machdep.c,v 1.3 2003/05/07 21:33:58 fvdl Exp $ */ | |||
3 | ||||
4 | /*- | |||
5 | * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. | |||
6 | * All rights reserved. | |||
7 | * | |||
8 | * This code is derived from software contributed to The NetBSD Foundation | |||
9 | * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, | |||
10 | * NASA Ames Research Center. | |||
11 | * | |||
12 | * Redistribution and use in source and binary forms, with or without | |||
13 | * modification, are permitted provided that the following conditions | |||
14 | * are met: | |||
15 | * 1. Redistributions of source code must retain the above copyright | |||
16 | * notice, this list of conditions and the following disclaimer. | |||
17 | * 2. Redistributions in binary form must reproduce the above copyright | |||
18 | * notice, this list of conditions and the following disclaimer in the | |||
19 | * documentation and/or other materials provided with the distribution. | |||
20 | * | |||
21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |||
22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |||
23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||
24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |||
25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
31 | * POSSIBILITY OF SUCH DAMAGE. | |||
32 | */ | |||
33 | ||||
34 | /* | |||
35 | * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. | |||
36 | * Copyright (c) 1994 Charles M. Hannum. All rights reserved. | |||
37 | * | |||
38 | * Redistribution and use in source and binary forms, with or without | |||
39 | * modification, are permitted provided that the following conditions | |||
40 | * are met: | |||
41 | * 1. Redistributions of source code must retain the above copyright | |||
42 | * notice, this list of conditions and the following disclaimer. | |||
43 | * 2. Redistributions in binary form must reproduce the above copyright | |||
44 | * notice, this list of conditions and the following disclaimer in the | |||
45 | * documentation and/or other materials provided with the distribution. | |||
46 | * 3. All advertising materials mentioning features or use of this software | |||
47 | * must display the following acknowledgement: | |||
48 | * This product includes software developed by Charles M. Hannum. | |||
49 | * 4. The name of the author may not be used to endorse or promote products | |||
50 | * derived from this software without specific prior written permission. | |||
51 | * | |||
52 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
53 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
54 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
55 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
56 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
57 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
58 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
59 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
60 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
61 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
62 | */ | |||
63 | ||||
64 | /* | |||
65 | * Machine-specific functions for PCI autoconfiguration. | |||
66 | */ | |||
67 | ||||
68 | #include <sys/param.h> | |||
69 | #include <sys/systm.h> | |||
70 | #include <sys/extent.h> | |||
71 | #include <sys/malloc.h> | |||
72 | ||||
73 | #include <machine/bus.h> | |||
74 | ||||
75 | #include <machine/pio.h> | |||
76 | #include <machine/intr.h> | |||
77 | #include <machine/biosvar.h> | |||
78 | ||||
79 | #include <dev/isa/isareg.h> | |||
80 | #include <dev/pci/pcivar.h> | |||
81 | #include <dev/pci/pcireg.h> | |||
82 | #include <dev/pci/pcidevs.h> | |||
83 | #include <dev/pci/ppbreg.h> | |||
84 | ||||
85 | #include "ioapic.h" | |||
86 | ||||
87 | #if NIOAPIC1 > 0 | |||
88 | #include <machine/i82093var.h> | |||
89 | #include <machine/mpbiosvar.h> | |||
90 | #endif | |||
91 | ||||
92 | #include "acpi.h" | |||
93 | ||||
94 | #include "acpidmar.h" | |||
95 | #if NACPIDMAR1 > 0 | |||
96 | #include <dev/acpi/acpidmar.h> | |||
97 | #endif | |||
98 | ||||
99 | /* | |||
100 | * Memory Mapped Configuration space access. | |||
101 | * | |||
102 | * Since mapping the whole configuration space will cost us up to | |||
103 | * 256MB of kernel virtual memory, we use separate mappings per bus. | |||
104 | * The mappings are created on-demand, such that we only use kernel | |||
105 | * virtual memory for busses that are actually present. | |||
106 | */ | |||
107 | bus_addr_t pci_mcfg_addr; | |||
108 | int pci_mcfg_min_bus, pci_mcfg_max_bus; | |||
109 | bus_space_tag_t pci_mcfgt; | |||
110 | bus_space_handle_t pci_mcfgh[256]; | |||
111 | ||||
112 | struct mutex pci_conf_lock = MUTEX_INITIALIZER(IPL_HIGH){ ((void *)0), ((((0xd)) > 0x0 && ((0xd)) < 0x9 ) ? 0x9 : ((0xd))), 0x0 }; | |||
113 | ||||
114 | #define PCI_CONF_LOCK()do { mtx_enter(&pci_conf_lock); } while (0) \ | |||
115 | do { \ | |||
116 | mtx_enter(&pci_conf_lock); \ | |||
117 | } while (0) | |||
118 | ||||
119 | #define PCI_CONF_UNLOCK()do { mtx_leave(&pci_conf_lock); } while (0) \ | |||
120 | do { \ | |||
121 | mtx_leave(&pci_conf_lock); \ | |||
122 | } while (0) | |||
123 | ||||
124 | #define PCI_MODE1_ENABLE0x80000000UL 0x80000000UL | |||
125 | #define PCI_MODE1_ADDRESS_REG0x0cf8 0x0cf8 | |||
126 | #define PCI_MODE1_DATA_REG0x0cfc 0x0cfc | |||
127 | ||||
128 | /* | |||
129 | * PCI doesn't have any special needs; just use the generic versions | |||
130 | * of these functions. | |||
131 | */ | |||
132 | struct bus_dma_tag pci_bus_dma_tag = { | |||
133 | NULL((void *)0), /* _may_bounce */ | |||
134 | _bus_dmamap_create, | |||
135 | _bus_dmamap_destroy, | |||
136 | _bus_dmamap_load, | |||
137 | _bus_dmamap_load_mbuf, | |||
138 | _bus_dmamap_load_uio, | |||
139 | _bus_dmamap_load_raw, | |||
140 | _bus_dmamap_unload, | |||
141 | _bus_dmamap_sync, | |||
142 | _bus_dmamem_alloc, | |||
143 | _bus_dmamem_alloc_range, | |||
144 | _bus_dmamem_free, | |||
145 | _bus_dmamem_map, | |||
146 | _bus_dmamem_unmap, | |||
147 | _bus_dmamem_mmap, | |||
148 | }; | |||
149 | ||||
150 | void | |||
151 | pci_mcfg_init(bus_space_tag_t iot, bus_addr_t addr, int segment, | |||
152 | int min_bus, int max_bus) | |||
153 | { | |||
154 | if (segment == 0) { | |||
155 | pci_mcfgt = iot; | |||
156 | pci_mcfg_addr = addr; | |||
157 | pci_mcfg_min_bus = min_bus; | |||
158 | pci_mcfg_max_bus = max_bus; | |||
159 | } | |||
160 | } | |||
161 | ||||
162 | pci_chipset_tag_t | |||
163 | pci_lookup_segment(int segment) | |||
164 | { | |||
165 | KASSERT(segment == 0)((segment == 0) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/arch/amd64/pci/pci_machdep.c" , 165, "segment == 0")); | |||
166 | return NULL((void *)0); | |||
167 | } | |||
168 | ||||
169 | void | |||
170 | pci_attach_hook(struct device *parent, struct device *self, | |||
171 | struct pcibus_attach_args *pba) | |||
172 | { | |||
173 | } | |||
174 | ||||
175 | int | |||
176 | pci_bus_maxdevs(pci_chipset_tag_t pc, int busno) | |||
177 | { | |||
178 | return (32); | |||
179 | } | |||
180 | ||||
181 | pcitag_t | |||
182 | pci_make_tag(pci_chipset_tag_t pc, int bus, int device, int function) | |||
183 | { | |||
184 | if (bus >= 256 || device >= 32 || function >= 8) | |||
185 | panic("pci_make_tag: bad request"); | |||
186 | ||||
187 | return (PCI_MODE1_ENABLE0x80000000UL | | |||
188 | (bus << 16) | (device << 11) | (function << 8)); | |||
189 | } | |||
190 | ||||
191 | void | |||
192 | pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp, int *fp) | |||
193 | { | |||
194 | if (bp != NULL((void *)0)) | |||
195 | *bp = (tag >> 16) & 0xff; | |||
196 | if (dp != NULL((void *)0)) | |||
197 | *dp = (tag >> 11) & 0x1f; | |||
198 | if (fp != NULL((void *)0)) | |||
199 | *fp = (tag >> 8) & 0x7; | |||
200 | } | |||
201 | ||||
202 | int | |||
203 | pci_conf_size(pci_chipset_tag_t pc, pcitag_t tag) | |||
204 | { | |||
205 | int bus; | |||
206 | ||||
207 | if (pci_mcfg_addr) { | |||
208 | pci_decompose_tag(pc, tag, &bus, NULL((void *)0), NULL((void *)0)); | |||
209 | if (bus >= pci_mcfg_min_bus && bus <= pci_mcfg_max_bus) | |||
210 | return PCIE_CONFIG_SPACE_SIZE0x1000; | |||
211 | } | |||
212 | ||||
213 | return PCI_CONFIG_SPACE_SIZE0x100; | |||
214 | } | |||
215 | ||||
216 | void | |||
217 | pci_mcfg_map_bus(int bus) | |||
218 | { | |||
219 | if (pci_mcfgh[bus]) | |||
220 | return; | |||
221 | ||||
222 | if (bus_space_map(pci_mcfgt, pci_mcfg_addr + (bus << 20), 1 << 20, | |||
223 | 0, &pci_mcfgh[bus])) | |||
224 | panic("pci_conf_read: cannot map mcfg space"); | |||
225 | } | |||
226 | ||||
227 | pcireg_t | |||
228 | pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg) | |||
229 | { | |||
230 | pcireg_t data; | |||
231 | int bus; | |||
232 | ||||
233 | KASSERT((reg & 0x3) == 0)(((reg & 0x3) == 0) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/arch/amd64/pci/pci_machdep.c" , 233, "(reg & 0x3) == 0")); | |||
234 | ||||
235 | if (pci_mcfg_addr && reg >= PCI_CONFIG_SPACE_SIZE0x100) { | |||
236 | pci_decompose_tag(pc, tag, &bus, NULL((void *)0), NULL((void *)0)); | |||
237 | if (bus >= pci_mcfg_min_bus && bus <= pci_mcfg_max_bus) { | |||
238 | pci_mcfg_map_bus(bus); | |||
239 | data = bus_space_read_4(pci_mcfgt, pci_mcfgh[bus],((pci_mcfgt)->read_4((pci_mcfgh[bus]), ((tag & 0x000ff00 ) << 4 | reg))) | |||
240 | (tag & 0x000ff00) << 4 | reg)((pci_mcfgt)->read_4((pci_mcfgh[bus]), ((tag & 0x000ff00 ) << 4 | reg))); | |||
241 | return data; | |||
242 | } | |||
243 | } | |||
244 | ||||
245 | PCI_CONF_LOCK()do { mtx_enter(&pci_conf_lock); } while (0); | |||
246 | outl(PCI_MODE1_ADDRESS_REG, tag | reg)( (__builtin_constant_p((0x0cf8)) && (0x0cf8) < 0x100 ) ? __outlc(0x0cf8, tag | reg) : __outl(0x0cf8, tag | reg)); | |||
247 | data = inl(PCI_MODE1_DATA_REG)( (__builtin_constant_p((0x0cfc)) && (0x0cfc) < 0x100 ) ? __inlc(0x0cfc) : __inl(0x0cfc)); | |||
248 | outl(PCI_MODE1_ADDRESS_REG, 0)( (__builtin_constant_p((0x0cf8)) && (0x0cf8) < 0x100 ) ? __outlc(0x0cf8, 0) : __outl(0x0cf8, 0)); | |||
249 | PCI_CONF_UNLOCK()do { mtx_leave(&pci_conf_lock); } while (0); | |||
250 | ||||
251 | return data; | |||
252 | } | |||
253 | ||||
254 | void | |||
255 | pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data) | |||
256 | { | |||
257 | int bus; | |||
258 | ||||
259 | KASSERT((reg & 0x3) == 0)(((reg & 0x3) == 0) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/arch/amd64/pci/pci_machdep.c" , 259, "(reg & 0x3) == 0")); | |||
260 | ||||
261 | if (pci_mcfg_addr && reg >= PCI_CONFIG_SPACE_SIZE0x100) { | |||
262 | pci_decompose_tag(pc, tag, &bus, NULL((void *)0), NULL((void *)0)); | |||
263 | if (bus >= pci_mcfg_min_bus && bus <= pci_mcfg_max_bus) { | |||
264 | pci_mcfg_map_bus(bus); | |||
265 | bus_space_write_4(pci_mcfgt, pci_mcfgh[bus],((pci_mcfgt)->write_4((pci_mcfgh[bus]), ((tag & 0x000ff00 ) << 4 | reg), (data))) | |||
266 | (tag & 0x000ff00) << 4 | reg, data)((pci_mcfgt)->write_4((pci_mcfgh[bus]), ((tag & 0x000ff00 ) << 4 | reg), (data))); | |||
267 | return; | |||
268 | } | |||
269 | } | |||
270 | ||||
271 | PCI_CONF_LOCK()do { mtx_enter(&pci_conf_lock); } while (0); | |||
272 | outl(PCI_MODE1_ADDRESS_REG, tag | reg)( (__builtin_constant_p((0x0cf8)) && (0x0cf8) < 0x100 ) ? __outlc(0x0cf8, tag | reg) : __outl(0x0cf8, tag | reg)); | |||
273 | outl(PCI_MODE1_DATA_REG, data)( (__builtin_constant_p((0x0cfc)) && (0x0cfc) < 0x100 ) ? __outlc(0x0cfc, data) : __outl(0x0cfc, data)); | |||
274 | outl(PCI_MODE1_ADDRESS_REG, 0)( (__builtin_constant_p((0x0cf8)) && (0x0cf8) < 0x100 ) ? __outlc(0x0cf8, 0) : __outl(0x0cf8, 0)); | |||
275 | PCI_CONF_UNLOCK()do { mtx_leave(&pci_conf_lock); } while (0); | |||
276 | } | |||
277 | ||||
278 | int | |||
279 | pci_msix_table_map(pci_chipset_tag_t pc, pcitag_t tag, | |||
280 | bus_space_tag_t memt, bus_space_handle_t *memh) | |||
281 | { | |||
282 | bus_addr_t base; | |||
283 | pcireg_t reg, table, type; | |||
284 | int bir, offset; | |||
285 | int off, tblsz; | |||
286 | ||||
287 | if (pci_get_capability(pc, tag, PCI_CAP_MSIX0x11, &off, ®) == 0) | |||
288 | panic("%s: no msix capability", __func__); | |||
289 | ||||
290 | table = pci_conf_read(pc, tag, off + PCI_MSIX_TABLE0x04); | |||
291 | bir = (table & PCI_MSIX_TABLE_BIR0x00000007); | |||
292 | offset = (table & PCI_MSIX_TABLE_OFF~(0x00000007)); | |||
293 | tblsz = PCI_MSIX_MC_TBLSZ(reg)(((reg) & 0x07ff0000) >> 16) + 1; | |||
294 | ||||
295 | bir = PCI_MAPREG_START0x10 + bir * 4; | |||
296 | type = pci_mapreg_type(pc, tag, bir); | |||
297 | if (pci_mapreg_info(pc, tag, bir, type, &base, NULL((void *)0), NULL((void *)0)) || | |||
298 | _bus_space_map(memt, base + offset, tblsz * 16, 0, memh)) | |||
299 | return -1; | |||
300 | ||||
301 | return 0; | |||
302 | } | |||
303 | ||||
304 | void | |||
305 | pci_msix_table_unmap(pci_chipset_tag_t pc, pcitag_t tag, | |||
306 | bus_space_tag_t memt, bus_space_handle_t memh) | |||
307 | { | |||
308 | pcireg_t reg; | |||
309 | int tblsz; | |||
310 | ||||
311 | if (pci_get_capability(pc, tag, PCI_CAP_MSIX0x11, NULL((void *)0), ®) == 0) | |||
312 | panic("%s: no msix capability", __func__); | |||
313 | ||||
314 | tblsz = PCI_MSIX_MC_TBLSZ(reg)(((reg) & 0x07ff0000) >> 16) + 1; | |||
315 | _bus_space_unmap(memt, memh, tblsz * 16, NULL((void *)0)); | |||
316 | } | |||
317 | ||||
318 | void msi_hwmask(struct pic *, int); | |||
319 | void msi_hwunmask(struct pic *, int); | |||
320 | void msi_addroute(struct pic *, struct cpu_info *, int, int, int); | |||
321 | void msi_delroute(struct pic *, struct cpu_info *, int, int, int); | |||
322 | ||||
323 | struct pic msi_pic = { | |||
324 | {0, {NULL((void *)0)}, NULL((void *)0), 0, "msi", NULL((void *)0), 0, 0}, | |||
325 | PIC_MSI3, | |||
326 | #ifdef MULTIPROCESSOR1 | |||
327 | {}, | |||
328 | #endif | |||
329 | msi_hwmask, | |||
330 | msi_hwunmask, | |||
331 | msi_addroute, | |||
332 | msi_delroute, | |||
333 | NULL((void *)0), | |||
334 | ioapic_edge_stubs | |||
335 | }; | |||
336 | ||||
337 | void | |||
338 | msi_hwmask(struct pic *pic, int pin) | |||
339 | { | |||
340 | } | |||
341 | ||||
342 | void | |||
343 | msi_hwunmask(struct pic *pic, int pin) | |||
344 | { | |||
345 | } | |||
346 | ||||
347 | void | |||
348 | msi_addroute(struct pic *pic, struct cpu_info *ci, int pin, int vec, int type) | |||
349 | { | |||
350 | pci_chipset_tag_t pc = NULL((void *)0); /* XXX */ | |||
351 | pcitag_t tag = pin; | |||
352 | pcireg_t reg, addr; | |||
353 | int off; | |||
354 | ||||
355 | if (pci_get_capability(pc, tag, PCI_CAP_MSI0x05, &off, ®) == 0) | |||
356 | panic("%s: no msi capability", __func__); | |||
357 | ||||
358 | addr = 0xfee00000UL | (ci->ci_apicid << 12); | |||
359 | ||||
360 | if (reg & PCI_MSI_MC_C640x00800000) { | |||
361 | pci_conf_write(pc, tag, off + PCI_MSI_MA0x04, addr); | |||
362 | pci_conf_write(pc, tag, off + PCI_MSI_MAU320x08, 0); | |||
363 | pci_conf_write(pc, tag, off + PCI_MSI_MD640x0c, vec); | |||
364 | } else { | |||
365 | pci_conf_write(pc, tag, off + PCI_MSI_MA0x04, addr); | |||
366 | pci_conf_write(pc, tag, off + PCI_MSI_MD320x08, vec); | |||
367 | } | |||
368 | pci_conf_write(pc, tag, off, reg | PCI_MSI_MC_MSIE0x00010000); | |||
369 | } | |||
370 | ||||
371 | void | |||
372 | msi_delroute(struct pic *pic, struct cpu_info *ci, int pin, int vec, int type) | |||
373 | { | |||
374 | pci_chipset_tag_t pc = NULL((void *)0); /* XXX */ | |||
375 | pcitag_t tag = pin; | |||
376 | pcireg_t reg; | |||
377 | int off; | |||
378 | ||||
379 | if (pci_get_capability(pc, tag, PCI_CAP_MSI0x05, &off, ®)) | |||
380 | pci_conf_write(pc, tag, off, reg & ~PCI_MSI_MC_MSIE0x00010000); | |||
381 | } | |||
382 | ||||
383 | int | |||
384 | pci_intr_map_msi(struct pci_attach_args *pa, pci_intr_handle_t *ihp) | |||
385 | { | |||
386 | pci_chipset_tag_t pc = pa->pa_pc; | |||
387 | pcitag_t tag = pa->pa_tag; | |||
388 | ||||
389 | if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED0x20) == 0 || mp_busses == NULL((void *)0) || | |||
390 | pci_get_capability(pc, tag, PCI_CAP_MSI0x05, NULL((void *)0), NULL((void *)0)) == 0) | |||
391 | return 1; | |||
392 | ||||
393 | ihp->tag = tag; | |||
394 | ihp->line = APIC_INT_VIA_MSG0x20000000; | |||
395 | ihp->pin = 0; | |||
396 | return 0; | |||
397 | } | |||
398 | ||||
399 | void msix_hwmask(struct pic *, int); | |||
400 | void msix_hwunmask(struct pic *, int); | |||
401 | void msix_addroute(struct pic *, struct cpu_info *, int, int, int); | |||
402 | void msix_delroute(struct pic *, struct cpu_info *, int, int, int); | |||
403 | ||||
404 | struct pic msix_pic = { | |||
405 | {0, {NULL((void *)0)}, NULL((void *)0), 0, "msix", NULL((void *)0), 0, 0}, | |||
406 | PIC_MSI3, | |||
407 | #ifdef MULTIPROCESSOR1 | |||
408 | {}, | |||
409 | #endif | |||
410 | msix_hwmask, | |||
411 | msix_hwunmask, | |||
412 | msix_addroute, | |||
413 | msix_delroute, | |||
414 | NULL((void *)0), | |||
415 | ioapic_edge_stubs | |||
416 | }; | |||
417 | ||||
418 | /* | |||
419 | * We pack the MSI-X vector number into the lower 8 bits of the PCI | |||
420 | * tag and use that as the MSI-X "PIC" pin number. This allows us to | |||
421 | * address 256 MSI-X vectors which ought to be enough for anybody. | |||
422 | */ | |||
423 | #define PCI_MSIX_VEC_MASK0xff 0xff | |||
424 | #define PCI_MSIX_VEC(pin)((pin) & 0xff) ((pin) & PCI_MSIX_VEC_MASK0xff) | |||
425 | #define PCI_MSIX_TAG(pin)((pin) & ~0xff) ((pin) & ~PCI_MSIX_VEC_MASK0xff) | |||
426 | #define PCI_MSIX_PIN(tag, vec)((tag) | (vec)) ((tag) | (vec)) | |||
427 | ||||
428 | void | |||
429 | msix_hwmask(struct pic *pic, int pin) | |||
430 | { | |||
431 | } | |||
432 | ||||
433 | void | |||
434 | msix_hwunmask(struct pic *pic, int pin) | |||
435 | { | |||
436 | } | |||
437 | ||||
438 | void | |||
439 | msix_addroute(struct pic *pic, struct cpu_info *ci, int pin, int vec, int type) | |||
440 | { | |||
441 | pci_chipset_tag_t pc = NULL((void *)0); /* XXX */ | |||
442 | bus_space_tag_t memt = X86_BUS_SPACE_MEM(&x86_bus_space_mem_ops); /* XXX */ | |||
443 | bus_space_handle_t memh; | |||
444 | pcitag_t tag = PCI_MSIX_TAG(pin)((pin) & ~0xff); | |||
445 | int entry = PCI_MSIX_VEC(pin)((pin) & 0xff); | |||
446 | pcireg_t reg, addr; | |||
447 | uint32_t ctrl; | |||
448 | int off; | |||
449 | ||||
450 | if (pci_get_capability(pc, tag, PCI_CAP_MSIX0x11, &off, ®) == 0) | |||
451 | panic("%s: no msix capability", __func__); | |||
452 | ||||
453 | KASSERT(entry <= PCI_MSIX_MC_TBLSZ(reg))((entry <= (((reg) & 0x07ff0000) >> 16)) ? (void )0 : __assert("diagnostic ", "/usr/src/sys/arch/amd64/pci/pci_machdep.c" , 453, "entry <= PCI_MSIX_MC_TBLSZ(reg)")); | |||
454 | ||||
455 | if (pci_msix_table_map(pc, tag, memt, &memh)) | |||
456 | panic("%s: cannot map registers", __func__); | |||
457 | ||||
458 | addr = 0xfee00000UL | (ci->ci_apicid << 12); | |||
459 | ||||
460 | bus_space_write_4(memt, memh, PCI_MSIX_MA(entry), addr)((memt)->write_4((memh), (((entry) * 16 + 0)), (addr))); | |||
461 | bus_space_write_4(memt, memh, PCI_MSIX_MAU32(entry), 0)((memt)->write_4((memh), (((entry) * 16 + 4)), (0))); | |||
462 | bus_space_write_4(memt, memh, PCI_MSIX_MD(entry), vec)((memt)->write_4((memh), (((entry) * 16 + 8)), (vec))); | |||
463 | bus_space_barrier(memt, memh, PCI_MSIX_MA(entry)((entry) * 16 + 0), 16, | |||
464 | BUS_SPACE_BARRIER_WRITE0x02); | |||
465 | ctrl = bus_space_read_4(memt, memh, PCI_MSIX_VC(entry))((memt)->read_4((memh), (((entry) * 16 + 12)))); | |||
466 | bus_space_write_4(memt, memh, PCI_MSIX_VC(entry),((memt)->write_4((memh), (((entry) * 16 + 12)), (ctrl & ~0x00000001))) | |||
467 | ctrl & ~PCI_MSIX_VC_MASK)((memt)->write_4((memh), (((entry) * 16 + 12)), (ctrl & ~0x00000001))); | |||
468 | ||||
469 | pci_msix_table_unmap(pc, tag, memt, memh); | |||
470 | ||||
471 | pci_conf_write(pc, tag, off, reg | PCI_MSIX_MC_MSIXE0x80000000); | |||
472 | } | |||
473 | ||||
474 | void | |||
475 | msix_delroute(struct pic *pic, struct cpu_info *ci, int pin, int vec, int type) | |||
476 | { | |||
477 | pci_chipset_tag_t pc = NULL((void *)0); /* XXX */ | |||
478 | bus_space_tag_t memt = X86_BUS_SPACE_MEM(&x86_bus_space_mem_ops); /* XXX */ | |||
479 | bus_space_handle_t memh; | |||
480 | pcitag_t tag = PCI_MSIX_TAG(pin)((pin) & ~0xff); | |||
481 | int entry = PCI_MSIX_VEC(pin)((pin) & 0xff); | |||
482 | pcireg_t reg; | |||
483 | uint32_t ctrl; | |||
484 | ||||
485 | if (pci_get_capability(pc, tag, PCI_CAP_MSIX0x11, NULL((void *)0), ®) == 0) | |||
486 | return; | |||
487 | ||||
488 | KASSERT(entry <= PCI_MSIX_MC_TBLSZ(reg))((entry <= (((reg) & 0x07ff0000) >> 16)) ? (void )0 : __assert("diagnostic ", "/usr/src/sys/arch/amd64/pci/pci_machdep.c" , 488, "entry <= PCI_MSIX_MC_TBLSZ(reg)")); | |||
489 | ||||
490 | if (pci_msix_table_map(pc, tag, memt, &memh)) | |||
491 | return; | |||
492 | ||||
493 | ctrl = bus_space_read_4(memt, memh, PCI_MSIX_VC(entry))((memt)->read_4((memh), (((entry) * 16 + 12)))); | |||
494 | bus_space_write_4(memt, memh, PCI_MSIX_VC(entry),((memt)->write_4((memh), (((entry) * 16 + 12)), (ctrl | 0x00000001 ))) | |||
495 | ctrl | PCI_MSIX_VC_MASK)((memt)->write_4((memh), (((entry) * 16 + 12)), (ctrl | 0x00000001 ))); | |||
496 | ||||
497 | pci_msix_table_unmap(pc, tag, memt, memh); | |||
498 | } | |||
499 | ||||
500 | int | |||
501 | pci_intr_map_msix(struct pci_attach_args *pa, int vec, pci_intr_handle_t *ihp) | |||
502 | { | |||
503 | pci_chipset_tag_t pc = pa->pa_pc; | |||
504 | pcitag_t tag = pa->pa_tag; | |||
505 | pcireg_t reg; | |||
506 | ||||
507 | KASSERT(PCI_MSIX_VEC(vec) == vec)((((vec) & 0xff) == vec) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/arch/amd64/pci/pci_machdep.c", 507, "PCI_MSIX_VEC(vec) == vec" )); | |||
508 | ||||
509 | if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED0x20) == 0 || mp_busses == NULL((void *)0) || | |||
510 | pci_get_capability(pc, tag, PCI_CAP_MSIX0x11, NULL((void *)0), ®) == 0) | |||
511 | return 1; | |||
512 | ||||
513 | if (vec > PCI_MSIX_MC_TBLSZ(reg)(((reg) & 0x07ff0000) >> 16)) | |||
514 | return 1; | |||
515 | ||||
516 | ihp->tag = PCI_MSIX_PIN(tag, vec)((tag) | (vec)); | |||
517 | ihp->line = APIC_INT_VIA_MSGX0x40000000; | |||
518 | ihp->pin = 0; | |||
519 | return 0; | |||
520 | } | |||
521 | ||||
522 | int | |||
523 | pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) | |||
524 | { | |||
525 | int pin = pa->pa_rawintrpin; | |||
526 | int line = pa->pa_intrline; | |||
527 | #if NIOAPIC1 > 0 | |||
528 | struct mp_intr_map *mip; | |||
| ||||
529 | int bus, dev, func; | |||
530 | #endif | |||
531 | ||||
532 | if (pin == 0) { | |||
533 | /* No IRQ used. */ | |||
534 | goto bad; | |||
535 | } | |||
536 | ||||
537 | if (pin > PCI_INTERRUPT_PIN_MAX0x04) { | |||
538 | printf("pci_intr_map: bad interrupt pin %d\n", pin); | |||
539 | goto bad; | |||
540 | } | |||
541 | ||||
542 | ihp->tag = pa->pa_tag; | |||
543 | ihp->line = line; | |||
544 | ihp->pin = pin; | |||
545 | ||||
546 | #if NIOAPIC1 > 0 | |||
547 | pci_decompose_tag(pa->pa_pc, pa->pa_tag, &bus, &dev, &func); | |||
548 | ||||
549 | if (mp_busses != NULL((void *)0)) { | |||
550 | int mpspec_pin = (dev << 2) | (pin - 1); | |||
551 | ||||
552 | if (bus < mp_nbusses) { | |||
553 | for (mip = mp_busses[bus].mb_intrs; | |||
554 | mip != NULL((void *)0); mip = mip->next) { | |||
555 | if (&mp_busses[bus] == mp_isa_bus || | |||
556 | &mp_busses[bus] == mp_eisa_bus) | |||
557 | continue; | |||
558 | if (mip->bus_pin == mpspec_pin) { | |||
559 | ihp->line = mip->ioapic_ih | line; | |||
560 | return 0; | |||
561 | } | |||
562 | } | |||
563 | } | |||
564 | ||||
565 | if (pa->pa_bridgetag) { | |||
566 | int swizpin = PPB_INTERRUPT_SWIZZLE(pin, dev)((((pin) + (dev) - 1) % 4) + 1); | |||
567 | if (pa->pa_bridgeih[swizpin - 1].line != -1) { | |||
568 | ihp->line = pa->pa_bridgeih[swizpin - 1].line; | |||
569 | ihp->line |= line; | |||
570 | return 0; | |||
571 | } | |||
572 | } | |||
573 | /* | |||
574 | * No explicit PCI mapping found. This is not fatal, | |||
575 | * we'll try the ISA (or possibly EISA) mappings next. | |||
576 | */ | |||
577 | } | |||
578 | #endif | |||
579 | ||||
580 | /* | |||
581 | * Section 6.2.4, `Miscellaneous Functions', says that 255 means | |||
582 | * `unknown' or `no connection' on a PC. We assume that a device with | |||
583 | * `no connection' either doesn't have an interrupt (in which case the | |||
584 | * pin number should be 0, and would have been noticed above), or | |||
585 | * wasn't configured by the BIOS (in which case we punt, since there's | |||
586 | * no real way we can know how the interrupt lines are mapped in the | |||
587 | * hardware). | |||
588 | * | |||
589 | * XXX | |||
590 | * Since IRQ 0 is only used by the clock, and we can't actually be sure | |||
591 | * that the BIOS did its job, we also recognize that as meaning that | |||
592 | * the BIOS has not configured the device. | |||
593 | */ | |||
594 | if (line == 0 || line == X86_PCI_INTERRUPT_LINE_NO_CONNECTION0xff) | |||
595 | goto bad; | |||
596 | ||||
597 | if (line >= NUM_LEGACY_IRQS16) { | |||
598 | printf("pci_intr_map: bad interrupt line %d\n", line); | |||
599 | goto bad; | |||
600 | } | |||
601 | if (line == 2) { | |||
602 | printf("pci_intr_map: changed line 2 to line 9\n"); | |||
603 | line = 9; | |||
604 | } | |||
605 | ||||
606 | #if NIOAPIC1 > 0 | |||
607 | if (mp_busses != NULL((void *)0)) { | |||
608 | if (mip == NULL((void *)0) && mp_isa_bus) { | |||
| ||||
609 | for (mip = mp_isa_bus->mb_intrs; mip != NULL((void *)0); | |||
610 | mip = mip->next) { | |||
611 | if (mip->bus_pin == line) { | |||
612 | ihp->line = mip->ioapic_ih | line; | |||
613 | return 0; | |||
614 | } | |||
615 | } | |||
616 | } | |||
617 | #if NEISA > 0 | |||
618 | if (mip == NULL((void *)0) && mp_eisa_bus) { | |||
619 | for (mip = mp_eisa_bus->mb_intrs; mip != NULL((void *)0); | |||
620 | mip = mip->next) { | |||
621 | if (mip->bus_pin == line) { | |||
622 | ihp->line = mip->ioapic_ih | line; | |||
623 | return 0; | |||
624 | } | |||
625 | } | |||
626 | } | |||
627 | #endif | |||
628 | if (mip == NULL((void *)0)) { | |||
629 | printf("pci_intr_map: " | |||
630 | "bus %d dev %d func %d pin %d; line %d\n", | |||
631 | bus, dev, func, pin, line); | |||
632 | printf("pci_intr_map: no MP mapping found\n"); | |||
633 | } | |||
634 | } | |||
635 | #endif | |||
636 | ||||
637 | return 0; | |||
638 | ||||
639 | bad: | |||
640 | ihp->line = -1; | |||
641 | return 1; | |||
642 | } | |||
643 | ||||
644 | const char * | |||
645 | pci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih) | |||
646 | { | |||
647 | static char irqstr[64]; | |||
648 | ||||
649 | if (ih.line == 0) | |||
650 | panic("pci_intr_string: bogus handle 0x%x", ih.line); | |||
651 | ||||
652 | if (ih.line & APIC_INT_VIA_MSG0x20000000) | |||
653 | return ("msi"); | |||
654 | if (ih.line & APIC_INT_VIA_MSGX0x40000000) | |||
655 | return ("msix"); | |||
656 | ||||
657 | #if NIOAPIC1 > 0 | |||
658 | if (ih.line & APIC_INT_VIA_APIC0x10000000) | |||
659 | snprintf(irqstr, sizeof(irqstr), "apic %d int %d", | |||
660 | APIC_IRQ_APIC(ih.line)((ih.line & 0x00ff0000) >> 16), APIC_IRQ_PIN(ih.line)((ih.line & 0x0000ff00) >> 8)); | |||
661 | else | |||
662 | snprintf(irqstr, sizeof(irqstr), "irq %d", | |||
663 | pci_intr_line(pc, ih)((ih.line) & 0xff)); | |||
664 | #else | |||
665 | snprintf(irqstr, sizeof(irqstr), "irq %d", pci_intr_line(pc, ih)((ih.line) & 0xff)); | |||
666 | #endif | |||
667 | return (irqstr); | |||
668 | } | |||
669 | ||||
670 | #include "acpiprt.h" | |||
671 | #if NACPIPRT1 > 0 | |||
672 | void acpiprt_route_interrupt(int bus, int dev, int pin); | |||
673 | #endif | |||
674 | ||||
675 | void * | |||
676 | pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level, | |||
677 | int (*func)(void *), void *arg, const char *what) | |||
678 | { | |||
679 | return pci_intr_establish_cpu(pc, ih, level, NULL((void *)0), func, arg, what); | |||
680 | } | |||
681 | ||||
682 | void * | |||
683 | pci_intr_establish_cpu(pci_chipset_tag_t pc, pci_intr_handle_t ih, | |||
684 | int level, struct cpu_info *ci, | |||
685 | int (*func)(void *), void *arg, const char *what) | |||
686 | { | |||
687 | int pin, irq; | |||
688 | int bus, dev; | |||
689 | pcitag_t tag = ih.tag; | |||
690 | struct pic *pic; | |||
691 | ||||
692 | if (ih.line & APIC_INT_VIA_MSG0x20000000) { | |||
693 | return intr_establish(-1, &msi_pic, tag, IST_PULSE1, level, | |||
694 | ci, func, arg, what); | |||
695 | } | |||
696 | if (ih.line & APIC_INT_VIA_MSGX0x40000000) { | |||
697 | return intr_establish(-1, &msix_pic, tag, IST_PULSE1, level, | |||
698 | ci, func, arg, what); | |||
699 | } | |||
700 | ||||
701 | pci_decompose_tag(pc, ih.tag, &bus, &dev, NULL((void *)0)); | |||
702 | #if NACPIPRT1 > 0 | |||
703 | acpiprt_route_interrupt(bus, dev, ih.pin); | |||
704 | #endif | |||
705 | ||||
706 | pic = &i8259_pic; | |||
707 | pin = irq = ih.line; | |||
708 | ||||
709 | #if NIOAPIC1 > 0 | |||
710 | if (ih.line & APIC_INT_VIA_APIC0x10000000) { | |||
711 | pic = (struct pic *)ioapic_find(APIC_IRQ_APIC(ih.line)((ih.line & 0x00ff0000) >> 16)); | |||
712 | if (pic == NULL((void *)0)) { | |||
713 | printf("pci_intr_establish: bad ioapic %d\n", | |||
714 | APIC_IRQ_APIC(ih.line)((ih.line & 0x00ff0000) >> 16)); | |||
715 | return NULL((void *)0); | |||
716 | } | |||
717 | pin = APIC_IRQ_PIN(ih.line)((ih.line & 0x0000ff00) >> 8); | |||
718 | irq = APIC_IRQ_LEGACY_IRQ(ih.line)((ih.line) & 0xff); | |||
719 | if (irq < 0 || irq >= NUM_LEGACY_IRQS16) | |||
720 | irq = -1; | |||
721 | } | |||
722 | #endif | |||
723 | ||||
724 | return intr_establish(irq, pic, pin, IST_LEVEL3, level, ci, | |||
725 | func, arg, what); | |||
726 | } | |||
727 | ||||
728 | void | |||
729 | pci_intr_disestablish(pci_chipset_tag_t pc, void *cookie) | |||
730 | { | |||
731 | intr_disestablish(cookie); | |||
732 | } | |||
733 | ||||
734 | struct extent *pciio_ex; | |||
735 | struct extent *pcimem_ex; | |||
736 | struct extent *pcibus_ex; | |||
737 | ||||
738 | void | |||
739 | pci_init_extents(void) | |||
740 | { | |||
741 | bios_memmap_t *bmp; | |||
742 | u_int64_t size; | |||
743 | ||||
744 | if (pciio_ex == NULL((void *)0)) { | |||
745 | /* | |||
746 | * We only have 64K of addressable I/O space. | |||
747 | * However, since BARs may contain garbage, we cover | |||
748 | * the full 32-bit address space defined by PCI of | |||
749 | * which we only make the first 64K available. | |||
750 | */ | |||
751 | pciio_ex = extent_create("pciio", 0, 0xffffffff, M_DEVBUF2, | |||
752 | NULL((void *)0), 0, EX_NOWAIT0x0000 | EX_FILLED0x0100); | |||
753 | if (pciio_ex == NULL((void *)0)) | |||
754 | return; | |||
755 | extent_free(pciio_ex, 0, 0x10000, EX_NOWAIT0x0000); | |||
756 | } | |||
757 | ||||
758 | if (pcimem_ex == NULL((void *)0)) { | |||
759 | /* | |||
760 | * Cover the 36-bit address space addressable by PAE | |||
761 | * here. As long as vendors continue to support | |||
762 | * 32-bit operating systems, we should never see BARs | |||
763 | * outside that region. | |||
764 | * | |||
765 | * Dell 13G servers have important devices outside the | |||
766 | * 36-bit address space. Until we can extract the address | |||
767 | * ranges from ACPI, expand the allowed range to suit. | |||
768 | */ | |||
769 | pcimem_ex = extent_create("pcimem", 0, 0xffffffffffffffffUL, | |||
770 | M_DEVBUF2, NULL((void *)0), 0, EX_NOWAIT0x0000); | |||
771 | if (pcimem_ex == NULL((void *)0)) | |||
772 | return; | |||
773 | extent_alloc_region(pcimem_ex, 0x40000000000UL, | |||
774 | 0xfffffc0000000000UL, EX_NOWAIT0x0000); | |||
775 | ||||
776 | for (bmp = bios_memmap; bmp->type != BIOS_MAP_END0x00; bmp++) { | |||
777 | /* | |||
778 | * Ignore address space beyond 4G. | |||
779 | */ | |||
780 | if (bmp->addr >= 0x100000000ULL) | |||
781 | continue; | |||
782 | size = bmp->size; | |||
783 | if (bmp->addr + size >= 0x100000000ULL) | |||
784 | size = 0x100000000ULL - bmp->addr; | |||
785 | ||||
786 | /* Ignore zero-sized regions. */ | |||
787 | if (size == 0) | |||
788 | continue; | |||
789 | ||||
790 | if (extent_alloc_region(pcimem_ex, bmp->addr, size, | |||
791 | EX_NOWAIT0x0000)) | |||
792 | printf("memory map conflict 0x%llx/0x%llx\n", | |||
793 | bmp->addr, bmp->size); | |||
794 | } | |||
795 | ||||
796 | /* Take out the video buffer area and BIOS areas. */ | |||
797 | extent_alloc_region(pcimem_ex, IOM_BEGIN0x0a0000, IOM_SIZE(0x100000 - 0x0a0000), | |||
798 | EX_CONFLICTOK0x0080 | EX_NOWAIT0x0000); | |||
799 | } | |||
800 | ||||
801 | if (pcibus_ex == NULL((void *)0)) { | |||
802 | pcibus_ex = extent_create("pcibus", 0, 0xff, M_DEVBUF2, | |||
803 | NULL((void *)0), 0, EX_NOWAIT0x0000); | |||
804 | } | |||
805 | } | |||
806 | ||||
807 | int | |||
808 | pci_probe_device_hook(pci_chipset_tag_t pc, struct pci_attach_args *pa) | |||
809 | { | |||
810 | #if NACPIDMAR1 > 0 | |||
811 | acpidmar_pci_hook(pc, pa); | |||
812 | #endif | |||
813 | return 0; | |||
814 | } | |||
815 | ||||
816 | #if NACPI1 > 0 | |||
817 | void acpi_pci_match(struct device *, struct pci_attach_args *); | |||
818 | pcireg_t acpi_pci_min_powerstate(pci_chipset_tag_t, pcitag_t); | |||
819 | void acpi_pci_set_powerstate(pci_chipset_tag_t, pcitag_t, int, int); | |||
820 | #endif | |||
821 | ||||
822 | void | |||
823 | pci_dev_postattach(struct device *dev, struct pci_attach_args *pa) | |||
824 | { | |||
825 | #if NACPI1 > 0 | |||
826 | acpi_pci_match(dev, pa); | |||
827 | #endif | |||
828 | } | |||
829 | ||||
830 | pcireg_t | |||
831 | pci_min_powerstate(pci_chipset_tag_t pc, pcitag_t tag) | |||
832 | { | |||
833 | #if NACPI1 > 0 | |||
834 | return acpi_pci_min_powerstate(pc, tag); | |||
835 | #else | |||
836 | return pci_get_powerstate(pc, tag); | |||
837 | #endif | |||
838 | } | |||
839 | ||||
840 | void | |||
841 | pci_set_powerstate_md(pci_chipset_tag_t pc, pcitag_t tag, int state, int pre) | |||
842 | { | |||
843 | #if NACPI1 > 0 | |||
844 | acpi_pci_set_powerstate(pc, tag, state, pre); | |||
845 | #endif | |||
846 | } |