Browse Source

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
Linus Torvalds 12 years ago
parent
commit
22446d3f23

+ 1 - 1
drivers/acpi/battery.c

@@ -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);

+ 1 - 1
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",
 				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));

+ 4 - 2
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)
 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)
 		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;

+ 0 - 4
drivers/acpi/utils.c

@@ -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:

+ 8 - 0
drivers/acpi/video_detect.c

@@ -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"),

+ 17 - 4
drivers/cpufreq/intel_pstate.c

@@ -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 {
 
 
 	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,
 					struct sample *sample)
 					struct sample *sample)
 {
 {
 	u64 core_pct;
 	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)
 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)

+ 44 - 11
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 = {
 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)
 	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)
 
 
 		/* 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)
 			; /* 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,
-						 bus_list)
+			list_for_each_entry_safe_reverse(dev, tmp,
+							 &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)
 	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)
 
 
 	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)
 
 
 	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)
 		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)
 	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)
 {
 {
 	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)
 
 
 	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)) {
-		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);
 		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;