1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2013-2015 ARM Limited, All Rights Reserved.
4 * Author: Marc Zyngier <marc.zyngier@arm.com>
7 #include <linux/acpi_iort.h>
8 #include <linux/device.h>
11 #include <linux/of_irq.h>
13 static struct irq_chip its_pmsi_irq_chip
= {
17 static int of_pmsi_get_dev_id(struct irq_domain
*domain
, struct device
*dev
,
22 /* Suck the DeviceID out of the msi-parent property */
24 struct of_phandle_args args
;
26 ret
= of_parse_phandle_with_args(dev
->of_node
,
27 "msi-parent", "#msi-cells",
29 if (args
.np
== irq_domain_get_of_node(domain
)) {
30 if (WARN_ON(args
.args_count
!= 1))
32 *dev_id
= args
.args
[0];
41 int __weak
iort_pmsi_get_dev_id(struct device
*dev
, u32
*dev_id
)
46 static int its_pmsi_prepare(struct irq_domain
*domain
, struct device
*dev
,
47 int nvec
, msi_alloc_info_t
*info
)
49 struct msi_domain_info
*msi_info
;
53 msi_info
= msi_get_domain_info(domain
->parent
);
56 ret
= of_pmsi_get_dev_id(domain
, dev
, &dev_id
);
58 ret
= iort_pmsi_get_dev_id(dev
, &dev_id
);
62 /* ITS specific DeviceID, as the core ITS ignores dev. */
63 info
->scratchpad
[0].ul
= dev_id
;
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(domain
->parent
,
71 static struct msi_domain_ops its_pmsi_ops
= {
72 .msi_prepare
= its_pmsi_prepare
,
75 static struct msi_domain_info its_pmsi_domain_info
= {
76 .flags
= (MSI_FLAG_USE_DEF_DOM_OPS
| MSI_FLAG_USE_DEF_CHIP_OPS
),
78 .chip
= &its_pmsi_irq_chip
,
81 static const struct of_device_id its_device_id
[] = {
82 { .compatible
= "arm,gic-v3-its", },
86 static int __init
its_pmsi_init_one(struct fwnode_handle
*fwnode
,
89 struct irq_domain
*parent
;
91 parent
= irq_find_matching_fwnode(fwnode
, DOMAIN_BUS_NEXUS
);
92 if (!parent
|| !msi_get_domain_info(parent
)) {
93 pr_err("%s: unable to locate ITS domain\n", name
);
97 if (!platform_msi_create_irq_domain(fwnode
, &its_pmsi_domain_info
,
99 pr_err("%s: unable to create platform domain\n", name
);
103 pr_info("Platform MSI: %s domain created\n", name
);
109 its_pmsi_parse_madt(union acpi_subtable_headers
*header
,
110 const unsigned long end
)
112 struct acpi_madt_generic_translator
*its_entry
;
113 struct fwnode_handle
*domain_handle
;
114 const char *node_name
;
117 its_entry
= (struct acpi_madt_generic_translator
*)header
;
118 node_name
= kasprintf(GFP_KERNEL
, "ITS@0x%lx",
119 (long)its_entry
->base_address
);
120 domain_handle
= iort_find_domain_token(its_entry
->translation_id
);
121 if (!domain_handle
) {
122 pr_err("%s: Unable to locate ITS domain handle\n", node_name
);
126 err
= its_pmsi_init_one(domain_handle
, node_name
);
133 static void __init
its_pmsi_acpi_init(void)
135 acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR
,
136 its_pmsi_parse_madt
, 0);
139 static inline void its_pmsi_acpi_init(void) { }
142 static void __init
its_pmsi_of_init(void)
144 struct device_node
*np
;
146 for (np
= of_find_matching_node(NULL
, its_device_id
); np
;
147 np
= of_find_matching_node(np
, its_device_id
)) {
148 if (!of_device_is_available(np
))
150 if (!of_property_read_bool(np
, "msi-controller"))
153 its_pmsi_init_one(of_node_to_fwnode(np
), np
->full_name
);
157 static int __init
its_pmsi_init(void)
160 its_pmsi_acpi_init();
163 early_initcall(its_pmsi_init
);