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

Commit 29d99b96 authored by Shawn Nematbakhsh's avatar Shawn Nematbakhsh Committed by Benson Leung
Browse files

cros_ec: Don't signal wake event for non-wake host events



The subset of wake-enabled host events is defined by the EC, but the EC
may still send non-wake host events if we're in the process of
suspending. Get the mask of wake-enabled host events from the EC and
filter out non-wake events to prevent spurious aborted suspend
attempts.

Signed-off-by: default avatarShawn Nematbakhsh <shawnn@chromium.org>
Signed-off-by: default avatarThierry Escande <thierry.escande@collabora.com>
Acked-for-MFD-by: default avatarLee Jones <lee.jones@linaro.org>
Signed-off-by: default avatarBenson Leung <bleung@chromium.org>
parent d4da97e5
Loading
Loading
Loading
Loading
+10 −3
Original line number Diff line number Diff line
@@ -54,12 +54,19 @@ static const struct mfd_cell ec_pd_cell = {
static irqreturn_t ec_irq_thread(int irq, void *data)
{
	struct cros_ec_device *ec_dev = data;
	bool wake_event = true;
	int ret;

	if (device_may_wakeup(ec_dev->dev))
	ret = cros_ec_get_next_event(ec_dev, &wake_event);

	/*
	 * Signal only if wake host events or any interrupt if
	 * cros_ec_get_next_event() returned an error (default value for
	 * wake_event is true)
	 */
	if (wake_event && device_may_wakeup(ec_dev->dev))
		pm_wakeup_event(ec_dev->dev, 0);

	ret = cros_ec_get_next_event(ec_dev);
	if (ret > 0)
		blocking_notifier_call_chain(&ec_dev->event_notifier,
					     0, ec_dev);
@@ -221,7 +228,7 @@ EXPORT_SYMBOL(cros_ec_suspend);

static void cros_ec_drain_events(struct cros_ec_device *ec_dev)
{
	while (cros_ec_get_next_event(ec_dev) > 0)
	while (cros_ec_get_next_event(ec_dev, NULL) > 0)
		blocking_notifier_call_chain(&ec_dev->event_notifier,
					     1, ec_dev);
}
+2 −1
Original line number Diff line number Diff line
@@ -231,7 +231,8 @@ static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data)
{
	struct cros_ec_device *ec_dev = data;

	if (ec_dev->mkbp_event_supported && cros_ec_get_next_event(ec_dev) > 0)
	if (ec_dev->mkbp_event_supported &&
	    cros_ec_get_next_event(ec_dev, NULL) > 0)
		blocking_notifier_call_chain(&ec_dev->event_notifier, 0,
					     ec_dev);
}
+71 −5
Original line number Diff line number Diff line
@@ -150,6 +150,40 @@ int cros_ec_check_result(struct cros_ec_device *ec_dev,
}
EXPORT_SYMBOL(cros_ec_check_result);

/*
 * cros_ec_get_host_event_wake_mask
 *
 * Get the mask of host events that cause wake from suspend.
 *
 * @ec_dev: EC device to call
 * @msg: message structure to use
 * @mask: result when function returns >=0.
 *
 * LOCKING:
 * the caller has ec_dev->lock mutex, or the caller knows there is
 * no other command in progress.
 */
static int cros_ec_get_host_event_wake_mask(struct cros_ec_device *ec_dev,
					    struct cros_ec_command *msg,
					    uint32_t *mask)
{
	struct ec_response_host_event_mask *r;
	int ret;

	msg->command = EC_CMD_HOST_EVENT_GET_WAKE_MASK;
	msg->version = 0;
	msg->outsize = 0;
	msg->insize = sizeof(*r);

	ret = send_command(ec_dev, msg);
	if (ret > 0) {
		r = (struct ec_response_host_event_mask *)msg->data;
		*mask = r->mask;
	}

	return ret;
}

static int cros_ec_host_command_proto_query(struct cros_ec_device *ec_dev,
					    int devidx,
					    struct cros_ec_command *msg)
@@ -387,6 +421,15 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev)
	else
		ec_dev->mkbp_event_supported = 1;

	/*
	 * Get host event wake mask, assume all events are wake events
	 * if unavailable.
	 */
	ret = cros_ec_get_host_event_wake_mask(ec_dev, proto_msg,
					       &ec_dev->host_event_wake_mask);
	if (ret < 0)
		ec_dev->host_event_wake_mask = U32_MAX;

	ret = 0;

exit:
@@ -504,12 +547,35 @@ static int get_keyboard_state_event(struct cros_ec_device *ec_dev)
	return ec_dev->event_size;
}

int cros_ec_get_next_event(struct cros_ec_device *ec_dev)
int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event)
{
	if (ec_dev->mkbp_event_supported)
		return get_next_event(ec_dev);
	else
		return get_keyboard_state_event(ec_dev);
	u32 host_event;
	int ret;

	if (!ec_dev->mkbp_event_supported) {
		ret = get_keyboard_state_event(ec_dev);
		if (ret < 0)
			return ret;

		if (wake_event)
			*wake_event = true;

		return ret;
	}

	ret = get_next_event(ec_dev);
	if (ret < 0)
		return ret;

	if (wake_event) {
		host_event = cros_ec_get_host_event(ec_dev);

		/* Consider non-host_event as wake event */
		*wake_event = !host_event ||
			      !!(host_event & ec_dev->host_event_wake_mask);
	}

	return ret;
}
EXPORT_SYMBOL(cros_ec_get_next_event);

+4 −1
Original line number Diff line number Diff line
@@ -149,6 +149,7 @@ struct cros_ec_device {

	struct ec_response_get_next_event event_data;
	int event_size;
	u32 host_event_wake_mask;
};

/**
@@ -299,10 +300,12 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev);
 * cros_ec_get_next_event -  Fetch next event from the ChromeOS EC
 *
 * @ec_dev: Device to fetch event from
 * @wake_event: Pointer to a bool set to true upon return if the event might be
 *              treated as a wake event. Ignored if null.
 *
 * Returns: 0 on success, Linux error number on failure
 */
int cros_ec_get_next_event(struct cros_ec_device *ec_dev);
int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event);

/**
 * cros_ec_get_host_event - Return a mask of event set by the EC.