blob: af4eaec0f7c348019eb787ef2224106925bfac35 [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
Jiang Liu507a8832015-06-01 16:05:42 +080026 __get_cached_msi_msg(irq_data_get_msi_desc(idata), &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
Jiang Liu83a18912014-11-09 23:10:34 +080038 pci_write_msi_msg(irq, &msg);
Jiang Liuc42574e2015-07-13 20:42:46 +000039 cpumask_copy(irq_data_get_affinity_mask(idata), 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;
Mark Maulefd58e552006-04-10 21:17:48 -050050
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -070051 irq = create_irq();
52 if (irq < 0)
53 return irq;
54
Thomas Gleixner53c909c2011-03-25 21:06:09 +010055 irq_set_msi_desc(irq, desc);
Rusty Russell51f7bd82015-03-05 10:48:49 +103056 dest_phys_id = cpu_physical_id(cpumask_any_and(&(irq_to_domain(irq)),
57 cpu_online_mask));
Ishimatsu Yasuaki9438a122007-04-06 16:51:12 +090058 vector = irq_to_vector(irq);
Mark Maulefd58e552006-04-10 21:17:48 -050059
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070060 msg.address_hi = 0;
61 msg.address_lo =
Eric W. Biederman38bc0362006-10-04 02:16:34 -070062 MSI_ADDR_HEADER |
Xiantao Zhang2fa89372009-02-16 15:14:48 +080063 MSI_ADDR_DEST_MODE_PHYS |
Eric W. Biederman38bc0362006-10-04 02:16:34 -070064 MSI_ADDR_REDIRECTION_CPU |
Xiantao Zhang2fa89372009-02-16 15:14:48 +080065 MSI_ADDR_DEST_ID_CPU(dest_phys_id);
Mark Maulefd58e552006-04-10 21:17:48 -050066
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070067 msg.data =
Eric W. Biederman38bc0362006-10-04 02:16:34 -070068 MSI_DATA_TRIGGER_EDGE |
Mark Maulefd58e552006-04-10 21:17:48 -050069 MSI_DATA_LEVEL_ASSERT |
70 MSI_DATA_DELIVERY_FIXED |
71 MSI_DATA_VECTOR(vector);
72
Jiang Liu83a18912014-11-09 23:10:34 +080073 pci_write_msi_msg(irq, &msg);
Thomas Gleixner53c909c2011-03-25 21:06:09 +010074 irq_set_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070075
Kenji Kaneshige3aff0372007-10-30 16:01:49 +090076 return 0;
Mark Maulefd58e552006-04-10 21:17:48 -050077}
78
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070079void ia64_teardown_msi_irq(unsigned int irq)
Mark Maulefd58e552006-04-10 21:17:48 -050080{
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -070081 destroy_irq(irq);
Mark Maulefd58e552006-04-10 21:17:48 -050082}
83
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +010084static void ia64_ack_msi_irq(struct irq_data *data)
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070085{
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +010086 irq_complete_move(data->irq);
Thomas Gleixner97499b2e2011-03-25 20:36:55 +010087 irq_move_irq(data);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070088 ia64_eoi();
89}
Mark Maulefd58e552006-04-10 21:17:48 -050090
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +010091static int ia64_msi_retrigger_irq(struct irq_data *data)
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070092{
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +010093 unsigned int vector = irq_to_vector(data->irq);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -070094 ia64_resend_irq(vector);
95
96 return 1;
97}
98
99/*
100 * Generic ops used on most IA64 platforms.
101 */
102static struct irq_chip ia64_msi_chip = {
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100103 .name = "PCI-MSI",
Thomas Gleixner280510f2014-11-23 12:23:20 +0100104 .irq_mask = pci_msi_mask_irq,
105 .irq_unmask = pci_msi_unmask_irq,
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100106 .irq_ack = ia64_ack_msi_irq,
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700107#ifdef CONFIG_SMP
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100108 .irq_set_affinity = ia64_set_msi_irq_affinity,
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700109#endif
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100110 .irq_retrigger = ia64_msi_retrigger_irq,
Mark Maulefd58e552006-04-10 21:17:48 -0500111};
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700112
113
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -0700114int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700115{
116 if (platform_setup_msi_irq)
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -0700117 return platform_setup_msi_irq(pdev, desc);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700118
Eric W. Biedermanf7feaca2007-01-28 12:56:37 -0700119 return ia64_setup_msi_irq(pdev, desc);
Eric W. Biederman3b7d1922006-10-04 02:16:59 -0700120}
121
122void arch_teardown_msi_irq(unsigned int irq)
123{
124 if (platform_teardown_msi_irq)
125 return platform_teardown_msi_irq(irq);
126
127 return ia64_teardown_msi_irq(irq);
128}
Fenghua Yu62fdd762008-10-17 12:14:13 -0700129
Suresh Siddhad3f13812011-08-23 17:05:25 -0700130#ifdef CONFIG_INTEL_IOMMU
Fenghua Yu62fdd762008-10-17 12:14:13 -0700131#ifdef CONFIG_SMP
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100132static int dmar_msi_set_affinity(struct irq_data *data,
133 const struct cpumask *mask, bool force)
Fenghua Yu62fdd762008-10-17 12:14:13 -0700134{
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100135 unsigned int irq = data->irq;
Fenghua Yu62fdd762008-10-17 12:14:13 -0700136 struct irq_cfg *cfg = irq_cfg + irq;
137 struct msi_msg msg;
Thomas Gleixner785aebd2014-03-04 20:43:38 +0000138 int cpu = cpumask_first_and(mask, cpu_online_mask);
Fenghua Yu62fdd762008-10-17 12:14:13 -0700139
140 if (irq_prepare_move(irq, cpu))
Yinghai Lud5dedd42009-04-27 17:59:21 -0700141 return -1;
Fenghua Yu62fdd762008-10-17 12:14:13 -0700142
143 dmar_msi_read(irq, &msg);
144
145 msg.data &= ~MSI_DATA_VECTOR_MASK;
146 msg.data |= MSI_DATA_VECTOR(cfg->vector);
Xiantao Zhang2fa89372009-02-16 15:14:48 +0800147 msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
148 msg.address_lo |= MSI_ADDR_DEST_ID_CPU(cpu_physical_id(cpu));
Fenghua Yu62fdd762008-10-17 12:14:13 -0700149
150 dmar_msi_write(irq, &msg);
Jiang Liuc42574e2015-07-13 20:42:46 +0000151 cpumask_copy(irq_data_get_affinity_mask(data), mask);
Yinghai Lud5dedd42009-04-27 17:59:21 -0700152
153 return 0;
Fenghua Yu62fdd762008-10-17 12:14:13 -0700154}
155#endif /* CONFIG_SMP */
156
Jaswinder Singh Rajput9542b212009-06-10 12:45:01 -0700157static struct irq_chip dmar_msi_type = {
Fenghua Yu62fdd762008-10-17 12:14:13 -0700158 .name = "DMAR_MSI",
Thomas Gleixner5c2837f2010-09-28 17:15:11 +0200159 .irq_unmask = dmar_msi_unmask,
160 .irq_mask = dmar_msi_mask,
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100161 .irq_ack = ia64_ack_msi_irq,
Fenghua Yu62fdd762008-10-17 12:14:13 -0700162#ifdef CONFIG_SMP
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100163 .irq_set_affinity = dmar_msi_set_affinity,
Fenghua Yu62fdd762008-10-17 12:14:13 -0700164#endif
Thomas Gleixnerf1f701e2011-02-04 20:18:43 +0100165 .irq_retrigger = ia64_msi_retrigger_irq,
Fenghua Yu62fdd762008-10-17 12:14:13 -0700166};
167
Jiang Liu34742db2015-04-13 14:11:41 +0800168static void
Fenghua Yu62fdd762008-10-17 12:14:13 -0700169msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
170{
171 struct irq_cfg *cfg = irq_cfg + irq;
172 unsigned dest;
Fenghua Yu62fdd762008-10-17 12:14:13 -0700173
Rusty Russell51f7bd82015-03-05 10:48:49 +1030174 dest = cpu_physical_id(cpumask_first_and(&(irq_to_domain(irq)),
175 cpu_online_mask));
Fenghua Yu62fdd762008-10-17 12:14:13 -0700176
177 msg->address_hi = 0;
178 msg->address_lo =
179 MSI_ADDR_HEADER |
Xiantao Zhang2fa89372009-02-16 15:14:48 +0800180 MSI_ADDR_DEST_MODE_PHYS |
Fenghua Yu62fdd762008-10-17 12:14:13 -0700181 MSI_ADDR_REDIRECTION_CPU |
Xiantao Zhang2fa89372009-02-16 15:14:48 +0800182 MSI_ADDR_DEST_ID_CPU(dest);
Fenghua Yu62fdd762008-10-17 12:14:13 -0700183
184 msg->data =
185 MSI_DATA_TRIGGER_EDGE |
186 MSI_DATA_LEVEL_ASSERT |
187 MSI_DATA_DELIVERY_FIXED |
188 MSI_DATA_VECTOR(cfg->vector);
Fenghua Yu62fdd762008-10-17 12:14:13 -0700189}
190
Jiang Liu34742db2015-04-13 14:11:41 +0800191int dmar_alloc_hwirq(int id, int node, void *arg)
Fenghua Yu62fdd762008-10-17 12:14:13 -0700192{
Jiang Liu34742db2015-04-13 14:11:41 +0800193 int irq;
Fenghua Yu62fdd762008-10-17 12:14:13 -0700194 struct msi_msg msg;
195
Jiang Liu34742db2015-04-13 14:11:41 +0800196 irq = create_irq();
197 if (irq > 0) {
198 irq_set_handler_data(irq, arg);
199 irq_set_chip_and_handler_name(irq, &dmar_msi_type,
200 handle_edge_irq, "edge");
201 msi_compose_msg(NULL, irq, &msg);
202 dmar_msi_write(irq, &msg);
203 }
204
205 return irq;
206}
207
208void dmar_free_hwirq(int irq)
209{
210 irq_set_handler_data(irq, NULL);
211 destroy_irq(irq);
Fenghua Yu62fdd762008-10-17 12:14:13 -0700212}
Suresh Siddhad3f13812011-08-23 17:05:25 -0700213#endif /* CONFIG_INTEL_IOMMU */
Fenghua Yu62fdd762008-10-17 12:14:13 -0700214