blob: c430f9198d1bfec6b50b9d6f21d2929ef55dcf45 [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;
Thomas Gleixner785aebd2014-03-04 20:43:38 +000020 int cpu = cpumask_first_and(cpu_mask, cpu_online_mask);
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +010021 unsigned int irq = idata->irq;
Mark Maulefd58e552006-04-10 21:17:48 -050022
Kenji Kaneshigea6cd63222008-02-25 14:32:22 +090023 if (irq_prepare_move(irq, cpu))
Yinghai Lud5dedd42009-04-27 17:59:21 -070024 return -1;
Yasuaki Ishimatsu4994be12007-07-17 21:22:33 +090025
Ben Hutchings30da5522010-07-23 14:56:28 +010026 get_cached_msi_msg(irq, &msg);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070027
28 addr = msg.address_lo;
Xiantao Zhang2fa89372009-02-16 15:14:48 +080029 addr &= MSI_ADDR_DEST_ID_MASK;
30 addr |= MSI_ADDR_DEST_ID_CPU(cpu_physical_id(cpu));
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070031 msg.address_lo = addr;
Mark Maulefd58e552006-04-10 21:17:48 -050032
Yasuaki Ishimatsucd378f12007-07-17 21:22:48 +090033 data = msg.data;
34 data &= MSI_DATA_VECTOR_MASK;
35 data |= MSI_DATA_VECTOR(irq_to_vector(irq));
36 msg.data = data;
37
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070038 write_msi_msg(irq, &msg);
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +010039 cpumask_copy(idata->affinity, cpumask_of(cpu));
Yinghai Lud5dedd42009-04-27 17:59:21 -070040
41 return 0;
Mark Maulefd58e552006-04-10 21:17:48 -050042}
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070043#endif /* CONFIG_SMP */
Mark Maulefd58e552006-04-10 21:17:48 -050044
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -070045int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
Mark Maulefd58e552006-04-10 21:17:48 -050046{
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070047 struct msi_msg msg;
Mark Maulefd58e552006-04-10 21:17:48 -050048 unsigned long dest_phys_id;
Kenji Kaneshige8a3a0ee2007-03-26 09:38:42 +090049 int irq, vector;
Yasuaki Ishimatsu4994be12007-07-17 21:22:33 +090050 cpumask_t mask;
Mark Maulefd58e552006-04-10 21:17:48 -050051
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -070052 irq = create_irq();
53 if (irq < 0)
54 return irq;
55
Thomas Gleixner53c909c2011-03-25 21:06:09 +010056 irq_set_msi_desc(irq, desc);
Srivatsa S. Bhat7d7f9842012-03-28 14:42:46 -070057 cpumask_and(&mask, &(irq_to_domain(irq)), cpu_online_mask);
Yasuaki Ishimatsu4994be12007-07-17 21:22:33 +090058 dest_phys_id = cpu_physical_id(first_cpu(mask));
Ishimatsu Yasuaki9438a122007-04-06 16:51:12 +090059 vector = irq_to_vector(irq);
Mark Maulefd58e552006-04-10 21:17:48 -050060
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070061 msg.address_hi = 0;
62 msg.address_lo =
Eric W. Biederman38bc0362006-10-04 02:16:34 -070063 MSI_ADDR_HEADER |
Xiantao Zhang2fa89372009-02-16 15:14:48 +080064 MSI_ADDR_DEST_MODE_PHYS |
Eric W. Biederman38bc0362006-10-04 02:16:34 -070065 MSI_ADDR_REDIRECTION_CPU |
Xiantao Zhang2fa89372009-02-16 15:14:48 +080066 MSI_ADDR_DEST_ID_CPU(dest_phys_id);
Mark Maulefd58e552006-04-10 21:17:48 -050067
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070068 msg.data =
Eric W. Biederman38bc0362006-10-04 02:16:34 -070069 MSI_DATA_TRIGGER_EDGE |
Mark Maulefd58e552006-04-10 21:17:48 -050070 MSI_DATA_LEVEL_ASSERT |
71 MSI_DATA_DELIVERY_FIXED |
72 MSI_DATA_VECTOR(vector);
73
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070074 write_msi_msg(irq, &msg);
Thomas Gleixner53c909c2011-03-25 21:06:09 +010075 irq_set_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070076
Kenji Kaneshige3aff0372007-10-30 16:01:49 +090077 return 0;
Mark Maulefd58e552006-04-10 21:17:48 -050078}
79
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070080void ia64_teardown_msi_irq(unsigned int irq)
Mark Maulefd58e552006-04-10 21:17:48 -050081{
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -070082 destroy_irq(irq);
Mark Maulefd58e552006-04-10 21:17:48 -050083}
84
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +010085static void ia64_ack_msi_irq(struct irq_data *data)
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070086{
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +010087 irq_complete_move(data->irq);
Thomas Gleixner97499b2e2011-03-25 20:36:55 +010088 irq_move_irq(data);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070089 ia64_eoi();
90}
Mark Maulefd58e552006-04-10 21:17:48 -050091
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +010092static int ia64_msi_retrigger_irq(struct irq_data *data)
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070093{
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +010094 unsigned int vector = irq_to_vector(data->irq);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070095 ia64_resend_irq(vector);
96
97 return 1;
98}
99
100/*
101 * Generic ops used on most IA64 platforms.
102 */
103static struct irq_chip ia64_msi_chip = {
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100104 .name = "PCI-MSI",
105 .irq_mask = mask_msi_irq,
106 .irq_unmask = unmask_msi_irq,
107 .irq_ack = ia64_ack_msi_irq,
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700108#ifdef CONFIG_SMP
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100109 .irq_set_affinity = ia64_set_msi_irq_affinity,
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700110#endif
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100111 .irq_retrigger = ia64_msi_retrigger_irq,
Mark Maulefd58e552006-04-10 21:17:48 -0500112};
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700113
114
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -0700115int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700116{
117 if (platform_setup_msi_irq)
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -0700118 return platform_setup_msi_irq(pdev, desc);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700119
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -0700120 return ia64_setup_msi_irq(pdev, desc);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700121}
122
123void arch_teardown_msi_irq(unsigned int irq)
124{
125 if (platform_teardown_msi_irq)
126 return platform_teardown_msi_irq(irq);
127
128 return ia64_teardown_msi_irq(irq);
129}
Fenghua Yu62fdd762008-10-17 12:14:13 -0700130
Suresh Siddhad3f13812011-08-23 17:05:25 -0700131#ifdef CONFIG_INTEL_IOMMU
Fenghua Yu62fdd762008-10-17 12:14:13 -0700132#ifdef CONFIG_SMP
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100133static int dmar_msi_set_affinity(struct irq_data *data,
134 const struct cpumask *mask, bool force)
Fenghua Yu62fdd762008-10-17 12:14:13 -0700135{
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100136 unsigned int irq = data->irq;
Fenghua Yu62fdd762008-10-17 12:14:13 -0700137 struct irq_cfg *cfg = irq_cfg + irq;
138 struct msi_msg msg;
Thomas Gleixner785aebd2014-03-04 20:43:38 +0000139 int cpu = cpumask_first_and(mask, cpu_online_mask);
Fenghua Yu62fdd762008-10-17 12:14:13 -0700140
141 if (irq_prepare_move(irq, cpu))
Yinghai Lud5dedd42009-04-27 17:59:21 -0700142 return -1;
Fenghua Yu62fdd762008-10-17 12:14:13 -0700143
144 dmar_msi_read(irq, &msg);
145
146 msg.data &= ~MSI_DATA_VECTOR_MASK;
147 msg.data |= MSI_DATA_VECTOR(cfg->vector);
Xiantao Zhang2fa89372009-02-16 15:14:48 +0800148 msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
149 msg.address_lo |= MSI_ADDR_DEST_ID_CPU(cpu_physical_id(cpu));
Fenghua Yu62fdd762008-10-17 12:14:13 -0700150
151 dmar_msi_write(irq, &msg);
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100152 cpumask_copy(data->affinity, mask);
Yinghai Lud5dedd42009-04-27 17:59:21 -0700153
154 return 0;
Fenghua Yu62fdd762008-10-17 12:14:13 -0700155}
156#endif /* CONFIG_SMP */
157
Jaswinder Singh Rajput9542b212009-06-10 12:45:01 -0700158static struct irq_chip dmar_msi_type = {
Fenghua Yu62fdd762008-10-17 12:14:13 -0700159 .name = "DMAR_MSI",
Thomas Gleixner5c2837f2010-09-28 17:15:11 +0200160 .irq_unmask = dmar_msi_unmask,
161 .irq_mask = dmar_msi_mask,
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100162 .irq_ack = ia64_ack_msi_irq,
Fenghua Yu62fdd762008-10-17 12:14:13 -0700163#ifdef CONFIG_SMP
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100164 .irq_set_affinity = dmar_msi_set_affinity,
Fenghua Yu62fdd762008-10-17 12:14:13 -0700165#endif
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100166 .irq_retrigger = ia64_msi_retrigger_irq,
Fenghua Yu62fdd762008-10-17 12:14:13 -0700167};
168
169static int
170msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
171{
172 struct irq_cfg *cfg = irq_cfg + irq;
173 unsigned dest;
174 cpumask_t mask;
175
Srivatsa S. Bhat7d7f9842012-03-28 14:42:46 -0700176 cpumask_and(&mask, &(irq_to_domain(irq)), cpu_online_mask);
Fenghua Yu62fdd762008-10-17 12:14:13 -0700177 dest = cpu_physical_id(first_cpu(mask));
178
179 msg->address_hi = 0;
180 msg->address_lo =
181 MSI_ADDR_HEADER |
Xiantao Zhang2fa89372009-02-16 15:14:48 +0800182 MSI_ADDR_DEST_MODE_PHYS |
Fenghua Yu62fdd762008-10-17 12:14:13 -0700183 MSI_ADDR_REDIRECTION_CPU |
Xiantao Zhang2fa89372009-02-16 15:14:48 +0800184 MSI_ADDR_DEST_ID_CPU(dest);
Fenghua Yu62fdd762008-10-17 12:14:13 -0700185
186 msg->data =
187 MSI_DATA_TRIGGER_EDGE |
188 MSI_DATA_LEVEL_ASSERT |
189 MSI_DATA_DELIVERY_FIXED |
190 MSI_DATA_VECTOR(cfg->vector);
191 return 0;
192}
193
194int arch_setup_dmar_msi(unsigned int irq)
195{
196 int ret;
197 struct msi_msg msg;
198
199 ret = msi_compose_msg(NULL, irq, &msg);
200 if (ret < 0)
201 return ret;
202 dmar_msi_write(irq, &msg);
Thomas Gleixner53c909c2011-03-25 21:06:09 +0100203 irq_set_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
204 "edge");
Fenghua Yu62fdd762008-10-17 12:14:13 -0700205 return 0;
206}
Suresh Siddhad3f13812011-08-23 17:05:25 -0700207#endif /* CONFIG_INTEL_IOMMU */
Fenghua Yu62fdd762008-10-17 12:14:13 -0700208