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