aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLv Zheng <lv.zheng@intel.com>2016-03-23 22:42:47 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-04-08 21:06:43 -0400
commit0e1affe41bdd7b1bef64c007d260e142bcaef220 (patch)
tree5ba7a34f72803543ddd36996f256ff79dd544a44
parent9735a22799b9214d17d3c231fe377fc852f042e9 (diff)
ACPI 2.0 / ECDT: Split EC_FLAGS_HANDLERS_INSTALLED
This patch splits EC_FLAGS_HANDLERS_INSTALLED so that address space handler can be installed when it is not possible to install GPE handler during early stage. This patch also tunes address space handler installation, making it happening earlier than GPE handler installation for the same purpose. Since acpi_ec_start()/acpi_ec_stop() will be entered multiple times after applying this change, it is also required to protect acpi_enable_gpe()/ acpi_disable_gpe() invocations. Link: https://bugzilla.kernel.org/show_bug.cgi?id=112911 Signed-off-by: Lv Zheng <lv.zheng@intel.com> Tested-by: Chris Bainbridge <chris.bainbridge@gmail.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/ec.c96
1 files changed, 55 insertions, 41 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index b420fb46669d..b8f474b78bc7 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -105,8 +105,8 @@ enum ec_command {
105enum { 105enum {
106 EC_FLAGS_QUERY_PENDING, /* Query is pending */ 106 EC_FLAGS_QUERY_PENDING, /* Query is pending */
107 EC_FLAGS_QUERY_GUARDING, /* Guard for SCI_EVT check */ 107 EC_FLAGS_QUERY_GUARDING, /* Guard for SCI_EVT check */
108 EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and 108 EC_FLAGS_GPE_HANDLER_INSTALLED, /* GPE handler installed */
109 * OpReg are installed */ 109 EC_FLAGS_EC_HANDLER_INSTALLED, /* OpReg handler installed */
110 EC_FLAGS_STARTED, /* Driver is started */ 110 EC_FLAGS_STARTED, /* Driver is started */
111 EC_FLAGS_STOPPED, /* Driver is stopped */ 111 EC_FLAGS_STOPPED, /* Driver is stopped */
112 EC_FLAGS_COMMAND_STORM, /* GPE storms occurred to the 112 EC_FLAGS_COMMAND_STORM, /* GPE storms occurred to the
@@ -367,7 +367,8 @@ static inline void acpi_ec_clear_gpe(struct acpi_ec *ec)
367static void acpi_ec_submit_request(struct acpi_ec *ec) 367static void acpi_ec_submit_request(struct acpi_ec *ec)
368{ 368{
369 ec->reference_count++; 369 ec->reference_count++;
370 if (ec->reference_count == 1) 370 if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags) &&
371 ec->reference_count == 1)
371 acpi_ec_enable_gpe(ec, true); 372 acpi_ec_enable_gpe(ec, true);
372} 373}
373 374
@@ -376,7 +377,8 @@ static void acpi_ec_complete_request(struct acpi_ec *ec)
376 bool flushed = false; 377 bool flushed = false;
377 378
378 ec->reference_count--; 379 ec->reference_count--;
379 if (ec->reference_count == 0) 380 if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags) &&
381 ec->reference_count == 0)
380 acpi_ec_disable_gpe(ec, true); 382 acpi_ec_disable_gpe(ec, true);
381 flushed = acpi_ec_flushed(ec); 383 flushed = acpi_ec_flushed(ec);
382 if (flushed) 384 if (flushed)
@@ -1287,52 +1289,64 @@ static int ec_install_handlers(struct acpi_ec *ec)
1287{ 1289{
1288 acpi_status status; 1290 acpi_status status;
1289 1291
1290 if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
1291 return 0;
1292 status = acpi_install_gpe_raw_handler(NULL, ec->gpe,
1293 ACPI_GPE_EDGE_TRIGGERED,
1294 &acpi_ec_gpe_handler, ec);
1295 if (ACPI_FAILURE(status))
1296 return -ENODEV;
1297
1298 acpi_ec_start(ec, false); 1292 acpi_ec_start(ec, false);
1299 status = acpi_install_address_space_handler(ec->handle, 1293
1300 ACPI_ADR_SPACE_EC, 1294 if (!test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) {
1301 &acpi_ec_space_handler, 1295 status = acpi_install_address_space_handler(ec->handle,
1302 NULL, ec); 1296 ACPI_ADR_SPACE_EC,
1303 if (ACPI_FAILURE(status)) { 1297 &acpi_ec_space_handler,
1304 if (status == AE_NOT_FOUND) { 1298 NULL, ec);
1305 /* 1299 if (ACPI_FAILURE(status)) {
1306 * Maybe OS fails in evaluating the _REG object. 1300 if (status == AE_NOT_FOUND) {
1307 * The AE_NOT_FOUND error will be ignored and OS 1301 /*
1308 * continue to initialize EC. 1302 * Maybe OS fails in evaluating the _REG
1309 */ 1303 * object. The AE_NOT_FOUND error will be
1310 pr_err("Fail in evaluating the _REG object" 1304 * ignored and OS * continue to initialize
1311 " of EC device. Broken bios is suspected.\n"); 1305 * EC.
1312 } else { 1306 */
1313 acpi_ec_stop(ec, false); 1307 pr_err("Fail in evaluating the _REG object"
1314 acpi_remove_gpe_handler(NULL, ec->gpe, 1308 " of EC device. Broken bios is suspected.\n");
1315 &acpi_ec_gpe_handler); 1309 } else {
1316 return -ENODEV; 1310 acpi_ec_stop(ec, false);
1311 return -ENODEV;
1312 }
1313 }
1314 set_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags);
1315 }
1316
1317 if (!test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags)) {
1318 status = acpi_install_gpe_raw_handler(NULL, ec->gpe,
1319 ACPI_GPE_EDGE_TRIGGERED,
1320 &acpi_ec_gpe_handler, ec);
1321 /* This is not fatal as we can poll EC events */
1322 if (ACPI_SUCCESS(status)) {
1323 set_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags);
1324 if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
1325 ec->reference_count >= 1)
1326 acpi_ec_enable_gpe(ec, true);
1317 } 1327 }
1318 } 1328 }
1319 1329
1320 set_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags);
1321 return 0; 1330 return 0;
1322} 1331}
1323 1332
1324static void ec_remove_handlers(struct acpi_ec *ec) 1333static void ec_remove_handlers(struct acpi_ec *ec)
1325{ 1334{
1326 if (!test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
1327 return;
1328 acpi_ec_stop(ec, false); 1335 acpi_ec_stop(ec, false);
1329 if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, 1336
1330 ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) 1337 if (test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) {
1331 pr_err("failed to remove space handler\n"); 1338 if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
1332 if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe, 1339 ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
1333 &acpi_ec_gpe_handler))) 1340 pr_err("failed to remove space handler\n");
1334 pr_err("failed to remove gpe handler\n"); 1341 clear_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags);
1335 clear_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags); 1342 }
1343
1344 if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags)) {
1345 if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
1346 &acpi_ec_gpe_handler)))
1347 pr_err("failed to remove gpe handler\n");
1348 clear_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags);
1349 }
1336} 1350}
1337 1351
1338static int acpi_ec_add(struct acpi_device *device) 1352static int acpi_ec_add(struct acpi_device *device)
@@ -1434,7 +1448,7 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context)
1434 1448
1435int __init acpi_boot_ec_enable(void) 1449int __init acpi_boot_ec_enable(void)
1436{ 1450{
1437 if (!boot_ec || test_bit(EC_FLAGS_HANDLERS_INSTALLED, &boot_ec->flags)) 1451 if (!boot_ec)
1438 return 0; 1452 return 0;
1439 if (!ec_install_handlers(boot_ec)) { 1453 if (!ec_install_handlers(boot_ec)) {
1440 first_ec = boot_ec; 1454 first_ec = boot_ec;