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.23 2004/04/09 18:14:32 njl Exp $
28 * $DragonFly: src/sys/dev/acpica5/acpi_resource.c,v 1.2 2004/06/27 08:52:39 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, void *arg)
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, arg, &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 *arg, 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 {
418 acpi_res_set_init(device_t dev, void *arg, void **context)
420 struct acpi_res_context *cp;
422 if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
423 bzero(cp, sizeof(*cp));
430 acpi_res_set_done(device_t dev, void *context)
432 struct acpi_res_context *cp = (struct acpi_res_context *)context;
440 acpi_res_set_ioport(device_t dev, void *context, u_int32_t base,
443 struct acpi_res_context *cp = (struct acpi_res_context *)context;
447 bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
451 acpi_res_set_iorange(device_t dev, void *context, u_int32_t low,
452 u_int32_t high, u_int32_t length, u_int32_t align)
454 struct acpi_res_context *cp = (struct acpi_res_context *)context;
458 device_printf(dev, "I/O range not supported\n");
462 acpi_res_set_memory(device_t dev, void *context, u_int32_t base,
465 struct acpi_res_context *cp = (struct acpi_res_context *)context;
470 bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
474 acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low,
475 u_int32_t high, u_int32_t length, u_int32_t align)
477 struct acpi_res_context *cp = (struct acpi_res_context *)context;
481 device_printf(dev, "memory range not supported\n");
485 acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, int count,
488 struct acpi_res_context *cp = (struct acpi_res_context *)context;
490 if (cp == NULL || irq == NULL)
493 /* This implements no resource relocation. */
497 bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
498 #if 0 /* From FreeBSD-5 XXX */
499 BUS_CONFIG_INTR(dev, *irq, (trig == ACPI_EDGE_SENSITIVE) ?
500 INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
501 INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
506 acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq, int count)
508 struct acpi_res_context *cp = (struct acpi_res_context *)context;
510 if (cp == NULL || drq == NULL)
513 /* This implements no resource relocation. */
517 bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
521 acpi_res_set_start_dependant(device_t dev, void *context, int preference)
523 struct acpi_res_context *cp = (struct acpi_res_context *)context;
527 device_printf(dev, "dependant functions not supported\n");
531 acpi_res_set_end_dependant(device_t dev, void *context)
533 struct acpi_res_context *cp = (struct acpi_res_context *)context;
537 device_printf(dev, "dependant functions not supported\n");
541 * Resource-owning placeholders.
543 * This code "owns" system resource objects that aren't
544 * otherwise useful to devices, and which shouldn't be
547 * Note that some systems claim *all* of the physical address space
548 * with a PNP0C01 device, so we cannot correctly "own" system memory
549 * here (must be done in the SMAP handler on x86 systems, for
553 static int acpi_sysresource_probe(device_t dev);
554 static int acpi_sysresource_attach(device_t dev);
556 static device_method_t acpi_sysresource_methods[] = {
557 /* Device interface */
558 DEVMETHOD(device_probe, acpi_sysresource_probe),
559 DEVMETHOD(device_attach, acpi_sysresource_attach),
564 static driver_t acpi_sysresource_driver = {
566 acpi_sysresource_methods,
570 static devclass_t acpi_sysresource_devclass;
571 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysresource_driver,
572 acpi_sysresource_devclass, 0, 0);
573 MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
576 acpi_sysresource_probe(device_t dev)
578 if (!acpi_disabled("sysresource") && acpi_MatchHid(dev, "PNP0C02"))
579 device_set_desc(dev, "System Resource");
588 acpi_sysresource_attach(device_t dev)
590 struct resource *res;
594 * Suck up all the resources that might have been assigned to us.
595 * Note that it's impossible to tell the difference between a
596 * resource that someone else has claimed, and one that doesn't
599 for (i = 0; i < 100; i++) {
601 res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 0);
603 res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 0);
605 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE);