From: Pi-Hsun Shih pihsun@chromium.org
[ Upstream commit f775ac78fcfc6bdc96bdda07029d11f2a5e84869 ]
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: Sasha Levin sashal@kernel.org --- drivers/platform/chrome/cros_ec_rpmsg.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/drivers/platform/chrome/cros_ec_rpmsg.c b/drivers/platform/chrome/cros_ec_rpmsg.c index dbc3f5523b839..7e8629e3db746 100644 --- a/drivers/platform/chrome/cros_ec_rpmsg.c +++ b/drivers/platform/chrome/cros_ec_rpmsg.c @@ -44,6 +44,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; };
/** @@ -177,7 +179,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); @@ -240,6 +249,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; }