xref: /freebsd/sys/dev/acpica/acpi_resource.c (revision 4a38527105d551d4ed3f8d8b51e055cc79be7c1b)
115e32d5dSMike Smith /*-
215e32d5dSMike Smith  * Copyright (c) 2000 Michael Smith
315e32d5dSMike Smith  * Copyright (c) 2000 BSDi
415e32d5dSMike Smith  * All rights reserved.
515e32d5dSMike Smith  *
615e32d5dSMike Smith  * Redistribution and use in source and binary forms, with or without
715e32d5dSMike Smith  * modification, are permitted provided that the following conditions
815e32d5dSMike Smith  * are met:
915e32d5dSMike Smith  * 1. Redistributions of source code must retain the above copyright
1015e32d5dSMike Smith  *    notice, this list of conditions and the following disclaimer.
1115e32d5dSMike Smith  * 2. Redistributions in binary form must reproduce the above copyright
1215e32d5dSMike Smith  *    notice, this list of conditions and the following disclaimer in the
1315e32d5dSMike Smith  *    documentation and/or other materials provided with the distribution.
1415e32d5dSMike Smith  *
1515e32d5dSMike Smith  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1615e32d5dSMike Smith  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1715e32d5dSMike Smith  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1815e32d5dSMike Smith  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1915e32d5dSMike Smith  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2015e32d5dSMike Smith  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2115e32d5dSMike Smith  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2215e32d5dSMike Smith  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2315e32d5dSMike Smith  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2415e32d5dSMike Smith  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2515e32d5dSMike Smith  * SUCH DAMAGE.
2615e32d5dSMike Smith  */
2715e32d5dSMike Smith 
28aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
2915e32d5dSMike Smith #include "opt_acpi.h"
3015e32d5dSMike Smith #include <sys/param.h>
3115e32d5dSMike Smith #include <sys/kernel.h>
3215e32d5dSMike Smith #include <sys/bus.h>
334fc477aaSJohn Baldwin #include <sys/limits.h>
3491233413SNate Lawson #include <sys/malloc.h>
35fe12f24bSPoul-Henning Kamp #include <sys/module.h>
36832183baSMike Smith 
37055c1fe2SJohn Baldwin #if defined(__i386__) || defined(__amd64__)
38055c1fe2SJohn Baldwin #include <machine/pci_cfgreg.h>
39055c1fe2SJohn Baldwin #endif
4015e32d5dSMike Smith #include <machine/bus.h>
4115e32d5dSMike Smith #include <machine/resource.h>
42832183baSMike Smith #include <sys/rman.h>
4315e32d5dSMike Smith 
44129d3046SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h>
45129d3046SJung-uk Kim #include <contrib/dev/acpica/include/accommon.h>
46129d3046SJung-uk Kim 
4715e32d5dSMike Smith #include <dev/acpica/acpivar.h>
4815e32d5dSMike Smith 
49224c3776SAndrew Turner #ifdef INTRNG
50224c3776SAndrew Turner #include "acpi_bus_if.h"
51224c3776SAndrew Turner #endif
52224c3776SAndrew Turner 
53be2b1797SNate Lawson /* Hooks for the ACPI CA debugging infrastructure */
54e71b6381SMike Smith #define _COMPONENT	ACPI_BUS
55741ef403SMike Smith ACPI_MODULE_NAME("RESOURCE")
560ae55423SMike Smith 
5795957f62SJohn Baldwin struct lookup_irq_request {
5895957f62SJohn Baldwin     ACPI_RESOURCE *acpi_res;
59d4d6ad3fSJayachandran C.     u_int	irq;
6095957f62SJohn Baldwin     int		counter;
6195957f62SJohn Baldwin     int		rid;
6295957f62SJohn Baldwin     int		found;
63d4d6ad3fSJayachandran C.     int		checkrid;
64d4d6ad3fSJayachandran C.     int		trig;
65d4d6ad3fSJayachandran C.     int		pol;
6695957f62SJohn Baldwin };
6795957f62SJohn Baldwin 
68055c1fe2SJohn Baldwin static char *pcilink_ids[] = { "PNP0C0F", NULL };
69055c1fe2SJohn Baldwin 
70*4a385271SAndrew Turner /*
71*4a385271SAndrew Turner  * Devices with invalid memory resources
72*4a385271SAndrew Turner  */
73*4a385271SAndrew Turner static char *bad_memresource_ids[] = {
74*4a385271SAndrew Turner     /* PRCx on Radxa Orion O6 conflicts with the PCI resource range */
75*4a385271SAndrew Turner     "CIXH2020",
76*4a385271SAndrew Turner     NULL
77*4a385271SAndrew Turner };
78*4a385271SAndrew Turner 
79*4a385271SAndrew Turner 
8095957f62SJohn Baldwin static ACPI_STATUS
acpi_lookup_irq_handler(ACPI_RESOURCE * res,void * context)8195957f62SJohn Baldwin acpi_lookup_irq_handler(ACPI_RESOURCE *res, void *context)
8295957f62SJohn Baldwin {
8395957f62SJohn Baldwin     struct lookup_irq_request *req;
84224e25e1SMatthew D Fleming     size_t len;
85a1330a71SAndrew Turner     u_int irqnum, trig, pol;
86a1330a71SAndrew Turner     bool found;
87a1330a71SAndrew Turner 
88a1330a71SAndrew Turner     found = false;
89a1330a71SAndrew Turner     req = (struct lookup_irq_request *)context;
9095957f62SJohn Baldwin 
91e8d472a7SJung-uk Kim     switch (res->Type) {
92e8d472a7SJung-uk Kim     case ACPI_RESOURCE_TYPE_IRQ:
93e8d472a7SJung-uk Kim 	irqnum = res->Data.Irq.InterruptCount;
94a1330a71SAndrew Turner 	for (int i = 0; i < irqnum; i++) {
95a1330a71SAndrew Turner 	    if (res->Data.Irq.Interrupts[i] == req->irq) {
96a1330a71SAndrew Turner 		found = true;
97a1330a71SAndrew Turner 		break;
98a1330a71SAndrew Turner 	    }
99a1330a71SAndrew Turner 	}
100f6c05906SJung-uk Kim 	len = ACPI_RS_SIZE(ACPI_RESOURCE_IRQ);
101d4d6ad3fSJayachandran C. 	trig = res->Data.Irq.Triggering;
102d4d6ad3fSJayachandran C. 	pol = res->Data.Irq.Polarity;
103f6c05906SJung-uk Kim 	break;
104f6c05906SJung-uk Kim     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
105e8d472a7SJung-uk Kim 	irqnum = res->Data.ExtendedIrq.InterruptCount;
106a1330a71SAndrew Turner 	for (int i = 0; i < irqnum; i++) {
107a1330a71SAndrew Turner 	    if (res->Data.ExtendedIrq.Interrupts[i] == req->irq) {
108a1330a71SAndrew Turner 		found = true;
109a1330a71SAndrew Turner 		break;
110a1330a71SAndrew Turner 	    }
111a1330a71SAndrew Turner 	}
112f6c05906SJung-uk Kim 	len = ACPI_RS_SIZE(ACPI_RESOURCE_EXTENDED_IRQ);
113d4d6ad3fSJayachandran C. 	trig = res->Data.ExtendedIrq.Triggering;
114d4d6ad3fSJayachandran C. 	pol = res->Data.ExtendedIrq.Polarity;
115f6c05906SJung-uk Kim 	break;
116f6c05906SJung-uk Kim     default:
117f6c05906SJung-uk Kim 	return (AE_OK);
11895957f62SJohn Baldwin     }
119a1330a71SAndrew Turner     if (!found)
120f6c05906SJung-uk Kim 	return (AE_OK);
121d4d6ad3fSJayachandran C.     if (req->checkrid) {
12295957f62SJohn Baldwin 	if (req->counter != req->rid) {
12395957f62SJohn Baldwin 	    req->counter++;
124f6c05906SJung-uk Kim 	    return (AE_OK);
12595957f62SJohn Baldwin 	}
126d4d6ad3fSJayachandran C.     }
12795957f62SJohn Baldwin     req->found = 1;
128d4d6ad3fSJayachandran C.     req->pol = pol;
129d4d6ad3fSJayachandran C.     req->trig = trig;
130d4d6ad3fSJayachandran C.     if (req->acpi_res != NULL)
131224e25e1SMatthew D Fleming 	bcopy(res, req->acpi_res, len);
13295957f62SJohn Baldwin     return (AE_CTRL_TERMINATE);
13395957f62SJohn Baldwin }
13495957f62SJohn Baldwin 
13595957f62SJohn Baldwin ACPI_STATUS
acpi_lookup_irq_resource(device_t dev,int rid,struct resource * res,ACPI_RESOURCE * acpi_res)13695957f62SJohn Baldwin acpi_lookup_irq_resource(device_t dev, int rid, struct resource *res,
13795957f62SJohn Baldwin     ACPI_RESOURCE *acpi_res)
13895957f62SJohn Baldwin {
13995957f62SJohn Baldwin     struct lookup_irq_request req;
14095957f62SJohn Baldwin     ACPI_STATUS status;
14195957f62SJohn Baldwin 
14295957f62SJohn Baldwin     req.acpi_res = acpi_res;
143d4d6ad3fSJayachandran C.     req.irq = rman_get_start(res);
14495957f62SJohn Baldwin     req.counter = 0;
14595957f62SJohn Baldwin     req.rid = rid;
14695957f62SJohn Baldwin     req.found = 0;
147d4d6ad3fSJayachandran C.     req.checkrid = 1;
14895957f62SJohn Baldwin     status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
14995957f62SJohn Baldwin 	acpi_lookup_irq_handler, &req);
15095957f62SJohn Baldwin     if (ACPI_SUCCESS(status) && req.found == 0)
15195957f62SJohn Baldwin 	status = AE_NOT_FOUND;
15295957f62SJohn Baldwin     return (status);
15395957f62SJohn Baldwin }
15495957f62SJohn Baldwin 
15595957f62SJohn Baldwin void
acpi_config_intr(device_t dev,ACPI_RESOURCE * res)15695957f62SJohn Baldwin acpi_config_intr(device_t dev, ACPI_RESOURCE *res)
15795957f62SJohn Baldwin {
15895957f62SJohn Baldwin     u_int irq;
15995957f62SJohn Baldwin     int pol, trig;
16095957f62SJohn Baldwin 
161e8d472a7SJung-uk Kim     switch (res->Type) {
162e8d472a7SJung-uk Kim     case ACPI_RESOURCE_TYPE_IRQ:
163e8d472a7SJung-uk Kim 	KASSERT(res->Data.Irq.InterruptCount == 1,
16495957f62SJohn Baldwin 	    ("%s: multiple interrupts", __func__));
16595957f62SJohn Baldwin 	irq = res->Data.Irq.Interrupts[0];
166e8d472a7SJung-uk Kim 	trig = res->Data.Irq.Triggering;
167e8d472a7SJung-uk Kim 	pol = res->Data.Irq.Polarity;
16895957f62SJohn Baldwin 	break;
169e8d472a7SJung-uk Kim     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
170e8d472a7SJung-uk Kim 	KASSERT(res->Data.ExtendedIrq.InterruptCount == 1,
17195957f62SJohn Baldwin 	    ("%s: multiple interrupts", __func__));
17295957f62SJohn Baldwin 	irq = res->Data.ExtendedIrq.Interrupts[0];
173e8d472a7SJung-uk Kim 	trig = res->Data.ExtendedIrq.Triggering;
174e8d472a7SJung-uk Kim 	pol = res->Data.ExtendedIrq.Polarity;
17595957f62SJohn Baldwin 	break;
17695957f62SJohn Baldwin     default:
177e8d472a7SJung-uk Kim 	panic("%s: bad resource type %u", __func__, res->Type);
17895957f62SJohn Baldwin     }
1799a7bf07cSJohn Baldwin 
1809a7bf07cSJohn Baldwin #if defined(__amd64__) || defined(__i386__)
1810a34d050SJohn Baldwin     if (irq < 16 && trig == ACPI_EDGE_SENSITIVE && pol == ACPI_ACTIVE_LOW &&
1820a34d050SJohn Baldwin 	acpi_override_isa_irq_polarity) {
1830a34d050SJohn Baldwin 	device_printf(dev, "forcing active-hi polarity for IRQ %u\n", irq);
1849a7bf07cSJohn Baldwin 	pol = ACPI_ACTIVE_HIGH;
1850a34d050SJohn Baldwin     }
1869a7bf07cSJohn Baldwin #endif
18795957f62SJohn Baldwin     BUS_CONFIG_INTR(dev, irq, (trig == ACPI_EDGE_SENSITIVE) ?
18895957f62SJohn Baldwin 	INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
18995957f62SJohn Baldwin 	INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
19095957f62SJohn Baldwin }
19195957f62SJohn Baldwin 
192d4d6ad3fSJayachandran C. #ifdef INTRNG
193d4d6ad3fSJayachandran C. int
acpi_map_intr(device_t dev,u_int irq,ACPI_HANDLE handle)194d4d6ad3fSJayachandran C. acpi_map_intr(device_t dev, u_int irq, ACPI_HANDLE handle)
195d4d6ad3fSJayachandran C. {
196d4d6ad3fSJayachandran C.     struct lookup_irq_request req;
197d4d6ad3fSJayachandran C.     int trig, pol;
198d4d6ad3fSJayachandran C. 
199d4d6ad3fSJayachandran C.     trig = ACPI_LEVEL_SENSITIVE;
200d4d6ad3fSJayachandran C.     pol = ACPI_ACTIVE_HIGH;
201d4d6ad3fSJayachandran C.     if (handle != NULL) {
202d4d6ad3fSJayachandran C. 	req.found = 0;
203d4d6ad3fSJayachandran C. 	req.acpi_res = NULL;
204d4d6ad3fSJayachandran C. 	req.irq = irq;
205d4d6ad3fSJayachandran C. 	req.counter = 0;
206d4d6ad3fSJayachandran C. 	req.rid = 0;
207d4d6ad3fSJayachandran C. 	req.checkrid = 0;
208d4d6ad3fSJayachandran C. 	AcpiWalkResources(handle, "_CRS", acpi_lookup_irq_handler, &req);
209d4d6ad3fSJayachandran C. 	if (req.found != 0) {
210d4d6ad3fSJayachandran C. 	    trig = req.trig;
211d4d6ad3fSJayachandran C. 	    pol = req.pol;
212d4d6ad3fSJayachandran C. 	}
213d4d6ad3fSJayachandran C.     }
214d4d6ad3fSJayachandran C.     return ACPI_BUS_MAP_INTR(device_get_parent(dev), dev, irq,
215d4d6ad3fSJayachandran C. 	(trig == ACPI_EDGE_SENSITIVE) ?  INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL,
216d4d6ad3fSJayachandran C. 	(pol == ACPI_ACTIVE_HIGH) ?  INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
217d4d6ad3fSJayachandran C. }
218d4d6ad3fSJayachandran C. #endif
219d4d6ad3fSJayachandran C. 
2204fc477aaSJohn Baldwin struct acpi_resource_context {
2214fc477aaSJohn Baldwin     struct acpi_parse_resource_set *set;
2224fc477aaSJohn Baldwin     device_t	dev;
2234fc477aaSJohn Baldwin     void	*context;
224e9a00a5dSJohn Baldwin     bool	ignore_producer_flag;
2254fc477aaSJohn Baldwin };
2264fc477aaSJohn Baldwin 
2274fc477aaSJohn Baldwin #ifdef ACPI_DEBUG_OUTPUT
2284fc477aaSJohn Baldwin static const char *
acpi_address_range_name(UINT8 ResourceType)2294fc477aaSJohn Baldwin acpi_address_range_name(UINT8 ResourceType)
2304fc477aaSJohn Baldwin {
2314fc477aaSJohn Baldwin     static char buf[16];
2324fc477aaSJohn Baldwin 
2334fc477aaSJohn Baldwin     switch (ResourceType) {
2344fc477aaSJohn Baldwin     case ACPI_MEMORY_RANGE:
2354fc477aaSJohn Baldwin 	    return ("Memory");
2364fc477aaSJohn Baldwin     case ACPI_IO_RANGE:
2374fc477aaSJohn Baldwin 	    return ("IO");
2384fc477aaSJohn Baldwin     case ACPI_BUS_NUMBER_RANGE:
2394fc477aaSJohn Baldwin 	    return ("Bus Number");
2404fc477aaSJohn Baldwin     default:
2414fc477aaSJohn Baldwin 	    snprintf(buf, sizeof(buf), "type %u", ResourceType);
2424fc477aaSJohn Baldwin 	    return (buf);
2434fc477aaSJohn Baldwin     }
2444fc477aaSJohn Baldwin }
2454fc477aaSJohn Baldwin #endif
2464fc477aaSJohn Baldwin 
2474fc477aaSJohn Baldwin static ACPI_STATUS
acpi_parse_resource(ACPI_RESOURCE * res,void * context)2484fc477aaSJohn Baldwin acpi_parse_resource(ACPI_RESOURCE *res, void *context)
2494fc477aaSJohn Baldwin {
2504fc477aaSJohn Baldwin     struct acpi_parse_resource_set *set;
2514fc477aaSJohn Baldwin     struct acpi_resource_context *arc;
2524fc477aaSJohn Baldwin     UINT64 min, max, length, gran;
253c0753890SWarner Losh #ifdef ACPI_DEBUG
254c0753890SWarner Losh     const char *name;
255c0753890SWarner Losh #endif
2564fc477aaSJohn Baldwin     device_t dev;
2574fc477aaSJohn Baldwin 
2584fc477aaSJohn Baldwin     arc = context;
2594fc477aaSJohn Baldwin     dev = arc->dev;
2604fc477aaSJohn Baldwin     set = arc->set;
2614fc477aaSJohn Baldwin 
2624fc477aaSJohn Baldwin     switch (res->Type) {
2634fc477aaSJohn Baldwin     case ACPI_RESOURCE_TYPE_END_TAG:
2644fc477aaSJohn Baldwin 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
2654fc477aaSJohn Baldwin 	break;
2664fc477aaSJohn Baldwin     case ACPI_RESOURCE_TYPE_FIXED_IO:
2674fc477aaSJohn Baldwin 	if (res->Data.FixedIo.AddressLength <= 0)
2684fc477aaSJohn Baldwin 	    break;
2694fc477aaSJohn Baldwin 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
2704fc477aaSJohn Baldwin 	    res->Data.FixedIo.Address, res->Data.FixedIo.AddressLength));
2714fc477aaSJohn Baldwin 	set->set_ioport(dev, arc->context, res->Data.FixedIo.Address,
2724fc477aaSJohn Baldwin 	    res->Data.FixedIo.AddressLength);
2734fc477aaSJohn Baldwin 	break;
2744fc477aaSJohn Baldwin     case ACPI_RESOURCE_TYPE_IO:
2754fc477aaSJohn Baldwin 	if (res->Data.Io.AddressLength <= 0)
2764fc477aaSJohn Baldwin 	    break;
2774fc477aaSJohn Baldwin 	if (res->Data.Io.Minimum == res->Data.Io.Maximum) {
2784fc477aaSJohn Baldwin 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
2794fc477aaSJohn Baldwin 		res->Data.Io.Minimum, res->Data.Io.AddressLength));
2804fc477aaSJohn Baldwin 	    set->set_ioport(dev, arc->context, res->Data.Io.Minimum,
2814fc477aaSJohn Baldwin 		res->Data.Io.AddressLength);
2824fc477aaSJohn Baldwin 	} else {
2834fc477aaSJohn Baldwin 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
2844fc477aaSJohn Baldwin 		res->Data.Io.Minimum, res->Data.Io.Maximum,
2854fc477aaSJohn Baldwin 		res->Data.Io.AddressLength));
2864fc477aaSJohn Baldwin 	    set->set_iorange(dev, arc->context, res->Data.Io.Minimum,
2874fc477aaSJohn Baldwin 		res->Data.Io.Maximum, res->Data.Io.AddressLength,
2884fc477aaSJohn Baldwin 		res->Data.Io.Alignment);
2894fc477aaSJohn Baldwin 	}
2904fc477aaSJohn Baldwin 	break;
2914fc477aaSJohn Baldwin     case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
2924fc477aaSJohn Baldwin 	if (res->Data.FixedMemory32.AddressLength <= 0)
2934fc477aaSJohn Baldwin 	    break;
2944fc477aaSJohn Baldwin 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
2954fc477aaSJohn Baldwin 	    res->Data.FixedMemory32.Address,
2964fc477aaSJohn Baldwin 	    res->Data.FixedMemory32.AddressLength));
2974fc477aaSJohn Baldwin 	set->set_memory(dev, arc->context, res->Data.FixedMemory32.Address,
2984fc477aaSJohn Baldwin 	    res->Data.FixedMemory32.AddressLength);
2994fc477aaSJohn Baldwin 	break;
3004fc477aaSJohn Baldwin     case ACPI_RESOURCE_TYPE_MEMORY32:
3014fc477aaSJohn Baldwin 	if (res->Data.Memory32.AddressLength <= 0)
3024fc477aaSJohn Baldwin 	    break;
3034fc477aaSJohn Baldwin 	if (res->Data.Memory32.Minimum == res->Data.Memory32.Maximum) {
3044fc477aaSJohn Baldwin 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
3054fc477aaSJohn Baldwin 		res->Data.Memory32.Minimum, res->Data.Memory32.AddressLength));
3064fc477aaSJohn Baldwin 	    set->set_memory(dev, arc->context, res->Data.Memory32.Minimum,
3074fc477aaSJohn Baldwin 		res->Data.Memory32.AddressLength);
3084fc477aaSJohn Baldwin 	} else {
3094fc477aaSJohn Baldwin 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
3104fc477aaSJohn Baldwin 		res->Data.Memory32.Minimum, res->Data.Memory32.Maximum,
3114fc477aaSJohn Baldwin 		res->Data.Memory32.AddressLength));
3124fc477aaSJohn Baldwin 	    set->set_memoryrange(dev, arc->context, res->Data.Memory32.Minimum,
3134fc477aaSJohn Baldwin 		res->Data.Memory32.Maximum, res->Data.Memory32.AddressLength,
3144fc477aaSJohn Baldwin 		res->Data.Memory32.Alignment);
3154fc477aaSJohn Baldwin 	}
3164fc477aaSJohn Baldwin 	break;
3174fc477aaSJohn Baldwin     case ACPI_RESOURCE_TYPE_MEMORY24:
3184fc477aaSJohn Baldwin 	if (res->Data.Memory24.AddressLength <= 0)
3194fc477aaSJohn Baldwin 	    break;
3204fc477aaSJohn Baldwin 	if (res->Data.Memory24.Minimum == res->Data.Memory24.Maximum) {
3214fc477aaSJohn Baldwin 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
3224fc477aaSJohn Baldwin 		res->Data.Memory24.Minimum, res->Data.Memory24.AddressLength));
3234fc477aaSJohn Baldwin 	    set->set_memory(dev, arc->context, res->Data.Memory24.Minimum,
3244fc477aaSJohn Baldwin 		res->Data.Memory24.AddressLength);
3254fc477aaSJohn Baldwin 	} else {
3264fc477aaSJohn Baldwin 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
3274fc477aaSJohn Baldwin 		res->Data.Memory24.Minimum, res->Data.Memory24.Maximum,
3284fc477aaSJohn Baldwin 		res->Data.Memory24.AddressLength));
3294fc477aaSJohn Baldwin 	    set->set_memoryrange(dev, arc->context, res->Data.Memory24.Minimum,
3304fc477aaSJohn Baldwin 		res->Data.Memory24.Maximum, res->Data.Memory24.AddressLength,
3314fc477aaSJohn Baldwin 		res->Data.Memory24.Alignment);
3324fc477aaSJohn Baldwin 	}
3334fc477aaSJohn Baldwin 	break;
3344fc477aaSJohn Baldwin     case ACPI_RESOURCE_TYPE_IRQ:
3354fc477aaSJohn Baldwin 	/*
3364fc477aaSJohn Baldwin 	 * from 1.0b 6.4.2
3374fc477aaSJohn Baldwin 	 * "This structure is repeated for each separate interrupt
3384fc477aaSJohn Baldwin 	 * required"
3394fc477aaSJohn Baldwin 	 */
3404fc477aaSJohn Baldwin 	set->set_irq(dev, arc->context, res->Data.Irq.Interrupts,
3414fc477aaSJohn Baldwin 	    res->Data.Irq.InterruptCount, res->Data.Irq.Triggering,
3424fc477aaSJohn Baldwin 	    res->Data.Irq.Polarity);
3434fc477aaSJohn Baldwin 	break;
3444fc477aaSJohn Baldwin     case ACPI_RESOURCE_TYPE_DMA:
3454fc477aaSJohn Baldwin 	/*
3464fc477aaSJohn Baldwin 	 * from 1.0b 6.4.3
3474fc477aaSJohn Baldwin 	 * "This structure is repeated for each separate DMA channel
3484fc477aaSJohn Baldwin 	 * required"
3494fc477aaSJohn Baldwin 	 */
3504fc477aaSJohn Baldwin 	set->set_drq(dev, arc->context, res->Data.Dma.Channels,
3514fc477aaSJohn Baldwin 	    res->Data.Dma.ChannelCount);
3524fc477aaSJohn Baldwin 	break;
3534fc477aaSJohn Baldwin     case ACPI_RESOURCE_TYPE_START_DEPENDENT:
3544fc477aaSJohn Baldwin 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependent functions\n"));
3554fc477aaSJohn Baldwin 	set->set_start_dependent(dev, arc->context,
3564fc477aaSJohn Baldwin 	    res->Data.StartDpf.CompatibilityPriority);
3574fc477aaSJohn Baldwin 	break;
3584fc477aaSJohn Baldwin     case ACPI_RESOURCE_TYPE_END_DEPENDENT:
3594fc477aaSJohn Baldwin 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependent functions\n"));
3604fc477aaSJohn Baldwin 	set->set_end_dependent(dev, arc->context);
3614fc477aaSJohn Baldwin 	break;
3624fc477aaSJohn Baldwin     case ACPI_RESOURCE_TYPE_ADDRESS16:
3634fc477aaSJohn Baldwin     case ACPI_RESOURCE_TYPE_ADDRESS32:
3644fc477aaSJohn Baldwin     case ACPI_RESOURCE_TYPE_ADDRESS64:
3654fc477aaSJohn Baldwin     case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
3664fc477aaSJohn Baldwin 	switch (res->Type) {
3674fc477aaSJohn Baldwin 	case ACPI_RESOURCE_TYPE_ADDRESS16:
3687cf3e94aSJung-uk Kim 	    gran = res->Data.Address16.Address.Granularity;
3697cf3e94aSJung-uk Kim 	    min = res->Data.Address16.Address.Minimum;
3707cf3e94aSJung-uk Kim 	    max = res->Data.Address16.Address.Maximum;
3717cf3e94aSJung-uk Kim 	    length = res->Data.Address16.Address.AddressLength;
372c0753890SWarner Losh #ifdef ACPI_DEBUG
373c0753890SWarner Losh 	    name = "Address16";
374c0753890SWarner Losh #endif
3754fc477aaSJohn Baldwin 	    break;
3764fc477aaSJohn Baldwin 	case ACPI_RESOURCE_TYPE_ADDRESS32:
3777cf3e94aSJung-uk Kim 	    gran = res->Data.Address32.Address.Granularity;
3787cf3e94aSJung-uk Kim 	    min = res->Data.Address32.Address.Minimum;
3797cf3e94aSJung-uk Kim 	    max = res->Data.Address32.Address.Maximum;
3807cf3e94aSJung-uk Kim 	    length = res->Data.Address32.Address.AddressLength;
381c0753890SWarner Losh #ifdef ACPI_DEBUG
382c0753890SWarner Losh 	    name = "Address32";
383c0753890SWarner Losh #endif
3844fc477aaSJohn Baldwin 	    break;
3854fc477aaSJohn Baldwin 	case ACPI_RESOURCE_TYPE_ADDRESS64:
3867cf3e94aSJung-uk Kim 	    gran = res->Data.Address64.Address.Granularity;
3877cf3e94aSJung-uk Kim 	    min = res->Data.Address64.Address.Minimum;
3887cf3e94aSJung-uk Kim 	    max = res->Data.Address64.Address.Maximum;
3897cf3e94aSJung-uk Kim 	    length = res->Data.Address64.Address.AddressLength;
390c0753890SWarner Losh #ifdef ACPI_DEBUG
391c0753890SWarner Losh 	    name = "Address64";
392c0753890SWarner Losh #endif
3934fc477aaSJohn Baldwin 	    break;
3944fc477aaSJohn Baldwin 	default:
3954fc477aaSJohn Baldwin 	    KASSERT(res->Type == ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64,
3964fc477aaSJohn Baldwin 		("should never happen"));
3977cf3e94aSJung-uk Kim 	    gran = res->Data.ExtAddress64.Address.Granularity;
3987cf3e94aSJung-uk Kim 	    min = res->Data.ExtAddress64.Address.Minimum;
3997cf3e94aSJung-uk Kim 	    max = res->Data.ExtAddress64.Address.Maximum;
4007cf3e94aSJung-uk Kim 	    length = res->Data.ExtAddress64.Address.AddressLength;
401c0753890SWarner Losh #ifdef ACPI_DEBUG
402c0753890SWarner Losh 	    name = "ExtAddress64";
403c0753890SWarner Losh #endif
4044fc477aaSJohn Baldwin 	    break;
4054fc477aaSJohn Baldwin 	}
4064fc477aaSJohn Baldwin 	if (length <= 0)
4074fc477aaSJohn Baldwin 	    break;
408e9a00a5dSJohn Baldwin 	if (!arc->ignore_producer_flag &&
4093d9294b0SAndrew Turner 	    res->Data.Address.ProducerConsumer != ACPI_CONSUMER) {
4104fc477aaSJohn Baldwin 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
4114fc477aaSJohn Baldwin 		"ignored %s %s producer\n", name,
4124fc477aaSJohn Baldwin 		acpi_address_range_name(res->Data.Address.ResourceType)));
4134fc477aaSJohn Baldwin 	    break;
4144fc477aaSJohn Baldwin 	}
4154fc477aaSJohn Baldwin 	if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE &&
4164fc477aaSJohn Baldwin 	    res->Data.Address.ResourceType != ACPI_IO_RANGE) {
4174fc477aaSJohn Baldwin 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
4184fc477aaSJohn Baldwin 		"ignored %s for non-memory, non-I/O\n", name));
4194fc477aaSJohn Baldwin 	    break;
4204fc477aaSJohn Baldwin 	}
4214fc477aaSJohn Baldwin 
4224fc477aaSJohn Baldwin #ifdef __i386__
4234fc477aaSJohn Baldwin 	if (min > ULONG_MAX || (res->Data.Address.MaxAddressFixed && max >
4244fc477aaSJohn Baldwin 	    ULONG_MAX)) {
4254fc477aaSJohn Baldwin 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored %s above 4G\n",
4264fc477aaSJohn Baldwin 		name));
4274fc477aaSJohn Baldwin 	    break;
4284fc477aaSJohn Baldwin 	}
4294fc477aaSJohn Baldwin 	if (max > ULONG_MAX)
4304fc477aaSJohn Baldwin 		max = ULONG_MAX;
4314fc477aaSJohn Baldwin #endif
4324fc477aaSJohn Baldwin 	if (res->Data.Address.MinAddressFixed == ACPI_ADDRESS_FIXED &&
4334fc477aaSJohn Baldwin 	    res->Data.Address.MaxAddressFixed == ACPI_ADDRESS_FIXED) {
4344fc477aaSJohn Baldwin 	    if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE) {
4354c2ed94fSJohn Baldwin 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/Memory 0x%jx/%ju\n",
4364c2ed94fSJohn Baldwin 		    name, (uintmax_t)min, (uintmax_t)length));
4374fc477aaSJohn Baldwin 		set->set_memory(dev, arc->context, min, length);
4384fc477aaSJohn Baldwin 	    } else {
4394c2ed94fSJohn Baldwin 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx/%ju\n", name,
4404c2ed94fSJohn Baldwin 		    (uintmax_t)min, (uintmax_t)length));
4414fc477aaSJohn Baldwin 		set->set_ioport(dev, arc->context, min, length);
4424fc477aaSJohn Baldwin 	    }
4431472117aSAndrew Turner 	} else if (res->Data.Address.MinAddressFixed != ACPI_ADDRESS_FIXED &&
4441472117aSAndrew Turner 	    res->Data.Address.MaxAddressFixed != ACPI_ADDRESS_FIXED) {
4451472117aSAndrew Turner 	    /* Fixed size, variable location resource descriptor */
4461472117aSAndrew Turner 	    min = roundup(min, gran + 1);
4471472117aSAndrew Turner 	    if ((min + length - 1) > max) {
4481472117aSAndrew Turner 		device_printf(dev,
4491472117aSAndrew Turner 		    "invalid memory range: start: %jx end: %jx max: %jx\n",
4501472117aSAndrew Turner 		    (uintmax_t)min, (uintmax_t)(min + length - 1),
4511472117aSAndrew Turner 		    (uintmax_t)max);
4521472117aSAndrew Turner 	    } else {
4531472117aSAndrew Turner 		if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE) {
4541472117aSAndrew Turner 		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
4551472117aSAndrew Turner 			"%s/Memory 0x%jx/%ju\n", name, (uintmax_t)min,
4561472117aSAndrew Turner 			(uintmax_t)length));
4571472117aSAndrew Turner 		    set->set_memory(dev, arc->context, min, length);
4581472117aSAndrew Turner 		} else {
4591472117aSAndrew Turner 		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx/%ju\n",
4601472117aSAndrew Turner 			name, (uintmax_t)min, (uintmax_t)length));
4611472117aSAndrew Turner 		    set->set_ioport(dev, arc->context, min, length);
4621472117aSAndrew Turner 		}
4631472117aSAndrew Turner 	    }
4644fc477aaSJohn Baldwin 	} else {
4654fc477aaSJohn Baldwin 	    if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
4664c2ed94fSJohn Baldwin 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
4674c2ed94fSJohn Baldwin 		    "%s/Memory 0x%jx-0x%jx/%ju\n", name, (uintmax_t)min,
4684c2ed94fSJohn Baldwin 		    (uintmax_t)max, (uintmax_t)length));
4694fc477aaSJohn Baldwin 		set->set_memoryrange(dev, arc->context, min, max, length, gran);
4704fc477aaSJohn Baldwin 	    } else {
4714c2ed94fSJohn Baldwin 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx-0x%jx/%ju\n",
4724c2ed94fSJohn Baldwin 		    name, (uintmax_t)min, (uintmax_t)max, (uintmax_t)length));
4734fc477aaSJohn Baldwin 		set->set_iorange(dev, arc->context, min, max, length, gran);
4744fc477aaSJohn Baldwin 	    }
4754fc477aaSJohn Baldwin 	}
4764fc477aaSJohn Baldwin 	break;
4774fc477aaSJohn Baldwin     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
4784fc477aaSJohn Baldwin 	if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) {
4794fc477aaSJohn Baldwin 	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored ExtIRQ producer\n"));
4804fc477aaSJohn Baldwin 	    break;
4814fc477aaSJohn Baldwin 	}
4824fc477aaSJohn Baldwin 	set->set_ext_irq(dev, arc->context, res->Data.ExtendedIrq.Interrupts,
4834fc477aaSJohn Baldwin 	    res->Data.ExtendedIrq.InterruptCount,
4844fc477aaSJohn Baldwin 	    res->Data.ExtendedIrq.Triggering, res->Data.ExtendedIrq.Polarity);
4854fc477aaSJohn Baldwin 	break;
4864fc477aaSJohn Baldwin     case ACPI_RESOURCE_TYPE_VENDOR:
4874fc477aaSJohn Baldwin 	ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
4884fc477aaSJohn Baldwin 	    "unimplemented VendorSpecific resource\n"));
4894fc477aaSJohn Baldwin 	break;
4904fc477aaSJohn Baldwin     default:
4914fc477aaSJohn Baldwin 	break;
4924fc477aaSJohn Baldwin     }
4934fc477aaSJohn Baldwin     return (AE_OK);
4944fc477aaSJohn Baldwin }
4954fc477aaSJohn Baldwin 
4960ae55423SMike Smith /*
49715e32d5dSMike Smith  * Fetch a device's resources and associate them with the device.
49815e32d5dSMike Smith  *
49915e32d5dSMike Smith  * Note that it might be nice to also locate ACPI-specific resource items, such
50015e32d5dSMike Smith  * as GPE bits.
501832183baSMike Smith  *
502832183baSMike Smith  * We really need to split the resource-fetching code out from the
503832183baSMike Smith  * resource-parsing code, since we may want to use the parsing
504832183baSMike Smith  * code for _PRS someday.
50515e32d5dSMike Smith  */
50615e32d5dSMike Smith ACPI_STATUS
acpi_parse_resources(device_t dev,ACPI_HANDLE handle,struct acpi_parse_resource_set * set,void * arg)507be2b1797SNate Lawson acpi_parse_resources(device_t dev, ACPI_HANDLE handle,
50872ad60adSNate Lawson 		     struct acpi_parse_resource_set *set, void *arg)
50915e32d5dSMike Smith {
5104fc477aaSJohn Baldwin     struct acpi_resource_context arc;
51115e32d5dSMike Smith     ACPI_STATUS		status;
51215e32d5dSMike Smith 
513b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
5140ae55423SMike Smith 
5154fc477aaSJohn Baldwin     set->set_init(dev, arg, &arc.context);
5164fc477aaSJohn Baldwin     arc.set = set;
5174fc477aaSJohn Baldwin     arc.dev = dev;
518e9a00a5dSJohn Baldwin     arc.ignore_producer_flag = false;
519e9a00a5dSJohn Baldwin 
52041c31f1cSEd Maste     /*
52141c31f1cSEd Maste      * UARTs on ThunderX2 set ResourceProducer on memory resources, with
52241c31f1cSEd Maste      * 7.2 firmware.
52341c31f1cSEd Maste      */
524e9a00a5dSJohn Baldwin     if (acpi_MatchHid(handle, "ARMH0011") != ACPI_MATCHHID_NOMATCH)
525e9a00a5dSJohn Baldwin 	    arc.ignore_producer_flag = true;
526e9a00a5dSJohn Baldwin 
527c7dada4cSRuslan Bukin     /*
528c7dada4cSRuslan Bukin      * ARM Coresight on N1SDP set ResourceProducer on memory resources.
529c7dada4cSRuslan Bukin      * Coresight devices: ETM, STM, TPIU, ETF/ETR, REP, FUN.
530c7dada4cSRuslan Bukin      */
531c7dada4cSRuslan Bukin     if (acpi_MatchHid(handle, "ARMHC500") != ACPI_MATCHHID_NOMATCH ||
532c7dada4cSRuslan Bukin         acpi_MatchHid(handle, "ARMHC502") != ACPI_MATCHHID_NOMATCH ||
533aed2afebSAleksandr Rybalko         acpi_MatchHid(handle, "ARMHC600") != ACPI_MATCHHID_NOMATCH ||
534c7dada4cSRuslan Bukin         acpi_MatchHid(handle, "ARMHC979") != ACPI_MATCHHID_NOMATCH ||
535c7dada4cSRuslan Bukin         acpi_MatchHid(handle, "ARMHC97C") != ACPI_MATCHHID_NOMATCH ||
536c7dada4cSRuslan Bukin         acpi_MatchHid(handle, "ARMHC98D") != ACPI_MATCHHID_NOMATCH ||
537aed2afebSAleksandr Rybalko         acpi_MatchHid(handle, "ARMHC9FF") != ACPI_MATCHHID_NOMATCH ||
538aed2afebSAleksandr Rybalko         acpi_MatchHid(handle, "ARMHD620") != ACPI_MATCHHID_NOMATCH)
539b62d159cSRuslan Bukin 	    arc.ignore_producer_flag = true;
540b62d159cSRuslan Bukin 
5416f38d2e7SAndrew Gallatin     /*
5426f38d2e7SAndrew Gallatin      * The DesignWare I2C Controller on Ampere Altra sets ResourceProducer on
5436f38d2e7SAndrew Gallatin      * memory resources.
5446f38d2e7SAndrew Gallatin      */
5456f38d2e7SAndrew Gallatin     if (acpi_MatchHid(handle, "APMC0D0F") != ACPI_MATCHHID_NOMATCH)
5466f38d2e7SAndrew Gallatin 	    arc.ignore_producer_flag = true;
5476f38d2e7SAndrew Gallatin 
5484fc477aaSJohn Baldwin     status = AcpiWalkResources(handle, "_CRS", acpi_parse_resource, &arc);
5494fc477aaSJohn Baldwin     if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
550832183baSMike Smith 	printf("can't fetch resources for %s - %s\n",
551832183baSMike Smith 	    acpi_name(handle), AcpiFormatException(status));
5520ae55423SMike Smith 	return_ACPI_STATUS (status);
55315e32d5dSMike Smith     }
5544fc477aaSJohn Baldwin     set->set_done(dev, arc.context);
5550ae55423SMike Smith     return_ACPI_STATUS (AE_OK);
55615e32d5dSMike Smith }
55715e32d5dSMike Smith 
558832183baSMike Smith /*
559832183baSMike Smith  * Resource-set vectors used to attach _CRS-derived resources
560832183baSMike Smith  * to an ACPI device.
561832183baSMike Smith  */
56272ad60adSNate Lawson static void	acpi_res_set_init(device_t dev, void *arg, void **context);
56315e32d5dSMike Smith static void	acpi_res_set_done(device_t dev, void *context);
564be2b1797SNate Lawson static void	acpi_res_set_ioport(device_t dev, void *context,
5654fc477aaSJohn Baldwin 				    uint64_t base, uint64_t length);
566be2b1797SNate Lawson static void	acpi_res_set_iorange(device_t dev, void *context,
5674fc477aaSJohn Baldwin 				     uint64_t low, uint64_t high,
5684fc477aaSJohn Baldwin 				     uint64_t length, uint64_t align);
569be2b1797SNate Lawson static void	acpi_res_set_memory(device_t dev, void *context,
5704fc477aaSJohn Baldwin 				    uint64_t base, uint64_t length);
571be2b1797SNate Lawson static void	acpi_res_set_memoryrange(device_t dev, void *context,
5724fc477aaSJohn Baldwin 					 uint64_t low, uint64_t high,
5734fc477aaSJohn Baldwin 					 uint64_t length, uint64_t align);
5744fc477aaSJohn Baldwin static void	acpi_res_set_irq(device_t dev, void *context, uint8_t *irq,
57524752c42SMarcel Moolenaar 				 int count, int trig, int pol);
576e8d472a7SJung-uk Kim static void	acpi_res_set_ext_irq(device_t dev, void *context,
5774fc477aaSJohn Baldwin 				 uint32_t *irq, int count, int trig, int pol);
5784fc477aaSJohn Baldwin static void	acpi_res_set_drq(device_t dev, void *context, uint8_t *drq,
57985dff349STakanori Watanabe 				 int count);
580e8d472a7SJung-uk Kim static void	acpi_res_set_start_dependent(device_t dev, void *context,
581be2b1797SNate Lawson 					     int preference);
582e8d472a7SJung-uk Kim static void	acpi_res_set_end_dependent(device_t dev, void *context);
58315e32d5dSMike Smith 
58415e32d5dSMike Smith struct acpi_parse_resource_set acpi_res_parse_set = {
58515e32d5dSMike Smith     acpi_res_set_init,
58615e32d5dSMike Smith     acpi_res_set_done,
58715e32d5dSMike Smith     acpi_res_set_ioport,
58815e32d5dSMike Smith     acpi_res_set_iorange,
58915e32d5dSMike Smith     acpi_res_set_memory,
59015e32d5dSMike Smith     acpi_res_set_memoryrange,
59115e32d5dSMike Smith     acpi_res_set_irq,
592e8d472a7SJung-uk Kim     acpi_res_set_ext_irq,
59315e32d5dSMike Smith     acpi_res_set_drq,
594e8d472a7SJung-uk Kim     acpi_res_set_start_dependent,
595e8d472a7SJung-uk Kim     acpi_res_set_end_dependent
59615e32d5dSMike Smith };
59715e32d5dSMike Smith 
59815e32d5dSMike Smith struct acpi_res_context {
59915e32d5dSMike Smith     int		ar_nio;
60015e32d5dSMike Smith     int		ar_nmem;
60115e32d5dSMike Smith     int		ar_nirq;
602832183baSMike Smith     int		ar_ndrq;
60372ad60adSNate Lawson     void 	*ar_parent;
60415e32d5dSMike Smith };
60515e32d5dSMike Smith 
606055c1fe2SJohn Baldwin /*
607055c1fe2SJohn Baldwin  * Some resources reported via _CRS should not be added as bus
608055c1fe2SJohn Baldwin  * resources.  This function returns true if a resource reported via
609055c1fe2SJohn Baldwin  * _CRS should be ignored.
610055c1fe2SJohn Baldwin  */
611055c1fe2SJohn Baldwin static bool
acpi_res_ignore(device_t dev,int type,rman_res_t start,rman_res_t count)612055c1fe2SJohn Baldwin acpi_res_ignore(device_t dev, int type, rman_res_t start, rman_res_t count)
613055c1fe2SJohn Baldwin {
614055c1fe2SJohn Baldwin     struct acpi_device *ad = device_get_ivars(dev);
615055c1fe2SJohn Baldwin     ACPI_DEVICE_INFO *devinfo;
616055c1fe2SJohn Baldwin     bool allow;
617055c1fe2SJohn Baldwin 
618055c1fe2SJohn Baldwin     /* Ignore IRQ resources for PCI link devices. */
619055c1fe2SJohn Baldwin     if (type == SYS_RES_IRQ &&
620055c1fe2SJohn Baldwin 	ACPI_ID_PROBE(device_get_parent(dev), dev, pcilink_ids, NULL) <= 0)
621055c1fe2SJohn Baldwin 	return (true);
622055c1fe2SJohn Baldwin 
623055c1fe2SJohn Baldwin     /*
624055c1fe2SJohn Baldwin      * Ignore most resources for PCI root bridges.  Some BIOSes
625055c1fe2SJohn Baldwin      * incorrectly enumerate the memory ranges they decode as plain
626055c1fe2SJohn Baldwin      * memory resources instead of as ResourceProducer ranges.  Other
627055c1fe2SJohn Baldwin      * BIOSes incorrectly list system resource entries for I/O ranges
628055c1fe2SJohn Baldwin      * under the PCI bridge.  Do allow the one known-correct case on
629055c1fe2SJohn Baldwin      * x86 of a PCI bridge claiming the I/O ports used for PCI config
630055c1fe2SJohn Baldwin      * access.
631055c1fe2SJohn Baldwin      */
632055c1fe2SJohn Baldwin     if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
633*4a385271SAndrew Turner 	if (type == SYS_RES_MEMORY &&
634*4a385271SAndrew Turner 	    ACPI_ID_PROBE(device_get_parent(dev), dev, bad_memresource_ids,
635*4a385271SAndrew Turner 	    NULL) <= 0)
636*4a385271SAndrew Turner 		return (true);
637*4a385271SAndrew Turner 
638055c1fe2SJohn Baldwin 	if (ACPI_SUCCESS(AcpiGetObjectInfo(ad->ad_handle, &devinfo))) {
639055c1fe2SJohn Baldwin 	    if ((devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) != 0) {
640055c1fe2SJohn Baldwin #if defined(__i386__) || defined(__amd64__)
641055c1fe2SJohn Baldwin 		allow = (type == SYS_RES_IOPORT && start == CONF1_ADDR_PORT);
642055c1fe2SJohn Baldwin #else
643055c1fe2SJohn Baldwin 		allow = false;
644055c1fe2SJohn Baldwin #endif
645055c1fe2SJohn Baldwin 		if (!allow) {
646055c1fe2SJohn Baldwin 		    AcpiOsFree(devinfo);
647055c1fe2SJohn Baldwin 		    return (true);
648055c1fe2SJohn Baldwin 		}
649055c1fe2SJohn Baldwin 	    }
650055c1fe2SJohn Baldwin 	    AcpiOsFree(devinfo);
651055c1fe2SJohn Baldwin 	}
652055c1fe2SJohn Baldwin     }
653055c1fe2SJohn Baldwin 
654055c1fe2SJohn Baldwin     return (false);
655055c1fe2SJohn Baldwin }
656055c1fe2SJohn Baldwin 
65715e32d5dSMike Smith static void
acpi_res_set_init(device_t dev,void * arg,void ** context)65872ad60adSNate Lawson acpi_res_set_init(device_t dev, void *arg, void **context)
65915e32d5dSMike Smith {
66015e32d5dSMike Smith     struct acpi_res_context	*cp;
66115e32d5dSMike Smith 
66215e32d5dSMike Smith     if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
66315e32d5dSMike Smith 	bzero(cp, sizeof(*cp));
66472ad60adSNate Lawson 	cp->ar_parent = arg;
66515e32d5dSMike Smith 	*context = cp;
66615e32d5dSMike Smith     }
66715e32d5dSMike Smith }
66815e32d5dSMike Smith 
66915e32d5dSMike Smith static void
acpi_res_set_done(device_t dev,void * context)67015e32d5dSMike Smith acpi_res_set_done(device_t dev, void *context)
67115e32d5dSMike Smith {
67215e32d5dSMike Smith     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
67315e32d5dSMike Smith 
67415e32d5dSMike Smith     if (cp == NULL)
67515e32d5dSMike Smith 	return;
67615e32d5dSMike Smith     AcpiOsFree(cp);
67715e32d5dSMike Smith }
67815e32d5dSMike Smith 
67915e32d5dSMike Smith static void
acpi_res_set_ioport(device_t dev,void * context,uint64_t base,uint64_t length)6804fc477aaSJohn Baldwin acpi_res_set_ioport(device_t dev, void *context, uint64_t base,
6814fc477aaSJohn Baldwin 		    uint64_t length)
68215e32d5dSMike Smith {
68315e32d5dSMike Smith     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
68415e32d5dSMike Smith 
68515e32d5dSMike Smith     if (cp == NULL)
68615e32d5dSMike Smith 	return;
687055c1fe2SJohn Baldwin     if (acpi_res_ignore(dev, SYS_RES_IOPORT, base, length))
688055c1fe2SJohn Baldwin 	return;
689adad4744SNate Lawson     bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
69015e32d5dSMike Smith }
69115e32d5dSMike Smith 
69215e32d5dSMike Smith static void
acpi_res_set_iorange(device_t dev,void * context,uint64_t low,uint64_t high,uint64_t length,uint64_t align)6934fc477aaSJohn Baldwin acpi_res_set_iorange(device_t dev, void *context, uint64_t low,
6944fc477aaSJohn Baldwin 		     uint64_t high, uint64_t length, uint64_t align)
69515e32d5dSMike Smith {
69615e32d5dSMike Smith     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
69715e32d5dSMike Smith 
69815e32d5dSMike Smith     if (cp == NULL)
69915e32d5dSMike Smith 	return;
700eb33d8ceSJohn Baldwin 
701eb33d8ceSJohn Baldwin     /*
702eb33d8ceSJohn Baldwin      * XXX: Some BIOSes contain buggy _CRS entries where fixed I/O
703eb33d8ceSJohn Baldwin      * ranges have the maximum base address (_MAX) to the end of the
704eb33d8ceSJohn Baldwin      * I/O range instead of the start.  These are then treated as a
705eb33d8ceSJohn Baldwin      * relocatable I/O range rather than a fixed I/O resource.  As a
706eb33d8ceSJohn Baldwin      * workaround, treat I/O resources encoded this way as fixed I/O
707eb33d8ceSJohn Baldwin      * ports.
708eb33d8ceSJohn Baldwin      */
709eb33d8ceSJohn Baldwin     if (high == (low + length)) {
710eb33d8ceSJohn Baldwin 	if (bootverbose)
711eb33d8ceSJohn Baldwin 	    device_printf(dev,
712eb33d8ceSJohn Baldwin 		"_CRS has fixed I/O port range defined as relocatable\n");
713eb33d8ceSJohn Baldwin 
714055c1fe2SJohn Baldwin 	if (acpi_res_ignore(dev, SYS_RES_IOPORT, low, length))
715055c1fe2SJohn Baldwin 	    return;
716eb33d8ceSJohn Baldwin 	bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, low, length);
717eb33d8ceSJohn Baldwin 	return;
718eb33d8ceSJohn Baldwin     }
719eb33d8ceSJohn Baldwin 
72015e32d5dSMike Smith     device_printf(dev, "I/O range not supported\n");
72115e32d5dSMike Smith }
72215e32d5dSMike Smith 
72315e32d5dSMike Smith static void
acpi_res_set_memory(device_t dev,void * context,uint64_t base,uint64_t length)7244fc477aaSJohn Baldwin acpi_res_set_memory(device_t dev, void *context, uint64_t base,
7254fc477aaSJohn Baldwin 		    uint64_t length)
72615e32d5dSMike Smith {
72715e32d5dSMike Smith     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
72815e32d5dSMike Smith 
72915e32d5dSMike Smith     if (cp == NULL)
73015e32d5dSMike Smith 	return;
731055c1fe2SJohn Baldwin     if (acpi_res_ignore(dev, SYS_RES_MEMORY, base, length))
732055c1fe2SJohn Baldwin 	return;
733adad4744SNate Lawson     bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
73415e32d5dSMike Smith }
73515e32d5dSMike Smith 
73615e32d5dSMike Smith static void
acpi_res_set_memoryrange(device_t dev,void * context,uint64_t low,uint64_t high,uint64_t length,uint64_t align)7374fc477aaSJohn Baldwin acpi_res_set_memoryrange(device_t dev, void *context, uint64_t low,
7384fc477aaSJohn Baldwin 			 uint64_t high, uint64_t length, uint64_t align)
73915e32d5dSMike Smith {
74015e32d5dSMike Smith     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
74115e32d5dSMike Smith 
74215e32d5dSMike Smith     if (cp == NULL)
74315e32d5dSMike Smith 	return;
74415e32d5dSMike Smith     device_printf(dev, "memory range not supported\n");
74515e32d5dSMike Smith }
74615e32d5dSMike Smith 
74715e32d5dSMike Smith static void
acpi_res_set_irq(device_t dev,void * context,uint8_t * irq,int count,int trig,int pol)7484fc477aaSJohn Baldwin acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count,
74924752c42SMarcel Moolenaar     int trig, int pol)
75015e32d5dSMike Smith {
75115e32d5dSMike Smith     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
752a52c8a65SEmmanuel Vadot     int i;
75315e32d5dSMike Smith 
754be2b1797SNate Lawson     if (cp == NULL || irq == NULL)
75585dff349STakanori Watanabe 	return;
75685dff349STakanori Watanabe 
757055c1fe2SJohn Baldwin     for (i = 0; i < count; i++) {
758055c1fe2SJohn Baldwin 	if (acpi_res_ignore(dev, SYS_RES_IRQ, irq[i], 1))
759055c1fe2SJohn Baldwin 	    continue;
760a52c8a65SEmmanuel Vadot         bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, irq[i], 1);
76115e32d5dSMike Smith     }
762055c1fe2SJohn Baldwin }
76315e32d5dSMike Smith 
76415e32d5dSMike Smith static void
acpi_res_set_ext_irq(device_t dev,void * context,uint32_t * irq,int count,int trig,int pol)7654fc477aaSJohn Baldwin acpi_res_set_ext_irq(device_t dev, void *context, uint32_t *irq, int count,
766e8d472a7SJung-uk Kim     int trig, int pol)
767e8d472a7SJung-uk Kim {
768e8d472a7SJung-uk Kim     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
769a52c8a65SEmmanuel Vadot     int i;
770e8d472a7SJung-uk Kim 
771e8d472a7SJung-uk Kim     if (cp == NULL || irq == NULL)
772e8d472a7SJung-uk Kim 	return;
773e8d472a7SJung-uk Kim 
774055c1fe2SJohn Baldwin     for (i = 0; i < count; i++) {
775055c1fe2SJohn Baldwin 	if (acpi_res_ignore(dev, SYS_RES_IRQ, irq[i], 1))
776055c1fe2SJohn Baldwin 	    continue;
777a52c8a65SEmmanuel Vadot         bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, irq[i], 1);
778e8d472a7SJung-uk Kim     }
779055c1fe2SJohn Baldwin }
780e8d472a7SJung-uk Kim 
781e8d472a7SJung-uk Kim static void
acpi_res_set_drq(device_t dev,void * context,uint8_t * drq,int count)7824fc477aaSJohn Baldwin acpi_res_set_drq(device_t dev, void *context, uint8_t *drq, int count)
78315e32d5dSMike Smith {
78415e32d5dSMike Smith     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
78515e32d5dSMike Smith 
786be2b1797SNate Lawson     if (cp == NULL || drq == NULL)
78785dff349STakanori Watanabe 	return;
78885dff349STakanori Watanabe 
78985dff349STakanori Watanabe     /* This implements no resource relocation. */
79085dff349STakanori Watanabe     if (count != 1)
79185dff349STakanori Watanabe 	return;
79285dff349STakanori Watanabe 
793055c1fe2SJohn Baldwin     if (acpi_res_ignore(dev, SYS_RES_DRQ, *drq, 1))
794055c1fe2SJohn Baldwin 	return;
795adad4744SNate Lawson     bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
79615e32d5dSMike Smith }
79715e32d5dSMike Smith 
79815e32d5dSMike Smith static void
acpi_res_set_start_dependent(device_t dev,void * context,int preference)799e8d472a7SJung-uk Kim acpi_res_set_start_dependent(device_t dev, void *context, int preference)
80015e32d5dSMike Smith {
80115e32d5dSMike Smith     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
80215e32d5dSMike Smith 
80315e32d5dSMike Smith     if (cp == NULL)
80415e32d5dSMike Smith 	return;
805e8d472a7SJung-uk Kim     device_printf(dev, "dependent functions not supported\n");
80615e32d5dSMike Smith }
80715e32d5dSMike Smith 
80815e32d5dSMike Smith static void
acpi_res_set_end_dependent(device_t dev,void * context)809e8d472a7SJung-uk Kim acpi_res_set_end_dependent(device_t dev, void *context)
81015e32d5dSMike Smith {
81115e32d5dSMike Smith     struct acpi_res_context	*cp = (struct acpi_res_context *)context;
81215e32d5dSMike Smith 
81315e32d5dSMike Smith     if (cp == NULL)
81415e32d5dSMike Smith 	return;
815e8d472a7SJung-uk Kim     device_printf(dev, "dependent functions not supported\n");
81615e32d5dSMike Smith }
817832183baSMike Smith 
818832183baSMike Smith /*
81991233413SNate Lawson  * Resource-owning placeholders for IO and memory pseudo-devices.
820832183baSMike Smith  *
821adad4744SNate Lawson  * This code allocates system resources that will be used by ACPI
822adad4744SNate Lawson  * child devices.  The acpi parent manages these resources through a
823adad4744SNate Lawson  * private rman.
824832183baSMike Smith  */
825832183baSMike Smith 
82691233413SNate Lawson static int	acpi_sysres_probe(device_t dev);
82791233413SNate Lawson static int	acpi_sysres_attach(device_t dev);
828832183baSMike Smith 
82991233413SNate Lawson static device_method_t acpi_sysres_methods[] = {
830832183baSMike Smith     /* Device interface */
83191233413SNate Lawson     DEVMETHOD(device_probe,	acpi_sysres_probe),
83291233413SNate Lawson     DEVMETHOD(device_attach,	acpi_sysres_attach),
833832183baSMike Smith 
83461bfd867SSofian Brabez     DEVMETHOD_END
835832183baSMike Smith };
836832183baSMike Smith 
83791233413SNate Lawson static driver_t acpi_sysres_driver = {
838832183baSMike Smith     "acpi_sysresource",
83991233413SNate Lawson     acpi_sysres_methods,
840832183baSMike Smith     0,
841832183baSMike Smith };
842832183baSMike Smith 
843916a5d8aSJohn Baldwin DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, 0, 0);
84464278df5SNate Lawson MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
845832183baSMike Smith 
846832183baSMike Smith static int
acpi_sysres_probe(device_t dev)84791233413SNate Lawson acpi_sysres_probe(device_t dev)
848832183baSMike Smith {
8495fcc8a58SNate Lawson     static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
8505efca36fSTakanori Watanabe     int rv;
85191233413SNate Lawson 
8525efca36fSTakanori Watanabe     if (acpi_disabled("sysresource"))
853832183baSMike Smith 	return (ENXIO);
8545efca36fSTakanori Watanabe     rv = ACPI_ID_PROBE(device_get_parent(dev), dev, sysres_ids, NULL);
8555efca36fSTakanori Watanabe     if (rv > 0){
8565efca36fSTakanori Watanabe 	return (rv);
8575efca36fSTakanori Watanabe     }
85891233413SNate Lawson     device_set_desc(dev, "System Resource");
859832183baSMike Smith     device_quiet(dev);
8605efca36fSTakanori Watanabe     return (rv);
861832183baSMike Smith }
862832183baSMike Smith 
863832183baSMike Smith static int
acpi_sysres_attach(device_t dev)86491233413SNate Lawson acpi_sysres_attach(device_t dev)
865832183baSMike Smith {
866adad4744SNate Lawson     device_t bus;
8670e1246e3SJohn Baldwin     struct acpi_softc *bus_sc;
868adad4744SNate Lawson     struct resource_list_entry *bus_rle, *dev_rle;
869adad4744SNate Lawson     struct resource_list *bus_rl, *dev_rl;
870adad4744SNate Lawson     int done, type;
8712dd1bdf1SJustin Hibbits     rman_res_t start, end, count;
872832183baSMike Smith 
873832183baSMike Smith     /*
874adad4744SNate Lawson      * Loop through all current resources to see if the new one overlaps
875adad4744SNate Lawson      * any existing ones.  If so, grow the old one up and/or down
876adad4744SNate Lawson      * accordingly.  Discard any that are wholly contained in the old.  If
877adad4744SNate Lawson      * the resource is unique, add it to the parent.  It will later go into
878adad4744SNate Lawson      * the rman pool.
879832183baSMike Smith      */
880adad4744SNate Lawson     bus = device_get_parent(dev);
881adad4744SNate Lawson     dev_rl = BUS_GET_RESOURCE_LIST(bus, dev);
8820e1246e3SJohn Baldwin     bus_sc = acpi_device_get_parent_softc(dev);
8830e1246e3SJohn Baldwin     bus_rl = &bus_sc->sysres_rl;
884be1bf4d2SPoul-Henning Kamp     STAILQ_FOREACH(dev_rle, dev_rl, link) {
885adad4744SNate Lawson 	if (dev_rle->type != SYS_RES_IOPORT && dev_rle->type != SYS_RES_MEMORY)
88691233413SNate Lawson 	    continue;
887adad4744SNate Lawson 
888adad4744SNate Lawson 	start = dev_rle->start;
889adad4744SNate Lawson 	end = dev_rle->end;
890adad4744SNate Lawson 	count = dev_rle->count;
891adad4744SNate Lawson 	type = dev_rle->type;
892adad4744SNate Lawson 	done = FALSE;
893adad4744SNate Lawson 
894be1bf4d2SPoul-Henning Kamp 	STAILQ_FOREACH(bus_rle, bus_rl, link) {
895adad4744SNate Lawson 	    if (bus_rle->type != type)
896adad4744SNate Lawson 		continue;
897adad4744SNate Lawson 
898adad4744SNate Lawson 	    /* New resource wholly contained in old, discard. */
899adad4744SNate Lawson 	    if (start >= bus_rle->start && end <= bus_rle->end)
900adad4744SNate Lawson 		break;
901adad4744SNate Lawson 
902adad4744SNate Lawson 	    /* New tail overlaps old head, grow existing resource downward. */
903adad4744SNate Lawson 	    if (start < bus_rle->start && end >= bus_rle->start) {
904adad4744SNate Lawson 		bus_rle->count += bus_rle->start - start;
905adad4744SNate Lawson 		bus_rle->start = start;
906adad4744SNate Lawson 		done = TRUE;
90791233413SNate Lawson 	    }
90891233413SNate Lawson 
909adad4744SNate Lawson 	    /* New head overlaps old tail, grow existing resource upward. */
910adad4744SNate Lawson 	    if (start <= bus_rle->end && end > bus_rle->end) {
911adad4744SNate Lawson 		bus_rle->count += end - bus_rle->end;
912adad4744SNate Lawson 		bus_rle->end = end;
913adad4744SNate Lawson 		done = TRUE;
91491233413SNate Lawson 	    }
91591233413SNate Lawson 
916adad4744SNate Lawson 	    /* If we adjusted the old resource, we're finished. */
917adad4744SNate Lawson 	    if (done)
918adad4744SNate Lawson 		break;
91991233413SNate Lawson 	}
920adad4744SNate Lawson 
921adad4744SNate Lawson 	/* If we didn't merge with anything, add this resource. */
922adad4744SNate Lawson 	if (bus_rle == NULL)
9230e1246e3SJohn Baldwin 	    resource_list_add_next(bus_rl, type, start, end, count);
924832183baSMike Smith     }
925be2b1797SNate Lawson 
926adad4744SNate Lawson     /* After merging/moving resources to the parent, free the list. */
927adad4744SNate Lawson     resource_list_free(dev_rl);
928adad4744SNate Lawson 
929832183baSMike Smith     return (0);
930832183baSMike Smith }
931