aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc/sysdev/fsl_msi.c
diff options
context:
space:
mode:
authorLi Yang <leoli@freescale.com>2010-04-22 16:31:39 +0800
committerKumar Gala <galak@kernel.crashing.org>2010-05-24 21:26:35 -0500
commit480599933a69a8a8dc1390c2164e49e20a1593b9 (patch)
treecf2b37f439c9e1b06cf17b6cd94559f0bfcdee13 /arch/powerpc/sysdev/fsl_msi.c
parent061ca4adfb2e3c986a182fd30f7e939a1ff8d29d (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.c36
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)