summaryrefslogtreecommitdiffstats
path: root/recipes-kernel/linux/linux-hierofalcon/412-7-styx-linux-tracking.git-f9a9d954f23b967cd26338afda9a0a96afe62c25.patch
blob: 16c2dbdac477fcc54dbb7727ec20d0d1fbb744f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
From 6082a087207706d5951768d2d48aaa2d21fc2c0d Mon Sep 17 00:00:00 2001
From: Adrian Calianu <adrian.calianu@enea.com>
Date: Tue, 11 Aug 2015 15:09:19 +0200
Subject: [PATCH] DO NOT UPSTREAM YET: Introducing ACPI support for GICv2m

From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
Date: Tue, 20 Jan 2015 23:21:20 -0600

Signed-off-by: Adrian Calianu <adrian.calianu@enea.com>
---
 drivers/irqchip/irq-gic-v2m.c        | 193 ++++++++++++++++++++++++++---------
 drivers/pci/pci-acpi.c               |  55 ++++++----
 include/linux/irqchip/arm-gic-acpi.h |   1 +
 include/linux/pci-acpi.h             |   3 +
 4 files changed, 185 insertions(+), 67 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
index fdf7065..c32eb55 100644
--- a/drivers/irqchip/irq-gic-v2m.c
+++ b/drivers/irqchip/irq-gic-v2m.c
@@ -15,6 +15,7 @@
 
 #define pr_fmt(fmt) "GICv2m: " fmt
 
+#include <linux/acpi.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
 #include <linux/kernel.h>
@@ -22,6 +23,7 @@
 #include <linux/of_pci.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/irqchip/arm-gic.h>
 
 /*
 * MSI_TYPER:
@@ -45,7 +47,6 @@
 
 struct v2m_data {
 	spinlock_t msi_cnt_lock;
-	struct msi_controller mchip;
 	struct resource res;	/* GICv2m resource */
 	void __iomem *base;	/* GICv2m virt address */
 	u32 spi_start;		/* The SPI number that MSIs start */
@@ -115,17 +116,17 @@ static int gicv2m_irq_gic_domain_alloc(struct irq_domain *domain,
 				       unsigned int virq,
 				       irq_hw_number_t hwirq)
 {
-	struct of_phandle_args args;
+    struct gic_irq_alloc_info info;
 	struct irq_data *d;
 	int err;
 
-	args.np = domain->parent->of_node;
-	args.args_count = 3;
-	args.args[0] = 0;
-	args.args[1] = hwirq - 32;
-	args.args[2] = IRQ_TYPE_EDGE_RISING;
+    err = gic_init_irq_alloc_info(GIC_INT_TYPE_NONE, hwirq,
+                      IRQ_TYPE_EDGE_RISING,
+                      domain->parent->of_node, &info);
+    if (err)
+        return err;
 
-	err = irq_domain_alloc_irqs_parent(domain, virq, 1, &args);
+    err = irq_domain_alloc_irqs_parent(domain, virq, 1, &info);
 	if (err)
 		return err;
 
@@ -192,7 +193,7 @@ static void gicv2m_irq_domain_free(struct irq_domain *domain,
 	irq_domain_free_irqs_parent(domain, virq, nr_irqs);
 }
 
-static const struct irq_domain_ops gicv2m_domain_ops = {
+static struct irq_domain_ops gicv2m_domain_ops = {
 	.alloc			= gicv2m_irq_domain_alloc,
 	.free			= gicv2m_irq_domain_free,
 };
@@ -213,11 +214,18 @@ static bool is_msi_spi_valid(u32 base, u32 num)
 	return true;
 }
 
-static int __init gicv2m_init_one(struct device_node *node,
-				  struct irq_domain *parent)
+char gicv2m_msi_domain_name[] = "V2M-MSI";
+char gicv2m_domain_name[] = "GICV2M";
+
+static int __init gicv2m_init_one(struct irq_domain *parent,
+                 u32 *spi_start, u32 *nr_spis,
+                 struct resource *res,
+                 enum irq_domain_ref_type type,
+                 void *ref)
 {
 	int ret;
 	struct v2m_data *v2m;
+    struct irq_domain *inner_domain;
 
 	v2m = kzalloc(sizeof(struct v2m_data), GFP_KERNEL);
 	if (!v2m) {
@@ -225,23 +233,17 @@ static int __init gicv2m_init_one(struct device_node *node,
 		return -ENOMEM;
 	}
 
-	ret = of_address_to_resource(node, 0, &v2m->res);
-	if (ret) {
-		pr_err("Failed to allocate v2m resource.\n");
-		goto err_free_v2m;
-	}
-
-	v2m->base = ioremap(v2m->res.start, resource_size(&v2m->res));
+    v2m->base = ioremap(res->start, resource_size(res));
 	if (!v2m->base) {
 		pr_err("Failed to map GICv2m resource\n");
 		ret = -ENOMEM;
 		goto err_free_v2m;
 	}
+    memcpy(&v2m->res,res, sizeof(struct resource));
 
-	if (!of_property_read_u32(node, "arm,msi-base-spi", &v2m->spi_start) &&
-	    !of_property_read_u32(node, "arm,msi-num-spis", &v2m->nr_spis)) {
-		pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
-			v2m->spi_start, v2m->nr_spis);
+    if (*spi_start && *nr_spis) {
+        v2m->spi_start = *spi_start;
+        v2m->nr_spis = *nr_spis;
 	} else {
 		u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER);
 
@@ -261,43 +263,50 @@ static int __init gicv2m_init_one(struct device_node *node,
 		goto err_iounmap;
 	}
 
-	v2m->domain = irq_domain_add_tree(NULL, &gicv2m_domain_ops, v2m);
-	if (!v2m->domain) {
+    inner_domain = irq_domain_add_tree(node, &gicv2m_domain_ops, v2m);
+    if (!inner_domain) {
 		pr_err("Failed to create GICv2m domain\n");
 		ret = -ENOMEM;
 		goto err_free_bm;
 	}
 
-	v2m->domain->parent = parent;
-	v2m->mchip.of_node = node;
-	v2m->mchip.domain = pci_msi_create_irq_domain(node,
-						      &gicv2m_msi_domain_info,
-						      v2m->domain);
-	if (!v2m->mchip.domain) {
-		pr_err("Failed to create MSI domain\n");
-		ret = -ENOMEM;
-		goto err_free_domains;
-	}
-
-	spin_lock_init(&v2m->msi_cnt_lock);
-
-	ret = of_pci_msi_chip_add(&v2m->mchip);
-	if (ret) {
-		pr_err("Failed to add msi_chip.\n");
-		goto err_free_domains;
-	}
-
-	pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", node->name,
-		(unsigned long)v2m->res.start, (unsigned long)v2m->res.end,
-		v2m->spi_start, (v2m->spi_start + v2m->nr_spis));
+    inner_domain->bus_token = DOMAIN_BUS_PLATFORM_MSI;
+    inner_domain->name = gicv2m_domain_name;
+
+    ret = -ENOMEM;
+    if (type == IRQ_DOMAIN_REF_OF_DEV_NODE) {
+        v2m->domain = pci_msi_create_irq_domain(
+                    (struct device_node *)ref,
+                    &gicv2m_msi_domain_info,
+                    inner_domain);
+        if (!v2m->domain) {
+            pr_err("Failed to create MSI domain\n");
+            goto err_free_domains;
+        }
+    } else {
+        v2m->domain = pci_msi_create_irq_domain( NULL,
+                    &gicv2m_msi_domain_info,
+                    inner_domain);
+        if (!v2m->domain) {
+            pr_err("Failed to create MSI domain\n");
+            goto err_free_domains;
+        }
+
+        v2m->domain->type = type;
+        v2m->domain->acpi_ref = ref;
+    }
+
+    v2m->domain->name = gicv2m_msi_domain_name;
+
+    spin_lock_init(&v2m->msi_cnt_lock);
 
 	return 0;
 
 err_free_domains:
-	if (v2m->mchip.domain)
-		irq_domain_remove(v2m->mchip.domain);
 	if (v2m->domain)
 		irq_domain_remove(v2m->domain);
+    if (inner_domain)
+        irq_domain_remove(inner_domain);
 err_free_bm:
 	kfree(v2m->bm);
 err_iounmap:
@@ -319,15 +328,101 @@ int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent)
 
 	for (child = of_find_matching_node(node, gicv2m_device_id); child;
 	     child = of_find_matching_node(child, gicv2m_device_id)) {
+        u32 spi_start = 0, nr_spis = 0;
+        struct resource res;
+
 		if (!of_find_property(child, "msi-controller", NULL))
 			continue;
 
-		ret = gicv2m_init_one(child, parent);
+       ret = of_address_to_resource(child, 0, &res);
+       if (ret) {
+           pr_err("Failed to allocate v2m resource.\n");
+           break;
+       }
+
+       if (!of_property_read_u32(child, "arm,msi-base-spi", &spi_start) &&
+           !of_property_read_u32(child, "arm,msi-num-spis", &nr_spis))
+           pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
+               spi_start, nr_spis);
+
+       ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,
+                     IRQ_DOMAIN_REF_OF_DEV_NODE, child);
+
 		if (ret) {
 			of_node_put(node);
 			break;
 		}
+        pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", child->name,
+            (unsigned long)res.start, (unsigned long)res.end,
+            spi_start, (spi_start + nr_spis));
 	}
 
 	return ret;
 }
+
+#ifdef CONFIG_ACPI
+static struct acpi_madt_generic_msi_frame *msi_frame;
+
+static int __init
+gicv2m_acpi_parse_madt_msi(struct acpi_subtable_header *header,
+           const unsigned long end)
+{
+   struct acpi_madt_generic_msi_frame *frame;
+
+   frame = (struct acpi_madt_generic_msi_frame *)header;
+   if (BAD_MADT_ENTRY(frame, end))
+       return -EINVAL;
+
+   if (msi_frame)
+       pr_warn("Only one GIC MSI FRAME supported.\n");
+   else
+       msi_frame = frame;
+
+   return 0;
+}
+
+int __init gicv2m_acpi_init(struct acpi_table_header *table,
+               struct irq_domain *parent)
+{
+   int ret = 0;
+   int count, i;
+   struct acpi_madt_generic_msi_frame *cur;
+
+   count = acpi_parse_entries(ACPI_SIG_MADT, sizeof(struct acpi_table_madt),
+                  gicv2m_acpi_parse_madt_msi, table,
+                  ACPI_MADT_TYPE_GENERIC_MSI_FRAME, 0);
+
+   if ((count <= 0) || !msi_frame) {
+       pr_debug("No valid ACPI GIC MSI FRAME exist\n");
+       return 0;
+   }
+
+   for (i = 0, cur = msi_frame; i < count; i++, cur++) {
+       struct resource res;
+       u32 spi_start = 0, nr_spis = 0;
+
+       res.start = cur->base_address;
+       res.end = cur->base_address + 0x1000;
+
+       if (cur->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
+           spi_start = cur->spi_base;
+           nr_spis = cur->spi_count;
+
+           pr_info("ACPI overriding V2M MSI_TYPER (base:%u, num:%u)\n",
+               spi_start, nr_spis);
+       }
+
+       ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,
+                     IRQ_DOMAIN_REF_ACPI_MSI_FRAME, msi_frame);
+       if (ret)
+           break;
+
+       pr_info("MSI frame ID %u: range[%#lx:%#lx], SPI[%d:%d]\n",
+           cur->msi_frame_id,
+           (unsigned long)res.start, (unsigned long)res.end,
+           spi_start, (spi_start + nr_spis));
+   }
+   return ret;
+}
+
+#endif /* CONFIG_ACPI */
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index fe42097..fa0d8ec 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -9,6 +9,7 @@
 
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/irqdomain.h>
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
 #include <linux/module.h>
@@ -717,25 +718,43 @@ static int __init acpi_pci_init(void)
 arch_initcall(acpi_pci_init);
 
 #ifdef CONFIG_PCI_MSI
-void pci_acpi_set_phb_msi_domain(struct pci_bus *bus) {
+static struct acpi_madt_generic_msi_frame *msi_frame;
+static int
+pci_acpi_parse_madt_msi(struct acpi_subtable_header *header,
+           const unsigned long end)
+{
+   struct acpi_madt_generic_msi_frame *frame;
+   frame = (struct acpi_madt_generic_msi_frame *)header;
+   if (BAD_MADT_ENTRY(frame, end))
+       return -EINVAL;
+
+   /* We currently support one MSI frame only */
+   if (!msi_frame)
+       msi_frame = frame;
+
+   return 0;
+}
+
+void pci_acpi_set_phb_msi_domain(struct pci_bus *bus)
+{
+   int count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_MSI_FRAME,
+                     pci_acpi_parse_madt_msi, 0);
+   if (count > 0) {
 #ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
-   u32 msi_frame_id = 0;
-   int num;
-
-   if (acpi_disabled)
-       return;
-
-   /**
-    * Since ACPI 5.1 currently does not define
-    * a way to associate MSI frame ID to a device,
-    * we can only support single MSI frame at the moment.
-    * Therefore, the id 0 is used as a default.
-    */
-   num = msi_get_num_irq_domain();
-   if (num <= 0 || num > 1)
-       return;
-
-        dev_set_msi_domain(&bus->dev, irq_find_acpi_msi_domain(msi_frame_id));
+       struct irq_domain *domain;
+       /**
+       * Since ACPI 5.1 currently does not define
+       * a way to associate MSI frame ID to a device,
+       * we can only support single MSI frame at the moment.
+       */
+       domain = irq_find_domain(IRQ_DOMAIN_REF_ACPI_MSI_FRAME, msi_frame);
+       if (!domain) {
+           pr_debug("Fail to find domain for MSI\n");
+           return;
+       }
+
+       dev_set_msi_domain(&bus->dev, domain);
 #endif
+    }
 }
 #endif /* CONFIG_PCI_MSI */
diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
index fa8033b..b02f065 100644
--- a/include/linux/irqchip/arm-gic-acpi.h
+++ b/include/linux/irqchip/arm-gic-acpi.h
@@ -26,6 +26,7 @@ struct acpi_table_header;
 
 void acpi_irq_init(void);
 int gic_v2_acpi_init(struct acpi_table_header *table, struct irq_domain **domain);
+int gicv2m_acpi_init(struct acpi_table_header *table, struct irq_domain *parent);
 #else
 static inline void acpi_gic_init(void) { }
 #endif
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index a965efa..759916d 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -77,6 +77,8 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
 static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
 #endif
 
+void pci_acpi_set_phb_msi_domain(struct pci_bus *bus);
+
 extern const u8 pci_acpi_dsm_uuid[];
 #define DEVICE_LABEL_DSM	0x07
 #define RESET_DELAY_DSM		0x08
@@ -85,6 +87,7 @@ extern const u8 pci_acpi_dsm_uuid[];
 #else	/* CONFIG_ACPI */
 static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
+static inline void pci_acpi_set_phb_msi_domain(struct pci_bus *bus) { };
 #endif	/* CONFIG_ACPI */
 
 #ifdef CONFIG_ACPI_APEI
-- 
1.9.1