diff options
author | Michael Ellerman <michael@ellerman.id.au> | 2007-04-05 03:19:12 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-05-02 22:02:37 -0400 |
commit | 314e77b3eec57001eaff82b82920150175b74e09 (patch) | |
tree | 7446d5c9faaf4bf5dcde576961c68fbe1813c998 | |
parent | 4aa9bc955d61fdf03b5f9cee67db188fe1ffa8b7 (diff) |
MSI: Remove dev->first_msi_irq
Now that we keep a list of msi descriptors, we don't need first_msi_irq
in the pci dev.
If we somehow have zero MSIs configured list_entry() will give us weird
oopes or nice memory corruption bugs. So be paranoid. Add BUG_ONs and also
a check in pci_msi_check_device() to make sure nvec > 0.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/pci/msi.c | 31 | ||||
-rw-r--r-- | include/linux/pci.h | 1 |
2 files changed, 20 insertions, 12 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 434c7182d926..7a44ba467481 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -269,7 +269,8 @@ static void __pci_restore_msix_state(struct pci_dev *dev) | |||
269 | msi_set_mask_bit(entry->irq, entry->msi_attrib.masked); | 269 | msi_set_mask_bit(entry->irq, entry->msi_attrib.masked); |
270 | } | 270 | } |
271 | 271 | ||
272 | entry = get_irq_msi(dev->first_msi_irq); | 272 | BUG_ON(list_empty(&dev->msi_list)); |
273 | entry = list_entry(dev->msi_list.next, struct msi_desc, list); | ||
273 | pos = entry->msi_attrib.pos; | 274 | pos = entry->msi_attrib.pos; |
274 | pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); | 275 | pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); |
275 | control &= ~PCI_MSIX_FLAGS_MASKALL; | 276 | control &= ~PCI_MSIX_FLAGS_MASKALL; |
@@ -341,7 +342,6 @@ static int msi_capability_init(struct pci_dev *dev) | |||
341 | } | 342 | } |
342 | entry->irq = irq; | 343 | entry->irq = irq; |
343 | list_add(&entry->list, &dev->msi_list); | 344 | list_add(&entry->list, &dev->msi_list); |
344 | dev->first_msi_irq = irq; | ||
345 | set_irq_msi(irq, entry); | 345 | set_irq_msi(irq, entry); |
346 | 346 | ||
347 | /* Set MSI enabled bits */ | 347 | /* Set MSI enabled bits */ |
@@ -433,7 +433,6 @@ static int msix_capability_init(struct pci_dev *dev, | |||
433 | avail = -EBUSY; | 433 | avail = -EBUSY; |
434 | return avail; | 434 | return avail; |
435 | } | 435 | } |
436 | dev->first_msi_irq = entries[0].vector; | ||
437 | /* Set MSI-X enabled bits */ | 436 | /* Set MSI-X enabled bits */ |
438 | pci_intx(dev, 0); /* disable intx */ | 437 | pci_intx(dev, 0); /* disable intx */ |
439 | msix_set_enable(dev, 1); | 438 | msix_set_enable(dev, 1); |
@@ -461,6 +460,14 @@ static int pci_msi_check_device(struct pci_dev* dev, int nvec, int type) | |||
461 | if (!pci_msi_enable || !dev || dev->no_msi) | 460 | if (!pci_msi_enable || !dev || dev->no_msi) |
462 | return -EINVAL; | 461 | return -EINVAL; |
463 | 462 | ||
463 | /* | ||
464 | * You can't ask to have 0 or less MSIs configured. | ||
465 | * a) it's stupid .. | ||
466 | * b) the list manipulation code assumes nvec >= 1. | ||
467 | */ | ||
468 | if (nvec < 1) | ||
469 | return -ERANGE; | ||
470 | |||
464 | /* Any bridge which does NOT route MSI transactions from it's | 471 | /* Any bridge which does NOT route MSI transactions from it's |
465 | * secondary bus to it's primary bus must set NO_MSI flag on | 472 | * secondary bus to it's primary bus must set NO_MSI flag on |
466 | * the secondary pci_bus. | 473 | * the secondary pci_bus. |
@@ -525,18 +532,17 @@ void pci_disable_msi(struct pci_dev* dev) | |||
525 | pci_intx(dev, 1); /* enable intx */ | 532 | pci_intx(dev, 1); /* enable intx */ |
526 | dev->msi_enabled = 0; | 533 | dev->msi_enabled = 0; |
527 | 534 | ||
528 | entry = get_irq_msi(dev->first_msi_irq); | 535 | BUG_ON(list_empty(&dev->msi_list)); |
529 | if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { | 536 | entry = list_entry(dev->msi_list.next, struct msi_desc, list); |
537 | if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { | ||
530 | return; | 538 | return; |
531 | } | 539 | } |
532 | 540 | ||
533 | default_irq = entry->msi_attrib.default_irq; | 541 | default_irq = entry->msi_attrib.default_irq; |
534 | msi_free_irq(dev, dev->first_msi_irq); | 542 | msi_free_irq(dev, entry->irq); |
535 | 543 | ||
536 | /* Restore dev->irq to its default pin-assertion irq */ | 544 | /* Restore dev->irq to its default pin-assertion irq */ |
537 | dev->irq = default_irq; | 545 | dev->irq = default_irq; |
538 | |||
539 | dev->first_msi_irq = 0; | ||
540 | } | 546 | } |
541 | EXPORT_SYMBOL(pci_disable_msi); | 547 | EXPORT_SYMBOL(pci_disable_msi); |
542 | 548 | ||
@@ -634,7 +640,6 @@ static void msix_free_all_irqs(struct pci_dev *dev) | |||
634 | 640 | ||
635 | list_for_each_entry(entry, &dev->msi_list, list) | 641 | list_for_each_entry(entry, &dev->msi_list, list) |
636 | msi_free_irq(dev, entry->irq); | 642 | msi_free_irq(dev, entry->irq); |
637 | dev->first_msi_irq = 0; | ||
638 | } | 643 | } |
639 | 644 | ||
640 | void pci_disable_msix(struct pci_dev* dev) | 645 | void pci_disable_msix(struct pci_dev* dev) |
@@ -664,8 +669,12 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev) | |||
664 | if (!pci_msi_enable || !dev) | 669 | if (!pci_msi_enable || !dev) |
665 | return; | 670 | return; |
666 | 671 | ||
667 | if (dev->msi_enabled) | 672 | if (dev->msi_enabled) { |
668 | msi_free_irq(dev, dev->first_msi_irq); | 673 | struct msi_desc *entry; |
674 | BUG_ON(list_empty(&dev->msi_list)); | ||
675 | entry = list_entry(dev->msi_list.next, struct msi_desc, list); | ||
676 | msi_free_irq(dev, entry->irq); | ||
677 | } | ||
669 | 678 | ||
670 | if (dev->msix_enabled) | 679 | if (dev->msix_enabled) |
671 | msix_free_all_irqs(dev); | 680 | msix_free_all_irqs(dev); |
diff --git a/include/linux/pci.h b/include/linux/pci.h index d43097dc8672..a15569bf78b5 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -189,7 +189,6 @@ struct pci_dev { | |||
189 | int rom_attr_enabled; /* has display of the rom attribute been enabled? */ | 189 | int rom_attr_enabled; /* has display of the rom attribute been enabled? */ |
190 | struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ | 190 | struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ |
191 | #ifdef CONFIG_PCI_MSI | 191 | #ifdef CONFIG_PCI_MSI |
192 | unsigned int first_msi_irq; | ||
193 | struct list_head msi_list; | 192 | struct list_head msi_list; |
194 | #endif | 193 | #endif |
195 | }; | 194 | }; |