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.20 2003/09/26 05:24:55 njl Exp $
28 * $DragonFly: src/sys/dev/acpica5/acpi_resource.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
32 #include <sys/param.h>
33 #include <sys/kernel.h>
36 #include <machine/bus.h>
37 #include <machine/resource.h>
41 #include <dev/acpica5/acpivar.h>
43 /* Hooks for the ACPI CA debugging infrastructure */
44 #define _COMPONENT ACPI_BUS
45 ACPI_MODULE_NAME("RESOURCE")
48 * Fetch a device's resources and associate them with the device.
50 * Note that it might be nice to also locate ACPI-specific resource items, such
53 * We really need to split the resource-fetching code out from the
54 * resource-parsing code, since we may want to use the parsing
55 * code for _PRS someday.
58 acpi_parse_resources(device_t dev, ACPI_HANDLE handle,
59 struct acpi_parse_resource_set *set)
67 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
70 * Special-case some devices that abuse _PRS/_CRS to mean
71 * something other than "I consume this resource".
73 * XXX do we really need this? It's only relevant once
74 * we start always-allocating these resources, and even
75 * then, the only special-cased device is likely to be
76 * the PCI interrupt link.
79 /* Fetch the device's current resources. */
80 buf.Length = ACPI_ALLOCATE_BUFFER;
81 if (ACPI_FAILURE((status = AcpiGetCurrentResources(handle, &buf)))) {
82 if (status != AE_NOT_FOUND)
83 printf("can't fetch resources for %s - %s\n",
84 acpi_name(handle), AcpiFormatException(status));
85 return_ACPI_STATUS (status);
87 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s - got %ld bytes of resources\n",
88 acpi_name(handle), (long)buf.Length));
89 set->set_init(dev, &context);
91 /* Iterate through the resources */
93 last = (char *)buf.Pointer + buf.Length;
95 res = (ACPI_RESOURCE *)curr;
98 /* Handle the individual resource types */
100 case ACPI_RSTYPE_END_TAG:
101 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
104 case ACPI_RSTYPE_FIXED_IO:
105 if (res->Data.FixedIo.RangeLength <= 0)
107 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
108 res->Data.FixedIo.BaseAddress,
109 res->Data.FixedIo.RangeLength));
110 set->set_ioport(dev, context,
111 res->Data.FixedIo.BaseAddress,
112 res->Data.FixedIo.RangeLength);
115 if (res->Data.Io.RangeLength <= 0)
117 if (res->Data.Io.MinBaseAddress == res->Data.Io.MaxBaseAddress) {
118 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
119 res->Data.Io.MinBaseAddress,
120 res->Data.Io.RangeLength));
121 set->set_ioport(dev, context,
122 res->Data.Io.MinBaseAddress,
123 res->Data.Io.RangeLength);
125 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
126 res->Data.Io.MinBaseAddress,
127 res->Data.Io.MaxBaseAddress,
128 res->Data.Io.RangeLength));
129 set->set_iorange(dev, context,
130 res->Data.Io.MinBaseAddress,
131 res->Data.Io.MaxBaseAddress,
132 res->Data.Io.RangeLength,
133 res->Data.Io.Alignment);
136 case ACPI_RSTYPE_FIXED_MEM32:
137 if (res->Data.FixedMemory32.RangeLength <= 0)
139 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
140 res->Data.FixedMemory32.RangeBaseAddress,
141 res->Data.FixedMemory32.RangeLength));
142 set->set_memory(dev, context,
143 res->Data.FixedMemory32.RangeBaseAddress,
144 res->Data.FixedMemory32.RangeLength);
146 case ACPI_RSTYPE_MEM32:
147 if (res->Data.Memory32.RangeLength <= 0)
149 if (res->Data.Memory32.MinBaseAddress ==
150 res->Data.Memory32.MaxBaseAddress) {
152 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
153 res->Data.Memory32.MinBaseAddress,
154 res->Data.Memory32.RangeLength));
155 set->set_memory(dev, context,
156 res->Data.Memory32.MinBaseAddress,
157 res->Data.Memory32.RangeLength);
159 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
160 res->Data.Memory32.MinBaseAddress,
161 res->Data.Memory32.MaxBaseAddress,
162 res->Data.Memory32.RangeLength));
163 set->set_memoryrange(dev, context,
164 res->Data.Memory32.MinBaseAddress,
165 res->Data.Memory32.MaxBaseAddress,
166 res->Data.Memory32.RangeLength,
167 res->Data.Memory32.Alignment);
170 case ACPI_RSTYPE_MEM24:
171 if (res->Data.Memory24.RangeLength <= 0)
173 if (res->Data.Memory24.MinBaseAddress ==
174 res->Data.Memory24.MaxBaseAddress) {
176 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
177 res->Data.Memory24.MinBaseAddress,
178 res->Data.Memory24.RangeLength));
179 set->set_memory(dev, context, res->Data.Memory24.MinBaseAddress,
180 res->Data.Memory24.RangeLength);
182 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
183 res->Data.Memory24.MinBaseAddress,
184 res->Data.Memory24.MaxBaseAddress,
185 res->Data.Memory24.RangeLength));
186 set->set_memoryrange(dev, context,
187 res->Data.Memory24.MinBaseAddress,
188 res->Data.Memory24.MaxBaseAddress,
189 res->Data.Memory24.RangeLength,
190 res->Data.Memory24.Alignment);
193 case ACPI_RSTYPE_IRQ:
196 * "This structure is repeated for each separate interrupt
199 set->set_irq(dev, context, res->Data.Irq.Interrupts,
200 res->Data.Irq.NumberOfInterrupts, res->Data.Irq.EdgeLevel,
201 res->Data.Irq.ActiveHighLow);
203 case ACPI_RSTYPE_DMA:
206 * "This structure is repeated for each separate dma channel
209 set->set_drq(dev, context, res->Data.Dma.Channels,
210 res->Data.Dma.NumberOfChannels);
212 case ACPI_RSTYPE_START_DPF:
213 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependant functions\n"));
214 set->set_start_dependant(dev, context,
215 res->Data.StartDpf.CompatibilityPriority);
217 case ACPI_RSTYPE_END_DPF:
218 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependant functions\n"));
219 set->set_end_dependant(dev, context);
221 case ACPI_RSTYPE_ADDRESS32:
222 if (res->Data.Address32.AddressLength <= 0)
224 if (res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) {
225 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
226 "ignored Address32 %s producer\n",
227 res->Data.Address32.ResourceType == ACPI_IO_RANGE ?
231 if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE &&
232 res->Data.Address32.ResourceType != ACPI_IO_RANGE) {
233 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
234 "ignored Address32 for non-memory, non-I/O\n"));
238 if (res->Data.Address32.MinAddressFixed == ACPI_ADDRESS_FIXED &&
239 res->Data.Address32.MaxAddressFixed == ACPI_ADDRESS_FIXED) {
241 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
242 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
243 "Address32/Memory 0x%x/%d\n",
244 res->Data.Address32.MinAddressRange,
245 res->Data.Address32.AddressLength));
246 set->set_memory(dev, context,
247 res->Data.Address32.MinAddressRange,
248 res->Data.Address32.AddressLength);
250 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
251 "Address32/IO 0x%x/%d\n",
252 res->Data.Address32.MinAddressRange,
253 res->Data.Address32.AddressLength));
254 set->set_ioport(dev, context,
255 res->Data.Address32.MinAddressRange,
256 res->Data.Address32.AddressLength);
259 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
260 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
261 "Address32/Memory 0x%x-0x%x/%d\n",
262 res->Data.Address32.MinAddressRange,
263 res->Data.Address32.MaxAddressRange,
264 res->Data.Address32.AddressLength));
265 set->set_memoryrange(dev, context,
266 res->Data.Address32.MinAddressRange,
267 res->Data.Address32.MaxAddressRange,
268 res->Data.Address32.AddressLength,
269 res->Data.Address32.Granularity);
271 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
272 "Address32/IO 0x%x-0x%x/%d\n",
273 res->Data.Address32.MinAddressRange,
274 res->Data.Address32.MaxAddressRange,
275 res->Data.Address32.AddressLength));
276 set->set_iorange(dev, context,
277 res->Data.Address32.MinAddressRange,
278 res->Data.Address32.MaxAddressRange,
279 res->Data.Address32.AddressLength,
280 res->Data.Address32.Granularity);
284 case ACPI_RSTYPE_ADDRESS16:
285 if (res->Data.Address16.AddressLength <= 0)
287 if (res->Data.Address16.ProducerConsumer != ACPI_CONSUMER) {
288 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
289 "ignored Address16 %s producer\n",
290 res->Data.Address16.ResourceType == ACPI_IO_RANGE ?
294 if (res->Data.Address16.ResourceType != ACPI_MEMORY_RANGE &&
295 res->Data.Address16.ResourceType != ACPI_IO_RANGE) {
296 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
297 "ignored Address16 for non-memory, non-I/O\n"));
301 if (res->Data.Address16.MinAddressFixed == ACPI_ADDRESS_FIXED &&
302 res->Data.Address16.MaxAddressFixed == ACPI_ADDRESS_FIXED) {
304 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) {
305 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
306 "Address16/Memory 0x%x/%d\n",
307 res->Data.Address16.MinAddressRange,
308 res->Data.Address16.AddressLength));
309 set->set_memory(dev, context,
310 res->Data.Address16.MinAddressRange,
311 res->Data.Address16.AddressLength);
313 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
314 "Address16/IO 0x%x/%d\n",
315 res->Data.Address16.MinAddressRange,
316 res->Data.Address16.AddressLength));
317 set->set_ioport(dev, context,
318 res->Data.Address16.MinAddressRange,
319 res->Data.Address16.AddressLength);
322 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) {
323 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
324 "Address16/Memory 0x%x-0x%x/%d\n",
325 res->Data.Address16.MinAddressRange,
326 res->Data.Address16.MaxAddressRange,
327 res->Data.Address16.AddressLength));
328 set->set_memoryrange(dev, context,
329 res->Data.Address16.MinAddressRange,
330 res->Data.Address16.MaxAddressRange,
331 res->Data.Address16.AddressLength,
332 res->Data.Address16.Granularity);
334 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
335 "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);
347 case ACPI_RSTYPE_ADDRESS64:
348 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
349 "unimplemented Address64 resource\n"));
351 case ACPI_RSTYPE_EXT_IRQ:
352 /* XXX special handling? */
353 set->set_irq(dev, context,res->Data.ExtendedIrq.Interrupts,
354 res->Data.ExtendedIrq.NumberOfInterrupts,
355 res->Data.ExtendedIrq.EdgeLevel,
356 res->Data.ExtendedIrq.ActiveHighLow);
358 case ACPI_RSTYPE_VENDOR:
359 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
360 "unimplemented VendorSpecific resource\n"));
367 AcpiOsFree(buf.Pointer);
368 set->set_done(dev, context);
369 return_ACPI_STATUS (AE_OK);
373 * Resource-set vectors used to attach _CRS-derived resources
376 static void acpi_res_set_init(device_t dev, void **context);
377 static void acpi_res_set_done(device_t dev, void *context);
378 static void acpi_res_set_ioport(device_t dev, void *context,
379 u_int32_t base, u_int32_t length);
380 static void acpi_res_set_iorange(device_t dev, void *context,
381 u_int32_t low, u_int32_t high,
382 u_int32_t length, u_int32_t align);
383 static void acpi_res_set_memory(device_t dev, void *context,
384 u_int32_t base, u_int32_t length);
385 static void acpi_res_set_memoryrange(device_t dev, void *context,
386 u_int32_t low, u_int32_t high,
387 u_int32_t length, u_int32_t align);
388 static void acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq,
389 int count, int trig, int pol);
390 static void acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq,
392 static void acpi_res_set_start_dependant(device_t dev, void *context,
394 static void acpi_res_set_end_dependant(device_t dev, void *context);
396 struct acpi_parse_resource_set acpi_res_parse_set = {
400 acpi_res_set_iorange,
402 acpi_res_set_memoryrange,
405 acpi_res_set_start_dependant,
406 acpi_res_set_end_dependant
409 struct acpi_res_context {
417 acpi_res_set_init(device_t dev, void **context)
419 struct acpi_res_context *cp;
421 if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
422 bzero(cp, sizeof(*cp));
428 acpi_res_set_done(device_t dev, void *context)
430 struct acpi_res_context *cp = (struct acpi_res_context *)context;
438 acpi_res_set_ioport(device_t dev, void *context, u_int32_t base,
441 struct acpi_res_context *cp = (struct acpi_res_context *)context;
445 bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
449 acpi_res_set_iorange(device_t dev, void *context, u_int32_t low,
450 u_int32_t high, u_int32_t length, u_int32_t align)
452 struct acpi_res_context *cp = (struct acpi_res_context *)context;
456 device_printf(dev, "I/O range not supported\n");
460 acpi_res_set_memory(device_t dev, void *context, u_int32_t base,
463 struct acpi_res_context *cp = (struct acpi_res_context *)context;
468 bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
472 acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low,
473 u_int32_t high, u_int32_t length, u_int32_t align)
475 struct acpi_res_context *cp = (struct acpi_res_context *)context;
479 device_printf(dev, "memory range not supported\n");
483 acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, int count,
486 struct acpi_res_context *cp = (struct acpi_res_context *)context;
488 if (cp == NULL || irq == NULL)
491 /* This implements no resource relocation. */
495 bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
496 #if 0 /* From FreeBSD-5 XXX */
497 BUS_CONFIG_INTR(dev, *irq, (trig == ACPI_EDGE_SENSITIVE) ?
498 INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
499 INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
504 acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq, int count)
506 struct acpi_res_context *cp = (struct acpi_res_context *)context;
508 if (cp == NULL || drq == NULL)
511 /* This implements no resource relocation. */
515 bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
519 acpi_res_set_start_dependant(device_t dev, void *context, int preference)
521 struct acpi_res_context *cp = (struct acpi_res_context *)context;
525 device_printf(dev, "dependant functions not supported\n");
529 acpi_res_set_end_dependant(device_t dev, void *context)
531 struct acpi_res_context *cp = (struct acpi_res_context *)context;
535 device_printf(dev, "dependant functions not supported\n");
539 * Resource-owning placeholders.
541 * This code "owns" system resource objects that aren't
542 * otherwise useful to devices, and which shouldn't be
545 * Note that some systems claim *all* of the physical address space
546 * with a PNP0C01 device, so we cannot correctly "own" system memory
547 * here (must be done in the SMAP handler on x86 systems, for
551 static int acpi_sysresource_probe(device_t dev);
552 static int acpi_sysresource_attach(device_t dev);
554 static device_method_t acpi_sysresource_methods[] = {
555 /* Device interface */
556 DEVMETHOD(device_probe, acpi_sysresource_probe),
557 DEVMETHOD(device_attach, acpi_sysresource_attach),
562 static driver_t acpi_sysresource_driver = {
564 acpi_sysresource_methods,
568 static devclass_t acpi_sysresource_devclass;
569 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysresource_driver,
570 acpi_sysresource_devclass, 0, 0);
573 acpi_sysresource_probe(device_t dev)
575 if (!acpi_disabled("sysresource") && acpi_MatchHid(dev, "PNP0C02"))
576 device_set_desc(dev, "System Resource");
585 acpi_sysresource_attach(device_t dev)
587 struct resource *res;
591 * Suck up all the resources that might have been assigned to us.
592 * Note that it's impossible to tell the difference between a
593 * resource that someone else has claimed, and one that doesn't
596 for (i = 0; i < 100; i++) {
598 res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, 0);
600 res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1, 0);
602 res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,