1 /*-
2 * Copyright (c) 2000 Michael Smith
3 * Copyright (c) 2000 BSDi
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: releng/5.0/sys/dev/acpica/acpi_resource.c 108248 2002-12-24 02:09:47Z marcel $
28 */
29
30 #include "opt_acpi.h"
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/bus.h>
34
35 #include <machine/bus.h>
36 #include <machine/resource.h>
37 #include <sys/rman.h>
38
39 #include "acpi.h"
40
41 #include <dev/acpica/acpivar.h>
42
43 /*
44 * Hooks for the ACPI CA debugging infrastructure
45 */
46 #define _COMPONENT ACPI_BUS
47 ACPI_MODULE_NAME("RESOURCE")
48
49 /*
50 * Fetch a device's resources and associate them with the device.
51 *
52 * Note that it might be nice to also locate ACPI-specific resource items, such
53 * as GPE bits.
54 *
55 * We really need to split the resource-fetching code out from the
56 * resource-parsing code, since we may want to use the parsing
57 * code for _PRS someday.
58 */
59 ACPI_STATUS
60 acpi_parse_resources(device_t dev, ACPI_HANDLE handle, struct acpi_parse_resource_set *set)
61 {
62 ACPI_BUFFER buf;
63 ACPI_RESOURCE *res;
64 char *curr, *last;
65 ACPI_STATUS status;
66 void *context;
67
68 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
69
70 /*
71 * Special-case some devices that abuse _PRS/_CRS to mean
72 * something other than "I consume this resource".
73 *
74 * XXX do we really need this? It's only relevant once
75 * we start always-allocating these resources, and even
76 * then, the only special-cased device is likely to be
77 * the PCI interrupt link.
78 */
79
80 /*
81 * Fetch the device's current resources.
82 */
83 buf.Length = ACPI_ALLOCATE_BUFFER;
84 if (ACPI_FAILURE((status = AcpiGetCurrentResources(handle, &buf)))) {
85 if (status != AE_NOT_FOUND)
86 printf("can't fetch resources for %s - %s\n",
87 acpi_name(handle), AcpiFormatException(status));
88 return_ACPI_STATUS(status);
89 }
90 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s - got %ld bytes of resources\n",
91 acpi_name(handle), (long)buf.Length));
92 set->set_init(dev, &context);
93
94 /*
95 * Iterate through the resources
96 */
97 curr = buf.Pointer;
98 last = (char *)buf.Pointer + buf.Length;
99 while (curr < last) {
100 res = (ACPI_RESOURCE *)curr;
101 curr += res->Length;
102
103 /*
104 * Handle the individual resource types
105 */
106 switch(res->Id) {
107 case ACPI_RSTYPE_END_TAG:
108 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
109 curr = last;
110 break;
111
112 case ACPI_RSTYPE_FIXED_IO:
113 if (res->Data.FixedIo.RangeLength <= 0)
114 break;
115 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
116 res->Data.FixedIo.BaseAddress,
117 res->Data.FixedIo.RangeLength));
118 set->set_ioport(dev, context,
119 res->Data.FixedIo.BaseAddress,
120 res->Data.FixedIo.RangeLength);
121 break;
122
123 case ACPI_RSTYPE_IO:
124 if (res->Data.Io.RangeLength <= 0)
125 break;
126 if (res->Data.Io.MinBaseAddress == res->Data.Io.MaxBaseAddress) {
127 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
128 res->Data.Io.MinBaseAddress,
129 res->Data.Io.RangeLength));
130 set->set_ioport(dev, context,
131 res->Data.Io.MinBaseAddress,
132 res->Data.Io.RangeLength);
133 } else {
134 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
135 res->Data.Io.MinBaseAddress,
136 res->Data.Io.MaxBaseAddress,
137 res->Data.Io.RangeLength));
138 set->set_iorange(dev, context,
139 res->Data.Io.MinBaseAddress,
140 res->Data.Io.MaxBaseAddress,
141 res->Data.Io.RangeLength, res->Data.Io.Alignment);
142 }
143 break;
144
145 case ACPI_RSTYPE_FIXED_MEM32:
146 if (res->Data.FixedMemory32.RangeLength <= 0)
147 break;
148 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
149 res->Data.FixedMemory32.RangeBaseAddress,
150 res->Data.FixedMemory32.RangeLength));
151 set->set_memory(dev, context, res->Data.FixedMemory32.RangeBaseAddress,
152 res->Data.FixedMemory32.RangeLength);
153 break;
154
155 case ACPI_RSTYPE_MEM32:
156 if (res->Data.Memory32.RangeLength <= 0)
157 break;
158 if (res->Data.Memory32.MinBaseAddress == res->Data.Memory32.MaxBaseAddress) {
159 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
160 res->Data.Memory32.MinBaseAddress,
161 res->Data.Memory32.RangeLength));
162 set->set_memory(dev, context,
163 res->Data.Memory32.MinBaseAddress,
164 res->Data.Memory32.RangeLength);
165 } else {
166 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
167 res->Data.Memory32.MinBaseAddress,
168 res->Data.Memory32.MaxBaseAddress,
169 res->Data.Memory32.RangeLength));
170 set->set_memoryrange(dev, context,
171 res->Data.Memory32.MinBaseAddress,
172 res->Data.Memory32.MaxBaseAddress,
173 res->Data.Memory32.RangeLength,
174 res->Data.Memory32.Alignment);
175 }
176 break;
177
178 case ACPI_RSTYPE_MEM24:
179 if (res->Data.Memory24.RangeLength <= 0)
180 break;
181 if (res->Data.Memory24.MinBaseAddress == res->Data.Memory24.MaxBaseAddress) {
182 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
183 res->Data.Memory24.MinBaseAddress,
184 res->Data.Memory24.RangeLength));
185 set->set_memory(dev, context, res->Data.Memory24.MinBaseAddress,
186 res->Data.Memory24.RangeLength);
187 } else {
188 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
189 res->Data.Memory24.MinBaseAddress,
190 res->Data.Memory24.MaxBaseAddress,
191 res->Data.Memory24.RangeLength));
192 set->set_memoryrange(dev, context,
193 res->Data.Memory24.MinBaseAddress,
194 res->Data.Memory24.MaxBaseAddress,
195 res->Data.Memory24.RangeLength,
196 res->Data.Memory24.Alignment);
197 }
198 break;
199
200 case ACPI_RSTYPE_IRQ:
201 /*
202 * from 1.0b 6.4.2
203 * "This structure is repeated for each separate interrupt
204 * required"
205 */
206 set->set_irq(dev, context, res->Data.Irq.Interrupts,
207 res->Data.Irq.NumberOfInterrupts);
208 break;
209
210 case ACPI_RSTYPE_DMA:
211 /*
212 * from 1.0b 6.4.3
213 * "This structure is repeated for each separate dma channel
214 * required"
215 */
216
217 set->set_drq(dev, context, res->Data.Dma.Channels,
218 res->Data.Dma.NumberOfChannels);
219 break;
220
221 case ACPI_RSTYPE_START_DPF:
222 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependant functions\n"));
223 set->set_start_dependant(dev, context,
224 res->Data.StartDpf.CompatibilityPriority);
225 break;
226
227 case ACPI_RSTYPE_END_DPF:
228 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependant functions\n"));
229 set->set_end_dependant(dev, context);
230 break;
231
232 case ACPI_RSTYPE_ADDRESS32:
233 if (res->Data.Address32.AddressLength <= 0)
234 break;
235 if (res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) {
236 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored Address32 %s producer\n",
237 (res->Data.Address32.ResourceType == ACPI_IO_RANGE) ?
238 "IO" : "Memory"));
239 break;
240 }
241 if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE &&
242 res->Data.Address32.ResourceType != ACPI_IO_RANGE) {
243 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
244 "ignored Address32 for non-memory, non-I/O\n"));
245 break;
246 }
247
248 if ((res->Data.Address32.MinAddressFixed == ACPI_ADDRESS_FIXED) &&
249 (res->Data.Address32.MaxAddressFixed == ACPI_ADDRESS_FIXED)) {
250 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
251 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/Memory 0x%x/%d\n",
252 res->Data.Address32.MinAddressRange,
253 res->Data.Address32.AddressLength));
254 set->set_memory(dev, context,
255 res->Data.Address32.MinAddressRange,
256 res->Data.Address32.AddressLength);
257 } else {
258 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/IO 0x%x/%d\n",
259 res->Data.Address32.MinAddressRange,
260 res->Data.Address32.AddressLength));
261 set->set_ioport(dev, context,
262 res->Data.Address32.MinAddressRange,
263 res->Data.Address32.AddressLength);
264 }
265 } else {
266 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
267 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/Memory 0x%x-0x%x/%d\n",
268 res->Data.Address32.MinAddressRange,
269 res->Data.Address32.MaxAddressRange,
270 res->Data.Address32.AddressLength));
271 set->set_memoryrange(dev, context,
272 res->Data.Address32.MinAddressRange,
273 res->Data.Address32.MaxAddressRange,
274 res->Data.Address32.AddressLength,
275 res->Data.Address32.Granularity);
276 } else {
277 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/IO 0x%x-0x%x/%d\n",
278 res->Data.Address32.MinAddressRange,
279 res->Data.Address32.MaxAddressRange,
280 res->Data.Address32.AddressLength));
281 set->set_iorange(dev, context,
282 res->Data.Address32.MinAddressRange,
283 res->Data.Address32.MaxAddressRange,
284 res->Data.Address32.AddressLength,
285 res->Data.Address32.Granularity);
286 }
287 }
288 break;
289
290 case ACPI_RSTYPE_ADDRESS16:
291 if (res->Data.Address16.AddressLength <= 0)
292 break;
293 if (res->Data.Address16.ProducerConsumer != ACPI_CONSUMER) {
294 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored Address16 %s producer\n",
295 (res->Data.Address16.ResourceType == ACPI_IO_RANGE) ?
296 "IO" : "Memory"));
297 break;
298 }
299 if (res->Data.Address16.ResourceType != ACPI_MEMORY_RANGE &&
300 res->Data.Address16.ResourceType != ACPI_IO_RANGE) {
301 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
302 "ignored Address16 for non-memory, non-I/O\n"));
303 break;
304 }
305
306 if ((res->Data.Address16.MinAddressFixed == ACPI_ADDRESS_FIXED) &&
307 (res->Data.Address16.MaxAddressFixed == ACPI_ADDRESS_FIXED)) {
308 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) {
309 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/Memory 0x%x/%d\n",
310 res->Data.Address16.MinAddressRange,
311 res->Data.Address16.AddressLength));
312 set->set_memory(dev, context,
313 res->Data.Address16.MinAddressRange,
314 res->Data.Address16.AddressLength);
315 } else {
316 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/IO 0x%x/%d\n",
317 res->Data.Address16.MinAddressRange,
318 res->Data.Address16.AddressLength));
319 set->set_ioport(dev, context,
320 res->Data.Address16.MinAddressRange,
321 res->Data.Address16.AddressLength);
322 }
323 } else {
324 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) {
325 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/Memory 0x%x-0x%x/%d\n",
326 res->Data.Address16.MinAddressRange,
327 res->Data.Address16.MaxAddressRange,
328 res->Data.Address16.AddressLength));
329 set->set_memoryrange(dev, context,
330 res->Data.Address16.MinAddressRange,
331 res->Data.Address16.MaxAddressRange,
332 res->Data.Address16.AddressLength,
333 res->Data.Address16.Granularity);
334 } else {
335 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/IO 0x%x-0x%x/%d\n",
336 res->Data.Address16.MinAddressRange,
337 res->Data.Address16.MaxAddressRange,
338 res->Data.Address16.AddressLength));
339 set->set_iorange(dev, context,
340 res->Data.Address16.MinAddressRange,
341 res->Data.Address16.MaxAddressRange,
342 res->Data.Address16.AddressLength,
343 res->Data.Address16.Granularity);
344 }
345 }
346 break;
347
348 case ACPI_RSTYPE_ADDRESS64:
349 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "unimplemented Address64 resource\n"));
350 break;
351
352 case ACPI_RSTYPE_EXT_IRQ:
353 /* XXX special handling? */
354 set->set_irq(dev, context,res->Data.ExtendedIrq.Interrupts,
355 res->Data.ExtendedIrq.NumberOfInterrupts);
356 break;
357
358 case ACPI_RSTYPE_VENDOR:
359 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "unimplemented VendorSpecific resource\n"));
360 break;
361 default:
362 break;
363 }
364 }
365 AcpiOsFree(buf.Pointer);
366 set->set_done(dev, context);
367 return_ACPI_STATUS(AE_OK);
368 }
369
370 /*
371 * Resource-set vectors used to attach _CRS-derived resources
372 * to an ACPI device.
373 */
374 static void acpi_res_set_init(device_t dev, void **context);
375 static void acpi_res_set_done(device_t dev, void *context);
376 static void acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length);
377 static void acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high,
378 u_int32_t length, u_int32_t align);
379 static void acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length);
380 static void acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high,
381 u_int32_t length, u_int32_t align);
382 static void acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq,
383 int count);
384 static void acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq,
385 int count);
386 static void acpi_res_set_start_dependant(device_t dev, void *context, int preference);
387 static void acpi_res_set_end_dependant(device_t dev, void *context);
388
389 struct acpi_parse_resource_set acpi_res_parse_set = {
390 acpi_res_set_init,
391 acpi_res_set_done,
392 acpi_res_set_ioport,
393 acpi_res_set_iorange,
394 acpi_res_set_memory,
395 acpi_res_set_memoryrange,
396 acpi_res_set_irq,
397 acpi_res_set_drq,
398 acpi_res_set_start_dependant,
399 acpi_res_set_end_dependant
400 };
401
402 struct acpi_res_context {
403 int ar_nio;
404 int ar_nmem;
405 int ar_nirq;
406 int ar_ndrq;
407 };
408
409 static void
410 acpi_res_set_init(device_t dev, void **context)
411 {
412 struct acpi_res_context *cp;
413
414 if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
415 bzero(cp, sizeof(*cp));
416 *context = cp;
417 }
418 }
419
420 static void
421 acpi_res_set_done(device_t dev, void *context)
422 {
423 struct acpi_res_context *cp = (struct acpi_res_context *)context;
424
425 if (cp == NULL)
426 return;
427 AcpiOsFree(cp);
428 }
429
430 static void
431 acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length)
432 {
433 struct acpi_res_context *cp = (struct acpi_res_context *)context;
434
435 if (cp == NULL)
436 return;
437 bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
438 }
439
440 static void
441 acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high, u_int32_t length, u_int32_t align)
442 {
443 struct acpi_res_context *cp = (struct acpi_res_context *)context;
444
445 if (cp == NULL)
446 return;
447 device_printf(dev, "I/O range not supported\n");
448 }
449
450 static void
451 acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length)
452 {
453 struct acpi_res_context *cp = (struct acpi_res_context *)context;
454
455 if (cp == NULL)
456 return;
457
458 bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
459 }
460
461 static void
462 acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high, u_int32_t length, u_int32_t align)
463 {
464 struct acpi_res_context *cp = (struct acpi_res_context *)context;
465
466 if (cp == NULL)
467 return;
468 device_printf(dev, "memory range not supported\n");
469 }
470
471 static void
472 acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, int count)
473 {
474 struct acpi_res_context *cp = (struct acpi_res_context *)context;
475
476 if (cp == NULL)
477 return;
478 if (irq == NULL)
479 return;
480
481 /*This implements no resource relocation.*/
482 if(count != 1)
483 return;
484
485 bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
486 }
487
488 static void
489 acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq, int count)
490 {
491 struct acpi_res_context *cp = (struct acpi_res_context *)context;
492
493 if (cp == NULL)
494 return;
495 if (drq == NULL)
496 return;
497
498 /*This implements no resource relocation.*/
499 if(count != 1)
500 return;
501
502 bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
503 }
504
505 static void
506 acpi_res_set_start_dependant(device_t dev, void *context, int preference)
507 {
508 struct acpi_res_context *cp = (struct acpi_res_context *)context;
509
510 if (cp == NULL)
511 return;
512 device_printf(dev, "dependant functions not supported\n");
513 }
514
515 static void
516 acpi_res_set_end_dependant(device_t dev, void *context)
517 {
518 struct acpi_res_context *cp = (struct acpi_res_context *)context;
519
520 if (cp == NULL)
521 return;
522 }
523
524 /*
525 * Resource-owning placeholders.
526 *
527 * This code "owns" system resource objects that aren't
528 * otherwise useful to devices, and which shouldn't be
529 * considered "free".
530 *
531 * Note that some systems claim *all* of the physical address space
532 * with a PNP0C01 device, so we cannot correctly "own" system memory
533 * here (must be done in the SMAP handler on x86 systems, for
534 * example).
535 */
536
537 static int acpi_sysresource_probe(device_t dev);
538 static int acpi_sysresource_attach(device_t dev);
539
540 static device_method_t acpi_sysresource_methods[] = {
541 /* Device interface */
542 DEVMETHOD(device_probe, acpi_sysresource_probe),
543 DEVMETHOD(device_attach, acpi_sysresource_attach),
544
545 {0, 0}
546 };
547
548 static driver_t acpi_sysresource_driver = {
549 "acpi_sysresource",
550 acpi_sysresource_methods,
551 0,
552 };
553
554 static devclass_t acpi_sysresource_devclass;
555 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysresource_driver, acpi_sysresource_devclass, 0, 0);
556
557 static int
558 acpi_sysresource_probe(device_t dev)
559 {
560 if (acpi_disabled("sysresource"))
561 return(ENXIO);
562 if (acpi_MatchHid(dev, "PNP0C02")) {
563 device_set_desc(dev, "system resource");
564 } else {
565 return(ENXIO);
566 }
567 device_quiet(dev);
568 return(-100);
569 }
570
571 static int
572 acpi_sysresource_attach(device_t dev)
573 {
574 struct resource *res;
575 int i, rid;
576
577 /*
578 * Suck up all the resources that might have been assigned to us.
579 * Note that it's impossible to tell the difference between a
580 * resource that someone else has claimed, and one that doesn't
581 * exist.
582 */
583 for (i = 0; i < 100; i++) {
584 rid = i;
585 res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, 0);
586 rid = i;
587 res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1, 0);
588 rid = i;
589 res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE);
590 }
591 return(0);
592 }
Cache object: 10cdaaa1595a1d5fd3ec8502463ebbe3
|