Commit 05a3c420 authored by Gwendal Grignou's avatar Gwendal Grignou Committed by Enric Balletbo i Serra

platform/chrome: cros-ec: Record event timestamp in the hard irq

To improve sensor timestamp precision, given EC and AP are in different
time domains, the AP needs to try to record the exact moment an event
was signalled to the AP by the EC as soon as possible after it happens.

First thing in the hard irq is the best place for this.
Signed-off-by: default avatarGwendal Grignou <gwendal@chromium.org>
Acked-by: default avatarJonathan Cameron <Jonathan.Cameron@kernel.org>
Acked-by: default avatarLee Jones <lee.jones@linaro.org>
Signed-off-by: default avatarEnric Balletbo i Serra <enric.balletbo@collabora.com>
parent d60ac88a
......@@ -31,6 +31,15 @@ static struct cros_ec_platform pd_p = {
.cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX),
};
static irqreturn_t ec_irq_handler(int irq, void *data)
{
struct cros_ec_device *ec_dev = data;
ec_dev->last_event_time = cros_ec_get_time_ns();
return IRQ_WAKE_THREAD;
}
static irqreturn_t ec_irq_thread(int irq, void *data)
{
struct cros_ec_device *ec_dev = data;
......@@ -141,9 +150,11 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
}
if (ec_dev->irq) {
err = devm_request_threaded_irq(dev, ec_dev->irq, NULL,
ec_irq_thread, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"chromeos-ec", ec_dev);
err = devm_request_threaded_irq(dev, ec_dev->irq,
ec_irq_handler,
ec_irq_thread,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"chromeos-ec", ec_dev);
if (err) {
dev_err(dev, "Failed to request IRQ %d: %d",
ec_dev->irq, err);
......
......@@ -200,13 +200,14 @@ static int ish_send(struct ishtp_cl_data *client_data,
* process_recv() - Received and parse incoming packet
* @cros_ish_cl: Client instance to get stats
* @rb_in_proc: Host interface message buffer
* @timestamp: Timestamp of when parent callback started
*
* Parse the incoming packet. If it is a response packet then it will
* update per instance flags and wake up the caller waiting to for the
* response. If it is an event packet then it will schedule event work.
*/
static void process_recv(struct ishtp_cl *cros_ish_cl,
struct ishtp_cl_rb *rb_in_proc)
struct ishtp_cl_rb *rb_in_proc, ktime_t timestamp)
{
size_t data_len = rb_in_proc->buf_idx;
struct ishtp_cl_data *client_data =
......@@ -295,6 +296,11 @@ static void process_recv(struct ishtp_cl *cros_ish_cl,
break;
case CROS_MKBP_EVENT:
/*
* Set timestamp from beginning of function since we actually
* got an incoming MKBP event
*/
client_data->ec_dev->last_event_time = timestamp;
/* The event system doesn't send any data in buffer */
schedule_work(&client_data->work_ec_evt);
......@@ -322,10 +328,17 @@ static void ish_event_cb(struct ishtp_cl_device *cl_device)
{
struct ishtp_cl_rb *rb_in_proc;
struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
ktime_t timestamp;
/*
* Take timestamp as close to hardware interrupt as possible for sensor
* timestamps.
*/
timestamp = cros_ec_get_time_ns();
while ((rb_in_proc = ishtp_cl_rx_get_rb(cros_ish_cl)) != NULL) {
/* Decide what to do with received data */
process_recv(cros_ish_cl, rb_in_proc);
process_recv(cros_ish_cl, rb_in_proc, timestamp);
}
}
......
......@@ -313,6 +313,8 @@ static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data)
{
struct cros_ec_device *ec_dev = data;
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,
......
......@@ -122,6 +122,8 @@ struct cros_ec_command {
* @event_data: Raw payload transferred with the MKBP event.
* @event_size: Size in bytes of the event data.
* @host_event_wake_mask: Mask of host events that cause wake from suspend.
* @last_event_time: exact time from the hard irq when we got notified of
* a new event.
* @ec: The platform_device used by the mfd driver to interface with the
* main EC.
* @pd: The platform_device used by the mfd driver to interface with the
......@@ -162,6 +164,7 @@ struct cros_ec_device {
int event_size;
u32 host_event_wake_mask;
u32 last_resume_result;
ktime_t last_event_time;
/* The platform devices used by the mfd driver */
struct platform_device *ec;
......@@ -210,4 +213,17 @@ int cros_ec_check_features(struct cros_ec_dev *ec, int feature);
int cros_ec_get_sensor_count(struct cros_ec_dev *ec);
/**
* cros_ec_get_time_ns() - Return time in ns.
*
* This is the function used to record the time for last_event_time in struct
* cros_ec_device during the hard irq.
*
* Return: ktime_t format since boot.
*/
static inline ktime_t cros_ec_get_time_ns(void)
{
return ktime_get_boottime_ns();
}
#endif /* __LINUX_CROS_EC_PROTO_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment