xref: /freebsd/sys/dev/pci/pci_pci.c (revision e36af2929a79cd322be0df1c516bd256b10c7203)
1bb0d0a8eSMike Smith /*-
2bb0d0a8eSMike Smith  * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier
3bb0d0a8eSMike Smith  * Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
4bb0d0a8eSMike Smith  * Copyright (c) 2000 BSDi
5bb0d0a8eSMike Smith  * All rights reserved.
6bb0d0a8eSMike Smith  *
7bb0d0a8eSMike Smith  * Redistribution and use in source and binary forms, with or without
8bb0d0a8eSMike Smith  * modification, are permitted provided that the following conditions
9bb0d0a8eSMike Smith  * are met:
10bb0d0a8eSMike Smith  * 1. Redistributions of source code must retain the above copyright
11bb0d0a8eSMike Smith  *    notice, this list of conditions and the following disclaimer.
12bb0d0a8eSMike Smith  * 2. Redistributions in binary form must reproduce the above copyright
13bb0d0a8eSMike Smith  *    notice, this list of conditions and the following disclaimer in the
14bb0d0a8eSMike Smith  *    documentation and/or other materials provided with the distribution.
15bb0d0a8eSMike Smith  * 3. The name of the author may not be used to endorse or promote products
16bb0d0a8eSMike Smith  *    derived from this software without specific prior written permission.
17bb0d0a8eSMike Smith  *
18bb0d0a8eSMike Smith  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19bb0d0a8eSMike Smith  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20bb0d0a8eSMike Smith  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21bb0d0a8eSMike Smith  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22bb0d0a8eSMike Smith  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23bb0d0a8eSMike Smith  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24bb0d0a8eSMike Smith  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25bb0d0a8eSMike Smith  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26bb0d0a8eSMike Smith  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27bb0d0a8eSMike Smith  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28bb0d0a8eSMike Smith  * SUCH DAMAGE.
29bb0d0a8eSMike Smith  */
30bb0d0a8eSMike Smith 
31aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
32aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
33aad970f1SDavid E. O'Brien 
34bb0d0a8eSMike Smith /*
35bb0d0a8eSMike Smith  * PCI:PCI bridge support.
36bb0d0a8eSMike Smith  */
37bb0d0a8eSMike Smith 
38bb0d0a8eSMike Smith #include <sys/param.h>
39bb0d0a8eSMike Smith #include <sys/systm.h>
40bb0d0a8eSMike Smith #include <sys/kernel.h>
4141ee9f1cSPoul-Henning Kamp #include <sys/module.h>
42bb0d0a8eSMike Smith #include <sys/bus.h>
43a8b354a8SWarner Losh #include <machine/bus.h>
44a8b354a8SWarner Losh #include <sys/rman.h>
451c54ff33SMatthew N. Dodd #include <sys/sysctl.h>
46bb0d0a8eSMike Smith 
47bb0d0a8eSMike Smith #include <machine/resource.h>
48bb0d0a8eSMike Smith 
4938d8c994SWarner Losh #include <dev/pci/pcivar.h>
5038d8c994SWarner Losh #include <dev/pci/pcireg.h>
5138d8c994SWarner Losh #include <dev/pci/pcib_private.h>
52bb0d0a8eSMike Smith 
53bb0d0a8eSMike Smith #include "pcib_if.h"
54bb0d0a8eSMike Smith 
55e36af292SJung-uk Kim #ifdef __HAVE_ACPI
56e36af292SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h>
57e36af292SJung-uk Kim #include "acpi_if.h"
58e36af292SJung-uk Kim #else
59e36af292SJung-uk Kim #define	ACPI_PWR_FOR_SLEEP(x, y, z)
60e36af292SJung-uk Kim #endif
61e36af292SJung-uk Kim 
62e36af292SJung-uk Kim extern int		pci_do_power_resume;
63e36af292SJung-uk Kim 
64bb0d0a8eSMike Smith static int		pcib_probe(device_t dev);
65e36af292SJung-uk Kim static int		pcib_suspend(device_t dev);
66e36af292SJung-uk Kim static int		pcib_resume(device_t dev);
67bb0d0a8eSMike Smith 
68bb0d0a8eSMike Smith static device_method_t pcib_methods[] = {
69bb0d0a8eSMike Smith     /* Device interface */
70bb0d0a8eSMike Smith     DEVMETHOD(device_probe,		pcib_probe),
71bb0d0a8eSMike Smith     DEVMETHOD(device_attach,		pcib_attach),
724e30440dSWarner Losh     DEVMETHOD(device_detach,		bus_generic_detach),
73bb0d0a8eSMike Smith     DEVMETHOD(device_shutdown,		bus_generic_shutdown),
74e36af292SJung-uk Kim     DEVMETHOD(device_suspend,		pcib_suspend),
75e36af292SJung-uk Kim     DEVMETHOD(device_resume,		pcib_resume),
76bb0d0a8eSMike Smith 
77bb0d0a8eSMike Smith     /* Bus interface */
78bb0d0a8eSMike Smith     DEVMETHOD(bus_print_child,		bus_generic_print_child),
79bb0d0a8eSMike Smith     DEVMETHOD(bus_read_ivar,		pcib_read_ivar),
80bb0d0a8eSMike Smith     DEVMETHOD(bus_write_ivar,		pcib_write_ivar),
81bb0d0a8eSMike Smith     DEVMETHOD(bus_alloc_resource,	pcib_alloc_resource),
82bb0d0a8eSMike Smith     DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
83bb0d0a8eSMike Smith     DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
84bb0d0a8eSMike Smith     DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
85bb0d0a8eSMike Smith     DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
86bb0d0a8eSMike Smith     DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
87bb0d0a8eSMike Smith 
88bb0d0a8eSMike Smith     /* pcib interface */
89bb0d0a8eSMike Smith     DEVMETHOD(pcib_maxslots,		pcib_maxslots),
90bb0d0a8eSMike Smith     DEVMETHOD(pcib_read_config,		pcib_read_config),
91bb0d0a8eSMike Smith     DEVMETHOD(pcib_write_config,	pcib_write_config),
92bb0d0a8eSMike Smith     DEVMETHOD(pcib_route_interrupt,	pcib_route_interrupt),
939bf4c9c1SJohn Baldwin     DEVMETHOD(pcib_alloc_msi,		pcib_alloc_msi),
949bf4c9c1SJohn Baldwin     DEVMETHOD(pcib_release_msi,		pcib_release_msi),
959bf4c9c1SJohn Baldwin     DEVMETHOD(pcib_alloc_msix,		pcib_alloc_msix),
969bf4c9c1SJohn Baldwin     DEVMETHOD(pcib_release_msix,	pcib_release_msix),
97e706f7f0SJohn Baldwin     DEVMETHOD(pcib_map_msi,		pcib_map_msi),
98bb0d0a8eSMike Smith 
99bb0d0a8eSMike Smith     { 0, 0 }
100bb0d0a8eSMike Smith };
101bb0d0a8eSMike Smith 
10204dda605SJohn Baldwin static devclass_t pcib_devclass;
103bb0d0a8eSMike Smith 
10404dda605SJohn Baldwin DEFINE_CLASS_0(pcib, pcib_driver, pcib_methods, sizeof(struct pcib_softc));
105bb0d0a8eSMike Smith DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, 0, 0);
106bb0d0a8eSMike Smith 
107bb0d0a8eSMike Smith /*
108b0a2d4b8SWarner Losh  * Is the prefetch window open (eg, can we allocate memory in it?)
109b0a2d4b8SWarner Losh  */
110b0a2d4b8SWarner Losh static int
111b0a2d4b8SWarner Losh pcib_is_prefetch_open(struct pcib_softc *sc)
112b0a2d4b8SWarner Losh {
113b0a2d4b8SWarner Losh 	return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit);
114b0a2d4b8SWarner Losh }
115b0a2d4b8SWarner Losh 
116b0a2d4b8SWarner Losh /*
117b0a2d4b8SWarner Losh  * Is the nonprefetch window open (eg, can we allocate memory in it?)
118b0a2d4b8SWarner Losh  */
119b0a2d4b8SWarner Losh static int
120b0a2d4b8SWarner Losh pcib_is_nonprefetch_open(struct pcib_softc *sc)
121b0a2d4b8SWarner Losh {
122b0a2d4b8SWarner Losh 	return (sc->membase > 0 && sc->membase < sc->memlimit);
123b0a2d4b8SWarner Losh }
124b0a2d4b8SWarner Losh 
125b0a2d4b8SWarner Losh /*
126b0a2d4b8SWarner Losh  * Is the io window open (eg, can we allocate ports in it?)
127b0a2d4b8SWarner Losh  */
128b0a2d4b8SWarner Losh static int
129b0a2d4b8SWarner Losh pcib_is_io_open(struct pcib_softc *sc)
130b0a2d4b8SWarner Losh {
131b0a2d4b8SWarner Losh 	return (sc->iobase > 0 && sc->iobase < sc->iolimit);
132b0a2d4b8SWarner Losh }
133b0a2d4b8SWarner Losh 
134b0a2d4b8SWarner Losh /*
135e36af292SJung-uk Kim  * Get current I/O decode.
136e36af292SJung-uk Kim  */
137e36af292SJung-uk Kim static void
138e36af292SJung-uk Kim pcib_get_io_decode(struct pcib_softc *sc)
139e36af292SJung-uk Kim {
140e36af292SJung-uk Kim 	device_t	dev;
141e36af292SJung-uk Kim 	uint32_t	iolow;
142e36af292SJung-uk Kim 
143e36af292SJung-uk Kim 	dev = sc->dev;
144e36af292SJung-uk Kim 
145e36af292SJung-uk Kim 	iolow = pci_read_config(dev, PCIR_IOBASEL_1, 1);
146e36af292SJung-uk Kim 	if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32)
147e36af292SJung-uk Kim 		sc->iobase = PCI_PPBIOBASE(
148e36af292SJung-uk Kim 		    pci_read_config(dev, PCIR_IOBASEH_1, 2), iolow);
149e36af292SJung-uk Kim 	else
150e36af292SJung-uk Kim 		sc->iobase = PCI_PPBIOBASE(0, iolow);
151e36af292SJung-uk Kim 
152e36af292SJung-uk Kim 	iolow = pci_read_config(dev, PCIR_IOLIMITL_1, 1);
153e36af292SJung-uk Kim 	if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32)
154e36af292SJung-uk Kim 		sc->iolimit = PCI_PPBIOLIMIT(
155e36af292SJung-uk Kim 		    pci_read_config(dev, PCIR_IOLIMITH_1, 2), iolow);
156e36af292SJung-uk Kim 	else
157e36af292SJung-uk Kim 		sc->iolimit = PCI_PPBIOLIMIT(0, iolow);
158e36af292SJung-uk Kim }
159e36af292SJung-uk Kim 
160e36af292SJung-uk Kim /*
161e36af292SJung-uk Kim  * Get current memory decode.
162e36af292SJung-uk Kim  */
163e36af292SJung-uk Kim static void
164e36af292SJung-uk Kim pcib_get_mem_decode(struct pcib_softc *sc)
165e36af292SJung-uk Kim {
166e36af292SJung-uk Kim 	device_t	dev;
167e36af292SJung-uk Kim 	pci_addr_t	pmemlow;
168e36af292SJung-uk Kim 
169e36af292SJung-uk Kim 	dev = sc->dev;
170e36af292SJung-uk Kim 
171e36af292SJung-uk Kim 	sc->membase = PCI_PPBMEMBASE(0,
172e36af292SJung-uk Kim 	    pci_read_config(dev, PCIR_MEMBASE_1, 2));
173e36af292SJung-uk Kim 	sc->memlimit = PCI_PPBMEMLIMIT(0,
174e36af292SJung-uk Kim 	    pci_read_config(dev, PCIR_MEMLIMIT_1, 2));
175e36af292SJung-uk Kim 
176e36af292SJung-uk Kim 	pmemlow = pci_read_config(dev, PCIR_PMBASEL_1, 2);
177e36af292SJung-uk Kim 	if ((pmemlow & PCIM_BRPM_MASK) == PCIM_BRPM_64)
178e36af292SJung-uk Kim 		sc->pmembase = PCI_PPBMEMBASE(
179e36af292SJung-uk Kim 		    pci_read_config(dev, PCIR_PMBASEH_1, 4), pmemlow);
180e36af292SJung-uk Kim 	else
181e36af292SJung-uk Kim 		sc->pmembase = PCI_PPBMEMBASE(0, pmemlow);
182e36af292SJung-uk Kim 
183e36af292SJung-uk Kim 	pmemlow = pci_read_config(dev, PCIR_PMLIMITL_1, 2);
184e36af292SJung-uk Kim 	if ((pmemlow & PCIM_BRPM_MASK) == PCIM_BRPM_64)
185e36af292SJung-uk Kim 		sc->pmemlimit = PCI_PPBMEMLIMIT(
186e36af292SJung-uk Kim 		    pci_read_config(dev, PCIR_PMLIMITH_1, 4), pmemlow);
187e36af292SJung-uk Kim 	else
188e36af292SJung-uk Kim 		sc->pmemlimit = PCI_PPBMEMLIMIT(0, pmemlow);
189e36af292SJung-uk Kim }
190e36af292SJung-uk Kim 
191e36af292SJung-uk Kim /*
192e36af292SJung-uk Kim  * Restore previous I/O decode.
193e36af292SJung-uk Kim  */
194e36af292SJung-uk Kim static void
195e36af292SJung-uk Kim pcib_set_io_decode(struct pcib_softc *sc)
196e36af292SJung-uk Kim {
197e36af292SJung-uk Kim 	device_t	dev;
198e36af292SJung-uk Kim 	uint32_t	iohi;
199e36af292SJung-uk Kim 
200e36af292SJung-uk Kim 	dev = sc->dev;
201e36af292SJung-uk Kim 
202e36af292SJung-uk Kim 	iohi = sc->iobase >> 16;
203e36af292SJung-uk Kim 	if (iohi > 0)
204e36af292SJung-uk Kim 		pci_write_config(dev, PCIR_IOBASEH_1, iohi, 2);
205e36af292SJung-uk Kim 	pci_write_config(dev, PCIR_IOBASEL_1, sc->iobase >> 8, 1);
206e36af292SJung-uk Kim 
207e36af292SJung-uk Kim 	iohi = sc->iolimit >> 16;
208e36af292SJung-uk Kim 	if (iohi > 0)
209e36af292SJung-uk Kim 		pci_write_config(dev, PCIR_IOLIMITH_1, iohi, 2);
210e36af292SJung-uk Kim 	pci_write_config(dev, PCIR_IOLIMITL_1, sc->iolimit >> 8, 1);
211e36af292SJung-uk Kim }
212e36af292SJung-uk Kim 
213e36af292SJung-uk Kim /*
214e36af292SJung-uk Kim  * Restore previous memory decode.
215e36af292SJung-uk Kim  */
216e36af292SJung-uk Kim static void
217e36af292SJung-uk Kim pcib_set_mem_decode(struct pcib_softc *sc)
218e36af292SJung-uk Kim {
219e36af292SJung-uk Kim 	device_t	dev;
220e36af292SJung-uk Kim 	pci_addr_t	pmemhi;
221e36af292SJung-uk Kim 
222e36af292SJung-uk Kim 	dev = sc->dev;
223e36af292SJung-uk Kim 
224e36af292SJung-uk Kim 	pci_write_config(dev, PCIR_MEMBASE_1, sc->membase >> 16, 2);
225e36af292SJung-uk Kim 	pci_write_config(dev, PCIR_MEMLIMIT_1, sc->memlimit >> 16, 2);
226e36af292SJung-uk Kim 
227e36af292SJung-uk Kim 	pmemhi = sc->pmembase >> 32;
228e36af292SJung-uk Kim 	if (pmemhi > 0)
229e36af292SJung-uk Kim 		pci_write_config(dev, PCIR_PMBASEH_1, pmemhi, 4);
230e36af292SJung-uk Kim 	pci_write_config(dev, PCIR_PMBASEL_1, sc->pmembase >> 16, 2);
231e36af292SJung-uk Kim 
232e36af292SJung-uk Kim 	pmemhi = sc->pmemlimit >> 32;
233e36af292SJung-uk Kim 	if (pmemhi > 0)
234e36af292SJung-uk Kim 		pci_write_config(dev, PCIR_PMLIMITH_1, pmemhi, 4);
235e36af292SJung-uk Kim 	pci_write_config(dev, PCIR_PMLIMITL_1, sc->pmemlimit >> 16, 2);
236e36af292SJung-uk Kim }
237e36af292SJung-uk Kim 
238e36af292SJung-uk Kim /*
239e36af292SJung-uk Kim  * Get current bridge configuration.
240e36af292SJung-uk Kim  */
241e36af292SJung-uk Kim static void
242e36af292SJung-uk Kim pcib_cfg_save(struct pcib_softc *sc)
243e36af292SJung-uk Kim {
244e36af292SJung-uk Kim 	device_t	dev;
245e36af292SJung-uk Kim 
246e36af292SJung-uk Kim 	dev = sc->dev;
247e36af292SJung-uk Kim 
248e36af292SJung-uk Kim 	sc->command = pci_read_config(dev, PCIR_COMMAND, 2);
249e36af292SJung-uk Kim 	sc->pribus = pci_read_config(dev, PCIR_PRIBUS_1, 1);
250e36af292SJung-uk Kim 	sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1);
251e36af292SJung-uk Kim 	sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1);
252e36af292SJung-uk Kim 	sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2);
253e36af292SJung-uk Kim 	sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1);
254e36af292SJung-uk Kim 	if (sc->command & PCIM_CMD_PORTEN)
255e36af292SJung-uk Kim 		pcib_get_io_decode(sc);
256e36af292SJung-uk Kim 	if (sc->command & PCIM_CMD_MEMEN)
257e36af292SJung-uk Kim 		pcib_get_mem_decode(sc);
258e36af292SJung-uk Kim }
259e36af292SJung-uk Kim 
260e36af292SJung-uk Kim /*
261e36af292SJung-uk Kim  * Restore previous bridge configuration.
262e36af292SJung-uk Kim  */
263e36af292SJung-uk Kim static void
264e36af292SJung-uk Kim pcib_cfg_restore(struct pcib_softc *sc)
265e36af292SJung-uk Kim {
266e36af292SJung-uk Kim 	device_t	dev;
267e36af292SJung-uk Kim 
268e36af292SJung-uk Kim 	dev = sc->dev;
269e36af292SJung-uk Kim 
270e36af292SJung-uk Kim 	pci_write_config(dev, PCIR_COMMAND, sc->command, 2);
271e36af292SJung-uk Kim 	pci_write_config(dev, PCIR_PRIBUS_1, sc->pribus, 1);
272e36af292SJung-uk Kim 	pci_write_config(dev, PCIR_SECBUS_1, sc->secbus, 1);
273e36af292SJung-uk Kim 	pci_write_config(dev, PCIR_SUBBUS_1, sc->subbus, 1);
274e36af292SJung-uk Kim 	pci_write_config(dev, PCIR_BRIDGECTL_1, sc->bridgectl, 2);
275e36af292SJung-uk Kim 	pci_write_config(dev, PCIR_SECLAT_1, sc->seclat, 1);
276e36af292SJung-uk Kim 	if (sc->command & PCIM_CMD_PORTEN)
277e36af292SJung-uk Kim 		pcib_set_io_decode(sc);
278e36af292SJung-uk Kim 	if (sc->command & PCIM_CMD_MEMEN)
279e36af292SJung-uk Kim 		pcib_set_mem_decode(sc);
280e36af292SJung-uk Kim }
281e36af292SJung-uk Kim 
282e36af292SJung-uk Kim /*
283bb0d0a8eSMike Smith  * Generic device interface
284bb0d0a8eSMike Smith  */
285bb0d0a8eSMike Smith static int
286bb0d0a8eSMike Smith pcib_probe(device_t dev)
287bb0d0a8eSMike Smith {
288bb0d0a8eSMike Smith     if ((pci_get_class(dev) == PCIC_BRIDGE) &&
289bb0d0a8eSMike Smith 	(pci_get_subclass(dev) == PCIS_BRIDGE_PCI)) {
290bb0d0a8eSMike Smith 	device_set_desc(dev, "PCI-PCI bridge");
291bb0d0a8eSMike Smith 	return(-10000);
292bb0d0a8eSMike Smith     }
293bb0d0a8eSMike Smith     return(ENXIO);
294bb0d0a8eSMike Smith }
295bb0d0a8eSMike Smith 
2966f0d5884SJohn Baldwin void
2976f0d5884SJohn Baldwin pcib_attach_common(device_t dev)
298bb0d0a8eSMike Smith {
299bb0d0a8eSMike Smith     struct pcib_softc	*sc;
300abf07f13SWarner Losh     struct sysctl_ctx_list *sctx;
301abf07f13SWarner Losh     struct sysctl_oid	*soid;
302bb0d0a8eSMike Smith 
303bb0d0a8eSMike Smith     sc = device_get_softc(dev);
304bb0d0a8eSMike Smith     sc->dev = dev;
305bb0d0a8eSMike Smith 
3064fa59183SMike Smith     /*
3074fa59183SMike Smith      * Get current bridge configuration.
3084fa59183SMike Smith      */
30955aaf894SMarius Strobl     sc->domain = pci_get_domain(dev);
3104fa59183SMike Smith     sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2);
311e36af292SJung-uk Kim     pcib_cfg_save(sc);
3124fa59183SMike Smith 
3134fa59183SMike Smith     /*
314abf07f13SWarner Losh      * Setup sysctl reporting nodes
315abf07f13SWarner Losh      */
316abf07f13SWarner Losh     sctx = device_get_sysctl_ctx(dev);
317abf07f13SWarner Losh     soid = device_get_sysctl_tree(dev);
318abf07f13SWarner Losh     SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "domain",
319abf07f13SWarner Losh       CTLFLAG_RD, &sc->domain, 0, "Domain number");
320abf07f13SWarner Losh     SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus",
321abf07f13SWarner Losh       CTLFLAG_RD, &sc->pribus, 0, "Primary bus number");
322abf07f13SWarner Losh     SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus",
323abf07f13SWarner Losh       CTLFLAG_RD, &sc->secbus, 0, "Secondary bus number");
324abf07f13SWarner Losh     SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus",
325abf07f13SWarner Losh       CTLFLAG_RD, &sc->subbus, 0, "Subordinate bus number");
326abf07f13SWarner Losh 
327abf07f13SWarner Losh     /*
3284fa59183SMike Smith      * Quirk handling.
3294fa59183SMike Smith      */
3304fa59183SMike Smith     switch (pci_get_devid(dev)) {
3314fa59183SMike Smith     case 0x12258086:		/* Intel 82454KX/GX (Orion) */
3324fa59183SMike Smith 	{
333b0cb115fSWarner Losh 	    uint8_t	supbus;
3344fa59183SMike Smith 
3354fa59183SMike Smith 	    supbus = pci_read_config(dev, 0x41, 1);
3364fa59183SMike Smith 	    if (supbus != 0xff) {
3374fa59183SMike Smith 		sc->secbus = supbus + 1;
3384fa59183SMike Smith 		sc->subbus = supbus + 1;
3394fa59183SMike Smith 	    }
3404fa59183SMike Smith 	    break;
3414fa59183SMike Smith 	}
3424fa59183SMike Smith 
343e4b59fc5SWarner Losh     /*
344e4b59fc5SWarner Losh      * The i82380FB mobile docking controller is a PCI-PCI bridge,
345e4b59fc5SWarner Losh      * and it is a subtractive bridge.  However, the ProgIf is wrong
346e4b59fc5SWarner Losh      * so the normal setting of PCIB_SUBTRACTIVE bit doesn't
347e4b59fc5SWarner Losh      * happen.  There's also a Toshiba bridge that behaves this
348e4b59fc5SWarner Losh      * way.
349e4b59fc5SWarner Losh      */
350e4b59fc5SWarner Losh     case 0x124b8086:		/* Intel 82380FB Mobile */
351e4b59fc5SWarner Losh     case 0x060513d7:		/* Toshiba ???? */
352e4b59fc5SWarner Losh 	sc->flags |= PCIB_SUBTRACTIVE;
353e4b59fc5SWarner Losh 	break;
354c94d6dbeSJung-uk Kim 
355c94d6dbeSJung-uk Kim     /* Compaq R3000 BIOS sets wrong subordinate bus number. */
356c94d6dbeSJung-uk Kim     case 0x00dd10de:
357c94d6dbeSJung-uk Kim 	{
358c94d6dbeSJung-uk Kim 	    char *cp;
359c94d6dbeSJung-uk Kim 
3601def0ca6SJung-uk Kim 	    if ((cp = getenv("smbios.planar.maker")) == NULL)
361c94d6dbeSJung-uk Kim 		break;
3621def0ca6SJung-uk Kim 	    if (strncmp(cp, "Compal", 6) != 0) {
3631def0ca6SJung-uk Kim 		freeenv(cp);
364c94d6dbeSJung-uk Kim 		break;
3651def0ca6SJung-uk Kim 	    }
3661def0ca6SJung-uk Kim 	    freeenv(cp);
3671def0ca6SJung-uk Kim 	    if ((cp = getenv("smbios.planar.product")) == NULL)
3681def0ca6SJung-uk Kim 		break;
3691def0ca6SJung-uk Kim 	    if (strncmp(cp, "08A0", 4) != 0) {
3701def0ca6SJung-uk Kim 		freeenv(cp);
3711def0ca6SJung-uk Kim 		break;
3721def0ca6SJung-uk Kim 	    }
3731def0ca6SJung-uk Kim 	    freeenv(cp);
374c94d6dbeSJung-uk Kim 	    if (sc->subbus < 0xa) {
375c94d6dbeSJung-uk Kim 		pci_write_config(dev, PCIR_SUBBUS_1, 0xa, 1);
376c94d6dbeSJung-uk Kim 		sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1);
377c94d6dbeSJung-uk Kim 	    }
378c94d6dbeSJung-uk Kim 	    break;
379c94d6dbeSJung-uk Kim 	}
380e4b59fc5SWarner Losh     }
381e4b59fc5SWarner Losh 
38222bf1c7fSJohn Baldwin     if (pci_msi_device_blacklisted(dev))
38322bf1c7fSJohn Baldwin 	sc->flags |= PCIB_DISABLE_MSI;
38422bf1c7fSJohn Baldwin 
385e4b59fc5SWarner Losh     /*
386e4b59fc5SWarner Losh      * Intel 815, 845 and other chipsets say they are PCI-PCI bridges,
387e4b59fc5SWarner Losh      * but have a ProgIF of 0x80.  The 82801 family (AA, AB, BAM/CAM,
388e4b59fc5SWarner Losh      * BA/CA/DB and E) PCI bridges are HUB-PCI bridges, in Intelese.
389e4b59fc5SWarner Losh      * This means they act as if they were subtractively decoding
390e4b59fc5SWarner Losh      * bridges and pass all transactions.  Mark them and real ProgIf 1
391e4b59fc5SWarner Losh      * parts as subtractive.
392e4b59fc5SWarner Losh      */
393e4b59fc5SWarner Losh     if ((pci_get_devid(dev) & 0xff00ffff) == 0x24008086 ||
394657d9f9fSJohn Baldwin       pci_read_config(dev, PCIR_PROGIF, 1) == PCIP_BRIDGE_PCI_SUBTRACTIVE)
395e4b59fc5SWarner Losh 	sc->flags |= PCIB_SUBTRACTIVE;
396e4b59fc5SWarner Losh 
397bb0d0a8eSMike Smith     if (bootverbose) {
39855aaf894SMarius Strobl 	device_printf(dev, "  domain            %d\n", sc->domain);
399bb0d0a8eSMike Smith 	device_printf(dev, "  secondary bus     %d\n", sc->secbus);
400bb0d0a8eSMike Smith 	device_printf(dev, "  subordinate bus   %d\n", sc->subbus);
401bb0d0a8eSMike Smith 	device_printf(dev, "  I/O decode        0x%x-0x%x\n", sc->iobase, sc->iolimit);
402b0a2d4b8SWarner Losh 	if (pcib_is_nonprefetch_open(sc))
403b0a2d4b8SWarner Losh 	    device_printf(dev, "  memory decode     0x%jx-0x%jx\n",
404b0a2d4b8SWarner Losh 	      (uintmax_t)sc->membase, (uintmax_t)sc->memlimit);
405b0a2d4b8SWarner Losh 	if (pcib_is_prefetch_open(sc))
406b0a2d4b8SWarner Losh 	    device_printf(dev, "  prefetched decode 0x%jx-0x%jx\n",
407b0a2d4b8SWarner Losh 	      (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit);
408b0a2d4b8SWarner Losh 	else
409b0a2d4b8SWarner Losh 	    device_printf(dev, "  no prefetched decode\n");
410e4b59fc5SWarner Losh 	if (sc->flags & PCIB_SUBTRACTIVE)
411e4b59fc5SWarner Losh 	    device_printf(dev, "  Subtractively decoded bridge.\n");
412bb0d0a8eSMike Smith     }
413bb0d0a8eSMike Smith 
414bb0d0a8eSMike Smith     /*
415bb0d0a8eSMike Smith      * XXX If the secondary bus number is zero, we should assign a bus number
4167e178674SWarner Losh      *     since the BIOS hasn't, then initialise the bridge.  A simple
4177e178674SWarner Losh      *     bus_alloc_resource with the a couple of busses seems like the right
4187e178674SWarner Losh      *     approach, but we don't know what busses the BIOS might have already
4197e178674SWarner Losh      *     assigned to other bridges on this bus that probe later than we do.
4207e178674SWarner Losh      *
4217e178674SWarner Losh      *     If the subordinate bus number is less than the secondary bus number,
422bb0d0a8eSMike Smith      *     we should pick a better value.  One sensible alternative would be to
423bb0d0a8eSMike Smith      *     pick 255; the only tradeoff here is that configuration transactions
4247e178674SWarner Losh      *     would be more widely routed than absolutely necessary.  We could
4257e178674SWarner Losh      *     then do a walk of the tree later and fix it.
426bb0d0a8eSMike Smith      */
4276f0d5884SJohn Baldwin }
428bb0d0a8eSMike Smith 
42938906aedSJohn Baldwin int
4306f0d5884SJohn Baldwin pcib_attach(device_t dev)
4316f0d5884SJohn Baldwin {
4326f0d5884SJohn Baldwin     struct pcib_softc	*sc;
4336f0d5884SJohn Baldwin     device_t		child;
4346f0d5884SJohn Baldwin 
4356f0d5884SJohn Baldwin     pcib_attach_common(dev);
4366f0d5884SJohn Baldwin     sc = device_get_softc(dev);
437bb0d0a8eSMike Smith     if (sc->secbus != 0) {
438cea0a895SJohn Baldwin 	child = device_add_child(dev, "pci", sc->secbus);
439bb0d0a8eSMike Smith 	if (child != NULL)
440bb0d0a8eSMike Smith 	    return(bus_generic_attach(dev));
441bb0d0a8eSMike Smith     }
442bb0d0a8eSMike Smith 
443bb0d0a8eSMike Smith     /* no secondary bus; we should have fixed this */
444bb0d0a8eSMike Smith     return(0);
445bb0d0a8eSMike Smith }
446bb0d0a8eSMike Smith 
4476f0d5884SJohn Baldwin int
448e36af292SJung-uk Kim pcib_suspend(device_t dev)
449e36af292SJung-uk Kim {
450e36af292SJung-uk Kim 	device_t	acpi_dev;
451e36af292SJung-uk Kim 	int		dstate, error;
452e36af292SJung-uk Kim 
453e36af292SJung-uk Kim 	pcib_cfg_save(device_get_softc(dev));
454e36af292SJung-uk Kim 	error = bus_generic_suspend(dev);
455e36af292SJung-uk Kim 	if (error == 0 && pci_do_power_resume) {
456e36af292SJung-uk Kim 		acpi_dev = devclass_get_device(devclass_find("acpi"), 0);
457e36af292SJung-uk Kim 		if (acpi_dev != NULL) {
458e36af292SJung-uk Kim 			dstate = PCI_POWERSTATE_D3;
459e36af292SJung-uk Kim 			ACPI_PWR_FOR_SLEEP(acpi_dev, dev, &dstate);
460e36af292SJung-uk Kim 			pci_set_powerstate(dev, dstate);
461e36af292SJung-uk Kim 		}
462e36af292SJung-uk Kim 	}
463e36af292SJung-uk Kim 	return (error);
464e36af292SJung-uk Kim }
465e36af292SJung-uk Kim 
466e36af292SJung-uk Kim int
467e36af292SJung-uk Kim pcib_resume(device_t dev)
468e36af292SJung-uk Kim {
469e36af292SJung-uk Kim 	device_t	acpi_dev;
470e36af292SJung-uk Kim 
471e36af292SJung-uk Kim 	if (pci_do_power_resume) {
472e36af292SJung-uk Kim 		acpi_dev = devclass_get_device(devclass_find("acpi"), 0);
473e36af292SJung-uk Kim 		if (acpi_dev != NULL) {
474e36af292SJung-uk Kim 			ACPI_PWR_FOR_SLEEP(acpi_dev, dev, NULL);
475e36af292SJung-uk Kim 			pci_set_powerstate(dev, PCI_POWERSTATE_D0);
476e36af292SJung-uk Kim 		}
477e36af292SJung-uk Kim 	}
478e36af292SJung-uk Kim 	pcib_cfg_restore(device_get_softc(dev));
479e36af292SJung-uk Kim 	return (bus_generic_resume(dev));
480e36af292SJung-uk Kim }
481e36af292SJung-uk Kim 
482e36af292SJung-uk Kim int
483bb0d0a8eSMike Smith pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
484bb0d0a8eSMike Smith {
485bb0d0a8eSMike Smith     struct pcib_softc	*sc = device_get_softc(dev);
486bb0d0a8eSMike Smith 
487bb0d0a8eSMike Smith     switch (which) {
48855aaf894SMarius Strobl     case PCIB_IVAR_DOMAIN:
48955aaf894SMarius Strobl 	*result = sc->domain;
49055aaf894SMarius Strobl 	return(0);
491bb0d0a8eSMike Smith     case PCIB_IVAR_BUS:
492bb0d0a8eSMike Smith 	*result = sc->secbus;
493bb0d0a8eSMike Smith 	return(0);
494bb0d0a8eSMike Smith     }
495bb0d0a8eSMike Smith     return(ENOENT);
496bb0d0a8eSMike Smith }
497bb0d0a8eSMike Smith 
4986f0d5884SJohn Baldwin int
499bb0d0a8eSMike Smith pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
500bb0d0a8eSMike Smith {
501bb0d0a8eSMike Smith     struct pcib_softc	*sc = device_get_softc(dev);
502bb0d0a8eSMike Smith 
503bb0d0a8eSMike Smith     switch (which) {
50455aaf894SMarius Strobl     case PCIB_IVAR_DOMAIN:
50555aaf894SMarius Strobl 	return(EINVAL);
506bb0d0a8eSMike Smith     case PCIB_IVAR_BUS:
507bb0d0a8eSMike Smith 	sc->secbus = value;
50855aaf894SMarius Strobl 	return(0);
509bb0d0a8eSMike Smith     }
510bb0d0a8eSMike Smith     return(ENOENT);
511bb0d0a8eSMike Smith }
512bb0d0a8eSMike Smith 
513bb0d0a8eSMike Smith /*
514bb0d0a8eSMike Smith  * We have to trap resource allocation requests and ensure that the bridge
515bb0d0a8eSMike Smith  * is set up to, or capable of handling them.
516bb0d0a8eSMike Smith  */
5176f0d5884SJohn Baldwin struct resource *
518bb0d0a8eSMike Smith pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
519bb0d0a8eSMike Smith     u_long start, u_long end, u_long count, u_int flags)
520bb0d0a8eSMike Smith {
521bb0d0a8eSMike Smith 	struct pcib_softc	*sc = device_get_softc(dev);
52226043836SJohn Baldwin 	const char *name, *suffix;
523a8b354a8SWarner Losh 	int ok;
524bb0d0a8eSMike Smith 
525bb0d0a8eSMike Smith 	/*
526bb0d0a8eSMike Smith 	 * Fail the allocation for this range if it's not supported.
527bb0d0a8eSMike Smith 	 */
52826043836SJohn Baldwin 	name = device_get_nameunit(child);
52926043836SJohn Baldwin 	if (name == NULL) {
53026043836SJohn Baldwin 		name = "";
53126043836SJohn Baldwin 		suffix = "";
53226043836SJohn Baldwin 	} else
53326043836SJohn Baldwin 		suffix = " ";
534bb0d0a8eSMike Smith 	switch (type) {
535bb0d0a8eSMike Smith 	case SYS_RES_IOPORT:
536a8b354a8SWarner Losh 		ok = 0;
537e4b59fc5SWarner Losh 		if (!pcib_is_io_open(sc))
538e4b59fc5SWarner Losh 			break;
539a8b354a8SWarner Losh 		ok = (start >= sc->iobase && end <= sc->iolimit);
540d98d9b12SMarcel Moolenaar 
541d98d9b12SMarcel Moolenaar 		/*
542d98d9b12SMarcel Moolenaar 		 * Make sure we allow access to VGA I/O addresses when the
543d98d9b12SMarcel Moolenaar 		 * bridge has the "VGA Enable" bit set.
544d98d9b12SMarcel Moolenaar 		 */
545d98d9b12SMarcel Moolenaar 		if (!ok && pci_is_vga_ioport_range(start, end))
546d98d9b12SMarcel Moolenaar 			ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0;
547d98d9b12SMarcel Moolenaar 
548e4b59fc5SWarner Losh 		if ((sc->flags & PCIB_SUBTRACTIVE) == 0) {
549a8b354a8SWarner Losh 			if (!ok) {
55012b8c86eSWarner Losh 				if (start < sc->iobase)
55112b8c86eSWarner Losh 					start = sc->iobase;
55212b8c86eSWarner Losh 				if (end > sc->iolimit)
55312b8c86eSWarner Losh 					end = sc->iolimit;
5542daa7a07SWarner Losh 				if (start < end)
5552daa7a07SWarner Losh 					ok = 1;
556a8b354a8SWarner Losh 			}
5571c54ff33SMatthew N. Dodd 		} else {
558e4b59fc5SWarner Losh 			ok = 1;
5599dffe835SWarner Losh #if 0
560795dceffSWarner Losh 			/*
561795dceffSWarner Losh 			 * If we overlap with the subtractive range, then
562795dceffSWarner Losh 			 * pick the upper range to use.
563795dceffSWarner Losh 			 */
564795dceffSWarner Losh 			if (start < sc->iolimit && end > sc->iobase)
565795dceffSWarner Losh 				start = sc->iolimit + 1;
5669dffe835SWarner Losh #endif
56712b8c86eSWarner Losh 		}
568a8b354a8SWarner Losh 		if (end < start) {
5692daa7a07SWarner Losh 			device_printf(dev, "ioport: end (%lx) < start (%lx)\n",
5702daa7a07SWarner Losh 			    end, start);
571a8b354a8SWarner Losh 			start = 0;
572a8b354a8SWarner Losh 			end = 0;
573a8b354a8SWarner Losh 			ok = 0;
574a8b354a8SWarner Losh 		}
575a8b354a8SWarner Losh 		if (!ok) {
57626043836SJohn Baldwin 			device_printf(dev, "%s%srequested unsupported I/O "
577a8b354a8SWarner Losh 			    "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n",
57826043836SJohn Baldwin 			    name, suffix, start, end, sc->iobase, sc->iolimit);
579bb0d0a8eSMike Smith 			return (NULL);
580bb0d0a8eSMike Smith 		}
5814fa59183SMike Smith 		if (bootverbose)
5822daa7a07SWarner Losh 			device_printf(dev,
58326043836SJohn Baldwin 			    "%s%srequested I/O range 0x%lx-0x%lx: in range\n",
58426043836SJohn Baldwin 			    name, suffix, start, end);
585bb0d0a8eSMike Smith 		break;
586bb0d0a8eSMike Smith 
587bb0d0a8eSMike Smith 	case SYS_RES_MEMORY:
588a8b354a8SWarner Losh 		ok = 0;
589a8b354a8SWarner Losh 		if (pcib_is_nonprefetch_open(sc))
590a8b354a8SWarner Losh 			ok = ok || (start >= sc->membase && end <= sc->memlimit);
591a8b354a8SWarner Losh 		if (pcib_is_prefetch_open(sc))
592a8b354a8SWarner Losh 			ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit);
593d98d9b12SMarcel Moolenaar 
594d98d9b12SMarcel Moolenaar 		/*
595d98d9b12SMarcel Moolenaar 		 * Make sure we allow access to VGA memory addresses when the
596d98d9b12SMarcel Moolenaar 		 * bridge has the "VGA Enable" bit set.
597d98d9b12SMarcel Moolenaar 		 */
598d98d9b12SMarcel Moolenaar 		if (!ok && pci_is_vga_memory_range(start, end))
599d98d9b12SMarcel Moolenaar 			ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0;
600d98d9b12SMarcel Moolenaar 
601e4b59fc5SWarner Losh 		if ((sc->flags & PCIB_SUBTRACTIVE) == 0) {
602a8b354a8SWarner Losh 			if (!ok) {
603a8b354a8SWarner Losh 				ok = 1;
604a8b354a8SWarner Losh 				if (flags & RF_PREFETCHABLE) {
605a8b354a8SWarner Losh 					if (pcib_is_prefetch_open(sc)) {
606a8b354a8SWarner Losh 						if (start < sc->pmembase)
607a8b354a8SWarner Losh 							start = sc->pmembase;
608a8b354a8SWarner Losh 						if (end > sc->pmemlimit)
609a8b354a8SWarner Losh 							end = sc->pmemlimit;
610a8b354a8SWarner Losh 					} else {
611a8b354a8SWarner Losh 						ok = 0;
612a8b354a8SWarner Losh 					}
613a8b354a8SWarner Losh 				} else {	/* non-prefetchable */
614a8b354a8SWarner Losh 					if (pcib_is_nonprefetch_open(sc)) {
615a8b354a8SWarner Losh 						if (start < sc->membase)
61612b8c86eSWarner Losh 							start = sc->membase;
61712b8c86eSWarner Losh 						if (end > sc->memlimit)
61812b8c86eSWarner Losh 							end = sc->memlimit;
6191c54ff33SMatthew N. Dodd 					} else {
620a8b354a8SWarner Losh 						ok = 0;
621a8b354a8SWarner Losh 					}
622a8b354a8SWarner Losh 				}
623a8b354a8SWarner Losh 			}
624a8b354a8SWarner Losh 		} else if (!ok) {
625e4b59fc5SWarner Losh 			ok = 1;	/* subtractive bridge: always ok */
6269dffe835SWarner Losh #if 0
627a8b354a8SWarner Losh 			if (pcib_is_nonprefetch_open(sc)) {
628795dceffSWarner Losh 				if (start < sc->memlimit && end > sc->membase)
629795dceffSWarner Losh 					start = sc->memlimit + 1;
630a8b354a8SWarner Losh 			}
631a8b354a8SWarner Losh 			if (pcib_is_prefetch_open(sc)) {
632795dceffSWarner Losh 				if (start < sc->pmemlimit && end > sc->pmembase)
633795dceffSWarner Losh 					start = sc->pmemlimit + 1;
6341c54ff33SMatthew N. Dodd 			}
6359dffe835SWarner Losh #endif
63612b8c86eSWarner Losh 		}
637a8b354a8SWarner Losh 		if (end < start) {
6382daa7a07SWarner Losh 			device_printf(dev, "memory: end (%lx) < start (%lx)\n",
6392daa7a07SWarner Losh 			    end, start);
640a8b354a8SWarner Losh 			start = 0;
641a8b354a8SWarner Losh 			end = 0;
642a8b354a8SWarner Losh 			ok = 0;
643a8b354a8SWarner Losh 		}
644a8b354a8SWarner Losh 		if (!ok && bootverbose)
64534428485SWarner Losh 			device_printf(dev,
64626043836SJohn Baldwin 			    "%s%srequested unsupported memory range %#lx-%#lx "
647b0a2d4b8SWarner Losh 			    "(decoding %#jx-%#jx, %#jx-%#jx)\n",
64826043836SJohn Baldwin 			    name, suffix, start, end,
649b0a2d4b8SWarner Losh 			    (uintmax_t)sc->membase, (uintmax_t)sc->memlimit,
650b0a2d4b8SWarner Losh 			    (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit);
651a8b354a8SWarner Losh 		if (!ok)
652bb0d0a8eSMike Smith 			return (NULL);
6534fa59183SMike Smith 		if (bootverbose)
65426043836SJohn Baldwin 			device_printf(dev,"%s%srequested memory range "
6552daa7a07SWarner Losh 			    "0x%lx-0x%lx: good\n",
65626043836SJohn Baldwin 			    name, suffix, start, end);
6574fa59183SMike Smith 		break;
6584fa59183SMike Smith 
659bb0d0a8eSMike Smith 	default:
6604fa59183SMike Smith 		break;
661bb0d0a8eSMike Smith 	}
662bb0d0a8eSMike Smith 	/*
663bb0d0a8eSMike Smith 	 * Bridge is OK decoding this resource, so pass it up.
664bb0d0a8eSMike Smith 	 */
6652daa7a07SWarner Losh 	return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
6662daa7a07SWarner Losh 	    count, flags));
667bb0d0a8eSMike Smith }
668bb0d0a8eSMike Smith 
669bb0d0a8eSMike Smith /*
670bb0d0a8eSMike Smith  * PCIB interface.
671bb0d0a8eSMike Smith  */
6726f0d5884SJohn Baldwin int
673bb0d0a8eSMike Smith pcib_maxslots(device_t dev)
674bb0d0a8eSMike Smith {
6754fa59183SMike Smith     return(PCI_SLOTMAX);
676bb0d0a8eSMike Smith }
677bb0d0a8eSMike Smith 
678bb0d0a8eSMike Smith /*
679bb0d0a8eSMike Smith  * Since we are a child of a PCI bus, its parent must support the pcib interface.
680bb0d0a8eSMike Smith  */
681b0cb115fSWarner Losh uint32_t
682795dceffSWarner Losh pcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width)
683bb0d0a8eSMike Smith {
684bb0d0a8eSMike Smith     return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, width));
685bb0d0a8eSMike Smith }
686bb0d0a8eSMike Smith 
6876f0d5884SJohn Baldwin void
688795dceffSWarner Losh pcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, int width)
689bb0d0a8eSMike Smith {
690bb0d0a8eSMike Smith     PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, val, width);
691bb0d0a8eSMike Smith }
692bb0d0a8eSMike Smith 
693bb0d0a8eSMike Smith /*
694bb0d0a8eSMike Smith  * Route an interrupt across a PCI bridge.
695bb0d0a8eSMike Smith  */
6962c2d1d07SBenno Rice int
697bb0d0a8eSMike Smith pcib_route_interrupt(device_t pcib, device_t dev, int pin)
698bb0d0a8eSMike Smith {
699bb0d0a8eSMike Smith     device_t	bus;
700bb0d0a8eSMike Smith     int		parent_intpin;
701bb0d0a8eSMike Smith     int		intnum;
702bb0d0a8eSMike Smith 
703bb0d0a8eSMike Smith     /*
704bb0d0a8eSMike Smith      *
705bb0d0a8eSMike Smith      * The PCI standard defines a swizzle of the child-side device/intpin to
706bb0d0a8eSMike Smith      * the parent-side intpin as follows.
707bb0d0a8eSMike Smith      *
708bb0d0a8eSMike Smith      * device = device on child bus
709bb0d0a8eSMike Smith      * child_intpin = intpin on child bus slot (0-3)
710bb0d0a8eSMike Smith      * parent_intpin = intpin on parent bus slot (0-3)
711bb0d0a8eSMike Smith      *
712bb0d0a8eSMike Smith      * parent_intpin = (device + child_intpin) % 4
713bb0d0a8eSMike Smith      */
714cdc95e1bSBernd Walter     parent_intpin = (pci_get_slot(dev) + (pin - 1)) % 4;
715bb0d0a8eSMike Smith 
716bb0d0a8eSMike Smith     /*
717bb0d0a8eSMike Smith      * Our parent is a PCI bus.  Its parent must export the pcib interface
718bb0d0a8eSMike Smith      * which includes the ability to route interrupts.
719bb0d0a8eSMike Smith      */
720bb0d0a8eSMike Smith     bus = device_get_parent(pcib);
721bb0d0a8eSMike Smith     intnum = PCIB_ROUTE_INTERRUPT(device_get_parent(bus), pcib, parent_intpin + 1);
72239981fedSJohn Baldwin     if (PCI_INTERRUPT_VALID(intnum) && bootverbose) {
723c6a121abSJohn Baldwin 	device_printf(pcib, "slot %d INT%c is routed to irq %d\n",
724c6a121abSJohn Baldwin 	    pci_get_slot(dev), 'A' + pin - 1, intnum);
7258046c4b9SMike Smith     }
726bb0d0a8eSMike Smith     return(intnum);
727bb0d0a8eSMike Smith }
728b173edafSJohn Baldwin 
729e706f7f0SJohn Baldwin /* Pass request to alloc MSI/MSI-X messages up to the parent bridge. */
7309bf4c9c1SJohn Baldwin int
7319bf4c9c1SJohn Baldwin pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs)
7329bf4c9c1SJohn Baldwin {
733bd82bbb1SAndrew Gallatin 	struct pcib_softc *sc = device_get_softc(pcib);
7349bf4c9c1SJohn Baldwin 	device_t bus;
7359bf4c9c1SJohn Baldwin 
73622bf1c7fSJohn Baldwin 	if (sc->flags & PCIB_DISABLE_MSI)
73722bf1c7fSJohn Baldwin 		return (ENXIO);
7389bf4c9c1SJohn Baldwin 	bus = device_get_parent(pcib);
7399bf4c9c1SJohn Baldwin 	return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount,
7409bf4c9c1SJohn Baldwin 	    irqs));
7419bf4c9c1SJohn Baldwin }
7429bf4c9c1SJohn Baldwin 
743e706f7f0SJohn Baldwin /* Pass request to release MSI/MSI-X messages up to the parent bridge. */
7449bf4c9c1SJohn Baldwin int
7459bf4c9c1SJohn Baldwin pcib_release_msi(device_t pcib, device_t dev, int count, int *irqs)
7469bf4c9c1SJohn Baldwin {
7479bf4c9c1SJohn Baldwin 	device_t bus;
7489bf4c9c1SJohn Baldwin 
7499bf4c9c1SJohn Baldwin 	bus = device_get_parent(pcib);
7509bf4c9c1SJohn Baldwin 	return (PCIB_RELEASE_MSI(device_get_parent(bus), dev, count, irqs));
7519bf4c9c1SJohn Baldwin }
7529bf4c9c1SJohn Baldwin 
7539bf4c9c1SJohn Baldwin /* Pass request to alloc an MSI-X message up to the parent bridge. */
7549bf4c9c1SJohn Baldwin int
755e706f7f0SJohn Baldwin pcib_alloc_msix(device_t pcib, device_t dev, int *irq)
7569bf4c9c1SJohn Baldwin {
757bd82bbb1SAndrew Gallatin 	struct pcib_softc *sc = device_get_softc(pcib);
7589bf4c9c1SJohn Baldwin 	device_t bus;
7599bf4c9c1SJohn Baldwin 
76022bf1c7fSJohn Baldwin 	if (sc->flags & PCIB_DISABLE_MSI)
76122bf1c7fSJohn Baldwin 		return (ENXIO);
7629bf4c9c1SJohn Baldwin 	bus = device_get_parent(pcib);
763e706f7f0SJohn Baldwin 	return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq));
7645fe82bcaSJohn Baldwin }
7655fe82bcaSJohn Baldwin 
7669bf4c9c1SJohn Baldwin /* Pass request to release an MSI-X message up to the parent bridge. */
7679bf4c9c1SJohn Baldwin int
7689bf4c9c1SJohn Baldwin pcib_release_msix(device_t pcib, device_t dev, int irq)
7699bf4c9c1SJohn Baldwin {
7709bf4c9c1SJohn Baldwin 	device_t bus;
7719bf4c9c1SJohn Baldwin 
7729bf4c9c1SJohn Baldwin 	bus = device_get_parent(pcib);
7739bf4c9c1SJohn Baldwin 	return (PCIB_RELEASE_MSIX(device_get_parent(bus), dev, irq));
7749bf4c9c1SJohn Baldwin }
7759bf4c9c1SJohn Baldwin 
776e706f7f0SJohn Baldwin /* Pass request to map MSI/MSI-X message up to parent bridge. */
777e706f7f0SJohn Baldwin int
778e706f7f0SJohn Baldwin pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr,
779e706f7f0SJohn Baldwin     uint32_t *data)
780e706f7f0SJohn Baldwin {
781e706f7f0SJohn Baldwin 	device_t bus;
7824522ac77SLuoqi Chen 	int error;
783e706f7f0SJohn Baldwin 
784e706f7f0SJohn Baldwin 	bus = device_get_parent(pcib);
7854522ac77SLuoqi Chen 	error = PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data);
7864522ac77SLuoqi Chen 	if (error)
7874522ac77SLuoqi Chen 		return (error);
7884522ac77SLuoqi Chen 
7894522ac77SLuoqi Chen 	pci_ht_map_msi(pcib, *addr);
7904522ac77SLuoqi Chen 	return (0);
791e706f7f0SJohn Baldwin }
792e706f7f0SJohn Baldwin 
793b173edafSJohn Baldwin /*
794b173edafSJohn Baldwin  * Try to read the bus number of a host-PCI bridge using appropriate config
795b173edafSJohn Baldwin  * registers.
796b173edafSJohn Baldwin  */
797b173edafSJohn Baldwin int
798b173edafSJohn Baldwin host_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func,
799b0cb115fSWarner Losh     uint8_t *busnum)
800b173edafSJohn Baldwin {
801b0cb115fSWarner Losh 	uint32_t id;
802b173edafSJohn Baldwin 
803b173edafSJohn Baldwin 	id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4);
8041bbf2464SJohn Baldwin 	if (id == 0xffffffff)
805b173edafSJohn Baldwin 		return (0);
806b173edafSJohn Baldwin 
807b173edafSJohn Baldwin 	switch (id) {
808b173edafSJohn Baldwin 	case 0x12258086:
809b173edafSJohn Baldwin 		/* Intel 824?? */
810b173edafSJohn Baldwin 		/* XXX This is a guess */
811b173edafSJohn Baldwin 		/* *busnum = read_config(bus, slot, func, 0x41, 1); */
812b173edafSJohn Baldwin 		*busnum = bus;
813b173edafSJohn Baldwin 		break;
814b173edafSJohn Baldwin 	case 0x84c48086:
815b173edafSJohn Baldwin 		/* Intel 82454KX/GX (Orion) */
816b173edafSJohn Baldwin 		*busnum = read_config(bus, slot, func, 0x4a, 1);
817b173edafSJohn Baldwin 		break;
818b173edafSJohn Baldwin 	case 0x84ca8086:
819b173edafSJohn Baldwin 		/*
820b173edafSJohn Baldwin 		 * For the 450nx chipset, there is a whole bundle of
821b173edafSJohn Baldwin 		 * things pretending to be host bridges. The MIOC will
822b173edafSJohn Baldwin 		 * be seen first and isn't really a pci bridge (the
823b173edafSJohn Baldwin 		 * actual busses are attached to the PXB's). We need to
824b173edafSJohn Baldwin 		 * read the registers of the MIOC to figure out the
825b173edafSJohn Baldwin 		 * bus numbers for the PXB channels.
826b173edafSJohn Baldwin 		 *
827b173edafSJohn Baldwin 		 * Since the MIOC doesn't have a pci bus attached, we
828b173edafSJohn Baldwin 		 * pretend it wasn't there.
829b173edafSJohn Baldwin 		 */
830b173edafSJohn Baldwin 		return (0);
831b173edafSJohn Baldwin 	case 0x84cb8086:
832b173edafSJohn Baldwin 		switch (slot) {
833b173edafSJohn Baldwin 		case 0x12:
834b173edafSJohn Baldwin 			/* Intel 82454NX PXB#0, Bus#A */
8351bbf2464SJohn Baldwin 			*busnum = read_config(bus, 0x10, func, 0xd0, 1);
836b173edafSJohn Baldwin 			break;
837b173edafSJohn Baldwin 		case 0x13:
838b173edafSJohn Baldwin 			/* Intel 82454NX PXB#0, Bus#B */
8391bbf2464SJohn Baldwin 			*busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1;
840b173edafSJohn Baldwin 			break;
841b173edafSJohn Baldwin 		case 0x14:
842b173edafSJohn Baldwin 			/* Intel 82454NX PXB#1, Bus#A */
8431bbf2464SJohn Baldwin 			*busnum = read_config(bus, 0x10, func, 0xd3, 1);
844b173edafSJohn Baldwin 			break;
845b173edafSJohn Baldwin 		case 0x15:
846b173edafSJohn Baldwin 			/* Intel 82454NX PXB#1, Bus#B */
8471bbf2464SJohn Baldwin 			*busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1;
848b173edafSJohn Baldwin 			break;
849b173edafSJohn Baldwin 		}
850b173edafSJohn Baldwin 		break;
851b173edafSJohn Baldwin 
852b173edafSJohn Baldwin 		/* ServerWorks -- vendor 0x1166 */
853b173edafSJohn Baldwin 	case 0x00051166:
854b173edafSJohn Baldwin 	case 0x00061166:
855b173edafSJohn Baldwin 	case 0x00081166:
856b173edafSJohn Baldwin 	case 0x00091166:
857b173edafSJohn Baldwin 	case 0x00101166:
858b173edafSJohn Baldwin 	case 0x00111166:
859b173edafSJohn Baldwin 	case 0x00171166:
860b173edafSJohn Baldwin 	case 0x01011166:
861b173edafSJohn Baldwin 	case 0x010f1014:
862b173edafSJohn Baldwin 	case 0x02011166:
863b173edafSJohn Baldwin 	case 0x03021014:
864b173edafSJohn Baldwin 		*busnum = read_config(bus, slot, func, 0x44, 1);
865b173edafSJohn Baldwin 		break;
8665165a17dSJohn Baldwin 
8675165a17dSJohn Baldwin 		/* Compaq/HP -- vendor 0x0e11 */
8685165a17dSJohn Baldwin 	case 0x60100e11:
8695165a17dSJohn Baldwin 		*busnum = read_config(bus, slot, func, 0xc8, 1);
8705165a17dSJohn Baldwin 		break;
871b173edafSJohn Baldwin 	default:
872b173edafSJohn Baldwin 		/* Don't know how to read bus number. */
873b173edafSJohn Baldwin 		return 0;
874b173edafSJohn Baldwin 	}
875b173edafSJohn Baldwin 
876b173edafSJohn Baldwin 	return 1;
877b173edafSJohn Baldwin }
878