diff options
Diffstat (limited to 'drivers/pci/msi.c')
-rw-r--r-- | drivers/pci/msi.c | 100 |
1 files changed, 51 insertions, 49 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 362773247fbf..d9f06fbfa0bf 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -75,22 +75,17 @@ void arch_teardown_msi_irqs(struct pci_dev *dev) | |||
75 | } | 75 | } |
76 | #endif | 76 | #endif |
77 | 77 | ||
78 | static void __msi_set_enable(struct pci_dev *dev, int pos, int enable) | 78 | static void msi_set_enable(struct pci_dev *dev, int pos, int enable) |
79 | { | 79 | { |
80 | u16 control; | 80 | u16 control; |
81 | 81 | ||
82 | if (pos) { | 82 | BUG_ON(!pos); |
83 | pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); | ||
84 | control &= ~PCI_MSI_FLAGS_ENABLE; | ||
85 | if (enable) | ||
86 | control |= PCI_MSI_FLAGS_ENABLE; | ||
87 | pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); | ||
88 | } | ||
89 | } | ||
90 | 83 | ||
91 | static void msi_set_enable(struct pci_dev *dev, int enable) | 84 | pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); |
92 | { | 85 | control &= ~PCI_MSI_FLAGS_ENABLE; |
93 | __msi_set_enable(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), enable); | 86 | if (enable) |
87 | control |= PCI_MSI_FLAGS_ENABLE; | ||
88 | pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); | ||
94 | } | 89 | } |
95 | 90 | ||
96 | static void msix_set_enable(struct pci_dev *dev, int enable) | 91 | static void msix_set_enable(struct pci_dev *dev, int enable) |
@@ -131,9 +126,6 @@ static inline __attribute_const__ u32 msi_enabled_mask(u16 control) | |||
131 | * mask all MSI interrupts by clearing the MSI enable bit does not work | 126 | * mask all MSI interrupts by clearing the MSI enable bit does not work |
132 | * reliably as devices without an INTx disable bit will then generate a | 127 | * reliably as devices without an INTx disable bit will then generate a |
133 | * level IRQ which will never be cleared. | 128 | * level IRQ which will never be cleared. |
134 | * | ||
135 | * Returns 1 if it succeeded in masking the interrupt and 0 if the device | ||
136 | * doesn't support MSI masking. | ||
137 | */ | 129 | */ |
138 | static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) | 130 | static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) |
139 | { | 131 | { |
@@ -303,7 +295,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev) | |||
303 | pos = entry->msi_attrib.pos; | 295 | pos = entry->msi_attrib.pos; |
304 | 296 | ||
305 | pci_intx_for_msi(dev, 0); | 297 | pci_intx_for_msi(dev, 0); |
306 | msi_set_enable(dev, 0); | 298 | msi_set_enable(dev, pos, 0); |
307 | write_msi_msg(dev->irq, &entry->msg); | 299 | write_msi_msg(dev->irq, &entry->msg); |
308 | 300 | ||
309 | pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); | 301 | pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); |
@@ -321,22 +313,22 @@ static void __pci_restore_msix_state(struct pci_dev *dev) | |||
321 | 313 | ||
322 | if (!dev->msix_enabled) | 314 | if (!dev->msix_enabled) |
323 | 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); | ||
324 | 320 | ||
325 | /* route the table */ | 321 | /* route the table */ |
326 | pci_intx_for_msi(dev, 0); | 322 | pci_intx_for_msi(dev, 0); |
327 | 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); | ||
328 | 325 | ||
329 | list_for_each_entry(entry, &dev->msi_list, list) { | 326 | list_for_each_entry(entry, &dev->msi_list, list) { |
330 | write_msi_msg(entry->irq, &entry->msg); | 327 | write_msi_msg(entry->irq, &entry->msg); |
331 | msix_mask_irq(entry, entry->masked); | 328 | msix_mask_irq(entry, entry->masked); |
332 | } | 329 | } |
333 | 330 | ||
334 | BUG_ON(list_empty(&dev->msi_list)); | ||
335 | entry = list_entry(dev->msi_list.next, struct msi_desc, list); | ||
336 | pos = entry->msi_attrib.pos; | ||
337 | pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); | ||
338 | control &= ~PCI_MSIX_FLAGS_MASKALL; | 331 | control &= ~PCI_MSIX_FLAGS_MASKALL; |
339 | control |= PCI_MSIX_FLAGS_ENABLE; | ||
340 | pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); | 332 | pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); |
341 | } | 333 | } |
342 | 334 | ||
@@ -365,9 +357,9 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) | |||
365 | u16 control; | 357 | u16 control; |
366 | unsigned mask; | 358 | unsigned mask; |
367 | 359 | ||
368 | msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */ | ||
369 | |||
370 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | 360 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); |
361 | msi_set_enable(dev, pos, 0); /* Disable MSI during set up */ | ||
362 | |||
371 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 363 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
372 | /* MSI Entry Initialization */ | 364 | /* MSI Entry Initialization */ |
373 | entry = alloc_msi_entry(dev); | 365 | entry = alloc_msi_entry(dev); |
@@ -381,7 +373,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) | |||
381 | entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ | 373 | entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ |
382 | entry->msi_attrib.pos = pos; | 374 | entry->msi_attrib.pos = pos; |
383 | 375 | ||
384 | entry->mask_pos = msi_mask_bits_reg(pos, entry->msi_attrib.is_64); | 376 | entry->mask_pos = msi_mask_reg(pos, entry->msi_attrib.is_64); |
385 | /* All MSIs are unmasked by default, Mask them all */ | 377 | /* All MSIs are unmasked by default, Mask them all */ |
386 | if (entry->msi_attrib.maskbit) | 378 | if (entry->msi_attrib.maskbit) |
387 | pci_read_config_dword(dev, entry->mask_pos, &entry->masked); | 379 | pci_read_config_dword(dev, entry->mask_pos, &entry->masked); |
@@ -399,7 +391,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) | |||
399 | 391 | ||
400 | /* Set MSI enabled bits */ | 392 | /* Set MSI enabled bits */ |
401 | pci_intx_for_msi(dev, 0); | 393 | pci_intx_for_msi(dev, 0); |
402 | msi_set_enable(dev, 1); | 394 | msi_set_enable(dev, pos, 1); |
403 | dev->msi_enabled = 1; | 395 | dev->msi_enabled = 1; |
404 | 396 | ||
405 | dev->irq = entry->irq; | 397 | dev->irq = entry->irq; |
@@ -427,11 +419,14 @@ static int msix_capability_init(struct pci_dev *dev, | |||
427 | u8 bir; | 419 | u8 bir; |
428 | void __iomem *base; | 420 | void __iomem *base; |
429 | 421 | ||
430 | msix_set_enable(dev, 0);/* Ensure msix is disabled as I set it up */ | ||
431 | |||
432 | 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 | |||
433 | /* Request & Map MSI-X table region */ | 429 | /* Request & Map MSI-X table region */ |
434 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
435 | nr_entries = multi_msix_capable(control); | 430 | nr_entries = multi_msix_capable(control); |
436 | 431 | ||
437 | 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); |
@@ -442,7 +437,6 @@ static int msix_capability_init(struct pci_dev *dev, | |||
442 | if (base == NULL) | 437 | if (base == NULL) |
443 | return -ENOMEM; | 438 | return -ENOMEM; |
444 | 439 | ||
445 | /* MSI-X Table Initialization */ | ||
446 | for (i = 0; i < nvec; i++) { | 440 | for (i = 0; i < nvec; i++) { |
447 | entry = alloc_msi_entry(dev); | 441 | entry = alloc_msi_entry(dev); |
448 | if (!entry) | 442 | if (!entry) |
@@ -455,7 +449,6 @@ static int msix_capability_init(struct pci_dev *dev, | |||
455 | entry->msi_attrib.default_irq = dev->irq; | 449 | entry->msi_attrib.default_irq = dev->irq; |
456 | entry->msi_attrib.pos = pos; | 450 | entry->msi_attrib.pos = pos; |
457 | entry->mask_base = base; | 451 | entry->mask_base = base; |
458 | msix_mask_irq(entry, 1); | ||
459 | 452 | ||
460 | list_add_tail(&entry->list, &dev->msi_list); | 453 | list_add_tail(&entry->list, &dev->msi_list); |
461 | } | 454 | } |
@@ -480,22 +473,31 @@ static int msix_capability_init(struct pci_dev *dev, | |||
480 | return ret; | 473 | return ret; |
481 | } | 474 | } |
482 | 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 | |||
483 | i = 0; | 484 | i = 0; |
484 | list_for_each_entry(entry, &dev->msi_list, list) { | 485 | list_for_each_entry(entry, &dev->msi_list, list) { |
485 | entries[i].vector = entry->irq; | 486 | entries[i].vector = entry->irq; |
486 | 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); | ||
487 | i++; | 492 | i++; |
488 | } | 493 | } |
489 | /* Set MSI-X enabled bits */ | 494 | |
495 | /* Set MSI-X enabled bits and unmask the function */ | ||
490 | pci_intx_for_msi(dev, 0); | 496 | pci_intx_for_msi(dev, 0); |
491 | msix_set_enable(dev, 1); | ||
492 | dev->msix_enabled = 1; | 497 | dev->msix_enabled = 1; |
493 | 498 | ||
494 | list_for_each_entry(entry, &dev->msi_list, list) { | 499 | control &= ~PCI_MSIX_FLAGS_MASKALL; |
495 | int vector = entry->msi_attrib.entry_nr; | 500 | pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); |
496 | entry->masked = readl(base + vector * PCI_MSIX_ENTRY_SIZE + | ||
497 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); | ||
498 | } | ||
499 | 501 | ||
500 | return 0; | 502 | return 0; |
501 | } | 503 | } |
@@ -596,17 +598,20 @@ void pci_msi_shutdown(struct pci_dev *dev) | |||
596 | struct msi_desc *desc; | 598 | struct msi_desc *desc; |
597 | u32 mask; | 599 | u32 mask; |
598 | u16 ctrl; | 600 | u16 ctrl; |
601 | unsigned pos; | ||
599 | 602 | ||
600 | if (!pci_msi_enable || !dev || !dev->msi_enabled) | 603 | if (!pci_msi_enable || !dev || !dev->msi_enabled) |
601 | return; | 604 | return; |
602 | 605 | ||
603 | msi_set_enable(dev, 0); | 606 | BUG_ON(list_empty(&dev->msi_list)); |
607 | desc = list_first_entry(&dev->msi_list, struct msi_desc, list); | ||
608 | pos = desc->msi_attrib.pos; | ||
609 | |||
610 | msi_set_enable(dev, pos, 0); | ||
604 | pci_intx_for_msi(dev, 1); | 611 | pci_intx_for_msi(dev, 1); |
605 | dev->msi_enabled = 0; | 612 | dev->msi_enabled = 0; |
606 | 613 | ||
607 | BUG_ON(list_empty(&dev->msi_list)); | 614 | pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &ctrl); |
608 | desc = list_first_entry(&dev->msi_list, struct msi_desc, list); | ||
609 | pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &ctrl); | ||
610 | mask = msi_capable_mask(ctrl); | 615 | mask = msi_capable_mask(ctrl); |
611 | msi_mask_irq(desc, mask, ~mask); | 616 | msi_mask_irq(desc, mask, ~mask); |
612 | 617 | ||
@@ -648,10 +653,7 @@ static int msi_free_irqs(struct pci_dev* dev) | |||
648 | 653 | ||
649 | list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) { | 654 | list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) { |
650 | if (entry->msi_attrib.is_msix) { | 655 | if (entry->msi_attrib.is_msix) { |
651 | writel(1, entry->mask_base + entry->msi_attrib.entry_nr | 656 | msix_mask_irq(entry, 1); |
652 | * PCI_MSIX_ENTRY_SIZE | ||
653 | + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); | ||
654 | |||
655 | if (list_is_last(&entry->list, &dev->msi_list)) | 657 | if (list_is_last(&entry->list, &dev->msi_list)) |
656 | iounmap(entry->mask_base); | 658 | iounmap(entry->mask_base); |
657 | } | 659 | } |
@@ -691,8 +693,8 @@ int pci_msix_table_size(struct pci_dev *dev) | |||
691 | * indicates the successful configuration of MSI-X capability structure | 693 | * indicates the successful configuration of MSI-X capability structure |
692 | * with new allocated MSI-X irqs. A return of < 0 indicates a failure. | 694 | * with new allocated MSI-X irqs. A return of < 0 indicates a failure. |
693 | * Or a return of > 0 indicates that driver request is exceeding the number | 695 | * Or a return of > 0 indicates that driver request is exceeding the number |
694 | * of irqs available. Driver should use the returned value to re-send | 696 | * of irqs or MSI-X vectors available. Driver should use the returned value to |
695 | * its request. | 697 | * re-send its request. |
696 | **/ | 698 | **/ |
697 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | 699 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) |
698 | { | 700 | { |
@@ -708,7 +710,7 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | |||
708 | 710 | ||
709 | nr_entries = pci_msix_table_size(dev); | 711 | nr_entries = pci_msix_table_size(dev); |
710 | if (nvec > nr_entries) | 712 | if (nvec > nr_entries) |
711 | return -EINVAL; | 713 | return nr_entries; |
712 | 714 | ||
713 | /* Check for any invalid entries */ | 715 | /* Check for any invalid entries */ |
714 | for (i = 0; i < nvec; i++) { | 716 | for (i = 0; i < nvec; i++) { |