diff options
Diffstat (limited to 'drivers/pci/msi.c')
| -rw-r--r-- | drivers/pci/msi.c | 285 |
1 files changed, 151 insertions, 134 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 9855c4c920b8..7f8429284fab 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
| @@ -23,8 +23,6 @@ | |||
| 23 | #include "pci.h" | 23 | #include "pci.h" |
| 24 | #include "msi.h" | 24 | #include "msi.h" |
| 25 | 25 | ||
| 26 | #define MSI_TARGET_CPU first_cpu(cpu_online_map) | ||
| 27 | |||
| 28 | static DEFINE_SPINLOCK(msi_lock); | 26 | static DEFINE_SPINLOCK(msi_lock); |
| 29 | static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; | 27 | static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; |
| 30 | static kmem_cache_t* msi_cachep; | 28 | static kmem_cache_t* msi_cachep; |
| @@ -37,9 +35,17 @@ static int nr_msix_devices; | |||
| 37 | 35 | ||
| 38 | #ifndef CONFIG_X86_IO_APIC | 36 | #ifndef CONFIG_X86_IO_APIC |
| 39 | int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; | 37 | int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; |
| 40 | u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 }; | ||
| 41 | #endif | 38 | #endif |
| 42 | 39 | ||
| 40 | static struct msi_ops *msi_ops; | ||
| 41 | |||
| 42 | int | ||
| 43 | msi_register(struct msi_ops *ops) | ||
| 44 | { | ||
| 45 | msi_ops = ops; | ||
| 46 | return 0; | ||
| 47 | } | ||
| 48 | |||
| 43 | static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags) | 49 | static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags) |
| 44 | { | 50 | { |
| 45 | memset(p, 0, NR_IRQS * sizeof(struct msi_desc)); | 51 | memset(p, 0, NR_IRQS * sizeof(struct msi_desc)); |
| @@ -92,7 +98,7 @@ static void msi_set_mask_bit(unsigned int vector, int flag) | |||
| 92 | static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) | 98 | static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) |
| 93 | { | 99 | { |
| 94 | struct msi_desc *entry; | 100 | struct msi_desc *entry; |
| 95 | struct msg_address address; | 101 | u32 address_hi, address_lo; |
| 96 | unsigned int irq = vector; | 102 | unsigned int irq = vector; |
| 97 | unsigned int dest_cpu = first_cpu(cpu_mask); | 103 | unsigned int dest_cpu = first_cpu(cpu_mask); |
| 98 | 104 | ||
| @@ -108,28 +114,36 @@ static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) | |||
| 108 | if (!pos) | 114 | if (!pos) |
| 109 | return; | 115 | return; |
| 110 | 116 | ||
| 117 | pci_read_config_dword(entry->dev, msi_upper_address_reg(pos), | ||
| 118 | &address_hi); | ||
| 111 | pci_read_config_dword(entry->dev, msi_lower_address_reg(pos), | 119 | pci_read_config_dword(entry->dev, msi_lower_address_reg(pos), |
| 112 | &address.lo_address.value); | 120 | &address_lo); |
| 113 | address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; | 121 | |
| 114 | address.lo_address.value |= (cpu_physical_id(dest_cpu) << | 122 | msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); |
| 115 | MSI_TARGET_CPU_SHIFT); | 123 | |
| 116 | entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu); | 124 | pci_write_config_dword(entry->dev, msi_upper_address_reg(pos), |
| 125 | address_hi); | ||
| 117 | pci_write_config_dword(entry->dev, msi_lower_address_reg(pos), | 126 | pci_write_config_dword(entry->dev, msi_lower_address_reg(pos), |
| 118 | address.lo_address.value); | 127 | address_lo); |
| 119 | set_native_irq_info(irq, cpu_mask); | 128 | set_native_irq_info(irq, cpu_mask); |
| 120 | break; | 129 | break; |
| 121 | } | 130 | } |
| 122 | case PCI_CAP_ID_MSIX: | 131 | case PCI_CAP_ID_MSIX: |
| 123 | { | 132 | { |
| 124 | int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + | 133 | int offset_hi = |
| 125 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET; | 134 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + |
| 126 | 135 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET; | |
| 127 | address.lo_address.value = readl(entry->mask_base + offset); | 136 | int offset_lo = |
| 128 | address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; | 137 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + |
| 129 | address.lo_address.value |= (cpu_physical_id(dest_cpu) << | 138 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET; |
| 130 | MSI_TARGET_CPU_SHIFT); | 139 | |
| 131 | entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu); | 140 | address_hi = readl(entry->mask_base + offset_hi); |
| 132 | writel(address.lo_address.value, entry->mask_base + offset); | 141 | address_lo = readl(entry->mask_base + offset_lo); |
| 142 | |||
| 143 | msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); | ||
| 144 | |||
| 145 | writel(address_hi, entry->mask_base + offset_hi); | ||
| 146 | writel(address_lo, entry->mask_base + offset_lo); | ||
| 133 | set_native_irq_info(irq, cpu_mask); | 147 | set_native_irq_info(irq, cpu_mask); |
| 134 | break; | 148 | break; |
| 135 | } | 149 | } |
| @@ -251,30 +265,6 @@ static struct hw_interrupt_type msi_irq_wo_maskbit_type = { | |||
| 251 | .set_affinity = set_msi_affinity | 265 | .set_affinity = set_msi_affinity |
| 252 | }; | 266 | }; |
| 253 | 267 | ||
| 254 | static void msi_data_init(struct msg_data *msi_data, | ||
| 255 | unsigned int vector) | ||
| 256 | { | ||
| 257 | memset(msi_data, 0, sizeof(struct msg_data)); | ||
| 258 | msi_data->vector = (u8)vector; | ||
| 259 | msi_data->delivery_mode = MSI_DELIVERY_MODE; | ||
| 260 | msi_data->level = MSI_LEVEL_MODE; | ||
| 261 | msi_data->trigger = MSI_TRIGGER_MODE; | ||
| 262 | } | ||
| 263 | |||
| 264 | static void msi_address_init(struct msg_address *msi_address) | ||
| 265 | { | ||
| 266 | unsigned int dest_id; | ||
| 267 | unsigned long dest_phys_id = cpu_physical_id(MSI_TARGET_CPU); | ||
| 268 | |||
| 269 | memset(msi_address, 0, sizeof(struct msg_address)); | ||
| 270 | msi_address->hi_address = (u32)0; | ||
| 271 | dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT); | ||
| 272 | msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE; | ||
| 273 | msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE; | ||
| 274 | msi_address->lo_address.u.dest_id = dest_id; | ||
| 275 | msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT); | ||
| 276 | } | ||
| 277 | |||
| 278 | static int msi_free_vector(struct pci_dev* dev, int vector, int reassign); | 268 | static int msi_free_vector(struct pci_dev* dev, int vector, int reassign); |
| 279 | static int assign_msi_vector(void) | 269 | static int assign_msi_vector(void) |
| 280 | { | 270 | { |
| @@ -369,13 +359,29 @@ static int msi_init(void) | |||
| 369 | return status; | 359 | return status; |
| 370 | } | 360 | } |
| 371 | 361 | ||
| 362 | status = msi_arch_init(); | ||
| 363 | if (status < 0) { | ||
| 364 | pci_msi_enable = 0; | ||
| 365 | printk(KERN_WARNING | ||
| 366 | "PCI: MSI arch init failed. MSI disabled.\n"); | ||
| 367 | return status; | ||
| 368 | } | ||
| 369 | |||
| 370 | if (! msi_ops) { | ||
| 371 | printk(KERN_WARNING | ||
| 372 | "PCI: MSI ops not registered. MSI disabled.\n"); | ||
| 373 | status = -EINVAL; | ||
| 374 | return status; | ||
| 375 | } | ||
| 376 | |||
| 377 | last_alloc_vector = assign_irq_vector(AUTO_ASSIGN); | ||
| 372 | status = msi_cache_init(); | 378 | status = msi_cache_init(); |
| 373 | if (status < 0) { | 379 | if (status < 0) { |
| 374 | pci_msi_enable = 0; | 380 | pci_msi_enable = 0; |
| 375 | printk(KERN_WARNING "PCI: MSI cache init failed\n"); | 381 | printk(KERN_WARNING "PCI: MSI cache init failed\n"); |
| 376 | return status; | 382 | return status; |
| 377 | } | 383 | } |
| 378 | last_alloc_vector = assign_irq_vector(AUTO_ASSIGN); | 384 | |
| 379 | if (last_alloc_vector < 0) { | 385 | if (last_alloc_vector < 0) { |
| 380 | pci_msi_enable = 0; | 386 | pci_msi_enable = 0; |
| 381 | printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); | 387 | printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); |
| @@ -442,9 +448,11 @@ static void enable_msi_mode(struct pci_dev *dev, int pos, int type) | |||
| 442 | /* Set enabled bits to single MSI & enable MSI_enable bit */ | 448 | /* Set enabled bits to single MSI & enable MSI_enable bit */ |
| 443 | msi_enable(control, 1); | 449 | msi_enable(control, 1); |
| 444 | pci_write_config_word(dev, msi_control_reg(pos), control); | 450 | pci_write_config_word(dev, msi_control_reg(pos), control); |
| 451 | dev->msi_enabled = 1; | ||
| 445 | } else { | 452 | } else { |
| 446 | msix_enable(control); | 453 | msix_enable(control); |
| 447 | pci_write_config_word(dev, msi_control_reg(pos), control); | 454 | pci_write_config_word(dev, msi_control_reg(pos), control); |
| 455 | dev->msix_enabled = 1; | ||
| 448 | } | 456 | } |
| 449 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { | 457 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { |
| 450 | /* PCI Express Endpoint device detected */ | 458 | /* PCI Express Endpoint device detected */ |
| @@ -461,9 +469,11 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type) | |||
| 461 | /* Set enabled bits to single MSI & enable MSI_enable bit */ | 469 | /* Set enabled bits to single MSI & enable MSI_enable bit */ |
| 462 | msi_disable(control); | 470 | msi_disable(control); |
| 463 | pci_write_config_word(dev, msi_control_reg(pos), control); | 471 | pci_write_config_word(dev, msi_control_reg(pos), control); |
| 472 | dev->msi_enabled = 0; | ||
| 464 | } else { | 473 | } else { |
| 465 | msix_disable(control); | 474 | msix_disable(control); |
| 466 | pci_write_config_word(dev, msi_control_reg(pos), control); | 475 | pci_write_config_word(dev, msi_control_reg(pos), control); |
| 476 | dev->msix_enabled = 0; | ||
| 467 | } | 477 | } |
| 468 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { | 478 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { |
| 469 | /* PCI Express Endpoint device detected */ | 479 | /* PCI Express Endpoint device detected */ |
| @@ -538,7 +548,6 @@ int pci_save_msi_state(struct pci_dev *dev) | |||
| 538 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]); | 548 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]); |
| 539 | if (control & PCI_MSI_FLAGS_MASKBIT) | 549 | if (control & PCI_MSI_FLAGS_MASKBIT) |
| 540 | pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]); | 550 | 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; | 551 | save_state->cap_nr = PCI_CAP_ID_MSI; |
| 543 | pci_add_saved_cap(dev, save_state); | 552 | pci_add_saved_cap(dev, save_state); |
| 544 | return 0; | 553 | return 0; |
| @@ -575,6 +584,8 @@ void pci_restore_msi_state(struct pci_dev *dev) | |||
| 575 | int pci_save_msix_state(struct pci_dev *dev) | 584 | int pci_save_msix_state(struct pci_dev *dev) |
| 576 | { | 585 | { |
| 577 | int pos; | 586 | int pos; |
| 587 | int temp; | ||
| 588 | int vector, head, tail = 0; | ||
| 578 | u16 control; | 589 | u16 control; |
| 579 | struct pci_cap_saved_state *save_state; | 590 | struct pci_cap_saved_state *save_state; |
| 580 | 591 | ||
| @@ -582,6 +593,7 @@ int pci_save_msix_state(struct pci_dev *dev) | |||
| 582 | if (pos <= 0 || dev->no_msi) | 593 | if (pos <= 0 || dev->no_msi) |
| 583 | return 0; | 594 | return 0; |
| 584 | 595 | ||
| 596 | /* save the capability */ | ||
| 585 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 597 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
| 586 | if (!(control & PCI_MSIX_FLAGS_ENABLE)) | 598 | if (!(control & PCI_MSIX_FLAGS_ENABLE)) |
| 587 | return 0; | 599 | return 0; |
| @@ -593,7 +605,38 @@ int pci_save_msix_state(struct pci_dev *dev) | |||
| 593 | } | 605 | } |
| 594 | *((u16 *)&save_state->data[0]) = control; | 606 | *((u16 *)&save_state->data[0]) = control; |
| 595 | 607 | ||
| 596 | disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); | 608 | /* save the table */ |
| 609 | temp = dev->irq; | ||
| 610 | if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { | ||
| 611 | kfree(save_state); | ||
| 612 | return -EINVAL; | ||
| 613 | } | ||
| 614 | |||
| 615 | vector = head = dev->irq; | ||
| 616 | while (head != tail) { | ||
| 617 | int j; | ||
| 618 | void __iomem *base; | ||
| 619 | struct msi_desc *entry; | ||
| 620 | |||
| 621 | entry = msi_desc[vector]; | ||
| 622 | base = entry->mask_base; | ||
| 623 | j = entry->msi_attrib.entry_nr; | ||
| 624 | |||
| 625 | entry->address_lo_save = | ||
| 626 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
| 627 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | ||
| 628 | entry->address_hi_save = | ||
| 629 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
| 630 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | ||
| 631 | entry->data_save = | ||
| 632 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
| 633 | PCI_MSIX_ENTRY_DATA_OFFSET); | ||
| 634 | |||
| 635 | tail = msi_desc[vector]->link.tail; | ||
| 636 | vector = tail; | ||
| 637 | } | ||
| 638 | dev->irq = temp; | ||
| 639 | |||
| 597 | save_state->cap_nr = PCI_CAP_ID_MSIX; | 640 | save_state->cap_nr = PCI_CAP_ID_MSIX; |
| 598 | pci_add_saved_cap(dev, save_state); | 641 | pci_add_saved_cap(dev, save_state); |
| 599 | return 0; | 642 | return 0; |
| @@ -606,8 +649,6 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
| 606 | int vector, head, tail = 0; | 649 | int vector, head, tail = 0; |
| 607 | void __iomem *base; | 650 | void __iomem *base; |
| 608 | int j; | 651 | int j; |
| 609 | struct msg_address address; | ||
| 610 | struct msg_data data; | ||
| 611 | struct msi_desc *entry; | 652 | struct msi_desc *entry; |
| 612 | int temp; | 653 | int temp; |
| 613 | struct pci_cap_saved_state *save_state; | 654 | struct pci_cap_saved_state *save_state; |
| @@ -633,20 +674,13 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
| 633 | base = entry->mask_base; | 674 | base = entry->mask_base; |
| 634 | j = entry->msi_attrib.entry_nr; | 675 | j = entry->msi_attrib.entry_nr; |
| 635 | 676 | ||
| 636 | msi_address_init(&address); | 677 | writel(entry->address_lo_save, |
| 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 + | 678 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 645 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | 679 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); |
| 646 | writel(address.hi_address, | 680 | writel(entry->address_hi_save, |
| 647 | base + j * PCI_MSIX_ENTRY_SIZE + | 681 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 648 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | 682 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); |
| 649 | writel(*(u32*)&data, | 683 | writel(entry->data_save, |
| 650 | base + j * PCI_MSIX_ENTRY_SIZE + | 684 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 651 | PCI_MSIX_ENTRY_DATA_OFFSET); | 685 | PCI_MSIX_ENTRY_DATA_OFFSET); |
| 652 | 686 | ||
| @@ -660,30 +694,32 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
| 660 | } | 694 | } |
| 661 | #endif | 695 | #endif |
| 662 | 696 | ||
| 663 | static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | 697 | static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) |
| 664 | { | 698 | { |
| 665 | struct msg_address address; | 699 | int status; |
| 666 | struct msg_data data; | 700 | u32 address_hi; |
| 701 | u32 address_lo; | ||
| 702 | u32 data; | ||
| 667 | int pos, vector = dev->irq; | 703 | int pos, vector = dev->irq; |
| 668 | u16 control; | 704 | u16 control; |
| 669 | 705 | ||
| 670 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | 706 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); |
| 671 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 707 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
| 708 | |||
| 672 | /* Configure MSI capability structure */ | 709 | /* Configure MSI capability structure */ |
| 673 | msi_address_init(&address); | 710 | status = msi_ops->setup(dev, vector, &address_hi, &address_lo, &data); |
| 674 | msi_data_init(&data, vector); | 711 | if (status < 0) |
| 675 | entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >> | 712 | return status; |
| 676 | MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); | 713 | |
| 677 | pci_write_config_dword(dev, msi_lower_address_reg(pos), | 714 | pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo); |
| 678 | address.lo_address.value); | ||
| 679 | if (is_64bit_address(control)) { | 715 | if (is_64bit_address(control)) { |
| 680 | pci_write_config_dword(dev, | 716 | pci_write_config_dword(dev, |
| 681 | msi_upper_address_reg(pos), address.hi_address); | 717 | msi_upper_address_reg(pos), address_hi); |
| 682 | pci_write_config_word(dev, | 718 | pci_write_config_word(dev, |
| 683 | msi_data_reg(pos, 1), *((u32*)&data)); | 719 | msi_data_reg(pos, 1), data); |
| 684 | } else | 720 | } else |
| 685 | pci_write_config_word(dev, | 721 | pci_write_config_word(dev, |
| 686 | msi_data_reg(pos, 0), *((u32*)&data)); | 722 | msi_data_reg(pos, 0), data); |
| 687 | if (entry->msi_attrib.maskbit) { | 723 | if (entry->msi_attrib.maskbit) { |
| 688 | unsigned int maskbits, temp; | 724 | unsigned int maskbits, temp; |
| 689 | /* All MSIs are unmasked by default, Mask them all */ | 725 | /* All MSIs are unmasked by default, Mask them all */ |
| @@ -697,6 +733,8 @@ static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | |||
| 697 | msi_mask_bits_reg(pos, is_64bit_address(control)), | 733 | msi_mask_bits_reg(pos, is_64bit_address(control)), |
| 698 | maskbits); | 734 | maskbits); |
| 699 | } | 735 | } |
| 736 | |||
| 737 | return 0; | ||
| 700 | } | 738 | } |
| 701 | 739 | ||
| 702 | /** | 740 | /** |
| @@ -710,6 +748,7 @@ static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | |||
| 710 | **/ | 748 | **/ |
| 711 | static int msi_capability_init(struct pci_dev *dev) | 749 | static int msi_capability_init(struct pci_dev *dev) |
| 712 | { | 750 | { |
| 751 | int status; | ||
| 713 | struct msi_desc *entry; | 752 | struct msi_desc *entry; |
| 714 | int pos, vector; | 753 | int pos, vector; |
| 715 | u16 control; | 754 | u16 control; |
| @@ -742,7 +781,12 @@ static int msi_capability_init(struct pci_dev *dev) | |||
| 742 | /* Replace with MSI handler */ | 781 | /* Replace with MSI handler */ |
| 743 | irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); | 782 | irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); |
| 744 | /* Configure MSI capability structure */ | 783 | /* Configure MSI capability structure */ |
| 745 | msi_register_init(dev, entry); | 784 | status = msi_register_init(dev, entry); |
| 785 | if (status != 0) { | ||
| 786 | dev->irq = entry->msi_attrib.default_vector; | ||
| 787 | kmem_cache_free(msi_cachep, entry); | ||
| 788 | return status; | ||
| 789 | } | ||
| 746 | 790 | ||
| 747 | attach_msi_entry(entry, vector); | 791 | attach_msi_entry(entry, vector); |
| 748 | /* Set MSI enabled bits */ | 792 | /* Set MSI enabled bits */ |
| @@ -765,8 +809,10 @@ static int msix_capability_init(struct pci_dev *dev, | |||
| 765 | struct msix_entry *entries, int nvec) | 809 | struct msix_entry *entries, int nvec) |
| 766 | { | 810 | { |
| 767 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; | 811 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; |
| 768 | struct msg_address address; | 812 | u32 address_hi; |
| 769 | struct msg_data data; | 813 | u32 address_lo; |
| 814 | u32 data; | ||
| 815 | int status; | ||
| 770 | int vector, pos, i, j, nr_entries, temp = 0; | 816 | int vector, pos, i, j, nr_entries, temp = 0; |
| 771 | unsigned long phys_addr; | 817 | unsigned long phys_addr; |
| 772 | u32 table_offset; | 818 | u32 table_offset; |
| @@ -822,18 +868,20 @@ static int msix_capability_init(struct pci_dev *dev, | |||
| 822 | /* Replace with MSI-X handler */ | 868 | /* Replace with MSI-X handler */ |
| 823 | irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); | 869 | irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); |
| 824 | /* Configure MSI-X capability structure */ | 870 | /* Configure MSI-X capability structure */ |
| 825 | msi_address_init(&address); | 871 | status = msi_ops->setup(dev, vector, |
| 826 | msi_data_init(&data, vector); | 872 | &address_hi, |
| 827 | entry->msi_attrib.current_cpu = | 873 | &address_lo, |
| 828 | ((address.lo_address.u.dest_id >> | 874 | &data); |
| 829 | MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); | 875 | if (status < 0) |
| 830 | writel(address.lo_address.value, | 876 | break; |
| 877 | |||
| 878 | writel(address_lo, | ||
| 831 | base + j * PCI_MSIX_ENTRY_SIZE + | 879 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 832 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | 880 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); |
| 833 | writel(address.hi_address, | 881 | writel(address_hi, |
| 834 | base + j * PCI_MSIX_ENTRY_SIZE + | 882 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 835 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | 883 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); |
| 836 | writel(*(u32*)&data, | 884 | writel(data, |
| 837 | base + j * PCI_MSIX_ENTRY_SIZE + | 885 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 838 | PCI_MSIX_ENTRY_DATA_OFFSET); | 886 | PCI_MSIX_ENTRY_DATA_OFFSET); |
| 839 | attach_msi_entry(entry, vector); | 887 | attach_msi_entry(entry, vector); |
| @@ -865,6 +913,7 @@ static int msix_capability_init(struct pci_dev *dev, | |||
| 865 | **/ | 913 | **/ |
| 866 | int pci_enable_msi(struct pci_dev* dev) | 914 | int pci_enable_msi(struct pci_dev* dev) |
| 867 | { | 915 | { |
| 916 | struct pci_bus *bus; | ||
| 868 | int pos, temp, status = -EINVAL; | 917 | int pos, temp, status = -EINVAL; |
| 869 | u16 control; | 918 | u16 control; |
| 870 | 919 | ||
| @@ -874,8 +923,9 @@ int pci_enable_msi(struct pci_dev* dev) | |||
| 874 | if (dev->no_msi) | 923 | if (dev->no_msi) |
| 875 | return status; | 924 | return status; |
| 876 | 925 | ||
| 877 | if (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) | 926 | for (bus = dev->bus; bus; bus = bus->parent) |
| 878 | return -EINVAL; | 927 | if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) |
| 928 | return -EINVAL; | ||
| 879 | 929 | ||
| 880 | temp = dev->irq; | 930 | temp = dev->irq; |
| 881 | 931 | ||
| @@ -887,23 +937,23 @@ int pci_enable_msi(struct pci_dev* dev) | |||
| 887 | if (!pos) | 937 | if (!pos) |
| 888 | return -EINVAL; | 938 | return -EINVAL; |
| 889 | 939 | ||
| 890 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
| 891 | if (control & PCI_MSI_FLAGS_ENABLE) | ||
| 892 | return 0; /* Already in MSI mode */ | ||
| 893 | |||
| 894 | if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { | 940 | if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { |
| 895 | /* Lookup Sucess */ | 941 | /* Lookup Sucess */ |
| 896 | unsigned long flags; | 942 | unsigned long flags; |
| 897 | 943 | ||
| 944 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
| 945 | if (control & PCI_MSI_FLAGS_ENABLE) | ||
| 946 | return 0; /* Already in MSI mode */ | ||
| 898 | spin_lock_irqsave(&msi_lock, flags); | 947 | spin_lock_irqsave(&msi_lock, flags); |
| 899 | if (!vector_irq[dev->irq]) { | 948 | if (!vector_irq[dev->irq]) { |
| 900 | msi_desc[dev->irq]->msi_attrib.state = 0; | 949 | msi_desc[dev->irq]->msi_attrib.state = 0; |
| 901 | vector_irq[dev->irq] = -1; | 950 | vector_irq[dev->irq] = -1; |
| 902 | nr_released_vectors--; | 951 | nr_released_vectors--; |
| 903 | spin_unlock_irqrestore(&msi_lock, flags); | 952 | spin_unlock_irqrestore(&msi_lock, flags); |
| 904 | msi_register_init(dev, msi_desc[dev->irq]); | 953 | status = msi_register_init(dev, msi_desc[dev->irq]); |
| 905 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | 954 | if (status == 0) |
| 906 | return 0; | 955 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); |
| 956 | return status; | ||
| 907 | } | 957 | } |
| 908 | spin_unlock_irqrestore(&msi_lock, flags); | 958 | spin_unlock_irqrestore(&msi_lock, flags); |
| 909 | dev->irq = temp; | 959 | dev->irq = temp; |
| @@ -980,6 +1030,8 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) | |||
| 980 | void __iomem *base; | 1030 | void __iomem *base; |
| 981 | unsigned long flags; | 1031 | unsigned long flags; |
| 982 | 1032 | ||
| 1033 | msi_ops->teardown(vector); | ||
| 1034 | |||
| 983 | spin_lock_irqsave(&msi_lock, flags); | 1035 | spin_lock_irqsave(&msi_lock, flags); |
| 984 | entry = msi_desc[vector]; | 1036 | entry = msi_desc[vector]; |
| 985 | if (!entry || entry->dev != dev) { | 1037 | if (!entry || entry->dev != dev) { |
| @@ -1008,33 +1060,8 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) | |||
| 1008 | entry_nr * PCI_MSIX_ENTRY_SIZE + | 1060 | entry_nr * PCI_MSIX_ENTRY_SIZE + |
| 1009 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); | 1061 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); |
| 1010 | 1062 | ||
| 1011 | if (head == vector) { | 1063 | if (head == vector) |
| 1012 | /* | ||
| 1013 | * Detect last MSI-X vector to be released. | ||
| 1014 | * Release the MSI-X memory-mapped table. | ||
| 1015 | */ | ||
| 1016 | #if 0 | ||
| 1017 | int pos, nr_entries; | ||
| 1018 | unsigned long phys_addr; | ||
| 1019 | u32 table_offset; | ||
| 1020 | u16 control; | ||
| 1021 | u8 bir; | ||
| 1022 | |||
| 1023 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | ||
| 1024 | pci_read_config_word(dev, msi_control_reg(pos), | ||
| 1025 | &control); | ||
| 1026 | nr_entries = multi_msix_capable(control); | ||
| 1027 | pci_read_config_dword(dev, msix_table_offset_reg(pos), | ||
| 1028 | &table_offset); | ||
| 1029 | bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); | ||
| 1030 | table_offset &= ~PCI_MSIX_FLAGS_BIRMASK; | ||
| 1031 | phys_addr = pci_resource_start(dev, bir) + table_offset; | ||
| 1032 | /* | ||
| 1033 | * FIXME! and what did you want to do with phys_addr? | ||
| 1034 | */ | ||
| 1035 | #endif | ||
| 1036 | iounmap(base); | 1064 | iounmap(base); |
| 1037 | } | ||
| 1038 | } | 1065 | } |
| 1039 | 1066 | ||
| 1040 | return 0; | 1067 | return 0; |
| @@ -1108,6 +1135,7 @@ static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec) | |||
| 1108 | **/ | 1135 | **/ |
| 1109 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | 1136 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) |
| 1110 | { | 1137 | { |
| 1138 | struct pci_bus *bus; | ||
| 1111 | int status, pos, nr_entries, free_vectors; | 1139 | int status, pos, nr_entries, free_vectors; |
| 1112 | int i, j, temp; | 1140 | int i, j, temp; |
| 1113 | u16 control; | 1141 | u16 control; |
| @@ -1116,6 +1144,13 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | |||
| 1116 | if (!pci_msi_enable || !dev || !entries) | 1144 | if (!pci_msi_enable || !dev || !entries) |
| 1117 | return -EINVAL; | 1145 | return -EINVAL; |
| 1118 | 1146 | ||
| 1147 | if (dev->no_msi) | ||
| 1148 | return -EINVAL; | ||
| 1149 | |||
| 1150 | for (bus = dev->bus; bus; bus = bus->parent) | ||
| 1151 | if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) | ||
| 1152 | return -EINVAL; | ||
| 1153 | |||
| 1119 | status = msi_init(); | 1154 | status = msi_init(); |
| 1120 | if (status < 0) | 1155 | if (status < 0) |
| 1121 | return status; | 1156 | return status; |
| @@ -1300,24 +1335,6 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev) | |||
| 1300 | } | 1335 | } |
| 1301 | msi_free_vector(dev, vector, 0); | 1336 | msi_free_vector(dev, vector, 0); |
| 1302 | if (warning) { | 1337 | if (warning) { |
| 1303 | /* Force to release the MSI-X memory-mapped table */ | ||
| 1304 | #if 0 | ||
| 1305 | unsigned long phys_addr; | ||
| 1306 | u32 table_offset; | ||
| 1307 | u16 control; | ||
| 1308 | u8 bir; | ||
| 1309 | |||
| 1310 | pci_read_config_word(dev, msi_control_reg(pos), | ||
| 1311 | &control); | ||
| 1312 | pci_read_config_dword(dev, msix_table_offset_reg(pos), | ||
| 1313 | &table_offset); | ||
| 1314 | bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); | ||
| 1315 | table_offset &= ~PCI_MSIX_FLAGS_BIRMASK; | ||
| 1316 | phys_addr = pci_resource_start(dev, bir) + table_offset; | ||
| 1317 | /* | ||
| 1318 | * FIXME! and what did you want to do with phys_addr? | ||
| 1319 | */ | ||
| 1320 | #endif | ||
| 1321 | iounmap(base); | 1338 | iounmap(base); |
| 1322 | printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " | 1339 | printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " |
| 1323 | "called without free_irq() on all MSI-X vectors\n", | 1340 | "called without free_irq() on all MSI-X vectors\n", |
