xref: /dflybsd-src/sys/dev/acpica/acpi_resource.c (revision df21e16d16b51cf8e1828be094b4866e5d0a1bc8)
15db2f26eSSascha Wildner /*-
25db2f26eSSascha Wildner  * Copyright (c) 2000 Michael Smith
35db2f26eSSascha Wildner  * Copyright (c) 2000 BSDi
45db2f26eSSascha Wildner  * All rights reserved.
55db2f26eSSascha Wildner  *
65db2f26eSSascha Wildner  * Redistribution and use in source and binary forms, with or without
75db2f26eSSascha Wildner  * modification, are permitted provided that the following conditions
85db2f26eSSascha Wildner  * are met:
95db2f26eSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
105db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
115db2f26eSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
125db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
135db2f26eSSascha Wildner  *    documentation and/or other materials provided with the distribution.
145db2f26eSSascha Wildner  *
155db2f26eSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
165db2f26eSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
175db2f26eSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
185db2f26eSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
195db2f26eSSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
205db2f26eSSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
215db2f26eSSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
225db2f26eSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
235db2f26eSSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
245db2f26eSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
255db2f26eSSascha Wildner  * SUCH DAMAGE.
265db2f26eSSascha Wildner  *
27ad52dd32SSascha Wildner  * $FreeBSD: head/sys/dev/acpica/acpi_resource.c 263975 2014-03-31 19:37:39Z imp $
285db2f26eSSascha Wildner  */
295db2f26eSSascha Wildner 
305db2f26eSSascha Wildner #include "opt_acpi.h"
315db2f26eSSascha Wildner #include <sys/param.h>
325db2f26eSSascha Wildner #include <sys/kernel.h>
335db2f26eSSascha Wildner #include <sys/bus.h>
34ad52dd32SSascha Wildner #include <sys/limits.h>
355db2f26eSSascha Wildner #include <sys/malloc.h>
365db2f26eSSascha Wildner #include <sys/module.h>
375db2f26eSSascha Wildner #include <sys/resource.h>
385db2f26eSSascha Wildner #include <sys/machintr.h>
395db2f26eSSascha Wildner 
405db2f26eSSascha Wildner #include <sys/rman.h>
415db2f26eSSascha Wildner 
425db2f26eSSascha Wildner #include "acpi.h"
435db2f26eSSascha Wildner #include <dev/acpica/acpivar.h>
445db2f26eSSascha Wildner 
455db2f26eSSascha Wildner /* Hooks for the ACPICA debugging infrastructure */
465db2f26eSSascha Wildner #define _COMPONENT	ACPI_BUS
475db2f26eSSascha Wildner ACPI_MODULE_NAME("RESOURCE")
485db2f26eSSascha Wildner 
495db2f26eSSascha Wildner struct lookup_irq_request {
505db2f26eSSascha Wildner     ACPI_RESOURCE *acpi_res;
515db2f26eSSascha Wildner     struct resource *res;
525db2f26eSSascha Wildner     int		counter;
535db2f26eSSascha Wildner     int		rid;
545db2f26eSSascha Wildner     int		found;
555db2f26eSSascha Wildner };
565db2f26eSSascha Wildner 
575db2f26eSSascha Wildner static ACPI_STATUS
585db2f26eSSascha Wildner acpi_lookup_irq_handler(ACPI_RESOURCE *res, void *context)
595db2f26eSSascha Wildner {
605db2f26eSSascha Wildner     struct lookup_irq_request *req;
615db2f26eSSascha Wildner     size_t len;
6273aefc74SSascha Wildner     u_int irqnum;
6373aefc74SSascha Wildner     u_int irq __debugvar;
645db2f26eSSascha Wildner 
655db2f26eSSascha Wildner     switch (res->Type) {
665db2f26eSSascha Wildner     case ACPI_RESOURCE_TYPE_IRQ:
675db2f26eSSascha Wildner 	irqnum = res->Data.Irq.InterruptCount;
685db2f26eSSascha Wildner 	irq = res->Data.Irq.Interrupts[0];
695db2f26eSSascha Wildner 	len = ACPI_RS_SIZE(ACPI_RESOURCE_IRQ);
705db2f26eSSascha Wildner 	break;
715db2f26eSSascha Wildner     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
725db2f26eSSascha Wildner 	irqnum = res->Data.ExtendedIrq.InterruptCount;
735db2f26eSSascha Wildner 	irq = res->Data.ExtendedIrq.Interrupts[0];
745db2f26eSSascha Wildner 	len = ACPI_RS_SIZE(ACPI_RESOURCE_EXTENDED_IRQ);
755db2f26eSSascha Wildner 	break;
765db2f26eSSascha Wildner     default:
775db2f26eSSascha Wildner 	return (AE_OK);
785db2f26eSSascha Wildner     }
795db2f26eSSascha Wildner     if (irqnum != 1)
805db2f26eSSascha Wildner 	return (AE_OK);
815db2f26eSSascha Wildner     req = (struct lookup_irq_request *)context;
825db2f26eSSascha Wildner     if (req->counter != req->rid) {
835db2f26eSSascha Wildner 	req->counter++;
845db2f26eSSascha Wildner 	return (AE_OK);
855db2f26eSSascha Wildner     }
865db2f26eSSascha Wildner     req->found = 1;
875db2f26eSSascha Wildner     KASSERT(irq == rman_get_start(req->res),
885db2f26eSSascha Wildner 	("IRQ resources do not match"));
895db2f26eSSascha Wildner     bcopy(res, req->acpi_res, len);
905db2f26eSSascha Wildner     return (AE_CTRL_TERMINATE);
915db2f26eSSascha Wildner }
925db2f26eSSascha Wildner 
935db2f26eSSascha Wildner ACPI_STATUS
945db2f26eSSascha Wildner acpi_lookup_irq_resource(device_t dev, int rid, struct resource *res,
955db2f26eSSascha Wildner     ACPI_RESOURCE *acpi_res)
965db2f26eSSascha Wildner {
975db2f26eSSascha Wildner     struct lookup_irq_request req;
985db2f26eSSascha Wildner     ACPI_STATUS status;
995db2f26eSSascha Wildner 
1005db2f26eSSascha Wildner     req.acpi_res = acpi_res;
1015db2f26eSSascha Wildner     req.res = res;
1025db2f26eSSascha Wildner     req.counter = 0;
1035db2f26eSSascha Wildner     req.rid = rid;
1045db2f26eSSascha Wildner     req.found = 0;
1055db2f26eSSascha Wildner     status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
1065db2f26eSSascha Wildner 	acpi_lookup_irq_handler, &req);
1075db2f26eSSascha Wildner     if (ACPI_SUCCESS(status) && req.found == 0)
1085db2f26eSSascha Wildner 	status = AE_NOT_FOUND;
1095db2f26eSSascha Wildner     return (status);
1105db2f26eSSascha Wildner }
1115db2f26eSSascha Wildner 
1125db2f26eSSascha Wildner void
1135db2f26eSSascha Wildner acpi_config_intr(device_t dev, ACPI_RESOURCE *res)
1145db2f26eSSascha Wildner {
1155db2f26eSSascha Wildner     u_int irq;
1165db2f26eSSascha Wildner     int pol, trig;
1175db2f26eSSascha Wildner     enum intr_trigger trigger;
1185db2f26eSSascha Wildner     enum intr_polarity polarity;
1195db2f26eSSascha Wildner 
1205db2f26eSSascha Wildner     switch (res->Type) {
1215db2f26eSSascha Wildner     case ACPI_RESOURCE_TYPE_IRQ:
1225db2f26eSSascha Wildner 	KASSERT(res->Data.Irq.InterruptCount == 1,
1235db2f26eSSascha Wildner 	    ("%s: multiple interrupts", __func__));
1245db2f26eSSascha Wildner 	irq = res->Data.Irq.Interrupts[0];
1255db2f26eSSascha Wildner 	trig = res->Data.Irq.Triggering;
1265db2f26eSSascha Wildner 	pol = res->Data.Irq.Polarity;
1275db2f26eSSascha Wildner 	break;
1285db2f26eSSascha Wildner     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
1295db2f26eSSascha Wildner 	KASSERT(res->Data.ExtendedIrq.InterruptCount == 1,
1305db2f26eSSascha Wildner 	    ("%s: multiple interrupts", __func__));
1315db2f26eSSascha Wildner 	irq = res->Data.ExtendedIrq.Interrupts[0];
1325db2f26eSSascha Wildner 	trig = res->Data.ExtendedIrq.Triggering;
1335db2f26eSSascha Wildner 	pol = res->Data.ExtendedIrq.Polarity;
1345db2f26eSSascha Wildner 	break;
1355db2f26eSSascha Wildner     default:
1365db2f26eSSascha Wildner 	panic("%s: bad resource type %u", __func__, res->Type);
1375db2f26eSSascha Wildner     }
1385db2f26eSSascha Wildner 
139ac8ea0adSSascha Wildner #if defined(__x86_64__)
140ad52dd32SSascha Wildner     /*
141ad52dd32SSascha Wildner      * XXX: Certain BIOSes have buggy AML that specify an IRQ that is
142ad52dd32SSascha Wildner      * edge-sensitive and active-lo.  However, edge-sensitive IRQs
143ad52dd32SSascha Wildner      * should be active-hi.  Force IRQs with an ISA IRQ value to be
144ad52dd32SSascha Wildner      * active-hi instead.
145ad52dd32SSascha Wildner      */
146ad52dd32SSascha Wildner     if (irq < 16 && trig == ACPI_EDGE_SENSITIVE && pol == ACPI_ACTIVE_LOW)
147ad52dd32SSascha Wildner 	pol = ACPI_ACTIVE_HIGH;
148ad52dd32SSascha Wildner #endif
149ad52dd32SSascha Wildner 
1505db2f26eSSascha Wildner     if (trig == ACPI_EDGE_SENSITIVE)
1515db2f26eSSascha Wildner     	trigger = INTR_TRIGGER_EDGE;
1525db2f26eSSascha Wildner     else
1535db2f26eSSascha Wildner     	trigger = INTR_TRIGGER_LEVEL;
1545db2f26eSSascha Wildner 
1555db2f26eSSascha Wildner     if (pol == ACPI_ACTIVE_HIGH)
1565db2f26eSSascha Wildner 	polarity = INTR_POLARITY_HIGH;
1575db2f26eSSascha Wildner     else
1585db2f26eSSascha Wildner     	polarity = INTR_POLARITY_LOW;
1595db2f26eSSascha Wildner 
1605db2f26eSSascha Wildner     if (machintr_legacy_intr_find(irq, trigger, polarity) < 0)
161ad52dd32SSascha Wildner 	kprintf("%s: Skip irq %d config\n", __func__, irq);
1625db2f26eSSascha Wildner     else
1635db2f26eSSascha Wildner 	BUS_CONFIG_INTR(dev, dev, irq, trigger, polarity);
1645db2f26eSSascha Wildner }
1655db2f26eSSascha Wildner 
166ad52dd32SSascha Wildner struct acpi_resource_context {
167ad52dd32SSascha Wildner     struct acpi_parse_resource_set *set;
168ad52dd32SSascha Wildner     device_t	dev;
169ad52dd32SSascha Wildner     void	*context;
170ad52dd32SSascha Wildner };
171ad52dd32SSascha Wildner 
172ad52dd32SSascha Wildner #ifdef ACPI_DEBUG_OUTPUT
173ad52dd32SSascha Wildner static const char *
174ad52dd32SSascha Wildner acpi_address_range_name(UINT8 ResourceType)
175ad52dd32SSascha Wildner {
176ad52dd32SSascha Wildner     static char buf[16];
177ad52dd32SSascha Wildner 
178ad52dd32SSascha Wildner     switch (ResourceType) {
179ad52dd32SSascha Wildner     case ACPI_MEMORY_RANGE:
180ad52dd32SSascha Wildner 	    return ("Memory");
181ad52dd32SSascha Wildner     case ACPI_IO_RANGE:
182ad52dd32SSascha Wildner 	    return ("IO");
183ad52dd32SSascha Wildner     case ACPI_BUS_NUMBER_RANGE:
184ad52dd32SSascha Wildner 	    return ("Bus Number");
185ad52dd32SSascha Wildner     default:
186ad52dd32SSascha Wildner 	    ksnprintf(buf, sizeof(buf), "type %u", ResourceType);
187ad52dd32SSascha Wildner 	    return (buf);
188ad52dd32SSascha Wildner     }
189ad52dd32SSascha Wildner }
190ad52dd32SSascha Wildner #endif
191ad52dd32SSascha Wildner 
192ad52dd32SSascha Wildner static ACPI_STATUS
193ad52dd32SSascha Wildner acpi_parse_resource(ACPI_RESOURCE *res, void *context)
194ad52dd32SSascha Wildner {
195ad52dd32SSascha Wildner     struct acpi_parse_resource_set *set;
196ad52dd32SSascha Wildner     struct acpi_resource_context *arc;
197ad52dd32SSascha Wildner     UINT64 min, max, length, gran;
198ad52dd32SSascha Wildner #ifdef ACPI_DEBUG
199ad52dd32SSascha Wildner     const char *name;
200ad52dd32SSascha Wildner #endif
201ad52dd32SSascha Wildner     device_t dev;
202ad52dd32SSascha Wildner 
203ad52dd32SSascha Wildner     arc = context;
204ad52dd32SSascha Wildner     dev = arc->dev;
205ad52dd32SSascha Wildner     set = arc->set;
206ad52dd32SSascha Wildner 
207ad52dd32SSascha Wildner     switch (res->Type) {
208ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_END_TAG:
209ad52dd32SSascha Wildner 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
210ad52dd32SSascha Wildner 	break;
211ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_FIXED_IO:
212ad52dd32SSascha Wildner 	if (res->Data.FixedIo.AddressLength <= 0)
213ad52dd32SSascha Wildner 	    break;
214ad52dd32SSascha Wildner 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
215ad52dd32SSascha Wildner 	    res->Data.FixedIo.Address, res->Data.FixedIo.AddressLength));
216ad52dd32SSascha Wildner 	set->set_ioport(dev, arc->context, res->Data.FixedIo.Address,
217ad52dd32SSascha Wildner 	    res->Data.FixedIo.AddressLength);
218ad52dd32SSascha Wildner 	break;
219ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_IO:
220ad52dd32SSascha Wildner 	if (res->Data.Io.AddressLength <= 0)
221ad52dd32SSascha Wildner 	    break;
222ad52dd32SSascha Wildner 	if (res->Data.Io.Minimum == res->Data.Io.Maximum) {
223ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
224ad52dd32SSascha Wildner 		res->Data.Io.Minimum, res->Data.Io.AddressLength));
225ad52dd32SSascha Wildner 	    set->set_ioport(dev, arc->context, res->Data.Io.Minimum,
226ad52dd32SSascha Wildner 		res->Data.Io.AddressLength);
227ad52dd32SSascha Wildner 	} else {
228ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
229ad52dd32SSascha Wildner 		res->Data.Io.Minimum, res->Data.Io.Maximum,
230ad52dd32SSascha Wildner 		res->Data.Io.AddressLength));
231ad52dd32SSascha Wildner 	    set->set_iorange(dev, arc->context, res->Data.Io.Minimum,
232ad52dd32SSascha Wildner 		res->Data.Io.Maximum, res->Data.Io.AddressLength,
233ad52dd32SSascha Wildner 		res->Data.Io.Alignment);
234ad52dd32SSascha Wildner 	}
235ad52dd32SSascha Wildner 	break;
236ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
237ad52dd32SSascha Wildner 	if (res->Data.FixedMemory32.AddressLength <= 0)
238ad52dd32SSascha Wildner 	    break;
239ad52dd32SSascha Wildner 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
240ad52dd32SSascha Wildner 	    res->Data.FixedMemory32.Address,
241ad52dd32SSascha Wildner 	    res->Data.FixedMemory32.AddressLength));
242ad52dd32SSascha Wildner 	set->set_memory(dev, arc->context, res->Data.FixedMemory32.Address,
243ad52dd32SSascha Wildner 	    res->Data.FixedMemory32.AddressLength);
244ad52dd32SSascha Wildner 	break;
245ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_MEMORY32:
246ad52dd32SSascha Wildner 	if (res->Data.Memory32.AddressLength <= 0)
247ad52dd32SSascha Wildner 	    break;
248ad52dd32SSascha Wildner 	if (res->Data.Memory32.Minimum == res->Data.Memory32.Maximum) {
249ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
250ad52dd32SSascha Wildner 		res->Data.Memory32.Minimum, res->Data.Memory32.AddressLength));
251ad52dd32SSascha Wildner 	    set->set_memory(dev, arc->context, res->Data.Memory32.Minimum,
252ad52dd32SSascha Wildner 		res->Data.Memory32.AddressLength);
253ad52dd32SSascha Wildner 	} else {
254ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
255ad52dd32SSascha Wildner 		res->Data.Memory32.Minimum, res->Data.Memory32.Maximum,
256ad52dd32SSascha Wildner 		res->Data.Memory32.AddressLength));
257ad52dd32SSascha Wildner 	    set->set_memoryrange(dev, arc->context, res->Data.Memory32.Minimum,
258ad52dd32SSascha Wildner 		res->Data.Memory32.Maximum, res->Data.Memory32.AddressLength,
259ad52dd32SSascha Wildner 		res->Data.Memory32.Alignment);
260ad52dd32SSascha Wildner 	}
261ad52dd32SSascha Wildner 	break;
262ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_MEMORY24:
263ad52dd32SSascha Wildner 	if (res->Data.Memory24.AddressLength <= 0)
264ad52dd32SSascha Wildner 	    break;
265ad52dd32SSascha Wildner 	if (res->Data.Memory24.Minimum == res->Data.Memory24.Maximum) {
266ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
267ad52dd32SSascha Wildner 		res->Data.Memory24.Minimum, res->Data.Memory24.AddressLength));
268ad52dd32SSascha Wildner 	    set->set_memory(dev, arc->context, res->Data.Memory24.Minimum,
269ad52dd32SSascha Wildner 		res->Data.Memory24.AddressLength);
270ad52dd32SSascha Wildner 	} else {
271ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
272ad52dd32SSascha Wildner 		res->Data.Memory24.Minimum, res->Data.Memory24.Maximum,
273ad52dd32SSascha Wildner 		res->Data.Memory24.AddressLength));
274ad52dd32SSascha Wildner 	    set->set_memoryrange(dev, arc->context, res->Data.Memory24.Minimum,
275ad52dd32SSascha Wildner 		res->Data.Memory24.Maximum, res->Data.Memory24.AddressLength,
276ad52dd32SSascha Wildner 		res->Data.Memory24.Alignment);
277ad52dd32SSascha Wildner 	}
278ad52dd32SSascha Wildner 	break;
279ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_IRQ:
280ad52dd32SSascha Wildner 	/*
281ad52dd32SSascha Wildner 	 * from 1.0b 6.4.2
282ad52dd32SSascha Wildner 	 * "This structure is repeated for each separate interrupt
283ad52dd32SSascha Wildner 	 * required"
284ad52dd32SSascha Wildner 	 */
285ad52dd32SSascha Wildner 	set->set_irq(dev, arc->context, res->Data.Irq.Interrupts,
286ad52dd32SSascha Wildner 	    res->Data.Irq.InterruptCount, res->Data.Irq.Triggering,
287ad52dd32SSascha Wildner 	    res->Data.Irq.Polarity);
288ad52dd32SSascha Wildner 	break;
289ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_DMA:
290ad52dd32SSascha Wildner 	/*
291ad52dd32SSascha Wildner 	 * from 1.0b 6.4.3
292ad52dd32SSascha Wildner 	 * "This structure is repeated for each separate DMA channel
293ad52dd32SSascha Wildner 	 * required"
294ad52dd32SSascha Wildner 	 */
295ad52dd32SSascha Wildner 	set->set_drq(dev, arc->context, res->Data.Dma.Channels,
296ad52dd32SSascha Wildner 	    res->Data.Dma.ChannelCount);
297ad52dd32SSascha Wildner 	break;
298ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_START_DEPENDENT:
299ad52dd32SSascha Wildner 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependent functions\n"));
300ad52dd32SSascha Wildner 	set->set_start_dependent(dev, arc->context,
301ad52dd32SSascha Wildner 	    res->Data.StartDpf.CompatibilityPriority);
302ad52dd32SSascha Wildner 	break;
303ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_END_DEPENDENT:
304ad52dd32SSascha Wildner 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependent functions\n"));
305ad52dd32SSascha Wildner 	set->set_end_dependent(dev, arc->context);
306ad52dd32SSascha Wildner 	break;
307ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_ADDRESS16:
308ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_ADDRESS32:
309ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_ADDRESS64:
310ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
311ad52dd32SSascha Wildner 	switch (res->Type) {
312ad52dd32SSascha Wildner 	case ACPI_RESOURCE_TYPE_ADDRESS16:
3135943f66cSSascha Wildner 	    gran = res->Data.Address16.Address.Granularity;
3145943f66cSSascha Wildner 	    min = res->Data.Address16.Address.Minimum;
3155943f66cSSascha Wildner 	    max = res->Data.Address16.Address.Maximum;
3165943f66cSSascha Wildner 	    length = res->Data.Address16.Address.AddressLength;
317ad52dd32SSascha Wildner #ifdef ACPI_DEBUG
318ad52dd32SSascha Wildner 	    name = "Address16";
319ad52dd32SSascha Wildner #endif
320ad52dd32SSascha Wildner 	    break;
321ad52dd32SSascha Wildner 	case ACPI_RESOURCE_TYPE_ADDRESS32:
3225943f66cSSascha Wildner 	    gran = res->Data.Address32.Address.Granularity;
3235943f66cSSascha Wildner 	    min = res->Data.Address32.Address.Minimum;
3245943f66cSSascha Wildner 	    max = res->Data.Address32.Address.Maximum;
3255943f66cSSascha Wildner 	    length = res->Data.Address32.Address.AddressLength;
326ad52dd32SSascha Wildner #ifdef ACPI_DEBUG
327ad52dd32SSascha Wildner 	    name = "Address32";
328ad52dd32SSascha Wildner #endif
329ad52dd32SSascha Wildner 	    break;
330ad52dd32SSascha Wildner 	case ACPI_RESOURCE_TYPE_ADDRESS64:
3315943f66cSSascha Wildner 	    gran = res->Data.Address64.Address.Granularity;
3325943f66cSSascha Wildner 	    min = res->Data.Address64.Address.Minimum;
3335943f66cSSascha Wildner 	    max = res->Data.Address64.Address.Maximum;
3345943f66cSSascha Wildner 	    length = res->Data.Address64.Address.AddressLength;
335ad52dd32SSascha Wildner #ifdef ACPI_DEBUG
336ad52dd32SSascha Wildner 	    name = "Address64";
337ad52dd32SSascha Wildner #endif
338ad52dd32SSascha Wildner 	    break;
339ad52dd32SSascha Wildner 	default:
340ad52dd32SSascha Wildner 	    KASSERT(res->Type == ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64,
341ad52dd32SSascha Wildner 		("should never happen"));
3425943f66cSSascha Wildner 	    gran = res->Data.ExtAddress64.Address.Granularity;
3435943f66cSSascha Wildner 	    min = res->Data.ExtAddress64.Address.Minimum;
3445943f66cSSascha Wildner 	    max = res->Data.ExtAddress64.Address.Maximum;
3455943f66cSSascha Wildner 	    length = res->Data.ExtAddress64.Address.AddressLength;
346ad52dd32SSascha Wildner #ifdef ACPI_DEBUG
347ad52dd32SSascha Wildner 	    name = "ExtAddress64";
348ad52dd32SSascha Wildner #endif
349ad52dd32SSascha Wildner 	    break;
350ad52dd32SSascha Wildner 	}
351ad52dd32SSascha Wildner 	if (length <= 0)
352ad52dd32SSascha Wildner 	    break;
353ad52dd32SSascha Wildner 	if (res->Data.Address.ProducerConsumer != ACPI_CONSUMER) {
354ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
355ad52dd32SSascha Wildner 		"ignored %s %s producer\n", name,
356ad52dd32SSascha Wildner 		acpi_address_range_name(res->Data.Address.ResourceType)));
357ad52dd32SSascha Wildner 	    break;
358ad52dd32SSascha Wildner 	}
359ad52dd32SSascha Wildner 	if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE &&
360ad52dd32SSascha Wildner 	    res->Data.Address.ResourceType != ACPI_IO_RANGE) {
361ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
362ad52dd32SSascha Wildner 		"ignored %s for non-memory, non-I/O\n", name));
363ad52dd32SSascha Wildner 	    break;
364ad52dd32SSascha Wildner 	}
365ad52dd32SSascha Wildner 	if (res->Data.Address.MinAddressFixed == ACPI_ADDRESS_FIXED &&
366ad52dd32SSascha Wildner 	    res->Data.Address.MaxAddressFixed == ACPI_ADDRESS_FIXED) {
367ad52dd32SSascha Wildner 	    if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE) {
368ad52dd32SSascha Wildner 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/Memory 0x%jx/%ju\n",
369ad52dd32SSascha Wildner 		    name, (uintmax_t)min, (uintmax_t)length));
370ad52dd32SSascha Wildner 		set->set_memory(dev, arc->context, min, length);
371ad52dd32SSascha Wildner 	    } else {
372ad52dd32SSascha Wildner 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx/%ju\n", name,
373ad52dd32SSascha Wildner 		    (uintmax_t)min, (uintmax_t)length));
374ad52dd32SSascha Wildner 		set->set_ioport(dev, arc->context, min, length);
375ad52dd32SSascha Wildner 	    }
376ad52dd32SSascha Wildner 	} else {
377ad52dd32SSascha Wildner 	    if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
378ad52dd32SSascha Wildner 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
379ad52dd32SSascha Wildner 		    "%s/Memory 0x%jx-0x%jx/%ju\n", name, (uintmax_t)min,
380ad52dd32SSascha Wildner 		    (uintmax_t)max, (uintmax_t)length));
381ad52dd32SSascha Wildner 		set->set_memoryrange(dev, arc->context, min, max, length, gran);
382ad52dd32SSascha Wildner 	    } else {
383ad52dd32SSascha Wildner 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx-0x%jx/%ju\n",
384ad52dd32SSascha Wildner 		    name, (uintmax_t)min, (uintmax_t)max, (uintmax_t)length));
385ad52dd32SSascha Wildner 		set->set_iorange(dev, arc->context, min, max, length, gran);
386ad52dd32SSascha Wildner 	    }
387ad52dd32SSascha Wildner 	}
388ad52dd32SSascha Wildner 	break;
389ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
390ad52dd32SSascha Wildner 	if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) {
391ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored ExtIRQ producer\n"));
392ad52dd32SSascha Wildner 	    break;
393ad52dd32SSascha Wildner 	}
394ad52dd32SSascha Wildner 	set->set_ext_irq(dev, arc->context, res->Data.ExtendedIrq.Interrupts,
395ad52dd32SSascha Wildner 	    res->Data.ExtendedIrq.InterruptCount,
396ad52dd32SSascha Wildner 	    res->Data.ExtendedIrq.Triggering, res->Data.ExtendedIrq.Polarity);
397ad52dd32SSascha Wildner 	break;
398ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_VENDOR:
399ad52dd32SSascha Wildner 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
400ad52dd32SSascha Wildner 	    "unimplemented VendorSpecific resource\n"));
401ad52dd32SSascha Wildner 	break;
402ad52dd32SSascha Wildner     default:
403ad52dd32SSascha Wildner 	break;
404ad52dd32SSascha Wildner     }
405ad52dd32SSascha Wildner     return (AE_OK);
406ad52dd32SSascha Wildner }
407ad52dd32SSascha Wildner 
4085db2f26eSSascha Wildner /*
4095db2f26eSSascha Wildner  * Fetch a device's resources and associate them with the device.
4105db2f26eSSascha Wildner  *
4115db2f26eSSascha Wildner  * Note that it might be nice to also locate ACPI-specific resource items, such
4125db2f26eSSascha Wildner  * as GPE bits.
4135db2f26eSSascha Wildner  *
4145db2f26eSSascha Wildner  * We really need to split the resource-fetching code out from the
4155db2f26eSSascha Wildner  * resource-parsing code, since we may want to use the parsing
4165db2f26eSSascha Wildner  * code for _PRS someday.
4175db2f26eSSascha Wildner  */
4185db2f26eSSascha Wildner ACPI_STATUS
4195db2f26eSSascha Wildner acpi_parse_resources(device_t dev, ACPI_HANDLE handle,
4205db2f26eSSascha Wildner 		     struct acpi_parse_resource_set *set, void *arg)
4215db2f26eSSascha Wildner {
422ad52dd32SSascha Wildner     struct acpi_resource_context arc;
4235db2f26eSSascha Wildner     ACPI_STATUS		status;
4245db2f26eSSascha Wildner 
4255db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
4265db2f26eSSascha Wildner 
427ad52dd32SSascha Wildner     set->set_init(dev, arg, &arc.context);
428ad52dd32SSascha Wildner     arc.set = set;
429ad52dd32SSascha Wildner     arc.dev = dev;
430ad52dd32SSascha Wildner     status = AcpiWalkResources(handle, "_CRS", acpi_parse_resource, &arc);
431ad52dd32SSascha Wildner     if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
4325db2f26eSSascha Wildner 	kprintf("can't fetch resources for %s - %s\n",
4335db2f26eSSascha Wildner 	    acpi_name(handle), AcpiFormatException(status));
4345db2f26eSSascha Wildner 	return_ACPI_STATUS (status);
4355db2f26eSSascha Wildner     }
436ad52dd32SSascha Wildner     set->set_done(dev, arc.context);
4375db2f26eSSascha Wildner     return_ACPI_STATUS (AE_OK);
4385db2f26eSSascha Wildner }
4395db2f26eSSascha Wildner 
4405db2f26eSSascha Wildner /*
4415db2f26eSSascha Wildner  * Resource-set vectors used to attach _CRS-derived resources
4425db2f26eSSascha Wildner  * to an ACPI device.
4435db2f26eSSascha Wildner  */
4445db2f26eSSascha Wildner static void	acpi_res_set_init(device_t dev, void *arg, void **context);
4455db2f26eSSascha Wildner static void	acpi_res_set_done(device_t dev, void *context);
4465db2f26eSSascha Wildner static void	acpi_res_set_ioport(device_t dev, void *context,
447ad52dd32SSascha Wildner 				    uint64_t base, uint64_t length);
4485db2f26eSSascha Wildner static void	acpi_res_set_iorange(device_t dev, void *context,
449ad52dd32SSascha Wildner 				     uint64_t low, uint64_t high,
450ad52dd32SSascha Wildner 				     uint64_t length, uint64_t align);
4515db2f26eSSascha Wildner static void	acpi_res_set_memory(device_t dev, void *context,
452ad52dd32SSascha Wildner 				    uint64_t base, uint64_t length);
4535db2f26eSSascha Wildner static void	acpi_res_set_memoryrange(device_t dev, void *context,
454ad52dd32SSascha Wildner 					 uint64_t low, uint64_t high,
455ad52dd32SSascha Wildner 					 uint64_t length, uint64_t align);
4563905511eSSascha Wildner static void	acpi_res_set_irq(device_t dev, void *context, uint8_t *irq,
4575db2f26eSSascha Wildner 				 int count, int trig, int pol);
4585db2f26eSSascha Wildner static void	acpi_res_set_ext_irq(device_t dev, void *context,
4593905511eSSascha Wildner 				 uint32_t *irq, int count, int trig, int pol);
4603905511eSSascha Wildner static void	acpi_res_set_drq(device_t dev, void *context, uint8_t *drq,
4615db2f26eSSascha Wildner 				 int count);
4625db2f26eSSascha Wildner static void	acpi_res_set_start_dependent(device_t dev, void *context,
4635db2f26eSSascha Wildner 					     int preference);
4645db2f26eSSascha Wildner static void	acpi_res_set_end_dependent(device_t dev, void *context);
4655db2f26eSSascha Wildner 
4665db2f26eSSascha Wildner struct acpi_parse_resource_set acpi_res_parse_set = {
4675db2f26eSSascha Wildner     acpi_res_set_init,
4685db2f26eSSascha Wildner     acpi_res_set_done,
4695db2f26eSSascha Wildner     acpi_res_set_ioport,
4705db2f26eSSascha Wildner     acpi_res_set_iorange,
4715db2f26eSSascha Wildner     acpi_res_set_memory,
4725db2f26eSSascha Wildner     acpi_res_set_memoryrange,
4735db2f26eSSascha Wildner     acpi_res_set_irq,
4745db2f26eSSascha Wildner     acpi_res_set_ext_irq,
4755db2f26eSSascha Wildner     acpi_res_set_drq,
4765db2f26eSSascha Wildner     acpi_res_set_start_dependent,
4775db2f26eSSascha Wildner     acpi_res_set_end_dependent
4785db2f26eSSascha Wildner };
4795db2f26eSSascha Wildner 
4805db2f26eSSascha Wildner struct acpi_res_context {
4815db2f26eSSascha Wildner     int		ar_nio;
4825db2f26eSSascha Wildner     int		ar_nmem;
4835db2f26eSSascha Wildner     int		ar_nirq;
4845db2f26eSSascha Wildner     int		ar_ndrq;
4855db2f26eSSascha Wildner     void 	*ar_parent;
4865db2f26eSSascha Wildner };
4875db2f26eSSascha Wildner 
4885db2f26eSSascha Wildner static void
4895db2f26eSSascha Wildner acpi_res_set_init(device_t dev, void *arg, void **context)
4905db2f26eSSascha Wildner {
4915db2f26eSSascha Wildner     struct acpi_res_context	*cp;
4925db2f26eSSascha Wildner 
4935db2f26eSSascha Wildner     if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
4945db2f26eSSascha Wildner 	bzero(cp, sizeof(*cp));
4955db2f26eSSascha Wildner 	cp->ar_parent = arg;
4965db2f26eSSascha Wildner 	*context = cp;
4975db2f26eSSascha Wildner     }
4985db2f26eSSascha Wildner }
4995db2f26eSSascha Wildner 
5005db2f26eSSascha Wildner static void
5015db2f26eSSascha Wildner acpi_res_set_done(device_t dev, void *context)
5025db2f26eSSascha Wildner {
5035db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
5045db2f26eSSascha Wildner 
5055db2f26eSSascha Wildner     if (cp == NULL)
5065db2f26eSSascha Wildner 	return;
5075db2f26eSSascha Wildner     AcpiOsFree(cp);
5085db2f26eSSascha Wildner }
5095db2f26eSSascha Wildner 
5105db2f26eSSascha Wildner static void
511ad52dd32SSascha Wildner acpi_res_set_ioport(device_t dev, void *context, uint64_t base,
512ad52dd32SSascha Wildner 		    uint64_t length)
5135db2f26eSSascha Wildner {
5145db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
5155db2f26eSSascha Wildner 
5165db2f26eSSascha Wildner     if (cp == NULL)
5175db2f26eSSascha Wildner 	return;
5185db2f26eSSascha Wildner     bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length, -1);
5195db2f26eSSascha Wildner }
5205db2f26eSSascha Wildner 
5215db2f26eSSascha Wildner static void
522ad52dd32SSascha Wildner acpi_res_set_iorange(device_t dev, void *context, uint64_t low,
523ad52dd32SSascha Wildner 		     uint64_t high, uint64_t length, uint64_t align)
5245db2f26eSSascha Wildner {
5255db2f26eSSascha Wildner     struct acpi_res_context *cp = (struct acpi_res_context *)context;
5269ed6fcdbSSepherosa Ziehau     uint64_t base;
5275db2f26eSSascha Wildner 
5285db2f26eSSascha Wildner     if (cp == NULL)
5295db2f26eSSascha Wildner 	return;
5309ed6fcdbSSepherosa Ziehau 
5319ed6fcdbSSepherosa Ziehau     base = roundup(low, align);
5329ed6fcdbSSepherosa Ziehau     if (base + length - 1 <= high) {
5339ed6fcdbSSepherosa Ziehau 	acpi_res_set_ioport(dev, context, base, length);
5349ed6fcdbSSepherosa Ziehau 	return;
5359ed6fcdbSSepherosa Ziehau     }
5369ed6fcdbSSepherosa Ziehau     device_printf(dev, "I/O range [0x%jx,0x%jx,0x%jx,0x%jx] not supported\n",
5379ed6fcdbSSepherosa Ziehau 	(uintmax_t)low, (uintmax_t)high, (uintmax_t)length, (uintmax_t)align);
5385db2f26eSSascha Wildner }
5395db2f26eSSascha Wildner 
5405db2f26eSSascha Wildner static void
541ad52dd32SSascha Wildner acpi_res_set_memory(device_t dev, void *context, uint64_t base,
542ad52dd32SSascha Wildner 		    uint64_t length)
5435db2f26eSSascha Wildner {
5445db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
5455db2f26eSSascha Wildner 
5465db2f26eSSascha Wildner     if (cp == NULL)
5475db2f26eSSascha Wildner 	return;
5485db2f26eSSascha Wildner 
5495db2f26eSSascha Wildner     bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length, -1);
5505db2f26eSSascha Wildner }
5515db2f26eSSascha Wildner 
5525db2f26eSSascha Wildner static void
553ad52dd32SSascha Wildner acpi_res_set_memoryrange(device_t dev, void *context, uint64_t low,
554ad52dd32SSascha Wildner 			 uint64_t high, uint64_t length, uint64_t align)
5555db2f26eSSascha Wildner {
5565db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
5575db2f26eSSascha Wildner 
5585db2f26eSSascha Wildner     if (cp == NULL)
5595db2f26eSSascha Wildner 	return;
5609ed6fcdbSSepherosa Ziehau     device_printf(dev, "memory range [0x%jx,0x%jx,0x%jx,0x%jx] "
5619ed6fcdbSSepherosa Ziehau         "not supported\n",
5629ed6fcdbSSepherosa Ziehau 	(uintmax_t)low, (uintmax_t)high, (uintmax_t)length, (uintmax_t)align);
5635db2f26eSSascha Wildner }
5645db2f26eSSascha Wildner 
5655db2f26eSSascha Wildner static void
5663905511eSSascha Wildner acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count,
5675db2f26eSSascha Wildner     int trig, int pol)
5685db2f26eSSascha Wildner {
5695db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
5705db2f26eSSascha Wildner 
5715db2f26eSSascha Wildner     if (cp == NULL || irq == NULL)
5725db2f26eSSascha Wildner 	return;
5735db2f26eSSascha Wildner 
5745db2f26eSSascha Wildner     /* This implements no resource relocation. */
5755db2f26eSSascha Wildner     if (count != 1)
5765db2f26eSSascha Wildner 	return;
5775db2f26eSSascha Wildner 
5785db2f26eSSascha Wildner     bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1,
5795db2f26eSSascha Wildner         machintr_legacy_intr_cpuid(*irq));
5805db2f26eSSascha Wildner }
5815db2f26eSSascha Wildner 
5825db2f26eSSascha Wildner static void
5833905511eSSascha Wildner acpi_res_set_ext_irq(device_t dev, void *context, uint32_t *irq, int count,
5845db2f26eSSascha Wildner     int trig, int pol)
5855db2f26eSSascha Wildner {
5865db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
5875db2f26eSSascha Wildner 
5885db2f26eSSascha Wildner     if (cp == NULL || irq == NULL)
5895db2f26eSSascha Wildner 	return;
5905db2f26eSSascha Wildner 
5915db2f26eSSascha Wildner     /* This implements no resource relocation. */
5925db2f26eSSascha Wildner     if (count != 1)
5935db2f26eSSascha Wildner 	return;
5945db2f26eSSascha Wildner 
59537bc3036SSepherosa Ziehau     /* There is no such IRQ at all */
59637bc3036SSepherosa Ziehau     if (machintr_legacy_intr_find(*irq,
59737bc3036SSepherosa Ziehau 	INTR_TRIGGER_CONFORM, INTR_POLARITY_CONFORM) < 0)
59837bc3036SSepherosa Ziehau 	return;
59937bc3036SSepherosa Ziehau 
6005db2f26eSSascha Wildner     bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1,
6015db2f26eSSascha Wildner         machintr_legacy_intr_cpuid(*irq));
6025db2f26eSSascha Wildner }
6035db2f26eSSascha Wildner 
6045db2f26eSSascha Wildner static void
6053905511eSSascha Wildner acpi_res_set_drq(device_t dev, void *context, uint8_t *drq, int count)
6065db2f26eSSascha Wildner {
6075db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
6085db2f26eSSascha Wildner 
6095db2f26eSSascha Wildner     if (cp == NULL || drq == NULL)
6105db2f26eSSascha Wildner 	return;
6115db2f26eSSascha Wildner 
6125db2f26eSSascha Wildner     /* This implements no resource relocation. */
6135db2f26eSSascha Wildner     if (count != 1)
6145db2f26eSSascha Wildner 	return;
6155db2f26eSSascha Wildner 
6165db2f26eSSascha Wildner     bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1, -1);
6175db2f26eSSascha Wildner }
6185db2f26eSSascha Wildner 
6195db2f26eSSascha Wildner static void
6205db2f26eSSascha Wildner acpi_res_set_start_dependent(device_t dev, void *context, int preference)
6215db2f26eSSascha Wildner {
6225db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
6235db2f26eSSascha Wildner 
6245db2f26eSSascha Wildner     if (cp == NULL)
6255db2f26eSSascha Wildner 	return;
6265db2f26eSSascha Wildner     device_printf(dev, "dependent functions not supported\n");
6275db2f26eSSascha Wildner }
6285db2f26eSSascha Wildner 
6295db2f26eSSascha Wildner static void
6305db2f26eSSascha Wildner acpi_res_set_end_dependent(device_t dev, void *context)
6315db2f26eSSascha Wildner {
6325db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
6335db2f26eSSascha Wildner 
6345db2f26eSSascha Wildner     if (cp == NULL)
6355db2f26eSSascha Wildner 	return;
6365db2f26eSSascha Wildner     device_printf(dev, "dependent functions not supported\n");
6375db2f26eSSascha Wildner }
6385db2f26eSSascha Wildner 
6395db2f26eSSascha Wildner /*
6405db2f26eSSascha Wildner  * Resource-owning placeholders for IO and memory pseudo-devices.
6415db2f26eSSascha Wildner  *
6425db2f26eSSascha Wildner  * This code allocates system resources that will be used by ACPI
6435db2f26eSSascha Wildner  * child devices.  The acpi parent manages these resources through a
6445db2f26eSSascha Wildner  * private rman.
6455db2f26eSSascha Wildner  */
6465db2f26eSSascha Wildner 
6475db2f26eSSascha Wildner static int	acpi_sysres_rid = 100;
6485db2f26eSSascha Wildner 
6495db2f26eSSascha Wildner static int	acpi_sysres_probe(device_t dev);
6505db2f26eSSascha Wildner static int	acpi_sysres_attach(device_t dev);
6515db2f26eSSascha Wildner 
6525db2f26eSSascha Wildner static device_method_t acpi_sysres_methods[] = {
6535db2f26eSSascha Wildner     /* Device interface */
6545db2f26eSSascha Wildner     DEVMETHOD(device_probe,	acpi_sysres_probe),
6555db2f26eSSascha Wildner     DEVMETHOD(device_attach,	acpi_sysres_attach),
6565db2f26eSSascha Wildner 
657d3c9c58eSSascha Wildner     DEVMETHOD_END
6585db2f26eSSascha Wildner };
6595db2f26eSSascha Wildner 
6605db2f26eSSascha Wildner static driver_t acpi_sysres_driver = {
6615db2f26eSSascha Wildner     "acpi_sysresource",
6625db2f26eSSascha Wildner     acpi_sysres_methods,
6635db2f26eSSascha Wildner     0,
664*df21e16dSImre Vadász     .gpri = KOBJ_GPRI_ACPI+2
6655db2f26eSSascha Wildner };
6665db2f26eSSascha Wildner 
6675db2f26eSSascha Wildner static devclass_t acpi_sysres_devclass;
6685db2f26eSSascha Wildner DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, acpi_sysres_devclass,
66908bd0208SSascha Wildner     NULL, NULL);
6705db2f26eSSascha Wildner MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
6715db2f26eSSascha Wildner 
6725db2f26eSSascha Wildner static int
6735db2f26eSSascha Wildner acpi_sysres_probe(device_t dev)
6745db2f26eSSascha Wildner {
6755db2f26eSSascha Wildner     static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
6765db2f26eSSascha Wildner 
6775db2f26eSSascha Wildner     if (acpi_disabled("sysresource") ||
6785db2f26eSSascha Wildner 	ACPI_ID_PROBE(device_get_parent(dev), dev, sysres_ids) == NULL)
6795db2f26eSSascha Wildner 	return (ENXIO);
6805db2f26eSSascha Wildner 
6815db2f26eSSascha Wildner     device_set_desc(dev, "System Resource");
68208710fc1SSascha Wildner     if (bootverbose == 0)
6835db2f26eSSascha Wildner 	    device_quiet(dev);
6845db2f26eSSascha Wildner     return (BUS_PROBE_DEFAULT);
6855db2f26eSSascha Wildner }
6865db2f26eSSascha Wildner 
6875db2f26eSSascha Wildner static int
6885db2f26eSSascha Wildner acpi_sysres_attach(device_t dev)
6895db2f26eSSascha Wildner {
6905db2f26eSSascha Wildner     device_t bus;
6915db2f26eSSascha Wildner     struct resource_list_entry *bus_rle, *dev_rle;
6925db2f26eSSascha Wildner     struct resource_list *bus_rl, *dev_rl;
6935db2f26eSSascha Wildner     int done, type;
6945db2f26eSSascha Wildner     u_long start, end, count;
695ad52dd32SSascha Wildner 
6965db2f26eSSascha Wildner     /*
6975db2f26eSSascha Wildner      * Loop through all current resources to see if the new one overlaps
6985db2f26eSSascha Wildner      * any existing ones.  If so, grow the old one up and/or down
6995db2f26eSSascha Wildner      * accordingly.  Discard any that are wholly contained in the old.  If
7005db2f26eSSascha Wildner      * the resource is unique, add it to the parent.  It will later go into
7015db2f26eSSascha Wildner      * the rman pool.
7025db2f26eSSascha Wildner      */
7035db2f26eSSascha Wildner     bus = device_get_parent(dev);
7045db2f26eSSascha Wildner     dev_rl = BUS_GET_RESOURCE_LIST(bus, dev);
7055db2f26eSSascha Wildner     bus_rl = BUS_GET_RESOURCE_LIST(device_get_parent(bus), bus);
7065db2f26eSSascha Wildner     if (bus_rl)
7075db2f26eSSascha Wildner 	kprintf("busrl is not null!\n");
7085db2f26eSSascha Wildner     SLIST_FOREACH(dev_rle, dev_rl, link) {
7095db2f26eSSascha Wildner 	if (dev_rle->type != SYS_RES_IOPORT && dev_rle->type != SYS_RES_MEMORY)
7105db2f26eSSascha Wildner 	    continue;
7115db2f26eSSascha Wildner 
7125db2f26eSSascha Wildner 	start = dev_rle->start;
7135db2f26eSSascha Wildner 	end = dev_rle->end;
7145db2f26eSSascha Wildner 	count = dev_rle->count;
7155db2f26eSSascha Wildner 	type = dev_rle->type;
7165db2f26eSSascha Wildner 	done = FALSE;
7175db2f26eSSascha Wildner 	if (bus_rl) {
7185db2f26eSSascha Wildner 	    SLIST_FOREACH(bus_rle, bus_rl, link) {
7195db2f26eSSascha Wildner 		if (bus_rle->type != type)
7205db2f26eSSascha Wildner 		    continue;
7215db2f26eSSascha Wildner 
7225db2f26eSSascha Wildner 		/* New resource wholly contained in old, discard. */
7235db2f26eSSascha Wildner 		if (start >= bus_rle->start && end <= bus_rle->end)
7245db2f26eSSascha Wildner 		    break;
7255db2f26eSSascha Wildner 
7265db2f26eSSascha Wildner 		/* New tail overlaps old head, grow existing resource downward. */
7275db2f26eSSascha Wildner 		if (start < bus_rle->start && end >= bus_rle->start) {
7285db2f26eSSascha Wildner 		    bus_rle->count += bus_rle->start - start;
7295db2f26eSSascha Wildner 		    bus_rle->start = start;
7305db2f26eSSascha Wildner 		    done = TRUE;
7315db2f26eSSascha Wildner 		}
7325db2f26eSSascha Wildner 
7335db2f26eSSascha Wildner 		/* New head overlaps old tail, grow existing resource upward. */
7345db2f26eSSascha Wildner 		if (start <= bus_rle->end && end > bus_rle->end) {
7355db2f26eSSascha Wildner 		    bus_rle->count += end - bus_rle->end;
7365db2f26eSSascha Wildner 		    bus_rle->end = end;
7375db2f26eSSascha Wildner 		    done = TRUE;
7385db2f26eSSascha Wildner 		}
7395db2f26eSSascha Wildner 
7405db2f26eSSascha Wildner 		/* If we adjusted the old resource, we're finished. */
7415db2f26eSSascha Wildner 		if (done)
7425db2f26eSSascha Wildner 		    break;
7435db2f26eSSascha Wildner 	    }
74408bd0208SSascha Wildner 	} else {
74508bd0208SSascha Wildner 	    bus_rle = NULL;
74608bd0208SSascha Wildner 	}
7475db2f26eSSascha Wildner 	/* If we didn't merge with anything, add this resource. */
748ad52dd32SSascha Wildner 	if (bus_rle == NULL)
7495db2f26eSSascha Wildner 	    bus_set_resource(bus, type, acpi_sysres_rid++, start, count, -1);
7505db2f26eSSascha Wildner     }
7515db2f26eSSascha Wildner 
7525db2f26eSSascha Wildner     /* After merging/moving resources to the parent, free the list. */
7535db2f26eSSascha Wildner     resource_list_free(dev_rl);
7545db2f26eSSascha Wildner 
7555db2f26eSSascha Wildner     return (0);
7565db2f26eSSascha Wildner }
757