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: releng/11.0/sys/dev/pci/pci_pci.c 314125 2017-02-23 07:11:48Z delphij $");
33119418Sobrien
3469783Smsmith/*
3569783Smsmith * PCI:PCI bridge support.
3669783Smsmith */
3769783Smsmith
38299142Sjhb#include "opt_pci.h"
39299142Sjhb
4069783Smsmith#include <sys/param.h>
41221393Sjhb#include <sys/bus.h>
4269783Smsmith#include <sys/kernel.h>
43221393Sjhb#include <sys/malloc.h>
44129876Sphk#include <sys/module.h>
45107546Simp#include <sys/rman.h>
46106844Smdodd#include <sys/sysctl.h>
47221393Sjhb#include <sys/systm.h>
48299142Sjhb#include <sys/taskqueue.h>
4969783Smsmith
50119285Simp#include <dev/pci/pcivar.h>
51119285Simp#include <dev/pci/pcireg.h>
52211430Sjhb#include <dev/pci/pci_private.h>
53119285Simp#include <dev/pci/pcib_private.h>
5469783Smsmith
5569783Smsmith#include "pcib_if.h"
5669783Smsmith
5769783Smsmithstatic int		pcib_probe(device_t dev);
58200341Sjkimstatic int		pcib_suspend(device_t dev);
59200341Sjkimstatic int		pcib_resume(device_t dev);
60211430Sjhbstatic int		pcib_power_for_sleep(device_t pcib, device_t dev,
61211430Sjhb			    int *pstate);
62299929Sandrewstatic int		pcib_ari_get_id(device_t pcib, device_t dev,
63299929Sandrew    enum pci_id_type type, uintptr_t *id);
64289494Sjmgstatic uint32_t		pcib_read_config(device_t dev, u_int b, u_int s,
65264011Srstone    u_int f, u_int reg, int width);
66264011Srstonestatic void		pcib_write_config(device_t dev, u_int b, u_int s,
67264011Srstone    u_int f, u_int reg, uint32_t val, int width);
68264011Srstonestatic int		pcib_ari_maxslots(device_t dev);
69264011Srstonestatic int		pcib_ari_maxfuncs(device_t dev);
70264011Srstonestatic int		pcib_try_enable_ari(device_t pcib, device_t dev);
71279443Srstonestatic int		pcib_ari_enabled(device_t pcib);
72279443Srstonestatic void		pcib_ari_decode_rid(device_t pcib, uint16_t rid,
73279443Srstone			    int *bus, int *slot, int *func);
74299142Sjhb#ifdef PCI_HP
75299142Sjhbstatic void		pcib_pcie_ab_timeout(void *arg);
76299142Sjhbstatic void		pcib_pcie_cc_timeout(void *arg);
77299142Sjhbstatic void		pcib_pcie_dll_timeout(void *arg);
78299142Sjhb#endif
7969783Smsmith
8069783Smsmithstatic device_method_t pcib_methods[] = {
8169783Smsmith    /* Device interface */
8269783Smsmith    DEVMETHOD(device_probe,		pcib_probe),
8369783Smsmith    DEVMETHOD(device_attach,		pcib_attach),
84300249Sjhb    DEVMETHOD(device_detach,		pcib_detach),
8569783Smsmith    DEVMETHOD(device_shutdown,		bus_generic_shutdown),
86200341Sjkim    DEVMETHOD(device_suspend,		pcib_suspend),
87200341Sjkim    DEVMETHOD(device_resume,		pcib_resume),
8869783Smsmith
8969783Smsmith    /* Bus interface */
90299142Sjhb    DEVMETHOD(bus_child_present,	pcib_child_present),
9169783Smsmith    DEVMETHOD(bus_read_ivar,		pcib_read_ivar),
9269783Smsmith    DEVMETHOD(bus_write_ivar,		pcib_write_ivar),
9369783Smsmith    DEVMETHOD(bus_alloc_resource,	pcib_alloc_resource),
94221393Sjhb#ifdef NEW_PCIB
95221393Sjhb    DEVMETHOD(bus_adjust_resource,	pcib_adjust_resource),
96221393Sjhb    DEVMETHOD(bus_release_resource,	pcib_release_resource),
97221393Sjhb#else
98221324Sjhb    DEVMETHOD(bus_adjust_resource,	bus_generic_adjust_resource),
9969783Smsmith    DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
100221393Sjhb#endif
10169783Smsmith    DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
10269783Smsmith    DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
10369783Smsmith    DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
10469783Smsmith    DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
10569783Smsmith
10669783Smsmith    /* pcib interface */
107264011Srstone    DEVMETHOD(pcib_maxslots,		pcib_ari_maxslots),
108264011Srstone    DEVMETHOD(pcib_maxfuncs,		pcib_ari_maxfuncs),
10969783Smsmith    DEVMETHOD(pcib_read_config,		pcib_read_config),
11069783Smsmith    DEVMETHOD(pcib_write_config,	pcib_write_config),
11169783Smsmith    DEVMETHOD(pcib_route_interrupt,	pcib_route_interrupt),
112164264Sjhb    DEVMETHOD(pcib_alloc_msi,		pcib_alloc_msi),
113164264Sjhb    DEVMETHOD(pcib_release_msi,		pcib_release_msi),
114164264Sjhb    DEVMETHOD(pcib_alloc_msix,		pcib_alloc_msix),
115164264Sjhb    DEVMETHOD(pcib_release_msix,	pcib_release_msix),
116169221Sjhb    DEVMETHOD(pcib_map_msi,		pcib_map_msi),
117211430Sjhb    DEVMETHOD(pcib_power_for_sleep,	pcib_power_for_sleep),
118299929Sandrew    DEVMETHOD(pcib_get_id,		pcib_ari_get_id),
119264011Srstone    DEVMETHOD(pcib_try_enable_ari,	pcib_try_enable_ari),
120279443Srstone    DEVMETHOD(pcib_ari_enabled,		pcib_ari_enabled),
121279443Srstone    DEVMETHOD(pcib_decode_rid,		pcib_ari_decode_rid),
12269783Smsmith
123227843Smarius    DEVMETHOD_END
12469783Smsmith};
12569783Smsmith
126154079Sjhbstatic devclass_t pcib_devclass;
12769783Smsmith
128154079SjhbDEFINE_CLASS_0(pcib, pcib_driver, pcib_methods, sizeof(struct pcib_softc));
129253120SmariusDRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, NULL, NULL);
13069783Smsmith
131303781Sjhb#if defined(NEW_PCIB) || defined(PCI_HP)
132261527SjhbSYSCTL_DECL(_hw_pci);
133303781Sjhb#endif
134221393Sjhb
135303781Sjhb#ifdef NEW_PCIB
136261527Sjhbstatic int pci_clear_pcib;
137261527SjhbSYSCTL_INT(_hw_pci, OID_AUTO, clear_pcib, CTLFLAG_RDTUN, &pci_clear_pcib, 0,
138261527Sjhb    "Clear firmware-assigned resources for PCI-PCI bridge I/O windows.");
139261527Sjhb
140221393Sjhb/*
141221393Sjhb * Is a resource from a child device sub-allocated from one of our
142221393Sjhb * resource managers?
143221393Sjhb */
144221393Sjhbstatic int
145221393Sjhbpcib_is_resource_managed(struct pcib_softc *sc, int type, struct resource *r)
146221393Sjhb{
147221393Sjhb
148221393Sjhb	switch (type) {
149261790Sjhb#ifdef PCI_RES_BUS
150261790Sjhb	case PCI_RES_BUS:
151261790Sjhb		return (rman_is_region_manager(r, &sc->bus.rman));
152261790Sjhb#endif
153221393Sjhb	case SYS_RES_IOPORT:
154221393Sjhb		return (rman_is_region_manager(r, &sc->io.rman));
155221393Sjhb	case SYS_RES_MEMORY:
156221393Sjhb		/* Prefetchable resources may live in either memory rman. */
157221393Sjhb		if (rman_get_flags(r) & RF_PREFETCHABLE &&
158221393Sjhb		    rman_is_region_manager(r, &sc->pmem.rman))
159221393Sjhb			return (1);
160221393Sjhb		return (rman_is_region_manager(r, &sc->mem.rman));
161221393Sjhb	}
162221393Sjhb	return (0);
163221393Sjhb}
164221393Sjhb
165221393Sjhbstatic int
166221393Sjhbpcib_is_window_open(struct pcib_window *pw)
167221393Sjhb{
168221393Sjhb
169221393Sjhb	return (pw->valid && pw->base < pw->limit);
170221393Sjhb}
171221393Sjhb
172221393Sjhb/*
173221393Sjhb * XXX: If RF_ACTIVE did not also imply allocating a bus space tag and
174221393Sjhb * handle for the resource, we could pass RF_ACTIVE up to the PCI bus
175221393Sjhb * when allocating the resource windows and rely on the PCI bus driver
176221393Sjhb * to do this for us.
177221393Sjhb */
178221393Sjhbstatic void
179221393Sjhbpcib_activate_window(struct pcib_softc *sc, int type)
180221393Sjhb{
181221393Sjhb
182221393Sjhb	PCI_ENABLE_IO(device_get_parent(sc->dev), sc->dev, type);
183221393Sjhb}
184221393Sjhb
185221393Sjhbstatic void
186221393Sjhbpcib_write_windows(struct pcib_softc *sc, int mask)
187221393Sjhb{
188221393Sjhb	device_t dev;
189221393Sjhb	uint32_t val;
190221393Sjhb
191221393Sjhb	dev = sc->dev;
192221393Sjhb	if (sc->io.valid && mask & WIN_IO) {
193221393Sjhb		val = pci_read_config(dev, PCIR_IOBASEL_1, 1);
194221393Sjhb		if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) {
195221393Sjhb			pci_write_config(dev, PCIR_IOBASEH_1,
196221393Sjhb			    sc->io.base >> 16, 2);
197221393Sjhb			pci_write_config(dev, PCIR_IOLIMITH_1,
198221393Sjhb			    sc->io.limit >> 16, 2);
199221393Sjhb		}
200221393Sjhb		pci_write_config(dev, PCIR_IOBASEL_1, sc->io.base >> 8, 1);
201221393Sjhb		pci_write_config(dev, PCIR_IOLIMITL_1, sc->io.limit >> 8, 1);
202221393Sjhb	}
203221393Sjhb
204221393Sjhb	if (mask & WIN_MEM) {
205221393Sjhb		pci_write_config(dev, PCIR_MEMBASE_1, sc->mem.base >> 16, 2);
206221393Sjhb		pci_write_config(dev, PCIR_MEMLIMIT_1, sc->mem.limit >> 16, 2);
207221393Sjhb	}
208221393Sjhb
209221393Sjhb	if (sc->pmem.valid && mask & WIN_PMEM) {
210221393Sjhb		val = pci_read_config(dev, PCIR_PMBASEL_1, 2);
211221393Sjhb		if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) {
212221393Sjhb			pci_write_config(dev, PCIR_PMBASEH_1,
213221393Sjhb			    sc->pmem.base >> 32, 4);
214221393Sjhb			pci_write_config(dev, PCIR_PMLIMITH_1,
215221393Sjhb			    sc->pmem.limit >> 32, 4);
216221393Sjhb		}
217221393Sjhb		pci_write_config(dev, PCIR_PMBASEL_1, sc->pmem.base >> 16, 2);
218221393Sjhb		pci_write_config(dev, PCIR_PMLIMITL_1, sc->pmem.limit >> 16, 2);
219221393Sjhb	}
220221393Sjhb}
221221393Sjhb
222253450Sjhb/*
223253450Sjhb * This is used to reject I/O port allocations that conflict with an
224253450Sjhb * ISA alias range.
225253450Sjhb */
226253450Sjhbstatic int
227294883Sjhibbitspcib_is_isa_range(struct pcib_softc *sc, rman_res_t start, rman_res_t end,
228294883Sjhibbits    rman_res_t count)
229253450Sjhb{
230294883Sjhibbits	rman_res_t next_alias;
231253450Sjhb
232253450Sjhb	if (!(sc->bridgectl & PCIB_BCR_ISA_ENABLE))
233253450Sjhb		return (0);
234253450Sjhb
235253450Sjhb	/* Only check fixed ranges for overlap. */
236253450Sjhb	if (start + count - 1 != end)
237253450Sjhb		return (0);
238253450Sjhb
239253450Sjhb	/* ISA aliases are only in the lower 64KB of I/O space. */
240253450Sjhb	if (start >= 65536)
241253450Sjhb		return (0);
242253450Sjhb
243253450Sjhb	/* Check for overlap with 0x000 - 0x0ff as a special case. */
244253450Sjhb	if (start < 0x100)
245253450Sjhb		goto alias;
246253450Sjhb
247253450Sjhb	/*
248253450Sjhb	 * If the start address is an alias, the range is an alias.
249253450Sjhb	 * Otherwise, compute the start of the next alias range and
250253450Sjhb	 * check if it is before the end of the candidate range.
251253450Sjhb	 */
252253450Sjhb	if ((start & 0x300) != 0)
253253450Sjhb		goto alias;
254253450Sjhb	next_alias = (start & ~0x3fful) | 0x100;
255253450Sjhb	if (next_alias <= end)
256253450Sjhb		goto alias;
257253450Sjhb	return (0);
258253450Sjhb
259253450Sjhbalias:
260253450Sjhb	if (bootverbose)
261253450Sjhb		device_printf(sc->dev,
262297000Sjhibbits		    "I/O range %#jx-%#jx overlaps with an ISA alias\n", start,
263253450Sjhb		    end);
264253450Sjhb	return (1);
265253450Sjhb}
266253450Sjhb
267221393Sjhbstatic void
268253450Sjhbpcib_add_window_resources(struct pcib_window *w, struct resource **res,
269253450Sjhb    int count)
270253450Sjhb{
271253450Sjhb	struct resource **newarray;
272253450Sjhb	int error, i;
273253450Sjhb
274253450Sjhb	newarray = malloc(sizeof(struct resource *) * (w->count + count),
275253450Sjhb	    M_DEVBUF, M_WAITOK);
276253450Sjhb	if (w->res != NULL)
277253450Sjhb		bcopy(w->res, newarray, sizeof(struct resource *) * w->count);
278253450Sjhb	bcopy(res, newarray + w->count, sizeof(struct resource *) * count);
279253450Sjhb	free(w->res, M_DEVBUF);
280253450Sjhb	w->res = newarray;
281253450Sjhb	w->count += count;
282289494Sjmg
283253450Sjhb	for (i = 0; i < count; i++) {
284253450Sjhb		error = rman_manage_region(&w->rman, rman_get_start(res[i]),
285253450Sjhb		    rman_get_end(res[i]));
286253450Sjhb		if (error)
287253450Sjhb			panic("Failed to add resource to rman");
288253450Sjhb	}
289253450Sjhb}
290253450Sjhb
291294883Sjhibbitstypedef void (nonisa_callback)(rman_res_t start, rman_res_t end, void *arg);
292253450Sjhb
293253450Sjhbstatic void
294294883Sjhibbitspcib_walk_nonisa_ranges(rman_res_t start, rman_res_t end, nonisa_callback *cb,
295253450Sjhb    void *arg)
296253450Sjhb{
297294883Sjhibbits	rman_res_t next_end;
298253450Sjhb
299253450Sjhb	/*
300253450Sjhb	 * If start is within an ISA alias range, move up to the start
301253450Sjhb	 * of the next non-alias range.  As a special case, addresses
302253450Sjhb	 * in the range 0x000 - 0x0ff should also be skipped since
303253450Sjhb	 * those are used for various system I/O devices in ISA
304253450Sjhb	 * systems.
305253450Sjhb	 */
306253450Sjhb	if (start <= 65535) {
307253450Sjhb		if (start < 0x100 || (start & 0x300) != 0) {
308253450Sjhb			start &= ~0x3ff;
309253450Sjhb			start += 0x400;
310253450Sjhb		}
311253450Sjhb	}
312253450Sjhb
313253450Sjhb	/* ISA aliases are only in the lower 64KB of I/O space. */
314253450Sjhb	while (start <= MIN(end, 65535)) {
315253450Sjhb		next_end = MIN(start | 0xff, end);
316253450Sjhb		cb(start, next_end, arg);
317253450Sjhb		start += 0x400;
318253450Sjhb	}
319253450Sjhb
320253450Sjhb	if (start <= end)
321253450Sjhb		cb(start, end, arg);
322253450Sjhb}
323253450Sjhb
324253450Sjhbstatic void
325294883Sjhibbitscount_ranges(rman_res_t start, rman_res_t end, void *arg)
326253450Sjhb{
327253450Sjhb	int *countp;
328253450Sjhb
329253450Sjhb	countp = arg;
330253450Sjhb	(*countp)++;
331253450Sjhb}
332253450Sjhb
333253450Sjhbstruct alloc_state {
334253450Sjhb	struct resource **res;
335253450Sjhb	struct pcib_softc *sc;
336253450Sjhb	int count, error;
337253450Sjhb};
338253450Sjhb
339253450Sjhbstatic void
340294883Sjhibbitsalloc_ranges(rman_res_t start, rman_res_t end, void *arg)
341253450Sjhb{
342253450Sjhb	struct alloc_state *as;
343253450Sjhb	struct pcib_window *w;
344253450Sjhb	int rid;
345253450Sjhb
346253450Sjhb	as = arg;
347253450Sjhb	if (as->error != 0)
348253450Sjhb		return;
349253450Sjhb
350253450Sjhb	w = &as->sc->io;
351253450Sjhb	rid = w->reg;
352253450Sjhb	if (bootverbose)
353253450Sjhb		device_printf(as->sc->dev,
354297000Sjhibbits		    "allocating non-ISA range %#jx-%#jx\n", start, end);
355253450Sjhb	as->res[as->count] = bus_alloc_resource(as->sc->dev, SYS_RES_IOPORT,
356253450Sjhb	    &rid, start, end, end - start + 1, 0);
357253450Sjhb	if (as->res[as->count] == NULL)
358253450Sjhb		as->error = ENXIO;
359253450Sjhb	else
360253450Sjhb		as->count++;
361253450Sjhb}
362253450Sjhb
363253450Sjhbstatic int
364294883Sjhibbitspcib_alloc_nonisa_ranges(struct pcib_softc *sc, rman_res_t start, rman_res_t end)
365253450Sjhb{
366253450Sjhb	struct alloc_state as;
367253450Sjhb	int i, new_count;
368253450Sjhb
369253450Sjhb	/* First, see how many ranges we need. */
370253450Sjhb	new_count = 0;
371253450Sjhb	pcib_walk_nonisa_ranges(start, end, count_ranges, &new_count);
372253450Sjhb
373253450Sjhb	/* Second, allocate the ranges. */
374253450Sjhb	as.res = malloc(sizeof(struct resource *) * new_count, M_DEVBUF,
375253450Sjhb	    M_WAITOK);
376253450Sjhb	as.sc = sc;
377253450Sjhb	as.count = 0;
378253450Sjhb	as.error = 0;
379253450Sjhb	pcib_walk_nonisa_ranges(start, end, alloc_ranges, &as);
380253450Sjhb	if (as.error != 0) {
381253450Sjhb		for (i = 0; i < as.count; i++)
382253450Sjhb			bus_release_resource(sc->dev, SYS_RES_IOPORT,
383253450Sjhb			    sc->io.reg, as.res[i]);
384253450Sjhb		free(as.res, M_DEVBUF);
385253450Sjhb		return (as.error);
386253450Sjhb	}
387253450Sjhb	KASSERT(as.count == new_count, ("%s: count mismatch", __func__));
388253450Sjhb
389253450Sjhb	/* Third, add the ranges to the window. */
390253450Sjhb	pcib_add_window_resources(&sc->io, as.res, as.count);
391253450Sjhb	free(as.res, M_DEVBUF);
392253450Sjhb	return (0);
393253450Sjhb}
394253450Sjhb
395253450Sjhbstatic void
396221393Sjhbpcib_alloc_window(struct pcib_softc *sc, struct pcib_window *w, int type,
397221393Sjhb    int flags, pci_addr_t max_address)
398221393Sjhb{
399253450Sjhb	struct resource *res;
400221393Sjhb	char buf[64];
401221393Sjhb	int error, rid;
402221393Sjhb
403295664Sjhibbits	if (max_address != (rman_res_t)max_address)
404296336Sjhibbits		max_address = ~0;
405221393Sjhb	w->rman.rm_start = 0;
406221393Sjhb	w->rman.rm_end = max_address;
407221393Sjhb	w->rman.rm_type = RMAN_ARRAY;
408221393Sjhb	snprintf(buf, sizeof(buf), "%s %s window",
409221393Sjhb	    device_get_nameunit(sc->dev), w->name);
410221393Sjhb	w->rman.rm_descr = strdup(buf, M_DEVBUF);
411221393Sjhb	error = rman_init(&w->rman);
412221393Sjhb	if (error)
413221393Sjhb		panic("Failed to initialize %s %s rman",
414221393Sjhb		    device_get_nameunit(sc->dev), w->name);
415221393Sjhb
416221393Sjhb	if (!pcib_is_window_open(w))
417221393Sjhb		return;
418221393Sjhb
419221393Sjhb	if (w->base > max_address || w->limit > max_address) {
420221393Sjhb		device_printf(sc->dev,
421221393Sjhb		    "initial %s window has too many bits, ignoring\n", w->name);
422221393Sjhb		return;
423221393Sjhb	}
424253450Sjhb	if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE)
425253450Sjhb		(void)pcib_alloc_nonisa_ranges(sc, w->base, w->limit);
426253450Sjhb	else {
427253450Sjhb		rid = w->reg;
428253450Sjhb		res = bus_alloc_resource(sc->dev, type, &rid, w->base, w->limit,
429253450Sjhb		    w->limit - w->base + 1, flags);
430253450Sjhb		if (res != NULL)
431253450Sjhb			pcib_add_window_resources(w, &res, 1);
432253450Sjhb	}
433221393Sjhb	if (w->res == NULL) {
434221393Sjhb		device_printf(sc->dev,
435221393Sjhb		    "failed to allocate initial %s window: %#jx-%#jx\n",
436221393Sjhb		    w->name, (uintmax_t)w->base, (uintmax_t)w->limit);
437221393Sjhb		w->base = max_address;
438221393Sjhb		w->limit = 0;
439221393Sjhb		pcib_write_windows(sc, w->mask);
440221393Sjhb		return;
441221393Sjhb	}
442221393Sjhb	pcib_activate_window(sc, type);
443221393Sjhb}
444221393Sjhb
445221393Sjhb/*
446221393Sjhb * Initialize I/O windows.
447221393Sjhb */
448221393Sjhbstatic void
449221393Sjhbpcib_probe_windows(struct pcib_softc *sc)
450221393Sjhb{
451221393Sjhb	pci_addr_t max;
452221393Sjhb	device_t dev;
453221393Sjhb	uint32_t val;
454221393Sjhb
455221393Sjhb	dev = sc->dev;
456221393Sjhb
457261527Sjhb	if (pci_clear_pcib) {
458282783Sjhibbits		pcib_bridge_init(dev);
459261527Sjhb	}
460261527Sjhb
461221393Sjhb	/* Determine if the I/O port window is implemented. */
462221393Sjhb	val = pci_read_config(dev, PCIR_IOBASEL_1, 1);
463221393Sjhb	if (val == 0) {
464221393Sjhb		/*
465221393Sjhb		 * If 'val' is zero, then only 16-bits of I/O space
466221393Sjhb		 * are supported.
467221393Sjhb		 */
468221393Sjhb		pci_write_config(dev, PCIR_IOBASEL_1, 0xff, 1);
469221393Sjhb		if (pci_read_config(dev, PCIR_IOBASEL_1, 1) != 0) {
470221393Sjhb			sc->io.valid = 1;
471221393Sjhb			pci_write_config(dev, PCIR_IOBASEL_1, 0, 1);
472221393Sjhb		}
473221393Sjhb	} else
474221393Sjhb		sc->io.valid = 1;
475221393Sjhb
476221393Sjhb	/* Read the existing I/O port window. */
477221393Sjhb	if (sc->io.valid) {
478221393Sjhb		sc->io.reg = PCIR_IOBASEL_1;
479221393Sjhb		sc->io.step = 12;
480221393Sjhb		sc->io.mask = WIN_IO;
481221393Sjhb		sc->io.name = "I/O port";
482221393Sjhb		if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) {
483221393Sjhb			sc->io.base = PCI_PPBIOBASE(
484221393Sjhb			    pci_read_config(dev, PCIR_IOBASEH_1, 2), val);
485221393Sjhb			sc->io.limit = PCI_PPBIOLIMIT(
486221393Sjhb			    pci_read_config(dev, PCIR_IOLIMITH_1, 2),
487221393Sjhb			    pci_read_config(dev, PCIR_IOLIMITL_1, 1));
488221393Sjhb			max = 0xffffffff;
489221393Sjhb		} else {
490221393Sjhb			sc->io.base = PCI_PPBIOBASE(0, val);
491221393Sjhb			sc->io.limit = PCI_PPBIOLIMIT(0,
492221393Sjhb			    pci_read_config(dev, PCIR_IOLIMITL_1, 1));
493221393Sjhb			max = 0xffff;
494221393Sjhb		}
495221393Sjhb		pcib_alloc_window(sc, &sc->io, SYS_RES_IOPORT, 0, max);
496221393Sjhb	}
497221393Sjhb
498221393Sjhb	/* Read the existing memory window. */
499221393Sjhb	sc->mem.valid = 1;
500221393Sjhb	sc->mem.reg = PCIR_MEMBASE_1;
501221393Sjhb	sc->mem.step = 20;
502221393Sjhb	sc->mem.mask = WIN_MEM;
503221393Sjhb	sc->mem.name = "memory";
504221393Sjhb	sc->mem.base = PCI_PPBMEMBASE(0,
505221393Sjhb	    pci_read_config(dev, PCIR_MEMBASE_1, 2));
506221393Sjhb	sc->mem.limit = PCI_PPBMEMLIMIT(0,
507221393Sjhb	    pci_read_config(dev, PCIR_MEMLIMIT_1, 2));
508221393Sjhb	pcib_alloc_window(sc, &sc->mem, SYS_RES_MEMORY, 0, 0xffffffff);
509221393Sjhb
510221393Sjhb	/* Determine if the prefetchable memory window is implemented. */
511221393Sjhb	val = pci_read_config(dev, PCIR_PMBASEL_1, 2);
512221393Sjhb	if (val == 0) {
513221393Sjhb		/*
514221393Sjhb		 * If 'val' is zero, then only 32-bits of memory space
515221393Sjhb		 * are supported.
516221393Sjhb		 */
517221393Sjhb		pci_write_config(dev, PCIR_PMBASEL_1, 0xffff, 2);
518221393Sjhb		if (pci_read_config(dev, PCIR_PMBASEL_1, 2) != 0) {
519221393Sjhb			sc->pmem.valid = 1;
520221393Sjhb			pci_write_config(dev, PCIR_PMBASEL_1, 0, 2);
521221393Sjhb		}
522221393Sjhb	} else
523221393Sjhb		sc->pmem.valid = 1;
524221393Sjhb
525221393Sjhb	/* Read the existing prefetchable memory window. */
526221393Sjhb	if (sc->pmem.valid) {
527221393Sjhb		sc->pmem.reg = PCIR_PMBASEL_1;
528221393Sjhb		sc->pmem.step = 20;
529221393Sjhb		sc->pmem.mask = WIN_PMEM;
530221393Sjhb		sc->pmem.name = "prefetch";
531221393Sjhb		if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) {
532221393Sjhb			sc->pmem.base = PCI_PPBMEMBASE(
533221393Sjhb			    pci_read_config(dev, PCIR_PMBASEH_1, 4), val);
534221393Sjhb			sc->pmem.limit = PCI_PPBMEMLIMIT(
535221393Sjhb			    pci_read_config(dev, PCIR_PMLIMITH_1, 4),
536221393Sjhb			    pci_read_config(dev, PCIR_PMLIMITL_1, 2));
537221393Sjhb			max = 0xffffffffffffffff;
538221393Sjhb		} else {
539221393Sjhb			sc->pmem.base = PCI_PPBMEMBASE(0, val);
540221393Sjhb			sc->pmem.limit = PCI_PPBMEMLIMIT(0,
541221393Sjhb			    pci_read_config(dev, PCIR_PMLIMITL_1, 2));
542221393Sjhb			max = 0xffffffff;
543221393Sjhb		}
544221393Sjhb		pcib_alloc_window(sc, &sc->pmem, SYS_RES_MEMORY,
545221393Sjhb		    RF_PREFETCHABLE, max);
546221393Sjhb	}
547221393Sjhb}
548221393Sjhb
549300249Sjhbstatic void
550300249Sjhbpcib_release_window(struct pcib_softc *sc, struct pcib_window *w, int type)
551300249Sjhb{
552300249Sjhb	device_t dev;
553300249Sjhb	int error, i;
554300249Sjhb
555300249Sjhb	if (!w->valid)
556300249Sjhb		return;
557300249Sjhb
558300249Sjhb	dev = sc->dev;
559300249Sjhb	error = rman_fini(&w->rman);
560300249Sjhb	if (error) {
561300249Sjhb		device_printf(dev, "failed to release %s rman\n", w->name);
562300249Sjhb		return;
563300249Sjhb	}
564300249Sjhb	free(__DECONST(char *, w->rman.rm_descr), M_DEVBUF);
565300249Sjhb
566300249Sjhb	for (i = 0; i < w->count; i++) {
567300249Sjhb		error = bus_free_resource(dev, type, w->res[i]);
568300249Sjhb		if (error)
569300249Sjhb			device_printf(dev,
570300249Sjhb			    "failed to release %s resource: %d\n", w->name,
571300249Sjhb			    error);
572300249Sjhb	}
573300249Sjhb	free(w->res, M_DEVBUF);
574300249Sjhb}
575300249Sjhb
576300249Sjhbstatic void
577300249Sjhbpcib_free_windows(struct pcib_softc *sc)
578300249Sjhb{
579300249Sjhb
580300249Sjhb	pcib_release_window(sc, &sc->pmem, SYS_RES_MEMORY);
581300249Sjhb	pcib_release_window(sc, &sc->mem, SYS_RES_MEMORY);
582300249Sjhb	pcib_release_window(sc, &sc->io, SYS_RES_IOPORT);
583300249Sjhb}
584300249Sjhb
585261790Sjhb#ifdef PCI_RES_BUS
586261790Sjhb/*
587261790Sjhb * Allocate a suitable secondary bus for this bridge if needed and
588261790Sjhb * initialize the resource manager for the secondary bus range.  Note
589261790Sjhb * that the minimum count is a desired value and this may allocate a
590261790Sjhb * smaller range.
591261790Sjhb */
592261790Sjhbvoid
593261790Sjhbpcib_setup_secbus(device_t dev, struct pcib_secbus *bus, int min_count)
594261790Sjhb{
595261790Sjhb	char buf[64];
596281874Sjhb	int error, rid, sec_reg;
597261790Sjhb
598261790Sjhb	switch (pci_read_config(dev, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE) {
599261790Sjhb	case PCIM_HDRTYPE_BRIDGE:
600281874Sjhb		sec_reg = PCIR_SECBUS_1;
601261790Sjhb		bus->sub_reg = PCIR_SUBBUS_1;
602261790Sjhb		break;
603261790Sjhb	case PCIM_HDRTYPE_CARDBUS:
604281874Sjhb		sec_reg = PCIR_SECBUS_2;
605261790Sjhb		bus->sub_reg = PCIR_SUBBUS_2;
606261790Sjhb		break;
607261790Sjhb	default:
608261790Sjhb		panic("not a PCI bridge");
609261790Sjhb	}
610281874Sjhb	bus->sec = pci_read_config(dev, sec_reg, 1);
611281874Sjhb	bus->sub = pci_read_config(dev, bus->sub_reg, 1);
612261790Sjhb	bus->dev = dev;
613261790Sjhb	bus->rman.rm_start = 0;
614261790Sjhb	bus->rman.rm_end = PCI_BUSMAX;
615261790Sjhb	bus->rman.rm_type = RMAN_ARRAY;
616261790Sjhb	snprintf(buf, sizeof(buf), "%s bus numbers", device_get_nameunit(dev));
617261790Sjhb	bus->rman.rm_descr = strdup(buf, M_DEVBUF);
618261790Sjhb	error = rman_init(&bus->rman);
619261790Sjhb	if (error)
620261790Sjhb		panic("Failed to initialize %s bus number rman",
621261790Sjhb		    device_get_nameunit(dev));
622261790Sjhb
623261790Sjhb	/*
624261790Sjhb	 * Allocate a bus range.  This will return an existing bus range
625261790Sjhb	 * if one exists, or a new bus range if one does not.
626261790Sjhb	 */
627261790Sjhb	rid = 0;
628296137Sjhibbits	bus->res = bus_alloc_resource_anywhere(dev, PCI_RES_BUS, &rid,
629261790Sjhb	    min_count, 0);
630261790Sjhb	if (bus->res == NULL) {
631261790Sjhb		/*
632261790Sjhb		 * Fall back to just allocating a range of a single bus
633261790Sjhb		 * number.
634261790Sjhb		 */
635296137Sjhibbits		bus->res = bus_alloc_resource_anywhere(dev, PCI_RES_BUS, &rid,
636261790Sjhb		    1, 0);
637261790Sjhb	} else if (rman_get_size(bus->res) < min_count)
638261790Sjhb		/*
639261790Sjhb		 * Attempt to grow the existing range to satisfy the
640261790Sjhb		 * minimum desired count.
641261790Sjhb		 */
642261790Sjhb		(void)bus_adjust_resource(dev, PCI_RES_BUS, bus->res,
643261790Sjhb		    rman_get_start(bus->res), rman_get_start(bus->res) +
644261790Sjhb		    min_count - 1);
645261790Sjhb
646261790Sjhb	/*
647261790Sjhb	 * Add the initial resource to the rman.
648261790Sjhb	 */
649261790Sjhb	if (bus->res != NULL) {
650261790Sjhb		error = rman_manage_region(&bus->rman, rman_get_start(bus->res),
651261790Sjhb		    rman_get_end(bus->res));
652261790Sjhb		if (error)
653261790Sjhb			panic("Failed to add resource to rman");
654261790Sjhb		bus->sec = rman_get_start(bus->res);
655261790Sjhb		bus->sub = rman_get_end(bus->res);
656261790Sjhb	}
657261790Sjhb}
658261790Sjhb
659300249Sjhbvoid
660300249Sjhbpcib_free_secbus(device_t dev, struct pcib_secbus *bus)
661300249Sjhb{
662300249Sjhb	int error;
663300249Sjhb
664300249Sjhb	error = rman_fini(&bus->rman);
665300249Sjhb	if (error) {
666300249Sjhb		device_printf(dev, "failed to release bus number rman\n");
667300249Sjhb		return;
668300249Sjhb	}
669300249Sjhb	free(__DECONST(char *, bus->rman.rm_descr), M_DEVBUF);
670300249Sjhb
671300249Sjhb	error = bus_free_resource(dev, PCI_RES_BUS, bus->res);
672300249Sjhb	if (error)
673300249Sjhb		device_printf(dev,
674300249Sjhb		    "failed to release bus numbers resource: %d\n", error);
675300249Sjhb}
676300249Sjhb
677261790Sjhbstatic struct resource *
678261790Sjhbpcib_suballoc_bus(struct pcib_secbus *bus, device_t child, int *rid,
679294883Sjhibbits    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
680261790Sjhb{
681261790Sjhb	struct resource *res;
682261790Sjhb
683261790Sjhb	res = rman_reserve_resource(&bus->rman, start, end, count, flags,
684261790Sjhb	    child);
685261790Sjhb	if (res == NULL)
686261790Sjhb		return (NULL);
687261790Sjhb
688261790Sjhb	if (bootverbose)
689261790Sjhb		device_printf(bus->dev,
690297000Sjhibbits		    "allocated bus range (%ju-%ju) for rid %d of %s\n",
691261790Sjhb		    rman_get_start(res), rman_get_end(res), *rid,
692261790Sjhb		    pcib_child_name(child));
693261790Sjhb	rman_set_rid(res, *rid);
694261790Sjhb	return (res);
695261790Sjhb}
696261790Sjhb
697261790Sjhb/*
698261790Sjhb * Attempt to grow the secondary bus range.  This is much simpler than
699261790Sjhb * for I/O windows as the range can only be grown by increasing
700261790Sjhb * subbus.
701261790Sjhb */
702261790Sjhbstatic int
703294883Sjhibbitspcib_grow_subbus(struct pcib_secbus *bus, rman_res_t new_end)
704261790Sjhb{
705294883Sjhibbits	rman_res_t old_end;
706261790Sjhb	int error;
707261790Sjhb
708261790Sjhb	old_end = rman_get_end(bus->res);
709261790Sjhb	KASSERT(new_end > old_end, ("attempt to shrink subbus"));
710261790Sjhb	error = bus_adjust_resource(bus->dev, PCI_RES_BUS, bus->res,
711261790Sjhb	    rman_get_start(bus->res), new_end);
712261790Sjhb	if (error)
713261790Sjhb		return (error);
714261790Sjhb	if (bootverbose)
715297000Sjhibbits		device_printf(bus->dev, "grew bus range to %ju-%ju\n",
716261790Sjhb		    rman_get_start(bus->res), rman_get_end(bus->res));
717261790Sjhb	error = rman_manage_region(&bus->rman, old_end + 1,
718261790Sjhb	    rman_get_end(bus->res));
719261790Sjhb	if (error)
720261790Sjhb		panic("Failed to add resource to rman");
721261790Sjhb	bus->sub = rman_get_end(bus->res);
722261790Sjhb	pci_write_config(bus->dev, bus->sub_reg, bus->sub, 1);
723261790Sjhb	return (0);
724261790Sjhb}
725261790Sjhb
726261790Sjhbstruct resource *
727261790Sjhbpcib_alloc_subbus(struct pcib_secbus *bus, device_t child, int *rid,
728294883Sjhibbits    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
729261790Sjhb{
730261790Sjhb	struct resource *res;
731294883Sjhibbits	rman_res_t start_free, end_free, new_end;
732261790Sjhb
733261790Sjhb	/*
734261790Sjhb	 * First, see if the request can be satisified by the existing
735261790Sjhb	 * bus range.
736261790Sjhb	 */
737261790Sjhb	res = pcib_suballoc_bus(bus, child, rid, start, end, count, flags);
738261790Sjhb	if (res != NULL)
739261790Sjhb		return (res);
740261790Sjhb
741261790Sjhb	/*
742261790Sjhb	 * Figure out a range to grow the bus range.  First, find the
743261790Sjhb	 * first bus number after the last allocated bus in the rman and
744261790Sjhb	 * enforce that as a minimum starting point for the range.
745261790Sjhb	 */
746261790Sjhb	if (rman_last_free_region(&bus->rman, &start_free, &end_free) != 0 ||
747261790Sjhb	    end_free != bus->sub)
748261790Sjhb		start_free = bus->sub + 1;
749261790Sjhb	if (start_free < start)
750261790Sjhb		start_free = start;
751261790Sjhb	new_end = start_free + count - 1;
752261790Sjhb
753261790Sjhb	/*
754261790Sjhb	 * See if this new range would satisfy the request if it
755261790Sjhb	 * succeeds.
756261790Sjhb	 */
757261790Sjhb	if (new_end > end)
758261790Sjhb		return (NULL);
759261790Sjhb
760261790Sjhb	/* Finally, attempt to grow the existing resource. */
761261790Sjhb	if (bootverbose) {
762261790Sjhb		device_printf(bus->dev,
763297000Sjhibbits		    "attempting to grow bus range for %ju buses\n", count);
764297000Sjhibbits		printf("\tback candidate range: %ju-%ju\n", start_free,
765261790Sjhb		    new_end);
766261790Sjhb	}
767261790Sjhb	if (pcib_grow_subbus(bus, new_end) == 0)
768261790Sjhb		return (pcib_suballoc_bus(bus, child, rid, start, end, count,
769261790Sjhb		    flags));
770261790Sjhb	return (NULL);
771261790Sjhb}
772261790Sjhb#endif
773261790Sjhb
774221393Sjhb#else
775221393Sjhb
776221393Sjhb/*
777163805Simp * Is the prefetch window open (eg, can we allocate memory in it?)
778163805Simp */
779163805Simpstatic int
780163805Simppcib_is_prefetch_open(struct pcib_softc *sc)
781163805Simp{
782163805Simp	return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit);
783163805Simp}
784163805Simp
785163805Simp/*
786163805Simp * Is the nonprefetch window open (eg, can we allocate memory in it?)
787163805Simp */
788163805Simpstatic int
789163805Simppcib_is_nonprefetch_open(struct pcib_softc *sc)
790163805Simp{
791163805Simp	return (sc->membase > 0 && sc->membase < sc->memlimit);
792163805Simp}
793163805Simp
794163805Simp/*
795163805Simp * Is the io window open (eg, can we allocate ports in it?)
796163805Simp */
797163805Simpstatic int
798163805Simppcib_is_io_open(struct pcib_softc *sc)
799163805Simp{
800163805Simp	return (sc->iobase > 0 && sc->iobase < sc->iolimit);
801163805Simp}
802163805Simp
803163805Simp/*
804200341Sjkim * Get current I/O decode.
805200341Sjkim */
806200341Sjkimstatic void
807200341Sjkimpcib_get_io_decode(struct pcib_softc *sc)
808200341Sjkim{
809200341Sjkim	device_t	dev;
810200341Sjkim	uint32_t	iolow;
811200341Sjkim
812200341Sjkim	dev = sc->dev;
813200341Sjkim
814200341Sjkim	iolow = pci_read_config(dev, PCIR_IOBASEL_1, 1);
815200341Sjkim	if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32)
816200341Sjkim		sc->iobase = PCI_PPBIOBASE(
817200341Sjkim		    pci_read_config(dev, PCIR_IOBASEH_1, 2), iolow);
818200341Sjkim	else
819200341Sjkim		sc->iobase = PCI_PPBIOBASE(0, iolow);
820200341Sjkim
821200341Sjkim	iolow = pci_read_config(dev, PCIR_IOLIMITL_1, 1);
822200341Sjkim	if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32)
823200341Sjkim		sc->iolimit = PCI_PPBIOLIMIT(
824200341Sjkim		    pci_read_config(dev, PCIR_IOLIMITH_1, 2), iolow);
825200341Sjkim	else
826200341Sjkim		sc->iolimit = PCI_PPBIOLIMIT(0, iolow);
827200341Sjkim}
828200341Sjkim
829200341Sjkim/*
830200341Sjkim * Get current memory decode.
831200341Sjkim */
832200341Sjkimstatic void
833200341Sjkimpcib_get_mem_decode(struct pcib_softc *sc)
834200341Sjkim{
835200341Sjkim	device_t	dev;
836200341Sjkim	pci_addr_t	pmemlow;
837200341Sjkim
838200341Sjkim	dev = sc->dev;
839200341Sjkim
840200341Sjkim	sc->membase = PCI_PPBMEMBASE(0,
841200341Sjkim	    pci_read_config(dev, PCIR_MEMBASE_1, 2));
842200341Sjkim	sc->memlimit = PCI_PPBMEMLIMIT(0,
843200341Sjkim	    pci_read_config(dev, PCIR_MEMLIMIT_1, 2));
844200341Sjkim
845200341Sjkim	pmemlow = pci_read_config(dev, PCIR_PMBASEL_1, 2);
846200341Sjkim	if ((pmemlow & PCIM_BRPM_MASK) == PCIM_BRPM_64)
847200341Sjkim		sc->pmembase = PCI_PPBMEMBASE(
848200341Sjkim		    pci_read_config(dev, PCIR_PMBASEH_1, 4), pmemlow);
849200341Sjkim	else
850200341Sjkim		sc->pmembase = PCI_PPBMEMBASE(0, pmemlow);
851200341Sjkim
852200341Sjkim	pmemlow = pci_read_config(dev, PCIR_PMLIMITL_1, 2);
853289494Sjmg	if ((pmemlow & PCIM_BRPM_MASK) == PCIM_BRPM_64)
854200341Sjkim		sc->pmemlimit = PCI_PPBMEMLIMIT(
855200341Sjkim		    pci_read_config(dev, PCIR_PMLIMITH_1, 4), pmemlow);
856200341Sjkim	else
857200341Sjkim		sc->pmemlimit = PCI_PPBMEMLIMIT(0, pmemlow);
858200341Sjkim}
859200341Sjkim
860200341Sjkim/*
861200341Sjkim * Restore previous I/O decode.
862200341Sjkim */
863200341Sjkimstatic void
864200341Sjkimpcib_set_io_decode(struct pcib_softc *sc)
865200341Sjkim{
866200341Sjkim	device_t	dev;
867200341Sjkim	uint32_t	iohi;
868200341Sjkim
869200341Sjkim	dev = sc->dev;
870200341Sjkim
871200341Sjkim	iohi = sc->iobase >> 16;
872200341Sjkim	if (iohi > 0)
873200341Sjkim		pci_write_config(dev, PCIR_IOBASEH_1, iohi, 2);
874200341Sjkim	pci_write_config(dev, PCIR_IOBASEL_1, sc->iobase >> 8, 1);
875200341Sjkim
876200341Sjkim	iohi = sc->iolimit >> 16;
877200341Sjkim	if (iohi > 0)
878200341Sjkim		pci_write_config(dev, PCIR_IOLIMITH_1, iohi, 2);
879200341Sjkim	pci_write_config(dev, PCIR_IOLIMITL_1, sc->iolimit >> 8, 1);
880200341Sjkim}
881200341Sjkim
882200341Sjkim/*
883200341Sjkim * Restore previous memory decode.
884200341Sjkim */
885200341Sjkimstatic void
886200341Sjkimpcib_set_mem_decode(struct pcib_softc *sc)
887200341Sjkim{
888200341Sjkim	device_t	dev;
889200341Sjkim	pci_addr_t	pmemhi;
890200341Sjkim
891200341Sjkim	dev = sc->dev;
892200341Sjkim
893200341Sjkim	pci_write_config(dev, PCIR_MEMBASE_1, sc->membase >> 16, 2);
894200341Sjkim	pci_write_config(dev, PCIR_MEMLIMIT_1, sc->memlimit >> 16, 2);
895200341Sjkim
896200341Sjkim	pmemhi = sc->pmembase >> 32;
897200341Sjkim	if (pmemhi > 0)
898200341Sjkim		pci_write_config(dev, PCIR_PMBASEH_1, pmemhi, 4);
899200341Sjkim	pci_write_config(dev, PCIR_PMBASEL_1, sc->pmembase >> 16, 2);
900200341Sjkim
901200341Sjkim	pmemhi = sc->pmemlimit >> 32;
902200341Sjkim	if (pmemhi > 0)
903200341Sjkim		pci_write_config(dev, PCIR_PMLIMITH_1, pmemhi, 4);
904200341Sjkim	pci_write_config(dev, PCIR_PMLIMITL_1, sc->pmemlimit >> 16, 2);
905200341Sjkim}
906221393Sjhb#endif
907200341Sjkim
908299142Sjhb#ifdef PCI_HP
909200341Sjkim/*
910299142Sjhb * PCI-express HotPlug support.
911299142Sjhb */
912303781Sjhbstatic int pci_enable_pcie_hp = 1;
913303781SjhbSYSCTL_INT(_hw_pci, OID_AUTO, enable_pcie_hp, CTLFLAG_RDTUN,
914303781Sjhb    &pci_enable_pcie_hp, 0,
915303781Sjhb    "Enable support for native PCI-express HotPlug.");
916303781Sjhb
917299142Sjhbstatic void
918299142Sjhbpcib_probe_hotplug(struct pcib_softc *sc)
919299142Sjhb{
920299142Sjhb	device_t dev;
921304434Svangyzen	uint16_t link_sta, slot_sta;
922299142Sjhb
923303781Sjhb	if (!pci_enable_pcie_hp)
924303781Sjhb		return;
925303781Sjhb
926299142Sjhb	dev = sc->dev;
927299142Sjhb	if (pci_find_cap(dev, PCIY_EXPRESS, NULL) != 0)
928299142Sjhb		return;
929299142Sjhb
930299142Sjhb	if (!(pcie_read_config(dev, PCIER_FLAGS, 2) & PCIEM_FLAGS_SLOT))
931299142Sjhb		return;
932299142Sjhb
933299142Sjhb	sc->pcie_link_cap = pcie_read_config(dev, PCIER_LINK_CAP, 4);
934299142Sjhb	sc->pcie_slot_cap = pcie_read_config(dev, PCIER_SLOT_CAP, 4);
935299142Sjhb
936304434Svangyzen	if ((sc->pcie_slot_cap & PCIEM_SLOT_CAP_HPC) == 0)
937304434Svangyzen		return;
938314125Sdelphij	if ((sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE) == 0)
939314125Sdelphij		return;
940304434Svangyzen
941303781Sjhb	/*
942304434Svangyzen	 * Some devices report that they have an MRL when they actually
943304434Svangyzen	 * do not.  Since they always report that the MRL is open, child
944304434Svangyzen	 * devices would be ignored.  Try to detect these devices and
945304434Svangyzen	 * ignore their claim of HotPlug support.
946304434Svangyzen	 *
947304434Svangyzen	 * If there is an open MRL but the Data Link Layer is active,
948304434Svangyzen	 * the MRL is not real.
949303781Sjhb	 */
950304434Svangyzen	if ((sc->pcie_slot_cap & PCIEM_SLOT_CAP_MRLSP) != 0 &&
951304434Svangyzen	    (sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE) != 0) {
952304434Svangyzen		link_sta = pcie_read_config(dev, PCIER_LINK_STA, 2);
953304434Svangyzen		slot_sta = pcie_read_config(dev, PCIER_SLOT_STA, 2);
954304434Svangyzen		if ((slot_sta & PCIEM_SLOT_STA_MRLSS) != 0 &&
955304434Svangyzen		    (link_sta & PCIEM_LINK_STA_DL_ACTIVE) != 0) {
956304434Svangyzen			return;
957304434Svangyzen		}
958304434Svangyzen	}
959304434Svangyzen
960304434Svangyzen	sc->flags |= PCIB_HOTPLUG;
961299142Sjhb}
962299142Sjhb
963299142Sjhb/*
964299142Sjhb * Send a HotPlug command to the slot control register.  If this slot
965300074Sjhb * uses command completion interrupts and a previous command is still
966300074Sjhb * in progress, then the command is dropped.  Once the previous
967300074Sjhb * command completes or times out, pcib_pcie_hotplug_update() will be
968300074Sjhb * invoked to post a new command based on the slot's state at that
969300074Sjhb * time.
970299142Sjhb */
971299142Sjhbstatic void
972299142Sjhbpcib_pcie_hotplug_command(struct pcib_softc *sc, uint16_t val, uint16_t mask)
973299142Sjhb{
974299142Sjhb	device_t dev;
975299142Sjhb	uint16_t ctl, new;
976299142Sjhb
977299142Sjhb	dev = sc->dev;
978300074Sjhb
979300074Sjhb	if (sc->flags & PCIB_HOTPLUG_CMD_PENDING)
980299142Sjhb		return;
981299142Sjhb
982300074Sjhb	ctl = pcie_read_config(dev, PCIER_SLOT_CTL, 2);
983300074Sjhb	new = (ctl & ~mask) | val;
984300074Sjhb	if (new == ctl)
985300074Sjhb		return;
986304434Svangyzen	if (bootverbose)
987304434Svangyzen		device_printf(dev, "HotPlug command: %04x -> %04x\n", ctl, new);
988300074Sjhb	pcie_write_config(dev, PCIER_SLOT_CTL, new, 2);
989300249Sjhb	if (!(sc->pcie_slot_cap & PCIEM_SLOT_CAP_NCCS) &&
990300249Sjhb	    (ctl & new) & PCIEM_SLOT_CTL_CCIE) {
991300074Sjhb		sc->flags |= PCIB_HOTPLUG_CMD_PENDING;
992300074Sjhb		if (!cold)
993300074Sjhb			callout_reset(&sc->pcie_cc_timer, hz,
994300074Sjhb			    pcib_pcie_cc_timeout, sc);
995299142Sjhb	}
996299142Sjhb}
997299142Sjhb
998299142Sjhbstatic void
999299142Sjhbpcib_pcie_hotplug_command_completed(struct pcib_softc *sc)
1000299142Sjhb{
1001299142Sjhb	device_t dev;
1002299142Sjhb
1003299142Sjhb	dev = sc->dev;
1004299142Sjhb
1005299142Sjhb	if (bootverbose)
1006299142Sjhb		device_printf(dev, "Command Completed\n");
1007299142Sjhb	if (!(sc->flags & PCIB_HOTPLUG_CMD_PENDING))
1008299142Sjhb		return;
1009300074Sjhb	callout_stop(&sc->pcie_cc_timer);
1010300074Sjhb	sc->flags &= ~PCIB_HOTPLUG_CMD_PENDING;
1011300249Sjhb	wakeup(sc);
1012299142Sjhb}
1013299142Sjhb
1014299142Sjhb/*
1015299142Sjhb * Returns true if a card is fully inserted from the user's
1016299142Sjhb * perspective.  It may not yet be ready for access, but the driver
1017299142Sjhb * can now start enabling access if necessary.
1018299142Sjhb */
1019299142Sjhbstatic bool
1020299142Sjhbpcib_hotplug_inserted(struct pcib_softc *sc)
1021299142Sjhb{
1022299142Sjhb
1023299142Sjhb	/* Pretend the card isn't present if a detach is forced. */
1024299142Sjhb	if (sc->flags & PCIB_DETACHING)
1025299142Sjhb		return (false);
1026299142Sjhb
1027299142Sjhb	/* Card must be present in the slot. */
1028299142Sjhb	if ((sc->pcie_slot_sta & PCIEM_SLOT_STA_PDS) == 0)
1029299142Sjhb		return (false);
1030299142Sjhb
1031299142Sjhb	/* A power fault implicitly turns off power to the slot. */
1032299142Sjhb	if (sc->pcie_slot_sta & PCIEM_SLOT_STA_PFD)
1033299142Sjhb		return (false);
1034299142Sjhb
1035299142Sjhb	/* If the MRL is disengaged, the slot is powered off. */
1036299142Sjhb	if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_MRLSP &&
1037299142Sjhb	    (sc->pcie_slot_sta & PCIEM_SLOT_STA_MRLSS) != 0)
1038299142Sjhb		return (false);
1039299142Sjhb
1040299142Sjhb	return (true);
1041299142Sjhb}
1042299142Sjhb
1043299142Sjhb/*
1044299142Sjhb * Returns -1 if the card is fully inserted, powered, and ready for
1045299142Sjhb * access.  Otherwise, returns 0.
1046299142Sjhb */
1047299142Sjhbstatic int
1048299142Sjhbpcib_hotplug_present(struct pcib_softc *sc)
1049299142Sjhb{
1050299142Sjhb
1051299142Sjhb	/* Card must be inserted. */
1052299142Sjhb	if (!pcib_hotplug_inserted(sc))
1053299142Sjhb		return (0);
1054299142Sjhb
1055299142Sjhb	/*
1056299142Sjhb	 * Require the Electromechanical Interlock to be engaged if
1057299142Sjhb	 * present.
1058299142Sjhb	 */
1059299142Sjhb	if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_EIP &&
1060299142Sjhb	    (sc->pcie_slot_sta & PCIEM_SLOT_STA_EIS) == 0)
1061299142Sjhb		return (0);
1062299142Sjhb
1063299142Sjhb	/* Require the Data Link Layer to be active. */
1064299142Sjhb	if (sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE) {
1065299142Sjhb		if (!(sc->pcie_link_sta & PCIEM_LINK_STA_DL_ACTIVE))
1066299142Sjhb			return (0);
1067299142Sjhb	}
1068299142Sjhb
1069299142Sjhb	return (-1);
1070299142Sjhb}
1071299142Sjhb
1072299142Sjhbstatic void
1073299142Sjhbpcib_pcie_hotplug_update(struct pcib_softc *sc, uint16_t val, uint16_t mask,
1074299142Sjhb    bool schedule_task)
1075299142Sjhb{
1076303835Svangyzen	bool card_inserted, ei_engaged;
1077299142Sjhb
1078304434Svangyzen	/* Clear DETACHING if Presence Detect has cleared. */
1079299142Sjhb	if ((sc->pcie_slot_sta & (PCIEM_SLOT_STA_PDC | PCIEM_SLOT_STA_PDS)) ==
1080299142Sjhb	    PCIEM_SLOT_STA_PDC)
1081299142Sjhb		sc->flags &= ~PCIB_DETACHING;
1082299142Sjhb
1083299142Sjhb	card_inserted = pcib_hotplug_inserted(sc);
1084299142Sjhb
1085299142Sjhb	/* Turn the power indicator on if a card is inserted. */
1086299142Sjhb	if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_PIP) {
1087299142Sjhb		mask |= PCIEM_SLOT_CTL_PIC;
1088299142Sjhb		if (card_inserted)
1089299142Sjhb			val |= PCIEM_SLOT_CTL_PI_ON;
1090299142Sjhb		else if (sc->flags & PCIB_DETACH_PENDING)
1091299142Sjhb			val |= PCIEM_SLOT_CTL_PI_BLINK;
1092299142Sjhb		else
1093299142Sjhb			val |= PCIEM_SLOT_CTL_PI_OFF;
1094299142Sjhb	}
1095299142Sjhb
1096299142Sjhb	/* Turn the power on via the Power Controller if a card is inserted. */
1097299142Sjhb	if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_PCP) {
1098299142Sjhb		mask |= PCIEM_SLOT_CTL_PCC;
1099299142Sjhb		if (card_inserted)
1100299142Sjhb			val |= PCIEM_SLOT_CTL_PC_ON;
1101299142Sjhb		else
1102299142Sjhb			val |= PCIEM_SLOT_CTL_PC_OFF;
1103299142Sjhb	}
1104299142Sjhb
1105299142Sjhb	/*
1106299142Sjhb	 * If a card is inserted, enable the Electromechanical
1107299142Sjhb	 * Interlock.  If a card is not inserted (or we are in the
1108299142Sjhb	 * process of detaching), disable the Electromechanical
1109299142Sjhb	 * Interlock.
1110299142Sjhb	 */
1111299142Sjhb	if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_EIP) {
1112300074Sjhb		mask |= PCIEM_SLOT_CTL_EIC;
1113303835Svangyzen		ei_engaged = (sc->pcie_slot_sta & PCIEM_SLOT_STA_EIS) != 0;
1114303835Svangyzen		if (card_inserted != ei_engaged)
1115299142Sjhb			val |= PCIEM_SLOT_CTL_EIC;
1116299142Sjhb	}
1117299142Sjhb
1118299142Sjhb	/*
1119299142Sjhb	 * Start a timer to see if the Data Link Layer times out.
1120304434Svangyzen	 * Note that we only start the timer if Presence Detect or MRL Sensor
1121299142Sjhb	 * changed on this interrupt.  Stop any scheduled timer if
1122299142Sjhb	 * the Data Link Layer is active.
1123299142Sjhb	 */
1124299142Sjhb	if (sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE) {
1125299142Sjhb		if (card_inserted &&
1126299142Sjhb		    !(sc->pcie_link_sta & PCIEM_LINK_STA_DL_ACTIVE) &&
1127304434Svangyzen		    sc->pcie_slot_sta &
1128304434Svangyzen		    (PCIEM_SLOT_STA_MRLSC | PCIEM_SLOT_STA_PDC)) {
1129299142Sjhb			if (cold)
1130299142Sjhb				device_printf(sc->dev,
1131299142Sjhb				    "Data Link Layer inactive\n");
1132299142Sjhb			else
1133299142Sjhb				callout_reset(&sc->pcie_dll_timer, hz,
1134299142Sjhb				    pcib_pcie_dll_timeout, sc);
1135299142Sjhb		} else if (sc->pcie_link_sta & PCIEM_LINK_STA_DL_ACTIVE)
1136299142Sjhb			callout_stop(&sc->pcie_dll_timer);
1137299142Sjhb	}
1138299142Sjhb
1139299142Sjhb	pcib_pcie_hotplug_command(sc, val, mask);
1140299142Sjhb
1141299142Sjhb	/*
1142303835Svangyzen	 * During attach the child "pci" device is added synchronously;
1143299142Sjhb	 * otherwise, the task is scheduled to manage the child
1144299142Sjhb	 * device.
1145299142Sjhb	 */
1146299142Sjhb	if (schedule_task &&
1147299142Sjhb	    (pcib_hotplug_present(sc) != 0) != (sc->child != NULL))
1148299142Sjhb		taskqueue_enqueue(taskqueue_thread, &sc->pcie_hp_task);
1149299142Sjhb}
1150299142Sjhb
1151299142Sjhbstatic void
1152299142Sjhbpcib_pcie_intr(void *arg)
1153299142Sjhb{
1154299142Sjhb	struct pcib_softc *sc;
1155299142Sjhb	device_t dev;
1156299142Sjhb
1157299142Sjhb	sc = arg;
1158299142Sjhb	dev = sc->dev;
1159299142Sjhb	sc->pcie_slot_sta = pcie_read_config(dev, PCIER_SLOT_STA, 2);
1160299142Sjhb
1161299142Sjhb	/* Clear the events just reported. */
1162299142Sjhb	pcie_write_config(dev, PCIER_SLOT_STA, sc->pcie_slot_sta, 2);
1163299142Sjhb
1164304434Svangyzen	if (bootverbose)
1165304434Svangyzen		device_printf(dev, "HotPlug interrupt: %#x\n",
1166304434Svangyzen		    sc->pcie_slot_sta);
1167304434Svangyzen
1168299142Sjhb	if (sc->pcie_slot_sta & PCIEM_SLOT_STA_ABP) {
1169299142Sjhb		if (sc->flags & PCIB_DETACH_PENDING) {
1170299142Sjhb			device_printf(dev,
1171299142Sjhb			    "Attention Button Pressed: Detach Cancelled\n");
1172299142Sjhb			sc->flags &= ~PCIB_DETACH_PENDING;
1173299142Sjhb			callout_stop(&sc->pcie_ab_timer);
1174299142Sjhb		} else {
1175299142Sjhb			device_printf(dev,
1176299142Sjhb		    "Attention Button Pressed: Detaching in 5 seconds\n");
1177299142Sjhb			sc->flags |= PCIB_DETACH_PENDING;
1178299142Sjhb			callout_reset(&sc->pcie_ab_timer, 5 * hz,
1179299142Sjhb			    pcib_pcie_ab_timeout, sc);
1180299142Sjhb		}
1181299142Sjhb	}
1182299142Sjhb	if (sc->pcie_slot_sta & PCIEM_SLOT_STA_PFD)
1183299142Sjhb		device_printf(dev, "Power Fault Detected\n");
1184299142Sjhb	if (sc->pcie_slot_sta & PCIEM_SLOT_STA_MRLSC)
1185299142Sjhb		device_printf(dev, "MRL Sensor Changed to %s\n",
1186299142Sjhb		    sc->pcie_slot_sta & PCIEM_SLOT_STA_MRLSS ? "open" :
1187299142Sjhb		    "closed");
1188299142Sjhb	if (bootverbose && sc->pcie_slot_sta & PCIEM_SLOT_STA_PDC)
1189304434Svangyzen		device_printf(dev, "Presence Detect Changed to %s\n",
1190299142Sjhb		    sc->pcie_slot_sta & PCIEM_SLOT_STA_PDS ? "card present" :
1191299142Sjhb		    "empty");
1192299142Sjhb	if (sc->pcie_slot_sta & PCIEM_SLOT_STA_CC)
1193299142Sjhb		pcib_pcie_hotplug_command_completed(sc);
1194299142Sjhb	if (sc->pcie_slot_sta & PCIEM_SLOT_STA_DLLSC) {
1195299142Sjhb		sc->pcie_link_sta = pcie_read_config(dev, PCIER_LINK_STA, 2);
1196299142Sjhb		if (bootverbose)
1197299142Sjhb			device_printf(dev,
1198299142Sjhb			    "Data Link Layer State Changed to %s\n",
1199299142Sjhb			    sc->pcie_link_sta & PCIEM_LINK_STA_DL_ACTIVE ?
1200299142Sjhb			    "active" : "inactive");
1201299142Sjhb	}
1202299142Sjhb
1203299142Sjhb	pcib_pcie_hotplug_update(sc, 0, 0, true);
1204299142Sjhb}
1205299142Sjhb
1206299142Sjhbstatic void
1207299142Sjhbpcib_pcie_hotplug_task(void *context, int pending)
1208299142Sjhb{
1209299142Sjhb	struct pcib_softc *sc;
1210299142Sjhb	device_t dev;
1211299142Sjhb
1212299142Sjhb	sc = context;
1213299142Sjhb	mtx_lock(&Giant);
1214299142Sjhb	dev = sc->dev;
1215299142Sjhb	if (pcib_hotplug_present(sc) != 0) {
1216299142Sjhb		if (sc->child == NULL) {
1217299142Sjhb			sc->child = device_add_child(dev, "pci", -1);
1218299142Sjhb			bus_generic_attach(dev);
1219299142Sjhb		}
1220299142Sjhb	} else {
1221299142Sjhb		if (sc->child != NULL) {
1222299142Sjhb			if (device_delete_child(dev, sc->child) == 0)
1223299142Sjhb				sc->child = NULL;
1224299142Sjhb		}
1225299142Sjhb	}
1226299142Sjhb	mtx_unlock(&Giant);
1227299142Sjhb}
1228299142Sjhb
1229299142Sjhbstatic void
1230299142Sjhbpcib_pcie_ab_timeout(void *arg)
1231299142Sjhb{
1232299142Sjhb	struct pcib_softc *sc;
1233299142Sjhb	device_t dev;
1234299142Sjhb
1235299142Sjhb	sc = arg;
1236299142Sjhb	dev = sc->dev;
1237299142Sjhb	mtx_assert(&Giant, MA_OWNED);
1238299142Sjhb	if (sc->flags & PCIB_DETACH_PENDING) {
1239299142Sjhb		sc->flags |= PCIB_DETACHING;
1240299142Sjhb		sc->flags &= ~PCIB_DETACH_PENDING;
1241299142Sjhb		pcib_pcie_hotplug_update(sc, 0, 0, true);
1242299142Sjhb	}
1243299142Sjhb}
1244299142Sjhb
1245299142Sjhbstatic void
1246299142Sjhbpcib_pcie_cc_timeout(void *arg)
1247299142Sjhb{
1248299142Sjhb	struct pcib_softc *sc;
1249299142Sjhb	device_t dev;
1250300249Sjhb	uint16_t sta;
1251299142Sjhb
1252299142Sjhb	sc = arg;
1253299142Sjhb	dev = sc->dev;
1254299142Sjhb	mtx_assert(&Giant, MA_OWNED);
1255300249Sjhb	sta = pcie_read_config(dev, PCIER_SLOT_STA, 2);
1256300249Sjhb	if (!(sta & PCIEM_SLOT_STA_CC)) {
1257299142Sjhb		device_printf(dev,
1258304434Svangyzen		    "HotPlug Command Timed Out - forcing detach\n");
1259299142Sjhb		sc->flags &= ~(PCIB_HOTPLUG_CMD_PENDING | PCIB_DETACH_PENDING);
1260299142Sjhb		sc->flags |= PCIB_DETACHING;
1261299142Sjhb		pcib_pcie_hotplug_update(sc, 0, 0, true);
1262300249Sjhb	} else {
1263300249Sjhb		device_printf(dev,
1264300249Sjhb	    "Missed HotPlug interrupt waiting for Command Completion\n");
1265300249Sjhb		pcib_pcie_intr(sc);
1266299142Sjhb	}
1267299142Sjhb}
1268299142Sjhb
1269299142Sjhbstatic void
1270299142Sjhbpcib_pcie_dll_timeout(void *arg)
1271299142Sjhb{
1272299142Sjhb	struct pcib_softc *sc;
1273299142Sjhb	device_t dev;
1274299142Sjhb	uint16_t sta;
1275299142Sjhb
1276299142Sjhb	sc = arg;
1277299142Sjhb	dev = sc->dev;
1278299142Sjhb	mtx_assert(&Giant, MA_OWNED);
1279299142Sjhb	sta = pcie_read_config(dev, PCIER_LINK_STA, 2);
1280299142Sjhb	if (!(sta & PCIEM_LINK_STA_DL_ACTIVE)) {
1281299142Sjhb		device_printf(dev,
1282299142Sjhb		    "Timed out waiting for Data Link Layer Active\n");
1283299142Sjhb		sc->flags |= PCIB_DETACHING;
1284299142Sjhb		pcib_pcie_hotplug_update(sc, 0, 0, true);
1285299142Sjhb	} else if (sta != sc->pcie_link_sta) {
1286299142Sjhb		device_printf(dev,
1287299142Sjhb		    "Missed HotPlug interrupt waiting for DLL Active\n");
1288299142Sjhb		pcib_pcie_intr(sc);
1289299142Sjhb	}
1290299142Sjhb}
1291299142Sjhb
1292299142Sjhbstatic int
1293299142Sjhbpcib_alloc_pcie_irq(struct pcib_softc *sc)
1294299142Sjhb{
1295299142Sjhb	device_t dev;
1296299142Sjhb	int count, error, rid;
1297299142Sjhb
1298299142Sjhb	rid = -1;
1299299142Sjhb	dev = sc->dev;
1300299142Sjhb
1301299142Sjhb	/*
1302299142Sjhb	 * For simplicity, only use MSI-X if there is a single message.
1303299142Sjhb	 * To support a device with multiple messages we would have to
1304299142Sjhb	 * use remap intr if the MSI number is not 0.
1305299142Sjhb	 */
1306299142Sjhb	count = pci_msix_count(dev);
1307299142Sjhb	if (count == 1) {
1308299142Sjhb		error = pci_alloc_msix(dev, &count);
1309299142Sjhb		if (error == 0)
1310299142Sjhb			rid = 1;
1311299142Sjhb	}
1312299142Sjhb
1313299142Sjhb	if (rid < 0 && pci_msi_count(dev) > 0) {
1314299142Sjhb		count = 1;
1315299142Sjhb		error = pci_alloc_msi(dev, &count);
1316299142Sjhb		if (error == 0)
1317299142Sjhb			rid = 1;
1318299142Sjhb	}
1319299142Sjhb
1320299142Sjhb	if (rid < 0)
1321299142Sjhb		rid = 0;
1322299142Sjhb
1323299142Sjhb	sc->pcie_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
1324299142Sjhb	    RF_ACTIVE);
1325299142Sjhb	if (sc->pcie_irq == NULL) {
1326299142Sjhb		device_printf(dev,
1327299142Sjhb		    "Failed to allocate interrupt for PCI-e events\n");
1328299142Sjhb		if (rid > 0)
1329299142Sjhb			pci_release_msi(dev);
1330299142Sjhb		return (ENXIO);
1331299142Sjhb	}
1332299142Sjhb
1333299142Sjhb	error = bus_setup_intr(dev, sc->pcie_irq, INTR_TYPE_MISC,
1334299142Sjhb	    NULL, pcib_pcie_intr, sc, &sc->pcie_ihand);
1335299142Sjhb	if (error) {
1336299142Sjhb		device_printf(dev, "Failed to setup PCI-e interrupt handler\n");
1337299142Sjhb		bus_release_resource(dev, SYS_RES_IRQ, rid, sc->pcie_irq);
1338299142Sjhb		if (rid > 0)
1339299142Sjhb			pci_release_msi(dev);
1340299142Sjhb		return (error);
1341299142Sjhb	}
1342299142Sjhb	return (0);
1343299142Sjhb}
1344299142Sjhb
1345300249Sjhbstatic int
1346300249Sjhbpcib_release_pcie_irq(struct pcib_softc *sc)
1347300249Sjhb{
1348300249Sjhb	device_t dev;
1349300249Sjhb	int error;
1350300249Sjhb
1351300249Sjhb	dev = sc->dev;
1352300249Sjhb	error = bus_teardown_intr(dev, sc->pcie_irq, sc->pcie_ihand);
1353300249Sjhb	if (error)
1354300249Sjhb		return (error);
1355300249Sjhb	error = bus_free_resource(dev, SYS_RES_IRQ, sc->pcie_irq);
1356300249Sjhb	if (error)
1357300249Sjhb		return (error);
1358300249Sjhb	return (pci_release_msi(dev));
1359300249Sjhb}
1360300249Sjhb
1361299142Sjhbstatic void
1362299142Sjhbpcib_setup_hotplug(struct pcib_softc *sc)
1363299142Sjhb{
1364299142Sjhb	device_t dev;
1365299142Sjhb	uint16_t mask, val;
1366299142Sjhb
1367299142Sjhb	dev = sc->dev;
1368299142Sjhb	callout_init(&sc->pcie_ab_timer, 0);
1369299142Sjhb	callout_init(&sc->pcie_cc_timer, 0);
1370299142Sjhb	callout_init(&sc->pcie_dll_timer, 0);
1371299142Sjhb	TASK_INIT(&sc->pcie_hp_task, 0, pcib_pcie_hotplug_task, sc);
1372299142Sjhb
1373299142Sjhb	/* Allocate IRQ. */
1374299142Sjhb	if (pcib_alloc_pcie_irq(sc) != 0)
1375299142Sjhb		return;
1376299142Sjhb
1377299142Sjhb	sc->pcie_link_sta = pcie_read_config(dev, PCIER_LINK_STA, 2);
1378299142Sjhb	sc->pcie_slot_sta = pcie_read_config(dev, PCIER_SLOT_STA, 2);
1379299142Sjhb
1380300249Sjhb	/* Clear any events previously pending. */
1381300249Sjhb	pcie_write_config(dev, PCIER_SLOT_STA, sc->pcie_slot_sta, 2);
1382300249Sjhb
1383299142Sjhb	/* Enable HotPlug events. */
1384299142Sjhb	mask = PCIEM_SLOT_CTL_DLLSCE | PCIEM_SLOT_CTL_HPIE |
1385299142Sjhb	    PCIEM_SLOT_CTL_CCIE | PCIEM_SLOT_CTL_PDCE | PCIEM_SLOT_CTL_MRLSCE |
1386299142Sjhb	    PCIEM_SLOT_CTL_PFDE | PCIEM_SLOT_CTL_ABPE;
1387299142Sjhb	val = PCIEM_SLOT_CTL_PDCE | PCIEM_SLOT_CTL_HPIE;
1388299142Sjhb	if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_APB)
1389299142Sjhb		val |= PCIEM_SLOT_CTL_ABPE;
1390299142Sjhb	if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_PCP)
1391299142Sjhb		val |= PCIEM_SLOT_CTL_PFDE;
1392299142Sjhb	if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_MRLSP)
1393299142Sjhb		val |= PCIEM_SLOT_CTL_MRLSCE;
1394299142Sjhb	if (!(sc->pcie_slot_cap & PCIEM_SLOT_CAP_NCCS))
1395299142Sjhb		val |= PCIEM_SLOT_CTL_CCIE;
1396299142Sjhb	if (sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE)
1397299142Sjhb		val |= PCIEM_SLOT_CTL_DLLSCE;
1398299142Sjhb
1399299142Sjhb	/* Turn the attention indicator off. */
1400299142Sjhb	if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_AIP) {
1401299142Sjhb		mask |= PCIEM_SLOT_CTL_AIC;
1402299142Sjhb		val |= PCIEM_SLOT_CTL_AI_OFF;
1403299142Sjhb	}
1404299142Sjhb
1405299142Sjhb	pcib_pcie_hotplug_update(sc, val, mask, false);
1406299142Sjhb}
1407300249Sjhb
1408300249Sjhbstatic int
1409300249Sjhbpcib_detach_hotplug(struct pcib_softc *sc)
1410300249Sjhb{
1411300249Sjhb	uint16_t mask, val;
1412300249Sjhb	int error;
1413300249Sjhb
1414300249Sjhb	/* Disable the card in the slot and force it to detach. */
1415300249Sjhb	if (sc->flags & PCIB_DETACH_PENDING) {
1416300249Sjhb		sc->flags &= ~PCIB_DETACH_PENDING;
1417300249Sjhb		callout_stop(&sc->pcie_ab_timer);
1418300249Sjhb	}
1419300249Sjhb	sc->flags |= PCIB_DETACHING;
1420300249Sjhb
1421300249Sjhb	if (sc->flags & PCIB_HOTPLUG_CMD_PENDING) {
1422300249Sjhb		callout_stop(&sc->pcie_cc_timer);
1423300249Sjhb		tsleep(sc, 0, "hpcmd", hz);
1424300249Sjhb		sc->flags &= ~PCIB_HOTPLUG_CMD_PENDING;
1425300249Sjhb	}
1426300249Sjhb
1427300249Sjhb	/* Disable HotPlug events. */
1428300249Sjhb	mask = PCIEM_SLOT_CTL_DLLSCE | PCIEM_SLOT_CTL_HPIE |
1429300249Sjhb	    PCIEM_SLOT_CTL_CCIE | PCIEM_SLOT_CTL_PDCE | PCIEM_SLOT_CTL_MRLSCE |
1430300249Sjhb	    PCIEM_SLOT_CTL_PFDE | PCIEM_SLOT_CTL_ABPE;
1431300249Sjhb	val = 0;
1432300249Sjhb
1433300249Sjhb	/* Turn the attention indicator off. */
1434300249Sjhb	if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_AIP) {
1435300249Sjhb		mask |= PCIEM_SLOT_CTL_AIC;
1436300249Sjhb		val |= PCIEM_SLOT_CTL_AI_OFF;
1437300249Sjhb	}
1438300249Sjhb
1439300249Sjhb	pcib_pcie_hotplug_update(sc, val, mask, false);
1440300249Sjhb
1441300249Sjhb	error = pcib_release_pcie_irq(sc);
1442300249Sjhb	if (error)
1443300249Sjhb		return (error);
1444300249Sjhb	taskqueue_drain(taskqueue_thread, &sc->pcie_hp_task);
1445300249Sjhb	callout_drain(&sc->pcie_ab_timer);
1446300249Sjhb	callout_drain(&sc->pcie_cc_timer);
1447300249Sjhb	callout_drain(&sc->pcie_dll_timer);
1448300249Sjhb	return (0);
1449300249Sjhb}
1450299142Sjhb#endif
1451299142Sjhb
1452299142Sjhb/*
1453200341Sjkim * Get current bridge configuration.
1454200341Sjkim */
1455200341Sjkimstatic void
1456200341Sjkimpcib_cfg_save(struct pcib_softc *sc)
1457200341Sjkim{
1458281874Sjhb#ifndef NEW_PCIB
1459200341Sjkim	device_t	dev;
1460281874Sjhb	uint16_t command;
1461200341Sjkim
1462200341Sjkim	dev = sc->dev;
1463200341Sjkim
1464281874Sjhb	command = pci_read_config(dev, PCIR_COMMAND, 2);
1465281874Sjhb	if (command & PCIM_CMD_PORTEN)
1466200341Sjkim		pcib_get_io_decode(sc);
1467281874Sjhb	if (command & PCIM_CMD_MEMEN)
1468200341Sjkim		pcib_get_mem_decode(sc);
1469221393Sjhb#endif
1470200341Sjkim}
1471200341Sjkim
1472200341Sjkim/*
1473200341Sjkim * Restore previous bridge configuration.
1474200341Sjkim */
1475200341Sjkimstatic void
1476200341Sjkimpcib_cfg_restore(struct pcib_softc *sc)
1477200341Sjkim{
1478200341Sjkim	device_t	dev;
1479281874Sjhb#ifndef NEW_PCIB
1480281874Sjhb	uint16_t command;
1481281874Sjhb#endif
1482200341Sjkim	dev = sc->dev;
1483200341Sjkim
1484221393Sjhb#ifdef NEW_PCIB
1485221393Sjhb	pcib_write_windows(sc, WIN_IO | WIN_MEM | WIN_PMEM);
1486221393Sjhb#else
1487281874Sjhb	command = pci_read_config(dev, PCIR_COMMAND, 2);
1488281874Sjhb	if (command & PCIM_CMD_PORTEN)
1489200341Sjkim		pcib_set_io_decode(sc);
1490281874Sjhb	if (command & PCIM_CMD_MEMEN)
1491200341Sjkim		pcib_set_mem_decode(sc);
1492221393Sjhb#endif
1493200341Sjkim}
1494200341Sjkim
1495200341Sjkim/*
149669783Smsmith * Generic device interface
149769783Smsmith */
149869783Smsmithstatic int
149969783Smsmithpcib_probe(device_t dev)
150069783Smsmith{
150169783Smsmith    if ((pci_get_class(dev) == PCIC_BRIDGE) &&
150269783Smsmith	(pci_get_subclass(dev) == PCIS_BRIDGE_PCI)) {
150369783Smsmith	device_set_desc(dev, "PCI-PCI bridge");
1504284086Smarcel	return(-10000);
150569783Smsmith    }
150669783Smsmith    return(ENXIO);
150769783Smsmith}
150869783Smsmith
1509102441Sjhbvoid
1510102441Sjhbpcib_attach_common(device_t dev)
151169783Smsmith{
151269783Smsmith    struct pcib_softc	*sc;
1513181789Simp    struct sysctl_ctx_list *sctx;
1514181789Simp    struct sysctl_oid	*soid;
1515253450Sjhb    int comma;
151669783Smsmith
151769783Smsmith    sc = device_get_softc(dev);
151869783Smsmith    sc->dev = dev;
151969783Smsmith
152069908Smsmith    /*
152169908Smsmith     * Get current bridge configuration.
152269908Smsmith     */
1523200341Sjkim    sc->domain = pci_get_domain(dev);
1524281874Sjhb#if !(defined(NEW_PCIB) && defined(PCI_RES_BUS))
1525281874Sjhb    sc->bus.sec = pci_read_config(dev, PCIR_SECBUS_1, 1);
1526281874Sjhb    sc->bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1);
1527281874Sjhb#endif
1528281874Sjhb    sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2);
1529200341Sjkim    pcib_cfg_save(sc);
153069783Smsmith
153169908Smsmith    /*
1532261790Sjhb     * The primary bus register should always be the bus of the
1533261790Sjhb     * parent.
1534261790Sjhb     */
1535261790Sjhb    sc->pribus = pci_get_bus(dev);
1536261790Sjhb    pci_write_config(dev, PCIR_PRIBUS_1, sc->pribus, 1);
1537261790Sjhb
1538261790Sjhb    /*
1539181789Simp     * Setup sysctl reporting nodes
1540181789Simp     */
1541181789Simp    sctx = device_get_sysctl_ctx(dev);
1542181789Simp    soid = device_get_sysctl_tree(dev);
1543181789Simp    SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "domain",
1544182706Simp      CTLFLAG_RD, &sc->domain, 0, "Domain number");
1545181789Simp    SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus",
1546182706Simp      CTLFLAG_RD, &sc->pribus, 0, "Primary bus number");
1547181789Simp    SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus",
1548261790Sjhb      CTLFLAG_RD, &sc->bus.sec, 0, "Secondary bus number");
1549181789Simp    SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus",
1550261790Sjhb      CTLFLAG_RD, &sc->bus.sub, 0, "Subordinate bus number");
1551181789Simp
1552181789Simp    /*
155369908Smsmith     * Quirk handling.
155469908Smsmith     */
155569908Smsmith    switch (pci_get_devid(dev)) {
1556281872Sjhb#if !(defined(NEW_PCIB) && defined(PCI_RES_BUS))
1557124365Simp    case 0x12258086:		/* Intel 82454KX/GX (Orion) */
155869908Smsmith	{
1559119266Simp	    uint8_t	supbus;
156069908Smsmith
156169908Smsmith	    supbus = pci_read_config(dev, 0x41, 1);
156269908Smsmith	    if (supbus != 0xff) {
1563261790Sjhb		sc->bus.sec = supbus + 1;
1564261790Sjhb		sc->bus.sub = supbus + 1;
156569908Smsmith	    }
1566124365Simp	    break;
156769908Smsmith	}
1568261790Sjhb#endif
1569124365Simp
1570124365Simp    /*
1571124365Simp     * The i82380FB mobile docking controller is a PCI-PCI bridge,
1572124365Simp     * and it is a subtractive bridge.  However, the ProgIf is wrong
1573124365Simp     * so the normal setting of PCIB_SUBTRACTIVE bit doesn't
1574286480Szbb     * happen.  There are also Toshiba and Cavium ThunderX bridges
1575286480Szbb     * that behave this way.
1576124365Simp     */
1577286480Szbb    case 0xa002177d:		/* Cavium ThunderX */
1578124365Simp    case 0x124b8086:		/* Intel 82380FB Mobile */
1579124365Simp    case 0x060513d7:		/* Toshiba ???? */
1580124365Simp	sc->flags |= PCIB_SUBTRACTIVE;
158169908Smsmith	break;
1582149521Sjkim
1583281872Sjhb#if !(defined(NEW_PCIB) && defined(PCI_RES_BUS))
1584149521Sjkim    /* Compaq R3000 BIOS sets wrong subordinate bus number. */
1585149521Sjkim    case 0x00dd10de:
1586149521Sjkim	{
1587149521Sjkim	    char *cp;
1588149521Sjkim
1589273174Sdavide	    if ((cp = kern_getenv("smbios.planar.maker")) == NULL)
1590149521Sjkim		break;
1591157949Sjkim	    if (strncmp(cp, "Compal", 6) != 0) {
1592157949Sjkim		freeenv(cp);
1593149521Sjkim		break;
1594157949Sjkim	    }
1595157949Sjkim	    freeenv(cp);
1596273174Sdavide	    if ((cp = kern_getenv("smbios.planar.product")) == NULL)
1597157949Sjkim		break;
1598157949Sjkim	    if (strncmp(cp, "08A0", 4) != 0) {
1599157949Sjkim		freeenv(cp);
1600157949Sjkim		break;
1601157949Sjkim	    }
1602157949Sjkim	    freeenv(cp);
1603261790Sjhb	    if (sc->bus.sub < 0xa) {
1604149521Sjkim		pci_write_config(dev, PCIR_SUBBUS_1, 0xa, 1);
1605261790Sjhb		sc->bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1);
1606149521Sjkim	    }
1607149521Sjkim	    break;
1608149521Sjkim	}
1609261790Sjhb#endif
161069908Smsmith    }
161169908Smsmith
1612165995Sjhb    if (pci_msi_device_blacklisted(dev))
1613165995Sjhb	sc->flags |= PCIB_DISABLE_MSI;
1614165995Sjhb
1615253120Smarius    if (pci_msix_device_blacklisted(dev))
1616253120Smarius	sc->flags |= PCIB_DISABLE_MSIX;
1617253120Smarius
1618124365Simp    /*
1619124365Simp     * Intel 815, 845 and other chipsets say they are PCI-PCI bridges,
1620124365Simp     * but have a ProgIF of 0x80.  The 82801 family (AA, AB, BAM/CAM,
1621124365Simp     * BA/CA/DB and E) PCI bridges are HUB-PCI bridges, in Intelese.
1622124365Simp     * This means they act as if they were subtractively decoding
1623124365Simp     * bridges and pass all transactions.  Mark them and real ProgIf 1
1624124365Simp     * parts as subtractive.
1625124365Simp     */
1626124365Simp    if ((pci_get_devid(dev) & 0xff00ffff) == 0x24008086 ||
1627168157Sjhb      pci_read_config(dev, PCIR_PROGIF, 1) == PCIP_BRIDGE_PCI_SUBTRACTIVE)
1628124365Simp	sc->flags |= PCIB_SUBTRACTIVE;
1629221393Sjhb
1630299142Sjhb#ifdef PCI_HP
1631299142Sjhb    pcib_probe_hotplug(sc);
1632299142Sjhb#endif
1633221393Sjhb#ifdef NEW_PCIB
1634261790Sjhb#ifdef PCI_RES_BUS
1635261790Sjhb    pcib_setup_secbus(dev, &sc->bus, 1);
1636261790Sjhb#endif
1637221393Sjhb    pcib_probe_windows(sc);
1638221393Sjhb#endif
1639299142Sjhb#ifdef PCI_HP
1640299142Sjhb    if (sc->flags & PCIB_HOTPLUG)
1641299142Sjhb	    pcib_setup_hotplug(sc);
1642299142Sjhb#endif
164369783Smsmith    if (bootverbose) {
1644172394Smarius	device_printf(dev, "  domain            %d\n", sc->domain);
1645261790Sjhb	device_printf(dev, "  secondary bus     %d\n", sc->bus.sec);
1646261790Sjhb	device_printf(dev, "  subordinate bus   %d\n", sc->bus.sub);
1647221393Sjhb#ifdef NEW_PCIB
1648221393Sjhb	if (pcib_is_window_open(&sc->io))
1649221393Sjhb	    device_printf(dev, "  I/O decode        0x%jx-0x%jx\n",
1650221393Sjhb	      (uintmax_t)sc->io.base, (uintmax_t)sc->io.limit);
1651221393Sjhb	if (pcib_is_window_open(&sc->mem))
1652221393Sjhb	    device_printf(dev, "  memory decode     0x%jx-0x%jx\n",
1653221393Sjhb	      (uintmax_t)sc->mem.base, (uintmax_t)sc->mem.limit);
1654221393Sjhb	if (pcib_is_window_open(&sc->pmem))
1655221393Sjhb	    device_printf(dev, "  prefetched decode 0x%jx-0x%jx\n",
1656221393Sjhb	      (uintmax_t)sc->pmem.base, (uintmax_t)sc->pmem.limit);
1657221393Sjhb#else
1658221393Sjhb	if (pcib_is_io_open(sc))
1659221393Sjhb	    device_printf(dev, "  I/O decode        0x%x-0x%x\n",
1660221393Sjhb	      sc->iobase, sc->iolimit);
1661163805Simp	if (pcib_is_nonprefetch_open(sc))
1662163805Simp	    device_printf(dev, "  memory decode     0x%jx-0x%jx\n",
1663163805Simp	      (uintmax_t)sc->membase, (uintmax_t)sc->memlimit);
1664163805Simp	if (pcib_is_prefetch_open(sc))
1665163805Simp	    device_printf(dev, "  prefetched decode 0x%jx-0x%jx\n",
1666163805Simp	      (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit);
1667221393Sjhb#endif
1668253450Sjhb	if (sc->bridgectl & (PCIB_BCR_ISA_ENABLE | PCIB_BCR_VGA_ENABLE) ||
1669253450Sjhb	    sc->flags & PCIB_SUBTRACTIVE) {
1670253450Sjhb		device_printf(dev, "  special decode    ");
1671253450Sjhb		comma = 0;
1672253450Sjhb		if (sc->bridgectl & PCIB_BCR_ISA_ENABLE) {
1673253450Sjhb			printf("ISA");
1674253450Sjhb			comma = 1;
1675253450Sjhb		}
1676253450Sjhb		if (sc->bridgectl & PCIB_BCR_VGA_ENABLE) {
1677253450Sjhb			printf("%sVGA", comma ? ", " : "");
1678253450Sjhb			comma = 1;
1679253450Sjhb		}
1680253450Sjhb		if (sc->flags & PCIB_SUBTRACTIVE)
1681253450Sjhb			printf("%ssubtractive", comma ? ", " : "");
1682253450Sjhb		printf("\n");
1683253450Sjhb	}
168469783Smsmith    }
168569783Smsmith
168669783Smsmith    /*
1687239103Sjhb     * Always enable busmastering on bridges so that transactions
1688239103Sjhb     * initiated on the secondary bus are passed through to the
1689239103Sjhb     * primary bus.
1690239103Sjhb     */
1691239103Sjhb    pci_enable_busmaster(dev);
1692102441Sjhb}
169369783Smsmith
1694299142Sjhb#ifdef PCI_HP
1695299142Sjhbstatic int
1696299142Sjhbpcib_present(struct pcib_softc *sc)
1697299142Sjhb{
1698299142Sjhb
1699299142Sjhb	if (sc->flags & PCIB_HOTPLUG)
1700299142Sjhb		return (pcib_hotplug_present(sc) != 0);
1701299142Sjhb	return (1);
1702299142Sjhb}
1703299142Sjhb#endif
1704299142Sjhb
1705103042Sjhbint
1706298711Sjhbpcib_attach_child(device_t dev)
1707298711Sjhb{
1708298711Sjhb	struct pcib_softc *sc;
1709298711Sjhb
1710298711Sjhb	sc = device_get_softc(dev);
1711298711Sjhb	if (sc->bus.sec == 0) {
1712298711Sjhb		/* no secondary bus; we should have fixed this */
1713298711Sjhb		return(0);
1714298711Sjhb	}
1715298711Sjhb
1716299142Sjhb#ifdef PCI_HP
1717299142Sjhb	if (!pcib_present(sc)) {
1718299142Sjhb		/* An empty HotPlug slot, so don't add a PCI bus yet. */
1719299142Sjhb		return (0);
1720299142Sjhb	}
1721299142Sjhb#endif
1722299142Sjhb
1723298711Sjhb	sc->child = device_add_child(dev, "pci", -1);
1724298711Sjhb	return (bus_generic_attach(dev));
1725298711Sjhb}
1726298711Sjhb
1727298711Sjhbint
1728102441Sjhbpcib_attach(device_t dev)
1729102441Sjhb{
1730102441Sjhb
1731102441Sjhb    pcib_attach_common(dev);
1732298711Sjhb    return (pcib_attach_child(dev));
173369783Smsmith}
173469783Smsmith
1735102441Sjhbint
1736300249Sjhbpcib_detach(device_t dev)
1737300249Sjhb{
1738300249Sjhb#if defined(PCI_HP) || defined(NEW_PCIB)
1739300249Sjhb	struct pcib_softc *sc;
1740300249Sjhb#endif
1741300249Sjhb	int error;
1742300249Sjhb
1743300249Sjhb#if defined(PCI_HP) || defined(NEW_PCIB)
1744300249Sjhb	sc = device_get_softc(dev);
1745300249Sjhb#endif
1746300249Sjhb	error = bus_generic_detach(dev);
1747300249Sjhb	if (error)
1748300249Sjhb		return (error);
1749300249Sjhb#ifdef PCI_HP
1750300249Sjhb	if (sc->flags & PCIB_HOTPLUG) {
1751300249Sjhb		error = pcib_detach_hotplug(sc);
1752300249Sjhb		if (error)
1753300249Sjhb			return (error);
1754300249Sjhb	}
1755300249Sjhb#endif
1756300249Sjhb	error = device_delete_children(dev);
1757300249Sjhb	if (error)
1758300249Sjhb		return (error);
1759300249Sjhb#ifdef NEW_PCIB
1760300249Sjhb	pcib_free_windows(sc);
1761300249Sjhb#ifdef PCI_RES_BUS
1762300249Sjhb	pcib_free_secbus(dev, &sc->bus);
1763300249Sjhb#endif
1764300249Sjhb#endif
1765300249Sjhb	return (0);
1766300249Sjhb}
1767300249Sjhb
1768300249Sjhbint
1769200341Sjkimpcib_suspend(device_t dev)
1770200341Sjkim{
1771200341Sjkim
1772200341Sjkim	pcib_cfg_save(device_get_softc(dev));
1773281873Sjhb	return (bus_generic_suspend(dev));
1774200341Sjkim}
1775200341Sjkim
1776200341Sjkimint
1777200341Sjkimpcib_resume(device_t dev)
1778200341Sjkim{
1779200341Sjkim
1780200341Sjkim	pcib_cfg_restore(device_get_softc(dev));
1781200341Sjkim	return (bus_generic_resume(dev));
1782200341Sjkim}
1783200341Sjkim
1784282783Sjhibbitsvoid
1785282783Sjhibbitspcib_bridge_init(device_t dev)
1786282783Sjhibbits{
1787282783Sjhibbits	pci_write_config(dev, PCIR_IOBASEL_1, 0xff, 1);
1788282783Sjhibbits	pci_write_config(dev, PCIR_IOBASEH_1, 0xffff, 2);
1789282783Sjhibbits	pci_write_config(dev, PCIR_IOLIMITL_1, 0, 1);
1790282783Sjhibbits	pci_write_config(dev, PCIR_IOLIMITH_1, 0, 2);
1791282783Sjhibbits	pci_write_config(dev, PCIR_MEMBASE_1, 0xffff, 2);
1792282783Sjhibbits	pci_write_config(dev, PCIR_MEMLIMIT_1, 0, 2);
1793282783Sjhibbits	pci_write_config(dev, PCIR_PMBASEL_1, 0xffff, 2);
1794282783Sjhibbits	pci_write_config(dev, PCIR_PMBASEH_1, 0xffffffff, 4);
1795282783Sjhibbits	pci_write_config(dev, PCIR_PMLIMITL_1, 0, 2);
1796282783Sjhibbits	pci_write_config(dev, PCIR_PMLIMITH_1, 0, 4);
1797282783Sjhibbits}
1798282783Sjhibbits
1799200341Sjkimint
1800299142Sjhbpcib_child_present(device_t dev, device_t child)
1801299142Sjhb{
1802299142Sjhb#ifdef PCI_HP
1803299142Sjhb	struct pcib_softc *sc = device_get_softc(dev);
1804299142Sjhb	int retval;
1805299142Sjhb
1806299142Sjhb	retval = bus_child_present(dev);
1807299142Sjhb	if (retval != 0 && sc->flags & PCIB_HOTPLUG)
1808299142Sjhb		retval = pcib_hotplug_present(sc);
1809299142Sjhb	return (retval);
1810299142Sjhb#else
1811299142Sjhb	return (bus_child_present(dev));
1812299142Sjhb#endif
1813299142Sjhb}
1814299142Sjhb
1815299142Sjhbint
181669783Smsmithpcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
181769783Smsmith{
181869783Smsmith    struct pcib_softc	*sc = device_get_softc(dev);
1819289494Sjmg
182069783Smsmith    switch (which) {
1821172394Smarius    case PCIB_IVAR_DOMAIN:
1822172394Smarius	*result = sc->domain;
1823172394Smarius	return(0);
182469783Smsmith    case PCIB_IVAR_BUS:
1825261790Sjhb	*result = sc->bus.sec;
182669783Smsmith	return(0);
182769783Smsmith    }
182869783Smsmith    return(ENOENT);
182969783Smsmith}
183069783Smsmith
1831102441Sjhbint
183269783Smsmithpcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
183369783Smsmith{
183469783Smsmith
183569783Smsmith    switch (which) {
1836172394Smarius    case PCIB_IVAR_DOMAIN:
1837172394Smarius	return(EINVAL);
183869783Smsmith    case PCIB_IVAR_BUS:
1839261790Sjhb	return(EINVAL);
184069783Smsmith    }
184169783Smsmith    return(ENOENT);
184269783Smsmith}
184369783Smsmith
1844221393Sjhb#ifdef NEW_PCIB
184569783Smsmith/*
1846221393Sjhb * Attempt to allocate a resource from the existing resources assigned
1847221393Sjhb * to a window.
1848221393Sjhb */
1849221393Sjhbstatic struct resource *
1850221393Sjhbpcib_suballoc_resource(struct pcib_softc *sc, struct pcib_window *w,
1851294883Sjhibbits    device_t child, int type, int *rid, rman_res_t start, rman_res_t end,
1852294883Sjhibbits    rman_res_t count, u_int flags)
1853221393Sjhb{
1854221393Sjhb	struct resource *res;
1855221393Sjhb
1856221393Sjhb	if (!pcib_is_window_open(w))
1857221393Sjhb		return (NULL);
1858221393Sjhb
1859221393Sjhb	res = rman_reserve_resource(&w->rman, start, end, count,
1860221393Sjhb	    flags & ~RF_ACTIVE, child);
1861221393Sjhb	if (res == NULL)
1862221393Sjhb		return (NULL);
1863221393Sjhb
1864221393Sjhb	if (bootverbose)
1865221393Sjhb		device_printf(sc->dev,
1866297000Sjhibbits		    "allocated %s range (%#jx-%#jx) for rid %x of %s\n",
1867221393Sjhb		    w->name, rman_get_start(res), rman_get_end(res), *rid,
1868221393Sjhb		    pcib_child_name(child));
1869221393Sjhb	rman_set_rid(res, *rid);
1870221393Sjhb
1871221393Sjhb	/*
1872221393Sjhb	 * If the resource should be active, pass that request up the
1873221393Sjhb	 * tree.  This assumes the parent drivers can handle
1874221393Sjhb	 * activating sub-allocated resources.
1875221393Sjhb	 */
1876221393Sjhb	if (flags & RF_ACTIVE) {
1877221393Sjhb		if (bus_activate_resource(child, type, *rid, res) != 0) {
1878221393Sjhb			rman_release_resource(res);
1879221393Sjhb			return (NULL);
1880221393Sjhb		}
1881221393Sjhb	}
1882221393Sjhb
1883221393Sjhb	return (res);
1884221393Sjhb}
1885221393Sjhb
1886253450Sjhb/* Allocate a fresh resource range for an unconfigured window. */
1887253450Sjhbstatic int
1888253450Sjhbpcib_alloc_new_window(struct pcib_softc *sc, struct pcib_window *w, int type,
1889294883Sjhibbits    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
1890253450Sjhb{
1891253450Sjhb	struct resource *res;
1892294883Sjhibbits	rman_res_t base, limit, wmask;
1893253450Sjhb	int rid;
1894253450Sjhb
1895253450Sjhb	/*
1896253450Sjhb	 * If this is an I/O window on a bridge with ISA enable set
1897253450Sjhb	 * and the start address is below 64k, then try to allocate an
1898253450Sjhb	 * initial window of 0x1000 bytes long starting at address
1899253450Sjhb	 * 0xf000 and walking down.  Note that if the original request
1900253450Sjhb	 * was larger than the non-aliased range size of 0x100 our
1901253450Sjhb	 * caller would have raised the start address up to 64k
1902253450Sjhb	 * already.
1903253450Sjhb	 */
1904253450Sjhb	if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE &&
1905253450Sjhb	    start < 65536) {
1906253450Sjhb		for (base = 0xf000; (long)base >= 0; base -= 0x1000) {
1907253450Sjhb			limit = base + 0xfff;
1908253450Sjhb
1909253450Sjhb			/*
1910253450Sjhb			 * Skip ranges that wouldn't work for the
1911253450Sjhb			 * original request.  Note that the actual
1912253450Sjhb			 * window that overlaps are the non-alias
1913253450Sjhb			 * ranges within [base, limit], so this isn't
1914253450Sjhb			 * quite a simple comparison.
1915253450Sjhb			 */
1916253450Sjhb			if (start + count > limit - 0x400)
1917253450Sjhb				continue;
1918253450Sjhb			if (base == 0) {
1919253450Sjhb				/*
1920253450Sjhb				 * The first open region for the window at
1921253450Sjhb				 * 0 is 0x400-0x4ff.
1922253450Sjhb				 */
1923253450Sjhb				if (end - count + 1 < 0x400)
1924253450Sjhb					continue;
1925253450Sjhb			} else {
1926253450Sjhb				if (end - count + 1 < base)
1927253450Sjhb					continue;
1928253450Sjhb			}
1929253450Sjhb
1930253450Sjhb			if (pcib_alloc_nonisa_ranges(sc, base, limit) == 0) {
1931253450Sjhb				w->base = base;
1932253450Sjhb				w->limit = limit;
1933253450Sjhb				return (0);
1934253450Sjhb			}
1935253450Sjhb		}
1936289494Sjmg		return (ENOSPC);
1937253450Sjhb	}
1938289494Sjmg
1939295664Sjhibbits	wmask = ((rman_res_t)1 << w->step) - 1;
1940253450Sjhb	if (RF_ALIGNMENT(flags) < w->step) {
1941253450Sjhb		flags &= ~RF_ALIGNMENT_MASK;
1942253450Sjhb		flags |= RF_ALIGNMENT_LOG2(w->step);
1943253450Sjhb	}
1944253450Sjhb	start &= ~wmask;
1945253450Sjhb	end |= wmask;
1946295664Sjhibbits	count = roundup2(count, (rman_res_t)1 << w->step);
1947253450Sjhb	rid = w->reg;
1948253450Sjhb	res = bus_alloc_resource(sc->dev, type, &rid, start, end, count,
1949253450Sjhb	    flags & ~RF_ACTIVE);
1950253450Sjhb	if (res == NULL)
1951253450Sjhb		return (ENOSPC);
1952253450Sjhb	pcib_add_window_resources(w, &res, 1);
1953253450Sjhb	pcib_activate_window(sc, type);
1954253450Sjhb	w->base = rman_get_start(res);
1955253450Sjhb	w->limit = rman_get_end(res);
1956253450Sjhb	return (0);
1957253450Sjhb}
1958253450Sjhb
1959253450Sjhb/* Try to expand an existing window to the requested base and limit. */
1960253450Sjhbstatic int
1961253450Sjhbpcib_expand_window(struct pcib_softc *sc, struct pcib_window *w, int type,
1962294883Sjhibbits    rman_res_t base, rman_res_t limit)
1963253450Sjhb{
1964253450Sjhb	struct resource *res;
1965253450Sjhb	int error, i, force_64k_base;
1966253450Sjhb
1967253450Sjhb	KASSERT(base <= w->base && limit >= w->limit,
1968253450Sjhb	    ("attempting to shrink window"));
1969253450Sjhb
1970253450Sjhb	/*
1971253450Sjhb	 * XXX: pcib_grow_window() doesn't try to do this anyway and
1972253450Sjhb	 * the error handling for all the edge cases would be tedious.
1973253450Sjhb	 */
1974253450Sjhb	KASSERT(limit == w->limit || base == w->base,
1975253450Sjhb	    ("attempting to grow both ends of a window"));
1976253450Sjhb
1977253450Sjhb	/*
1978253450Sjhb	 * Yet more special handling for requests to expand an I/O
1979253450Sjhb	 * window behind an ISA-enabled bridge.  Since I/O windows
1980253450Sjhb	 * have to grow in 0x1000 increments and the end of the 0xffff
1981253450Sjhb	 * range is an alias, growing a window below 64k will always
1982253450Sjhb	 * result in allocating new resources and never adjusting an
1983253450Sjhb	 * existing resource.
1984253450Sjhb	 */
1985253450Sjhb	if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE &&
1986253450Sjhb	    (limit <= 65535 || (base <= 65535 && base != w->base))) {
1987253450Sjhb		KASSERT(limit == w->limit || limit <= 65535,
1988253450Sjhb		    ("attempting to grow both ends across 64k ISA alias"));
1989253450Sjhb
1990253450Sjhb		if (base != w->base)
1991253450Sjhb			error = pcib_alloc_nonisa_ranges(sc, base, w->base - 1);
1992253450Sjhb		else
1993253450Sjhb			error = pcib_alloc_nonisa_ranges(sc, w->limit + 1,
1994253450Sjhb			    limit);
1995253450Sjhb		if (error == 0) {
1996253450Sjhb			w->base = base;
1997253450Sjhb			w->limit = limit;
1998253450Sjhb		}
1999253450Sjhb		return (error);
2000253450Sjhb	}
2001253450Sjhb
2002253450Sjhb	/*
2003253450Sjhb	 * Find the existing resource to adjust.  Usually there is only one,
2004253450Sjhb	 * but for an ISA-enabled bridge we might be growing the I/O window
2005253450Sjhb	 * above 64k and need to find the existing resource that maps all
2006253450Sjhb	 * of the area above 64k.
2007253450Sjhb	 */
2008253450Sjhb	for (i = 0; i < w->count; i++) {
2009253450Sjhb		if (rman_get_end(w->res[i]) == w->limit)
2010253450Sjhb			break;
2011253450Sjhb	}
2012253450Sjhb	KASSERT(i != w->count, ("did not find existing resource"));
2013253450Sjhb	res = w->res[i];
2014253450Sjhb
2015253450Sjhb	/*
2016253450Sjhb	 * Usually the resource we found should match the window's
2017253450Sjhb	 * existing range.  The one exception is the ISA-enabled case
2018253450Sjhb	 * mentioned above in which case the resource should start at
2019253450Sjhb	 * 64k.
2020253450Sjhb	 */
2021253450Sjhb	if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE &&
2022253450Sjhb	    w->base <= 65535) {
2023253450Sjhb		KASSERT(rman_get_start(res) == 65536,
2024253450Sjhb		    ("existing resource mismatch"));
2025253450Sjhb		force_64k_base = 1;
2026253450Sjhb	} else {
2027253450Sjhb		KASSERT(w->base == rman_get_start(res),
2028253450Sjhb		    ("existing resource mismatch"));
2029253450Sjhb		force_64k_base = 0;
2030289494Sjmg	}
2031253450Sjhb
2032253450Sjhb	error = bus_adjust_resource(sc->dev, type, res, force_64k_base ?
2033253450Sjhb	    rman_get_start(res) : base, limit);
2034253450Sjhb	if (error)
2035253450Sjhb		return (error);
2036253450Sjhb
2037253450Sjhb	/* Add the newly allocated region to the resource manager. */
2038253450Sjhb	if (w->base != base) {
2039253450Sjhb		error = rman_manage_region(&w->rman, base, w->base - 1);
2040253450Sjhb		w->base = base;
2041253450Sjhb	} else {
2042253450Sjhb		error = rman_manage_region(&w->rman, w->limit + 1, limit);
2043253450Sjhb		w->limit = limit;
2044253450Sjhb	}
2045253450Sjhb	if (error) {
2046253450Sjhb		if (bootverbose)
2047253450Sjhb			device_printf(sc->dev,
2048253450Sjhb			    "failed to expand %s resource manager\n", w->name);
2049253450Sjhb		(void)bus_adjust_resource(sc->dev, type, res, force_64k_base ?
2050253450Sjhb		    rman_get_start(res) : w->base, w->limit);
2051253450Sjhb	}
2052253450Sjhb	return (error);
2053253450Sjhb}
2054253450Sjhb
2055221393Sjhb/*
2056221393Sjhb * Attempt to grow a window to make room for a given resource request.
2057221393Sjhb */
2058221393Sjhbstatic int
2059221393Sjhbpcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type,
2060294883Sjhibbits    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
2061221393Sjhb{
2062294883Sjhibbits	rman_res_t align, start_free, end_free, front, back, wmask;
2063253450Sjhb	int error;
2064221393Sjhb
2065221393Sjhb	/*
2066221393Sjhb	 * Clamp the desired resource range to the maximum address
2067221393Sjhb	 * this window supports.  Reject impossible requests.
2068253450Sjhb	 *
2069253450Sjhb	 * For I/O port requests behind a bridge with the ISA enable
2070253450Sjhb	 * bit set, force large allocations to start above 64k.
2071221393Sjhb	 */
2072221393Sjhb	if (!w->valid)
2073221393Sjhb		return (EINVAL);
2074253450Sjhb	if (sc->bridgectl & PCIB_BCR_ISA_ENABLE && count > 0x100 &&
2075253450Sjhb	    start < 65536)
2076253450Sjhb		start = 65536;
2077221393Sjhb	if (end > w->rman.rm_end)
2078221393Sjhb		end = w->rman.rm_end;
2079221393Sjhb	if (start + count - 1 > end || start + count < start)
2080221393Sjhb		return (EINVAL);
2081295664Sjhibbits	wmask = ((rman_res_t)1 << w->step) - 1;
2082221393Sjhb
2083221393Sjhb	/*
2084221393Sjhb	 * If there is no resource at all, just try to allocate enough
2085221393Sjhb	 * aligned space for this resource.
2086221393Sjhb	 */
2087221393Sjhb	if (w->res == NULL) {
2088253450Sjhb		error = pcib_alloc_new_window(sc, w, type, start, end, count,
2089253450Sjhb		    flags);
2090253450Sjhb		if (error) {
2091221393Sjhb			if (bootverbose)
2092221393Sjhb				device_printf(sc->dev,
2093297000Sjhibbits		    "failed to allocate initial %s window (%#jx-%#jx,%#jx)\n",
2094221393Sjhb				    w->name, start, end, count);
2095253450Sjhb			return (error);
2096221393Sjhb		}
2097221393Sjhb		if (bootverbose)
2098221393Sjhb			device_printf(sc->dev,
2099253450Sjhb			    "allocated initial %s window of %#jx-%#jx\n",
2100253450Sjhb			    w->name, (uintmax_t)w->base, (uintmax_t)w->limit);
2101221393Sjhb		goto updatewin;
2102221393Sjhb	}
2103221393Sjhb
2104221393Sjhb	/*
2105221393Sjhb	 * See if growing the window would help.  Compute the minimum
2106221393Sjhb	 * amount of address space needed on both the front and back
2107221393Sjhb	 * ends of the existing window to satisfy the allocation.
2108221393Sjhb	 *
2109221393Sjhb	 * For each end, build a candidate region adjusting for the
2110221393Sjhb	 * required alignment, etc.  If there is a free region at the
2111221393Sjhb	 * edge of the window, grow from the inner edge of the free
2112221393Sjhb	 * region.  Otherwise grow from the window boundary.
2113221393Sjhb	 *
2114253450Sjhb	 * Growing an I/O window below 64k for a bridge with the ISA
2115253450Sjhb	 * enable bit doesn't require any special magic as the step
2116253450Sjhb	 * size of an I/O window (1k) always includes multiple
2117253450Sjhb	 * non-alias ranges when it is grown in either direction.
2118253450Sjhb	 *
2119221393Sjhb	 * XXX: Special case: if w->res is completely empty and the
2120221393Sjhb	 * request size is larger than w->res, we should find the
2121221393Sjhb	 * optimal aligned buffer containing w->res and allocate that.
2122221393Sjhb	 */
2123221393Sjhb	if (bootverbose)
2124221393Sjhb		device_printf(sc->dev,
2125297000Sjhibbits		    "attempting to grow %s window for (%#jx-%#jx,%#jx)\n",
2126221393Sjhb		    w->name, start, end, count);
2127295664Sjhibbits	align = (rman_res_t)1 << RF_ALIGNMENT(flags);
2128253450Sjhb	if (start < w->base) {
2129221393Sjhb		if (rman_first_free_region(&w->rman, &start_free, &end_free) !=
2130253450Sjhb		    0 || start_free != w->base)
2131253450Sjhb			end_free = w->base;
2132221393Sjhb		if (end_free > end)
2133237008Sjhb			end_free = end + 1;
2134221393Sjhb
2135221393Sjhb		/* Move end_free down until it is properly aligned. */
2136221393Sjhb		end_free &= ~(align - 1);
2137222930Sjhb		end_free--;
2138222930Sjhb		front = end_free - (count - 1);
2139221393Sjhb
2140221393Sjhb		/*
2141221393Sjhb		 * The resource would now be allocated at (front,
2142221393Sjhb		 * end_free).  Ensure that fits in the (start, end)
2143221393Sjhb		 * bounds.  end_free is checked above.  If 'front' is
2144221393Sjhb		 * ok, ensure it is properly aligned for this window.
2145221393Sjhb		 * Also check for underflow.
2146221393Sjhb		 */
2147221393Sjhb		if (front >= start && front <= end_free) {
2148221393Sjhb			if (bootverbose)
2149297000Sjhibbits				printf("\tfront candidate range: %#jx-%#jx\n",
2150221393Sjhb				    front, end_free);
2151237272Sjhb			front &= ~wmask;
2152253450Sjhb			front = w->base - front;
2153221393Sjhb		} else
2154221393Sjhb			front = 0;
2155221393Sjhb	} else
2156221393Sjhb		front = 0;
2157253450Sjhb	if (end > w->limit) {
2158221393Sjhb		if (rman_last_free_region(&w->rman, &start_free, &end_free) !=
2159253450Sjhb		    0 || end_free != w->limit)
2160253450Sjhb			start_free = w->limit + 1;
2161221393Sjhb		if (start_free < start)
2162221393Sjhb			start_free = start;
2163221393Sjhb
2164221393Sjhb		/* Move start_free up until it is properly aligned. */
2165221393Sjhb		start_free = roundup2(start_free, align);
2166222930Sjhb		back = start_free + count - 1;
2167221393Sjhb
2168221393Sjhb		/*
2169221393Sjhb		 * The resource would now be allocated at (start_free,
2170221393Sjhb		 * back).  Ensure that fits in the (start, end)
2171221393Sjhb		 * bounds.  start_free is checked above.  If 'back' is
2172221393Sjhb		 * ok, ensure it is properly aligned for this window.
2173221393Sjhb		 * Also check for overflow.
2174221393Sjhb		 */
2175221393Sjhb		if (back <= end && start_free <= back) {
2176221393Sjhb			if (bootverbose)
2177297000Sjhibbits				printf("\tback candidate range: %#jx-%#jx\n",
2178221393Sjhb				    start_free, back);
2179237272Sjhb			back |= wmask;
2180253450Sjhb			back -= w->limit;
2181221393Sjhb		} else
2182221393Sjhb			back = 0;
2183221393Sjhb	} else
2184221393Sjhb		back = 0;
2185221393Sjhb
2186221393Sjhb	/*
2187221393Sjhb	 * Try to allocate the smallest needed region first.
2188221393Sjhb	 * If that fails, fall back to the other region.
2189221393Sjhb	 */
2190221393Sjhb	error = ENOSPC;
2191221393Sjhb	while (front != 0 || back != 0) {
2192221393Sjhb		if (front != 0 && (front <= back || back == 0)) {
2193253450Sjhb			error = pcib_expand_window(sc, w, type, w->base - front,
2194253450Sjhb			    w->limit);
2195221393Sjhb			if (error == 0)
2196221393Sjhb				break;
2197221393Sjhb			front = 0;
2198221393Sjhb		} else {
2199253450Sjhb			error = pcib_expand_window(sc, w, type, w->base,
2200253450Sjhb			    w->limit + back);
2201221393Sjhb			if (error == 0)
2202221393Sjhb				break;
2203221393Sjhb			back = 0;
2204221393Sjhb		}
2205221393Sjhb	}
2206221393Sjhb
2207221393Sjhb	if (error)
2208221393Sjhb		return (error);
2209221393Sjhb	if (bootverbose)
2210253450Sjhb		device_printf(sc->dev, "grew %s window to %#jx-%#jx\n",
2211253450Sjhb		    w->name, (uintmax_t)w->base, (uintmax_t)w->limit);
2212221393Sjhb
2213221393Sjhbupdatewin:
2214253450Sjhb	/* Write the new window. */
2215237272Sjhb	KASSERT((w->base & wmask) == 0, ("start address is not aligned"));
2216237272Sjhb	KASSERT((w->limit & wmask) == wmask, ("end address is not aligned"));
2217221393Sjhb	pcib_write_windows(sc, w->mask);
2218221393Sjhb	return (0);
2219221393Sjhb}
2220221393Sjhb
2221221393Sjhb/*
222269783Smsmith * We have to trap resource allocation requests and ensure that the bridge
222369783Smsmith * is set up to, or capable of handling them.
222469783Smsmith */
2225102441Sjhbstruct resource *
2226221393Sjhbpcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
2227294883Sjhibbits    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
2228221393Sjhb{
2229221393Sjhb	struct pcib_softc *sc;
2230221393Sjhb	struct resource *r;
2231221393Sjhb
2232221393Sjhb	sc = device_get_softc(dev);
2233221393Sjhb
2234221393Sjhb	/*
2235221393Sjhb	 * VGA resources are decoded iff the VGA enable bit is set in
2236221393Sjhb	 * the bridge control register.  VGA resources do not fall into
2237221393Sjhb	 * the resource windows and are passed up to the parent.
2238221393Sjhb	 */
2239221393Sjhb	if ((type == SYS_RES_IOPORT && pci_is_vga_ioport_range(start, end)) ||
2240221393Sjhb	    (type == SYS_RES_MEMORY && pci_is_vga_memory_range(start, end))) {
2241221393Sjhb		if (sc->bridgectl & PCIB_BCR_VGA_ENABLE)
2242221393Sjhb			return (bus_generic_alloc_resource(dev, child, type,
2243221393Sjhb			    rid, start, end, count, flags));
2244221393Sjhb		else
2245221393Sjhb			return (NULL);
2246221393Sjhb	}
2247221393Sjhb
2248221393Sjhb	switch (type) {
2249261790Sjhb#ifdef PCI_RES_BUS
2250261790Sjhb	case PCI_RES_BUS:
2251261790Sjhb		return (pcib_alloc_subbus(&sc->bus, child, rid, start, end,
2252261790Sjhb		    count, flags));
2253261790Sjhb#endif
2254221393Sjhb	case SYS_RES_IOPORT:
2255253450Sjhb		if (pcib_is_isa_range(sc, start, end, count))
2256253450Sjhb			return (NULL);
2257221393Sjhb		r = pcib_suballoc_resource(sc, &sc->io, child, type, rid, start,
2258221393Sjhb		    end, count, flags);
2259237673Smarius		if (r != NULL || (sc->flags & PCIB_SUBTRACTIVE) != 0)
2260221393Sjhb			break;
2261221393Sjhb		if (pcib_grow_window(sc, &sc->io, type, start, end, count,
2262221393Sjhb		    flags) == 0)
2263221393Sjhb			r = pcib_suballoc_resource(sc, &sc->io, child, type,
2264221393Sjhb			    rid, start, end, count, flags);
2265221393Sjhb		break;
2266221393Sjhb	case SYS_RES_MEMORY:
2267221393Sjhb		/*
2268221393Sjhb		 * For prefetchable resources, prefer the prefetchable
2269221393Sjhb		 * memory window, but fall back to the regular memory
2270221393Sjhb		 * window if that fails.  Try both windows before
2271221393Sjhb		 * attempting to grow a window in case the firmware
2272221393Sjhb		 * has used a range in the regular memory window to
2273221393Sjhb		 * map a prefetchable BAR.
2274221393Sjhb		 */
2275221393Sjhb		if (flags & RF_PREFETCHABLE) {
2276221393Sjhb			r = pcib_suballoc_resource(sc, &sc->pmem, child, type,
2277221393Sjhb			    rid, start, end, count, flags);
2278221393Sjhb			if (r != NULL)
2279221393Sjhb				break;
2280221393Sjhb		}
2281221393Sjhb		r = pcib_suballoc_resource(sc, &sc->mem, child, type, rid,
2282221393Sjhb		    start, end, count, flags);
2283237673Smarius		if (r != NULL || (sc->flags & PCIB_SUBTRACTIVE) != 0)
2284221393Sjhb			break;
2285221393Sjhb		if (flags & RF_PREFETCHABLE) {
2286221393Sjhb			if (pcib_grow_window(sc, &sc->pmem, type, start, end,
2287221393Sjhb			    count, flags) == 0) {
2288221393Sjhb				r = pcib_suballoc_resource(sc, &sc->pmem, child,
2289221393Sjhb				    type, rid, start, end, count, flags);
2290221393Sjhb				if (r != NULL)
2291221393Sjhb					break;
2292221393Sjhb			}
2293221393Sjhb		}
2294221393Sjhb		if (pcib_grow_window(sc, &sc->mem, type, start, end, count,
2295221393Sjhb		    flags & ~RF_PREFETCHABLE) == 0)
2296221393Sjhb			r = pcib_suballoc_resource(sc, &sc->mem, child, type,
2297221393Sjhb			    rid, start, end, count, flags);
2298221393Sjhb		break;
2299221393Sjhb	default:
2300221393Sjhb		return (bus_generic_alloc_resource(dev, child, type, rid,
2301221393Sjhb		    start, end, count, flags));
2302221393Sjhb	}
2303221393Sjhb
2304221393Sjhb	/*
2305221393Sjhb	 * If attempts to suballocate from the window fail but this is a
2306221393Sjhb	 * subtractive bridge, pass the request up the tree.
2307221393Sjhb	 */
2308221393Sjhb	if (sc->flags & PCIB_SUBTRACTIVE && r == NULL)
2309221393Sjhb		return (bus_generic_alloc_resource(dev, child, type, rid,
2310221393Sjhb		    start, end, count, flags));
2311221393Sjhb	return (r);
2312221393Sjhb}
2313221393Sjhb
2314221393Sjhbint
2315221393Sjhbpcib_adjust_resource(device_t bus, device_t child, int type, struct resource *r,
2316294883Sjhibbits    rman_res_t start, rman_res_t end)
2317221393Sjhb{
2318221393Sjhb	struct pcib_softc *sc;
2319221393Sjhb
2320221393Sjhb	sc = device_get_softc(bus);
2321221393Sjhb	if (pcib_is_resource_managed(sc, type, r))
2322221393Sjhb		return (rman_adjust_resource(r, start, end));
2323221393Sjhb	return (bus_generic_adjust_resource(bus, child, type, r, start, end));
2324221393Sjhb}
2325221393Sjhb
2326221393Sjhbint
2327221393Sjhbpcib_release_resource(device_t dev, device_t child, int type, int rid,
2328221393Sjhb    struct resource *r)
2329221393Sjhb{
2330221393Sjhb	struct pcib_softc *sc;
2331221393Sjhb	int error;
2332221393Sjhb
2333221393Sjhb	sc = device_get_softc(dev);
2334221393Sjhb	if (pcib_is_resource_managed(sc, type, r)) {
2335221393Sjhb		if (rman_get_flags(r) & RF_ACTIVE) {
2336221393Sjhb			error = bus_deactivate_resource(child, type, rid, r);
2337221393Sjhb			if (error)
2338221393Sjhb				return (error);
2339221393Sjhb		}
2340221393Sjhb		return (rman_release_resource(r));
2341221393Sjhb	}
2342221393Sjhb	return (bus_generic_release_resource(dev, child, type, rid, r));
2343221393Sjhb}
2344221393Sjhb#else
2345221393Sjhb/*
2346221393Sjhb * We have to trap resource allocation requests and ensure that the bridge
2347221393Sjhb * is set up to, or capable of handling them.
2348221393Sjhb */
2349221393Sjhbstruct resource *
2350289494Sjmgpcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
2351294883Sjhibbits    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
235269783Smsmith{
2353124365Simp	struct pcib_softc	*sc = device_get_softc(dev);
2354164130Sjhb	const char *name, *suffix;
2355124365Simp	int ok;
235669783Smsmith
235769783Smsmith	/*
235869783Smsmith	 * Fail the allocation for this range if it's not supported.
235969783Smsmith	 */
2360164130Sjhb	name = device_get_nameunit(child);
2361164130Sjhb	if (name == NULL) {
2362164130Sjhb		name = "";
2363164130Sjhb		suffix = "";
2364164130Sjhb	} else
2365164130Sjhb		suffix = " ";
236669783Smsmith	switch (type) {
236769783Smsmith	case SYS_RES_IOPORT:
2368107546Simp		ok = 0;
2369124365Simp		if (!pcib_is_io_open(sc))
2370124365Simp			break;
2371124365Simp		ok = (start >= sc->iobase && end <= sc->iolimit);
2372145652Smarcel
2373145652Smarcel		/*
2374145652Smarcel		 * Make sure we allow access to VGA I/O addresses when the
2375145652Smarcel		 * bridge has the "VGA Enable" bit set.
2376145652Smarcel		 */
2377145652Smarcel		if (!ok && pci_is_vga_ioport_range(start, end))
2378145652Smarcel			ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0;
2379145652Smarcel
2380124365Simp		if ((sc->flags & PCIB_SUBTRACTIVE) == 0) {
2381124365Simp			if (!ok) {
2382124365Simp				if (start < sc->iobase)
2383124365Simp					start = sc->iobase;
2384124365Simp				if (end > sc->iolimit)
2385124365Simp					end = sc->iolimit;
2386142051Simp				if (start < end)
2387142051Simp					ok = 1;
2388124365Simp			}
2389106844Smdodd		} else {
2390124365Simp			ok = 1;
2391189844Simp#if 0
2392189792Simp			/*
2393189792Simp			 * If we overlap with the subtractive range, then
2394189792Simp			 * pick the upper range to use.
2395189792Simp			 */
2396189792Simp			if (start < sc->iolimit && end > sc->iobase)
2397189792Simp				start = sc->iolimit + 1;
2398189844Simp#endif
2399106844Smdodd		}
2400124365Simp		if (end < start) {
2401297000Sjhibbits			device_printf(dev, "ioport: end (%jx) < start (%jx)\n",
2402142051Simp			    end, start);
2403124365Simp			start = 0;
2404124365Simp			end = 0;
2405124365Simp			ok = 0;
2406124365Simp		}
2407124365Simp		if (!ok) {
2408164130Sjhb			device_printf(dev, "%s%srequested unsupported I/O "
2409297000Sjhibbits			    "range 0x%jx-0x%jx (decoding 0x%x-0x%x)\n",
2410164130Sjhb			    name, suffix, start, end, sc->iobase, sc->iolimit);
2411124365Simp			return (NULL);
2412124365Simp		}
2413124365Simp		if (bootverbose)
2414142051Simp			device_printf(dev,
2415297000Sjhibbits			    "%s%srequested I/O range 0x%jx-0x%jx: in range\n",
2416164130Sjhb			    name, suffix, start, end);
2417124365Simp		break;
241869783Smsmith
241969783Smsmith	case SYS_RES_MEMORY:
2420107546Simp		ok = 0;
2421107546Simp		if (pcib_is_nonprefetch_open(sc))
2422124365Simp			ok = ok || (start >= sc->membase && end <= sc->memlimit);
2423107546Simp		if (pcib_is_prefetch_open(sc))
2424124365Simp			ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit);
2425145652Smarcel
2426145652Smarcel		/*
2427145652Smarcel		 * Make sure we allow access to VGA memory addresses when the
2428145652Smarcel		 * bridge has the "VGA Enable" bit set.
2429145652Smarcel		 */
2430145652Smarcel		if (!ok && pci_is_vga_memory_range(start, end))
2431145652Smarcel			ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0;
2432145652Smarcel
2433124365Simp		if ((sc->flags & PCIB_SUBTRACTIVE) == 0) {
2434124365Simp			if (!ok) {
2435124365Simp				ok = 1;
2436124365Simp				if (flags & RF_PREFETCHABLE) {
2437124365Simp					if (pcib_is_prefetch_open(sc)) {
2438124365Simp						if (start < sc->pmembase)
2439124365Simp							start = sc->pmembase;
2440124365Simp						if (end > sc->pmemlimit)
2441124365Simp							end = sc->pmemlimit;
2442124365Simp					} else {
2443124365Simp						ok = 0;
2444124365Simp					}
2445124365Simp				} else {	/* non-prefetchable */
2446124365Simp					if (pcib_is_nonprefetch_open(sc)) {
2447124365Simp						if (start < sc->membase)
2448124365Simp							start = sc->membase;
2449124365Simp						if (end > sc->memlimit)
2450124365Simp							end = sc->memlimit;
2451124365Simp					} else {
2452124365Simp						ok = 0;
2453124365Simp					}
2454124365Simp				}
2455107546Simp			}
2456107546Simp		} else if (!ok) {
2457124365Simp			ok = 1;	/* subtractive bridge: always ok */
2458189844Simp#if 0
2459124365Simp			if (pcib_is_nonprefetch_open(sc)) {
2460189792Simp				if (start < sc->memlimit && end > sc->membase)
2461189792Simp					start = sc->memlimit + 1;
2462124365Simp			}
2463124365Simp			if (pcib_is_prefetch_open(sc)) {
2464189792Simp				if (start < sc->pmemlimit && end > sc->pmembase)
2465189792Simp					start = sc->pmemlimit + 1;
2466124365Simp			}
2467189844Simp#endif
2468106844Smdodd		}
2469124365Simp		if (end < start) {
2470297000Sjhibbits			device_printf(dev, "memory: end (%jx) < start (%jx)\n",
2471142051Simp			    end, start);
2472124365Simp			start = 0;
2473124365Simp			end = 0;
2474124365Simp			ok = 0;
2475124365Simp		}
2476124365Simp		if (!ok && bootverbose)
2477124365Simp			device_printf(dev,
2478297000Sjhibbits			    "%s%srequested unsupported memory range %#jx-%#jx "
2479163805Simp			    "(decoding %#jx-%#jx, %#jx-%#jx)\n",
2480164130Sjhb			    name, suffix, start, end,
2481163805Simp			    (uintmax_t)sc->membase, (uintmax_t)sc->memlimit,
2482163805Simp			    (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit);
2483124365Simp		if (!ok)
2484124365Simp			return (NULL);
2485124365Simp		if (bootverbose)
2486164130Sjhb			device_printf(dev,"%s%srequested memory range "
2487297000Sjhibbits			    "0x%jx-0x%jx: good\n",
2488164130Sjhb			    name, suffix, start, end);
2489124365Simp		break;
249069908Smsmith
249169783Smsmith	default:
2492124365Simp		break;
249369783Smsmith	}
2494124365Simp	/*
2495124365Simp	 * Bridge is OK decoding this resource, so pass it up.
2496124365Simp	 */
2497142051Simp	return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
2498142051Simp	    count, flags));
249969783Smsmith}
2500221393Sjhb#endif
250169783Smsmith
250269783Smsmith/*
2503264011Srstone * If ARI is enabled on this downstream port, translate the function number
2504264011Srstone * to the non-ARI slot/function.  The downstream port will convert it back in
2505264011Srstone * hardware.  If ARI is not enabled slot and func are not modified.
2506264011Srstone */
2507264011Srstonestatic __inline void
2508264011Srstonepcib_xlate_ari(device_t pcib, int bus, int *slot, int *func)
2509264011Srstone{
2510264011Srstone	struct pcib_softc *sc;
2511264011Srstone	int ari_func;
2512264011Srstone
2513264011Srstone	sc = device_get_softc(pcib);
2514264011Srstone	ari_func = *func;
2515264011Srstone
2516264011Srstone	if (sc->flags & PCIB_ENABLE_ARI) {
2517264011Srstone		KASSERT(*slot == 0,
2518264011Srstone		    ("Non-zero slot number with ARI enabled!"));
2519264011Srstone		*slot = PCIE_ARI_SLOT(ari_func);
2520264011Srstone		*func = PCIE_ARI_FUNC(ari_func);
2521264011Srstone	}
2522264011Srstone}
2523264011Srstone
2524264011Srstone
2525264011Srstonestatic void
2526264011Srstonepcib_enable_ari(struct pcib_softc *sc, uint32_t pcie_pos)
2527264011Srstone{
2528264011Srstone	uint32_t ctl2;
2529264011Srstone
2530264011Srstone	ctl2 = pci_read_config(sc->dev, pcie_pos + PCIER_DEVICE_CTL2, 4);
2531264011Srstone	ctl2 |= PCIEM_CTL2_ARI;
2532264011Srstone	pci_write_config(sc->dev, pcie_pos + PCIER_DEVICE_CTL2, ctl2, 4);
2533264011Srstone
2534264011Srstone	sc->flags |= PCIB_ENABLE_ARI;
2535264011Srstone}
2536264011Srstone
2537264011Srstone/*
253869783Smsmith * PCIB interface.
253969783Smsmith */
2540102441Sjhbint
254169783Smsmithpcib_maxslots(device_t dev)
254269783Smsmith{
2543264011Srstone	return (PCI_SLOTMAX);
254469783Smsmith}
254569783Smsmith
2546264011Srstonestatic int
2547264011Srstonepcib_ari_maxslots(device_t dev)
2548264011Srstone{
2549264011Srstone	struct pcib_softc *sc;
2550264011Srstone
2551264011Srstone	sc = device_get_softc(dev);
2552264011Srstone
2553264011Srstone	if (sc->flags & PCIB_ENABLE_ARI)
2554264011Srstone		return (PCIE_ARI_SLOTMAX);
2555264011Srstone	else
2556264011Srstone		return (PCI_SLOTMAX);
2557264011Srstone}
2558264011Srstone
2559264011Srstonestatic int
2560264011Srstonepcib_ari_maxfuncs(device_t dev)
2561264011Srstone{
2562264011Srstone	struct pcib_softc *sc;
2563264011Srstone
2564264011Srstone	sc = device_get_softc(dev);
2565264011Srstone
2566264011Srstone	if (sc->flags & PCIB_ENABLE_ARI)
2567264011Srstone		return (PCIE_ARI_FUNCMAX);
2568264011Srstone	else
2569264011Srstone		return (PCI_FUNCMAX);
2570264011Srstone}
2571264011Srstone
2572279443Srstonestatic void
2573279443Srstonepcib_ari_decode_rid(device_t pcib, uint16_t rid, int *bus, int *slot,
2574279443Srstone    int *func)
2575279443Srstone{
2576279443Srstone	struct pcib_softc *sc;
2577279443Srstone
2578279443Srstone	sc = device_get_softc(pcib);
2579279443Srstone
2580279443Srstone	*bus = PCI_RID2BUS(rid);
2581279443Srstone	if (sc->flags & PCIB_ENABLE_ARI) {
2582279443Srstone		*slot = PCIE_ARI_RID2SLOT(rid);
2583279443Srstone		*func = PCIE_ARI_RID2FUNC(rid);
2584279443Srstone	} else {
2585279443Srstone		*slot = PCI_RID2SLOT(rid);
2586279443Srstone		*func = PCI_RID2FUNC(rid);
2587279443Srstone	}
2588279443Srstone}
2589279443Srstone
259069783Smsmith/*
259169783Smsmith * Since we are a child of a PCI bus, its parent must support the pcib interface.
259269783Smsmith */
2593264011Srstonestatic uint32_t
2594189792Simppcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width)
259569783Smsmith{
2596299142Sjhb#ifdef PCI_HP
2597299142Sjhb	struct pcib_softc *sc;
2598264011Srstone
2599299142Sjhb	sc = device_get_softc(dev);
2600299142Sjhb	if (!pcib_present(sc)) {
2601299142Sjhb		switch (width) {
2602299142Sjhb		case 2:
2603299142Sjhb			return (0xffff);
2604299142Sjhb		case 1:
2605299142Sjhb			return (0xff);
2606299142Sjhb		default:
2607299142Sjhb			return (0xffffffff);
2608299142Sjhb		}
2609299142Sjhb	}
2610299142Sjhb#endif
2611264011Srstone	pcib_xlate_ari(dev, b, &s, &f);
2612264011Srstone	return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s,
2613264011Srstone	    f, reg, width));
261469783Smsmith}
261569783Smsmith
2616264011Srstonestatic void
2617189792Simppcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, int width)
261869783Smsmith{
2619299142Sjhb#ifdef PCI_HP
2620299142Sjhb	struct pcib_softc *sc;
2621264011Srstone
2622299142Sjhb	sc = device_get_softc(dev);
2623299142Sjhb	if (!pcib_present(sc))
2624299142Sjhb		return;
2625299142Sjhb#endif
2626264011Srstone	pcib_xlate_ari(dev, b, &s, &f);
2627264011Srstone	PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f,
2628264011Srstone	    reg, val, width);
262969783Smsmith}
263069783Smsmith
263169783Smsmith/*
263269783Smsmith * Route an interrupt across a PCI bridge.
263369783Smsmith */
2634109229Sbennoint
263569783Smsmithpcib_route_interrupt(device_t pcib, device_t dev, int pin)
263669783Smsmith{
263769783Smsmith    device_t	bus;
263869783Smsmith    int		parent_intpin;
263969783Smsmith    int		intnum;
264069783Smsmith
2641289494Sjmg    /*
264269783Smsmith     *
264369783Smsmith     * The PCI standard defines a swizzle of the child-side device/intpin to
264469783Smsmith     * the parent-side intpin as follows.
264569783Smsmith     *
264669783Smsmith     * device = device on child bus
264769783Smsmith     * child_intpin = intpin on child bus slot (0-3)
264869783Smsmith     * parent_intpin = intpin on parent bus slot (0-3)
264969783Smsmith     *
265069783Smsmith     * parent_intpin = (device + child_intpin) % 4
265169783Smsmith     */
2652115234Sticso    parent_intpin = (pci_get_slot(dev) + (pin - 1)) % 4;
265369783Smsmith
265469783Smsmith    /*
265569783Smsmith     * Our parent is a PCI bus.  Its parent must export the pcib interface
265669783Smsmith     * which includes the ability to route interrupts.
265769783Smsmith     */
265869783Smsmith    bus = device_get_parent(pcib);
265969783Smsmith    intnum = PCIB_ROUTE_INTERRUPT(device_get_parent(bus), pcib, parent_intpin + 1);
2660131398Sjhb    if (PCI_INTERRUPT_VALID(intnum) && bootverbose) {
2661102977Sjhb	device_printf(pcib, "slot %d INT%c is routed to irq %d\n",
2662102977Sjhb	    pci_get_slot(dev), 'A' + pin - 1, intnum);
266390554Smsmith    }
266469783Smsmith    return(intnum);
266569783Smsmith}
2666107172Sjhb
2667169221Sjhb/* Pass request to alloc MSI/MSI-X messages up to the parent bridge. */
2668164264Sjhbint
2669164264Sjhbpcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs)
2670164264Sjhb{
2671169902Sgallatin	struct pcib_softc *sc = device_get_softc(pcib);
2672164264Sjhb	device_t bus;
2673164264Sjhb
2674165995Sjhb	if (sc->flags & PCIB_DISABLE_MSI)
2675165995Sjhb		return (ENXIO);
2676164264Sjhb	bus = device_get_parent(pcib);
2677164264Sjhb	return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount,
2678164264Sjhb	    irqs));
2679164264Sjhb}
2680164264Sjhb
2681169221Sjhb/* Pass request to release MSI/MSI-X messages up to the parent bridge. */
2682164264Sjhbint
2683164264Sjhbpcib_release_msi(device_t pcib, device_t dev, int count, int *irqs)
2684164264Sjhb{
2685164264Sjhb	device_t bus;
2686164264Sjhb
2687164264Sjhb	bus = device_get_parent(pcib);
2688164264Sjhb	return (PCIB_RELEASE_MSI(device_get_parent(bus), dev, count, irqs));
2689164264Sjhb}
2690164264Sjhb
2691164264Sjhb/* Pass request to alloc an MSI-X message up to the parent bridge. */
2692164264Sjhbint
2693169221Sjhbpcib_alloc_msix(device_t pcib, device_t dev, int *irq)
2694164264Sjhb{
2695169902Sgallatin	struct pcib_softc *sc = device_get_softc(pcib);
2696164264Sjhb	device_t bus;
2697164264Sjhb
2698253120Smarius	if (sc->flags & PCIB_DISABLE_MSIX)
2699165995Sjhb		return (ENXIO);
2700164264Sjhb	bus = device_get_parent(pcib);
2701169221Sjhb	return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq));
2702164264Sjhb}
2703164264Sjhb
2704169221Sjhb/* Pass request to release an MSI-X message up to the parent bridge. */
2705166176Sjhbint
2706169221Sjhbpcib_release_msix(device_t pcib, device_t dev, int irq)
2707166176Sjhb{
2708166176Sjhb	device_t bus;
2709166176Sjhb
2710166176Sjhb	bus = device_get_parent(pcib);
2711169221Sjhb	return (PCIB_RELEASE_MSIX(device_get_parent(bus), dev, irq));
2712166176Sjhb}
2713166176Sjhb
2714169221Sjhb/* Pass request to map MSI/MSI-X message up to parent bridge. */
2715164264Sjhbint
2716169221Sjhbpcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr,
2717169221Sjhb    uint32_t *data)
2718164264Sjhb{
2719164264Sjhb	device_t bus;
2720180753Sluoqi	int error;
2721164264Sjhb
2722164264Sjhb	bus = device_get_parent(pcib);
2723180753Sluoqi	error = PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data);
2724180753Sluoqi	if (error)
2725180753Sluoqi		return (error);
2726180753Sluoqi
2727180753Sluoqi	pci_ht_map_msi(pcib, *addr);
2728180753Sluoqi	return (0);
2729164264Sjhb}
2730164264Sjhb
2731211430Sjhb/* Pass request for device power state up to parent bridge. */
2732211430Sjhbint
2733211430Sjhbpcib_power_for_sleep(device_t pcib, device_t dev, int *pstate)
2734211430Sjhb{
2735211430Sjhb	device_t bus;
2736211430Sjhb
2737211430Sjhb	bus = device_get_parent(pcib);
2738211430Sjhb	return (PCIB_POWER_FOR_SLEEP(bus, dev, pstate));
2739211430Sjhb}
2740264007Srstone
2741279443Srstonestatic int
2742279443Srstonepcib_ari_enabled(device_t pcib)
2743279443Srstone{
2744279443Srstone	struct pcib_softc *sc;
2745279443Srstone
2746279443Srstone	sc = device_get_softc(pcib);
2747279443Srstone
2748279443Srstone	return ((sc->flags & PCIB_ENABLE_ARI) != 0);
2749279443Srstone}
2750279443Srstone
2751299929Sandrewstatic int
2752299929Sandrewpcib_ari_get_id(device_t pcib, device_t dev, enum pci_id_type type,
2753299929Sandrew    uintptr_t *id)
2754264011Srstone{
2755264011Srstone	struct pcib_softc *sc;
2756299932Sandrew	device_t bus_dev;
2757264011Srstone	uint8_t bus, slot, func;
2758264011Srstone
2759299932Sandrew	if (type != PCI_ID_RID) {
2760299932Sandrew		bus_dev = device_get_parent(pcib);
2761299932Sandrew		return (PCIB_GET_ID(device_get_parent(bus_dev), dev, type, id));
2762299932Sandrew	}
2763299929Sandrew
2764264011Srstone	sc = device_get_softc(pcib);
2765264011Srstone
2766264011Srstone	if (sc->flags & PCIB_ENABLE_ARI) {
2767264011Srstone		bus = pci_get_bus(dev);
2768264011Srstone		func = pci_get_function(dev);
2769264011Srstone
2770299929Sandrew		*id = (PCI_ARI_RID(bus, func));
2771264011Srstone	} else {
2772264011Srstone		bus = pci_get_bus(dev);
2773264011Srstone		slot = pci_get_slot(dev);
2774264011Srstone		func = pci_get_function(dev);
2775264011Srstone
2776299929Sandrew		*id = (PCI_RID(bus, slot, func));
2777264011Srstone	}
2778299929Sandrew
2779299929Sandrew	return (0);
2780264011Srstone}
2781264011Srstone
2782264011Srstone/*
2783264011Srstone * Check that the downstream port (pcib) and the endpoint device (dev) both
2784264011Srstone * support ARI.  If so, enable it and return 0, otherwise return an error.
2785264011Srstone */
2786264011Srstonestatic int
2787264011Srstonepcib_try_enable_ari(device_t pcib, device_t dev)
2788264011Srstone{
2789264011Srstone	struct pcib_softc *sc;
2790264011Srstone	int error;
2791264011Srstone	uint32_t cap2;
2792264011Srstone	int ari_cap_off;
2793264011Srstone	uint32_t ari_ver;
2794264011Srstone	uint32_t pcie_pos;
2795264011Srstone
2796264011Srstone	sc = device_get_softc(pcib);
2797264011Srstone
2798264011Srstone	/*
2799264011Srstone	 * ARI is controlled in a register in the PCIe capability structure.
2800264011Srstone	 * If the downstream port does not have the PCIe capability structure
2801264011Srstone	 * then it does not support ARI.
2802264011Srstone	 */
2803264011Srstone	error = pci_find_cap(pcib, PCIY_EXPRESS, &pcie_pos);
2804264011Srstone	if (error != 0)
2805264011Srstone		return (ENODEV);
2806264011Srstone
2807264011Srstone	/* Check that the PCIe port advertises ARI support. */
2808264011Srstone	cap2 = pci_read_config(pcib, pcie_pos + PCIER_DEVICE_CAP2, 4);
2809264011Srstone	if (!(cap2 & PCIEM_CAP2_ARI))
2810264011Srstone		return (ENODEV);
2811264011Srstone
2812264011Srstone	/*
2813264011Srstone	 * Check that the endpoint device advertises ARI support via the ARI
2814264011Srstone	 * extended capability structure.
2815264011Srstone	 */
2816264011Srstone	error = pci_find_extcap(dev, PCIZ_ARI, &ari_cap_off);
2817264011Srstone	if (error != 0)
2818264011Srstone		return (ENODEV);
2819264011Srstone
2820264011Srstone	/*
2821264011Srstone	 * Finally, check that the endpoint device supports the same version
2822264011Srstone	 * of ARI that we do.
2823264011Srstone	 */
2824264011Srstone	ari_ver = pci_read_config(dev, ari_cap_off, 4);
2825264011Srstone	if (PCI_EXTCAP_VER(ari_ver) != PCIB_SUPPORTED_ARI_VER) {
2826264011Srstone		if (bootverbose)
2827264011Srstone			device_printf(pcib,
2828264011Srstone			    "Unsupported version of ARI (%d) detected\n",
2829264011Srstone			    PCI_EXTCAP_VER(ari_ver));
2830264011Srstone
2831264011Srstone		return (ENXIO);
2832264011Srstone	}
2833264011Srstone
2834264011Srstone	pcib_enable_ari(sc, pcie_pos);
2835264011Srstone
2836264011Srstone	return (0);
2837264011Srstone}
2838