186231Stmm/*- 286231Stmm * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier 386231Stmm * Copyright (c) 2000 Michael Smith <msmith@freebsd.org> 486231Stmm * Copyright (c) 2000 BSDi 5117119Stmm * Copyright (c) 2001, 2003 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 34153057Smarius#include <sys/cdefs.h> 35153057Smarius__FBSDID("$FreeBSD: releng/11.0/sys/sparc64/pci/apb.c 297000 2016-03-18 01:28:41Z jhibbits $"); 36153057Smarius 3786231Stmm/* 3886231Stmm * Support for the Sun APB (Advanced PCI Bridge) PCI-PCI bridge. 3986231Stmm * This bridge does not fully comply to the PCI bridge specification, and is 4086231Stmm * therefore not supported by the generic driver. 41129051Smarius * We can use some of the pcib methods anyway. 4286231Stmm */ 4386231Stmm 44117119Stmm#include "opt_ofw_pci.h" 45117119Stmm 4686231Stmm#include <sys/param.h> 4786231Stmm#include <sys/systm.h> 4886231Stmm#include <sys/kernel.h> 49130025Sphk#include <sys/module.h> 5086231Stmm#include <sys/bus.h> 51221393Sjhb#include <sys/rman.h> 52225931Smarius#include <sys/sysctl.h> 5386231Stmm 54133589Smarius#include <dev/ofw/ofw_bus.h> 5593067Stmm#include <dev/ofw/openfirm.h> 5693067Stmm 57117119Stmm#include <machine/bus.h> 5886231Stmm#include <machine/resource.h> 5986231Stmm 60119291Simp#include <dev/pci/pcireg.h> 61119291Simp#include <dev/pci/pcivar.h> 62119291Simp#include <dev/pci/pcib_private.h> 6386231Stmm 6486231Stmm#include "pcib_if.h" 6586231Stmm 66117119Stmm#include <sparc64/pci/ofw_pci.h> 67117119Stmm#include <sparc64/pci/ofw_pcib_subr.h> 68117119Stmm 6986231Stmm/* 7086231Stmm * Bridge-specific data. 7186231Stmm */ 7286231Stmmstruct apb_softc { 73117119Stmm struct ofw_pcib_gen_softc sc_bsc; 74153057Smarius uint8_t sc_iomap; 75153057Smarius uint8_t sc_memmap; 7686231Stmm}; 7786231Stmm 78117119Stmmstatic device_probe_t apb_probe; 79117119Stmmstatic device_attach_t apb_attach; 80117119Stmmstatic bus_alloc_resource_t apb_alloc_resource; 81225931Smariusstatic bus_adjust_resource_t apb_adjust_resource; 8286231Stmm 8386231Stmmstatic device_method_t apb_methods[] = { 8486231Stmm /* Device interface */ 8586231Stmm DEVMETHOD(device_probe, apb_probe), 8686231Stmm DEVMETHOD(device_attach, apb_attach), 8786231Stmm 8886231Stmm /* Bus interface */ 8986231Stmm DEVMETHOD(bus_alloc_resource, apb_alloc_resource), 90225931Smarius DEVMETHOD(bus_adjust_resource, apb_adjust_resource), 91225931Smarius DEVMETHOD(bus_release_resource, bus_generic_release_resource), 9286231Stmm 9386231Stmm /* pcib interface */ 94117119Stmm DEVMETHOD(pcib_route_interrupt, ofw_pcib_gen_route_interrupt), 9586231Stmm 96133589Smarius /* ofw_bus interface */ 97133589Smarius DEVMETHOD(ofw_bus_get_node, ofw_pcib_gen_get_node), 98133589Smarius 99227848Smarius DEVMETHOD_END 10086231Stmm}; 10186231Stmm 102154079Sjhbstatic devclass_t pcib_devclass; 10386231Stmm 104216962SmariusDEFINE_CLASS_1(pcib, apb_driver, apb_methods, sizeof(struct apb_softc), 105216962Smarius pcib_driver); 106200874SmariusEARLY_DRIVER_MODULE(apb, pci, apb_driver, pcib_devclass, 0, 0, BUS_PASS_BUS); 107200815SmariusMODULE_DEPEND(apb, pci, 1, 1, 1); 10886231Stmm 10986231Stmm/* APB specific registers */ 11086231Stmm#define APBR_IOMAP 0xde 11186231Stmm#define APBR_MEMMAP 0xdf 11286231Stmm 11386231Stmm/* Definitions for the mapping registers */ 11486231Stmm#define APB_IO_SCALE 0x200000 11586231Stmm#define APB_MEM_SCALE 0x20000000 11686231Stmm 11786231Stmm/* 11886231Stmm * Generic device interface 11986231Stmm */ 12086231Stmmstatic int 12186231Stmmapb_probe(device_t dev) 12286231Stmm{ 12386231Stmm 12486231Stmm if (pci_get_vendor(dev) == 0x108e && /* Sun */ 12586231Stmm pci_get_device(dev) == 0x5000) { /* APB */ 12686231Stmm device_set_desc(dev, "APB PCI-PCI bridge"); 12786231Stmm return (0); 12886231Stmm } 12986231Stmm return (ENXIO); 13086231Stmm} 13186231Stmm 13286231Stmmstatic void 133294883Sjhibbitsapb_map_print(uint8_t map, rman_res_t scale) 13486231Stmm{ 13586231Stmm int i, first; 13686231Stmm 13786231Stmm for (first = 1, i = 0; i < 8; i++) { 13886231Stmm if ((map & (1 << i)) != 0) { 139297000Sjhibbits printf("%s0x%jx-0x%jx", first ? "" : ", ", 14086231Stmm i * scale, (i + 1) * scale - 1); 14186231Stmm first = 0; 14286231Stmm } 14386231Stmm } 14486231Stmm} 14586231Stmm 14686231Stmmstatic int 147294883Sjhibbitsapb_checkrange(uint8_t map, rman_res_t scale, rman_res_t start, rman_res_t end) 14886231Stmm{ 14986231Stmm int i, ei; 15086231Stmm 15186231Stmm i = start / scale; 15286231Stmm ei = end / scale; 15386231Stmm if (i > 7 || ei > 7) 15486231Stmm return (0); 15586231Stmm for (; i <= ei; i++) 15686231Stmm if ((map & (1 << i)) == 0) 15786231Stmm return (0); 15886231Stmm return (1); 15986231Stmm} 16086231Stmm 16186231Stmmstatic int 16286231Stmmapb_attach(device_t dev) 16386231Stmm{ 16488369Stmm struct apb_softc *sc; 165225931Smarius struct sysctl_ctx_list *sctx; 166225931Smarius struct sysctl_oid *soid; 16786231Stmm 16886231Stmm sc = device_get_softc(dev); 16986231Stmm 17086231Stmm /* 17186231Stmm * Get current bridge configuration. 17286231Stmm */ 173178279Smarius sc->sc_bsc.ops_pcib_sc.domain = pci_get_domain(dev); 174281930Sjhb sc->sc_bsc.ops_pcib_sc.pribus = pci_get_bus(dev); 175281930Sjhb pci_write_config(dev, PCIR_PRIBUS_1, sc->sc_bsc.ops_pcib_sc.pribus, 1); 176261790Sjhb sc->sc_bsc.ops_pcib_sc.bus.sec = 177178279Smarius pci_read_config(dev, PCIR_SECBUS_1, 1); 178261790Sjhb sc->sc_bsc.ops_pcib_sc.bus.sub = 179178279Smarius pci_read_config(dev, PCIR_SUBBUS_1, 1); 180225931Smarius sc->sc_bsc.ops_pcib_sc.bridgectl = 181225931Smarius pci_read_config(dev, PCIR_BRIDGECTL_1, 2); 182117119Stmm sc->sc_iomap = pci_read_config(dev, APBR_IOMAP, 1); 183117119Stmm sc->sc_memmap = pci_read_config(dev, APBR_MEMMAP, 1); 184225931Smarius 185225931Smarius /* 186225931Smarius * Setup SYSCTL reporting nodes. 187225931Smarius */ 188225931Smarius sctx = device_get_sysctl_ctx(dev); 189225931Smarius soid = device_get_sysctl_tree(dev); 190225931Smarius SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "domain", 191225931Smarius CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.domain, 0, 192225931Smarius "Domain number"); 193225931Smarius SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus", 194225931Smarius CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.pribus, 0, 195225931Smarius "Primary bus number"); 196225931Smarius SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus", 197261790Sjhb CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.bus.sec, 0, 198225931Smarius "Secondary bus number"); 199225931Smarius SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus", 200261790Sjhb CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.bus.sub, 0, 201225931Smarius "Subordinate bus number"); 202225931Smarius 203117119Stmm ofw_pcib_gen_setup(dev); 20486231Stmm 20586231Stmm if (bootverbose) { 206172394Smarius device_printf(dev, " domain %d\n", 207172394Smarius sc->sc_bsc.ops_pcib_sc.domain); 208117119Stmm device_printf(dev, " secondary bus %d\n", 209261790Sjhb sc->sc_bsc.ops_pcib_sc.bus.sec); 210117119Stmm device_printf(dev, " subordinate bus %d\n", 211261790Sjhb sc->sc_bsc.ops_pcib_sc.bus.sub); 21286231Stmm device_printf(dev, " I/O decode "); 213117119Stmm apb_map_print(sc->sc_iomap, APB_IO_SCALE); 21486231Stmm printf("\n"); 21586231Stmm device_printf(dev, " memory decode "); 216117119Stmm apb_map_print(sc->sc_memmap, APB_MEM_SCALE); 21786231Stmm printf("\n"); 21886231Stmm } 21986231Stmm 220178279Smarius device_add_child(dev, "pci", -1); 221117119Stmm return (bus_generic_attach(dev)); 22286231Stmm} 22386231Stmm 22486231Stmm/* 22586231Stmm * We have to trap resource allocation requests and ensure that the bridge 22686231Stmm * is set up to, or capable of handling them. 22786231Stmm */ 22886231Stmmstatic struct resource * 229178279Smariusapb_alloc_resource(device_t dev, device_t child, int type, int *rid, 230294883Sjhibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 23186231Stmm{ 23288369Stmm struct apb_softc *sc; 23386231Stmm 23486231Stmm sc = device_get_softc(dev); 235145610Smarcel 23686231Stmm /* 23786231Stmm * If this is a "default" allocation against this rid, we can't work 238129051Smarius * out where it's coming from (we should actually never see these) so 239129051Smarius * we just have to punt. 24086231Stmm */ 241295832Sjhibbits if (RMAN_IS_DEFAULT_RANGE(start, end)) { 24286231Stmm device_printf(dev, "can't decode default resource id %d for " 243206019Smarius "%s, bypassing\n", *rid, device_get_nameunit(child)); 244145610Smarcel goto passup; 245145610Smarcel } 24686231Stmm 247145610Smarcel /* 248145610Smarcel * Fail the allocation for this range if it's not supported. 249145610Smarcel * XXX we should probably just fix up the bridge decode and 250145610Smarcel * soldier on. 251145610Smarcel */ 252145610Smarcel switch (type) { 253145610Smarcel case SYS_RES_IOPORT: 254145610Smarcel if (!apb_checkrange(sc->sc_iomap, APB_IO_SCALE, start, end)) { 255206019Smarius device_printf(dev, "device %s requested unsupported " 256297000Sjhibbits "I/O range 0x%jx-0x%jx\n", 257206019Smarius device_get_nameunit(child), start, end); 258145610Smarcel return (NULL); 259145610Smarcel } 260145610Smarcel if (bootverbose) 261145610Smarcel device_printf(sc->sc_bsc.ops_pcib_sc.dev, "device " 262297000Sjhibbits "%s requested decoded I/O range 0x%jx-0x%jx\n", 263206019Smarius device_get_nameunit(child), start, end); 264145610Smarcel break; 265145610Smarcel case SYS_RES_MEMORY: 266225931Smarius if (!apb_checkrange(sc->sc_memmap, APB_MEM_SCALE, start, 267225931Smarius end)) { 268206019Smarius device_printf(dev, "device %s requested unsupported " 269297000Sjhibbits "memory range 0x%jx-0x%jx\n", 270206019Smarius device_get_nameunit(child), start, end); 271145610Smarcel return (NULL); 27286231Stmm } 273145610Smarcel if (bootverbose) 274145610Smarcel device_printf(sc->sc_bsc.ops_pcib_sc.dev, "device " 275297000Sjhibbits "%s requested decoded memory range 0x%jx-0x%jx\n", 276206019Smarius device_get_nameunit(child), start, end); 277145610Smarcel break; 27886231Stmm } 27986231Stmm 280145610Smarcel passup: 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} 287225931Smarius 288225931Smariusstatic int 289225931Smariusapb_adjust_resource(device_t dev, device_t child, int type, 290294883Sjhibbits struct resource *r, rman_res_t start, rman_res_t end) 291225931Smarius{ 292225931Smarius struct apb_softc *sc; 293225931Smarius 294225931Smarius sc = device_get_softc(dev); 295225931Smarius switch (type) { 296225931Smarius case SYS_RES_IOPORT: 297225931Smarius if (!apb_checkrange(sc->sc_iomap, APB_IO_SCALE, start, end)) 298225931Smarius return (ENXIO); 299225931Smarius break; 300225931Smarius case SYS_RES_MEMORY: 301225931Smarius if (!apb_checkrange(sc->sc_memmap, APB_MEM_SCALE, start, end)) 302225931Smarius return (ENXIO); 303225931Smarius break; 304225931Smarius } 305225931Smarius return (bus_generic_adjust_resource(dev, child, type, r, start, end)); 306225931Smarius} 307