Loading drivers/acpi/ec.c +18 −107 Original line number Diff line number Diff line Loading @@ -31,7 +31,6 @@ /* Uncomment next line to get verbose printout */ /* #define DEBUG */ #define DEBUG_REF 0 #define pr_fmt(fmt) "ACPI : EC: " fmt #include <linux/kernel.h> Loading Loading @@ -77,9 +76,7 @@ enum ec_command { * when trying to clear the EC */ enum { EC_FLAGS_EVENT_ENABLED, /* Event is enabled */ EC_FLAGS_EVENT_PENDING, /* Event is pending */ EC_FLAGS_EVENT_DETECTED, /* Event is detected */ EC_FLAGS_QUERY_PENDING, /* Query is pending */ EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and * OpReg are installed */ EC_FLAGS_STARTED, /* Driver is started */ Loading @@ -91,13 +88,6 @@ enum { #define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */ #define ACPI_EC_COMMAND_COMPLETE 0x02 /* Completed last byte */ #define ec_debug_ref(ec, fmt, ...) \ do { \ if (DEBUG_REF) \ pr_debug("%lu: " fmt, ec->reference_count, \ ## __VA_ARGS__); \ } while (0) /* ec.c is compiled in acpi namespace so this shows up as acpi.ec_delay param */ static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY; module_param(ec_delay, uint, 0644); Loading Loading @@ -161,12 +151,6 @@ static bool acpi_ec_flushed(struct acpi_ec *ec) return ec->reference_count == 1; } static bool acpi_ec_has_pending_event(struct acpi_ec *ec) { return test_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags) || test_bit(EC_FLAGS_EVENT_PENDING, &ec->flags); } /* -------------------------------------------------------------------------- * EC Registers * -------------------------------------------------------------------------- */ Loading Loading @@ -334,97 +318,34 @@ static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag) * the flush operation is not in * progress * @ec: the EC device * @allow_event: whether event should be handled * * This function must be used before taking a new action that should hold * the reference count. If this function returns false, then the action * must be discarded or it will prevent the flush operation from being * completed. * * During flushing, QR_EC command need to pass this check when there is a * pending event, so that the reference count held for the pending event * can be decreased by the completion of the QR_EC command. */ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec, bool allow_event) static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec) { if (!acpi_ec_started(ec)) { if (!allow_event || !acpi_ec_has_pending_event(ec)) if (!acpi_ec_started(ec)) return false; } acpi_ec_submit_request(ec); return true; } static void acpi_ec_submit_event(struct acpi_ec *ec) static void acpi_ec_submit_query(struct acpi_ec *ec) { if (!test_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags) || !test_bit(EC_FLAGS_EVENT_ENABLED, &ec->flags)) return; /* Hold reference for pending event */ if (!acpi_ec_submit_flushable_request(ec, true)) return; ec_debug_ref(ec, "Increase event\n"); if (!test_and_set_bit(EC_FLAGS_EVENT_PENDING, &ec->flags)) { pr_debug("***** Event query started *****\n"); if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { pr_debug("***** Event started *****\n"); schedule_work(&ec->work); return; } acpi_ec_complete_request(ec); ec_debug_ref(ec, "Decrease event\n"); } static void acpi_ec_complete_event(struct acpi_ec *ec) static void acpi_ec_complete_query(struct acpi_ec *ec) { if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { clear_bit(EC_FLAGS_EVENT_PENDING, &ec->flags); pr_debug("***** Event query stopped *****\n"); /* Unhold reference for pending event */ acpi_ec_complete_request(ec); ec_debug_ref(ec, "Decrease event\n"); /* Check if there is another SCI_EVT detected */ acpi_ec_submit_event(ec); } clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); pr_debug("***** Event stopped *****\n"); } static void acpi_ec_submit_detection(struct acpi_ec *ec) { /* Hold reference for query submission */ if (!acpi_ec_submit_flushable_request(ec, false)) return; ec_debug_ref(ec, "Increase query\n"); if (!test_and_set_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags)) { pr_debug("***** Event detection blocked *****\n"); acpi_ec_submit_event(ec); return; } acpi_ec_complete_request(ec); ec_debug_ref(ec, "Decrease query\n"); } static void acpi_ec_complete_detection(struct acpi_ec *ec) { if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { clear_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags); pr_debug("***** Event detetion unblocked *****\n"); /* Unhold reference for query submission */ acpi_ec_complete_request(ec); ec_debug_ref(ec, "Decrease query\n"); } } static void acpi_ec_enable_event(struct acpi_ec *ec) { unsigned long flags; spin_lock_irqsave(&ec->lock, flags); set_bit(EC_FLAGS_EVENT_ENABLED, &ec->flags); /* * An event may be pending even with SCI_EVT=0, so QR_EC should * always be issued right after started. */ acpi_ec_submit_detection(ec); spin_unlock_irqrestore(&ec->lock, flags); } static int ec_transaction_completed(struct acpi_ec *ec) Loading Loading @@ -468,7 +389,6 @@ static void advance_transaction(struct acpi_ec *ec) t->rdata[t->ri++] = acpi_ec_read_data(ec); if (t->rlen == t->ri) { t->flags |= ACPI_EC_COMMAND_COMPLETE; acpi_ec_complete_event(ec); if (t->command == ACPI_EC_COMMAND_QUERY) pr_debug("***** Command(%s) hardware completion *****\n", acpi_ec_cmd_string(t->command)); Loading @@ -479,7 +399,6 @@ static void advance_transaction(struct acpi_ec *ec) } else if (t->wlen == t->wi && (status & ACPI_EC_FLAG_IBF) == 0) { t->flags |= ACPI_EC_COMMAND_COMPLETE; acpi_ec_complete_event(ec); wakeup = true; } goto out; Loading @@ -488,17 +407,16 @@ static void advance_transaction(struct acpi_ec *ec) !(status & ACPI_EC_FLAG_SCI) && (t->command == ACPI_EC_COMMAND_QUERY)) { t->flags |= ACPI_EC_COMMAND_POLL; acpi_ec_complete_detection(ec); acpi_ec_complete_query(ec); t->rdata[t->ri++] = 0x00; t->flags |= ACPI_EC_COMMAND_COMPLETE; acpi_ec_complete_event(ec); pr_debug("***** Command(%s) software completion *****\n", acpi_ec_cmd_string(t->command)); wakeup = true; } else if ((status & ACPI_EC_FLAG_IBF) == 0) { acpi_ec_write_cmd(ec, t->command); t->flags |= ACPI_EC_COMMAND_POLL; acpi_ec_complete_detection(ec); acpi_ec_complete_query(ec); } else goto err; goto out; Loading @@ -519,7 +437,7 @@ static void advance_transaction(struct acpi_ec *ec) } out: if (status & ACPI_EC_FLAG_SCI) acpi_ec_submit_detection(ec); acpi_ec_submit_query(ec); if (wakeup && in_interrupt()) wake_up(&ec->wait); } Loading Loading @@ -580,11 +498,10 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, /* start transaction */ spin_lock_irqsave(&ec->lock, tmp); /* Enable GPE for command processing (IBF=0/OBF=1) */ if (!acpi_ec_submit_flushable_request(ec, true)) { if (!acpi_ec_submit_flushable_request(ec)) { ret = -EINVAL; goto unlock; } ec_debug_ref(ec, "Increase command\n"); /* following two actions should be kept atomic */ ec->curr = t; pr_debug("***** Command(%s) started *****\n", Loading @@ -600,7 +517,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, ec->curr = NULL; /* Disable GPE for command processing (IBF=0/OBF=1) */ acpi_ec_complete_request(ec); ec_debug_ref(ec, "Decrease command\n"); unlock: spin_unlock_irqrestore(&ec->lock, tmp); return ret; Loading Loading @@ -762,10 +678,8 @@ static void acpi_ec_start(struct acpi_ec *ec, bool resuming) if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) { pr_debug("+++++ Starting EC +++++\n"); /* Enable GPE for event processing (SCI_EVT=1) */ if (!resuming) { if (!resuming) acpi_ec_submit_request(ec); ec_debug_ref(ec, "Increase driver\n"); } pr_info("+++++ EC started +++++\n"); } spin_unlock_irqrestore(&ec->lock, flags); Loading Loading @@ -794,10 +708,8 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool suspending) wait_event(ec->wait, acpi_ec_stopped(ec)); spin_lock_irqsave(&ec->lock, flags); /* Disable GPE for event processing (SCI_EVT=1) */ if (!suspending) { if (!suspending) acpi_ec_complete_request(ec); ec_debug_ref(ec, "Decrease driver\n"); } clear_bit(EC_FLAGS_STARTED, &ec->flags); clear_bit(EC_FLAGS_STOPPED, &ec->flags); pr_info("+++++ EC stopped +++++\n"); Loading Loading @@ -967,9 +879,7 @@ static void acpi_ec_gpe_poller(struct work_struct *work) { struct acpi_ec *ec = container_of(work, struct acpi_ec, work); pr_debug("***** Event poller started *****\n"); acpi_ec_query(ec, NULL); pr_debug("***** Event poller stopped *****\n"); } static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, Loading Loading @@ -1039,6 +949,7 @@ static struct acpi_ec *make_acpi_ec(void) if (!ec) return NULL; ec->flags = 1 << EC_FLAGS_QUERY_PENDING; mutex_init(&ec->mutex); init_waitqueue_head(&ec->wait); INIT_LIST_HEAD(&ec->list); Loading Loading @@ -1189,7 +1100,7 @@ static int acpi_ec_add(struct acpi_device *device) ret = ec_install_handlers(ec); /* EC is fully operational, allow queries */ acpi_ec_enable_event(ec); clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); /* Clear stale _Q events if hardware might require that */ if (EC_FLAGS_CLEAR_ON_RESUME) Loading Loading
drivers/acpi/ec.c +18 −107 Original line number Diff line number Diff line Loading @@ -31,7 +31,6 @@ /* Uncomment next line to get verbose printout */ /* #define DEBUG */ #define DEBUG_REF 0 #define pr_fmt(fmt) "ACPI : EC: " fmt #include <linux/kernel.h> Loading Loading @@ -77,9 +76,7 @@ enum ec_command { * when trying to clear the EC */ enum { EC_FLAGS_EVENT_ENABLED, /* Event is enabled */ EC_FLAGS_EVENT_PENDING, /* Event is pending */ EC_FLAGS_EVENT_DETECTED, /* Event is detected */ EC_FLAGS_QUERY_PENDING, /* Query is pending */ EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and * OpReg are installed */ EC_FLAGS_STARTED, /* Driver is started */ Loading @@ -91,13 +88,6 @@ enum { #define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */ #define ACPI_EC_COMMAND_COMPLETE 0x02 /* Completed last byte */ #define ec_debug_ref(ec, fmt, ...) \ do { \ if (DEBUG_REF) \ pr_debug("%lu: " fmt, ec->reference_count, \ ## __VA_ARGS__); \ } while (0) /* ec.c is compiled in acpi namespace so this shows up as acpi.ec_delay param */ static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY; module_param(ec_delay, uint, 0644); Loading Loading @@ -161,12 +151,6 @@ static bool acpi_ec_flushed(struct acpi_ec *ec) return ec->reference_count == 1; } static bool acpi_ec_has_pending_event(struct acpi_ec *ec) { return test_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags) || test_bit(EC_FLAGS_EVENT_PENDING, &ec->flags); } /* -------------------------------------------------------------------------- * EC Registers * -------------------------------------------------------------------------- */ Loading Loading @@ -334,97 +318,34 @@ static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag) * the flush operation is not in * progress * @ec: the EC device * @allow_event: whether event should be handled * * This function must be used before taking a new action that should hold * the reference count. If this function returns false, then the action * must be discarded or it will prevent the flush operation from being * completed. * * During flushing, QR_EC command need to pass this check when there is a * pending event, so that the reference count held for the pending event * can be decreased by the completion of the QR_EC command. */ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec, bool allow_event) static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec) { if (!acpi_ec_started(ec)) { if (!allow_event || !acpi_ec_has_pending_event(ec)) if (!acpi_ec_started(ec)) return false; } acpi_ec_submit_request(ec); return true; } static void acpi_ec_submit_event(struct acpi_ec *ec) static void acpi_ec_submit_query(struct acpi_ec *ec) { if (!test_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags) || !test_bit(EC_FLAGS_EVENT_ENABLED, &ec->flags)) return; /* Hold reference for pending event */ if (!acpi_ec_submit_flushable_request(ec, true)) return; ec_debug_ref(ec, "Increase event\n"); if (!test_and_set_bit(EC_FLAGS_EVENT_PENDING, &ec->flags)) { pr_debug("***** Event query started *****\n"); if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { pr_debug("***** Event started *****\n"); schedule_work(&ec->work); return; } acpi_ec_complete_request(ec); ec_debug_ref(ec, "Decrease event\n"); } static void acpi_ec_complete_event(struct acpi_ec *ec) static void acpi_ec_complete_query(struct acpi_ec *ec) { if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { clear_bit(EC_FLAGS_EVENT_PENDING, &ec->flags); pr_debug("***** Event query stopped *****\n"); /* Unhold reference for pending event */ acpi_ec_complete_request(ec); ec_debug_ref(ec, "Decrease event\n"); /* Check if there is another SCI_EVT detected */ acpi_ec_submit_event(ec); } clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); pr_debug("***** Event stopped *****\n"); } static void acpi_ec_submit_detection(struct acpi_ec *ec) { /* Hold reference for query submission */ if (!acpi_ec_submit_flushable_request(ec, false)) return; ec_debug_ref(ec, "Increase query\n"); if (!test_and_set_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags)) { pr_debug("***** Event detection blocked *****\n"); acpi_ec_submit_event(ec); return; } acpi_ec_complete_request(ec); ec_debug_ref(ec, "Decrease query\n"); } static void acpi_ec_complete_detection(struct acpi_ec *ec) { if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { clear_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags); pr_debug("***** Event detetion unblocked *****\n"); /* Unhold reference for query submission */ acpi_ec_complete_request(ec); ec_debug_ref(ec, "Decrease query\n"); } } static void acpi_ec_enable_event(struct acpi_ec *ec) { unsigned long flags; spin_lock_irqsave(&ec->lock, flags); set_bit(EC_FLAGS_EVENT_ENABLED, &ec->flags); /* * An event may be pending even with SCI_EVT=0, so QR_EC should * always be issued right after started. */ acpi_ec_submit_detection(ec); spin_unlock_irqrestore(&ec->lock, flags); } static int ec_transaction_completed(struct acpi_ec *ec) Loading Loading @@ -468,7 +389,6 @@ static void advance_transaction(struct acpi_ec *ec) t->rdata[t->ri++] = acpi_ec_read_data(ec); if (t->rlen == t->ri) { t->flags |= ACPI_EC_COMMAND_COMPLETE; acpi_ec_complete_event(ec); if (t->command == ACPI_EC_COMMAND_QUERY) pr_debug("***** Command(%s) hardware completion *****\n", acpi_ec_cmd_string(t->command)); Loading @@ -479,7 +399,6 @@ static void advance_transaction(struct acpi_ec *ec) } else if (t->wlen == t->wi && (status & ACPI_EC_FLAG_IBF) == 0) { t->flags |= ACPI_EC_COMMAND_COMPLETE; acpi_ec_complete_event(ec); wakeup = true; } goto out; Loading @@ -488,17 +407,16 @@ static void advance_transaction(struct acpi_ec *ec) !(status & ACPI_EC_FLAG_SCI) && (t->command == ACPI_EC_COMMAND_QUERY)) { t->flags |= ACPI_EC_COMMAND_POLL; acpi_ec_complete_detection(ec); acpi_ec_complete_query(ec); t->rdata[t->ri++] = 0x00; t->flags |= ACPI_EC_COMMAND_COMPLETE; acpi_ec_complete_event(ec); pr_debug("***** Command(%s) software completion *****\n", acpi_ec_cmd_string(t->command)); wakeup = true; } else if ((status & ACPI_EC_FLAG_IBF) == 0) { acpi_ec_write_cmd(ec, t->command); t->flags |= ACPI_EC_COMMAND_POLL; acpi_ec_complete_detection(ec); acpi_ec_complete_query(ec); } else goto err; goto out; Loading @@ -519,7 +437,7 @@ static void advance_transaction(struct acpi_ec *ec) } out: if (status & ACPI_EC_FLAG_SCI) acpi_ec_submit_detection(ec); acpi_ec_submit_query(ec); if (wakeup && in_interrupt()) wake_up(&ec->wait); } Loading Loading @@ -580,11 +498,10 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, /* start transaction */ spin_lock_irqsave(&ec->lock, tmp); /* Enable GPE for command processing (IBF=0/OBF=1) */ if (!acpi_ec_submit_flushable_request(ec, true)) { if (!acpi_ec_submit_flushable_request(ec)) { ret = -EINVAL; goto unlock; } ec_debug_ref(ec, "Increase command\n"); /* following two actions should be kept atomic */ ec->curr = t; pr_debug("***** Command(%s) started *****\n", Loading @@ -600,7 +517,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, ec->curr = NULL; /* Disable GPE for command processing (IBF=0/OBF=1) */ acpi_ec_complete_request(ec); ec_debug_ref(ec, "Decrease command\n"); unlock: spin_unlock_irqrestore(&ec->lock, tmp); return ret; Loading Loading @@ -762,10 +678,8 @@ static void acpi_ec_start(struct acpi_ec *ec, bool resuming) if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) { pr_debug("+++++ Starting EC +++++\n"); /* Enable GPE for event processing (SCI_EVT=1) */ if (!resuming) { if (!resuming) acpi_ec_submit_request(ec); ec_debug_ref(ec, "Increase driver\n"); } pr_info("+++++ EC started +++++\n"); } spin_unlock_irqrestore(&ec->lock, flags); Loading Loading @@ -794,10 +708,8 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool suspending) wait_event(ec->wait, acpi_ec_stopped(ec)); spin_lock_irqsave(&ec->lock, flags); /* Disable GPE for event processing (SCI_EVT=1) */ if (!suspending) { if (!suspending) acpi_ec_complete_request(ec); ec_debug_ref(ec, "Decrease driver\n"); } clear_bit(EC_FLAGS_STARTED, &ec->flags); clear_bit(EC_FLAGS_STOPPED, &ec->flags); pr_info("+++++ EC stopped +++++\n"); Loading Loading @@ -967,9 +879,7 @@ static void acpi_ec_gpe_poller(struct work_struct *work) { struct acpi_ec *ec = container_of(work, struct acpi_ec, work); pr_debug("***** Event poller started *****\n"); acpi_ec_query(ec, NULL); pr_debug("***** Event poller stopped *****\n"); } static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, Loading Loading @@ -1039,6 +949,7 @@ static struct acpi_ec *make_acpi_ec(void) if (!ec) return NULL; ec->flags = 1 << EC_FLAGS_QUERY_PENDING; mutex_init(&ec->mutex); init_waitqueue_head(&ec->wait); INIT_LIST_HEAD(&ec->list); Loading Loading @@ -1189,7 +1100,7 @@ static int acpi_ec_add(struct acpi_device *device) ret = ec_install_handlers(ec); /* EC is fully operational, allow queries */ acpi_ec_enable_event(ec); clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); /* Clear stale _Q events if hardware might require that */ if (EC_FLAGS_CLEAR_ON_RESUME) Loading