apb.c revision 86231
1/*- 2 * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier 3 * Copyright (c) 2000 Michael Smith <msmith@freebsd.org> 4 * Copyright (c) 2000 BSDi 5 * Copyright (c) 2001 Thomas Moestl <tmm@FreeBSD.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * from: FreeBSD: src/sys/dev/pci/pci_pci.c,v 1.3 2000/12/13 32 * 33 * $FreeBSD: head/sys/sparc64/pci/apb.c 86231 2001-11-09 20:19:58Z tmm $ 34 */ 35 36/* 37 * Support for the Sun APB (Advanced PCI Bridge) PCI-PCI bridge. 38 * This bridge does not fully comply to the PCI bridge specification, and is 39 * therefore not supported by the generic driver. 40 * We can use some pf the pcib methods anyway. 41 */ 42 43#include <sys/param.h> 44#include <sys/systm.h> 45#include <sys/kernel.h> 46#include <sys/malloc.h> 47#include <sys/bus.h> 48 49#include <machine/resource.h> 50 51#include <pci/pcivar.h> 52#include <pci/pcireg.h> 53#include <pci/pcib.h> 54 55#include "pcib_if.h" 56 57/* 58 * Bridge-specific data. 59 */ 60struct apb_softc { 61 u_int8_t iomap; 62 u_int8_t memmap; 63}; 64 65static int apb_probe(device_t dev); 66static int apb_attach(device_t dev); 67static struct resource *apb_alloc_resource(device_t dev, device_t child, 68 int type, int *rid, u_long start, u_long end, u_long count, u_int flags); 69static int apb_route_interrupt(device_t pcib, device_t dev, int pin); 70 71static device_method_t apb_methods[] = { 72 /* Device interface */ 73 DEVMETHOD(device_probe, apb_probe), 74 DEVMETHOD(device_attach, apb_attach), 75 DEVMETHOD(device_shutdown, bus_generic_shutdown), 76 DEVMETHOD(device_suspend, bus_generic_suspend), 77 DEVMETHOD(device_resume, bus_generic_resume), 78 79 /* Bus interface */ 80 DEVMETHOD(bus_print_child, bus_generic_print_child), 81 DEVMETHOD(bus_read_ivar, pcib_read_ivar), 82 DEVMETHOD(bus_write_ivar, pcib_write_ivar), 83 DEVMETHOD(bus_alloc_resource, apb_alloc_resource), 84 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 85 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 86 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 87 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 88 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 89 90 /* pcib interface */ 91 DEVMETHOD(pcib_maxslots, pcib_maxslots), 92 DEVMETHOD(pcib_read_config, pcib_read_config), 93 DEVMETHOD(pcib_write_config, pcib_write_config), 94 DEVMETHOD(pcib_route_interrupt, apb_route_interrupt), 95 96 { 0, 0 } 97}; 98 99static driver_t apb_driver = { 100 "pcib", 101 apb_methods, 102 sizeof(struct pcib_softc), 103}; 104 105static devclass_t apb_devclass; 106 107DRIVER_MODULE(apb, pci, apb_driver, apb_devclass, 0, 0); 108 109#define APB_SOFTC(sc) ((struct apb_softc *)((sc)->extptr)) 110 111/* APB specific registers */ 112#define APBR_IOMAP 0xde 113#define APBR_MEMMAP 0xdf 114 115/* Definitions for the mapping registers */ 116#define APB_IO_SCALE 0x200000 117#define APB_MEM_SCALE 0x20000000 118 119/* 120 * Generic device interface 121 */ 122static int 123apb_probe(device_t dev) 124{ 125 126 if (pci_get_vendor(dev) == 0x108e && /* Sun */ 127 pci_get_device(dev) == 0x5000) { /* APB */ 128 device_set_desc(dev, "APB PCI-PCI bridge"); 129 return (0); 130 } 131 return (ENXIO); 132} 133 134static void 135apb_map_print(u_int8_t map, u_long scale) 136{ 137 int i, first; 138 139 for (first = 1, i = 0; i < 8; i++) { 140 if ((map & (1 << i)) != 0) { 141 printf("%s0x%lx-0x%lx", first ? "" : ", ", 142 i * scale, (i + 1) * scale - 1); 143 first = 0; 144 } 145 } 146} 147 148static int 149apb_map_checkrange(u_int8_t map, u_long scale, u_long start, u_long end) 150{ 151 int i, ei; 152 153 i = start / scale; 154 ei = end / scale; 155 if (i > 7 || ei > 7) 156 return (0); 157 for (; i <= ei; i++) 158 if ((map & (1 << i)) == 0) 159 return (0); 160 return (1); 161} 162 163static int 164apb_attach(device_t dev) 165{ 166 struct pcib_softc *sc; 167 struct apb_softc *asc; 168 device_t child; 169 170 sc = device_get_softc(dev); 171 sc->dev = dev; 172 sc->extptr = malloc(sizeof(struct apb_softc), M_DEVBUF, M_NOWAIT); 173 asc = APB_SOFTC(sc); 174 175 /* 176 * Get current bridge configuration. 177 */ 178 sc->command = pci_read_config(dev, PCIR_COMMAND, 1); 179 sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1); 180 sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); 181 sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2); 182 sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2); 183 sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1); 184 185 /* The APB does not implement base/limit registers. */ 186 sc->iobase = sc->iolimit = 0; 187 sc->membase = sc->memlimit = 0; 188 sc->pmembase = sc->pmemlimit = 0; 189 190 asc->iomap = pci_read_config(dev, APBR_IOMAP, 1); 191 asc->memmap = pci_read_config(dev, APBR_MEMMAP, 1); 192 193 if (bootverbose) { 194 device_printf(dev, " secondary bus %d\n", sc->secbus); 195 device_printf(dev, " subordinate bus %d\n", sc->subbus); 196 device_printf(dev, " I/O decode "); 197 apb_map_print(asc->iomap, APB_IO_SCALE); 198 printf("\n"); 199 device_printf(dev, " memory decode "); 200 apb_map_print(asc->memmap, APB_MEM_SCALE); 201 printf("\n"); 202 } 203 204 /* 205 * XXX If the subordinate bus number is less than the secondary bus 206 * number, we should pick a better value. One sensible alternative 207 * would be to pick 255; the only tradeoff here is that configuration 208 * transactions would be more widely routed than absolutely necessary. 209 */ 210 if (sc->secbus != 0) { 211 child = device_add_child(dev, "pci", -1); 212 if (child != NULL) 213 return (bus_generic_attach(dev)); 214 } else 215 panic("apb_attach: APB with uninitialized secbus"); 216 217 /* no secondary bus; we should have fixed this */ 218 return (0); 219} 220 221/* 222 * We have to trap resource allocation requests and ensure that the bridge 223 * is set up to, or capable of handling them. 224 */ 225static struct resource * 226apb_alloc_resource(device_t dev, device_t child, int type, int *rid, 227 u_long start, u_long end, u_long count, u_int flags) 228{ 229 struct pcib_softc *sc; 230 struct apb_softc *asc; 231 232 sc = device_get_softc(dev); 233 asc = APB_SOFTC(sc); 234 /* 235 * If this is a "default" allocation against this rid, we can't work 236 * out where it's coming from (we should actually never see these) so we 237 * just have to punt. 238 */ 239 if ((start == 0) && (end == ~0)) { 240 device_printf(dev, "can't decode default resource id %d for " 241 "%s%d, bypassing\n", *rid, device_get_name(child), 242 device_get_unit(child)); 243 } else { 244 /* 245 * Fail the allocation for this range if it's not supported. 246 * XXX we should probably just fix up the bridge decode and 247 * soldier on. 248 */ 249 switch (type) { 250 case SYS_RES_IOPORT: 251 if (!apb_map_checkrange(asc->iomap, APB_IO_SCALE, start, 252 end)) { 253 device_printf(dev, "device %s%d requested " 254 "unsupported I/O range 0x%lx-0x%lx\n", 255 device_get_name(child), 256 device_get_unit(child), start, end); 257 return (NULL); 258 } 259 if (bootverbose) 260 device_printf(sc->dev, "device %s%d requested " 261 "decoded I/O range 0x%lx-0x%lx\n", 262 device_get_name(child), 263 device_get_unit(child), start, end); 264 break; 265 266 case SYS_RES_MEMORY: 267 if (!apb_map_checkrange(asc->memmap, APB_MEM_SCALE, 268 start, end)) { 269 device_printf(dev, "device %s%d requested " 270 "unsupported memory range 0x%lx-0x%lx\n", 271 device_get_name(child), 272 device_get_unit(child), start, end); 273 return (NULL); 274 } 275 if (bootverbose) 276 device_printf(sc->dev, "device %s%d requested " 277 "decoded memory range 0x%lx-0x%lx\n", 278 device_get_name(child), 279 device_get_unit(child), start, end); 280 break; 281 282 default: 283 break; 284 } 285 } 286 287 /* 288 * Bridge is OK decoding this resource, so pass it up. 289 */ 290 return (bus_generic_alloc_resource(dev, child, type, rid, start, end, 291 count, flags)); 292} 293 294/* 295 * Route an interrupt across a PCI bridge - the APB does not route interrupts, 296 * and routing of interrupts that are not preinitialized is not supported yet. 297 */ 298static int 299apb_route_interrupt(device_t pcib, device_t dev, int pin) 300{ 301 302 panic("apb_route_interrupt"); 303} 304