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.
21 #include "phys_space.h"
22 #include "hw_root_bus.h"
33 #include <l4/cxx/list>
34 #include <l4/sys/platform_control>
37 #define _COMPONENT ACPI_BUS_COMPONENT
38 ACPI_MODULE_NAME("l4main");
40 // Default ACPICA debug flags. Can be set by user with --acpi-debug-level.
41 static unsigned _acpi_debug_level =
45 //| ACPI_LV_ALL_EXCEPTIONS
47 //| ACPI_LV_INIT_NAMES
53 | ACPI_LV_VERBOSE_INFO
60 void acpi_set_debug_level(unsigned level)
62 _acpi_debug_level = level;
65 unsigned acpi_get_debug_level()
67 return _acpi_debug_level;
72 struct Acpi_default_driver : Hw::Acpi_device_driver {};
74 static Io_irq_pin *_sci = 0;
76 static Hw::Acpi_device_driver *acpi_default_driver()
78 static Acpi_default_driver d;
82 enum Acpi_irq_model_id {
83 ACPI_IRQ_MODEL_PIC = 0,
84 ACPI_IRQ_MODEL_IOAPIC,
85 ACPI_IRQ_MODEL_IOSAPIC,
86 ACPI_IRQ_MODEL_PLATFORM,
90 static int acpi_bus_init_irq(void)
92 ACPI_STATUS status = AE_OK;
93 ACPI_OBJECT arg = { ACPI_TYPE_INTEGER };
94 ACPI_OBJECT_LIST arg_list = { 1, &arg };
95 char const *message = NULL;
98 //int acpi_irq_model = ACPI_IRQ_MODEL_PIC;
99 int acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
101 * Let the system know what interrupt model we are using by
102 * evaluating the \_PIC object, if exists.
105 switch (acpi_irq_model) {
106 case ACPI_IRQ_MODEL_PIC:
109 case ACPI_IRQ_MODEL_IOAPIC:
112 case ACPI_IRQ_MODEL_IOSAPIC:
115 case ACPI_IRQ_MODEL_PLATFORM:
116 message = "platform specific model";
119 d_printf(DBG_ERR, "ERROR: Unknown interrupt routing model\n");
123 d_printf(DBG_INFO, "Using %s for interrupt routing\n", message);
125 arg.Integer.Value = acpi_irq_model;
127 status = AcpiEvaluateObject(NULL, (char*)"\\_PIC", &arg_list, NULL);
128 if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
129 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
139 Hw::Device *last_device;
140 Hw::Device *current_bus;
144 static unsigned acpi_adr_t_to_f(unsigned art)
148 case ACPI_MEMORY_RANGE: return Resource::Mmio_res;
149 case ACPI_IO_RANGE: return Resource::Io_res;
150 case ACPI_BUS_NUMBER_RANGE: return Resource::Bus_res;
156 acpi_adr_res(l4_uint32_t id, Hw::Device *host, ACPI_RESOURCE_ADDRESS const *ar,
157 l4_uint64_t s, l4_uint64_t l, bool qw)
159 unsigned flags = acpi_adr_t_to_f(ar->ResourceType);
165 flags |= Resource::F_width_64bit;
168 if (ar->ProducerConsumer == ACPI_PRODUCER)
169 r = new Resource_provider(flags, s, s + l - 1);
171 r = new Resource(flags, s, s + l -1);
174 host->add_resource_rq(r);
178 discover_pre_cb(ACPI_HANDLE obj, UINT32 nl, void *ctxt, void **)
180 Discover_ctxt *c = reinterpret_cast<Discover_ctxt*>(ctxt);
184 c->current_bus = c->last_device;
191 ACPI_NAMESPACE_NODE *node = AcpiNsValidateHandle(obj);
194 //AcpiUtReleaseMutex(ACPI_MTX_NAMESPACE);
198 Acpi_ptr<ACPI_DEVICE_INFO> info;
199 if (!ACPI_SUCCESS(AcpiGetObjectInfo(node, info.ref())))
202 if (info->Type != ACPI_TYPE_DEVICE && info->Type != ACPI_TYPE_PROCESSOR)
205 l4_uint32_t adr = ~0U;
208 if (info->Valid & ACPI_VALID_ADR)
211 nd = c->current_bus->get_child_dev_adr(adr, true);
214 nd = c->current_bus->get_child_dev_uid((l4_umword_t)obj, adr, true);
219 l4_uint32_t nv = info->Name;
221 for (unsigned i = 0; i < 4; ++i)
230 if (info->Valid & ACPI_VALID_HID)
231 nd->set_hid(info->HardwareId.String);
233 if (info->Valid & ACPI_VALID_CID)
234 for (unsigned i = 0; i < info->CompatibleIdList.Count; ++i)
235 nd->add_cid(info->CompatibleIdList.Ids[i].String);
237 Hw::Acpi_device_driver *drv = 0;
238 if (info->Valid & ACPI_VALID_HID)
239 drv = Hw::Acpi_device_driver::find(info->HardwareId.String);
241 if (!drv && (info->Valid & ACPI_VALID_CID))
242 for (unsigned i = 0; i < info->CompatibleIdList.Count; ++i)
243 if ((drv = Hw::Acpi_device_driver::find(info->CompatibleIdList.Ids[i].String)))
247 drv = acpi_default_driver();
250 drv->probe(nd, obj, info.get());
256 discover_post_cb(ACPI_HANDLE, UINT32 nl, void *ctxt, void **)
258 Discover_ctxt *c = reinterpret_cast<Discover_ctxt*>(ctxt);
262 c->last_device = c->current_bus;
263 c->current_bus = c->current_bus->parent();
265 c->current_bus = system_bus();
271 static int acpi_enter_sleep(int sleepstate = 3 /* s3 */)
273 // Disable the system control interrupt (SCI) (in line with ACPI spec).
274 // Clear all pending SCIs because otherwise they would trigger after resume.
275 // Background: The SCI is level triggered. Fiasco receives the IRQ, counts it
276 // internally and masks it. As the IRQ count is in software, it survives
277 // suspend to RAM (in contrast, hardware interrupts -- like all hardware
278 // system state except RAM contents are lost on suspend). Thus, when we later
279 // re-enable the SCI, a stored IRQ would immediately be delivered to IO.
283 L4::Cap<L4::Platform_control> pf = L4Re::Env::env()->get_cap<L4::Platform_control>("icu");
286 d_printf(DBG_ERR, "error: no platform control capability found\n");
290 l4_uint8_t sleeptypea, sleeptypeb;
292 ACPI_STATUS status = AcpiGetSleepTypeData(sleepstate, &sleeptypea, &sleeptypeb);
293 if (ACPI_FAILURE(status))
295 d_printf(DBG_ERR, "error: cannot determining ACPI sleep type\n");
299 status = AcpiEnterSleepStatePrep(sleepstate);
300 if (ACPI_FAILURE(status))
302 d_printf(DBG_WARN, "warning: AcpiEnterSleepStatePrep failed, ignoring\n");
303 //ignore... this WILL throw errors on T41p
306 /* Clear wake status */
307 status = AcpiWriteBitRegister(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
308 if (ACPI_FAILURE(status))
309 d_printf(DBG_WARN, "warning: cannot clear wake status\n");
311 /* Clear all fixed and general purpose status bits */
312 status = AcpiHwClearAcpiStatus();
313 if (ACPI_FAILURE(status))
314 d_printf(DBG_WARN, "warning: cannot clear all fixed and GPE status bits.\n");
317 * 1) Disable/Clear all GPEs
318 * 2) Enable all wakeup GPEs
320 status = AcpiDisableAllGpes();
321 if (ACPI_FAILURE(status))
322 d_printf(DBG_WARN, "warning: disabling all GPEs.\n");
324 AcpiGbl_SystemAwakeAndRunning = FALSE;
326 status = AcpiHwEnableAllWakeupGpes();
327 if (ACPI_FAILURE(status))
328 d_printf(DBG_WARN, "waring: cannot enable all wakeup GPEs\n");
330 d_printf(DBG_DEBUG2, "call platform control object for suspend\n");
332 if ((err = l4_error(pf->system_suspend(sleeptypea | ((unsigned)sleeptypeb << 8)))) < 0)
333 d_printf(DBG_ERR, "error: suspend failed: %d\n", err);
335 d_printf(DBG_DEBUG2, "resume: wakeup from suspend\n");
337 // out of spec, but required on buggy systems
338 AcpiWriteBitRegister(ACPI_BITREG_SCI_ENABLE, 1);
340 AcpiLeaveSleepStatePrep(sleepstate);
342 ACPI_EVENT_STATUS pwr_btn_s;
344 AcpiGetEventStatus(ACPI_EVENT_POWER_BUTTON, &pwr_btn_s);
346 if (pwr_btn_s & ACPI_EVENT_FLAG_SET)
348 AcpiClearEvent(ACPI_EVENT_POWER_BUTTON);
349 /* FIXME: remember for later */
352 status = AcpiDisableAllGpes();
353 if (ACPI_FAILURE(status))
354 d_printf(DBG_WARN, "warning: disabling all GPEs.\n");
356 status = AcpiLeaveSleepState(sleepstate);
357 if (ACPI_FAILURE(status))
358 d_printf(DBG_WARN, "warning: AcpiLeaveSleepState failed\n");
360 status = AcpiEnableAllRuntimeGpes();
361 if (ACPI_FAILURE(status))
362 d_printf(DBG_WARN, "warning: cannot enable all wakeup GPEs\n");
364 // re-enable system control interrupt (SCI)
370 acpi_fixed_device_event_handler(void *context)
372 Hw::Device *dev = static_cast<Hw::Device*>(context);
373 // generate an artificial device notification with value 0x80
374 dev->notify(Hw::Acpi_dev::Acpi_event, 0x80, 1);
375 trace_event(TRACE_ACPI_EVENT, "Acpi fixed event. Device '%s'.\n",
381 * \brief Determine name of given ACPI handle.
383 * \param handle The ACPI handle of be queried.
384 * \retval name Name of the ACPI object.
386 static void acpi_get_name(ACPI_HANDLE handle, char name[5])
388 Acpi_ptr<ACPI_DEVICE_INFO> info;
391 status = AcpiGetObjectInfo(handle, info.ref());
392 if (ACPI_FAILURE(status))
393 strncpy(name, "NONE", 4);
396 l4_uint32_t nv = info->Name;
397 for (unsigned i = 0; i < 4; ++i)
407 * \brief Trace all ACPI events.
409 * Global ACPI event handler. This is only called if ACPI event tracing is
413 acpi_trace_events(UINT32 type, ACPI_HANDLE handle, UINT32 event, void *)
416 acpi_get_name(handle, name);
417 d_printf(DBG_INFO, "ACPI Event. Device %s. Type %s. Number 0x%x.\n",
418 name, type == ACPI_EVENT_TYPE_GPE ? "GPE" : "FIXED", event);
422 * \brief Trace all ACPI notifications.
424 * Global ACPI notification handler. This is only called if ACPI event tracing
428 acpi_trace_notifications(ACPI_HANDLE handle, UINT32 event, void *)
431 acpi_get_name(handle, name);
432 d_printf(DBG_INFO, "ACPI Notification. Device %s. Event '0x%x'.\n",
436 struct Acpi_pm : Hw::Root_bus::Pm
441 if ((res = acpi_enter_sleep()) < 0)
442 d_printf(DBG_ERR, "error: suspend failed: %d\n", res);
450 if ((res = acpi_enter_sleep(5)) < 0)
451 d_printf(DBG_ERR, "error: shutdown failed: %d\n", res);
458 ACPI_STATUS status = AcpiReset();
459 if (status == AE_NOT_EXIST)
467 static Acpi_pm _acpi_pm;
469 static Hw::Device *find_dev(char const *hid)
471 for (auto i = Hw::Device::iterator(0, system_bus(), L4VBUS_MAX_DEPTH); i != Hw::Device::iterator(); ++i)
472 if ((*i)->match_cid(hid))
479 acpi_install_fixed_button_handler(char const *hid, UINT32 event, char const *name)
481 Hw::Device *button = find_dev(hid);
484 d_printf(DBG_INFO, "ACPI: %s button not found, create an artificial one\n", name);
485 button = new Hw::Device();
486 button->set_hid(hid);
487 system_bus()->add_child(button);
490 d_printf(DBG_INFO, "ACPI: %s button is a fixed event on this system\n", name);
491 ACPI_STATUS s = AcpiInstallFixedEventHandler(event,
492 acpi_fixed_device_event_handler, button);
494 d_printf(DBG_ERR, "ACPI: could not register power-button handler: %s\n",
495 AcpiFormatException(s));
496 else if (ACPI_FAILURE(s = AcpiEnableEvent(event, 0)))
497 d_printf(DBG_ERR, "ACPI: could not enable power-button event: %s\n",
498 AcpiFormatException(s));
506 d_printf(DBG_INFO, "Hello from L4-ACPICA\n");
508 Hw::Pci::register_root_bridge(0, new Hw::Pci::Port_root_bridge(0, 0));
510 AcpiDbgLevel = acpi_get_debug_level();
512 //0. enable workarounds, see include/acglobals.h
513 AcpiGbl_EnableInterpreterSlack = (1==1);
516 status = AcpiInitializeSubsystem();
520 status = AcpiInitializeTables(0, 0, TRUE);
524 status = AcpiReallocateRootTable();
528 status = AcpiLoadTables();
530 if(ACPI_FAILURE(status))
533 d_printf(DBG_DEBUG, "enable ACPI subsystem\n");
534 status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION);
536 if (ACPI_FAILURE(status))
538 d_printf(DBG_ERR, "Unable to start the ACPI Interpreter\n");
544 d_printf(DBG_DEBUG, "initialize ACPI objects\n");
545 status = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION);
546 if (ACPI_FAILURE(status)) {
547 d_printf(DBG_ERR, "Unable to initialize ACPI objects\n");
551 d_printf(DBG_DEBUG, "Interpreter enabled\n");
554 * Get the system interrupt model and evaluate \_PIC.
556 int result = acpi_bus_init_irq();
559 d_printf(DBG_ERR, "Could not initialize ACPI IRQ stuff\n");
564 c.last_device = system_bus();
565 c.current_bus = system_bus();
568 status = AcpiWalkNamespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
570 discover_pre_cb, discover_post_cb, &c, 0);
572 status = AcpiSubsystemStatus();
574 if (ACPI_FAILURE(status))
577 d_printf(DBG_INFO, "ACPI subsystem initialized\n");
580 Acpi_auto_buffer ret_buffer;
581 ret_buffer.Length = ACPI_ALLOCATE_BUFFER;
583 status = AcpiGetSystemInfo(&ret_buffer);
585 if(ACPI_FAILURE(status))
588 acpi_print_system_info(ret_buffer.Pointer);
591 if ((AcpiGbl_FADT.Flags & ACPI_FADT_POWER_BUTTON) == 0)
592 acpi_install_fixed_button_handler("PNP0C0C", ACPI_EVENT_POWER_BUTTON, "power");
594 if ((AcpiGbl_FADT.Flags & ACPI_FADT_SLEEP_BUTTON) == 0)
595 acpi_install_fixed_button_handler("PNP0C0E", ACPI_EVENT_SLEEP_BUTTON, "sleep");
597 if (trace_event_enabled(TRACE_ACPI_EVENT))
599 status = AcpiInstallGlobalEventHandler(acpi_trace_events, 0);
600 if (ACPI_FAILURE(status))
602 "error: could not install global event handler.\n");
604 status = AcpiInstallNotifyHandler(ACPI_ROOT_OBJECT, ACPI_ALL_NOTIFY,
605 acpi_trace_notifications, 0);
606 if (ACPI_FAILURE(status))
608 "error: could not install global device notification handler.\n");
611 status = AcpiUpdateAllGpes();
612 if(ACPI_FAILURE(status))
614 d_printf(DBG_ERR, "Could not update all GPEs\n");
618 status = AcpiEnableAllRuntimeGpes();
619 if(ACPI_FAILURE(status))
621 d_printf(DBG_ERR, "Could not enable all GPEs\n");
625 dynamic_cast<Hw::Root_bus*>(system_bus())->set_pm(&_acpi_pm);
636 typedef std::map<l4_uint64_t, Acpi_device_driver *> Drv_list;
638 static Drv_list &drv_list()
644 static l4_uint64_t acpi_get_key(char const *hid)
647 for (unsigned i = 0; i < 8 && hid[i]; ++i)
648 k = (k << 8) | hid[i];
652 static Resource *res(l4_uint32_t id, unsigned long flags, l4_uint64_t start,
655 Resource *r = new Resource(flags, start, end);
662 void register_sci(Io_irq_pin *sci)
669 Acpi_dev::discover_crs(Hw::Device *host)
671 Acpi_auto_buffer buf;
672 buf.Length = ACPI_ALLOCATE_BUFFER;
674 if (ACPI_FAILURE(AcpiGetCurrentResources(this->handle(), &buf)))
677 char const *p = (char const *)buf.Pointer;
678 l4_uint32_t res_id = 0x00504341; // ACPx
681 ACPI_RESOURCE const *r = (ACPI_RESOURCE const *)p;
682 ACPI_RESOURCE_DATA const *d = &r->Data;
687 case ACPI_RESOURCE_TYPE_END_TAG:
690 case ACPI_RESOURCE_TYPE_IRQ:
691 flags = Resource::Irq_res | Resource::Irq_type_base;
692 flags |= (!d->Irq.Triggering) * Resource::Irq_type_base * L4_IRQ_F_LEVEL;
693 flags |= (!!d->Irq.Polarity) * Resource::Irq_type_base * L4_IRQ_F_NEG;
694 for (unsigned c = 0; c < d->Irq.InterruptCount; ++c)
695 host->add_resource_rq(res(res_id++, flags, d->Irq.Interrupts[c],
696 d->Irq.Interrupts[c]));
699 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
700 flags = Resource::Irq_res | Resource::Irq_type_base;
701 flags |= (!d->ExtendedIrq.Triggering) * Resource::Irq_type_base * L4_IRQ_F_LEVEL;
702 flags |= (!!d->ExtendedIrq.Polarity) * Resource::Irq_type_base * L4_IRQ_F_NEG;
703 if (d->ExtendedIrq.ResourceSource.StringPtr)
705 d_printf(DBG_DEBUG2, "hoo indirect IRQ resource found src=%s idx=%d\n",
706 d->ExtendedIrq.ResourceSource.StringPtr,
707 d->ExtendedIrq.ResourceSource.Index);
711 for (unsigned c = 0; c < d->ExtendedIrq.InterruptCount; ++c)
712 host->add_resource_rq(res(res_id++, flags, d->ExtendedIrq.Interrupts[c],
713 d->ExtendedIrq.Interrupts[c]));
717 case ACPI_RESOURCE_TYPE_IO:
718 flags = Resource::Io_res;
719 host->add_resource_rq(res(res_id++, flags, d->Io.Minimum,
720 d->Io.Minimum + d->Io.AddressLength - 1));
723 case ACPI_RESOURCE_TYPE_FIXED_IO:
724 flags = Resource::Io_res;
725 host->add_resource_rq(res(res_id++, flags, d->FixedIo.Address,
726 d->FixedIo.Address + d->FixedIo.AddressLength - 1));
729 case ACPI_RESOURCE_TYPE_MEMORY24:
730 flags = Resource::Mmio_res;
731 host->add_resource_rq(res(res_id++, flags, d->Memory24.Minimum,
732 d->Memory24.Minimum + d->Memory24.AddressLength - 1));
735 case ACPI_RESOURCE_TYPE_MEMORY32:
736 flags = Resource::Mmio_res;
737 host->add_resource_rq(res(res_id++, flags, d->Memory32.Minimum,
738 d->Memory32.Minimum + d->Memory32.AddressLength - 1));
741 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
742 flags = Resource::Mmio_res;
743 host->add_resource_rq(res(res_id++, flags, d->FixedMemory32.Address,
744 d->FixedMemory32.Address + d->FixedMemory32.AddressLength - 1));
747 case ACPI_RESOURCE_TYPE_ADDRESS16:
748 acpi_adr_res(res_id++, host, &d->Address, d->Address16.Minimum, d->Address16.AddressLength, 0);
751 case ACPI_RESOURCE_TYPE_ADDRESS32:
752 acpi_adr_res(res_id++, host, &d->Address, d->Address32.Minimum, d->Address32.AddressLength, 0);
755 case ACPI_RESOURCE_TYPE_ADDRESS64:
756 acpi_adr_res(res_id++, host, &d->Address, d->Address64.Minimum, d->Address64.AddressLength, 1);
760 d_printf(DBG_WARN, "WARNING: ignoring ACPI resource (unknown type: %d)\n", r->Type);
770 static void acpi_dev_notification_handler(ACPI_HANDLE, UINT32 event, void *ctxt)
772 Hw::Device *device = static_cast<Hw::Device*>(ctxt);
773 trace_event(TRACE_ACPI_EVENT, "ACPI device notification. Device = %s, Event = 0x%x\n",
774 device->name(), event);
775 device->notify(Acpi_dev::Acpi_event, event, 1);
779 Acpi_dev::enable_notifications(Hw::Device *host)
781 if (_have_notification_handler)
784 ACPI_STATUS s = AcpiInstallNotifyHandler(handle(), ACPI_ALL_NOTIFY, acpi_dev_notification_handler, host);
787 _have_notification_handler = true;
789 d_printf(DBG_ERR, "error: cannot install notification handler for ACPI device: %s\n",
790 AcpiFormatException(s));
794 Acpi_dev::disable_notifications(Hw::Device *)
796 if (!_have_notification_handler)
799 ACPI_STATUS s = AcpiRemoveNotifyHandler(handle(), ACPI_ALL_NOTIFY, acpi_dev_notification_handler);
801 d_printf(DBG_ERR, "error: cannot remove notification handler for ACPI device: %s\n",
802 AcpiFormatException(s));
804 _have_notification_handler = false;
808 Acpi_device_driver::register_driver(char const *hid, Acpi_device_driver *driver)
810 drv_list()[acpi_get_key(hid)] = driver;
815 Acpi_device_driver::find(char const *hid)
817 Drv_list const &l = drv_list();
818 Drv_list::const_iterator r = l.find(acpi_get_key(hid));
825 Acpi_device_driver::probe(Hw::Device *device, ACPI_HANDLE acpi_hdl,
826 ACPI_DEVICE_INFO const *)
828 Acpi_dev *adev = new Acpi_dev(acpi_hdl);
829 adev->discover_crs(device);
830 device->add_feature(adev);