@@ -15,10 +15,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/acpi.h>
#include <linux/bitmap.h>
#include <linux/cpu.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/iort.h>
#include <linux/log2.h>
#include <linux/mm.h>
#include <linux/msi.h>
@@ -1248,6 +1250,11 @@ static int its_irq_gic_domain_alloc(struct irq_domain *domain,
fwspec.param[0] = GIC_IRQ_TYPE_LPI;
fwspec.param[1] = hwirq;
fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
+ } else if (is_fwnode_irqchip(domain->parent->fwnode)) {
+ fwspec.fwnode = domain->parent->fwnode;
+ fwspec.param_count = 2;
+ fwspec.param[0] = hwirq;
+ fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
} else {
return -EINVAL;
}
@@ -1541,6 +1548,52 @@ int its_cpu_init(void)
return 0;
}
+#ifdef CONFIG_ACPI
+
+#define ACPI_GICV3_ITS_MEM_SIZE (2 * SZ_64K)
+
+static struct irq_domain *its_parent __initdata;
+
+static int __init
+gic_acpi_parse_madt_its(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_translator *its_entry;
+ struct fwnode_handle *domain_handle;
+ int err;
+
+ its_entry = (struct acpi_madt_generic_translator *)header;
+ domain_handle = irq_domain_alloc_fwnode((void *)its_entry->base_address);
+ if (!domain_handle) {
+ pr_err("Unable to allocate GICv2m domain token\n");
+ return -ENOMEM;
+ }
+
+ /* ITS works as msi controller in ACPI case */
+ err = its_probe_one(its_entry->base_address, ACPI_GICV3_ITS_MEM_SIZE,
+ its_parent, true, domain_handle);
+ if (err) {
+ irq_domain_free_fwnode(domain_handle);
+ return err;
+ }
+ iort_register_domain_token(its_entry->translation_id, domain_handle);
+ return 0;
+}
+
+void __init its_acpi_probe(struct irq_domain *parent_domain)
+{
+ int count;
+
+ its_parent = parent_domain;
+ count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
+ gic_acpi_parse_madt_its, 0);
+ if (count <= 0)
+ pr_info("No valid GIC ITS entries exist\n");
+}
+#else
+static inline void __init its_acpi_probe(struct irq_domain *parent_domain) { }
+#endif
+
static struct of_device_id its_device_id[] = {
{ .compatible = "arm,gic-v3-its", },
{},
@@ -1557,7 +1610,8 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
np = of_find_matching_node(np, its_device_id)) {
its_of_probe(np, parent_domain);
}
- }
+ } else
+ its_acpi_probe(parent_domain);
if (list_empty(&its_nodes)) {
pr_warn("ITS: No ITS available, not enabling LPIs\n");