28 */ 29 30/* 31 * PSIM 'iobus' local bus. Should be set up in the device tree like: 32 * 33 * /iobus@0x80000000/name psim-iobus 34 * 35 * Code borrowed from various nexus.c and uninorth.c :-) 36 */ 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/kernel.h> 41#include <sys/malloc.h> 42#include <sys/module.h> 43#include <sys/bus.h> 44#include <machine/bus.h> 45#include <sys/rman.h> 46 47#include <dev/ofw/openfirm.h> 48 49#include <machine/vmparam.h> 50#include <vm/vm.h> 51#include <vm/pmap.h> 52#include <machine/pmap.h> 53 54#include <machine/resource.h> 55#include <machine/nexusvar.h> 56 57#include <powerpc/psim/iobusvar.h> 58 59struct iobus_softc { 60 phandle_t sc_node; 61 vm_offset_t sc_addr; 62 vm_offset_t sc_size; 63 struct rman sc_mem_rman; 64}; 65 66static MALLOC_DEFINE(M_IOBUS, "iobus", "iobus device information"); 67 68static int iobus_probe(device_t); 69static int iobus_attach(device_t); 70static int iobus_print_child(device_t dev, device_t child); 71static void iobus_probe_nomatch(device_t, device_t); 72static int iobus_read_ivar(device_t, device_t, int, uintptr_t *); 73static int iobus_write_ivar(device_t, device_t, int, uintptr_t); 74static struct resource *iobus_alloc_resource(device_t, device_t, int, int *, 75 u_long, u_long, u_long, u_int); 76static int iobus_activate_resource(device_t, device_t, int, int, 77 struct resource *); 78static int iobus_deactivate_resource(device_t, device_t, int, int, 79 struct resource *); 80static int iobus_release_resource(device_t, device_t, int, int, 81 struct resource *); 82 83/* 84 * Bus interface definition 85 */ 86static device_method_t iobus_methods[] = { 87 /* Device interface */ 88 DEVMETHOD(device_probe, iobus_probe), 89 DEVMETHOD(device_attach, iobus_attach), 90 DEVMETHOD(device_detach, bus_generic_detach), 91 DEVMETHOD(device_shutdown, bus_generic_shutdown), 92 DEVMETHOD(device_suspend, bus_generic_suspend), 93 DEVMETHOD(device_resume, bus_generic_resume), 94 95 /* Bus interface */ 96 DEVMETHOD(bus_print_child, iobus_print_child), 97 DEVMETHOD(bus_probe_nomatch, iobus_probe_nomatch), 98 DEVMETHOD(bus_read_ivar, iobus_read_ivar), 99 DEVMETHOD(bus_write_ivar, iobus_write_ivar), 100 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 101 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 102 103 DEVMETHOD(bus_alloc_resource, iobus_alloc_resource), 104 DEVMETHOD(bus_release_resource, iobus_release_resource), 105 DEVMETHOD(bus_activate_resource, iobus_activate_resource), 106 DEVMETHOD(bus_deactivate_resource, iobus_deactivate_resource), 107 108 { 0, 0 } 109}; 110 111static driver_t iobus_driver = { 112 "iobus", 113 iobus_methods, 114 sizeof(struct iobus_softc) 115}; 116 117devclass_t iobus_devclass; 118 119DRIVER_MODULE(iobus, nexus, iobus_driver, iobus_devclass, 0, 0); 120 121static int 122iobus_probe(device_t dev) 123{ 124 char *type = nexus_get_name(dev); 125 126 if (strcmp(type, "psim-iobus") != 0) 127 return (ENXIO); 128 129 device_set_desc(dev, "PSIM local bus"); 130 return (0); 131} 132 133/* 134 * Add interrupt/addr range to the dev's resource list if present 135 */ 136static void 137iobus_add_intr(phandle_t devnode, struct iobus_devinfo *dinfo) 138{ 139 u_int intr = -1; 140 141 if (OF_getprop(devnode, "interrupt", &intr, sizeof(intr)) != -1) { 142 resource_list_add(&dinfo->id_resources, 143 SYS_RES_IRQ, 0, intr, intr, 1); 144 } 145 dinfo->id_interrupt = intr; 146} 147 148 149static void 150iobus_add_reg(phandle_t devnode, struct iobus_devinfo *dinfo, 151 vm_offset_t iobus_off) 152{ 153 u_int size; 154 int i; 155 156 size = OF_getprop(devnode, "reg", dinfo->id_reg,sizeof(dinfo->id_reg)); 157 158 if (size != -1) { 159 dinfo->id_nregs = size / (sizeof(dinfo->id_reg[0])); 160 161 for (i = 0; i < dinfo->id_nregs; i+= 3) { 162 /* 163 * Scale the absolute addresses back to iobus 164 * relative offsets. This is to better simulate 165 * macio 166 */ 167 dinfo->id_reg[i+1] -= iobus_off; 168 169 resource_list_add(&dinfo->id_resources, 170 SYS_RES_MEMORY, 0, 171 dinfo->id_reg[i+1], 172 dinfo->id_reg[i+1] + 173 dinfo->id_reg[i+2], 174 dinfo->id_reg[i+2]); 175 } 176 } 177} 178 179 180static int 181iobus_attach(device_t dev) 182{ 183 struct iobus_softc *sc; 184 struct iobus_devinfo *dinfo; 185 phandle_t root; 186 phandle_t child; 187 device_t cdev; 188 char *name; 189 u_int reg[2]; 190 int size; 191 192 sc = device_get_softc(dev); 193 sc->sc_node = nexus_get_node(dev); 194 195 /* 196 * Find the base addr/size of the iobus, and initialize the 197 * resource manager 198 */ 199 size = OF_getprop(sc->sc_node, "reg", reg, sizeof(reg)); 200 if (size == sizeof(reg)) { 201 sc->sc_addr = reg[0]; 202 sc->sc_size = reg[1]; 203 } else { 204 return (ENXIO); 205 } 206 207 sc->sc_mem_rman.rm_type = RMAN_ARRAY; 208 sc->sc_mem_rman.rm_descr = "IOBus Device Memory"; 209 if (rman_init(&sc->sc_mem_rman) != 0) { 210 device_printf(dev, 211 "failed to init mem range resources\n"); 212 return (ENXIO); 213 } 214 rman_manage_region(&sc->sc_mem_rman, 0, sc->sc_size); 215 216 /* 217 * Iterate through the sub-devices 218 */ 219 root = sc->sc_node; 220 221 for (child = OF_child(root); child != 0; child = OF_peer(child)) { 222 OF_getprop_alloc(child, "name", 1, (void **)&name); 223 224 cdev = device_add_child(dev, NULL, -1); 225 if (cdev != NULL) { 226 dinfo = malloc(sizeof(*dinfo), M_IOBUS, M_WAITOK); 227 memset(dinfo, 0, sizeof(*dinfo)); 228 resource_list_init(&dinfo->id_resources); 229 dinfo->id_node = child; 230 dinfo->id_name = name; 231 iobus_add_intr(child, dinfo); 232 iobus_add_reg(child, dinfo, sc->sc_addr); 233 device_set_ivars(cdev, dinfo); 234 } else { 235 free(name, M_OFWPROP); 236 } 237 } 238 239 return (bus_generic_attach(dev)); 240} 241 242 243static int 244iobus_print_child(device_t dev, device_t child) 245{ 246 struct iobus_devinfo *dinfo; 247 struct resource_list *rl; 248 int retval = 0; 249 250 dinfo = device_get_ivars(child); 251 rl = &dinfo->id_resources; 252 253 retval += bus_print_child_header(dev, child); 254 255 retval += printf(" offset 0x%x", dinfo->id_reg[1]); 256 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 257 258 retval += bus_print_child_footer(dev, child); 259 260 return (retval); 261} 262 263 264static void 265iobus_probe_nomatch(device_t dev, device_t child) 266{ 267} 268 269 270static int 271iobus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 272{ 273 struct iobus_devinfo *dinfo; 274 275 if ((dinfo = device_get_ivars(child)) == 0) 276 return (ENOENT); 277 278 switch (which) { 279 case IOBUS_IVAR_NODE: 280 *result = dinfo->id_node; 281 break; 282 case IOBUS_IVAR_NAME: 283 *result = (uintptr_t)dinfo->id_name; 284 break; 285 case IOBUS_IVAR_NREGS: 286 *result = dinfo->id_nregs; 287 break; 288 case IOBUS_IVAR_REGS: 289 *result = (uintptr_t)dinfo->id_reg; 290 break; 291 default: 292 return (ENOENT); 293 } 294 295 return (0); 296} 297 298 299static int 300iobus_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 301{ 302 return (EINVAL); 303} 304 305 306static struct resource * 307iobus_alloc_resource(device_t bus, device_t child, int type, int *rid, 308 u_long start, u_long end, u_long count, u_int flags) 309{ 310 struct iobus_softc *sc; 311 int needactivate; 312 struct resource *rv; 313 struct rman *rm;
|
343 rman_set_bushandle(rv, rman_get_start(rv)); 344 345 if (needactivate) { 346 if (bus_activate_resource(child, type, *rid, rv) != 0) { 347 device_printf(bus, 348 "failed to activate resource for %s\n", 349 device_get_nameunit(child)); 350 rman_release_resource(rv); 351 return (NULL); 352 } 353 } 354 355 return (rv); 356} 357 358 359static int 360iobus_release_resource(device_t bus, device_t child, int type, int rid, 361 struct resource *res) 362{ 363 if (rman_get_flags(res) & RF_ACTIVE) { 364 int error = bus_deactivate_resource(child, type, rid, res); 365 if (error) 366 return error; 367 } 368 369 return (rman_release_resource(res)); 370} 371 372 373static int 374iobus_activate_resource(device_t bus, device_t child, int type, int rid, 375 struct resource *res) 376{ 377 struct iobus_softc *sc; 378 void *p; 379 380 sc = device_get_softc(bus); 381 382 if (type == SYS_RES_IRQ) 383 return (bus_activate_resource(bus, type, rid, res)); 384 385 if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) { 386 p = pmap_mapdev((vm_offset_t)rman_get_start(res) + sc->sc_addr, 387 (vm_size_t)rman_get_size(res)); 388 if (p == NULL) 389 return (ENOMEM); 390 rman_set_virtual(res, p); 391 rman_set_bushandle(res, (u_long)p); 392 } 393 394 return (rman_activate_resource(res)); 395} 396 397 398static int 399iobus_deactivate_resource(device_t bus, device_t child, int type, int rid, 400 struct resource *res) 401{ 402 /* 403 * If this is a memory resource, unmap it. 404 */ 405 if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) { 406 u_int32_t psize; 407 408 psize = rman_get_size(res); 409 pmap_unmapdev((vm_offset_t)rman_get_virtual(res), psize); 410 } 411 412 return (rman_deactivate_resource(res)); 413}
|