acpi_resource.c revision 253392
1104862Sru/*-
2104862Sru * Copyright (c) 2000 Michael Smith
3104862Sru * Copyright (c) 2000 BSDi
4104862Sru * All rights reserved.
5104862Sru *
6104862Sru * Redistribution and use in source and binary forms, with or without
7104862Sru * modification, are permitted provided that the following conditions
8104862Sru * are met:
9104862Sru * 1. Redistributions of source code must retain the above copyright
10104862Sru *    notice, this list of conditions and the following disclaimer.
11104862Sru * 2. Redistributions in binary form must reproduce the above copyright
12104862Sru *    notice, this list of conditions and the following disclaimer in the
13104862Sru *    documentation and/or other materials provided with the distribution.
14104862Sru *
15104862Sru * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16104862Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17104862Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18104862Sru * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19104862Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20104862Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21104862Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22104862Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23104862Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24104862Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25104862Sru * SUCH DAMAGE.
26104862Sru */
27104862Sru
28104862Sru#include <sys/cdefs.h>
29104862Sru__FBSDID("$FreeBSD: head/sys/dev/acpica/acpi_resource.c 253392 2013-07-16 14:42:16Z jhb $");
30104862Sru
31104862Sru#include "opt_acpi.h"
32104862Sru#include <sys/param.h>
33104862Sru#include <sys/kernel.h>
34104862Sru#include <sys/bus.h>
35104862Sru#include <sys/limits.h>
36104862Sru#include <sys/malloc.h>
37104862Sru#include <sys/module.h>
38104862Sru
39104862Sru#include <machine/bus.h>
40104862Sru#include <machine/resource.h>
41104862Sru#include <sys/rman.h>
42104862Sru
43104862Sru#include <contrib/dev/acpica/include/acpi.h>
44104862Sru#include <contrib/dev/acpica/include/accommon.h>
45104862Sru
46104862Sru#include <dev/acpica/acpivar.h>
47104862Sru
48104862Sru/* Hooks for the ACPI CA debugging infrastructure */
49104862Sru#define _COMPONENT	ACPI_BUS
50104862SruACPI_MODULE_NAME("RESOURCE")
51104862Sru
52104862Srustruct lookup_irq_request {
53104862Sru    ACPI_RESOURCE *acpi_res;
54104862Sru    struct resource *res;
55104862Sru    int		counter;
56104862Sru    int		rid;
57104862Sru    int		found;
58104862Sru};
59104862Sru
60104862Srustatic ACPI_STATUS
61104862Sruacpi_lookup_irq_handler(ACPI_RESOURCE *res, void *context)
62104862Sru{
63104862Sru    struct lookup_irq_request *req;
64104862Sru    size_t len;
65104862Sru    u_int irqnum, irq;
66104862Sru
67104862Sru    switch (res->Type) {
68104862Sru    case ACPI_RESOURCE_TYPE_IRQ:
69104862Sru	irqnum = res->Data.Irq.InterruptCount;
70104862Sru	irq = res->Data.Irq.Interrupts[0];
71104862Sru	len = ACPI_RS_SIZE(ACPI_RESOURCE_IRQ);
72104862Sru	break;
73104862Sru    case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
74104862Sru	irqnum = res->Data.ExtendedIrq.InterruptCount;
75104862Sru	irq = res->Data.ExtendedIrq.Interrupts[0];
76104862Sru	len = ACPI_RS_SIZE(ACPI_RESOURCE_EXTENDED_IRQ);
77104862Sru	break;
78104862Sru    default:
79104862Sru	return (AE_OK);
80104862Sru    }
81104862Sru    if (irqnum != 1)
82104862Sru	return (AE_OK);
83104862Sru    req = (struct lookup_irq_request *)context;
84104862Sru    if (req->counter != req->rid) {
85104862Sru	req->counter++;
86104862Sru	return (AE_OK);
87104862Sru    }
88104862Sru    req->found = 1;
89104862Sru    KASSERT(irq == rman_get_start(req->res),
90104862Sru	("IRQ resources do not match"));
91104862Sru    bcopy(res, req->acpi_res, len);
92104862Sru    return (AE_CTRL_TERMINATE);
93104862Sru}
94104862Sru
95104862SruACPI_STATUS
96104862Sruacpi_lookup_irq_resource(device_t dev, int rid, struct resource *res,
97104862Sru    ACPI_RESOURCE *acpi_res)
98104862Sru{
99104862Sru    struct lookup_irq_request req;
100104862Sru    ACPI_STATUS status;
101104862Sru
102104862Sru    req.acpi_res = acpi_res;
103104862Sru    req.res = res;
104104862Sru    req.counter = 0;
105104862Sru    req.rid = rid;
106104862Sru    req.found = 0;
107104862Sru    status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
108104862Sru	acpi_lookup_irq_handler, &req);
109104862Sru    if (ACPI_SUCCESS(status) && req.found == 0)
110104862Sru	status = AE_NOT_FOUND;
111104862Sru    return (status);
112104862Sru}
113104862Sru
114104862Sruvoid
115104862Sruacpi_config_intr(device_t dev, ACPI_RESOURCE *res)
116104862Sru{
117104862Sru    u_int irq;
118104862Sru    int pol, trig;
119104862Sru
120104862Sru    switch (res->Type) {
121104862Sru    case ACPI_RESOURCE_TYPE_IRQ:
122104862Sru	KASSERT(res->Data.Irq.InterruptCount == 1,
123104862Sru	    ("%s: multiple interrupts", __func__));
124104862Sru	irq = res->Data.Irq.Interrupts[0];
125104862Sru	trig = res->Data.Irq.Triggering;
126104862Sru	pol = res->Data.Irq.Polarity;
127104862Sru	break;
128104862Sru    case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
129104862Sru	KASSERT(res->Data.ExtendedIrq.InterruptCount == 1,
130104862Sru	    ("%s: multiple interrupts", __func__));
131104862Sru	irq = res->Data.ExtendedIrq.Interrupts[0];
132104862Sru	trig = res->Data.ExtendedIrq.Triggering;
133104862Sru	pol = res->Data.ExtendedIrq.Polarity;
134104862Sru	break;
135104862Sru    default:
136104862Sru	panic("%s: bad resource type %u", __func__, res->Type);
137104862Sru    }
138104862Sru
139104862Sru#if defined(__amd64__) || defined(__i386__)
140104862Sru    /*
141104862Sru     * XXX: Certain BIOSes have buggy AML that specify an IRQ that is
142104862Sru     * edge-sensitive and active-lo.  However, edge-sensitive IRQs
143104862Sru     * should be active-hi.  Force IRQs with an ISA IRQ value to be
144104862Sru     * active-hi instead.
145104862Sru     */
146104862Sru    if (irq < 16 && trig == ACPI_EDGE_SENSITIVE && pol == ACPI_ACTIVE_LOW)
147104862Sru	pol = ACPI_ACTIVE_HIGH;
148104862Sru#endif
149104862Sru    BUS_CONFIG_INTR(dev, irq, (trig == ACPI_EDGE_SENSITIVE) ?
150104862Sru	INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
151104862Sru	INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
152104862Sru}
153104862Sru
154104862Srustruct acpi_resource_context {
155104862Sru    struct acpi_parse_resource_set *set;
156104862Sru    device_t	dev;
157104862Sru    void	*context;
158104862Sru};
159104862Sru
160104862Sru#ifdef ACPI_DEBUG_OUTPUT
161104862Srustatic const char *
162104862Sruacpi_address_range_name(UINT8 ResourceType)
163104862Sru{
164104862Sru    static char buf[16];
165104862Sru
166104862Sru    switch (ResourceType) {
167104862Sru    case ACPI_MEMORY_RANGE:
168104862Sru	    return ("Memory");
169104862Sru    case ACPI_IO_RANGE:
170104862Sru	    return ("IO");
171104862Sru    case ACPI_BUS_NUMBER_RANGE:
172104862Sru	    return ("Bus Number");
173104862Sru    default:
174104862Sru	    snprintf(buf, sizeof(buf), "type %u", ResourceType);
175104862Sru	    return (buf);
176104862Sru    }
177104862Sru}
178104862Sru#endif
179104862Sru
180104862Srustatic ACPI_STATUS
181104862Sruacpi_parse_resource(ACPI_RESOURCE *res, void *context)
182104862Sru{
183104862Sru    struct acpi_parse_resource_set *set;
184104862Sru    struct acpi_resource_context *arc;
185104862Sru    UINT64 min, max, length, gran;
186104862Sru    const char *name;
187104862Sru    device_t dev;
188104862Sru
189104862Sru    arc = context;
190104862Sru    dev = arc->dev;
191104862Sru    set = arc->set;
192104862Sru
193104862Sru    switch (res->Type) {
194104862Sru    case ACPI_RESOURCE_TYPE_END_TAG:
195104862Sru	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
196104862Sru	break;
197104862Sru    case ACPI_RESOURCE_TYPE_FIXED_IO:
198104862Sru	if (res->Data.FixedIo.AddressLength <= 0)
199104862Sru	    break;
200104862Sru	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
201104862Sru	    res->Data.FixedIo.Address, res->Data.FixedIo.AddressLength));
202104862Sru	set->set_ioport(dev, arc->context, res->Data.FixedIo.Address,
203104862Sru	    res->Data.FixedIo.AddressLength);
204104862Sru	break;
205104862Sru    case ACPI_RESOURCE_TYPE_IO:
206104862Sru	if (res->Data.Io.AddressLength <= 0)
207104862Sru	    break;
208104862Sru	if (res->Data.Io.Minimum == res->Data.Io.Maximum) {
209104862Sru	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
210104862Sru		res->Data.Io.Minimum, res->Data.Io.AddressLength));
211104862Sru	    set->set_ioport(dev, arc->context, res->Data.Io.Minimum,
212104862Sru		res->Data.Io.AddressLength);
213104862Sru	} else {
214104862Sru	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
215104862Sru		res->Data.Io.Minimum, res->Data.Io.Maximum,
216104862Sru		res->Data.Io.AddressLength));
217104862Sru	    set->set_iorange(dev, arc->context, res->Data.Io.Minimum,
218104862Sru		res->Data.Io.Maximum, res->Data.Io.AddressLength,
219104862Sru		res->Data.Io.Alignment);
220104862Sru	}
221104862Sru	break;
222104862Sru    case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
223104862Sru	if (res->Data.FixedMemory32.AddressLength <= 0)
224104862Sru	    break;
225104862Sru	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
226104862Sru	    res->Data.FixedMemory32.Address,
227104862Sru	    res->Data.FixedMemory32.AddressLength));
228104862Sru	set->set_memory(dev, arc->context, res->Data.FixedMemory32.Address,
229104862Sru	    res->Data.FixedMemory32.AddressLength);
230104862Sru	break;
231104862Sru    case ACPI_RESOURCE_TYPE_MEMORY32:
232104862Sru	if (res->Data.Memory32.AddressLength <= 0)
233104862Sru	    break;
234104862Sru	if (res->Data.Memory32.Minimum == res->Data.Memory32.Maximum) {
235104862Sru	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
236104862Sru		res->Data.Memory32.Minimum, res->Data.Memory32.AddressLength));
237104862Sru	    set->set_memory(dev, arc->context, res->Data.Memory32.Minimum,
238104862Sru		res->Data.Memory32.AddressLength);
239104862Sru	} else {
240104862Sru	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
241104862Sru		res->Data.Memory32.Minimum, res->Data.Memory32.Maximum,
242104862Sru		res->Data.Memory32.AddressLength));
243104862Sru	    set->set_memoryrange(dev, arc->context, res->Data.Memory32.Minimum,
244104862Sru		res->Data.Memory32.Maximum, res->Data.Memory32.AddressLength,
245104862Sru		res->Data.Memory32.Alignment);
246104862Sru	}
247104862Sru	break;
248104862Sru    case ACPI_RESOURCE_TYPE_MEMORY24:
249104862Sru	if (res->Data.Memory24.AddressLength <= 0)
250104862Sru	    break;
251104862Sru	if (res->Data.Memory24.Minimum == res->Data.Memory24.Maximum) {
252104862Sru	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
253104862Sru		res->Data.Memory24.Minimum, res->Data.Memory24.AddressLength));
254104862Sru	    set->set_memory(dev, arc->context, res->Data.Memory24.Minimum,
255104862Sru		res->Data.Memory24.AddressLength);
256104862Sru	} else {
257104862Sru	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
258104862Sru		res->Data.Memory24.Minimum, res->Data.Memory24.Maximum,
259104862Sru		res->Data.Memory24.AddressLength));
260104862Sru	    set->set_memoryrange(dev, arc->context, res->Data.Memory24.Minimum,
261104862Sru		res->Data.Memory24.Maximum, res->Data.Memory24.AddressLength,
262104862Sru		res->Data.Memory24.Alignment);
263104862Sru	}
264104862Sru	break;
265104862Sru    case ACPI_RESOURCE_TYPE_IRQ:
266104862Sru	/*
267104862Sru	 * from 1.0b 6.4.2
268104862Sru	 * "This structure is repeated for each separate interrupt
269104862Sru	 * required"
270104862Sru	 */
271104862Sru	set->set_irq(dev, arc->context, res->Data.Irq.Interrupts,
272104862Sru	    res->Data.Irq.InterruptCount, res->Data.Irq.Triggering,
273104862Sru	    res->Data.Irq.Polarity);
274104862Sru	break;
275104862Sru    case ACPI_RESOURCE_TYPE_DMA:
276104862Sru	/*
277104862Sru	 * from 1.0b 6.4.3
278104862Sru	 * "This structure is repeated for each separate DMA channel
279104862Sru	 * required"
280104862Sru	 */
281104862Sru	set->set_drq(dev, arc->context, res->Data.Dma.Channels,
282104862Sru	    res->Data.Dma.ChannelCount);
283104862Sru	break;
284104862Sru    case ACPI_RESOURCE_TYPE_START_DEPENDENT:
285104862Sru	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependent functions\n"));
286104862Sru	set->set_start_dependent(dev, arc->context,
287104862Sru	    res->Data.StartDpf.CompatibilityPriority);
288104862Sru	break;
289104862Sru    case ACPI_RESOURCE_TYPE_END_DEPENDENT:
290104862Sru	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependent functions\n"));
291104862Sru	set->set_end_dependent(dev, arc->context);
292104862Sru	break;
293104862Sru    case ACPI_RESOURCE_TYPE_ADDRESS16:
294104862Sru    case ACPI_RESOURCE_TYPE_ADDRESS32:
295104862Sru    case ACPI_RESOURCE_TYPE_ADDRESS64:
296104862Sru    case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
297104862Sru	switch (res->Type) {
298104862Sru	case ACPI_RESOURCE_TYPE_ADDRESS16:
299104862Sru	    gran = res->Data.Address16.Granularity;
300104862Sru	    min = res->Data.Address16.Minimum;
301104862Sru	    max = res->Data.Address16.Maximum;
302104862Sru	    length = res->Data.Address16.AddressLength;
303104862Sru	    name = "Address16";
304104862Sru	    break;
305104862Sru	case ACPI_RESOURCE_TYPE_ADDRESS32:
306104862Sru	    gran = res->Data.Address32.Granularity;
307104862Sru	    min = res->Data.Address32.Minimum;
308104862Sru	    max = res->Data.Address32.Maximum;
309104862Sru	    length = res->Data.Address32.AddressLength;
310104862Sru	    name = "Address32";
311104862Sru	    break;
312104862Sru	case ACPI_RESOURCE_TYPE_ADDRESS64:
313104862Sru	    gran = res->Data.Address64.Granularity;
314104862Sru	    min = res->Data.Address64.Minimum;
315104862Sru	    max = res->Data.Address64.Maximum;
316104862Sru	    length = res->Data.Address64.AddressLength;
317104862Sru	    name = "Address64";
318104862Sru	    break;
319104862Sru	default:
320104862Sru	    KASSERT(res->Type == ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64,
321104862Sru		("should never happen"));
322104862Sru	    gran = res->Data.ExtAddress64.Granularity;
323104862Sru	    min = res->Data.ExtAddress64.Minimum;
324104862Sru	    max = res->Data.ExtAddress64.Maximum;
325104862Sru	    length = res->Data.ExtAddress64.AddressLength;
326104862Sru	    name = "ExtAddress64";
327104862Sru	    break;
328104862Sru	}
329104862Sru	if (length <= 0)
330104862Sru	    break;
331104862Sru	if (res->Data.Address.ProducerConsumer != ACPI_CONSUMER) {
332104862Sru	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
333104862Sru		"ignored %s %s producer\n", name,
334104862Sru		acpi_address_range_name(res->Data.Address.ResourceType)));
335104862Sru	    break;
336104862Sru	}
337104862Sru	if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE &&
338104862Sru	    res->Data.Address.ResourceType != ACPI_IO_RANGE) {
339104862Sru	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
340104862Sru		"ignored %s for non-memory, non-I/O\n", name));
341104862Sru	    break;
342104862Sru	}
343104862Sru
344104862Sru#ifdef __i386__
345104862Sru	if (min > ULONG_MAX || (res->Data.Address.MaxAddressFixed && max >
346104862Sru	    ULONG_MAX)) {
347104862Sru	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored %s above 4G\n",
348104862Sru		name));
349104862Sru	    break;
350104862Sru	}
351104862Sru	if (max > ULONG_MAX)
352104862Sru		max = ULONG_MAX;
353104862Sru#endif
354104862Sru	if (res->Data.Address.MinAddressFixed == ACPI_ADDRESS_FIXED &&
355104862Sru	    res->Data.Address.MaxAddressFixed == ACPI_ADDRESS_FIXED) {
356104862Sru	    if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE) {
357104862Sru		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/Memory 0x%jx/%ju\n",
358104862Sru		    name, (uintmax_t)min, (uintmax_t)length));
359104862Sru		set->set_memory(dev, arc->context, min, length);
360104862Sru	    } else {
361104862Sru		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx/%ju\n", name,
362104862Sru		    (uintmax_t)min, (uintmax_t)length));
363104862Sru		set->set_ioport(dev, arc->context, min, length);
364104862Sru	    }
365104862Sru	} else {
366104862Sru	    if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
367104862Sru		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
368104862Sru		    "%s/Memory 0x%jx-0x%jx/%ju\n", name, (uintmax_t)min,
369104862Sru		    (uintmax_t)max, (uintmax_t)length));
370104862Sru		set->set_memoryrange(dev, arc->context, min, max, length, gran);
371104862Sru	    } else {
372104862Sru		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx-0x%jx/%ju\n",
373104862Sru		    name, (uintmax_t)min, (uintmax_t)max, (uintmax_t)length));
374104862Sru		set->set_iorange(dev, arc->context, min, max, length, gran);
375104862Sru	    }
376104862Sru	}
377104862Sru	break;
378104862Sru    case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
379104862Sru	if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) {
380104862Sru	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored ExtIRQ producer\n"));
381104862Sru	    break;
382104862Sru	}
383104862Sru	set->set_ext_irq(dev, arc->context, res->Data.ExtendedIrq.Interrupts,
384104862Sru	    res->Data.ExtendedIrq.InterruptCount,
385104862Sru	    res->Data.ExtendedIrq.Triggering, res->Data.ExtendedIrq.Polarity);
386104862Sru	break;
387104862Sru    case ACPI_RESOURCE_TYPE_VENDOR:
388104862Sru	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
389104862Sru	    "unimplemented VendorSpecific resource\n"));
390104862Sru	break;
391104862Sru    default:
392104862Sru	break;
393104862Sru    }
394104862Sru    return (AE_OK);
395104862Sru}
396104862Sru
397104862Sru/*
398104862Sru * Fetch a device's resources and associate them with the device.
399104862Sru *
400104862Sru * Note that it might be nice to also locate ACPI-specific resource items, such
401104862Sru * as GPE bits.
402104862Sru *
403104862Sru * We really need to split the resource-fetching code out from the
404104862Sru * resource-parsing code, since we may want to use the parsing
405104862Sru * code for _PRS someday.
406104862Sru */
407104862SruACPI_STATUS
408104862Sruacpi_parse_resources(device_t dev, ACPI_HANDLE handle,
409104862Sru		     struct acpi_parse_resource_set *set, void *arg)
410104862Sru{
411104862Sru    struct acpi_resource_context arc;
412104862Sru    ACPI_STATUS		status;
413104862Sru
414104862Sru    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
415104862Sru
416104862Sru    set->set_init(dev, arg, &arc.context);
417104862Sru    arc.set = set;
418104862Sru    arc.dev = dev;
419104862Sru    status = AcpiWalkResources(handle, "_CRS", acpi_parse_resource, &arc);
420104862Sru    if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
421104862Sru	printf("can't fetch resources for %s - %s\n",
422104862Sru	    acpi_name(handle), AcpiFormatException(status));
423104862Sru	return_ACPI_STATUS (status);
424104862Sru    }
425104862Sru    set->set_done(dev, arc.context);
426104862Sru    return_ACPI_STATUS (AE_OK);
427104862Sru}
428104862Sru
429104862Sru/*
430104862Sru * Resource-set vectors used to attach _CRS-derived resources
431104862Sru * to an ACPI device.
432104862Sru */
433104862Srustatic void	acpi_res_set_init(device_t dev, void *arg, void **context);
434104862Srustatic void	acpi_res_set_done(device_t dev, void *context);
435104862Srustatic void	acpi_res_set_ioport(device_t dev, void *context,
436104862Sru				    uint64_t base, uint64_t length);
437104862Srustatic void	acpi_res_set_iorange(device_t dev, void *context,
438104862Sru				     uint64_t low, uint64_t high,
439104862Sru				     uint64_t length, uint64_t align);
440104862Srustatic void	acpi_res_set_memory(device_t dev, void *context,
441104862Sru				    uint64_t base, uint64_t length);
442104862Srustatic void	acpi_res_set_memoryrange(device_t dev, void *context,
443104862Sru					 uint64_t low, uint64_t high,
444104862Sru					 uint64_t length, uint64_t align);
445104862Srustatic void	acpi_res_set_irq(device_t dev, void *context, uint8_t *irq,
446104862Sru				 int count, int trig, int pol);
447104862Srustatic void	acpi_res_set_ext_irq(device_t dev, void *context,
448104862Sru				 uint32_t *irq, int count, int trig, int pol);
449104862Srustatic void	acpi_res_set_drq(device_t dev, void *context, uint8_t *drq,
450104862Sru				 int count);
451104862Srustatic void	acpi_res_set_start_dependent(device_t dev, void *context,
452104862Sru					     int preference);
453104862Srustatic void	acpi_res_set_end_dependent(device_t dev, void *context);
454104862Sru
455104862Srustruct acpi_parse_resource_set acpi_res_parse_set = {
456104862Sru    acpi_res_set_init,
457104862Sru    acpi_res_set_done,
458104862Sru    acpi_res_set_ioport,
459104862Sru    acpi_res_set_iorange,
460104862Sru    acpi_res_set_memory,
461104862Sru    acpi_res_set_memoryrange,
462104862Sru    acpi_res_set_irq,
463104862Sru    acpi_res_set_ext_irq,
464104862Sru    acpi_res_set_drq,
465104862Sru    acpi_res_set_start_dependent,
466104862Sru    acpi_res_set_end_dependent
467104862Sru};
468104862Sru
469104862Srustruct acpi_res_context {
470104862Sru    int		ar_nio;
471104862Sru    int		ar_nmem;
472104862Sru    int		ar_nirq;
473104862Sru    int		ar_ndrq;
474104862Sru    void 	*ar_parent;
475104862Sru};
476104862Sru
477104862Srustatic void
478104862Sruacpi_res_set_init(device_t dev, void *arg, void **context)
479104862Sru{
480104862Sru    struct acpi_res_context	*cp;
481104862Sru
482104862Sru    if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
483104862Sru	bzero(cp, sizeof(*cp));
484104862Sru	cp->ar_parent = arg;
485104862Sru	*context = cp;
486104862Sru    }
487104862Sru}
488104862Sru
489104862Srustatic void
490104862Sruacpi_res_set_done(device_t dev, void *context)
491104862Sru{
492104862Sru    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
493104862Sru
494104862Sru    if (cp == NULL)
495104862Sru	return;
496104862Sru    AcpiOsFree(cp);
497104862Sru}
498104862Sru
499104862Srustatic void
500104862Sruacpi_res_set_ioport(device_t dev, void *context, uint64_t base,
501104862Sru		    uint64_t length)
502104862Sru{
503104862Sru    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
504104862Sru
505104862Sru    if (cp == NULL)
506104862Sru	return;
507104862Sru    bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
508104862Sru}
509104862Sru
510104862Srustatic void
511104862Sruacpi_res_set_iorange(device_t dev, void *context, uint64_t low,
512104862Sru		     uint64_t high, uint64_t length, uint64_t align)
513104862Sru{
514104862Sru    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
515104862Sru
516104862Sru    if (cp == NULL)
517104862Sru	return;
518104862Sru    device_printf(dev, "I/O range not supported\n");
519104862Sru}
520104862Sru
521104862Srustatic void
522104862Sruacpi_res_set_memory(device_t dev, void *context, uint64_t base,
523104862Sru		    uint64_t length)
524104862Sru{
525104862Sru    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
526104862Sru
527104862Sru    if (cp == NULL)
528104862Sru	return;
529104862Sru
530104862Sru    bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
531104862Sru}
532104862Sru
533104862Srustatic void
534104862Sruacpi_res_set_memoryrange(device_t dev, void *context, uint64_t low,
535104862Sru			 uint64_t high, uint64_t length, uint64_t align)
536104862Sru{
537104862Sru    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
538104862Sru
539104862Sru    if (cp == NULL)
540104862Sru	return;
541104862Sru    device_printf(dev, "memory range not supported\n");
542104862Sru}
543104862Sru
544104862Srustatic void
545104862Sruacpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count,
546104862Sru    int trig, int pol)
547104862Sru{
548104862Sru    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
549104862Sru
550104862Sru    if (cp == NULL || irq == NULL)
551104862Sru	return;
552104862Sru
553104862Sru    /* This implements no resource relocation. */
554104862Sru    if (count != 1)
555104862Sru	return;
556104862Sru
557104862Sru    bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
558104862Sru}
559104862Sru
560104862Srustatic void
561104862Sruacpi_res_set_ext_irq(device_t dev, void *context, uint32_t *irq, int count,
562104862Sru    int trig, int pol)
563104862Sru{
564104862Sru    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
565104862Sru
566104862Sru    if (cp == NULL || irq == NULL)
567104862Sru	return;
568104862Sru
569104862Sru    /* This implements no resource relocation. */
570104862Sru    if (count != 1)
571104862Sru	return;
572104862Sru
573104862Sru    bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
574104862Sru}
575104862Sru
576104862Srustatic void
577104862Sruacpi_res_set_drq(device_t dev, void *context, uint8_t *drq, int count)
578104862Sru{
579104862Sru    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
580104862Sru
581104862Sru    if (cp == NULL || drq == NULL)
582104862Sru	return;
583104862Sru
584104862Sru    /* This implements no resource relocation. */
585104862Sru    if (count != 1)
586104862Sru	return;
587104862Sru
588104862Sru    bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
589104862Sru}
590104862Sru
591104862Srustatic void
592104862Sruacpi_res_set_start_dependent(device_t dev, void *context, int preference)
593104862Sru{
594104862Sru    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
595104862Sru
596    if (cp == NULL)
597	return;
598    device_printf(dev, "dependent functions not supported\n");
599}
600
601static void
602acpi_res_set_end_dependent(device_t dev, void *context)
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
611/*
612 * Resource-owning placeholders for IO and memory pseudo-devices.
613 *
614 * This code allocates system resources that will be used by ACPI
615 * child devices.  The acpi parent manages these resources through a
616 * private rman.
617 */
618
619static int	acpi_sysres_rid = 100;
620
621static int	acpi_sysres_probe(device_t dev);
622static int	acpi_sysres_attach(device_t dev);
623
624static device_method_t acpi_sysres_methods[] = {
625    /* Device interface */
626    DEVMETHOD(device_probe,	acpi_sysres_probe),
627    DEVMETHOD(device_attach,	acpi_sysres_attach),
628
629    DEVMETHOD_END
630};
631
632static driver_t acpi_sysres_driver = {
633    "acpi_sysresource",
634    acpi_sysres_methods,
635    0,
636};
637
638static devclass_t acpi_sysres_devclass;
639DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, acpi_sysres_devclass,
640    0, 0);
641MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
642
643static int
644acpi_sysres_probe(device_t dev)
645{
646    static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
647
648    if (acpi_disabled("sysresource") ||
649	ACPI_ID_PROBE(device_get_parent(dev), dev, sysres_ids) == NULL)
650	return (ENXIO);
651
652    device_set_desc(dev, "System Resource");
653    device_quiet(dev);
654    return (BUS_PROBE_DEFAULT);
655}
656
657static int
658acpi_sysres_attach(device_t dev)
659{
660    device_t bus;
661    struct resource_list_entry *bus_rle, *dev_rle;
662    struct resource_list *bus_rl, *dev_rl;
663    int done, type;
664    u_long start, end, count;
665
666    /*
667     * Loop through all current resources to see if the new one overlaps
668     * any existing ones.  If so, grow the old one up and/or down
669     * accordingly.  Discard any that are wholly contained in the old.  If
670     * the resource is unique, add it to the parent.  It will later go into
671     * the rman pool.
672     */
673    bus = device_get_parent(dev);
674    dev_rl = BUS_GET_RESOURCE_LIST(bus, dev);
675    bus_rl = BUS_GET_RESOURCE_LIST(device_get_parent(bus), bus);
676    STAILQ_FOREACH(dev_rle, dev_rl, link) {
677	if (dev_rle->type != SYS_RES_IOPORT && dev_rle->type != SYS_RES_MEMORY)
678	    continue;
679
680	start = dev_rle->start;
681	end = dev_rle->end;
682	count = dev_rle->count;
683	type = dev_rle->type;
684	done = FALSE;
685
686	STAILQ_FOREACH(bus_rle, bus_rl, link) {
687	    if (bus_rle->type != type)
688		continue;
689
690	    /* New resource wholly contained in old, discard. */
691	    if (start >= bus_rle->start && end <= bus_rle->end)
692		break;
693
694	    /* New tail overlaps old head, grow existing resource downward. */
695	    if (start < bus_rle->start && end >= bus_rle->start) {
696		bus_rle->count += bus_rle->start - start;
697		bus_rle->start = start;
698		done = TRUE;
699	    }
700
701	    /* New head overlaps old tail, grow existing resource upward. */
702	    if (start <= bus_rle->end && end > bus_rle->end) {
703		bus_rle->count += end - bus_rle->end;
704		bus_rle->end = end;
705		done = TRUE;
706	    }
707
708	    /* If we adjusted the old resource, we're finished. */
709	    if (done)
710		break;
711	}
712
713	/* If we didn't merge with anything, add this resource. */
714	if (bus_rle == NULL)
715	    bus_set_resource(bus, type, acpi_sysres_rid++, start, count);
716    }
717
718    /* After merging/moving resources to the parent, free the list. */
719    resource_list_free(dev_rl);
720
721    return (0);
722}
723