On 12 October 2017 at 19:32, Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx> wrote: > The Socionext Synquacer SoC's implementation of GICv3 has a so-called > 'pre-ITS', which maps 32-bit writes targeted at a separate window of > size '4 << device_id_bits' onto writes to GITS_TRANSLATER with device > ID taken from bits [device_id_bits + 1:2] of the window offset. > Writes that target GITS_TRANSLATER directly are reported as originating > from device ID #0. > > So add a workaround for this. Given that this breaks isolation, clear > the IRQ_DOMAIN_FLAG_MSI_REMAP flag as well. > > Signed-off-by: Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx> > --- > Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt | 4 ++ > arch/arm64/Kconfig | 8 +++ > drivers/irqchip/irq-gic-v3-its.c | 63 +++++++++++++++++++- > 3 files changed, 72 insertions(+), 3 deletions(-) > > diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt > index 4c29cdab0ea5..0798a61bbf99 100644 > --- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt > +++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt > @@ -75,6 +75,10 @@ These nodes must have the following properties: > - reg: Specifies the base physical address and size of the ITS > registers. > > +Optional: > +- socionext,synquacer-pre-its: (u32, u32) tuple describing the host address > + and size of the pre-ITS window, as implemented on the Socionext Synquacer SoC > + > The main GIC node must contain the appropriate #address-cells, > #size-cells and ranges properties for the reg property of all ITS > nodes. > diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig > index 0df64a6a56d4..c4361dff2b74 100644 > --- a/arch/arm64/Kconfig > +++ b/arch/arm64/Kconfig > @@ -539,6 +539,14 @@ config QCOM_QDF2400_ERRATUM_0065 > > If unsure, say Y. > > +config SOCIONEXT_SYNQUACER_PREITS > + bool "Socionext Synquacer: Workaround for GICv3 pre-ITS" > + default y > + help > + Socionext Synquacer SoCs implement a separate h/w block to generate > + MSI doorbell writes with non-zero values for the device ID. > + > + If unsure, say Y. > endmenu > > > diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c > index 891de07fd4cc..2fc4fba0cc4c 100644 > --- a/drivers/irqchip/irq-gic-v3-its.c > +++ b/drivers/irqchip/irq-gic-v3-its.c > @@ -97,12 +97,18 @@ struct its_node { > struct its_cmd_block *cmd_write; > struct its_baser tables[GITS_BASER_NR_REGS]; > struct its_collection *collections; > + struct fwnode_handle *fwnode_handle; > struct list_head its_device_list; > u64 flags; > u32 ite_size; > u32 device_ids; > int numa_node; > + unsigned int msi_domain_flag_mask; > bool is_v4; > + > + /* for Socionext Synquacer pre-ITS */ > + u32 pre_its_base; > + u32 pre_its_size; > }; > > #define ITS_ITT_ALIGN SZ_256 > @@ -1095,14 +1101,29 @@ static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val, > return IRQ_SET_MASK_OK_DONE; > } > > +static u64 its_irq_get_msi_base(struct its_device *its_dev) > +{ > + struct its_node *its = its_dev->its; > + > + if (unlikely(its->pre_its_size > 0)) > + /* > + * The Socionext Synquacer SoC has a so-called 'pre-ITS', > + * which maps 32-bit writes targeted at a separate window of > + * size '4 << device_id_bits' onto writes to GITS_TRANSLATER > + * with device ID taken from bits [device_id_bits + 1:2] of > + * the window offset. > + */ > + return its->pre_its_base + (its_dev->device_id << 2); > + > + return its->phys_base + GITS_TRANSLATER; > +} > + > static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg) > { > struct its_device *its_dev = irq_data_get_irq_chip_data(d); > - struct its_node *its; > u64 addr; > > - its = its_dev->its; > - addr = its->phys_base + GITS_TRANSLATER; > + addr = its_irq_get_msi_base(its_dev); > > msg->address_lo = lower_32_bits(addr); > msg->address_hi = upper_32_bits(addr); > @@ -2752,6 +2773,27 @@ static void __maybe_unused its_enable_quirk_qdf2400_e0065(void *data) > its->ite_size = 16; > } > > +static void __maybe_unused its_enable_quirk_socionext_synquacer(void *data) > +{ > + struct its_node *its = data; > + u32 pre_its_window[2]; > + u32 ids; > + > + if (!fwnode_property_read_u32_array(its->fwnode_handle, > + "socionext,synquacer-pre-its", > + pre_its_window, > + ARRAY_SIZE(pre_its_window))) { > + its->pre_its_base = pre_its_window[0]; > + its->pre_its_size = pre_its_window[1]; > + > + ids = ilog2(its->pre_its_size) - 2; > + if (its->device_ids > ids) > + its->device_ids = ids; > + > + its->msi_domain_flag_mask = ~IRQ_DOMAIN_FLAG_MSI_REMAP; > + } > +} > + > static const struct gic_quirk its_quirks[] = { > #ifdef CONFIG_CAVIUM_ERRATUM_22375 > { > @@ -2777,6 +2819,19 @@ static const struct gic_quirk its_quirks[] = { > .init = its_enable_quirk_qdf2400_e0065, > }, > #endif > +#ifdef CONFIG_SOCIONEXT_SYNQUACER_PREITS > + { > + /* > + * The Socionext Synquacer SoC incorporates ARM's own GIC-500 > + * implementation, but with a 'pre-ITS' added that requires > + * special handling in software. > + */ > + .desc = "ITS: Socionext Synquacer pre-ITS", > + .iidr = 0x0001143b, > + .mask = 0xffffffff, > + .init = its_enable_quirk_socionext_synquacer, > + }, > +#endif > { > } > }; > @@ -2806,6 +2861,7 @@ static int its_init_domain(struct fwnode_handle *handle, struct its_node *its) > inner_domain->parent = its_parent; > irq_domain_update_bus_token(inner_domain, DOMAIN_BUS_NEXUS); > inner_domain->flags |= IRQ_DOMAIN_FLAG_MSI_REMAP; > + inner_domain->flags &= its->msi_domain_flag_mask; Oops. its->msi_domain_flag_mask defaults to 0, so this breaks other platforms. Unless there are better suggestions, I will move the ~ from the assignment to here. > info->ops = &its_msi_domain_ops; > info->data = its; > inner_domain->host_data = info; > @@ -2959,6 +3015,7 @@ static int __init its_probe_one(struct resource *res, > goto out_free_its; > } > its->cmd_write = its->cmd_base; > + its->fwnode_handle = handle; > > its_enable_quirks(its); > > -- > 2.11.0 > -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html