1 | /* $NetBSD: pci.h,v 1.22 2016/01/17 01:40:39 riastradh Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2013 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Taylor R. Campbell. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | #ifndef _LINUX_PCI_H_ |
33 | #define _LINUX_PCI_H_ |
34 | |
35 | #ifdef _KERNEL_OPT |
36 | #if defined(i386) || defined(amd64) |
37 | #include "acpica.h" |
38 | #else /* !(i386 || amd64) */ |
39 | #define NACPICA 0 |
40 | #endif /* i386 || amd64 */ |
41 | #endif |
42 | |
43 | #include <sys/types.h> |
44 | #include <sys/param.h> |
45 | #include <sys/bus.h> |
46 | #include <sys/cdefs.h> |
47 | #include <sys/kmem.h> |
48 | #include <sys/systm.h> |
49 | |
50 | #include <machine/limits.h> |
51 | |
52 | #include <dev/pci/pcidevs.h> |
53 | #include <dev/pci/pcireg.h> |
54 | #include <dev/pci/pcivar.h> |
55 | #include <dev/pci/agpvar.h> |
56 | |
57 | #if NACPICA > 0 |
58 | #include <dev/acpi/acpivar.h> |
59 | #include <dev/acpi/acpi_pci.h> |
60 | #else |
61 | struct acpi_devnode; |
62 | #endif |
63 | |
64 | #include <linux/dma-mapping.h> |
65 | #include <linux/ioport.h> |
66 | #include <linux/kernel.h> |
67 | |
68 | struct pci_bus { |
69 | u_int number; |
70 | }; |
71 | |
72 | struct pci_device_id { |
73 | uint32_t vendor; |
74 | uint32_t device; |
75 | uint32_t subvendor; |
76 | uint32_t subdevice; |
77 | uint32_t class; |
78 | uint32_t class_mask; |
79 | unsigned long driver_data; |
80 | }; |
81 | |
82 | #define PCI_ANY_ID ((pcireg_t)-1) |
83 | |
84 | #define PCI_BASE_CLASS_DISPLAY PCI_CLASS_DISPLAY |
85 | |
86 | #define PCI_CLASS_DISPLAY_VGA \ |
87 | ((PCI_CLASS_DISPLAY << 8) | PCI_SUBCLASS_DISPLAY_VGA) |
88 | #define PCI_CLASS_BRIDGE_ISA \ |
89 | ((PCI_CLASS_BRIDGE << 8) | PCI_SUBCLASS_BRIDGE_ISA) |
90 | CTASSERT(PCI_CLASS_BRIDGE_ISA == 0x0601); |
91 | |
92 | /* XXX This is getting silly... */ |
93 | #define PCI_VENDOR_ID_ASUSTEK PCI_VENDOR_ASUSTEK |
94 | #define PCI_VENDOR_ID_ATI PCI_VENDOR_ATI |
95 | #define PCI_VENDOR_ID_DELL PCI_VENDOR_DELL |
96 | #define PCI_VENDOR_ID_IBM PCI_VENDOR_IBM |
97 | #define PCI_VENDOR_ID_HP PCI_VENDOR_HP |
98 | #define PCI_VENDOR_ID_INTEL PCI_VENDOR_INTEL |
99 | #define PCI_VENDOR_ID_NVIDIA PCI_VENDOR_NVIDIA |
100 | #define PCI_VENDOR_ID_SONY PCI_VENDOR_SONY |
101 | #define PCI_VENDOR_ID_VIA PCI_VENDOR_VIATECH |
102 | |
103 | #define PCI_DEVICE_ID_ATI_RADEON_QY PCI_PRODUCT_ATI_RADEON_RV100_QY |
104 | |
105 | #define PCI_DEVFN(DEV, FN) \ |
106 | (__SHIFTIN((DEV), __BITS(3, 7)) | __SHIFTIN((FN), __BITS(0, 2))) |
107 | #define PCI_SLOT(DEVFN) __SHIFTOUT((DEVFN), __BITS(3, 7)) |
108 | #define PCI_FUNC(DEVFN) __SHIFTOUT((DEVFN), __BITS(0, 2)) |
109 | |
110 | #define PCI_NUM_RESOURCES ((PCI_MAPREG_END - PCI_MAPREG_START) / 4) |
111 | #define DEVICE_COUNT_RESOURCE PCI_NUM_RESOURCES |
112 | |
113 | #define PCI_CAP_ID_AGP PCI_CAP_AGP |
114 | |
115 | typedef int pci_power_t; |
116 | |
117 | #define PCI_D0 0 |
118 | #define PCI_D1 1 |
119 | #define PCI_D2 2 |
120 | #define PCI_D3hot 3 |
121 | #define PCI_D3cold 4 |
122 | |
123 | #define __pci_iomem |
124 | |
125 | struct pci_dev { |
126 | struct pci_attach_args pd_pa; |
127 | int pd_kludges; /* Gotta lose 'em... */ |
128 | #define NBPCI_KLUDGE_GET_MUMBLE 0x01 |
129 | #define NBPCI_KLUDGE_MAP_ROM 0x02 |
130 | bus_space_tag_t pd_rom_bst; |
131 | bus_space_handle_t pd_rom_bsh; |
132 | bus_size_t pd_rom_size; |
133 | bus_space_handle_t pd_rom_found_bsh; |
134 | bus_size_t pd_rom_found_size; |
135 | void *pd_rom_vaddr; |
136 | device_t pd_dev; |
137 | struct drm_device *pd_drm_dev; /* XXX Nouveau kludge! */ |
138 | struct { |
139 | pcireg_t type; |
140 | bus_addr_t addr; |
141 | bus_size_t size; |
142 | int flags; |
143 | bus_space_tag_t bst; |
144 | bus_space_handle_t bsh; |
145 | void __pci_iomem *kva; |
146 | } pd_resources[PCI_NUM_RESOURCES]; |
147 | struct pci_conf_state *pd_saved_state; |
148 | struct acpi_devnode *pd_ad; |
149 | struct pci_bus *bus; |
150 | uint32_t devfn; |
151 | uint16_t vendor; |
152 | uint16_t device; |
153 | uint16_t subsystem_vendor; |
154 | uint16_t subsystem_device; |
155 | uint8_t revision; |
156 | uint32_t class; |
157 | bool msi_enabled; |
158 | }; |
159 | |
160 | static inline device_t |
161 | pci_dev_dev(struct pci_dev *pdev) |
162 | { |
163 | return pdev->pd_dev; |
164 | } |
165 | |
166 | /* XXX Nouveau kludge! */ |
167 | static inline struct drm_device * |
168 | pci_get_drvdata(struct pci_dev *pdev) |
169 | { |
170 | return pdev->pd_drm_dev; |
171 | } |
172 | |
173 | static inline void |
174 | linux_pci_dev_init(struct pci_dev *pdev, device_t dev, |
175 | const struct pci_attach_args *pa, int kludges) |
176 | { |
177 | const uint32_t subsystem_id = pci_conf_read(pa->pa_pc, pa->pa_tag, |
178 | PCI_SUBSYS_ID_REG); |
179 | unsigned i; |
180 | |
181 | pdev->pd_pa = *pa; |
182 | pdev->pd_kludges = kludges; |
183 | pdev->pd_rom_vaddr = NULL; |
184 | pdev->pd_dev = dev; |
185 | #if (NACPICA > 0) |
186 | pdev->pd_ad = acpi_pcidev_find(0 /*XXX segment*/, pa->pa_bus, |
187 | pa->pa_device, pa->pa_function); |
188 | #else |
189 | pdev->pd_ad = NULL; |
190 | #endif |
191 | pdev->bus = kmem_zalloc(sizeof(struct pci_bus), KM_NOSLEEP); |
192 | pdev->bus->number = pa->pa_bus; |
193 | pdev->devfn = PCI_DEVFN(pa->pa_device, pa->pa_function); |
194 | pdev->vendor = PCI_VENDOR(pa->pa_id); |
195 | pdev->device = PCI_PRODUCT(pa->pa_id); |
196 | pdev->subsystem_vendor = PCI_SUBSYS_VENDOR(subsystem_id); |
197 | pdev->subsystem_device = PCI_SUBSYS_ID(subsystem_id); |
198 | pdev->revision = PCI_REVISION(pa->pa_class); |
199 | pdev->class = __SHIFTOUT(pa->pa_class, 0xffffff00UL); /* ? */ |
200 | |
201 | CTASSERT(__arraycount(pdev->pd_resources) == PCI_NUM_RESOURCES); |
202 | for (i = 0; i < PCI_NUM_RESOURCES; i++) { |
203 | const int reg = PCI_BAR(i); |
204 | |
205 | pdev->pd_resources[i].type = pci_mapreg_type(pa->pa_pc, |
206 | pa->pa_tag, reg); |
207 | if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, reg, |
208 | pdev->pd_resources[i].type, |
209 | &pdev->pd_resources[i].addr, |
210 | &pdev->pd_resources[i].size, |
211 | &pdev->pd_resources[i].flags)) { |
212 | pdev->pd_resources[i].addr = 0; |
213 | pdev->pd_resources[i].size = 0; |
214 | pdev->pd_resources[i].flags = 0; |
215 | } |
216 | pdev->pd_resources[i].kva = NULL; |
217 | } |
218 | } |
219 | |
220 | static inline int |
221 | pci_find_capability(struct pci_dev *pdev, int cap) |
222 | { |
223 | return pci_get_capability(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, cap, |
224 | NULL, NULL); |
225 | } |
226 | |
227 | static inline int |
228 | pci_read_config_dword(struct pci_dev *pdev, int reg, uint32_t *valuep) |
229 | { |
230 | KASSERT(!ISSET(reg, 3)); |
231 | *valuep = pci_conf_read(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, reg); |
232 | return 0; |
233 | } |
234 | |
235 | static inline int |
236 | pci_read_config_word(struct pci_dev *pdev, int reg, uint16_t *valuep) |
237 | { |
238 | KASSERT(!ISSET(reg, 1)); |
239 | *valuep = pci_conf_read(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, |
240 | (reg &~ 2)) >> (8 * (reg & 2)); |
241 | return 0; |
242 | } |
243 | |
244 | static inline int |
245 | pci_read_config_byte(struct pci_dev *pdev, int reg, uint8_t *valuep) |
246 | { |
247 | *valuep = pci_conf_read(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, |
248 | (reg &~ 3)) >> (8 * (reg & 3)); |
249 | return 0; |
250 | } |
251 | |
252 | static inline int |
253 | pci_write_config_dword(struct pci_dev *pdev, int reg, uint32_t value) |
254 | { |
255 | KASSERT(!ISSET(reg, 3)); |
256 | pci_conf_write(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, reg, value); |
257 | return 0; |
258 | } |
259 | |
260 | static inline void |
261 | pci_rmw_config(struct pci_dev *pdev, int reg, unsigned int bytes, |
262 | uint32_t value) |
263 | { |
264 | const uint32_t mask = ~((~0UL) << (8 * bytes)); |
265 | const int reg32 = (reg &~ 3); |
266 | const unsigned int shift = (8 * (reg & 3)); |
267 | uint32_t value32; |
268 | |
269 | KASSERT(bytes <= 4); |
270 | KASSERT(!ISSET(value, ~mask)); |
271 | pci_read_config_dword(pdev, reg32, &value32); |
272 | value32 &=~ (mask << shift); |
273 | value32 |= (value << shift); |
274 | pci_write_config_dword(pdev, reg32, value32); |
275 | } |
276 | |
277 | static inline int |
278 | pci_write_config_word(struct pci_dev *pdev, int reg, uint16_t value) |
279 | { |
280 | KASSERT(!ISSET(reg, 1)); |
281 | pci_rmw_config(pdev, reg, 2, value); |
282 | return 0; |
283 | } |
284 | |
285 | static inline int |
286 | pci_write_config_byte(struct pci_dev *pdev, int reg, uint8_t value) |
287 | { |
288 | pci_rmw_config(pdev, reg, 1, value); |
289 | return 0; |
290 | } |
291 | |
292 | /* |
293 | * XXX pci msi |
294 | */ |
295 | static inline int |
296 | pci_enable_msi(struct pci_dev *pdev) |
297 | { |
298 | return -ENOSYS; |
299 | } |
300 | |
301 | static inline void |
302 | pci_disable_msi(struct pci_dev *pdev __unused) |
303 | { |
304 | KASSERT(pdev->msi_enabled); |
305 | } |
306 | |
307 | static inline void |
308 | pci_set_master(struct pci_dev *pdev) |
309 | { |
310 | pcireg_t csr; |
311 | |
312 | csr = pci_conf_read(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, |
313 | PCI_COMMAND_STATUS_REG); |
314 | csr |= PCI_COMMAND_MASTER_ENABLE; |
315 | pci_conf_write(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, |
316 | PCI_COMMAND_STATUS_REG, csr); |
317 | } |
318 | |
319 | static inline void |
320 | pci_clear_master(struct pci_dev *pdev) |
321 | { |
322 | pcireg_t csr; |
323 | |
324 | csr = pci_conf_read(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, |
325 | PCI_COMMAND_STATUS_REG); |
326 | csr &= ~(pcireg_t)PCI_COMMAND_MASTER_ENABLE; |
327 | pci_conf_write(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, |
328 | PCI_COMMAND_STATUS_REG, csr); |
329 | } |
330 | |
331 | #define PCIBIOS_MIN_MEM 0x100000 /* XXX bogus x86 kludge bollocks */ |
332 | |
333 | static inline bus_addr_t |
334 | pcibios_align_resource(void *p, const struct resource *resource, |
335 | bus_addr_t addr, bus_size_t size) |
336 | { |
337 | panic("pcibios_align_resource has accessed unaligned neurons!" ); |
338 | } |
339 | |
340 | static inline int |
341 | pci_bus_alloc_resource(struct pci_bus *bus, struct resource *resource, |
342 | bus_size_t size, bus_size_t align, bus_addr_t start, int type __unused, |
343 | bus_addr_t (*align_fn)(void *, const struct resource *, bus_addr_t, |
344 | bus_size_t) __unused, |
345 | struct pci_dev *pdev) |
346 | { |
347 | const struct pci_attach_args *const pa = &pdev->pd_pa; |
348 | bus_space_tag_t bst; |
349 | int error; |
350 | |
351 | switch (resource->flags) { |
352 | case IORESOURCE_MEM: |
353 | bst = pa->pa_memt; |
354 | break; |
355 | |
356 | case IORESOURCE_IO: |
357 | bst = pa->pa_iot; |
358 | break; |
359 | |
360 | default: |
361 | panic("I don't know what kind of resource you want!" ); |
362 | } |
363 | |
364 | resource->r_bst = bst; |
365 | error = bus_space_alloc(bst, start, __type_max(bus_addr_t), |
366 | size, align, 0, 0, &resource->start, &resource->r_bsh); |
367 | if (error) |
368 | return error; |
369 | |
370 | resource->size = size; |
371 | return 0; |
372 | } |
373 | |
374 | /* |
375 | * XXX Mega-kludgerific! pci_get_bus_and_slot and pci_get_class are |
376 | * defined only for their single purposes in i915drm, in |
377 | * i915_get_bridge_dev and intel_detect_pch. We can't define them more |
378 | * generally without adapting pci_find_device (and pci_enumerate_bus |
379 | * internally) to pass a cookie through. |
380 | */ |
381 | |
382 | static inline int /* XXX inline? */ |
383 | pci_kludgey_match_bus0_dev0_func0(const struct pci_attach_args *pa) |
384 | { |
385 | |
386 | if (pa->pa_bus != 0) |
387 | return 0; |
388 | if (pa->pa_device != 0) |
389 | return 0; |
390 | if (pa->pa_function != 0) |
391 | return 0; |
392 | |
393 | return 1; |
394 | } |
395 | |
396 | static inline struct pci_dev * |
397 | pci_get_bus_and_slot(int bus, int slot) |
398 | { |
399 | struct pci_attach_args pa; |
400 | |
401 | KASSERT(bus == 0); |
402 | KASSERT(slot == PCI_DEVFN(0, 0)); |
403 | |
404 | if (!pci_find_device(&pa, &pci_kludgey_match_bus0_dev0_func0)) |
405 | return NULL; |
406 | |
407 | struct pci_dev *const pdev = kmem_zalloc(sizeof(*pdev), KM_SLEEP); |
408 | linux_pci_dev_init(pdev, NULL, &pa, NBPCI_KLUDGE_GET_MUMBLE); |
409 | |
410 | return pdev; |
411 | } |
412 | |
413 | static inline int /* XXX inline? */ |
414 | pci_kludgey_match_isa_bridge(const struct pci_attach_args *pa) |
415 | { |
416 | |
417 | if (PCI_CLASS(pa->pa_class) != PCI_CLASS_BRIDGE) |
418 | return 0; |
419 | if (PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_BRIDGE_ISA) |
420 | return 0; |
421 | |
422 | return 1; |
423 | } |
424 | |
425 | static inline void |
426 | pci_dev_put(struct pci_dev *pdev) |
427 | { |
428 | |
429 | if (pdev == NULL) |
430 | return; |
431 | |
432 | KASSERT(ISSET(pdev->pd_kludges, NBPCI_KLUDGE_GET_MUMBLE)); |
433 | kmem_free(pdev, sizeof(*pdev)); |
434 | } |
435 | |
436 | static inline struct pci_dev * |
437 | pci_get_class(uint32_t class_subclass_shifted __unused, struct pci_dev *from) |
438 | { |
439 | struct pci_attach_args pa; |
440 | |
441 | KASSERT(class_subclass_shifted == (PCI_CLASS_BRIDGE_ISA << 8)); |
442 | |
443 | if (from != NULL) { |
444 | pci_dev_put(from); |
445 | return NULL; |
446 | } |
447 | |
448 | if (!pci_find_device(&pa, &pci_kludgey_match_isa_bridge)) |
449 | return NULL; |
450 | |
451 | struct pci_dev *const pdev = kmem_zalloc(sizeof(*pdev), KM_SLEEP); |
452 | linux_pci_dev_init(pdev, NULL, &pa, NBPCI_KLUDGE_GET_MUMBLE); |
453 | |
454 | return pdev; |
455 | } |
456 | |
457 | #define __pci_rom_iomem |
458 | |
459 | static inline void |
460 | pci_unmap_rom(struct pci_dev *pdev, void __pci_rom_iomem *vaddr __unused) |
461 | { |
462 | |
463 | /* XXX Disable the ROM address decoder. */ |
464 | KASSERT(ISSET(pdev->pd_kludges, NBPCI_KLUDGE_MAP_ROM)); |
465 | KASSERT(vaddr == pdev->pd_rom_vaddr); |
466 | bus_space_unmap(pdev->pd_rom_bst, pdev->pd_rom_bsh, pdev->pd_rom_size); |
467 | pdev->pd_kludges &= ~NBPCI_KLUDGE_MAP_ROM; |
468 | pdev->pd_rom_vaddr = NULL; |
469 | } |
470 | |
471 | /* XXX Whattakludge! Should move this in sys/arch/. */ |
472 | static int |
473 | pci_map_rom_md(struct pci_dev *pdev) |
474 | { |
475 | #if defined(__i386__) || defined(__x86_64__) || defined(__ia64__) |
476 | const bus_addr_t rom_base = 0xc0000; |
477 | const bus_size_t rom_size = 0x20000; |
478 | bus_space_handle_t rom_bsh; |
479 | int error; |
480 | |
481 | if (PCI_CLASS(pdev->pd_pa.pa_class) != PCI_CLASS_DISPLAY) |
482 | return ENXIO; |
483 | if (PCI_SUBCLASS(pdev->pd_pa.pa_class) != PCI_SUBCLASS_DISPLAY_VGA) |
484 | return ENXIO; |
485 | /* XXX Check whether this is the primary VGA card? */ |
486 | error = bus_space_map(pdev->pd_pa.pa_memt, rom_base, rom_size, |
487 | (BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE), &rom_bsh); |
488 | if (error) |
489 | return ENXIO; |
490 | |
491 | pdev->pd_rom_bst = pdev->pd_pa.pa_memt; |
492 | pdev->pd_rom_bsh = rom_bsh; |
493 | pdev->pd_rom_size = rom_size; |
494 | pdev->pd_kludges |= NBPCI_KLUDGE_MAP_ROM; |
495 | |
496 | return 0; |
497 | #else |
498 | return ENXIO; |
499 | #endif |
500 | } |
501 | |
502 | static inline void __pci_rom_iomem * |
503 | pci_map_rom(struct pci_dev *pdev, size_t *sizep) |
504 | { |
505 | |
506 | KASSERT(!ISSET(pdev->pd_kludges, NBPCI_KLUDGE_MAP_ROM)); |
507 | |
508 | if (pci_mapreg_map(&pdev->pd_pa, PCI_MAPREG_ROM, PCI_MAPREG_TYPE_ROM, |
509 | (BUS_SPACE_MAP_PREFETCHABLE | BUS_SPACE_MAP_LINEAR), |
510 | &pdev->pd_rom_bst, &pdev->pd_rom_bsh, NULL, &pdev->pd_rom_size) |
511 | != 0) |
512 | goto fail_mi; |
513 | pdev->pd_kludges |= NBPCI_KLUDGE_MAP_ROM; |
514 | |
515 | /* XXX This type is obviously wrong in general... */ |
516 | if (pci_find_rom(&pdev->pd_pa, pdev->pd_rom_bst, pdev->pd_rom_bsh, |
517 | pdev->pd_rom_size, PCI_ROM_CODE_TYPE_X86, |
518 | &pdev->pd_rom_found_bsh, &pdev->pd_rom_found_size)) { |
519 | pci_unmap_rom(pdev, NULL); |
520 | goto fail_mi; |
521 | } |
522 | goto success; |
523 | |
524 | fail_mi: |
525 | if (pci_map_rom_md(pdev) != 0) |
526 | goto fail_md; |
527 | |
528 | /* XXX This type is obviously wrong in general... */ |
529 | if (pci_find_rom(&pdev->pd_pa, pdev->pd_rom_bst, pdev->pd_rom_bsh, |
530 | pdev->pd_rom_size, PCI_ROM_CODE_TYPE_X86, |
531 | &pdev->pd_rom_found_bsh, &pdev->pd_rom_found_size)) { |
532 | pci_unmap_rom(pdev, NULL); |
533 | goto fail_md; |
534 | } |
535 | |
536 | success: |
537 | KASSERT(pdev->pd_rom_found_size <= SIZE_T_MAX); |
538 | *sizep = pdev->pd_rom_found_size; |
539 | pdev->pd_rom_vaddr = bus_space_vaddr(pdev->pd_rom_bst, |
540 | pdev->pd_rom_found_bsh); |
541 | return pdev->pd_rom_vaddr; |
542 | |
543 | fail_md: |
544 | return NULL; |
545 | } |
546 | |
547 | static inline void __pci_rom_iomem * |
548 | pci_platform_rom(struct pci_dev *pdev __unused, size_t *sizep) |
549 | { |
550 | |
551 | *sizep = 0; |
552 | return NULL; |
553 | } |
554 | |
555 | static inline int |
556 | pci_enable_rom(struct pci_dev *pdev) |
557 | { |
558 | const pci_chipset_tag_t pc = pdev->pd_pa.pa_pc; |
559 | const pcitag_t tag = pdev->pd_pa.pa_tag; |
560 | pcireg_t addr; |
561 | int s; |
562 | |
563 | /* XXX Don't do anything if the ROM isn't there. */ |
564 | |
565 | s = splhigh(); |
566 | addr = pci_conf_read(pc, tag, PCI_MAPREG_ROM); |
567 | addr |= PCI_MAPREG_ROM_ENABLE; |
568 | pci_conf_write(pc, tag, PCI_MAPREG_ROM, addr); |
569 | splx(s); |
570 | |
571 | return 0; |
572 | } |
573 | |
574 | static inline void |
575 | pci_disable_rom(struct pci_dev *pdev) |
576 | { |
577 | const pci_chipset_tag_t pc = pdev->pd_pa.pa_pc; |
578 | const pcitag_t tag = pdev->pd_pa.pa_tag; |
579 | pcireg_t addr; |
580 | int s; |
581 | |
582 | s = splhigh(); |
583 | addr = pci_conf_read(pc, tag, PCI_MAPREG_ROM); |
584 | addr &= ~(pcireg_t)PCI_MAPREG_ROM_ENABLE; |
585 | pci_conf_write(pc, tag, PCI_MAPREG_ROM, addr); |
586 | splx(s); |
587 | } |
588 | |
589 | static inline bus_addr_t |
590 | pci_resource_start(struct pci_dev *pdev, unsigned i) |
591 | { |
592 | |
593 | KASSERT(i < PCI_NUM_RESOURCES); |
594 | return pdev->pd_resources[i].addr; |
595 | } |
596 | |
597 | static inline bus_size_t |
598 | pci_resource_len(struct pci_dev *pdev, unsigned i) |
599 | { |
600 | |
601 | KASSERT(i < PCI_NUM_RESOURCES); |
602 | return pdev->pd_resources[i].size; |
603 | } |
604 | |
605 | static inline bus_addr_t |
606 | pci_resource_end(struct pci_dev *pdev, unsigned i) |
607 | { |
608 | |
609 | return pci_resource_start(pdev, i) + (pci_resource_len(pdev, i) - 1); |
610 | } |
611 | |
612 | static inline int |
613 | pci_resource_flags(struct pci_dev *pdev, unsigned i) |
614 | { |
615 | |
616 | KASSERT(i < PCI_NUM_RESOURCES); |
617 | return pdev->pd_resources[i].flags; |
618 | } |
619 | |
620 | static inline void __pci_iomem * |
621 | pci_iomap(struct pci_dev *pdev, unsigned i, bus_size_t size) |
622 | { |
623 | int error; |
624 | |
625 | KASSERT(i < PCI_NUM_RESOURCES); |
626 | KASSERT(pdev->pd_resources[i].kva == NULL); |
627 | |
628 | if (PCI_MAPREG_TYPE(pdev->pd_resources[i].type) != PCI_MAPREG_TYPE_MEM) |
629 | return NULL; |
630 | if (pdev->pd_resources[i].size < size) |
631 | return NULL; |
632 | error = bus_space_map(pdev->pd_pa.pa_memt, pdev->pd_resources[i].addr, |
633 | size, BUS_SPACE_MAP_LINEAR | pdev->pd_resources[i].flags, |
634 | &pdev->pd_resources[i].bsh); |
635 | if (error) { |
636 | /* Horrible hack: try asking the fake AGP device. */ |
637 | if (!agp_i810_borrow(pdev->pd_resources[i].addr, size, |
638 | &pdev->pd_resources[i].bsh)) |
639 | return NULL; |
640 | } |
641 | pdev->pd_resources[i].bst = pdev->pd_pa.pa_memt; |
642 | pdev->pd_resources[i].kva = bus_space_vaddr(pdev->pd_resources[i].bst, |
643 | pdev->pd_resources[i].bsh); |
644 | |
645 | return pdev->pd_resources[i].kva; |
646 | } |
647 | |
648 | static inline void |
649 | pci_iounmap(struct pci_dev *pdev, void __pci_iomem *kva) |
650 | { |
651 | unsigned i; |
652 | |
653 | CTASSERT(__arraycount(pdev->pd_resources) == PCI_NUM_RESOURCES); |
654 | for (i = 0; i < PCI_NUM_RESOURCES; i++) { |
655 | if (pdev->pd_resources[i].kva == kva) |
656 | break; |
657 | } |
658 | KASSERT(i < PCI_NUM_RESOURCES); |
659 | |
660 | pdev->pd_resources[i].kva = NULL; |
661 | bus_space_unmap(pdev->pd_resources[i].bst, pdev->pd_resources[i].bsh, |
662 | pdev->pd_resources[i].size); |
663 | } |
664 | |
665 | static inline void |
666 | pci_save_state(struct pci_dev *pdev) |
667 | { |
668 | |
669 | KASSERT(pdev->pd_saved_state == NULL); |
670 | pdev->pd_saved_state = kmem_alloc(sizeof(*pdev->pd_saved_state), |
671 | KM_SLEEP); |
672 | pci_conf_capture(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, |
673 | pdev->pd_saved_state); |
674 | } |
675 | |
676 | static inline void |
677 | pci_restore_state(struct pci_dev *pdev) |
678 | { |
679 | |
680 | KASSERT(pdev->pd_saved_state != NULL); |
681 | pci_conf_restore(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, |
682 | pdev->pd_saved_state); |
683 | kmem_free(pdev->pd_saved_state, sizeof(*pdev->pd_saved_state)); |
684 | pdev->pd_saved_state = NULL; |
685 | } |
686 | |
687 | static inline bool |
688 | pci_is_pcie(struct pci_dev *pdev) |
689 | { |
690 | |
691 | return (pci_find_capability(pdev, PCI_CAP_PCIEXPRESS) != 0); |
692 | } |
693 | |
694 | static inline bool |
695 | pci_dma_supported(struct pci_dev *pdev, uintmax_t mask) |
696 | { |
697 | |
698 | /* XXX Cop-out. */ |
699 | if (mask > DMA_BIT_MASK(32)) |
700 | return pci_dma64_available(&pdev->pd_pa); |
701 | else |
702 | return true; |
703 | } |
704 | |
705 | #endif /* _LINUX_PCI_H_ */ |
706 | |