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 64 static struct rman intr_rman; 65 static struct rman mem_rman; 66 67 static device_probe_t nexus_probe; 68 static device_attach_t nexus_attach; 69 70 static bus_activate_resource_t nexus_activate_resource; 71 static bus_adjust_resource_t nexus_adjust_resource; 72 static bus_alloc_resource_t nexus_alloc_resource; 73 static bus_deactivate_resource_t nexus_deactivate_resource; 74 static bus_map_resource_t nexus_map_resource; 75 static bus_release_resource_t nexus_release_resource; 76 static bus_unmap_resource_t nexus_unmap_resource; 77 78 #ifdef SMP 79 static bus_bind_intr_t nexus_bind_intr; 80 #endif 81 static bus_config_intr_t nexus_config_intr; 82 static bus_setup_intr_t nexus_setup_intr; 83 static bus_teardown_intr_t nexus_teardown_intr; 84 85 static bus_get_bus_tag_t nexus_get_bus_tag; 86 87 static ofw_bus_map_intr_t nexus_ofw_map_intr; 88 89 static device_method_t nexus_methods[] = { 90 /* Device interface */ 91 DEVMETHOD(device_probe, nexus_probe), 92 DEVMETHOD(device_attach, nexus_attach), 93 94 /* Bus interface */ 95 DEVMETHOD(bus_add_child, bus_generic_add_child), 96 DEVMETHOD(bus_adjust_resource, nexus_adjust_resource), 97 DEVMETHOD(bus_activate_resource, nexus_activate_resource), 98 DEVMETHOD(bus_alloc_resource, nexus_alloc_resource), 99 DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource), 100 DEVMETHOD(bus_map_resource, nexus_map_resource), 101 DEVMETHOD(bus_release_resource, nexus_release_resource), 102 DEVMETHOD(bus_unmap_resource, nexus_unmap_resource), 103 #ifdef SMP 104 DEVMETHOD(bus_bind_intr, nexus_bind_intr), 105 #endif 106 DEVMETHOD(bus_config_intr, nexus_config_intr), 107 DEVMETHOD(bus_setup_intr, nexus_setup_intr), 108 DEVMETHOD(bus_teardown_intr, nexus_teardown_intr), 109 DEVMETHOD(bus_get_bus_tag, nexus_get_bus_tag), 110 111 /* ofw_bus interface */ 112 DEVMETHOD(ofw_bus_map_intr, nexus_ofw_map_intr), 113 114 DEVMETHOD_END 115 }; 116 117 DEFINE_CLASS_0(nexus, nexus_driver, nexus_methods, 1); 118 EARLY_DRIVER_MODULE(nexus, root, nexus_driver, 0, 0, BUS_PASS_BUS); 119 MODULE_VERSION(nexus, 1); 120 121 static int 122 nexus_probe(device_t dev) 123 { 124 125 device_quiet(dev); /* suppress attach message for neatness */ 126 127 return (BUS_PROBE_DEFAULT); 128 } 129 130 static int 131 nexus_attach(device_t dev) 132 { 133 134 intr_rman.rm_type = RMAN_ARRAY; 135 intr_rman.rm_descr = "Interrupts"; 136 mem_rman.rm_type = RMAN_ARRAY; 137 mem_rman.rm_descr = "I/O memory addresses"; 138 if (rman_init(&intr_rman) != 0 || rman_init(&mem_rman) != 0 || 139 rman_manage_region(&intr_rman, 0, ~0) != 0 || 140 rman_manage_region(&mem_rman, 0, BUS_SPACE_MAXADDR) != 0) 141 panic("%s: failed to set up rmans.", __func__); 142 143 /* Add ofwbus0. */ 144 device_add_child(dev, "ofwbus", 0); 145 146 /* Now, probe children. */ 147 bus_generic_probe(dev); 148 bus_generic_attach(dev); 149 150 return (0); 151 } 152 153 static int 154 nexus_setup_intr(device_t bus __unused, device_t child, struct resource *r, 155 int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, 156 void **cookiep) 157 { 158 int error, domain; 159 160 if (r == NULL) 161 panic("%s: NULL interrupt resource!", __func__); 162 163 if (cookiep != NULL) 164 *cookiep = NULL; 165 if ((rman_get_flags(r) & RF_SHAREABLE) == 0) 166 flags |= INTR_EXCL; 167 168 /* We depend here on rman_activate_resource() being idempotent. */ 169 error = rman_activate_resource(r); 170 if (error) 171 return (error); 172 173 if (bus_get_domain(child, &domain) != 0) { 174 if(bootverbose) 175 device_printf(child, "no domain found\n"); 176 domain = 0; 177 } 178 error = powerpc_setup_intr(device_get_nameunit(child), 179 rman_get_start(r), filt, intr, arg, flags, cookiep, domain); 180 181 return (error); 182 } 183 184 static int 185 nexus_teardown_intr(device_t bus __unused, device_t child __unused, 186 struct resource *r, void *ih) 187 { 188 189 if (r == NULL) 190 return (EINVAL); 191 192 return (powerpc_teardown_intr(ih)); 193 } 194 195 static bus_space_tag_t 196 nexus_get_bus_tag(device_t bus __unused, device_t child __unused) 197 { 198 199 #if BYTE_ORDER == LITTLE_ENDIAN 200 return(&bs_le_tag); 201 #else 202 return(&bs_be_tag); 203 #endif 204 } 205 206 #ifdef SMP 207 static int 208 nexus_bind_intr(device_t bus __unused, device_t child __unused, 209 struct resource *r, int cpu) 210 { 211 212 return (powerpc_bind_intr(rman_get_start(r), cpu)); 213 } 214 #endif 215 216 static int 217 nexus_config_intr(device_t dev, int irq, enum intr_trigger trig, 218 enum intr_polarity pol) 219 { 220 221 return (powerpc_config_intr(irq, trig, pol)); 222 } 223 224 static int 225 nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells, 226 pcell_t *irq) 227 { 228 u_int intr = MAP_IRQ(iparent, irq[0]); 229 if (icells > 1) 230 powerpc_fw_config_intr(intr, irq[1]); 231 return (intr); 232 } 233 234 /* 235 * Allocate a resource on behalf of child. NB: child is usually going to be a 236 * child of one of our descendants, not a direct child of nexus0. 237 */ 238 static struct resource * 239 nexus_alloc_resource(device_t bus, device_t child, int type, int *rid, 240 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 241 { 242 struct rman *rm; 243 struct resource *rv; 244 245 switch (type) { 246 case SYS_RES_IRQ: 247 rm = &intr_rman; 248 break; 249 case SYS_RES_MEMORY: 250 rm = &mem_rman; 251 break; 252 default: 253 return (NULL); 254 } 255 256 rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, 257 child); 258 if (rv == NULL) 259 return (NULL); 260 rman_set_rid(rv, *rid); 261 262 if ((flags & RF_ACTIVE) != 0) { 263 if (bus_activate_resource(child, type, *rid, rv) != 0) { 264 rman_release_resource(rv); 265 return (NULL); 266 } 267 } 268 269 return (rv); 270 } 271 272 static int 273 nexus_activate_resource(device_t bus __unused, device_t child __unused, 274 int type, int rid __unused, struct resource *r) 275 { 276 277 if (type == SYS_RES_MEMORY) { 278 vm_paddr_t start; 279 void *p; 280 281 start = (vm_paddr_t) rman_get_start(r); 282 if (bootverbose) 283 printf("nexus mapdev: start %jx, len %jd\n", 284 (uintmax_t)start, rman_get_size(r)); 285 286 p = pmap_mapdev(start, (vm_size_t) rman_get_size(r)); 287 if (p == NULL) 288 return (ENOMEM); 289 rman_set_virtual(r, p); 290 rman_set_bustag(r, &bs_be_tag); 291 rman_set_bushandle(r, (u_long)p); 292 } 293 return (rman_activate_resource(r)); 294 } 295 296 static int 297 nexus_deactivate_resource(device_t bus __unused, device_t child __unused, 298 int type __unused, int rid __unused, struct resource *r) 299 { 300 301 /* 302 * If this is a memory resource, unmap it. 303 */ 304 if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) { 305 bus_size_t psize; 306 307 psize = rman_get_size(r); 308 pmap_unmapdev(rman_get_virtual(r), psize); 309 } 310 311 return (rman_deactivate_resource(r)); 312 } 313 314 static int 315 nexus_adjust_resource(device_t bus, device_t child __unused, int type, 316 struct resource *r, rman_res_t start, rman_res_t end) 317 { 318 struct rman *rm; 319 320 switch (type) { 321 case SYS_RES_IRQ: 322 rm = &intr_rman; 323 break; 324 case SYS_RES_MEMORY: 325 rm = &mem_rman; 326 break; 327 default: 328 return (EINVAL); 329 } 330 if (rm == NULL) 331 return (ENXIO); 332 if (rman_is_region_manager(r, rm) == 0) 333 return (EINVAL); 334 return (rman_adjust_resource(r, start, end)); 335 } 336 337 static int 338 nexus_release_resource(device_t bus, device_t child, int type, 339 int rid, struct resource *r) 340 { 341 int error; 342 343 if ((rman_get_flags(r) & RF_ACTIVE) != 0) { 344 error = bus_deactivate_resource(child, type, rid, r); 345 if (error) 346 return (error); 347 } 348 return (rman_release_resource(r)); 349 } 350 351 static int 352 nexus_map_resource(device_t bus, device_t child, int type, struct resource *r, 353 struct resource_map_request *argsp, struct resource_map *map) 354 { 355 struct resource_map_request args; 356 rman_res_t length, start; 357 int error; 358 359 /* Resources must be active to be mapped. */ 360 if (!(rman_get_flags(r) & RF_ACTIVE)) 361 return (ENXIO); 362 363 /* Mappings are only supported on I/O and memory resources. */ 364 switch (type) { 365 case SYS_RES_IOPORT: 366 case SYS_RES_MEMORY: 367 break; 368 default: 369 return (EINVAL); 370 } 371 372 resource_init_map_request(&args); 373 error = resource_validate_map_request(r, argsp, &args, &start, &length); 374 if (error) 375 return (error); 376 377 /* 378 * If this is a memory resource, map it into the kernel. 379 */ 380 switch (type) { 381 case SYS_RES_IOPORT: 382 panic("%s:%d SYS_RES_IOPORT handling not implemented", __func__, __LINE__); 383 /* XXX: untested 384 map->r_bushandle = start; 385 map->r_bustag = nexus_get_bus_tag(NULL, NULL); 386 map->r_size = length; 387 map->r_vaddr = NULL; 388 */ 389 break; 390 case SYS_RES_MEMORY: 391 map->r_vaddr = pmap_mapdev_attr(start, length, args.memattr); 392 map->r_bustag = nexus_get_bus_tag(NULL, NULL); 393 map->r_size = length; 394 map->r_bushandle = (bus_space_handle_t)map->r_vaddr; 395 break; 396 } 397 398 return (0); 399 400 } 401 402 static int 403 nexus_unmap_resource(device_t bus, device_t child, int type, struct resource *r, 404 struct resource_map *map) 405 { 406 407 /* 408 * If this is a memory resource, unmap it. 409 */ 410 switch (type) { 411 case SYS_RES_MEMORY: 412 pmap_unmapdev(map->r_vaddr, map->r_size); 413 /* FALLTHROUGH */ 414 case SYS_RES_IOPORT: 415 break; 416 default: 417 return (EINVAL); 418 } 419 420 return (0); 421 422 } 423