Loading drivers/acpi/ec.c +77 −45 Original line number Diff line number Diff line Loading @@ -201,14 +201,13 @@ static void advance_transaction(struct acpi_ec *ec, u8 status) spin_unlock_irqrestore(&ec->curr_lock, flags); } static void acpi_ec_gpe_query(void *ec_cxt); static int acpi_ec_sync_query(struct acpi_ec *ec); static int ec_check_sci(struct acpi_ec *ec, u8 state) static int ec_check_sci_sync(struct acpi_ec *ec, u8 state) { if (state & ACPI_EC_FLAG_SCI) { if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) return acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec); return acpi_ec_sync_query(ec); } return 0; } Loading Loading @@ -249,11 +248,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, { unsigned long tmp; int ret = 0; pr_debug(PREFIX "transaction start\n"); /* disable GPE during transaction if storm is detected */ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { acpi_disable_gpe(NULL, ec->gpe); } if (EC_FLAGS_MSI) udelay(ACPI_EC_MSI_UDELAY); /* start transaction */ Loading @@ -269,16 +263,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, spin_lock_irqsave(&ec->curr_lock, tmp); ec->curr = NULL; spin_unlock_irqrestore(&ec->curr_lock, tmp); if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { /* check if we received SCI during transaction */ ec_check_sci(ec, acpi_ec_read_status(ec)); /* it is safe to enable GPE outside of transaction */ acpi_enable_gpe(NULL, ec->gpe); } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) { pr_info(PREFIX "GPE storm detected, " "transactions will use polling mode\n"); set_bit(EC_FLAGS_GPE_STORM, &ec->flags); } return ret; } Loading Loading @@ -321,7 +305,24 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) status = -ETIME; goto end; } pr_debug(PREFIX "transaction start\n"); /* disable GPE during transaction if storm is detected */ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { acpi_disable_gpe(NULL, ec->gpe); } status = acpi_ec_transaction_unlocked(ec, t); /* check if we received SCI during transaction */ ec_check_sci_sync(ec, acpi_ec_read_status(ec)); if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { /* it is safe to enable GPE outside of transaction */ acpi_enable_gpe(NULL, ec->gpe); } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) { pr_info(PREFIX "GPE storm detected, " "transactions will use polling mode\n"); set_bit(EC_FLAGS_GPE_STORM, &ec->flags); } end: if (ec->global_lock) acpi_release_global_lock(glk); Loading Loading @@ -443,7 +444,7 @@ int ec_transaction(u8 command, EXPORT_SYMBOL(ec_transaction); static int acpi_ec_query(struct acpi_ec *ec, u8 * data) static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data) { int result; u8 d; Loading @@ -452,20 +453,16 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data) .wlen = 0, .rlen = 1}; if (!ec || !data) return -EINVAL; /* * Query the EC to find out which _Qxx method we need to evaluate. * Note that successful completion of the query causes the ACPI_EC_SCI * bit to be cleared (and thus clearing the interrupt source). */ result = acpi_ec_transaction(ec, &t); result = acpi_ec_transaction_unlocked(ec, &t); if (result) return result; if (!d) return -ENODATA; *data = d; return 0; } Loading Loading @@ -509,43 +506,78 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); static void acpi_ec_gpe_query(void *ec_cxt) static void acpi_ec_run(void *cxt) { struct acpi_ec *ec = ec_cxt; u8 value = 0; struct acpi_ec_query_handler *handler, copy; if (!ec || acpi_ec_query(ec, &value)) struct acpi_ec_query_handler *handler = cxt; if (!handler) return; mutex_lock(&ec->lock); pr_debug(PREFIX "start query execution\n"); if (handler->func) handler->func(handler->data); else if (handler->handle) acpi_evaluate_object(handler->handle, NULL, NULL, NULL); pr_debug(PREFIX "stop query execution\n"); kfree(handler); } static int acpi_ec_sync_query(struct acpi_ec *ec) { u8 value = 0; int status; struct acpi_ec_query_handler *handler, *copy; if ((status = acpi_ec_query_unlocked(ec, &value))) return status; list_for_each_entry(handler, &ec->list, node) { if (value == handler->query_bit) { /* have custom handler for this bit */ memcpy(©, handler, sizeof(copy)); mutex_unlock(&ec->lock); if (copy.func) { copy.func(copy.data); } else if (copy.handle) { acpi_evaluate_object(copy.handle, NULL, NULL, NULL); copy = kmalloc(sizeof(*handler), GFP_KERNEL); if (!copy) return -ENOMEM; memcpy(copy, handler, sizeof(*copy)); pr_debug(PREFIX "push query execution (0x%2x) on queue\n", value); return acpi_os_execute(OSL_GPE_HANDLER, acpi_ec_run, copy); } return; } return 0; } static void acpi_ec_gpe_query(void *ec_cxt) { struct acpi_ec *ec = ec_cxt; if (!ec) return; mutex_lock(&ec->lock); acpi_ec_sync_query(ec); mutex_unlock(&ec->lock); } static void acpi_ec_gpe_query(void *ec_cxt); static int ec_check_sci(struct acpi_ec *ec, u8 state) { if (state & ACPI_EC_FLAG_SCI) { if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { pr_debug(PREFIX "push gpe query to the queue\n"); return acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ec_gpe_query, ec); } } return 0; } static u32 acpi_ec_gpe_handler(void *data) { struct acpi_ec *ec = data; u8 status; pr_debug(PREFIX "~~~> interrupt\n"); status = acpi_ec_read_status(ec); advance_transaction(ec, status); if (ec_transaction_done(ec) && (status & ACPI_EC_FLAG_IBF) == 0) advance_transaction(ec, acpi_ec_read_status(ec)); if (ec_transaction_done(ec) && (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) { wake_up(&ec->wait); ec_check_sci(ec, status); ec_check_sci(ec, acpi_ec_read_status(ec)); } return ACPI_INTERRUPT_HANDLED; } Loading Loading
drivers/acpi/ec.c +77 −45 Original line number Diff line number Diff line Loading @@ -201,14 +201,13 @@ static void advance_transaction(struct acpi_ec *ec, u8 status) spin_unlock_irqrestore(&ec->curr_lock, flags); } static void acpi_ec_gpe_query(void *ec_cxt); static int acpi_ec_sync_query(struct acpi_ec *ec); static int ec_check_sci(struct acpi_ec *ec, u8 state) static int ec_check_sci_sync(struct acpi_ec *ec, u8 state) { if (state & ACPI_EC_FLAG_SCI) { if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) return acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec); return acpi_ec_sync_query(ec); } return 0; } Loading Loading @@ -249,11 +248,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, { unsigned long tmp; int ret = 0; pr_debug(PREFIX "transaction start\n"); /* disable GPE during transaction if storm is detected */ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { acpi_disable_gpe(NULL, ec->gpe); } if (EC_FLAGS_MSI) udelay(ACPI_EC_MSI_UDELAY); /* start transaction */ Loading @@ -269,16 +263,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, spin_lock_irqsave(&ec->curr_lock, tmp); ec->curr = NULL; spin_unlock_irqrestore(&ec->curr_lock, tmp); if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { /* check if we received SCI during transaction */ ec_check_sci(ec, acpi_ec_read_status(ec)); /* it is safe to enable GPE outside of transaction */ acpi_enable_gpe(NULL, ec->gpe); } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) { pr_info(PREFIX "GPE storm detected, " "transactions will use polling mode\n"); set_bit(EC_FLAGS_GPE_STORM, &ec->flags); } return ret; } Loading Loading @@ -321,7 +305,24 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) status = -ETIME; goto end; } pr_debug(PREFIX "transaction start\n"); /* disable GPE during transaction if storm is detected */ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { acpi_disable_gpe(NULL, ec->gpe); } status = acpi_ec_transaction_unlocked(ec, t); /* check if we received SCI during transaction */ ec_check_sci_sync(ec, acpi_ec_read_status(ec)); if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { /* it is safe to enable GPE outside of transaction */ acpi_enable_gpe(NULL, ec->gpe); } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) { pr_info(PREFIX "GPE storm detected, " "transactions will use polling mode\n"); set_bit(EC_FLAGS_GPE_STORM, &ec->flags); } end: if (ec->global_lock) acpi_release_global_lock(glk); Loading Loading @@ -443,7 +444,7 @@ int ec_transaction(u8 command, EXPORT_SYMBOL(ec_transaction); static int acpi_ec_query(struct acpi_ec *ec, u8 * data) static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data) { int result; u8 d; Loading @@ -452,20 +453,16 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data) .wlen = 0, .rlen = 1}; if (!ec || !data) return -EINVAL; /* * Query the EC to find out which _Qxx method we need to evaluate. * Note that successful completion of the query causes the ACPI_EC_SCI * bit to be cleared (and thus clearing the interrupt source). */ result = acpi_ec_transaction(ec, &t); result = acpi_ec_transaction_unlocked(ec, &t); if (result) return result; if (!d) return -ENODATA; *data = d; return 0; } Loading Loading @@ -509,43 +506,78 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); static void acpi_ec_gpe_query(void *ec_cxt) static void acpi_ec_run(void *cxt) { struct acpi_ec *ec = ec_cxt; u8 value = 0; struct acpi_ec_query_handler *handler, copy; if (!ec || acpi_ec_query(ec, &value)) struct acpi_ec_query_handler *handler = cxt; if (!handler) return; mutex_lock(&ec->lock); pr_debug(PREFIX "start query execution\n"); if (handler->func) handler->func(handler->data); else if (handler->handle) acpi_evaluate_object(handler->handle, NULL, NULL, NULL); pr_debug(PREFIX "stop query execution\n"); kfree(handler); } static int acpi_ec_sync_query(struct acpi_ec *ec) { u8 value = 0; int status; struct acpi_ec_query_handler *handler, *copy; if ((status = acpi_ec_query_unlocked(ec, &value))) return status; list_for_each_entry(handler, &ec->list, node) { if (value == handler->query_bit) { /* have custom handler for this bit */ memcpy(©, handler, sizeof(copy)); mutex_unlock(&ec->lock); if (copy.func) { copy.func(copy.data); } else if (copy.handle) { acpi_evaluate_object(copy.handle, NULL, NULL, NULL); copy = kmalloc(sizeof(*handler), GFP_KERNEL); if (!copy) return -ENOMEM; memcpy(copy, handler, sizeof(*copy)); pr_debug(PREFIX "push query execution (0x%2x) on queue\n", value); return acpi_os_execute(OSL_GPE_HANDLER, acpi_ec_run, copy); } return; } return 0; } static void acpi_ec_gpe_query(void *ec_cxt) { struct acpi_ec *ec = ec_cxt; if (!ec) return; mutex_lock(&ec->lock); acpi_ec_sync_query(ec); mutex_unlock(&ec->lock); } static void acpi_ec_gpe_query(void *ec_cxt); static int ec_check_sci(struct acpi_ec *ec, u8 state) { if (state & ACPI_EC_FLAG_SCI) { if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { pr_debug(PREFIX "push gpe query to the queue\n"); return acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ec_gpe_query, ec); } } return 0; } static u32 acpi_ec_gpe_handler(void *data) { struct acpi_ec *ec = data; u8 status; pr_debug(PREFIX "~~~> interrupt\n"); status = acpi_ec_read_status(ec); advance_transaction(ec, status); if (ec_transaction_done(ec) && (status & ACPI_EC_FLAG_IBF) == 0) advance_transaction(ec, acpi_ec_read_status(ec)); if (ec_transaction_done(ec) && (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) { wake_up(&ec->wait); ec_check_sci(ec, status); ec_check_sci(ec, acpi_ec_read_status(ec)); } return ACPI_INTERRUPT_HANDLED; } Loading