From 108cc2e7d212c7d52694fb400423da807e1e5fe4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 30 Apr 2013 12:42:50 +0300 Subject: SFI: fix compiler warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/sfi/sfi_core.c:164:26: warning: no previous prototype for ‘sfi_map_table’ [-Wmissing-prototypes] drivers/sfi/sfi_core.c:192:6: warning: no previous prototype for ‘sfi_unmap_table’ [-Wmissing-prototypes] Signed-off-by: Andy Shevchenko Signed-off-by: Len Brown diff --git a/drivers/sfi/sfi_core.c b/drivers/sfi/sfi_core.c index 1e824fb..296db7a 100644 --- a/drivers/sfi/sfi_core.c +++ b/drivers/sfi/sfi_core.c @@ -161,7 +161,7 @@ static int sfi_verify_table(struct sfi_table_header *table) * Check for common case that we can re-use mapping to SYST, * which requires syst_pa, syst_va to be initialized. */ -struct sfi_table_header *sfi_map_table(u64 pa) +static struct sfi_table_header *sfi_map_table(u64 pa) { struct sfi_table_header *th; u32 length; @@ -189,7 +189,7 @@ struct sfi_table_header *sfi_map_table(u64 pa) * Undoes effect of sfi_map_table() by unmapping table * if it did not completely fit on same page as SYST. */ -void sfi_unmap_table(struct sfi_table_header *th) +static void sfi_unmap_table(struct sfi_table_header *th) { if (!TABLE_ON_PAGE(syst_va, th, th->len)) sfi_unmap_memory(th, TABLE_ON_PAGE(th, th, th->len) ? -- cgit v0.10.2 From e7ddf4b7b3c5fe64902c4fb9edac92532c87cd75 Mon Sep 17 00:00:00 2001 From: Srinidhi Kasagar Date: Fri, 19 Dec 2014 23:13:51 +0530 Subject: cpufreq: Add SFI based cpufreq driver support This adds the SFI based cpu freq driver for some of the Intel's Silvermont based Atom architectures like Z34xx and Z35xx. Signed-off-by: Rudramuni, Vishwesh M Signed-off-by: Srinidhi Kasagar Acked-by: Viresh Kumar Signed-off-by: Len Brown diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h index e21331ce..4f6dae6 100644 --- a/arch/x86/include/uapi/asm/msr-index.h +++ b/arch/x86/include/uapi/asm/msr-index.h @@ -318,6 +318,7 @@ #define MSR_IA32_PERF_STATUS 0x00000198 #define MSR_IA32_PERF_CTL 0x00000199 +#define INTEL_PERF_CTL_MASK 0xffff #define MSR_AMD_PSTATE_DEF_BASE 0xc0010064 #define MSR_AMD_PERF_STATUS 0xc0010063 #define MSR_AMD_PERF_CTL 0xc0010062 diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86 index 89ae88f..c59bdcb 100644 --- a/drivers/cpufreq/Kconfig.x86 +++ b/drivers/cpufreq/Kconfig.x86 @@ -57,6 +57,16 @@ config X86_ACPI_CPUFREQ_CPB By enabling this option the acpi_cpufreq driver provides the old entry in addition to the new boost ones, for compatibility reasons. +config X86_SFI_CPUFREQ + tristate "SFI Performance-States driver" + depends on X86_INTEL_MID && SFI + help + This adds a CPUFreq driver for some Silvermont based Intel Atom + architectures like Z34xx and Z35xx which enumerate processor + performance states through SFI. + + If in doubt, say N. + config ELAN_CPUFREQ tristate "AMD Elan SC400 and SC410" depends on MELAN diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 40c53dc..2e50f55 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o obj-$(CONFIG_X86_INTEL_PSTATE) += intel_pstate.o obj-$(CONFIG_X86_AMD_FREQ_SENSITIVITY) += amd_freq_sensitivity.o +obj-$(CONFIG_X86_SFI_CPUFREQ) += sfi-cpufreq.o ################################################################################## # ARM SoC drivers diff --git a/drivers/cpufreq/sfi-cpufreq.c b/drivers/cpufreq/sfi-cpufreq.c new file mode 100644 index 0000000..ffa3389 --- /dev/null +++ b/drivers/cpufreq/sfi-cpufreq.c @@ -0,0 +1,136 @@ +/* + * SFI Performance States Driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License. + * + * 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. + * + * Author: Vishwesh M Rudramuni + * Author: Srinidhi Kasagar + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct cpufreq_frequency_table *freq_table; +static struct sfi_freq_table_entry *sfi_cpufreq_array; +static int num_freq_table_entries; + +static int sfi_parse_freq(struct sfi_table_header *table) +{ + struct sfi_table_simple *sb; + struct sfi_freq_table_entry *pentry; + int totallen; + + sb = (struct sfi_table_simple *)table; + num_freq_table_entries = SFI_GET_NUM_ENTRIES(sb, + struct sfi_freq_table_entry); + if (num_freq_table_entries <= 1) { + pr_err("No p-states discovered\n"); + return -ENODEV; + } + + pentry = (struct sfi_freq_table_entry *)sb->pentry; + totallen = num_freq_table_entries * sizeof(*pentry); + + sfi_cpufreq_array = kzalloc(totallen, GFP_KERNEL); + if (!sfi_cpufreq_array) + return -ENOMEM; + + memcpy(sfi_cpufreq_array, pentry, totallen); + + return 0; +} + +static int sfi_cpufreq_target(struct cpufreq_policy *policy, unsigned int index) +{ + unsigned int next_perf_state = 0; /* Index into perf table */ + u32 lo, hi; + + next_perf_state = policy->freq_table[index].driver_data; + + rdmsr_on_cpu(policy->cpu, MSR_IA32_PERF_CTL, &lo, &hi); + lo = (lo & ~INTEL_PERF_CTL_MASK) | + ((u32) sfi_cpufreq_array[next_perf_state].ctrl_val & + INTEL_PERF_CTL_MASK); + wrmsr_on_cpu(policy->cpu, MSR_IA32_PERF_CTL, lo, hi); + + return 0; +} + +static int sfi_cpufreq_cpu_init(struct cpufreq_policy *policy) +{ + policy->shared_type = CPUFREQ_SHARED_TYPE_HW; + policy->cpuinfo.transition_latency = 100000; /* 100us */ + + return cpufreq_table_validate_and_show(policy, freq_table); +} + +static struct cpufreq_driver sfi_cpufreq_driver = { + .flags = CPUFREQ_CONST_LOOPS, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = sfi_cpufreq_target, + .init = sfi_cpufreq_cpu_init, + .name = "sfi-cpufreq", + .attr = cpufreq_generic_attr, +}; + +static int __init sfi_cpufreq_init(void) +{ + int ret, i; + + /* parse the freq table from SFI */ + ret = sfi_table_parse(SFI_SIG_FREQ, NULL, NULL, sfi_parse_freq); + if (ret) + return ret; + + freq_table = kzalloc(sizeof(*freq_table) * + (num_freq_table_entries + 1), GFP_KERNEL); + if (!freq_table) { + ret = -ENOMEM; + goto err_free_array; + } + + for (i = 0; i < num_freq_table_entries; i++) { + freq_table[i].driver_data = i; + freq_table[i].frequency = sfi_cpufreq_array[i].freq_mhz * 1000; + } + freq_table[i].frequency = CPUFREQ_TABLE_END; + + ret = cpufreq_register_driver(&sfi_cpufreq_driver); + if (ret) + goto err_free_tbl; + + return ret; + +err_free_tbl: + kfree(freq_table); +err_free_array: + kfree(sfi_cpufreq_array); + return ret; +} +late_initcall(sfi_cpufreq_init); + +static void __exit sfi_cpufreq_exit(void) +{ + cpufreq_unregister_driver(&sfi_cpufreq_driver); + kfree(freq_table); + kfree(sfi_cpufreq_array); +} +module_exit(sfi_cpufreq_exit); + +MODULE_AUTHOR("Vishwesh M Rudramuni "); +MODULE_DESCRIPTION("SFI Performance-States Driver"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 3295d73002f4be341069a000aec4b8d7e5ea8d2c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 9 Jan 2015 16:22:57 +0100 Subject: ACPI / video: Add disable_native_backlight quirk for Samsung 730U3E/740U3E The Samsung 730U3E/740U3E has integrated ATI Radeon graphics, and backlight control does not work properly when using the native interfaces. Link: https://bugzilla.redhat.com/show_bug.cgi?id=1094948 Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 032db45..497d986 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -522,6 +522,15 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "370R4E/370R4V/370R5E/3570RE/370R5V"), }, }, + { + /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */ + .callback = video_disable_native_backlight, + .ident = "SAMSUNG 730U3E/740U3E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"), + }, + }, { /* https://bugzilla.redhat.com/show_bug.cgi?id=1163574 */ -- cgit v0.10.2 From 97d746578b1fc4ce461e6279220cab3605f02469 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Tue, 16 Dec 2014 18:12:30 +0200 Subject: ACPICA: take ACPI_MTX_INTERPRETER in acpi_unload_table_id() acpi_tb_delete_namespace_by_owner() expects ACPI_MTX_INTERPRETER to be taken. This fixes the following issue: ACPI Error: Mutex [0x0] is not acquired, cannot release (20141107/utmutex-322) Call Trace: [] dump_stack+0x4f/0x7b [] acpi_ut_release_mutex+0x47/0x67 [] acpi_tb_delete_namespace_by_owner+0x57/0x8d [] acpi_unload_table_id+0x3a/0x5e Signed-off-by: Octavian Purdila Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 6482b0d..9520ae1 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -281,6 +281,11 @@ acpi_status acpi_unload_table_id(acpi_owner_id id) ACPI_FUNCTION_TRACE(acpi_unload_table_id); + status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + /* Find table in the global table list */ for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { if (id != acpi_gbl_root_table_list.tables[i].owner_id) { @@ -297,6 +302,8 @@ acpi_status acpi_unload_table_id(acpi_owner_id id) acpi_tb_set_table_loaded_flag(i, FALSE); break; } + + (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); return_ACPI_STATUS(status); } -- cgit v0.10.2 From 4483d59e29fea65ef428be92a866aed50e28c795 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 8 Jan 2015 09:57:25 +0200 Subject: ACPI / LPSS: check the result of ioremap() If it fails we have to skip the device. Signed-off-by: Heikki Krogerus Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 4f3febf..d12f98a 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -340,6 +340,8 @@ static int acpi_lpss_create_device(struct acpi_device *adev, pdata->mmio_size = resource_size(&rentry->res); pdata->mmio_base = ioremap(rentry->res.start, pdata->mmio_size); + if (!pdata->mmio_base) + goto err_out; break; } -- cgit v0.10.2 From de14da2a72e929b146b2d91da2856a8b78e0dd63 Mon Sep 17 00:00:00 2001 From: Yaowei Bai Date: Thu, 15 Jan 2015 21:59:16 +0800 Subject: ACPI / Documentation: add a missing '=' Signed-off-by: Yaowei Bai Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/acpi/enumeration.txt b/Documentation/acpi/enumeration.txt index b60d2ab..9b121a5 100644 --- a/Documentation/acpi/enumeration.txt +++ b/Documentation/acpi/enumeration.txt @@ -243,7 +243,7 @@ input driver: .owner = THIS_MODULE, .pm = &mpu3050_pm, .of_match_table = mpu3050_of_match, - .acpi_match_table ACPI_PTR(mpu3050_acpi_match), + .acpi_match_table = ACPI_PTR(mpu3050_acpi_match), }, .probe = mpu3050_probe, .remove = mpu3050_remove, -- cgit v0.10.2 From 3a75ef0c788f092d912b2944e323e6447d557437 Mon Sep 17 00:00:00 2001 From: Yaowei Bai Date: Sat, 17 Jan 2015 15:31:07 +0800 Subject: MAINTAINERS / ACPI: add the necessary '/' according to entry rules Signed-off-by: Yaowei Bai Signed-off-by: Rafael J. Wysocki diff --git a/MAINTAINERS b/MAINTAINERS index 2fa3853..98b6123 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -270,12 +270,12 @@ F: drivers/acpi/ F: drivers/pnp/pnpacpi/ F: include/linux/acpi.h F: include/acpi/ -F: Documentation/acpi +F: Documentation/acpi/ F: Documentation/ABI/testing/sysfs-bus-acpi F: drivers/pci/*acpi* F: drivers/pci/*/*acpi* F: drivers/pci/*/*/*acpi* -F: tools/power/acpi +F: tools/power/acpi/ ACPI COMPONENT ARCHITECTURE (ACPICA) M: Robert Moore -- cgit v0.10.2 From 194fe6f28e2819d3f50fbed24c3b72f21501dbfa Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 8 Jan 2015 06:29:04 +0000 Subject: drivers: cpuidle: Don't initialize big.LITTLE driver if MCPM is unavailable If big.LITTLE driver is initialized even when MCPM is unavailable, we get the below warning the first time cpu tries to enter deeper C-states. ------------[ cut here ]------------ WARNING: CPU: 4 PID: 0 at kernel/arch/arm/common/mcpm_entry.c:130 mcpm_cpu_suspend+0x6d/0x74() Modules linked in: CPU: 4 PID: 0 Comm: swapper/4 Not tainted 3.19.0-rc3-00007-gaf5a2cb1ad5c-dirty #11 Hardware name: ARM-Versatile Express [] (unwind_backtrace) from [] (show_stack+0x11/0x14) [] (show_stack) from [] (dump_stack+0x6d/0x78) [] (dump_stack) from [] (warn_slowpath_common+0x69/0x90) [] (warn_slowpath_common) from [] (warn_slowpath_null+0x17/0x1c) [] (warn_slowpath_null) from [] (mcpm_cpu_suspend+0x6d/0x74) [] (mcpm_cpu_suspend) from [] (bl_powerdown_finisher+0x21/0x24) [] (bl_powerdown_finisher) from [] (cpu_suspend_abort+0x1/0x14) [] (cpu_suspend_abort) from [<00000000>] ( (null)) ---[ end trace d098e3fd00000008 ]--- This patch fixes the issue by checking for the availability of MCPM before initializing the big.LITTLE cpuidle driver Signed-off-by: Sudeep Holla Acked-by: Lorenzo Pieralisi Cc: Lorenzo Pieralisi Cc: Daniel Lezcano Cc: "Rafael J. Wysocki" Signed-off-by: Daniel Lezcano diff --git a/drivers/cpuidle/cpuidle-big_little.c b/drivers/cpuidle/cpuidle-big_little.c index e3e225f..40c34fa 100644 --- a/drivers/cpuidle/cpuidle-big_little.c +++ b/drivers/cpuidle/cpuidle-big_little.c @@ -182,6 +182,10 @@ static int __init bl_idle_init(void) */ if (!of_match_node(compatible_machine_match, root)) return -ENODEV; + + if (!mcpm_is_available()) + return -EUNATCH; + /* * For now the differentiation between little and big cores * is based on the part number. A7 cores are considered little -- cgit v0.10.2 From 0c78808f51d11564a29728091e87b80d6e54d499 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 14 Jan 2015 19:28:22 +0800 Subject: ACPI / EC: Cleanup transaction wakeup code This patch moves transaction wakeup code into advance_transaction(). No functional changes. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 1b5853f..3e19123 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -200,7 +200,7 @@ static int ec_transaction_completed(struct acpi_ec *ec) return ret; } -static bool advance_transaction(struct acpi_ec *ec) +static void advance_transaction(struct acpi_ec *ec) { struct transaction *t; u8 status; @@ -235,7 +235,7 @@ static bool advance_transaction(struct acpi_ec *ec) t->flags |= ACPI_EC_COMMAND_COMPLETE; wakeup = true; } - return wakeup; + goto out; } else { if (EC_FLAGS_QUERY_HANDSHAKE && !(status & ACPI_EC_FLAG_SCI) && @@ -251,7 +251,7 @@ static bool advance_transaction(struct acpi_ec *ec) t->flags |= ACPI_EC_COMMAND_POLL; } else goto err; - return wakeup; + goto out; } err: /* @@ -262,14 +262,16 @@ err: if (in_interrupt() && t) ++t->irq_count; } - return wakeup; +out: + if (wakeup && in_interrupt()) + wake_up(&ec->wait); } 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); + advance_transaction(ec); } static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data); @@ -304,7 +306,7 @@ static int ec_poll(struct acpi_ec *ec) return 0; } spin_lock_irqsave(&ec->lock, flags); - (void)advance_transaction(ec); + advance_transaction(ec); spin_unlock_irqrestore(&ec->lock, flags); } while (time_before(jiffies, delay)); pr_debug("controller reset, restart transaction\n"); @@ -688,8 +690,7 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, struct acpi_ec *ec = data; spin_lock_irqsave(&ec->lock, flags); - if (advance_transaction(ec)) - wake_up(&ec->wait); + advance_transaction(ec); spin_unlock_irqrestore(&ec->lock, flags); ec_check_sci(ec, acpi_ec_read_status(ec)); return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE; -- cgit v0.10.2 From 01305d4139cd345aa9f64cecfd7fc7b237e1444e Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 14 Jan 2015 19:28:28 +0800 Subject: ACPI / EC: Add reference counting for query handlers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds reference counting for query handlers in order to eliminate kmalloc()/kfree() usage. Signed-off-by: Lv Zheng Tested-by: Steffen Weber Tested-by: Ortwin Glück Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 3e19123..87b9911 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -105,6 +105,7 @@ struct acpi_ec_query_handler { acpi_handle handle; void *data; u8 query_bit; + struct kref kref; }; struct transaction { @@ -580,6 +581,27 @@ static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data) /* -------------------------------------------------------------------------- Event Management -------------------------------------------------------------------------- */ +static struct acpi_ec_query_handler * +acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler) +{ + if (handler) + kref_get(&handler->kref); + return handler; +} + +static void acpi_ec_query_handler_release(struct kref *kref) +{ + struct acpi_ec_query_handler *handler = + container_of(kref, struct acpi_ec_query_handler, kref); + + kfree(handler); +} + +static void acpi_ec_put_query_handler(struct acpi_ec_query_handler *handler) +{ + kref_put(&handler->kref, acpi_ec_query_handler_release); +} + int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, acpi_handle handle, acpi_ec_query_func func, void *data) @@ -595,6 +617,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, handler->func = func; handler->data = data; mutex_lock(&ec->mutex); + kref_init(&handler->kref); list_add(&handler->node, &ec->list); mutex_unlock(&ec->mutex); return 0; @@ -604,15 +627,18 @@ EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler); void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) { struct acpi_ec_query_handler *handler, *tmp; + LIST_HEAD(free_list); mutex_lock(&ec->mutex); list_for_each_entry_safe(handler, tmp, &ec->list, node) { if (query_bit == handler->query_bit) { - list_del(&handler->node); - kfree(handler); + list_del_init(&handler->node); + list_add(&handler->node, &free_list); } } mutex_unlock(&ec->mutex); + list_for_each_entry(handler, &free_list, node) + acpi_ec_put_query_handler(handler); } EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); @@ -628,14 +654,14 @@ static void acpi_ec_run(void *cxt) else if (handler->handle) acpi_evaluate_object(handler->handle, NULL, NULL, NULL); pr_debug("##### Query(0x%02x) stopped #####\n", handler->query_bit); - kfree(handler); + acpi_ec_put_query_handler(handler); } static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) { u8 value = 0; int status; - struct acpi_ec_query_handler *handler, *copy; + struct acpi_ec_query_handler *handler; status = acpi_ec_query_unlocked(ec, &value); if (data) @@ -646,15 +672,12 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) list_for_each_entry(handler, &ec->list, node) { if (value == handler->query_bit) { /* have custom handler for this bit */ - copy = kmalloc(sizeof(*handler), GFP_KERNEL); - if (!copy) - return -ENOMEM; - memcpy(copy, handler, sizeof(*copy)); + handler = acpi_ec_get_query_handler(handler); pr_debug("##### Query(0x%02x) scheduled #####\n", handler->query_bit); - return acpi_os_execute((copy->func) ? + return acpi_os_execute((handler->func) ? OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER, - acpi_ec_run, copy); + acpi_ec_run, handler); } } return 0; -- cgit v0.10.2 From c2cf5769fae1ce208ea00fa85298d1d19969300a Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 14 Jan 2015 19:28:33 +0800 Subject: ACPI / EC: Fix returning values in acpi_ec_sync_query() The returning value of acpi_os_execute() is erroneously handled as errno. This patch corrects it by returning EBUSY to indicate the work queue item creation failure. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 87b9911..a94ee9f 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -660,14 +660,15 @@ static void acpi_ec_run(void *cxt) static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) { u8 value = 0; - int status; + int result; + acpi_status status; struct acpi_ec_query_handler *handler; - status = acpi_ec_query_unlocked(ec, &value); + result = acpi_ec_query_unlocked(ec, &value); if (data) *data = value; - if (status) - return status; + if (result) + return result; list_for_each_entry(handler, &ec->list, node) { if (value == handler->query_bit) { @@ -675,12 +676,15 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) handler = acpi_ec_get_query_handler(handler); pr_debug("##### Query(0x%02x) scheduled #####\n", handler->query_bit); - return acpi_os_execute((handler->func) ? + status = acpi_os_execute((handler->func) ? OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER, acpi_ec_run, handler); + if (ACPI_FAILURE(status)) + result = -EBUSY; + break; } } - return 0; + return result; } static void acpi_ec_gpe_query(void *ec_cxt) -- cgit v0.10.2 From f3e14329517ee190d34455d729430ef9d0473675 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 14 Jan 2015 19:28:41 +0800 Subject: ACPI / EC: Fix a code path that global lock is not held Currently QR_EC is queued up on CPU 0 to be safe with SMM because there is no global lock held for acpi_ec_gpe_query(). As we are about to move QR_EC to a non CPU 0 bound work queue to avoid invoking kmalloc() in advance_transaction(), we have to acquire global lock for the new QR_EC work item to avoid regressions. Known issue: 1. Global lock for acpi_ec_clear(). This is an existing issue that acpi_ec_clear() which invokes acpi_ec_sync_query() also suffers from the same issue. But this patch's target is only the code to invoke acpi_ec_sync_query() in a CPU 0 bound work queue item, and the acpi_ec_clear() can be automatically fixed by further patch that merges the redundant code, so it is left unchanged. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index a94ee9f..3c97122 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -690,11 +690,21 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) static void acpi_ec_gpe_query(void *ec_cxt) { struct acpi_ec *ec = ec_cxt; + acpi_status status; + u32 glk; if (!ec) return; mutex_lock(&ec->mutex); + if (ec->global_lock) { + status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); + if (ACPI_FAILURE(status)) + goto unlock; + } acpi_ec_sync_query(ec, NULL); + if (ec->global_lock) + acpi_release_global_lock(glk); +unlock: mutex_unlock(&ec->mutex); } -- cgit v0.10.2 From 74443bbed72ab22ee005ecb6ecdc657a8018e1db Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 14 Jan 2015 19:28:47 +0800 Subject: ACPI / EC: Fix issues related to the SCI_EVT handling This patch fixes 2 issues related to the draining behavior. But it doesn't implement the draining support, it only cleans up code so that further draining support is possible. The draining behavior is expected by some platforms (for example, Samsung) where SCI_EVT is set only once for a set of events and might be cleared for the very first QR_EC command issued after SCI_EVT is set. EC firmware on such platforms will return 0x00 to indicate "no outstanding event". Thus after seeing an SCI_EVT indication, EC driver need to fetch events until 0x00 returned (see acpi_ec_clear()). Issue 1 - acpi_ec_submit_query(): It's reported on Samsung laptops that SCI_EVT isn't checked when the transactions are advanced in ec_poll(), which leads to SCI_EVT triggering source lost: If no EC GPE IRQs are arrived after that, EC driver cannot detect this event and handle it. See comment 244/247 for kernel bugzilla 44161. This patch fixes this issue by moving SCI_EVT checks into advance_transaction(). So that SCI_EVT is checked each time we are going to handle the EC firmware indications. And this check will happen for both IRQ context and task context. Since after doing that, SCI_EVT is also checked after completing a transaction, ec_check_sci() and ec_check_sci_sync() can be removed. Issue 2 - acpi_ec_complete_query(): We expect to clear EC_FLAGS_QUERY_PENDING to allow queuing another draining QR_EC after writing a QR_EC command and before reading the event. After reading the event, SCI_EVT might be cleared by the firmware, thus it may not be possible to queue such a draining QR_EC at that time. But putting the EC_FLAGS_QUERY_PENDING clearing code after start_transaction() is wrong as there are chances that after start_transaction(), QR_EC can fail to be sent. If this happens, EC_FLAG_QUERY_PENDING will be cleared earlier. As a consequence, the draining QR_EC will also be queued earlier than expected. This patch also moves this code into advance_transaction() where QR_EC is just sent (ACPI_EC_COMMAND_POLL flagged) to fix this issue. Notes: 1. After introducing the 2 SCI_EVT related handlings into advance_transaction(), a next QR_EC can be queued right after writing the current QR_EC command and before reading the event. But this still hasn't implemented the draining behavior as the draining support requires: If a previous returned event value isn't 0x00, a draining QR_EC need to be issued even when SCI_EVT isn't set. 2. In this patch, acpi_os_execute() is also converted into a seperate work item to avoid invoking kmalloc() in the atomic context. We can do this because of the previous global lock fix. 3. Originally, EC_FLAGS_EVENT_PENDING is also used to avoid queuing up multiple work items (created by acpi_os_execute()), this can be covered by only using a single work item. But this patch still keeps this flag as there are different usages in the driver initialization steps relying on this flag. Link: https://bugzilla.kernel.org/show_bug.cgi?id=44161 Reported-by: Kieran Clancy Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 3c97122..89e89b2 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -120,6 +120,8 @@ struct transaction { u8 flags; }; +static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data); + struct acpi_ec *boot_ec, *first_ec; EXPORT_SYMBOL(first_ec); @@ -189,6 +191,22 @@ static const char *acpi_ec_cmd_string(u8 cmd) #define acpi_ec_cmd_string(cmd) "UNDEF" #endif +static void acpi_ec_submit_query(struct acpi_ec *ec) +{ + if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { + pr_debug("***** Event started *****\n"); + schedule_work(&ec->work); + } +} + +static void acpi_ec_complete_query(struct acpi_ec *ec) +{ + if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { + clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); + pr_debug("***** Event stopped *****\n"); + } +} + static int ec_transaction_completed(struct acpi_ec *ec) { unsigned long flags; @@ -242,6 +260,7 @@ 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_query(ec); t->rdata[t->ri++] = 0x00; t->flags |= ACPI_EC_COMMAND_COMPLETE; pr_debug("***** Command(%s) software completion *****\n", @@ -250,6 +269,7 @@ static void advance_transaction(struct acpi_ec *ec) } else if ((status & ACPI_EC_FLAG_IBF) == 0) { acpi_ec_write_cmd(ec, t->command); t->flags |= ACPI_EC_COMMAND_POLL; + acpi_ec_complete_query(ec); } else goto err; goto out; @@ -264,6 +284,8 @@ err: ++t->irq_count; } out: + if (status & ACPI_EC_FLAG_SCI) + acpi_ec_submit_query(ec); if (wakeup && in_interrupt()) wake_up(&ec->wait); } @@ -275,17 +297,6 @@ static void start_transaction(struct acpi_ec *ec) advance_transaction(ec); } -static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data); - -static int ec_check_sci_sync(struct acpi_ec *ec, u8 state) -{ - if (state & ACPI_EC_FLAG_SCI) { - if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) - return acpi_ec_sync_query(ec, NULL); - } - return 0; -} - static int ec_poll(struct acpi_ec *ec) { unsigned long flags; @@ -333,10 +344,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, pr_debug("***** Command(%s) started *****\n", acpi_ec_cmd_string(t->command)); start_transaction(ec); - if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { - clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); - pr_debug("***** Event stopped *****\n"); - } spin_unlock_irqrestore(&ec->lock, tmp); ret = ec_poll(ec); spin_lock_irqsave(&ec->lock, tmp); @@ -376,8 +383,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) status = acpi_ec_transaction_unlocked(ec, t); - /* check if we received SCI during transaction */ - ec_check_sci_sync(ec, acpi_ec_read_status(ec)); if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { msleep(1); /* It is safe to enable the GPE outside of the transaction. */ @@ -687,14 +692,12 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) return result; } -static void acpi_ec_gpe_query(void *ec_cxt) +static void acpi_ec_gpe_poller(struct work_struct *work) { - struct acpi_ec *ec = ec_cxt; acpi_status status; u32 glk; + struct acpi_ec *ec = container_of(work, struct acpi_ec, work); - if (!ec) - return; mutex_lock(&ec->mutex); if (ec->global_lock) { status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); @@ -708,18 +711,6 @@ unlock: mutex_unlock(&ec->mutex); } -static int ec_check_sci(struct acpi_ec *ec, u8 state) -{ - if (state & ACPI_EC_FLAG_SCI) { - if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { - pr_debug("***** Event started *****\n"); - return acpi_os_execute(OSL_NOTIFY_HANDLER, - acpi_ec_gpe_query, ec); - } - } - return 0; -} - static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, u32 gpe_number, void *data) { @@ -729,7 +720,6 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, spin_lock_irqsave(&ec->lock, flags); advance_transaction(ec); spin_unlock_irqrestore(&ec->lock, flags); - ec_check_sci(ec, acpi_ec_read_status(ec)); return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE; } @@ -793,6 +783,7 @@ static struct acpi_ec *make_acpi_ec(void) init_waitqueue_head(&ec->wait); INIT_LIST_HEAD(&ec->list); spin_lock_init(&ec->lock); + INIT_WORK(&ec->work, acpi_ec_gpe_poller); return ec; } diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 163e82f..dc42078 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -127,6 +127,7 @@ struct acpi_ec { struct list_head list; struct transaction *curr; spinlock_t lock; + struct work_struct work; }; extern struct acpi_ec *first_ec; -- cgit v0.10.2 From 550b3aac5a72c4209f1ad3bc0ade663d5cb36f7f Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 14 Jan 2015 19:28:53 +0800 Subject: ACPI / EC: Cleanup QR_EC related code The QR_EC related code pieces have redundants, this patch merges them into acpi_ec_query() which invokes acpi_ec_transaction() where EC mutex and the global lock are already held. After doing so, query handler traversal still need to be locked by EC mutex after invoking acpi_ec_transaction(). Note that EC event handling is sequential. We fetch one event from firmware event queue and process it until 0x00 or error returned. So we don't need to hold mutex for whole acpi_ec_clear() process to determine whether we should continue to drain. And for the same reason, we don't need to hold mutex for the whole procedure from the QR_EC transaction to the query handler traversal. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 89e89b2..c385606 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -120,7 +120,7 @@ struct transaction { u8 flags; }; -static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data); +static int acpi_ec_query(struct acpi_ec *ec, u8 *data); struct acpi_ec *boot_ec, *first_ec; EXPORT_SYMBOL(first_ec); @@ -508,7 +508,7 @@ static void acpi_ec_clear(struct acpi_ec *ec) u8 value = 0; for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) { - status = acpi_ec_sync_query(ec, &value); + status = acpi_ec_query(ec, &value); if (status || !value) break; } @@ -539,14 +539,11 @@ void acpi_ec_unblock_transactions(void) if (!ec) return; - mutex_lock(&ec->mutex); /* Allow transactions to be carried out again */ clear_bit(EC_FLAGS_BLOCKED, &ec->flags); if (EC_FLAGS_CLEAR_ON_RESUME) acpi_ec_clear(ec); - - mutex_unlock(&ec->mutex); } void acpi_ec_unblock_transactions_early(void) @@ -559,30 +556,6 @@ void acpi_ec_unblock_transactions_early(void) clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags); } -static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data) -{ - int result; - u8 d; - struct transaction t = {.command = ACPI_EC_COMMAND_QUERY, - .wdata = NULL, .rdata = &d, - .wlen = 0, .rlen = 1}; - - if (!ec || !data) - return -EINVAL; - /* - * Query the EC to find out which _Qxx method we need to evaluate. - * Note that successful completion of the query causes the ACPI_EC_SCI - * bit to be cleared (and thus clearing the interrupt source). - */ - result = acpi_ec_transaction_unlocked(ec, &t); - if (result) - return result; - if (!d) - return -ENODATA; - *data = d; - return 0; -} - /* -------------------------------------------------------------------------- Event Management -------------------------------------------------------------------------- */ @@ -662,19 +635,30 @@ static void acpi_ec_run(void *cxt) acpi_ec_put_query_handler(handler); } -static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) +static int acpi_ec_query(struct acpi_ec *ec, u8 *data) { u8 value = 0; int result; acpi_status status; struct acpi_ec_query_handler *handler; + struct transaction t = {.command = ACPI_EC_COMMAND_QUERY, + .wdata = NULL, .rdata = &value, + .wlen = 0, .rlen = 1}; - result = acpi_ec_query_unlocked(ec, &value); - if (data) - *data = value; + /* + * Query the EC to find out which _Qxx method we need to evaluate. + * Note that successful completion of the query causes the ACPI_EC_SCI + * bit to be cleared (and thus clearing the interrupt source). + */ + result = acpi_ec_transaction(ec, &t); if (result) return result; + if (data) + *data = value; + if (!value) + return -ENODATA; + mutex_lock(&ec->mutex); list_for_each_entry(handler, &ec->list, node) { if (value == handler->query_bit) { /* have custom handler for this bit */ @@ -689,26 +673,15 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) break; } } + mutex_unlock(&ec->mutex); return result; } static void acpi_ec_gpe_poller(struct work_struct *work) { - acpi_status status; - u32 glk; struct acpi_ec *ec = container_of(work, struct acpi_ec, work); - mutex_lock(&ec->mutex); - if (ec->global_lock) { - status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); - if (ACPI_FAILURE(status)) - goto unlock; - } - acpi_ec_sync_query(ec, NULL); - if (ec->global_lock) - acpi_release_global_lock(glk); -unlock: - mutex_unlock(&ec->mutex); + acpi_ec_query(ec, NULL); } static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, @@ -932,11 +905,8 @@ static int acpi_ec_add(struct acpi_device *device) clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); /* Clear stale _Q events if hardware might require that */ - if (EC_FLAGS_CLEAR_ON_RESUME) { - mutex_lock(&ec->mutex); + if (EC_FLAGS_CLEAR_ON_RESUME) acpi_ec_clear(ec); - mutex_unlock(&ec->mutex); - } return ret; } -- cgit v0.10.2 From b893e80e314749bce4597a262b7d04e929016e51 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 23 Jan 2015 09:42:39 +0200 Subject: ACPI / LPSS: Remove non-existing clock control from Intel Lynxpoint I2C Intel Lynxpoint I2C does not have clock parameter register like SPI and UART do have. Therefore remove LPSS_CLK_GATE flag from the Lynxpoint I2C device description in order to not needlessly toggle clock enable bit in non-existing register. Signed-off-by: Jarkko Nikula Acked-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index d12f98a..794cf3e 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -129,7 +129,7 @@ static struct lpss_device_desc lpt_dev_desc = { }; static struct lpss_device_desc lpt_i2c_dev_desc = { - .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_LTR, + .flags = LPSS_CLK | LPSS_LTR, .prv_offset = 0x800, }; -- cgit v0.10.2 From 8b691c9cf297bc32a021b7fef0dd0e32f130e542 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 23 Jan 2015 08:12:06 +0000 Subject: ACPI / sleep: mark acpi_sleep_dmi_check() __init This makes a difference if the compiler decides not to inline the function, as then the function's reference to acpisleep_dmi_table[] yields a section mismatch warning. Signed-off-by: Jan Beulich Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 8aa9254..7f251dd 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -321,7 +321,7 @@ static struct dmi_system_id acpisleep_dmi_table[] __initdata = { {}, }; -static void acpi_sleep_dmi_check(void) +static void __init acpi_sleep_dmi_check(void) { int year; -- cgit v0.10.2 From bac2a909a096c9110525c18cbb8ce73c660d5f71 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 21 Jan 2015 02:17:42 +0100 Subject: PCI / PM: Avoid resuming PCI devices during system suspend Commit f25c0ae2b4c4 (ACPI / PM: Avoid resuming devices in ACPI PM domain during system suspend) modified the ACPI PM domain's system suspend callbacks to allow devices attached to it to be left in the runtime-suspended state during system suspend so as to optimize the suspend process. This was based on the general mechanism introduced by commit aae4518b3124 (PM / sleep: Mechanism to avoid resuming runtime-suspended devices unnecessarily). Extend that approach to PCI devices by modifying the PCI bus type's ->prepare callback to return 1 for devices that are runtime-suspended when it is being executed and that are in a suitable power state and need not be resumed going forward. Signed-off-by: Rafael J. Wysocki Acked-by: Bjorn Helgaas diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 3542150..4890639 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -501,12 +501,29 @@ static int acpi_pci_run_wake(struct pci_dev *dev, bool enable) return 0; } +static bool acpi_pci_need_resume(struct pci_dev *dev) +{ + struct acpi_device *adev = ACPI_COMPANION(&dev->dev); + + if (!adev || !acpi_device_power_manageable(adev)) + return false; + + if (device_may_wakeup(&dev->dev) != !!adev->wakeup.prepare_count) + return true; + + if (acpi_target_system_state() == ACPI_STATE_S0) + return false; + + return !!adev->power.flags.dsw_present; +} + static struct pci_platform_pm_ops acpi_pci_platform_pm = { .is_manageable = acpi_pci_power_manageable, .set_state = acpi_pci_set_power_state, .choose_state = acpi_pci_choose_state, .sleep_wake = acpi_pci_sleep_wake, .run_wake = acpi_pci_run_wake, + .need_resume = acpi_pci_need_resume, }; void acpi_pci_add_bus(struct pci_bus *bus) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 887e6bd..741023e 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -653,7 +653,6 @@ static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev) static int pci_pm_prepare(struct device *dev) { struct device_driver *drv = dev->driver; - int error = 0; /* * Devices having power.ignore_children set may still be necessary for @@ -662,10 +661,12 @@ static int pci_pm_prepare(struct device *dev) if (dev->power.ignore_children) pm_runtime_resume(dev); - if (drv && drv->pm && drv->pm->prepare) - error = drv->pm->prepare(dev); - - return error; + if (drv && drv->pm && drv->pm->prepare) { + int error = drv->pm->prepare(dev); + if (error) + return error; + } + return pci_dev_keep_suspended(to_pci_dev(dev)); } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index cab05f3..7a671ab 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -521,6 +521,11 @@ static inline int platform_pci_run_wake(struct pci_dev *dev, bool enable) pci_platform_pm->run_wake(dev, enable) : -ENODEV; } +static inline bool platform_pci_need_resume(struct pci_dev *dev) +{ + return pci_platform_pm ? pci_platform_pm->need_resume(dev) : false; +} + /** * pci_raw_set_power_state - Use PCI PM registers to set the power state of * given PCI device @@ -1999,6 +2004,27 @@ bool pci_dev_run_wake(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_dev_run_wake); +/** + * pci_dev_keep_suspended - Check if the device can stay in the suspended state. + * @pci_dev: Device to check. + * + * Return 'true' if the device is runtime-suspended, it doesn't have to be + * reconfigured due to wakeup settings difference between system and runtime + * suspend and the current power state of it is suitable for the upcoming + * (system) transition. + */ +bool pci_dev_keep_suspended(struct pci_dev *pci_dev) +{ + struct device *dev = &pci_dev->dev; + + if (!pm_runtime_suspended(dev) + || (device_can_wakeup(dev) && !device_may_wakeup(dev)) + || platform_pci_need_resume(pci_dev)) + return false; + + return pci_target_state(pci_dev) == pci_dev->current_state; +} + void pci_config_pm_runtime_get(struct pci_dev *pdev) { struct device *dev = &pdev->dev; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 8aff29a..febb3db 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -50,6 +50,10 @@ int pci_probe_reset_function(struct pci_dev *dev); * for given device (the device's wake-up capability has to be * enabled by @sleep_wake for this feature to work) * + * @need_resume: returns 'true' if the given device (which is currently + * suspended) needs to be resumed to be configured for system + * wakeup. + * * If given platform is generally capable of power managing PCI devices, all of * these callbacks are mandatory. */ @@ -59,6 +63,7 @@ struct pci_platform_pm_ops { pci_power_t (*choose_state)(struct pci_dev *dev); int (*sleep_wake)(struct pci_dev *dev, bool enable); int (*run_wake)(struct pci_dev *dev, bool enable); + bool (*need_resume)(struct pci_dev *dev); }; int pci_set_platform_pm(struct pci_platform_pm_ops *ops); @@ -67,6 +72,7 @@ void pci_power_up(struct pci_dev *dev); void pci_disable_enabled_device(struct pci_dev *dev); int pci_finish_runtime_suspend(struct pci_dev *dev); int __pci_pme_wakeup(struct pci_dev *dev, void *ign); +bool pci_dev_keep_suspended(struct pci_dev *dev); void pci_config_pm_runtime_get(struct pci_dev *dev); void pci_config_pm_runtime_put(struct pci_dev *dev); void pci_pm_init(struct pci_dev *dev); -- cgit v0.10.2 From f5f4eda4c9b9e26ec7d7c8ce083e386016ffc0f8 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 5 Dec 2014 11:19:08 -0600 Subject: PM / QoS: Add debugfs support to view the list of constraints PM QoS requests are notoriously hard to debug and made even more so due to their highly dynamic nature. Having visibility into the internal data representation per constraint allows us to have much better appreciation of potential issues or bad usage by drivers in the system. So introduce for all classes of PM QoS, an entry in /sys/kernel/debug/pm_qos that shall show all the current requests as well as the snapshot of the value these requests boil down to. For example: ==> /sys/kernel/debug/pm_qos/cpu_dma_latency <== 1: 4444: Active 2: 2000000000: Default 3: 2000000000: Default 4: 2000000000: Default Type=Minimum, Value=4444, Requests: active=1 / total=4 ==> /sys/kernel/debug/pm_qos/memory_bandwidth <== Empty! ... The actual value listed will have their meaning based on the QoS it is on, the 'Type' indicates what logic it would use to collate the information - Minimum, Maximum, or Sum. Value is the collation of all requests. This interface also compares the values with the defaults for the QoS class and marks the ones that are currently active. Signed-off-by: Nishanth Menon Signed-off-by: Dave Gerlach Acked-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 5f4c006..97b0df7 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include #include @@ -182,6 +184,81 @@ static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value) c->target_value = value; } +static inline int pm_qos_get_value(struct pm_qos_constraints *c); +static int pm_qos_dbg_show_requests(struct seq_file *s, void *unused) +{ + struct pm_qos_object *qos = (struct pm_qos_object *)s->private; + struct pm_qos_constraints *c; + struct pm_qos_request *req; + char *type; + unsigned long flags; + int tot_reqs = 0; + int active_reqs = 0; + + if (IS_ERR_OR_NULL(qos)) { + pr_err("%s: bad qos param!\n", __func__); + return -EINVAL; + } + c = qos->constraints; + if (IS_ERR_OR_NULL(c)) { + pr_err("%s: Bad constraints on qos?\n", __func__); + return -EINVAL; + } + + /* Lock to ensure we have a snapshot */ + spin_lock_irqsave(&pm_qos_lock, flags); + if (plist_head_empty(&c->list)) { + seq_puts(s, "Empty!\n"); + goto out; + } + + switch (c->type) { + case PM_QOS_MIN: + type = "Minimum"; + break; + case PM_QOS_MAX: + type = "Maximum"; + break; + case PM_QOS_SUM: + type = "Sum"; + break; + default: + type = "Unknown"; + } + + plist_for_each_entry(req, &c->list, node) { + char *state = "Default"; + + if ((req->node).prio != c->default_value) { + active_reqs++; + state = "Active"; + } + tot_reqs++; + seq_printf(s, "%d: %d: %s\n", tot_reqs, + (req->node).prio, state); + } + + seq_printf(s, "Type=%s, Value=%d, Requests: active=%d / total=%d\n", + type, pm_qos_get_value(c), active_reqs, tot_reqs); + +out: + spin_unlock_irqrestore(&pm_qos_lock, flags); + return 0; +} + +static int pm_qos_dbg_open(struct inode *inode, struct file *file) +{ + return single_open(file, pm_qos_dbg_show_requests, + inode->i_private); +} + +static const struct file_operations pm_qos_debug_fops = { + .open = pm_qos_dbg_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /** * pm_qos_update_target - manages the constraints list and calls the notifiers * if needed @@ -509,12 +586,17 @@ int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier) EXPORT_SYMBOL_GPL(pm_qos_remove_notifier); /* User space interface to PM QoS classes via misc devices */ -static int register_pm_qos_misc(struct pm_qos_object *qos) +static int register_pm_qos_misc(struct pm_qos_object *qos, struct dentry *d) { qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR; qos->pm_qos_power_miscdev.name = qos->name; qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops; + if (d) { + (void)debugfs_create_file(qos->name, S_IRUGO, d, + (void *)qos, &pm_qos_debug_fops); + } + return misc_register(&qos->pm_qos_power_miscdev); } @@ -608,11 +690,16 @@ static int __init pm_qos_power_init(void) { int ret = 0; int i; + struct dentry *d; BUILD_BUG_ON(ARRAY_SIZE(pm_qos_array) != PM_QOS_NUM_CLASSES); + d = debugfs_create_dir("pm_qos", NULL); + if (IS_ERR_OR_NULL(d)) + d = NULL; + for (i = PM_QOS_CPU_DMA_LATENCY; i < PM_QOS_NUM_CLASSES; i++) { - ret = register_pm_qos_misc(pm_qos_array[i]); + ret = register_pm_qos_misc(pm_qos_array[i], d); if (ret < 0) { printk(KERN_ERR "pm_qos_param: %s setup failed\n", pm_qos_array[i]->name); -- cgit v0.10.2 From a6a919b6ae7c438c89c4c7349c8bc1e48a30ef4d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 21 Dec 2014 22:14:26 +0100 Subject: cpufreq: drop owner assignment from platform_drivers This platform_driver does not need to set an owner, it will be populated by the driver core. Signed-off-by: Wolfram Sang Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/ls1x-cpufreq.c b/drivers/cpufreq/ls1x-cpufreq.c index 25fbd6a..f0913ee 100644 --- a/drivers/cpufreq/ls1x-cpufreq.c +++ b/drivers/cpufreq/ls1x-cpufreq.c @@ -210,7 +210,6 @@ out: static struct platform_driver ls1x_cpufreq_platdrv = { .driver = { .name = "ls1x-cpufreq", - .owner = THIS_MODULE, }, .probe = ls1x_cpufreq_probe, .remove = ls1x_cpufreq_remove, -- cgit v0.10.2 From 90de2a4aa9f355b55e57eaf2fd584897dd0adf8c Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Tue, 23 Dec 2014 22:09:48 -0800 Subject: cpufreq: suspend cpufreq governors on shutdown We should stop cpufreq governors when we shut down the system. If we don't do this, we can end up with this deadlock: 1. cpufreq governor may be running on a CPU other than CPU0. 2. In machine_restart() we call smp_send_stop() which stops CPUs. If one of these CPUs was actively running a cpufreq governor then it may have the mutex / spinlock needed to access the main PMIC in the system (perhaps over I2C) 3. If a machine needs access to the main PMIC in order to shutdown then it will never get it since the mutex was lost when the other CPU stopped. 4. We'll hang (possibly eventually hitting the hard lockup detector). Let's avoid the problem by stopping the cpufreq governor at shutdown, which is a sensible thing to do anyway. Signed-off-by: Doug Anderson Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 46bed4f..dad72359 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -2556,6 +2557,14 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) } EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); +/* + * Stop cpufreq at shutdown to make sure it isn't holding any locks + * or mutexes when secondary CPUs are halted. + */ +static struct syscore_ops cpufreq_syscore_ops = { + .shutdown = cpufreq_suspend, +}; + static int __init cpufreq_core_init(void) { if (cpufreq_disabled()) @@ -2564,6 +2573,8 @@ static int __init cpufreq_core_init(void) cpufreq_global_kobject = kobject_create(); BUG_ON(!cpufreq_global_kobject); + register_syscore_ops(&cpufreq_syscore_ops); + return 0; } core_initcall(cpufreq_core_init); -- cgit v0.10.2 From 4679ec3727a0eb4d57e23dffa8e19ce911362c9f Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Wed, 24 Dec 2014 11:22:55 -0600 Subject: PM / OPP: export dev_pm_opp_get_notifier Allows user drivers such as devfreq to be modules. Signed-off-by: Nishanth Menon Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 106c693..435c94e 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -742,6 +742,7 @@ struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev) return &dev_opp->srcu_head; } +EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier); #ifdef CONFIG_OF /** -- cgit v0.10.2 From 327854c871178af58461b34f116a0300fbb3a74f Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Wed, 24 Dec 2014 11:22:56 -0600 Subject: PM / OPP: Ensure consistent naming of static functions All exported functions use dev_pm_* prefix and all static functions are now standardized with _ prefix. This is better than having to deal with multiple function naming styles within the same file. Signed-off-by: Nishanth Menon Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 435c94e..f4aa85a 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -117,7 +117,7 @@ do { \ } while (0) /** - * find_device_opp() - find device_opp struct using device pointer + * _find_device_opp() - find device_opp struct using device pointer * @dev: device pointer used to lookup device OPPs * * Search list of device OPPs for one containing matching device. Does a RCU @@ -130,7 +130,7 @@ do { \ * is a RCU protected pointer. This means that device_opp is valid as long * as we are under RCU lock. */ -static struct device_opp *find_device_opp(struct device *dev) +static struct device_opp *_find_device_opp(struct device *dev) { struct device_opp *tmp_dev_opp, *dev_opp = ERR_PTR(-ENODEV); @@ -226,7 +226,7 @@ int dev_pm_opp_get_opp_count(struct device *dev) rcu_read_lock(); - dev_opp = find_device_opp(dev); + dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) { count = PTR_ERR(dev_opp); dev_err(dev, "%s: device OPP not found (%d)\n", @@ -280,7 +280,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, opp_rcu_lockdep_assert(); - dev_opp = find_device_opp(dev); + dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) { int r = PTR_ERR(dev_opp); dev_err(dev, "%s: device OPP not found (%d)\n", __func__, r); @@ -333,7 +333,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev, return ERR_PTR(-EINVAL); } - dev_opp = find_device_opp(dev); + dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) return ERR_CAST(dev_opp); @@ -383,7 +383,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, return ERR_PTR(-EINVAL); } - dev_opp = find_device_opp(dev); + dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) return ERR_CAST(dev_opp); @@ -403,7 +403,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, } EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor); -static struct device_opp *add_device_opp(struct device *dev) +static struct device_opp *_add_device_opp(struct device *dev) { struct device_opp *dev_opp; @@ -424,8 +424,8 @@ static struct device_opp *add_device_opp(struct device *dev) return dev_opp; } -static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq, - unsigned long u_volt, bool dynamic) +static int _opp_add_dynamic(struct device *dev, unsigned long freq, + long u_volt, bool dynamic) { struct device_opp *dev_opp = NULL; struct dev_pm_opp *opp, *new_opp; @@ -449,9 +449,9 @@ static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq, new_opp->dynamic = dynamic; /* Check for existing list for 'dev' */ - dev_opp = find_device_opp(dev); + dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) { - dev_opp = add_device_opp(dev); + dev_opp = _add_device_opp(dev); if (!dev_opp) { ret = -ENOMEM; goto free_opp; @@ -527,26 +527,26 @@ free_opp: */ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) { - return dev_pm_opp_add_dynamic(dev, freq, u_volt, true); + return _opp_add_dynamic(dev, freq, u_volt, true); } EXPORT_SYMBOL_GPL(dev_pm_opp_add); -static void kfree_opp_rcu(struct rcu_head *head) +static void _kfree_opp_rcu(struct rcu_head *head) { struct dev_pm_opp *opp = container_of(head, struct dev_pm_opp, rcu_head); kfree_rcu(opp, rcu_head); } -static void kfree_device_rcu(struct rcu_head *head) +static void _kfree_device_rcu(struct rcu_head *head) { struct device_opp *device_opp = container_of(head, struct device_opp, rcu_head); kfree_rcu(device_opp, rcu_head); } -static void __dev_pm_opp_remove(struct device_opp *dev_opp, - struct dev_pm_opp *opp) +static void _opp_remove(struct device_opp *dev_opp, + struct dev_pm_opp *opp) { /* * Notify the changes in the availability of the operable @@ -554,12 +554,12 @@ static void __dev_pm_opp_remove(struct device_opp *dev_opp, */ srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp); list_del_rcu(&opp->node); - call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, kfree_opp_rcu); + call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu); if (list_empty(&dev_opp->opp_list)) { list_del_rcu(&dev_opp->node); call_srcu(&dev_opp->srcu_head.srcu, &dev_opp->rcu_head, - kfree_device_rcu); + _kfree_device_rcu); } } @@ -579,7 +579,7 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq) /* Hold our list modification lock here */ mutex_lock(&dev_opp_list_lock); - dev_opp = find_device_opp(dev); + dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) goto unlock; @@ -596,14 +596,14 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq) goto unlock; } - __dev_pm_opp_remove(dev_opp, opp); + _opp_remove(dev_opp, opp); unlock: mutex_unlock(&dev_opp_list_lock); } EXPORT_SYMBOL_GPL(dev_pm_opp_remove); /** - * opp_set_availability() - helper to set the availability of an opp + * _opp_set_availability() - helper to set the availability of an opp * @dev: device for which we do this operation * @freq: OPP frequency to modify availability * @availability_req: availability status requested for this opp @@ -621,8 +621,8 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_remove); * that this function is *NOT* called under RCU protection or in contexts where * mutex locking or synchronize_rcu() blocking calls cannot be used. */ -static int opp_set_availability(struct device *dev, unsigned long freq, - bool availability_req) +static int _opp_set_availability(struct device *dev, unsigned long freq, + bool availability_req) { struct device_opp *dev_opp; struct dev_pm_opp *new_opp, *tmp_opp, *opp = ERR_PTR(-ENODEV); @@ -638,7 +638,7 @@ static int opp_set_availability(struct device *dev, unsigned long freq, mutex_lock(&dev_opp_list_lock); /* Find the device_opp */ - dev_opp = find_device_opp(dev); + dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) { r = PTR_ERR(dev_opp); dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r); @@ -668,7 +668,7 @@ static int opp_set_availability(struct device *dev, unsigned long freq, list_replace_rcu(&opp->node, &new_opp->node); mutex_unlock(&dev_opp_list_lock); - call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, kfree_opp_rcu); + call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu); /* Notify the change of the OPP availability */ if (availability_req) @@ -703,7 +703,7 @@ unlock: */ int dev_pm_opp_enable(struct device *dev, unsigned long freq) { - return opp_set_availability(dev, freq, true); + return _opp_set_availability(dev, freq, true); } EXPORT_SYMBOL_GPL(dev_pm_opp_enable); @@ -725,7 +725,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_enable); */ int dev_pm_opp_disable(struct device *dev, unsigned long freq) { - return opp_set_availability(dev, freq, false); + return _opp_set_availability(dev, freq, false); } EXPORT_SYMBOL_GPL(dev_pm_opp_disable); @@ -735,7 +735,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_disable); */ struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev) { - struct device_opp *dev_opp = find_device_opp(dev); + struct device_opp *dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) return ERR_CAST(dev_opp); /* matching type */ @@ -778,7 +778,7 @@ int of_init_opp_table(struct device *dev) unsigned long freq = be32_to_cpup(val++) * 1000; unsigned long volt = be32_to_cpup(val++); - if (dev_pm_opp_add_dynamic(dev, freq, volt, false)) + if (_opp_add_dynamic(dev, freq, volt, false)) dev_warn(dev, "%s: Failed to add OPP %ld\n", __func__, freq); nr -= 2; @@ -800,7 +800,7 @@ void of_free_opp_table(struct device *dev) struct dev_pm_opp *opp, *tmp; /* Check for existing list for 'dev' */ - dev_opp = find_device_opp(dev); + dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) { int error = PTR_ERR(dev_opp); if (error != -ENODEV) @@ -817,7 +817,7 @@ void of_free_opp_table(struct device *dev) /* Free static OPPs */ list_for_each_entry_safe(opp, tmp, &dev_opp->opp_list, node) { if (!opp->dynamic) - __dev_pm_opp_remove(dev_opp, opp); + _opp_remove(dev_opp, opp); } mutex_unlock(&dev_opp_list_lock); -- cgit v0.10.2 From 984f16c8490cba715444124a453ed4a2ac7a5a54 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Wed, 24 Dec 2014 11:22:57 -0600 Subject: PM / OPP: Update kernel documentation kernel doc has gotten bit-rotted over time. Re-sync with Locking and Return information. document all functions properly and ensure that ./scripts/kernel-doc -v ./drivers/base/power/opp.c >/dev/null returns no errors Signed-off-by: Nishanth Menon Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index f4aa85a..1d20e09 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -123,7 +123,7 @@ do { \ * Search list of device OPPs for one containing matching device. Does a RCU * reader operation to grab the pointer needed. * - * Returns pointer to 'struct device_opp' if found, otherwise -ENODEV or + * Return: pointer to 'struct device_opp' if found, otherwise -ENODEV or * -EINVAL based on type of error. * * Locking: This function must be called under rcu_read_lock(). device_opp @@ -153,7 +153,7 @@ static struct device_opp *_find_device_opp(struct device *dev) * dev_pm_opp_get_voltage() - Gets the voltage corresponding to an available opp * @opp: opp for which voltage has to be returned for * - * Return voltage in micro volt corresponding to the opp, else + * Return: voltage in micro volt corresponding to the opp, else * return 0 * * Locking: This function must be called under rcu_read_lock(). opp is a rcu @@ -183,7 +183,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage); * dev_pm_opp_get_freq() - Gets the frequency corresponding to an available opp * @opp: opp for which frequency has to be returned for * - * Return frequency in hertz corresponding to the opp, else + * Return: frequency in hertz corresponding to the opp, else * return 0 * * Locking: This function must be called under rcu_read_lock(). opp is a rcu @@ -213,7 +213,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq); * dev_pm_opp_get_opp_count() - Get number of opps available in the opp list * @dev: device for which we do this operation * - * This function returns the number of available opps if there are any, + * Return: This function returns the number of available opps if there are any, * else returns 0 if none or the corresponding error value. * * Locking: This function takes rcu_read_lock(). @@ -251,9 +251,9 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count); * @freq: frequency to search for * @available: true/false - match for available opp * - * Searches for exact match in the opp list and returns pointer to the matching - * opp if found, else returns ERR_PTR in case of error and should be handled - * using IS_ERR. Error return values can be: + * Return: Searches for exact match in the opp list and returns pointer to the + * matching opp if found, else returns ERR_PTR in case of error and should + * be handled using IS_ERR. Error return values can be: * EINVAL: for bad pointer * ERANGE: no match found for search * ENODEV: if device not found in list of registered devices @@ -307,7 +307,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact); * Search for the matching ceil *available* OPP from a starting freq * for a device. * - * Returns matching *opp and refreshes *freq accordingly, else returns + * Return: matching *opp and refreshes *freq accordingly, else returns * ERR_PTR in case of error and should be handled using IS_ERR. Error return * values can be: * EINVAL: for bad pointer @@ -357,7 +357,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil); * Search for the matching floor *available* OPP from a starting freq * for a device. * - * Returns matching *opp and refreshes *freq accordingly, else returns + * Return: matching *opp and refreshes *freq accordingly, else returns * ERR_PTR in case of error and should be handled using IS_ERR. Error return * values can be: * EINVAL: for bad pointer @@ -403,6 +403,15 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, } EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor); +/** + * _add_device_opp() - Allocate a new device OPP table + * @dev: device for which we do this operation + * + * New device node which uses OPPs - used when multiple devices with OPP tables + * are maintained. + * + * Return: valid device_opp pointer if success, else NULL. + */ static struct device_opp *_add_device_opp(struct device *dev) { struct device_opp *dev_opp; @@ -424,6 +433,33 @@ static struct device_opp *_add_device_opp(struct device *dev) return dev_opp; } +/** + * _opp_add_dynamic() - Allocate a dynamic OPP. + * @dev: device for which we do this operation + * @freq: Frequency in Hz for this OPP + * @u_volt: Voltage in uVolts for this OPP + * @dynamic: Dynamically added OPPs. + * + * This function adds an opp definition to the opp list and returns status. + * The opp is made available by default and it can be controlled using + * dev_pm_opp_enable/disable functions and may be removed by dev_pm_opp_remove. + * + * NOTE: "dynamic" parameter impacts OPPs added by the of_init_opp_table and + * freed by of_free_opp_table. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function internally uses RCU updater strategy with mutex locks + * to keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. + * + * Return: + * 0 On success OR + * Duplicate OPPs (both freq and volt are same) and opp->available + * -EEXIST Freq are same and volt are different OR + * Duplicate OPPs (both freq and volt are same) and !opp->available + * -ENOMEM Memory allocation failure + */ static int _opp_add_dynamic(struct device *dev, unsigned long freq, long u_volt, bool dynamic) { @@ -519,11 +555,11 @@ free_opp: * mutex cannot be locked. * * Return: - * 0: On success OR + * 0 On success OR * Duplicate OPPs (both freq and volt are same) and opp->available - * -EEXIST: Freq are same and volt are different OR + * -EEXIST Freq are same and volt are different OR * Duplicate OPPs (both freq and volt are same) and !opp->available - * -ENOMEM: Memory allocation failure + * -ENOMEM Memory allocation failure */ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) { @@ -531,6 +567,10 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) } EXPORT_SYMBOL_GPL(dev_pm_opp_add); +/** + * _kfree_opp_rcu() - Free OPP RCU handler + * @head: RCU head + */ static void _kfree_opp_rcu(struct rcu_head *head) { struct dev_pm_opp *opp = container_of(head, struct dev_pm_opp, rcu_head); @@ -538,6 +578,10 @@ static void _kfree_opp_rcu(struct rcu_head *head) kfree_rcu(opp, rcu_head); } +/** + * _kfree_device_rcu() - Free device_opp RCU handler + * @head: RCU head + */ static void _kfree_device_rcu(struct rcu_head *head) { struct device_opp *device_opp = container_of(head, struct device_opp, rcu_head); @@ -545,6 +589,17 @@ static void _kfree_device_rcu(struct rcu_head *head) kfree_rcu(device_opp, rcu_head); } +/** + * _opp_remove() - Remove an OPP from a table definition + * @dev_opp: points back to the device_opp struct this opp belongs to + * @opp: pointer to the OPP to remove + * + * This function removes an opp definition from the opp list. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * It is assumed that the caller holds required mutex for an RCU updater + * strategy. + */ static void _opp_remove(struct device_opp *dev_opp, struct dev_pm_opp *opp) { @@ -569,6 +624,12 @@ static void _opp_remove(struct device_opp *dev_opp, * @freq: OPP to remove with matching 'freq' * * This function removes an opp from the opp list. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function internally uses RCU updater strategy with mutex locks + * to keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. */ void dev_pm_opp_remove(struct device *dev, unsigned long freq) { @@ -611,7 +672,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_remove); * Set the availability of an OPP with an RCU operation, opp_{enable,disable} * share a common logic which is isolated here. * - * Returns -EINVAL for bad pointers, -ENOMEM if no memory available for the + * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the * copy operation, returns 0 if no modifcation was done OR modification was * successful. * @@ -700,6 +761,10 @@ unlock: * integrity of the internal data structures. Callers should ensure that * this function is *NOT* called under RCU protection or in contexts where * mutex locking or synchronize_rcu() blocking calls cannot be used. + * + * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the + * copy operation, returns 0 if no modifcation was done OR modification was + * successful. */ int dev_pm_opp_enable(struct device *dev, unsigned long freq) { @@ -722,6 +787,10 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_enable); * integrity of the internal data structures. Callers should ensure that * this function is *NOT* called under RCU protection or in contexts where * mutex locking or synchronize_rcu() blocking calls cannot be used. + * + * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the + * copy operation, returns 0 if no modifcation was done OR modification was + * successful. */ int dev_pm_opp_disable(struct device *dev, unsigned long freq) { @@ -732,6 +801,16 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_disable); /** * dev_pm_opp_get_notifier() - find notifier_head of the device with opp * @dev: device pointer used to lookup device OPPs. + * + * Return: pointer to notifier head if found, otherwise -ENODEV or + * -EINVAL based on type of error casted as pointer. value must be checked + * with IS_ERR to determine valid pointer or error result. + * + * Locking: This function must be called under rcu_read_lock(). dev_opp is a RCU + * protected pointer. The reason for the same is that the opp pointer which is + * returned will remain valid for use with opp_get_{voltage, freq} only while + * under the locked area. The pointer returned must be used prior to unlocking + * with rcu_read_unlock() to maintain the integrity of the pointer. */ struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev) { @@ -750,6 +829,22 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier); * @dev: device pointer used to lookup device OPPs. * * Register the initial OPP table with the OPP library for given device. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function indirectly uses RCU updater strategy with mutex locks + * to keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. + * + * Return: + * 0 On success OR + * Duplicate OPPs (both freq and volt are same) and opp->available + * -EEXIST Freq are same and volt are different OR + * Duplicate OPPs (both freq and volt are same) and !opp->available + * -ENOMEM Memory allocation failure + * -ENODEV when 'operating-points' property is not found or is invalid data + * in device node. + * -ENODATA when empty 'operating-points' property is found */ int of_init_opp_table(struct device *dev) { @@ -793,6 +888,12 @@ EXPORT_SYMBOL_GPL(of_init_opp_table); * @dev: device pointer used to lookup device OPPs. * * Free OPPs created using static entries present in DT. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function indirectly uses RCU updater strategy with mutex locks + * to keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. */ void of_free_opp_table(struct device *dev) { -- cgit v0.10.2 From f90b8ad83a6ae984edb6b489ed02e45dadfd263e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 9 Jan 2015 09:27:58 +0100 Subject: PM / QoS: Use lockdep asserts to find missing hold of power.lock Add lockdep asserts for holding the dev->power.lock to non-static functions which require this. They could be used outside of the file so asserts may help in detecting locking misuse. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index a8fe4c1..e56d538 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -64,6 +64,8 @@ enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask) struct pm_qos_flags *pqf; s32 val; + lockdep_assert_held(&dev->power.lock); + if (IS_ERR_OR_NULL(qos)) return PM_QOS_FLAGS_UNDEFINED; @@ -104,6 +106,8 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_flags); */ s32 __dev_pm_qos_read_value(struct device *dev) { + lockdep_assert_held(&dev->power.lock); + return IS_ERR_OR_NULL(dev->power.qos) ? 0 : pm_qos_read_value(&dev->power.qos->resume_latency); } -- cgit v0.10.2 From 04bf1c7f76b05be8134a833ec023f1c96f81b8a1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 9 Jan 2015 09:27:57 +0100 Subject: PM / OPP: Assert RCU lock in exported functions Add lockdep asserts for holding the RCU lock when calling dev_pm_opp_get_freq() and dev_pm_opp_get_voltage() to aid in detecting RCU misuses. These are called often after dev_pm_opp_find_freq_ceil/exact() which already asserts for RCU lock. However one could make an error by releasing lock too early - just after dev_pm_opp_find_freq_ceil(). Signed-off-by: Krzysztof Kozlowski Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 1d20e09..15bf299 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -169,6 +169,8 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp) struct dev_pm_opp *tmp_opp; unsigned long v = 0; + opp_rcu_lockdep_assert(); + tmp_opp = rcu_dereference(opp); if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available) pr_err("%s: Invalid parameters\n", __func__); @@ -199,6 +201,8 @@ unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp) struct dev_pm_opp *tmp_opp; unsigned long f = 0; + opp_rcu_lockdep_assert(); + tmp_opp = rcu_dereference(opp); if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available) pr_err("%s: Invalid parameters\n", __func__); -- cgit v0.10.2 From e673f1639bc565ce3509ed36bc3987c2af407cd2 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 2 Jan 2015 12:34:22 +0530 Subject: cpufreq: remove dangling comment It doesn't make any sense at all and is a leftover of some earlier commit. Remove it. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index dad72359..a95cdc5 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2007,10 +2007,6 @@ int cpufreq_driver_target(struct cpufreq_policy *policy, } EXPORT_SYMBOL_GPL(cpufreq_driver_target); -/* - * when "event" is CPUFREQ_GOV_LIMITS - */ - static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event) { -- cgit v0.10.2 From f13f1184a1f4e046306c33e542b4d654866e5d70 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 2 Jan 2015 12:34:23 +0530 Subject: cpufreq: remove extra parenthesis We can live without it and so we should. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a95cdc5..a180bb4 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -903,7 +903,7 @@ static int cpufreq_add_dev_interface(struct cpufreq_policy *policy, /* set up files for this cpu device */ drv_attr = cpufreq_driver->attr; - while ((drv_attr) && (*drv_attr)) { + while (drv_attr && *drv_attr) { ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); if (ret) return ret; -- cgit v0.10.2 From 09347b2905169b361e8ff5d75308982165d61c13 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 2 Jan 2015 12:34:24 +0530 Subject: cpufreq: don't need line break in show_scaling_cur_freq() No need of an unnecessary line break. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a180bb4..4c70f7a 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -514,8 +514,7 @@ show_one(cpuinfo_transition_latency, cpuinfo.transition_latency); show_one(scaling_min_freq, min); show_one(scaling_max_freq, max); -static ssize_t show_scaling_cur_freq( - struct cpufreq_policy *policy, char *buf) +static ssize_t show_scaling_cur_freq(struct cpufreq_policy *policy, char *buf) { ssize_t ret; -- cgit v0.10.2 From db5f299574267c50067b967f898633d4dec7ecc4 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 2 Jan 2015 12:34:25 +0530 Subject: cpufreq: merge 'if' blocks in __cpufreq_remove_dev_prepare() There are two 'if' blocks here, checking for !cpufreq_driver->setpolicy and has_target(). Both are actually doing the same thing, merge them. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 4c70f7a..626ef84 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1371,11 +1371,10 @@ static int __cpufreq_remove_dev_prepare(struct device *dev, pr_err("%s: Failed to stop governor\n", __func__); return ret; } - } - if (!cpufreq_driver->setpolicy) strncpy(per_cpu(cpufreq_cpu_governor, cpu), policy->governor->name, CPUFREQ_NAME_LEN); + } down_read(&policy->rwsem); cpus = cpumask_weight(policy->cpus); -- cgit v0.10.2 From 42f91fa1166f1d6c9fba37f167dd3c3f846be00a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 2 Jan 2015 12:34:26 +0530 Subject: cpufreq: s/__find_governor/find_governor Remove unnecessary from find_governor's name. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 626ef84..faffdaa 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -433,7 +433,7 @@ static ssize_t store_boost(struct kobject *kobj, struct attribute *attr, } define_one_global_rw(boost); -static struct cpufreq_governor *__find_governor(const char *str_governor) +static struct cpufreq_governor *find_governor(const char *str_governor) { struct cpufreq_governor *t; @@ -469,7 +469,7 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, mutex_lock(&cpufreq_governor_mutex); - t = __find_governor(str_governor); + t = find_governor(str_governor); if (t == NULL) { int ret; @@ -479,7 +479,7 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, mutex_lock(&cpufreq_governor_mutex); if (ret == 0) - t = __find_governor(str_governor); + t = find_governor(str_governor); } if (t != NULL) { @@ -936,7 +936,7 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy) memcpy(&new_policy, policy, sizeof(*policy)); /* Update governor of new_policy to the governor used before hotplug */ - gov = __find_governor(per_cpu(cpufreq_cpu_governor, policy->cpu)); + gov = find_governor(per_cpu(cpufreq_cpu_governor, policy->cpu)); if (gov) pr_debug("Restoring governor %s for cpu %d\n", policy->governor->name, policy->cpu); @@ -2102,7 +2102,7 @@ int cpufreq_register_governor(struct cpufreq_governor *governor) governor->initialized = 0; err = -EBUSY; - if (__find_governor(governor->name) == NULL) { + if (!find_governor(governor->name)) { err = 0; list_add(&governor->governor_list, &cpufreq_governor_list); } -- cgit v0.10.2 From 2e1cc3a5d7efa42d3aa4aaa77b9b2c3a51bb6073 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 2 Jan 2015 12:34:27 +0530 Subject: cpufreq: No need to check for has_target() Either we can be setpolicy or target type, nothing else. And so the else part of setpolicy will automatically be of has_target() type. And so we don't need to check it again. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index faffdaa..1454ab3 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -464,7 +464,7 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, *policy = CPUFREQ_POLICY_POWERSAVE; err = 0; } - } else if (has_target()) { + } else { struct cpufreq_governor *t; mutex_lock(&cpufreq_governor_mutex); -- cgit v0.10.2 From a1e1dc41c4efb41e1e402a6b5a45b75687030664 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 2 Jan 2015 12:34:28 +0530 Subject: cpufreq: pass policy to cpufreq_out_of_sync There is no point finding out the 'policy' again within cpufreq_out_of_sync() when all the callers already have it. Just make them pass policy instead. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 1454ab3..0a9e764 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1509,30 +1509,23 @@ static void handle_update(struct work_struct *work) /** * cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're * in deep trouble. - * @cpu: cpu number - * @old_freq: CPU frequency the kernel thinks the CPU runs at + * @policy: policy managing CPUs * @new_freq: CPU frequency the CPU actually runs at * * We adjust to current frequency first, and need to clean up later. * So either call to cpufreq_update_policy() or schedule handle_update()). */ -static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, +static void cpufreq_out_of_sync(struct cpufreq_policy *policy, unsigned int new_freq) { - struct cpufreq_policy *policy; struct cpufreq_freqs freqs; - unsigned long flags; pr_debug("Warning: CPU frequency out of sync: cpufreq and timing core thinks of %u, is %u kHz\n", - old_freq, new_freq); + policy->cur, new_freq); - freqs.old = old_freq; + freqs.old = policy->cur; freqs.new = new_freq; - read_lock_irqsave(&cpufreq_driver_lock, flags); - policy = per_cpu(cpufreq_cpu_data, cpu); - read_unlock_irqrestore(&cpufreq_driver_lock, flags); - cpufreq_freq_transition_begin(policy, &freqs); cpufreq_freq_transition_end(policy, &freqs, 0); } @@ -1597,7 +1590,7 @@ static unsigned int __cpufreq_get(unsigned int cpu) /* verify no discrepancy between actual and saved value exists */ if (unlikely(ret_freq != policy->cur)) { - cpufreq_out_of_sync(cpu, policy->cur, ret_freq); + cpufreq_out_of_sync(policy, ret_freq); schedule_work(&policy->update); } } @@ -2302,8 +2295,7 @@ int cpufreq_update_policy(unsigned int cpu) policy->cur = new_policy.cur; } else { if (policy->cur != new_policy.cur && has_target()) - cpufreq_out_of_sync(cpu, policy->cur, - new_policy.cur); + cpufreq_out_of_sync(policy, new_policy.cur); } } -- cgit v0.10.2 From d92d50a4622b55cf114033309286696b3bd0fa5b Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 2 Jan 2015 12:34:29 +0530 Subject: cpufreq: pass policy to __cpufreq_get() There is no point finding out the 'policy' again within __cpufreq_get() when all the callers already have it. Just make them pass policy instead. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 0a9e764..420f270 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -63,7 +63,7 @@ static DECLARE_RWSEM(cpufreq_rwsem); /* internal prototypes */ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event); -static unsigned int __cpufreq_get(unsigned int cpu); +static unsigned int __cpufreq_get(struct cpufreq_policy *policy); static void handle_update(struct work_struct *work); /** @@ -563,7 +563,7 @@ store_one(scaling_max_freq, max); static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy, char *buf) { - unsigned int cur_freq = __cpufreq_get(policy->cpu); + unsigned int cur_freq = __cpufreq_get(policy); if (!cur_freq) return sprintf(buf, ""); return sprintf(buf, "%u\n", cur_freq); @@ -1575,15 +1575,14 @@ unsigned int cpufreq_quick_get_max(unsigned int cpu) } EXPORT_SYMBOL(cpufreq_quick_get_max); -static unsigned int __cpufreq_get(unsigned int cpu) +static unsigned int __cpufreq_get(struct cpufreq_policy *policy) { - struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); unsigned int ret_freq = 0; if (!cpufreq_driver->get) return ret_freq; - ret_freq = cpufreq_driver->get(cpu); + ret_freq = cpufreq_driver->get(policy->cpu); if (ret_freq && policy->cur && !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { @@ -1611,7 +1610,7 @@ unsigned int cpufreq_get(unsigned int cpu) if (policy) { down_read(&policy->rwsem); - ret_freq = __cpufreq_get(cpu); + ret_freq = __cpufreq_get(policy); up_read(&policy->rwsem); cpufreq_cpu_put(policy); -- cgit v0.10.2 From bc68b7dfda54373fb5d0cee8c44a070d590b8433 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 2 Jan 2015 12:34:30 +0530 Subject: cpufreq: update driver_data->flags only if we are registering driver We should first check if a cpufreq driver is already registered or not before updating driver_data->flags. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 420f270..0247da2 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2440,9 +2440,6 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) pr_debug("trying to register driver %s\n", driver_data->name); - if (driver_data->setpolicy) - driver_data->flags |= CPUFREQ_CONST_LOOPS; - write_lock_irqsave(&cpufreq_driver_lock, flags); if (cpufreq_driver) { write_unlock_irqrestore(&cpufreq_driver_lock, flags); @@ -2451,6 +2448,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) cpufreq_driver = driver_data; write_unlock_irqrestore(&cpufreq_driver_lock, flags); + if (driver_data->setpolicy) + driver_data->flags |= CPUFREQ_CONST_LOOPS; + if (cpufreq_boost_supported()) { /* * Check if driver provides function to enable boost - -- cgit v0.10.2 From 22a7cfb01415cfa4284af20555942c427af452e0 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 2 Jan 2015 12:34:31 +0530 Subject: cpufreq: get rid of CONFIG_{HOTPLUG_CPU|SMP} mess These are messing up more than the benefit they provide. It isn't a lot of code anyway, that we will compile without them. Kill them. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 0247da2..1e72621 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -958,7 +958,6 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy) } } -#ifdef CONFIG_HOTPLUG_CPU static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu, struct device *dev) { @@ -996,7 +995,6 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, return sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); } -#endif static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu) { @@ -1107,19 +1105,15 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) { unsigned int j, cpu = dev->id; int ret = -ENOMEM; - struct cpufreq_policy *policy; + struct cpufreq_policy *policy, *tpolicy; unsigned long flags; bool recover_policy = cpufreq_suspended; -#ifdef CONFIG_HOTPLUG_CPU - struct cpufreq_policy *tpolicy; -#endif if (cpu_is_offline(cpu)) return 0; pr_debug("adding CPU %u\n", cpu); -#ifdef CONFIG_SMP /* check whether a different CPU already registered this * CPU because it is in the same boat. */ policy = cpufreq_cpu_get(cpu); @@ -1127,12 +1121,10 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) cpufreq_cpu_put(policy); return 0; } -#endif if (!down_read_trylock(&cpufreq_rwsem)) return 0; -#ifdef CONFIG_HOTPLUG_CPU /* Check if this cpu was hot-unplugged earlier and has siblings */ read_lock_irqsave(&cpufreq_driver_lock, flags); list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) { @@ -1144,7 +1136,6 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) } } read_unlock_irqrestore(&cpufreq_driver_lock, flags); -#endif /* * Restore the saved policy when doing light-weight init and fall back -- cgit v0.10.2 From 7f0c020ab6ecb513394de9b02df33a5cfc62084f Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 2 Jan 2015 12:34:32 +0530 Subject: cpufreq: get rid of 'tpolicy' from __cpufreq_add_dev() There is no need of this separate variable, use 'policy' instead. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 1e72621..127cc6f 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1105,7 +1105,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) { unsigned int j, cpu = dev->id; int ret = -ENOMEM; - struct cpufreq_policy *policy, *tpolicy; + struct cpufreq_policy *policy; unsigned long flags; bool recover_policy = cpufreq_suspended; @@ -1127,10 +1127,10 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) /* Check if this cpu was hot-unplugged earlier and has siblings */ read_lock_irqsave(&cpufreq_driver_lock, flags); - list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) { - if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) { + list_for_each_entry(policy, &cpufreq_policy_list, policy_list) { + if (cpumask_test_cpu(cpu, policy->related_cpus)) { read_unlock_irqrestore(&cpufreq_driver_lock, flags); - ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev); + ret = cpufreq_add_policy_cpu(policy, cpu, dev); up_read(&cpufreq_rwsem); return ret; } -- cgit v0.10.2 From d7a9771c1a37af8d0cd0cf97723aeea88b9de8bb Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 2 Jan 2015 12:34:33 +0530 Subject: cpufreq: use light-weight cpufreq_cpu_get_raw() in __cpufreq_add_dev() We just need to check if a 'policy' is already present for the cpu we are adding. We don't need to take all the locks and do kobject usage updates. Use the light-weight cpufreq_cpu_get_raw() routine instead. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 127cc6f..3a41513 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1116,11 +1116,9 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) /* check whether a different CPU already registered this * CPU because it is in the same boat. */ - policy = cpufreq_cpu_get(cpu); - if (unlikely(policy)) { - cpufreq_cpu_put(policy); + policy = cpufreq_cpu_get_raw(cpu); + if (unlikely(policy)) return 0; - } if (!down_read_trylock(&cpufreq_rwsem)) return 0; -- cgit v0.10.2 From 39c132eebdd26a3041a92fc64fc1e61293eb39da Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 2 Jan 2015 12:34:34 +0530 Subject: cpufreq: limit the scope of l_p_j variables These variables are just used within adjust_jiffies() and so must be local to it. Also there is no need of a dummy routine for CONFIG_SMP case as we can take care of all that with help of macros in the same routine. It doesn't look that ugly. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 3a41513..96abdcd 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -250,12 +250,12 @@ EXPORT_SYMBOL_GPL(cpufreq_cpu_put); * systems as each CPU might be scaled differently. So, use the arch * per-CPU loops_per_jiffy value wherever possible. */ -#ifndef CONFIG_SMP -static unsigned long l_p_j_ref; -static unsigned int l_p_j_ref_freq; - static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { +#ifndef CONFIG_SMP + static unsigned long l_p_j_ref; + static unsigned int l_p_j_ref_freq; + if (ci->flags & CPUFREQ_CONST_LOOPS) return; @@ -271,13 +271,8 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) pr_debug("scaling loops_per_jiffy to %lu for frequency %u kHz\n", loops_per_jiffy, ci->new); } -} -#else -static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) -{ - return; -} #endif +} static void __cpufreq_notify_transition(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs, unsigned int state) -- cgit v0.10.2 From ce1bcfe94db895cbd6876e176af5824742b29e25 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 2 Jan 2015 12:34:35 +0530 Subject: cpufreq: check cpufreq_policy_list instead of scanning policies for all CPUs CPUFREQ_STICKY flag is set by drivers which don't want to get unregistered even if cpufreq-core isn't able to initialize policy for any CPU. When this flag isn't set, we try to unregister the driver. To find out which CPUs are registered and which are not, we try to check per_cpu cpufreq_cpu_data for all CPUs. Because we have a list of valid policies available now, we better check if the list is empty or not instead of the 'for' loop. That will be much more efficient. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 96abdcd..09f333f 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2455,23 +2455,12 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) if (ret) goto err_boost_unreg; - if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) { - int i; - ret = -ENODEV; - - /* check for at least one working CPU */ - for (i = 0; i < nr_cpu_ids; i++) - if (cpu_possible(i) && per_cpu(cpufreq_cpu_data, i)) { - ret = 0; - break; - } - + if (!(cpufreq_driver->flags & CPUFREQ_STICKY) && + list_empty(&cpufreq_policy_list)) { /* if all ->init() calls failed, unregister */ - if (ret) { - pr_debug("no CPU initialized for driver %s\n", - driver_data->name); - goto err_if_unreg; - } + pr_debug("%s: No CPU initialized for driver %s\n", __func__, + driver_data->name); + goto err_if_unreg; } register_hotcpu_notifier(&cpufreq_cpu_notifier); -- cgit v0.10.2 From 818c57126e101abf87741131298354258396480c Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 2 Jan 2015 12:34:38 +0530 Subject: cpufreq: move some initialization stuff to cpufreq_policy_alloc() We need to initialize completion and work only on policy allocation and not really on the policy restore side and so we better move this piece of code to cpufreq_policy_alloc(). Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 09f333f..70b568a 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1026,6 +1026,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(void) init_rwsem(&policy->rwsem); spin_lock_init(&policy->transition_lock); init_waitqueue_head(&policy->transition_wait); + init_completion(&policy->kobj_unregister); + INIT_WORK(&policy->update, handle_update); return policy; @@ -1155,9 +1157,6 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) cpumask_copy(policy->cpus, cpumask_of(cpu)); - init_completion(&policy->kobj_unregister); - INIT_WORK(&policy->update, handle_update); - /* call driver. From then on the cpufreq must be able * to accept all calls to ->verify and ->setpolicy for this CPU */ -- cgit v0.10.2 From 00d0b29472d1605851c12c77aaa3664413a71fbf Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Jan 2015 21:09:00 +0530 Subject: cpufreq: stats: Improve module description string The MODULE_DESCRIPTION() string is just too long and then is broken into multiple lines just to make checkpatch happy. Rewrite it to make it more precise. Reviewed-by: Prarit Bhargava Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 0cd9b4d..80801f8 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -374,8 +374,7 @@ static void __exit cpufreq_stats_exit(void) } MODULE_AUTHOR("Zou Nan hai "); -MODULE_DESCRIPTION("'cpufreq_stats' - A driver to export cpufreq stats " - "through sysfs filesystem"); +MODULE_DESCRIPTION("Export cpufreq stats via sysfs"); MODULE_LICENSE("GPL"); module_init(cpufreq_stats_init); -- cgit v0.10.2 From b8c674482f3cd0d93d07dbc2518cc96c3cc24ed0 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Jan 2015 21:09:01 +0530 Subject: cpufreq: stats: return -EEXIST when stats are already allocated __cpufreq_stats_create_table() is called from: - cpufreq notifier on creation of a new policy. Stats will always be NULL here. - cpufreq_stats_init() for all CPUs as cpufreq-stats might have been initialized after cpufreq driver. For any policy, 'stats' will be NULL for the first CPU only and will be valid for all other CPUs managed by the same policy. While we return for other CPUs, we don't return the right error value. It's not that we would fail with -EBUSY. But generally, this is what these return values mean: - EBUSY: we are busy right now, try again. And the retry attempt might be immediate. - EEXIST: We already have what you are trying to create and there is no need to create it again, and so no more tries are required. Reviewed-by: Prarit Bhargava Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 80801f8..d2299ca 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -192,8 +192,10 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) if (unlikely(!table)) return 0; + /* stats already initialized */ if (per_cpu(cpufreq_stats_table, cpu)) - return -EBUSY; + return -EEXIST; + stat = kzalloc(sizeof(*stat), GFP_KERNEL); if ((stat) == NULL) return -ENOMEM; -- cgit v0.10.2 From 43b9cdaf5c22230269b8edd99ec78380a6ac0715 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Jan 2015 21:09:02 +0530 Subject: cpufreq: stats: remove unused cpufreq_stats_attribute It was never used, but is there since the first commit. Remove it. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index d2299ca..14f8d85 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -33,11 +33,6 @@ struct cpufreq_stats { static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table); -struct cpufreq_stats_attribute { - struct attribute attr; - ssize_t(*show) (struct cpufreq_stats *, char *); -}; - static int cpufreq_stats_update(unsigned int cpu) { struct cpufreq_stats *stat; -- cgit v0.10.2 From 9531347c61f689ac6de899a03ce91be4157277f7 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Jan 2015 21:09:03 +0530 Subject: cpufreq: stats: initialize 'cur_time' on its definition 'cur_time' is defined in the first line and is then assigned a value in the next line. Initialize it while defining it. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 14f8d85..21bec77 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -36,9 +36,8 @@ static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table); static int cpufreq_stats_update(unsigned int cpu) { struct cpufreq_stats *stat; - unsigned long long cur_time; + unsigned long long cur_time = get_jiffies_64(); - cur_time = get_jiffies_64(); spin_lock(&cpufreq_stats_lock); stat = per_cpu(cpufreq_stats_table, cpu); if (stat->time_in_state) -- cgit v0.10.2 From f93dbbbd108936b18b3230af36d9a36866ce69a7 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Jan 2015 21:09:04 +0530 Subject: cpufreq: stats: don't check for freq table while freeing stats While we allocate stats, we do need to check if freq-table is present or not as we need to use it then. But while freeing stats, all we need to know is if stats holds a valid pointer value. There is no use of testing if cpufreq table is present or not. Don't check it. Reviewed-by: Prarit Bhargava Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 21bec77..e9d6842 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -168,8 +168,7 @@ static void cpufreq_stats_free_table(unsigned int cpu) if (!policy) return; - if (cpufreq_frequency_get_table(policy->cpu)) - __cpufreq_stats_free_table(policy); + __cpufreq_stats_free_table(policy); cpufreq_cpu_put(policy); } -- cgit v0.10.2 From 2aba0c1bae564a59fc38c407abf7985f9e347cc4 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Jan 2015 21:09:05 +0530 Subject: cpufreq: stats: pass 'stat' to cpufreq_stats_update() It is better to pass a struct cpufreq_stats pointer to cpufreq_stats_update() instead of a CPU number, because that's all it needs. Even if we pass a cpu number to cpufreq_stats_update(), it reads the per-cpu variable to get 'stats' out of it. So we are doing these operations unnecessarily: - First getting the cpu number to pass to cpufreq_stats_update(), stat->cpu. - And then getting stats from the cpu, per_cpu(cpufreq_stats_table, cpu). Reviewed-by: Prarit Bhargava Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index e9d6842..6c234f5 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -33,13 +33,11 @@ struct cpufreq_stats { static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table); -static int cpufreq_stats_update(unsigned int cpu) +static int cpufreq_stats_update(struct cpufreq_stats *stat) { - struct cpufreq_stats *stat; unsigned long long cur_time = get_jiffies_64(); spin_lock(&cpufreq_stats_lock); - stat = per_cpu(cpufreq_stats_table, cpu); if (stat->time_in_state) stat->time_in_state[stat->last_index] += cur_time - stat->last_time; @@ -64,7 +62,7 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); if (!stat) return 0; - cpufreq_stats_update(stat->cpu); + cpufreq_stats_update(stat); for (i = 0; i < stat->state_num; i++) { len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i], (unsigned long long) @@ -82,7 +80,7 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); if (!stat) return 0; - cpufreq_stats_update(stat->cpu); + cpufreq_stats_update(stat); len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); len += snprintf(buf + len, PAGE_SIZE - len, " : "); for (i = 0; i < stat->state_num; i++) { @@ -307,7 +305,7 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb, if (old_index == -1 || new_index == -1) return 0; - cpufreq_stats_update(freq->cpu); + cpufreq_stats_update(stat); if (old_index == new_index) return 0; -- cgit v0.10.2 From a9aaf2915ee265735c28b764551d084e61a694e0 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 13 Jan 2015 11:34:00 +0530 Subject: cpufreq: stats: get rid of per-cpu cpufreq_stats_table All CPUs sharing a cpufreq policy share stats too. For this reason, add a stats pointer to struct cpufreq_policy and drop per-CPU variable cpufreq_stats_table used for accessing cpufreq stats so as to reduce code complexity. Reviewed-by: Prarit Bhargava Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 6c234f5..3792b2e 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -31,8 +31,6 @@ struct cpufreq_stats { #endif }; -static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table); - static int cpufreq_stats_update(struct cpufreq_stats *stat) { unsigned long long cur_time = get_jiffies_64(); @@ -48,20 +46,15 @@ static int cpufreq_stats_update(struct cpufreq_stats *stat) static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf) { - struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); - if (!stat) - return 0; - return sprintf(buf, "%d\n", - per_cpu(cpufreq_stats_table, stat->cpu)->total_trans); + return sprintf(buf, "%d\n", policy->stats->total_trans); } static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) { + struct cpufreq_stats *stat = policy->stats; ssize_t len = 0; int i; - struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); - if (!stat) - return 0; + cpufreq_stats_update(stat); for (i = 0; i < stat->state_num; i++) { len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i], @@ -74,12 +67,10 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) #ifdef CONFIG_CPU_FREQ_STAT_DETAILS static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) { + struct cpufreq_stats *stat = policy->stats; ssize_t len = 0; int i, j; - struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); - if (!stat) - return 0; cpufreq_stats_update(stat); len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); len += snprintf(buf + len, PAGE_SIZE - len, " : "); @@ -145,8 +136,9 @@ static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) static void __cpufreq_stats_free_table(struct cpufreq_policy *policy) { - struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); + struct cpufreq_stats *stat = policy->stats; + /* Already freed */ if (!stat) return; @@ -155,7 +147,7 @@ static void __cpufreq_stats_free_table(struct cpufreq_policy *policy) sysfs_remove_group(&policy->kobj, &stats_attr_group); kfree(stat->time_in_state); kfree(stat); - per_cpu(cpufreq_stats_table, policy->cpu) = NULL; + policy->stats = NULL; } static void cpufreq_stats_free_table(unsigned int cpu) @@ -184,7 +176,7 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) return 0; /* stats already initialized */ - if (per_cpu(cpufreq_stats_table, cpu)) + if (policy->stats) return -EEXIST; stat = kzalloc(sizeof(*stat), GFP_KERNEL); @@ -196,7 +188,7 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) goto error_out; stat->cpu = cpu; - per_cpu(cpufreq_stats_table, cpu) = stat; + policy->stats = stat; cpufreq_for_each_valid_entry(pos, table) count++; @@ -231,7 +223,7 @@ error_alloc: sysfs_remove_group(&policy->kobj, &stats_attr_group); error_out: kfree(stat); - per_cpu(cpufreq_stats_table, cpu) = NULL; + policy->stats = NULL; return ret; } @@ -254,15 +246,7 @@ static void cpufreq_stats_create_table(unsigned int cpu) static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy) { - struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, - policy->last_cpu); - - pr_debug("Updating stats_table for new_cpu %u from last_cpu %u\n", - policy->cpu, policy->last_cpu); - per_cpu(cpufreq_stats_table, policy->cpu) = per_cpu(cpufreq_stats_table, - policy->last_cpu); - per_cpu(cpufreq_stats_table, policy->last_cpu) = NULL; - stat->cpu = policy->cpu; + policy->stats->cpu = policy->cpu; } static int cpufreq_stat_notifier_policy(struct notifier_block *nb, @@ -288,27 +272,36 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb, unsigned long val, void *data) { struct cpufreq_freqs *freq = data; + struct cpufreq_policy *policy = cpufreq_cpu_get(freq->cpu); struct cpufreq_stats *stat; int old_index, new_index; - if (val != CPUFREQ_POSTCHANGE) + if (!policy) { + pr_err("%s: No policy found\n", __func__); return 0; + } - stat = per_cpu(cpufreq_stats_table, freq->cpu); - if (!stat) - return 0; + if (val != CPUFREQ_POSTCHANGE) + goto put_policy; + + if (!policy->stats) { + pr_debug("%s: No stats found\n", __func__); + goto put_policy; + } + + stat = policy->stats; old_index = stat->last_index; new_index = freq_table_get_index(stat, freq->new); /* We can't do stat->time_in_state[-1]= .. */ if (old_index == -1 || new_index == -1) - return 0; + goto put_policy; cpufreq_stats_update(stat); if (old_index == new_index) - return 0; + goto put_policy; spin_lock(&cpufreq_stats_lock); stat->last_index = new_index; @@ -317,6 +310,9 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb, #endif stat->total_trans++; spin_unlock(&cpufreq_stats_lock); + +put_policy: + cpufreq_cpu_put(policy); return 0; } diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 4d078ce..60b7b49 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -113,6 +113,9 @@ struct cpufreq_policy { wait_queue_head_t transition_wait; struct task_struct *transition_task; /* Task which is doing the transition */ + /* cpufreq-stats */ + struct cpufreq_stats *stats; + /* For cpufreq driver's internal use */ void *driver_data; }; -- cgit v0.10.2 From 5094160786ede5c08a6901648787a5bf9b0dc2e1 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Jan 2015 21:09:07 +0530 Subject: cpufreq: stats: rename 'struct cpufreq_stats' objects as 'stats' Currently we name objects of 'struct cpufreq_stats' as 'stat' and 'stats'. Use 'stats' to make it consistent. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 3792b2e..cdc5233 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -31,15 +31,15 @@ struct cpufreq_stats { #endif }; -static int cpufreq_stats_update(struct cpufreq_stats *stat) +static int cpufreq_stats_update(struct cpufreq_stats *stats) { unsigned long long cur_time = get_jiffies_64(); spin_lock(&cpufreq_stats_lock); - if (stat->time_in_state) - stat->time_in_state[stat->last_index] += - cur_time - stat->last_time; - stat->last_time = cur_time; + if (stats->time_in_state) + stats->time_in_state[stats->last_index] += + cur_time - stats->last_time; + stats->last_time = cur_time; spin_unlock(&cpufreq_stats_lock); return 0; } @@ -51,15 +51,15 @@ static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf) static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) { - struct cpufreq_stats *stat = policy->stats; + struct cpufreq_stats *stats = policy->stats; ssize_t len = 0; int i; - cpufreq_stats_update(stat); - for (i = 0; i < stat->state_num; i++) { - len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i], + cpufreq_stats_update(stats); + for (i = 0; i < stats->state_num; i++) { + len += sprintf(buf + len, "%u %llu\n", stats->freq_table[i], (unsigned long long) - jiffies_64_to_clock_t(stat->time_in_state[i])); + jiffies_64_to_clock_t(stats->time_in_state[i])); } return len; } @@ -67,36 +67,36 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) #ifdef CONFIG_CPU_FREQ_STAT_DETAILS static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) { - struct cpufreq_stats *stat = policy->stats; + struct cpufreq_stats *stats = policy->stats; ssize_t len = 0; int i, j; - cpufreq_stats_update(stat); + cpufreq_stats_update(stats); len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); len += snprintf(buf + len, PAGE_SIZE - len, " : "); - for (i = 0; i < stat->state_num; i++) { + for (i = 0; i < stats->state_num; i++) { if (len >= PAGE_SIZE) break; len += snprintf(buf + len, PAGE_SIZE - len, "%9u ", - stat->freq_table[i]); + stats->freq_table[i]); } if (len >= PAGE_SIZE) return PAGE_SIZE; len += snprintf(buf + len, PAGE_SIZE - len, "\n"); - for (i = 0; i < stat->state_num; i++) { + for (i = 0; i < stats->state_num; i++) { if (len >= PAGE_SIZE) break; len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ", - stat->freq_table[i]); + stats->freq_table[i]); - for (j = 0; j < stat->state_num; j++) { + for (j = 0; j < stats->state_num; j++) { if (len >= PAGE_SIZE) break; len += snprintf(buf + len, PAGE_SIZE - len, "%9u ", - stat->trans_table[i*stat->max_state+j]); + stats->trans_table[i*stats->max_state+j]); } if (len >= PAGE_SIZE) break; @@ -125,28 +125,28 @@ static struct attribute_group stats_attr_group = { .name = "stats" }; -static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) +static int freq_table_get_index(struct cpufreq_stats *stats, unsigned int freq) { int index; - for (index = 0; index < stat->max_state; index++) - if (stat->freq_table[index] == freq) + for (index = 0; index < stats->max_state; index++) + if (stats->freq_table[index] == freq) return index; return -1; } static void __cpufreq_stats_free_table(struct cpufreq_policy *policy) { - struct cpufreq_stats *stat = policy->stats; + struct cpufreq_stats *stats = policy->stats; /* Already freed */ - if (!stat) + if (!stats) return; - pr_debug("%s: Free stat table\n", __func__); + pr_debug("%s: Free stats table\n", __func__); sysfs_remove_group(&policy->kobj, &stats_attr_group); - kfree(stat->time_in_state); - kfree(stat); + kfree(stats->time_in_state); + kfree(stats); policy->stats = NULL; } @@ -166,7 +166,7 @@ static void cpufreq_stats_free_table(unsigned int cpu) static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) { unsigned int i, count = 0, ret = 0; - struct cpufreq_stats *stat; + struct cpufreq_stats *stats; unsigned int alloc_size; unsigned int cpu = policy->cpu; struct cpufreq_frequency_table *pos, *table; @@ -179,16 +179,16 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) if (policy->stats) return -EEXIST; - stat = kzalloc(sizeof(*stat), GFP_KERNEL); - if ((stat) == NULL) + stats = kzalloc(sizeof(*stats), GFP_KERNEL); + if ((stats) == NULL) return -ENOMEM; ret = sysfs_create_group(&policy->kobj, &stats_attr_group); if (ret) goto error_out; - stat->cpu = cpu; - policy->stats = stat; + stats->cpu = cpu; + policy->stats = stats; cpufreq_for_each_valid_entry(pos, table) count++; @@ -198,31 +198,31 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) #ifdef CONFIG_CPU_FREQ_STAT_DETAILS alloc_size += count * count * sizeof(int); #endif - stat->max_state = count; - stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL); - if (!stat->time_in_state) { + stats->max_state = count; + stats->time_in_state = kzalloc(alloc_size, GFP_KERNEL); + if (!stats->time_in_state) { ret = -ENOMEM; goto error_alloc; } - stat->freq_table = (unsigned int *)(stat->time_in_state + count); + stats->freq_table = (unsigned int *)(stats->time_in_state + count); #ifdef CONFIG_CPU_FREQ_STAT_DETAILS - stat->trans_table = stat->freq_table + count; + stats->trans_table = stats->freq_table + count; #endif i = 0; cpufreq_for_each_valid_entry(pos, table) - if (freq_table_get_index(stat, pos->frequency) == -1) - stat->freq_table[i++] = pos->frequency; - stat->state_num = i; + if (freq_table_get_index(stats, pos->frequency) == -1) + stats->freq_table[i++] = pos->frequency; + stats->state_num = i; spin_lock(&cpufreq_stats_lock); - stat->last_time = get_jiffies_64(); - stat->last_index = freq_table_get_index(stat, policy->cur); + stats->last_time = get_jiffies_64(); + stats->last_index = freq_table_get_index(stats, policy->cur); spin_unlock(&cpufreq_stats_lock); return 0; error_alloc: sysfs_remove_group(&policy->kobj, &stats_attr_group); error_out: - kfree(stat); + kfree(stats); policy->stats = NULL; return ret; } @@ -273,7 +273,7 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb, { struct cpufreq_freqs *freq = data; struct cpufreq_policy *policy = cpufreq_cpu_get(freq->cpu); - struct cpufreq_stats *stat; + struct cpufreq_stats *stats; int old_index, new_index; if (!policy) { @@ -289,26 +289,26 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb, goto put_policy; } - stat = policy->stats; + stats = policy->stats; - old_index = stat->last_index; - new_index = freq_table_get_index(stat, freq->new); + old_index = stats->last_index; + new_index = freq_table_get_index(stats, freq->new); - /* We can't do stat->time_in_state[-1]= .. */ + /* We can't do stats->time_in_state[-1]= .. */ if (old_index == -1 || new_index == -1) goto put_policy; - cpufreq_stats_update(stat); + cpufreq_stats_update(stats); if (old_index == new_index) goto put_policy; spin_lock(&cpufreq_stats_lock); - stat->last_index = new_index; + stats->last_index = new_index; #ifdef CONFIG_CPU_FREQ_STAT_DETAILS - stat->trans_table[old_index * stat->max_state + new_index]++; + stats->trans_table[old_index * stats->max_state + new_index]++; #endif - stat->total_trans++; + stats->total_trans++; spin_unlock(&cpufreq_stats_lock); put_policy: -- cgit v0.10.2 From 7c418ff099110d987846c8c670479a3b90ed1dcb Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Jan 2015 21:09:08 +0530 Subject: cpufreq: Remove (now) unused 'last_cpu' from struct cpufreq_policy 'last_cpu' was used only from cpufreq-stats and isn't used anymore. Get rid of it. Reviewed-by: Prarit Bhargava Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 70b568a..60ef37d 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1086,10 +1086,7 @@ static int update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu, } down_write(&policy->rwsem); - - policy->last_cpu = policy->cpu; policy->cpu = cpu; - up_write(&policy->rwsem); blocking_notifier_call_chain(&cpufreq_policy_notifier_list, diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 60b7b49..7e1a389 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -66,8 +66,6 @@ struct cpufreq_policy { unsigned int shared_type; /* ACPI: ANY or ALL affected CPUs should set cpufreq */ unsigned int cpu; /* cpu nr of CPU managing this policy */ - unsigned int last_cpu; /* cpu nr of previous CPU that managed - * this policy */ struct clk *clk; struct cpufreq_cpuinfo cpuinfo;/* see above */ -- cgit v0.10.2 From c92f2125ac5338151bb5c45e371c701e107e3197 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Jan 2015 21:09:09 +0530 Subject: cpufreq: stats: drop 'cpu' field of struct cpufreq_stats 'cpu' field of struct cpufreq_stats isn't used anymore and so can be dropped. This change makes cpufreq_stats_update_policy_cpu() empty and so that is removed as well. Reviewed-by: Prarit Bhargava Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index cdc5233..e1fe0a9 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -18,7 +18,6 @@ static spinlock_t cpufreq_stats_lock; struct cpufreq_stats { - unsigned int cpu; unsigned int total_trans; unsigned long long last_time; unsigned int max_state; @@ -187,7 +186,6 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) if (ret) goto error_out; - stats->cpu = cpu; policy->stats = stats; cpufreq_for_each_valid_entry(pos, table) @@ -244,22 +242,12 @@ static void cpufreq_stats_create_table(unsigned int cpu) cpufreq_cpu_put(policy); } -static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy) -{ - policy->stats->cpu = policy->cpu; -} - static int cpufreq_stat_notifier_policy(struct notifier_block *nb, unsigned long val, void *data) { int ret = 0; struct cpufreq_policy *policy = data; - if (val == CPUFREQ_UPDATE_POLICY_CPU) { - cpufreq_stats_update_policy_cpu(policy); - return 0; - } - if (val == CPUFREQ_CREATE_POLICY) ret = __cpufreq_stats_create_table(policy); else if (val == CPUFREQ_REMOVE_POLICY) -- cgit v0.10.2 From d9f354460db8b58a8395936d323b4ca6e8428b9d Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Jan 2015 21:09:10 +0530 Subject: cpufreq: remove CPUFREQ_UPDATE_POLICY_CPU notifications CPUFREQ_UPDATE_POLICY_CPU notifications were used only from cpufreq-stats which doesn't use it anymore. Remove them. This also decrements values of other notification macros defined after CPUFREQ_UPDATE_POLICY_CPU by 1 to remove gaps. Hopefully all users are using macro's instead of direct numbers and so they wouldn't break as macro values are changed now. Reviewed-by: Prarit Bhargava Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 60ef37d..ca69f42 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1089,9 +1089,6 @@ static int update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu, policy->cpu = cpu; up_write(&policy->rwsem); - blocking_notifier_call_chain(&cpufreq_policy_notifier_list, - CPUFREQ_UPDATE_POLICY_CPU, policy); - return 0; } diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 7e1a389..2ee4888 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -368,9 +368,8 @@ static inline void cpufreq_resume(void) {} #define CPUFREQ_INCOMPATIBLE (1) #define CPUFREQ_NOTIFY (2) #define CPUFREQ_START (3) -#define CPUFREQ_UPDATE_POLICY_CPU (4) -#define CPUFREQ_CREATE_POLICY (5) -#define CPUFREQ_REMOVE_POLICY (6) +#define CPUFREQ_CREATE_POLICY (4) +#define CPUFREQ_REMOVE_POLICY (5) #ifdef CONFIG_CPU_FREQ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list); -- cgit v0.10.2 From a685c6d023c77303ca8700f37bf06eb85ffbf06a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Jan 2015 21:09:11 +0530 Subject: cpufreq: stats: create sysfs group once we are ready Userspace is free to read value of any file from cpufreq/stats directory once they are created. __cpufreq_stats_create_table() is creating the sysfs files first and then allocating resources for them. Though it would be quite difficult to trigger the racy situation here, but for the sake of keeping sensible code lets create sysfs entries only after we are ready to go. This also does some makeup to the routine to make it look better. Reviewed-by: Prarit Bhargava Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index e1fe0a9..5d7bf9b 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -164,12 +164,13 @@ static void cpufreq_stats_free_table(unsigned int cpu) static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) { - unsigned int i, count = 0, ret = 0; + unsigned int i = 0, count = 0, ret = -ENOMEM; struct cpufreq_stats *stats; unsigned int alloc_size; unsigned int cpu = policy->cpu; struct cpufreq_frequency_table *pos, *table; + /* We need cpufreq table for creating stats table */ table = cpufreq_frequency_get_table(cpu); if (unlikely(!table)) return 0; @@ -179,15 +180,10 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) return -EEXIST; stats = kzalloc(sizeof(*stats), GFP_KERNEL); - if ((stats) == NULL) + if (!stats) return -ENOMEM; - ret = sysfs_create_group(&policy->kobj, &stats_attr_group); - if (ret) - goto error_out; - - policy->stats = stats; - + /* Find total allocation size */ cpufreq_for_each_valid_entry(pos, table) count++; @@ -196,32 +192,42 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) #ifdef CONFIG_CPU_FREQ_STAT_DETAILS alloc_size += count * count * sizeof(int); #endif - stats->max_state = count; + + /* Allocate memory for time_in_state/freq_table/trans_table in one go */ stats->time_in_state = kzalloc(alloc_size, GFP_KERNEL); - if (!stats->time_in_state) { - ret = -ENOMEM; - goto error_alloc; - } + if (!stats->time_in_state) + goto free_stat; + stats->freq_table = (unsigned int *)(stats->time_in_state + count); #ifdef CONFIG_CPU_FREQ_STAT_DETAILS stats->trans_table = stats->freq_table + count; #endif - i = 0; + + stats->max_state = count; + + /* Find valid-unique entries */ cpufreq_for_each_valid_entry(pos, table) if (freq_table_get_index(stats, pos->frequency) == -1) stats->freq_table[i++] = pos->frequency; stats->state_num = i; + spin_lock(&cpufreq_stats_lock); stats->last_time = get_jiffies_64(); stats->last_index = freq_table_get_index(stats, policy->cur); spin_unlock(&cpufreq_stats_lock); - return 0; -error_alloc: - sysfs_remove_group(&policy->kobj, &stats_attr_group); -error_out: - kfree(stats); + + policy->stats = stats; + ret = sysfs_create_group(&policy->kobj, &stats_attr_group); + if (!ret) + return 0; + + /* We failed, release resources */ policy->stats = NULL; + kfree(stats->time_in_state); +free_stat: + kfree(stats); + return ret; } -- cgit v0.10.2 From c960f9b22d63934401949fb20d10ec4e69b535b2 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Jan 2015 21:09:12 +0530 Subject: cpufreq: stats: time_in_state can't be NULL in cpufreq_stats_update() 'time_in_state' can't be NULL if 'stats' is valid. These are allocated together and only if time_in_state is allocated successfully, we update policy->stats. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 5d7bf9b..a9a6dc4 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -35,9 +35,7 @@ static int cpufreq_stats_update(struct cpufreq_stats *stats) unsigned long long cur_time = get_jiffies_64(); spin_lock(&cpufreq_stats_lock); - if (stats->time_in_state) - stats->time_in_state[stats->last_index] += - cur_time - stats->last_time; + stats->time_in_state[stats->last_index] += cur_time - stats->last_time; stats->last_time = cur_time; spin_unlock(&cpufreq_stats_lock); return 0; -- cgit v0.10.2 From 9225913d386537f84f0eb72f022a8b4b9e684846 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Jan 2015 21:09:13 +0530 Subject: cpufreq: stats: don't update stats from show_trans_table() cpufreq_stats_update() updates time_in_state and nothing else. It should ideally be updated only in two cases: - User requested for the current value of time_in_state. - We have switched states and so need to update time for the last state. Currently, we are also doing this while user asks for the transition table of frequencies. It wouldn't do any harm, but no good as well. Its useless here. Remove it. Reviewed-by: Prarit Bhargava Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index a9a6dc4..4cd2611 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -68,7 +68,6 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) ssize_t len = 0; int i, j; - cpufreq_stats_update(stats); len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); len += snprintf(buf + len, PAGE_SIZE - len, " : "); for (i = 0; i < stats->state_num; i++) { -- cgit v0.10.2 From e73476949c6d1e2edd04bbf7b5bae30afa370e33 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Jan 2015 21:09:14 +0530 Subject: cpufreq: stats: don't update stats on false notifiers We need to call cpufreq_stats_update() to update 'time_in_state' for the last frequency. This is achieved by calling it from cpufreq_stat_notifier_trans(), which is called after frequency transition. But if we detect that the cpu's frequency haven't really changed and its a false POSTCHANGE notification, we don't really need to update time_in_state. It wouldn't cause any harm in calling cpufreq_stats_update() but we can avoid calling it here and call it when the frequency really changes. The result will be the same but more efficient. Reviewed-by: Prarit Bhargava Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 4cd2611..c948086 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -289,11 +289,11 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb, if (old_index == -1 || new_index == -1) goto put_policy; - cpufreq_stats_update(stats); - if (old_index == new_index) goto put_policy; + cpufreq_stats_update(stats); + spin_lock(&cpufreq_stats_lock); stats->last_index = new_index; #ifdef CONFIG_CPU_FREQ_STAT_DETAILS -- cgit v0.10.2 From 490285c65e2398a533035dd9d75cb606a61ea39a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 6 Jan 2015 21:09:15 +0530 Subject: cpufreq: stats: drop unnecessary locking There is no possibility of any race on updating last_index, trans_table or total_trans as these are updated only by cpufreq_stat_notifier_trans() which will be called sequentially. The only place where locking is still relevant is: cpufreq_stats_update(), which updates time_in_state and last_time. This can be called by two thread in parallel, that may result in races. The two threads being: - sysfs read of time_in_state - and frequency transition that calls cpufreq_stat_notifier_trans(). Remove locking from the first case mentioned above. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index c948086..5e370a3 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -207,12 +207,10 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) cpufreq_for_each_valid_entry(pos, table) if (freq_table_get_index(stats, pos->frequency) == -1) stats->freq_table[i++] = pos->frequency; - stats->state_num = i; - spin_lock(&cpufreq_stats_lock); + stats->state_num = i; stats->last_time = get_jiffies_64(); stats->last_index = freq_table_get_index(stats, policy->cur); - spin_unlock(&cpufreq_stats_lock); policy->stats = stats; ret = sysfs_create_group(&policy->kobj, &stats_attr_group); @@ -294,13 +292,11 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb, cpufreq_stats_update(stats); - spin_lock(&cpufreq_stats_lock); stats->last_index = new_index; #ifdef CONFIG_CPU_FREQ_STAT_DETAILS stats->trans_table[old_index * stats->max_state + new_index]++; #endif stats->total_trans++; - spin_unlock(&cpufreq_stats_lock); put_policy: cpufreq_cpu_put(policy); -- cgit v0.10.2 From d78cb3680c8e95c100d5a351b8cfc7dd3c589b68 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 11 Jan 2015 23:27:38 +0100 Subject: PM / hibernate: Remove unused function Remove the function get_safe_write_buffer() that is not used anywhere. This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 0c40c16..8e75a5a 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -2310,8 +2310,6 @@ static inline void free_highmem_data(void) free_image_page(buffer, PG_UNSAFE_CLEAR); } #else -static inline int get_safe_write_buffer(void) { return 0; } - static unsigned int count_highmem_image_pages(struct memory_bitmap *bm) { return 0; } -- cgit v0.10.2 From 382548a62ade2c003c77a1055b6eb2a47ce30084 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 20 Jan 2015 11:33:09 +0100 Subject: PM / Domains: Remove pm_genpd_dev_need_restore() API There are currently no users of this API, let's remove it. Additionally, if such feature would be needed future wise, a better option is likely use pm_runtime_set_active|suspended() in some form. Signed-off-by: Ulf Hansson Acked-by: Geert Uytterhoeven Acked-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 0d8780c..c5280f2 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1559,26 +1559,6 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, } /** - * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag. - * @dev: Device to set/unset the flag for. - * @val: The new value of the device's "need restore" flag. - */ -void pm_genpd_dev_need_restore(struct device *dev, bool val) -{ - struct pm_subsys_data *psd; - unsigned long flags; - - spin_lock_irqsave(&dev->power.lock, flags); - - psd = dev_to_psd(dev); - if (psd && psd->domain_data) - to_gpd_data(psd->domain_data)->need_restore = val ? 1 : 0; - - spin_unlock_irqrestore(&dev->power.lock, flags); -} -EXPORT_SYMBOL_GPL(pm_genpd_dev_need_restore); - -/** * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. * @genpd: Master PM domain to add the subdomain to. * @subdomain: Subdomain to be added. diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index a9edab2..ed60776 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -140,7 +140,6 @@ extern int __pm_genpd_name_add_device(const char *domain_name, extern int pm_genpd_remove_device(struct generic_pm_domain *genpd, struct device *dev); -extern void pm_genpd_dev_need_restore(struct device *dev, bool val); extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, struct generic_pm_domain *new_subdomain); extern int pm_genpd_add_subdomain_names(const char *master_name, @@ -187,7 +186,6 @@ static inline int pm_genpd_remove_device(struct generic_pm_domain *genpd, { return -ENOSYS; } -static inline void pm_genpd_dev_need_restore(struct device *dev, bool val) {} static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, struct generic_pm_domain *new_sd) { -- cgit v0.10.2 From e044d8f92f79db167bb7f9dfd0f317e3238d82d1 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 26 Jan 2015 16:58:48 +0800 Subject: ACPI: Introduce acpi_unload_parent_table() usages in Linux kernel ACPICA has implemented acpi_unload_parent_table() which can exactly replace the acpi_get_id()/acpi_unload_table_id() implemented in Linux kernel. The acpi_unload_parent_table() has been unit tested in ACPICA simulation environment. This patch can also help to reduce the source code differences between Linux and ACPICA. Signed-off-by: Lv Zheng Acked-by: Bjorn Helgaas Tested-by: Octavian Purdila Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index dae9401..51a8329 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -53,50 +53,6 @@ ACPI_MODULE_NAME("nsxfobj") /******************************************************************************* * - * FUNCTION: acpi_get_id - * - * PARAMETERS: Handle - Handle of object whose id is desired - * ret_id - Where the id will be placed - * - * RETURN: Status - * - * DESCRIPTION: This routine returns the owner id associated with a handle - * - ******************************************************************************/ -acpi_status acpi_get_id(acpi_handle handle, acpi_owner_id * ret_id) -{ - struct acpi_namespace_node *node; - acpi_status status; - - /* Parameter Validation */ - - if (!ret_id) { - return (AE_BAD_PARAMETER); - } - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return (status); - } - - /* Convert and validate the handle */ - - node = acpi_ns_validate_handle(handle); - if (!node) { - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - return (AE_BAD_PARAMETER); - } - - *ret_id = node->owner_id; - - status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - return (status); -} - -ACPI_EXPORT_SYMBOL(acpi_get_id) - -/******************************************************************************* - * * FUNCTION: acpi_get_type * * PARAMETERS: handle - Handle of object whose type is desired diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 9520ae1..0f9dd80 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -265,52 +265,6 @@ ACPI_EXPORT_SYMBOL(acpi_get_table_header) /******************************************************************************* * - * FUNCTION: acpi_unload_table_id - * - * PARAMETERS: id - Owner ID of the table to be removed. - * - * RETURN: Status - * - * DESCRIPTION: This routine is used to force the unload of a table (by id) - * - ******************************************************************************/ -acpi_status acpi_unload_table_id(acpi_owner_id id) -{ - int i; - acpi_status status = AE_NOT_EXIST; - - ACPI_FUNCTION_TRACE(acpi_unload_table_id); - - status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Find table in the global table list */ - for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { - if (id != acpi_gbl_root_table_list.tables[i].owner_id) { - continue; - } - /* - * Delete all namespace objects owned by this table. Note that these - * objects can appear anywhere in the namespace by virtue of the AML - * "Scope" operator. Thus, we need to track ownership by an ID, not - * simply a position within the hierarchy - */ - acpi_tb_delete_namespace_by_owner(i); - status = acpi_tb_release_owner_id(i); - acpi_tb_set_table_loaded_flag(i, FALSE); - break; - } - - (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); - return_ACPI_STATUS(status); -} - -ACPI_EXPORT_SYMBOL(acpi_unload_table_id) - -/******************************************************************************* - * * FUNCTION: acpi_get_table_with_size * * PARAMETERS: signature - ACPI signature of needed table diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index bada2099..c32fb78 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -475,7 +475,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) struct slot *slot = bss_hotplug_slot->private; struct pci_dev *dev, *temp; int rc; - acpi_owner_id ssdt_id = 0; + acpi_handle ssdt_hdl = NULL; /* Acquire update access to the bus */ mutex_lock(&sn_hotplug_mutex); @@ -522,7 +522,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) if (ACPI_SUCCESS(ret) && (adr>>16) == (slot->device_num + 1)) { /* retain the owner id */ - acpi_get_id(chandle, &ssdt_id); + ssdt_hdl = chandle; ret = acpi_bus_get_device(chandle, &device); @@ -547,12 +547,13 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) pci_unlock_rescan_remove(); /* Remove the SSDT for the slot from the ACPI namespace */ - if (SN_ACPI_BASE_SUPPORT() && ssdt_id) { + if (SN_ACPI_BASE_SUPPORT() && ssdt_hdl) { acpi_status ret; - ret = acpi_unload_table_id(ssdt_id); + ret = acpi_unload_parent_table(ssdt_hdl); if (ACPI_FAILURE(ret)) { - printk(KERN_ERR "%s: acpi_unload_table_id failed (0x%x) for id %d\n", - __func__, ret, ssdt_id); + acpi_handle_err(ssdt_hdl, + "%s: acpi_unload_parent_table failed (0x%x)\n", + __func__, ret); /* try to continue on */ } } diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 5ba7846..5dd21bc 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -891,12 +891,6 @@ ACPI_APP_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(1) ACPI_GLOBAL(u8, acpi_gbl_permanent_mmap); ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_id(acpi_handle object, - acpi_owner_id * out_type)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_unload_table_id(acpi_owner_id id)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_get_table_with_size(acpi_string signature, u32 instance, struct acpi_table_header -- cgit v0.10.2 From a45de93eb10ae44446aec2c73d722562ab46092a Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 26 Jan 2015 16:58:56 +0800 Subject: ACPICA: Resources: Provide common part for struct acpi_resource_address structures. struct acpi_resource_address and struct acpi_resource_extended_address64 share substracts just at different offsets. To unify the parsing functions, OSPMs like Linux need a new ACPI_ADDRESS64_ATTRIBUTE as their substructs, so they can extract the shared data. This patch also synchronizes the structure changes to the Linux kernel. The usages are searched by matching the following keywords: 1. acpi_resource_address 2. acpi_resource_extended_address 3. ACPI_RESOURCE_TYPE_ADDRESS 4. ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS And we found and fixed the usages in the following files: arch/ia64/kernel/acpi-ext.c arch/ia64/pci/pci.c arch/x86/pci/acpi.c arch/x86/pci/mmconfig-shared.c drivers/xen/xen-acpi-memhotplug.c drivers/acpi/acpi_memhotplug.c drivers/acpi/pci_root.c drivers/acpi/resource.c drivers/char/hpet.c drivers/pnp/pnpacpi/rsparser.c drivers/hv/vmbus_drv.c Build tests are passed with defconfig/allnoconfig/allyesconfig and defconfig+CONFIG_ACPI=n. Original-by: Thomas Gleixner Original-by: Jiang Liu Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/arch/ia64/kernel/acpi-ext.c b/arch/ia64/kernel/acpi-ext.c index 8b9318d..bd09bf7 100644 --- a/arch/ia64/kernel/acpi-ext.c +++ b/arch/ia64/kernel/acpi-ext.c @@ -69,10 +69,10 @@ static acpi_status find_csr_space(struct acpi_resource *resource, void *data) status = acpi_resource_to_address64(resource, &addr); if (ACPI_SUCCESS(status) && addr.resource_type == ACPI_MEMORY_RANGE && - addr.address_length && + addr.address.address_length && addr.producer_consumer == ACPI_CONSUMER) { - space->base = addr.minimum; - space->length = addr.address_length; + space->base = addr.address.minimum; + space->length = addr.address.address_length; return AE_CTRL_TERMINATE; } return AE_OK; /* keep looking */ diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 291a582..46920aa 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -188,12 +188,12 @@ static u64 add_io_space(struct pci_root_info *info, name = (char *)(iospace + 1); - min = addr->minimum; - max = min + addr->address_length - 1; + min = addr->address.minimum; + max = min + addr->address.address_length - 1; if (addr->info.io.translation_type == ACPI_SPARSE_TRANSLATION) sparse = 1; - space_nr = new_space(addr->translation_offset, sparse); + space_nr = new_space(addr->address.translation_offset, sparse); if (space_nr == ~0) goto free_resource; @@ -247,7 +247,7 @@ static acpi_status resource_to_window(struct acpi_resource *resource, if (ACPI_SUCCESS(status) && (addr->resource_type == ACPI_MEMORY_RANGE || addr->resource_type == ACPI_IO_RANGE) && - addr->address_length && + addr->address.address_length && addr->producer_consumer == ACPI_PRODUCER) return AE_OK; @@ -284,7 +284,7 @@ static acpi_status add_window(struct acpi_resource *res, void *data) if (addr.resource_type == ACPI_MEMORY_RANGE) { flags = IORESOURCE_MEM; root = &iomem_resource; - offset = addr.translation_offset; + offset = addr.address.translation_offset; } else if (addr.resource_type == ACPI_IO_RANGE) { flags = IORESOURCE_IO; root = &ioport_resource; @@ -297,8 +297,8 @@ static acpi_status add_window(struct acpi_resource *res, void *data) resource = &info->res[info->res_num]; resource->name = info->name; resource->flags = flags; - resource->start = addr.minimum + offset; - resource->end = resource->start + addr.address_length - 1; + resource->start = addr.address.minimum + offset; + resource->end = resource->start + addr.address.address_length - 1; info->res_offset[info->res_num] = offset; if (insert_resource(root, resource)) { diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index cfd1b13..bb98afd 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -231,23 +231,23 @@ static acpi_status resource_to_addr(struct acpi_resource *resource, case ACPI_RESOURCE_TYPE_MEMORY24: memory24 = &resource->data.memory24; addr->resource_type = ACPI_MEMORY_RANGE; - addr->minimum = memory24->minimum; - addr->address_length = memory24->address_length; - addr->maximum = addr->minimum + addr->address_length - 1; + addr->address.minimum = memory24->minimum; + addr->address.address_length = memory24->address_length; + addr->address.maximum = addr->address.minimum + addr->address.address_length - 1; return AE_OK; case ACPI_RESOURCE_TYPE_MEMORY32: memory32 = &resource->data.memory32; addr->resource_type = ACPI_MEMORY_RANGE; - addr->minimum = memory32->minimum; - addr->address_length = memory32->address_length; - addr->maximum = addr->minimum + addr->address_length - 1; + addr->address.minimum = memory32->minimum; + addr->address.address_length = memory32->address_length; + addr->address.maximum = addr->address.minimum + addr->address.address_length - 1; return AE_OK; case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: fixed_memory32 = &resource->data.fixed_memory32; addr->resource_type = ACPI_MEMORY_RANGE; - addr->minimum = fixed_memory32->address; - addr->address_length = fixed_memory32->address_length; - addr->maximum = addr->minimum + addr->address_length - 1; + addr->address.minimum = fixed_memory32->address; + addr->address.address_length = fixed_memory32->address_length; + addr->address.maximum = addr->address.minimum + addr->address.address_length - 1; return AE_OK; case ACPI_RESOURCE_TYPE_ADDRESS16: case ACPI_RESOURCE_TYPE_ADDRESS32: @@ -256,7 +256,7 @@ static acpi_status resource_to_addr(struct acpi_resource *resource, if (ACPI_SUCCESS(status) && (addr->resource_type == ACPI_MEMORY_RANGE || addr->resource_type == ACPI_IO_RANGE) && - addr->address_length > 0) { + addr->address.address_length > 0) { return AE_OK; } break; @@ -298,8 +298,8 @@ static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data) } else return AE_OK; - start = addr.minimum + addr.translation_offset; - orig_end = end = addr.maximum + addr.translation_offset; + start = addr.address.minimum + addr.address.translation_offset; + orig_end = end = addr.address.maximum + addr.address.translation_offset; /* Exclude non-addressable range or non-addressable portion of range */ end = min(end, (u64)iomem_resource.end); @@ -320,7 +320,7 @@ static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data) res->flags = flags; res->start = start; res->end = end; - info->res_offset[info->res_num] = addr.translation_offset; + info->res_offset[info->res_num] = addr.address.translation_offset; info->res_num++; if (!pci_use_crs) diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 326198a..5a8dcea 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c @@ -397,12 +397,12 @@ static acpi_status check_mcfg_resource(struct acpi_resource *res, void *data) status = acpi_resource_to_address64(res, &address); if (ACPI_FAILURE(status) || - (address.address_length <= 0) || + (address.address.address_length <= 0) || (address.resource_type != ACPI_MEMORY_RANGE)) return AE_OK; - if ((mcfg_res->start >= address.minimum) && - (mcfg_res->end < (address.minimum + address.address_length))) { + if ((mcfg_res->start >= address.address.minimum) && + (mcfg_res->end < (address.address.minimum + address.address.address_length))) { mcfg_res->flags = 1; return AE_CTRL_TERMINATE; } diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 23e2319..ee28f4d 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -101,8 +101,8 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context) /* Can we combine the resource range information? */ if ((info->caching == address64.info.mem.caching) && (info->write_protect == address64.info.mem.write_protect) && - (info->start_addr + info->length == address64.minimum)) { - info->length += address64.address_length; + (info->start_addr + info->length == address64.address.minimum)) { + info->length += address64.address.address_length; return AE_OK; } } @@ -114,8 +114,8 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context) INIT_LIST_HEAD(&new->list); new->caching = address64.info.mem.caching; new->write_protect = address64.info.mem.write_protect; - new->start_addr = address64.minimum; - new->length = address64.address_length; + new->start_addr = address64.address.minimum; + new->length = address64.address.address_length; list_add_tail(&new->list, &mem_device->res_list); return AE_OK; diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c index 916fd09..94a3a05 100644 --- a/drivers/acpi/acpica/rsaddr.c +++ b/drivers/acpi/acpica/rsaddr.c @@ -74,7 +74,7 @@ struct acpi_rsconvert_info acpi_rs_convert_address16[5] = { * Address Translation Offset * Address Length */ - {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.address16.granularity), + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.address16.address.granularity), AML_OFFSET(address16.granularity), 5}, @@ -112,7 +112,7 @@ struct acpi_rsconvert_info acpi_rs_convert_address32[5] = { * Address Translation Offset * Address Length */ - {ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.address32.granularity), + {ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.address32.address.granularity), AML_OFFSET(address32.granularity), 5}, @@ -150,7 +150,7 @@ struct acpi_rsconvert_info acpi_rs_convert_address64[5] = { * Address Translation Offset * Address Length */ - {ACPI_RSC_MOVE64, ACPI_RS_OFFSET(data.address64.granularity), + {ACPI_RSC_MOVE64, ACPI_RS_OFFSET(data.address64.address.granularity), AML_OFFSET(address64.granularity), 5}, @@ -194,7 +194,8 @@ struct acpi_rsconvert_info acpi_rs_convert_ext_address64[5] = { * Address Length * Type-Specific Attribute */ - {ACPI_RSC_MOVE64, ACPI_RS_OFFSET(data.ext_address64.granularity), + {ACPI_RSC_MOVE64, + ACPI_RS_OFFSET(data.ext_address64.address.granularity), AML_OFFSET(ext_address64.granularity), 6} }; diff --git a/drivers/acpi/acpica/rsdumpinfo.c b/drivers/acpi/acpica/rsdumpinfo.c index 2f9332d..6ba7ad5 100644 --- a/drivers/acpi/acpica/rsdumpinfo.c +++ b/drivers/acpi/acpica/rsdumpinfo.c @@ -183,15 +183,15 @@ struct acpi_rsdump_info acpi_rs_dump_address16[8] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address16), "16-Bit WORD Address Space", NULL}, {ACPI_RSD_ADDRESS, 0, NULL, NULL}, - {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.granularity), "Granularity", - NULL}, - {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.minimum), "Address Minimum", - NULL}, - {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.maximum), "Address Maximum", - NULL}, - {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.translation_offset), + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.granularity), + "Granularity", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.minimum), + "Address Minimum", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.maximum), + "Address Maximum", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.translation_offset), "Translation Offset", NULL}, - {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address_length), + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.address_length), "Address Length", NULL}, {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address16.resource_source), NULL, NULL} }; @@ -200,15 +200,15 @@ struct acpi_rsdump_info acpi_rs_dump_address32[8] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address32), "32-Bit DWORD Address Space", NULL}, {ACPI_RSD_ADDRESS, 0, NULL, NULL}, - {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.granularity), "Granularity", - NULL}, - {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.minimum), "Address Minimum", - NULL}, - {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.maximum), "Address Maximum", - NULL}, - {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.translation_offset), + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.granularity), + "Granularity", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.minimum), + "Address Minimum", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.maximum), + "Address Maximum", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.translation_offset), "Translation Offset", NULL}, - {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address_length), + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.address_length), "Address Length", NULL}, {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address32.resource_source), NULL, NULL} }; @@ -217,15 +217,15 @@ struct acpi_rsdump_info acpi_rs_dump_address64[8] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address64), "64-Bit QWORD Address Space", NULL}, {ACPI_RSD_ADDRESS, 0, NULL, NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.granularity), "Granularity", - NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.minimum), "Address Minimum", - NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.maximum), "Address Maximum", - NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.translation_offset), + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.granularity), + "Granularity", NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.minimum), + "Address Minimum", NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.maximum), + "Address Maximum", NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.translation_offset), "Translation Offset", NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address_length), + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.address_length), "Address Length", NULL}, {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address64.resource_source), NULL, NULL} }; @@ -234,15 +234,16 @@ struct acpi_rsdump_info acpi_rs_dump_ext_address64[8] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_ext_address64), "64-Bit Extended Address Space", NULL}, {ACPI_RSD_ADDRESS, 0, NULL, NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.granularity), + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address.granularity), "Granularity", NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.minimum), + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address.minimum), "Address Minimum", NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.maximum), + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address.maximum), "Address Maximum", NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.translation_offset), + {ACPI_RSD_UINT64, + ACPI_RSD_OFFSET(ext_address64.address.translation_offset), "Translation Offset", NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address_length), + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address.address_length), "Address Length", NULL}, {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.type_specific), "Type-Specific Attribute", NULL} diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index 877ab92..2952878 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -60,11 +60,11 @@ ACPI_MODULE_NAME("rsxface") ACPI_COPY_FIELD(out, in, min_address_fixed); \ ACPI_COPY_FIELD(out, in, max_address_fixed); \ ACPI_COPY_FIELD(out, in, info); \ - ACPI_COPY_FIELD(out, in, granularity); \ - ACPI_COPY_FIELD(out, in, minimum); \ - ACPI_COPY_FIELD(out, in, maximum); \ - ACPI_COPY_FIELD(out, in, translation_offset); \ - ACPI_COPY_FIELD(out, in, address_length); \ + ACPI_COPY_FIELD(out, in, address.granularity); \ + ACPI_COPY_FIELD(out, in, address.minimum); \ + ACPI_COPY_FIELD(out, in, address.maximum); \ + ACPI_COPY_FIELD(out, in, address.translation_offset); \ + ACPI_COPY_FIELD(out, in, address.address_length); \ ACPI_COPY_FIELD(out, in, resource_source); /* Local prototypes */ static acpi_status diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index c6bcb8c..e53e0f6 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -112,10 +112,10 @@ get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) if (ACPI_FAILURE(status)) return AE_OK; - if ((address.address_length > 0) && + if ((address.address.address_length > 0) && (address.resource_type == ACPI_BUS_NUMBER_RANGE)) { - res->start = address.minimum; - res->end = address.minimum + address.address_length - 1; + res->start = address.address.minimum; + res->end = address.address.minimum + address.address.address_length - 1; } return AE_OK; diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 782a0d1..d0a4d90 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -202,22 +202,22 @@ bool acpi_dev_resource_address_space(struct acpi_resource *ares, if (ACPI_FAILURE(status)) return false; - res->start = addr.minimum; - res->end = addr.maximum; + res->start = addr.address.minimum; + res->end = addr.address.maximum; window = addr.producer_consumer == ACPI_PRODUCER; switch(addr.resource_type) { case ACPI_MEMORY_RANGE: - len = addr.maximum - addr.minimum + 1; + len = addr.address.maximum - addr.address.minimum + 1; res->flags = acpi_dev_memresource_flags(len, addr.info.mem.write_protect, window); break; case ACPI_IO_RANGE: - io_decode = addr.granularity == 0xfff ? + io_decode = addr.address.granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16; - res->flags = acpi_dev_ioresource_flags(addr.minimum, - addr.maximum, + res->flags = acpi_dev_ioresource_flags(addr.address.minimum, + addr.address.maximum, io_decode, window); break; case ACPI_BUS_NUMBER_RANGE: @@ -253,22 +253,22 @@ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, ext_addr = &ares->data.ext_address64; - res->start = ext_addr->minimum; - res->end = ext_addr->maximum; + res->start = ext_addr->address.minimum; + res->end = ext_addr->address.maximum; window = ext_addr->producer_consumer == ACPI_PRODUCER; switch(ext_addr->resource_type) { case ACPI_MEMORY_RANGE: - len = ext_addr->maximum - ext_addr->minimum + 1; + len = ext_addr->address.maximum - ext_addr->address.minimum + 1; res->flags = acpi_dev_memresource_flags(len, ext_addr->info.mem.write_protect, window); break; case ACPI_IO_RANGE: - io_decode = ext_addr->granularity == 0xfff ? + io_decode = ext_addr->address.granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16; - res->flags = acpi_dev_ioresource_flags(ext_addr->minimum, - ext_addr->maximum, + res->flags = acpi_dev_ioresource_flags(ext_addr->address.minimum, + ext_addr->address.maximum, io_decode, window); break; case ACPI_BUS_NUMBER_RANGE: diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index d5d4cd8..5c0baa9 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -976,8 +976,8 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) status = acpi_resource_to_address64(res, &addr); if (ACPI_SUCCESS(status)) { - hdp->hd_phys_address = addr.minimum; - hdp->hd_address = ioremap(addr.minimum, addr.address_length); + hdp->hd_phys_address = addr.address.minimum; + hdp->hd_address = ioremap(addr.address.minimum, addr.address.address_length); if (hpet_is_known(hdp)) { iounmap(hdp->hd_address); diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 4d6b269..bb3725b 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -861,8 +861,8 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) break; case ACPI_RESOURCE_TYPE_ADDRESS64: - hyperv_mmio.start = res->data.address64.minimum; - hyperv_mmio.end = res->data.address64.maximum; + hyperv_mmio.start = res->data.address64.address.minimum; + hyperv_mmio.end = res->data.address64.address.maximum; break; } diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 66977eb..2d9bc78 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -410,12 +410,12 @@ static __init void pnpacpi_parse_address_option(struct pnp_dev *dev, if (p->resource_type == ACPI_MEMORY_RANGE) { if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) flags = IORESOURCE_MEM_WRITEABLE; - pnp_register_mem_resource(dev, option_flags, p->minimum, - p->minimum, 0, p->address_length, + pnp_register_mem_resource(dev, option_flags, p->address.minimum, + p->address.minimum, 0, p->address.address_length, flags); } else if (p->resource_type == ACPI_IO_RANGE) - pnp_register_port_resource(dev, option_flags, p->minimum, - p->minimum, 0, p->address_length, + pnp_register_port_resource(dev, option_flags, p->address.minimum, + p->address.minimum, 0, p->address.address_length, IORESOURCE_IO_FIXED); } @@ -429,12 +429,12 @@ static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev, if (p->resource_type == ACPI_MEMORY_RANGE) { if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) flags = IORESOURCE_MEM_WRITEABLE; - pnp_register_mem_resource(dev, option_flags, p->minimum, - p->minimum, 0, p->address_length, + pnp_register_mem_resource(dev, option_flags, p->address.minimum, + p->address.minimum, 0, p->address.address_length, flags); } else if (p->resource_type == ACPI_IO_RANGE) - pnp_register_port_resource(dev, option_flags, p->minimum, - p->minimum, 0, p->address_length, + pnp_register_port_resource(dev, option_flags, p->address.minimum, + p->address.minimum, 0, p->address.address_length, IORESOURCE_IO_FIXED); } diff --git a/drivers/xen/xen-acpi-memhotplug.c b/drivers/xen/xen-acpi-memhotplug.c index 34e40b7..4fc886c 100644 --- a/drivers/xen/xen-acpi-memhotplug.c +++ b/drivers/xen/xen-acpi-memhotplug.c @@ -117,8 +117,8 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context) list_for_each_entry(info, &mem_device->res_list, list) { if ((info->caching == address64.info.mem.caching) && (info->write_protect == address64.info.mem.write_protect) && - (info->start_addr + info->length == address64.minimum)) { - info->length += address64.address_length; + (info->start_addr + info->length == address64.address.minimum)) { + info->length += address64.address.address_length; return AE_OK; } } @@ -130,8 +130,8 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context) INIT_LIST_HEAD(&new->list); new->caching = address64.info.mem.caching; new->write_protect = address64.info.mem.write_protect; - new->start_addr = address64.minimum; - new->length = address64.address_length; + new->start_addr = address64.address.minimum; + new->length = address64.address.address_length; list_add_tail(&new->list, &mem_device->res_list); return AE_OK; diff --git a/include/acpi/acrestyp.h b/include/acpi/acrestyp.h index eb760ca..0b75e01 100644 --- a/include/acpi/acrestyp.h +++ b/include/acpi/acrestyp.h @@ -305,43 +305,51 @@ struct acpi_resource_source { u8 max_address_fixed; \ union acpi_resource_attribute info; -struct acpi_resource_address { -ACPI_RESOURCE_ADDRESS_COMMON}; - -struct acpi_resource_address16 { - ACPI_RESOURCE_ADDRESS_COMMON u16 granularity; +struct acpi_address16_attribute { + u16 granularity; u16 minimum; u16 maximum; u16 translation_offset; u16 address_length; - struct acpi_resource_source resource_source; }; -struct acpi_resource_address32 { - ACPI_RESOURCE_ADDRESS_COMMON u32 granularity; +struct acpi_address32_attribute { + u32 granularity; u32 minimum; u32 maximum; u32 translation_offset; u32 address_length; - struct acpi_resource_source resource_source; }; -struct acpi_resource_address64 { - ACPI_RESOURCE_ADDRESS_COMMON u64 granularity; +struct acpi_address64_attribute { + u64 granularity; u64 minimum; u64 maximum; u64 translation_offset; u64 address_length; +}; + +struct acpi_resource_address { +ACPI_RESOURCE_ADDRESS_COMMON}; + +struct acpi_resource_address16 { + ACPI_RESOURCE_ADDRESS_COMMON struct acpi_address16_attribute address; + struct acpi_resource_source resource_source; +}; + +struct acpi_resource_address32 { + ACPI_RESOURCE_ADDRESS_COMMON struct acpi_address32_attribute address; + struct acpi_resource_source resource_source; +}; + +struct acpi_resource_address64 { + ACPI_RESOURCE_ADDRESS_COMMON struct acpi_address64_attribute address; struct acpi_resource_source resource_source; }; struct acpi_resource_extended_address64 { ACPI_RESOURCE_ADDRESS_COMMON u8 revision_ID; - u64 granularity; - u64 minimum; - u64 maximum; - u64 translation_offset; - u64 address_length; + struct acpi_address64_attribute address; u64 type_specific; }; -- cgit v0.10.2 From 6234f38016ad56321ad0e4bfb57a10a3d940380a Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Mon, 24 Nov 2014 13:28:17 +0100 Subject: PM / devfreq: tegra: add devfreq driver for Tegra Activity Monitor The ACTMON block can monitor several counters, providing averaging and firing interrupts based on watermarking configuration. This implementation monitors the MCALL and MCCPU counters to choose an appropriate frequency for the external memory clock. This patch is based on work by Alex Frid and Mikko Perttunen . Signed-off-by: Tomeu Vizoso Signed-off-by: MyungJoo Ham diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index faf4e70..4aab799 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -87,4 +87,14 @@ config ARM_EXYNOS5_BUS_DEVFREQ It reads PPMU counters of memory controllers and adjusts the operating frequencies and voltages with OPP support. +config ARM_TEGRA_DEVFREQ + tristate "Tegra DEVFREQ Driver" + depends on ARCH_TEGRA_124_SOC + select DEVFREQ_GOV_SIMPLE_ONDEMAND + select PM_OPP + help + This adds the DEVFREQ driver for the Tegra family of SoCs. + It reads ACTMON counters of memory controllers and adjusts the + operating frequencies and voltages with OPP support. + endif # PM_DEVFREQ diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 16138c9..0ea991f 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o # DEVFREQ Drivers obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos/ obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos/ +obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o diff --git a/drivers/devfreq/tegra-devfreq.c b/drivers/devfreq/tegra-devfreq.c new file mode 100644 index 0000000..3479096 --- /dev/null +++ b/drivers/devfreq/tegra-devfreq.c @@ -0,0 +1,718 @@ +/* + * A devfreq driver for NVIDIA Tegra SoCs + * + * Copyright (c) 2014 NVIDIA CORPORATION. All rights reserved. + * Copyright (C) 2014 Google, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "governor.h" + +#define ACTMON_GLB_STATUS 0x0 +#define ACTMON_GLB_PERIOD_CTRL 0x4 + +#define ACTMON_DEV_CTRL 0x0 +#define ACTMON_DEV_CTRL_K_VAL_SHIFT 10 +#define ACTMON_DEV_CTRL_ENB_PERIODIC BIT(18) +#define ACTMON_DEV_CTRL_AVG_BELOW_WMARK_EN BIT(20) +#define ACTMON_DEV_CTRL_AVG_ABOVE_WMARK_EN BIT(21) +#define ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_NUM_SHIFT 23 +#define ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_NUM_SHIFT 26 +#define ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN BIT(29) +#define ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN BIT(30) +#define ACTMON_DEV_CTRL_ENB BIT(31) + +#define ACTMON_DEV_UPPER_WMARK 0x4 +#define ACTMON_DEV_LOWER_WMARK 0x8 +#define ACTMON_DEV_INIT_AVG 0xc +#define ACTMON_DEV_AVG_UPPER_WMARK 0x10 +#define ACTMON_DEV_AVG_LOWER_WMARK 0x14 +#define ACTMON_DEV_COUNT_WEIGHT 0x18 +#define ACTMON_DEV_AVG_COUNT 0x20 +#define ACTMON_DEV_INTR_STATUS 0x24 + +#define ACTMON_INTR_STATUS_CLEAR 0xffffffff + +#define ACTMON_DEV_INTR_CONSECUTIVE_UPPER BIT(31) +#define ACTMON_DEV_INTR_CONSECUTIVE_LOWER BIT(30) + +#define ACTMON_ABOVE_WMARK_WINDOW 1 +#define ACTMON_BELOW_WMARK_WINDOW 3 +#define ACTMON_BOOST_FREQ_STEP 16000 + +/* activity counter is incremented every 256 memory transactions, and each + * transaction takes 4 EMC clocks for Tegra124; So the COUNT_WEIGHT is + * 4 * 256 = 1024. + */ +#define ACTMON_COUNT_WEIGHT 0x400 + +/* + * ACTMON_AVERAGE_WINDOW_LOG2: default value for @DEV_CTRL_K_VAL, which + * translates to 2 ^ (K_VAL + 1). ex: 2 ^ (6 + 1) = 128 + */ +#define ACTMON_AVERAGE_WINDOW_LOG2 6 +#define ACTMON_SAMPLING_PERIOD 12 /* ms */ +#define ACTMON_DEFAULT_AVG_BAND 6 /* 1/10 of % */ + +#define KHZ 1000 + +/* Assume that the bus is saturated if the utilization is 25% */ +#define BUS_SATURATION_RATIO 25 + +/** + * struct tegra_devfreq_device_config - configuration specific to an ACTMON + * device + * + * Coefficients and thresholds are in % + */ +struct tegra_devfreq_device_config { + u32 offset; + u32 irq_mask; + + unsigned int boost_up_coeff; + unsigned int boost_down_coeff; + unsigned int boost_up_threshold; + unsigned int boost_down_threshold; + u32 avg_dependency_threshold; +}; + +enum tegra_actmon_device { + MCALL = 0, + MCCPU, +}; + +static struct tegra_devfreq_device_config actmon_device_configs[] = { + { + /* MCALL */ + .offset = 0x1c0, + .irq_mask = 1 << 26, + .boost_up_coeff = 200, + .boost_down_coeff = 50, + .boost_up_threshold = 60, + .boost_down_threshold = 40, + }, + { + /* MCCPU */ + .offset = 0x200, + .irq_mask = 1 << 25, + .boost_up_coeff = 800, + .boost_down_coeff = 90, + .boost_up_threshold = 27, + .boost_down_threshold = 10, + .avg_dependency_threshold = 50000, + }, +}; + +/** + * struct tegra_devfreq_device - state specific to an ACTMON device + * + * Frequencies are in kHz. + */ +struct tegra_devfreq_device { + const struct tegra_devfreq_device_config *config; + + void __iomem *regs; + u32 avg_band_freq; + u32 avg_count; + + unsigned long target_freq; + unsigned long boost_freq; +}; + +struct tegra_devfreq { + struct devfreq *devfreq; + + struct platform_device *pdev; + struct reset_control *reset; + struct clk *clock; + void __iomem *regs; + + spinlock_t lock; + + struct clk *emc_clock; + unsigned long max_freq; + unsigned long cur_freq; + struct notifier_block rate_change_nb; + + struct tegra_devfreq_device devices[ARRAY_SIZE(actmon_device_configs)]; +}; + +struct tegra_actmon_emc_ratio { + unsigned long cpu_freq; + unsigned long emc_freq; +}; + +static struct tegra_actmon_emc_ratio actmon_emc_ratios[] = { + { 1400000, ULONG_MAX }, + { 1200000, 750000 }, + { 1100000, 600000 }, + { 1000000, 500000 }, + { 800000, 375000 }, + { 500000, 200000 }, + { 250000, 100000 }, +}; + +static unsigned long do_percent(unsigned long val, unsigned int pct) +{ + return val * pct / 100; +} + +static void tegra_devfreq_update_avg_wmark(struct tegra_devfreq_device *dev) +{ + u32 avg = dev->avg_count; + u32 band = dev->avg_band_freq * ACTMON_SAMPLING_PERIOD; + + writel(avg + band, dev->regs + ACTMON_DEV_AVG_UPPER_WMARK); + avg = max(avg, band); + writel(avg - band, dev->regs + ACTMON_DEV_AVG_LOWER_WMARK); +} + +static void tegra_devfreq_update_wmark(struct tegra_devfreq *tegra, + struct tegra_devfreq_device *dev) +{ + u32 val = tegra->cur_freq * ACTMON_SAMPLING_PERIOD; + + writel(do_percent(val, dev->config->boost_up_threshold), + dev->regs + ACTMON_DEV_UPPER_WMARK); + + writel(do_percent(val, dev->config->boost_down_threshold), + dev->regs + ACTMON_DEV_LOWER_WMARK); +} + +static void actmon_write_barrier(struct tegra_devfreq *tegra) +{ + /* ensure the update has reached the ACTMON */ + wmb(); + readl(tegra->regs + ACTMON_GLB_STATUS); +} + +static irqreturn_t actmon_isr(int irq, void *data) +{ + struct tegra_devfreq *tegra = data; + struct tegra_devfreq_device *dev = NULL; + unsigned long flags; + u32 val; + unsigned int i; + + val = readl(tegra->regs + ACTMON_GLB_STATUS); + + for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { + if (val & tegra->devices[i].config->irq_mask) { + dev = tegra->devices + i; + break; + } + } + + if (!dev) + return IRQ_NONE; + + spin_lock_irqsave(&tegra->lock, flags); + + dev->avg_count = readl(dev->regs + ACTMON_DEV_AVG_COUNT); + tegra_devfreq_update_avg_wmark(dev); + + val = readl(dev->regs + ACTMON_DEV_INTR_STATUS); + if (val & ACTMON_DEV_INTR_CONSECUTIVE_UPPER) { + val = readl(dev->regs + ACTMON_DEV_CTRL) | + ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN | + ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; + + /* + * new_boost = min(old_boost * up_coef + step, max_freq) + */ + dev->boost_freq = do_percent(dev->boost_freq, + dev->config->boost_up_coeff); + dev->boost_freq += ACTMON_BOOST_FREQ_STEP; + if (dev->boost_freq >= tegra->max_freq) { + dev->boost_freq = tegra->max_freq; + val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN; + } + writel(val, dev->regs + ACTMON_DEV_CTRL); + } else if (val & ACTMON_DEV_INTR_CONSECUTIVE_LOWER) { + val = readl(dev->regs + ACTMON_DEV_CTRL) | + ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN | + ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; + + /* + * new_boost = old_boost * down_coef + * or 0 if (old_boost * down_coef < step / 2) + */ + dev->boost_freq = do_percent(dev->boost_freq, + dev->config->boost_down_coeff); + if (dev->boost_freq < (ACTMON_BOOST_FREQ_STEP >> 1)) { + dev->boost_freq = 0; + val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; + } + writel(val, dev->regs + ACTMON_DEV_CTRL); + } + + if (dev->config->avg_dependency_threshold) { + val = readl(dev->regs + ACTMON_DEV_CTRL); + if (dev->avg_count >= dev->config->avg_dependency_threshold) + val |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; + else if (dev->boost_freq == 0) + val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; + writel(val, dev->regs + ACTMON_DEV_CTRL); + } + + writel(ACTMON_INTR_STATUS_CLEAR, dev->regs + ACTMON_DEV_INTR_STATUS); + + actmon_write_barrier(tegra); + + spin_unlock_irqrestore(&tegra->lock, flags); + + return IRQ_WAKE_THREAD; +} + +static unsigned long actmon_cpu_to_emc_rate(struct tegra_devfreq *tegra, + unsigned long cpu_freq) +{ + unsigned int i; + struct tegra_actmon_emc_ratio *ratio = actmon_emc_ratios; + + for (i = 0; i < ARRAY_SIZE(actmon_emc_ratios); i++, ratio++) { + if (cpu_freq >= ratio->cpu_freq) { + if (ratio->emc_freq >= tegra->max_freq) + return tegra->max_freq; + else + return ratio->emc_freq; + } + } + + return 0; +} + +static void actmon_update_target(struct tegra_devfreq *tegra, + struct tegra_devfreq_device *dev) +{ + unsigned long cpu_freq = 0; + unsigned long static_cpu_emc_freq = 0; + unsigned int avg_sustain_coef; + unsigned long flags; + + if (dev->config->avg_dependency_threshold) { + cpu_freq = cpufreq_get(0); + static_cpu_emc_freq = actmon_cpu_to_emc_rate(tegra, cpu_freq); + } + + spin_lock_irqsave(&tegra->lock, flags); + + dev->target_freq = dev->avg_count / ACTMON_SAMPLING_PERIOD; + avg_sustain_coef = 100 * 100 / dev->config->boost_up_threshold; + dev->target_freq = do_percent(dev->target_freq, avg_sustain_coef); + dev->target_freq += dev->boost_freq; + + if (dev->avg_count >= dev->config->avg_dependency_threshold) + dev->target_freq = max(dev->target_freq, static_cpu_emc_freq); + + spin_unlock_irqrestore(&tegra->lock, flags); +} + +static irqreturn_t actmon_thread_isr(int irq, void *data) +{ + struct tegra_devfreq *tegra = data; + + mutex_lock(&tegra->devfreq->lock); + update_devfreq(tegra->devfreq); + mutex_unlock(&tegra->devfreq->lock); + + return IRQ_HANDLED; +} + +static int tegra_actmon_rate_notify_cb(struct notifier_block *nb, + unsigned long action, void *ptr) +{ + struct clk_notifier_data *data = ptr; + struct tegra_devfreq *tegra = container_of(nb, struct tegra_devfreq, + rate_change_nb); + unsigned int i; + unsigned long flags; + + spin_lock_irqsave(&tegra->lock, flags); + + switch (action) { + case POST_RATE_CHANGE: + tegra->cur_freq = data->new_rate / KHZ; + + for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) + tegra_devfreq_update_wmark(tegra, tegra->devices + i); + + actmon_write_barrier(tegra); + break; + case PRE_RATE_CHANGE: + /* fall through */ + case ABORT_RATE_CHANGE: + break; + }; + + spin_unlock_irqrestore(&tegra->lock, flags); + + return NOTIFY_OK; +} + +static void tegra_actmon_configure_device(struct tegra_devfreq *tegra, + struct tegra_devfreq_device *dev) +{ + u32 val; + + dev->avg_band_freq = tegra->max_freq * ACTMON_DEFAULT_AVG_BAND / KHZ; + dev->target_freq = tegra->cur_freq; + + dev->avg_count = tegra->cur_freq * ACTMON_SAMPLING_PERIOD; + writel(dev->avg_count, dev->regs + ACTMON_DEV_INIT_AVG); + + tegra_devfreq_update_avg_wmark(dev); + tegra_devfreq_update_wmark(tegra, dev); + + writel(ACTMON_COUNT_WEIGHT, dev->regs + ACTMON_DEV_COUNT_WEIGHT); + writel(ACTMON_INTR_STATUS_CLEAR, dev->regs + ACTMON_DEV_INTR_STATUS); + + val = 0; + val |= ACTMON_DEV_CTRL_ENB_PERIODIC | + ACTMON_DEV_CTRL_AVG_ABOVE_WMARK_EN | + ACTMON_DEV_CTRL_AVG_BELOW_WMARK_EN; + val |= (ACTMON_AVERAGE_WINDOW_LOG2 - 1) + << ACTMON_DEV_CTRL_K_VAL_SHIFT; + val |= (ACTMON_BELOW_WMARK_WINDOW - 1) + << ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_NUM_SHIFT; + val |= (ACTMON_ABOVE_WMARK_WINDOW - 1) + << ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_NUM_SHIFT; + val |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN | + ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN; + + writel(val, dev->regs + ACTMON_DEV_CTRL); + + actmon_write_barrier(tegra); + + val = readl(dev->regs + ACTMON_DEV_CTRL); + val |= ACTMON_DEV_CTRL_ENB; + writel(val, dev->regs + ACTMON_DEV_CTRL); + + actmon_write_barrier(tegra); +} + +static int tegra_devfreq_suspend(struct device *dev) +{ + struct platform_device *pdev; + struct tegra_devfreq *tegra; + struct tegra_devfreq_device *actmon_dev; + unsigned int i; + u32 val; + + pdev = container_of(dev, struct platform_device, dev); + tegra = platform_get_drvdata(pdev); + + for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { + actmon_dev = &tegra->devices[i]; + + val = readl(actmon_dev->regs + ACTMON_DEV_CTRL); + val &= ~ACTMON_DEV_CTRL_ENB; + writel(val, actmon_dev->regs + ACTMON_DEV_CTRL); + + writel(ACTMON_INTR_STATUS_CLEAR, + actmon_dev->regs + ACTMON_DEV_INTR_STATUS); + + actmon_write_barrier(tegra); + } + + return 0; +} + +static int tegra_devfreq_resume(struct device *dev) +{ + struct platform_device *pdev; + struct tegra_devfreq *tegra; + struct tegra_devfreq_device *actmon_dev; + unsigned int i; + + pdev = container_of(dev, struct platform_device, dev); + tegra = platform_get_drvdata(pdev); + + for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { + actmon_dev = &tegra->devices[i]; + + tegra_actmon_configure_device(tegra, actmon_dev); + } + + return 0; +} + +static int tegra_devfreq_target(struct device *dev, unsigned long *freq, + u32 flags) +{ + struct platform_device *pdev; + struct tegra_devfreq *tegra; + struct dev_pm_opp *opp; + unsigned long rate = *freq * KHZ; + + pdev = container_of(dev, struct platform_device, dev); + tegra = platform_get_drvdata(pdev); + + rcu_read_lock(); + opp = devfreq_recommended_opp(dev, &rate, flags); + if (IS_ERR(opp)) { + rcu_read_unlock(); + dev_err(dev, "Failed to find opp for %lu KHz\n", *freq); + return PTR_ERR(opp); + } + rate = dev_pm_opp_get_freq(opp); + rcu_read_unlock(); + + /* TODO: Once we have per-user clk constraints, set a floor */ + clk_set_rate(tegra->emc_clock, rate); + + /* TODO: Set voltage as well */ + + return 0; +} + +static int tegra_devfreq_get_dev_status(struct device *dev, + struct devfreq_dev_status *stat) +{ + struct platform_device *pdev; + struct tegra_devfreq *tegra; + struct tegra_devfreq_device *actmon_dev; + + pdev = container_of(dev, struct platform_device, dev); + tegra = platform_get_drvdata(pdev); + + stat->current_frequency = tegra->cur_freq; + + /* To be used by the tegra governor */ + stat->private_data = tegra; + + /* The below are to be used by the other governors */ + + actmon_dev = &tegra->devices[MCALL]; + + /* Number of cycles spent on memory access */ + stat->busy_time = actmon_dev->avg_count; + + /* The bus can be considered to be saturated way before 100% */ + stat->busy_time *= 100 / BUS_SATURATION_RATIO; + + /* Number of cycles in a sampling period */ + stat->total_time = ACTMON_SAMPLING_PERIOD * tegra->cur_freq; + + return 0; +} + +static int tegra_devfreq_get_target(struct devfreq *devfreq, + unsigned long *freq) +{ + struct devfreq_dev_status stat; + struct tegra_devfreq *tegra; + struct tegra_devfreq_device *dev; + unsigned long target_freq = 0; + unsigned int i; + int err; + + err = devfreq->profile->get_dev_status(devfreq->dev.parent, &stat); + if (err) + return err; + + tegra = stat.private_data; + + for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { + dev = &tegra->devices[i]; + + actmon_update_target(tegra, dev); + + target_freq = max(target_freq, dev->target_freq); + } + + *freq = target_freq; + + return 0; +} + +static int tegra_devfreq_event_handler(struct devfreq *devfreq, + unsigned int event, void *data) +{ + return 0; +} + +static struct devfreq_governor tegra_devfreq_governor = { + .name = "tegra", + .get_target_freq = tegra_devfreq_get_target, + .event_handler = tegra_devfreq_event_handler, +}; + +static struct devfreq_dev_profile tegra_devfreq_profile = { + .polling_ms = 0, + .target = tegra_devfreq_target, + .get_dev_status = tegra_devfreq_get_dev_status, +}; + +static int tegra_devfreq_probe(struct platform_device *pdev) +{ + struct tegra_devfreq *tegra; + struct tegra_devfreq_device *dev; + struct resource *res; + unsigned long max_freq; + unsigned int i; + int irq; + int err; + + tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL); + if (!tegra) + return -ENOMEM; + + spin_lock_init(&tegra->lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Failed to get regs resource\n"); + return -ENODEV; + } + + tegra->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(tegra->regs)) { + dev_err(&pdev->dev, "Failed to get IO memory\n"); + return PTR_ERR(tegra->regs); + } + + tegra->reset = devm_reset_control_get(&pdev->dev, "actmon"); + if (IS_ERR(tegra->reset)) { + dev_err(&pdev->dev, "Failed to get reset\n"); + return PTR_ERR(tegra->reset); + } + + tegra->clock = devm_clk_get(&pdev->dev, "actmon"); + if (IS_ERR(tegra->clock)) { + dev_err(&pdev->dev, "Failed to get actmon clock\n"); + return PTR_ERR(tegra->clock); + } + + tegra->emc_clock = devm_clk_get(&pdev->dev, "emc"); + if (IS_ERR(tegra->emc_clock)) { + dev_err(&pdev->dev, "Failed to get emc clock\n"); + return PTR_ERR(tegra->emc_clock); + } + + err = of_init_opp_table(&pdev->dev); + if (err) { + dev_err(&pdev->dev, "Failed to init operating point table\n"); + return err; + } + + tegra->rate_change_nb.notifier_call = tegra_actmon_rate_notify_cb; + err = clk_notifier_register(tegra->emc_clock, &tegra->rate_change_nb); + if (err) { + dev_err(&pdev->dev, + "Failed to register rate change notifier\n"); + return err; + } + + reset_control_assert(tegra->reset); + + err = clk_prepare_enable(tegra->clock); + if (err) { + reset_control_deassert(tegra->reset); + return err; + } + + reset_control_deassert(tegra->reset); + + max_freq = clk_round_rate(tegra->emc_clock, ULONG_MAX); + tegra->max_freq = max_freq / KHZ; + + clk_set_rate(tegra->emc_clock, max_freq); + + tegra->cur_freq = clk_get_rate(tegra->emc_clock) / KHZ; + + writel(ACTMON_SAMPLING_PERIOD - 1, + tegra->regs + ACTMON_GLB_PERIOD_CTRL); + + for (i = 0; i < ARRAY_SIZE(actmon_device_configs); i++) { + dev = tegra->devices + i; + dev->config = actmon_device_configs + i; + dev->regs = tegra->regs + dev->config->offset; + + tegra_actmon_configure_device(tegra, tegra->devices + i); + } + + err = devfreq_add_governor(&tegra_devfreq_governor); + if (err) { + dev_err(&pdev->dev, "Failed to add governor\n"); + return err; + } + + tegra_devfreq_profile.initial_freq = clk_get_rate(tegra->emc_clock); + tegra->devfreq = devm_devfreq_add_device(&pdev->dev, + &tegra_devfreq_profile, + "tegra", + NULL); + + irq = platform_get_irq(pdev, 0); + err = devm_request_threaded_irq(&pdev->dev, irq, actmon_isr, + actmon_thread_isr, IRQF_SHARED, + "tegra-devfreq", tegra); + if (err) { + dev_err(&pdev->dev, "Interrupt request failed\n"); + return err; + } + + platform_set_drvdata(pdev, tegra); + + return 0; +} + +static int tegra_devfreq_remove(struct platform_device *pdev) +{ + struct tegra_devfreq *tegra = platform_get_drvdata(pdev); + + clk_notifier_unregister(tegra->emc_clock, &tegra->rate_change_nb); + + clk_disable_unprepare(tegra->clock); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(tegra_devfreq_pm_ops, + tegra_devfreq_suspend, + tegra_devfreq_resume); + +static struct of_device_id tegra_devfreq_of_match[] = { + { .compatible = "nvidia,tegra124-actmon" }, + { }, +}; + +static struct platform_driver tegra_devfreq_driver = { + .probe = tegra_devfreq_probe, + .remove = tegra_devfreq_remove, + .driver = { + .name = "tegra-devfreq", + .owner = THIS_MODULE, + .of_match_table = tegra_devfreq_of_match, + .pm = &tegra_devfreq_pm_ops, + }, +}; +module_platform_driver(tegra_devfreq_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Tegra devfreq driver"); +MODULE_AUTHOR("Tomeu Vizoso "); +MODULE_DEVICE_TABLE(of, tegra_devfreq_of_match); -- cgit v0.10.2 From a03ff6f20c396fb84cf61501a31fefdf0a5eb5a7 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Mon, 26 Jan 2015 14:43:04 +0100 Subject: PM / sleep: Mention async suspend in PM_TRACE documentation Document pm_tracing actually affecting suspend in non-trivial way. Signed-off-by: Pavel Machek Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/power/s2ram.txt b/Documentation/power/s2ram.txt index 1bdfa04..4685aee 100644 --- a/Documentation/power/s2ram.txt +++ b/Documentation/power/s2ram.txt @@ -69,6 +69,10 @@ Reason for this is that the RTC is the only reliably available piece of hardware during resume operations where a value can be set that will survive a reboot. +pm_trace is not compatible with asynchronous suspend, so it turns +asynchronous suspend off (which may work around timing or +ordering-sensitive bugs). + Consequence is that after a resume (even if it is successful) your system clock will have a value corresponding to the magic number instead of the correct date/time! It is therefore advisable to use a program like ntp-date -- cgit v0.10.2 From 5c1de006e8e66b0be05be422416629e344c71652 Mon Sep 17 00:00:00 2001 From: "sriram@marirs.net.in" Date: Mon, 22 Dec 2014 22:17:37 +0530 Subject: cpupower Makefile change to help run the tool without 'make install' The cpupower tool, when compiled against libcpupower.so fail's to run as the linker file path's are missing during compilation. So added changes in the Makefile to run cpupower tool, which helps us run the tool without doing a 'make install'. Signed-off-by: Sriram Raghunathan Acked-by: Thomas Renninger Signed-off-by: Rafael J. Wysocki diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile index 2e2ba2e..3ed7c04 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile @@ -209,7 +209,7 @@ $(OUTPUT)%.o: %.c $(OUTPUT)cpupower: $(UTIL_OBJS) $(OUTPUT)libcpupower.so.$(LIB_MAJ) $(ECHO) " CC " $@ - $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lcpupower -lrt -lpci -L$(OUTPUT) -o $@ + $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lcpupower -Wl,-rpath=./ -lrt -lpci -L$(OUTPUT) -o $@ $(QUIET) $(STRIPCMD) $@ $(OUTPUT)po/$(PACKAGE).pot: $(UTIL_SRC) -- cgit v0.10.2 From 7ab0256e57ae4423fbfb6b6c1611578c634702c9 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 28 Jan 2015 13:53:28 -0800 Subject: intel_pstate: Add support for SkyLake Add SKL cpuid. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 742eefb..7d9f822 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -825,6 +825,7 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = { ICPU(0x46, core_params), ICPU(0x47, core_params), ICPU(0x4c, byt_params), + ICPU(0x4e, core_params), ICPU(0x4f, core_params), ICPU(0x56, core_params), {} -- cgit v0.10.2 From d01b1f48c5fd95901203bd830458eaf619ed6c47 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 28 Jan 2015 15:03:27 -0800 Subject: intel_pstate: expose turbo range to sysfs This patch adds "turbo_pct" to the intel_pstate sysfs interface. turbo_pct will display the percentage of the total supported pstates that are in the turbo range. This value is independent of whether turbo has been disabled or not. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/cpu-freq/intel-pstate.txt b/Documentation/cpu-freq/intel-pstate.txt index 765d7fc..7767ce6 100644 --- a/Documentation/cpu-freq/intel-pstate.txt +++ b/Documentation/cpu-freq/intel-pstate.txt @@ -37,6 +37,10 @@ controlling P state selection. These files have been added to no_turbo: limits the driver to selecting P states below the turbo frequency range. + turbo_pct: displays the percentage of the total performance that + is supported by hardware that is in the turbo range. This number + is independent of whether turbo has been disabled or not. + For contemporary Intel processors, the frequency is controlled by the processor itself and the P-states exposed to software are related to performance levels. The idea that frequency can be set to a single diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 7d9f822..ed6dd7d 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -338,6 +338,22 @@ static void __init intel_pstate_debug_expose_params(void) return sprintf(buf, "%u\n", limits.object); \ } +static ssize_t show_turbo_pct(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct cpudata *cpu; + int total, no_turbo, turbo_pct; + uint32_t turbo_fp; + + cpu = all_cpu_data[0]; + + total = cpu->pstate.turbo_pstate - cpu->pstate.min_pstate + 1; + no_turbo = cpu->pstate.max_pstate - cpu->pstate.min_pstate + 1; + turbo_fp = div_fp(int_tofp(no_turbo), int_tofp(total)); + turbo_pct = 100 - fp_toint(mul_fp(turbo_fp, int_tofp(100))); + return sprintf(buf, "%u\n", turbo_pct); +} + static ssize_t show_no_turbo(struct kobject *kobj, struct attribute *attr, char *buf) { @@ -418,11 +434,13 @@ show_one(min_perf_pct, min_perf_pct); define_one_global_rw(no_turbo); define_one_global_rw(max_perf_pct); define_one_global_rw(min_perf_pct); +define_one_global_ro(turbo_pct); static struct attribute *intel_pstate_attributes[] = { &no_turbo.attr, &max_perf_pct.attr, &min_perf_pct.attr, + &turbo_pct.attr, NULL }; -- cgit v0.10.2 From 0522424ecb333c0874c4e74bc053dd662bed40df Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 28 Jan 2015 15:03:28 -0800 Subject: intel_pstate: Add num_pstates to sysfs Add a sysfs interface to display the total number of supported pstates. This value is independent of whether turbo has been enabled or disabled. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/cpu-freq/intel-pstate.txt b/Documentation/cpu-freq/intel-pstate.txt index 7767ce6..6557507 100644 --- a/Documentation/cpu-freq/intel-pstate.txt +++ b/Documentation/cpu-freq/intel-pstate.txt @@ -41,6 +41,10 @@ controlling P state selection. These files have been added to is supported by hardware that is in the turbo range. This number is independent of whether turbo has been disabled or not. + num_pstates: displays the number of pstates that are supported + by hardware. This number is independent of whether turbo has + been disabled or not. + For contemporary Intel processors, the frequency is controlled by the processor itself and the P-states exposed to software are related to performance levels. The idea that frequency can be set to a single diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index ed6dd7d..80ecc35 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -354,6 +354,17 @@ static ssize_t show_turbo_pct(struct kobject *kobj, return sprintf(buf, "%u\n", turbo_pct); } +static ssize_t show_num_pstates(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct cpudata *cpu; + int total; + + cpu = all_cpu_data[0]; + total = cpu->pstate.turbo_pstate - cpu->pstate.min_pstate + 1; + return sprintf(buf, "%u\n", total); +} + static ssize_t show_no_turbo(struct kobject *kobj, struct attribute *attr, char *buf) { @@ -435,12 +446,14 @@ define_one_global_rw(no_turbo); define_one_global_rw(max_perf_pct); define_one_global_rw(min_perf_pct); define_one_global_ro(turbo_pct); +define_one_global_ro(num_pstates); static struct attribute *intel_pstate_attributes[] = { &no_turbo.attr, &max_perf_pct.attr, &min_perf_pct.attr, &turbo_pct.attr, + &num_pstates.attr, NULL }; -- cgit v0.10.2 From 630ec286dd85c5838493ab7ef975881c42069ef0 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 29 Jan 2015 12:17:13 -0800 Subject: intel_pstate: respect cpufreq policy request When thermal or other subsystem requests to change the policy, use that irrepective of whether cpufreq policy is PERFORMANCE or not. Without this change, when thermal subsystem passive policy wants to reduce performance, it still runs at 100%. Signed-off-by: Srinivas Pandruvada Signed-off-by: Kristen Carlson Accardi Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 80ecc35..dfee572 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -919,7 +919,8 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) if (!policy->cpuinfo.max_freq) return -ENODEV; - if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) { + if (policy->policy == CPUFREQ_POLICY_PERFORMANCE && + policy->max >= policy->cpuinfo.max_freq) { limits.min_perf_pct = 100; limits.min_perf = int_tofp(1); limits.max_policy_pct = 100; -- cgit v0.10.2 From a04759924e2528c5cc2af49b183c5638fe8d9bed Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Thu, 29 Jan 2015 13:03:52 -0800 Subject: intel_pstate: honor user space min_perf_pct override on resume If the user has requested an override of the min_perf_pct via sysfs, then it should be restored whenever policy is updated, such as on resume. Take the max of whatever the user requested and whatever the policy is. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index dfee572..e7e808d 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -148,6 +148,8 @@ struct perf_limits { int32_t min_perf; int max_policy_pct; int max_sysfs_pct; + int min_policy_pct; + int min_sysfs_pct; }; static struct perf_limits limits = { @@ -159,6 +161,8 @@ static struct perf_limits limits = { .min_perf = 0, .max_policy_pct = 100, .max_sysfs_pct = 100, + .min_policy_pct = 0, + .min_sysfs_pct = 0, }; static inline void pid_reset(struct _pid *pid, int setpoint, int busy, @@ -431,7 +435,9 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b, ret = sscanf(buf, "%u", &input); if (ret != 1) return -EINVAL; - limits.min_perf_pct = clamp_t(int, input, 0 , 100); + + limits.min_sysfs_pct = clamp_t(int, input, 0 , 100); + limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct); limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100)); if (hwp_active) @@ -921,6 +927,7 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) if (policy->policy == CPUFREQ_POLICY_PERFORMANCE && policy->max >= policy->cpuinfo.max_freq) { + limits.min_policy_pct = 100; limits.min_perf_pct = 100; limits.min_perf = int_tofp(1); limits.max_policy_pct = 100; @@ -930,8 +937,9 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) return 0; } - limits.min_perf_pct = (policy->min * 100) / policy->cpuinfo.max_freq; - limits.min_perf_pct = clamp_t(int, limits.min_perf_pct, 0 , 100); + limits.min_policy_pct = (policy->min * 100) / policy->cpuinfo.max_freq; + limits.min_policy_pct = clamp_t(int, limits.min_policy_pct, 0 , 100); + limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct); limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100)); limits.max_policy_pct = (policy->max * 100) / policy->cpuinfo.max_freq; -- cgit v0.10.2 From c9257f78b4f785d200737d60453fff51b57a2356 Mon Sep 17 00:00:00 2001 From: Todd E Brandt Date: Fri, 12 Dec 2014 20:06:46 -0800 Subject: PM / sleep: export suspend_resume trace event Export the suspend_resume tracepoint so it can be used in loadable modules. Signed-off-by: Todd Brandt Signed-off-by: Rafael J. Wysocki diff --git a/kernel/trace/power-traces.c b/kernel/trace/power-traces.c index 1c71382..eb4220a 100644 --- a/kernel/trace/power-traces.c +++ b/kernel/trace/power-traces.c @@ -13,5 +13,6 @@ #define CREATE_TRACE_POINTS #include +EXPORT_TRACEPOINT_SYMBOL_GPL(suspend_resume); EXPORT_TRACEPOINT_SYMBOL_GPL(cpu_idle); -- cgit v0.10.2 From f262f28c147051e7aa6daaf4fb5996833ffadff4 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 26 Jan 2015 13:16:27 +0900 Subject: PM / devfreq: event: Add devfreq_event class This patch adds a new class in devfreq, devfreq_event, which provides raw data (e.g., memory bus utilization, GPU utilization) for devfreq governors. - devfreq_event device : Provides raw data for a governor of a devfreq device - devfreq device : Monitors device state and changes frequency/voltage of the device using the raw data from its devfreq_event device. A devfreq device dertermines performance states (normally the frequency and the voltage vlues) based on the results its designtated devfreq governor: e.g., ondemand, performance, powersave. In order to give such results required by a devfreq device, the devfreq governor requires data that indicates the performance requirement given to the devfreq device. The conventional (previous) implementatino of devfreq subsystem requires a devfreq device driver to implement its own mechanism to acquire performance requirement for its governor. However, there had been issues with such requirements: 1. Although performance requirement of such devices is usually acquired from common devices (PMU/PPMU), we do not have any abstract structure to represent them properly. 2. Such performance requirement devices (PMU/PPMU) are actual hardware pieces that may be represented by Device Tree directly while devfreq device itself is a virtual entity that are not considered to be represented by Device Tree according to Device Tree folks. In order to address such issues, a devferq_event device (represented by this patch) provides a template for device drivers representing performance monitoring unit, which gives the basic or raw data for preformance requirement, which in turn, is required by devfreq governors. The following description explains the feature of two kind of devfreq class: - devfreq class (existing) : devfreq consumer device use raw data from devfreq_event device for determining proper current system state and change voltage/frequency dynamically using various governors. - devfreq_event class (new) : Provide measured raw data to devfreq device for governor Cc: MyungJoo Ham Cc: Kyungmin Park Signed-off-by: Chanwoo Choi [Commit message rewritten & conflict resolved by MyungJoo] Signed-off-by: MyungJoo Ham diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index 4aab799..51dccb3 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -97,4 +97,6 @@ config ARM_TEGRA_DEVFREQ It reads ACTMON counters of memory controllers and adjusts the operating frequencies and voltages with OPP support. +source "drivers/devfreq/event/Kconfig" + endif # PM_DEVFREQ diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 0ea991f..9256c35 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -8,3 +8,6 @@ obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos/ obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos/ obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o + +# DEVFREQ Event Drivers +obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/ diff --git a/drivers/devfreq/devfreq-event.c b/drivers/devfreq/devfreq-event.c new file mode 100644 index 0000000..f304a02 --- /dev/null +++ b/drivers/devfreq/devfreq-event.c @@ -0,0 +1,494 @@ +/* + * devfreq-event: a framework to provide raw data and events of devfreq devices + * + * Copyright (C) 2015 Samsung Electronics + * Author: Chanwoo Choi + * + * 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 driver is based on drivers/devfreq/devfreq.c. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct class *devfreq_event_class; + +/* The list of all devfreq event list */ +static LIST_HEAD(devfreq_event_list); +static DEFINE_MUTEX(devfreq_event_list_lock); + +#define to_devfreq_event(DEV) container_of(DEV, struct devfreq_event_dev, dev) + +/** + * devfreq_event_enable_edev() - Enable the devfreq-event dev and increase + * the enable_count of devfreq-event dev. + * @edev : the devfreq-event device + * + * Note that this function increase the enable_count and enable the + * devfreq-event device. The devfreq-event device should be enabled before + * using it by devfreq device. + */ +int devfreq_event_enable_edev(struct devfreq_event_dev *edev) +{ + int ret = 0; + + if (!edev || !edev->desc) + return -EINVAL; + + mutex_lock(&edev->lock); + if (edev->desc->ops && edev->desc->ops->enable + && edev->enable_count == 0) { + ret = edev->desc->ops->enable(edev); + if (ret < 0) + goto err; + } + edev->enable_count++; +err: + mutex_unlock(&edev->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(devfreq_event_enable_edev); + +/** + * devfreq_event_disable_edev() - Disable the devfreq-event dev and decrease + * the enable_count of the devfreq-event dev. + * @edev : the devfreq-event device + * + * Note that this function decrease the enable_count and disable the + * devfreq-event device. After the devfreq-event device is disabled, + * devfreq device can't use the devfreq-event device for get/set/reset + * operations. + */ +int devfreq_event_disable_edev(struct devfreq_event_dev *edev) +{ + int ret = 0; + + if (!edev || !edev->desc) + return -EINVAL; + + mutex_lock(&edev->lock); + if (edev->enable_count <= 0) { + dev_warn(&edev->dev, "unbalanced enable_count\n"); + ret = -EIO; + goto err; + } + + if (edev->desc->ops && edev->desc->ops->disable + && edev->enable_count == 1) { + ret = edev->desc->ops->disable(edev); + if (ret < 0) + goto err; + } + edev->enable_count--; +err: + mutex_unlock(&edev->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(devfreq_event_disable_edev); + +/** + * devfreq_event_is_enabled() - Check whether devfreq-event dev is enabled or + * not. + * @edev : the devfreq-event device + * + * Note that this function check whether devfreq-event dev is enabled or not. + * If return true, the devfreq-event dev is enabeld. If return false, the + * devfreq-event dev is disabled. + */ +bool devfreq_event_is_enabled(struct devfreq_event_dev *edev) +{ + bool enabled = false; + + if (!edev || !edev->desc) + return enabled; + + mutex_lock(&edev->lock); + + if (edev->enable_count > 0) + enabled = true; + + mutex_unlock(&edev->lock); + + return enabled; +} +EXPORT_SYMBOL_GPL(devfreq_event_is_enabled); + +/** + * devfreq_event_set_event() - Set event to devfreq-event dev to start. + * @edev : the devfreq-event device + * + * Note that this function set the event to the devfreq-event device to start + * for getting the event data which could be various event type. + */ +int devfreq_event_set_event(struct devfreq_event_dev *edev) +{ + int ret; + + if (!edev || !edev->desc) + return -EINVAL; + + if (!edev->desc->ops || !edev->desc->ops->set_event) + return -EINVAL; + + if (!devfreq_event_is_enabled(edev)) + return -EPERM; + + mutex_lock(&edev->lock); + ret = edev->desc->ops->set_event(edev); + mutex_unlock(&edev->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(devfreq_event_set_event); + +/** + * devfreq_event_get_event() - Get {load|total}_count from devfreq-event dev. + * @edev : the devfreq-event device + * @edata : the calculated data of devfreq-event device + * + * Note that this function get the calculated event data from devfreq-event dev + * after stoping the progress of whole sequence of devfreq-event dev. + */ +int devfreq_event_get_event(struct devfreq_event_dev *edev, + struct devfreq_event_data *edata) +{ + int ret; + + if (!edev || !edev->desc) + return -EINVAL; + + if (!edev->desc->ops || !edev->desc->ops->get_event) + return -EINVAL; + + if (!devfreq_event_is_enabled(edev)) + return -EINVAL; + + edata->total_count = edata->load_count = 0; + + mutex_lock(&edev->lock); + ret = edev->desc->ops->get_event(edev, edata); + if (ret < 0) + edata->total_count = edata->load_count = 0; + mutex_unlock(&edev->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(devfreq_event_get_event); + +/** + * devfreq_event_reset_event() - Reset all opeations of devfreq-event dev. + * @edev : the devfreq-event device + * + * Note that this function stop all operations of devfreq-event dev and reset + * the current event data to make the devfreq-event device into initial state. + */ +int devfreq_event_reset_event(struct devfreq_event_dev *edev) +{ + int ret = 0; + + if (!edev || !edev->desc) + return -EINVAL; + + if (!devfreq_event_is_enabled(edev)) + return -EPERM; + + mutex_lock(&edev->lock); + if (edev->desc->ops && edev->desc->ops->reset) + ret = edev->desc->ops->reset(edev); + mutex_unlock(&edev->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(devfreq_event_reset_event); + +/** + * devfreq_event_get_edev_by_phandle() - Get the devfreq-event dev from + * devicetree. + * @dev : the pointer to the given device + * @index : the index into list of devfreq-event device + * + * Note that this function return the pointer of devfreq-event device. + */ +struct devfreq_event_dev *devfreq_event_get_edev_by_phandle(struct device *dev, + int index) +{ + struct device_node *node; + struct devfreq_event_dev *edev; + + if (!dev->of_node) { + dev_err(dev, "device does not have a device node entry\n"); + return ERR_PTR(-EINVAL); + } + + node = of_parse_phandle(dev->of_node, "devfreq-events", index); + if (!node) { + dev_err(dev, "failed to get phandle in %s node\n", + dev->of_node->full_name); + return ERR_PTR(-ENODEV); + } + + mutex_lock(&devfreq_event_list_lock); + list_for_each_entry(edev, &devfreq_event_list, node) { + if (!strcmp(edev->desc->name, node->name)) + goto out; + } + edev = NULL; +out: + mutex_unlock(&devfreq_event_list_lock); + + if (!edev) { + dev_err(dev, "unable to get devfreq-event device : %s\n", + node->name); + of_node_put(node); + return ERR_PTR(-ENODEV); + } + + of_node_put(node); + + return edev; +} +EXPORT_SYMBOL_GPL(devfreq_event_get_edev_by_phandle); + +/** + * devfreq_event_get_edev_count() - Get the count of devfreq-event dev + * @dev : the pointer to the given device + * + * Note that this function return the count of devfreq-event devices. + */ +int devfreq_event_get_edev_count(struct device *dev) +{ + int count; + + if (!dev->of_node) { + dev_err(dev, "device does not have a device node entry\n"); + return -EINVAL; + } + + count = of_property_count_elems_of_size(dev->of_node, "devfreq-events", + sizeof(u32)); + if (count < 0 ) { + dev_err(dev, + "failed to get the count of devfreq-event in %s node\n", + dev->of_node->full_name); + return count; + } + + return count; +} +EXPORT_SYMBOL_GPL(devfreq_event_get_edev_count); + +static void devfreq_event_release_edev(struct device *dev) +{ + struct devfreq_event_dev *edev = to_devfreq_event(dev); + + kfree(edev); +} + +/** + * devfreq_event_add_edev() - Add new devfreq-event device. + * @dev : the device owning the devfreq-event device being created + * @desc : the devfreq-event device's decriptor which include essential + * data for devfreq-event device. + * + * Note that this function add new devfreq-event device to devfreq-event class + * list and register the device of the devfreq-event device. + */ +struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev, + struct devfreq_event_desc *desc) +{ + struct devfreq_event_dev *edev; + static atomic_t event_no = ATOMIC_INIT(0); + int ret; + + if (!dev || !desc) + return ERR_PTR(-EINVAL); + + if (!desc->name || !desc->ops) + return ERR_PTR(-EINVAL); + + if (!desc->ops->set_event || !desc->ops->get_event) + return ERR_PTR(-EINVAL); + + edev = kzalloc(sizeof(struct devfreq_event_dev), GFP_KERNEL); + if (!edev) + return ERR_PTR(-ENOMEM); + + mutex_init(&edev->lock); + edev->desc = desc; + edev->enable_count = 0; + edev->dev.parent = dev; + edev->dev.class = devfreq_event_class; + edev->dev.release = devfreq_event_release_edev; + + dev_set_name(&edev->dev, "event.%d", atomic_inc_return(&event_no) - 1); + ret = device_register(&edev->dev); + if (ret < 0) { + put_device(&edev->dev); + return ERR_PTR(ret); + } + dev_set_drvdata(&edev->dev, edev); + + INIT_LIST_HEAD(&edev->node); + + mutex_lock(&devfreq_event_list_lock); + list_add(&edev->node, &devfreq_event_list); + mutex_unlock(&devfreq_event_list_lock); + + return edev; +} +EXPORT_SYMBOL_GPL(devfreq_event_add_edev); + +/** + * devfreq_event_remove_edev() - Remove the devfreq-event device registered. + * @dev : the devfreq-event device + * + * Note that this function remove the registered devfreq-event device. + */ +int devfreq_event_remove_edev(struct devfreq_event_dev *edev) +{ + if (!edev) + return -EINVAL; + + WARN_ON(edev->enable_count); + + mutex_lock(&devfreq_event_list_lock); + list_del(&edev->node); + mutex_unlock(&devfreq_event_list_lock); + + device_unregister(&edev->dev); + + return 0; +} +EXPORT_SYMBOL_GPL(devfreq_event_remove_edev); + +static int devm_devfreq_event_match(struct device *dev, void *res, void *data) +{ + struct devfreq_event_dev **r = res; + + if (WARN_ON(!r || !*r)) + return 0; + + return *r == data; +} + +static void devm_devfreq_event_release(struct device *dev, void *res) +{ + devfreq_event_remove_edev(*(struct devfreq_event_dev **)res); +} + +/** + * devm_devfreq_event_add_edev() - Resource-managed devfreq_event_add_edev() + * @dev : the device owning the devfreq-event device being created + * @desc : the devfreq-event device's decriptor which include essential + * data for devfreq-event device. + * + * Note that this function manages automatically the memory of devfreq-event + * device using device resource management and simplify the free operation + * for memory of devfreq-event device. + */ +struct devfreq_event_dev *devm_devfreq_event_add_edev(struct device *dev, + struct devfreq_event_desc *desc) +{ + struct devfreq_event_dev **ptr, *edev; + + ptr = devres_alloc(devm_devfreq_event_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + edev = devfreq_event_add_edev(dev, desc); + if (IS_ERR(edev)) { + devres_free(ptr); + return ERR_PTR(-ENOMEM); + } + + *ptr = edev; + devres_add(dev, ptr); + + return edev; +} +EXPORT_SYMBOL_GPL(devm_devfreq_event_add_edev); + +/** + * devm_devfreq_event_remove_edev()- Resource-managed devfreq_event_remove_edev() + * @dev : the device owning the devfreq-event device being created + * @edev : the devfreq-event device + * + * Note that this function manages automatically the memory of devfreq-event + * device using device resource management. + */ +void devm_devfreq_event_remove_edev(struct device *dev, + struct devfreq_event_dev *edev) +{ + WARN_ON(devres_release(dev, devm_devfreq_event_release, + devm_devfreq_event_match, edev)); +} +EXPORT_SYMBOL_GPL(devm_devfreq_event_remove_edev); + +/* + * Device attributes for devfreq-event class. + */ +static ssize_t name_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct devfreq_event_dev *edev = to_devfreq_event(dev); + + if (!edev || !edev->desc) + return -EINVAL; + + return sprintf(buf, "%s\n", edev->desc->name); +} +static DEVICE_ATTR_RO(name); + +static ssize_t enable_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct devfreq_event_dev *edev = to_devfreq_event(dev); + + if (!edev || !edev->desc) + return -EINVAL; + + return sprintf(buf, "%d\n", edev->enable_count); +} +static DEVICE_ATTR_RO(enable_count); + +static struct attribute *devfreq_event_attrs[] = { + &dev_attr_name.attr, + &dev_attr_enable_count.attr, + NULL, +}; +ATTRIBUTE_GROUPS(devfreq_event); + +static int __init devfreq_event_init(void) +{ + devfreq_event_class = class_create(THIS_MODULE, "devfreq-event"); + if (IS_ERR(devfreq_event_class)) { + pr_err("%s: couldn't create class\n", __FILE__); + return PTR_ERR(devfreq_event_class); + } + + devfreq_event_class->dev_groups = devfreq_event_groups; + + return 0; +} +subsys_initcall(devfreq_event_init); + +static void __exit devfreq_event_exit(void) +{ + class_destroy(devfreq_event_class); +} +module_exit(devfreq_event_exit); + +MODULE_AUTHOR("Chanwoo Choi "); +MODULE_DESCRIPTION("DEVFREQ-Event class support"); +MODULE_LICENSE("GPL"); diff --git a/drivers/devfreq/event/Kconfig b/drivers/devfreq/event/Kconfig new file mode 100644 index 0000000..a11720a --- /dev/null +++ b/drivers/devfreq/event/Kconfig @@ -0,0 +1,25 @@ +menuconfig PM_DEVFREQ_EVENT + bool "DEVFREQ-Event device Support" + help + The devfreq-event device provide the raw data and events which + indicate the current state of devfreq-event device. The provided + data from devfreq-event device is used to monitor the state of + device and determine the suitable size of resource to reduce the + wasted resource. + + The devfreq-event device can support the various type of events + (e.g., raw data, utilization, latency, bandwidth). The events + may be used by devfreq governor and other subsystem. + +if PM_DEVFREQ_EVENT + +config DEVFREQ_EVENT_EXYNOS_PPMU + bool "EXYNOS PPMU (Platform Performance Monitoring Unit) DEVFREQ event Driver" + depends on ARCH_EXYNOS + select PM_OPP + help + This add the devfreq-event driver for Exynos SoC. It provides PPMU + (Platform Performance Monitoring Unit) counters to estimate the + utilization of each module. + +endif # PM_DEVFREQ_EVENT diff --git a/drivers/devfreq/event/Makefile b/drivers/devfreq/event/Makefile new file mode 100644 index 0000000..be146ea --- /dev/null +++ b/drivers/devfreq/event/Makefile @@ -0,0 +1,2 @@ +# Exynos DEVFREQ Event Drivers +obj-$(CONFIG_DEVFREQ_EVENT_EXYNOS_PPMU) += exynos-ppmu.o diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c new file mode 100644 index 0000000..135be0a --- /dev/null +++ b/drivers/devfreq/event/exynos-ppmu.c @@ -0,0 +1,374 @@ +/* + * exynos_ppmu.c - EXYNOS PPMU (Platform Performance Monitoring Unit) support + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Author : Chanwoo Choi + * + * 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 driver is based on drivers/devfreq/exynos/exynos_ppmu.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "exynos-ppmu.h" + +struct exynos_ppmu_data { + void __iomem *base; + struct clk *clk; +}; + +struct exynos_ppmu { + struct devfreq_event_dev **edev; + struct devfreq_event_desc *desc; + unsigned int num_events; + + struct device *dev; + struct mutex lock; + + struct exynos_ppmu_data ppmu; +}; + +#define PPMU_EVENT(name) \ + { "ppmu-event0-"#name, PPMU_PMNCNT0 }, \ + { "ppmu-event1-"#name, PPMU_PMNCNT1 }, \ + { "ppmu-event2-"#name, PPMU_PMNCNT2 }, \ + { "ppmu-event3-"#name, PPMU_PMNCNT3 } + +struct __exynos_ppmu_events { + char *name; + int id; +} ppmu_events[] = { + /* For Exynos3250, Exynos4 and Exynos5260 */ + PPMU_EVENT(g3d), + PPMU_EVENT(fsys), + + /* For Exynos4 SoCs and Exynos3250 */ + PPMU_EVENT(dmc0), + PPMU_EVENT(dmc1), + PPMU_EVENT(cpu), + PPMU_EVENT(rightbus), + PPMU_EVENT(leftbus), + PPMU_EVENT(lcd0), + PPMU_EVENT(camif), + + /* Only for Exynos3250 and Exynos5260 */ + PPMU_EVENT(mfc), + + /* Only for Exynos4 SoCs */ + PPMU_EVENT(mfc-left), + PPMU_EVENT(mfc-right), + + /* Only for Exynos5260 SoCs */ + PPMU_EVENT(drex0-s0), + PPMU_EVENT(drex0-s1), + PPMU_EVENT(drex1-s0), + PPMU_EVENT(drex1-s1), + PPMU_EVENT(eagle), + PPMU_EVENT(kfc), + PPMU_EVENT(isp), + PPMU_EVENT(fimc), + PPMU_EVENT(gscl), + PPMU_EVENT(mscl), + PPMU_EVENT(fimd0x), + PPMU_EVENT(fimd1x), + { /* sentinel */ }, +}; + +static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ppmu_events); i++) + if (!strcmp(edev->desc->name, ppmu_events[i].name)) + return ppmu_events[i].id; + + return -EINVAL; +} + +static int exynos_ppmu_disable(struct devfreq_event_dev *edev) +{ + struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); + u32 pmnc; + + /* Disable all counters */ + __raw_writel(PPMU_CCNT_MASK | + PPMU_PMCNT0_MASK | + PPMU_PMCNT1_MASK | + PPMU_PMCNT2_MASK | + PPMU_PMCNT3_MASK, + info->ppmu.base + PPMU_CNTENC); + + /* Disable PPMU */ + pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); + pmnc &= ~PPMU_PMNC_ENABLE_MASK; + __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); + + return 0; +} + +static int exynos_ppmu_set_event(struct devfreq_event_dev *edev) +{ + struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); + int id = exynos_ppmu_find_ppmu_id(edev); + u32 pmnc, cntens; + + if (id < 0) + return id; + + /* Enable specific counter */ + cntens = __raw_readl(info->ppmu.base + PPMU_CNTENS); + cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); + __raw_writel(cntens, info->ppmu.base + PPMU_CNTENS); + + /* Set the event of Read/Write data count */ + __raw_writel(PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT, + info->ppmu.base + PPMU_BEVTxSEL(id)); + + /* Reset cycle counter/performance counter and enable PPMU */ + pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); + pmnc &= ~(PPMU_PMNC_ENABLE_MASK + | PPMU_PMNC_COUNTER_RESET_MASK + | PPMU_PMNC_CC_RESET_MASK); + pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT); + pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT); + pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT); + __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); + + return 0; +} + +static int exynos_ppmu_get_event(struct devfreq_event_dev *edev, + struct devfreq_event_data *edata) +{ + struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); + int id = exynos_ppmu_find_ppmu_id(edev); + u32 pmnc, cntenc; + + if (id < 0) + return -EINVAL; + + /* Disable PPMU */ + pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); + pmnc &= ~PPMU_PMNC_ENABLE_MASK; + __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); + + /* Read cycle count */ + edata->total_count = __raw_readl(info->ppmu.base + PPMU_CCNT); + + /* Read performance count */ + switch (id) { + case PPMU_PMNCNT0: + case PPMU_PMNCNT1: + case PPMU_PMNCNT2: + edata->load_count + = __raw_readl(info->ppmu.base + PPMU_PMNCT(id)); + break; + case PPMU_PMNCNT3: + edata->load_count = + ((__raw_readl(info->ppmu.base + PPMU_PMCNT3_HIGH) << 8) + | __raw_readl(info->ppmu.base + PPMU_PMCNT3_LOW)); + break; + default: + return -EINVAL; + } + + /* Disable specific counter */ + cntenc = __raw_readl(info->ppmu.base + PPMU_CNTENC); + cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); + __raw_writel(cntenc, info->ppmu.base + PPMU_CNTENC); + + dev_dbg(&edev->dev, "%s (event: %ld/%ld)\n", edev->desc->name, + edata->load_count, edata->total_count); + + return 0; +} + +static struct devfreq_event_ops exynos_ppmu_ops = { + .disable = exynos_ppmu_disable, + .set_event = exynos_ppmu_set_event, + .get_event = exynos_ppmu_get_event, +}; + +static int of_get_devfreq_events(struct device_node *np, + struct exynos_ppmu *info) +{ + struct devfreq_event_desc *desc; + struct device *dev = info->dev; + struct device_node *events_np, *node; + int i, j, count; + + events_np = of_get_child_by_name(np, "events"); + if (!events_np) { + dev_err(dev, + "failed to get child node of devfreq-event devices\n"); + return -EINVAL; + } + + count = of_get_child_count(events_np); + desc = devm_kzalloc(dev, sizeof(*desc) * count, GFP_KERNEL); + if (!desc) + return -ENOMEM; + info->num_events = count; + + j = 0; + for_each_child_of_node(events_np, node) { + for (i = 0; i < ARRAY_SIZE(ppmu_events); i++) { + if (!ppmu_events[i].name) + continue; + + if (!of_node_cmp(node->name, ppmu_events[i].name)) + break; + } + + if (i == ARRAY_SIZE(ppmu_events)) { + dev_warn(dev, + "don't know how to configure events : %s\n", + node->name); + continue; + } + + desc[j].ops = &exynos_ppmu_ops; + desc[j].driver_data = info; + + of_property_read_string(node, "event-name", &desc[j].name); + + j++; + + of_node_put(node); + } + info->desc = desc; + + of_node_put(events_np); + + return 0; +} + +static int exynos_ppmu_parse_dt(struct exynos_ppmu *info) +{ + struct device *dev = info->dev; + struct device_node *np = dev->of_node; + int ret = 0; + + if (!np) { + dev_err(dev, "failed to find devicetree node\n"); + return -EINVAL; + } + + /* Maps the memory mapped IO to control PPMU register */ + info->ppmu.base = of_iomap(np, 0); + if (IS_ERR_OR_NULL(info->ppmu.base)) { + dev_err(dev, "failed to map memory region\n"); + return -ENOMEM; + } + + info->ppmu.clk = devm_clk_get(dev, "ppmu"); + if (IS_ERR(info->ppmu.clk)) { + info->ppmu.clk = NULL; + dev_warn(dev, "cannot get PPMU clock\n"); + } + + ret = of_get_devfreq_events(np, info); + if (ret < 0) { + dev_err(dev, "failed to parse exynos ppmu dt node\n"); + goto err; + } + + return 0; + +err: + iounmap(info->ppmu.base); + + return ret; +} + +static int exynos_ppmu_probe(struct platform_device *pdev) +{ + struct exynos_ppmu *info; + struct devfreq_event_dev **edev; + struct devfreq_event_desc *desc; + int i, ret = 0, size; + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + mutex_init(&info->lock); + info->dev = &pdev->dev; + + /* Parse dt data to get resource */ + ret = exynos_ppmu_parse_dt(info); + if (ret < 0) { + dev_err(&pdev->dev, + "failed to parse devicetree for resource\n"); + return ret; + } + desc = info->desc; + + size = sizeof(struct devfreq_event_dev *) * info->num_events; + info->edev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + if (!info->edev) { + dev_err(&pdev->dev, + "failed to allocate memory devfreq-event devices\n"); + return -ENOMEM; + } + edev = info->edev; + platform_set_drvdata(pdev, info); + + for (i = 0; i < info->num_events; i++) { + edev[i] = devm_devfreq_event_add_edev(&pdev->dev, &desc[i]); + if (IS_ERR(edev)) { + ret = PTR_ERR(edev); + dev_err(&pdev->dev, + "failed to add devfreq-event device\n"); + goto err; + } + } + + clk_prepare_enable(info->ppmu.clk); + + return 0; +err: + iounmap(info->ppmu.base); + + return ret; +} + +static int exynos_ppmu_remove(struct platform_device *pdev) +{ + struct exynos_ppmu *info = platform_get_drvdata(pdev); + + clk_disable_unprepare(info->ppmu.clk); + iounmap(info->ppmu.base); + + return 0; +} + +static struct of_device_id exynos_ppmu_id_match[] = { + { .compatible = "samsung,exynos-ppmu", }, + { /* sentinel */ }, +}; + +static struct platform_driver exynos_ppmu_driver = { + .probe = exynos_ppmu_probe, + .remove = exynos_ppmu_remove, + .driver = { + .name = "exynos-ppmu", + .of_match_table = exynos_ppmu_id_match, + }, +}; +module_platform_driver(exynos_ppmu_driver); + +MODULE_DESCRIPTION("Exynos PPMU(Platform Performance Monitoring Unit) driver"); +MODULE_AUTHOR("Chanwoo Choi "); +MODULE_LICENSE("GPL"); diff --git a/drivers/devfreq/event/exynos-ppmu.h b/drivers/devfreq/event/exynos-ppmu.h new file mode 100644 index 0000000..4e831d4 --- /dev/null +++ b/drivers/devfreq/event/exynos-ppmu.h @@ -0,0 +1,93 @@ +/* + * exynos_ppmu.h - EXYNOS PPMU header file + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Author : Chanwoo Choi + * + * 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. + */ + +#ifndef __EXYNOS_PPMU_H__ +#define __EXYNOS_PPMU_H__ + +enum ppmu_state { + PPMU_DISABLE = 0, + PPMU_ENABLE, +}; + +enum ppmu_counter { + PPMU_PMNCNT0 = 0, + PPMU_PMNCNT1, + PPMU_PMNCNT2, + PPMU_PMNCNT3, + + PPMU_PMNCNT_MAX, +}; + +enum ppmu_event_type { + PPMU_RO_BUSY_CYCLE_CNT = 0x0, + PPMU_WO_BUSY_CYCLE_CNT = 0x1, + PPMU_RW_BUSY_CYCLE_CNT = 0x2, + PPMU_RO_REQUEST_CNT = 0x3, + PPMU_WO_REQUEST_CNT = 0x4, + PPMU_RO_DATA_CNT = 0x5, + PPMU_WO_DATA_CNT = 0x6, + PPMU_RO_LATENCY = 0x12, + PPMU_WO_LATENCY = 0x16, +}; + +enum ppmu_reg { + /* PPC control register */ + PPMU_PMNC = 0x00, + PPMU_CNTENS = 0x10, + PPMU_CNTENC = 0x20, + PPMU_INTENS = 0x30, + PPMU_INTENC = 0x40, + PPMU_FLAG = 0x50, + + /* Cycle Counter and Performance Event Counter Register */ + PPMU_CCNT = 0x100, + PPMU_PMCNT0 = 0x110, + PPMU_PMCNT1 = 0x120, + PPMU_PMCNT2 = 0x130, + PPMU_PMCNT3_HIGH = 0x140, + PPMU_PMCNT3_LOW = 0x150, + + /* Bus Event Generator */ + PPMU_BEVT0SEL = 0x1000, + PPMU_BEVT1SEL = 0x1100, + PPMU_BEVT2SEL = 0x1200, + PPMU_BEVT3SEL = 0x1300, + PPMU_COUNTER_RESET = 0x1810, + PPMU_READ_OVERFLOW_CNT = 0x1810, + PPMU_READ_UNDERFLOW_CNT = 0x1814, + PPMU_WRITE_OVERFLOW_CNT = 0x1850, + PPMU_WRITE_UNDERFLOW_CNT = 0x1854, + PPMU_READ_PENDING_CNT = 0x1880, + PPMU_WRITE_PENDING_CNT = 0x1884 +}; + +/* PMNC register */ +#define PPMU_PMNC_CC_RESET_SHIFT 2 +#define PPMU_PMNC_COUNTER_RESET_SHIFT 1 +#define PPMU_PMNC_ENABLE_SHIFT 0 +#define PPMU_PMNC_START_MODE_MASK BIT(16) +#define PPMU_PMNC_CC_DIVIDER_MASK BIT(3) +#define PPMU_PMNC_CC_RESET_MASK BIT(2) +#define PPMU_PMNC_COUNTER_RESET_MASK BIT(1) +#define PPMU_PMNC_ENABLE_MASK BIT(0) + +/* CNTENS/CNTENC/INTENS/INTENC/FLAG register */ +#define PPMU_CCNT_MASK BIT(31) +#define PPMU_PMCNT3_MASK BIT(3) +#define PPMU_PMCNT2_MASK BIT(2) +#define PPMU_PMCNT1_MASK BIT(1) +#define PPMU_PMCNT0_MASK BIT(0) + +/* PPMU_PMNCTx/PPMU_BETxSEL registers */ +#define PPMU_PMNCT(x) (PPMU_PMCNT0 + (0x10 * x)) +#define PPMU_BEVTxSEL(x) (PPMU_BEVT0SEL + (0x100 * x)) + +#endif /* __EXYNOS_PPMU_H__ */ diff --git a/include/linux/devfreq-event.h b/include/linux/devfreq-event.h new file mode 100644 index 0000000..602fbbf --- /dev/null +++ b/include/linux/devfreq-event.h @@ -0,0 +1,196 @@ +/* + * devfreq-event: a framework to provide raw data and events of devfreq devices + * + * Copyright (C) 2014 Samsung Electronics + * Author: Chanwoo Choi + * + * 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. + */ + +#ifndef __LINUX_DEVFREQ_EVENT_H__ +#define __LINUX_DEVFREQ_EVENT_H__ + +#include + +/** + * struct devfreq_event_dev - the devfreq-event device + * + * @node : Contain the devfreq-event device that have been registered. + * @dev : the device registered by devfreq-event class. dev.parent is + * the device using devfreq-event. + * @lock : a mutex to protect accessing devfreq-event. + * @enable_count: the number of enable function have been called. + * @desc : the description for devfreq-event device. + * + * This structure contains devfreq-event device information. + */ +struct devfreq_event_dev { + struct list_head node; + + struct device dev; + struct mutex lock; + u32 enable_count; + + const struct devfreq_event_desc *desc; +}; + +/** + * struct devfreq_event_data - the devfreq-event data + * + * @load_count : load count of devfreq-event device for the given period. + * @total_count : total count of devfreq-event device for the given period. + * each count may represent a clock cycle, a time unit + * (ns/us/...), or anything the device driver wants. + * Generally, utilization is load_count / total_count. + * + * This structure contains the data of devfreq-event device for polling period. + */ +struct devfreq_event_data { + unsigned long load_count; + unsigned long total_count; +}; + +/** + * struct devfreq_event_ops - the operations of devfreq-event device + * + * @enable : Enable the devfreq-event device. + * @disable : Disable the devfreq-event device. + * @reset : Reset all setting of the devfreq-event device. + * @set_event : Set the specific event type for the devfreq-event device. + * @get_event : Get the result of the devfreq-event devie with specific + * event type. + * + * This structure contains devfreq-event device operations which can be + * implemented by devfreq-event device drivers. + */ +struct devfreq_event_ops { + /* Optional functions */ + int (*enable)(struct devfreq_event_dev *edev); + int (*disable)(struct devfreq_event_dev *edev); + int (*reset)(struct devfreq_event_dev *edev); + + /* Mandatory functions */ + int (*set_event)(struct devfreq_event_dev *edev); + int (*get_event)(struct devfreq_event_dev *edev, + struct devfreq_event_data *edata); +}; + +/** + * struct devfreq_event_desc - the descriptor of devfreq-event device + * + * @name : the name of devfreq-event device. + * @driver_data : the private data for devfreq-event driver. + * @ops : the operation to control devfreq-event device. + * + * Each devfreq-event device is described with a this structure. + * This structure contains the various data for devfreq-event device. + */ +struct devfreq_event_desc { + const char *name; + void *driver_data; + + struct devfreq_event_ops *ops; +}; + +#if defined(CONFIG_PM_DEVFREQ_EVENT) +extern int devfreq_event_enable_edev(struct devfreq_event_dev *edev); +extern int devfreq_event_disable_edev(struct devfreq_event_dev *edev); +extern bool devfreq_event_is_enabled(struct devfreq_event_dev *edev); +extern int devfreq_event_set_event(struct devfreq_event_dev *edev); +extern int devfreq_event_get_event(struct devfreq_event_dev *edev, + struct devfreq_event_data *edata); +extern int devfreq_event_reset_event(struct devfreq_event_dev *edev); +extern struct devfreq_event_dev *devfreq_event_get_edev_by_phandle( + struct device *dev, int index); +extern int devfreq_event_get_edev_count(struct device *dev); +extern struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev, + struct devfreq_event_desc *desc); +extern int devfreq_event_remove_edev(struct devfreq_event_dev *edev); +extern struct devfreq_event_dev *devm_devfreq_event_add_edev(struct device *dev, + struct devfreq_event_desc *desc); +extern void devm_devfreq_event_remove_edev(struct device *dev, + struct devfreq_event_dev *edev); +static inline void *devfreq_event_get_drvdata(struct devfreq_event_dev *edev) +{ + return edev->desc->driver_data; +} +#else +static inline int devfreq_event_enable_edev(struct devfreq_event_dev *edev) +{ + return -EINVAL; +} + +static inline int devfreq_event_disable_edev(struct devfreq_event_dev *edev) +{ + return -EINVAL; +} + +static inline bool devfreq_event_is_enabled(struct devfreq_event_dev *edev) +{ + return false; +} + +static inline int devfreq_event_set_event(struct devfreq_event_dev *edev) +{ + return -EINVAL; +} + +static inline int devfreq_event_get_event(struct devfreq_event_dev *edev, + struct devfreq_event_data *edata) +{ + return -EINVAL; +} + +static inline int devfreq_event_reset_event(struct devfreq_event_dev *edev) +{ + return -EINVAL; +} + +static inline void *devfreq_event_get_drvdata(struct devfreq_event_dev *edev) +{ + return ERR_PTR(-EINVAL); +} + +static inline struct devfreq_event_dev *devfreq_event_get_edev_by_phandle( + struct device *dev, int index) +{ + return ERR_PTR(-EINVAL); +} + +static inline int devfreq_event_get_edev_count(struct device *dev) +{ + return -EINVAL; +} + +static inline struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev, + struct devfreq_event_desc *desc) +{ + return ERR_PTR(-EINVAL); +} + +static inline int devfreq_event_remove_edev(struct devfreq_event_dev *edev) +{ + return -EINVAL; +} + +static inline struct devfreq_event_dev *devm_devfreq_event_add_edev( + struct device *dev, + struct devfreq_event_desc *desc) +{ + return ERR_PTR(-EINVAL); +} + +static inline void devm_devfreq_event_remove_edev(struct device *dev, + struct devfreq_event_dev *edev) +{ +} + +static inline void *devfreq_event_get_drvdata(struct devfreq_event_dev *edev) +{ + return NULL; +} +#endif /* CONFIG_PM_DEVFREQ_EVENT */ + +#endif /* __LINUX_DEVFREQ_EVENT_H__ */ -- cgit v0.10.2 From e6ee31924709bd7d3ac2f67a76e5393081554f6f Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 30 Jan 2015 13:54:08 +0900 Subject: devfreq: Fix build break of devfreq-event class This patch fixes the build break of the exynos-ppmu driver because Makefile in drivers/devfreq don't include the entry of devfreq-event.c driver. The original patch[1] includes the entry to build devfreq-event.c without the build break. This build break is generated in the process of merging the patch. [1] https://lkml.org/lkml/2015/1/25/579 - [PATCH v10 1/7] devfreq: event: Add new devfreq_event class to provide basic data for devfreq governor CC init/version.o LD init/built-in.o drivers/built-in.o: In function `exynos_ppmu_probe': binder.c:(.text+0x4447ec): undefined reference to `devm_devfreq_event_add_edev' make: *** [vmlinux] Error 1 Cc: Rafael J. Wysocki Cc: MyungJoo Ham Signed-off-by: Chanwoo Choi diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 9256c35..5134f9e 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_PM_DEVFREQ) += devfreq.o +obj-$(CONFIG_PM_DEVFREQ_EVENT) += devfreq-event.o obj-$(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) += governor_simpleondemand.o obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE) += governor_performance.o obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o -- cgit v0.10.2 From 6d96302ffc0ff9754cc1bc349206c8b5808f2e8a Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 26 Jan 2015 13:16:29 +0900 Subject: PM / devfreq: event: Add documentation for exynos-ppmu devfreq-event driver This patch adds the documentation for Exynos PPMU (Platform Performance Monitoring Unit) devfreq-event driver. Cc: MyungJoo Ham Cc: Kyungmin Park Signed-off-by: Chanwoo Choi Signed-off-by: MyungJoo Ham diff --git a/Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt b/Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt new file mode 100644 index 0000000..b54bf3a --- /dev/null +++ b/Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt @@ -0,0 +1,110 @@ + +* Samsung Exynos PPMU (Platform Performance Monitoring Unit) device + +The Samsung Exynos SoC has PPMU (Platform Performance Monitoring Unit) for +each IP. PPMU provides the primitive values to get performance data. These +PPMU events provide information of the SoC's behaviors so that you may +use to analyze system performance, to make behaviors visible and to count +usages of each IP (DMC, CPU, RIGHTBUS, LEFTBUS, CAM interface, LCD, G3D, MFC). +The Exynos PPMU driver uses the devfreq-event class to provide event data +to various devfreq devices. The devfreq devices would use the event data when +derterming the current state of each IP. + +Required properties: +- compatible: Should be "samsung,exynos-ppmu". +- reg: physical base address of each PPMU and length of memory mapped region. + +Optional properties: +- clock-names : the name of clock used by the PPMU, "ppmu" +- clocks : phandles for clock specified in "clock-names" property +- #clock-cells: should be 1. + +Example1 : PPMU nodes in exynos3250.dtsi are listed below. + + ppmu_dmc0: ppmu_dmc0@106a0000 { + compatible = "samsung,exynos-ppmu"; + reg = <0x106a0000 0x2000>; + status = "disabled"; + }; + + ppmu_dmc1: ppmu_dmc1@106b0000 { + compatible = "samsung,exynos-ppmu"; + reg = <0x106b0000 0x2000>; + status = "disabled"; + }; + + ppmu_cpu: ppmu_cpu@106c0000 { + compatible = "samsung,exynos-ppmu"; + reg = <0x106c0000 0x2000>; + status = "disabled"; + }; + + ppmu_rightbus: ppmu_rightbus@112a0000 { + compatible = "samsung,exynos-ppmu"; + reg = <0x112a0000 0x2000>; + clocks = <&cmu CLK_PPMURIGHT>; + clock-names = "ppmu"; + status = "disabled"; + }; + + ppmu_leftbus: ppmu_leftbus0@116a0000 { + compatible = "samsung,exynos-ppmu"; + reg = <0x116a0000 0x2000>; + clocks = <&cmu CLK_PPMULEFT>; + clock-names = "ppmu"; + status = "disabled"; + }; + +Example2 : Events of each PPMU node in exynos3250-rinato.dts are listed below. + + &ppmu_dmc0 { + status = "okay"; + + events { + ppmu_dmc0_3: ppmu-event3-dmc0 { + event-name = "ppmu-event3-dmc0"; + }; + + ppmu_dmc0_2: ppmu-event2-dmc0 { + event-name = "ppmu-event2-dmc0"; + }; + + ppmu_dmc0_1: ppmu-event1-dmc0 { + event-name = "ppmu-event1-dmc0"; + }; + + ppmu_dmc0_0: ppmu-event0-dmc0 { + event-name = "ppmu-event0-dmc0"; + }; + }; + }; + + &ppmu_dmc1 { + status = "okay"; + + events { + ppmu_dmc1_3: ppmu-event3-dmc1 { + event-name = "ppmu-event3-dmc1"; + }; + }; + }; + + &ppmu_leftbus { + status = "okay"; + + events { + ppmu_leftbus_3: ppmu-event3-leftbus { + event-name = "ppmu-event3-leftbus"; + }; + }; + }; + + &ppmu_rightbus { + status = "okay"; + + events { + ppmu_rightbus_3: ppmu-event3-rightbus { + event-name = "ppmu-event3-rightbus"; + }; + }; + }; -- cgit v0.10.2 From b00783fd90388d221dabd4df2affeea7da2363cd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 2 Feb 2015 23:55:08 +0100 Subject: ACPI / cpuidle: Drop unnecessary calls from acpi_idle_do_entry() Since the cpuidle core calls stop_critical_timings() and start_critical_timings() around the execution of ->enter callbacks, acpi_idle_do_entry() doesn't need to do that (and really shouldn't). Also using "inline" on it is pointless and the kerneldoc entry does not reflect the actual situation any more. Fix all of the above. Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 87b704e..f365171 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -681,15 +681,13 @@ static int acpi_idle_bm_check(void) } /** - * acpi_idle_do_entry - a helper function that does C2 and C3 type entry + * acpi_idle_do_entry - enter idle state using the appropriate method * @cx: cstate data * * Caller disables interrupt before call and enables interrupt after return. */ -static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) +static void acpi_idle_do_entry(struct acpi_processor_cx *cx) { - /* Don't trace irqs off for idle */ - stop_critical_timings(); if (cx->entry_method == ACPI_CSTATE_FFH) { /* Call into architectural FFH based C-state */ acpi_processor_ffh_cstate_enter(cx); @@ -703,7 +701,6 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) gets asserted in time to freeze execution properly. */ inl(acpi_gbl_FADT.xpm_timer_block.address); } - start_critical_timings(); } /** -- cgit v0.10.2 From 67f592c8f681061d69c621b97a868e679c8a77be Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 2 Feb 2015 23:55:17 +0100 Subject: ACPI / cpuidle: Drop unnecessary calls from ->enter callback routines acpi_idle_enter_simple() and acpi_idle_enter_bm() don't need to call sched_clock_idle_sleep/wakeup_event(), because that's taken care of by the core already. Namely, sched_clock_idle_sleep_event() is called by tick_nohz_start_idle() called by __tick_nohz_idle_enter() which in turn is called by tick_nohz_idle_enter() and that is called by cpu_idle_loop(). Analogously for sched_clock_idle_wakeup_event(). For this reason, drop those calls from the ACPI cpuidle driver's ->enter callback routines. Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index f365171..ceeff3d 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -791,12 +791,8 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, if (cx->type == ACPI_STATE_C3) ACPI_FLUSH_CPU_CACHE(); - /* Tell the scheduler that we are going deep-idle: */ - sched_clock_idle_sleep_event(); acpi_idle_do_entry(cx); - sched_clock_idle_wakeup_event(0); - lapic_timer_state_broadcast(pr, cx, 0); return index; } @@ -842,8 +838,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, acpi_unlazy_tlb(smp_processor_id()); - /* Tell the scheduler that we are going deep-idle: */ - sched_clock_idle_sleep_event(); /* * Must be done before busmaster disable as we might need to * access HPET ! @@ -881,8 +875,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, raw_spin_unlock(&c3_lock); } - sched_clock_idle_wakeup_event(0); - lapic_timer_state_broadcast(pr, cx, 0); return index; } -- cgit v0.10.2 From adcb2623f149abd4d4783ecada543a01e25d1c04 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 2 Feb 2015 23:55:42 +0100 Subject: ACPI / cpuidle: Clean up fallback to C1 checks acpi_idle_enter_simple() and acpi_idle_enter_bm() both check if C2/C3 type entry is supported on MP in the same way, so move those checks to a separate function and call it from both places (and it doesn't need to check if the state type is not C1, because the functions in question won't be called otherwise). While at it, use IS_ENABLED() for the CONFIG_HOTPLUG_CPU check. Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index ceeff3d..94c85ff 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -758,6 +758,13 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) return 0; } +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; +} + /** * acpi_idle_enter_simple - enters an ACPI state without BM handling * @dev: the target CPU @@ -775,12 +782,8 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, if (unlikely(!pr)) return -EINVAL; -#ifdef CONFIG_HOTPLUG_CPU - if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && - !pr->flags.has_cst && - !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) + if (acpi_idle_fallback_to_c1(pr)) return acpi_idle_enter_c1(dev, drv, CPUIDLE_DRIVER_STATE_START); -#endif /* * Must be done before busmaster disable as we might need to @@ -819,12 +822,8 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, if (unlikely(!pr)) return -EINVAL; -#ifdef CONFIG_HOTPLUG_CPU - if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && - !pr->flags.has_cst && - !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) + if (acpi_idle_fallback_to_c1(pr)) return acpi_idle_enter_c1(dev, drv, CPUIDLE_DRIVER_STATE_START); -#endif if (!cx->bm_sts_skip && acpi_idle_bm_check()) { if (drv->safe_state_index >= 0) { -- cgit v0.10.2 From de6cc4ec6ea05de1933dc3b832013960af49c852 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 2 Feb 2015 23:55:47 +0100 Subject: ACPI / cpuidle: Drop irrelevant comment from acpi_idle_enter_simple() The comment about bus master disable in acpi_idle_enter_simple() is irrelevant, because the function doesn't disable bus mastering, so drop it. Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 94c85ff..1798bbe 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -785,10 +785,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, if (acpi_idle_fallback_to_c1(pr)) return acpi_idle_enter_c1(dev, drv, CPUIDLE_DRIVER_STATE_START); - /* - * Must be done before busmaster disable as we might need to - * access HPET ! - */ lapic_timer_state_broadcast(pr, cx, 1); if (cx->type == ACPI_STATE_C3) -- cgit v0.10.2 From 5f97d6628640842229824c9f4fd433621c5a7b72 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 2 Feb 2015 23:55:55 +0100 Subject: ACPI / cpuidle: Clean up white space in a switch statement White space in the switch statement in acpi_processor_setup_cpuidle_states() does not adhere to the kernel coding style and that makes the code difficult to read. Clean that up. Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 1798bbe..c05d5ec 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -968,20 +968,20 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) state->flags = 0; switch (cx->type) { - case ACPI_STATE_C1: + case ACPI_STATE_C1: state->enter = acpi_idle_enter_c1; state->enter_dead = acpi_idle_play_dead; drv->safe_state_index = count; break; - case ACPI_STATE_C2: + case ACPI_STATE_C2: state->enter = acpi_idle_enter_simple; state->enter_dead = acpi_idle_play_dead; drv->safe_state_index = count; break; - case ACPI_STATE_C3: + case ACPI_STATE_C3: state->enter = pr->flags.bm_check ? acpi_idle_enter_bm : acpi_idle_enter_simple; -- cgit v0.10.2 From 2a7383529109252a7f9d81639784e5fddb4f3df4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 2 Feb 2015 23:56:03 +0100 Subject: ACPI / cpuidle: Drop flags.bm_check tests from acpi_idle_enter_bm() Since acpi_idle_enter_bm() is only used if flags.bm_check is set for the given acpi_processor object, it doesn't make sense to check that flag in there. For this reason, drop flags.bm_check tests (and some code depending on them) from acpi_idle_enter_bm(). Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index c05d5ec..eaa3258 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -842,28 +842,25 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, /* * disable bus master * bm_check implies we need ARB_DIS - * !bm_check implies we need cache flush * bm_control implies whether we can do ARB_DIS * * That leaves a case where bm_check is set and bm_control is * not set. In that case we cannot do much, we enter C3 * without doing anything. */ - if (pr->flags.bm_check && pr->flags.bm_control) { + if (pr->flags.bm_control) { raw_spin_lock(&c3_lock); c3_cpu_count++; /* Disable bus master arbitration when all CPUs are in C3 */ if (c3_cpu_count == num_online_cpus()) acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1); raw_spin_unlock(&c3_lock); - } else if (!pr->flags.bm_check) { - ACPI_FLUSH_CPU_CACHE(); } acpi_idle_do_entry(cx); /* Re-enable bus master arbitration */ - if (pr->flags.bm_check && pr->flags.bm_control) { + if (pr->flags.bm_control) { raw_spin_lock(&c3_lock); acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0); c3_cpu_count--; -- cgit v0.10.2 From 6ffae8c06fab058d6c3f8ecb7f921327721034e7 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 31 Jan 2015 06:02:44 +0530 Subject: cpufreq: Set cpufreq_cpu_data to NULL before putting kobject In __cpufreq_remove_dev_finish(), per-cpu 'cpufreq_cpu_data' needs to be cleared before calling kobject_put(&policy->kobj) and under cpufreq_driver_lock. Otherwise, if someone else calls cpufreq_cpu_get() in parallel with it, they can obtain a non-NULL policy from that after kobject_put(&policy->kobj) was executed. Consider this case: Thread A Thread B cpufreq_cpu_get() acquire cpufreq_driver_lock read-per-cpu cpufreq_cpu_data kobject_put(&policy->kobj); kobject_get(&policy->kobj); ... per_cpu(&cpufreq_cpu_data, cpu) = NULL And this will result in a warning like this one: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 4 at include/linux/kref.h:47 kobject_get+0x41/0x50() Modules linked in: acpi_cpufreq(+) nfsd auth_rpcgss nfs_acl lockd grace sunrpc xfs libcrc32c sd_mod ixgbe igb mdio ahci hwmon ... Call Trace: [] dump_stack+0x46/0x58 [] warn_slowpath_common+0x81/0xa0 [] warn_slowpath_null+0x1a/0x20 [] kobject_get+0x41/0x50 [] cpufreq_cpu_get+0x75/0xc0 [] cpufreq_update_policy+0x2e/0x1f0 [] ? up+0x32/0x50 [] ? acpi_ns_get_node+0xcb/0xf2 [] ? acpi_evaluate_object+0x22c/0x252 [] ? acpi_get_handle+0x95/0xc0 [] ? acpi_has_method+0x25/0x40 [] acpi_processor_ppc_has_changed+0x77/0x82 [] ? move_linked_works+0x66/0x90 [] acpi_processor_notify+0x58/0xe7 [] acpi_ev_notify_dispatch+0x44/0x5c [] acpi_os_execute_deferred+0x15/0x22 [] process_one_work+0x160/0x410 [] worker_thread+0x11b/0x520 [] ? rescuer_thread+0x380/0x380 [] kthread+0xe1/0x100 [] ? kthread_create_on_node+0x1b0/0x1b0 [] ret_from_fork+0x7c/0xb0 [] ? kthread_create_on_node+0x1b0/0x1b0 ---[ end trace 89e66eb9795efdf7 ]--- The actual code flow is as follows: Thread A: Workqueue: kacpi_notify acpi_processor_notify() acpi_processor_ppc_has_changed() cpufreq_update_policy() cpufreq_cpu_get() kobject_get() Thread B: xenbus_thread() xenbus_thread() msg->u.watch.handle->callback() handle_vcpu_hotplug_event() vcpu_hotplug() cpu_down() __cpu_notify(CPU_POST_DEAD..) cpufreq_cpu_callback() __cpufreq_remove_dev_finish() cpufreq_policy_put_kobj() kobject_put() cpufreq_cpu_get() gets the policy from per-cpu variable cpufreq_cpu_data under cpufreq_driver_lock, and once it gets a valid policy it expects it to not be freed until cpufreq_cpu_put() is called. But the race happens when another thread puts the kobject first and updates cpufreq_cpu_data before or later. And so the first thread gets a valid policy structure and before it does kobject_get() on it, the second one has already done kobject_put(). Fix this by setting cpufreq_cpu_data to NULL before putting the kobject and that too under locks. Reported-by: Ethan Zhao Reported-by: Santosh Shilimkar Signed-off-by: Viresh Kumar Cc: 3.12+ # 3.12+ Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index ca69f42..2b181f7 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1392,9 +1392,10 @@ static int __cpufreq_remove_dev_finish(struct device *dev, unsigned long flags; struct cpufreq_policy *policy; - read_lock_irqsave(&cpufreq_driver_lock, flags); + write_lock_irqsave(&cpufreq_driver_lock, flags); policy = per_cpu(cpufreq_cpu_data, cpu); - read_unlock_irqrestore(&cpufreq_driver_lock, flags); + per_cpu(cpufreq_cpu_data, cpu) = NULL; + write_unlock_irqrestore(&cpufreq_driver_lock, flags); if (!policy) { pr_debug("%s: No cpu_data found\n", __func__); @@ -1449,7 +1450,6 @@ static int __cpufreq_remove_dev_finish(struct device *dev, } } - per_cpu(cpufreq_cpu_data, cpu) = NULL; return 0; } -- cgit v0.10.2 From d2cecb3d66e39765f3dec8adfb88c322e709b06d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 3 Feb 2015 21:54:48 +0100 Subject: ACPI / cpuidle: Merge acpi_idle_enter_c1() and acpi_idle_enter_simple() acpi_idle_enter_c1() and acpi_idle_enter_simple() are close enough to each other that they can be merged into one function which reduces duplication of code quite a bit. Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index eaa3258..58113a6 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -704,34 +704,6 @@ static void acpi_idle_do_entry(struct acpi_processor_cx *cx) } /** - * acpi_idle_enter_c1 - enters an ACPI C1 state-type - * @dev: the target CPU - * @drv: cpuidle driver containing cpuidle state info - * @index: index of target state - * - * This is equivalent to the HALT instruction. - */ -static int acpi_idle_enter_c1(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int index) -{ - struct acpi_processor *pr; - struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); - - pr = __this_cpu_read(processors); - - if (unlikely(!pr)) - return -EINVAL; - - lapic_timer_state_broadcast(pr, cx, 1); - acpi_idle_do_entry(cx); - - lapic_timer_state_broadcast(pr, cx, 0); - - return index; -} - - -/** * acpi_idle_play_dead - enters an ACPI state for long-term idle (i.e. off-lining) * @dev: the target CPU * @index: the index of suggested state @@ -766,7 +738,7 @@ static bool acpi_idle_fallback_to_c1(struct acpi_processor *pr) } /** - * acpi_idle_enter_simple - enters an ACPI state without BM handling + * acpi_idle_enter_simple - enters a CPU idle state without BM handling * @dev: the target CPU * @drv: cpuidle driver with cpuidle state information * @index: the index of suggested state @@ -782,8 +754,10 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, if (unlikely(!pr)) return -EINVAL; - if (acpi_idle_fallback_to_c1(pr)) - return acpi_idle_enter_c1(dev, drv, CPUIDLE_DRIVER_STATE_START); + if (cx->type != ACPI_STATE_C1 && acpi_idle_fallback_to_c1(pr)) { + index = CPUIDLE_DRIVER_STATE_START; + cx = per_cpu(acpi_cstate[index], dev->cpu); + } lapic_timer_state_broadcast(pr, cx, 1); @@ -819,7 +793,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, return -EINVAL; if (acpi_idle_fallback_to_c1(pr)) - return acpi_idle_enter_c1(dev, drv, CPUIDLE_DRIVER_STATE_START); + return acpi_idle_enter_simple(dev, drv, CPUIDLE_DRIVER_STATE_START); if (!cx->bm_sts_skip && acpi_idle_bm_check()) { if (drv->safe_state_index >= 0) { @@ -967,11 +941,6 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) switch (cx->type) { case ACPI_STATE_C1: - state->enter = acpi_idle_enter_c1; - state->enter_dead = acpi_idle_play_dead; - drv->safe_state_index = count; - break; - case ACPI_STATE_C2: state->enter = acpi_idle_enter_simple; state->enter_dead = acpi_idle_play_dead; -- cgit v0.10.2 From 6491bc0c616969f7ae1fcb30a8823c333e2944c7 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 3 Feb 2015 21:55:11 +0100 Subject: ACPI / cpuidle: Common callback routine for entering states Introduce a common ->enter callback routine for the ACPI cpuidle driver, acpi_idle_enter(), which helps to reduce code complexity, size and duplication and prevents theoretically possible failues that an incorrect routine may be run to enter the given idle state due to a firmware bug (eg. when _CST returns a different set of states for each processor). Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 58113a6..c256bd7 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -737,74 +737,17 @@ static bool acpi_idle_fallback_to_c1(struct acpi_processor *pr) !pr->flags.has_cst; } -/** - * acpi_idle_enter_simple - enters a CPU idle state without BM handling - * @dev: the target CPU - * @drv: cpuidle driver with cpuidle state information - * @index: the index of suggested state - */ -static int acpi_idle_enter_simple(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int index) -{ - struct acpi_processor *pr; - struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); - - pr = __this_cpu_read(processors); - - if (unlikely(!pr)) - return -EINVAL; - - if (cx->type != ACPI_STATE_C1 && acpi_idle_fallback_to_c1(pr)) { - index = CPUIDLE_DRIVER_STATE_START; - cx = per_cpu(acpi_cstate[index], dev->cpu); - } - - lapic_timer_state_broadcast(pr, cx, 1); - - if (cx->type == ACPI_STATE_C3) - ACPI_FLUSH_CPU_CACHE(); - - acpi_idle_do_entry(cx); - - lapic_timer_state_broadcast(pr, cx, 0); - return index; -} - static int c3_cpu_count; static DEFINE_RAW_SPINLOCK(c3_lock); /** * acpi_idle_enter_bm - enters C3 with proper BM handling - * @dev: the target CPU - * @drv: cpuidle driver containing state data - * @index: the index of suggested state - * - * If BM is detected, the deepest non-C3 idle state is entered instead. + * @pr: Target processor + * @cx: Target state context */ -static int acpi_idle_enter_bm(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int index) +static void acpi_idle_enter_bm(struct acpi_processor *pr, + struct acpi_processor_cx *cx) { - struct acpi_processor *pr; - struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); - - pr = __this_cpu_read(processors); - - if (unlikely(!pr)) - return -EINVAL; - - if (acpi_idle_fallback_to_c1(pr)) - return acpi_idle_enter_simple(dev, drv, CPUIDLE_DRIVER_STATE_START); - - if (!cx->bm_sts_skip && acpi_idle_bm_check()) { - if (drv->safe_state_index >= 0) { - return drv->states[drv->safe_state_index].enter(dev, - drv, drv->safe_state_index); - } else { - acpi_safe_halt(); - return -EBUSY; - } - } - acpi_unlazy_tlb(smp_processor_id()); /* @@ -842,6 +785,45 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, } lapic_timer_state_broadcast(pr, cx, 0); +} + +static int acpi_idle_enter(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); + struct acpi_processor *pr; + + pr = __this_cpu_read(processors); + if (unlikely(!pr)) + return -EINVAL; + + if (cx->type != ACPI_STATE_C1) { + if (acpi_idle_fallback_to_c1(pr)) { + 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); + return index; + } else if (drv->safe_state_index >= 0) { + index = drv->safe_state_index; + cx = per_cpu(acpi_cstate[index], dev->cpu); + } else { + acpi_safe_halt(); + return -EBUSY; + } + } + } + + lapic_timer_state_broadcast(pr, cx, 1); + + if (cx->type == ACPI_STATE_C3) + ACPI_FLUSH_CPU_CACHE(); + + acpi_idle_do_entry(cx); + + lapic_timer_state_broadcast(pr, cx, 0); + return index; } @@ -936,22 +918,12 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN); state->exit_latency = cx->latency; state->target_residency = cx->latency * latency_factor; + state->enter = acpi_idle_enter; state->flags = 0; - switch (cx->type) { - - case ACPI_STATE_C1: - case ACPI_STATE_C2: - state->enter = acpi_idle_enter_simple; + if (cx->type == ACPI_STATE_C1 || cx->type == ACPI_STATE_C2) { state->enter_dead = acpi_idle_play_dead; drv->safe_state_index = count; - break; - - case ACPI_STATE_C3: - state->enter = pr->flags.bm_check ? - acpi_idle_enter_bm : - acpi_idle_enter_simple; - break; } count++; -- cgit v0.10.2 From c793504de3de484076e1eb96d5187af55f47945c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 2 Feb 2015 10:42:47 +0800 Subject: ACPI: Remove redundant check in function acpi_dev_resource_address_space() The ACPI type is checked in acpi_resource_to_address64() anyway. Signed-off-by: Thomas Gleixner Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index d0a4d90..1c616a5 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -189,15 +189,6 @@ bool acpi_dev_resource_address_space(struct acpi_resource *ares, u64 len; u8 io_decode; - switch (ares->type) { - case ACPI_RESOURCE_TYPE_ADDRESS16: - case ACPI_RESOURCE_TYPE_ADDRESS32: - case ACPI_RESOURCE_TYPE_ADDRESS64: - break; - default: - return false; - } - status = acpi_resource_to_address64(ares, &addr); if (ACPI_FAILURE(status)) return false; -- cgit v0.10.2 From c420dbd13ef7f399a865498496ac9ce2755b8007 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 2 Feb 2015 10:42:48 +0800 Subject: ACPI: Implement proper length checks for mem resources Check whether the resulting length is the same as the given length. Check for start <= end as well. We need to hand in the resource for this, so we can apply the flags directly. [Jiang] Remove enforcement that resource starting address must be non-zero. Signed-off-by: Thomas Gleixner Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 1c616a5..3e7d9f6 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -34,21 +34,37 @@ #define valid_IRQ(i) (true) #endif -static unsigned long acpi_dev_memresource_flags(u64 len, u8 write_protect, - bool window) +static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io) { - unsigned long flags = IORESOURCE_MEM; + u64 reslen = end - start + 1; - if (len == 0) - flags |= IORESOURCE_DISABLED; + /* + * CHECKME: len might be required to check versus a minimum + * length as well. 1 for io is fine, but for memory it does + * not make any sense at all. + */ + if (len && reslen && reslen == len && start <= end) + return true; + + pr_info("ACPI: invalid or unassigned resource %s [%016llx - %016llx] length [%016llx]\n", + io ? "io" : "mem", start, end, len); + + return false; +} + +static void acpi_dev_memresource_flags(struct resource *res, u64 len, + u8 write_protect, bool window) +{ + res->flags = IORESOURCE_MEM; + + if (!acpi_dev_resource_len_valid(res->start, res->end, len, false)) + res->flags |= IORESOURCE_DISABLED; if (write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + res->flags |= IORESOURCE_MEM_WRITEABLE; if (window) - flags |= IORESOURCE_WINDOW; - - return flags; + res->flags |= IORESOURCE_WINDOW; } static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, @@ -56,7 +72,7 @@ static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, { res->start = start; res->end = start + len - 1; - res->flags = acpi_dev_memresource_flags(len, write_protect, false); + acpi_dev_memresource_flags(res, len, write_protect, false); } /** @@ -77,24 +93,18 @@ 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->minimum && !memory24->address_length) - return false; acpi_dev_get_memresource(res, memory24->minimum, memory24->address_length, memory24->write_protect); break; case ACPI_RESOURCE_TYPE_MEMORY32: memory32 = &ares->data.memory32; - if (!memory32->minimum && !memory32->address_length) - return false; acpi_dev_get_memresource(res, memory32->minimum, memory32->address_length, memory32->write_protect); break; case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: fixed_memory32 = &ares->data.fixed_memory32; - if (!fixed_memory32->address && !fixed_memory32->address_length) - return false; acpi_dev_get_memresource(res, fixed_memory32->address, fixed_memory32->address_length, fixed_memory32->write_protect); @@ -102,7 +112,8 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) default: return false; } - return true; + + return !(res->flags & IORESOURCE_DISABLED); } EXPORT_SYMBOL_GPL(acpi_dev_resource_memory); @@ -186,7 +197,6 @@ bool acpi_dev_resource_address_space(struct acpi_resource *ares, acpi_status status; struct acpi_resource_address64 addr; bool window; - u64 len; u8 io_decode; status = acpi_resource_to_address64(ares, &addr); @@ -199,10 +209,9 @@ bool acpi_dev_resource_address_space(struct acpi_resource *ares, switch(addr.resource_type) { case ACPI_MEMORY_RANGE: - len = addr.address.maximum - addr.address.minimum + 1; - res->flags = acpi_dev_memresource_flags(len, - addr.info.mem.write_protect, - window); + acpi_dev_memresource_flags(res, addr.address.address_length, + addr.info.mem.write_protect, + window); break; case ACPI_IO_RANGE: io_decode = addr.address.granularity == 0xfff ? @@ -236,7 +245,6 @@ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, { struct acpi_resource_extended_address64 *ext_addr; bool window; - u64 len; u8 io_decode; if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) @@ -250,10 +258,10 @@ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, switch(ext_addr->resource_type) { case ACPI_MEMORY_RANGE: - len = ext_addr->address.maximum - ext_addr->address.minimum + 1; - res->flags = acpi_dev_memresource_flags(len, - ext_addr->info.mem.write_protect, - window); + acpi_dev_memresource_flags(res, + ext_addr->address.address_length, + ext_addr->info.mem.write_protect, + window); break; case ACPI_IO_RANGE: io_decode = ext_addr->address.granularity == 0xfff ? -- cgit v0.10.2 From 1d0420f1cfc4763a8c5bfc617e0a40f710c2f74d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 2 Feb 2015 10:42:49 +0800 Subject: ACPI: Use the length check for io resources as well Also apply length check to IO resources. [Jiang] Remove enforcement that resource starting address must be non-zero. Signed-off-by: Thomas Gleixner Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 3e7d9f6..16d291c 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -117,31 +117,30 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) } EXPORT_SYMBOL_GPL(acpi_dev_resource_memory); -static unsigned int acpi_dev_ioresource_flags(u64 start, u64 end, u8 io_decode, - bool window) +static void acpi_dev_ioresource_flags(struct resource *res, u64 len, + u8 io_decode, bool window) { - int flags = IORESOURCE_IO; + res->flags = IORESOURCE_IO; - if (io_decode == ACPI_DECODE_16) - flags |= IORESOURCE_IO_16BIT_ADDR; + if (!acpi_dev_resource_len_valid(res->start, res->end, len, true)) + res->flags |= IORESOURCE_DISABLED; - if (start > end || end >= 0x10003) - flags |= IORESOURCE_DISABLED; + if (res->end >= 0x10003) + res->flags |= IORESOURCE_DISABLED; - if (window) - flags |= IORESOURCE_WINDOW; + if (io_decode == ACPI_DECODE_16) + res->flags |= IORESOURCE_IO_16BIT_ADDR; - return flags; + if (window) + res->flags |= IORESOURCE_WINDOW; } static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, u8 io_decode) { - u64 end = start + len - 1; - res->start = start; - res->end = end; - res->flags = acpi_dev_ioresource_flags(start, end, io_decode, false); + res->end = start + len - 1; + acpi_dev_ioresource_flags(res, len, io_decode, false); } /** @@ -161,16 +160,12 @@ 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->minimum && !io->address_length) - return false; acpi_dev_get_ioresource(res, io->minimum, io->address_length, io->io_decode); break; case ACPI_RESOURCE_TYPE_FIXED_IO: fixed_io = &ares->data.fixed_io; - if (!fixed_io->address && !fixed_io->address_length) - return false; acpi_dev_get_ioresource(res, fixed_io->address, fixed_io->address_length, ACPI_DECODE_10); @@ -178,7 +173,8 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) default: return false; } - return true; + + return !(res->flags & IORESOURCE_DISABLED); } EXPORT_SYMBOL_GPL(acpi_dev_resource_io); @@ -216,9 +212,8 @@ bool acpi_dev_resource_address_space(struct acpi_resource *ares, case ACPI_IO_RANGE: io_decode = addr.address.granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16; - res->flags = acpi_dev_ioresource_flags(addr.address.minimum, - addr.address.maximum, - io_decode, window); + acpi_dev_ioresource_flags(res, addr.address.address_length, + io_decode, window); break; case ACPI_BUS_NUMBER_RANGE: res->flags = IORESOURCE_BUS; @@ -266,9 +261,8 @@ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, case ACPI_IO_RANGE: io_decode = ext_addr->address.granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16; - res->flags = acpi_dev_ioresource_flags(ext_addr->address.minimum, - ext_addr->address.maximum, - io_decode, window); + acpi_dev_ioresource_flags(res, ext_addr->address.address_length, + io_decode, window); break; case ACPI_BUS_NUMBER_RANGE: res->flags = IORESOURCE_BUS; -- cgit v0.10.2 From e814f6deee6188265b5af9f1190e5734f116860e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 2 Feb 2015 10:42:50 +0800 Subject: ACPI: Let the parser return false for disabled resources If the parser disables a resource during parsing, let it return false, so the calling code does not need to implement further checks. Signed-off-by: Thomas Gleixner Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 16d291c..cdb1a3c 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -219,10 +219,10 @@ bool acpi_dev_resource_address_space(struct acpi_resource *ares, res->flags = IORESOURCE_BUS; break; default: - res->flags = 0; + return false; } - return true; + return !(res->flags & IORESOURCE_DISABLED); } EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); @@ -268,10 +268,10 @@ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, res->flags = IORESOURCE_BUS; break; default: - res->flags = 0; + return false; } - return true; + return !(res->flags & IORESOURCE_DISABLED); } EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space); -- cgit v0.10.2 From eb76d55e66a9bed2359cc5a0f08168b287c4dea8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 2 Feb 2015 10:42:51 +0800 Subject: ACPI: Unify the parsing of address_space and ext_address_space With the unions in place which let us identify the substructs we can use a single parser for address_space and ext_address_space. Signed-off-by: Thomas Gleixner Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index cdb1a3c..99903d1 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -178,6 +178,35 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) } EXPORT_SYMBOL_GPL(acpi_dev_resource_io); +static bool acpi_decode_space(struct resource *res, + struct acpi_resource_address *addr, + struct acpi_address64_attribute *attr) +{ + u8 iodec = attr->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16; + bool window = addr->producer_consumer == ACPI_PRODUCER; + bool wp = addr->info.mem.write_protect; + u64 len = attr->address_length; + + res->start = attr->minimum; + res->end = attr->maximum; + + switch (addr->resource_type) { + case ACPI_MEMORY_RANGE: + acpi_dev_memresource_flags(res, len, wp, window); + break; + case ACPI_IO_RANGE: + acpi_dev_ioresource_flags(res, len, iodec, window); + break; + case ACPI_BUS_NUMBER_RANGE: + res->flags = IORESOURCE_BUS; + break; + default: + return false; + } + + return !(res->flags & IORESOURCE_DISABLED); +} + /** * acpi_dev_resource_address_space - Extract ACPI address space information. * @ares: Input ACPI resource object. @@ -190,39 +219,13 @@ EXPORT_SYMBOL_GPL(acpi_dev_resource_io); bool acpi_dev_resource_address_space(struct acpi_resource *ares, struct resource *res) { - acpi_status status; struct acpi_resource_address64 addr; - bool window; - u8 io_decode; - - status = acpi_resource_to_address64(ares, &addr); - if (ACPI_FAILURE(status)) - return false; - res->start = addr.address.minimum; - res->end = addr.address.maximum; - window = addr.producer_consumer == ACPI_PRODUCER; - - switch(addr.resource_type) { - case ACPI_MEMORY_RANGE: - acpi_dev_memresource_flags(res, addr.address.address_length, - addr.info.mem.write_protect, - window); - break; - case ACPI_IO_RANGE: - io_decode = addr.address.granularity == 0xfff ? - ACPI_DECODE_10 : ACPI_DECODE_16; - acpi_dev_ioresource_flags(res, addr.address.address_length, - io_decode, window); - break; - case ACPI_BUS_NUMBER_RANGE: - res->flags = IORESOURCE_BUS; - break; - default: + if (ACPI_FAILURE(acpi_resource_to_address64(ares, &addr))) return false; - } - return !(res->flags & IORESOURCE_DISABLED); + return acpi_decode_space(res, (struct acpi_resource_address *)&addr, + &addr.address); } EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); @@ -239,39 +242,14 @@ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, struct resource *res) { struct acpi_resource_extended_address64 *ext_addr; - bool window; - u8 io_decode; if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) return false; ext_addr = &ares->data.ext_address64; - res->start = ext_addr->address.minimum; - res->end = ext_addr->address.maximum; - window = ext_addr->producer_consumer == ACPI_PRODUCER; - - switch(ext_addr->resource_type) { - case ACPI_MEMORY_RANGE: - acpi_dev_memresource_flags(res, - ext_addr->address.address_length, - ext_addr->info.mem.write_protect, - window); - break; - case ACPI_IO_RANGE: - io_decode = ext_addr->address.granularity == 0xfff ? - ACPI_DECODE_10 : ACPI_DECODE_16; - acpi_dev_ioresource_flags(res, ext_addr->address.address_length, - io_decode, window); - break; - case ACPI_BUS_NUMBER_RANGE: - res->flags = IORESOURCE_BUS; - break; - default: - return false; - } - - return !(res->flags & IORESOURCE_DISABLED); + return acpi_decode_space(res, (struct acpi_resource_address *)ext_addr, + &ext_addr->address); } EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space); -- cgit v0.10.2 From 72e26b0d487fc494f40aa61e10a0757791e62e36 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 2 Feb 2015 10:42:52 +0800 Subject: ACPI: Move the window flag logic to the combined parser Normal memory and io resources have window always set to false. Move the flag logic to the unified address space parser. Signed-off-by: Thomas Gleixner Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 99903d1..15d1793 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -53,7 +53,7 @@ static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io) } static void acpi_dev_memresource_flags(struct resource *res, u64 len, - u8 write_protect, bool window) + u8 write_protect) { res->flags = IORESOURCE_MEM; @@ -62,9 +62,6 @@ static void acpi_dev_memresource_flags(struct resource *res, u64 len, if (write_protect == ACPI_READ_WRITE_MEMORY) res->flags |= IORESOURCE_MEM_WRITEABLE; - - if (window) - res->flags |= IORESOURCE_WINDOW; } static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, @@ -72,7 +69,7 @@ static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, { res->start = start; res->end = start + len - 1; - acpi_dev_memresource_flags(res, len, write_protect, false); + acpi_dev_memresource_flags(res, len, write_protect); } /** @@ -118,7 +115,7 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) EXPORT_SYMBOL_GPL(acpi_dev_resource_memory); static void acpi_dev_ioresource_flags(struct resource *res, u64 len, - u8 io_decode, bool window) + u8 io_decode) { res->flags = IORESOURCE_IO; @@ -130,9 +127,6 @@ static void acpi_dev_ioresource_flags(struct resource *res, u64 len, if (io_decode == ACPI_DECODE_16) res->flags |= IORESOURCE_IO_16BIT_ADDR; - - if (window) - res->flags |= IORESOURCE_WINDOW; } static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, @@ -140,7 +134,7 @@ static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, { res->start = start; res->end = start + len - 1; - acpi_dev_ioresource_flags(res, len, io_decode, false); + acpi_dev_ioresource_flags(res, len, io_decode); } /** @@ -183,7 +177,6 @@ static bool acpi_decode_space(struct resource *res, struct acpi_address64_attribute *attr) { u8 iodec = attr->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16; - bool window = addr->producer_consumer == ACPI_PRODUCER; bool wp = addr->info.mem.write_protect; u64 len = attr->address_length; @@ -192,10 +185,10 @@ static bool acpi_decode_space(struct resource *res, switch (addr->resource_type) { case ACPI_MEMORY_RANGE: - acpi_dev_memresource_flags(res, len, wp, window); + acpi_dev_memresource_flags(res, len, wp); break; case ACPI_IO_RANGE: - acpi_dev_ioresource_flags(res, len, iodec, window); + acpi_dev_ioresource_flags(res, len, iodec); break; case ACPI_BUS_NUMBER_RANGE: res->flags = IORESOURCE_BUS; @@ -204,6 +197,9 @@ static bool acpi_decode_space(struct resource *res, return false; } + if (addr->producer_consumer == ACPI_PRODUCER) + res->flags |= IORESOURCE_WINDOW; + return !(res->flags & IORESOURCE_DISABLED); } -- cgit v0.10.2 From fcb29bbcd5404494eb46ad24908a4843b5a32060 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 2 Feb 2015 10:42:53 +0800 Subject: ACPI: Add prefetch decoding to the address space parser Add support of PREFETCH attributre to ACPI address space and extended address space parser. Signed-off-by: Thomas Gleixner Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 15d1793..7ce00a6 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -200,6 +200,9 @@ static bool acpi_decode_space(struct resource *res, if (addr->producer_consumer == ACPI_PRODUCER) res->flags |= IORESOURCE_WINDOW; + if (addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY) + res->flags |= IORESOURCE_PREFETCH; + return !(res->flags & IORESOURCE_DISABLED); } -- cgit v0.10.2 From 8515f9368161730655b64ddaf8b11a3d20049610 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 2 Feb 2015 10:42:54 +0800 Subject: ACPI: Fix a bug in parsing ACPI Memory24 resource According to ACPI spec 5, section 6.4.3.1 "24-Bit Memory Range Descriptor", minimum, maximum and address_length field in struct acpi_resource_memory24 is in granularity of 256-bytes. So shift 8-bit left to get correct address. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 7ce00a6..5544c6d 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -90,8 +90,8 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) switch (ares->type) { case ACPI_RESOURCE_TYPE_MEMORY24: memory24 = &ares->data.memory24; - acpi_dev_get_memresource(res, memory24->minimum, - memory24->address_length, + acpi_dev_get_memresource(res, memory24->minimum << 8, + memory24->address_length << 8, memory24->write_protect); break; case ACPI_RESOURCE_TYPE_MEMORY32: -- cgit v0.10.2 From 581c19f3a72ae9ff7f24f2a6c2e67f269ed4392a Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 2 Feb 2015 10:42:55 +0800 Subject: ACPI: Normalize return value of resource parser functions Normalize return value of resource parse functions as: 1) return "true" if resource is assigned. 2) return "false" and IORESOURCE_DISABLED setting in res->flags if resource is unassigned. 3) return "false" and zeroing res->flags if it's not an valid or expected resource. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 5544c6d..3256129 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -80,6 +80,11 @@ static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, * Check if the given ACPI resource object represents a memory resource and * if that's the case, use the information in it to populate the generic * resource object pointed to by @res. + * + * Return: + * 1) false with res->flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 3) true: valid assigned resource */ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) { @@ -107,6 +112,7 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) fixed_memory32->write_protect); break; default: + res->flags = 0; return false; } @@ -145,6 +151,11 @@ static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, * Check if the given ACPI resource object represents an I/O resource and * if that's the case, use the information in it to populate the generic * resource object pointed to by @res. + * + * Return: + * 1) false with res->flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 3) true: valid assigned resource */ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) { @@ -165,6 +176,7 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) ACPI_DECODE_10); break; default: + res->flags = 0; return false; } @@ -214,12 +226,18 @@ static bool acpi_decode_space(struct resource *res, * Check if the given ACPI resource object represents an address space resource * and if that's the case, use the information in it to populate the generic * resource object pointed to by @res. + * + * Return: + * 1) false with res->flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 3) true: valid assigned resource */ bool acpi_dev_resource_address_space(struct acpi_resource *ares, struct resource *res) { struct acpi_resource_address64 addr; + res->flags = 0; if (ACPI_FAILURE(acpi_resource_to_address64(ares, &addr))) return false; @@ -236,12 +254,18 @@ EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); * Check if the given ACPI resource object represents an extended address space * resource and if that's the case, use the information in it to populate the * generic resource object pointed to by @res. + * + * Return: + * 1) false with res->flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 3) true: valid assigned resource */ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, struct resource *res) { struct acpi_resource_extended_address64 *ext_addr; + res->flags = 0; if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) return false; @@ -339,6 +363,11 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, * represented by the resource and populate the generic resource object pointed * to by @res accordingly. If the registration of the GSI is not successful, * IORESOURCE_DISABLED will be set it that object's flags. + * + * Return: + * 1) false with res->flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 3) true: valid assigned resource */ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, struct resource *res) @@ -372,6 +401,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, ext_irq->sharable, false); break; default: + res->flags = 0; return false; } -- cgit v0.10.2 From c78b688561e684098a11012ca21a6d578f9dfb67 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 2 Feb 2015 10:42:56 +0800 Subject: ACPI: Set flag IORESOURCE_UNSET for unassigned resources Also set flag IORESOURCE_UNSET for unassigned resource in addition to IORESOURCE_DISABLED to mark resource as unassigned. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 3256129..5bf73a9 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -58,7 +58,7 @@ static void acpi_dev_memresource_flags(struct resource *res, u64 len, res->flags = IORESOURCE_MEM; if (!acpi_dev_resource_len_valid(res->start, res->end, len, false)) - res->flags |= IORESOURCE_DISABLED; + res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; if (write_protect == ACPI_READ_WRITE_MEMORY) res->flags |= IORESOURCE_MEM_WRITEABLE; @@ -126,10 +126,10 @@ static void acpi_dev_ioresource_flags(struct resource *res, u64 len, res->flags = IORESOURCE_IO; if (!acpi_dev_resource_len_valid(res->start, res->end, len, true)) - res->flags |= IORESOURCE_DISABLED; + res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; if (res->end >= 0x10003) - res->flags |= IORESOURCE_DISABLED; + res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; if (io_decode == ACPI_DECODE_16) res->flags |= IORESOURCE_IO_16BIT_ADDR; @@ -304,7 +304,7 @@ static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi) { res->start = gsi; res->end = gsi; - res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED; + res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED | IORESOURCE_UNSET; } static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, -- cgit v0.10.2 From a274019fc332d7b4dcb85735978c2018522be312 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 2 Feb 2015 10:42:57 +0800 Subject: ACPI: Enforce stricter checks for address space descriptors Enforce stricter checks for address space descriptors according to ACPI spec. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 5bf73a9..57891a6 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -192,6 +192,15 @@ static bool acpi_decode_space(struct resource *res, bool wp = addr->info.mem.write_protect; u64 len = attr->address_length; + /* + * Filter out invalid descriptor according to ACPI Spec 5.0, section + * 6.4.3.5 Address Space Resource Descriptors. + */ + if ((addr->min_address_fixed != addr->max_address_fixed && len) || + (addr->min_address_fixed && addr->max_address_fixed && !len)) + pr_debug("ACPI: Invalid address space min_addr_fix %d, max_addr_fix %d, len %llx\n", + addr->min_address_fixed, addr->max_address_fixed, len); + res->start = attr->minimum; res->end = attr->maximum; -- cgit v0.10.2 From a49170b552423a3e85fc4f0d778c707402ee4863 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 2 Feb 2015 10:42:58 +0800 Subject: ACPI: Return translation offset when parsing ACPI address space resources Change function acpi_dev_resource_address_space() and acpi_dev_resource_ext_address_space() to return address space translation offset. It's based on a patch from Yinghai Lu . Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 57891a6..c902c8e 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -184,13 +184,14 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) } EXPORT_SYMBOL_GPL(acpi_dev_resource_io); -static bool acpi_decode_space(struct resource *res, +static bool acpi_decode_space(struct resource_win *win, struct acpi_resource_address *addr, struct acpi_address64_attribute *attr) { u8 iodec = attr->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16; bool wp = addr->info.mem.write_protect; u64 len = attr->address_length; + struct resource *res = &win->res; /* * Filter out invalid descriptor according to ACPI Spec 5.0, section @@ -218,6 +219,8 @@ static bool acpi_decode_space(struct resource *res, return false; } + win->offset = attr->translation_offset; + if (addr->producer_consumer == ACPI_PRODUCER) res->flags |= IORESOURCE_WINDOW; @@ -230,27 +233,28 @@ static bool acpi_decode_space(struct resource *res, /** * acpi_dev_resource_address_space - Extract ACPI address space information. * @ares: Input ACPI resource object. - * @res: Output generic resource object. + * @win: Output generic resource object. * * Check if the given ACPI resource object represents an address space resource * and if that's the case, use the information in it to populate the generic - * resource object pointed to by @res. + * resource object pointed to by @win. * * Return: - * 1) false with res->flags setting to zero: not the expected resource type - * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 1) false with win->res.flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in win->res.flags: valid unassigned + * resource * 3) true: valid assigned resource */ bool acpi_dev_resource_address_space(struct acpi_resource *ares, - struct resource *res) + struct resource_win *win) { struct acpi_resource_address64 addr; - res->flags = 0; + win->res.flags = 0; if (ACPI_FAILURE(acpi_resource_to_address64(ares, &addr))) return false; - return acpi_decode_space(res, (struct acpi_resource_address *)&addr, + return acpi_decode_space(win, (struct acpi_resource_address *)&addr, &addr.address); } EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); @@ -258,29 +262,30 @@ EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); /** * acpi_dev_resource_ext_address_space - Extract ACPI address space information. * @ares: Input ACPI resource object. - * @res: Output generic resource object. + * @win: Output generic resource object. * * Check if the given ACPI resource object represents an extended address space * resource and if that's the case, use the information in it to populate the - * generic resource object pointed to by @res. + * generic resource object pointed to by @win. * * Return: - * 1) false with res->flags setting to zero: not the expected resource type - * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 1) false with win->res.flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in win->res.flags: valid unassigned + * resource * 3) true: valid assigned resource */ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, - struct resource *res) + struct resource_win *win) { struct acpi_resource_extended_address64 *ext_addr; - res->flags = 0; + win->res.flags = 0; if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) return false; ext_addr = &ares->data.ext_address64; - return acpi_decode_space(res, (struct acpi_resource_address *)ext_addr, + return acpi_decode_space(win, (struct acpi_resource_address *)ext_addr, &ext_addr->address); } EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space); @@ -441,7 +446,7 @@ struct res_proc_context { int error; }; -static acpi_status acpi_dev_new_resource_entry(struct resource *r, +static acpi_status acpi_dev_new_resource_entry(struct resource_win *win, struct res_proc_context *c) { struct resource_list_entry *rentry; @@ -451,7 +456,7 @@ static acpi_status acpi_dev_new_resource_entry(struct resource *r, c->error = -ENOMEM; return AE_NO_MEMORY; } - rentry->res = *r; + rentry->res = win->res; list_add_tail(&rentry->node, c->list); c->count++; return AE_OK; @@ -461,7 +466,8 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, void *context) { struct res_proc_context *c = context; - struct resource r; + struct resource_win win; + struct resource *res = &win.res; int i; if (c->preproc) { @@ -476,18 +482,18 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, } } - memset(&r, 0, sizeof(r)); + memset(&win, 0, sizeof(win)); - if (acpi_dev_resource_memory(ares, &r) - || acpi_dev_resource_io(ares, &r) - || acpi_dev_resource_address_space(ares, &r) - || acpi_dev_resource_ext_address_space(ares, &r)) - return acpi_dev_new_resource_entry(&r, c); + if (acpi_dev_resource_memory(ares, res) + || acpi_dev_resource_io(ares, res) + || acpi_dev_resource_address_space(ares, &win) + || acpi_dev_resource_ext_address_space(ares, &win)) + return acpi_dev_new_resource_entry(&win, c); - for (i = 0; acpi_dev_resource_interrupt(ares, i, &r); i++) { + for (i = 0; acpi_dev_resource_interrupt(ares, i, res); i++) { acpi_status status; - status = acpi_dev_new_resource_entry(&r, c); + status = acpi_dev_new_resource_entry(&win, c); if (ACPI_FAILURE(status)) return status; } diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 2d9bc78..ff0356f 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -180,20 +180,21 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, struct pnp_dev *dev = data; struct acpi_resource_dma *dma; struct acpi_resource_vendor_typed *vendor_typed; - struct resource r = {0}; + struct resource_win win = {{0}, 0}; + struct resource *r = &win.res; int i, flags; - if (acpi_dev_resource_address_space(res, &r) - || acpi_dev_resource_ext_address_space(res, &r)) { - pnp_add_resource(dev, &r); + if (acpi_dev_resource_address_space(res, &win) + || acpi_dev_resource_ext_address_space(res, &win)) { + pnp_add_resource(dev, &win.res); return AE_OK; } - r.flags = 0; - if (acpi_dev_resource_interrupt(res, 0, &r)) { - pnpacpi_add_irqresource(dev, &r); - for (i = 1; acpi_dev_resource_interrupt(res, i, &r); i++) - pnpacpi_add_irqresource(dev, &r); + r->flags = 0; + if (acpi_dev_resource_interrupt(res, 0, r)) { + pnpacpi_add_irqresource(dev, r); + for (i = 1; acpi_dev_resource_interrupt(res, i, r); i++) + pnpacpi_add_irqresource(dev, r); if (i > 1) { /* @@ -209,7 +210,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, } } return AE_OK; - } else if (r.flags & IORESOURCE_DISABLED) { + } else if (r->flags & IORESOURCE_DISABLED) { pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); return AE_OK; } @@ -218,13 +219,13 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, case ACPI_RESOURCE_TYPE_MEMORY24: case ACPI_RESOURCE_TYPE_MEMORY32: case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - if (acpi_dev_resource_memory(res, &r)) - pnp_add_resource(dev, &r); + if (acpi_dev_resource_memory(res, r)) + pnp_add_resource(dev, r); break; case ACPI_RESOURCE_TYPE_IO: case ACPI_RESOURCE_TYPE_FIXED_IO: - if (acpi_dev_resource_io(res, &r)) - pnp_add_resource(dev, &r); + if (acpi_dev_resource_io(res, r)) + pnp_add_resource(dev, r); break; case ACPI_RESOURCE_TYPE_DMA: dma = &res->data.dma; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index d459cd1..be9eaee 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -285,12 +285,17 @@ extern int pnpacpi_disabled; #define PXM_INVAL (-1) +struct resource_win { + struct resource res; + resource_size_t offset; +}; + bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res); bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res); bool acpi_dev_resource_address_space(struct acpi_resource *ares, - struct resource *res); + struct resource_win *win); bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, - struct resource *res); + struct resource_win *win); unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable); bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, struct resource *res); -- cgit v0.10.2 From 2ea3d266bab3b497238113b20136f7c3f69ad9c0 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 2 Feb 2015 10:42:59 +0800 Subject: ACPI: Translate resource into master side address for bridge window resources Add translation_offset into the result address for bridge window resources to form the master side address. Currently acpi_dev_resource_{ext_}address_space() are only used for devices instead of bridges, so it won't break current users. Later it will be used to support PCI host bridge drivers. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index c902c8e..4dc8cfb 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -205,6 +205,21 @@ static bool acpi_decode_space(struct resource_win *win, res->start = attr->minimum; res->end = attr->maximum; + /* + * For bridges that translate addresses across the bridge, + * translation_offset is the offset that must be added to the + * address on the secondary side to obtain the address on the + * primary side. Non-bridge devices must list 0 for all Address + * Translation offset bits. + */ + if (addr->producer_consumer == ACPI_PRODUCER) { + res->start += attr->translation_offset; + res->end += attr->translation_offset; + } else if (attr->translation_offset) { + pr_debug("ACPI: translation_offset(%lld) is invalid for non-bridge device.\n", + attr->translation_offset); + } + switch (addr->resource_type) { case ACPI_MEMORY_RANGE: acpi_dev_memresource_flags(res, len, wp); -- cgit v0.10.2 From 93286f4798590e711aa395503401f8632fb74f9a Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 2 Feb 2015 10:43:00 +0800 Subject: ACPI: Add field offset to struct resource_list_entry Add field offset to struct resource_list_entry to host address space translation offset so it could be used to represent bridge resources. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 4dc8cfb..1c3abae 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -472,6 +472,7 @@ static acpi_status acpi_dev_new_resource_entry(struct resource_win *win, return AE_NO_MEMORY; } rentry->res = win->res; + rentry->offset = win->offset; list_add_tail(&rentry->node, c->list); c->count++; return AE_OK; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index be9eaee..21dac3c 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -303,6 +303,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, struct resource_list_entry { struct list_head node; struct resource res; + resource_size_t offset; }; void acpi_dev_free_resource_list(struct list_head *list); -- cgit v0.10.2 From 62d1141ff34e35de496ba06491c8e854b23b3f3e Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 2 Feb 2015 10:43:01 +0800 Subject: ACPI: Introduce helper function acpi_dev_filter_resource_type() Introduce helper function acpi_dev_filter_resource_type(), which may be used by acpi_dev_get_resources() to filer out resource based on resource type. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 1c3abae..3ea0d17 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -569,3 +569,58 @@ int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, return c.count; } EXPORT_SYMBOL_GPL(acpi_dev_get_resources); + +/** + * acpi_dev_filter_resource_type - Filter ACPI resource according to resource + * types + * @ares: Input ACPI resource object. + * @types: Valid resource types of IORESOURCE_XXX + * + * This is a hepler function to support acpi_dev_get_resources(), which filters + * ACPI resource objects according to resource types. + */ +int acpi_dev_filter_resource_type(struct acpi_resource *ares, + unsigned long types) +{ + unsigned long type = 0; + + switch (ares->type) { + case ACPI_RESOURCE_TYPE_MEMORY24: + case ACPI_RESOURCE_TYPE_MEMORY32: + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + type = IORESOURCE_MEM; + break; + case ACPI_RESOURCE_TYPE_IO: + case ACPI_RESOURCE_TYPE_FIXED_IO: + type = IORESOURCE_IO; + break; + case ACPI_RESOURCE_TYPE_IRQ: + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + type = IORESOURCE_IRQ; + break; + case ACPI_RESOURCE_TYPE_DMA: + case ACPI_RESOURCE_TYPE_FIXED_DMA: + type = IORESOURCE_DMA; + break; + case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: + type = IORESOURCE_REG; + break; + case ACPI_RESOURCE_TYPE_ADDRESS16: + case ACPI_RESOURCE_TYPE_ADDRESS32: + case ACPI_RESOURCE_TYPE_ADDRESS64: + case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: + if (ares->data.address.resource_type == ACPI_MEMORY_RANGE) + type = IORESOURCE_MEM; + else if (ares->data.address.resource_type == ACPI_IO_RANGE) + type = IORESOURCE_IO; + else if (ares->data.address.resource_type == + ACPI_BUS_NUMBER_RANGE) + type = IORESOURCE_BUS; + break; + default: + break; + } + + return (type & types) ? 0 : 1; +} +EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 21dac3c..e818dec 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -310,6 +310,14 @@ void acpi_dev_free_resource_list(struct list_head *list); int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, int (*preproc)(struct acpi_resource *, void *), void *preproc_data); +int acpi_dev_filter_resource_type(struct acpi_resource *ares, + unsigned long types); + +static inline int acpi_dev_filter_resource_type_cb(struct acpi_resource *ares, + void *arg) +{ + return acpi_dev_filter_resource_type(ares, (unsigned long)arg); +} int acpi_check_resource_conflict(const struct resource *res); -- cgit v0.10.2 From a64fc82c4f1598db024de7b3d79e7213379769ff Mon Sep 17 00:00:00 2001 From: Wonhong Kwon Date: Tue, 3 Feb 2015 17:22:00 +0900 Subject: PM / hibernate: exclude freed pages from allocated pages printout hibernate_preallocate_memory() prints out that how many pages are allocated, but it doesn't take into consideration the pages freed by free_unnecessary_pages(). Therefore, it always shows the count more than actually allocated. Signed-off-by: Wonhong Kwon [ rjw: Subject ] Signed-off-by: Rafael J. Wysocki diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 8e75a5a..c24d5a2 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1472,9 +1472,9 @@ static inline unsigned long preallocate_highmem_fraction(unsigned long nr_pages, /** * free_unnecessary_pages - Release preallocated pages not needed for the image */ -static void free_unnecessary_pages(void) +static unsigned long free_unnecessary_pages(void) { - unsigned long save, to_free_normal, to_free_highmem; + unsigned long save, to_free_normal, to_free_highmem, free; save = count_data_pages(); if (alloc_normal >= save) { @@ -1495,6 +1495,7 @@ static void free_unnecessary_pages(void) else to_free_normal = 0; } + free = to_free_normal + to_free_highmem; memory_bm_position_reset(©_bm); @@ -1518,6 +1519,8 @@ static void free_unnecessary_pages(void) swsusp_unset_page_free(page); __free_page(page); } + + return free; } /** @@ -1707,7 +1710,7 @@ int hibernate_preallocate_memory(void) * pages in memory, but we have allocated more. Release the excessive * ones now. */ - free_unnecessary_pages(); + pages -= free_unnecessary_pages(); out: stop = ktime_get(); -- cgit v0.10.2 From 49d400c74a8939ae783e3555459926b281a2b17d Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 27 Jan 2015 21:13:38 +0100 Subject: PM / Domains: Rename __pm_genpd_alloc|free_dev_data() In a step to get consistent names of functions in genpd, rename the internal __pm_genpd_alloc|free_dev_data() into gendp_alloc|free_dev_data(). As discussed on the linux-pm list, let's move towards the following name rules: Internal functions: genpd_* _genpd_* __genpd_* External functions: pm_genpd_* _pm_genpd_* __pm_genpd_* Signed-off-by: Ulf Hansson Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index c5280f2..f9e7df5 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1384,7 +1384,7 @@ EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron); #endif /* CONFIG_PM_SLEEP */ -static struct generic_pm_domain_data *__pm_genpd_alloc_dev_data(struct device *dev) +static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev) { struct generic_pm_domain_data *gpd_data; @@ -1398,8 +1398,8 @@ static struct generic_pm_domain_data *__pm_genpd_alloc_dev_data(struct device *d return gpd_data; } -static void __pm_genpd_free_dev_data(struct device *dev, - struct generic_pm_domain_data *gpd_data) +static void genpd_free_dev_data(struct device *dev, + struct generic_pm_domain_data *gpd_data) { dev_pm_qos_remove_notifier(dev, &gpd_data->nb); kfree(gpd_data); @@ -1423,7 +1423,7 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)) return -EINVAL; - gpd_data_new = __pm_genpd_alloc_dev_data(dev); + gpd_data_new = genpd_alloc_dev_data(dev); if (!gpd_data_new) return -ENOMEM; @@ -1477,7 +1477,7 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, genpd_release_lock(genpd); if (gpd_data != gpd_data_new) - __pm_genpd_free_dev_data(dev, gpd_data_new); + genpd_free_dev_data(dev, gpd_data_new); return ret; } @@ -1548,7 +1548,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, dev_pm_put_subsys_data(dev); if (remove) - __pm_genpd_free_dev_data(dev, gpd_data); + genpd_free_dev_data(dev, gpd_data); return 0; -- cgit v0.10.2 From c1dbe2fbb33ef425a81e1a7cffd17c113c87cdbc Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 27 Jan 2015 21:13:39 +0100 Subject: PM / Domains: Remove reference counting for the generic_pm_domain_data The reference counting was needed when genpd supported PM domain device callbacks. Since this option has been removed, let's also remove the reference counting of the struct generic_pm_domain_data. Signed-off-by: Ulf Hansson Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index f9e7df5..351df5b 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1456,7 +1456,6 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, gpd_data = gpd_data_new; dev->power.subsys_data->domain_data = &gpd_data->base; } - gpd_data->refcount++; if (td) gpd_data->td = *td; @@ -1504,7 +1503,6 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, { struct generic_pm_domain_data *gpd_data; struct pm_domain_data *pdd; - bool remove = false; int ret = 0; dev_dbg(dev, "%s()\n", __func__); @@ -1533,10 +1531,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, pdd = dev->power.subsys_data->domain_data; list_del_init(&pdd->list_node); gpd_data = to_gpd_data(pdd); - if (--gpd_data->refcount == 0) { - dev->power.subsys_data->domain_data = NULL; - remove = true; - } + dev->power.subsys_data->domain_data = NULL; spin_unlock_irq(&dev->power.lock); @@ -1547,8 +1542,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, genpd_release_lock(genpd); dev_pm_put_subsys_data(dev); - if (remove) - genpd_free_dev_data(dev, gpd_data); + genpd_free_dev_data(dev, gpd_data); return 0; diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index ed60776..e160a0b 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -114,7 +114,6 @@ struct generic_pm_domain_data { struct gpd_timing_data td; struct notifier_block nb; struct mutex lock; - unsigned int refcount; int need_restore; }; -- cgit v0.10.2 From 14b530648834c9ec9853954750957bab0f792538 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 27 Jan 2015 21:13:40 +0100 Subject: PM / Domains: Don't allow an existing generic_pm_domain_data When adding a device to a genpd, a struct generic_pm_domain_data is allocated per device. Verify that there are no existing generic_pm_domain_data for the device we are about to add, since that tells us it has already been added to a genpd. When genpd supported PM domain device callbacks, this was a valid scenario. Now it isn't so let's return an error code. Signed-off-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 351df5b..76eb0c3 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1444,26 +1444,30 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, if (ret) goto out; - genpd->device_count++; - genpd->max_off_time_changed = true; - spin_lock_irq(&dev->power.lock); - dev->pm_domain = &genpd->domain; if (dev->power.subsys_data->domain_data) { - gpd_data = to_gpd_data(dev->power.subsys_data->domain_data); - } else { - gpd_data = gpd_data_new; - dev->power.subsys_data->domain_data = &gpd_data->base; + spin_unlock_irq(&dev->power.lock); + ret = -EINVAL; + goto out; } + + gpd_data = gpd_data_new; + dev->power.subsys_data->domain_data = &gpd_data->base; + if (td) gpd_data->td = *td; + dev->pm_domain = &genpd->domain; + spin_unlock_irq(&dev->power.lock); if (genpd->attach_dev) genpd->attach_dev(genpd, dev); + genpd->device_count++; + genpd->max_off_time_changed = true; + mutex_lock(&gpd_data->lock); gpd_data->base.dev = dev; list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); -- cgit v0.10.2 From e07b45cb98839aa972c099ffd5fc5eb2ff1b2e26 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 27 Jan 2015 21:13:41 +0100 Subject: PM / Domains: Don't check for an existing device when adding a new When adding a device to a genpd, we no longer need to walk genpd's list of existing devices to verify it hasn't already been added. Instead we can now rely on the verification of not allowing existing generic_pm_domain_data for a device, since that has the same meaning. Signed-off-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 76eb0c3..88198ba 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1415,7 +1415,6 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, struct gpd_timing_data *td) { struct generic_pm_domain_data *gpd_data_new, *gpd_data = NULL; - struct pm_domain_data *pdd; int ret = 0; dev_dbg(dev, "%s()\n", __func__); @@ -1434,12 +1433,6 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, goto out; } - list_for_each_entry(pdd, &genpd->dev_list, list_node) - if (pdd->dev == dev) { - ret = -EINVAL; - goto out; - } - ret = dev_pm_get_subsys_data(dev); if (ret) goto out; -- cgit v0.10.2 From c0356db7d1b66840882744cbd9d9c5960b2d88c7 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 27 Jan 2015 21:13:42 +0100 Subject: PM / Domains: Eliminate the mutex for the generic_pm_domain_data While adding devices to their PM domains, dev_pm_qos_add_notifier() was invoked while allocating the generic_pm_domain_data for the device. Since the generic_pm_domain_data's device pointer will be assigned after allocation, the ->genpd_dev_pm_qos_notifier() callback could be called prior having a valid pointer to the device. Similar scenario existed while removing a device from a genpd. To cope with these scenarios a mutex was used to protect the pointer to the device. By re-order the sequence for when dev_pm_qos_add|remove_notifier() are invoked, we make sure the ->genpd_dev_pm_qos_notifier() callback are always called with a valid device pointer available. In this way, we eliminate the need for protecting the pointer and thus we can remove the mutex from the struct generic_pm_domain_data. Signed-off-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 88198ba..1f026c1 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -344,14 +344,7 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, struct device *dev; gpd_data = container_of(nb, struct generic_pm_domain_data, nb); - - mutex_lock(&gpd_data->lock); dev = gpd_data->base.dev; - if (!dev) { - mutex_unlock(&gpd_data->lock); - return NOTIFY_DONE; - } - mutex_unlock(&gpd_data->lock); for (;;) { struct generic_pm_domain *genpd; @@ -1392,16 +1385,12 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev) if (!gpd_data) return NULL; - mutex_init(&gpd_data->lock); - gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier; - dev_pm_qos_add_notifier(dev, &gpd_data->nb); return gpd_data; } static void genpd_free_dev_data(struct device *dev, struct generic_pm_domain_data *gpd_data) { - dev_pm_qos_remove_notifier(dev, &gpd_data->nb); kfree(gpd_data); } @@ -1414,7 +1403,7 @@ static void genpd_free_dev_data(struct device *dev, int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, struct gpd_timing_data *td) { - struct generic_pm_domain_data *gpd_data_new, *gpd_data = NULL; + struct generic_pm_domain_data *gpd_data; int ret = 0; dev_dbg(dev, "%s()\n", __func__); @@ -1422,8 +1411,8 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)) return -EINVAL; - gpd_data_new = genpd_alloc_dev_data(dev); - if (!gpd_data_new) + gpd_data = genpd_alloc_dev_data(dev); + if (!gpd_data) return -ENOMEM; genpd_acquire_lock(genpd); @@ -1445,7 +1434,6 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, goto out; } - gpd_data = gpd_data_new; dev->power.subsys_data->domain_data = &gpd_data->base; if (td) @@ -1461,19 +1449,20 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, genpd->device_count++; genpd->max_off_time_changed = true; - mutex_lock(&gpd_data->lock); gpd_data->base.dev = dev; list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); gpd_data->need_restore = -1; gpd_data->td.constraint_changed = true; gpd_data->td.effective_constraint_ns = -1; - mutex_unlock(&gpd_data->lock); + gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier; out: genpd_release_lock(genpd); - if (gpd_data != gpd_data_new) - genpd_free_dev_data(dev, gpd_data_new); + if (ret) + genpd_free_dev_data(dev, gpd_data); + else + dev_pm_qos_add_notifier(dev, &gpd_data->nb); return ret; } @@ -1509,6 +1498,11 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, || pd_to_genpd(dev->pm_domain) != genpd) return -EINVAL; + /* The above validation also means we have existing domain_data. */ + pdd = dev->power.subsys_data->domain_data; + gpd_data = to_gpd_data(pdd); + dev_pm_qos_remove_notifier(dev, &gpd_data->nb); + genpd_acquire_lock(genpd); if (genpd->prepared_count > 0) { @@ -1525,16 +1519,12 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, spin_lock_irq(&dev->power.lock); dev->pm_domain = NULL; - pdd = dev->power.subsys_data->domain_data; list_del_init(&pdd->list_node); - gpd_data = to_gpd_data(pdd); dev->power.subsys_data->domain_data = NULL; spin_unlock_irq(&dev->power.lock); - mutex_lock(&gpd_data->lock); pdd->dev = NULL; - mutex_unlock(&gpd_data->lock); genpd_release_lock(genpd); @@ -1545,6 +1535,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, out: genpd_release_lock(genpd); + dev_pm_qos_add_notifier(dev, &gpd_data->nb); return ret; } diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index e160a0b..080e778 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -113,7 +113,6 @@ struct generic_pm_domain_data { struct pm_domain_data base; struct gpd_timing_data td; struct notifier_block nb; - struct mutex lock; int need_restore; }; -- cgit v0.10.2 From 3e235685de3f7e53e17d671b2379df10c6dfa4f2 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 27 Jan 2015 21:13:43 +0100 Subject: PM / Domains: Free pm_subsys_data in error path in __pm_genpd_add_device() The error path in __pm_genpd_add_device() didn't decrease the reference to the struct pm_subsys_data. Let's move the calls to dev_pm_get|put_subsys_data() into genpd_alloc|free_dev_data() to fix this issue and thus prevent a potential memory leakage. Signed-off-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 1f026c1..3bd342f 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1380,18 +1380,30 @@ EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron); static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev) { struct generic_pm_domain_data *gpd_data; + int ret; + + ret = dev_pm_get_subsys_data(dev); + if (ret) + return ERR_PTR(ret); gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL); - if (!gpd_data) - return NULL; + if (!gpd_data) { + ret = -ENOMEM; + goto err_put; + } return gpd_data; + + err_put: + dev_pm_put_subsys_data(dev); + return ERR_PTR(ret); } static void genpd_free_dev_data(struct device *dev, struct generic_pm_domain_data *gpd_data) { kfree(gpd_data); + dev_pm_put_subsys_data(dev); } /** @@ -1412,8 +1424,8 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, return -EINVAL; gpd_data = genpd_alloc_dev_data(dev); - if (!gpd_data) - return -ENOMEM; + if (IS_ERR(gpd_data)) + return PTR_ERR(gpd_data); genpd_acquire_lock(genpd); @@ -1422,10 +1434,6 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, goto out; } - ret = dev_pm_get_subsys_data(dev); - if (ret) - goto out; - spin_lock_irq(&dev->power.lock); if (dev->power.subsys_data->domain_data) { @@ -1528,7 +1536,6 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, genpd_release_lock(genpd); - dev_pm_put_subsys_data(dev); genpd_free_dev_data(dev, gpd_data); return 0; -- cgit v0.10.2 From f104e1e5ef5788f02de2053bfbd0f02d629b6036 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 27 Jan 2015 21:13:44 +0100 Subject: PM / Domains: Re-order initialization of generic_pm_domain_data Move the initialization of the struct generic_pm_domain_data into genpd_alloc_dev_data(), including the assignment of the device's ->pm_domain() callback. Make corresponding changes to genpd_free_dev_data(). These changes will make the related code more readable. It will also decrease the critical regions for where genpd's mutex is being held and for where the device's power related spinlock is being held. Signed-off-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 3bd342f..0fd5ee1 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1377,7 +1377,9 @@ EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron); #endif /* CONFIG_PM_SLEEP */ -static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev) +static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev, + struct generic_pm_domain *genpd, + struct gpd_timing_data *td) { struct generic_pm_domain_data *gpd_data; int ret; @@ -1392,8 +1394,32 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev) goto err_put; } + if (td) + gpd_data->td = *td; + + gpd_data->base.dev = dev; + gpd_data->need_restore = -1; + gpd_data->td.constraint_changed = true; + gpd_data->td.effective_constraint_ns = -1; + gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier; + + spin_lock_irq(&dev->power.lock); + + if (dev->power.subsys_data->domain_data) { + ret = -EINVAL; + goto err_free; + } + + dev->power.subsys_data->domain_data = &gpd_data->base; + dev->pm_domain = &genpd->domain; + + spin_unlock_irq(&dev->power.lock); + return gpd_data; + err_free: + spin_unlock_irq(&dev->power.lock); + kfree(gpd_data); err_put: dev_pm_put_subsys_data(dev); return ERR_PTR(ret); @@ -1402,6 +1428,13 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev) static void genpd_free_dev_data(struct device *dev, struct generic_pm_domain_data *gpd_data) { + spin_lock_irq(&dev->power.lock); + + dev->pm_domain = NULL; + dev->power.subsys_data->domain_data = NULL; + + spin_unlock_irq(&dev->power.lock); + kfree(gpd_data); dev_pm_put_subsys_data(dev); } @@ -1423,7 +1456,7 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)) return -EINVAL; - gpd_data = genpd_alloc_dev_data(dev); + gpd_data = genpd_alloc_dev_data(dev, genpd, td); if (IS_ERR(gpd_data)) return PTR_ERR(gpd_data); @@ -1434,35 +1467,13 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, goto out; } - spin_lock_irq(&dev->power.lock); - - if (dev->power.subsys_data->domain_data) { - spin_unlock_irq(&dev->power.lock); - ret = -EINVAL; - goto out; - } - - dev->power.subsys_data->domain_data = &gpd_data->base; - - if (td) - gpd_data->td = *td; - - dev->pm_domain = &genpd->domain; - - spin_unlock_irq(&dev->power.lock); - if (genpd->attach_dev) genpd->attach_dev(genpd, dev); genpd->device_count++; genpd->max_off_time_changed = true; - gpd_data->base.dev = dev; list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); - gpd_data->need_restore = -1; - gpd_data->td.constraint_changed = true; - gpd_data->td.effective_constraint_ns = -1; - gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier; out: genpd_release_lock(genpd); @@ -1524,15 +1535,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, if (genpd->detach_dev) genpd->detach_dev(genpd, dev); - spin_lock_irq(&dev->power.lock); - - dev->pm_domain = NULL; list_del_init(&pdd->list_node); - dev->power.subsys_data->domain_data = NULL; - - spin_unlock_irq(&dev->power.lock); - - pdd->dev = NULL; genpd_release_lock(genpd); -- cgit v0.10.2 From b472c2faf471b72e7f3ffe35200dfb3d227487b7 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 27 Jan 2015 21:13:45 +0100 Subject: PM / Domains: Handle errors from genpd's ->attach_dev() callback The optional genpd's ->attach_dev() callback is invoked from __pm_genpd_add_device(). Let's add error handling from the response from this callback and propagate the error code. When __pm_genpd_add_device() is invoked through the generic OF-based PM domain look-up path, the device is being probed. Returning an error will mean the device won't be attached to its PM domain. Errors of -EPROBE_DEFER get special treatment and is propagated to the driver core. Therefore this change also enables the ->attach_dev() callback to be able to request for a deferred probe sequence. Signed-off-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 0fd5ee1..ba4abbe 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1467,8 +1467,9 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, goto out; } - if (genpd->attach_dev) - genpd->attach_dev(genpd, dev); + ret = genpd->attach_dev ? genpd->attach_dev(genpd, dev) : 0; + if (ret) + goto out; genpd->device_count++; genpd->max_off_time_changed = true; -- cgit v0.10.2 From 766bb53c015bcc28dbd5ceb7c004581af7ab51b2 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 29 Jan 2015 18:39:04 +0100 Subject: PM: Update function header for dev_pm_get_subsys_data() The commit "PM: Make dev_pm_get_subsys_data() always return 0 on success" changed the return value from dev_pm_get_subsys_data(). Let's update the comment in the function header to reflect this change as well. Signed-off-by: Ulf Hansson Acked-by: Geert Uytterhoeven Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c index b0f1388..a1ee51d 100644 --- a/drivers/base/power/common.c +++ b/drivers/base/power/common.c @@ -19,8 +19,8 @@ * @dev: Device to handle. * * If power.subsys_data is NULL, point it to a new object, otherwise increment - * its reference counter. Return 1 if a new object has been created, otherwise - * return 0 or error code. + * its reference counter. Return 0 if new object has been created or refcount + * increased, otherwise negative error code. */ int dev_pm_get_subsys_data(struct device *dev) { -- cgit v0.10.2 From 1e95e3b2da424db68d0a465273f1901a990c6277 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 29 Jan 2015 18:39:05 +0100 Subject: PM: Convert dev_pm_put_subsys_data() into a void function Clients using the dev_pm_put_subsys_data() API isn't interested of a return value. They care only of decreasing a reference to the device's pm_subsys_data. So, let's convert the API to a void function, which anyway seems like reasonable thing to do. Signed-off-by: Ulf Hansson Acked-by: Geert Uytterhoeven Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c index a1ee51d..f32b802 100644 --- a/drivers/base/power/common.c +++ b/drivers/base/power/common.c @@ -56,13 +56,11 @@ EXPORT_SYMBOL_GPL(dev_pm_get_subsys_data); * @dev: Device to handle. * * If the reference counter of power.subsys_data is zero after dropping the - * reference, power.subsys_data is removed. Return 1 if that happens or 0 - * otherwise. + * reference, power.subsys_data is removed. */ -int dev_pm_put_subsys_data(struct device *dev) +void dev_pm_put_subsys_data(struct device *dev) { struct pm_subsys_data *psd; - int ret = 1; spin_lock_irq(&dev->power.lock); @@ -70,18 +68,14 @@ int dev_pm_put_subsys_data(struct device *dev) if (!psd) goto out; - if (--psd->refcount == 0) { + if (--psd->refcount == 0) dev->power.subsys_data = NULL; - } else { + else psd = NULL; - ret = 0; - } out: spin_unlock_irq(&dev->power.lock); kfree(psd); - - return ret; } EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data); diff --git a/include/linux/pm.h b/include/linux/pm.h index 8b59763..e2f1be6 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -597,7 +597,7 @@ struct dev_pm_info { extern void update_pm_runtime_accounting(struct device *dev); extern int dev_pm_get_subsys_data(struct device *dev); -extern int dev_pm_put_subsys_data(struct device *dev); +extern void dev_pm_put_subsys_data(struct device *dev); /* * Power domains provide callbacks that are executed during system suspend, -- cgit v0.10.2 From 1e63eaf0c45f0ac733ef2818cd93e3e9047ef1c5 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 27 Jan 2015 14:06:07 +0530 Subject: cpufreq: Drop cpufreq_disabled() check from cpufreq_cpu_{get|put}() When cpufreq is disabled, the per-cpu variable would have been set to NULL. Remove this unnecessary check. [ Changelog from Saravana Kannan. ] Signed-off-by: Viresh Kumar Acked-by: Saravana Kannan Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 2b181f7..1587094 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -203,7 +203,7 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) struct cpufreq_policy *policy = NULL; unsigned long flags; - if (cpufreq_disabled() || (cpu >= nr_cpu_ids)) + if (cpu >= nr_cpu_ids) return NULL; if (!down_read_trylock(&cpufreq_rwsem)) @@ -230,9 +230,6 @@ EXPORT_SYMBOL_GPL(cpufreq_cpu_get); void cpufreq_cpu_put(struct cpufreq_policy *policy) { - if (cpufreq_disabled()) - return; - kobject_put(&policy->kobj); up_read(&cpufreq_rwsem); } -- cgit v0.10.2 From b4f0676fe20da6abe4577cf960862bed7a31647e Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 27 Jan 2015 14:06:08 +0530 Subject: cpufreq: Create for_each_policy() To make code more readable and less error prone, lets create a helper macro for iterating over all active policies. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 1587094..baa238f 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -31,6 +31,12 @@ #include #include +/* Macros to iterate over lists */ +/* Iterate over online CPUs policies */ +static LIST_HEAD(cpufreq_policy_list); +#define for_each_policy(__policy) \ + list_for_each_entry(__policy, &cpufreq_policy_list, policy_list) + /** * The "cpufreq driver" - the arch- or hardware-dependent low * level driver of CPUFreq support, and its spinlock. This lock @@ -41,7 +47,6 @@ static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback); static DEFINE_RWLOCK(cpufreq_driver_lock); DEFINE_MUTEX(cpufreq_governor_lock); -static LIST_HEAD(cpufreq_policy_list); /* This one keeps track of the previously set governor of a removed CPU */ static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); @@ -1113,7 +1118,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) /* Check if this cpu was hot-unplugged earlier and has siblings */ read_lock_irqsave(&cpufreq_driver_lock, flags); - list_for_each_entry(policy, &cpufreq_policy_list, policy_list) { + for_each_policy(policy) { if (cpumask_test_cpu(cpu, policy->related_cpus)) { read_unlock_irqrestore(&cpufreq_driver_lock, flags); ret = cpufreq_add_policy_cpu(policy, cpu, dev); @@ -1647,7 +1652,7 @@ void cpufreq_suspend(void) pr_debug("%s: Suspending Governors\n", __func__); - list_for_each_entry(policy, &cpufreq_policy_list, policy_list) { + for_each_policy(policy) { if (__cpufreq_governor(policy, CPUFREQ_GOV_STOP)) pr_err("%s: Failed to stop governor for policy: %p\n", __func__, policy); @@ -1681,7 +1686,7 @@ void cpufreq_resume(void) pr_debug("%s: Resuming Governors\n", __func__); - list_for_each_entry(policy, &cpufreq_policy_list, policy_list) { + for_each_policy(policy) { if (cpufreq_driver->resume && cpufreq_driver->resume(policy)) pr_err("%s: Failed to resume driver: %p\n", __func__, policy); @@ -2324,7 +2329,7 @@ static int cpufreq_boost_set_sw(int state) struct cpufreq_policy *policy; int ret = -EINVAL; - list_for_each_entry(policy, &cpufreq_policy_list, policy_list) { + for_each_policy(policy) { freq_table = cpufreq_frequency_get_table(policy->cpu); if (freq_table) { ret = cpufreq_frequency_table_cpuinfo(policy, -- cgit v0.10.2 From f7b2706117bc4459cd748352cbe4ae69a41c8ed6 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 27 Jan 2015 14:06:09 +0530 Subject: cpufreq: Create for_each_governor() To make code more readable and less error prone, lets create a helper macro for iterating over all available governors. Signed-off-by: Viresh Kumar Acked-by: Saravana Kannan Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index baa238f..28e59a4 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -37,6 +37,11 @@ static LIST_HEAD(cpufreq_policy_list); #define for_each_policy(__policy) \ list_for_each_entry(__policy, &cpufreq_policy_list, policy_list) +/* Iterate over governors */ +static LIST_HEAD(cpufreq_governor_list); +#define for_each_governor(__governor) \ + list_for_each_entry(__governor, &cpufreq_governor_list, governor_list) + /** * The "cpufreq driver" - the arch- or hardware-dependent low * level driver of CPUFreq support, and its spinlock. This lock @@ -99,7 +104,6 @@ void disable_cpufreq(void) { off = 1; } -static LIST_HEAD(cpufreq_governor_list); static DEFINE_MUTEX(cpufreq_governor_mutex); bool have_governor_per_policy(void) @@ -434,7 +438,7 @@ static struct cpufreq_governor *find_governor(const char *str_governor) { struct cpufreq_governor *t; - list_for_each_entry(t, &cpufreq_governor_list, governor_list) + for_each_governor(t) if (!strncasecmp(str_governor, t->name, CPUFREQ_NAME_LEN)) return t; @@ -636,7 +640,7 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy, goto out; } - list_for_each_entry(t, &cpufreq_governor_list, governor_list) { + for_each_governor(t) { if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char)) - (CPUFREQ_NAME_LEN + 2))) goto out; -- cgit v0.10.2 From 17ad13ba842bd5c197e20c17e107788aa0498ba9 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 3 Feb 2015 19:21:21 +0100 Subject: cpufreq-dt: Drop unnecessary check before cpufreq_cooling_unregister() invocation The cpufreq_cooling_unregister() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring [ rjw: Subject ] Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index fde97d6..bab67db 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -320,8 +320,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy) { struct private_data *priv = policy->driver_data; - if (priv->cdev) - cpufreq_cooling_unregister(priv->cdev); + cpufreq_cooling_unregister(priv->cdev); dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); of_free_opp_table(priv->cpu_dev); clk_put(policy->clk); -- cgit v0.10.2 From efd756daf4ddae3cec2404c4e0b680b7cfdd6a45 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 5 Feb 2015 00:40:08 +0100 Subject: ACPI / PCC: Use pr_debug() for debug messages in pcc_init() pcc_init() uses pr_err() to print two messages that are really debug and not interesting to users. Replace those pr_err() with pr_debug(). Reported-by: Cristian Signed-off-by: Rafael J. Wysocki diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index 6dbf6fc..e8902f8 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -386,7 +386,7 @@ static int __init pcc_init(void) ret = acpi_pcc_probe(); if (ret) { - pr_err("ACPI PCC probe failed.\n"); + pr_debug("ACPI PCC probe failed.\n"); return -ENODEV; } @@ -394,7 +394,7 @@ static int __init pcc_init(void) pcc_mbox_probe, NULL, 0, NULL, 0); if (!pcc_pdev) { - pr_err("Err creating PCC platform bundle\n"); + pr_debug("Err creating PCC platform bundle\n"); return -ENODEV; } -- cgit v0.10.2 From 90e97820619dc912b52cc9d103272819d8b51259 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 5 Feb 2015 13:44:43 +0800 Subject: resources: Move struct resource_list_entry from ACPI into resource core Currently ACPI, PCI and pnp all implement the same resource list management with different data structure. We need to transfer from one data structure into another when passing resources from one subsystem into another subsystem. So move struct resource_list_entry from ACPI into resource core and rename it as resource_entry, then it could be reused by different subystems and avoid the data structure conversion. Introduce dedicated header file resource_ext.h instead of embedding it into ioport.h to avoid header file inclusion order issues. Signed-off-by: Jiang Liu Acked-by: Vinod Koul Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 4f3febf..dfd1b80 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -313,7 +313,7 @@ static int acpi_lpss_create_device(struct acpi_device *adev, { struct lpss_device_desc *dev_desc; struct lpss_private_data *pdata; - struct resource_list_entry *rentry; + struct resource_entry *rentry; struct list_head resource_list; struct platform_device *pdev; int ret; @@ -333,12 +333,12 @@ static int acpi_lpss_create_device(struct acpi_device *adev, goto err_out; list_for_each_entry(rentry, &resource_list, node) - if (resource_type(&rentry->res) == IORESOURCE_MEM) { + if (resource_type(rentry->res) == IORESOURCE_MEM) { if (dev_desc->prv_size_override) pdata->mmio_size = dev_desc->prv_size_override; else - pdata->mmio_size = resource_size(&rentry->res); - pdata->mmio_base = ioremap(rentry->res.start, + pdata->mmio_size = resource_size(rentry->res); + pdata->mmio_base = ioremap(rentry->res->start, pdata->mmio_size); break; } diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index 6ba8beb..1284138 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -45,7 +45,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) struct platform_device *pdev = NULL; struct acpi_device *acpi_parent; struct platform_device_info pdevinfo; - struct resource_list_entry *rentry; + struct resource_entry *rentry; struct list_head resource_list; struct resource *resources = NULL; int count; @@ -71,7 +71,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) } count = 0; list_for_each_entry(rentry, &resource_list, node) - resources[count++] = rentry->res; + resources[count++] = *rentry->res; acpi_dev_free_resource_list(&resource_list); } diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 3ea0d17..4752b99 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -444,12 +444,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt); */ void acpi_dev_free_resource_list(struct list_head *list) { - struct resource_list_entry *rentry, *re; - - list_for_each_entry_safe(rentry, re, list, node) { - list_del(&rentry->node); - kfree(rentry); - } + resource_list_free(list); } EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list); @@ -464,16 +459,16 @@ struct res_proc_context { static acpi_status acpi_dev_new_resource_entry(struct resource_win *win, struct res_proc_context *c) { - struct resource_list_entry *rentry; + struct resource_entry *rentry; - rentry = kmalloc(sizeof(*rentry), GFP_KERNEL); + rentry = resource_list_create_entry(NULL, 0); if (!rentry) { c->error = -ENOMEM; return AE_NO_MEMORY; } - rentry->res = win->res; + *rentry->res = win->res; rentry->offset = win->offset; - list_add_tail(&rentry->node, c->list); + resource_list_add_tail(rentry, c->list); c->count++; return AE_OK; } @@ -534,7 +529,7 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, * returned as the final error code. * * The resultant struct resource objects are put on the list pointed to by - * @list, that must be empty initially, as members of struct resource_list_entry + * @list, that must be empty initially, as members of struct resource_entry * objects. Callers of this routine should use %acpi_dev_free_resource_list() to * free that list. * diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c index de361a1..5a63564 100644 --- a/drivers/dma/acpi-dma.c +++ b/drivers/dma/acpi-dma.c @@ -43,7 +43,7 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp, { const struct acpi_csrt_shared_info *si; struct list_head resource_list; - struct resource_list_entry *rentry; + struct resource_entry *rentry; resource_size_t mem = 0, irq = 0; int ret; @@ -56,10 +56,10 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp, return 0; list_for_each_entry(rentry, &resource_list, node) { - if (resource_type(&rentry->res) == IORESOURCE_MEM) - mem = rentry->res.start; - else if (resource_type(&rentry->res) == IORESOURCE_IRQ) - irq = rentry->res.start; + if (resource_type(rentry->res) == IORESOURCE_MEM) + mem = rentry->res->start; + else if (resource_type(rentry->res) == IORESOURCE_IRQ) + irq = rentry->res->start; } acpi_dev_free_resource_list(&resource_list); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index e818dec..e538221 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -27,6 +27,7 @@ #include #include /* for struct resource */ +#include #include #include @@ -285,11 +286,6 @@ extern int pnpacpi_disabled; #define PXM_INVAL (-1) -struct resource_win { - struct resource res; - resource_size_t offset; -}; - bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res); bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res); bool acpi_dev_resource_address_space(struct acpi_resource *ares, @@ -300,12 +296,6 @@ unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable); bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, struct resource *res); -struct resource_list_entry { - struct list_head node; - struct resource res; - resource_size_t offset; -}; - void acpi_dev_free_resource_list(struct list_head *list); int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, int (*preproc)(struct acpi_resource *, void *), diff --git a/include/linux/resource_ext.h b/include/linux/resource_ext.h new file mode 100644 index 0000000..e2bf63d --- /dev/null +++ b/include/linux/resource_ext.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2015, Intel Corporation + * Author: Jiang Liu + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + */ +#ifndef _LINUX_RESOURCE_EXT_H +#define _LINUX_RESOURCE_EXT_H +#include +#include +#include +#include + +/* Represent resource window for bridge devices */ +struct resource_win { + struct resource res; /* In master (CPU) address space */ + resource_size_t offset; /* Translation offset for bridge */ +}; + +/* + * Common resource list management data structure and interfaces to support + * ACPI, PNP and PCI host bridge etc. + */ +struct resource_entry { + struct list_head node; + struct resource *res; /* In master (CPU) address space */ + resource_size_t offset; /* Translation offset for bridge */ + struct resource __res; /* Default storage for res */ +}; + +extern struct resource_entry * +resource_list_create_entry(struct resource *res, size_t extra_size); +extern void resource_list_free(struct list_head *head); + +static inline void resource_list_add(struct resource_entry *entry, + struct list_head *head) +{ + list_add(&entry->node, head); +} + +static inline void resource_list_add_tail(struct resource_entry *entry, + struct list_head *head) +{ + list_add_tail(&entry->node, head); +} + +static inline void resource_list_del(struct resource_entry *entry) +{ + list_del(&entry->node); +} + +static inline void resource_list_free_entry(struct resource_entry *entry) +{ + kfree(entry); +} + +static inline void +resource_list_destroy_entry(struct resource_entry *entry) +{ + resource_list_del(entry); + resource_list_free_entry(entry); +} + +#define resource_list_for_each_entry(entry, list) \ + list_for_each_entry((entry), (list), node) + +#define resource_list_for_each_entry_safe(entry, tmp, list) \ + list_for_each_entry_safe((entry), (tmp), (list), node) + +#endif /* _LINUX_RESOURCE_EXT_H */ diff --git a/kernel/resource.c b/kernel/resource.c index 0bcebff..19f2357 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -1529,6 +1530,30 @@ int iomem_is_exclusive(u64 addr) return err; } +struct resource_entry *resource_list_create_entry(struct resource *res, + size_t extra_size) +{ + struct resource_entry *entry; + + entry = kzalloc(sizeof(*entry) + extra_size, GFP_KERNEL); + if (entry) { + INIT_LIST_HEAD(&entry->node); + entry->res = res ? res : &entry->__res; + } + + return entry; +} +EXPORT_SYMBOL(resource_list_create_entry); + +void resource_list_free(struct list_head *head) +{ + struct resource_entry *entry, *tmp; + + list_for_each_entry_safe(entry, tmp, head, node) + resource_list_destroy_entry(entry); +} +EXPORT_SYMBOL(resource_list_free); + static int __init strict_iomem(char *str) { if (strstr(str, "relaxed")) -- cgit v0.10.2 From 14d76b68f2819a1d0b50236a7e9e9f2ea69869d9 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 5 Feb 2015 13:44:44 +0800 Subject: PCI: Use common resource list management code instead of private implementation Use common resource list management data structure and interfaces instead of private implementation. Signed-off-by: Jiang Liu Acked-by: Will Deacon Acked-by: Bjorn Helgaas Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index a4effd6..0169917 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -422,17 +422,16 @@ static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) static int pcibios_init_resources(int busnr, struct pci_sys_data *sys) { int ret; - struct pci_host_bridge_window *window; + struct resource_entry *window; if (list_empty(&sys->resources)) { pci_add_resource_offset(&sys->resources, &iomem_resource, sys->mem_offset); } - list_for_each_entry(window, &sys->resources, list) { + resource_list_for_each_entry(window, &sys->resources) if (resource_type(window->res) == IORESOURCE_IO) return 0; - } sys->io_res.start = (busnr * SZ_64K) ? : pcibios_min_io; sys->io_res.end = (busnr + 1) * SZ_64K - 1; diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c index f3a2cfc..7bcf06a 100644 --- a/arch/x86/pci/bus_numa.c +++ b/arch/x86/pci/bus_numa.c @@ -31,7 +31,7 @@ void x86_pci_root_bus_resources(int bus, struct list_head *resources) { struct pci_root_info *info = x86_find_pci_root_info(bus); struct pci_root_res *root_res; - struct pci_host_bridge_window *window; + struct resource_entry *window; bool found = false; if (!info) @@ -41,7 +41,7 @@ void x86_pci_root_bus_resources(int bus, struct list_head *resources) bus); /* already added by acpi ? */ - list_for_each_entry(window, resources, list) + resource_list_for_each_entry(window, resources) if (window->res->flags & IORESOURCE_BUS) { found = true; break; diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 8fb1618..90fa3a7 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -20,17 +20,16 @@ void pci_add_resource_offset(struct list_head *resources, struct resource *res, resource_size_t offset) { - struct pci_host_bridge_window *window; + struct resource_entry *entry; - window = kzalloc(sizeof(struct pci_host_bridge_window), GFP_KERNEL); - if (!window) { + entry = resource_list_create_entry(res, 0); + if (!entry) { printk(KERN_ERR "PCI: can't add host bridge window %pR\n", res); return; } - window->res = res; - window->offset = offset; - list_add_tail(&window->list, resources); + entry->offset = offset; + resource_list_add_tail(entry, resources); } EXPORT_SYMBOL(pci_add_resource_offset); @@ -42,12 +41,7 @@ EXPORT_SYMBOL(pci_add_resource); void pci_free_resource_list(struct list_head *resources) { - struct pci_host_bridge_window *window, *tmp; - - list_for_each_entry_safe(window, tmp, resources, list) { - list_del(&window->list); - kfree(window); - } + resource_list_free(resources); } EXPORT_SYMBOL(pci_free_resource_list); diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c index 0e5f3c9..39b2dbe 100644 --- a/drivers/pci/host-bridge.c +++ b/drivers/pci/host-bridge.c @@ -35,10 +35,10 @@ void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region, struct resource *res) { struct pci_host_bridge *bridge = find_pci_host_bridge(bus); - struct pci_host_bridge_window *window; + struct resource_entry *window; resource_size_t offset = 0; - list_for_each_entry(window, &bridge->windows, list) { + resource_list_for_each_entry(window, &bridge->windows) { if (resource_contains(window->res, res)) { offset = window->offset; break; @@ -60,10 +60,10 @@ void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res, struct pci_bus_region *region) { struct pci_host_bridge *bridge = find_pci_host_bridge(bus); - struct pci_host_bridge_window *window; + struct resource_entry *window; resource_size_t offset = 0; - list_for_each_entry(window, &bridge->windows, list) { + resource_list_for_each_entry(window, &bridge->windows) { struct pci_bus_region bus_region; if (resource_type(res) != resource_type(window->res)) diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c index 6eb1aa7..aee3c62 100644 --- a/drivers/pci/host/pci-host-generic.c +++ b/drivers/pci/host/pci-host-generic.c @@ -149,14 +149,14 @@ static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci) struct device *dev = pci->host.dev.parent; struct device_node *np = dev->of_node; resource_size_t iobase; - struct pci_host_bridge_window *win; + struct resource_entry *win; err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources, &iobase); if (err) return err; - list_for_each_entry(win, &pci->resources, list) { + resource_list_for_each_entry(win, &pci->resources) { struct resource *parent, *res = win->res; switch (resource_type(res)) { diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c index b1d0596..a704257 100644 --- a/drivers/pci/host/pci-xgene.c +++ b/drivers/pci/host/pci-xgene.c @@ -401,11 +401,11 @@ static int xgene_pcie_map_ranges(struct xgene_pcie_port *port, struct list_head *res, resource_size_t io_base) { - struct pci_host_bridge_window *window; + struct resource_entry *window; struct device *dev = port->dev; int ret; - list_for_each_entry(window, res, list) { + resource_list_for_each_entry(window, res) { struct resource *res = window->res; u64 restype = resource_type(res); diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c index ef3ebaf..601261df 100644 --- a/drivers/pci/host/pcie-xilinx.c +++ b/drivers/pci/host/pcie-xilinx.c @@ -737,7 +737,7 @@ static int xilinx_pcie_parse_and_add_res(struct xilinx_pcie_port *port) resource_size_t offset; struct of_pci_range_parser parser; struct of_pci_range range; - struct pci_host_bridge_window *win; + struct resource_entry *win; int err = 0, mem_resno = 0; /* Get the ranges */ @@ -807,7 +807,7 @@ static int xilinx_pcie_parse_and_add_res(struct xilinx_pcie_port *port) free_resources: release_child_resources(&iomem_resource); - list_for_each_entry(win, &port->resources, list) + resource_list_for_each_entry(win, &port->resources) devm_kfree(dev, win->res); pci_free_resource_list(&port->resources); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 23212f8..8d2f400 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1895,7 +1895,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, int error; struct pci_host_bridge *bridge; struct pci_bus *b, *b2; - struct pci_host_bridge_window *window, *n; + struct resource_entry *window, *n; struct resource *res; resource_size_t offset; char bus_addr[64]; @@ -1959,8 +1959,8 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, printk(KERN_INFO "PCI host bridge to bus %s\n", dev_name(&b->dev)); /* Add initial resources to the bus */ - list_for_each_entry_safe(window, n, resources, list) { - list_move_tail(&window->list, &bridge->windows); + resource_list_for_each_entry_safe(window, n, resources) { + list_move_tail(&window->node, &bridge->windows); res = window->res; offset = window->offset; if (res->flags & IORESOURCE_BUS) @@ -2060,12 +2060,12 @@ void pci_bus_release_busn_res(struct pci_bus *b) struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata, struct list_head *resources) { - struct pci_host_bridge_window *window; + struct resource_entry *window; bool found = false; struct pci_bus *b; int max; - list_for_each_entry(window, resources, list) + resource_list_for_each_entry(window, resources) if (window->res->flags & IORESOURCE_BUS) { found = true; break; diff --git a/include/linux/pci.h b/include/linux/pci.h index 9603094..faa60fa 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -397,16 +398,10 @@ static inline int pci_channel_offline(struct pci_dev *pdev) return (pdev->error_state != pci_channel_io_normal); } -struct pci_host_bridge_window { - struct list_head list; - struct resource *res; /* host bridge aperture (CPU address) */ - resource_size_t offset; /* bus address + offset = CPU address */ -}; - struct pci_host_bridge { struct device dev; struct pci_bus *bus; /* root bus */ - struct list_head windows; /* pci_host_bridge_windows */ + struct list_head windows; /* resource_entry */ void (*release_fn)(struct pci_host_bridge *); void *release_data; }; -- cgit v0.10.2 From 812dbd9994f122629db73205a7f7f46b430a6360 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 5 Feb 2015 13:44:45 +0800 Subject: x86/PCI: Fix the range check for IO resources The range check in setup_res() checks the IO range against iomem_resource. That's just wrong. Reworked based on Thomas original patch. Signed-off-by: Thomas Gleixner Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index bb98afd..1d725d9 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -283,7 +283,7 @@ static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data) struct acpi_resource_address64 addr; acpi_status status; unsigned long flags; - u64 start, orig_end, end; + u64 start, orig_end, end, res_end; status = resource_to_addr(acpi_res, &addr); if (!ACPI_SUCCESS(status)) @@ -293,8 +293,10 @@ static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data) flags = IORESOURCE_MEM; if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY) flags |= IORESOURCE_PREFETCH; + res_end = (u64)iomem_resource.end; } else if (addr.resource_type == ACPI_IO_RANGE) { flags = IORESOURCE_IO; + res_end = (u64)ioport_resource.end; } else return AE_OK; @@ -302,7 +304,7 @@ static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data) orig_end = end = addr.address.maximum + addr.address.translation_offset; /* Exclude non-addressable range or non-addressable portion of range */ - end = min(end, (u64)iomem_resource.end); + end = min(end, res_end); if (end <= start) { dev_info(&info->bridge->dev, "host bridge window [%#llx-%#llx] " -- cgit v0.10.2 From 593669c2ac0fe18baee04a3cd5539a148aa48574 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 5 Feb 2015 13:44:46 +0800 Subject: x86/PCI/ACPI: Use common ACPI resource interfaces to simplify implementation Use common ACPI resource discovery interfaces to simplify PCI host bridge resource enumeration. Signed-off-by: Jiang Liu Acked-by: Bjorn Helgaas Signed-off-by: Rafael J. Wysocki diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 1d725d9..6ac2738 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -10,9 +10,6 @@ struct pci_root_info { struct acpi_device *bridge; char name[16]; - unsigned int res_num; - struct resource *res; - resource_size_t *res_offset; struct pci_sysdata sd; #ifdef CONFIG_PCI_MMCONFIG bool mcfg_added; @@ -218,132 +215,41 @@ static void teardown_mcfg_map(struct pci_root_info *info) } #endif -static acpi_status resource_to_addr(struct acpi_resource *resource, - struct acpi_resource_address64 *addr) -{ - acpi_status status; - struct acpi_resource_memory24 *memory24; - struct acpi_resource_memory32 *memory32; - struct acpi_resource_fixed_memory32 *fixed_memory32; - - memset(addr, 0, sizeof(*addr)); - switch (resource->type) { - case ACPI_RESOURCE_TYPE_MEMORY24: - memory24 = &resource->data.memory24; - addr->resource_type = ACPI_MEMORY_RANGE; - addr->address.minimum = memory24->minimum; - addr->address.address_length = memory24->address_length; - addr->address.maximum = addr->address.minimum + addr->address.address_length - 1; - return AE_OK; - case ACPI_RESOURCE_TYPE_MEMORY32: - memory32 = &resource->data.memory32; - addr->resource_type = ACPI_MEMORY_RANGE; - addr->address.minimum = memory32->minimum; - addr->address.address_length = memory32->address_length; - addr->address.maximum = addr->address.minimum + addr->address.address_length - 1; - return AE_OK; - case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - fixed_memory32 = &resource->data.fixed_memory32; - addr->resource_type = ACPI_MEMORY_RANGE; - addr->address.minimum = fixed_memory32->address; - addr->address.address_length = fixed_memory32->address_length; - addr->address.maximum = addr->address.minimum + addr->address.address_length - 1; - return AE_OK; - case ACPI_RESOURCE_TYPE_ADDRESS16: - case ACPI_RESOURCE_TYPE_ADDRESS32: - case ACPI_RESOURCE_TYPE_ADDRESS64: - status = acpi_resource_to_address64(resource, addr); - if (ACPI_SUCCESS(status) && - (addr->resource_type == ACPI_MEMORY_RANGE || - addr->resource_type == ACPI_IO_RANGE) && - addr->address.address_length > 0) { - return AE_OK; - } - break; - } - return AE_ERROR; -} - -static acpi_status count_resource(struct acpi_resource *acpi_res, void *data) +static void validate_resources(struct device *dev, struct list_head *crs_res, + unsigned long type) { - struct pci_root_info *info = data; - struct acpi_resource_address64 addr; - acpi_status status; - - status = resource_to_addr(acpi_res, &addr); - if (ACPI_SUCCESS(status)) - info->res_num++; - return AE_OK; -} - -static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data) -{ - struct pci_root_info *info = data; - struct resource *res; - struct acpi_resource_address64 addr; - acpi_status status; - unsigned long flags; - u64 start, orig_end, end, res_end; - - status = resource_to_addr(acpi_res, &addr); - if (!ACPI_SUCCESS(status)) - return AE_OK; - - if (addr.resource_type == ACPI_MEMORY_RANGE) { - flags = IORESOURCE_MEM; - if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY) - flags |= IORESOURCE_PREFETCH; - res_end = (u64)iomem_resource.end; - } else if (addr.resource_type == ACPI_IO_RANGE) { - flags = IORESOURCE_IO; - res_end = (u64)ioport_resource.end; - } else - return AE_OK; - - start = addr.address.minimum + addr.address.translation_offset; - orig_end = end = addr.address.maximum + addr.address.translation_offset; - - /* Exclude non-addressable range or non-addressable portion of range */ - end = min(end, res_end); - if (end <= start) { - dev_info(&info->bridge->dev, - "host bridge window [%#llx-%#llx] " - "(ignored, not CPU addressable)\n", start, orig_end); - return AE_OK; - } else if (orig_end != end) { - dev_info(&info->bridge->dev, - "host bridge window [%#llx-%#llx] " - "([%#llx-%#llx] ignored, not CPU addressable)\n", - start, orig_end, end + 1, orig_end); - } + LIST_HEAD(list); + struct resource *res1, *res2, *root = NULL; + struct resource_entry *tmp, *entry, *entry2; - res = &info->res[info->res_num]; - res->name = info->name; - res->flags = flags; - res->start = start; - res->end = end; - info->res_offset[info->res_num] = addr.address.translation_offset; - info->res_num++; + BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0); + root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource; - if (!pci_use_crs) - dev_printk(KERN_DEBUG, &info->bridge->dev, - "host bridge window %pR (ignored)\n", res); + list_splice_init(crs_res, &list); + resource_list_for_each_entry_safe(entry, tmp, &list) { + bool free = false; + resource_size_t end; - return AE_OK; -} - -static void coalesce_windows(struct pci_root_info *info, unsigned long type) -{ - int i, j; - struct resource *res1, *res2; - - for (i = 0; i < info->res_num; i++) { - res1 = &info->res[i]; + res1 = entry->res; if (!(res1->flags & type)) - continue; + goto next; + + /* Exclude non-addressable range or non-addressable portion */ + end = min(res1->end, root->end); + if (end <= res1->start) { + dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n", + res1); + free = true; + goto next; + } else if (res1->end != end) { + dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n", + res1, (unsigned long long)end + 1, + (unsigned long long)res1->end); + res1->end = end; + } - for (j = i + 1; j < info->res_num; j++) { - res2 = &info->res[j]; + resource_list_for_each_entry(entry2, crs_res) { + res2 = entry2->res; if (!(res2->flags & type)) continue; @@ -355,118 +261,92 @@ static void coalesce_windows(struct pci_root_info *info, unsigned long type) if (resource_overlaps(res1, res2)) { res2->start = min(res1->start, res2->start); res2->end = max(res1->end, res2->end); - dev_info(&info->bridge->dev, - "host bridge window expanded to %pR; %pR ignored\n", + dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n", res2, res1); - res1->flags = 0; + free = true; + goto next; } } + +next: + resource_list_del(entry); + if (free) + resource_list_free_entry(entry); + else + resource_list_add_tail(entry, crs_res); } } static void add_resources(struct pci_root_info *info, - struct list_head *resources) + struct list_head *resources, + struct list_head *crs_res) { - int i; - struct resource *res, *root, *conflict; - - coalesce_windows(info, IORESOURCE_MEM); - coalesce_windows(info, IORESOURCE_IO); + struct resource_entry *entry, *tmp; + struct resource *res, *conflict, *root = NULL; - for (i = 0; i < info->res_num; i++) { - res = &info->res[i]; + validate_resources(&info->bridge->dev, crs_res, IORESOURCE_MEM); + validate_resources(&info->bridge->dev, crs_res, IORESOURCE_IO); + resource_list_for_each_entry_safe(entry, tmp, crs_res) { + res = entry->res; if (res->flags & IORESOURCE_MEM) root = &iomem_resource; else if (res->flags & IORESOURCE_IO) root = &ioport_resource; else - continue; + BUG_ON(res); conflict = insert_resource_conflict(root, res); - if (conflict) + if (conflict) { dev_info(&info->bridge->dev, "ignoring host bridge window %pR (conflicts with %s %pR)\n", res, conflict->name, conflict); - else - pci_add_resource_offset(resources, res, - info->res_offset[i]); + resource_list_destroy_entry(entry); + } } -} -static void free_pci_root_info_res(struct pci_root_info *info) -{ - kfree(info->res); - info->res = NULL; - kfree(info->res_offset); - info->res_offset = NULL; - info->res_num = 0; + list_splice_tail(crs_res, resources); } -static void __release_pci_root_info(struct pci_root_info *info) +static void release_pci_root_info(struct pci_host_bridge *bridge) { - int i; struct resource *res; + struct resource_entry *entry; + struct pci_root_info *info = bridge->release_data; - for (i = 0; i < info->res_num; i++) { - res = &info->res[i]; - - if (!res->parent) - continue; - - if (!(res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) - continue; - - release_resource(res); + resource_list_for_each_entry(entry, &bridge->windows) { + res = entry->res; + if (res->parent && + (res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) + release_resource(res); } - free_pci_root_info_res(info); - teardown_mcfg_map(info); - kfree(info); } -static void release_pci_root_info(struct pci_host_bridge *bridge) -{ - struct pci_root_info *info = bridge->release_data; - - __release_pci_root_info(info); -} - static void probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device, - int busnum, int domain) + int busnum, int domain, + struct list_head *list) { - size_t size; + int ret; + struct resource_entry *entry; sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum); info->bridge = device; - - info->res_num = 0; - acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, - info); - if (!info->res_num) - return; - - size = sizeof(*info->res) * info->res_num; - info->res = kzalloc_node(size, GFP_KERNEL, info->sd.node); - if (!info->res) { - info->res_num = 0; - return; - } - - size = sizeof(*info->res_offset) * info->res_num; - info->res_num = 0; - info->res_offset = kzalloc_node(size, GFP_KERNEL, info->sd.node); - if (!info->res_offset) { - kfree(info->res); - info->res = NULL; - return; - } - - acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, - info); + ret = acpi_dev_get_resources(device, list, + acpi_dev_filter_resource_type_cb, + (void *)(IORESOURCE_IO | IORESOURCE_MEM)); + if (ret < 0) + dev_warn(&device->dev, + "failed to parse _CRS method, error code %d\n", ret); + else if (ret == 0) + dev_dbg(&device->dev, + "no IO and memory resources present in _CRS\n"); + else + resource_list_for_each_entry(entry, list) + entry->res->name = info->name; } struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) @@ -475,6 +355,8 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) struct pci_root_info *info; int domain = root->segment; int busnum = root->secondary.start; + struct resource_entry *res_entry; + LIST_HEAD(crs_res); LIST_HEAD(resources); struct pci_bus *bus; struct pci_sysdata *sd; @@ -522,18 +404,22 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) memcpy(bus->sysdata, sd, sizeof(*sd)); kfree(info); } else { - probe_pci_root_info(info, device, busnum, domain); - /* insert busn res at first */ pci_add_resource(&resources, &root->secondary); + /* * _CRS with no apertures is normal, so only fall back to * defaults or native bridge info if we're ignoring _CRS. */ - if (pci_use_crs) - add_resources(info, &resources); - else { - free_pci_root_info_res(info); + probe_pci_root_info(info, device, busnum, domain, &crs_res); + if (pci_use_crs) { + add_resources(info, &resources, &crs_res); + } else { + resource_list_for_each_entry(res_entry, &crs_res) + dev_printk(KERN_DEBUG, &device->dev, + "host bridge window %pR (ignored)\n", + res_entry->res); + resource_list_free(&crs_res); x86_pci_root_bus_resources(busnum, &resources); } @@ -548,8 +434,9 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) to_pci_host_bridge(bus->bridge), release_pci_root_info, info); } else { - pci_free_resource_list(&resources); - __release_pci_root_info(info); + resource_list_free(&resources); + teardown_mcfg_map(info); + kfree(info); } } -- cgit v0.10.2 From b4b55cda587442477a3a9f0669e26bba4b7800c0 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 5 Feb 2015 13:44:47 +0800 Subject: x86/PCI: Refine the way to release PCI IRQ resources Some PCI device drivers assume that pci_dev->irq won't change after calling pci_disable_device() and pci_enable_device() during suspend and resume. Commit c03b3b0738a5 ("x86, irq, mpparse: Release IOAPIC pin when PCI device is disabled") frees PCI IRQ resources when pci_disable_device() is called and reallocate IRQ resources when pci_enable_device() is called again. This breaks above assumption. So commit 3eec595235c1 ("x86, irq, PCI: Keep IRQ assignment for PCI devices during suspend/hibernation") and 9eabc99a635a ("x86, irq, PCI: Keep IRQ assignment for runtime power management") fix the issue by avoiding freeing/reallocating IRQ resources during PCI device suspend/resume. They achieve this by checking dev.power.is_prepared and dev.power.runtime_status. PM maintainer, Rafael, then pointed out that it's really an ugly fix which leaking PM internal state information to IRQ subsystem. Recently David Vrabel also reports an regression in pciback driver caused by commit cffe0a2b5a34 ("x86, irq: Keep balance of IOAPIC pin reference count"). Please refer to: http://lkml.org/lkml/2015/1/14/546 So this patch refine the way to release PCI IRQ resources. Instead of releasing PCI IRQ resources in pci_disable_device()/ pcibios_disable_device(), we now release it at driver unbinding notification BUS_NOTIFY_UNBOUND_DRIVER. In other word, we only release PCI IRQ resources when there's no driver bound to the PCI device, and it keeps the assumption that pci_dev->irq won't through multiple invocation of pci_enable_device()/pci_disable_device(). Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h index 164e3f8..fa1195d 100644 --- a/arch/x86/include/asm/pci_x86.h +++ b/arch/x86/include/asm/pci_x86.h @@ -93,8 +93,6 @@ extern raw_spinlock_t pci_config_lock; extern int (*pcibios_enable_irq)(struct pci_dev *dev); extern void (*pcibios_disable_irq)(struct pci_dev *dev); -extern bool mp_should_keep_irq(struct device *dev); - struct pci_raw_ops { int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn, int reg, int len, u32 *val); diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 7b20bcc..ff1f0af 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -497,6 +497,31 @@ void __init pcibios_set_cache_line_size(void) } } +/* + * Some device drivers assume dev->irq won't change after calling + * pci_disable_device(). So delay releasing of IRQ resource to driver + * unbinding time. Otherwise it will break PM subsystem and drivers + * like xen-pciback etc. + */ +static int pci_irq_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct pci_dev *dev = to_pci_dev(data); + + if (action != BUS_NOTIFY_UNBOUND_DRIVER) + return NOTIFY_DONE; + + if (pcibios_disable_irq) + pcibios_disable_irq(dev); + + return NOTIFY_OK; +} + +static struct notifier_block pci_irq_nb = { + .notifier_call = pci_irq_notifier, + .priority = INT_MIN, +}; + int __init pcibios_init(void) { if (!raw_pci_ops) { @@ -509,6 +534,9 @@ int __init pcibios_init(void) if (pci_bf_sort >= pci_force_bf) pci_sort_breadthfirst(); + + bus_register_notifier(&pci_bus_type, &pci_irq_nb); + return 0; } @@ -667,12 +695,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) return 0; } -void pcibios_disable_device (struct pci_dev *dev) -{ - if (!pci_dev_msi_enabled(dev) && pcibios_disable_irq) - pcibios_disable_irq(dev); -} - int pci_ext_cfg_avail(void) { if (raw_pci_ext_ops) diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c index 44b9271..95c2471 100644 --- a/arch/x86/pci/intel_mid_pci.c +++ b/arch/x86/pci/intel_mid_pci.c @@ -234,10 +234,10 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev) static void intel_mid_pci_irq_disable(struct pci_dev *dev) { - if (!mp_should_keep_irq(&dev->dev) && dev->irq_managed && - dev->irq > 0) { + if (dev->irq_managed && dev->irq > 0) { mp_unmap_irq(dev->irq); dev->irq_managed = 0; + dev->irq = 0; } } diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index 5dc6ca5..e71b3db 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c @@ -1256,22 +1256,9 @@ static int pirq_enable_irq(struct pci_dev *dev) return 0; } -bool mp_should_keep_irq(struct device *dev) -{ - if (dev->power.is_prepared) - return true; -#ifdef CONFIG_PM - if (dev->power.runtime_status == RPM_SUSPENDING) - return true; -#endif - - return false; -} - static void pirq_disable_irq(struct pci_dev *dev) { - if (io_apic_assign_pci_irqs && !mp_should_keep_irq(&dev->dev) && - dev->irq_managed && dev->irq) { + if (io_apic_assign_pci_irqs && dev->irq_managed && dev->irq) { mp_unmap_irq(dev->irq); dev->irq = 0; dev->irq_managed = 0; diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index b1def41..e7f718d 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -485,14 +485,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev) if (!pin || !dev->irq_managed || dev->irq <= 0) return; - /* Keep IOAPIC pin configuration when suspending */ - if (dev->dev.power.is_prepared) - return; -#ifdef CONFIG_PM - if (dev->dev.power.runtime_status == RPM_SUSPENDING) - return; -#endif - entry = acpi_pci_irq_lookup(dev, pin); if (!entry) return; @@ -513,5 +505,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev) if (gsi >= 0) { acpi_unregister_gsi(gsi); dev->irq_managed = 0; + dev->irq = 0; } } -- cgit v0.10.2 From ecf5636dcd59cd5508641f995cc4c2bafedbb995 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 5 Feb 2015 13:44:48 +0800 Subject: ACPI: Add interfaces to parse IOAPIC ID for IOAPIC hotplug We need to parse APIC ID for IOAPIC registration for IOAPIC hotplug. ACPI _MAT method and MADT table are used to figure out IOAPIC ID, just like parsing CPU APIC ID for CPU hotplug. [ tglx: Fixed docbook comment ] Signed-off-by: Yinghai Lu Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Borislav Petkov Cc: Len Brown Link: http://lkml.kernel.org/r/1414387308-27148-8-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 02e4839..7962651 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -4,6 +4,10 @@ * * Alex Chiang * - Unified x86/ia64 implementations + * + * I/O APIC hotplug support + * Yinghai Lu + * Jiang Liu */ #include #include @@ -12,6 +16,21 @@ #define _COMPONENT ACPI_PROCESSOR_COMPONENT ACPI_MODULE_NAME("processor_core"); +static struct acpi_table_madt *get_madt_table(void) +{ + static struct acpi_table_madt *madt; + static int read_madt; + + if (!read_madt) { + if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, + (struct acpi_table_header **)&madt))) + madt = NULL; + read_madt++; + } + + return madt; +} + static int map_lapic_id(struct acpi_subtable_header *entry, u32 acpi_id, int *apic_id) { @@ -67,17 +86,10 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, static int map_madt_entry(int type, u32 acpi_id) { unsigned long madt_end, entry; - static struct acpi_table_madt *madt; - static int read_madt; int phys_id = -1; /* CPU hardware ID */ + struct acpi_table_madt *madt; - if (!read_madt) { - if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, - (struct acpi_table_header **)&madt))) - madt = NULL; - read_madt++; - } - + madt = get_madt_table(); if (!madt) return phys_id; @@ -203,3 +215,96 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) return acpi_map_cpuid(phys_id, acpi_id); } EXPORT_SYMBOL_GPL(acpi_get_cpuid); + +#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC +static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base, + u64 *phys_addr, int *ioapic_id) +{ + struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry; + + if (ioapic->global_irq_base != gsi_base) + return 0; + + *phys_addr = ioapic->address; + *ioapic_id = ioapic->id; + return 1; +} + +static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr) +{ + struct acpi_subtable_header *hdr; + unsigned long madt_end, entry; + struct acpi_table_madt *madt; + int apic_id = -1; + + madt = get_madt_table(); + if (!madt) + return apic_id; + + entry = (unsigned long)madt; + madt_end = entry + madt->header.length; + + /* Parse all entries looking for a match. */ + entry += sizeof(struct acpi_table_madt); + while (entry + sizeof(struct acpi_subtable_header) < madt_end) { + hdr = (struct acpi_subtable_header *)entry; + if (hdr->type == ACPI_MADT_TYPE_IO_APIC && + get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id)) + break; + else + entry += hdr->length; + } + + return apic_id; +} + +static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base, + u64 *phys_addr) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_subtable_header *header; + union acpi_object *obj; + int apic_id = -1; + + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) + goto exit; + + if (!buffer.length || !buffer.pointer) + goto exit; + + obj = buffer.pointer; + if (obj->type != ACPI_TYPE_BUFFER || + obj->buffer.length < sizeof(struct acpi_subtable_header)) + goto exit; + + header = (struct acpi_subtable_header *)obj->buffer.pointer; + if (header->type == ACPI_MADT_TYPE_IO_APIC) + get_ioapic_id(header, gsi_base, phys_addr, &apic_id); + +exit: + kfree(buffer.pointer); + return apic_id; +} + +/** + * acpi_get_ioapic_id - Get IOAPIC ID and physical address matching @gsi_base + * @handle: ACPI object for IOAPIC device + * @gsi_base: GSI base to match with + * @phys_addr: Pointer to store physical address of matching IOAPIC record + * + * Walk resources returned by ACPI_MAT method, then ACPI MADT table, to search + * for an ACPI IOAPIC record matching @gsi_base. + * Return IOAPIC id and store physical address in @phys_addr if found a match, + * otherwise return <0. + */ +int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr) +{ + int apic_id; + + apic_id = parse_mat_ioapic_entry(handle, gsi_base, phys_addr); + if (apic_id == -1) + apic_id = parse_madt_ioapic_entry(gsi_base, phys_addr); + + return apic_id; +} +#endif /* CONFIG_ACPI_HOTPLUG_IOAPIC */ diff --git a/include/linux/acpi.h b/include/linux/acpi.h index e538221..24c7aa8 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -152,6 +152,10 @@ int acpi_map_cpu(acpi_handle handle, int physid, int *pcpu); int acpi_unmap_cpu(int cpu); #endif /* CONFIG_ACPI_HOTPLUG_CPU */ +#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC +int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr); +#endif + int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base); int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base); int acpi_ioapic_registered(acpi_handle handle, u32 gsi_base); -- cgit v0.10.2 From c183619b63ec934110e3a173a34b414e26869f96 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 5 Feb 2015 13:44:49 +0800 Subject: x86/irq, ACPI: Implement ACPI driver to support IOAPIC hotplug Enable support of IOAPIC hotplug by: 1) reintroducing ACPI based IOAPIC driver 2) enhance pci_root driver to hook hotplug events The ACPI IOAPIC driver is always enabled if all of ACPI, PCI and IOAPIC are enabled. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Borislav Petkov Cc: Len Brown Link: http://lkml.kernel.org/r/1414387308-27148-19-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 8951cefb..e6c3ddd 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -315,6 +315,12 @@ config ACPI_HOTPLUG_MEMORY To compile this driver as a module, choose M here: the module will be called acpi_memhotplug. +config ACPI_HOTPLUG_IOAPIC + bool + depends on PCI + depends on X86_IO_APIC + default y + config ACPI_SBS tristate "Smart Battery System" depends on X86 diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index f74317c..e59494c 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -70,6 +70,7 @@ obj-$(CONFIG_ACPI_PROCESSOR) += processor.o obj-y += container.o obj-$(CONFIG_ACPI_THERMAL) += thermal.o obj-y += acpi_memhotplug.o +obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_SBS) += sbshc.o obj-$(CONFIG_ACPI_SBS) += sbs.o diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 163e82f..caca280 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -35,6 +35,13 @@ void acpi_int340x_thermal_init(void); int acpi_sysfs_init(void); void acpi_container_init(void); void acpi_memory_hotplug_init(void); +#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC +int acpi_ioapic_add(struct acpi_pci_root *root); +int acpi_ioapic_remove(struct acpi_pci_root *root); +#else +static inline int acpi_ioapic_add(struct acpi_pci_root *root) { return 0; } +static inline int acpi_ioapic_remove(struct acpi_pci_root *root) { return 0; } +#endif #ifdef CONFIG_ACPI_DOCK void register_dock_dependent_device(struct acpi_device *adev, acpi_handle dshandle); diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c new file mode 100644 index 0000000..ccdc8db --- /dev/null +++ b/drivers/acpi/ioapic.c @@ -0,0 +1,229 @@ +/* + * IOAPIC/IOxAPIC/IOSAPIC driver + * + * Copyright (C) 2009 Fujitsu Limited. + * (c) Copyright 2009 Hewlett-Packard Development Company, L.P. + * + * Copyright (C) 2014 Intel Corporation + * + * 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. + * + * Based on original drivers/pci/ioapic.c + * Yinghai Lu + * Jiang Liu + */ + +/* + * This driver manages I/O APICs added by hotplug after boot. + * We try to claim all I/O APIC devices, but those present at boot were + * registered when we parsed the ACPI MADT. + */ + +#define pr_fmt(fmt) "ACPI : IOAPIC: " fmt + +#include +#include +#include +#include + +struct acpi_pci_ioapic { + acpi_handle root_handle; + acpi_handle handle; + u32 gsi_base; + struct resource res; + struct pci_dev *pdev; + struct list_head list; +}; + +static LIST_HEAD(ioapic_list); +static DEFINE_MUTEX(ioapic_list_lock); + +static acpi_status setup_res(struct acpi_resource *acpi_res, void *data) +{ + struct resource *res = data; + struct resource_win win; + + res->flags = 0; + if (acpi_dev_filter_resource_type(acpi_res, IORESOURCE_MEM) == 0) + return AE_OK; + + if (!acpi_dev_resource_memory(acpi_res, res)) { + if (acpi_dev_resource_address_space(acpi_res, &win) || + acpi_dev_resource_ext_address_space(acpi_res, &win)) + *res = win.res; + } + if ((res->flags & IORESOURCE_PREFETCH) || + (res->flags & IORESOURCE_DISABLED)) + res->flags = 0; + + return AE_CTRL_TERMINATE; +} + +static bool acpi_is_ioapic(acpi_handle handle, char **type) +{ + acpi_status status; + struct acpi_device_info *info; + char *hid = NULL; + bool match = false; + + if (!acpi_has_method(handle, "_GSB")) + return false; + + status = acpi_get_object_info(handle, &info); + if (ACPI_SUCCESS(status)) { + if (info->valid & ACPI_VALID_HID) + hid = info->hardware_id.string; + if (hid) { + if (strcmp(hid, "ACPI0009") == 0) { + *type = "IOxAPIC"; + match = true; + } else if (strcmp(hid, "ACPI000A") == 0) { + *type = "IOAPIC"; + match = true; + } + } + kfree(info); + } + + return match; +} + +static acpi_status handle_ioapic_add(acpi_handle handle, u32 lvl, + void *context, void **rv) +{ + acpi_status status; + unsigned long long gsi_base; + struct acpi_pci_ioapic *ioapic; + struct pci_dev *dev = NULL; + struct resource *res = NULL; + char *type = NULL; + + if (!acpi_is_ioapic(handle, &type)) + return AE_OK; + + mutex_lock(&ioapic_list_lock); + list_for_each_entry(ioapic, &ioapic_list, list) + if (ioapic->handle == handle) { + mutex_unlock(&ioapic_list_lock); + return AE_OK; + } + + status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsi_base); + if (ACPI_FAILURE(status)) { + acpi_handle_warn(handle, "failed to evaluate _GSB method\n"); + goto exit; + } + + ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL); + if (!ioapic) { + pr_err("cannot allocate memory for new IOAPIC\n"); + goto exit; + } else { + ioapic->root_handle = (acpi_handle)context; + ioapic->handle = handle; + ioapic->gsi_base = (u32)gsi_base; + INIT_LIST_HEAD(&ioapic->list); + } + + if (acpi_ioapic_registered(handle, (u32)gsi_base)) + goto done; + + dev = acpi_get_pci_dev(handle); + if (dev && pci_resource_len(dev, 0)) { + if (pci_enable_device(dev) < 0) + goto exit_put; + pci_set_master(dev); + if (pci_request_region(dev, 0, type)) + goto exit_disable; + res = &dev->resource[0]; + ioapic->pdev = dev; + } else { + pci_dev_put(dev); + dev = NULL; + + res = &ioapic->res; + acpi_walk_resources(handle, METHOD_NAME__CRS, setup_res, res); + if (res->flags == 0) { + acpi_handle_warn(handle, "failed to get resource\n"); + goto exit_free; + } else if (request_resource(&iomem_resource, res)) { + acpi_handle_warn(handle, "failed to insert resource\n"); + goto exit_free; + } + } + + if (acpi_register_ioapic(handle, res->start, (u32)gsi_base)) { + acpi_handle_warn(handle, "failed to register IOAPIC\n"); + goto exit_release; + } +done: + list_add(&ioapic->list, &ioapic_list); + mutex_unlock(&ioapic_list_lock); + + if (dev) + dev_info(&dev->dev, "%s at %pR, GSI %u\n", + type, res, (u32)gsi_base); + else + acpi_handle_info(handle, "%s at %pR, GSI %u\n", + type, res, (u32)gsi_base); + + return AE_OK; + +exit_release: + if (dev) + pci_release_region(dev, 0); + else + release_resource(res); +exit_disable: + if (dev) + pci_disable_device(dev); +exit_put: + pci_dev_put(dev); +exit_free: + kfree(ioapic); +exit: + mutex_unlock(&ioapic_list_lock); + *(acpi_status *)rv = AE_ERROR; + return AE_OK; +} + +int acpi_ioapic_add(struct acpi_pci_root *root) +{ + acpi_status status, retval = AE_OK; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, root->device->handle, + UINT_MAX, handle_ioapic_add, NULL, + root->device->handle, (void **)&retval); + + return ACPI_SUCCESS(status) && ACPI_SUCCESS(retval) ? 0 : -ENODEV; +} + +int acpi_ioapic_remove(struct acpi_pci_root *root) +{ + int retval = 0; + struct acpi_pci_ioapic *ioapic, *tmp; + + mutex_lock(&ioapic_list_lock); + list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) { + if (root->device->handle != ioapic->root_handle) + continue; + + if (acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base)) + retval = -EBUSY; + + if (ioapic->pdev) { + pci_release_region(ioapic->pdev, 0); + pci_disable_device(ioapic->pdev); + pci_dev_put(ioapic->pdev); + } else if (ioapic->res.flags && ioapic->res.parent) { + release_resource(&ioapic->res); + } + list_del(&ioapic->list); + kfree(ioapic); + } + mutex_unlock(&ioapic_list_lock); + + return retval; +} diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index e53e0f6..68a5f71 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -621,6 +621,7 @@ static int acpi_pci_root_add(struct acpi_device *device, if (hotadd) { pcibios_resource_survey_bus(root->bus); pci_assign_unassigned_root_bus_resources(root->bus); + acpi_ioapic_add(root); } pci_lock_rescan_remove(); @@ -644,6 +645,8 @@ static void acpi_pci_root_remove(struct acpi_device *device) pci_stop_root_bus(root->bus); + WARN_ON(acpi_ioapic_remove(root)); + device_set_run_wake(root->bus->bridge, false); pci_acpi_remove_bus_pm_notifier(device); -- cgit v0.10.2 From 1c4c81a244a91a8ba37df3de33decca5d95cff0b Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 5 Feb 2015 15:19:48 +0800 Subject: ACPICA: Events: Back port "ACPICA: Save current masks of enabled GPEs after enable register writes" This is a back port result of the Linux commit: Commit c50f13c672df758b59e026c15b9118f3ed46edc4 Subject: ACPICA: Save current masks of enabled GPEs after enable register writes Besides of the indent divergences, only a missing prototype added due to the ACPICA internal coding style. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c index 17e4bbf..9e2b94c 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -167,8 +167,8 @@ u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info) ******************************************************************************/ acpi_status -acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block, void *context) +acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info * gpe_xrupt_info, + struct acpi_gpe_block_info * gpe_block, void *context) { struct acpi_gpe_device_info *info = context; diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index e889a53..c637666 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -604,7 +604,6 @@ ACPI_EXPORT_SYMBOL(acpi_enable_all_runtime_gpes) * all GPE blocks. * ******************************************************************************/ - acpi_status acpi_enable_all_wakeup_gpes(void) { acpi_status status; diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index 494027f..6a955a9 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -54,6 +54,10 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block, void *context); +static acpi_status +acpi_hw_gpe_enable_write(u8 enable_mask, + struct acpi_gpe_register_info *gpe_register_info); + /****************************************************************************** * * FUNCTION: acpi_hw_get_gpe_register_bit -- cgit v0.10.2 From 833bb9316a3b4644b2671317ec4889e343ae5d42 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 5 Feb 2015 15:19:54 +0800 Subject: ACPICA: Events: Remove duplicated sanity check in acpi_ev_enable_gpe() ACPICA commit ca10324788bc9bdaf47fa9e51145129c1299144d This patch deletes a sanity check from acpi_ev_enable_gpe(). This kind of check is already done in acpi_enable_gpe()/acpi_remove_gpe_handler()/acpi_update_all_gpes() before invoking acpi_ev_enable_gpe(): 1. acpi_enable_gpe(): same check (skip if DISPATCH_NONE) is now implemented. 2. acpi_remove_gpe_handler(): a more strict check (skip if !DISPATCH_HANDLER) is implemented. 3. acpi_update_all_gpes(): a more strict check (skip if DISPATCH_NONE || DISPATCH_HANDLER || CAN_WAKE) 4. acpi_set_gpe(): since it is invoked by the OSPM driver where the GPE handler is known to be available, such check isn't needed. So we can simply remove this duplicated check from acpi_ev_enable_gpe(). Lv Zheng. Link: https://github.com/acpica/acpica/commit/ca103247 Signed-off-by: Lv Zheng Signed-off-by: David E. Box Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index aa70154..b2e63e7 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -114,17 +114,6 @@ acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) ACPI_FUNCTION_TRACE(ev_enable_gpe); - /* - * We will only allow a GPE to be enabled if it has either an associated - * method (_Lxx/_Exx) or a handler, or is using the implicit notify - * feature. Otherwise, the GPE will be immediately disabled by - * acpi_ev_gpe_dispatch the first time it fires. - */ - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == - ACPI_GPE_DISPATCH_NONE) { - return_ACPI_STATUS(AE_NO_HANDLER); - } - /* Clear the GPE (of stale events) */ status = acpi_hw_clear_gpe(gpe_event_info); -- cgit v0.10.2 From b18da580343b88fa33bbba8a7f48392447bc6cbf Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 5 Feb 2015 15:20:01 +0800 Subject: ACPICA: Events: Remove acpi_ev_valid_gpe_event() due to current restriction ACPICA commit 8823b44ff53859ab24ecfcfd3fba8cc56b17d223 Currently we rely on the logic that GPE blocks will never be deleted, otherwise we can be broken by the race between acpi_ev_create_gpe_block(), acpi_ev_delete_gpe_block() and acpi_ev_gpe_detect(). On the other hand, if we want to protect GPE block creation/deletion, we need to use a different synchronization facility to protect the period between acpi_ev_gpe_dispatch() and acpi_ev_asynch_enable_gpe(). Which leaves us no choice but abandoning the ACPI_MTX_EVENTS used during this period. This patch removes ACPI_MTX_EVENTS used during this period and the acpi_ev_valid_gpe_event() to reflect current restriction. Lv Zheng. Link: https://github.com/acpica/acpica/commit/8823b44f Signed-off-by: Lv Zheng Signed-off-by: David E. Box Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 7a7811a..38b94a1 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -143,8 +143,6 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle, acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context); -u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info); - acpi_status acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block, void *context); diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index b2e63e7..ddee967 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -474,51 +474,14 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) { struct acpi_gpe_event_info *gpe_event_info = context; acpi_status status; - struct acpi_gpe_event_info *local_gpe_event_info; struct acpi_evaluate_info *info; struct acpi_gpe_notify_info *notify; ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); - /* Allocate a local GPE block */ - - local_gpe_event_info = - ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_event_info)); - if (!local_gpe_event_info) { - ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "while handling a GPE")); - return_VOID; - } - - status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); - if (ACPI_FAILURE(status)) { - ACPI_FREE(local_gpe_event_info); - return_VOID; - } - - /* Must revalidate the gpe_number/gpe_block */ - - if (!acpi_ev_valid_gpe_event(gpe_event_info)) { - status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); - ACPI_FREE(local_gpe_event_info); - return_VOID; - } - - /* - * Take a snapshot of the GPE info for this level - we copy the info to - * prevent a race condition with remove_handler/remove_block. - */ - ACPI_MEMCPY(local_gpe_event_info, gpe_event_info, - sizeof(struct acpi_gpe_event_info)); - - status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); - if (ACPI_FAILURE(status)) { - ACPI_FREE(local_gpe_event_info); - return_VOID; - } - /* Do the correct dispatch - normal method or implicit notify */ - switch (local_gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { + switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { case ACPI_GPE_DISPATCH_NOTIFY: /* * Implicit notify. @@ -531,7 +494,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) * June 2012: Expand implicit notify mechanism to support * notifies on multiple device objects. */ - notify = local_gpe_event_info->dispatch.notify_list; + notify = gpe_event_info->dispatch.notify_list; while (ACPI_SUCCESS(status) && notify) { status = acpi_ev_queue_notify_request(notify->device_node, @@ -555,7 +518,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) * _Lxx/_Exx control method that corresponds to this GPE */ info->prefix_node = - local_gpe_event_info->dispatch.method_node; + gpe_event_info->dispatch.method_node; info->flags = ACPI_IGNORE_RETURN_VALUE; status = acpi_ns_evaluate(info); @@ -565,25 +528,27 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "while evaluating GPE method [%4.4s]", - acpi_ut_get_node_name - (local_gpe_event_info->dispatch. - method_node))); + acpi_ut_get_node_name(gpe_event_info-> + dispatch. + method_node))); } break; default: - return_VOID; /* Should never happen */ + goto error_exit; /* Should never happen */ } /* Defer enabling of GPE until all notify handlers are done */ status = acpi_os_execute(OSL_NOTIFY_HANDLER, - acpi_ev_asynch_enable_gpe, - local_gpe_event_info); - if (ACPI_FAILURE(status)) { - ACPI_FREE(local_gpe_event_info); + acpi_ev_asynch_enable_gpe, gpe_event_info); + if (ACPI_SUCCESS(status)) { + return_VOID; } + +error_exit: + acpi_ev_asynch_enable_gpe(gpe_event_info); return_VOID; } @@ -611,7 +576,6 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context) (void)acpi_ev_finish_gpe(gpe_event_info); acpi_os_release_lock(acpi_gbl_gpe_lock, flags); - ACPI_FREE(gpe_event_info); return; } diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c index 9e2b94c..3f1c5aa 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -108,53 +108,6 @@ unlock_and_exit: /******************************************************************************* * - * FUNCTION: acpi_ev_valid_gpe_event - * - * PARAMETERS: gpe_event_info - Info for this GPE - * - * RETURN: TRUE if the gpe_event is valid - * - * DESCRIPTION: Validate a GPE event. DO NOT CALL FROM INTERRUPT LEVEL. - * Should be called only when the GPE lists are semaphore locked - * and not subject to change. - * - ******************************************************************************/ - -u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info) -{ - struct acpi_gpe_xrupt_info *gpe_xrupt_block; - struct acpi_gpe_block_info *gpe_block; - - ACPI_FUNCTION_ENTRY(); - - /* No need for spin lock since we are not changing any list elements */ - - /* Walk the GPE interrupt levels */ - - gpe_xrupt_block = acpi_gbl_gpe_xrupt_list_head; - while (gpe_xrupt_block) { - gpe_block = gpe_xrupt_block->gpe_block_list_head; - - /* Walk the GPE blocks on this interrupt level */ - - while (gpe_block) { - if ((&gpe_block->event_info[0] <= gpe_event_info) && - (&gpe_block->event_info[gpe_block->gpe_count] > - gpe_event_info)) { - return (TRUE); - } - - gpe_block = gpe_block->next; - } - - gpe_xrupt_block = gpe_xrupt_block->next; - } - - return (FALSE); -} - -/******************************************************************************* - * * FUNCTION: acpi_ev_get_gpe_device * * PARAMETERS: GPE_WALK_CALLBACK @@ -167,8 +120,8 @@ u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info) ******************************************************************************/ acpi_status -acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info * gpe_xrupt_info, - struct acpi_gpe_block_info * gpe_block, void *context) +acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, void *context) { struct acpi_gpe_device_info *info = context; -- cgit v0.10.2 From b7be6883c7b0414f72c785b498d133194151cd8b Mon Sep 17 00:00:00 2001 From: "David E. Box" Date: Thu, 5 Feb 2015 15:20:07 +0800 Subject: ACPICA: Events: Fix uninitialized variable ACPICA commit 8e21180050270897499652e922c6a41b8eb388b6 Recent changes to acpi_ev_asynch_execute_gpe_method left Status variable uninitialized before use. Initialize to AE_OK. Link: https://github.com/acpica/acpica/commit/8e211800 Signed-off-by: David E. Box Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index ddee967..d8b919a 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -473,7 +473,7 @@ unlock_and_exit: static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) { struct acpi_gpe_event_info *gpe_event_info = context; - acpi_status status; + acpi_status status = AE_OK; struct acpi_evaluate_info *info; struct acpi_gpe_notify_info *notify; -- cgit v0.10.2 From c539251e7c1537c8b3dcaa1c89f5393d04996013 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 5 Feb 2015 15:20:14 +0800 Subject: ACPICA: Events: Cleanup of resetting the GPE handler to NULL before removing ACPICA commit b2b18bb38045404e253f10787b8a4ae6e94cdee6 This patch prevents acpi_remove_gpe_handler() from leaking the stale gpe_event_info->Dispatch.Handler to the caller to avoid possible NULL pointer references. Lv Zheng. Link: https://github.com/acpica/acpica/commit/b2b18bb3 Signed-off-by: Lv Zheng Signed-off-by: David E. Box Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index 55a58f3..b6b0c23 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -896,6 +896,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, /* Remove the handler */ handler = gpe_event_info->dispatch.handler; + gpe_event_info->dispatch.handler = NULL; /* Restore Method node (if any), set dispatch flags */ -- cgit v0.10.2 From 779ba5a39214f0e3112bd2b94c26df03dc518a29 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 5 Feb 2015 15:20:22 +0800 Subject: ACPICA: Events: Cleanup to move acpi_gbl_global_event_handler invocation out of acpi_ev_gpe_dispatch() ACPICA commit 04f25acdd4f655ae33f83de789bb5f4b7790171c This patch follows acpi_ev_fixed_event_detect(), which invokes acpi_gbl_global_event_handler instead of invoking it in acpi_ev_fixed_event_dispatch(), moves acpi_gbl_global_event_handler from acpi_ev_gpe_dispatch() to acpi_ev_gpe_detect(). This makes further cleanups around acpi_ev_gpe_dispatch() simpler. Lv Zheng. Link: https://github.com/acpica/acpica/commit/04f25acd Signed-off-by: Lv Zheng Signed-off-by: David E. Box Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index d8b919a..4a4f41a 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -328,7 +328,10 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list) { acpi_status status; struct acpi_gpe_block_info *gpe_block; + struct acpi_namespace_node *gpe_device; struct acpi_gpe_register_info *gpe_register_info; + struct acpi_gpe_event_info *gpe_event_info; + u32 gpe_number; u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; u8 enabled_status_byte; u32 status_reg; @@ -356,6 +359,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list) gpe_block = gpe_xrupt_list->gpe_block_list_head; while (gpe_block) { + gpe_device = gpe_block->node; + /* * Read all of the 8-bit GPE status and enable registers in this GPE * block, saving all of them. Find all currently active GP events. @@ -431,16 +436,33 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list) /* Examine one GPE bit */ + gpe_event_info = + &gpe_block-> + event_info[((acpi_size) i * + ACPI_GPE_REGISTER_WIDTH) + j]; + gpe_number = + j + gpe_register_info->base_gpe_number; + if (enabled_status_byte & (1 << j)) { + + /* Invoke global event handler if present */ + + acpi_gpe_count++; + if (acpi_gbl_global_event_handler) { + acpi_gbl_global_event_handler + (ACPI_EVENT_TYPE_GPE, + gpe_device, gpe_number, + acpi_gbl_global_event_handler_context); + } + /* * Found an active GPE. Dispatch the event to a handler * or method. */ int_status |= - acpi_ev_gpe_dispatch(gpe_block-> - node, - &gpe_block-> - event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number); + acpi_ev_gpe_dispatch(gpe_device, + gpe_event_info, + gpe_number); } } } @@ -645,15 +667,6 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, ACPI_FUNCTION_TRACE(ev_gpe_dispatch); - /* Invoke global event handler if present */ - - acpi_gpe_count++; - if (acpi_gbl_global_event_handler) { - acpi_gbl_global_event_handler(ACPI_EVENT_TYPE_GPE, gpe_device, - gpe_number, - acpi_gbl_global_event_handler_context); - } - /* * Always disable the GPE so that it does not keep firing before * any asynchronous activity completes (either from the execution -- cgit v0.10.2 From 7c43312af8b363b679d1e7840858ff8d204a4d91 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 5 Feb 2015 15:20:29 +0800 Subject: ACPICA: Events: Cleanup GPE dispatcher type obtaining code ACPICA commit 7926d5ca9452c87f866938dcea8f12e1efb58f89 There is an issue in acpi_install_gpe_handler() and acpi_remove_gpe_handler(). The code to obtain the GPE dispatcher type from the Handler->original_flags is wrong: if (((Handler->original_flags & ACPI_GPE_DISPATCH_METHOD) || (Handler->original_flags & ACPI_GPE_DISPATCH_NOTIFY)) && ACPI_GPE_DISPATCH_NOTIFY is 0x03 and ACPI_GPE_DISPATCH_METHOD is 0x02, thus this statement is TRUE for the following dispatcher types: 0x01 (ACPI_GPE_DISPATCH_HANDLER): not expected 0x02 (ACPI_GPE_DISPATCH_METHOD): expected 0x03 (ACPI_GPE_DISPATCH_NOTIFY): expected There is no functional issue due to this because Handler->original_flags is only set in acpi_install_gpe_handler(), and an earlier checker has excluded the ACPI_GPE_DISPATCH_HANDLER: if ((gpe_event_info->Flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) { Status = AE_ALREADY_EXISTS; goto free_and_exit; } ... Handler->original_flags = (u8) (gpe_event_info->Flags & (ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK)); We need to clean this up before modifying the GPE dispatcher type values. In order to prevent such issue from happening in the future, this patch introduces ACPI_GPE_DISPATCH_TYPE() macro to be used to obtain the GPE dispatcher types. Lv Zheng. Link: https://github.com/acpica/acpica/commit/7926d5ca Signed-off-by: Lv Zheng Signed-off-by: David E. Box Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 4a4f41a..fccdfb2 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -503,7 +503,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) /* Do the correct dispatch - normal method or implicit notify */ - switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { + switch (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)) { case ACPI_GPE_DISPATCH_NOTIFY: /* * Implicit notify. @@ -707,7 +707,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, * If there is neither a handler nor a method, leave the GPE * disabled. */ - switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { + switch (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)) { case ACPI_GPE_DISPATCH_HANDLER: /* Invoke the installed handler (at interrupt level) */ diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index d86699e..d0a6024 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -474,10 +474,10 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, * Ignore GPEs that have no corresponding _Lxx/_Exx method * and GPEs that are used to wake the system */ - if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == ACPI_GPE_DISPATCH_NONE) - || ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) - == ACPI_GPE_DISPATCH_HANDLER) + || (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == + ACPI_GPE_DISPATCH_HANDLER) || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { continue; } diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index 7be9283..ebfd40d 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -401,7 +401,7 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle, return_ACPI_STATUS(AE_OK); } - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == ACPI_GPE_DISPATCH_HANDLER) { /* If there is already a handler, ignore this GPE method */ @@ -409,7 +409,7 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle, return_ACPI_STATUS(AE_OK); } - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == ACPI_GPE_DISPATCH_METHOD) { /* * If there is already a method, ignore this method. But check diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c index 3f1c5aa..b197812 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -324,7 +324,7 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, ACPI_GPE_REGISTER_WIDTH) + j]; - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == ACPI_GPE_DISPATCH_HANDLER) { /* Delete an installed handler block */ @@ -333,10 +333,8 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, gpe_event_info->dispatch.handler = NULL; gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; - } else - if ((gpe_event_info-> - flags & ACPI_GPE_DISPATCH_MASK) == - ACPI_GPE_DISPATCH_NOTIFY) { + } else if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) + == ACPI_GPE_DISPATCH_NOTIFY) { /* Delete the implicit notification device list */ diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index b6b0c23..61b0261 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -775,7 +775,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device, /* Make sure that there isn't a handler there already */ - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == ACPI_GPE_DISPATCH_HANDLER) { status = AE_ALREADY_EXISTS; goto free_and_exit; @@ -793,9 +793,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device, * automatically during initialization, in which case it has to be * disabled now to avoid spurious execution of the handler. */ - if (((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) || - (handler->original_flags & ACPI_GPE_DISPATCH_NOTIFY)) && - gpe_event_info->runtime_count) { + if (((ACPI_GPE_DISPATCH_TYPE(handler->original_flags) == + ACPI_GPE_DISPATCH_METHOD) || + (ACPI_GPE_DISPATCH_TYPE(handler->original_flags) == + ACPI_GPE_DISPATCH_NOTIFY)) && gpe_event_info->runtime_count) { handler->originally_enabled = TRUE; (void)acpi_ev_remove_gpe_reference(gpe_event_info); @@ -880,7 +881,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, /* Make sure that a handler is indeed installed */ - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) != + if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != ACPI_GPE_DISPATCH_HANDLER) { status = AE_NOT_EXIST; goto unlock_and_exit; @@ -910,9 +911,10 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, * enabled, it should be enabled at this point to restore the * post-initialization configuration. */ - if (((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) || - (handler->original_flags & ACPI_GPE_DISPATCH_NOTIFY)) && - handler->originally_enabled) { + if (((ACPI_GPE_DISPATCH_TYPE(handler->original_flags) == + ACPI_GPE_DISPATCH_METHOD) || + (ACPI_GPE_DISPATCH_TYPE(handler->original_flags) == + ACPI_GPE_DISPATCH_NOTIFY)) && handler->originally_enabled) { (void)acpi_ev_add_gpe_reference(gpe_event_info); } diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index c637666..b836139 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -132,7 +132,7 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (gpe_event_info) { - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) != + if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != ACPI_GPE_DISPATCH_NONE) { status = acpi_ev_add_gpe_reference(gpe_event_info); } else { @@ -313,7 +313,7 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device, * known as an "implicit notify". Note: The GPE is assumed to be * level-triggered (for windows compatibility). */ - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == ACPI_GPE_DISPATCH_NONE) { /* * This is the first device for implicit notify on this GPE. @@ -327,7 +327,7 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device, * If we already have an implicit notify on this GPE, add * this device to the notify list. */ - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == ACPI_GPE_DISPATCH_NOTIFY) { /* Ensure that the device is not already in the list */ diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index 6a955a9..ed85fe7 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -225,7 +225,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, /* GPE currently handled? */ - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) != + if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != ACPI_GPE_DISPATCH_NONE) { local_event_status |= ACPI_EVENT_FLAG_HAS_HANDLER; } diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index bbef173..401705d 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -757,6 +757,7 @@ typedef u32 acpi_event_status; #define ACPI_GPE_DISPATCH_HANDLER (u8) 0x02 #define ACPI_GPE_DISPATCH_NOTIFY (u8) 0x03 #define ACPI_GPE_DISPATCH_MASK (u8) 0x03 +#define ACPI_GPE_DISPATCH_TYPE(flags) ((u8) ((flags) & ACPI_GPE_DISPATCH_MASK)) #define ACPI_GPE_LEVEL_TRIGGERED (u8) 0x04 #define ACPI_GPE_EDGE_TRIGGERED (u8) 0x00 -- cgit v0.10.2 From d6c02669b486a7742a27e9f3a7a66148a5a7c248 Mon Sep 17 00:00:00 2001 From: "David E. Box" Date: Thu, 5 Feb 2015 15:20:38 +0800 Subject: ACPICA: Hardware: Cast GPE enable_mask before storing ACPICA commit 490ec7f7839bf7ee5e8710a34d1d1a78d54a49b6 In function acpi_hw_low_set_gpe(), cast enable_mask to u8 before storing. The mask was read from a 32 bit register but is an 8 bit value. Fixes Visual Studio compiler warning. Link: https://github.com/acpica/acpica/commit/490ec7f7 Signed-off-by: David E. Box Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index ed85fe7..b7fb00d 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -150,7 +150,7 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action) status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address); if (ACPI_SUCCESS(status) && (action & ACPI_GPE_SAVE_MASK)) { - gpe_register_info->enable_mask = enable_mask; + gpe_register_info->enable_mask = (u8)enable_mask; } return (status); } -- cgit v0.10.2 From 82a809419429f2e6142d2c5d88d91661f8aecb87 Mon Sep 17 00:00:00 2001 From: "David E. Box" Date: Thu, 5 Feb 2015 15:20:45 +0800 Subject: ACPICA: Update Copyright headers to 2015 ACPICA commit 8990e73ab2aa15d6a0068b860ab54feff25bee36 Link: https://github.com/acpica/acpica/commit/8990e73a Signed-off-by: David E. Box Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h index 3d2c882..d863016 100644 --- a/drivers/acpi/acpica/acapps.h +++ b/drivers/acpi/acpica/acapps.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -47,7 +47,7 @@ /* Common info for tool signons */ #define ACPICA_NAME "Intel ACPI Component Architecture" -#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2014 Intel Corporation" +#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2015 Intel Corporation" #if ACPI_MACHINE_WIDTH == 64 #define ACPI_WIDTH "-64" diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h index 6f1c616..853aa2d 100644 --- a/drivers/acpi/acpica/accommon.h +++ b/drivers/acpi/acpica/accommon.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index 1d026ff..4169bb8 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h index d3e2cc3..408f04b 100644 --- a/drivers/acpi/acpica/acdispat.h +++ b/drivers/acpi/acpica/acdispat.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 38b94a1..228704b7 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 7f60582..a165d25 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h index c318d3e..196a552 100644 --- a/drivers/acpi/acpica/achware.h +++ b/drivers/acpi/acpica/achware.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h index b01f71c..1886bde 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 680d23b..7add32e 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index 4bceb11..cf607fe 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index ee1c040..952fbe0 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index 8abb393..3e9720e 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index dda0e6a..a5f17de 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h index 6168b85..74a390c 100644 --- a/drivers/acpi/acpica/acparser.h +++ b/drivers/acpi/acpica/acparser.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index bd3908d..a972d11 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h index 4b008e8..efc4c71 100644 --- a/drivers/acpi/acpica/acresrc.h +++ b/drivers/acpi/acpica/acresrc.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h index cf73461..d14b547 100644 --- a/drivers/acpi/acpica/acstruct.h +++ b/drivers/acpi/acpica/acstruct.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 1afe46e..1c127a4 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 486d342..c2f03e8 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index 5908cce..3a95068 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -7,7 +7,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h index 3a0beeb..ee0cdd6 100644 --- a/drivers/acpi/acpica/amlresrc.h +++ b/drivers/acpi/acpica/amlresrc.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c index 720b1cd..3e69897 100644 --- a/drivers/acpi/acpica/dsargs.c +++ b/drivers/acpi/acpica/dsargs.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c index 8daf9de..39da9da 100644 --- a/drivers/acpi/acpica/dscontrol.c +++ b/drivers/acpi/acpica/dscontrol.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index c576661..43b40de 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index aee5e45..bbe74bc 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 3c7f737..d72565a 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c index b67522d..2e4c42b 100644 --- a/drivers/acpi/acpica/dsmthdat.c +++ b/drivers/acpi/acpica/dsmthdat.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index a1e7e6b..8a7b07b 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index 6c0759c..7724418 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index 9f74795..e5ff89b 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c index f7f5107..df54d46 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index 15623da..843942f 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c index 2ac28d2..fcaa30c 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c index 9d6e2c1..43b3ea4 100644 --- a/drivers/acpi/acpica/dswscope.c +++ b/drivers/acpi/acpica/dswscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index 24f7d5e..89ac202 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c index c7bffff..bf6873f 100644 --- a/drivers/acpi/acpica/evevent.c +++ b/drivers/acpi/acpica/evevent.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evglock.c b/drivers/acpi/acpica/evglock.c index 3393a73..b78dc7c 100644 --- a/drivers/acpi/acpica/evglock.c +++ b/drivers/acpi/acpica/evglock.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index fccdfb2..836c79b 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index d0a6024..ce2a7cf 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index ebfd40d..7670508 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c index b197812..c369b19 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c index 78ac293..74e8595f 100644 --- a/drivers/acpi/acpica/evhandler.c +++ b/drivers/acpi/acpica/evhandler.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c index 24ea342..f7c9dfe 100644 --- a/drivers/acpi/acpica/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 8eb8575..9abace3 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 1b148a4..da32339 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c index 29630e3..0366703 100644 --- a/drivers/acpi/acpica/evsci.c +++ b/drivers/acpi/acpica/evsci.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index 61b0261..6d04ae9 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index bb8cbf5..df06a23 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index b836139..b8af53b 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index 2d6f187..f21afba 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 7d29494..6e0df2b 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index c545386..89a976b 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index 95d23da..aaeea48 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index 6fbfad4..e67d0ac 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 0f23c3f..7c213b6 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index b994845..c161dd9 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index 1d1b27a..4947992 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index 2207e62..b56fc9d 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index b49ea2a..472030f 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c index dbb03b5..453b00c 100644 --- a/drivers/acpi/acpica/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index 1b8e941..7793068 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index 2ede656..fcc618a 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index 363767c..b813fed 100644 --- a/drivers/acpi/acpica/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index 29e9e99..c930edd 100644 --- a/drivers/acpi/acpica/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c index 118e942..4c2836d 100644 --- a/drivers/acpi/acpica/exprep.c +++ b/drivers/acpi/acpica/exprep.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index cd5288a..0fe188e2 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c index ab06026..c7e3b92 100644 --- a/drivers/acpi/acpica/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c index 3cde553..b6b7f3a 100644 --- a/drivers/acpi/acpica/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c index 3af8de3..d2964af 100644 --- a/drivers/acpi/acpica/exresop.c +++ b/drivers/acpi/acpica/exresop.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index daf49f7..a7eee24 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c index 04bd16c..3101607 100644 --- a/drivers/acpi/acpica/exstoren.c +++ b/drivers/acpi/acpica/exstoren.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c index fd11018..6fa3c8d 100644 --- a/drivers/acpi/acpica/exstorob.c +++ b/drivers/acpi/acpica/exstorob.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c index f7da641..0545065 100644 --- a/drivers/acpi/acpica/exsystem.c +++ b/drivers/acpi/acpica/exsystem.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c index d9d72df..3f4225e 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c index 1e66d96..e5c5949 100644 --- a/drivers/acpi/acpica/hwacpi.c +++ b/drivers/acpi/acpica/hwacpi.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c index 858fdd6..e5599f6 100644 --- a/drivers/acpi/acpica/hwesleep.c +++ b/drivers/acpi/acpica/hwesleep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index b7fb00d..84bc550 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c index 6aade8e..c5214de 100644 --- a/drivers/acpi/acpica/hwpci.c +++ b/drivers/acpi/acpica/hwpci.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index a4c34d2..3cf77af 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index d590693..7d21cae 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index 76ab5c1..675c709 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c index 6b91912..2bd33fe 100644 --- a/drivers/acpi/acpica/hwvalid.c +++ b/drivers/acpi/acpica/hwvalid.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index 96d007df..5f97468 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index 6921c7f..3b37676 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index f1249e3..24fa19a 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index 607eb9e..e107f92 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsarguments.c b/drivers/acpi/acpica/nsarguments.c index 80fcfc8..5d347a7 100644 --- a/drivers/acpi/acpica/nsarguments.c +++ b/drivers/acpi/acpica/nsarguments.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsconvert.c b/drivers/acpi/acpica/nsconvert.c index b55642c..1a8b39c 100644 --- a/drivers/acpi/acpica/nsconvert.c +++ b/drivers/acpi/acpica/nsconvert.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index 3d88ef4..80f097e 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c index 42d3710..7dc367e 100644 --- a/drivers/acpi/acpica/nsdumpdv.c +++ b/drivers/acpi/acpica/nsdumpdv.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index e634a05..7bcc68f 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index a3fb7e4..4a85c45 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index 7c9d018..bd6cd4a 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index 7eee0a6..d293d97 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c index a42ee9d..677bc93 100644 --- a/drivers/acpi/acpica/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index e83cff3..c95a119 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index 392910f..0eb5431 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsprepkg.c b/drivers/acpi/acpica/nsprepkg.c index 1b13b92..8b79958 100644 --- a/drivers/acpi/acpica/nsprepkg.c +++ b/drivers/acpi/acpica/nsprepkg.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index 7e417aa..151fcd9 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index b09e6be..c30672d 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index af1cc42..4a9d4a6 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index 4a5e3f5..6ad0200 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 4758a1f..c68609a 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index 4bd558b..b6030a2 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 8c6c11c..d66c326 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index 51a8329..7933835 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index 314d314..6d03877 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index b058e23..9043722 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index a688507..2f5ddd8 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index 1755d2a..1af4a40 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psopinfo.c b/drivers/acpi/acpica/psopinfo.c index 0d8d37f..e18e7c4 100644 --- a/drivers/acpi/acpica/psopinfo.c +++ b/drivers/acpi/acpica/psopinfo.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index 6d27b59..a555f7f 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psscope.c b/drivers/acpi/acpica/psscope.c index 32d250f..9d669cc 100644 --- a/drivers/acpi/acpica/psscope.c +++ b/drivers/acpi/acpica/psscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c index 0b64181..89984f3 100644 --- a/drivers/acpi/acpica/pstree.c +++ b/drivers/acpi/acpica/pstree.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index 3cd4880..960505a 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c index 9cb07e1..ba5f691 100644 --- a/drivers/acpi/acpica/pswalk.c +++ b/drivers/acpi/acpica/pswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index e135aca..841a5ea 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c index 94a3a05..66d406e 100644 --- a/drivers/acpi/acpica/rsaddr.c +++ b/drivers/acpi/acpica/rsaddr.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index 6895567..cb739a6 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index 049d9c2..15434e4 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c index c3c56b5..1539394 100644 --- a/drivers/acpi/acpica/rsdump.c +++ b/drivers/acpi/acpica/rsdump.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsdumpinfo.c b/drivers/acpi/acpica/rsdumpinfo.c index 6ba7ad5..b29d9ec 100644 --- a/drivers/acpi/acpica/rsdumpinfo.c +++ b/drivers/acpi/acpica/rsdumpinfo.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c index 9d3f8a9..edecfc6 100644 --- a/drivers/acpi/acpica/rsinfo.c +++ b/drivers/acpi/acpica/rsinfo.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsio.c b/drivers/acpi/acpica/rsio.c index 19d6487..5adba01 100644 --- a/drivers/acpi/acpica/rsio.c +++ b/drivers/acpi/acpica/rsio.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsirq.c b/drivers/acpi/acpica/rsirq.c index 3461f7d..07cfa70 100644 --- a/drivers/acpi/acpica/rsirq.c +++ b/drivers/acpi/acpica/rsirq.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c index 7729129..50d5be2 100644 --- a/drivers/acpi/acpica/rslist.c +++ b/drivers/acpi/acpica/rslist.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsmemory.c b/drivers/acpi/acpica/rsmemory.c index eab4483..c6b8086 100644 --- a/drivers/acpi/acpica/rsmemory.c +++ b/drivers/acpi/acpica/rsmemory.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c index 41eea4b..1fe49d2 100644 --- a/drivers/acpi/acpica/rsmisc.c +++ b/drivers/acpi/acpica/rsmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsserial.c b/drivers/acpi/acpica/rsserial.c index 9e84072..4c8c6fe 100644 --- a/drivers/acpi/acpica/rsserial.c +++ b/drivers/acpi/acpica/rsserial.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c index 897a5ce..ece3cd6 100644 --- a/drivers/acpi/acpica/rsutils.c +++ b/drivers/acpi/acpica/rsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index 2952878..8e6276d 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index f499c10..6a14495 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 41519a9..7d24860 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c index cb94770..0b879fc 100644 --- a/drivers/acpi/acpica/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 755b90c..9bad45e 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbprint.c b/drivers/acpi/acpica/tbprint.c index df3bb20..ef16c06 100644 --- a/drivers/acpi/acpica/tbprint.c +++ b/drivers/acpi/acpica/tbprint.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 6b1ca99..6559a58 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 0f9dd80..60e94f8 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index ab5308b..aadb300 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c index 43a54af..eac52cf 100644 --- a/drivers/acpi/acpica/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c index a1acec9..1279f50 100644 --- a/drivers/acpi/acpica/utaddress.c +++ b/drivers/acpi/acpica/utaddress.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c index efac83c..61d8f6d 100644 --- a/drivers/acpi/acpica/utalloc.c +++ b/drivers/acpi/acpica/utalloc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utbuffer.c b/drivers/acpi/acpica/utbuffer.c index 038ea88..242bd07 100644 --- a/drivers/acpi/acpica/utbuffer.c +++ b/drivers/acpi/acpica/utbuffer.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c index 78fde0a..eacc5ee 100644 --- a/drivers/acpi/acpica/utcache.c +++ b/drivers/acpi/acpica/utcache.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index ff601c0..c37ec50 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index e516254..57078e3 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index 40e923e..988e23b 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index a3516de..71fce38 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/uterror.c b/drivers/acpi/acpica/uterror.c index 8e544d4..9ef80f2 100644 --- a/drivers/acpi/acpica/uterror.c +++ b/drivers/acpi/acpica/uterror.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c index 8fed148..6c738fa 100644 --- a/drivers/acpi/acpica/uteval.c +++ b/drivers/acpi/acpica/uteval.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utexcep.c b/drivers/acpi/acpica/utexcep.c index 0403dca..743a0ae 100644 --- a/drivers/acpi/acpica/utexcep.c +++ b/drivers/acpi/acpica/utexcep.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utfileio.c b/drivers/acpi/acpica/utfileio.c index 4e263a8..7e1168b 100644 --- a/drivers/acpi/acpica/utfileio.c +++ b/drivers/acpi/acpica/utfileio.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index 77ceac7..5e8df91 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/uthex.c b/drivers/acpi/acpica/uthex.c index 9afa944..aa44827 100644 --- a/drivers/acpi/acpica/uthex.c +++ b/drivers/acpi/acpica/uthex.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c index 4b12880..27431cf 100644 --- a/drivers/acpi/acpica/utids.c +++ b/drivers/acpi/acpica/utids.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c index 77120ec..e402e07 100644 --- a/drivers/acpi/acpica/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utlock.c b/drivers/acpi/acpica/utlock.c index dc6e965..089f78b 100644 --- a/drivers/acpi/acpica/utlock.c +++ b/drivers/acpi/acpica/utlock.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c index d44dee6..f9ff100 100644 --- a/drivers/acpi/acpica/utmath.c +++ b/drivers/acpi/acpica/utmath.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 2e2bb14..56bbacd 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index 82717ff..37b8b58 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index dfa9009b..7d83efe 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c index 685766f..574cd31 100644 --- a/drivers/acpi/acpica/utosi.c +++ b/drivers/acpi/acpica/utosi.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utownerid.c b/drivers/acpi/acpica/utownerid.c index 36bec57..2959217 100644 --- a/drivers/acpi/acpica/utownerid.c +++ b/drivers/acpi/acpica/utownerid.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utpredef.c b/drivers/acpi/acpica/utpredef.c index db30caf..29e4499 100644 --- a/drivers/acpi/acpica/utpredef.c +++ b/drivers/acpi/acpica/utpredef.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utprint.c b/drivers/acpi/acpica/utprint.c index 0ce3f5a..82ca914 100644 --- a/drivers/acpi/acpica/utprint.c +++ b/drivers/acpi/acpica/utprint.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index bc1ff82..b3505db 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c index 1cc97a7..8274cc1 100644 --- a/drivers/acpi/acpica/utstate.c +++ b/drivers/acpi/acpica/utstate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c index 6dc54b3..83b6c52 100644 --- a/drivers/acpi/acpica/utstring.c +++ b/drivers/acpi/acpica/utstring.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c index 7d0ee96..130dd9f 100644 --- a/drivers/acpi/acpica/uttrack.c +++ b/drivers/acpi/acpica/uttrack.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utuuid.c b/drivers/acpi/acpica/utuuid.c index 4dc3313..c6149a2 100644 --- a/drivers/acpi/acpica/utuuid.c +++ b/drivers/acpi/acpica/utuuid.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index 49c873c..0929187 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c index 88ef77f..306e785 100644 --- a/drivers/acpi/acpica/utxferror.c +++ b/drivers/acpi/acpica/utxferror.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c index b1fd688..083a768 100644 --- a/drivers/acpi/acpica/utxfinit.c +++ b/drivers/acpi/acpica/utxfinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxfmutex.c b/drivers/acpi/acpica/utxfmutex.c index 2a0f9e0..f2606af 100644 --- a/drivers/acpi/acpica/utxfmutex.c +++ b/drivers/acpi/acpica/utxfmutex.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acbuffer.h b/include/acpi/acbuffer.h index d5ec6c8..6b040f4 100644 --- a/include/acpi/acbuffer.h +++ b/include/acpi/acbuffer.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h index 5a0a3e5..03aacfb 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h index 8b06e4c..11c3a01 100644 --- a/include/acpi/acexcep.h +++ b/include/acpi/acexcep.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h index 7461327..273de70 100644 --- a/include/acpi/acnames.h +++ b/include/acpi/acnames.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index 1baae6e..9318a87 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acpi.h b/include/acpi/acpi.h index a08e55a..b0bb30e 100644 --- a/include/acpi/acpi.h +++ b/include/acpi/acpi.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index 03b3e6d..0bc78df 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -7,7 +7,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 5dd21bc..f81e530 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acrestyp.h b/include/acpi/acrestyp.h index 0b75e01..ebe2426 100644 --- a/include/acpi/acrestyp.h +++ b/include/acpi/acrestyp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index bee19d8..d4081fe 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index 29e7937..b80b0e6 100644 --- a/include/acpi/actbl1.h +++ b/include/acpi/actbl1.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index ecff624..f06d75e 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/actbl3.h b/include/acpi/actbl3.h index 5480cb2..440ca81 100644 --- a/include/acpi/actbl3.h +++ b/include/acpi/actbl3.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 401705d..453cebb 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index 5f8cc1f..ad74dc5 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/platform/acenvex.h b/include/acpi/platform/acenvex.h index 2b61238..71e5ec5 100644 --- a/include/acpi/platform/acenvex.h +++ b/include/acpi/platform/acenvex.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h index 384875d..f54de0a 100644 --- a/include/acpi/platform/acgcc.h +++ b/include/acpi/platform/acgcc.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 1ba7c19..74ba46c 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h index 568d4b8..acedc3f 100644 --- a/include/acpi/platform/aclinuxex.h +++ b/include/acpi/platform/aclinuxex.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/tools/power/acpi/common/cmfsize.c b/tools/power/acpi/common/cmfsize.c index f4b9533..eec6880 100644 --- a/tools/power/acpi/common/cmfsize.c +++ b/tools/power/acpi/common/cmfsize.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/tools/power/acpi/common/getopt.c b/tools/power/acpi/common/getopt.c index 2f0f34a..5da129e 100644 --- a/tools/power/acpi/common/getopt.c +++ b/tools/power/acpi/common/getopt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/tools/power/acpi/os_specific/service_layers/oslibcfs.c b/tools/power/acpi/os_specific/service_layers/oslibcfs.c index c13ff9c..b51e40a 100644 --- a/tools/power/acpi/os_specific/service_layers/oslibcfs.c +++ b/tools/power/acpi/os_specific/service_layers/oslibcfs.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c index 0dc2485..92f1fd7 100644 --- a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c +++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/tools/power/acpi/os_specific/service_layers/osunixdir.c b/tools/power/acpi/os_specific/service_layers/osunixdir.c index 733f9e4..e153fcb 100644 --- a/tools/power/acpi/os_specific/service_layers/osunixdir.c +++ b/tools/power/acpi/os_specific/service_layers/osunixdir.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/tools/power/acpi/os_specific/service_layers/osunixmap.c b/tools/power/acpi/os_specific/service_layers/osunixmap.c index 99b47b6..3853a73 100644 --- a/tools/power/acpi/os_specific/service_layers/osunixmap.c +++ b/tools/power/acpi/os_specific/service_layers/osunixmap.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/tools/power/acpi/os_specific/service_layers/osunixxf.c b/tools/power/acpi/os_specific/service_layers/osunixxf.c index 7ccb073..6858c08 100644 --- a/tools/power/acpi/os_specific/service_layers/osunixxf.c +++ b/tools/power/acpi/os_specific/service_layers/osunixxf.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/tools/power/acpi/tools/acpidump/acpidump.h b/tools/power/acpi/tools/acpidump/acpidump.h index a2d37d6..84bdef0 100644 --- a/tools/power/acpi/tools/acpidump/acpidump.h +++ b/tools/power/acpi/tools/acpidump/acpidump.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/tools/power/acpi/tools/acpidump/apdump.c b/tools/power/acpi/tools/acpidump/apdump.c index 24d32968..c736adf 100644 --- a/tools/power/acpi/tools/acpidump/apdump.c +++ b/tools/power/acpi/tools/acpidump/apdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/tools/power/acpi/tools/acpidump/apfiles.c b/tools/power/acpi/tools/acpidump/apfiles.c index d470046..8f2fe16 100644 --- a/tools/power/acpi/tools/acpidump/apfiles.c +++ b/tools/power/acpi/tools/acpidump/apfiles.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/tools/power/acpi/tools/acpidump/apmain.c b/tools/power/acpi/tools/acpidump/apmain.c index 853b4da..d0ba653 100644 --- a/tools/power/acpi/tools/acpidump/apmain.c +++ b/tools/power/acpi/tools/acpidump/apmain.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without -- cgit v0.10.2 From 121b7d91e902f19d21a669618f6b8966180e5131 Mon Sep 17 00:00:00 2001 From: "David E. Box" Date: Thu, 5 Feb 2015 15:20:54 +0800 Subject: ACPICA: Update version to 20150204 ACPICA commit e06b1624b02dc8317d144e9a6fe9d684c5fa2f90 Version 20150204. Link: https://github.com/acpica/acpica/commit/e06b1624 Signed-off-by: David E. Box Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index f81e530..96e4ef3 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -46,7 +46,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20141107 +#define ACPI_CA_VERSION 0x20150204 #include #include -- cgit v0.10.2 From 0d0988af81ac809b30f818f0c0f065327ff6423b Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 5 Feb 2015 16:27:03 +0800 Subject: ACPICA: Events: Introduce ACPI_GPE_DISPATCH_RAW_HANDLER to fix 2 issues for the current GPE APIs ACPICA commit 199cad16530a45aea2bec98e528866e20c5927e1 Since whether the GPE should be disabled/enabled/cleared should only be determined by the GPE driver's state machine: 1. GPE should be disabled if the driver wants to switch to the GPE polling mode when a GPE storm condition is indicated and should be enabled if the driver wants to switch back to the GPE interrupt mode when all of the storm conditions are cleared. The conditions should be protected by the driver's specific lock. 2. GPE should be enabled if the driver has accepted more than one request and should be disabled if the driver has completed all of the requests. The request count should be protected by the driver's specific lock. 3. GPE should be cleared either when the driver is about to handle an edge triggered GPE or when the driver has completed to handle a level triggered GPE. The handling code should be protected by the driver's specific lock. Thus the GPE enabling/disabling/clearing operations are likely to be performed with the driver's specific lock held while we currently cannot do this. This is because: 1. We have the acpi_gbl_gpe_lock held before invoking the GPE driver's handler. Driver's specific lock is likely to be held inside of the handler, thus we can see some dead lock issues due to the reversed locking order or recursive locking. In order to solve such dead lock issues, we need to unlock the acpi_gbl_gpe_lock before invoking the handler. BZ 1100. 2. Since GPE disabling/enabling/clearing should be determined by the GPE driver's state machine, we shouldn't perform such operations inside of ACPICA for a GPE handler to mess up the driver's state machine. BZ 1101. Originally this patch includes a logic to flush GPE handlers, it is dropped due to the following reasons: 1. This is a different issue; 2. Linux OSL has fixed this by flushing SCI in acpi_os_wait_events_complete(). We will pick up this topic when the Linux OSL fix turns out to be not sufficient. Note that currently the internal operations and the acpi_gbl_gpe_lock are also used by ACPI_GPE_DISPATCH_METHOD and ACPI_GPE_DISPATCH_NOTIFY. In order not to introduce regressions, we add one ACPI_GPE_DISPATCH_RAW_HANDLER type to be distiguished from ACPI_GPE_DISPATCH_HANDLER. For which the acpi_gbl_gpe_lock is unlocked before invoking the GPE handler and the internal enabling/disabling operations are bypassed to allow drivers to perform them at a proper position using the GPE APIs and ACPI_GPE_DISPATCH_RAW_HANDLER users should invoke acpi_set_gpe() instead of acpi_enable_gpe()/acpi_disable_gpe() to bypass the internal GPE clearing code in acpi_enable_gpe(). Lv Zheng. Known issues: 1. Edge-triggered GPE lost for frequent enablings On some buggy silicon platforms, GPE enable line may not be directly wired to the GPE trigger line. In that case, when GPE enabling is frequently performed for edge-triggered GPEs, GPE status may stay set without being triggered. This patch may maginify this problem as it allows GPE enabling to be parallel performed during the process the GPEs are handled. This is an existing issue, because: 1. For task context: Current ACPI_GPE_DISPATCH_METHOD practices have proven that this isn't a real issue - we can re-enable edge-triggered GPE in a work queue where the GPE status bit might already be set. 2. For IRQ context: This can even happen when the GPE enabling occurs before returning from the GPE handler and after unlocking the GPE lock. Thus currently no code is included to protect this. Link: https://github.com/acpica/acpica/commit/199cad16 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 836c79b..5ed064e 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -332,6 +332,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list) struct acpi_gpe_register_info *gpe_register_info; struct acpi_gpe_event_info *gpe_event_info; u32 gpe_number; + struct acpi_gpe_handler_info *gpe_handler_info; u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; u8 enabled_status_byte; u32 status_reg; @@ -455,14 +456,49 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list) acpi_gbl_global_event_handler_context); } - /* - * Found an active GPE. Dispatch the event to a handler - * or method. - */ - int_status |= - acpi_ev_gpe_dispatch(gpe_device, - gpe_event_info, - gpe_number); + /* Found an active GPE */ + + if (ACPI_GPE_DISPATCH_TYPE + (gpe_event_info->flags) == + ACPI_GPE_DISPATCH_RAW_HANDLER) { + + /* Dispatch the event to a raw handler */ + + gpe_handler_info = + gpe_event_info->dispatch. + handler; + + /* + * There is no protection around the namespace node + * and the GPE handler to ensure a safe destruction + * because: + * 1. The namespace node is expected to always + * exist after loading a table. + * 2. The GPE handler is expected to be flushed by + * acpi_os_wait_events_complete() before the + * destruction. + */ + acpi_os_release_lock + (acpi_gbl_gpe_lock, flags); + int_status |= + gpe_handler_info-> + address(gpe_device, + gpe_number, + gpe_handler_info-> + context); + flags = + acpi_os_acquire_lock + (acpi_gbl_gpe_lock); + } else { + /* + * Dispatch the event to a standard handler or + * method. + */ + int_status |= + acpi_ev_gpe_dispatch + (gpe_device, gpe_event_info, + gpe_number); + } } } } diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index ce2a7cf..e0f24c5 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -478,6 +478,8 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, ACPI_GPE_DISPATCH_NONE) || (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == ACPI_GPE_DISPATCH_HANDLER) + || (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == + ACPI_GPE_DISPATCH_RAW_HANDLER) || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { continue; } diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index 7670508..8840296 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -401,8 +401,10 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle, return_ACPI_STATUS(AE_OK); } - if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == - ACPI_GPE_DISPATCH_HANDLER) { + if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == + ACPI_GPE_DISPATCH_HANDLER) || + (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == + ACPI_GPE_DISPATCH_RAW_HANDLER)) { /* If there is already a handler, ignore this GPE method */ diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c index c369b19..3a958f3 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -324,8 +324,10 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, ACPI_GPE_REGISTER_WIDTH) + j]; - if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == - ACPI_GPE_DISPATCH_HANDLER) { + if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == + ACPI_GPE_DISPATCH_HANDLER) || + (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == + ACPI_GPE_DISPATCH_RAW_HANDLER)) { /* Delete an installed handler block */ diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index 6d04ae9..81f2d9e 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -51,6 +51,16 @@ #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evxface") +#if (!ACPI_REDUCED_HARDWARE) +/* Local prototypes */ +static acpi_status +acpi_ev_install_gpe_handler(acpi_handle gpe_device, + u32 gpe_number, + u32 type, + u8 is_raw_handler, + acpi_gpe_handler address, void *context); + +#endif /******************************************************************************* @@ -76,6 +86,7 @@ ACPI_MODULE_NAME("evxface") * handlers. * ******************************************************************************/ + acpi_status acpi_install_notify_handler(acpi_handle device, u32 handler_type, @@ -717,32 +728,37 @@ ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler) /******************************************************************************* * - * FUNCTION: acpi_install_gpe_handler + * FUNCTION: acpi_ev_install_gpe_handler * * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT * defined GPEs) * gpe_number - The GPE number within the GPE block * type - Whether this GPE should be treated as an * edge- or level-triggered interrupt. + * is_raw_handler - Whether this GPE should be handled using + * the special GPE handler mode. * address - Address of the handler * context - Value passed to the handler on each GPE * * RETURN: Status * - * DESCRIPTION: Install a handler for a General Purpose Event. + * DESCRIPTION: Internal function to install a handler for a General Purpose + * Event. * ******************************************************************************/ -acpi_status -acpi_install_gpe_handler(acpi_handle gpe_device, - u32 gpe_number, - u32 type, acpi_gpe_handler address, void *context) +static acpi_status +acpi_ev_install_gpe_handler(acpi_handle gpe_device, + u32 gpe_number, + u32 type, + u8 is_raw_handler, + acpi_gpe_handler address, void *context) { struct acpi_gpe_event_info *gpe_event_info; struct acpi_gpe_handler_info *handler; acpi_status status; acpi_cpu_flags flags; - ACPI_FUNCTION_TRACE(acpi_install_gpe_handler); + ACPI_FUNCTION_TRACE(ev_install_gpe_handler); /* Parameter validation */ @@ -775,8 +791,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device, /* Make sure that there isn't a handler there already */ - if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == - ACPI_GPE_DISPATCH_HANDLER) { + if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == + ACPI_GPE_DISPATCH_HANDLER) || + (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == + ACPI_GPE_DISPATCH_RAW_HANDLER)) { status = AE_ALREADY_EXISTS; goto free_and_exit; } @@ -817,7 +835,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device, gpe_event_info->flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); - gpe_event_info->flags |= (u8)(type | ACPI_GPE_DISPATCH_HANDLER); + gpe_event_info->flags |= + (u8)(type | + (is_raw_handler ? ACPI_GPE_DISPATCH_RAW_HANDLER : + ACPI_GPE_DISPATCH_HANDLER)); acpi_os_release_lock(acpi_gbl_gpe_lock, flags); @@ -831,10 +852,78 @@ free_and_exit: goto unlock_and_exit; } +/******************************************************************************* + * + * FUNCTION: acpi_install_gpe_handler + * + * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT + * defined GPEs) + * gpe_number - The GPE number within the GPE block + * type - Whether this GPE should be treated as an + * edge- or level-triggered interrupt. + * address - Address of the handler + * context - Value passed to the handler on each GPE + * + * RETURN: Status + * + * DESCRIPTION: Install a handler for a General Purpose Event. + * + ******************************************************************************/ + +acpi_status +acpi_install_gpe_handler(acpi_handle gpe_device, + u32 gpe_number, + u32 type, acpi_gpe_handler address, void *context) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_install_gpe_handler); + + status = + acpi_ev_install_gpe_handler(gpe_device, gpe_number, type, FALSE, + address, context); + + return_ACPI_STATUS(status); +} + ACPI_EXPORT_SYMBOL(acpi_install_gpe_handler) /******************************************************************************* * + * FUNCTION: acpi_install_gpe_raw_handler + * + * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT + * defined GPEs) + * gpe_number - The GPE number within the GPE block + * type - Whether this GPE should be treated as an + * edge- or level-triggered interrupt. + * address - Address of the handler + * context - Value passed to the handler on each GPE + * + * RETURN: Status + * + * DESCRIPTION: Install a handler for a General Purpose Event. + * + ******************************************************************************/ +acpi_status +acpi_install_gpe_raw_handler(acpi_handle gpe_device, + u32 gpe_number, + u32 type, acpi_gpe_handler address, void *context) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_install_gpe_raw_handler); + + status = acpi_ev_install_gpe_handler(gpe_device, gpe_number, type, TRUE, + address, context); + + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_install_gpe_raw_handler) + +/******************************************************************************* + * * FUNCTION: acpi_remove_gpe_handler * * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT @@ -881,8 +970,10 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, /* Make sure that a handler is indeed installed */ - if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != - ACPI_GPE_DISPATCH_HANDLER) { + if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != + ACPI_GPE_DISPATCH_HANDLER) && + (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != + ACPI_GPE_DISPATCH_RAW_HANDLER)) { status = AE_NOT_EXIST; goto unlock_and_exit; } diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 96e4ef3..d56f5d7 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -569,6 +569,14 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status address, void *context)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status + acpi_install_gpe_raw_handler(acpi_handle + gpe_device, + u32 gpe_number, + u32 type, + acpi_gpe_handler + address, + void *context)) +ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_remove_gpe_handler(acpi_handle gpe_device, u32 gpe_number, acpi_gpe_handler diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 453cebb..b034f10 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -744,7 +744,7 @@ typedef u32 acpi_event_status; /* * GPE info flags - Per GPE * +-------+-+-+---+ - * | 7:4 |3|2|1:0| + * | 7:5 |4|3|2:0| * +-------+-+-+---+ * | | | | * | | | +-- Type of dispatch:to method, handler, notify, or none @@ -756,14 +756,15 @@ typedef u32 acpi_event_status; #define ACPI_GPE_DISPATCH_METHOD (u8) 0x01 #define ACPI_GPE_DISPATCH_HANDLER (u8) 0x02 #define ACPI_GPE_DISPATCH_NOTIFY (u8) 0x03 -#define ACPI_GPE_DISPATCH_MASK (u8) 0x03 +#define ACPI_GPE_DISPATCH_RAW_HANDLER (u8) 0x04 +#define ACPI_GPE_DISPATCH_MASK (u8) 0x07 #define ACPI_GPE_DISPATCH_TYPE(flags) ((u8) ((flags) & ACPI_GPE_DISPATCH_MASK)) -#define ACPI_GPE_LEVEL_TRIGGERED (u8) 0x04 +#define ACPI_GPE_LEVEL_TRIGGERED (u8) 0x08 #define ACPI_GPE_EDGE_TRIGGERED (u8) 0x00 -#define ACPI_GPE_XRUPT_TYPE_MASK (u8) 0x04 +#define ACPI_GPE_XRUPT_TYPE_MASK (u8) 0x08 -#define ACPI_GPE_CAN_WAKE (u8) 0x08 +#define ACPI_GPE_CAN_WAKE (u8) 0x10 /* * Flags for GPE and Lock interfaces -- cgit v0.10.2 From eb3d80f729e07394685239ddd137fbee5c13a2ea Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 5 Feb 2015 16:27:09 +0800 Subject: ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce divergences This can help to reduce source code differences between Linux and ACPICA upstream. Further driver cleanups also require these APIs to eliminate GPE storms. 1. acpi_set_gpe(): An API that driver should invoke in the case it wants to disable/enable IRQ without honoring the reference count implemented in the acpi_disable_gpe() and acpi_enable_gpe(). Note that this API should only be invoked inside a acpi_enable_gpe()/acpi_disable_gpe() pair. 2. acpi_finish_gpe(): Drivers returned ACPI_REENABLE_GPE unset from the GPE handler should use this API instead of invoking acpi_set_gpe()/acpi_enable_gpe() to re-enable the GPE. The GPE APIs can be invoked inside of a GPE handler or in the task context with a driver provided lock held. This driver provided lock is safe to be held in the GPE handler by the driver. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index b8af53b..caaeb1a 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -183,6 +183,68 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number) ACPI_EXPORT_SYMBOL(acpi_disable_gpe) +/******************************************************************************* + * + * FUNCTION: acpi_set_gpe + * + * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 + * gpe_number - GPE level within the GPE block + * action - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE + * + * RETURN: Status + * + * DESCRIPTION: Enable or disable an individual GPE. This function bypasses + * the reference count mechanism used in the acpi_enable_gpe and + * acpi_disable_gpe interfaces -- and should be used with care. + * + * Note: Typically used to disable a runtime GPE for short period of time, + * then re-enable it, without disturbing the existing reference counts. This + * is useful, for example, in the Embedded Controller (EC) driver. + * + ******************************************************************************/ +acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action) +{ + struct acpi_gpe_event_info *gpe_event_info; + acpi_status status; + acpi_cpu_flags flags; + + ACPI_FUNCTION_TRACE(acpi_set_gpe); + + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + + /* Ensure that we have a valid GPE number */ + + gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); + if (!gpe_event_info) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + /* Perform the action */ + + switch (action) { + case ACPI_GPE_ENABLE: + + status = acpi_ev_enable_gpe(gpe_event_info); + break; + + case ACPI_GPE_DISABLE: + + status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); + break; + + default: + + status = AE_BAD_PARAMETER; + break; + } + +unlock_and_exit: + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_set_gpe) /******************************************************************************* * @@ -530,6 +592,49 @@ unlock_and_exit: ACPI_EXPORT_SYMBOL(acpi_get_gpe_status) +/******************************************************************************* + * + * FUNCTION: acpi_finish_gpe + * + * PARAMETERS: gpe_device - Namespace node for the GPE Block + * (NULL for FADT defined GPEs) + * gpe_number - GPE level within the GPE block + * + * RETURN: Status + * + * DESCRIPTION: Clear and conditionally reenable a GPE. This completes the GPE + * processing. Intended for use by asynchronous host-installed + * GPE handlers. The GPE is only reenabled if the enable_for_run bit + * is set in the GPE info. + * + ******************************************************************************/ +acpi_status acpi_finish_gpe(acpi_handle gpe_device, u32 gpe_number) +{ + struct acpi_gpe_event_info *gpe_event_info; + acpi_status status; + acpi_cpu_flags flags; + + ACPI_FUNCTION_TRACE(acpi_finish_gpe); + + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + + /* Ensure that we have a valid GPE number */ + + gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); + if (!gpe_event_info) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + status = acpi_ev_finish_gpe(gpe_event_info); + +unlock_and_exit: + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_finish_gpe) + /****************************************************************************** * * FUNCTION: acpi_disable_all_gpes -- cgit v0.10.2 From 2eedd3d8398b266ee8e846ded03218bb6a00e2c1 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 5 Feb 2015 16:27:15 +0800 Subject: ACPICA: Events: Enable APIs to allow interrupt/polling adaptive request based GPE handling model ACPICA commit da9a83e1a845f2d7332bdbc0632466b2595e5424 For acpi_set_gpe()/acpi_enable_gpe(), our target is to purify them to be APIs that can be used for various GPE handling models, so we need them to be pure GPE enabling APIs. GPE enabling/disabling has 2 use cases: 1. Driver may permanently enable/disable GPEs according to the usage counts. 1. When upper layers (the users of the driver) submit requests to the driver, it means they care about the underlying hardware. GPE need to be enabled for the first request submission and disabled for the last request completion. 2. When the GPE is shared between 2+ silicon logics. GPE need to be enabled for either silicon logic's driver and disabled when all of the drivers are not started. For these cases, acpi_enable_gpe()/acpi_disable_gpe() should be used. When the usage count is increased from 0 to 1, the GPE is enabled and it is disabled when the usage count is decrased from 1 to 0. 2. Driver may temporarily disables the GPE to enter an GPE polling mode and wants to re-enable it later. 1. Prevent GPE storming: when a driver cannot fully solve the condition that triggered the GPE in the GPE context, in order not to trigger GPE storm, driver has to disable GPE to switch into the polling mode and re-enables it in the non interrupt context after the storming condition is cleared. 2. Meet throughput requirement: some IO drivers need to poll hardware again and again until nothing indicated instead of just handling once for one interruption, this need to be done in the polling mode or the IO flood may prevent the GPE handler from returning. 3. Meet realtime requirement: in order not to block CPU to handle higher realtime prioritized GPEs, lower priority GPEs can be handled in the polling mode. For these cases, acpi_set_gpe() should be used to switch to/from the polling mode. This patch adds unconditional GPE enabling support into acpi_set_gpe() so that this API can be used by the drivers to switch back from the GPE polling mode unconditionally. Originally this function includes GPE clearing logic in it. First, the GPE clearing is typically used in the GPE handling code to: 1. Acknowledge the GPE when we know there is an edge triggered GPE raised and is about to handle it, otherwise the unexpected clearing may lead to a GPE loss; 2. Issue actions after we have handled a level triggered GPE, otherwise the unexpected clearing may trigger unwanted OSPM actions to the hardware (for example, clocking in out-dated write FIFO data). Thus the GPE clearing is not suitable to be used in the GPE enabling APIs. Second, the combination of acknowledging and enabling may also not be expected by the hardware drivers. For GPE clearing, we have a seperate API acpi_clear_gpe(). There are cases drivers do want the 2 operations to be split. So splitting these 2 operations could facilitates drivers the maximum possibilities to achieve success. For a combined one, we already have acpi_finish_gpe() ready to be invoked. Given the fact that drivers should complete all outstanding requests before putting themselves into the sleep states, as this API is executed for outstanding requests, it should also have nothing to do with the "RUN"/"WAKE" distinguishing. That's why the acpi_set_gpe(ACPI_GPE_ENABLE) should not be implemented by acpi_hw_low_set_gpe(ACPI_GPE_CONDITIONAL_ENABLE). This patch thus converts acpi_set_gpe(ACPI_GPE_ENABLE) into acpi_hw_low_set_gpe(ACPI_GPE_ENABLE) to achieve a seperate GPE enabling API. Drivers then are encouraged to use this API when they need to switch to/from the GPE polling mode. Note that the acpi_set_gpe()/acpi_finish_gpe() should be first introduced to Linux using a divergence reduction patch before sending a linuxized version of this patch. Lv Zheng. Link: https://github.com/acpica/acpica/commit/da9a83e1 Signed-off-by: Lv Zheng Signed-off-by: David E. Box Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index caaeb1a..70eb47e 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -194,12 +194,21 @@ ACPI_EXPORT_SYMBOL(acpi_disable_gpe) * RETURN: Status * * DESCRIPTION: Enable or disable an individual GPE. This function bypasses - * the reference count mechanism used in the acpi_enable_gpe and - * acpi_disable_gpe interfaces -- and should be used with care. - * - * Note: Typically used to disable a runtime GPE for short period of time, - * then re-enable it, without disturbing the existing reference counts. This - * is useful, for example, in the Embedded Controller (EC) driver. + * the reference count mechanism used in the acpi_enable_gpe(), + * acpi_disable_gpe() interfaces. + * This API is typically used by the GPE raw handler mode driver + * to switch between the polling mode and the interrupt mode after + * the driver has enabled the GPE. + * The APIs should be invoked in this order: + * acpi_enable_gpe() <- Ensure the reference count > 0 + * acpi_set_gpe(ACPI_GPE_DISABLE) <- Enter polling mode + * acpi_set_gpe(ACPI_GPE_ENABLE) <- Leave polling mode + * acpi_disable_gpe() <- Decrease the reference count + * + * Note: If a GPE is shared by 2 silicon components, then both the drivers + * should support GPE polling mode or disabling the GPE for long period + * for one driver may break the other. So use it with care since all + * firmware _Lxx/_Exx handlers currently rely on the GPE interrupt mode. * ******************************************************************************/ acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action) @@ -225,7 +234,7 @@ acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action) switch (action) { case ACPI_GPE_ENABLE: - status = acpi_ev_enable_gpe(gpe_event_info); + status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE); break; case ACPI_GPE_DISABLE: -- cgit v0.10.2 From ca37bfdfbc8d0a3ec73e4b97bb26dcfa51d515aa Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 5 Feb 2015 16:27:22 +0800 Subject: ACPI / EC: Fix several GPE handling issues by deploying ACPI_GPE_DISPATCH_RAW_HANDLER mode. This patch switches EC driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode where the GPE lock is not held for acpi_ec_gpe_handler() and the ACPICA internal GPE enabling/disabling/clearing operations are bypassed so that further improvements are possible with the GPE APIs. There are 2 strong reasons for deploying raw GPE handler mode in the EC driver: 1. Some hardware logics can control their interrupts via their own registers, so their interrupts can be disabled/enabled/acknowledged without using the super IRQ controller provided functions. While there is no mean (EC commands) for the EC driver to achieve this. 2. During suspending, the EC driver is still working for a while to complete the platform firmware provided functionailities using ec_poll() after all GPEs are disabled (see acpi_ec_block_transactions()), which means the EC driver will drive the EC GPE out of the GPE core's control. Without deploying the raw GPE handler mode, we can see many races between the EC driver and the GPE core due to the above restrictions: 1. There is a race condition due to ACPICA internal GPE disabling/clearing/enabling logics in acpi_ev_gpe_dispatch(): Orignally EC GPE is disabled (EN=0), cleared (STS=0) before invoking a GPE handler and re-enabled (EN=1) after invoking a GPE handler in acpi_ev_gpe_dispatch(). When re-enabling appears, GPE may be flagged (STS=1). ================================================================= (event pending A) ================================================================= acpi_ev_gpe_dispatch() ec_poll() EN=0 STS=0 acpi_ec_gpe_handler() ***************************************************************** (event handling A) Lock(EC) advance_transaction() EC_SC read ================================================================= (event pending B) ================================================================= EC_SC handled Unlock(EC) ***************************************************************** ***************************************************************** (event handling B) Lock(EC) advance_transaction() EC_SC read ================================================================= (event pending C) ================================================================= EC_SC handled Unlock(EC) ***************************************************************** EN=1 This race condition is the root cause of different issues on different silicon variations. A. Silicon variation A: On some platforms, GPE will be triggered due to "writing 1 to EN when STS=1". This is because both EN and STS lines are wired to the GPE trigger line. 1. Issue 1: We can see no-op acpi_ec_gpe_handler() invoked on such platforms. This is because: a. event pending B: An event can arrive after ACPICA's GPE clearing performed in acpi_ev_gpe_dispatch(), this event may fail to be detected by EC_SC read that is performed before its arrival; b. event handling B: The event can be handled in ec_poll() because EC lock is released after acpi_ec_gpe_handler() invocation; c. There is no code in ec_poll() to clear STS but the GPE can still be triggered by the EN=1 write performed in acpi_ev_finish_gpe(), this leads to a no-op EC GPE handler invocation; d. As no-op GPE handler invocations are counted by the EC driver to trigger the command storming conditions, the wrong no-op GPE handler invocations thus can easily trigger wrong command storming conditions. Note 1: If we removed GPE disabling/enabling code from acpi_ev_gpe_dispatch(), we could still see no-op GPE handlers triggered by the event arriving after the GPE clearing and before the GPE handling on both silicon variation A and B. This can only occur if the CPU is very slow (timing slice between STS=0 write and EC_SC read should be short enough before hardware sets another GPE indication). Thus this is very rare and is not what we need to fix. B. Silicon variation B: On other platforms, GPE may not be triggered due to "writing 1 to EN when STS=1". This is because only STS line is wired to the GPE trigger line. 2. Issue 2: We can see GPE loss on such platforms. This is because: a. event pending B vs. event handling A: An event can arrive after ACPICA's GPE handling performed in acpi_ev_gpe_dispatch(), or event pending C vs. event handling B: An event can arrive after Linux's GPE handling performed in ec_poll(), these events may fail to be detected by EC_SC read that is performed before their arrival; b. The GPE cannot be triggered by EN=1 write performed in acpi_ev_finish_gpe(); c. If no polling mechanism is implemented in the driver for the pending event (for example, SCI_EVT), this event is lost due to no GPE being triggered. Note 2: On most platforms, there might be another rule that GPE may not be triggered due to "writing 1 to STS when STS=1 and EN=1". Then on silicon variation B, an even worse case is if the issue 2 event loss happens, further events may never trigger GPE again on such platforms due to being blocked by the current STS=1. Unless someone clears STS, all events have to be polled. 2. There is a race condition due to lacking in GPE status checking in EC driver: Originally, GPE status is checked in ACPICA core but not checked in the GPE handler. Thus since the status checking and handling is not locked, it can be interrupted by another handling path. ================================================================= (event pending A) ================================================================= acpi_ev_gpe_detect() ec_poll() if (EN==1 && STS==1) ***************************************************************** (event handling A) Lock(EC) advance_transaction() EC_SC read EC_SC handled Unlock(EC) ***************************************************************** acpi_ev_gpe_dispatch() EN=0 STS=0 acpi_ec_gpe_handler() ***************************************************************** (event handling B) Lock(EC) advance_transaction() EC_SC read Unlock(EC) ***************************************************************** 3. Issue 3: We can see no-op acpi_ec_gpe_handler() invoked on both silicon variation A and B. This is because: a. event pending A: An event can arrive to trigger an EC GPE and ACPICA checks it and is about to invoke the EC GPE handler; b. event handling A: The event can be handled in ec_poll() because EC lock is not held after the GPE status checking; c. event handling B: Then when the EC GPE handler is invoked, it becomes a no-op GPE handler invocation. d. As no-op GPE handler invocations are counted by the EC driver to trigger the command storming conditions, the wrong no-op GPE handler invocations thus can easily trigger wrong command storming conditions. Note 3: This no-op GPE handler invocation is rare because the time between the IRQ arrival and the acpi_ec_gpe_handler() invocation is less than the timeout value waited in ec_poll(). So most of the no-op GPE handler invocations are caused by the reason described in issue 1. 3. There is a race condition due to ACPICA internal GPE clearing logic in acpi_enable_gpe(): During runtime, acpi_enable_gpe() can be invoked by the EC storming prevention code. When it is invoked, GPE may be flagged (STS=1). ================================================================= (event pending A) ================================================================= acpi_ev_gpe_dispatch() acpi_ec_transaction() EN=0 STS=0 acpi_ec_gpe_handler() ***************************************************************** (event handling A) Lock(EC) advance_transaction() EC_SC read EC_SC handled Unlock(EC) ***************************************************************** EN=1 ? Lock(EC) Unlock(EC) ================================================================= (event pending B) ================================================================= acpi_enable_gpe() STS=0 EN=1 4. Issue 4: We can see GPE loss on both silicon variation A and B platforms. This is because: a. event pending B: An event can arrive right before ACPICA's GPE clearing performed in acpi_enable_gpe(); b. If the GPE is cleared when GPE is disabled, then EN=1 write in acpi_enable_gpe() cannot trigger this GPE; c. If no polling mechanism is implemented in the driver for this event (for example, SCI_EVT), this event is lost due to no GPE being triggered. Note 4: Currently we don't have this issue, but after we switch the EC driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode, we need to take care of handling this because the EN=1 write in acpi_ev_gpe_dispatch() will be abandoned. There might be more race issues for the current GPE handler usages. This is because the EC IRQ's enabling/disabling/checking/clearing/handling operations should be locked by a single lock that is under the EC driver's control to achieve the serialization. Which means we need to invoke GPE APIs with EC driver's lock held and all ACPICA internal GPE operations related to the GPE handler should be abandoned. Invoking GPE APIs inside of the EC driver lock and bypassing ACPICA internal GPE operations requires the ACPI_GPE_DISPATCH_RAW_HANDLER mode where the same lock used by the APIs are released prior than invoking the handlers. Otherwise, we can see dead locks due to circular locking dependencies (see Reference below). This patch then switches the EC driver into the ACPI_GPE_DISPATCH_RAW_HANDLER mode so that it can perform correct GPE operations using the GPE APIs: 1. Bypasses EN modifications performed in acpi_ev_gpe_dispatch() by using acpi_install_gpe_raw_handler() and invoking all GPE APIs with EC spin lock held. This can fix issue 1 as it makes a non frequent GPE enabling/disabling environment. 2. Bypasses STS clearing performed in acpi_enable_gpe() by replacing acpi_enable_gpe()/acpi_disable_gpe() with acpi_set_gpe(). This can fix issue 4. And this can also help to fix issue 1 as it makes a no sudden GPE clearing environment when GPE is frequently enabled/disabled. 3. Ensures STS acknowledged before handling by invoking acpi_clear_gpe() in advance_transaction(). This can finally fix issue 1 even in a frequent GPE enabling/disabling environment. And this can also finally fix issue 3 when issue 2 is fixed. Note 3: GPE clearing is edge triggered W1C, which means we can clear it right before handling it. Since all EC GPE indications are handled in advance_transaction() by previous commits, we can now move GPE clearing into it to implement the correct GPE clearing. Note 4: We can use acpi_set_gpe() which is not shared GPE safer instead of acpi_enable_gpe()/acpi_disable_gpe() because EC GPE is not shared by other hardware, which is mentioned in the ACPI specification 5.0, 12.6 Interrupt Model: "OSPM driver treats this as an edge event (the EC SCI cannot be shared)". So we can stop using shared GPE safer APIs acpi_enable_gpe()/acpi_disable_gpe() in the EC driver. Otherwise cleanups need to be made in acpi_ev_enable_gpe() to bypass the GPE clearing logic before keeping acpi_enable_gpe(). This patch also invokes advance_transaction() when GPE is re-enabled in the task context which: 1. Ensures EN=1 can trigger GPE by checking and handling EC status register right after EN=1 writes. This can fix issue 2. After applying this patch, without frequent GPE enablings considered: ================================================================= (event pending A) ================================================================= acpi_ec_gpe_handler() ec_poll() ***************************************************************** (event handling A) Lock(EC) advance_transaction() if STS==1 STS=0 EC_SC read ================================================================= (event pending B) ================================================================= EC_SC handled Unlock(EC) ***************************************************************** ***************************************************************** (event handling B) Lock(EC) advance_transaction() if STS==1 STS=0 EC_SC read ================================================================= (event pending C) ================================================================= EC_SC handled Unlock(EC) ***************************************************************** The event pending for issue 1 (event pending B) can arrive as a next GPE due to the previous IRQ context STS=0 write. And if it is handled by ec_poll() (event handling B), as it is also acknowledged by ec_poll(), the event pending for issue 2 (event pending C) can properly arrive as a next GPE after the task context STS=0 write. So no GPE will be lost and never triggered due to GPE clearing performed in the wrong position. And since all GPE handling is performed after a locked GPE status checking, we can hardly see no-op GPE handler invocations due to issue 1 and 3. We may still see no-op GPE handler invocations due to "Note 1", but as it is inevitable, it needn't be fixed. After applying this patch, with frequent GPE enablings considered: ================================================================= (event pending A) ================================================================= acpi_ec_gpe_handler() acpi_ec_transaction() ***************************************************************** (event handling A) Lock(EC) advance_transaction() if STS==1 STS=0 EC_SC read ================================================================= (event pending B) ================================================================= EC_SC handled Unlock(EC) ***************************************************************** ***************************************************************** (event handling B) Lock(EC) EN=1 if STS==1 advance_transaction() if STS==1 STS=0 EC_SC read ================================================================= (event pending C) ================================================================= EC_SC handled Unlock(EC) ***************************************************************** The event pending for issue 2 can be manually handled by advance_transaction(). And after the STS=0 write performed in the manual triggered advance_transaction(), GPE can always arrive. So no GPE will be lost due to frequent GPE disabling/enabling performed in the driver like issue 4. Note 5: It's ideally when EN=1 write occurred, an IRQ thread should be woken up to handle the GPE when the GPE was raised. But this requires the IRQ thread to contain the poller code for all EC GPE indications, while currently some of the indications are handled in the user tasks. It then is very hard for the code to determine whether a user task should be invoked or the poller work item should be scheduled. So we have to invoke advance_transaction() directly now and it leaves us such a restriction for the GPE re-enabling: it must be performed in the task context to avoid starving the GPEs. As a conclusion: we can see the EC GPE is always handled in serial after deploying the raw GPE handler mode: Lock(EC) if (STS==1) STS=0 EC_SC read EC_SC handled Unlock(EC) The EC driver specific lock is responsible to make the EC GPE handling processes serialized so that EC can handle its GPE from both IRQ and task contexts and the next IRQ can be ensured to arrive after this process. Note 6: We have many EC_FLAGS_MSI qurik users in the current driver. They all seem to be suffering from unexpected GPE triggering source lost. And they are false root caused to a timing issue. Since EC communication protocol has already flow control defined, timing shouldn't be the root cause, while this fix might be fixing the root cause of the old bugs. Link: https://lkml.org/lkml/2014/11/4/974 Link: https://lkml.org/lkml/2014/11/18/316 Link: https://www.spinics.net/lists/linux-acpi/msg54340.html Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index c385606..2540870 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -121,6 +121,7 @@ struct transaction { }; static int acpi_ec_query(struct acpi_ec *ec, u8 *data); +static void advance_transaction(struct acpi_ec *ec); struct acpi_ec *boot_ec, *first_ec; EXPORT_SYMBOL(first_ec); @@ -132,7 +133,7 @@ static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */ /* -------------------------------------------------------------------------- - * Transaction Management + * EC Registers * -------------------------------------------------------------------------- */ static inline u8 acpi_ec_read_status(struct acpi_ec *ec) @@ -191,6 +192,64 @@ static const char *acpi_ec_cmd_string(u8 cmd) #define acpi_ec_cmd_string(cmd) "UNDEF" #endif +/* -------------------------------------------------------------------------- + * GPE Registers + * -------------------------------------------------------------------------- */ + +static inline bool acpi_ec_is_gpe_raised(struct acpi_ec *ec) +{ + acpi_event_status gpe_status = 0; + + (void)acpi_get_gpe_status(NULL, ec->gpe, &gpe_status); + return (gpe_status & ACPI_EVENT_FLAG_SET) ? true : false; +} + +static inline void acpi_ec_enable_gpe(struct acpi_ec *ec, bool open) +{ + if (open) + acpi_enable_gpe(NULL, ec->gpe); + else + acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE); + if (acpi_ec_is_gpe_raised(ec)) { + /* + * On some platforms, EN=1 writes cannot trigger GPE. So + * software need to manually trigger a pseudo GPE event on + * EN=1 writes. + */ + pr_debug("***** Polling quirk *****\n"); + advance_transaction(ec); + } +} + +static inline void acpi_ec_disable_gpe(struct acpi_ec *ec, bool close) +{ + if (close) + acpi_disable_gpe(NULL, ec->gpe); + else + acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE); +} + +static inline void acpi_ec_clear_gpe(struct acpi_ec *ec) +{ + /* + * GPE STS is a W1C register, which means: + * 1. Software can clear it without worrying about clearing other + * GPEs' STS bits when the hardware sets them in parallel. + * 2. As long as software can ensure only clearing it when it is + * set, hardware won't set it in parallel. + * So software can clear GPE in any contexts. + * Warning: do not move the check into advance_transaction() as the + * EC commands will be sent without GPE raised. + */ + if (!acpi_ec_is_gpe_raised(ec)) + return; + acpi_clear_gpe(NULL, ec->gpe); +} + +/* -------------------------------------------------------------------------- + * Transaction Management + * -------------------------------------------------------------------------- */ + static void acpi_ec_submit_query(struct acpi_ec *ec) { if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { @@ -227,6 +286,12 @@ static void advance_transaction(struct acpi_ec *ec) pr_debug("===== %s (%d) =====\n", in_interrupt() ? "IRQ" : "TASK", smp_processor_id()); + /* + * By always clearing STS before handling all indications, we can + * ensure a hardware STS 0->1 change after this clearing can always + * trigger a GPE interrupt. + */ + acpi_ec_clear_gpe(ec); status = acpi_ec_read_status(ec); t = ec->curr; if (!t) @@ -378,7 +443,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) /* disable GPE during transaction if storm is detected */ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { /* It has to be disabled, so that it doesn't trigger. */ - acpi_disable_gpe(NULL, ec->gpe); + acpi_ec_disable_gpe(ec, false); } status = acpi_ec_transaction_unlocked(ec, t); @@ -386,7 +451,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { msleep(1); /* It is safe to enable the GPE outside of the transaction. */ - acpi_enable_gpe(NULL, ec->gpe); + acpi_ec_enable_gpe(ec, false); } else if (t->irq_count > ec_storm_threshold) { pr_info("GPE storm detected(%d GPEs), " "transactions will use polling mode\n", @@ -693,7 +758,7 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, spin_lock_irqsave(&ec->lock, flags); advance_transaction(ec); spin_unlock_irqrestore(&ec->lock, flags); - return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE; + return ACPI_INTERRUPT_HANDLED; } /* -------------------------------------------------------------------------- @@ -812,13 +877,13 @@ static int ec_install_handlers(struct acpi_ec *ec) if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) return 0; - status = acpi_install_gpe_handler(NULL, ec->gpe, + status = acpi_install_gpe_raw_handler(NULL, ec->gpe, ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec); if (ACPI_FAILURE(status)) return -ENODEV; - acpi_enable_gpe(NULL, ec->gpe); + acpi_ec_enable_gpe(ec, true); status = acpi_install_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, @@ -833,7 +898,7 @@ static int ec_install_handlers(struct acpi_ec *ec) pr_err("Fail in evaluating the _REG object" " of EC device. Broken bios is suspected.\n"); } else { - acpi_disable_gpe(NULL, ec->gpe); + acpi_ec_disable_gpe(ec, true); acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); return -ENODEV; @@ -848,7 +913,7 @@ static void ec_remove_handlers(struct acpi_ec *ec) { if (!test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) return; - acpi_disable_gpe(NULL, ec->gpe); + acpi_ec_disable_gpe(ec, true); if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) pr_err("failed to remove space handler\n"); -- cgit v0.10.2 From 9e295ac14d6a59180beed0735e6a504c2ee87761 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 5 Feb 2015 16:27:29 +0800 Subject: ACPI / EC: Reduce ec_poll() by referencing the last register access timestamp. Timeout in the ec_poll() doesn't refer to the last register access time. It thus can win the competition against the acpi_ec_gpe_handler() if a transaction takes longer than 1ms but individual register accesses are less than 1ms. In some cases, it can make the following silicon bug easier to be triggered: GPE EN is not wired to the GPE trigger line, so when GPE STS is already set when 1 is written to GPE EN, no GPE can be triggered. This patch adds register access timestamp reference support for ec_poll() to reduce the number of ec_poll() invocations. Reported-by: Venkat Raghavulu Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 2540870..e000cf7 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -71,6 +71,7 @@ enum ec_command { #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ #define ACPI_EC_MSI_UDELAY 550 /* Wait 550us for MSI EC */ +#define ACPI_EC_UDELAY_POLL 1000 /* Wait 1ms for EC transaction polling */ #define ACPI_EC_CLEAR_MAX 100 /* Maximum number of events to query * when trying to clear the EC */ @@ -118,6 +119,7 @@ struct transaction { u8 wlen; u8 rlen; u8 flags; + unsigned long timestamp; }; static int acpi_ec_query(struct acpi_ec *ec, u8 *data); @@ -155,6 +157,7 @@ static inline u8 acpi_ec_read_data(struct acpi_ec *ec) { u8 x = inb(ec->data_addr); + ec->curr->timestamp = jiffies; pr_debug("EC_DATA(R) = 0x%2.2x\n", x); return x; } @@ -163,12 +166,14 @@ static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) { pr_debug("EC_SC(W) = 0x%2.2x\n", command); outb(command, ec->command_addr); + ec->curr->timestamp = jiffies; } static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) { pr_debug("EC_DATA(W) = 0x%2.2x\n", data); outb(data, ec->data_addr); + ec->curr->timestamp = jiffies; } #ifdef DEBUG @@ -359,6 +364,7 @@ static void start_transaction(struct acpi_ec *ec) { ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0; ec->curr->flags = 0; + ec->curr->timestamp = jiffies; advance_transaction(ec); } @@ -370,20 +376,25 @@ static int ec_poll(struct acpi_ec *ec) while (repeat--) { unsigned long delay = jiffies + msecs_to_jiffies(ec_delay); + unsigned long usecs = ACPI_EC_UDELAY_POLL; do { /* don't sleep with disabled interrupts */ if (EC_FLAGS_MSI || irqs_disabled()) { - udelay(ACPI_EC_MSI_UDELAY); + usecs = ACPI_EC_MSI_UDELAY; + udelay(usecs); if (ec_transaction_completed(ec)) return 0; } else { if (wait_event_timeout(ec->wait, ec_transaction_completed(ec), - msecs_to_jiffies(1))) + usecs_to_jiffies(usecs))) return 0; } spin_lock_irqsave(&ec->lock, flags); - advance_transaction(ec); + if (time_after(jiffies, + ec->curr->timestamp + + usecs_to_jiffies(usecs))) + advance_transaction(ec); spin_unlock_irqrestore(&ec->lock, flags); } while (time_before(jiffies, delay)); pr_debug("controller reset, restart transaction\n"); -- cgit v0.10.2 From a8d4fc227f312edea06bb4ebbeeb6db89c798e91 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 5 Feb 2015 16:27:35 +0800 Subject: ACPI / EC: Update revision due to raw handler mode. The bug fixes around GPE races have been done to the EC driver by the previous commits. This patch increases the revision to 3 to indicate the behavior differences between the old and the new drivers. The copyright/authorship notices are also updated. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index e000cf7..5563253 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1,8 +1,8 @@ /* - * ec.c - ACPI Embedded Controller Driver (v2.2) + * ec.c - ACPI Embedded Controller Driver (v3) * - * Copyright (C) 2001-2014 Intel Corporation - * Author: 2014 Lv Zheng + * Copyright (C) 2001-2015 Intel Corporation + * Author: 2014, 2015 Lv Zheng * 2006, 2007 Alexey Starikovskiy * 2006 Denis Sadykov * 2004 Luming Yu -- cgit v0.10.2 From 2fad93083e288a7d24bf7284c87f0d80a5a2c599 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Thu, 5 Feb 2015 17:33:14 +0800 Subject: ACPI / table: remove duplicate NULL check for the handler of acpi_table_parse() In acpi_table_parse(), pointer of the table to pass to handler() is checked before handler() called, so remove all the duplicate NULL check in the handler function. CC: Tony Luck CC: Thomas Gleixner Signed-off-by: Hanjun Guo Signed-off-by: Rafael J. Wysocki diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index e795cb8..2c44989 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -380,9 +380,6 @@ static void __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) static int __init acpi_parse_madt(struct acpi_table_header *table) { - if (!table) - return -EINVAL; - acpi_madt = (struct acpi_table_madt *)table; acpi_madt_rev = acpi_madt->header.revision; @@ -645,9 +642,6 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table) struct acpi_table_header *fadt_header; struct acpi_table_fadt *fadt; - if (!table) - return -EINVAL; - fadt_header = (struct acpi_table_header *)table; if (fadt_header->revision != 3) return -ENODEV; /* Only deal with ACPI 2.0 FADT */ diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index b9e30da..14d3652 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -843,13 +843,7 @@ int acpi_ioapic_registered(acpi_handle handle, u32 gsi_base) static int __init acpi_parse_sbf(struct acpi_table_header *table) { - struct acpi_table_boot *sb; - - sb = (struct acpi_table_boot *)table; - if (!sb) { - printk(KERN_WARNING PREFIX "Unable to map SBF\n"); - return -ENODEV; - } + struct acpi_table_boot *sb = (struct acpi_table_boot *)table; sbf_port = sb->cmos_index; /* Save CMOS port */ @@ -863,13 +857,7 @@ static struct resource *hpet_res __initdata; static int __init acpi_parse_hpet(struct acpi_table_header *table) { - struct acpi_table_hpet *hpet_tbl; - - hpet_tbl = (struct acpi_table_hpet *)table; - if (!hpet_tbl) { - printk(KERN_WARNING PREFIX "Unable to map HPET\n"); - return -ENODEV; - } + struct acpi_table_hpet *hpet_tbl = (struct acpi_table_hpet *)table; if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) { printk(KERN_WARNING PREFIX "HPET timers must be located in " diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 24b5476..1333cbdc 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -177,12 +177,7 @@ static int __init slit_valid(struct acpi_table_slit *slit) static int __init acpi_parse_slit(struct acpi_table_header *table) { - struct acpi_table_slit *slit; - - if (!table) - return -EINVAL; - - slit = (struct acpi_table_slit *)table; + struct acpi_table_slit *slit = (struct acpi_table_slit *)table; if (!slit_valid(slit)) { printk(KERN_INFO "ACPI: SLIT table looks invalid. Not used.\n"); @@ -260,11 +255,8 @@ acpi_parse_memory_affinity(struct acpi_subtable_header * header, static int __init acpi_parse_srat(struct acpi_table_header *table) { - struct acpi_table_srat *srat; - if (!table) - return -EINVAL; + struct acpi_table_srat *srat = (struct acpi_table_srat *)table; - srat = (struct acpi_table_srat *)table; acpi_srat_revision = srat->header.revision; /* Real work done in acpi_table_parse_srat below. */ -- cgit v0.10.2 From 92082a8886f30a1c492a31ac4b5a4966bb64b1a6 Mon Sep 17 00:00:00 2001 From: Ken Xue Date: Fri, 6 Feb 2015 08:27:51 +0800 Subject: ACPI: add AMD ACPI2Platform device support for x86 system This new feature is to interpret AMD specific ACPI device to platform device such as I2C, UART, GPIO found on AMD CZ and later chipsets. It based on example intel LPSS. Now, it can support AMD I2C, UART and GPIO. Signed-off-by: Ken Xue Acked-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 0dc9d01..3e15cee 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -496,6 +496,17 @@ config X86_INTEL_LPSS things like clock tree (common clock framework) and pincontrol which are needed by the LPSS peripheral drivers. +config X86_AMD_PLATFORM_DEVICE + bool "AMD ACPI2Platform devices support" + depends on ACPI + select COMMON_CLK + select PINCTRL + ---help--- + Select to interpret AMD specific ACPI device to platform device + such as I2C, UART, GPIO found on AMD Carrizo and later chipsets. + I2C and UART depend on COMMON_CLK to set clock. GPIO driver is + implemented under PINCTRL subsystem. + config IOSF_MBI tristate "Intel SoC IOSF Sideband support for SoC platforms" depends on PCI diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index f74317c..0071141 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -40,7 +40,7 @@ acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o acpi-y += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o acpi-y += pci_root.o pci_link.o pci_irq.o -acpi-y += acpi_lpss.o +acpi-y += acpi_lpss.o acpi_apd.o acpi-y += acpi_platform.o acpi-y += acpi_pnp.o acpi-y += int340x_thermal.o diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c new file mode 100644 index 0000000..3984ea9 --- /dev/null +++ b/drivers/acpi/acpi_apd.c @@ -0,0 +1,150 @@ +/* + * AMD ACPI support for ACPI2platform device. + * + * Copyright (c) 2014,2015 AMD Corporation. + * Authors: Ken Xue + * Wu, Jeff + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +ACPI_MODULE_NAME("acpi_apd"); +struct apd_private_data; + +/** + * ACPI_APD_SYSFS : add device attributes in sysfs + * ACPI_APD_PM : attach power domain to device + */ +#define ACPI_APD_SYSFS BIT(0) +#define ACPI_APD_PM BIT(1) + +/** + * struct apd_device_desc - a descriptor for apd device + * @flags: device flags like %ACPI_APD_SYSFS, %ACPI_APD_PM + * @fixed_clk_rate: fixed rate input clock source for acpi device; + * 0 means no fixed rate input clock source + * @setup: a hook routine to set device resource during create platform device + * + * Device description defined as acpi_device_id.driver_data + */ +struct apd_device_desc { + unsigned int flags; + unsigned int fixed_clk_rate; + int (*setup)(struct apd_private_data *pdata); +}; + +struct apd_private_data { + struct clk *clk; + struct acpi_device *adev; + const struct apd_device_desc *dev_desc; +}; + +#ifdef CONFIG_X86_AMD_PLATFORM_DEVICE +#define APD_ADDR(desc) ((unsigned long)&desc) + +static int acpi_apd_setup(struct apd_private_data *pdata) +{ + const struct apd_device_desc *dev_desc = pdata->dev_desc; + struct clk *clk = ERR_PTR(-ENODEV); + + if (dev_desc->fixed_clk_rate) { + clk = clk_register_fixed_rate(&pdata->adev->dev, + dev_name(&pdata->adev->dev), + NULL, CLK_IS_ROOT, + dev_desc->fixed_clk_rate); + clk_register_clkdev(clk, NULL, dev_name(&pdata->adev->dev)); + pdata->clk = clk; + } + + return 0; +} + +static struct apd_device_desc cz_i2c_desc = { + .setup = acpi_apd_setup, + .fixed_clk_rate = 133000000, +}; + +static struct apd_device_desc cz_uart_desc = { + .setup = acpi_apd_setup, + .fixed_clk_rate = 48000000, +}; + +#else + +#define APD_ADDR(desc) (0UL) + +#endif /* CONFIG_X86_AMD_PLATFORM_DEVICE */ + +/** +* Create platform device during acpi scan attach handle. +* Return value > 0 on success of creating device. +*/ +static int acpi_apd_create_device(struct acpi_device *adev, + const struct acpi_device_id *id) +{ + const struct apd_device_desc *dev_desc = (void *)id->driver_data; + struct apd_private_data *pdata; + struct platform_device *pdev; + int ret; + + if (!dev_desc) { + pdev = acpi_create_platform_device(adev); + return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1; + } + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdata->adev = adev; + pdata->dev_desc = dev_desc; + + if (dev_desc->setup) { + ret = dev_desc->setup(pdata); + if (ret) + goto err_out; + } + + adev->driver_data = pdata; + pdev = acpi_create_platform_device(adev); + if (!IS_ERR_OR_NULL(pdev)) + return 1; + + ret = PTR_ERR(pdev); + adev->driver_data = NULL; + + err_out: + kfree(pdata); + return ret; +} + +static const struct acpi_device_id acpi_apd_device_ids[] = { + /* Generic apd devices */ + { "AMD0010", APD_ADDR(cz_i2c_desc) }, + { "AMD0020", APD_ADDR(cz_uart_desc) }, + { "AMD0030", }, + { } +}; + +static struct acpi_scan_handler apd_handler = { + .ids = acpi_apd_device_ids, + .attach = acpi_apd_create_device, +}; + +void __init acpi_apd_init(void) +{ + acpi_scan_add_handler(&apd_handler); +} diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 163e82f..c24ae9d 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -68,6 +68,8 @@ static inline void acpi_debugfs_init(void) { return; } #endif void acpi_lpss_init(void); +void acpi_apd_init(void); + acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src); bool acpi_queue_hotplug_work(struct work_struct *work); void acpi_device_hotplug(struct acpi_device *adev, u32 src); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index dc4d896..bbca783 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2544,6 +2544,7 @@ int __init acpi_scan_init(void) acpi_pci_link_init(); acpi_processor_init(); acpi_lpss_init(); + acpi_apd_init(); acpi_cmos_rtc_init(); acpi_container_init(); acpi_memory_hotplug_init(); -- cgit v0.10.2 From ad479e7f47ca09c3f3190603ead4d01cf8fe6fa8 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 6 Feb 2015 08:57:52 +0800 Subject: ACPI / EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using the 2 flags, we can indicate an inter-mediate state where the current transactions should be completed while the new transactions should be dropped. The comparison of the old flag and the new flags: Old New about to set BLOCKED STOPPED set / STARTED set BLOCKED set STOPPED clear / STARTED clear BLOCKED clear STOPPED clear / STARTED set A new period can be indicated by the 2 flags. The new period is between the point where we are about to set BLOCKED and the point when the BLOCKED is set. The new flags facilitate us with acpi_ec_started() check to allow the EC transaction to be submitted during the new period. This period thus can be used as a grace period for the EC transaction flushing. The only functional change after applying this patch is: 1. The GPE enabling/disabling is protected by the EC specific lock. We can do this because of recent ACPICA GPE API enhancement. This is reasonable as the GPE disabling/enabling state should only be determined by the EC driver's state machine which is protected by the EC spinlock. Signed-off-by: Lv Zheng Tested-by: Ortwin Glück Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 5563253..a6179b7 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -80,7 +80,8 @@ enum { EC_FLAGS_GPE_STORM, /* GPE storm detected */ EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and * OpReg are installed */ - EC_FLAGS_BLOCKED, /* Transactions are blocked */ + EC_FLAGS_STARTED, /* Driver is started */ + EC_FLAGS_STOPPED, /* Driver is stopped */ }; #define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */ @@ -135,6 +136,16 @@ static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */ /* -------------------------------------------------------------------------- + * Device Flags + * -------------------------------------------------------------------------- */ + +static bool acpi_ec_started(struct acpi_ec *ec) +{ + return test_bit(EC_FLAGS_STARTED, &ec->flags) && + !test_bit(EC_FLAGS_STOPPED, &ec->flags); +} + +/* -------------------------------------------------------------------------- * EC Registers * -------------------------------------------------------------------------- */ @@ -415,6 +426,10 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, udelay(ACPI_EC_MSI_UDELAY); /* start transaction */ spin_lock_irqsave(&ec->lock, tmp); + if (!acpi_ec_started(ec)) { + ret = -EINVAL; + goto unlock; + } /* following two actions should be kept atomic */ ec->curr = t; pr_debug("***** Command(%s) started *****\n", @@ -426,6 +441,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, pr_debug("***** Command(%s) stopped *****\n", acpi_ec_cmd_string(t->command)); ec->curr = NULL; +unlock: spin_unlock_irqrestore(&ec->lock, tmp); return ret; } @@ -440,10 +456,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) if (t->rdata) memset(t->rdata, 0, t->rlen); mutex_lock(&ec->mutex); - if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) { - status = -EINVAL; - goto unlock; - } if (ec->global_lock) { status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); if (ACPI_FAILURE(status)) { @@ -595,6 +607,37 @@ static void acpi_ec_clear(struct acpi_ec *ec) pr_info("%d stale EC events cleared\n", i); } +static void acpi_ec_start(struct acpi_ec *ec, bool resuming) +{ + unsigned long flags; + + spin_lock_irqsave(&ec->lock, flags); + if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) { + pr_debug("+++++ Starting EC +++++\n"); + if (!resuming) + acpi_ec_enable_gpe(ec, true); + pr_info("+++++ EC started +++++\n"); + } + spin_unlock_irqrestore(&ec->lock, flags); +} + +static void acpi_ec_stop(struct acpi_ec *ec, bool suspending) +{ + unsigned long flags; + + spin_lock_irqsave(&ec->lock, flags); + if (acpi_ec_started(ec)) { + pr_debug("+++++ Stopping EC +++++\n"); + set_bit(EC_FLAGS_STOPPED, &ec->flags); + if (!suspending) + acpi_ec_disable_gpe(ec, true); + clear_bit(EC_FLAGS_STARTED, &ec->flags); + clear_bit(EC_FLAGS_STOPPED, &ec->flags); + pr_info("+++++ EC stopped +++++\n"); + } + spin_unlock_irqrestore(&ec->lock, flags); +} + void acpi_ec_block_transactions(void) { struct acpi_ec *ec = first_ec; @@ -604,7 +647,7 @@ void acpi_ec_block_transactions(void) mutex_lock(&ec->mutex); /* Prevent transactions from being carried out */ - set_bit(EC_FLAGS_BLOCKED, &ec->flags); + acpi_ec_stop(ec, true); mutex_unlock(&ec->mutex); } @@ -616,7 +659,7 @@ void acpi_ec_unblock_transactions(void) return; /* Allow transactions to be carried out again */ - clear_bit(EC_FLAGS_BLOCKED, &ec->flags); + acpi_ec_start(ec, true); if (EC_FLAGS_CLEAR_ON_RESUME) acpi_ec_clear(ec); @@ -629,7 +672,7 @@ void acpi_ec_unblock_transactions_early(void) * atomic context during wakeup, so we don't need to acquire the mutex). */ if (first_ec) - clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags); + acpi_ec_start(first_ec, true); } /* -------------------------------------------------------------------------- @@ -894,7 +937,7 @@ static int ec_install_handlers(struct acpi_ec *ec) if (ACPI_FAILURE(status)) return -ENODEV; - acpi_ec_enable_gpe(ec, true); + acpi_ec_start(ec, false); status = acpi_install_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, @@ -909,7 +952,7 @@ static int ec_install_handlers(struct acpi_ec *ec) pr_err("Fail in evaluating the _REG object" " of EC device. Broken bios is suspected.\n"); } else { - acpi_ec_disable_gpe(ec, true); + acpi_ec_stop(ec, false); acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); return -ENODEV; @@ -924,7 +967,7 @@ static void ec_remove_handlers(struct acpi_ec *ec) { if (!test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) return; - acpi_ec_disable_gpe(ec, true); + acpi_ec_stop(ec, false); if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) pr_err("failed to remove space handler\n"); -- cgit v0.10.2 From 9887d22add48f24ca3a7605c89b0a21ed337f185 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 6 Feb 2015 08:57:59 +0800 Subject: ACPI / EC: Add command flushing support. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch implements the EC command flushing support. During the grace period indicated by EC_FLAGS_STARTED and EC_FLAGS_STOPPED, all submitted EC command transactions can be completed and new submissions are prevented before suspending so that the EC hardware can be ensured to be in the idle state when the system is resumed. There is a good indicator for flush support: All acpi_ec_submit_request() is invoked after checking driver state with acpi_ec_started() except the first one. This means all code paths can be flushed as fast as possible by discarding the requests occurred after the flush operation. The reference increased for such kind of code path is wrapped by acpi_ec_submit_flushable_request(). Signed-off-by: Lv Zheng Tested-by: Ortwin Glück Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index a6179b7..1fa1463 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -145,6 +145,11 @@ static bool acpi_ec_started(struct acpi_ec *ec) !test_bit(EC_FLAGS_STOPPED, &ec->flags); } +static bool acpi_ec_flushed(struct acpi_ec *ec) +{ + return ec->reference_count == 1; +} + /* -------------------------------------------------------------------------- * EC Registers * -------------------------------------------------------------------------- */ @@ -266,6 +271,44 @@ static inline void acpi_ec_clear_gpe(struct acpi_ec *ec) * Transaction Management * -------------------------------------------------------------------------- */ +static void acpi_ec_submit_request(struct acpi_ec *ec) +{ + ec->reference_count++; + if (ec->reference_count == 1) + acpi_ec_enable_gpe(ec, true); +} + +static void acpi_ec_complete_request(struct acpi_ec *ec) +{ + bool flushed = false; + + ec->reference_count--; + if (ec->reference_count == 0) + acpi_ec_disable_gpe(ec, true); + flushed = acpi_ec_flushed(ec); + if (flushed) + wake_up(&ec->wait); +} + +/* + * acpi_ec_submit_flushable_request() - Increase the reference count unless + * the flush operation is not in + * progress + * @ec: the EC device + * + * 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. + */ +static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec) +{ + if (!acpi_ec_started(ec)) + return false; + acpi_ec_submit_request(ec); + return true; +} + static void acpi_ec_submit_query(struct acpi_ec *ec) { if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { @@ -426,7 +469,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, udelay(ACPI_EC_MSI_UDELAY); /* start transaction */ spin_lock_irqsave(&ec->lock, tmp); - if (!acpi_ec_started(ec)) { + /* Enable GPE for command processing (IBF=0/OBF=1) */ + if (!acpi_ec_submit_flushable_request(ec)) { ret = -EINVAL; goto unlock; } @@ -441,6 +485,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, pr_debug("***** Command(%s) stopped *****\n", acpi_ec_cmd_string(t->command)); ec->curr = NULL; + /* Disable GPE for command processing (IBF=0/OBF=1) */ + acpi_ec_complete_request(ec); unlock: spin_unlock_irqrestore(&ec->lock, tmp); return ret; @@ -614,13 +660,25 @@ static void acpi_ec_start(struct acpi_ec *ec, bool resuming) spin_lock_irqsave(&ec->lock, flags); 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) - acpi_ec_enable_gpe(ec, true); + acpi_ec_submit_request(ec); pr_info("+++++ EC started +++++\n"); } spin_unlock_irqrestore(&ec->lock, flags); } +static bool acpi_ec_stopped(struct acpi_ec *ec) +{ + unsigned long flags; + bool flushed; + + spin_lock_irqsave(&ec->lock, flags); + flushed = acpi_ec_flushed(ec); + spin_unlock_irqrestore(&ec->lock, flags); + return flushed; +} + static void acpi_ec_stop(struct acpi_ec *ec, bool suspending) { unsigned long flags; @@ -629,8 +687,12 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool suspending) if (acpi_ec_started(ec)) { pr_debug("+++++ Stopping EC +++++\n"); set_bit(EC_FLAGS_STOPPED, &ec->flags); + spin_unlock_irqrestore(&ec->lock, flags); + wait_event(ec->wait, acpi_ec_stopped(ec)); + spin_lock_irqsave(&ec->lock, flags); + /* Disable GPE for event processing (SCI_EVT=1) */ if (!suspending) - acpi_ec_disable_gpe(ec, true); + acpi_ec_complete_request(ec); clear_bit(EC_FLAGS_STARTED, &ec->flags); clear_bit(EC_FLAGS_STOPPED, &ec->flags); pr_info("+++++ EC stopped +++++\n"); diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index dc42078..7dc69d8 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -122,6 +122,7 @@ struct acpi_ec { unsigned long data_addr; unsigned long global_lock; unsigned long flags; + unsigned long reference_count; struct mutex mutex; wait_queue_head_t wait; struct list_head list; -- cgit v0.10.2 From e1d4d90fc0313d3d58cbd7912c90f8ef24df45ff Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 6 Feb 2015 08:58:05 +0800 Subject: ACPI / EC: Refine command storm prevention support This patch refines EC command storm prevention support. Current command storming code is wrong, when the storming condition is detected, it only flags the condition without doing anything for the current command but performing storming prevention for the follow-up commands. So: 1. The first command which suffers from the storming still suffers from storming. 2. The follow-up commands which may not suffer from the storming are unconditionally forced into the storming prevention mode. Ideally, we should only enable storm prevention immediately after detection for the current command so that the next command can try the power/performance efficient interrupt mode again. This patch improves the command storm prevention by disabling GPE right after the detection and re-enabling it right before completing the command transaction using the GPE storming prevention APIs. This thus deploys the following GPE handling model: 1. acpi_enable_gpe()/acpi_disable_gpe() for reference count changes: This set of APIs are used for EC usage reference counting. 2. acpi_set_gpe(ACPI_GPE_ENABLE)/acpi_set_gpe(ACPI_GPE_DISABLE): This set of APIs are used for preventing GPE storm. They must be invoked when the reference count > 0. Note that as the storming prevention should always happen when there is an outstanding request, or GPE enabling value will be messed up by the races. This patch also adds BUG_ON() to enforces this rule to prevent future bugs. The msleep(1) used after completing a transaction is useless now as this sounds like a guard time only useful for platforms that need the EC_FLAGS_MSI quirks while we have fixed GPE race issues using the previous raw handler mode enabling. It is kept to avoid regressions. A seperate patch which deletes EC_FLAGS_MSI quirks should take care of deleting it. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 1fa1463..982b67f 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -77,11 +77,12 @@ enum ec_command { enum { EC_FLAGS_QUERY_PENDING, /* Query is pending */ - EC_FLAGS_GPE_STORM, /* GPE storm detected */ EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and * OpReg are installed */ EC_FLAGS_STARTED, /* Driver is started */ EC_FLAGS_STOPPED, /* Driver is stopped */ + EC_FLAGS_COMMAND_STORM, /* GPE storms occurred to the + * current command processing */ }; #define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */ @@ -229,8 +230,10 @@ static inline void acpi_ec_enable_gpe(struct acpi_ec *ec, bool open) { if (open) acpi_enable_gpe(NULL, ec->gpe); - else + else { + BUG_ON(ec->reference_count < 1); acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE); + } if (acpi_ec_is_gpe_raised(ec)) { /* * On some platforms, EN=1 writes cannot trigger GPE. So @@ -246,8 +249,10 @@ static inline void acpi_ec_disable_gpe(struct acpi_ec *ec, bool close) { if (close) acpi_disable_gpe(NULL, ec->gpe); - else + else { + BUG_ON(ec->reference_count < 1); acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE); + } } static inline void acpi_ec_clear_gpe(struct acpi_ec *ec) @@ -290,6 +295,24 @@ static void acpi_ec_complete_request(struct acpi_ec *ec) wake_up(&ec->wait); } +static void acpi_ec_set_storm(struct acpi_ec *ec, u8 flag) +{ + if (!test_bit(flag, &ec->flags)) { + acpi_ec_disable_gpe(ec, false); + pr_debug("+++++ Polling enabled +++++\n"); + set_bit(flag, &ec->flags); + } +} + +static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag) +{ + if (test_bit(flag, &ec->flags)) { + clear_bit(flag, &ec->flags); + acpi_ec_enable_gpe(ec, false); + pr_debug("+++++ Polling disabled +++++\n"); + } +} + /* * acpi_ec_submit_flushable_request() - Increase the reference count unless * the flush operation is not in @@ -404,8 +427,13 @@ err: * otherwise will take a not handled IRQ as a false one. */ if (!(status & ACPI_EC_FLAG_SCI)) { - if (in_interrupt() && t) - ++t->irq_count; + if (in_interrupt() && t) { + if (t->irq_count < ec_storm_threshold) + ++t->irq_count; + /* Allow triggering on 0 threshold */ + if (t->irq_count == ec_storm_threshold) + acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM); + } } out: if (status & ACPI_EC_FLAG_SCI) @@ -482,6 +510,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, spin_unlock_irqrestore(&ec->lock, tmp); ret = ec_poll(ec); spin_lock_irqsave(&ec->lock, tmp); + if (t->irq_count == ec_storm_threshold) + acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM); pr_debug("***** Command(%s) stopped *****\n", acpi_ec_cmd_string(t->command)); ec->curr = NULL; @@ -509,24 +539,11 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) goto unlock; } } - /* disable GPE during transaction if storm is detected */ - if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { - /* It has to be disabled, so that it doesn't trigger. */ - acpi_ec_disable_gpe(ec, false); - } status = acpi_ec_transaction_unlocked(ec, t); - if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { + if (test_bit(EC_FLAGS_COMMAND_STORM, &ec->flags)) msleep(1); - /* It is safe to enable the GPE outside of the transaction. */ - acpi_ec_enable_gpe(ec, false); - } else if (t->irq_count > ec_storm_threshold) { - pr_info("GPE storm detected(%d GPEs), " - "transactions will use polling mode\n", - t->irq_count); - set_bit(EC_FLAGS_GPE_STORM, &ec->flags); - } if (ec->global_lock) acpi_release_global_lock(glk); unlock: -- cgit v0.10.2 From f252cb09e1cb46834014aaa3814fbfb2352e9071 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 6 Feb 2015 08:58:10 +0800 Subject: ACPI / EC: Add query flushing support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch implementes the QR_EC flushing support. Grace periods are implemented from the detection of an SCI_EVT to the submission/completion of the QR_EC transaction. During this period, all EC command transactions are allowed to be submitted. Note that query periods and event periods are intentionally distiguished to allow further improvements. 1. Query period: from the detection of an SCI_EVT to the sumission of the QR_EC command. This period is used for storming prevention, as currently QR_EC is deferred to a work queue rather than directly issued from the IRQ context even there is no other transactions pending, so malicous SCI_EVT GPE can act like "level triggered" to trigger a GPE storm. We need to be prepared for this. And in the future, we may change it to be a part of the advance_transaction() where we will try QR_EC submission in appropriate positions to avoid such GPE storming. 2. Event period: from the detection of an SCI_EVT to the completion of the QR_EC command. We may extend it to the completion of _Qxx evaluation. This is actually a grace period for event flushing, but we only flush queries due to the reason stated in known issue 1. That's also why we use EC_FLAGS_EVENT_xxx. During this period, QR_EC transactions need to pass the flushable submission check. In this patch, the following flags are implemented: 1. EC_FLAGS_EVENT_ENABLED: this is derived from the old EC_FLAGS_QUERY_PENDING flag which can block SCI_EVT handlings. With this flag, the logics implemented by the original flag are extended: 1. Old logic: unless both of the flags are set, the event poller will not be scheduled, and 2. New logic: as soon as both of the flags are set, the evet poller will be scheduled. 2. EC_FLAGS_EVENT_DETECTED: this is also derived from the old EC_FLAGS_QUERY_PENDING flag which can block SCI_EVT detection. It thus can be used to indicate the storming prevention period for query submission. acpi_ec_submit_request()/acpi_ec_complete_request() are invoked to implement this period so that acpi_set_gpe() can be invoked under the "reference count > 0" condition. 3. EC_FLAGS_EVENT_PENDING: this is newly added to indicate the grace period for event flushing (query flushing for now). acpi_ec_submit_request()/acpi_ec_complete_request() are invoked to implement this period so that the flushing process can wait until the event handling (query transaction for now) to be completed. Link: https://bugzilla.kernel.org/show_bug.cgi?id=82611 Link: https://bugzilla.kernel.org/show_bug.cgi?id=77431 Signed-off-by: Lv Zheng Tested-by: Ortwin Glück Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 982b67f..40002ae 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -76,7 +76,9 @@ enum ec_command { * when trying to clear the EC */ enum { - EC_FLAGS_QUERY_PENDING, /* Query is pending */ + EC_FLAGS_EVENT_ENABLED, /* Event is enabled */ + EC_FLAGS_EVENT_PENDING, /* Event is pending */ + EC_FLAGS_EVENT_DETECTED, /* Event is detected */ EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and * OpReg are installed */ EC_FLAGS_STARTED, /* Driver is started */ @@ -151,6 +153,12 @@ 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 * -------------------------------------------------------------------------- */ @@ -318,36 +326,93 @@ 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) +static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec, + bool allow_event) { - if (!acpi_ec_started(ec)) - return false; + if (!acpi_ec_started(ec)) { + if (!allow_event || !acpi_ec_has_pending_event(ec)) + return false; + } acpi_ec_submit_request(ec); return true; } -static void acpi_ec_submit_query(struct acpi_ec *ec) +static void acpi_ec_submit_event(struct acpi_ec *ec) { - if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { - pr_debug("***** Event started *****\n"); + 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; + if (!test_and_set_bit(EC_FLAGS_EVENT_PENDING, &ec->flags)) { + pr_debug("***** Event query started *****\n"); schedule_work(&ec->work); + return; + } + acpi_ec_complete_request(ec); +} + +static void acpi_ec_complete_event(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); + /* 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; + if (!test_and_set_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags)) { + pr_debug("***** Event detection blocked *****\n"); + acpi_ec_submit_event(ec); + return; } + acpi_ec_complete_request(ec); } -static void acpi_ec_complete_query(struct acpi_ec *ec) +static void acpi_ec_complete_detection(struct acpi_ec *ec) { if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { - clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); - pr_debug("***** Event stopped *****\n"); + clear_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags); + pr_debug("***** Event detetion unblocked *****\n"); + /* Unhold reference for query submission */ + acpi_ec_complete_request(ec); } } +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) { unsigned long flags; @@ -389,6 +454,7 @@ 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)); @@ -399,6 +465,7 @@ 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; @@ -407,16 +474,17 @@ 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_query(ec); + acpi_ec_complete_detection(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_query(ec); + acpi_ec_complete_detection(ec); } else goto err; goto out; @@ -437,7 +505,7 @@ err: } out: if (status & ACPI_EC_FLAG_SCI) - acpi_ec_submit_query(ec); + acpi_ec_submit_detection(ec); if (wakeup && in_interrupt()) wake_up(&ec->wait); } @@ -498,7 +566,7 @@ 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)) { + if (!acpi_ec_submit_flushable_request(ec, true)) { ret = -EINVAL; goto unlock; } @@ -879,7 +947,9 @@ 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, @@ -949,7 +1019,6 @@ 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); @@ -1100,7 +1169,7 @@ static int acpi_ec_add(struct acpi_device *device) ret = ec_install_handlers(ec); /* EC is fully operational, allow queries */ - clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); + acpi_ec_enable_event(ec); /* Clear stale _Q events if hardware might require that */ if (EC_FLAGS_CLEAR_ON_RESUME) -- cgit v0.10.2 From b5bca896ef3c4dd8aa1aac55256cb094c7376a77 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 6 Feb 2015 08:58:16 +0800 Subject: ACPI / EC: Add GPE reference counting debugging messages This patch enhances debugging with the GPE reference count messages added. No functional changes. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 40002ae..14d0c89 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -31,6 +31,7 @@ /* Uncomment next line to get verbose printout */ /* #define DEBUG */ +#define DEBUG_REF 0 #define pr_fmt(fmt) "ACPI : EC: " fmt #include @@ -90,6 +91,13 @@ 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); @@ -356,12 +364,14 @@ static void acpi_ec_submit_event(struct acpi_ec *ec) /* 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"); 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) @@ -371,6 +381,7 @@ static void acpi_ec_complete_event(struct acpi_ec *ec) 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); } @@ -381,12 +392,14 @@ 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; } acpi_ec_complete_request(ec); + ec_debug_ref(ec, "Decrease query\n"); } static void acpi_ec_complete_detection(struct acpi_ec *ec) @@ -396,6 +409,7 @@ static void acpi_ec_complete_detection(struct acpi_ec *ec) pr_debug("***** Event detetion unblocked *****\n"); /* Unhold reference for query submission */ acpi_ec_complete_request(ec); + ec_debug_ref(ec, "Decrease query\n"); } } @@ -570,6 +584,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *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", @@ -585,6 +600,7 @@ 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; @@ -746,8 +762,10 @@ 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"); } spin_unlock_irqrestore(&ec->lock, flags); @@ -776,8 +794,10 @@ 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"); -- cgit v0.10.2 From d64c3b0bb9195d4de856d841337368d930cdb0ed Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Fri, 6 Feb 2015 13:41:55 -0800 Subject: intel_pstate: provide option to only use intel_pstate with HWP Allow users the option to disable the driver for any hardware which does not support HWP. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 4df73da..07e6701 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1469,6 +1469,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. no_hwp Do not enable hardware P state control (HWP) if available. + hwp_only + Only load intel_pstate on systems which support + hardware P state control (HWP) if available. intremap= [X86-64, Intel-IOMMU] on enable Interrupt Remapping (default) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index e7e808d..872c577 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -1019,6 +1019,7 @@ static struct cpufreq_driver intel_pstate_driver = { static int __initdata no_load; static int __initdata no_hwp; +static int __initdata hwp_only; static unsigned int force_load; static int intel_pstate_msrs_not_valid(void) @@ -1216,6 +1217,9 @@ static int __init intel_pstate_init(void) if (cpu_has(c,X86_FEATURE_HWP) && !no_hwp) intel_pstate_hwp_enable(); + if (!hwp_active && hwp_only) + goto out; + rc = cpufreq_register_driver(&intel_pstate_driver); if (rc) goto out; @@ -1250,6 +1254,8 @@ static int __init intel_pstate_setup(char *str) no_hwp = 1; if (!strcmp(str, "force")) force_load = 1; + if (!strcmp(str, "hwp_only")) + hwp_only = 1; return 0; } early_param("intel_pstate", intel_pstate_setup); -- cgit v0.10.2 From f6a55884d76c5f493538866793fddd47b4ecf646 Mon Sep 17 00:00:00 2001 From: Andreas Ruprecht Date: Sun, 8 Feb 2015 20:36:38 +0100 Subject: USB / PM: Remove unneeded #ifdef and associated dead code In commit ceb6c9c862c8 ("USB / PM: Drop CONFIG_PM_RUNTIME from the USB core"), all occurrences of CONFIG_PM_RUNTIME in the USB core code were replaced by CONFIG_PM. This created the following structure of #ifdef blocks in drivers/usb/core/hub.c: [...] #ifdef CONFIG_PM #ifdef CONFIG_PM /* always on / undead */ #else /* dead */ #endif [...] This patch removes unnecessary inner "#ifdef CONFIG_PM" as well as the corresponding dead #else block. This inconsistency was found using the undertaker-checkpatch tool. Signed-off-by: Andreas Ruprecht Signed-off-by: Rafael J. Wysocki diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index aeb50bb..eaffb02 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3452,8 +3452,6 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) return status; } -#ifdef CONFIG_PM - int usb_remote_wakeup(struct usb_device *udev) { int status = 0; @@ -3512,16 +3510,6 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, return connect_change; } -#else - -static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, - u16 portstatus, u16 portchange) -{ - return 0; -} - -#endif - static int check_ports_changed(struct usb_hub *hub) { int port1; -- cgit v0.10.2 From 8dcb52cbcadf7cbee62a7723f8a588a31281eccd Mon Sep 17 00:00:00 2001 From: Andreas Ruprecht Date: Sun, 8 Feb 2015 14:12:59 +0100 Subject: ACPI / PM: Remove unneeded nested #ifdef In commit 5de21bb998b8 ("ACPI / PM: Drop CONFIG_PM_RUNTIME from the ACPI core"), all occurrences of CONFIG_PM_RUNTIME were replaced with CONFIG_PM. This created the following structure of #ifdef blocks in the code: [...] #ifdef CONFIG_PM #ifdef CONFIG_PM /* always on / undead */ #ifdef CONFIG_PM_SLEEP [...] #endif #endif [...] #endif This patch removes the inner "#ifdef CONFIG_PM" block as it will always be enabled when the outer block is enabled. This inconsistency was found using the undertaker-checkpatch tool. Signed-off-by: Andreas Ruprecht Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index c0d44d3..735db11 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -1027,7 +1027,6 @@ EXPORT_SYMBOL_GPL(acpi_subsys_freeze); static struct dev_pm_domain acpi_general_pm_domain = { .ops = { -#ifdef CONFIG_PM .runtime_suspend = acpi_subsys_runtime_suspend, .runtime_resume = acpi_subsys_runtime_resume, #ifdef CONFIG_PM_SLEEP @@ -1041,7 +1040,6 @@ static struct dev_pm_domain acpi_general_pm_domain = { .poweroff_late = acpi_subsys_suspend_late, .restore_early = acpi_subsys_resume_early, #endif -#endif }, }; -- cgit v0.10.2 From e77a16355a29230b99bafe55834a8252e55308ec Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 7 Feb 2015 09:53:53 +0100 Subject: ACPI / video: Add disable_native_backlight quirk for Samsung 510R Backlight control through the native intel interface does not work properly on the Samsung 510R, where as using the acpi_video interface does work, add a quirk for this. Link: https://bugzilla.redhat.com/show_bug.cgi?id=1186097 Cc: All applicable Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 497d986..88a4f99 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -523,6 +523,15 @@ static struct dmi_system_id video_dmi_table[] __initdata = { }, }, { + /* https://bugzilla.redhat.com/show_bug.cgi?id=1186097 */ + .callback = video_disable_native_backlight, + .ident = "SAMSUNG 3570R/370R/470R/450R/510R/4450RV", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "3570R/370R/470R/450R/510R/4450RV"), + }, + }, + { /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */ .callback = video_disable_native_backlight, .ident = "SAMSUNG 730U3E/740U3E", -- cgit v0.10.2 From 98481e79b60a50d699b79292ff1b7e56e7fa8425 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 15 Aug 2014 00:36:50 -0400 Subject: tools/power turbostat: relax dependency on root permission For turbostat to run as non-root, it needs to permissions: 1. read access to /dev/cpu/*/msr via standard user/group/world file permissions 2. CAP_SYS_RAWIO eg. # setcap cap_sys_rawio=ep turbostat Yes, running as root still works. Signed-off-by: Len Brown diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 5b1b807..6f29fc1 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -38,6 +38,8 @@ #include #include #include +#include +#include char *proc_stat = "/proc/stat"; unsigned int interval_sec = 5; /* set with -i interval_sec */ @@ -251,15 +253,13 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr) sprintf(pathname, "/dev/cpu/%d/msr", cpu); fd = open(pathname, O_RDONLY); if (fd < 0) - return -1; + err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, or run as root", pathname); retval = pread(fd, msr, sizeof *msr, offset); close(fd); - if (retval != sizeof *msr) { - fprintf(stderr, "%s offset 0x%llx read failed\n", pathname, (unsigned long long)offset); - return -1; - } + if (retval != sizeof *msr) + err(-1, "%s offset 0x%llx read failed", pathname, (unsigned long long)offset); return 0; } @@ -1462,10 +1462,40 @@ void check_dev_msr() "Try \"# modprobe msr\""); } -void check_super_user() +void check_permissions() { - if (getuid() != 0) - errx(-6, "must be root"); + struct __user_cap_header_struct cap_header_data; + cap_user_header_t cap_header = &cap_header_data; + struct __user_cap_data_struct cap_data_data; + cap_user_data_t cap_data = &cap_data_data; + extern int capget(cap_user_header_t hdrp, cap_user_data_t datap); + int do_exit = 0; + + /* check for CAP_SYS_RAWIO */ + cap_header->pid = getpid(); + cap_header->version = _LINUX_CAPABILITY_VERSION; + if (capget(cap_header, cap_data) < 0) + err(-6, "capget(2) failed"); + + if ((cap_data->effective & (1 << CAP_SYS_RAWIO)) == 0) { + do_exit++; + warnx("capget(CAP_SYS_RAWIO) failed," + " try \"# setcap cap_sys_rawio=ep %s\"", progname); + } + + /* test file permissions */ + if (euidaccess("/dev/cpu/0/msr", R_OK)) { + do_exit++; + warn("/dev/cpu/0/msr open failed, try chown or chmod +r /dev/cpu/*/msr"); + } + + /* if all else fails, thell them to be root */ + if (do_exit) + if (getuid() != 0) + warnx("Or simply run as root"); + + if (do_exit) + exit(-6); } int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) @@ -2299,10 +2329,9 @@ void setup_all_buffers(void) void turbostat_init() { - check_cpuid(); - check_dev_msr(); - check_super_user(); + check_permissions(); + check_cpuid(); setup_all_buffers(); @@ -2441,7 +2470,7 @@ int main(int argc, char **argv) cmdline(argc, argv); if (verbose) - fprintf(stderr, "turbostat v3.7 Feb 6, 2014" + fprintf(stderr, "turbostat v3.8 14-Aug 2014" " - Len Brown \n"); turbostat_init(); -- cgit v0.10.2 From 3a9a941d0b9361eac81fb763a89fb465f70b1c28 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 15 Aug 2014 02:39:52 -0400 Subject: tools/power turbostat: decode MSR_*_PERF_LIMIT_REASONS The Processor generation code-named Haswell added MSR_{CORE | GFX | RING}_PERF_LIMIT_REASONS to explain when and how the processor limits frequency. turbostat -v will now decode these bits. Each MSR has an "Active" set of bits which describe current conditions, and a "Logged" set of bits, which describe what has happened since last cleared. Turbostat currently doesn't clear the log bits. Signed-off-by: Len Brown diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h index c8aa65d..f721330 100644 --- a/arch/x86/include/uapi/asm/msr-index.h +++ b/arch/x86/include/uapi/asm/msr-index.h @@ -152,6 +152,10 @@ #define MSR_CC6_DEMOTION_POLICY_CONFIG 0x00000668 #define MSR_MC6_DEMOTION_POLICY_CONFIG 0x00000669 +#define MSR_CORE_PERF_LIMIT_REASONS 0x00000690 +#define MSR_GFX_PERF_LIMIT_REASONS 0x000006B0 +#define MSR_RING_PERF_LIMIT_REASONS 0x000006B1 + /* Hardware P state interface */ #define MSR_PPERF 0x0000064e #define MSR_PERF_LIMIT_REASONS 0x0000064f diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 6f29fc1..5891309 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -83,6 +83,9 @@ unsigned int tcc_activation_temp; unsigned int tcc_activation_temp_override; double rapl_power_units, rapl_energy_units, rapl_time_units; double rapl_joule_counter_range; +unsigned int do_core_perf_limit_reasons; +unsigned int do_gfx_perf_limit_reasons; +unsigned int do_ring_perf_limit_reasons; #define RAPL_PKG (1 << 0) /* 0x610 MSR_PKG_POWER_LIMIT */ @@ -1178,6 +1181,7 @@ print_nhm_turbo_ratio_limits: if (ratio) fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n", ratio, bclk, ratio * bclk); + } void free_all_buffers(void) @@ -1594,6 +1598,103 @@ int print_epb(struct thread_data *t, struct core_data *c, struct pkg_data *p) return 0; } +/* + * print_perf_limit() + */ +int print_perf_limit(struct thread_data *t, struct core_data *c, struct pkg_data *p) +{ + unsigned long long msr; + int cpu; + + cpu = t->cpu_id; + + /* per-package */ + if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) + return 0; + + if (cpu_migrate(cpu)) { + fprintf(stderr, "Could not migrate to CPU %d\n", cpu); + return -1; + } + + if (do_core_perf_limit_reasons) { + get_msr(cpu, MSR_CORE_PERF_LIMIT_REASONS, &msr); + fprintf(stderr, "cpu%d: MSR_CORE_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr); + fprintf(stderr, " (Active: %s%s%s%s%s%s%s%s%s%s%s%s%s%s)", + (msr & 1 << 0) ? "PROCHOT, " : "", + (msr & 1 << 1) ? "ThermStatus, " : "", + (msr & 1 << 2) ? "bit2, " : "", + (msr & 1 << 4) ? "Graphics, " : "", + (msr & 1 << 5) ? "Auto-HWP, " : "", + (msr & 1 << 6) ? "VR-Therm, " : "", + (msr & 1 << 8) ? "Amps, " : "", + (msr & 1 << 9) ? "CorePwr, " : "", + (msr & 1 << 10) ? "PkgPwrL1, " : "", + (msr & 1 << 11) ? "PkgPwrL2, " : "", + (msr & 1 << 12) ? "MultiCoreTurbo, " : "", + (msr & 1 << 13) ? "Transitions, " : "", + (msr & 1 << 14) ? "bit14, " : "", + (msr & 1 << 15) ? "bit15, " : ""); + fprintf(stderr, " (Logged: %s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n", + (msr & 1 << 16) ? "PROCHOT, " : "", + (msr & 1 << 17) ? "ThermStatus, " : "", + (msr & 1 << 18) ? "bit18, " : "", + (msr & 1 << 20) ? "Graphics, " : "", + (msr & 1 << 21) ? "Auto-HWP, " : "", + (msr & 1 << 22) ? "VR-Therm, " : "", + (msr & 1 << 24) ? "Amps, " : "", + (msr & 1 << 25) ? "CorePwr, " : "", + (msr & 1 << 26) ? "PkgPwrL1, " : "", + (msr & 1 << 27) ? "PkgPwrL2, " : "", + (msr & 1 << 28) ? "MultiCoreTurbo, " : "", + (msr & 1 << 29) ? "Transitions, " : "", + (msr & 1 << 30) ? "bit30, " : "", + (msr & 1 << 31) ? "bit31, " : ""); + + } + if (do_gfx_perf_limit_reasons) { + get_msr(cpu, MSR_GFX_PERF_LIMIT_REASONS, &msr); + fprintf(stderr, "cpu%d: MSR_GFX_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr); + fprintf(stderr, " (Active: %s%s%s%s%s%s%s%s)", + (msr & 1 << 0) ? "PROCHOT, " : "", + (msr & 1 << 1) ? "ThermStatus, " : "", + (msr & 1 << 4) ? "Graphics, " : "", + (msr & 1 << 6) ? "VR-Therm, " : "", + (msr & 1 << 8) ? "Amps, " : "", + (msr & 1 << 9) ? "GFXPwr, " : "", + (msr & 1 << 10) ? "PkgPwrL1, " : "", + (msr & 1 << 11) ? "PkgPwrL2, " : ""); + fprintf(stderr, " (Logged: %s%s%s%s%s%s%s%s)\n", + (msr & 1 << 16) ? "PROCHOT, " : "", + (msr & 1 << 17) ? "ThermStatus, " : "", + (msr & 1 << 20) ? "Graphics, " : "", + (msr & 1 << 22) ? "VR-Therm, " : "", + (msr & 1 << 24) ? "Amps, " : "", + (msr & 1 << 25) ? "GFXPwr, " : "", + (msr & 1 << 26) ? "PkgPwrL1, " : "", + (msr & 1 << 27) ? "PkgPwrL2, " : ""); + } + if (do_ring_perf_limit_reasons) { + get_msr(cpu, MSR_RING_PERF_LIMIT_REASONS, &msr); + fprintf(stderr, "cpu%d: MSR_RING_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr); + fprintf(stderr, " (Active: %s%s%s%s%s%s)", + (msr & 1 << 0) ? "PROCHOT, " : "", + (msr & 1 << 1) ? "ThermStatus, " : "", + (msr & 1 << 6) ? "VR-Therm, " : "", + (msr & 1 << 8) ? "Amps, " : "", + (msr & 1 << 10) ? "PkgPwrL1, " : "", + (msr & 1 << 11) ? "PkgPwrL2, " : ""); + fprintf(stderr, " (Logged: %s%s%s%s%s%s)\n", + (msr & 1 << 16) ? "PROCHOT, " : "", + (msr & 1 << 17) ? "ThermStatus, " : "", + (msr & 1 << 22) ? "VR-Therm, " : "", + (msr & 1 << 24) ? "Amps, " : "", + (msr & 1 << 26) ? "PkgPwrL1, " : "", + (msr & 1 << 27) ? "PkgPwrL2, " : ""); + } + return 0; +} + #define RAPL_POWER_GRANULARITY 0x7FFF /* 15 bit power granularity */ #define RAPL_TIME_GRANULARITY 0x3F /* 6 bit time granularity */ @@ -1683,6 +1784,27 @@ void rapl_probe(unsigned int family, unsigned int model) return; } +void perf_limit_reasons_probe(family, model) +{ + if (!genuine_intel) + return; + + if (family != 6) + return; + + switch (model) { + case 0x3C: /* HSW */ + case 0x45: /* HSW */ + case 0x46: /* HSW */ + do_gfx_perf_limit_reasons = 1; + case 0x3F: /* HSX */ + do_core_perf_limit_reasons = 1; + do_ring_perf_limit_reasons = 1; + default: + return; + } +} + int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p) { unsigned long long msr; @@ -2104,6 +2226,7 @@ void check_cpuid() do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model); do_ivt_turbo_ratio_limit = has_ivt_turbo_ratio_limit(family, model); rapl_probe(family, model); + perf_limit_reasons_probe(family, model); return; } @@ -2342,6 +2465,9 @@ void turbostat_init() for_all_cpus(print_epb, ODD_COUNTERS); if (verbose) + for_all_cpus(print_perf_limit, ODD_COUNTERS); + + if (verbose) for_all_cpus(print_rapl, ODD_COUNTERS); for_all_cpus(set_temperature_target, ODD_COUNTERS); -- cgit v0.10.2 From 5c493df25a0d9e0c3bda742250ecfc5953bf4ccd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 9 Feb 2015 15:40:30 +0100 Subject: Merge branch 'pci/host-generic' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci into acpi-resources modified: drivers/of/of_pci.c This fixes a build failure after merging the 'acpi-resources' branch with the PCI tree caused by bad interactions between that branch and the only commit in 'pci/host-generic'. Also that commit contains a bug which can be fixed by removing one line of code, so do that too. Link: http://marc.info/?l=linux-kernel&m=142344882101429&w=2 Link: http://marc.info/?l=linux-next&m=142346304003932&w=2 Signed-off-by: Rafael J. Wysocki diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index 88471d3..62426d8 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c @@ -140,6 +140,7 @@ int of_pci_get_host_bridge_resources(struct device_node *dev, unsigned char busno, unsigned char bus_max, struct list_head *resources, resource_size_t *io_base) { + struct resource_entry *window; struct resource *res; struct resource *bus_range; struct of_pci_range range; @@ -225,6 +226,8 @@ int of_pci_get_host_bridge_resources(struct device_node *dev, conversion_failed: kfree(res); parse_failed: + resource_list_for_each_entry(window, resources) + kfree(window->res); pci_free_resource_list(resources); return err; } -- cgit v0.10.2 From d7899447535929b3672442b7b42a09ae4e48fa91 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 23 Jan 2015 00:12:33 -0500 Subject: tools/power turbostat: relax dependency on invariant TSC Turbostat can be useful on systems that do not support invariant TSC, so allow it to run on those systgems. All arithmetic in turbostat using the TSC value is per-processsor, so it does not depend on the TSC values being in sync acrosss processors. Turbostat uses gettimeofday() for the measurement interval rather than using the TSC directly, so that key metric is also immune from variable TSC. Turbostat prints a TSC sanity check column: TSC_MHz = TSC_delta/interval If this column is constant and is close to the processor base frequency, then the TSC is behaving properly. The other key turbostat columns are calculated this way: Avg_Mhz = APERF_delta/interval %Busy = MPERF_delta/TSC_delta Bzy_MHz = TSC_delta/APERF_delta/MPERF_delta/interval Tested on Core2 and Core2-Xeon, and so this patch includes a few other changes to remove the assumption that target systems are Nehalem and newer. Signed-off-by: Len Brown diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 5891309..b654b64 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -61,8 +61,8 @@ unsigned int has_epb; unsigned int units = 1000000; /* MHz etc */ unsigned int genuine_intel; unsigned int has_invariant_tsc; -unsigned int do_nehalem_platform_info; -unsigned int do_nehalem_turbo_ratio_limit; +unsigned int do_nhm_platform_info; +unsigned int do_nhm_turbo_ratio_limit; unsigned int do_ivt_turbo_ratio_limit; unsigned int extra_msr_offset32; unsigned int extra_msr_offset64; @@ -284,7 +284,7 @@ void print_header(void) outp += sprintf(outp, " CPU"); if (has_aperf) outp += sprintf(outp, " Avg_MHz"); - if (do_nhm_cstates) + if (has_aperf) outp += sprintf(outp, " %%Busy"); if (has_aperf) outp += sprintf(outp, " Bzy_MHz"); @@ -340,7 +340,7 @@ void print_header(void) outp += sprintf(outp, " PKG_%%"); if (do_rapl & RAPL_DRAM_PERF_STATUS) outp += sprintf(outp, " RAM_%%"); - } else { + } else if (do_rapl && rapl_joules) { if (do_rapl & RAPL_PKG) outp += sprintf(outp, " Pkg_J"); if (do_rapl & RAPL_CORES) @@ -460,25 +460,25 @@ int format_counters(struct thread_data *t, struct core_data *c, outp += sprintf(outp, "%8d", t->cpu_id); } - /* AvgMHz */ + /* Avg_MHz */ if (has_aperf) outp += sprintf(outp, "%8.0f", 1.0 / units * t->aperf / interval_float); - /* %c0 */ - if (do_nhm_cstates) { + /* %Busy */ + if (has_aperf) { if (!skip_c0) outp += sprintf(outp, "%8.2f", 100.0 * t->mperf/t->tsc); else outp += sprintf(outp, "********"); } - /* BzyMHz */ + /* Bzy_MHz */ if (has_aperf) outp += sprintf(outp, "%8.0f", 1.0 * t->tsc / units * t->aperf / t->mperf / interval_float); - /* TSC */ + /* TSC_MHz */ outp += sprintf(outp, "%8.0f", 1.0 * t->tsc/units/interval_float); /* SMI */ @@ -564,7 +564,7 @@ int format_counters(struct thread_data *t, struct core_data *c, outp += sprintf(outp, fmt8, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); if (do_rapl & RAPL_DRAM_PERF_STATUS) outp += sprintf(outp, fmt8, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); - } else { + } else if (do_rapl && rapl_joules) { if (do_rapl & RAPL_PKG) outp += sprintf(outp, fmt8, p->energy_pkg * rapl_energy_units); @@ -581,8 +581,8 @@ int format_counters(struct thread_data *t, struct core_data *c, outp += sprintf(outp, fmt8, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); if (do_rapl & RAPL_DRAM_PERF_STATUS) outp += sprintf(outp, fmt8, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); - outp += sprintf(outp, fmt8, interval_float); + outp += sprintf(outp, fmt8, interval_float); } done: outp += sprintf(outp, "\n"); @@ -1022,7 +1022,7 @@ void print_verbose_header(void) unsigned long long msr; unsigned int ratio; - if (!do_nehalem_platform_info) + if (!do_nhm_platform_info) return; get_msr(0, MSR_NHM_PLATFORM_INFO, &msr); @@ -1135,7 +1135,7 @@ print_nhm_turbo_ratio_limits: } fprintf(stderr, ")\n"); - if (!do_nehalem_turbo_ratio_limit) + if (!do_nhm_turbo_ratio_limit) return; get_msr(0, MSR_NHM_TURBO_RATIO_LIMIT, &msr); @@ -1462,8 +1462,7 @@ void check_dev_msr() struct stat sb; if (stat("/dev/cpu/0/msr", &sb)) - err(-5, "no /dev/cpu/0/msr\n" - "Try \"# modprobe msr\""); + err(-5, "no /dev/cpu/0/msr, Try \"# modprobe msr\" "); } void check_permissions() @@ -1496,13 +1495,27 @@ void check_permissions() /* if all else fails, thell them to be root */ if (do_exit) if (getuid() != 0) - warnx("Or simply run as root"); + warnx("... or simply run as root"); if (do_exit) exit(-6); } -int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) +/* + * NHM adds support for additional MSRs: + * + * MSR_SMI_COUNT 0x00000034 + * + * MSR_NHM_PLATFORM_INFO 0x000000ce + * MSR_NHM_SNB_PKG_CST_CFG_CTL 0x000000e2 + * + * MSR_PKG_C3_RESIDENCY 0x000003f8 + * MSR_PKG_C6_RESIDENCY 0x000003f9 + * MSR_CORE_C3_RESIDENCY 0x000003fc + * MSR_CORE_C6_RESIDENCY 0x000003fd + * + */ +int has_nhm_msrs(unsigned int family, unsigned int model) { if (!genuine_intel) return 0; @@ -1529,13 +1542,27 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) case 0x3D: /* BDW */ case 0x4F: /* BDX */ case 0x56: /* BDX-DE */ - return 1; case 0x2E: /* Nehalem-EX Xeon - Beckton */ case 0x2F: /* Westmere-EX Xeon - Eagleton */ + return 1; default: return 0; } } +int has_nhm_turbo_ratio_limit(unsigned int family, unsigned int model) +{ + if (!has_nhm_msrs(family, model)) + return 0; + + switch (model) { + /* Nehalem compatible, but do not include turbo-ratio limit support */ + case 0x2E: /* Nehalem-EX Xeon - Beckton */ + case 0x2F: /* Westmere-EX Xeon - Eagleton */ + return 0; + default: + return 1; + } +} int has_ivt_turbo_ratio_limit(unsigned int family, unsigned int model) { if (!genuine_intel) @@ -1994,8 +2021,15 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p) return 0; } +/* + * SNB adds support for additional MSRs: + * + * MSR_PKG_C7_RESIDENCY 0x000003fa + * MSR_CORE_C7_RESIDENCY 0x000003fe + * MSR_PKG_C2_RESIDENCY 0x0000060d + */ -int is_snb(unsigned int family, unsigned int model) +int has_snb_msrs(unsigned int family, unsigned int model) { if (!genuine_intel) return 0; @@ -2017,7 +2051,14 @@ int is_snb(unsigned int family, unsigned int model) return 0; } -int has_c8_c9_c10(unsigned int family, unsigned int model) +/* + * HSW adds support for additional MSRs: + * + * MSR_PKG_C8_RESIDENCY 0x00000630 + * MSR_PKG_C9_RESIDENCY 0x00000631 + * MSR_PKG_C10_RESIDENCY 0x00000632 + */ +int has_hsw_msrs(unsigned int family, unsigned int model) { if (!genuine_intel) return 0; @@ -2069,7 +2110,7 @@ double slm_bclk(void) double discover_bclk(unsigned int family, unsigned int model) { - if (is_snb(family, model)) + if (has_snb_msrs(family, model)) return 100.00; else if (is_slm(family, model)) return slm_bclk(); @@ -2117,7 +2158,7 @@ int set_temperature_target(struct thread_data *t, struct core_data *c, struct pk } /* Temperature Target MSR is Nehalem and newer only */ - if (!do_nehalem_platform_info) + if (!do_nhm_platform_info) goto guess; if (get_msr(0, MSR_IA32_TEMPERATURE_TARGET, &msr)) @@ -2181,18 +2222,15 @@ void check_cpuid() ebx = ecx = edx = 0; __get_cpuid(0x80000000, &max_level, &ebx, &ecx, &edx); - if (max_level < 0x80000007) - errx(1, "CPUID: no invariant TSC (max_level 0x%x)", max_level); + if (max_level >= 0x80000007) { - /* - * Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8 - * this check is valid for both Intel and AMD - */ - __get_cpuid(0x80000007, &eax, &ebx, &ecx, &edx); - has_invariant_tsc = edx & (1 << 8); - - if (!has_invariant_tsc) - errx(1, "No invariant TSC"); + /* + * Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8 + * this check is valid for both Intel and AMD + */ + __get_cpuid(0x80000007, &eax, &ebx, &ecx, &edx); + has_invariant_tsc = edx & (1 << 8); + } /* * APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0 @@ -2215,15 +2253,13 @@ void check_cpuid() if (!has_aperf) errx(-1, "No APERF"); - do_nehalem_platform_info = genuine_intel && has_invariant_tsc; - do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */ - do_smi = do_nhm_cstates; - do_snb_cstates = is_snb(family, model); - do_c8_c9_c10 = has_c8_c9_c10(family, model); + do_nhm_platform_info = do_nhm_cstates = do_smi = has_nhm_msrs(family, model); + do_snb_cstates = has_snb_msrs(family, model); + do_c8_c9_c10 = has_hsw_msrs(family, model); do_slm_cstates = is_slm(family, model); bclk = discover_bclk(family, model); - do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model); + do_nhm_turbo_ratio_limit = has_nhm_turbo_ratio_limit(family, model); do_ivt_turbo_ratio_limit = has_ivt_turbo_ratio_limit(family, model); rapl_probe(family, model); perf_limit_reasons_probe(family, model); -- cgit v0.10.2 From a729617c58529be0be8faa22c5d45748bb0f12e5 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 23 Jan 2015 01:33:58 -0500 Subject: tools/power turbostat: relax dependency on APERF_MSR While turbostat is significantly less useful on systems with no APERF_MSR, it seems more friendly to run on such systems and report what we can, rather than refusing to run. Update man page to reflect recent changes. Signed-off-by: Len Brown diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 index 56bfb52..9b95069 100644 --- a/tools/power/x86/turbostat/turbostat.8 +++ b/tools/power/x86/turbostat/turbostat.8 @@ -12,16 +12,16 @@ turbostat \- Report processor frequency and idle statistics .RB [ "\-i interval_sec" ] .SH DESCRIPTION \fBturbostat \fP reports processor topology, frequency, -idle power-state statistics, temperature and power on modern X86 processors. -Either \fBcommand\fP is forked and statistics are printed -upon its completion, or statistics are printed periodically. - -\fBturbostat \fP -must be run on root, and -minimally requires that the processor -supports an "invariant" TSC, plus the APERF and MPERF MSRs. -Additional information is reported depending on hardware counter support. - +idle power-state statistics, temperature and power on X86 processors. +There are two ways to invoke turbostat. +The first method is to supply a +\fBcommand\fP, which is forked and statistics are printed +upon its completion. +The second method is to omit the command, +and turbodstat will print statistics every 5 seconds. +The 5-second interval can changed using the -i option. + +Some information is not availalbe on older processors. .SS Options The \fB-p\fP option limits output to the 1st thread in 1st core of each package. .PP @@ -130,12 +130,13 @@ cpu3: MSR_IA32_THERM_STATUS: 0x884e0000 (27 C +/- 1) ... .fi The \fBmax efficiency\fP frequency, a.k.a. Low Frequency Mode, is the frequency -available at the minimum package voltage. The \fBTSC frequency\fP is the nominal -maximum frequency of the processor if turbo-mode were not available. This frequency +available at the minimum package voltage. The \fBTSC frequency\fP is the base +frequency of the processor -- this should match the brand string +in /proc/cpuinfo. This base frequency should be sustainable on all CPUs indefinitely, given nominal power and cooling. The remaining rows show what maximum turbo frequency is possible -depending on the number of idle cores. Note that this information is -not available on all processors. +depending on the number of idle cores. Note that not all information is +available on all processors. .SH FORK EXAMPLE If turbostat is invoked with a command, it will fork that command and output the statistics gathered when the command exits. @@ -176,6 +177,11 @@ not including any non-busy idle time. .B "turbostat " must be run as root. +Alternatively, non-root users can be enabled to run turbostat this way: + +# setcap cap_sys_rawio=ep ./turbostat + +# chmod +r /dev/cpu/*/msr .B "turbostat " reads hardware counters, but doesn't write them. @@ -184,15 +190,33 @@ multiple invocations of itself. \fBturbostat \fP may work poorly on Linux-2.6.20 through 2.6.29, -as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF +as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF MSRs in those kernels. -If the TSC column does not make sense, then -the other numbers will also make no sense. -Turbostat is lightweight, and its data collection is not atomic. -These issues are usually caused by an extremely short measurement -interval (much less than 1 second), or system activity that prevents -turbostat from being able to run on all CPUS to quickly collect data. +AVG_MHz = APERF_delta/measurement_interval. This is the actual +number of elapsed cycles divided by the entire sample interval -- +including idle time. Note that this calculation is resiliant +to systems lacking a non-stop TSC. + +TSC_MHz = TSC_delta/measurement_interval. +On a system with an invariant TSC, this value will be constant +and will closely match the base frequency value shown +in the brand string in /proc/cpuinfo. On a system where +the TSC stops in idle, TSC_MHz will drop +below the processor's base frequency. + +%Busy = MPERF_delta/TSC_delta + +Bzy_MHz = TSC_delta/APERF_delta/MPERF_delta/measurement_interval + +Note that these calculations depend on TSC_delta, so they +are not reliable during intervals when TSC_MHz is not running at the base frequency. + +Turbostat data collection is not atomic. +Extremely short measurement intervals (much less than 1 second), +or system activity that prevents turbostat from being able +to run on all CPUS to quickly collect data, will result in +inconsistent results. The APERF, MPERF MSRs are defined to count non-halted cycles. Although it is not guaranteed by the architecture, turbostat assumes diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index b654b64..a02c02f 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -673,24 +673,26 @@ delta_thread(struct thread_data *new, struct thread_data *old, old->c1 = new->c1 - old->c1; - if ((new->aperf > old->aperf) && (new->mperf > old->mperf)) { - old->aperf = new->aperf - old->aperf; - old->mperf = new->mperf - old->mperf; - } else { + if (has_aperf) { + if ((new->aperf > old->aperf) && (new->mperf > old->mperf)) { + old->aperf = new->aperf - old->aperf; + old->mperf = new->mperf - old->mperf; + } else { - if (!aperf_mperf_unstable) { - fprintf(stderr, "%s: APERF or MPERF went backwards *\n", progname); - fprintf(stderr, "* Frequency results do not cover entire interval *\n"); - fprintf(stderr, "* fix this by running Linux-2.6.30 or later *\n"); + if (!aperf_mperf_unstable) { + fprintf(stderr, "%s: APERF or MPERF went backwards *\n", progname); + fprintf(stderr, "* Frequency results do not cover entire interval *\n"); + fprintf(stderr, "* fix this by running Linux-2.6.30 or later *\n"); - aperf_mperf_unstable = 1; + aperf_mperf_unstable = 1; + } + /* + * mperf delta is likely a huge "positive" number + * can not use it for calculating c0 time + */ + skip_c0 = 1; + skip_c1 = 1; } - /* - * mperf delta is likely a huge "positive" number - * can not use it for calculating c0 time - */ - skip_c0 = 1; - skip_c1 = 1; } @@ -2244,14 +2246,11 @@ void check_cpuid() has_epb = ecx & (1 << 3); if (verbose) - fprintf(stderr, "CPUID(6): %s%s%s%s\n", - has_aperf ? "APERF" : "No APERF!", - do_dts ? ", DTS" : "", - do_ptm ? ", PTM": "", - has_epb ? ", EPB": ""); - - if (!has_aperf) - errx(-1, "No APERF"); + fprintf(stderr, "CPUID(6): %sAPERF, %sDTS, %sPTM, %sEPB\n", + has_aperf ? "" : "No ", + do_dts ? "" : "No ", + do_ptm ? "" : "No ", + has_epb ? "" : "No "); do_nhm_platform_info = do_nhm_cstates = do_smi = has_nhm_msrs(family, model); do_snb_cstates = has_snb_msrs(family, model); @@ -2632,7 +2631,7 @@ int main(int argc, char **argv) cmdline(argc, argv); if (verbose) - fprintf(stderr, "turbostat v3.8 14-Aug 2014" + fprintf(stderr, "turbostat v3.9 23-Jan, 2015" " - Len Brown \n"); turbostat_init(); -- cgit v0.10.2