diff options
-rw-r--r-- | drivers/pci/msi.c | 195 | ||||
-rw-r--r-- | drivers/pci/msi.h | 9 | ||||
-rw-r--r-- | include/linux/pci.h | 6 |
3 files changed, 104 insertions, 106 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 75d1c0dacffa..cca6cb3ccdac 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -87,63 +87,100 @@ static void msi_set_mask_bit(unsigned int vector, int flag) | |||
87 | } | 87 | } |
88 | } | 88 | } |
89 | 89 | ||
90 | #ifdef CONFIG_SMP | 90 | static void read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) |
91 | static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) | ||
92 | { | 91 | { |
93 | struct msi_desc *entry; | 92 | switch(entry->msi_attrib.type) { |
94 | u32 address_hi, address_lo; | 93 | case PCI_CAP_ID_MSI: |
95 | unsigned int irq = vector; | 94 | { |
96 | unsigned int dest_cpu = first_cpu(cpu_mask); | 95 | struct pci_dev *dev = entry->dev; |
97 | 96 | int pos = entry->msi_attrib.pos; | |
98 | entry = (struct msi_desc *)msi_desc[vector]; | 97 | u16 data; |
99 | if (!entry || !entry->dev) | 98 | |
100 | return; | 99 | pci_read_config_dword(dev, msi_lower_address_reg(pos), |
100 | &msg->address_lo); | ||
101 | if (entry->msi_attrib.is_64) { | ||
102 | pci_read_config_dword(dev, msi_upper_address_reg(pos), | ||
103 | &msg->address_hi); | ||
104 | pci_read_config_word(dev, msi_data_reg(pos, 1), &data); | ||
105 | } else { | ||
106 | msg->address_hi = 0; | ||
107 | pci_read_config_word(dev, msi_data_reg(pos, 1), &data); | ||
108 | } | ||
109 | msg->data = data; | ||
110 | break; | ||
111 | } | ||
112 | case PCI_CAP_ID_MSIX: | ||
113 | { | ||
114 | void __iomem *base; | ||
115 | base = entry->mask_base + | ||
116 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; | ||
117 | |||
118 | msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | ||
119 | msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | ||
120 | msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET); | ||
121 | break; | ||
122 | } | ||
123 | default: | ||
124 | BUG(); | ||
125 | } | ||
126 | } | ||
101 | 127 | ||
128 | static void write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) | ||
129 | { | ||
102 | switch (entry->msi_attrib.type) { | 130 | switch (entry->msi_attrib.type) { |
103 | case PCI_CAP_ID_MSI: | 131 | case PCI_CAP_ID_MSI: |
104 | { | 132 | { |
105 | int pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI); | 133 | struct pci_dev *dev = entry->dev; |
106 | 134 | int pos = entry->msi_attrib.pos; | |
107 | if (!pos) | 135 | |
108 | return; | 136 | pci_write_config_dword(dev, msi_lower_address_reg(pos), |
109 | 137 | msg->address_lo); | |
110 | pci_read_config_dword(entry->dev, msi_upper_address_reg(pos), | 138 | if (entry->msi_attrib.is_64) { |
111 | &address_hi); | 139 | pci_write_config_dword(dev, msi_upper_address_reg(pos), |
112 | pci_read_config_dword(entry->dev, msi_lower_address_reg(pos), | 140 | msg->address_hi); |
113 | &address_lo); | 141 | pci_write_config_word(dev, msi_data_reg(pos, 1), |
114 | 142 | msg->data); | |
115 | msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); | 143 | } else { |
116 | 144 | pci_write_config_word(dev, msi_data_reg(pos, 0), | |
117 | pci_write_config_dword(entry->dev, msi_upper_address_reg(pos), | 145 | msg->data); |
118 | address_hi); | 146 | } |
119 | pci_write_config_dword(entry->dev, msi_lower_address_reg(pos), | ||
120 | address_lo); | ||
121 | set_native_irq_info(irq, cpu_mask); | ||
122 | break; | 147 | break; |
123 | } | 148 | } |
124 | case PCI_CAP_ID_MSIX: | 149 | case PCI_CAP_ID_MSIX: |
125 | { | 150 | { |
126 | int offset_hi = | 151 | void __iomem *base; |
127 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + | 152 | base = entry->mask_base + |
128 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET; | 153 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; |
129 | int offset_lo = | 154 | |
130 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + | 155 | writel(msg->address_lo, |
131 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET; | 156 | base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); |
132 | 157 | writel(msg->address_hi, | |
133 | address_hi = readl(entry->mask_base + offset_hi); | 158 | base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); |
134 | address_lo = readl(entry->mask_base + offset_lo); | 159 | writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET); |
135 | |||
136 | msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); | ||
137 | |||
138 | writel(address_hi, entry->mask_base + offset_hi); | ||
139 | writel(address_lo, entry->mask_base + offset_lo); | ||
140 | set_native_irq_info(irq, cpu_mask); | ||
141 | break; | 160 | break; |
142 | } | 161 | } |
143 | default: | 162 | default: |
144 | break; | 163 | BUG(); |
145 | } | 164 | } |
146 | } | 165 | } |
166 | |||
167 | #ifdef CONFIG_SMP | ||
168 | static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) | ||
169 | { | ||
170 | struct msi_desc *entry; | ||
171 | struct msi_msg msg; | ||
172 | unsigned int irq = vector; | ||
173 | unsigned int dest_cpu = first_cpu(cpu_mask); | ||
174 | |||
175 | entry = (struct msi_desc *)msi_desc[vector]; | ||
176 | if (!entry || !entry->dev) | ||
177 | return; | ||
178 | |||
179 | read_msi_msg(entry, &msg); | ||
180 | msi_ops->target(vector, dest_cpu, &msg.address_hi, &msg.address_lo); | ||
181 | write_msi_msg(entry, &msg); | ||
182 | set_native_irq_info(irq, cpu_mask); | ||
183 | } | ||
147 | #else | 184 | #else |
148 | #define set_msi_affinity NULL | 185 | #define set_msi_affinity NULL |
149 | #endif /* CONFIG_SMP */ | 186 | #endif /* CONFIG_SMP */ |
@@ -606,23 +643,10 @@ int pci_save_msix_state(struct pci_dev *dev) | |||
606 | 643 | ||
607 | vector = head = dev->irq; | 644 | vector = head = dev->irq; |
608 | while (head != tail) { | 645 | while (head != tail) { |
609 | int j; | ||
610 | void __iomem *base; | ||
611 | struct msi_desc *entry; | 646 | struct msi_desc *entry; |
612 | 647 | ||
613 | entry = msi_desc[vector]; | 648 | entry = msi_desc[vector]; |
614 | base = entry->mask_base; | 649 | read_msi_msg(entry, &entry->msg_save); |
615 | j = entry->msi_attrib.entry_nr; | ||
616 | |||
617 | entry->address_lo_save = | ||
618 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
619 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | ||
620 | entry->address_hi_save = | ||
621 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
622 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | ||
623 | entry->data_save = | ||
624 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
625 | PCI_MSIX_ENTRY_DATA_OFFSET); | ||
626 | 650 | ||
627 | tail = msi_desc[vector]->link.tail; | 651 | tail = msi_desc[vector]->link.tail; |
628 | vector = tail; | 652 | vector = tail; |
@@ -639,8 +663,6 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
639 | u16 save; | 663 | u16 save; |
640 | int pos; | 664 | int pos; |
641 | int vector, head, tail = 0; | 665 | int vector, head, tail = 0; |
642 | void __iomem *base; | ||
643 | int j; | ||
644 | struct msi_desc *entry; | 666 | struct msi_desc *entry; |
645 | int temp; | 667 | int temp; |
646 | struct pci_cap_saved_state *save_state; | 668 | struct pci_cap_saved_state *save_state; |
@@ -663,18 +685,7 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
663 | vector = head = dev->irq; | 685 | vector = head = dev->irq; |
664 | while (head != tail) { | 686 | while (head != tail) { |
665 | entry = msi_desc[vector]; | 687 | entry = msi_desc[vector]; |
666 | base = entry->mask_base; | 688 | write_msi_msg(entry, &entry->msg_save); |
667 | j = entry->msi_attrib.entry_nr; | ||
668 | |||
669 | writel(entry->address_lo_save, | ||
670 | base + j * PCI_MSIX_ENTRY_SIZE + | ||
671 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | ||
672 | writel(entry->address_hi_save, | ||
673 | base + j * PCI_MSIX_ENTRY_SIZE + | ||
674 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | ||
675 | writel(entry->data_save, | ||
676 | base + j * PCI_MSIX_ENTRY_SIZE + | ||
677 | PCI_MSIX_ENTRY_DATA_OFFSET); | ||
678 | 689 | ||
679 | tail = msi_desc[vector]->link.tail; | 690 | tail = msi_desc[vector]->link.tail; |
680 | vector = tail; | 691 | vector = tail; |
@@ -689,29 +700,19 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
689 | static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | 700 | static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) |
690 | { | 701 | { |
691 | int status; | 702 | int status; |
692 | u32 address_hi; | 703 | struct msi_msg msg; |
693 | u32 address_lo; | ||
694 | u32 data; | ||
695 | int pos, vector = dev->irq; | 704 | int pos, vector = dev->irq; |
696 | u16 control; | 705 | u16 control; |
697 | 706 | ||
698 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | 707 | pos = entry->msi_attrib.pos; |
699 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 708 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
700 | 709 | ||
701 | /* Configure MSI capability structure */ | 710 | /* Configure MSI capability structure */ |
702 | status = msi_ops->setup(dev, vector, &address_hi, &address_lo, &data); | 711 | status = msi_ops->setup(dev, vector, &msg.address_hi, &msg.address_lo, &msg.data); |
703 | if (status < 0) | 712 | if (status < 0) |
704 | return status; | 713 | return status; |
705 | 714 | ||
706 | pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo); | 715 | write_msi_msg(entry, &msg); |
707 | if (is_64bit_address(control)) { | ||
708 | pci_write_config_dword(dev, | ||
709 | msi_upper_address_reg(pos), address_hi); | ||
710 | pci_write_config_word(dev, | ||
711 | msi_data_reg(pos, 1), data); | ||
712 | } else | ||
713 | pci_write_config_word(dev, | ||
714 | msi_data_reg(pos, 0), data); | ||
715 | if (entry->msi_attrib.maskbit) { | 716 | if (entry->msi_attrib.maskbit) { |
716 | unsigned int maskbits, temp; | 717 | unsigned int maskbits, temp; |
717 | /* All MSIs are unmasked by default, Mask them all */ | 718 | /* All MSIs are unmasked by default, Mask them all */ |
@@ -761,9 +762,11 @@ static int msi_capability_init(struct pci_dev *dev) | |||
761 | entry->link.tail = vector; | 762 | entry->link.tail = vector; |
762 | entry->msi_attrib.type = PCI_CAP_ID_MSI; | 763 | entry->msi_attrib.type = PCI_CAP_ID_MSI; |
763 | entry->msi_attrib.state = 0; /* Mark it not active */ | 764 | entry->msi_attrib.state = 0; /* Mark it not active */ |
765 | entry->msi_attrib.is_64 = is_64bit_address(control); | ||
764 | entry->msi_attrib.entry_nr = 0; | 766 | entry->msi_attrib.entry_nr = 0; |
765 | entry->msi_attrib.maskbit = is_mask_bit_support(control); | 767 | entry->msi_attrib.maskbit = is_mask_bit_support(control); |
766 | entry->msi_attrib.default_vector = dev->irq; /* Save IOAPIC IRQ */ | 768 | entry->msi_attrib.default_vector = dev->irq; /* Save IOAPIC IRQ */ |
769 | entry->msi_attrib.pos = pos; | ||
767 | dev->irq = vector; | 770 | dev->irq = vector; |
768 | entry->dev = dev; | 771 | entry->dev = dev; |
769 | if (is_mask_bit_support(control)) { | 772 | if (is_mask_bit_support(control)) { |
@@ -801,9 +804,7 @@ static int msix_capability_init(struct pci_dev *dev, | |||
801 | struct msix_entry *entries, int nvec) | 804 | struct msix_entry *entries, int nvec) |
802 | { | 805 | { |
803 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; | 806 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; |
804 | u32 address_hi; | 807 | struct msi_msg msg; |
805 | u32 address_lo; | ||
806 | u32 data; | ||
807 | int status; | 808 | int status; |
808 | int vector, pos, i, j, nr_entries, temp = 0; | 809 | int vector, pos, i, j, nr_entries, temp = 0; |
809 | unsigned long phys_addr; | 810 | unsigned long phys_addr; |
@@ -840,9 +841,11 @@ static int msix_capability_init(struct pci_dev *dev, | |||
840 | entries[i].vector = vector; | 841 | entries[i].vector = vector; |
841 | entry->msi_attrib.type = PCI_CAP_ID_MSIX; | 842 | entry->msi_attrib.type = PCI_CAP_ID_MSIX; |
842 | entry->msi_attrib.state = 0; /* Mark it not active */ | 843 | entry->msi_attrib.state = 0; /* Mark it not active */ |
844 | entry->msi_attrib.is_64 = 1; | ||
843 | entry->msi_attrib.entry_nr = j; | 845 | entry->msi_attrib.entry_nr = j; |
844 | entry->msi_attrib.maskbit = 1; | 846 | entry->msi_attrib.maskbit = 1; |
845 | entry->msi_attrib.default_vector = dev->irq; | 847 | entry->msi_attrib.default_vector = dev->irq; |
848 | entry->msi_attrib.pos = pos; | ||
846 | entry->dev = dev; | 849 | entry->dev = dev; |
847 | entry->mask_base = base; | 850 | entry->mask_base = base; |
848 | if (!head) { | 851 | if (!head) { |
@@ -861,21 +864,13 @@ static int msix_capability_init(struct pci_dev *dev, | |||
861 | irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); | 864 | irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); |
862 | /* Configure MSI-X capability structure */ | 865 | /* Configure MSI-X capability structure */ |
863 | status = msi_ops->setup(dev, vector, | 866 | status = msi_ops->setup(dev, vector, |
864 | &address_hi, | 867 | &msg.address_hi, |
865 | &address_lo, | 868 | &msg.address_lo, |
866 | &data); | 869 | &msg.data); |
867 | if (status < 0) | 870 | if (status < 0) |
868 | break; | 871 | break; |
869 | 872 | ||
870 | writel(address_lo, | 873 | write_msi_msg(entry, &msg); |
871 | base + j * PCI_MSIX_ENTRY_SIZE + | ||
872 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | ||
873 | writel(address_hi, | ||
874 | base + j * PCI_MSIX_ENTRY_SIZE + | ||
875 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | ||
876 | writel(data, | ||
877 | base + j * PCI_MSIX_ENTRY_SIZE + | ||
878 | PCI_MSIX_ENTRY_DATA_OFFSET); | ||
879 | attach_msi_entry(entry, vector); | 874 | attach_msi_entry(entry, vector); |
880 | } | 875 | } |
881 | if (i != nvec) { | 876 | if (i != nvec) { |
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 9b31d4cbbce4..62f61b61d2c9 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h | |||
@@ -130,10 +130,10 @@ struct msi_desc { | |||
130 | __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ | 130 | __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ |
131 | __u8 maskbit : 1; /* mask-pending bit supported ? */ | 131 | __u8 maskbit : 1; /* mask-pending bit supported ? */ |
132 | __u8 state : 1; /* {0: free, 1: busy} */ | 132 | __u8 state : 1; /* {0: free, 1: busy} */ |
133 | __u8 reserved: 1; /* reserved */ | 133 | __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */ |
134 | __u8 entry_nr; /* specific enabled entry */ | 134 | __u8 entry_nr; /* specific enabled entry */ |
135 | __u8 default_vector; /* default pre-assigned vector */ | 135 | __u8 default_vector; /* default pre-assigned vector */ |
136 | __u8 unused; /* formerly unused destination cpu*/ | 136 | __u8 pos; /* Location of the msi capability */ |
137 | }msi_attrib; | 137 | }msi_attrib; |
138 | 138 | ||
139 | struct { | 139 | struct { |
@@ -146,10 +146,7 @@ struct msi_desc { | |||
146 | 146 | ||
147 | #ifdef CONFIG_PM | 147 | #ifdef CONFIG_PM |
148 | /* PM save area for MSIX address/data */ | 148 | /* PM save area for MSIX address/data */ |
149 | 149 | struct msi_msg msg_save; | |
150 | u32 address_hi_save; | ||
151 | u32 address_lo_save; | ||
152 | u32 data_save; | ||
153 | #endif | 150 | #endif |
154 | }; | 151 | }; |
155 | 152 | ||
diff --git a/include/linux/pci.h b/include/linux/pci.h index 4431ce4e1e6f..b9bb6c46e056 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -595,6 +595,12 @@ struct msix_entry { | |||
595 | u16 entry; /* driver uses to specify entry, OS writes */ | 595 | u16 entry; /* driver uses to specify entry, OS writes */ |
596 | }; | 596 | }; |
597 | 597 | ||
598 | struct msi_msg { | ||
599 | u32 address_lo; /* low 32 bits of msi message address */ | ||
600 | u32 address_hi; /* high 32 bits of msi message address */ | ||
601 | u32 data; /* 16 bits of msi message data */ | ||
602 | }; | ||
603 | |||
598 | #ifndef CONFIG_PCI_MSI | 604 | #ifndef CONFIG_PCI_MSI |
599 | static inline void pci_scan_msi_device(struct pci_dev *dev) {} | 605 | static inline void pci_scan_msi_device(struct pci_dev *dev) {} |
600 | static inline int pci_enable_msi(struct pci_dev *dev) {return -1;} | 606 | static inline int pci_enable_msi(struct pci_dev *dev) {return -1;} |