Skip to content

Commit 71cddb7

Browse files
peter50216Enric Balletbo i Serra
authored andcommitted
platform/chrome: cros_ec_rpmsg: Fix race with host command when probe failed
Since the rpmsg_endpoint is created before probe is called, it's possible that a host event is received during cros_ec_register, and there would be some pending work in the host_event_work workqueue while cros_ec_register is called. If cros_ec_register fails, when the leftover work in host_event_work run, the ec_dev from the drvdata of the rpdev could be already set to NULL, causing kernel crash when trying to run cros_ec_get_next_event. Fix this by creating the rpmsg_endpoint by ourself, and when cros_ec_register fails (or on remove), destroy the endpoint first (to make sure there's no more new calls to cros_ec_rpmsg_callback), and then cancel all works in the host_event_work workqueue. Cc: [email protected] Fixes: 2de89fd ("platform/chrome: cros_ec: Add EC host command support using rpmsg") Signed-off-by: Pi-Hsun Shih <[email protected]> Signed-off-by: Enric Balletbo i Serra <[email protected]>
1 parent 0144c00 commit 71cddb7

File tree

1 file changed

+28
-5
lines changed

1 file changed

+28
-5
lines changed

drivers/platform/chrome/cros_ec_rpmsg.c

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ struct cros_ec_rpmsg {
4141
struct rpmsg_device *rpdev;
4242
struct completion xfer_ack;
4343
struct work_struct host_event_work;
44+
struct rpmsg_endpoint *ept;
4445
};
4546

4647
/**
@@ -72,7 +73,6 @@ static int cros_ec_pkt_xfer_rpmsg(struct cros_ec_device *ec_dev,
7273
struct cros_ec_command *ec_msg)
7374
{
7475
struct cros_ec_rpmsg *ec_rpmsg = ec_dev->priv;
75-
struct rpmsg_device *rpdev = ec_rpmsg->rpdev;
7676
struct ec_host_response *response;
7777
unsigned long timeout;
7878
int len;
@@ -85,7 +85,7 @@ static int cros_ec_pkt_xfer_rpmsg(struct cros_ec_device *ec_dev,
8585
dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
8686

8787
reinit_completion(&ec_rpmsg->xfer_ack);
88-
ret = rpmsg_send(rpdev->ept, ec_dev->dout, len);
88+
ret = rpmsg_send(ec_rpmsg->ept, ec_dev->dout, len);
8989
if (ret) {
9090
dev_err(ec_dev->dev, "rpmsg send failed\n");
9191
return ret;
@@ -196,11 +196,24 @@ static int cros_ec_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
196196
return 0;
197197
}
198198

199+
static struct rpmsg_endpoint *
200+
cros_ec_rpmsg_create_ept(struct rpmsg_device *rpdev)
201+
{
202+
struct rpmsg_channel_info chinfo = {};
203+
204+
strscpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE);
205+
chinfo.src = rpdev->src;
206+
chinfo.dst = RPMSG_ADDR_ANY;
207+
208+
return rpmsg_create_ept(rpdev, cros_ec_rpmsg_callback, NULL, chinfo);
209+
}
210+
199211
static int cros_ec_rpmsg_probe(struct rpmsg_device *rpdev)
200212
{
201213
struct device *dev = &rpdev->dev;
202214
struct cros_ec_rpmsg *ec_rpmsg;
203215
struct cros_ec_device *ec_dev;
216+
int ret;
204217

205218
ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
206219
if (!ec_dev)
@@ -225,7 +238,18 @@ static int cros_ec_rpmsg_probe(struct rpmsg_device *rpdev)
225238
INIT_WORK(&ec_rpmsg->host_event_work,
226239
cros_ec_rpmsg_host_event_function);
227240

228-
return cros_ec_register(ec_dev);
241+
ec_rpmsg->ept = cros_ec_rpmsg_create_ept(rpdev);
242+
if (!ec_rpmsg->ept)
243+
return -ENOMEM;
244+
245+
ret = cros_ec_register(ec_dev);
246+
if (ret < 0) {
247+
rpmsg_destroy_ept(ec_rpmsg->ept);
248+
cancel_work_sync(&ec_rpmsg->host_event_work);
249+
return ret;
250+
}
251+
252+
return 0;
229253
}
230254

231255
static void cros_ec_rpmsg_remove(struct rpmsg_device *rpdev)
@@ -234,7 +258,7 @@ static void cros_ec_rpmsg_remove(struct rpmsg_device *rpdev)
234258
struct cros_ec_rpmsg *ec_rpmsg = ec_dev->priv;
235259

236260
cros_ec_unregister(ec_dev);
237-
261+
rpmsg_destroy_ept(ec_rpmsg->ept);
238262
cancel_work_sync(&ec_rpmsg->host_event_work);
239263
}
240264

@@ -271,7 +295,6 @@ static struct rpmsg_driver cros_ec_driver_rpmsg = {
271295
},
272296
.probe = cros_ec_rpmsg_probe,
273297
.remove = cros_ec_rpmsg_remove,
274-
.callback = cros_ec_rpmsg_callback,
275298
};
276299

277300
module_rpmsg_driver(cros_ec_driver_rpmsg);

0 commit comments

Comments
 (0)