All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Avoid _BIX ACPI method on Lenovo Yoga 300.
@ 2016-09-14  8:40 Dave Lambley
  2016-09-14 10:34 ` Zheng, Lv
  0 siblings, 1 reply; 11+ messages in thread
From: Dave Lambley @ 2016-09-14  8:40 UTC (permalink / raw)
  To: linux-acpi; +Cc: Dave Lambley, Rafael J. Wysocki, Len Brown

On the (current?) Yoga 300 firmware, the _BIX method fails with an error.
This prevents the kernel from correctly detecting the presence of a
battery.

[   28.641906] ACPI Exception: AE_AML_PACKAGE_LIMIT, Index (0x000000010) is beyond end of object (length 0xD) (20160422/exoparg2-427)
[   28.641924] ACPI Error: Method parse/execution failed [\_SB.PCI0.LPCB.H_EC.BAT1._BIX] (Node ffff9145fb0b2230), AE_AML_PACKAGE_LIMIT (20160422/psparse-542)

Fortunately, the _BIF method can be used to get battery information. This
change causes the kernel to use the _BIF method to preference on the
Yogo 300, allowing the battery to be detected correctly.

Signed-off-by: Dave Lambley <linux@davel.me.uk>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
CC: Len Brown <lenb@kernel.org>
---
 drivers/acpi/battery.c | 29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index ab23479..2b165a8 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -69,6 +69,7 @@ MODULE_LICENSE("GPL");
 static async_cookie_t async_cookie;
 static int battery_bix_broken_package;
 static int battery_notification_delay_ms;
+static int battery_avoid_bix;
 static unsigned int cache_time = 1000;
 module_param(cache_time, uint, 0644);
 MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
@@ -434,11 +435,16 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
 {
 	int result = -EFAULT;
 	acpi_status status = 0;
-	char *name = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags) ?
-			"_BIX" : "_BIF";
+	bool use_bix = !battery_avoid_bix &&
+			test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
+
+	char *name = use_bix ? "_BIX" : "_BIF";
 
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 
+	if (battery_avoid_bix)
+		dev_dbg(&battery->device->dev, "ACPI _BIX method blacklisted on this hardware, avoiding.");
+
 	if (!acpi_battery_present(battery))
 		return 0;
 	mutex_lock(&battery->lock);
@@ -451,11 +457,11 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
 		return -ENODEV;
 	}
 
-	if (battery_bix_broken_package)
+	if (use_bix && battery_bix_broken_package)
 		result = extract_package(battery, buffer.pointer,
 				extended_info_offsets + 1,
 				ARRAY_SIZE(extended_info_offsets) - 1);
-	else if (test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags))
+	else if (use_bix)
 		result = extract_package(battery, buffer.pointer,
 				extended_info_offsets,
 				ARRAY_SIZE(extended_info_offsets));
@@ -1134,6 +1140,12 @@ battery_notification_delay_quirk(const struct dmi_system_id *d)
 	return 0;
 }
 
+static int __init
+battery_avoid_bix_quirk(const struct dmi_system_id *d)
+{
+	battery_avoid_bix = 1;
+	return 0;
+}
 static const struct dmi_system_id bat_dmi_table[] __initconst = {
 	{
 		.callback = battery_bix_broken_package_quirk,
@@ -1151,6 +1163,15 @@ static const struct dmi_system_id bat_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-573G"),
 		},
 	},
+	{
+		.callback = battery_avoid_bix_quirk,
+		.ident = "Lenovo Yogo 3000",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "80M1"),
+		},
+	},
+
 	{},
 };
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* RE: [PATCH] Avoid _BIX ACPI method on Lenovo Yoga 300.
  2016-09-14  8:40 [PATCH] Avoid _BIX ACPI method on Lenovo Yoga 300 Dave Lambley
@ 2016-09-14 10:34 ` Zheng, Lv
  2016-09-17 22:56   ` [PATCH] If _BIX fails, retry with _BIF Dave Lambley
  0 siblings, 1 reply; 11+ messages in thread
From: Zheng, Lv @ 2016-09-14 10:34 UTC (permalink / raw)
  To: Dave Lambley, linux-acpi; +Cc: Rafael J. Wysocki, Len Brown

Hi,

> From: linux-acpi-owner@vger.kernel.org [mailto:linux-acpi-owner@vger.kernel.org] On Behalf Of Dave
> Lambley
> Subject: [PATCH] Avoid _BIX ACPI method on Lenovo Yoga 300.
> 
> On the (current?) Yoga 300 firmware, the _BIX method fails with an error.
> This prevents the kernel from correctly detecting the presence of a
> battery.
> 
> [   28.641906] ACPI Exception: AE_AML_PACKAGE_LIMIT, Index (0x000000010) is beyond end of object
> (length 0xD) (20160422/exoparg2-427)
> [   28.641924] ACPI Error: Method parse/execution failed [\_SB.PCI0.LPCB.H_EC.BAT1._BIX] (Node
> ffff9145fb0b2230), AE_AML_PACKAGE_LIMIT (20160422/psparse-542)
> 
> Fortunately, the _BIF method can be used to get battery information. This
> change causes the kernel to use the _BIF method to preference on the
> Yogo 300, allowing the battery to be detected correctly.

Wasn't it better to try _BIX first, and then _BIF next when _BIX failed.
What's the merit of increasing the number of the platform quirks?

Thanks
Lv

> 
> Signed-off-by: Dave Lambley <linux@davel.me.uk>
> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
> CC: Len Brown <lenb@kernel.org>
> ---
>  drivers/acpi/battery.c | 29 +++++++++++++++++++++++++----
>  1 file changed, 25 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
> index ab23479..2b165a8 100644
> --- a/drivers/acpi/battery.c
> +++ b/drivers/acpi/battery.c
> @@ -69,6 +69,7 @@ MODULE_LICENSE("GPL");
>  static async_cookie_t async_cookie;
>  static int battery_bix_broken_package;
>  static int battery_notification_delay_ms;
> +static int battery_avoid_bix;
>  static unsigned int cache_time = 1000;
>  module_param(cache_time, uint, 0644);
>  MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
> @@ -434,11 +435,16 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
>  {
>  	int result = -EFAULT;
>  	acpi_status status = 0;
> -	char *name = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags) ?
> -			"_BIX" : "_BIF";
> +	bool use_bix = !battery_avoid_bix &&
> +			test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
> +
> +	char *name = use_bix ? "_BIX" : "_BIF";
> 
>  	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
> 
> +	if (battery_avoid_bix)
> +		dev_dbg(&battery->device->dev, "ACPI _BIX method blacklisted on this hardware, avoiding.");
> +
>  	if (!acpi_battery_present(battery))
>  		return 0;
>  	mutex_lock(&battery->lock);
> @@ -451,11 +457,11 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
>  		return -ENODEV;
>  	}
> 
> -	if (battery_bix_broken_package)
> +	if (use_bix && battery_bix_broken_package)
>  		result = extract_package(battery, buffer.pointer,
>  				extended_info_offsets + 1,
>  				ARRAY_SIZE(extended_info_offsets) - 1);
> -	else if (test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags))
> +	else if (use_bix)
>  		result = extract_package(battery, buffer.pointer,
>  				extended_info_offsets,
>  				ARRAY_SIZE(extended_info_offsets));
> @@ -1134,6 +1140,12 @@ battery_notification_delay_quirk(const struct dmi_system_id *d)
>  	return 0;
>  }
> 
> +static int __init
> +battery_avoid_bix_quirk(const struct dmi_system_id *d)
> +{
> +	battery_avoid_bix = 1;
> +	return 0;
> +}
>  static const struct dmi_system_id bat_dmi_table[] __initconst = {
>  	{
>  		.callback = battery_bix_broken_package_quirk,
> @@ -1151,6 +1163,15 @@ static const struct dmi_system_id bat_dmi_table[] __initconst = {
>  			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-573G"),
>  		},
>  	},
> +	{
> +		.callback = battery_avoid_bix_quirk,
> +		.ident = "Lenovo Yogo 3000",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "80M1"),
> +		},
> +	},
> +
>  	{},
>  };
> 
> --
> 2.7.4
> 
> --
> 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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH] If _BIX fails, retry with _BIF.
  2016-09-14 10:34 ` Zheng, Lv
@ 2016-09-17 22:56   ` Dave Lambley
  2016-11-02 18:37     ` [PATCH v2] Lenovo Yoga 300 battery support Dave Lambley
  0 siblings, 1 reply; 11+ messages in thread
From: Dave Lambley @ 2016-09-17 22:56 UTC (permalink / raw)
  To: linux-acpi; +Cc: Dave Lambley, Rafael J. Wysocki, Len Brown

The Lenovo Yoga 300 laptop's firmware advertises that it provides the _BIX
method. Unfortunately (some versions of?) the implementation return
badly-formed data.

[   21.712228] ACPI Exception: AE_AML_PACKAGE_LIMIT, Index (0x000000010) is beyond end of object (length 0xD) (20160422/exoparg2-427)
[   21.712244] ACPI Error: Method parse/execution failed [\_SB.PCI0.LPCB.H_EC.BAT1._BIX] (Node ffff95f8ff0b20f0), AE_AML_PACKAGE_LIMIT (2016042
2/psparse-542)

The _BIF method does succeed.

Signed-off-by: Dave Lambley <linux@davel.me.uk>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
CC: Len Brown <lenb@kernel.org>
---
 drivers/acpi/battery.c | 68 ++++++++++++++++++++++++++++++++------------------
 1 file changed, 44 insertions(+), 24 deletions(-)

diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index ab23479..71ae7e7 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -430,39 +430,24 @@ static int acpi_battery_get_status(struct acpi_battery *battery)
 	return 0;
 }
 
-static int acpi_battery_get_info(struct acpi_battery *battery)
+
+int extract_battery_info(const int use_bix,
+			 struct acpi_battery *battery,
+			 const struct acpi_buffer  *buffer)
 {
 	int result = -EFAULT;
-	acpi_status status = 0;
-	char *name = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags) ?
-			"_BIX" : "_BIF";
-
-	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 
-	if (!acpi_battery_present(battery))
-		return 0;
-	mutex_lock(&battery->lock);
-	status = acpi_evaluate_object(battery->device->handle, name,
-						NULL, &buffer);
-	mutex_unlock(&battery->lock);
-
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s", name));
-		return -ENODEV;
-	}
-
-	if (battery_bix_broken_package)
-		result = extract_package(battery, buffer.pointer,
+	if (use_bix && battery_bix_broken_package)
+		result = extract_package(battery, buffer->pointer,
 				extended_info_offsets + 1,
 				ARRAY_SIZE(extended_info_offsets) - 1);
-	else if (test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags))
-		result = extract_package(battery, buffer.pointer,
+	else if (use_bix)
+		result = extract_package(battery, buffer->pointer,
 				extended_info_offsets,
 				ARRAY_SIZE(extended_info_offsets));
 	else
-		result = extract_package(battery, buffer.pointer,
+		result = extract_package(battery, buffer->pointer,
 				info_offsets, ARRAY_SIZE(info_offsets));
-	kfree(buffer.pointer);
 	if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
 		battery->full_charge_capacity = battery->design_capacity;
 	if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) &&
@@ -483,6 +468,41 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
 	return result;
 }
 
+static int acpi_battery_get_info(struct acpi_battery *battery)
+{
+	acpi_status status = 0;
+	const int xinfo = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
+	int use_bix;
+
+	if (!acpi_battery_present(battery))
+		return 0;
+
+
+	for (use_bix = xinfo ? 1 : 0; use_bix >= 0; use_bix--) {
+		struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+
+		mutex_lock(&battery->lock);
+		status = acpi_evaluate_object(battery->device->handle,
+							use_bix ? "_BIX":"_BIF",
+							NULL, &buffer);
+		mutex_unlock(&battery->lock);
+
+		if (ACPI_FAILURE(status)) {
+			ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s",
+					use_bix ? "_BIX":"_BIF"));
+		} else {
+			const int result = extract_battery_info(use_bix,
+								battery,
+								&buffer);
+
+			kfree(buffer.pointer);
+			return result;
+		}
+	}
+
+	return -ENODEV;
+}
+
 static int acpi_battery_get_state(struct acpi_battery *battery)
 {
 	int result = 0;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2] Lenovo Yoga 300 battery support
  2016-09-17 22:56   ` [PATCH] If _BIX fails, retry with _BIF Dave Lambley
@ 2016-11-02 18:37     ` Dave Lambley
  2016-11-02 18:37       ` [PATCH v2] If _BIX fails, retry with _BIF Dave Lambley
  0 siblings, 1 reply; 11+ messages in thread
From: Dave Lambley @ 2016-11-02 18:37 UTC (permalink / raw)
  To: linux-acpi; +Cc: Dave Lambley, Rafael J. Wysocki, Len Brown

This patch allows Linux to detect the battery in the Lenovo Yoga 300
laptop. It does this by tolerating a bug in the firmware which breaks the
_BIX method but not _BIF. Without this patch, the battery is not presented
to userland.

On a system with non-buggy firmware, the behaviour should be unchanged.

With the patch, something like this gets logged,

[ 3004.858993] ACPI Exception: AE_AML_PACKAGE_LIMIT, Index (0x000000010) is beyond end of object (length 0xD) (20160831/exoparg2-427)
[ 3004.859015] ACPI Error: Method parse/execution failed [\_SB.PCI0.LPCB.H_EC.BAT1._BIX] (Node ffff955bbb0b32d0), AE_AML_PACKAGE_LIMIT (20160831/psparse-543)
[ 3004.859038] ACPI Exception: AE_AML_PACKAGE_LIMIT, Evaluating _BIX (20160831/battery-493)
[ 3004.873413] [Firmware Bug]: The _BIX method is broken, using _BIF.

v1 -> v2
	- Log when falling back to _BIF method.
	- Rebased against v4.9-rc2.

Signed-off-by: Dave Lambley <linux@davel.me.uk>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Len Brown <lenb@kernel.org>

Dave Lambley (1):
  If _BIX fails, retry with _BIF.

 drivers/acpi/battery.c | 72 +++++++++++++++++++++++++++++++++-----------------
 1 file changed, 48 insertions(+), 24 deletions(-)

-- 
2.7.4


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2] If _BIX fails, retry with _BIF.
  2016-11-02 18:37     ` [PATCH v2] Lenovo Yoga 300 battery support Dave Lambley
@ 2016-11-02 18:37       ` Dave Lambley
  2016-11-02 23:26         ` Henrique de Moraes Holschuh
  0 siblings, 1 reply; 11+ messages in thread
From: Dave Lambley @ 2016-11-02 18:37 UTC (permalink / raw)
  To: linux-acpi; +Cc: Dave Lambley, Rafael J. Wysocki, Len Brown

The Lenovo Yoga 300 laptop's firmware advertises that it provides the _BIX
the method to retrieve battery information. Unfortunately (some versions
of?) the implementation return with an error.

[   21.712228] ACPI Exception: AE_AML_PACKAGE_LIMIT, Index (0x000000010) is beyond end of object (length 0xD) (20160422/exoparg2-427)
[   21.712244] ACPI Error: Method parse/execution failed [\_SB.PCI0.LPCB.H_EC.BAT1._BIX] (Node ffff95f8ff0b20f0), AE_AML_PACKAGE_LIMIT (2016042
2/psparse-542)

The _BIF method does succeed and returns convincing data. We detect _BIX
failing and automatically retry with _BIF.

Signed-off-by: Dave Lambley <linux@davel.me.uk>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Len Brown <lenb@kernel.org>
---
 drivers/acpi/battery.c | 72 +++++++++++++++++++++++++++++++++-----------------
 1 file changed, 48 insertions(+), 24 deletions(-)

diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 93ecae5..ad5a62c 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -430,39 +430,24 @@ static int acpi_battery_get_status(struct acpi_battery *battery)
 	return 0;
 }
 
-static int acpi_battery_get_info(struct acpi_battery *battery)
+
+int extract_battery_info(const int use_bix,
+			 struct acpi_battery *battery,
+			 const struct acpi_buffer *buffer)
 {
 	int result = -EFAULT;
-	acpi_status status = 0;
-	char *name = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags) ?
-			"_BIX" : "_BIF";
-
-	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 
-	if (!acpi_battery_present(battery))
-		return 0;
-	mutex_lock(&battery->lock);
-	status = acpi_evaluate_object(battery->device->handle, name,
-						NULL, &buffer);
-	mutex_unlock(&battery->lock);
-
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s", name));
-		return -ENODEV;
-	}
-
-	if (battery_bix_broken_package)
-		result = extract_package(battery, buffer.pointer,
+	if (use_bix && battery_bix_broken_package)
+		result = extract_package(battery, buffer->pointer,
 				extended_info_offsets + 1,
 				ARRAY_SIZE(extended_info_offsets) - 1);
-	else if (test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags))
-		result = extract_package(battery, buffer.pointer,
+	else if (use_bix)
+		result = extract_package(battery, buffer->pointer,
 				extended_info_offsets,
 				ARRAY_SIZE(extended_info_offsets));
 	else
-		result = extract_package(battery, buffer.pointer,
+		result = extract_package(battery, buffer->pointer,
 				info_offsets, ARRAY_SIZE(info_offsets));
-	kfree(buffer.pointer);
 	if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
 		battery->full_charge_capacity = battery->design_capacity;
 	if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) &&
@@ -483,6 +468,45 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
 	return result;
 }
 
+static int acpi_battery_get_info(struct acpi_battery *battery)
+{
+	const int xinfo = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
+	int use_bix;
+	int result = -ENODEV;
+
+	if (!acpi_battery_present(battery))
+		return 0;
+
+
+	for (use_bix = xinfo ? 1 : 0; use_bix >= 0; use_bix--) {
+		struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+		acpi_status status = AE_ERROR;
+
+		mutex_lock(&battery->lock);
+		status = acpi_evaluate_object(battery->device->handle,
+					      use_bix ? "_BIX":"_BIF",
+					      NULL, &buffer);
+		mutex_unlock(&battery->lock);
+
+		if (ACPI_FAILURE(status)) {
+			ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s",
+					use_bix ? "_BIX":"_BIF"));
+		} else {
+			result = extract_battery_info(use_bix,
+						      battery,
+						      &buffer);
+
+			kfree(buffer.pointer);
+			break;
+		}
+	}
+
+	if (!result && !use_bix && xinfo)
+		pr_warn(FW_BUG "The _BIX method is broken, using _BIF.\n");
+
+	return result;
+}
+
 static int acpi_battery_get_state(struct acpi_battery *battery)
 {
 	int result = 0;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] If _BIX fails, retry with _BIF.
  2016-11-02 18:37       ` [PATCH v2] If _BIX fails, retry with _BIF Dave Lambley
@ 2016-11-02 23:26         ` Henrique de Moraes Holschuh
  2016-11-03  8:33           ` Dave Lambley
  0 siblings, 1 reply; 11+ messages in thread
From: Henrique de Moraes Holschuh @ 2016-11-02 23:26 UTC (permalink / raw)
  To: Dave Lambley; +Cc: linux-acpi, Rafael J. Wysocki, Len Brown

On Wed, 02 Nov 2016, Dave Lambley wrote:
> -static int acpi_battery_get_info(struct acpi_battery *battery)
> +
> +int extract_battery_info(const int use_bix,
> +			 struct acpi_battery *battery,
> +			 const struct acpi_buffer *buffer)

Shouldn't extract_battery_info() be static as well?

-- 
  Henrique Holschuh

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] If _BIX fails, retry with _BIF.
  2016-11-02 23:26         ` Henrique de Moraes Holschuh
@ 2016-11-03  8:33           ` Dave Lambley
  2016-11-03 22:38             ` Henrique de Moraes Holschuh
  0 siblings, 1 reply; 11+ messages in thread
From: Dave Lambley @ 2016-11-03  8:33 UTC (permalink / raw)
  To: Henrique de Moraes Holschuh; +Cc: linux-acpi, Rafael J. Wysocki, Len Brown

On 2 November 2016 at 23:26, Henrique de Moraes Holschuh <hmh@hmh.eng.br> wrote:
>
> On Wed, 02 Nov 2016, Dave Lambley wrote:
> > -static int acpi_battery_get_info(struct acpi_battery *battery)
> > +
> > +int extract_battery_info(const int use_bix,
> > +                      struct acpi_battery *battery,
> > +                      const struct acpi_buffer *buffer)
>
> Shouldn't extract_battery_info() be static as well?

I do not believe it needs to be exported. It is a new function only
used inside battery.c.

Best regards,
Dave

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] If _BIX fails, retry with _BIF.
  2016-11-03  8:33           ` Dave Lambley
@ 2016-11-03 22:38             ` Henrique de Moraes Holschuh
  2016-11-04  1:05               ` [PATCH v3 0/1] Lenovo Yoga 300 battery support Dave Lambley
  0 siblings, 1 reply; 11+ messages in thread
From: Henrique de Moraes Holschuh @ 2016-11-03 22:38 UTC (permalink / raw)
  To: Dave Lambley; +Cc: linux-acpi, Rafael J. Wysocki, Len Brown

On Thu, 03 Nov 2016, Dave Lambley wrote:
> On 2 November 2016 at 23:26, Henrique de Moraes Holschuh <hmh@hmh.eng.br> wrote:
> >
> > On Wed, 02 Nov 2016, Dave Lambley wrote:
> > > -static int acpi_battery_get_info(struct acpi_battery *battery)
> > > +
> > > +int extract_battery_info(const int use_bix,
> > > +                      struct acpi_battery *battery,
> > > +                      const struct acpi_buffer *buffer)
> >
> > Shouldn't extract_battery_info() be static as well?
> 
> I do not believe it needs to be exported. It is a new function only
> used inside battery.c.

Indeed.  Therefore, it really should be made static.

Please fix that on the next version of your patch...

-- 
  Henrique Holschuh

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v3 0/1] Lenovo Yoga 300 battery support
  2016-11-03 22:38             ` Henrique de Moraes Holschuh
@ 2016-11-04  1:05               ` Dave Lambley
  2016-11-04  1:05                 ` [PATCH v3 1/1] If _BIX fails, retry with _BIF Dave Lambley
  0 siblings, 1 reply; 11+ messages in thread
From: Dave Lambley @ 2016-11-04  1:05 UTC (permalink / raw)
  To: linux-acpi
  Cc: Henrique de Moraes Holschuh, Dave Lambley, Rafael J. Wysocki, Len Brown

This patch allows Linux to detect the battery in the Lenovo Yoga 300
laptop. It does this by tolerating a bug in the firmware which breaks the
_BIX method but not _BIF. Without this patch, the battery is not presented
to userland.

On a system with non-buggy firmware, the behaviour should be unchanged.

With the patch, on affected systems something like this gets logged,

[ 3004.858993] ACPI Exception: AE_AML_PACKAGE_LIMIT, Index (0x000000010) is beyond end of object (length 0xD) (20160831/exoparg2-427)
[ 3004.859015] ACPI Error: Method parse/execution failed [\_SB.PCI0.LPCB.H_EC.BAT1._BIX] (Node ffff955bbb0b32d0), AE_AML_PACKAGE_LIMIT (20160831/psparse-543)
[ 3004.859038] ACPI Exception: AE_AML_PACKAGE_LIMIT, Evaluating _BIX (20160831/battery-493)
[ 3004.873413] [Firmware Bug]: The _BIX method is broken, using _BIF.

v2 -> v3
	- No longer unnecessarily exports extract_battery_info().

v1 -> v2
	- Log when falling back to _BIF method.
	- Rebased against v4.9-rc2.

Signed-off-by: Dave Lambley <linux@davel.me.uk>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Len Brown <lenb@kernel.org>

Dave Lambley (1):
  If _BIX fails, retry with _BIF.

 drivers/acpi/battery.c | 72 +++++++++++++++++++++++++++++++++-----------------
 1 file changed, 48 insertions(+), 24 deletions(-)

-- 
2.7.4


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v3 1/1] If _BIX fails, retry with _BIF.
  2016-11-04  1:05               ` [PATCH v3 0/1] Lenovo Yoga 300 battery support Dave Lambley
@ 2016-11-04  1:05                 ` Dave Lambley
  2016-11-24  1:25                   ` Rafael J. Wysocki
  0 siblings, 1 reply; 11+ messages in thread
From: Dave Lambley @ 2016-11-04  1:05 UTC (permalink / raw)
  To: linux-acpi
  Cc: Henrique de Moraes Holschuh, Dave Lambley, Rafael J. Wysocki, Len Brown

The Lenovo Yoga 300 laptop's firmware advertises that it provides the _BIX
the method to retrieve battery information. Unfortunately (some versions
of?) the implementation return with an error.

[   21.712228] ACPI Exception: AE_AML_PACKAGE_LIMIT, Index (0x000000010) is beyond end of object (length 0xD) (20160422/exoparg2-427)
[   21.712244] ACPI Error: Method parse/execution failed [\_SB.PCI0.LPCB.H_EC.BAT1._BIX] (Node ffff95f8ff0b20f0), AE_AML_PACKAGE_LIMIT (20160422/psparse-542)

The _BIF method does succeed and returns convincing data. We detect _BIX
failing and automatically retry with _BIF.

Signed-off-by: Dave Lambley <linux@davel.me.uk>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Len Brown <lenb@kernel.org>
---
 drivers/acpi/battery.c | 72 +++++++++++++++++++++++++++++++++-----------------
 1 file changed, 48 insertions(+), 24 deletions(-)

diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 93ecae5..05fe9eb 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -430,39 +430,24 @@ static int acpi_battery_get_status(struct acpi_battery *battery)
 	return 0;
 }
 
-static int acpi_battery_get_info(struct acpi_battery *battery)
+
+static int extract_battery_info(const int use_bix,
+			 struct acpi_battery *battery,
+			 const struct acpi_buffer *buffer)
 {
 	int result = -EFAULT;
-	acpi_status status = 0;
-	char *name = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags) ?
-			"_BIX" : "_BIF";
-
-	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 
-	if (!acpi_battery_present(battery))
-		return 0;
-	mutex_lock(&battery->lock);
-	status = acpi_evaluate_object(battery->device->handle, name,
-						NULL, &buffer);
-	mutex_unlock(&battery->lock);
-
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s", name));
-		return -ENODEV;
-	}
-
-	if (battery_bix_broken_package)
-		result = extract_package(battery, buffer.pointer,
+	if (use_bix && battery_bix_broken_package)
+		result = extract_package(battery, buffer->pointer,
 				extended_info_offsets + 1,
 				ARRAY_SIZE(extended_info_offsets) - 1);
-	else if (test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags))
-		result = extract_package(battery, buffer.pointer,
+	else if (use_bix)
+		result = extract_package(battery, buffer->pointer,
 				extended_info_offsets,
 				ARRAY_SIZE(extended_info_offsets));
 	else
-		result = extract_package(battery, buffer.pointer,
+		result = extract_package(battery, buffer->pointer,
 				info_offsets, ARRAY_SIZE(info_offsets));
-	kfree(buffer.pointer);
 	if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
 		battery->full_charge_capacity = battery->design_capacity;
 	if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) &&
@@ -483,6 +468,45 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
 	return result;
 }
 
+static int acpi_battery_get_info(struct acpi_battery *battery)
+{
+	const int xinfo = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
+	int use_bix;
+	int result = -ENODEV;
+
+	if (!acpi_battery_present(battery))
+		return 0;
+
+
+	for (use_bix = xinfo ? 1 : 0; use_bix >= 0; use_bix--) {
+		struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+		acpi_status status = AE_ERROR;
+
+		mutex_lock(&battery->lock);
+		status = acpi_evaluate_object(battery->device->handle,
+					      use_bix ? "_BIX":"_BIF",
+					      NULL, &buffer);
+		mutex_unlock(&battery->lock);
+
+		if (ACPI_FAILURE(status)) {
+			ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s",
+					use_bix ? "_BIX":"_BIF"));
+		} else {
+			result = extract_battery_info(use_bix,
+						      battery,
+						      &buffer);
+
+			kfree(buffer.pointer);
+			break;
+		}
+	}
+
+	if (!result && !use_bix && xinfo)
+		pr_warn(FW_BUG "The _BIX method is broken, using _BIF.\n");
+
+	return result;
+}
+
 static int acpi_battery_get_state(struct acpi_battery *battery)
 {
 	int result = 0;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 1/1] If _BIX fails, retry with _BIF.
  2016-11-04  1:05                 ` [PATCH v3 1/1] If _BIX fails, retry with _BIF Dave Lambley
@ 2016-11-24  1:25                   ` Rafael J. Wysocki
  0 siblings, 0 replies; 11+ messages in thread
From: Rafael J. Wysocki @ 2016-11-24  1:25 UTC (permalink / raw)
  To: Dave Lambley; +Cc: linux-acpi, Henrique de Moraes Holschuh, Len Brown

On Friday, November 04, 2016 01:05:40 AM Dave Lambley wrote:
> The Lenovo Yoga 300 laptop's firmware advertises that it provides the _BIX
> the method to retrieve battery information. Unfortunately (some versions
> of?) the implementation return with an error.
> 
> [   21.712228] ACPI Exception: AE_AML_PACKAGE_LIMIT, Index (0x000000010) is beyond end of object (length 0xD) (20160422/exoparg2-427)
> [   21.712244] ACPI Error: Method parse/execution failed [\_SB.PCI0.LPCB.H_EC.BAT1._BIX] (Node ffff95f8ff0b20f0), AE_AML_PACKAGE_LIMIT (20160422/psparse-542)
> 
> The _BIF method does succeed and returns convincing data. We detect _BIX
> failing and automatically retry with _BIF.
> 
> Signed-off-by: Dave Lambley <linux@davel.me.uk>
> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
> Cc: Len Brown <lenb@kernel.org>

Patch applied.

Thanks,
Rafael


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2016-11-24  1:17 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-14  8:40 [PATCH] Avoid _BIX ACPI method on Lenovo Yoga 300 Dave Lambley
2016-09-14 10:34 ` Zheng, Lv
2016-09-17 22:56   ` [PATCH] If _BIX fails, retry with _BIF Dave Lambley
2016-11-02 18:37     ` [PATCH v2] Lenovo Yoga 300 battery support Dave Lambley
2016-11-02 18:37       ` [PATCH v2] If _BIX fails, retry with _BIF Dave Lambley
2016-11-02 23:26         ` Henrique de Moraes Holschuh
2016-11-03  8:33           ` Dave Lambley
2016-11-03 22:38             ` Henrique de Moraes Holschuh
2016-11-04  1:05               ` [PATCH v3 0/1] Lenovo Yoga 300 battery support Dave Lambley
2016-11-04  1:05                 ` [PATCH v3 1/1] If _BIX fails, retry with _BIF Dave Lambley
2016-11-24  1:25                   ` Rafael J. Wysocki

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.