linux-acpi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
To: Lv Zheng <lv.zheng@intel.com>
Cc: "Rafael J . Wysocki" <rafael.j.wysocki@intel.com>,
	"Rafael J . Wysocki" <rjw@rjwysocki.net>,
	Len Brown <len.brown@intel.com>, Lv Zheng <zetalog@gmail.com>,
	linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org
Subject: Re: [RFC PATCH v6 5/5] ACPI: button: Add an optional workaround to fix a persistent close issue for old userspace
Date: Fri, 23 Jun 2017 16:03:47 +0200	[thread overview]
Message-ID: <20170623140347.GR26073@mail.corp.redhat.com> (raw)
In-Reply-To: <5a66477ba6096b51d1b012919c5f6fe4e8f0e6a4.1498034513.git.lv.zheng@intel.com>

On Jun 21 2017 or thereabouts, Lv Zheng wrote:
> From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> 
> Because of the variation of firmware implementation, there is a chance
> the LID state is unknown:
> 1. Some platforms send "open" ACPI notification to the OS and the event
>    arrive before the button driver is resumed;
> 2. Some platforms send "open" ACPI notification to the OS, but the
> event
>    arrives after the button driver is resumed, ex., Samsung N210+;
> 3. Some platforms never send an "open" ACPI notification to the OS, but
>    update the cached _LID return value to "open", and this update
> arrives
>    before the button driver is resumed;
> 4. Some platforms never send an "open" ACPI notification to the OS, but
>    update the cached _LID return value to "open", but this update
> arrives
>    after the button driver is resumed, ex., Surface Pro 3;
> 5. Some platforms never send an "open" ACPI notification to the OS, and
>    _LID ACPI method returns a value which stays to "close", ex.,
>    Surface Pro 1.
> Currently, all cases work find with systemd 233, but only case 1,2,3,4 work
> fine with old userspace.
> 
> After fixing all the other issues for old userspace programs, case 5 is the
> only case that the exported input node is still not fully compliant to
> SW_LID ABI and thus needs quirks or ABI changes.
> 
> This patch provides a dynamic SW_LID input node solution to make sure we do
> not export an input node with an unknown state to prevent suspend loops.
> 
> The database of unreliable devices is left to userspace to handle with a
> hwdb file and a udev rule.
> 
> Reworked by Lv to make this solution optional, code based on top of old
> "ignore" mode and make lid_reliable configurable to all lid devices to
> eliminate the difficulties of synchronously handling global lid_device.
> 

Well, you changed it enough to make it wrong now. See inlined:

> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> Signed-off-by: Lv Zheng <lv.zheng@intel.com>
> ---
>  drivers/acpi/button.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 88 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
> index 91c9989..f11045d 100644
> --- a/drivers/acpi/button.c
> +++ b/drivers/acpi/button.c
> @@ -107,11 +107,13 @@ struct acpi_button {
>  	unsigned int type;
>  	struct input_dev *input;
>  	struct timer_list lid_timer;
> +	bool lid_reliable;
>  	char phys[32];			/* for input device */
>  	unsigned long pushed;
>  	bool suspended;
>  };
>  
> +static DEFINE_MUTEX(lid_input_lock);
>  static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
>  static struct acpi_device *lid_device;
>  static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
> @@ -128,6 +130,10 @@ static unsigned long lid_update_interval __read_mostly = 1 * MSEC_PER_SEC;
>  module_param(lid_update_interval, ulong, 0644);
>  MODULE_PARM_DESC(lid_update_interval, "Interval (ms) between lid periodic updates");
>  
> +static bool lid_unreliable __read_mostly = false;
> +module_param(lid_unreliable, bool, 0644);
> +MODULE_PARM_DESC(lid_unreliable, "Dynamically adding/removing input node for unreliable lids");
> +
>  /* --------------------------------------------------------------------------
>                                FS Interface (/proc)
>     -------------------------------------------------------------------------- */
> @@ -152,6 +158,9 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state)
>  	struct acpi_button *button = acpi_driver_data(device);
>  	int ret;
>  
> +	if (!button->input)
> +		return -EINVAL;
> +
>  	if (lid_init_state == ACPI_BUTTON_LID_INIT_IGNORE)
>  		input_report_switch(button->input, SW_LID, 0);
>  
> @@ -306,6 +315,8 @@ static void acpi_button_remove_input(struct acpi_device *device)
>  {
>  	struct acpi_button *button = acpi_driver_data(device);
>  
> +	if (!button->input)
> +		return;
>  	input_unregister_device(button->input);
>  	button->input = NULL;
>  }
> @@ -316,6 +327,9 @@ static int acpi_button_add_input(struct acpi_device *device)
>  	struct input_dev *input;
>  	int error;
>  
> +	if (button->input)
> +		return 0;
> +
>  	input = input_allocate_device();
>  	if (!input) {
>  		error = -ENOMEM;
> @@ -378,8 +392,10 @@ static void acpi_lid_initialize_state(struct acpi_device *device)
>  		break;
>  	case ACPI_BUTTON_LID_INIT_METHOD:
>  		(void)acpi_lid_update_state(device);
> +		mutex_unlock(&lid_input_lock);
>  		if (lid_periodic_update)
>  			acpi_lid_start_timer(device, lid_update_interval);
> +		mutex_lock(&lid_input_lock);
>  		break;
>  	case ACPI_BUTTON_LID_INIT_IGNORE:
>  	default:
> @@ -391,7 +407,9 @@ static void acpi_lid_timeout(ulong arg)
>  {
>  	struct acpi_device *device = (struct acpi_device *)arg;
>  
> +	mutex_lock(&lid_input_lock);
>  	acpi_lid_initialize_state(device);
> +	mutex_unlock(&lid_input_lock);
>  }
>  
>  static void acpi_button_notify(struct acpi_device *device, u32 event)
> @@ -406,7 +424,11 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
>  	case ACPI_BUTTON_NOTIFY_STATUS:
>  		input = button->input;
>  		if (button->type == ACPI_BUTTON_TYPE_LID) {
> +			mutex_lock(&lid_input_lock);
> +			if (!button->input)
> +				acpi_button_add_input(device);
>  			acpi_lid_update_state(device);
> +			mutex_unlock(&lid_input_lock);
>  		} else {
>  			int keycode;
>  
> @@ -440,8 +462,13 @@ static int acpi_button_suspend(struct device *dev)
>  	struct acpi_device *device = to_acpi_device(dev);
>  	struct acpi_button *button = acpi_driver_data(device);
>  
> -	if (button->type == ACPI_BUTTON_TYPE_LID)
> +	if (button->type == ACPI_BUTTON_TYPE_LID) {
> +		mutex_lock(&lid_input_lock);
> +		if (!button->lid_reliable)
> +			acpi_button_remove_input(device);
> +		mutex_unlock(&lid_input_lock);
>  		del_timer(&button->lid_timer);
> +	}
>  	button->suspended = true;
>  	return 0;
>  }
> @@ -459,6 +486,38 @@ static int acpi_button_resume(struct device *dev)
>  }
>  #endif
>  
> +static ssize_t lid_reliable_show(struct device *dev,
> +				 struct device_attribute *attr, char *buf)
> +{
> +	struct acpi_device *device = to_acpi_device(dev);
> +	struct acpi_button *button = acpi_driver_data(device);
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", button->lid_reliable);
> +}
> +static ssize_t lid_reliable_store(struct device *dev,
> +				  struct device_attribute *attr,
> +				  const char *buf, size_t count)
> +{
> +	struct acpi_device *device = to_acpi_device(dev);
> +	struct acpi_button *button = acpi_driver_data(device);
> +
> +	mutex_lock(&lid_input_lock);
> +	if (strtobool(buf, &button->lid_reliable) < 0) {
> +		mutex_unlock(&lid_input_lock);
> +		return -EINVAL;
> +	}
> +	if (button->lid_reliable)
> +		acpi_button_add_input(device);
> +	else {
> +		lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE;

Why would you link the "ignore" option to those unreliable switches?
When the input node is registered, we know that the _LID method gets
reliable, so why would you not query its state?

> +		acpi_button_remove_input(device);
> +	}
> +	acpi_lid_initialize_state(device);
> +	mutex_unlock(&lid_input_lock);
> +	return count;
> +}
> +static DEVICE_ATTR_RW(lid_reliable);
> +
>  static int acpi_button_add(struct acpi_device *device)
>  {
>  	struct acpi_button *button;
> @@ -507,21 +566,37 @@ static int acpi_button_add(struct acpi_device *device)
>  
>  	snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid);
>  
> -	error = acpi_button_add_input(device);
> -	if (error)
> -		goto err_remove_fs;
> -
>  	if (button->type == ACPI_BUTTON_TYPE_LID) {
>  		/*
>  		 * This assumes there's only one lid device, or if there are
>  		 * more we only care about the last one...
>  		 */
>  		lid_device = device;
> +		device_create_file(&device->dev, &dev_attr_lid_reliable);
> +		mutex_lock(&lid_input_lock);
> +		error = acpi_button_add_input(device);
> +		if (error) {
> +			mutex_unlock(&lid_input_lock);
> +			goto err_remove_fs;
> +		}
> +		if (lid_unreliable) {
> +			lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE;
> +			button->lid_reliable = false;
> +		} else
> +			button->lid_reliable = true;

You can not add the input node if you mark it later on as unreliable.
You are presenting an unknown state to user space, which is bad.

Cheers,
Benjamin

>  		if (lid_periodic_update)
>  			acpi_lid_initialize_state(device);
> -		else
> +		else {
> +			mutex_unlock(&lid_input_lock);
>  			acpi_lid_start_timer(device,
>  				lid_notify_timeout * MSEC_PER_SEC);
> +			mutex_lock(&lid_input_lock);
> +		}
> +		mutex_unlock(&lid_input_lock);
> +	} else {
> +		error = acpi_button_add_input(device);
> +		if (error)
> +			goto err_remove_fs;
>  	}
>  
>  	printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device));
> @@ -539,9 +614,14 @@ static int acpi_button_remove(struct acpi_device *device)
>  	struct acpi_button *button = acpi_driver_data(device);
>  
>  	acpi_button_remove_fs(device);
> -	if (button->type == ACPI_BUTTON_TYPE_LID)
> +	if (button->type == ACPI_BUTTON_TYPE_LID) {
> +		mutex_lock(&lid_input_lock);
> +		acpi_button_remove_input(device);
> +		mutex_unlock(&lid_input_lock);
>  		del_timer_sync(&button->lid_timer);
> -	acpi_button_remove_input(device);
> +		device_remove_file(&device->dev, &dev_attr_lid_reliable);
> +	} else
> +		acpi_button_remove_input(device);
>  	kfree(button);
>  	return 0;
>  }
> -- 
> 2.7.4
> 

      reply	other threads:[~2017-06-23 14:03 UTC|newest]

Thread overview: 62+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-05-05  2:39 [PATCH 1/5] Revert "ACPI / button: Remove lid_init_state=method mode" Lv Zheng
2017-05-05  2:39 ` [PATCH 2/5] ACPI: button: Add button.lid_init_state=close Lv Zheng
2017-05-05  2:39 ` [PATCH 3/5] ACPI: button: Fix lid notification Lv Zheng
2017-05-05  2:39 ` [PATCH 4/5] ACPI: button: Always notify kernel space using _LID returning value Lv Zheng
2017-05-05  2:40 ` [PATCH 5/5] ACPI: button: Obselete acpi_lid_open() invocations Lv Zheng
2017-05-09  1:21   ` Julian Wiedmann
2017-05-09  6:19     ` Zheng, Lv
2017-05-09  1:22 ` [PATCH 1/5] Revert "ACPI / button: Remove lid_init_state=method mode" Julian Wiedmann
2017-05-09  6:17   ` Zheng, Lv
2017-05-09  7:02 ` [PATCH v2 " Lv Zheng
2017-05-09  7:02 ` [PATCH v2 2/5] ACPI: button: Add button.lid_init_state=close Lv Zheng
2017-05-11 10:20   ` Benjamin Tissoires
2017-05-12  1:31     ` Zheng, Lv
2017-05-12  9:55       ` Benjamin Tissoires
2017-05-15  1:44         ` Zheng, Lv
2017-05-09  7:02 ` [PATCH v2 3/5] ACPI: button: Fix lid notification Lv Zheng
2017-05-11 10:21   ` Benjamin Tissoires
2017-05-09  7:02 ` [PATCH v2 4/5] ACPI: button: Always notify kernel space using _LID returning value Lv Zheng
2017-05-11 10:28   ` Benjamin Tissoires
2017-05-12  1:22     ` Zheng, Lv
2017-05-12 10:06       ` Benjamin Tissoires
2017-05-15  2:11         ` Zheng, Lv
2017-05-09  7:02 ` [PATCH v2 5/5] ACPI: button: Obselete acpi_lid_open() invocations Lv Zheng
2017-05-10 10:30   ` [Intel-gfx] " Jani Nikula
2017-05-11 10:33   ` Benjamin Tissoires
2017-05-12  1:25     ` Zheng, Lv
2017-05-12  6:08       ` Zheng, Lv
2017-05-12 10:20         ` Benjamin Tissoires
2017-05-15  3:55           ` Zheng, Lv
2017-05-15  7:12             ` Benjamin Tissoires
2017-05-15  8:42               ` Jani Nikula
2017-05-15  9:21                 ` [Intel-gfx] " Benjamin Tissoires
2017-05-15  9:41                   ` Jani Nikula
2017-05-26 23:42 ` [RFC PATCH v3 1/5] ACPI: button: Add indication of BIOS notification and faked events Lv Zheng
2017-05-29 16:04   ` Benjamin Tissoires
2017-05-31  8:57     ` Zheng, Lv
2017-05-26 23:42 ` [RFC PATCH v3 2/5] ACPI: button: Extends complement switch event support for all modes Lv Zheng
2017-05-26 23:42 ` [RFC PATCH v3 3/5] ACPI: button: Add lid event type debugging messages Lv Zheng
2017-05-26 23:42 ` [RFC PATCH v3 4/5] ACPI: button: Fix lid notification Lv Zheng
     [not found] ` <2a779ae8c280c968b3237ac4a3d9580df7262a46.1493951798.git.lv.zheng-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2017-05-26 23:42   ` [RFC PATCH v3 5/5] ACPI: button: Always notify kernel space using _LID returning value Lv Zheng
2017-05-29 16:08     ` Benjamin Tissoires
2017-05-31  8:59       ` Zheng, Lv
2017-05-31  9:41 ` [RFC PATCH v4 1/5] ACPI: button: Add indication of BIOS notification and faked events Lv Zheng
2017-05-31  9:41 ` [RFC PATCH v4 2/5] ACPI: button: Extends complement switch event support for all modes Lv Zheng
2017-05-31  9:42 ` [RFC PATCH v4 3/5] ACPI: button: Add lid event type debugging messages Lv Zheng
2017-05-31  9:42 ` [RFC PATCH v4 4/5] ACPI: button: Fix lid notification locks Lv Zheng
2017-05-31  9:42 ` [RFC PATCH v4 5/5] ACPI: button: Cleanup lid notification logics Lv Zheng
2017-06-07  9:43 ` [RFC PATCH 0/2] ACPI: button: Fix button.lid_init_state=method mode Lv Zheng
2017-06-07  9:43   ` [RFC PATCH v5 1/2] ACPI: button: Fix issue that button notify cannot report stateful SW_LID state Lv Zheng
2017-06-13  6:17     ` [lkp-robot] [ACPI] 4d0c35c1af: BUG:scheduling_while_atomic kernel test robot
2017-06-07  9:43   ` [RFC PATCH v5 2/2] ACPI: button: Add a quirk mode for Surface Pro 1 like laptop Lv Zheng
2017-06-21  8:54 ` [RFC PATCH v6 0/5] ACPI: button: Fix button.lid_init_state=method mode Lv Zheng
2017-06-21  8:55   ` [RFC PATCH v6 1/5] ACPI: button: Add a workaround to fix an order issue for old userspace Lv Zheng
2017-06-23 14:02     ` Benjamin Tissoires
2017-06-30  1:34     ` [lkp-robot] [ACPI] c4a9ff748c: BUG:scheduling_while_atomic kernel test robot
2017-06-21  8:55   ` [RFC PATCH v6 2/5] ACPI: button: Add an optional workaround to fix an event missing issue for old userspace Lv Zheng
2017-06-23 14:03     ` Benjamin Tissoires
2017-06-21  8:55   ` [RFC PATCH v6 3/5] ACPI: button: Rework lid_init_state=ignore mode Lv Zheng
2017-06-23 14:03     ` Benjamin Tissoires
2017-06-21  8:55   ` [RFC PATCH v6 4/5] ACPI: button: extract input creation/destruction helpers Lv Zheng
2017-06-21  8:55   ` [RFC PATCH v6 5/5] ACPI: button: Add an optional workaround to fix a persistent close issue for old userspace Lv Zheng
2017-06-23 14:03     ` Benjamin Tissoires [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170623140347.GR26073@mail.corp.redhat.com \
    --to=benjamin.tissoires@redhat.com \
    --cc=len.brown@intel.com \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lv.zheng@intel.com \
    --cc=rafael.j.wysocki@intel.com \
    --cc=rjw@rjwysocki.net \
    --cc=zetalog@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).