aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-iop13xx
diff options
context:
space:
mode:
authorDaniel Wolstenholme <daniel.e.wolstenholme@intel.com>2007-05-11 01:33:02 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-05-11 12:41:52 -0400
commit2fd0237538480c8d704c385b6f9abc3f6c46b760 (patch)
tree4f4052fb01ec00d4717bc7741602e02aa9833ef6 /arch/arm/mach-iop13xx
parent87b247c41674e29f90bf4938799ab079951ccc6b (diff)
[ARM] iop13xx: msi support
Enable devices to signal interrupts via PCI memory cycles. rev6: * fix enable/disable typo, Michael Ellerman rev5: * fix up ack, enable, and disable for iop13xx_msi_chip rev4: * move smp compile fix to separate patch * use dynamic_irq_init in create_irq() * hookup mask/unmask routines in iop13xx_msi_chip rev3: * change msi.c to use linux/smp.h instead of asm/smp.h * call dynamic_irq_cleanup at destroy_irq time rev2: * destroy_irq did not take the full 128 bits of msi_irq_in_use into account * added missing '&' for calls to test_and_set_bit and clear_bit [ebiederm@xmission.com: review comments/suggestions] [dan.j.williams@intel.com: cleanups/forward port to 2.6-git] Signed-off-by: Daniel Wolstenholme <daniel.e.wolstenholme@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Acked-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-iop13xx')
-rw-r--r--arch/arm/mach-iop13xx/Makefile1
-rw-r--r--arch/arm/mach-iop13xx/irq.c5
-rw-r--r--arch/arm/mach-iop13xx/msi.c194
-rw-r--r--arch/arm/mach-iop13xx/pci.c16
4 files changed, 215 insertions, 1 deletions
diff --git a/arch/arm/mach-iop13xx/Makefile b/arch/arm/mach-iop13xx/Makefile
index da1609dc0dee..cad015fee12f 100644
--- a/arch/arm/mach-iop13xx/Makefile
+++ b/arch/arm/mach-iop13xx/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_ARCH_IOP13XX) += io.o
10obj-$(CONFIG_ARCH_IOP13XX) += tpmi.o 10obj-$(CONFIG_ARCH_IOP13XX) += tpmi.o
11obj-$(CONFIG_MACH_IQ81340SC) += iq81340sc.o 11obj-$(CONFIG_MACH_IQ81340SC) += iq81340sc.o
12obj-$(CONFIG_MACH_IQ81340MC) += iq81340mc.o 12obj-$(CONFIG_MACH_IQ81340MC) += iq81340mc.o
13obj-$(CONFIG_PCI_MSI) += msi.o
diff --git a/arch/arm/mach-iop13xx/irq.c b/arch/arm/mach-iop13xx/irq.c
index b2eb0b961031..5791addd436b 100644
--- a/arch/arm/mach-iop13xx/irq.c
+++ b/arch/arm/mach-iop13xx/irq.c
@@ -26,6 +26,7 @@
26#include <asm/hardware.h> 26#include <asm/hardware.h>
27#include <asm/mach-types.h> 27#include <asm/mach-types.h>
28#include <asm/arch/irqs.h> 28#include <asm/arch/irqs.h>
29#include <asm/arch/msi.h>
29 30
30/* INTCTL0 CP6 R0 Page 4 31/* INTCTL0 CP6 R0 Page 4
31 */ 32 */
@@ -258,7 +259,7 @@ void __init iop13xx_init_irq(void)
258 write_intbase(INTBASE); 259 write_intbase(INTBASE);
259 write_intsize(INTSIZE_4); 260 write_intsize(INTSIZE_4);
260 261
261 for(i = 0; i < NR_IOP13XX_IRQS; i++) { 262 for(i = 0; i <= IRQ_IOP13XX_HPI; i++) {
262 if (i < 32) 263 if (i < 32)
263 set_irq_chip(i, &iop13xx_irqchip1); 264 set_irq_chip(i, &iop13xx_irqchip1);
264 else if (i < 64) 265 else if (i < 64)
@@ -271,4 +272,6 @@ void __init iop13xx_init_irq(void)
271 set_irq_handler(i, handle_level_irq); 272 set_irq_handler(i, handle_level_irq);
272 set_irq_flags(i, IRQF_VALID | IRQF_PROBE); 273 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
273 } 274 }
275
276 iop13xx_msi_init();
274} 277}
diff --git a/arch/arm/mach-iop13xx/msi.c b/arch/arm/mach-iop13xx/msi.c
new file mode 100644
index 000000000000..2d2369302220
--- /dev/null
+++ b/arch/arm/mach-iop13xx/msi.c
@@ -0,0 +1,194 @@
1/*
2 * arch/arm/mach-iop13xx/msi.c
3 *
4 * PCI MSI support for the iop13xx processor
5 *
6 * Copyright (c) 2006, Intel Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place - Suite 330, Boston, MA 02111-1307 USA.
20 *
21 */
22#include <linux/pci.h>
23#include <linux/msi.h>
24#include <asm/mach/irq.h>
25#include <asm/irq.h>
26
27
28#define IOP13XX_NUM_MSI_IRQS 128
29static DECLARE_BITMAP(msi_irq_in_use, IOP13XX_NUM_MSI_IRQS);
30
31/* IMIPR0 CP6 R8 Page 1
32 */
33static inline u32 read_imipr_0(void)
34{
35 u32 val;
36 asm volatile("mrc p6, 0, %0, c8, c1, 0":"=r" (val));
37 return val;
38}
39static inline void write_imipr_0(u32 val)
40{
41 asm volatile("mcr p6, 0, %0, c8, c1, 0"::"r" (val));
42}
43
44/* IMIPR1 CP6 R9 Page 1
45 */
46static inline u32 read_imipr_1(void)
47{
48 u32 val;
49 asm volatile("mrc p6, 0, %0, c9, c1, 0":"=r" (val));
50 return val;
51}
52static inline void write_imipr_1(u32 val)
53{
54 asm volatile("mcr p6, 0, %0, c9, c1, 0"::"r" (val));
55}
56
57/* IMIPR2 CP6 R10 Page 1
58 */
59static inline u32 read_imipr_2(void)
60{
61 u32 val;
62 asm volatile("mrc p6, 0, %0, c10, c1, 0":"=r" (val));
63 return val;
64}
65static inline void write_imipr_2(u32 val)
66{
67 asm volatile("mcr p6, 0, %0, c10, c1, 0"::"r" (val));
68}
69
70/* IMIPR3 CP6 R11 Page 1
71 */
72static inline u32 read_imipr_3(void)
73{
74 u32 val;
75 asm volatile("mrc p6, 0, %0, c11, c1, 0":"=r" (val));
76 return val;
77}
78static inline void write_imipr_3(u32 val)
79{
80 asm volatile("mcr p6, 0, %0, c11, c1, 0"::"r" (val));
81}
82
83static u32 (*read_imipr[])(void) = {
84 read_imipr_0,
85 read_imipr_1,
86 read_imipr_2,
87 read_imipr_3,
88};
89
90static void (*write_imipr[])(u32) = {
91 write_imipr_0,
92 write_imipr_1,
93 write_imipr_2,
94 write_imipr_3,
95};
96
97static void iop13xx_msi_handler(unsigned int irq, struct irq_desc *desc)
98{
99 int i, j;
100 unsigned long status;
101
102 /* read IMIPR registers and find any active interrupts,
103 * then call ISR for each active interrupt
104 */
105 for (i = 0; i < ARRAY_SIZE(read_imipr); i++) {
106 status = (read_imipr[i])();
107 if (!status)
108 continue;
109
110 do {
111 j = find_first_bit(&status, 32);
112 (write_imipr[i])(1 << j); /* write back to clear bit */
113 desc = irq_desc + IRQ_IOP13XX_MSI_0 + j + (32*i);
114 desc_handle_irq(IRQ_IOP13XX_MSI_0 + j + (32*i), desc);
115 status = (read_imipr[i])();
116 } while (status);
117 }
118}
119
120void __init iop13xx_msi_init(void)
121{
122 set_irq_chained_handler(IRQ_IOP13XX_INBD_MSI, iop13xx_msi_handler);
123}
124
125/*
126 * Dynamic irq allocate and deallocation
127 */
128int create_irq(void)
129{
130 int irq, pos;
131
132again:
133 pos = find_first_zero_bit(msi_irq_in_use, IOP13XX_NUM_MSI_IRQS);
134 irq = IRQ_IOP13XX_MSI_0 + pos;
135 if (irq > NR_IRQS)
136 return -ENOSPC;
137 /* test_and_set_bit operates on 32-bits at a time */
138 if (test_and_set_bit(pos, msi_irq_in_use))
139 goto again;
140
141 dynamic_irq_init(irq);
142
143 return irq;
144}
145
146void destroy_irq(unsigned int irq)
147{
148 int pos = irq - IRQ_IOP13XX_MSI_0;
149
150 dynamic_irq_cleanup(irq);
151
152 clear_bit(pos, msi_irq_in_use);
153}
154
155void arch_teardown_msi_irq(unsigned int irq)
156{
157 destroy_irq(irq);
158}
159
160static void iop13xx_msi_nop(unsigned int irq)
161{
162 return;
163}
164
165static struct irq_chip iop13xx_msi_chip = {
166 .name = "PCI-MSI",
167 .ack = iop13xx_msi_nop,
168 .enable = unmask_msi_irq,
169 .disable = mask_msi_irq,
170 .mask = mask_msi_irq,
171 .unmask = unmask_msi_irq,
172};
173
174int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
175{
176 int id, irq = create_irq();
177 struct msi_msg msg;
178
179 if (irq < 0)
180 return irq;
181
182 set_irq_msi(irq, desc);
183
184 msg.address_hi = 0x0;
185 msg.address_lo = IOP13XX_MU_MIMR_PCI;
186
187 id = iop13xx_cpu_id();
188 msg.data = (id << IOP13XX_MU_MIMR_CORE_SELECT) | (irq & 0x7f);
189
190 write_msi_msg(irq, &msg);
191 set_irq_chip_and_handler(irq, &iop13xx_msi_chip, handle_simple_irq);
192
193 return irq;
194}
diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c
index d1d0d32ca77c..1c9e94c38b7e 100644
--- a/arch/arm/mach-iop13xx/pci.c
+++ b/arch/arm/mach-iop13xx/pci.c
@@ -559,6 +559,14 @@ void __init iop13xx_atue_setup(void)
559 int func = iop13xx_atu_function(IOP13XX_INIT_ATU_ATUE); 559 int func = iop13xx_atu_function(IOP13XX_INIT_ATU_ATUE);
560 u32 reg_val; 560 u32 reg_val;
561 561
562#ifdef CONFIG_PCI_MSI
563 /* BAR 0 (inbound msi window) */
564 __raw_writel(IOP13XX_MU_BASE_PHYS, IOP13XX_MU_MUBAR);
565 __raw_writel(~(IOP13XX_MU_WINDOW_SIZE - 1), IOP13XX_ATUE_IALR0);
566 __raw_writel(IOP13XX_MU_BASE_PHYS, IOP13XX_ATUE_IATVR0);
567 __raw_writel(IOP13XX_MU_BASE_PCI, IOP13XX_ATUE_IABAR0);
568#endif
569
562 /* BAR 1 (1:1 mapping with Physical RAM) */ 570 /* BAR 1 (1:1 mapping with Physical RAM) */
563 /* Set limit and enable */ 571 /* Set limit and enable */
564 __raw_writel(~(IOP13XX_MAX_RAM_SIZE - PHYS_OFFSET - 1) & ~0x1, 572 __raw_writel(~(IOP13XX_MAX_RAM_SIZE - PHYS_OFFSET - 1) & ~0x1,
@@ -720,6 +728,14 @@ void __init iop13xx_atux_setup(void)
720 else 728 else
721 atux_trhfa_timeout = jiffies; 729 atux_trhfa_timeout = jiffies;
722 730
731#ifdef CONFIG_PCI_MSI
732 /* BAR 0 (inbound msi window) */
733 __raw_writel(IOP13XX_MU_BASE_PHYS, IOP13XX_MU_MUBAR);
734 __raw_writel(~(IOP13XX_MU_WINDOW_SIZE - 1), IOP13XX_ATUX_IALR0);
735 __raw_writel(IOP13XX_MU_BASE_PHYS, IOP13XX_ATUX_IATVR0);
736 __raw_writel(IOP13XX_MU_BASE_PCI, IOP13XX_ATUX_IABAR0);
737#endif
738
723 /* BAR 1 (1:1 mapping with Physical RAM) */ 739 /* BAR 1 (1:1 mapping with Physical RAM) */
724 /* Set limit and enable */ 740 /* Set limit and enable */
725 __raw_writel(~(IOP13XX_MAX_RAM_SIZE - PHYS_OFFSET - 1) & ~0x1, 741 __raw_writel(~(IOP13XX_MAX_RAM_SIZE - PHYS_OFFSET - 1) & ~0x1,