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_get_rman_t nexus_get_rman; 71 static bus_map_resource_t nexus_map_resource; 72 static bus_unmap_resource_t nexus_unmap_resource; 73 74 #ifdef SMP 75 static bus_bind_intr_t nexus_bind_intr; 76 #endif 77 static bus_config_intr_t nexus_config_intr; 78 static bus_setup_intr_t nexus_setup_intr; 79 static bus_teardown_intr_t nexus_teardown_intr; 80 81 static bus_get_bus_tag_t nexus_get_bus_tag; 82 83 static ofw_bus_map_intr_t nexus_ofw_map_intr; 84 85 static 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 114 DEFINE_CLASS_0(nexus, nexus_driver, nexus_methods, 1); 115 EARLY_DRIVER_MODULE(nexus, root, nexus_driver, 0, 0, BUS_PASS_BUS); 116 MODULE_VERSION(nexus, 1); 117 118 static int 119 nexus_probe(device_t dev) 120 { 121 122 device_quiet(dev); /* suppress attach message for neatness */ 123 124 return (BUS_PROBE_DEFAULT); 125 } 126 127 static int 128 nexus_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 150 static int 151 nexus_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 181 static int 182 nexus_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 192 static bus_space_tag_t 193 nexus_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 204 static int 205 nexus_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 213 static int 214 nexus_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 221 static int 222 nexus_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 231 static struct rman * 232 nexus_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 244 static int 245 nexus_map_resource(device_t bus, device_t child, int type, 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 (type) { 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 (type) { 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 301 static int 302 nexus_unmap_resource(device_t bus, device_t child, int type, struct resource *r, 303 struct resource_map *map) 304 { 305 306 /* 307 * If this is a memory resource, unmap it. 308 */ 309 switch (type) { 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