bb95e7103a3945617b1e027d5214a609d42269ee
[openwrt/openwrt.git] / target / linux / realtek / patches-5.15 / 319-irqchip-irq-realtek-rtl-fix-VPE-affinity.patch
1 From 2cd00b51470a30198b048a5fca48a04db77e29cc Mon Sep 17 00:00:00 2001
2 From: INAGAKI Hiroshi <musashino.open@gmail.com>
3 Date: Fri, 21 May 2021 23:16:37 +0900
4 Subject: [PATCH] realtek: backport irq-realtek-rtl driver from 5.12 to 5.10
5
6 This patch backports "irq-realtek-rtl" driver to Kernel 5.10 from 5.12.
7 "MACH_REALTEK_RTL" is used as a platform name in upstream, but "RTL838X"
8 is used in OpenWrt, so update the dependency by the additional patch.
9
10 Submitted-by: INAGAKI Hiroshi <musashino.open@gmail.com>
11 ---
12 drivers/irqchip/irq-realtek-rtl.c | 38 +++++++++++------
13 1 files changed, 58 insertions(+), 20 deletions(-)
14
15 --- a/drivers/irqchip/irq-realtek-rtl.c
16 +++ b/drivers/irqchip/irq-realtek-rtl.c
17 @@ -28,6 +28,7 @@ static DEFINE_RAW_SPINLOCK(irq_lock);
18
19 #define REG(offset, cpu) (realtek_ictl_base[cpu] + offset)
20
21 +static u32 realtek_ictl_unmask[NR_CPUS];
22 static void __iomem *realtek_ictl_base[NR_CPUS];
23 static cpumask_t realtek_ictl_cpu_configurable;
24
25 @@ -41,11 +42,29 @@ struct realtek_ictl_output {
26 };
27
28 /*
29 - * IRR0-IRR3 store 4 bits per interrupt, but Realtek uses inverted numbering,
30 - * placing IRQ 31 in the first four bits. A routing value of '0' means the
31 - * interrupt is left disconnected. Routing values {1..15} connect to output
32 - * lines {0..14}.
33 + * Per CPU we have a set of 5 registers that determine interrupt handling for
34 + * 32 external interrupts. GIMR (enable/disable interrupt) plus IRR0-IRR3 that
35 + * contain "routing" or "priority" values. GIMR uses one bit for each interrupt
36 + * and IRRx store 4 bits per interrupt. Realtek uses inverted numbering,
37 + * placing IRQ 31 in the first four bits. The register combinations give the
38 + * following results for a single interrupt in the wild:
39 + *
40 + * a) GIMR = 0 / IRRx > 0 -> no interrupts
41 + * b) GIMR = 0 / IRRx = 0 -> no interrupts
42 + * c) GIMR = 1 / IRRx > 0 -> interrupts
43 + * d) GIMR = 1 / IRRx = 0 -> rare interrupts in SMP environment
44 + *
45 + * Combination d) seems to trigger interrupts only on a VPE if the other VPE
46 + * has GIMR = 0 and IRRx > 0. E.g. busy without interrupts allowed. To provide
47 + * IRQ balancing features in SMP this driver will handle the registers as
48 + * follows:
49 + *
50 + * 1) set IRRx > 0 for VPE where the interrupt is desired
51 + * 2) set IRRx = 0 for VPE where the interrupt is not desired
52 + * 3) set both GIMR = 0 to mask (disabled) interrupt
53 + * 4) set GIMR = 1 to unmask (enable) interrupt but only for VPE where IRRx > 0
54 */
55 +
56 #define IRR_OFFSET(idx) (4 * (3 - (idx * 4) / 32))
57 #define IRR_SHIFT(idx) ((idx * 4) % 32)
58
59 @@ -65,19 +84,33 @@ static inline void write_irr(void __iome
60 writel(irr, irr0 + offset);
61 }
62
63 +static inline void enable_gimr(int hwirq, int cpu)
64 +{
65 + u32 value;
66 +
67 + value = readl(REG(RTL_ICTL_GIMR, cpu));
68 + value |= (BIT(hwirq) & realtek_ictl_unmask[cpu]);
69 + writel(value, REG(RTL_ICTL_GIMR, cpu));
70 +}
71 +
72 +static inline void disable_gimr(int hwirq, int cpu)
73 +{
74 + u32 value;
75 +
76 + value = readl(REG(RTL_ICTL_GIMR, cpu));
77 + value &= ~BIT(hwirq);
78 + writel(value, REG(RTL_ICTL_GIMR, cpu));
79 +}
80 +
81 static void realtek_ictl_unmask_irq(struct irq_data *i)
82 {
83 unsigned long flags;
84 - u32 value;
85 int cpu;
86
87 raw_spin_lock_irqsave(&irq_lock, flags);
88
89 - for_each_cpu(cpu, &realtek_ictl_cpu_configurable) {
90 - value = readl(REG(RTL_ICTL_GIMR, cpu));
91 - value |= BIT(i->hwirq);
92 - writel(value, REG(RTL_ICTL_GIMR, cpu));
93 - }
94 + for_each_cpu(cpu, &realtek_ictl_cpu_configurable)
95 + enable_gimr(i->hwirq, cpu);
96
97 raw_spin_unlock_irqrestore(&irq_lock, flags);
98 }
99 @@ -85,16 +118,12 @@ static void realtek_ictl_unmask_irq(stru
100 static void realtek_ictl_mask_irq(struct irq_data *i)
101 {
102 unsigned long flags;
103 - u32 value;
104 int cpu;
105
106 raw_spin_lock_irqsave(&irq_lock, flags);
107
108 - for_each_cpu(cpu, &realtek_ictl_cpu_configurable) {
109 - value = readl(REG(RTL_ICTL_GIMR, cpu));
110 - value &= ~BIT(i->hwirq);
111 - writel(value, REG(RTL_ICTL_GIMR, cpu));
112 - }
113 + for_each_cpu(cpu, &realtek_ictl_cpu_configurable)
114 + disable_gimr(i->hwirq, cpu);
115
116 raw_spin_unlock_irqrestore(&irq_lock, flags);
117 }
118 @@ -116,11 +145,17 @@ static int __maybe_unused realtek_ictl_i
119 cpumask_and(&cpu_enable, &cpu_configure, dest);
120 cpumask_andnot(&cpu_disable, &cpu_configure, dest);
121
122 - for_each_cpu(cpu, &cpu_disable)
123 + for_each_cpu(cpu, &cpu_disable) {
124 write_irr(REG(RTL_ICTL_IRR0, cpu), i->hwirq, 0);
125 + realtek_ictl_unmask[cpu] &= ~BIT(i->hwirq);
126 + disable_gimr(i->hwirq, cpu);
127 + }
128
129 - for_each_cpu(cpu, &cpu_enable)
130 + for_each_cpu(cpu, &cpu_enable) {
131 write_irr(REG(RTL_ICTL_IRR0, cpu), i->hwirq, output->output_index + 1);
132 + realtek_ictl_unmask[cpu] |= BIT(i->hwirq);
133 + enable_gimr(i->hwirq, cpu);
134 + }
135
136 irq_data_update_effective_affinity(i, &cpu_enable);
137
138 @@ -149,6 +184,7 @@ static int intc_map(struct irq_domain *d
139
140 output->child_mask |= BIT(hw);
141 write_irr(REG(RTL_ICTL_IRR0, 0), hw, output->output_index + 1);
142 + realtek_ictl_unmask[0] |= BIT(hw);
143
144 raw_spin_unlock_irqrestore(&irq_lock, flags);
145
146 @@ -279,9 +315,11 @@ static int __init realtek_rtl_of_init(st
147 cpumask_set_cpu(cpu, &realtek_ictl_cpu_configurable);
148
149 /* Disable all cascaded interrupts and clear routing */
150 - writel(0, REG(RTL_ICTL_GIMR, cpu));
151 - for (soc_irq = 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++)
152 + for (soc_irq = 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++) {
153 write_irr(REG(RTL_ICTL_IRR0, cpu), soc_irq, 0);
154 + realtek_ictl_unmask[cpu] &= ~BIT(soc_irq);
155 + disable_gimr(soc_irq, cpu);
156 + }
157 }
158 }
159