mirror of
https://github.com/torvalds/linux.git
synced 2024-11-16 17:12:06 +00:00
ACPI and power management fixes for 3.14-rc2
- 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. / -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABCAAGBQJS9BjXAAoJEILEb/54YlRxETkP/iypvMbG0LfnTOC3xGE5tkqP G/E/QR7km3+DKMq9AY/GcQ9B5i1NXqy9ffbwQPmIAy3LMbCkFSb/6GfmIgBKKVpy LGHOnqe89DqEvYYiXgLlvXgn6QLf3Kh6Dlyenc0WYuFjhefatnxK0WOyDxzgSh2M +walAqi8Mxu5nNiFFs9qInhV71Wriy0m6PFzCDs5ObbAbJmvRQeBGsyiPW8V+im1 tuPQ4w0p4Kt+oTr1Plq61DMuOBYi2A4ShWU10WsxS37iSK00GdbBycXt3kvdEAKe RFDBcVNyEMcw3GOXAA9Fz7eXX+S/RxWg3yaeqsy+hr7Ev1haJVAiOvxNU2J5fcyp RmpI/QHGStePqL+Ua7dYSO31quaclB/HwlEhgFPDzgSQI0qG6HxWlSz5nJLso2+c ZwDMzek9maIT7/S5Xwq/yCOo0VUB5xx2lLxZa5oUXv65h2e888ilmKwJJvvhrIUL 7zpnQ7PYRaTqYJgXefNKuT04nioNSkNnAIyUgpHKMeMZibyEFHWPGSICTinP1Gjj uk690wuFKrPawyXLr8mweOkElqa6fT8DgywGwJLfTqObhQghrapNOiM2W5m4yrDN mFv/uQgwFxgdm+ZM2E2utnD4W3ozo+3GdptCgGMIPP1JMXigX7GElUFCU+RL3D8K OrvlQEb5jmKNIFzOMGtf =FSnS -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
22446d3f23
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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"),
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user