acpi_resource.c revision 134217
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 134217 2004-08-23 16:28:42Z 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
507static void
508acpi_res_set_init(device_t dev, void *arg, void **context)
509{
510    struct acpi_res_context	*cp;
511
512    if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
513	bzero(cp, sizeof(*cp));
514	cp->ar_parent = arg;
515	*context = cp;
516    }
517}
518
519static void
520acpi_res_set_done(device_t dev, void *context)
521{
522    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
523
524    if (cp == NULL)
525	return;
526    AcpiOsFree(cp);
527}
528
529static void
530acpi_res_set_ioport(device_t dev, void *context, u_int32_t base,
531		    u_int32_t length)
532{
533    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
534
535    if (cp == NULL)
536	return;
537    bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
538}
539
540static void
541acpi_res_set_iorange(device_t dev, void *context, u_int32_t low,
542		     u_int32_t high, u_int32_t length, u_int32_t align)
543{
544    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
545
546    if (cp == NULL)
547	return;
548    device_printf(dev, "I/O range not supported\n");
549}
550
551static void
552acpi_res_set_memory(device_t dev, void *context, u_int32_t base,
553		    u_int32_t length)
554{
555    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
556
557    if (cp == NULL)
558	return;
559
560    bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
561}
562
563static void
564acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low,
565			 u_int32_t high, u_int32_t length, u_int32_t align)
566{
567    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
568
569    if (cp == NULL)
570	return;
571    device_printf(dev, "memory range not supported\n");
572}
573
574static void
575acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, int count,
576    int trig, int pol)
577{
578    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
579
580    if (cp == NULL || irq == NULL)
581	return;
582
583    /* This implements no resource relocation. */
584    if (count != 1)
585	return;
586
587    bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
588}
589
590static void
591acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq, int count)
592{
593    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
594
595    if (cp == NULL || drq == NULL)
596	return;
597
598    /* This implements no resource relocation. */
599    if (count != 1)
600	return;
601
602    bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
603}
604
605static void
606acpi_res_set_start_dependant(device_t dev, void *context, int preference)
607{
608    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
609
610    if (cp == NULL)
611	return;
612    device_printf(dev, "dependant functions not supported\n");
613}
614
615static void
616acpi_res_set_end_dependant(device_t dev, void *context)
617{
618    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
619
620    if (cp == NULL)
621	return;
622    device_printf(dev, "dependant functions not supported\n");
623}
624
625/*
626 * Resource-owning placeholders for IO and memory pseudo-devices.
627 *
628 * This code allocates system resources that will be used by ACPI
629 * child devices.  The acpi parent manages these resources through a
630 * private rman.
631 */
632
633static int	acpi_sysres_rid = 100;
634
635static int	acpi_sysres_probe(device_t dev);
636static int	acpi_sysres_attach(device_t dev);
637
638static device_method_t acpi_sysres_methods[] = {
639    /* Device interface */
640    DEVMETHOD(device_probe,	acpi_sysres_probe),
641    DEVMETHOD(device_attach,	acpi_sysres_attach),
642
643    {0, 0}
644};
645
646static driver_t acpi_sysres_driver = {
647    "acpi_sysresource",
648    acpi_sysres_methods,
649    0,
650};
651
652static devclass_t acpi_sysres_devclass;
653DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, acpi_sysres_devclass,
654    0, 0);
655MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
656
657static int
658acpi_sysres_probe(device_t dev)
659{
660    static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
661
662    if (acpi_disabled("sysresource") ||
663	ACPI_ID_PROBE(device_get_parent(dev), dev, sysres_ids) == NULL)
664	return (ENXIO);
665
666    device_set_desc(dev, "System Resource");
667    device_quiet(dev);
668    return (-100);
669}
670
671static int
672acpi_sysres_attach(device_t dev)
673{
674    device_t bus;
675    struct resource_list_entry *bus_rle, *dev_rle;
676    struct resource_list *bus_rl, *dev_rl;
677    int done, type;
678    u_long start, end, count;
679
680    /*
681     * Loop through all current resources to see if the new one overlaps
682     * any existing ones.  If so, grow the old one up and/or down
683     * accordingly.  Discard any that are wholly contained in the old.  If
684     * the resource is unique, add it to the parent.  It will later go into
685     * the rman pool.
686     */
687    bus = device_get_parent(dev);
688    dev_rl = BUS_GET_RESOURCE_LIST(bus, dev);
689    bus_rl = BUS_GET_RESOURCE_LIST(device_get_parent(bus), bus);
690    SLIST_FOREACH(dev_rle, dev_rl, link) {
691	if (dev_rle->type != SYS_RES_IOPORT && dev_rle->type != SYS_RES_MEMORY)
692	    continue;
693
694	start = dev_rle->start;
695	end = dev_rle->end;
696	count = dev_rle->count;
697	type = dev_rle->type;
698	done = FALSE;
699
700	SLIST_FOREACH(bus_rle, bus_rl, link) {
701	    if (bus_rle->type != type)
702		continue;
703
704	    /* New resource wholly contained in old, discard. */
705	    if (start >= bus_rle->start && end <= bus_rle->end)
706		break;
707
708	    /* New tail overlaps old head, grow existing resource downward. */
709	    if (start < bus_rle->start && end >= bus_rle->start) {
710		bus_rle->count += bus_rle->start - start;
711		bus_rle->start = start;
712		done = TRUE;
713	    }
714
715	    /* New head overlaps old tail, grow existing resource upward. */
716	    if (start <= bus_rle->end && end > bus_rle->end) {
717		bus_rle->count += end - bus_rle->end;
718		bus_rle->end = end;
719		done = TRUE;
720	    }
721
722	    /* If we adjusted the old resource, we're finished. */
723	    if (done)
724		break;
725	}
726
727	/* If we didn't merge with anything, add this resource. */
728	if (bus_rle == NULL)
729	    bus_set_resource(bus, type, acpi_sysres_rid++, start, count);
730    }
731
732    /* After merging/moving resources to the parent, free the list. */
733    resource_list_free(dev_rl);
734
735    return (0);
736}
737