diff options
Diffstat (limited to 'arch/ia64/kernel/msi_ia64.c')
-rw-r--r-- | arch/ia64/kernel/msi_ia64.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c index 60c6ef67ebb2..702a09c13238 100644 --- a/arch/ia64/kernel/msi_ia64.c +++ b/arch/ia64/kernel/msi_ia64.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/pci.h> | 5 | #include <linux/pci.h> |
6 | #include <linux/irq.h> | 6 | #include <linux/irq.h> |
7 | #include <linux/msi.h> | 7 | #include <linux/msi.h> |
8 | #include <linux/dmar.h> | ||
8 | #include <asm/smp.h> | 9 | #include <asm/smp.h> |
9 | 10 | ||
10 | /* | 11 | /* |
@@ -162,3 +163,82 @@ void arch_teardown_msi_irq(unsigned int irq) | |||
162 | 163 | ||
163 | return ia64_teardown_msi_irq(irq); | 164 | return ia64_teardown_msi_irq(irq); |
164 | } | 165 | } |
166 | |||
167 | #ifdef CONFIG_DMAR | ||
168 | #ifdef CONFIG_SMP | ||
169 | static void dmar_msi_set_affinity(unsigned int irq, cpumask_t mask) | ||
170 | { | ||
171 | struct irq_cfg *cfg = irq_cfg + irq; | ||
172 | struct msi_msg msg; | ||
173 | int cpu = first_cpu(mask); | ||
174 | |||
175 | |||
176 | if (!cpu_online(cpu)) | ||
177 | return; | ||
178 | |||
179 | if (irq_prepare_move(irq, cpu)) | ||
180 | return; | ||
181 | |||
182 | dmar_msi_read(irq, &msg); | ||
183 | |||
184 | msg.data &= ~MSI_DATA_VECTOR_MASK; | ||
185 | msg.data |= MSI_DATA_VECTOR(cfg->vector); | ||
186 | msg.address_lo &= ~MSI_ADDR_DESTID_MASK; | ||
187 | msg.address_lo |= MSI_ADDR_DESTID_CPU(cpu_physical_id(cpu)); | ||
188 | |||
189 | dmar_msi_write(irq, &msg); | ||
190 | irq_desc[irq].affinity = mask; | ||
191 | } | ||
192 | #endif /* CONFIG_SMP */ | ||
193 | |||
194 | struct irq_chip dmar_msi_type = { | ||
195 | .name = "DMAR_MSI", | ||
196 | .unmask = dmar_msi_unmask, | ||
197 | .mask = dmar_msi_mask, | ||
198 | .ack = ia64_ack_msi_irq, | ||
199 | #ifdef CONFIG_SMP | ||
200 | .set_affinity = dmar_msi_set_affinity, | ||
201 | #endif | ||
202 | .retrigger = ia64_msi_retrigger_irq, | ||
203 | }; | ||
204 | |||
205 | static int | ||
206 | msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) | ||
207 | { | ||
208 | struct irq_cfg *cfg = irq_cfg + irq; | ||
209 | unsigned dest; | ||
210 | cpumask_t mask; | ||
211 | |||
212 | cpus_and(mask, irq_to_domain(irq), cpu_online_map); | ||
213 | dest = cpu_physical_id(first_cpu(mask)); | ||
214 | |||
215 | msg->address_hi = 0; | ||
216 | msg->address_lo = | ||
217 | MSI_ADDR_HEADER | | ||
218 | MSI_ADDR_DESTMODE_PHYS | | ||
219 | MSI_ADDR_REDIRECTION_CPU | | ||
220 | MSI_ADDR_DESTID_CPU(dest); | ||
221 | |||
222 | msg->data = | ||
223 | MSI_DATA_TRIGGER_EDGE | | ||
224 | MSI_DATA_LEVEL_ASSERT | | ||
225 | MSI_DATA_DELIVERY_FIXED | | ||
226 | MSI_DATA_VECTOR(cfg->vector); | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | int arch_setup_dmar_msi(unsigned int irq) | ||
231 | { | ||
232 | int ret; | ||
233 | struct msi_msg msg; | ||
234 | |||
235 | ret = msi_compose_msg(NULL, irq, &msg); | ||
236 | if (ret < 0) | ||
237 | return ret; | ||
238 | dmar_msi_write(irq, &msg); | ||
239 | set_irq_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq, | ||
240 | "edge"); | ||
241 | return 0; | ||
242 | } | ||
243 | #endif /* CONFIG_DMAR */ | ||
244 | |||