diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-02-07 12:12:21 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-02-07 12:12:21 -0800 |
commit | 22446d3f23dd250ed1922edc8cc8a003bcb2538e (patch) | |
tree | e13cb0713f382d27f5d932ac80cdfecf933a82e1 | |
parent | 9343224bfd4be6a02e6ae0c0d66426c955c7d76e (diff) | |
parent | a2ff34c433932e201ea3c5081335f3beeb2509bd (diff) |
Merge tag 'pm+acpi-3.14-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull ACPI and power management fixes from Rafael Wysocki:
"These include a fix for a recent ACPI hotplug regression, four
concurrency related fixes and one PCI device removal fix for
ACPI-based PCI hotplug (ACPIPHP), intel_pstate fix that should go into
stable, three simple ACPI cleanups and a new entry for the ACPI video
blacklist.
Specifics:
- Fix for a recent ACPI hotplug regression causing a NULL pointer
dereference to occur while handling ACPI eject notifications for
already ejected devices. From Toshi Kani.
- Four concurrency-related fixes for ACPIPHP. Two of them add
missing locking and the other two fix race conditions related to
reference counting.
- ACPIPHP fix to avoid NULL pointer dereferences during device
removal involving Virtual Funcions.
- intel_pstate fix to make it compute the percentage of time the CPU
is busy properly. From Dirk Brandewie.
- Removal of two unnecessary NULL pointer checks in ACPI code and a
fix for sscanf() format string from Dan Carpenter and Luis G.F.
- New ACPI video blacklist entry for HP EliteBook Revolve 810 from
Mika Westerberg"
* tag 'pm+acpi-3.14-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
ACPI / hotplug: Fix panic on eject to ejected device
ACPI / battery: Fix incorrect sscanf() string in acpi_battery_init_alarm()
ACPI / proc: remove unneeded NULL check
ACPI / utils: remove a pointless NULL check
ACPI / video: Add HP EliteBook Revolve 810 to the blacklist
intel_pstate: Take core C0 time into account for core busy calculation
ACPI / hotplug / PCI: Fix bridge removal race vs dock events
ACPI / hotplug / PCI: Fix bridge removal race in handle_hotplug_event()
ACPI / hotplug / PCI: Scan root bus under the PCI rescan-remove lock
ACPI / hotplug / PCI: Move PCI rescan-remove locking to hotplug_event()
ACPI / hotplug / PCI: Remove entries from bus->devices in reverse order
-rw-r--r-- | drivers/acpi/battery.c | 2 | ||||
-rw-r--r-- | drivers/acpi/proc.c | 2 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 6 | ||||
-rw-r--r-- | drivers/acpi/utils.c | 4 | ||||
-rw-r--r-- | drivers/acpi/video_detect.c | 8 | ||||
-rw-r--r-- | drivers/cpufreq/intel_pstate.c | 21 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 55 |
7 files changed, 75 insertions, 23 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 470e7542bf31..018a42883706 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -549,7 +549,7 @@ static ssize_t acpi_battery_alarm_store(struct device *dev, { unsigned long x; struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); - if (sscanf(buf, "%ld\n", &x) == 1) + if (sscanf(buf, "%lu\n", &x) == 1) battery->alarm = x/1000; if (acpi_battery_present(battery)) acpi_battery_set_alarm(battery); diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index 50fe34ffe932..75c28eae8860 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c @@ -60,7 +60,7 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) seq_printf(seq, "%c%-8s %s:%s\n", dev->wakeup.flags.run_wake ? '*' : ' ', (device_may_wakeup(&dev->dev) || - (ldev && device_may_wakeup(ldev))) ? + device_may_wakeup(ldev)) ? "enabled" : "disabled", ldev->bus ? ldev->bus->name : "no-bus", dev_name(ldev)); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 7384158c7f87..57b053f424d1 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -484,7 +484,6 @@ static void acpi_device_hotplug(void *data, u32 src) static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) { u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - struct acpi_scan_handler *handler = data; struct acpi_device *adev; acpi_status status; @@ -500,7 +499,10 @@ static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) break; case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - if (!handler->hotplug.enabled) { + if (!adev->handler) + goto err_out; + + if (!adev->handler->hotplug.enabled) { acpi_handle_err(handle, "Eject disabled\n"); ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; goto err_out; diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 0347a37eb438..85e3b612bdc0 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -99,10 +99,6 @@ acpi_extract_package(union acpi_object *package, union acpi_object *element = &(package->package.elements[i]); - if (!element) { - return AE_BAD_DATA; - } - switch (element->type) { case ACPI_TYPE_INTEGER: diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index f0447d3daf2c..a697b77b8865 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -170,6 +170,14 @@ static struct dmi_system_id video_detect_dmi_table[] = { }, { .callback = video_detect_force_vendor, + .ident = "HP EliteBook Revolve 810", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook Revolve 810 G1"), + }, + }, + { + .callback = video_detect_force_vendor, .ident = "Lenovo Yoga 13", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 7e257b233602..79606f473f48 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -57,6 +57,7 @@ struct sample { int32_t core_pct_busy; u64 aperf; u64 mperf; + unsigned long long tsc; int freq; }; @@ -96,6 +97,7 @@ struct cpudata { u64 prev_aperf; u64 prev_mperf; + unsigned long long prev_tsc; int sample_ptr; struct sample samples[SAMPLE_COUNT]; }; @@ -548,30 +550,41 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu, struct sample *sample) { u64 core_pct; - core_pct = div64_u64(int_tofp(sample->aperf * 100), - sample->mperf); - sample->freq = fp_toint(cpu->pstate.max_pstate * core_pct * 1000); + u64 c0_pct; - sample->core_pct_busy = core_pct; + core_pct = div64_u64(sample->aperf * 100, sample->mperf); + + c0_pct = div64_u64(sample->mperf * 100, sample->tsc); + sample->freq = fp_toint( + mul_fp(int_tofp(cpu->pstate.max_pstate), + int_tofp(core_pct * 1000))); + + sample->core_pct_busy = mul_fp(int_tofp(core_pct), + div_fp(int_tofp(c0_pct + 1), int_tofp(100))); } static inline void intel_pstate_sample(struct cpudata *cpu) { u64 aperf, mperf; + unsigned long long tsc; rdmsrl(MSR_IA32_APERF, aperf); rdmsrl(MSR_IA32_MPERF, mperf); + tsc = native_read_tsc(); cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT; cpu->samples[cpu->sample_ptr].aperf = aperf; cpu->samples[cpu->sample_ptr].mperf = mperf; + cpu->samples[cpu->sample_ptr].tsc = tsc; cpu->samples[cpu->sample_ptr].aperf -= cpu->prev_aperf; cpu->samples[cpu->sample_ptr].mperf -= cpu->prev_mperf; + cpu->samples[cpu->sample_ptr].tsc -= cpu->prev_tsc; intel_pstate_calc_busy(cpu, &cpu->samples[cpu->sample_ptr]); cpu->prev_aperf = aperf; cpu->prev_mperf = mperf; + cpu->prev_tsc = tsc; } static inline void intel_pstate_set_sample_time(struct cpudata *cpu) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index cd929aed3613..e2a783fdb98f 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -210,10 +210,29 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) } } +static void dock_event(acpi_handle handle, u32 type, void *data) +{ + struct acpiphp_context *context; + + mutex_lock(&acpiphp_context_lock); + context = acpiphp_get_context(handle); + if (!context || WARN_ON(context->handle != handle) + || context->func.parent->is_going_away) { + mutex_unlock(&acpiphp_context_lock); + return; + } + get_bridge(context->func.parent); + acpiphp_put_context(context); + mutex_unlock(&acpiphp_context_lock); + + hotplug_event(handle, type, data); + + put_bridge(context->func.parent); +} static const struct acpi_dock_ops acpiphp_dock_ops = { .fixup = post_dock_fixups, - .handler = hotplug_event, + .handler = dock_event, }; /* Check whether the PCI device is managed by native PCIe hotplug driver */ @@ -441,7 +460,9 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) list_del(&bridge->list); mutex_unlock(&bridge_mutex); + mutex_lock(&acpiphp_context_lock); bridge->is_going_away = true; + mutex_unlock(&acpiphp_context_lock); } /** @@ -742,7 +763,7 @@ static void trim_stale_devices(struct pci_dev *dev) /* The device is a bridge. so check the bus below it. */ pm_runtime_get_sync(&dev->dev); - list_for_each_entry_safe(child, tmp, &bus->devices, bus_list) + list_for_each_entry_safe_reverse(child, tmp, &bus->devices, bus_list) trim_stale_devices(child); pm_runtime_put(&dev->dev); @@ -773,8 +794,8 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) ; /* do nothing */ } else if (get_slot_status(slot) == ACPI_STA_ALL) { /* remove stale devices if any */ - list_for_each_entry_safe(dev, tmp, &bus->devices, - bus_list) + list_for_each_entry_safe_reverse(dev, tmp, + &bus->devices, bus_list) if (PCI_SLOT(dev->devfn) == slot->device) trim_stale_devices(dev); @@ -805,7 +826,7 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus) int i; unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; - list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { + list_for_each_entry_safe_reverse(dev, tmp, &bus->devices, bus_list) { for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { struct resource *res = &dev->resource[i]; if ((res->flags & type_mask) && !res->start && @@ -829,7 +850,11 @@ void acpiphp_check_host_bridge(acpi_handle handle) bridge = acpiphp_handle_to_bridge(handle); if (bridge) { + pci_lock_rescan_remove(); + acpiphp_check_bridge(bridge); + + pci_unlock_rescan_remove(); put_bridge(bridge); } } @@ -852,6 +877,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) mutex_unlock(&acpiphp_context_lock); + pci_lock_rescan_remove(); acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); switch (type) { @@ -905,6 +931,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) break; } + pci_unlock_rescan_remove(); if (bridge) put_bridge(bridge); } @@ -915,11 +942,9 @@ static void hotplug_event_work(void *data, u32 type) acpi_handle handle = context->handle; acpi_scan_lock_acquire(); - pci_lock_rescan_remove(); hotplug_event(handle, type, context); - pci_unlock_rescan_remove(); acpi_scan_lock_release(); acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); put_bridge(context->func.parent); @@ -937,6 +962,7 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) { struct acpiphp_context *context; u32 ost_code = ACPI_OST_SC_SUCCESS; + acpi_status status; switch (type) { case ACPI_NOTIFY_BUS_CHECK: @@ -972,13 +998,20 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) mutex_lock(&acpiphp_context_lock); context = acpiphp_get_context(handle); - if (context && !WARN_ON(context->handle != handle)) { - get_bridge(context->func.parent); - acpiphp_put_context(context); - acpi_hotplug_execute(hotplug_event_work, context, type); + if (!context || WARN_ON(context->handle != handle) + || context->func.parent->is_going_away) + goto err_out; + + get_bridge(context->func.parent); + acpiphp_put_context(context); + status = acpi_hotplug_execute(hotplug_event_work, context, type); + if (ACPI_SUCCESS(status)) { mutex_unlock(&acpiphp_context_lock); return; } + put_bridge(context->func.parent); + + err_out: mutex_unlock(&acpiphp_context_lock); ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; |