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