diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/msi.c | 63 |
1 files changed, 44 insertions, 19 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 88362f1bd9cf..c71e8e4c7168 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -334,13 +334,15 @@ static int msi_capability_init(struct pci_dev *dev) | |||
334 | msi_mask_bits_reg(pos, is_64bit_address(control)), | 334 | msi_mask_bits_reg(pos, is_64bit_address(control)), |
335 | maskbits); | 335 | maskbits); |
336 | } | 336 | } |
337 | list_add(&entry->list, &dev->msi_list); | ||
338 | |||
337 | /* Configure MSI capability structure */ | 339 | /* Configure MSI capability structure */ |
338 | ret = arch_setup_msi_irq(dev, entry); | 340 | ret = arch_setup_msi_irqs(dev, 1, PCI_CAP_ID_MSI); |
339 | if (ret) { | 341 | if (ret) { |
342 | list_del(&entry->list); | ||
340 | kfree(entry); | 343 | kfree(entry); |
341 | return ret; | 344 | return ret; |
342 | } | 345 | } |
343 | list_add(&entry->list, &dev->msi_list); | ||
344 | 346 | ||
345 | /* Set MSI enabled bits */ | 347 | /* Set MSI enabled bits */ |
346 | pci_intx(dev, 0); /* disable intx */ | 348 | pci_intx(dev, 0); /* disable intx */ |
@@ -365,7 +367,7 @@ static int msix_capability_init(struct pci_dev *dev, | |||
365 | struct msix_entry *entries, int nvec) | 367 | struct msix_entry *entries, int nvec) |
366 | { | 368 | { |
367 | struct msi_desc *entry; | 369 | struct msi_desc *entry; |
368 | int irq, pos, i, j, nr_entries, ret; | 370 | int pos, i, j, nr_entries, ret; |
369 | unsigned long phys_addr; | 371 | unsigned long phys_addr; |
370 | u32 table_offset; | 372 | u32 table_offset; |
371 | u16 control; | 373 | u16 control; |
@@ -404,30 +406,33 @@ static int msix_capability_init(struct pci_dev *dev, | |||
404 | entry->dev = dev; | 406 | entry->dev = dev; |
405 | entry->mask_base = base; | 407 | entry->mask_base = base; |
406 | 408 | ||
407 | /* Configure MSI-X capability structure */ | ||
408 | ret = arch_setup_msi_irq(dev, entry); | ||
409 | if (ret) { | ||
410 | kfree(entry); | ||
411 | break; | ||
412 | } | ||
413 | entries[i].vector = entry->irq; | ||
414 | list_add(&entry->list, &dev->msi_list); | 409 | list_add(&entry->list, &dev->msi_list); |
415 | } | 410 | } |
416 | if (i != nvec) { | 411 | |
417 | int avail = i - 1; | 412 | ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX); |
418 | i--; | 413 | if (ret) { |
419 | for (; i >= 0; i--) { | 414 | int avail = 0; |
420 | irq = (entries + i)->vector; | 415 | list_for_each_entry(entry, &dev->msi_list, list) { |
421 | msi_free_irq(dev, irq); | 416 | if (entry->irq != 0) { |
422 | (entries + i)->vector = 0; | 417 | avail++; |
418 | msi_free_irq(dev, entry->irq); | ||
419 | } | ||
423 | } | 420 | } |
421 | |||
424 | /* If we had some success report the number of irqs | 422 | /* If we had some success report the number of irqs |
425 | * we succeeded in setting up. | 423 | * we succeeded in setting up. |
426 | */ | 424 | */ |
427 | if (avail <= 0) | 425 | if (avail == 0) |
428 | avail = -EBUSY; | 426 | avail = ret; |
429 | return avail; | 427 | return avail; |
430 | } | 428 | } |
429 | |||
430 | i = 0; | ||
431 | list_for_each_entry(entry, &dev->msi_list, list) { | ||
432 | entries[i].vector = entry->irq; | ||
433 | set_irq_msi(entry->irq, entry); | ||
434 | i++; | ||
435 | } | ||
431 | /* Set MSI-X enabled bits */ | 436 | /* Set MSI-X enabled bits */ |
432 | pci_intx(dev, 0); /* disable intx */ | 437 | pci_intx(dev, 0); /* disable intx */ |
433 | msix_set_enable(dev, 1); | 438 | msix_set_enable(dev, 1); |
@@ -694,3 +699,23 @@ arch_msi_check_device(struct pci_dev* dev, int nvec, int type) | |||
694 | return 0; | 699 | return 0; |
695 | } | 700 | } |
696 | 701 | ||
702 | int __attribute__ ((weak)) | ||
703 | arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry) | ||
704 | { | ||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | int __attribute__ ((weak)) | ||
709 | arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | ||
710 | { | ||
711 | struct msi_desc *entry; | ||
712 | int ret; | ||
713 | |||
714 | list_for_each_entry(entry, &dev->msi_list, list) { | ||
715 | ret = arch_setup_msi_irq(dev, entry); | ||
716 | if (ret) | ||
717 | return ret; | ||
718 | } | ||
719 | |||
720 | return 0; | ||
721 | } | ||