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