1046d9ce6SRafael J. Wysocki /* 2046d9ce6SRafael J. Wysocki * drivers/acpi/resource.c - ACPI device resources interpretation. 3046d9ce6SRafael J. Wysocki * 4046d9ce6SRafael J. Wysocki * Copyright (C) 2012, Intel Corp. 5046d9ce6SRafael J. Wysocki * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> 6046d9ce6SRafael J. Wysocki * 7046d9ce6SRafael J. Wysocki * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8046d9ce6SRafael J. Wysocki * 9046d9ce6SRafael J. Wysocki * This program is free software; you can redistribute it and/or modify 10046d9ce6SRafael J. Wysocki * it under the terms of the GNU General Public License version 2 as published 11046d9ce6SRafael J. Wysocki * by the Free Software Foundation. 12046d9ce6SRafael J. Wysocki * 13046d9ce6SRafael J. Wysocki * This program is distributed in the hope that it will be useful, but 14046d9ce6SRafael J. Wysocki * WITHOUT ANY WARRANTY; without even the implied warranty of 15046d9ce6SRafael J. Wysocki * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16046d9ce6SRafael J. Wysocki * General Public License for more details. 17046d9ce6SRafael J. Wysocki * 18046d9ce6SRafael J. Wysocki * You should have received a copy of the GNU General Public License along 19046d9ce6SRafael J. Wysocki * with this program; if not, write to the Free Software Foundation, Inc., 20046d9ce6SRafael J. Wysocki * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 21046d9ce6SRafael J. Wysocki * 22046d9ce6SRafael J. Wysocki * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 23046d9ce6SRafael J. Wysocki */ 24046d9ce6SRafael J. Wysocki 25046d9ce6SRafael J. Wysocki #include <linux/acpi.h> 26046d9ce6SRafael J. Wysocki #include <linux/device.h> 27046d9ce6SRafael J. Wysocki #include <linux/export.h> 28046d9ce6SRafael J. Wysocki #include <linux/ioport.h> 298e345c99SRafael J. Wysocki #include <linux/slab.h> 30046d9ce6SRafael J. Wysocki 31046d9ce6SRafael J. Wysocki #ifdef CONFIG_X86 32046d9ce6SRafael J. Wysocki #define valid_IRQ(i) (((i) != 0) && ((i) != 2)) 33046d9ce6SRafael J. Wysocki #else 34046d9ce6SRafael J. Wysocki #define valid_IRQ(i) (true) 35046d9ce6SRafael J. Wysocki #endif 36046d9ce6SRafael J. Wysocki 37c420dbd1SThomas Gleixner static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io) 38046d9ce6SRafael J. Wysocki { 39c420dbd1SThomas Gleixner u64 reslen = end - start + 1; 40046d9ce6SRafael J. Wysocki 41c420dbd1SThomas Gleixner /* 42c420dbd1SThomas Gleixner * CHECKME: len might be required to check versus a minimum 43c420dbd1SThomas Gleixner * length as well. 1 for io is fine, but for memory it does 44c420dbd1SThomas Gleixner * not make any sense at all. 45c420dbd1SThomas Gleixner */ 46c420dbd1SThomas Gleixner if (len && reslen && reslen == len && start <= end) 47c420dbd1SThomas Gleixner return true; 48c420dbd1SThomas Gleixner 49c420dbd1SThomas Gleixner pr_info("ACPI: invalid or unassigned resource %s [%016llx - %016llx] length [%016llx]\n", 50c420dbd1SThomas Gleixner io ? "io" : "mem", start, end, len); 51c420dbd1SThomas Gleixner 52c420dbd1SThomas Gleixner return false; 53c420dbd1SThomas Gleixner } 54c420dbd1SThomas Gleixner 55c420dbd1SThomas Gleixner static void acpi_dev_memresource_flags(struct resource *res, u64 len, 56c420dbd1SThomas Gleixner u8 write_protect, bool window) 57c420dbd1SThomas Gleixner { 58c420dbd1SThomas Gleixner res->flags = IORESOURCE_MEM; 59c420dbd1SThomas Gleixner 60c420dbd1SThomas Gleixner if (!acpi_dev_resource_len_valid(res->start, res->end, len, false)) 61c420dbd1SThomas Gleixner res->flags |= IORESOURCE_DISABLED; 62046d9ce6SRafael J. Wysocki 63046d9ce6SRafael J. Wysocki if (write_protect == ACPI_READ_WRITE_MEMORY) 64c420dbd1SThomas Gleixner res->flags |= IORESOURCE_MEM_WRITEABLE; 65046d9ce6SRafael J. Wysocki 66046d9ce6SRafael J. Wysocki if (window) 67c420dbd1SThomas Gleixner res->flags |= IORESOURCE_WINDOW; 68046d9ce6SRafael J. Wysocki } 69046d9ce6SRafael J. Wysocki 70046d9ce6SRafael J. Wysocki static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, 71046d9ce6SRafael J. Wysocki u8 write_protect) 72046d9ce6SRafael J. Wysocki { 73046d9ce6SRafael J. Wysocki res->start = start; 74046d9ce6SRafael J. Wysocki res->end = start + len - 1; 75c420dbd1SThomas Gleixner acpi_dev_memresource_flags(res, len, write_protect, false); 76046d9ce6SRafael J. Wysocki } 77046d9ce6SRafael J. Wysocki 78046d9ce6SRafael J. Wysocki /** 79046d9ce6SRafael J. Wysocki * acpi_dev_resource_memory - Extract ACPI memory resource information. 80046d9ce6SRafael J. Wysocki * @ares: Input ACPI resource object. 81046d9ce6SRafael J. Wysocki * @res: Output generic resource object. 82046d9ce6SRafael J. Wysocki * 83046d9ce6SRafael J. Wysocki * Check if the given ACPI resource object represents a memory resource and 84046d9ce6SRafael J. Wysocki * if that's the case, use the information in it to populate the generic 85046d9ce6SRafael J. Wysocki * resource object pointed to by @res. 86046d9ce6SRafael J. Wysocki */ 87046d9ce6SRafael J. Wysocki bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) 88046d9ce6SRafael J. Wysocki { 89046d9ce6SRafael J. Wysocki struct acpi_resource_memory24 *memory24; 90046d9ce6SRafael J. Wysocki struct acpi_resource_memory32 *memory32; 91046d9ce6SRafael J. Wysocki struct acpi_resource_fixed_memory32 *fixed_memory32; 92046d9ce6SRafael J. Wysocki 93046d9ce6SRafael J. Wysocki switch (ares->type) { 94046d9ce6SRafael J. Wysocki case ACPI_RESOURCE_TYPE_MEMORY24: 95046d9ce6SRafael J. Wysocki memory24 = &ares->data.memory24; 96046d9ce6SRafael J. Wysocki acpi_dev_get_memresource(res, memory24->minimum, 97046d9ce6SRafael J. Wysocki memory24->address_length, 98046d9ce6SRafael J. Wysocki memory24->write_protect); 99046d9ce6SRafael J. Wysocki break; 100046d9ce6SRafael J. Wysocki case ACPI_RESOURCE_TYPE_MEMORY32: 101046d9ce6SRafael J. Wysocki memory32 = &ares->data.memory32; 102046d9ce6SRafael J. Wysocki acpi_dev_get_memresource(res, memory32->minimum, 103046d9ce6SRafael J. Wysocki memory32->address_length, 104046d9ce6SRafael J. Wysocki memory32->write_protect); 105046d9ce6SRafael J. Wysocki break; 106046d9ce6SRafael J. Wysocki case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 107046d9ce6SRafael J. Wysocki fixed_memory32 = &ares->data.fixed_memory32; 108046d9ce6SRafael J. Wysocki acpi_dev_get_memresource(res, fixed_memory32->address, 109046d9ce6SRafael J. Wysocki fixed_memory32->address_length, 110046d9ce6SRafael J. Wysocki fixed_memory32->write_protect); 111046d9ce6SRafael J. Wysocki break; 112046d9ce6SRafael J. Wysocki default: 113046d9ce6SRafael J. Wysocki return false; 114046d9ce6SRafael J. Wysocki } 115c420dbd1SThomas Gleixner 116c420dbd1SThomas Gleixner return !(res->flags & IORESOURCE_DISABLED); 117046d9ce6SRafael J. Wysocki } 118046d9ce6SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_dev_resource_memory); 119046d9ce6SRafael J. Wysocki 1201d0420f1SThomas Gleixner static void acpi_dev_ioresource_flags(struct resource *res, u64 len, 1211d0420f1SThomas Gleixner u8 io_decode, bool window) 122046d9ce6SRafael J. Wysocki { 1231d0420f1SThomas Gleixner res->flags = IORESOURCE_IO; 1241d0420f1SThomas Gleixner 1251d0420f1SThomas Gleixner if (!acpi_dev_resource_len_valid(res->start, res->end, len, true)) 1261d0420f1SThomas Gleixner res->flags |= IORESOURCE_DISABLED; 1271d0420f1SThomas Gleixner 1281d0420f1SThomas Gleixner if (res->end >= 0x10003) 1291d0420f1SThomas Gleixner res->flags |= IORESOURCE_DISABLED; 130046d9ce6SRafael J. Wysocki 131046d9ce6SRafael J. Wysocki if (io_decode == ACPI_DECODE_16) 1321d0420f1SThomas Gleixner res->flags |= IORESOURCE_IO_16BIT_ADDR; 133046d9ce6SRafael J. Wysocki 134046d9ce6SRafael J. Wysocki if (window) 1351d0420f1SThomas Gleixner res->flags |= IORESOURCE_WINDOW; 136046d9ce6SRafael J. Wysocki } 137046d9ce6SRafael J. Wysocki 138046d9ce6SRafael J. Wysocki static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, 139046d9ce6SRafael J. Wysocki u8 io_decode) 140046d9ce6SRafael J. Wysocki { 141046d9ce6SRafael J. Wysocki res->start = start; 1421d0420f1SThomas Gleixner res->end = start + len - 1; 1431d0420f1SThomas Gleixner acpi_dev_ioresource_flags(res, len, io_decode, false); 144046d9ce6SRafael J. Wysocki } 145046d9ce6SRafael J. Wysocki 146046d9ce6SRafael J. Wysocki /** 147046d9ce6SRafael J. Wysocki * acpi_dev_resource_io - Extract ACPI I/O resource information. 148046d9ce6SRafael J. Wysocki * @ares: Input ACPI resource object. 149046d9ce6SRafael J. Wysocki * @res: Output generic resource object. 150046d9ce6SRafael J. Wysocki * 151046d9ce6SRafael J. Wysocki * Check if the given ACPI resource object represents an I/O resource and 152046d9ce6SRafael J. Wysocki * if that's the case, use the information in it to populate the generic 153046d9ce6SRafael J. Wysocki * resource object pointed to by @res. 154046d9ce6SRafael J. Wysocki */ 155046d9ce6SRafael J. Wysocki bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) 156046d9ce6SRafael J. Wysocki { 157046d9ce6SRafael J. Wysocki struct acpi_resource_io *io; 158046d9ce6SRafael J. Wysocki struct acpi_resource_fixed_io *fixed_io; 159046d9ce6SRafael J. Wysocki 160046d9ce6SRafael J. Wysocki switch (ares->type) { 161046d9ce6SRafael J. Wysocki case ACPI_RESOURCE_TYPE_IO: 162046d9ce6SRafael J. Wysocki io = &ares->data.io; 163046d9ce6SRafael J. Wysocki acpi_dev_get_ioresource(res, io->minimum, 164046d9ce6SRafael J. Wysocki io->address_length, 165046d9ce6SRafael J. Wysocki io->io_decode); 166046d9ce6SRafael J. Wysocki break; 167046d9ce6SRafael J. Wysocki case ACPI_RESOURCE_TYPE_FIXED_IO: 168046d9ce6SRafael J. Wysocki fixed_io = &ares->data.fixed_io; 169046d9ce6SRafael J. Wysocki acpi_dev_get_ioresource(res, fixed_io->address, 170046d9ce6SRafael J. Wysocki fixed_io->address_length, 171046d9ce6SRafael J. Wysocki ACPI_DECODE_10); 172046d9ce6SRafael J. Wysocki break; 173046d9ce6SRafael J. Wysocki default: 174046d9ce6SRafael J. Wysocki return false; 175046d9ce6SRafael J. Wysocki } 1761d0420f1SThomas Gleixner 1771d0420f1SThomas Gleixner return !(res->flags & IORESOURCE_DISABLED); 178046d9ce6SRafael J. Wysocki } 179046d9ce6SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_dev_resource_io); 180046d9ce6SRafael J. Wysocki 181*eb76d55eSThomas Gleixner static bool acpi_decode_space(struct resource *res, 182*eb76d55eSThomas Gleixner struct acpi_resource_address *addr, 183*eb76d55eSThomas Gleixner struct acpi_address64_attribute *attr) 184*eb76d55eSThomas Gleixner { 185*eb76d55eSThomas Gleixner u8 iodec = attr->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16; 186*eb76d55eSThomas Gleixner bool window = addr->producer_consumer == ACPI_PRODUCER; 187*eb76d55eSThomas Gleixner bool wp = addr->info.mem.write_protect; 188*eb76d55eSThomas Gleixner u64 len = attr->address_length; 189*eb76d55eSThomas Gleixner 190*eb76d55eSThomas Gleixner res->start = attr->minimum; 191*eb76d55eSThomas Gleixner res->end = attr->maximum; 192*eb76d55eSThomas Gleixner 193*eb76d55eSThomas Gleixner switch (addr->resource_type) { 194*eb76d55eSThomas Gleixner case ACPI_MEMORY_RANGE: 195*eb76d55eSThomas Gleixner acpi_dev_memresource_flags(res, len, wp, window); 196*eb76d55eSThomas Gleixner break; 197*eb76d55eSThomas Gleixner case ACPI_IO_RANGE: 198*eb76d55eSThomas Gleixner acpi_dev_ioresource_flags(res, len, iodec, window); 199*eb76d55eSThomas Gleixner break; 200*eb76d55eSThomas Gleixner case ACPI_BUS_NUMBER_RANGE: 201*eb76d55eSThomas Gleixner res->flags = IORESOURCE_BUS; 202*eb76d55eSThomas Gleixner break; 203*eb76d55eSThomas Gleixner default: 204*eb76d55eSThomas Gleixner return false; 205*eb76d55eSThomas Gleixner } 206*eb76d55eSThomas Gleixner 207*eb76d55eSThomas Gleixner return !(res->flags & IORESOURCE_DISABLED); 208*eb76d55eSThomas Gleixner } 209*eb76d55eSThomas Gleixner 210046d9ce6SRafael J. Wysocki /** 211046d9ce6SRafael J. Wysocki * acpi_dev_resource_address_space - Extract ACPI address space information. 212046d9ce6SRafael J. Wysocki * @ares: Input ACPI resource object. 213046d9ce6SRafael J. Wysocki * @res: Output generic resource object. 214046d9ce6SRafael J. Wysocki * 215046d9ce6SRafael J. Wysocki * Check if the given ACPI resource object represents an address space resource 216046d9ce6SRafael J. Wysocki * and if that's the case, use the information in it to populate the generic 217046d9ce6SRafael J. Wysocki * resource object pointed to by @res. 218046d9ce6SRafael J. Wysocki */ 219046d9ce6SRafael J. Wysocki bool acpi_dev_resource_address_space(struct acpi_resource *ares, 220046d9ce6SRafael J. Wysocki struct resource *res) 221046d9ce6SRafael J. Wysocki { 222046d9ce6SRafael J. Wysocki struct acpi_resource_address64 addr; 223046d9ce6SRafael J. Wysocki 224*eb76d55eSThomas Gleixner if (ACPI_FAILURE(acpi_resource_to_address64(ares, &addr))) 2256658c739SJiang Liu return false; 226046d9ce6SRafael J. Wysocki 227*eb76d55eSThomas Gleixner return acpi_decode_space(res, (struct acpi_resource_address *)&addr, 228*eb76d55eSThomas Gleixner &addr.address); 229046d9ce6SRafael J. Wysocki } 230046d9ce6SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); 231046d9ce6SRafael J. Wysocki 232046d9ce6SRafael J. Wysocki /** 233046d9ce6SRafael J. Wysocki * acpi_dev_resource_ext_address_space - Extract ACPI address space information. 234046d9ce6SRafael J. Wysocki * @ares: Input ACPI resource object. 235046d9ce6SRafael J. Wysocki * @res: Output generic resource object. 236046d9ce6SRafael J. Wysocki * 237046d9ce6SRafael J. Wysocki * Check if the given ACPI resource object represents an extended address space 238046d9ce6SRafael J. Wysocki * resource and if that's the case, use the information in it to populate the 239046d9ce6SRafael J. Wysocki * generic resource object pointed to by @res. 240046d9ce6SRafael J. Wysocki */ 241046d9ce6SRafael J. Wysocki bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, 242046d9ce6SRafael J. Wysocki struct resource *res) 243046d9ce6SRafael J. Wysocki { 244046d9ce6SRafael J. Wysocki struct acpi_resource_extended_address64 *ext_addr; 245046d9ce6SRafael J. Wysocki 246046d9ce6SRafael J. Wysocki if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) 247046d9ce6SRafael J. Wysocki return false; 248046d9ce6SRafael J. Wysocki 249046d9ce6SRafael J. Wysocki ext_addr = &ares->data.ext_address64; 250046d9ce6SRafael J. Wysocki 251*eb76d55eSThomas Gleixner return acpi_decode_space(res, (struct acpi_resource_address *)ext_addr, 252*eb76d55eSThomas Gleixner &ext_addr->address); 253046d9ce6SRafael J. Wysocki } 254046d9ce6SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space); 255046d9ce6SRafael J. Wysocki 256046d9ce6SRafael J. Wysocki /** 257046d9ce6SRafael J. Wysocki * acpi_dev_irq_flags - Determine IRQ resource flags. 258046d9ce6SRafael J. Wysocki * @triggering: Triggering type as provided by ACPI. 259046d9ce6SRafael J. Wysocki * @polarity: Interrupt polarity as provided by ACPI. 260046d9ce6SRafael J. Wysocki * @shareable: Whether or not the interrupt is shareable. 261046d9ce6SRafael J. Wysocki */ 262046d9ce6SRafael J. Wysocki unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable) 263046d9ce6SRafael J. Wysocki { 264046d9ce6SRafael J. Wysocki unsigned long flags; 265046d9ce6SRafael J. Wysocki 266046d9ce6SRafael J. Wysocki if (triggering == ACPI_LEVEL_SENSITIVE) 267046d9ce6SRafael J. Wysocki flags = polarity == ACPI_ACTIVE_LOW ? 268046d9ce6SRafael J. Wysocki IORESOURCE_IRQ_LOWLEVEL : IORESOURCE_IRQ_HIGHLEVEL; 269046d9ce6SRafael J. Wysocki else 270046d9ce6SRafael J. Wysocki flags = polarity == ACPI_ACTIVE_LOW ? 271046d9ce6SRafael J. Wysocki IORESOURCE_IRQ_LOWEDGE : IORESOURCE_IRQ_HIGHEDGE; 272046d9ce6SRafael J. Wysocki 273046d9ce6SRafael J. Wysocki if (shareable == ACPI_SHARED) 274046d9ce6SRafael J. Wysocki flags |= IORESOURCE_IRQ_SHAREABLE; 275046d9ce6SRafael J. Wysocki 276046d9ce6SRafael J. Wysocki return flags | IORESOURCE_IRQ; 277046d9ce6SRafael J. Wysocki } 278046d9ce6SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_dev_irq_flags); 279046d9ce6SRafael J. Wysocki 280046d9ce6SRafael J. Wysocki static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi) 281046d9ce6SRafael J. Wysocki { 282046d9ce6SRafael J. Wysocki res->start = gsi; 283046d9ce6SRafael J. Wysocki res->end = gsi; 284046d9ce6SRafael J. Wysocki res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED; 285046d9ce6SRafael J. Wysocki } 286046d9ce6SRafael J. Wysocki 287046d9ce6SRafael J. Wysocki static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, 288204ebc0aSMika Westerberg u8 triggering, u8 polarity, u8 shareable, 289204ebc0aSMika Westerberg bool legacy) 290046d9ce6SRafael J. Wysocki { 291046d9ce6SRafael J. Wysocki int irq, p, t; 292046d9ce6SRafael J. Wysocki 293046d9ce6SRafael J. Wysocki if (!valid_IRQ(gsi)) { 294046d9ce6SRafael J. Wysocki acpi_dev_irqresource_disabled(res, gsi); 295046d9ce6SRafael J. Wysocki return; 296046d9ce6SRafael J. Wysocki } 297046d9ce6SRafael J. Wysocki 298046d9ce6SRafael J. Wysocki /* 299046d9ce6SRafael J. Wysocki * In IO-APIC mode, use overrided attribute. Two reasons: 300046d9ce6SRafael J. Wysocki * 1. BIOS bug in DSDT 301046d9ce6SRafael J. Wysocki * 2. BIOS uses IO-APIC mode Interrupt Source Override 302204ebc0aSMika Westerberg * 303204ebc0aSMika Westerberg * We do this only if we are dealing with IRQ() or IRQNoFlags() 304204ebc0aSMika Westerberg * resource (the legacy ISA resources). With modern ACPI 5 devices 305204ebc0aSMika Westerberg * using extended IRQ descriptors we take the IRQ configuration 306204ebc0aSMika Westerberg * from _CRS directly. 307046d9ce6SRafael J. Wysocki */ 308204ebc0aSMika Westerberg if (legacy && !acpi_get_override_irq(gsi, &t, &p)) { 309046d9ce6SRafael J. Wysocki u8 trig = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE; 310046d9ce6SRafael J. Wysocki u8 pol = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; 311046d9ce6SRafael J. Wysocki 312046d9ce6SRafael J. Wysocki if (triggering != trig || polarity != pol) { 313046d9ce6SRafael J. Wysocki pr_warning("ACPI: IRQ %d override to %s, %s\n", gsi, 314204ebc0aSMika Westerberg t ? "level" : "edge", p ? "low" : "high"); 315046d9ce6SRafael J. Wysocki triggering = trig; 316046d9ce6SRafael J. Wysocki polarity = pol; 317046d9ce6SRafael J. Wysocki } 318046d9ce6SRafael J. Wysocki } 319046d9ce6SRafael J. Wysocki 320046d9ce6SRafael J. Wysocki res->flags = acpi_dev_irq_flags(triggering, polarity, shareable); 321046d9ce6SRafael J. Wysocki irq = acpi_register_gsi(NULL, gsi, triggering, polarity); 322046d9ce6SRafael J. Wysocki if (irq >= 0) { 323046d9ce6SRafael J. Wysocki res->start = irq; 324046d9ce6SRafael J. Wysocki res->end = irq; 325046d9ce6SRafael J. Wysocki } else { 326046d9ce6SRafael J. Wysocki acpi_dev_irqresource_disabled(res, gsi); 327046d9ce6SRafael J. Wysocki } 328046d9ce6SRafael J. Wysocki } 329046d9ce6SRafael J. Wysocki 330046d9ce6SRafael J. Wysocki /** 331046d9ce6SRafael J. Wysocki * acpi_dev_resource_interrupt - Extract ACPI interrupt resource information. 332046d9ce6SRafael J. Wysocki * @ares: Input ACPI resource object. 333046d9ce6SRafael J. Wysocki * @index: Index into the array of GSIs represented by the resource. 334046d9ce6SRafael J. Wysocki * @res: Output generic resource object. 335046d9ce6SRafael J. Wysocki * 336046d9ce6SRafael J. Wysocki * Check if the given ACPI resource object represents an interrupt resource 337046d9ce6SRafael J. Wysocki * and @index does not exceed the resource's interrupt count (true is returned 338046d9ce6SRafael J. Wysocki * in that case regardless of the results of the other checks)). If that's the 339046d9ce6SRafael J. Wysocki * case, register the GSI corresponding to @index from the array of interrupts 340046d9ce6SRafael J. Wysocki * represented by the resource and populate the generic resource object pointed 341046d9ce6SRafael J. Wysocki * to by @res accordingly. If the registration of the GSI is not successful, 342046d9ce6SRafael J. Wysocki * IORESOURCE_DISABLED will be set it that object's flags. 343046d9ce6SRafael J. Wysocki */ 344046d9ce6SRafael J. Wysocki bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, 345046d9ce6SRafael J. Wysocki struct resource *res) 346046d9ce6SRafael J. Wysocki { 347046d9ce6SRafael J. Wysocki struct acpi_resource_irq *irq; 348046d9ce6SRafael J. Wysocki struct acpi_resource_extended_irq *ext_irq; 349046d9ce6SRafael J. Wysocki 350046d9ce6SRafael J. Wysocki switch (ares->type) { 351046d9ce6SRafael J. Wysocki case ACPI_RESOURCE_TYPE_IRQ: 352046d9ce6SRafael J. Wysocki /* 353046d9ce6SRafael J. Wysocki * Per spec, only one interrupt per descriptor is allowed in 354046d9ce6SRafael J. Wysocki * _CRS, but some firmware violates this, so parse them all. 355046d9ce6SRafael J. Wysocki */ 356046d9ce6SRafael J. Wysocki irq = &ares->data.irq; 357046d9ce6SRafael J. Wysocki if (index >= irq->interrupt_count) { 358046d9ce6SRafael J. Wysocki acpi_dev_irqresource_disabled(res, 0); 359046d9ce6SRafael J. Wysocki return false; 360046d9ce6SRafael J. Wysocki } 361046d9ce6SRafael J. Wysocki acpi_dev_get_irqresource(res, irq->interrupts[index], 362046d9ce6SRafael J. Wysocki irq->triggering, irq->polarity, 363204ebc0aSMika Westerberg irq->sharable, true); 364046d9ce6SRafael J. Wysocki break; 365046d9ce6SRafael J. Wysocki case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 366046d9ce6SRafael J. Wysocki ext_irq = &ares->data.extended_irq; 367046d9ce6SRafael J. Wysocki if (index >= ext_irq->interrupt_count) { 368046d9ce6SRafael J. Wysocki acpi_dev_irqresource_disabled(res, 0); 369046d9ce6SRafael J. Wysocki return false; 370046d9ce6SRafael J. Wysocki } 371046d9ce6SRafael J. Wysocki acpi_dev_get_irqresource(res, ext_irq->interrupts[index], 372046d9ce6SRafael J. Wysocki ext_irq->triggering, ext_irq->polarity, 373204ebc0aSMika Westerberg ext_irq->sharable, false); 374046d9ce6SRafael J. Wysocki break; 375046d9ce6SRafael J. Wysocki default: 376046d9ce6SRafael J. Wysocki return false; 377046d9ce6SRafael J. Wysocki } 378046d9ce6SRafael J. Wysocki 379046d9ce6SRafael J. Wysocki return true; 380046d9ce6SRafael J. Wysocki } 381046d9ce6SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt); 3828e345c99SRafael J. Wysocki 3838e345c99SRafael J. Wysocki /** 3848e345c99SRafael J. Wysocki * acpi_dev_free_resource_list - Free resource from %acpi_dev_get_resources(). 3858e345c99SRafael J. Wysocki * @list: The head of the resource list to free. 3868e345c99SRafael J. Wysocki */ 3878e345c99SRafael J. Wysocki void acpi_dev_free_resource_list(struct list_head *list) 3888e345c99SRafael J. Wysocki { 3898e345c99SRafael J. Wysocki struct resource_list_entry *rentry, *re; 3908e345c99SRafael J. Wysocki 3918e345c99SRafael J. Wysocki list_for_each_entry_safe(rentry, re, list, node) { 3928e345c99SRafael J. Wysocki list_del(&rentry->node); 3938e345c99SRafael J. Wysocki kfree(rentry); 3948e345c99SRafael J. Wysocki } 3958e345c99SRafael J. Wysocki } 3968e345c99SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list); 3978e345c99SRafael J. Wysocki 3988e345c99SRafael J. Wysocki struct res_proc_context { 3998e345c99SRafael J. Wysocki struct list_head *list; 4008e345c99SRafael J. Wysocki int (*preproc)(struct acpi_resource *, void *); 4018e345c99SRafael J. Wysocki void *preproc_data; 4028e345c99SRafael J. Wysocki int count; 4038e345c99SRafael J. Wysocki int error; 4048e345c99SRafael J. Wysocki }; 4058e345c99SRafael J. Wysocki 4068e345c99SRafael J. Wysocki static acpi_status acpi_dev_new_resource_entry(struct resource *r, 4078e345c99SRafael J. Wysocki struct res_proc_context *c) 4088e345c99SRafael J. Wysocki { 4098e345c99SRafael J. Wysocki struct resource_list_entry *rentry; 4108e345c99SRafael J. Wysocki 4118e345c99SRafael J. Wysocki rentry = kmalloc(sizeof(*rentry), GFP_KERNEL); 4128e345c99SRafael J. Wysocki if (!rentry) { 4138e345c99SRafael J. Wysocki c->error = -ENOMEM; 4148e345c99SRafael J. Wysocki return AE_NO_MEMORY; 4158e345c99SRafael J. Wysocki } 4168e345c99SRafael J. Wysocki rentry->res = *r; 4178e345c99SRafael J. Wysocki list_add_tail(&rentry->node, c->list); 4188e345c99SRafael J. Wysocki c->count++; 4198e345c99SRafael J. Wysocki return AE_OK; 4208e345c99SRafael J. Wysocki } 4218e345c99SRafael J. Wysocki 4228e345c99SRafael J. Wysocki static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, 4238e345c99SRafael J. Wysocki void *context) 4248e345c99SRafael J. Wysocki { 4258e345c99SRafael J. Wysocki struct res_proc_context *c = context; 4268e345c99SRafael J. Wysocki struct resource r; 4278e345c99SRafael J. Wysocki int i; 4288e345c99SRafael J. Wysocki 4298e345c99SRafael J. Wysocki if (c->preproc) { 4308e345c99SRafael J. Wysocki int ret; 4318e345c99SRafael J. Wysocki 4328e345c99SRafael J. Wysocki ret = c->preproc(ares, c->preproc_data); 4338e345c99SRafael J. Wysocki if (ret < 0) { 4348e345c99SRafael J. Wysocki c->error = ret; 4358a66790bSRafael J. Wysocki return AE_CTRL_TERMINATE; 4368e345c99SRafael J. Wysocki } else if (ret > 0) { 4378e345c99SRafael J. Wysocki return AE_OK; 4388e345c99SRafael J. Wysocki } 4398e345c99SRafael J. Wysocki } 4408e345c99SRafael J. Wysocki 4418e345c99SRafael J. Wysocki memset(&r, 0, sizeof(r)); 4428e345c99SRafael J. Wysocki 4438e345c99SRafael J. Wysocki if (acpi_dev_resource_memory(ares, &r) 4448e345c99SRafael J. Wysocki || acpi_dev_resource_io(ares, &r) 4458e345c99SRafael J. Wysocki || acpi_dev_resource_address_space(ares, &r) 4468e345c99SRafael J. Wysocki || acpi_dev_resource_ext_address_space(ares, &r)) 4478e345c99SRafael J. Wysocki return acpi_dev_new_resource_entry(&r, c); 4488e345c99SRafael J. Wysocki 4498e345c99SRafael J. Wysocki for (i = 0; acpi_dev_resource_interrupt(ares, i, &r); i++) { 4508e345c99SRafael J. Wysocki acpi_status status; 4518e345c99SRafael J. Wysocki 4528e345c99SRafael J. Wysocki status = acpi_dev_new_resource_entry(&r, c); 4538e345c99SRafael J. Wysocki if (ACPI_FAILURE(status)) 4548e345c99SRafael J. Wysocki return status; 4558e345c99SRafael J. Wysocki } 4568e345c99SRafael J. Wysocki 4578e345c99SRafael J. Wysocki return AE_OK; 4588e345c99SRafael J. Wysocki } 4598e345c99SRafael J. Wysocki 4608e345c99SRafael J. Wysocki /** 4618e345c99SRafael J. Wysocki * acpi_dev_get_resources - Get current resources of a device. 4628e345c99SRafael J. Wysocki * @adev: ACPI device node to get the resources for. 4638e345c99SRafael J. Wysocki * @list: Head of the resultant list of resources (must be empty). 4648e345c99SRafael J. Wysocki * @preproc: The caller's preprocessing routine. 4658e345c99SRafael J. Wysocki * @preproc_data: Pointer passed to the caller's preprocessing routine. 4668e345c99SRafael J. Wysocki * 4678e345c99SRafael J. Wysocki * Evaluate the _CRS method for the given device node and process its output by 4688e345c99SRafael J. Wysocki * (1) executing the @preproc() rountine provided by the caller, passing the 4698e345c99SRafael J. Wysocki * resource pointer and @preproc_data to it as arguments, for each ACPI resource 4708e345c99SRafael J. Wysocki * returned and (2) converting all of the returned ACPI resources into struct 4718e345c99SRafael J. Wysocki * resource objects if possible. If the return value of @preproc() in step (1) 4728e345c99SRafael J. Wysocki * is different from 0, step (2) is not applied to the given ACPI resource and 4738e345c99SRafael J. Wysocki * if that value is negative, the whole processing is aborted and that value is 4748e345c99SRafael J. Wysocki * returned as the final error code. 4758e345c99SRafael J. Wysocki * 4768e345c99SRafael J. Wysocki * The resultant struct resource objects are put on the list pointed to by 4778e345c99SRafael J. Wysocki * @list, that must be empty initially, as members of struct resource_list_entry 4788e345c99SRafael J. Wysocki * objects. Callers of this routine should use %acpi_dev_free_resource_list() to 4798e345c99SRafael J. Wysocki * free that list. 4808e345c99SRafael J. Wysocki * 4818e345c99SRafael J. Wysocki * The number of resources in the output list is returned on success, an error 4828e345c99SRafael J. Wysocki * code reflecting the error condition is returned otherwise. 4838e345c99SRafael J. Wysocki */ 4848e345c99SRafael J. Wysocki int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, 4858e345c99SRafael J. Wysocki int (*preproc)(struct acpi_resource *, void *), 4868e345c99SRafael J. Wysocki void *preproc_data) 4878e345c99SRafael J. Wysocki { 4888e345c99SRafael J. Wysocki struct res_proc_context c; 4898e345c99SRafael J. Wysocki acpi_status status; 4908e345c99SRafael J. Wysocki 4918e345c99SRafael J. Wysocki if (!adev || !adev->handle || !list_empty(list)) 4928e345c99SRafael J. Wysocki return -EINVAL; 4938e345c99SRafael J. Wysocki 494952c63e9SJiang Liu if (!acpi_has_method(adev->handle, METHOD_NAME__CRS)) 4958e345c99SRafael J. Wysocki return 0; 4968e345c99SRafael J. Wysocki 4978e345c99SRafael J. Wysocki c.list = list; 4988e345c99SRafael J. Wysocki c.preproc = preproc; 4998e345c99SRafael J. Wysocki c.preproc_data = preproc_data; 5008e345c99SRafael J. Wysocki c.count = 0; 5018e345c99SRafael J. Wysocki c.error = 0; 5028e345c99SRafael J. Wysocki status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS, 5038e345c99SRafael J. Wysocki acpi_dev_process_resource, &c); 5048e345c99SRafael J. Wysocki if (ACPI_FAILURE(status)) { 5058e345c99SRafael J. Wysocki acpi_dev_free_resource_list(list); 5068e345c99SRafael J. Wysocki return c.error ? c.error : -EIO; 5078e345c99SRafael J. Wysocki } 5088e345c99SRafael J. Wysocki 5098e345c99SRafael J. Wysocki return c.count; 5108e345c99SRafael J. Wysocki } 5118e345c99SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_dev_get_resources); 512