aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2007-04-18 05:39:21 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-05-02 22:02:38 -0400
commit9c8313343c83c0ca731ceb8d2a4ab1e022ed9c94 (patch)
tree1e37ef3ebcdcb344adb74c1667ad04cf87010f5e
parent7fe3730de729b758e9f69b862b9255d998671b5f (diff)
MSI: Give archs the option to allocate all MSI/Xs at once.
This patch introduces an optional function, arch_setup_msi_irqs(), (note the plural) which gives an arch the opportunity to do per-device setup for MSI/X and then allocate all the requested MSI/Xs at once. If that's not required by the arch, the default version simply calls arch_setup_msi_irq() for each MSI irq required. arch_setup_msi_irqs() is passed a pdev, attached to the pdev is a list of msi_descs with irq == 0, it is up to the arch to connect these up to an irq (via set_irq_msi()) or return an error. For convenience the number of vectors and the type are passed also. All msi_descs with irq != 0 are considered allocated, and the arch teardown routine will be called on them when necessary. The existing semantics of pci_enable_msix() are that if the requested number of irqs can not be allocated, the maximum number that _could_ be allocated is returned. To support that, we define that in case of an error from arch_setup_msi_irqs(), the number of msi_descs with irq != 0 are considered allocated, and are counted toward the "max that could be allocated". Signed-off-by: Michael Ellerman <michael@ellerman.id.au> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/pci/msi.c63
-rw-r--r--include/linux/msi.h1
2 files changed, 45 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
702int __attribute__ ((weak))
703arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry)
704{
705 return 0;
706}
707
708int __attribute__ ((weak))
709arch_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}
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 931e013f1db5..494627ae021f 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -41,6 +41,7 @@ struct msi_desc {
41 */ 41 */
42int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc); 42int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc);
43void arch_teardown_msi_irq(unsigned int irq); 43void arch_teardown_msi_irq(unsigned int irq);
44extern int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
44extern int arch_msi_check_device(struct pci_dev* dev, int nvec, int type); 45extern int arch_msi_check_device(struct pci_dev* dev, int nvec, int type);
45 46
46 47