pci_pci.c revision 279443
169783Smsmith/*-
269783Smsmith * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier
369783Smsmith * Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
469783Smsmith * Copyright (c) 2000 BSDi
569783Smsmith * All rights reserved.
669783Smsmith *
769783Smsmith * Redistribution and use in source and binary forms, with or without
869783Smsmith * modification, are permitted provided that the following conditions
969783Smsmith * are met:
1069783Smsmith * 1. Redistributions of source code must retain the above copyright
1169783Smsmith *    notice, this list of conditions and the following disclaimer.
1269783Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1369783Smsmith *    notice, this list of conditions and the following disclaimer in the
1469783Smsmith *    documentation and/or other materials provided with the distribution.
1569783Smsmith * 3. The name of the author may not be used to endorse or promote products
1669783Smsmith *    derived from this software without specific prior written permission.
1769783Smsmith *
1869783Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1969783Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2069783Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2169783Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2269783Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2369783Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2469783Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2569783Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2669783Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2769783Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2869783Smsmith * SUCH DAMAGE.
2969783Smsmith */
3069783Smsmith
31119418Sobrien#include <sys/cdefs.h>
32119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/pci/pci_pci.c 279443 2015-03-01 00:39:40Z rstone $");
33119418Sobrien
3469783Smsmith/*
3569783Smsmith * PCI:PCI bridge support.
3669783Smsmith */
3769783Smsmith
3869783Smsmith#include <sys/param.h>
39221393Sjhb#include <sys/bus.h>
4069783Smsmith#include <sys/kernel.h>
41221393Sjhb#include <sys/malloc.h>
42129876Sphk#include <sys/module.h>
43107546Simp#include <sys/rman.h>
44106844Smdodd#include <sys/sysctl.h>
45221393Sjhb#include <sys/systm.h>
4669783Smsmith
47119285Simp#include <dev/pci/pcivar.h>
48119285Simp#include <dev/pci/pcireg.h>
49211430Sjhb#include <dev/pci/pci_private.h>
50119285Simp#include <dev/pci/pcib_private.h>
5169783Smsmith
5269783Smsmith#include "pcib_if.h"
5369783Smsmith
5469783Smsmithstatic int		pcib_probe(device_t dev);
55200341Sjkimstatic int		pcib_suspend(device_t dev);
56200341Sjkimstatic int		pcib_resume(device_t dev);
57211430Sjhbstatic int		pcib_power_for_sleep(device_t pcib, device_t dev,
58211430Sjhb			    int *pstate);
59264011Srstonestatic uint16_t		pcib_ari_get_rid(device_t pcib, device_t dev);
60264011Srstonestatic uint32_t		pcib_read_config(device_t dev, u_int b, u_int s,
61264011Srstone    u_int f, u_int reg, int width);
62264011Srstonestatic void		pcib_write_config(device_t dev, u_int b, u_int s,
63264011Srstone    u_int f, u_int reg, uint32_t val, int width);
64264011Srstonestatic int		pcib_ari_maxslots(device_t dev);
65264011Srstonestatic int		pcib_ari_maxfuncs(device_t dev);
66264011Srstonestatic int		pcib_try_enable_ari(device_t pcib, device_t dev);
67279443Srstonestatic int		pcib_ari_enabled(device_t pcib);
68279443Srstonestatic void		pcib_ari_decode_rid(device_t pcib, uint16_t rid,
69279443Srstone			    int *bus, int *slot, int *func);
7069783Smsmith
7169783Smsmithstatic device_method_t pcib_methods[] = {
7269783Smsmith    /* Device interface */
7369783Smsmith    DEVMETHOD(device_probe,		pcib_probe),
7469783Smsmith    DEVMETHOD(device_attach,		pcib_attach),
75145661Simp    DEVMETHOD(device_detach,		bus_generic_detach),
7669783Smsmith    DEVMETHOD(device_shutdown,		bus_generic_shutdown),
77200341Sjkim    DEVMETHOD(device_suspend,		pcib_suspend),
78200341Sjkim    DEVMETHOD(device_resume,		pcib_resume),
7969783Smsmith
8069783Smsmith    /* Bus interface */
8169783Smsmith    DEVMETHOD(bus_read_ivar,		pcib_read_ivar),
8269783Smsmith    DEVMETHOD(bus_write_ivar,		pcib_write_ivar),
8369783Smsmith    DEVMETHOD(bus_alloc_resource,	pcib_alloc_resource),
84221393Sjhb#ifdef NEW_PCIB
85221393Sjhb    DEVMETHOD(bus_adjust_resource,	pcib_adjust_resource),
86221393Sjhb    DEVMETHOD(bus_release_resource,	pcib_release_resource),
87221393Sjhb#else
88221324Sjhb    DEVMETHOD(bus_adjust_resource,	bus_generic_adjust_resource),
8969783Smsmith    DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
90221393Sjhb#endif
9169783Smsmith    DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
9269783Smsmith    DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
9369783Smsmith    DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
9469783Smsmith    DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
9569783Smsmith
9669783Smsmith    /* pcib interface */
97264011Srstone    DEVMETHOD(pcib_maxslots,		pcib_ari_maxslots),
98264011Srstone    DEVMETHOD(pcib_maxfuncs,		pcib_ari_maxfuncs),
9969783Smsmith    DEVMETHOD(pcib_read_config,		pcib_read_config),
10069783Smsmith    DEVMETHOD(pcib_write_config,	pcib_write_config),
10169783Smsmith    DEVMETHOD(pcib_route_interrupt,	pcib_route_interrupt),
102164264Sjhb    DEVMETHOD(pcib_alloc_msi,		pcib_alloc_msi),
103164264Sjhb    DEVMETHOD(pcib_release_msi,		pcib_release_msi),
104164264Sjhb    DEVMETHOD(pcib_alloc_msix,		pcib_alloc_msix),
105164264Sjhb    DEVMETHOD(pcib_release_msix,	pcib_release_msix),
106169221Sjhb    DEVMETHOD(pcib_map_msi,		pcib_map_msi),
107211430Sjhb    DEVMETHOD(pcib_power_for_sleep,	pcib_power_for_sleep),
108264011Srstone    DEVMETHOD(pcib_get_rid,		pcib_ari_get_rid),
109264011Srstone    DEVMETHOD(pcib_try_enable_ari,	pcib_try_enable_ari),
110279443Srstone    DEVMETHOD(pcib_ari_enabled,		pcib_ari_enabled),
111279443Srstone    DEVMETHOD(pcib_decode_rid,		pcib_ari_decode_rid),
11269783Smsmith
113227843Smarius    DEVMETHOD_END
11469783Smsmith};
11569783Smsmith
116154079Sjhbstatic devclass_t pcib_devclass;
11769783Smsmith
118154079SjhbDEFINE_CLASS_0(pcib, pcib_driver, pcib_methods, sizeof(struct pcib_softc));
119253120SmariusDRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, NULL, NULL);
12069783Smsmith
121221393Sjhb#ifdef NEW_PCIB
122261527SjhbSYSCTL_DECL(_hw_pci);
123221393Sjhb
124261527Sjhbstatic int pci_clear_pcib;
125261527SjhbSYSCTL_INT(_hw_pci, OID_AUTO, clear_pcib, CTLFLAG_RDTUN, &pci_clear_pcib, 0,
126261527Sjhb    "Clear firmware-assigned resources for PCI-PCI bridge I/O windows.");
127261527Sjhb
128221393Sjhb/*
129221393Sjhb * Is a resource from a child device sub-allocated from one of our
130221393Sjhb * resource managers?
131221393Sjhb */
132221393Sjhbstatic int
133221393Sjhbpcib_is_resource_managed(struct pcib_softc *sc, int type, struct resource *r)
134221393Sjhb{
135221393Sjhb
136221393Sjhb	switch (type) {
137261790Sjhb#ifdef PCI_RES_BUS
138261790Sjhb	case PCI_RES_BUS:
139261790Sjhb		return (rman_is_region_manager(r, &sc->bus.rman));
140261790Sjhb#endif
141221393Sjhb	case SYS_RES_IOPORT:
142221393Sjhb		return (rman_is_region_manager(r, &sc->io.rman));
143221393Sjhb	case SYS_RES_MEMORY:
144221393Sjhb		/* Prefetchable resources may live in either memory rman. */
145221393Sjhb		if (rman_get_flags(r) & RF_PREFETCHABLE &&
146221393Sjhb		    rman_is_region_manager(r, &sc->pmem.rman))
147221393Sjhb			return (1);
148221393Sjhb		return (rman_is_region_manager(r, &sc->mem.rman));
149221393Sjhb	}
150221393Sjhb	return (0);
151221393Sjhb}
152221393Sjhb
153221393Sjhbstatic int
154221393Sjhbpcib_is_window_open(struct pcib_window *pw)
155221393Sjhb{
156221393Sjhb
157221393Sjhb	return (pw->valid && pw->base < pw->limit);
158221393Sjhb}
159221393Sjhb
160221393Sjhb/*
161221393Sjhb * XXX: If RF_ACTIVE did not also imply allocating a bus space tag and
162221393Sjhb * handle for the resource, we could pass RF_ACTIVE up to the PCI bus
163221393Sjhb * when allocating the resource windows and rely on the PCI bus driver
164221393Sjhb * to do this for us.
165221393Sjhb */
166221393Sjhbstatic void
167221393Sjhbpcib_activate_window(struct pcib_softc *sc, int type)
168221393Sjhb{
169221393Sjhb
170221393Sjhb	PCI_ENABLE_IO(device_get_parent(sc->dev), sc->dev, type);
171221393Sjhb}
172221393Sjhb
173221393Sjhbstatic void
174221393Sjhbpcib_write_windows(struct pcib_softc *sc, int mask)
175221393Sjhb{
176221393Sjhb	device_t dev;
177221393Sjhb	uint32_t val;
178221393Sjhb
179221393Sjhb	dev = sc->dev;
180221393Sjhb	if (sc->io.valid && mask & WIN_IO) {
181221393Sjhb		val = pci_read_config(dev, PCIR_IOBASEL_1, 1);
182221393Sjhb		if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) {
183221393Sjhb			pci_write_config(dev, PCIR_IOBASEH_1,
184221393Sjhb			    sc->io.base >> 16, 2);
185221393Sjhb			pci_write_config(dev, PCIR_IOLIMITH_1,
186221393Sjhb			    sc->io.limit >> 16, 2);
187221393Sjhb		}
188221393Sjhb		pci_write_config(dev, PCIR_IOBASEL_1, sc->io.base >> 8, 1);
189221393Sjhb		pci_write_config(dev, PCIR_IOLIMITL_1, sc->io.limit >> 8, 1);
190221393Sjhb	}
191221393Sjhb
192221393Sjhb	if (mask & WIN_MEM) {
193221393Sjhb		pci_write_config(dev, PCIR_MEMBASE_1, sc->mem.base >> 16, 2);
194221393Sjhb		pci_write_config(dev, PCIR_MEMLIMIT_1, sc->mem.limit >> 16, 2);
195221393Sjhb	}
196221393Sjhb
197221393Sjhb	if (sc->pmem.valid && mask & WIN_PMEM) {
198221393Sjhb		val = pci_read_config(dev, PCIR_PMBASEL_1, 2);
199221393Sjhb		if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) {
200221393Sjhb			pci_write_config(dev, PCIR_PMBASEH_1,
201221393Sjhb			    sc->pmem.base >> 32, 4);
202221393Sjhb			pci_write_config(dev, PCIR_PMLIMITH_1,
203221393Sjhb			    sc->pmem.limit >> 32, 4);
204221393Sjhb		}
205221393Sjhb		pci_write_config(dev, PCIR_PMBASEL_1, sc->pmem.base >> 16, 2);
206221393Sjhb		pci_write_config(dev, PCIR_PMLIMITL_1, sc->pmem.limit >> 16, 2);
207221393Sjhb	}
208221393Sjhb}
209221393Sjhb
210253450Sjhb/*
211253450Sjhb * This is used to reject I/O port allocations that conflict with an
212253450Sjhb * ISA alias range.
213253450Sjhb */
214253450Sjhbstatic int
215253450Sjhbpcib_is_isa_range(struct pcib_softc *sc, u_long start, u_long end, u_long count)
216253450Sjhb{
217253450Sjhb	u_long next_alias;
218253450Sjhb
219253450Sjhb	if (!(sc->bridgectl & PCIB_BCR_ISA_ENABLE))
220253450Sjhb		return (0);
221253450Sjhb
222253450Sjhb	/* Only check fixed ranges for overlap. */
223253450Sjhb	if (start + count - 1 != end)
224253450Sjhb		return (0);
225253450Sjhb
226253450Sjhb	/* ISA aliases are only in the lower 64KB of I/O space. */
227253450Sjhb	if (start >= 65536)
228253450Sjhb		return (0);
229253450Sjhb
230253450Sjhb	/* Check for overlap with 0x000 - 0x0ff as a special case. */
231253450Sjhb	if (start < 0x100)
232253450Sjhb		goto alias;
233253450Sjhb
234253450Sjhb	/*
235253450Sjhb	 * If the start address is an alias, the range is an alias.
236253450Sjhb	 * Otherwise, compute the start of the next alias range and
237253450Sjhb	 * check if it is before the end of the candidate range.
238253450Sjhb	 */
239253450Sjhb	if ((start & 0x300) != 0)
240253450Sjhb		goto alias;
241253450Sjhb	next_alias = (start & ~0x3fful) | 0x100;
242253450Sjhb	if (next_alias <= end)
243253450Sjhb		goto alias;
244253450Sjhb	return (0);
245253450Sjhb
246253450Sjhbalias:
247253450Sjhb	if (bootverbose)
248253450Sjhb		device_printf(sc->dev,
249253450Sjhb		    "I/O range %#lx-%#lx overlaps with an ISA alias\n", start,
250253450Sjhb		    end);
251253450Sjhb	return (1);
252253450Sjhb}
253253450Sjhb
254221393Sjhbstatic void
255253450Sjhbpcib_add_window_resources(struct pcib_window *w, struct resource **res,
256253450Sjhb    int count)
257253450Sjhb{
258253450Sjhb	struct resource **newarray;
259253450Sjhb	int error, i;
260253450Sjhb
261253450Sjhb	newarray = malloc(sizeof(struct resource *) * (w->count + count),
262253450Sjhb	    M_DEVBUF, M_WAITOK);
263253450Sjhb	if (w->res != NULL)
264253450Sjhb		bcopy(w->res, newarray, sizeof(struct resource *) * w->count);
265253450Sjhb	bcopy(res, newarray + w->count, sizeof(struct resource *) * count);
266253450Sjhb	free(w->res, M_DEVBUF);
267253450Sjhb	w->res = newarray;
268253450Sjhb	w->count += count;
269253450Sjhb
270253450Sjhb	for (i = 0; i < count; i++) {
271253450Sjhb		error = rman_manage_region(&w->rman, rman_get_start(res[i]),
272253450Sjhb		    rman_get_end(res[i]));
273253450Sjhb		if (error)
274253450Sjhb			panic("Failed to add resource to rman");
275253450Sjhb	}
276253450Sjhb}
277253450Sjhb
278253450Sjhbtypedef void (nonisa_callback)(u_long start, u_long end, void *arg);
279253450Sjhb
280253450Sjhbstatic void
281253450Sjhbpcib_walk_nonisa_ranges(u_long start, u_long end, nonisa_callback *cb,
282253450Sjhb    void *arg)
283253450Sjhb{
284253450Sjhb	u_long next_end;
285253450Sjhb
286253450Sjhb	/*
287253450Sjhb	 * If start is within an ISA alias range, move up to the start
288253450Sjhb	 * of the next non-alias range.  As a special case, addresses
289253450Sjhb	 * in the range 0x000 - 0x0ff should also be skipped since
290253450Sjhb	 * those are used for various system I/O devices in ISA
291253450Sjhb	 * systems.
292253450Sjhb	 */
293253450Sjhb	if (start <= 65535) {
294253450Sjhb		if (start < 0x100 || (start & 0x300) != 0) {
295253450Sjhb			start &= ~0x3ff;
296253450Sjhb			start += 0x400;
297253450Sjhb		}
298253450Sjhb	}
299253450Sjhb
300253450Sjhb	/* ISA aliases are only in the lower 64KB of I/O space. */
301253450Sjhb	while (start <= MIN(end, 65535)) {
302253450Sjhb		next_end = MIN(start | 0xff, end);
303253450Sjhb		cb(start, next_end, arg);
304253450Sjhb		start += 0x400;
305253450Sjhb	}
306253450Sjhb
307253450Sjhb	if (start <= end)
308253450Sjhb		cb(start, end, arg);
309253450Sjhb}
310253450Sjhb
311253450Sjhbstatic void
312253450Sjhbcount_ranges(u_long start, u_long end, void *arg)
313253450Sjhb{
314253450Sjhb	int *countp;
315253450Sjhb
316253450Sjhb	countp = arg;
317253450Sjhb	(*countp)++;
318253450Sjhb}
319253450Sjhb
320253450Sjhbstruct alloc_state {
321253450Sjhb	struct resource **res;
322253450Sjhb	struct pcib_softc *sc;
323253450Sjhb	int count, error;
324253450Sjhb};
325253450Sjhb
326253450Sjhbstatic void
327253450Sjhballoc_ranges(u_long start, u_long end, void *arg)
328253450Sjhb{
329253450Sjhb	struct alloc_state *as;
330253450Sjhb	struct pcib_window *w;
331253450Sjhb	int rid;
332253450Sjhb
333253450Sjhb	as = arg;
334253450Sjhb	if (as->error != 0)
335253450Sjhb		return;
336253450Sjhb
337253450Sjhb	w = &as->sc->io;
338253450Sjhb	rid = w->reg;
339253450Sjhb	if (bootverbose)
340253450Sjhb		device_printf(as->sc->dev,
341253450Sjhb		    "allocating non-ISA range %#lx-%#lx\n", start, end);
342253450Sjhb	as->res[as->count] = bus_alloc_resource(as->sc->dev, SYS_RES_IOPORT,
343253450Sjhb	    &rid, start, end, end - start + 1, 0);
344253450Sjhb	if (as->res[as->count] == NULL)
345253450Sjhb		as->error = ENXIO;
346253450Sjhb	else
347253450Sjhb		as->count++;
348253450Sjhb}
349253450Sjhb
350253450Sjhbstatic int
351253450Sjhbpcib_alloc_nonisa_ranges(struct pcib_softc *sc, u_long start, u_long end)
352253450Sjhb{
353253450Sjhb	struct alloc_state as;
354253450Sjhb	int i, new_count;
355253450Sjhb
356253450Sjhb	/* First, see how many ranges we need. */
357253450Sjhb	new_count = 0;
358253450Sjhb	pcib_walk_nonisa_ranges(start, end, count_ranges, &new_count);
359253450Sjhb
360253450Sjhb	/* Second, allocate the ranges. */
361253450Sjhb	as.res = malloc(sizeof(struct resource *) * new_count, M_DEVBUF,
362253450Sjhb	    M_WAITOK);
363253450Sjhb	as.sc = sc;
364253450Sjhb	as.count = 0;
365253450Sjhb	as.error = 0;
366253450Sjhb	pcib_walk_nonisa_ranges(start, end, alloc_ranges, &as);
367253450Sjhb	if (as.error != 0) {
368253450Sjhb		for (i = 0; i < as.count; i++)
369253450Sjhb			bus_release_resource(sc->dev, SYS_RES_IOPORT,
370253450Sjhb			    sc->io.reg, as.res[i]);
371253450Sjhb		free(as.res, M_DEVBUF);
372253450Sjhb		return (as.error);
373253450Sjhb	}
374253450Sjhb	KASSERT(as.count == new_count, ("%s: count mismatch", __func__));
375253450Sjhb
376253450Sjhb	/* Third, add the ranges to the window. */
377253450Sjhb	pcib_add_window_resources(&sc->io, as.res, as.count);
378253450Sjhb	free(as.res, M_DEVBUF);
379253450Sjhb	return (0);
380253450Sjhb}
381253450Sjhb
382253450Sjhbstatic void
383221393Sjhbpcib_alloc_window(struct pcib_softc *sc, struct pcib_window *w, int type,
384221393Sjhb    int flags, pci_addr_t max_address)
385221393Sjhb{
386253450Sjhb	struct resource *res;
387221393Sjhb	char buf[64];
388221393Sjhb	int error, rid;
389221393Sjhb
390221393Sjhb	if (max_address != (u_long)max_address)
391221393Sjhb		max_address = ~0ul;
392221393Sjhb	w->rman.rm_start = 0;
393221393Sjhb	w->rman.rm_end = max_address;
394221393Sjhb	w->rman.rm_type = RMAN_ARRAY;
395221393Sjhb	snprintf(buf, sizeof(buf), "%s %s window",
396221393Sjhb	    device_get_nameunit(sc->dev), w->name);
397221393Sjhb	w->rman.rm_descr = strdup(buf, M_DEVBUF);
398221393Sjhb	error = rman_init(&w->rman);
399221393Sjhb	if (error)
400221393Sjhb		panic("Failed to initialize %s %s rman",
401221393Sjhb		    device_get_nameunit(sc->dev), w->name);
402221393Sjhb
403221393Sjhb	if (!pcib_is_window_open(w))
404221393Sjhb		return;
405221393Sjhb
406221393Sjhb	if (w->base > max_address || w->limit > max_address) {
407221393Sjhb		device_printf(sc->dev,
408221393Sjhb		    "initial %s window has too many bits, ignoring\n", w->name);
409221393Sjhb		return;
410221393Sjhb	}
411253450Sjhb	if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE)
412253450Sjhb		(void)pcib_alloc_nonisa_ranges(sc, w->base, w->limit);
413253450Sjhb	else {
414253450Sjhb		rid = w->reg;
415253450Sjhb		res = bus_alloc_resource(sc->dev, type, &rid, w->base, w->limit,
416253450Sjhb		    w->limit - w->base + 1, flags);
417253450Sjhb		if (res != NULL)
418253450Sjhb			pcib_add_window_resources(w, &res, 1);
419253450Sjhb	}
420221393Sjhb	if (w->res == NULL) {
421221393Sjhb		device_printf(sc->dev,
422221393Sjhb		    "failed to allocate initial %s window: %#jx-%#jx\n",
423221393Sjhb		    w->name, (uintmax_t)w->base, (uintmax_t)w->limit);
424221393Sjhb		w->base = max_address;
425221393Sjhb		w->limit = 0;
426221393Sjhb		pcib_write_windows(sc, w->mask);
427221393Sjhb		return;
428221393Sjhb	}
429221393Sjhb	pcib_activate_window(sc, type);
430221393Sjhb}
431221393Sjhb
432221393Sjhb/*
433221393Sjhb * Initialize I/O windows.
434221393Sjhb */
435221393Sjhbstatic void
436221393Sjhbpcib_probe_windows(struct pcib_softc *sc)
437221393Sjhb{
438221393Sjhb	pci_addr_t max;
439221393Sjhb	device_t dev;
440221393Sjhb	uint32_t val;
441221393Sjhb
442221393Sjhb	dev = sc->dev;
443221393Sjhb
444261527Sjhb	if (pci_clear_pcib) {
445261527Sjhb		pci_write_config(dev, PCIR_IOBASEL_1, 0xff, 1);
446261527Sjhb		pci_write_config(dev, PCIR_IOBASEH_1, 0xffff, 2);
447261527Sjhb		pci_write_config(dev, PCIR_IOLIMITL_1, 0, 1);
448261527Sjhb		pci_write_config(dev, PCIR_IOLIMITH_1, 0, 2);
449261527Sjhb		pci_write_config(dev, PCIR_MEMBASE_1, 0xffff, 2);
450261527Sjhb		pci_write_config(dev, PCIR_MEMLIMIT_1, 0, 2);
451261527Sjhb		pci_write_config(dev, PCIR_PMBASEL_1, 0xffff, 2);
452261527Sjhb		pci_write_config(dev, PCIR_PMBASEH_1, 0xffffffff, 4);
453261527Sjhb		pci_write_config(dev, PCIR_PMLIMITL_1, 0, 2);
454261527Sjhb		pci_write_config(dev, PCIR_PMLIMITH_1, 0, 4);
455261527Sjhb	}
456261527Sjhb
457221393Sjhb	/* Determine if the I/O port window is implemented. */
458221393Sjhb	val = pci_read_config(dev, PCIR_IOBASEL_1, 1);
459221393Sjhb	if (val == 0) {
460221393Sjhb		/*
461221393Sjhb		 * If 'val' is zero, then only 16-bits of I/O space
462221393Sjhb		 * are supported.
463221393Sjhb		 */
464221393Sjhb		pci_write_config(dev, PCIR_IOBASEL_1, 0xff, 1);
465221393Sjhb		if (pci_read_config(dev, PCIR_IOBASEL_1, 1) != 0) {
466221393Sjhb			sc->io.valid = 1;
467221393Sjhb			pci_write_config(dev, PCIR_IOBASEL_1, 0, 1);
468221393Sjhb		}
469221393Sjhb	} else
470221393Sjhb		sc->io.valid = 1;
471221393Sjhb
472221393Sjhb	/* Read the existing I/O port window. */
473221393Sjhb	if (sc->io.valid) {
474221393Sjhb		sc->io.reg = PCIR_IOBASEL_1;
475221393Sjhb		sc->io.step = 12;
476221393Sjhb		sc->io.mask = WIN_IO;
477221393Sjhb		sc->io.name = "I/O port";
478221393Sjhb		if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) {
479221393Sjhb			sc->io.base = PCI_PPBIOBASE(
480221393Sjhb			    pci_read_config(dev, PCIR_IOBASEH_1, 2), val);
481221393Sjhb			sc->io.limit = PCI_PPBIOLIMIT(
482221393Sjhb			    pci_read_config(dev, PCIR_IOLIMITH_1, 2),
483221393Sjhb			    pci_read_config(dev, PCIR_IOLIMITL_1, 1));
484221393Sjhb			max = 0xffffffff;
485221393Sjhb		} else {
486221393Sjhb			sc->io.base = PCI_PPBIOBASE(0, val);
487221393Sjhb			sc->io.limit = PCI_PPBIOLIMIT(0,
488221393Sjhb			    pci_read_config(dev, PCIR_IOLIMITL_1, 1));
489221393Sjhb			max = 0xffff;
490221393Sjhb		}
491221393Sjhb		pcib_alloc_window(sc, &sc->io, SYS_RES_IOPORT, 0, max);
492221393Sjhb	}
493221393Sjhb
494221393Sjhb	/* Read the existing memory window. */
495221393Sjhb	sc->mem.valid = 1;
496221393Sjhb	sc->mem.reg = PCIR_MEMBASE_1;
497221393Sjhb	sc->mem.step = 20;
498221393Sjhb	sc->mem.mask = WIN_MEM;
499221393Sjhb	sc->mem.name = "memory";
500221393Sjhb	sc->mem.base = PCI_PPBMEMBASE(0,
501221393Sjhb	    pci_read_config(dev, PCIR_MEMBASE_1, 2));
502221393Sjhb	sc->mem.limit = PCI_PPBMEMLIMIT(0,
503221393Sjhb	    pci_read_config(dev, PCIR_MEMLIMIT_1, 2));
504221393Sjhb	pcib_alloc_window(sc, &sc->mem, SYS_RES_MEMORY, 0, 0xffffffff);
505221393Sjhb
506221393Sjhb	/* Determine if the prefetchable memory window is implemented. */
507221393Sjhb	val = pci_read_config(dev, PCIR_PMBASEL_1, 2);
508221393Sjhb	if (val == 0) {
509221393Sjhb		/*
510221393Sjhb		 * If 'val' is zero, then only 32-bits of memory space
511221393Sjhb		 * are supported.
512221393Sjhb		 */
513221393Sjhb		pci_write_config(dev, PCIR_PMBASEL_1, 0xffff, 2);
514221393Sjhb		if (pci_read_config(dev, PCIR_PMBASEL_1, 2) != 0) {
515221393Sjhb			sc->pmem.valid = 1;
516221393Sjhb			pci_write_config(dev, PCIR_PMBASEL_1, 0, 2);
517221393Sjhb		}
518221393Sjhb	} else
519221393Sjhb		sc->pmem.valid = 1;
520221393Sjhb
521221393Sjhb	/* Read the existing prefetchable memory window. */
522221393Sjhb	if (sc->pmem.valid) {
523221393Sjhb		sc->pmem.reg = PCIR_PMBASEL_1;
524221393Sjhb		sc->pmem.step = 20;
525221393Sjhb		sc->pmem.mask = WIN_PMEM;
526221393Sjhb		sc->pmem.name = "prefetch";
527221393Sjhb		if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) {
528221393Sjhb			sc->pmem.base = PCI_PPBMEMBASE(
529221393Sjhb			    pci_read_config(dev, PCIR_PMBASEH_1, 4), val);
530221393Sjhb			sc->pmem.limit = PCI_PPBMEMLIMIT(
531221393Sjhb			    pci_read_config(dev, PCIR_PMLIMITH_1, 4),
532221393Sjhb			    pci_read_config(dev, PCIR_PMLIMITL_1, 2));
533221393Sjhb			max = 0xffffffffffffffff;
534221393Sjhb		} else {
535221393Sjhb			sc->pmem.base = PCI_PPBMEMBASE(0, val);
536221393Sjhb			sc->pmem.limit = PCI_PPBMEMLIMIT(0,
537221393Sjhb			    pci_read_config(dev, PCIR_PMLIMITL_1, 2));
538221393Sjhb			max = 0xffffffff;
539221393Sjhb		}
540221393Sjhb		pcib_alloc_window(sc, &sc->pmem, SYS_RES_MEMORY,
541221393Sjhb		    RF_PREFETCHABLE, max);
542221393Sjhb	}
543221393Sjhb}
544221393Sjhb
545261790Sjhb#ifdef PCI_RES_BUS
546261790Sjhb/*
547261790Sjhb * Allocate a suitable secondary bus for this bridge if needed and
548261790Sjhb * initialize the resource manager for the secondary bus range.  Note
549261790Sjhb * that the minimum count is a desired value and this may allocate a
550261790Sjhb * smaller range.
551261790Sjhb */
552261790Sjhbvoid
553261790Sjhbpcib_setup_secbus(device_t dev, struct pcib_secbus *bus, int min_count)
554261790Sjhb{
555261790Sjhb	char buf[64];
556261790Sjhb	int error, rid;
557261790Sjhb
558261790Sjhb	switch (pci_read_config(dev, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE) {
559261790Sjhb	case PCIM_HDRTYPE_BRIDGE:
560261790Sjhb		bus->sub_reg = PCIR_SUBBUS_1;
561261790Sjhb		break;
562261790Sjhb	case PCIM_HDRTYPE_CARDBUS:
563261790Sjhb		bus->sub_reg = PCIR_SUBBUS_2;
564261790Sjhb		break;
565261790Sjhb	default:
566261790Sjhb		panic("not a PCI bridge");
567261790Sjhb	}
568261790Sjhb	bus->dev = dev;
569261790Sjhb	bus->rman.rm_start = 0;
570261790Sjhb	bus->rman.rm_end = PCI_BUSMAX;
571261790Sjhb	bus->rman.rm_type = RMAN_ARRAY;
572261790Sjhb	snprintf(buf, sizeof(buf), "%s bus numbers", device_get_nameunit(dev));
573261790Sjhb	bus->rman.rm_descr = strdup(buf, M_DEVBUF);
574261790Sjhb	error = rman_init(&bus->rman);
575261790Sjhb	if (error)
576261790Sjhb		panic("Failed to initialize %s bus number rman",
577261790Sjhb		    device_get_nameunit(dev));
578261790Sjhb
579261790Sjhb	/*
580261790Sjhb	 * Allocate a bus range.  This will return an existing bus range
581261790Sjhb	 * if one exists, or a new bus range if one does not.
582261790Sjhb	 */
583261790Sjhb	rid = 0;
584261790Sjhb	bus->res = bus_alloc_resource(dev, PCI_RES_BUS, &rid, 0ul, ~0ul,
585261790Sjhb	    min_count, 0);
586261790Sjhb	if (bus->res == NULL) {
587261790Sjhb		/*
588261790Sjhb		 * Fall back to just allocating a range of a single bus
589261790Sjhb		 * number.
590261790Sjhb		 */
591261790Sjhb		bus->res = bus_alloc_resource(dev, PCI_RES_BUS, &rid, 0ul, ~0ul,
592261790Sjhb		    1, 0);
593261790Sjhb	} else if (rman_get_size(bus->res) < min_count)
594261790Sjhb		/*
595261790Sjhb		 * Attempt to grow the existing range to satisfy the
596261790Sjhb		 * minimum desired count.
597261790Sjhb		 */
598261790Sjhb		(void)bus_adjust_resource(dev, PCI_RES_BUS, bus->res,
599261790Sjhb		    rman_get_start(bus->res), rman_get_start(bus->res) +
600261790Sjhb		    min_count - 1);
601261790Sjhb
602261790Sjhb	/*
603261790Sjhb	 * Add the initial resource to the rman.
604261790Sjhb	 */
605261790Sjhb	if (bus->res != NULL) {
606261790Sjhb		error = rman_manage_region(&bus->rman, rman_get_start(bus->res),
607261790Sjhb		    rman_get_end(bus->res));
608261790Sjhb		if (error)
609261790Sjhb			panic("Failed to add resource to rman");
610261790Sjhb		bus->sec = rman_get_start(bus->res);
611261790Sjhb		bus->sub = rman_get_end(bus->res);
612261790Sjhb	}
613261790Sjhb}
614261790Sjhb
615261790Sjhbstatic struct resource *
616261790Sjhbpcib_suballoc_bus(struct pcib_secbus *bus, device_t child, int *rid,
617261790Sjhb    u_long start, u_long end, u_long count, u_int flags)
618261790Sjhb{
619261790Sjhb	struct resource *res;
620261790Sjhb
621261790Sjhb	res = rman_reserve_resource(&bus->rman, start, end, count, flags,
622261790Sjhb	    child);
623261790Sjhb	if (res == NULL)
624261790Sjhb		return (NULL);
625261790Sjhb
626261790Sjhb	if (bootverbose)
627261790Sjhb		device_printf(bus->dev,
628261790Sjhb		    "allocated bus range (%lu-%lu) for rid %d of %s\n",
629261790Sjhb		    rman_get_start(res), rman_get_end(res), *rid,
630261790Sjhb		    pcib_child_name(child));
631261790Sjhb	rman_set_rid(res, *rid);
632261790Sjhb	return (res);
633261790Sjhb}
634261790Sjhb
635261790Sjhb/*
636261790Sjhb * Attempt to grow the secondary bus range.  This is much simpler than
637261790Sjhb * for I/O windows as the range can only be grown by increasing
638261790Sjhb * subbus.
639261790Sjhb */
640261790Sjhbstatic int
641261790Sjhbpcib_grow_subbus(struct pcib_secbus *bus, u_long new_end)
642261790Sjhb{
643261790Sjhb	u_long old_end;
644261790Sjhb	int error;
645261790Sjhb
646261790Sjhb	old_end = rman_get_end(bus->res);
647261790Sjhb	KASSERT(new_end > old_end, ("attempt to shrink subbus"));
648261790Sjhb	error = bus_adjust_resource(bus->dev, PCI_RES_BUS, bus->res,
649261790Sjhb	    rman_get_start(bus->res), new_end);
650261790Sjhb	if (error)
651261790Sjhb		return (error);
652261790Sjhb	if (bootverbose)
653261790Sjhb		device_printf(bus->dev, "grew bus range to %lu-%lu\n",
654261790Sjhb		    rman_get_start(bus->res), rman_get_end(bus->res));
655261790Sjhb	error = rman_manage_region(&bus->rman, old_end + 1,
656261790Sjhb	    rman_get_end(bus->res));
657261790Sjhb	if (error)
658261790Sjhb		panic("Failed to add resource to rman");
659261790Sjhb	bus->sub = rman_get_end(bus->res);
660261790Sjhb	pci_write_config(bus->dev, bus->sub_reg, bus->sub, 1);
661261790Sjhb	return (0);
662261790Sjhb}
663261790Sjhb
664261790Sjhbstruct resource *
665261790Sjhbpcib_alloc_subbus(struct pcib_secbus *bus, device_t child, int *rid,
666261790Sjhb    u_long start, u_long end, u_long count, u_int flags)
667261790Sjhb{
668261790Sjhb	struct resource *res;
669261790Sjhb	u_long start_free, end_free, new_end;
670261790Sjhb
671261790Sjhb	/*
672261790Sjhb	 * First, see if the request can be satisified by the existing
673261790Sjhb	 * bus range.
674261790Sjhb	 */
675261790Sjhb	res = pcib_suballoc_bus(bus, child, rid, start, end, count, flags);
676261790Sjhb	if (res != NULL)
677261790Sjhb		return (res);
678261790Sjhb
679261790Sjhb	/*
680261790Sjhb	 * Figure out a range to grow the bus range.  First, find the
681261790Sjhb	 * first bus number after the last allocated bus in the rman and
682261790Sjhb	 * enforce that as a minimum starting point for the range.
683261790Sjhb	 */
684261790Sjhb	if (rman_last_free_region(&bus->rman, &start_free, &end_free) != 0 ||
685261790Sjhb	    end_free != bus->sub)
686261790Sjhb		start_free = bus->sub + 1;
687261790Sjhb	if (start_free < start)
688261790Sjhb		start_free = start;
689261790Sjhb	new_end = start_free + count - 1;
690261790Sjhb
691261790Sjhb	/*
692261790Sjhb	 * See if this new range would satisfy the request if it
693261790Sjhb	 * succeeds.
694261790Sjhb	 */
695261790Sjhb	if (new_end > end)
696261790Sjhb		return (NULL);
697261790Sjhb
698261790Sjhb	/* Finally, attempt to grow the existing resource. */
699261790Sjhb	if (bootverbose) {
700261790Sjhb		device_printf(bus->dev,
701261790Sjhb		    "attempting to grow bus range for %lu buses\n", count);
702261790Sjhb		printf("\tback candidate range: %lu-%lu\n", start_free,
703261790Sjhb		    new_end);
704261790Sjhb	}
705261790Sjhb	if (pcib_grow_subbus(bus, new_end) == 0)
706261790Sjhb		return (pcib_suballoc_bus(bus, child, rid, start, end, count,
707261790Sjhb		    flags));
708261790Sjhb	return (NULL);
709261790Sjhb}
710261790Sjhb#endif
711261790Sjhb
712221393Sjhb#else
713221393Sjhb
714221393Sjhb/*
715163805Simp * Is the prefetch window open (eg, can we allocate memory in it?)
716163805Simp */
717163805Simpstatic int
718163805Simppcib_is_prefetch_open(struct pcib_softc *sc)
719163805Simp{
720163805Simp	return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit);
721163805Simp}
722163805Simp
723163805Simp/*
724163805Simp * Is the nonprefetch window open (eg, can we allocate memory in it?)
725163805Simp */
726163805Simpstatic int
727163805Simppcib_is_nonprefetch_open(struct pcib_softc *sc)
728163805Simp{
729163805Simp	return (sc->membase > 0 && sc->membase < sc->memlimit);
730163805Simp}
731163805Simp
732163805Simp/*
733163805Simp * Is the io window open (eg, can we allocate ports in it?)
734163805Simp */
735163805Simpstatic int
736163805Simppcib_is_io_open(struct pcib_softc *sc)
737163805Simp{
738163805Simp	return (sc->iobase > 0 && sc->iobase < sc->iolimit);
739163805Simp}
740163805Simp
741163805Simp/*
742200341Sjkim * Get current I/O decode.
743200341Sjkim */
744200341Sjkimstatic void
745200341Sjkimpcib_get_io_decode(struct pcib_softc *sc)
746200341Sjkim{
747200341Sjkim	device_t	dev;
748200341Sjkim	uint32_t	iolow;
749200341Sjkim
750200341Sjkim	dev = sc->dev;
751200341Sjkim
752200341Sjkim	iolow = pci_read_config(dev, PCIR_IOBASEL_1, 1);
753200341Sjkim	if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32)
754200341Sjkim		sc->iobase = PCI_PPBIOBASE(
755200341Sjkim		    pci_read_config(dev, PCIR_IOBASEH_1, 2), iolow);
756200341Sjkim	else
757200341Sjkim		sc->iobase = PCI_PPBIOBASE(0, iolow);
758200341Sjkim
759200341Sjkim	iolow = pci_read_config(dev, PCIR_IOLIMITL_1, 1);
760200341Sjkim	if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32)
761200341Sjkim		sc->iolimit = PCI_PPBIOLIMIT(
762200341Sjkim		    pci_read_config(dev, PCIR_IOLIMITH_1, 2), iolow);
763200341Sjkim	else
764200341Sjkim		sc->iolimit = PCI_PPBIOLIMIT(0, iolow);
765200341Sjkim}
766200341Sjkim
767200341Sjkim/*
768200341Sjkim * Get current memory decode.
769200341Sjkim */
770200341Sjkimstatic void
771200341Sjkimpcib_get_mem_decode(struct pcib_softc *sc)
772200341Sjkim{
773200341Sjkim	device_t	dev;
774200341Sjkim	pci_addr_t	pmemlow;
775200341Sjkim
776200341Sjkim	dev = sc->dev;
777200341Sjkim
778200341Sjkim	sc->membase = PCI_PPBMEMBASE(0,
779200341Sjkim	    pci_read_config(dev, PCIR_MEMBASE_1, 2));
780200341Sjkim	sc->memlimit = PCI_PPBMEMLIMIT(0,
781200341Sjkim	    pci_read_config(dev, PCIR_MEMLIMIT_1, 2));
782200341Sjkim
783200341Sjkim	pmemlow = pci_read_config(dev, PCIR_PMBASEL_1, 2);
784200341Sjkim	if ((pmemlow & PCIM_BRPM_MASK) == PCIM_BRPM_64)
785200341Sjkim		sc->pmembase = PCI_PPBMEMBASE(
786200341Sjkim		    pci_read_config(dev, PCIR_PMBASEH_1, 4), pmemlow);
787200341Sjkim	else
788200341Sjkim		sc->pmembase = PCI_PPBMEMBASE(0, pmemlow);
789200341Sjkim
790200341Sjkim	pmemlow = pci_read_config(dev, PCIR_PMLIMITL_1, 2);
791200341Sjkim	if ((pmemlow & PCIM_BRPM_MASK) == PCIM_BRPM_64)
792200341Sjkim		sc->pmemlimit = PCI_PPBMEMLIMIT(
793200341Sjkim		    pci_read_config(dev, PCIR_PMLIMITH_1, 4), pmemlow);
794200341Sjkim	else
795200341Sjkim		sc->pmemlimit = PCI_PPBMEMLIMIT(0, pmemlow);
796200341Sjkim}
797200341Sjkim
798200341Sjkim/*
799200341Sjkim * Restore previous I/O decode.
800200341Sjkim */
801200341Sjkimstatic void
802200341Sjkimpcib_set_io_decode(struct pcib_softc *sc)
803200341Sjkim{
804200341Sjkim	device_t	dev;
805200341Sjkim	uint32_t	iohi;
806200341Sjkim
807200341Sjkim	dev = sc->dev;
808200341Sjkim
809200341Sjkim	iohi = sc->iobase >> 16;
810200341Sjkim	if (iohi > 0)
811200341Sjkim		pci_write_config(dev, PCIR_IOBASEH_1, iohi, 2);
812200341Sjkim	pci_write_config(dev, PCIR_IOBASEL_1, sc->iobase >> 8, 1);
813200341Sjkim
814200341Sjkim	iohi = sc->iolimit >> 16;
815200341Sjkim	if (iohi > 0)
816200341Sjkim		pci_write_config(dev, PCIR_IOLIMITH_1, iohi, 2);
817200341Sjkim	pci_write_config(dev, PCIR_IOLIMITL_1, sc->iolimit >> 8, 1);
818200341Sjkim}
819200341Sjkim
820200341Sjkim/*
821200341Sjkim * Restore previous memory decode.
822200341Sjkim */
823200341Sjkimstatic void
824200341Sjkimpcib_set_mem_decode(struct pcib_softc *sc)
825200341Sjkim{
826200341Sjkim	device_t	dev;
827200341Sjkim	pci_addr_t	pmemhi;
828200341Sjkim
829200341Sjkim	dev = sc->dev;
830200341Sjkim
831200341Sjkim	pci_write_config(dev, PCIR_MEMBASE_1, sc->membase >> 16, 2);
832200341Sjkim	pci_write_config(dev, PCIR_MEMLIMIT_1, sc->memlimit >> 16, 2);
833200341Sjkim
834200341Sjkim	pmemhi = sc->pmembase >> 32;
835200341Sjkim	if (pmemhi > 0)
836200341Sjkim		pci_write_config(dev, PCIR_PMBASEH_1, pmemhi, 4);
837200341Sjkim	pci_write_config(dev, PCIR_PMBASEL_1, sc->pmembase >> 16, 2);
838200341Sjkim
839200341Sjkim	pmemhi = sc->pmemlimit >> 32;
840200341Sjkim	if (pmemhi > 0)
841200341Sjkim		pci_write_config(dev, PCIR_PMLIMITH_1, pmemhi, 4);
842200341Sjkim	pci_write_config(dev, PCIR_PMLIMITL_1, sc->pmemlimit >> 16, 2);
843200341Sjkim}
844221393Sjhb#endif
845200341Sjkim
846200341Sjkim/*
847200341Sjkim * Get current bridge configuration.
848200341Sjkim */
849200341Sjkimstatic void
850200341Sjkimpcib_cfg_save(struct pcib_softc *sc)
851200341Sjkim{
852200341Sjkim	device_t	dev;
853200341Sjkim
854200341Sjkim	dev = sc->dev;
855200341Sjkim
856200341Sjkim	sc->command = pci_read_config(dev, PCIR_COMMAND, 2);
857200341Sjkim	sc->pribus = pci_read_config(dev, PCIR_PRIBUS_1, 1);
858261790Sjhb	sc->bus.sec = pci_read_config(dev, PCIR_SECBUS_1, 1);
859261790Sjhb	sc->bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1);
860200341Sjkim	sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2);
861200341Sjkim	sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1);
862221393Sjhb#ifndef NEW_PCIB
863200341Sjkim	if (sc->command & PCIM_CMD_PORTEN)
864200341Sjkim		pcib_get_io_decode(sc);
865200341Sjkim	if (sc->command & PCIM_CMD_MEMEN)
866200341Sjkim		pcib_get_mem_decode(sc);
867221393Sjhb#endif
868200341Sjkim}
869200341Sjkim
870200341Sjkim/*
871200341Sjkim * Restore previous bridge configuration.
872200341Sjkim */
873200341Sjkimstatic void
874200341Sjkimpcib_cfg_restore(struct pcib_softc *sc)
875200341Sjkim{
876200341Sjkim	device_t	dev;
877200341Sjkim
878200341Sjkim	dev = sc->dev;
879200341Sjkim
880200341Sjkim	pci_write_config(dev, PCIR_COMMAND, sc->command, 2);
881200341Sjkim	pci_write_config(dev, PCIR_PRIBUS_1, sc->pribus, 1);
882261790Sjhb	pci_write_config(dev, PCIR_SECBUS_1, sc->bus.sec, 1);
883261790Sjhb	pci_write_config(dev, PCIR_SUBBUS_1, sc->bus.sub, 1);
884200341Sjkim	pci_write_config(dev, PCIR_BRIDGECTL_1, sc->bridgectl, 2);
885200341Sjkim	pci_write_config(dev, PCIR_SECLAT_1, sc->seclat, 1);
886221393Sjhb#ifdef NEW_PCIB
887221393Sjhb	pcib_write_windows(sc, WIN_IO | WIN_MEM | WIN_PMEM);
888221393Sjhb#else
889200341Sjkim	if (sc->command & PCIM_CMD_PORTEN)
890200341Sjkim		pcib_set_io_decode(sc);
891200341Sjkim	if (sc->command & PCIM_CMD_MEMEN)
892200341Sjkim		pcib_set_mem_decode(sc);
893221393Sjhb#endif
894200341Sjkim}
895200341Sjkim
896200341Sjkim/*
89769783Smsmith * Generic device interface
89869783Smsmith */
89969783Smsmithstatic int
90069783Smsmithpcib_probe(device_t dev)
90169783Smsmith{
90269783Smsmith    if ((pci_get_class(dev) == PCIC_BRIDGE) &&
90369783Smsmith	(pci_get_subclass(dev) == PCIS_BRIDGE_PCI)) {
90469783Smsmith	device_set_desc(dev, "PCI-PCI bridge");
90569783Smsmith	return(-10000);
90669783Smsmith    }
90769783Smsmith    return(ENXIO);
90869783Smsmith}
90969783Smsmith
910102441Sjhbvoid
911102441Sjhbpcib_attach_common(device_t dev)
91269783Smsmith{
91369783Smsmith    struct pcib_softc	*sc;
914181789Simp    struct sysctl_ctx_list *sctx;
915181789Simp    struct sysctl_oid	*soid;
916253450Sjhb    int comma;
91769783Smsmith
91869783Smsmith    sc = device_get_softc(dev);
91969783Smsmith    sc->dev = dev;
92069783Smsmith
92169908Smsmith    /*
92269908Smsmith     * Get current bridge configuration.
92369908Smsmith     */
924200341Sjkim    sc->domain = pci_get_domain(dev);
925200341Sjkim    sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2);
926200341Sjkim    pcib_cfg_save(sc);
92769783Smsmith
92869908Smsmith    /*
929261790Sjhb     * The primary bus register should always be the bus of the
930261790Sjhb     * parent.
931261790Sjhb     */
932261790Sjhb    sc->pribus = pci_get_bus(dev);
933261790Sjhb    pci_write_config(dev, PCIR_PRIBUS_1, sc->pribus, 1);
934261790Sjhb
935261790Sjhb    /*
936181789Simp     * Setup sysctl reporting nodes
937181789Simp     */
938181789Simp    sctx = device_get_sysctl_ctx(dev);
939181789Simp    soid = device_get_sysctl_tree(dev);
940181789Simp    SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "domain",
941182706Simp      CTLFLAG_RD, &sc->domain, 0, "Domain number");
942181789Simp    SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus",
943182706Simp      CTLFLAG_RD, &sc->pribus, 0, "Primary bus number");
944181789Simp    SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus",
945261790Sjhb      CTLFLAG_RD, &sc->bus.sec, 0, "Secondary bus number");
946181789Simp    SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus",
947261790Sjhb      CTLFLAG_RD, &sc->bus.sub, 0, "Subordinate bus number");
948181789Simp
949181789Simp    /*
95069908Smsmith     * Quirk handling.
95169908Smsmith     */
95269908Smsmith    switch (pci_get_devid(dev)) {
953261790Sjhb#if !defined(NEW_PCIB) && !defined(PCI_RES_BUS)
954124365Simp    case 0x12258086:		/* Intel 82454KX/GX (Orion) */
95569908Smsmith	{
956119266Simp	    uint8_t	supbus;
95769908Smsmith
95869908Smsmith	    supbus = pci_read_config(dev, 0x41, 1);
95969908Smsmith	    if (supbus != 0xff) {
960261790Sjhb		sc->bus.sec = supbus + 1;
961261790Sjhb		sc->bus.sub = supbus + 1;
96269908Smsmith	    }
963124365Simp	    break;
96469908Smsmith	}
965261790Sjhb#endif
966124365Simp
967124365Simp    /*
968124365Simp     * The i82380FB mobile docking controller is a PCI-PCI bridge,
969124365Simp     * and it is a subtractive bridge.  However, the ProgIf is wrong
970124365Simp     * so the normal setting of PCIB_SUBTRACTIVE bit doesn't
971124365Simp     * happen.  There's also a Toshiba bridge that behaves this
972124365Simp     * way.
973124365Simp     */
974124365Simp    case 0x124b8086:		/* Intel 82380FB Mobile */
975124365Simp    case 0x060513d7:		/* Toshiba ???? */
976124365Simp	sc->flags |= PCIB_SUBTRACTIVE;
97769908Smsmith	break;
978149521Sjkim
979261790Sjhb#if !defined(NEW_PCIB) && !defined(PCI_RES_BUS)
980149521Sjkim    /* Compaq R3000 BIOS sets wrong subordinate bus number. */
981149521Sjkim    case 0x00dd10de:
982149521Sjkim	{
983149521Sjkim	    char *cp;
984149521Sjkim
985273174Sdavide	    if ((cp = kern_getenv("smbios.planar.maker")) == NULL)
986149521Sjkim		break;
987157949Sjkim	    if (strncmp(cp, "Compal", 6) != 0) {
988157949Sjkim		freeenv(cp);
989149521Sjkim		break;
990157949Sjkim	    }
991157949Sjkim	    freeenv(cp);
992273174Sdavide	    if ((cp = kern_getenv("smbios.planar.product")) == NULL)
993157949Sjkim		break;
994157949Sjkim	    if (strncmp(cp, "08A0", 4) != 0) {
995157949Sjkim		freeenv(cp);
996157949Sjkim		break;
997157949Sjkim	    }
998157949Sjkim	    freeenv(cp);
999261790Sjhb	    if (sc->bus.sub < 0xa) {
1000149521Sjkim		pci_write_config(dev, PCIR_SUBBUS_1, 0xa, 1);
1001261790Sjhb		sc->bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1);
1002149521Sjkim	    }
1003149521Sjkim	    break;
1004149521Sjkim	}
1005261790Sjhb#endif
100669908Smsmith    }
100769908Smsmith
1008165995Sjhb    if (pci_msi_device_blacklisted(dev))
1009165995Sjhb	sc->flags |= PCIB_DISABLE_MSI;
1010165995Sjhb
1011253120Smarius    if (pci_msix_device_blacklisted(dev))
1012253120Smarius	sc->flags |= PCIB_DISABLE_MSIX;
1013253120Smarius
1014124365Simp    /*
1015124365Simp     * Intel 815, 845 and other chipsets say they are PCI-PCI bridges,
1016124365Simp     * but have a ProgIF of 0x80.  The 82801 family (AA, AB, BAM/CAM,
1017124365Simp     * BA/CA/DB and E) PCI bridges are HUB-PCI bridges, in Intelese.
1018124365Simp     * This means they act as if they were subtractively decoding
1019124365Simp     * bridges and pass all transactions.  Mark them and real ProgIf 1
1020124365Simp     * parts as subtractive.
1021124365Simp     */
1022124365Simp    if ((pci_get_devid(dev) & 0xff00ffff) == 0x24008086 ||
1023168157Sjhb      pci_read_config(dev, PCIR_PROGIF, 1) == PCIP_BRIDGE_PCI_SUBTRACTIVE)
1024124365Simp	sc->flags |= PCIB_SUBTRACTIVE;
1025221393Sjhb
1026221393Sjhb#ifdef NEW_PCIB
1027261790Sjhb#ifdef PCI_RES_BUS
1028261790Sjhb    pcib_setup_secbus(dev, &sc->bus, 1);
1029261790Sjhb#endif
1030221393Sjhb    pcib_probe_windows(sc);
1031221393Sjhb#endif
103269783Smsmith    if (bootverbose) {
1033172394Smarius	device_printf(dev, "  domain            %d\n", sc->domain);
1034261790Sjhb	device_printf(dev, "  secondary bus     %d\n", sc->bus.sec);
1035261790Sjhb	device_printf(dev, "  subordinate bus   %d\n", sc->bus.sub);
1036221393Sjhb#ifdef NEW_PCIB
1037221393Sjhb	if (pcib_is_window_open(&sc->io))
1038221393Sjhb	    device_printf(dev, "  I/O decode        0x%jx-0x%jx\n",
1039221393Sjhb	      (uintmax_t)sc->io.base, (uintmax_t)sc->io.limit);
1040221393Sjhb	if (pcib_is_window_open(&sc->mem))
1041221393Sjhb	    device_printf(dev, "  memory decode     0x%jx-0x%jx\n",
1042221393Sjhb	      (uintmax_t)sc->mem.base, (uintmax_t)sc->mem.limit);
1043221393Sjhb	if (pcib_is_window_open(&sc->pmem))
1044221393Sjhb	    device_printf(dev, "  prefetched decode 0x%jx-0x%jx\n",
1045221393Sjhb	      (uintmax_t)sc->pmem.base, (uintmax_t)sc->pmem.limit);
1046221393Sjhb#else
1047221393Sjhb	if (pcib_is_io_open(sc))
1048221393Sjhb	    device_printf(dev, "  I/O decode        0x%x-0x%x\n",
1049221393Sjhb	      sc->iobase, sc->iolimit);
1050163805Simp	if (pcib_is_nonprefetch_open(sc))
1051163805Simp	    device_printf(dev, "  memory decode     0x%jx-0x%jx\n",
1052163805Simp	      (uintmax_t)sc->membase, (uintmax_t)sc->memlimit);
1053163805Simp	if (pcib_is_prefetch_open(sc))
1054163805Simp	    device_printf(dev, "  prefetched decode 0x%jx-0x%jx\n",
1055163805Simp	      (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit);
1056221393Sjhb#endif
1057253450Sjhb	if (sc->bridgectl & (PCIB_BCR_ISA_ENABLE | PCIB_BCR_VGA_ENABLE) ||
1058253450Sjhb	    sc->flags & PCIB_SUBTRACTIVE) {
1059253450Sjhb		device_printf(dev, "  special decode    ");
1060253450Sjhb		comma = 0;
1061253450Sjhb		if (sc->bridgectl & PCIB_BCR_ISA_ENABLE) {
1062253450Sjhb			printf("ISA");
1063253450Sjhb			comma = 1;
1064253450Sjhb		}
1065253450Sjhb		if (sc->bridgectl & PCIB_BCR_VGA_ENABLE) {
1066253450Sjhb			printf("%sVGA", comma ? ", " : "");
1067253450Sjhb			comma = 1;
1068253450Sjhb		}
1069253450Sjhb		if (sc->flags & PCIB_SUBTRACTIVE)
1070253450Sjhb			printf("%ssubtractive", comma ? ", " : "");
1071253450Sjhb		printf("\n");
1072253450Sjhb	}
107369783Smsmith    }
107469783Smsmith
107569783Smsmith    /*
1076239103Sjhb     * Always enable busmastering on bridges so that transactions
1077239103Sjhb     * initiated on the secondary bus are passed through to the
1078239103Sjhb     * primary bus.
1079239103Sjhb     */
1080239103Sjhb    pci_enable_busmaster(dev);
1081102441Sjhb}
108269783Smsmith
1083103042Sjhbint
1084102441Sjhbpcib_attach(device_t dev)
1085102441Sjhb{
1086102441Sjhb    struct pcib_softc	*sc;
1087102441Sjhb    device_t		child;
1088102441Sjhb
1089102441Sjhb    pcib_attach_common(dev);
1090102441Sjhb    sc = device_get_softc(dev);
1091261790Sjhb    if (sc->bus.sec != 0) {
1092261790Sjhb	child = device_add_child(dev, "pci", sc->bus.sec);
109369783Smsmith	if (child != NULL)
109469783Smsmith	    return(bus_generic_attach(dev));
1095181798Simp    }
109669783Smsmith
109769783Smsmith    /* no secondary bus; we should have fixed this */
109869783Smsmith    return(0);
109969783Smsmith}
110069783Smsmith
1101102441Sjhbint
1102200341Sjkimpcib_suspend(device_t dev)
1103200341Sjkim{
1104211430Sjhb	device_t	pcib;
1105200341Sjkim	int		dstate, error;
1106200341Sjkim
1107200341Sjkim	pcib_cfg_save(device_get_softc(dev));
1108200341Sjkim	error = bus_generic_suspend(dev);
1109214110Sjkim	if (error == 0 && pci_do_power_suspend) {
1110211430Sjhb		dstate = PCI_POWERSTATE_D3;
1111211430Sjhb		pcib = device_get_parent(device_get_parent(dev));
1112211430Sjhb		if (PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0)
1113200341Sjkim			pci_set_powerstate(dev, dstate);
1114200341Sjkim	}
1115200341Sjkim	return (error);
1116200341Sjkim}
1117200341Sjkim
1118200341Sjkimint
1119200341Sjkimpcib_resume(device_t dev)
1120200341Sjkim{
1121211430Sjhb	device_t	pcib;
1122277710Sjhb	int dstate;
1123200341Sjkim
1124200341Sjkim	if (pci_do_power_resume) {
1125211430Sjhb		pcib = device_get_parent(device_get_parent(dev));
1126277710Sjhb		dstate = PCI_POWERSTATE_D0;
1127277710Sjhb		if (PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0)
1128277710Sjhb			pci_set_powerstate(dev, dstate);
1129200341Sjkim	}
1130200341Sjkim	pcib_cfg_restore(device_get_softc(dev));
1131200341Sjkim	return (bus_generic_resume(dev));
1132200341Sjkim}
1133200341Sjkim
1134200341Sjkimint
113569783Smsmithpcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
113669783Smsmith{
113769783Smsmith    struct pcib_softc	*sc = device_get_softc(dev);
113869783Smsmith
113969783Smsmith    switch (which) {
1140172394Smarius    case PCIB_IVAR_DOMAIN:
1141172394Smarius	*result = sc->domain;
1142172394Smarius	return(0);
114369783Smsmith    case PCIB_IVAR_BUS:
1144261790Sjhb	*result = sc->bus.sec;
114569783Smsmith	return(0);
114669783Smsmith    }
114769783Smsmith    return(ENOENT);
114869783Smsmith}
114969783Smsmith
1150102441Sjhbint
115169783Smsmithpcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
115269783Smsmith{
115369783Smsmith
115469783Smsmith    switch (which) {
1155172394Smarius    case PCIB_IVAR_DOMAIN:
1156172394Smarius	return(EINVAL);
115769783Smsmith    case PCIB_IVAR_BUS:
1158261790Sjhb	return(EINVAL);
115969783Smsmith    }
116069783Smsmith    return(ENOENT);
116169783Smsmith}
116269783Smsmith
1163221393Sjhb#ifdef NEW_PCIB
116469783Smsmith/*
1165221393Sjhb * Attempt to allocate a resource from the existing resources assigned
1166221393Sjhb * to a window.
1167221393Sjhb */
1168221393Sjhbstatic struct resource *
1169221393Sjhbpcib_suballoc_resource(struct pcib_softc *sc, struct pcib_window *w,
1170221393Sjhb    device_t child, int type, int *rid, u_long start, u_long end, u_long count,
1171221393Sjhb    u_int flags)
1172221393Sjhb{
1173221393Sjhb	struct resource *res;
1174221393Sjhb
1175221393Sjhb	if (!pcib_is_window_open(w))
1176221393Sjhb		return (NULL);
1177221393Sjhb
1178221393Sjhb	res = rman_reserve_resource(&w->rman, start, end, count,
1179221393Sjhb	    flags & ~RF_ACTIVE, child);
1180221393Sjhb	if (res == NULL)
1181221393Sjhb		return (NULL);
1182221393Sjhb
1183221393Sjhb	if (bootverbose)
1184221393Sjhb		device_printf(sc->dev,
1185221393Sjhb		    "allocated %s range (%#lx-%#lx) for rid %x of %s\n",
1186221393Sjhb		    w->name, rman_get_start(res), rman_get_end(res), *rid,
1187221393Sjhb		    pcib_child_name(child));
1188221393Sjhb	rman_set_rid(res, *rid);
1189221393Sjhb
1190221393Sjhb	/*
1191221393Sjhb	 * If the resource should be active, pass that request up the
1192221393Sjhb	 * tree.  This assumes the parent drivers can handle
1193221393Sjhb	 * activating sub-allocated resources.
1194221393Sjhb	 */
1195221393Sjhb	if (flags & RF_ACTIVE) {
1196221393Sjhb		if (bus_activate_resource(child, type, *rid, res) != 0) {
1197221393Sjhb			rman_release_resource(res);
1198221393Sjhb			return (NULL);
1199221393Sjhb		}
1200221393Sjhb	}
1201221393Sjhb
1202221393Sjhb	return (res);
1203221393Sjhb}
1204221393Sjhb
1205253450Sjhb/* Allocate a fresh resource range for an unconfigured window. */
1206253450Sjhbstatic int
1207253450Sjhbpcib_alloc_new_window(struct pcib_softc *sc, struct pcib_window *w, int type,
1208253450Sjhb    u_long start, u_long end, u_long count, u_int flags)
1209253450Sjhb{
1210253450Sjhb	struct resource *res;
1211253450Sjhb	u_long base, limit, wmask;
1212253450Sjhb	int rid;
1213253450Sjhb
1214253450Sjhb	/*
1215253450Sjhb	 * If this is an I/O window on a bridge with ISA enable set
1216253450Sjhb	 * and the start address is below 64k, then try to allocate an
1217253450Sjhb	 * initial window of 0x1000 bytes long starting at address
1218253450Sjhb	 * 0xf000 and walking down.  Note that if the original request
1219253450Sjhb	 * was larger than the non-aliased range size of 0x100 our
1220253450Sjhb	 * caller would have raised the start address up to 64k
1221253450Sjhb	 * already.
1222253450Sjhb	 */
1223253450Sjhb	if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE &&
1224253450Sjhb	    start < 65536) {
1225253450Sjhb		for (base = 0xf000; (long)base >= 0; base -= 0x1000) {
1226253450Sjhb			limit = base + 0xfff;
1227253450Sjhb
1228253450Sjhb			/*
1229253450Sjhb			 * Skip ranges that wouldn't work for the
1230253450Sjhb			 * original request.  Note that the actual
1231253450Sjhb			 * window that overlaps are the non-alias
1232253450Sjhb			 * ranges within [base, limit], so this isn't
1233253450Sjhb			 * quite a simple comparison.
1234253450Sjhb			 */
1235253450Sjhb			if (start + count > limit - 0x400)
1236253450Sjhb				continue;
1237253450Sjhb			if (base == 0) {
1238253450Sjhb				/*
1239253450Sjhb				 * The first open region for the window at
1240253450Sjhb				 * 0 is 0x400-0x4ff.
1241253450Sjhb				 */
1242253450Sjhb				if (end - count + 1 < 0x400)
1243253450Sjhb					continue;
1244253450Sjhb			} else {
1245253450Sjhb				if (end - count + 1 < base)
1246253450Sjhb					continue;
1247253450Sjhb			}
1248253450Sjhb
1249253450Sjhb			if (pcib_alloc_nonisa_ranges(sc, base, limit) == 0) {
1250253450Sjhb				w->base = base;
1251253450Sjhb				w->limit = limit;
1252253450Sjhb				return (0);
1253253450Sjhb			}
1254253450Sjhb		}
1255253450Sjhb		return (ENOSPC);
1256253450Sjhb	}
1257253450Sjhb
1258253450Sjhb	wmask = (1ul << w->step) - 1;
1259253450Sjhb	if (RF_ALIGNMENT(flags) < w->step) {
1260253450Sjhb		flags &= ~RF_ALIGNMENT_MASK;
1261253450Sjhb		flags |= RF_ALIGNMENT_LOG2(w->step);
1262253450Sjhb	}
1263253450Sjhb	start &= ~wmask;
1264253450Sjhb	end |= wmask;
1265253450Sjhb	count = roundup2(count, 1ul << w->step);
1266253450Sjhb	rid = w->reg;
1267253450Sjhb	res = bus_alloc_resource(sc->dev, type, &rid, start, end, count,
1268253450Sjhb	    flags & ~RF_ACTIVE);
1269253450Sjhb	if (res == NULL)
1270253450Sjhb		return (ENOSPC);
1271253450Sjhb	pcib_add_window_resources(w, &res, 1);
1272253450Sjhb	pcib_activate_window(sc, type);
1273253450Sjhb	w->base = rman_get_start(res);
1274253450Sjhb	w->limit = rman_get_end(res);
1275253450Sjhb	return (0);
1276253450Sjhb}
1277253450Sjhb
1278253450Sjhb/* Try to expand an existing window to the requested base and limit. */
1279253450Sjhbstatic int
1280253450Sjhbpcib_expand_window(struct pcib_softc *sc, struct pcib_window *w, int type,
1281253450Sjhb    u_long base, u_long limit)
1282253450Sjhb{
1283253450Sjhb	struct resource *res;
1284253450Sjhb	int error, i, force_64k_base;
1285253450Sjhb
1286253450Sjhb	KASSERT(base <= w->base && limit >= w->limit,
1287253450Sjhb	    ("attempting to shrink window"));
1288253450Sjhb
1289253450Sjhb	/*
1290253450Sjhb	 * XXX: pcib_grow_window() doesn't try to do this anyway and
1291253450Sjhb	 * the error handling for all the edge cases would be tedious.
1292253450Sjhb	 */
1293253450Sjhb	KASSERT(limit == w->limit || base == w->base,
1294253450Sjhb	    ("attempting to grow both ends of a window"));
1295253450Sjhb
1296253450Sjhb	/*
1297253450Sjhb	 * Yet more special handling for requests to expand an I/O
1298253450Sjhb	 * window behind an ISA-enabled bridge.  Since I/O windows
1299253450Sjhb	 * have to grow in 0x1000 increments and the end of the 0xffff
1300253450Sjhb	 * range is an alias, growing a window below 64k will always
1301253450Sjhb	 * result in allocating new resources and never adjusting an
1302253450Sjhb	 * existing resource.
1303253450Sjhb	 */
1304253450Sjhb	if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE &&
1305253450Sjhb	    (limit <= 65535 || (base <= 65535 && base != w->base))) {
1306253450Sjhb		KASSERT(limit == w->limit || limit <= 65535,
1307253450Sjhb		    ("attempting to grow both ends across 64k ISA alias"));
1308253450Sjhb
1309253450Sjhb		if (base != w->base)
1310253450Sjhb			error = pcib_alloc_nonisa_ranges(sc, base, w->base - 1);
1311253450Sjhb		else
1312253450Sjhb			error = pcib_alloc_nonisa_ranges(sc, w->limit + 1,
1313253450Sjhb			    limit);
1314253450Sjhb		if (error == 0) {
1315253450Sjhb			w->base = base;
1316253450Sjhb			w->limit = limit;
1317253450Sjhb		}
1318253450Sjhb		return (error);
1319253450Sjhb	}
1320253450Sjhb
1321253450Sjhb	/*
1322253450Sjhb	 * Find the existing resource to adjust.  Usually there is only one,
1323253450Sjhb	 * but for an ISA-enabled bridge we might be growing the I/O window
1324253450Sjhb	 * above 64k and need to find the existing resource that maps all
1325253450Sjhb	 * of the area above 64k.
1326253450Sjhb	 */
1327253450Sjhb	for (i = 0; i < w->count; i++) {
1328253450Sjhb		if (rman_get_end(w->res[i]) == w->limit)
1329253450Sjhb			break;
1330253450Sjhb	}
1331253450Sjhb	KASSERT(i != w->count, ("did not find existing resource"));
1332253450Sjhb	res = w->res[i];
1333253450Sjhb
1334253450Sjhb	/*
1335253450Sjhb	 * Usually the resource we found should match the window's
1336253450Sjhb	 * existing range.  The one exception is the ISA-enabled case
1337253450Sjhb	 * mentioned above in which case the resource should start at
1338253450Sjhb	 * 64k.
1339253450Sjhb	 */
1340253450Sjhb	if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE &&
1341253450Sjhb	    w->base <= 65535) {
1342253450Sjhb		KASSERT(rman_get_start(res) == 65536,
1343253450Sjhb		    ("existing resource mismatch"));
1344253450Sjhb		force_64k_base = 1;
1345253450Sjhb	} else {
1346253450Sjhb		KASSERT(w->base == rman_get_start(res),
1347253450Sjhb		    ("existing resource mismatch"));
1348253450Sjhb		force_64k_base = 0;
1349253450Sjhb	}
1350253450Sjhb
1351253450Sjhb	error = bus_adjust_resource(sc->dev, type, res, force_64k_base ?
1352253450Sjhb	    rman_get_start(res) : base, limit);
1353253450Sjhb	if (error)
1354253450Sjhb		return (error);
1355253450Sjhb
1356253450Sjhb	/* Add the newly allocated region to the resource manager. */
1357253450Sjhb	if (w->base != base) {
1358253450Sjhb		error = rman_manage_region(&w->rman, base, w->base - 1);
1359253450Sjhb		w->base = base;
1360253450Sjhb	} else {
1361253450Sjhb		error = rman_manage_region(&w->rman, w->limit + 1, limit);
1362253450Sjhb		w->limit = limit;
1363253450Sjhb	}
1364253450Sjhb	if (error) {
1365253450Sjhb		if (bootverbose)
1366253450Sjhb			device_printf(sc->dev,
1367253450Sjhb			    "failed to expand %s resource manager\n", w->name);
1368253450Sjhb		(void)bus_adjust_resource(sc->dev, type, res, force_64k_base ?
1369253450Sjhb		    rman_get_start(res) : w->base, w->limit);
1370253450Sjhb	}
1371253450Sjhb	return (error);
1372253450Sjhb}
1373253450Sjhb
1374221393Sjhb/*
1375221393Sjhb * Attempt to grow a window to make room for a given resource request.
1376221393Sjhb */
1377221393Sjhbstatic int
1378221393Sjhbpcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type,
1379221393Sjhb    u_long start, u_long end, u_long count, u_int flags)
1380221393Sjhb{
1381237272Sjhb	u_long align, start_free, end_free, front, back, wmask;
1382253450Sjhb	int error;
1383221393Sjhb
1384221393Sjhb	/*
1385221393Sjhb	 * Clamp the desired resource range to the maximum address
1386221393Sjhb	 * this window supports.  Reject impossible requests.
1387253450Sjhb	 *
1388253450Sjhb	 * For I/O port requests behind a bridge with the ISA enable
1389253450Sjhb	 * bit set, force large allocations to start above 64k.
1390221393Sjhb	 */
1391221393Sjhb	if (!w->valid)
1392221393Sjhb		return (EINVAL);
1393253450Sjhb	if (sc->bridgectl & PCIB_BCR_ISA_ENABLE && count > 0x100 &&
1394253450Sjhb	    start < 65536)
1395253450Sjhb		start = 65536;
1396221393Sjhb	if (end > w->rman.rm_end)
1397221393Sjhb		end = w->rman.rm_end;
1398221393Sjhb	if (start + count - 1 > end || start + count < start)
1399221393Sjhb		return (EINVAL);
1400237272Sjhb	wmask = (1ul << w->step) - 1;
1401221393Sjhb
1402221393Sjhb	/*
1403221393Sjhb	 * If there is no resource at all, just try to allocate enough
1404221393Sjhb	 * aligned space for this resource.
1405221393Sjhb	 */
1406221393Sjhb	if (w->res == NULL) {
1407253450Sjhb		error = pcib_alloc_new_window(sc, w, type, start, end, count,
1408253450Sjhb		    flags);
1409253450Sjhb		if (error) {
1410221393Sjhb			if (bootverbose)
1411221393Sjhb				device_printf(sc->dev,
1412221393Sjhb		    "failed to allocate initial %s window (%#lx-%#lx,%#lx)\n",
1413221393Sjhb				    w->name, start, end, count);
1414253450Sjhb			return (error);
1415221393Sjhb		}
1416221393Sjhb		if (bootverbose)
1417221393Sjhb			device_printf(sc->dev,
1418253450Sjhb			    "allocated initial %s window of %#jx-%#jx\n",
1419253450Sjhb			    w->name, (uintmax_t)w->base, (uintmax_t)w->limit);
1420221393Sjhb		goto updatewin;
1421221393Sjhb	}
1422221393Sjhb
1423221393Sjhb	/*
1424221393Sjhb	 * See if growing the window would help.  Compute the minimum
1425221393Sjhb	 * amount of address space needed on both the front and back
1426221393Sjhb	 * ends of the existing window to satisfy the allocation.
1427221393Sjhb	 *
1428221393Sjhb	 * For each end, build a candidate region adjusting for the
1429221393Sjhb	 * required alignment, etc.  If there is a free region at the
1430221393Sjhb	 * edge of the window, grow from the inner edge of the free
1431221393Sjhb	 * region.  Otherwise grow from the window boundary.
1432221393Sjhb	 *
1433253450Sjhb	 * Growing an I/O window below 64k for a bridge with the ISA
1434253450Sjhb	 * enable bit doesn't require any special magic as the step
1435253450Sjhb	 * size of an I/O window (1k) always includes multiple
1436253450Sjhb	 * non-alias ranges when it is grown in either direction.
1437253450Sjhb	 *
1438221393Sjhb	 * XXX: Special case: if w->res is completely empty and the
1439221393Sjhb	 * request size is larger than w->res, we should find the
1440221393Sjhb	 * optimal aligned buffer containing w->res and allocate that.
1441221393Sjhb	 */
1442221393Sjhb	if (bootverbose)
1443221393Sjhb		device_printf(sc->dev,
1444221393Sjhb		    "attempting to grow %s window for (%#lx-%#lx,%#lx)\n",
1445221393Sjhb		    w->name, start, end, count);
1446221393Sjhb	align = 1ul << RF_ALIGNMENT(flags);
1447253450Sjhb	if (start < w->base) {
1448221393Sjhb		if (rman_first_free_region(&w->rman, &start_free, &end_free) !=
1449253450Sjhb		    0 || start_free != w->base)
1450253450Sjhb			end_free = w->base;
1451221393Sjhb		if (end_free > end)
1452237008Sjhb			end_free = end + 1;
1453221393Sjhb
1454221393Sjhb		/* Move end_free down until it is properly aligned. */
1455221393Sjhb		end_free &= ~(align - 1);
1456222930Sjhb		end_free--;
1457222930Sjhb		front = end_free - (count - 1);
1458221393Sjhb
1459221393Sjhb		/*
1460221393Sjhb		 * The resource would now be allocated at (front,
1461221393Sjhb		 * end_free).  Ensure that fits in the (start, end)
1462221393Sjhb		 * bounds.  end_free is checked above.  If 'front' is
1463221393Sjhb		 * ok, ensure it is properly aligned for this window.
1464221393Sjhb		 * Also check for underflow.
1465221393Sjhb		 */
1466221393Sjhb		if (front >= start && front <= end_free) {
1467221393Sjhb			if (bootverbose)
1468221393Sjhb				printf("\tfront candidate range: %#lx-%#lx\n",
1469221393Sjhb				    front, end_free);
1470237272Sjhb			front &= ~wmask;
1471253450Sjhb			front = w->base - front;
1472221393Sjhb		} else
1473221393Sjhb			front = 0;
1474221393Sjhb	} else
1475221393Sjhb		front = 0;
1476253450Sjhb	if (end > w->limit) {
1477221393Sjhb		if (rman_last_free_region(&w->rman, &start_free, &end_free) !=
1478253450Sjhb		    0 || end_free != w->limit)
1479253450Sjhb			start_free = w->limit + 1;
1480221393Sjhb		if (start_free < start)
1481221393Sjhb			start_free = start;
1482221393Sjhb
1483221393Sjhb		/* Move start_free up until it is properly aligned. */
1484221393Sjhb		start_free = roundup2(start_free, align);
1485222930Sjhb		back = start_free + count - 1;
1486221393Sjhb
1487221393Sjhb		/*
1488221393Sjhb		 * The resource would now be allocated at (start_free,
1489221393Sjhb		 * back).  Ensure that fits in the (start, end)
1490221393Sjhb		 * bounds.  start_free is checked above.  If 'back' is
1491221393Sjhb		 * ok, ensure it is properly aligned for this window.
1492221393Sjhb		 * Also check for overflow.
1493221393Sjhb		 */
1494221393Sjhb		if (back <= end && start_free <= back) {
1495221393Sjhb			if (bootverbose)
1496221393Sjhb				printf("\tback candidate range: %#lx-%#lx\n",
1497221393Sjhb				    start_free, back);
1498237272Sjhb			back |= wmask;
1499253450Sjhb			back -= w->limit;
1500221393Sjhb		} else
1501221393Sjhb			back = 0;
1502221393Sjhb	} else
1503221393Sjhb		back = 0;
1504221393Sjhb
1505221393Sjhb	/*
1506221393Sjhb	 * Try to allocate the smallest needed region first.
1507221393Sjhb	 * If that fails, fall back to the other region.
1508221393Sjhb	 */
1509221393Sjhb	error = ENOSPC;
1510221393Sjhb	while (front != 0 || back != 0) {
1511221393Sjhb		if (front != 0 && (front <= back || back == 0)) {
1512253450Sjhb			error = pcib_expand_window(sc, w, type, w->base - front,
1513253450Sjhb			    w->limit);
1514221393Sjhb			if (error == 0)
1515221393Sjhb				break;
1516221393Sjhb			front = 0;
1517221393Sjhb		} else {
1518253450Sjhb			error = pcib_expand_window(sc, w, type, w->base,
1519253450Sjhb			    w->limit + back);
1520221393Sjhb			if (error == 0)
1521221393Sjhb				break;
1522221393Sjhb			back = 0;
1523221393Sjhb		}
1524221393Sjhb	}
1525221393Sjhb
1526221393Sjhb	if (error)
1527221393Sjhb		return (error);
1528221393Sjhb	if (bootverbose)
1529253450Sjhb		device_printf(sc->dev, "grew %s window to %#jx-%#jx\n",
1530253450Sjhb		    w->name, (uintmax_t)w->base, (uintmax_t)w->limit);
1531221393Sjhb
1532221393Sjhbupdatewin:
1533253450Sjhb	/* Write the new window. */
1534237272Sjhb	KASSERT((w->base & wmask) == 0, ("start address is not aligned"));
1535237272Sjhb	KASSERT((w->limit & wmask) == wmask, ("end address is not aligned"));
1536221393Sjhb	pcib_write_windows(sc, w->mask);
1537221393Sjhb	return (0);
1538221393Sjhb}
1539221393Sjhb
1540221393Sjhb/*
154169783Smsmith * We have to trap resource allocation requests and ensure that the bridge
154269783Smsmith * is set up to, or capable of handling them.
154369783Smsmith */
1544102441Sjhbstruct resource *
1545221393Sjhbpcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
1546221393Sjhb    u_long start, u_long end, u_long count, u_int flags)
1547221393Sjhb{
1548221393Sjhb	struct pcib_softc *sc;
1549221393Sjhb	struct resource *r;
1550221393Sjhb
1551221393Sjhb	sc = device_get_softc(dev);
1552221393Sjhb
1553221393Sjhb	/*
1554221393Sjhb	 * VGA resources are decoded iff the VGA enable bit is set in
1555221393Sjhb	 * the bridge control register.  VGA resources do not fall into
1556221393Sjhb	 * the resource windows and are passed up to the parent.
1557221393Sjhb	 */
1558221393Sjhb	if ((type == SYS_RES_IOPORT && pci_is_vga_ioport_range(start, end)) ||
1559221393Sjhb	    (type == SYS_RES_MEMORY && pci_is_vga_memory_range(start, end))) {
1560221393Sjhb		if (sc->bridgectl & PCIB_BCR_VGA_ENABLE)
1561221393Sjhb			return (bus_generic_alloc_resource(dev, child, type,
1562221393Sjhb			    rid, start, end, count, flags));
1563221393Sjhb		else
1564221393Sjhb			return (NULL);
1565221393Sjhb	}
1566221393Sjhb
1567221393Sjhb	switch (type) {
1568261790Sjhb#ifdef PCI_RES_BUS
1569261790Sjhb	case PCI_RES_BUS:
1570261790Sjhb		return (pcib_alloc_subbus(&sc->bus, child, rid, start, end,
1571261790Sjhb		    count, flags));
1572261790Sjhb#endif
1573221393Sjhb	case SYS_RES_IOPORT:
1574253450Sjhb		if (pcib_is_isa_range(sc, start, end, count))
1575253450Sjhb			return (NULL);
1576221393Sjhb		r = pcib_suballoc_resource(sc, &sc->io, child, type, rid, start,
1577221393Sjhb		    end, count, flags);
1578237673Smarius		if (r != NULL || (sc->flags & PCIB_SUBTRACTIVE) != 0)
1579221393Sjhb			break;
1580221393Sjhb		if (pcib_grow_window(sc, &sc->io, type, start, end, count,
1581221393Sjhb		    flags) == 0)
1582221393Sjhb			r = pcib_suballoc_resource(sc, &sc->io, child, type,
1583221393Sjhb			    rid, start, end, count, flags);
1584221393Sjhb		break;
1585221393Sjhb	case SYS_RES_MEMORY:
1586221393Sjhb		/*
1587221393Sjhb		 * For prefetchable resources, prefer the prefetchable
1588221393Sjhb		 * memory window, but fall back to the regular memory
1589221393Sjhb		 * window if that fails.  Try both windows before
1590221393Sjhb		 * attempting to grow a window in case the firmware
1591221393Sjhb		 * has used a range in the regular memory window to
1592221393Sjhb		 * map a prefetchable BAR.
1593221393Sjhb		 */
1594221393Sjhb		if (flags & RF_PREFETCHABLE) {
1595221393Sjhb			r = pcib_suballoc_resource(sc, &sc->pmem, child, type,
1596221393Sjhb			    rid, start, end, count, flags);
1597221393Sjhb			if (r != NULL)
1598221393Sjhb				break;
1599221393Sjhb		}
1600221393Sjhb		r = pcib_suballoc_resource(sc, &sc->mem, child, type, rid,
1601221393Sjhb		    start, end, count, flags);
1602237673Smarius		if (r != NULL || (sc->flags & PCIB_SUBTRACTIVE) != 0)
1603221393Sjhb			break;
1604221393Sjhb		if (flags & RF_PREFETCHABLE) {
1605221393Sjhb			if (pcib_grow_window(sc, &sc->pmem, type, start, end,
1606221393Sjhb			    count, flags) == 0) {
1607221393Sjhb				r = pcib_suballoc_resource(sc, &sc->pmem, child,
1608221393Sjhb				    type, rid, start, end, count, flags);
1609221393Sjhb				if (r != NULL)
1610221393Sjhb					break;
1611221393Sjhb			}
1612221393Sjhb		}
1613221393Sjhb		if (pcib_grow_window(sc, &sc->mem, type, start, end, count,
1614221393Sjhb		    flags & ~RF_PREFETCHABLE) == 0)
1615221393Sjhb			r = pcib_suballoc_resource(sc, &sc->mem, child, type,
1616221393Sjhb			    rid, start, end, count, flags);
1617221393Sjhb		break;
1618221393Sjhb	default:
1619221393Sjhb		return (bus_generic_alloc_resource(dev, child, type, rid,
1620221393Sjhb		    start, end, count, flags));
1621221393Sjhb	}
1622221393Sjhb
1623221393Sjhb	/*
1624221393Sjhb	 * If attempts to suballocate from the window fail but this is a
1625221393Sjhb	 * subtractive bridge, pass the request up the tree.
1626221393Sjhb	 */
1627221393Sjhb	if (sc->flags & PCIB_SUBTRACTIVE && r == NULL)
1628221393Sjhb		return (bus_generic_alloc_resource(dev, child, type, rid,
1629221393Sjhb		    start, end, count, flags));
1630221393Sjhb	return (r);
1631221393Sjhb}
1632221393Sjhb
1633221393Sjhbint
1634221393Sjhbpcib_adjust_resource(device_t bus, device_t child, int type, struct resource *r,
1635221393Sjhb    u_long start, u_long end)
1636221393Sjhb{
1637221393Sjhb	struct pcib_softc *sc;
1638221393Sjhb
1639221393Sjhb	sc = device_get_softc(bus);
1640221393Sjhb	if (pcib_is_resource_managed(sc, type, r))
1641221393Sjhb		return (rman_adjust_resource(r, start, end));
1642221393Sjhb	return (bus_generic_adjust_resource(bus, child, type, r, start, end));
1643221393Sjhb}
1644221393Sjhb
1645221393Sjhbint
1646221393Sjhbpcib_release_resource(device_t dev, device_t child, int type, int rid,
1647221393Sjhb    struct resource *r)
1648221393Sjhb{
1649221393Sjhb	struct pcib_softc *sc;
1650221393Sjhb	int error;
1651221393Sjhb
1652221393Sjhb	sc = device_get_softc(dev);
1653221393Sjhb	if (pcib_is_resource_managed(sc, type, r)) {
1654221393Sjhb		if (rman_get_flags(r) & RF_ACTIVE) {
1655221393Sjhb			error = bus_deactivate_resource(child, type, rid, r);
1656221393Sjhb			if (error)
1657221393Sjhb				return (error);
1658221393Sjhb		}
1659221393Sjhb		return (rman_release_resource(r));
1660221393Sjhb	}
1661221393Sjhb	return (bus_generic_release_resource(dev, child, type, rid, r));
1662221393Sjhb}
1663221393Sjhb#else
1664221393Sjhb/*
1665221393Sjhb * We have to trap resource allocation requests and ensure that the bridge
1666221393Sjhb * is set up to, or capable of handling them.
1667221393Sjhb */
1668221393Sjhbstruct resource *
166969783Smsmithpcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
1670142051Simp    u_long start, u_long end, u_long count, u_int flags)
167169783Smsmith{
1672124365Simp	struct pcib_softc	*sc = device_get_softc(dev);
1673164130Sjhb	const char *name, *suffix;
1674124365Simp	int ok;
167569783Smsmith
167669783Smsmith	/*
167769783Smsmith	 * Fail the allocation for this range if it's not supported.
167869783Smsmith	 */
1679164130Sjhb	name = device_get_nameunit(child);
1680164130Sjhb	if (name == NULL) {
1681164130Sjhb		name = "";
1682164130Sjhb		suffix = "";
1683164130Sjhb	} else
1684164130Sjhb		suffix = " ";
168569783Smsmith	switch (type) {
168669783Smsmith	case SYS_RES_IOPORT:
1687107546Simp		ok = 0;
1688124365Simp		if (!pcib_is_io_open(sc))
1689124365Simp			break;
1690124365Simp		ok = (start >= sc->iobase && end <= sc->iolimit);
1691145652Smarcel
1692145652Smarcel		/*
1693145652Smarcel		 * Make sure we allow access to VGA I/O addresses when the
1694145652Smarcel		 * bridge has the "VGA Enable" bit set.
1695145652Smarcel		 */
1696145652Smarcel		if (!ok && pci_is_vga_ioport_range(start, end))
1697145652Smarcel			ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0;
1698145652Smarcel
1699124365Simp		if ((sc->flags & PCIB_SUBTRACTIVE) == 0) {
1700124365Simp			if (!ok) {
1701124365Simp				if (start < sc->iobase)
1702124365Simp					start = sc->iobase;
1703124365Simp				if (end > sc->iolimit)
1704124365Simp					end = sc->iolimit;
1705142051Simp				if (start < end)
1706142051Simp					ok = 1;
1707124365Simp			}
1708106844Smdodd		} else {
1709124365Simp			ok = 1;
1710189844Simp#if 0
1711189792Simp			/*
1712189792Simp			 * If we overlap with the subtractive range, then
1713189792Simp			 * pick the upper range to use.
1714189792Simp			 */
1715189792Simp			if (start < sc->iolimit && end > sc->iobase)
1716189792Simp				start = sc->iolimit + 1;
1717189844Simp#endif
1718106844Smdodd		}
1719124365Simp		if (end < start) {
1720142051Simp			device_printf(dev, "ioport: end (%lx) < start (%lx)\n",
1721142051Simp			    end, start);
1722124365Simp			start = 0;
1723124365Simp			end = 0;
1724124365Simp			ok = 0;
1725124365Simp		}
1726124365Simp		if (!ok) {
1727164130Sjhb			device_printf(dev, "%s%srequested unsupported I/O "
1728124365Simp			    "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n",
1729164130Sjhb			    name, suffix, start, end, sc->iobase, sc->iolimit);
1730124365Simp			return (NULL);
1731124365Simp		}
1732124365Simp		if (bootverbose)
1733142051Simp			device_printf(dev,
1734164130Sjhb			    "%s%srequested I/O range 0x%lx-0x%lx: in range\n",
1735164130Sjhb			    name, suffix, start, end);
1736124365Simp		break;
173769783Smsmith
173869783Smsmith	case SYS_RES_MEMORY:
1739107546Simp		ok = 0;
1740107546Simp		if (pcib_is_nonprefetch_open(sc))
1741124365Simp			ok = ok || (start >= sc->membase && end <= sc->memlimit);
1742107546Simp		if (pcib_is_prefetch_open(sc))
1743124365Simp			ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit);
1744145652Smarcel
1745145652Smarcel		/*
1746145652Smarcel		 * Make sure we allow access to VGA memory addresses when the
1747145652Smarcel		 * bridge has the "VGA Enable" bit set.
1748145652Smarcel		 */
1749145652Smarcel		if (!ok && pci_is_vga_memory_range(start, end))
1750145652Smarcel			ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0;
1751145652Smarcel
1752124365Simp		if ((sc->flags & PCIB_SUBTRACTIVE) == 0) {
1753124365Simp			if (!ok) {
1754124365Simp				ok = 1;
1755124365Simp				if (flags & RF_PREFETCHABLE) {
1756124365Simp					if (pcib_is_prefetch_open(sc)) {
1757124365Simp						if (start < sc->pmembase)
1758124365Simp							start = sc->pmembase;
1759124365Simp						if (end > sc->pmemlimit)
1760124365Simp							end = sc->pmemlimit;
1761124365Simp					} else {
1762124365Simp						ok = 0;
1763124365Simp					}
1764124365Simp				} else {	/* non-prefetchable */
1765124365Simp					if (pcib_is_nonprefetch_open(sc)) {
1766124365Simp						if (start < sc->membase)
1767124365Simp							start = sc->membase;
1768124365Simp						if (end > sc->memlimit)
1769124365Simp							end = sc->memlimit;
1770124365Simp					} else {
1771124365Simp						ok = 0;
1772124365Simp					}
1773124365Simp				}
1774107546Simp			}
1775107546Simp		} else if (!ok) {
1776124365Simp			ok = 1;	/* subtractive bridge: always ok */
1777189844Simp#if 0
1778124365Simp			if (pcib_is_nonprefetch_open(sc)) {
1779189792Simp				if (start < sc->memlimit && end > sc->membase)
1780189792Simp					start = sc->memlimit + 1;
1781124365Simp			}
1782124365Simp			if (pcib_is_prefetch_open(sc)) {
1783189792Simp				if (start < sc->pmemlimit && end > sc->pmembase)
1784189792Simp					start = sc->pmemlimit + 1;
1785124365Simp			}
1786189844Simp#endif
1787106844Smdodd		}
1788124365Simp		if (end < start) {
1789142051Simp			device_printf(dev, "memory: end (%lx) < start (%lx)\n",
1790142051Simp			    end, start);
1791124365Simp			start = 0;
1792124365Simp			end = 0;
1793124365Simp			ok = 0;
1794124365Simp		}
1795124365Simp		if (!ok && bootverbose)
1796124365Simp			device_printf(dev,
1797164130Sjhb			    "%s%srequested unsupported memory range %#lx-%#lx "
1798163805Simp			    "(decoding %#jx-%#jx, %#jx-%#jx)\n",
1799164130Sjhb			    name, suffix, start, end,
1800163805Simp			    (uintmax_t)sc->membase, (uintmax_t)sc->memlimit,
1801163805Simp			    (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit);
1802124365Simp		if (!ok)
1803124365Simp			return (NULL);
1804124365Simp		if (bootverbose)
1805164130Sjhb			device_printf(dev,"%s%srequested memory range "
1806142051Simp			    "0x%lx-0x%lx: good\n",
1807164130Sjhb			    name, suffix, start, end);
1808124365Simp		break;
180969908Smsmith
181069783Smsmith	default:
1811124365Simp		break;
181269783Smsmith	}
1813124365Simp	/*
1814124365Simp	 * Bridge is OK decoding this resource, so pass it up.
1815124365Simp	 */
1816142051Simp	return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
1817142051Simp	    count, flags));
181869783Smsmith}
1819221393Sjhb#endif
182069783Smsmith
182169783Smsmith/*
1822264011Srstone * If ARI is enabled on this downstream port, translate the function number
1823264011Srstone * to the non-ARI slot/function.  The downstream port will convert it back in
1824264011Srstone * hardware.  If ARI is not enabled slot and func are not modified.
1825264011Srstone */
1826264011Srstonestatic __inline void
1827264011Srstonepcib_xlate_ari(device_t pcib, int bus, int *slot, int *func)
1828264011Srstone{
1829264011Srstone	struct pcib_softc *sc;
1830264011Srstone	int ari_func;
1831264011Srstone
1832264011Srstone	sc = device_get_softc(pcib);
1833264011Srstone	ari_func = *func;
1834264011Srstone
1835264011Srstone	if (sc->flags & PCIB_ENABLE_ARI) {
1836264011Srstone		KASSERT(*slot == 0,
1837264011Srstone		    ("Non-zero slot number with ARI enabled!"));
1838264011Srstone		*slot = PCIE_ARI_SLOT(ari_func);
1839264011Srstone		*func = PCIE_ARI_FUNC(ari_func);
1840264011Srstone	}
1841264011Srstone}
1842264011Srstone
1843264011Srstone
1844264011Srstonestatic void
1845264011Srstonepcib_enable_ari(struct pcib_softc *sc, uint32_t pcie_pos)
1846264011Srstone{
1847264011Srstone	uint32_t ctl2;
1848264011Srstone
1849264011Srstone	ctl2 = pci_read_config(sc->dev, pcie_pos + PCIER_DEVICE_CTL2, 4);
1850264011Srstone	ctl2 |= PCIEM_CTL2_ARI;
1851264011Srstone	pci_write_config(sc->dev, pcie_pos + PCIER_DEVICE_CTL2, ctl2, 4);
1852264011Srstone
1853264011Srstone	sc->flags |= PCIB_ENABLE_ARI;
1854264011Srstone}
1855264011Srstone
1856264011Srstone/*
185769783Smsmith * PCIB interface.
185869783Smsmith */
1859102441Sjhbint
186069783Smsmithpcib_maxslots(device_t dev)
186169783Smsmith{
1862264011Srstone	return (PCI_SLOTMAX);
186369783Smsmith}
186469783Smsmith
1865264011Srstonestatic int
1866264011Srstonepcib_ari_maxslots(device_t dev)
1867264011Srstone{
1868264011Srstone	struct pcib_softc *sc;
1869264011Srstone
1870264011Srstone	sc = device_get_softc(dev);
1871264011Srstone
1872264011Srstone	if (sc->flags & PCIB_ENABLE_ARI)
1873264011Srstone		return (PCIE_ARI_SLOTMAX);
1874264011Srstone	else
1875264011Srstone		return (PCI_SLOTMAX);
1876264011Srstone}
1877264011Srstone
1878264011Srstonestatic int
1879264011Srstonepcib_ari_maxfuncs(device_t dev)
1880264011Srstone{
1881264011Srstone	struct pcib_softc *sc;
1882264011Srstone
1883264011Srstone	sc = device_get_softc(dev);
1884264011Srstone
1885264011Srstone	if (sc->flags & PCIB_ENABLE_ARI)
1886264011Srstone		return (PCIE_ARI_FUNCMAX);
1887264011Srstone	else
1888264011Srstone		return (PCI_FUNCMAX);
1889264011Srstone}
1890264011Srstone
1891279443Srstonestatic void
1892279443Srstonepcib_ari_decode_rid(device_t pcib, uint16_t rid, int *bus, int *slot,
1893279443Srstone    int *func)
1894279443Srstone{
1895279443Srstone	struct pcib_softc *sc;
1896279443Srstone
1897279443Srstone	sc = device_get_softc(pcib);
1898279443Srstone
1899279443Srstone	*bus = PCI_RID2BUS(rid);
1900279443Srstone	if (sc->flags & PCIB_ENABLE_ARI) {
1901279443Srstone		*slot = PCIE_ARI_RID2SLOT(rid);
1902279443Srstone		*func = PCIE_ARI_RID2FUNC(rid);
1903279443Srstone	} else {
1904279443Srstone		*slot = PCI_RID2SLOT(rid);
1905279443Srstone		*func = PCI_RID2FUNC(rid);
1906279443Srstone	}
1907279443Srstone}
1908279443Srstone
190969783Smsmith/*
191069783Smsmith * Since we are a child of a PCI bus, its parent must support the pcib interface.
191169783Smsmith */
1912264011Srstonestatic uint32_t
1913189792Simppcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width)
191469783Smsmith{
1915264011Srstone
1916264011Srstone	pcib_xlate_ari(dev, b, &s, &f);
1917264011Srstone	return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s,
1918264011Srstone	    f, reg, width));
191969783Smsmith}
192069783Smsmith
1921264011Srstonestatic void
1922189792Simppcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, int width)
192369783Smsmith{
1924264011Srstone
1925264011Srstone	pcib_xlate_ari(dev, b, &s, &f);
1926264011Srstone	PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f,
1927264011Srstone	    reg, val, width);
192869783Smsmith}
192969783Smsmith
193069783Smsmith/*
193169783Smsmith * Route an interrupt across a PCI bridge.
193269783Smsmith */
1933109229Sbennoint
193469783Smsmithpcib_route_interrupt(device_t pcib, device_t dev, int pin)
193569783Smsmith{
193669783Smsmith    device_t	bus;
193769783Smsmith    int		parent_intpin;
193869783Smsmith    int		intnum;
193969783Smsmith
194069783Smsmith    /*
194169783Smsmith     *
194269783Smsmith     * The PCI standard defines a swizzle of the child-side device/intpin to
194369783Smsmith     * the parent-side intpin as follows.
194469783Smsmith     *
194569783Smsmith     * device = device on child bus
194669783Smsmith     * child_intpin = intpin on child bus slot (0-3)
194769783Smsmith     * parent_intpin = intpin on parent bus slot (0-3)
194869783Smsmith     *
194969783Smsmith     * parent_intpin = (device + child_intpin) % 4
195069783Smsmith     */
1951115234Sticso    parent_intpin = (pci_get_slot(dev) + (pin - 1)) % 4;
195269783Smsmith
195369783Smsmith    /*
195469783Smsmith     * Our parent is a PCI bus.  Its parent must export the pcib interface
195569783Smsmith     * which includes the ability to route interrupts.
195669783Smsmith     */
195769783Smsmith    bus = device_get_parent(pcib);
195869783Smsmith    intnum = PCIB_ROUTE_INTERRUPT(device_get_parent(bus), pcib, parent_intpin + 1);
1959131398Sjhb    if (PCI_INTERRUPT_VALID(intnum) && bootverbose) {
1960102977Sjhb	device_printf(pcib, "slot %d INT%c is routed to irq %d\n",
1961102977Sjhb	    pci_get_slot(dev), 'A' + pin - 1, intnum);
196290554Smsmith    }
196369783Smsmith    return(intnum);
196469783Smsmith}
1965107172Sjhb
1966169221Sjhb/* Pass request to alloc MSI/MSI-X messages up to the parent bridge. */
1967164264Sjhbint
1968164264Sjhbpcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs)
1969164264Sjhb{
1970169902Sgallatin	struct pcib_softc *sc = device_get_softc(pcib);
1971164264Sjhb	device_t bus;
1972164264Sjhb
1973165995Sjhb	if (sc->flags & PCIB_DISABLE_MSI)
1974165995Sjhb		return (ENXIO);
1975164264Sjhb	bus = device_get_parent(pcib);
1976164264Sjhb	return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount,
1977164264Sjhb	    irqs));
1978164264Sjhb}
1979164264Sjhb
1980169221Sjhb/* Pass request to release MSI/MSI-X messages up to the parent bridge. */
1981164264Sjhbint
1982164264Sjhbpcib_release_msi(device_t pcib, device_t dev, int count, int *irqs)
1983164264Sjhb{
1984164264Sjhb	device_t bus;
1985164264Sjhb
1986164264Sjhb	bus = device_get_parent(pcib);
1987164264Sjhb	return (PCIB_RELEASE_MSI(device_get_parent(bus), dev, count, irqs));
1988164264Sjhb}
1989164264Sjhb
1990164264Sjhb/* Pass request to alloc an MSI-X message up to the parent bridge. */
1991164264Sjhbint
1992169221Sjhbpcib_alloc_msix(device_t pcib, device_t dev, int *irq)
1993164264Sjhb{
1994169902Sgallatin	struct pcib_softc *sc = device_get_softc(pcib);
1995164264Sjhb	device_t bus;
1996164264Sjhb
1997253120Smarius	if (sc->flags & PCIB_DISABLE_MSIX)
1998165995Sjhb		return (ENXIO);
1999164264Sjhb	bus = device_get_parent(pcib);
2000169221Sjhb	return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq));
2001164264Sjhb}
2002164264Sjhb
2003169221Sjhb/* Pass request to release an MSI-X message up to the parent bridge. */
2004166176Sjhbint
2005169221Sjhbpcib_release_msix(device_t pcib, device_t dev, int irq)
2006166176Sjhb{
2007166176Sjhb	device_t bus;
2008166176Sjhb
2009166176Sjhb	bus = device_get_parent(pcib);
2010169221Sjhb	return (PCIB_RELEASE_MSIX(device_get_parent(bus), dev, irq));
2011166176Sjhb}
2012166176Sjhb
2013169221Sjhb/* Pass request to map MSI/MSI-X message up to parent bridge. */
2014164264Sjhbint
2015169221Sjhbpcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr,
2016169221Sjhb    uint32_t *data)
2017164264Sjhb{
2018164264Sjhb	device_t bus;
2019180753Sluoqi	int error;
2020164264Sjhb
2021164264Sjhb	bus = device_get_parent(pcib);
2022180753Sluoqi	error = PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data);
2023180753Sluoqi	if (error)
2024180753Sluoqi		return (error);
2025180753Sluoqi
2026180753Sluoqi	pci_ht_map_msi(pcib, *addr);
2027180753Sluoqi	return (0);
2028164264Sjhb}
2029164264Sjhb
2030211430Sjhb/* Pass request for device power state up to parent bridge. */
2031211430Sjhbint
2032211430Sjhbpcib_power_for_sleep(device_t pcib, device_t dev, int *pstate)
2033211430Sjhb{
2034211430Sjhb	device_t bus;
2035211430Sjhb
2036211430Sjhb	bus = device_get_parent(pcib);
2037211430Sjhb	return (PCIB_POWER_FOR_SLEEP(bus, dev, pstate));
2038211430Sjhb}
2039264007Srstone
2040279443Srstonestatic int
2041279443Srstonepcib_ari_enabled(device_t pcib)
2042279443Srstone{
2043279443Srstone	struct pcib_softc *sc;
2044279443Srstone
2045279443Srstone	sc = device_get_softc(pcib);
2046279443Srstone
2047279443Srstone	return ((sc->flags & PCIB_ENABLE_ARI) != 0);
2048279443Srstone}
2049279443Srstone
2050264011Srstonestatic uint16_t
2051264011Srstonepcib_ari_get_rid(device_t pcib, device_t dev)
2052264011Srstone{
2053264011Srstone	struct pcib_softc *sc;
2054264011Srstone	uint8_t bus, slot, func;
2055264011Srstone
2056264011Srstone	sc = device_get_softc(pcib);
2057264011Srstone
2058264011Srstone	if (sc->flags & PCIB_ENABLE_ARI) {
2059264011Srstone		bus = pci_get_bus(dev);
2060264011Srstone		func = pci_get_function(dev);
2061264011Srstone
2062264011Srstone		return (PCI_ARI_RID(bus, func));
2063264011Srstone	} else {
2064264011Srstone		bus = pci_get_bus(dev);
2065264011Srstone		slot = pci_get_slot(dev);
2066264011Srstone		func = pci_get_function(dev);
2067264011Srstone
2068264011Srstone		return (PCI_RID(bus, slot, func));
2069264011Srstone	}
2070264011Srstone}
2071264011Srstone
2072264011Srstone/*
2073264011Srstone * Check that the downstream port (pcib) and the endpoint device (dev) both
2074264011Srstone * support ARI.  If so, enable it and return 0, otherwise return an error.
2075264011Srstone */
2076264011Srstonestatic int
2077264011Srstonepcib_try_enable_ari(device_t pcib, device_t dev)
2078264011Srstone{
2079264011Srstone	struct pcib_softc *sc;
2080264011Srstone	int error;
2081264011Srstone	uint32_t cap2;
2082264011Srstone	int ari_cap_off;
2083264011Srstone	uint32_t ari_ver;
2084264011Srstone	uint32_t pcie_pos;
2085264011Srstone
2086264011Srstone	sc = device_get_softc(pcib);
2087264011Srstone
2088264011Srstone	/*
2089264011Srstone	 * ARI is controlled in a register in the PCIe capability structure.
2090264011Srstone	 * If the downstream port does not have the PCIe capability structure
2091264011Srstone	 * then it does not support ARI.
2092264011Srstone	 */
2093264011Srstone	error = pci_find_cap(pcib, PCIY_EXPRESS, &pcie_pos);
2094264011Srstone	if (error != 0)
2095264011Srstone		return (ENODEV);
2096264011Srstone
2097264011Srstone	/* Check that the PCIe port advertises ARI support. */
2098264011Srstone	cap2 = pci_read_config(pcib, pcie_pos + PCIER_DEVICE_CAP2, 4);
2099264011Srstone	if (!(cap2 & PCIEM_CAP2_ARI))
2100264011Srstone		return (ENODEV);
2101264011Srstone
2102264011Srstone	/*
2103264011Srstone	 * Check that the endpoint device advertises ARI support via the ARI
2104264011Srstone	 * extended capability structure.
2105264011Srstone	 */
2106264011Srstone	error = pci_find_extcap(dev, PCIZ_ARI, &ari_cap_off);
2107264011Srstone	if (error != 0)
2108264011Srstone		return (ENODEV);
2109264011Srstone
2110264011Srstone	/*
2111264011Srstone	 * Finally, check that the endpoint device supports the same version
2112264011Srstone	 * of ARI that we do.
2113264011Srstone	 */
2114264011Srstone	ari_ver = pci_read_config(dev, ari_cap_off, 4);
2115264011Srstone	if (PCI_EXTCAP_VER(ari_ver) != PCIB_SUPPORTED_ARI_VER) {
2116264011Srstone		if (bootverbose)
2117264011Srstone			device_printf(pcib,
2118264011Srstone			    "Unsupported version of ARI (%d) detected\n",
2119264011Srstone			    PCI_EXTCAP_VER(ari_ver));
2120264011Srstone
2121264011Srstone		return (ENXIO);
2122264011Srstone	}
2123264011Srstone
2124264011Srstone	pcib_enable_ari(sc, pcie_pos);
2125264011Srstone
2126264011Srstone	return (0);
2127264011Srstone}
2128264011Srstone
2129