diff options
| -rw-r--r-- | drivers/pci/msi.c | 46 |
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 | } |
