xref: /kernel/linux/linux-5.10/drivers/acpi/irq.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * ACPI GSI IRQ layer
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2015 ARM Ltd.
68c2ecf20Sopenharmony_ci * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/acpi.h>
98c2ecf20Sopenharmony_ci#include <linux/irq.h>
108c2ecf20Sopenharmony_ci#include <linux/irqdomain.h>
118c2ecf20Sopenharmony_ci#include <linux/of.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cienum acpi_irq_model_id acpi_irq_model;
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistatic struct fwnode_handle *acpi_gsi_domain_id;
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/**
188c2ecf20Sopenharmony_ci * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
198c2ecf20Sopenharmony_ci * @gsi: GSI IRQ number to map
208c2ecf20Sopenharmony_ci * @irq: pointer where linux IRQ number is stored
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * irq location updated with irq value [>0 on success, 0 on failure]
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * Returns: 0 on success
258c2ecf20Sopenharmony_ci *          -EINVAL on failure
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_ciint acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
308c2ecf20Sopenharmony_ci							DOMAIN_BUS_ANY);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	*irq = irq_find_mapping(d, gsi);
338c2ecf20Sopenharmony_ci	/*
348c2ecf20Sopenharmony_ci	 * *irq == 0 means no mapping, that should
358c2ecf20Sopenharmony_ci	 * be reported as a failure
368c2ecf20Sopenharmony_ci	 */
378c2ecf20Sopenharmony_ci	return (*irq > 0) ? 0 : -EINVAL;
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/**
428c2ecf20Sopenharmony_ci * acpi_register_gsi() - Map a GSI to a linux IRQ number
438c2ecf20Sopenharmony_ci * @dev: device for which IRQ has to be mapped
448c2ecf20Sopenharmony_ci * @gsi: GSI IRQ number
458c2ecf20Sopenharmony_ci * @trigger: trigger type of the GSI number to be mapped
468c2ecf20Sopenharmony_ci * @polarity: polarity of the GSI to be mapped
478c2ecf20Sopenharmony_ci *
488c2ecf20Sopenharmony_ci * Returns: a valid linux IRQ number on success
498c2ecf20Sopenharmony_ci *          -EINVAL on failure
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_ciint acpi_register_gsi(struct device *dev, u32 gsi, int trigger,
528c2ecf20Sopenharmony_ci		      int polarity)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	struct irq_fwspec fwspec;
558c2ecf20Sopenharmony_ci	unsigned int irq;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	if (WARN_ON(!acpi_gsi_domain_id)) {
588c2ecf20Sopenharmony_ci		pr_warn("GSI: No registered irqchip, giving up\n");
598c2ecf20Sopenharmony_ci		return -EINVAL;
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	fwspec.fwnode = acpi_gsi_domain_id;
638c2ecf20Sopenharmony_ci	fwspec.param[0] = gsi;
648c2ecf20Sopenharmony_ci	fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity);
658c2ecf20Sopenharmony_ci	fwspec.param_count = 2;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	irq = irq_create_fwspec_mapping(&fwspec);
688c2ecf20Sopenharmony_ci	if (!irq)
698c2ecf20Sopenharmony_ci		return -EINVAL;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	return irq;
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_register_gsi);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/**
768c2ecf20Sopenharmony_ci * acpi_unregister_gsi() - Free a GSI<->linux IRQ number mapping
778c2ecf20Sopenharmony_ci * @gsi: GSI IRQ number
788c2ecf20Sopenharmony_ci */
798c2ecf20Sopenharmony_civoid acpi_unregister_gsi(u32 gsi)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
828c2ecf20Sopenharmony_ci							DOMAIN_BUS_ANY);
838c2ecf20Sopenharmony_ci	int irq = irq_find_mapping(d, gsi);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	irq_dispose_mapping(irq);
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_unregister_gsi);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci/**
908c2ecf20Sopenharmony_ci * acpi_get_irq_source_fwhandle() - Retrieve fwhandle from IRQ resource source.
918c2ecf20Sopenharmony_ci * @source: acpi_resource_source to use for the lookup.
928c2ecf20Sopenharmony_ci *
938c2ecf20Sopenharmony_ci * Description:
948c2ecf20Sopenharmony_ci * Retrieve the fwhandle of the device referenced by the given IRQ resource
958c2ecf20Sopenharmony_ci * source.
968c2ecf20Sopenharmony_ci *
978c2ecf20Sopenharmony_ci * Return:
988c2ecf20Sopenharmony_ci * The referenced device fwhandle or NULL on failure
998c2ecf20Sopenharmony_ci */
1008c2ecf20Sopenharmony_cistatic struct fwnode_handle *
1018c2ecf20Sopenharmony_ciacpi_get_irq_source_fwhandle(const struct acpi_resource_source *source)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	struct fwnode_handle *result;
1048c2ecf20Sopenharmony_ci	struct acpi_device *device;
1058c2ecf20Sopenharmony_ci	acpi_handle handle;
1068c2ecf20Sopenharmony_ci	acpi_status status;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	if (!source->string_length)
1098c2ecf20Sopenharmony_ci		return acpi_gsi_domain_id;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	status = acpi_get_handle(NULL, source->string_ptr, &handle);
1128c2ecf20Sopenharmony_ci	if (WARN_ON(ACPI_FAILURE(status)))
1138c2ecf20Sopenharmony_ci		return NULL;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	device = acpi_bus_get_acpi_device(handle);
1168c2ecf20Sopenharmony_ci	if (WARN_ON(!device))
1178c2ecf20Sopenharmony_ci		return NULL;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	result = &device->fwnode;
1208c2ecf20Sopenharmony_ci	acpi_bus_put_acpi_device(device);
1218c2ecf20Sopenharmony_ci	return result;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci/*
1258c2ecf20Sopenharmony_ci * Context for the resource walk used to lookup IRQ resources.
1268c2ecf20Sopenharmony_ci * Contains a return code, the lookup index, and references to the flags
1278c2ecf20Sopenharmony_ci * and fwspec where the result is returned.
1288c2ecf20Sopenharmony_ci */
1298c2ecf20Sopenharmony_cistruct acpi_irq_parse_one_ctx {
1308c2ecf20Sopenharmony_ci	int rc;
1318c2ecf20Sopenharmony_ci	unsigned int index;
1328c2ecf20Sopenharmony_ci	unsigned long *res_flags;
1338c2ecf20Sopenharmony_ci	struct irq_fwspec *fwspec;
1348c2ecf20Sopenharmony_ci};
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci/**
1378c2ecf20Sopenharmony_ci * acpi_irq_parse_one_match - Handle a matching IRQ resource.
1388c2ecf20Sopenharmony_ci * @fwnode: matching fwnode
1398c2ecf20Sopenharmony_ci * @hwirq: hardware IRQ number
1408c2ecf20Sopenharmony_ci * @triggering: triggering attributes of hwirq
1418c2ecf20Sopenharmony_ci * @polarity: polarity attributes of hwirq
1428c2ecf20Sopenharmony_ci * @polarity: polarity attributes of hwirq
1438c2ecf20Sopenharmony_ci * @shareable: shareable attributes of hwirq
1448c2ecf20Sopenharmony_ci * @ctx: acpi_irq_parse_one_ctx updated by this function
1458c2ecf20Sopenharmony_ci *
1468c2ecf20Sopenharmony_ci * Description:
1478c2ecf20Sopenharmony_ci * Handle a matching IRQ resource by populating the given ctx with
1488c2ecf20Sopenharmony_ci * the information passed.
1498c2ecf20Sopenharmony_ci */
1508c2ecf20Sopenharmony_cistatic inline void acpi_irq_parse_one_match(struct fwnode_handle *fwnode,
1518c2ecf20Sopenharmony_ci					    u32 hwirq, u8 triggering,
1528c2ecf20Sopenharmony_ci					    u8 polarity, u8 shareable,
1538c2ecf20Sopenharmony_ci					    struct acpi_irq_parse_one_ctx *ctx)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	if (!fwnode)
1568c2ecf20Sopenharmony_ci		return;
1578c2ecf20Sopenharmony_ci	ctx->rc = 0;
1588c2ecf20Sopenharmony_ci	*ctx->res_flags = acpi_dev_irq_flags(triggering, polarity, shareable);
1598c2ecf20Sopenharmony_ci	ctx->fwspec->fwnode = fwnode;
1608c2ecf20Sopenharmony_ci	ctx->fwspec->param[0] = hwirq;
1618c2ecf20Sopenharmony_ci	ctx->fwspec->param[1] = acpi_dev_get_irq_type(triggering, polarity);
1628c2ecf20Sopenharmony_ci	ctx->fwspec->param_count = 2;
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci/**
1668c2ecf20Sopenharmony_ci * acpi_irq_parse_one_cb - Handle the given resource.
1678c2ecf20Sopenharmony_ci * @ares: resource to handle
1688c2ecf20Sopenharmony_ci * @context: context for the walk
1698c2ecf20Sopenharmony_ci *
1708c2ecf20Sopenharmony_ci * Description:
1718c2ecf20Sopenharmony_ci * This is called by acpi_walk_resources passing each resource returned by
1728c2ecf20Sopenharmony_ci * the _CRS method. We only inspect IRQ resources. Since IRQ resources
1738c2ecf20Sopenharmony_ci * might contain multiple interrupts we check if the index is within this
1748c2ecf20Sopenharmony_ci * one's interrupt array, otherwise we subtract the current resource IRQ
1758c2ecf20Sopenharmony_ci * count from the lookup index to prepare for the next resource.
1768c2ecf20Sopenharmony_ci * Once a match is found we call acpi_irq_parse_one_match to populate
1778c2ecf20Sopenharmony_ci * the result and end the walk by returning AE_CTRL_TERMINATE.
1788c2ecf20Sopenharmony_ci *
1798c2ecf20Sopenharmony_ci * Return:
1808c2ecf20Sopenharmony_ci * AE_OK if the walk should continue, AE_CTRL_TERMINATE if a matching
1818c2ecf20Sopenharmony_ci * IRQ resource was found.
1828c2ecf20Sopenharmony_ci */
1838c2ecf20Sopenharmony_cistatic acpi_status acpi_irq_parse_one_cb(struct acpi_resource *ares,
1848c2ecf20Sopenharmony_ci					 void *context)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	struct acpi_irq_parse_one_ctx *ctx = context;
1878c2ecf20Sopenharmony_ci	struct acpi_resource_irq *irq;
1888c2ecf20Sopenharmony_ci	struct acpi_resource_extended_irq *eirq;
1898c2ecf20Sopenharmony_ci	struct fwnode_handle *fwnode;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	switch (ares->type) {
1928c2ecf20Sopenharmony_ci	case ACPI_RESOURCE_TYPE_IRQ:
1938c2ecf20Sopenharmony_ci		irq = &ares->data.irq;
1948c2ecf20Sopenharmony_ci		if (ctx->index >= irq->interrupt_count) {
1958c2ecf20Sopenharmony_ci			ctx->index -= irq->interrupt_count;
1968c2ecf20Sopenharmony_ci			return AE_OK;
1978c2ecf20Sopenharmony_ci		}
1988c2ecf20Sopenharmony_ci		fwnode = acpi_gsi_domain_id;
1998c2ecf20Sopenharmony_ci		acpi_irq_parse_one_match(fwnode, irq->interrupts[ctx->index],
2008c2ecf20Sopenharmony_ci					 irq->triggering, irq->polarity,
2018c2ecf20Sopenharmony_ci					 irq->shareable, ctx);
2028c2ecf20Sopenharmony_ci		return AE_CTRL_TERMINATE;
2038c2ecf20Sopenharmony_ci	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
2048c2ecf20Sopenharmony_ci		eirq = &ares->data.extended_irq;
2058c2ecf20Sopenharmony_ci		if (eirq->producer_consumer == ACPI_PRODUCER)
2068c2ecf20Sopenharmony_ci			return AE_OK;
2078c2ecf20Sopenharmony_ci		if (ctx->index >= eirq->interrupt_count) {
2088c2ecf20Sopenharmony_ci			ctx->index -= eirq->interrupt_count;
2098c2ecf20Sopenharmony_ci			return AE_OK;
2108c2ecf20Sopenharmony_ci		}
2118c2ecf20Sopenharmony_ci		fwnode = acpi_get_irq_source_fwhandle(&eirq->resource_source);
2128c2ecf20Sopenharmony_ci		acpi_irq_parse_one_match(fwnode, eirq->interrupts[ctx->index],
2138c2ecf20Sopenharmony_ci					 eirq->triggering, eirq->polarity,
2148c2ecf20Sopenharmony_ci					 eirq->shareable, ctx);
2158c2ecf20Sopenharmony_ci		return AE_CTRL_TERMINATE;
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	return AE_OK;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci/**
2228c2ecf20Sopenharmony_ci * acpi_irq_parse_one - Resolve an interrupt for a device
2238c2ecf20Sopenharmony_ci * @handle: the device whose interrupt is to be resolved
2248c2ecf20Sopenharmony_ci * @index: index of the interrupt to resolve
2258c2ecf20Sopenharmony_ci * @fwspec: structure irq_fwspec filled by this function
2268c2ecf20Sopenharmony_ci * @flags: resource flags filled by this function
2278c2ecf20Sopenharmony_ci *
2288c2ecf20Sopenharmony_ci * Description:
2298c2ecf20Sopenharmony_ci * Resolves an interrupt for a device by walking its CRS resources to find
2308c2ecf20Sopenharmony_ci * the appropriate ACPI IRQ resource and populating the given struct irq_fwspec
2318c2ecf20Sopenharmony_ci * and flags.
2328c2ecf20Sopenharmony_ci *
2338c2ecf20Sopenharmony_ci * Return:
2348c2ecf20Sopenharmony_ci * The result stored in ctx.rc by the callback, or the default -EINVAL value
2358c2ecf20Sopenharmony_ci * if an error occurs.
2368c2ecf20Sopenharmony_ci */
2378c2ecf20Sopenharmony_cistatic int acpi_irq_parse_one(acpi_handle handle, unsigned int index,
2388c2ecf20Sopenharmony_ci			      struct irq_fwspec *fwspec, unsigned long *flags)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	struct acpi_irq_parse_one_ctx ctx = { -EINVAL, index, flags, fwspec };
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	acpi_walk_resources(handle, METHOD_NAME__CRS, acpi_irq_parse_one_cb, &ctx);
2438c2ecf20Sopenharmony_ci	return ctx.rc;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci/**
2478c2ecf20Sopenharmony_ci * acpi_irq_get - Lookup an ACPI IRQ resource and use it to initialize resource.
2488c2ecf20Sopenharmony_ci * @handle: ACPI device handle
2498c2ecf20Sopenharmony_ci * @index:  ACPI IRQ resource index to lookup
2508c2ecf20Sopenharmony_ci * @res:    Linux IRQ resource to initialize
2518c2ecf20Sopenharmony_ci *
2528c2ecf20Sopenharmony_ci * Description:
2538c2ecf20Sopenharmony_ci * Look for the ACPI IRQ resource with the given index and use it to initialize
2548c2ecf20Sopenharmony_ci * the given Linux IRQ resource.
2558c2ecf20Sopenharmony_ci *
2568c2ecf20Sopenharmony_ci * Return:
2578c2ecf20Sopenharmony_ci * 0 on success
2588c2ecf20Sopenharmony_ci * -EINVAL if an error occurs
2598c2ecf20Sopenharmony_ci * -EPROBE_DEFER if the IRQ lookup/conversion failed
2608c2ecf20Sopenharmony_ci */
2618c2ecf20Sopenharmony_ciint acpi_irq_get(acpi_handle handle, unsigned int index, struct resource *res)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct irq_fwspec fwspec;
2648c2ecf20Sopenharmony_ci	struct irq_domain *domain;
2658c2ecf20Sopenharmony_ci	unsigned long flags;
2668c2ecf20Sopenharmony_ci	int rc;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	rc = acpi_irq_parse_one(handle, index, &fwspec, &flags);
2698c2ecf20Sopenharmony_ci	if (rc)
2708c2ecf20Sopenharmony_ci		return rc;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	domain = irq_find_matching_fwnode(fwspec.fwnode, DOMAIN_BUS_ANY);
2738c2ecf20Sopenharmony_ci	if (!domain)
2748c2ecf20Sopenharmony_ci		return -EPROBE_DEFER;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	rc = irq_create_fwspec_mapping(&fwspec);
2778c2ecf20Sopenharmony_ci	if (rc <= 0)
2788c2ecf20Sopenharmony_ci		return -EINVAL;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	res->start = rc;
2818c2ecf20Sopenharmony_ci	res->end = rc;
2828c2ecf20Sopenharmony_ci	res->flags = flags;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	return 0;
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_irq_get);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci/**
2898c2ecf20Sopenharmony_ci * acpi_set_irq_model - Setup the GSI irqdomain information
2908c2ecf20Sopenharmony_ci * @model: the value assigned to acpi_irq_model
2918c2ecf20Sopenharmony_ci * @fwnode: the irq_domain identifier for mapping and looking up
2928c2ecf20Sopenharmony_ci *          GSI interrupts
2938c2ecf20Sopenharmony_ci */
2948c2ecf20Sopenharmony_civoid __init acpi_set_irq_model(enum acpi_irq_model_id model,
2958c2ecf20Sopenharmony_ci			       struct fwnode_handle *fwnode)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	acpi_irq_model = model;
2988c2ecf20Sopenharmony_ci	acpi_gsi_domain_id = fwnode;
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci/**
3028c2ecf20Sopenharmony_ci * acpi_irq_create_hierarchy - Create a hierarchical IRQ domain with the default
3038c2ecf20Sopenharmony_ci *                             GSI domain as its parent.
3048c2ecf20Sopenharmony_ci * @flags:      Irq domain flags associated with the domain
3058c2ecf20Sopenharmony_ci * @size:       Size of the domain.
3068c2ecf20Sopenharmony_ci * @fwnode:     Optional fwnode of the interrupt controller
3078c2ecf20Sopenharmony_ci * @ops:        Pointer to the interrupt domain callbacks
3088c2ecf20Sopenharmony_ci * @host_data:  Controller private data pointer
3098c2ecf20Sopenharmony_ci */
3108c2ecf20Sopenharmony_cistruct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
3118c2ecf20Sopenharmony_ci					     unsigned int size,
3128c2ecf20Sopenharmony_ci					     struct fwnode_handle *fwnode,
3138c2ecf20Sopenharmony_ci					     const struct irq_domain_ops *ops,
3148c2ecf20Sopenharmony_ci					     void *host_data)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
3178c2ecf20Sopenharmony_ci							DOMAIN_BUS_ANY);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (!d)
3208c2ecf20Sopenharmony_ci		return NULL;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	return irq_domain_create_hierarchy(d, flags, size, fwnode, ops,
3238c2ecf20Sopenharmony_ci					   host_data);
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_irq_create_hierarchy);
326