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