Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2d09af4a authored by Dave Lambley's avatar Dave Lambley Committed by Rafael J. Wysocki
Browse files

ACPI / battery: If _BIX fails, retry with _BIF



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: default avatarDave Lambley <linux@davel.me.uk>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent a25f0944
Loading
Loading
Loading
Loading
+48 −24
Original line number Diff line number Diff line
@@ -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;