platform/chrome: cros_ec_rpmsg: Fix race with host event
authorPi-Hsun Shih <pihsun@chromium.org>
Fri, 14 Feb 2020 08:26:38 +0000 (16:26 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 21 Apr 2020 07:04:51 +0000 (09:04 +0200)
commit f775ac78fcfc6bdc96bdda07029d11f2a5e84869 upstream.

Host event can be sent by remoteproc by any time, and
cros_ec_rpmsg_callback would be called after cros_ec_rpmsg_create_ept.
But the cros_ec_device is initialized after that, which cause host event
handler to use cros_ec_device that are not initialized properly yet.

Fix this by don't schedule host event handler before cros_ec_register
returns. Instead, remember that we have a pending host event, and
schedule host event handler after cros_ec_register.

Fixes: 71cddb7097e2 ("platform/chrome: cros_ec_rpmsg: Fix race with host command when probe failed.")
Signed-off-by: Pi-Hsun Shih <pihsun@chromium.org>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/platform/chrome/cros_ec_rpmsg.c

index 0c3738c..aa2059b 100644 (file)
@@ -42,6 +42,8 @@ struct cros_ec_rpmsg {
        struct completion xfer_ack;
        struct work_struct host_event_work;
        struct rpmsg_endpoint *ept;
+       bool has_pending_host_event;
+       bool probe_done;
 };
 
 /**
@@ -186,7 +188,14 @@ static int cros_ec_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
                memcpy(ec_dev->din, resp->data, len);
                complete(&ec_rpmsg->xfer_ack);
        } else if (resp->type == HOST_EVENT_MARK) {
-               schedule_work(&ec_rpmsg->host_event_work);
+               /*
+                * If the host event is sent before cros_ec_register is
+                * finished, queue the host event.
+                */
+               if (ec_rpmsg->probe_done)
+                       schedule_work(&ec_rpmsg->host_event_work);
+               else
+                       ec_rpmsg->has_pending_host_event = true;
        } else {
                dev_warn(ec_dev->dev, "rpmsg received invalid type = %d",
                         resp->type);
@@ -249,6 +258,11 @@ static int cros_ec_rpmsg_probe(struct rpmsg_device *rpdev)
                return ret;
        }
 
+       ec_rpmsg->probe_done = true;
+
+       if (ec_rpmsg->has_pending_host_event)
+               schedule_work(&ec_rpmsg->host_event_work);
+
        return 0;
 }