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