|
15 | 15 | #include "cros_ec_trace.h" |
16 | 16 |
|
17 | 17 | #define EC_COMMAND_RETRIES 50 |
| 18 | +#define RWSIG_CONTINUE_RETRIES 8 |
| 19 | +#define RWSIG_CONTINUE_MAX_ERRORS_IN_ROW 3 |
18 | 20 |
|
19 | 21 | static const int cros_ec_error_map[] = { |
20 | 22 | [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 |
288 | 290 | return ret; |
289 | 291 | } |
290 | 292 |
|
| 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 | + |
291 | 351 | static int cros_ec_get_proto_info(struct cros_ec_device *ec_dev, int devidx) |
292 | 352 | { |
293 | 353 | struct cros_ec_command *msg; |
|
0 commit comments