FAILED: patch "[PATCH] irqchip/mips-gic: Use the correct local interrupt map" failed to apply to 4.14-stable tree
Subsystems (4)
[email protected]
maintainerThe patch below does not apply to the 4.14-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 6d4d367d0e9ffab4d64a3436256a6a052dc1195d Mon Sep 17 00:00:00 2001
From: Paul Burton <[email protected]>
Date: Wed, 5 Jun 2019 09:34:10 +0100
Subject: [PATCH] irqchip/mips-gic: Use the correct local interrupt map
registers
The MIPS GIC contains a block of registers used to map local interrupts to a particular CPU interrupt pin. Since these registers are found at a consecutive range of addresses we access them using an index, via the (read|write)_gic_v[lo]_map accessor functions. We currently use values from enum mips_gic_local_interrupt as those indices.
Unfortunately whilst enum mips_gic_local_interrupt provides the correct offsets for bits in the pending & mask registers, the ordering of the map registers is subtly different... Compared with the ordering of pending & mask bits, the map registers move the FDC from the end of the list to index 3 after the timer interrupt. As a result the performance counter & software interrupts are therefore at indices 4-6 rather than indices 3-5.
Notably this causes problems with performance counter interrupts being incorrectly mapped on some systems, and presumably will also cause problems for FDC interrupts.
Introduce a function to map from enum mips_gic_local_interrupt to the index of the corresponding map register, and use it to ensure we access the map registers for the correct interrupts.
arch/mips/include/asm/mips-gic.h +30 -0
@@ -314,6 +314,36 @@ static inline bool mips_gic_present(void)return IS_ENABLED (CONFIG_MIPS_GIC ) && mips_gic_base; } +/** +* mips_gic_vx_map_reg() - Return GIC_Vx_<intr>_MAP register offset +* @intr: A GIC local interrupt +* +* Determine the index of the GIC_VL_<intr>_MAP or GIC_VO_<intr>_MAP register +* within the block of GIC map registers. This is almost the same as the order +* of interrupts in the pending & mask registers, as used by enum +* mips_gic_local_interrupt, but moves the FDC interrupt & thus offsets the +* interrupts after it... +* +* Return: The map register index corresponding to @intr. +* +* The return value is suitable for use with the (read|write)_gic_v[lo]_map +* accessor functions. +*/ +static inline unsigned int +mips_gic_vx_map_reg (enum mips_gic_local_interrupt intr) +{ +/* WD, Compare & Timer are 1:1 */ +if (intr <=GIC_LOCAL_INT_TIMER ) +return intr; + +/* FDC moves to after Timer... */ +if (intr ==GIC_LOCAL_INT_FDC ) +return GIC_LOCAL_INT_TIMER +1 ; + +/* As a result everything else is offset by 1 */ +return intr +1 ; +} +/** * gic_get_c0_compare_int() - Return cp0 count/compare interrupt virq *
drivers/irqchip/irq-mips-gic.c +2 -2
@@ -388,7 +388,7 @@ static void gic_all_vpes_irq_cpu_online(struct irq_data *d) intr =GIC_HWIRQ_TO_LOCAL (d->hwirq); cd =irq_data_get_irq_chip_data (d); -write_gic_vl_map (intr, cd->map); +write_gic_vl_map (mips_gic_vx_map_reg (intr), cd->map);if (cd->mask)write_gic_vl_smask (BIT (intr)); }
@@ -517,7 +517,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,spin_lock_irqsave (&gic_lock, flags);for_each_online_cpu (cpu) {write_gic_vl_other (mips_cm_vp_id (cpu)); -write_gic_vo_map (intr, map); +write_gic_vo_map (mips_gic_vx_map_reg (intr), map); }spin_unlock_irqrestore (&gic_lock, flags);