Commit ff26a502 authored by Andy Grover's avatar Andy Grover

ACPI: EC update

 - Move call to acpi_ec_query out of the interrupt handler. This will
   ensure that we do not try to acquire the Global Lock at interrupt
   level.
 - Get the handle for the ECDT.
parent 7e167397
...@@ -80,6 +80,7 @@ static struct acpi_driver acpi_ec_driver = { ...@@ -80,6 +80,7 @@ static struct acpi_driver acpi_ec_driver = {
struct acpi_ec { struct acpi_ec {
acpi_handle handle; acpi_handle handle;
unsigned long uid;
unsigned long gpe_bit; unsigned long gpe_bit;
acpi_generic_address status_addr; acpi_generic_address status_addr;
acpi_generic_address command_addr; acpi_generic_address command_addr;
...@@ -90,9 +91,6 @@ struct acpi_ec { ...@@ -90,9 +91,6 @@ struct acpi_ec {
/* If we find an EC via the ECDT, we need to keep a ptr to its context */ /* If we find an EC via the ECDT, we need to keep a ptr to its context */
static struct acpi_ec *ec_ecdt; static struct acpi_ec *ec_ecdt;
/* compare this against UIDs in properly enumerated ECs to determine if we
have a dupe */
static unsigned long ecdt_uid = 0xFFFFFFFF;
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
Transaction Management Transaction Management
...@@ -297,80 +295,65 @@ struct acpi_ec_query_data { ...@@ -297,80 +295,65 @@ struct acpi_ec_query_data {
u8 data; u8 data;
}; };
static void static void
acpi_ec_gpe_query ( acpi_ec_gpe_query (
void *data) void *ec_cxt)
{ {
struct acpi_ec_query_data *query_data = NULL; 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'}; static char object_name[5] = {'_','Q','0','0','\0'};
const char hex[] = {'0','1','2','3','4','5','6','7', const char hex[] = {'0','1','2','3','4','5','6','7',
'8','9','A','B','C','D','E','F'}; '8','9','A','B','C','D','E','F'};
ACPI_FUNCTION_TRACE("acpi_ec_gpe_query"); ACPI_FUNCTION_TRACE("acpi_ec_gpe_query");
if (!data) if (!ec_cxt)
return; goto end;
query_data = (struct acpi_ec_query_data *) data; spin_lock_irqsave(&ec->lock, flags);
acpi_hw_low_level_read(8, &value, &ec->command_addr, 0);
spin_unlock_irqrestore(&ec->lock, flags);
object_name[2] = hex[((query_data->data >> 4) & 0x0F)]; /* TBD: Implement asynch events!
object_name[3] = hex[(query_data->data & 0x0F)]; * 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).
*/
if (!(value & ACPI_EC_FLAG_SCI))
goto end;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name)); if (acpi_ec_query(ec, &value))
goto end;
object_name[2] = hex[((value >> 4) & 0x0F)];
object_name[3] = hex[(value & 0x0F)];
acpi_evaluate_object(query_data->handle, object_name, NULL, NULL); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name));
kfree(query_data); acpi_evaluate_object(ec->handle, object_name, NULL, NULL);
return; end:
acpi_enable_event(ec->gpe_bit, ACPI_EVENT_GPE, 0);
} }
static void static void
acpi_ec_gpe_handler ( acpi_ec_gpe_handler (
void *data) void *data)
{ {
acpi_status status = AE_OK; acpi_status status = AE_OK;
struct acpi_ec *ec = (struct acpi_ec *) data; struct acpi_ec *ec = (struct acpi_ec *) data;
u32 value = 0;
unsigned long flags = 0;
struct acpi_ec_query_data *query_data = NULL;
if (!ec) if (!ec)
return; return;
spin_lock_irqsave(&ec->lock, flags); acpi_disable_event(ec->gpe_bit, ACPI_EVENT_GPE, 0);
acpi_hw_low_level_read(8, &value, &ec->command_addr, 0);
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).
*/
if (!(value & ACPI_EC_FLAG_SCI))
return;
if (acpi_ec_query(ec, &value))
return;
query_data = kmalloc(sizeof(struct acpi_ec_query_data), GFP_ATOMIC);
if (!query_data)
return;
query_data->handle = ec->handle;
query_data->data = value;
status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
acpi_ec_gpe_query, query_data); acpi_ec_gpe_query, ec);
if (ACPI_FAILURE(status))
kfree(query_data);
return;
} }
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
Address Space Management Address Space Management
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
...@@ -559,6 +542,7 @@ acpi_ec_add ( ...@@ -559,6 +542,7 @@ acpi_ec_add (
memset(ec, 0, sizeof(struct acpi_ec)); memset(ec, 0, sizeof(struct acpi_ec));
ec->handle = device->handle; ec->handle = device->handle;
ec->uid = -1;
ec->lock = SPIN_LOCK_UNLOCKED; ec->lock = SPIN_LOCK_UNLOCKED;
sprintf(acpi_device_name(device), "%s", ACPI_EC_DEVICE_NAME); sprintf(acpi_device_name(device), "%s", ACPI_EC_DEVICE_NAME);
sprintf(acpi_device_class(device), "%s", ACPI_EC_CLASS); sprintf(acpi_device_class(device), "%s", ACPI_EC_CLASS);
...@@ -567,10 +551,10 @@ acpi_ec_add ( ...@@ -567,10 +551,10 @@ acpi_ec_add (
/* Use the global lock for all EC transactions? */ /* Use the global lock for all EC transactions? */
acpi_evaluate_integer(ec->handle, "_GLK", NULL, &ec->global_lock); acpi_evaluate_integer(ec->handle, "_GLK", NULL, &ec->global_lock);
/* If our UID matches ecdt_uid, we already found this EC via the /* If our UID matches the UID for the ECDT-enumerated EC,
ECDT. Abort. */ we already found this EC, so abort. */
acpi_evaluate_integer(ec->handle, "_UID", NULL, &uid); acpi_evaluate_integer(ec->handle, "_UID", NULL, &uid);
if (ecdt_uid == uid) { if (ec_ecdt && ec_ecdt->uid == uid) {
result = -ENODEV; result = -ENODEV;
goto end; goto end;
} }
...@@ -758,7 +742,12 @@ acpi_ec_ecdt_probe (void) ...@@ -758,7 +742,12 @@ acpi_ec_ecdt_probe (void)
ec_ecdt->lock = SPIN_LOCK_UNLOCKED; ec_ecdt->lock = SPIN_LOCK_UNLOCKED;
/* use the GL just to be safe */ /* use the GL just to be safe */
ec_ecdt->global_lock = TRUE; ec_ecdt->global_lock = TRUE;
ecdt_uid = ecdt_ptr->uid; ec_ecdt->uid = ecdt_ptr->uid;
status = acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle);
if (ACPI_FAILURE(status)) {
goto error;
}
/* /*
* Install GPE handler * Install GPE handler
...@@ -783,7 +772,9 @@ acpi_ec_ecdt_probe (void) ...@@ -783,7 +772,9 @@ acpi_ec_ecdt_probe (void)
return 0; return 0;
error: error:
printk(KERN_ERR PREFIX "Could not use ECDT\n");
kfree(ec_ecdt); kfree(ec_ecdt);
ec_ecdt = NULL;
return -ENODEV; return -ENODEV;
} }
...@@ -835,3 +826,4 @@ acpi_ec_exit (void) ...@@ -835,3 +826,4 @@ acpi_ec_exit (void)
return_VOID; return_VOID;
} }
...@@ -330,7 +330,7 @@ struct acpi_table_ecdt { ...@@ -330,7 +330,7 @@ struct acpi_table_ecdt {
acpi_generic_address ec_data; acpi_generic_address ec_data;
u32 uid; u32 uid;
u8 gpe_bit; u8 gpe_bit;
char *ec_id; char ec_id[0];
} __attribute__ ((packed)); } __attribute__ ((packed));
/* Table Handlers */ /* Table Handlers */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment