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.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
12 #include <linux/interrupt.h>
13 #include <linux/pci.h>
14 #include <linux/dmar.h>
15 #include <linux/hpet.h>
16 #include <linux/msi.h>
17 #include <asm/msidef.h>
19 #include <asm/hw_irq.h>
21 #include <asm/irq_remapping.h>
23 void native_compose_msi_msg(struct pci_dev
*pdev
,
24 unsigned int irq
, unsigned int dest
,
25 struct msi_msg
*msg
, u8 hpet_id
)
27 struct irq_cfg
*cfg
= irq_cfg(irq
);
29 msg
->address_hi
= MSI_ADDR_BASE_HI
;
32 msg
->address_hi
|= MSI_ADDR_EXT_DEST_ID(dest
);
36 ((apic
->irq_dest_mode
== 0) ?
37 MSI_ADDR_DEST_MODE_PHYSICAL
:
38 MSI_ADDR_DEST_MODE_LOGICAL
) |
39 ((apic
->irq_delivery_mode
!= dest_LowestPrio
) ?
40 MSI_ADDR_REDIRECTION_CPU
:
41 MSI_ADDR_REDIRECTION_LOWPRI
) |
42 MSI_ADDR_DEST_ID(dest
);
45 MSI_DATA_TRIGGER_EDGE
|
46 MSI_DATA_LEVEL_ASSERT
|
47 ((apic
->irq_delivery_mode
!= dest_LowestPrio
) ?
48 MSI_DATA_DELIVERY_FIXED
:
49 MSI_DATA_DELIVERY_LOWPRI
) |
50 MSI_DATA_VECTOR(cfg
->vector
);
53 static int msi_compose_msg(struct pci_dev
*pdev
, unsigned int irq
,
54 struct msi_msg
*msg
, u8 hpet_id
)
64 err
= assign_irq_vector(irq
, cfg
, apic
->target_cpus());
68 err
= apic
->cpu_mask_to_apicid_and(cfg
->domain
,
69 apic
->target_cpus(), &dest
);
73 x86_msi
.compose_msi_msg(pdev
, irq
, dest
, msg
, hpet_id
);
79 msi_set_affinity(struct irq_data
*data
, const struct cpumask
*mask
, bool force
)
81 struct irq_cfg
*cfg
= irqd_cfg(data
);
86 ret
= apic_set_affinity(data
, mask
, &dest
);
90 __get_cached_msi_msg(data
->msi_desc
, &msg
);
92 msg
.data
&= ~MSI_DATA_VECTOR_MASK
;
93 msg
.data
|= MSI_DATA_VECTOR(cfg
->vector
);
94 msg
.address_lo
&= ~MSI_ADDR_DEST_ID_MASK
;
95 msg
.address_lo
|= MSI_ADDR_DEST_ID(dest
);
97 __pci_write_msi_msg(data
->msi_desc
, &msg
);
99 return IRQ_SET_MASK_OK_NOCOPY
;
103 * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
104 * which implement the MSI or MSI-X Capability Structure.
106 static struct irq_chip msi_chip
= {
108 .irq_unmask
= pci_msi_unmask_irq
,
109 .irq_mask
= pci_msi_mask_irq
,
110 .irq_ack
= apic_ack_edge
,
111 .irq_set_affinity
= msi_set_affinity
,
112 .irq_retrigger
= apic_retrigger_irq
,
113 .flags
= IRQCHIP_SKIP_SET_WAKE
,
116 int setup_msi_irq(struct pci_dev
*dev
, struct msi_desc
*msidesc
,
117 unsigned int irq_base
, unsigned int irq_offset
)
119 struct irq_chip
*chip
= &msi_chip
;
121 unsigned int irq
= irq_base
+ irq_offset
;
124 ret
= msi_compose_msg(dev
, irq
, &msg
, -1);
128 irq_set_msi_desc_off(irq_base
, irq_offset
, msidesc
);
131 * MSI-X message is written per-IRQ, the offset is always 0.
132 * MSI message denotes a contiguous group of IRQs, written for 0th IRQ.
135 pci_write_msi_msg(irq
, &msg
);
137 setup_remapped_irq(irq
, irq_cfg(irq
), chip
);
139 irq_set_chip_and_handler_name(irq
, chip
, handle_edge_irq
, "edge");
141 dev_dbg(&dev
->dev
, "irq %d for MSI/MSI-X\n", irq
);
146 int native_setup_msi_irqs(struct pci_dev
*dev
, int nvec
, int type
)
148 struct msi_desc
*msidesc
;
152 /* Multiple MSI vectors only supported with interrupt remapping */
153 if (type
== PCI_CAP_ID_MSI
&& nvec
> 1)
156 node
= dev_to_node(&dev
->dev
);
158 list_for_each_entry(msidesc
, &dev
->msi_list
, list
) {
159 irq
= irq_alloc_hwirq(node
);
163 ret
= setup_msi_irq(dev
, msidesc
, irq
, 0);
173 void native_teardown_msi_irq(unsigned int irq
)
178 #ifdef CONFIG_DMAR_TABLE
180 dmar_msi_set_affinity(struct irq_data
*data
, const struct cpumask
*mask
,
183 struct irq_cfg
*cfg
= irqd_cfg(data
);
184 unsigned int dest
, irq
= data
->irq
;
188 ret
= apic_set_affinity(data
, mask
, &dest
);
192 dmar_msi_read(irq
, &msg
);
194 msg
.data
&= ~MSI_DATA_VECTOR_MASK
;
195 msg
.data
|= MSI_DATA_VECTOR(cfg
->vector
);
196 msg
.address_lo
&= ~MSI_ADDR_DEST_ID_MASK
;
197 msg
.address_lo
|= MSI_ADDR_DEST_ID(dest
);
198 msg
.address_hi
= MSI_ADDR_BASE_HI
| MSI_ADDR_EXT_DEST_ID(dest
);
200 dmar_msi_write(irq
, &msg
);
202 return IRQ_SET_MASK_OK_NOCOPY
;
205 static struct irq_chip dmar_msi_type
= {
207 .irq_unmask
= dmar_msi_unmask
,
208 .irq_mask
= dmar_msi_mask
,
209 .irq_ack
= apic_ack_edge
,
210 .irq_set_affinity
= dmar_msi_set_affinity
,
211 .irq_retrigger
= apic_retrigger_irq
,
212 .flags
= IRQCHIP_SKIP_SET_WAKE
,
215 int arch_setup_dmar_msi(unsigned int irq
)
220 ret
= msi_compose_msg(NULL
, irq
, &msg
, -1);
223 dmar_msi_write(irq
, &msg
);
224 irq_set_chip_and_handler_name(irq
, &dmar_msi_type
, handle_edge_irq
,
231 * MSI message composition
233 #ifdef CONFIG_HPET_TIMER
235 static int hpet_msi_set_affinity(struct irq_data
*data
,
236 const struct cpumask
*mask
, bool force
)
238 struct irq_cfg
*cfg
= irqd_cfg(data
);
243 ret
= apic_set_affinity(data
, mask
, &dest
);
247 hpet_msi_read(data
->handler_data
, &msg
);
249 msg
.data
&= ~MSI_DATA_VECTOR_MASK
;
250 msg
.data
|= MSI_DATA_VECTOR(cfg
->vector
);
251 msg
.address_lo
&= ~MSI_ADDR_DEST_ID_MASK
;
252 msg
.address_lo
|= MSI_ADDR_DEST_ID(dest
);
254 hpet_msi_write(data
->handler_data
, &msg
);
256 return IRQ_SET_MASK_OK_NOCOPY
;
259 static struct irq_chip hpet_msi_type
= {
261 .irq_unmask
= hpet_msi_unmask
,
262 .irq_mask
= hpet_msi_mask
,
263 .irq_ack
= apic_ack_edge
,
264 .irq_set_affinity
= hpet_msi_set_affinity
,
265 .irq_retrigger
= apic_retrigger_irq
,
266 .flags
= IRQCHIP_SKIP_SET_WAKE
,
269 int default_setup_hpet_msi(unsigned int irq
, unsigned int id
)
271 struct irq_chip
*chip
= &hpet_msi_type
;
275 ret
= msi_compose_msg(NULL
, irq
, &msg
, id
);
279 hpet_msi_write(irq_get_handler_data(irq
), &msg
);
280 irq_set_status_flags(irq
, IRQ_MOVE_PCNTXT
);
281 setup_remapped_irq(irq
, irq_cfg(irq
), chip
);
283 irq_set_chip_and_handler_name(irq
, chip
, handle_edge_irq
, "edge");