ACPI and power management fixes for 3.16-rc5
- Missing device ID for ACPI enumeration of PNP devices that we overlooked during the recent rework of that code from Zhang Rui. - Fix for a problem introduced during the 3.14 cycle in the ACPI device resources management code and causing it to reject all resources of length 0 although some of them are actually valid which affects serial ports detection on a number of systems. From Andy Whitcroft. - intel_pstate fix for a boot problem on some BayTrail-based systems introduced by a previous fix related to that platform during the 3.13 cycle from Dirk Brandewie. - Revert of a 3.13 commit that removed the ACPI AC /proc interface which turns out to be still needed by some old utilities (kpowersave from kde 3.5.10 in particular) from Lan Tianyu. - cpufreq build fix for the davinci ARM platform from Prabhakar Lad (the breakage was introduced during the 3.10 cycle). - ACPI-related i915 fix preventing firmware on some Thinkpad laptops from setting backlight levels incorrectly during AC plug/unplug. From Aaron Lu. - Fixes for two nasty race conditions in the ACPI embedded controller driver that may be responsible for a number of past bug reports related to the EC from Lv Zhang and a fix for two memory leaks in error code paths in that driver from Colin Ian King. - Fixes for a couple of corner-case issues in the intel_pstate driver (all candidates for -stable) from Dirk Brandewie and Vincent Minet. - Fixes for two corner-case issues in the ACPI battery driver from Josef Gajdusek and Lan Tianyu. - Two new ACPI video blacklist entries for Acer TravelMate B113 and Dell Inspiron 5737 from Edward Lin and Martin Kepplinger. / -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABCAAGBQJTvvNjAAoJEILEb/54YlRx9hgQAIsDBUU1b3jmDiL5QwN7n2OW VJ7T4nEiigk2waeCgCrucEP4Sqj7H+tjmoPPwptn4rPYTGf7/xk7fi6A3w9eXidd YPMhOj3JnsZPSDxWAM75xTkonqWBakpB5WfHF9EvNFKFoFu4uIvwfhtrnZl+qVT6 Bmd2Q5hDvA1BTndtD1b+xc3o+Pj05YCPhWwpyqakTfUQYeqWtvlMX9q1+50sTMjr 6B0ouTQ/h9Pm9kuN+cogioPXRNJdTlCRm8vHUD8JUOV5zR2PaKcswzdrU3IYnOuk d0m9B9EHSoFCsSQyoDlgxxZfQhp6u1m8z4ht/Sn2qcbHOjWHAnVQaLYH1nnyO6IT n1Ddi/HQAxKmc8KlQ7ECVZezW2pJaRgbyjq3HVwykA3imP39sfE4Yo7TmmXLczZs 2Ltin2N+3/P0qOdlxRjT9pJ9Fw2DSzDOReaNMxz6GSM4EcPdXHEZahGhpNnXOMZx zFzohGjq5zwn5FoAihHwDfj3WpsUTG7SCoszQFGsXk+4HR1HMywgD2tEY04YSzZz +7ZE9svEavvulNlWk/ZXZ8Fw97I8dZYjb7Ij9/cEYisltTeILCBLqwOnIlHqbgEb tTjRHXtGZ8ljCtTniq5D1giauHp15/h+ThU9eNYLnDt+F5BuW/XIEv786jlP2S/J J0z35itUs5b0NRJmpOzP =1zjY -----END PGP SIGNATURE----- Merge tag 'pm+acpi-3.16-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull ACPI and power management fixes from Rafael Wysocki: "These are a few regression fixes for ACPI device enumeration and resources management, intel_pstate and cpufreq, a revert of an ACPI commit removing user space interfaces in /proc that we incorrectly thought were not used any more, fixes for some long-standing concurrency issues in the ACPI EC driver, two ACPI battery driver fixes, stable-candidate fixes for intel_pstate, an ACPI-related fix for i915 and two new ACPI video blacklist entries for Win8-oriented BIOSes. Specifics: - Missing device ID for ACPI enumeration of PNP devices that we overlooked during the recent rework of that code from Zhang Rui. - Fix for a problem introduced during the 3.14 cycle in the ACPI device resources management code and causing it to reject all resources of length 0 although some of them are actually valid which affects serial ports detection on a number of systems. From Andy Whitcroft. - intel_pstate fix for a boot problem on some BayTrail-based systems introduced by a previous fix related to that platform during the 3.13 cycle from Dirk Brandewie. - Revert of a 3.13 commit that removed the ACPI AC /proc interface which turns out to be still needed by some old utilities (kpowersave from kde 3.5.10 in particular) from Lan Tianyu. - cpufreq build fix for the davinci ARM platform from Prabhakar Lad (the breakage was introduced during the 3.10 cycle). - ACPI-related i915 fix preventing firmware on some Thinkpad laptops from setting backlight levels incorrectly during AC plug/unplug. From Aaron Lu. - Fixes for two nasty race conditions in the ACPI embedded controller driver that may be responsible for a number of past bug reports related to the EC from Lv Zhang and a fix for two memory leaks in error code paths in that driver from Colin Ian King. - Fixes for a couple of corner-case issues in the intel_pstate driver (all candidates for -stable) from Dirk Brandewie and Vincent Minet. - Fixes for two corner-case issues in the ACPI battery driver from Josef Gajdusek and Lan Tianyu. - Two new ACPI video blacklist entries for Acer TravelMate B113 and Dell Inspiron 5737 from Edward Lin and Martin Kepplinger" * tag 'pm+acpi-3.16-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: ACPI / PNP: add soc_button_array device ID to PNP IDs list cpufreq: Makefile: fix compilation for davinci platform ACPI / video: Add Acer TravelMate B113 to native backlight blacklist ACPI / video: Add Dell Inspiron 5737 to the blacklist ACPI / i915: ignore firmware requests for backlight change ACPI / battery: fix wrong value of capacity_now reported when fully charged ACPI / resources: only reject zero length resources based at address zero ACPI / battery: Retry to get battery information if failed during probing ACPI / EC: Free saved_ec on error exit path ACPI / EC: Add detailed fields debugging support of EC_SC(R). ACPI / EC: Update revision due to recent changes ACPI / EC: Fix race condition in ec_transaction_completed() ACPI / EC: Remove duplicated ec_wait_ibf0() waiter ACPI / EC: Add asynchronous command byte write support ACPI / EC: Avoid race condition related to advance_transaction() intel_pstate: Set CPU number before accessing MSRs intel_pstate: Update documentation of {max,min}_perf_pct sysfs files intel_pstate: don't touch turbo bit if turbo disabled or unavailable. intel_pstate: Fix setting VID Revert "ACPI / AC: Remove AC's proc directory."
This commit is contained in:
commit
b67db9d5e1
|
@ -15,10 +15,13 @@ New sysfs files for controlling P state selection have been added to
|
||||||
/sys/devices/system/cpu/intel_pstate/
|
/sys/devices/system/cpu/intel_pstate/
|
||||||
|
|
||||||
max_perf_pct: limits the maximum P state that will be requested by
|
max_perf_pct: limits the maximum P state that will be requested by
|
||||||
the driver stated as a percentage of the available performance.
|
the driver stated as a percentage of the available performance. The
|
||||||
|
available (P states) performance may be reduced by the no_turbo
|
||||||
|
setting described below.
|
||||||
|
|
||||||
min_perf_pct: limits the minimum P state that will be requested by
|
min_perf_pct: limits the minimum P state that will be requested by
|
||||||
the driver stated as a percentage of the available performance.
|
the driver stated as a percentage of the max (non-turbo)
|
||||||
|
performance level.
|
||||||
|
|
||||||
no_turbo: limits the driver to selecting P states below the turbo
|
no_turbo: limits the driver to selecting P states below the turbo
|
||||||
frequency range.
|
frequency range.
|
||||||
|
|
|
@ -30,6 +30,10 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/dmi.h>
|
#include <linux/dmi.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||||
|
#include <linux/proc_fs.h>
|
||||||
|
#include <linux/seq_file.h>
|
||||||
|
#endif
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/power_supply.h>
|
#include <linux/power_supply.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
|
@ -52,6 +56,7 @@ MODULE_AUTHOR("Paul Diefenbaugh");
|
||||||
MODULE_DESCRIPTION("ACPI AC Adapter Driver");
|
MODULE_DESCRIPTION("ACPI AC Adapter Driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
|
||||||
static int acpi_ac_add(struct acpi_device *device);
|
static int acpi_ac_add(struct acpi_device *device);
|
||||||
static int acpi_ac_remove(struct acpi_device *device);
|
static int acpi_ac_remove(struct acpi_device *device);
|
||||||
static void acpi_ac_notify(struct acpi_device *device, u32 event);
|
static void acpi_ac_notify(struct acpi_device *device, u32 event);
|
||||||
|
@ -67,6 +72,13 @@ static int acpi_ac_resume(struct device *dev);
|
||||||
#endif
|
#endif
|
||||||
static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume);
|
static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume);
|
||||||
|
|
||||||
|
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||||
|
extern struct proc_dir_entry *acpi_lock_ac_dir(void);
|
||||||
|
extern void *acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
|
||||||
|
static int acpi_ac_open_fs(struct inode *inode, struct file *file);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static int ac_sleep_before_get_state_ms;
|
static int ac_sleep_before_get_state_ms;
|
||||||
|
|
||||||
static struct acpi_driver acpi_ac_driver = {
|
static struct acpi_driver acpi_ac_driver = {
|
||||||
|
@ -91,6 +103,16 @@ struct acpi_ac {
|
||||||
|
|
||||||
#define to_acpi_ac(x) container_of(x, struct acpi_ac, charger)
|
#define to_acpi_ac(x) container_of(x, struct acpi_ac, charger)
|
||||||
|
|
||||||
|
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||||
|
static const struct file_operations acpi_ac_fops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.open = acpi_ac_open_fs,
|
||||||
|
.read = seq_read,
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = single_release,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------
|
||||||
AC Adapter Management
|
AC Adapter Management
|
||||||
-------------------------------------------------------------------------- */
|
-------------------------------------------------------------------------- */
|
||||||
|
@ -143,6 +165,83 @@ static enum power_supply_property ac_props[] = {
|
||||||
POWER_SUPPLY_PROP_ONLINE,
|
POWER_SUPPLY_PROP_ONLINE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||||
|
/* --------------------------------------------------------------------------
|
||||||
|
FS Interface (/proc)
|
||||||
|
-------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static struct proc_dir_entry *acpi_ac_dir;
|
||||||
|
|
||||||
|
static int acpi_ac_seq_show(struct seq_file *seq, void *offset)
|
||||||
|
{
|
||||||
|
struct acpi_ac *ac = seq->private;
|
||||||
|
|
||||||
|
|
||||||
|
if (!ac)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (acpi_ac_get_state(ac)) {
|
||||||
|
seq_puts(seq, "ERROR: Unable to read AC Adapter state\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
seq_puts(seq, "state: ");
|
||||||
|
switch (ac->state) {
|
||||||
|
case ACPI_AC_STATUS_OFFLINE:
|
||||||
|
seq_puts(seq, "off-line\n");
|
||||||
|
break;
|
||||||
|
case ACPI_AC_STATUS_ONLINE:
|
||||||
|
seq_puts(seq, "on-line\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
seq_puts(seq, "unknown\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int acpi_ac_open_fs(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return single_open(file, acpi_ac_seq_show, PDE_DATA(inode));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int acpi_ac_add_fs(struct acpi_ac *ac)
|
||||||
|
{
|
||||||
|
struct proc_dir_entry *entry = NULL;
|
||||||
|
|
||||||
|
printk(KERN_WARNING PREFIX "Deprecated procfs I/F for AC is loaded,"
|
||||||
|
" please retry with CONFIG_ACPI_PROCFS_POWER cleared\n");
|
||||||
|
if (!acpi_device_dir(ac->device)) {
|
||||||
|
acpi_device_dir(ac->device) =
|
||||||
|
proc_mkdir(acpi_device_bid(ac->device), acpi_ac_dir);
|
||||||
|
if (!acpi_device_dir(ac->device))
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 'state' [R] */
|
||||||
|
entry = proc_create_data(ACPI_AC_FILE_STATE,
|
||||||
|
S_IRUGO, acpi_device_dir(ac->device),
|
||||||
|
&acpi_ac_fops, ac);
|
||||||
|
if (!entry)
|
||||||
|
return -ENODEV;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int acpi_ac_remove_fs(struct acpi_ac *ac)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (acpi_device_dir(ac->device)) {
|
||||||
|
remove_proc_entry(ACPI_AC_FILE_STATE,
|
||||||
|
acpi_device_dir(ac->device));
|
||||||
|
remove_proc_entry(acpi_device_bid(ac->device), acpi_ac_dir);
|
||||||
|
acpi_device_dir(ac->device) = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------
|
||||||
Driver Model
|
Driver Model
|
||||||
-------------------------------------------------------------------------- */
|
-------------------------------------------------------------------------- */
|
||||||
|
@ -243,6 +342,11 @@ static int acpi_ac_add(struct acpi_device *device)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
ac->charger.name = acpi_device_bid(device);
|
ac->charger.name = acpi_device_bid(device);
|
||||||
|
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||||
|
result = acpi_ac_add_fs(ac);
|
||||||
|
if (result)
|
||||||
|
goto end;
|
||||||
|
#endif
|
||||||
ac->charger.type = POWER_SUPPLY_TYPE_MAINS;
|
ac->charger.type = POWER_SUPPLY_TYPE_MAINS;
|
||||||
ac->charger.properties = ac_props;
|
ac->charger.properties = ac_props;
|
||||||
ac->charger.num_properties = ARRAY_SIZE(ac_props);
|
ac->charger.num_properties = ARRAY_SIZE(ac_props);
|
||||||
|
@ -258,8 +362,12 @@ static int acpi_ac_add(struct acpi_device *device)
|
||||||
ac->battery_nb.notifier_call = acpi_ac_battery_notify;
|
ac->battery_nb.notifier_call = acpi_ac_battery_notify;
|
||||||
register_acpi_notifier(&ac->battery_nb);
|
register_acpi_notifier(&ac->battery_nb);
|
||||||
end:
|
end:
|
||||||
if (result)
|
if (result) {
|
||||||
|
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||||
|
acpi_ac_remove_fs(ac);
|
||||||
|
#endif
|
||||||
kfree(ac);
|
kfree(ac);
|
||||||
|
}
|
||||||
|
|
||||||
dmi_check_system(ac_dmi_table);
|
dmi_check_system(ac_dmi_table);
|
||||||
return result;
|
return result;
|
||||||
|
@ -303,6 +411,10 @@ static int acpi_ac_remove(struct acpi_device *device)
|
||||||
power_supply_unregister(&ac->charger);
|
power_supply_unregister(&ac->charger);
|
||||||
unregister_acpi_notifier(&ac->battery_nb);
|
unregister_acpi_notifier(&ac->battery_nb);
|
||||||
|
|
||||||
|
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||||
|
acpi_ac_remove_fs(ac);
|
||||||
|
#endif
|
||||||
|
|
||||||
kfree(ac);
|
kfree(ac);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -315,9 +427,20 @@ static int __init acpi_ac_init(void)
|
||||||
if (acpi_disabled)
|
if (acpi_disabled)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
result = acpi_bus_register_driver(&acpi_ac_driver);
|
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||||
if (result < 0)
|
acpi_ac_dir = acpi_lock_ac_dir();
|
||||||
|
if (!acpi_ac_dir)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
result = acpi_bus_register_driver(&acpi_ac_driver);
|
||||||
|
if (result < 0) {
|
||||||
|
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||||
|
acpi_unlock_ac_dir(acpi_ac_dir);
|
||||||
|
#endif
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -325,6 +448,9 @@ static int __init acpi_ac_init(void)
|
||||||
static void __exit acpi_ac_exit(void)
|
static void __exit acpi_ac_exit(void)
|
||||||
{
|
{
|
||||||
acpi_bus_unregister_driver(&acpi_ac_driver);
|
acpi_bus_unregister_driver(&acpi_ac_driver);
|
||||||
|
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||||
|
acpi_unlock_ac_dir(acpi_ac_dir);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
module_init(acpi_ac_init);
|
module_init(acpi_ac_init);
|
||||||
module_exit(acpi_ac_exit);
|
module_exit(acpi_ac_exit);
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
|
||||||
static const struct acpi_device_id acpi_pnp_device_ids[] = {
|
static const struct acpi_device_id acpi_pnp_device_ids[] = {
|
||||||
|
/* soc_button_array */
|
||||||
|
{"PNP0C40"},
|
||||||
/* pata_isapnp */
|
/* pata_isapnp */
|
||||||
{"PNP0600"}, /* Generic ESDI/IDE/ATA compatible hard disk controller */
|
{"PNP0600"}, /* Generic ESDI/IDE/ATA compatible hard disk controller */
|
||||||
/* floppy */
|
/* floppy */
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||||
|
@ -534,6 +535,20 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
|
||||||
" invalid.\n");
|
" invalid.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When fully charged, some batteries wrongly report
|
||||||
|
* capacity_now = design_capacity instead of = full_charge_capacity
|
||||||
|
*/
|
||||||
|
if (battery->capacity_now > battery->full_charge_capacity
|
||||||
|
&& battery->full_charge_capacity != ACPI_BATTERY_VALUE_UNKNOWN) {
|
||||||
|
battery->capacity_now = battery->full_charge_capacity;
|
||||||
|
if (battery->capacity_now != battery->design_capacity)
|
||||||
|
printk_once(KERN_WARNING FW_BUG
|
||||||
|
"battery: reported current charge level (%d) "
|
||||||
|
"is higher than reported maximum charge level (%d).\n",
|
||||||
|
battery->capacity_now, battery->full_charge_capacity);
|
||||||
|
}
|
||||||
|
|
||||||
if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)
|
if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)
|
||||||
&& battery->capacity_now >= 0 && battery->capacity_now <= 100)
|
&& battery->capacity_now >= 0 && battery->capacity_now <= 100)
|
||||||
battery->capacity_now = (battery->capacity_now *
|
battery->capacity_now = (battery->capacity_now *
|
||||||
|
@ -1151,6 +1166,28 @@ static struct dmi_system_id bat_dmi_table[] = {
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some machines'(E,G Lenovo Z480) ECs are not stable
|
||||||
|
* during boot up and this causes battery driver fails to be
|
||||||
|
* probed due to failure of getting battery information
|
||||||
|
* from EC sometimes. After several retries, the operation
|
||||||
|
* may work. So add retry code here and 20ms sleep between
|
||||||
|
* every retries.
|
||||||
|
*/
|
||||||
|
static int acpi_battery_update_retry(struct acpi_battery *battery)
|
||||||
|
{
|
||||||
|
int retry, ret;
|
||||||
|
|
||||||
|
for (retry = 5; retry; retry--) {
|
||||||
|
ret = acpi_battery_update(battery, false);
|
||||||
|
if (!ret)
|
||||||
|
break;
|
||||||
|
|
||||||
|
msleep(20);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int acpi_battery_add(struct acpi_device *device)
|
static int acpi_battery_add(struct acpi_device *device)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
@ -1169,9 +1206,11 @@ static int acpi_battery_add(struct acpi_device *device)
|
||||||
mutex_init(&battery->sysfs_lock);
|
mutex_init(&battery->sysfs_lock);
|
||||||
if (acpi_has_method(battery->device->handle, "_BIX"))
|
if (acpi_has_method(battery->device->handle, "_BIX"))
|
||||||
set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
|
set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
|
||||||
result = acpi_battery_update(battery, false);
|
|
||||||
|
result = acpi_battery_update_retry(battery);
|
||||||
if (result)
|
if (result)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||||
result = acpi_battery_add_fs(device);
|
result = acpi_battery_add_fs(device);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
/*
|
/*
|
||||||
* ec.c - ACPI Embedded Controller Driver (v2.1)
|
* ec.c - ACPI Embedded Controller Driver (v2.2)
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2008 Alexey Starikovskiy <astarikovskiy@suse.de>
|
* Copyright (C) 2001-2014 Intel Corporation
|
||||||
* Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
|
* Author: 2014 Lv Zheng <lv.zheng@intel.com>
|
||||||
* Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
|
* 2006, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
|
||||||
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
|
* 2006 Denis Sadykov <denis.m.sadykov@intel.com>
|
||||||
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
|
* 2004 Luming Yu <luming.yu@intel.com>
|
||||||
|
* 2001, 2002 Andy Grover <andrew.grover@intel.com>
|
||||||
|
* 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
|
||||||
|
* Copyright (C) 2008 Alexey Starikovskiy <astarikovskiy@suse.de>
|
||||||
*
|
*
|
||||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
*
|
*
|
||||||
|
@ -52,6 +55,7 @@
|
||||||
/* EC status register */
|
/* EC status register */
|
||||||
#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */
|
#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */
|
||||||
#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */
|
#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */
|
||||||
|
#define ACPI_EC_FLAG_CMD 0x08 /* Input buffer contains a command */
|
||||||
#define ACPI_EC_FLAG_BURST 0x10 /* burst mode */
|
#define ACPI_EC_FLAG_BURST 0x10 /* burst mode */
|
||||||
#define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */
|
#define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */
|
||||||
|
|
||||||
|
@ -78,6 +82,9 @@ enum {
|
||||||
EC_FLAGS_BLOCKED, /* Transactions are blocked */
|
EC_FLAGS_BLOCKED, /* Transactions are blocked */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */
|
||||||
|
#define ACPI_EC_COMMAND_COMPLETE 0x02 /* Completed last byte */
|
||||||
|
|
||||||
/* ec.c is compiled in acpi namespace so this shows up as acpi.ec_delay param */
|
/* ec.c is compiled in acpi namespace so this shows up as acpi.ec_delay param */
|
||||||
static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
|
static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
|
||||||
module_param(ec_delay, uint, 0644);
|
module_param(ec_delay, uint, 0644);
|
||||||
|
@ -109,7 +116,7 @@ struct transaction {
|
||||||
u8 ri;
|
u8 ri;
|
||||||
u8 wlen;
|
u8 wlen;
|
||||||
u8 rlen;
|
u8 rlen;
|
||||||
bool done;
|
u8 flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct acpi_ec *boot_ec, *first_ec;
|
struct acpi_ec *boot_ec, *first_ec;
|
||||||
|
@ -127,83 +134,104 @@ static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
|
||||||
static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
|
static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
|
||||||
{
|
{
|
||||||
u8 x = inb(ec->command_addr);
|
u8 x = inb(ec->command_addr);
|
||||||
pr_debug("---> status = 0x%2.2x\n", x);
|
pr_debug("EC_SC(R) = 0x%2.2x "
|
||||||
|
"SCI_EVT=%d BURST=%d CMD=%d IBF=%d OBF=%d\n",
|
||||||
|
x,
|
||||||
|
!!(x & ACPI_EC_FLAG_SCI),
|
||||||
|
!!(x & ACPI_EC_FLAG_BURST),
|
||||||
|
!!(x & ACPI_EC_FLAG_CMD),
|
||||||
|
!!(x & ACPI_EC_FLAG_IBF),
|
||||||
|
!!(x & ACPI_EC_FLAG_OBF));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
|
static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
|
||||||
{
|
{
|
||||||
u8 x = inb(ec->data_addr);
|
u8 x = inb(ec->data_addr);
|
||||||
pr_debug("---> data = 0x%2.2x\n", x);
|
pr_debug("EC_DATA(R) = 0x%2.2x\n", x);
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
|
static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
|
||||||
{
|
{
|
||||||
pr_debug("<--- command = 0x%2.2x\n", command);
|
pr_debug("EC_SC(W) = 0x%2.2x\n", command);
|
||||||
outb(command, ec->command_addr);
|
outb(command, ec->command_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
|
static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
|
||||||
{
|
{
|
||||||
pr_debug("<--- data = 0x%2.2x\n", data);
|
pr_debug("EC_DATA(W) = 0x%2.2x\n", data);
|
||||||
outb(data, ec->data_addr);
|
outb(data, ec->data_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ec_transaction_done(struct acpi_ec *ec)
|
static int ec_transaction_completed(struct acpi_ec *ec)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
spin_lock_irqsave(&ec->lock, flags);
|
spin_lock_irqsave(&ec->lock, flags);
|
||||||
if (!ec->curr || ec->curr->done)
|
if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE))
|
||||||
ret = 1;
|
ret = 1;
|
||||||
spin_unlock_irqrestore(&ec->lock, flags);
|
spin_unlock_irqrestore(&ec->lock, flags);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start_transaction(struct acpi_ec *ec)
|
static bool advance_transaction(struct acpi_ec *ec)
|
||||||
{
|
{
|
||||||
ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0;
|
|
||||||
ec->curr->done = false;
|
|
||||||
acpi_ec_write_cmd(ec, ec->curr->command);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void advance_transaction(struct acpi_ec *ec, u8 status)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
struct transaction *t;
|
struct transaction *t;
|
||||||
|
u8 status;
|
||||||
|
bool wakeup = false;
|
||||||
|
|
||||||
spin_lock_irqsave(&ec->lock, flags);
|
pr_debug("===== %s =====\n", in_interrupt() ? "IRQ" : "TASK");
|
||||||
|
status = acpi_ec_read_status(ec);
|
||||||
t = ec->curr;
|
t = ec->curr;
|
||||||
if (!t)
|
if (!t)
|
||||||
goto unlock;
|
goto err;
|
||||||
if (t->wlen > t->wi) {
|
if (t->flags & ACPI_EC_COMMAND_POLL) {
|
||||||
if ((status & ACPI_EC_FLAG_IBF) == 0)
|
if (t->wlen > t->wi) {
|
||||||
acpi_ec_write_data(ec,
|
if ((status & ACPI_EC_FLAG_IBF) == 0)
|
||||||
t->wdata[t->wi++]);
|
acpi_ec_write_data(ec, t->wdata[t->wi++]);
|
||||||
else
|
else
|
||||||
goto err;
|
goto err;
|
||||||
} else if (t->rlen > t->ri) {
|
} else if (t->rlen > t->ri) {
|
||||||
if ((status & ACPI_EC_FLAG_OBF) == 1) {
|
if ((status & ACPI_EC_FLAG_OBF) == 1) {
|
||||||
t->rdata[t->ri++] = acpi_ec_read_data(ec);
|
t->rdata[t->ri++] = acpi_ec_read_data(ec);
|
||||||
if (t->rlen == t->ri)
|
if (t->rlen == t->ri) {
|
||||||
t->done = true;
|
t->flags |= ACPI_EC_COMMAND_COMPLETE;
|
||||||
|
wakeup = true;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
goto err;
|
||||||
|
} else if (t->wlen == t->wi &&
|
||||||
|
(status & ACPI_EC_FLAG_IBF) == 0) {
|
||||||
|
t->flags |= ACPI_EC_COMMAND_COMPLETE;
|
||||||
|
wakeup = true;
|
||||||
|
}
|
||||||
|
return wakeup;
|
||||||
|
} else {
|
||||||
|
if ((status & ACPI_EC_FLAG_IBF) == 0) {
|
||||||
|
acpi_ec_write_cmd(ec, t->command);
|
||||||
|
t->flags |= ACPI_EC_COMMAND_POLL;
|
||||||
} else
|
} else
|
||||||
goto err;
|
goto err;
|
||||||
} else if (t->wlen == t->wi &&
|
return wakeup;
|
||||||
(status & ACPI_EC_FLAG_IBF) == 0)
|
}
|
||||||
t->done = true;
|
|
||||||
goto unlock;
|
|
||||||
err:
|
err:
|
||||||
/*
|
/*
|
||||||
* If SCI bit is set, then don't think it's a false IRQ
|
* If SCI bit is set, then don't think it's a false IRQ
|
||||||
* otherwise will take a not handled IRQ as a false one.
|
* otherwise will take a not handled IRQ as a false one.
|
||||||
*/
|
*/
|
||||||
if (in_interrupt() && !(status & ACPI_EC_FLAG_SCI))
|
if (!(status & ACPI_EC_FLAG_SCI)) {
|
||||||
++t->irq_count;
|
if (in_interrupt() && t)
|
||||||
|
++t->irq_count;
|
||||||
|
}
|
||||||
|
return wakeup;
|
||||||
|
}
|
||||||
|
|
||||||
unlock:
|
static void start_transaction(struct acpi_ec *ec)
|
||||||
spin_unlock_irqrestore(&ec->lock, flags);
|
{
|
||||||
|
ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0;
|
||||||
|
ec->curr->flags = 0;
|
||||||
|
(void)advance_transaction(ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data);
|
static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data);
|
||||||
|
@ -228,15 +256,17 @@ static int ec_poll(struct acpi_ec *ec)
|
||||||
/* don't sleep with disabled interrupts */
|
/* don't sleep with disabled interrupts */
|
||||||
if (EC_FLAGS_MSI || irqs_disabled()) {
|
if (EC_FLAGS_MSI || irqs_disabled()) {
|
||||||
udelay(ACPI_EC_MSI_UDELAY);
|
udelay(ACPI_EC_MSI_UDELAY);
|
||||||
if (ec_transaction_done(ec))
|
if (ec_transaction_completed(ec))
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
if (wait_event_timeout(ec->wait,
|
if (wait_event_timeout(ec->wait,
|
||||||
ec_transaction_done(ec),
|
ec_transaction_completed(ec),
|
||||||
msecs_to_jiffies(1)))
|
msecs_to_jiffies(1)))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
advance_transaction(ec, acpi_ec_read_status(ec));
|
spin_lock_irqsave(&ec->lock, flags);
|
||||||
|
(void)advance_transaction(ec);
|
||||||
|
spin_unlock_irqrestore(&ec->lock, flags);
|
||||||
} while (time_before(jiffies, delay));
|
} while (time_before(jiffies, delay));
|
||||||
pr_debug("controller reset, restart transaction\n");
|
pr_debug("controller reset, restart transaction\n");
|
||||||
spin_lock_irqsave(&ec->lock, flags);
|
spin_lock_irqsave(&ec->lock, flags);
|
||||||
|
@ -268,23 +298,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ec_check_ibf0(struct acpi_ec *ec)
|
|
||||||
{
|
|
||||||
u8 status = acpi_ec_read_status(ec);
|
|
||||||
return (status & ACPI_EC_FLAG_IBF) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ec_wait_ibf0(struct acpi_ec *ec)
|
|
||||||
{
|
|
||||||
unsigned long delay = jiffies + msecs_to_jiffies(ec_delay);
|
|
||||||
/* interrupt wait manually if GPE mode is not active */
|
|
||||||
while (time_before(jiffies, delay))
|
|
||||||
if (wait_event_timeout(ec->wait, ec_check_ibf0(ec),
|
|
||||||
msecs_to_jiffies(1)))
|
|
||||||
return 0;
|
|
||||||
return -ETIME;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
|
static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
|
@ -305,12 +318,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ec_wait_ibf0(ec)) {
|
|
||||||
pr_err("input buffer is not empty, "
|
|
||||||
"aborting transaction\n");
|
|
||||||
status = -ETIME;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
pr_debug("transaction start (cmd=0x%02x, addr=0x%02x)\n",
|
pr_debug("transaction start (cmd=0x%02x, addr=0x%02x)\n",
|
||||||
t->command, t->wdata ? t->wdata[0] : 0);
|
t->command, t->wdata ? t->wdata[0] : 0);
|
||||||
/* disable GPE during transaction if storm is detected */
|
/* disable GPE during transaction if storm is detected */
|
||||||
|
@ -334,7 +341,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
|
||||||
set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
|
set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
|
||||||
}
|
}
|
||||||
pr_debug("transaction end\n");
|
pr_debug("transaction end\n");
|
||||||
end:
|
|
||||||
if (ec->global_lock)
|
if (ec->global_lock)
|
||||||
acpi_release_global_lock(glk);
|
acpi_release_global_lock(glk);
|
||||||
unlock:
|
unlock:
|
||||||
|
@ -634,17 +640,14 @@ static int ec_check_sci(struct acpi_ec *ec, u8 state)
|
||||||
static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
|
static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
|
||||||
u32 gpe_number, void *data)
|
u32 gpe_number, void *data)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
struct acpi_ec *ec = data;
|
struct acpi_ec *ec = data;
|
||||||
u8 status = acpi_ec_read_status(ec);
|
|
||||||
|
|
||||||
pr_debug("~~~> interrupt, status:0x%02x\n", status);
|
spin_lock_irqsave(&ec->lock, flags);
|
||||||
|
if (advance_transaction(ec))
|
||||||
advance_transaction(ec, status);
|
|
||||||
if (ec_transaction_done(ec) &&
|
|
||||||
(acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) {
|
|
||||||
wake_up(&ec->wait);
|
wake_up(&ec->wait);
|
||||||
ec_check_sci(ec, acpi_ec_read_status(ec));
|
spin_unlock_irqrestore(&ec->lock, flags);
|
||||||
}
|
ec_check_sci(ec, acpi_ec_read_status(ec));
|
||||||
return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
|
return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1066,8 +1069,10 @@ int __init acpi_ec_ecdt_probe(void)
|
||||||
/* fall through */
|
/* fall through */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EC_FLAGS_SKIP_DSDT_SCAN)
|
if (EC_FLAGS_SKIP_DSDT_SCAN) {
|
||||||
|
kfree(saved_ec);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
/* This workaround is needed only on some broken machines,
|
/* This workaround is needed only on some broken machines,
|
||||||
* which require early EC, but fail to provide ECDT */
|
* which require early EC, but fail to provide ECDT */
|
||||||
|
@ -1105,6 +1110,7 @@ install:
|
||||||
}
|
}
|
||||||
error:
|
error:
|
||||||
kfree(boot_ec);
|
kfree(boot_ec);
|
||||||
|
kfree(saved_ec);
|
||||||
boot_ec = NULL;
|
boot_ec = NULL;
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
|
||||||
switch (ares->type) {
|
switch (ares->type) {
|
||||||
case ACPI_RESOURCE_TYPE_MEMORY24:
|
case ACPI_RESOURCE_TYPE_MEMORY24:
|
||||||
memory24 = &ares->data.memory24;
|
memory24 = &ares->data.memory24;
|
||||||
if (!memory24->address_length)
|
if (!memory24->minimum && !memory24->address_length)
|
||||||
return false;
|
return false;
|
||||||
acpi_dev_get_memresource(res, memory24->minimum,
|
acpi_dev_get_memresource(res, memory24->minimum,
|
||||||
memory24->address_length,
|
memory24->address_length,
|
||||||
|
@ -85,7 +85,7 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
|
||||||
break;
|
break;
|
||||||
case ACPI_RESOURCE_TYPE_MEMORY32:
|
case ACPI_RESOURCE_TYPE_MEMORY32:
|
||||||
memory32 = &ares->data.memory32;
|
memory32 = &ares->data.memory32;
|
||||||
if (!memory32->address_length)
|
if (!memory32->minimum && !memory32->address_length)
|
||||||
return false;
|
return false;
|
||||||
acpi_dev_get_memresource(res, memory32->minimum,
|
acpi_dev_get_memresource(res, memory32->minimum,
|
||||||
memory32->address_length,
|
memory32->address_length,
|
||||||
|
@ -93,7 +93,7 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
|
||||||
break;
|
break;
|
||||||
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
|
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
|
||||||
fixed_memory32 = &ares->data.fixed_memory32;
|
fixed_memory32 = &ares->data.fixed_memory32;
|
||||||
if (!fixed_memory32->address_length)
|
if (!fixed_memory32->address && !fixed_memory32->address_length)
|
||||||
return false;
|
return false;
|
||||||
acpi_dev_get_memresource(res, fixed_memory32->address,
|
acpi_dev_get_memresource(res, fixed_memory32->address,
|
||||||
fixed_memory32->address_length,
|
fixed_memory32->address_length,
|
||||||
|
@ -150,7 +150,7 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res)
|
||||||
switch (ares->type) {
|
switch (ares->type) {
|
||||||
case ACPI_RESOURCE_TYPE_IO:
|
case ACPI_RESOURCE_TYPE_IO:
|
||||||
io = &ares->data.io;
|
io = &ares->data.io;
|
||||||
if (!io->address_length)
|
if (!io->minimum && !io->address_length)
|
||||||
return false;
|
return false;
|
||||||
acpi_dev_get_ioresource(res, io->minimum,
|
acpi_dev_get_ioresource(res, io->minimum,
|
||||||
io->address_length,
|
io->address_length,
|
||||||
|
@ -158,7 +158,7 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res)
|
||||||
break;
|
break;
|
||||||
case ACPI_RESOURCE_TYPE_FIXED_IO:
|
case ACPI_RESOURCE_TYPE_FIXED_IO:
|
||||||
fixed_io = &ares->data.fixed_io;
|
fixed_io = &ares->data.fixed_io;
|
||||||
if (!fixed_io->address_length)
|
if (!fixed_io->address && !fixed_io->address_length)
|
||||||
return false;
|
return false;
|
||||||
acpi_dev_get_ioresource(res, fixed_io->address,
|
acpi_dev_get_ioresource(res, fixed_io->address,
|
||||||
fixed_io->address_length,
|
fixed_io->address_length,
|
||||||
|
|
|
@ -241,13 +241,14 @@ static bool acpi_video_use_native_backlight(void)
|
||||||
return use_native_backlight_dmi;
|
return use_native_backlight_dmi;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool acpi_video_verify_backlight_support(void)
|
bool acpi_video_verify_backlight_support(void)
|
||||||
{
|
{
|
||||||
if (acpi_osi_is_win8() && acpi_video_use_native_backlight() &&
|
if (acpi_osi_is_win8() && acpi_video_use_native_backlight() &&
|
||||||
backlight_device_registered(BACKLIGHT_RAW))
|
backlight_device_registered(BACKLIGHT_RAW))
|
||||||
return false;
|
return false;
|
||||||
return acpi_video_backlight_support();
|
return acpi_video_backlight_support();
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(acpi_video_verify_backlight_support);
|
||||||
|
|
||||||
/* backlight device sysfs support */
|
/* backlight device sysfs support */
|
||||||
static int acpi_video_get_brightness(struct backlight_device *bd)
|
static int acpi_video_get_brightness(struct backlight_device *bd)
|
||||||
|
@ -562,6 +563,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
|
||||||
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-471G"),
|
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-471G"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.callback = video_set_use_native_backlight,
|
||||||
|
.ident = "Acer TravelMate B113",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate B113"),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.callback = video_set_use_native_backlight,
|
.callback = video_set_use_native_backlight,
|
||||||
.ident = "HP ProBook 4340s",
|
.ident = "HP ProBook 4340s",
|
||||||
|
|
|
@ -166,6 +166,14 @@ static struct dmi_system_id video_detect_dmi_table[] = {
|
||||||
DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
|
DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.callback = video_detect_force_vendor,
|
||||||
|
.ident = "Dell Inspiron 5737",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5737"),
|
||||||
|
},
|
||||||
|
},
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ) += arm_big_little.o
|
||||||
# LITTLE drivers, so that it is probed last.
|
# LITTLE drivers, so that it is probed last.
|
||||||
obj-$(CONFIG_ARM_DT_BL_CPUFREQ) += arm_big_little_dt.o
|
obj-$(CONFIG_ARM_DT_BL_CPUFREQ) += arm_big_little_dt.o
|
||||||
|
|
||||||
obj-$(CONFIG_ARCH_DAVINCI_DA850) += davinci-cpufreq.o
|
obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o
|
||||||
obj-$(CONFIG_UX500_SOC_DB8500) += dbx500-cpufreq.o
|
obj-$(CONFIG_UX500_SOC_DB8500) += dbx500-cpufreq.o
|
||||||
obj-$(CONFIG_ARM_EXYNOS_CPUFREQ) += exynos-cpufreq.o
|
obj-$(CONFIG_ARM_EXYNOS_CPUFREQ) += exynos-cpufreq.o
|
||||||
obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o
|
obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o
|
||||||
|
|
|
@ -128,6 +128,7 @@ static struct pstate_funcs pstate_funcs;
|
||||||
|
|
||||||
struct perf_limits {
|
struct perf_limits {
|
||||||
int no_turbo;
|
int no_turbo;
|
||||||
|
int turbo_disabled;
|
||||||
int max_perf_pct;
|
int max_perf_pct;
|
||||||
int min_perf_pct;
|
int min_perf_pct;
|
||||||
int32_t max_perf;
|
int32_t max_perf;
|
||||||
|
@ -287,7 +288,10 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
|
||||||
if (ret != 1)
|
if (ret != 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
limits.no_turbo = clamp_t(int, input, 0 , 1);
|
limits.no_turbo = clamp_t(int, input, 0 , 1);
|
||||||
|
if (limits.turbo_disabled) {
|
||||||
|
pr_warn("Turbo disabled by BIOS or unavailable on processor\n");
|
||||||
|
limits.no_turbo = limits.turbo_disabled;
|
||||||
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,21 +361,21 @@ static int byt_get_min_pstate(void)
|
||||||
{
|
{
|
||||||
u64 value;
|
u64 value;
|
||||||
rdmsrl(BYT_RATIOS, value);
|
rdmsrl(BYT_RATIOS, value);
|
||||||
return (value >> 8) & 0x3F;
|
return (value >> 8) & 0x7F;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int byt_get_max_pstate(void)
|
static int byt_get_max_pstate(void)
|
||||||
{
|
{
|
||||||
u64 value;
|
u64 value;
|
||||||
rdmsrl(BYT_RATIOS, value);
|
rdmsrl(BYT_RATIOS, value);
|
||||||
return (value >> 16) & 0x3F;
|
return (value >> 16) & 0x7F;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int byt_get_turbo_pstate(void)
|
static int byt_get_turbo_pstate(void)
|
||||||
{
|
{
|
||||||
u64 value;
|
u64 value;
|
||||||
rdmsrl(BYT_TURBO_RATIOS, value);
|
rdmsrl(BYT_TURBO_RATIOS, value);
|
||||||
return value & 0x3F;
|
return value & 0x7F;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void byt_set_pstate(struct cpudata *cpudata, int pstate)
|
static void byt_set_pstate(struct cpudata *cpudata, int pstate)
|
||||||
|
@ -381,7 +385,7 @@ static void byt_set_pstate(struct cpudata *cpudata, int pstate)
|
||||||
u32 vid;
|
u32 vid;
|
||||||
|
|
||||||
val = pstate << 8;
|
val = pstate << 8;
|
||||||
if (limits.no_turbo)
|
if (limits.no_turbo && !limits.turbo_disabled)
|
||||||
val |= (u64)1 << 32;
|
val |= (u64)1 << 32;
|
||||||
|
|
||||||
vid_fp = cpudata->vid.min + mul_fp(
|
vid_fp = cpudata->vid.min + mul_fp(
|
||||||
|
@ -405,8 +409,8 @@ static void byt_get_vid(struct cpudata *cpudata)
|
||||||
|
|
||||||
|
|
||||||
rdmsrl(BYT_VIDS, value);
|
rdmsrl(BYT_VIDS, value);
|
||||||
cpudata->vid.min = int_tofp((value >> 8) & 0x3f);
|
cpudata->vid.min = int_tofp((value >> 8) & 0x7f);
|
||||||
cpudata->vid.max = int_tofp((value >> 16) & 0x3f);
|
cpudata->vid.max = int_tofp((value >> 16) & 0x7f);
|
||||||
cpudata->vid.ratio = div_fp(
|
cpudata->vid.ratio = div_fp(
|
||||||
cpudata->vid.max - cpudata->vid.min,
|
cpudata->vid.max - cpudata->vid.min,
|
||||||
int_tofp(cpudata->pstate.max_pstate -
|
int_tofp(cpudata->pstate.max_pstate -
|
||||||
|
@ -448,7 +452,7 @@ static void core_set_pstate(struct cpudata *cpudata, int pstate)
|
||||||
u64 val;
|
u64 val;
|
||||||
|
|
||||||
val = pstate << 8;
|
val = pstate << 8;
|
||||||
if (limits.no_turbo)
|
if (limits.no_turbo && !limits.turbo_disabled)
|
||||||
val |= (u64)1 << 32;
|
val |= (u64)1 << 32;
|
||||||
|
|
||||||
wrmsrl_on_cpu(cpudata->cpu, MSR_IA32_PERF_CTL, val);
|
wrmsrl_on_cpu(cpudata->cpu, MSR_IA32_PERF_CTL, val);
|
||||||
|
@ -696,9 +700,8 @@ static int intel_pstate_init_cpu(unsigned int cpunum)
|
||||||
|
|
||||||
cpu = all_cpu_data[cpunum];
|
cpu = all_cpu_data[cpunum];
|
||||||
|
|
||||||
intel_pstate_get_cpu_pstates(cpu);
|
|
||||||
|
|
||||||
cpu->cpu = cpunum;
|
cpu->cpu = cpunum;
|
||||||
|
intel_pstate_get_cpu_pstates(cpu);
|
||||||
|
|
||||||
init_timer_deferrable(&cpu->timer);
|
init_timer_deferrable(&cpu->timer);
|
||||||
cpu->timer.function = intel_pstate_timer_func;
|
cpu->timer.function = intel_pstate_timer_func;
|
||||||
|
@ -741,7 +744,7 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
|
||||||
limits.min_perf = int_tofp(1);
|
limits.min_perf = int_tofp(1);
|
||||||
limits.max_perf_pct = 100;
|
limits.max_perf_pct = 100;
|
||||||
limits.max_perf = int_tofp(1);
|
limits.max_perf = int_tofp(1);
|
||||||
limits.no_turbo = 0;
|
limits.no_turbo = limits.turbo_disabled;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
limits.min_perf_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
|
limits.min_perf_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
|
||||||
|
@ -784,6 +787,7 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
struct cpudata *cpu;
|
struct cpudata *cpu;
|
||||||
int rc;
|
int rc;
|
||||||
|
u64 misc_en;
|
||||||
|
|
||||||
rc = intel_pstate_init_cpu(policy->cpu);
|
rc = intel_pstate_init_cpu(policy->cpu);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -791,8 +795,13 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
|
||||||
|
|
||||||
cpu = all_cpu_data[policy->cpu];
|
cpu = all_cpu_data[policy->cpu];
|
||||||
|
|
||||||
if (!limits.no_turbo &&
|
rdmsrl(MSR_IA32_MISC_ENABLE, misc_en);
|
||||||
limits.min_perf_pct == 100 && limits.max_perf_pct == 100)
|
if (misc_en & MSR_IA32_MISC_ENABLE_TURBO_DISABLE ||
|
||||||
|
cpu->pstate.max_pstate == cpu->pstate.turbo_pstate) {
|
||||||
|
limits.turbo_disabled = 1;
|
||||||
|
limits.no_turbo = 1;
|
||||||
|
}
|
||||||
|
if (limits.min_perf_pct == 100 && limits.max_perf_pct == 100)
|
||||||
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
|
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
|
||||||
else
|
else
|
||||||
policy->policy = CPUFREQ_POLICY_POWERSAVE;
|
policy->policy = CPUFREQ_POLICY_POWERSAVE;
|
||||||
|
|
|
@ -403,6 +403,15 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
|
||||||
|
|
||||||
DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp);
|
DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the acpi_video interface is not supposed to be used, don't
|
||||||
|
* bother processing backlight level change requests from firmware.
|
||||||
|
*/
|
||||||
|
if (!acpi_video_verify_backlight_support()) {
|
||||||
|
DRM_DEBUG_KMS("opregion backlight request ignored\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(bclp & ASLE_BCLP_VALID))
|
if (!(bclp & ASLE_BCLP_VALID))
|
||||||
return ASLC_BACKLIGHT_FAILED;
|
return ASLC_BACKLIGHT_FAILED;
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ extern void acpi_video_unregister(void);
|
||||||
extern void acpi_video_unregister_backlight(void);
|
extern void acpi_video_unregister_backlight(void);
|
||||||
extern int acpi_video_get_edid(struct acpi_device *device, int type,
|
extern int acpi_video_get_edid(struct acpi_device *device, int type,
|
||||||
int device_id, void **edid);
|
int device_id, void **edid);
|
||||||
|
extern bool acpi_video_verify_backlight_support(void);
|
||||||
#else
|
#else
|
||||||
static inline int acpi_video_register(void) { return 0; }
|
static inline int acpi_video_register(void) { return 0; }
|
||||||
static inline void acpi_video_unregister(void) { return; }
|
static inline void acpi_video_unregister(void) { return; }
|
||||||
|
@ -31,6 +32,7 @@ static inline int acpi_video_get_edid(struct acpi_device *device, int type,
|
||||||
{
|
{
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
static inline bool acpi_video_verify_backlight_support(void) { return false; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue