diff options
Diffstat (limited to 'arm64-socionext-96b-enablement.patch')
-rw-r--r-- | arm64-socionext-96b-enablement.patch | 262 |
1 files changed, 0 insertions, 262 deletions
diff --git a/arm64-socionext-96b-enablement.patch b/arm64-socionext-96b-enablement.patch index 0a7df3a19..fa93f0c8e 100644 --- a/arm64-socionext-96b-enablement.patch +++ b/arm64-socionext-96b-enablement.patch @@ -1,265 +1,3 @@ -From 58be18a7bbf9dca67f4260ac172a44baa59d0ee9 Mon Sep 17 00:00:00 2001 -From: Ard Biesheuvel <ard.biesheuvel@linaro.org> -Date: Mon, 21 Aug 2017 10:47:48 +0100 -Subject: arm64: acpi/gtdt: validate CNTFRQ after having enabled the frame - -The ACPI GTDT code validates the CNTFRQ field of each MMIO timer -frame against the CNTFRQ system register of the current CPU, to -ensure that they are equal, which is mandated by the architecture. - -However, reading the CNTFRQ field of a frame is not possible until -the RFRQ bit in the frame's CNTACRn register is set, and doing so -before that willl produce the following error: - - arch_timer: [Firmware Bug]: CNTFRQ mismatch: frame @ 0x00000000e0be0000: (0x00000000), CPU: (0x0ee6b280) - arch_timer: Disabling MMIO timers due to CNTFRQ mismatch - arch_timer: Failed to initialize memory-mapped timer. - -The reason is that the CNTFRQ field is RES0 if access is not enabled. - -So move the validation of CNTFRQ into the loop that iterates over the -timers to find the best frame, but defer it until after we have selected -the best frame, which should also have enabled the RFRQ bit. - -Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> ---- - drivers/clocksource/arm_arch_timer.c | 38 ++++++++++++++++++++---------------- - 1 file changed, 21 insertions(+), 17 deletions(-) - -diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c -index fd4b7f6..14e2419 100644 ---- a/drivers/clocksource/arm_arch_timer.c -+++ b/drivers/clocksource/arm_arch_timer.c -@@ -1268,10 +1268,6 @@ arch_timer_mem_find_best_frame(struct arch_timer_mem *timer_mem) - - iounmap(cntctlbase); - -- if (!best_frame) -- pr_err("Unable to find a suitable frame in timer @ %pa\n", -- &timer_mem->cntctlbase); -- - return best_frame; - } - -@@ -1372,6 +1368,8 @@ static int __init arch_timer_mem_of_init(struct device_node *np) - - frame = arch_timer_mem_find_best_frame(timer_mem); - if (!frame) { -+ pr_err("Unable to find a suitable frame in timer @ %pa\n", -+ &timer_mem->cntctlbase); - ret = -EINVAL; - goto out; - } -@@ -1420,7 +1418,7 @@ arch_timer_mem_verify_cntfrq(struct arch_timer_mem *timer_mem) - static int __init arch_timer_mem_acpi_init(int platform_timer_count) - { - struct arch_timer_mem *timers, *timer; -- struct arch_timer_mem_frame *frame; -+ struct arch_timer_mem_frame *frame, *best_frame = NULL; - int timer_count, i, ret = 0; - - timers = kcalloc(platform_timer_count, sizeof(*timers), -@@ -1432,14 +1430,6 @@ static int __init arch_timer_mem_acpi_init(int platform_timer_count) - if (ret || !timer_count) - goto out; - -- for (i = 0; i < timer_count; i++) { -- ret = arch_timer_mem_verify_cntfrq(&timers[i]); -- if (ret) { -- pr_err("Disabling MMIO timers due to CNTFRQ mismatch\n"); -- goto out; -- } -- } -- - /* - * While unlikely, it's theoretically possible that none of the frames - * in a timer expose the combination of feature we want. -@@ -1448,12 +1438,26 @@ static int __init arch_timer_mem_acpi_init(int platform_timer_count) - timer = &timers[i]; - - frame = arch_timer_mem_find_best_frame(timer); -- if (frame) -- break; -+ if (!best_frame) -+ best_frame = frame; -+ -+ ret = arch_timer_mem_verify_cntfrq(timer); -+ if (ret) { -+ pr_err("Disabling MMIO timers due to CNTFRQ mismatch\n"); -+ goto out; -+ } -+ -+ if (!best_frame) /* implies !frame */ -+ /* -+ * Only complain about missing suitable frames if we -+ * haven't already found one in a previous iteration. -+ */ -+ pr_err("Unable to find a suitable frame in timer @ %pa\n", -+ &timer->cntctlbase); - } - -- if (frame) -- ret = arch_timer_mem_frame_register(frame); -+ if (best_frame) -+ ret = arch_timer_mem_frame_register(best_frame); - out: - kfree(timers); - return ret; --- -cgit v1.1 - -From 33d983b5bb2929ae242606925e708092b1dfdd8f Mon Sep 17 00:00:00 2001 -From: Ard Biesheuvel <ard.biesheuvel@linaro.org> -Date: Sat, 2 Sep 2017 11:01:22 +0100 -Subject: drivers/irqchip: gicv3: add workaround for Synquacer pre-ITS - -In their infinite wisdom, the Socionext engineers have decided -that ITS device IDs should not be hardwired, but it should be -left up to the software to assign them, by allowing it to -redirect MSI doorbell writes via a separate hardware block -that issues the doorbell write with a device ID that is -derived from the memory address. This completely breaks any -kind of isolation, or virtualization in general, for that -matter, but add support for it nonetheless. - -Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> ---- - arch/arm64/Kconfig | 8 +++++++ - drivers/irqchip/irq-gic-v3-its.c | 48 +++++++++++++++++++++++++++++++++++----- - 2 files changed, 51 insertions(+), 5 deletions(-) - -diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig -index 0df64a6..c4361df 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 e8d8934..0d372f1 100644 ---- a/drivers/irqchip/irq-gic-v3-its.c -+++ b/drivers/irqchip/irq-gic-v3-its.c -@@ -46,6 +46,7 @@ - #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1ULL << 0) - #define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1) - #define ITS_FLAGS_WORKAROUND_CAVIUM_23144 (1ULL << 2) -+#define ITS_FLAGS_WORKAROUND_SOCIONEXT_PREITS (1ULL << 3) - - #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) - -@@ -99,6 +100,10 @@ struct its_node { - struct its_collection *collections; - struct list_head its_device_list; - u64 flags; -+#ifdef CONFIG_SOCIONEXT_SYNQUACER_PREITS -+ u64 pre_its_base; -+ u64 pre_its_size; -+#endif - u32 ite_size; - u32 device_ids; - int numa_node; -@@ -1102,13 +1107,29 @@ static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg) - u64 addr; - - its = its_dev->its; -- addr = its->phys_base + GITS_TRANSLATER; -+ -+#ifdef CONFIG_SOCIONEXT_SYNQUACER_PREITS -+ if (its->flags & ITS_FLAGS_WORKAROUND_SOCIONEXT_PREITS) -+ -+ /* -+ * The Socionext Synquacer SoC has a so-called 'pre-ITS', -+ * which maps 32-bit writes into 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. -+ */ -+ addr = its->pre_its_base + (its_dev->device_id << 2); -+ else -+#endif -+ addr = its->phys_base + GITS_TRANSLATER; - - msg->address_lo = lower_32_bits(addr); - msg->address_hi = upper_32_bits(addr); - msg->data = its_get_event_id(d); - -- iommu_dma_map_msi_msg(d->irq, msg); -+ if (!IS_ENABLED(CONFIG_SOCIONEXT_SYNQUACER_PREITS) || -+ !(its->flags & ITS_FLAGS_WORKAROUND_SOCIONEXT_PREITS)) -+ iommu_dma_map_msi_msg(d->irq, msg); - } - - static int its_irq_set_irqchip_state(struct irq_data *d, -@@ -1666,6 +1687,11 @@ static int its_alloc_tables(struct its_node *its) - ids = 0x14; /* 20 bits, 8MB */ - } - -+#ifdef CONFIG_SOCIONEXT_SYNQUACER_PREITS -+ if (its->flags & ITS_FLAGS_WORKAROUND_SOCIONEXT_PREITS) -+ ids = ilog2(its->pre_its_size) - 2; -+#endif -+ - its->device_ids = ids; - - for (i = 0; i < GITS_BASER_NR_REGS; i++) { -@@ -2788,11 +2814,21 @@ static const struct gic_quirk its_quirks[] = { - } - }; - --static void its_enable_quirks(struct its_node *its) -+static void its_enable_quirks(struct its_node *its, -+ struct fwnode_handle *handle) - { - u32 iidr = readl_relaxed(its->base + GITS_IIDR); - - gic_enable_quirks(iidr, its_quirks, its); -+ -+#ifdef CONFIG_SOCIONEXT_SYNQUACER_PREITS -+ if (!fwnode_property_read_u64_array(handle, -+ "socionext,synquacer-pre-its", -+ &its->pre_its_base, 2)) { -+ its->flags |= ITS_FLAGS_WORKAROUND_SOCIONEXT_PREITS; -+ pr_info("ITS: enabling workaround for Socionext Synquacer pre-ITS\n"); -+ } -+#endif - } - - static int its_init_domain(struct fwnode_handle *handle, struct its_node *its) -@@ -2812,7 +2848,9 @@ 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; -+ -+ if (!(its->flags & ITS_FLAGS_WORKAROUND_SOCIONEXT_PREITS)) -+ inner_domain->flags |= IRQ_DOMAIN_FLAG_MSI_REMAP; - info->ops = &its_msi_domain_ops; - info->data = its; - inner_domain->host_data = info; -@@ -2966,7 +3004,7 @@ static int __init its_probe_one(struct resource *res, - } - its->cmd_write = its->cmd_base; - -- its_enable_quirks(its); -+ its_enable_quirks(its, handle); - - err = its_alloc_tables(its); - if (err) --- -cgit v1.1 - From 26e7bb47b0fb03a01be1e391a08c7375b45335a2 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel <ard.biesheuvel@linaro.org> Date: Mon, 21 Aug 2017 20:29:05 +0100 |