int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet, unsigned int *virq) { int result; struct ps3_private *pd; result = ps3_virq_setup(cpu, outlet, virq); if (result) { pr_debug("%s:%d: ps3_virq_setup failed\n", __func__, __LINE__); goto fail_setup; } pd = irq_get_chip_data(*virq); /* Binds outlet to cpu + virq. */ result = lv1_connect_irq_plug_ext(pd->ppe_id, pd->thread_id, *virq, outlet, 0); if (result) { pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n", __func__, __LINE__, ps3_result(result)); result = -EPERM; goto fail_connect; } return result; fail_connect: ps3_virq_destroy(*virq); fail_setup: return result; }
int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet, unsigned int *virq) { int result; struct ps3_private *pd; /* This defines the default interrupt distribution policy. */ if (cpu == PS3_BINDING_CPU_ANY) cpu = 0; pd = &per_cpu(ps3_private, cpu); *virq = irq_create_mapping(NULL, outlet); if (*virq == NO_IRQ) { pr_debug("%s:%d: irq_create_mapping failed: outlet %lu\n", __func__, __LINE__, outlet); result = -ENOMEM; goto fail_create; } /* Binds outlet to cpu + virq. */ result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0); if (result) { pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n", __func__, __LINE__, ps3_result(result)); result = -EPERM; goto fail_connect; } pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__, outlet, cpu, *virq); result = set_irq_chip_data(*virq, pd); if (result) { pr_debug("%s:%d: set_irq_chip_data failed\n", __func__, __LINE__); goto fail_set; } return result; fail_set: lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, *virq); fail_connect: irq_dispose_mapping(*virq); fail_create: return result; }
static int ps3pic_attach(device_t dev) { struct ps3pic_softc *sc; uint64_t ppe; int thread; sc = device_get_softc(dev); sc->bitmap_thread0 = contigmalloc(128 /* 512 bits * 2 */, M_PS3PIC, M_NOWAIT | M_ZERO, 0, BUS_SPACE_MAXADDR, 64 /* alignment */, PAGE_SIZE /* boundary */); sc->mask_thread0 = sc->bitmap_thread0 + 4; sc->bitmap_thread1 = sc->bitmap_thread0 + 8; sc->mask_thread1 = sc->bitmap_thread0 + 12; lv1_get_logical_ppe_id(&ppe); thread = 32 - fls(mfctrl()); lv1_configure_irq_state_bitmap(ppe, thread, vtophys(sc->bitmap_thread0)); #ifdef SMP lv1_configure_irq_state_bitmap(ppe, !thread, vtophys(sc->bitmap_thread1)); /* Map both IPIs to the same VIRQ to avoid changes in intr_machdep */ lv1_construct_event_receive_port(&sc->sc_ipi_outlet[0]); lv1_connect_irq_plug_ext(ppe, thread, sc->sc_ipi_outlet[0], sc->sc_ipi_outlet[0], 0); lv1_construct_event_receive_port(&sc->sc_ipi_outlet[1]); lv1_connect_irq_plug_ext(ppe, !thread, sc->sc_ipi_outlet[0], sc->sc_ipi_outlet[1], 0); #endif powerpc_register_pic(dev, 0, sc->sc_ipi_outlet[0], 1, FALSE); return (0); }
static void ps3bus_resources_init_by_type(struct rman *rm, int bus_index, int dev_index, uint64_t irq_type, uint64_t reg_type, struct ps3bus_devinfo *dinfo) { uint64_t _irq_type, irq, outlet; uint64_t _reg_type, paddr, len; uint64_t ppe, junk; int i, result; int thread; resource_list_init(&dinfo->resources); lv1_get_logical_ppe_id(&ppe); thread = 32 - fls(mfctrl()); /* Scan for interrupts */ for (i = 0; i < 10; i++) { result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, (lv1_repository_string("bus") >> 32) | bus_index, lv1_repository_string("dev") | dev_index, lv1_repository_string("intr") | i, 0, &_irq_type, &irq); if (result != 0) break; if (_irq_type != irq_type) continue; lv1_construct_io_irq_outlet(irq, &outlet); lv1_connect_irq_plug_ext(ppe, thread, outlet, outlet, 0); resource_list_add(&dinfo->resources, SYS_RES_IRQ, i, outlet, outlet, 1); } /* Scan for registers */ for (i = 0; i < 10; i++) { result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, (lv1_repository_string("bus") >> 32) | bus_index, lv1_repository_string("dev") | dev_index, lv1_repository_string("reg") | i, lv1_repository_string("type"), &_reg_type, &junk); if (result != 0) break; if (_reg_type != reg_type) continue; result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, (lv1_repository_string("bus") >> 32) | bus_index, lv1_repository_string("dev") | dev_index, lv1_repository_string("reg") | i, lv1_repository_string("data"), &paddr, &len); result = lv1_map_device_mmio_region(dinfo->bus, dinfo->dev, paddr, len, 12 /* log_2(4 KB) */, &paddr); if (result != 0) { printf("Mapping registers failed for device " "%d.%d (%ld.%ld): %d\n", dinfo->bus, dinfo->dev, dinfo->bustype, dinfo->devtype, result); break; } rman_manage_region(rm, paddr, paddr + len - 1); resource_list_add(&dinfo->resources, SYS_RES_MEMORY, i, paddr, paddr + len, len); } }