|
@@ -15,10 +15,13 @@
|
|
|
* 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/irqdomain.h>
|
|
|
+#include <linux/acpi_iort.h>
|
|
|
#include <linux/log2.h>
|
|
|
#include <linux/mm.h>
|
|
|
#include <linux/msi.h>
|
|
@@ -1438,6 +1441,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;
|
|
|
}
|
|
@@ -1797,6 +1805,57 @@ static int __init its_of_probe(struct device_node *node)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_ACPI
|
|
|
+
|
|
|
+#define ACPI_GICV3_ITS_MEM_SIZE (SZ_128K)
|
|
|
+
|
|
|
+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 *dom_handle;
|
|
|
+ struct resource res;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ its_entry = (struct acpi_madt_generic_translator *)header;
|
|
|
+ memset(&res, 0, sizeof(res));
|
|
|
+ res.start = its_entry->base_address;
|
|
|
+ res.end = its_entry->base_address + ACPI_GICV3_ITS_MEM_SIZE - 1;
|
|
|
+ res.flags = IORESOURCE_MEM;
|
|
|
+
|
|
|
+ dom_handle = irq_domain_alloc_fwnode((void *)its_entry->base_address);
|
|
|
+ if (!dom_handle) {
|
|
|
+ pr_err("ITS@%pa: Unable to allocate GICv3 ITS domain token\n",
|
|
|
+ &res.start);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ err = iort_register_domain_token(its_entry->translation_id, dom_handle);
|
|
|
+ if (err) {
|
|
|
+ pr_err("ITS@%pa: Unable to register GICv3 ITS domain token (ITS ID %d) to IORT\n",
|
|
|
+ &res.start, its_entry->translation_id);
|
|
|
+ goto dom_err;
|
|
|
+ }
|
|
|
+
|
|
|
+ err = its_probe_one(&res, dom_handle, NUMA_NO_NODE);
|
|
|
+ if (!err)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ iort_deregister_domain_token(its_entry->translation_id);
|
|
|
+dom_err:
|
|
|
+ irq_domain_free_fwnode(dom_handle);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+static void __init its_acpi_probe(void)
|
|
|
+{
|
|
|
+ acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
|
|
|
+ gic_acpi_parse_madt_its, 0);
|
|
|
+}
|
|
|
+#else
|
|
|
+static void __init its_acpi_probe(void) { }
|
|
|
+#endif
|
|
|
+
|
|
|
int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
|
|
|
struct irq_domain *parent_domain)
|
|
|
{
|
|
@@ -1807,7 +1866,7 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
|
|
|
if (of_node)
|
|
|
its_of_probe(of_node);
|
|
|
else
|
|
|
- return -ENODEV;
|
|
|
+ its_acpi_probe();
|
|
|
|
|
|
if (list_empty(&its_nodes)) {
|
|
|
pr_warn("ITS: No ITS available, not enabling LPIs\n");
|