diff options
Diffstat (limited to 'drivers/pci/msi.c')
| -rw-r--r-- | drivers/pci/msi.c | 227 |
1 files changed, 198 insertions, 29 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index a77e79c8c82e..2087a397ef16 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
| @@ -504,6 +504,201 @@ void pci_scan_msi_device(struct pci_dev *dev) | |||
| 504 | nr_reserved_vectors++; | 504 | nr_reserved_vectors++; |
| 505 | } | 505 | } |
| 506 | 506 | ||
| 507 | #ifdef CONFIG_PM | ||
| 508 | int pci_save_msi_state(struct pci_dev *dev) | ||
| 509 | { | ||
| 510 | int pos, i = 0; | ||
| 511 | u16 control; | ||
| 512 | struct pci_cap_saved_state *save_state; | ||
| 513 | u32 *cap; | ||
| 514 | |||
| 515 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | ||
| 516 | if (pos <= 0 || dev->no_msi) | ||
| 517 | return 0; | ||
| 518 | |||
| 519 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
| 520 | if (!(control & PCI_MSI_FLAGS_ENABLE)) | ||
| 521 | return 0; | ||
| 522 | |||
| 523 | save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u32) * 5, | ||
| 524 | GFP_KERNEL); | ||
| 525 | if (!save_state) { | ||
| 526 | printk(KERN_ERR "Out of memory in pci_save_msi_state\n"); | ||
| 527 | return -ENOMEM; | ||
| 528 | } | ||
| 529 | cap = &save_state->data[0]; | ||
| 530 | |||
| 531 | pci_read_config_dword(dev, pos, &cap[i++]); | ||
| 532 | control = cap[0] >> 16; | ||
| 533 | pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, &cap[i++]); | ||
| 534 | if (control & PCI_MSI_FLAGS_64BIT) { | ||
| 535 | pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, &cap[i++]); | ||
| 536 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_64, &cap[i++]); | ||
| 537 | } else | ||
| 538 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]); | ||
| 539 | if (control & PCI_MSI_FLAGS_MASKBIT) | ||
| 540 | pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]); | ||
| 541 | disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | ||
| 542 | save_state->cap_nr = PCI_CAP_ID_MSI; | ||
| 543 | pci_add_saved_cap(dev, save_state); | ||
| 544 | return 0; | ||
| 545 | } | ||
| 546 | |||
| 547 | void pci_restore_msi_state(struct pci_dev *dev) | ||
| 548 | { | ||
| 549 | int i = 0, pos; | ||
| 550 | u16 control; | ||
| 551 | struct pci_cap_saved_state *save_state; | ||
| 552 | u32 *cap; | ||
| 553 | |||
| 554 | save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSI); | ||
| 555 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | ||
| 556 | if (!save_state || pos <= 0) | ||
| 557 | return; | ||
| 558 | cap = &save_state->data[0]; | ||
| 559 | |||
| 560 | control = cap[i++] >> 16; | ||
| 561 | pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, cap[i++]); | ||
| 562 | if (control & PCI_MSI_FLAGS_64BIT) { | ||
| 563 | pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, cap[i++]); | ||
| 564 | pci_write_config_dword(dev, pos + PCI_MSI_DATA_64, cap[i++]); | ||
| 565 | } else | ||
| 566 | pci_write_config_dword(dev, pos + PCI_MSI_DATA_32, cap[i++]); | ||
| 567 | if (control & PCI_MSI_FLAGS_MASKBIT) | ||
| 568 | pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, cap[i++]); | ||
| 569 | pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); | ||
| 570 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | ||
| 571 | pci_remove_saved_cap(save_state); | ||
| 572 | kfree(save_state); | ||
| 573 | } | ||
| 574 | |||
| 575 | int pci_save_msix_state(struct pci_dev *dev) | ||
| 576 | { | ||
| 577 | int pos; | ||
| 578 | u16 control; | ||
| 579 | struct pci_cap_saved_state *save_state; | ||
| 580 | |||
| 581 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | ||
| 582 | if (pos <= 0 || dev->no_msi) | ||
| 583 | return 0; | ||
| 584 | |||
| 585 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
| 586 | if (!(control & PCI_MSIX_FLAGS_ENABLE)) | ||
| 587 | return 0; | ||
| 588 | save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u16), | ||
| 589 | GFP_KERNEL); | ||
| 590 | if (!save_state) { | ||
| 591 | printk(KERN_ERR "Out of memory in pci_save_msix_state\n"); | ||
| 592 | return -ENOMEM; | ||
| 593 | } | ||
| 594 | *((u16 *)&save_state->data[0]) = control; | ||
| 595 | |||
| 596 | disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); | ||
| 597 | save_state->cap_nr = PCI_CAP_ID_MSIX; | ||
| 598 | pci_add_saved_cap(dev, save_state); | ||
| 599 | return 0; | ||
| 600 | } | ||
| 601 | |||
| 602 | void pci_restore_msix_state(struct pci_dev *dev) | ||
| 603 | { | ||
| 604 | u16 save; | ||
| 605 | int pos; | ||
| 606 | int vector, head, tail = 0; | ||
| 607 | void __iomem *base; | ||
| 608 | int j; | ||
| 609 | struct msg_address address; | ||
| 610 | struct msg_data data; | ||
| 611 | struct msi_desc *entry; | ||
| 612 | int temp; | ||
| 613 | struct pci_cap_saved_state *save_state; | ||
| 614 | |||
| 615 | save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX); | ||
| 616 | if (!save_state) | ||
| 617 | return; | ||
| 618 | save = *((u16 *)&save_state->data[0]); | ||
| 619 | pci_remove_saved_cap(save_state); | ||
| 620 | kfree(save_state); | ||
| 621 | |||
| 622 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | ||
| 623 | if (pos <= 0) | ||
| 624 | return; | ||
| 625 | |||
| 626 | /* route the table */ | ||
| 627 | temp = dev->irq; | ||
| 628 | if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) | ||
| 629 | return; | ||
| 630 | vector = head = dev->irq; | ||
| 631 | while (head != tail) { | ||
| 632 | entry = msi_desc[vector]; | ||
| 633 | base = entry->mask_base; | ||
| 634 | j = entry->msi_attrib.entry_nr; | ||
| 635 | |||
| 636 | msi_address_init(&address); | ||
| 637 | msi_data_init(&data, vector); | ||
| 638 | |||
| 639 | address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; | ||
| 640 | address.lo_address.value |= entry->msi_attrib.current_cpu << | ||
| 641 | MSI_TARGET_CPU_SHIFT; | ||
| 642 | |||
| 643 | writel(address.lo_address.value, | ||
| 644 | base + j * PCI_MSIX_ENTRY_SIZE + | ||
| 645 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | ||
| 646 | writel(address.hi_address, | ||
| 647 | base + j * PCI_MSIX_ENTRY_SIZE + | ||
| 648 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | ||
| 649 | writel(*(u32*)&data, | ||
| 650 | base + j * PCI_MSIX_ENTRY_SIZE + | ||
| 651 | PCI_MSIX_ENTRY_DATA_OFFSET); | ||
| 652 | |||
| 653 | tail = msi_desc[vector]->link.tail; | ||
| 654 | vector = tail; | ||
| 655 | } | ||
| 656 | dev->irq = temp; | ||
| 657 | |||
| 658 | pci_write_config_word(dev, msi_control_reg(pos), save); | ||
| 659 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); | ||
| 660 | } | ||
| 661 | #endif | ||
| 662 | |||
| 663 | static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | ||
| 664 | { | ||
| 665 | struct msg_address address; | ||
| 666 | struct msg_data data; | ||
| 667 | int pos, vector = dev->irq; | ||
| 668 | u16 control; | ||
| 669 | |||
| 670 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | ||
| 671 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
| 672 | /* Configure MSI capability structure */ | ||
| 673 | msi_address_init(&address); | ||
| 674 | msi_data_init(&data, vector); | ||
| 675 | entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >> | ||
| 676 | MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); | ||
| 677 | pci_write_config_dword(dev, msi_lower_address_reg(pos), | ||
| 678 | address.lo_address.value); | ||
| 679 | if (is_64bit_address(control)) { | ||
| 680 | pci_write_config_dword(dev, | ||
| 681 | msi_upper_address_reg(pos), address.hi_address); | ||
| 682 | pci_write_config_word(dev, | ||
| 683 | msi_data_reg(pos, 1), *((u32*)&data)); | ||
| 684 | } else | ||
| 685 | pci_write_config_word(dev, | ||
| 686 | msi_data_reg(pos, 0), *((u32*)&data)); | ||
| 687 | if (entry->msi_attrib.maskbit) { | ||
| 688 | unsigned int maskbits, temp; | ||
| 689 | /* All MSIs are unmasked by default, Mask them all */ | ||
| 690 | pci_read_config_dword(dev, | ||
| 691 | msi_mask_bits_reg(pos, is_64bit_address(control)), | ||
| 692 | &maskbits); | ||
| 693 | temp = (1 << multi_msi_capable(control)); | ||
| 694 | temp = ((temp - 1) & ~temp); | ||
| 695 | maskbits |= temp; | ||
| 696 | pci_write_config_dword(dev, | ||
| 697 | msi_mask_bits_reg(pos, is_64bit_address(control)), | ||
| 698 | maskbits); | ||
| 699 | } | ||
| 700 | } | ||
| 701 | |||
| 507 | /** | 702 | /** |
| 508 | * msi_capability_init - configure device's MSI capability structure | 703 | * msi_capability_init - configure device's MSI capability structure |
| 509 | * @dev: pointer to the pci_dev data structure of MSI device function | 704 | * @dev: pointer to the pci_dev data structure of MSI device function |
| @@ -516,8 +711,6 @@ void pci_scan_msi_device(struct pci_dev *dev) | |||
| 516 | static int msi_capability_init(struct pci_dev *dev) | 711 | static int msi_capability_init(struct pci_dev *dev) |
| 517 | { | 712 | { |
| 518 | struct msi_desc *entry; | 713 | struct msi_desc *entry; |
| 519 | struct msg_address address; | ||
| 520 | struct msg_data data; | ||
| 521 | int pos, vector; | 714 | int pos, vector; |
| 522 | u16 control; | 715 | u16 control; |
| 523 | 716 | ||
| @@ -549,33 +742,8 @@ static int msi_capability_init(struct pci_dev *dev) | |||
| 549 | /* Replace with MSI handler */ | 742 | /* Replace with MSI handler */ |
| 550 | irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); | 743 | irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); |
| 551 | /* Configure MSI capability structure */ | 744 | /* Configure MSI capability structure */ |
| 552 | msi_address_init(&address); | 745 | msi_register_init(dev, entry); |
| 553 | msi_data_init(&data, vector); | 746 | |
| 554 | entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >> | ||
| 555 | MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); | ||
| 556 | pci_write_config_dword(dev, msi_lower_address_reg(pos), | ||
| 557 | address.lo_address.value); | ||
| 558 | if (is_64bit_address(control)) { | ||
| 559 | pci_write_config_dword(dev, | ||
| 560 | msi_upper_address_reg(pos), address.hi_address); | ||
| 561 | pci_write_config_word(dev, | ||
| 562 | msi_data_reg(pos, 1), *((u32*)&data)); | ||
| 563 | } else | ||
| 564 | pci_write_config_word(dev, | ||
| 565 | msi_data_reg(pos, 0), *((u32*)&data)); | ||
| 566 | if (entry->msi_attrib.maskbit) { | ||
| 567 | unsigned int maskbits, temp; | ||
| 568 | /* All MSIs are unmasked by default, Mask them all */ | ||
| 569 | pci_read_config_dword(dev, | ||
| 570 | msi_mask_bits_reg(pos, is_64bit_address(control)), | ||
| 571 | &maskbits); | ||
| 572 | temp = (1 << multi_msi_capable(control)); | ||
| 573 | temp = ((temp - 1) & ~temp); | ||
| 574 | maskbits |= temp; | ||
| 575 | pci_write_config_dword(dev, | ||
| 576 | msi_mask_bits_reg(pos, is_64bit_address(control)), | ||
| 577 | maskbits); | ||
| 578 | } | ||
| 579 | attach_msi_entry(entry, vector); | 747 | attach_msi_entry(entry, vector); |
| 580 | /* Set MSI enabled bits */ | 748 | /* Set MSI enabled bits */ |
| 581 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | 749 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); |
| @@ -731,6 +899,7 @@ int pci_enable_msi(struct pci_dev* dev) | |||
| 731 | vector_irq[dev->irq] = -1; | 899 | vector_irq[dev->irq] = -1; |
| 732 | nr_released_vectors--; | 900 | nr_released_vectors--; |
| 733 | spin_unlock_irqrestore(&msi_lock, flags); | 901 | spin_unlock_irqrestore(&msi_lock, flags); |
| 902 | msi_register_init(dev, msi_desc[dev->irq]); | ||
| 734 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | 903 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); |
| 735 | return 0; | 904 | return 0; |
| 736 | } | 905 | } |
