From: Len Brown <len.brown@intel.com>
To: linux-acpi@vger.kernel.org
Cc: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>,
Len Brown <len.brown@intel.com>
Subject: [PATCH 10/20] ACPI: ec: fix race in status register access
Date: Fri, 9 Mar 2007 22:49:28 -0500 [thread overview]
Message-ID: <11734985863491-git-send-email-len.brown@intel.com> (raw)
Message-ID: <c70b5fb8f6869f720160f774f9915730a6371d9c.1173498420.git.len.brown@intel.com> (raw)
In-Reply-To: <11734985862291-git-send-email-len.brown@intel.com>
In-Reply-To: <7292576043666ff39946dee14641fe719ba8c7e8.1173498420.git.len.brown@intel.com>
From: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Delay the read of the EC status register until
after the event that caused it occurs -- otherwise
it is possible to read and act on stale status that was
associated with the previous event.
Do this with a perpetually incrementing "event_count" to detect
when a new event occurs and it is safe to read status.
There is no workaround for polling mode -- it is inherently
exposed to reading and acting on stale status, since it
doesn't have an interrupt to tell it the event completed.
http://bugzilla.kernel.org/show_bug.cgi?id=8110
Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/acpi/ec.c | 40 +++++++++++++++++++++++-----------------
1 files changed, 23 insertions(+), 17 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index ab68883..1e525dd 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -100,6 +100,7 @@ static struct acpi_ec {
unsigned long global_lock;
struct mutex lock;
atomic_t query_pending;
+ atomic_t event_count;
atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */
wait_queue_head_t wait;
} *ec_ecdt;
@@ -131,10 +132,12 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
outb(data, ec->data_addr);
}
-static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
+static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event,
+ unsigned old_count)
{
u8 status = acpi_ec_read_status(ec);
-
+ if (old_count == atomic_read(&ec->event_count))
+ return 0;
if (event == ACPI_EC_EVENT_OBF_1) {
if (status & ACPI_EC_FLAG_OBF)
return 1;
@@ -146,19 +149,19 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
return 0;
}
-static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event)
+static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, unsigned count)
{
if (acpi_ec_mode == EC_POLL) {
unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
while (time_before(jiffies, delay)) {
- if (acpi_ec_check_status(ec, event))
+ if (acpi_ec_check_status(ec, event, 0))
return 0;
}
} else {
if (wait_event_timeout(ec->wait,
- acpi_ec_check_status(ec, event),
+ acpi_ec_check_status(ec, event, count),
msecs_to_jiffies(ACPI_EC_DELAY)) ||
- acpi_ec_check_status(ec, event)) {
+ acpi_ec_check_status(ec, event, 0)) {
return 0;
} else {
printk(KERN_ERR PREFIX "acpi_ec_wait timeout,"
@@ -225,21 +228,22 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
u8 * rdata, unsigned rdata_len)
{
int result = 0;
-
+ unsigned count = atomic_read(&ec->event_count);
acpi_ec_write_cmd(ec, command);
for (; wdata_len > 0; --wdata_len) {
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count);
if (result) {
printk(KERN_ERR PREFIX
"write_cmd timeout, command = %d\n", command);
goto end;
}
+ count = atomic_read(&ec->event_count);
acpi_ec_write_data(ec, *(wdata++));
}
if (!rdata_len) {
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count);
if (result) {
printk(KERN_ERR PREFIX
"finish-write timeout, command = %d\n", command);
@@ -250,13 +254,13 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
}
for (; rdata_len > 0; --rdata_len) {
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, count);
if (result) {
printk(KERN_ERR PREFIX "read timeout, command = %d\n",
command);
goto end;
}
-
+ count = atomic_read(&ec->event_count);
*(rdata++) = acpi_ec_read_data(ec);
}
end:
@@ -288,7 +292,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
/* Make sure GPE is enabled before doing transaction */
acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0);
if (status) {
printk(KERN_DEBUG PREFIX
"input buffer is not empty, aborting transaction\n");
@@ -369,8 +373,8 @@ int ec_write(u8 addr, u8 val)
EXPORT_SYMBOL(ec_write);
int ec_transaction(u8 command,
- const u8 * wdata, unsigned wdata_len,
- u8 * rdata, unsigned rdata_len)
+ const u8 * wdata, unsigned wdata_len,
+ u8 * rdata, unsigned rdata_len)
{
struct acpi_ec *ec;
@@ -435,7 +439,7 @@ static u32 acpi_ec_gpe_handler(void *data)
acpi_status status = AE_OK;
u8 value;
struct acpi_ec *ec = (struct acpi_ec *)data;
-
+ atomic_inc(&ec->event_count);
if (acpi_ec_mode == EC_INTR) {
wake_up(&ec->wait);
}
@@ -633,6 +637,7 @@ static int acpi_ec_add(struct acpi_device *device)
ec->uid = -1;
mutex_init(&ec->lock);
atomic_set(&ec->query_pending, 0);
+ atomic_set(&ec->event_count, 1);
if (acpi_ec_mode == EC_INTR) {
atomic_set(&ec->leaving_burst, 1);
init_waitqueue_head(&ec->wait);
@@ -807,6 +812,7 @@ acpi_fake_ecdt_callback(acpi_handle handle,
acpi_status status;
mutex_init(&ec_ecdt->lock);
+ atomic_set(&ec->event_count, 1);
if (acpi_ec_mode == EC_INTR) {
init_waitqueue_head(&ec_ecdt->wait);
}
@@ -888,6 +894,7 @@ static int __init acpi_ec_get_real_ecdt(void)
return -ENOMEM;
mutex_init(&ec_ecdt->lock);
+ atomic_set(&ec_ecdt->event_count, 1);
if (acpi_ec_mode == EC_INTR) {
init_waitqueue_head(&ec_ecdt->wait);
}
@@ -1016,8 +1023,7 @@ static int __init acpi_ec_set_intr_mode(char *str)
acpi_ec_mode = EC_POLL;
}
acpi_ec_driver.ops.add = acpi_ec_add;
- printk(KERN_NOTICE PREFIX "%s mode.\n",
- intr ? "interrupt" : "polling");
+ printk(KERN_NOTICE PREFIX "%s mode.\n", intr ? "interrupt" : "polling");
return 1;
}
--
1.5.0.3.310.g05ef5
next prev parent reply other threads:[~2007-03-10 3:49 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-03-10 3:49 ACPI patches for release to 2.6.21-rc Len Brown
[not found] ` <7292576043666ff39946dee14641fe719ba8c7e8.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` [PATCH 01/20] ACPI: fix S3 fan resume issue Len Brown
[not found] ` <adb005818b71e9476581a1de5742e2f427ac9e2b.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` [PATCH 02/20] ACPI: ibm-acpi: fix initial status of backlight device Len Brown
[not found] ` <2bc808a8c4821a8ef4e3dc35b8fc577a9d2c6f0d.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` [PATCH 03/20] ACPI: ibm-acpi: make ibm-acpi bay support optional Len Brown
[not found] ` <690b8d9d54941c90af1d43b0cc24903d20386f5b.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` [PATCH 04/20] ACPI: Altix: cannot register acpi bus driver before bus scan Len Brown
[not found] ` <3fd0b2d9ad7612f249e5516d887ab7c61b24ddb9.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` [PATCH 05/20] ACPI: Altix: reinitialize acpi tables Len Brown
[not found] ` <610a3d069665ba2b27e42c90129ce640c4d6e515.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` [PATCH 06/20] ACPICA: Fix ACPI Global Lock re-entrancy Len Brown
[not found] ` <8607c673bdd593d4ce439a36412a213a8efb282b.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` [PATCH 07/20] sony-laptop: fix uninitialised variable Len Brown
[not found] ` <03d926f82800f32642b32ba547c7a002a371a78f.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` [PATCH 08/20] ACPI: Add kernel-parameters hint that acpi=off doesn't work on IA64 Len Brown
[not found] ` <ff24ba74b6d3befbfbafa142582211b5a6095d45.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` [PATCH 09/20] ACPI: ThinkPad Z60m: usb mouse stops working after suspend to RAM Len Brown
[not found] ` <c70b5fb8f6869f720160f774f9915730a6371d9c.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` Len Brown [this message]
2007-03-10 7:29 ` [PATCH 10/20] ACPI: ec: fix race in status register access Alexey Starikovskiy
2007-03-10 7:34 ` Len Brown
[not found] ` <74586fca38109d2fc75daf678635928f64b4ccec.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` [PATCH 11/20] ACPI: fix Thinkpad 600/600E/600X interrupts Len Brown
[not found] ` <2f894ef9c8b36a35d80709bedca276d2fc691941.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` [PATCH 12/20] ACPI: fix boot hang w/o "noapic" on MSI MS-6390-L Len Brown
[not found] ` <c9bf296b6467968ecb9d988e7ed754a19c2e63d9.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` [PATCH 13/20] ACPI: ibm-acpi: improve backlight power handling Len Brown
[not found] ` <362ea087db9d99bb0cf79479544dfafa9e18c300.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` [PATCH 14/20] ACPI: fix parallel port IRQ after resume from S3 Len Brown
[not found] ` <d7930085c28d295b573f6862ff863ccbb8a580ce.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` [PATCH 15/20] ACPI: repair nvidia early quirk breakage on x86_64 Len Brown
[not found] ` <df33c77e3981e71afc8727ee5c432ba1a1bba68c.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` [PATCH 16/20] libata-acpi: allow _GTF on SATA, but disable on PATA for now Len Brown
[not found] ` <117349 85922550-git-send-email-len.brown@intel.com>
[not found] ` <f110ef58e6c9bd562999247c5e8a5b8e722fbd11.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` [PATCH 17/20] asus-laptop: make code static Len Brown
[not found] ` <98fb8fe10f4b88170f578d8c33eaa2315d73b4f7.1173498420.git.len.brown@intel.com>
2007-03-10 3:49 ` [PATCH 19/20] ACPI: video: Fix spelling and grammar mistakes Len Brown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=11734985863491-git-send-email-len.brown@intel.com \
--to=len.brown@intel.com \
--cc=alexey.y.starikovskiy@intel.com \
--cc=linux-acpi@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).