diff options
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r-- | drivers/acpi/ec.c | 96 |
1 files changed, 67 insertions, 29 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index ba5b56db9d27..d7d32c28829b 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -39,10 +39,9 @@ | |||
39 | #include <linux/list.h> | 39 | #include <linux/list.h> |
40 | #include <linux/spinlock.h> | 40 | #include <linux/spinlock.h> |
41 | #include <linux/slab.h> | 41 | #include <linux/slab.h> |
42 | #include <asm/io.h> | 42 | #include <linux/acpi.h> |
43 | #include <acpi/acpi_bus.h> | ||
44 | #include <acpi/acpi_drivers.h> | ||
45 | #include <linux/dmi.h> | 43 | #include <linux/dmi.h> |
44 | #include <asm/io.h> | ||
46 | 45 | ||
47 | #include "internal.h" | 46 | #include "internal.h" |
48 | 47 | ||
@@ -68,6 +67,8 @@ enum ec_command { | |||
68 | #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ | 67 | #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ |
69 | #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ | 68 | #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ |
70 | #define ACPI_EC_MSI_UDELAY 550 /* Wait 550us for MSI EC */ | 69 | #define ACPI_EC_MSI_UDELAY 550 /* Wait 550us for MSI EC */ |
70 | #define ACPI_EC_CLEAR_MAX 100 /* Maximum number of events to query | ||
71 | * when trying to clear the EC */ | ||
71 | 72 | ||
72 | enum { | 73 | enum { |
73 | EC_FLAGS_QUERY_PENDING, /* Query is pending */ | 74 | EC_FLAGS_QUERY_PENDING, /* Query is pending */ |
@@ -91,10 +92,6 @@ static unsigned int ec_storm_threshold __read_mostly = 8; | |||
91 | module_param(ec_storm_threshold, uint, 0644); | 92 | module_param(ec_storm_threshold, uint, 0644); |
92 | MODULE_PARM_DESC(ec_storm_threshold, "Maxim false GPE numbers not considered as GPE storm"); | 93 | MODULE_PARM_DESC(ec_storm_threshold, "Maxim false GPE numbers not considered as GPE storm"); |
93 | 94 | ||
94 | /* If we find an EC via the ECDT, we need to keep a ptr to its context */ | ||
95 | /* External interfaces use first EC only, so remember */ | ||
96 | typedef int (*acpi_ec_query_func) (void *data); | ||
97 | |||
98 | struct acpi_ec_query_handler { | 95 | struct acpi_ec_query_handler { |
99 | struct list_head node; | 96 | struct list_head node; |
100 | acpi_ec_query_func func; | 97 | acpi_ec_query_func func; |
@@ -121,6 +118,7 @@ EXPORT_SYMBOL(first_ec); | |||
121 | static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */ | 118 | static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */ |
122 | static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */ | 119 | static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */ |
123 | static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */ | 120 | static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */ |
121 | static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ | ||
124 | 122 | ||
125 | /* -------------------------------------------------------------------------- | 123 | /* -------------------------------------------------------------------------- |
126 | Transaction Management | 124 | Transaction Management |
@@ -387,27 +385,6 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) | |||
387 | return acpi_ec_transaction(ec, &t); | 385 | return acpi_ec_transaction(ec, &t); |
388 | } | 386 | } |
389 | 387 | ||
390 | /* | ||
391 | * Externally callable EC access functions. For now, assume 1 EC only | ||
392 | */ | ||
393 | int ec_burst_enable(void) | ||
394 | { | ||
395 | if (!first_ec) | ||
396 | return -ENODEV; | ||
397 | return acpi_ec_burst_enable(first_ec); | ||
398 | } | ||
399 | |||
400 | EXPORT_SYMBOL(ec_burst_enable); | ||
401 | |||
402 | int ec_burst_disable(void) | ||
403 | { | ||
404 | if (!first_ec) | ||
405 | return -ENODEV; | ||
406 | return acpi_ec_burst_disable(first_ec); | ||
407 | } | ||
408 | |||
409 | EXPORT_SYMBOL(ec_burst_disable); | ||
410 | |||
411 | int ec_read(u8 addr, u8 *val) | 388 | int ec_read(u8 addr, u8 *val) |
412 | { | 389 | { |
413 | int err; | 390 | int err; |
@@ -466,6 +443,29 @@ acpi_handle ec_get_handle(void) | |||
466 | 443 | ||
467 | EXPORT_SYMBOL(ec_get_handle); | 444 | EXPORT_SYMBOL(ec_get_handle); |
468 | 445 | ||
446 | static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data); | ||
447 | |||
448 | /* | ||
449 | * Clears stale _Q events that might have accumulated in the EC. | ||
450 | * Run with locked ec mutex. | ||
451 | */ | ||
452 | static void acpi_ec_clear(struct acpi_ec *ec) | ||
453 | { | ||
454 | int i, status; | ||
455 | u8 value = 0; | ||
456 | |||
457 | for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) { | ||
458 | status = acpi_ec_query_unlocked(ec, &value); | ||
459 | if (status || !value) | ||
460 | break; | ||
461 | } | ||
462 | |||
463 | if (unlikely(i == ACPI_EC_CLEAR_MAX)) | ||
464 | pr_warn("Warning: Maximum of %d stale EC events cleared\n", i); | ||
465 | else | ||
466 | pr_info("%d stale EC events cleared\n", i); | ||
467 | } | ||
468 | |||
469 | void acpi_ec_block_transactions(void) | 469 | void acpi_ec_block_transactions(void) |
470 | { | 470 | { |
471 | struct acpi_ec *ec = first_ec; | 471 | struct acpi_ec *ec = first_ec; |
@@ -489,6 +489,10 @@ void acpi_ec_unblock_transactions(void) | |||
489 | mutex_lock(&ec->mutex); | 489 | mutex_lock(&ec->mutex); |
490 | /* Allow transactions to be carried out again */ | 490 | /* Allow transactions to be carried out again */ |
491 | clear_bit(EC_FLAGS_BLOCKED, &ec->flags); | 491 | clear_bit(EC_FLAGS_BLOCKED, &ec->flags); |
492 | |||
493 | if (EC_FLAGS_CLEAR_ON_RESUME) | ||
494 | acpi_ec_clear(ec); | ||
495 | |||
492 | mutex_unlock(&ec->mutex); | 496 | mutex_unlock(&ec->mutex); |
493 | } | 497 | } |
494 | 498 | ||
@@ -779,9 +783,9 @@ static int ec_install_handlers(struct acpi_ec *ec) | |||
779 | pr_err("Fail in evaluating the _REG object" | 783 | pr_err("Fail in evaluating the _REG object" |
780 | " of EC device. Broken bios is suspected.\n"); | 784 | " of EC device. Broken bios is suspected.\n"); |
781 | } else { | 785 | } else { |
786 | acpi_disable_gpe(NULL, ec->gpe); | ||
782 | acpi_remove_gpe_handler(NULL, ec->gpe, | 787 | acpi_remove_gpe_handler(NULL, ec->gpe, |
783 | &acpi_ec_gpe_handler); | 788 | &acpi_ec_gpe_handler); |
784 | acpi_disable_gpe(NULL, ec->gpe); | ||
785 | return -ENODEV; | 789 | return -ENODEV; |
786 | } | 790 | } |
787 | } | 791 | } |
@@ -847,6 +851,13 @@ static int acpi_ec_add(struct acpi_device *device) | |||
847 | 851 | ||
848 | /* EC is fully operational, allow queries */ | 852 | /* EC is fully operational, allow queries */ |
849 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); | 853 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
854 | |||
855 | /* Clear stale _Q events if hardware might require that */ | ||
856 | if (EC_FLAGS_CLEAR_ON_RESUME) { | ||
857 | mutex_lock(&ec->mutex); | ||
858 | acpi_ec_clear(ec); | ||
859 | mutex_unlock(&ec->mutex); | ||
860 | } | ||
850 | return ret; | 861 | return ret; |
851 | } | 862 | } |
852 | 863 | ||
@@ -948,6 +959,30 @@ static int ec_enlarge_storm_threshold(const struct dmi_system_id *id) | |||
948 | return 0; | 959 | return 0; |
949 | } | 960 | } |
950 | 961 | ||
962 | /* | ||
963 | * On some hardware it is necessary to clear events accumulated by the EC during | ||
964 | * sleep. These ECs stop reporting GPEs until they are manually polled, if too | ||
965 | * many events are accumulated. (e.g. Samsung Series 5/9 notebooks) | ||
966 | * | ||
967 | * https://bugzilla.kernel.org/show_bug.cgi?id=44161 | ||
968 | * | ||
969 | * Ideally, the EC should also be instructed NOT to accumulate events during | ||
970 | * sleep (which Windows seems to do somehow), but the interface to control this | ||
971 | * behaviour is not known at this time. | ||
972 | * | ||
973 | * Models known to be affected are Samsung 530Uxx/535Uxx/540Uxx/550Pxx/900Xxx, | ||
974 | * however it is very likely that other Samsung models are affected. | ||
975 | * | ||
976 | * On systems which don't accumulate _Q events during sleep, this extra check | ||
977 | * should be harmless. | ||
978 | */ | ||
979 | static int ec_clear_on_resume(const struct dmi_system_id *id) | ||
980 | { | ||
981 | pr_debug("Detected system needing EC poll on resume.\n"); | ||
982 | EC_FLAGS_CLEAR_ON_RESUME = 1; | ||
983 | return 0; | ||
984 | } | ||
985 | |||
951 | static struct dmi_system_id ec_dmi_table[] __initdata = { | 986 | static struct dmi_system_id ec_dmi_table[] __initdata = { |
952 | { | 987 | { |
953 | ec_skip_dsdt_scan, "Compal JFL92", { | 988 | ec_skip_dsdt_scan, "Compal JFL92", { |
@@ -991,6 +1026,9 @@ static struct dmi_system_id ec_dmi_table[] __initdata = { | |||
991 | ec_validate_ecdt, "ASUS hardware", { | 1026 | ec_validate_ecdt, "ASUS hardware", { |
992 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek Computer Inc."), | 1027 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek Computer Inc."), |
993 | DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),}, NULL}, | 1028 | DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),}, NULL}, |
1029 | { | ||
1030 | ec_clear_on_resume, "Samsung hardware", { | ||
1031 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL}, | ||
994 | {}, | 1032 | {}, |
995 | }; | 1033 | }; |
996 | 1034 | ||