diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2018-05-08 08:14:32 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2018-05-13 09:59:00 -0400 |
commit | 25eaaabb51c9925dc65f5b54fd9a362bf118e70a (patch) | |
tree | a2909723beda59d3fe019ae40bc2076ae1541679 /drivers/irqchip/irq-mvebu-icu.c | |
parent | 6988e0e0d28328467e218f59589b2770675a9ebd (diff) |
irqchip/mvebu-gicp: Use level-triggered MSIs between ICU and GICP
The ICU and GICP drivers are using an ugly side-band mechanism to
find out about the "clear" doorbell when using level interrupts.
Let's convert it to level-triggered MSIs, which result in a nice
cleanup.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Miquel Raynal <miquel.raynal@bootlin.com>
Cc: Rob Herring <robh@kernel.org>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Cc: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
Link: https://lkml.kernel.org/r/20180508121438.11301-4-marc.zyngier@arm.com
Diffstat (limited to 'drivers/irqchip/irq-mvebu-icu.c')
-rw-r--r-- | drivers/irqchip/irq-mvebu-icu.c | 33 |
1 files changed, 17 insertions, 16 deletions
diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c index e18c48d3a92e..13063339b416 100644 --- a/drivers/irqchip/irq-mvebu-icu.c +++ b/drivers/irqchip/irq-mvebu-icu.c | |||
@@ -21,8 +21,6 @@ | |||
21 | 21 | ||
22 | #include <dt-bindings/interrupt-controller/mvebu-icu.h> | 22 | #include <dt-bindings/interrupt-controller/mvebu-icu.h> |
23 | 23 | ||
24 | #include "irq-mvebu-gicp.h" | ||
25 | |||
26 | /* ICU registers */ | 24 | /* ICU registers */ |
27 | #define ICU_SETSPI_NSR_AL 0x10 | 25 | #define ICU_SETSPI_NSR_AL 0x10 |
28 | #define ICU_SETSPI_NSR_AH 0x14 | 26 | #define ICU_SETSPI_NSR_AH 0x14 |
@@ -43,6 +41,7 @@ struct mvebu_icu { | |||
43 | void __iomem *base; | 41 | void __iomem *base; |
44 | struct irq_domain *domain; | 42 | struct irq_domain *domain; |
45 | struct device *dev; | 43 | struct device *dev; |
44 | atomic_t initialized; | ||
46 | }; | 45 | }; |
47 | 46 | ||
48 | struct mvebu_icu_irq_data { | 47 | struct mvebu_icu_irq_data { |
@@ -51,6 +50,18 @@ struct mvebu_icu_irq_data { | |||
51 | unsigned int type; | 50 | unsigned int type; |
52 | }; | 51 | }; |
53 | 52 | ||
53 | static void mvebu_icu_init(struct mvebu_icu *icu, struct msi_msg *msg) | ||
54 | { | ||
55 | if (atomic_cmpxchg(&icu->initialized, false, true)) | ||
56 | return; | ||
57 | |||
58 | /* Set Clear/Set ICU SPI message address in AP */ | ||
59 | writel_relaxed(msg[0].address_hi, icu->base + ICU_SETSPI_NSR_AH); | ||
60 | writel_relaxed(msg[0].address_lo, icu->base + ICU_SETSPI_NSR_AL); | ||
61 | writel_relaxed(msg[1].address_hi, icu->base + ICU_CLRSPI_NSR_AH); | ||
62 | writel_relaxed(msg[1].address_lo, icu->base + ICU_CLRSPI_NSR_AL); | ||
63 | } | ||
64 | |||
54 | static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg) | 65 | static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg) |
55 | { | 66 | { |
56 | struct irq_data *d = irq_get_irq_data(desc->irq); | 67 | struct irq_data *d = irq_get_irq_data(desc->irq); |
@@ -59,6 +70,8 @@ static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg) | |||
59 | unsigned int icu_int; | 70 | unsigned int icu_int; |
60 | 71 | ||
61 | if (msg->address_lo || msg->address_hi) { | 72 | if (msg->address_lo || msg->address_hi) { |
73 | /* One off initialization */ | ||
74 | mvebu_icu_init(icu, msg); | ||
62 | /* Configure the ICU with irq number & type */ | 75 | /* Configure the ICU with irq number & type */ |
63 | icu_int = msg->data | ICU_INT_ENABLE; | 76 | icu_int = msg->data | ICU_INT_ENABLE; |
64 | if (icu_irqd->type & IRQ_TYPE_EDGE_RISING) | 77 | if (icu_irqd->type & IRQ_TYPE_EDGE_RISING) |
@@ -197,9 +210,7 @@ static int mvebu_icu_probe(struct platform_device *pdev) | |||
197 | struct device_node *node = pdev->dev.of_node; | 210 | struct device_node *node = pdev->dev.of_node; |
198 | struct device_node *gicp_dn; | 211 | struct device_node *gicp_dn; |
199 | struct resource *res; | 212 | struct resource *res; |
200 | phys_addr_t setspi, clrspi; | 213 | int i; |
201 | u32 i, icu_int; | ||
202 | int ret; | ||
203 | 214 | ||
204 | icu = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_icu), | 215 | icu = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_icu), |
205 | GFP_KERNEL); | 216 | GFP_KERNEL); |
@@ -242,22 +253,12 @@ static int mvebu_icu_probe(struct platform_device *pdev) | |||
242 | if (!gicp_dn) | 253 | if (!gicp_dn) |
243 | return -ENODEV; | 254 | return -ENODEV; |
244 | 255 | ||
245 | ret = mvebu_gicp_get_doorbells(gicp_dn, &setspi, &clrspi); | ||
246 | if (ret) | ||
247 | return ret; | ||
248 | |||
249 | /* Set Clear/Set ICU SPI message address in AP */ | ||
250 | writel_relaxed(upper_32_bits(setspi), icu->base + ICU_SETSPI_NSR_AH); | ||
251 | writel_relaxed(lower_32_bits(setspi), icu->base + ICU_SETSPI_NSR_AL); | ||
252 | writel_relaxed(upper_32_bits(clrspi), icu->base + ICU_CLRSPI_NSR_AH); | ||
253 | writel_relaxed(lower_32_bits(clrspi), icu->base + ICU_CLRSPI_NSR_AL); | ||
254 | |||
255 | /* | 256 | /* |
256 | * Clean all ICU interrupts with type SPI_NSR, required to | 257 | * Clean all ICU interrupts with type SPI_NSR, required to |
257 | * avoid unpredictable SPI assignments done by firmware. | 258 | * avoid unpredictable SPI assignments done by firmware. |
258 | */ | 259 | */ |
259 | for (i = 0 ; i < ICU_MAX_IRQS ; i++) { | 260 | for (i = 0 ; i < ICU_MAX_IRQS ; i++) { |
260 | icu_int = readl(icu->base + ICU_INT_CFG(i)); | 261 | u32 icu_int = readl_relaxed(icu->base + ICU_INT_CFG(i)); |
261 | if ((icu_int >> ICU_GROUP_SHIFT) == ICU_GRP_NSR) | 262 | if ((icu_int >> ICU_GROUP_SHIFT) == ICU_GRP_NSR) |
262 | writel_relaxed(0x0, icu->base + ICU_INT_CFG(i)); | 263 | writel_relaxed(0x0, icu->base + ICU_INT_CFG(i)); |
263 | } | 264 | } |