Annotation of sys/arch/i386/pci/pcibios.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: pcibios.c,v 1.37 2007/03/19 05:32:05 deraadt Exp $ */
2: /* $NetBSD: pcibios.c,v 1.5 2000/08/01 05:23:59 uch Exp $ */
3:
4: /*
5: * Copyright (c) 2000 Michael Shalayeff
6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20: * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
21: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23: * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26: * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27: * THE POSSIBILITY OF SUCH DAMAGE.
28: */
29: /*-
30: * Copyright (c) 1999 The NetBSD Foundation, Inc.
31: * All rights reserved.
32: *
33: * This code is derived from software contributed to The NetBSD Foundation
34: * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
35: * NASA Ames Research Center.
36: *
37: * Redistribution and use in source and binary forms, with or without
38: * modification, are permitted provided that the following conditions
39: * are met:
40: * 1. Redistributions of source code must retain the above copyright
41: * notice, this list of conditions and the following disclaimer.
42: * 2. Redistributions in binary form must reproduce the above copyright
43: * notice, this list of conditions and the following disclaimer in the
44: * documentation and/or other materials provided with the distribution.
45: * 3. All advertising materials mentioning features or use of this software
46: * must display the following acknowledgement:
47: * This product includes software developed by the NetBSD
48: * Foundation, Inc. and its contributors.
49: * 4. Neither the name of The NetBSD Foundation nor the names of its
50: * contributors may be used to endorse or promote products derived
51: * from this software without specific prior written permission.
52: *
53: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
54: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
55: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
57: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
58: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
59: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
60: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
61: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
62: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
63: * POSSIBILITY OF SUCH DAMAGE.
64: */
65: /*
66: * Copyright (c) 1999, by UCHIYAMA Yasushi
67: * All rights reserved.
68: *
69: * Redistribution and use in source and binary forms, with or without
70: * modification, are permitted provided that the following conditions
71: * are met:
72: * 1. Redistributions of source code must retain the above copyright
73: * notice, this list of conditions and the following disclaimer.
74: * 2. The name of the developer may NOT be used to endorse or promote products
75: * derived from this software without specific prior written permission.
76: *
77: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
78: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
79: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
80: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
81: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
82: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
83: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
84: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
85: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
86: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
87: * SUCH DAMAGE.
88: */
89:
90: /*
91: * Interface to the PCI BIOS and PCI Interrupt Routing table.
92: */
93:
94: #include <sys/param.h>
95: #include <sys/systm.h>
96: #include <sys/device.h>
97: #include <sys/malloc.h>
98:
99: #include <dev/isa/isareg.h>
100: #include <i386/isa/isa_machdep.h>
101:
102: #include <dev/pci/pcireg.h>
103: #include <dev/pci/pcivar.h>
104: #include <dev/pci/pcidevs.h>
105:
106: #include <i386/pci/pcibiosvar.h>
107:
108: #include <machine/biosvar.h>
109:
110: int pcibios_flags;
111: int pcibios_present;
112:
113: struct pcibios_pir_header pcibios_pir_header;
114: struct pcibios_intr_routing *pcibios_pir_table;
115: int pcibios_pir_table_nentries;
116: int pcibios_flags = 0;
117:
118: struct bios32_entry pcibios_entry;
119: struct bios32_entry_info pcibios_entry_info;
120:
121: struct pcibios_intr_routing *pcibios_pir_init(struct pcibios_softc *);
122:
123: int pcibios_get_status(struct pcibios_softc *,
124: u_int32_t *, u_int32_t *, u_int32_t *,
125: u_int32_t *, u_int32_t *, u_int32_t *, u_int32_t *);
126: int pcibios_get_intr_routing(struct pcibios_softc *,
127: struct pcibios_intr_routing *, int *, u_int16_t *);
128:
129: int pcibios_return_code(struct pcibios_softc *, u_int16_t, const char *);
130:
131: void pcibios_print_exclirq(struct pcibios_softc *);
132: void pcibios_print_pir_table(void);
133:
134: #define PCI_IRQ_TABLE_START 0xf0000
135: #define PCI_IRQ_TABLE_END 0xfffff
136:
137: struct cfdriver pcibios_cd = {
138: NULL, "pcibios", DV_DULL
139: };
140:
141: int pcibiosprobe(struct device *, void *, void *);
142: void pcibiosattach(struct device *, struct device *, void *);
143:
144: struct cfattach pcibios_ca = {
145: sizeof(struct pcibios_softc), pcibiosprobe, pcibiosattach
146: };
147:
148: int
149: pcibiosprobe(struct device *parent, void *match, void *aux)
150: {
151: struct bios_attach_args *ba = aux;
152: u_int32_t rev_maj, rev_min, mech1, mech2, scmech1, scmech2, maxbus;
153: int rv;
154:
155: if (strcmp(ba->bios_dev, "pcibios"))
156: return 0;
157:
158: rv = bios32_service(PCIBIOS_SIGNATURE, &pcibios_entry,
159: &pcibios_entry_info);
160:
161: PCIBIOS_PRINTV(("pcibiosprobe: 0x%lx:0x%lx at 0x%lx[0x%lx]\n",
162: pcibios_entry.segment, pcibios_entry.offset,
163: pcibios_entry_info.bei_base, pcibios_entry_info.bei_size));
164:
165: return rv &&
166: pcibios_get_status(NULL, &rev_maj, &rev_min, &mech1, &mech2,
167: &scmech1, &scmech2, &maxbus) == PCIBIOS_SUCCESS;
168: }
169:
170: void
171: pcibiosattach(struct device *parent, struct device *self, void *aux)
172: {
173: struct pcibios_softc *sc = (struct pcibios_softc *)self;
174: u_int32_t rev_maj, rev_min, mech1, mech2, scmech1, scmech2;
175:
176: pcibios_flags = sc->sc_dev.dv_cfdata->cf_flags;
177:
178: pcibios_get_status((struct pcibios_softc *)self, &rev_maj,
179: &rev_min, &mech1, &mech2,
180: &scmech1, &scmech2, &sc->max_bus);
181:
182: printf(": rev %d.%d @ 0x%lx/0x%lx\n",
183: rev_maj, rev_min >> 4, pcibios_entry_info.bei_base,
184: pcibios_entry_info.bei_size);
185:
186: PCIBIOS_PRINTV(("%s: config mechanism %s%s, special cycles %s%s, "
187: "last bus %d\n", sc->sc_dev.dv_xname,
188: mech1 ? "[1]" : "[x]", mech2 ? "[2]" : "[x]",
189: scmech1 ? "[1]" : "[x]", scmech2 ? "[2]" : "[x]", sc->max_bus));
190:
191: /*
192: * The PCI BIOS tells us the config mechanism; fill it in now
193: * so that pci_mode_detect() doesn't have to look for it.
194: */
195: pci_mode = mech1 ? 1 : 2;
196:
197: pcibios_present = 1;
198:
199: /*
200: * Find the PCI IRQ Routing table.
201: */
202:
203: if (!(pcibios_flags & PCIBIOS_INTR_FIXUP) &&
204: pcibios_pir_init((struct pcibios_softc *)self) != NULL) {
205: int rv;
206:
207: /*
208: * Fixup interrupt routing.
209: */
210: rv = pci_intr_fixup(sc, NULL, I386_BUS_SPACE_IO);
211: switch (rv) {
212: case -1:
213: /* Non-fatal error. */
214: printf("%s: Warning, unable to fix up PCI interrupt "
215: "routing\n", sc->sc_dev.dv_xname);
216: break;
217:
218: case 1:
219: /* Fatal error. */
220: printf("%s: interrupt fixup failed\n", sc->sc_dev.dv_xname);
221: return;
222: }
223:
224: /*
225: * XXX Clear `pciirq' from the ISA interrupt allocation
226: * XXX mask.
227: */
228: }
229:
230: if (!(pcibios_flags & PCIBIOS_BUS_FIXUP)) {
231: sc->max_bus = pci_bus_fixup(NULL, 0);
232: printf("%s: PCI bus #%d is the last bus\n",
233: sc->sc_dev.dv_xname, sc->max_bus);
234: }
235:
236: if (!(pcibios_flags & PCIBIOS_ADDR_FIXUP))
237: pci_addr_fixup(sc, NULL, sc->max_bus);
238: }
239:
240: struct pcibios_intr_routing *
241: pcibios_pir_init(struct pcibios_softc *sc)
242: {
243: paddr_t pa;
244:
245: pcibios_pir_table = NULL;
246: for (pa = PCI_IRQ_TABLE_START; pa < PCI_IRQ_TABLE_END; pa += 16) {
247: u_int8_t *p, cksum;
248: struct pcibios_pir_header *pirh;
249: int i;
250:
251: p = ISA_HOLE_VADDR(pa);
252: pirh = (struct pcibios_pir_header *)p;
253: /*
254: * Some laptops (such as the Toshiba Libretto L series)
255: * use _PIR instead of the standard $PIR for the signature
256: * so we check for that too.
257: */
258: if (pirh->signature != BIOS32_MAKESIG('$', 'P', 'I', 'R') &&
259: pirh->signature != BIOS32_MAKESIG('_', 'P', 'I', 'R'))
260: continue;
261:
262: if (pirh->tablesize < sizeof(*pirh))
263: continue;
264:
265: cksum = 0;
266: for (i = 0; i < pirh->tablesize; i++)
267: cksum += p[i];
268:
269: printf("%s: PCI IRQ Routing Table rev %d.%d @ 0x%lx/%d "
270: "(%d entries)\n", sc->sc_dev.dv_xname,
271: pirh->version >> 8, pirh->version & 0xff, pa,
272: pirh->tablesize, (pirh->tablesize - sizeof(*pirh)) / 16);
273:
274: if (cksum != 0) {
275: printf("%s: bad IRQ table checksum\n",
276: sc->sc_dev.dv_xname);
277: continue;
278: }
279:
280: if (pirh->tablesize % 16 != 0) {
281: printf("%s: bad IRQ table size\n", sc->sc_dev.dv_xname);
282: continue;
283: }
284:
285: if (pirh->version != 0x0100) {
286: printf("%s: unsupported IRQ table version\n",
287: sc->sc_dev.dv_xname);
288: continue;
289: }
290:
291: /*
292: * We can handle this table! Make a copy of it.
293: */
294: pcibios_pir_header = *pirh;
295: pcibios_pir_table =
296: malloc(pirh->tablesize - sizeof(*pirh), M_DEVBUF, M_NOWAIT);
297: if (pcibios_pir_table == NULL) {
298: printf("%s: no memory for $PIR\n", sc->sc_dev.dv_xname);
299: return NULL;
300: }
301: bcopy(p + sizeof(*pirh), pcibios_pir_table,
302: pirh->tablesize - sizeof(*pirh));
303: pcibios_pir_table_nentries =
304: (pirh->tablesize - sizeof(*pirh)) / 16;
305:
306: }
307:
308: /*
309: * If there was no PIR table found, try using the PCI BIOS
310: * Get Interrupt Routing call.
311: *
312: * XXX The interface to this call sucks; just allocate enough
313: * XXX room for 32 entries.
314: */
315: if (pcibios_pir_table == NULL) {
316:
317: pcibios_pir_table_nentries = 32;
318: pcibios_pir_table = malloc(pcibios_pir_table_nentries *
319: sizeof(*pcibios_pir_table), M_DEVBUF, M_NOWAIT);
320: if (pcibios_pir_table == NULL) {
321: printf("%s: no memory for $PIR\n", sc->sc_dev.dv_xname);
322: return NULL;
323: }
324: if (pcibios_get_intr_routing(sc, pcibios_pir_table,
325: &pcibios_pir_table_nentries,
326: &pcibios_pir_header.exclusive_irq) != PCIBIOS_SUCCESS) {
327: printf("%s: PCI IRQ Routing information unavailable.\n",
328: sc->sc_dev.dv_xname);
329: free(pcibios_pir_table, M_DEVBUF);
330: pcibios_pir_table = NULL;
331: pcibios_pir_table_nentries = 0;
332: return NULL;
333: }
334: printf("%s: PCI BIOS has %d Interrupt Routing table entries\n",
335: sc->sc_dev.dv_xname, pcibios_pir_table_nentries);
336: }
337:
338: pcibios_print_exclirq(sc);
339: if (pcibios_flags & PCIBIOS_INTRDEBUG)
340: pcibios_print_pir_table();
341: return pcibios_pir_table;
342: }
343:
344: int
345: pcibios_get_status(struct pcibios_softc *sc, u_int32_t *rev_maj,
346: u_int32_t *rev_min, u_int32_t *mech1, u_int32_t *mech2, u_int32_t *scmech1,
347: u_int32_t *scmech2, u_int32_t *maxbus)
348: {
349: u_int32_t ax, bx, cx, edx;
350: int rv;
351:
352: __asm __volatile("pushl %%es\n\t"
353: "pushl %%ds\n\t"
354: "movw 4(%%edi), %%cx\n\t"
355: "movl %%ecx, %%ds\n\t"
356: "lcall %%cs:*(%%edi)\n\t"
357: "pop %%ds\n\t"
358: "pop %%es\n\t"
359: "jc 1f\n\t"
360: "xor %%ah, %%ah\n"
361: "1:"
362: : "=a" (ax), "=b" (bx), "=c" (cx), "=d" (edx)
363: : "0" (0xb101), "D" (&pcibios_entry)
364: : "cc", "memory");
365:
366: rv = pcibios_return_code(sc, ax, "pcibios_get_status");
367: if (rv != PCIBIOS_SUCCESS)
368: return (rv);
369:
370: if (edx != BIOS32_MAKESIG('P', 'C', 'I', ' '))
371: return (PCIBIOS_SERVICE_NOT_PRESENT); /* XXX */
372:
373: /*
374: * Fill in the various pieces of info we're looking for.
375: */
376: *mech1 = ax & 1;
377: *mech2 = ax & (1 << 1);
378: *scmech1 = ax & (1 << 4);
379: *scmech2 = ax & (1 << 5);
380: *rev_maj = (bx >> 8) & 0xff;
381: *rev_min = bx & 0xff;
382: *maxbus = cx & 0xff;
383:
384: return (PCIBIOS_SUCCESS);
385: }
386:
387: int
388: pcibios_get_intr_routing(struct pcibios_softc *sc,
389: struct pcibios_intr_routing *table, int *nentries, u_int16_t *exclirq)
390: {
391: u_int32_t ax, bx;
392: int rv;
393: struct {
394: u_int16_t size;
395: u_int32_t offset;
396: u_int16_t segment;
397: } __attribute__((__packed__)) args;
398:
399: args.size = *nentries * sizeof(*table);
400: args.offset = (u_int32_t)table;
401: args.segment = GSEL(GDATA_SEL, SEL_KPL);
402:
403: memset(table, 0, args.size);
404:
405: __asm __volatile("pushl %%es\n\t"
406: "pushl %%ds\n\t"
407: "movw 4(%%esi), %%cx\n\t"
408: "movl %%ecx, %%ds\n\t"
409: "lcall %%cs:*(%%esi)\n\t"
410: "popl %%ds\n\t"
411: "popl %%es\n\t"
412: "jc 1f\n\t"
413: "xor %%ah, %%ah\n"
414: "1:\n"
415: : "=a" (ax), "=b" (bx)
416: : "0" (0xb10e), "1" (0), "D" (&args), "S" (&pcibios_entry)
417: : "%ecx", "%edx", "cc", "memory");
418:
419: rv = pcibios_return_code(sc, ax, "pcibios_get_intr_routing");
420: if (rv != PCIBIOS_SUCCESS)
421: return (rv);
422:
423: *nentries = args.size / sizeof(*table);
424: *exclirq |= bx;
425:
426: return (PCIBIOS_SUCCESS);
427: }
428:
429: int
430: pcibios_return_code(struct pcibios_softc *sc, u_int16_t ax, const char *func)
431: {
432: const char *errstr;
433: int rv = ax >> 8;
434: char *nam;
435:
436: if (sc)
437: nam = sc->sc_dev.dv_xname;
438: else
439: nam = "pcibios0";
440:
441: switch (rv) {
442: case PCIBIOS_SUCCESS:
443: return (PCIBIOS_SUCCESS);
444:
445: case PCIBIOS_SERVICE_NOT_PRESENT:
446: errstr = "service not present";
447: break;
448:
449: case PCIBIOS_FUNCTION_NOT_SUPPORTED:
450: errstr = "function not supported";
451: break;
452:
453: case PCIBIOS_BAD_VENDOR_ID:
454: errstr = "bad vendor ID";
455: break;
456:
457: case PCIBIOS_DEVICE_NOT_FOUND:
458: errstr = "device not found";
459: break;
460:
461: case PCIBIOS_BAD_REGISTER_NUMBER:
462: errstr = "bad register number";
463: break;
464:
465: case PCIBIOS_SET_FAILED:
466: errstr = "set failed";
467: break;
468:
469: case PCIBIOS_BUFFER_TOO_SMALL:
470: errstr = "buffer too small";
471: break;
472:
473: default:
474: printf("%s: %s - unknown return code 0x%x\n",
475: nam, func, rv);
476: return (rv);
477: }
478:
479: printf("%s: %s - %s\n", nam, func, errstr);
480: return (rv);
481: }
482:
483: void
484: pcibios_print_exclirq(struct pcibios_softc *sc)
485: {
486: int i;
487:
488: if (pcibios_pir_header.exclusive_irq) {
489: printf("%s: PCI Exclusive IRQs:", sc->sc_dev.dv_xname);
490: for (i = 0; i < 16; i++) {
491: if (pcibios_pir_header.exclusive_irq & (1 << i))
492: printf(" %d", i);
493: }
494: printf("\n");
495: }
496: }
497:
498: void
499: pcibios_print_pir_table(void)
500: {
501: int i, j;
502:
503: for (i = 0; i < pcibios_pir_table_nentries; i++) {
504: printf("PIR Entry %d:\n", i);
505: printf("\tBus: %d Device: %d\n",
506: pcibios_pir_table[i].bus,
507: PIR_DEVFUNC_DEVICE(pcibios_pir_table[i].device));
508: for (j = 0; j < 4; j++) {
509: printf("\t\tINT%c: link 0x%02x bitmap 0x%04x\n",
510: 'A' + j,
511: pcibios_pir_table[i].linkmap[j].link,
512: pcibios_pir_table[i].linkmap[j].bitmap);
513: }
514: }
515: }
516:
517: void
518: pci_device_foreach(struct pcibios_softc *sc, pci_chipset_tag_t pc, int maxbus,
519: void (*func)(struct pcibios_softc *, pci_chipset_tag_t, pcitag_t))
520: {
521: const struct pci_quirkdata *qd;
522: int bus, device, function, maxdevs, nfuncs;
523: pcireg_t id, bhlcr;
524: pcitag_t tag;
525:
526: for (bus = 0; bus <= maxbus; bus++) {
527: maxdevs = pci_bus_maxdevs(pc, bus);
528: for (device = 0; device < maxdevs; device++) {
529: tag = pci_make_tag(pc, bus, device, 0);
530: id = pci_conf_read(pc, tag, PCI_ID_REG);
531:
532: /* Invalid vendor ID value? */
533: if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
534: continue;
535: /* XXX Not invalid, but we've done this ~forever. */
536: if (PCI_VENDOR(id) == 0)
537: continue;
538:
539: qd = pci_lookup_quirkdata(PCI_VENDOR(id),
540: PCI_PRODUCT(id));
541:
542: bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
543: if (PCI_HDRTYPE_MULTIFN(bhlcr) ||
544: (qd != NULL &&
545: (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
546: nfuncs = 8;
547: else
548: nfuncs = 1;
549:
550: for (function = 0; function < nfuncs; function++) {
551: tag = pci_make_tag(pc, bus, device, function);
552: id = pci_conf_read(pc, tag, PCI_ID_REG);
553:
554: /* Invalid vendor ID value? */
555: if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
556: continue;
557: /*
558: * XXX Not invalid, but we've done this
559: * ~forever.
560: */
561: if (PCI_VENDOR(id) == 0)
562: continue;
563: (*func)(sc, pc, tag);
564: }
565: }
566: }
567: }
CVSweb