aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/resource.c
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 /drivers/acpi/resource.c
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>
Diffstat (limited to 'drivers/acpi/resource.c')
-rw-r--r--drivers/acpi/resource.c393
1 files changed, 393 insertions, 0 deletions
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);