apb.c revision 130025
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 * $FreeBSD: head/sys/sparc64/pci/apb.c 130025 2004-06-03 05:58:30Z phk $ 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. 40129051Smarius * We can use some of the pcib methods anyway. 4186231Stmm */ 4286231Stmm 43117119Stmm#include "opt_ofw_pci.h" 44117119Stmm 4586231Stmm#include <sys/param.h> 4686231Stmm#include <sys/systm.h> 4786231Stmm#include <sys/kernel.h> 48130025Sphk#include <sys/module.h> 4986231Stmm#include <sys/bus.h> 5086231Stmm 5193067Stmm#include <dev/ofw/openfirm.h> 5293067Stmm 53117119Stmm#include <machine/bus.h> 54117119Stmm#include <machine/ofw_bus.h> 5586231Stmm#include <machine/resource.h> 5686231Stmm 57119291Simp#include <dev/pci/pcireg.h> 58119291Simp#include <dev/pci/pcivar.h> 59119291Simp#include <dev/pci/pcib_private.h> 6086231Stmm 6186231Stmm#include "pcib_if.h" 6286231Stmm 63117119Stmm#include <sparc64/pci/ofw_pci.h> 64117119Stmm#include <sparc64/pci/ofw_pcib_subr.h> 65117119Stmm 6686231Stmm/* 6786231Stmm * Bridge-specific data. 6886231Stmm */ 6986231Stmmstruct apb_softc { 70117119Stmm struct ofw_pcib_gen_softc sc_bsc; 71117119Stmm u_int8_t sc_iomap; 72117119Stmm u_int8_t sc_memmap; 7386231Stmm}; 7486231Stmm 75117119Stmmstatic device_probe_t apb_probe; 76117119Stmmstatic device_attach_t apb_attach; 77117119Stmmstatic bus_alloc_resource_t apb_alloc_resource; 7886231Stmm 7986231Stmmstatic device_method_t apb_methods[] = { 8086231Stmm /* Device interface */ 8186231Stmm DEVMETHOD(device_probe, apb_probe), 8286231Stmm DEVMETHOD(device_attach, apb_attach), 8386231Stmm DEVMETHOD(device_shutdown, bus_generic_shutdown), 8486231Stmm DEVMETHOD(device_suspend, bus_generic_suspend), 8586231Stmm DEVMETHOD(device_resume, bus_generic_resume), 8686231Stmm 8786231Stmm /* Bus interface */ 8886231Stmm DEVMETHOD(bus_print_child, bus_generic_print_child), 89117119Stmm DEVMETHOD(bus_read_ivar, pcib_read_ivar), 90117119Stmm DEVMETHOD(bus_write_ivar, pcib_write_ivar), 9186231Stmm DEVMETHOD(bus_alloc_resource, apb_alloc_resource), 9286231Stmm DEVMETHOD(bus_release_resource, bus_generic_release_resource), 9386231Stmm DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 9486231Stmm DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 9586231Stmm DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 9686231Stmm DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 9786231Stmm 9886231Stmm /* pcib interface */ 99117119Stmm DEVMETHOD(pcib_maxslots, pcib_maxslots), 100117119Stmm DEVMETHOD(pcib_read_config, pcib_read_config), 101117119Stmm DEVMETHOD(pcib_write_config, pcib_write_config), 102117119Stmm DEVMETHOD(pcib_route_interrupt, ofw_pcib_gen_route_interrupt), 10386231Stmm 104117119Stmm /* ofw_pci interface */ 105117119Stmm DEVMETHOD(ofw_pci_get_node, ofw_pcib_gen_get_node), 106117119Stmm DEVMETHOD(ofw_pci_adjust_busrange, ofw_pcib_gen_adjust_busrange), 107117119Stmm 10886231Stmm { 0, 0 } 10986231Stmm}; 11086231Stmm 11186231Stmmstatic driver_t apb_driver = { 11286231Stmm "pcib", 11386231Stmm apb_methods, 11488701Stmm sizeof(struct apb_softc), 11586231Stmm}; 11686231Stmm 117117119StmmDRIVER_MODULE(apb, pci, apb_driver, pcib_devclass, 0, 0); 11886231Stmm 11986231Stmm/* APB specific registers */ 12086231Stmm#define APBR_IOMAP 0xde 12186231Stmm#define APBR_MEMMAP 0xdf 12286231Stmm 12386231Stmm/* Definitions for the mapping registers */ 12486231Stmm#define APB_IO_SCALE 0x200000 12586231Stmm#define APB_MEM_SCALE 0x20000000 12686231Stmm 12786231Stmm/* 12886231Stmm * Generic device interface 12986231Stmm */ 13086231Stmmstatic int 13186231Stmmapb_probe(device_t dev) 13286231Stmm{ 13386231Stmm 13486231Stmm if (pci_get_vendor(dev) == 0x108e && /* Sun */ 13586231Stmm pci_get_device(dev) == 0x5000) { /* APB */ 13686231Stmm device_set_desc(dev, "APB PCI-PCI bridge"); 13786231Stmm return (0); 13886231Stmm } 13986231Stmm return (ENXIO); 14086231Stmm} 14186231Stmm 14286231Stmmstatic void 14386231Stmmapb_map_print(u_int8_t map, u_long scale) 14486231Stmm{ 14586231Stmm int i, first; 14686231Stmm 14786231Stmm for (first = 1, i = 0; i < 8; i++) { 14886231Stmm if ((map & (1 << i)) != 0) { 14986231Stmm printf("%s0x%lx-0x%lx", first ? "" : ", ", 15086231Stmm i * scale, (i + 1) * scale - 1); 15186231Stmm first = 0; 15286231Stmm } 15386231Stmm } 15486231Stmm} 15586231Stmm 15686231Stmmstatic int 15786231Stmmapb_map_checkrange(u_int8_t map, u_long scale, u_long start, u_long end) 15886231Stmm{ 15986231Stmm int i, ei; 16086231Stmm 16186231Stmm i = start / scale; 16286231Stmm ei = end / scale; 16386231Stmm if (i > 7 || ei > 7) 16486231Stmm return (0); 16586231Stmm for (; i <= ei; i++) 16686231Stmm if ((map & (1 << i)) == 0) 16786231Stmm return (0); 16886231Stmm return (1); 16986231Stmm} 17086231Stmm 17186231Stmmstatic int 17286231Stmmapb_attach(device_t dev) 17386231Stmm{ 17488369Stmm struct apb_softc *sc; 17586231Stmm 17686231Stmm sc = device_get_softc(dev); 17786231Stmm 17886231Stmm /* 17986231Stmm * Get current bridge configuration. 18086231Stmm */ 181117119Stmm sc->sc_iomap = pci_read_config(dev, APBR_IOMAP, 1); 182117119Stmm sc->sc_memmap = pci_read_config(dev, APBR_MEMMAP, 1); 183117119Stmm ofw_pcib_gen_setup(dev); 18486231Stmm 18586231Stmm if (bootverbose) { 186117119Stmm device_printf(dev, " secondary bus %d\n", 187117119Stmm sc->sc_bsc.ops_pcib_sc.secbus); 188117119Stmm device_printf(dev, " subordinate bus %d\n", 189117119Stmm sc->sc_bsc.ops_pcib_sc.subbus); 19086231Stmm device_printf(dev, " I/O decode "); 191117119Stmm apb_map_print(sc->sc_iomap, APB_IO_SCALE); 19286231Stmm printf("\n"); 19386231Stmm device_printf(dev, " memory decode "); 194117119Stmm apb_map_print(sc->sc_memmap, APB_MEM_SCALE); 19586231Stmm printf("\n"); 19686231Stmm } 19786231Stmm 198117119Stmm device_add_child(dev, "pci", sc->sc_bsc.ops_pcib_sc.secbus); 199117119Stmm return (bus_generic_attach(dev)); 20086231Stmm} 20186231Stmm 20286231Stmm/* 20386231Stmm * We have to trap resource allocation requests and ensure that the bridge 20486231Stmm * is set up to, or capable of handling them. 20586231Stmm */ 20686231Stmmstatic struct resource * 20786231Stmmapb_alloc_resource(device_t dev, device_t child, int type, int *rid, 20886231Stmm u_long start, u_long end, u_long count, u_int flags) 20986231Stmm{ 21088369Stmm struct apb_softc *sc; 21186231Stmm 21286231Stmm sc = device_get_softc(dev); 21386231Stmm /* 21486231Stmm * If this is a "default" allocation against this rid, we can't work 215129051Smarius * out where it's coming from (we should actually never see these) so 216129051Smarius * we just have to punt. 21786231Stmm */ 21886231Stmm if ((start == 0) && (end == ~0)) { 21986231Stmm device_printf(dev, "can't decode default resource id %d for " 22086231Stmm "%s%d, bypassing\n", *rid, device_get_name(child), 22186231Stmm device_get_unit(child)); 22286231Stmm } else { 22386231Stmm /* 22486231Stmm * Fail the allocation for this range if it's not supported. 22586231Stmm * XXX we should probably just fix up the bridge decode and 22686231Stmm * soldier on. 22786231Stmm */ 22886231Stmm switch (type) { 22986231Stmm case SYS_RES_IOPORT: 230117119Stmm if (!apb_map_checkrange(sc->sc_iomap, APB_IO_SCALE, 231117119Stmm start, end)) { 23286231Stmm device_printf(dev, "device %s%d requested " 23386231Stmm "unsupported I/O range 0x%lx-0x%lx\n", 23486231Stmm device_get_name(child), 23586231Stmm device_get_unit(child), start, end); 23686231Stmm return (NULL); 23786231Stmm } 23886231Stmm if (bootverbose) 239117119Stmm device_printf(sc->sc_bsc.ops_pcib_sc.dev, 240117119Stmm "device %s%d requested decoded I/O range " 241117119Stmm "0x%lx-0x%lx\n", device_get_name(child), 24286231Stmm device_get_unit(child), start, end); 24386231Stmm break; 24486231Stmm 24586231Stmm case SYS_RES_MEMORY: 246117119Stmm if (!apb_map_checkrange(sc->sc_memmap, APB_MEM_SCALE, 24786231Stmm start, end)) { 24886231Stmm device_printf(dev, "device %s%d requested " 24986231Stmm "unsupported memory range 0x%lx-0x%lx\n", 25086231Stmm device_get_name(child), 25186231Stmm device_get_unit(child), start, end); 25286231Stmm return (NULL); 25386231Stmm } 25486231Stmm if (bootverbose) 255117119Stmm device_printf(sc->sc_bsc.ops_pcib_sc.dev, 256117119Stmm "device %s%d requested decoded memory " 257117119Stmm "range 0x%lx-0x%lx\n", 25886231Stmm device_get_name(child), 25986231Stmm device_get_unit(child), start, end); 26086231Stmm break; 26186231Stmm 26286231Stmm default: 26386231Stmm break; 26486231Stmm } 26586231Stmm } 26686231Stmm 26786231Stmm /* 26886231Stmm * Bridge is OK decoding this resource, so pass it up. 26986231Stmm */ 27086231Stmm return (bus_generic_alloc_resource(dev, child, type, rid, start, end, 27186231Stmm count, flags)); 27286231Stmm} 273