Commit 22446d3f authored by Linus Torvalds's avatar Linus Torvalds

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
parents 9343224b a2ff34c4
...@@ -549,7 +549,7 @@ static ssize_t acpi_battery_alarm_store(struct device *dev, ...@@ -549,7 +549,7 @@ static ssize_t acpi_battery_alarm_store(struct device *dev,
{ {
unsigned long x; unsigned long x;
struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); 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; battery->alarm = x/1000;
if (acpi_battery_present(battery)) if (acpi_battery_present(battery))
acpi_battery_set_alarm(battery); acpi_battery_set_alarm(battery);
......
...@@ -60,7 +60,7 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) ...@@ -60,7 +60,7 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
seq_printf(seq, "%c%-8s %s:%s\n", seq_printf(seq, "%c%-8s %s:%s\n",
dev->wakeup.flags.run_wake ? '*' : ' ', dev->wakeup.flags.run_wake ? '*' : ' ',
(device_may_wakeup(&dev->dev) || (device_may_wakeup(&dev->dev) ||
(ldev && device_may_wakeup(ldev))) ? device_may_wakeup(ldev)) ?
"enabled" : "disabled", "enabled" : "disabled",
ldev->bus ? ldev->bus->name : ldev->bus ? ldev->bus->name :
"no-bus", dev_name(ldev)); "no-bus", dev_name(ldev));
......
...@@ -484,7 +484,6 @@ static void acpi_device_hotplug(void *data, u32 src) ...@@ -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) static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
{ {
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
struct acpi_scan_handler *handler = data;
struct acpi_device *adev; struct acpi_device *adev;
acpi_status status; acpi_status status;
...@@ -500,7 +499,10 @@ static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) ...@@ -500,7 +499,10 @@ static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
break; break;
case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_NOTIFY_EJECT_REQUEST:
acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); 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"); acpi_handle_err(handle, "Eject disabled\n");
ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
goto err_out; goto err_out;
......
...@@ -99,10 +99,6 @@ acpi_extract_package(union acpi_object *package, ...@@ -99,10 +99,6 @@ acpi_extract_package(union acpi_object *package,
union acpi_object *element = &(package->package.elements[i]); union acpi_object *element = &(package->package.elements[i]);
if (!element) {
return AE_BAD_DATA;
}
switch (element->type) { switch (element->type) {
case ACPI_TYPE_INTEGER: case ACPI_TYPE_INTEGER:
......
...@@ -170,6 +170,14 @@ static struct dmi_system_id video_detect_dmi_table[] = { ...@@ -170,6 +170,14 @@ static struct dmi_system_id video_detect_dmi_table[] = {
}, },
{ {
.callback = video_detect_force_vendor, .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", .ident = "Lenovo Yoga 13",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
......
...@@ -57,6 +57,7 @@ struct sample { ...@@ -57,6 +57,7 @@ struct sample {
int32_t core_pct_busy; int32_t core_pct_busy;
u64 aperf; u64 aperf;
u64 mperf; u64 mperf;
unsigned long long tsc;
int freq; int freq;
}; };
...@@ -96,6 +97,7 @@ struct cpudata { ...@@ -96,6 +97,7 @@ struct cpudata {
u64 prev_aperf; u64 prev_aperf;
u64 prev_mperf; u64 prev_mperf;
unsigned long long prev_tsc;
int sample_ptr; int sample_ptr;
struct sample samples[SAMPLE_COUNT]; struct sample samples[SAMPLE_COUNT];
}; };
...@@ -548,30 +550,41 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu, ...@@ -548,30 +550,41 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu,
struct sample *sample) struct sample *sample)
{ {
u64 core_pct; u64 core_pct;
core_pct = div64_u64(int_tofp(sample->aperf * 100), u64 c0_pct;
sample->mperf);
sample->freq = fp_toint(cpu->pstate.max_pstate * core_pct * 1000);
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) static inline void intel_pstate_sample(struct cpudata *cpu)
{ {
u64 aperf, mperf; u64 aperf, mperf;
unsigned long long tsc;
rdmsrl(MSR_IA32_APERF, aperf); rdmsrl(MSR_IA32_APERF, aperf);
rdmsrl(MSR_IA32_MPERF, mperf); rdmsrl(MSR_IA32_MPERF, mperf);
tsc = native_read_tsc();
cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT; cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT;
cpu->samples[cpu->sample_ptr].aperf = aperf; cpu->samples[cpu->sample_ptr].aperf = aperf;
cpu->samples[cpu->sample_ptr].mperf = mperf; 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].aperf -= cpu->prev_aperf;
cpu->samples[cpu->sample_ptr].mperf -= cpu->prev_mperf; 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]); intel_pstate_calc_busy(cpu, &cpu->samples[cpu->sample_ptr]);
cpu->prev_aperf = aperf; cpu->prev_aperf = aperf;
cpu->prev_mperf = mperf; cpu->prev_mperf = mperf;
cpu->prev_tsc = tsc;
} }
static inline void intel_pstate_set_sample_time(struct cpudata *cpu) static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
......
...@@ -210,10 +210,29 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) ...@@ -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 = { static const struct acpi_dock_ops acpiphp_dock_ops = {
.fixup = post_dock_fixups, .fixup = post_dock_fixups,
.handler = hotplug_event, .handler = dock_event,
}; };
/* Check whether the PCI device is managed by native PCIe hotplug driver */ /* Check whether the PCI device is managed by native PCIe hotplug driver */
...@@ -441,7 +460,9 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) ...@@ -441,7 +460,9 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
list_del(&bridge->list); list_del(&bridge->list);
mutex_unlock(&bridge_mutex); mutex_unlock(&bridge_mutex);
mutex_lock(&acpiphp_context_lock);
bridge->is_going_away = true; bridge->is_going_away = true;
mutex_unlock(&acpiphp_context_lock);
} }
/** /**
...@@ -742,7 +763,7 @@ static void trim_stale_devices(struct pci_dev *dev) ...@@ -742,7 +763,7 @@ static void trim_stale_devices(struct pci_dev *dev)
/* The device is a bridge. so check the bus below it. */ /* The device is a bridge. so check the bus below it. */
pm_runtime_get_sync(&dev->dev); 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); trim_stale_devices(child);
pm_runtime_put(&dev->dev); pm_runtime_put(&dev->dev);
...@@ -773,8 +794,8 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) ...@@ -773,8 +794,8 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
; /* do nothing */ ; /* do nothing */
} else if (get_slot_status(slot) == ACPI_STA_ALL) { } else if (get_slot_status(slot) == ACPI_STA_ALL) {
/* remove stale devices if any */ /* remove stale devices if any */
list_for_each_entry_safe(dev, tmp, &bus->devices, list_for_each_entry_safe_reverse(dev, tmp,
bus_list) &bus->devices, bus_list)
if (PCI_SLOT(dev->devfn) == slot->device) if (PCI_SLOT(dev->devfn) == slot->device)
trim_stale_devices(dev); trim_stale_devices(dev);
...@@ -805,7 +826,7 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus) ...@@ -805,7 +826,7 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
int i; int i;
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; 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++) { for (i=0; i<PCI_BRIDGE_RESOURCES; i++) {
struct resource *res = &dev->resource[i]; struct resource *res = &dev->resource[i];
if ((res->flags & type_mask) && !res->start && if ((res->flags & type_mask) && !res->start &&
...@@ -829,7 +850,11 @@ void acpiphp_check_host_bridge(acpi_handle handle) ...@@ -829,7 +850,11 @@ void acpiphp_check_host_bridge(acpi_handle handle)
bridge = acpiphp_handle_to_bridge(handle); bridge = acpiphp_handle_to_bridge(handle);
if (bridge) { if (bridge) {
pci_lock_rescan_remove();
acpiphp_check_bridge(bridge); acpiphp_check_bridge(bridge);
pci_unlock_rescan_remove();
put_bridge(bridge); put_bridge(bridge);
} }
} }
...@@ -852,6 +877,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) ...@@ -852,6 +877,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
mutex_unlock(&acpiphp_context_lock); mutex_unlock(&acpiphp_context_lock);
pci_lock_rescan_remove();
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
switch (type) { switch (type) {
...@@ -905,6 +931,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) ...@@ -905,6 +931,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
break; break;
} }
pci_unlock_rescan_remove();
if (bridge) if (bridge)
put_bridge(bridge); put_bridge(bridge);
} }
...@@ -915,11 +942,9 @@ static void hotplug_event_work(void *data, u32 type) ...@@ -915,11 +942,9 @@ static void hotplug_event_work(void *data, u32 type)
acpi_handle handle = context->handle; acpi_handle handle = context->handle;
acpi_scan_lock_acquire(); acpi_scan_lock_acquire();
pci_lock_rescan_remove();
hotplug_event(handle, type, context); hotplug_event(handle, type, context);
pci_unlock_rescan_remove();
acpi_scan_lock_release(); acpi_scan_lock_release();
acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL);
put_bridge(context->func.parent); put_bridge(context->func.parent);
...@@ -937,6 +962,7 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) ...@@ -937,6 +962,7 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
{ {
struct acpiphp_context *context; struct acpiphp_context *context;
u32 ost_code = ACPI_OST_SC_SUCCESS; u32 ost_code = ACPI_OST_SC_SUCCESS;
acpi_status status;
switch (type) { switch (type) {
case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_BUS_CHECK:
...@@ -972,13 +998,20 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) ...@@ -972,13 +998,20 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
mutex_lock(&acpiphp_context_lock); mutex_lock(&acpiphp_context_lock);
context = acpiphp_get_context(handle); context = acpiphp_get_context(handle);
if (context && !WARN_ON(context->handle != handle)) { if (!context || WARN_ON(context->handle != handle)
|| context->func.parent->is_going_away)
goto err_out;
get_bridge(context->func.parent); get_bridge(context->func.parent);
acpiphp_put_context(context); acpiphp_put_context(context);
acpi_hotplug_execute(hotplug_event_work, context, type); status = acpi_hotplug_execute(hotplug_event_work, context, type);
if (ACPI_SUCCESS(status)) {
mutex_unlock(&acpiphp_context_lock); mutex_unlock(&acpiphp_context_lock);
return; return;
} }
put_bridge(context->func.parent);
err_out:
mutex_unlock(&acpiphp_context_lock); mutex_unlock(&acpiphp_context_lock);
ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment