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