hc
2024-05-10 9999e48639b3cecb08ffb37358bcba3b48161b29
kernel/drivers/irqchip/irq-mvebu-icu.c
....@@ -13,6 +13,7 @@
1313 #include <linux/irq.h>
1414 #include <linux/irqchip.h>
1515 #include <linux/irqdomain.h>
16
+#include <linux/jump_label.h>
1617 #include <linux/kernel.h>
1718 #include <linux/msi.h>
1819 #include <linux/of_irq.h>
....@@ -26,6 +27,10 @@
2627 #define ICU_SETSPI_NSR_AH 0x14
2728 #define ICU_CLRSPI_NSR_AL 0x18
2829 #define ICU_CLRSPI_NSR_AH 0x1c
30
+#define ICU_SET_SEI_AL 0x50
31
+#define ICU_SET_SEI_AH 0x54
32
+#define ICU_CLR_SEI_AL 0x58
33
+#define ICU_CLR_SEI_AH 0x5C
2934 #define ICU_INT_CFG(x) (0x100 + 4 * (x))
3035 #define ICU_INT_ENABLE BIT(24)
3136 #define ICU_IS_EDGE BIT(28)
....@@ -36,12 +41,23 @@
3641 #define ICU_SATA0_ICU_ID 109
3742 #define ICU_SATA1_ICU_ID 107
3843
44
+struct mvebu_icu_subset_data {
45
+ unsigned int icu_group;
46
+ unsigned int offset_set_ah;
47
+ unsigned int offset_set_al;
48
+ unsigned int offset_clr_ah;
49
+ unsigned int offset_clr_al;
50
+};
51
+
3952 struct mvebu_icu {
40
- struct irq_chip irq_chip;
4153 void __iomem *base;
42
- struct irq_domain *domain;
4354 struct device *dev;
55
+};
56
+
57
+struct mvebu_icu_msi_data {
58
+ struct mvebu_icu *icu;
4459 atomic_t initialized;
60
+ const struct mvebu_icu_subset_data *subset_data;
4561 };
4662
4763 struct mvebu_icu_irq_data {
....@@ -50,28 +66,40 @@
5066 unsigned int type;
5167 };
5268
53
-static void mvebu_icu_init(struct mvebu_icu *icu, struct msi_msg *msg)
69
+static DEFINE_STATIC_KEY_FALSE(legacy_bindings);
70
+
71
+static void mvebu_icu_init(struct mvebu_icu *icu,
72
+ struct mvebu_icu_msi_data *msi_data,
73
+ struct msi_msg *msg)
5474 {
55
- if (atomic_cmpxchg(&icu->initialized, false, true))
75
+ const struct mvebu_icu_subset_data *subset = msi_data->subset_data;
76
+
77
+ if (atomic_cmpxchg(&msi_data->initialized, false, true))
5678 return;
5779
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);
80
+ /* Set 'SET' ICU SPI message address in AP */
81
+ writel_relaxed(msg[0].address_hi, icu->base + subset->offset_set_ah);
82
+ writel_relaxed(msg[0].address_lo, icu->base + subset->offset_set_al);
83
+
84
+ if (subset->icu_group != ICU_GRP_NSR)
85
+ return;
86
+
87
+ /* Set 'CLEAR' ICU SPI message address in AP (level-MSI only) */
88
+ writel_relaxed(msg[1].address_hi, icu->base + subset->offset_clr_ah);
89
+ writel_relaxed(msg[1].address_lo, icu->base + subset->offset_clr_al);
6390 }
6491
6592 static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg)
6693 {
6794 struct irq_data *d = irq_get_irq_data(desc->irq);
95
+ struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(d->domain);
6896 struct mvebu_icu_irq_data *icu_irqd = d->chip_data;
6997 struct mvebu_icu *icu = icu_irqd->icu;
7098 unsigned int icu_int;
7199
72100 if (msg->address_lo || msg->address_hi) {
73
- /* One off initialization */
74
- mvebu_icu_init(icu, msg);
101
+ /* One off initialization per domain */
102
+ mvebu_icu_init(icu, msi_data, msg);
75103 /* Configure the ICU with irq number & type */
76104 icu_int = msg->data | ICU_INT_ENABLE;
77105 if (icu_irqd->type & IRQ_TYPE_EDGE_RISING)
....@@ -101,36 +129,65 @@
101129 }
102130 }
103131
132
+static struct irq_chip mvebu_icu_nsr_chip = {
133
+ .name = "ICU-NSR",
134
+ .irq_mask = irq_chip_mask_parent,
135
+ .irq_unmask = irq_chip_unmask_parent,
136
+ .irq_eoi = irq_chip_eoi_parent,
137
+ .irq_set_type = irq_chip_set_type_parent,
138
+ .irq_set_affinity = irq_chip_set_affinity_parent,
139
+};
140
+
141
+static struct irq_chip mvebu_icu_sei_chip = {
142
+ .name = "ICU-SEI",
143
+ .irq_ack = irq_chip_ack_parent,
144
+ .irq_mask = irq_chip_mask_parent,
145
+ .irq_unmask = irq_chip_unmask_parent,
146
+ .irq_set_type = irq_chip_set_type_parent,
147
+ .irq_set_affinity = irq_chip_set_affinity_parent,
148
+};
149
+
104150 static int
105151 mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
106152 unsigned long *hwirq, unsigned int *type)
107153 {
154
+ struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(d);
108155 struct mvebu_icu *icu = platform_msi_get_host_data(d);
109
- unsigned int icu_group;
156
+ unsigned int param_count = static_branch_unlikely(&legacy_bindings) ? 3 : 2;
110157
111158 /* Check the count of the parameters in dt */
112
- if (WARN_ON(fwspec->param_count < 3)) {
159
+ if (WARN_ON(fwspec->param_count != param_count)) {
113160 dev_err(icu->dev, "wrong ICU parameter count %d\n",
114161 fwspec->param_count);
115162 return -EINVAL;
116163 }
117164
118
- /* Only ICU group type is handled */
119
- icu_group = fwspec->param[0];
120
- if (icu_group != ICU_GRP_NSR && icu_group != ICU_GRP_SR &&
121
- icu_group != ICU_GRP_SEI && icu_group != ICU_GRP_REI) {
122
- dev_err(icu->dev, "wrong ICU group type %x\n", icu_group);
123
- return -EINVAL;
165
+ if (static_branch_unlikely(&legacy_bindings)) {
166
+ *hwirq = fwspec->param[1];
167
+ *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
168
+ if (fwspec->param[0] != ICU_GRP_NSR) {
169
+ dev_err(icu->dev, "wrong ICU group type %x\n",
170
+ fwspec->param[0]);
171
+ return -EINVAL;
172
+ }
173
+ } else {
174
+ *hwirq = fwspec->param[0];
175
+ *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
176
+
177
+ /*
178
+ * The ICU receives level interrupts. While the NSR are also
179
+ * level interrupts, SEI are edge interrupts. Force the type
180
+ * here in this case. Please note that this makes the interrupt
181
+ * handling unreliable.
182
+ */
183
+ if (msi_data->subset_data->icu_group == ICU_GRP_SEI)
184
+ *type = IRQ_TYPE_EDGE_RISING;
124185 }
125186
126
- *hwirq = fwspec->param[1];
127187 if (*hwirq >= ICU_MAX_IRQS) {
128188 dev_err(icu->dev, "invalid interrupt number %ld\n", *hwirq);
129189 return -EINVAL;
130190 }
131
-
132
- /* Mask the type to prevent wrong DT configuration */
133
- *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
134191
135192 return 0;
136193 }
....@@ -142,8 +199,10 @@
142199 int err;
143200 unsigned long hwirq;
144201 struct irq_fwspec *fwspec = args;
145
- struct mvebu_icu *icu = platform_msi_get_host_data(domain);
202
+ struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(domain);
203
+ struct mvebu_icu *icu = msi_data->icu;
146204 struct mvebu_icu_irq_data *icu_irqd;
205
+ struct irq_chip *chip = &mvebu_icu_nsr_chip;
147206
148207 icu_irqd = kmalloc(sizeof(*icu_irqd), GFP_KERNEL);
149208 if (!icu_irqd)
....@@ -156,7 +215,10 @@
156215 goto free_irqd;
157216 }
158217
159
- icu_irqd->icu_group = fwspec->param[0];
218
+ if (static_branch_unlikely(&legacy_bindings))
219
+ icu_irqd->icu_group = fwspec->param[0];
220
+ else
221
+ icu_irqd->icu_group = msi_data->subset_data->icu_group;
160222 icu_irqd->icu = icu;
161223
162224 err = platform_msi_domain_alloc(domain, virq, nr_irqs);
....@@ -170,8 +232,11 @@
170232 if (err)
171233 goto free_msi;
172234
235
+ if (icu_irqd->icu_group == ICU_GRP_SEI)
236
+ chip = &mvebu_icu_sei_chip;
237
+
173238 err = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
174
- &icu->irq_chip, icu_irqd);
239
+ chip, icu_irqd);
175240 if (err) {
176241 dev_err(icu->dev, "failed to set the data to IRQ domain\n");
177242 goto free_msi;
....@@ -204,11 +269,84 @@
204269 .free = mvebu_icu_irq_domain_free,
205270 };
206271
272
+static const struct mvebu_icu_subset_data mvebu_icu_nsr_subset_data = {
273
+ .icu_group = ICU_GRP_NSR,
274
+ .offset_set_ah = ICU_SETSPI_NSR_AH,
275
+ .offset_set_al = ICU_SETSPI_NSR_AL,
276
+ .offset_clr_ah = ICU_CLRSPI_NSR_AH,
277
+ .offset_clr_al = ICU_CLRSPI_NSR_AL,
278
+};
279
+
280
+static const struct mvebu_icu_subset_data mvebu_icu_sei_subset_data = {
281
+ .icu_group = ICU_GRP_SEI,
282
+ .offset_set_ah = ICU_SET_SEI_AH,
283
+ .offset_set_al = ICU_SET_SEI_AL,
284
+};
285
+
286
+static const struct of_device_id mvebu_icu_subset_of_match[] = {
287
+ {
288
+ .compatible = "marvell,cp110-icu-nsr",
289
+ .data = &mvebu_icu_nsr_subset_data,
290
+ },
291
+ {
292
+ .compatible = "marvell,cp110-icu-sei",
293
+ .data = &mvebu_icu_sei_subset_data,
294
+ },
295
+ {},
296
+};
297
+
298
+static int mvebu_icu_subset_probe(struct platform_device *pdev)
299
+{
300
+ struct mvebu_icu_msi_data *msi_data;
301
+ struct device_node *msi_parent_dn;
302
+ struct device *dev = &pdev->dev;
303
+ struct irq_domain *irq_domain;
304
+
305
+ msi_data = devm_kzalloc(dev, sizeof(*msi_data), GFP_KERNEL);
306
+ if (!msi_data)
307
+ return -ENOMEM;
308
+
309
+ if (static_branch_unlikely(&legacy_bindings)) {
310
+ msi_data->icu = dev_get_drvdata(dev);
311
+ msi_data->subset_data = &mvebu_icu_nsr_subset_data;
312
+ } else {
313
+ msi_data->icu = dev_get_drvdata(dev->parent);
314
+ msi_data->subset_data = of_device_get_match_data(dev);
315
+ }
316
+
317
+ dev->msi_domain = of_msi_get_domain(dev, dev->of_node,
318
+ DOMAIN_BUS_PLATFORM_MSI);
319
+ if (!dev->msi_domain)
320
+ return -EPROBE_DEFER;
321
+
322
+ msi_parent_dn = irq_domain_get_of_node(dev->msi_domain);
323
+ if (!msi_parent_dn)
324
+ return -ENODEV;
325
+
326
+ irq_domain = platform_msi_create_device_tree_domain(dev, ICU_MAX_IRQS,
327
+ mvebu_icu_write_msg,
328
+ &mvebu_icu_domain_ops,
329
+ msi_data);
330
+ if (!irq_domain) {
331
+ dev_err(dev, "Failed to create ICU MSI domain\n");
332
+ return -ENOMEM;
333
+ }
334
+
335
+ return 0;
336
+}
337
+
338
+static struct platform_driver mvebu_icu_subset_driver = {
339
+ .probe = mvebu_icu_subset_probe,
340
+ .driver = {
341
+ .name = "mvebu-icu-subset",
342
+ .of_match_table = mvebu_icu_subset_of_match,
343
+ },
344
+};
345
+builtin_platform_driver(mvebu_icu_subset_driver);
346
+
207347 static int mvebu_icu_probe(struct platform_device *pdev)
208348 {
209349 struct mvebu_icu *icu;
210
- struct device_node *node = pdev->dev.of_node;
211
- struct device_node *gicp_dn;
212350 struct resource *res;
213351 int i;
214352
....@@ -226,53 +364,38 @@
226364 return PTR_ERR(icu->base);
227365 }
228366
229
- icu->irq_chip.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
230
- "ICU.%x",
231
- (unsigned int)res->start);
232
- if (!icu->irq_chip.name)
233
- return -ENOMEM;
234
-
235
- icu->irq_chip.irq_mask = irq_chip_mask_parent;
236
- icu->irq_chip.irq_unmask = irq_chip_unmask_parent;
237
- icu->irq_chip.irq_eoi = irq_chip_eoi_parent;
238
- icu->irq_chip.irq_set_type = irq_chip_set_type_parent;
239
-#ifdef CONFIG_SMP
240
- icu->irq_chip.irq_set_affinity = irq_chip_set_affinity_parent;
241
-#endif
242
-
243367 /*
244
- * We're probed after MSI domains have been resolved, so force
245
- * resolution here.
368
+ * Legacy bindings: ICU is one node with one MSI parent: force manually
369
+ * the probe of the NSR interrupts side.
370
+ * New bindings: ICU node has children, one per interrupt controller
371
+ * having its own MSI parent: call platform_populate().
372
+ * All ICU instances should use the same bindings.
246373 */
247
- pdev->dev.msi_domain = of_msi_get_domain(&pdev->dev, node,
248
- DOMAIN_BUS_PLATFORM_MSI);
249
- if (!pdev->dev.msi_domain)
250
- return -EPROBE_DEFER;
251
-
252
- gicp_dn = irq_domain_get_of_node(pdev->dev.msi_domain);
253
- if (!gicp_dn)
254
- return -ENODEV;
374
+ if (!of_get_child_count(pdev->dev.of_node))
375
+ static_branch_enable(&legacy_bindings);
255376
256377 /*
257
- * Clean all ICU interrupts with type SPI_NSR, required to
378
+ * Clean all ICU interrupts of type NSR and SEI, required to
258379 * avoid unpredictable SPI assignments done by firmware.
259380 */
260381 for (i = 0 ; i < ICU_MAX_IRQS ; i++) {
261
- u32 icu_int = readl_relaxed(icu->base + ICU_INT_CFG(i));
262
- if ((icu_int >> ICU_GROUP_SHIFT) == ICU_GRP_NSR)
382
+ u32 icu_int, icu_grp;
383
+
384
+ icu_int = readl_relaxed(icu->base + ICU_INT_CFG(i));
385
+ icu_grp = icu_int >> ICU_GROUP_SHIFT;
386
+
387
+ if (icu_grp == ICU_GRP_NSR ||
388
+ (icu_grp == ICU_GRP_SEI &&
389
+ !static_branch_unlikely(&legacy_bindings)))
263390 writel_relaxed(0x0, icu->base + ICU_INT_CFG(i));
264391 }
265392
266
- icu->domain =
267
- platform_msi_create_device_domain(&pdev->dev, ICU_MAX_IRQS,
268
- mvebu_icu_write_msg,
269
- &mvebu_icu_domain_ops, icu);
270
- if (!icu->domain) {
271
- dev_err(&pdev->dev, "Failed to create ICU domain\n");
272
- return -ENOMEM;
273
- }
393
+ platform_set_drvdata(pdev, icu);
274394
275
- return 0;
395
+ if (static_branch_unlikely(&legacy_bindings))
396
+ return mvebu_icu_subset_probe(pdev);
397
+ else
398
+ return devm_of_platform_populate(&pdev->dev);
276399 }
277400
278401 static const struct of_device_id mvebu_icu_of_match[] = {