-/* $OpenBSD: mvkpcie.c,v 1.7 2020/07/17 08:07:34 patrick Exp $ */
+/* $OpenBSD: mvkpcie.c,v 1.8 2021/01/19 19:46:40 kettenis Exp $ */
/*
* Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
* Copyright (c) 2020 Patrick Wildt <patrick@blueri.se>
uint32_t sc_bridge_io_hi;
uint32_t sc_bridge_mem;
+ struct interrupt_controller sc_ic;
+ struct intrhand *sc_intx_handlers[4];
struct interrupt_controller sc_msi_ic;
struct intrhand *sc_msi_handlers[32];
struct mvkpcie_dmamem *sc_msi_addr;
bus_space_handle_t *);
int mvkpcie_intc_intr(void *);
+void *mvkpcie_intc_intr_establish(void *, int *, int, struct cpu_info *,
+ int (*)(void *), void *, char *);
+void mvkpcie_intc_intr_disestablish(void *);
void *mvkpcie_intc_intr_establish_msi(void *, uint64_t *, uint64_t *,
int , struct cpu_info *, int (*)(void *), void *, char *);
void mvkpcie_intc_intr_disestablish_msi(void *);
int i, j, nranges, rangeslen;
pcireg_t csr, bir, blr;
uint32_t reg;
+ int node;
int timo;
if (faa->fa_nreg < 1) {
pba.pba_bus = sc->sc_bus;
pba.pba_flags |= PCI_FLAGS_MSI_ENABLED;
+ node = OF_getnodebyname(faa->fa_node, "interrupt-controller");
+ if (node) {
+ sc->sc_ic.ic_node = node;
+ sc->sc_ic.ic_cookie = self;
+ sc->sc_ic.ic_establish = mvkpcie_intc_intr_establish;
+ sc->sc_ic.ic_disestablish = mvkpcie_intc_intr_disestablish;
+ arm_intr_register_fdt(&sc->sc_ic);
+ }
+
sc->sc_msi_ic.ic_node = faa->fa_node;
sc->sc_msi_ic.ic_cookie = self;
sc->sc_msi_ic.ic_establish_msi = mvkpcie_intc_intr_establish_msi;
int
mvkpcie_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
{
- return -1;
+ int pin = pa->pa_rawintrpin;
+
+ if (pin == 0 || pin > PCI_INTERRUPT_PIN_MAX)
+ return -1;
+
+ if (pa->pa_tag == 0)
+ return -1;
+
+ ihp->ih_pc = pa->pa_pc;
+ ihp->ih_tag = pa->pa_intrtag;
+ ihp->ih_intrpin = pa->pa_intrpin;
+ ihp->ih_type = PCI_INTX;
+
+ return 0;
}
const char *
if (!(HREAD4(sc, HOST_CTRL_INT_STATUS) & HOST_CTRL_INT_MASK_CORE_INT))
return 0;
- if (!(HREAD4(sc, PCIE_CORE_ISR0_STATUS) & PCIE_CORE_ISR0_MASK_MSI_INT))
- return 0;
+ if (HREAD4(sc, PCIE_CORE_ISR0_STATUS) & PCIE_CORE_ISR0_MASK_MSI_INT) {
+ pending = HREAD4(sc, PCIE_CORE_MSI_STATUS);
+ while (pending) {
+ i = ffs(pending) - 1;
+ HWRITE4(sc, PCIE_CORE_MSI_STATUS, (1 << i));
+ pending &= ~(1 << i);
+
+ i = HREAD4(sc, PCIE_CORE_MSI_PAYLOAD) & 0xff;
+ if ((ih = sc->sc_msi_handlers[i]) != NULL) {
+ s = splraise(ih->ih_ipl);
+ if (ih->ih_func(ih->ih_arg))
+ ih->ih_count.ec_count++;
+ splx(s);
+ }
+ }
+ HWRITE4(sc, PCIE_CORE_ISR0_STATUS, PCIE_CORE_ISR0_MASK_MSI_INT);
+ }
- pending = HREAD4(sc, PCIE_CORE_MSI_STATUS);
- while (pending) {
- i = ffs(pending) - 1;
- HWRITE4(sc, PCIE_CORE_MSI_STATUS, (1 << i));
- pending &= ~(1 << i);
-
- i = HREAD4(sc, PCIE_CORE_MSI_PAYLOAD) & 0xff;
- if ((ih = sc->sc_msi_handlers[i]) != NULL) {
- s = splraise(ih->ih_ipl);
- if (ih->ih_func(ih->ih_arg))
- ih->ih_count.ec_count++;
- splx(s);
+ pending = HREAD4(sc, PCIE_CORE_ISR1_STATUS);
+ for (i = 0; i < nitems(sc->sc_intx_handlers); i++) {
+ if (pending & PCIE_CORE_ISR1_MASK_INTX(i)) {
+ if ((ih = sc->sc_intx_handlers[i]) != NULL) {
+ s = splraise(ih->ih_ipl);
+ if (ih->ih_func(ih->ih_arg))
+ ih->ih_count.ec_count++;
+ splx(s);
+ }
}
}
+ HWRITE4(sc, PCIE_CORE_ISR1_STATUS, pending);
- HWRITE4(sc, PCIE_CORE_ISR0_STATUS, PCIE_CORE_ISR0_MASK_MSI_INT);
HWRITE4(sc, HOST_CTRL_INT_STATUS, HOST_CTRL_INT_MASK_CORE_INT);
return 1;
}
+void *
+mvkpcie_intc_intr_establish(void *cookie, int *cell, int level,
+ struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
+{
+ struct mvkpcie_softc *sc = (struct mvkpcie_softc *)cookie;
+ struct intrhand *ih;
+ int irq = cell[0];
+ int s;
+
+ if (ci != NULL && !CPU_IS_PRIMARY(ci))
+ return NULL;
+
+ if (irq < 0 || irq > nitems(sc->sc_intx_handlers))
+ return NULL;
+
+ /* Don't allow shared interrupts for now. */
+ if (sc->sc_intx_handlers[irq])
+ return NULL;
+
+ ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
+ ih->ih_func = func;
+ ih->ih_arg = arg;
+ ih->ih_ipl = level & IPL_IRQMASK;
+ ih->ih_irq = irq;
+ ih->ih_name = name;
+ ih->ih_sc = sc;
+
+ s = splhigh();
+
+ sc->sc_intx_handlers[irq] = ih;
+
+ if (name != NULL)
+ evcount_attach(&ih->ih_count, name, &ih->ih_irq);
+
+ mvkpcie_intc_recalc_ipl(sc);
+
+ splx(s);
+
+ HCLR4(sc, PCIE_CORE_ISR1_MASK, PCIE_CORE_ISR1_MASK_INTX(irq));
+
+ return (ih);
+}
+
+void
+mvkpcie_intc_intr_disestablish(void *cookie)
+{
+ struct intrhand *ih = cookie;
+ struct mvkpcie_softc *sc = ih->ih_sc;
+ int s;
+
+ HSET4(sc, PCIE_CORE_ISR1_MASK, PCIE_CORE_ISR1_MASK_INTX(ih->ih_irq));
+
+ s = splhigh();
+
+ sc->sc_intx_handlers[ih->ih_irq] = NULL;
+ if (ih->ih_name != NULL)
+ evcount_detach(&ih->ih_count);
+ free(ih, M_DEVBUF, sizeof(*ih));
+
+ mvkpcie_intc_recalc_ipl(sc);
+
+ splx(s);
+}
+
void *
mvkpcie_intc_intr_establish_msi(void *cookie, uint64_t *addr, uint64_t *data,
int level, struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
int min = IPL_HIGH;
int irq;
- for (irq = 0; irq < nitems(sc->sc_msi_handlers); irq++) {
- ih = sc->sc_msi_handlers[irq];
+ for (irq = 0; irq < nitems(sc->sc_intx_handlers); irq++) {
+ ih = sc->sc_intx_handlers[irq];
if (ih == NULL)
continue;