2 * linux/kernel/irq/msi.c
4 * Copyright (C) 2014 Intel Corp.
5 * Author: Jiang Liu <jiang.liu@linux.intel.com>
7 * This file is licensed under GPLv2.
9 * This file contains common code to support Message Signalled Interrupt for
10 * PCI compatible and non PCI compatible devices.
12 #include <linux/types.h>
13 #include <linux/device.h>
14 #include <linux/irq.h>
15 #include <linux/irqdomain.h>
16 #include <linux/msi.h>
18 /* Temparory solution for building, will be removed later */
19 #include <linux/pci.h>
21 void __get_cached_msi_msg(struct msi_desc
*entry
, struct msi_msg
*msg
)
26 void get_cached_msi_msg(unsigned int irq
, struct msi_msg
*msg
)
28 struct msi_desc
*entry
= irq_get_msi_desc(irq
);
30 __get_cached_msi_msg(entry
, msg
);
32 EXPORT_SYMBOL_GPL(get_cached_msi_msg
);
34 #ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
35 static inline void irq_chip_write_msi_msg(struct irq_data
*data
,
38 data
->chip
->irq_write_msi_msg(data
, msg
);
42 * msi_domain_set_affinity - Generic affinity setter function for MSI domains
43 * @irq_data: The irq data associated to the interrupt
44 * @mask: The affinity mask to set
45 * @force: Flag to enforce setting (disable online checks)
47 * Intended to be used by MSI interrupt controllers which are
48 * implemented with hierarchical domains.
50 int msi_domain_set_affinity(struct irq_data
*irq_data
,
51 const struct cpumask
*mask
, bool force
)
53 struct irq_data
*parent
= irq_data
->parent_data
;
57 ret
= parent
->chip
->irq_set_affinity(parent
, mask
, force
);
58 if (ret
>= 0 && ret
!= IRQ_SET_MASK_OK_DONE
) {
59 BUG_ON(irq_chip_compose_msi_msg(irq_data
, &msg
));
60 irq_chip_write_msi_msg(irq_data
, &msg
);
66 static void msi_domain_activate(struct irq_domain
*domain
,
67 struct irq_data
*irq_data
)
71 BUG_ON(irq_chip_compose_msi_msg(irq_data
, &msg
));
72 irq_chip_write_msi_msg(irq_data
, &msg
);
75 static void msi_domain_deactivate(struct irq_domain
*domain
,
76 struct irq_data
*irq_data
)
80 memset(&msg
, 0, sizeof(msg
));
81 irq_chip_write_msi_msg(irq_data
, &msg
);
84 static int msi_domain_alloc(struct irq_domain
*domain
, unsigned int virq
,
85 unsigned int nr_irqs
, void *arg
)
87 struct msi_domain_info
*info
= domain
->host_data
;
88 struct msi_domain_ops
*ops
= info
->ops
;
89 irq_hw_number_t hwirq
= ops
->get_hwirq(info
, arg
);
92 if (irq_find_mapping(domain
, hwirq
) > 0)
95 ret
= irq_domain_alloc_irqs_parent(domain
, virq
, nr_irqs
, arg
);
99 for (i
= 0; i
< nr_irqs
; i
++) {
100 ret
= ops
->msi_init(domain
, info
, virq
+ i
, hwirq
+ i
, arg
);
103 for (i
--; i
> 0; i
--)
104 ops
->msi_free(domain
, info
, virq
+ i
);
106 irq_domain_free_irqs_top(domain
, virq
, nr_irqs
);
114 static void msi_domain_free(struct irq_domain
*domain
, unsigned int virq
,
115 unsigned int nr_irqs
)
117 struct msi_domain_info
*info
= domain
->host_data
;
120 if (info
->ops
->msi_free
) {
121 for (i
= 0; i
< nr_irqs
; i
++)
122 info
->ops
->msi_free(domain
, info
, virq
+ i
);
124 irq_domain_free_irqs_top(domain
, virq
, nr_irqs
);
127 static struct irq_domain_ops msi_domain_ops
= {
128 .alloc
= msi_domain_alloc
,
129 .free
= msi_domain_free
,
130 .activate
= msi_domain_activate
,
131 .deactivate
= msi_domain_deactivate
,
134 #ifdef GENERIC_MSI_DOMAIN_OPS
135 static irq_hw_number_t
msi_domain_ops_get_hwirq(struct msi_domain_info
*info
,
136 msi_alloc_info_t
*arg
)
141 static int msi_domain_ops_prepare(struct irq_domain
*domain
, struct device
*dev
,
142 int nvec
, msi_alloc_info_t
*arg
)
144 memset(arg
, 0, sizeof(*arg
));
148 static void msi_domain_ops_set_desc(msi_alloc_info_t
*arg
,
149 struct msi_desc
*desc
)
154 #define msi_domain_ops_get_hwirq NULL
155 #define msi_domain_ops_prepare NULL
156 #define msi_domain_ops_set_desc NULL
157 #endif /* !GENERIC_MSI_DOMAIN_OPS */
159 static int msi_domain_ops_init(struct irq_domain
*domain
,
160 struct msi_domain_info
*info
,
161 unsigned int virq
, irq_hw_number_t hwirq
,
162 msi_alloc_info_t
*arg
)
164 irq_domain_set_hwirq_and_chip(domain
, virq
, hwirq
, info
->chip
,
166 if (info
->handler
&& info
->handler_name
) {
167 __irq_set_handler(virq
, info
->handler
, 0, info
->handler_name
);
168 if (info
->handler_data
)
169 irq_set_handler_data(virq
, info
->handler_data
);
174 static int msi_domain_ops_check(struct irq_domain
*domain
,
175 struct msi_domain_info
*info
,
181 static struct msi_domain_ops msi_domain_ops_default
= {
182 .get_hwirq
= msi_domain_ops_get_hwirq
,
183 .msi_init
= msi_domain_ops_init
,
184 .msi_check
= msi_domain_ops_check
,
185 .msi_prepare
= msi_domain_ops_prepare
,
186 .set_desc
= msi_domain_ops_set_desc
,
189 static void msi_domain_update_dom_ops(struct msi_domain_info
*info
)
191 struct msi_domain_ops
*ops
= info
->ops
;
194 info
->ops
= &msi_domain_ops_default
;
198 if (ops
->get_hwirq
== NULL
)
199 ops
->get_hwirq
= msi_domain_ops_default
.get_hwirq
;
200 if (ops
->msi_init
== NULL
)
201 ops
->msi_init
= msi_domain_ops_default
.msi_init
;
202 if (ops
->msi_check
== NULL
)
203 ops
->msi_check
= msi_domain_ops_default
.msi_check
;
204 if (ops
->msi_prepare
== NULL
)
205 ops
->msi_prepare
= msi_domain_ops_default
.msi_prepare
;
206 if (ops
->set_desc
== NULL
)
207 ops
->set_desc
= msi_domain_ops_default
.set_desc
;
210 static void msi_domain_update_chip_ops(struct msi_domain_info
*info
)
212 struct irq_chip
*chip
= info
->chip
;
216 chip
->irq_mask
= pci_msi_mask_irq
;
217 if (!chip
->irq_unmask
)
218 chip
->irq_unmask
= pci_msi_unmask_irq
;
219 if (!chip
->irq_set_affinity
)
220 chip
->irq_set_affinity
= msi_domain_set_affinity
;
224 * msi_create_irq_domain - Create a MSI interrupt domain
225 * @of_node: Optional device-tree node of the interrupt controller
226 * @info: MSI domain info
227 * @parent: Parent irq domain
229 struct irq_domain
*msi_create_irq_domain(struct device_node
*node
,
230 struct msi_domain_info
*info
,
231 struct irq_domain
*parent
)
233 if (info
->flags
& MSI_FLAG_USE_DEF_DOM_OPS
)
234 msi_domain_update_dom_ops(info
);
235 if (info
->flags
& MSI_FLAG_USE_DEF_CHIP_OPS
)
236 msi_domain_update_chip_ops(info
);
238 return irq_domain_add_hierarchy(parent
, 0, 0, node
, &msi_domain_ops
,
243 * msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
244 * @domain: The domain to allocate from
245 * @dev: Pointer to device struct of the device for which the interrupts
247 * @nvec: The number of interrupts to allocate
249 * Returns 0 on success or an error code.
251 int msi_domain_alloc_irqs(struct irq_domain
*domain
, struct device
*dev
,
254 struct msi_domain_info
*info
= domain
->host_data
;
255 struct msi_domain_ops
*ops
= info
->ops
;
256 msi_alloc_info_t arg
;
257 struct msi_desc
*desc
;
258 int i
, ret
, virq
= -1;
260 ret
= ops
->msi_check(domain
, info
, dev
);
262 ret
= ops
->msi_prepare(domain
, dev
, nvec
, &arg
);
266 for_each_msi_entry(desc
, dev
) {
267 ops
->set_desc(&arg
, desc
);
268 if (info
->flags
& MSI_FLAG_IDENTITY_MAP
)
269 virq
= (int)ops
->get_hwirq(info
, &arg
);
273 virq
= __irq_domain_alloc_irqs(domain
, virq
, desc
->nvec_used
,
274 dev_to_node(dev
), &arg
, false);
277 if (ops
->handle_error
)
278 ret
= ops
->handle_error(domain
, desc
, ret
);
280 ops
->msi_finish(&arg
, ret
);
284 for (i
= 0; i
< desc
->nvec_used
; i
++)
285 irq_set_msi_desc_off(virq
, i
, desc
);
289 ops
->msi_finish(&arg
, 0);
291 for_each_msi_entry(desc
, dev
) {
292 if (desc
->nvec_used
== 1)
293 dev_dbg(dev
, "irq %d for MSI\n", virq
);
295 dev_dbg(dev
, "irq [%d-%d] for MSI\n",
296 virq
, virq
+ desc
->nvec_used
- 1);
303 * msi_domain_free_irqs - Free interrupts from a MSI interrupt @domain associated tp @dev
304 * @domain: The domain to managing the interrupts
305 * @dev: Pointer to device struct of the device for which the interrupts
308 void msi_domain_free_irqs(struct irq_domain
*domain
, struct device
*dev
)
310 struct msi_desc
*desc
;
312 for_each_msi_entry(desc
, dev
) {
314 * We might have failed to allocate an MSI early
315 * enough that there is no IRQ associated to this
316 * entry. If that's the case, don't do anything.
319 irq_domain_free_irqs(desc
->irq
, desc
->nvec_used
);
326 * msi_get_domain_info - Get the MSI interrupt domain info for @domain
327 * @domain: The interrupt domain to retrieve data from
329 * Returns the pointer to the msi_domain_info stored in
330 * @domain->host_data.
332 struct msi_domain_info
*msi_get_domain_info(struct irq_domain
*domain
)
334 return (struct msi_domain_info
*)domain
->host_data
;
337 #endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */