rite_8(gicv3, GICR_PROPBASER, xbaser); /* Check the cache attributes we set */ @@ -835,8 +881,11 @@ its_init_cpu_lpi(device_t dev, struct gicv3_its_softc *sc) * Set the LPI pending table base */ xbaser = vtophys(sc->sc_pend_base[cpuid]) | - (GICR_PENDBASER_CACHE_NIWAWB << GICR_PENDBASER_CACHE_SHIFT) | - (GICR_PENDBASER_SHARE_IS << GICR_PENDBASER_SHARE_SHIFT); + (GICR_PENDBASER_CACHE_NIWAWB << GICR_PENDBASER_CACHE_SHIFT); + if (sc->sc_its_flags & ITS_FLAGS_FORCE_NOSHAREABLE) + xbaser |= GITS_CBASER_SHARE_NS << GITS_CBASER_SHARE_SHIFT; + else + xbaser |= GITS_CBASER_SHARE_IS << GITS_CBASER_SHARE_SHIFT; gic_r_write_8(gicv3, GICR_PENDBASER, xbaser); @@ -1017,6 +1066,7 @@ gicv3_its_attach(device_t dev) sc->sc_irq_length = gicv3_get_nirqs(dev); sc->sc_irq_base = GIC_FIRST_LPI; sc->sc_irq_base += device_get_unit(dev) * sc->sc_irq_length; + sc->malloc_max_addr = ~0; rid = 0; sc->sc_its_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, @@ -1034,7 +1084,7 @@ gicv3_its_attach(device_t dev) CPU_COPY(&all_cpus, &sc->sc_cpus); iidr = gic_its_read_4(sc, GITS_IIDR); for (i = 0; i < nitems(its_quirks); i++) { - if ((iidr & its_quirks[i].iidr_mask) == its_quirks[i].iidr) { + if (its_quirks[i].detect(dev)) { if (bootverbose) { device_printf(dev, "Applying %s\n", its_quirks[i].desc); @@ -1128,6 +1178,21 @@ gicv3_its_detach(device_t dev) return (ENXIO); } +static bool +its_detect_cavium_22375(device_t dev) +{ + uint32_t iidr; + struct gicv3_its_softc *sc; + + sc = device_get_softc(dev); + iidr = gic_its_read_4(sc, GITS_IIDR); + if ((iidr & ~GITS_IIDR_REVISION_MASK) == + GITS_IIDR_RAW(GITS_IIDR_IMPL_CAVIUM, GITS_IIDR_PROD_THUNDER, + GITS_IIDR_VAR_THUNDER_1, 0)) + return (true); + return(false); +} + static void its_quirk_cavium_22375(device_t dev) { @@ -1151,6 +1216,46 @@ its_quirk_cavium_22375(device_t dev) } } +#ifdef FDT +static bool +its_detect_rk356x(device_t dev) +{ + + if (ofw_bus_is_machine_compatible("rockchip,rk3566") || + ofw_bus_is_machine_compatible("rockchip,rk3568")) + return (true); + return(false); +} + +static void +its_quirk_rk356x(device_t dev) +{ + struct gicv3_its_softc *sc; + + sc = device_get_softc(dev); + sc->malloc_max_addr = (1ul << 32) - 1; +} + +static bool +its_detect_rk3588(device_t dev) +{ + + if (ofw_bus_is_machine_compatible("rockchip,rk3588") || + ofw_bus_is_machine_compatible("rockchip,rk3588s")) + return (true); + return(false); +} + +static void +its_quirk_rk3588(device_t dev) +{ + struct gicv3_its_softc *sc; + + sc = device_get_softc(dev); + sc->sc_its_flags |= ITS_FLAGS_FORCE_NOSHAREABLE; +} +#endif + static void gicv3_its_disable_intr(device_t dev, struct intr_irqsrc *isrc) { @@ -1400,7 +1505,8 @@ its_device_alloc(struct gicv3_its_softc *sc, int devid) shareable = false; l2_table = contigmalloc_domainset(ptable->ptab_l2_size, - M_GICV3_ITS, sc->sc_ds, M_WAITOK | M_ZERO, 0, (1ul << 48) - 1, + M_GICV3_ITS, sc->sc_ds, M_WAITOK | M_ZERO, 0, + gicv3_its_limit_max_addr(sc, (1ul << 48) - 1), ptable->ptab_page_size, 0); if (!shareable) @@ -1461,7 +1567,8 @@ its_device_get(device_t dev, device_t child, u_int nvecs) itt_size = roundup2(MAX(nvecs, 2) * esize, 256); its_dev->itt = contigmalloc_domainset(itt_size, M_GICV3_ITS, sc->sc_ds, M_NOWAIT | M_ZERO, 0, - LPI_INT_TRANS_TAB_MAX_ADDR, LPI_INT_TRANS_TAB_ALIGN, 0); + gicv3_its_limit_max_addr(sc, LPI_INT_TRANS_TAB_MAX_ADDR), + LPI_INT_TRANS_TAB_ALIGN, 0); if (its_dev->itt == NULL) { vmem_free(sc->sc_irq_alloc, its_dev->lpis.lpi_base, nvecs); free(its_dev, M_GICV3_ITS); @@ -2233,17 +2340,20 @@ static int gicv3_its_fdt_attach(device_t dev) { struct gicv3_its_softc *sc; - phandle_t xref; + phandle_t xref, node; int err; sc = device_get_softc(dev); sc->dev = dev; + node = ofw_bus_get_node(dev); err = gicv3_its_attach(dev); if (err != 0) return (err); + if (OF_hasprop(node, "dma-noncoherent")) + sc->sc_its_flags |= ITS_FLAGS_FORCE_NOSHAREABLE; /* Register this device as a interrupt controller */ - xref = OF_xref_from_node(ofw_bus_get_node(dev)); + xref = OF_xref_from_node(node); sc->sc_pic = intr_pic_register(dev, xref); err = intr_pic_add_handler(device_get_parent(dev), sc->sc_pic, gicv3_its_intr, sc, sc->sc_irq_base, sc->sc_irq_length);