diff mbox

[v3] ACPI / PM: Fix incorrect wakeup irq setting before suspend-to-idle

Message ID 1444378813-17857-1-git-send-email-yu.c.chen@intel.com (mailing list archive)
State Changes Requested, archived
Headers show

Commit Message

Chen Yu Oct. 9, 2015, 8:20 a.m. UTC
For ACPI compatible system, SCI(ACPI System Control
Interrupt) is used to wake system up from suspend-to-idle.
Once CPU is woken up by SCI, interrupt handler will
firstly checks if current interrupt is legal to wake up
the whole system, thus irq_pm_check_wakeup is invoked
to validate the irq number. However, before suspend-to-idle,
acpi_gbl_FADT.sci_interrupt is marked rather than actual
irq number in acpi_freeze_prepare, this might lead to unable
to wake up the system.

This patch fixes this problem by marking the irq number
return by acpi_gsi_to_irq as IRQD_WAKEUP_STATE, rather than
marking the acpi_gbl_FADT.sci_interrupt. Meanwhile this patch
fixes the same problems inside acpi_os_remove_interrupt_handler
and acpi_os_wait_events_complete respectively.

Signed-off-by: Chen Yu <yu.c.chen@intel.com>
---
v3:
 - 1.Rename acpi_inuse_irq to acpi_sci_irq for better understanding.
   2.If the irq handler is not registered, skip the synchronize_hardirq
     in acpi_os_wait_events_complete and return immediately in
     acpi_os_remove_interrupt_handler.
   3.For acpi_freeze_prepare and acpi_freeze_restore, if the acpi irq
     handler is not properly registered, we do not leverage acpi irq
     to wake up the system, but expect other peripherals(such as PCI devices
     and USB devices)to invoke enable_irq_wake for us.
v2:
 - 1.Define a global acpi_inuse_irq variable, store irq in it
     and access it directly from acpi_freeze_prepare(), and it
     doesn't have to depend on CONFIG_SUSPEND as it is just the
     IRQ number actually used by ACPI.
   2.Also fix the same problems inside acpi_os_remove_interrupt_handler,
     acpi_os_wait_events_complete.
---
 drivers/acpi/osl.c   | 12 ++++++++----
 drivers/acpi/sleep.c |  6 ++++--
 include/linux/acpi.h |  3 +++
 3 files changed, 15 insertions(+), 6 deletions(-)

Comments

Lv Zheng Oct. 9, 2015, 8:32 a.m. UTC | #1
Hi, Yu

> From: Chen, Yu C
> Sent: Friday, October 09, 2015 4:20 PM
> 
> For ACPI compatible system, SCI(ACPI System Control
> Interrupt) is used to wake system up from suspend-to-idle.
> Once CPU is woken up by SCI, interrupt handler will
> firstly checks if current interrupt is legal to wake up
> the whole system, thus irq_pm_check_wakeup is invoked
> to validate the irq number. However, before suspend-to-idle,
> acpi_gbl_FADT.sci_interrupt is marked rather than actual
> irq number in acpi_freeze_prepare, this might lead to unable
> to wake up the system.
> 
> This patch fixes this problem by marking the irq number
> return by acpi_gsi_to_irq as IRQD_WAKEUP_STATE, rather than
> marking the acpi_gbl_FADT.sci_interrupt. Meanwhile this patch
> fixes the same problems inside acpi_os_remove_interrupt_handler
> and acpi_os_wait_events_complete respectively.
> 
> Signed-off-by: Chen Yu <yu.c.chen@intel.com>
> ---
> v3:
>  - 1.Rename acpi_inuse_irq to acpi_sci_irq for better understanding.
>    2.If the irq handler is not registered, skip the synchronize_hardirq
>      in acpi_os_wait_events_complete and return immediately in
>      acpi_os_remove_interrupt_handler.
>    3.For acpi_freeze_prepare and acpi_freeze_restore, if the acpi irq
>      handler is not properly registered, we do not leverage acpi irq
>      to wake up the system, but expect other peripherals(such as PCI devices
>      and USB devices)to invoke enable_irq_wake for us.
> v2:
>  - 1.Define a global acpi_inuse_irq variable, store irq in it
>      and access it directly from acpi_freeze_prepare(), and it
>      doesn't have to depend on CONFIG_SUSPEND as it is just the
>      IRQ number actually used by ACPI.
>    2.Also fix the same problems inside acpi_os_remove_interrupt_handler,
>      acpi_os_wait_events_complete.
> ---
>  drivers/acpi/osl.c   | 12 ++++++++----
>  drivers/acpi/sleep.c |  6 ++++--
>  include/linux/acpi.h |  3 +++
>  3 files changed, 15 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
> index 739a4a6..8e1a5d3 100644
> --- a/drivers/acpi/osl.c
> +++ b/drivers/acpi/osl.c
> @@ -81,6 +81,7 @@ static struct workqueue_struct *kacpid_wq;
>  static struct workqueue_struct *kacpi_notify_wq;
>  static struct workqueue_struct *kacpi_hotplug_wq;
>  static bool acpi_os_initialized;
> +unsigned int acpi_sci_irq = INVALID_ACPI_IRQ;
> 
>  /*
>   * This list of permanent mappings is for memory that may be accessed from
> @@ -856,17 +857,20 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
>  		acpi_irq_handler = NULL;
>  		return AE_NOT_ACQUIRED;
>  	}
> +	acpi_sci_irq = irq;
> 
>  	return AE_OK;
>  }
> 
>  acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler)

Why don't you rename irq here to gsi to improve the readability?
The false naming and the wrong example written for this function are probably the root causes of all other bad code.
So if we want to stop people making future mistakes, we need to cleanup ourselves.

Thanks and best regards
-Lv

>  {
> -	if (irq != acpi_gbl_FADT.sci_interrupt)
> +	if ((irq != acpi_gbl_FADT.sci_interrupt) ||
> +			IS_INVALID_ACPI_IRQ(acpi_sci_irq))
>  		return AE_BAD_PARAMETER;
> 
> -	free_irq(irq, acpi_irq);
> +	free_irq(acpi_sci_irq, acpi_irq);
>  	acpi_irq_handler = NULL;
> +	acpi_sci_irq = INVALID_ACPI_IRQ;
> 
>  	return AE_OK;
>  }
> @@ -1180,8 +1184,8 @@ void acpi_os_wait_events_complete(void)
>  	 * Make sure the GPE handler or the fixed event handler is not used
>  	 * on another CPU after removal.
>  	 */
> -	if (acpi_irq_handler)
> -		synchronize_hardirq(acpi_gbl_FADT.sci_interrupt);
> +	if (!IS_INVALID_ACPI_IRQ(acpi_sci_irq))
> +		synchronize_hardirq(acpi_sci_irq);
>  	flush_workqueue(kacpid_wq);
>  	flush_workqueue(kacpi_notify_wq);
>  }
> diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
> index 2f0d4db..1704595 100644
> --- a/drivers/acpi/sleep.c
> +++ b/drivers/acpi/sleep.c
> @@ -632,14 +632,16 @@ static int acpi_freeze_prepare(void)
>  	acpi_enable_wakeup_devices(ACPI_STATE_S0);
>  	acpi_enable_all_wakeup_gpes();
>  	acpi_os_wait_events_complete();
> -	enable_irq_wake(acpi_gbl_FADT.sci_interrupt);
> +	if (!IS_INVALID_ACPI_IRQ(acpi_sci_irq))
> +		enable_irq_wake(acpi_sci_irq);
>  	return 0;
>  }
> 
>  static void acpi_freeze_restore(void)
>  {
>  	acpi_disable_wakeup_devices(ACPI_STATE_S0);
> -	disable_irq_wake(acpi_gbl_FADT.sci_interrupt);
> +	if (!IS_INVALID_ACPI_IRQ(acpi_sci_irq))
> +		disable_irq_wake(acpi_sci_irq);
>  	acpi_enable_all_runtime_gpes();
>  }
> 
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index 43856d1..2f05dc0 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -193,6 +193,9 @@ int acpi_ioapic_registered(acpi_handle handle, u32 gsi_base);
>  void acpi_irq_stats_init(void);
>  extern u32 acpi_irq_handled;
>  extern u32 acpi_irq_not_handled;
> +extern unsigned int acpi_sci_irq;
> +#define INVALID_ACPI_IRQ  ((unsigned)-1)
> +#define IS_INVALID_ACPI_IRQ(x) unlikely((x) == INVALID_ACPI_IRQ)
> 
>  extern int sbf_port;
>  extern unsigned long acpi_realmode_flags;
> --
> 1.8.4.2

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Chen Yu Oct. 9, 2015, 9:50 a.m. UTC | #2
Hi, LV

> -----Original Message-----
> From: Zheng, Lv
> Sent: Friday, October 09, 2015 4:33 PM
> To: Chen, Yu C; rjw@rjwysocki.net; lenb@kernel.org
> Cc: linux-pm@vger.kernel.org; linux-acpi@vger.kernel.org; linux-
> kernel@vger.kernel.org; Zhang, Rui
> Subject: RE: [PATCH][v3] ACPI / PM: Fix incorrect wakeup irq setting before
> suspend-to-idle
> 
> Hi, Yu
> 
> > From: Chen, Yu C
> > Sent: Friday, October 09, 2015 4:20 PM
> >
> >
> >  acpi_status acpi_os_remove_interrupt_handler(u32 irq,
> > acpi_osd_handler handler)
> 
> Why don't you rename irq here to gsi to improve the readability?
> The false naming and the wrong example written for this function are
> probably the root causes of all other bad code.
> So if we want to stop people making future mistakes, we need to cleanup
> ourselves.
> 
OK, will rewrite in next version.

> Thanks and best regards
> -Lv
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lv Zheng Oct. 10, 2015, 2:28 a.m. UTC | #3
Hi,

> From: Chen, Yu C
> Sent: Friday, October 09, 2015 5:50 PM
> 
> Hi, LV
> 
> > From: Zheng, Lv
> > Sent: Friday, October 09, 2015 4:33 PM
> >
> > Hi, Yu
> >
> > > From: Chen, Yu C
> > > Sent: Friday, October 09, 2015 4:20 PM
> > >
> > >
> > >  acpi_status acpi_os_remove_interrupt_handler(u32 irq,
> > > acpi_osd_handler handler)
> >
> > Why don't you rename irq here to gsi to improve the readability?
> > The false naming and the wrong example written for this function are
> > probably the root causes of all other bad code.
> > So if we want to stop people making future mistakes, we need to cleanup
> > ourselves.
> >
> OK, will rewrite in next version.

You can add Acked-by: Lv Zheng <lv.zheng@intel.com>
And don't forget to mark it as a stable material.

One more question is:
Do you want the modules to use "acpi_sci_irq"?
If the answer is no, then please ignore this question.

Thanks and best regards
-Lv 


> 
> > Thanks and best regards
> > -Lv
> >

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki Oct. 12, 2015, 8:20 p.m. UTC | #4
On Friday, October 09, 2015 09:50:21 AM Chen, Yu C wrote:
> Hi, LV
> 
> > -----Original Message-----
> > From: Zheng, Lv
> > Sent: Friday, October 09, 2015 4:33 PM
> > To: Chen, Yu C; rjw@rjwysocki.net; lenb@kernel.org
> > Cc: linux-pm@vger.kernel.org; linux-acpi@vger.kernel.org; linux-
> > kernel@vger.kernel.org; Zhang, Rui
> > Subject: RE: [PATCH][v3] ACPI / PM: Fix incorrect wakeup irq setting before
> > suspend-to-idle
> > 
> > Hi, Yu
> > 
> > > From: Chen, Yu C
> > > Sent: Friday, October 09, 2015 4:20 PM
> > >
> > >
> > >  acpi_status acpi_os_remove_interrupt_handler(u32 irq,
> > > acpi_osd_handler handler)
> > 
> > Why don't you rename irq here to gsi to improve the readability?
> > The false naming and the wrong example written for this function are
> > probably the root causes of all other bad code.
> > So if we want to stop people making future mistakes, we need to cleanup
> > ourselves.
> > 
> OK, will rewrite in next version.

It would be good to change the subject of the patch too I think, because it is
not about wakeup IRQs only any more.

Thanks,
Rafael

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Chen Yu Oct. 14, 2015, 5:44 p.m. UTC | #5
Hi ,Rafael,

> -----Original Message-----

> From: Rafael J. Wysocki [mailto:rjw@rjwysocki.net]

> Sent: Tuesday, October 13, 2015 4:20 AM

> To: Chen, Yu C

> Cc: Zheng, Lv; linux-pm@vger.kernel.org; linux-acpi@vger.kernel.org; linux-

> kernel@vger.kernel.org; Zhang, Rui; Wysocki, Rafael J; Brown, Len

> Subject: Re: [PATCH][v3] ACPI / PM: Fix incorrect wakeup irq setting before

> suspend-to-idle

> 

> On Friday, October 09, 2015 09:50:21 AM Chen, Yu C wrote:

> > Hi, LV

> >

> > > -----Original Message-----

> > > From: Zheng, Lv

> > > Sent: Friday, October 09, 2015 4:33 PM

> > > To: Chen, Yu C; rjw@rjwysocki.net; lenb@kernel.org

> > > Cc: linux-pm@vger.kernel.org; linux-acpi@vger.kernel.org; linux-

> > > kernel@vger.kernel.org; Zhang, Rui

> > > Subject: RE: [PATCH][v3] ACPI / PM: Fix incorrect wakeup irq setting

> > > before suspend-to-idle

> > >

> > > Hi, Yu

> > >

> > > > From: Chen, Yu C

> > > > Sent: Friday, October 09, 2015 4:20 PM

> > > >

> > > >

> > > >  acpi_status acpi_os_remove_interrupt_handler(u32 irq,

> > > > acpi_osd_handler handler)

> > >

> > > Why don't you rename irq here to gsi to improve the readability?

> > > The false naming and the wrong example written for this function are

> > > probably the root causes of all other bad code.

> > > So if we want to stop people making future mistakes, we need to

> > > cleanup ourselves.

> > >

> > OK, will rewrite in next version.

> 

> It would be good to change the subject of the patch too I think, because it is

> not about wakeup IRQs only any more.

> 

OK, will send another series of patches.

Best Regards,
Yu
diff mbox

Patch

diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 739a4a6..8e1a5d3 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -81,6 +81,7 @@  static struct workqueue_struct *kacpid_wq;
 static struct workqueue_struct *kacpi_notify_wq;
 static struct workqueue_struct *kacpi_hotplug_wq;
 static bool acpi_os_initialized;
+unsigned int acpi_sci_irq = INVALID_ACPI_IRQ;
 
 /*
  * This list of permanent mappings is for memory that may be accessed from
@@ -856,17 +857,20 @@  acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
 		acpi_irq_handler = NULL;
 		return AE_NOT_ACQUIRED;
 	}
+	acpi_sci_irq = irq;
 
 	return AE_OK;
 }
 
 acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler)
 {
-	if (irq != acpi_gbl_FADT.sci_interrupt)
+	if ((irq != acpi_gbl_FADT.sci_interrupt) ||
+			IS_INVALID_ACPI_IRQ(acpi_sci_irq))
 		return AE_BAD_PARAMETER;
 
-	free_irq(irq, acpi_irq);
+	free_irq(acpi_sci_irq, acpi_irq);
 	acpi_irq_handler = NULL;
+	acpi_sci_irq = INVALID_ACPI_IRQ;
 
 	return AE_OK;
 }
@@ -1180,8 +1184,8 @@  void acpi_os_wait_events_complete(void)
 	 * Make sure the GPE handler or the fixed event handler is not used
 	 * on another CPU after removal.
 	 */
-	if (acpi_irq_handler)
-		synchronize_hardirq(acpi_gbl_FADT.sci_interrupt);
+	if (!IS_INVALID_ACPI_IRQ(acpi_sci_irq))
+		synchronize_hardirq(acpi_sci_irq);
 	flush_workqueue(kacpid_wq);
 	flush_workqueue(kacpi_notify_wq);
 }
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 2f0d4db..1704595 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -632,14 +632,16 @@  static int acpi_freeze_prepare(void)
 	acpi_enable_wakeup_devices(ACPI_STATE_S0);
 	acpi_enable_all_wakeup_gpes();
 	acpi_os_wait_events_complete();
-	enable_irq_wake(acpi_gbl_FADT.sci_interrupt);
+	if (!IS_INVALID_ACPI_IRQ(acpi_sci_irq))
+		enable_irq_wake(acpi_sci_irq);
 	return 0;
 }
 
 static void acpi_freeze_restore(void)
 {
 	acpi_disable_wakeup_devices(ACPI_STATE_S0);
-	disable_irq_wake(acpi_gbl_FADT.sci_interrupt);
+	if (!IS_INVALID_ACPI_IRQ(acpi_sci_irq))
+		disable_irq_wake(acpi_sci_irq);
 	acpi_enable_all_runtime_gpes();
 }
 
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 43856d1..2f05dc0 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -193,6 +193,9 @@  int acpi_ioapic_registered(acpi_handle handle, u32 gsi_base);
 void acpi_irq_stats_init(void);
 extern u32 acpi_irq_handled;
 extern u32 acpi_irq_not_handled;
+extern unsigned int acpi_sci_irq;
+#define INVALID_ACPI_IRQ  ((unsigned)-1)
+#define IS_INVALID_ACPI_IRQ(x) unlikely((x) == INVALID_ACPI_IRQ)
 
 extern int sbf_port;
 extern unsigned long acpi_realmode_flags;