diff options
author | Li Yang <leoli@freescale.com> | 2010-04-22 16:31:39 +0800 |
---|---|---|
committer | Kumar Gala <galak@kernel.crashing.org> | 2010-05-24 21:26:35 -0500 |
commit | 480599933a69a8a8dc1390c2164e49e20a1593b9 (patch) | |
tree | cf2b37f439c9e1b06cf17b6cd94559f0bfcdee13 /arch/powerpc/sysdev/fsl_msi.c | |
parent | 061ca4adfb2e3c986a182fd30f7e939a1ff8d29d (diff) |
powerpc/fsl_msi: add removal path and probe failing path
Also cleanup the probe function.
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/sysdev/fsl_msi.c')
-rw-r--r-- | arch/powerpc/sysdev/fsl_msi.c | 36 |
1 files changed, 30 insertions, 6 deletions
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 1ab70391597..f7ca9e6fa5f 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -250,6 +250,30 @@ unlock: raw_spin_unlock(&desc->lock); } +static int fsl_of_msi_remove(struct of_device *ofdev) +{ + struct fsl_msi *msi = ofdev->dev.platform_data; + int virq, i; + struct fsl_msi_cascade_data *cascade_data; + + if (msi->list.prev != NULL) + list_del(&msi->list); + for (i = 0; i < NR_MSI_REG; i++) { + virq = msi->msi_virqs[i]; + if (virq != NO_IRQ) { + cascade_data = get_irq_data(virq); + kfree(cascade_data); + irq_dispose_mapping(virq); + } + } + if (msi->bitmap.bitmap) + msi_bitmap_free(&msi->bitmap); + iounmap(msi->msi_regs); + kfree(msi); + + return 0; +} + static int __devinit fsl_of_msi_probe(struct of_device *dev, const struct of_device_id *match) { @@ -269,9 +293,9 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, msi = kzalloc(sizeof(struct fsl_msi), GFP_KERNEL); if (!msi) { dev_err(&dev->dev, "No memory for MSI structure\n"); - err = -ENOMEM; - goto error_out; + return -ENOMEM; } + dev->dev.platform_data = msi; msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR, NR_MSI_IRQS, &fsl_msi_host_ops, 0); @@ -328,9 +352,7 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, offset = *p / IRQS_PER_MSI_REG; count /= sizeof(u32); - for (i = 0; i < count / 2; i++) { - if (i > NR_MSI_REG) - break; + for (i = 0; i < min(count / 2, NR_MSI_REG); i++) { virt_msir = irq_of_parse_and_map(dev->node, i); if (virt_msir != NO_IRQ) { cascade_data = kzalloc( @@ -342,6 +364,7 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, err = -ENOMEM; goto error_out; } + msi->msi_virqs[i] = virt_msir; cascade_data->index = i + offset; cascade_data->msi_data = msi; set_irq_data(virt_msir, (void *)cascade_data); @@ -363,7 +386,7 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, } return 0; error_out: - kfree(msi); + fsl_of_msi_remove(dev); return err; } @@ -393,6 +416,7 @@ static struct of_platform_driver fsl_of_msi_driver = { .name = "fsl-msi", .match_table = fsl_of_msi_ids, .probe = fsl_of_msi_probe, + .remove = fsl_of_msi_remove, }; static __init int fsl_of_msi_init(void) |