static void openpic_send_ipi(cpuid_t target, uint32_t mesg) { struct cpu_info * const ci = curcpu(); uint32_t cpumask = 0; switch (target) { case IPI_DST_ALL: case IPI_DST_NOTME: for (u_int i = 0; i < ncpu; i++) { struct cpu_info * const dst_ci = cpu_lookup(i); if (target == IPI_DST_ALL || dst_ci != ci) { cpumask |= 1 << cpu_index(dst_ci); atomic_or_32(&dst_ci->ci_pending_ipis, mesg); } } break; default: { struct cpu_info * const dst_ci = cpu_lookup(target); cpumask = 1 << cpu_index(dst_ci); atomic_or_32(&dst_ci->ci_pending_ipis, mesg); break; } } openpic_write(OPENPIC_IPI(cpu_index(ci), 1), cpumask); }
static void openpic_eoi(openpic_info *info, int cpu) { openpic_write(info, OPENPIC_EOI(cpu), 0); // the Linux driver does this: //openpic_read(info, OPENPIC_EOI(cpu)); }
void openpic_unmask(device_t dev, u_int irq) { struct openpic_softc *sc; uint32_t x; sc = device_get_softc(dev); if (irq < sc->sc_nirq) { x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); x &= ~OPENPIC_IMASK; openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); } else { x = openpic_read(sc, OPENPIC_IPI_VECTOR(0)); x &= ~OPENPIC_IMASK; openpic_write(sc, OPENPIC_IPI_VECTOR(0), x); } }
void md_setup_interrupts(void) { if (!openpic_base) return; /* clear the reset on all CPU's */ openpic_write(OPENPIC_PROC_INIT, 0); openpic_set_priority(cpu_number(), 0); }
static void openpic_disable_irq(openpic_info *info, int irq) { uint32 x; x = openpic_read(info, OPENPIC_SRC_VECTOR(irq)); x |= OPENPIC_IMASK; openpic_write(info, OPENPIC_SRC_VECTOR(irq), x); }
static void openpic_set_priority(openpic_info *info, int cpu, int pri) { uint32 x; x = openpic_read(info, OPENPIC_CPU_PRIORITY(cpu)); x &= ~OPENPIC_CPU_PRIORITY_MASK; x |= pri; openpic_write(info, OPENPIC_CPU_PRIORITY(cpu), x); }
void openpic_enable(device_t dev, u_int irq, u_int vector) { struct openpic_softc *sc; uint32_t x; sc = device_get_softc(dev); if (irq < sc->sc_nirq) { x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); x &= ~(OPENPIC_IMASK | OPENPIC_VECTOR_MASK); x |= vector; openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); } else { x = openpic_read(sc, OPENPIC_IPI_VECTOR(0)); x &= ~(OPENPIC_IMASK | OPENPIC_VECTOR_MASK); x |= vector; openpic_write(sc, OPENPIC_IPI_VECTOR(0), x); } }
void openpic_set_priority(int cpu, int pri) { u_int x; x = openpic_read(OPENPIC_CPU_PRIORITY(cpu)); x &= ~OPENPIC_CPU_PRIORITY_MASK; x |= pri; openpic_write(OPENPIC_CPU_PRIORITY(cpu), x); }
void setup_openpic_ipi(void) { uint32_t x; ipiops.ppc_send_ipi = openpic_send_ipi; ipiops.ppc_establish_ipi = openpic_establish_ipi; ipiops.ppc_ipi_vector = IPI_VECTOR; /* Some (broken) openpic's byteswap on read, but not write. */ openpic_write(OPENPIC_IPI_VECTOR(0), OPENPIC_IMASK); x = openpic_read(OPENPIC_IPI_VECTOR(0)); if (x != OPENPIC_IMASK) x = bswap32(openpic_read(OPENPIC_IPI_VECTOR(1))); else x = openpic_read(OPENPIC_IPI_VECTOR(1)); x &= ~(OPENPIC_IMASK | OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK); x |= (15 << OPENPIC_PRIORITY_SHIFT) | ipiops.ppc_ipi_vector; openpic_write(OPENPIC_IPI_VECTOR(1), x); }
void openpic_eoi(device_t dev, u_int irq __unused) { struct openpic_softc *sc; u_int cpuid; cpuid = (dev == root_pic) ? PCPU_GET(cpuid) : 0; sc = device_get_softc(dev); openpic_write(sc, OPENPIC_PCPU_EOI(cpuid), 0); }
void openpic_bind(device_t dev, u_int irq, cpumask_t cpumask) { struct openpic_softc *sc; /* If we aren't directly connected to the CPU, this won't work */ if (dev != root_pic) return; sc = device_get_softc(dev); openpic_write(sc, OPENPIC_IDEST(irq), cpumask); }
void openpic_ipi(device_t dev, u_int cpu) { struct openpic_softc *sc; KASSERT(dev == root_pic, ("Cannot send IPIs from non-root OpenPIC")); sc = device_get_softc(dev); sched_pin(); openpic_write(sc, OPENPIC_PCPU_IPI_DISPATCH(PCPU_GET(cpuid), 0), 1u << cpu); sched_unpin(); }
static __inline void openpic_set_priority(struct openpic_softc *sc, int pri) { u_int tpr; uint32_t x; sched_pin(); tpr = OPENPIC_PCPU_TPR((sc->sc_dev == root_pic) ? PCPU_GET(cpuid) : 0); x = openpic_read(sc, tpr); x &= ~OPENPIC_TPR_MASK; x |= pri; openpic_write(sc, tpr, x); sched_unpin(); }
static void openpic_enable_irq(openpic_info *info, int irq, int type) { // TODO: Align this code with the sequence recommended in the Open PIC // Specification (v 1.2 section 5.2.2). uint32 x; x = openpic_read(info, OPENPIC_SRC_VECTOR(irq)); x &= ~(OPENPIC_IMASK | OPENPIC_SENSE_LEVEL | OPENPIC_SENSE_EDGE); if (type == IRQ_TYPE_LEVEL) x |= OPENPIC_SENSE_LEVEL; else x |= OPENPIC_SENSE_EDGE; openpic_write(info, OPENPIC_SRC_VECTOR(irq), x); }
int md_setup_trampoline(volatile struct cpu_hatch_data *h, struct cpu_info *ci) { if (!openpic_base) return -1; /* construct an absolute branch instruction */ /* ba cpu_spinup_trampoline */ *(u_int *)EXC_RST = 0x48000002 | (u_int)cpu_spinup_trampoline; __syncicache((void *)EXC_RST, 0x100); h->running = -1; /* Start secondary CPU. */ openpic_write(OPENPIC_PROC_INIT, (1 << 1)); return 1; }
void opic_finish_setup(struct pic_ops *pic) { uint32_t cpumask = 0; int i; #ifdef OPENPIC_DISTRIBUTE for (i = 0; i < ncpu; i++) cpumask |= (1 << cpu_info[i].ci_index); #else cpumask = 1; #endif for (i = 0; i < pic->pic_numintrs; i++) { /* send all interrupts to all active CPUs */ openpic_write(OPENPIC_IDEST(i), cpumask); } }
void openpic_config(device_t dev, u_int irq, enum intr_trigger trig, enum intr_polarity pol) { struct openpic_softc *sc; uint32_t x; sc = device_get_softc(dev); x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); if (pol == INTR_POLARITY_LOW) x &= ~OPENPIC_POLARITY_POSITIVE; else x |= OPENPIC_POLARITY_POSITIVE; if (trig == INTR_TRIGGER_EDGE) x &= ~OPENPIC_SENSE_LEVEL; else x |= OPENPIC_SENSE_LEVEL; openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); }
static status_t openpic_init(openpic_info *info) { uint32 x = openpic_read(info, OPENPIC_FEATURE); const char *featureVersion; char versionBuffer[64]; switch (x & OPENPIC_FEATURE_VERSION_MASK) { case 1: featureVersion = "1.0"; break; case 2: featureVersion = "1.2"; break; case 3: featureVersion = "1.3"; break; default: snprintf(versionBuffer, sizeof(versionBuffer), "unknown (feature reg: 0x%lx)", x); featureVersion = versionBuffer; break; } info->cpu_count = ((x & OPENPIC_FEATURE_LAST_CPU_MASK) >> OPENPIC_FEATURE_LAST_CPU_SHIFT) + 1; info->irq_count = ((x & OPENPIC_FEATURE_LAST_IRQ_MASK) >> OPENPIC_FEATURE_LAST_IRQ_SHIFT) + 1; /* * PSIM seems to report 1 too many IRQs */ // if (sc->sc_psim) // sc->sc_nirq--; dprintf("openpic: Version %s, supports %d CPUs and %d irqs\n", featureVersion, info->cpu_count, info->irq_count); /* disable all interrupts */ for (int irq = 0; irq < info->irq_count; irq++) openpic_write(info, OPENPIC_SRC_VECTOR(irq), OPENPIC_IMASK); openpic_set_priority(info, 0, 15); /* we don't need 8259 passthrough mode */ x = openpic_read(info, OPENPIC_CONFIG); x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE; openpic_write(info, OPENPIC_CONFIG, x); /* send all interrupts to cpu 0 */ for (int irq = 0; irq < info->irq_count; irq++) openpic_write(info, OPENPIC_IDEST(irq), 1 << 0); for (int irq = 0; irq < info->irq_count; irq++) { x = irq; x |= OPENPIC_IMASK; x |= OPENPIC_POLARITY_POSITIVE; x |= OPENPIC_SENSE_LEVEL; x |= 8 << OPENPIC_PRIORITY_SHIFT; openpic_write(info, OPENPIC_SRC_VECTOR(irq), x); } /* XXX IPI */ /* XXX set spurious intr vector */ openpic_set_priority(info, 0, 0); /* clear all pending interrupts */ for (int irq = 0; irq < info->irq_count; irq++) { openpic_read_irq(info, 0); openpic_eoi(info, 0); } return B_OK; }
int openpic_attach(device_t dev) { struct openpic_softc *sc; u_int cpu, ipi, irq; u_int32_t x; sc = device_get_softc(dev); sc->sc_dev = dev; sc->sc_rid = 0; sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid, RF_ACTIVE); if (sc->sc_memr == NULL) { device_printf(dev, "Could not alloc mem resource!\n"); return (ENXIO); } sc->sc_bt = rman_get_bustag(sc->sc_memr); sc->sc_bh = rman_get_bushandle(sc->sc_memr); /* Reset the PIC */ x = openpic_read(sc, OPENPIC_CONFIG); x |= OPENPIC_CONFIG_RESET; openpic_write(sc, OPENPIC_CONFIG, x); while (openpic_read(sc, OPENPIC_CONFIG) & OPENPIC_CONFIG_RESET) { powerpc_sync(); DELAY(100); } /* Check if this is a cascaded PIC */ sc->sc_irq = 0; sc->sc_intr = NULL; do { struct resource_list *rl; rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); if (rl == NULL) break; if (resource_list_find(rl, SYS_RES_IRQ, 0) == NULL) break; sc->sc_intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irq, RF_ACTIVE); /* XXX Cascaded PICs pass NULL trapframes! */ bus_setup_intr(dev, sc->sc_intr, INTR_TYPE_MISC | INTR_MPSAFE, openpic_intr, NULL, dev, &sc->sc_icookie); } while (0); /* Reset the PIC */ x = openpic_read(sc, OPENPIC_CONFIG); x |= OPENPIC_CONFIG_RESET; openpic_write(sc, OPENPIC_CONFIG, x); while (openpic_read(sc, OPENPIC_CONFIG) & OPENPIC_CONFIG_RESET) { powerpc_sync(); DELAY(100); } x = openpic_read(sc, OPENPIC_FEATURE); switch (x & OPENPIC_FEATURE_VERSION_MASK) { case 1: sc->sc_version = "1.0"; break; case 2: sc->sc_version = "1.2"; break; case 3: sc->sc_version = "1.3"; break; default: sc->sc_version = "unknown"; break; } sc->sc_ncpu = ((x & OPENPIC_FEATURE_LAST_CPU_MASK) >> OPENPIC_FEATURE_LAST_CPU_SHIFT) + 1; sc->sc_nirq = ((x & OPENPIC_FEATURE_LAST_IRQ_MASK) >> OPENPIC_FEATURE_LAST_IRQ_SHIFT) + 1; /* * PSIM seems to report 1 too many IRQs and CPUs */ if (sc->sc_psim) { sc->sc_nirq--; sc->sc_ncpu--; } if (bootverbose) device_printf(dev, "Version %s, supports %d CPUs and %d irqs\n", sc->sc_version, sc->sc_ncpu, sc->sc_nirq); for (cpu = 0; cpu < sc->sc_ncpu; cpu++) openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 15); /* Reset and disable all interrupts. */ for (irq = 0; irq < sc->sc_nirq; irq++) { x = irq; /* irq == vector. */ x |= OPENPIC_IMASK; x |= OPENPIC_POLARITY_NEGATIVE; x |= OPENPIC_SENSE_LEVEL; x |= 8 << OPENPIC_PRIORITY_SHIFT; openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); } /* Reset and disable all IPIs. */ for (ipi = 0; ipi < 4; ipi++) { x = sc->sc_nirq + ipi; x |= OPENPIC_IMASK; x |= 15 << OPENPIC_PRIORITY_SHIFT; openpic_write(sc, OPENPIC_IPI_VECTOR(ipi), x); } /* we don't need 8259 passthrough mode */ x = openpic_read(sc, OPENPIC_CONFIG); x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE; openpic_write(sc, OPENPIC_CONFIG, x); /* send all interrupts to cpu 0 */ for (irq = 0; irq < sc->sc_nirq; irq++) openpic_write(sc, OPENPIC_IDEST(irq), 1 << 0); /* clear all pending interrupts from cpu 0 */ for (irq = 0; irq < sc->sc_nirq; irq++) { (void)openpic_read(sc, OPENPIC_PCPU_IACK(0)); openpic_write(sc, OPENPIC_PCPU_EOI(0), 0); } for (cpu = 0; cpu < sc->sc_ncpu; cpu++) openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 0); powerpc_register_pic(dev, sc->sc_nirq); /* If this is not a cascaded PIC, it must be the root PIC */ if (sc->sc_intr == NULL) root_pic = dev; return (0); }