^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * ACPI GSI IRQ layer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2015 ARM Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/irqdomain.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) enum acpi_irq_model_id acpi_irq_model;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) static struct fwnode_handle *acpi_gsi_domain_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * @gsi: GSI IRQ number to map
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * @irq: pointer where linux IRQ number is stored
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * irq location updated with irq value [>0 on success, 0 on failure]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * Returns: 0 on success
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * -EINVAL on failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) DOMAIN_BUS_ANY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) *irq = irq_find_mapping(d, gsi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * *irq == 0 means no mapping, that should
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * be reported as a failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return (*irq > 0) ? 0 : -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * acpi_register_gsi() - Map a GSI to a linux IRQ number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * @dev: device for which IRQ has to be mapped
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * @gsi: GSI IRQ number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * @trigger: trigger type of the GSI number to be mapped
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * @polarity: polarity of the GSI to be mapped
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * Returns: a valid linux IRQ number on success
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * -EINVAL on failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) int acpi_register_gsi(struct device *dev, u32 gsi, int trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) int polarity)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct irq_fwspec fwspec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if (WARN_ON(!acpi_gsi_domain_id)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) pr_warn("GSI: No registered irqchip, giving up\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) fwspec.fwnode = acpi_gsi_domain_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) fwspec.param[0] = gsi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) fwspec.param_count = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return irq_create_fwspec_mapping(&fwspec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) EXPORT_SYMBOL_GPL(acpi_register_gsi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * acpi_unregister_gsi() - Free a GSI<->linux IRQ number mapping
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * @gsi: GSI IRQ number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) void acpi_unregister_gsi(u32 gsi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) DOMAIN_BUS_ANY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) int irq = irq_find_mapping(d, gsi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) irq_dispose_mapping(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * acpi_get_irq_source_fwhandle() - Retrieve fwhandle from IRQ resource source.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * @source: acpi_resource_source to use for the lookup.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * Retrieve the fwhandle of the device referenced by the given IRQ resource
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * source.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * Return:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * The referenced device fwhandle or NULL on failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static struct fwnode_handle *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) acpi_get_irq_source_fwhandle(const struct acpi_resource_source *source)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) struct fwnode_handle *result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) struct acpi_device *device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) acpi_handle handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (!source->string_length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return acpi_gsi_domain_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) status = acpi_get_handle(NULL, source->string_ptr, &handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (WARN_ON(ACPI_FAILURE(status)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) device = acpi_bus_get_acpi_device(handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (WARN_ON(!device))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) result = &device->fwnode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) acpi_bus_put_acpi_device(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * Context for the resource walk used to lookup IRQ resources.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * Contains a return code, the lookup index, and references to the flags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * and fwspec where the result is returned.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) struct acpi_irq_parse_one_ctx {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) unsigned int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) unsigned long *res_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) struct irq_fwspec *fwspec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * acpi_irq_parse_one_match - Handle a matching IRQ resource.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * @fwnode: matching fwnode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * @hwirq: hardware IRQ number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * @triggering: triggering attributes of hwirq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * @polarity: polarity attributes of hwirq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * @polarity: polarity attributes of hwirq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * @shareable: shareable attributes of hwirq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * @ctx: acpi_irq_parse_one_ctx updated by this function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * Handle a matching IRQ resource by populating the given ctx with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * the information passed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static inline void acpi_irq_parse_one_match(struct fwnode_handle *fwnode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) u32 hwirq, u8 triggering,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) u8 polarity, u8 shareable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) struct acpi_irq_parse_one_ctx *ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (!fwnode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) ctx->rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) *ctx->res_flags = acpi_dev_irq_flags(triggering, polarity, shareable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) ctx->fwspec->fwnode = fwnode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) ctx->fwspec->param[0] = hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) ctx->fwspec->param[1] = acpi_dev_get_irq_type(triggering, polarity);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) ctx->fwspec->param_count = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * acpi_irq_parse_one_cb - Handle the given resource.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * @ares: resource to handle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * @context: context for the walk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) * This is called by acpi_walk_resources passing each resource returned by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) * the _CRS method. We only inspect IRQ resources. Since IRQ resources
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) * might contain multiple interrupts we check if the index is within this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * one's interrupt array, otherwise we subtract the current resource IRQ
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * count from the lookup index to prepare for the next resource.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) * Once a match is found we call acpi_irq_parse_one_match to populate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) * the result and end the walk by returning AE_CTRL_TERMINATE.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) * Return:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) * AE_OK if the walk should continue, AE_CTRL_TERMINATE if a matching
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * IRQ resource was found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) static acpi_status acpi_irq_parse_one_cb(struct acpi_resource *ares,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) void *context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) struct acpi_irq_parse_one_ctx *ctx = context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) struct acpi_resource_irq *irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) struct acpi_resource_extended_irq *eirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) struct fwnode_handle *fwnode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) switch (ares->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) case ACPI_RESOURCE_TYPE_IRQ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) irq = &ares->data.irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (ctx->index >= irq->interrupt_count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) ctx->index -= irq->interrupt_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) fwnode = acpi_gsi_domain_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) acpi_irq_parse_one_match(fwnode, irq->interrupts[ctx->index],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) irq->triggering, irq->polarity,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) irq->shareable, ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return AE_CTRL_TERMINATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) eirq = &ares->data.extended_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (eirq->producer_consumer == ACPI_PRODUCER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) return AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) if (ctx->index >= eirq->interrupt_count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) ctx->index -= eirq->interrupt_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) return AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) fwnode = acpi_get_irq_source_fwhandle(&eirq->resource_source);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) acpi_irq_parse_one_match(fwnode, eirq->interrupts[ctx->index],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) eirq->triggering, eirq->polarity,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) eirq->shareable, ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) return AE_CTRL_TERMINATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * acpi_irq_parse_one - Resolve an interrupt for a device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * @handle: the device whose interrupt is to be resolved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * @index: index of the interrupt to resolve
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) * @fwspec: structure irq_fwspec filled by this function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * @flags: resource flags filled by this function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) * Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * Resolves an interrupt for a device by walking its CRS resources to find
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * the appropriate ACPI IRQ resource and populating the given struct irq_fwspec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) * and flags.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * Return:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) * The result stored in ctx.rc by the callback, or the default -EINVAL value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) * if an error occurs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) static int acpi_irq_parse_one(acpi_handle handle, unsigned int index,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) struct irq_fwspec *fwspec, unsigned long *flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) struct acpi_irq_parse_one_ctx ctx = { -EINVAL, index, flags, fwspec };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) acpi_walk_resources(handle, METHOD_NAME__CRS, acpi_irq_parse_one_cb, &ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return ctx.rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * acpi_irq_get - Lookup an ACPI IRQ resource and use it to initialize resource.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * @handle: ACPI device handle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) * @index: ACPI IRQ resource index to lookup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * @res: Linux IRQ resource to initialize
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) * Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) * Look for the ACPI IRQ resource with the given index and use it to initialize
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) * the given Linux IRQ resource.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) * Return:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) * 0 on success
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * -EINVAL if an error occurs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * -EPROBE_DEFER if the IRQ lookup/conversion failed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) int acpi_irq_get(acpi_handle handle, unsigned int index, struct resource *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) struct irq_fwspec fwspec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) struct irq_domain *domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) rc = acpi_irq_parse_one(handle, index, &fwspec, &flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) domain = irq_find_matching_fwnode(fwspec.fwnode, DOMAIN_BUS_ANY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) if (!domain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) return -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) rc = irq_create_fwspec_mapping(&fwspec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (rc <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) res->start = rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) res->end = rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) res->flags = flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) EXPORT_SYMBOL_GPL(acpi_irq_get);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) * acpi_set_irq_model - Setup the GSI irqdomain information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) * @model: the value assigned to acpi_irq_model
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) * @fwnode: the irq_domain identifier for mapping and looking up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) * GSI interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) void __init acpi_set_irq_model(enum acpi_irq_model_id model,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) struct fwnode_handle *fwnode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) acpi_irq_model = model;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) acpi_gsi_domain_id = fwnode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) * acpi_irq_create_hierarchy - Create a hierarchical IRQ domain with the default
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) * GSI domain as its parent.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) * @flags: Irq domain flags associated with the domain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) * @size: Size of the domain.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) * @fwnode: Optional fwnode of the interrupt controller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) * @ops: Pointer to the interrupt domain callbacks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) * @host_data: Controller private data pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) unsigned int size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) struct fwnode_handle *fwnode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) const struct irq_domain_ops *ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) void *host_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) DOMAIN_BUS_ANY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) if (!d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) return irq_domain_create_hierarchy(d, flags, size, fwnode, ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) host_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) EXPORT_SYMBOL_GPL(acpi_irq_create_hierarchy);