2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
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.
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.
26 * $FreeBSD: src/sys/pci/pci_compat.c,v 1.35.2.1 2001/10/14 21:14:14 luigi Exp $
27 * $DragonFly: src/sys/bus/pci/pci_compat.c,v 1.12 2006/10/25 20:55:51 dillon Exp $
33 /* for compatibility to FreeBSD-2.2 and 3.x versions of PCI code */
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 #include <sys/module.h>
45 #include <machine/smp.h>
46 #include <sys/interrupt.h>
48 #include <sys/pciio.h>
52 struct pci_compat_driver
{
54 struct pci_device
*dvp
;
57 /* ------------------------------------------------------------------------- */
60 pci_conf_read(pcici_t cfg
, u_long reg
)
62 return (pci_read_config(cfg
->dev
, reg
, 4));
66 pci_conf_write(pcici_t cfg
, u_long reg
, u_long data
)
68 pci_write_config(cfg
->dev
, reg
, data
, 4);
72 pci_map_port(pcici_t cfg
, u_long reg
, pci_port_t
* pa
)
78 res
= bus_alloc_resource(cfg
->dev
, SYS_RES_IOPORT
, &rid
,
81 *pa
= rman_get_start(res
);
88 pci_map_mem(pcici_t cfg
, u_long reg
, vm_offset_t
* va
, vm_offset_t
* pa
)
94 res
= bus_alloc_resource(cfg
->dev
, SYS_RES_MEMORY
, &rid
,
97 *pa
= rman_get_start(res
);
98 *va
= (vm_offset_t
) rman_get_virtual(res
);
105 pci_map_int(pcici_t cfg
, pci_inthand_t
*handler
, void *arg
)
107 return (pci_map_int_right(cfg
, handler
, arg
, 0));
111 pci_map_int_right(pcici_t cfg
, pci_inthand_t
*handler
, void *arg
, u_int intflags
)
117 if (cfg
->intpin
!= 0) {
118 int irq
= cfg
->intline
;
120 struct resource
*res
;
122 int resflags
= RF_SHAREABLE
|RF_ACTIVE
;
125 if (intflags
& INTR_FAST
)
127 if (intflags
& INTR_EXCL
)
128 resflags
&= ~RF_SHAREABLE
;
130 res
= bus_alloc_resource(cfg
->dev
, SYS_RES_IRQ
, &rid
,
131 irq
, irq
, 1, resflags
);
133 printf("pci_map_int: can't allocate interrupt\n");
138 * This is ugly. Translate the mask into an interrupt type.
141 error
= BUS_SETUP_INTR(device_get_parent(cfg
->dev
), cfg
->dev
,
142 res
, flags
, handler
, arg
, &ih
, NULL
);
148 * XXX this apic stuff looks totally busted. It should
149 * move to the nexus code which actually registers the
155 nextpin
= next_apic_irq(irq
);
161 * Attempt handling of some broken mp tables.
163 * It's OK to yell (since the mp tables are broken).
165 * Hanging in the boot is not OK
169 nextpin
= next_apic_irq(nextpin
);
170 while (muxcnt
< 5 && nextpin
>= 0) {
172 nextpin
= next_apic_irq(nextpin
);
175 printf("bogus MP table, more than 4 IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n");
179 printf("bogus MP table, %d IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n", muxcnt
);
181 nextpin
= next_apic_irq(irq
);
182 while (nextpin
>= 0) {
184 res
= bus_alloc_resource(cfg
->dev
, SYS_RES_IRQ
, &rid
,
188 printf("pci_map_int: can't allocate extra interrupt\n");
191 error
= BUS_SETUP_INTR(device_get_parent(cfg
->dev
),
192 cfg
->dev
, res
, flags
,
193 handler
, arg
, &ih
, NULL
);
195 printf("pci_map_int: BUS_SETUP_INTR failed\n");
198 printf("Registered extra interrupt handler for int %d (in addition to int %d)\n", nextpin
, irq
);
199 nextpin
= next_apic_irq(nextpin
);
207 pci_unmap_int(pcici_t cfg
)
209 return (0); /* not supported, yet, since cfg doesn't know about idesc */
213 pci_get_parent_from_tag(pcici_t tag
)
215 return (pcici_t
)pci_devlist_get_parent(tag
);
219 pci_get_bus_from_tag(pcici_t tag
)
225 * A simple driver to wrap the old pci driver mechanism for back-compat.
229 pci_compat_probe(device_t dev
)
231 struct pci_device
*dvp
;
232 struct pci_devinfo
*dinfo
;
237 dinfo
= device_get_ivars(dev
);
239 dvp
= ((struct pci_compat_driver
*)device_get_driver(dev
))->dvp
;
242 * Do the wrapped probe.
245 if (dvp
&& dvp
->pd_probe
) {
246 name
= dvp
->pd_probe(cfg
, (cfg
->device
<< 16) + cfg
->vendor
);
248 device_set_desc_copy(dev
, name
);
249 /* Allow newbus drivers to match "better" */
258 pci_compat_attach(device_t dev
)
260 struct pci_device
*dvp
;
261 struct pci_devinfo
*dinfo
;
265 dinfo
= device_get_ivars(dev
);
267 dvp
= ((struct pci_compat_driver
*)device_get_driver(dev
))->dvp
;
269 unit
= device_get_unit(dev
);
270 if (unit
> *dvp
->pd_count
)
271 *dvp
->pd_count
= unit
;
273 dvp
->pd_attach(cfg
, unit
);
274 device_printf(dev
, "driver is using old-style compatability shims\n");
278 static device_method_t pci_compat_methods
[] = {
279 /* Device interface */
280 DEVMETHOD(device_probe
, pci_compat_probe
),
281 DEVMETHOD(device_attach
, pci_compat_attach
),
287 * Create a new style driver around each old pci driver.
290 compat_pci_handler(module_t mod
, int type
, void *data
)
292 struct pci_device
*dvp
= (struct pci_device
*)data
;
293 struct pci_compat_driver
*driver
;
294 devclass_t pci_devclass
= devclass_find("pci");
298 driver
= kmalloc(sizeof(struct pci_compat_driver
), M_DEVBUF
, M_WAITOK
| M_ZERO
);
299 driver
->driver
.name
= dvp
->pd_name
;
300 driver
->driver
.methods
= pci_compat_methods
;
301 driver
->driver
.size
= sizeof(struct pci_devinfo
*);
303 devclass_add_driver(pci_devclass
, (driver_t
*)driver
);
306 printf("%s: module unload not supported!\n", dvp
->pd_name
);