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.24 2004/05/30 20:08:23 phk Exp $
28 * $DragonFly: src/sys/dev/acpica5/acpi_resource.c,v 1.3 2004/07/05 00:07:35 dillon Exp $
32 #include <sys/param.h>
33 #include <sys/kernel.h>
35 #include <sys/module.h>
37 #include <machine/bus.h>
38 #include <machine/resource.h>
42 #include <dev/acpica5/acpivar.h>
44 /* Hooks for the ACPI CA debugging infrastructure */
45 #define _COMPONENT ACPI_BUS
46 ACPI_MODULE_NAME("RESOURCE")
49 * Fetch a device's resources and associate them with the device.
51 * Note that it might be nice to also locate ACPI-specific resource items, such
54 * We really need to split the resource-fetching code out from the
55 * resource-parsing code, since we may want to use the parsing
56 * code for _PRS someday.
59 acpi_parse_resources(device_t dev, ACPI_HANDLE handle,
60 struct acpi_parse_resource_set *set, void *arg)
68 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
71 * Special-case some devices that abuse _PRS/_CRS to mean
72 * something other than "I consume this resource".
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.
80 /* Fetch the device's current resources. */
81 buf.Length = ACPI_ALLOCATE_BUFFER;
82 if (ACPI_FAILURE((status = AcpiGetCurrentResources(handle, &buf)))) {
83 if (status != AE_NOT_FOUND)
84 printf("can't fetch resources for %s - %s\n",
85 acpi_name(handle), AcpiFormatException(status));
86 return_ACPI_STATUS (status);
88 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s - got %ld bytes of resources\n",
89 acpi_name(handle), (long)buf.Length));
90 set->set_init(dev, arg, &context);
92 /* Iterate through the resources */
94 last = (char *)buf.Pointer + buf.Length;
96 res = (ACPI_RESOURCE *)curr;
99 /* Handle the individual resource types */
101 case ACPI_RSTYPE_END_TAG:
102 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
105 case ACPI_RSTYPE_FIXED_IO:
106 if (res->Data.FixedIo.RangeLength <= 0)
108 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
109 res->Data.FixedIo.BaseAddress,
110 res->Data.FixedIo.RangeLength));
111 set->set_ioport(dev, context,
112 res->Data.FixedIo.BaseAddress,
113 res->Data.FixedIo.RangeLength);
116 if (res->Data.Io.RangeLength <= 0)
118 if (res->Data.Io.MinBaseAddress == res->Data.Io.MaxBaseAddress) {
119 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
120 res->Data.Io.MinBaseAddress,
121 res->Data.Io.RangeLength));
122 set->set_ioport(dev, context,
123 res->Data.Io.MinBaseAddress,
124 res->Data.Io.RangeLength);
126 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
127 res->Data.Io.MinBaseAddress,
128 res->Data.Io.MaxBaseAddress,
129 res->Data.Io.RangeLength));
130 set->set_iorange(dev, context,
131 res->Data.Io.MinBaseAddress,
132 res->Data.Io.MaxBaseAddress,
133 res->Data.Io.RangeLength,
134 res->Data.Io.Alignment);
137 case ACPI_RSTYPE_FIXED_MEM32:
138 if (res->Data.FixedMemory32.RangeLength <= 0)
140 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
141 res->Data.FixedMemory32.RangeBaseAddress,
142 res->Data.FixedMemory32.RangeLength));
143 set->set_memory(dev, context,
144 res->Data.FixedMemory32.RangeBaseAddress,
145 res->Data.FixedMemory32.RangeLength);
147 case ACPI_RSTYPE_MEM32:
148 if (res->Data.Memory32.RangeLength <= 0)
150 if (res->Data.Memory32.MinBaseAddress ==
151 res->Data.Memory32.MaxBaseAddress) {
153 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
154 res->Data.Memory32.MinBaseAddress,
155 res->Data.Memory32.RangeLength));
156 set->set_memory(dev, context,
157 res->Data.Memory32.MinBaseAddress,
158 res->Data.Memory32.RangeLength);
160 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
161 res->Data.Memory32.MinBaseAddress,
162 res->Data.Memory32.MaxBaseAddress,
163 res->Data.Memory32.RangeLength));
164 set->set_memoryrange(dev, context,
165 res->Data.Memory32.MinBaseAddress,
166 res->Data.Memory32.MaxBaseAddress,
167 res->Data.Memory32.RangeLength,
168 res->Data.Memory32.Alignment);
171 case ACPI_RSTYPE_MEM24:
172 if (res->Data.Memory24.RangeLength <= 0)
174 if (res->Data.Memory24.MinBaseAddress ==
175 res->Data.Memory24.MaxBaseAddress) {
177 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
178 res->Data.Memory24.MinBaseAddress,
179 res->Data.Memory24.RangeLength));
180 set->set_memory(dev, context, res->Data.Memory24.MinBaseAddress,
181 res->Data.Memory24.RangeLength);
183 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
184 res->Data.Memory24.MinBaseAddress,
185 res->Data.Memory24.MaxBaseAddress,
186 res->Data.Memory24.RangeLength));
187 set->set_memoryrange(dev, context,
188 res->Data.Memory24.MinBaseAddress,
189 res->Data.Memory24.MaxBaseAddress,
190 res->Data.Memory24.RangeLength,
191 res->Data.Memory24.Alignment);
194 case ACPI_RSTYPE_IRQ:
197 * "This structure is repeated for each separate interrupt
200 set->set_irq(dev, context, res->Data.Irq.Interrupts,
201 res->Data.Irq.NumberOfInterrupts, res->Data.Irq.EdgeLevel,
202 res->Data.Irq.ActiveHighLow);
204 case ACPI_RSTYPE_DMA:
207 * "This structure is repeated for each separate dma channel
210 set->set_drq(dev, context, res->Data.Dma.Channels,
211 res->Data.Dma.NumberOfChannels);
213 case ACPI_RSTYPE_START_DPF:
214 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependant functions\n"));
215 set->set_start_dependant(dev, context,
216 res->Data.StartDpf.CompatibilityPriority);
218 case ACPI_RSTYPE_END_DPF:
219 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependant functions\n"));
220 set->set_end_dependant(dev, context);
222 case ACPI_RSTYPE_ADDRESS32:
223 if (res->Data.Address32.AddressLength <= 0)
225 if (res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) {
226 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
227 "ignored Address32 %s producer\n",
228 res->Data.Address32.ResourceType == ACPI_IO_RANGE ?
232 if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE &&
233 res->Data.Address32.ResourceType != ACPI_IO_RANGE) {
234 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
235 "ignored Address32 for non-memory, non-I/O\n"));
239 if (res->Data.Address32.MinAddressFixed == ACPI_ADDRESS_FIXED &&
240 res->Data.Address32.MaxAddressFixed == ACPI_ADDRESS_FIXED) {
242 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
243 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
244 "Address32/Memory 0x%x/%d\n",
245 res->Data.Address32.MinAddressRange,
246 res->Data.Address32.AddressLength));
247 set->set_memory(dev, context,
248 res->Data.Address32.MinAddressRange,
249 res->Data.Address32.AddressLength);
251 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
252 "Address32/IO 0x%x/%d\n",
253 res->Data.Address32.MinAddressRange,
254 res->Data.Address32.AddressLength));
255 set->set_ioport(dev, context,
256 res->Data.Address32.MinAddressRange,
257 res->Data.Address32.AddressLength);
260 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
261 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
262 "Address32/Memory 0x%x-0x%x/%d\n",
263 res->Data.Address32.MinAddressRange,
264 res->Data.Address32.MaxAddressRange,
265 res->Data.Address32.AddressLength));
266 set->set_memoryrange(dev, context,
267 res->Data.Address32.MinAddressRange,
268 res->Data.Address32.MaxAddressRange,
269 res->Data.Address32.AddressLength,
270 res->Data.Address32.Granularity);
272 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
273 "Address32/IO 0x%x-0x%x/%d\n",
274 res->Data.Address32.MinAddressRange,
275 res->Data.Address32.MaxAddressRange,
276 res->Data.Address32.AddressLength));
277 set->set_iorange(dev, context,
278 res->Data.Address32.MinAddressRange,
279 res->Data.Address32.MaxAddressRange,
280 res->Data.Address32.AddressLength,
281 res->Data.Address32.Granularity);
285 case ACPI_RSTYPE_ADDRESS16:
286 if (res->Data.Address16.AddressLength <= 0)
288 if (res->Data.Address16.ProducerConsumer != ACPI_CONSUMER) {
289 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
290 "ignored Address16 %s producer\n",
291 res->Data.Address16.ResourceType == ACPI_IO_RANGE ?
295 if (res->Data.Address16.ResourceType != ACPI_MEMORY_RANGE &&
296 res->Data.Address16.ResourceType != ACPI_IO_RANGE) {
297 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
298 "ignored Address16 for non-memory, non-I/O\n"));
302 if (res->Data.Address16.MinAddressFixed == ACPI_ADDRESS_FIXED &&
303 res->Data.Address16.MaxAddressFixed == ACPI_ADDRESS_FIXED) {
305 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) {
306 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
307 "Address16/Memory 0x%x/%d\n",
308 res->Data.Address16.MinAddressRange,
309 res->Data.Address16.AddressLength));
310 set->set_memory(dev, context,
311 res->Data.Address16.MinAddressRange,
312 res->Data.Address16.AddressLength);
314 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
315 "Address16/IO 0x%x/%d\n",
316 res->Data.Address16.MinAddressRange,
317 res->Data.Address16.AddressLength));
318 set->set_ioport(dev, context,
319 res->Data.Address16.MinAddressRange,
320 res->Data.Address16.AddressLength);
323 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) {
324 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
325 "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);
335 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
336 "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);
348 case ACPI_RSTYPE_ADDRESS64:
349 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
350 "unimplemented Address64 resource\n"));
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 res->Data.ExtendedIrq.EdgeLevel,
357 res->Data.ExtendedIrq.ActiveHighLow);
359 case ACPI_RSTYPE_VENDOR:
360 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
361 "unimplemented VendorSpecific resource\n"));
368 AcpiOsFree(buf.Pointer);
369 set->set_done(dev, context);
370 return_ACPI_STATUS (AE_OK);
374 * Resource-set vectors used to attach _CRS-derived resources
377 static void acpi_res_set_init(device_t dev, void *arg, void **context);
378 static void acpi_res_set_done(device_t dev, void *context);
379 static void acpi_res_set_ioport(device_t dev, void *context,
380 u_int32_t base, u_int32_t length);
381 static void acpi_res_set_iorange(device_t dev, void *context,
382 u_int32_t low, u_int32_t high,
383 u_int32_t length, u_int32_t align);
384 static void acpi_res_set_memory(device_t dev, void *context,
385 u_int32_t base, u_int32_t length);
386 static void acpi_res_set_memoryrange(device_t dev, void *context,
387 u_int32_t low, u_int32_t high,
388 u_int32_t length, u_int32_t align);
389 static void acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq,
390 int count, int trig, int pol);
391 static void acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq,
393 static void acpi_res_set_start_dependant(device_t dev, void *context,
395 static void acpi_res_set_end_dependant(device_t dev, void *context);
397 struct acpi_parse_resource_set acpi_res_parse_set = {
401 acpi_res_set_iorange,
403 acpi_res_set_memoryrange,
406 acpi_res_set_start_dependant,
407 acpi_res_set_end_dependant
410 struct acpi_res_context {
419 acpi_res_set_init(device_t dev, void *arg, void **context)
421 struct acpi_res_context *cp;
423 if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
424 bzero(cp, sizeof(*cp));
431 acpi_res_set_done(device_t dev, void *context)
433 struct acpi_res_context *cp = (struct acpi_res_context *)context;
441 acpi_res_set_ioport(device_t dev, void *context, u_int32_t base,
444 struct acpi_res_context *cp = (struct acpi_res_context *)context;
448 bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
452 acpi_res_set_iorange(device_t dev, void *context, u_int32_t low,
453 u_int32_t high, u_int32_t length, u_int32_t align)
455 struct acpi_res_context *cp = (struct acpi_res_context *)context;
459 device_printf(dev, "I/O range not supported\n");
463 acpi_res_set_memory(device_t dev, void *context, u_int32_t base,
466 struct acpi_res_context *cp = (struct acpi_res_context *)context;
471 bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
475 acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low,
476 u_int32_t high, u_int32_t length, u_int32_t align)
478 struct acpi_res_context *cp = (struct acpi_res_context *)context;
482 device_printf(dev, "memory range not supported\n");
486 acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, int count,
489 struct acpi_res_context *cp = (struct acpi_res_context *)context;
491 if (cp == NULL || irq == NULL)
494 /* This implements no resource relocation. */
498 bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
499 #if 0 /* From FreeBSD-5 XXX */
500 BUS_CONFIG_INTR(dev, *irq, (trig == ACPI_EDGE_SENSITIVE) ?
501 INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
502 INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
507 acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq, int count)
509 struct acpi_res_context *cp = (struct acpi_res_context *)context;
511 if (cp == NULL || drq == NULL)
514 /* This implements no resource relocation. */
518 bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
522 acpi_res_set_start_dependant(device_t dev, void *context, int preference)
524 struct acpi_res_context *cp = (struct acpi_res_context *)context;
528 device_printf(dev, "dependant functions not supported\n");
532 acpi_res_set_end_dependant(device_t dev, void *context)
534 struct acpi_res_context *cp = (struct acpi_res_context *)context;
538 device_printf(dev, "dependant functions not supported\n");
542 * Resource-owning placeholders.
544 * This code "owns" system resource objects that aren't
545 * otherwise useful to devices, and which shouldn't be
548 * Note that some systems claim *all* of the physical address space
549 * with a PNP0C01 device, so we cannot correctly "own" system memory
550 * here (must be done in the SMAP handler on x86 systems, for
554 static int acpi_sysresource_probe(device_t dev);
555 static int acpi_sysresource_attach(device_t dev);
557 static device_method_t acpi_sysresource_methods[] = {
558 /* Device interface */
559 DEVMETHOD(device_probe, acpi_sysresource_probe),
560 DEVMETHOD(device_attach, acpi_sysresource_attach),
565 static driver_t acpi_sysresource_driver = {
567 acpi_sysresource_methods,
571 static devclass_t acpi_sysresource_devclass;
572 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysresource_driver,
573 acpi_sysresource_devclass, 0, 0);
574 MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
577 acpi_sysresource_probe(device_t dev)
579 if (!acpi_disabled("sysresource") && acpi_MatchHid(dev, "PNP0C02"))
580 device_set_desc(dev, "System Resource");
589 acpi_sysresource_attach(device_t dev)
591 struct resource *res;
595 * Suck up all the resources that might have been assigned to us.
596 * Note that it's impossible to tell the difference between a
597 * resource that someone else has claimed, and one that doesn't
600 for (i = 0; i < 100; i++) {
602 res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 0);
604 res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 0);
606 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE);