aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r--arch/powerpc/sysdev/Kconfig6
-rw-r--r--arch/powerpc/sysdev/Makefile1
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c3
-rw-r--r--arch/powerpc/sysdev/fsl_rio.c10
-rw-r--r--arch/powerpc/sysdev/fsl_rmu.c6
-rw-r--r--arch/powerpc/sysdev/mpic.c8
-rw-r--r--arch/powerpc/sysdev/ppc4xx_hsta_msi.c215
-rw-r--r--arch/powerpc/sysdev/ppc4xx_pci.c21
8 files changed, 255 insertions, 15 deletions
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/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 3f415e252ea5..4bd091a05583 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -1150,8 +1150,7 @@ static int fsl_pci_pme_probe(struct pci_controller *hose)
1150 pci = hose->private_data; 1150 pci = hose->private_data;
1151 1151
1152 /* Enable PTOD, ENL23D & EXL23D */ 1152 /* Enable PTOD, ENL23D & EXL23D */
1153 out_be32(&pci->pex_pme_mes_disr, 0); 1153 clrbits32(&pci->pex_pme_mes_disr,
1154 setbits32(&pci->pex_pme_mes_disr,
1155 PME_DISR_EN_PTOD | PME_DISR_EN_ENL23D | PME_DISR_EN_EXL23D); 1154 PME_DISR_EN_PTOD | PME_DISR_EN_ENL23D | PME_DISR_EN_EXL23D);
1156 1155
1157 out_be32(&pci->pex_pme_mes_ier, 0); 1156 out_be32(&pci->pex_pme_mes_ier, 0);
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index cf2b0840a672..c04b718307c8 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -391,8 +391,10 @@ int fsl_rio_setup(struct platform_device *dev)
391 ops->get_inb_message = fsl_get_inb_message; 391 ops->get_inb_message = fsl_get_inb_message;
392 392
393 rmu_node = of_parse_phandle(dev->dev.of_node, "fsl,srio-rmu-handle", 0); 393 rmu_node = of_parse_phandle(dev->dev.of_node, "fsl,srio-rmu-handle", 0);
394 if (!rmu_node) 394 if (!rmu_node) {
395 dev_err(&dev->dev, "No valid fsl,srio-rmu-handle property\n");
395 goto err_rmu; 396 goto err_rmu;
397 }
396 rc = of_address_to_resource(rmu_node, 0, &rmu_regs); 398 rc = of_address_to_resource(rmu_node, 0, &rmu_regs);
397 if (rc) { 399 if (rc) {
398 dev_err(&dev->dev, "Can't get %s property 'reg'\n", 400 dev_err(&dev->dev, "Can't get %s property 'reg'\n",
@@ -413,6 +415,7 @@ int fsl_rio_setup(struct platform_device *dev)
413 /*set up doobell node*/ 415 /*set up doobell node*/
414 np = of_find_compatible_node(NULL, NULL, "fsl,srio-dbell-unit"); 416 np = of_find_compatible_node(NULL, NULL, "fsl,srio-dbell-unit");
415 if (!np) { 417 if (!np) {
418 dev_err(&dev->dev, "No fsl,srio-dbell-unit node\n");
416 rc = -ENODEV; 419 rc = -ENODEV;
417 goto err_dbell; 420 goto err_dbell;
418 } 421 }
@@ -441,6 +444,7 @@ int fsl_rio_setup(struct platform_device *dev)
441 /*set up port write node*/ 444 /*set up port write node*/
442 np = of_find_compatible_node(NULL, NULL, "fsl,srio-port-write-unit"); 445 np = of_find_compatible_node(NULL, NULL, "fsl,srio-port-write-unit");
443 if (!np) { 446 if (!np) {
447 dev_err(&dev->dev, "No fsl,srio-port-write-unit node\n");
444 rc = -ENODEV; 448 rc = -ENODEV;
445 goto err_pw; 449 goto err_pw;
446 } 450 }
@@ -633,14 +637,18 @@ int fsl_rio_setup(struct platform_device *dev)
633 return 0; 637 return 0;
634err: 638err:
635 kfree(pw); 639 kfree(pw);
640 pw = NULL;
636err_pw: 641err_pw:
637 kfree(dbell); 642 kfree(dbell);
643 dbell = NULL;
638err_dbell: 644err_dbell:
639 iounmap(rmu_regs_win); 645 iounmap(rmu_regs_win);
646 rmu_regs_win = NULL;
640err_rmu: 647err_rmu:
641 kfree(ops); 648 kfree(ops);
642err_ops: 649err_ops:
643 iounmap(rio_regs_win); 650 iounmap(rio_regs_win);
651 rio_regs_win = NULL;
644err_rio_regs: 652err_rio_regs:
645 return rc; 653 return rc;
646} 654}
diff --git a/arch/powerpc/sysdev/fsl_rmu.c b/arch/powerpc/sysdev/fsl_rmu.c
index 00e224a1048c..b48197ae44d0 100644
--- a/arch/powerpc/sysdev/fsl_rmu.c
+++ b/arch/powerpc/sysdev/fsl_rmu.c
@@ -881,9 +881,9 @@ fsl_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
881 rc = request_irq(IRQ_RIO_RX(mport), fsl_rio_rx_handler, 0, 881 rc = request_irq(IRQ_RIO_RX(mport), fsl_rio_rx_handler, 0,
882 "msg_rx", (void *)mport); 882 "msg_rx", (void *)mport);
883 if (rc < 0) { 883 if (rc < 0) {
884 dma_free_coherent(priv->dev, RIO_MSG_BUFFER_SIZE, 884 dma_free_coherent(priv->dev,
885 rmu->msg_tx_ring.virt_buffer[i], 885 rmu->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
886 rmu->msg_tx_ring.phys_buffer[i]); 886 rmu->msg_rx_ring.virt, rmu->msg_rx_ring.phys);
887 goto out; 887 goto out;
888 } 888 }
889 889
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 8209744b2829..be33c9768ea1 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -1588,10 +1588,6 @@ void __init mpic_init(struct mpic *mpic)
1588 num_timers = 8; 1588 num_timers = 8;
1589 } 1589 }
1590 1590
1591 /* FSL mpic error interrupt intialization */
1592 if (mpic->flags & MPIC_FSL_HAS_EIMR)
1593 mpic_err_int_init(mpic, MPIC_FSL_ERR_INT);
1594
1595 /* Initialize timers to our reserved vectors and mask them for now */ 1591 /* Initialize timers to our reserved vectors and mask them for now */
1596 for (i = 0; i < num_timers; i++) { 1592 for (i = 0; i < num_timers; i++) {
1597 unsigned int offset = mpic_tm_offset(mpic, i); 1593 unsigned int offset = mpic_tm_offset(mpic, i);
@@ -1675,6 +1671,10 @@ void __init mpic_init(struct mpic *mpic)
1675 irq_set_chained_handler(virq, &mpic_cascade); 1671 irq_set_chained_handler(virq, &mpic_cascade);
1676 } 1672 }
1677 } 1673 }
1674
1675 /* FSL mpic error interrupt intialization */
1676 if (mpic->flags & MPIC_FSL_HAS_EIMR)
1677 mpic_err_int_init(mpic, MPIC_FSL_ERR_INT);
1678} 1678}
1679 1679
1680void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) 1680void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio)
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 4914fd3f41ec..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;
@@ -1440,7 +1444,8 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np)
1440 ppc4xx_pciex_hwops = &ppc405ex_pcie_hwops; 1444 ppc4xx_pciex_hwops = &ppc405ex_pcie_hwops;
1441#endif 1445#endif
1442#ifdef CONFIG_476FPE 1446#ifdef CONFIG_476FPE
1443 if (of_device_is_compatible(np, "ibm,plb-pciex-476fpe")) 1447 if (of_device_is_compatible(np, "ibm,plb-pciex-476fpe")
1448 || of_device_is_compatible(np, "ibm,plb-pciex-476gtr"))
1444 ppc4xx_pciex_hwops = &ppc_476fpe_pcie_hwops; 1449 ppc4xx_pciex_hwops = &ppc_476fpe_pcie_hwops;
1445#endif 1450#endif
1446 if (ppc4xx_pciex_hwops == NULL) { 1451 if (ppc4xx_pciex_hwops == NULL) {
@@ -1751,7 +1756,10 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port,
1751 dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, 1756 dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL,
1752 sa | DCRO_PEGPL_460SX_OMR1MSKL_UOT 1757 sa | DCRO_PEGPL_460SX_OMR1MSKL_UOT
1753 | DCRO_PEGPL_OMRxMSKL_VAL); 1758 | DCRO_PEGPL_OMRxMSKL_VAL);
1754 else if (of_device_is_compatible(port->node, "ibm,plb-pciex-476fpe")) 1759 else if (of_device_is_compatible(
1760 port->node, "ibm,plb-pciex-476fpe") ||
1761 of_device_is_compatible(
1762 port->node, "ibm,plb-pciex-476gtr"))
1755 dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, 1763 dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL,
1756 sa | DCRO_PEGPL_476FPE_OMR1MSKL_UOT 1764 sa | DCRO_PEGPL_476FPE_OMR1MSKL_UOT
1757 | DCRO_PEGPL_OMRxMSKL_VAL); 1765 | DCRO_PEGPL_OMRxMSKL_VAL);
@@ -1881,7 +1889,10 @@ static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port,
1881 sa |= PCI_BASE_ADDRESS_MEM_PREFETCH; 1889 sa |= PCI_BASE_ADDRESS_MEM_PREFETCH;
1882 1890
1883 if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx") || 1891 if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx") ||
1884 of_device_is_compatible(port->node, "ibm,plb-pciex-476fpe")) 1892 of_device_is_compatible(
1893 port->node, "ibm,plb-pciex-476fpe") ||
1894 of_device_is_compatible(
1895 port->node, "ibm,plb-pciex-476gtr"))
1885 sa |= PCI_BASE_ADDRESS_MEM_TYPE_64; 1896 sa |= PCI_BASE_ADDRESS_MEM_TYPE_64;
1886 1897
1887 out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); 1898 out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa));