aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/msi.c46
1 files changed, 28 insertions, 18 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 79e56906c7f1..944e45e4a84f 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -313,22 +313,22 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
313 313
314 if (!dev->msix_enabled) 314 if (!dev->msix_enabled)
315 return; 315 return;
316 BUG_ON(list_empty(&dev->msi_list));
317 entry = list_entry(dev->msi_list.next, struct msi_desc, list);
318 pos = entry->msi_attrib.pos;
319 pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
316 320
317 /* route the table */ 321 /* route the table */
318 pci_intx_for_msi(dev, 0); 322 pci_intx_for_msi(dev, 0);
319 msix_set_enable(dev, 0); 323 control |= PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL;
324 pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
320 325
321 list_for_each_entry(entry, &dev->msi_list, list) { 326 list_for_each_entry(entry, &dev->msi_list, list) {
322 write_msi_msg(entry->irq, &entry->msg); 327 write_msi_msg(entry->irq, &entry->msg);
323 msix_mask_irq(entry, entry->masked); 328 msix_mask_irq(entry, entry->masked);
324 } 329 }
325 330
326 BUG_ON(list_empty(&dev->msi_list));
327 entry = list_entry(dev->msi_list.next, struct msi_desc, list);
328 pos = entry->msi_attrib.pos;
329 pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
330 control &= ~PCI_MSIX_FLAGS_MASKALL; 331 control &= ~PCI_MSIX_FLAGS_MASKALL;
331 control |= PCI_MSIX_FLAGS_ENABLE;
332 pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); 332 pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
333} 333}
334 334
@@ -419,11 +419,14 @@ static int msix_capability_init(struct pci_dev *dev,
419 u8 bir; 419 u8 bir;
420 void __iomem *base; 420 void __iomem *base;
421 421
422 msix_set_enable(dev, 0);/* Ensure msix is disabled as I set it up */
423
424 pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); 422 pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
423 pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
424
425 /* Ensure MSI-X is disabled while it is set up */
426 control &= ~PCI_MSIX_FLAGS_ENABLE;
427 pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
428
425 /* Request & Map MSI-X table region */ 429 /* Request & Map MSI-X table region */
426 pci_read_config_word(dev, msi_control_reg(pos), &control);
427 nr_entries = multi_msix_capable(control); 430 nr_entries = multi_msix_capable(control);
428 431
429 pci_read_config_dword(dev, msix_table_offset_reg(pos), &table_offset); 432 pci_read_config_dword(dev, msix_table_offset_reg(pos), &table_offset);
@@ -434,7 +437,6 @@ static int msix_capability_init(struct pci_dev *dev,
434 if (base == NULL) 437 if (base == NULL)
435 return -ENOMEM; 438 return -ENOMEM;
436 439
437 /* MSI-X Table Initialization */
438 for (i = 0; i < nvec; i++) { 440 for (i = 0; i < nvec; i++) {
439 entry = alloc_msi_entry(dev); 441 entry = alloc_msi_entry(dev);
440 if (!entry) 442 if (!entry)
@@ -447,7 +449,6 @@ static int msix_capability_init(struct pci_dev *dev,
447 entry->msi_attrib.default_irq = dev->irq; 449 entry->msi_attrib.default_irq = dev->irq;
448 entry->msi_attrib.pos = pos; 450 entry->msi_attrib.pos = pos;
449 entry->mask_base = base; 451 entry->mask_base = base;
450 msix_mask_irq(entry, 1);
451 452
452 list_add_tail(&entry->list, &dev->msi_list); 453 list_add_tail(&entry->list, &dev->msi_list);
453 } 454 }
@@ -472,22 +473,31 @@ static int msix_capability_init(struct pci_dev *dev,
472 return ret; 473 return ret;
473 } 474 }
474 475
476 /*
477 * Some devices require MSI-X to be enabled before we can touch the
478 * MSI-X registers. We need to mask all the vectors to prevent
479 * interrupts coming in before they're fully set up.
480 */
481 control |= PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE;
482 pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
483
475 i = 0; 484 i = 0;
476 list_for_each_entry(entry, &dev->msi_list, list) { 485 list_for_each_entry(entry, &dev->msi_list, list) {
477 entries[i].vector = entry->irq; 486 entries[i].vector = entry->irq;
478 set_irq_msi(entry->irq, entry); 487 set_irq_msi(entry->irq, entry);
488 j = entries[i].entry;
489 entry->masked = readl(base + j * PCI_MSIX_ENTRY_SIZE +
490 PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
491 msix_mask_irq(entry, 1);
479 i++; 492 i++;
480 } 493 }
481 /* Set MSI-X enabled bits */ 494
495 /* Set MSI-X enabled bits and unmask the function */
482 pci_intx_for_msi(dev, 0); 496 pci_intx_for_msi(dev, 0);
483 msix_set_enable(dev, 1);
484 dev->msix_enabled = 1; 497 dev->msix_enabled = 1;
485 498
486 list_for_each_entry(entry, &dev->msi_list, list) { 499 control &= ~PCI_MSIX_FLAGS_MASKALL;
487 int vector = entry->msi_attrib.entry_nr; 500 pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
488 entry->masked = readl(base + vector * PCI_MSIX_ENTRY_SIZE +
489 PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
490 }
491 501
492 return 0; 502 return 0;
493} 503}