apb.c revision 88701
186231Stmm/*-
286231Stmm * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier
386231Stmm * Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
486231Stmm * Copyright (c) 2000 BSDi
586231Stmm * Copyright (c) 2001 Thomas Moestl <tmm@FreeBSD.org>
686231Stmm * All rights reserved.
786231Stmm *
886231Stmm * Redistribution and use in source and binary forms, with or without
986231Stmm * modification, are permitted provided that the following conditions
1086231Stmm * are met:
1186231Stmm * 1. Redistributions of source code must retain the above copyright
1286231Stmm *    notice, this list of conditions and the following disclaimer.
1386231Stmm * 2. Redistributions in binary form must reproduce the above copyright
1486231Stmm *    notice, this list of conditions and the following disclaimer in the
1586231Stmm *    documentation and/or other materials provided with the distribution.
1686231Stmm * 3. The name of the author may not be used to endorse or promote products
1786231Stmm *    derived from this software without specific prior written permission.
1886231Stmm *
1986231Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2086231Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2186231Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2286231Stmm * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2386231Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2486231Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2586231Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2686231Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2786231Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2886231Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2986231Stmm * SUCH DAMAGE.
3086231Stmm *
3186231Stmm *	from: FreeBSD: src/sys/dev/pci/pci_pci.c,v 1.3 2000/12/13
3286231Stmm *
3386231Stmm * $FreeBSD: head/sys/sparc64/pci/apb.c 88701 2001-12-30 16:14:33Z tmm $
3486231Stmm */
3586231Stmm
3686231Stmm/*
3786231Stmm * Support for the Sun APB (Advanced PCI Bridge) PCI-PCI bridge.
3886231Stmm * This bridge does not fully comply to the PCI bridge specification, and is
3986231Stmm * therefore not supported by the generic driver.
4086231Stmm * We can use some pf the pcib methods anyway.
4186231Stmm */
4286231Stmm
4386231Stmm#include <sys/param.h>
4486231Stmm#include <sys/systm.h>
4586231Stmm#include <sys/kernel.h>
4686231Stmm#include <sys/malloc.h>
4786231Stmm#include <sys/bus.h>
4886231Stmm
4986231Stmm#include <machine/resource.h>
5086231Stmm
5186231Stmm#include <pci/pcivar.h>
5286231Stmm#include <pci/pcireg.h>
5386231Stmm
5486231Stmm#include "pcib_if.h"
5586231Stmm
5686231Stmm/*
5786231Stmm * Bridge-specific data.
5886231Stmm */
5986231Stmmstruct apb_softc {
6088369Stmm	device_t	dev;
6188369Stmm	u_int8_t	secbus;		/* secondary bus number */
6288369Stmm	u_int8_t	subbus;		/* subordinate bus number */
6386231Stmm	u_int8_t	iomap;
6486231Stmm	u_int8_t	memmap;
6586231Stmm};
6686231Stmm
6786231Stmmstatic int apb_probe(device_t dev);
6886231Stmmstatic int apb_attach(device_t dev);
6986231Stmmstatic struct resource *apb_alloc_resource(device_t dev, device_t child,
7086231Stmm    int type, int *rid, u_long start, u_long end, u_long count, u_int flags);
7188369Stmmstatic int apb_read_ivar(device_t dev, device_t child, int which,
7288369Stmm    uintptr_t *result);
7388369Stmmstatic int apb_write_ivar(device_t dev, device_t child, int which,
7488369Stmm    uintptr_t value);
7588369Stmmstatic int apb_maxslots(device_t dev);
7688369Stmmstatic u_int32_t apb_read_config(device_t dev, int b, int s, int f, int reg,
7788369Stmm    int width);
7888369Stmmstatic void apb_write_config(device_t dev, int b, int s, int f, int reg,
7988369Stmm    u_int32_t val, int width);
8086231Stmmstatic int apb_route_interrupt(device_t pcib, device_t dev, int pin);
8186231Stmm
8286231Stmmstatic device_method_t apb_methods[] = {
8386231Stmm	/* Device interface */
8486231Stmm	DEVMETHOD(device_probe,		apb_probe),
8586231Stmm	DEVMETHOD(device_attach,	apb_attach),
8686231Stmm	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
8786231Stmm	DEVMETHOD(device_suspend,	bus_generic_suspend),
8886231Stmm	DEVMETHOD(device_resume,	bus_generic_resume),
8986231Stmm
9086231Stmm	/* Bus interface */
9186231Stmm	DEVMETHOD(bus_print_child,	bus_generic_print_child),
9288369Stmm	DEVMETHOD(bus_read_ivar,	apb_read_ivar),
9388369Stmm	DEVMETHOD(bus_write_ivar,	apb_write_ivar),
9486231Stmm	DEVMETHOD(bus_alloc_resource,	apb_alloc_resource),
9586231Stmm	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
9686231Stmm	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
9786231Stmm	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
9886231Stmm	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
9986231Stmm	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
10086231Stmm
10186231Stmm	/* pcib interface */
10288369Stmm	DEVMETHOD(pcib_maxslots,	apb_maxslots),
10388369Stmm	DEVMETHOD(pcib_read_config,	apb_read_config),
10488369Stmm	DEVMETHOD(pcib_write_config,	apb_write_config),
10586231Stmm	DEVMETHOD(pcib_route_interrupt,	apb_route_interrupt),
10686231Stmm
10786231Stmm	{ 0, 0 }
10886231Stmm};
10986231Stmm
11086231Stmmstatic driver_t apb_driver = {
11186231Stmm	"pcib",
11286231Stmm	apb_methods,
11388701Stmm	sizeof(struct apb_softc),
11486231Stmm};
11586231Stmm
11686231Stmmstatic devclass_t apb_devclass;
11786231Stmm
11886231StmmDRIVER_MODULE(apb, pci, apb_driver, apb_devclass, 0, 0);
11986231Stmm
12086231Stmm/* APB specific registers */
12186231Stmm#define	APBR_IOMAP	0xde
12286231Stmm#define	APBR_MEMMAP	0xdf
12386231Stmm
12486231Stmm/* Definitions for the mapping registers */
12586231Stmm#define	APB_IO_SCALE	0x200000
12686231Stmm#define	APB_MEM_SCALE	0x20000000
12786231Stmm
12886231Stmm/*
12986231Stmm * Generic device interface
13086231Stmm */
13186231Stmmstatic int
13286231Stmmapb_probe(device_t dev)
13386231Stmm{
13486231Stmm
13586231Stmm	if (pci_get_vendor(dev) == 0x108e &&	/* Sun */
13686231Stmm	    pci_get_device(dev) == 0x5000)  {	/* APB */
13786231Stmm		device_set_desc(dev, "APB PCI-PCI bridge");
13886231Stmm		return (0);
13986231Stmm	}
14086231Stmm	return (ENXIO);
14186231Stmm}
14286231Stmm
14386231Stmmstatic void
14486231Stmmapb_map_print(u_int8_t map, u_long scale)
14586231Stmm{
14686231Stmm	int i, first;
14786231Stmm
14886231Stmm	for (first = 1, i = 0; i < 8; i++) {
14986231Stmm		if ((map & (1 << i)) != 0) {
15086231Stmm			printf("%s0x%lx-0x%lx", first ? "" : ", ",
15186231Stmm			    i * scale, (i + 1) * scale - 1);
15286231Stmm			first = 0;
15386231Stmm		}
15486231Stmm	}
15586231Stmm}
15686231Stmm
15786231Stmmstatic int
15886231Stmmapb_map_checkrange(u_int8_t map, u_long scale, u_long start, u_long end)
15986231Stmm{
16086231Stmm	int i, ei;
16186231Stmm
16286231Stmm	i = start / scale;
16386231Stmm	ei = end / scale;
16486231Stmm	if (i > 7 || ei > 7)
16586231Stmm		return (0);
16686231Stmm	for (; i <= ei; i++)
16786231Stmm		if ((map & (1 << i)) == 0)
16886231Stmm			return (0);
16986231Stmm	return (1);
17086231Stmm}
17186231Stmm
17286231Stmmstatic int
17386231Stmmapb_attach(device_t dev)
17486231Stmm{
17588369Stmm	struct apb_softc *sc;
17686231Stmm	device_t child;
17786231Stmm
17886231Stmm	sc = device_get_softc(dev);
17986231Stmm	sc->dev = dev;
18086231Stmm
18186231Stmm	/*
18286231Stmm	 * Get current bridge configuration.
18386231Stmm	 */
18486231Stmm	sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1);
18586231Stmm	sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1);
18688369Stmm	sc->iomap = pci_read_config(dev, APBR_IOMAP, 1);
18788369Stmm	sc->memmap = pci_read_config(dev, APBR_MEMMAP, 1);
18886231Stmm
18986231Stmm	if (bootverbose) {
19086231Stmm		device_printf(dev, "  secondary bus     %d\n", sc->secbus);
19186231Stmm		device_printf(dev, "  subordinate bus   %d\n", sc->subbus);
19286231Stmm		device_printf(dev, "  I/O decode        ");
19388369Stmm		apb_map_print(sc->iomap, APB_IO_SCALE);
19486231Stmm		printf("\n");
19586231Stmm		device_printf(dev, "  memory decode     ");
19688369Stmm		apb_map_print(sc->memmap, APB_MEM_SCALE);
19786231Stmm		printf("\n");
19886231Stmm	}
19986231Stmm
20086231Stmm	/*
20186231Stmm	 * XXX If the subordinate bus number is less than the secondary bus
20286231Stmm	 * number, we should pick a better value.  One sensible alternative
20386231Stmm	 * would be to pick 255; the only tradeoff here is that configuration
20486231Stmm	 * transactions would be more widely routed than absolutely necessary.
20586231Stmm	 */
20686231Stmm	if (sc->secbus != 0) {
20786231Stmm		child = device_add_child(dev, "pci", -1);
20886231Stmm		if (child != NULL)
20986231Stmm			return (bus_generic_attach(dev));
21086231Stmm	} else
21186231Stmm		panic("apb_attach: APB with uninitialized secbus");
21286231Stmm
21386231Stmm	/* no secondary bus; we should have fixed this */
21486231Stmm	return (0);
21586231Stmm}
21686231Stmm
21786231Stmm/*
21886231Stmm * We have to trap resource allocation requests and ensure that the bridge
21986231Stmm * is set up to, or capable of handling them.
22086231Stmm */
22186231Stmmstatic struct resource *
22286231Stmmapb_alloc_resource(device_t dev, device_t child, int type, int *rid,
22386231Stmm    u_long start, u_long end, u_long count, u_int flags)
22486231Stmm{
22588369Stmm	struct apb_softc *sc;
22686231Stmm
22786231Stmm	sc = device_get_softc(dev);
22886231Stmm	/*
22986231Stmm	 * If this is a "default" allocation against this rid, we can't work
23086231Stmm	 * out where it's coming from (we should actually never see these) so we
23186231Stmm	 * just have to punt.
23286231Stmm	 */
23386231Stmm	if ((start == 0) && (end == ~0)) {
23486231Stmm		device_printf(dev, "can't decode default resource id %d for "
23586231Stmm		    "%s%d, bypassing\n", *rid, device_get_name(child),
23686231Stmm		    device_get_unit(child));
23786231Stmm	} else {
23886231Stmm		/*
23986231Stmm		 * Fail the allocation for this range if it's not supported.
24086231Stmm		 * XXX we should probably just fix up the bridge decode and
24186231Stmm		 * soldier on.
24286231Stmm		 */
24386231Stmm		switch (type) {
24486231Stmm		case SYS_RES_IOPORT:
24588369Stmm			if (!apb_map_checkrange(sc->iomap, APB_IO_SCALE, start,
24686231Stmm			    end)) {
24786231Stmm				device_printf(dev, "device %s%d requested "
24886231Stmm				    "unsupported I/O range 0x%lx-0x%lx\n",
24986231Stmm				    device_get_name(child),
25086231Stmm				    device_get_unit(child), start, end);
25186231Stmm				return (NULL);
25286231Stmm			}
25386231Stmm			if (bootverbose)
25486231Stmm				device_printf(sc->dev, "device %s%d requested "
25586231Stmm				    "decoded I/O range 0x%lx-0x%lx\n",
25686231Stmm				    device_get_name(child),
25786231Stmm				    device_get_unit(child), start, end);
25886231Stmm			break;
25986231Stmm
26086231Stmm		case SYS_RES_MEMORY:
26188369Stmm			if (!apb_map_checkrange(sc->memmap, APB_MEM_SCALE,
26286231Stmm			    start, end)) {
26386231Stmm				device_printf(dev, "device %s%d requested "
26486231Stmm				    "unsupported memory range 0x%lx-0x%lx\n",
26586231Stmm				    device_get_name(child),
26686231Stmm				    device_get_unit(child), start, end);
26786231Stmm				return (NULL);
26886231Stmm			}
26986231Stmm			if (bootverbose)
27086231Stmm				device_printf(sc->dev, "device %s%d requested "
27186231Stmm				    "decoded memory range 0x%lx-0x%lx\n",
27286231Stmm				    device_get_name(child),
27386231Stmm				    device_get_unit(child), start, end);
27486231Stmm			break;
27586231Stmm
27686231Stmm		default:
27786231Stmm			break;
27886231Stmm		}
27986231Stmm	}
28086231Stmm
28186231Stmm	/*
28286231Stmm	 * Bridge is OK decoding this resource, so pass it up.
28386231Stmm	 */
28486231Stmm	return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
28586231Stmm	    count, flags));
28686231Stmm}
28786231Stmm
28888369Stmmstatic int
28988369Stmmapb_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
29088369Stmm{
29188369Stmm	struct apb_softc *sc = device_get_softc(dev);
29288369Stmm
29388369Stmm	switch (which) {
29488369Stmm	case PCIB_IVAR_BUS:
29588369Stmm		*result = sc->secbus;
29688369Stmm		return (0);
29788369Stmm	}
29888369Stmm	return (ENOENT);
29988369Stmm}
30088369Stmm
30188369Stmmstatic int
30288369Stmmapb_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
30388369Stmm{
30488369Stmm	struct apb_softc *sc = device_get_softc(dev);
30588369Stmm
30688369Stmm	switch (which) {
30788369Stmm	case PCIB_IVAR_BUS:
30888369Stmm		sc->secbus = value;
30988369Stmm		break;
31088369Stmm	}
31188369Stmm	return (ENOENT);
31288369Stmm}
31388369Stmm
31486231Stmm/*
31588369Stmm * PCIB interface.
31688369Stmm */
31788369Stmmstatic int
31888369Stmmapb_maxslots(device_t dev)
31988369Stmm{
32088369Stmm
32188369Stmm	return (PCI_SLOTMAX);
32288369Stmm}
32388369Stmm
32488369Stmm/*
32588369Stmm * Since we are a child of a PCI bus, its parent must support the pcib
32688369Stmm * interface.
32788369Stmm */
32888369Stmmstatic u_int32_t
32988369Stmmapb_read_config(device_t dev, int b, int s, int f, int reg, int width)
33088369Stmm{
33188369Stmm
33288369Stmm	return (PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b,
33388369Stmm	    s, f,  reg, width));
33488369Stmm}
33588369Stmm
33688369Stmmstatic void
33788369Stmmapb_write_config(device_t dev, int b, int s, int f, int reg, u_int32_t val,
33888369Stmm    int width)
33988369Stmm{
34088369Stmm
34188369Stmm	PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg,
34288369Stmm	    val, width);
34388369Stmm}
34488369Stmm
34588369Stmm/*
34686231Stmm * Route an interrupt across a PCI bridge - the APB does not route interrupts,
34786231Stmm * and routing of interrupts that are not preinitialized is not supported yet.
34886231Stmm */
34986231Stmmstatic int
35086231Stmmapb_route_interrupt(device_t pcib, device_t dev, int pin)
35186231Stmm{
35286231Stmm
35386231Stmm	panic("apb_route_interrupt");
35486231Stmm}
355