Skip to contentSkip to conversation

ACPI patches for 2.6.26

PATCH In review Len Brown 5 participants 54 messages Apr 29, 2008 – May 4, 2008

Subsystems (10)
Documentation x86 ACPI MIPS +6 more subsystems
lore
Share & tools
lore

Len Brown

author reviewer
#0 lore raw

Here is the current queue for 2.6.26.

It is available in the git tree:
git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git release

as well as a consolidated plain patch:
ftp://ftp.kernel.org/pub/linux/kernel/people/lenb/acpi/patches/release/2.6.25/acpi-release-20080321-2.6.25.diff.gz

I've excluded the ACPICA series and the PNP series from this patch-bomb, as you've recently seen them and they're unchanged since you did.

thanks,
-Len

author reviewer
#1 lore raw

PATCH 1/171 ACPI: crosslink ACPI and "real" device nodes

From: David Brownell <[email protected]>

Add cross-links between ACPI device and "real" devices in sysfs, exposing otherwise-hidden interrelationships between the various device nodes for ACPI stuff. As a representative example, one hardware device is exposed as two logical devices (PNP and ACPI):

.../pnp0/00:06/ .../LNXSYSTM:00/device:00/PNP0A03:00/device:15/PNP0B00:00/

The PNP device gets a "firmware_node" link pointing to the ACPI device, and is what a Linux device driver binds to. The ACPI device has instead a "physical_node" link pointing back to the PNP device. Other firmware frameworks, like OpenFirmware, could do the same thing to couple their firmware tables to the rest of the system.

(Based on a patch from Zhang Rui. This version is modified to not depend on the patch makig ACPI initialize driver model wakeup flags.)

---
 drivers/acpi/glue.c |   20 ++++++++++++++++++++
 1 files changed, 20 insertions(+), 0 deletions(-)
drivers/acpi/glue.c +20 -0
index eda0978..06f8634 100644
@@ -142,6 +142,7 @@ EXPORT_SYMBOL(acpi_get_physical_device);
 
 static int acpi_bind_one(struct device *dev, acpi_handle handle)
 {
+	struct acpi_device *acpi_dev;
 	acpi_status status;
 
 	if (dev->archdata.acpi_handle) {
@@ -157,6 +158,16 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
 	}
 	dev->archdata.acpi_handle = handle;
 
+	status = acpi_bus_get_device(handle, &acpi_dev);
+	if (!ACPI_FAILURE(status)) {
+		int ret;
+
+		ret = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,
+				"firmware_node");
+		ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
+				"physical_node");
+	}
+
 	return 0;
 }
 
@@ -165,8 +176,17 @@ static int acpi_unbind_one(struct device *dev)
 	if (!dev->archdata.acpi_handle)
 		return 0;
 	if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) {
+		struct acpi_device *acpi_dev;
+
 		/* acpi_get_physical_device increase refcnt by one */
 		put_device(dev);
+
+		if (!acpi_bus_get_device(dev->archdata.acpi_handle,
+					&acpi_dev)) {
+			sysfs_remove_link(&dev->kobj, "firmware_node");
+			sysfs_remove_link(&acpi_dev->dev.kobj, "physical_node");
+		}
+
 		acpi_detach_data(dev->archdata.acpi_handle,
 				 acpi_glue_data_handler);
 		dev->archdata.acpi_handle = NULL;
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#2 lore raw

PATCH 2/171 ACPI: EC: Restore udelay in poll mode

In reply to Len Brown

From: Alexey Starikovskiy <[email protected]>

This fixes keyboard event handling on some systems.

Note that this delay was thought unnecessary, and removed
from linux-2.6.20 with 50c1e1138cb94f6aca0f8555777edbcefe0324e2 'ACPI: ec: Drop udelay() from poll mode. Loop by reading status field instead.'

---
 drivers/acpi/ec.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
drivers/acpi/ec.c +2 -0
index 7222a18..828c752 100644
@@ -73,6 +73,7 @@ enum ec_event {
 
 #define ACPI_EC_DELAY		500	/* Wait 500ms max. during EC ops */
 #define ACPI_EC_UDELAY_GLK	1000	/* Wait 1ms max. to get global lock */
+#define ACPI_EC_UDELAY		100	/* Wait 100us before polling EC again */
 
 enum {
 	EC_FLAGS_WAIT_GPE = 0,		/* Don't check status until GPE arrives */
@@ -227,6 +228,7 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
 		while (time_before(jiffies, delay)) {
 			if (acpi_ec_check_status(ec, event))
 				goto end;
+			udelay(ACPI_EC_UDELAY);
 		}
 	}
 	pr_err(PREFIX "acpi_ec_wait timeout,"
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#3 lore raw

PATCH 3/171 ACPI: EC: Add poll timer

In reply to Len Brown

From: Alexey Starikovskiy <[email protected]>

If we can not use interrupt mode of EC for some reason, start polling EC for events periodically.

---
 drivers/acpi/ec.c |   43 +++++++++++++++++++++++++++++++++++++++----
 1 files changed, 39 insertions(+), 4 deletions(-)
drivers/acpi/ec.c +39 -4
index 828c752..63e0ac2 100644
@@ -84,6 +84,7 @@ enum {
 	EC_FLAGS_NO_WDATA_GPE,		/* Don't expect WDATA GPE event */
 	EC_FLAGS_WDATA,			/* Data is being written */
 	EC_FLAGS_NO_OBF1_GPE,		/* Don't expect GPE before read */
+	EC_FLAGS_RESCHEDULE_POLL	/* Re-schedule poll */
 };
 
 static int acpi_ec_remove(struct acpi_device *device, int type);
@@ -130,6 +131,7 @@ static struct acpi_ec {
 	struct mutex lock;
 	wait_queue_head_t wait;
 	struct list_head list;
+	struct delayed_work work;
 	u8 handlers_installed;
 } *boot_ec, *first_ec;
 
@@ -178,6 +180,20 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
 	return 0;
 }
 
+static void ec_schedule_ec_poll(struct acpi_ec *ec)
+{
+	if (test_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags))
+		schedule_delayed_work(&ec->work,
+				      msecs_to_jiffies(ACPI_EC_DELAY));
+}
+
+static void ec_switch_to_poll_mode(struct acpi_ec *ec)
+{
+	clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
+	acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
+	set_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
+}
+
 static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
 {
 	int ret = 0;
@@ -218,7 +234,8 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
 				if (printk_ratelimit())
 					pr_info(PREFIX "missing confirmations, "
 						"switch off interrupt mode.\n");
-				clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
+				ec_switch_to_poll_mode(ec);
+				ec_schedule_ec_poll(ec);
 			}
 			goto end;
 		}
@@ -529,28 +546,37 @@ static u32 acpi_ec_gpe_handler(void *data)
 {
 	acpi_status status = AE_OK;
 	struct acpi_ec *ec = data;
+	u8 state = acpi_ec_read_status(ec);
 
 	pr_debug(PREFIX "~~~> interrupt\n");
 	clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
 	if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
 		wake_up(&ec->wait);
 
-	if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) {
+	if (state & ACPI_EC_FLAG_SCI) {
 		if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
 			status = acpi_os_execute(OSL_EC_BURST_HANDLER,
 				acpi_ec_gpe_query, ec);
-	} else if (unlikely(!test_bit(EC_FLAGS_GPE_MODE, &ec->flags))) {
+	} else if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) &&
+		   in_interrupt()) {
 		/* this is non-query, must be confirmation */
 		if (printk_ratelimit())
 			pr_info(PREFIX "non-query interrupt received,"
 				" switching to interrupt mode\n");
 		set_bit(EC_FLAGS_GPE_MODE, &ec->flags);
+		clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
 	}
-
+	ec_schedule_ec_poll(ec);
 	return ACPI_SUCCESS(status) ?
 	    ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
 }
 
+static void do_ec_poll(struct work_struct *work)
+{
+	struct acpi_ec *ec = container_of(work, struct acpi_ec, work.work);
+	(void)acpi_ec_gpe_handler(ec);
+}
+
 /* --------------------------------------------------------------------------
                              Address Space Management
    -------------------------------------------------------------------------- */
@@ -711,6 +737,7 @@ static struct acpi_ec *make_acpi_ec(void)
 	mutex_init(&ec->lock);
 	init_waitqueue_head(&ec->wait);
 	INIT_LIST_HEAD(&ec->list);
+	INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll);
 	return ec;
 }
 
@@ -752,8 +779,15 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
 	return AE_CTRL_TERMINATE;
 }
 
+static void ec_poll_stop(struct acpi_ec *ec)
+{
+	clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
+	cancel_delayed_work(&ec->work);
+}
+
 static void ec_remove_handlers(struct acpi_ec *ec)
 {
+	ec_poll_stop(ec);
 	if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
 				ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
 		pr_err(PREFIX "failed to remove space handler\n");
@@ -899,6 +933,7 @@ static int acpi_ec_start(struct acpi_device *device)
 
 	/* EC is fully operational, allow queries */
 	clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+	ec_schedule_ec_poll(ec);
 	return ret;
 }
 
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#4 lore raw

PATCH 4/171 ACPI: EC: Improve debug output

In reply to Len Brown

From: Alexey Starikovskiy <[email protected]>

---
 drivers/acpi/ec.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)
drivers/acpi/ec.c +4 -4
index 63e0ac2..1a7949c 100644
@@ -248,9 +248,9 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
 			udelay(ACPI_EC_UDELAY);
 		}
 	}
-	pr_err(PREFIX "acpi_ec_wait timeout,"
-			       " status = %d, expect_event = %d\n",
-			       acpi_ec_read_status(ec), event);
+	pr_err(PREFIX "acpi_ec_wait timeout, status = 0x%2.2x, event = %s\n",
+		acpi_ec_read_status(ec),
+		(event == ACPI_EC_EVENT_OBF_1) ? "\"b0=1\"" : "\"b1=0\"");
 	ret = -ETIME;
       end:
 	clear_bit(EC_FLAGS_ADDRESS, &ec->flags);
@@ -264,8 +264,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
 {
 	int result = 0;
 	set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
-	acpi_ec_write_cmd(ec, command);
 	pr_debug(PREFIX "transaction start\n");
+	acpi_ec_write_cmd(ec, command);
 	for (; wdata_len > 0; --wdata_len) {
 		result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
 		if (result) {
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#5 lore raw

PATCH 5/171 ACPI: EC: Replace broken controller workarounds with poll mode.

In reply to Len Brown

From: Alexey Starikovskiy <[email protected]>

---
 drivers/acpi/ec.c |   61 ++++++++++------------------------------------------
 1 files changed, 12 insertions(+), 49 deletions(-)
drivers/acpi/ec.c +12 -49
index 1a7949c..7f07b68 100644
@@ -79,11 +79,7 @@ enum {
 	EC_FLAGS_WAIT_GPE = 0,		/* Don't check status until GPE arrives */
 	EC_FLAGS_QUERY_PENDING,		/* Query is pending */
 	EC_FLAGS_GPE_MODE,		/* Expect GPE to be sent for status change */
-	EC_FLAGS_NO_ADDRESS_GPE,	/* Expect GPE only for non-address event */
-	EC_FLAGS_ADDRESS,		/* Address is being written */
-	EC_FLAGS_NO_WDATA_GPE,		/* Don't expect WDATA GPE event */
-	EC_FLAGS_WDATA,			/* Data is being written */
-	EC_FLAGS_NO_OBF1_GPE,		/* Don't expect GPE before read */
+	EC_FLAGS_NO_GPE,		/* Don't use GPE mode */
 	EC_FLAGS_RESCHEDULE_POLL	/* Re-schedule poll */
 };
 
@@ -189,6 +185,7 @@ static void ec_schedule_ec_poll(struct acpi_ec *ec)
 
 static void ec_switch_to_poll_mode(struct acpi_ec *ec)
 {
+	set_bit(EC_FLAGS_NO_GPE, &ec->flags);
 	clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
 	acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
 	set_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
@@ -196,65 +193,34 @@ static void ec_switch_to_poll_mode(struct acpi_ec *ec)
 
 static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
 {
-	int ret = 0;
-
-	if (unlikely(event == ACPI_EC_EVENT_OBF_1 &&
-		     test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags)))
-		force_poll = 1;
-	if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) &&
-		     test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags)))
-		force_poll = 1;
-	if (unlikely(test_bit(EC_FLAGS_WDATA, &ec->flags) &&
-		     test_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags)))
-		force_poll = 1;
 	if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) &&
 	    likely(!force_poll)) {
 		if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event),
 				       msecs_to_jiffies(ACPI_EC_DELAY)))
-			goto end;
+			return 0;
 		clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
 		if (acpi_ec_check_status(ec, event)) {
-			if (event == ACPI_EC_EVENT_OBF_1) {
-				/* miss OBF_1 GPE, don't expect it */
-				pr_info(PREFIX "missing OBF confirmation, "
-					"don't expect it any longer.\n");
-				set_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags);
-			} else if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) {
-				/* miss address GPE, don't expect it anymore */
-				pr_info(PREFIX "missing address confirmation, "
-					"don't expect it any longer.\n");
-				set_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags);
-			} else if (test_bit(EC_FLAGS_WDATA, &ec->flags)) {
-				/* miss write data GPE, don't expect it */
-				pr_info(PREFIX "missing write data confirmation, "
-					"don't expect it any longer.\n");
-				set_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags);
-			} else {
-				/* missing GPEs, switch back to poll mode */
-				if (printk_ratelimit())
-					pr_info(PREFIX "missing confirmations, "
+			/* missing GPEs, switch back to poll mode */
+			if (printk_ratelimit())
+				pr_info(PREFIX "missing confirmations, "
 						"switch off interrupt mode.\n");
-				ec_switch_to_poll_mode(ec);
-				ec_schedule_ec_poll(ec);
-			}
-			goto end;
+			ec_switch_to_poll_mode(ec);
+			ec_schedule_ec_poll(ec);
+			return 0;
 		}
 	} else {
 		unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
 		clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
 		while (time_before(jiffies, delay)) {
 			if (acpi_ec_check_status(ec, event))
-				goto end;
+				return 0;
 			udelay(ACPI_EC_UDELAY);
 		}
 	}
 	pr_err(PREFIX "acpi_ec_wait timeout, status = 0x%2.2x, event = %s\n",
 		acpi_ec_read_status(ec),
 		(event == ACPI_EC_EVENT_OBF_1) ? "\"b0=1\"" : "\"b1=0\"");
-	ret = -ETIME;
-      end:
-	clear_bit(EC_FLAGS_ADDRESS, &ec->flags);
-	return ret;
+	return -ETIME;
 }
 
 static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
@@ -273,15 +239,11 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
 			       "write_cmd timeout, command = %d\n", command);
 			goto end;
 		}
-		/* mark the address byte written to EC */
-		if (rdata_len + wdata_len > 1)
-			set_bit(EC_FLAGS_ADDRESS, &ec->flags);
 		set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
 		acpi_ec_write_data(ec, *(wdata++));
 	}
 
 	if (!rdata_len) {
-		set_bit(EC_FLAGS_WDATA, &ec->flags);
 		result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
 		if (result) {
 			pr_err(PREFIX
@@ -558,6 +520,7 @@ static u32 acpi_ec_gpe_handler(void *data)
 			status = acpi_os_execute(OSL_EC_BURST_HANDLER,
 				acpi_ec_gpe_query, ec);
 	} else if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) &&
+		   !test_bit(EC_FLAGS_NO_GPE, &ec->flags) &&
 		   in_interrupt()) {
 		/* this is non-query, must be confirmation */
 		if (printk_ratelimit())
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#6 lore raw

PATCH 6/171 ACPI: EC: Switch off GPE mode during suspend/resume

In reply to Len Brown

From: Alexey Starikovskiy <[email protected]>

---
 drivers/acpi/ec.c |   60 +++++++++++++++++++++++++++++++++-------------------
 1 files changed, 38 insertions(+), 22 deletions(-)
drivers/acpi/ec.c +38 -22
index 7f07b68..da67d22 100644
@@ -83,28 +83,6 @@ enum {
 	EC_FLAGS_RESCHEDULE_POLL	/* Re-schedule poll */
 };
 
-static int acpi_ec_remove(struct acpi_device *device, int type);
-static int acpi_ec_start(struct acpi_device *device);
-static int acpi_ec_stop(struct acpi_device *device, int type);
-static int acpi_ec_add(struct acpi_device *device);
-
-static const struct acpi_device_id ec_device_ids[] = {
-	{"PNP0C09", 0},
-	{"", 0},
-};
-
-static struct acpi_driver acpi_ec_driver = {
-	.name = "ec",
-	.class = ACPI_EC_CLASS,
-	.ids = ec_device_ids,
-	.ops = {
-		.add = acpi_ec_add,
-		.remove = acpi_ec_remove,
-		.start = acpi_ec_start,
-		.stop = acpi_ec_stop,
-		},
-};
-
 /* If we find an EC via the ECDT, we need to keep a ptr to its context */
 /* External interfaces use first EC only, so remember */
 typedef int (*acpi_ec_query_func) (void *data);
@@ -924,6 +902,11 @@ int __init acpi_boot_ec_enable(void)
 	return -EFAULT;
 }
 
+static const struct acpi_device_id ec_device_ids[] = {
+	{"PNP0C09", 0},
+	{"", 0},
+};
+
 int __init acpi_ec_ecdt_probe(void)
 {
 	int ret;
@@ -973,6 +956,39 @@ int __init acpi_ec_ecdt_probe(void)
 	return -ENODEV;
 }
 
+static int acpi_ec_suspend(struct acpi_device *device, pm_message_t state)
+{
+	struct acpi_ec *ec = acpi_driver_data(device);
+	/* Stop using GPE */
+	set_bit(EC_FLAGS_NO_GPE, &ec->flags);
+	clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
+	acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
+	return 0;
+}
+
+static int acpi_ec_resume(struct acpi_device *device)
+{
+	struct acpi_ec *ec = acpi_driver_data(device);
+	/* Enable use of GPE back */
+	clear_bit(EC_FLAGS_NO_GPE, &ec->flags);
+	acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
+	return 0;
+}
+
+static struct acpi_driver acpi_ec_driver = {
+	.name = "ec",
+	.class = ACPI_EC_CLASS,
+	.ids = ec_device_ids,
+	.ops = {
+		.add = acpi_ec_add,
+		.remove = acpi_ec_remove,
+		.start = acpi_ec_start,
+		.stop = acpi_ec_stop,
+		.suspend = acpi_ec_suspend,
+		.resume = acpi_ec_resume,
+		},
+};
+
 static int __init acpi_ec_init(void)
 {
 	int result = 0;
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#7 lore raw

PATCH 7/171 ACPI: EC: Detect irq storm

In reply to Len Brown

From: Alexey Starikovskiy <[email protected]>

Problem seems to be that hw fails to clear GPE after we service it and write 1 into corresponding bit. Thus, as soon as we get interrupts enabled again, we receive a new one. Google gives too many results for "acer interrupt storm" for this being one-broken-machine case.

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

---
 drivers/acpi/ec.c |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)
drivers/acpi/ec.c +11 -0
index da67d22..f0e8216 100644
@@ -106,6 +106,7 @@ static struct acpi_ec {
 	wait_queue_head_t wait;
 	struct list_head list;
 	struct delayed_work work;
+	atomic_t irq_count;
 	u8 handlers_installed;
 } *boot_ec, *first_ec;
 
@@ -171,6 +172,7 @@ static void ec_switch_to_poll_mode(struct acpi_ec *ec)
 
 static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
 {
+	atomic_set(&ec->irq_count, 0);
 	if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) &&
 	    likely(!force_poll)) {
 		if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event),
@@ -489,6 +491,12 @@ static u32 acpi_ec_gpe_handler(void *data)
 	u8 state = acpi_ec_read_status(ec);
 
 	pr_debug(PREFIX "~~~> interrupt\n");
+	atomic_inc(&ec->irq_count);
+	if (atomic_read(&ec->irq_count) > 5) {
+		pr_err(PREFIX "GPE storm detected, disabling EC GPE\n");
+		ec_switch_to_poll_mode(ec);
+		goto end;
+	}
 	clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
 	if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
 		wake_up(&ec->wait);
@@ -507,6 +515,7 @@ static u32 acpi_ec_gpe_handler(void *data)
 		set_bit(EC_FLAGS_GPE_MODE, &ec->flags);
 		clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
 	}
+end:
 	ec_schedule_ec_poll(ec);
 	return ACPI_SUCCESS(status) ?
 	    ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
@@ -515,6 +524,7 @@ static u32 acpi_ec_gpe_handler(void *data)
 static void do_ec_poll(struct work_struct *work)
 {
 	struct acpi_ec *ec = container_of(work, struct acpi_ec, work.work);
+	atomic_set(&ec->irq_count, 0);
 	(void)acpi_ec_gpe_handler(ec);
 }
 
@@ -679,6 +689,7 @@ static struct acpi_ec *make_acpi_ec(void)
 	init_waitqueue_head(&ec->wait);
 	INIT_LIST_HEAD(&ec->list);
 	INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll);
+	atomic_set(&ec->irq_count, 0);
 	return ec;
 }
 
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#8 lore raw

PATCH 8/171 ACPI: EC: Use default setup handler

In reply to Len Brown

From: Alexey Starikovskiy <[email protected]>

---
 drivers/acpi/ec.c |   16 +---------------
 1 files changed, 1 insertions(+), 15 deletions(-)
drivers/acpi/ec.c +1 -15
index f0e8216..167af37 100644
@@ -533,20 +533,6 @@ static void do_ec_poll(struct work_struct *work)
    -------------------------------------------------------------------------- */
 
 static acpi_status
-acpi_ec_space_setup(acpi_handle region_handle,
-		    u32 function, void *handler_context, void **return_context)
-{
-	/*
-	 * The EC object is in the handler context and is needed
-	 * when calling the acpi_ec_space_handler.
-	 */
-	*return_context = (function != ACPI_REGION_DEACTIVATE) ?
-	    handler_context : NULL;
-
-	return AE_OK;
-}
-
-static acpi_status
 acpi_ec_space_handler(u32 function, acpi_physical_address address,
 		      u32 bits, acpi_integer *value,
 		      void *handler_context, void *region_context)
@@ -858,7 +844,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
 	status = acpi_install_address_space_handler(ec->handle,
 						    ACPI_ADR_SPACE_EC,
 						    &acpi_ec_space_handler,
-						    &acpi_ec_space_setup, ec);
+						    NULL, ec);
 	if (ACPI_FAILURE(status)) {
 		acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
 		return -ENODEV;
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#9 lore raw

PATCH 9/171 ACPI: EC: Don't delete boot EC

In reply to Len Brown

From: Alexey Starikovskiy <[email protected]>

---
 drivers/acpi/ec.c |   43 +++++++++++++++++++------------------------
 1 files changed, 19 insertions(+), 24 deletions(-)
drivers/acpi/ec.c +19 -24
index 167af37..3d93621 100644
@@ -708,9 +708,6 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
 	status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
 	if (ACPI_FAILURE(status))
 		return status;
-	/* Find and register all query methods */
-	acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1,
-			    acpi_ec_register_query_methods, ec, NULL);
 	/* Use the global lock for all EC transactions? */
 	acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
 	ec->handle = handle;
@@ -745,31 +742,28 @@ static int acpi_ec_add(struct acpi_device *device)
 	strcpy(acpi_device_class(device), ACPI_EC_CLASS);
 
 	/* Check for boot EC */
-	if (boot_ec) {
-		if (boot_ec->handle == device->handle) {
-			/* Pre-loaded EC from DSDT, just move pointer */
-			ec = boot_ec;
-			boot_ec = NULL;
-			goto end;
-		} else if (boot_ec->handle == ACPI_ROOT_OBJECT) {
-			/* ECDT-based EC, time to shut it down */
-			ec_remove_handlers(boot_ec);
-			kfree(boot_ec);
-			first_ec = boot_ec = NULL;
+	if (boot_ec &&
+	    (boot_ec->handle == device->handle ||
+	     boot_ec->handle == ACPI_ROOT_OBJECT)) {
+		ec = boot_ec;
+		boot_ec = NULL;
+	} else {
+		ec = make_acpi_ec();
+		if (!ec)
+			return -ENOMEM;
+		if (ec_parse_device(device->handle, 0, ec, NULL) !=
+		    AE_CTRL_TERMINATE) {
+			kfree(ec);
+			return -EINVAL;
 		}
 	}
 
-	ec = make_acpi_ec();
-	if (!ec)
-		return -ENOMEM;
-
-	if (ec_parse_device(device->handle, 0, ec, NULL) !=
-	    AE_CTRL_TERMINATE) {
-		kfree(ec);
-		return -EINVAL;
-	}
 	ec->handle = device->handle;
-      end:
+
+	/* Find and register all query methods */
+	acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
+			    acpi_ec_register_query_methods, ec, NULL);
+
 	if (!first_ec)
 		first_ec = ec;
 	acpi_driver_data(device) = ec;
@@ -924,6 +918,7 @@ int __init acpi_ec_ecdt_probe(void)
 		boot_ec->data_addr = ecdt_ptr->data.address;
 		boot_ec->gpe = ecdt_ptr->gpe;
 		boot_ec->handle = ACPI_ROOT_OBJECT;
+		acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle);
 	} else {
 		/* This workaround is needed only on some broken machines,
 		 * which require early EC, but fail to provide ECDT */
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#10 lore raw

PATCH 10/171 ACPI : Disable the device's ability to wake the sleeping system in the boot phase

In reply to Len Brown

From: Zhao Yakui <[email protected]>

In some machines some GPE is shared by several ACPI devices, for example:
sleep button, keyboard, mouse. At the same time one of them is non-wake(runtime) device and the other are wake devices. In such case OSPM should call the _PSW object to disable the device's ability to wake the sleeping system in the boot phase.
Otherwise there will be ACPI interrupt flood triggered by the GPE input.

The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW. So it is necessary to call _DSW object first. Only when it is not present will the _PSW object used.

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

---
 drivers/acpi/scan.c |   43 ++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 42 insertions(+), 1 deletions(-)
drivers/acpi/scan.c +42 -1
index e6ce262..bd32351 100644
@@ -692,6 +692,9 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
 	acpi_status status = 0;
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 	union acpi_object *package = NULL;
+	union acpi_object in_arg[3];
+	struct acpi_object_list arg_list = { 3, in_arg };
+	acpi_status psw_status = AE_OK;
 
 	struct acpi_device_id button_device_ids[] = {
 		{"PNP0C0D", 0},
@@ -700,7 +703,6 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
 		{"", 0},
 	};
 
-
 	/* _PRW */
 	status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
 	if (ACPI_FAILURE(status)) {
@@ -718,6 +720,45 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
 	kfree(buffer.pointer);
 
 	device->wakeup.flags.valid = 1;
+	/* Call _PSW/_DSW object to disable its ability to wake the sleeping
+	 * system for the ACPI device with the _PRW object.
+	 * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW.
+	 * So it is necessary to call _DSW object first. Only when it is not
+	 * present will the _PSW object used.
+	 */
+	/*
+	 * Three agruments are needed for the _DSW object.
+	 * Argument 0: enable/disable the wake capabilities
+	 * When _DSW object is called to disable the wake capabilities, maybe
+	 * the first argument is filled. The value of the other two agruments
+	 * is meaningless.
+	 */
+	in_arg[0].type = ACPI_TYPE_INTEGER;
+	in_arg[0].integer.value = 0;
+	in_arg[1].type = ACPI_TYPE_INTEGER;
+	in_arg[1].integer.value = 0;
+	in_arg[2].type = ACPI_TYPE_INTEGER;
+	in_arg[2].integer.value = 0;
+	psw_status = acpi_evaluate_object(device->handle, "_DSW",
+						&arg_list, NULL);
+	if (ACPI_FAILURE(psw_status) && (psw_status != AE_NOT_FOUND))
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in evaluate _DSW\n"));
+	/*
+	 * When the _DSW object is not present, OSPM will call _PSW object.
+	 */
+	if (psw_status == AE_NOT_FOUND) {
+		/*
+		 * Only one agruments is required for the _PSW object.
+		 * agrument 0: enable/disable the wake capabilities
+		 */
+		arg_list.count = 1;
+		in_arg[0].integer.value = 0;
+		psw_status = acpi_evaluate_object(device->handle, "_PSW",
+						&arg_list, NULL);
+		if (ACPI_FAILURE(psw_status) && (psw_status != AE_NOT_FOUND))
+			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in "
+						"evaluate _PSW\n"));
+	}
 	/* Power button, Lid switch always enable wakeup */
 	if (!acpi_match_device_ids(device, button_device_ids))
 		device->wakeup.flags.run_wake = 1;
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#11 lore raw

PATCH 11/171 #if 0 acpi/bay.c:eject_removable_drive()

In reply to Len Brown

From: Adrian Bunk <[email protected]>

This patch #if 0's the unused eject_removable_drive().

---
 drivers/acpi/bay.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
drivers/acpi/bay.c +2 -0
index 1fa8681..d2fc941 100644
@@ -201,6 +201,7 @@ static int is_ejectable_bay(acpi_handle handle)
 	return 0;
 }
 
+#if 0
 /**
  * eject_removable_drive - try to eject this drive
  * @dev : the device structure of the drive
@@ -225,6 +226,7 @@ int eject_removable_drive(struct device *dev)
 	return 0;
 }
 EXPORT_SYMBOL_GPL(eject_removable_drive);
+#endif  /*  0  */
 
 static int acpi_bay_add_fs(struct bay *bay)
 {
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#12 lore raw

PATCH 12/171 PM: Remove legacy PM

In reply to Len Brown

From: Pavel Machek <[email protected]>

AFAICT pm_send_all is a nop when noone uses pm_register...

Hmm.. can we just force CONFIG_PM_LEGACY=n, and see what happens?

Or maybe this is better idea? It may break build somewhere, but it should be easy to fix... (it builds here, i386 and x86-64).

---
 arch/frv/kernel/pm.c            |    8 --
 arch/mips/au1000/common/power.c |   17 +---
 arch/x86/kernel/apm_32.c        |   15 ---
 kernel/power/Kconfig            |   10 --
 kernel/power/Makefile           |    1 -
 kernel/power/pm.c               |  205 ---------------------------------------
 6 files changed, 2 insertions(+), 254 deletions(-)
 delete mode 100644 kernel/power/pm.c
arch/frv/kernel/pm.c +0 -8
index c57ce3f..73f3aee 100644
@@ -163,14 +163,11 @@ static int sysctl_pm_do_suspend(ctl_table *ctl, int write, struct file *filp,
 	if ((mode != 1) && (mode != 5))
 		return -EINVAL;
 
-	retval = pm_send_all(PM_SUSPEND, (void *)3);
-
 	if (retval == 0) {
 		if (mode == 5)
 		    retval = pm_do_bus_sleep();
 		else
 		    retval = pm_do_suspend();
-		pm_send_all(PM_RESUME, (void *)0);
 	}
 
 	return retval;
@@ -183,9 +180,6 @@ static int try_set_cmode(int new_cmode)
 	if (!(clock_cmodes_permitted & (1<<new_cmode)))
 		return -EINVAL;
 
-	/* tell all the drivers we're suspending */
-	pm_send_all(PM_SUSPEND, (void *)3);
-
 	/* now change cmode */
 	local_irq_disable();
 	frv_dma_pause_all();
@@ -201,8 +195,6 @@ static int try_set_cmode(int new_cmode)
 	frv_dma_resume_all();
 	local_irq_enable();
 
-	/* tell all the drivers we're resuming */
-	pm_send_all(PM_RESUME, (void *)0);
 	return 0;
 }
 
arch/mips/au1000/common/power.c +2 -15
index 54047d6..a9f7f63 100644
@@ -258,7 +258,6 @@ int au_sleep(void)
 static int pm_do_sleep(ctl_table * ctl, int write, struct file *file,
 		       void __user *buffer, size_t * len, loff_t *ppos)
 {
-	int retval = 0;
 #ifdef SLEEP_TEST_TIMEOUT
 #define TMPBUFLEN2 16
 	char buf[TMPBUFLEN2], *p;
@@ -278,33 +277,21 @@ static int pm_do_sleep(ctl_table * ctl, int write, struct file *file,
 		p = buf;
 		sleep_ticks = simple_strtoul(p, &p, 0);
 #endif
-		retval = pm_send_all(PM_SUSPEND, (void *) 2);
-
-		if (retval)
-			return retval;
 
 		au_sleep();
-		retval = pm_send_all(PM_RESUME, (void *) 0);
 	}
-	return retval;
+	return 0;
 }
 
 static int pm_do_suspend(ctl_table * ctl, int write, struct file *file,
 			 void __user *buffer, size_t * len, loff_t *ppos)
 {
-	int retval = 0;
-
 	if (!write) {
 		*len = 0;
 	} else {
-		retval = pm_send_all(PM_SUSPEND, (void *) 2);
-		if (retval)
-			return retval;
 		suspend_mode = 1;
-
-		retval = pm_send_all(PM_RESUME, (void *) 0);
 	}
-	return retval;
+	return 0;
 }
 
 
arch/x86/kernel/apm_32.c +0 -15
index d4438ef..d7e92bf 100644
@@ -1189,19 +1189,6 @@ static int suspend(int vetoable)
 	int err;
 	struct apm_user	*as;
 
-	if (pm_send_all(PM_SUSPEND, (void *)3)) {
-		/* Vetoed */
-		if (vetoable) {
-			if (apm_info.connection_version > 0x100)
-				set_system_power_state(APM_STATE_REJECT);
-			err = -EBUSY;
-			ignore_sys_suspend = 0;
-			printk(KERN_WARNING "apm: suspend was vetoed.\n");
-			goto out;
-		}
-		printk(KERN_CRIT "apm: suspend was vetoed, but suspending anyway.\n");
-	}
-
 	device_suspend(PMSG_SUSPEND);
 	local_irq_disable();
 	device_power_down(PMSG_SUSPEND);
@@ -1224,7 +1211,6 @@ static int suspend(int vetoable)
 	device_power_up();
 	local_irq_enable();
 	device_resume();
-	pm_send_all(PM_RESUME, (void *)0);
 	queue_event(APM_NORMAL_RESUME, NULL);
  out:
 	spin_lock(&user_list_lock);
@@ -1337,7 +1323,6 @@ static void check_events(void)
 			if ((event != APM_NORMAL_RESUME)
 			    || (ignore_normal_resume == 0)) {
 				device_resume();
-				pm_send_all(PM_RESUME, (void *)0);
 				queue_event(event, NULL);
 			}
 			ignore_normal_resume = 0;
kernel/power/Kconfig +0 -10
index 6233f3b..b45da40 100644
@@ -19,16 +19,6 @@ config PM
 	  will issue the hlt instruction if nothing is to be done, thereby
 	  sending the processor to sleep and saving power.
 
-config PM_LEGACY
-	bool "Legacy Power Management API (DEPRECATED)"
-	depends on PM
-	default n
-	---help---
-	   Support for pm_register() and friends.  This old API is obsoleted
-	   by the driver model.
-
-	   If unsure, say N.
-
 config PM_DEBUG
 	bool "Power Management Debug Support"
 	depends on PM
kernel/power/Makefile +0 -1
index f7dfff2..597823b 100644
@@ -4,7 +4,6 @@ EXTRA_CFLAGS	+=	-DDEBUG
 endif
 
 obj-y				:= main.o
-obj-$(CONFIG_PM_LEGACY)		+= pm.o
 obj-$(CONFIG_PM_SLEEP)		+= process.o console.o
 obj-$(CONFIG_HIBERNATION)	+= swsusp.o disk.o snapshot.o swap.o user.o
 
kernel/power/pm.c deleted +0 -205

205 lines not on this page · raw message

Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#13 lore raw

PATCH 13/171 PM: arch/x86/kernel/apm_32.c: fix build warning

In reply to Len Brown

From: Andrew Morton <[email protected]>

arch/x86/kernel/apm_32.c:1215: warning: label 'out' defined but not used

---
 arch/x86/kernel/apm_32.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)
arch/x86/kernel/apm_32.c +0 -1
index d7e92bf..bc8b57d 100644
@@ -1212,7 +1212,6 @@ static int suspend(int vetoable)
 	local_irq_enable();
 	device_resume();
 	queue_event(APM_NORMAL_RESUME, NULL);
- out:
 	spin_lock(&user_list_lock);
 	for (as = user_list; as != NULL; as = as->next) {
 		as->suspend_wait = 0;
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#14 lore raw

PATCH 14/171 MIPS Alchemy: Crapectomy after removal of pm_send_all calls.

In reply to Len Brown

From: Ralf Baechle <[email protected]>

---
 arch/mips/au1000/common/power.c |   20 --------------------
 1 files changed, 0 insertions(+), 20 deletions(-)
arch/mips/au1000/common/power.c +0 -20
index a9f7f63..725a52f 100644
@@ -283,18 +283,6 @@ static int pm_do_sleep(ctl_table * ctl, int write, struct file *file,
 	return 0;
 }
 
-static int pm_do_suspend(ctl_table * ctl, int write, struct file *file,
-			 void __user *buffer, size_t * len, loff_t *ppos)
-{
-	if (!write) {
-		*len = 0;
-	} else {
-		suspend_mode = 1;
-	}
-	return 0;
-}
-
-
 static int pm_do_freq(ctl_table * ctl, int write, struct file *file,
 		      void __user *buffer, size_t * len, loff_t *ppos)
 {
@@ -408,14 +396,6 @@ static int pm_do_freq(ctl_table * ctl, int write, struct file *file,
 
 static struct ctl_table pm_table[] = {
 	{
-		.ctl_name 	= CTL_UNNUMBERED,
-		.procname	= "suspend",
-		.data		= NULL,
-		.maxlen		= 0,
-		.mode		= 0600,
-		.proc_handler	= &pm_do_suspend
-	},
-	{
 		.ctl_name	= CTL_UNNUMBERED,
 		.procname	= "sleep",
 		.data		= NULL,
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#15 lore raw

PATCH 85/171 eeepc-laptop: add base driver

In reply to Len Brown

From: Eric Cooper <[email protected]>

This patch is based on Eric Cooper's work to clean the original asus_acpi given by Asus. It's a platform driver (/sys/devices/platform/eeepc/) wich support:
- hotkeys - wlan on/off - camera on/off - cardr on/off

---
 drivers/misc/Kconfig        |   11 +
 drivers/misc/Makefile       |    3 +-
 drivers/misc/eeepc-laptop.c |  442 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 455 insertions(+), 1 deletions(-)
 create mode 100644 drivers/misc/eeepc-laptop.c
drivers/misc/Kconfig +11 -0
index 962817e..10c5ecf 100644
@@ -327,4 +327,15 @@ config ENCLOSURE_SERVICES
 	  driver (SCSI/ATA) which supports enclosures
 	  or a SCSI enclosure device (SES) to use these services.
 
+config EEEPC_LAPTOP
+	tristate "Eee PC Hotkey Driver (EXPERIMENTAL)"
+	depends on X86
+	depends on ACPI
+	depends on EXPERIMENTAL
+	---help---
+	  This driver supports the Fn-Fx keys on Eee PC laptops.
+	  It also adds the ability to switch camera/wlan on/off.
+
+	  If you have an Eee PC laptop, say Y or M here.
+
 endif # MISC_DEVICES
drivers/misc/Makefile +2 -1
index 3b12f5d..ef53a92 100644
@@ -7,7 +7,8 @@ obj-$(CONFIG_IBM_ASM)		+= ibmasm/
 obj-$(CONFIG_HDPU_FEATURES)	+= hdpuftrs/
 obj-$(CONFIG_MSI_LAPTOP)     += msi-laptop.o
 obj-$(CONFIG_ACER_WMI)     += acer-wmi.o
-obj-$(CONFIG_ASUS_LAPTOP)     += asus-laptop.o
+obj-$(CONFIG_ASUS_LAPTOP)	+= asus-laptop.o
+obj-$(CONFIG_EEEPC_LAPTOP)	+= eeepc-laptop.o
 obj-$(CONFIG_ATMEL_PWM)		+= atmel_pwm.o
 obj-$(CONFIG_ATMEL_SSC)		+= atmel-ssc.o
 obj-$(CONFIG_TC1100_WMI)	+= tc1100-wmi.o
drivers/misc/eeepc-laptop.c new file +442 -0

442 lines not on this page · raw message

Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#16 lore raw

PATCH 86/171 eeepc-laptop: add backlight

In reply to Len Brown

From: Corentin Chary <[email protected]>

Add backlight class support to the eeepc-laptop driver.

---
 drivers/misc/Kconfig        |    1 +
 drivers/misc/eeepc-laptop.c |   77 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 78 insertions(+), 0 deletions(-)
drivers/misc/Kconfig +1 -0
index 10c5ecf..e9ab291 100644
@@ -331,6 +331,7 @@ config EEEPC_LAPTOP
 	tristate "Eee PC Hotkey Driver (EXPERIMENTAL)"
 	depends on X86
 	depends on ACPI
+	depends on BACKLIGHT_CLASS_DEVICE
 	depends on EXPERIMENTAL
 	---help---
 	  This driver supports the Fn-Fx keys on Eee PC laptops.
drivers/misc/eeepc-laptop.c +77 -0

139 lines not on this page · raw message

Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#17 lore raw

PATCH 87/171 eeepc-laptop: add hwmon fan control

In reply to Len Brown

From: Corentin Chary <[email protected]>

Adds an hwmon interface to control the fan.

---
 drivers/misc/Kconfig        |    1 +
 drivers/misc/eeepc-laptop.c |  147 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 148 insertions(+), 0 deletions(-)
drivers/misc/Kconfig +1 -0
index e9ab291..7547523 100644
@@ -332,6 +332,7 @@ config EEEPC_LAPTOP
 	depends on X86
 	depends on ACPI
 	depends on BACKLIGHT_CLASS_DEVICE
+	depends on HWMON
 	depends on EXPERIMENTAL
 	---help---
 	  This driver supports the Fn-Fx keys on Eee PC laptops.
drivers/misc/eeepc-laptop.c +147 -0

198 lines not on this page · raw message

Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#18 lore raw

PATCH 88/171 eeepc-laptop: MAINTAINERS entry

In reply to Len Brown

From: Corentin CHARY <[email protected]>

---
 MAINTAINERS |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)
MAINTAINERS +7 -0
index e467758..3d9886d 100644
@@ -1523,6 +1523,13 @@ L:	[email protected]
 W:	bluesmoke.sourceforge.net
 S:	Maintained
 
+EEEPC LAPTOP EXTRAS DRIVER
+P:	Corentin Chary
+M:	[email protected]
+L:	[email protected]
+W:	http://sourceforge.net/projects/acpi4asus
+S:	Maintained
+
 EEPRO100 NETWORK DRIVER
 P:	Andrey V. Savochkin
 M:	[email protected]
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#19 lore raw

PATCH 89/171 ACPI: re-name acpi_pm_ops to acpi_suspend_ops

In reply to Len Brown

From: Len Brown <[email protected]>

... as they are platform_suspend_ops after all.

cosmetic re-name only, no functional change.

---
 drivers/acpi/sleep/main.c |   42 +++++++++++++++++++++---------------------
 1 files changed, 21 insertions(+), 21 deletions(-)
drivers/acpi/sleep/main.c +21 -21
index 71183ee..c3b0cd8 100644
@@ -51,7 +51,7 @@ static int acpi_sleep_prepare(u32 acpi_state)
 }
 
 #ifdef CONFIG_SUSPEND
-static struct platform_suspend_ops acpi_pm_ops;
+static struct platform_suspend_ops acpi_suspend_ops;
 
 extern void do_suspend_lowlevel(void);
 
@@ -65,11 +65,11 @@ static u32 acpi_suspend_states[] = {
 static int init_8259A_after_S1;
 
 /**
- *	acpi_pm_begin - Set the target system sleep state to the state
+ *	acpi_suspend_begin - Set the target system sleep state to the state
  *		associated with given @pm_state, if supported.
  */
 
-static int acpi_pm_begin(suspend_state_t pm_state)
+static int acpi_suspend_begin(suspend_state_t pm_state)
 {
 	u32 acpi_state = acpi_suspend_states[pm_state];
 	int error = 0;
@@ -85,13 +85,13 @@ static int acpi_pm_begin(suspend_state_t pm_state)
 }
 
 /**
- *	acpi_pm_prepare - Do preliminary suspend work.
+ *	acpi_suspend_prepare - Do preliminary suspend work.
  *
  *	If necessary, set the firmware waking vector and do arch-specific
  *	nastiness to get the wakeup code to the waking vector.
  */
 
-static int acpi_pm_prepare(void)
+static int acpi_suspend_prepare(void)
 {
 	int error = acpi_sleep_prepare(acpi_target_sleep_state);
 
@@ -104,7 +104,7 @@ static int acpi_pm_prepare(void)
 }
 
 /**
- *	acpi_pm_enter - Actually enter a sleep state.
+ *	acpi_suspend_enter - Actually enter a sleep state.
  *	@pm_state: ignored
  *
  *	Flush caches and go to sleep. For STR we have to call arch-specific
@@ -112,7 +112,7 @@ static int acpi_pm_prepare(void)
  *	It's unfortunate, but it works. Please fix if you're feeling frisky.
  */
 
-static int acpi_pm_enter(suspend_state_t pm_state)
+static int acpi_suspend_enter(suspend_state_t pm_state)
 {
 	acpi_status status = AE_OK;
 	unsigned long flags = 0;
@@ -169,13 +169,13 @@ static int acpi_pm_enter(suspend_state_t pm_state)
 }
 
 /**
- *	acpi_pm_finish - Instruct the platform to leave a sleep state.
+ *	acpi_suspend_finish - Instruct the platform to leave a sleep state.
  *
  *	This is called after we wake back up (or if entering the sleep state
  *	failed). 
  */
 
-static void acpi_pm_finish(void)
+static void acpi_suspend_finish(void)
 {
 	u32 acpi_state = acpi_target_sleep_state;
 
@@ -196,19 +196,19 @@ static void acpi_pm_finish(void)
 }
 
 /**
- *	acpi_pm_end - Finish up suspend sequence.
+ *	acpi_suspend_end - Finish up suspend sequence.
  */
 
-static void acpi_pm_end(void)
+static void acpi_suspend_end(void)
 {
 	/*
-	 * This is necessary in case acpi_pm_finish() is not called during a
+	 * This is necessary in case acpi_suspend_finish() is not called during a
 	 * failing transition to a sleep state.
 	 */
 	acpi_target_sleep_state = ACPI_STATE_S0;
 }
 
-static int acpi_pm_state_valid(suspend_state_t pm_state)
+static int acpi_suspend_state_valid(suspend_state_t pm_state)
 {
 	u32 acpi_state;
 
@@ -224,13 +224,13 @@ static int acpi_pm_state_valid(suspend_state_t pm_state)
 	}
 }
 
-static struct platform_suspend_ops acpi_pm_ops = {
-	.valid = acpi_pm_state_valid,
-	.begin = acpi_pm_begin,
-	.prepare = acpi_pm_prepare,
-	.enter = acpi_pm_enter,
-	.finish = acpi_pm_finish,
-	.end = acpi_pm_end,
+static struct platform_suspend_ops acpi_suspend_ops = {
+	.valid = acpi_suspend_state_valid,
+	.begin = acpi_suspend_begin,
+	.prepare = acpi_suspend_prepare,
+	.enter = acpi_suspend_enter,
+	.finish = acpi_suspend_finish,
+	.end = acpi_suspend_end,
 };
 
 /*
@@ -492,7 +492,7 @@ int __init acpi_sleep_init(void)
 		}
 	}
 
-	suspend_set_ops(&acpi_pm_ops);
+	suspend_set_ops(&acpi_suspend_ops);
 #endif
 
 #ifdef CONFIG_HIBERNATION
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#20 lore raw

PATCH 91/171 ACPI: GPE enabling should happen after EC installation

In reply to Len Brown

From: Alexey Starikovskiy <[email protected]>

GPE could try to access EC region, so should not be enabled before EC is installed

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

---
 drivers/acpi/utilities/utxface.c |   35 +++++++++++++++++------------------
 1 files changed, 17 insertions(+), 18 deletions(-)
drivers/acpi/utilities/utxface.c +17 -18
index 2d49691..df41312 100644
@@ -192,24 +192,6 @@ acpi_status acpi_enable_subsystem(u32 flags)
 		}
 	}
 
-	/*
-	 * Complete the GPE initialization for the GPE blocks defined in the FADT
-	 * (GPE block 0 and 1).
-	 *
-	 * Note1: This is where the _PRW methods are executed for the GPEs. These
-	 * methods can only be executed after the SCI and Global Lock handlers are
-	 * installed and initialized.
-	 *
-	 * Note2: Currently, there seems to be no need to run the _REG methods
-	 * before execution of the _PRW methods and enabling of the GPEs.
-	 */
-	if (!(flags & ACPI_NO_EVENT_INIT)) {
-		status = acpi_ev_install_fadt_gpes();
-		if (ACPI_FAILURE(status)) {
-			return (status);
-		}
-	}
-
 	return_ACPI_STATUS(status);
 }
 
@@ -280,6 +262,23 @@ acpi_status acpi_initialize_objects(u32 flags)
 	}
 
 	/*
+	 * Complete the GPE initialization for the GPE blocks defined in the FADT
+	 * (GPE block 0 and 1).
+	 *
+	 * Note1: This is where the _PRW methods are executed for the GPEs. These
+	 * methods can only be executed after the SCI and Global Lock handlers are
+	 * installed and initialized.
+	 *
+	 * Note2: Currently, there seems to be no need to run the _REG methods
+	 * before execution of the _PRW methods and enabling of the GPEs.
+	 */
+	if (!(flags & ACPI_NO_EVENT_INIT)) {
+		status = acpi_ev_install_fadt_gpes();
+		if (ACPI_FAILURE(status))
+			return (status);
+	}
+
+	/*
 	 * Empty the caches (delete the cached objects) on the assumption that
 	 * the table load filled them up more than they will be at runtime --
 	 * thus wasting non-paged memory.
Signature · 1 line
1.5.5.1.99.gf0ec4
#21 lore raw

Re: [PATCH 091/171] ACPI: GPE enabling should happen after EC installation

Quoted 4 lines · Len Brown

From: Alexey Starikovskiy <[email protected]>

GPE could try to access EC region, so should not be enabled before EC is installed

It is caused by broken bios if GPE method tries to access EC region before EC is initialized correctly. It is more appropriate to fix this issue by upgrading bios rather than by the patch.
And this patch will cause some potential problems.

In the course of GPE event initialization the GPE will be set as RUN_TIME and deferred to be enabled.(Only update the GPE enable mask and not write the GPE register). And when the acpi_ev_install_fadt_gpes is called, some GPEs will be changed from the RUN_TIME to WAKEUP and only RUNTIME GPEs are enabled.(GPE register will be accessed).

If acpi_ev_install_fadt_gpe is called after EC is stalled, the acpi_enable_gpe will be called , in which some GPEs will be also enabled. In fact these are the WAKUP GPEs and shouldn't be enabled. Maybe this will bring some potential problems.

Best regards.
Yakui

Quoted 61 lines

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

---
 drivers/acpi/utilities/utxface.c |   35 +++++++++++++++++------------------
 1 files changed, 17 insertions(+), 18 deletions(-)
drivers/acpi/utilities/utxface.c +17 -18
index 2d49691..df41312 100644
@@ -192,24 +192,6 @@ acpi_status acpi_enable_subsystem(u32 flags)
 		}
 	}
 
-	/*
-	 * Complete the GPE initialization for the GPE blocks defined in the FADT
-	 * (GPE block 0 and 1).
-	 *
-	 * Note1: This is where the _PRW methods are executed for the GPEs. These
-	 * methods can only be executed after the SCI and Global Lock handlers are
-	 * installed and initialized.
-	 *
-	 * Note2: Currently, there seems to be no need to run the _REG methods
-	 * before execution of the _PRW methods and enabling of the GPEs.
-	 */
-	if (!(flags & ACPI_NO_EVENT_INIT)) {
-		status = acpi_ev_install_fadt_gpes();
-		if (ACPI_FAILURE(status)) {
-			return (status);
-		}
-	}
-
 	return_ACPI_STATUS(status);
 }
 
@@ -280,6 +262,23 @@ acpi_status acpi_initialize_objects(u32 flags)
 	}
 
 	/*
+	 * Complete the GPE initialization for the GPE blocks defined in the FADT
+	 * (GPE block 0 and 1).
+	 *
+	 * Note1: This is where the _PRW methods are executed for the GPEs. These
+	 * methods can only be executed after the SCI and Global Lock handlers are
+	 * installed and initialized.
+	 *
+	 * Note2: Currently, there seems to be no need to run the _REG methods
+	 * before execution of the _PRW methods and enabling of the GPEs.
+	 */
+	if (!(flags & ACPI_NO_EVENT_INIT)) {
+		status = acpi_ev_install_fadt_gpes();
+		if (ACPI_FAILURE(status))
+			return (status);
+	}
+
+	/*
 	 * Empty the caches (delete the cached objects) on the assumption that
 	 * the table load filled them up more than they will be at runtime --
 	 * thus wasting non-paged memory.
#22 lore raw

Re: [PATCH 091/171] ACPI: GPE enabling should happen after EC installation

Quoted 10 lines · On Wednesday 30 April 2008 11:25:34 Zhao Yakui wrote:
Quoted 4 lines · Len Brown

From: Alexey Starikovskiy <[email protected]>

GPE could try to access EC region, so should not be enabled before EC is installed

It is caused by broken bios if GPE method tries to access EC region before EC is initialized correctly. It is more appropriate to fix this issue by upgrading bios rather than by the patch.
And this patch will cause some potential problems.

1) Does the BIOS in question work under Windows?
2) Does the system in question require a BIOS upgrade under Windows for this issue?

If the answer to both of those is 'no', then the answer is that it's a Linux bug, and a patch of some description is appropriate.

Just because there are crappy BIOS's out there, and we'd rather not put in nasty fixes, doesn't mean that we shouldn't.

-Carlos

Signature · 3 lines
E-Mail: [email protected]
Web: strangeworlds.co.uk
GPG Key ID: 0x23EE722D
#23 lore raw

Re: [PATCH 091/171] ACPI: GPE enabling should happen after EC installation

Quoted 7 lines · On Wednesday 30 April 2008 07:58:53 Carlos Corbacho wrote:
Quoted 6 lines · On Wednesday 30 April 2008 11:25:34 Zhao Yakui wrote:
Quoted 4 lines · Len Brown

From: Alexey Starikovskiy <[email protected]>

GPE could try to access EC region, so should not be enabled before EC is installed

Quoted 6 lines
Quoted 4 lines

It is caused by broken bios if GPE method tries to access EC region before EC is initialized correctly. It is more appropriate to fix this issue by upgrading bios rather than by the patch.
And this patch will cause some potential problems.

1) Does the BIOS in question work under Windows?

^^^
that should be 'not work'

Quoted 8 lines

2) Does the system in question require a BIOS upgrade under Windows for this issue?

If the answer to both of those is 'no', then the answer is that it's a Linux bug, and a patch of some description is appropriate.

Just because there are crappy BIOS's out there, and we'd rather not put in nasty fixes, doesn't mean that we shouldn't.

-Carlos

Signature · 3 lines
E-Mail: [email protected]
Web: strangeworlds.co.uk
GPG Key ID: 0x23EE722D
#24 lore raw

Re: [PATCH 091/171] ACPI: GPE enabling should happen after EC installation

Quoted 13 lines · Carlos Corbacho
Quoted 12 lines · On Wednesday 30 April 2008 07:58:53 Carlos Corbacho wrote:
Quoted 10 lines · On Wednesday 30 April 2008 11:25:34 Zhao Yakui wrote:
Quoted 4 lines · Len Brown

From: Alexey Starikovskiy <[email protected]>

GPE could try to access EC region, so should not be enabled before EC is installed

It is caused by broken bios if GPE method tries to access EC region before EC is initialized correctly. It is more appropriate to fix this issue by upgrading bios rather than by the patch.
And this patch will cause some potential problems.

Quoted 4 lines
Quoted 1 line

1) Does the BIOS in question work under Windows?

^^^
that should be 'not work'

For the laptop in bug 9916:
Windows can work on the BIOS in question. In fact only warning message is printed for Linux and it won't break anything. (Maybe the warning message also exists on windows. But we can't see them.)

Quoted 4 lines
Quoted 4 lines

2) Does the system in question require a BIOS upgrade under Windows for this issue?

After the BIOS is upgraded, the warning message disappears on Linux. It is very lucky that we have such a laptop. After the bios is upgraded, the warning message disappears.

Quoted 8 lines
Quoted 5 lines

If the answer to both of those is 'no', then the answer is that it's a Linux bug, and a patch of some description is appropriate.

Just because there are crappy BIOS's out there, and we'd rather not put in nasty fixes, doesn't mean that we shouldn't.

-Carlos

#25 lore raw

Re: [PATCH 091/171] ACPI: GPE enabling should happen after EC installation

Quoted 12 lines · Zhao Yakui
Quoted 11 lines · Carlos Corbacho
Quoted 10 lines · On Wednesday 30 April 2008 07:58:53 Carlos Corbacho wrote:
Quoted 9 lines · On Wednesday 30 April 2008 11:25:34 Zhao Yakui wrote:
Quoted 4 lines · Len Brown

From: Alexey Starikovskiy <[email protected]>

GPE could try to access EC region, so should not be enabled before EC is installed

It is caused by broken bios if GPE method tries to access EC region before EC is initialized correctly. It is more appropriate to fix this issue by upgrading bios rather than by the patch.
And this patch will cause some potential problems.

Quoted 7 lines
Quoted 3 lines
Quoted 1 line

1) Does the BIOS in question work under Windows?

^^^
that should be 'not work'

For the laptop in bug 9916:
Windows can work on the BIOS in question. In fact only warning message is printed for Linux and it won't break anything. (Maybe the warning message also exists on windows. But we can't see them.)

This is generally a stupid idea to enable interrupt before you have handler for it ready, even if you are able to _survive_ unhandled interrupt.

Your other issue about WAKE GPEs, which could be wrongly enabled, could be solved by moving WAKE GPE init closer to RUNTIME GPE one:

Regards,
Alex.

drivers/acpi/events/evgpeblk.c +0 -0
index 361ebe6..37c68ae 100644
@@ -940,6 +940,27 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
					acpi_ev_save_method_info, gpe_block,
					NULL);

+ /*
+ * Runtime option: Should wake GPEs be enabled at runtime? The default
+ * is no, they should only be enabled just as the machine goes to sleep.
+ */
+ if (acpi_gbl_leave_wake_gpes_disabled) {
+ /*
+ * Differentiate runtime vs wake GPEs, via the _PRW control methods.
+ * Each GPE that has one or more _PRWs that reference it is by
+ * definition a wake GPE and will not be enabled while the machine
+ * is running.
+ */
+ gpe_info.gpe_block = gpe_block;
+ gpe_info.gpe_device = gpe_device;
+
+ status =
+ acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,

+					   ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK,
+					   acpi_ev_match_prw_and_gpe, &gpe_info,
+					   NULL);
+	}
+
	/* Return the new block */

	if (return_gpe_block) {
@@ -995,27 +1016,6 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
	}

	/*

- * Runtime option: Should wake GPEs be enabled at runtime? The default
- * is no, they should only be enabled just as the machine goes to sleep.
- */
- if (acpi_gbl_leave_wake_gpes_disabled) {
- /*
- * Differentiate runtime vs wake GPEs, via the _PRW control methods.
- * Each GPE that has one or more _PRWs that reference it is by
- * definition a wake GPE and will not be enabled while the machine
- * is running.
- */
- gpe_info.gpe_block = gpe_block;
- gpe_info.gpe_device = gpe_device;
-
- status =
- acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,

-					   ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK,
-					   acpi_ev_match_prw_and_gpe, &gpe_info,
-					   NULL);

- }
-
- /*
* Enable all GPEs in this block that have these attributes:
* 1) are "runtime" or "run/wake" GPEs, and
* 2) have a corresponding _Lxx or _Exx method

#26 lore raw

Re: [PATCH 091/171] ACPI: GPE enabling should happen after EC installation

Quoted 20 lines · Alexey Starikovskiy
Quoted 12 lines · Zhao Yakui
Quoted 11 lines · Carlos Corbacho
Quoted 10 lines · On Wednesday 30 April 2008 07:58:53 Carlos Corbacho wrote:
Quoted 9 lines · On Wednesday 30 April 2008 11:25:34 Zhao Yakui wrote:
Quoted 4 lines · Len Brown

From: Alexey Starikovskiy <[email protected]>

GPE could try to access EC region, so should not be enabled before EC is installed

It is caused by broken bios if GPE method tries to access EC region before EC is initialized correctly. It is more appropriate to fix this issue by upgrading bios rather than by the patch.
And this patch will cause some potential problems.

Quoted 7 lines
Quoted 3 lines
Quoted 1 line

1) Does the BIOS in question work under Windows?

^^^
that should be 'not work'

For the laptop in bug 9916:
Windows can work on the BIOS in question. In fact only warning message is printed for Linux and it won't break anything. (Maybe the warning message also exists on windows. But we can't see them.)

Quoted 5 lines

This is generally a stupid idea to enable interrupt before you have handler for it ready, even if you are able to _survive_ unhandled interrupt.

Your other issue about WAKE GPEs, which could be wrongly enabled, could be solved by moving WAKE GPE init closer to RUNTIME GPE one:

Thanks for the so quick response.
The following patch can solve the issue about the WAKE GPEs.

But after the patch is applied, it seems that we make a lot of changes about the GPE initialization flowchart in ACPICA. Will these be easily accepted by ACPICA author?
At the same time some RUNTIME GPEs will be enabled twice. When acpi_enable_gpe is called in the course of EC installation, some RUNTIME GPEs will also be enabled. In fact when the acpi_ev_install_fadt_gpes is called, all the RUNTIME GPEs will be enabled. In such case it brings that some RUNTIME GPEs are enabled twice. Of course the patch should work fine if it is safe to enable RUNTTME GPEs twice.

Best regards.
Yakui

Quoted 66 lines

Regards,
Alex.

drivers/acpi/events/evgpeblk.c +21 -21
index 361ebe6..37c68ae 100644
@@ -940,6 +940,27 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
 					acpi_ev_save_method_info, gpe_block,
 					NULL);
 
+	/*
+	 * Runtime option: Should wake GPEs be enabled at runtime?  The default
+	 * is no, they should only be enabled just as the machine goes to sleep.
+	 */
+	if (acpi_gbl_leave_wake_gpes_disabled) {
+		/*
+		 * Differentiate runtime vs wake GPEs, via the _PRW control methods.
+		 * Each GPE that has one or more _PRWs that reference it is by
+		 * definition a wake GPE and will not be enabled while the machine
+		 * is running.
+		 */
+		gpe_info.gpe_block = gpe_block;
+		gpe_info.gpe_device = gpe_device;
+
+		status =
+		    acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+					   ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK,
+					   acpi_ev_match_prw_and_gpe, &gpe_info,
+					   NULL);
+	}
+
 	/* Return the new block */
 
 	if (return_gpe_block) {
@@ -995,27 +1016,6 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
 	}
 
 	/*
-	 * Runtime option: Should wake GPEs be enabled at runtime?  The default
-	 * is no, they should only be enabled just as the machine goes to sleep.
-	 */
-	if (acpi_gbl_leave_wake_gpes_disabled) {
-		/*
-		 * Differentiate runtime vs wake GPEs, via the _PRW control methods.
-		 * Each GPE that has one or more _PRWs that reference it is by
-		 * definition a wake GPE and will not be enabled while the machine
-		 * is running.
-		 */
-		gpe_info.gpe_block = gpe_block;
-		gpe_info.gpe_device = gpe_device;
-
-		status =
-		    acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
-					   ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK,
-					   acpi_ev_match_prw_and_gpe, &gpe_info,
-					   NULL);
-	}
-
-	/*
 	 * Enable all GPEs in this block that have these attributes:
 	 * 1) are "runtime" or "run/wake" GPEs, and
 	 * 2) have a corresponding _Lxx or _Exx method
#27 lore raw

Re: [PATCH 091/171] ACPI: GPE enabling should happen after EC installation

Quoted 2 lines · Zhao Yakui

But after the patch is applied, it seems that we make a lot of changes about the GPE initialization flowchart in ACPICA.

And this flowchart is cast in stone?

Quoted 1 line

Will these be easily accepted by ACPICA author?

You should probably ask him, not me. We are talking Bob Moore here, yes? Why don't you add CC to him if you are worried?

Quoted 6 lines

At the same time some RUNTIME GPEs will be enabled twice. When acpi_enable_gpe is called in the course of EC installation, some RUNTIME GPEs will also be enabled. In fact when the acpi_ev_install_fadt_gpes is called, all the RUNTIME GPEs will be enabled. In such case it brings that some RUNTIME GPEs are enabled twice. Of course the patch should work fine if it is safe to enable RUNTTME GPEs twice.

Please advise me, how we are not enabling them twice if EC init happens after? The same acpi_enable_gpe will be called from it.

Regards,
Alex.

#28 lore raw

Re: [PATCH 091/171] ACPI: GPE enabling should happen after EC installation

Quoted 4 lines · Alexey Starikovskiy
Quoted 2 lines · Zhao Yakui

But after the patch is applied, it seems that we make a lot of changes about the GPE initialization flowchart in ACPICA.

And this flowchart is cast in stone?

After the two patches are applied, the issue in bug9916 can be fixed. But in fact the issue in bug9916 is related with bios.
In the L02 method the _PSR object of AC will be accessed.

Quoted 4 lines

Method (_PSR, 0, NotSerialized)

                   {
                       Return (HPAC)  
                   }

HPAC is defined in EC OperationRegion. IMO Whether the HPAC can be
accessed should be determined by the flag of H8DR, which indicates whether the EC operation region can be accessed. (1 means that EC opregion can be accessed. 0 means that EC opregion can't be accessed.)
It seems that this is an obvious bios bug. It is more appropriate to
fix this issue by upgrading bios.
IMO it is unnecessary to make a lot of changes about GPE
initialization flowchart for the obvious bios bug.

At the same time it is very luck that there exists ECDT table on the
laptop of bug9916. And after the two patches are applied, the GPE can be enabled after EC installation. But if the ECDT table doesn't exist(EC device has no _INI object in DSDT table), it seems that GPE enabling still happens before EC installation.

Quoted 3 lines
Quoted 1 line

Will these be easily accepted by ACPICA author?

You should probably ask him, not me. We are talking Bob Moore here, yes? Why don't you add CC to him if you are worried?

CC Bob and Lin Ming to see this issue.

Quoted 12 lines
Quoted 6 lines

At the same time some RUNTIME GPEs will be enabled twice. When acpi_enable_gpe is called in the course of EC installation, some RUNTIME GPEs will also be enabled. In fact when the acpi_ev_install_fadt_gpes is called, all the RUNTIME GPEs will be enabled. In such case it brings that some RUNTIME GPEs are enabled twice. Of course the patch should work fine if it is safe to enable RUNTTME GPEs twice.

Please advise me, how we are not enabling them twice if EC init happens after? The same acpi_enable_gpe will be called from it.

Regards,
Alex.

#29 lore raw

Re: [PATCH 091/171] ACPI: GPE enabling should happen after EC installation

In reply to Carlos Corbacho
Quoted 12 lines · Carlos Corbacho
Quoted 10 lines · On Wednesday 30 April 2008 11:25:34 Zhao Yakui wrote:
Quoted 4 lines · Len Brown

From: Alexey Starikovskiy <[email protected]>

GPE could try to access EC region, so should not be enabled before EC is installed

It is caused by broken bios if GPE method tries to access EC region before EC is initialized correctly. It is more appropriate to fix this issue by upgrading bios rather than by the patch.
And this patch will cause some potential problems.

Quoted 6 lines

1) Does the BIOS in question work under Windows?
2) Does the system in question require a BIOS upgrade under Windows for this issue?

If the answer to both of those is 'no', then the answer is that it's a Linux bug, and a patch of some description is appropriate.

3) Did the vendor issue an O.S. "driver workaround"? If so, it means we add a *quirk*, and not that we hose ACPI for everyone else.

Quoted 2 lines

Just because there are crappy BIOS's out there, and we'd rather not put in nasty fixes, doesn't mean that we shouldn't.

But it means we need to limit the damage these nasty fixes can do to others.

Signature · 4 lines
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh
author reviewer
#30 lore raw

PATCH 92/171 2.6.25 regression: powertop says 120K wakeups/sec

In reply to Len Brown

From: Venkatesh Pallipadi <[email protected]>

Patch to fix huge number of wakeups reported due to recent changes in processor_idle.c. The problem was that the entry_method determination was broken due to one of the recent commits (bc71bec91f987) causing C1 entry to not to go to halt.

http://lkml.org/lkml/2008/3/22/124

---
 drivers/acpi/processor_idle.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)
drivers/acpi/processor_idle.c +4 -0
index 788da97..836362b 100644
@@ -848,6 +848,7 @@ static int acpi_processor_get_power_info_default(struct acpi_processor *pr)
 		/* all processors need to support C1 */
 		pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
 		pr->power.states[ACPI_STATE_C1].valid = 1;
+		pr->power.states[ACPI_STATE_C1].entry_method = ACPI_CSTATE_HALT;
 	}
 	/* the C0 state only exists as a filler in our array */
 	pr->power.states[ACPI_STATE_C0].valid = 1;
@@ -960,6 +961,9 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
 				 cx.address);
 		}
 
+		if (cx.type == ACPI_STATE_C1) {
+			cx.valid = 1;
+		}
 
 		obj = &(element->package.elements[2]);
 		if (obj->type != ACPI_TYPE_INTEGER)
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#31 lore raw

PATCH 93/171 flush kacpi_notify_wq before removing notify handler

In reply to Len Brown

From: Zhang Rui <[email protected]>

Flush kacpi_notify_wq before notify handler is removed, this can fix a bug which the deferred notify handler is executed after the notify_handler has already been removed.
http://bugzilla.kernel.org/show_bug.cgi?id=9772

---
 drivers/acpi/osl.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
drivers/acpi/osl.c +1 -0
index a498a6c..235a138 100644
@@ -742,6 +742,7 @@ EXPORT_SYMBOL(acpi_os_execute);
 void acpi_os_wait_events_complete(void *context)
 {
 	flush_workqueue(kacpid_wq);
+	flush_workqueue(kacpi_notify_wq);
 }
 
 EXPORT_SYMBOL(acpi_os_wait_events_complete);
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#32 lore raw

PATCH 94/171 thermal: add the support for building the generic thermal as a module

In reply to Len Brown

From: Zhang Rui <[email protected]>

Build the generic thermal driver as module "thermal_sys".

Make ACPI thermal, video, processor and fan SELECT the generic thermal driver, as these drivers rely on it to build the sysfs I/F.

---
 drivers/acpi/Kconfig      |    3 +++
 drivers/misc/Kconfig      |    1 +
 drivers/thermal/Kconfig   |    4 ++--
 drivers/thermal/Makefile  |    3 ++-
 drivers/thermal/thermal.c |    2 +-
 include/linux/thermal.h   |   14 --------------
 6 files changed, 9 insertions(+), 18 deletions(-)
drivers/acpi/Kconfig +3 -0
index b4f5e85..c52fca8 100644
@@ -140,6 +140,7 @@ config ACPI_VIDEO
 	tristate "Video"
 	depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
 	depends on INPUT
+	select THERMAL
 	help
 	  This driver implement the ACPI Extensions For Display Adapters
 	  for integrated graphics devices on motherboard, as specified in
@@ -151,6 +152,7 @@ config ACPI_VIDEO
 
 config ACPI_FAN
 	tristate "Fan"
+	select THERMAL
 	default y
 	help
 	  This driver adds support for ACPI fan devices, allowing user-mode 
@@ -172,6 +174,7 @@ config ACPI_BAY
 
 config ACPI_PROCESSOR
 	tristate "Processor"
+	select THERMAL
 	default y
 	help
 	  This driver installs ACPI as the idle handler for Linux, and uses
drivers/misc/Kconfig +1 -0
index 297a48f..08f35d7 100644
@@ -344,6 +344,7 @@ config ATMEL_SSC
 config INTEL_MENLOW
 	tristate "Thermal Management driver for Intel menlow platform"
 	depends on ACPI_THERMAL
+	select THERMAL
 	depends on X86
 	---help---
 	  ACPI thermal management enhancement driver on
drivers/thermal/Kconfig +2 -2
index 17e71d5..4b62852 100644
@@ -3,7 +3,7 @@
 #
 
 menuconfig THERMAL
-	bool "Generic Thermal sysfs driver"
+	tristate "Generic Thermal sysfs driver"
 	help
 	  Generic Thermal Sysfs driver offers a generic mechanism for
 	  thermal management. Usually it's made up of one or more thermal
@@ -11,4 +11,4 @@ menuconfig THERMAL
 	  Each thermal zone contains its own temperature, trip points,
 	  cooling devices.
 	  All platforms with ACPI thermal support can use this driver.
-	  If you want this support, you should say Y here.
+	  If you want this support, you should say Y or M here.
drivers/thermal/Makefile +2 -1
index 8ef1232..02b6451 100644
@@ -2,4 +2,5 @@
 # Makefile for sensor chip drivers.
 #
 
-obj-$(CONFIG_THERMAL)		+= thermal.o
+thermal_sys-objs	+= thermal.o
+obj-$(CONFIG_THERMAL)		+= thermal_sys.o
drivers/thermal/thermal.c +1 -1
index 7f79bbf..cf56af4 100644
@@ -31,7 +31,7 @@
 #include <linux/thermal.h>
 #include <linux/spinlock.h>
 
-MODULE_AUTHOR("Zhang Rui")
+MODULE_AUTHOR("Zhang Rui");
 MODULE_DESCRIPTION("Generic thermal management sysfs support");
 MODULE_LICENSE("GPL");
 
include/linux/thermal.h +0 -14
index 90c1c19..3ff680b 100644
@@ -88,24 +88,10 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
 				     struct thermal_cooling_device *);
 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
 				       struct thermal_cooling_device *);
-
-#ifdef	CONFIG_THERMAL
 struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
 							       struct
 							       thermal_cooling_device_ops
 							       *);
 void thermal_cooling_device_unregister(struct thermal_cooling_device *);
-#else
-static inline struct thermal_cooling_device
-*thermal_cooling_device_register(char *c, void *v,
-				 struct thermal_cooling_device_ops *t)
-{
-	return NULL;
-}
-static inline
-    void thermal_cooling_device_unregister(struct thermal_cooling_device *t)
-{
-};
-#endif
 
 #endif /* __THERMAL_H__ */
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#33 lore raw

PATCH 95/171 thermal: add new get_crit_temp callback

In reply to Len Brown

From: Zhang, Rui <[email protected]>

Add a new callback so that the generic thermal can get the critical trip point info of a thermal zone,
which is needed for building the tempX_crit hwmon sysfs attribute.

---
 drivers/acpi/thermal.c  |   13 +++++++++++++
 include/linux/thermal.h |    1 +
 2 files changed, 14 insertions(+), 0 deletions(-)
drivers/acpi/thermal.c +13 -0
index 766bd25..ec707ed 100644
@@ -1012,6 +1012,18 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
 	return -EINVAL;
 }
 
+static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
+				unsigned long *temperature) {
+	struct acpi_thermal *tz = thermal->devdata;
+
+	if (tz->trips.critical.flags.valid) {
+		*temperature = KELVIN_TO_MILLICELSIUS(
+				tz->trips.critical.temperature);
+		return 0;
+	} else
+		return -EINVAL;
+}
+
 typedef int (*cb)(struct thermal_zone_device *, int,
 		  struct thermal_cooling_device *);
 static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
@@ -1103,6 +1115,7 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
 	.set_mode = thermal_set_mode,
 	.get_trip_type = thermal_get_trip_type,
 	.get_trip_temp = thermal_get_trip_temp,
+	.get_crit_temp = thermal_get_crit_temp,
 };
 
 static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
include/linux/thermal.h +1 -0
index 3ff680b..16e6a8b 100644
@@ -41,6 +41,7 @@ struct thermal_zone_device_ops {
 	int (*set_mode) (struct thermal_zone_device *, const char *);
 	int (*get_trip_type) (struct thermal_zone_device *, int, char *);
 	int (*get_trip_temp) (struct thermal_zone_device *, int, char *);
+	int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *);
 };
 
 struct thermal_cooling_device_ops {
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#34 lore raw

PATCH 96/171 thermal: add hwmon sysfs I/F

In reply to Len Brown

From: Zhang Rui <[email protected]>

Add hwmon sys I/F for generic thermal driver.

Note: we have one hwmon class device for EACH TYPE of the thermal zone device.

---
 drivers/thermal/thermal.c |  163 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/thermal.h   |   24 +++++++
 2 files changed, 187 insertions(+), 0 deletions(-)
drivers/thermal/thermal.c +163 -0
index cf56af4..6098787 100644
@@ -295,6 +295,164 @@ thermal_cooling_device_trip_point_show(struct device *dev,
 
 /* Device management */
 
+#if defined(CONFIG_HWMON) ||	\
+	(defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE))
+/* hwmon sys I/F */
+#include <linux/hwmon.h>
+static LIST_HEAD(thermal_hwmon_list);
+
+static ssize_t
+name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct thermal_hwmon_device *hwmon = dev->driver_data;
+	return sprintf(buf, "%s\n", hwmon->type);
+}
+static DEVICE_ATTR(name, 0444, name_show, NULL);
+
+static ssize_t
+temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct thermal_hwmon_attr *hwmon_attr
+			= container_of(attr, struct thermal_hwmon_attr, attr);
+	struct thermal_zone_device *tz
+			= container_of(hwmon_attr, struct thermal_zone_device,
+				       temp_input);
+
+	return tz->ops->get_temp(tz, buf);
+}
+
+static ssize_t
+temp_crit_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct thermal_hwmon_attr *hwmon_attr
+			= container_of(attr, struct thermal_hwmon_attr, attr);
+	struct thermal_zone_device *tz
+			= container_of(hwmon_attr, struct thermal_zone_device,
+				       temp_crit);
+
+	return tz->ops->get_trip_temp(tz, 0, buf);
+}
+
+
+static int
+thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+	struct thermal_hwmon_device *hwmon;
+	int new_hwmon_device = 1;
+	int result;
+
+	mutex_lock(&thermal_list_lock);
+	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
+		if (!strcmp(hwmon->type, tz->type)) {
+			new_hwmon_device = 0;
+			mutex_unlock(&thermal_list_lock);
+			goto register_sys_interface;
+		}
+	mutex_unlock(&thermal_list_lock);
+
+	hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
+	if (!hwmon)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&hwmon->tz_list);
+	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
+	hwmon->device = hwmon_device_register(NULL);
+	if (IS_ERR(hwmon->device)) {
+		result = PTR_ERR(hwmon->device);
+		goto free_mem;
+	}
+	hwmon->device->driver_data = hwmon;
+	result = device_create_file(hwmon->device, &dev_attr_name);
+	if (result)
+		goto unregister_hwmon_device;
+
+ register_sys_interface:
+	tz->hwmon = hwmon;
+	hwmon->count++;
+
+	snprintf(tz->temp_input.name, THERMAL_NAME_LENGTH,
+		 "temp%d_input", hwmon->count);
+	tz->temp_input.attr.attr.name = tz->temp_input.name;
+	tz->temp_input.attr.attr.mode = 0444;
+	tz->temp_input.attr.show = temp_input_show;
+	result = device_create_file(hwmon->device, &tz->temp_input.attr);
+	if (result)
+		goto unregister_hwmon_device;
+
+	if (tz->ops->get_crit_temp) {
+		unsigned long temperature;
+		if (!tz->ops->get_crit_temp(tz, &temperature)) {
+			snprintf(tz->temp_crit.name, THERMAL_NAME_LENGTH,
+				"temp%d_crit", hwmon->count);
+			tz->temp_crit.attr.attr.name = tz->temp_crit.name;
+			tz->temp_crit.attr.attr.mode = 0444;
+			tz->temp_crit.attr.show = temp_crit_show;
+			result = device_create_file(hwmon->device,
+						    &tz->temp_crit.attr);
+			if (result)
+				goto unregister_hwmon_device;
+		}
+	}
+
+	mutex_lock(&thermal_list_lock);
+	if (new_hwmon_device)
+		list_add_tail(&hwmon->node, &thermal_hwmon_list);
+	list_add_tail(&tz->hwmon_node, &hwmon->tz_list);
+	mutex_unlock(&thermal_list_lock);
+
+	return 0;
+
+ unregister_hwmon_device:
+	device_remove_file(hwmon->device, &tz->temp_crit.attr);
+	device_remove_file(hwmon->device, &tz->temp_input.attr);
+	if (new_hwmon_device) {
+		device_remove_file(hwmon->device, &dev_attr_name);
+		hwmon_device_unregister(hwmon->device);
+	}
+ free_mem:
+	if (new_hwmon_device)
+		kfree(hwmon);
+
+	return result;
+}
+
+static void
+thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+	struct thermal_hwmon_device *hwmon = tz->hwmon;
+
+	tz->hwmon = NULL;
+	device_remove_file(hwmon->device, &tz->temp_input.attr);
+	device_remove_file(hwmon->device, &tz->temp_crit.attr);
+
+	mutex_lock(&thermal_list_lock);
+	list_del(&tz->hwmon_node);
+	if (!list_empty(&hwmon->tz_list)) {
+		mutex_unlock(&thermal_list_lock);
+		return;
+	}
+	list_del(&hwmon->node);
+	mutex_unlock(&thermal_list_lock);
+
+	device_remove_file(hwmon->device, &dev_attr_name);
+	hwmon_device_unregister(hwmon->device);
+	kfree(hwmon);
+}
+#else
+static int
+thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+	return 0;
+}
+
+static void
+thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+}
+#endif
+
+
 /**
  * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
  * @tz:		thermal zone device
@@ -642,6 +800,10 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
 			goto unregister;
 	}
 
+	result = thermal_add_hwmon_sysfs(tz);
+	if (result)
+		goto unregister;
+
 	mutex_lock(&thermal_list_lock);
 	list_add_tail(&tz->node, &thermal_tz_list);
 	if (ops->bind)
@@ -700,6 +862,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
 	for (count = 0; count < tz->trips; count++)
 		TRIP_POINT_ATTR_REMOVE(&tz->device, count);
 
+	thermal_remove_hwmon_sysfs(tz);
 	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
 	idr_destroy(&tz->idr);
 	mutex_destroy(&tz->lock);
include/linux/thermal.h +24 -0
index 16e6a8b..06d3e6e 100644
@@ -66,6 +66,23 @@ struct thermal_cooling_device {
 				((long)t-2732+5)/10 : ((long)t-2732-5)/10)
 #define CELSIUS_TO_KELVIN(t)	((t)*10+2732)
 
+#if defined(CONFIG_HWMON) ||	\
+	(defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE))
+/* thermal zone devices with the same type share one hwmon device */
+struct thermal_hwmon_device {
+	char type[THERMAL_NAME_LENGTH];
+	struct device *device;
+	int count;
+	struct list_head tz_list;
+	struct list_head node;
+};
+
+struct thermal_hwmon_attr {
+	struct device_attribute attr;
+	char name[16];
+};
+#endif
+
 struct thermal_zone_device {
 	int id;
 	char type[THERMAL_NAME_LENGTH];
@@ -77,6 +94,13 @@ struct thermal_zone_device {
 	struct idr idr;
 	struct mutex lock;	/* protect cooling devices list */
 	struct list_head node;
+#if defined(CONFIG_HWMON) ||	\
+	(defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE))
+	struct list_head hwmon_node;
+	struct thermal_hwmon_device *hwmon;
+	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
+	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
+#endif
 };
 
 struct thermal_zone_device *thermal_zone_device_register(char *, int, void *,
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#35 lore raw

PATCH 97/171 thermal: update the documentation

In reply to Len Brown

From: Zhang Rui <[email protected]>

Update the documentation for the thermal driver hwmon sys I/F.

Change the ACPI thermal zone type to be consistent with hwmon.

---
 Documentation/thermal/sysfs-api.txt |   33 +++++++++++++++++++++++++++------
 drivers/acpi/thermal.c              |    2 +-
 2 files changed, 28 insertions(+), 7 deletions(-)
Documentation/thermal/sysfs-api.txt +27 -6
index d9f28be..70d68ce 100644
@@ -108,10 +108,12 @@ and throttle appropriate devices.
 RO	read only value
 RW	read/write value
 
-All thermal sysfs attributes will be represented under /sys/class/thermal
+Thermal sysfs attributes will be represented under /sys/class/thermal.
+Hwmon sysfs I/F extension is also available under /sys/class/hwmon
+if hwmon is compiled in or built as a module.
 
 Thermal zone device sys I/F, created once it's registered:
-|thermal_zone[0-*]:
+/sys/class/thermal/thermal_zone[0-*]:
 	|-----type:			Type of the thermal zone
 	|-----temp:			Current temperature
 	|-----mode:			Working mode of the thermal zone
@@ -119,7 +121,7 @@ Thermal zone device sys I/F, created once it's registered:
 	|-----trip_point_[0-*]_type:	Trip point type
 
 Thermal cooling device sys I/F, created once it's registered:
-|cooling_device[0-*]:
+/sys/class/thermal/cooling_device[0-*]:
 	|-----type :			Type of the cooling device(processor/fan/...)
 	|-----max_state:		Maximum cooling state of the cooling device
 	|-----cur_state:		Current cooling state of the cooling device
@@ -130,10 +132,19 @@ They represent the relationship between a thermal zone and its associated coolin
 They are created/removed for each
 thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device successful execution.
 
-|thermal_zone[0-*]
+/sys/class/thermal/thermal_zone[0-*]
 	|-----cdev[0-*]:		The [0-*]th cooling device in the current thermal zone
 	|-----cdev[0-*]_trip_point:	Trip point that cdev[0-*] is associated with
 
+Besides the thermal zone device sysfs I/F and cooling device sysfs I/F,
+the generic thermal driver also creates a hwmon sysfs I/F for each _type_ of
+thermal zone device. E.g. the generic thermal driver registers one hwmon class device
+and build the associated hwmon sysfs I/F for all the registered ACPI thermal zones.
+/sys/class/hwmon/hwmon[0-*]:
+	|-----name:			The type of the thermal zone devices.
+	|-----temp[1-*]_input:		The current temperature of thermal zone [1-*].
+	|-----temp[1-*]_critical:	The critical trip point of thermal zone [1-*].
+Please read Documentation/hwmon/sysfs-interface for additional information.
 
 ***************************
 * Thermal zone attributes *
@@ -141,7 +152,10 @@ thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device successful e
 
 type				Strings which represent the thermal zone type.
 				This is given by thermal zone driver as part of registration.
-				Eg: "ACPI thermal zone" indicates it's a ACPI thermal device
+				Eg: "acpitz" indicates it's an ACPI thermal device.
+				In order to keep it consistent with hwmon sys attribute,
+				this should be a short, lowercase string,
+				not containing spaces nor dashes.
 				RO
 				Required
 
@@ -218,7 +232,7 @@ the sys I/F structure will be built like this:
 /sys/class/thermal:
 
 |thermal_zone1:
-	|-----type:			ACPI thermal zone
+	|-----type:			acpitz
 	|-----temp:			37000
 	|-----mode:			kernel
 	|-----trip_point_0_temp:	100000
@@ -243,3 +257,10 @@ the sys I/F structure will be built like this:
 	|-----type:			Fan
 	|-----max_state:		2
 	|-----cur_state:		0
+
+/sys/class/hwmon:
+
+|hwmon0:
+	|-----name:			acpitz
+	|-----temp1_input:		37000
+	|-----temp1_crit:		100000
drivers/acpi/thermal.c +1 -1
index ec707ed..5e9641c 100644
@@ -1136,7 +1136,7 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
 
 	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
 			tz->trips.active[i].flags.valid; i++, trips++);
-	tz->thermal_zone = thermal_zone_device_register("ACPI thermal zone",
+	tz->thermal_zone = thermal_zone_device_register("acpitz",
 					trips, tz, &acpi_thermal_zone_ops);
 	if (IS_ERR(tz->thermal_zone))
 		return -ENODEV;
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#36 lore raw

PATCH 98/171 ACPI: elide a non-zero test on a result that is never 0

In reply to Len Brown

From: Julia Lawall <[email protected]>

thermal_cooling_device_register used to return NULL if THERMAL is "n". As the ACPI fan, processor and video drivers SELECT the generic thermal in PATCH 01, this is not a problem any more.

---
 drivers/acpi/fan.c            |   35 +++++++++++++++++------------------
 drivers/acpi/processor_core.c |   31 +++++++++++++++----------------
 drivers/acpi/video.c          |   28 +++++++++++++---------------
 drivers/misc/intel_menlow.c   |   23 +++++++++--------------
 4 files changed, 54 insertions(+), 63 deletions(-)
drivers/acpi/fan.c +17 -18
index c8e3cba..cf635cd 100644
@@ -260,24 +260,23 @@ static int acpi_fan_add(struct acpi_device *device)
 		result = PTR_ERR(cdev);
 		goto end;
 	}
-	if (cdev) {
-		printk(KERN_INFO PREFIX
-			"%s is registered as cooling_device%d\n",
-			device->dev.bus_id, cdev->id);
-
-		acpi_driver_data(device) = cdev;
-		result = sysfs_create_link(&device->dev.kobj,
-					   &cdev->device.kobj,
-					   "thermal_cooling");
-		if (result)
-			return result;
-
-		result = sysfs_create_link(&cdev->device.kobj,
-					   &device->dev.kobj,
-					   "device");
-		if (result)
-			return result;
-	}
+
+	printk(KERN_INFO PREFIX
+		"%s is registered as cooling_device%d\n",
+		device->dev.bus_id, cdev->id);
+
+	acpi_driver_data(device) = cdev;
+	result = sysfs_create_link(&device->dev.kobj,
+				   &cdev->device.kobj,
+				   "thermal_cooling");
+	if (result)
+		printk(KERN_ERR PREFIX "Create sysfs link\n");
+
+	result = sysfs_create_link(&cdev->device.kobj,
+				   &device->dev.kobj,
+				   "device");
+	if (result)
+		printk(KERN_ERR PREFIX "Create sysfs link\n");
 
 	result = acpi_fan_add_fs(device);
 	if (result)
drivers/acpi/processor_core.c +15 -16
index a825b43..ea5f628 100644
@@ -674,22 +674,21 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
 		result = PTR_ERR(pr->cdev);
 		goto end;
 	}
-	if (pr->cdev) {
-		printk(KERN_INFO PREFIX
-			"%s is registered as cooling_device%d\n",
-			device->dev.bus_id, pr->cdev->id);
-
-		result = sysfs_create_link(&device->dev.kobj,
-					   &pr->cdev->device.kobj,
-					   "thermal_cooling");
-		if (result)
-			return result;
-		result = sysfs_create_link(&pr->cdev->device.kobj,
-					   &device->dev.kobj,
-					   "device");
-		if (result)
-			return result;
-	}
+
+	printk(KERN_INFO PREFIX
+		"%s is registered as cooling_device%d\n",
+		device->dev.bus_id, pr->cdev->id);
+
+	result = sysfs_create_link(&device->dev.kobj,
+				   &pr->cdev->device.kobj,
+				   "thermal_cooling");
+	if (result)
+		printk(KERN_ERR PREFIX "Create sysfs link\n");
+	result = sysfs_create_link(&pr->cdev->device.kobj,
+				   &device->dev.kobj,
+				   "device");
+	if (result)
+		printk(KERN_ERR PREFIX "Create sysfs link\n");
 
 	if (pr->flags.throttling) {
 		printk(KERN_INFO PREFIX "%s [%s] (supports",
drivers/acpi/video.c +13 -15
index 980a741..55c0956 100644
@@ -734,21 +734,19 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
 		if (IS_ERR(device->cdev))
 			return;
 
-		if (device->cdev) {
-			printk(KERN_INFO PREFIX
-				"%s is registered as cooling_device%d\n",
-				device->dev->dev.bus_id, device->cdev->id);
-			result = sysfs_create_link(&device->dev->dev.kobj,
-					  &device->cdev->device.kobj,
-					  "thermal_cooling");
-			if (result)
-				printk(KERN_ERR PREFIX "Create sysfs link\n");
-			result = sysfs_create_link(&device->cdev->device.kobj,
-					  &device->dev->dev.kobj,
-					  "device");
-                        if (result)
-				printk(KERN_ERR PREFIX "Create sysfs link\n");
-		}
+		printk(KERN_INFO PREFIX
+			"%s is registered as cooling_device%d\n",
+			device->dev->dev.bus_id, device->cdev->id);
+		result = sysfs_create_link(&device->dev->dev.kobj,
+				&device->cdev->device.kobj,
+				"thermal_cooling");
+		if (result)
+			printk(KERN_ERR PREFIX "Create sysfs link\n");
+		result = sysfs_create_link(&device->cdev->device.kobj,
+				&device->dev->dev.kobj, "device");
+		if (result)
+			printk(KERN_ERR PREFIX "Create sysfs link\n");
+
 	}
 	if (device->cap._DCS && device->cap._DSS){
 		static int count = 0;
drivers/misc/intel_menlow.c +9 -14
index 0c0bb30..3db83a2 100644
@@ -175,20 +175,15 @@ static int intel_menlow_memory_add(struct acpi_device *device)
 		goto end;
 	}
 
-	if (cdev) {
-		acpi_driver_data(device) = cdev;
-		result = sysfs_create_link(&device->dev.kobj,
-					&cdev->device.kobj, "thermal_cooling");
-		if (result)
-			goto unregister;
-
-		result = sysfs_create_link(&cdev->device.kobj,
-					&device->dev.kobj, "device");
-		if (result) {
-			sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
-			goto unregister;
-		}
-	}
+	acpi_driver_data(device) = cdev;
+	result = sysfs_create_link(&device->dev.kobj,
+				&cdev->device.kobj, "thermal_cooling");
+	if (result)
+		printk(KERN_ERR PREFIX "Create sysfs link\n");
+	result = sysfs_create_link(&cdev->device.kobj,
+				&device->dev.kobj, "device");
+	if (result)
+		printk(KERN_ERR PREFIX "Create sysfs link\n");
 
  end:
 	return result;
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#37 lore raw

PATCH 99/171 ACPI: update thermal temperature

In reply to Len Brown

From: Zhang, Rui <[email protected]>

Fix the problem that thermal_get_temp returns the cached value, which causes the temperature in generic thermal never updates.

---
 drivers/acpi/thermal.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)
drivers/acpi/thermal.c +5 -0
index 5e9641c..782c225 100644
@@ -884,10 +884,15 @@ static void acpi_thermal_check(void *data)
 static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
 {
 	struct acpi_thermal *tz = thermal->devdata;
+	int result;
 
 	if (!tz)
 		return -EINVAL;
 
+	result = acpi_thermal_get_temperature(tz);
+	if (result)
+		return result;
+
 	return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(tz->temperature));
 }
 
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#38 lore raw

PATCH 100/171 thermal: re-name thermal.c to thermal_sys.c

In reply to Len Brown

From: Len Brown <[email protected]>

thermal_sys was already the name of the resulting module, and it is built from this one source file.

---
 drivers/thermal/Makefile      |    1 -
 drivers/thermal/thermal.c     |  899 -----------------------------------------
 drivers/thermal/thermal_sys.c |  899 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 899 insertions(+), 900 deletions(-)
 delete mode 100644 drivers/thermal/thermal.c
 create mode 100644 drivers/thermal/thermal_sys.c
drivers/thermal/Makefile +0 -1
index 02b6451..31108a0 100644
@@ -2,5 +2,4 @@
 # Makefile for sensor chip drivers.
 #
 
-thermal_sys-objs	+= thermal.o
 obj-$(CONFIG_THERMAL)		+= thermal_sys.o
drivers/thermal/thermal.c deleted +0 -899

899 lines not on this page · raw message

drivers/thermal/thermal_sys.c new file +899 -0

899 lines not on this page · raw message

Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#39 lore raw

PATCH 156/171 ACPI: thinkpad-acpi: BIOS backlight mode helper (v2)

In reply to Len Brown

From: Henrique de Moraes Holschuh <[email protected]>

Lenovo ThinkPads with generic ACPI backlight level control can be easily set to react to keyboard brightness key presses in a more predictable way than what they do when in "DOS / bootloader" mode after Linux brings up the ACPI interface.

The switch to the ACPI backlight mode in the firmware is designed to be safe to use only as an one way trapdoor. One is not to force the firmware to switch back to "DOS/bootloader" mode except by rebooting. The mode switch itself is performed by calling any of the ACPI _BCL methods at least once.

When in ACPI mode, the backlight firmware just issues (standard) events for the brightness up/down hot key presses along with the non-standard HKEY events which thinkpad-acpi traps, and doesn't touch the hardware.

thinkpad-acpi will:

1. Place the ThinkPad firmware in ACPI backlight control mode if one is available
2. Suppress HKEY backlight change notifications by default to avoid double-reporting when ACPI video is loaded when the ThinkPad is in ACPI backlight control mode
3. Urge the user to load the ACPI video driver

The user is free to use either the ACPI video driver to get the brightness key events, or to override the thinkpad-acpi default hotkey mask to get them from thinkpad-acpi as well (this will result in duplicate events if ACPI video is loaded, so let's hope distros won't screw this up).

Provided userspace is sane, all should work (and *keep* working), which is more that can be said about the non-ACPI mode of the new Lenovo ThinkPad BIOSes when coupled to current userspace and X.org drivers.

Full guidelines for backlight hot key reporting and use of the thinkpad-acpi backlight interface have been added to the documentation.

---
 Documentation/laptops/thinkpad-acpi.txt |   49 +++++++
 drivers/misc/thinkpad_acpi.c            |  238 +++++++++++++++++--------------
 2 files changed, 182 insertions(+), 105 deletions(-)
Documentation/laptops/thinkpad-acpi.txt +49 -0
index 76cb428..bbc8275 100644
@@ -571,6 +571,46 @@ netlink interface and the input layer interface, and don't bother at all
 with hotkey_report_mode.
 
 
+Brightness hotkey notes:
+
+These are the current sane choices for brightness key mapping in
+thinkpad-acpi:
+
+For IBM and Lenovo models *without* ACPI backlight control (the ones on
+which thinkpad-acpi will autoload its backlight interface by default,
+and on which ACPI video does not export a backlight interface):
+
+1. Don't enable or map the brightness hotkeys in thinkpad-acpi, as
+   these older firmware versions unfortunately won't respect the hotkey
+   mask for brightness keys anyway, and always reacts to them.  This
+   usually work fine, unless X.org is doing something to block the BIOS.
+   In that case, use (3) below.  This is the default mode of operation.
+
+2. Enable the hotkeys, but map them to something else that is NOT
+   KEY_BRIGHTNESS_UP/DOWN or any other keycode that would cause
+   userspace to try to change the backlight level, and use that as an
+   on-screen-display hint.
+
+3. IF AND ONLY IF X.org finds a way to block the firmware from
+   automatically changing the brightness, enable the hotkeys and map
+   them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN, and feed that to
+   something that calls xbacklight.  thinkpad-acpi will not be able to
+   change brightness in that case either, so you should disable its
+   backlight interface.
+
+For Lenovo models *with* ACPI backlight control:
+
+1. Load up ACPI video and use that.  ACPI video will report ACPI
+   events for brightness change keys.  Do not mess with thinkpad-acpi
+   defaults in this case.  thinkpad-acpi should not have anything to do
+   with backlight events in a scenario where ACPI video is loaded:
+   brightness hotkeys must be disabled, and the backlight interface is
+   to be kept disabled as well.  This is the default mode of operation.
+
+2. Do *NOT* load up ACPI video, enable the hotkeys in thinkpad-acpi,
+   and map them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN.  Process
+   these keys on userspace somehow (e.g. by calling xbacklight).
+
 Bluetooth
 ---------
 
@@ -1090,6 +1130,15 @@ it there will be the following attributes:
 		dim the display.
 
 
+WARNING:
+
+    Whatever you do, do NOT ever call thinkpad-acpi backlight-level change
+    interface and the ACPI-based backlight level change interface
+    (available on newer BIOSes, and driven by the Linux ACPI video driver)
+    at the same time.  The two will interact in bad ways, do funny things,
+    and maybe reduce the life of the backlight lamps by needlessly kicking
+    its level up and down at every change.
+
 Volume control -- /proc/acpi/ibm/volume
 ---------------------------------------
 
drivers/misc/thinkpad_acpi.c +133 -105

286 lines not on this page · raw message

Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#40 lore raw

PATCH 157/171 ACPI: thinkpad-acpi: warn once about weird hotkey masks

In reply to Len Brown

From: Henrique de Moraes Holschuh <[email protected]>

thinkpad-acpi knows for a while now how to best program the hotkeys by default, and always enable them by default. Unfortunately, this information has not filtered down everywhere it needs to, yet. Notably, old ibm-acpi documentation and most "thinkpad setup guides" will have wrong information on this area.

Warn the local admin once whenever any of the following patterns are met:

1. Attempts to set hotkey mask to 0xffff (artifact from docs and config for the old ibm-acpi driver and behaviour). This mask makes no real-world sense;

2. Attempts to set hotkey mask to 0xffffffff, which means the user is trying to just have "everything work" without even reading the documentation, or that we need to get a bug report, because there is a new thinkpad out there with new exciting hot keys :-)

3. Attempts to set hotkey mask to 0xffffff, which is almost never the correct way to set up volume and brightness event reporting (and with the current state-of-the-art, it is known to never be right way to do it).

The driver will perform any and all requested operations, though, regardless of any warnings. I hope these warnings can be removed one or two years from now.

---
 drivers/misc/thinkpad_acpi.c |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)
drivers/misc/thinkpad_acpi.c +17 -0
index 2c85a2e..cd263c5 100644
@@ -237,6 +237,10 @@ static struct {
 	u32 hotkey_poll_active:1;
 } tp_features;
 
+static struct {
+	u16 hotkey_mask_ff:1;
+} tp_warned;
+
 struct thinkpad_id_data {
 	unsigned int vendor;	/* ThinkPad vendor:
 				 * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
@@ -1182,6 +1186,19 @@ static int hotkey_mask_set(u32 mask)
 	int rc = 0;
 
 	if (tp_features.hotkey_mask) {
+		if (!tp_warned.hotkey_mask_ff &&
+		    (mask == 0xffff || mask == 0xffffff ||
+		     mask == 0xffffffff)) {
+			tp_warned.hotkey_mask_ff = 1;
+			printk(TPACPI_NOTICE
+			       "setting the hotkey mask to 0x%08x is likely "
+			       "not the best way to go about it\n", mask);
+			printk(TPACPI_NOTICE
+			       "please consider using the driver defaults, "
+			       "and refer to up-to-date thinkpad-acpi "
+			       "documentation\n");
+		}
+
 		HOTKEY_CONFIG_CRITICAL_START
 		for (i = 0; i < 32; i++) {
 			u32 m = 1 << i;
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#41 lore raw

PATCH 158/171 ACPI: thinkpad-acpi: enhance box identification output

In reply to Len Brown

From: Henrique de Moraes Holschuh <[email protected]>

During initialization, thinkpad-acpi outputs some messages to make sure releavant box identification information is easily available in-line with the rest of the driver messages.

Enhance those messages to output the alfanumeric model number as well.

---
 drivers/misc/thinkpad_acpi.c |   11 ++++++++---
 1 files changed, 8 insertions(+), 3 deletions(-)
drivers/misc/thinkpad_acpi.c +8 -3
index cd263c5..c8c1d6c 100644
@@ -251,7 +251,8 @@ struct thinkpad_id_data {
 	u16 bios_model;		/* Big Endian, TP-1Y = 0x5931, 0 = unknown */
 	u16 ec_model;
 
-	char *model_str;
+	char *model_str;	/* ThinkPad T43 */
+	char *nummodel_str;	/* 9384A9C for a 9384-A9C model */
 };
 static struct thinkpad_id_data thinkpad_id;
 
@@ -988,12 +989,13 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
 			thinkpad_id.ec_version_str : "unknown");
 
 	if (thinkpad_id.vendor && thinkpad_id.model_str)
-		printk(TPACPI_INFO "%s %s\n",
+		printk(TPACPI_INFO "%s %s, model %s\n",
 			(thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
 				"IBM" : ((thinkpad_id.vendor ==
 						PCI_VENDOR_ID_LENOVO) ?
 					"Lenovo" : "Unknown vendor"),
-			thinkpad_id.model_str);
+			thinkpad_id.model_str,
+			thinkpad_id.nummodel_str);
 
 	return 0;
 }
@@ -5875,6 +5877,9 @@ static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
 		kfree(tp->model_str);
 		tp->model_str = NULL;
 	}
+
+	tp->nummodel_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_NAME),
+					GFP_KERNEL);
 }
 
 static int __init probe_for_thinkpad(void)
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#42 lore raw

PATCH 159/171 ACPI: thinkpad-acpi: rate-limit CMOS/EC unsynced error messages

In reply to Len Brown

From: Henrique de Moraes Holschuh <[email protected]>

If userspace applications mess with the CMOS NVRAM, or something causes both the ACPI firmware and thinkpad-acpi to try to change the brightness at the same time, it is possible to have the CMOS and EC registers for the current brightness go out of sync.

Should that happen, thinkpad-acpi could be really obnoxious when using a brightness_mode of 3 (both EC and CMOS). Instead of complaining a massive number of times, make sure to complain only once until EC and CMOS are back in sync.

---
 drivers/misc/thinkpad_acpi.c |   22 +++++++++++++++-------
 1 files changed, 15 insertions(+), 7 deletions(-)
drivers/misc/thinkpad_acpi.c +15 -7
index c8c1d6c..3513d99 100644
@@ -239,6 +239,7 @@ static struct {
 
 static struct {
 	u16 hotkey_mask_ff:1;
+	u16 bright_cmos_ec_unsync:1;
 } tp_warned;
 
 struct thinkpad_id_data {
@@ -4322,13 +4323,20 @@ static int brightness_get(struct backlight_device *bd)
 		level = lcmos;
 	}
 
-	if (brightness_mode == 3 && lec != lcmos) {
-		printk(TPACPI_ERR
-			"CMOS NVRAM (%u) and EC (%u) do not agree "
-			"on display brightness level\n",
-			(unsigned int) lcmos,
-			(unsigned int) lec);
-		return -EIO;
+	if (brightness_mode == 3) {
+		if (lec == lcmos)
+			tp_warned.bright_cmos_ec_unsync = 0;
+		else {
+			if (!tp_warned.bright_cmos_ec_unsync) {
+				printk(TPACPI_ERR
+					"CMOS NVRAM (%u) and EC (%u) do not "
+					"agree on display brightness level\n",
+					(unsigned int) lcmos,
+					(unsigned int) lec);
+				tp_warned.bright_cmos_ec_unsync = 1;
+			}
+			return -EIO;
+		}
 	}
 
 	return level;
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#43 lore raw

PATCH 160/171 ACPI: thinkpad-acpi: fix brightness dimming control bug

In reply to Len Brown

From: Henrique de Moraes Holschuh <[email protected]>

ibm-acpi and thinkpad-acpi did not know about bit 5 of the EC backlight level control register (EC 0x31), so it was always forced to zero on any writes.

This would disable the BIOS option to *not* use a dimmer backlight level scale while on battery, and who knows what else (there are two other control bits of unknown function).

Bit 5 controls the "reduce backlight levels when on battery" optional functionality (active low). Bits 6 and 7 are better left alone as well, instead of being forced to zero.

---
 drivers/misc/thinkpad_acpi.c |   64 ++++++++++++++++++++++++++++++++----------
 1 files changed, 49 insertions(+), 15 deletions(-)
drivers/misc/thinkpad_acpi.c +49 -15
index 3513d99..1a26423 100644
@@ -4294,8 +4294,16 @@ static struct ibm_struct ecdump_driver_data = {
 
 #define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
 
+enum {
+	TP_EC_BACKLIGHT = 0x31,
+
+	/* TP_EC_BACKLIGHT bitmasks */
+	TP_EC_BACKLIGHT_LVLMSK = 0x1F,
+	TP_EC_BACKLIGHT_CMDMSK = 0xE0,
+	TP_EC_BACKLIGHT_MAPSW = 0x20,
+};
+
 static struct backlight_device *ibm_backlight_device;
-static int brightness_offset = 0x31;
 static int brightness_mode;
 static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
 
@@ -4304,16 +4312,24 @@ static struct mutex brightness_mutex;
 /*
  * ThinkPads can read brightness from two places: EC 0x31, or
  * CMOS NVRAM byte 0x5E, bits 0-3.
+ *
+ * EC 0x31 has the following layout
+ *   Bit 7: unknown function
+ *   Bit 6: unknown function
+ *   Bit 5: Z: honour scale changes, NZ: ignore scale changes
+ *   Bit 4: must be set to zero to avoid problems
+ *   Bit 3-0: backlight brightness level
+ *
+ * brightness_get_raw returns status data in the EC 0x31 layout
  */
-static int brightness_get(struct backlight_device *bd)
+static int brightness_get_raw(int *status)
 {
 	u8 lec = 0, lcmos = 0, level = 0;
 
 	if (brightness_mode & 1) {
-		if (!acpi_ec_read(brightness_offset, &lec))
+		if (!acpi_ec_read(TP_EC_BACKLIGHT, &lec))
 			return -EIO;
-		lec &= (tp_features.bright_16levels)? 0x0f : 0x07;
-		level = lec;
+		level = lec & TP_EC_BACKLIGHT_LVLMSK;
 	};
 	if (brightness_mode & 2) {
 		lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
@@ -4324,6 +4340,8 @@ static int brightness_get(struct backlight_device *bd)
 	}
 
 	if (brightness_mode == 3) {
+		*status = lec;	/* Prefer EC, CMOS is just a backing store */
+		lec &= TP_EC_BACKLIGHT_LVLMSK;
 		if (lec == lcmos)
 			tp_warned.bright_cmos_ec_unsync = 0;
 		else {
@@ -4337,9 +4355,11 @@ static int brightness_get(struct backlight_device *bd)
 			}
 			return -EIO;
 		}
+	} else {
+		*status = level;
 	}
 
-	return level;
+	return 0;
 }
 
 /* May return EINTR which can always be mapped to ERESTARTSYS */
@@ -4347,19 +4367,22 @@ static int brightness_set(int value)
 {
 	int cmos_cmd, inc, i, res;
 	int current_value;
+	int command_bits;
 
-	if (value > ((tp_features.bright_16levels)? 15 : 7))
+	if (value > ((tp_features.bright_16levels)? 15 : 7) ||
+	    value < 0)
 		return -EINVAL;
 
 	res = mutex_lock_interruptible(&brightness_mutex);
 	if (res < 0)
 		return res;
 
-	current_value = brightness_get(NULL);
-	if (current_value < 0) {
-		res = current_value;
+	res = brightness_get_raw(&current_value);
+	if (res < 0)
 		goto errout;
-	}
+
+	command_bits = current_value & TP_EC_BACKLIGHT_CMDMSK;
+	current_value &= TP_EC_BACKLIGHT_LVLMSK;
 
 	cmos_cmd = value > current_value ?
 			TP_CMOS_BRIGHTNESS_UP :
@@ -4374,7 +4397,8 @@ static int brightness_set(int value)
 			goto errout;
 		}
 		if ((brightness_mode & 1) &&
-		    !acpi_ec_write(brightness_offset, i + inc)) {
+		    !acpi_ec_write(TP_EC_BACKLIGHT,
+				   (i + inc) | command_bits)) {
 			res = -EIO;
 			goto errout;;
 		}
@@ -4397,6 +4421,17 @@ static int brightness_update_status(struct backlight_device *bd)
 				bd->props.brightness : 0);
 }
 
+static int brightness_get(struct backlight_device *bd)
+{
+	int status, res;
+
+	res = brightness_get_raw(&status);
+	if (res < 0)
+		return 0; /* FIXME: teach backlight about error handling */
+
+	return status & TP_EC_BACKLIGHT_LVLMSK;
+}
+
 static struct backlight_ops ibm_backlight_data = {
 	.get_brightness = brightness_get,
 	.update_status  = brightness_update_status,
@@ -4461,8 +4496,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
 	if (brightness_mode > 3)
 		return -EINVAL;
 
-	b = brightness_get(NULL);
-	if (b < 0)
+	if (brightness_get_raw(&b) < 0)
 		return 1;
 
 	if (tp_features.bright_16levels)
@@ -4480,7 +4514,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
 
 	ibm_backlight_device->props.max_brightness =
 				(tp_features.bright_16levels)? 15 : 7;
-	ibm_backlight_device->props.brightness = b;
+	ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
 	backlight_update_status(ibm_backlight_device);
 
 	return 0;
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#44 lore raw

PATCH 161/171 ACPI: thinkpad-acpi: claim tpacpi as an official short handle

In reply to Len Brown

From: Henrique de Moraes Holschuh <[email protected]>

Unfortunately, a lot of stuff in the kernel has size limitations, so "thinkpad-acpi" ends up eating up too much real estate. We were using "tpacpi" in symbols already, but this shorthand was not visible to userland.

Document that the driver will use tpacpi as a short hand where necessary, and use it to name the kernel thread for NVRAM polling (now named "ktpacpi_nvramd").

Also, register a module alias with the shorthand. One can refer to the module using the shorthand name.

---
 Documentation/laptops/thinkpad-acpi.txt |    5 +++++
 drivers/misc/thinkpad_acpi.c            |    8 ++++++--
 2 files changed, 11 insertions(+), 2 deletions(-)
Documentation/laptops/thinkpad-acpi.txt +5 -0
index bbc8275..0f403ff 100644
@@ -18,6 +18,11 @@ This driver used to be named ibm-acpi until kernel 2.6.21 and release
 moved to the drivers/misc tree and renamed to thinkpad-acpi for kernel
 2.6.22, and release 0.14.
 
+The driver is named "thinkpad-acpi".  In some places, like module
+names, "thinkpad_acpi" is used because of userspace issues.
+
+"tpacpi" is used as a shorthand where "thinkpad-acpi" would be too
+long due to lenght limitations on some Linux kernel versions.
 
 Status
 ------
drivers/misc/thinkpad_acpi.c +6 -2
index 1a26423..f23acc8 100644
@@ -133,8 +133,11 @@ enum {
 #define TPACPI_PROC_DIR "ibm"
 #define TPACPI_ACPI_EVENT_PREFIX "ibm"
 #define TPACPI_DRVR_NAME TPACPI_FILE
+#define TPACPI_DRVR_SHORTNAME "tpacpi"
 #define TPACPI_HWMON_DRVR_NAME TPACPI_NAME "_hwmon"
 
+#define TPACPI_NVRAM_KTHREAD_NAME "ktpacpi_nvramd"
+
 #define TPACPI_MAX_ACPI_ARGS 3
 
 /* Debugging */
@@ -1522,8 +1525,7 @@ static void hotkey_poll_setup(int may_warn)
 	    (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) {
 		if (!tpacpi_hotkey_task) {
 			tpacpi_hotkey_task = kthread_run(hotkey_kthread,
-							 NULL,
-							 TPACPI_FILE "d");
+					NULL, TPACPI_NVRAM_KTHREAD_NAME);
 			if (IS_ERR(tpacpi_hotkey_task)) {
 				tpacpi_hotkey_task = NULL;
 				printk(TPACPI_ERR
@@ -6315,6 +6317,8 @@ static int __init thinkpad_acpi_module_init(void)
 /* Please remove this in year 2009 */
 MODULE_ALIAS("ibm_acpi");
 
+MODULE_ALIAS(TPACPI_DRVR_SHORTNAME);
+
 /*
  * DMI matching for module autoloading
  *
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#45 lore raw

PATCH 162/171 ACPI: thinkpad-acpi: prepare light and LED for sysfs support

In reply to Len Brown

From: Henrique de Moraes Holschuh <[email protected]>

Do some preparatory work to add sysfs support to the thinklight and thinkpad leds driver.

---
 drivers/misc/Kconfig         |    2 +
 drivers/misc/thinkpad_acpi.c |  191 ++++++++++++++++++++++++++++++------------
 2 files changed, 138 insertions(+), 55 deletions(-)
drivers/misc/Kconfig +2 -0
index 297a48f..3a5d769 100644
@@ -245,6 +245,8 @@ config THINKPAD_ACPI
 	select HWMON
 	select NVRAM
 	depends on INPUT
+	select NEW_LEDS
+	select LEDS_CLASS
 	---help---
 	  This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
 	  support for Fn-Fx key combinations, Bluetooth control, video
drivers/misc/thinkpad_acpi.c +136 -55

290 lines not on this page · raw message

Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#46 lore raw

PATCH 163/171 ACPI: thinkpad-acpi: add sysfs led class support for thinklight (v3.1)

In reply to Len Brown

From: Henrique de Moraes Holschuh <[email protected]>

Add a sysfs led class interface to the thinklight (light subdriver).

---
 Documentation/laptops/thinkpad-acpi.txt |   25 +++++++++++---
 drivers/misc/thinkpad_acpi.c            |   57 ++++++++++++++++++++++++++++++-
 2 files changed, 76 insertions(+), 6 deletions(-)
Documentation/laptops/thinkpad-acpi.txt +20 -5
index 0f403ff..22c1ac4 100644
@@ -692,16 +692,31 @@ while others are still having problems. For more information:
 
 https://bugs.freedesktop.org/show_bug.cgi?id=2000
 
-ThinkLight control -- /proc/acpi/ibm/light
-------------------------------------------
+ThinkLight control
+------------------
+
+procfs: /proc/acpi/ibm/light
+sysfs attributes: as per led class, for the "tpacpi::thinklight" led
+
+procfs notes:
 
-The current status of the ThinkLight can be found in this file. A few
-models which do not make the status available will show it as
-"unknown". The available commands are:
+The ThinkLight status can be read and set through the procfs interface.  A
+few models which do not make the status available will show the ThinkLight
+status as "unknown". The available commands are:
 
 	echo on  > /proc/acpi/ibm/light
 	echo off > /proc/acpi/ibm/light
 
+sysfs notes:
+
+The ThinkLight sysfs interface is documented by the led class
+documentation, in Documentation/leds-class.txt.  The ThinkLight led name
+is "tpacpi::thinklight".
+
+Due to limitations in the sysfs led class, if the status of the thinklight
+cannot be read or if it is unknown, thinkpad-acpi will report it as "off".
+It is impossible to know if the status returned through sysfs is valid.
+
 Docking / undocking -- /proc/acpi/ibm/dock
 ------------------------------------------
 
drivers/misc/thinkpad_acpi.c +56 -1

82 lines not on this page · raw message

Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#47 lore raw

PATCH 164/171 ACPI: thinkpad-acpi: add sysfs led class support to thinkpad leds (v3.1)

In reply to Len Brown

From: Henrique de Moraes Holschuh <[email protected]>

Add a sysfs led class interface to the led subdriver.

---
 Documentation/laptops/thinkpad-acpi.txt |   47 +++++++++--
 drivers/misc/thinkpad_acpi.c            |  136 ++++++++++++++++++++++++++++++-
 2 files changed, 176 insertions(+), 7 deletions(-)
Documentation/laptops/thinkpad-acpi.txt +41 -6
index 22c1ac4..27ca0f9 100644
@@ -875,28 +875,63 @@ The cmos command interface is prone to firmware split-brain problems, as
 in newer ThinkPads it is just a compatibility layer.  Do not use it, it is
 exported just as a debug tool.
 
-LED control -- /proc/acpi/ibm/led
----------------------------------
+LED control
+-----------
 
-Some of the LED indicators can be controlled through this feature. The
-available commands are:
+procfs: /proc/acpi/ibm/led
+sysfs attributes: as per led class, see below for names
+
+Some of the LED indicators can be controlled through this feature.  On
+some older ThinkPad models, it is possible to query the status of the
+LED indicators as well.  Newer ThinkPads cannot query the real status
+of the LED indicators.
+
+procfs notes:
+
+The available commands are:
 
 	echo '<led number> on' >/proc/acpi/ibm/led
 	echo '<led number> off' >/proc/acpi/ibm/led
 	echo '<led number> blink' >/proc/acpi/ibm/led
 
 The <led number> range is 0 to 7. The set of LEDs that can be
-controlled varies from model to model. Here is the mapping on the X40:
+controlled varies from model to model. Here is the common ThinkPad
+mapping:
 
 	0 - power
 	1 - battery (orange)
 	2 - battery (green)
-	3 - UltraBase
+	3 - UltraBase/dock
 	4 - UltraBay
+	5 - UltraBase battery slot
+	6 - (unknown)
 	7 - standby
 
 All of the above can be turned on and off and can be made to blink.
 
+sysfs notes:
+
+The ThinkPad LED sysfs interface is described in detail by the led class
+documentation, in Documentation/leds-class.txt.
+
+The leds are named (in LED ID order, from 0 to7):
+"tpacpi::power", "tpacpi:orange:batt", "tpacpi:green:batt",
+"tpacpi::dock_active", "tpacpi::bay_active", "tpacpi::dock_batt",
+"tpacpi::unknown_led", "tpacpi::standby".
+
+Due to limitations in the sysfs led class, if the status of the LED
+indicators cannot be read due to an error, thinkpad-acpi will report it as
+a brightness of zero (same as LED off).
+
+If the thinkpad firmware doesn't support reading the current status,
+trying to read the current LED brightness will just return whatever
+brightness was last written to that attribute.
+
+These LEDs can blink using hardware acceleration.  To request that a
+ThinkPad indicator LED should blink in hardware accelerated mode, use the
+"timer" trigger, and leave the delay_on and delay_off parameters set to
+zero (to request hardware acceleration autodetection).
+
 ACPI sounds -- /proc/acpi/ibm/beep
 ----------------------------------
 
drivers/misc/thinkpad_acpi.c +135 -1

184 lines not on this page · raw message

Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#48 lore raw

PATCH 165/171 ACPI: thinkpad-acpi: fluff really minor fix

In reply to Len Brown

From: Henrique de Moraes Holschuh <[email protected]>

Fix a minor (nano?) thing that bothered me at exactly at the wrong time.

---
 drivers/misc/thinkpad_acpi.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/misc/thinkpad_acpi.c +1 -1
index 547324e..0d05719 100644
@@ -3880,7 +3880,7 @@ static int led_set_status(unsigned int led, enum led_status_t ledstatus)
 					      led * led_exp_hlbl[ledstatus]);
 			if (rc >= 0)
 				rc = ec_write(TPACPI_LED_EC_HLCL,
-					       led * led_exp_hlcl[ledstatus]);
+					      led * led_exp_hlcl[ledstatus]);
 			break;
 	case TPACPI_LED_NEW:
 			/* all others */
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#49 lore raw

PATCH 166/171 ACPI: thinkpad-acpi: use a private workqueue

In reply to Len Brown

From: Henrique de Moraes Holschuh <[email protected]>

Switch all task workers to a private thinkpad-acpi workqueue.

This way, we don't risk causing trouble for other tasks scheduled to the default work queue, as our workers end up needing to access the ACPI EC, run ACPI AML code, trigger SMI traps... and none of those are exactly known to be fast, simple operations.

---
 drivers/misc/thinkpad_acpi.c |   26 +++++++++++++++++++-------
 1 files changed, 19 insertions(+), 7 deletions(-)
drivers/misc/thinkpad_acpi.c +19 -7
index 0d05719..22ba93c 100644
@@ -140,6 +140,7 @@ enum {
 #define TPACPI_HWMON_DRVR_NAME TPACPI_NAME "_hwmon"
 
 #define TPACPI_NVRAM_KTHREAD_NAME "ktpacpi_nvramd"
+#define TPACPI_WORKQUEUE_NAME "ktpacpid"
 
 #define TPACPI_MAX_ACPI_ARGS 3
 
@@ -272,6 +273,8 @@ static enum {
 static int experimental;
 static u32 dbg_level;
 
+static struct workqueue_struct *tpacpi_wq;
+
 /* Special LED class that can defer work */
 struct tpacpi_led_classdev {
 	struct led_classdev led_classdev;
@@ -3297,7 +3300,7 @@ static void light_sysfs_set(struct led_classdev *led_cdev,
 			     struct tpacpi_led_classdev,
 			     led_classdev);
 	data->new_brightness = brightness;
-	schedule_work(&data->work);
+	queue_work(tpacpi_wq, &data->work);
 }
 
 static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev)
@@ -3354,7 +3357,7 @@ static void light_exit(void)
 {
 	led_classdev_unregister(&tpacpi_led_thinklight.led_classdev);
 	if (work_pending(&tpacpi_led_thinklight.work))
-		flush_scheduled_work();
+		flush_workqueue(tpacpi_wq);
 }
 
 static int light_read(char *p)
@@ -3924,7 +3927,7 @@ static void led_sysfs_set(struct led_classdev *led_cdev,
 			     struct tpacpi_led_classdev, led_classdev);
 
 	data->new_brightness = brightness;
-	schedule_work(&data->work);
+	queue_work(tpacpi_wq, &data->work);
 }
 
 static int led_sysfs_blink_set(struct led_classdev *led_cdev,
@@ -3942,7 +3945,7 @@ static int led_sysfs_blink_set(struct led_classdev *led_cdev,
 		return -EINVAL;
 
 	data->new_brightness = TPACPI_LED_BLINK;
-	schedule_work(&data->work);
+	queue_work(tpacpi_wq, &data->work);
 
 	return 0;
 }
@@ -5407,11 +5410,11 @@ static void fan_watchdog_reset(void)
 	if (fan_watchdog_maxinterval > 0 &&
 	    tpacpi_lifecycle != TPACPI_LIFE_EXITING) {
 		fan_watchdog_active = 1;
-		if (!schedule_delayed_work(&fan_watchdog_task,
+		if (!queue_delayed_work(tpacpi_wq, &fan_watchdog_task,
 				msecs_to_jiffies(fan_watchdog_maxinterval
 						 * 1000))) {
 			printk(TPACPI_ERR
-			       "failed to schedule the fan watchdog, "
+			       "failed to queue the fan watchdog, "
 			       "watchdog will not trigger\n");
 		}
 	} else
@@ -5781,7 +5784,7 @@ static void fan_exit(void)
 			   &driver_attr_fan_watchdog);
 
 	cancel_delayed_work(&fan_watchdog_task);
-	flush_scheduled_work();
+	flush_workqueue(tpacpi_wq);
 }
 
 static int fan_read(char *p)
@@ -6435,6 +6438,9 @@ static void thinkpad_acpi_module_exit(void)
 	if (proc_dir)
 		remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir);
 
+	if (tpacpi_wq)
+		destroy_workqueue(tpacpi_wq);
+
 	kfree(thinkpad_id.bios_version_str);
 	kfree(thinkpad_id.ec_version_str);
 	kfree(thinkpad_id.model_str);
@@ -6465,6 +6471,12 @@ static int __init thinkpad_acpi_module_init(void)
 	TPACPI_ACPIHANDLE_INIT(ecrd);
 	TPACPI_ACPIHANDLE_INIT(ecwr);
 
+	tpacpi_wq = create_singlethread_workqueue(TPACPI_WORKQUEUE_NAME);
+	if (!tpacpi_wq) {
+		thinkpad_acpi_module_exit();
+		return -ENOMEM;
+	}
+
 	proc_dir = proc_mkdir(TPACPI_PROC_DIR, acpi_root_dir);
 	if (!proc_dir) {
 		printk(TPACPI_ERR
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#50 lore raw

PATCH 167/171 ACPI: thinkpad-acpi: fix selects in Kconfig

In reply to Len Brown

From: Henrique de Moraes Holschuh <[email protected]>

Add missing select for BACKLIGHT_LCD_SUPPORT, as select doesn't select the dependencies of a symbol for us.

Also, "select INPUT" in Kconfig. We are not an Input device, nor are we anywhere close to the input subsystem in the Kconfig tree, so using "depends on INPUT" is not user-friendly at all.

---
 drivers/misc/Kconfig |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
drivers/misc/Kconfig +2 -1
index 3a5d769..2e21794 100644
@@ -241,10 +241,11 @@ config SONYPI_COMPAT
 config THINKPAD_ACPI
 	tristate "ThinkPad ACPI Laptop Extras"
 	depends on X86 && ACPI
+	select BACKLIGHT_LCD_SUPPORT
 	select BACKLIGHT_CLASS_DEVICE
 	select HWMON
 	select NVRAM
-	depends on INPUT
+	select INPUT
 	select NEW_LEDS
 	select LEDS_CLASS
 	---help---
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#51 lore raw

PATCH 168/171 ACPI: thinkpad-acpi: bump up version to 0.20

In reply to Len Brown

From: Henrique de Moraes Holschuh <[email protected]>

Full LED sysfs support, and the rest of the assorted minor fixes and enhancements are a good reason to checkpoint a new version...

---
 Documentation/laptops/thinkpad-acpi.txt |    4 ++--
 drivers/misc/thinkpad_acpi.c            |    2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)
Documentation/laptops/thinkpad-acpi.txt +2 -2
index 27ca0f9..a2ea504 100644
@@ -1,7 +1,7 @@
 		     ThinkPad ACPI Extras Driver
 
-                            Version 0.19
-                         January 06th, 2008
+                            Version 0.20
+                          April 09th, 2008
 
                Borislav Deianov <[email protected]>
              Henrique de Moraes Holschuh <[email protected]>
drivers/misc/thinkpad_acpi.c +1 -1
index 22ba93c..76e3ae3 100644
@@ -21,7 +21,7 @@
  *  02110-1301, USA.
  */
 
-#define TPACPI_VERSION "0.19"
+#define TPACPI_VERSION "0.20"
 #define TPACPI_SYSFS_VERSION 0x020200
 
 /*
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#52 lore raw

PATCH 170/171 ACPI: check a return value correctly in acpi_power_get_context()

In reply to Len Brown

From: Li Zefan <[email protected]>

We should check *resource != NULL rather than resource != NULL, which will be always true.

---
 drivers/acpi/power.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/acpi/power.c +1 -1
index 76bf6d9..f2a76ac 100644
@@ -121,7 +121,7 @@ acpi_power_get_context(acpi_handle handle,
 	}
 
 	*resource = acpi_driver_data(device);
-	if (!resource)
+	if (!*resource)
 		return -ENODEV;
 
 	return 0;
Signature · 1 line
1.5.5.1.99.gf0ec4
author reviewer
#53 lore raw

PATCH 171/171 thinkpad_acpi: fix possible NULL pointer dereference if kstrdup failed

In reply to Len Brown

From: Cyrill Gorcunov <[email protected]>

---
 drivers/misc/thinkpad_acpi.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/misc/thinkpad_acpi.c +1 -1
index 6cb7812..31115c9 100644
@@ -5826,7 +5826,7 @@ static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
 
 	tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION),
 					GFP_KERNEL);
-	if (strnicmp(tp->model_str, "ThinkPad", 8) != 0) {
+	if (tp->model_str && strnicmp(tp->model_str, "ThinkPad", 8) != 0) {
 		kfree(tp->model_str);
 		tp->model_str = NULL;
 	}
Signature · 1 line
1.5.5.1.99.gf0ec4