Commit | Line | Data |
---|---|---|
3a288fd5 GR |
1 | /* |
2 | * Freescale Management Complex (MC) bus driver MSI support | |
3 | * | |
4 | * Copyright (C) 2015 Freescale Semiconductor, Inc. | |
5 | * Author: German Rivera <German.Rivera@freescale.com> | |
6 | * | |
7 | * This file is licensed under the terms of the GNU General Public | |
8 | * License version 2. This program is licensed "as is" without any | |
9 | * warranty of any kind, whether express or implied. | |
10 | */ | |
11 | ||
3a288fd5 GR |
12 | #include <linux/of_device.h> |
13 | #include <linux/of_address.h> | |
14 | #include <linux/irqchip/arm-gic-v3.h> | |
15 | #include <linux/irq.h> | |
16 | #include <linux/msi.h> | |
17 | #include <linux/of.h> | |
18 | #include <linux/of_irq.h> | |
d4e75132 | 19 | #include "../include/mc-bus.h" |
3a288fd5 GR |
20 | |
21 | static struct irq_chip its_msi_irq_chip = { | |
22 | .name = "fsl-mc-bus-msi", | |
23 | .irq_mask = irq_chip_mask_parent, | |
24 | .irq_unmask = irq_chip_unmask_parent, | |
25 | .irq_eoi = irq_chip_eoi_parent, | |
26 | .irq_set_affinity = msi_domain_set_affinity | |
27 | }; | |
28 | ||
29 | static int its_fsl_mc_msi_prepare(struct irq_domain *msi_domain, | |
30 | struct device *dev, | |
31 | int nvec, msi_alloc_info_t *info) | |
32 | { | |
33 | struct fsl_mc_device *mc_bus_dev; | |
34 | struct msi_domain_info *msi_info; | |
35 | ||
df5e9b5f | 36 | if (WARN_ON(!dev_is_fsl_mc(dev))) |
3a288fd5 GR |
37 | return -EINVAL; |
38 | ||
39 | mc_bus_dev = to_fsl_mc_device(dev); | |
40 | if (WARN_ON(!(mc_bus_dev->flags & FSL_MC_IS_DPRC))) | |
41 | return -EINVAL; | |
42 | ||
43 | /* | |
44 | * Set the device Id to be passed to the GIC-ITS: | |
45 | * | |
46 | * NOTE: This device id corresponds to the IOMMU stream ID | |
47 | * associated with the DPRC object (ICID). | |
48 | */ | |
49 | info->scratchpad[0].ul = mc_bus_dev->icid; | |
50 | msi_info = msi_get_domain_info(msi_domain->parent); | |
51 | return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info); | |
52 | } | |
53 | ||
54 | static struct msi_domain_ops its_fsl_mc_msi_ops = { | |
55 | .msi_prepare = its_fsl_mc_msi_prepare, | |
56 | }; | |
57 | ||
58 | static struct msi_domain_info its_fsl_mc_msi_domain_info = { | |
59 | .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), | |
60 | .ops = &its_fsl_mc_msi_ops, | |
61 | .chip = &its_msi_irq_chip, | |
62 | }; | |
63 | ||
64 | static const struct of_device_id its_device_id[] = { | |
65 | { .compatible = "arm,gic-v3-its", }, | |
66 | {}, | |
67 | }; | |
68 | ||
69 | int __init its_fsl_mc_msi_init(void) | |
70 | { | |
71 | struct device_node *np; | |
72 | struct irq_domain *parent; | |
73 | struct irq_domain *mc_msi_domain; | |
74 | ||
75 | for (np = of_find_matching_node(NULL, its_device_id); np; | |
76 | np = of_find_matching_node(np, its_device_id)) { | |
77 | if (!of_property_read_bool(np, "msi-controller")) | |
78 | continue; | |
79 | ||
80 | parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS); | |
81 | if (!parent || !msi_get_domain_info(parent)) { | |
82 | pr_err("%s: unable to locate ITS domain\n", | |
83 | np->full_name); | |
84 | continue; | |
85 | } | |
86 | ||
87 | mc_msi_domain = fsl_mc_msi_create_irq_domain( | |
88 | of_node_to_fwnode(np), | |
89 | &its_fsl_mc_msi_domain_info, | |
90 | parent); | |
91 | if (!mc_msi_domain) { | |
92 | pr_err("%s: unable to create fsl-mc domain\n", | |
93 | np->full_name); | |
94 | continue; | |
95 | } | |
96 | ||
97 | WARN_ON(mc_msi_domain-> | |
98 | host_data != &its_fsl_mc_msi_domain_info); | |
99 | ||
100 | pr_info("fsl-mc MSI: %s domain created\n", np->full_name); | |
101 | } | |
102 | ||
103 | return 0; | |
104 | } | |
105 | ||
106 | void its_fsl_mc_msi_cleanup(void) | |
107 | { | |
108 | struct device_node *np; | |
109 | ||
110 | for (np = of_find_matching_node(NULL, its_device_id); np; | |
111 | np = of_find_matching_node(np, its_device_id)) { | |
112 | struct irq_domain *mc_msi_domain = irq_find_matching_host( | |
113 | np, | |
114 | DOMAIN_BUS_FSL_MC_MSI); | |
115 | ||
116 | if (!of_property_read_bool(np, "msi-controller")) | |
117 | continue; | |
118 | ||
3a288fd5 GR |
119 | if (mc_msi_domain && |
120 | mc_msi_domain->host_data == &its_fsl_mc_msi_domain_info) | |
121 | irq_domain_remove(mc_msi_domain); | |
122 | } | |
123 | } |