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 9855c4c920b..7f8429284fa 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", |