aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-11-14 18:30:01 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-11-14 18:30:01 -0500
commit046d9ce6820e99087e81511284045eada94950e8 (patch)
treeee711962f10007ca4f439aedbe8986ac531a4988
parentb4b6cae2f36d92b31788f10816709d5290a1119a (diff)
ACPI: Move device resources interpretation code from PNP to ACPI core
Move some code used for parsing ACPI device resources from the PNP subsystem to the ACPI core, so that other bus types (platform, SPI, I2C) can use the same routines for parsing resources in a consistent way, without duplicating code. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/resource.c393
-rw-r--r--drivers/pnp/base.h2
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c296
-rw-r--r--drivers/pnp/resource.c16
-rw-r--r--include/linux/acpi.h10
6 files changed, 454 insertions, 264 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 227c82bbe9a1..3223edfb23b6 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -32,6 +32,7 @@ acpi-$(CONFIG_ACPI_SLEEP) += proc.o
32# 32#
33acpi-y += bus.o glue.o 33acpi-y += bus.o glue.o
34acpi-y += scan.o 34acpi-y += scan.o
35acpi-y += resource.o
35acpi-y += processor_core.o 36acpi-y += processor_core.o
36acpi-y += ec.o 37acpi-y += ec.o
37acpi-$(CONFIG_ACPI_DOCK) += dock.o 38acpi-$(CONFIG_ACPI_DOCK) += dock.o
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
new file mode 100644
index 000000000000..3e7fd349e29d
--- /dev/null
+++ b/drivers/acpi/resource.c
@@ -0,0 +1,393 @@
1/*
2 * drivers/acpi/resource.c - ACPI device resources interpretation.
3 *
4 * Copyright (C) 2012, Intel Corp.
5 * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
6 *
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as published
11 * by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 *
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 */
24
25#include <linux/acpi.h>
26#include <linux/device.h>
27#include <linux/export.h>
28#include <linux/ioport.h>
29
30#ifdef CONFIG_X86
31#define valid_IRQ(i) (((i) != 0) && ((i) != 2))
32#else
33#define valid_IRQ(i) (true)
34#endif
35
36static unsigned long acpi_dev_memresource_flags(u64 len, u8 write_protect,
37 bool window)
38{
39 unsigned long flags = IORESOURCE_MEM;
40
41 if (len == 0)
42 flags |= IORESOURCE_DISABLED;
43
44 if (write_protect == ACPI_READ_WRITE_MEMORY)
45 flags |= IORESOURCE_MEM_WRITEABLE;
46
47 if (window)
48 flags |= IORESOURCE_WINDOW;
49
50 return flags;
51}
52
53static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len,
54 u8 write_protect)
55{
56 res->start = start;
57 res->end = start + len - 1;
58 res->flags = acpi_dev_memresource_flags(len, write_protect, false);
59}
60
61/**
62 * acpi_dev_resource_memory - Extract ACPI memory resource information.
63 * @ares: Input ACPI resource object.
64 * @res: Output generic resource object.
65 *
66 * Check if the given ACPI resource object represents a memory resource and
67 * if that's the case, use the information in it to populate the generic
68 * resource object pointed to by @res.
69 */
70bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
71{
72 struct acpi_resource_memory24 *memory24;
73 struct acpi_resource_memory32 *memory32;
74 struct acpi_resource_fixed_memory32 *fixed_memory32;
75
76 switch (ares->type) {
77 case ACPI_RESOURCE_TYPE_MEMORY24:
78 memory24 = &ares->data.memory24;
79 acpi_dev_get_memresource(res, memory24->minimum,
80 memory24->address_length,
81 memory24->write_protect);
82 break;
83 case ACPI_RESOURCE_TYPE_MEMORY32:
84 memory32 = &ares->data.memory32;
85 acpi_dev_get_memresource(res, memory32->minimum,
86 memory32->address_length,
87 memory32->write_protect);
88 break;
89 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
90 fixed_memory32 = &ares->data.fixed_memory32;
91 acpi_dev_get_memresource(res, fixed_memory32->address,
92 fixed_memory32->address_length,
93 fixed_memory32->write_protect);
94 break;
95 default:
96 return false;
97 }
98 return true;
99}
100EXPORT_SYMBOL_GPL(acpi_dev_resource_memory);
101
102static unsigned int acpi_dev_ioresource_flags(u64 start, u64 end, u8 io_decode,
103 bool window)
104{
105 int flags = IORESOURCE_IO;
106
107 if (io_decode == ACPI_DECODE_16)
108 flags |= IORESOURCE_IO_16BIT_ADDR;
109
110 if (start > end || end >= 0x10003)
111 flags |= IORESOURCE_DISABLED;
112
113 if (window)
114 flags |= IORESOURCE_WINDOW;
115
116 return flags;
117}
118
119static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len,
120 u8 io_decode)
121{
122 u64 end = start + len - 1;
123
124 res->start = start;
125 res->end = end;
126 res->flags = acpi_dev_ioresource_flags(start, end, io_decode, false);
127}
128
129/**
130 * acpi_dev_resource_io - Extract ACPI I/O resource information.
131 * @ares: Input ACPI resource object.
132 * @res: Output generic resource object.
133 *
134 * Check if the given ACPI resource object represents an I/O resource and
135 * if that's the case, use the information in it to populate the generic
136 * resource object pointed to by @res.
137 */
138bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res)
139{
140 struct acpi_resource_io *io;
141 struct acpi_resource_fixed_io *fixed_io;
142
143 switch (ares->type) {
144 case ACPI_RESOURCE_TYPE_IO:
145 io = &ares->data.io;
146 acpi_dev_get_ioresource(res, io->minimum,
147 io->address_length,
148 io->io_decode);
149 break;
150 case ACPI_RESOURCE_TYPE_FIXED_IO:
151 fixed_io = &ares->data.fixed_io;
152 acpi_dev_get_ioresource(res, fixed_io->address,
153 fixed_io->address_length,
154 ACPI_DECODE_10);
155 break;
156 default:
157 return false;
158 }
159 return true;
160}
161EXPORT_SYMBOL_GPL(acpi_dev_resource_io);
162
163/**
164 * acpi_dev_resource_address_space - Extract ACPI address space information.
165 * @ares: Input ACPI resource object.
166 * @res: Output generic resource object.
167 *
168 * Check if the given ACPI resource object represents an address space resource
169 * and if that's the case, use the information in it to populate the generic
170 * resource object pointed to by @res.
171 */
172bool acpi_dev_resource_address_space(struct acpi_resource *ares,
173 struct resource *res)
174{
175 acpi_status status;
176 struct acpi_resource_address64 addr;
177 bool window;
178 u64 len;
179 u8 io_decode;
180
181 switch (ares->type) {
182 case ACPI_RESOURCE_TYPE_ADDRESS16:
183 case ACPI_RESOURCE_TYPE_ADDRESS32:
184 case ACPI_RESOURCE_TYPE_ADDRESS64:
185 break;
186 default:
187 return false;
188 }
189
190 status = acpi_resource_to_address64(ares, &addr);
191 if (ACPI_FAILURE(status))
192 return true;
193
194 res->start = addr.minimum;
195 res->end = addr.maximum;
196 window = addr.producer_consumer == ACPI_PRODUCER;
197
198 switch(addr.resource_type) {
199 case ACPI_MEMORY_RANGE:
200 len = addr.maximum - addr.minimum + 1;
201 res->flags = acpi_dev_memresource_flags(len,
202 addr.info.mem.write_protect,
203 window);
204 break;
205 case ACPI_IO_RANGE:
206 io_decode = addr.granularity == 0xfff ?
207 ACPI_DECODE_10 : ACPI_DECODE_16;
208 res->flags = acpi_dev_ioresource_flags(addr.minimum,
209 addr.maximum,
210 io_decode, window);
211 break;
212 case ACPI_BUS_NUMBER_RANGE:
213 res->flags = IORESOURCE_BUS;
214 break;
215 default:
216 res->flags = 0;
217 }
218
219 return true;
220}
221EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space);
222
223/**
224 * acpi_dev_resource_ext_address_space - Extract ACPI address space information.
225 * @ares: Input ACPI resource object.
226 * @res: Output generic resource object.
227 *
228 * Check if the given ACPI resource object represents an extended address space
229 * resource and if that's the case, use the information in it to populate the
230 * generic resource object pointed to by @res.
231 */
232bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares,
233 struct resource *res)
234{
235 struct acpi_resource_extended_address64 *ext_addr;
236 bool window;
237 u64 len;
238 u8 io_decode;
239
240 if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64)
241 return false;
242
243 ext_addr = &ares->data.ext_address64;
244
245 res->start = ext_addr->minimum;
246 res->end = ext_addr->maximum;
247 window = ext_addr->producer_consumer == ACPI_PRODUCER;
248
249 switch(ext_addr->resource_type) {
250 case ACPI_MEMORY_RANGE:
251 len = ext_addr->maximum - ext_addr->minimum + 1;
252 res->flags = acpi_dev_memresource_flags(len,
253 ext_addr->info.mem.write_protect,
254 window);
255 break;
256 case ACPI_IO_RANGE:
257 io_decode = ext_addr->granularity == 0xfff ?
258 ACPI_DECODE_10 : ACPI_DECODE_16;
259 res->flags = acpi_dev_ioresource_flags(ext_addr->minimum,
260 ext_addr->maximum,
261 io_decode, window);
262 break;
263 case ACPI_BUS_NUMBER_RANGE:
264 res->flags = IORESOURCE_BUS;
265 break;
266 default:
267 res->flags = 0;
268 }
269
270 return true;
271}
272EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space);
273
274/**
275 * acpi_dev_irq_flags - Determine IRQ resource flags.
276 * @triggering: Triggering type as provided by ACPI.
277 * @polarity: Interrupt polarity as provided by ACPI.
278 * @shareable: Whether or not the interrupt is shareable.
279 */
280unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable)
281{
282 unsigned long flags;
283
284 if (triggering == ACPI_LEVEL_SENSITIVE)
285 flags = polarity == ACPI_ACTIVE_LOW ?
286 IORESOURCE_IRQ_LOWLEVEL : IORESOURCE_IRQ_HIGHLEVEL;
287 else
288 flags = polarity == ACPI_ACTIVE_LOW ?
289 IORESOURCE_IRQ_LOWEDGE : IORESOURCE_IRQ_HIGHEDGE;
290
291 if (shareable == ACPI_SHARED)
292 flags |= IORESOURCE_IRQ_SHAREABLE;
293
294 return flags | IORESOURCE_IRQ;
295}
296EXPORT_SYMBOL_GPL(acpi_dev_irq_flags);
297
298static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi)
299{
300 res->start = gsi;
301 res->end = gsi;
302 res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED;
303}
304
305static void acpi_dev_get_irqresource(struct resource *res, u32 gsi,
306 u8 triggering, u8 polarity, u8 shareable)
307{
308 int irq, p, t;
309
310 if (!valid_IRQ(gsi)) {
311 acpi_dev_irqresource_disabled(res, gsi);
312 return;
313 }
314
315 /*
316 * In IO-APIC mode, use overrided attribute. Two reasons:
317 * 1. BIOS bug in DSDT
318 * 2. BIOS uses IO-APIC mode Interrupt Source Override
319 */
320 if (!acpi_get_override_irq(gsi, &t, &p)) {
321 u8 trig = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
322 u8 pol = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
323
324 if (triggering != trig || polarity != pol) {
325 pr_warning("ACPI: IRQ %d override to %s, %s\n", gsi,
326 t ? "edge" : "level", p ? "low" : "high");
327 triggering = trig;
328 polarity = pol;
329 }
330 }
331
332 res->flags = acpi_dev_irq_flags(triggering, polarity, shareable);
333 irq = acpi_register_gsi(NULL, gsi, triggering, polarity);
334 if (irq >= 0) {
335 res->start = irq;
336 res->end = irq;
337 } else {
338 acpi_dev_irqresource_disabled(res, gsi);
339 }
340}
341
342/**
343 * acpi_dev_resource_interrupt - Extract ACPI interrupt resource information.
344 * @ares: Input ACPI resource object.
345 * @index: Index into the array of GSIs represented by the resource.
346 * @res: Output generic resource object.
347 *
348 * Check if the given ACPI resource object represents an interrupt resource
349 * and @index does not exceed the resource's interrupt count (true is returned
350 * in that case regardless of the results of the other checks)). If that's the
351 * case, register the GSI corresponding to @index from the array of interrupts
352 * represented by the resource and populate the generic resource object pointed
353 * to by @res accordingly. If the registration of the GSI is not successful,
354 * IORESOURCE_DISABLED will be set it that object's flags.
355 */
356bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
357 struct resource *res)
358{
359 struct acpi_resource_irq *irq;
360 struct acpi_resource_extended_irq *ext_irq;
361
362 switch (ares->type) {
363 case ACPI_RESOURCE_TYPE_IRQ:
364 /*
365 * Per spec, only one interrupt per descriptor is allowed in
366 * _CRS, but some firmware violates this, so parse them all.
367 */
368 irq = &ares->data.irq;
369 if (index >= irq->interrupt_count) {
370 acpi_dev_irqresource_disabled(res, 0);
371 return false;
372 }
373 acpi_dev_get_irqresource(res, irq->interrupts[index],
374 irq->triggering, irq->polarity,
375 irq->sharable);
376 break;
377 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
378 ext_irq = &ares->data.extended_irq;
379 if (index >= ext_irq->interrupt_count) {
380 acpi_dev_irqresource_disabled(res, 0);
381 return false;
382 }
383 acpi_dev_get_irqresource(res, ext_irq->interrupts[index],
384 ext_irq->triggering, ext_irq->polarity,
385 ext_irq->sharable);
386 break;
387 default:
388 return false;
389 }
390
391 return true;
392}
393EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt);
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h
index fa4e0a5db3f8..ffd53e3eb92f 100644
--- a/drivers/pnp/base.h
+++ b/drivers/pnp/base.h
@@ -159,6 +159,8 @@ struct pnp_resource {
159 159
160void pnp_free_resource(struct pnp_resource *pnp_res); 160void pnp_free_resource(struct pnp_resource *pnp_res);
161 161
162struct pnp_resource *pnp_add_resource(struct pnp_dev *dev,
163 struct resource *res);
162struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq, 164struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
163 int flags); 165 int flags);
164struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma, 166struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 5be4a392a3ae..b8f4ea7b27fc 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -28,37 +28,6 @@
28#include "../base.h" 28#include "../base.h"
29#include "pnpacpi.h" 29#include "pnpacpi.h"
30 30
31#ifdef CONFIG_IA64
32#define valid_IRQ(i) (1)
33#else
34#define valid_IRQ(i) (((i) != 0) && ((i) != 2))
35#endif
36
37/*
38 * Allocated Resources
39 */
40static int irq_flags(int triggering, int polarity, int shareable)
41{
42 int flags;
43
44 if (triggering == ACPI_LEVEL_SENSITIVE) {
45 if (polarity == ACPI_ACTIVE_LOW)
46 flags = IORESOURCE_IRQ_LOWLEVEL;
47 else
48 flags = IORESOURCE_IRQ_HIGHLEVEL;
49 } else {
50 if (polarity == ACPI_ACTIVE_LOW)
51 flags = IORESOURCE_IRQ_LOWEDGE;
52 else
53 flags = IORESOURCE_IRQ_HIGHEDGE;
54 }
55
56 if (shareable == ACPI_SHARED)
57 flags |= IORESOURCE_IRQ_SHAREABLE;
58
59 return flags;
60}
61
62static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering, 31static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering,
63 int *polarity, int *shareable) 32 int *polarity, int *shareable)
64{ 33{
@@ -94,45 +63,6 @@ static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering,
94 *shareable = ACPI_EXCLUSIVE; 63 *shareable = ACPI_EXCLUSIVE;
95} 64}
96 65
97static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev,
98 u32 gsi, int triggering,
99 int polarity, int shareable)
100{
101 int irq, flags;
102 int p, t;
103
104 if (!valid_IRQ(gsi)) {
105 pnp_add_irq_resource(dev, gsi, IORESOURCE_DISABLED);
106 return;
107 }
108
109 /*
110 * in IO-APIC mode, use overrided attribute. Two reasons:
111 * 1. BIOS bug in DSDT
112 * 2. BIOS uses IO-APIC mode Interrupt Source Override
113 */
114 if (!acpi_get_override_irq(gsi, &t, &p)) {
115 t = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
116 p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
117
118 if (triggering != t || polarity != p) {
119 dev_warn(&dev->dev, "IRQ %d override to %s, %s\n",
120 gsi, t ? "edge":"level", p ? "low":"high");
121 triggering = t;
122 polarity = p;
123 }
124 }
125
126 flags = irq_flags(triggering, polarity, shareable);
127 irq = acpi_register_gsi(&dev->dev, gsi, triggering, polarity);
128 if (irq >= 0)
129 pcibios_penalize_isa_irq(irq, 1);
130 else
131 flags |= IORESOURCE_DISABLED;
132
133 pnp_add_irq_resource(dev, irq, flags);
134}
135
136static int dma_flags(struct pnp_dev *dev, int type, int bus_master, 66static int dma_flags(struct pnp_dev *dev, int type, int bus_master,
137 int transfer) 67 int transfer)
138{ 68{
@@ -177,21 +107,16 @@ static int dma_flags(struct pnp_dev *dev, int type, int bus_master,
177 return flags; 107 return flags;
178} 108}
179 109
180static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start, 110/*
181 u64 len, int io_decode, 111 * Allocated Resources
182 int window) 112 */
183{
184 int flags = 0;
185 u64 end = start + len - 1;
186 113
187 if (io_decode == ACPI_DECODE_16) 114static void pnpacpi_add_irqresource(struct pnp_dev *dev, struct resource *r)
188 flags |= IORESOURCE_IO_16BIT_ADDR; 115{
189 if (len == 0 || end >= 0x10003) 116 if (!(r->flags & IORESOURCE_DISABLED))
190 flags |= IORESOURCE_DISABLED; 117 pcibios_penalize_isa_irq(r->start, 1);
191 if (window)
192 flags |= IORESOURCE_WINDOW;
193 118
194 pnp_add_io_resource(dev, start, end, flags); 119 pnp_add_resource(dev, r);
195} 120}
196 121
197/* 122/*
@@ -249,130 +174,49 @@ static void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev,
249 } 174 }
250} 175}
251 176
252static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev,
253 u64 start, u64 len,
254 int write_protect, int window)
255{
256 int flags = 0;
257 u64 end = start + len - 1;
258
259 if (len == 0)
260 flags |= IORESOURCE_DISABLED;
261 if (write_protect == ACPI_READ_WRITE_MEMORY)
262 flags |= IORESOURCE_MEM_WRITEABLE;
263 if (window)
264 flags |= IORESOURCE_WINDOW;
265
266 pnp_add_mem_resource(dev, start, end, flags);
267}
268
269static void pnpacpi_parse_allocated_busresource(struct pnp_dev *dev,
270 u64 start, u64 len)
271{
272 u64 end = start + len - 1;
273
274 pnp_add_bus_resource(dev, start, end);
275}
276
277static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev,
278 struct acpi_resource *res)
279{
280 struct acpi_resource_address64 addr, *p = &addr;
281 acpi_status status;
282 int window;
283 u64 len;
284
285 status = acpi_resource_to_address64(res, p);
286 if (!ACPI_SUCCESS(status)) {
287 dev_warn(&dev->dev, "failed to convert resource type %d\n",
288 res->type);
289 return;
290 }
291
292 /* Windows apparently computes length rather than using _LEN */
293 len = p->maximum - p->minimum + 1;
294 window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
295
296 if (p->resource_type == ACPI_MEMORY_RANGE)
297 pnpacpi_parse_allocated_memresource(dev, p->minimum, len,
298 p->info.mem.write_protect, window);
299 else if (p->resource_type == ACPI_IO_RANGE)
300 pnpacpi_parse_allocated_ioresource(dev, p->minimum, len,
301 p->granularity == 0xfff ? ACPI_DECODE_10 :
302 ACPI_DECODE_16, window);
303 else if (p->resource_type == ACPI_BUS_NUMBER_RANGE)
304 pnpacpi_parse_allocated_busresource(dev, p->minimum, len);
305}
306
307static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev,
308 struct acpi_resource *res)
309{
310 struct acpi_resource_extended_address64 *p = &res->data.ext_address64;
311 int window;
312 u64 len;
313
314 /* Windows apparently computes length rather than using _LEN */
315 len = p->maximum - p->minimum + 1;
316 window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
317
318 if (p->resource_type == ACPI_MEMORY_RANGE)
319 pnpacpi_parse_allocated_memresource(dev, p->minimum, len,
320 p->info.mem.write_protect, window);
321 else if (p->resource_type == ACPI_IO_RANGE)
322 pnpacpi_parse_allocated_ioresource(dev, p->minimum, len,
323 p->granularity == 0xfff ? ACPI_DECODE_10 :
324 ACPI_DECODE_16, window);
325 else if (p->resource_type == ACPI_BUS_NUMBER_RANGE)
326 pnpacpi_parse_allocated_busresource(dev, p->minimum, len);
327}
328
329static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, 177static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
330 void *data) 178 void *data)
331{ 179{
332 struct pnp_dev *dev = data; 180 struct pnp_dev *dev = data;
333 struct acpi_resource_irq *irq;
334 struct acpi_resource_dma *dma; 181 struct acpi_resource_dma *dma;
335 struct acpi_resource_io *io;
336 struct acpi_resource_fixed_io *fixed_io;
337 struct acpi_resource_vendor_typed *vendor_typed; 182 struct acpi_resource_vendor_typed *vendor_typed;
338 struct acpi_resource_memory24 *memory24; 183 struct resource r;
339 struct acpi_resource_memory32 *memory32;
340 struct acpi_resource_fixed_memory32 *fixed_memory32;
341 struct acpi_resource_extended_irq *extended_irq;
342 int i, flags; 184 int i, flags;
343 185
344 switch (res->type) { 186 if (acpi_dev_resource_memory(res, &r)
345 case ACPI_RESOURCE_TYPE_IRQ: 187 || acpi_dev_resource_io(res, &r)
346 /* 188 || acpi_dev_resource_address_space(res, &r)
347 * Per spec, only one interrupt per descriptor is allowed in 189 || acpi_dev_resource_ext_address_space(res, &r)) {
348 * _CRS, but some firmware violates this, so parse them all. 190 pnp_add_resource(dev, &r);
349 */ 191 return AE_OK;
350 irq = &res->data.irq; 192 }
351 if (irq->interrupt_count == 0)
352 pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
353 else {
354 for (i = 0; i < irq->interrupt_count; i++) {
355 pnpacpi_parse_allocated_irqresource(dev,
356 irq->interrupts[i],
357 irq->triggering,
358 irq->polarity,
359 irq->sharable);
360 }
361 193
194 r.flags = 0;
195 if (acpi_dev_resource_interrupt(res, 0, &r)) {
196 pnpacpi_add_irqresource(dev, &r);
197 for (i = 1; acpi_dev_resource_interrupt(res, i, &r); i++)
198 pnpacpi_add_irqresource(dev, &r);
199
200 if (i > 1) {
362 /* 201 /*
363 * The IRQ encoder puts a single interrupt in each 202 * The IRQ encoder puts a single interrupt in each
364 * descriptor, so if a _CRS descriptor has more than 203 * descriptor, so if a _CRS descriptor has more than
365 * one interrupt, we won't be able to re-encode it. 204 * one interrupt, we won't be able to re-encode it.
366 */ 205 */
367 if (pnp_can_write(dev) && irq->interrupt_count > 1) { 206 if (pnp_can_write(dev)) {
368 dev_warn(&dev->dev, "multiple interrupts in " 207 dev_warn(&dev->dev, "multiple interrupts in "
369 "_CRS descriptor; configuration can't " 208 "_CRS descriptor; configuration can't "
370 "be changed\n"); 209 "be changed\n");
371 dev->capabilities &= ~PNP_WRITE; 210 dev->capabilities &= ~PNP_WRITE;
372 } 211 }
373 } 212 }
374 break; 213 return AE_OK;
214 } else if (r.flags & IORESOURCE_DISABLED) {
215 pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
216 return AE_OK;
217 }
375 218
219 switch (res->type) {
376 case ACPI_RESOURCE_TYPE_DMA: 220 case ACPI_RESOURCE_TYPE_DMA:
377 dma = &res->data.dma; 221 dma = &res->data.dma;
378 if (dma->channel_count > 0 && dma->channels[0] != (u8) -1) 222 if (dma->channel_count > 0 && dma->channels[0] != (u8) -1)
@@ -383,26 +227,10 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
383 pnp_add_dma_resource(dev, dma->channels[0], flags); 227 pnp_add_dma_resource(dev, dma->channels[0], flags);
384 break; 228 break;
385 229
386 case ACPI_RESOURCE_TYPE_IO:
387 io = &res->data.io;
388 pnpacpi_parse_allocated_ioresource(dev,
389 io->minimum,
390 io->address_length,
391 io->io_decode, 0);
392 break;
393
394 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 230 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
395 case ACPI_RESOURCE_TYPE_END_DEPENDENT: 231 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
396 break; 232 break;
397 233
398 case ACPI_RESOURCE_TYPE_FIXED_IO:
399 fixed_io = &res->data.fixed_io;
400 pnpacpi_parse_allocated_ioresource(dev,
401 fixed_io->address,
402 fixed_io->address_length,
403 ACPI_DECODE_10, 0);
404 break;
405
406 case ACPI_RESOURCE_TYPE_VENDOR: 234 case ACPI_RESOURCE_TYPE_VENDOR:
407 vendor_typed = &res->data.vendor_typed; 235 vendor_typed = &res->data.vendor_typed;
408 pnpacpi_parse_allocated_vendor(dev, vendor_typed); 236 pnpacpi_parse_allocated_vendor(dev, vendor_typed);
@@ -411,66 +239,6 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
411 case ACPI_RESOURCE_TYPE_END_TAG: 239 case ACPI_RESOURCE_TYPE_END_TAG:
412 break; 240 break;
413 241
414 case ACPI_RESOURCE_TYPE_MEMORY24:
415 memory24 = &res->data.memory24;
416 pnpacpi_parse_allocated_memresource(dev,
417 memory24->minimum,
418 memory24->address_length,
419 memory24->write_protect, 0);
420 break;
421 case ACPI_RESOURCE_TYPE_MEMORY32:
422 memory32 = &res->data.memory32;
423 pnpacpi_parse_allocated_memresource(dev,
424 memory32->minimum,
425 memory32->address_length,
426 memory32->write_protect, 0);
427 break;
428 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
429 fixed_memory32 = &res->data.fixed_memory32;
430 pnpacpi_parse_allocated_memresource(dev,
431 fixed_memory32->address,
432 fixed_memory32->address_length,
433 fixed_memory32->write_protect, 0);
434 break;
435 case ACPI_RESOURCE_TYPE_ADDRESS16:
436 case ACPI_RESOURCE_TYPE_ADDRESS32:
437 case ACPI_RESOURCE_TYPE_ADDRESS64:
438 pnpacpi_parse_allocated_address_space(dev, res);
439 break;
440
441 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
442 pnpacpi_parse_allocated_ext_address_space(dev, res);
443 break;
444
445 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
446 extended_irq = &res->data.extended_irq;
447
448 if (extended_irq->interrupt_count == 0)
449 pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
450 else {
451 for (i = 0; i < extended_irq->interrupt_count; i++) {
452 pnpacpi_parse_allocated_irqresource(dev,
453 extended_irq->interrupts[i],
454 extended_irq->triggering,
455 extended_irq->polarity,
456 extended_irq->sharable);
457 }
458
459 /*
460 * The IRQ encoder puts a single interrupt in each
461 * descriptor, so if a _CRS descriptor has more than
462 * one interrupt, we won't be able to re-encode it.
463 */
464 if (pnp_can_write(dev) &&
465 extended_irq->interrupt_count > 1) {
466 dev_warn(&dev->dev, "multiple interrupts in "
467 "_CRS descriptor; configuration can't "
468 "be changed\n");
469 dev->capabilities &= ~PNP_WRITE;
470 }
471 }
472 break;
473
474 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: 242 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
475 break; 243 break;
476 244
@@ -531,7 +299,7 @@ static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev,
531 if (p->interrupts[i]) 299 if (p->interrupts[i])
532 __set_bit(p->interrupts[i], map.bits); 300 __set_bit(p->interrupts[i], map.bits);
533 301
534 flags = irq_flags(p->triggering, p->polarity, p->sharable); 302 flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable);
535 pnp_register_irq_resource(dev, option_flags, &map, flags); 303 pnp_register_irq_resource(dev, option_flags, &map, flags);
536} 304}
537 305
@@ -555,7 +323,7 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev,
555 } 323 }
556 } 324 }
557 325
558 flags = irq_flags(p->triggering, p->polarity, p->sharable); 326 flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable);
559 pnp_register_irq_resource(dev, option_flags, &map, flags); 327 pnp_register_irq_resource(dev, option_flags, &map, flags);
560} 328}
561 329
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index b0ecacbe53b1..3e6db1c1dc29 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -503,6 +503,22 @@ static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev)
503 return pnp_res; 503 return pnp_res;
504} 504}
505 505
506struct pnp_resource *pnp_add_resource(struct pnp_dev *dev,
507 struct resource *res)
508{
509 struct pnp_resource *pnp_res;
510
511 pnp_res = pnp_new_resource(dev);
512 if (!pnp_res) {
513 dev_err(&dev->dev, "can't add resource %pR\n", res);
514 return NULL;
515 }
516
517 pnp_res->res = *res;
518 dev_dbg(&dev->dev, "%pR\n", res);
519 return pnp_res;
520}
521
506struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq, 522struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
507 int flags) 523 int flags)
508{ 524{
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 48761cb481db..16fcaf8dad3d 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -251,6 +251,16 @@ extern int pnpacpi_disabled;
251 251
252#define PXM_INVAL (-1) 252#define PXM_INVAL (-1)
253 253
254bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res);
255bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res);
256bool acpi_dev_resource_address_space(struct acpi_resource *ares,
257 struct resource *res);
258bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares,
259 struct resource *res);
260unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable);
261bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
262 struct resource *res);
263
254int acpi_check_resource_conflict(const struct resource *res); 264int acpi_check_resource_conflict(const struct resource *res);
255 265
256int acpi_check_region(resource_size_t start, resource_size_t n, 266int acpi_check_region(resource_size_t start, resource_size_t n,