1/*- 2 * Copyright 1998 Massachusetts Institute of Technology 3 * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. 4 * Copyright 2006 by Marius Strobl <marius@FreeBSD.org>. 5 * All rights reserved. 6 * 7 * Permission to use, copy, modify, and distribute this software and 8 * its documentation for any purpose and without fee is hereby 9 * granted, provided that both the above copyright notice and this 10 * permission notice appear in all copies, that both the above 11 * copyright notice and this permission notice appear in all 12 * supporting documentation, and that the name of M.I.T. not be used 13 * in advertising or publicity pertaining to distribution of the 14 * software without specific, written prior permission. M.I.T. makes 15 * no representations about the suitability of this software for any 16 * purpose. It is provided "as is" without express or implied 17 * warranty. 18 * 19 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 20 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 21 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 22 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 23 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * from: FreeBSD: src/sys/i386/i386/nexus.c,v 1.43 2001/02/09 33 */ 34 35/* 36 * This code implements a `root nexus' for Power ISA Architecture 37 * machines. The function of the root nexus is to serve as an 38 * attachment point for both processors and buses, and to manage 39 * resources which are common to all of them. In particular, 40 * this code implements the core resource managers for interrupt 41 * requests and I/O memory address space. 42 */ 43 44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/bus.h> 47#include <sys/kernel.h> 48#include <sys/malloc.h> 49#include <sys/module.h> 50#include <sys/rman.h> 51 52#include <vm/vm.h> 53#include <vm/pmap.h> 54 55#include <machine/bus.h> 56#include <machine/endian.h> 57#include <machine/intr_machdep.h> 58#include <machine/resource.h> 59 60#include <dev/ofw/ofw_bus.h> 61#include <dev/ofw/ofw_bus_subr.h> 62#include <dev/ofw/openfirm.h> 63 64static struct rman intr_rman; 65static struct rman mem_rman; 66 67static device_probe_t nexus_probe; 68static device_attach_t nexus_attach; 69 70static bus_get_rman_t nexus_get_rman; 71static bus_map_resource_t nexus_map_resource; 72static bus_unmap_resource_t nexus_unmap_resource; 73 74#ifdef SMP 75static bus_bind_intr_t nexus_bind_intr; 76#endif 77static bus_config_intr_t nexus_config_intr; 78static bus_setup_intr_t nexus_setup_intr; 79static bus_teardown_intr_t nexus_teardown_intr; 80 81static bus_get_bus_tag_t nexus_get_bus_tag; 82 83static ofw_bus_map_intr_t nexus_ofw_map_intr; 84 85static device_method_t nexus_methods[] = { 86 /* Device interface */ 87 DEVMETHOD(device_probe, nexus_probe), 88 DEVMETHOD(device_attach, nexus_attach), 89 90 /* Bus interface */ 91 DEVMETHOD(bus_add_child, bus_generic_add_child), 92 DEVMETHOD(bus_adjust_resource, bus_generic_rman_adjust_resource), 93 DEVMETHOD(bus_activate_resource, bus_generic_rman_activate_resource), 94 DEVMETHOD(bus_alloc_resource, bus_generic_rman_alloc_resource), 95 DEVMETHOD(bus_deactivate_resource, bus_generic_rman_deactivate_resource), 96 DEVMETHOD(bus_get_rman, nexus_get_rman), 97 DEVMETHOD(bus_map_resource, nexus_map_resource), 98 DEVMETHOD(bus_release_resource, bus_generic_rman_release_resource), 99 DEVMETHOD(bus_unmap_resource, nexus_unmap_resource), 100#ifdef SMP 101 DEVMETHOD(bus_bind_intr, nexus_bind_intr), 102#endif 103 DEVMETHOD(bus_config_intr, nexus_config_intr), 104 DEVMETHOD(bus_setup_intr, nexus_setup_intr), 105 DEVMETHOD(bus_teardown_intr, nexus_teardown_intr), 106 DEVMETHOD(bus_get_bus_tag, nexus_get_bus_tag), 107 108 /* ofw_bus interface */ 109 DEVMETHOD(ofw_bus_map_intr, nexus_ofw_map_intr), 110 111 DEVMETHOD_END 112}; 113 114DEFINE_CLASS_0(nexus, nexus_driver, nexus_methods, 1); 115EARLY_DRIVER_MODULE(nexus, root, nexus_driver, 0, 0, BUS_PASS_BUS); 116MODULE_VERSION(nexus, 1); 117 118static int 119nexus_probe(device_t dev) 120{ 121 122 device_quiet(dev); /* suppress attach message for neatness */ 123 124 return (BUS_PROBE_DEFAULT); 125} 126 127static int 128nexus_attach(device_t dev) 129{ 130 131 intr_rman.rm_type = RMAN_ARRAY; 132 intr_rman.rm_descr = "Interrupts"; 133 mem_rman.rm_type = RMAN_ARRAY; 134 mem_rman.rm_descr = "I/O memory addresses"; 135 if (rman_init(&intr_rman) != 0 || rman_init(&mem_rman) != 0 || 136 rman_manage_region(&intr_rman, 0, ~0) != 0 || 137 rman_manage_region(&mem_rman, 0, BUS_SPACE_MAXADDR) != 0) 138 panic("%s: failed to set up rmans.", __func__); 139 140 /* Add ofwbus0. */ 141 device_add_child(dev, "ofwbus", 0); 142 143 /* Now, probe children. */ 144 bus_generic_probe(dev); 145 bus_generic_attach(dev); 146 147 return (0); 148} 149 150static int 151nexus_setup_intr(device_t bus __unused, device_t child, struct resource *r, 152 int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, 153 void **cookiep) 154{ 155 int error, domain; 156 157 if (r == NULL) 158 panic("%s: NULL interrupt resource!", __func__); 159 160 if (cookiep != NULL) 161 *cookiep = NULL; 162 if ((rman_get_flags(r) & RF_SHAREABLE) == 0) 163 flags |= INTR_EXCL; 164 165 /* We depend here on rman_activate_resource() being idempotent. */ 166 error = rman_activate_resource(r); 167 if (error) 168 return (error); 169 170 if (bus_get_domain(child, &domain) != 0) { 171 if(bootverbose) 172 device_printf(child, "no domain found\n"); 173 domain = 0; 174 } 175 error = powerpc_setup_intr(device_get_nameunit(child), 176 rman_get_start(r), filt, intr, arg, flags, cookiep, domain); 177 178 return (error); 179} 180 181static int 182nexus_teardown_intr(device_t bus __unused, device_t child __unused, 183 struct resource *r, void *ih) 184{ 185 186 if (r == NULL) 187 return (EINVAL); 188 189 return (powerpc_teardown_intr(ih)); 190} 191 192static bus_space_tag_t 193nexus_get_bus_tag(device_t bus __unused, device_t child __unused) 194{ 195 196#if BYTE_ORDER == LITTLE_ENDIAN 197 return(&bs_le_tag); 198#else 199 return(&bs_be_tag); 200#endif 201} 202 203#ifdef SMP 204static int 205nexus_bind_intr(device_t bus __unused, device_t child __unused, 206 struct resource *r, int cpu) 207{ 208 209 return (powerpc_bind_intr(rman_get_start(r), cpu)); 210} 211#endif 212 213static int 214nexus_config_intr(device_t dev, int irq, enum intr_trigger trig, 215 enum intr_polarity pol) 216{ 217 218 return (powerpc_config_intr(irq, trig, pol)); 219} 220 221static int 222nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells, 223 pcell_t *irq) 224{ 225 u_int intr = MAP_IRQ(iparent, irq[0]); 226 if (icells > 1) 227 powerpc_fw_config_intr(intr, irq[1]); 228 return (intr); 229} 230 231static struct rman * 232nexus_get_rman(device_t bus, int type, u_int flags) 233{ 234 switch (type) { 235 case SYS_RES_IRQ: 236 return (&intr_rman); 237 case SYS_RES_MEMORY: 238 return (&mem_rman); 239 default: 240 return (NULL); 241 } 242} 243 244static int 245nexus_map_resource(device_t bus, device_t child, struct resource *r, 246 struct resource_map_request *argsp, struct resource_map *map) 247{ 248 struct resource_map_request args; 249 rman_res_t length, start; 250 int error; 251 252 /* Resources must be active to be mapped. */ 253 if (!(rman_get_flags(r) & RF_ACTIVE)) 254 return (ENXIO); 255 256 /* Mappings are only supported on I/O and memory resources. */ 257 switch (rman_get_type(r)) { 258 case SYS_RES_IOPORT: 259 case SYS_RES_MEMORY: 260 break; 261 default: 262 return (EINVAL); 263 } 264 265 resource_init_map_request(&args); 266 error = resource_validate_map_request(r, argsp, &args, &start, &length); 267 if (error) 268 return (error); 269 270 /* 271 * If this is a memory resource, map it into the kernel. 272 */ 273 switch (rman_get_type(r)) { 274 case SYS_RES_IOPORT: 275 panic("%s:%d SYS_RES_IOPORT handling not implemented", __func__, __LINE__); 276 /* XXX: untested 277 map->r_bushandle = start; 278 if ((rman_get_flags(r) & RF_LITTLEENDIAN) != 0) 279 map->r_bustag = &bs_le_tag; 280 else 281 map->r_bustag = nexus_get_bus_tag(NULL, NULL); 282 map->r_size = length; 283 map->r_vaddr = NULL; 284 */ 285 break; 286 case SYS_RES_MEMORY: 287 map->r_vaddr = pmap_mapdev_attr(start, length, args.memattr); 288 if ((rman_get_flags(r) & RF_LITTLEENDIAN) != 0) 289 map->r_bustag = &bs_le_tag; 290 else 291 map->r_bustag = nexus_get_bus_tag(NULL, NULL); 292 map->r_size = length; 293 map->r_bushandle = (bus_space_handle_t)map->r_vaddr; 294 break; 295 } 296 297 return (0); 298 299} 300 301static int 302nexus_unmap_resource(device_t bus, device_t child, struct resource *r, 303 struct resource_map *map) 304{ 305 306 /* 307 * If this is a memory resource, unmap it. 308 */ 309 switch (rman_get_type(r)) { 310 case SYS_RES_MEMORY: 311 pmap_unmapdev(map->r_vaddr, map->r_size); 312 /* FALLTHROUGH */ 313 case SYS_RES_IOPORT: 314 break; 315 default: 316 return (EINVAL); 317 } 318 319 return (0); 320 321} 322