Hi Marc, Thank you for your review! > From: Marc Zyngier, Sent: Wednesday, February 14, 2024 7:58 PM > > [+ Geert, who deals with Renesas SoCs on a daily basis] > > Hi Yoshihiro, > > On Wed, 14 Feb 2024 05:20:50 +0000, > Yoshihiro Shimoda <yoshihiro.shimoda.uh@xxxxxxxxxxx> wrote: > > > > The GICv3 ITS on Renesas R-Car has limitations: > > - It can access lower 32-bits memory area only. > > - It cannot use Sharable/cache attributes. > > > > So, set ITS_FLAGS_FORCE_NON_SHAREABLE flag, and set GFP_DMA to all > > memory allocation APIs for getting lower 32-bits memory area on > > the R-Car. Note that GFP_DMA32 cannot work correctly because > > the environment doens't have DMA32 zone like below: > > nit: doesn't Oops. I'll fix it. > > > > [ 0.000000] Zone ranges: > > [ 0.000000] DMA [mem 0x0000000048000000-0x00000000ffffffff] > > [ 0.000000] DMA32 empty > > [ 0.000000] Normal [mem 0x0000000100000000-0x00000004ffffffff] > > Unfortunately, none of that is a universal truth. The way DMA and > DMA32 are expressed is pretty variable. See this for example: > > https://lore.kernel.org/all/cover.1703683642.git.baruch@xxxxxxxxxx/ > > So I can't see how you can reliably rely on this layout. It may work > today on your platform, but I wouldn't take this as a guarantee. So, IIUC, I should use DMA API for it instead. > > > > Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@xxxxxxxxxxx> > > --- > > arch/arm64/Kconfig | 9 +++++ > > drivers/irqchip/irq-gic-v3-its.c | 59 +++++++++++++++++++++----------- > > 2 files changed, 48 insertions(+), 20 deletions(-) > > > > diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig > > index c1a16a9dae72..49fe3006e142 100644 > > --- a/arch/arm64/Kconfig > > +++ b/arch/arm64/Kconfig > > @@ -1250,6 +1250,15 @@ config SOCIONEXT_SYNQUACER_PREITS > > > > If unsure, say Y. > > > > +config RENESAS_RCAR_GIC_ITS > > + bool "Renesas R-Car: Workaround for GICv3 ITS" > > + default n > > + help > > + Renesas R-Car Gen4 SoCs has a limitation about GICv3 ITS which can > > + access lower 32-bits memory address range only. > > + > > + If unsure, say Y. > > Either this should be 'default y', or you should drop this last line. > Being 'default n' and saying 'if you don't know, say y' is > counterproductive. I got it. I'll fix it. > Also: > > - This must carry an official erratum number > > - You must document it in Documentation/arch/arm64/silicon-errata.rst I got it. > > + > > endmenu # "ARM errata workarounds via the alternatives framework" > > > > choice > > diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c > > index d097001c1e3e..e0e672b561b9 100644 > > --- a/drivers/irqchip/irq-gic-v3-its.c > > +++ b/drivers/irqchip/irq-gic-v3-its.c > > @@ -186,6 +186,7 @@ static LIST_HEAD(its_nodes); > > static DEFINE_RAW_SPINLOCK(its_lock); > > static struct rdists *gic_rdists; > > static struct irq_domain *its_parent; > > +static gfp_t its_gfp_quirk; > > Why is that global? Why isn't this computed on a per-ITS basis? Since > you are introducing a generic mechanism here, you shouldn't assume > that all ITSs are subjected to the same issue. Since some functions doesn't have struct its_node, I think adding the argument makes complex the code. I'll avoid to use a global value somehow. > > > > static unsigned long its_list_map; > > static u16 vmovp_seq_num; > > @@ -1846,7 +1847,7 @@ static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info) > > struct its_vlpi_map *maps; > > > > maps = kcalloc(its_dev->event_map.nr_lpis, sizeof(*maps), > > - GFP_ATOMIC); > > + GFP_ATOMIC | its_gfp_quirk); > > This data structure is never exposed to the GIC. Why do we need to > constraint this allocation? I'm sorry, I didn't understand that. I'll drop this. > > if (!maps) { > > ret = -ENOMEM; > > goto out; > > @@ -2044,7 +2045,7 @@ static struct lpi_range *mk_lpi_range(u32 base, u32 span) > > { > > struct lpi_range *range; > > > > - range = kmalloc(sizeof(*range), GFP_KERNEL); > > + range = kmalloc(sizeof(*range), GFP_KERNEL | its_gfp_quirk); > > Same thing. I'll drop this. > > if (range) { > > range->base_id = base; > > range->span = span; > > @@ -2169,7 +2170,7 @@ static unsigned long *its_lpi_alloc(int nr_irqs, u32 *base, int *nr_ids) > > if (err) > > goto out; > > > > - bitmap = bitmap_zalloc(nr_irqs, GFP_ATOMIC); > > + bitmap = bitmap_zalloc(nr_irqs, GFP_ATOMIC | its_gfp_quirk); > > Same thing. I'll drop this. > > if (!bitmap) > > goto out; > > > > @@ -2201,7 +2202,7 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags) > > { > > struct page *prop_page; > > > > - prop_page = alloc_pages(gfp_flags, get_order(LPI_PROPBASE_SZ)); > > + prop_page = alloc_pages(gfp_flags | its_gfp_quirk, get_order(LPI_PROPBASE_SZ)); > > This only affects the redistributors. Why should we constraint it? To be honest, I don't know why, but this is required on my environment. Otherwise, the MSI interrupt never happens. Anyway, I should have learned the hardware bug in detail... > > if (!prop_page) > > return NULL; > > > > @@ -2335,7 +2336,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser, > > order = get_order(GITS_BASER_PAGES_MAX * psz); > > } > > > > - page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, order); > > + page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO | its_gfp_quirk, order); > > if (!page) > > return -ENOMEM; > > > > @@ -2808,7 +2809,7 @@ static bool allocate_vpe_l2_table(int cpu, u32 id) > > > > /* Allocate memory for 2nd level table */ > > if (!table[idx]) { > > - page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(psz)); > > + page = alloc_pages(GFP_KERNEL | __GFP_ZERO | its_gfp_quirk, get_order(psz)); > > if (!page) > > return false; > > > > @@ -2860,7 +2861,7 @@ static int allocate_vpe_l1_table(void) > > if (val & GICR_VPROPBASER_4_1_VALID) > > goto out; > > > > - gic_data_rdist()->vpe_table_mask = kzalloc(sizeof(cpumask_t), GFP_ATOMIC); > > + gic_data_rdist()->vpe_table_mask = kzalloc(sizeof(cpumask_t), GFP_ATOMIC | its_gfp_quirk); > > This is a cpumask allocation, not exposed to the GIC. What is the > reason for constraining it? I'm sorry, I didn't understand the specification. I'll drop this. > > if (!gic_data_rdist()->vpe_table_mask) > > return -ENOMEM; > > > > @@ -2927,7 +2928,7 @@ static int allocate_vpe_l1_table(void) > > > > pr_debug("np = %d, npg = %lld, psz = %d, epp = %d, esz = %d\n", > > np, npg, psz, epp, esz); > > - page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, get_order(np * PAGE_SIZE)); > > + page = alloc_pages(GFP_ATOMIC | __GFP_ZERO | its_gfp_quirk, get_order(np * PAGE_SIZE)); > > if (!page) > > return -ENOMEM; > > > > @@ -2957,7 +2958,7 @@ static int its_alloc_collections(struct its_node *its) > > int i; > > > > its->collections = kcalloc(nr_cpu_ids, sizeof(*its->collections), > > - GFP_KERNEL); > > + GFP_KERNEL | its_gfp_quirk); > > Same thing. I'll drop this. > > if (!its->collections) > > return -ENOMEM; > > > > @@ -2971,7 +2972,7 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags) > > { > > struct page *pend_page; > > > > - pend_page = alloc_pages(gfp_flags | __GFP_ZERO, > > + pend_page = alloc_pages(gfp_flags | __GFP_ZERO | its_gfp_quirk, > > get_order(LPI_PENDBASE_SZ)); > > This is a redistributor-private allocation. If it is the ITSs that are > affected by this bug, why are the pending tables constrained? Thank you for the comment. This is not needed on my environment. So, I'll drop it. > > if (!pend_page) > > return NULL; > > @@ -3319,7 +3320,7 @@ static bool its_alloc_table_entry(struct its_node *its, > > > > /* Allocate memory for 2nd level table */ > > if (!table[idx]) { > > - page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, > > + page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO | its_gfp_quirk, > > get_order(baser->psz)); > > if (!page) > > return false; > > @@ -3415,7 +3416,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, > > if (WARN_ON(!is_power_of_2(nvecs))) > > nvecs = roundup_pow_of_two(nvecs); > > > > - dev = kzalloc(sizeof(*dev), GFP_KERNEL); > > + dev = kzalloc(sizeof(*dev), GFP_KERNEL | its_gfp_quirk); > > /* > > * Even if the device wants a single LPI, the ITT must be > > * sized as a power of two (and you need at least one bit...). > > @@ -3423,14 +3424,14 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, > > nr_ites = max(2, nvecs); > > sz = nr_ites * (FIELD_GET(GITS_TYPER_ITT_ENTRY_SIZE, its->typer) + 1); > > sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1; > > - itt = kzalloc_node(sz, GFP_KERNEL, its->numa_node); > > + itt = kzalloc_node(sz, GFP_KERNEL | its_gfp_quirk, its->numa_node); > > if (alloc_lpis) { > > lpi_map = its_lpi_alloc(nvecs, &lpi_base, &nr_lpis); > > if (lpi_map) > > col_map = kcalloc(nr_lpis, sizeof(*col_map), > > - GFP_KERNEL); > > + GFP_KERNEL | its_gfp_quirk); > > This is kernel-private memory, not visible by the GIC. I'll drop this. > > } else { > > - col_map = kcalloc(nr_ites, sizeof(*col_map), GFP_KERNEL); > > + col_map = kcalloc(nr_ites, sizeof(*col_map), GFP_KERNEL | its_gfp_quirk); > > Same thing. I'll drop this. > > nr_lpis = 0; > > lpi_base = 0; > > } > > @@ -4754,6 +4755,16 @@ static bool __maybe_unused its_enable_rk3588001(void *data) > > return true; > > } > > > > +static bool __maybe_unused its_enable_renesas_rcar_gic_its(void *data) > > +{ > > + struct its_node *its = data; > > + > > + its->flags |= ITS_FLAGS_FORCE_NON_SHAREABLE; > > + its_gfp_quirk = GFP_DMA; > > + > > + return true; > > +} > > + > > static bool its_set_non_coherent(void *data) > > { > > struct its_node *its = data; > > @@ -4815,6 +4826,14 @@ static const struct gic_quirk its_quirks[] = { > > .mask = 0xffffffff, > > .init = its_enable_rk3588001, > > }, > > +#endif > > +#ifdef CONFIG_RENESAS_RCAR_GIC_ITS > > + { > > + .desc = "ITS: Renesas R-Car Gen4 GICv3 ITS", > > + .iidr = 0x0201743b, > > + .mask = 0xffffffff, > > + .init = its_enable_renesas_rcar_gic_its, > > + }, > > Huh. This describes a GIC600 implemented by ARM. Which means your are > actively forcing your quirk on *every* implementations, including > those that are not affected by this hardware issue. Definitely not > acceptable. I understood it. I'll add a condition like its_enable_rk3588001() to affect this quirk for my environment only. I believe that such adding condition is acceptable because the CONFIG_ROCKCHIP_ERRATUM_3588001 is the same iidr value of my environment. > > #endif > > { > > .desc = "ITS: non-coherent attribute", > > @@ -4974,7 +4993,7 @@ static int its_init_domain(struct its_node *its) > > struct irq_domain *inner_domain; > > struct msi_domain_info *info; > > > > - info = kzalloc(sizeof(*info), GFP_KERNEL); > > + info = kzalloc(sizeof(*info), GFP_KERNEL | its_gfp_quirk); > > Kernel memory only. I'll drop it. > > if (!info) > > return -ENOMEM; > > > > @@ -5011,7 +5030,7 @@ static int its_init_vpe_domain(void) > > > > entries = roundup_pow_of_two(nr_cpu_ids); > > vpe_proxy.vpes = kcalloc(entries, sizeof(*vpe_proxy.vpes), > > - GFP_KERNEL); > > + GFP_KERNEL | its_gfp_quirk); > > if (!vpe_proxy.vpes) > > return -ENOMEM; > > > > @@ -5108,7 +5127,7 @@ static int __init its_probe_one(struct its_node *its) > > } > > } > > > > - page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, > > + page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO | its_gfp_quirk, > > get_order(ITS_CMD_QUEUE_SZ)); > > if (!page) { > > err = -ENOMEM; > > @@ -5352,7 +5371,7 @@ static struct its_node __init *its_node_init(struct resource *res, > > > > pr_info("ITS %pR\n", res); > > > > - its = kzalloc(sizeof(*its), GFP_KERNEL); > > + its = kzalloc(sizeof(*its), GFP_KERNEL | its_gfp_quirk); > > Kernel memory only. I'll drop it. > > if (!its) > > goto out_unmap; > > > > @@ -5520,7 +5539,7 @@ static void __init acpi_table_parse_srat_its(void) > > return; > > > > its_srat_maps = kmalloc_array(count, sizeof(struct its_srat_map), > > - GFP_KERNEL); > > + GFP_KERNEL | its_gfp_quirk); > > Kernel memory only. I'll drop it. > > if (!its_srat_maps) > > return; > > > > I suggest that you start reading the architecture spec and understand > what is the memory that is accessible by the GIC, because at least > half of this patch is completely unnecessary. > > You also need to be clear about what is affected by this bug: ITS > only? or also the RDs? If both are affected, they need to be handled > separately. > > In any case, you must not assume that all ITSs in a system are > subjected to this bug, which means that you must have per-ITS tracking > of the GFP flags. > > Finally, the DMA story itself needs to be sorted out, because you are > relying on something that is incredibly fragile. Thank you very much for your suggestion. I'll learn the architecture spec and reconsider the implementation, especially DMA related. Best regards, Yoshihiro Shimoda > HTH, > > M. > > -- > Without deviation from the norm, progress is not possible.