Commit b67db9d5 authored by Linus Torvalds's avatar Linus Torvalds

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."
parents 4c718423 20910442
......@@ -15,10 +15,13 @@ New sysfs files for controlling P state selection have been added to
/sys/devices/system/cpu/intel_pstate/
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
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
frequency range.
......
......@@ -30,6 +30,10 @@
#include <linux/types.h>
#include <linux/dmi.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/power_supply.h>
#include <linux/acpi.h>
......@@ -52,6 +56,7 @@ MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION("ACPI AC Adapter Driver");
MODULE_LICENSE("GPL");
static int acpi_ac_add(struct acpi_device *device);
static int acpi_ac_remove(struct acpi_device *device);
static void acpi_ac_notify(struct acpi_device *device, u32 event);
......@@ -67,6 +72,13 @@ static int acpi_ac_resume(struct device *dev);
#endif
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 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)
#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
-------------------------------------------------------------------------- */
......@@ -143,6 +165,83 @@ static enum power_supply_property ac_props[] = {
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
-------------------------------------------------------------------------- */
......@@ -243,6 +342,11 @@ static int acpi_ac_add(struct acpi_device *device)
goto end;
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.properties = 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;
register_acpi_notifier(&ac->battery_nb);
end:
if (result)
if (result) {
#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_ac_remove_fs(ac);
#endif
kfree(ac);
}
dmi_check_system(ac_dmi_table);
return result;
......@@ -303,6 +411,10 @@ static int acpi_ac_remove(struct acpi_device *device)
power_supply_unregister(&ac->charger);
unregister_acpi_notifier(&ac->battery_nb);
#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_ac_remove_fs(ac);
#endif
kfree(ac);
return 0;
......@@ -315,9 +427,20 @@ static int __init acpi_ac_init(void)
if (acpi_disabled)
return -ENODEV;
#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_ac_dir = acpi_lock_ac_dir();
if (!acpi_ac_dir)
return -ENODEV;
#endif
result = acpi_bus_register_driver(&acpi_ac_driver);
if (result < 0)
if (result < 0) {
#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_unlock_ac_dir(acpi_ac_dir);
#endif
return -ENODEV;
}
return 0;
}
......@@ -325,6 +448,9 @@ static int __init acpi_ac_init(void)
static void __exit acpi_ac_exit(void)
{
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_exit(acpi_ac_exit);
......@@ -14,6 +14,8 @@
#include <linux/module.h>
static const struct acpi_device_id acpi_pnp_device_ids[] = {
/* soc_button_array */
{"PNP0C40"},
/* pata_isapnp */
{"PNP0600"}, /* Generic ESDI/IDE/ATA compatible hard disk controller */
/* floppy */
......
......@@ -35,6 +35,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/suspend.h>
#include <linux/delay.h>
#include <asm/unaligned.h>
#ifdef CONFIG_ACPI_PROCFS_POWER
......@@ -534,6 +535,20 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
" 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)
&& battery->capacity_now >= 0 && battery->capacity_now <= 100)
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)
{
int result = 0;
......@@ -1169,9 +1206,11 @@ static int acpi_battery_add(struct acpi_device *device)
mutex_init(&battery->sysfs_lock);
if (acpi_has_method(battery->device->handle, "_BIX"))
set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
result = acpi_battery_update(battery, false);
result = acpi_battery_update_retry(battery);
if (result)
goto fail;
#ifdef CONFIG_ACPI_PROCFS_POWER
result = acpi_battery_add_fs(device);
#endif
......
/*
* 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) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
* Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
* Copyright (C) 2001-2014 Intel Corporation
* Author: 2014 Lv Zheng <lv.zheng@intel.com>
* 2006, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
* 2006 Denis Sadykov <denis.m.sadykov@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 */
#define ACPI_EC_FLAG_OBF 0x01 /* Output 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_SCI 0x20 /* EC-SCI occurred */
......@@ -78,6 +82,9 @@ enum {
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 */
static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
module_param(ec_delay, uint, 0644);
......@@ -109,7 +116,7 @@ struct transaction {
u8 ri;
u8 wlen;
u8 rlen;
bool done;
u8 flags;
};
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)
{
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;
}
static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
{
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;
}
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);
}
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);
}
static int ec_transaction_done(struct acpi_ec *ec)
static int ec_transaction_completed(struct acpi_ec *ec)
{
unsigned long flags;
int ret = 0;
spin_lock_irqsave(&ec->lock, flags);
if (!ec->curr || ec->curr->done)
if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE))
ret = 1;
spin_unlock_irqrestore(&ec->lock, flags);
return ret;
}
static void start_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)
static bool advance_transaction(struct acpi_ec *ec)
{
unsigned long flags;
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;
if (!t)
goto unlock;
goto err;
if (t->flags & ACPI_EC_COMMAND_POLL) {
if (t->wlen > t->wi) {
if ((status & ACPI_EC_FLAG_IBF) == 0)
acpi_ec_write_data(ec,
t->wdata[t->wi++]);
acpi_ec_write_data(ec, t->wdata[t->wi++]);
else
goto err;
} else if (t->rlen > t->ri) {
if ((status & ACPI_EC_FLAG_OBF) == 1) {
t->rdata[t->ri++] = acpi_ec_read_data(ec);
if (t->rlen == t->ri)
t->done = true;
if (t->rlen == t->ri) {
t->flags |= ACPI_EC_COMMAND_COMPLETE;
wakeup = true;
}
} else
goto err;
} else if (t->wlen == t->wi &&
(status & ACPI_EC_FLAG_IBF) == 0)
t->done = true;
goto unlock;
(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
goto err;
return wakeup;
}
err:
/*
* 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.
*/
if (in_interrupt() && !(status & ACPI_EC_FLAG_SCI))
if (!(status & ACPI_EC_FLAG_SCI)) {
if (in_interrupt() && t)
++t->irq_count;
}
return wakeup;
}
unlock:
spin_unlock_irqrestore(&ec->lock, flags);
static void start_transaction(struct acpi_ec *ec)
{
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);
......@@ -228,15 +256,17 @@ static int ec_poll(struct acpi_ec *ec)
/* don't sleep with disabled interrupts */
if (EC_FLAGS_MSI || irqs_disabled()) {
udelay(ACPI_EC_MSI_UDELAY);
if (ec_transaction_done(ec))
if (ec_transaction_completed(ec))
return 0;
} else {
if (wait_event_timeout(ec->wait,
ec_transaction_done(ec),
ec_transaction_completed(ec),
msecs_to_jiffies(1)))
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));
pr_debug("controller reset, restart transaction\n");
spin_lock_irqsave(&ec->lock, flags);
......@@ -268,23 +298,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
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)
{
int status;
......@@ -305,12 +318,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
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",
t->command, t->wdata ? t->wdata[0] : 0);
/* 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);
}
pr_debug("transaction end\n");
end:
if (ec->global_lock)
acpi_release_global_lock(glk);
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,
u32 gpe_number, void *data)
{
unsigned long flags;
struct acpi_ec *ec = data;
u8 status = acpi_ec_read_status(ec);
pr_debug("~~~> interrupt, status:0x%02x\n", status);
advance_transaction(ec, status);
if (ec_transaction_done(ec) &&
(acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) {
spin_lock_irqsave(&ec->lock, flags);
if (advance_transaction(ec))
wake_up(&ec->wait);
spin_unlock_irqrestore(&ec->lock, flags);
ec_check_sci(ec, acpi_ec_read_status(ec));
}
return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
}
......@@ -1066,8 +1069,10 @@ int __init acpi_ec_ecdt_probe(void)
/* fall through */
}
if (EC_FLAGS_SKIP_DSDT_SCAN)
if (EC_FLAGS_SKIP_DSDT_SCAN) {
kfree(saved_ec);
return -ENODEV;
}
/* This workaround is needed only on some broken machines,
* which require early EC, but fail to provide ECDT */
......@@ -1105,6 +1110,7 @@ int __init acpi_ec_ecdt_probe(void)
}
error:
kfree(boot_ec);
kfree(saved_ec);
boot_ec = NULL;
return -ENODEV;
}
......
......@@ -77,7 +77,7 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
switch (ares->type) {
case ACPI_RESOURCE_TYPE_MEMORY24:
memory24 = &ares->data.memory24;
if (!memory24->address_length)
if (!memory24->minimum && !memory24->address_length)
return false;
acpi_dev_get_memresource(res, memory24->minimum,
memory24->address_length,
......@@ -85,7 +85,7 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
break;
case ACPI_RESOURCE_TYPE_MEMORY32:
memory32 = &ares->data.memory32;
if (!memory32->address_length)
if (!memory32->minimum && !memory32->address_length)
return false;
acpi_dev_get_memresource(res, memory32->minimum,
memory32->address_length,
......@@ -93,7 +93,7 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
break;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
fixed_memory32 = &ares->data.fixed_memory32;
if (!fixed_memory32->address_length)
if (!fixed_memory32->address && !fixed_memory32->address_length)
return false;
acpi_dev_get_memresource(res, fixed_memory32->address,
fixed_memory32->address_length,
......@@ -150,7 +150,7 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res)
switch (ares->type) {
case ACPI_RESOURCE_TYPE_IO:
io = &ares->data.io;
if (!io->address_length)
if (!io->minimum && !io->address_length)
return false;
acpi_dev_get_ioresource(res, io->minimum,
io->address_length,
......@@ -158,7 +158,7 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res)
break;
case ACPI_RESOURCE_TYPE_FIXED_IO:
fixed_io = &ares->data.fixed_io;
if (!fixed_io->address_length)
if (!fixed_io->address && !fixed_io->address_length)
return false;
acpi_dev_get_ioresource(res, fixed_io->address,
fixed_io->address_length,
......
......@@ -241,13 +241,14 @@ static bool acpi_video_use_native_backlight(void)
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() &&
backlight_device_registered(BACKLIGHT_RAW))
return false;
return acpi_video_backlight_support();
}
EXPORT_SYMBOL_GPL(acpi_video_verify_backlight_support);
/* backlight device sysfs support */
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"),
},
},
{
.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,
.ident = "HP ProBook 4340s",
......
......@@ -166,6 +166,14 @@ static struct dmi_system_id video_detect_dmi_table[] = {
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.
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_ARM_EXYNOS_CPUFREQ) += exynos-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o
......
......@@ -128,6 +128,7 @@ static struct pstate_funcs pstate_funcs;
struct perf_limits {
int no_turbo;
int turbo_disabled;
int max_perf_pct;
int min_perf_pct;
int32_t max_perf;
......@@ -287,7 +288,10 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
if (ret != 1)
return -EINVAL;
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;
}
......@@ -357,21 +361,21 @@ static int byt_get_min_pstate(void)
{
u64 value;
rdmsrl(BYT_RATIOS, value);
return (value >> 8) & 0x3F;
return (value >> 8) & 0x7F;
}
static int byt_get_max_pstate(void)
{
u64 value;
rdmsrl(BYT_RATIOS, value);
return (value >> 16) & 0x3F;
return (value >> 16) & 0x7F;
}
static int byt_get_turbo_pstate(void)
{
u64 value;
rdmsrl(BYT_TURBO_RATIOS, value);
return value & 0x3F;
return value & 0x7F;
}
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;
val = pstate << 8;
if (limits.no_turbo)
if (limits.no_turbo && !limits.turbo_disabled)
val |= (u64)1 << 32;
vid_fp = cpudata->vid.min + mul_fp(
......@@ -405,8 +409,8 @@ static void byt_get_vid(struct cpudata *cpudata)
rdmsrl(BYT_VIDS, value);
cpudata->vid.min = int_tofp((value >> 8) & 0x3f);
cpudata->vid.max = int_tofp((value >> 16) & 0x3f);
cpudata->vid.min = int_tofp((value >> 8) & 0x7f);
cpudata->vid.max = int_tofp((value >> 16) & 0x7f);
cpudata->vid.ratio = div_fp(
cpudata->vid.max - cpudata->vid.min,
int_tofp(cpudata->pstate.max_pstate -
......@@ -448,7 +452,7 @@ static void core_set_pstate(struct cpudata *cpudata, int pstate)
u64 val;
val = pstate << 8;
if (limits.no_turbo)
if (limits.no_turbo && !limits.turbo_disabled)
val |= (u64)1 << 32;
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];
intel_pstate_get_cpu_pstates(cpu);
cpu->cpu = cpunum;
intel_pstate_get_cpu_pstates(cpu);
init_timer_deferrable(&cpu->timer);
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.max_perf_pct = 100;
limits.max_perf = int_tofp(1);
limits.no_turbo = 0;
limits.no_turbo = limits.turbo_disabled;
return 0;
}
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;
int rc;
u64 misc_en;
rc = intel_pstate_init_cpu(policy->cpu);
if (rc)
......@@ -791,8 +795,13 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
cpu = all_cpu_data[policy->cpu];
if (!limits.no_turbo &&
limits.min_perf_pct == 100 && limits.max_perf_pct == 100)
rdmsrl(MSR_IA32_MISC_ENABLE, misc_en);
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;
else
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);
/*
* 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))
return ASLC_BACKLIGHT_FAILED;
......
......@@ -22,6 +22,7 @@ extern void acpi_video_unregister(void);
extern void acpi_video_unregister_backlight(void);
extern int acpi_video_get_edid(struct acpi_device *device, int type,
int device_id, void **edid);
extern bool acpi_video_verify_backlight_support(void);
#else
static inline int acpi_video_register(void) { return 0; }
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;
}
static inline bool acpi_video_verify_backlight_support(void) { return false; }
#endif
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment