diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-05-09 22:58:24 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-05-09 22:58:24 -0400 |
commit | b48d441a8ab8a89bd32a3a981a05b8a26905dfc7 (patch) | |
tree | 09faed1b557b70f439064d3baaefef91e0ee7334 /arch/powerpc/sysdev | |
parent | a7243c1d09ade57d8d48a350753dc2d1af735805 (diff) | |
parent | dce4c92d69db53ed0e09191428f17ac9a14ad248 (diff) |
Merge remote-tracking branch 'jwb/next' into next
Josh writes:
<<
A few patches from Suzie for 47x kexec/kdump support, and some MSI patches
from Mai La.
>>
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r-- | arch/powerpc/sysdev/ppc4xx_msi.c | 42 |
1 files changed, 28 insertions, 14 deletions
diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c index 1c2d7af17bbe..82c6702dcbab 100644 --- a/arch/powerpc/sysdev/ppc4xx_msi.c +++ b/arch/powerpc/sysdev/ppc4xx_msi.c | |||
@@ -28,10 +28,11 @@ | |||
28 | #include <linux/of_platform.h> | 28 | #include <linux/of_platform.h> |
29 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
30 | #include <linux/export.h> | 30 | #include <linux/export.h> |
31 | #include <linux/kernel.h> | ||
31 | #include <asm/prom.h> | 32 | #include <asm/prom.h> |
32 | #include <asm/hw_irq.h> | 33 | #include <asm/hw_irq.h> |
33 | #include <asm/ppc-pci.h> | 34 | #include <asm/ppc-pci.h> |
34 | #include <boot/dcr.h> | 35 | #include <asm/dcr.h> |
35 | #include <asm/dcr-regs.h> | 36 | #include <asm/dcr-regs.h> |
36 | #include <asm/msi_bitmap.h> | 37 | #include <asm/msi_bitmap.h> |
37 | 38 | ||
@@ -43,13 +44,14 @@ | |||
43 | #define PEIH_FLUSH0 0x30 | 44 | #define PEIH_FLUSH0 0x30 |
44 | #define PEIH_FLUSH1 0x38 | 45 | #define PEIH_FLUSH1 0x38 |
45 | #define PEIH_CNTRST 0x48 | 46 | #define PEIH_CNTRST 0x48 |
46 | #define NR_MSI_IRQS 4 | 47 | |
48 | static int msi_irqs; | ||
47 | 49 | ||
48 | struct ppc4xx_msi { | 50 | struct ppc4xx_msi { |
49 | u32 msi_addr_lo; | 51 | u32 msi_addr_lo; |
50 | u32 msi_addr_hi; | 52 | u32 msi_addr_hi; |
51 | void __iomem *msi_regs; | 53 | void __iomem *msi_regs; |
52 | int msi_virqs[NR_MSI_IRQS]; | 54 | int *msi_virqs; |
53 | struct msi_bitmap bitmap; | 55 | struct msi_bitmap bitmap; |
54 | struct device_node *msi_dev; | 56 | struct device_node *msi_dev; |
55 | }; | 57 | }; |
@@ -61,7 +63,7 @@ static int ppc4xx_msi_init_allocator(struct platform_device *dev, | |||
61 | { | 63 | { |
62 | int err; | 64 | int err; |
63 | 65 | ||
64 | err = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS, | 66 | err = msi_bitmap_alloc(&msi_data->bitmap, msi_irqs, |
65 | dev->dev.of_node); | 67 | dev->dev.of_node); |
66 | if (err) | 68 | if (err) |
67 | return err; | 69 | return err; |
@@ -83,6 +85,11 @@ static int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
83 | struct msi_desc *entry; | 85 | struct msi_desc *entry; |
84 | struct ppc4xx_msi *msi_data = &ppc4xx_msi; | 86 | struct ppc4xx_msi *msi_data = &ppc4xx_msi; |
85 | 87 | ||
88 | msi_data->msi_virqs = kmalloc((msi_irqs) * sizeof(int), | ||
89 | GFP_KERNEL); | ||
90 | if (!msi_data->msi_virqs) | ||
91 | return -ENOMEM; | ||
92 | |||
86 | list_for_each_entry(entry, &dev->msi_list, list) { | 93 | list_for_each_entry(entry, &dev->msi_list, list) { |
87 | int_no = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1); | 94 | int_no = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1); |
88 | if (int_no >= 0) | 95 | if (int_no >= 0) |
@@ -150,12 +157,11 @@ static int ppc4xx_setup_pcieh_hw(struct platform_device *dev, | |||
150 | if (!sdr_addr) | 157 | if (!sdr_addr) |
151 | return -1; | 158 | return -1; |
152 | 159 | ||
153 | SDR0_WRITE(sdr_addr, (u64)res.start >> 32); /*HIGH addr */ | 160 | mtdcri(SDR0, *sdr_addr, upper_32_bits(res.start)); /*HIGH addr */ |
154 | SDR0_WRITE(sdr_addr + 1, res.start & 0xFFFFFFFF); /* Low addr */ | 161 | mtdcri(SDR0, *sdr_addr + 1, lower_32_bits(res.start)); /* Low addr */ |
155 | |||
156 | 162 | ||
157 | msi->msi_dev = of_find_node_by_name(NULL, "ppc4xx-msi"); | 163 | msi->msi_dev = of_find_node_by_name(NULL, "ppc4xx-msi"); |
158 | if (msi->msi_dev) | 164 | if (!msi->msi_dev) |
159 | return -ENODEV; | 165 | return -ENODEV; |
160 | 166 | ||
161 | msi->msi_regs = of_iomap(msi->msi_dev, 0); | 167 | msi->msi_regs = of_iomap(msi->msi_dev, 0); |
@@ -167,9 +173,12 @@ static int ppc4xx_setup_pcieh_hw(struct platform_device *dev, | |||
167 | (u32) (msi->msi_regs + PEIH_TERMADH), (u32) (msi->msi_regs)); | 173 | (u32) (msi->msi_regs + PEIH_TERMADH), (u32) (msi->msi_regs)); |
168 | 174 | ||
169 | msi_virt = dma_alloc_coherent(&dev->dev, 64, &msi_phys, GFP_KERNEL); | 175 | msi_virt = dma_alloc_coherent(&dev->dev, 64, &msi_phys, GFP_KERNEL); |
170 | msi->msi_addr_hi = 0x0; | 176 | if (!msi_virt) |
171 | msi->msi_addr_lo = (u32) msi_phys; | 177 | return -ENOMEM; |
172 | dev_dbg(&dev->dev, "PCIE-MSI: msi address 0x%x\n", msi->msi_addr_lo); | 178 | msi->msi_addr_hi = upper_32_bits(msi_phys); |
179 | msi->msi_addr_lo = lower_32_bits(msi_phys & 0xffffffff); | ||
180 | dev_dbg(&dev->dev, "PCIE-MSI: msi address high 0x%x, low 0x%x\n", | ||
181 | msi->msi_addr_hi, msi->msi_addr_lo); | ||
173 | 182 | ||
174 | /* Progam the Interrupt handler Termination addr registers */ | 183 | /* Progam the Interrupt handler Termination addr registers */ |
175 | out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi); | 184 | out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi); |
@@ -185,6 +194,8 @@ static int ppc4xx_setup_pcieh_hw(struct platform_device *dev, | |||
185 | out_be32(msi->msi_regs + PEIH_MSIED, *msi_data); | 194 | out_be32(msi->msi_regs + PEIH_MSIED, *msi_data); |
186 | out_be32(msi->msi_regs + PEIH_MSIMK, *msi_mask); | 195 | out_be32(msi->msi_regs + PEIH_MSIMK, *msi_mask); |
187 | 196 | ||
197 | dma_free_coherent(&dev->dev, 64, msi_virt, msi_phys); | ||
198 | |||
188 | return 0; | 199 | return 0; |
189 | } | 200 | } |
190 | 201 | ||
@@ -194,7 +205,7 @@ static int ppc4xx_of_msi_remove(struct platform_device *dev) | |||
194 | int i; | 205 | int i; |
195 | int virq; | 206 | int virq; |
196 | 207 | ||
197 | for (i = 0; i < NR_MSI_IRQS; i++) { | 208 | for (i = 0; i < msi_irqs; i++) { |
198 | virq = msi->msi_virqs[i]; | 209 | virq = msi->msi_virqs[i]; |
199 | if (virq != NO_IRQ) | 210 | if (virq != NO_IRQ) |
200 | irq_dispose_mapping(virq); | 211 | irq_dispose_mapping(virq); |
@@ -215,8 +226,6 @@ static int __devinit ppc4xx_msi_probe(struct platform_device *dev) | |||
215 | struct resource res; | 226 | struct resource res; |
216 | int err = 0; | 227 | int err = 0; |
217 | 228 | ||
218 | msi = &ppc4xx_msi;/*keep the msi data for further use*/ | ||
219 | |||
220 | dev_dbg(&dev->dev, "PCIE-MSI: Setting up MSI support...\n"); | 229 | dev_dbg(&dev->dev, "PCIE-MSI: Setting up MSI support...\n"); |
221 | 230 | ||
222 | msi = kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL); | 231 | msi = kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL); |
@@ -234,6 +243,10 @@ static int __devinit ppc4xx_msi_probe(struct platform_device *dev) | |||
234 | goto error_out; | 243 | goto error_out; |
235 | } | 244 | } |
236 | 245 | ||
246 | msi_irqs = of_irq_count(dev->dev.of_node); | ||
247 | if (!msi_irqs) | ||
248 | return -ENODEV; | ||
249 | |||
237 | if (ppc4xx_setup_pcieh_hw(dev, res, msi)) | 250 | if (ppc4xx_setup_pcieh_hw(dev, res, msi)) |
238 | goto error_out; | 251 | goto error_out; |
239 | 252 | ||
@@ -242,6 +255,7 @@ static int __devinit ppc4xx_msi_probe(struct platform_device *dev) | |||
242 | dev_err(&dev->dev, "Error allocating MSI bitmap\n"); | 255 | dev_err(&dev->dev, "Error allocating MSI bitmap\n"); |
243 | goto error_out; | 256 | goto error_out; |
244 | } | 257 | } |
258 | ppc4xx_msi = *msi; | ||
245 | 259 | ||
246 | ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs; | 260 | ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs; |
247 | ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs; | 261 | ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs; |