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