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