acpi_resource.c revision 134086
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 134086 2004-08-20 16:52:44Z njl $");
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 "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->Id) {
64    case ACPI_RSTYPE_IRQ:
65    case ACPI_RSTYPE_EXT_IRQ:
66	if (res->Id == ACPI_RSTYPE_IRQ) {
67	    irqnum = res->Data.Irq.NumberOfInterrupts;
68	    irq = res->Data.Irq.Interrupts[0];
69	} else {
70	    irqnum = res->Data.ExtendedIrq.NumberOfInterrupts;
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->Id) {
115    case ACPI_RSTYPE_IRQ:
116	KASSERT(res->Data.Irq.NumberOfInterrupts == 1,
117	    ("%s: multiple interrupts", __func__));
118	irq = res->Data.Irq.Interrupts[0];
119	trig = res->Data.Irq.EdgeLevel;
120	pol = res->Data.Irq.ActiveHighLow;
121	break;
122    case ACPI_RSTYPE_EXT_IRQ:
123	KASSERT(res->Data.ExtendedIrq.NumberOfInterrupts == 1,
124	    ("%s: multiple interrupts", __func__));
125	irq = res->Data.ExtendedIrq.Interrupts[0];
126	trig = res->Data.ExtendedIrq.EdgeLevel;
127	pol = res->Data.ExtendedIrq.ActiveHighLow;
128	break;
129    default:
130	panic("%s: bad resource type %u", __func__, res->Id);
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->Id) {
190	case ACPI_RSTYPE_END_TAG:
191	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
192	    curr = last;
193	    break;
194	case ACPI_RSTYPE_FIXED_IO:
195	    if (res->Data.FixedIo.RangeLength <= 0)
196		break;
197	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
198			     res->Data.FixedIo.BaseAddress,
199			     res->Data.FixedIo.RangeLength));
200	    set->set_ioport(dev, context,
201			    res->Data.FixedIo.BaseAddress,
202			    res->Data.FixedIo.RangeLength);
203	    break;
204	case ACPI_RSTYPE_IO:
205	    if (res->Data.Io.RangeLength <= 0)
206		break;
207	    if (res->Data.Io.MinBaseAddress == res->Data.Io.MaxBaseAddress) {
208		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
209				 res->Data.Io.MinBaseAddress,
210				 res->Data.Io.RangeLength));
211		set->set_ioport(dev, context,
212				res->Data.Io.MinBaseAddress,
213				res->Data.Io.RangeLength);
214	    } else {
215		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
216				 res->Data.Io.MinBaseAddress,
217				 res->Data.Io.MaxBaseAddress,
218				 res->Data.Io.RangeLength));
219		set->set_iorange(dev, context,
220				 res->Data.Io.MinBaseAddress,
221				 res->Data.Io.MaxBaseAddress,
222				 res->Data.Io.RangeLength,
223				 res->Data.Io.Alignment);
224	    }
225	    break;
226	case ACPI_RSTYPE_FIXED_MEM32:
227	    if (res->Data.FixedMemory32.RangeLength <= 0)
228		break;
229	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
230			      res->Data.FixedMemory32.RangeBaseAddress,
231			      res->Data.FixedMemory32.RangeLength));
232	    set->set_memory(dev, context,
233			    res->Data.FixedMemory32.RangeBaseAddress,
234			    res->Data.FixedMemory32.RangeLength);
235	    break;
236	case ACPI_RSTYPE_MEM32:
237	    if (res->Data.Memory32.RangeLength <= 0)
238		break;
239	    if (res->Data.Memory32.MinBaseAddress ==
240		res->Data.Memory32.MaxBaseAddress) {
241
242		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
243				  res->Data.Memory32.MinBaseAddress,
244				  res->Data.Memory32.RangeLength));
245		set->set_memory(dev, context,
246				res->Data.Memory32.MinBaseAddress,
247				res->Data.Memory32.RangeLength);
248	    } else {
249		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
250				 res->Data.Memory32.MinBaseAddress,
251				 res->Data.Memory32.MaxBaseAddress,
252				 res->Data.Memory32.RangeLength));
253		set->set_memoryrange(dev, context,
254				     res->Data.Memory32.MinBaseAddress,
255				     res->Data.Memory32.MaxBaseAddress,
256				     res->Data.Memory32.RangeLength,
257				     res->Data.Memory32.Alignment);
258	    }
259	    break;
260	case ACPI_RSTYPE_MEM24:
261	    if (res->Data.Memory24.RangeLength <= 0)
262		break;
263	    if (res->Data.Memory24.MinBaseAddress ==
264		res->Data.Memory24.MaxBaseAddress) {
265
266		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
267				 res->Data.Memory24.MinBaseAddress,
268				 res->Data.Memory24.RangeLength));
269		set->set_memory(dev, context, res->Data.Memory24.MinBaseAddress,
270				res->Data.Memory24.RangeLength);
271	    } else {
272		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
273				 res->Data.Memory24.MinBaseAddress,
274				 res->Data.Memory24.MaxBaseAddress,
275				 res->Data.Memory24.RangeLength));
276		set->set_memoryrange(dev, context,
277				     res->Data.Memory24.MinBaseAddress,
278				     res->Data.Memory24.MaxBaseAddress,
279				     res->Data.Memory24.RangeLength,
280				     res->Data.Memory24.Alignment);
281	    }
282	    break;
283	case ACPI_RSTYPE_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.NumberOfInterrupts, res->Data.Irq.EdgeLevel,
291		res->Data.Irq.ActiveHighLow);
292	    break;
293	case ACPI_RSTYPE_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.NumberOfChannels);
301	    break;
302	case ACPI_RSTYPE_START_DPF:
303	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependant functions\n"));
304	    set->set_start_dependant(dev, context,
305				     res->Data.StartDpf.CompatibilityPriority);
306	    break;
307	case ACPI_RSTYPE_END_DPF:
308	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependant functions\n"));
309	    set->set_end_dependant(dev, context);
310	    break;
311	case ACPI_RSTYPE_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.MinAddressRange,
335				     res->Data.Address32.AddressLength));
336		    set->set_memory(dev, context,
337				    res->Data.Address32.MinAddressRange,
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.MinAddressRange,
343				     res->Data.Address32.AddressLength));
344		    set->set_ioport(dev, context,
345				    res->Data.Address32.MinAddressRange,
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.MinAddressRange,
353				     res->Data.Address32.MaxAddressRange,
354				     res->Data.Address32.AddressLength));
355		    set->set_memoryrange(dev, context,
356					  res->Data.Address32.MinAddressRange,
357					  res->Data.Address32.MaxAddressRange,
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.MinAddressRange,
364				     res->Data.Address32.MaxAddressRange,
365				     res->Data.Address32.AddressLength));
366		    set->set_iorange(dev, context,
367				     res->Data.Address32.MinAddressRange,
368				     res->Data.Address32.MaxAddressRange,
369				     res->Data.Address32.AddressLength,
370				     res->Data.Address32.Granularity);
371		}
372	    }
373	    break;
374	case ACPI_RSTYPE_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.MinAddressRange,
398				     res->Data.Address16.AddressLength));
399		    set->set_memory(dev, context,
400				    res->Data.Address16.MinAddressRange,
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.MinAddressRange,
406				     res->Data.Address16.AddressLength));
407		    set->set_ioport(dev, context,
408				    res->Data.Address16.MinAddressRange,
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.MinAddressRange,
416				     res->Data.Address16.MaxAddressRange,
417				     res->Data.Address16.AddressLength));
418		    set->set_memoryrange(dev, context,
419					  res->Data.Address16.MinAddressRange,
420					  res->Data.Address16.MaxAddressRange,
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.MinAddressRange,
427				     res->Data.Address16.MaxAddressRange,
428				     res->Data.Address16.AddressLength));
429		    set->set_iorange(dev, context,
430				     res->Data.Address16.MinAddressRange,
431				     res->Data.Address16.MaxAddressRange,
432				     res->Data.Address16.AddressLength,
433				     res->Data.Address16.Granularity);
434		}
435	    }
436	    break;
437	case ACPI_RSTYPE_ADDRESS64:
438	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
439			     "unimplemented Address64 resource\n"));
440	    break;
441	case ACPI_RSTYPE_EXT_IRQ:
442	    /* XXX special handling? */
443	    set->set_irq(dev, context,res->Data.ExtendedIrq.Interrupts,
444		res->Data.ExtendedIrq.NumberOfInterrupts,
445		res->Data.ExtendedIrq.EdgeLevel,
446		res->Data.ExtendedIrq.ActiveHighLow);
447	    break;
448	case ACPI_RSTYPE_VENDOR:
449	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
450			     "unimplemented VendorSpecific resource\n"));
451	    break;
452	default:
453	    break;
454	}
455    }
456
457    AcpiOsFree(buf.Pointer);
458    set->set_done(dev, context);
459    return_ACPI_STATUS (AE_OK);
460}
461
462/*
463 * Resource-set vectors used to attach _CRS-derived resources
464 * to an ACPI device.
465 */
466static void	acpi_res_set_init(device_t dev, void *arg, void **context);
467static void	acpi_res_set_done(device_t dev, void *context);
468static void	acpi_res_set_ioport(device_t dev, void *context,
469				    u_int32_t base, u_int32_t length);
470static void	acpi_res_set_iorange(device_t dev, void *context,
471				     u_int32_t low, u_int32_t high,
472				     u_int32_t length, u_int32_t align);
473static void	acpi_res_set_memory(device_t dev, void *context,
474				    u_int32_t base, u_int32_t length);
475static void	acpi_res_set_memoryrange(device_t dev, void *context,
476					 u_int32_t low, u_int32_t high,
477					 u_int32_t length, u_int32_t align);
478static void	acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq,
479				 int count, int trig, int pol);
480static void	acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq,
481				 int count);
482static void	acpi_res_set_start_dependant(device_t dev, void *context,
483					     int preference);
484static void	acpi_res_set_end_dependant(device_t dev, void *context);
485
486struct acpi_parse_resource_set acpi_res_parse_set = {
487    acpi_res_set_init,
488    acpi_res_set_done,
489    acpi_res_set_ioport,
490    acpi_res_set_iorange,
491    acpi_res_set_memory,
492    acpi_res_set_memoryrange,
493    acpi_res_set_irq,
494    acpi_res_set_drq,
495    acpi_res_set_start_dependant,
496    acpi_res_set_end_dependant
497};
498
499struct acpi_res_context {
500    int		ar_nio;
501    int		ar_nmem;
502    int		ar_nirq;
503    int		ar_ndrq;
504    void 	*ar_parent;
505};
506
507/*
508 * Add a resource to the device's resource list.  We define our own function
509 * for this since bus_set_resource() doesn't handle duplicates of any kind.
510 *
511 * XXX This should be merged into resource_list_add() eventually.
512 */
513static int
514acpi_reslist_add(device_t dev, int type, int rid, u_long start, u_long count)
515{
516    struct resource_list_entry *rle;
517    struct resource_list *rl;
518    u_long end;
519
520    end = start + count - 1;
521    rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
522
523    /*
524     * Loop through all current resources to see if the new one overlaps
525     * any existing ones.  If so, the old one always takes precedence and
526     * the new one is adjusted (or rejected).  We check for three cases:
527     *
528     * 1. Tail of new resource overlaps head of old resource:  truncate the
529     *    new resource so it is contiguous with the start of the old.
530     * 2. New resource wholly contained within the old resource:  error.
531     * 3. Head of new resource overlaps tail of old resource:  truncate the
532     *    new resource so it is contiguous, following the old.
533     */
534    SLIST_FOREACH(rle, rl, link) {
535	if (rle->type == type) {
536	    if (start < rle->start && end >= rle->start) {
537		count = rle->start - start;
538		break;
539	    } else if (start >= rle->start && start <= rle->end) {
540		if (end > rle->end) {
541		    start = rle->end + 1;
542		    count = end - rle->end + 1;
543		    break;
544		} else
545		    return (EEXIST);
546	    }
547	}
548    }
549    return (bus_set_resource(dev, type, rid, start, count));
550}
551
552static void
553acpi_res_set_init(device_t dev, void *arg, void **context)
554{
555    struct acpi_res_context	*cp;
556
557    if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
558	bzero(cp, sizeof(*cp));
559	cp->ar_parent = arg;
560	*context = cp;
561    }
562}
563
564static void
565acpi_res_set_done(device_t dev, void *context)
566{
567    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
568
569    if (cp == NULL)
570	return;
571    AcpiOsFree(cp);
572}
573
574static void
575acpi_res_set_ioport(device_t dev, void *context, u_int32_t base,
576		    u_int32_t length)
577{
578    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
579
580    if (cp == NULL)
581	return;
582    acpi_reslist_add(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
583}
584
585static void
586acpi_res_set_iorange(device_t dev, void *context, u_int32_t low,
587		     u_int32_t high, u_int32_t length, u_int32_t align)
588{
589    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
590
591    if (cp == NULL)
592	return;
593    device_printf(dev, "I/O range not supported\n");
594}
595
596static void
597acpi_res_set_memory(device_t dev, void *context, u_int32_t base,
598		    u_int32_t length)
599{
600    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
601
602    if (cp == NULL)
603	return;
604
605    acpi_reslist_add(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
606}
607
608static void
609acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low,
610			 u_int32_t high, u_int32_t length, u_int32_t align)
611{
612    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
613
614    if (cp == NULL)
615	return;
616    device_printf(dev, "memory range not supported\n");
617}
618
619static void
620acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, int count,
621    int trig, int pol)
622{
623    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
624
625    if (cp == NULL || irq == NULL)
626	return;
627
628    /* This implements no resource relocation. */
629    if (count != 1)
630	return;
631
632    acpi_reslist_add(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
633}
634
635static void
636acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq, int count)
637{
638    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
639
640    if (cp == NULL || drq == NULL)
641	return;
642
643    /* This implements no resource relocation. */
644    if (count != 1)
645	return;
646
647    acpi_reslist_add(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
648}
649
650static void
651acpi_res_set_start_dependant(device_t dev, void *context, int preference)
652{
653    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
654
655    if (cp == NULL)
656	return;
657    device_printf(dev, "dependant functions not supported\n");
658}
659
660static void
661acpi_res_set_end_dependant(device_t dev, void *context)
662{
663    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
664
665    if (cp == NULL)
666	return;
667    device_printf(dev, "dependant functions not supported\n");
668}
669
670/*
671 * Resource-owning placeholders for IO and memory pseudo-devices.
672 *
673 * This code allocates system resource objects that will be owned by ACPI
674 * child devices.  Really, the acpi parent device should have the resources
675 * but this would significantly affect the device probe code.
676 */
677
678static int	acpi_sysres_probe(device_t dev);
679static int	acpi_sysres_attach(device_t dev);
680
681static device_method_t acpi_sysres_methods[] = {
682    /* Device interface */
683    DEVMETHOD(device_probe,	acpi_sysres_probe),
684    DEVMETHOD(device_attach,	acpi_sysres_attach),
685
686    {0, 0}
687};
688
689static driver_t acpi_sysres_driver = {
690    "acpi_sysresource",
691    acpi_sysres_methods,
692    0,
693};
694
695static devclass_t acpi_sysres_devclass;
696DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, acpi_sysres_devclass,
697    0, 0);
698MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
699
700static int
701acpi_sysres_probe(device_t dev)
702{
703    static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
704
705    if (acpi_disabled("sysresource") ||
706	ACPI_ID_PROBE(device_get_parent(dev), dev, sysres_ids) == NULL)
707	return (ENXIO);
708
709    device_set_desc(dev, "System Resource");
710    device_quiet(dev);
711    return (-100);
712}
713
714static int
715acpi_sysres_attach(device_t dev)
716{
717    device_t gparent;
718    struct resource *res;
719    struct rman *rm;
720    struct resource_list_entry *rle;
721    struct resource_list *rl;
722
723    /*
724     * Pre-allocate/manage all memory and IO resources.  We detect duplicates
725     * by setting rle->res to the resource we got from the parent.  We can't
726     * ignore them since rman can't handle duplicates.
727     */
728    rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
729    SLIST_FOREACH(rle, rl, link) {
730	if (rle->res != NULL) {
731	    device_printf(dev, "duplicate resource for %lx\n", rle->start);
732	    continue;
733	}
734
735	/* Only memory and IO resources are valid here. */
736	switch (rle->type) {
737	case SYS_RES_IOPORT:
738	    rm = &acpi_rman_io;
739	    break;
740	case SYS_RES_MEMORY:
741	    rm = &acpi_rman_mem;
742	    break;
743	default:
744	    continue;
745	}
746
747	/* Pre-allocate resource and add to our rman pool. */
748	gparent = device_get_parent(device_get_parent(dev));
749	res = BUS_ALLOC_RESOURCE(gparent, dev, rle->type, &rle->rid,
750	    rle->start, rle->start + rle->count - 1, rle->count, 0);
751	if (res != NULL) {
752	    rman_manage_region(rm, rman_get_start(res), rman_get_end(res));
753	    rle->res = res;
754	}
755    }
756
757    return (0);
758}
759
760/* XXX The resource list may require locking and refcounting. */
761struct resource_list_entry *
762acpi_sysres_find(int type, u_long addr)
763{
764    device_t *devs;
765    int i, numdevs;
766    struct resource_list *rl;
767    struct resource_list_entry *rle;
768
769    /* We only consider IO and memory resources for our pool. */
770    rle = NULL;
771    if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY)
772        return (rle);
773
774    /* Find all the sysresource devices. */
775    if (devclass_get_devices(acpi_sysres_devclass, &devs, &numdevs) != 0)
776	return (rle);
777
778    /* Check each device for a resource that contains "addr". */
779    for (i = 0; i < numdevs && rle == NULL; i++) {
780	rl = BUS_GET_RESOURCE_LIST(device_get_parent(devs[i]), devs[i]);
781	if (rl == NULL)
782	    continue;
783	SLIST_FOREACH(rle, rl, link) {
784	    if (type == rle->type && addr >= rle->start &&
785		addr < rle->start + rle->count)
786		break;
787	}
788    }
789
790    free(devs, M_TEMP);
791    return (rle);
792}
793