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: Dave Lambley <linux@davel.me.uk> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
Родитель
a25f0944ba
Коммит
2d09af4a88
|
@ -430,39 +430,24 @@ static int acpi_battery_get_status(struct acpi_battery *battery)
|
||||||
return 0;
|
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;
|
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 (use_bix && battery_bix_broken_package)
|
||||||
|
result = extract_package(battery, buffer->pointer,
|
||||||
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,
|
|
||||||
extended_info_offsets + 1,
|
extended_info_offsets + 1,
|
||||||
ARRAY_SIZE(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,
|
result = extract_package(battery, buffer->pointer,
|
||||||
extended_info_offsets,
|
extended_info_offsets,
|
||||||
ARRAY_SIZE(extended_info_offsets));
|
ARRAY_SIZE(extended_info_offsets));
|
||||||
else
|
else
|
||||||
result = extract_package(battery, buffer.pointer,
|
result = extract_package(battery, buffer->pointer,
|
||||||
info_offsets, ARRAY_SIZE(info_offsets));
|
info_offsets, ARRAY_SIZE(info_offsets));
|
||||||
kfree(buffer.pointer);
|
|
||||||
if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
|
if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
|
||||||
battery->full_charge_capacity = battery->design_capacity;
|
battery->full_charge_capacity = battery->design_capacity;
|
||||||
if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) &&
|
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;
|
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)
|
static int acpi_battery_get_state(struct acpi_battery *battery)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче