/* * Map an interrupt using the firmware reg, interrupt-map and * interrupt-map-mask properties. * The interrupt property to be mapped must be of size intrsz, and pointed to * by intr. The regs property of the node for which the mapping is done must * be passed as regs. This property is an array of register specifications; * the size of the address part of such a specification must be passed as * physsz. Only the first element of the property is used. * imap and imapsz hold the interrupt mask and it's size. * imapmsk is a pointer to the interrupt-map-mask property, which must have * a size of physsz + intrsz; it may be NULL, in which case a full mask is * assumed. * maskbuf must point to a buffer of length physsz + intrsz. * The interrupt is returned in result, which must point to a buffer of length * rintrsz (which gives the expected size of the mapped interrupt). * Returns 1 if a mapping was found, 0 otherwise. */ int ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz, void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result, int rintrsz, phandle_t *iparent) { phandle_t parent; uint8_t *ref = maskbuf; uint8_t *uiintr = intr; uint8_t *uiregs = regs; uint8_t *uiimapmsk = imapmsk; uint8_t *mptr; pcell_t pintrsz; int i, rsz, tsz; rsz = -1; if (imapmsk != NULL) { for (i = 0; i < physsz; i++) ref[i] = uiregs[i] & uiimapmsk[i]; for (i = 0; i < intrsz; i++) ref[physsz + i] = uiintr[i] & uiimapmsk[physsz + i]; } else { bcopy(regs, ref, physsz); bcopy(intr, ref + physsz, intrsz); } mptr = imap; i = imapsz; while (i > 0) { bcopy(mptr + physsz + intrsz, &parent, sizeof(parent)); if (OF_searchprop(parent, "#interrupt-cells", &pintrsz, sizeof(pintrsz)) == -1) pintrsz = 1; /* default */ pintrsz *= sizeof(pcell_t); /* Compute the map stride size. */ tsz = physsz + intrsz + sizeof(phandle_t) + pintrsz; KASSERT(i >= tsz, ("ofw_bus_search_intrmap: truncated map")); /* * XXX: Apple hardware uses a second cell to set information * on the interrupt trigger type. This information should * be used somewhere to program the PIC. */ if (bcmp(ref, mptr, physsz + intrsz) == 0) { bcopy(mptr + physsz + intrsz + sizeof(parent), result, rintrsz); if (iparent != NULL) *iparent = parent; return (1); } mptr += tsz; i -= tsz; } return (0); }
static int vdevice_attach(device_t dev) { phandle_t root, child; device_t cdev; int icells, i, nintr, *intr; phandle_t iparent; struct vdevice_devinfo *dinfo; root = ofw_bus_get_node(dev); for (child = OF_child(root); child != 0; child = OF_peer(child)) { dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&dinfo->mdi_obdinfo, child) != 0) { free(dinfo, M_DEVBUF); continue; } resource_list_init(&dinfo->mdi_resources); if (OF_searchprop(child, "#interrupt-cells", &icells, sizeof(icells)) <= 0) icells = 2; if (OF_getprop(child, "interrupt-parent", &iparent, sizeof(iparent)) <= 0) iparent = -1; nintr = OF_getprop_alloc(child, "interrupts", sizeof(*intr), (void **)&intr); if (nintr > 0) { for (i = 0; i < nintr; i += icells) { u_int irq = intr[i]; if (iparent != -1) irq = ofw_bus_map_intr(dev, iparent, icells, &intr[i]); resource_list_add(&dinfo->mdi_resources, SYS_RES_IRQ, i, irq, irq, i); } } cdev = device_add_child(dev, NULL, -1); if (cdev == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", dinfo->mdi_obdinfo.obd_name); ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo); free(dinfo, M_DEVBUF); continue; } device_set_ivars(cdev, dinfo); } return (bus_generic_attach(dev)); }
int fdt_parent_addr_cells(phandle_t node) { pcell_t addr_cells; /* Find out #address-cells of the superior bus. */ if (OF_searchprop(OF_parent(node), "#address-cells", &addr_cells, sizeof(addr_cells)) <= 0) return (2); return ((int)fdt32_to_cpu(addr_cells)); }
/* * Add an interrupt to the dev's resource list if present */ static void unin_chip_add_intr(phandle_t devnode, struct unin_chip_devinfo *dinfo) { phandle_t iparent; int *intr; int i, nintr; int icells; if (dinfo->udi_ninterrupts >= 6) { printf("unin: device has more than 6 interrupts\n"); return; } nintr = OF_getprop_alloc(devnode, "interrupts", sizeof(*intr), (void **)&intr); if (nintr == -1) { nintr = OF_getprop_alloc(devnode, "AAPL,interrupts", sizeof(*intr), (void **)&intr); if (nintr == -1) return; } if (intr[0] == -1) return; if (OF_getprop(devnode, "interrupt-parent", &iparent, sizeof(iparent)) <= 0) panic("Interrupt but no interrupt parent!\n"); if (OF_searchprop(iparent, "#interrupt-cells", &icells, sizeof(icells)) <= 0) icells = 1; for (i = 0; i < nintr; i+=icells) { u_int irq = MAP_IRQ(iparent, intr[i]); resource_list_add(&dinfo->udi_resources, SYS_RES_IRQ, dinfo->udi_ninterrupts, irq, irq, 1); if (icells > 1) { powerpc_config_intr(irq, (intr[i+1] & 1) ? INTR_TRIGGER_LEVEL : INTR_TRIGGER_EDGE, INTR_POLARITY_LOW); } dinfo->udi_interrupts[dinfo->udi_ninterrupts] = irq; dinfo->udi_ninterrupts++; } }
/* * Add an interrupt to the dev's resource list if present */ static void macio_add_intr(phandle_t devnode, struct macio_devinfo *dinfo) { int *intr; int i, nintr; int icells; if (dinfo->mdi_ninterrupts >= 6) { printf("macio: device has more than 6 interrupts\n"); return; } if (OF_searchprop(devnode, "#interrupt-cells", &icells, sizeof(icells)) <= 0) icells = 1; nintr = OF_getprop_alloc(devnode, "interrupts", sizeof(*intr), (void **)&intr); if (nintr == -1) { nintr = OF_getprop_alloc(devnode, "AAPL,interrupts", sizeof(*intr), (void **)&intr); if (nintr == -1) return; } if (intr[0] == -1) return; for (i = 0; i < nintr; i+=icells) { resource_list_add(&dinfo->mdi_resources, SYS_RES_IRQ, dinfo->mdi_ninterrupts, intr[i], intr[i], 1); dinfo->mdi_interrupts[dinfo->mdi_ninterrupts] = intr[i]; dinfo->mdi_ninterrupts++; } }
static struct nexus_devinfo * nexus_setup_dinfo(device_t dev, phandle_t node) { struct nexus_softc *sc; struct nexus_devinfo *ndi; uint32_t *reg, *intr, icells; uint64_t phys, size; phandle_t iparent; int i, j; int nintr; int nreg; sc = device_get_softc(dev); ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&ndi->ndi_obdinfo, node) != 0) { free(ndi, M_DEVBUF); return (NULL); } if (NEXUS_EXCLUDED(ndi->ndi_obdinfo.obd_name, ndi->ndi_obdinfo.obd_type)) { ofw_bus_gen_destroy_devinfo(&ndi->ndi_obdinfo); free(ndi, M_DEVBUF); return (NULL); } resource_list_init(&ndi->ndi_rl); nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)®); if (nreg == -1) nreg = 0; for (i = 0; i < nreg; i += sc->acells + sc->scells) { phys = size = 0; for (j = 0; j < sc->acells; j++) { phys <<= 32; phys |= reg[i + j]; } for (j = 0; j < sc->scells; j++) { size <<= 32; size |= reg[i + sc->acells + j]; } /* Skip the dummy reg property of glue devices like ssm(4). */ if (size != 0) resource_list_add(&ndi->ndi_rl, SYS_RES_MEMORY, i, phys, phys + size - 1, size); } free(reg, M_OFWPROP); nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intr), (void **)&intr); if (nintr > 0) { iparent = 0; OF_searchprop(node, "interrupt-parent", &iparent, sizeof(iparent)); OF_searchprop(iparent, "#interrupt-cells", &icells, sizeof(icells)); for (i = 0; i < nintr; i+= icells) { intr[i] = MAP_IRQ(iparent, intr[i]); resource_list_add(&ndi->ndi_rl, SYS_RES_IRQ, i, intr[i], intr[i], 1); if (icells > 1) { powerpc_config_intr(intr[i], (intr[i+1] & 1) ? INTR_TRIGGER_LEVEL : INTR_TRIGGER_EDGE, INTR_POLARITY_LOW); } } free(intr, M_OFWPROP); } return (ndi); }
/* * Scan Open Firmware child nodes, and attach these as children * of the macgpio bus */ static int macgpio_attach(device_t dev) { struct macgpio_softc *sc; struct macgpio_devinfo *dinfo; phandle_t root, child, iparent; device_t cdev; uint32_t irq; sc = device_get_softc(dev); root = sc->sc_node = ofw_bus_get_node(dev); sc->sc_gpios = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_gpios_rid, RF_ACTIVE); /* * Iterate through the sub-devices */ for (child = OF_child(root); child != 0; child = OF_peer(child)) { dinfo = malloc(sizeof(*dinfo), M_MACGPIO, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&dinfo->mdi_obdinfo, child) != 0) { free(dinfo, M_MACGPIO); continue; } if (OF_getprop(child,"reg",&dinfo->gpio_num, sizeof(dinfo->gpio_num)) != sizeof(dinfo->gpio_num)) { /* * Some early GPIO controllers don't provide GPIO * numbers for GPIOs designed only to provide * interrupt resources. We should still allow these * to attach, but with caution. */ dinfo->gpio_num = -1; } resource_list_init(&dinfo->mdi_resources); if (OF_getprop(child, "interrupts", &irq, sizeof(irq)) == sizeof(irq)) { OF_searchprop(child, "interrupt-parent", &iparent, sizeof(iparent)); resource_list_add(&dinfo->mdi_resources, SYS_RES_IRQ, 0, MAP_IRQ(iparent, irq), MAP_IRQ(iparent, irq), 1); } /* Fix messed-up offsets */ if (dinfo->gpio_num > 0x50) dinfo->gpio_num -= 0x50; cdev = device_add_child(dev, NULL, -1); if (cdev == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", dinfo->mdi_obdinfo.obd_name); ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo); free(dinfo, M_MACGPIO); continue; } device_set_ivars(cdev, dinfo); } return (bus_generic_attach(dev)); }