FreeBSD/Linux Kernel Cross Reference
sys/pci/pci_compat.c
1 /*
2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
10 * disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 *
28 */
29
30 #include "pci.h"
31 #if NPCI > 0
32
33 /* for compatibility to FreeBSD-2.2 version of PCI code */
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 #include <sys/linker_set.h>
39
40 #include <vm/vm.h>
41 #include <vm/pmap.h>
42 #include <sys/interrupt.h>
43
44 #include <pci/pcireg.h>
45 #include <pci/pcivar.h>
46
47 #ifdef RESOURCE_CHECK
48 #include <sys/drvresource.h>
49 #endif
50
51 #ifdef APIC_IO
52 #include <machine/smp.h>
53 #endif
54
55 #ifdef PCI_COMPAT
56
57 /* ------------------------------------------------------------------------- */
58
59 static int
60 pci_mapno(pcicfgregs *cfg, int reg)
61 {
62 int i, nummaps;
63 pcimap *map;
64
65 nummaps = cfg->nummaps;
66 map = cfg->map;
67
68 for (i = 0; i < nummaps; i++)
69 if (map[i].reg == reg)
70 return (i);
71 return (-1);
72 }
73
74 static int
75 pci_porten(pcicfgregs *cfg)
76 {
77 return ((cfg->cmdreg & PCIM_CMD_PORTEN) != 0);
78 }
79
80 static int
81 pci_isportmap(pcicfgregs *cfg, int map)
82
83 {
84 return ((unsigned)map < cfg->nummaps
85 && (cfg->map[map].type & PCI_MAPPORT) != 0);
86 }
87
88 static int
89 pci_memen(pcicfgregs *cfg)
90 {
91 return ((cfg->cmdreg & PCIM_CMD_MEMEN) != 0);
92 }
93
94 static int
95 pci_ismemmap(pcicfgregs *cfg, int map)
96 {
97 return ((unsigned)map < cfg->nummaps
98 && (cfg->map[map].type & PCI_MAPMEM) != 0);
99 }
100
101 /* ------------------------------------------------------------------------- */
102
103 u_long
104 pci_conf_read(pcici_t tag, u_long reg)
105 {
106 return (pci_cfgread(tag, reg, 4));
107 }
108
109 void
110 pci_conf_write(pcici_t tag, u_long reg, u_long data)
111 {
112 pci_cfgwrite(tag, reg, data, 4);
113 }
114
115 int pci_map_port(pcici_t cfg, u_long reg, pci_port_t* pa)
116 {
117 int map;
118
119 map = pci_mapno(cfg, reg);
120 if (pci_porten(cfg) && pci_isportmap(cfg, map)) {
121 u_int32_t iobase;
122 u_int32_t iosize;
123
124 iobase = cfg->map[map].base;
125 iosize = 1 << cfg->map[map].ln2size;
126 #ifdef RESOURCE_CHECK
127 if (resource_claim(cfg, REST_PORT, RESF_NONE,
128 iobase, iobase + iosize -1) == 0)
129 #endif /* RESOURCE_CHECK */
130 {
131 *pa = iobase;
132 return (1);
133 }
134 }
135 return (0);
136 }
137
138 int pci_map_mem(pcici_t cfg, u_long reg, vm_offset_t* va, vm_offset_t* pa)
139 {
140 int map;
141
142 map = pci_mapno(cfg, reg);
143 if (pci_memen(cfg) && pci_ismemmap(cfg, map)) {
144 u_int32_t paddr;
145 u_int32_t psize;
146
147 paddr = cfg->map[map].base;
148 psize = 1 << cfg->map[map].ln2size;
149 #ifdef RESOURCE_CHECK
150 if (resource_claim(cfg, REST_MEM, RESF_NONE,
151 paddr, paddr + psize -1) == 0)
152 #endif /* RESOURCE_CHECK */
153 {
154 u_int32_t poffs;
155 vm_offset_t vaddr;
156
157 poffs = paddr - trunc_page(paddr);
158 #ifdef __i386__
159 vaddr = (vm_offset_t)pmap_mapdev(paddr-poffs, psize+poffs);
160 #endif
161 #ifdef __alpha__
162 vaddr = paddr-poffs;
163 #endif
164 if (vaddr != NULL) {
165 vaddr += poffs;
166 *va = vaddr;
167 *pa = paddr;
168 return (1);
169 }
170 }
171 }
172 return (0);
173 }
174
175 int
176 pci_map_dense(pcici_t cfg, u_long reg, vm_offset_t* va, vm_offset_t* pa)
177 {
178 if(pci_map_mem(cfg, reg, va, pa)){
179 #ifdef __alpha__
180 vm_offset_t dense;
181
182 if(dense = pci_cvt_to_dense(*pa)){
183 *pa = dense;
184 *va = ALPHA_PHYS_TO_K0SEG(*pa);
185 return (1);
186 }
187 #endif
188 #ifdef __i386__
189 return(1);
190 #endif
191 }
192 return (0);
193 }
194
195 int
196 pci_map_bwx(pcici_t cfg, u_long reg, vm_offset_t* va, vm_offset_t* pa)
197 {
198 if(pci_map_mem(cfg, reg, va, pa)){
199 #ifdef __alpha__
200 vm_offset_t bwx;
201
202 if(bwx = pci_cvt_to_bwx(*pa)){
203 *pa = bwx;
204 *va = ALPHA_PHYS_TO_K0SEG(*pa);
205 return (1);
206 }
207 #endif
208 #ifdef __i386__
209 return(1);
210 #endif
211 }
212 return (0);
213 }
214
215 int
216 pci_map_int(pcici_t cfg, pci_inthand_t *handler, void *arg, intrmask_t *maskptr)
217 {
218 return (pci_map_int_right(cfg, handler, arg, maskptr, 0));
219 }
220
221 int
222 pci_map_int_right(pcici_t cfg, pci_inthand_t *handler, void *arg,
223 intrmask_t *maskptr, u_int flags)
224 {
225 int error;
226 #ifdef APIC_IO
227 int nextpin, muxcnt;
228 #endif
229 if (cfg->intpin != 0) {
230 int irq = cfg->intline;
231 void *dev_instance = (void *)-1; /* XXX use cfg->devdata */
232 void *idesc;
233
234 idesc = intr_create(dev_instance, irq, handler, arg, maskptr,
235 flags);
236 error = intr_connect(idesc);
237 if (error != 0)
238 return 0;
239 #ifdef APIC_IO
240 nextpin = next_apic_irq(irq);
241
242 if (nextpin < 0)
243 return 1;
244
245 /*
246 * Attempt handling of some broken mp tables.
247 *
248 * It's OK to yell (since the mp tables are broken).
249 *
250 * Hanging in the boot is not OK
251 */
252
253 muxcnt = 2;
254 nextpin = next_apic_irq(nextpin);
255 while (muxcnt < 5 && nextpin >= 0) {
256 muxcnt++;
257 nextpin = next_apic_irq(nextpin);
258 }
259 if (muxcnt >= 5) {
260 printf("bogus MP table, more than 4 IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n");
261 return 0;
262 }
263
264 printf("bogus MP table, %d IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n", muxcnt);
265
266 nextpin = next_apic_irq(irq);
267 while (nextpin >= 0) {
268 idesc = intr_create(dev_instance, nextpin, handler,
269 arg, maskptr, flags);
270 error = intr_connect(idesc);
271 if (error != 0)
272 return 0;
273 printf("Registered extra interrupt handler for int %d (in addition to int %d)\n", nextpin, irq);
274 nextpin = next_apic_irq(nextpin);
275 }
276 #endif
277 }
278 return (1);
279 }
280
281 int
282 pci_unmap_int(pcici_t cfg)
283 {
284 return (0); /* not supported, yet, since cfg doesn't know about idesc */
285 }
286
287 pcici_t
288 pci_get_parent_from_tag(pcici_t tag)
289 {
290 return (pcici_t)pci_devlist_get_parent(tag);
291 }
292
293 int
294 pci_get_bus_from_tag(pcici_t tag)
295 {
296 return tag->bus;
297 }
298
299 /* ------------------------------------------------------------------------- */
300
301 /*
302 * Preliminary support for "wired" PCI devices.
303 * This code supports currently only devices on PCI bus 0, since the
304 * mapping from PCI BIOS bus numbers to configuration file bus numbers
305 * is not yet maintained, whenever a PCI to PCI bridge is found.
306 * The "bus" field of "pciwirecfg" correlates an PCI bus with the bridge
307 * it is attached to. The "biosbus" field is to be updated for each bus,
308 * whose bridge is probed. An entry with bus != 0 and biosbus == 0 is
309 * invalid and will be skipped in the search for a wired unit, but not
310 * in the test for a free unit number.
311 */
312
313 typedef struct {
314 char *name;
315 int unit;
316 u_int8_t bus;
317 u_int8_t slot;
318 u_int8_t func;
319 u_int8_t biosbus;
320 } pciwirecfg;
321
322 static pciwirecfg pci_wireddevs[] = {
323 /* driver, unit, bus, slot, func, BIOS bus */
324 #ifdef PCI_DEBUG
325 { "ncr", 2, 1, 4, 0, 0 },
326 { "ed", 2, 1, 5, 0, 0 },
327 #endif /* PCI_DEBUG */
328 /* do not delete the end marker that follows this comment !!! */
329 { NULL }
330 };
331
332 /* return unit number of wired device, or -1 if no match */
333
334 static int
335 pci_wiredunit(pcicfgregs *cfg, char *name)
336 {
337 pciwirecfg *p;
338
339 p = pci_wireddevs;
340 while (p->name != NULL) {
341 if (p->bus == cfg->bus
342 && p->slot == cfg->slot
343 && p->func == cfg->func
344 && strcmp(p->name, name) == 0)
345 return (p->unit);
346 p++;
347 }
348 return (-1);
349 }
350
351 /* return free unit number equal or greater to the one supplied as parameter */
352
353 static int
354 pci_freeunit(pcicfgregs *cfg, char *name, int unit)
355 {
356 pciwirecfg *p;
357
358 p = pci_wireddevs;
359 while (p->name != NULL) {
360 if (p->unit == unit && strcmp(p->name, name) == 0) {
361 p = pci_wireddevs;
362 unit++;
363 } else {
364 p++;
365 }
366 }
367 return (unit);
368 }
369
370 static const char *drvname;
371
372 static const char*
373 pci_probedrv(pcicfgregs *cfg, struct pci_device *dvp)
374 {
375 if (dvp && dvp->pd_probe) {
376 pcidi_t type = (cfg->device << 16) + cfg->vendor;
377 return (dvp->pd_probe(cfg, type));
378 }
379 return (NULL);
380 }
381
382 static struct pci_lkm *pci_lkm_head;
383
384 static struct pci_device*
385 pci_finddrv(pcicfgregs *cfg)
386 {
387 struct pci_device **dvpp;
388 struct pci_device *dvp = NULL;
389 struct pci_lkm *lkm;
390
391 drvname = NULL;
392 lkm = pci_lkm_head;
393 while (drvname == NULL && lkm != NULL) {
394 dvp = lkm->dvp;
395 drvname = pci_probedrv(cfg, dvp);
396 lkm = lkm->next;
397 }
398
399 /*
400 * it wasn't a loaded driver, look in the linked in ones
401 */
402 dvpp = (struct pci_device **)pcidevice_set.ls_items;
403 while (drvname == NULL && (dvp = *dvpp++) != NULL)
404 drvname = pci_probedrv(cfg, dvp);
405
406 /*
407 * It wasn't one of the linked in drivers either, so try the defaults.
408 */
409 if (drvname == NULL) {
410 dvp = &chipset_device;
411 if ((drvname = pci_probedrv(cfg, dvp)) == NULL)
412 dvp = NULL;;
413 }
414 return (dvp);
415 }
416
417 static void
418 pci_drvmessage(pcicfgregs *cfg, char *name, int unit)
419 {
420 if (drvname == NULL || *drvname == '\0')
421 return;
422 printf("%s%d: <%s> rev 0x%02x", name, unit, drvname, cfg->revid);
423 if (cfg->intpin != 0)
424 printf(" int %c irq %d", cfg->intpin + 'a' -1, cfg->intline);
425 printf(" on pci%d.%d.%d\n", cfg->bus, cfg->slot, cfg->func);
426 }
427
428
429 void
430 pci_drvattach(struct pci_devinfo *dinfo)
431 {
432 struct pci_device *dvp;
433 pcicfgregs *cfg;
434
435 cfg = &dinfo->cfg;
436 dvp = pci_finddrv(cfg);
437 if (dvp != NULL) {
438 int unit;
439
440 unit = pci_wiredunit(cfg, dvp->pd_name);
441 if (unit < 0) {
442 unit = pci_freeunit(cfg, dvp->pd_name, *dvp->pd_count);
443 *dvp->pd_count = unit +1;
444 }
445 pci_drvmessage(cfg, dvp->pd_name, unit);
446 if (dvp->pd_attach)
447 dvp->pd_attach(cfg, unit);
448
449 dinfo->device = dvp;
450
451 /*
452 * XXX KDM for some devices, dvp->pd_name winds up NULL.
453 * I haven't investigated enough to figure out why this
454 * would happen.
455 */
456 if (dvp->pd_name != NULL)
457 strncpy(dinfo->conf.pd_name, dvp->pd_name,
458 sizeof(dinfo->conf.pd_name));
459 else
460 strncpy(dinfo->conf.pd_name, "????",
461 sizeof(dinfo->conf.pd_name));
462 dinfo->conf.pd_name[sizeof(dinfo->conf.pd_name) - 1] = 0;
463
464 dinfo->conf.pd_unit = unit;
465
466 }
467 }
468
469 /* ------------------------------------------------------------------------- */
470
471 static void
472 pci_rescan(void)
473 {
474 /* XXX do nothing, currently, soon to come ... */
475 }
476
477 int pci_register_lkm (struct pci_device *dvp, int if_revision)
478 {
479 struct pci_lkm *lkm;
480
481 if (if_revision != 0) {
482 return (-1);
483 }
484 if (dvp == NULL || dvp->pd_probe == NULL || dvp->pd_attach == NULL) {
485 return (-1);
486 }
487 lkm = malloc (sizeof (*lkm), M_DEVBUF, M_WAITOK);
488 if (lkm == NULL) {
489 return (-1);
490 }
491
492 lkm->dvp = dvp;
493 lkm->next = pci_lkm_head;
494 pci_lkm_head = lkm;
495 pci_rescan();
496 return (0);
497 }
498
499 void
500 pci_configure(void)
501 {
502 pci_probe(NULL);
503 }
504
505 /* ------------------------------------------------------------------------- */
506
507 #endif /* PCI_COMPAT */
508 #endif /* NPCI > 0 */
Cache object: 0280e7aa485c456e95506e0b4f041310
|