18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * pnpacpi -- PnP ACPI driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr> 68c2ecf20Sopenharmony_ci * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com> 78c2ecf20Sopenharmony_ci * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. 88c2ecf20Sopenharmony_ci * Bjorn Helgaas <bjorn.helgaas@hp.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/acpi.h> 128c2ecf20Sopenharmony_ci#include <linux/pci.h> 138c2ecf20Sopenharmony_ci#include <linux/pnp.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include "../base.h" 168c2ecf20Sopenharmony_ci#include "pnpacpi.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic void decode_irq_flags(struct pnp_dev *dev, int flags, u8 *triggering, 198c2ecf20Sopenharmony_ci u8 *polarity, u8 *shareable) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci switch (flags & (IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_HIGHLEVEL | 228c2ecf20Sopenharmony_ci IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE)) { 238c2ecf20Sopenharmony_ci case IORESOURCE_IRQ_LOWLEVEL: 248c2ecf20Sopenharmony_ci *triggering = ACPI_LEVEL_SENSITIVE; 258c2ecf20Sopenharmony_ci *polarity = ACPI_ACTIVE_LOW; 268c2ecf20Sopenharmony_ci break; 278c2ecf20Sopenharmony_ci case IORESOURCE_IRQ_HIGHLEVEL: 288c2ecf20Sopenharmony_ci *triggering = ACPI_LEVEL_SENSITIVE; 298c2ecf20Sopenharmony_ci *polarity = ACPI_ACTIVE_HIGH; 308c2ecf20Sopenharmony_ci break; 318c2ecf20Sopenharmony_ci case IORESOURCE_IRQ_LOWEDGE: 328c2ecf20Sopenharmony_ci *triggering = ACPI_EDGE_SENSITIVE; 338c2ecf20Sopenharmony_ci *polarity = ACPI_ACTIVE_LOW; 348c2ecf20Sopenharmony_ci break; 358c2ecf20Sopenharmony_ci case IORESOURCE_IRQ_HIGHEDGE: 368c2ecf20Sopenharmony_ci *triggering = ACPI_EDGE_SENSITIVE; 378c2ecf20Sopenharmony_ci *polarity = ACPI_ACTIVE_HIGH; 388c2ecf20Sopenharmony_ci break; 398c2ecf20Sopenharmony_ci default: 408c2ecf20Sopenharmony_ci dev_err(&dev->dev, "can't encode invalid IRQ mode %#x\n", 418c2ecf20Sopenharmony_ci flags); 428c2ecf20Sopenharmony_ci *triggering = ACPI_EDGE_SENSITIVE; 438c2ecf20Sopenharmony_ci *polarity = ACPI_ACTIVE_HIGH; 448c2ecf20Sopenharmony_ci break; 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (flags & IORESOURCE_IRQ_SHAREABLE) 488c2ecf20Sopenharmony_ci *shareable = ACPI_SHARED; 498c2ecf20Sopenharmony_ci else 508c2ecf20Sopenharmony_ci *shareable = ACPI_EXCLUSIVE; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int dma_flags(struct pnp_dev *dev, int type, int bus_master, 548c2ecf20Sopenharmony_ci int transfer) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci int flags = 0; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (bus_master) 598c2ecf20Sopenharmony_ci flags |= IORESOURCE_DMA_MASTER; 608c2ecf20Sopenharmony_ci switch (type) { 618c2ecf20Sopenharmony_ci case ACPI_COMPATIBILITY: 628c2ecf20Sopenharmony_ci flags |= IORESOURCE_DMA_COMPATIBLE; 638c2ecf20Sopenharmony_ci break; 648c2ecf20Sopenharmony_ci case ACPI_TYPE_A: 658c2ecf20Sopenharmony_ci flags |= IORESOURCE_DMA_TYPEA; 668c2ecf20Sopenharmony_ci break; 678c2ecf20Sopenharmony_ci case ACPI_TYPE_B: 688c2ecf20Sopenharmony_ci flags |= IORESOURCE_DMA_TYPEB; 698c2ecf20Sopenharmony_ci break; 708c2ecf20Sopenharmony_ci case ACPI_TYPE_F: 718c2ecf20Sopenharmony_ci flags |= IORESOURCE_DMA_TYPEF; 728c2ecf20Sopenharmony_ci break; 738c2ecf20Sopenharmony_ci default: 748c2ecf20Sopenharmony_ci /* Set a default value ? */ 758c2ecf20Sopenharmony_ci flags |= IORESOURCE_DMA_COMPATIBLE; 768c2ecf20Sopenharmony_ci dev_err(&dev->dev, "invalid DMA type %d\n", type); 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci switch (transfer) { 798c2ecf20Sopenharmony_ci case ACPI_TRANSFER_8: 808c2ecf20Sopenharmony_ci flags |= IORESOURCE_DMA_8BIT; 818c2ecf20Sopenharmony_ci break; 828c2ecf20Sopenharmony_ci case ACPI_TRANSFER_8_16: 838c2ecf20Sopenharmony_ci flags |= IORESOURCE_DMA_8AND16BIT; 848c2ecf20Sopenharmony_ci break; 858c2ecf20Sopenharmony_ci case ACPI_TRANSFER_16: 868c2ecf20Sopenharmony_ci flags |= IORESOURCE_DMA_16BIT; 878c2ecf20Sopenharmony_ci break; 888c2ecf20Sopenharmony_ci default: 898c2ecf20Sopenharmony_ci /* Set a default value ? */ 908c2ecf20Sopenharmony_ci flags |= IORESOURCE_DMA_8AND16BIT; 918c2ecf20Sopenharmony_ci dev_err(&dev->dev, "invalid DMA transfer type %d\n", transfer); 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci return flags; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/* 988c2ecf20Sopenharmony_ci * Allocated Resources 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic void pnpacpi_add_irqresource(struct pnp_dev *dev, struct resource *r) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci if (!(r->flags & IORESOURCE_DISABLED)) 1048c2ecf20Sopenharmony_ci pcibios_penalize_isa_irq(r->start, 1); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci pnp_add_resource(dev, r); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* 1108c2ecf20Sopenharmony_ci * Device CSRs that do not appear in PCI config space should be described 1118c2ecf20Sopenharmony_ci * via ACPI. This would normally be done with Address Space Descriptors 1128c2ecf20Sopenharmony_ci * marked as "consumer-only," but old versions of Windows and Linux ignore 1138c2ecf20Sopenharmony_ci * the producer/consumer flag, so HP invented a vendor-defined resource to 1148c2ecf20Sopenharmony_ci * describe the location and size of CSR space. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_cistatic struct acpi_vendor_uuid hp_ccsr_uuid = { 1178c2ecf20Sopenharmony_ci .subtype = 2, 1188c2ecf20Sopenharmony_ci .data = { 0xf9, 0xad, 0xe9, 0x69, 0x4f, 0x92, 0x5f, 0xab, 0xf6, 0x4a, 1198c2ecf20Sopenharmony_ci 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad }, 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic int vendor_resource_matches(struct pnp_dev *dev, 1238c2ecf20Sopenharmony_ci struct acpi_resource_vendor_typed *vendor, 1248c2ecf20Sopenharmony_ci struct acpi_vendor_uuid *match, 1258c2ecf20Sopenharmony_ci int expected_len) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci int uuid_len = sizeof(vendor->uuid); 1288c2ecf20Sopenharmony_ci u8 uuid_subtype = vendor->uuid_subtype; 1298c2ecf20Sopenharmony_ci u8 *uuid = vendor->uuid; 1308c2ecf20Sopenharmony_ci int actual_len; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* byte_length includes uuid_subtype and uuid */ 1338c2ecf20Sopenharmony_ci actual_len = vendor->byte_length - uuid_len - 1; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (uuid_subtype == match->subtype && 1368c2ecf20Sopenharmony_ci uuid_len == sizeof(match->data) && 1378c2ecf20Sopenharmony_ci memcmp(uuid, match->data, uuid_len) == 0) { 1388c2ecf20Sopenharmony_ci if (expected_len && expected_len != actual_len) { 1398c2ecf20Sopenharmony_ci dev_err(&dev->dev, 1408c2ecf20Sopenharmony_ci "wrong vendor descriptor size; expected %d, found %d bytes\n", 1418c2ecf20Sopenharmony_ci expected_len, actual_len); 1428c2ecf20Sopenharmony_ci return 0; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return 1; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return 0; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev, 1528c2ecf20Sopenharmony_ci struct acpi_resource_vendor_typed *vendor) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci struct { u64 start, length; } range; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (vendor_resource_matches(dev, vendor, &hp_ccsr_uuid, 1578c2ecf20Sopenharmony_ci sizeof(range))) { 1588c2ecf20Sopenharmony_ci memcpy(&range, vendor->byte_data, sizeof(range)); 1598c2ecf20Sopenharmony_ci pnp_add_mem_resource(dev, range.start, range.start + 1608c2ecf20Sopenharmony_ci range.length - 1, 0); 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, 1658c2ecf20Sopenharmony_ci void *data) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct pnp_dev *dev = data; 1688c2ecf20Sopenharmony_ci struct acpi_resource_dma *dma; 1698c2ecf20Sopenharmony_ci struct acpi_resource_vendor_typed *vendor_typed; 1708c2ecf20Sopenharmony_ci struct acpi_resource_gpio *gpio; 1718c2ecf20Sopenharmony_ci struct resource_win win = {{0}, 0}; 1728c2ecf20Sopenharmony_ci struct resource *r = &win.res; 1738c2ecf20Sopenharmony_ci int i, flags; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (acpi_dev_resource_address_space(res, &win) 1768c2ecf20Sopenharmony_ci || acpi_dev_resource_ext_address_space(res, &win)) { 1778c2ecf20Sopenharmony_ci pnp_add_resource(dev, &win.res); 1788c2ecf20Sopenharmony_ci return AE_OK; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci r->flags = 0; 1828c2ecf20Sopenharmony_ci if (acpi_dev_resource_interrupt(res, 0, r)) { 1838c2ecf20Sopenharmony_ci pnpacpi_add_irqresource(dev, r); 1848c2ecf20Sopenharmony_ci for (i = 1; acpi_dev_resource_interrupt(res, i, r); i++) 1858c2ecf20Sopenharmony_ci pnpacpi_add_irqresource(dev, r); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (i > 1) { 1888c2ecf20Sopenharmony_ci /* 1898c2ecf20Sopenharmony_ci * The IRQ encoder puts a single interrupt in each 1908c2ecf20Sopenharmony_ci * descriptor, so if a _CRS descriptor has more than 1918c2ecf20Sopenharmony_ci * one interrupt, we won't be able to re-encode it. 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_ci if (pnp_can_write(dev)) { 1948c2ecf20Sopenharmony_ci dev_warn(&dev->dev, 1958c2ecf20Sopenharmony_ci "multiple interrupts in _CRS descriptor; configuration can't be changed\n"); 1968c2ecf20Sopenharmony_ci dev->capabilities &= ~PNP_WRITE; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci return AE_OK; 2008c2ecf20Sopenharmony_ci } else if (acpi_gpio_get_irq_resource(res, &gpio)) { 2018c2ecf20Sopenharmony_ci /* 2028c2ecf20Sopenharmony_ci * If the resource is GpioInt() type then extract the IRQ 2038c2ecf20Sopenharmony_ci * from GPIO resource and fill it into IRQ resource type. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_ci i = acpi_dev_gpio_irq_get(dev->data, 0); 2068c2ecf20Sopenharmony_ci if (i >= 0) { 2078c2ecf20Sopenharmony_ci flags = acpi_dev_irq_flags(gpio->triggering, 2088c2ecf20Sopenharmony_ci gpio->polarity, 2098c2ecf20Sopenharmony_ci gpio->shareable); 2108c2ecf20Sopenharmony_ci } else { 2118c2ecf20Sopenharmony_ci flags = IORESOURCE_DISABLED; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci pnp_add_irq_resource(dev, i, flags); 2148c2ecf20Sopenharmony_ci return AE_OK; 2158c2ecf20Sopenharmony_ci } else if (r->flags & IORESOURCE_DISABLED) { 2168c2ecf20Sopenharmony_ci pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); 2178c2ecf20Sopenharmony_ci return AE_OK; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci switch (res->type) { 2218c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY24: 2228c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY32: 2238c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 2248c2ecf20Sopenharmony_ci if (acpi_dev_resource_memory(res, r)) 2258c2ecf20Sopenharmony_ci pnp_add_resource(dev, r); 2268c2ecf20Sopenharmony_ci break; 2278c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_IO: 2288c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_IO: 2298c2ecf20Sopenharmony_ci if (acpi_dev_resource_io(res, r)) 2308c2ecf20Sopenharmony_ci pnp_add_resource(dev, r); 2318c2ecf20Sopenharmony_ci break; 2328c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_DMA: 2338c2ecf20Sopenharmony_ci dma = &res->data.dma; 2348c2ecf20Sopenharmony_ci if (dma->channel_count > 0 && dma->channels[0] != (u8) -1) 2358c2ecf20Sopenharmony_ci flags = dma_flags(dev, dma->type, dma->bus_master, 2368c2ecf20Sopenharmony_ci dma->transfer); 2378c2ecf20Sopenharmony_ci else 2388c2ecf20Sopenharmony_ci flags = IORESOURCE_DISABLED; 2398c2ecf20Sopenharmony_ci pnp_add_dma_resource(dev, dma->channels[0], flags); 2408c2ecf20Sopenharmony_ci break; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_START_DEPENDENT: 2438c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_END_DEPENDENT: 2448c2ecf20Sopenharmony_ci break; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_VENDOR: 2478c2ecf20Sopenharmony_ci vendor_typed = &res->data.vendor_typed; 2488c2ecf20Sopenharmony_ci pnpacpi_parse_allocated_vendor(dev, vendor_typed); 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_END_TAG: 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_SERIAL_BUS: 2588c2ecf20Sopenharmony_ci /* serial bus connections (I2C/SPI/UART) are not pnp */ 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci default: 2628c2ecf20Sopenharmony_ci dev_warn(&dev->dev, "unknown resource type %d in _CRS\n", 2638c2ecf20Sopenharmony_ci res->type); 2648c2ecf20Sopenharmony_ci return AE_ERROR; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return AE_OK; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ciint pnpacpi_parse_allocated_resource(struct pnp_dev *dev) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci struct acpi_device *acpi_dev = dev->data; 2738c2ecf20Sopenharmony_ci acpi_handle handle = acpi_dev->handle; 2748c2ecf20Sopenharmony_ci acpi_status status; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, "parse allocated resources\n"); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci pnp_init_resources(dev); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci status = acpi_walk_resources(handle, METHOD_NAME__CRS, 2818c2ecf20Sopenharmony_ci pnpacpi_allocated_resource, dev); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 2848c2ecf20Sopenharmony_ci if (status != AE_NOT_FOUND) 2858c2ecf20Sopenharmony_ci dev_err(&dev->dev, "can't evaluate _CRS: %d", status); 2868c2ecf20Sopenharmony_ci return -EPERM; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci return 0; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic __init void pnpacpi_parse_dma_option(struct pnp_dev *dev, 2928c2ecf20Sopenharmony_ci unsigned int option_flags, 2938c2ecf20Sopenharmony_ci struct acpi_resource_dma *p) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci int i; 2968c2ecf20Sopenharmony_ci unsigned char map = 0, flags; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci for (i = 0; i < p->channel_count; i++) 2998c2ecf20Sopenharmony_ci map |= 1 << p->channels[i]; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci flags = dma_flags(dev, p->type, p->bus_master, p->transfer); 3028c2ecf20Sopenharmony_ci pnp_register_dma_resource(dev, option_flags, map, flags); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, 3068c2ecf20Sopenharmony_ci unsigned int option_flags, 3078c2ecf20Sopenharmony_ci struct acpi_resource_irq *p) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci int i; 3108c2ecf20Sopenharmony_ci pnp_irq_mask_t map; 3118c2ecf20Sopenharmony_ci unsigned char flags; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci bitmap_zero(map.bits, PNP_IRQ_NR); 3148c2ecf20Sopenharmony_ci for (i = 0; i < p->interrupt_count; i++) 3158c2ecf20Sopenharmony_ci if (p->interrupts[i]) 3168c2ecf20Sopenharmony_ci __set_bit(p->interrupts[i], map.bits); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->shareable); 3198c2ecf20Sopenharmony_ci pnp_register_irq_resource(dev, option_flags, &map, flags); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, 3238c2ecf20Sopenharmony_ci unsigned int option_flags, 3248c2ecf20Sopenharmony_ci struct acpi_resource_extended_irq *p) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci int i; 3278c2ecf20Sopenharmony_ci pnp_irq_mask_t map; 3288c2ecf20Sopenharmony_ci unsigned char flags; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci bitmap_zero(map.bits, PNP_IRQ_NR); 3318c2ecf20Sopenharmony_ci for (i = 0; i < p->interrupt_count; i++) { 3328c2ecf20Sopenharmony_ci if (p->interrupts[i]) { 3338c2ecf20Sopenharmony_ci if (p->interrupts[i] < PNP_IRQ_NR) 3348c2ecf20Sopenharmony_ci __set_bit(p->interrupts[i], map.bits); 3358c2ecf20Sopenharmony_ci else 3368c2ecf20Sopenharmony_ci dev_err(&dev->dev, 3378c2ecf20Sopenharmony_ci "ignoring IRQ %d option (too large for %d entry bitmap)\n", 3388c2ecf20Sopenharmony_ci p->interrupts[i], PNP_IRQ_NR); 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->shareable); 3438c2ecf20Sopenharmony_ci pnp_register_irq_resource(dev, option_flags, &map, flags); 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic __init void pnpacpi_parse_port_option(struct pnp_dev *dev, 3478c2ecf20Sopenharmony_ci unsigned int option_flags, 3488c2ecf20Sopenharmony_ci struct acpi_resource_io *io) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci unsigned char flags = 0; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (io->io_decode == ACPI_DECODE_16) 3538c2ecf20Sopenharmony_ci flags = IORESOURCE_IO_16BIT_ADDR; 3548c2ecf20Sopenharmony_ci pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum, 3558c2ecf20Sopenharmony_ci io->alignment, io->address_length, flags); 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev, 3598c2ecf20Sopenharmony_ci unsigned int option_flags, 3608c2ecf20Sopenharmony_ci struct acpi_resource_fixed_io *io) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci pnp_register_port_resource(dev, option_flags, io->address, io->address, 3638c2ecf20Sopenharmony_ci 0, io->address_length, IORESOURCE_IO_FIXED); 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, 3678c2ecf20Sopenharmony_ci unsigned int option_flags, 3688c2ecf20Sopenharmony_ci struct acpi_resource_memory24 *p) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci unsigned char flags = 0; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (p->write_protect == ACPI_READ_WRITE_MEMORY) 3738c2ecf20Sopenharmony_ci flags = IORESOURCE_MEM_WRITEABLE; 3748c2ecf20Sopenharmony_ci pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, 3758c2ecf20Sopenharmony_ci p->alignment, p->address_length, flags); 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev, 3798c2ecf20Sopenharmony_ci unsigned int option_flags, 3808c2ecf20Sopenharmony_ci struct acpi_resource_memory32 *p) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci unsigned char flags = 0; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (p->write_protect == ACPI_READ_WRITE_MEMORY) 3858c2ecf20Sopenharmony_ci flags = IORESOURCE_MEM_WRITEABLE; 3868c2ecf20Sopenharmony_ci pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, 3878c2ecf20Sopenharmony_ci p->alignment, p->address_length, flags); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev, 3918c2ecf20Sopenharmony_ci unsigned int option_flags, 3928c2ecf20Sopenharmony_ci struct acpi_resource_fixed_memory32 *p) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci unsigned char flags = 0; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (p->write_protect == ACPI_READ_WRITE_MEMORY) 3978c2ecf20Sopenharmony_ci flags = IORESOURCE_MEM_WRITEABLE; 3988c2ecf20Sopenharmony_ci pnp_register_mem_resource(dev, option_flags, p->address, p->address, 3998c2ecf20Sopenharmony_ci 0, p->address_length, flags); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic __init void pnpacpi_parse_address_option(struct pnp_dev *dev, 4038c2ecf20Sopenharmony_ci unsigned int option_flags, 4048c2ecf20Sopenharmony_ci struct acpi_resource *r) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci struct acpi_resource_address64 addr, *p = &addr; 4078c2ecf20Sopenharmony_ci acpi_status status; 4088c2ecf20Sopenharmony_ci unsigned char flags = 0; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci status = acpi_resource_to_address64(r, p); 4118c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 4128c2ecf20Sopenharmony_ci dev_warn(&dev->dev, "can't convert resource type %d\n", 4138c2ecf20Sopenharmony_ci r->type); 4148c2ecf20Sopenharmony_ci return; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (p->resource_type == ACPI_MEMORY_RANGE) { 4188c2ecf20Sopenharmony_ci if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) 4198c2ecf20Sopenharmony_ci flags = IORESOURCE_MEM_WRITEABLE; 4208c2ecf20Sopenharmony_ci pnp_register_mem_resource(dev, option_flags, p->address.minimum, 4218c2ecf20Sopenharmony_ci p->address.minimum, 0, p->address.address_length, 4228c2ecf20Sopenharmony_ci flags); 4238c2ecf20Sopenharmony_ci } else if (p->resource_type == ACPI_IO_RANGE) 4248c2ecf20Sopenharmony_ci pnp_register_port_resource(dev, option_flags, p->address.minimum, 4258c2ecf20Sopenharmony_ci p->address.minimum, 0, p->address.address_length, 4268c2ecf20Sopenharmony_ci IORESOURCE_IO_FIXED); 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev, 4308c2ecf20Sopenharmony_ci unsigned int option_flags, 4318c2ecf20Sopenharmony_ci struct acpi_resource *r) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct acpi_resource_extended_address64 *p = &r->data.ext_address64; 4348c2ecf20Sopenharmony_ci unsigned char flags = 0; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (p->resource_type == ACPI_MEMORY_RANGE) { 4378c2ecf20Sopenharmony_ci if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) 4388c2ecf20Sopenharmony_ci flags = IORESOURCE_MEM_WRITEABLE; 4398c2ecf20Sopenharmony_ci pnp_register_mem_resource(dev, option_flags, p->address.minimum, 4408c2ecf20Sopenharmony_ci p->address.minimum, 0, p->address.address_length, 4418c2ecf20Sopenharmony_ci flags); 4428c2ecf20Sopenharmony_ci } else if (p->resource_type == ACPI_IO_RANGE) 4438c2ecf20Sopenharmony_ci pnp_register_port_resource(dev, option_flags, p->address.minimum, 4448c2ecf20Sopenharmony_ci p->address.minimum, 0, p->address.address_length, 4458c2ecf20Sopenharmony_ci IORESOURCE_IO_FIXED); 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistruct acpipnp_parse_option_s { 4498c2ecf20Sopenharmony_ci struct pnp_dev *dev; 4508c2ecf20Sopenharmony_ci unsigned int option_flags; 4518c2ecf20Sopenharmony_ci}; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, 4548c2ecf20Sopenharmony_ci void *data) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci int priority; 4578c2ecf20Sopenharmony_ci struct acpipnp_parse_option_s *parse_data = data; 4588c2ecf20Sopenharmony_ci struct pnp_dev *dev = parse_data->dev; 4598c2ecf20Sopenharmony_ci unsigned int option_flags = parse_data->option_flags; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci switch (res->type) { 4628c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_IRQ: 4638c2ecf20Sopenharmony_ci pnpacpi_parse_irq_option(dev, option_flags, &res->data.irq); 4648c2ecf20Sopenharmony_ci break; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_DMA: 4678c2ecf20Sopenharmony_ci pnpacpi_parse_dma_option(dev, option_flags, &res->data.dma); 4688c2ecf20Sopenharmony_ci break; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_START_DEPENDENT: 4718c2ecf20Sopenharmony_ci switch (res->data.start_dpf.compatibility_priority) { 4728c2ecf20Sopenharmony_ci case ACPI_GOOD_CONFIGURATION: 4738c2ecf20Sopenharmony_ci priority = PNP_RES_PRIORITY_PREFERRED; 4748c2ecf20Sopenharmony_ci break; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci case ACPI_ACCEPTABLE_CONFIGURATION: 4778c2ecf20Sopenharmony_ci priority = PNP_RES_PRIORITY_ACCEPTABLE; 4788c2ecf20Sopenharmony_ci break; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci case ACPI_SUB_OPTIMAL_CONFIGURATION: 4818c2ecf20Sopenharmony_ci priority = PNP_RES_PRIORITY_FUNCTIONAL; 4828c2ecf20Sopenharmony_ci break; 4838c2ecf20Sopenharmony_ci default: 4848c2ecf20Sopenharmony_ci priority = PNP_RES_PRIORITY_INVALID; 4858c2ecf20Sopenharmony_ci break; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci parse_data->option_flags = pnp_new_dependent_set(dev, priority); 4888c2ecf20Sopenharmony_ci break; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_END_DEPENDENT: 4918c2ecf20Sopenharmony_ci parse_data->option_flags = 0; 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_IO: 4958c2ecf20Sopenharmony_ci pnpacpi_parse_port_option(dev, option_flags, &res->data.io); 4968c2ecf20Sopenharmony_ci break; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_IO: 4998c2ecf20Sopenharmony_ci pnpacpi_parse_fixed_port_option(dev, option_flags, 5008c2ecf20Sopenharmony_ci &res->data.fixed_io); 5018c2ecf20Sopenharmony_ci break; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_VENDOR: 5048c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_END_TAG: 5058c2ecf20Sopenharmony_ci break; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY24: 5088c2ecf20Sopenharmony_ci pnpacpi_parse_mem24_option(dev, option_flags, 5098c2ecf20Sopenharmony_ci &res->data.memory24); 5108c2ecf20Sopenharmony_ci break; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY32: 5138c2ecf20Sopenharmony_ci pnpacpi_parse_mem32_option(dev, option_flags, 5148c2ecf20Sopenharmony_ci &res->data.memory32); 5158c2ecf20Sopenharmony_ci break; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 5188c2ecf20Sopenharmony_ci pnpacpi_parse_fixed_mem32_option(dev, option_flags, 5198c2ecf20Sopenharmony_ci &res->data.fixed_memory32); 5208c2ecf20Sopenharmony_ci break; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS16: 5238c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS32: 5248c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS64: 5258c2ecf20Sopenharmony_ci pnpacpi_parse_address_option(dev, option_flags, res); 5268c2ecf20Sopenharmony_ci break; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: 5298c2ecf20Sopenharmony_ci pnpacpi_parse_ext_address_option(dev, option_flags, res); 5308c2ecf20Sopenharmony_ci break; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 5338c2ecf20Sopenharmony_ci pnpacpi_parse_ext_irq_option(dev, option_flags, 5348c2ecf20Sopenharmony_ci &res->data.extended_irq); 5358c2ecf20Sopenharmony_ci break; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: 5388c2ecf20Sopenharmony_ci break; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci default: 5418c2ecf20Sopenharmony_ci dev_warn(&dev->dev, "unknown resource type %d in _PRS\n", 5428c2ecf20Sopenharmony_ci res->type); 5438c2ecf20Sopenharmony_ci return AE_ERROR; 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci return AE_OK; 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ciint __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci struct acpi_device *acpi_dev = dev->data; 5528c2ecf20Sopenharmony_ci acpi_handle handle = acpi_dev->handle; 5538c2ecf20Sopenharmony_ci acpi_status status; 5548c2ecf20Sopenharmony_ci struct acpipnp_parse_option_s parse_data; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, "parse resource options\n"); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci parse_data.dev = dev; 5598c2ecf20Sopenharmony_ci parse_data.option_flags = 0; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci status = acpi_walk_resources(handle, METHOD_NAME__PRS, 5628c2ecf20Sopenharmony_ci pnpacpi_option_resource, &parse_data); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 5658c2ecf20Sopenharmony_ci if (status != AE_NOT_FOUND) 5668c2ecf20Sopenharmony_ci dev_err(&dev->dev, "can't evaluate _PRS: %d", status); 5678c2ecf20Sopenharmony_ci return -EPERM; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci return 0; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic int pnpacpi_supported_resource(struct acpi_resource *res) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci switch (res->type) { 5758c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_IRQ: 5768c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_DMA: 5778c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_IO: 5788c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_IO: 5798c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY24: 5808c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY32: 5818c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 5828c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS16: 5838c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS32: 5848c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS64: 5858c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: 5868c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 5878c2ecf20Sopenharmony_ci return 1; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci return 0; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci/* 5938c2ecf20Sopenharmony_ci * Set resource 5948c2ecf20Sopenharmony_ci */ 5958c2ecf20Sopenharmony_cistatic acpi_status pnpacpi_count_resources(struct acpi_resource *res, 5968c2ecf20Sopenharmony_ci void *data) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci int *res_cnt = data; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (pnpacpi_supported_resource(res)) 6018c2ecf20Sopenharmony_ci (*res_cnt)++; 6028c2ecf20Sopenharmony_ci return AE_OK; 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct acpi_resource **resource = data; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (pnpacpi_supported_resource(res)) { 6108c2ecf20Sopenharmony_ci (*resource)->type = res->type; 6118c2ecf20Sopenharmony_ci (*resource)->length = sizeof(struct acpi_resource); 6128c2ecf20Sopenharmony_ci if (res->type == ACPI_RESOURCE_TYPE_IRQ) 6138c2ecf20Sopenharmony_ci (*resource)->data.irq.descriptor_length = 6148c2ecf20Sopenharmony_ci res->data.irq.descriptor_length; 6158c2ecf20Sopenharmony_ci (*resource)++; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci return AE_OK; 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ciint pnpacpi_build_resource_template(struct pnp_dev *dev, 6228c2ecf20Sopenharmony_ci struct acpi_buffer *buffer) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci struct acpi_device *acpi_dev = dev->data; 6258c2ecf20Sopenharmony_ci acpi_handle handle = acpi_dev->handle; 6268c2ecf20Sopenharmony_ci struct acpi_resource *resource; 6278c2ecf20Sopenharmony_ci int res_cnt = 0; 6288c2ecf20Sopenharmony_ci acpi_status status; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci status = acpi_walk_resources(handle, METHOD_NAME__CRS, 6318c2ecf20Sopenharmony_ci pnpacpi_count_resources, &res_cnt); 6328c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 6338c2ecf20Sopenharmony_ci dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status); 6348c2ecf20Sopenharmony_ci return -EINVAL; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci if (!res_cnt) 6378c2ecf20Sopenharmony_ci return -EINVAL; 6388c2ecf20Sopenharmony_ci buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1; 6398c2ecf20Sopenharmony_ci buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL); 6408c2ecf20Sopenharmony_ci if (!buffer->pointer) 6418c2ecf20Sopenharmony_ci return -ENOMEM; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci resource = (struct acpi_resource *)buffer->pointer; 6448c2ecf20Sopenharmony_ci status = acpi_walk_resources(handle, METHOD_NAME__CRS, 6458c2ecf20Sopenharmony_ci pnpacpi_type_resources, &resource); 6468c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 6478c2ecf20Sopenharmony_ci kfree(buffer->pointer); 6488c2ecf20Sopenharmony_ci dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status); 6498c2ecf20Sopenharmony_ci return -EINVAL; 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci /* resource will pointer the end resource now */ 6528c2ecf20Sopenharmony_ci resource->type = ACPI_RESOURCE_TYPE_END_TAG; 6538c2ecf20Sopenharmony_ci resource->length = sizeof(struct acpi_resource); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci return 0; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic void pnpacpi_encode_irq(struct pnp_dev *dev, 6598c2ecf20Sopenharmony_ci struct acpi_resource *resource, 6608c2ecf20Sopenharmony_ci struct resource *p) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci struct acpi_resource_irq *irq = &resource->data.irq; 6638c2ecf20Sopenharmony_ci u8 triggering, polarity, shareable; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (!pnp_resource_enabled(p)) { 6668c2ecf20Sopenharmony_ci irq->interrupt_count = 0; 6678c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode irq (%s)\n", 6688c2ecf20Sopenharmony_ci p ? "disabled" : "missing"); 6698c2ecf20Sopenharmony_ci return; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable); 6738c2ecf20Sopenharmony_ci irq->triggering = triggering; 6748c2ecf20Sopenharmony_ci irq->polarity = polarity; 6758c2ecf20Sopenharmony_ci irq->shareable = shareable; 6768c2ecf20Sopenharmony_ci irq->interrupt_count = 1; 6778c2ecf20Sopenharmony_ci irq->interrupts[0] = p->start; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode irq %d %s %s %s (%d-byte descriptor)\n", 6808c2ecf20Sopenharmony_ci (int) p->start, 6818c2ecf20Sopenharmony_ci triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge", 6828c2ecf20Sopenharmony_ci polarity == ACPI_ACTIVE_LOW ? "low" : "high", 6838c2ecf20Sopenharmony_ci irq->shareable == ACPI_SHARED ? "shared" : "exclusive", 6848c2ecf20Sopenharmony_ci irq->descriptor_length); 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_cistatic void pnpacpi_encode_ext_irq(struct pnp_dev *dev, 6888c2ecf20Sopenharmony_ci struct acpi_resource *resource, 6898c2ecf20Sopenharmony_ci struct resource *p) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq; 6928c2ecf20Sopenharmony_ci u8 triggering, polarity, shareable; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if (!pnp_resource_enabled(p)) { 6958c2ecf20Sopenharmony_ci extended_irq->interrupt_count = 0; 6968c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode extended irq (%s)\n", 6978c2ecf20Sopenharmony_ci p ? "disabled" : "missing"); 6988c2ecf20Sopenharmony_ci return; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable); 7028c2ecf20Sopenharmony_ci extended_irq->producer_consumer = ACPI_CONSUMER; 7038c2ecf20Sopenharmony_ci extended_irq->triggering = triggering; 7048c2ecf20Sopenharmony_ci extended_irq->polarity = polarity; 7058c2ecf20Sopenharmony_ci extended_irq->shareable = shareable; 7068c2ecf20Sopenharmony_ci extended_irq->interrupt_count = 1; 7078c2ecf20Sopenharmony_ci extended_irq->interrupts[0] = p->start; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode irq %d %s %s %s\n", (int) p->start, 7108c2ecf20Sopenharmony_ci triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge", 7118c2ecf20Sopenharmony_ci polarity == ACPI_ACTIVE_LOW ? "low" : "high", 7128c2ecf20Sopenharmony_ci extended_irq->shareable == ACPI_SHARED ? "shared" : "exclusive"); 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic void pnpacpi_encode_dma(struct pnp_dev *dev, 7168c2ecf20Sopenharmony_ci struct acpi_resource *resource, 7178c2ecf20Sopenharmony_ci struct resource *p) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci struct acpi_resource_dma *dma = &resource->data.dma; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (!pnp_resource_enabled(p)) { 7228c2ecf20Sopenharmony_ci dma->channel_count = 0; 7238c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode dma (%s)\n", 7248c2ecf20Sopenharmony_ci p ? "disabled" : "missing"); 7258c2ecf20Sopenharmony_ci return; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci /* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */ 7298c2ecf20Sopenharmony_ci switch (p->flags & IORESOURCE_DMA_SPEED_MASK) { 7308c2ecf20Sopenharmony_ci case IORESOURCE_DMA_TYPEA: 7318c2ecf20Sopenharmony_ci dma->type = ACPI_TYPE_A; 7328c2ecf20Sopenharmony_ci break; 7338c2ecf20Sopenharmony_ci case IORESOURCE_DMA_TYPEB: 7348c2ecf20Sopenharmony_ci dma->type = ACPI_TYPE_B; 7358c2ecf20Sopenharmony_ci break; 7368c2ecf20Sopenharmony_ci case IORESOURCE_DMA_TYPEF: 7378c2ecf20Sopenharmony_ci dma->type = ACPI_TYPE_F; 7388c2ecf20Sopenharmony_ci break; 7398c2ecf20Sopenharmony_ci default: 7408c2ecf20Sopenharmony_ci dma->type = ACPI_COMPATIBILITY; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci switch (p->flags & IORESOURCE_DMA_TYPE_MASK) { 7448c2ecf20Sopenharmony_ci case IORESOURCE_DMA_8BIT: 7458c2ecf20Sopenharmony_ci dma->transfer = ACPI_TRANSFER_8; 7468c2ecf20Sopenharmony_ci break; 7478c2ecf20Sopenharmony_ci case IORESOURCE_DMA_8AND16BIT: 7488c2ecf20Sopenharmony_ci dma->transfer = ACPI_TRANSFER_8_16; 7498c2ecf20Sopenharmony_ci break; 7508c2ecf20Sopenharmony_ci default: 7518c2ecf20Sopenharmony_ci dma->transfer = ACPI_TRANSFER_16; 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci dma->bus_master = !!(p->flags & IORESOURCE_DMA_MASTER); 7558c2ecf20Sopenharmony_ci dma->channel_count = 1; 7568c2ecf20Sopenharmony_ci dma->channels[0] = p->start; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode dma %d " 7598c2ecf20Sopenharmony_ci "type %#x transfer %#x master %d\n", 7608c2ecf20Sopenharmony_ci (int) p->start, dma->type, dma->transfer, dma->bus_master); 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_cistatic void pnpacpi_encode_io(struct pnp_dev *dev, 7648c2ecf20Sopenharmony_ci struct acpi_resource *resource, 7658c2ecf20Sopenharmony_ci struct resource *p) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci struct acpi_resource_io *io = &resource->data.io; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci if (pnp_resource_enabled(p)) { 7708c2ecf20Sopenharmony_ci /* Note: pnp_assign_port copies pnp_port->flags into p->flags */ 7718c2ecf20Sopenharmony_ci io->io_decode = (p->flags & IORESOURCE_IO_16BIT_ADDR) ? 7728c2ecf20Sopenharmony_ci ACPI_DECODE_16 : ACPI_DECODE_10; 7738c2ecf20Sopenharmony_ci io->minimum = p->start; 7748c2ecf20Sopenharmony_ci io->maximum = p->end; 7758c2ecf20Sopenharmony_ci io->alignment = 0; /* Correct? */ 7768c2ecf20Sopenharmony_ci io->address_length = resource_size(p); 7778c2ecf20Sopenharmony_ci } else { 7788c2ecf20Sopenharmony_ci io->minimum = 0; 7798c2ecf20Sopenharmony_ci io->address_length = 0; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode io %#x-%#x decode %#x\n", io->minimum, 7838c2ecf20Sopenharmony_ci io->minimum + io->address_length - 1, io->io_decode); 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_cistatic void pnpacpi_encode_fixed_io(struct pnp_dev *dev, 7878c2ecf20Sopenharmony_ci struct acpi_resource *resource, 7888c2ecf20Sopenharmony_ci struct resource *p) 7898c2ecf20Sopenharmony_ci{ 7908c2ecf20Sopenharmony_ci struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (pnp_resource_enabled(p)) { 7938c2ecf20Sopenharmony_ci fixed_io->address = p->start; 7948c2ecf20Sopenharmony_ci fixed_io->address_length = resource_size(p); 7958c2ecf20Sopenharmony_ci } else { 7968c2ecf20Sopenharmony_ci fixed_io->address = 0; 7978c2ecf20Sopenharmony_ci fixed_io->address_length = 0; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode fixed_io %#x-%#x\n", fixed_io->address, 8018c2ecf20Sopenharmony_ci fixed_io->address + fixed_io->address_length - 1); 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_cistatic void pnpacpi_encode_mem24(struct pnp_dev *dev, 8058c2ecf20Sopenharmony_ci struct acpi_resource *resource, 8068c2ecf20Sopenharmony_ci struct resource *p) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci struct acpi_resource_memory24 *memory24 = &resource->data.memory24; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci if (pnp_resource_enabled(p)) { 8118c2ecf20Sopenharmony_ci /* Note: pnp_assign_mem copies pnp_mem->flags into p->flags */ 8128c2ecf20Sopenharmony_ci memory24->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ? 8138c2ecf20Sopenharmony_ci ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; 8148c2ecf20Sopenharmony_ci memory24->minimum = p->start; 8158c2ecf20Sopenharmony_ci memory24->maximum = p->end; 8168c2ecf20Sopenharmony_ci memory24->alignment = 0; 8178c2ecf20Sopenharmony_ci memory24->address_length = resource_size(p); 8188c2ecf20Sopenharmony_ci } else { 8198c2ecf20Sopenharmony_ci memory24->minimum = 0; 8208c2ecf20Sopenharmony_ci memory24->address_length = 0; 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode mem24 %#x-%#x write_protect %#x\n", 8248c2ecf20Sopenharmony_ci memory24->minimum, 8258c2ecf20Sopenharmony_ci memory24->minimum + memory24->address_length - 1, 8268c2ecf20Sopenharmony_ci memory24->write_protect); 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_cistatic void pnpacpi_encode_mem32(struct pnp_dev *dev, 8308c2ecf20Sopenharmony_ci struct acpi_resource *resource, 8318c2ecf20Sopenharmony_ci struct resource *p) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci struct acpi_resource_memory32 *memory32 = &resource->data.memory32; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci if (pnp_resource_enabled(p)) { 8368c2ecf20Sopenharmony_ci memory32->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ? 8378c2ecf20Sopenharmony_ci ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; 8388c2ecf20Sopenharmony_ci memory32->minimum = p->start; 8398c2ecf20Sopenharmony_ci memory32->maximum = p->end; 8408c2ecf20Sopenharmony_ci memory32->alignment = 0; 8418c2ecf20Sopenharmony_ci memory32->address_length = resource_size(p); 8428c2ecf20Sopenharmony_ci } else { 8438c2ecf20Sopenharmony_ci memory32->minimum = 0; 8448c2ecf20Sopenharmony_ci memory32->alignment = 0; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode mem32 %#x-%#x write_protect %#x\n", 8488c2ecf20Sopenharmony_ci memory32->minimum, 8498c2ecf20Sopenharmony_ci memory32->minimum + memory32->address_length - 1, 8508c2ecf20Sopenharmony_ci memory32->write_protect); 8518c2ecf20Sopenharmony_ci} 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_cistatic void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev, 8548c2ecf20Sopenharmony_ci struct acpi_resource *resource, 8558c2ecf20Sopenharmony_ci struct resource *p) 8568c2ecf20Sopenharmony_ci{ 8578c2ecf20Sopenharmony_ci struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci if (pnp_resource_enabled(p)) { 8608c2ecf20Sopenharmony_ci fixed_memory32->write_protect = 8618c2ecf20Sopenharmony_ci p->flags & IORESOURCE_MEM_WRITEABLE ? 8628c2ecf20Sopenharmony_ci ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; 8638c2ecf20Sopenharmony_ci fixed_memory32->address = p->start; 8648c2ecf20Sopenharmony_ci fixed_memory32->address_length = resource_size(p); 8658c2ecf20Sopenharmony_ci } else { 8668c2ecf20Sopenharmony_ci fixed_memory32->address = 0; 8678c2ecf20Sopenharmony_ci fixed_memory32->address_length = 0; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " encode fixed_mem32 %#x-%#x write_protect %#x\n", 8718c2ecf20Sopenharmony_ci fixed_memory32->address, 8728c2ecf20Sopenharmony_ci fixed_memory32->address + fixed_memory32->address_length - 1, 8738c2ecf20Sopenharmony_ci fixed_memory32->write_protect); 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ciint pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci int i = 0; 8798c2ecf20Sopenharmony_ci /* pnpacpi_build_resource_template allocates extra mem */ 8808c2ecf20Sopenharmony_ci int res_cnt = (buffer->length - 1) / sizeof(struct acpi_resource) - 1; 8818c2ecf20Sopenharmony_ci struct acpi_resource *resource = buffer->pointer; 8828c2ecf20Sopenharmony_ci unsigned int port = 0, irq = 0, dma = 0, mem = 0; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, "encode %d resources\n", res_cnt); 8858c2ecf20Sopenharmony_ci while (i < res_cnt) { 8868c2ecf20Sopenharmony_ci switch (resource->type) { 8878c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_IRQ: 8888c2ecf20Sopenharmony_ci pnpacpi_encode_irq(dev, resource, 8898c2ecf20Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_IRQ, irq)); 8908c2ecf20Sopenharmony_ci irq++; 8918c2ecf20Sopenharmony_ci break; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_DMA: 8948c2ecf20Sopenharmony_ci pnpacpi_encode_dma(dev, resource, 8958c2ecf20Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_DMA, dma)); 8968c2ecf20Sopenharmony_ci dma++; 8978c2ecf20Sopenharmony_ci break; 8988c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_IO: 8998c2ecf20Sopenharmony_ci pnpacpi_encode_io(dev, resource, 9008c2ecf20Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_IO, port)); 9018c2ecf20Sopenharmony_ci port++; 9028c2ecf20Sopenharmony_ci break; 9038c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_IO: 9048c2ecf20Sopenharmony_ci pnpacpi_encode_fixed_io(dev, resource, 9058c2ecf20Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_IO, port)); 9068c2ecf20Sopenharmony_ci port++; 9078c2ecf20Sopenharmony_ci break; 9088c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY24: 9098c2ecf20Sopenharmony_ci pnpacpi_encode_mem24(dev, resource, 9108c2ecf20Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_MEM, mem)); 9118c2ecf20Sopenharmony_ci mem++; 9128c2ecf20Sopenharmony_ci break; 9138c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY32: 9148c2ecf20Sopenharmony_ci pnpacpi_encode_mem32(dev, resource, 9158c2ecf20Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_MEM, mem)); 9168c2ecf20Sopenharmony_ci mem++; 9178c2ecf20Sopenharmony_ci break; 9188c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 9198c2ecf20Sopenharmony_ci pnpacpi_encode_fixed_mem32(dev, resource, 9208c2ecf20Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_MEM, mem)); 9218c2ecf20Sopenharmony_ci mem++; 9228c2ecf20Sopenharmony_ci break; 9238c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 9248c2ecf20Sopenharmony_ci pnpacpi_encode_ext_irq(dev, resource, 9258c2ecf20Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_IRQ, irq)); 9268c2ecf20Sopenharmony_ci irq++; 9278c2ecf20Sopenharmony_ci break; 9288c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_START_DEPENDENT: 9298c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_END_DEPENDENT: 9308c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_VENDOR: 9318c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_END_TAG: 9328c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS16: 9338c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS32: 9348c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS64: 9358c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: 9368c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: 9378c2ecf20Sopenharmony_ci default: /* other type */ 9388c2ecf20Sopenharmony_ci dev_warn(&dev->dev, 9398c2ecf20Sopenharmony_ci "can't encode unknown resource type %d\n", 9408c2ecf20Sopenharmony_ci resource->type); 9418c2ecf20Sopenharmony_ci return -EINVAL; 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci resource++; 9448c2ecf20Sopenharmony_ci i++; 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci return 0; 9478c2ecf20Sopenharmony_ci} 948