1 // SPDX-License-Identifier: GPL-2.0
3 * Freescale Management Complex (MC) bus driver MSI support
5 * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
6 * Author: German Rivera <German.Rivera@freescale.com>
10 #include <linux/acpi.h>
11 #include <linux/acpi_iort.h>
12 #include <linux/of_device.h>
13 #include <linux/of_address.h>
14 #include <linux/irq.h>
15 #include <linux/msi.h>
17 #include <linux/of_irq.h>
18 #include <linux/fsl/mc.h>
20 static struct irq_chip its_msi_irq_chip
= {
22 .irq_mask
= irq_chip_mask_parent
,
23 .irq_unmask
= irq_chip_unmask_parent
,
24 .irq_eoi
= irq_chip_eoi_parent
,
25 .irq_set_affinity
= msi_domain_set_affinity
28 static u32
fsl_mc_msi_domain_get_msi_id(struct irq_domain
*domain
,
29 struct fsl_mc_device
*mc_dev
)
31 struct device_node
*of_node
;
34 of_node
= irq_domain_get_of_node(domain
);
35 out_id
= of_node
? of_msi_map_id(&mc_dev
->dev
, of_node
, mc_dev
->icid
) :
36 iort_msi_map_id(&mc_dev
->dev
, mc_dev
->icid
);
41 static int its_fsl_mc_msi_prepare(struct irq_domain
*msi_domain
,
43 int nvec
, msi_alloc_info_t
*info
)
45 struct fsl_mc_device
*mc_bus_dev
;
46 struct msi_domain_info
*msi_info
;
48 if (!dev_is_fsl_mc(dev
))
51 mc_bus_dev
= to_fsl_mc_device(dev
);
52 if (!(mc_bus_dev
->flags
& FSL_MC_IS_DPRC
))
56 * Set the device Id to be passed to the GIC-ITS:
58 * NOTE: This device id corresponds to the IOMMU stream ID
59 * associated with the DPRC object (ICID).
61 info
->scratchpad
[0].ul
= fsl_mc_msi_domain_get_msi_id(msi_domain
,
63 msi_info
= msi_get_domain_info(msi_domain
->parent
);
65 /* Allocate at least 32 MSIs, and always as a power of 2 */
66 nvec
= max_t(int, 32, roundup_pow_of_two(nvec
));
67 return msi_info
->ops
->msi_prepare(msi_domain
->parent
, dev
, nvec
, info
);
70 static struct msi_domain_ops its_fsl_mc_msi_ops __ro_after_init
= {
71 .msi_prepare
= its_fsl_mc_msi_prepare
,
74 static struct msi_domain_info its_fsl_mc_msi_domain_info
= {
75 .flags
= (MSI_FLAG_USE_DEF_DOM_OPS
| MSI_FLAG_USE_DEF_CHIP_OPS
),
76 .ops
= &its_fsl_mc_msi_ops
,
77 .chip
= &its_msi_irq_chip
,
80 static const struct of_device_id its_device_id
[] = {
81 { .compatible
= "arm,gic-v3-its", },
85 static void __init
its_fsl_mc_msi_init_one(struct fwnode_handle
*handle
,
88 struct irq_domain
*parent
;
89 struct irq_domain
*mc_msi_domain
;
91 parent
= irq_find_matching_fwnode(handle
, DOMAIN_BUS_NEXUS
);
92 if (!parent
|| !msi_get_domain_info(parent
)) {
93 pr_err("%s: unable to locate ITS domain\n", name
);
97 mc_msi_domain
= fsl_mc_msi_create_irq_domain(handle
,
98 &its_fsl_mc_msi_domain_info
,
100 if (!mc_msi_domain
) {
101 pr_err("%s: unable to create fsl-mc domain\n", name
);
105 pr_info("fsl-mc MSI: %s domain created\n", name
);
110 its_fsl_mc_msi_parse_madt(union acpi_subtable_headers
*header
,
111 const unsigned long end
)
113 struct acpi_madt_generic_translator
*its_entry
;
114 struct fwnode_handle
*dom_handle
;
115 const char *node_name
;
118 its_entry
= (struct acpi_madt_generic_translator
*)header
;
119 node_name
= kasprintf(GFP_KERNEL
, "ITS@0x%lx",
120 (long)its_entry
->base_address
);
122 dom_handle
= iort_find_domain_token(its_entry
->translation_id
);
124 pr_err("%s: Unable to locate ITS domain handle\n", node_name
);
129 its_fsl_mc_msi_init_one(dom_handle
, node_name
);
137 static void __init
its_fsl_mc_acpi_msi_init(void)
139 acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR
,
140 its_fsl_mc_msi_parse_madt
, 0);
143 static inline void its_fsl_mc_acpi_msi_init(void) { }
146 static void __init
its_fsl_mc_of_msi_init(void)
148 struct device_node
*np
;
150 for (np
= of_find_matching_node(NULL
, its_device_id
); np
;
151 np
= of_find_matching_node(np
, its_device_id
)) {
152 if (!of_device_is_available(np
))
154 if (!of_property_read_bool(np
, "msi-controller"))
157 its_fsl_mc_msi_init_one(of_node_to_fwnode(np
),
162 static int __init
its_fsl_mc_msi_init(void)
164 its_fsl_mc_of_msi_init();
165 its_fsl_mc_acpi_msi_init();
170 early_initcall(its_fsl_mc_msi_init
);