aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimur Tabi <timur@freescale.com>2011-12-13 15:51:59 -0500
committerKumar Gala <galak@kernel.crashing.org>2012-01-04 16:47:44 -0500
commit446bc1ffe4f2cac228909fe0ac48884d12700d81 (patch)
treeebc83802cd7f4c140159384c2b7e6e492080891f
parentc6ca52ad32cb9a4b9b331a60966ffa4d00ce3f37 (diff)
powerpc/fsl: add MSI support for the Freescale hypervisor
Add support for vmpic-msi nodes to the fsl_msi driver. The MSI is virtualized by the hypervisor, so the vmpic-msi does not contain a 'reg' property. Instead, the driver uses hcalls. Add support for the "msi-address-64" property to the fsl_pci driver. The Freescale hypervisor typically puts the virtualized MSIIR register in the page after the end of DDR, so we extend the DDR ATMU to cover it. Any other location for MSIIR is not supported, for now. Signed-off-by: Timur Tabi <timur@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c68
-rw-r--r--arch/powerpc/sysdev/fsl_msi.h7
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c29
3 files changed, 81 insertions, 23 deletions
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index 89548e07ddeb..ecb5c1946d22 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -23,6 +23,8 @@
23#include <asm/hw_irq.h> 23#include <asm/hw_irq.h>
24#include <asm/ppc-pci.h> 24#include <asm/ppc-pci.h>
25#include <asm/mpic.h> 25#include <asm/mpic.h>
26#include <asm/fsl_hcalls.h>
27
26#include "fsl_msi.h" 28#include "fsl_msi.h"
27#include "fsl_pci.h" 29#include "fsl_pci.h"
28 30
@@ -163,11 +165,13 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
163 */ 165 */
164 np = of_parse_phandle(hose->dn, "fsl,msi", 0); 166 np = of_parse_phandle(hose->dn, "fsl,msi", 0);
165 if (np) { 167 if (np) {
166 if (of_device_is_compatible(np, "fsl,mpic-msi")) 168 if (of_device_is_compatible(np, "fsl,mpic-msi") ||
169 of_device_is_compatible(np, "fsl,vmpic-msi"))
167 phandle = np->phandle; 170 phandle = np->phandle;
168 else { 171 else {
169 dev_err(&pdev->dev, "node %s has an invalid fsl,msi" 172 dev_err(&pdev->dev,
170 " phandle\n", hose->dn->full_name); 173 "node %s has an invalid fsl,msi phandle %u\n",
174 hose->dn->full_name, np->phandle);
171 return -EINVAL; 175 return -EINVAL;
172 } 176 }
173 } 177 }
@@ -196,16 +200,14 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
196 200
197 if (hwirq < 0) { 201 if (hwirq < 0) {
198 rc = hwirq; 202 rc = hwirq;
199 pr_debug("%s: fail allocating msi interrupt\n", 203 dev_err(&pdev->dev, "could not allocate MSI interrupt\n");
200 __func__);
201 goto out_free; 204 goto out_free;
202 } 205 }
203 206
204 virq = irq_create_mapping(msi_data->irqhost, hwirq); 207 virq = irq_create_mapping(msi_data->irqhost, hwirq);
205 208
206 if (virq == NO_IRQ) { 209 if (virq == NO_IRQ) {
207 pr_debug("%s: fail mapping hwirq 0x%x\n", 210 dev_err(&pdev->dev, "fail mapping hwirq %i\n", hwirq);
208 __func__, hwirq);
209 msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1); 211 msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1);
210 rc = -ENOSPC; 212 rc = -ENOSPC;
211 goto out_free; 213 goto out_free;
@@ -234,6 +236,7 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
234 u32 intr_index; 236 u32 intr_index;
235 u32 have_shift = 0; 237 u32 have_shift = 0;
236 struct fsl_msi_cascade_data *cascade_data; 238 struct fsl_msi_cascade_data *cascade_data;
239 unsigned int ret;
237 240
238 cascade_data = irq_get_handler_data(irq); 241 cascade_data = irq_get_handler_data(irq);
239 msi_data = cascade_data->msi_data; 242 msi_data = cascade_data->msi_data;
@@ -265,6 +268,14 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
265 case FSL_PIC_IP_IPIC: 268 case FSL_PIC_IP_IPIC:
266 msir_value = fsl_msi_read(msi_data->msi_regs, msir_index * 0x4); 269 msir_value = fsl_msi_read(msi_data->msi_regs, msir_index * 0x4);
267 break; 270 break;
271 case FSL_PIC_IP_VMPIC:
272 ret = fh_vmpic_get_msir(virq_to_hw(irq), &msir_value);
273 if (ret) {
274 pr_err("fsl-msi: fh_vmpic_get_msir() failed for "
275 "irq %u (ret=%u)\n", irq, ret);
276 msir_value = 0;
277 }
278 break;
268 } 279 }
269 280
270 while (msir_value) { 281 while (msir_value) {
@@ -282,6 +293,7 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
282 293
283 switch (msi_data->feature & FSL_PIC_IP_MASK) { 294 switch (msi_data->feature & FSL_PIC_IP_MASK) {
284 case FSL_PIC_IP_MPIC: 295 case FSL_PIC_IP_MPIC:
296 case FSL_PIC_IP_VMPIC:
285 chip->irq_eoi(idata); 297 chip->irq_eoi(idata);
286 break; 298 break;
287 case FSL_PIC_IP_IPIC: 299 case FSL_PIC_IP_IPIC:
@@ -311,7 +323,8 @@ static int fsl_of_msi_remove(struct platform_device *ofdev)
311 } 323 }
312 if (msi->bitmap.bitmap) 324 if (msi->bitmap.bitmap)
313 msi_bitmap_free(&msi->bitmap); 325 msi_bitmap_free(&msi->bitmap);
314 iounmap(msi->msi_regs); 326 if ((msi->feature & FSL_PIC_IP_MASK) != FSL_PIC_IP_VMPIC)
327 iounmap(msi->msi_regs);
315 kfree(msi); 328 kfree(msi);
316 329
317 return 0; 330 return 0;
@@ -383,26 +396,32 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)
383 goto error_out; 396 goto error_out;
384 } 397 }
385 398
386 /* Get the MSI reg base */ 399 /*
387 err = of_address_to_resource(dev->dev.of_node, 0, &res); 400 * Under the Freescale hypervisor, the msi nodes don't have a 'reg'
388 if (err) { 401 * property. Instead, we use hypercalls to access the MSI.
389 dev_err(&dev->dev, "%s resource error!\n", 402 */
403 if ((features->fsl_pic_ip & FSL_PIC_IP_MASK) != FSL_PIC_IP_VMPIC) {
404 err = of_address_to_resource(dev->dev.of_node, 0, &res);
405 if (err) {
406 dev_err(&dev->dev, "invalid resource for node %s\n",
390 dev->dev.of_node->full_name); 407 dev->dev.of_node->full_name);
391 goto error_out; 408 goto error_out;
392 } 409 }
393 410
394 msi->msi_regs = ioremap(res.start, resource_size(&res)); 411 msi->msi_regs = ioremap(res.start, resource_size(&res));
395 if (!msi->msi_regs) { 412 if (!msi->msi_regs) {
396 dev_err(&dev->dev, "ioremap problem failed\n"); 413 dev_err(&dev->dev, "could not map node %s\n",
397 goto error_out; 414 dev->dev.of_node->full_name);
415 goto error_out;
416 }
417 msi->msiir_offset =
418 features->msiir_offset + (res.start & 0xfffff);
398 } 419 }
399 420
400 msi->feature = features->fsl_pic_ip; 421 msi->feature = features->fsl_pic_ip;
401 422
402 msi->irqhost->host_data = msi; 423 msi->irqhost->host_data = msi;
403 424
404 msi->msiir_offset = features->msiir_offset + (res.start & 0xfffff);
405
406 /* 425 /*
407 * Remember the phandle, so that we can match with any PCI nodes 426 * Remember the phandle, so that we can match with any PCI nodes
408 * that have an "fsl,msi" property. 427 * that have an "fsl,msi" property.
@@ -476,6 +495,11 @@ static const struct fsl_msi_feature ipic_msi_feature = {
476 .msiir_offset = 0x38, 495 .msiir_offset = 0x38,
477}; 496};
478 497
498static const struct fsl_msi_feature vmpic_msi_feature = {
499 .fsl_pic_ip = FSL_PIC_IP_VMPIC,
500 .msiir_offset = 0,
501};
502
479static const struct of_device_id fsl_of_msi_ids[] = { 503static const struct of_device_id fsl_of_msi_ids[] = {
480 { 504 {
481 .compatible = "fsl,mpic-msi", 505 .compatible = "fsl,mpic-msi",
@@ -485,6 +509,10 @@ static const struct of_device_id fsl_of_msi_ids[] = {
485 .compatible = "fsl,ipic-msi", 509 .compatible = "fsl,ipic-msi",
486 .data = (void *)&ipic_msi_feature, 510 .data = (void *)&ipic_msi_feature,
487 }, 511 },
512 {
513 .compatible = "fsl,vmpic-msi",
514 .data = (void *)&vmpic_msi_feature,
515 },
488 {} 516 {}
489}; 517};
490 518
diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h
index b5d25ba51311..f6c646a52541 100644
--- a/arch/powerpc/sysdev/fsl_msi.h
+++ b/arch/powerpc/sysdev/fsl_msi.h
@@ -20,9 +20,10 @@
20#define IRQS_PER_MSI_REG 32 20#define IRQS_PER_MSI_REG 32
21#define NR_MSI_IRQS (NR_MSI_REG * IRQS_PER_MSI_REG) 21#define NR_MSI_IRQS (NR_MSI_REG * IRQS_PER_MSI_REG)
22 22
23#define FSL_PIC_IP_MASK 0x0000000F 23#define FSL_PIC_IP_MASK 0x0000000F
24#define FSL_PIC_IP_MPIC 0x00000001 24#define FSL_PIC_IP_MPIC 0x00000001
25#define FSL_PIC_IP_IPIC 0x00000002 25#define FSL_PIC_IP_IPIC 0x00000002
26#define FSL_PIC_IP_VMPIC 0x00000003
26 27
27struct fsl_msi { 28struct fsl_msi {
28 struct irq_host *irqhost; 29 struct irq_host *irqhost;
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 8f92446ff0ae..3b61e8cf3421 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -137,6 +137,8 @@ static void __init setup_pci_atmu(struct pci_controller *hose,
137 u32 piwar = PIWAR_EN | PIWAR_PF | PIWAR_TGI_LOCAL | 137 u32 piwar = PIWAR_EN | PIWAR_PF | PIWAR_TGI_LOCAL |
138 PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP; 138 PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
139 char *name = hose->dn->full_name; 139 char *name = hose->dn->full_name;
140 const u64 *reg;
141 int len;
140 142
141 pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n", 143 pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n",
142 (u64)rsrc->start, (u64)resource_size(rsrc)); 144 (u64)rsrc->start, (u64)resource_size(rsrc));
@@ -229,6 +231,33 @@ static void __init setup_pci_atmu(struct pci_controller *hose,
229 231
230 /* Setup inbound mem window */ 232 /* Setup inbound mem window */
231 mem = memblock_end_of_DRAM(); 233 mem = memblock_end_of_DRAM();
234
235 /*
236 * The msi-address-64 property, if it exists, indicates the physical
237 * address of the MSIIR register. Normally, this register is located
238 * inside CCSR, so the ATMU that covers all of CCSR is used. But if
239 * this property exists, then we normally need to create a new ATMU
240 * for it. For now, however, we cheat. The only entity that creates
241 * this property is the Freescale hypervisor, and the address is
242 * specified in the partition configuration. Typically, the address
243 * is located in the page immediately after the end of DDR. If so, we
244 * can avoid allocating a new ATMU by extending the DDR ATMU by one
245 * page.
246 */
247 reg = of_get_property(hose->dn, "msi-address-64", &len);
248 if (reg && (len == sizeof(u64))) {
249 u64 address = be64_to_cpup(reg);
250
251 if ((address >= mem) && (address < (mem + PAGE_SIZE))) {
252 pr_info("%s: extending DDR ATMU to cover MSIIR", name);
253 mem += PAGE_SIZE;
254 } else {
255 /* TODO: Create a new ATMU for MSIIR */
256 pr_warn("%s: msi-address-64 address of %llx is "
257 "unsupported\n", name, address);
258 }
259 }
260
232 sz = min(mem, paddr_lo); 261 sz = min(mem, paddr_lo);
233 mem_log = __ilog2_u64(sz); 262 mem_log = __ilog2_u64(sz);
234 263