Call the MAPTI command earlier in the ITS driver

The GICv3 Software Overview suggests when allocating a new MSI/MSI-X
interrupt we need to call MAPD followed by MAPTI. Unfortunately the code
would place a MOVI command between these. This is invalid as it needs
values set by the MAPTI to be present.

Re-order so we allocate a temporary CPU for the interrupt, then use the
MAPTI command to assign the MSI to it.

MFC after:	2 weeks
Sponsored by:	DARPA, AFRL
This commit is contained in:
Andrew Turner 2020-01-31 11:33:11 +00:00
parent 0f4d8b77c0
commit 80ba579b00

View File

@ -928,21 +928,29 @@ gicv3_its_post_filter(device_t dev, struct intr_irqsrc *isrc)
}
static int
gicv3_its_bind_intr(device_t dev, struct intr_irqsrc *isrc)
gicv3_its_select_cpu(device_t dev, struct intr_irqsrc *isrc)
{
struct gicv3_its_irqsrc *girq;
struct gicv3_its_softc *sc;
sc = device_get_softc(dev);
girq = (struct gicv3_its_irqsrc *)isrc;
if (CPU_EMPTY(&isrc->isrc_cpu)) {
sc->gic_irq_cpu = intr_irq_next_cpu(sc->gic_irq_cpu,
&sc->sc_cpus);
CPU_SETOF(sc->gic_irq_cpu, &isrc->isrc_cpu);
}
its_cmd_movi(dev, girq);
return (0);
}
static int
gicv3_its_bind_intr(device_t dev, struct intr_irqsrc *isrc)
{
struct gicv3_its_irqsrc *girq;
gicv3_its_select_cpu(dev, isrc);
girq = (struct gicv3_its_irqsrc *)isrc;
its_cmd_movi(dev, girq);
return (0);
}
@ -1129,6 +1137,10 @@ gicv3_its_alloc_msi(device_t dev, device_t child, int count, int maxcount,
girq = &sc->sc_irqs[irq];
girq->gi_its_dev = its_dev;
srcs[i] = (struct intr_irqsrc *)girq;
/* Map the message to the given IRQ */
gicv3_its_select_cpu(dev, (struct intr_irqsrc *)girq);
its_cmd_mapti(dev, girq);
}
its_dev->lpis.lpi_busy += count;
*pic = dev;
@ -1189,6 +1201,10 @@ gicv3_its_alloc_msix(device_t dev, device_t child, device_t *pic,
girq = &sc->sc_irqs[irq];
girq->gi_its_dev = its_dev;
/* Map the message to the given IRQ */
gicv3_its_select_cpu(dev, (struct intr_irqsrc *)girq);
its_cmd_mapti(dev, girq);
*pic = dev;
*isrcp = (struct intr_irqsrc *)girq;
@ -1229,9 +1245,6 @@ gicv3_its_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc,
sc = device_get_softc(dev);
girq = (struct gicv3_its_irqsrc *)isrc;
/* Map the message to the given IRQ */
its_cmd_mapti(dev, girq);
*addr = vtophys(rman_get_virtual(sc->sc_its_res)) + GITS_TRANSLATER;
*data = girq->gi_irq - girq->gi_its_dev->lpis.lpi_base;