• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/ia64/kernel/
1/*
2 * MSI hooks for standard x86 apic
3 */
4
5#include <linux/pci.h>
6#include <linux/irq.h>
7#include <linux/msi.h>
8#include <linux/dmar.h>
9#include <asm/smp.h>
10#include <asm/msidef.h>
11
12static struct irq_chip	ia64_msi_chip;
13
14#ifdef CONFIG_SMP
15static int ia64_set_msi_irq_affinity(unsigned int irq,
16				      const cpumask_t *cpu_mask)
17{
18	struct msi_msg msg;
19	u32 addr, data;
20	int cpu = first_cpu(*cpu_mask);
21
22	if (!cpu_online(cpu))
23		return -1;
24
25	if (irq_prepare_move(irq, cpu))
26		return -1;
27
28	get_cached_msi_msg(irq, &msg);
29
30	addr = msg.address_lo;
31	addr &= MSI_ADDR_DEST_ID_MASK;
32	addr |= MSI_ADDR_DEST_ID_CPU(cpu_physical_id(cpu));
33	msg.address_lo = addr;
34
35	data = msg.data;
36	data &= MSI_DATA_VECTOR_MASK;
37	data |= MSI_DATA_VECTOR(irq_to_vector(irq));
38	msg.data = data;
39
40	write_msi_msg(irq, &msg);
41	cpumask_copy(irq_desc[irq].affinity, cpumask_of(cpu));
42
43	return 0;
44}
45#endif /* CONFIG_SMP */
46
47int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
48{
49	struct msi_msg	msg;
50	unsigned long	dest_phys_id;
51	int	irq, vector;
52	cpumask_t mask;
53
54	irq = create_irq();
55	if (irq < 0)
56		return irq;
57
58	set_irq_msi(irq, desc);
59	cpus_and(mask, irq_to_domain(irq), cpu_online_map);
60	dest_phys_id = cpu_physical_id(first_cpu(mask));
61	vector = irq_to_vector(irq);
62
63	msg.address_hi = 0;
64	msg.address_lo =
65		MSI_ADDR_HEADER |
66		MSI_ADDR_DEST_MODE_PHYS |
67		MSI_ADDR_REDIRECTION_CPU |
68		MSI_ADDR_DEST_ID_CPU(dest_phys_id);
69
70	msg.data =
71		MSI_DATA_TRIGGER_EDGE |
72		MSI_DATA_LEVEL_ASSERT |
73		MSI_DATA_DELIVERY_FIXED |
74		MSI_DATA_VECTOR(vector);
75
76	write_msi_msg(irq, &msg);
77	set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
78
79	return 0;
80}
81
82void ia64_teardown_msi_irq(unsigned int irq)
83{
84	destroy_irq(irq);
85}
86
87static void ia64_ack_msi_irq(unsigned int irq)
88{
89	irq_complete_move(irq);
90	move_native_irq(irq);
91	ia64_eoi();
92}
93
94static int ia64_msi_retrigger_irq(unsigned int irq)
95{
96	unsigned int vector = irq_to_vector(irq);
97	ia64_resend_irq(vector);
98
99	return 1;
100}
101
102/*
103 * Generic ops used on most IA64 platforms.
104 */
105static struct irq_chip ia64_msi_chip = {
106	.name		= "PCI-MSI",
107	.mask		= mask_msi_irq,
108	.unmask		= unmask_msi_irq,
109	.ack		= ia64_ack_msi_irq,
110#ifdef CONFIG_SMP
111	.set_affinity	= ia64_set_msi_irq_affinity,
112#endif
113	.retrigger	= ia64_msi_retrigger_irq,
114};
115
116
117int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
118{
119	if (platform_setup_msi_irq)
120		return platform_setup_msi_irq(pdev, desc);
121
122	return ia64_setup_msi_irq(pdev, desc);
123}
124
125void arch_teardown_msi_irq(unsigned int irq)
126{
127	if (platform_teardown_msi_irq)
128		return platform_teardown_msi_irq(irq);
129
130	return ia64_teardown_msi_irq(irq);
131}
132
133#ifdef CONFIG_DMAR
134#ifdef CONFIG_SMP
135static int dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
136{
137	struct irq_cfg *cfg = irq_cfg + irq;
138	struct msi_msg msg;
139	int cpu = cpumask_first(mask);
140
141	if (!cpu_online(cpu))
142		return -1;
143
144	if (irq_prepare_move(irq, cpu))
145		return -1;
146
147	dmar_msi_read(irq, &msg);
148
149	msg.data &= ~MSI_DATA_VECTOR_MASK;
150	msg.data |= MSI_DATA_VECTOR(cfg->vector);
151	msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
152	msg.address_lo |= MSI_ADDR_DEST_ID_CPU(cpu_physical_id(cpu));
153
154	dmar_msi_write(irq, &msg);
155	cpumask_copy(irq_desc[irq].affinity, mask);
156
157	return 0;
158}
159#endif /* CONFIG_SMP */
160
161static struct irq_chip dmar_msi_type = {
162	.name = "DMAR_MSI",
163	.unmask = dmar_msi_unmask,
164	.mask = dmar_msi_mask,
165	.ack = ia64_ack_msi_irq,
166#ifdef CONFIG_SMP
167	.set_affinity = dmar_msi_set_affinity,
168#endif
169	.retrigger = ia64_msi_retrigger_irq,
170};
171
172static int
173msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
174{
175	struct irq_cfg *cfg = irq_cfg + irq;
176	unsigned dest;
177	cpumask_t mask;
178
179	cpus_and(mask, irq_to_domain(irq), cpu_online_map);
180	dest = cpu_physical_id(first_cpu(mask));
181
182	msg->address_hi = 0;
183	msg->address_lo =
184		MSI_ADDR_HEADER |
185		MSI_ADDR_DEST_MODE_PHYS |
186		MSI_ADDR_REDIRECTION_CPU |
187		MSI_ADDR_DEST_ID_CPU(dest);
188
189	msg->data =
190		MSI_DATA_TRIGGER_EDGE |
191		MSI_DATA_LEVEL_ASSERT |
192		MSI_DATA_DELIVERY_FIXED |
193		MSI_DATA_VECTOR(cfg->vector);
194	return 0;
195}
196
197int arch_setup_dmar_msi(unsigned int irq)
198{
199	int ret;
200	struct msi_msg msg;
201
202	ret = msi_compose_msg(NULL, irq, &msg);
203	if (ret < 0)
204		return ret;
205	dmar_msi_write(irq, &msg);
206	set_irq_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
207		"edge");
208	return 0;
209}
210#endif /* CONFIG_DMAR */
211