aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2007-04-05 03:19:12 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-05-02 22:02:37 -0400
commit314e77b3eec57001eaff82b82920150175b74e09 (patch)
tree7446d5c9faaf4bf5dcde576961c68fbe1813c998
parent4aa9bc955d61fdf03b5f9cee67db188fe1ffa8b7 (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.c31
-rw-r--r--include/linux/pci.h1
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}
541EXPORT_SYMBOL(pci_disable_msi); 547EXPORT_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
640void pci_disable_msix(struct pci_dev* dev) 645void 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};