2 * (c) 2011 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.
20 #include "phys_space.h"
30 #include <l4/cxx/list>
32 #define _COMPONENT ACPI_BUS_COMPONENT
33 ACPI_MODULE_NAME("l4main");
37 struct Prt_entry : public cxx::List_item
44 class Acpi_pci_irq_router_rs : public Resource_space
50 Acpi_pci_irq_router_rs() : _prt(0) {}
52 int add_prt_entry(ACPI_HANDLE obj, ACPI_PCI_ROUTING_TABLE *e);
53 int find(int device, int pin, struct acpica_pci_irq **irq);
54 bool request(Resource *parent, Device *, Resource *child, Device *cdev);
55 bool alloc(Resource *, Device *, Resource *, Device *, bool)
61 Acpi_pci_irq_router_rs::request(Resource *parent, Device *,
62 Resource *child, Device *cdev)
66 printf("requesting IRQ resource: ");
69 printf(" at ACPI IRQ routing resource\n");
72 Hw::Device *cd = dynamic_cast<Hw::Device*>(cdev);
77 struct acpica_pci_irq *irq = 0;
79 if (find(cd->adr() >> 16, child->start(), &irq) < 0)
85 child->del_flags(Resource::F_relative);
86 child->start(irq->irq);
87 child->del_flags(Resource::Irq_type_mask);
88 unsigned flags = Resource::Irq_type_base;
89 flags |= (!irq->trigger) * Resource::Irq_type_base * L4_IRQ_F_LEVEL;
90 flags |= (!!irq->polarity) * Resource::Irq_type_base * L4_IRQ_F_NEG;
91 child->add_flags(flags);
93 child->parent(parent);
98 enum Acpi_irq_model_id {
99 ACPI_IRQ_MODEL_PIC = 0,
100 ACPI_IRQ_MODEL_IOAPIC,
101 ACPI_IRQ_MODEL_IOSAPIC,
102 ACPI_IRQ_MODEL_PLATFORM,
107 get_irq_cb(ACPI_RESOURCE *res, void *ctxt)
109 acpica_pci_irq *irq = (acpica_pci_irq*)ctxt;
115 case ACPI_RESOURCE_TYPE_IRQ:
116 irq->irq = res->Data.Irq.Interrupts[0];
117 irq->polarity = res->Data.Irq.Polarity;
118 irq->trigger = res->Data.Irq.Triggering;
121 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
122 irq->irq = res->Data.ExtendedIrq.Interrupts[0];
123 irq->polarity = res->Data.ExtendedIrq.Polarity;
124 irq->trigger = res->Data.ExtendedIrq.Triggering;
133 Acpi_pci_irq_router_rs::add_prt_entry(ACPI_HANDLE obj,
134 ACPI_PCI_ROUTING_TABLE *e)
139 Prt_entry *ne = new Prt_entry();
143 ne->slot = (e->Address >> 16) & 0xffff;
146 ne->irq.irq = e->SourceIndex;
147 ne->irq.polarity = ACPI_ACTIVE_LOW;
148 ne->irq.trigger = ACPI_LEVEL_SENSITIVE;
152 d_printf(DBG_DEBUG, " (dev[%s][%d]) ", e->Source, e->SourceIndex);
154 status = AcpiGetHandle(obj, e->Source, &link);
155 if (ACPI_FAILURE(status))
157 d_printf(DBG_WARN, "\nWARNING: Could not find PCI IRQ Link Device...\n");
161 status = AcpiWalkResources(link, (char*)"_CRS", get_irq_cb, &ne->irq);
162 if (ACPI_FAILURE(status))
164 d_printf(DBG_WARN, "\nWARNING: Could not evaluate _CRS of PCI IRQ Link Device\n");
169 _prt = cxx::List_item::push_back(_prt, ne);
174 Acpi_pci_irq_router_rs::find(int device, int pin, struct acpica_pci_irq **irq)
176 Prt_entry::T_iter<Prt_entry> c = _prt;
179 if (c->slot == (unsigned)device && c->pin == pin)
192 static int acpi_bus_init_irq(void)
194 ACPI_STATUS status = AE_OK;
195 ACPI_OBJECT arg = { ACPI_TYPE_INTEGER };
196 ACPI_OBJECT_LIST arg_list = { 1, &arg };
197 char const *message = NULL;
200 //int acpi_irq_model = ACPI_IRQ_MODEL_PIC;
201 int acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
203 * Let the system know what interrupt model we are using by
204 * evaluating the \_PIC object, if exists.
207 switch (acpi_irq_model) {
208 case ACPI_IRQ_MODEL_PIC:
211 case ACPI_IRQ_MODEL_IOAPIC:
214 case ACPI_IRQ_MODEL_IOSAPIC:
217 case ACPI_IRQ_MODEL_PLATFORM:
218 message = "platform specific model";
221 d_printf(DBG_ERR, "ERROR: Unknown interrupt routing model\n");
225 d_printf(DBG_INFO, "Using %s for interrupt routing\n", message);
227 arg.Integer.Value = acpi_irq_model;
229 status = AcpiEvaluateObject(NULL, (char*)"\\_PIC", &arg_list, NULL);
230 if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
231 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
241 Hw::Device *last_device;
242 Hw::Device *current_bus;
246 class Acpi_res_discover : public Hw::Discover_res_if
249 Acpi_res_discover(ACPI_HANDLE obj) : obj(obj) {}
251 void discover_resources(Hw::Device *host);
252 void setup_resources(Hw::Device *) {}
255 void discover_prt(Hw::Device *host);
256 void discover_crs(Hw::Device *host);
262 Acpi_res_discover::discover_prt(Hw::Device *host)
268 status = AcpiGetHandle(obj, (char*)"_PRT", &handle);
271 if (ACPI_FAILURE(status))
273 Resource *r = new Pci_irq_router_res<Pci_pci_bridge_irq_router_rs>();
274 host->add_resource(r);
279 ret_buf.Length = sizeof (buffer);
280 ret_buf.Pointer = buffer;
282 status = AcpiGetName (obj, ACPI_FULL_PATHNAME, &ret_buf);
284 if (ACPI_FAILURE (status))
285 AcpiOsPrintf ("Could not convert name to pathname\n");
287 AcpiOsPrintf ("ACPI: PCI IRQ routing [%s._PRT]\n", buffer);
290 buf.Length = ACPI_ALLOCATE_BUFFER;
292 status = AcpiGetIrqRoutingTable(obj, &buf);
294 if (ACPI_FAILURE(status))
296 d_printf(DBG_ERR, "ERROR: while getting PRT for [%s]\n", "buffer");
297 Resource *r = new Pci_irq_router_res<Pci_pci_bridge_irq_router_rs>();
298 host->add_resource(r);
302 typedef Pci_irq_router_res<Acpi_pci_irq_router_rs> Irq_res;
303 Irq_res *r = new Irq_res();
305 char *p = (char*)buf.Pointer;
306 char *e = (char*)buf.Pointer + buf.Length;
309 ACPI_PCI_ROUTING_TABLE *prt = (ACPI_PCI_ROUTING_TABLE *)p;
310 if (prt->Length == 0)
313 if (p + prt->Length > e)
316 int err = r->provided()->add_prt_entry(obj, prt);
323 host->add_resource(r);
326 static unsigned acpi_adr_t_to_f(unsigned art)
330 case ACPI_MEMORY_RANGE: return Resource::Mmio_res;
331 case ACPI_IO_RANGE: return Resource::Io_res;
332 case ACPI_BUS_NUMBER_RANGE: return Resource::Bus_res;
338 acpi_adr_res(Hw::Device *host, ACPI_RESOURCE_ADDRESS const *ar, l4_uint64_t s, l4_uint64_t l,
341 unsigned flags = acpi_adr_t_to_f(ar->ResourceType)
342 | Resource::F_fixed_size | Resource::F_fixed_addr;
348 flags |= Resource::F_width_64bit;
351 if (ar->ProducerConsumer == ACPI_PRODUCER)
352 r = new Resource_provider(flags, s, s + l - 1);
354 r = new Resource(flags, s, s + l -1);
356 host->add_resource(r);
360 Acpi_res_discover::discover_crs(Hw::Device *host)
363 buf.Length = ACPI_ALLOCATE_BUFFER;
365 if (ACPI_FAILURE(AcpiGetCurrentResources(obj, &buf)))
368 char const *p = (char const *)buf.Pointer;
371 ACPI_RESOURCE const *r = (ACPI_RESOURCE const *)p;
372 ACPI_RESOURCE_DATA const *d = &r->Data;
377 case ACPI_RESOURCE_TYPE_END_TAG:
378 AcpiOsFree(buf.Pointer);
381 case ACPI_RESOURCE_TYPE_IRQ:
382 flags = Resource::Irq_res | Resource::Irq_type_base;
383 flags |= (!d->Irq.Triggering) * Resource::Irq_type_base * L4_IRQ_F_LEVEL;
384 flags |= (!!d->Irq.Polarity) * Resource::Irq_type_base * L4_IRQ_F_NEG;
385 for (unsigned c = 0; c < d->Irq.InterruptCount; ++c)
386 host->add_resource(new Resource(flags, d->Irq.Interrupts[c],
387 d->Irq.Interrupts[c]));
390 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
391 flags = Resource::Irq_res | Resource::Irq_type_base;
392 flags |= (!d->ExtendedIrq.Triggering) * Resource::Irq_type_base * L4_IRQ_F_LEVEL;
393 flags |= (!!d->ExtendedIrq.Polarity) * Resource::Irq_type_base * L4_IRQ_F_NEG;
394 if (d->ExtendedIrq.ResourceSource.StringPtr)
396 d_printf(DBG_DEBUG2, "hoo indirect IRQ resource found src=%s idx=%d\n",
397 d->ExtendedIrq.ResourceSource.StringPtr,
398 d->ExtendedIrq.ResourceSource.Index);
402 for (unsigned c = 0; c < d->ExtendedIrq.InterruptCount; ++c)
403 host->add_resource(new Resource(flags, d->ExtendedIrq.Interrupts[c],
404 d->ExtendedIrq.Interrupts[c]));
408 case ACPI_RESOURCE_TYPE_IO:
409 flags = Resource::Io_res | Resource::F_fixed_size | Resource::F_fixed_addr;
410 host->add_resource(new Resource(flags, d->Io.Minimum,
411 d->Io.Minimum + d->Io.AddressLength - 1));
414 case ACPI_RESOURCE_TYPE_FIXED_IO:
415 flags = Resource::Io_res | Resource::F_fixed_size | Resource::F_fixed_addr;
416 host->add_resource(new Resource(flags, d->FixedIo.Address,
417 d->FixedIo.Address + d->FixedIo.AddressLength - 1));
420 case ACPI_RESOURCE_TYPE_MEMORY24:
421 flags = Resource::Mmio_res | Resource::F_fixed_size | Resource::F_fixed_addr;
422 host->add_resource(new Resource(flags, d->Memory24.Minimum,
423 d->Memory24.Minimum + d->Memory24.AddressLength - 1));
426 case ACPI_RESOURCE_TYPE_MEMORY32:
427 flags = Resource::Mmio_res | Resource::F_fixed_size | Resource::F_fixed_addr;
428 host->add_resource(new Resource(flags, d->Memory32.Minimum,
429 d->Memory32.Minimum + d->Memory32.AddressLength - 1));
432 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
433 flags = Resource::Mmio_res | Resource::F_fixed_size | Resource::F_fixed_addr;
434 host->add_resource(new Resource(flags, d->FixedMemory32.Address,
435 d->FixedMemory32.Address + d->FixedMemory32.AddressLength - 1));
438 case ACPI_RESOURCE_TYPE_ADDRESS16:
439 acpi_adr_res(host, &d->Address, d->Address16.Minimum, d->Address16.AddressLength, 0);
442 case ACPI_RESOURCE_TYPE_ADDRESS32:
443 acpi_adr_res(host, &d->Address, d->Address32.Minimum, d->Address32.AddressLength, 0);
446 case ACPI_RESOURCE_TYPE_ADDRESS64:
447 acpi_adr_res(host, &d->Address, d->Address64.Minimum, d->Address64.AddressLength, 1);
451 d_printf(DBG_WARN, "WARNING: ignoring ACPI recource (unkown type: %d)\n", r->Type);
460 AcpiOsFree(buf.Pointer);
464 Acpi_res_discover::discover_resources(Hw::Device *host)
466 Pci_bridge *bridge = dynamic_cast<Pci_bridge*>(host->discover_bus_if());
474 for (Resource_list::const_iterator i = host->resources()->begin();
475 i != host->resources()->end(); ++i)
477 if ((*i)->type() == Resource::Bus_res)
478 bridge->num = bridge->subordinate = (*i)->start();
485 get_adr(ACPI_HANDLE dev)
488 if (ACPI_FAILURE(AcpiGetHandle(dev, const_cast<char*>("_ADR"), &adr)))
493 ret_buf.Pointer = &adro;
494 ret_buf.Length = sizeof(adro);
495 if (ACPI_SUCCESS(AcpiEvaluateObject(adr, NULL, NULL, &ret_buf)))
499 case ACPI_TYPE_INTEGER:
500 return adro.Integer.Value;
510 get_name(ACPI_HANDLE dev, Hw::Device *hd)
515 buf.Length = sizeof(str);
516 if (ACPI_SUCCESS(AcpiGetName(dev, ACPI_SINGLE_NAME, &buf)))
522 discover_pre_cb(ACPI_HANDLE obj, UINT32 nl, void *ctxt, void **)
524 Discover_ctxt *c = reinterpret_cast<Discover_ctxt*>(ctxt);
531 c->current_bus = c->last_device;
535 l4_uint32_t adr = get_adr(obj);
537 Hw::Device *nd = c->current_bus->get_child_dev_uid((l4_umword_t)obj, adr, true);
542 ACPI_PNP_DEVICE_ID *hid = 0;
543 ACPI_PNP_DEVICE_ID_LIST *cid = 0;
546 if (ACPI_FAILURE(AcpiUtAcquireMutex(ACPI_MTX_NAMESPACE)))
550 ACPI_NAMESPACE_NODE *node = AcpiNsValidateHandle(obj);
553 //AcpiUtReleaseMutex(ACPI_MTX_NAMESPACE);
557 if (ACPI_SUCCESS(AcpiUtExecute_HID(node, &hid)))
559 nd->set_hid(hid->String);
560 pci_rb |= AcpiUtIsPciRootBridge(hid->String);
564 if (ACPI_SUCCESS(AcpiUtExecute_CID(node, &cid)))
566 for (unsigned i = 0; i < cid->Count; ++i)
568 nd->add_cid(cid->Ids[i].String);
569 pci_rb |= AcpiUtIsPciRootBridge(cid->Ids[i].String);
575 //AcpiUtReleaseMutex(ACPI_MTX_NAMESPACE);
577 // hm, this seems very specific for PCI
580 d_printf(DBG_DEBUG, "Found PCI root bridge...\n");
581 if (Pci_root_bridge *rb = pci_root_bridge(0))
585 // we found a second root bridge
586 // create a new root pridge instance
587 rb = new Pci_port_root_bridge(-1, nd);
592 nd->set_discover_bus_if(rb);
595 d_printf(DBG_ERR, "ERROR: there is no PCI bus driver for this platform\n");
598 nd->add_resource_discoverer(new Acpi_res_discover(obj));
604 discover_post_cb(ACPI_HANDLE, UINT32 nl, void *ctxt, void **)
606 Discover_ctxt *c = reinterpret_cast<Discover_ctxt*>(ctxt);
610 c->current_bus = c->current_bus->parent();
620 d_printf(DBG_INFO, "Hello from L4-ACPICA\n");
622 pci_register_root_bridge(0, new Pci_port_root_bridge(0, 0));
627 // | ACPI_LV_FUNCTIONSkern/irq.cpp
628 // | ACPI_LV_ALL_EXCEPTIONS
630 // | ACPI_LV_INIT_NAMES
632 // | ACPI_LV_RESOURCES
635 // | ACPI_LV_OPREGION
636 | ACPI_LV_VERBOSE_INFO
638 // | ACPI_LV_DISPATCH
643 //0. enable workarounds, see include/acglobals.h
644 AcpiGbl_EnableInterpreterSlack = (1==1);
647 status = AcpiInitializeSubsystem();
651 status = AcpiInitializeTables (0, 0, TRUE);
655 status = AcpiReallocateRootTable ();
659 status = AcpiLoadTables ();
661 if(ACPI_FAILURE(status))
664 d_printf(DBG_DEBUG, "enable ACPI subsystem\n");
665 status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION);
667 if (ACPI_FAILURE(status))
669 d_printf(DBG_ERR, "Unable to start the ACPI Interpreter\n");
673 d_printf(DBG_DEBUG, "initialize ACPI objects\n");
674 status = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION);
675 if (ACPI_FAILURE(status)) {
676 d_printf(DBG_ERR, "Unable to initialize ACPI objects\n");
680 d_printf(DBG_DEBUG, "Interpreter enabled\n");
683 c.last_device = system_bus();
684 c.current_bus = system_bus();
688 d_printf(DBG_DEBUG, "scanning for PCI root bridge\n");
689 status = AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
691 discover_pre_cb, discover_post_cb, &c, 0);
694 * Get the system interrupt model and evaluate \_PIC.
696 int result = acpi_bus_init_irq();
699 d_printf(DBG_ERR, "Could not initialize ACPI IRQ stuff\n");
702 status = AcpiSubsystemStatus();
704 if (ACPI_FAILURE(status))
707 d_printf(DBG_INFO, "ACPI subsystem initialized\n");
709 ACPI_BUFFER ret_buffer;
710 ret_buffer.Length = ACPI_ALLOCATE_BUFFER;
712 status = AcpiGetSystemInfo(&ret_buffer);
714 if(ACPI_FAILURE(status))
717 acpi_print_system_info(ret_buffer.Pointer);
719 AcpiOsFree(ret_buffer.Pointer);