apb.c revision 86231
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 86231 2001-11-09 20:19:58Z 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#include <pci/pcib.h> 5486231Stmm 5586231Stmm#include "pcib_if.h" 5686231Stmm 5786231Stmm/* 5886231Stmm * Bridge-specific data. 5986231Stmm */ 6086231Stmmstruct apb_softc { 6186231Stmm u_int8_t iomap; 6286231Stmm u_int8_t memmap; 6386231Stmm}; 6486231Stmm 6586231Stmmstatic int apb_probe(device_t dev); 6686231Stmmstatic int apb_attach(device_t dev); 6786231Stmmstatic struct resource *apb_alloc_resource(device_t dev, device_t child, 6886231Stmm int type, int *rid, u_long start, u_long end, u_long count, u_int flags); 6986231Stmmstatic int apb_route_interrupt(device_t pcib, device_t dev, int pin); 7086231Stmm 7186231Stmmstatic device_method_t apb_methods[] = { 7286231Stmm /* Device interface */ 7386231Stmm DEVMETHOD(device_probe, apb_probe), 7486231Stmm DEVMETHOD(device_attach, apb_attach), 7586231Stmm DEVMETHOD(device_shutdown, bus_generic_shutdown), 7686231Stmm DEVMETHOD(device_suspend, bus_generic_suspend), 7786231Stmm DEVMETHOD(device_resume, bus_generic_resume), 7886231Stmm 7986231Stmm /* Bus interface */ 8086231Stmm DEVMETHOD(bus_print_child, bus_generic_print_child), 8186231Stmm DEVMETHOD(bus_read_ivar, pcib_read_ivar), 8286231Stmm DEVMETHOD(bus_write_ivar, pcib_write_ivar), 8386231Stmm DEVMETHOD(bus_alloc_resource, apb_alloc_resource), 8486231Stmm DEVMETHOD(bus_release_resource, bus_generic_release_resource), 8586231Stmm DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 8686231Stmm DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 8786231Stmm DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 8886231Stmm DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 8986231Stmm 9086231Stmm /* pcib interface */ 9186231Stmm DEVMETHOD(pcib_maxslots, pcib_maxslots), 9286231Stmm DEVMETHOD(pcib_read_config, pcib_read_config), 9386231Stmm DEVMETHOD(pcib_write_config, pcib_write_config), 9486231Stmm DEVMETHOD(pcib_route_interrupt, apb_route_interrupt), 9586231Stmm 9686231Stmm { 0, 0 } 9786231Stmm}; 9886231Stmm 9986231Stmmstatic driver_t apb_driver = { 10086231Stmm "pcib", 10186231Stmm apb_methods, 10286231Stmm sizeof(struct pcib_softc), 10386231Stmm}; 10486231Stmm 10586231Stmmstatic devclass_t apb_devclass; 10686231Stmm 10786231StmmDRIVER_MODULE(apb, pci, apb_driver, apb_devclass, 0, 0); 10886231Stmm 10986231Stmm#define APB_SOFTC(sc) ((struct apb_softc *)((sc)->extptr)) 11086231Stmm 11186231Stmm/* APB specific registers */ 11286231Stmm#define APBR_IOMAP 0xde 11386231Stmm#define APBR_MEMMAP 0xdf 11486231Stmm 11586231Stmm/* Definitions for the mapping registers */ 11686231Stmm#define APB_IO_SCALE 0x200000 11786231Stmm#define APB_MEM_SCALE 0x20000000 11886231Stmm 11986231Stmm/* 12086231Stmm * Generic device interface 12186231Stmm */ 12286231Stmmstatic int 12386231Stmmapb_probe(device_t dev) 12486231Stmm{ 12586231Stmm 12686231Stmm if (pci_get_vendor(dev) == 0x108e && /* Sun */ 12786231Stmm pci_get_device(dev) == 0x5000) { /* APB */ 12886231Stmm device_set_desc(dev, "APB PCI-PCI bridge"); 12986231Stmm return (0); 13086231Stmm } 13186231Stmm return (ENXIO); 13286231Stmm} 13386231Stmm 13486231Stmmstatic void 13586231Stmmapb_map_print(u_int8_t map, u_long scale) 13686231Stmm{ 13786231Stmm int i, first; 13886231Stmm 13986231Stmm for (first = 1, i = 0; i < 8; i++) { 14086231Stmm if ((map & (1 << i)) != 0) { 14186231Stmm printf("%s0x%lx-0x%lx", first ? "" : ", ", 14286231Stmm i * scale, (i + 1) * scale - 1); 14386231Stmm first = 0; 14486231Stmm } 14586231Stmm } 14686231Stmm} 14786231Stmm 14886231Stmmstatic int 14986231Stmmapb_map_checkrange(u_int8_t map, u_long scale, u_long start, u_long end) 15086231Stmm{ 15186231Stmm int i, ei; 15286231Stmm 15386231Stmm i = start / scale; 15486231Stmm ei = end / scale; 15586231Stmm if (i > 7 || ei > 7) 15686231Stmm return (0); 15786231Stmm for (; i <= ei; i++) 15886231Stmm if ((map & (1 << i)) == 0) 15986231Stmm return (0); 16086231Stmm return (1); 16186231Stmm} 16286231Stmm 16386231Stmmstatic int 16486231Stmmapb_attach(device_t dev) 16586231Stmm{ 16686231Stmm struct pcib_softc *sc; 16786231Stmm struct apb_softc *asc; 16886231Stmm device_t child; 16986231Stmm 17086231Stmm sc = device_get_softc(dev); 17186231Stmm sc->dev = dev; 17286231Stmm sc->extptr = malloc(sizeof(struct apb_softc), M_DEVBUF, M_NOWAIT); 17386231Stmm asc = APB_SOFTC(sc); 17486231Stmm 17586231Stmm /* 17686231Stmm * Get current bridge configuration. 17786231Stmm */ 17886231Stmm sc->command = pci_read_config(dev, PCIR_COMMAND, 1); 17986231Stmm sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1); 18086231Stmm sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); 18186231Stmm sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2); 18286231Stmm sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2); 18386231Stmm sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1); 18486231Stmm 18586231Stmm /* The APB does not implement base/limit registers. */ 18686231Stmm sc->iobase = sc->iolimit = 0; 18786231Stmm sc->membase = sc->memlimit = 0; 18886231Stmm sc->pmembase = sc->pmemlimit = 0; 18986231Stmm 19086231Stmm asc->iomap = pci_read_config(dev, APBR_IOMAP, 1); 19186231Stmm asc->memmap = pci_read_config(dev, APBR_MEMMAP, 1); 19286231Stmm 19386231Stmm if (bootverbose) { 19486231Stmm device_printf(dev, " secondary bus %d\n", sc->secbus); 19586231Stmm device_printf(dev, " subordinate bus %d\n", sc->subbus); 19686231Stmm device_printf(dev, " I/O decode "); 19786231Stmm apb_map_print(asc->iomap, APB_IO_SCALE); 19886231Stmm printf("\n"); 19986231Stmm device_printf(dev, " memory decode "); 20086231Stmm apb_map_print(asc->memmap, APB_MEM_SCALE); 20186231Stmm printf("\n"); 20286231Stmm } 20386231Stmm 20486231Stmm /* 20586231Stmm * XXX If the subordinate bus number is less than the secondary bus 20686231Stmm * number, we should pick a better value. One sensible alternative 20786231Stmm * would be to pick 255; the only tradeoff here is that configuration 20886231Stmm * transactions would be more widely routed than absolutely necessary. 20986231Stmm */ 21086231Stmm if (sc->secbus != 0) { 21186231Stmm child = device_add_child(dev, "pci", -1); 21286231Stmm if (child != NULL) 21386231Stmm return (bus_generic_attach(dev)); 21486231Stmm } else 21586231Stmm panic("apb_attach: APB with uninitialized secbus"); 21686231Stmm 21786231Stmm /* no secondary bus; we should have fixed this */ 21886231Stmm return (0); 21986231Stmm} 22086231Stmm 22186231Stmm/* 22286231Stmm * We have to trap resource allocation requests and ensure that the bridge 22386231Stmm * is set up to, or capable of handling them. 22486231Stmm */ 22586231Stmmstatic struct resource * 22686231Stmmapb_alloc_resource(device_t dev, device_t child, int type, int *rid, 22786231Stmm u_long start, u_long end, u_long count, u_int flags) 22886231Stmm{ 22986231Stmm struct pcib_softc *sc; 23086231Stmm struct apb_softc *asc; 23186231Stmm 23286231Stmm sc = device_get_softc(dev); 23386231Stmm asc = APB_SOFTC(sc); 23486231Stmm /* 23586231Stmm * If this is a "default" allocation against this rid, we can't work 23686231Stmm * out where it's coming from (we should actually never see these) so we 23786231Stmm * just have to punt. 23886231Stmm */ 23986231Stmm if ((start == 0) && (end == ~0)) { 24086231Stmm device_printf(dev, "can't decode default resource id %d for " 24186231Stmm "%s%d, bypassing\n", *rid, device_get_name(child), 24286231Stmm device_get_unit(child)); 24386231Stmm } else { 24486231Stmm /* 24586231Stmm * Fail the allocation for this range if it's not supported. 24686231Stmm * XXX we should probably just fix up the bridge decode and 24786231Stmm * soldier on. 24886231Stmm */ 24986231Stmm switch (type) { 25086231Stmm case SYS_RES_IOPORT: 25186231Stmm if (!apb_map_checkrange(asc->iomap, APB_IO_SCALE, start, 25286231Stmm end)) { 25386231Stmm device_printf(dev, "device %s%d requested " 25486231Stmm "unsupported I/O range 0x%lx-0x%lx\n", 25586231Stmm device_get_name(child), 25686231Stmm device_get_unit(child), start, end); 25786231Stmm return (NULL); 25886231Stmm } 25986231Stmm if (bootverbose) 26086231Stmm device_printf(sc->dev, "device %s%d requested " 26186231Stmm "decoded I/O range 0x%lx-0x%lx\n", 26286231Stmm device_get_name(child), 26386231Stmm device_get_unit(child), start, end); 26486231Stmm break; 26586231Stmm 26686231Stmm case SYS_RES_MEMORY: 26786231Stmm if (!apb_map_checkrange(asc->memmap, APB_MEM_SCALE, 26886231Stmm start, end)) { 26986231Stmm device_printf(dev, "device %s%d requested " 27086231Stmm "unsupported memory range 0x%lx-0x%lx\n", 27186231Stmm device_get_name(child), 27286231Stmm device_get_unit(child), start, end); 27386231Stmm return (NULL); 27486231Stmm } 27586231Stmm if (bootverbose) 27686231Stmm device_printf(sc->dev, "device %s%d requested " 27786231Stmm "decoded memory range 0x%lx-0x%lx\n", 27886231Stmm device_get_name(child), 27986231Stmm device_get_unit(child), start, end); 28086231Stmm break; 28186231Stmm 28286231Stmm default: 28386231Stmm break; 28486231Stmm } 28586231Stmm } 28686231Stmm 28786231Stmm /* 28886231Stmm * Bridge is OK decoding this resource, so pass it up. 28986231Stmm */ 29086231Stmm return (bus_generic_alloc_resource(dev, child, type, rid, start, end, 29186231Stmm count, flags)); 29286231Stmm} 29386231Stmm 29486231Stmm/* 29586231Stmm * Route an interrupt across a PCI bridge - the APB does not route interrupts, 29686231Stmm * and routing of interrupts that are not preinitialized is not supported yet. 29786231Stmm */ 29886231Stmmstatic int 29986231Stmmapb_route_interrupt(device_t pcib, device_t dev, int pin) 30086231Stmm{ 30186231Stmm 30286231Stmm panic("apb_route_interrupt"); 30386231Stmm} 304