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