diff options
Diffstat (limited to 'drivers/acpi/ec.c')
| -rw-r--r-- | drivers/acpi/ec.c | 468 | 
1 files changed, 379 insertions, 89 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index e7bd57cc550a..680531062160 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -104,10 +104,12 @@ enum ec_command {  #define ACPI_EC_MAX_QUERIES	16	/* Maximum number of parallel queries */  enum { +	EC_FLAGS_QUERY_ENABLED,		/* Query is enabled */  	EC_FLAGS_QUERY_PENDING,		/* Query is pending */  	EC_FLAGS_QUERY_GUARDING,	/* Guard for SCI_EVT check */  	EC_FLAGS_GPE_HANDLER_INSTALLED,	/* GPE handler installed */  	EC_FLAGS_EC_HANDLER_INSTALLED,	/* OpReg handler installed */ +	EC_FLAGS_EVT_HANDLER_INSTALLED, /* _Qxx handlers installed */  	EC_FLAGS_STARTED,		/* Driver is started */  	EC_FLAGS_STOPPED,		/* Driver is stopped */  	EC_FLAGS_COMMAND_STORM,		/* GPE storms occurred to the @@ -145,6 +147,10 @@ static unsigned int ec_storm_threshold  __read_mostly = 8;  module_param(ec_storm_threshold, uint, 0644);  MODULE_PARM_DESC(ec_storm_threshold, "Maxim false GPE numbers not considered as GPE storm"); +static bool ec_freeze_events __read_mostly = true; +module_param(ec_freeze_events, bool, 0644); +MODULE_PARM_DESC(ec_freeze_events, "Disabling event handling during suspend/resume"); +  struct acpi_ec_query_handler {  	struct list_head node;  	acpi_ec_query_func func; @@ -179,6 +185,7 @@ static void acpi_ec_event_processor(struct work_struct *work);  struct acpi_ec *boot_ec, *first_ec;  EXPORT_SYMBOL(first_ec); +static bool boot_ec_is_ecdt = false;  static struct workqueue_struct *ec_query_wq;  static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ @@ -239,6 +246,30 @@ static bool acpi_ec_started(struct acpi_ec *ec)  	       !test_bit(EC_FLAGS_STOPPED, &ec->flags);  } +static bool acpi_ec_event_enabled(struct acpi_ec *ec) +{ +	/* +	 * There is an OSPM early stage logic. During the early stages +	 * (boot/resume), OSPMs shouldn't enable the event handling, only +	 * the EC transactions are allowed to be performed. +	 */ +	if (!test_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags)) +		return false; +	/* +	 * However, disabling the event handling is experimental for late +	 * stage (suspend), and is controlled by the boot parameter of +	 * "ec_freeze_events": +	 * 1. true:  The EC event handling is disabled before entering +	 *           the noirq stage. +	 * 2. false: The EC event handling is automatically disabled as +	 *           soon as the EC driver is stopped. +	 */ +	if (ec_freeze_events) +		return acpi_ec_started(ec); +	else +		return test_bit(EC_FLAGS_STARTED, &ec->flags); +} +  static bool acpi_ec_flushed(struct acpi_ec *ec)  {  	return ec->reference_count == 1; @@ -429,7 +460,8 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec)  static void acpi_ec_submit_query(struct acpi_ec *ec)  { -	if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { +	if (acpi_ec_event_enabled(ec) && +	    !test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {  		ec_dbg_evt("Command(%s) submitted/blocked",  			   acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));  		ec->nr_pending_queries++; @@ -446,6 +478,86 @@ static void acpi_ec_complete_query(struct acpi_ec *ec)  	}  } +static inline void __acpi_ec_enable_event(struct acpi_ec *ec) +{ +	if (!test_and_set_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags)) +		ec_log_drv("event unblocked"); +	if (!test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) +		advance_transaction(ec); +} + +static inline void __acpi_ec_disable_event(struct acpi_ec *ec) +{ +	if (test_and_clear_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags)) +		ec_log_drv("event blocked"); +} + +/* + * Process _Q events that might have accumulated in the EC. + * Run with locked ec mutex. + */ +static void acpi_ec_clear(struct acpi_ec *ec) +{ +	int i, status; +	u8 value = 0; + +	for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) { +		status = acpi_ec_query(ec, &value); +		if (status || !value) +			break; +	} +	if (unlikely(i == ACPI_EC_CLEAR_MAX)) +		pr_warn("Warning: Maximum of %d stale EC events cleared\n", i); +	else +		pr_info("%d stale EC events cleared\n", i); +} + +static void acpi_ec_enable_event(struct acpi_ec *ec) +{ +	unsigned long flags; + +	spin_lock_irqsave(&ec->lock, flags); +	if (acpi_ec_started(ec)) +		__acpi_ec_enable_event(ec); +	spin_unlock_irqrestore(&ec->lock, flags); + +	/* Drain additional events if hardware requires that */ +	if (EC_FLAGS_CLEAR_ON_RESUME) +		acpi_ec_clear(ec); +} + +static bool acpi_ec_query_flushed(struct acpi_ec *ec) +{ +	bool flushed; +	unsigned long flags; + +	spin_lock_irqsave(&ec->lock, flags); +	flushed = !ec->nr_pending_queries; +	spin_unlock_irqrestore(&ec->lock, flags); +	return flushed; +} + +static void __acpi_ec_flush_event(struct acpi_ec *ec) +{ +	/* +	 * When ec_freeze_events is true, we need to flush events in +	 * the proper position before entering the noirq stage. +	 */ +	wait_event(ec->wait, acpi_ec_query_flushed(ec)); +	if (ec_query_wq) +		flush_workqueue(ec_query_wq); +} + +static void acpi_ec_disable_event(struct acpi_ec *ec) +{ +	unsigned long flags; + +	spin_lock_irqsave(&ec->lock, flags); +	__acpi_ec_disable_event(ec); +	spin_unlock_irqrestore(&ec->lock, flags); +	__acpi_ec_flush_event(ec); +} +  static bool acpi_ec_guard_event(struct acpi_ec *ec)  {  	bool guarded = true; @@ -832,27 +944,6 @@ acpi_handle ec_get_handle(void)  }  EXPORT_SYMBOL(ec_get_handle); -/* - * Process _Q events that might have accumulated in the EC. - * Run with locked ec mutex. - */ -static void acpi_ec_clear(struct acpi_ec *ec) -{ -	int i, status; -	u8 value = 0; - -	for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) { -		status = acpi_ec_query(ec, &value); -		if (status || !value) -			break; -	} - -	if (unlikely(i == ACPI_EC_CLEAR_MAX)) -		pr_warn("Warning: Maximum of %d stale EC events cleared\n", i); -	else -		pr_info("%d stale EC events cleared\n", i); -} -  static void acpi_ec_start(struct acpi_ec *ec, bool resuming)  {  	unsigned long flags; @@ -896,7 +987,8 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool suspending)  		if (!suspending) {  			acpi_ec_complete_request(ec);  			ec_dbg_ref(ec, "Decrease driver"); -		} +		} else if (!ec_freeze_events) +			__acpi_ec_disable_event(ec);  		clear_bit(EC_FLAGS_STARTED, &ec->flags);  		clear_bit(EC_FLAGS_STOPPED, &ec->flags);  		ec_log_drv("EC stopped"); @@ -919,20 +1011,6 @@ void acpi_ec_block_transactions(void)  void acpi_ec_unblock_transactions(void)  { -	struct acpi_ec *ec = first_ec; - -	if (!ec) -		return; - -	/* Allow transactions to be carried out again */ -	acpi_ec_start(ec, true); - -	if (EC_FLAGS_CLEAR_ON_RESUME) -		acpi_ec_clear(ec); -} - -void acpi_ec_unblock_transactions_early(void) -{  	/*  	 * Allow transactions to happen again (this function is called from  	 * atomic context during wakeup, so we don't need to acquire the mutex). @@ -1228,13 +1306,21 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,  static acpi_status  ec_parse_io_ports(struct acpi_resource *resource, void *context); -static struct acpi_ec *make_acpi_ec(void) +static void acpi_ec_free(struct acpi_ec *ec) +{ +	if (first_ec == ec) +		first_ec = NULL; +	if (boot_ec == ec) +		boot_ec = NULL; +	kfree(ec); +} + +static struct acpi_ec *acpi_ec_alloc(void)  {  	struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);  	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); @@ -1290,7 +1376,12 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)  	return AE_CTRL_TERMINATE;  } -static int ec_install_handlers(struct acpi_ec *ec) +/* + * Note: This function returns an error code only when the address space + *       handler is not installed, which means "not able to handle + *       transactions". + */ +static int ec_install_handlers(struct acpi_ec *ec, bool handle_events)  {  	acpi_status status; @@ -1319,6 +1410,16 @@ static int ec_install_handlers(struct acpi_ec *ec)  		set_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags);  	} +	if (!handle_events) +		return 0; + +	if (!test_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags)) { +		/* Find and register all query methods */ +		acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1, +				    acpi_ec_register_query_methods, +				    NULL, ec, NULL); +		set_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags); +	}  	if (!test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags)) {  		status = acpi_install_gpe_raw_handler(NULL, ec->gpe,  					  ACPI_GPE_EDGE_TRIGGERED, @@ -1329,6 +1430,9 @@ static int ec_install_handlers(struct acpi_ec *ec)  			if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&  			    ec->reference_count >= 1)  				acpi_ec_enable_gpe(ec, true); + +			/* EC is fully operational, allow queries */ +			acpi_ec_enable_event(ec);  		}  	} @@ -1363,23 +1467,104 @@ static void ec_remove_handlers(struct acpi_ec *ec)  			pr_err("failed to remove gpe handler\n");  		clear_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags);  	} +	if (test_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags)) { +		acpi_ec_remove_query_handlers(ec, true, 0); +		clear_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags); +	}  } -static struct acpi_ec *acpi_ec_alloc(void) +static int acpi_ec_setup(struct acpi_ec *ec, bool handle_events)  { -	struct acpi_ec *ec; +	int ret; -	/* Check for boot EC */ -	if (boot_ec) { -		ec = boot_ec; -		boot_ec = NULL; -		ec_remove_handlers(ec); -		if (first_ec == ec) -			first_ec = NULL; -	} else { -		ec = make_acpi_ec(); +	ret = ec_install_handlers(ec, handle_events); +	if (ret) +		return ret; + +	/* First EC capable of handling transactions */ +	if (!first_ec) { +		first_ec = ec; +		acpi_handle_info(first_ec->handle, "Used as first EC\n");  	} -	return ec; + +	acpi_handle_info(ec->handle, +			 "GPE=0x%lx, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", +			 ec->gpe, ec->command_addr, ec->data_addr); +	return ret; +} + +static int acpi_config_boot_ec(struct acpi_ec *ec, acpi_handle handle, +			       bool handle_events, bool is_ecdt) +{ +	int ret; + +	/* +	 * Changing the ACPI handle results in a re-configuration of the +	 * boot EC. And if it happens after the namespace initialization, +	 * it causes _REG evaluations. +	 */ +	if (boot_ec && boot_ec->handle != handle) +		ec_remove_handlers(boot_ec); + +	/* Unset old boot EC */ +	if (boot_ec != ec) +		acpi_ec_free(boot_ec); + +	/* +	 * ECDT device creation is split into acpi_ec_ecdt_probe() and +	 * acpi_ec_ecdt_start(). This function takes care of completing the +	 * ECDT parsing logic as the handle update should be performed +	 * between the installation/uninstallation of the handlers. +	 */ +	if (ec->handle != handle) +		ec->handle = handle; + +	ret = acpi_ec_setup(ec, handle_events); +	if (ret) +		return ret; + +	/* Set new boot EC */ +	if (!boot_ec) { +		boot_ec = ec; +		boot_ec_is_ecdt = is_ecdt; +	} + +	acpi_handle_info(boot_ec->handle, +			 "Used as boot %s EC to handle transactions%s\n", +			 is_ecdt ? "ECDT" : "DSDT", +			 handle_events ? " and events" : ""); +	return ret; +} + +static bool acpi_ec_ecdt_get_handle(acpi_handle *phandle) +{ +	struct acpi_table_ecdt *ecdt_ptr; +	acpi_status status; +	acpi_handle handle; + +	status = acpi_get_table(ACPI_SIG_ECDT, 1, +				(struct acpi_table_header **)&ecdt_ptr); +	if (ACPI_FAILURE(status)) +		return false; + +	status = acpi_get_handle(NULL, ecdt_ptr->id, &handle); +	if (ACPI_FAILURE(status)) +		return false; + +	*phandle = handle; +	return true; +} + +static bool acpi_is_boot_ec(struct acpi_ec *ec) +{ +	if (!boot_ec) +		return false; +	if (ec->handle == boot_ec->handle && +	    ec->gpe == boot_ec->gpe && +	    ec->command_addr == boot_ec->command_addr && +	    ec->data_addr == boot_ec->data_addr) +		return true; +	return false;  }  static int acpi_ec_add(struct acpi_device *device) @@ -1395,16 +1580,21 @@ static int acpi_ec_add(struct acpi_device *device)  		return -ENOMEM;  	if (ec_parse_device(device->handle, 0, ec, NULL) !=  		AE_CTRL_TERMINATE) { -			kfree(ec); -			return -EINVAL; +			ret = -EINVAL; +			goto err_alloc;  	} -	/* Find and register all query methods */ -	acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1, -			    acpi_ec_register_query_methods, NULL, ec, NULL); +	if (acpi_is_boot_ec(ec)) { +		boot_ec_is_ecdt = false; +		acpi_handle_debug(ec->handle, "duplicated.\n"); +		acpi_ec_free(ec); +		ec = boot_ec; +		ret = acpi_config_boot_ec(ec, ec->handle, true, false); +	} else +		ret = acpi_ec_setup(ec, true); +	if (ret) +		goto err_query; -	if (!first_ec) -		first_ec = ec;  	device->driver_data = ec;  	ret = !!request_region(ec->data_addr, 1, "EC data"); @@ -1412,20 +1602,17 @@ static int acpi_ec_add(struct acpi_device *device)  	ret = !!request_region(ec->command_addr, 1, "EC cmd");  	WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr); -	pr_info("GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n", -			  ec->gpe, ec->command_addr, ec->data_addr); - -	ret = ec_install_handlers(ec); -  	/* Reprobe devices depending on the EC */  	acpi_walk_dep_device_list(ec->handle); +	acpi_handle_debug(ec->handle, "enumerated.\n"); +	return 0; -	/* EC is fully operational, allow queries */ -	clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); - -	/* Clear stale _Q events if hardware might require that */ -	if (EC_FLAGS_CLEAR_ON_RESUME) -		acpi_ec_clear(ec); +err_query: +	if (ec != boot_ec) +		acpi_ec_remove_query_handlers(ec, true, 0); +err_alloc: +	if (ec != boot_ec) +		acpi_ec_free(ec);  	return ret;  } @@ -1437,14 +1624,13 @@ static int acpi_ec_remove(struct acpi_device *device)  		return -EINVAL;  	ec = acpi_driver_data(device); -	ec_remove_handlers(ec); -	acpi_ec_remove_query_handlers(ec, true, 0);  	release_region(ec->data_addr, 1);  	release_region(ec->command_addr, 1);  	device->driver_data = NULL; -	if (ec == first_ec) -		first_ec = NULL; -	kfree(ec); +	if (ec != boot_ec) { +		ec_remove_handlers(ec); +		acpi_ec_free(ec); +	}  	return 0;  } @@ -1486,9 +1672,8 @@ int __init acpi_ec_dsdt_probe(void)  	if (!ec)  		return -ENOMEM;  	/* -	 * Finding EC from DSDT if there is no ECDT EC available. When this -	 * function is invoked, ACPI tables have been fully loaded, we can -	 * walk namespace now. +	 * At this point, the namespace is initialized, so start to find +	 * the namespace objects.  	 */  	status = acpi_get_devices(ec_device_ids[0].id,  				  ec_parse_device, ec, NULL); @@ -1496,16 +1681,47 @@ int __init acpi_ec_dsdt_probe(void)  		ret = -ENODEV;  		goto error;  	} -	ret = ec_install_handlers(ec); - +	/* +	 * When the DSDT EC is available, always re-configure boot EC to +	 * have _REG evaluated. _REG can only be evaluated after the +	 * namespace initialization. +	 * At this point, the GPE is not fully initialized, so do not to +	 * handle the events. +	 */ +	ret = acpi_config_boot_ec(ec, ec->handle, false, false);  error:  	if (ret) -		kfree(ec); -	else -		first_ec = boot_ec = ec; +		acpi_ec_free(ec);  	return ret;  } +/* + * If the DSDT EC is not functioning, we still need to prepare a fully + * functioning ECDT EC first in order to handle the events. + * https://bugzilla.kernel.org/show_bug.cgi?id=115021 + */ +int __init acpi_ec_ecdt_start(void) +{ +	acpi_handle handle; + +	if (!boot_ec) +		return -ENODEV; +	/* +	 * The DSDT EC should have already been started in +	 * acpi_ec_add(). +	 */ +	if (!boot_ec_is_ecdt) +		return -ENODEV; + +	/* +	 * At this point, the namespace and the GPE is initialized, so +	 * start to find the namespace objects and handle the events. +	 */ +	if (!acpi_ec_ecdt_get_handle(&handle)) +		return -ENODEV; +	return acpi_config_boot_ec(boot_ec, handle, true, true); +} +  #if 0  /*   * Some EC firmware variations refuses to respond QR_EC when SCI_EVT is not @@ -1600,7 +1816,6 @@ int __init acpi_ec_ecdt_probe(void)  		goto error;  	} -	pr_info("EC description table is found, configuring boot EC\n");  	if (EC_FLAGS_CORRECT_ECDT) {  		ec->command_addr = ecdt_ptr->data.address;  		ec->data_addr = ecdt_ptr->control.address; @@ -1609,16 +1824,90 @@ int __init acpi_ec_ecdt_probe(void)  		ec->data_addr = ecdt_ptr->data.address;  	}  	ec->gpe = ecdt_ptr->gpe; -	ec->handle = ACPI_ROOT_OBJECT; -	ret = ec_install_handlers(ec); + +	/* +	 * At this point, the namespace is not initialized, so do not find +	 * the namespace objects, or handle the events. +	 */ +	ret = acpi_config_boot_ec(ec, ACPI_ROOT_OBJECT, false, true);  error:  	if (ret) -		kfree(ec); -	else -		first_ec = boot_ec = ec; +		acpi_ec_free(ec);  	return ret;  } +#ifdef CONFIG_PM_SLEEP +static void acpi_ec_enter_noirq(struct acpi_ec *ec) +{ +	unsigned long flags; + +	if (ec == first_ec) { +		spin_lock_irqsave(&ec->lock, flags); +		ec->saved_busy_polling = ec_busy_polling; +		ec->saved_polling_guard = ec_polling_guard; +		ec_busy_polling = true; +		ec_polling_guard = 0; +		ec_log_drv("interrupt blocked"); +		spin_unlock_irqrestore(&ec->lock, flags); +	} +} + +static void acpi_ec_leave_noirq(struct acpi_ec *ec) +{ +	unsigned long flags; + +	if (ec == first_ec) { +		spin_lock_irqsave(&ec->lock, flags); +		ec_busy_polling = ec->saved_busy_polling; +		ec_polling_guard = ec->saved_polling_guard; +		ec_log_drv("interrupt unblocked"); +		spin_unlock_irqrestore(&ec->lock, flags); +	} +} + +static int acpi_ec_suspend_noirq(struct device *dev) +{ +	struct acpi_ec *ec = +		acpi_driver_data(to_acpi_device(dev)); + +	acpi_ec_enter_noirq(ec); +	return 0; +} + +static int acpi_ec_resume_noirq(struct device *dev) +{ +	struct acpi_ec *ec = +		acpi_driver_data(to_acpi_device(dev)); + +	acpi_ec_leave_noirq(ec); +	return 0; +} + +static int acpi_ec_suspend(struct device *dev) +{ +	struct acpi_ec *ec = +		acpi_driver_data(to_acpi_device(dev)); + +	if (ec_freeze_events) +		acpi_ec_disable_event(ec); +	return 0; +} + +static int acpi_ec_resume(struct device *dev) +{ +	struct acpi_ec *ec = +		acpi_driver_data(to_acpi_device(dev)); + +	acpi_ec_enable_event(ec); +	return 0; +} +#endif + +static const struct dev_pm_ops acpi_ec_pm = { +	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend_noirq, acpi_ec_resume_noirq) +	SET_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend, acpi_ec_resume) +}; +  static int param_set_event_clearing(const char *val, struct kernel_param *kp)  {  	int result = 0; @@ -1664,6 +1953,7 @@ static struct acpi_driver acpi_ec_driver = {  		.add = acpi_ec_add,  		.remove = acpi_ec_remove,  		}, +	.drv.pm = &acpi_ec_pm,  };  static inline int acpi_ec_query_init(void)  |