acpi_resource.c revision 246128
1251881Speter/*-
2251881Speter * Copyright (c) 2000 Michael Smith
3251881Speter * Copyright (c) 2000 BSDi
4251881Speter * All rights reserved.
5251881Speter *
6251881Speter * Redistribution and use in source and binary forms, with or without
7251881Speter * modification, are permitted provided that the following conditions
8251881Speter * are met:
9251881Speter * 1. Redistributions of source code must retain the above copyright
10251881Speter *    notice, this list of conditions and the following disclaimer.
11251881Speter * 2. Redistributions in binary form must reproduce the above copyright
12251881Speter *    notice, this list of conditions and the following disclaimer in the
13251881Speter *    documentation and/or other materials provided with the distribution.
14251881Speter *
15251881Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16251881Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18251881Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25251881Speter * SUCH DAMAGE.
26251881Speter */
27251881Speter
28251881Speter#include <sys/cdefs.h>
29251881Speter__FBSDID("$FreeBSD: head/sys/dev/acpica/acpi_resource.c 246128 2013-01-30 18:01:20Z sbz $");
30251881Speter
31251881Speter#include "opt_acpi.h"
32251881Speter#include <sys/param.h>
33251881Speter#include <sys/kernel.h>
34251881Speter#include <sys/bus.h>
35251881Speter#include <sys/limits.h>
36251881Speter#include <sys/malloc.h>
37251881Speter#include <sys/module.h>
38251881Speter
39251881Speter#include <machine/bus.h>
40251881Speter#include <machine/resource.h>
41251881Speter#include <sys/rman.h>
42251881Speter
43251881Speter#include <contrib/dev/acpica/include/acpi.h>
44251881Speter#include <contrib/dev/acpica/include/accommon.h>
45251881Speter
46251881Speter#include <dev/acpica/acpivar.h>
47251881Speter
48251881Speter/* Hooks for the ACPI CA debugging infrastructure */
49251881Speter#define _COMPONENT	ACPI_BUS
50251881SpeterACPI_MODULE_NAME("RESOURCE")
51251881Speter
52251881Speterstruct lookup_irq_request {
53251881Speter    ACPI_RESOURCE *acpi_res;
54251881Speter    struct resource *res;
55251881Speter    int		counter;
56251881Speter    int		rid;
57251881Speter    int		found;
58251881Speter};
59251881Speter
60251881Speterstatic ACPI_STATUS
61251881Speteracpi_lookup_irq_handler(ACPI_RESOURCE *res, void *context)
62251881Speter{
63251881Speter    struct lookup_irq_request *req;
64251881Speter    size_t len;
65251881Speter    u_int irqnum, irq;
66251881Speter
67251881Speter    switch (res->Type) {
68251881Speter    case ACPI_RESOURCE_TYPE_IRQ:
69251881Speter	irqnum = res->Data.Irq.InterruptCount;
70251881Speter	irq = res->Data.Irq.Interrupts[0];
71251881Speter	len = ACPI_RS_SIZE(ACPI_RESOURCE_IRQ);
72251881Speter	break;
73251881Speter    case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
74251881Speter	irqnum = res->Data.ExtendedIrq.InterruptCount;
75251881Speter	irq = res->Data.ExtendedIrq.Interrupts[0];
76251881Speter	len = ACPI_RS_SIZE(ACPI_RESOURCE_EXTENDED_IRQ);
77251881Speter	break;
78251881Speter    default:
79251881Speter	return (AE_OK);
80251881Speter    }
81251881Speter    if (irqnum != 1)
82251881Speter	return (AE_OK);
83251881Speter    req = (struct lookup_irq_request *)context;
84251881Speter    if (req->counter != req->rid) {
85251881Speter	req->counter++;
86251881Speter	return (AE_OK);
87251881Speter    }
88251881Speter    req->found = 1;
89251881Speter    KASSERT(irq == rman_get_start(req->res),
90251881Speter	("IRQ resources do not match"));
91251881Speter    bcopy(res, req->acpi_res, len);
92251881Speter    return (AE_CTRL_TERMINATE);
93251881Speter}
94251881Speter
95251881SpeterACPI_STATUS
96251881Speteracpi_lookup_irq_resource(device_t dev, int rid, struct resource *res,
97251881Speter    ACPI_RESOURCE *acpi_res)
98251881Speter{
99251881Speter    struct lookup_irq_request req;
100251881Speter    ACPI_STATUS status;
101251881Speter
102251881Speter    req.acpi_res = acpi_res;
103251881Speter    req.res = res;
104251881Speter    req.counter = 0;
105251881Speter    req.rid = rid;
106251881Speter    req.found = 0;
107251881Speter    status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
108251881Speter	acpi_lookup_irq_handler, &req);
109251881Speter    if (ACPI_SUCCESS(status) && req.found == 0)
110251881Speter	status = AE_NOT_FOUND;
111251881Speter    return (status);
112251881Speter}
113251881Speter
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    BUS_CONFIG_INTR(dev, irq, (trig == ACPI_EDGE_SENSITIVE) ?
139	INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
140	INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
141}
142
143struct acpi_resource_context {
144    struct acpi_parse_resource_set *set;
145    device_t	dev;
146    void	*context;
147};
148
149#ifdef ACPI_DEBUG_OUTPUT
150static const char *
151acpi_address_range_name(UINT8 ResourceType)
152{
153    static char buf[16];
154
155    switch (ResourceType) {
156    case ACPI_MEMORY_RANGE:
157	    return ("Memory");
158    case ACPI_IO_RANGE:
159	    return ("IO");
160    case ACPI_BUS_NUMBER_RANGE:
161	    return ("Bus Number");
162    default:
163	    snprintf(buf, sizeof(buf), "type %u", ResourceType);
164	    return (buf);
165    }
166}
167#endif
168
169static ACPI_STATUS
170acpi_parse_resource(ACPI_RESOURCE *res, void *context)
171{
172    struct acpi_parse_resource_set *set;
173    struct acpi_resource_context *arc;
174    UINT64 min, max, length, gran;
175    const char *name;
176    device_t dev;
177
178    arc = context;
179    dev = arc->dev;
180    set = arc->set;
181
182    switch (res->Type) {
183    case ACPI_RESOURCE_TYPE_END_TAG:
184	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
185	break;
186    case ACPI_RESOURCE_TYPE_FIXED_IO:
187	if (res->Data.FixedIo.AddressLength <= 0)
188	    break;
189	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
190	    res->Data.FixedIo.Address, res->Data.FixedIo.AddressLength));
191	set->set_ioport(dev, arc->context, res->Data.FixedIo.Address,
192	    res->Data.FixedIo.AddressLength);
193	break;
194    case ACPI_RESOURCE_TYPE_IO:
195	if (res->Data.Io.AddressLength <= 0)
196	    break;
197	if (res->Data.Io.Minimum == res->Data.Io.Maximum) {
198	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
199		res->Data.Io.Minimum, res->Data.Io.AddressLength));
200	    set->set_ioport(dev, arc->context, res->Data.Io.Minimum,
201		res->Data.Io.AddressLength);
202	} else {
203	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
204		res->Data.Io.Minimum, res->Data.Io.Maximum,
205		res->Data.Io.AddressLength));
206	    set->set_iorange(dev, arc->context, res->Data.Io.Minimum,
207		res->Data.Io.Maximum, res->Data.Io.AddressLength,
208		res->Data.Io.Alignment);
209	}
210	break;
211    case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
212	if (res->Data.FixedMemory32.AddressLength <= 0)
213	    break;
214	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
215	    res->Data.FixedMemory32.Address,
216	    res->Data.FixedMemory32.AddressLength));
217	set->set_memory(dev, arc->context, res->Data.FixedMemory32.Address,
218	    res->Data.FixedMemory32.AddressLength);
219	break;
220    case ACPI_RESOURCE_TYPE_MEMORY32:
221	if (res->Data.Memory32.AddressLength <= 0)
222	    break;
223	if (res->Data.Memory32.Minimum == res->Data.Memory32.Maximum) {
224	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
225		res->Data.Memory32.Minimum, res->Data.Memory32.AddressLength));
226	    set->set_memory(dev, arc->context, res->Data.Memory32.Minimum,
227		res->Data.Memory32.AddressLength);
228	} else {
229	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
230		res->Data.Memory32.Minimum, res->Data.Memory32.Maximum,
231		res->Data.Memory32.AddressLength));
232	    set->set_memoryrange(dev, arc->context, res->Data.Memory32.Minimum,
233		res->Data.Memory32.Maximum, res->Data.Memory32.AddressLength,
234		res->Data.Memory32.Alignment);
235	}
236	break;
237    case ACPI_RESOURCE_TYPE_MEMORY24:
238	if (res->Data.Memory24.AddressLength <= 0)
239	    break;
240	if (res->Data.Memory24.Minimum == res->Data.Memory24.Maximum) {
241	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
242		res->Data.Memory24.Minimum, res->Data.Memory24.AddressLength));
243	    set->set_memory(dev, arc->context, res->Data.Memory24.Minimum,
244		res->Data.Memory24.AddressLength);
245	} else {
246	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
247		res->Data.Memory24.Minimum, res->Data.Memory24.Maximum,
248		res->Data.Memory24.AddressLength));
249	    set->set_memoryrange(dev, arc->context, res->Data.Memory24.Minimum,
250		res->Data.Memory24.Maximum, res->Data.Memory24.AddressLength,
251		res->Data.Memory24.Alignment);
252	}
253	break;
254    case ACPI_RESOURCE_TYPE_IRQ:
255	/*
256	 * from 1.0b 6.4.2
257	 * "This structure is repeated for each separate interrupt
258	 * required"
259	 */
260	set->set_irq(dev, arc->context, res->Data.Irq.Interrupts,
261	    res->Data.Irq.InterruptCount, res->Data.Irq.Triggering,
262	    res->Data.Irq.Polarity);
263	break;
264    case ACPI_RESOURCE_TYPE_DMA:
265	/*
266	 * from 1.0b 6.4.3
267	 * "This structure is repeated for each separate DMA channel
268	 * required"
269	 */
270	set->set_drq(dev, arc->context, res->Data.Dma.Channels,
271	    res->Data.Dma.ChannelCount);
272	break;
273    case ACPI_RESOURCE_TYPE_START_DEPENDENT:
274	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependent functions\n"));
275	set->set_start_dependent(dev, arc->context,
276	    res->Data.StartDpf.CompatibilityPriority);
277	break;
278    case ACPI_RESOURCE_TYPE_END_DEPENDENT:
279	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependent functions\n"));
280	set->set_end_dependent(dev, arc->context);
281	break;
282    case ACPI_RESOURCE_TYPE_ADDRESS16:
283    case ACPI_RESOURCE_TYPE_ADDRESS32:
284    case ACPI_RESOURCE_TYPE_ADDRESS64:
285    case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
286	switch (res->Type) {
287	case ACPI_RESOURCE_TYPE_ADDRESS16:
288	    gran = res->Data.Address16.Granularity;
289	    min = res->Data.Address16.Minimum;
290	    max = res->Data.Address16.Maximum;
291	    length = res->Data.Address16.AddressLength;
292	    name = "Address16";
293	    break;
294	case ACPI_RESOURCE_TYPE_ADDRESS32:
295	    gran = res->Data.Address32.Granularity;
296	    min = res->Data.Address32.Minimum;
297	    max = res->Data.Address32.Maximum;
298	    length = res->Data.Address32.AddressLength;
299	    name = "Address32";
300	    break;
301	case ACPI_RESOURCE_TYPE_ADDRESS64:
302	    gran = res->Data.Address64.Granularity;
303	    min = res->Data.Address64.Minimum;
304	    max = res->Data.Address64.Maximum;
305	    length = res->Data.Address64.AddressLength;
306	    name = "Address64";
307	    break;
308	default:
309	    KASSERT(res->Type == ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64,
310		("should never happen"));
311	    gran = res->Data.ExtAddress64.Granularity;
312	    min = res->Data.ExtAddress64.Minimum;
313	    max = res->Data.ExtAddress64.Maximum;
314	    length = res->Data.ExtAddress64.AddressLength;
315	    name = "ExtAddress64";
316	    break;
317	}
318	if (length <= 0)
319	    break;
320	if (res->Data.Address.ProducerConsumer != ACPI_CONSUMER) {
321	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
322		"ignored %s %s producer\n", name,
323		acpi_address_range_name(res->Data.Address.ResourceType)));
324	    break;
325	}
326	if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE &&
327	    res->Data.Address.ResourceType != ACPI_IO_RANGE) {
328	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
329		"ignored %s for non-memory, non-I/O\n", name));
330	    break;
331	}
332
333#ifdef __i386__
334	if (min > ULONG_MAX || (res->Data.Address.MaxAddressFixed && max >
335	    ULONG_MAX)) {
336	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored %s above 4G\n",
337		name));
338	    break;
339	}
340	if (max > ULONG_MAX)
341		max = ULONG_MAX;
342#endif
343	if (res->Data.Address.MinAddressFixed == ACPI_ADDRESS_FIXED &&
344	    res->Data.Address.MaxAddressFixed == ACPI_ADDRESS_FIXED) {
345	    if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE) {
346		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/Memory 0x%jx/%ju\n",
347		    name, (uintmax_t)min, (uintmax_t)length));
348		set->set_memory(dev, arc->context, min, length);
349	    } else {
350		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx/%ju\n", name,
351		    (uintmax_t)min, (uintmax_t)length));
352		set->set_ioport(dev, arc->context, min, length);
353	    }
354	} else {
355	    if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
356		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
357		    "%s/Memory 0x%jx-0x%jx/%ju\n", name, (uintmax_t)min,
358		    (uintmax_t)max, (uintmax_t)length));
359		set->set_memoryrange(dev, arc->context, min, max, length, gran);
360	    } else {
361		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx-0x%jx/%ju\n",
362		    name, (uintmax_t)min, (uintmax_t)max, (uintmax_t)length));
363		set->set_iorange(dev, arc->context, min, max, length, gran);
364	    }
365	}
366	break;
367    case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
368	if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) {
369	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored ExtIRQ producer\n"));
370	    break;
371	}
372	set->set_ext_irq(dev, arc->context, res->Data.ExtendedIrq.Interrupts,
373	    res->Data.ExtendedIrq.InterruptCount,
374	    res->Data.ExtendedIrq.Triggering, res->Data.ExtendedIrq.Polarity);
375	break;
376    case ACPI_RESOURCE_TYPE_VENDOR:
377	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
378	    "unimplemented VendorSpecific resource\n"));
379	break;
380    default:
381	break;
382    }
383    return (AE_OK);
384}
385
386/*
387 * Fetch a device's resources and associate them with the device.
388 *
389 * Note that it might be nice to also locate ACPI-specific resource items, such
390 * as GPE bits.
391 *
392 * We really need to split the resource-fetching code out from the
393 * resource-parsing code, since we may want to use the parsing
394 * code for _PRS someday.
395 */
396ACPI_STATUS
397acpi_parse_resources(device_t dev, ACPI_HANDLE handle,
398		     struct acpi_parse_resource_set *set, void *arg)
399{
400    struct acpi_resource_context arc;
401    ACPI_STATUS		status;
402
403    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
404
405    set->set_init(dev, arg, &arc.context);
406    arc.set = set;
407    arc.dev = dev;
408    status = AcpiWalkResources(handle, "_CRS", acpi_parse_resource, &arc);
409    if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
410	printf("can't fetch resources for %s - %s\n",
411	    acpi_name(handle), AcpiFormatException(status));
412	return_ACPI_STATUS (status);
413    }
414    set->set_done(dev, arc.context);
415    return_ACPI_STATUS (AE_OK);
416}
417
418/*
419 * Resource-set vectors used to attach _CRS-derived resources
420 * to an ACPI device.
421 */
422static void	acpi_res_set_init(device_t dev, void *arg, void **context);
423static void	acpi_res_set_done(device_t dev, void *context);
424static void	acpi_res_set_ioport(device_t dev, void *context,
425				    uint64_t base, uint64_t length);
426static void	acpi_res_set_iorange(device_t dev, void *context,
427				     uint64_t low, uint64_t high,
428				     uint64_t length, uint64_t align);
429static void	acpi_res_set_memory(device_t dev, void *context,
430				    uint64_t base, uint64_t length);
431static void	acpi_res_set_memoryrange(device_t dev, void *context,
432					 uint64_t low, uint64_t high,
433					 uint64_t length, uint64_t align);
434static void	acpi_res_set_irq(device_t dev, void *context, uint8_t *irq,
435				 int count, int trig, int pol);
436static void	acpi_res_set_ext_irq(device_t dev, void *context,
437				 uint32_t *irq, int count, int trig, int pol);
438static void	acpi_res_set_drq(device_t dev, void *context, uint8_t *drq,
439				 int count);
440static void	acpi_res_set_start_dependent(device_t dev, void *context,
441					     int preference);
442static void	acpi_res_set_end_dependent(device_t dev, void *context);
443
444struct acpi_parse_resource_set acpi_res_parse_set = {
445    acpi_res_set_init,
446    acpi_res_set_done,
447    acpi_res_set_ioport,
448    acpi_res_set_iorange,
449    acpi_res_set_memory,
450    acpi_res_set_memoryrange,
451    acpi_res_set_irq,
452    acpi_res_set_ext_irq,
453    acpi_res_set_drq,
454    acpi_res_set_start_dependent,
455    acpi_res_set_end_dependent
456};
457
458struct acpi_res_context {
459    int		ar_nio;
460    int		ar_nmem;
461    int		ar_nirq;
462    int		ar_ndrq;
463    void 	*ar_parent;
464};
465
466static void
467acpi_res_set_init(device_t dev, void *arg, void **context)
468{
469    struct acpi_res_context	*cp;
470
471    if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
472	bzero(cp, sizeof(*cp));
473	cp->ar_parent = arg;
474	*context = cp;
475    }
476}
477
478static void
479acpi_res_set_done(device_t dev, void *context)
480{
481    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
482
483    if (cp == NULL)
484	return;
485    AcpiOsFree(cp);
486}
487
488static void
489acpi_res_set_ioport(device_t dev, void *context, uint64_t base,
490		    uint64_t length)
491{
492    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
493
494    if (cp == NULL)
495	return;
496    bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
497}
498
499static void
500acpi_res_set_iorange(device_t dev, void *context, uint64_t low,
501		     uint64_t high, uint64_t length, uint64_t align)
502{
503    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
504
505    if (cp == NULL)
506	return;
507    device_printf(dev, "I/O range not supported\n");
508}
509
510static void
511acpi_res_set_memory(device_t dev, void *context, uint64_t base,
512		    uint64_t length)
513{
514    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
515
516    if (cp == NULL)
517	return;
518
519    bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
520}
521
522static void
523acpi_res_set_memoryrange(device_t dev, void *context, uint64_t low,
524			 uint64_t high, uint64_t length, uint64_t align)
525{
526    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
527
528    if (cp == NULL)
529	return;
530    device_printf(dev, "memory range not supported\n");
531}
532
533static void
534acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count,
535    int trig, int pol)
536{
537    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
538
539    if (cp == NULL || irq == NULL)
540	return;
541
542    /* This implements no resource relocation. */
543    if (count != 1)
544	return;
545
546    bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
547}
548
549static void
550acpi_res_set_ext_irq(device_t dev, void *context, uint32_t *irq, int count,
551    int trig, int pol)
552{
553    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
554
555    if (cp == NULL || irq == NULL)
556	return;
557
558    /* This implements no resource relocation. */
559    if (count != 1)
560	return;
561
562    bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
563}
564
565static void
566acpi_res_set_drq(device_t dev, void *context, uint8_t *drq, int count)
567{
568    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
569
570    if (cp == NULL || drq == NULL)
571	return;
572
573    /* This implements no resource relocation. */
574    if (count != 1)
575	return;
576
577    bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
578}
579
580static void
581acpi_res_set_start_dependent(device_t dev, void *context, int preference)
582{
583    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
584
585    if (cp == NULL)
586	return;
587    device_printf(dev, "dependent functions not supported\n");
588}
589
590static void
591acpi_res_set_end_dependent(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    device_printf(dev, "dependent functions not supported\n");
598}
599
600/*
601 * Resource-owning placeholders for IO and memory pseudo-devices.
602 *
603 * This code allocates system resources that will be used by ACPI
604 * child devices.  The acpi parent manages these resources through a
605 * private rman.
606 */
607
608static int	acpi_sysres_rid = 100;
609
610static int	acpi_sysres_probe(device_t dev);
611static int	acpi_sysres_attach(device_t dev);
612
613static device_method_t acpi_sysres_methods[] = {
614    /* Device interface */
615    DEVMETHOD(device_probe,	acpi_sysres_probe),
616    DEVMETHOD(device_attach,	acpi_sysres_attach),
617
618    DEVMETHOD_END
619};
620
621static driver_t acpi_sysres_driver = {
622    "acpi_sysresource",
623    acpi_sysres_methods,
624    0,
625};
626
627static devclass_t acpi_sysres_devclass;
628DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, acpi_sysres_devclass,
629    0, 0);
630MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
631
632static int
633acpi_sysres_probe(device_t dev)
634{
635    static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
636
637    if (acpi_disabled("sysresource") ||
638	ACPI_ID_PROBE(device_get_parent(dev), dev, sysres_ids) == NULL)
639	return (ENXIO);
640
641    device_set_desc(dev, "System Resource");
642    device_quiet(dev);
643    return (BUS_PROBE_DEFAULT);
644}
645
646static int
647acpi_sysres_attach(device_t dev)
648{
649    device_t bus;
650    struct resource_list_entry *bus_rle, *dev_rle;
651    struct resource_list *bus_rl, *dev_rl;
652    int done, type;
653    u_long start, end, count;
654
655    /*
656     * Loop through all current resources to see if the new one overlaps
657     * any existing ones.  If so, grow the old one up and/or down
658     * accordingly.  Discard any that are wholly contained in the old.  If
659     * the resource is unique, add it to the parent.  It will later go into
660     * the rman pool.
661     */
662    bus = device_get_parent(dev);
663    dev_rl = BUS_GET_RESOURCE_LIST(bus, dev);
664    bus_rl = BUS_GET_RESOURCE_LIST(device_get_parent(bus), bus);
665    STAILQ_FOREACH(dev_rle, dev_rl, link) {
666	if (dev_rle->type != SYS_RES_IOPORT && dev_rle->type != SYS_RES_MEMORY)
667	    continue;
668
669	start = dev_rle->start;
670	end = dev_rle->end;
671	count = dev_rle->count;
672	type = dev_rle->type;
673	done = FALSE;
674
675	STAILQ_FOREACH(bus_rle, bus_rl, link) {
676	    if (bus_rle->type != type)
677		continue;
678
679	    /* New resource wholly contained in old, discard. */
680	    if (start >= bus_rle->start && end <= bus_rle->end)
681		break;
682
683	    /* New tail overlaps old head, grow existing resource downward. */
684	    if (start < bus_rle->start && end >= bus_rle->start) {
685		bus_rle->count += bus_rle->start - start;
686		bus_rle->start = start;
687		done = TRUE;
688	    }
689
690	    /* New head overlaps old tail, grow existing resource upward. */
691	    if (start <= bus_rle->end && end > bus_rle->end) {
692		bus_rle->count += end - bus_rle->end;
693		bus_rle->end = end;
694		done = TRUE;
695	    }
696
697	    /* If we adjusted the old resource, we're finished. */
698	    if (done)
699		break;
700	}
701
702	/* If we didn't merge with anything, add this resource. */
703	if (bus_rle == NULL)
704	    bus_set_resource(bus, type, acpi_sysres_rid++, start, count);
705    }
706
707    /* After merging/moving resources to the parent, free the list. */
708    resource_list_free(dev_rl);
709
710    return (0);
711}
712