xref: /dflybsd-src/sys/dev/acpica/acpi_resource.c (revision 8506772f4f44fcae9c78e61800e54be0399905f8)
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
acpi_lookup_irq_handler(ACPI_RESOURCE * res,void * context)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
acpi_lookup_irq_resource(device_t dev,int rid,struct resource * res,ACPI_RESOURCE * acpi_res)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
acpi_config_intr(device_t dev,ACPI_RESOURCE * res)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__)
140*8506772fSMichael Neumann     if (irq < 16 && trig == ACPI_EDGE_SENSITIVE && pol == ACPI_ACTIVE_LOW &&
141*8506772fSMichael Neumann 	acpi_override_isa_irq_polarity) {
142*8506772fSMichael Neumann 	device_printf(dev, "forcing active-hi polarity for IRQ %u\n", irq);
143ad52dd32SSascha Wildner 	pol = ACPI_ACTIVE_HIGH;
144*8506772fSMichael Neumann     }
145ad52dd32SSascha Wildner #endif
146ad52dd32SSascha Wildner 
1475db2f26eSSascha Wildner     if (trig == ACPI_EDGE_SENSITIVE)
1485db2f26eSSascha Wildner     	trigger = INTR_TRIGGER_EDGE;
1495db2f26eSSascha Wildner     else
1505db2f26eSSascha Wildner     	trigger = INTR_TRIGGER_LEVEL;
1515db2f26eSSascha Wildner 
1525db2f26eSSascha Wildner     if (pol == ACPI_ACTIVE_HIGH)
1535db2f26eSSascha Wildner 	polarity = INTR_POLARITY_HIGH;
1545db2f26eSSascha Wildner     else
1555db2f26eSSascha Wildner     	polarity = INTR_POLARITY_LOW;
1565db2f26eSSascha Wildner 
1575db2f26eSSascha Wildner     if (machintr_legacy_intr_find(irq, trigger, polarity) < 0)
158ad52dd32SSascha Wildner 	kprintf("%s: Skip irq %d config\n", __func__, irq);
1595db2f26eSSascha Wildner     else
1605db2f26eSSascha Wildner 	BUS_CONFIG_INTR(dev, dev, irq, trigger, polarity);
1615db2f26eSSascha Wildner }
1625db2f26eSSascha Wildner 
163ad52dd32SSascha Wildner struct acpi_resource_context {
164ad52dd32SSascha Wildner     struct acpi_parse_resource_set *set;
165ad52dd32SSascha Wildner     device_t	dev;
166ad52dd32SSascha Wildner     void	*context;
167ad52dd32SSascha Wildner };
168ad52dd32SSascha Wildner 
169ad52dd32SSascha Wildner #ifdef ACPI_DEBUG_OUTPUT
170ad52dd32SSascha Wildner static const char *
acpi_address_range_name(UINT8 ResourceType)171ad52dd32SSascha Wildner acpi_address_range_name(UINT8 ResourceType)
172ad52dd32SSascha Wildner {
173ad52dd32SSascha Wildner     static char buf[16];
174ad52dd32SSascha Wildner 
175ad52dd32SSascha Wildner     switch (ResourceType) {
176ad52dd32SSascha Wildner     case ACPI_MEMORY_RANGE:
177ad52dd32SSascha Wildner 	    return ("Memory");
178ad52dd32SSascha Wildner     case ACPI_IO_RANGE:
179ad52dd32SSascha Wildner 	    return ("IO");
180ad52dd32SSascha Wildner     case ACPI_BUS_NUMBER_RANGE:
181ad52dd32SSascha Wildner 	    return ("Bus Number");
182ad52dd32SSascha Wildner     default:
183ad52dd32SSascha Wildner 	    ksnprintf(buf, sizeof(buf), "type %u", ResourceType);
184ad52dd32SSascha Wildner 	    return (buf);
185ad52dd32SSascha Wildner     }
186ad52dd32SSascha Wildner }
187ad52dd32SSascha Wildner #endif
188ad52dd32SSascha Wildner 
189ad52dd32SSascha Wildner static ACPI_STATUS
acpi_parse_resource(ACPI_RESOURCE * res,void * context)190ad52dd32SSascha Wildner acpi_parse_resource(ACPI_RESOURCE *res, void *context)
191ad52dd32SSascha Wildner {
192ad52dd32SSascha Wildner     struct acpi_parse_resource_set *set;
193ad52dd32SSascha Wildner     struct acpi_resource_context *arc;
194ad52dd32SSascha Wildner     UINT64 min, max, length, gran;
195ad52dd32SSascha Wildner #ifdef ACPI_DEBUG
196ad52dd32SSascha Wildner     const char *name;
197ad52dd32SSascha Wildner #endif
198ad52dd32SSascha Wildner     device_t dev;
199ad52dd32SSascha Wildner 
200ad52dd32SSascha Wildner     arc = context;
201ad52dd32SSascha Wildner     dev = arc->dev;
202ad52dd32SSascha Wildner     set = arc->set;
203ad52dd32SSascha Wildner 
204ad52dd32SSascha Wildner     switch (res->Type) {
205ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_END_TAG:
206ad52dd32SSascha Wildner 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
207ad52dd32SSascha Wildner 	break;
208ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_FIXED_IO:
209ad52dd32SSascha Wildner 	if (res->Data.FixedIo.AddressLength <= 0)
210ad52dd32SSascha Wildner 	    break;
211ad52dd32SSascha Wildner 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
212ad52dd32SSascha Wildner 	    res->Data.FixedIo.Address, res->Data.FixedIo.AddressLength));
213ad52dd32SSascha Wildner 	set->set_ioport(dev, arc->context, res->Data.FixedIo.Address,
214ad52dd32SSascha Wildner 	    res->Data.FixedIo.AddressLength);
215ad52dd32SSascha Wildner 	break;
216ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_IO:
217ad52dd32SSascha Wildner 	if (res->Data.Io.AddressLength <= 0)
218ad52dd32SSascha Wildner 	    break;
219ad52dd32SSascha Wildner 	if (res->Data.Io.Minimum == res->Data.Io.Maximum) {
220ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
221ad52dd32SSascha Wildner 		res->Data.Io.Minimum, res->Data.Io.AddressLength));
222ad52dd32SSascha Wildner 	    set->set_ioport(dev, arc->context, res->Data.Io.Minimum,
223ad52dd32SSascha Wildner 		res->Data.Io.AddressLength);
224ad52dd32SSascha Wildner 	} else {
225ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
226ad52dd32SSascha Wildner 		res->Data.Io.Minimum, res->Data.Io.Maximum,
227ad52dd32SSascha Wildner 		res->Data.Io.AddressLength));
228ad52dd32SSascha Wildner 	    set->set_iorange(dev, arc->context, res->Data.Io.Minimum,
229ad52dd32SSascha Wildner 		res->Data.Io.Maximum, res->Data.Io.AddressLength,
230ad52dd32SSascha Wildner 		res->Data.Io.Alignment);
231ad52dd32SSascha Wildner 	}
232ad52dd32SSascha Wildner 	break;
233ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
234ad52dd32SSascha Wildner 	if (res->Data.FixedMemory32.AddressLength <= 0)
235ad52dd32SSascha Wildner 	    break;
236ad52dd32SSascha Wildner 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
237ad52dd32SSascha Wildner 	    res->Data.FixedMemory32.Address,
238ad52dd32SSascha Wildner 	    res->Data.FixedMemory32.AddressLength));
239ad52dd32SSascha Wildner 	set->set_memory(dev, arc->context, res->Data.FixedMemory32.Address,
240ad52dd32SSascha Wildner 	    res->Data.FixedMemory32.AddressLength);
241ad52dd32SSascha Wildner 	break;
242ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_MEMORY32:
243ad52dd32SSascha Wildner 	if (res->Data.Memory32.AddressLength <= 0)
244ad52dd32SSascha Wildner 	    break;
245ad52dd32SSascha Wildner 	if (res->Data.Memory32.Minimum == res->Data.Memory32.Maximum) {
246ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
247ad52dd32SSascha Wildner 		res->Data.Memory32.Minimum, res->Data.Memory32.AddressLength));
248ad52dd32SSascha Wildner 	    set->set_memory(dev, arc->context, res->Data.Memory32.Minimum,
249ad52dd32SSascha Wildner 		res->Data.Memory32.AddressLength);
250ad52dd32SSascha Wildner 	} else {
251ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
252ad52dd32SSascha Wildner 		res->Data.Memory32.Minimum, res->Data.Memory32.Maximum,
253ad52dd32SSascha Wildner 		res->Data.Memory32.AddressLength));
254ad52dd32SSascha Wildner 	    set->set_memoryrange(dev, arc->context, res->Data.Memory32.Minimum,
255ad52dd32SSascha Wildner 		res->Data.Memory32.Maximum, res->Data.Memory32.AddressLength,
256ad52dd32SSascha Wildner 		res->Data.Memory32.Alignment);
257ad52dd32SSascha Wildner 	}
258ad52dd32SSascha Wildner 	break;
259ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_MEMORY24:
260ad52dd32SSascha Wildner 	if (res->Data.Memory24.AddressLength <= 0)
261ad52dd32SSascha Wildner 	    break;
262ad52dd32SSascha Wildner 	if (res->Data.Memory24.Minimum == res->Data.Memory24.Maximum) {
263ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
264ad52dd32SSascha Wildner 		res->Data.Memory24.Minimum, res->Data.Memory24.AddressLength));
265ad52dd32SSascha Wildner 	    set->set_memory(dev, arc->context, res->Data.Memory24.Minimum,
266ad52dd32SSascha Wildner 		res->Data.Memory24.AddressLength);
267ad52dd32SSascha Wildner 	} else {
268ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
269ad52dd32SSascha Wildner 		res->Data.Memory24.Minimum, res->Data.Memory24.Maximum,
270ad52dd32SSascha Wildner 		res->Data.Memory24.AddressLength));
271ad52dd32SSascha Wildner 	    set->set_memoryrange(dev, arc->context, res->Data.Memory24.Minimum,
272ad52dd32SSascha Wildner 		res->Data.Memory24.Maximum, res->Data.Memory24.AddressLength,
273ad52dd32SSascha Wildner 		res->Data.Memory24.Alignment);
274ad52dd32SSascha Wildner 	}
275ad52dd32SSascha Wildner 	break;
276ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_IRQ:
277ad52dd32SSascha Wildner 	/*
278ad52dd32SSascha Wildner 	 * from 1.0b 6.4.2
279ad52dd32SSascha Wildner 	 * "This structure is repeated for each separate interrupt
280ad52dd32SSascha Wildner 	 * required"
281ad52dd32SSascha Wildner 	 */
282ad52dd32SSascha Wildner 	set->set_irq(dev, arc->context, res->Data.Irq.Interrupts,
283ad52dd32SSascha Wildner 	    res->Data.Irq.InterruptCount, res->Data.Irq.Triggering,
284ad52dd32SSascha Wildner 	    res->Data.Irq.Polarity);
285ad52dd32SSascha Wildner 	break;
286ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_DMA:
287ad52dd32SSascha Wildner 	/*
288ad52dd32SSascha Wildner 	 * from 1.0b 6.4.3
289ad52dd32SSascha Wildner 	 * "This structure is repeated for each separate DMA channel
290ad52dd32SSascha Wildner 	 * required"
291ad52dd32SSascha Wildner 	 */
292ad52dd32SSascha Wildner 	set->set_drq(dev, arc->context, res->Data.Dma.Channels,
293ad52dd32SSascha Wildner 	    res->Data.Dma.ChannelCount);
294ad52dd32SSascha Wildner 	break;
295ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_START_DEPENDENT:
296ad52dd32SSascha Wildner 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependent functions\n"));
297ad52dd32SSascha Wildner 	set->set_start_dependent(dev, arc->context,
298ad52dd32SSascha Wildner 	    res->Data.StartDpf.CompatibilityPriority);
299ad52dd32SSascha Wildner 	break;
300ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_END_DEPENDENT:
301ad52dd32SSascha Wildner 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependent functions\n"));
302ad52dd32SSascha Wildner 	set->set_end_dependent(dev, arc->context);
303ad52dd32SSascha Wildner 	break;
304ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_ADDRESS16:
305ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_ADDRESS32:
306ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_ADDRESS64:
307ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
308ad52dd32SSascha Wildner 	switch (res->Type) {
309ad52dd32SSascha Wildner 	case ACPI_RESOURCE_TYPE_ADDRESS16:
3105943f66cSSascha Wildner 	    gran = res->Data.Address16.Address.Granularity;
3115943f66cSSascha Wildner 	    min = res->Data.Address16.Address.Minimum;
3125943f66cSSascha Wildner 	    max = res->Data.Address16.Address.Maximum;
3135943f66cSSascha Wildner 	    length = res->Data.Address16.Address.AddressLength;
314ad52dd32SSascha Wildner #ifdef ACPI_DEBUG
315ad52dd32SSascha Wildner 	    name = "Address16";
316ad52dd32SSascha Wildner #endif
317ad52dd32SSascha Wildner 	    break;
318ad52dd32SSascha Wildner 	case ACPI_RESOURCE_TYPE_ADDRESS32:
3195943f66cSSascha Wildner 	    gran = res->Data.Address32.Address.Granularity;
3205943f66cSSascha Wildner 	    min = res->Data.Address32.Address.Minimum;
3215943f66cSSascha Wildner 	    max = res->Data.Address32.Address.Maximum;
3225943f66cSSascha Wildner 	    length = res->Data.Address32.Address.AddressLength;
323ad52dd32SSascha Wildner #ifdef ACPI_DEBUG
324ad52dd32SSascha Wildner 	    name = "Address32";
325ad52dd32SSascha Wildner #endif
326ad52dd32SSascha Wildner 	    break;
327ad52dd32SSascha Wildner 	case ACPI_RESOURCE_TYPE_ADDRESS64:
3285943f66cSSascha Wildner 	    gran = res->Data.Address64.Address.Granularity;
3295943f66cSSascha Wildner 	    min = res->Data.Address64.Address.Minimum;
3305943f66cSSascha Wildner 	    max = res->Data.Address64.Address.Maximum;
3315943f66cSSascha Wildner 	    length = res->Data.Address64.Address.AddressLength;
332ad52dd32SSascha Wildner #ifdef ACPI_DEBUG
333ad52dd32SSascha Wildner 	    name = "Address64";
334ad52dd32SSascha Wildner #endif
335ad52dd32SSascha Wildner 	    break;
336ad52dd32SSascha Wildner 	default:
337ad52dd32SSascha Wildner 	    KASSERT(res->Type == ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64,
338ad52dd32SSascha Wildner 		("should never happen"));
3395943f66cSSascha Wildner 	    gran = res->Data.ExtAddress64.Address.Granularity;
3405943f66cSSascha Wildner 	    min = res->Data.ExtAddress64.Address.Minimum;
3415943f66cSSascha Wildner 	    max = res->Data.ExtAddress64.Address.Maximum;
3425943f66cSSascha Wildner 	    length = res->Data.ExtAddress64.Address.AddressLength;
343ad52dd32SSascha Wildner #ifdef ACPI_DEBUG
344ad52dd32SSascha Wildner 	    name = "ExtAddress64";
345ad52dd32SSascha Wildner #endif
346ad52dd32SSascha Wildner 	    break;
347ad52dd32SSascha Wildner 	}
348ad52dd32SSascha Wildner 	if (length <= 0)
349ad52dd32SSascha Wildner 	    break;
350ad52dd32SSascha Wildner 	if (res->Data.Address.ProducerConsumer != ACPI_CONSUMER) {
351ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
352ad52dd32SSascha Wildner 		"ignored %s %s producer\n", name,
353ad52dd32SSascha Wildner 		acpi_address_range_name(res->Data.Address.ResourceType)));
354ad52dd32SSascha Wildner 	    break;
355ad52dd32SSascha Wildner 	}
356ad52dd32SSascha Wildner 	if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE &&
357ad52dd32SSascha Wildner 	    res->Data.Address.ResourceType != ACPI_IO_RANGE) {
358ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
359ad52dd32SSascha Wildner 		"ignored %s for non-memory, non-I/O\n", name));
360ad52dd32SSascha Wildner 	    break;
361ad52dd32SSascha Wildner 	}
362ad52dd32SSascha Wildner 	if (res->Data.Address.MinAddressFixed == ACPI_ADDRESS_FIXED &&
363ad52dd32SSascha Wildner 	    res->Data.Address.MaxAddressFixed == ACPI_ADDRESS_FIXED) {
364ad52dd32SSascha Wildner 	    if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE) {
365ad52dd32SSascha Wildner 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/Memory 0x%jx/%ju\n",
366ad52dd32SSascha Wildner 		    name, (uintmax_t)min, (uintmax_t)length));
367ad52dd32SSascha Wildner 		set->set_memory(dev, arc->context, min, length);
368ad52dd32SSascha Wildner 	    } else {
369ad52dd32SSascha Wildner 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx/%ju\n", name,
370ad52dd32SSascha Wildner 		    (uintmax_t)min, (uintmax_t)length));
371ad52dd32SSascha Wildner 		set->set_ioport(dev, arc->context, min, length);
372ad52dd32SSascha Wildner 	    }
373ad52dd32SSascha Wildner 	} else {
374ad52dd32SSascha Wildner 	    if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
375ad52dd32SSascha Wildner 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
376ad52dd32SSascha Wildner 		    "%s/Memory 0x%jx-0x%jx/%ju\n", name, (uintmax_t)min,
377ad52dd32SSascha Wildner 		    (uintmax_t)max, (uintmax_t)length));
378ad52dd32SSascha Wildner 		set->set_memoryrange(dev, arc->context, min, max, length, gran);
379ad52dd32SSascha Wildner 	    } else {
380ad52dd32SSascha Wildner 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx-0x%jx/%ju\n",
381ad52dd32SSascha Wildner 		    name, (uintmax_t)min, (uintmax_t)max, (uintmax_t)length));
382ad52dd32SSascha Wildner 		set->set_iorange(dev, arc->context, min, max, length, gran);
383ad52dd32SSascha Wildner 	    }
384ad52dd32SSascha Wildner 	}
385ad52dd32SSascha Wildner 	break;
386ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
387ad52dd32SSascha Wildner 	if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) {
388ad52dd32SSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored ExtIRQ producer\n"));
389ad52dd32SSascha Wildner 	    break;
390ad52dd32SSascha Wildner 	}
391ad52dd32SSascha Wildner 	set->set_ext_irq(dev, arc->context, res->Data.ExtendedIrq.Interrupts,
392ad52dd32SSascha Wildner 	    res->Data.ExtendedIrq.InterruptCount,
393ad52dd32SSascha Wildner 	    res->Data.ExtendedIrq.Triggering, res->Data.ExtendedIrq.Polarity);
394ad52dd32SSascha Wildner 	break;
395ad52dd32SSascha Wildner     case ACPI_RESOURCE_TYPE_VENDOR:
396ad52dd32SSascha Wildner 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
397ad52dd32SSascha Wildner 	    "unimplemented VendorSpecific resource\n"));
398ad52dd32SSascha Wildner 	break;
399ad52dd32SSascha Wildner     default:
400ad52dd32SSascha Wildner 	break;
401ad52dd32SSascha Wildner     }
402ad52dd32SSascha Wildner     return (AE_OK);
403ad52dd32SSascha Wildner }
404ad52dd32SSascha Wildner 
4055db2f26eSSascha Wildner /*
4065db2f26eSSascha Wildner  * Fetch a device's resources and associate them with the device.
4075db2f26eSSascha Wildner  *
4085db2f26eSSascha Wildner  * Note that it might be nice to also locate ACPI-specific resource items, such
4095db2f26eSSascha Wildner  * as GPE bits.
4105db2f26eSSascha Wildner  *
4115db2f26eSSascha Wildner  * We really need to split the resource-fetching code out from the
4125db2f26eSSascha Wildner  * resource-parsing code, since we may want to use the parsing
4135db2f26eSSascha Wildner  * code for _PRS someday.
4145db2f26eSSascha Wildner  */
4155db2f26eSSascha Wildner ACPI_STATUS
acpi_parse_resources(device_t dev,ACPI_HANDLE handle,struct acpi_parse_resource_set * set,void * arg)4165db2f26eSSascha Wildner acpi_parse_resources(device_t dev, ACPI_HANDLE handle,
4175db2f26eSSascha Wildner 		     struct acpi_parse_resource_set *set, void *arg)
4185db2f26eSSascha Wildner {
419ad52dd32SSascha Wildner     struct acpi_resource_context arc;
4205db2f26eSSascha Wildner     ACPI_STATUS		status;
4215db2f26eSSascha Wildner 
4225db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
4235db2f26eSSascha Wildner 
424ad52dd32SSascha Wildner     set->set_init(dev, arg, &arc.context);
425ad52dd32SSascha Wildner     arc.set = set;
426ad52dd32SSascha Wildner     arc.dev = dev;
427ad52dd32SSascha Wildner     status = AcpiWalkResources(handle, "_CRS", acpi_parse_resource, &arc);
428ad52dd32SSascha Wildner     if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
4295db2f26eSSascha Wildner 	kprintf("can't fetch resources for %s - %s\n",
4305db2f26eSSascha Wildner 	    acpi_name(handle), AcpiFormatException(status));
4315db2f26eSSascha Wildner 	return_ACPI_STATUS (status);
4325db2f26eSSascha Wildner     }
433ad52dd32SSascha Wildner     set->set_done(dev, arc.context);
4345db2f26eSSascha Wildner     return_ACPI_STATUS (AE_OK);
4355db2f26eSSascha Wildner }
4365db2f26eSSascha Wildner 
4375db2f26eSSascha Wildner /*
4385db2f26eSSascha Wildner  * Resource-set vectors used to attach _CRS-derived resources
4395db2f26eSSascha Wildner  * to an ACPI device.
4405db2f26eSSascha Wildner  */
4415db2f26eSSascha Wildner static void	acpi_res_set_init(device_t dev, void *arg, void **context);
4425db2f26eSSascha Wildner static void	acpi_res_set_done(device_t dev, void *context);
4435db2f26eSSascha Wildner static void	acpi_res_set_ioport(device_t dev, void *context,
444ad52dd32SSascha Wildner 				    uint64_t base, uint64_t length);
4455db2f26eSSascha Wildner static void	acpi_res_set_iorange(device_t dev, void *context,
446ad52dd32SSascha Wildner 				     uint64_t low, uint64_t high,
447ad52dd32SSascha Wildner 				     uint64_t length, uint64_t align);
4485db2f26eSSascha Wildner static void	acpi_res_set_memory(device_t dev, void *context,
449ad52dd32SSascha Wildner 				    uint64_t base, uint64_t length);
4505db2f26eSSascha Wildner static void	acpi_res_set_memoryrange(device_t dev, void *context,
451ad52dd32SSascha Wildner 					 uint64_t low, uint64_t high,
452ad52dd32SSascha Wildner 					 uint64_t length, uint64_t align);
4533905511eSSascha Wildner static void	acpi_res_set_irq(device_t dev, void *context, uint8_t *irq,
4545db2f26eSSascha Wildner 				 int count, int trig, int pol);
4555db2f26eSSascha Wildner static void	acpi_res_set_ext_irq(device_t dev, void *context,
4563905511eSSascha Wildner 				 uint32_t *irq, int count, int trig, int pol);
4573905511eSSascha Wildner static void	acpi_res_set_drq(device_t dev, void *context, uint8_t *drq,
4585db2f26eSSascha Wildner 				 int count);
4595db2f26eSSascha Wildner static void	acpi_res_set_start_dependent(device_t dev, void *context,
4605db2f26eSSascha Wildner 					     int preference);
4615db2f26eSSascha Wildner static void	acpi_res_set_end_dependent(device_t dev, void *context);
4625db2f26eSSascha Wildner 
4635db2f26eSSascha Wildner struct acpi_parse_resource_set acpi_res_parse_set = {
4645db2f26eSSascha Wildner     acpi_res_set_init,
4655db2f26eSSascha Wildner     acpi_res_set_done,
4665db2f26eSSascha Wildner     acpi_res_set_ioport,
4675db2f26eSSascha Wildner     acpi_res_set_iorange,
4685db2f26eSSascha Wildner     acpi_res_set_memory,
4695db2f26eSSascha Wildner     acpi_res_set_memoryrange,
4705db2f26eSSascha Wildner     acpi_res_set_irq,
4715db2f26eSSascha Wildner     acpi_res_set_ext_irq,
4725db2f26eSSascha Wildner     acpi_res_set_drq,
4735db2f26eSSascha Wildner     acpi_res_set_start_dependent,
4745db2f26eSSascha Wildner     acpi_res_set_end_dependent
4755db2f26eSSascha Wildner };
4765db2f26eSSascha Wildner 
4775db2f26eSSascha Wildner struct acpi_res_context {
4785db2f26eSSascha Wildner     int		ar_nio;
4795db2f26eSSascha Wildner     int		ar_nmem;
4805db2f26eSSascha Wildner     int		ar_nirq;
4815db2f26eSSascha Wildner     int		ar_ndrq;
4825db2f26eSSascha Wildner     void 	*ar_parent;
4835db2f26eSSascha Wildner };
4845db2f26eSSascha Wildner 
4855db2f26eSSascha Wildner static void
acpi_res_set_init(device_t dev,void * arg,void ** context)4865db2f26eSSascha Wildner acpi_res_set_init(device_t dev, void *arg, void **context)
4875db2f26eSSascha Wildner {
4885db2f26eSSascha Wildner     struct acpi_res_context	*cp;
4895db2f26eSSascha Wildner 
4905db2f26eSSascha Wildner     if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
4915db2f26eSSascha Wildner 	bzero(cp, sizeof(*cp));
4925db2f26eSSascha Wildner 	cp->ar_parent = arg;
4935db2f26eSSascha Wildner 	*context = cp;
4945db2f26eSSascha Wildner     }
4955db2f26eSSascha Wildner }
4965db2f26eSSascha Wildner 
4975db2f26eSSascha Wildner static void
acpi_res_set_done(device_t dev,void * context)4985db2f26eSSascha Wildner acpi_res_set_done(device_t dev, void *context)
4995db2f26eSSascha Wildner {
5005db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
5015db2f26eSSascha Wildner 
5025db2f26eSSascha Wildner     if (cp == NULL)
5035db2f26eSSascha Wildner 	return;
5045db2f26eSSascha Wildner     AcpiOsFree(cp);
5055db2f26eSSascha Wildner }
5065db2f26eSSascha Wildner 
5075db2f26eSSascha Wildner static void
acpi_res_set_ioport(device_t dev,void * context,uint64_t base,uint64_t length)508ad52dd32SSascha Wildner acpi_res_set_ioport(device_t dev, void *context, uint64_t base,
509ad52dd32SSascha Wildner 		    uint64_t length)
5105db2f26eSSascha Wildner {
5115db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
5125db2f26eSSascha Wildner 
5135db2f26eSSascha Wildner     if (cp == NULL)
5145db2f26eSSascha Wildner 	return;
5155db2f26eSSascha Wildner     bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length, -1);
5165db2f26eSSascha Wildner }
5175db2f26eSSascha Wildner 
5185db2f26eSSascha Wildner static void
acpi_res_set_iorange(device_t dev,void * context,uint64_t low,uint64_t high,uint64_t length,uint64_t align)519ad52dd32SSascha Wildner acpi_res_set_iorange(device_t dev, void *context, uint64_t low,
520ad52dd32SSascha Wildner 		     uint64_t high, uint64_t length, uint64_t align)
5215db2f26eSSascha Wildner {
5225db2f26eSSascha Wildner     struct acpi_res_context *cp = (struct acpi_res_context *)context;
5239ed6fcdbSSepherosa Ziehau     uint64_t base;
5245db2f26eSSascha Wildner 
5255db2f26eSSascha Wildner     if (cp == NULL)
5265db2f26eSSascha Wildner 	return;
527dd62cb10SMatthew Dillon     if (align == 0)	/* broken acpi resources might pass align == 0 */
528dd62cb10SMatthew Dillon 	align = 1;
5299ed6fcdbSSepherosa Ziehau 
5309ed6fcdbSSepherosa Ziehau     base = roundup(low, align);
5319ed6fcdbSSepherosa Ziehau     if (base + length - 1 <= high) {
5329ed6fcdbSSepherosa Ziehau 	acpi_res_set_ioport(dev, context, base, length);
5339ed6fcdbSSepherosa Ziehau 	return;
5349ed6fcdbSSepherosa Ziehau     }
5359ed6fcdbSSepherosa Ziehau     device_printf(dev, "I/O range [0x%jx,0x%jx,0x%jx,0x%jx] not supported\n",
5369ed6fcdbSSepherosa Ziehau 	(uintmax_t)low, (uintmax_t)high, (uintmax_t)length, (uintmax_t)align);
5375db2f26eSSascha Wildner }
5385db2f26eSSascha Wildner 
5395db2f26eSSascha Wildner static void
acpi_res_set_memory(device_t dev,void * context,uint64_t base,uint64_t length)540ad52dd32SSascha Wildner acpi_res_set_memory(device_t dev, void *context, uint64_t base,
541ad52dd32SSascha Wildner 		    uint64_t length)
5425db2f26eSSascha Wildner {
5435db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
5445db2f26eSSascha Wildner 
5455db2f26eSSascha Wildner     if (cp == NULL)
5465db2f26eSSascha Wildner 	return;
5475db2f26eSSascha Wildner 
5485db2f26eSSascha Wildner     bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length, -1);
5495db2f26eSSascha Wildner }
5505db2f26eSSascha Wildner 
5515db2f26eSSascha Wildner static void
acpi_res_set_memoryrange(device_t dev,void * context,uint64_t low,uint64_t high,uint64_t length,uint64_t align)552ad52dd32SSascha Wildner acpi_res_set_memoryrange(device_t dev, void *context, uint64_t low,
553ad52dd32SSascha Wildner 			 uint64_t high, uint64_t length, uint64_t align)
5545db2f26eSSascha Wildner {
5555db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
5565db2f26eSSascha Wildner 
5575db2f26eSSascha Wildner     if (cp == NULL)
5585db2f26eSSascha Wildner 	return;
5599ed6fcdbSSepherosa Ziehau     device_printf(dev, "memory range [0x%jx,0x%jx,0x%jx,0x%jx] "
5609ed6fcdbSSepherosa Ziehau         "not supported\n",
5619ed6fcdbSSepherosa Ziehau 	(uintmax_t)low, (uintmax_t)high, (uintmax_t)length, (uintmax_t)align);
5625db2f26eSSascha Wildner }
5635db2f26eSSascha Wildner 
5645db2f26eSSascha Wildner static void
acpi_res_set_irq(device_t dev,void * context,uint8_t * irq,int count,int trig,int pol)5653905511eSSascha Wildner acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count,
5665db2f26eSSascha Wildner     int trig, int pol)
5675db2f26eSSascha Wildner {
5685db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
5695db2f26eSSascha Wildner 
5705db2f26eSSascha Wildner     if (cp == NULL || irq == NULL)
5715db2f26eSSascha Wildner 	return;
5725db2f26eSSascha Wildner 
5735db2f26eSSascha Wildner     /* This implements no resource relocation. */
5745db2f26eSSascha Wildner     if (count != 1)
5755db2f26eSSascha Wildner 	return;
5765db2f26eSSascha Wildner 
5775db2f26eSSascha Wildner     bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1,
5785db2f26eSSascha Wildner         machintr_legacy_intr_cpuid(*irq));
5795db2f26eSSascha Wildner }
5805db2f26eSSascha Wildner 
5815db2f26eSSascha Wildner static void
acpi_res_set_ext_irq(device_t dev,void * context,uint32_t * irq,int count,int trig,int pol)5823905511eSSascha Wildner acpi_res_set_ext_irq(device_t dev, void *context, uint32_t *irq, int count,
5835db2f26eSSascha Wildner     int trig, int pol)
5845db2f26eSSascha Wildner {
5855db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
5865db2f26eSSascha Wildner 
5875db2f26eSSascha Wildner     if (cp == NULL || irq == NULL)
5885db2f26eSSascha Wildner 	return;
5895db2f26eSSascha Wildner 
5905db2f26eSSascha Wildner     /* This implements no resource relocation. */
5915db2f26eSSascha Wildner     if (count != 1)
5925db2f26eSSascha Wildner 	return;
5935db2f26eSSascha Wildner 
59437bc3036SSepherosa Ziehau     /* There is no such IRQ at all */
59537bc3036SSepherosa Ziehau     if (machintr_legacy_intr_find(*irq,
59637bc3036SSepherosa Ziehau 	INTR_TRIGGER_CONFORM, INTR_POLARITY_CONFORM) < 0)
59737bc3036SSepherosa Ziehau 	return;
59837bc3036SSepherosa Ziehau 
5995db2f26eSSascha Wildner     bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1,
6005db2f26eSSascha Wildner         machintr_legacy_intr_cpuid(*irq));
6015db2f26eSSascha Wildner }
6025db2f26eSSascha Wildner 
6035db2f26eSSascha Wildner static void
acpi_res_set_drq(device_t dev,void * context,uint8_t * drq,int count)6043905511eSSascha Wildner acpi_res_set_drq(device_t dev, void *context, uint8_t *drq, int count)
6055db2f26eSSascha Wildner {
6065db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
6075db2f26eSSascha Wildner 
6085db2f26eSSascha Wildner     if (cp == NULL || drq == NULL)
6095db2f26eSSascha Wildner 	return;
6105db2f26eSSascha Wildner 
6115db2f26eSSascha Wildner     /* This implements no resource relocation. */
6125db2f26eSSascha Wildner     if (count != 1)
6135db2f26eSSascha Wildner 	return;
6145db2f26eSSascha Wildner 
6155db2f26eSSascha Wildner     bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1, -1);
6165db2f26eSSascha Wildner }
6175db2f26eSSascha Wildner 
6185db2f26eSSascha Wildner static void
acpi_res_set_start_dependent(device_t dev,void * context,int preference)6195db2f26eSSascha Wildner acpi_res_set_start_dependent(device_t dev, void *context, int preference)
6205db2f26eSSascha Wildner {
6215db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
6225db2f26eSSascha Wildner 
6235db2f26eSSascha Wildner     if (cp == NULL)
6245db2f26eSSascha Wildner 	return;
6255db2f26eSSascha Wildner     device_printf(dev, "dependent functions not supported\n");
6265db2f26eSSascha Wildner }
6275db2f26eSSascha Wildner 
6285db2f26eSSascha Wildner static void
acpi_res_set_end_dependent(device_t dev,void * context)6295db2f26eSSascha Wildner acpi_res_set_end_dependent(device_t dev, void *context)
6305db2f26eSSascha Wildner {
6315db2f26eSSascha Wildner     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
6325db2f26eSSascha Wildner 
6335db2f26eSSascha Wildner     if (cp == NULL)
6345db2f26eSSascha Wildner 	return;
6355db2f26eSSascha Wildner     device_printf(dev, "dependent functions not supported\n");
6365db2f26eSSascha Wildner }
6375db2f26eSSascha Wildner 
6385db2f26eSSascha Wildner /*
6395db2f26eSSascha Wildner  * Resource-owning placeholders for IO and memory pseudo-devices.
6405db2f26eSSascha Wildner  *
6415db2f26eSSascha Wildner  * This code allocates system resources that will be used by ACPI
6425db2f26eSSascha Wildner  * child devices.  The acpi parent manages these resources through a
6435db2f26eSSascha Wildner  * private rman.
6445db2f26eSSascha Wildner  */
6455db2f26eSSascha Wildner 
6465db2f26eSSascha Wildner static int	acpi_sysres_rid = 100;
6475db2f26eSSascha Wildner 
6485db2f26eSSascha Wildner static int	acpi_sysres_probe(device_t dev);
6495db2f26eSSascha Wildner static int	acpi_sysres_attach(device_t dev);
6505db2f26eSSascha Wildner 
6515db2f26eSSascha Wildner static device_method_t acpi_sysres_methods[] = {
6525db2f26eSSascha Wildner     /* Device interface */
6535db2f26eSSascha Wildner     DEVMETHOD(device_probe,	acpi_sysres_probe),
6545db2f26eSSascha Wildner     DEVMETHOD(device_attach,	acpi_sysres_attach),
6555db2f26eSSascha Wildner 
656d3c9c58eSSascha Wildner     DEVMETHOD_END
6575db2f26eSSascha Wildner };
6585db2f26eSSascha Wildner 
6595db2f26eSSascha Wildner static driver_t acpi_sysres_driver = {
6605db2f26eSSascha Wildner     "acpi_sysresource",
6615db2f26eSSascha Wildner     acpi_sysres_methods,
6625db2f26eSSascha Wildner     0,
663df21e16dSImre Vadász     .gpri = KOBJ_GPRI_ACPI+2
6645db2f26eSSascha Wildner };
6655db2f26eSSascha Wildner 
6665db2f26eSSascha Wildner static devclass_t acpi_sysres_devclass;
6675db2f26eSSascha Wildner DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, acpi_sysres_devclass,
66808bd0208SSascha Wildner     NULL, NULL);
6695db2f26eSSascha Wildner MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
6705db2f26eSSascha Wildner 
6715db2f26eSSascha Wildner static int
acpi_sysres_probe(device_t dev)6725db2f26eSSascha Wildner acpi_sysres_probe(device_t dev)
6735db2f26eSSascha Wildner {
6745db2f26eSSascha Wildner     static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
6755db2f26eSSascha Wildner 
6765db2f26eSSascha Wildner     if (acpi_disabled("sysresource") ||
6775db2f26eSSascha Wildner 	ACPI_ID_PROBE(device_get_parent(dev), dev, sysres_ids) == NULL)
6785db2f26eSSascha Wildner 	return (ENXIO);
6795db2f26eSSascha Wildner 
6805db2f26eSSascha Wildner     device_set_desc(dev, "System Resource");
68108710fc1SSascha Wildner     if (bootverbose == 0)
6825db2f26eSSascha Wildner 	    device_quiet(dev);
6835db2f26eSSascha Wildner     return (BUS_PROBE_DEFAULT);
6845db2f26eSSascha Wildner }
6855db2f26eSSascha Wildner 
6865db2f26eSSascha Wildner static int
acpi_sysres_attach(device_t dev)6875db2f26eSSascha Wildner acpi_sysres_attach(device_t dev)
6885db2f26eSSascha Wildner {
6895db2f26eSSascha Wildner     device_t bus;
6905db2f26eSSascha Wildner     struct resource_list_entry *bus_rle, *dev_rle;
6915db2f26eSSascha Wildner     struct resource_list *bus_rl, *dev_rl;
6925db2f26eSSascha Wildner     int done, type;
6935db2f26eSSascha Wildner     u_long start, end, count;
694ad52dd32SSascha Wildner 
6955db2f26eSSascha Wildner     /*
6965db2f26eSSascha Wildner      * Loop through all current resources to see if the new one overlaps
6975db2f26eSSascha Wildner      * any existing ones.  If so, grow the old one up and/or down
6985db2f26eSSascha Wildner      * accordingly.  Discard any that are wholly contained in the old.  If
6995db2f26eSSascha Wildner      * the resource is unique, add it to the parent.  It will later go into
7005db2f26eSSascha Wildner      * the rman pool.
7015db2f26eSSascha Wildner      */
7025db2f26eSSascha Wildner     bus = device_get_parent(dev);
7035db2f26eSSascha Wildner     dev_rl = BUS_GET_RESOURCE_LIST(bus, dev);
7045db2f26eSSascha Wildner     bus_rl = BUS_GET_RESOURCE_LIST(device_get_parent(bus), bus);
7055db2f26eSSascha Wildner     if (bus_rl)
7065db2f26eSSascha Wildner 	kprintf("busrl is not null!\n");
7075db2f26eSSascha Wildner     SLIST_FOREACH(dev_rle, dev_rl, link) {
7085db2f26eSSascha Wildner 	if (dev_rle->type != SYS_RES_IOPORT && dev_rle->type != SYS_RES_MEMORY)
7095db2f26eSSascha Wildner 	    continue;
7105db2f26eSSascha Wildner 
7115db2f26eSSascha Wildner 	start = dev_rle->start;
7125db2f26eSSascha Wildner 	end = dev_rle->end;
7135db2f26eSSascha Wildner 	count = dev_rle->count;
7145db2f26eSSascha Wildner 	type = dev_rle->type;
7155db2f26eSSascha Wildner 	done = FALSE;
7165db2f26eSSascha Wildner 	if (bus_rl) {
7175db2f26eSSascha Wildner 	    SLIST_FOREACH(bus_rle, bus_rl, link) {
7185db2f26eSSascha Wildner 		if (bus_rle->type != type)
7195db2f26eSSascha Wildner 		    continue;
7205db2f26eSSascha Wildner 
7215db2f26eSSascha Wildner 		/* New resource wholly contained in old, discard. */
7225db2f26eSSascha Wildner 		if (start >= bus_rle->start && end <= bus_rle->end)
7235db2f26eSSascha Wildner 		    break;
7245db2f26eSSascha Wildner 
7255db2f26eSSascha Wildner 		/* New tail overlaps old head, grow existing resource downward. */
7265db2f26eSSascha Wildner 		if (start < bus_rle->start && end >= bus_rle->start) {
7275db2f26eSSascha Wildner 		    bus_rle->count += bus_rle->start - start;
7285db2f26eSSascha Wildner 		    bus_rle->start = start;
7295db2f26eSSascha Wildner 		    done = TRUE;
7305db2f26eSSascha Wildner 		}
7315db2f26eSSascha Wildner 
7325db2f26eSSascha Wildner 		/* New head overlaps old tail, grow existing resource upward. */
7335db2f26eSSascha Wildner 		if (start <= bus_rle->end && end > bus_rle->end) {
7345db2f26eSSascha Wildner 		    bus_rle->count += end - bus_rle->end;
7355db2f26eSSascha Wildner 		    bus_rle->end = end;
7365db2f26eSSascha Wildner 		    done = TRUE;
7375db2f26eSSascha Wildner 		}
7385db2f26eSSascha Wildner 
7395db2f26eSSascha Wildner 		/* If we adjusted the old resource, we're finished. */
7405db2f26eSSascha Wildner 		if (done)
7415db2f26eSSascha Wildner 		    break;
7425db2f26eSSascha Wildner 	    }
74308bd0208SSascha Wildner 	} else {
74408bd0208SSascha Wildner 	    bus_rle = NULL;
74508bd0208SSascha Wildner 	}
7465db2f26eSSascha Wildner 	/* If we didn't merge with anything, add this resource. */
747ad52dd32SSascha Wildner 	if (bus_rle == NULL)
7485db2f26eSSascha Wildner 	    bus_set_resource(bus, type, acpi_sysres_rid++, start, count, -1);
7495db2f26eSSascha Wildner     }
7505db2f26eSSascha Wildner 
7515db2f26eSSascha Wildner     /* After merging/moving resources to the parent, free the list. */
7525db2f26eSSascha Wildner     resource_list_free(dev_rl);
7535db2f26eSSascha Wildner 
7545db2f26eSSascha Wildner     return (0);
7555db2f26eSSascha Wildner }
756