2 * Freescale Management Complex (MC) bus driver MSI support
4 * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
5 * Author: German Rivera <German.Rivera@freescale.com>
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.
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>
18 #include <linux/of_irq.h>
19 #include "fsl-mc-private.h"
21 static struct irq_chip its_msi_irq_chip
= {
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
29 static int its_fsl_mc_msi_prepare(struct irq_domain
*msi_domain
,
31 int nvec
, msi_alloc_info_t
*info
)
33 struct fsl_mc_device
*mc_bus_dev
;
34 struct msi_domain_info
*msi_info
;
36 if (WARN_ON(!dev_is_fsl_mc(dev
)))
39 mc_bus_dev
= to_fsl_mc_device(dev
);
40 if (WARN_ON(!(mc_bus_dev
->flags
& FSL_MC_IS_DPRC
)))
44 * Set the device Id to be passed to the GIC-ITS:
46 * NOTE: This device id corresponds to the IOMMU stream ID
47 * associated with the DPRC object (ICID).
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
);
54 static struct msi_domain_ops its_fsl_mc_msi_ops __ro_after_init
= {
55 .msi_prepare
= its_fsl_mc_msi_prepare
,
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
,
64 static const struct of_device_id its_device_id
[] = {
65 { .compatible
= "arm,gic-v3-its", },
69 int __init
its_fsl_mc_msi_init(void)
71 struct device_node
*np
;
72 struct irq_domain
*parent
;
73 struct irq_domain
*mc_msi_domain
;
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"))
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",
87 mc_msi_domain
= fsl_mc_msi_create_irq_domain(
88 of_node_to_fwnode(np
),
89 &its_fsl_mc_msi_domain_info
,
92 pr_err("%s: unable to create fsl-mc domain\n",
97 WARN_ON(mc_msi_domain
->host_data
!=
98 &its_fsl_mc_msi_domain_info
);
100 pr_info("fsl-mc MSI: %s domain created\n", np
->full_name
);
106 void its_fsl_mc_msi_cleanup(void)
108 struct device_node
*np
;
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(
114 DOMAIN_BUS_FSL_MC_MSI
);
116 if (!of_property_read_bool(np
, "msi-controller"))
120 mc_msi_domain
->host_data
== &its_fsl_mc_msi_domain_info
)
121 irq_domain_remove(mc_msi_domain
);