]>
Commit | Line | Data |
---|---|---|
5aa54b75 FG |
1 | From c075f8efc5513551233dabce366eed01e32b62a4 Mon Sep 17 00:00:00 2001 |
2 | From: Thomas Gleixner <tglx@linutronix.de> | |
3 | Date: Thu, 1 Jun 2017 13:12:18 +0800 | |
4 | Subject: [PATCH] pinctrl/amd: Use regular interrupt instead of chained | |
5 | MIME-Version: 1.0 | |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
9 | BugLink: https://bugs.launchpad.net/bugs/1671360 | |
10 | ||
11 | The AMD pinctrl driver uses a chained interrupt to demultiplex the GPIO | |
12 | interrupts. Kevin Vandeventer reported, that his new AMD Ryzen locks up | |
13 | hard on boot when the AMD pinctrl driver is initialized. The reason is an | |
14 | interrupt storm. It's not clear whether that's caused by hardware or | |
15 | firmware or both. | |
16 | ||
17 | Using chained interrupts on X86 is a dangerous endavour. If a system is | |
18 | misconfigured or the hardware buggy there is no safety net to catch an | |
19 | interrupt storm. | |
20 | ||
21 | Convert the driver to use a regular interrupt for the demultiplex | |
22 | handler. This allows the interrupt storm detector to catch the malfunction | |
23 | and lets the system boot up. | |
24 | ||
25 | This should be backported to stable because it's likely that more users run | |
26 | into this problem as the AMD Ryzen machines are spreading. | |
27 | ||
28 | Reported-by: Kevin Vandeventer | |
29 | Link: https://bugzilla.suse.com/show_bug.cgi?id=1034261 | |
30 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | |
31 | Signed-off-by: Linus Walleij <linus.walleij@linaro.org> | |
32 | (backported from commit babdc22b0ccf4ef5a3075ce6e4afc26b7a279faf linux-next) | |
33 | Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com> | |
34 | Acked-by: Stefan Bader <stefan.bader@canonical.com> | |
35 | Acked-by: Seth Forshee <seth.forshee@canonical.com> | |
36 | Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> | |
37 | ||
38 | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | |
39 | --- | |
40 | drivers/pinctrl/pinctrl-amd.c | 90 +++++++++++++++++++------------------------ | |
41 | 1 file changed, 40 insertions(+), 50 deletions(-) | |
42 | ||
43 | diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c | |
44 | index cfcf9db02c7d..07a88b83e02b 100644 | |
45 | --- a/drivers/pinctrl/pinctrl-amd.c | |
46 | +++ b/drivers/pinctrl/pinctrl-amd.c | |
47 | @@ -478,64 +478,54 @@ static struct irq_chip amd_gpio_irqchip = { | |
48 | .irq_set_type = amd_gpio_irq_set_type, | |
49 | }; | |
50 | ||
51 | -static void amd_gpio_irq_handler(struct irq_desc *desc) | |
52 | +#define PIN_IRQ_PENDING (BIT(INTERRUPT_STS_OFF) | BIT(WAKE_STS_OFF)) | |
53 | + | |
54 | +static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id) | |
55 | { | |
56 | - u32 i; | |
57 | - u32 off; | |
58 | - u32 reg; | |
59 | - u32 pin_reg; | |
60 | - u64 reg64; | |
61 | - int handled = 0; | |
62 | - unsigned int irq; | |
63 | + struct amd_gpio *gpio_dev = dev_id; | |
64 | + struct gpio_chip *gc = &gpio_dev->gc; | |
65 | + irqreturn_t ret = IRQ_NONE; | |
66 | + unsigned int i, irqnr; | |
67 | unsigned long flags; | |
68 | - struct irq_chip *chip = irq_desc_get_chip(desc); | |
69 | - struct gpio_chip *gc = irq_desc_get_handler_data(desc); | |
70 | - struct amd_gpio *gpio_dev = gpiochip_get_data(gc); | |
71 | + u32 *regs, regval; | |
72 | + u64 status, mask; | |
73 | ||
74 | - chained_irq_enter(chip, desc); | |
75 | - /*enable GPIO interrupt again*/ | |
76 | + /* Read the wake status */ | |
77 | raw_spin_lock_irqsave(&gpio_dev->lock, flags); | |
78 | - reg = readl(gpio_dev->base + WAKE_INT_STATUS_REG1); | |
79 | - reg64 = reg; | |
80 | - reg64 = reg64 << 32; | |
81 | - | |
82 | - reg = readl(gpio_dev->base + WAKE_INT_STATUS_REG0); | |
83 | - reg64 |= reg; | |
84 | + status = readl(gpio_dev->base + WAKE_INT_STATUS_REG1); | |
85 | + status <<= 32; | |
86 | + status |= readl(gpio_dev->base + WAKE_INT_STATUS_REG0); | |
87 | raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); | |
88 | ||
89 | - /* | |
90 | - * first 46 bits indicates interrupt status. | |
91 | - * one bit represents four interrupt sources. | |
92 | - */ | |
93 | - for (off = 0; off < 46 ; off++) { | |
94 | - if (reg64 & BIT(off)) { | |
95 | - for (i = 0; i < 4; i++) { | |
96 | - pin_reg = readl(gpio_dev->base + | |
97 | - (off * 4 + i) * 4); | |
98 | - if ((pin_reg & BIT(INTERRUPT_STS_OFF)) || | |
99 | - (pin_reg & BIT(WAKE_STS_OFF))) { | |
100 | - irq = irq_find_mapping(gc->irqdomain, | |
101 | - off * 4 + i); | |
102 | - generic_handle_irq(irq); | |
103 | - writel(pin_reg, | |
104 | - gpio_dev->base | |
105 | - + (off * 4 + i) * 4); | |
106 | - handled++; | |
107 | - } | |
108 | - } | |
109 | + /* Bit 0-45 contain the relevant status bits */ | |
110 | + status &= (1ULL << 46) - 1; | |
111 | + regs = gpio_dev->base; | |
112 | + for (mask = 1, irqnr = 0; status; mask <<= 1, regs += 4, irqnr += 4) { | |
113 | + if (!(status & mask)) | |
114 | + continue; | |
115 | + status &= ~mask; | |
116 | + | |
117 | + /* Each status bit covers four pins */ | |
118 | + for (i = 0; i < 4; i++) { | |
119 | + regval = readl(regs + i); | |
120 | + if (!(regval & PIN_IRQ_PENDING)) | |
121 | + continue; | |
122 | + irq = irq_find_mapping(gc->irqdomain, irqnr + i); | |
123 | + generic_handle_irq(irq); | |
124 | + /* Clear interrupt */ | |
125 | + writel(regval, regs + i); | |
126 | + ret = IRQ_HANDLED; | |
127 | } | |
128 | } | |
129 | ||
130 | - if (handled == 0) | |
131 | - handle_bad_irq(desc); | |
132 | - | |
133 | + /* Signal EOI to the GPIO unit */ | |
134 | raw_spin_lock_irqsave(&gpio_dev->lock, flags); | |
135 | - reg = readl(gpio_dev->base + WAKE_INT_MASTER_REG); | |
136 | - reg |= EOI_MASK; | |
137 | - writel(reg, gpio_dev->base + WAKE_INT_MASTER_REG); | |
138 | + regval = readl(gpio_dev->base + WAKE_INT_MASTER_REG); | |
139 | + regval |= EOI_MASK; | |
140 | + writel(regval, gpio_dev->base + WAKE_INT_MASTER_REG); | |
141 | raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); | |
142 | ||
143 | - chained_irq_exit(chip, desc); | |
144 | + return ret; | |
145 | } | |
146 | ||
147 | static int amd_get_groups_count(struct pinctrl_dev *pctldev) | |
148 | @@ -803,10 +793,10 @@ static int amd_gpio_probe(struct platform_device *pdev) | |
149 | goto out2; | |
150 | } | |
151 | ||
152 | - gpiochip_set_chained_irqchip(&gpio_dev->gc, | |
153 | - &amd_gpio_irqchip, | |
154 | - irq_base, | |
155 | - amd_gpio_irq_handler); | |
156 | + ret = devm_request_irq(&pdev->dev, irq_base, amd_gpio_irq_handler, 0, | |
157 | + KBUILD_MODNAME, gpio_dev); | |
158 | + if (ret) | |
159 | + goto out2; | |
160 | ||
161 | platform_set_drvdata(pdev, gpio_dev); | |
162 | ||
163 | -- | |
164 | 2.11.0 | |
165 |