diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/Makefile | 1 | ||||
-rw-r--r-- | drivers/acpi/acpi_lpat.c | 161 | ||||
-rw-r--r-- | drivers/acpi/acpi_lpss.c | 21 | ||||
-rw-r--r-- | drivers/acpi/acpica/utdebug.c | 4 | ||||
-rw-r--r-- | drivers/acpi/ec.c | 129 | ||||
-rw-r--r-- | drivers/acpi/event.c | 7 | ||||
-rw-r--r-- | drivers/acpi/pmic/intel_pmic.c | 133 | ||||
-rw-r--r-- | drivers/acpi/processor_idle.c | 48 | ||||
-rw-r--r-- | drivers/acpi/resource.c | 2 | ||||
-rw-r--r-- | drivers/acpi/video.c | 9 |
10 files changed, 271 insertions, 244 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index b18cd2151ddb..623b117ad1a2 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -55,6 +55,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o ifdef CONFIG_ACPI_VIDEO acpi-y += video_detect.o endif +acpi-y += acpi_lpat.o # These are (potentially) separate modules diff --git a/drivers/acpi/acpi_lpat.c b/drivers/acpi/acpi_lpat.c new file mode 100644 index 000000000000..feb61c1630eb --- /dev/null +++ b/drivers/acpi/acpi_lpat.c @@ -0,0 +1,161 @@ +/* + * acpi_lpat.c - LPAT table processing functions + * + * Copyright (C) 2015 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/acpi.h> +#include <acpi/acpi_lpat.h> + +/** + * acpi_lpat_raw_to_temp(): Return temperature from raw value through + * LPAT conversion table + * + * @lpat_table: the temperature_raw mapping table structure + * @raw: the raw value, used as a key to get the temerature from the + * above mapping table + * + * A positive converted temperarure value will be returned on success, + * a negative errno will be returned in error cases. + */ +int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table, + int raw) +{ + int i, delta_temp, delta_raw, temp; + struct acpi_lpat *lpat = lpat_table->lpat; + + for (i = 0; i < lpat_table->lpat_count - 1; i++) { + if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) || + (raw <= lpat[i].raw && raw >= lpat[i+1].raw)) + break; + } + + if (i == lpat_table->lpat_count - 1) + return -ENOENT; + + delta_temp = lpat[i+1].temp - lpat[i].temp; + delta_raw = lpat[i+1].raw - lpat[i].raw; + temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw; + + return temp; +} +EXPORT_SYMBOL_GPL(acpi_lpat_raw_to_temp); + +/** + * acpi_lpat_temp_to_raw(): Return raw value from temperature through + * LPAT conversion table + * + * @lpat: the temperature_raw mapping table + * @temp: the temperature, used as a key to get the raw value from the + * above mapping table + * + * A positive converted temperature value will be returned on success, + * a negative errno will be returned in error cases. + */ +int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table, + int temp) +{ + int i, delta_temp, delta_raw, raw; + struct acpi_lpat *lpat = lpat_table->lpat; + + for (i = 0; i < lpat_table->lpat_count - 1; i++) { + if (temp >= lpat[i].temp && temp <= lpat[i+1].temp) + break; + } + + if (i == lpat_table->lpat_count - 1) + return -ENOENT; + + delta_temp = lpat[i+1].temp - lpat[i].temp; + delta_raw = lpat[i+1].raw - lpat[i].raw; + raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp; + + return raw; +} +EXPORT_SYMBOL_GPL(acpi_lpat_temp_to_raw); + +/** + * acpi_lpat_get_conversion_table(): Parse ACPI LPAT table if present. + * + * @handle: Handle to acpi device + * + * Parse LPAT table to a struct of type acpi_lpat_table. On success + * it returns a pointer to newly allocated table. This table must + * be freed by the caller when finished processing, using a call to + * acpi_lpat_free_conversion_table. + */ +struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table(acpi_handle + handle) +{ + struct acpi_lpat_conversion_table *lpat_table = NULL; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj_p, *obj_e; + int *lpat, i; + acpi_status status; + + status = acpi_evaluate_object(handle, "LPAT", NULL, &buffer); + if (ACPI_FAILURE(status)) + return NULL; + + obj_p = (union acpi_object *)buffer.pointer; + if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) || + (obj_p->package.count % 2) || (obj_p->package.count < 4)) + goto out; + + lpat = kcalloc(obj_p->package.count, sizeof(int), GFP_KERNEL); + if (!lpat) + goto out; + + for (i = 0; i < obj_p->package.count; i++) { + obj_e = &obj_p->package.elements[i]; + if (obj_e->type != ACPI_TYPE_INTEGER) { + kfree(lpat); + goto out; + } + lpat[i] = (s64)obj_e->integer.value; + } + + lpat_table = kzalloc(sizeof(*lpat_table), GFP_KERNEL); + if (!lpat_table) { + kfree(lpat); + goto out; + } + + lpat_table->lpat = (struct acpi_lpat *)lpat; + lpat_table->lpat_count = obj_p->package.count / 2; + +out: + kfree(buffer.pointer); + return lpat_table; +} +EXPORT_SYMBOL_GPL(acpi_lpat_get_conversion_table); + +/** + * acpi_lpat_free_conversion_table(): Free LPAT table. + * + * @lpat_table: the temperature_raw mapping table structure + * + * Frees the LPAT table previously allocated by a call to + * acpi_lpat_get_conversion_table. + */ +void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table + *lpat_table) +{ + if (lpat_table) { + kfree(lpat_table->lpat); + kfree(lpat_table); + } +} +EXPORT_SYMBOL_GPL(acpi_lpat_free_conversion_table); + +MODULE_LICENSE("GPL"); diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 02e835f3cf8a..657964e8ab7e 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -105,7 +105,7 @@ static void lpss_uart_setup(struct lpss_private_data *pdata) } } -static void byt_i2c_setup(struct lpss_private_data *pdata) +static void lpss_deassert_reset(struct lpss_private_data *pdata) { unsigned int offset; u32 val; @@ -114,9 +114,18 @@ static void byt_i2c_setup(struct lpss_private_data *pdata) val = readl(pdata->mmio_base + offset); val |= LPSS_RESETS_RESET_APB | LPSS_RESETS_RESET_FUNC; writel(val, pdata->mmio_base + offset); +} + +#define LPSS_I2C_ENABLE 0x6c + +static void byt_i2c_setup(struct lpss_private_data *pdata) +{ + lpss_deassert_reset(pdata); if (readl(pdata->mmio_base + pdata->dev_desc->prv_offset)) pdata->fixed_clk_rate = 133000000; + + writel(0, pdata->mmio_base + LPSS_I2C_ENABLE); } static struct lpss_device_desc lpt_dev_desc = { @@ -125,7 +134,7 @@ static struct lpss_device_desc lpt_dev_desc = { }; static struct lpss_device_desc lpt_i2c_dev_desc = { - .flags = LPSS_CLK | LPSS_LTR, + .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_LTR, .prv_offset = 0x800, }; @@ -166,6 +175,12 @@ static struct lpss_device_desc byt_i2c_dev_desc = { .setup = byt_i2c_setup, }; +static struct lpss_device_desc bsw_spi_dev_desc = { + .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX, + .prv_offset = 0x400, + .setup = lpss_deassert_reset, +}; + #else #define LPSS_ADDR(desc) (0UL) @@ -198,7 +213,7 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = { /* Braswell LPSS devices */ { "80862288", LPSS_ADDR(byt_pwm_dev_desc) }, { "8086228A", LPSS_ADDR(byt_uart_dev_desc) }, - { "8086228E", LPSS_ADDR(byt_spi_dev_desc) }, + { "8086228E", LPSS_ADDR(bsw_spi_dev_desc) }, { "808622C1", LPSS_ADDR(byt_i2c_dev_desc) }, { "INT3430", LPSS_ADDR(lpt_dev_desc) }, diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 57078e3ea9b7..4f3f888d33bb 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -111,8 +111,8 @@ void acpi_ut_track_stack_ptr(void) * RETURN: Updated pointer to the function name * * DESCRIPTION: Remove the "Acpi" prefix from the function name, if present. - * This allows compiler macros such as __FUNCTION__ to be used - * with no change to the debug output. + * This allows compiler macros such as __func__ to be used with no + * change to the debug output. * ******************************************************************************/ diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 14d0c89ada2a..a8dd2f763382 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -31,7 +31,6 @@ /* Uncomment next line to get verbose printout */ /* #define DEBUG */ -#define DEBUG_REF 0 #define pr_fmt(fmt) "ACPI : EC: " fmt #include <linux/kernel.h> @@ -77,9 +76,7 @@ enum ec_command { * when trying to clear the EC */ enum { - EC_FLAGS_EVENT_ENABLED, /* Event is enabled */ - EC_FLAGS_EVENT_PENDING, /* Event is pending */ - EC_FLAGS_EVENT_DETECTED, /* Event is detected */ + EC_FLAGS_QUERY_PENDING, /* Query is pending */ EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and * OpReg are installed */ EC_FLAGS_STARTED, /* Driver is started */ @@ -91,13 +88,6 @@ enum { #define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */ #define ACPI_EC_COMMAND_COMPLETE 0x02 /* Completed last byte */ -#define ec_debug_ref(ec, fmt, ...) \ - do { \ - if (DEBUG_REF) \ - pr_debug("%lu: " fmt, ec->reference_count, \ - ## __VA_ARGS__); \ - } while (0) - /* 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); @@ -161,12 +151,6 @@ static bool acpi_ec_flushed(struct acpi_ec *ec) return ec->reference_count == 1; } -static bool acpi_ec_has_pending_event(struct acpi_ec *ec) -{ - return test_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags) || - test_bit(EC_FLAGS_EVENT_PENDING, &ec->flags); -} - /* -------------------------------------------------------------------------- * EC Registers * -------------------------------------------------------------------------- */ @@ -334,97 +318,34 @@ static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag) * the flush operation is not in * progress * @ec: the EC device - * @allow_event: whether event should be handled * * This function must be used before taking a new action that should hold * the reference count. If this function returns false, then the action * must be discarded or it will prevent the flush operation from being * completed. - * - * During flushing, QR_EC command need to pass this check when there is a - * pending event, so that the reference count held for the pending event - * can be decreased by the completion of the QR_EC command. */ -static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec, - bool allow_event) +static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec) { - if (!acpi_ec_started(ec)) { - if (!allow_event || !acpi_ec_has_pending_event(ec)) - return false; - } + if (!acpi_ec_started(ec)) + return false; acpi_ec_submit_request(ec); return true; } -static void acpi_ec_submit_event(struct acpi_ec *ec) +static void acpi_ec_submit_query(struct acpi_ec *ec) { - if (!test_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags) || - !test_bit(EC_FLAGS_EVENT_ENABLED, &ec->flags)) - return; - /* Hold reference for pending event */ - if (!acpi_ec_submit_flushable_request(ec, true)) - return; - ec_debug_ref(ec, "Increase event\n"); - if (!test_and_set_bit(EC_FLAGS_EVENT_PENDING, &ec->flags)) { - pr_debug("***** Event query started *****\n"); + if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { + pr_debug("***** Event started *****\n"); schedule_work(&ec->work); - return; } - acpi_ec_complete_request(ec); - ec_debug_ref(ec, "Decrease event\n"); } -static void acpi_ec_complete_event(struct acpi_ec *ec) +static void acpi_ec_complete_query(struct acpi_ec *ec) { if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { - clear_bit(EC_FLAGS_EVENT_PENDING, &ec->flags); - pr_debug("***** Event query stopped *****\n"); - /* Unhold reference for pending event */ - acpi_ec_complete_request(ec); - ec_debug_ref(ec, "Decrease event\n"); - /* Check if there is another SCI_EVT detected */ - acpi_ec_submit_event(ec); - } -} - -static void acpi_ec_submit_detection(struct acpi_ec *ec) -{ - /* Hold reference for query submission */ - if (!acpi_ec_submit_flushable_request(ec, false)) - return; - ec_debug_ref(ec, "Increase query\n"); - if (!test_and_set_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags)) { - pr_debug("***** Event detection blocked *****\n"); - acpi_ec_submit_event(ec); - return; + clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); + pr_debug("***** Event stopped *****\n"); } - acpi_ec_complete_request(ec); - ec_debug_ref(ec, "Decrease query\n"); -} - -static void acpi_ec_complete_detection(struct acpi_ec *ec) -{ - if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { - clear_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags); - pr_debug("***** Event detetion unblocked *****\n"); - /* Unhold reference for query submission */ - acpi_ec_complete_request(ec); - ec_debug_ref(ec, "Decrease query\n"); - } -} - -static void acpi_ec_enable_event(struct acpi_ec *ec) -{ - unsigned long flags; - - spin_lock_irqsave(&ec->lock, flags); - set_bit(EC_FLAGS_EVENT_ENABLED, &ec->flags); - /* - * An event may be pending even with SCI_EVT=0, so QR_EC should - * always be issued right after started. - */ - acpi_ec_submit_detection(ec); - spin_unlock_irqrestore(&ec->lock, flags); } static int ec_transaction_completed(struct acpi_ec *ec) @@ -468,7 +389,6 @@ static void advance_transaction(struct acpi_ec *ec) t->rdata[t->ri++] = acpi_ec_read_data(ec); if (t->rlen == t->ri) { t->flags |= ACPI_EC_COMMAND_COMPLETE; - acpi_ec_complete_event(ec); if (t->command == ACPI_EC_COMMAND_QUERY) pr_debug("***** Command(%s) hardware completion *****\n", acpi_ec_cmd_string(t->command)); @@ -479,7 +399,6 @@ static void advance_transaction(struct acpi_ec *ec) } else if (t->wlen == t->wi && (status & ACPI_EC_FLAG_IBF) == 0) { t->flags |= ACPI_EC_COMMAND_COMPLETE; - acpi_ec_complete_event(ec); wakeup = true; } goto out; @@ -488,17 +407,16 @@ static void advance_transaction(struct acpi_ec *ec) !(status & ACPI_EC_FLAG_SCI) && (t->command == ACPI_EC_COMMAND_QUERY)) { t->flags |= ACPI_EC_COMMAND_POLL; - acpi_ec_complete_detection(ec); + acpi_ec_complete_query(ec); t->rdata[t->ri++] = 0x00; t->flags |= ACPI_EC_COMMAND_COMPLETE; - acpi_ec_complete_event(ec); pr_debug("***** Command(%s) software completion *****\n", acpi_ec_cmd_string(t->command)); wakeup = true; } else if ((status & ACPI_EC_FLAG_IBF) == 0) { acpi_ec_write_cmd(ec, t->command); t->flags |= ACPI_EC_COMMAND_POLL; - acpi_ec_complete_detection(ec); + acpi_ec_complete_query(ec); } else goto err; goto out; @@ -519,7 +437,7 @@ err: } out: if (status & ACPI_EC_FLAG_SCI) - acpi_ec_submit_detection(ec); + acpi_ec_submit_query(ec); if (wakeup && in_interrupt()) wake_up(&ec->wait); } @@ -580,11 +498,10 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, /* start transaction */ spin_lock_irqsave(&ec->lock, tmp); /* Enable GPE for command processing (IBF=0/OBF=1) */ - if (!acpi_ec_submit_flushable_request(ec, true)) { + if (!acpi_ec_submit_flushable_request(ec)) { ret = -EINVAL; goto unlock; } - ec_debug_ref(ec, "Increase command\n"); /* following two actions should be kept atomic */ ec->curr = t; pr_debug("***** Command(%s) started *****\n", @@ -600,7 +517,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, ec->curr = NULL; /* Disable GPE for command processing (IBF=0/OBF=1) */ acpi_ec_complete_request(ec); - ec_debug_ref(ec, "Decrease command\n"); unlock: spin_unlock_irqrestore(&ec->lock, tmp); return ret; @@ -762,11 +678,9 @@ static void acpi_ec_start(struct acpi_ec *ec, bool resuming) if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) { pr_debug("+++++ Starting EC +++++\n"); /* Enable GPE for event processing (SCI_EVT=1) */ - if (!resuming) { + if (!resuming) acpi_ec_submit_request(ec); - ec_debug_ref(ec, "Increase driver\n"); - } - pr_info("+++++ EC started +++++\n"); + pr_debug("EC started\n"); } spin_unlock_irqrestore(&ec->lock, flags); } @@ -794,13 +708,11 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool suspending) wait_event(ec->wait, acpi_ec_stopped(ec)); spin_lock_irqsave(&ec->lock, flags); /* Disable GPE for event processing (SCI_EVT=1) */ - if (!suspending) { + if (!suspending) acpi_ec_complete_request(ec); - ec_debug_ref(ec, "Decrease driver\n"); - } clear_bit(EC_FLAGS_STARTED, &ec->flags); clear_bit(EC_FLAGS_STOPPED, &ec->flags); - pr_info("+++++ EC stopped +++++\n"); + pr_debug("EC stopped\n"); } spin_unlock_irqrestore(&ec->lock, flags); } @@ -967,9 +879,7 @@ static void acpi_ec_gpe_poller(struct work_struct *work) { struct acpi_ec *ec = container_of(work, struct acpi_ec, work); - pr_debug("***** Event poller started *****\n"); acpi_ec_query(ec, NULL); - pr_debug("***** Event poller stopped *****\n"); } static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, @@ -1039,6 +949,7 @@ static struct acpi_ec *make_acpi_ec(void) if (!ec) return NULL; + ec->flags = 1 << EC_FLAGS_QUERY_PENDING; mutex_init(&ec->mutex); init_waitqueue_head(&ec->wait); INIT_LIST_HEAD(&ec->list); @@ -1189,7 +1100,7 @@ static int acpi_ec_add(struct acpi_device *device) ret = ec_install_handlers(ec); /* EC is fully operational, allow queries */ - acpi_ec_enable_event(ec); + clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); /* Clear stale _Q events if hardware might require that */ if (EC_FLAGS_CLEAR_ON_RESUME) diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index ef2d730734dc..e24ea4e796e4 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -100,7 +100,6 @@ int acpi_bus_generate_netlink_event(const char *device_class, struct acpi_genl_event *event; void *msg_header; int size; - int result; /* allocate memory */ size = nla_total_size(sizeof(struct acpi_genl_event)) + @@ -137,11 +136,7 @@ int acpi_bus_generate_netlink_event(const char *device_class, event->data = data; /* send multicast genetlink message */ - result = genlmsg_end(skb, msg_header); - if (result < 0) { - nlmsg_free(skb); - return result; - } + genlmsg_end(skb, msg_header); genlmsg_multicast(&acpi_event_genl_family, skb, 0, 0, GFP_ATOMIC); return 0; diff --git a/drivers/acpi/pmic/intel_pmic.c b/drivers/acpi/pmic/intel_pmic.c index a732e5d7e322..bd772cd56494 100644 --- a/drivers/acpi/pmic/intel_pmic.c +++ b/drivers/acpi/pmic/intel_pmic.c @@ -16,20 +16,15 @@ #include <linux/module.h> #include <linux/acpi.h> #include <linux/regmap.h> +#include <acpi/acpi_lpat.h> #include "intel_pmic.h" #define PMIC_POWER_OPREGION_ID 0x8d #define PMIC_THERMAL_OPREGION_ID 0x8c -struct acpi_lpat { - int temp; - int raw; -}; - struct intel_pmic_opregion { struct mutex lock; - struct acpi_lpat *lpat; - int lpat_count; + struct acpi_lpat_conversion_table *lpat_table; struct regmap *regmap; struct intel_pmic_opregion_data *data; }; @@ -50,105 +45,6 @@ static int pmic_get_reg_bit(int address, struct pmic_table *table, return -ENOENT; } -/** - * raw_to_temp(): Return temperature from raw value through LPAT table - * - * @lpat: the temperature_raw mapping table - * @count: the count of the above mapping table - * @raw: the raw value, used as a key to get the temerature from the - * above mapping table - * - * A positive value will be returned on success, a negative errno will - * be returned in error cases. - */ -static int raw_to_temp(struct acpi_lpat *lpat, int count, int raw) -{ - int i, delta_temp, delta_raw, temp; - - for (i = 0; i < count - 1; i++) { - if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) || - (raw <= lpat[i].raw && raw >= lpat[i+1].raw)) - break; - } - - if (i == count - 1) - return -ENOENT; - - delta_temp = lpat[i+1].temp - lpat[i].temp; - delta_raw = lpat[i+1].raw - lpat[i].raw; - temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw; - - return temp; -} - -/** - * temp_to_raw(): Return raw value from temperature through LPAT table - * - * @lpat: the temperature_raw mapping table - * @count: the count of the above mapping table - * @temp: the temperature, used as a key to get the raw value from the - * above mapping table - * - * A positive value will be returned on success, a negative errno will - * be returned in error cases. - */ -static int temp_to_raw(struct acpi_lpat *lpat, int count, int temp) -{ - int i, delta_temp, delta_raw, raw; - - for (i = 0; i < count - 1; i++) { - if (temp >= lpat[i].temp && temp <= lpat[i+1].temp) - break; - } - - if (i == count - 1) - return -ENOENT; - - delta_temp = lpat[i+1].temp - lpat[i].temp; - delta_raw = lpat[i+1].raw - lpat[i].raw; - raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp; - - return raw; -} - -static void pmic_thermal_lpat(struct intel_pmic_opregion *opregion, - acpi_handle handle, struct device *dev) -{ - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj_p, *obj_e; - int *lpat, i; - acpi_status status; - - status = acpi_evaluate_object(handle, "LPAT", NULL, &buffer); - if (ACPI_FAILURE(status)) - return; - - obj_p = (union acpi_object *)buffer.pointer; - if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) || - (obj_p->package.count % 2) || (obj_p->package.count < 4)) - goto out; - - lpat = devm_kmalloc(dev, sizeof(int) * obj_p->package.count, - GFP_KERNEL); - if (!lpat) - goto out; - - for (i = 0; i < obj_p->package.count; i++) { - obj_e = &obj_p->package.elements[i]; - if (obj_e->type != ACPI_TYPE_INTEGER) { - devm_kfree(dev, lpat); - goto out; - } - lpat[i] = (s64)obj_e->integer.value; - } - - opregion->lpat = (struct acpi_lpat *)lpat; - opregion->lpat_count = obj_p->package.count / 2; - -out: - kfree(buffer.pointer); -} - static acpi_status intel_pmic_power_handler(u32 function, acpi_physical_address address, u32 bits, u64 *value64, void *handler_context, void *region_context) @@ -192,12 +88,12 @@ static int pmic_read_temp(struct intel_pmic_opregion *opregion, if (raw_temp < 0) return raw_temp; - if (!opregion->lpat) { + if (!opregion->lpat_table) { *value = raw_temp; return 0; } - temp = raw_to_temp(opregion->lpat, opregion->lpat_count, raw_temp); + temp = acpi_lpat_raw_to_temp(opregion->lpat_table, raw_temp); if (temp < 0) return temp; @@ -223,9 +119,8 @@ static int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg, if (!opregion->data->update_aux) return -ENXIO; - if (opregion->lpat) { - raw_temp = temp_to_raw(opregion->lpat, opregion->lpat_count, - *value); + if (opregion->lpat_table) { + raw_temp = acpi_lpat_temp_to_raw(opregion->lpat_table, *value); if (raw_temp < 0) return raw_temp; } else { @@ -314,6 +209,7 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, { acpi_status status; struct intel_pmic_opregion *opregion; + int ret; if (!dev || !regmap || !d) return -EINVAL; @@ -327,14 +223,16 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, mutex_init(&opregion->lock); opregion->regmap = regmap; - pmic_thermal_lpat(opregion, handle, dev); + opregion->lpat_table = acpi_lpat_get_conversion_table(handle); status = acpi_install_address_space_handler(handle, PMIC_POWER_OPREGION_ID, intel_pmic_power_handler, NULL, opregion); - if (ACPI_FAILURE(status)) - return -ENODEV; + if (ACPI_FAILURE(status)) { + ret = -ENODEV; + goto out_error; + } status = acpi_install_address_space_handler(handle, PMIC_THERMAL_OPREGION_ID, @@ -343,11 +241,16 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, if (ACPI_FAILURE(status)) { acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID, intel_pmic_power_handler); - return -ENODEV; + ret = -ENODEV; + goto out_error; } opregion->data = d; return 0; + +out_error: + acpi_lpat_free_conversion_table(opregion->lpat_table); + return ret; } EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index c256bd7fbd78..c6bb9f1257c9 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -732,9 +732,8 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) static bool acpi_idle_fallback_to_c1(struct acpi_processor *pr) { - return IS_ENABLED(CONFIG_HOTPLUG_CPU) && num_online_cpus() > 1 && - !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED) && - !pr->flags.has_cst; + return IS_ENABLED(CONFIG_HOTPLUG_CPU) && !pr->flags.has_cst && + !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED); } static int c3_cpu_count; @@ -744,9 +743,10 @@ static DEFINE_RAW_SPINLOCK(c3_lock); * acpi_idle_enter_bm - enters C3 with proper BM handling * @pr: Target processor * @cx: Target state context + * @timer_bc: Whether or not to change timer mode to broadcast */ static void acpi_idle_enter_bm(struct acpi_processor *pr, - struct acpi_processor_cx *cx) + struct acpi_processor_cx *cx, bool timer_bc) { acpi_unlazy_tlb(smp_processor_id()); @@ -754,7 +754,8 @@ static void acpi_idle_enter_bm(struct acpi_processor *pr, * Must be done before busmaster disable as we might need to * access HPET ! */ - lapic_timer_state_broadcast(pr, cx, 1); + if (timer_bc) + lapic_timer_state_broadcast(pr, cx, 1); /* * disable bus master @@ -784,7 +785,8 @@ static void acpi_idle_enter_bm(struct acpi_processor *pr, raw_spin_unlock(&c3_lock); } - lapic_timer_state_broadcast(pr, cx, 0); + if (timer_bc) + lapic_timer_state_broadcast(pr, cx, 0); } static int acpi_idle_enter(struct cpuidle_device *dev, @@ -798,12 +800,12 @@ static int acpi_idle_enter(struct cpuidle_device *dev, return -EINVAL; if (cx->type != ACPI_STATE_C1) { - if (acpi_idle_fallback_to_c1(pr)) { + if (acpi_idle_fallback_to_c1(pr) && num_online_cpus() > 1) { index = CPUIDLE_DRIVER_STATE_START; cx = per_cpu(acpi_cstate[index], dev->cpu); } else if (cx->type == ACPI_STATE_C3 && pr->flags.bm_check) { if (cx->bm_sts_skip || !acpi_idle_bm_check()) { - acpi_idle_enter_bm(pr, cx); + acpi_idle_enter_bm(pr, cx, true); return index; } else if (drv->safe_state_index >= 0) { index = drv->safe_state_index; @@ -827,6 +829,27 @@ static int acpi_idle_enter(struct cpuidle_device *dev, return index; } +static void acpi_idle_enter_freeze(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); + + if (cx->type == ACPI_STATE_C3) { + struct acpi_processor *pr = __this_cpu_read(processors); + + if (unlikely(!pr)) + return; + + if (pr->flags.bm_check) { + acpi_idle_enter_bm(pr, cx, false); + return; + } else { + ACPI_FLUSH_CPU_CACHE(); + } + } + acpi_idle_do_entry(cx); +} + struct cpuidle_driver acpi_idle_driver = { .name = "acpi_idle", .owner = THIS_MODULE, @@ -925,6 +948,15 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) state->enter_dead = acpi_idle_play_dead; drv->safe_state_index = count; } + /* + * Halt-induced C1 is not good for ->enter_freeze, because it + * re-enables interrupts on exit. Moreover, C1 is generally not + * particularly interesting from the suspend-to-idle angle, so + * avoid C1 and the situations in which we may need to fall back + * to it altogether. + */ + if (cx->type != ACPI_STATE_C1 && !acpi_idle_fallback_to_c1(pr)) + state->enter_freeze = acpi_idle_enter_freeze; count++; if (count == CPUIDLE_STATE_MAX) diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 4752b9939987..c723668e3e27 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -46,7 +46,7 @@ static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io) if (len && reslen && reslen == len && start <= end) return true; - pr_info("ACPI: invalid or unassigned resource %s [%016llx - %016llx] length [%016llx]\n", + pr_debug("ACPI: invalid or unassigned resource %s [%016llx - %016llx] length [%016llx]\n", io ? "io" : "mem", start, end, len); return false; diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 88a4f99dd2a7..debd30917010 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -540,6 +540,15 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"), }, }, + { + /* https://bugs.freedesktop.org/show_bug.cgi?id=87286 */ + .callback = video_disable_native_backlight, + .ident = "SAMSUNG 900X3C/900X3D/900X3E/900X4C/900X4D", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "900X3C/900X3D/900X3E/900X4C/900X4D"), + }, + }, { /* https://bugzilla.redhat.com/show_bug.cgi?id=1163574 */ |