]> git.karo-electronics.de Git - linux-beck.git/blob - arch/x86/kernel/apic/msi.c
3c825867aeb5411a0f30747ef531864dabd2c0df
[linux-beck.git] / arch / x86 / kernel / apic / msi.c
1 /*
2  * Support of MSI, HPET and DMAR interrupts.
3  *
4  * Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
5  *      Moved from arch/x86/kernel/apic/io_apic.c.
6  * Jiang Liu <jiang.liu@linux.intel.com>
7  *      Convert to hierarchical irqdomain
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13 #include <linux/mm.h>
14 #include <linux/interrupt.h>
15 #include <linux/pci.h>
16 #include <linux/dmar.h>
17 #include <linux/hpet.h>
18 #include <linux/msi.h>
19 #include <linux/irqdomain.h>
20 #include <asm/msidef.h>
21 #include <asm/hpet.h>
22 #include <asm/hw_irq.h>
23 #include <asm/apic.h>
24 #include <asm/irq_remapping.h>
25
26 static struct irq_domain *msi_default_domain;
27
28 static void irq_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
29 {
30         struct irq_cfg *cfg = irqd_cfg(data);
31
32         msg->address_hi = MSI_ADDR_BASE_HI;
33
34         if (x2apic_enabled())
35                 msg->address_hi |= MSI_ADDR_EXT_DEST_ID(cfg->dest_apicid);
36
37         msg->address_lo =
38                 MSI_ADDR_BASE_LO |
39                 ((apic->irq_dest_mode == 0) ?
40                         MSI_ADDR_DEST_MODE_PHYSICAL :
41                         MSI_ADDR_DEST_MODE_LOGICAL) |
42                 ((apic->irq_delivery_mode != dest_LowestPrio) ?
43                         MSI_ADDR_REDIRECTION_CPU :
44                         MSI_ADDR_REDIRECTION_LOWPRI) |
45                 MSI_ADDR_DEST_ID(cfg->dest_apicid);
46
47         msg->data =
48                 MSI_DATA_TRIGGER_EDGE |
49                 MSI_DATA_LEVEL_ASSERT |
50                 ((apic->irq_delivery_mode != dest_LowestPrio) ?
51                         MSI_DATA_DELIVERY_FIXED :
52                         MSI_DATA_DELIVERY_LOWPRI) |
53                 MSI_DATA_VECTOR(cfg->vector);
54 }
55
56 /*
57  * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
58  * which implement the MSI or MSI-X Capability Structure.
59  */
60 static struct irq_chip pci_msi_controller = {
61         .name                   = "PCI-MSI",
62         .irq_unmask             = pci_msi_unmask_irq,
63         .irq_mask               = pci_msi_mask_irq,
64         .irq_ack                = irq_chip_ack_parent,
65         .irq_set_affinity       = msi_domain_set_affinity,
66         .irq_retrigger          = irq_chip_retrigger_hierarchy,
67         .irq_compose_msi_msg    = irq_msi_compose_msg,
68         .irq_write_msi_msg      = pci_msi_domain_write_msg,
69         .flags                  = IRQCHIP_SKIP_SET_WAKE,
70 };
71
72 int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
73 {
74         struct irq_domain *domain;
75         struct irq_alloc_info info;
76
77         init_irq_alloc_info(&info, NULL);
78         info.type = X86_IRQ_ALLOC_TYPE_MSI;
79         info.msi_dev = dev;
80
81         domain = irq_remapping_get_irq_domain(&info);
82         if (domain == NULL)
83                 domain = msi_default_domain;
84         if (domain == NULL)
85                 return -ENOSYS;
86
87         return pci_msi_domain_alloc_irqs(domain, dev, nvec, type);
88 }
89
90 void native_teardown_msi_irq(unsigned int irq)
91 {
92         irq_domain_free_irqs(irq, 1);
93 }
94
95 static irq_hw_number_t pci_msi_get_hwirq(struct msi_domain_info *info,
96                                          msi_alloc_info_t *arg)
97 {
98         return arg->msi_hwirq;
99 }
100
101 static int pci_msi_prepare(struct irq_domain *domain, struct device *dev,
102                            int nvec, msi_alloc_info_t *arg)
103 {
104         struct pci_dev *pdev = to_pci_dev(dev);
105         struct msi_desc *desc = first_pci_msi_entry(pdev);
106
107         init_irq_alloc_info(arg, NULL);
108         arg->msi_dev = pdev;
109         if (desc->msi_attrib.is_msix) {
110                 arg->type = X86_IRQ_ALLOC_TYPE_MSIX;
111         } else {
112                 arg->type = X86_IRQ_ALLOC_TYPE_MSI;
113                 arg->flags |= X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
114         }
115
116         return 0;
117 }
118
119 static void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
120 {
121         arg->msi_hwirq = pci_msi_domain_calc_hwirq(arg->msi_dev, desc);
122 }
123
124 static struct msi_domain_ops pci_msi_domain_ops = {
125         .get_hwirq      = pci_msi_get_hwirq,
126         .msi_prepare    = pci_msi_prepare,
127         .set_desc       = pci_msi_set_desc,
128 };
129
130 static struct msi_domain_info pci_msi_domain_info = {
131         .flags          = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
132                           MSI_FLAG_PCI_MSIX,
133         .ops            = &pci_msi_domain_ops,
134         .chip           = &pci_msi_controller,
135         .handler        = handle_edge_irq,
136         .handler_name   = "edge",
137 };
138
139 void arch_init_msi_domain(struct irq_domain *parent)
140 {
141         if (disable_apic)
142                 return;
143
144         msi_default_domain = pci_msi_create_irq_domain(NULL,
145                                         &pci_msi_domain_info, parent);
146         if (!msi_default_domain)
147                 pr_warn("failed to initialize irqdomain for MSI/MSI-x.\n");
148 }
149
150 #ifdef CONFIG_IRQ_REMAP
151 static struct irq_chip pci_msi_ir_controller = {
152         .name                   = "IR-PCI-MSI",
153         .irq_unmask             = pci_msi_unmask_irq,
154         .irq_mask               = pci_msi_mask_irq,
155         .irq_ack                = irq_chip_ack_parent,
156         .irq_set_affinity       = msi_domain_set_affinity,
157         .irq_retrigger          = irq_chip_retrigger_hierarchy,
158         .irq_write_msi_msg      = pci_msi_domain_write_msg,
159         .flags                  = IRQCHIP_SKIP_SET_WAKE,
160 };
161
162 static struct msi_domain_info pci_msi_ir_domain_info = {
163         .flags          = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
164                           MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX,
165         .ops            = &pci_msi_domain_ops,
166         .chip           = &pci_msi_ir_controller,
167         .handler        = handle_edge_irq,
168         .handler_name   = "edge",
169 };
170
171 struct irq_domain *arch_create_msi_irq_domain(struct irq_domain *parent)
172 {
173         return pci_msi_create_irq_domain(NULL, &pci_msi_ir_domain_info, parent);
174 }
175 #endif
176
177 #ifdef CONFIG_DMAR_TABLE
178 static int
179 dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
180                       bool force)
181 {
182         struct irq_data *parent = data->parent_data;
183         struct msi_msg msg;
184         int ret;
185
186         ret = parent->chip->irq_set_affinity(parent, mask, force);
187         if (ret >= 0) {
188                 irq_chip_compose_msi_msg(data, &msg);
189                 dmar_msi_write(data->irq, &msg);
190         }
191
192         return ret;
193 }
194
195 static void dmar_msi_write_msg(struct irq_data *data, struct msi_msg *msg)
196 {
197         dmar_msi_write(data->irq, msg);
198 }
199
200 static struct irq_chip dmar_msi_controller = {
201         .name                   = "DMAR-MSI",
202         .irq_unmask             = dmar_msi_unmask,
203         .irq_mask               = dmar_msi_mask,
204         .irq_ack                = irq_chip_ack_parent,
205         .irq_set_affinity       = dmar_msi_set_affinity,
206         .irq_retrigger          = irq_chip_retrigger_hierarchy,
207         .irq_compose_msi_msg    = irq_msi_compose_msg,
208         .irq_write_msi_msg      = dmar_msi_write_msg,
209         .flags                  = IRQCHIP_SKIP_SET_WAKE,
210 };
211
212 static int dmar_domain_alloc(struct irq_domain *domain, unsigned int virq,
213                              unsigned int nr_irqs, void *arg)
214 {
215         struct irq_alloc_info *info = arg;
216         int ret;
217
218         if (nr_irqs > 1 || !info || info->type != X86_IRQ_ALLOC_TYPE_DMAR)
219                 return -EINVAL;
220         if (irq_find_mapping(domain, info->dmar_id)) {
221                 pr_warn("IRQ for DMAR%d already exists.\n", info->dmar_id);
222                 return -EEXIST;
223         }
224
225         ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
226         if (ret >= 0) {
227                 irq_domain_set_hwirq_and_chip(domain, virq, info->dmar_id,
228                                               &dmar_msi_controller, NULL);
229                 irq_set_handler_data(virq, info->dmar_data);
230                 __irq_set_handler(virq, handle_edge_irq, 0, "edge");
231         }
232
233         return ret;
234 }
235
236 static void dmar_domain_free(struct irq_domain *domain, unsigned int virq,
237                              unsigned int nr_irqs)
238 {
239         BUG_ON(nr_irqs > 1);
240         irq_domain_free_irqs_top(domain, virq, nr_irqs);
241 }
242
243 static void dmar_domain_activate(struct irq_domain *domain,
244                                  struct irq_data *irq_data)
245 {
246         struct msi_msg msg;
247
248         BUG_ON(irq_chip_compose_msi_msg(irq_data, &msg));
249         dmar_msi_write(irq_data->irq, &msg);
250 }
251
252 static void dmar_domain_deactivate(struct irq_domain *domain,
253                                    struct irq_data *irq_data)
254 {
255         struct msi_msg msg;
256
257         memset(&msg, 0, sizeof(msg));
258         dmar_msi_write(irq_data->irq, &msg);
259 }
260
261 static struct irq_domain_ops dmar_domain_ops = {
262         .alloc = dmar_domain_alloc,
263         .free = dmar_domain_free,
264         .activate = dmar_domain_activate,
265         .deactivate = dmar_domain_deactivate,
266 };
267
268 static struct irq_domain *dmar_get_irq_domain(void)
269 {
270         static struct irq_domain *dmar_domain;
271         static DEFINE_MUTEX(dmar_lock);
272
273         mutex_lock(&dmar_lock);
274         if (dmar_domain == NULL) {
275                 dmar_domain = irq_domain_add_tree(NULL, &dmar_domain_ops, NULL);
276                 if (dmar_domain)
277                         dmar_domain->parent = x86_vector_domain;
278         }
279         mutex_unlock(&dmar_lock);
280
281         return dmar_domain;
282 }
283
284 int dmar_alloc_hwirq(int id, int node, void *arg)
285 {
286         struct irq_domain *domain = dmar_get_irq_domain();
287         struct irq_alloc_info info;
288
289         if (!domain)
290                 return -1;
291
292         init_irq_alloc_info(&info, NULL);
293         info.type = X86_IRQ_ALLOC_TYPE_DMAR;
294         info.dmar_id = id;
295         info.dmar_data = arg;
296
297         return irq_domain_alloc_irqs(domain, 1, node, &info);
298 }
299
300 void dmar_free_hwirq(int irq)
301 {
302         irq_domain_free_irqs(irq, 1);
303 }
304 #endif
305
306 /*
307  * MSI message composition
308  */
309 #ifdef CONFIG_HPET_TIMER
310 static inline int hpet_dev_id(struct irq_domain *domain)
311 {
312         return (int)(long)domain->host_data;
313 }
314
315 static int hpet_msi_set_affinity(struct irq_data *data,
316                                  const struct cpumask *mask, bool force)
317 {
318         struct irq_data *parent = data->parent_data;
319         struct msi_msg msg;
320         int ret;
321
322         ret = parent->chip->irq_set_affinity(parent, mask, force);
323         if (ret >= 0 && ret != IRQ_SET_MASK_OK_DONE) {
324                 irq_chip_compose_msi_msg(data, &msg);
325                 hpet_msi_write(data->handler_data, &msg);
326         }
327
328         return ret;
329 }
330
331 static void hpet_msi_write_msg(struct irq_data *data, struct msi_msg *msg)
332 {
333         hpet_msi_write(data->handler_data, msg);
334 }
335
336 static struct irq_chip hpet_msi_controller = {
337         .name = "HPET-MSI",
338         .irq_unmask = hpet_msi_unmask,
339         .irq_mask = hpet_msi_mask,
340         .irq_ack = irq_chip_ack_parent,
341         .irq_set_affinity = hpet_msi_set_affinity,
342         .irq_retrigger = irq_chip_retrigger_hierarchy,
343         .irq_compose_msi_msg = irq_msi_compose_msg,
344         .irq_write_msi_msg = hpet_msi_write_msg,
345         .flags = IRQCHIP_SKIP_SET_WAKE,
346 };
347
348 static int hpet_domain_alloc(struct irq_domain *domain, unsigned int virq,
349                              unsigned int nr_irqs, void *arg)
350 {
351         struct irq_alloc_info *info = arg;
352         int ret;
353
354         if (nr_irqs > 1 || !info || info->type != X86_IRQ_ALLOC_TYPE_HPET)
355                 return -EINVAL;
356         if (irq_find_mapping(domain, info->hpet_index)) {
357                 pr_warn("IRQ for HPET%d already exists.\n", info->hpet_index);
358                 return -EEXIST;
359         }
360
361         ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
362         if (ret >= 0) {
363                 irq_set_status_flags(virq, IRQ_MOVE_PCNTXT);
364                 irq_domain_set_hwirq_and_chip(domain, virq, info->hpet_index,
365                                               &hpet_msi_controller, NULL);
366                 irq_set_handler_data(virq, info->hpet_data);
367                 __irq_set_handler(virq, handle_edge_irq, 0, "edge");
368         }
369
370         return ret;
371 }
372
373 static void hpet_domain_free(struct irq_domain *domain, unsigned int virq,
374                              unsigned int nr_irqs)
375 {
376         BUG_ON(nr_irqs > 1);
377         irq_clear_status_flags(virq, IRQ_MOVE_PCNTXT);
378         irq_domain_free_irqs_top(domain, virq, nr_irqs);
379 }
380
381 static void hpet_domain_activate(struct irq_domain *domain,
382                                 struct irq_data *irq_data)
383 {
384         struct msi_msg msg;
385
386         BUG_ON(irq_chip_compose_msi_msg(irq_data, &msg));
387         hpet_msi_write(irq_get_handler_data(irq_data->irq), &msg);
388 }
389
390 static void hpet_domain_deactivate(struct irq_domain *domain,
391                                   struct irq_data *irq_data)
392 {
393         struct msi_msg msg;
394
395         memset(&msg, 0, sizeof(msg));
396         hpet_msi_write(irq_get_handler_data(irq_data->irq), &msg);
397 }
398
399 static struct irq_domain_ops hpet_domain_ops = {
400         .alloc = hpet_domain_alloc,
401         .free = hpet_domain_free,
402         .activate = hpet_domain_activate,
403         .deactivate = hpet_domain_deactivate,
404 };
405
406 struct irq_domain *hpet_create_irq_domain(int hpet_id)
407 {
408         struct irq_domain *parent;
409         struct irq_alloc_info info;
410
411         if (x86_vector_domain == NULL)
412                 return NULL;
413
414         init_irq_alloc_info(&info, NULL);
415         info.type = X86_IRQ_ALLOC_TYPE_HPET;
416         info.hpet_id = hpet_id;
417         parent = irq_remapping_get_ir_irq_domain(&info);
418         if (parent == NULL)
419                 parent = x86_vector_domain;
420         else
421                 hpet_msi_controller.name = "IR-HPET-MSI";
422
423         return irq_domain_add_hierarchy(parent, 0, 0, NULL, &hpet_domain_ops,
424                                         (void *)(long)hpet_id);
425 }
426
427 int hpet_assign_irq(struct irq_domain *domain, struct hpet_dev *dev,
428                     int dev_num)
429 {
430         struct irq_alloc_info info;
431
432         init_irq_alloc_info(&info, NULL);
433         info.type = X86_IRQ_ALLOC_TYPE_HPET;
434         info.hpet_data = dev;
435         info.hpet_id = hpet_dev_id(domain);
436         info.hpet_index = dev_num;
437
438         return irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, NULL);
439 }
440 #endif