162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * drivers/acpi/resource.c - ACPI device resources interpretation. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012, Intel Corp. 662306a36Sopenharmony_ci * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/acpi.h> 1462306a36Sopenharmony_ci#include <linux/device.h> 1562306a36Sopenharmony_ci#include <linux/export.h> 1662306a36Sopenharmony_ci#include <linux/ioport.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <linux/irq.h> 1962306a36Sopenharmony_ci#include <linux/dmi.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#ifdef CONFIG_X86 2262306a36Sopenharmony_ci#define valid_IRQ(i) (((i) != 0) && ((i) != 2)) 2362306a36Sopenharmony_cistatic inline bool acpi_iospace_resource_valid(struct resource *res) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci /* On X86 IO space is limited to the [0 - 64K] IO port range */ 2662306a36Sopenharmony_ci return res->end < 0x10003; 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ci#else 2962306a36Sopenharmony_ci#define valid_IRQ(i) (true) 3062306a36Sopenharmony_ci/* 3162306a36Sopenharmony_ci * ACPI IO descriptors on arches other than X86 contain MMIO CPU physical 3262306a36Sopenharmony_ci * addresses mapping IO space in CPU physical address space, IO space 3362306a36Sopenharmony_ci * resources can be placed anywhere in the 64-bit physical address space. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_cistatic inline bool 3662306a36Sopenharmony_ciacpi_iospace_resource_valid(struct resource *res) { return true; } 3762306a36Sopenharmony_ci#endif 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_ACPI_GENERIC_GSI) 4062306a36Sopenharmony_cistatic inline bool is_gsi(struct acpi_resource_extended_irq *ext_irq) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci return ext_irq->resource_source.string_length == 0 && 4362306a36Sopenharmony_ci ext_irq->producer_consumer == ACPI_CONSUMER; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci#else 4662306a36Sopenharmony_cistatic inline bool is_gsi(struct acpi_resource_extended_irq *ext_irq) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci return true; 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci#endif 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci u64 reslen = end - start + 1; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* 5762306a36Sopenharmony_ci * CHECKME: len might be required to check versus a minimum 5862306a36Sopenharmony_ci * length as well. 1 for io is fine, but for memory it does 5962306a36Sopenharmony_ci * not make any sense at all. 6062306a36Sopenharmony_ci * Note: some BIOSes report incorrect length for ACPI address space 6162306a36Sopenharmony_ci * descriptor, so remove check of 'reslen == len' to avoid regression. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_ci if (len && reslen && start <= end) 6462306a36Sopenharmony_ci return true; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci pr_debug("ACPI: invalid or unassigned resource %s [%016llx - %016llx] length [%016llx]\n", 6762306a36Sopenharmony_ci io ? "io" : "mem", start, end, len); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci return false; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void acpi_dev_memresource_flags(struct resource *res, u64 len, 7362306a36Sopenharmony_ci u8 write_protect) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci res->flags = IORESOURCE_MEM; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (!acpi_dev_resource_len_valid(res->start, res->end, len, false)) 7862306a36Sopenharmony_ci res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (write_protect == ACPI_READ_WRITE_MEMORY) 8162306a36Sopenharmony_ci res->flags |= IORESOURCE_MEM_WRITEABLE; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, 8562306a36Sopenharmony_ci u8 write_protect) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci res->start = start; 8862306a36Sopenharmony_ci res->end = start + len - 1; 8962306a36Sopenharmony_ci acpi_dev_memresource_flags(res, len, write_protect); 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/** 9362306a36Sopenharmony_ci * acpi_dev_resource_memory - Extract ACPI memory resource information. 9462306a36Sopenharmony_ci * @ares: Input ACPI resource object. 9562306a36Sopenharmony_ci * @res: Output generic resource object. 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * Check if the given ACPI resource object represents a memory resource and 9862306a36Sopenharmony_ci * if that's the case, use the information in it to populate the generic 9962306a36Sopenharmony_ci * resource object pointed to by @res. 10062306a36Sopenharmony_ci * 10162306a36Sopenharmony_ci * Return: 10262306a36Sopenharmony_ci * 1) false with res->flags setting to zero: not the expected resource type 10362306a36Sopenharmony_ci * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource 10462306a36Sopenharmony_ci * 3) true: valid assigned resource 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_cibool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct acpi_resource_memory24 *memory24; 10962306a36Sopenharmony_ci struct acpi_resource_memory32 *memory32; 11062306a36Sopenharmony_ci struct acpi_resource_fixed_memory32 *fixed_memory32; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci switch (ares->type) { 11362306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY24: 11462306a36Sopenharmony_ci memory24 = &ares->data.memory24; 11562306a36Sopenharmony_ci acpi_dev_get_memresource(res, memory24->minimum << 8, 11662306a36Sopenharmony_ci memory24->address_length << 8, 11762306a36Sopenharmony_ci memory24->write_protect); 11862306a36Sopenharmony_ci break; 11962306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY32: 12062306a36Sopenharmony_ci memory32 = &ares->data.memory32; 12162306a36Sopenharmony_ci acpi_dev_get_memresource(res, memory32->minimum, 12262306a36Sopenharmony_ci memory32->address_length, 12362306a36Sopenharmony_ci memory32->write_protect); 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 12662306a36Sopenharmony_ci fixed_memory32 = &ares->data.fixed_memory32; 12762306a36Sopenharmony_ci acpi_dev_get_memresource(res, fixed_memory32->address, 12862306a36Sopenharmony_ci fixed_memory32->address_length, 12962306a36Sopenharmony_ci fixed_memory32->write_protect); 13062306a36Sopenharmony_ci break; 13162306a36Sopenharmony_ci default: 13262306a36Sopenharmony_ci res->flags = 0; 13362306a36Sopenharmony_ci return false; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return !(res->flags & IORESOURCE_DISABLED); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_dev_resource_memory); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic void acpi_dev_ioresource_flags(struct resource *res, u64 len, 14162306a36Sopenharmony_ci u8 io_decode, u8 translation_type) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci res->flags = IORESOURCE_IO; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (!acpi_dev_resource_len_valid(res->start, res->end, len, true)) 14662306a36Sopenharmony_ci res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (!acpi_iospace_resource_valid(res)) 14962306a36Sopenharmony_ci res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (io_decode == ACPI_DECODE_16) 15262306a36Sopenharmony_ci res->flags |= IORESOURCE_IO_16BIT_ADDR; 15362306a36Sopenharmony_ci if (translation_type == ACPI_SPARSE_TRANSLATION) 15462306a36Sopenharmony_ci res->flags |= IORESOURCE_IO_SPARSE; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, 15862306a36Sopenharmony_ci u8 io_decode) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci res->start = start; 16162306a36Sopenharmony_ci res->end = start + len - 1; 16262306a36Sopenharmony_ci acpi_dev_ioresource_flags(res, len, io_decode, 0); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/** 16662306a36Sopenharmony_ci * acpi_dev_resource_io - Extract ACPI I/O resource information. 16762306a36Sopenharmony_ci * @ares: Input ACPI resource object. 16862306a36Sopenharmony_ci * @res: Output generic resource object. 16962306a36Sopenharmony_ci * 17062306a36Sopenharmony_ci * Check if the given ACPI resource object represents an I/O resource and 17162306a36Sopenharmony_ci * if that's the case, use the information in it to populate the generic 17262306a36Sopenharmony_ci * resource object pointed to by @res. 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci * Return: 17562306a36Sopenharmony_ci * 1) false with res->flags setting to zero: not the expected resource type 17662306a36Sopenharmony_ci * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource 17762306a36Sopenharmony_ci * 3) true: valid assigned resource 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_cibool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct acpi_resource_io *io; 18262306a36Sopenharmony_ci struct acpi_resource_fixed_io *fixed_io; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci switch (ares->type) { 18562306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_IO: 18662306a36Sopenharmony_ci io = &ares->data.io; 18762306a36Sopenharmony_ci acpi_dev_get_ioresource(res, io->minimum, 18862306a36Sopenharmony_ci io->address_length, 18962306a36Sopenharmony_ci io->io_decode); 19062306a36Sopenharmony_ci break; 19162306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_IO: 19262306a36Sopenharmony_ci fixed_io = &ares->data.fixed_io; 19362306a36Sopenharmony_ci acpi_dev_get_ioresource(res, fixed_io->address, 19462306a36Sopenharmony_ci fixed_io->address_length, 19562306a36Sopenharmony_ci ACPI_DECODE_10); 19662306a36Sopenharmony_ci break; 19762306a36Sopenharmony_ci default: 19862306a36Sopenharmony_ci res->flags = 0; 19962306a36Sopenharmony_ci return false; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return !(res->flags & IORESOURCE_DISABLED); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_dev_resource_io); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic bool acpi_decode_space(struct resource_win *win, 20762306a36Sopenharmony_ci struct acpi_resource_address *addr, 20862306a36Sopenharmony_ci struct acpi_address64_attribute *attr) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci u8 iodec = attr->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16; 21162306a36Sopenharmony_ci bool wp = addr->info.mem.write_protect; 21262306a36Sopenharmony_ci u64 len = attr->address_length; 21362306a36Sopenharmony_ci u64 start, end, offset = 0; 21462306a36Sopenharmony_ci struct resource *res = &win->res; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* 21762306a36Sopenharmony_ci * Filter out invalid descriptor according to ACPI Spec 5.0, section 21862306a36Sopenharmony_ci * 6.4.3.5 Address Space Resource Descriptors. 21962306a36Sopenharmony_ci */ 22062306a36Sopenharmony_ci if ((addr->min_address_fixed != addr->max_address_fixed && len) || 22162306a36Sopenharmony_ci (addr->min_address_fixed && addr->max_address_fixed && !len)) 22262306a36Sopenharmony_ci pr_debug("ACPI: Invalid address space min_addr_fix %d, max_addr_fix %d, len %llx\n", 22362306a36Sopenharmony_ci addr->min_address_fixed, addr->max_address_fixed, len); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* 22662306a36Sopenharmony_ci * For bridges that translate addresses across the bridge, 22762306a36Sopenharmony_ci * translation_offset is the offset that must be added to the 22862306a36Sopenharmony_ci * address on the secondary side to obtain the address on the 22962306a36Sopenharmony_ci * primary side. Non-bridge devices must list 0 for all Address 23062306a36Sopenharmony_ci * Translation offset bits. 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci if (addr->producer_consumer == ACPI_PRODUCER) 23362306a36Sopenharmony_ci offset = attr->translation_offset; 23462306a36Sopenharmony_ci else if (attr->translation_offset) 23562306a36Sopenharmony_ci pr_debug("ACPI: translation_offset(%lld) is invalid for non-bridge device.\n", 23662306a36Sopenharmony_ci attr->translation_offset); 23762306a36Sopenharmony_ci start = attr->minimum + offset; 23862306a36Sopenharmony_ci end = attr->maximum + offset; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci win->offset = offset; 24162306a36Sopenharmony_ci res->start = start; 24262306a36Sopenharmony_ci res->end = end; 24362306a36Sopenharmony_ci if (sizeof(resource_size_t) < sizeof(u64) && 24462306a36Sopenharmony_ci (offset != win->offset || start != res->start || end != res->end)) { 24562306a36Sopenharmony_ci pr_warn("acpi resource window ([%#llx-%#llx] ignored, not CPU addressable)\n", 24662306a36Sopenharmony_ci attr->minimum, attr->maximum); 24762306a36Sopenharmony_ci return false; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci switch (addr->resource_type) { 25162306a36Sopenharmony_ci case ACPI_MEMORY_RANGE: 25262306a36Sopenharmony_ci acpi_dev_memresource_flags(res, len, wp); 25362306a36Sopenharmony_ci break; 25462306a36Sopenharmony_ci case ACPI_IO_RANGE: 25562306a36Sopenharmony_ci acpi_dev_ioresource_flags(res, len, iodec, 25662306a36Sopenharmony_ci addr->info.io.translation_type); 25762306a36Sopenharmony_ci break; 25862306a36Sopenharmony_ci case ACPI_BUS_NUMBER_RANGE: 25962306a36Sopenharmony_ci res->flags = IORESOURCE_BUS; 26062306a36Sopenharmony_ci break; 26162306a36Sopenharmony_ci default: 26262306a36Sopenharmony_ci return false; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (addr->producer_consumer == ACPI_PRODUCER) 26662306a36Sopenharmony_ci res->flags |= IORESOURCE_WINDOW; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY) 26962306a36Sopenharmony_ci res->flags |= IORESOURCE_PREFETCH; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci return !(res->flags & IORESOURCE_DISABLED); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci/** 27562306a36Sopenharmony_ci * acpi_dev_resource_address_space - Extract ACPI address space information. 27662306a36Sopenharmony_ci * @ares: Input ACPI resource object. 27762306a36Sopenharmony_ci * @win: Output generic resource object. 27862306a36Sopenharmony_ci * 27962306a36Sopenharmony_ci * Check if the given ACPI resource object represents an address space resource 28062306a36Sopenharmony_ci * and if that's the case, use the information in it to populate the generic 28162306a36Sopenharmony_ci * resource object pointed to by @win. 28262306a36Sopenharmony_ci * 28362306a36Sopenharmony_ci * Return: 28462306a36Sopenharmony_ci * 1) false with win->res.flags setting to zero: not the expected resource type 28562306a36Sopenharmony_ci * 2) false with IORESOURCE_DISABLED in win->res.flags: valid unassigned 28662306a36Sopenharmony_ci * resource 28762306a36Sopenharmony_ci * 3) true: valid assigned resource 28862306a36Sopenharmony_ci */ 28962306a36Sopenharmony_cibool acpi_dev_resource_address_space(struct acpi_resource *ares, 29062306a36Sopenharmony_ci struct resource_win *win) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct acpi_resource_address64 addr; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci win->res.flags = 0; 29562306a36Sopenharmony_ci if (ACPI_FAILURE(acpi_resource_to_address64(ares, &addr))) 29662306a36Sopenharmony_ci return false; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci return acpi_decode_space(win, (struct acpi_resource_address *)&addr, 29962306a36Sopenharmony_ci &addr.address); 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci/** 30462306a36Sopenharmony_ci * acpi_dev_resource_ext_address_space - Extract ACPI address space information. 30562306a36Sopenharmony_ci * @ares: Input ACPI resource object. 30662306a36Sopenharmony_ci * @win: Output generic resource object. 30762306a36Sopenharmony_ci * 30862306a36Sopenharmony_ci * Check if the given ACPI resource object represents an extended address space 30962306a36Sopenharmony_ci * resource and if that's the case, use the information in it to populate the 31062306a36Sopenharmony_ci * generic resource object pointed to by @win. 31162306a36Sopenharmony_ci * 31262306a36Sopenharmony_ci * Return: 31362306a36Sopenharmony_ci * 1) false with win->res.flags setting to zero: not the expected resource type 31462306a36Sopenharmony_ci * 2) false with IORESOURCE_DISABLED in win->res.flags: valid unassigned 31562306a36Sopenharmony_ci * resource 31662306a36Sopenharmony_ci * 3) true: valid assigned resource 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_cibool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, 31962306a36Sopenharmony_ci struct resource_win *win) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct acpi_resource_extended_address64 *ext_addr; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci win->res.flags = 0; 32462306a36Sopenharmony_ci if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) 32562306a36Sopenharmony_ci return false; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci ext_addr = &ares->data.ext_address64; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return acpi_decode_space(win, (struct acpi_resource_address *)ext_addr, 33062306a36Sopenharmony_ci &ext_addr->address); 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci/** 33562306a36Sopenharmony_ci * acpi_dev_irq_flags - Determine IRQ resource flags. 33662306a36Sopenharmony_ci * @triggering: Triggering type as provided by ACPI. 33762306a36Sopenharmony_ci * @polarity: Interrupt polarity as provided by ACPI. 33862306a36Sopenharmony_ci * @shareable: Whether or not the interrupt is shareable. 33962306a36Sopenharmony_ci * @wake_capable: Wake capability as provided by ACPI. 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_ciunsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable, u8 wake_capable) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci unsigned long flags; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (triggering == ACPI_LEVEL_SENSITIVE) 34662306a36Sopenharmony_ci flags = polarity == ACPI_ACTIVE_LOW ? 34762306a36Sopenharmony_ci IORESOURCE_IRQ_LOWLEVEL : IORESOURCE_IRQ_HIGHLEVEL; 34862306a36Sopenharmony_ci else 34962306a36Sopenharmony_ci flags = polarity == ACPI_ACTIVE_LOW ? 35062306a36Sopenharmony_ci IORESOURCE_IRQ_LOWEDGE : IORESOURCE_IRQ_HIGHEDGE; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (shareable == ACPI_SHARED) 35362306a36Sopenharmony_ci flags |= IORESOURCE_IRQ_SHAREABLE; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (wake_capable == ACPI_WAKE_CAPABLE) 35662306a36Sopenharmony_ci flags |= IORESOURCE_IRQ_WAKECAPABLE; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci return flags | IORESOURCE_IRQ; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_dev_irq_flags); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci/** 36362306a36Sopenharmony_ci * acpi_dev_get_irq_type - Determine irq type. 36462306a36Sopenharmony_ci * @triggering: Triggering type as provided by ACPI. 36562306a36Sopenharmony_ci * @polarity: Interrupt polarity as provided by ACPI. 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_ciunsigned int acpi_dev_get_irq_type(int triggering, int polarity) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci switch (polarity) { 37062306a36Sopenharmony_ci case ACPI_ACTIVE_LOW: 37162306a36Sopenharmony_ci return triggering == ACPI_EDGE_SENSITIVE ? 37262306a36Sopenharmony_ci IRQ_TYPE_EDGE_FALLING : 37362306a36Sopenharmony_ci IRQ_TYPE_LEVEL_LOW; 37462306a36Sopenharmony_ci case ACPI_ACTIVE_HIGH: 37562306a36Sopenharmony_ci return triggering == ACPI_EDGE_SENSITIVE ? 37662306a36Sopenharmony_ci IRQ_TYPE_EDGE_RISING : 37762306a36Sopenharmony_ci IRQ_TYPE_LEVEL_HIGH; 37862306a36Sopenharmony_ci case ACPI_ACTIVE_BOTH: 37962306a36Sopenharmony_ci if (triggering == ACPI_EDGE_SENSITIVE) 38062306a36Sopenharmony_ci return IRQ_TYPE_EDGE_BOTH; 38162306a36Sopenharmony_ci fallthrough; 38262306a36Sopenharmony_ci default: 38362306a36Sopenharmony_ci return IRQ_TYPE_NONE; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_dev_get_irq_type); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic const struct dmi_system_id medion_laptop[] = { 38962306a36Sopenharmony_ci { 39062306a36Sopenharmony_ci .ident = "MEDION P15651", 39162306a36Sopenharmony_ci .matches = { 39262306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), 39362306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "M15T"), 39462306a36Sopenharmony_ci }, 39562306a36Sopenharmony_ci }, 39662306a36Sopenharmony_ci { 39762306a36Sopenharmony_ci .ident = "MEDION S17405", 39862306a36Sopenharmony_ci .matches = { 39962306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), 40062306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "M17T"), 40162306a36Sopenharmony_ci }, 40262306a36Sopenharmony_ci }, 40362306a36Sopenharmony_ci { 40462306a36Sopenharmony_ci .ident = "MEDION S17413", 40562306a36Sopenharmony_ci .matches = { 40662306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), 40762306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "M1xA"), 40862306a36Sopenharmony_ci }, 40962306a36Sopenharmony_ci }, 41062306a36Sopenharmony_ci { } 41162306a36Sopenharmony_ci}; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic const struct dmi_system_id asus_laptop[] = { 41462306a36Sopenharmony_ci { 41562306a36Sopenharmony_ci .ident = "Asus Vivobook K3402ZA", 41662306a36Sopenharmony_ci .matches = { 41762306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 41862306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "K3402ZA"), 41962306a36Sopenharmony_ci }, 42062306a36Sopenharmony_ci }, 42162306a36Sopenharmony_ci { 42262306a36Sopenharmony_ci .ident = "Asus Vivobook K3502ZA", 42362306a36Sopenharmony_ci .matches = { 42462306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 42562306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "K3502ZA"), 42662306a36Sopenharmony_ci }, 42762306a36Sopenharmony_ci }, 42862306a36Sopenharmony_ci { 42962306a36Sopenharmony_ci .ident = "Asus Vivobook S5402ZA", 43062306a36Sopenharmony_ci .matches = { 43162306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 43262306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "S5402ZA"), 43362306a36Sopenharmony_ci }, 43462306a36Sopenharmony_ci }, 43562306a36Sopenharmony_ci { 43662306a36Sopenharmony_ci .ident = "Asus Vivobook S5602ZA", 43762306a36Sopenharmony_ci .matches = { 43862306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 43962306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "S5602ZA"), 44062306a36Sopenharmony_ci }, 44162306a36Sopenharmony_ci }, 44262306a36Sopenharmony_ci { 44362306a36Sopenharmony_ci .ident = "Asus ExpertBook B1402CBA", 44462306a36Sopenharmony_ci .matches = { 44562306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 44662306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "B1402CBA"), 44762306a36Sopenharmony_ci }, 44862306a36Sopenharmony_ci }, 44962306a36Sopenharmony_ci { 45062306a36Sopenharmony_ci /* Asus ExpertBook B1402CVA */ 45162306a36Sopenharmony_ci .matches = { 45262306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 45362306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "B1402CVA"), 45462306a36Sopenharmony_ci }, 45562306a36Sopenharmony_ci }, 45662306a36Sopenharmony_ci { 45762306a36Sopenharmony_ci .ident = "Asus ExpertBook B1502CBA", 45862306a36Sopenharmony_ci .matches = { 45962306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 46062306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "B1502CBA"), 46162306a36Sopenharmony_ci }, 46262306a36Sopenharmony_ci }, 46362306a36Sopenharmony_ci { 46462306a36Sopenharmony_ci .ident = "Asus ExpertBook B2402CBA", 46562306a36Sopenharmony_ci .matches = { 46662306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 46762306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "B2402CBA"), 46862306a36Sopenharmony_ci }, 46962306a36Sopenharmony_ci }, 47062306a36Sopenharmony_ci { 47162306a36Sopenharmony_ci .ident = "Asus ExpertBook B2402FBA", 47262306a36Sopenharmony_ci .matches = { 47362306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 47462306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "B2402FBA"), 47562306a36Sopenharmony_ci }, 47662306a36Sopenharmony_ci }, 47762306a36Sopenharmony_ci { 47862306a36Sopenharmony_ci .ident = "Asus ExpertBook B2502", 47962306a36Sopenharmony_ci .matches = { 48062306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 48162306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "B2502CBA"), 48262306a36Sopenharmony_ci }, 48362306a36Sopenharmony_ci }, 48462306a36Sopenharmony_ci { } 48562306a36Sopenharmony_ci}; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic const struct dmi_system_id tongfang_gm_rg[] = { 48862306a36Sopenharmony_ci { 48962306a36Sopenharmony_ci .ident = "TongFang GMxRGxx/XMG CORE 15 (M22)/TUXEDO Stellaris 15 Gen4 AMD", 49062306a36Sopenharmony_ci .matches = { 49162306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "GMxRGxx"), 49262306a36Sopenharmony_ci }, 49362306a36Sopenharmony_ci }, 49462306a36Sopenharmony_ci { } 49562306a36Sopenharmony_ci}; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic const struct dmi_system_id maingear_laptop[] = { 49862306a36Sopenharmony_ci { 49962306a36Sopenharmony_ci .ident = "MAINGEAR Vector Pro 2 15", 50062306a36Sopenharmony_ci .matches = { 50162306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Micro Electronics Inc"), 50262306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "MG-VCP2-15A3070T"), 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci }, 50562306a36Sopenharmony_ci { 50662306a36Sopenharmony_ci /* TongFang GMxXGxx/TUXEDO Polaris 15 Gen5 AMD */ 50762306a36Sopenharmony_ci .matches = { 50862306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "GMxXGxx"), 50962306a36Sopenharmony_ci }, 51062306a36Sopenharmony_ci }, 51162306a36Sopenharmony_ci { 51262306a36Sopenharmony_ci /* TongFang GMxXGxx sold as Eluktronics Inc. RP-15 */ 51362306a36Sopenharmony_ci .matches = { 51462306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Eluktronics Inc."), 51562306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "RP-15"), 51662306a36Sopenharmony_ci }, 51762306a36Sopenharmony_ci }, 51862306a36Sopenharmony_ci { 51962306a36Sopenharmony_ci /* TongFang GM6XGxX/TUXEDO Stellaris 16 Gen5 AMD */ 52062306a36Sopenharmony_ci .matches = { 52162306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "GM6XGxX"), 52262306a36Sopenharmony_ci }, 52362306a36Sopenharmony_ci }, 52462306a36Sopenharmony_ci { 52562306a36Sopenharmony_ci .ident = "MAINGEAR Vector Pro 2 17", 52662306a36Sopenharmony_ci .matches = { 52762306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Micro Electronics Inc"), 52862306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "MG-VCP2-17A3070T"), 52962306a36Sopenharmony_ci }, 53062306a36Sopenharmony_ci }, 53162306a36Sopenharmony_ci { } 53262306a36Sopenharmony_ci}; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cistatic const struct dmi_system_id pcspecialist_laptop[] = { 53562306a36Sopenharmony_ci { 53662306a36Sopenharmony_ci /* TongFang GM6BGEQ / PCSpecialist Elimina Pro 16 M, RTX 3050 */ 53762306a36Sopenharmony_ci .matches = { 53862306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "GM6BGEQ"), 53962306a36Sopenharmony_ci }, 54062306a36Sopenharmony_ci }, 54162306a36Sopenharmony_ci { 54262306a36Sopenharmony_ci /* TongFang GM6BG5Q, RTX 4050 */ 54362306a36Sopenharmony_ci .matches = { 54462306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "GM6BG5Q"), 54562306a36Sopenharmony_ci }, 54662306a36Sopenharmony_ci }, 54762306a36Sopenharmony_ci { 54862306a36Sopenharmony_ci /* TongFang GM6BG0Q / PCSpecialist Elimina Pro 16 M, RTX 4060 */ 54962306a36Sopenharmony_ci .matches = { 55062306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "GM6BG0Q"), 55162306a36Sopenharmony_ci }, 55262306a36Sopenharmony_ci }, 55362306a36Sopenharmony_ci { 55462306a36Sopenharmony_ci /* Infinity E15-5A165-BM */ 55562306a36Sopenharmony_ci .matches = { 55662306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "GM5RG1E0009COM"), 55762306a36Sopenharmony_ci }, 55862306a36Sopenharmony_ci }, 55962306a36Sopenharmony_ci { 56062306a36Sopenharmony_ci /* Infinity E15-5A305-1M */ 56162306a36Sopenharmony_ci .matches = { 56262306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "GM5RGEE0016COM"), 56362306a36Sopenharmony_ci }, 56462306a36Sopenharmony_ci }, 56562306a36Sopenharmony_ci { 56662306a36Sopenharmony_ci /* Lunnen Ground 15 / AMD Ryzen 5 5500U */ 56762306a36Sopenharmony_ci .matches = { 56862306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Lunnen"), 56962306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "LLL5DAW"), 57062306a36Sopenharmony_ci }, 57162306a36Sopenharmony_ci }, 57262306a36Sopenharmony_ci { 57362306a36Sopenharmony_ci /* Lunnen Ground 16 / AMD Ryzen 7 5800U */ 57462306a36Sopenharmony_ci .matches = { 57562306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Lunnen"), 57662306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "LL6FA"), 57762306a36Sopenharmony_ci }, 57862306a36Sopenharmony_ci }, 57962306a36Sopenharmony_ci { 58062306a36Sopenharmony_ci /* MAIBENBEN X577 */ 58162306a36Sopenharmony_ci .matches = { 58262306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "MAIBENBEN"), 58362306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "X577"), 58462306a36Sopenharmony_ci }, 58562306a36Sopenharmony_ci }, 58662306a36Sopenharmony_ci { } 58762306a36Sopenharmony_ci}; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cistatic const struct dmi_system_id lg_laptop[] = { 59062306a36Sopenharmony_ci { 59162306a36Sopenharmony_ci .ident = "LG Electronics 17U70P", 59262306a36Sopenharmony_ci .matches = { 59362306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), 59462306a36Sopenharmony_ci DMI_MATCH(DMI_BOARD_NAME, "17U70P"), 59562306a36Sopenharmony_ci }, 59662306a36Sopenharmony_ci }, 59762306a36Sopenharmony_ci { } 59862306a36Sopenharmony_ci}; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistruct irq_override_cmp { 60162306a36Sopenharmony_ci const struct dmi_system_id *system; 60262306a36Sopenharmony_ci unsigned char irq; 60362306a36Sopenharmony_ci unsigned char triggering; 60462306a36Sopenharmony_ci unsigned char polarity; 60562306a36Sopenharmony_ci unsigned char shareable; 60662306a36Sopenharmony_ci bool override; 60762306a36Sopenharmony_ci}; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic const struct irq_override_cmp override_table[] = { 61062306a36Sopenharmony_ci { medion_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, 61162306a36Sopenharmony_ci { asus_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, 61262306a36Sopenharmony_ci { tongfang_gm_rg, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, 61362306a36Sopenharmony_ci { maingear_laptop, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, 61462306a36Sopenharmony_ci { pcspecialist_laptop, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, 61562306a36Sopenharmony_ci { lg_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, 61662306a36Sopenharmony_ci}; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_cistatic bool acpi_dev_irq_override(u32 gsi, u8 triggering, u8 polarity, 61962306a36Sopenharmony_ci u8 shareable) 62062306a36Sopenharmony_ci{ 62162306a36Sopenharmony_ci int i; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(override_table); i++) { 62462306a36Sopenharmony_ci const struct irq_override_cmp *entry = &override_table[i]; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci if (dmi_check_system(entry->system) && 62762306a36Sopenharmony_ci entry->irq == gsi && 62862306a36Sopenharmony_ci entry->triggering == triggering && 62962306a36Sopenharmony_ci entry->polarity == polarity && 63062306a36Sopenharmony_ci entry->shareable == shareable) 63162306a36Sopenharmony_ci return entry->override; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci#ifdef CONFIG_X86 63562306a36Sopenharmony_ci /* 63662306a36Sopenharmony_ci * Always use the MADT override info, except for the i8042 PS/2 ctrl 63762306a36Sopenharmony_ci * IRQs (1 and 12). For these the DSDT IRQ settings should sometimes 63862306a36Sopenharmony_ci * be used otherwise PS/2 keyboards / mice will not work. 63962306a36Sopenharmony_ci */ 64062306a36Sopenharmony_ci if (gsi != 1 && gsi != 12) 64162306a36Sopenharmony_ci return true; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci /* If the override comes from an INT_SRC_OVR MADT entry, honor it. */ 64462306a36Sopenharmony_ci if (acpi_int_src_ovr[gsi]) 64562306a36Sopenharmony_ci return true; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci /* 64862306a36Sopenharmony_ci * IRQ override isn't needed on modern AMD Zen systems and 64962306a36Sopenharmony_ci * this override breaks active low IRQs on AMD Ryzen 6000 and 65062306a36Sopenharmony_ci * newer systems. Skip it. 65162306a36Sopenharmony_ci */ 65262306a36Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_ZEN)) 65362306a36Sopenharmony_ci return false; 65462306a36Sopenharmony_ci#endif 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci return true; 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cistatic void acpi_dev_get_irqresource(struct resource *res, u32 gsi, 66062306a36Sopenharmony_ci u8 triggering, u8 polarity, u8 shareable, 66162306a36Sopenharmony_ci u8 wake_capable, bool check_override) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci int irq, p, t; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci if (!valid_IRQ(gsi)) { 66662306a36Sopenharmony_ci irqresource_disabled(res, gsi); 66762306a36Sopenharmony_ci return; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* 67162306a36Sopenharmony_ci * In IO-APIC mode, use overridden attribute. Two reasons: 67262306a36Sopenharmony_ci * 1. BIOS bug in DSDT 67362306a36Sopenharmony_ci * 2. BIOS uses IO-APIC mode Interrupt Source Override 67462306a36Sopenharmony_ci * 67562306a36Sopenharmony_ci * We do this only if we are dealing with IRQ() or IRQNoFlags() 67662306a36Sopenharmony_ci * resource (the legacy ISA resources). With modern ACPI 5 devices 67762306a36Sopenharmony_ci * using extended IRQ descriptors we take the IRQ configuration 67862306a36Sopenharmony_ci * from _CRS directly. 67962306a36Sopenharmony_ci */ 68062306a36Sopenharmony_ci if (check_override && 68162306a36Sopenharmony_ci acpi_dev_irq_override(gsi, triggering, polarity, shareable) && 68262306a36Sopenharmony_ci !acpi_get_override_irq(gsi, &t, &p)) { 68362306a36Sopenharmony_ci u8 trig = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE; 68462306a36Sopenharmony_ci u8 pol = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (triggering != trig || polarity != pol) { 68762306a36Sopenharmony_ci pr_warn("ACPI: IRQ %d override to %s%s, %s%s\n", gsi, 68862306a36Sopenharmony_ci t ? "level" : "edge", 68962306a36Sopenharmony_ci trig == triggering ? "" : "(!)", 69062306a36Sopenharmony_ci p ? "low" : "high", 69162306a36Sopenharmony_ci pol == polarity ? "" : "(!)"); 69262306a36Sopenharmony_ci triggering = trig; 69362306a36Sopenharmony_ci polarity = pol; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci res->flags = acpi_dev_irq_flags(triggering, polarity, shareable, wake_capable); 69862306a36Sopenharmony_ci irq = acpi_register_gsi(NULL, gsi, triggering, polarity); 69962306a36Sopenharmony_ci if (irq >= 0) { 70062306a36Sopenharmony_ci res->start = irq; 70162306a36Sopenharmony_ci res->end = irq; 70262306a36Sopenharmony_ci } else { 70362306a36Sopenharmony_ci irqresource_disabled(res, gsi); 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci/** 70862306a36Sopenharmony_ci * acpi_dev_resource_interrupt - Extract ACPI interrupt resource information. 70962306a36Sopenharmony_ci * @ares: Input ACPI resource object. 71062306a36Sopenharmony_ci * @index: Index into the array of GSIs represented by the resource. 71162306a36Sopenharmony_ci * @res: Output generic resource object. 71262306a36Sopenharmony_ci * 71362306a36Sopenharmony_ci * Check if the given ACPI resource object represents an interrupt resource 71462306a36Sopenharmony_ci * and @index does not exceed the resource's interrupt count (true is returned 71562306a36Sopenharmony_ci * in that case regardless of the results of the other checks)). If that's the 71662306a36Sopenharmony_ci * case, register the GSI corresponding to @index from the array of interrupts 71762306a36Sopenharmony_ci * represented by the resource and populate the generic resource object pointed 71862306a36Sopenharmony_ci * to by @res accordingly. If the registration of the GSI is not successful, 71962306a36Sopenharmony_ci * IORESOURCE_DISABLED will be set it that object's flags. 72062306a36Sopenharmony_ci * 72162306a36Sopenharmony_ci * Return: 72262306a36Sopenharmony_ci * 1) false with res->flags setting to zero: not the expected resource type 72362306a36Sopenharmony_ci * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource 72462306a36Sopenharmony_ci * 3) true: valid assigned resource 72562306a36Sopenharmony_ci */ 72662306a36Sopenharmony_cibool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, 72762306a36Sopenharmony_ci struct resource *res) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci struct acpi_resource_irq *irq; 73062306a36Sopenharmony_ci struct acpi_resource_extended_irq *ext_irq; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci switch (ares->type) { 73362306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_IRQ: 73462306a36Sopenharmony_ci /* 73562306a36Sopenharmony_ci * Per spec, only one interrupt per descriptor is allowed in 73662306a36Sopenharmony_ci * _CRS, but some firmware violates this, so parse them all. 73762306a36Sopenharmony_ci */ 73862306a36Sopenharmony_ci irq = &ares->data.irq; 73962306a36Sopenharmony_ci if (index >= irq->interrupt_count) { 74062306a36Sopenharmony_ci irqresource_disabled(res, 0); 74162306a36Sopenharmony_ci return false; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci acpi_dev_get_irqresource(res, irq->interrupts[index], 74462306a36Sopenharmony_ci irq->triggering, irq->polarity, 74562306a36Sopenharmony_ci irq->shareable, irq->wake_capable, 74662306a36Sopenharmony_ci true); 74762306a36Sopenharmony_ci break; 74862306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 74962306a36Sopenharmony_ci ext_irq = &ares->data.extended_irq; 75062306a36Sopenharmony_ci if (index >= ext_irq->interrupt_count) { 75162306a36Sopenharmony_ci irqresource_disabled(res, 0); 75262306a36Sopenharmony_ci return false; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci if (is_gsi(ext_irq)) 75562306a36Sopenharmony_ci acpi_dev_get_irqresource(res, ext_irq->interrupts[index], 75662306a36Sopenharmony_ci ext_irq->triggering, ext_irq->polarity, 75762306a36Sopenharmony_ci ext_irq->shareable, ext_irq->wake_capable, 75862306a36Sopenharmony_ci false); 75962306a36Sopenharmony_ci else 76062306a36Sopenharmony_ci irqresource_disabled(res, 0); 76162306a36Sopenharmony_ci break; 76262306a36Sopenharmony_ci default: 76362306a36Sopenharmony_ci res->flags = 0; 76462306a36Sopenharmony_ci return false; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci return true; 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci/** 77262306a36Sopenharmony_ci * acpi_dev_free_resource_list - Free resource from %acpi_dev_get_resources(). 77362306a36Sopenharmony_ci * @list: The head of the resource list to free. 77462306a36Sopenharmony_ci */ 77562306a36Sopenharmony_civoid acpi_dev_free_resource_list(struct list_head *list) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci resource_list_free(list); 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_dev_free_resource_list); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cistruct res_proc_context { 78262306a36Sopenharmony_ci struct list_head *list; 78362306a36Sopenharmony_ci int (*preproc)(struct acpi_resource *, void *); 78462306a36Sopenharmony_ci void *preproc_data; 78562306a36Sopenharmony_ci int count; 78662306a36Sopenharmony_ci int error; 78762306a36Sopenharmony_ci}; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic acpi_status acpi_dev_new_resource_entry(struct resource_win *win, 79062306a36Sopenharmony_ci struct res_proc_context *c) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci struct resource_entry *rentry; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci rentry = resource_list_create_entry(NULL, 0); 79562306a36Sopenharmony_ci if (!rentry) { 79662306a36Sopenharmony_ci c->error = -ENOMEM; 79762306a36Sopenharmony_ci return AE_NO_MEMORY; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci *rentry->res = win->res; 80062306a36Sopenharmony_ci rentry->offset = win->offset; 80162306a36Sopenharmony_ci resource_list_add_tail(rentry, c->list); 80262306a36Sopenharmony_ci c->count++; 80362306a36Sopenharmony_ci return AE_OK; 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic acpi_status acpi_dev_process_resource(struct acpi_resource *ares, 80762306a36Sopenharmony_ci void *context) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci struct res_proc_context *c = context; 81062306a36Sopenharmony_ci struct resource_win win; 81162306a36Sopenharmony_ci struct resource *res = &win.res; 81262306a36Sopenharmony_ci int i; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci if (c->preproc) { 81562306a36Sopenharmony_ci int ret; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci ret = c->preproc(ares, c->preproc_data); 81862306a36Sopenharmony_ci if (ret < 0) { 81962306a36Sopenharmony_ci c->error = ret; 82062306a36Sopenharmony_ci return AE_ABORT_METHOD; 82162306a36Sopenharmony_ci } else if (ret > 0) { 82262306a36Sopenharmony_ci return AE_OK; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci memset(&win, 0, sizeof(win)); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci if (acpi_dev_resource_memory(ares, res) 82962306a36Sopenharmony_ci || acpi_dev_resource_io(ares, res) 83062306a36Sopenharmony_ci || acpi_dev_resource_address_space(ares, &win) 83162306a36Sopenharmony_ci || acpi_dev_resource_ext_address_space(ares, &win)) 83262306a36Sopenharmony_ci return acpi_dev_new_resource_entry(&win, c); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci for (i = 0; acpi_dev_resource_interrupt(ares, i, res); i++) { 83562306a36Sopenharmony_ci acpi_status status; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci status = acpi_dev_new_resource_entry(&win, c); 83862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) 83962306a36Sopenharmony_ci return status; 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci return AE_OK; 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistatic int __acpi_dev_get_resources(struct acpi_device *adev, 84662306a36Sopenharmony_ci struct list_head *list, 84762306a36Sopenharmony_ci int (*preproc)(struct acpi_resource *, void *), 84862306a36Sopenharmony_ci void *preproc_data, char *method) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci struct res_proc_context c; 85162306a36Sopenharmony_ci acpi_status status; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (!adev || !adev->handle || !list_empty(list)) 85462306a36Sopenharmony_ci return -EINVAL; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci if (!acpi_has_method(adev->handle, method)) 85762306a36Sopenharmony_ci return 0; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci c.list = list; 86062306a36Sopenharmony_ci c.preproc = preproc; 86162306a36Sopenharmony_ci c.preproc_data = preproc_data; 86262306a36Sopenharmony_ci c.count = 0; 86362306a36Sopenharmony_ci c.error = 0; 86462306a36Sopenharmony_ci status = acpi_walk_resources(adev->handle, method, 86562306a36Sopenharmony_ci acpi_dev_process_resource, &c); 86662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 86762306a36Sopenharmony_ci acpi_dev_free_resource_list(list); 86862306a36Sopenharmony_ci return c.error ? c.error : -EIO; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci return c.count; 87262306a36Sopenharmony_ci} 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci/** 87562306a36Sopenharmony_ci * acpi_dev_get_resources - Get current resources of a device. 87662306a36Sopenharmony_ci * @adev: ACPI device node to get the resources for. 87762306a36Sopenharmony_ci * @list: Head of the resultant list of resources (must be empty). 87862306a36Sopenharmony_ci * @preproc: The caller's preprocessing routine. 87962306a36Sopenharmony_ci * @preproc_data: Pointer passed to the caller's preprocessing routine. 88062306a36Sopenharmony_ci * 88162306a36Sopenharmony_ci * Evaluate the _CRS method for the given device node and process its output by 88262306a36Sopenharmony_ci * (1) executing the @preproc() routine provided by the caller, passing the 88362306a36Sopenharmony_ci * resource pointer and @preproc_data to it as arguments, for each ACPI resource 88462306a36Sopenharmony_ci * returned and (2) converting all of the returned ACPI resources into struct 88562306a36Sopenharmony_ci * resource objects if possible. If the return value of @preproc() in step (1) 88662306a36Sopenharmony_ci * is different from 0, step (2) is not applied to the given ACPI resource and 88762306a36Sopenharmony_ci * if that value is negative, the whole processing is aborted and that value is 88862306a36Sopenharmony_ci * returned as the final error code. 88962306a36Sopenharmony_ci * 89062306a36Sopenharmony_ci * The resultant struct resource objects are put on the list pointed to by 89162306a36Sopenharmony_ci * @list, that must be empty initially, as members of struct resource_entry 89262306a36Sopenharmony_ci * objects. Callers of this routine should use %acpi_dev_free_resource_list() to 89362306a36Sopenharmony_ci * free that list. 89462306a36Sopenharmony_ci * 89562306a36Sopenharmony_ci * The number of resources in the output list is returned on success, an error 89662306a36Sopenharmony_ci * code reflecting the error condition is returned otherwise. 89762306a36Sopenharmony_ci */ 89862306a36Sopenharmony_ciint acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, 89962306a36Sopenharmony_ci int (*preproc)(struct acpi_resource *, void *), 90062306a36Sopenharmony_ci void *preproc_data) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci return __acpi_dev_get_resources(adev, list, preproc, preproc_data, 90362306a36Sopenharmony_ci METHOD_NAME__CRS); 90462306a36Sopenharmony_ci} 90562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_dev_get_resources); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_cistatic int is_memory(struct acpi_resource *ares, void *not_used) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci struct resource_win win; 91062306a36Sopenharmony_ci struct resource *res = &win.res; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci memset(&win, 0, sizeof(win)); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci if (acpi_dev_filter_resource_type(ares, IORESOURCE_MEM)) 91562306a36Sopenharmony_ci return 1; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci return !(acpi_dev_resource_memory(ares, res) 91862306a36Sopenharmony_ci || acpi_dev_resource_address_space(ares, &win) 91962306a36Sopenharmony_ci || acpi_dev_resource_ext_address_space(ares, &win)); 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci/** 92362306a36Sopenharmony_ci * acpi_dev_get_dma_resources - Get current DMA resources of a device. 92462306a36Sopenharmony_ci * @adev: ACPI device node to get the resources for. 92562306a36Sopenharmony_ci * @list: Head of the resultant list of resources (must be empty). 92662306a36Sopenharmony_ci * 92762306a36Sopenharmony_ci * Evaluate the _DMA method for the given device node and process its 92862306a36Sopenharmony_ci * output. 92962306a36Sopenharmony_ci * 93062306a36Sopenharmony_ci * The resultant struct resource objects are put on the list pointed to 93162306a36Sopenharmony_ci * by @list, that must be empty initially, as members of struct 93262306a36Sopenharmony_ci * resource_entry objects. Callers of this routine should use 93362306a36Sopenharmony_ci * %acpi_dev_free_resource_list() to free that list. 93462306a36Sopenharmony_ci * 93562306a36Sopenharmony_ci * The number of resources in the output list is returned on success, 93662306a36Sopenharmony_ci * an error code reflecting the error condition is returned otherwise. 93762306a36Sopenharmony_ci */ 93862306a36Sopenharmony_ciint acpi_dev_get_dma_resources(struct acpi_device *adev, struct list_head *list) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci return __acpi_dev_get_resources(adev, list, is_memory, NULL, 94162306a36Sopenharmony_ci METHOD_NAME__DMA); 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_dev_get_dma_resources); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci/** 94662306a36Sopenharmony_ci * acpi_dev_get_memory_resources - Get current memory resources of a device. 94762306a36Sopenharmony_ci * @adev: ACPI device node to get the resources for. 94862306a36Sopenharmony_ci * @list: Head of the resultant list of resources (must be empty). 94962306a36Sopenharmony_ci * 95062306a36Sopenharmony_ci * This is a helper function that locates all memory type resources of @adev 95162306a36Sopenharmony_ci * with acpi_dev_get_resources(). 95262306a36Sopenharmony_ci * 95362306a36Sopenharmony_ci * The number of resources in the output list is returned on success, an error 95462306a36Sopenharmony_ci * code reflecting the error condition is returned otherwise. 95562306a36Sopenharmony_ci */ 95662306a36Sopenharmony_ciint acpi_dev_get_memory_resources(struct acpi_device *adev, struct list_head *list) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci return acpi_dev_get_resources(adev, list, is_memory, NULL); 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_dev_get_memory_resources); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci/** 96362306a36Sopenharmony_ci * acpi_dev_filter_resource_type - Filter ACPI resource according to resource 96462306a36Sopenharmony_ci * types 96562306a36Sopenharmony_ci * @ares: Input ACPI resource object. 96662306a36Sopenharmony_ci * @types: Valid resource types of IORESOURCE_XXX 96762306a36Sopenharmony_ci * 96862306a36Sopenharmony_ci * This is a helper function to support acpi_dev_get_resources(), which filters 96962306a36Sopenharmony_ci * ACPI resource objects according to resource types. 97062306a36Sopenharmony_ci */ 97162306a36Sopenharmony_ciint acpi_dev_filter_resource_type(struct acpi_resource *ares, 97262306a36Sopenharmony_ci unsigned long types) 97362306a36Sopenharmony_ci{ 97462306a36Sopenharmony_ci unsigned long type = 0; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci switch (ares->type) { 97762306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY24: 97862306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY32: 97962306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 98062306a36Sopenharmony_ci type = IORESOURCE_MEM; 98162306a36Sopenharmony_ci break; 98262306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_IO: 98362306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_IO: 98462306a36Sopenharmony_ci type = IORESOURCE_IO; 98562306a36Sopenharmony_ci break; 98662306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_IRQ: 98762306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 98862306a36Sopenharmony_ci type = IORESOURCE_IRQ; 98962306a36Sopenharmony_ci break; 99062306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_DMA: 99162306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_DMA: 99262306a36Sopenharmony_ci type = IORESOURCE_DMA; 99362306a36Sopenharmony_ci break; 99462306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: 99562306a36Sopenharmony_ci type = IORESOURCE_REG; 99662306a36Sopenharmony_ci break; 99762306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS16: 99862306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS32: 99962306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS64: 100062306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: 100162306a36Sopenharmony_ci if (ares->data.address.resource_type == ACPI_MEMORY_RANGE) 100262306a36Sopenharmony_ci type = IORESOURCE_MEM; 100362306a36Sopenharmony_ci else if (ares->data.address.resource_type == ACPI_IO_RANGE) 100462306a36Sopenharmony_ci type = IORESOURCE_IO; 100562306a36Sopenharmony_ci else if (ares->data.address.resource_type == 100662306a36Sopenharmony_ci ACPI_BUS_NUMBER_RANGE) 100762306a36Sopenharmony_ci type = IORESOURCE_BUS; 100862306a36Sopenharmony_ci break; 100962306a36Sopenharmony_ci default: 101062306a36Sopenharmony_ci break; 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci return (type & types) ? 0 : 1; 101462306a36Sopenharmony_ci} 101562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type); 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_cistatic int acpi_dev_consumes_res(struct acpi_device *adev, struct resource *res) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci struct list_head resource_list; 102062306a36Sopenharmony_ci struct resource_entry *rentry; 102162306a36Sopenharmony_ci int ret, found = 0; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci INIT_LIST_HEAD(&resource_list); 102462306a36Sopenharmony_ci ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); 102562306a36Sopenharmony_ci if (ret < 0) 102662306a36Sopenharmony_ci return 0; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci list_for_each_entry(rentry, &resource_list, node) { 102962306a36Sopenharmony_ci if (resource_contains(rentry->res, res)) { 103062306a36Sopenharmony_ci found = 1; 103162306a36Sopenharmony_ci break; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci acpi_dev_free_resource_list(&resource_list); 103762306a36Sopenharmony_ci return found; 103862306a36Sopenharmony_ci} 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_cistatic acpi_status acpi_res_consumer_cb(acpi_handle handle, u32 depth, 104162306a36Sopenharmony_ci void *context, void **ret) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci struct resource *res = context; 104462306a36Sopenharmony_ci struct acpi_device **consumer = (struct acpi_device **) ret; 104562306a36Sopenharmony_ci struct acpi_device *adev = acpi_fetch_acpi_dev(handle); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci if (!adev) 104862306a36Sopenharmony_ci return AE_OK; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci if (acpi_dev_consumes_res(adev, res)) { 105162306a36Sopenharmony_ci *consumer = adev; 105262306a36Sopenharmony_ci return AE_CTRL_TERMINATE; 105362306a36Sopenharmony_ci } 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci return AE_OK; 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci/** 105962306a36Sopenharmony_ci * acpi_resource_consumer - Find the ACPI device that consumes @res. 106062306a36Sopenharmony_ci * @res: Resource to search for. 106162306a36Sopenharmony_ci * 106262306a36Sopenharmony_ci * Search the current resource settings (_CRS) of every ACPI device node 106362306a36Sopenharmony_ci * for @res. If we find an ACPI device whose _CRS includes @res, return 106462306a36Sopenharmony_ci * it. Otherwise, return NULL. 106562306a36Sopenharmony_ci */ 106662306a36Sopenharmony_cistruct acpi_device *acpi_resource_consumer(struct resource *res) 106762306a36Sopenharmony_ci{ 106862306a36Sopenharmony_ci struct acpi_device *consumer = NULL; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci acpi_get_devices(NULL, acpi_res_consumer_cb, res, (void **) &consumer); 107162306a36Sopenharmony_ci return consumer; 107262306a36Sopenharmony_ci} 1073