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