On Tue, 14 Feb 2017, Thierry Escande wrote: > From: Shawn Nematbakhsh <sha...@chromium.org> > > 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: Shawn Nematbakhsh <sha...@chromium.org> > Signed-off-by: Thierry Escande <thierry.esca...@collabora.com> > --- > drivers/mfd/cros_ec.c | 13 ++++-- > drivers/platform/chrome/cros_ec_proto.c | 76 > ++++++++++++++++++++++++++++++--- > include/linux/mfd/cros_ec.h | 5 ++- > 3 files changed, 85 insertions(+), 9 deletions(-)
Looks okay from an MFD perspective: For my own reference: Acked-for-MFD-by: Lee Jones <lee.jo...@linaro.org> > diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c > index 9b66a98..1bcb502 100644 > --- a/drivers/mfd/cros_ec.c > +++ b/drivers/mfd/cros_ec.c > @@ -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); > @@ -212,7 +219,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); > } > diff --git a/drivers/platform/chrome/cros_ec_proto.c > b/drivers/platform/chrome/cros_ec_proto.c > index d6942a6..8dfa7fc 100644 > --- a/drivers/platform/chrome/cros_ec_proto.c > +++ b/drivers/platform/chrome/cros_ec_proto.c > @@ -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); > > diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h > index 2ceb245..bb85325 100644 > --- a/include/linux/mfd/cros_ec.h > +++ b/include/linux/mfd/cros_ec.h > @@ -148,6 +148,7 @@ struct cros_ec_device { > > struct ec_response_get_next_event event_data; > int event_size; > + u32 host_event_wake_mask; > }; > > /** > @@ -294,10 +295,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. -- Lee Jones Linaro STMicroelectronics Landing Team Lead Linaro.org │ Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog