2 * (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3 * Alexander Warg <warg@os.inf.tu-dresden.de>
4 * economic rights: Technische Universität Dresden (Germany)
6 * This file is part of TUD:OS and distributed under the terms of the
7 * GNU General Public License 2.
8 * Please see the COPYING-GPL-2 file for details.
19 #include "phys_space.h"
29 #include <l4/cxx/list>
31 #define _COMPONENT ACPI_BUS_COMPONENT
32 ACPI_MODULE_NAME("l4main");
36 struct Prt_entry : public cxx::List_item
43 class Acpi_pci_irq_router_rs : public Resource_space
49 Acpi_pci_irq_router_rs() : _prt(0) {}
51 int add_prt_entry(ACPI_HANDLE obj, ACPI_PCI_ROUTING_TABLE *e);
52 int find(int device, int pin, struct acpica_pci_irq **irq);
53 bool request(Resource *parent, Device *, Resource *child, Device *cdev);
54 bool alloc(Resource *, Device *, Resource *, Device *, bool)
60 Acpi_pci_irq_router_rs::request(Resource *parent, Device *,
61 Resource *child, Device *cdev)
64 printf("requesting IRQ resource: ");
66 printf(" at ACPI IRQ routing resource\n");
68 Adr_resource *cr = dynamic_cast<Adr_resource*>(child);
72 child->parent(parent);
76 Hw::Device *cd = dynamic_cast<Hw::Device*>(cdev);
81 struct acpica_pci_irq *irq = 0;
83 if (find(cd->adr() >> 16, cr->start(), &irq) < 0)
89 cr->del_flags(Resource::F_relative);
91 cr->del_flags(Resource::Irq_info_base * 3);
93 flags |= (!irq->trigger) * Resource::Irq_info_base;
94 flags |= (!!irq->polarity) * Resource::Irq_info_base * 2;
102 enum Acpi_irq_model_id {
103 ACPI_IRQ_MODEL_PIC = 0,
104 ACPI_IRQ_MODEL_IOAPIC,
105 ACPI_IRQ_MODEL_IOSAPIC,
106 ACPI_IRQ_MODEL_PLATFORM,
111 get_irq_cb(ACPI_RESOURCE *res, void *ctxt)
113 acpica_pci_irq *irq = (acpica_pci_irq*)ctxt;
119 case ACPI_RESOURCE_TYPE_IRQ:
120 irq->irq = res->Data.Irq.Interrupts[0];
121 irq->polarity = res->Data.Irq.Polarity;
122 irq->trigger = res->Data.Irq.Triggering;
125 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
126 irq->irq = res->Data.ExtendedIrq.Interrupts[0];
127 irq->polarity = res->Data.ExtendedIrq.Polarity;
128 irq->trigger = res->Data.ExtendedIrq.Triggering;
137 Acpi_pci_irq_router_rs::add_prt_entry(ACPI_HANDLE obj,
138 ACPI_PCI_ROUTING_TABLE *e)
143 Prt_entry *ne = new Prt_entry();
147 ne->slot = (e->Address >> 16) & 0xffff;
150 ne->irq.irq = e->SourceIndex;
151 ne->irq.polarity = ACPI_ACTIVE_LOW;
152 ne->irq.trigger = ACPI_LEVEL_SENSITIVE;
156 if (Io_config::cfg->verbose() >= 2)
157 printf(" (dev[%s][%d]) ", e->Source, e->SourceIndex);
159 status = AcpiGetHandle(obj, e->Source, &link);
160 if (ACPI_FAILURE(status))
162 printf("\nWarning: Could not find PCI IRQ Link Device...\n");
166 status = AcpiWalkResources(link, (char*)"_CRS", get_irq_cb, &ne->irq);
167 if (ACPI_FAILURE(status))
169 printf("\nWarning: Could not evaluate _CRS of PCI IRQ Link Device\n");
174 _prt = cxx::List_item::push_back(_prt, ne);
179 Acpi_pci_irq_router_rs::find(int device, int pin, struct acpica_pci_irq **irq)
181 Prt_entry::T_iter<Prt_entry> c = _prt;
184 if (c->slot == (unsigned)device && c->pin == pin)
197 static int acpi_bus_init_irq(void)
199 ACPI_STATUS status = AE_OK;
200 ACPI_OBJECT arg = { ACPI_TYPE_INTEGER };
201 ACPI_OBJECT_LIST arg_list = { 1, &arg };
202 char const *message = NULL;
205 //int acpi_irq_model = ACPI_IRQ_MODEL_PIC;
206 int acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
208 * Let the system know what interrupt model we are using by
209 * evaluating the \_PIC object, if exists.
212 switch (acpi_irq_model) {
213 case ACPI_IRQ_MODEL_PIC:
216 case ACPI_IRQ_MODEL_IOAPIC:
219 case ACPI_IRQ_MODEL_IOSAPIC:
222 case ACPI_IRQ_MODEL_PLATFORM:
223 message = "platform specific model";
226 printf("Unknown interrupt routing model\n");
230 printf("Using %s for interrupt routing\n", message);
232 arg.Integer.Value = acpi_irq_model;
234 status = AcpiEvaluateObject(NULL, (char*)"\\_PIC", &arg_list, NULL);
235 if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
236 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
246 Hw::Device *last_device;
247 Hw::Device *current_bus;
251 class Acpi_res_discover : public Hw::Discover_res_if
254 Acpi_res_discover(ACPI_HANDLE obj) : obj(obj) {}
256 void discover_resources(Hw::Device *host);
257 void setup_resources(Hw::Device *) {}
260 void discover_prt(Hw::Device *host);
261 void discover_crs(Hw::Device *host);
267 Acpi_res_discover::discover_prt(Hw::Device *host)
273 status = AcpiGetHandle(obj, (char*)"_PRT", &handle);
276 if (ACPI_FAILURE(status))
278 Resource *r = new Pci_irq_router_res<Pci_pci_bridge_irq_router_rs>();
279 host->add_resource(r);
284 ret_buf.Length = sizeof (buffer);
285 ret_buf.Pointer = buffer;
287 status = AcpiGetName (obj, ACPI_FULL_PATHNAME, &ret_buf);
289 if (ACPI_FAILURE (status))
290 AcpiOsPrintf ("Could not convert name to pathname\n");
292 AcpiOsPrintf ("ACPI: PCI IRQ routing [%s._PRT]\n", buffer);
295 buf.Length = ACPI_ALLOCATE_BUFFER;
297 status = AcpiGetIrqRoutingTable(obj, &buf);
299 if (ACPI_FAILURE(status))
301 printf("ERROR: while getting PRT for [%s]\n", "buffer");
302 Resource *r = new Pci_irq_router_res<Pci_pci_bridge_irq_router_rs>();
303 host->add_resource(r);
307 typedef Pci_irq_router_res<Acpi_pci_irq_router_rs> Irq_res;
308 Irq_res *r = new Irq_res();
310 char *p = (char*)buf.Pointer;
311 char *e = (char*)buf.Pointer + buf.Length;
314 ACPI_PCI_ROUTING_TABLE *prt = (ACPI_PCI_ROUTING_TABLE *)p;
315 if (prt->Length == 0)
318 if (p + prt->Length > e)
321 int err = r->provided()->add_prt_entry(obj, prt);
328 host->add_resource(r);
331 static unsigned acpi_adr_t_to_f(unsigned art)
335 case ACPI_MEMORY_RANGE: return Resource::Mmio_res;
336 case ACPI_IO_RANGE: return Resource::Io_res;
337 case ACPI_BUS_NUMBER_RANGE: return Resource::Bus_res;
343 acpi_adr_res(Hw::Device *host, ACPI_RESOURCE_ADDRESS const *ar, l4_uint64_t s, l4_uint64_t l,
346 unsigned flags = acpi_adr_t_to_f(ar->ResourceType)
347 | Resource::F_fixed_size | Resource::F_fixed_addr;
353 flags |= Resource::F_width_64bit;
356 if (ar->ProducerConsumer == ACPI_PRODUCER)
357 r = new Adr_resource_provider(flags, s, s + l - 1);
359 r = new Adr_resource(flags, s, s + l -1);
361 host->add_resource(r);
365 Acpi_res_discover::discover_crs(Hw::Device *host)
368 buf.Length = ACPI_ALLOCATE_BUFFER;
370 if (ACPI_FAILURE(AcpiGetCurrentResources(obj, &buf)))
373 char const *p = (char const *)buf.Pointer;
376 ACPI_RESOURCE const *r = (ACPI_RESOURCE const *)p;
377 ACPI_RESOURCE_DATA const *d = &r->Data;
382 case ACPI_RESOURCE_TYPE_END_TAG:
383 AcpiOsFree(buf.Pointer);
386 case ACPI_RESOURCE_TYPE_IRQ:
387 flags = Resource::Irq_res;
388 flags |= (!d->Irq.Triggering) * Resource::Irq_info_base;
389 flags |= (!!d->Irq.Polarity) * Resource::Irq_info_base * 2;
390 for (unsigned c = 0; c < d->Irq.InterruptCount; ++c)
391 host->add_resource(new Adr_resource(flags, d->Irq.Interrupts[c],
392 d->Irq.Interrupts[c]));
395 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
396 flags = Resource::Irq_res;
397 flags |= (!d->ExtendedIrq.Triggering) * Resource::Irq_info_base;
398 flags |= (!!d->ExtendedIrq.Polarity) * Resource::Irq_info_base * 2;
399 if (d->ExtendedIrq.ResourceSource.StringPtr)
401 printf("hoo indirect IRQ resource found src=%s idx=%d\n",
402 d->ExtendedIrq.ResourceSource.StringPtr,
403 d->ExtendedIrq.ResourceSource.Index);
407 for (unsigned c = 0; c < d->ExtendedIrq.InterruptCount; ++c)
408 host->add_resource(new Adr_resource(flags, d->ExtendedIrq.Interrupts[c],
409 d->ExtendedIrq.Interrupts[c]));
413 case ACPI_RESOURCE_TYPE_IO:
414 flags = Resource::Io_res | Resource::F_fixed_size | Resource::F_fixed_addr;
415 host->add_resource(new Adr_resource(flags, d->Io.Minimum,
416 d->Io.Minimum + d->Io.AddressLength - 1));
419 case ACPI_RESOURCE_TYPE_FIXED_IO:
420 flags = Resource::Io_res | Resource::F_fixed_size | Resource::F_fixed_addr;
421 host->add_resource(new Adr_resource(flags, d->FixedIo.Address,
422 d->FixedIo.Address + d->FixedIo.AddressLength - 1));
425 case ACPI_RESOURCE_TYPE_MEMORY24:
426 flags = Resource::Mmio_res | Resource::F_fixed_size | Resource::F_fixed_addr;
427 host->add_resource(new Adr_resource(flags, d->Memory24.Minimum,
428 d->Memory24.Minimum + d->Memory24.AddressLength - 1));
431 case ACPI_RESOURCE_TYPE_MEMORY32:
432 flags = Resource::Mmio_res | Resource::F_fixed_size | Resource::F_fixed_addr;
433 host->add_resource(new Adr_resource(flags, d->Memory32.Minimum,
434 d->Memory32.Minimum + d->Memory32.AddressLength - 1));
437 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
438 flags = Resource::Mmio_res | Resource::F_fixed_size | Resource::F_fixed_addr;
439 host->add_resource(new Adr_resource(flags, d->FixedMemory32.Address,
440 d->FixedMemory32.Address + d->FixedMemory32.AddressLength - 1));
443 case ACPI_RESOURCE_TYPE_ADDRESS16:
444 acpi_adr_res(host, &d->Address, d->Address16.Minimum, d->Address16.AddressLength, 0);
447 case ACPI_RESOURCE_TYPE_ADDRESS32:
448 acpi_adr_res(host, &d->Address, d->Address32.Minimum, d->Address32.AddressLength, 0);
451 case ACPI_RESOURCE_TYPE_ADDRESS64:
452 acpi_adr_res(host, &d->Address, d->Address64.Minimum, d->Address64.AddressLength, 1);
456 printf("IGNORE ACPI RES: %d\n", r->Type);
465 AcpiOsFree(buf.Pointer);
469 Acpi_res_discover::discover_resources(Hw::Device *host)
471 if (dynamic_cast<Pci_bridge*>(host->discover_bus_if()))
479 get_adr(ACPI_HANDLE dev)
482 if (ACPI_FAILURE(AcpiGetHandle(dev, const_cast<char*>("_ADR"), &adr)))
487 ret_buf.Pointer = &adro;
488 ret_buf.Length = sizeof(adro);
489 if (ACPI_SUCCESS(AcpiEvaluateObject(adr, NULL, NULL, &ret_buf)))
493 case ACPI_TYPE_INTEGER:
494 return adro.Integer.Value;
504 get_name(ACPI_HANDLE dev, Hw::Device *hd)
509 buf.Length = sizeof(str);
510 if (ACPI_SUCCESS(AcpiGetName(dev, ACPI_SINGLE_NAME, &buf)))
516 discover_pre_cb(ACPI_HANDLE obj, UINT32 nl, void *ctxt, void **)
518 Discover_ctxt *c = reinterpret_cast<Discover_ctxt*>(ctxt);
525 c->current_bus = c->last_device;
529 l4_uint32_t adr = get_adr(obj);
531 Hw::Device *nd = c->current_bus->get_child_dev_uid((l4_umword_t)obj, adr, true);
536 ACPI_DEVICE_ID *hid = 0;
537 ACPI_DEVICE_ID_LIST *cid = 0;
540 if (ACPI_FAILURE(AcpiUtAcquireMutex(ACPI_MTX_NAMESPACE)))
544 ACPI_NAMESPACE_NODE *node = AcpiNsValidateHandle(obj);
547 //AcpiUtReleaseMutex(ACPI_MTX_NAMESPACE);
551 if (ACPI_SUCCESS(AcpiUtExecute_HID(node, &hid)))
553 nd->set_hid(hid->String);
554 pci_rb |= AcpiUtIsPciRootBridge(hid->String);
558 if (ACPI_SUCCESS(AcpiUtExecute_CID(node, &cid)))
560 for (unsigned i = 0; i < cid->Count; ++i)
562 nd->add_cid(cid->Ids[i].String);
563 pci_rb |= AcpiUtIsPciRootBridge(cid->Ids[i].String);
569 //AcpiUtReleaseMutex(ACPI_MTX_NAMESPACE);
571 // hm, this seems very specific for PCI
574 printf("Found PCI root bridge...\n");
575 if (Pci_root_bridge *rb = pci_root_bridge(0))
579 // we found a second root bridge
580 // create a new root pridge instance
581 rb = new Pci_port_root_bridge(nd);
586 nd->set_discover_bus_if(rb);
589 printf("ERROR: there is no PCI bus driver for this platform\n");
592 nd->add_resource_discoverer(new Acpi_res_discover(obj));
598 discover_post_cb(ACPI_HANDLE, UINT32 nl, void *ctxt, void **)
600 Discover_ctxt *c = reinterpret_cast<Discover_ctxt*>(ctxt);
604 c->current_bus = c->current_bus->parent();
614 printf("Hello from L4-ACPICA\n");
616 pci_register_root_bridge(0, new Pci_port_root_bridge(0));
621 // | ACPI_LV_FUNCTIONSkern/irq.cpp
622 // | ACPI_LV_ALL_EXCEPTIONS
624 // | ACPI_LV_INIT_NAMES
626 // | ACPI_LV_RESOURCES
629 // | ACPI_LV_OPREGION
630 | ACPI_LV_VERBOSE_INFO
632 // | ACPI_LV_DISPATCH
637 //0. enable workarounds, see include/acglobals.h
638 AcpiGbl_EnableInterpreterSlack = (1==1);
641 status = AcpiInitializeSubsystem();
645 status = AcpiInitializeTables (0, 0, TRUE);
649 status = AcpiReallocateRootTable ();
653 status = AcpiLoadTables ();
655 if(ACPI_FAILURE(status))
658 printf("enable ACPI subsystem\n");
659 status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION);
661 if (ACPI_FAILURE(status))
663 printf("Unable to start the ACPI Interpreter\n");
667 printf("initialize ACPI objects\n");
668 status = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION);
669 if (ACPI_FAILURE(status)) {
670 printf("Unable to initialize ACPI objects\n");
674 printf("Interpreter enabled\n");
677 c.last_device = system_bus();
678 c.current_bus = system_bus();
682 printf("scanning for PCI root bridge\n");
683 status = AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
685 discover_pre_cb, discover_post_cb, &c, 0);
688 * Get the system interrupt model and evaluate \_PIC.
690 int result = acpi_bus_init_irq();
693 printf("Could not initialize ACPI IRQ stuff\n");
696 status = AcpiSubsystemStatus();
698 if (ACPI_FAILURE(status))
700 else if (Io_config::cfg->verbose() > 1)
701 printf("acpi_subsystem initialized\n");
704 ACPI_BUFFER ret_buffer;
705 ret_buffer.Length = ACPI_ALLOCATE_BUFFER;
707 status = AcpiGetSystemInfo(&ret_buffer);
709 if(ACPI_FAILURE(status))
712 acpi_print_system_info(ret_buffer.Pointer);
714 AcpiOsFree(ret_buffer.Pointer);