2 * Copyright (c) 2000 Michael Smith
3 * Copyright (c) 2000 BSDi
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
27 * $FreeBSD: src/sys/dev/acpica/acpi_resource.c,v 1.25 2004/06/13 22:52:30 njl Exp $
28 * $DragonFly: src/sys/dev/acpica5/acpi_resource.c,v 1.9 2007/10/23 03:04:48 y0netan1 Exp $
32 #include <sys/param.h>
33 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/module.h>
40 #include <dev/acpica5/acpivar.h>
42 /* Hooks for the ACPI CA debugging infrastructure */
43 #define _COMPONENT ACPI_BUS
44 ACPI_MODULE_NAME("RESOURCE")
47 * Fetch a device's resources and associate them with the device.
49 * Note that it might be nice to also locate ACPI-specific resource items, such
52 * We really need to split the resource-fetching code out from the
53 * resource-parsing code, since we may want to use the parsing
54 * code for _PRS someday.
57 acpi_parse_resources(device_t dev, ACPI_HANDLE handle,
58 struct acpi_parse_resource_set *set, void *arg)
66 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
69 * Special-case some devices that abuse _PRS/_CRS to mean
70 * something other than "I consume this resource".
72 * XXX do we really need this? It's only relevant once
73 * we start always-allocating these resources, and even
74 * then, the only special-cased device is likely to be
75 * the PCI interrupt link.
78 /* Fetch the device's current resources. */
79 buf.Length = ACPI_ALLOCATE_BUFFER;
80 if (ACPI_FAILURE((status = AcpiGetCurrentResources(handle, &buf)))) {
81 if (status != AE_NOT_FOUND && status != AE_TYPE)
82 kprintf("can't fetch resources for %s - %s\n",
83 acpi_name(handle), AcpiFormatException(status));
84 return_ACPI_STATUS (status);
86 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s - got %ld bytes of resources\n",
87 acpi_name(handle), (long)buf.Length));
88 set->set_init(dev, arg, &context);
90 /* Iterate through the resources */
92 last = (char *)buf.Pointer + buf.Length;
94 res = (ACPI_RESOURCE *)curr;
97 /* Handle the individual resource types */
99 case ACPI_RESOURCE_TYPE_END_TAG:
100 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
103 case ACPI_RESOURCE_TYPE_FIXED_IO:
104 if (res->Data.FixedIo.AddressLength <= 0)
106 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
107 res->Data.FixedIo.Address,
108 res->Data.FixedIo.AddressLength));
109 set->set_ioport(dev, context,
110 res->Data.FixedIo.Address,
111 res->Data.FixedIo.AddressLength);
113 case ACPI_RESOURCE_TYPE_IO:
114 if (res->Data.Io.AddressLength <= 0)
116 if (res->Data.Io.Minimum == res->Data.Io.Maximum) {
117 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
118 res->Data.Io.Minimum,
119 res->Data.Io.AddressLength));
120 set->set_ioport(dev, context,
121 res->Data.Io.Minimum,
122 res->Data.Io.AddressLength);
124 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
125 res->Data.Io.Minimum,
126 res->Data.Io.Maximum,
127 res->Data.Io.AddressLength));
128 set->set_iorange(dev, context,
129 res->Data.Io.Minimum,
130 res->Data.Io.Maximum,
131 res->Data.Io.AddressLength,
132 res->Data.Io.Alignment);
135 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
136 if (res->Data.FixedMemory32.AddressLength <= 0)
138 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
139 res->Data.FixedMemory32.Address,
140 res->Data.FixedMemory32.AddressLength));
141 set->set_memory(dev, context,
142 res->Data.FixedMemory32.Address,
143 res->Data.FixedMemory32.AddressLength);
145 case ACPI_RESOURCE_TYPE_MEMORY32:
146 if (res->Data.Memory32.AddressLength <= 0)
148 if (res->Data.Memory32.Minimum ==
149 res->Data.Memory32.Maximum) {
151 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
152 res->Data.Memory32.Minimum,
153 res->Data.Memory32.AddressLength));
154 set->set_memory(dev, context,
155 res->Data.Memory32.Minimum,
156 res->Data.Memory32.AddressLength);
158 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
159 res->Data.Memory32.Minimum,
160 res->Data.Memory32.Maximum,
161 res->Data.Memory32.AddressLength));
162 set->set_memoryrange(dev, context,
163 res->Data.Memory32.Minimum,
164 res->Data.Memory32.Maximum,
165 res->Data.Memory32.AddressLength,
166 res->Data.Memory32.Alignment);
169 case ACPI_RESOURCE_TYPE_MEMORY24:
170 if (res->Data.Memory24.AddressLength <= 0)
172 if (res->Data.Memory24.Minimum ==
173 res->Data.Memory24.Maximum) {
175 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
176 res->Data.Memory24.Minimum,
177 res->Data.Memory24.AddressLength));
178 set->set_memory(dev, context, res->Data.Memory24.Minimum,
179 res->Data.Memory24.AddressLength);
181 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
182 res->Data.Memory24.Minimum,
183 res->Data.Memory24.Maximum,
184 res->Data.Memory24.AddressLength));
185 set->set_memoryrange(dev, context,
186 res->Data.Memory24.Minimum,
187 res->Data.Memory24.Maximum,
188 res->Data.Memory24.AddressLength,
189 res->Data.Memory24.Alignment);
192 case ACPI_RESOURCE_TYPE_IRQ:
195 * "This structure is repeated for each separate interrupt
198 set->set_irq(dev, context, res->Data.Irq.Interrupts,
199 res->Data.Irq.InterruptCount, res->Data.Irq.Triggering,
200 res->Data.Irq.Polarity);
202 case ACPI_RESOURCE_TYPE_DMA:
205 * "This structure is repeated for each separate dma channel
208 set->set_drq(dev, context, res->Data.Dma.Channels,
209 res->Data.Dma.ChannelCount);
211 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
212 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependent functions\n"));
213 set->set_start_dependant(dev, context,
214 res->Data.StartDpf.CompatibilityPriority);
216 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
217 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependent functions\n"));
218 set->set_end_dependant(dev, context);
220 case ACPI_RESOURCE_TYPE_ADDRESS32:
221 if (res->Data.Address32.AddressLength <= 0)
223 if (res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) {
224 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
225 "ignored Address32 %s producer\n",
226 res->Data.Address32.ResourceType == ACPI_IO_RANGE ?
230 if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE &&
231 res->Data.Address32.ResourceType != ACPI_IO_RANGE) {
232 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
233 "ignored Address32 for non-memory, non-I/O\n"));
237 if (res->Data.Address32.Minimum == ACPI_ADDRESS_FIXED &&
238 res->Data.Address32.Maximum == ACPI_ADDRESS_FIXED) {
240 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
241 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
242 "Address32/Memory 0x%x/%d\n",
243 res->Data.Address32.Minimum,
244 res->Data.Address32.AddressLength));
245 set->set_memory(dev, context,
246 res->Data.Address32.Minimum,
247 res->Data.Address32.AddressLength);
249 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
250 "Address32/IO 0x%x/%d\n",
251 res->Data.Address32.Minimum,
252 res->Data.Address32.AddressLength));
253 set->set_ioport(dev, context,
254 res->Data.Address32.Minimum,
255 res->Data.Address32.AddressLength);
258 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
259 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
260 "Address32/Memory 0x%x-0x%x/%d\n",
261 res->Data.Address32.Minimum,
262 res->Data.Address32.Maximum,
263 res->Data.Address32.AddressLength));
264 set->set_memoryrange(dev, context,
265 res->Data.Address32.Minimum,
266 res->Data.Address32.Maximum,
267 res->Data.Address32.AddressLength,
268 res->Data.Address32.Granularity);
270 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
271 "Address32/IO 0x%x-0x%x/%d\n",
272 res->Data.Address32.Minimum,
273 res->Data.Address32.Maximum,
274 res->Data.Address32.AddressLength));
275 set->set_iorange(dev, context,
276 res->Data.Address32.Minimum,
277 res->Data.Address32.Maximum,
278 res->Data.Address32.AddressLength,
279 res->Data.Address32.Granularity);
283 case ACPI_RESOURCE_TYPE_ADDRESS16:
284 if (res->Data.Address16.AddressLength <= 0)
286 if (res->Data.Address16.ProducerConsumer != ACPI_CONSUMER) {
287 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
288 "ignored Address16 %s producer\n",
289 res->Data.Address16.ResourceType == ACPI_IO_RANGE ?
293 if (res->Data.Address16.ResourceType != ACPI_MEMORY_RANGE &&
294 res->Data.Address16.ResourceType != ACPI_IO_RANGE) {
295 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
296 "ignored Address16 for non-memory, non-I/O\n"));
300 if (res->Data.Address16.Minimum == ACPI_ADDRESS_FIXED &&
301 res->Data.Address16.Maximum == ACPI_ADDRESS_FIXED) {
303 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) {
304 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
305 "Address16/Memory 0x%x/%d\n",
306 res->Data.Address16.Minimum,
307 res->Data.Address16.AddressLength));
308 set->set_memory(dev, context,
309 res->Data.Address16.Minimum,
310 res->Data.Address16.AddressLength);
312 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
313 "Address16/IO 0x%x/%d\n",
314 res->Data.Address16.Minimum,
315 res->Data.Address16.AddressLength));
316 set->set_ioport(dev, context,
317 res->Data.Address16.Minimum,
318 res->Data.Address16.AddressLength);
321 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) {
322 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
323 "Address16/Memory 0x%x-0x%x/%d\n",
324 res->Data.Address16.Minimum,
325 res->Data.Address16.Maximum,
326 res->Data.Address16.AddressLength));
327 set->set_memoryrange(dev, context,
328 res->Data.Address16.Minimum,
329 res->Data.Address16.Maximum,
330 res->Data.Address16.AddressLength,
331 res->Data.Address16.Granularity);
333 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
334 "Address16/IO 0x%x-0x%x/%d\n",
335 res->Data.Address16.Minimum,
336 res->Data.Address16.Maximum,
337 res->Data.Address16.AddressLength));
338 set->set_iorange(dev, context,
339 res->Data.Address16.Minimum,
340 res->Data.Address16.Maximum,
341 res->Data.Address16.AddressLength,
342 res->Data.Address16.Granularity);
346 case ACPI_RESOURCE_TYPE_ADDRESS64:
347 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
348 "unimplemented Address64 resource\n"));
350 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
351 /* XXX special handling? */
352 set->set_ext_irq(dev, context, res->Data.ExtendedIrq.Interrupts,
353 res->Data.ExtendedIrq.InterruptCount,
354 res->Data.ExtendedIrq.Triggering,
355 res->Data.ExtendedIrq.Polarity);
357 case ACPI_RESOURCE_TYPE_VENDOR:
358 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
359 "unimplemented VendorSpecific resource\n"));
366 AcpiOsFree(buf.Pointer);
367 set->set_done(dev, context);
368 return_ACPI_STATUS (AE_OK);
372 * Resource-set vectors used to attach _CRS-derived resources
375 static void acpi_res_set_init(device_t dev, void *arg, void **context);
376 static void acpi_res_set_done(device_t dev, void *context);
377 static void acpi_res_set_ioport(device_t dev, void *context,
378 u_int32_t base, u_int32_t length);
379 static void acpi_res_set_iorange(device_t dev, void *context,
380 u_int32_t low, u_int32_t high,
381 u_int32_t length, u_int32_t align);
382 static void acpi_res_set_memory(device_t dev, void *context,
383 u_int32_t base, u_int32_t length);
384 static void acpi_res_set_memoryrange(device_t dev, void *context,
385 u_int32_t low, u_int32_t high,
386 u_int32_t length, u_int32_t align);
387 static void acpi_res_set_irq(device_t dev, void *context, u_int8_t *irq,
388 int count, int trig, int pol);
389 static void acpi_res_set_ext_irq(device_t dev, void *context,
390 u_int32_t *irq, int count, int trig,
392 static void acpi_res_set_drq(device_t dev, void *context, u_int8_t *drq,
394 static void acpi_res_set_start_dependant(device_t dev, void *context,
396 static void acpi_res_set_end_dependant(device_t dev, void *context);
398 struct acpi_parse_resource_set acpi_res_parse_set = {
402 acpi_res_set_iorange,
404 acpi_res_set_memoryrange,
406 acpi_res_set_ext_irq,
408 acpi_res_set_start_dependant,
409 acpi_res_set_end_dependant
412 struct acpi_res_context {
421 acpi_res_set_init(device_t dev, void *arg, void **context)
423 struct acpi_res_context *cp;
425 if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
426 bzero(cp, sizeof(*cp));
433 acpi_res_set_done(device_t dev, void *context)
435 struct acpi_res_context *cp = (struct acpi_res_context *)context;
443 acpi_res_set_ioport(device_t dev, void *context, u_int32_t base,
446 struct acpi_res_context *cp = (struct acpi_res_context *)context;
450 bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
454 acpi_res_set_iorange(device_t dev, void *context, u_int32_t low,
455 u_int32_t high, u_int32_t length, u_int32_t align)
457 struct acpi_res_context *cp = (struct acpi_res_context *)context;
461 device_printf(dev, "I/O range not supported\n");
465 acpi_res_set_memory(device_t dev, void *context, u_int32_t base,
468 struct acpi_res_context *cp = (struct acpi_res_context *)context;
473 bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
477 acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low,
478 u_int32_t high, u_int32_t length, u_int32_t align)
480 struct acpi_res_context *cp = (struct acpi_res_context *)context;
484 device_printf(dev, "memory range not supported\n");
488 acpi_res_set_irq(device_t dev, void *context, u_int8_t *irq, int count,
491 struct acpi_res_context *cp = (struct acpi_res_context *)context;
493 if (cp == NULL || irq == NULL)
496 /* This implements no resource relocation. */
500 bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
501 #if 0 /* From FreeBSD-5 XXX */
502 BUS_CONFIG_INTR(dev, *irq, (trig == ACPI_EDGE_SENSITIVE) ?
503 INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
504 INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
509 acpi_res_set_ext_irq(device_t dev, void *context, u_int32_t *irq, int count,
512 struct acpi_res_context *cp = (struct acpi_res_context *)context;
514 if (cp == NULL || irq == NULL)
517 /* This implements no resource relocation. */
521 bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
522 #if 0 /* From FreeBSD-5 XXX */
523 BUS_CONFIG_INTR(dev, *irq, (trig == ACPI_EDGE_SENSITIVE) ?
524 INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
525 INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
530 acpi_res_set_drq(device_t dev, void *context, u_int8_t *drq, int count)
532 struct acpi_res_context *cp = (struct acpi_res_context *)context;
534 if (cp == NULL || drq == NULL)
537 /* This implements no resource relocation. */
541 bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
545 acpi_res_set_start_dependant(device_t dev, void *context, int preference)
547 struct acpi_res_context *cp = (struct acpi_res_context *)context;
551 device_printf(dev, "dependent functions not supported\n");
555 acpi_res_set_end_dependant(device_t dev, void *context)
557 struct acpi_res_context *cp = (struct acpi_res_context *)context;
561 device_printf(dev, "dependent functions not supported\n");
565 * Resource-owning placeholders for IO and memory pseudo-devices.
567 * This code allocates system resource objects that will be owned by ACPI
568 * child devices. Really, the acpi parent device should have the resources
569 * but this would significantly affect the device probe code.
572 static int acpi_sysres_probe(device_t dev);
573 static int acpi_sysres_attach(device_t dev);
575 static device_method_t acpi_sysres_methods[] = {
576 /* Device interface */
577 DEVMETHOD(device_probe, acpi_sysres_probe),
578 DEVMETHOD(device_attach, acpi_sysres_attach),
583 static driver_t acpi_sysres_driver = {
589 static devclass_t acpi_sysres_devclass;
590 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, acpi_sysres_devclass,
592 MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
595 acpi_sysres_probe(device_t dev)
599 h = acpi_get_handle(dev);
600 if (acpi_disabled("sysresource") ||
601 (!acpi_MatchHid(h, "PNP0C01") && !acpi_MatchHid(h, "PNP0C02")))
604 device_set_desc(dev, "System Resource");
610 acpi_sysres_attach(device_t dev)
613 struct resource *res;
615 struct resource_list_entry *rle;
616 struct resource_list *rl;
619 * Pre-allocate/manage all memory and IO resources. We detect duplicates
620 * by setting rle->res to the resource we got from the parent. We can't
621 * ignore them since rman can't handle duplicates.
623 rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
624 SLIST_FOREACH(rle, rl, link) {
625 if (rle->res != NULL) {
626 device_printf(dev, "duplicate resource for %lx\n", rle->start);
630 /* Only memory and IO resources are valid here. */
642 /* Pre-allocate resource and add to our rman pool. */
643 gparent = device_get_parent(device_get_parent(dev));
644 res = BUS_ALLOC_RESOURCE(gparent, dev, rle->type, &rle->rid,
645 rle->start, rle->start + rle->count - 1, rle->count, 0);
647 rman_manage_region(rm, rman_get_start(res), rman_get_end(res));
655 struct resource_list_entry *
656 acpi_sysres_find(int type, u_long addr)
660 struct resource_list *rl;
661 struct resource_list_entry *rle;
663 /* We only consider IO and memory resources for our pool. */
665 if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY)
668 /* Find all the sysresource devices. */
669 if (devclass_get_devices(acpi_sysres_devclass, &devs, &numdevs) != 0)
672 /* Check each device for a resource that contains "addr". */
673 for (i = 0; i < numdevs && rle == NULL; i++) {
674 rl = BUS_GET_RESOURCE_LIST(device_get_parent(devs[i]), devs[i]);
677 SLIST_FOREACH(rle, rl, link) {
678 if (type == rle->type && addr >= rle->start &&
679 addr < rle->start + rle->count)