mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-30 10:39:04 +00:00
f1f97db627
OpenWRT's developer guide prefers having actual patches so they an be sent upstream more easily. However, in this case, Adding proper fields also allows for `git am` to properly function. Some of these patches are quite old, and lack much traceable history. This commit tries to rectify that, by digging in the history to find where and how it was first added. It is by no means perfect and also shows some patches that should have been long gone. Signed-off-by: Olliver Schinagl <oliver@schinagl.nl>
160 lines
5.3 KiB
Diff
160 lines
5.3 KiB
Diff
From 2cd00b51470a30198b048a5fca48a04db77e29cc Mon Sep 17 00:00:00 2001
|
|
From: INAGAKI Hiroshi <musashino.open@gmail.com>
|
|
Date: Fri, 21 May 2021 23:16:37 +0900
|
|
Subject: [PATCH] realtek: backport irq-realtek-rtl driver from 5.12 to 5.10
|
|
|
|
This patch backports "irq-realtek-rtl" driver to Kernel 5.10 from 5.12.
|
|
"MACH_REALTEK_RTL" is used as a platform name in upstream, but "RTL838X"
|
|
is used in OpenWrt, so update the dependency by the additional patch.
|
|
|
|
Submitted-by: INAGAKI Hiroshi <musashino.open@gmail.com>
|
|
---
|
|
drivers/irqchip/irq-realtek-rtl.c | 38 +++++++++++------
|
|
1 files changed, 58 insertions(+), 20 deletions(-)
|
|
|
|
--- a/drivers/irqchip/irq-realtek-rtl.c
|
|
+++ b/drivers/irqchip/irq-realtek-rtl.c
|
|
@@ -28,6 +28,7 @@ static DEFINE_RAW_SPINLOCK(irq_lock);
|
|
|
|
#define REG(offset, cpu) (realtek_ictl_base[cpu] + offset)
|
|
|
|
+static u32 realtek_ictl_unmask[NR_CPUS];
|
|
static void __iomem *realtek_ictl_base[NR_CPUS];
|
|
static cpumask_t realtek_ictl_cpu_configurable;
|
|
|
|
@@ -41,11 +42,29 @@ struct realtek_ictl_output {
|
|
};
|
|
|
|
/*
|
|
- * IRR0-IRR3 store 4 bits per interrupt, but Realtek uses inverted numbering,
|
|
- * placing IRQ 31 in the first four bits. A routing value of '0' means the
|
|
- * interrupt is left disconnected. Routing values {1..15} connect to output
|
|
- * lines {0..14}.
|
|
+ * Per CPU we have a set of 5 registers that determine interrupt handling for
|
|
+ * 32 external interrupts. GIMR (enable/disable interrupt) plus IRR0-IRR3 that
|
|
+ * contain "routing" or "priority" values. GIMR uses one bit for each interrupt
|
|
+ * and IRRx store 4 bits per interrupt. Realtek uses inverted numbering,
|
|
+ * placing IRQ 31 in the first four bits. The register combinations give the
|
|
+ * following results for a single interrupt in the wild:
|
|
+ *
|
|
+ * a) GIMR = 0 / IRRx > 0 -> no interrupts
|
|
+ * b) GIMR = 0 / IRRx = 0 -> no interrupts
|
|
+ * c) GIMR = 1 / IRRx > 0 -> interrupts
|
|
+ * d) GIMR = 1 / IRRx = 0 -> rare interrupts in SMP environment
|
|
+ *
|
|
+ * Combination d) seems to trigger interrupts only on a VPE if the other VPE
|
|
+ * has GIMR = 0 and IRRx > 0. E.g. busy without interrupts allowed. To provide
|
|
+ * IRQ balancing features in SMP this driver will handle the registers as
|
|
+ * follows:
|
|
+ *
|
|
+ * 1) set IRRx > 0 for VPE where the interrupt is desired
|
|
+ * 2) set IRRx = 0 for VPE where the interrupt is not desired
|
|
+ * 3) set both GIMR = 0 to mask (disabled) interrupt
|
|
+ * 4) set GIMR = 1 to unmask (enable) interrupt but only for VPE where IRRx > 0
|
|
*/
|
|
+
|
|
#define IRR_OFFSET(idx) (4 * (3 - (idx * 4) / 32))
|
|
#define IRR_SHIFT(idx) ((idx * 4) % 32)
|
|
|
|
@@ -65,19 +84,33 @@ static inline void write_irr(void __iome
|
|
writel(irr, irr0 + offset);
|
|
}
|
|
|
|
+static inline void enable_gimr(int hwirq, int cpu)
|
|
+{
|
|
+ u32 value;
|
|
+
|
|
+ value = readl(REG(RTL_ICTL_GIMR, cpu));
|
|
+ value |= (BIT(hwirq) & realtek_ictl_unmask[cpu]);
|
|
+ writel(value, REG(RTL_ICTL_GIMR, cpu));
|
|
+}
|
|
+
|
|
+static inline void disable_gimr(int hwirq, int cpu)
|
|
+{
|
|
+ u32 value;
|
|
+
|
|
+ value = readl(REG(RTL_ICTL_GIMR, cpu));
|
|
+ value &= ~BIT(hwirq);
|
|
+ writel(value, REG(RTL_ICTL_GIMR, cpu));
|
|
+}
|
|
+
|
|
static void realtek_ictl_unmask_irq(struct irq_data *i)
|
|
{
|
|
unsigned long flags;
|
|
- u32 value;
|
|
int cpu;
|
|
|
|
raw_spin_lock_irqsave(&irq_lock, flags);
|
|
|
|
- for_each_cpu(cpu, &realtek_ictl_cpu_configurable) {
|
|
- value = readl(REG(RTL_ICTL_GIMR, cpu));
|
|
- value |= BIT(i->hwirq);
|
|
- writel(value, REG(RTL_ICTL_GIMR, cpu));
|
|
- }
|
|
+ for_each_cpu(cpu, &realtek_ictl_cpu_configurable)
|
|
+ enable_gimr(i->hwirq, cpu);
|
|
|
|
raw_spin_unlock_irqrestore(&irq_lock, flags);
|
|
}
|
|
@@ -85,16 +118,12 @@ static void realtek_ictl_unmask_irq(stru
|
|
static void realtek_ictl_mask_irq(struct irq_data *i)
|
|
{
|
|
unsigned long flags;
|
|
- u32 value;
|
|
int cpu;
|
|
|
|
raw_spin_lock_irqsave(&irq_lock, flags);
|
|
|
|
- for_each_cpu(cpu, &realtek_ictl_cpu_configurable) {
|
|
- value = readl(REG(RTL_ICTL_GIMR, cpu));
|
|
- value &= ~BIT(i->hwirq);
|
|
- writel(value, REG(RTL_ICTL_GIMR, cpu));
|
|
- }
|
|
+ for_each_cpu(cpu, &realtek_ictl_cpu_configurable)
|
|
+ disable_gimr(i->hwirq, cpu);
|
|
|
|
raw_spin_unlock_irqrestore(&irq_lock, flags);
|
|
}
|
|
@@ -116,11 +145,17 @@ static int __maybe_unused realtek_ictl_i
|
|
cpumask_and(&cpu_enable, &cpu_configure, dest);
|
|
cpumask_andnot(&cpu_disable, &cpu_configure, dest);
|
|
|
|
- for_each_cpu(cpu, &cpu_disable)
|
|
+ for_each_cpu(cpu, &cpu_disable) {
|
|
write_irr(REG(RTL_ICTL_IRR0, cpu), i->hwirq, 0);
|
|
+ realtek_ictl_unmask[cpu] &= ~BIT(i->hwirq);
|
|
+ disable_gimr(i->hwirq, cpu);
|
|
+ }
|
|
|
|
- for_each_cpu(cpu, &cpu_enable)
|
|
+ for_each_cpu(cpu, &cpu_enable) {
|
|
write_irr(REG(RTL_ICTL_IRR0, cpu), i->hwirq, output->output_index + 1);
|
|
+ realtek_ictl_unmask[cpu] |= BIT(i->hwirq);
|
|
+ enable_gimr(i->hwirq, cpu);
|
|
+ }
|
|
|
|
irq_data_update_effective_affinity(i, &cpu_enable);
|
|
|
|
@@ -149,6 +184,7 @@ static int intc_map(struct irq_domain *d
|
|
|
|
output->child_mask |= BIT(hw);
|
|
write_irr(REG(RTL_ICTL_IRR0, 0), hw, output->output_index + 1);
|
|
+ realtek_ictl_unmask[0] |= BIT(hw);
|
|
|
|
raw_spin_unlock_irqrestore(&irq_lock, flags);
|
|
|
|
@@ -279,9 +315,11 @@ static int __init realtek_rtl_of_init(st
|
|
cpumask_set_cpu(cpu, &realtek_ictl_cpu_configurable);
|
|
|
|
/* Disable all cascaded interrupts and clear routing */
|
|
- writel(0, REG(RTL_ICTL_GIMR, cpu));
|
|
- for (soc_irq = 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++)
|
|
+ for (soc_irq = 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++) {
|
|
write_irr(REG(RTL_ICTL_IRR0, cpu), soc_irq, 0);
|
|
+ realtek_ictl_unmask[cpu] &= ~BIT(soc_irq);
|
|
+ disable_gimr(soc_irq, cpu);
|
|
+ }
|
|
}
|
|
}
|
|
|