xref: /freebsd/sys/dev/acpica/acpi_resource.c (revision 4b9d6057)
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     /*
521      * The DesignWare I2C Controller on Ampere Altra sets ResourceProducer on
522      * memory resources.
523      */
524     if (acpi_MatchHid(handle, "APMC0D0F") != ACPI_MATCHHID_NOMATCH)
525 	    arc.ignore_producer_flag = true;
526 
527     status = AcpiWalkResources(handle, "_CRS", acpi_parse_resource, &arc);
528     if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
529 	printf("can't fetch resources for %s - %s\n",
530 	    acpi_name(handle), AcpiFormatException(status));
531 	return_ACPI_STATUS (status);
532     }
533     set->set_done(dev, arc.context);
534     return_ACPI_STATUS (AE_OK);
535 }
536 
537 /*
538  * Resource-set vectors used to attach _CRS-derived resources
539  * to an ACPI device.
540  */
541 static void	acpi_res_set_init(device_t dev, void *arg, void **context);
542 static void	acpi_res_set_done(device_t dev, void *context);
543 static void	acpi_res_set_ioport(device_t dev, void *context,
544 				    uint64_t base, uint64_t length);
545 static void	acpi_res_set_iorange(device_t dev, void *context,
546 				     uint64_t low, uint64_t high,
547 				     uint64_t length, uint64_t align);
548 static void	acpi_res_set_memory(device_t dev, void *context,
549 				    uint64_t base, uint64_t length);
550 static void	acpi_res_set_memoryrange(device_t dev, void *context,
551 					 uint64_t low, uint64_t high,
552 					 uint64_t length, uint64_t align);
553 static void	acpi_res_set_irq(device_t dev, void *context, uint8_t *irq,
554 				 int count, int trig, int pol);
555 static void	acpi_res_set_ext_irq(device_t dev, void *context,
556 				 uint32_t *irq, int count, int trig, int pol);
557 static void	acpi_res_set_drq(device_t dev, void *context, uint8_t *drq,
558 				 int count);
559 static void	acpi_res_set_start_dependent(device_t dev, void *context,
560 					     int preference);
561 static void	acpi_res_set_end_dependent(device_t dev, void *context);
562 
563 struct acpi_parse_resource_set acpi_res_parse_set = {
564     acpi_res_set_init,
565     acpi_res_set_done,
566     acpi_res_set_ioport,
567     acpi_res_set_iorange,
568     acpi_res_set_memory,
569     acpi_res_set_memoryrange,
570     acpi_res_set_irq,
571     acpi_res_set_ext_irq,
572     acpi_res_set_drq,
573     acpi_res_set_start_dependent,
574     acpi_res_set_end_dependent
575 };
576 
577 struct acpi_res_context {
578     int		ar_nio;
579     int		ar_nmem;
580     int		ar_nirq;
581     int		ar_ndrq;
582     void 	*ar_parent;
583 };
584 
585 static void
586 acpi_res_set_init(device_t dev, void *arg, void **context)
587 {
588     struct acpi_res_context	*cp;
589 
590     if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
591 	bzero(cp, sizeof(*cp));
592 	cp->ar_parent = arg;
593 	*context = cp;
594     }
595 }
596 
597 static void
598 acpi_res_set_done(device_t dev, void *context)
599 {
600     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
601 
602     if (cp == NULL)
603 	return;
604     AcpiOsFree(cp);
605 }
606 
607 static void
608 acpi_res_set_ioport(device_t dev, void *context, uint64_t base,
609 		    uint64_t length)
610 {
611     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
612 
613     if (cp == NULL)
614 	return;
615     bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
616 }
617 
618 static void
619 acpi_res_set_iorange(device_t dev, void *context, uint64_t low,
620 		     uint64_t high, uint64_t length, uint64_t align)
621 {
622     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
623 
624     if (cp == NULL)
625 	return;
626 
627     /*
628      * XXX: Some BIOSes contain buggy _CRS entries where fixed I/O
629      * ranges have the maximum base address (_MAX) to the end of the
630      * I/O range instead of the start.  These are then treated as a
631      * relocatable I/O range rather than a fixed I/O resource.  As a
632      * workaround, treat I/O resources encoded this way as fixed I/O
633      * ports.
634      */
635     if (high == (low + length)) {
636 	if (bootverbose)
637 	    device_printf(dev,
638 		"_CRS has fixed I/O port range defined as relocatable\n");
639 
640 	bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, low, length);
641 	return;
642     }
643 
644     device_printf(dev, "I/O range not supported\n");
645 }
646 
647 static void
648 acpi_res_set_memory(device_t dev, void *context, uint64_t base,
649 		    uint64_t length)
650 {
651     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
652 
653     if (cp == NULL)
654 	return;
655     bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
656 }
657 
658 static void
659 acpi_res_set_memoryrange(device_t dev, void *context, uint64_t low,
660 			 uint64_t high, uint64_t length, uint64_t align)
661 {
662     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
663 
664     if (cp == NULL)
665 	return;
666     device_printf(dev, "memory range not supported\n");
667 }
668 
669 static void
670 acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count,
671     int trig, int pol)
672 {
673     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
674     int i;
675 
676     if (cp == NULL || irq == NULL)
677 	return;
678 
679     for (i = 0; i < count; i++)
680         bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, irq[i], 1);
681 }
682 
683 static void
684 acpi_res_set_ext_irq(device_t dev, void *context, uint32_t *irq, int count,
685     int trig, int pol)
686 {
687     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
688     int i;
689 
690     if (cp == NULL || irq == NULL)
691 	return;
692 
693     for (i = 0; i < count; i++)
694         bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, irq[i], 1);
695 }
696 
697 static void
698 acpi_res_set_drq(device_t dev, void *context, uint8_t *drq, int count)
699 {
700     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
701 
702     if (cp == NULL || drq == NULL)
703 	return;
704 
705     /* This implements no resource relocation. */
706     if (count != 1)
707 	return;
708 
709     bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
710 }
711 
712 static void
713 acpi_res_set_start_dependent(device_t dev, void *context, int preference)
714 {
715     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
716 
717     if (cp == NULL)
718 	return;
719     device_printf(dev, "dependent functions not supported\n");
720 }
721 
722 static void
723 acpi_res_set_end_dependent(device_t dev, void *context)
724 {
725     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
726 
727     if (cp == NULL)
728 	return;
729     device_printf(dev, "dependent functions not supported\n");
730 }
731 
732 /*
733  * Resource-owning placeholders for IO and memory pseudo-devices.
734  *
735  * This code allocates system resources that will be used by ACPI
736  * child devices.  The acpi parent manages these resources through a
737  * private rman.
738  */
739 
740 static int	acpi_sysres_rid = 100;
741 
742 static int	acpi_sysres_probe(device_t dev);
743 static int	acpi_sysres_attach(device_t dev);
744 
745 static device_method_t acpi_sysres_methods[] = {
746     /* Device interface */
747     DEVMETHOD(device_probe,	acpi_sysres_probe),
748     DEVMETHOD(device_attach,	acpi_sysres_attach),
749 
750     DEVMETHOD_END
751 };
752 
753 static driver_t acpi_sysres_driver = {
754     "acpi_sysresource",
755     acpi_sysres_methods,
756     0,
757 };
758 
759 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, 0, 0);
760 MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
761 
762 static int
763 acpi_sysres_probe(device_t dev)
764 {
765     static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
766     int rv;
767 
768     if (acpi_disabled("sysresource"))
769 	return (ENXIO);
770     rv = ACPI_ID_PROBE(device_get_parent(dev), dev, sysres_ids, NULL);
771     if (rv > 0){
772 	return (rv);
773     }
774     device_set_desc(dev, "System Resource");
775     device_quiet(dev);
776     return (rv);
777 }
778 
779 static int
780 acpi_sysres_attach(device_t dev)
781 {
782     device_t bus;
783     struct resource_list_entry *bus_rle, *dev_rle;
784     struct resource_list *bus_rl, *dev_rl;
785     int done, type;
786     rman_res_t start, end, count;
787 
788     /*
789      * Loop through all current resources to see if the new one overlaps
790      * any existing ones.  If so, grow the old one up and/or down
791      * accordingly.  Discard any that are wholly contained in the old.  If
792      * the resource is unique, add it to the parent.  It will later go into
793      * the rman pool.
794      */
795     bus = device_get_parent(dev);
796     dev_rl = BUS_GET_RESOURCE_LIST(bus, dev);
797     bus_rl = BUS_GET_RESOURCE_LIST(device_get_parent(bus), bus);
798     STAILQ_FOREACH(dev_rle, dev_rl, link) {
799 	if (dev_rle->type != SYS_RES_IOPORT && dev_rle->type != SYS_RES_MEMORY)
800 	    continue;
801 
802 	start = dev_rle->start;
803 	end = dev_rle->end;
804 	count = dev_rle->count;
805 	type = dev_rle->type;
806 	done = FALSE;
807 
808 	STAILQ_FOREACH(bus_rle, bus_rl, link) {
809 	    if (bus_rle->type != type)
810 		continue;
811 
812 	    /* New resource wholly contained in old, discard. */
813 	    if (start >= bus_rle->start && end <= bus_rle->end)
814 		break;
815 
816 	    /* New tail overlaps old head, grow existing resource downward. */
817 	    if (start < bus_rle->start && end >= bus_rle->start) {
818 		bus_rle->count += bus_rle->start - start;
819 		bus_rle->start = start;
820 		done = TRUE;
821 	    }
822 
823 	    /* New head overlaps old tail, grow existing resource upward. */
824 	    if (start <= bus_rle->end && end > bus_rle->end) {
825 		bus_rle->count += end - bus_rle->end;
826 		bus_rle->end = end;
827 		done = TRUE;
828 	    }
829 
830 	    /* If we adjusted the old resource, we're finished. */
831 	    if (done)
832 		break;
833 	}
834 
835 	/* If we didn't merge with anything, add this resource. */
836 	if (bus_rle == NULL)
837 	    bus_set_resource(bus, type, acpi_sysres_rid++, start, count);
838     }
839 
840     /* After merging/moving resources to the parent, free the list. */
841     resource_list_free(dev_rl);
842 
843     return (0);
844 }
845