aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlistair Popple <alistair@popple.id.au>2014-03-05 22:52:28 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-04-30 18:26:30 -0400
commite2c37d908336dc27c8b405f063c2a163124947fa (patch)
tree2a5582122d13305abcd4558ed6810329369ea211
parent2a2c74b2efcb1a0ca3fdcb5fbb96ad8de6a29177 (diff)
powerpc: Added PCI MSI support using the HSTA module
The PPC476GTR SoC supports message signalled interrupts (MSI) by writing to special addresses within the High Speed Transfer Assist (HSTA) module. This patch adds support for PCI MSI with a new system device. The DMA window is also updated to allow access to the entire 42-bit address range to allow PCI devices write access to the HSTA module. Signed-off-by: Alistair Popple <alistair@popple.id.au> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--Documentation/devicetree/bindings/powerpc/4xx/hsta.txt19
-rw-r--r--arch/powerpc/boot/dts/akebono.dts46
-rw-r--r--arch/powerpc/boot/treeboot-akebono.c15
-rw-r--r--arch/powerpc/platforms/44x/Kconfig2
-rw-r--r--arch/powerpc/sysdev/Kconfig6
-rw-r--r--arch/powerpc/sysdev/Makefile1
-rw-r--r--arch/powerpc/sysdev/ppc4xx_hsta_msi.c215
-rw-r--r--arch/powerpc/sysdev/ppc4xx_pci.c8
8 files changed, 287 insertions, 25 deletions
diff --git a/Documentation/devicetree/bindings/powerpc/4xx/hsta.txt b/Documentation/devicetree/bindings/powerpc/4xx/hsta.txt
new file mode 100644
index 000000000000..c737c8338705
--- /dev/null
+++ b/Documentation/devicetree/bindings/powerpc/4xx/hsta.txt
@@ -0,0 +1,19 @@
1
2ppc476gtr High Speed Serial Assist (HSTA) node
3==============================================
4
5The 476gtr SoC contains a high speed serial assist module attached
6between the plb4 and plb6 system buses to provide high speed data
7transfer between memory and system peripherals as well as support for
8PCI message signalled interrupts.
9
10Currently only the MSI support is used by Linux using the following
11device tree entries:
12
13Require properties:
14- compatible : "ibm,476gtr-hsta-msi", "ibm,hsta-msi"
15- reg : register mapping for the HSTA MSI space
16- interrupt-parent : parent controller for mapping interrupts
17- interrupts : ordered interrupt mapping for each MSI in the register
18 space. The first interrupt should be associated with a
19 register offset of 0x00, the second to 0x10, etc.
diff --git a/arch/powerpc/boot/dts/akebono.dts b/arch/powerpc/boot/dts/akebono.dts
index 96ac13b2a02d..f92ecfed3d2f 100644
--- a/arch/powerpc/boot/dts/akebono.dts
+++ b/arch/powerpc/boot/dts/akebono.dts
@@ -82,6 +82,28 @@
82 ranges; 82 ranges;
83 clock-frequency = <200000000>; // 200Mhz 83 clock-frequency = <200000000>; // 200Mhz
84 84
85 HSTA0: hsta@310000e0000 {
86 compatible = "ibm,476gtr-hsta-msi", "ibm,hsta-msi";
87 reg = <0x310 0x000e0000 0x0 0xf0>;
88 interrupt-parent = <&MPIC>;
89 interrupts = <108 0
90 109 0
91 110 0
92 111 0
93 112 0
94 113 0
95 114 0
96 115 0
97 116 0
98 117 0
99 118 0
100 119 0
101 120 0
102 121 0
103 122 0
104 123 0>;
105 };
106
85 MAL0: mcmal { 107 MAL0: mcmal {
86 compatible = "ibm,mcmal-476gtr", "ibm,mcmal2"; 108 compatible = "ibm,mcmal-476gtr", "ibm,mcmal2";
87 dcr-reg = <0xc0000000 0x062>; 109 dcr-reg = <0xc0000000 0x062>;
@@ -242,8 +264,10 @@
242 ranges = <0x02000000 0x00000000 0x80000000 0x00000110 0x80000000 0x0 0x80000000 264 ranges = <0x02000000 0x00000000 0x80000000 0x00000110 0x80000000 0x0 0x80000000
243 0x01000000 0x0 0x0 0x00000140 0x0 0x0 0x00010000>; 265 0x01000000 0x0 0x0 0x00000140 0x0 0x0 0x00010000>;
244 266
245 /* Inbound starting at 0 to memsize filled in by zImage */ 267 /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI
246 dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x0>; 268 * PCI devices must be able to write to the HSTA module.
269 */
270 dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>;
247 271
248 /* This drives busses 0 to 0xf */ 272 /* This drives busses 0 to 0xf */
249 bus-range = <0x0 0xf>; 273 bus-range = <0x0 0xf>;
@@ -280,8 +304,10 @@
280 ranges = <0x02000000 0x00000000 0x80000000 0x00000210 0x80000000 0x0 0x80000000 304 ranges = <0x02000000 0x00000000 0x80000000 0x00000210 0x80000000 0x0 0x80000000
281 0x01000000 0x0 0x0 0x00000240 0x0 0x0 0x00010000>; 305 0x01000000 0x0 0x0 0x00000240 0x0 0x0 0x00010000>;
282 306
283 /* Inbound starting at 0 to memsize filled in by zImage */ 307 /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI
284 dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x0>; 308 * PCI devices must be able to write to the HSTA module.
309 */
310 dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>;
285 311
286 /* This drives busses 0 to 0xf */ 312 /* This drives busses 0 to 0xf */
287 bus-range = <0x0 0xf>; 313 bus-range = <0x0 0xf>;
@@ -318,8 +344,10 @@
318 ranges = <0x02000000 0x00000000 0x80000000 0x00000190 0x80000000 0x0 0x80000000 344 ranges = <0x02000000 0x00000000 0x80000000 0x00000190 0x80000000 0x0 0x80000000
319 0x01000000 0x0 0x0 0x000001c0 0x0 0x0 0x00010000>; 345 0x01000000 0x0 0x0 0x000001c0 0x0 0x0 0x00010000>;
320 346
321 /* Inbound starting at 0 to memsize filled in by zImage */ 347 /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI
322 dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x0>; 348 * PCI devices must be able to write to the HSTA module.
349 */
350 dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>;
323 351
324 /* This drives busses 0 to 0xf */ 352 /* This drives busses 0 to 0xf */
325 bus-range = <0x0 0xf>; 353 bus-range = <0x0 0xf>;
@@ -356,8 +384,10 @@
356 ranges = <0x02000000 0x00000000 0x80000000 0x00000290 0x80000000 0x0 0x80000000 384 ranges = <0x02000000 0x00000000 0x80000000 0x00000290 0x80000000 0x0 0x80000000
357 0x01000000 0x0 0x0 0x000002c0 0x0 0x0 0x00010000>; 385 0x01000000 0x0 0x0 0x000002c0 0x0 0x0 0x00010000>;
358 386
359 /* Inbound starting at 0 to memsize filled in by zImage */ 387 /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI
360 dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x0>; 388 * PCI devices must be able to write to the HSTA module.
389 */
390 dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>;
361 391
362 /* This drives busses 0 to 0xf */ 392 /* This drives busses 0 to 0xf */
363 bus-range = <0x0 0xf>; 393 bus-range = <0x0 0xf>;
diff --git a/arch/powerpc/boot/treeboot-akebono.c b/arch/powerpc/boot/treeboot-akebono.c
index 070a20f2f5d1..b73174c34fe4 100644
--- a/arch/powerpc/boot/treeboot-akebono.c
+++ b/arch/powerpc/boot/treeboot-akebono.c
@@ -75,24 +75,9 @@ static void ibm_akebono_fixups(void)
75{ 75{
76 void *emac; 76 void *emac;
77 u32 reg; 77 u32 reg;
78 void *devp = finddevice("/");
79 u32 dma_ranges[7];
80 78
81 dt_fixup_memory(0x0ULL, ibm_akebono_memsize); 79 dt_fixup_memory(0x0ULL, ibm_akebono_memsize);
82 80
83 while ((devp = find_node_by_devtype(devp, "pci"))) {
84 if (getprop(devp, "dma-ranges", dma_ranges,
85 sizeof(dma_ranges)) < 0) {
86 printf("%s: Failed to get dma-ranges\r\n", __func__);
87 continue;
88 }
89
90 dma_ranges[5] = ibm_akebono_memsize >> 32;
91 dma_ranges[6] = ibm_akebono_memsize & 0xffffffffUL;
92
93 setprop(devp, "dma-ranges", dma_ranges, sizeof(dma_ranges));
94 }
95
96 /* Fixup the SD timeout frequency */ 81 /* Fixup the SD timeout frequency */
97 mtdcrx(CCTL0_MCO4, 0x1); 82 mtdcrx(CCTL0_MCO4, 0x1);
98 83
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index b0202d83063e..8beec7d00cac 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -206,6 +206,8 @@ config AKEBONO
206 select SWIOTLB 206 select SWIOTLB
207 select 476FPE 207 select 476FPE
208 select PPC4xx_PCI_EXPRESS 208 select PPC4xx_PCI_EXPRESS
209 select PCI_MSI
210 select PPC4xx_HSTA_MSI
209 select I2C 211 select I2C
210 select I2C_IBM_IIC 212 select I2C_IBM_IIC
211 select NETDEVICES 213 select NETDEVICES
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
index 7baa70d6dc01..a19332a38715 100644
--- a/arch/powerpc/sysdev/Kconfig
+++ b/arch/powerpc/sysdev/Kconfig
@@ -7,6 +7,12 @@ config PPC4xx_PCI_EXPRESS
7 depends on PCI && 4xx 7 depends on PCI && 4xx
8 default n 8 default n
9 9
10config PPC4xx_HSTA_MSI
11 bool
12 depends on PCI_MSI
13 depends on PCI && 4xx
14 default n
15
10config PPC4xx_MSI 16config PPC4xx_MSI
11 bool 17 bool
12 depends on PCI_MSI 18 depends on PCI_MSI
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index afbcc37aa094..f7cb2a1b01fa 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_OF_RTC) += of_rtc.o
45ifeq ($(CONFIG_PCI),y) 45ifeq ($(CONFIG_PCI),y)
46obj-$(CONFIG_4xx) += ppc4xx_pci.o 46obj-$(CONFIG_4xx) += ppc4xx_pci.o
47endif 47endif
48obj-$(CONFIG_PPC4xx_HSTA_MSI) += ppc4xx_hsta_msi.o
48obj-$(CONFIG_PPC4xx_MSI) += ppc4xx_msi.o 49obj-$(CONFIG_PPC4xx_MSI) += ppc4xx_msi.o
49obj-$(CONFIG_PPC4xx_CPM) += ppc4xx_cpm.o 50obj-$(CONFIG_PPC4xx_CPM) += ppc4xx_cpm.o
50obj-$(CONFIG_PPC4xx_GPIO) += ppc4xx_gpio.o 51obj-$(CONFIG_PPC4xx_GPIO) += ppc4xx_gpio.o
diff --git a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c
new file mode 100644
index 000000000000..11c888416f0a
--- /dev/null
+++ b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c
@@ -0,0 +1,215 @@
1/*
2 * MSI support for PPC4xx SoCs using High Speed Transfer Assist (HSTA) for
3 * generation of the interrupt.
4 *
5 * Copyright © 2013 Alistair Popple <alistair@popple.id.au> IBM Corporation
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12
13#include <linux/kernel.h>
14#include <linux/interrupt.h>
15#include <linux/msi.h>
16#include <linux/of.h>
17#include <linux/of_platform.h>
18#include <linux/pci.h>
19#include <linux/semaphore.h>
20#include <asm/msi_bitmap.h>
21
22struct ppc4xx_hsta_msi {
23 struct device *dev;
24
25 /* The ioremapped HSTA MSI IO space */
26 u32 __iomem *data;
27
28 /* Physical address of HSTA MSI IO space */
29 u64 address;
30 struct msi_bitmap bmp;
31
32 /* An array mapping offsets to hardware IRQs */
33 int *irq_map;
34
35 /* Number of hwirqs supported */
36 int irq_count;
37};
38static struct ppc4xx_hsta_msi ppc4xx_hsta_msi;
39
40static int hsta_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
41{
42 struct msi_msg msg;
43 struct msi_desc *entry;
44 int irq, hwirq;
45 u64 addr;
46
47 list_for_each_entry(entry, &dev->msi_list, list) {
48 irq = msi_bitmap_alloc_hwirqs(&ppc4xx_hsta_msi.bmp, 1);
49 if (irq < 0) {
50 pr_debug("%s: Failed to allocate msi interrupt\n",
51 __func__);
52 return irq;
53 }
54
55 hwirq = ppc4xx_hsta_msi.irq_map[irq];
56 if (hwirq == NO_IRQ) {
57 pr_err("%s: Failed mapping irq %d\n", __func__, irq);
58 return -EINVAL;
59 }
60
61 /*
62 * HSTA generates interrupts on writes to 128-bit aligned
63 * addresses.
64 */
65 addr = ppc4xx_hsta_msi.address + irq*0x10;
66 msg.address_hi = upper_32_bits(addr);
67 msg.address_lo = lower_32_bits(addr);
68
69 /* Data is not used by the HSTA. */
70 msg.data = 0;
71
72 pr_debug("%s: Setup irq %d (0x%0llx)\n", __func__, hwirq,
73 (((u64) msg.address_hi) << 32) | msg.address_lo);
74
75 if (irq_set_msi_desc(hwirq, entry)) {
76 pr_err(
77 "%s: Invalid hwirq %d specified in device tree\n",
78 __func__, hwirq);
79 msi_bitmap_free_hwirqs(&ppc4xx_hsta_msi.bmp, irq, 1);
80 return -EINVAL;
81 }
82 write_msi_msg(hwirq, &msg);
83 }
84
85 return 0;
86}
87
88static int hsta_find_hwirq_offset(int hwirq)
89{
90 int irq;
91
92 /* Find the offset given the hwirq */
93 for (irq = 0; irq < ppc4xx_hsta_msi.irq_count; irq++)
94 if (ppc4xx_hsta_msi.irq_map[irq] == hwirq)
95 return irq;
96
97 return -EINVAL;
98}
99
100static void hsta_teardown_msi_irqs(struct pci_dev *dev)
101{
102 struct msi_desc *entry;
103 int irq;
104
105 list_for_each_entry(entry, &dev->msi_list, list) {
106 if (entry->irq == NO_IRQ)
107 continue;
108
109 irq = hsta_find_hwirq_offset(entry->irq);
110
111 /* entry->irq should always be in irq_map */
112 BUG_ON(irq < 0);
113 irq_set_msi_desc(entry->irq, NULL);
114 msi_bitmap_free_hwirqs(&ppc4xx_hsta_msi.bmp, irq, 1);
115 pr_debug("%s: Teardown IRQ %u (index %u)\n", __func__,
116 entry->irq, irq);
117 }
118}
119
120static int hsta_msi_check_device(struct pci_dev *pdev, int nvec, int type)
121{
122 /* We don't support MSI-X */
123 if (type == PCI_CAP_ID_MSIX) {
124 pr_debug("%s: MSI-X not supported.\n", __func__);
125 return -EINVAL;
126 }
127
128 return 0;
129}
130
131static int hsta_msi_probe(struct platform_device *pdev)
132{
133 struct device *dev = &pdev->dev;
134 struct resource *mem;
135 int irq, ret, irq_count;
136
137 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
138 if (IS_ERR(mem)) {
139 dev_err(dev, "Unable to get mmio space\n");
140 return -EINVAL;
141 }
142
143 irq_count = of_irq_count(dev->of_node);
144 if (!irq_count) {
145 dev_err(dev, "Unable to find IRQ range\n");
146 return -EINVAL;
147 }
148
149 ppc4xx_hsta_msi.dev = dev;
150 ppc4xx_hsta_msi.address = mem->start;
151 ppc4xx_hsta_msi.data = ioremap(mem->start, resource_size(mem));
152 ppc4xx_hsta_msi.irq_count = irq_count;
153 if (IS_ERR(ppc4xx_hsta_msi.data)) {
154 dev_err(dev, "Unable to map memory\n");
155 return -ENOMEM;
156 }
157
158 ret = msi_bitmap_alloc(&ppc4xx_hsta_msi.bmp, irq_count, dev->of_node);
159 if (ret)
160 goto out;
161
162 ppc4xx_hsta_msi.irq_map = kmalloc(sizeof(int) * irq_count, GFP_KERNEL);
163 if (IS_ERR(ppc4xx_hsta_msi.irq_map)) {
164 ret = -ENOMEM;
165 goto out1;
166 }
167
168 /* Setup a mapping from irq offsets to hardware irq numbers */
169 for (irq = 0; irq < irq_count; irq++) {
170 ppc4xx_hsta_msi.irq_map[irq] =
171 irq_of_parse_and_map(dev->of_node, irq);
172 if (ppc4xx_hsta_msi.irq_map[irq] == NO_IRQ) {
173 dev_err(dev, "Unable to map IRQ\n");
174 ret = -EINVAL;
175 goto out2;
176 }
177 }
178
179 ppc_md.setup_msi_irqs = hsta_setup_msi_irqs;
180 ppc_md.teardown_msi_irqs = hsta_teardown_msi_irqs;
181 ppc_md.msi_check_device = hsta_msi_check_device;
182 return 0;
183
184out2:
185 kfree(ppc4xx_hsta_msi.irq_map);
186
187out1:
188 msi_bitmap_free(&ppc4xx_hsta_msi.bmp);
189
190out:
191 iounmap(ppc4xx_hsta_msi.data);
192 return ret;
193}
194
195static const struct of_device_id hsta_msi_ids[] = {
196 {
197 .compatible = "ibm,hsta-msi",
198 },
199 {}
200};
201
202static struct platform_driver hsta_msi_driver = {
203 .probe = hsta_msi_probe,
204 .driver = {
205 .name = "hsta-msi",
206 .owner = THIS_MODULE,
207 .of_match_table = hsta_msi_ids,
208 },
209};
210
211static int hsta_msi_init(void)
212{
213 return platform_driver_register(&hsta_msi_driver);
214}
215subsys_initcall(hsta_msi_init);
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c
index 5a4f61ee6b33..df6e2fc4ff92 100644
--- a/arch/powerpc/sysdev/ppc4xx_pci.c
+++ b/arch/powerpc/sysdev/ppc4xx_pci.c
@@ -176,8 +176,12 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
176 return -ENXIO; 176 return -ENXIO;
177 } 177 }
178 178
179 /* Check that we are fully contained within 32 bits space */ 179 /* Check that we are fully contained within 32 bits space if we are not
180 if (res->end > 0xffffffff) { 180 * running on a 460sx or 476fpe which have 64 bit bus addresses.
181 */
182 if (res->end > 0xffffffff &&
183 !(of_device_is_compatible(hose->dn, "ibm,plb-pciex-460sx")
184 || of_device_is_compatible(hose->dn, "ibm,plb-pciex-476fpe"))) {
181 printk(KERN_ERR "%s: dma-ranges outside of 32 bits space\n", 185 printk(KERN_ERR "%s: dma-ranges outside of 32 bits space\n",
182 hose->dn->full_name); 186 hose->dn->full_name);
183 return -ENXIO; 187 return -ENXIO;