diff options
| -rw-r--r-- | arch/powerpc/sysdev/fsl_msi.c | 36 | ||||
| -rw-r--r-- | arch/powerpc/sysdev/fsl_msi.h | 1 |
2 files changed, 31 insertions, 6 deletions
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 1ab703915972..f7ca9e6fa5f0 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c | |||
| @@ -250,6 +250,30 @@ unlock: | |||
| 250 | raw_spin_unlock(&desc->lock); | 250 | raw_spin_unlock(&desc->lock); |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | static int fsl_of_msi_remove(struct of_device *ofdev) | ||
| 254 | { | ||
| 255 | struct fsl_msi *msi = ofdev->dev.platform_data; | ||
| 256 | int virq, i; | ||
| 257 | struct fsl_msi_cascade_data *cascade_data; | ||
| 258 | |||
| 259 | if (msi->list.prev != NULL) | ||
| 260 | list_del(&msi->list); | ||
| 261 | for (i = 0; i < NR_MSI_REG; i++) { | ||
| 262 | virq = msi->msi_virqs[i]; | ||
| 263 | if (virq != NO_IRQ) { | ||
| 264 | cascade_data = get_irq_data(virq); | ||
| 265 | kfree(cascade_data); | ||
| 266 | irq_dispose_mapping(virq); | ||
| 267 | } | ||
| 268 | } | ||
| 269 | if (msi->bitmap.bitmap) | ||
| 270 | msi_bitmap_free(&msi->bitmap); | ||
| 271 | iounmap(msi->msi_regs); | ||
| 272 | kfree(msi); | ||
| 273 | |||
| 274 | return 0; | ||
| 275 | } | ||
| 276 | |||
| 253 | static int __devinit fsl_of_msi_probe(struct of_device *dev, | 277 | static int __devinit fsl_of_msi_probe(struct of_device *dev, |
| 254 | const struct of_device_id *match) | 278 | const struct of_device_id *match) |
| 255 | { | 279 | { |
| @@ -269,9 +293,9 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, | |||
| 269 | msi = kzalloc(sizeof(struct fsl_msi), GFP_KERNEL); | 293 | msi = kzalloc(sizeof(struct fsl_msi), GFP_KERNEL); |
| 270 | if (!msi) { | 294 | if (!msi) { |
| 271 | dev_err(&dev->dev, "No memory for MSI structure\n"); | 295 | dev_err(&dev->dev, "No memory for MSI structure\n"); |
| 272 | err = -ENOMEM; | 296 | return -ENOMEM; |
| 273 | goto error_out; | ||
| 274 | } | 297 | } |
| 298 | dev->dev.platform_data = msi; | ||
| 275 | 299 | ||
| 276 | msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR, | 300 | msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR, |
| 277 | NR_MSI_IRQS, &fsl_msi_host_ops, 0); | 301 | NR_MSI_IRQS, &fsl_msi_host_ops, 0); |
| @@ -328,9 +352,7 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, | |||
| 328 | offset = *p / IRQS_PER_MSI_REG; | 352 | offset = *p / IRQS_PER_MSI_REG; |
| 329 | 353 | ||
| 330 | count /= sizeof(u32); | 354 | count /= sizeof(u32); |
| 331 | for (i = 0; i < count / 2; i++) { | 355 | for (i = 0; i < min(count / 2, NR_MSI_REG); i++) { |
| 332 | if (i > NR_MSI_REG) | ||
| 333 | break; | ||
| 334 | virt_msir = irq_of_parse_and_map(dev->node, i); | 356 | virt_msir = irq_of_parse_and_map(dev->node, i); |
| 335 | if (virt_msir != NO_IRQ) { | 357 | if (virt_msir != NO_IRQ) { |
| 336 | cascade_data = kzalloc( | 358 | cascade_data = kzalloc( |
| @@ -342,6 +364,7 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, | |||
| 342 | err = -ENOMEM; | 364 | err = -ENOMEM; |
| 343 | goto error_out; | 365 | goto error_out; |
| 344 | } | 366 | } |
| 367 | msi->msi_virqs[i] = virt_msir; | ||
| 345 | cascade_data->index = i + offset; | 368 | cascade_data->index = i + offset; |
| 346 | cascade_data->msi_data = msi; | 369 | cascade_data->msi_data = msi; |
| 347 | set_irq_data(virt_msir, (void *)cascade_data); | 370 | set_irq_data(virt_msir, (void *)cascade_data); |
| @@ -363,7 +386,7 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, | |||
| 363 | } | 386 | } |
| 364 | return 0; | 387 | return 0; |
| 365 | error_out: | 388 | error_out: |
| 366 | kfree(msi); | 389 | fsl_of_msi_remove(dev); |
| 367 | return err; | 390 | return err; |
| 368 | } | 391 | } |
| 369 | 392 | ||
| @@ -393,6 +416,7 @@ static struct of_platform_driver fsl_of_msi_driver = { | |||
| 393 | .name = "fsl-msi", | 416 | .name = "fsl-msi", |
| 394 | .match_table = fsl_of_msi_ids, | 417 | .match_table = fsl_of_msi_ids, |
| 395 | .probe = fsl_of_msi_probe, | 418 | .probe = fsl_of_msi_probe, |
| 419 | .remove = fsl_of_msi_remove, | ||
| 396 | }; | 420 | }; |
| 397 | 421 | ||
| 398 | static __init int fsl_of_msi_init(void) | 422 | static __init int fsl_of_msi_init(void) |
diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h index 8fc5523d6ee3..624580c252d7 100644 --- a/arch/powerpc/sysdev/fsl_msi.h +++ b/arch/powerpc/sysdev/fsl_msi.h | |||
| @@ -32,6 +32,7 @@ struct fsl_msi { | |||
| 32 | u32 msi_addr_hi; | 32 | u32 msi_addr_hi; |
| 33 | void __iomem *msi_regs; | 33 | void __iomem *msi_regs; |
| 34 | u32 feature; | 34 | u32 feature; |
| 35 | int msi_virqs[NR_MSI_REG]; | ||
| 35 | 36 | ||
| 36 | struct msi_bitmap bitmap; | 37 | struct msi_bitmap bitmap; |
| 37 | 38 | ||
