aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDuc Dang <dhdang@apm.com>2015-06-05 16:56:34 -0400
committerBjorn Helgaas <bhelgaas@google.com>2015-06-05 16:56:34 -0400
commitdcd19de36775b689df602139f3e40bfb114d5d12 (patch)
treecd10fb434431da064a0816ed582989fb7f522569
parent5ebe6afaf0057ac3eaeb98defd5456894b446d22 (diff)
PCI: xgene: Add APM X-Gene v1 PCIe MSI/MSIX termination driver
APM X-Gene v1 SoC supports its own implementation of MSI, which is not compliant to GIC V2M specification for MSI Termination. There is a single MSI block in X-Gene v1 SOC which serves all 5 PCIe ports. This MSI block supports 2048 MSI termination ports coalesced into 16 physical HW IRQ lines and shared across all 5 PCIe ports. As there are only 16 HW IRQs to serve 2048 MSI vectors, to support set_affinity correctly for each MSI vectors, the 16 HW IRQs are statically allocated to 8 X-Gene v1 cores (2 HW IRQs for each cores). To steer MSI interrupt to target CPU, MSI vector is moved around these HW IRQs lines. With this approach, the total MSI vectors this driver supports is reduced to 256. [bhelgaas: squash doc, driver, maintainer update] Signed-off-by: Duc Dang <dhdang@apm.com> Signed-off-by: Tanmay Inamdar <tinamdar@apm.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r--Documentation/devicetree/bindings/pci/xgene-pci-msi.txt68
-rw-r--r--MAINTAINERS8
-rw-r--r--drivers/pci/host/Kconfig9
-rw-r--r--drivers/pci/host/Makefile1
-rw-r--r--drivers/pci/host/pci-xgene-msi.c596
-rw-r--r--drivers/pci/host/pci-xgene.c21
6 files changed, 703 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/pci/xgene-pci-msi.txt b/Documentation/devicetree/bindings/pci/xgene-pci-msi.txt
new file mode 100644
index 000000000000..36d881c8e6d4
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/xgene-pci-msi.txt
@@ -0,0 +1,68 @@
1* AppliedMicro X-Gene v1 PCIe MSI controller
2
3Required properties:
4
5- compatible: should be "apm,xgene1-msi" to identify
6 X-Gene v1 PCIe MSI controller block.
7- msi-controller: indicates that this is X-Gene v1 PCIe MSI controller node
8- reg: physical base address (0x79000000) and length (0x900000) for controller
9 registers. These registers include the MSI termination address and data
10 registers as well as the MSI interrupt status registers.
11- reg-names: not required
12- interrupts: A list of 16 interrupt outputs of the controller, starting from
13 interrupt number 0x10 to 0x1f.
14- interrupt-names: not required
15
16Each PCIe node needs to have property msi-parent that points to msi controller node
17
18Examples:
19
20SoC DTSI:
21
22 + MSI node:
23 msi@79000000 {
24 compatible = "apm,xgene1-msi";
25 msi-controller;
26 reg = <0x00 0x79000000 0x0 0x900000>;
27 interrupts = <0x0 0x10 0x4>
28 <0x0 0x11 0x4>
29 <0x0 0x12 0x4>
30 <0x0 0x13 0x4>
31 <0x0 0x14 0x4>
32 <0x0 0x15 0x4>
33 <0x0 0x16 0x4>
34 <0x0 0x17 0x4>
35 <0x0 0x18 0x4>
36 <0x0 0x19 0x4>
37 <0x0 0x1a 0x4>
38 <0x0 0x1b 0x4>
39 <0x0 0x1c 0x4>
40 <0x0 0x1d 0x4>
41 <0x0 0x1e 0x4>
42 <0x0 0x1f 0x4>;
43 };
44
45 + PCIe controller node with msi-parent property pointing to MSI node:
46 pcie0: pcie@1f2b0000 {
47 status = "disabled";
48 device_type = "pci";
49 compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
50 #interrupt-cells = <1>;
51 #size-cells = <2>;
52 #address-cells = <3>;
53 reg = < 0x00 0x1f2b0000 0x0 0x00010000 /* Controller registers */
54 0xe0 0xd0000000 0x0 0x00040000>; /* PCI config space */
55 reg-names = "csr", "cfg";
56 ranges = <0x01000000 0x00 0x00000000 0xe0 0x10000000 0x00 0x00010000 /* io */
57 0x02000000 0x00 0x80000000 0xe1 0x80000000 0x00 0x80000000>; /* mem */
58 dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
59 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
60 interrupt-map-mask = <0x0 0x0 0x0 0x7>;
61 interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1
62 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1
63 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1
64 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>;
65 dma-coherent;
66 clocks = <&pcie0clk 0>;
67 msi-parent= <&msi>;
68 };
diff --git a/MAINTAINERS b/MAINTAINERS
index 781e099495d3..59aa7b321c40 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7564,6 +7564,14 @@ L: linux-pci@vger.kernel.org
7564S: Orphan 7564S: Orphan
7565F: drivers/pci/host/*spear* 7565F: drivers/pci/host/*spear*
7566 7566
7567PCI MSI DRIVER FOR APPLIEDMICRO XGENE
7568M: Duc Dang <dhdang@apm.com>
7569L: linux-pci@vger.kernel.org
7570L: linux-arm-kernel@lists.infradead.org
7571S: Maintained
7572F: Documentation/devicetree/bindings/pci/xgene-pci-msi.txt
7573F: drivers/pci/host/pci-xgene-msi.c
7574
7567PCMCIA SUBSYSTEM 7575PCMCIA SUBSYSTEM
7568P: Linux PCMCIA Team 7576P: Linux PCMCIA Team
7569L: linux-pcmcia@lists.infradead.org 7577L: linux-pcmcia@lists.infradead.org
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 1dfb567b3522..9c48e9986bc7 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -89,11 +89,20 @@ config PCI_XGENE
89 depends on ARCH_XGENE 89 depends on ARCH_XGENE
90 depends on OF 90 depends on OF
91 select PCIEPORTBUS 91 select PCIEPORTBUS
92 select PCI_MSI_IRQ_DOMAIN if PCI_MSI
92 help 93 help
93 Say Y here if you want internal PCI support on APM X-Gene SoC. 94 Say Y here if you want internal PCI support on APM X-Gene SoC.
94 There are 5 internal PCIe ports available. Each port is GEN3 capable 95 There are 5 internal PCIe ports available. Each port is GEN3 capable
95 and have varied lanes from x1 to x8. 96 and have varied lanes from x1 to x8.
96 97
98config PCI_XGENE_MSI
99 bool "X-Gene v1 PCIe MSI feature"
100 depends on PCI_XGENE && PCI_MSI
101 default y
102 help
103 Say Y here if you want PCIe MSI support for the APM X-Gene v1 SoC.
104 This MSI driver supports 5 PCIe ports on the APM X-Gene v1 SoC.
105
97config PCI_LAYERSCAPE 106config PCI_LAYERSCAPE
98 bool "Freescale Layerscape PCIe controller" 107 bool "Freescale Layerscape PCIe controller"
99 depends on OF && ARM 108 depends on OF && ARM
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index f733b4e27642..1957431d3fcc 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
11obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o 11obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
12obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o 12obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
13obj-$(CONFIG_PCI_XGENE) += pci-xgene.o 13obj-$(CONFIG_PCI_XGENE) += pci-xgene.o
14obj-$(CONFIG_PCI_XGENE_MSI) += pci-xgene-msi.o
14obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o 15obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
15obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o 16obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o
16obj-$(CONFIG_PCIE_IPROC) += pcie-iproc.o 17obj-$(CONFIG_PCIE_IPROC) += pcie-iproc.o
diff --git a/drivers/pci/host/pci-xgene-msi.c b/drivers/pci/host/pci-xgene-msi.c
new file mode 100644
index 000000000000..2d31d4d6fd08
--- /dev/null
+++ b/drivers/pci/host/pci-xgene-msi.c
@@ -0,0 +1,596 @@
1/*
2 * APM X-Gene MSI Driver
3 *
4 * Copyright (c) 2014, Applied Micro Circuits Corporation
5 * Author: Tanmay Inamdar <tinamdar@apm.com>
6 * Duc Dang <dhdang@apm.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18#include <linux/cpu.h>
19#include <linux/interrupt.h>
20#include <linux/module.h>
21#include <linux/msi.h>
22#include <linux/of_irq.h>
23#include <linux/irqchip/chained_irq.h>
24#include <linux/pci.h>
25#include <linux/platform_device.h>
26#include <linux/of_pci.h>
27
28#define MSI_IR0 0x000000
29#define MSI_INT0 0x800000
30#define IDX_PER_GROUP 8
31#define IRQS_PER_IDX 16
32#define NR_HW_IRQS 16
33#define NR_MSI_VEC (IDX_PER_GROUP * IRQS_PER_IDX * NR_HW_IRQS)
34
35struct xgene_msi_group {
36 struct xgene_msi *msi;
37 int gic_irq;
38 u32 msi_grp;
39};
40
41struct xgene_msi {
42 struct device_node *node;
43 struct msi_controller mchip;
44 struct irq_domain *domain;
45 u64 msi_addr;
46 void __iomem *msi_regs;
47 unsigned long *bitmap;
48 struct mutex bitmap_lock;
49 struct xgene_msi_group *msi_groups;
50 int num_cpus;
51};
52
53/* Global data */
54static struct xgene_msi xgene_msi_ctrl;
55
56static struct irq_chip xgene_msi_top_irq_chip = {
57 .name = "X-Gene1 MSI",
58 .irq_enable = pci_msi_unmask_irq,
59 .irq_disable = pci_msi_mask_irq,
60 .irq_mask = pci_msi_mask_irq,
61 .irq_unmask = pci_msi_unmask_irq,
62};
63
64static struct msi_domain_info xgene_msi_domain_info = {
65 .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
66 MSI_FLAG_PCI_MSIX),
67 .chip = &xgene_msi_top_irq_chip,
68};
69
70/*
71 * X-Gene v1 has 16 groups of MSI termination registers MSInIRx, where
72 * n is group number (0..F), x is index of registers in each group (0..7)
73 * The register layout is as follows:
74 * MSI0IR0 base_addr
75 * MSI0IR1 base_addr + 0x10000
76 * ... ...
77 * MSI0IR6 base_addr + 0x60000
78 * MSI0IR7 base_addr + 0x70000
79 * MSI1IR0 base_addr + 0x80000
80 * MSI1IR1 base_addr + 0x90000
81 * ... ...
82 * MSI1IR7 base_addr + 0xF0000
83 * MSI2IR0 base_addr + 0x100000
84 * ... ...
85 * MSIFIR0 base_addr + 0x780000
86 * MSIFIR1 base_addr + 0x790000
87 * ... ...
88 * MSIFIR7 base_addr + 0x7F0000
89 * MSIINT0 base_addr + 0x800000
90 * MSIINT1 base_addr + 0x810000
91 * ... ...
92 * MSIINTF base_addr + 0x8F0000
93 *
94 * Each index register supports 16 MSI vectors (0..15) to generate interrupt.
95 * There are total 16 GIC IRQs assigned for these 16 groups of MSI termination
96 * registers.
97 *
98 * Each MSI termination group has 1 MSIINTn register (n is 0..15) to indicate
99 * the MSI pending status caused by 1 of its 8 index registers.
100 */
101
102/* MSInIRx read helper */
103static u32 xgene_msi_ir_read(struct xgene_msi *msi,
104 u32 msi_grp, u32 msir_idx)
105{
106 return readl_relaxed(msi->msi_regs + MSI_IR0 +
107 (msi_grp << 19) + (msir_idx << 16));
108}
109
110/* MSIINTn read helper */
111static u32 xgene_msi_int_read(struct xgene_msi *msi, u32 msi_grp)
112{
113 return readl_relaxed(msi->msi_regs + MSI_INT0 + (msi_grp << 16));
114}
115
116/*
117 * With 2048 MSI vectors supported, the MSI message can be constructed using
118 * following scheme:
119 * - Divide into 8 256-vector groups
120 * Group 0: 0-255
121 * Group 1: 256-511
122 * Group 2: 512-767
123 * ...
124 * Group 7: 1792-2047
125 * - Each 256-vector group is divided into 16 16-vector groups
126 * As an example: 16 16-vector groups for 256-vector group 0-255 is
127 * Group 0: 0-15
128 * Group 1: 16-32
129 * ...
130 * Group 15: 240-255
131 * - The termination address of MSI vector in 256-vector group n and 16-vector
132 * group x is the address of MSIxIRn
133 * - The data for MSI vector in 16-vector group x is x
134 */
135static u32 hwirq_to_reg_set(unsigned long hwirq)
136{
137 return (hwirq / (NR_HW_IRQS * IRQS_PER_IDX));
138}
139
140static u32 hwirq_to_group(unsigned long hwirq)
141{
142 return (hwirq % NR_HW_IRQS);
143}
144
145static u32 hwirq_to_msi_data(unsigned long hwirq)
146{
147 return ((hwirq / NR_HW_IRQS) % IRQS_PER_IDX);
148}
149
150static void xgene_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
151{
152 struct xgene_msi *msi = irq_data_get_irq_chip_data(data);
153 u32 reg_set = hwirq_to_reg_set(data->hwirq);
154 u32 group = hwirq_to_group(data->hwirq);
155 u64 target_addr = msi->msi_addr + (((8 * group) + reg_set) << 16);
156
157 msg->address_hi = upper_32_bits(target_addr);
158 msg->address_lo = lower_32_bits(target_addr);
159 msg->data = hwirq_to_msi_data(data->hwirq);
160}
161
162/*
163 * X-Gene v1 only has 16 MSI GIC IRQs for 2048 MSI vectors. To maintain
164 * the expected behaviour of .set_affinity for each MSI interrupt, the 16
165 * MSI GIC IRQs are statically allocated to 8 X-Gene v1 cores (2 GIC IRQs
166 * for each core). The MSI vector is moved fom 1 MSI GIC IRQ to another
167 * MSI GIC IRQ to steer its MSI interrupt to correct X-Gene v1 core. As a
168 * consequence, the total MSI vectors that X-Gene v1 supports will be
169 * reduced to 256 (2048/8) vectors.
170 */
171static int hwirq_to_cpu(unsigned long hwirq)
172{
173 return (hwirq % xgene_msi_ctrl.num_cpus);
174}
175
176static unsigned long hwirq_to_canonical_hwirq(unsigned long hwirq)
177{
178 return (hwirq - hwirq_to_cpu(hwirq));
179}
180
181static int xgene_msi_set_affinity(struct irq_data *irqdata,
182 const struct cpumask *mask, bool force)
183{
184 int target_cpu = cpumask_first(mask);
185 int curr_cpu;
186
187 curr_cpu = hwirq_to_cpu(irqdata->hwirq);
188 if (curr_cpu == target_cpu)
189 return IRQ_SET_MASK_OK_DONE;
190
191 /* Update MSI number to target the new CPU */
192 irqdata->hwirq = hwirq_to_canonical_hwirq(irqdata->hwirq) + target_cpu;
193
194 return IRQ_SET_MASK_OK;
195}
196
197static struct irq_chip xgene_msi_bottom_irq_chip = {
198 .name = "MSI",
199 .irq_set_affinity = xgene_msi_set_affinity,
200 .irq_compose_msi_msg = xgene_compose_msi_msg,
201};
202
203static int xgene_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
204 unsigned int nr_irqs, void *args)
205{
206 struct xgene_msi *msi = domain->host_data;
207 int msi_irq;
208
209 mutex_lock(&msi->bitmap_lock);
210
211 msi_irq = bitmap_find_next_zero_area(msi->bitmap, NR_MSI_VEC, 0,
212 msi->num_cpus, 0);
213 if (msi_irq < NR_MSI_VEC)
214 bitmap_set(msi->bitmap, msi_irq, msi->num_cpus);
215 else
216 msi_irq = -ENOSPC;
217
218 mutex_unlock(&msi->bitmap_lock);
219
220 if (msi_irq < 0)
221 return msi_irq;
222
223 irq_domain_set_info(domain, virq, msi_irq,
224 &xgene_msi_bottom_irq_chip, domain->host_data,
225 handle_simple_irq, NULL, NULL);
226 set_irq_flags(virq, IRQF_VALID);
227
228 return 0;
229}
230
231static void xgene_irq_domain_free(struct irq_domain *domain,
232 unsigned int virq, unsigned int nr_irqs)
233{
234 struct irq_data *d = irq_domain_get_irq_data(domain, virq);
235 struct xgene_msi *msi = irq_data_get_irq_chip_data(d);
236 u32 hwirq;
237
238 mutex_lock(&msi->bitmap_lock);
239
240 hwirq = hwirq_to_canonical_hwirq(d->hwirq);
241 bitmap_clear(msi->bitmap, hwirq, msi->num_cpus);
242
243 mutex_unlock(&msi->bitmap_lock);
244
245 irq_domain_free_irqs_parent(domain, virq, nr_irqs);
246}
247
248static const struct irq_domain_ops msi_domain_ops = {
249 .alloc = xgene_irq_domain_alloc,
250 .free = xgene_irq_domain_free,
251};
252
253static int xgene_allocate_domains(struct xgene_msi *msi)
254{
255 msi->domain = irq_domain_add_linear(NULL, NR_MSI_VEC,
256 &msi_domain_ops, msi);
257 if (!msi->domain)
258 return -ENOMEM;
259
260 msi->mchip.domain = pci_msi_create_irq_domain(msi->mchip.of_node,
261 &xgene_msi_domain_info,
262 msi->domain);
263
264 if (!msi->mchip.domain) {
265 irq_domain_remove(msi->domain);
266 return -ENOMEM;
267 }
268
269 return 0;
270}
271
272static void xgene_free_domains(struct xgene_msi *msi)
273{
274 if (msi->mchip.domain)
275 irq_domain_remove(msi->mchip.domain);
276 if (msi->domain)
277 irq_domain_remove(msi->domain);
278}
279
280static int xgene_msi_init_allocator(struct xgene_msi *xgene_msi)
281{
282 int size = BITS_TO_LONGS(NR_MSI_VEC) * sizeof(long);
283
284 xgene_msi->bitmap = kzalloc(size, GFP_KERNEL);
285 if (!xgene_msi->bitmap)
286 return -ENOMEM;
287
288 mutex_init(&xgene_msi->bitmap_lock);
289
290 xgene_msi->msi_groups = kcalloc(NR_HW_IRQS,
291 sizeof(struct xgene_msi_group),
292 GFP_KERNEL);
293 if (!xgene_msi->msi_groups)
294 return -ENOMEM;
295
296 return 0;
297}
298
299static void xgene_msi_isr(unsigned int irq, struct irq_desc *desc)
300{
301 struct irq_chip *chip = irq_desc_get_chip(desc);
302 struct xgene_msi_group *msi_groups;
303 struct xgene_msi *xgene_msi;
304 unsigned int virq;
305 int msir_index, msir_val, hw_irq;
306 u32 intr_index, grp_select, msi_grp;
307
308 chained_irq_enter(chip, desc);
309
310 msi_groups = irq_desc_get_handler_data(desc);
311 xgene_msi = msi_groups->msi;
312 msi_grp = msi_groups->msi_grp;
313
314 /*
315 * MSIINTn (n is 0..F) indicates if there is a pending MSI interrupt
316 * If bit x of this register is set (x is 0..7), one or more interupts
317 * corresponding to MSInIRx is set.
318 */
319 grp_select = xgene_msi_int_read(xgene_msi, msi_grp);
320 while (grp_select) {
321 msir_index = ffs(grp_select) - 1;
322 /*
323 * Calculate MSInIRx address to read to check for interrupts
324 * (refer to termination address and data assignment
325 * described in xgene_compose_msi_msg() )
326 */
327 msir_val = xgene_msi_ir_read(xgene_msi, msi_grp, msir_index);
328 while (msir_val) {
329 intr_index = ffs(msir_val) - 1;
330 /*
331 * Calculate MSI vector number (refer to the termination
332 * address and data assignment described in
333 * xgene_compose_msi_msg function)
334 */
335 hw_irq = (((msir_index * IRQS_PER_IDX) + intr_index) *
336 NR_HW_IRQS) + msi_grp;
337 /*
338 * As we have multiple hw_irq that maps to single MSI,
339 * always look up the virq using the hw_irq as seen from
340 * CPU0
341 */
342 hw_irq = hwirq_to_canonical_hwirq(hw_irq);
343 virq = irq_find_mapping(xgene_msi->domain, hw_irq);
344 WARN_ON(!virq);
345 if (virq != 0)
346 generic_handle_irq(virq);
347 msir_val &= ~(1 << intr_index);
348 }
349 grp_select &= ~(1 << msir_index);
350
351 if (!grp_select) {
352 /*
353 * We handled all interrupts happened in this group,
354 * resample this group MSI_INTx register in case
355 * something else has been made pending in the meantime
356 */
357 grp_select = xgene_msi_int_read(xgene_msi, msi_grp);
358 }
359 }
360
361 chained_irq_exit(chip, desc);
362}
363
364static int xgene_msi_remove(struct platform_device *pdev)
365{
366 int virq, i;
367 struct xgene_msi *msi = platform_get_drvdata(pdev);
368
369 for (i = 0; i < NR_HW_IRQS; i++) {
370 virq = msi->msi_groups[i].gic_irq;
371 if (virq != 0) {
372 irq_set_chained_handler(virq, NULL);
373 irq_set_handler_data(virq, NULL);
374 }
375 }
376 kfree(msi->msi_groups);
377
378 kfree(msi->bitmap);
379 msi->bitmap = NULL;
380
381 xgene_free_domains(msi);
382
383 return 0;
384}
385
386static int xgene_msi_hwirq_alloc(unsigned int cpu)
387{
388 struct xgene_msi *msi = &xgene_msi_ctrl;
389 struct xgene_msi_group *msi_group;
390 cpumask_var_t mask;
391 int i;
392 int err;
393
394 for (i = cpu; i < NR_HW_IRQS; i += msi->num_cpus) {
395 msi_group = &msi->msi_groups[i];
396 if (!msi_group->gic_irq)
397 continue;
398
399 irq_set_chained_handler(msi_group->gic_irq,
400 xgene_msi_isr);
401 err = irq_set_handler_data(msi_group->gic_irq, msi_group);
402 if (err) {
403 pr_err("failed to register GIC IRQ handler\n");
404 return -EINVAL;
405 }
406 /*
407 * Statically allocate MSI GIC IRQs to each CPU core.
408 * With 8-core X-Gene v1, 2 MSI GIC IRQs are allocated
409 * to each core.
410 */
411 if (alloc_cpumask_var(&mask, GFP_KERNEL)) {
412 cpumask_clear(mask);
413 cpumask_set_cpu(cpu, mask);
414 err = irq_set_affinity(msi_group->gic_irq, mask);
415 if (err)
416 pr_err("failed to set affinity for GIC IRQ");
417 free_cpumask_var(mask);
418 } else {
419 pr_err("failed to alloc CPU mask for affinity\n");
420 err = -EINVAL;
421 }
422
423 if (err) {
424 irq_set_chained_handler(msi_group->gic_irq, NULL);
425 irq_set_handler_data(msi_group->gic_irq, NULL);
426 return err;
427 }
428 }
429
430 return 0;
431}
432
433static void xgene_msi_hwirq_free(unsigned int cpu)
434{
435 struct xgene_msi *msi = &xgene_msi_ctrl;
436 struct xgene_msi_group *msi_group;
437 int i;
438
439 for (i = cpu; i < NR_HW_IRQS; i += msi->num_cpus) {
440 msi_group = &msi->msi_groups[i];
441 if (!msi_group->gic_irq)
442 continue;
443
444 irq_set_chained_handler(msi_group->gic_irq, NULL);
445 irq_set_handler_data(msi_group->gic_irq, NULL);
446 }
447}
448
449static int xgene_msi_cpu_callback(struct notifier_block *nfb,
450 unsigned long action, void *hcpu)
451{
452 unsigned cpu = (unsigned long)hcpu;
453
454 switch (action) {
455 case CPU_ONLINE:
456 case CPU_ONLINE_FROZEN:
457 xgene_msi_hwirq_alloc(cpu);
458 break;
459 case CPU_DEAD:
460 case CPU_DEAD_FROZEN:
461 xgene_msi_hwirq_free(cpu);
462 break;
463 default:
464 break;
465 }
466
467 return NOTIFY_OK;
468}
469
470static struct notifier_block xgene_msi_cpu_notifier = {
471 .notifier_call = xgene_msi_cpu_callback,
472};
473
474static const struct of_device_id xgene_msi_match_table[] = {
475 {.compatible = "apm,xgene1-msi"},
476 {},
477};
478
479static int xgene_msi_probe(struct platform_device *pdev)
480{
481 struct resource *res;
482 int rc, irq_index;
483 struct xgene_msi *xgene_msi;
484 unsigned int cpu;
485 int virt_msir;
486 u32 msi_val, msi_idx;
487
488 xgene_msi = &xgene_msi_ctrl;
489
490 platform_set_drvdata(pdev, xgene_msi);
491
492 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
493 xgene_msi->msi_regs = devm_ioremap_resource(&pdev->dev, res);
494 if (IS_ERR(xgene_msi->msi_regs)) {
495 dev_err(&pdev->dev, "no reg space\n");
496 rc = -EINVAL;
497 goto error;
498 }
499 xgene_msi->msi_addr = res->start;
500
501 xgene_msi->num_cpus = num_possible_cpus();
502
503 rc = xgene_msi_init_allocator(xgene_msi);
504 if (rc) {
505 dev_err(&pdev->dev, "Error allocating MSI bitmap\n");
506 goto error;
507 }
508
509 rc = xgene_allocate_domains(xgene_msi);
510 if (rc) {
511 dev_err(&pdev->dev, "Failed to allocate MSI domain\n");
512 goto error;
513 }
514
515 for (irq_index = 0; irq_index < NR_HW_IRQS; irq_index++) {
516 virt_msir = platform_get_irq(pdev, irq_index);
517 if (virt_msir < 0) {
518 dev_err(&pdev->dev, "Cannot translate IRQ index %d\n",
519 irq_index);
520 rc = -EINVAL;
521 goto error;
522 }
523 xgene_msi->msi_groups[irq_index].gic_irq = virt_msir;
524 xgene_msi->msi_groups[irq_index].msi_grp = irq_index;
525 xgene_msi->msi_groups[irq_index].msi = xgene_msi;
526 }
527
528 /*
529 * MSInIRx registers are read-to-clear; before registering
530 * interrupt handlers, read all of them to clear spurious
531 * interrupts that may occur before the driver is probed.
532 */
533 for (irq_index = 0; irq_index < NR_HW_IRQS; irq_index++) {
534 for (msi_idx = 0; msi_idx < IDX_PER_GROUP; msi_idx++)
535 msi_val = xgene_msi_ir_read(xgene_msi, irq_index,
536 msi_idx);
537 /* Read MSIINTn to confirm */
538 msi_val = xgene_msi_int_read(xgene_msi, irq_index);
539 if (msi_val) {
540 dev_err(&pdev->dev, "Failed to clear spurious IRQ\n");
541 rc = -EINVAL;
542 goto error;
543 }
544 }
545
546 cpu_notifier_register_begin();
547
548 for_each_online_cpu(cpu)
549 if (xgene_msi_hwirq_alloc(cpu)) {
550 dev_err(&pdev->dev, "failed to register MSI handlers\n");
551 cpu_notifier_register_done();
552 goto error;
553 }
554
555 rc = __register_hotcpu_notifier(&xgene_msi_cpu_notifier);
556 if (rc) {
557 dev_err(&pdev->dev, "failed to add CPU MSI notifier\n");
558 cpu_notifier_register_done();
559 goto error;
560 }
561
562 cpu_notifier_register_done();
563
564 xgene_msi->mchip.of_node = pdev->dev.of_node;
565 rc = of_pci_msi_chip_add(&xgene_msi->mchip);
566 if (rc) {
567 dev_err(&pdev->dev, "failed to add MSI controller chip\n");
568 goto error_notifier;
569 }
570
571 dev_info(&pdev->dev, "APM X-Gene PCIe MSI driver loaded\n");
572
573 return 0;
574
575error_notifier:
576 unregister_hotcpu_notifier(&xgene_msi_cpu_notifier);
577error:
578 xgene_msi_remove(pdev);
579 return rc;
580}
581
582static struct platform_driver xgene_msi_driver = {
583 .driver = {
584 .name = "xgene-msi",
585 .owner = THIS_MODULE,
586 .of_match_table = xgene_msi_match_table,
587 },
588 .probe = xgene_msi_probe,
589 .remove = xgene_msi_remove,
590};
591
592static int __init xgene_pcie_msi_init(void)
593{
594 return platform_driver_register(&xgene_msi_driver);
595}
596subsys_initcall(xgene_pcie_msi_init);
diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c
index ee082c0366ec..3e5a636c9a9a 100644
--- a/drivers/pci/host/pci-xgene.c
+++ b/drivers/pci/host/pci-xgene.c
@@ -468,6 +468,23 @@ static int xgene_pcie_setup(struct xgene_pcie_port *port,
468 return 0; 468 return 0;
469} 469}
470 470
471static int xgene_pcie_msi_enable(struct pci_bus *bus)
472{
473 struct device_node *msi_node;
474
475 msi_node = of_parse_phandle(bus->dev.of_node,
476 "msi-parent", 0);
477 if (!msi_node)
478 return -ENODEV;
479
480 bus->msi = of_pci_find_msi_chip_by_node(msi_node);
481 if (!bus->msi)
482 return -ENODEV;
483
484 bus->msi->dev = &bus->dev;
485 return 0;
486}
487
471static int xgene_pcie_probe_bridge(struct platform_device *pdev) 488static int xgene_pcie_probe_bridge(struct platform_device *pdev)
472{ 489{
473 struct device_node *dn = pdev->dev.of_node; 490 struct device_node *dn = pdev->dev.of_node;
@@ -504,6 +521,10 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
504 if (!bus) 521 if (!bus)
505 return -ENOMEM; 522 return -ENOMEM;
506 523
524 if (IS_ENABLED(CONFIG_PCI_MSI))
525 if (xgene_pcie_msi_enable(bus))
526 dev_info(port->dev, "failed to enable MSI\n");
527
507 pci_scan_child_bus(bus); 528 pci_scan_child_bus(bus);
508 pci_assign_unassigned_bus_resources(bus); 529 pci_assign_unassigned_bus_resources(bus);
509 pci_bus_add_devices(bus); 530 pci_bus_add_devices(bus);