13e0a4e85SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * pnpacpi -- PnP ACPI driver
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
61da177e4SLinus Torvalds * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
740ab4f4cSBjorn Helgaas * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
840ab4f4cSBjorn Helgaas * Bjorn Helgaas <bjorn.helgaas@hp.com>
91da177e4SLinus Torvalds */
101da177e4SLinus Torvalds #include <linux/kernel.h>
111da177e4SLinus Torvalds #include <linux/acpi.h>
121da177e4SLinus Torvalds #include <linux/pci.h>
1302d83b5dSBjorn Helgaas #include <linux/pnp.h>
145a0e3ad6STejun Heo #include <linux/slab.h>
1502d83b5dSBjorn Helgaas #include "../base.h"
161da177e4SLinus Torvalds #include "pnpacpi.h"
171da177e4SLinus Torvalds
decode_irq_flags(struct pnp_dev * dev,int flags,u8 * triggering,u8 * polarity,u8 * shareable)18bbee06d0SFabian Frederick static void decode_irq_flags(struct pnp_dev *dev, int flags, u8 *triggering,
19bbee06d0SFabian Frederick u8 *polarity, u8 *shareable)
201da177e4SLinus Torvalds {
21e9fe9e18SBjorn Helgaas switch (flags & (IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_HIGHLEVEL |
22e9fe9e18SBjorn Helgaas IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE)) {
231da177e4SLinus Torvalds case IORESOURCE_IRQ_LOWLEVEL:
2450eca3ebSBob Moore *triggering = ACPI_LEVEL_SENSITIVE;
2550eca3ebSBob Moore *polarity = ACPI_ACTIVE_LOW;
261da177e4SLinus Torvalds break;
271da177e4SLinus Torvalds case IORESOURCE_IRQ_HIGHLEVEL:
2850eca3ebSBob Moore *triggering = ACPI_LEVEL_SENSITIVE;
2950eca3ebSBob Moore *polarity = ACPI_ACTIVE_HIGH;
301da177e4SLinus Torvalds break;
311da177e4SLinus Torvalds case IORESOURCE_IRQ_LOWEDGE:
3250eca3ebSBob Moore *triggering = ACPI_EDGE_SENSITIVE;
3350eca3ebSBob Moore *polarity = ACPI_ACTIVE_LOW;
341da177e4SLinus Torvalds break;
351da177e4SLinus Torvalds case IORESOURCE_IRQ_HIGHEDGE:
3650eca3ebSBob Moore *triggering = ACPI_EDGE_SENSITIVE;
3750eca3ebSBob Moore *polarity = ACPI_ACTIVE_HIGH;
381da177e4SLinus Torvalds break;
39e9fe9e18SBjorn Helgaas default:
40e9fe9e18SBjorn Helgaas dev_err(&dev->dev, "can't encode invalid IRQ mode %#x\n",
41e9fe9e18SBjorn Helgaas flags);
42e9fe9e18SBjorn Helgaas *triggering = ACPI_EDGE_SENSITIVE;
43e9fe9e18SBjorn Helgaas *polarity = ACPI_ACTIVE_HIGH;
44e9fe9e18SBjorn Helgaas break;
451da177e4SLinus Torvalds }
46a993273bSBjorn Helgaas
47a993273bSBjorn Helgaas if (flags & IORESOURCE_IRQ_SHAREABLE)
48a993273bSBjorn Helgaas *shareable = ACPI_SHARED;
49a993273bSBjorn Helgaas else
50a993273bSBjorn Helgaas *shareable = ACPI_EXCLUSIVE;
511da177e4SLinus Torvalds }
521da177e4SLinus Torvalds
dma_flags(struct pnp_dev * dev,int type,int bus_master,int transfer)53958a1fddSBjorn Helgaas static int dma_flags(struct pnp_dev *dev, int type, int bus_master,
54958a1fddSBjorn Helgaas int transfer)
55362ea087SMichael Karcher {
56362ea087SMichael Karcher int flags = 0;
57362ea087SMichael Karcher
58362ea087SMichael Karcher if (bus_master)
59362ea087SMichael Karcher flags |= IORESOURCE_DMA_MASTER;
60362ea087SMichael Karcher switch (type) {
61362ea087SMichael Karcher case ACPI_COMPATIBILITY:
62362ea087SMichael Karcher flags |= IORESOURCE_DMA_COMPATIBLE;
63362ea087SMichael Karcher break;
64362ea087SMichael Karcher case ACPI_TYPE_A:
65362ea087SMichael Karcher flags |= IORESOURCE_DMA_TYPEA;
66362ea087SMichael Karcher break;
67362ea087SMichael Karcher case ACPI_TYPE_B:
68362ea087SMichael Karcher flags |= IORESOURCE_DMA_TYPEB;
69362ea087SMichael Karcher break;
70362ea087SMichael Karcher case ACPI_TYPE_F:
71362ea087SMichael Karcher flags |= IORESOURCE_DMA_TYPEF;
72362ea087SMichael Karcher break;
73362ea087SMichael Karcher default:
74362ea087SMichael Karcher /* Set a default value ? */
75362ea087SMichael Karcher flags |= IORESOURCE_DMA_COMPATIBLE;
76958a1fddSBjorn Helgaas dev_err(&dev->dev, "invalid DMA type %d\n", type);
77362ea087SMichael Karcher }
78362ea087SMichael Karcher switch (transfer) {
79362ea087SMichael Karcher case ACPI_TRANSFER_8:
80362ea087SMichael Karcher flags |= IORESOURCE_DMA_8BIT;
81362ea087SMichael Karcher break;
82362ea087SMichael Karcher case ACPI_TRANSFER_8_16:
83362ea087SMichael Karcher flags |= IORESOURCE_DMA_8AND16BIT;
84362ea087SMichael Karcher break;
85362ea087SMichael Karcher case ACPI_TRANSFER_16:
86362ea087SMichael Karcher flags |= IORESOURCE_DMA_16BIT;
87362ea087SMichael Karcher break;
88362ea087SMichael Karcher default:
89362ea087SMichael Karcher /* Set a default value ? */
90362ea087SMichael Karcher flags |= IORESOURCE_DMA_8AND16BIT;
91958a1fddSBjorn Helgaas dev_err(&dev->dev, "invalid DMA transfer type %d\n", transfer);
92362ea087SMichael Karcher }
93362ea087SMichael Karcher
94362ea087SMichael Karcher return flags;
95362ea087SMichael Karcher }
96362ea087SMichael Karcher
97046d9ce6SRafael J. Wysocki /*
98046d9ce6SRafael J. Wysocki * Allocated Resources
99046d9ce6SRafael J. Wysocki */
100046d9ce6SRafael J. Wysocki
pnpacpi_add_irqresource(struct pnp_dev * dev,struct resource * r)101046d9ce6SRafael J. Wysocki static void pnpacpi_add_irqresource(struct pnp_dev *dev, struct resource *r)
1021da177e4SLinus Torvalds {
103046d9ce6SRafael J. Wysocki if (!(r->flags & IORESOURCE_DISABLED))
104046d9ce6SRafael J. Wysocki pcibios_penalize_isa_irq(r->start, 1);
10507d4e9afSBjorn Helgaas
106046d9ce6SRafael J. Wysocki pnp_add_resource(dev, r);
1071da177e4SLinus Torvalds }
1081da177e4SLinus Torvalds
10940ab4f4cSBjorn Helgaas /*
11040ab4f4cSBjorn Helgaas * Device CSRs that do not appear in PCI config space should be described
11140ab4f4cSBjorn Helgaas * via ACPI. This would normally be done with Address Space Descriptors
11240ab4f4cSBjorn Helgaas * marked as "consumer-only," but old versions of Windows and Linux ignore
11340ab4f4cSBjorn Helgaas * the producer/consumer flag, so HP invented a vendor-defined resource to
11440ab4f4cSBjorn Helgaas * describe the location and size of CSR space.
11540ab4f4cSBjorn Helgaas */
11640ab4f4cSBjorn Helgaas static struct acpi_vendor_uuid hp_ccsr_uuid = {
11740ab4f4cSBjorn Helgaas .subtype = 2,
11840ab4f4cSBjorn Helgaas .data = { 0xf9, 0xad, 0xe9, 0x69, 0x4f, 0x92, 0x5f, 0xab, 0xf6, 0x4a,
11940ab4f4cSBjorn Helgaas 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad },
12040ab4f4cSBjorn Helgaas };
12140ab4f4cSBjorn Helgaas
vendor_resource_matches(struct pnp_dev * dev,struct acpi_resource_vendor_typed * vendor,struct acpi_vendor_uuid * match,int expected_len)12240ab4f4cSBjorn Helgaas static int vendor_resource_matches(struct pnp_dev *dev,
12340ab4f4cSBjorn Helgaas struct acpi_resource_vendor_typed *vendor,
12440ab4f4cSBjorn Helgaas struct acpi_vendor_uuid *match,
12540ab4f4cSBjorn Helgaas int expected_len)
12640ab4f4cSBjorn Helgaas {
12740ab4f4cSBjorn Helgaas int uuid_len = sizeof(vendor->uuid);
12840ab4f4cSBjorn Helgaas u8 uuid_subtype = vendor->uuid_subtype;
12940ab4f4cSBjorn Helgaas u8 *uuid = vendor->uuid;
13040ab4f4cSBjorn Helgaas int actual_len;
13140ab4f4cSBjorn Helgaas
13240ab4f4cSBjorn Helgaas /* byte_length includes uuid_subtype and uuid */
13340ab4f4cSBjorn Helgaas actual_len = vendor->byte_length - uuid_len - 1;
13440ab4f4cSBjorn Helgaas
13540ab4f4cSBjorn Helgaas if (uuid_subtype == match->subtype &&
13640ab4f4cSBjorn Helgaas uuid_len == sizeof(match->data) &&
13740ab4f4cSBjorn Helgaas memcmp(uuid, match->data, uuid_len) == 0) {
13840ab4f4cSBjorn Helgaas if (expected_len && expected_len != actual_len) {
1391d7f2cddSAndy Shevchenko dev_err(&dev->dev,
1401d7f2cddSAndy Shevchenko "wrong vendor descriptor size; expected %d, found %d bytes\n",
14140ab4f4cSBjorn Helgaas expected_len, actual_len);
14240ab4f4cSBjorn Helgaas return 0;
14340ab4f4cSBjorn Helgaas }
14440ab4f4cSBjorn Helgaas
14540ab4f4cSBjorn Helgaas return 1;
14640ab4f4cSBjorn Helgaas }
14740ab4f4cSBjorn Helgaas
14840ab4f4cSBjorn Helgaas return 0;
14940ab4f4cSBjorn Helgaas }
15040ab4f4cSBjorn Helgaas
pnpacpi_parse_allocated_vendor(struct pnp_dev * dev,struct acpi_resource_vendor_typed * vendor)15140ab4f4cSBjorn Helgaas static void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev,
15240ab4f4cSBjorn Helgaas struct acpi_resource_vendor_typed *vendor)
15340ab4f4cSBjorn Helgaas {
154*ba3f5058SDmitry Antipov struct { u64 start, length; } range;
15540ab4f4cSBjorn Helgaas
156*ba3f5058SDmitry Antipov if (vendor_resource_matches(dev, vendor, &hp_ccsr_uuid,
157*ba3f5058SDmitry Antipov sizeof(range))) {
158*ba3f5058SDmitry Antipov memcpy(&range, vendor->byte_data, sizeof(range));
159*ba3f5058SDmitry Antipov pnp_add_mem_resource(dev, range.start, range.start +
160*ba3f5058SDmitry Antipov range.length - 1, 0);
16140ab4f4cSBjorn Helgaas }
16240ab4f4cSBjorn Helgaas }
16340ab4f4cSBjorn Helgaas
pnpacpi_allocated_resource(struct acpi_resource * res,void * data)1641da177e4SLinus Torvalds static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
1651da177e4SLinus Torvalds void *data)
1661da177e4SLinus Torvalds {
1674ab55d8dSBjorn Helgaas struct pnp_dev *dev = data;
1689570a20eSBjorn Helgaas struct acpi_resource_dma *dma;
16940ab4f4cSBjorn Helgaas struct acpi_resource_vendor_typed *vendor_typed;
1702a56e919SJagadish Krishnamoorthy struct acpi_resource_gpio *gpio;
171a49170b5SJiang Liu struct resource_win win = {{0}, 0};
172a49170b5SJiang Liu struct resource *r = &win.res;
173dc16f5f2SBjorn Helgaas int i, flags;
1741da177e4SLinus Torvalds
175a49170b5SJiang Liu if (acpi_dev_resource_address_space(res, &win)
176a49170b5SJiang Liu || acpi_dev_resource_ext_address_space(res, &win)) {
177a49170b5SJiang Liu pnp_add_resource(dev, &win.res);
178046d9ce6SRafael J. Wysocki return AE_OK;
1791da177e4SLinus Torvalds }
1805acf9141SBjorn Helgaas
181a49170b5SJiang Liu r->flags = 0;
182a49170b5SJiang Liu if (acpi_dev_resource_interrupt(res, 0, r)) {
183a49170b5SJiang Liu pnpacpi_add_irqresource(dev, r);
184a49170b5SJiang Liu for (i = 1; acpi_dev_resource_interrupt(res, i, r); i++)
185a49170b5SJiang Liu pnpacpi_add_irqresource(dev, r);
186046d9ce6SRafael J. Wysocki
187046d9ce6SRafael J. Wysocki if (i > 1) {
1885acf9141SBjorn Helgaas /*
1895acf9141SBjorn Helgaas * The IRQ encoder puts a single interrupt in each
1905acf9141SBjorn Helgaas * descriptor, so if a _CRS descriptor has more than
1915acf9141SBjorn Helgaas * one interrupt, we won't be able to re-encode it.
1925acf9141SBjorn Helgaas */
193046d9ce6SRafael J. Wysocki if (pnp_can_write(dev)) {
1941d7f2cddSAndy Shevchenko dev_warn(&dev->dev,
1951d7f2cddSAndy Shevchenko "multiple interrupts in _CRS descriptor; configuration can't be changed\n");
1965acf9141SBjorn Helgaas dev->capabilities &= ~PNP_WRITE;
1975acf9141SBjorn Helgaas }
1985acf9141SBjorn Helgaas }
199046d9ce6SRafael J. Wysocki return AE_OK;
2002a56e919SJagadish Krishnamoorthy } else if (acpi_gpio_get_irq_resource(res, &gpio)) {
2012a56e919SJagadish Krishnamoorthy /*
2022a56e919SJagadish Krishnamoorthy * If the resource is GpioInt() type then extract the IRQ
2032a56e919SJagadish Krishnamoorthy * from GPIO resource and fill it into IRQ resource type.
2042a56e919SJagadish Krishnamoorthy */
2052a56e919SJagadish Krishnamoorthy i = acpi_dev_gpio_irq_get(dev->data, 0);
2062a56e919SJagadish Krishnamoorthy if (i >= 0) {
2072a56e919SJagadish Krishnamoorthy flags = acpi_dev_irq_flags(gpio->triggering,
2082a56e919SJagadish Krishnamoorthy gpio->polarity,
2095ff81160SRaul E Rangel gpio->shareable,
2105ff81160SRaul E Rangel gpio->wake_capable);
2112a56e919SJagadish Krishnamoorthy } else {
2122a56e919SJagadish Krishnamoorthy flags = IORESOURCE_DISABLED;
2132a56e919SJagadish Krishnamoorthy }
2142a56e919SJagadish Krishnamoorthy pnp_add_irq_resource(dev, i, flags);
2152a56e919SJagadish Krishnamoorthy return AE_OK;
216a49170b5SJiang Liu } else if (r->flags & IORESOURCE_DISABLED) {
217046d9ce6SRafael J. Wysocki pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
218046d9ce6SRafael J. Wysocki return AE_OK;
219046d9ce6SRafael J. Wysocki }
2201da177e4SLinus Torvalds
221046d9ce6SRafael J. Wysocki switch (res->type) {
22289935315SZhang Rui case ACPI_RESOURCE_TYPE_MEMORY24:
22389935315SZhang Rui case ACPI_RESOURCE_TYPE_MEMORY32:
22489935315SZhang Rui case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
225a49170b5SJiang Liu if (acpi_dev_resource_memory(res, r))
226a49170b5SJiang Liu pnp_add_resource(dev, r);
22789935315SZhang Rui break;
22889935315SZhang Rui case ACPI_RESOURCE_TYPE_IO:
22989935315SZhang Rui case ACPI_RESOURCE_TYPE_FIXED_IO:
230a49170b5SJiang Liu if (acpi_dev_resource_io(res, r))
231a49170b5SJiang Liu pnp_add_resource(dev, r);
23289935315SZhang Rui break;
23350eca3ebSBob Moore case ACPI_RESOURCE_TYPE_DMA:
2349570a20eSBjorn Helgaas dma = &res->data.dma;
2355acf9141SBjorn Helgaas if (dma->channel_count > 0 && dma->channels[0] != (u8) -1)
236958a1fddSBjorn Helgaas flags = dma_flags(dev, dma->type, dma->bus_master,
237dc16f5f2SBjorn Helgaas dma->transfer);
2385acf9141SBjorn Helgaas else
2395acf9141SBjorn Helgaas flags = IORESOURCE_DISABLED;
240dc16f5f2SBjorn Helgaas pnp_add_dma_resource(dev, dma->channels[0], flags);
2411da177e4SLinus Torvalds break;
2420af5853bSLen Brown
2430af5853bSLen Brown case ACPI_RESOURCE_TYPE_START_DEPENDENT:
2440af5853bSLen Brown case ACPI_RESOURCE_TYPE_END_DEPENDENT:
2450af5853bSLen Brown break;
2460af5853bSLen Brown
2470af5853bSLen Brown case ACPI_RESOURCE_TYPE_VENDOR:
24840ab4f4cSBjorn Helgaas vendor_typed = &res->data.vendor_typed;
24940ab4f4cSBjorn Helgaas pnpacpi_parse_allocated_vendor(dev, vendor_typed);
2500af5853bSLen Brown break;
2510af5853bSLen Brown
2520af5853bSLen Brown case ACPI_RESOURCE_TYPE_END_TAG:
2530af5853bSLen Brown break;
2540af5853bSLen Brown
2550af5853bSLen Brown case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
2560af5853bSLen Brown break;
2570af5853bSLen Brown
25886e75410SHarb Abdulhamid case ACPI_RESOURCE_TYPE_SERIAL_BUS:
25986e75410SHarb Abdulhamid /* serial bus connections (I2C/SPI/UART) are not pnp */
26086e75410SHarb Abdulhamid break;
26186e75410SHarb Abdulhamid
2621da177e4SLinus Torvalds default:
263af11cb2dSBjorn Helgaas dev_warn(&dev->dev, "unknown resource type %d in _CRS\n",
264af11cb2dSBjorn Helgaas res->type);
2651da177e4SLinus Torvalds return AE_ERROR;
2661da177e4SLinus Torvalds }
2671da177e4SLinus Torvalds
2681da177e4SLinus Torvalds return AE_OK;
2691da177e4SLinus Torvalds }
2701da177e4SLinus Torvalds
pnpacpi_parse_allocated_resource(struct pnp_dev * dev)271d152cf5dSBjorn Helgaas int pnpacpi_parse_allocated_resource(struct pnp_dev *dev)
2721da177e4SLinus Torvalds {
273c4da6940SBjorn Helgaas struct acpi_device *acpi_dev = dev->data;
274c4da6940SBjorn Helgaas acpi_handle handle = acpi_dev->handle;
275d152cf5dSBjorn Helgaas acpi_status status;
2764ab55d8dSBjorn Helgaas
2772f53432cSBjorn Helgaas pnp_dbg(&dev->dev, "parse allocated resources\n");
27872dcc883SBjorn Helgaas
279f4490002SBjorn Helgaas pnp_init_resources(dev);
2801da177e4SLinus Torvalds
281d152cf5dSBjorn Helgaas status = acpi_walk_resources(handle, METHOD_NAME__CRS,
2824ab55d8dSBjorn Helgaas pnpacpi_allocated_resource, dev);
283d152cf5dSBjorn Helgaas
284d152cf5dSBjorn Helgaas if (ACPI_FAILURE(status)) {
285d152cf5dSBjorn Helgaas if (status != AE_NOT_FOUND)
286d152cf5dSBjorn Helgaas dev_err(&dev->dev, "can't evaluate _CRS: %d", status);
287d152cf5dSBjorn Helgaas return -EPERM;
288d152cf5dSBjorn Helgaas }
289d152cf5dSBjorn Helgaas return 0;
2901da177e4SLinus Torvalds }
2911da177e4SLinus Torvalds
pnpacpi_parse_dma_option(struct pnp_dev * dev,unsigned int option_flags,struct acpi_resource_dma * p)292c1caf06cSBjorn Helgaas static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev,
2931f32ca31SBjorn Helgaas unsigned int option_flags,
2949dd78466SBjorn Helgaas struct acpi_resource_dma *p)
2951da177e4SLinus Torvalds {
2961da177e4SLinus Torvalds int i;
29718fd470aSWitold Szczeponik unsigned char map = 0, flags;
2981da177e4SLinus Torvalds
29950eca3ebSBob Moore for (i = 0; i < p->channel_count; i++)
300c227536bSBjorn Helgaas map |= 1 << p->channels[i];
301362ea087SMichael Karcher
30218fd470aSWitold Szczeponik flags = dma_flags(dev, p->type, p->bus_master, p->transfer);
3031f32ca31SBjorn Helgaas pnp_register_dma_resource(dev, option_flags, map, flags);
3041da177e4SLinus Torvalds }
3051da177e4SLinus Torvalds
pnpacpi_parse_irq_option(struct pnp_dev * dev,unsigned int option_flags,struct acpi_resource_irq * p)306c1caf06cSBjorn Helgaas static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev,
3071f32ca31SBjorn Helgaas unsigned int option_flags,
3081da177e4SLinus Torvalds struct acpi_resource_irq *p)
3091da177e4SLinus Torvalds {
3101da177e4SLinus Torvalds int i;
311c227536bSBjorn Helgaas pnp_irq_mask_t map;
31218fd470aSWitold Szczeponik unsigned char flags;
3131da177e4SLinus Torvalds
314c227536bSBjorn Helgaas bitmap_zero(map.bits, PNP_IRQ_NR);
31550eca3ebSBob Moore for (i = 0; i < p->interrupt_count; i++)
3161da177e4SLinus Torvalds if (p->interrupts[i])
317c227536bSBjorn Helgaas __set_bit(p->interrupts[i], map.bits);
3181da177e4SLinus Torvalds
3195ff81160SRaul E Rangel flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->shareable, p->wake_capable);
3201f32ca31SBjorn Helgaas pnp_register_irq_resource(dev, option_flags, &map, flags);
3211da177e4SLinus Torvalds }
3221da177e4SLinus Torvalds
pnpacpi_parse_ext_irq_option(struct pnp_dev * dev,unsigned int option_flags,struct acpi_resource_extended_irq * p)323c1caf06cSBjorn Helgaas static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev,
3241f32ca31SBjorn Helgaas unsigned int option_flags,
32550eca3ebSBob Moore struct acpi_resource_extended_irq *p)
3261da177e4SLinus Torvalds {
3271da177e4SLinus Torvalds int i;
328c227536bSBjorn Helgaas pnp_irq_mask_t map;
32918fd470aSWitold Szczeponik unsigned char flags;
3301da177e4SLinus Torvalds
331c227536bSBjorn Helgaas bitmap_zero(map.bits, PNP_IRQ_NR);
332fe2cf598SBjorn Helgaas for (i = 0; i < p->interrupt_count; i++) {
333fe2cf598SBjorn Helgaas if (p->interrupts[i]) {
334fe2cf598SBjorn Helgaas if (p->interrupts[i] < PNP_IRQ_NR)
335c227536bSBjorn Helgaas __set_bit(p->interrupts[i], map.bits);
336fe2cf598SBjorn Helgaas else
3371d7f2cddSAndy Shevchenko dev_err(&dev->dev,
3381d7f2cddSAndy Shevchenko "ignoring IRQ %d option (too large for %d entry bitmap)\n",
339fe2cf598SBjorn Helgaas p->interrupts[i], PNP_IRQ_NR);
340fe2cf598SBjorn Helgaas }
341fe2cf598SBjorn Helgaas }
3421da177e4SLinus Torvalds
3435ff81160SRaul E Rangel flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->shareable, p->wake_capable);
3441f32ca31SBjorn Helgaas pnp_register_irq_resource(dev, option_flags, &map, flags);
3451da177e4SLinus Torvalds }
3461da177e4SLinus Torvalds
pnpacpi_parse_port_option(struct pnp_dev * dev,unsigned int option_flags,struct acpi_resource_io * io)347c1caf06cSBjorn Helgaas static __init void pnpacpi_parse_port_option(struct pnp_dev *dev,
3481f32ca31SBjorn Helgaas unsigned int option_flags,
3491da177e4SLinus Torvalds struct acpi_resource_io *io)
3501da177e4SLinus Torvalds {
351c227536bSBjorn Helgaas unsigned char flags = 0;
3521da177e4SLinus Torvalds
353c227536bSBjorn Helgaas if (io->io_decode == ACPI_DECODE_16)
35418fd470aSWitold Szczeponik flags = IORESOURCE_IO_16BIT_ADDR;
3551f32ca31SBjorn Helgaas pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum,
356c227536bSBjorn Helgaas io->alignment, io->address_length, flags);
3571da177e4SLinus Torvalds }
3581da177e4SLinus Torvalds
pnpacpi_parse_fixed_port_option(struct pnp_dev * dev,unsigned int option_flags,struct acpi_resource_fixed_io * io)359c1caf06cSBjorn Helgaas static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev,
3601f32ca31SBjorn Helgaas unsigned int option_flags,
3611da177e4SLinus Torvalds struct acpi_resource_fixed_io *io)
3621da177e4SLinus Torvalds {
3631f32ca31SBjorn Helgaas pnp_register_port_resource(dev, option_flags, io->address, io->address,
36418fd470aSWitold Szczeponik 0, io->address_length, IORESOURCE_IO_FIXED);
3651da177e4SLinus Torvalds }
3661da177e4SLinus Torvalds
pnpacpi_parse_mem24_option(struct pnp_dev * dev,unsigned int option_flags,struct acpi_resource_memory24 * p)367c1caf06cSBjorn Helgaas static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev,
3681f32ca31SBjorn Helgaas unsigned int option_flags,
36950eca3ebSBob Moore struct acpi_resource_memory24 *p)
3701da177e4SLinus Torvalds {
371c227536bSBjorn Helgaas unsigned char flags = 0;
3721da177e4SLinus Torvalds
373c227536bSBjorn Helgaas if (p->write_protect == ACPI_READ_WRITE_MEMORY)
37418fd470aSWitold Szczeponik flags = IORESOURCE_MEM_WRITEABLE;
3751f32ca31SBjorn Helgaas pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum,
376c227536bSBjorn Helgaas p->alignment, p->address_length, flags);
3771da177e4SLinus Torvalds }
3781da177e4SLinus Torvalds
pnpacpi_parse_mem32_option(struct pnp_dev * dev,unsigned int option_flags,struct acpi_resource_memory32 * p)379c1caf06cSBjorn Helgaas static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev,
3801f32ca31SBjorn Helgaas unsigned int option_flags,
38150eca3ebSBob Moore struct acpi_resource_memory32 *p)
3821da177e4SLinus Torvalds {
383c227536bSBjorn Helgaas unsigned char flags = 0;
3841da177e4SLinus Torvalds
385c227536bSBjorn Helgaas if (p->write_protect == ACPI_READ_WRITE_MEMORY)
38618fd470aSWitold Szczeponik flags = IORESOURCE_MEM_WRITEABLE;
3871f32ca31SBjorn Helgaas pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum,
388c227536bSBjorn Helgaas p->alignment, p->address_length, flags);
3891da177e4SLinus Torvalds }
3901da177e4SLinus Torvalds
pnpacpi_parse_fixed_mem32_option(struct pnp_dev * dev,unsigned int option_flags,struct acpi_resource_fixed_memory32 * p)391c1caf06cSBjorn Helgaas static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev,
3921f32ca31SBjorn Helgaas unsigned int option_flags,
39350eca3ebSBob Moore struct acpi_resource_fixed_memory32 *p)
3941da177e4SLinus Torvalds {
395c227536bSBjorn Helgaas unsigned char flags = 0;
3961da177e4SLinus Torvalds
397c227536bSBjorn Helgaas if (p->write_protect == ACPI_READ_WRITE_MEMORY)
39818fd470aSWitold Szczeponik flags = IORESOURCE_MEM_WRITEABLE;
3991f32ca31SBjorn Helgaas pnp_register_mem_resource(dev, option_flags, p->address, p->address,
400c227536bSBjorn Helgaas 0, p->address_length, flags);
4011da177e4SLinus Torvalds }
4021da177e4SLinus Torvalds
pnpacpi_parse_address_option(struct pnp_dev * dev,unsigned int option_flags,struct acpi_resource * r)403c1caf06cSBjorn Helgaas static __init void pnpacpi_parse_address_option(struct pnp_dev *dev,
4041f32ca31SBjorn Helgaas unsigned int option_flags,
40507d4e9afSBjorn Helgaas struct acpi_resource *r)
4066f957eafSBjorn Helgaas {
4076f957eafSBjorn Helgaas struct acpi_resource_address64 addr, *p = &addr;
4086f957eafSBjorn Helgaas acpi_status status;
409c227536bSBjorn Helgaas unsigned char flags = 0;
4106f957eafSBjorn Helgaas
4116f957eafSBjorn Helgaas status = acpi_resource_to_address64(r, p);
412958a1fddSBjorn Helgaas if (ACPI_FAILURE(status)) {
413958a1fddSBjorn Helgaas dev_warn(&dev->dev, "can't convert resource type %d\n",
4149dd78466SBjorn Helgaas r->type);
4156f957eafSBjorn Helgaas return;
4166f957eafSBjorn Helgaas }
4176f957eafSBjorn Helgaas
4186f957eafSBjorn Helgaas if (p->resource_type == ACPI_MEMORY_RANGE) {
419c227536bSBjorn Helgaas if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
42018fd470aSWitold Szczeponik flags = IORESOURCE_MEM_WRITEABLE;
421a45de93eSLv Zheng pnp_register_mem_resource(dev, option_flags, p->address.minimum,
422a45de93eSLv Zheng p->address.minimum, 0, p->address.address_length,
4231f32ca31SBjorn Helgaas flags);
424c227536bSBjorn Helgaas } else if (p->resource_type == ACPI_IO_RANGE)
425a45de93eSLv Zheng pnp_register_port_resource(dev, option_flags, p->address.minimum,
426a45de93eSLv Zheng p->address.minimum, 0, p->address.address_length,
42718fd470aSWitold Szczeponik IORESOURCE_IO_FIXED);
4286f957eafSBjorn Helgaas }
4296f957eafSBjorn Helgaas
pnpacpi_parse_ext_address_option(struct pnp_dev * dev,unsigned int option_flags,struct acpi_resource * r)4308cb24c8fSBjorn Helgaas static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev,
4318cb24c8fSBjorn Helgaas unsigned int option_flags,
4328cb24c8fSBjorn Helgaas struct acpi_resource *r)
4338cb24c8fSBjorn Helgaas {
4348cb24c8fSBjorn Helgaas struct acpi_resource_extended_address64 *p = &r->data.ext_address64;
4358cb24c8fSBjorn Helgaas unsigned char flags = 0;
4368cb24c8fSBjorn Helgaas
4378cb24c8fSBjorn Helgaas if (p->resource_type == ACPI_MEMORY_RANGE) {
4388cb24c8fSBjorn Helgaas if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
43918fd470aSWitold Szczeponik flags = IORESOURCE_MEM_WRITEABLE;
440a45de93eSLv Zheng pnp_register_mem_resource(dev, option_flags, p->address.minimum,
441a45de93eSLv Zheng p->address.minimum, 0, p->address.address_length,
4428cb24c8fSBjorn Helgaas flags);
4438cb24c8fSBjorn Helgaas } else if (p->resource_type == ACPI_IO_RANGE)
444a45de93eSLv Zheng pnp_register_port_resource(dev, option_flags, p->address.minimum,
445a45de93eSLv Zheng p->address.minimum, 0, p->address.address_length,
44618fd470aSWitold Szczeponik IORESOURCE_IO_FIXED);
4478cb24c8fSBjorn Helgaas }
4488cb24c8fSBjorn Helgaas
4491da177e4SLinus Torvalds struct acpipnp_parse_option_s {
4501da177e4SLinus Torvalds struct pnp_dev *dev;
4511f32ca31SBjorn Helgaas unsigned int option_flags;
4521da177e4SLinus Torvalds };
4531da177e4SLinus Torvalds
pnpacpi_option_resource(struct acpi_resource * res,void * data)4542bb9a6b3SThomas Renninger static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
4551da177e4SLinus Torvalds void *data)
4561da177e4SLinus Torvalds {
457e2a1a6f1SBjorn Helgaas int priority;
4584721a4ccSBjorn Helgaas struct acpipnp_parse_option_s *parse_data = data;
4591da177e4SLinus Torvalds struct pnp_dev *dev = parse_data->dev;
4601f32ca31SBjorn Helgaas unsigned int option_flags = parse_data->option_flags;
4611da177e4SLinus Torvalds
462eca008c8SLen Brown switch (res->type) {
46350eca3ebSBob Moore case ACPI_RESOURCE_TYPE_IRQ:
4641f32ca31SBjorn Helgaas pnpacpi_parse_irq_option(dev, option_flags, &res->data.irq);
4651da177e4SLinus Torvalds break;
4660af5853bSLen Brown
46750eca3ebSBob Moore case ACPI_RESOURCE_TYPE_DMA:
4681f32ca31SBjorn Helgaas pnpacpi_parse_dma_option(dev, option_flags, &res->data.dma);
4691da177e4SLinus Torvalds break;
4700af5853bSLen Brown
47150eca3ebSBob Moore case ACPI_RESOURCE_TYPE_START_DEPENDENT:
4721da177e4SLinus Torvalds switch (res->data.start_dpf.compatibility_priority) {
4731da177e4SLinus Torvalds case ACPI_GOOD_CONFIGURATION:
4741da177e4SLinus Torvalds priority = PNP_RES_PRIORITY_PREFERRED;
4751da177e4SLinus Torvalds break;
4761da177e4SLinus Torvalds
4771da177e4SLinus Torvalds case ACPI_ACCEPTABLE_CONFIGURATION:
4781da177e4SLinus Torvalds priority = PNP_RES_PRIORITY_ACCEPTABLE;
4791da177e4SLinus Torvalds break;
4801da177e4SLinus Torvalds
4811da177e4SLinus Torvalds case ACPI_SUB_OPTIMAL_CONFIGURATION:
4821da177e4SLinus Torvalds priority = PNP_RES_PRIORITY_FUNCTIONAL;
4831da177e4SLinus Torvalds break;
4841da177e4SLinus Torvalds default:
4851da177e4SLinus Torvalds priority = PNP_RES_PRIORITY_INVALID;
4861da177e4SLinus Torvalds break;
4871da177e4SLinus Torvalds }
4881f32ca31SBjorn Helgaas parse_data->option_flags = pnp_new_dependent_set(dev, priority);
4891da177e4SLinus Torvalds break;
4900af5853bSLen Brown
49150eca3ebSBob Moore case ACPI_RESOURCE_TYPE_END_DEPENDENT:
4921f32ca31SBjorn Helgaas parse_data->option_flags = 0;
493b008b8d7SMatthieu Castet break;
4940af5853bSLen Brown
4950af5853bSLen Brown case ACPI_RESOURCE_TYPE_IO:
4961f32ca31SBjorn Helgaas pnpacpi_parse_port_option(dev, option_flags, &res->data.io);
4970af5853bSLen Brown break;
4980af5853bSLen Brown
4990af5853bSLen Brown case ACPI_RESOURCE_TYPE_FIXED_IO:
5001f32ca31SBjorn Helgaas pnpacpi_parse_fixed_port_option(dev, option_flags,
501c1caf06cSBjorn Helgaas &res->data.fixed_io);
5020af5853bSLen Brown break;
5030af5853bSLen Brown
5040af5853bSLen Brown case ACPI_RESOURCE_TYPE_VENDOR:
5050af5853bSLen Brown case ACPI_RESOURCE_TYPE_END_TAG:
5060af5853bSLen Brown break;
5070af5853bSLen Brown
5080af5853bSLen Brown case ACPI_RESOURCE_TYPE_MEMORY24:
5091f32ca31SBjorn Helgaas pnpacpi_parse_mem24_option(dev, option_flags,
5101f32ca31SBjorn Helgaas &res->data.memory24);
5110af5853bSLen Brown break;
5120af5853bSLen Brown
5130af5853bSLen Brown case ACPI_RESOURCE_TYPE_MEMORY32:
5141f32ca31SBjorn Helgaas pnpacpi_parse_mem32_option(dev, option_flags,
5151f32ca31SBjorn Helgaas &res->data.memory32);
5160af5853bSLen Brown break;
5170af5853bSLen Brown
5180af5853bSLen Brown case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
5191f32ca31SBjorn Helgaas pnpacpi_parse_fixed_mem32_option(dev, option_flags,
5200af5853bSLen Brown &res->data.fixed_memory32);
5210af5853bSLen Brown break;
5220af5853bSLen Brown
5230af5853bSLen Brown case ACPI_RESOURCE_TYPE_ADDRESS16:
5240af5853bSLen Brown case ACPI_RESOURCE_TYPE_ADDRESS32:
5250af5853bSLen Brown case ACPI_RESOURCE_TYPE_ADDRESS64:
5261f32ca31SBjorn Helgaas pnpacpi_parse_address_option(dev, option_flags, res);
5270af5853bSLen Brown break;
5280af5853bSLen Brown
5290af5853bSLen Brown case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
5308cb24c8fSBjorn Helgaas pnpacpi_parse_ext_address_option(dev, option_flags, res);
5310af5853bSLen Brown break;
5320af5853bSLen Brown
5330af5853bSLen Brown case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
5341f32ca31SBjorn Helgaas pnpacpi_parse_ext_irq_option(dev, option_flags,
535c1caf06cSBjorn Helgaas &res->data.extended_irq);
5360af5853bSLen Brown break;
5370af5853bSLen Brown
5380af5853bSLen Brown case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
5390af5853bSLen Brown break;
5400af5853bSLen Brown
5411da177e4SLinus Torvalds default:
542af11cb2dSBjorn Helgaas dev_warn(&dev->dev, "unknown resource type %d in _PRS\n",
543af11cb2dSBjorn Helgaas res->type);
5441da177e4SLinus Torvalds return AE_ERROR;
5451da177e4SLinus Torvalds }
5461da177e4SLinus Torvalds
5471da177e4SLinus Torvalds return AE_OK;
5481da177e4SLinus Torvalds }
5491da177e4SLinus Torvalds
pnpacpi_parse_resource_option_data(struct pnp_dev * dev)550d152cf5dSBjorn Helgaas int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev)
5511da177e4SLinus Torvalds {
552c4da6940SBjorn Helgaas struct acpi_device *acpi_dev = dev->data;
553c4da6940SBjorn Helgaas acpi_handle handle = acpi_dev->handle;
5541da177e4SLinus Torvalds acpi_status status;
5551da177e4SLinus Torvalds struct acpipnp_parse_option_s parse_data;
5561da177e4SLinus Torvalds
5572f53432cSBjorn Helgaas pnp_dbg(&dev->dev, "parse resource options\n");
55872dcc883SBjorn Helgaas
5591da177e4SLinus Torvalds parse_data.dev = dev;
5601f32ca31SBjorn Helgaas parse_data.option_flags = 0;
5611f32ca31SBjorn Helgaas
5621da177e4SLinus Torvalds status = acpi_walk_resources(handle, METHOD_NAME__PRS,
5631da177e4SLinus Torvalds pnpacpi_option_resource, &parse_data);
5641da177e4SLinus Torvalds
565d152cf5dSBjorn Helgaas if (ACPI_FAILURE(status)) {
566d152cf5dSBjorn Helgaas if (status != AE_NOT_FOUND)
567d152cf5dSBjorn Helgaas dev_err(&dev->dev, "can't evaluate _PRS: %d", status);
568d152cf5dSBjorn Helgaas return -EPERM;
569d152cf5dSBjorn Helgaas }
570d152cf5dSBjorn Helgaas return 0;
5711da177e4SLinus Torvalds }
5721da177e4SLinus Torvalds
pnpacpi_supported_resource(struct acpi_resource * res)573b5f2490bSBjorn Helgaas static int pnpacpi_supported_resource(struct acpi_resource *res)
574b5f2490bSBjorn Helgaas {
575b5f2490bSBjorn Helgaas switch (res->type) {
576b5f2490bSBjorn Helgaas case ACPI_RESOURCE_TYPE_IRQ:
577b5f2490bSBjorn Helgaas case ACPI_RESOURCE_TYPE_DMA:
578b5f2490bSBjorn Helgaas case ACPI_RESOURCE_TYPE_IO:
579b5f2490bSBjorn Helgaas case ACPI_RESOURCE_TYPE_FIXED_IO:
580b5f2490bSBjorn Helgaas case ACPI_RESOURCE_TYPE_MEMORY24:
581b5f2490bSBjorn Helgaas case ACPI_RESOURCE_TYPE_MEMORY32:
582b5f2490bSBjorn Helgaas case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
583b5f2490bSBjorn Helgaas case ACPI_RESOURCE_TYPE_ADDRESS16:
584b5f2490bSBjorn Helgaas case ACPI_RESOURCE_TYPE_ADDRESS32:
585b5f2490bSBjorn Helgaas case ACPI_RESOURCE_TYPE_ADDRESS64:
5868cb24c8fSBjorn Helgaas case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
587b5f2490bSBjorn Helgaas case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
588b5f2490bSBjorn Helgaas return 1;
589b5f2490bSBjorn Helgaas }
590b5f2490bSBjorn Helgaas return 0;
591b5f2490bSBjorn Helgaas }
592b5f2490bSBjorn Helgaas
5931da177e4SLinus Torvalds /*
5941da177e4SLinus Torvalds * Set resource
5951da177e4SLinus Torvalds */
pnpacpi_count_resources(struct acpi_resource * res,void * data)5961da177e4SLinus Torvalds static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
5971da177e4SLinus Torvalds void *data)
5981da177e4SLinus Torvalds {
5994721a4ccSBjorn Helgaas int *res_cnt = data;
600b5f2490bSBjorn Helgaas
601b5f2490bSBjorn Helgaas if (pnpacpi_supported_resource(res))
6021da177e4SLinus Torvalds (*res_cnt)++;
6031da177e4SLinus Torvalds return AE_OK;
6041da177e4SLinus Torvalds }
6051da177e4SLinus Torvalds
pnpacpi_type_resources(struct acpi_resource * res,void * data)6061c6e7d0aSBjorn Helgaas static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data)
6071da177e4SLinus Torvalds {
6084721a4ccSBjorn Helgaas struct acpi_resource **resource = data;
609b5f2490bSBjorn Helgaas
610b5f2490bSBjorn Helgaas if (pnpacpi_supported_resource(res)) {
611eca008c8SLen Brown (*resource)->type = res->type;
612b5f2490bSBjorn Helgaas (*resource)->length = sizeof(struct acpi_resource);
61336d872a3SBjorn Helgaas if (res->type == ACPI_RESOURCE_TYPE_IRQ)
61436d872a3SBjorn Helgaas (*resource)->data.irq.descriptor_length =
61536d872a3SBjorn Helgaas res->data.irq.descriptor_length;
6161da177e4SLinus Torvalds (*resource)++;
6171da177e4SLinus Torvalds }
6181da177e4SLinus Torvalds
6191da177e4SLinus Torvalds return AE_OK;
6201da177e4SLinus Torvalds }
6211da177e4SLinus Torvalds
pnpacpi_build_resource_template(struct pnp_dev * dev,struct acpi_buffer * buffer)622cdef6254SBjorn Helgaas int pnpacpi_build_resource_template(struct pnp_dev *dev,
6231da177e4SLinus Torvalds struct acpi_buffer *buffer)
6241da177e4SLinus Torvalds {
625c4da6940SBjorn Helgaas struct acpi_device *acpi_dev = dev->data;
626c4da6940SBjorn Helgaas acpi_handle handle = acpi_dev->handle;
6271da177e4SLinus Torvalds struct acpi_resource *resource;
6281da177e4SLinus Torvalds int res_cnt = 0;
6291da177e4SLinus Torvalds acpi_status status;
6301da177e4SLinus Torvalds
6311da177e4SLinus Torvalds status = acpi_walk_resources(handle, METHOD_NAME__CRS,
6321da177e4SLinus Torvalds pnpacpi_count_resources, &res_cnt);
6331da177e4SLinus Torvalds if (ACPI_FAILURE(status)) {
634d152cf5dSBjorn Helgaas dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
6351da177e4SLinus Torvalds return -EINVAL;
6361da177e4SLinus Torvalds }
6371da177e4SLinus Torvalds if (!res_cnt)
6381da177e4SLinus Torvalds return -EINVAL;
6391da177e4SLinus Torvalds buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
640cd861280SRobert P. J. Day buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL);
6411da177e4SLinus Torvalds if (!buffer->pointer)
6421da177e4SLinus Torvalds return -ENOMEM;
64372dcc883SBjorn Helgaas
6441da177e4SLinus Torvalds resource = (struct acpi_resource *)buffer->pointer;
6451da177e4SLinus Torvalds status = acpi_walk_resources(handle, METHOD_NAME__CRS,
6461da177e4SLinus Torvalds pnpacpi_type_resources, &resource);
6471da177e4SLinus Torvalds if (ACPI_FAILURE(status)) {
6481da177e4SLinus Torvalds kfree(buffer->pointer);
649d152cf5dSBjorn Helgaas dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
6501da177e4SLinus Torvalds return -EINVAL;
6511da177e4SLinus Torvalds }
6521da177e4SLinus Torvalds /* resource will pointer the end resource now */
65350eca3ebSBob Moore resource->type = ACPI_RESOURCE_TYPE_END_TAG;
654f084dbb9SYinghai Lu resource->length = sizeof(struct acpi_resource);
6551da177e4SLinus Torvalds
6561da177e4SLinus Torvalds return 0;
6571da177e4SLinus Torvalds }
6581da177e4SLinus Torvalds
pnpacpi_encode_irq(struct pnp_dev * dev,struct acpi_resource * resource,struct resource * p)65972dcc883SBjorn Helgaas static void pnpacpi_encode_irq(struct pnp_dev *dev,
66072dcc883SBjorn Helgaas struct acpi_resource *resource,
6611da177e4SLinus Torvalds struct resource *p)
6621da177e4SLinus Torvalds {
6639570a20eSBjorn Helgaas struct acpi_resource_irq *irq = &resource->data.irq;
664bbee06d0SFabian Frederick u8 triggering, polarity, shareable;
6651da177e4SLinus Torvalds
666aee3ad81SBjorn Helgaas if (!pnp_resource_enabled(p)) {
667aee3ad81SBjorn Helgaas irq->interrupt_count = 0;
6682f53432cSBjorn Helgaas pnp_dbg(&dev->dev, " encode irq (%s)\n",
669aee3ad81SBjorn Helgaas p ? "disabled" : "missing");
670aee3ad81SBjorn Helgaas return;
671aee3ad81SBjorn Helgaas }
672aee3ad81SBjorn Helgaas
673a993273bSBjorn Helgaas decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
6749570a20eSBjorn Helgaas irq->triggering = triggering;
6759570a20eSBjorn Helgaas irq->polarity = polarity;
676c163f90cSErik Schmauss irq->shareable = shareable;
6779570a20eSBjorn Helgaas irq->interrupt_count = 1;
6789570a20eSBjorn Helgaas irq->interrupts[0] = p->start;
67972dcc883SBjorn Helgaas
6802f53432cSBjorn Helgaas pnp_dbg(&dev->dev, " encode irq %d %s %s %s (%d-byte descriptor)\n",
68136d872a3SBjorn Helgaas (int) p->start,
68272dcc883SBjorn Helgaas triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
68372dcc883SBjorn Helgaas polarity == ACPI_ACTIVE_LOW ? "low" : "high",
684c163f90cSErik Schmauss irq->shareable == ACPI_SHARED ? "shared" : "exclusive",
68536d872a3SBjorn Helgaas irq->descriptor_length);
6861da177e4SLinus Torvalds }
6871da177e4SLinus Torvalds
pnpacpi_encode_ext_irq(struct pnp_dev * dev,struct acpi_resource * resource,struct resource * p)68872dcc883SBjorn Helgaas static void pnpacpi_encode_ext_irq(struct pnp_dev *dev,
68972dcc883SBjorn Helgaas struct acpi_resource *resource,
6901da177e4SLinus Torvalds struct resource *p)
6911da177e4SLinus Torvalds {
6929570a20eSBjorn Helgaas struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq;
693bbee06d0SFabian Frederick u8 triggering, polarity, shareable;
6941da177e4SLinus Torvalds
695aee3ad81SBjorn Helgaas if (!pnp_resource_enabled(p)) {
696aee3ad81SBjorn Helgaas extended_irq->interrupt_count = 0;
6972f53432cSBjorn Helgaas pnp_dbg(&dev->dev, " encode extended irq (%s)\n",
698aee3ad81SBjorn Helgaas p ? "disabled" : "missing");
699aee3ad81SBjorn Helgaas return;
700aee3ad81SBjorn Helgaas }
701aee3ad81SBjorn Helgaas
702a993273bSBjorn Helgaas decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
7039570a20eSBjorn Helgaas extended_irq->producer_consumer = ACPI_CONSUMER;
7049570a20eSBjorn Helgaas extended_irq->triggering = triggering;
7059570a20eSBjorn Helgaas extended_irq->polarity = polarity;
706c163f90cSErik Schmauss extended_irq->shareable = shareable;
7079570a20eSBjorn Helgaas extended_irq->interrupt_count = 1;
7089570a20eSBjorn Helgaas extended_irq->interrupts[0] = p->start;
70972dcc883SBjorn Helgaas
7102f53432cSBjorn Helgaas pnp_dbg(&dev->dev, " encode irq %d %s %s %s\n", (int) p->start,
71172dcc883SBjorn Helgaas triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
71272dcc883SBjorn Helgaas polarity == ACPI_ACTIVE_LOW ? "low" : "high",
713c163f90cSErik Schmauss extended_irq->shareable == ACPI_SHARED ? "shared" : "exclusive");
7141da177e4SLinus Torvalds }
7151da177e4SLinus Torvalds
pnpacpi_encode_dma(struct pnp_dev * dev,struct acpi_resource * resource,struct resource * p)71672dcc883SBjorn Helgaas static void pnpacpi_encode_dma(struct pnp_dev *dev,
71772dcc883SBjorn Helgaas struct acpi_resource *resource,
7181da177e4SLinus Torvalds struct resource *p)
7191da177e4SLinus Torvalds {
7209570a20eSBjorn Helgaas struct acpi_resource_dma *dma = &resource->data.dma;
7219570a20eSBjorn Helgaas
722aee3ad81SBjorn Helgaas if (!pnp_resource_enabled(p)) {
723aee3ad81SBjorn Helgaas dma->channel_count = 0;
7242f53432cSBjorn Helgaas pnp_dbg(&dev->dev, " encode dma (%s)\n",
725aee3ad81SBjorn Helgaas p ? "disabled" : "missing");
726aee3ad81SBjorn Helgaas return;
727aee3ad81SBjorn Helgaas }
728aee3ad81SBjorn Helgaas
7291da177e4SLinus Torvalds /* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
730ccc4c7bbSVojtech Pavlik switch (p->flags & IORESOURCE_DMA_SPEED_MASK) {
731ccc4c7bbSVojtech Pavlik case IORESOURCE_DMA_TYPEA:
7329570a20eSBjorn Helgaas dma->type = ACPI_TYPE_A;
733ccc4c7bbSVojtech Pavlik break;
734ccc4c7bbSVojtech Pavlik case IORESOURCE_DMA_TYPEB:
7359570a20eSBjorn Helgaas dma->type = ACPI_TYPE_B;
736ccc4c7bbSVojtech Pavlik break;
737ccc4c7bbSVojtech Pavlik case IORESOURCE_DMA_TYPEF:
7389570a20eSBjorn Helgaas dma->type = ACPI_TYPE_F;
739ccc4c7bbSVojtech Pavlik break;
740ccc4c7bbSVojtech Pavlik default:
7419570a20eSBjorn Helgaas dma->type = ACPI_COMPATIBILITY;
742ccc4c7bbSVojtech Pavlik }
743ccc4c7bbSVojtech Pavlik
744ccc4c7bbSVojtech Pavlik switch (p->flags & IORESOURCE_DMA_TYPE_MASK) {
745ccc4c7bbSVojtech Pavlik case IORESOURCE_DMA_8BIT:
7469570a20eSBjorn Helgaas dma->transfer = ACPI_TRANSFER_8;
747ccc4c7bbSVojtech Pavlik break;
748ccc4c7bbSVojtech Pavlik case IORESOURCE_DMA_8AND16BIT:
7499570a20eSBjorn Helgaas dma->transfer = ACPI_TRANSFER_8_16;
750ccc4c7bbSVojtech Pavlik break;
751ccc4c7bbSVojtech Pavlik default:
7529570a20eSBjorn Helgaas dma->transfer = ACPI_TRANSFER_16;
753ccc4c7bbSVojtech Pavlik }
754ccc4c7bbSVojtech Pavlik
7559570a20eSBjorn Helgaas dma->bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
7569570a20eSBjorn Helgaas dma->channel_count = 1;
7579570a20eSBjorn Helgaas dma->channels[0] = p->start;
75872dcc883SBjorn Helgaas
7592f53432cSBjorn Helgaas pnp_dbg(&dev->dev, " encode dma %d "
76072dcc883SBjorn Helgaas "type %#x transfer %#x master %d\n",
76172dcc883SBjorn Helgaas (int) p->start, dma->type, dma->transfer, dma->bus_master);
7621da177e4SLinus Torvalds }
7631da177e4SLinus Torvalds
pnpacpi_encode_io(struct pnp_dev * dev,struct acpi_resource * resource,struct resource * p)76472dcc883SBjorn Helgaas static void pnpacpi_encode_io(struct pnp_dev *dev,
76572dcc883SBjorn Helgaas struct acpi_resource *resource,
7661da177e4SLinus Torvalds struct resource *p)
7671da177e4SLinus Torvalds {
7689570a20eSBjorn Helgaas struct acpi_resource_io *io = &resource->data.io;
7699570a20eSBjorn Helgaas
770aee3ad81SBjorn Helgaas if (pnp_resource_enabled(p)) {
771aee3ad81SBjorn Helgaas /* Note: pnp_assign_port copies pnp_port->flags into p->flags */
77208c9f262SBjorn Helgaas io->io_decode = (p->flags & IORESOURCE_IO_16BIT_ADDR) ?
7731da177e4SLinus Torvalds ACPI_DECODE_16 : ACPI_DECODE_10;
7749570a20eSBjorn Helgaas io->minimum = p->start;
7759570a20eSBjorn Helgaas io->maximum = p->end;
7769570a20eSBjorn Helgaas io->alignment = 0; /* Correct? */
77728f65c11SJoe Perches io->address_length = resource_size(p);
778aee3ad81SBjorn Helgaas } else {
779aee3ad81SBjorn Helgaas io->minimum = 0;
780aee3ad81SBjorn Helgaas io->address_length = 0;
781aee3ad81SBjorn Helgaas }
78272dcc883SBjorn Helgaas
7832f53432cSBjorn Helgaas pnp_dbg(&dev->dev, " encode io %#x-%#x decode %#x\n", io->minimum,
784aee3ad81SBjorn Helgaas io->minimum + io->address_length - 1, io->io_decode);
7851da177e4SLinus Torvalds }
7861da177e4SLinus Torvalds
pnpacpi_encode_fixed_io(struct pnp_dev * dev,struct acpi_resource * resource,struct resource * p)78772dcc883SBjorn Helgaas static void pnpacpi_encode_fixed_io(struct pnp_dev *dev,
78872dcc883SBjorn Helgaas struct acpi_resource *resource,
7891da177e4SLinus Torvalds struct resource *p)
7901da177e4SLinus Torvalds {
7919570a20eSBjorn Helgaas struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io;
7929570a20eSBjorn Helgaas
793aee3ad81SBjorn Helgaas if (pnp_resource_enabled(p)) {
7949570a20eSBjorn Helgaas fixed_io->address = p->start;
79528f65c11SJoe Perches fixed_io->address_length = resource_size(p);
796aee3ad81SBjorn Helgaas } else {
797aee3ad81SBjorn Helgaas fixed_io->address = 0;
798aee3ad81SBjorn Helgaas fixed_io->address_length = 0;
799aee3ad81SBjorn Helgaas }
80072dcc883SBjorn Helgaas
8012f53432cSBjorn Helgaas pnp_dbg(&dev->dev, " encode fixed_io %#x-%#x\n", fixed_io->address,
802aee3ad81SBjorn Helgaas fixed_io->address + fixed_io->address_length - 1);
8031da177e4SLinus Torvalds }
8041da177e4SLinus Torvalds
pnpacpi_encode_mem24(struct pnp_dev * dev,struct acpi_resource * resource,struct resource * p)80572dcc883SBjorn Helgaas static void pnpacpi_encode_mem24(struct pnp_dev *dev,
80672dcc883SBjorn Helgaas struct acpi_resource *resource,
8071da177e4SLinus Torvalds struct resource *p)
8081da177e4SLinus Torvalds {
8099570a20eSBjorn Helgaas struct acpi_resource_memory24 *memory24 = &resource->data.memory24;
8109570a20eSBjorn Helgaas
811aee3ad81SBjorn Helgaas if (pnp_resource_enabled(p)) {
812aee3ad81SBjorn Helgaas /* Note: pnp_assign_mem copies pnp_mem->flags into p->flags */
813aee3ad81SBjorn Helgaas memory24->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ?
8141da177e4SLinus Torvalds ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
8159570a20eSBjorn Helgaas memory24->minimum = p->start;
8169570a20eSBjorn Helgaas memory24->maximum = p->end;
8179570a20eSBjorn Helgaas memory24->alignment = 0;
81828f65c11SJoe Perches memory24->address_length = resource_size(p);
819aee3ad81SBjorn Helgaas } else {
820aee3ad81SBjorn Helgaas memory24->minimum = 0;
821aee3ad81SBjorn Helgaas memory24->address_length = 0;
822aee3ad81SBjorn Helgaas }
82372dcc883SBjorn Helgaas
8242f53432cSBjorn Helgaas pnp_dbg(&dev->dev, " encode mem24 %#x-%#x write_protect %#x\n",
825aee3ad81SBjorn Helgaas memory24->minimum,
826aee3ad81SBjorn Helgaas memory24->minimum + memory24->address_length - 1,
82772dcc883SBjorn Helgaas memory24->write_protect);
8281da177e4SLinus Torvalds }
8291da177e4SLinus Torvalds
pnpacpi_encode_mem32(struct pnp_dev * dev,struct acpi_resource * resource,struct resource * p)83072dcc883SBjorn Helgaas static void pnpacpi_encode_mem32(struct pnp_dev *dev,
83172dcc883SBjorn Helgaas struct acpi_resource *resource,
8321da177e4SLinus Torvalds struct resource *p)
8331da177e4SLinus Torvalds {
8349570a20eSBjorn Helgaas struct acpi_resource_memory32 *memory32 = &resource->data.memory32;
8359570a20eSBjorn Helgaas
836aee3ad81SBjorn Helgaas if (pnp_resource_enabled(p)) {
837aee3ad81SBjorn Helgaas memory32->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ?
8381da177e4SLinus Torvalds ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
8399570a20eSBjorn Helgaas memory32->minimum = p->start;
8409570a20eSBjorn Helgaas memory32->maximum = p->end;
8419570a20eSBjorn Helgaas memory32->alignment = 0;
84228f65c11SJoe Perches memory32->address_length = resource_size(p);
843aee3ad81SBjorn Helgaas } else {
844aee3ad81SBjorn Helgaas memory32->minimum = 0;
845aee3ad81SBjorn Helgaas memory32->alignment = 0;
846aee3ad81SBjorn Helgaas }
84772dcc883SBjorn Helgaas
8482f53432cSBjorn Helgaas pnp_dbg(&dev->dev, " encode mem32 %#x-%#x write_protect %#x\n",
849aee3ad81SBjorn Helgaas memory32->minimum,
850aee3ad81SBjorn Helgaas memory32->minimum + memory32->address_length - 1,
85172dcc883SBjorn Helgaas memory32->write_protect);
8521da177e4SLinus Torvalds }
8531da177e4SLinus Torvalds
pnpacpi_encode_fixed_mem32(struct pnp_dev * dev,struct acpi_resource * resource,struct resource * p)85472dcc883SBjorn Helgaas static void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev,
85572dcc883SBjorn Helgaas struct acpi_resource *resource,
8561da177e4SLinus Torvalds struct resource *p)
8571da177e4SLinus Torvalds {
8589570a20eSBjorn Helgaas struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32;
8599570a20eSBjorn Helgaas
860aee3ad81SBjorn Helgaas if (pnp_resource_enabled(p)) {
8619570a20eSBjorn Helgaas fixed_memory32->write_protect =
862aee3ad81SBjorn Helgaas p->flags & IORESOURCE_MEM_WRITEABLE ?
8631da177e4SLinus Torvalds ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
8649570a20eSBjorn Helgaas fixed_memory32->address = p->start;
86528f65c11SJoe Perches fixed_memory32->address_length = resource_size(p);
866aee3ad81SBjorn Helgaas } else {
867aee3ad81SBjorn Helgaas fixed_memory32->address = 0;
868aee3ad81SBjorn Helgaas fixed_memory32->address_length = 0;
869aee3ad81SBjorn Helgaas }
87072dcc883SBjorn Helgaas
8712f53432cSBjorn Helgaas pnp_dbg(&dev->dev, " encode fixed_mem32 %#x-%#x write_protect %#x\n",
872aee3ad81SBjorn Helgaas fixed_memory32->address,
873aee3ad81SBjorn Helgaas fixed_memory32->address + fixed_memory32->address_length - 1,
87472dcc883SBjorn Helgaas fixed_memory32->write_protect);
8751da177e4SLinus Torvalds }
8761da177e4SLinus Torvalds
pnpacpi_encode_resources(struct pnp_dev * dev,struct acpi_buffer * buffer)8774ab55d8dSBjorn Helgaas int pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer)
8781da177e4SLinus Torvalds {
8791da177e4SLinus Torvalds int i = 0;
8801da177e4SLinus Torvalds /* pnpacpi_build_resource_template allocates extra mem */
8811da177e4SLinus Torvalds int res_cnt = (buffer->length - 1) / sizeof(struct acpi_resource) - 1;
8824721a4ccSBjorn Helgaas struct acpi_resource *resource = buffer->pointer;
883fac69a2bSFabian Frederick unsigned int port = 0, irq = 0, dma = 0, mem = 0;
8841da177e4SLinus Torvalds
8852f53432cSBjorn Helgaas pnp_dbg(&dev->dev, "encode %d resources\n", res_cnt);
8861da177e4SLinus Torvalds while (i < res_cnt) {
887eca008c8SLen Brown switch (resource->type) {
88850eca3ebSBob Moore case ACPI_RESOURCE_TYPE_IRQ:
88972dcc883SBjorn Helgaas pnpacpi_encode_irq(dev, resource,
8907e2cf31fSBjorn Helgaas pnp_get_resource(dev, IORESOURCE_IRQ, irq));
8911da177e4SLinus Torvalds irq++;
8921da177e4SLinus Torvalds break;
8931da177e4SLinus Torvalds
89450eca3ebSBob Moore case ACPI_RESOURCE_TYPE_DMA:
89572dcc883SBjorn Helgaas pnpacpi_encode_dma(dev, resource,
8967e2cf31fSBjorn Helgaas pnp_get_resource(dev, IORESOURCE_DMA, dma));
8971da177e4SLinus Torvalds dma++;
8981da177e4SLinus Torvalds break;
89950eca3ebSBob Moore case ACPI_RESOURCE_TYPE_IO:
90072dcc883SBjorn Helgaas pnpacpi_encode_io(dev, resource,
9017e2cf31fSBjorn Helgaas pnp_get_resource(dev, IORESOURCE_IO, port));
9021da177e4SLinus Torvalds port++;
9031da177e4SLinus Torvalds break;
90450eca3ebSBob Moore case ACPI_RESOURCE_TYPE_FIXED_IO:
90572dcc883SBjorn Helgaas pnpacpi_encode_fixed_io(dev, resource,
9067e2cf31fSBjorn Helgaas pnp_get_resource(dev, IORESOURCE_IO, port));
9071da177e4SLinus Torvalds port++;
9081da177e4SLinus Torvalds break;
90950eca3ebSBob Moore case ACPI_RESOURCE_TYPE_MEMORY24:
91072dcc883SBjorn Helgaas pnpacpi_encode_mem24(dev, resource,
9117e2cf31fSBjorn Helgaas pnp_get_resource(dev, IORESOURCE_MEM, mem));
9121da177e4SLinus Torvalds mem++;
9131da177e4SLinus Torvalds break;
91450eca3ebSBob Moore case ACPI_RESOURCE_TYPE_MEMORY32:
91572dcc883SBjorn Helgaas pnpacpi_encode_mem32(dev, resource,
9167e2cf31fSBjorn Helgaas pnp_get_resource(dev, IORESOURCE_MEM, mem));
9171da177e4SLinus Torvalds mem++;
9181da177e4SLinus Torvalds break;
91950eca3ebSBob Moore case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
92072dcc883SBjorn Helgaas pnpacpi_encode_fixed_mem32(dev, resource,
9217e2cf31fSBjorn Helgaas pnp_get_resource(dev, IORESOURCE_MEM, mem));
9221da177e4SLinus Torvalds mem++;
9231da177e4SLinus Torvalds break;
9240af5853bSLen Brown case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
92572dcc883SBjorn Helgaas pnpacpi_encode_ext_irq(dev, resource,
9267e2cf31fSBjorn Helgaas pnp_get_resource(dev, IORESOURCE_IRQ, irq));
9270af5853bSLen Brown irq++;
9280af5853bSLen Brown break;
9290af5853bSLen Brown case ACPI_RESOURCE_TYPE_START_DEPENDENT:
9300af5853bSLen Brown case ACPI_RESOURCE_TYPE_END_DEPENDENT:
9310af5853bSLen Brown case ACPI_RESOURCE_TYPE_VENDOR:
9320af5853bSLen Brown case ACPI_RESOURCE_TYPE_END_TAG:
9330af5853bSLen Brown case ACPI_RESOURCE_TYPE_ADDRESS16:
9340af5853bSLen Brown case ACPI_RESOURCE_TYPE_ADDRESS32:
9350af5853bSLen Brown case ACPI_RESOURCE_TYPE_ADDRESS64:
9360af5853bSLen Brown case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
9370af5853bSLen Brown case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
9381da177e4SLinus Torvalds default: /* other type */
9391d7f2cddSAndy Shevchenko dev_warn(&dev->dev,
9401d7f2cddSAndy Shevchenko "can't encode unknown resource type %d\n",
9411d7f2cddSAndy Shevchenko resource->type);
9421da177e4SLinus Torvalds return -EINVAL;
9431da177e4SLinus Torvalds }
9441da177e4SLinus Torvalds resource++;
9451da177e4SLinus Torvalds i++;
9461da177e4SLinus Torvalds }
9471da177e4SLinus Torvalds return 0;
9481da177e4SLinus Torvalds }
949