2 * Support of MSI, HPET and DMAR interrupts.
4 * Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
5 * Moved from arch/x86/kernel/apic/io_apic.c.
6 * Jiang Liu <jiang.liu@linux.intel.com>
7 * Convert to hierarchical irqdomain
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
14 #include <linux/interrupt.h>
15 #include <linux/pci.h>
16 #include <linux/dmar.h>
17 #include <linux/hpet.h>
18 #include <linux/msi.h>
19 #include <linux/irqdomain.h>
20 #include <asm/msidef.h>
22 #include <asm/hw_irq.h>
24 #include <asm/irq_remapping.h>
26 static struct irq_domain
*msi_default_domain
;
28 void native_compose_msi_msg(struct pci_dev
*pdev
,
29 unsigned int irq
, unsigned int dest
,
30 struct msi_msg
*msg
, u8 hpet_id
)
32 struct irq_cfg
*cfg
= irq_cfg(irq
);
34 msg
->address_hi
= MSI_ADDR_BASE_HI
;
37 msg
->address_hi
|= MSI_ADDR_EXT_DEST_ID(dest
);
41 ((apic
->irq_dest_mode
== 0) ?
42 MSI_ADDR_DEST_MODE_PHYSICAL
:
43 MSI_ADDR_DEST_MODE_LOGICAL
) |
44 ((apic
->irq_delivery_mode
!= dest_LowestPrio
) ?
45 MSI_ADDR_REDIRECTION_CPU
:
46 MSI_ADDR_REDIRECTION_LOWPRI
) |
47 MSI_ADDR_DEST_ID(dest
);
50 MSI_DATA_TRIGGER_EDGE
|
51 MSI_DATA_LEVEL_ASSERT
|
52 ((apic
->irq_delivery_mode
!= dest_LowestPrio
) ?
53 MSI_DATA_DELIVERY_FIXED
:
54 MSI_DATA_DELIVERY_LOWPRI
) |
55 MSI_DATA_VECTOR(cfg
->vector
);
58 static void irq_msi_compose_msg(struct irq_data
*data
, struct msi_msg
*msg
)
60 struct irq_cfg
*cfg
= irqd_cfg(data
);
62 msg
->address_hi
= MSI_ADDR_BASE_HI
;
65 msg
->address_hi
|= MSI_ADDR_EXT_DEST_ID(cfg
->dest_apicid
);
69 ((apic
->irq_dest_mode
== 0) ?
70 MSI_ADDR_DEST_MODE_PHYSICAL
:
71 MSI_ADDR_DEST_MODE_LOGICAL
) |
72 ((apic
->irq_delivery_mode
!= dest_LowestPrio
) ?
73 MSI_ADDR_REDIRECTION_CPU
:
74 MSI_ADDR_REDIRECTION_LOWPRI
) |
75 MSI_ADDR_DEST_ID(cfg
->dest_apicid
);
78 MSI_DATA_TRIGGER_EDGE
|
79 MSI_DATA_LEVEL_ASSERT
|
80 ((apic
->irq_delivery_mode
!= dest_LowestPrio
) ?
81 MSI_DATA_DELIVERY_FIXED
:
82 MSI_DATA_DELIVERY_LOWPRI
) |
83 MSI_DATA_VECTOR(cfg
->vector
);
86 static void msi_update_msg(struct msi_msg
*msg
, struct irq_data
*irq_data
)
88 struct irq_cfg
*cfg
= irqd_cfg(irq_data
);
90 msg
->data
&= ~MSI_DATA_VECTOR_MASK
;
91 msg
->data
|= MSI_DATA_VECTOR(cfg
->vector
);
92 msg
->address_lo
&= ~MSI_ADDR_DEST_ID_MASK
;
93 msg
->address_lo
|= MSI_ADDR_DEST_ID(cfg
->dest_apicid
);
96 static int msi_compose_msg(struct pci_dev
*pdev
, unsigned int irq
,
97 struct msi_msg
*msg
, u8 hpet_id
)
107 err
= assign_irq_vector(irq
, cfg
, apic
->target_cpus());
111 err
= apic
->cpu_mask_to_apicid_and(cfg
->domain
,
112 apic
->target_cpus(), &dest
);
116 x86_msi
.compose_msi_msg(pdev
, irq
, dest
, msg
, hpet_id
);
122 * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
123 * which implement the MSI or MSI-X Capability Structure.
125 static struct irq_chip pci_msi_controller
= {
127 .irq_unmask
= pci_msi_unmask_irq
,
128 .irq_mask
= pci_msi_mask_irq
,
129 .irq_ack
= irq_chip_ack_parent
,
130 .irq_set_affinity
= msi_domain_set_affinity
,
131 .irq_retrigger
= irq_chip_retrigger_hierarchy
,
132 .irq_print_chip
= irq_remapping_print_chip
,
133 .irq_compose_msi_msg
= irq_msi_compose_msg
,
134 .irq_write_msi_msg
= pci_msi_domain_write_msg
,
135 .flags
= IRQCHIP_SKIP_SET_WAKE
,
138 int native_setup_msi_irqs(struct pci_dev
*dev
, int nvec
, int type
)
140 struct irq_domain
*domain
;
141 struct irq_alloc_info info
;
143 init_irq_alloc_info(&info
, NULL
);
144 info
.type
= X86_IRQ_ALLOC_TYPE_MSI
;
147 domain
= irq_remapping_get_irq_domain(&info
);
149 domain
= msi_default_domain
;
153 return pci_msi_domain_alloc_irqs(domain
, dev
, nvec
, type
);
156 void native_teardown_msi_irq(unsigned int irq
)
158 irq_domain_free_irqs(irq
, 1);
161 static irq_hw_number_t
pci_msi_get_hwirq(struct msi_domain_info
*info
,
162 msi_alloc_info_t
*arg
)
164 return arg
->msi_hwirq
;
167 static int pci_msi_prepare(struct irq_domain
*domain
, struct device
*dev
,
168 int nvec
, msi_alloc_info_t
*arg
)
170 struct pci_dev
*pdev
= to_pci_dev(dev
);
171 struct msi_desc
*desc
= first_pci_msi_entry(pdev
);
173 init_irq_alloc_info(arg
, NULL
);
175 if (desc
->msi_attrib
.is_msix
) {
176 arg
->type
= X86_IRQ_ALLOC_TYPE_MSIX
;
178 arg
->type
= X86_IRQ_ALLOC_TYPE_MSI
;
179 arg
->flags
|= X86_IRQ_ALLOC_CONTIGUOUS_VECTORS
;
185 static void pci_msi_set_desc(msi_alloc_info_t
*arg
, struct msi_desc
*desc
)
187 arg
->msi_hwirq
= pci_msi_domain_calc_hwirq(arg
->msi_dev
, desc
);
190 static struct msi_domain_ops pci_msi_domain_ops
= {
191 .get_hwirq
= pci_msi_get_hwirq
,
192 .msi_prepare
= pci_msi_prepare
,
193 .set_desc
= pci_msi_set_desc
,
196 static struct msi_domain_info pci_msi_domain_info
= {
197 .flags
= MSI_FLAG_USE_DEF_DOM_OPS
| MSI_FLAG_USE_DEF_CHIP_OPS
|
198 MSI_FLAG_MULTI_PCI_MSI
| MSI_FLAG_PCI_MSIX
,
199 .ops
= &pci_msi_domain_ops
,
200 .chip
= &pci_msi_controller
,
201 .handler
= handle_edge_irq
,
202 .handler_name
= "edge",
205 void arch_init_msi_domain(struct irq_domain
*parent
)
210 msi_default_domain
= pci_msi_create_irq_domain(NULL
,
211 &pci_msi_domain_info
, parent
);
212 if (!msi_default_domain
)
213 pr_warn("failed to initialize irqdomain for MSI/MSI-x.\n");
216 #ifdef CONFIG_IRQ_REMAP
217 struct irq_domain
*arch_create_msi_irq_domain(struct irq_domain
*parent
)
219 return msi_create_irq_domain(NULL
, &pci_msi_domain_info
, parent
);
223 #ifdef CONFIG_DMAR_TABLE
225 dmar_msi_set_affinity(struct irq_data
*data
, const struct cpumask
*mask
,
228 struct irq_cfg
*cfg
= irqd_cfg(data
);
229 unsigned int dest
, irq
= data
->irq
;
233 ret
= apic_set_affinity(data
, mask
, &dest
);
237 dmar_msi_read(irq
, &msg
);
239 msg
.data
&= ~MSI_DATA_VECTOR_MASK
;
240 msg
.data
|= MSI_DATA_VECTOR(cfg
->vector
);
241 msg
.address_lo
&= ~MSI_ADDR_DEST_ID_MASK
;
242 msg
.address_lo
|= MSI_ADDR_DEST_ID(dest
);
243 msg
.address_hi
= MSI_ADDR_BASE_HI
| MSI_ADDR_EXT_DEST_ID(dest
);
245 dmar_msi_write(irq
, &msg
);
247 return IRQ_SET_MASK_OK_NOCOPY
;
250 static struct irq_chip dmar_msi_type
= {
252 .irq_unmask
= dmar_msi_unmask
,
253 .irq_mask
= dmar_msi_mask
,
254 .irq_ack
= apic_ack_edge
,
255 .irq_set_affinity
= dmar_msi_set_affinity
,
256 .irq_retrigger
= apic_retrigger_irq
,
257 .flags
= IRQCHIP_SKIP_SET_WAKE
,
260 int arch_setup_dmar_msi(unsigned int irq
)
265 ret
= msi_compose_msg(NULL
, irq
, &msg
, -1);
268 dmar_msi_write(irq
, &msg
);
269 irq_set_chip_and_handler_name(irq
, &dmar_msi_type
, handle_edge_irq
,
274 int dmar_alloc_hwirq(void)
276 return irq_domain_alloc_irqs(NULL
, 1, NUMA_NO_NODE
, NULL
);
279 void dmar_free_hwirq(int irq
)
281 irq_domain_free_irqs(irq
, 1);
286 * MSI message composition
288 #ifdef CONFIG_HPET_TIMER
289 static inline int hpet_dev_id(struct irq_domain
*domain
)
291 return (int)(long)domain
->host_data
;
294 static int hpet_msi_set_affinity(struct irq_data
*data
,
295 const struct cpumask
*mask
, bool force
)
297 struct irq_data
*parent
= data
->parent_data
;
301 ret
= parent
->chip
->irq_set_affinity(parent
, mask
, force
);
302 if (ret
>= 0 && ret
!= IRQ_SET_MASK_OK_DONE
) {
303 hpet_msi_read(data
->handler_data
, &msg
);
304 msi_update_msg(&msg
, data
);
305 hpet_msi_write(data
->handler_data
, &msg
);
311 static struct irq_chip hpet_msi_controller
= {
313 .irq_unmask
= hpet_msi_unmask
,
314 .irq_mask
= hpet_msi_mask
,
315 .irq_ack
= irq_chip_ack_parent
,
316 .irq_set_affinity
= hpet_msi_set_affinity
,
317 .irq_retrigger
= irq_chip_retrigger_hierarchy
,
318 .irq_print_chip
= irq_remapping_print_chip
,
319 .irq_compose_msi_msg
= irq_msi_compose_msg
,
320 .flags
= IRQCHIP_SKIP_SET_WAKE
,
323 int default_setup_hpet_msi(unsigned int irq
, unsigned int id
)
325 struct irq_chip
*chip
= &hpet_msi_controller
;
329 ret
= msi_compose_msg(NULL
, irq
, &msg
, id
);
333 hpet_msi_write(irq_get_handler_data(irq
), &msg
);
334 irq_set_status_flags(irq
, IRQ_MOVE_PCNTXT
);
335 setup_remapped_irq(irq
, irq_cfg(irq
), chip
);
337 irq_set_chip_and_handler_name(irq
, chip
, handle_edge_irq
, "edge");
341 static int hpet_domain_alloc(struct irq_domain
*domain
, unsigned int virq
,
342 unsigned int nr_irqs
, void *arg
)
344 struct irq_alloc_info
*info
= arg
;
347 if (nr_irqs
> 1 || !info
|| info
->type
!= X86_IRQ_ALLOC_TYPE_HPET
)
349 if (irq_find_mapping(domain
, info
->hpet_index
)) {
350 pr_warn("IRQ for HPET%d already exists.\n", info
->hpet_index
);
354 ret
= irq_domain_alloc_irqs_parent(domain
, virq
, nr_irqs
, arg
);
356 irq_set_status_flags(virq
, IRQ_MOVE_PCNTXT
);
357 irq_domain_set_hwirq_and_chip(domain
, virq
, info
->hpet_index
,
358 &hpet_msi_controller
, NULL
);
359 irq_set_handler_data(virq
, info
->hpet_data
);
360 __irq_set_handler(virq
, handle_edge_irq
, 0, "edge");
366 static void hpet_domain_free(struct irq_domain
*domain
, unsigned int virq
,
367 unsigned int nr_irqs
)
370 irq_clear_status_flags(virq
, IRQ_MOVE_PCNTXT
);
371 irq_domain_free_irqs_top(domain
, virq
, nr_irqs
);
374 static void hpet_domain_activate(struct irq_domain
*domain
,
375 struct irq_data
*irq_data
)
379 BUG_ON(irq_chip_compose_msi_msg(irq_data
, &msg
));
380 hpet_msi_write(irq_get_handler_data(irq_data
->irq
), &msg
);
383 static void hpet_domain_deactivate(struct irq_domain
*domain
,
384 struct irq_data
*irq_data
)
388 memset(&msg
, 0, sizeof(msg
));
389 hpet_msi_write(irq_get_handler_data(irq_data
->irq
), &msg
);
392 static struct irq_domain_ops hpet_domain_ops
= {
393 .alloc
= hpet_domain_alloc
,
394 .free
= hpet_domain_free
,
395 .activate
= hpet_domain_activate
,
396 .deactivate
= hpet_domain_deactivate
,
399 struct irq_domain
*hpet_create_irq_domain(int hpet_id
)
401 struct irq_domain
*parent
;
402 struct irq_alloc_info info
;
404 if (x86_vector_domain
== NULL
)
407 init_irq_alloc_info(&info
, NULL
);
408 info
.type
= X86_IRQ_ALLOC_TYPE_HPET
;
409 info
.hpet_id
= hpet_id
;
410 parent
= irq_remapping_get_ir_irq_domain(&info
);
412 parent
= x86_vector_domain
;
414 return irq_domain_add_hierarchy(parent
, 0, 0, NULL
, &hpet_domain_ops
,
415 (void *)(long)hpet_id
);
418 int hpet_assign_irq(struct irq_domain
*domain
, struct hpet_dev
*dev
,
421 struct irq_alloc_info info
;
423 init_irq_alloc_info(&info
, NULL
);
424 info
.type
= X86_IRQ_ALLOC_TYPE_HPET
;
425 info
.hpet_data
= dev
;
426 info
.hpet_id
= hpet_dev_id(domain
);
427 info
.hpet_index
= dev_num
;
429 return irq_domain_alloc_irqs(domain
, 1, NUMA_NO_NODE
, NULL
);