OSDN Git Service

x86/hpet: Enhance HPET IRQ to support hierarchical irqdomains
[uclinux-h8/linux.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  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 #include <linux/mm.h>
12 #include <linux/interrupt.h>
13 #include <linux/pci.h>
14 #include <linux/dmar.h>
15 #include <linux/hpet.h>
16 #include <linux/msi.h>
17 #include <linux/irqdomain.h>
18 #include <asm/msidef.h>
19 #include <asm/hpet.h>
20 #include <asm/hw_irq.h>
21 #include <asm/apic.h>
22 #include <asm/irq_remapping.h>
23
24 void native_compose_msi_msg(struct pci_dev *pdev,
25                             unsigned int irq, unsigned int dest,
26                             struct msi_msg *msg, u8 hpet_id)
27 {
28         struct irq_cfg *cfg = irq_cfg(irq);
29
30         msg->address_hi = MSI_ADDR_BASE_HI;
31
32         if (x2apic_enabled())
33                 msg->address_hi |= MSI_ADDR_EXT_DEST_ID(dest);
34
35         msg->address_lo =
36                 MSI_ADDR_BASE_LO |
37                 ((apic->irq_dest_mode == 0) ?
38                         MSI_ADDR_DEST_MODE_PHYSICAL :
39                         MSI_ADDR_DEST_MODE_LOGICAL) |
40                 ((apic->irq_delivery_mode != dest_LowestPrio) ?
41                         MSI_ADDR_REDIRECTION_CPU :
42                         MSI_ADDR_REDIRECTION_LOWPRI) |
43                 MSI_ADDR_DEST_ID(dest);
44
45         msg->data =
46                 MSI_DATA_TRIGGER_EDGE |
47                 MSI_DATA_LEVEL_ASSERT |
48                 ((apic->irq_delivery_mode != dest_LowestPrio) ?
49                         MSI_DATA_DELIVERY_FIXED :
50                         MSI_DATA_DELIVERY_LOWPRI) |
51                 MSI_DATA_VECTOR(cfg->vector);
52 }
53
54 static void irq_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
55 {
56         struct irq_cfg *cfg = irqd_cfg(data);
57
58         msg->address_hi = MSI_ADDR_BASE_HI;
59
60         if (x2apic_enabled())
61                 msg->address_hi |= MSI_ADDR_EXT_DEST_ID(cfg->dest_apicid);
62
63         msg->address_lo =
64                 MSI_ADDR_BASE_LO |
65                 ((apic->irq_dest_mode == 0) ?
66                         MSI_ADDR_DEST_MODE_PHYSICAL :
67                         MSI_ADDR_DEST_MODE_LOGICAL) |
68                 ((apic->irq_delivery_mode != dest_LowestPrio) ?
69                         MSI_ADDR_REDIRECTION_CPU :
70                         MSI_ADDR_REDIRECTION_LOWPRI) |
71                 MSI_ADDR_DEST_ID(cfg->dest_apicid);
72
73         msg->data =
74                 MSI_DATA_TRIGGER_EDGE |
75                 MSI_DATA_LEVEL_ASSERT |
76                 ((apic->irq_delivery_mode != dest_LowestPrio) ?
77                         MSI_DATA_DELIVERY_FIXED :
78                         MSI_DATA_DELIVERY_LOWPRI) |
79                 MSI_DATA_VECTOR(cfg->vector);
80 }
81
82 static void msi_update_msg(struct msi_msg *msg, struct irq_data *irq_data)
83 {
84         struct irq_cfg *cfg = irqd_cfg(irq_data);
85
86         msg->data &= ~MSI_DATA_VECTOR_MASK;
87         msg->data |= MSI_DATA_VECTOR(cfg->vector);
88         msg->address_lo &= ~MSI_ADDR_DEST_ID_MASK;
89         msg->address_lo |= MSI_ADDR_DEST_ID(cfg->dest_apicid);
90 }
91
92 static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
93                            struct msi_msg *msg, u8 hpet_id)
94 {
95         struct irq_cfg *cfg;
96         int err;
97         unsigned dest;
98
99         if (disable_apic)
100                 return -ENXIO;
101
102         cfg = irq_cfg(irq);
103         err = assign_irq_vector(irq, cfg, apic->target_cpus());
104         if (err)
105                 return err;
106
107         err = apic->cpu_mask_to_apicid_and(cfg->domain,
108                                            apic->target_cpus(), &dest);
109         if (err)
110                 return err;
111
112         x86_msi.compose_msi_msg(pdev, irq, dest, msg, hpet_id);
113
114         return 0;
115 }
116
117 static int
118 msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
119 {
120         struct irq_cfg *cfg = irqd_cfg(data);
121         struct msi_msg msg;
122         unsigned int dest;
123         int ret;
124
125         ret = apic_set_affinity(data, mask, &dest);
126         if (ret)
127                 return ret;
128
129         __get_cached_msi_msg(data->msi_desc, &msg);
130
131         msg.data &= ~MSI_DATA_VECTOR_MASK;
132         msg.data |= MSI_DATA_VECTOR(cfg->vector);
133         msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
134         msg.address_lo |= MSI_ADDR_DEST_ID(dest);
135
136         __pci_write_msi_msg(data->msi_desc, &msg);
137
138         return IRQ_SET_MASK_OK_NOCOPY;
139 }
140
141 /*
142  * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
143  * which implement the MSI or MSI-X Capability Structure.
144  */
145 static struct irq_chip msi_chip = {
146         .name                   = "PCI-MSI",
147         .irq_unmask             = pci_msi_unmask_irq,
148         .irq_mask               = pci_msi_mask_irq,
149         .irq_ack                = apic_ack_edge,
150         .irq_set_affinity       = msi_set_affinity,
151         .irq_retrigger          = apic_retrigger_irq,
152         .flags                  = IRQCHIP_SKIP_SET_WAKE,
153 };
154
155 int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
156                   unsigned int irq_base, unsigned int irq_offset)
157 {
158         struct irq_chip *chip = &msi_chip;
159         struct msi_msg msg;
160         unsigned int irq = irq_base + irq_offset;
161         int ret;
162
163         ret = msi_compose_msg(dev, irq, &msg, -1);
164         if (ret < 0)
165                 return ret;
166
167         irq_set_msi_desc_off(irq_base, irq_offset, msidesc);
168
169         /*
170          * MSI-X message is written per-IRQ, the offset is always 0.
171          * MSI message denotes a contiguous group of IRQs, written for 0th IRQ.
172          */
173         if (!irq_offset)
174                 pci_write_msi_msg(irq, &msg);
175
176         setup_remapped_irq(irq, irq_cfg(irq), chip);
177
178         irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
179
180         dev_dbg(&dev->dev, "irq %d for MSI/MSI-X\n", irq);
181
182         return 0;
183 }
184
185 int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
186 {
187         struct msi_desc *msidesc;
188         int irq, ret;
189
190         /* Multiple MSI vectors only supported with interrupt remapping */
191         if (type == PCI_CAP_ID_MSI && nvec > 1)
192                 return 1;
193
194         list_for_each_entry(msidesc, &dev->msi_list, list) {
195                 irq = irq_domain_alloc_irqs(NULL, 1, NUMA_NO_NODE, NULL);
196                 if (irq <= 0)
197                         return -ENOSPC;
198
199                 ret = setup_msi_irq(dev, msidesc, irq, 0);
200                 if (ret < 0) {
201                         irq_domain_free_irqs(irq, 1);
202                         return ret;
203                 }
204
205         }
206         return 0;
207 }
208
209 void native_teardown_msi_irq(unsigned int irq)
210 {
211         irq_domain_free_irqs(irq, 1);
212 }
213
214 #ifdef CONFIG_DMAR_TABLE
215 static int
216 dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
217                       bool force)
218 {
219         struct irq_cfg *cfg = irqd_cfg(data);
220         unsigned int dest, irq = data->irq;
221         struct msi_msg msg;
222         int ret;
223
224         ret = apic_set_affinity(data, mask, &dest);
225         if (ret)
226                 return ret;
227
228         dmar_msi_read(irq, &msg);
229
230         msg.data &= ~MSI_DATA_VECTOR_MASK;
231         msg.data |= MSI_DATA_VECTOR(cfg->vector);
232         msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
233         msg.address_lo |= MSI_ADDR_DEST_ID(dest);
234         msg.address_hi = MSI_ADDR_BASE_HI | MSI_ADDR_EXT_DEST_ID(dest);
235
236         dmar_msi_write(irq, &msg);
237
238         return IRQ_SET_MASK_OK_NOCOPY;
239 }
240
241 static struct irq_chip dmar_msi_type = {
242         .name                   = "DMAR_MSI",
243         .irq_unmask             = dmar_msi_unmask,
244         .irq_mask               = dmar_msi_mask,
245         .irq_ack                = apic_ack_edge,
246         .irq_set_affinity       = dmar_msi_set_affinity,
247         .irq_retrigger          = apic_retrigger_irq,
248         .flags                  = IRQCHIP_SKIP_SET_WAKE,
249 };
250
251 int arch_setup_dmar_msi(unsigned int irq)
252 {
253         int ret;
254         struct msi_msg msg;
255
256         ret = msi_compose_msg(NULL, irq, &msg, -1);
257         if (ret < 0)
258                 return ret;
259         dmar_msi_write(irq, &msg);
260         irq_set_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
261                                       "edge");
262         return 0;
263 }
264
265 int dmar_alloc_hwirq(void)
266 {
267         return irq_domain_alloc_irqs(NULL, 1, NUMA_NO_NODE, NULL);
268 }
269
270 void dmar_free_hwirq(int irq)
271 {
272         irq_domain_free_irqs(irq, 1);
273 }
274 #endif
275
276 /*
277  * MSI message composition
278  */
279 #ifdef CONFIG_HPET_TIMER
280 static inline int hpet_dev_id(struct irq_domain *domain)
281 {
282         return (int)(long)domain->host_data;
283 }
284
285 static int hpet_msi_set_affinity(struct irq_data *data,
286                                  const struct cpumask *mask, bool force)
287 {
288         struct irq_data *parent = data->parent_data;
289         struct msi_msg msg;
290         int ret;
291
292         ret = parent->chip->irq_set_affinity(parent, mask, force);
293         if (ret >= 0 && ret != IRQ_SET_MASK_OK_DONE) {
294                 hpet_msi_read(data->handler_data, &msg);
295                 msi_update_msg(&msg, data);
296                 hpet_msi_write(data->handler_data, &msg);
297         }
298
299         return ret;
300 }
301
302 static struct irq_chip hpet_msi_controller = {
303         .name = "HPET_MSI",
304         .irq_unmask = hpet_msi_unmask,
305         .irq_mask = hpet_msi_mask,
306         .irq_ack = irq_chip_ack_parent,
307         .irq_set_affinity = hpet_msi_set_affinity,
308         .irq_retrigger = irq_chip_retrigger_hierarchy,
309         .irq_print_chip = irq_remapping_print_chip,
310         .irq_compose_msi_msg = irq_msi_compose_msg,
311         .flags = IRQCHIP_SKIP_SET_WAKE,
312 };
313
314 int default_setup_hpet_msi(unsigned int irq, unsigned int id)
315 {
316         struct irq_chip *chip = &hpet_msi_controller;
317         struct msi_msg msg;
318         int ret;
319
320         ret = msi_compose_msg(NULL, irq, &msg, id);
321         if (ret < 0)
322                 return ret;
323
324         hpet_msi_write(irq_get_handler_data(irq), &msg);
325         irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
326         setup_remapped_irq(irq, irq_cfg(irq), chip);
327
328         irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
329         return 0;
330 }
331
332 static int hpet_domain_alloc(struct irq_domain *domain, unsigned int virq,
333                              unsigned int nr_irqs, void *arg)
334 {
335         struct irq_alloc_info *info = arg;
336         int ret;
337
338         if (nr_irqs > 1 || !info || info->type != X86_IRQ_ALLOC_TYPE_HPET)
339                 return -EINVAL;
340         if (irq_find_mapping(domain, info->hpet_index)) {
341                 pr_warn("IRQ for HPET%d already exists.\n", info->hpet_index);
342                 return -EEXIST;
343         }
344
345         ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
346         if (ret >= 0) {
347                 irq_set_status_flags(virq, IRQ_MOVE_PCNTXT);
348                 irq_domain_set_hwirq_and_chip(domain, virq, info->hpet_index,
349                                               &hpet_msi_controller, NULL);
350                 irq_set_handler_data(virq, info->hpet_data);
351                 __irq_set_handler(virq, handle_edge_irq, 0, "edge");
352         }
353
354         return ret;
355 }
356
357 static void hpet_domain_free(struct irq_domain *domain, unsigned int virq,
358                              unsigned int nr_irqs)
359 {
360         BUG_ON(nr_irqs > 1);
361         irq_clear_status_flags(virq, IRQ_MOVE_PCNTXT);
362         irq_domain_free_irqs_top(domain, virq, nr_irqs);
363 }
364
365 static void hpet_domain_activate(struct irq_domain *domain,
366                                 struct irq_data *irq_data)
367 {
368         struct msi_msg msg;
369
370         BUG_ON(irq_chip_compose_msi_msg(irq_data, &msg));
371         hpet_msi_write(irq_get_handler_data(irq_data->irq), &msg);
372 }
373
374 static void hpet_domain_deactivate(struct irq_domain *domain,
375                                   struct irq_data *irq_data)
376 {
377         struct msi_msg msg;
378
379         memset(&msg, 0, sizeof(msg));
380         hpet_msi_write(irq_get_handler_data(irq_data->irq), &msg);
381 }
382
383 static struct irq_domain_ops hpet_domain_ops = {
384         .alloc = hpet_domain_alloc,
385         .free = hpet_domain_free,
386         .activate = hpet_domain_activate,
387         .deactivate = hpet_domain_deactivate,
388 };
389
390 struct irq_domain *hpet_create_irq_domain(int hpet_id)
391 {
392         struct irq_domain *parent;
393         struct irq_alloc_info info;
394
395         if (x86_vector_domain == NULL)
396                 return NULL;
397
398         init_irq_alloc_info(&info, NULL);
399         info.type = X86_IRQ_ALLOC_TYPE_HPET;
400         info.hpet_id = hpet_id;
401         parent = irq_remapping_get_ir_irq_domain(&info);
402         if (parent == NULL)
403                 parent = x86_vector_domain;
404
405         return irq_domain_add_hierarchy(parent, 0, 0, NULL, &hpet_domain_ops,
406                                         (void *)(long)hpet_id);
407 }
408
409 int hpet_assign_irq(struct irq_domain *domain, struct hpet_dev *dev,
410                     int dev_num)
411 {
412         struct irq_alloc_info info;
413
414         init_irq_alloc_info(&info, NULL);
415         info.type = X86_IRQ_ALLOC_TYPE_HPET;
416         info.hpet_data = dev;
417         info.hpet_id = hpet_dev_id(domain);
418         info.hpet_index = dev_num;
419
420         return irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, NULL);
421 }
422 #endif