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.16.4.1 2003/08/22 20:49:20 jhb Exp $
28 * $DragonFly: src/sys/dev/acpica/Attic/acpi_resource.c,v 1.1 2003/09/24 03:32:16 drhodus Exp $
32 #include <sys/param.h>
33 #include <sys/kernel.h>
36 #include <machine/bus.h>
37 #include <machine/resource.h>
42 #include <dev/acpica/acpivar.h>
45 * Hooks for the ACPI CA debugging infrastructure
47 #define _COMPONENT ACPI_BUS
48 ACPI_MODULE_NAME("RESOURCE")
51 * Fetch a device's resources and associate them with the device.
53 * Note that it might be nice to also locate ACPI-specific resource items, such
56 * We really need to split the resource-fetching code out from the
57 * resource-parsing code, since we may want to use the parsing
58 * code for _PRS someday.
61 acpi_parse_resources(device_t dev, ACPI_HANDLE handle, struct acpi_parse_resource_set *set)
69 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
72 * Special-case some devices that abuse _PRS/_CRS to mean
73 * something other than "I consume this resource".
75 * XXX do we really need this? It's only relevant once
76 * we start always-allocating these resources, and even
77 * then, the only special-cased device is likely to be
78 * the PCI interrupt link.
82 * Fetch the device's current resources.
84 buf.Length = ACPI_ALLOCATE_BUFFER;
85 if (ACPI_FAILURE((status = AcpiGetCurrentResources(handle, &buf)))) {
86 if (status != AE_NOT_FOUND)
87 printf("can't fetch resources for %s - %s\n",
88 acpi_name(handle), AcpiFormatException(status));
89 return_ACPI_STATUS(status);
91 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s - got %ld bytes of resources\n",
92 acpi_name(handle), (long)buf.Length));
93 set->set_init(dev, &context);
96 * Iterate through the resources
99 last = (char *)buf.Pointer + buf.Length;
100 while (curr < last) {
101 res = (ACPI_RESOURCE *)curr;
105 * Handle the individual resource types
108 case ACPI_RSTYPE_END_TAG:
109 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
113 case ACPI_RSTYPE_FIXED_IO:
114 if (res->Data.FixedIo.RangeLength <= 0)
116 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
117 res->Data.FixedIo.BaseAddress,
118 res->Data.FixedIo.RangeLength));
119 set->set_ioport(dev, context,
120 res->Data.FixedIo.BaseAddress,
121 res->Data.FixedIo.RangeLength);
125 if (res->Data.Io.RangeLength <= 0)
127 if (res->Data.Io.MinBaseAddress == res->Data.Io.MaxBaseAddress) {
128 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
129 res->Data.Io.MinBaseAddress,
130 res->Data.Io.RangeLength));
131 set->set_ioport(dev, context,
132 res->Data.Io.MinBaseAddress,
133 res->Data.Io.RangeLength);
135 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
136 res->Data.Io.MinBaseAddress,
137 res->Data.Io.MaxBaseAddress,
138 res->Data.Io.RangeLength));
139 set->set_iorange(dev, context,
140 res->Data.Io.MinBaseAddress,
141 res->Data.Io.MaxBaseAddress,
142 res->Data.Io.RangeLength, res->Data.Io.Alignment);
146 case ACPI_RSTYPE_FIXED_MEM32:
147 if (res->Data.FixedMemory32.RangeLength <= 0)
149 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
150 res->Data.FixedMemory32.RangeBaseAddress,
151 res->Data.FixedMemory32.RangeLength));
152 set->set_memory(dev, context, res->Data.FixedMemory32.RangeBaseAddress,
153 res->Data.FixedMemory32.RangeLength);
156 case ACPI_RSTYPE_MEM32:
157 if (res->Data.Memory32.RangeLength <= 0)
159 if (res->Data.Memory32.MinBaseAddress == res->Data.Memory32.MaxBaseAddress) {
160 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
161 res->Data.Memory32.MinBaseAddress,
162 res->Data.Memory32.RangeLength));
163 set->set_memory(dev, context,
164 res->Data.Memory32.MinBaseAddress,
165 res->Data.Memory32.RangeLength);
167 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
168 res->Data.Memory32.MinBaseAddress,
169 res->Data.Memory32.MaxBaseAddress,
170 res->Data.Memory32.RangeLength));
171 set->set_memoryrange(dev, context,
172 res->Data.Memory32.MinBaseAddress,
173 res->Data.Memory32.MaxBaseAddress,
174 res->Data.Memory32.RangeLength,
175 res->Data.Memory32.Alignment);
179 case ACPI_RSTYPE_MEM24:
180 if (res->Data.Memory24.RangeLength <= 0)
182 if (res->Data.Memory24.MinBaseAddress == res->Data.Memory24.MaxBaseAddress) {
183 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
184 res->Data.Memory24.MinBaseAddress,
185 res->Data.Memory24.RangeLength));
186 set->set_memory(dev, context, res->Data.Memory24.MinBaseAddress,
187 res->Data.Memory24.RangeLength);
189 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
190 res->Data.Memory24.MinBaseAddress,
191 res->Data.Memory24.MaxBaseAddress,
192 res->Data.Memory24.RangeLength));
193 set->set_memoryrange(dev, context,
194 res->Data.Memory24.MinBaseAddress,
195 res->Data.Memory24.MaxBaseAddress,
196 res->Data.Memory24.RangeLength,
197 res->Data.Memory24.Alignment);
201 case ACPI_RSTYPE_IRQ:
204 * "This structure is repeated for each separate interrupt
207 set->set_irq(dev, context, res->Data.Irq.Interrupts,
208 res->Data.Irq.NumberOfInterrupts);
211 case ACPI_RSTYPE_DMA:
214 * "This structure is repeated for each separate dma channel
218 set->set_drq(dev, context, res->Data.Dma.Channels,
219 res->Data.Dma.NumberOfChannels);
222 case ACPI_RSTYPE_START_DPF:
223 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependant functions\n"));
224 set->set_start_dependant(dev, context,
225 res->Data.StartDpf.CompatibilityPriority);
228 case ACPI_RSTYPE_END_DPF:
229 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependant functions\n"));
230 set->set_end_dependant(dev, context);
233 case ACPI_RSTYPE_ADDRESS32:
234 if (res->Data.Address32.AddressLength <= 0)
236 if (res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) {
237 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored Address32 %s producer\n",
238 (res->Data.Address32.ResourceType == ACPI_IO_RANGE) ?
242 if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE &&
243 res->Data.Address32.ResourceType != ACPI_IO_RANGE) {
244 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
245 "ignored Address32 for non-memory, non-I/O\n"));
249 if ((res->Data.Address32.MinAddressFixed == ACPI_ADDRESS_FIXED) &&
250 (res->Data.Address32.MaxAddressFixed == ACPI_ADDRESS_FIXED)) {
251 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
252 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/Memory 0x%x/%d\n",
253 res->Data.Address32.MinAddressRange,
254 res->Data.Address32.AddressLength));
255 set->set_memory(dev, context,
256 res->Data.Address32.MinAddressRange,
257 res->Data.Address32.AddressLength);
259 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/IO 0x%x/%d\n",
260 res->Data.Address32.MinAddressRange,
261 res->Data.Address32.AddressLength));
262 set->set_ioport(dev, context,
263 res->Data.Address32.MinAddressRange,
264 res->Data.Address32.AddressLength);
267 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
268 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/Memory 0x%x-0x%x/%d\n",
269 res->Data.Address32.MinAddressRange,
270 res->Data.Address32.MaxAddressRange,
271 res->Data.Address32.AddressLength));
272 set->set_memoryrange(dev, context,
273 res->Data.Address32.MinAddressRange,
274 res->Data.Address32.MaxAddressRange,
275 res->Data.Address32.AddressLength,
276 res->Data.Address32.Granularity);
278 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/IO 0x%x-0x%x/%d\n",
279 res->Data.Address32.MinAddressRange,
280 res->Data.Address32.MaxAddressRange,
281 res->Data.Address32.AddressLength));
282 set->set_iorange(dev, context,
283 res->Data.Address32.MinAddressRange,
284 res->Data.Address32.MaxAddressRange,
285 res->Data.Address32.AddressLength,
286 res->Data.Address32.Granularity);
291 case ACPI_RSTYPE_ADDRESS16:
292 if (res->Data.Address16.AddressLength <= 0)
294 if (res->Data.Address16.ProducerConsumer != ACPI_CONSUMER) {
295 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored Address16 %s producer\n",
296 (res->Data.Address16.ResourceType == ACPI_IO_RANGE) ?
300 if (res->Data.Address16.ResourceType != ACPI_MEMORY_RANGE &&
301 res->Data.Address16.ResourceType != ACPI_IO_RANGE) {
302 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
303 "ignored Address16 for non-memory, non-I/O\n"));
307 if ((res->Data.Address16.MinAddressFixed == ACPI_ADDRESS_FIXED) &&
308 (res->Data.Address16.MaxAddressFixed == ACPI_ADDRESS_FIXED)) {
309 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) {
310 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/Memory 0x%x/%d\n",
311 res->Data.Address16.MinAddressRange,
312 res->Data.Address16.AddressLength));
313 set->set_memory(dev, context,
314 res->Data.Address16.MinAddressRange,
315 res->Data.Address16.AddressLength);
317 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/IO 0x%x/%d\n",
318 res->Data.Address16.MinAddressRange,
319 res->Data.Address16.AddressLength));
320 set->set_ioport(dev, context,
321 res->Data.Address16.MinAddressRange,
322 res->Data.Address16.AddressLength);
325 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) {
326 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/Memory 0x%x-0x%x/%d\n",
327 res->Data.Address16.MinAddressRange,
328 res->Data.Address16.MaxAddressRange,
329 res->Data.Address16.AddressLength));
330 set->set_memoryrange(dev, context,
331 res->Data.Address16.MinAddressRange,
332 res->Data.Address16.MaxAddressRange,
333 res->Data.Address16.AddressLength,
334 res->Data.Address16.Granularity);
336 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/IO 0x%x-0x%x/%d\n",
337 res->Data.Address16.MinAddressRange,
338 res->Data.Address16.MaxAddressRange,
339 res->Data.Address16.AddressLength));
340 set->set_iorange(dev, context,
341 res->Data.Address16.MinAddressRange,
342 res->Data.Address16.MaxAddressRange,
343 res->Data.Address16.AddressLength,
344 res->Data.Address16.Granularity);
349 case ACPI_RSTYPE_ADDRESS64:
350 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "unimplemented Address64 resource\n"));
353 case ACPI_RSTYPE_EXT_IRQ:
354 /* XXX special handling? */
355 set->set_irq(dev, context,res->Data.ExtendedIrq.Interrupts,
356 res->Data.ExtendedIrq.NumberOfInterrupts);
359 case ACPI_RSTYPE_VENDOR:
360 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "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 **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, u_int32_t base, u_int32_t length);
378 static void acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high,
379 u_int32_t length, u_int32_t align);
380 static void acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length);
381 static void acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high,
382 u_int32_t length, u_int32_t align);
383 static void acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq,
385 static void acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq,
387 static void acpi_res_set_start_dependant(device_t dev, void *context, int preference);
388 static void acpi_res_set_end_dependant(device_t dev, void *context);
390 struct acpi_parse_resource_set acpi_res_parse_set = {
394 acpi_res_set_iorange,
396 acpi_res_set_memoryrange,
399 acpi_res_set_start_dependant,
400 acpi_res_set_end_dependant
403 struct acpi_res_context {
411 acpi_res_set_init(device_t dev, void **context)
413 struct acpi_res_context *cp;
415 if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
416 bzero(cp, sizeof(*cp));
422 acpi_res_set_done(device_t dev, void *context)
424 struct acpi_res_context *cp = (struct acpi_res_context *)context;
432 acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length)
434 struct acpi_res_context *cp = (struct acpi_res_context *)context;
438 bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
442 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)
444 struct acpi_res_context *cp = (struct acpi_res_context *)context;
448 device_printf(dev, "I/O range not supported\n");
452 acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length)
454 struct acpi_res_context *cp = (struct acpi_res_context *)context;
459 bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
463 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)
465 struct acpi_res_context *cp = (struct acpi_res_context *)context;
469 device_printf(dev, "memory range not supported\n");
473 acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, int count)
475 struct acpi_res_context *cp = (struct acpi_res_context *)context;
482 /*This implements no resource relocation.*/
486 bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
490 acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq, int count)
492 struct acpi_res_context *cp = (struct acpi_res_context *)context;
499 /*This implements no resource relocation.*/
503 bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
507 acpi_res_set_start_dependant(device_t dev, void *context, int preference)
509 struct acpi_res_context *cp = (struct acpi_res_context *)context;
513 device_printf(dev, "dependant functions not supported\n");
517 acpi_res_set_end_dependant(device_t dev, void *context)
519 struct acpi_res_context *cp = (struct acpi_res_context *)context;
526 * Resource-owning placeholders.
528 * This code "owns" system resource objects that aren't
529 * otherwise useful to devices, and which shouldn't be
532 * Note that some systems claim *all* of the physical address space
533 * with a PNP0C01 device, so we cannot correctly "own" system memory
534 * here (must be done in the SMAP handler on x86 systems, for
538 static int acpi_sysresource_probe(device_t dev);
539 static int acpi_sysresource_attach(device_t dev);
541 static device_method_t acpi_sysresource_methods[] = {
542 /* Device interface */
543 DEVMETHOD(device_probe, acpi_sysresource_probe),
544 DEVMETHOD(device_attach, acpi_sysresource_attach),
549 static driver_t acpi_sysresource_driver = {
551 acpi_sysresource_methods,
555 static devclass_t acpi_sysresource_devclass;
556 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysresource_driver, acpi_sysresource_devclass, 0, 0);
559 acpi_sysresource_probe(device_t dev)
561 if (acpi_disabled("sysresource"))
563 if (acpi_MatchHid(dev, "PNP0C02")) {
564 device_set_desc(dev, "system resource");
573 acpi_sysresource_attach(device_t dev)
575 struct resource *res;
579 * Suck up all the resources that might have been assigned to us.
580 * Note that it's impossible to tell the difference between a
581 * resource that someone else has claimed, and one that doesn't
584 for (i = 0; i < 100; i++) {
586 res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, 0);
588 res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1, 0);
590 res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE);