Skip to contentSkip to conversation

ACPI patches for 2.6.34-rc3

PATCH In review Len Brown 2 participants 15 messages Apr 6, 2010

Subsystems (3)
lore
Share & tools
lore

Len Brown

author reviewer
#0 lore raw

Here are the ACPI patches for 2.6.34-rc3.

Please speak up if you see problems with any of them, or know of additional patches which merit inclusion in 2.6.34.

thanks,
-Len Brown, Intel Open Source Technology Center

author reviewer
#1 lore raw

PATCH 1/12 ACPI: EC: Allow multibyte access to EC

From: Alexey Starikovskiy <[email protected]>

http://bugzilla.kernel.org/show_bug.cgi?id=14667

---
 drivers/acpi/acpica/exprep.c |   12 ++++++++++++
 drivers/acpi/ec.c            |   35 +++++++++--------------------------
 2 files changed, 21 insertions(+), 26 deletions(-)
drivers/acpi/acpica/exprep.c +12 -0
index edf62bf..a610ebe 100644
@@ -468,6 +468,18 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
 
 		acpi_ut_add_reference(obj_desc->field.region_obj);
 
+		/* allow full data read from EC address space */
+		if (obj_desc->field.region_obj->region.space_id ==
+			ACPI_ADR_SPACE_EC) {
+			if (obj_desc->common_field.bit_length > 8)
+				obj_desc->common_field.access_bit_width =
+				ACPI_ROUND_UP(obj_desc->common_field.
+							bit_length, 8);
+				obj_desc->common_field.access_byte_width =
+				ACPI_DIV_8(obj_desc->common_field.
+							access_bit_width);
+		}
+
 		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
 				  "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n",
 				  obj_desc->field.start_field_bit_offset,
drivers/acpi/ec.c +9 -26
index 1ac28c6..7208a69 100644
@@ -628,12 +628,12 @@ static u32 acpi_ec_gpe_handler(void *data)
 
 static acpi_status
 acpi_ec_space_handler(u32 function, acpi_physical_address address,
-		      u32 bits, u64 *value,
+		      u32 bits, u64 *value64,
 		      void *handler_context, void *region_context)
 {
 	struct acpi_ec *ec = handler_context;
-	int result = 0, i;
-	u8 temp = 0;
+	int result = 0, i, bytes = bits / 8;
+	u8 *value = (u8 *)value64;
 
 	if ((address > 0xFF) || !value || !handler_context)
 		return AE_BAD_PARAMETER;
@@ -641,32 +641,15 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
 	if (function != ACPI_READ && function != ACPI_WRITE)
 		return AE_BAD_PARAMETER;
 
-	if (bits != 8 && acpi_strict)
-		return AE_BAD_PARAMETER;
-
-	if (EC_FLAGS_MSI)
+	if (EC_FLAGS_MSI || bits > 8)
 		acpi_ec_burst_enable(ec);
 
-	if (function == ACPI_READ) {
-		result = acpi_ec_read(ec, address, &temp);
-		*value = temp;
-	} else {
-		temp = 0xff & (*value);
-		result = acpi_ec_write(ec, address, temp);
-	}
-
-	for (i = 8; unlikely(bits - i > 0); i += 8) {
-		++address;
-		if (function == ACPI_READ) {
-			result = acpi_ec_read(ec, address, &temp);
-			(*value) |= ((u64)temp) << i;
-		} else {
-			temp = 0xff & ((*value) >> i);
-			result = acpi_ec_write(ec, address, temp);
-		}
-	}
+	for (i = 0; i < bytes; ++i, ++address, ++value)
+		result = (function == ACPI_READ) ?
+			acpi_ec_read(ec, address, value) :
+			acpi_ec_write(ec, address, *value);
 
-	if (EC_FLAGS_MSI)
+	if (EC_FLAGS_MSI || bits > 8)
 		acpi_ec_burst_disable(ec);
 
 	switch (result) {
Signature · 1 line
1.6.0.6
author reviewer
#2 lore raw

PATCH 2/12 ACPI / PM: Move ACPI video resume to a PM notifier

In reply to Len Brown

From: Rafael Wysocki <[email protected]>

There is a problem with the ACPI video resume routine that it's executed before the GPU that may be accessed by it. To fix this issue, move the ACPI video resume to a power management notifier, so that it's executed after resuming all devices, including the GPU.

http://bugzilla.kernel.org/show_bug.cgi?id=15096

---
 drivers/acpi/video.c |   31 +++++++++++++++++++++++--------
 1 files changed, 23 insertions(+), 8 deletions(-)
drivers/acpi/video.c +23 -8
index 2ff2b6a..fc2a690 100644
@@ -43,6 +43,7 @@
 #include <linux/dmi.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
+#include <linux/suspend.h>
 
 #define PREFIX "ACPI: "
 
@@ -88,7 +89,6 @@ module_param(allow_duplicates, bool, 0644);
 static int register_count = 0;
 static int acpi_video_bus_add(struct acpi_device *device);
 static int acpi_video_bus_remove(struct acpi_device *device, int type);
-static int acpi_video_resume(struct acpi_device *device);
 static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
 
 static const struct acpi_device_id video_device_ids[] = {
@@ -104,7 +104,6 @@ static struct acpi_driver acpi_video_bus = {
 	.ops = {
 		.add = acpi_video_bus_add,
 		.remove = acpi_video_bus_remove,
-		.resume = acpi_video_resume,
 		.notify = acpi_video_bus_notify,
 		},
 };
@@ -159,6 +158,7 @@ struct acpi_video_bus {
 	struct proc_dir_entry *dir;
 	struct input_dev *input;
 	char phys[32];	/* for input device */
+	struct notifier_block pm_nb;
 };
 
 struct acpi_video_device_flags {
@@ -2232,24 +2232,31 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
 	return;
 }
 
-static int instance;
-static int acpi_video_resume(struct acpi_device *device)
+static int acpi_video_resume(struct notifier_block *nb,
+				unsigned long val, void *ign)
 {
 	struct acpi_video_bus *video;
 	struct acpi_video_device *video_device;
 	int i;
 
-	if (!device || !acpi_driver_data(device))
-		return -EINVAL;
+	switch (val) {
+	case PM_HIBERNATION_PREPARE:
+	case PM_SUSPEND_PREPARE:
+	case PM_RESTORE_PREPARE:
+		return NOTIFY_DONE;
+	}
 
-	video = acpi_driver_data(device);
+	video = container_of(nb, struct acpi_video_bus, pm_nb);
+
+	dev_info(&video->device->dev, "Restoring backlight state\n");
 
 	for (i = 0; i < video->attached_count; i++) {
 		video_device = video->attached_array[i].bind_info;
 		if (video_device && video_device->backlight)
 			acpi_video_set_brightness(video_device->backlight);
 	}
-	return AE_OK;
+
+	return NOTIFY_OK;
 }
 
 static acpi_status
@@ -2273,6 +2280,8 @@ acpi_video_bus_match(acpi_handle handle, u32 level, void *context,
 	return AE_OK;
 }
 
+static int instance;
+
 static int acpi_video_bus_add(struct acpi_device *device)
 {
 	struct acpi_video_bus *video;
@@ -2366,6 +2375,10 @@ static int acpi_video_bus_add(struct acpi_device *device)
 	       video->flags.rom ? "yes" : "no",
 	       video->flags.post ? "yes" : "no");
 
+	video->pm_nb.notifier_call = acpi_video_resume;
+	video->pm_nb.priority = 0;
+	register_pm_notifier(&video->pm_nb);
+
 	return 0;
 
  err_free_input_dev:
@@ -2392,6 +2405,8 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type)
 
 	video = acpi_driver_data(device);
 
+	unregister_pm_notifier(&video->pm_nb);
+
 	acpi_video_bus_stop_devices(video);
 	acpi_video_bus_put_devices(video);
 	acpi_video_bus_remove_fs(device);
Signature · 6 lines
1.6.0.6

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#3 lore raw

Re: [PATCH 02/12] ACPI / PM: Move ACPI video resume to a PM notifier

Quoted 7 lines · Len Brown

From: Rafael Wysocki <[email protected]>

There is a problem with the ACPI video resume routine that it's executed before the GPU that may be accessed by it. To fix this issue, move the ACPI video resume to a power management notifier, so that it's executed after resuming all devices, including the GPU.

Quoted 6 lines

http://bugzilla.kernel.org/show_bug.cgi?id=15096

Thanks, but this requires the appended patch on top.

I sent a replacement version yesterday,
https://patchwork.kernel.org/patch/90593/, but you haven't received it, apparently.

Rafael

---
From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / video: Save initial backlight brightness in props

The initial backlight brightness has to be written to device->backlight->props in case it has to be restored before there's a chance to call acpi_video_device_lcd_set_level().

Something like this happens during boot, when the kernel checks if a hibernation image is present and executes power management notifiers (in either case). One of these notifiers tries to restore the previous brightness level, but this won't work if the initial brightness is not saved by acpi_video_device_find_cap().

---
 drivers/acpi/video.c |    7 +++++++
 1 file changed, 7 insertions(+)
drivers/acpi/video.c +7 -0
Index: linux-2.6/drivers/acpi/video.c
===================================================================
@@ -1020,6 +1020,13 @@ static void acpi_video_device_find_cap(s
 		if (IS_ERR(device->backlight))
 			return;
 
+		/*
+		 * Save current brightness level in case we have to restore it
+		 * before acpi_video_device_lcd_set_level() is called next time.
+		 */
+		device->backlight->props.brightness =
+				acpi_video_get_brightness(device->backlight);
+
 		result = sysfs_create_link(&device->backlight->dev.kobj,
 					   &device->dev->dev.kobj, "device");
 		if (result)

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

author reviewer
#4 lore raw

Re: [PATCH 02/12] ACPI / PM: Move ACPI video resume to a PM notifier

patch refreshed -- i'll send a new pull request now.

thanks,
Len Brown, Intel Open Source Technology Center

Quoted 65 lines · Rafael J. Wysocki
Quoted 7 lines · Len Brown

From: Rafael Wysocki <[email protected]>

There is a problem with the ACPI video resume routine that it's executed before the GPU that may be accessed by it. To fix this issue, move the ACPI video resume to a power management notifier, so that it's executed after resuming all devices, including the GPU.

Quoted 6 lines

http://bugzilla.kernel.org/show_bug.cgi?id=15096

Thanks, but this requires the appended patch on top.

I sent a replacement version yesterday,
https://patchwork.kernel.org/patch/90593/, but you haven't received it, apparently.

Rafael

---
From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / video: Save initial backlight brightness in props

The initial backlight brightness has to be written to device->backlight->props in case it has to be restored before there's a chance to call acpi_video_device_lcd_set_level().

Something like this happens during boot, when the kernel checks if a hibernation image is present and executes power management notifiers (in either case). One of these notifiers tries to restore the previous brightness level, but this won't work if the initial brightness is not saved by acpi_video_device_find_cap().

---
 drivers/acpi/video.c |    7 +++++++
 1 file changed, 7 insertions(+)

Index: linux-2.6/drivers/acpi/video.c
===================================================================

drivers/acpi/video.c +7 -1
@@ -1020,6 +1020,13 @@ static void acpi_video_device_find_cap(s
 		if (IS_ERR(device->backlight))
 			return;
 
+		/*
+		 * Save current brightness level in case we have to restore it
+		 * before acpi_video_device_lcd_set_level() is called next time.
+		 */
+		device->backlight->props.brightness =
+				acpi_video_get_brightness(device->backlight);
+
 		result = sysfs_create_link(&device->backlight->dev.kobj,
 					   &device->dev->dev.kobj, "device");
 		if (result)
--

To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

author reviewer
#5 lore raw

PATCH 3/12 ACPI dock: support multiple ACPI dock devices

In reply to Len Brown

From: Zhang Rui <[email protected]>

There may be multiple ACPI dock devices exist in ACPI namespace and we should probe all of them.
http://bugzilla.kernel.org/show_bug.cgi?id=15521

---
 drivers/acpi/dock.c |    7 ++-----
 1 files changed, 2 insertions(+), 5 deletions(-)
drivers/acpi/dock.c +2 -5
index d9a85f1..9d67bc6 100644
@@ -1025,13 +1025,10 @@ static int dock_remove(struct dock_station *ds)
 static acpi_status
 find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
-	acpi_status status = AE_OK;
-
 	if (is_dock(handle))
-		if (dock_add(handle) >= 0)
-			status = AE_CTRL_TERMINATE;
+		dock_add(handle);
 
-	return status;
+	return AE_OK;
 }
 
 static acpi_status
Signature · 1 line
1.6.0.6
author reviewer
#6 lore raw

PATCH 4/12 ACPI: fixes a false alarm from lockdep

In reply to Len Brown

From: Zhang Rui <[email protected]>

fixes a false alarm from lockdep, as acpi hotplug workqueue waits other workqueues.
http://bugzilla.kernel.org/show_bug.cgi?id=14553
https://bugzilla.kernel.org/show_bug.cgi?id=15521

Original-patch-from: Andrew Morton <[email protected]>

---
 drivers/acpi/osl.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)
drivers/acpi/osl.c +8 -1
index 8e6d866..900da68 100644
@@ -758,7 +758,14 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
 	queue = hp ? kacpi_hotplug_wq :
 		(type == OSL_NOTIFY_HANDLER ? kacpi_notify_wq : kacpid_wq);
 	dpc->wait = hp ? 1 : 0;
-	INIT_WORK(&dpc->work, acpi_os_execute_deferred);
+
+	if (queue == kacpi_hotplug_wq)
+		INIT_WORK(&dpc->work, acpi_os_execute_deferred);
+	else if (queue == kacpi_notify_wq)
+		INIT_WORK(&dpc->work, acpi_os_execute_deferred);
+	else
+		INIT_WORK(&dpc->work, acpi_os_execute_deferred);
+
 	ret = queue_work(queue, &dpc->work);
 
 	if (!ret) {
Signature · 1 line
1.6.0.6
author reviewer
#7 lore raw

PATCH 5/12 ACPI / ACPICA: Do not check reference counters in acpi_ev_enable_gpe()

In reply to Len Brown

From: Rafael J. Wysocki <[email protected]>

acpi_ev_enable_gpe() should enable the GPE at the hardware level regardless of the value of the GPE's runtime reference counter.

There are only two callers of acpi_ev_enable_gpe(), acpi_enable_gpe() and acpi_set_gpe(). The first one checks the GPE's runtime reference counter itself and only calls acpi_ev_enable_gpe() if it's equal to one, and the other one is supposed to enable the GPE unconditionally (if called with ACPI_GPE_ENABLE).

This change fixes the problem in acpi_enable_wakeup_device() where the GPE will not be enabled for wakeup if it's runtime reference counter is zero, which is a regression from 2.6.33.

---
 drivers/acpi/acpica/evgpe.c |   19 +++++++------------
 1 files changed, 7 insertions(+), 12 deletions(-)
drivers/acpi/acpica/evgpe.c +7 -12
index 837de66..78c5550 100644
@@ -117,19 +117,14 @@ acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
 	if (ACPI_FAILURE(status))
 		return_ACPI_STATUS(status);
 
-	/* Mark wake-enabled or HW enable, or both */
-
-	if (gpe_event_info->runtime_count) {
-		/* Clear the GPE (of stale events), then enable it */
-		status = acpi_hw_clear_gpe(gpe_event_info);
-		if (ACPI_FAILURE(status))
-			return_ACPI_STATUS(status);
-
-		/* Enable the requested runtime GPE */
-		status = acpi_hw_write_gpe_enable_reg(gpe_event_info);
-	}
+	/* Clear the GPE (of stale events), then enable it */
+	status = acpi_hw_clear_gpe(gpe_event_info);
+	if (ACPI_FAILURE(status))
+		return_ACPI_STATUS(status);
 
-	return_ACPI_STATUS(AE_OK);
+	/* Enable the requested GPE */
+	status = acpi_hw_write_gpe_enable_reg(gpe_event_info);
+	return_ACPI_STATUS(status);
 }
 
 /*******************************************************************************
Signature · 1 line
1.6.0.6
author reviewer
#8 lore raw

PATCH 6/12 ACPI: use _HID when supplied by root-level devices

In reply to Len Brown

From: Bjorn Helgaas <[email protected]>

Previously, we assumed the only Device object immediately below the root was the \_SB Scope (which the ACPI CA treats as a Device), so we forced the HID of all such objects to ACPI_BUS_HID ("LNXSYBUS").

However, there are DSDTs that supply root-level Device objects with _HIDs. This patch makes us pay attention to those _HIDs and only add the synthetic ACPI_BUS_HID for root-level objects that do not supply their own _HID.

For example, this DSDT: https://bugzilla.kernel.org/show_bug.cgi?id=15605
contains:

    Scope (_SB) {
	...
    }
    Device (AMW0) {
	Name (_HID, EisaId ("PNP0C14"))
	...
    }

and we should use "PNP0C14" for the AMW0 device, not "LNXSYBUS".

---
 drivers/acpi/scan.c |   12 ++++++------
 1 files changed, 6 insertions(+), 6 deletions(-)
drivers/acpi/scan.c +6 -6
index 189cbc2..95c90ff 100644
@@ -1080,12 +1080,6 @@ static void acpi_device_set_id(struct acpi_device *device)
 		if (ACPI_IS_ROOT_DEVICE(device)) {
 			acpi_add_id(device, ACPI_SYSTEM_HID);
 			break;
-		} else if (ACPI_IS_ROOT_DEVICE(device->parent)) {
-			/* \_SB_, the only root-level namespace device */
-			acpi_add_id(device, ACPI_BUS_HID);
-			strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
-			strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
-			break;
 		}
 
 		status = acpi_get_object_info(device->handle, &info);
@@ -1120,6 +1114,12 @@ static void acpi_device_set_id(struct acpi_device *device)
 			acpi_add_id(device, ACPI_DOCK_HID);
 		else if (!acpi_ibm_smbus_match(device))
 			acpi_add_id(device, ACPI_SMBUS_IBM_HID);
+		else if (!acpi_device_hid(device) &&
+			 ACPI_IS_ROOT_DEVICE(device->parent)) {
+			acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
+			strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
+			strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
+		}
 
 		break;
 	case ACPI_BUS_TYPE_POWER:
Signature · 1 line
1.6.0.6
author reviewer
#9 lore raw

PATCH 7/12 ACPI: NUMA: map pxms to low node ids

In reply to Len Brown

From: David Rientjes <[email protected]>

pxms are mapped to low node ids to maintain generic kernel use of functions such as pxm_to_node() that are used to determine device affinity. Otherwise, there is no pxm-to-node and node-to-pxm matching rule for x86_64 users of NUMA emulation where a single pxm may be bound to multiple NUMA nodes.

---
 drivers/acpi/numa.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
drivers/acpi/numa.c +4 -2
index b872546..b0337d3 100644
@@ -61,8 +61,10 @@ int node_to_pxm(int node)
 
 void __acpi_map_pxm_to_node(int pxm, int node)
 {
-	pxm_to_node_map[pxm] = node;
-	node_to_pxm_map[node] = pxm;
+	if (pxm_to_node_map[pxm] == NUMA_NO_NODE || node < pxm_to_node_map[pxm])
+		pxm_to_node_map[pxm] = node;
+	if (node_to_pxm_map[node] == PXM_INVAL || pxm < node_to_pxm_map[node])
+		node_to_pxm_map[node] = pxm;
 }
 
 int acpi_map_pxm_to_node(int pxm)
Signature · 1 line
1.6.0.6
author reviewer
#10 lore raw

PATCH 8/12 ACPI: Don't send KEY_UNKNOWN for random video notifications

In reply to Len Brown

From: Matthew Garrett <[email protected]>

I have a machine here that's sending 0xD1 notifications on the video device once every second or so. I have no idea why (it's a prototype, it may be broken), but sending KEY_UNKNOWN is unhelpful and results in the console becoming unusable. Let's not report keys unless we have something useful to say about them.

---
 drivers/acpi/video.c |   29 ++++++++++++++++-------------
 1 files changed, 16 insertions(+), 13 deletions(-)
drivers/acpi/video.c +16 -13
index cbe6f39..2c7ca7a 100644
@@ -2122,7 +2122,7 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event)
 {
 	struct acpi_video_bus *video = acpi_driver_data(device);
 	struct input_dev *input;
-	int keycode;
+	int keycode = 0;
 
 	if (!video)
 		return;
@@ -2158,17 +2158,19 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event)
 		break;
 
 	default:
-		keycode = KEY_UNKNOWN;
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Unsupported event [0x%x]\n", event));
 		break;
 	}
 
 	acpi_notifier_call_chain(device, event, 0);
-	input_report_key(input, keycode, 1);
-	input_sync(input);
-	input_report_key(input, keycode, 0);
-	input_sync(input);
+
+	if (keycode) {
+		input_report_key(input, keycode, 1);
+		input_sync(input);
+		input_report_key(input, keycode, 0);
+		input_sync(input);
+	}
 
 	return;
 }
@@ -2179,7 +2181,7 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
 	struct acpi_device *device = NULL;
 	struct acpi_video_bus *bus;
 	struct input_dev *input;
-	int keycode;
+	int keycode = 0;
 
 	if (!video_device)
 		return;
@@ -2220,17 +2222,19 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
 		keycode = KEY_DISPLAY_OFF;
 		break;
 	default:
-		keycode = KEY_UNKNOWN;
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Unsupported event [0x%x]\n", event));
 		break;
 	}
 
 	acpi_notifier_call_chain(device, event, 0);
-	input_report_key(input, keycode, 1);
-	input_sync(input);
-	input_report_key(input, keycode, 0);
-	input_sync(input);
+
+	if (keycode) {
+		input_report_key(input, keycode, 1);
+		input_sync(input);
+		input_report_key(input, keycode, 0);
+		input_sync(input);
+	}
 
 	return;
 }
@@ -2357,7 +2361,6 @@ static int acpi_video_bus_add(struct acpi_device *device)
 	set_bit(KEY_BRIGHTNESSDOWN, input->keybit);
 	set_bit(KEY_BRIGHTNESS_ZERO, input->keybit);
 	set_bit(KEY_DISPLAY_OFF, input->keybit);
-	set_bit(KEY_UNKNOWN, input->keybit);
 
 	error = input_register_device(input);
 	if (error)
Signature · 1 line
1.6.0.6
author reviewer
#11 lore raw

PATCH 9/12 PNPACPI: truncate _CRS windows with _LEN > _MAX - _MIN + 1

In reply to Len Brown

From: Bjorn Helgaas <[email protected]>

The ACPI spec (sec 6.4.3.5 in v4.0) requires that for Address Space Resource Descriptors, _LEN <= _MAX - _MIN + 1 in all cases, but there are BIOSes that violate this. We experimentally determined that Windows truncates the resource so it doesn't extend past _MAX, so let's do the same thing in Linux.

http://bugzilla.kernel.org/show_bug.cgi?id=15480

---
 drivers/pnp/pnpacpi/rsparser.c |   42 ++++++++++++++++++++++++++++-----------
 1 files changed, 30 insertions(+), 12 deletions(-)
drivers/pnp/pnpacpi/rsparser.c +30 -12
index 54514aa..fe5bfa9 100644
@@ -273,12 +273,33 @@ static void pnpacpi_parse_allocated_busresource(struct pnp_dev *dev,
 	pnp_add_bus_resource(dev, start, end);
 }
 
+static u64 addr_space_length(struct pnp_dev *dev, u64 min, u64 max, u64 len)
+{
+	u64 max_len;
+
+	max_len = max - min + 1;
+	if (len <= max_len)
+		return len;
+
+	/*
+	 * Per 6.4.3.5, _LEN cannot exceed _MAX - _MIN + 1, but some BIOSes
+	 * don't do this correctly, e.g.,
+	 * https://bugzilla.kernel.org/show_bug.cgi?id=15480
+	 */
+	dev_info(&dev->dev,
+	         "resource length %#llx doesn't fit in %#llx-%#llx, trimming\n",
+		 (unsigned long long) len, (unsigned long long) min,
+		 (unsigned long long) max);
+	return max_len;
+}
+
 static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev,
 						  struct acpi_resource *res)
 {
 	struct acpi_resource_address64 addr, *p = &addr;
 	acpi_status status;
 	int window;
+	u64 len;
 
 	status = acpi_resource_to_address64(res, p);
 	if (!ACPI_SUCCESS(status)) {
@@ -287,20 +308,18 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev,
 		return;
 	}
 
+	len = addr_space_length(dev, p->minimum, p->maximum, p->address_length);
 	window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
 
 	if (p->resource_type == ACPI_MEMORY_RANGE)
-		pnpacpi_parse_allocated_memresource(dev,
-			p->minimum, p->address_length,
+		pnpacpi_parse_allocated_memresource(dev, p->minimum, len,
 			p->info.mem.write_protect, window);
 	else if (p->resource_type == ACPI_IO_RANGE)
-		pnpacpi_parse_allocated_ioresource(dev,
-			p->minimum, p->address_length,
+		pnpacpi_parse_allocated_ioresource(dev, p->minimum, len,
 			p->granularity == 0xfff ? ACPI_DECODE_10 :
 				ACPI_DECODE_16, window);
 	else if (p->resource_type == ACPI_BUS_NUMBER_RANGE)
-		pnpacpi_parse_allocated_busresource(dev, p->minimum,
-						    p->address_length);
+		pnpacpi_parse_allocated_busresource(dev, p->minimum, len);
 }
 
 static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev,
@@ -308,21 +327,20 @@ static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev,
 {
 	struct acpi_resource_extended_address64 *p = &res->data.ext_address64;
 	int window;
+	u64 len;
 
+	len = addr_space_length(dev, p->minimum, p->maximum, p->address_length);
 	window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
 
 	if (p->resource_type == ACPI_MEMORY_RANGE)
-		pnpacpi_parse_allocated_memresource(dev,
-			p->minimum, p->address_length,
+		pnpacpi_parse_allocated_memresource(dev, p->minimum, len,
 			p->info.mem.write_protect, window);
 	else if (p->resource_type == ACPI_IO_RANGE)
-		pnpacpi_parse_allocated_ioresource(dev,
-			p->minimum, p->address_length,
+		pnpacpi_parse_allocated_ioresource(dev, p->minimum, len,
 			p->granularity == 0xfff ? ACPI_DECODE_10 :
 				ACPI_DECODE_16, window);
 	else if (p->resource_type == ACPI_BUS_NUMBER_RANGE)
-		pnpacpi_parse_allocated_busresource(dev, p->minimum,
-						    p->address_length);
+		pnpacpi_parse_allocated_busresource(dev, p->minimum, len);
 }
 
 static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
Signature · 1 line
1.6.0.6
author reviewer
#12 lore raw

PATCH 10/12 ACPI: battery: Fix CONFIG_ACPI_SYSFS_POWER=n

In reply to Len Brown

From: Alan Jenkins <[email protected]>

Disabling CONFIG_ACPI_SYSFS_POWER changes the behaviour of acpi_battery_update(). It will call acpi_battery_get_info() even if the battery is not present. I haven't noticed this causing any problem, but it does look like a bad idea.

---
 drivers/acpi/battery.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/acpi/battery.c +2 -2
index 75f39f2..52df994 100644
@@ -567,13 +567,13 @@ static int acpi_battery_update(struct acpi_battery *battery)
 	result = acpi_battery_get_status(battery);
 	if (result)
 		return result;
-#ifdef CONFIG_ACPI_SYSFS_POWER
 	if (!acpi_battery_present(battery)) {
+#ifdef CONFIG_ACPI_SYSFS_POWER
 		sysfs_remove_battery(battery);
+#endif
 		battery->update_time = 0;
 		return 0;
 	}
-#endif
 	if (!battery->update_time ||
 	    old_present != acpi_battery_present(battery)) {
 		result = acpi_battery_get_info(battery);
Signature · 1 line
1.6.0.6
author reviewer
#13 lore raw

PATCH 11/12 ACPI: battery drivers should call power_supply_changed()

In reply to Len Brown

From: Alan Jenkins <[email protected]>

Calling kobject_uevent() directly is a layering violation. In particular, it means we'll miss updating the generic LED trigger.

---
 drivers/acpi/battery.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/acpi/battery.c +1 -1
index 52df994..db78b6e 100644
@@ -879,7 +879,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event)
 #ifdef CONFIG_ACPI_SYSFS_POWER
 	/* acpi_battery_update could remove power_supply object */
 	if (battery->bat.dev)
-		kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE);
+		power_supply_changed(&battery->bat);
 #endif
 }
 
Signature · 1 line
1.6.0.6
author reviewer
#14 lore raw

PATCH 12/12 ACPI: Reduce ACPI resource conflict message to KERN_WARNING, printk cleanup

In reply to Len Brown

From: Chase Douglas <[email protected]>

By default, ACPI resource conflict messages are logged at level KERN_ERR. This is a rather high level for a message that is more a warning than an indication of a real kernel error. Also, KERN_ERR level messages can appear over some boot splash screens, and this message is not serious enough to warrant such treatment. Thus, the log level has been reduced to KERN_WARNING.

[lenb changed to KERN_WARNING rather than all the way to KERN_INFO]

Also, cleanup message to use %pR resource printing format.

---
 drivers/acpi/osl.c |   14 ++++----------
 1 files changed, 4 insertions(+), 10 deletions(-)
drivers/acpi/osl.c +4 -10
index 8e6d866..6e49f62 100644
@@ -1151,16 +1151,10 @@ int acpi_check_resource_conflict(const struct resource *res)
 
 	if (clash) {
 		if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) {
-			printk("%sACPI: %s resource %s [0x%llx-0x%llx]"
-			       " conflicts with ACPI region %s"
-			       " [0x%llx-0x%llx]\n",
-			       acpi_enforce_resources == ENFORCE_RESOURCES_LAX
-			       ? KERN_WARNING : KERN_ERR,
-			       ioport ? "I/O" : "Memory", res->name,
-			       (long long) res->start, (long long) res->end,
-			       res_list_elem->name,
-			       (long long) res_list_elem->start,
-			       (long long) res_list_elem->end);
+			printk(KERN_WARNING "ACPI: resource %s %pR"
+			       " conflicts with ACPI region %s %pR\n",
+			       res->name, res, res_list_elem->name,
+			       res_list_elem);
 			if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX)
 				printk(KERN_NOTICE "ACPI: This conflict may"
 				       " cause random problems and system"
Signature · 1 line
1.6.0.6