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 Adr_resource *cr = dynamic_cast<Adr_resource*>(child);
76 child->parent(parent);
80 Hw::Device *cd = dynamic_cast<Hw::Device*>(cdev);
85 struct acpica_pci_irq *irq = 0;
87 if (find(cd->adr() >> 16, cr->start(), &irq) < 0)
93 cr->del_flags(Resource::F_relative);
95 cr->del_flags(Resource::Irq_info_base * 3);
97 flags |= (!irq->trigger) * Resource::Irq_info_base;
98 flags |= (!!irq->polarity) * Resource::Irq_info_base * 2;
106 enum Acpi_irq_model_id {
107 ACPI_IRQ_MODEL_PIC = 0,
108 ACPI_IRQ_MODEL_IOAPIC,
109 ACPI_IRQ_MODEL_IOSAPIC,
110 ACPI_IRQ_MODEL_PLATFORM,
115 get_irq_cb(ACPI_RESOURCE *res, void *ctxt)
117 acpica_pci_irq *irq = (acpica_pci_irq*)ctxt;
123 case ACPI_RESOURCE_TYPE_IRQ:
124 irq->irq = res->Data.Irq.Interrupts[0];
125 irq->polarity = res->Data.Irq.Polarity;
126 irq->trigger = res->Data.Irq.Triggering;
129 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
130 irq->irq = res->Data.ExtendedIrq.Interrupts[0];
131 irq->polarity = res->Data.ExtendedIrq.Polarity;
132 irq->trigger = res->Data.ExtendedIrq.Triggering;
141 Acpi_pci_irq_router_rs::add_prt_entry(ACPI_HANDLE obj,
142 ACPI_PCI_ROUTING_TABLE *e)
147 Prt_entry *ne = new Prt_entry();
151 ne->slot = (e->Address >> 16) & 0xffff;
154 ne->irq.irq = e->SourceIndex;
155 ne->irq.polarity = ACPI_ACTIVE_LOW;
156 ne->irq.trigger = ACPI_LEVEL_SENSITIVE;
160 d_printf(DBG_DEBUG, " (dev[%s][%d]) ", e->Source, e->SourceIndex);
162 status = AcpiGetHandle(obj, e->Source, &link);
163 if (ACPI_FAILURE(status))
165 d_printf(DBG_WARN, "\nWARNING: Could not find PCI IRQ Link Device...\n");
169 status = AcpiWalkResources(link, (char*)"_CRS", get_irq_cb, &ne->irq);
170 if (ACPI_FAILURE(status))
172 d_printf(DBG_WARN, "\nWARNING: Could not evaluate _CRS of PCI IRQ Link Device\n");
177 _prt = cxx::List_item::push_back(_prt, ne);
182 Acpi_pci_irq_router_rs::find(int device, int pin, struct acpica_pci_irq **irq)
184 Prt_entry::T_iter<Prt_entry> c = _prt;
187 if (c->slot == (unsigned)device && c->pin == pin)
200 static int acpi_bus_init_irq(void)
202 ACPI_STATUS status = AE_OK;
203 ACPI_OBJECT arg = { ACPI_TYPE_INTEGER };
204 ACPI_OBJECT_LIST arg_list = { 1, &arg };
205 char const *message = NULL;
208 //int acpi_irq_model = ACPI_IRQ_MODEL_PIC;
209 int acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
211 * Let the system know what interrupt model we are using by
212 * evaluating the \_PIC object, if exists.
215 switch (acpi_irq_model) {
216 case ACPI_IRQ_MODEL_PIC:
219 case ACPI_IRQ_MODEL_IOAPIC:
222 case ACPI_IRQ_MODEL_IOSAPIC:
225 case ACPI_IRQ_MODEL_PLATFORM:
226 message = "platform specific model";
229 d_printf(DBG_ERR, "ERROR: Unknown interrupt routing model\n");
233 d_printf(DBG_INFO, "Using %s for interrupt routing\n", message);
235 arg.Integer.Value = acpi_irq_model;
237 status = AcpiEvaluateObject(NULL, (char*)"\\_PIC", &arg_list, NULL);
238 if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
239 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
249 Hw::Device *last_device;
250 Hw::Device *current_bus;
254 class Acpi_res_discover : public Hw::Discover_res_if
257 Acpi_res_discover(ACPI_HANDLE obj) : obj(obj) {}
259 void discover_resources(Hw::Device *host);
260 void setup_resources(Hw::Device *) {}
263 void discover_prt(Hw::Device *host);
264 void discover_crs(Hw::Device *host);
270 Acpi_res_discover::discover_prt(Hw::Device *host)
276 status = AcpiGetHandle(obj, (char*)"_PRT", &handle);
279 if (ACPI_FAILURE(status))
281 Resource *r = new Pci_irq_router_res<Pci_pci_bridge_irq_router_rs>();
282 host->add_resource(r);
287 ret_buf.Length = sizeof (buffer);
288 ret_buf.Pointer = buffer;
290 status = AcpiGetName (obj, ACPI_FULL_PATHNAME, &ret_buf);
292 if (ACPI_FAILURE (status))
293 AcpiOsPrintf ("Could not convert name to pathname\n");
295 AcpiOsPrintf ("ACPI: PCI IRQ routing [%s._PRT]\n", buffer);
298 buf.Length = ACPI_ALLOCATE_BUFFER;
300 status = AcpiGetIrqRoutingTable(obj, &buf);
302 if (ACPI_FAILURE(status))
304 d_printf(DBG_ERR, "ERROR: while getting PRT for [%s]\n", "buffer");
305 Resource *r = new Pci_irq_router_res<Pci_pci_bridge_irq_router_rs>();
306 host->add_resource(r);
310 typedef Pci_irq_router_res<Acpi_pci_irq_router_rs> Irq_res;
311 Irq_res *r = new Irq_res();
313 char *p = (char*)buf.Pointer;
314 char *e = (char*)buf.Pointer + buf.Length;
317 ACPI_PCI_ROUTING_TABLE *prt = (ACPI_PCI_ROUTING_TABLE *)p;
318 if (prt->Length == 0)
321 if (p + prt->Length > e)
324 int err = r->provided()->add_prt_entry(obj, prt);
331 host->add_resource(r);
334 static unsigned acpi_adr_t_to_f(unsigned art)
338 case ACPI_MEMORY_RANGE: return Resource::Mmio_res;
339 case ACPI_IO_RANGE: return Resource::Io_res;
340 case ACPI_BUS_NUMBER_RANGE: return Resource::Bus_res;
346 acpi_adr_res(Hw::Device *host, ACPI_RESOURCE_ADDRESS const *ar, l4_uint64_t s, l4_uint64_t l,
349 unsigned flags = acpi_adr_t_to_f(ar->ResourceType)
350 | Resource::F_fixed_size | Resource::F_fixed_addr;
356 flags |= Resource::F_width_64bit;
359 if (ar->ProducerConsumer == ACPI_PRODUCER)
360 r = new Adr_resource_provider(flags, s, s + l - 1);
362 r = new Adr_resource(flags, s, s + l -1);
364 host->add_resource(r);
368 Acpi_res_discover::discover_crs(Hw::Device *host)
371 buf.Length = ACPI_ALLOCATE_BUFFER;
373 if (ACPI_FAILURE(AcpiGetCurrentResources(obj, &buf)))
376 char const *p = (char const *)buf.Pointer;
379 ACPI_RESOURCE const *r = (ACPI_RESOURCE const *)p;
380 ACPI_RESOURCE_DATA const *d = &r->Data;
385 case ACPI_RESOURCE_TYPE_END_TAG:
386 AcpiOsFree(buf.Pointer);
389 case ACPI_RESOURCE_TYPE_IRQ:
390 flags = Resource::Irq_res;
391 flags |= (!d->Irq.Triggering) * Resource::Irq_info_base;
392 flags |= (!!d->Irq.Polarity) * Resource::Irq_info_base * 2;
393 for (unsigned c = 0; c < d->Irq.InterruptCount; ++c)
394 host->add_resource(new Adr_resource(flags, d->Irq.Interrupts[c],
395 d->Irq.Interrupts[c]));
398 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
399 flags = Resource::Irq_res;
400 flags |= (!d->ExtendedIrq.Triggering) * Resource::Irq_info_base;
401 flags |= (!!d->ExtendedIrq.Polarity) * Resource::Irq_info_base * 2;
402 if (d->ExtendedIrq.ResourceSource.StringPtr)
404 d_printf(DBG_DEBUG2, "hoo indirect IRQ resource found src=%s idx=%d\n",
405 d->ExtendedIrq.ResourceSource.StringPtr,
406 d->ExtendedIrq.ResourceSource.Index);
410 for (unsigned c = 0; c < d->ExtendedIrq.InterruptCount; ++c)
411 host->add_resource(new Adr_resource(flags, d->ExtendedIrq.Interrupts[c],
412 d->ExtendedIrq.Interrupts[c]));
416 case ACPI_RESOURCE_TYPE_IO:
417 flags = Resource::Io_res | Resource::F_fixed_size | Resource::F_fixed_addr;
418 host->add_resource(new Adr_resource(flags, d->Io.Minimum,
419 d->Io.Minimum + d->Io.AddressLength - 1));
422 case ACPI_RESOURCE_TYPE_FIXED_IO:
423 flags = Resource::Io_res | Resource::F_fixed_size | Resource::F_fixed_addr;
424 host->add_resource(new Adr_resource(flags, d->FixedIo.Address,
425 d->FixedIo.Address + d->FixedIo.AddressLength - 1));
428 case ACPI_RESOURCE_TYPE_MEMORY24:
429 flags = Resource::Mmio_res | Resource::F_fixed_size | Resource::F_fixed_addr;
430 host->add_resource(new Adr_resource(flags, d->Memory24.Minimum,
431 d->Memory24.Minimum + d->Memory24.AddressLength - 1));
434 case ACPI_RESOURCE_TYPE_MEMORY32:
435 flags = Resource::Mmio_res | Resource::F_fixed_size | Resource::F_fixed_addr;
436 host->add_resource(new Adr_resource(flags, d->Memory32.Minimum,
437 d->Memory32.Minimum + d->Memory32.AddressLength - 1));
440 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
441 flags = Resource::Mmio_res | Resource::F_fixed_size | Resource::F_fixed_addr;
442 host->add_resource(new Adr_resource(flags, d->FixedMemory32.Address,
443 d->FixedMemory32.Address + d->FixedMemory32.AddressLength - 1));
446 case ACPI_RESOURCE_TYPE_ADDRESS16:
447 acpi_adr_res(host, &d->Address, d->Address16.Minimum, d->Address16.AddressLength, 0);
450 case ACPI_RESOURCE_TYPE_ADDRESS32:
451 acpi_adr_res(host, &d->Address, d->Address32.Minimum, d->Address32.AddressLength, 0);
454 case ACPI_RESOURCE_TYPE_ADDRESS64:
455 acpi_adr_res(host, &d->Address, d->Address64.Minimum, d->Address64.AddressLength, 1);
459 d_printf(DBG_WARN, "WARNING: ignoring ACPI recource (unkown type: %d)\n", r->Type);
468 AcpiOsFree(buf.Pointer);
472 Acpi_res_discover::discover_resources(Hw::Device *host)
474 Pci_bridge *bridge = dynamic_cast<Pci_bridge*>(host->discover_bus_if());
482 for (Resource_list::iterator i = host->resources()->begin();
483 i != host->resources()->end(); ++i)
485 if ((*i)->type() == Resource::Bus_res)
486 bridge->num = bridge->subordinate = static_cast<Adr_resource*>(*i)->start();
493 get_adr(ACPI_HANDLE dev)
496 if (ACPI_FAILURE(AcpiGetHandle(dev, const_cast<char*>("_ADR"), &adr)))
501 ret_buf.Pointer = &adro;
502 ret_buf.Length = sizeof(adro);
503 if (ACPI_SUCCESS(AcpiEvaluateObject(adr, NULL, NULL, &ret_buf)))
507 case ACPI_TYPE_INTEGER:
508 return adro.Integer.Value;
518 get_name(ACPI_HANDLE dev, Hw::Device *hd)
523 buf.Length = sizeof(str);
524 if (ACPI_SUCCESS(AcpiGetName(dev, ACPI_SINGLE_NAME, &buf)))
530 discover_pre_cb(ACPI_HANDLE obj, UINT32 nl, void *ctxt, void **)
532 Discover_ctxt *c = reinterpret_cast<Discover_ctxt*>(ctxt);
539 c->current_bus = c->last_device;
543 l4_uint32_t adr = get_adr(obj);
545 Hw::Device *nd = c->current_bus->get_child_dev_uid((l4_umword_t)obj, adr, true);
550 ACPI_DEVICE_ID *hid = 0;
551 ACPI_DEVICE_ID_LIST *cid = 0;
554 if (ACPI_FAILURE(AcpiUtAcquireMutex(ACPI_MTX_NAMESPACE)))
558 ACPI_NAMESPACE_NODE *node = AcpiNsValidateHandle(obj);
561 //AcpiUtReleaseMutex(ACPI_MTX_NAMESPACE);
565 if (ACPI_SUCCESS(AcpiUtExecute_HID(node, &hid)))
567 nd->set_hid(hid->String);
568 pci_rb |= AcpiUtIsPciRootBridge(hid->String);
572 if (ACPI_SUCCESS(AcpiUtExecute_CID(node, &cid)))
574 for (unsigned i = 0; i < cid->Count; ++i)
576 nd->add_cid(cid->Ids[i].String);
577 pci_rb |= AcpiUtIsPciRootBridge(cid->Ids[i].String);
583 //AcpiUtReleaseMutex(ACPI_MTX_NAMESPACE);
585 // hm, this seems very specific for PCI
588 d_printf(DBG_DEBUG, "Found PCI root bridge...\n");
589 if (Pci_root_bridge *rb = pci_root_bridge(0))
593 // we found a second root bridge
594 // create a new root pridge instance
595 rb = new Pci_port_root_bridge(-1, nd);
600 nd->set_discover_bus_if(rb);
603 d_printf(DBG_ERR, "ERROR: there is no PCI bus driver for this platform\n");
606 nd->add_resource_discoverer(new Acpi_res_discover(obj));
612 discover_post_cb(ACPI_HANDLE, UINT32 nl, void *ctxt, void **)
614 Discover_ctxt *c = reinterpret_cast<Discover_ctxt*>(ctxt);
618 c->current_bus = c->current_bus->parent();
628 d_printf(DBG_INFO, "Hello from L4-ACPICA\n");
630 pci_register_root_bridge(0, new Pci_port_root_bridge(0, 0));
635 // | ACPI_LV_FUNCTIONSkern/irq.cpp
636 // | ACPI_LV_ALL_EXCEPTIONS
638 // | ACPI_LV_INIT_NAMES
640 // | ACPI_LV_RESOURCES
643 // | ACPI_LV_OPREGION
644 | ACPI_LV_VERBOSE_INFO
646 // | ACPI_LV_DISPATCH
651 //0. enable workarounds, see include/acglobals.h
652 AcpiGbl_EnableInterpreterSlack = (1==1);
655 status = AcpiInitializeSubsystem();
659 status = AcpiInitializeTables (0, 0, TRUE);
663 status = AcpiReallocateRootTable ();
667 status = AcpiLoadTables ();
669 if(ACPI_FAILURE(status))
672 d_printf(DBG_DEBUG, "enable ACPI subsystem\n");
673 status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION);
675 if (ACPI_FAILURE(status))
677 d_printf(DBG_ERR, "Unable to start the ACPI Interpreter\n");
681 d_printf(DBG_DEBUG, "initialize ACPI objects\n");
682 status = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION);
683 if (ACPI_FAILURE(status)) {
684 d_printf(DBG_ERR, "Unable to initialize ACPI objects\n");
688 d_printf(DBG_DEBUG, "Interpreter enabled\n");
691 c.last_device = system_bus();
692 c.current_bus = system_bus();
696 d_printf(DBG_DEBUG, "scanning for PCI root bridge\n");
697 status = AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
699 discover_pre_cb, discover_post_cb, &c, 0);
702 * Get the system interrupt model and evaluate \_PIC.
704 int result = acpi_bus_init_irq();
707 d_printf(DBG_ERR, "Could not initialize ACPI IRQ stuff\n");
710 status = AcpiSubsystemStatus();
712 if (ACPI_FAILURE(status))
715 d_printf(DBG_INFO, "ACPI subsystem initialized\n");
717 ACPI_BUFFER ret_buffer;
718 ret_buffer.Length = ACPI_ALLOCATE_BUFFER;
720 status = AcpiGetSystemInfo(&ret_buffer);
722 if(ACPI_FAILURE(status))
725 acpi_print_system_info(ret_buffer.Pointer);
727 AcpiOsFree(ret_buffer.Pointer);