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:
Linus Torvalds 2014-07-10 18:36:30 -07:00
commit b67db9d5e1
12 changed files with 318 additions and 105 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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 */

View File

@ -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

View File

@ -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;
} }

View File

@ -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,

View File

@ -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",

View File

@ -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"),
},
},
{ }, { },
}; };

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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