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