blob: fb2f1e622877e202f8bdb6be4d6922fa6431986f [file] [log] [blame]
Mark Maulefd58e552006-04-10 21:17:48 -05001/*
2 * MSI hooks for standard x86 apic
3 */
4
5#include <linux/pci.h>
6#include <linux/irq.h>
Eric W. Biederman3b7d1922006-10-04 02:16:59 -07007#include <linux/msi.h>
Fenghua Yu62fdd762008-10-17 12:14:13 -07008#include <linux/dmar.h>
Christian Kujaua4cffb62006-06-26 14:00:02 +02009#include <asm/smp.h>
Xiantao Zhang2fa89372009-02-16 15:14:48 +080010#include <asm/msidef.h>
Mark Maulefd58e552006-04-10 21:17:48 -050011
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070012static struct irq_chip ia64_msi_chip;
Mark Maulefd58e552006-04-10 21:17:48 -050013
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070014#ifdef CONFIG_SMP
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +010015static int ia64_set_msi_irq_affinity(struct irq_data *idata,
16 const cpumask_t *cpu_mask, bool force)
Mark Maulefd58e552006-04-10 21:17:48 -050017{
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070018 struct msi_msg msg;
Yasuaki Ishimatsucd378f12007-07-17 21:22:48 +090019 u32 addr, data;
Rusty Russell0de26522008-12-13 21:20:26 +103020 int cpu = first_cpu(*cpu_mask);
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +010021 unsigned int irq = idata->irq;
Mark Maulefd58e552006-04-10 21:17:48 -050022
Yasuaki Ishimatsucd378f12007-07-17 21:22:48 +090023 if (!cpu_online(cpu))
Yinghai Lud5dedd42009-04-27 17:59:21 -070024 return -1;
Yasuaki Ishimatsucd378f12007-07-17 21:22:48 +090025
Kenji Kaneshigea6cd63222008-02-25 14:32:22 +090026 if (irq_prepare_move(irq, cpu))
Yinghai Lud5dedd42009-04-27 17:59:21 -070027 return -1;
Yasuaki Ishimatsu4994be12007-07-17 21:22:33 +090028
Ben Hutchings30da5522010-07-23 14:56:28 +010029 get_cached_msi_msg(irq, &msg);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070030
31 addr = msg.address_lo;
Xiantao Zhang2fa89372009-02-16 15:14:48 +080032 addr &= MSI_ADDR_DEST_ID_MASK;
33 addr |= MSI_ADDR_DEST_ID_CPU(cpu_physical_id(cpu));
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070034 msg.address_lo = addr;
Mark Maulefd58e552006-04-10 21:17:48 -050035
Yasuaki Ishimatsucd378f12007-07-17 21:22:48 +090036 data = msg.data;
37 data &= MSI_DATA_VECTOR_MASK;
38 data |= MSI_DATA_VECTOR(irq_to_vector(irq));
39 msg.data = data;
40
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070041 write_msi_msg(irq, &msg);
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +010042 cpumask_copy(idata->affinity, cpumask_of(cpu));
Yinghai Lud5dedd42009-04-27 17:59:21 -070043
44 return 0;
Mark Maulefd58e552006-04-10 21:17:48 -050045}
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070046#endif /* CONFIG_SMP */
Mark Maulefd58e552006-04-10 21:17:48 -050047
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -070048int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
Mark Maulefd58e552006-04-10 21:17:48 -050049{
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070050 struct msi_msg msg;
Mark Maulefd58e552006-04-10 21:17:48 -050051 unsigned long dest_phys_id;
Kenji Kaneshige8a3a0ee2007-03-26 09:38:42 +090052 int irq, vector;
Yasuaki Ishimatsu4994be12007-07-17 21:22:33 +090053 cpumask_t mask;
Mark Maulefd58e552006-04-10 21:17:48 -050054
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -070055 irq = create_irq();
56 if (irq < 0)
57 return irq;
58
Thomas Gleixner53c909c2011-03-25 21:06:09 +010059 irq_set_msi_desc(irq, desc);
Srivatsa S. Bhat7d7f9842012-03-28 14:42:46 -070060 cpumask_and(&mask, &(irq_to_domain(irq)), cpu_online_mask);
Yasuaki Ishimatsu4994be12007-07-17 21:22:33 +090061 dest_phys_id = cpu_physical_id(first_cpu(mask));
Ishimatsu Yasuaki9438a122007-04-06 16:51:12 +090062 vector = irq_to_vector(irq);
Mark Maulefd58e552006-04-10 21:17:48 -050063
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070064 msg.address_hi = 0;
65 msg.address_lo =
Eric W. Biederman38bc0362006-10-04 02:16:34 -070066 MSI_ADDR_HEADER |
Xiantao Zhang2fa89372009-02-16 15:14:48 +080067 MSI_ADDR_DEST_MODE_PHYS |
Eric W. Biederman38bc0362006-10-04 02:16:34 -070068 MSI_ADDR_REDIRECTION_CPU |
Xiantao Zhang2fa89372009-02-16 15:14:48 +080069 MSI_ADDR_DEST_ID_CPU(dest_phys_id);
Mark Maulefd58e552006-04-10 21:17:48 -050070
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070071 msg.data =
Eric W. Biederman38bc0362006-10-04 02:16:34 -070072 MSI_DATA_TRIGGER_EDGE |
Mark Maulefd58e552006-04-10 21:17:48 -050073 MSI_DATA_LEVEL_ASSERT |
74 MSI_DATA_DELIVERY_FIXED |
75 MSI_DATA_VECTOR(vector);
76
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070077 write_msi_msg(irq, &msg);
Thomas Gleixner53c909c2011-03-25 21:06:09 +010078 irq_set_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070079
Kenji Kaneshige3aff0372007-10-30 16:01:49 +090080 return 0;
Mark Maulefd58e552006-04-10 21:17:48 -050081}
82
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070083void ia64_teardown_msi_irq(unsigned int irq)
Mark Maulefd58e552006-04-10 21:17:48 -050084{
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -070085 destroy_irq(irq);
Mark Maulefd58e552006-04-10 21:17:48 -050086}
87
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +010088static void ia64_ack_msi_irq(struct irq_data *data)
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070089{
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +010090 irq_complete_move(data->irq);
Thomas Gleixner97499b2e2011-03-25 20:36:55 +010091 irq_move_irq(data);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070092 ia64_eoi();
93}
Mark Maulefd58e552006-04-10 21:17:48 -050094
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +010095static int ia64_msi_retrigger_irq(struct irq_data *data)
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070096{
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +010097 unsigned int vector = irq_to_vector(data->irq);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070098 ia64_resend_irq(vector);
99
100 return 1;
101}
102
103/*
104 * Generic ops used on most IA64 platforms.
105 */
106static struct irq_chip ia64_msi_chip = {
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100107 .name = "PCI-MSI",
108 .irq_mask = mask_msi_irq,
109 .irq_unmask = unmask_msi_irq,
110 .irq_ack = ia64_ack_msi_irq,
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700111#ifdef CONFIG_SMP
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100112 .irq_set_affinity = ia64_set_msi_irq_affinity,
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700113#endif
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100114 .irq_retrigger = ia64_msi_retrigger_irq,
Mark Maulefd58e552006-04-10 21:17:48 -0500115};
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700116
117
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -0700118int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700119{
120 if (platform_setup_msi_irq)
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -0700121 return platform_setup_msi_irq(pdev, desc);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700122
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -0700123 return ia64_setup_msi_irq(pdev, desc);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700124}
125
126void arch_teardown_msi_irq(unsigned int irq)
127{
128 if (platform_teardown_msi_irq)
129 return platform_teardown_msi_irq(irq);
130
131 return ia64_teardown_msi_irq(irq);
132}
Fenghua Yu62fdd762008-10-17 12:14:13 -0700133
Suresh Siddhad3f13812011-08-23 17:05:25 -0700134#ifdef CONFIG_INTEL_IOMMU
Fenghua Yu62fdd762008-10-17 12:14:13 -0700135#ifdef CONFIG_SMP
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100136static int dmar_msi_set_affinity(struct irq_data *data,
137 const struct cpumask *mask, bool force)
Fenghua Yu62fdd762008-10-17 12:14:13 -0700138{
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100139 unsigned int irq = data->irq;
Fenghua Yu62fdd762008-10-17 12:14:13 -0700140 struct irq_cfg *cfg = irq_cfg + irq;
141 struct msi_msg msg;
Rusty Russell0de26522008-12-13 21:20:26 +1030142 int cpu = cpumask_first(mask);
Fenghua Yu62fdd762008-10-17 12:14:13 -0700143
144 if (!cpu_online(cpu))
Yinghai Lud5dedd42009-04-27 17:59:21 -0700145 return -1;
Fenghua Yu62fdd762008-10-17 12:14:13 -0700146
147 if (irq_prepare_move(irq, cpu))
Yinghai Lud5dedd42009-04-27 17:59:21 -0700148 return -1;
Fenghua Yu62fdd762008-10-17 12:14:13 -0700149
150 dmar_msi_read(irq, &msg);
151
152 msg.data &= ~MSI_DATA_VECTOR_MASK;
153 msg.data |= MSI_DATA_VECTOR(cfg->vector);
Xiantao Zhang2fa89372009-02-16 15:14:48 +0800154 msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
155 msg.address_lo |= MSI_ADDR_DEST_ID_CPU(cpu_physical_id(cpu));
Fenghua Yu62fdd762008-10-17 12:14:13 -0700156
157 dmar_msi_write(irq, &msg);
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100158 cpumask_copy(data->affinity, mask);
Yinghai Lud5dedd42009-04-27 17:59:21 -0700159
160 return 0;
Fenghua Yu62fdd762008-10-17 12:14:13 -0700161}
162#endif /* CONFIG_SMP */
163
Jaswinder Singh Rajput9542b212009-06-10 12:45:01 -0700164static struct irq_chip dmar_msi_type = {
Fenghua Yu62fdd762008-10-17 12:14:13 -0700165 .name = "DMAR_MSI",
Thomas Gleixner5c2837f2010-09-28 17:15:11 +0200166 .irq_unmask = dmar_msi_unmask,
167 .irq_mask = dmar_msi_mask,
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100168 .irq_ack = ia64_ack_msi_irq,
Fenghua Yu62fdd762008-10-17 12:14:13 -0700169#ifdef CONFIG_SMP
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100170 .irq_set_affinity = dmar_msi_set_affinity,
Fenghua Yu62fdd762008-10-17 12:14:13 -0700171#endif
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100172 .irq_retrigger = ia64_msi_retrigger_irq,
Fenghua Yu62fdd762008-10-17 12:14:13 -0700173};
174
175static int
176msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
177{
178 struct irq_cfg *cfg = irq_cfg + irq;
179 unsigned dest;
180 cpumask_t mask;
181
Srivatsa S. Bhat7d7f9842012-03-28 14:42:46 -0700182 cpumask_and(&mask, &(irq_to_domain(irq)), cpu_online_mask);
Fenghua Yu62fdd762008-10-17 12:14:13 -0700183 dest = cpu_physical_id(first_cpu(mask));
184
185 msg->address_hi = 0;
186 msg->address_lo =
187 MSI_ADDR_HEADER |
Xiantao Zhang2fa89372009-02-16 15:14:48 +0800188 MSI_ADDR_DEST_MODE_PHYS |
Fenghua Yu62fdd762008-10-17 12:14:13 -0700189 MSI_ADDR_REDIRECTION_CPU |
Xiantao Zhang2fa89372009-02-16 15:14:48 +0800190 MSI_ADDR_DEST_ID_CPU(dest);
Fenghua Yu62fdd762008-10-17 12:14:13 -0700191
192 msg->data =
193 MSI_DATA_TRIGGER_EDGE |
194 MSI_DATA_LEVEL_ASSERT |
195 MSI_DATA_DELIVERY_FIXED |
196 MSI_DATA_VECTOR(cfg->vector);
197 return 0;
198}
199
200int arch_setup_dmar_msi(unsigned int irq)
201{
202 int ret;
203 struct msi_msg msg;
204
205 ret = msi_compose_msg(NULL, irq, &msg);
206 if (ret < 0)
207 return ret;
208 dmar_msi_write(irq, &msg);
Thomas Gleixner53c909c2011-03-25 21:06:09 +0100209 irq_set_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
210 "edge");
Fenghua Yu62fdd762008-10-17 12:14:13 -0700211 return 0;
212}
Suresh Siddhad3f13812011-08-23 17:05:25 -0700213#endif /* CONFIG_INTEL_IOMMU */
Fenghua Yu62fdd762008-10-17 12:14:13 -0700214