lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 11 Nov 2019 10:30:58 +0100
From:   Enric Balletbo i Serra <enric.balletbo@...labora.com>
To:     Jonathan Cameron <jic23@...nel.org>,
        Gwendal Grignou <gwendal@...omium.org>
Cc:     briannorris@...omium.org, knaack.h@....de, lars@...afoo.de,
        pmeerw@...erw.net, lee.jones@...aro.org, bleung@...omium.org,
        dianders@...omium.org, groeck@...omium.org,
        fabien.lahoudere@...labora.com, linux-kernel@...r.kernel.org,
        linux-iio@...r.kernel.org, Enrico Granata <egranata@...omium.org>
Subject: Re: [PATCH v4 06/17] platform: chrome: cros_ec: handle MKBP more
 events flag



On 10/11/19 13:28, Jonathan Cameron wrote:
> On Tue,  5 Nov 2019 14:26:41 -0800
> Gwendal Grignou <gwendal@...omium.org> wrote:
> 
>> From: Enrico Granata <egranata@...omium.org>
>>
>> The ChromeOS EC has support for signaling to the host that
>> a single IRQ can serve multiple MKBP (Matrix KeyBoard Protocol)
>> events.
>>
>> Doing this serves an optimization purpose, as it minimizes the
>> number of round-trips into the interrupt handling machinery, and
>> it proves beneficial to sensor timestamping as it keeps the desired
>> synchronization of event times between the two processors.
>>
>> This patch adds kernel support for this EC feature, allowing the
>> ec_irq to loop until all events have been served.
>>
>> Signed-off-by: Enrico Granata <egranata@...omium.org>
>> Signed-off-by: Gwendal Grignou <gwendal@...omium.org>
> A couple of trivial things inline.  
> I just checked with the script and it doesn't seem to warn on the ()
> but the documentation for kernel-doc suggests it should be there...
> 
> I guess things are more relaxed than I though.. Fix them if you are
> doing another spin perhaps but don't bother otherwise.
> 
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@...wei.com>
> 

Looks good to me, please fix the above comments and:

Acked-by: Enric Balletbo i Serra <enric.balletbo@...labora.com>

Thanks,
 Enric


>> ---
>> Changes in v4:
>> - Check patch with --strict option
>>     Alignement
>> Changes in v3:
>>   Fix indentation.
>> Changes in v2:
>>   Process flag inside cros_ec_get_next_event, clean flag from event.
>>   Introduce public function cros_ec_handle_event(), use it in rpmsg and
>>     ishtp transport layer.
>>   Remplace dev_info with dev_dbg, call only once.
>>
>>  drivers/platform/chrome/cros_ec.c           | 34 +++++++--
>>  drivers/platform/chrome/cros_ec_ishtp.c     |  8 +-
>>  drivers/platform/chrome/cros_ec_lpc.c       | 15 +++-
>>  drivers/platform/chrome/cros_ec_proto.c     | 81 +++++++++++++--------
>>  drivers/platform/chrome/cros_ec_rpmsg.c     | 19 +----
>>  include/linux/platform_data/cros_ec_proto.h | 12 ++-
>>  6 files changed, 107 insertions(+), 62 deletions(-)
>>
>> diff --git a/drivers/platform/chrome/cros_ec.c b/drivers/platform/chrome/cros_ec.c
>> index d3dfa27171e6..c9f0b9ebcbc1 100644
>> --- a/drivers/platform/chrome/cros_ec.c
>> +++ b/drivers/platform/chrome/cros_ec.c
>> @@ -40,13 +40,23 @@ static irqreturn_t ec_irq_handler(int irq, void *data)
>>  	return IRQ_WAKE_THREAD;
>>  }
>>  
>> -static irqreturn_t ec_irq_thread(int irq, void *data)
>> +/**
>> + * cros_ec_handle_event - process and forward pending events on EC
> 
> cros_ec_handle_event() - 
> 
>> + * @ec_dev: Device with events to process.
>> + *
>> + * Call this function in a loop when the kernel is notified that the EC has
>> + * pending events.
>> + *
>> + * Return: true if more events are still pending and this function should be
>> + * called again.
>> + */
>> +bool cros_ec_handle_event(struct cros_ec_device *ec_dev)
>>  {
>> -	struct cros_ec_device *ec_dev = data;
>> -	bool wake_event = true;
>> +	bool wake_event;
>> +	bool ec_has_more_events;
>>  	int ret;
>>  
>> -	ret = cros_ec_get_next_event(ec_dev, &wake_event);
>> +	ret = cros_ec_get_next_event(ec_dev, &wake_event, &ec_has_more_events);
>>  
>>  	/*
>>  	 * Signal only if wake host events or any interrupt if
>> @@ -59,6 +69,20 @@ static irqreturn_t ec_irq_thread(int irq, void *data)
>>  	if (ret > 0)
>>  		blocking_notifier_call_chain(&ec_dev->event_notifier,
>>  					     0, ec_dev);
>> +
>> +	return ec_has_more_events;
>> +}
>> +EXPORT_SYMBOL(cros_ec_handle_event);
>> +
>> +static irqreturn_t ec_irq_thread(int irq, void *data)
>> +{
>> +	struct cros_ec_device *ec_dev = data;
>> +	bool ec_has_more_events;
>> +
>> +	do {
>> +		ec_has_more_events = cros_ec_handle_event(ec_dev);
>> +	} while (ec_has_more_events);
>> +
>>  	return IRQ_HANDLED;
>>  }
>>  
>> @@ -274,7 +298,7 @@ EXPORT_SYMBOL(cros_ec_suspend);
>>  static void cros_ec_report_events_during_suspend(struct cros_ec_device *ec_dev)
>>  {
>>  	while (ec_dev->mkbp_event_supported &&
>> -	       cros_ec_get_next_event(ec_dev, NULL) > 0)
>> +	       cros_ec_get_next_event(ec_dev, NULL, NULL) > 0)
>>  		blocking_notifier_call_chain(&ec_dev->event_notifier,
>>  					     1, ec_dev);
>>  }
>> diff --git a/drivers/platform/chrome/cros_ec_ishtp.c b/drivers/platform/chrome/cros_ec_ishtp.c
>> index 5c848f22b44b..e5996821d08b 100644
>> --- a/drivers/platform/chrome/cros_ec_ishtp.c
>> +++ b/drivers/platform/chrome/cros_ec_ishtp.c
>> @@ -136,11 +136,11 @@ static void ish_evt_handler(struct work_struct *work)
>>  	struct ishtp_cl_data *client_data =
>>  		container_of(work, struct ishtp_cl_data, work_ec_evt);
>>  	struct cros_ec_device *ec_dev = client_data->ec_dev;
>> +	bool ec_has_more_events;
>>  
>> -	if (cros_ec_get_next_event(ec_dev, NULL) > 0) {
>> -		blocking_notifier_call_chain(&ec_dev->event_notifier,
>> -					     0, ec_dev);
>> -	}
>> +	do {
>> +		ec_has_more_events = cros_ec_handle_event(ec_dev);
>> +	} while (ec_has_more_events);
>>  }
>>  
>>  /**
>> diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c
>> index 3c77496e164d..dccf479c6625 100644
>> --- a/drivers/platform/chrome/cros_ec_lpc.c
>> +++ b/drivers/platform/chrome/cros_ec_lpc.c
>> @@ -312,13 +312,20 @@ static int cros_ec_lpc_readmem(struct cros_ec_device *ec, unsigned int offset,
>>  static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data)
>>  {
>>  	struct cros_ec_device *ec_dev = data;
>> +	bool ec_has_more_events;
>> +	int ret;
>>  
>>  	ec_dev->last_event_time = cros_ec_get_time_ns();
>>  
>> -	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);
>> +	if (ec_dev->mkbp_event_supported)
>> +		do {
>> +			ret = cros_ec_get_next_event(ec_dev, NULL,
>> +						     &ec_has_more_events);
>> +			if (ret > 0)
>> +				blocking_notifier_call_chain(
>> +						&ec_dev->event_notifier, 0,
>> +						ec_dev);
>> +		} while (ec_has_more_events);
>>  
>>  	if (value == ACPI_NOTIFY_DEVICE_WAKE)
>>  		pm_system_wakeup();
>> diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c
>> index b502933e911b..03173ca66b1b 100644
>> --- a/drivers/platform/chrome/cros_ec_proto.c
>> +++ b/drivers/platform/chrome/cros_ec_proto.c
>> @@ -456,7 +456,10 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev)
>>  	if (ret < 0 || ver_mask == 0)
>>  		ec_dev->mkbp_event_supported = 0;
>>  	else
>> -		ec_dev->mkbp_event_supported = 1;
>> +		ec_dev->mkbp_event_supported = fls(ver_mask);
>> +
>> +	dev_dbg(ec_dev->dev, "MKBP support version %u\n",
>> +		ec_dev->mkbp_event_supported - 1);
>>  
>>  	/* Probe if host sleep v1 is supported for S0ix failure detection. */
>>  	ret = cros_ec_get_host_command_version_mask(ec_dev,
>> @@ -569,6 +572,7 @@ EXPORT_SYMBOL(cros_ec_cmd_xfer_status);
>>  
>>  static int get_next_event_xfer(struct cros_ec_device *ec_dev,
>>  			       struct cros_ec_command *msg,
>> +			       struct ec_response_get_next_event_v1 *event,
>>  			       int version, uint32_t size)
>>  {
>>  	int ret;
>> @@ -581,7 +585,7 @@ static int get_next_event_xfer(struct cros_ec_device *ec_dev,
>>  	ret = cros_ec_cmd_xfer(ec_dev, msg);
>>  	if (ret > 0) {
>>  		ec_dev->event_size = ret - 1;
>> -		memcpy(&ec_dev->event_data, msg->data, ret);
>> +		ec_dev->event_data = *event;
>>  	}
>>  
>>  	return ret;
>> @@ -589,30 +593,26 @@ static int get_next_event_xfer(struct cros_ec_device *ec_dev,
>>  
>>  static int get_next_event(struct cros_ec_device *ec_dev)
>>  {
>> -	u8 buffer[sizeof(struct cros_ec_command) + sizeof(ec_dev->event_data)];
>> -	struct cros_ec_command *msg = (struct cros_ec_command *)&buffer;
>> -	static int cmd_version = 1;
>> -	int ret;
>> +	struct {
>> +		struct cros_ec_command msg;
>> +		struct ec_response_get_next_event_v1 event;
>> +	} __packed buf;
>> +	struct cros_ec_command *msg = &buf.msg;
>> +	struct ec_response_get_next_event_v1 *event = &buf.event;
>> +	const int cmd_version = ec_dev->mkbp_event_supported - 1;
>>  
>> +	memset(msg, 0, sizeof(*msg));
>>  	if (ec_dev->suspended) {
>>  		dev_dbg(ec_dev->dev, "Device suspended.\n");
>>  		return -EHOSTDOWN;
>>  	}
>>  
>> -	if (cmd_version == 1) {
>> -		ret = get_next_event_xfer(ec_dev, msg, cmd_version,
>> -				sizeof(struct ec_response_get_next_event_v1));
>> -		if (ret < 0 || msg->result != EC_RES_INVALID_VERSION)
>> -			return ret;
>> -
>> -		/* Fallback to version 0 for future send attempts */
>> -		cmd_version = 0;
>> -	}
>> -
>> -	ret = get_next_event_xfer(ec_dev, msg, cmd_version,
>> +	if (cmd_version == 0)
>> +		return get_next_event_xfer(ec_dev, msg, event, 0,
>>  				  sizeof(struct ec_response_get_next_event));
>>  
>> -	return ret;
>> +	return get_next_event_xfer(ec_dev, msg, event, cmd_version,
>> +				sizeof(struct ec_response_get_next_event_v1));
>>  }
>>  
>>  static int get_keyboard_state_event(struct cros_ec_device *ec_dev)
>> @@ -639,32 +639,55 @@ static int get_keyboard_state_event(struct cros_ec_device *ec_dev)
>>   * @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.
>> + * @has_more_events: Pointer to bool set to true if more than one event is
>> + *              pending.
>> + *              Some EC will set this flag to indicate cros_ec_get_next_event()
>> + *              can be called multiple times in a row.
>> + *              It is an optimization to prevent issuing a EC command for
>> + *              nothing or wait for another interrupt from the EC to process
>> + *              the next message.
>> + *              Ignored if null.
>>   *
>>   * Return: negative error code on errors; 0 for no data; or else number of
>>   * bytes received (i.e., an event was retrieved successfully). Event types are
>>   * written out to @ec_dev->event_data.event_type on success.
>>   */
>> -int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event)
>> +int cros_ec_get_next_event(struct cros_ec_device *ec_dev,
>> +			   bool *wake_event,
>> +			   bool *has_more_events)
>>  {
>>  	u8 event_type;
>>  	u32 host_event;
>>  	int ret;
>>  
>> -	if (!ec_dev->mkbp_event_supported) {
>> -		ret = get_keyboard_state_event(ec_dev);
>> -		if (ret <= 0)
>> -			return ret;
>> +	/*
>> +	 * Default value for wake_event.
>> +	 * Wake up on keyboard event, wake up for spurious interrupt or link
>> +	 * error to the EC.
>> +	 */
>> +	if (wake_event)
>> +		*wake_event = true;
>>  
>> -		if (wake_event)
>> -			*wake_event = true;
>> +	/*
>> +	 * Default value for has_more_events.
>> +	 * EC will raise another interrupt if AP does not process all events
>> +	 * anyway.
>> +	 */
>> +	if (has_more_events)
>> +		*has_more_events = false;
>>  
>> -		return ret;
>> -	}
>> +	if (!ec_dev->mkbp_event_supported)
>> +		return get_keyboard_state_event(ec_dev);
>>  
>>  	ret = get_next_event(ec_dev);
>>  	if (ret <= 0)
>>  		return ret;
>>  
>> +	if (has_more_events)
>> +		*has_more_events = ec_dev->event_data.event_type &
>> +			EC_MKBP_HAS_MORE_EVENTS;
>> +	ec_dev->event_data.event_type &= EC_MKBP_EVENT_TYPE_MASK;
>> +
>>  	if (wake_event) {
>>  		event_type = ec_dev->event_data.event_type;
>>  		host_event = cros_ec_get_host_event(ec_dev);
>> @@ -679,11 +702,7 @@ int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event)
>>  		else if (host_event &&
>>  			 !(host_event & ec_dev->host_event_wake_mask))
>>  			*wake_event = false;
>> -		/* Consider all other events as wake events. */
>> -		else
>> -			*wake_event = true;
>>  	}
>> -
> 
> Nitpick. Unrelated whitespace change ;)
> 
>>  	return ret;
>>  }
>>  EXPORT_SYMBOL(cros_ec_get_next_event);
>> diff --git a/drivers/platform/chrome/cros_ec_rpmsg.c b/drivers/platform/chrome/cros_ec_rpmsg.c
>> index 0c3738c3244d..bd068afe43b5 100644
>> --- a/drivers/platform/chrome/cros_ec_rpmsg.c
>> +++ b/drivers/platform/chrome/cros_ec_rpmsg.c
>> @@ -143,22 +143,11 @@ cros_ec_rpmsg_host_event_function(struct work_struct *host_event_work)
>>  						      struct cros_ec_rpmsg,
>>  						      host_event_work);
>>  	struct cros_ec_device *ec_dev = dev_get_drvdata(&ec_rpmsg->rpdev->dev);
>> -	bool wake_event = true;
>> -	int ret;
>> -
>> -	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);
>> +	bool ec_has_more_events;
>>  
>> -	if (ret > 0)
>> -		blocking_notifier_call_chain(&ec_dev->event_notifier,
>> -					     0, ec_dev);
>> +	do {
>> +		ec_has_more_events = cros_ec_handle_event(ec_dev);
>> +	} while (ec_has_more_events);
>>  }
>>  
>>  static int cros_ec_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
>> diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h
>> index b183024fef1f..e238930ae967 100644
>> --- a/include/linux/platform_data/cros_ec_proto.h
>> +++ b/include/linux/platform_data/cros_ec_proto.h
>> @@ -116,7 +116,9 @@ struct cros_ec_command {
>>   *            code.
>>   * @pkt_xfer: Send packet to EC and get response.
>>   * @lock: One transaction at a time.
>> - * @mkbp_event_supported: True if this EC supports the MKBP event protocol.
>> + * @mkbp_event_supported: 0 if MKBP not supported. Otherwise its value is
>> + *                        the maximum supported version of the MKBP host event
>> + *                        command + 1.
>>   * @host_sleep_v1: True if this EC supports the sleep v1 command.
>>   * @event_notifier: Interrupt event notifier for transport devices.
>>   * @event_data: Raw payload transferred with the MKBP event.
>> @@ -156,7 +158,7 @@ struct cros_ec_device {
>>  	int (*pkt_xfer)(struct cros_ec_device *ec,
>>  			struct cros_ec_command *msg);
>>  	struct mutex lock;
>> -	bool mkbp_event_supported;
>> +	u8 mkbp_event_supported;
>>  	bool host_sleep_v1;
>>  	struct blocking_notifier_head event_notifier;
>>  
>> @@ -205,7 +207,9 @@ int cros_ec_unregister(struct cros_ec_device *ec_dev);
>>  
>>  int cros_ec_query_all(struct cros_ec_device *ec_dev);
>>  
>> -int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event);
>> +int cros_ec_get_next_event(struct cros_ec_device *ec_dev,
>> +			   bool *wake_event,
>> +			   bool *has_more_events);
>>  
>>  u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev);
>>  
>> @@ -213,6 +217,8 @@ int cros_ec_check_features(struct cros_ec_dev *ec, int feature);
>>  
>>  int cros_ec_get_sensor_count(struct cros_ec_dev *ec);
>>  
>> +bool cros_ec_handle_event(struct cros_ec_device *ec_dev);
>> +
>>  /**
>>   * cros_ec_get_time_ns - Return time in ns.
>>   *
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ