* [PATCH] Don't disable interrupts during EC access
@ 2004-11-15 22:56 Andi Kleen
0 siblings, 0 replies; 16+ messages in thread
From: Andi Kleen @ 2004-11-15 22:56 UTC (permalink / raw)
To: acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
On VIA chipset + A64 laptops the EC access can take a long time. This causes
the system to lose timer interrupts while ACPI waits for the event,
and causes it to always fallback to slower timer sources.
This patch replaces the spinlock with a semaphore and sleeps instead
of busy polling. This should also save power.
Signed-off-by: Andi Kleen <ak-l3A5Bk7waGM@public.gmane.org>
-Andi
diff -u linux/drivers/acpi/ec.c-o linux/drivers/acpi/ec.c
--- linux/drivers/acpi/ec.c-o 2004-10-26 09:57:32.000000000 -0700
+++ linux/drivers/acpi/ec.c 2004-11-15 12:55:58.000000000 -0800
@@ -29,10 +29,12 @@
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/actypes.h>
+#include <asm/msr.h>
#define _COMPONENT ACPI_EC_COMPONENT
ACPI_MODULE_NAME ("acpi_ec")
@@ -53,7 +55,7 @@
#define ACPI_EC_EVENT_IBE 0x02 /* Input buffer empty */
#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */
-#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */
+#define ACPI_EC_UDELAY_COUNT 10 /* Wait 10ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
#define ACPI_EC_COMMAND_READ 0x80
@@ -85,7 +87,6 @@
struct acpi_generic_address command_addr;
struct acpi_generic_address data_addr;
unsigned long global_lock;
- spinlock_t lock;
};
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
@@ -116,7 +117,7 @@
acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr);
if (acpi_ec_status & ACPI_EC_FLAG_OBF)
return 0;
- udelay(ACPI_EC_UDELAY);
+ msleep(1);
} while (--i>0);
break;
case ACPI_EC_EVENT_IBE:
@@ -124,16 +125,16 @@
acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr);
if (!(acpi_ec_status & ACPI_EC_FLAG_IBF))
return 0;
- udelay(ACPI_EC_UDELAY);
+ msleep(1);
} while (--i>0);
break;
default:
return -EINVAL;
}
-
return -ETIME;
}
+static DECLARE_MUTEX(ec_mutex);
static int
acpi_ec_read (
@@ -143,7 +144,6 @@
{
acpi_status status = AE_OK;
int result = 0;
- unsigned long flags = 0;
u32 glk = 0;
ACPI_FUNCTION_TRACE("acpi_ec_read");
@@ -158,8 +158,9 @@
if (ACPI_FAILURE(status))
return_VALUE(-ENODEV);
}
-
- spin_lock_irqsave(&ec->lock, flags);
+
+ WARN_ON(in_interrupt());
+ down(&ec_mutex);
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->command_addr);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
@@ -173,16 +174,15 @@
acpi_hw_low_level_read(8, data, &ec->data_addr);
-
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
*data, address));
+
end:
- spin_unlock_irqrestore(&ec->lock, flags);
+ up(&ec_mutex);
if (ec->global_lock)
acpi_release_global_lock(glk);
-
return_VALUE(result);
}
@@ -195,7 +195,6 @@
{
int result = 0;
acpi_status status = AE_OK;
- unsigned long flags = 0;
u32 glk = 0;
ACPI_FUNCTION_TRACE("acpi_ec_write");
@@ -209,7 +208,8 @@
return_VALUE(-ENODEV);
}
- spin_lock_irqsave(&ec->lock, flags);
+ WARN_ON(in_interrupt());
+ down(&ec_mutex);
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->command_addr);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
@@ -230,7 +230,7 @@
data, address));
end:
- spin_unlock_irqrestore(&ec->lock, flags);
+ up(&ec_mutex);
if (ec->global_lock)
acpi_release_global_lock(glk);
@@ -287,7 +287,6 @@
{
int result = 0;
acpi_status status = AE_OK;
- unsigned long flags = 0;
u32 glk = 0;
ACPI_FUNCTION_TRACE("acpi_ec_query");
@@ -308,7 +307,7 @@
* Note that successful completion of the query causes the ACPI_EC_SCI
* bit to be cleared (and thus clearing the interrupt source).
*/
- spin_lock_irqsave(&ec->lock, flags);
+ down(&ec_mutex);
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, &ec->command_addr);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
@@ -320,7 +319,7 @@
result = -ENODATA;
end:
- spin_unlock_irqrestore(&ec->lock, flags);
+ up(&ec_mutex);
if (ec->global_lock)
acpi_release_global_lock(glk);
@@ -344,7 +343,6 @@
{
struct acpi_ec *ec = (struct acpi_ec *) ec_cxt;
u32 value = 0;
- unsigned long flags = 0;
static char object_name[5] = {'_','Q','0','0','\0'};
const char hex[] = {'0','1','2','3','4','5','6','7',
'8','9','A','B','C','D','E','F'};
@@ -354,9 +352,9 @@
if (!ec_cxt)
goto end;
- spin_lock_irqsave(&ec->lock, flags);
+ down(&ec_mutex);
acpi_hw_low_level_read(8, &value, &ec->command_addr);
- spin_unlock_irqrestore(&ec->lock, flags);
+ up(&ec_mutex);
/* TBD: Implement asynch events!
* NOTE: All we care about are EC-SCI's. Other EC events are
@@ -588,7 +586,6 @@
ec->handle = device->handle;
ec->uid = -1;
- ec->lock = SPIN_LOCK_UNLOCKED;
strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_EC_CLASS);
acpi_driver_data(device) = ec;
@@ -802,7 +799,6 @@
ec_ecdt->status_addr = ecdt_ptr->ec_control;
ec_ecdt->data_addr = ecdt_ptr->ec_data;
ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit;
- ec_ecdt->lock = SPIN_LOCK_UNLOCKED;
/* use the GL just to be safe */
ec_ecdt->global_lock = TRUE;
ec_ecdt->uid = ecdt_ptr->uid;
-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
^ permalink raw reply [flat|nested] 16+ messages in thread
* RE: [PATCH] Don't disable interrupts during EC access
@ 2004-11-16 6:15 Yu, Luming
2004-11-16 12:16 ` Matthew Wilcox
0 siblings, 1 reply; 16+ messages in thread
From: Yu, Luming @ 2004-11-16 6:15 UTC (permalink / raw)
To: Andi Kleen, acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f; +Cc: Fu, Michael
Andi,
This patch seems to break the atomic operation.
The original code enclosed by spin_lock_irqsave/spin_unlock_irqresotre is trying to make sure the first operation to EC_COMMAND
register , and the second operation to EC_DATA register belong to one atomic transaction.
Thanks
Luming
>-----Original Message-----
>From: acpi-devel-admin-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
>[mailto:acpi-devel-admin-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org] On Behalf Of Andi Kleen
>Sent: 2004年11月16日 6:56
>To: acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
>Subject: [ACPI] [PATCH] Don't disable interrupts during EC access
>
>
>On VIA chipset + A64 laptops the EC access can take a long
>time. This causes
>the system to lose timer interrupts while ACPI waits for the event,
>and causes it to always fallback to slower timer sources.
>
>This patch replaces the spinlock with a semaphore and sleeps instead
>of busy polling. This should also save power.
>
>Signed-off-by: Andi Kleen <ak-l3A5Bk7waGM@public.gmane.org>
>
>-Andi
>
>diff -u linux/drivers/acpi/ec.c-o linux/drivers/acpi/ec.c
>--- linux/drivers/acpi/ec.c-o 2004-10-26 09:57:32.000000000 -0700
>+++ linux/drivers/acpi/ec.c 2004-11-15 12:55:58.000000000 -0800
>@@ -29,10 +29,12 @@
> #include <linux/types.h>
> #include <linux/delay.h>
> #include <linux/proc_fs.h>
>+#include <linux/interrupt.h>
> #include <asm/io.h>
> #include <acpi/acpi_bus.h>
> #include <acpi/acpi_drivers.h>
> #include <acpi/actypes.h>
>+#include <asm/msr.h>
>
> #define _COMPONENT ACPI_EC_COMPONENT
> ACPI_MODULE_NAME ("acpi_ec")
>@@ -53,7 +55,7 @@
> #define ACPI_EC_EVENT_IBE 0x02 /* Input buffer empty */
>
> #define ACPI_EC_UDELAY 100 /* Poll @ 100us
>increments */
>-#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max.
>during EC ops */
>+#define ACPI_EC_UDELAY_COUNT 10 /* Wait 10ms max.
>during EC ops */
> #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get
>global lock */
>
> #define ACPI_EC_COMMAND_READ 0x80
>@@ -85,7 +87,6 @@
> struct acpi_generic_address command_addr;
> struct acpi_generic_address data_addr;
> unsigned long global_lock;
>- spinlock_t lock;
> };
>
> /* If we find an EC via the ECDT, we need to keep a ptr to
>its context */
>@@ -116,7 +117,7 @@
> acpi_hw_low_level_read(8,
>&acpi_ec_status, &ec->status_addr);
> if (acpi_ec_status & ACPI_EC_FLAG_OBF)
> return 0;
>- udelay(ACPI_EC_UDELAY);
>+ msleep(1);
> } while (--i>0);
> break;
> case ACPI_EC_EVENT_IBE:
>@@ -124,16 +125,16 @@
> acpi_hw_low_level_read(8,
>&acpi_ec_status, &ec->status_addr);
> if (!(acpi_ec_status & ACPI_EC_FLAG_IBF))
> return 0;
>- udelay(ACPI_EC_UDELAY);
>+ msleep(1);
> } while (--i>0);
> break;
> default:
> return -EINVAL;
> }
>-
> return -ETIME;
> }
>
>+static DECLARE_MUTEX(ec_mutex);
>
> static int
> acpi_ec_read (
>@@ -143,7 +144,6 @@
> {
> acpi_status status = AE_OK;
> int result = 0;
>- unsigned long flags = 0;
> u32 glk = 0;
>
> ACPI_FUNCTION_TRACE("acpi_ec_read");
>@@ -158,8 +158,9 @@
> if (ACPI_FAILURE(status))
> return_VALUE(-ENODEV);
> }
>-
>- spin_lock_irqsave(&ec->lock, flags);
>+
>+ WARN_ON(in_interrupt());
>+ down(&ec_mutex);
>
> acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ,
>&ec->command_addr);
> result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
>@@ -173,16 +174,15 @@
>
>
> acpi_hw_low_level_read(8, data, &ec->data_addr);
>-
> ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from
>address [%02x]\n",
> *data, address));
>
>+
> end:
>- spin_unlock_irqrestore(&ec->lock, flags);
>+ up(&ec_mutex);
>
> if (ec->global_lock)
> acpi_release_global_lock(glk);
>-
> return_VALUE(result);
> }
>
>@@ -195,7 +195,6 @@
> {
> int result = 0;
> acpi_status status = AE_OK;
>- unsigned long flags = 0;
> u32 glk = 0;
>
> ACPI_FUNCTION_TRACE("acpi_ec_write");
>@@ -209,7 +208,8 @@
> return_VALUE(-ENODEV);
> }
>
>- spin_lock_irqsave(&ec->lock, flags);
>+ WARN_ON(in_interrupt());
>+ down(&ec_mutex);
>
> acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE,
>&ec->command_addr);
> result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
>@@ -230,7 +230,7 @@
> data, address));
>
> end:
>- spin_unlock_irqrestore(&ec->lock, flags);
>+ up(&ec_mutex);
>
> if (ec->global_lock)
> acpi_release_global_lock(glk);
>@@ -287,7 +287,6 @@
> {
> int result = 0;
> acpi_status status = AE_OK;
>- unsigned long flags = 0;
> u32 glk = 0;
>
> ACPI_FUNCTION_TRACE("acpi_ec_query");
>@@ -308,7 +307,7 @@
> * Note that successful completion of the query causes
>the ACPI_EC_SCI
> * bit to be cleared (and thus clearing the interrupt source).
> */
>- spin_lock_irqsave(&ec->lock, flags);
>+ down(&ec_mutex);
>
> acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY,
>&ec->command_addr);
> result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
>@@ -320,7 +319,7 @@
> result = -ENODATA;
>
> end:
>- spin_unlock_irqrestore(&ec->lock, flags);
>+ up(&ec_mutex);
>
> if (ec->global_lock)
> acpi_release_global_lock(glk);
>@@ -344,7 +343,6 @@
> {
> struct acpi_ec *ec = (struct acpi_ec *) ec_cxt;
> u32 value = 0;
>- unsigned long flags = 0;
> static char object_name[5] = {'_','Q','0','0','\0'};
> const char hex[] =
>{'0','1','2','3','4','5','6','7',
>
>'8','9','A','B','C','D','E','F'};
>@@ -354,9 +352,9 @@
> if (!ec_cxt)
> goto end;
>
>- spin_lock_irqsave(&ec->lock, flags);
>+ down(&ec_mutex);
> acpi_hw_low_level_read(8, &value, &ec->command_addr);
>- spin_unlock_irqrestore(&ec->lock, flags);
>+ up(&ec_mutex);
>
> /* TBD: Implement asynch events!
> * NOTE: All we care about are EC-SCI's. Other EC events are
>@@ -588,7 +586,6 @@
>
> ec->handle = device->handle;
> ec->uid = -1;
>- ec->lock = SPIN_LOCK_UNLOCKED;
> strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
> strcpy(acpi_device_class(device), ACPI_EC_CLASS);
> acpi_driver_data(device) = ec;
>@@ -802,7 +799,6 @@
> ec_ecdt->status_addr = ecdt_ptr->ec_control;
> ec_ecdt->data_addr = ecdt_ptr->ec_data;
> ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit;
>- ec_ecdt->lock = SPIN_LOCK_UNLOCKED;
> /* use the GL just to be safe */
> ec_ecdt->global_lock = TRUE;
> ec_ecdt->uid = ecdt_ptr->uid;
>
>
>-------------------------------------------------------
>This SF.Net email is sponsored by: InterSystems CACHE
>FREE OODBMS DOWNLOAD - A multidimensional database that combines
>robust object and relational technologies, making it a perfect match
>for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
>_______________________________________________
>Acpi-devel mailing list
>Acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
>https://lists.sourceforge.net/lists/listinfo/acpi-devel
>
-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Don't disable interrupts during EC access
2004-11-16 6:15 Yu, Luming
@ 2004-11-16 12:16 ` Matthew Wilcox
[not found] ` <20041116121616.GG1108-+pPCBgu9SkPzIGdyhVEDUDl5KyyQGfY2kSSpQ9I8OhVaa/9Udqfwiw@public.gmane.org>
0 siblings, 1 reply; 16+ messages in thread
From: Matthew Wilcox @ 2004-11-16 12:16 UTC (permalink / raw)
To: Yu, Luming
Cc: Andi Kleen, acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
Fu, Michael
On Tue, Nov 16, 2004 at 02:15:47PM +0800, Yu, Luming wrote:
> Andi,
>
> This patch seems to break the atomic operation.
> The original code enclosed by spin_lock_irqsave/spin_unlock_irqresotre is trying to make sure the first operation to EC_COMMAND
> register , and the second operation to EC_DATA register belong to one atomic transaction.
Why would converting from a spinlock to a semaphore break this?
--
"Next the statesmen will invent cheap lies, putting the blame upon
the nation that is attacked, and every man will be glad of those
conscience-soothing falsities, and will diligently study them, and refuse
to examine any refutations of them; and thus he will by and by convince
himself that the war is just, and will thank God for the better sleep
he enjoys after this process of grotesque self-deception." -- Mark Twain
-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Don't disable interrupts during EC access
[not found] ` <20041116121616.GG1108-+pPCBgu9SkPzIGdyhVEDUDl5KyyQGfY2kSSpQ9I8OhVaa/9Udqfwiw@public.gmane.org>
@ 2004-11-16 12:29 ` Andi Kleen
[not found] ` <20041116122946.GG28839-B4tOwbsTzaBolqkO4TVVkw@public.gmane.org>
0 siblings, 1 reply; 16+ messages in thread
From: Andi Kleen @ 2004-11-16 12:29 UTC (permalink / raw)
To: Matthew Wilcox
Cc: Yu, Luming, Andi Kleen,
acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Fu, Michael
[I didn't see Luming's original mail, so answering to this one]
On Tue, Nov 16, 2004 at 12:16:16PM +0000, Matthew Wilcox wrote:
> On Tue, Nov 16, 2004 at 02:15:47PM +0800, Yu, Luming wrote:
> > Andi,
> >
> > This patch seems to break the atomic operation.
> > The original code enclosed by spin_lock_irqsave/spin_unlock_irqresotre is trying to make sure the first operation to EC_COMMAND
> > register , and the second operation to EC_DATA register belong to one atomic transaction.
>
> Why would converting from a spinlock to a semaphore break this?
As Willy said the operation should be still atomic in respect to
the register.
And the event polling can take several ms, there is just no way
to do this during runtime with interrupts off. Especially since
thermal will do this every few seconds. With my patch at least
only kacpid is blocked for that long, not the whole system.
-Andi
-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
^ permalink raw reply [flat|nested] 16+ messages in thread
* RE: [PATCH] Don't disable interrupts during EC access
@ 2004-11-16 15:21 Yu, Luming
2004-11-16 15:37 ` Andi Kleen
0 siblings, 1 reply; 16+ messages in thread
From: Yu, Luming @ 2004-11-16 15:21 UTC (permalink / raw)
To: Andi Kleen, Matthew Wilcox
Cc: acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Fu, Michael,
Brown, Len, Moore, Robert
>On Tue, Nov 16, 2004 at 12:16:16PM +0000, Matthew Wilcox wrote:
>> On Tue, Nov 16, 2004 at 02:15:47PM +0800, Yu, Luming wrote:
>> > Andi,
>> >
>> > This patch seems to break the atomic operation.
>> > The original code enclosed by
>spin_lock_irqsave/spin_unlock_irqresotre is trying to make
>sure the first operation to EC_COMMAND
>> > register , and the second operation to EC_DATA register
>belong to one atomic transaction.
>>
>> Why would converting from a spinlock to a semaphore break this?
>
>As Willy said the operation should be still atomic in respect to
>the register.
It is just due to odd hardware behavior. :-)
For example, if you want to read data from EC. The first step
is writing 0x80 (read command) to ec command register.
Then, if EC (hardware) write data into the output buffer, the
output buffer flag (OBF) in the status register is set.
(I assume it is within 1ms). According to ACPI spec,
now, EC interrupt will get triggered. And this is
firmware generated edge interrupt. It will hold until OBF get reset.
When the host processor reads this data from the output buffer,
the OBF can be reset.
So, if you remove the spin_lock_irqsave, when OBF is set
you could get interrupt storm.
For detail, please refer to ACPI spec :
12 ACPI Embedded Controller Interface Specification.
>
>And the event polling can take several ms, there is just no way
>to do this during runtime with interrupts off. Especially since
>thermal will do this every few seconds. With my patch at least
>only kacpid is blocked for that long, not the whole system.
>
>-Andi
>
As for thermal event, AFAIK, not all laptops use EC to generate thermal
event. And I'm thinking of a algorithm.
There is a issue of kacpid consuming a lot of CPU time, which should
be due to GPEs keep firing without any control. Current GPE handling
just
re-enable GPEs after handling GPEs without considering any semantics
conveyed by that GPE. For example, some laptop could keep generating
thermal GPE interrupt, if temperature is above a threshold. All these
thermal events
is just telling OS one thing, that is "temperature is above a specific
threshold,
please turn on cooling methods ...." . Maybe this is platform issue,
but driver should handle this case smoothly.
http://bugme.osdl.org/show_bug.cgi?id=3686
Thanks
Luming
-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Don't disable interrupts during EC access
2004-11-16 15:21 Yu, Luming
@ 2004-11-16 15:37 ` Andi Kleen
[not found] ` <20041116153709.GA2392-B4tOwbsTzaBolqkO4TVVkw@public.gmane.org>
0 siblings, 1 reply; 16+ messages in thread
From: Andi Kleen @ 2004-11-16 15:37 UTC (permalink / raw)
To: Yu, Luming
Cc: Andi Kleen, Matthew Wilcox,
acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Fu, Michael,
Brown, Len, Moore, Robert
On Tue, Nov 16, 2004 at 11:21:03PM +0800, Yu, Luming wrote:
> It is just due to odd hardware behavior. :-)
> For example, if you want to read data from EC. The first step
> is writing 0x80 (read command) to ec command register.
> Then, if EC (hardware) write data into the output buffer, the
> output buffer flag (OBF) in the status register is set.
> (I assume it is within 1ms). According to ACPI spec,
> now, EC interrupt will get triggered. And this is
> firmware generated edge interrupt. It will hold until OBF get reset.
> When the host processor reads this data from the output buffer,
> the OBF can be reset.
>
> So, if you remove the spin_lock_irqsave, when OBF is set
> you could get interrupt storm.
>
> For detail, please refer to ACPI spec :
> 12 ACPI Embedded Controller Interface Specification.
Ok. But the problem is not the actual write, but the waiting
for the event which takes extremly long on these machines
(it's not a single broken machine, but has been observed
on several VIA based laptops). Would it work to only disable
interrupts during the register write/read, but not during the
polling delay?
Another possible way would be to only disable the ACPI interrupt
in the local APIC and keep the others alive (but what to do in PIC mode?)
>
> >
> >And the event polling can take several ms, there is just no way
> >to do this during runtime with interrupts off. Especially since
> >thermal will do this every few seconds. With my patch at least
> >only kacpid is blocked for that long, not the whole system.
> >
> >-Andi
> >
>
> As for thermal event, AFAIK, not all laptops use EC to generate thermal
> event. And I'm thinking of a algorithm.
A better algorithm to do this would be fine, but even if you do
the EC access only very infrequent it's imho still not really
appropiate to lose timer interrupts and create long scheduling bubbles
durign this. So some solution for the broken EC reads needs to be found even
independent from the thermal algorithm.
-Andi
-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
^ permalink raw reply [flat|nested] 16+ messages in thread
* RE: [PATCH] Don't disable interrupts during EC access
@ 2004-11-16 15:41 Yu, Luming
0 siblings, 0 replies; 16+ messages in thread
From: Yu, Luming @ 2004-11-16 15:41 UTC (permalink / raw)
To: Yu, Luming, Andi Kleen, Matthew Wilcox
Cc: acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Fu, Michael,
Brown, Len, Moore, Robert
I forget one thing that could make me feel frustrated.
There is a user outside of ACPI driver, that is sonypi_ec_read,
which can be invoked by sonypi_misc_ioctl, which haven't
disable EC-GPE. :-)
If everything is handled by kacpid. I even think semaphore
is also unnecessary. Because every thing is run in the order
of a queue. :-)
Thanks
Luming
>-----Original Message-----
>From: acpi-devel-admin-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
>[mailto:acpi-devel-admin-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org] On Behalf Of Yu, Luming
>Sent: 2004年11月16日 23:21
>To: Andi Kleen; Matthew Wilcox
>Cc: acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org; Fu, Michael; Brown, Len;
>Moore, Robert
>Subject: RE: [ACPI] [PATCH] Don't disable interrupts during EC access
>
>>On Tue, Nov 16, 2004 at 12:16:16PM +0000, Matthew Wilcox wrote:
>>> On Tue, Nov 16, 2004 at 02:15:47PM +0800, Yu, Luming wrote:
>>> > Andi,
>>> >
>>> > This patch seems to break the atomic operation.
>>> > The original code enclosed by
>>spin_lock_irqsave/spin_unlock_irqresotre is trying to make
>>sure the first operation to EC_COMMAND
>>> > register , and the second operation to EC_DATA register
>>belong to one atomic transaction.
>>>
>>> Why would converting from a spinlock to a semaphore break this?
>>
>>As Willy said the operation should be still atomic in respect to
>>the register.
>
>It is just due to odd hardware behavior. :-)
>For example, if you want to read data from EC. The first step
>is writing 0x80 (read command) to ec command register.
>Then, if EC (hardware) write data into the output buffer, the
>output buffer flag (OBF) in the status register is set.
>(I assume it is within 1ms). According to ACPI spec,
>now, EC interrupt will get triggered. And this is
>firmware generated edge interrupt. It will hold until OBF get reset.
>When the host processor reads this data from the output buffer,
>the OBF can be reset.
>
>So, if you remove the spin_lock_irqsave, when OBF is set
>you could get interrupt storm.
>
>For detail, please refer to ACPI spec :
>12 ACPI Embedded Controller Interface Specification.
>
>>
>>And the event polling can take several ms, there is just no way
>>to do this during runtime with interrupts off. Especially since
>>thermal will do this every few seconds. With my patch at least
>>only kacpid is blocked for that long, not the whole system.
>>
>>-Andi
>>
>
>As for thermal event, AFAIK, not all laptops use EC to
>generate thermal
>event. And I'm thinking of a algorithm.
>
> There is a issue of kacpid consuming a lot of CPU time, which should
>be due to GPEs keep firing without any control. Current GPE handling
>just
>re-enable GPEs after handling GPEs without considering any semantics
>conveyed by that GPE. For example, some laptop could keep generating
>thermal GPE interrupt, if temperature is above a threshold. All these
>thermal events
>is just telling OS one thing, that is "temperature is above a specific
>threshold,
> please turn on cooling methods ...." . Maybe this is platform issue,
> but driver should handle this case smoothly.
>
>http://bugme.osdl.org/show_bug.cgi?id=3686
>
>
>Thanks
>Luming
>
>
>
>-------------------------------------------------------
>This SF.Net email is sponsored by: InterSystems CACHE
>FREE OODBMS DOWNLOAD - A multidimensional database that combines
>robust object and relational technologies, making it a perfect match
>for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
>_______________________________________________
>Acpi-devel mailing list
>Acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
>https://lists.sourceforge.net/lists/listinfo/acpi-devel
>
-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Don't disable interrupts during EC access
[not found] ` <20041116122946.GG28839-B4tOwbsTzaBolqkO4TVVkw@public.gmane.org>
@ 2004-11-17 1:25 ` Stefan Seyfried
0 siblings, 0 replies; 16+ messages in thread
From: Stefan Seyfried @ 2004-11-17 1:25 UTC (permalink / raw)
To: acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
On Tue, Nov 16, 2004 at 01:29:46PM +0100, Andi Kleen wrote:
> And the event polling can take several ms, there is just no way
> to do this during runtime with interrupts off. Especially since
> thermal will do this every few seconds. With my patch at least
> only kacpid is blocked for that long, not the whole system.
may this also help the awfully slow battery polling on some machines
(e.g. Dell D600) or is this a completely different case?
--
Stefan Seyfried
-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
^ permalink raw reply [flat|nested] 16+ messages in thread
* RE: [PATCH] Don't disable interrupts during EC access
@ 2004-11-17 6:12 Yu, Luming
0 siblings, 0 replies; 16+ messages in thread
From: Yu, Luming @ 2004-11-17 6:12 UTC (permalink / raw)
To: Andi Kleen
Cc: Matthew Wilcox, acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
Fu, Michael, Brown, Len, Moore, Robert
>Another possible way would be to only disable the ACPI interrupt
>in the local APIC and keep the others alive (but what to do
>in PIC mode?)
Disable EC GPE in your patch could achieve the goal.
Thanks,
Luming
-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Don't disable interrupts during EC access
[not found] ` <20041116153709.GA2392-B4tOwbsTzaBolqkO4TVVkw@public.gmane.org>
@ 2004-11-17 6:55 ` Dmitry Torokhov
0 siblings, 0 replies; 16+ messages in thread
From: Dmitry Torokhov @ 2004-11-17 6:55 UTC (permalink / raw)
To: acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
Cc: Andi Kleen, Yu, Luming, Matthew Wilcox, Fu, Michael, Brown, Len,
Moore, Robert
On Tuesday 16 November 2004 10:37 am, Andi Kleen wrote:
> > For detail, please refer to ACPI spec :
> > 12 ? ACPI Embedded Controller Interface Specification.
>
> Ok. But the problem is not the actual write, but the waiting
> for the event which takes extremly long on these machines
> (it's not a single broken machine, but has been observed
> on several VIA based laptops). Would it work to only disable
> interrupts during the register write/read, but not during the
> polling delay?
Actually, the proper solution would be to get rid of polling entirely,
like in the patch below. Could anyone with a box with EC verify that
it works?
Btw, what's up with initializing every variable in ACPI code? It is
not free after all...
--
Dmitry
===================================================================
ChangeSet@1.1998, 2004-11-17 01:44:59-05:00, dtor_core-yWtbtysYrB+LZ21kGMrzwg@public.gmane.org
ACPI: EC - switch from busy-polling to event-based completion
signalling. EC operations take quite a long time and busy
polling with interrupts disabled causes big latencies or
even losing timer interrupts.
Also get rid of unneeded variable initializations.
Based on patch by Andi Kleen <ak-l3A5Bk7waGM@public.gmane.org>
Signed-off-by: Dmitry Torokhov <dtor-JGs/UdohzUI@public.gmane.org>
ec.c | 217 ++++++++++++++++++++++++++++++++++---------------------------------
1 files changed, 113 insertions(+), 104 deletions(-)
===================================================================
diff -Nru a/drivers/acpi/ec.c b/drivers/acpi/ec.c
--- a/drivers/acpi/ec.c 2004-11-17 01:45:43 -05:00
+++ b/drivers/acpi/ec.c 2004-11-17 01:45:43 -05:00
@@ -31,6 +31,7 @@
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/interrupt.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -51,11 +52,7 @@
#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */
#define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */
-#define ACPI_EC_EVENT_OBF 0x01 /* Output buffer full */
-#define ACPI_EC_EVENT_IBE 0x02 /* Input buffer empty */
-
-#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */
-#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */
+#define ACPI_EC_DELAY 10 /* Wait 10ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
#define ACPI_EC_COMMAND_READ 0x80
@@ -87,7 +84,9 @@
struct acpi_generic_address command_addr;
struct acpi_generic_address data_addr;
unsigned long global_lock;
- spinlock_t lock;
+ unsigned int expect_ibe;
+ struct semaphore sem;
+ wait_queue_head_t wait;
};
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
@@ -100,53 +99,56 @@
Transaction Management
-------------------------------------------------------------------------- */
-static int
-acpi_ec_wait (
- struct acpi_ec *ec,
- u8 event)
+static inline u32 acpi_ec_read_status(struct acpi_ec *ec)
{
- u32 acpi_ec_status = 0;
- u32 i = ACPI_EC_UDELAY_COUNT;
+ u32 status = 0;
- if (!ec)
- return -EINVAL;
+ acpi_hw_low_level_read(8, &status, &ec->status_addr);
+ return status;
+}
- /* Poll the EC status register waiting for the event to occur. */
- switch (event) {
- case ACPI_EC_EVENT_OBF:
- do {
- acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr);
- if (acpi_ec_status & ACPI_EC_FLAG_OBF)
- return 0;
- udelay(ACPI_EC_UDELAY);
- } while (--i>0);
- break;
- case ACPI_EC_EVENT_IBE:
- do {
- acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr);
- if (!(acpi_ec_status & ACPI_EC_FLAG_IBF))
- return 0;
- udelay(ACPI_EC_UDELAY);
- } while (--i>0);
- break;
- default:
- return -EINVAL;
- }
+static inline void acpi_ec_expect_ibe(struct acpi_ec *ec)
+{
+ ec->expect_ibe = 1;
+ mb();
+}
+
+static int acpi_ec_wait_ibe(struct acpi_ec *ec)
+{
+ int result;
+
+ result = wait_event_interruptible_timeout(ec->wait,
+ !(acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF),
+ msecs_to_jiffies(ACPI_EC_DELAY));
+ if (result == 0)
+ result = -ETIME;
- return -ETIME;
+ return result;
}
+static int acpi_ec_wait_obf(struct acpi_ec *ec)
+{
+ int result;
+
+ result = wait_event_interruptible_timeout(ec->wait,
+ (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF),
+ msecs_to_jiffies(ACPI_EC_DELAY));
+ if (result == 0)
+ result = -ETIME;
+
+ return result;
+}
+
static int
acpi_ec_read (
struct acpi_ec *ec,
u8 address,
u32 *data)
{
- acpi_status status = AE_OK;
- int result = 0;
- unsigned long flags = 0;
- u32 glk = 0;
+ acpi_status status;
+ int result;
+ u32 glk;
ACPI_FUNCTION_TRACE("acpi_ec_read");
@@ -160,27 +162,28 @@
if (ACPI_FAILURE(status))
return_VALUE(-ENODEV);
}
-
- spin_lock_irqsave(&ec->lock, flags);
+ WARN_ON(in_interrupt());
+ down(&ec->sem);
+
+ acpi_ec_expect_ibe(ec);
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->command_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (result)
+ result = acpi_ec_wait_ibe(ec);
+ if (result < 0)
goto end;
acpi_hw_low_level_write(8, address, &ec->data_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
- if (result)
+ result = acpi_ec_wait_obf(ec);
+ if (result < 0)
goto end;
-
acpi_hw_low_level_read(8, data, &ec->data_addr);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
*data, address));
end:
- spin_unlock_irqrestore(&ec->lock, flags);
+ up(&ec->sem);
if (ec->global_lock)
acpi_release_global_lock(glk);
@@ -195,10 +198,9 @@
u8 address,
u8 data)
{
- int result = 0;
- acpi_status status = AE_OK;
- unsigned long flags = 0;
- u32 glk = 0;
+ int result;
+ acpi_status status;
+ u32 glk;
ACPI_FUNCTION_TRACE("acpi_ec_write");
@@ -211,28 +213,32 @@
return_VALUE(-ENODEV);
}
- spin_lock_irqsave(&ec->lock, flags);
+ WARN_ON(in_interrupt());
+ down(&ec->sem);
+ acpi_ec_expect_ibe(ec);
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->command_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (result)
+ result = acpi_ec_wait_ibe(ec);
+ if (result < 0)
goto end;
+ acpi_ec_expect_ibe(ec);
acpi_hw_low_level_write(8, address, &ec->data_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (result)
+ result = acpi_ec_wait_ibe(ec);
+ if (result < 0)
goto end;
+ acpi_ec_expect_ibe(ec);
acpi_hw_low_level_write(8, data, &ec->data_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (result)
+ result = acpi_ec_wait_ibe(ec);
+ if (result < 0)
goto end;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
data, address));
end:
- spin_unlock_irqrestore(&ec->lock, flags);
+ up(&ec->sem);
if (ec->global_lock)
acpi_release_global_lock(glk);
@@ -287,10 +293,9 @@
struct acpi_ec *ec,
u32 *data)
{
- int result = 0;
- acpi_status status = AE_OK;
- unsigned long flags = 0;
- u32 glk = 0;
+ int result;
+ acpi_status status;
+ u32 glk;
ACPI_FUNCTION_TRACE("acpi_ec_query");
@@ -310,19 +315,20 @@
* Note that successful completion of the query causes the ACPI_EC_SCI
* bit to be cleared (and thus clearing the interrupt source).
*/
- spin_lock_irqsave(&ec->lock, flags);
+ WARN_ON(in_interrupt());
+ down(&ec->sem);
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, &ec->command_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
- if (result)
+ result = acpi_ec_wait_obf(ec);
+ if (result < 0)
goto end;
-
+
acpi_hw_low_level_read(8, data, &ec->data_addr);
if (!*data)
result = -ENODATA;
end:
- spin_unlock_irqrestore(&ec->lock, flags);
+ up(&ec->sem);
if (ec->global_lock)
acpi_release_global_lock(glk);
@@ -345,8 +351,7 @@
void *ec_cxt)
{
struct acpi_ec *ec = (struct acpi_ec *) ec_cxt;
- u32 value = 0;
- unsigned long flags = 0;
+ u32 value;
static char object_name[5] = {'_','Q','0','0','\0'};
const char hex[] = {'0','1','2','3','4','5','6','7',
'8','9','A','B','C','D','E','F'};
@@ -354,11 +359,7 @@
ACPI_FUNCTION_TRACE("acpi_ec_gpe_query");
if (!ec_cxt)
- goto end;
-
- spin_lock_irqsave(&ec->lock, flags);
- acpi_hw_low_level_read(8, &value, &ec->command_addr);
- spin_unlock_irqrestore(&ec->lock, flags);
+ goto end;
/* TBD: Implement asynch events!
* NOTE: All we care about are EC-SCI's. Other EC events are
@@ -366,12 +367,12 @@
* treat EC-SCIs as level (versus EDGE!) triggered, preventing
* a purely interrupt-driven approach (grumble, grumble).
*/
- if (!(value & ACPI_EC_FLAG_SCI))
+ if (!(acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI))
goto end;
if (acpi_ec_query(ec, &value))
goto end;
-
+
object_name[2] = hex[((value >> 4) & 0x0F)];
object_name[3] = hex[(value & 0x0F)];
@@ -388,6 +389,7 @@
void *data)
{
acpi_status status = AE_OK;
+ u32 value;
struct acpi_ec *ec = (struct acpi_ec *) data;
if (!ec)
@@ -395,13 +397,20 @@
acpi_disable_gpe(NULL, ec->gpe_bit, ACPI_ISR);
- status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
- acpi_ec_gpe_query, ec);
+ value = acpi_ec_read_status(ec);
- if (status == AE_OK)
- return ACPI_INTERRUPT_HANDLED;
- else
- return ACPI_INTERRUPT_NOT_HANDLED;
+ if ((value & ACPI_EC_FLAG_OBF) ||
+ (ec->expect_ibe && !(value & ACPI_EC_FLAG_IBF))) {
+ ec->expect_ibe = 0;
+ wake_up(&ec->wait);
+ }
+
+ if (value & ACPI_EC_FLAG_SCI)
+ status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
+ acpi_ec_gpe_query, ec);
+
+ return status == AE_OK ?
+ ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
}
/* --------------------------------------------------------------------------
@@ -419,10 +428,8 @@
* The EC object is in the handler context and is needed
* when calling the acpi_ec_space_handler.
*/
- if(function == ACPI_REGION_DEACTIVATE)
- *return_context = NULL;
- else
- *return_context = handler_context;
+ *return_context = (function != ACPI_REGION_DEACTIVATE) ?
+ handler_context : NULL;
return AE_OK;
}
@@ -437,9 +444,9 @@
void *handler_context,
void *region_context)
{
- int result = 0;
- struct acpi_ec *ec = NULL;
- u32 temp = 0;
+ int result;
+ struct acpi_ec *ec;
+ u32 temp;
ACPI_FUNCTION_TRACE("acpi_ec_space_handler");
@@ -529,7 +536,7 @@
acpi_ec_add_fs (
struct acpi_device *device)
{
- struct proc_dir_entry *entry = NULL;
+ struct proc_dir_entry *entry;
ACPI_FUNCTION_TRACE("acpi_ec_add_fs");
@@ -580,9 +587,9 @@
acpi_ec_add (
struct acpi_device *device)
{
- int result = 0;
- acpi_status status = AE_OK;
- struct acpi_ec *ec = NULL;
+ int result;
+ acpi_status status;
+ struct acpi_ec *ec;
unsigned long uid;
ACPI_FUNCTION_TRACE("acpi_ec_add");
@@ -597,7 +604,8 @@
ec->handle = device->handle;
ec->uid = -1;
- ec->lock = SPIN_LOCK_UNLOCKED;
+ init_MUTEX(&ec->sem);
+ init_waitqueue_head(&ec->wait);
strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_EC_CLASS);
acpi_driver_data(device) = ec;
@@ -611,7 +619,7 @@
if (ec_ecdt && ec_ecdt->uid == uid) {
acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler);
-
+
acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler);
kfree(ec_ecdt);
@@ -651,7 +659,7 @@
struct acpi_device *device,
int type)
{
- struct acpi_ec *ec = NULL;
+ struct acpi_ec *ec;
ACPI_FUNCTION_TRACE("acpi_ec_remove");
@@ -706,8 +714,8 @@
acpi_ec_start (
struct acpi_device *device)
{
- acpi_status status = AE_OK;
- struct acpi_ec *ec = NULL;
+ acpi_status status;
+ struct acpi_ec *ec;
ACPI_FUNCTION_TRACE("acpi_ec_start");
@@ -763,8 +771,8 @@
struct acpi_device *device,
int type)
{
- acpi_status status = AE_OK;
- struct acpi_ec *ec = NULL;
+ acpi_status status;
+ struct acpi_ec *ec;
ACPI_FUNCTION_TRACE("acpi_ec_stop");
@@ -792,7 +800,7 @@
acpi_status status;
struct acpi_table_ecdt *ecdt_ptr;
- status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
+ status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
(struct acpi_table_header **) &ecdt_ptr);
if (ACPI_FAILURE(status))
return 0;
@@ -807,11 +815,12 @@
return -ENOMEM;
memset(ec_ecdt, 0, sizeof(struct acpi_ec));
+ init_MUTEX(&ec_ecdt->sem);
+ init_waitqueue_head(&ec_ecdt->wait);
ec_ecdt->command_addr = ecdt_ptr->ec_control;
ec_ecdt->status_addr = ecdt_ptr->ec_control;
ec_ecdt->data_addr = ecdt_ptr->ec_data;
ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit;
- ec_ecdt->lock = SPIN_LOCK_UNLOCKED;
/* use the GL just to be safe */
ec_ecdt->global_lock = TRUE;
ec_ecdt->uid = ecdt_ptr->uid;
@@ -855,7 +864,7 @@
static int __init acpi_ec_init (void)
{
- int result = 0;
+ int result;
ACPI_FUNCTION_TRACE("acpi_ec_init");
-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
^ permalink raw reply [flat|nested] 16+ messages in thread
* RE: [PATCH] Don't disable interrupts during EC access
@ 2004-11-17 7:10 Li, Shaohua
[not found] ` <16A54BF5D6E14E4D916CE26C9AD305758EF9BD-4yWAQGcml66iAffOGbnezLfspsVTdybXVpNB7YpNyf8@public.gmane.org>
0 siblings, 1 reply; 16+ messages in thread
From: Li, Shaohua @ 2004-11-17 7:10 UTC (permalink / raw)
To: Dmitry Torokhov, acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
Cc: Andi Kleen, Yu, Luming, Matthew Wilcox, Fu, Michael, Brown, Len,
Moore, Robert
>On Tuesday 16 November 2004 10:37 am, Andi Kleen wrote:
>> > For detail, please refer to ACPI spec :
>> > 12 ? ACPI Embedded Controller Interface Specification.
>>
>> Ok. But the problem is not the actual write, but the waiting
>> for the event which takes extremly long on these machines
>> (it's not a single broken machine, but has been observed
>> on several VIA based laptops). Would it work to only disable
>> interrupts during the register write/read, but not during the
>> polling delay?
>
>Actually, the proper solution would be to get rid of polling entirely,
>like in the patch below. Could anyone with a box with EC verify that
>it works?
>
>Btw, what's up with initializing every variable in ACPI code? It is
>not free after all...
>
I agree the right solution should be to stop polling, but did you look
at the comments in ec.c (line 361)? It said some systems can't work with
asynchronous mode.
Thanks,
Shaohua
-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
^ permalink raw reply [flat|nested] 16+ messages in thread
* RE: [PATCH] Don't disable interrupts during EC access
@ 2004-11-17 7:46 Yu, Luming
2004-11-17 8:02 ` Dmitry Torokhov
0 siblings, 1 reply; 16+ messages in thread
From: Yu, Luming @ 2004-11-17 7:46 UTC (permalink / raw)
To: Li, Shaohua, Dmitry Torokhov,
acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
Cc: Andi Kleen, Matthew Wilcox, Fu, Michael, Brown, Len,
Moore, Robert
Spec defined EC-SCI is edge-trigged.
So, I think that is solution sticking with Spec.
Not sure, how many laptop break this rule.
If wait_event_interruptible_timeout returns due to timeout,
Can we think it of polling timeout?
So, I suggest Dmitry to complete that to include
level-trigged situation.
Thanks
Luming
>-----Original Message-----
>From: Li, Shaohua
>Sent: 2004年11月17日 15:10
>To: Dmitry Torokhov; acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
>Cc: Andi Kleen; Yu, Luming; Matthew Wilcox; Fu, Michael;
>Brown, Len; Moore, Robert
>Subject: RE: [ACPI] [PATCH] Don't disable interrupts during EC access
>
>>On Tuesday 16 November 2004 10:37 am, Andi Kleen wrote:
>>> > For detail, please refer to ACPI spec :
>>> > 12 ? ACPI Embedded Controller Interface Specification.
>>>
>>> Ok. But the problem is not the actual write, but the waiting
>>> for the event which takes extremly long on these machines
>>> (it's not a single broken machine, but has been observed
>>> on several VIA based laptops). Would it work to only disable
>>> interrupts during the register write/read, but not during the
>>> polling delay?
>>
>>Actually, the proper solution would be to get rid of polling entirely,
>>like in the patch below. Could anyone with a box with EC verify that
>>it works?
>>
>>Btw, what's up with initializing every variable in ACPI code? It is
>>not free after all...
>>
>I agree the right solution should be to stop polling, but did
>you look at the comments in ec.c (line 361)? It said some
>systems can't work with asynchronous mode.
>
>Thanks,
>Shaohua
>
-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Don't disable interrupts during EC access
[not found] ` <16A54BF5D6E14E4D916CE26C9AD305758EF9BD-4yWAQGcml66iAffOGbnezLfspsVTdybXVpNB7YpNyf8@public.gmane.org>
@ 2004-11-17 7:58 ` Dmitry Torokhov
0 siblings, 0 replies; 16+ messages in thread
From: Dmitry Torokhov @ 2004-11-17 7:58 UTC (permalink / raw)
To: Li, Shaohua
Cc: acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Andi Kleen,
Yu, Luming, Matthew Wilcox, Fu, Michael, Brown, Len,
Moore, Robert
On Wednesday 17 November 2004 02:10 am, Li, Shaohua wrote:
> >On Tuesday 16 November 2004 10:37 am, Andi Kleen wrote:
> >> > For detail, please refer to ACPI spec :
> >> > 12 ? ACPI Embedded Controller Interface Specification.
> >>
> >> Ok. But the problem is not the actual write, but the waiting
> >> for the event which takes extremly long on these machines
> >> (it's not a single broken machine, but has been observed
> >> on several VIA based laptops). Would it work to only disable
> >> interrupts during the register write/read, but not during the
> >> polling delay?
> >
> >Actually, the proper solution would be to get rid of polling entirely,
> >like in the patch below. Could anyone with a box with EC verify that
> >it works?
> >
> >Btw, what's up with initializing every variable in ACPI code? It is
> >not free after all...
> >
> I agree the right solution should be to stop polling, but did you look
> at the comments in ec.c (line 361)? It said some systems can't work with
> asynchronous mode.
>
Hmm... Let's see. We can only have 1 reader/writer active at the same time
per EC becuase they are serialized via ec->sem. So the only thing we can
race with is SCI generated by firmware in response to external factors.
So I guess we still need sleep-polling in acpi_ec_query_data, something
like this:
while (unlikely(down_trylock(&ec->sem))) {
/* reader or writer is waiting for completion */
value = acpi_ec_read_status(ec);
if ((value & ACPI_EC_FLAG_OBF) ||
(ec->expect_ibe && !(value & ACPI_EC_FLAG_IBF))) {
ec->expect_ibe = 0;
wake_up(&ec->wait);
}
msleep(1);
}
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, &ec->command_addr);
result = acpi_ec_wait_obf(ec);
if (result < 0)
goto end;
.....
Will this work?
--
Dmitry
-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Don't disable interrupts during EC access
2004-11-17 7:46 Yu, Luming
@ 2004-11-17 8:02 ` Dmitry Torokhov
[not found] ` <200411170302.58634.dtor_core-yWtbtysYrB+LZ21kGMrzwg@public.gmane.org>
0 siblings, 1 reply; 16+ messages in thread
From: Dmitry Torokhov @ 2004-11-17 8:02 UTC (permalink / raw)
To: Yu, Luming
Cc: Li, Shaohua, acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
Andi Kleen, Matthew Wilcox, Fu, Michael, Brown, Len,
Moore, Robert
On Wednesday 17 November 2004 02:46 am, Yu, Luming wrote:
> Spec defined EC-SCI is edge-trigged.
> So, I think that is solution sticking with Spec.
> Not sure, how many laptop break this rule.
>
> If wait_event_interruptible_timeout returns due to timeout,
> Can we think it of polling timeout?
>
Yes, I think this is a great idea - if we time out check the
status register one more time to verify that we did not miss
interrupt because SCI was raised earlier.
--
Dmitry
-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Don't disable interrupts during EC access
[not found] ` <200411170302.58634.dtor_core-yWtbtysYrB+LZ21kGMrzwg@public.gmane.org>
@ 2004-11-17 21:53 ` Len Brown
2004-11-18 6:14 ` Dmitry Torokhov
0 siblings, 1 reply; 16+ messages in thread
From: Len Brown @ 2004-11-17 21:53 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Luming Yu, Shaohua Li, ACPI Developers, Andi Kleen,
Matthew Wilcox, Michael Fu, Robert Moore
just to add some fuel to this fire,
here is an example of where we don't wait long enough for the EC:
http://bugzilla.kernel.org/show_bug.cgi?id=2845
-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Don't disable interrupts during EC access
2004-11-17 21:53 ` Len Brown
@ 2004-11-18 6:14 ` Dmitry Torokhov
0 siblings, 0 replies; 16+ messages in thread
From: Dmitry Torokhov @ 2004-11-18 6:14 UTC (permalink / raw)
To: Len Brown
Cc: Luming Yu, Shaohua Li, ACPI Developers, Andi Kleen,
Matthew Wilcox, Michael Fu, Robert Moore
On Wednesday 17 November 2004 04:53 pm, Len Brown wrote:
> just to add some fuel to this fire,
> here is an example of where we don't wait long enough for the EC:
>
> http://bugzilla.kernel.org/show_bug.cgi?id=2845
>
>
Ok, so here is the new version that tries to hanle level-triggered SCIs
while using event signalling instead of polling.
Since we serialize access to EC via ec->sem semaphore there can be only
one reader/writer at one time so they can not race with each other.
acpi_ec_gpe_query() also holds ec->sem until EC is queried which should
reset SCI condition. The only poblem window that I see is when there is
an SCI was raised and acpi_ec_gpe_handler() scheduled acpi_ec_gpe_query()
and there comes a reader or writer. To take care of it instead of doing
normal "down" in acpi_ec_gpe_query() we will do down_trylock(). If it is
unsuccessful that means that other thread is waiting on IO completion and
we will do the soft polling (interrupts enabled) for it and wake it up
when IO completes.
Am I missing somethig?
Please give it a try - it compiles but since I don't have EC I am not
able to test it.
--
Dmitry
===================================================================
ChangeSet@1.2001, 2004-11-18 01:11:46-05:00, dtor_core-yWtbtysYrB+LZ21kGMrzwg@public.gmane.org
ACPI: EC - switch from busy-polling to event-based completion
signalling. EC operations take quite a long time and busy
polling with interrupts disabled causes big latencies or
even losing timer interrupts.
EC IO timeout has been increased from 10 to 50ms.
Also get rid of unneeded variable initializations.
Based on patch by Andi Kleen <ak-l3A5Bk7waGM@public.gmane.org>
Signed-off-by: Dmitry Torokhov <dtor-JGs/UdohzUI@public.gmane.org>
ec.c | 222 ++++++++++++++++++++++++++++++++++++++-----------------------------
1 files changed, 126 insertions(+), 96 deletions(-)
===================================================================
diff -Nru a/drivers/acpi/ec.c b/drivers/acpi/ec.c
--- a/drivers/acpi/ec.c 2004-11-18 01:13:03 -05:00
+++ b/drivers/acpi/ec.c 2004-11-18 01:13:03 -05:00
@@ -31,6 +31,7 @@
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/interrupt.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -54,8 +55,7 @@
#define ACPI_EC_EVENT_OBF 0x01 /* Output buffer full */
#define ACPI_EC_EVENT_IBE 0x02 /* Input buffer empty */
-#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */
-#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */
+#define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
#define ACPI_EC_COMMAND_READ 0x80
@@ -87,7 +87,9 @@
struct acpi_generic_address command_addr;
struct acpi_generic_address data_addr;
unsigned long global_lock;
- spinlock_t lock;
+ unsigned int expect_event;
+ struct semaphore sem;
+ wait_queue_head_t wait;
};
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
@@ -100,53 +102,59 @@
Transaction Management
-------------------------------------------------------------------------- */
-static int
-acpi_ec_wait (
- struct acpi_ec *ec,
- u8 event)
+static inline u32 acpi_ec_read_status(struct acpi_ec *ec)
{
- u32 acpi_ec_status = 0;
- u32 i = ACPI_EC_UDELAY_COUNT;
+ u32 status = 0;
- if (!ec)
- return -EINVAL;
+ acpi_hw_low_level_read(8, &status, &ec->status_addr);
+ return status;
+}
+
+static int acpi_ec_wait(struct acpi_ec *ec, unsigned int event)
+{
+ int result;
- /* Poll the EC status register waiting for the event to occur. */
+ ec->expect_event = event;
+ smp_mb();
+
+ result = wait_event_interruptible_timeout(ec->wait,
+ !ec->expect_event,
+ msecs_to_jiffies(ACPI_EC_DELAY));
+ ec->expect_event = 0;
+ smp_mb();
+
+ if (result < 0)
+ return result;
+
+ /*
+ * Verify that the event in question has actually happened by
+ * querying EC status. Do the check even if operation timed-out
+ * to make sure that we did not miss interrupt.
+ */
switch (event) {
case ACPI_EC_EVENT_OBF:
- do {
- acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr);
- if (acpi_ec_status & ACPI_EC_FLAG_OBF)
- return 0;
- udelay(ACPI_EC_UDELAY);
- } while (--i>0);
+ if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF)
+ return 0;
break;
+
case ACPI_EC_EVENT_IBE:
- do {
- acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr);
- if (!(acpi_ec_status & ACPI_EC_FLAG_IBF))
- return 0;
- udelay(ACPI_EC_UDELAY);
- } while (--i>0);
+ if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
+ return 0;
break;
- default:
- return -EINVAL;
}
return -ETIME;
}
-
static int
acpi_ec_read (
struct acpi_ec *ec,
u8 address,
u32 *data)
{
- acpi_status status = AE_OK;
- int result = 0;
- unsigned long flags = 0;
- u32 glk = 0;
+ acpi_status status;
+ int result;
+ u32 glk;
ACPI_FUNCTION_TRACE("acpi_ec_read");
@@ -160,8 +168,9 @@
if (ACPI_FAILURE(status))
return_VALUE(-ENODEV);
}
-
- spin_lock_irqsave(&ec->lock, flags);
+
+ WARN_ON(in_interrupt());
+ down(&ec->sem);
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->command_addr);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
@@ -173,14 +182,13 @@
if (result)
goto end;
-
acpi_hw_low_level_read(8, data, &ec->data_addr);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
*data, address));
end:
- spin_unlock_irqrestore(&ec->lock, flags);
+ up(&ec->sem);
if (ec->global_lock)
acpi_release_global_lock(glk);
@@ -195,10 +203,9 @@
u8 address,
u8 data)
{
- int result = 0;
- acpi_status status = AE_OK;
- unsigned long flags = 0;
- u32 glk = 0;
+ int result;
+ acpi_status status;
+ u32 glk;
ACPI_FUNCTION_TRACE("acpi_ec_write");
@@ -211,7 +218,8 @@
return_VALUE(-ENODEV);
}
- spin_lock_irqsave(&ec->lock, flags);
+ WARN_ON(in_interrupt());
+ down(&ec->sem);
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->command_addr);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
@@ -232,7 +240,7 @@
data, address));
end:
- spin_unlock_irqrestore(&ec->lock, flags);
+ up(&ec->sem);
if (ec->global_lock)
acpi_release_global_lock(glk);
@@ -287,10 +295,9 @@
struct acpi_ec *ec,
u32 *data)
{
- int result = 0;
- acpi_status status = AE_OK;
- unsigned long flags = 0;
- u32 glk = 0;
+ int result;
+ acpi_status status;
+ u32 glk;
ACPI_FUNCTION_TRACE("acpi_ec_query");
@@ -310,20 +317,16 @@
* Note that successful completion of the query causes the ACPI_EC_SCI
* bit to be cleared (and thus clearing the interrupt source).
*/
- spin_lock_irqsave(&ec->lock, flags);
-
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, &ec->command_addr);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
if (result)
goto end;
-
+
acpi_hw_low_level_read(8, data, &ec->data_addr);
if (!*data)
result = -ENODATA;
end:
- spin_unlock_irqrestore(&ec->lock, flags);
-
if (ec->global_lock)
acpi_release_global_lock(glk);
@@ -345,33 +348,50 @@
void *ec_cxt)
{
struct acpi_ec *ec = (struct acpi_ec *) ec_cxt;
- u32 value = 0;
- unsigned long flags = 0;
+ u32 value;
+ int result = -ENODATA;
static char object_name[5] = {'_','Q','0','0','\0'};
const char hex[] = {'0','1','2','3','4','5','6','7',
'8','9','A','B','C','D','E','F'};
ACPI_FUNCTION_TRACE("acpi_ec_gpe_query");
- if (!ec_cxt)
- goto end;
-
- spin_lock_irqsave(&ec->lock, flags);
- acpi_hw_low_level_read(8, &value, &ec->command_addr);
- spin_unlock_irqrestore(&ec->lock, flags);
-
- /* TBD: Implement asynch events!
- * NOTE: All we care about are EC-SCI's. Other EC events are
- * handled via polling (yuck!). This is because some systems
- * treat EC-SCIs as level (versus EDGE!) triggered, preventing
- * a purely interrupt-driven approach (grumble, grumble).
+ /*
+ * Because some systems treat EC-SCIs as level (versus EDGE!)
+ * triggered we can not just check SCI flag here. If there is
+ * a reader/writer waiting on response we need to wait till
+ * data is available and wake it up. Only when there is no
+ * outstanding requests we can finally service SCI.
*/
- if (!(value & ACPI_EC_FLAG_SCI))
- goto end;
- if (acpi_ec_query(ec, &value))
+ while (unlikely(down_trylock(&ec->sem))) {
+
+ /* Reader or writer is waiting holding ec->sem */
+ value = acpi_ec_read_status(ec);
+
+ if ((ec->expect_event == ACPI_EC_EVENT_OBF &&
+ (value & ACPI_EC_FLAG_OBF)) ||
+ (ec->expect_event == ACPI_EC_EVENT_IBE &&
+ !(value & ACPI_EC_FLAG_IBF))) {
+ ec->expect_event = 0;
+ wake_up(&ec->wait);
+ }
+
+ /*
+ * Even if we never get IBE/OBF condition client
+ * will eventually time out allowing us proceed.
+ */
+ msleep(1);
+ }
+
+ if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI)
+ result = acpi_ec_query(ec, &value);
+
+ up(&ec->sem);
+
+ if (result)
goto end;
-
+
object_name[2] = hex[((value >> 4) & 0x0F)];
object_name[3] = hex[(value & 0x0F)];
@@ -388,6 +408,7 @@
void *data)
{
acpi_status status = AE_OK;
+ u32 value;
struct acpi_ec *ec = (struct acpi_ec *) data;
if (!ec)
@@ -395,13 +416,22 @@
acpi_disable_gpe(NULL, ec->gpe_bit, ACPI_ISR);
- status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
- acpi_ec_gpe_query, ec);
+ value = acpi_ec_read_status(ec);
- if (status == AE_OK)
- return ACPI_INTERRUPT_HANDLED;
- else
- return ACPI_INTERRUPT_NOT_HANDLED;
+ if ((ec->expect_event == ACPI_EC_EVENT_OBF &&
+ (value & ACPI_EC_FLAG_OBF)) ||
+ (ec->expect_event == ACPI_EC_EVENT_IBE &&
+ !(value & ACPI_EC_FLAG_IBF))) {
+ ec->expect_event = 0;
+ wake_up(&ec->wait);
+ }
+
+ if (value & ACPI_EC_FLAG_SCI)
+ status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
+ acpi_ec_gpe_query, ec);
+
+ return status == AE_OK ?
+ ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
}
/* --------------------------------------------------------------------------
@@ -419,10 +449,8 @@
* The EC object is in the handler context and is needed
* when calling the acpi_ec_space_handler.
*/
- if(function == ACPI_REGION_DEACTIVATE)
- *return_context = NULL;
- else
- *return_context = handler_context;
+ *return_context = (function != ACPI_REGION_DEACTIVATE) ?
+ handler_context : NULL;
return AE_OK;
}
@@ -437,9 +465,9 @@
void *handler_context,
void *region_context)
{
- int result = 0;
- struct acpi_ec *ec = NULL;
- u32 temp = 0;
+ int result;
+ struct acpi_ec *ec;
+ u32 temp;
ACPI_FUNCTION_TRACE("acpi_ec_space_handler");
@@ -506,7 +534,7 @@
seq_printf(seq, "ports: 0x%02x, 0x%02x\n",
(u32) ec->status_addr.address, (u32) ec->data_addr.address);
seq_printf(seq, "use global lock: %s\n",
- ec->global_lock?"yes":"no");
+ ec->global_lock ? "yes" : "no");
end:
return_VALUE(0);
@@ -529,7 +557,7 @@
acpi_ec_add_fs (
struct acpi_device *device)
{
- struct proc_dir_entry *entry = NULL;
+ struct proc_dir_entry *entry;
ACPI_FUNCTION_TRACE("acpi_ec_add_fs");
@@ -580,9 +608,9 @@
acpi_ec_add (
struct acpi_device *device)
{
- int result = 0;
- acpi_status status = AE_OK;
- struct acpi_ec *ec = NULL;
+ int result;
+ acpi_status status;
+ struct acpi_ec *ec;
unsigned long uid;
ACPI_FUNCTION_TRACE("acpi_ec_add");
@@ -597,7 +625,8 @@
ec->handle = device->handle;
ec->uid = -1;
- ec->lock = SPIN_LOCK_UNLOCKED;
+ init_MUTEX(&ec->sem);
+ init_waitqueue_head(&ec->wait);
strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_EC_CLASS);
acpi_driver_data(device) = ec;
@@ -611,7 +640,7 @@
if (ec_ecdt && ec_ecdt->uid == uid) {
acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler);
-
+
acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler);
kfree(ec_ecdt);
@@ -651,7 +680,7 @@
struct acpi_device *device,
int type)
{
- struct acpi_ec *ec = NULL;
+ struct acpi_ec *ec;
ACPI_FUNCTION_TRACE("acpi_ec_remove");
@@ -706,8 +735,8 @@
acpi_ec_start (
struct acpi_device *device)
{
- acpi_status status = AE_OK;
- struct acpi_ec *ec = NULL;
+ acpi_status status;
+ struct acpi_ec *ec;
ACPI_FUNCTION_TRACE("acpi_ec_start");
@@ -763,8 +792,8 @@
struct acpi_device *device,
int type)
{
- acpi_status status = AE_OK;
- struct acpi_ec *ec = NULL;
+ acpi_status status;
+ struct acpi_ec *ec;
ACPI_FUNCTION_TRACE("acpi_ec_stop");
@@ -792,7 +821,7 @@
acpi_status status;
struct acpi_table_ecdt *ecdt_ptr;
- status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
+ status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
(struct acpi_table_header **) &ecdt_ptr);
if (ACPI_FAILURE(status))
return 0;
@@ -807,11 +836,12 @@
return -ENOMEM;
memset(ec_ecdt, 0, sizeof(struct acpi_ec));
+ init_MUTEX(&ec_ecdt->sem);
+ init_waitqueue_head(&ec_ecdt->wait);
ec_ecdt->command_addr = ecdt_ptr->ec_control;
ec_ecdt->status_addr = ecdt_ptr->ec_control;
ec_ecdt->data_addr = ecdt_ptr->ec_data;
ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit;
- ec_ecdt->lock = SPIN_LOCK_UNLOCKED;
/* use the GL just to be safe */
ec_ecdt->global_lock = TRUE;
ec_ecdt->uid = ecdt_ptr->uid;
@@ -855,7 +885,7 @@
static int __init acpi_ec_init (void)
{
- int result = 0;
+ int result;
ACPI_FUNCTION_TRACE("acpi_ec_init");
-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2004-11-18 6:14 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-11-17 7:10 [PATCH] Don't disable interrupts during EC access Li, Shaohua
[not found] ` <16A54BF5D6E14E4D916CE26C9AD305758EF9BD-4yWAQGcml66iAffOGbnezLfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2004-11-17 7:58 ` Dmitry Torokhov
-- strict thread matches above, loose matches on Subject: below --
2004-11-17 7:46 Yu, Luming
2004-11-17 8:02 ` Dmitry Torokhov
[not found] ` <200411170302.58634.dtor_core-yWtbtysYrB+LZ21kGMrzwg@public.gmane.org>
2004-11-17 21:53 ` Len Brown
2004-11-18 6:14 ` Dmitry Torokhov
2004-11-17 6:12 Yu, Luming
2004-11-16 15:41 Yu, Luming
2004-11-16 15:21 Yu, Luming
2004-11-16 15:37 ` Andi Kleen
[not found] ` <20041116153709.GA2392-B4tOwbsTzaBolqkO4TVVkw@public.gmane.org>
2004-11-17 6:55 ` Dmitry Torokhov
2004-11-16 6:15 Yu, Luming
2004-11-16 12:16 ` Matthew Wilcox
[not found] ` <20041116121616.GG1108-+pPCBgu9SkPzIGdyhVEDUDl5KyyQGfY2kSSpQ9I8OhVaa/9Udqfwiw@public.gmane.org>
2004-11-16 12:29 ` Andi Kleen
[not found] ` <20041116122946.GG28839-B4tOwbsTzaBolqkO4TVVkw@public.gmane.org>
2004-11-17 1:25 ` Stefan Seyfried
2004-11-15 22:56 Andi Kleen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox