Annotation of sys/arch/sh/dev/pci_addr_fixup.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: pci_addr_fixup.c,v 1.2 2006/10/19 22:42:53 drahn Exp $ */
2: /* $NetBSD: pci_addr_fixup.c,v 1.7 2000/08/03 20:10:45 nathanw Exp $ */
3:
4: /*-
5: * Copyright (c) 2000 UCHIYAMA Yasushi. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. The name of the author may not be used to endorse or promote products
16: * derived from this software without specific prior written permission.
17: *
18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28: */
29:
30: #include <sys/param.h>
31: #include <sys/systm.h>
32: #include <sys/malloc.h>
33: #include <sys/kernel.h>
34: #include <sys/device.h>
35: #include <sys/extent.h>
36:
37: #include <uvm/uvm_param.h>
38: #include <machine/bus.h>
39:
40: #include <dev/pci/pcireg.h>
41: #include <dev/pci/pcivar.h>
42: #include <dev/pci/pcidevs.h>
43:
44: #include <sh/dev/shpcicvar.h>
45:
46: typedef int (*pciaddr_resource_manage_func_t)(struct shpcic_softc *,
47: pci_chipset_tag_t, pcitag_t, int, struct extent *, int, bus_addr_t *,
48: bus_size_t);
49: void pciaddr_resource_manage(struct shpcic_softc *,
50: pci_chipset_tag_t, pcitag_t, pciaddr_resource_manage_func_t);
51: void pciaddr_resource_reserve(struct shpcic_softc *,
52: pci_chipset_tag_t, pcitag_t);
53: void pciaddr_resource_reserve_disabled(struct shpcic_softc *,
54: pci_chipset_tag_t, pcitag_t);
55: int pciaddr_do_resource_reserve(struct shpcic_softc *,
56: pci_chipset_tag_t, pcitag_t, int, struct extent *, int,
57: bus_addr_t *, bus_size_t);
58: int pciaddr_do_resource_reserve_disabled(struct shpcic_softc *,
59: pci_chipset_tag_t, pcitag_t, int, struct extent *, int,
60: bus_addr_t *, bus_size_t);
61: void pciaddr_resource_allocate(struct shpcic_softc *,
62: pci_chipset_tag_t, pcitag_t);
63: int pciaddr_do_resource_allocate(struct shpcic_softc *,
64: pci_chipset_tag_t, pcitag_t, int, struct extent *, int, bus_addr_t *,
65: bus_size_t);
66: bus_addr_t pciaddr_ioaddr(u_int32_t);
67: void pciaddr_print_devid(pci_chipset_tag_t, pcitag_t);
68:
69: int pciaddr_device_is_agp(pci_chipset_tag_t, pcitag_t);
70:
71: void pci_device_foreach(struct shpcic_softc *sc, pci_chipset_tag_t pc,
72: int maxbus,
73: void (*func)(struct shpcic_softc *, pci_chipset_tag_t, pcitag_t));
74:
75: #define PCIADDR_MEM_START 0x0
76: #define PCIADDR_MEM_END 0xffffffff
77: #define PCIADDR_PORT_START 0x0
78: #define PCIADDR_PORT_END 0xffff
79:
80: #define PCIBR_VERBOSE 1
81: int pcibr_flags = 0;
82:
83: #define PCIBIOS_PRINTV(x) if (pcibr_flags & PCIBR_VERBOSE) \
84: printf x
85:
86: void
87: pci_addr_fixup(void *v, int maxbus)
88: {
89: struct shpcic_softc *sc = v;
90:
91: const char *verbose_header =
92: "[%s]-----------------------\n"
93: " device vendor product\n"
94: " register space address size\n"
95: "--------------------------------------------\n";
96: const char *verbose_footer =
97: "--------------------------[%3d devices bogus]\n";
98:
99: sc->extent_mem = extent_create("PCI I/O memory space",
100: sc->sc_membus_space.bus_base,
101: sc->sc_membus_space.bus_base + sc->sc_membus_space.bus_size,
102: M_DEVBUF, 0, 0, EX_NOWAIT);
103: KASSERT(sc->extent_mem);
104: sc->extent_port = extent_create("PCI I/O port space",
105: sc->sc_iobus_space.bus_base,
106: sc->sc_iobus_space.bus_base + sc->sc_iobus_space.bus_size,
107: M_DEVBUF, 0, 0, EX_NOWAIT);
108: KASSERT(sc->extent_port);
109:
110: /*
111: * 1. check & reserve system BIOS setting.
112: */
113: PCIBIOS_PRINTV((verbose_header, "System BIOS Setting"));
114: pci_device_foreach(sc, &sc->sc_pci_chipset, maxbus,
115: pciaddr_resource_reserve);
116: pci_device_foreach(sc, &sc->sc_pci_chipset, maxbus,
117: pciaddr_resource_reserve_disabled);
118: PCIBIOS_PRINTV((verbose_footer, sc->nbogus));
119:
120: {
121: struct extent_region *rp;
122: struct extent *ex = sc->extent_mem;
123: for (rp = LIST_FIRST(&ex->ex_regions);
124: rp; rp = LIST_NEXT(rp, er_link)) {
125: }
126: }
127: {
128: struct extent_region *rp;
129: struct extent *ex = sc->extent_port;
130: for (rp = LIST_FIRST(&ex->ex_regions);
131: rp; rp = LIST_NEXT(rp, er_link)) {
132: }
133: }
134:
135: /*
136: * 4. do fixup
137: */
138: PCIBIOS_PRINTV((verbose_header, "PCIBIOS fixup stage"));
139: sc->nbogus = 0;
140: pci_device_foreach(sc, &sc->sc_pci_chipset, maxbus,
141: pciaddr_resource_allocate);
142: PCIBIOS_PRINTV((verbose_footer, sc->nbogus));
143:
144: }
145:
146: void
147: pciaddr_resource_reserve(struct shpcic_softc *sc, pci_chipset_tag_t pc,
148: pcitag_t tag)
149: {
150: if (pcibr_flags & PCIBR_VERBOSE)
151: pciaddr_print_devid(pc, tag);
152: pciaddr_resource_manage(sc, pc, tag, pciaddr_do_resource_reserve);
153: }
154: void
155: pciaddr_resource_reserve_disabled(struct shpcic_softc *sc,
156: pci_chipset_tag_t pc, pcitag_t tag)
157: {
158: if (pcibr_flags & PCIBR_VERBOSE)
159: pciaddr_print_devid(pc, tag);
160: pciaddr_resource_manage(sc, pc, tag,
161: pciaddr_do_resource_reserve_disabled);
162: }
163:
164:
165: void
166: pciaddr_resource_allocate(struct shpcic_softc *sc, pci_chipset_tag_t pc,
167: pcitag_t tag)
168: {
169: if (pcibr_flags & PCIBR_VERBOSE)
170: pciaddr_print_devid(pc, tag);
171: pciaddr_resource_manage(sc, pc, tag, pciaddr_do_resource_allocate);
172: }
173:
174: void
175: pciaddr_resource_manage(struct shpcic_softc *sc, pci_chipset_tag_t pc,
176: pcitag_t tag, pciaddr_resource_manage_func_t func)
177: {
178: struct extent *ex;
179: pcireg_t val, mask;
180: bus_addr_t addr;
181: bus_size_t size;
182: int error, mapreg, type, reg_start, reg_end, width;
183:
184: val = pci_conf_read(pc, tag, PCI_BHLC_REG);
185: switch (PCI_HDRTYPE_TYPE(val)) {
186: default:
187: printf("WARNING: unknown PCI device header.\n");
188: sc->nbogus++;
189: return;
190: case 0:
191: reg_start = PCI_MAPREG_START;
192: reg_end = PCI_MAPREG_END;
193: break;
194: case 1: /* PCI-PCI bridge */
195: reg_start = PCI_MAPREG_START;
196: reg_end = PCI_MAPREG_PPB_END;
197: break;
198: case 2: /* PCI-CardBus bridge */
199: reg_start = PCI_MAPREG_START;
200: reg_end = PCI_MAPREG_PCB_END;
201: break;
202: }
203: error = 0;
204:
205: for (mapreg = reg_start; mapreg < reg_end; mapreg += width) {
206: /* inquire PCI device bus space requirement */
207: val = pci_conf_read(pc, tag, mapreg);
208: pci_conf_write(pc, tag, mapreg, ~0);
209:
210: mask = pci_conf_read(pc, tag, mapreg);
211: pci_conf_write(pc, tag, mapreg, val);
212:
213: type = PCI_MAPREG_TYPE(val);
214: width = 4;
215: if (type == PCI_MAPREG_TYPE_MEM) {
216: if (PCI_MAPREG_MEM_TYPE(val) ==
217: PCI_MAPREG_MEM_TYPE_64BIT) {
218: /* XXX We could examine the upper 32 bits
219: * XXX of the BAR here, but we are totally
220: * XXX unprepared to handle a non-zero value,
221: * XXX either here or anywhere else in
222: * XXX i386-land.
223: * XXX So just arrange to not look at the
224: * XXX upper 32 bits, lest we misinterpret
225: * XXX it as a 32-bit BAR set to zero.
226: */
227: width = 8;
228: }
229: addr = PCI_MAPREG_MEM_ADDR(val);
230: size = PCI_MAPREG_MEM_SIZE(mask);
231: ex = sc->extent_mem;
232: /* XXX */
233: /*
234: * sh-IPL allocates a low address for PCI memory
235: * on px-eh systems, clobber it so it gets 'remapped'
236: */
237: if (addr != 0 && addr < sc->sc_membus_space.bus_base) {
238: val = 0;
239: pci_conf_write(pc, tag, mapreg, val);
240: }
241: } else {
242: /* XXX some devices give 32bit value */
243: if (sc->sc_iobus_space.bus_base != PCIADDR_PORT_START) {
244: /*
245: * if the bus base is not 0 skew all addresses
246: */
247: val &= PCIADDR_PORT_END;
248: val |= sc->sc_iobus_space.bus_base;
249: pci_conf_write(pc, tag, mapreg, val);
250: }
251: addr = PCI_MAPREG_IO_ADDR(val);
252: size = PCI_MAPREG_IO_SIZE(mask);
253: ex = sc->extent_port;
254: }
255:
256: if (!size) /* unused register */
257: continue;
258:
259: /* reservation/allocation phase */
260: error += (*func) (sc, pc, tag, mapreg, ex, type, &addr, size);
261:
262: PCIBIOS_PRINTV(("\t%02xh %s 0x%08x 0x%08x\n",
263: mapreg, type ? "port" : "mem ",
264: (unsigned int)addr, (unsigned int)size));
265: }
266:
267: if (error)
268: sc->nbogus++;
269:
270: PCIBIOS_PRINTV(("\t\t[%s]\n", error ? "NG" : "OK"));
271: }
272:
273: int
274: pciaddr_do_resource_allocate(struct shpcic_softc *sc, pci_chipset_tag_t pc,
275: pcitag_t tag, int mapreg, struct extent *ex, int type, bus_addr_t *addr,
276: bus_size_t size)
277: {
278: bus_addr_t start;
279: int error;
280:
281: if (type == PCI_MAPREG_TYPE_IO) {
282: if ((*addr & PCIADDR_PORT_END) != 0)
283: return (0);
284: } else if (*addr) /* no need to allocate */
285: return (0);
286:
287: /* XXX Don't allocate if device is AGP device to avoid conflict. */
288: if (pciaddr_device_is_agp(pc, tag))
289: return (0);
290:
291: start = (type == PCI_MAPREG_TYPE_MEM ? sc->sc_membus_space.bus_base
292: : sc->sc_iobus_space.bus_base);
293: if (start < ex->ex_start || start + size - 1 >= ex->ex_end) {
294: PCIBIOS_PRINTV(("No available resources. fixup failed\n"));
295: return (1);
296: }
297: error = extent_alloc_subregion(ex, start, ex->ex_end, size, size, 0, 0,
298: EX_FAST|EX_NOWAIT|EX_MALLOCOK, addr);
299: if (error) {
300: PCIBIOS_PRINTV(("No available resources. fixup failed\n"));
301: return (1);
302: }
303:
304: /* write new address to PCI device configuration header */
305: pci_conf_write(pc, tag, mapreg, *addr);
306: /* check */
307: if (pcibr_flags & PCIBR_VERBOSE) {
308: printf("pci_addr_fixup: ");
309: pciaddr_print_devid(pc, tag);
310: }
311:
312: if (pciaddr_ioaddr(pci_conf_read(pc, tag, mapreg)) != *addr) {
313: pci_conf_write(pc, tag, mapreg, 0); /* clear */
314: printf("fixup failed. (new address=%#lx)\n", *addr);
315: return (1);
316: }
317: if (pcibr_flags & PCIBR_VERBOSE)
318: printf("new address 0x%08lx\n", *addr);
319:
320: return (0);
321: }
322:
323: int
324: pciaddr_do_resource_reserve(struct shpcic_softc *sc, pci_chipset_tag_t pc,
325: pcitag_t tag, int mapreg, struct extent *ex, int type, bus_addr_t *addr,
326: bus_size_t size)
327: {
328: pcireg_t val;
329: int error;
330:
331: if ((type == PCI_MAPREG_TYPE_IO) && ((*addr & PCIADDR_PORT_END) == 0))
332: return (0);
333: if (*addr == 0)
334: return (0);
335:
336: val = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
337: if (type == PCI_MAPREG_TYPE_MEM &&
338: (val & PCI_COMMAND_MEM_ENABLE) != PCI_COMMAND_MEM_ENABLE)
339: return (0);
340: if (type == PCI_MAPREG_TYPE_IO &&
341: (val & PCI_COMMAND_IO_ENABLE) != PCI_COMMAND_IO_ENABLE)
342: return (0);
343:
344: error = extent_alloc_region(ex, *addr, size, EX_NOWAIT | EX_MALLOCOK);
345: if (error) {
346: PCIBIOS_PRINTV(("Resource conflict.\n"));
347: pci_conf_write(pc, tag, mapreg, 0); /* clear */
348: return (1);
349: }
350:
351: return (0);
352: }
353:
354: int
355: pciaddr_do_resource_reserve_disabled(struct shpcic_softc *sc,
356: pci_chipset_tag_t pc, pcitag_t tag, int mapreg, struct extent *ex,
357: int type, bus_addr_t *addr, bus_size_t size)
358: {
359: pcireg_t val;
360: int error;
361:
362: if ((type == PCI_MAPREG_TYPE_IO) && ((*addr & PCIADDR_PORT_END) == 0))
363: return (0);
364: if (*addr == 0)
365: return (0);
366:
367: val = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
368: if (type == PCI_MAPREG_TYPE_MEM &&
369: (val & PCI_COMMAND_MEM_ENABLE) == PCI_COMMAND_MEM_ENABLE)
370: return (0);
371: if (type == PCI_MAPREG_TYPE_IO &&
372: (val & PCI_COMMAND_IO_ENABLE) == PCI_COMMAND_IO_ENABLE)
373: return (0);
374:
375: error = extent_alloc_region(ex, *addr, size, EX_NOWAIT | EX_MALLOCOK);
376: if (error) {
377: PCIBIOS_PRINTV(("Resource conflict.\n"));
378: pci_conf_write(pc, tag, mapreg, 0); /* clear */
379: return (1);
380: }
381:
382: return (0);
383: }
384:
385: bus_addr_t
386: pciaddr_ioaddr(u_int32_t val)
387: {
388: return ((PCI_MAPREG_TYPE(val) == PCI_MAPREG_TYPE_MEM)
389: ? PCI_MAPREG_MEM_ADDR(val)
390: : (PCI_MAPREG_IO_ADDR(val)));
391: }
392:
393: void
394: pciaddr_print_devid(pci_chipset_tag_t pc, pcitag_t tag)
395: {
396: int bus, device, function;
397: pcireg_t id;
398:
399: id = pci_conf_read(pc, tag, PCI_ID_REG);
400: pci_decompose_tag(pc, tag, &bus, &device, &function);
401: printf("%03d:%02d:%d %04x:%04x\n", bus, device, function,
402: PCI_VENDOR(id), PCI_PRODUCT(id));
403: }
404:
405: int
406: pciaddr_device_is_agp(pci_chipset_tag_t pc, pcitag_t tag)
407: {
408: pcireg_t class, status, rval;
409: int off;
410:
411: /* Check AGP device. */
412: class = pci_conf_read(pc, tag, PCI_CLASS_REG);
413: if (PCI_CLASS(class) == PCI_CLASS_DISPLAY) {
414: status = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
415: if (status & PCI_STATUS_CAPLIST_SUPPORT) {
416: rval = pci_conf_read(pc, tag, PCI_CAPLISTPTR_REG);
417: for (off = PCI_CAPLIST_PTR(rval);
418: off != 0;
419: off = PCI_CAPLIST_NEXT(rval) ) {
420: rval = pci_conf_read(pc, tag, off);
421: if (PCI_CAPLIST_CAP(rval) == PCI_CAP_AGP)
422: return (1);
423: }
424: }
425: }
426: return (0);
427: }
428:
429: void
430: pci_device_foreach(struct shpcic_softc *sc, pci_chipset_tag_t pc, int maxbus,
431: void (*func)(struct shpcic_softc *, pci_chipset_tag_t, pcitag_t))
432: {
433: const struct pci_quirkdata *qd;
434: int bus, device, function, maxdevs, nfuncs;
435: pcireg_t id, bhlcr;
436: pcitag_t tag;
437:
438: for (bus = 0; bus <= maxbus; bus++) {
439: maxdevs = pci_bus_maxdevs(pc, bus);
440: for (device = 0; device < maxdevs; device++) {
441: tag = pci_make_tag(pc, bus, device, 0);
442: id = pci_conf_read(pc, tag, PCI_ID_REG);
443:
444: /* Invalid vendor ID value? */
445: if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
446: continue;
447: /* XXX Not invalid, but we've done this ~forever. */
448: if (PCI_VENDOR(id) == 0)
449: continue;
450:
451: qd = pci_lookup_quirkdata(PCI_VENDOR(id),
452: PCI_PRODUCT(id));
453:
454: bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
455: if (PCI_HDRTYPE_MULTIFN(bhlcr) ||
456: (qd != NULL &&
457: (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
458: nfuncs = 8;
459: else
460: nfuncs = 1;
461:
462: for (function = 0; function < nfuncs; function++) {
463: tag = pci_make_tag(pc, bus, device, function);
464: id = pci_conf_read(pc, tag, PCI_ID_REG);
465:
466: /* Invalid vendor ID value? */
467: if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
468: continue;
469: /*
470: * XXX Not invalid, but we've done this
471: * ~forever.
472: */
473: if (PCI_VENDOR(id) == 0)
474: continue;
475: (*func)(sc, pc, tag);
476: }
477: }
478: }
479: }
CVSweb