Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4c611060 authored by Alexey Starikovskiy's avatar Alexey Starikovskiy Committed by Len Brown
Browse files

ACPI: EC: Drop ECDT-based boot_ec as soon as we find DSDT-based one.



ASUS notebooks have numerous problems with EC initialization
This patch tries to work around three known issues reported
in bugzilla 8598, 8709 and 8909/8919.

Signed-off-by: default avatarAlexey Starikovskiy <astarikovskiy@suse.de>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 40ffbfad
Loading
Loading
Loading
Loading
+39 −51
Original line number Original line Diff line number Diff line
@@ -121,6 +121,7 @@ static struct acpi_ec {
	atomic_t event_count;
	atomic_t event_count;
	wait_queue_head_t wait;
	wait_queue_head_t wait;
	struct list_head list;
	struct list_head list;
	u8 handlers_installed;
} *boot_ec, *first_ec;
} *boot_ec, *first_ec;


/* --------------------------------------------------------------------------
/* --------------------------------------------------------------------------
@@ -680,32 +681,50 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
	status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
	status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
	if (ACPI_FAILURE(status))
	if (ACPI_FAILURE(status))
		return status;
		return status;

	/* Find and register all query methods */
	/* Find and register all query methods */
	acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1,
	acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1,
			    acpi_ec_register_query_methods, ec, NULL);
			    acpi_ec_register_query_methods, ec, NULL);

	/* Use the global lock for all EC transactions? */
	/* Use the global lock for all EC transactions? */
	acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
	acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);

	ec->handle = handle;
	ec->handle = handle;

	printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
			  ec->gpe, ec->command_addr, ec->data_addr);

	return AE_CTRL_TERMINATE;
	return AE_CTRL_TERMINATE;
}
}


static void ec_remove_handlers(struct acpi_ec *ec)
{
	if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
				ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
		printk(KERN_ERR PREFIX "failed to remove space handler\n");
	if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
				&acpi_ec_gpe_handler)))
		printk(KERN_ERR PREFIX "failed to remove gpe handler\n");
	ec->handlers_installed = 0;
}

static int acpi_ec_add(struct acpi_device *device)
static int acpi_ec_add(struct acpi_device *device)
{
{
	struct acpi_ec *ec = NULL;
	struct acpi_ec *ec = NULL;


	if (!device)
	if (!device)
		return -EINVAL;
		return -EINVAL;

	strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
	strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
	strcpy(acpi_device_class(device), ACPI_EC_CLASS);
	strcpy(acpi_device_class(device), ACPI_EC_CLASS);


	/* Check for boot EC */
	if (boot_ec) {
		if (boot_ec->handle == device->handle) {
			/* Pre-loaded EC from DSDT, just move pointer */
			ec = boot_ec;
			boot_ec = NULL;
			goto end;
		} else if (boot_ec->handle == ACPI_ROOT_OBJECT) {
			/* ECDT-based EC, time to shut it down */
			ec_remove_handlers(boot_ec);
			kfree(boot_ec);
			first_ec = boot_ec = NULL;
		}
	}

	ec = make_acpi_ec();
	ec = make_acpi_ec();
	if (!ec)
	if (!ec)
		return -ENOMEM;
		return -ENOMEM;
@@ -715,25 +734,14 @@ static int acpi_ec_add(struct acpi_device *device)
		kfree(ec);
		kfree(ec);
		return -EINVAL;
		return -EINVAL;
	}
	}

	/* Check if we found the boot EC */
	if (boot_ec) {
		if (boot_ec->gpe == ec->gpe) {
			/* We might have incorrect info for GL at boot time */
			mutex_lock(&boot_ec->lock);
			boot_ec->global_lock = ec->global_lock;
			/* Copy handlers from new ec into boot ec */
			list_splice(&ec->list, &boot_ec->list);
			mutex_unlock(&boot_ec->lock);
			kfree(ec);
			ec = boot_ec;
		}
	} else
		first_ec = ec;
	ec->handle = device->handle;
	ec->handle = device->handle;
      end:
	if (!first_ec)
		first_ec = ec;
	acpi_driver_data(device) = ec;
	acpi_driver_data(device) = ec;

	acpi_ec_add_fs(device);
	acpi_ec_add_fs(device);
	printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
			  ec->gpe, ec->command_addr, ec->data_addr);
	return 0;
	return 0;
}
}


@@ -756,9 +764,6 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
	acpi_driver_data(device) = NULL;
	acpi_driver_data(device) = NULL;
	if (ec == first_ec)
	if (ec == first_ec)
		first_ec = NULL;
		first_ec = NULL;

	/* Don't touch boot EC */
	if (boot_ec != ec)
	kfree(ec);
	kfree(ec);
	return 0;
	return 0;
}
}
@@ -789,6 +794,8 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context)
static int ec_install_handlers(struct acpi_ec *ec)
static int ec_install_handlers(struct acpi_ec *ec)
{
{
	acpi_status status;
	acpi_status status;
	if (ec->handlers_installed)
		return 0;
	status = acpi_install_gpe_handler(NULL, ec->gpe,
	status = acpi_install_gpe_handler(NULL, ec->gpe,
					  ACPI_GPE_EDGE_TRIGGERED,
					  ACPI_GPE_EDGE_TRIGGERED,
					  &acpi_ec_gpe_handler, ec);
					  &acpi_ec_gpe_handler, ec);
@@ -807,6 +814,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
		return -ENODEV;
		return -ENODEV;
	}
	}


	ec->handlers_installed = 1;
	return 0;
	return 0;
}
}


@@ -823,41 +831,22 @@ static int acpi_ec_start(struct acpi_device *device)
	if (!ec)
	if (!ec)
		return -EINVAL;
		return -EINVAL;


	/* Boot EC is already working */
	if (ec != boot_ec)
	ret = ec_install_handlers(ec);
	ret = ec_install_handlers(ec);


	/* EC is fully operational, allow queries */
	/* EC is fully operational, allow queries */
	atomic_set(&ec->query_pending, 0);
	atomic_set(&ec->query_pending, 0);

	return ret;
	return ret;
}
}


static int acpi_ec_stop(struct acpi_device *device, int type)
static int acpi_ec_stop(struct acpi_device *device, int type)
{
{
	acpi_status status;
	struct acpi_ec *ec;
	struct acpi_ec *ec;

	if (!device)
	if (!device)
		return -EINVAL;
		return -EINVAL;

	ec = acpi_driver_data(device);
	ec = acpi_driver_data(device);
	if (!ec)
	if (!ec)
		return -EINVAL;
		return -EINVAL;

	ec_remove_handlers(ec);
	/* Don't touch boot EC */
	if (ec == boot_ec)
		return 0;

	status = acpi_remove_address_space_handler(ec->handle,
						   ACPI_ADR_SPACE_EC,
						   &acpi_ec_space_handler);
	if (ACPI_FAILURE(status))
		return -ENODEV;

	status = acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
	if (ACPI_FAILURE(status))
		return -ENODEV;


	return 0;
	return 0;
}
}
@@ -877,7 +866,7 @@ int __init acpi_ec_ecdt_probe(void)
	status = acpi_get_table(ACPI_SIG_ECDT, 1,
	status = acpi_get_table(ACPI_SIG_ECDT, 1,
				(struct acpi_table_header **)&ecdt_ptr);
				(struct acpi_table_header **)&ecdt_ptr);
	if (ACPI_SUCCESS(status)) {
	if (ACPI_SUCCESS(status)) {
		printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n\n");
		printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n");
		boot_ec->command_addr = ecdt_ptr->control.address;
		boot_ec->command_addr = ecdt_ptr->control.address;
		boot_ec->data_addr = ecdt_ptr->data.address;
		boot_ec->data_addr = ecdt_ptr->data.address;
		boot_ec->gpe = ecdt_ptr->gpe;
		boot_ec->gpe = ecdt_ptr->gpe;
@@ -899,7 +888,6 @@ int __init acpi_ec_ecdt_probe(void)
      error:
      error:
	kfree(boot_ec);
	kfree(boot_ec);
	boot_ec = NULL;
	boot_ec = NULL;

	return -ENODEV;
	return -ENODEV;
}
}