xref: /freebsd/sys/dev/acpica/acpi_resource.c (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
1 /*-
2  * Copyright (c) 2000 Michael Smith
3  * Copyright (c) 2000 BSDi
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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.
14  *
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
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 #include "opt_acpi.h"
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/bus.h>
33 #include <sys/limits.h>
34 #include <sys/malloc.h>
35 #include <sys/module.h>
36 
37 #include <machine/bus.h>
38 #include <machine/resource.h>
39 #include <sys/rman.h>
40 
41 #include <contrib/dev/acpica/include/acpi.h>
42 #include <contrib/dev/acpica/include/accommon.h>
43 
44 #include <dev/acpica/acpivar.h>
45 
46 #ifdef INTRNG
47 #include "acpi_bus_if.h"
48 #endif
49 
50 /* Hooks for the ACPI CA debugging infrastructure */
51 #define _COMPONENT	ACPI_BUS
52 ACPI_MODULE_NAME("RESOURCE")
53 
54 struct lookup_irq_request {
55     ACPI_RESOURCE *acpi_res;
56     u_int	irq;
57     int		counter;
58     int		rid;
59     int		found;
60     int		checkrid;
61     int		trig;
62     int		pol;
63 };
64 
65 static ACPI_STATUS
66 acpi_lookup_irq_handler(ACPI_RESOURCE *res, void *context)
67 {
68     struct lookup_irq_request *req;
69     size_t len;
70     u_int irqnum, irq, trig, pol;
71 
72     switch (res->Type) {
73     case ACPI_RESOURCE_TYPE_IRQ:
74 	irqnum = res->Data.Irq.InterruptCount;
75 	irq = res->Data.Irq.Interrupts[0];
76 	len = ACPI_RS_SIZE(ACPI_RESOURCE_IRQ);
77 	trig = res->Data.Irq.Triggering;
78 	pol = res->Data.Irq.Polarity;
79 	break;
80     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
81 	irqnum = res->Data.ExtendedIrq.InterruptCount;
82 	irq = res->Data.ExtendedIrq.Interrupts[0];
83 	len = ACPI_RS_SIZE(ACPI_RESOURCE_EXTENDED_IRQ);
84 	trig = res->Data.ExtendedIrq.Triggering;
85 	pol = res->Data.ExtendedIrq.Polarity;
86 	break;
87     default:
88 	return (AE_OK);
89     }
90     if (irqnum != 1)
91 	return (AE_OK);
92     req = (struct lookup_irq_request *)context;
93     if (req->checkrid) {
94 	if (req->counter != req->rid) {
95 	    req->counter++;
96 	    return (AE_OK);
97 	}
98 	KASSERT(irq == req->irq, ("IRQ resources do not match"));
99     } else {
100 	if (req->irq != irq)
101 	    return (AE_OK);
102     }
103     req->found = 1;
104     req->pol = pol;
105     req->trig = trig;
106     if (req->acpi_res != NULL)
107 	bcopy(res, req->acpi_res, len);
108     return (AE_CTRL_TERMINATE);
109 }
110 
111 ACPI_STATUS
112 acpi_lookup_irq_resource(device_t dev, int rid, struct resource *res,
113     ACPI_RESOURCE *acpi_res)
114 {
115     struct lookup_irq_request req;
116     ACPI_STATUS status;
117 
118     req.acpi_res = acpi_res;
119     req.irq = rman_get_start(res);
120     req.counter = 0;
121     req.rid = rid;
122     req.found = 0;
123     req.checkrid = 1;
124     status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
125 	acpi_lookup_irq_handler, &req);
126     if (ACPI_SUCCESS(status) && req.found == 0)
127 	status = AE_NOT_FOUND;
128     return (status);
129 }
130 
131 void
132 acpi_config_intr(device_t dev, ACPI_RESOURCE *res)
133 {
134     u_int irq;
135     int pol, trig;
136 
137     switch (res->Type) {
138     case ACPI_RESOURCE_TYPE_IRQ:
139 	KASSERT(res->Data.Irq.InterruptCount == 1,
140 	    ("%s: multiple interrupts", __func__));
141 	irq = res->Data.Irq.Interrupts[0];
142 	trig = res->Data.Irq.Triggering;
143 	pol = res->Data.Irq.Polarity;
144 	break;
145     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
146 	KASSERT(res->Data.ExtendedIrq.InterruptCount == 1,
147 	    ("%s: multiple interrupts", __func__));
148 	irq = res->Data.ExtendedIrq.Interrupts[0];
149 	trig = res->Data.ExtendedIrq.Triggering;
150 	pol = res->Data.ExtendedIrq.Polarity;
151 	break;
152     default:
153 	panic("%s: bad resource type %u", __func__, res->Type);
154     }
155 
156 #if defined(__amd64__) || defined(__i386__)
157     /*
158      * XXX: Certain BIOSes have buggy AML that specify an IRQ that is
159      * edge-sensitive and active-lo.  However, edge-sensitive IRQs
160      * should be active-hi.  Force IRQs with an ISA IRQ value to be
161      * active-hi instead.
162      */
163     if (irq < 16 && trig == ACPI_EDGE_SENSITIVE && pol == ACPI_ACTIVE_LOW)
164 	pol = ACPI_ACTIVE_HIGH;
165 #endif
166     BUS_CONFIG_INTR(dev, irq, (trig == ACPI_EDGE_SENSITIVE) ?
167 	INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
168 	INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
169 }
170 
171 #ifdef INTRNG
172 int
173 acpi_map_intr(device_t dev, u_int irq, ACPI_HANDLE handle)
174 {
175     struct lookup_irq_request req;
176     int trig, pol;
177 
178     trig = ACPI_LEVEL_SENSITIVE;
179     pol = ACPI_ACTIVE_HIGH;
180     if (handle != NULL) {
181 	req.found = 0;
182 	req.acpi_res = NULL;
183 	req.irq = irq;
184 	req.counter = 0;
185 	req.rid = 0;
186 	req.checkrid = 0;
187 	AcpiWalkResources(handle, "_CRS", acpi_lookup_irq_handler, &req);
188 	if (req.found != 0) {
189 	    trig = req.trig;
190 	    pol = req.pol;
191 	}
192     }
193     return ACPI_BUS_MAP_INTR(device_get_parent(dev), dev, irq,
194 	(trig == ACPI_EDGE_SENSITIVE) ?  INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL,
195 	(pol == ACPI_ACTIVE_HIGH) ?  INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
196 }
197 #endif
198 
199 struct acpi_resource_context {
200     struct acpi_parse_resource_set *set;
201     device_t	dev;
202     void	*context;
203     bool	ignore_producer_flag;
204 };
205 
206 #ifdef ACPI_DEBUG_OUTPUT
207 static const char *
208 acpi_address_range_name(UINT8 ResourceType)
209 {
210     static char buf[16];
211 
212     switch (ResourceType) {
213     case ACPI_MEMORY_RANGE:
214 	    return ("Memory");
215     case ACPI_IO_RANGE:
216 	    return ("IO");
217     case ACPI_BUS_NUMBER_RANGE:
218 	    return ("Bus Number");
219     default:
220 	    snprintf(buf, sizeof(buf), "type %u", ResourceType);
221 	    return (buf);
222     }
223 }
224 #endif
225 
226 static ACPI_STATUS
227 acpi_parse_resource(ACPI_RESOURCE *res, void *context)
228 {
229     struct acpi_parse_resource_set *set;
230     struct acpi_resource_context *arc;
231     UINT64 min, max, length, gran;
232 #ifdef ACPI_DEBUG
233     const char *name;
234 #endif
235     device_t dev;
236 
237     arc = context;
238     dev = arc->dev;
239     set = arc->set;
240 
241     switch (res->Type) {
242     case ACPI_RESOURCE_TYPE_END_TAG:
243 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
244 	break;
245     case ACPI_RESOURCE_TYPE_FIXED_IO:
246 	if (res->Data.FixedIo.AddressLength <= 0)
247 	    break;
248 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
249 	    res->Data.FixedIo.Address, res->Data.FixedIo.AddressLength));
250 	set->set_ioport(dev, arc->context, res->Data.FixedIo.Address,
251 	    res->Data.FixedIo.AddressLength);
252 	break;
253     case ACPI_RESOURCE_TYPE_IO:
254 	if (res->Data.Io.AddressLength <= 0)
255 	    break;
256 	if (res->Data.Io.Minimum == res->Data.Io.Maximum) {
257 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
258 		res->Data.Io.Minimum, res->Data.Io.AddressLength));
259 	    set->set_ioport(dev, arc->context, res->Data.Io.Minimum,
260 		res->Data.Io.AddressLength);
261 	} else {
262 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
263 		res->Data.Io.Minimum, res->Data.Io.Maximum,
264 		res->Data.Io.AddressLength));
265 	    set->set_iorange(dev, arc->context, res->Data.Io.Minimum,
266 		res->Data.Io.Maximum, res->Data.Io.AddressLength,
267 		res->Data.Io.Alignment);
268 	}
269 	break;
270     case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
271 	if (res->Data.FixedMemory32.AddressLength <= 0)
272 	    break;
273 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
274 	    res->Data.FixedMemory32.Address,
275 	    res->Data.FixedMemory32.AddressLength));
276 	set->set_memory(dev, arc->context, res->Data.FixedMemory32.Address,
277 	    res->Data.FixedMemory32.AddressLength);
278 	break;
279     case ACPI_RESOURCE_TYPE_MEMORY32:
280 	if (res->Data.Memory32.AddressLength <= 0)
281 	    break;
282 	if (res->Data.Memory32.Minimum == res->Data.Memory32.Maximum) {
283 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
284 		res->Data.Memory32.Minimum, res->Data.Memory32.AddressLength));
285 	    set->set_memory(dev, arc->context, res->Data.Memory32.Minimum,
286 		res->Data.Memory32.AddressLength);
287 	} else {
288 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
289 		res->Data.Memory32.Minimum, res->Data.Memory32.Maximum,
290 		res->Data.Memory32.AddressLength));
291 	    set->set_memoryrange(dev, arc->context, res->Data.Memory32.Minimum,
292 		res->Data.Memory32.Maximum, res->Data.Memory32.AddressLength,
293 		res->Data.Memory32.Alignment);
294 	}
295 	break;
296     case ACPI_RESOURCE_TYPE_MEMORY24:
297 	if (res->Data.Memory24.AddressLength <= 0)
298 	    break;
299 	if (res->Data.Memory24.Minimum == res->Data.Memory24.Maximum) {
300 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
301 		res->Data.Memory24.Minimum, res->Data.Memory24.AddressLength));
302 	    set->set_memory(dev, arc->context, res->Data.Memory24.Minimum,
303 		res->Data.Memory24.AddressLength);
304 	} else {
305 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
306 		res->Data.Memory24.Minimum, res->Data.Memory24.Maximum,
307 		res->Data.Memory24.AddressLength));
308 	    set->set_memoryrange(dev, arc->context, res->Data.Memory24.Minimum,
309 		res->Data.Memory24.Maximum, res->Data.Memory24.AddressLength,
310 		res->Data.Memory24.Alignment);
311 	}
312 	break;
313     case ACPI_RESOURCE_TYPE_IRQ:
314 	/*
315 	 * from 1.0b 6.4.2
316 	 * "This structure is repeated for each separate interrupt
317 	 * required"
318 	 */
319 	set->set_irq(dev, arc->context, res->Data.Irq.Interrupts,
320 	    res->Data.Irq.InterruptCount, res->Data.Irq.Triggering,
321 	    res->Data.Irq.Polarity);
322 	break;
323     case ACPI_RESOURCE_TYPE_DMA:
324 	/*
325 	 * from 1.0b 6.4.3
326 	 * "This structure is repeated for each separate DMA channel
327 	 * required"
328 	 */
329 	set->set_drq(dev, arc->context, res->Data.Dma.Channels,
330 	    res->Data.Dma.ChannelCount);
331 	break;
332     case ACPI_RESOURCE_TYPE_START_DEPENDENT:
333 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependent functions\n"));
334 	set->set_start_dependent(dev, arc->context,
335 	    res->Data.StartDpf.CompatibilityPriority);
336 	break;
337     case ACPI_RESOURCE_TYPE_END_DEPENDENT:
338 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependent functions\n"));
339 	set->set_end_dependent(dev, arc->context);
340 	break;
341     case ACPI_RESOURCE_TYPE_ADDRESS16:
342     case ACPI_RESOURCE_TYPE_ADDRESS32:
343     case ACPI_RESOURCE_TYPE_ADDRESS64:
344     case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
345 	switch (res->Type) {
346 	case ACPI_RESOURCE_TYPE_ADDRESS16:
347 	    gran = res->Data.Address16.Address.Granularity;
348 	    min = res->Data.Address16.Address.Minimum;
349 	    max = res->Data.Address16.Address.Maximum;
350 	    length = res->Data.Address16.Address.AddressLength;
351 #ifdef ACPI_DEBUG
352 	    name = "Address16";
353 #endif
354 	    break;
355 	case ACPI_RESOURCE_TYPE_ADDRESS32:
356 	    gran = res->Data.Address32.Address.Granularity;
357 	    min = res->Data.Address32.Address.Minimum;
358 	    max = res->Data.Address32.Address.Maximum;
359 	    length = res->Data.Address32.Address.AddressLength;
360 #ifdef ACPI_DEBUG
361 	    name = "Address32";
362 #endif
363 	    break;
364 	case ACPI_RESOURCE_TYPE_ADDRESS64:
365 	    gran = res->Data.Address64.Address.Granularity;
366 	    min = res->Data.Address64.Address.Minimum;
367 	    max = res->Data.Address64.Address.Maximum;
368 	    length = res->Data.Address64.Address.AddressLength;
369 #ifdef ACPI_DEBUG
370 	    name = "Address64";
371 #endif
372 	    break;
373 	default:
374 	    KASSERT(res->Type == ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64,
375 		("should never happen"));
376 	    gran = res->Data.ExtAddress64.Address.Granularity;
377 	    min = res->Data.ExtAddress64.Address.Minimum;
378 	    max = res->Data.ExtAddress64.Address.Maximum;
379 	    length = res->Data.ExtAddress64.Address.AddressLength;
380 #ifdef ACPI_DEBUG
381 	    name = "ExtAddress64";
382 #endif
383 	    break;
384 	}
385 	if (length <= 0)
386 	    break;
387 	if (!arc->ignore_producer_flag &&
388 	    res->Data.Address.ProducerConsumer != ACPI_CONSUMER) {
389 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
390 		"ignored %s %s producer\n", name,
391 		acpi_address_range_name(res->Data.Address.ResourceType)));
392 	    break;
393 	}
394 	if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE &&
395 	    res->Data.Address.ResourceType != ACPI_IO_RANGE) {
396 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
397 		"ignored %s for non-memory, non-I/O\n", name));
398 	    break;
399 	}
400 
401 #ifdef __i386__
402 	if (min > ULONG_MAX || (res->Data.Address.MaxAddressFixed && max >
403 	    ULONG_MAX)) {
404 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored %s above 4G\n",
405 		name));
406 	    break;
407 	}
408 	if (max > ULONG_MAX)
409 		max = ULONG_MAX;
410 #endif
411 	if (res->Data.Address.MinAddressFixed == ACPI_ADDRESS_FIXED &&
412 	    res->Data.Address.MaxAddressFixed == ACPI_ADDRESS_FIXED) {
413 	    if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE) {
414 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/Memory 0x%jx/%ju\n",
415 		    name, (uintmax_t)min, (uintmax_t)length));
416 		set->set_memory(dev, arc->context, min, length);
417 	    } else {
418 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx/%ju\n", name,
419 		    (uintmax_t)min, (uintmax_t)length));
420 		set->set_ioport(dev, arc->context, min, length);
421 	    }
422 	} else if (res->Data.Address.MinAddressFixed != ACPI_ADDRESS_FIXED &&
423 	    res->Data.Address.MaxAddressFixed != ACPI_ADDRESS_FIXED) {
424 	    /* Fixed size, variable location resource descriptor */
425 	    min = roundup(min, gran + 1);
426 	    if ((min + length - 1) > max) {
427 		device_printf(dev,
428 		    "invalid memory range: start: %jx end: %jx max: %jx\n",
429 		    (uintmax_t)min, (uintmax_t)(min + length - 1),
430 		    (uintmax_t)max);
431 	    } else {
432 		if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE) {
433 		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
434 			"%s/Memory 0x%jx/%ju\n", name, (uintmax_t)min,
435 			(uintmax_t)length));
436 		    set->set_memory(dev, arc->context, min, length);
437 		} else {
438 		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx/%ju\n",
439 			name, (uintmax_t)min, (uintmax_t)length));
440 		    set->set_ioport(dev, arc->context, min, length);
441 		}
442 	    }
443 	} else {
444 	    if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
445 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
446 		    "%s/Memory 0x%jx-0x%jx/%ju\n", name, (uintmax_t)min,
447 		    (uintmax_t)max, (uintmax_t)length));
448 		set->set_memoryrange(dev, arc->context, min, max, length, gran);
449 	    } else {
450 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx-0x%jx/%ju\n",
451 		    name, (uintmax_t)min, (uintmax_t)max, (uintmax_t)length));
452 		set->set_iorange(dev, arc->context, min, max, length, gran);
453 	    }
454 	}
455 	break;
456     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
457 	if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) {
458 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored ExtIRQ producer\n"));
459 	    break;
460 	}
461 	set->set_ext_irq(dev, arc->context, res->Data.ExtendedIrq.Interrupts,
462 	    res->Data.ExtendedIrq.InterruptCount,
463 	    res->Data.ExtendedIrq.Triggering, res->Data.ExtendedIrq.Polarity);
464 	break;
465     case ACPI_RESOURCE_TYPE_VENDOR:
466 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
467 	    "unimplemented VendorSpecific resource\n"));
468 	break;
469     default:
470 	break;
471     }
472     return (AE_OK);
473 }
474 
475 /*
476  * Fetch a device's resources and associate them with the device.
477  *
478  * Note that it might be nice to also locate ACPI-specific resource items, such
479  * as GPE bits.
480  *
481  * We really need to split the resource-fetching code out from the
482  * resource-parsing code, since we may want to use the parsing
483  * code for _PRS someday.
484  */
485 ACPI_STATUS
486 acpi_parse_resources(device_t dev, ACPI_HANDLE handle,
487 		     struct acpi_parse_resource_set *set, void *arg)
488 {
489     struct acpi_resource_context arc;
490     ACPI_STATUS		status;
491 
492     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
493 
494     set->set_init(dev, arg, &arc.context);
495     arc.set = set;
496     arc.dev = dev;
497     arc.ignore_producer_flag = false;
498 
499     /*
500      * UARTs on ThunderX2 set ResourceProducer on memory resources, with
501      * 7.2 firmware.
502      */
503     if (acpi_MatchHid(handle, "ARMH0011") != ACPI_MATCHHID_NOMATCH)
504 	    arc.ignore_producer_flag = true;
505 
506     /*
507      * ARM Coresight on N1SDP set ResourceProducer on memory resources.
508      * Coresight devices: ETM, STM, TPIU, ETF/ETR, REP, FUN.
509      */
510     if (acpi_MatchHid(handle, "ARMHC500") != ACPI_MATCHHID_NOMATCH ||
511         acpi_MatchHid(handle, "ARMHC502") != ACPI_MATCHHID_NOMATCH ||
512         acpi_MatchHid(handle, "ARMHC600") != ACPI_MATCHHID_NOMATCH ||
513         acpi_MatchHid(handle, "ARMHC979") != ACPI_MATCHHID_NOMATCH ||
514         acpi_MatchHid(handle, "ARMHC97C") != ACPI_MATCHHID_NOMATCH ||
515         acpi_MatchHid(handle, "ARMHC98D") != ACPI_MATCHHID_NOMATCH ||
516         acpi_MatchHid(handle, "ARMHC9FF") != ACPI_MATCHHID_NOMATCH ||
517         acpi_MatchHid(handle, "ARMHD620") != ACPI_MATCHHID_NOMATCH)
518 	    arc.ignore_producer_flag = true;
519 
520     status = AcpiWalkResources(handle, "_CRS", acpi_parse_resource, &arc);
521     if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
522 	printf("can't fetch resources for %s - %s\n",
523 	    acpi_name(handle), AcpiFormatException(status));
524 	return_ACPI_STATUS (status);
525     }
526     set->set_done(dev, arc.context);
527     return_ACPI_STATUS (AE_OK);
528 }
529 
530 /*
531  * Resource-set vectors used to attach _CRS-derived resources
532  * to an ACPI device.
533  */
534 static void	acpi_res_set_init(device_t dev, void *arg, void **context);
535 static void	acpi_res_set_done(device_t dev, void *context);
536 static void	acpi_res_set_ioport(device_t dev, void *context,
537 				    uint64_t base, uint64_t length);
538 static void	acpi_res_set_iorange(device_t dev, void *context,
539 				     uint64_t low, uint64_t high,
540 				     uint64_t length, uint64_t align);
541 static void	acpi_res_set_memory(device_t dev, void *context,
542 				    uint64_t base, uint64_t length);
543 static void	acpi_res_set_memoryrange(device_t dev, void *context,
544 					 uint64_t low, uint64_t high,
545 					 uint64_t length, uint64_t align);
546 static void	acpi_res_set_irq(device_t dev, void *context, uint8_t *irq,
547 				 int count, int trig, int pol);
548 static void	acpi_res_set_ext_irq(device_t dev, void *context,
549 				 uint32_t *irq, int count, int trig, int pol);
550 static void	acpi_res_set_drq(device_t dev, void *context, uint8_t *drq,
551 				 int count);
552 static void	acpi_res_set_start_dependent(device_t dev, void *context,
553 					     int preference);
554 static void	acpi_res_set_end_dependent(device_t dev, void *context);
555 
556 struct acpi_parse_resource_set acpi_res_parse_set = {
557     acpi_res_set_init,
558     acpi_res_set_done,
559     acpi_res_set_ioport,
560     acpi_res_set_iorange,
561     acpi_res_set_memory,
562     acpi_res_set_memoryrange,
563     acpi_res_set_irq,
564     acpi_res_set_ext_irq,
565     acpi_res_set_drq,
566     acpi_res_set_start_dependent,
567     acpi_res_set_end_dependent
568 };
569 
570 struct acpi_res_context {
571     int		ar_nio;
572     int		ar_nmem;
573     int		ar_nirq;
574     int		ar_ndrq;
575     void 	*ar_parent;
576 };
577 
578 static void
579 acpi_res_set_init(device_t dev, void *arg, void **context)
580 {
581     struct acpi_res_context	*cp;
582 
583     if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
584 	bzero(cp, sizeof(*cp));
585 	cp->ar_parent = arg;
586 	*context = cp;
587     }
588 }
589 
590 static void
591 acpi_res_set_done(device_t dev, void *context)
592 {
593     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
594 
595     if (cp == NULL)
596 	return;
597     AcpiOsFree(cp);
598 }
599 
600 static void
601 acpi_res_set_ioport(device_t dev, void *context, uint64_t base,
602 		    uint64_t length)
603 {
604     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
605 
606     if (cp == NULL)
607 	return;
608     bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
609 }
610 
611 static void
612 acpi_res_set_iorange(device_t dev, void *context, uint64_t low,
613 		     uint64_t high, uint64_t length, uint64_t align)
614 {
615     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
616 
617     if (cp == NULL)
618 	return;
619 
620     /*
621      * XXX: Some BIOSes contain buggy _CRS entries where fixed I/O
622      * ranges have the maximum base address (_MAX) to the end of the
623      * I/O range instead of the start.  These are then treated as a
624      * relocatable I/O range rather than a fixed I/O resource.  As a
625      * workaround, treat I/O resources encoded this way as fixed I/O
626      * ports.
627      */
628     if (high == (low + length)) {
629 	if (bootverbose)
630 	    device_printf(dev,
631 		"_CRS has fixed I/O port range defined as relocatable\n");
632 
633 	bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, low, length);
634 	return;
635     }
636 
637     device_printf(dev, "I/O range not supported\n");
638 }
639 
640 static void
641 acpi_res_set_memory(device_t dev, void *context, uint64_t base,
642 		    uint64_t length)
643 {
644     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
645 
646     if (cp == NULL)
647 	return;
648     bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
649 }
650 
651 static void
652 acpi_res_set_memoryrange(device_t dev, void *context, uint64_t low,
653 			 uint64_t high, uint64_t length, uint64_t align)
654 {
655     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
656 
657     if (cp == NULL)
658 	return;
659     device_printf(dev, "memory range not supported\n");
660 }
661 
662 static void
663 acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count,
664     int trig, int pol)
665 {
666     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
667     int i;
668 
669     if (cp == NULL || irq == NULL)
670 	return;
671 
672     for (i = 0; i < count; i++)
673         bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, irq[i], 1);
674 }
675 
676 static void
677 acpi_res_set_ext_irq(device_t dev, void *context, uint32_t *irq, int count,
678     int trig, int pol)
679 {
680     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
681     int i;
682 
683     if (cp == NULL || irq == NULL)
684 	return;
685 
686     for (i = 0; i < count; i++)
687         bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, irq[i], 1);
688 }
689 
690 static void
691 acpi_res_set_drq(device_t dev, void *context, uint8_t *drq, int count)
692 {
693     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
694 
695     if (cp == NULL || drq == NULL)
696 	return;
697 
698     /* This implements no resource relocation. */
699     if (count != 1)
700 	return;
701 
702     bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
703 }
704 
705 static void
706 acpi_res_set_start_dependent(device_t dev, void *context, int preference)
707 {
708     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
709 
710     if (cp == NULL)
711 	return;
712     device_printf(dev, "dependent functions not supported\n");
713 }
714 
715 static void
716 acpi_res_set_end_dependent(device_t dev, void *context)
717 {
718     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
719 
720     if (cp == NULL)
721 	return;
722     device_printf(dev, "dependent functions not supported\n");
723 }
724 
725 /*
726  * Resource-owning placeholders for IO and memory pseudo-devices.
727  *
728  * This code allocates system resources that will be used by ACPI
729  * child devices.  The acpi parent manages these resources through a
730  * private rman.
731  */
732 
733 static int	acpi_sysres_rid = 100;
734 
735 static int	acpi_sysres_probe(device_t dev);
736 static int	acpi_sysres_attach(device_t dev);
737 
738 static device_method_t acpi_sysres_methods[] = {
739     /* Device interface */
740     DEVMETHOD(device_probe,	acpi_sysres_probe),
741     DEVMETHOD(device_attach,	acpi_sysres_attach),
742 
743     DEVMETHOD_END
744 };
745 
746 static driver_t acpi_sysres_driver = {
747     "acpi_sysresource",
748     acpi_sysres_methods,
749     0,
750 };
751 
752 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, 0, 0);
753 MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
754 
755 static int
756 acpi_sysres_probe(device_t dev)
757 {
758     static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
759     int rv;
760 
761     if (acpi_disabled("sysresource"))
762 	return (ENXIO);
763     rv = ACPI_ID_PROBE(device_get_parent(dev), dev, sysres_ids, NULL);
764     if (rv > 0){
765 	return (rv);
766     }
767     device_set_desc(dev, "System Resource");
768     device_quiet(dev);
769     return (rv);
770 }
771 
772 static int
773 acpi_sysres_attach(device_t dev)
774 {
775     device_t bus;
776     struct resource_list_entry *bus_rle, *dev_rle;
777     struct resource_list *bus_rl, *dev_rl;
778     int done, type;
779     rman_res_t start, end, count;
780 
781     /*
782      * Loop through all current resources to see if the new one overlaps
783      * any existing ones.  If so, grow the old one up and/or down
784      * accordingly.  Discard any that are wholly contained in the old.  If
785      * the resource is unique, add it to the parent.  It will later go into
786      * the rman pool.
787      */
788     bus = device_get_parent(dev);
789     dev_rl = BUS_GET_RESOURCE_LIST(bus, dev);
790     bus_rl = BUS_GET_RESOURCE_LIST(device_get_parent(bus), bus);
791     STAILQ_FOREACH(dev_rle, dev_rl, link) {
792 	if (dev_rle->type != SYS_RES_IOPORT && dev_rle->type != SYS_RES_MEMORY)
793 	    continue;
794 
795 	start = dev_rle->start;
796 	end = dev_rle->end;
797 	count = dev_rle->count;
798 	type = dev_rle->type;
799 	done = FALSE;
800 
801 	STAILQ_FOREACH(bus_rle, bus_rl, link) {
802 	    if (bus_rle->type != type)
803 		continue;
804 
805 	    /* New resource wholly contained in old, discard. */
806 	    if (start >= bus_rle->start && end <= bus_rle->end)
807 		break;
808 
809 	    /* New tail overlaps old head, grow existing resource downward. */
810 	    if (start < bus_rle->start && end >= bus_rle->start) {
811 		bus_rle->count += bus_rle->start - start;
812 		bus_rle->start = start;
813 		done = TRUE;
814 	    }
815 
816 	    /* New head overlaps old tail, grow existing resource upward. */
817 	    if (start <= bus_rle->end && end > bus_rle->end) {
818 		bus_rle->count += end - bus_rle->end;
819 		bus_rle->end = end;
820 		done = TRUE;
821 	    }
822 
823 	    /* If we adjusted the old resource, we're finished. */
824 	    if (done)
825 		break;
826 	}
827 
828 	/* If we didn't merge with anything, add this resource. */
829 	if (bus_rle == NULL)
830 	    bus_set_resource(bus, type, acpi_sysres_rid++, start, count);
831     }
832 
833     /* After merging/moving resources to the parent, free the list. */
834     resource_list_free(dev_rl);
835 
836     return (0);
837 }
838