Skip to content

Commit 5ffa0db

Browse files
niedzwiecki-dawidTzung-Bi Shih
authored andcommitted
platform/chrome: cros_ec: jump to RW before probing
There are EC devices, like FPMCU, that use RWSIG as a method of authenticating RW section. After the authentication succeeds, EC device waits some time before jumping to RW. EC can be probed before the jump, which means there is a time window after jump to RW in which EC won't respond, because it is not initialized. It can cause a communication errors after probing. To avoid such problems, send the RWSIG continue command first, which skips waiting for the jump to RW. Send the command more times, to make sure EC is ready in RW before the start of the actual probing process. If a EC device doesn't support the RWSIG, it will respond with invalid command error code and probing will continue as usual. Signed-off-by: Dawid Niedzwiecki <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Tzung-Bi Shih <[email protected]>
1 parent cfa842c commit 5ffa0db

File tree

9 files changed

+74
-6
lines changed

9 files changed

+74
-6
lines changed

drivers/platform/chrome/cros_ec.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,11 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
204204
mutex_init(&ec_dev->lock);
205205
lockdep_set_class(&ec_dev->lock, &ec_dev->lockdep_key);
206206

207+
/* Send RWSIG continue to jump to RW for devices using RWSIG. */
208+
err = cros_ec_rwsig_continue(ec_dev);
209+
if (err)
210+
dev_info(dev, "Failed to continue RWSIG: %d\n", err);
211+
207212
err = cros_ec_query_all(ec_dev);
208213
if (err) {
209214
dev_err(dev, "Cannot identify the EC: error %d\n", err);

drivers/platform/chrome/cros_ec_i2c.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,8 @@ static int cros_ec_i2c_probe(struct i2c_client *client)
305305
ec_dev->phys_name = client->adapter->name;
306306
ec_dev->din_size = sizeof(struct ec_host_response_i2c) +
307307
sizeof(struct ec_response_get_protocol_info);
308-
ec_dev->dout_size = sizeof(struct ec_host_request_i2c);
308+
ec_dev->dout_size = sizeof(struct ec_host_request_i2c) +
309+
sizeof(struct ec_params_rwsig_action);
309310

310311
err = cros_ec_register(ec_dev);
311312
if (err) {

drivers/platform/chrome/cros_ec_ishtp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ static int cros_ec_dev_init(struct ishtp_cl_data *client_data)
557557
ec_dev->phys_name = dev_name(dev);
558558
ec_dev->din_size = sizeof(struct cros_ish_in_msg) +
559559
sizeof(struct ec_response_get_protocol_info);
560-
ec_dev->dout_size = sizeof(struct cros_ish_out_msg);
560+
ec_dev->dout_size = sizeof(struct cros_ish_out_msg) + sizeof(struct ec_params_rwsig_action);
561561

562562
return cros_ec_register(ec_dev);
563563
}

drivers/platform/chrome/cros_ec_lpc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
573573
ec_dev->cmd_readmem = cros_ec_lpc_readmem;
574574
ec_dev->din_size = sizeof(struct ec_host_response) +
575575
sizeof(struct ec_response_get_protocol_info);
576-
ec_dev->dout_size = sizeof(struct ec_host_request);
576+
ec_dev->dout_size = sizeof(struct ec_host_request) + sizeof(struct ec_params_rwsig_action);
577577
ec_dev->priv = ec_lpc;
578578

579579
/*

drivers/platform/chrome/cros_ec_proto.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include "cros_ec_trace.h"
1616

1717
#define EC_COMMAND_RETRIES 50
18+
#define RWSIG_CONTINUE_RETRIES 8
19+
#define RWSIG_CONTINUE_MAX_ERRORS_IN_ROW 3
1820

1921
static const int cros_ec_error_map[] = {
2022
[EC_RES_INVALID_COMMAND] = -EOPNOTSUPP,
@@ -288,6 +290,64 @@ static int cros_ec_get_host_event_wake_mask(struct cros_ec_device *ec_dev, uint3
288290
return ret;
289291
}
290292

293+
int cros_ec_rwsig_continue(struct cros_ec_device *ec_dev)
294+
{
295+
struct cros_ec_command *msg;
296+
struct ec_params_rwsig_action *rwsig_action;
297+
int ret = 0;
298+
int error_count = 0;
299+
300+
ec_dev->proto_version = 3;
301+
302+
msg = kmalloc(sizeof(*msg) + sizeof(*rwsig_action), GFP_KERNEL);
303+
if (!msg)
304+
return -ENOMEM;
305+
306+
msg->version = 0;
307+
msg->command = EC_CMD_RWSIG_ACTION;
308+
msg->insize = 0;
309+
msg->outsize = sizeof(*rwsig_action);
310+
311+
rwsig_action = (struct ec_params_rwsig_action *)msg->data;
312+
rwsig_action->action = RWSIG_ACTION_CONTINUE;
313+
314+
for (int i = 0; i < RWSIG_CONTINUE_RETRIES; i++) {
315+
ret = cros_ec_send_command(ec_dev, msg);
316+
317+
if (ret < 0) {
318+
if (++error_count >= RWSIG_CONTINUE_MAX_ERRORS_IN_ROW)
319+
break;
320+
} else if (msg->result == EC_RES_INVALID_COMMAND) {
321+
/*
322+
* If EC_RES_INVALID_COMMAND is retured, it means RWSIG
323+
* is not supported or EC is already in RW, so there is
324+
* nothing left to do.
325+
*/
326+
break;
327+
} else if (msg->result != EC_RES_SUCCESS) {
328+
/* Unexpected command error. */
329+
ret = cros_ec_map_error(msg->result);
330+
break;
331+
} else {
332+
/*
333+
* The EC_CMD_RWSIG_ACTION succeed. Send the command
334+
* more times, to make sure EC is in RW. A following
335+
* command can timeout, because EC may need some time to
336+
* initialize after jump to RW.
337+
*/
338+
error_count = 0;
339+
}
340+
341+
if (ret != -ETIMEDOUT)
342+
usleep_range(90000, 100000);
343+
}
344+
345+
kfree(msg);
346+
347+
return ret;
348+
}
349+
EXPORT_SYMBOL(cros_ec_rwsig_continue);
350+
291351
static int cros_ec_get_proto_info(struct cros_ec_device *ec_dev, int devidx)
292352
{
293353
struct cros_ec_command *msg;

drivers/platform/chrome/cros_ec_rpmsg.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ static int cros_ec_rpmsg_probe(struct rpmsg_device *rpdev)
231231
ec_dev->phys_name = dev_name(&rpdev->dev);
232232
ec_dev->din_size = sizeof(struct ec_host_response) +
233233
sizeof(struct ec_response_get_protocol_info);
234-
ec_dev->dout_size = sizeof(struct ec_host_request);
234+
ec_dev->dout_size = sizeof(struct ec_host_request) + sizeof(struct ec_params_rwsig_action);
235235
dev_set_drvdata(dev, ec_dev);
236236

237237
ec_rpmsg->rpdev = rpdev;

drivers/platform/chrome/cros_ec_spi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,7 @@ static int cros_ec_spi_probe(struct spi_device *spi)
766766
ec_dev->din_size = EC_MSG_PREAMBLE_COUNT +
767767
sizeof(struct ec_host_response) +
768768
sizeof(struct ec_response_get_protocol_info);
769-
ec_dev->dout_size = sizeof(struct ec_host_request);
769+
ec_dev->dout_size = sizeof(struct ec_host_request) + sizeof(struct ec_params_rwsig_action);
770770

771771
ec_spi->last_transfer_ns = ktime_get_ns();
772772

drivers/platform/chrome/cros_ec_uart.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ static int cros_ec_uart_probe(struct serdev_device *serdev)
283283
ec_dev->pkt_xfer = cros_ec_uart_pkt_xfer;
284284
ec_dev->din_size = sizeof(struct ec_host_response) +
285285
sizeof(struct ec_response_get_protocol_info);
286-
ec_dev->dout_size = sizeof(struct ec_host_request);
286+
ec_dev->dout_size = sizeof(struct ec_host_request) + sizeof(struct ec_params_rwsig_action);
287287

288288
serdev_device_set_client_ops(serdev, &cros_ec_uart_client_ops);
289289

include/linux/platform_data/cros_ec_proto.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,8 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
246246
int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
247247
struct cros_ec_command *msg);
248248

249+
int cros_ec_rwsig_continue(struct cros_ec_device *ec_dev);
250+
249251
int cros_ec_query_all(struct cros_ec_device *ec_dev);
250252

251253
int cros_ec_get_next_event(struct cros_ec_device *ec_dev,

0 commit comments

Comments
 (0)