NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/41112: No ACPI events on HP NC4400



The following reply was made to PR kern/41112; it has been noted by GNATS.

From: Jukka Ruohonen <jruohonen%iki.fi@localhost>
To: gnats-bugs%NetBSD.org@localhost
Cc: 
Subject: Re: kern/41112: No ACPI events on HP NC4400
Date: Wed, 1 Apr 2009 13:10:37 +0300

 > >Fix:
 >      Solved; see below.
 > 
 
 I was able to fix this on my own. However, the proposed solution is somewhat
 major so I hope someone with more knowledge will look into this.
 
 It seems that the ACPI _GPE-handler ends up in an infinite loop on some
 laptops. The current NetBSD implementation has only one thread scheduling
 all ACPI notify events. Possibly because the state of some variables is
 changed during evaluation, the sysmon-queue gets polluted by repeated notify
 requests. The impact is quite critical: due deadlock, no notify events will
 get through, causing the _GPE-handler to block. This in turn will eventually
 lead to overheating and excessive memory usage.
 
 This behavior is documented to affect several HP laptops.[1] I think FreeBSD
 tried to solve similar issue in their 'OsdSchedule.c' by having equal
 priorities for OSL_GPE_HANDLER and OSL_NOTIFY_HANDLER. However, this did not
 solve the issue for me. It really seems that there needs to be another
 thread handling the notify events.
 
 Thus, as a quick "hack", I duplicated the functions in 'sysmon_taskq.c' as
 'sysmon_notify_*()' and enabled a separate "sysmon notify queue" in
 'init_main.c'. The included diff will give some idea on how these two
 separate threads could be possibly scheduled. (As said, this was not really
 a serious attempt.)
 
 [1] http://bugzilla.kernel.org/show_bug.cgi?id=5534
 
 * * *
 
 --- OsdSchedule.c.~1.10.~      2009-04-01 12:05:46.000000000 +0300
 +++ OsdSchedule.c      2009-04-01 12:31:22.000000000 +0300
 @@ -58,6 +58,10 @@
  
  #include <dev/sysmon/sysmon_taskq.h>
  
 +#ifdef SYSMON_NOTIFYQ
 +#include <dev/sysmon/sysmon_notifyq.h>
 +#endif
 +
  extern int acpi_suspended;
  
  #define       _COMPONENT      ACPI_OS_SERVICES
 @@ -78,6 +82,11 @@
        ACPI_FUNCTION_TRACE(__func__);
  
        sysmon_task_queue_init();
 +
 +#ifdef SYSMON_NOTIFYQ
 +      sysmon_notify_queue_init();
 +#endif
 +
        mutex_init(&acpi_osd_sleep_mtx, MUTEX_DEFAULT, IPL_NONE);
        cv_init(&acpi_osd_sleep_cv, "acpislp");
  
 @@ -97,6 +106,10 @@
  
        sysmon_task_queue_fini();
  
 +#ifdef SYSMON_NOTIFYQ
 +      sysmon_notify_queue_fini();
 +#endif
 +
        return_VOID;
  }
  
 @@ -120,10 +133,13 @@
  AcpiOsExecute(ACPI_EXECUTE_TYPE Type, ACPI_OSD_EXEC_CALLBACK Function,
      void *Context)
  {
 -      int pri;
 +      int pri, rv;
 +      bool notify;
  
        ACPI_FUNCTION_TRACE(__func__);
  
 +      notify = false;
 +
        switch (Type) {
        case OSL_GPE_HANDLER:
                pri = 10;
 @@ -134,6 +150,7 @@
                pri = 5;
                break;
        case OSL_NOTIFY_HANDLER:
 +              notify = true;
                pri = 3;
                break;
        case OSL_DEBUGGER_THREAD:
 @@ -143,7 +160,17 @@
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
  
 -      switch (sysmon_task_queue_sched(pri, Function, Context)) {
 +#ifndef SYSMON_NOTIFYQ
 +      rv = sysmon_task_queue_sched(pri, Function, Context);
 +#else
 +      rv = (notify != false) ?
 +          sysmon_notify_queue_sched(pri, Function, Context) :
 +          sysmon_task_queue_sched(pri, Function, Context);
 +#endif
 +
 +
 +      switch (rv) {
 +
        case 0:
                return_ACPI_STATUS(AE_OK);
  
  
 


Home | Main Index | Thread Index | Old Index