Lines Matching +full:firmware +full:- +full:reset
1 // SPDX-License-Identifier: GPL-2.0
6 // ISHTP client driver for talking to the Chrome OS EC firmware running
8 // (ISH-TP).
15 #include <linux/intel-ish-client-if.h>
22 * The AP->ISH messages and corresponding ISH->AP responses are
25 * The MKBP ISH->AP events are serialized. We need one additional RX
33 CROS_EC_COMMAND = 1, /* AP->ISH message */
34 CROS_MKBP_EVENT = 2, /* ISH->AP events */
38 * ISH firmware timeout for 1 message send failure is 1Hz, and the
39 * firmware will retry 2 times, so 3Hz is used for timeout.
71 #define cl_data_to_dev(client_data) ishtp_device((client_data)->cl_device)
74 * The Read-Write Semaphore is used to prevent message TX or RX while
75 * the ishtp client is being initialized or undergoing reset.
77 * The readers are the kernel function calls responsible for IA->ISH
78 * and ISH->AP messaging.
80 * The writers are .reset() and .probe() function.
85 * struct response_info - Encapsulate firmware response related
89 * @data: Copy the data received from firmware here.
92 * @size: Actual size of data received from firmware.
95 * @received: Set to true on receiving a valid firmware response to host command
96 * @wait_queue: Wait queue for host to wait for firmware response.
109 * struct ishtp_cl_data - Encapsulate per ISH TP Client.
111 * @cros_ish_cl: ISHTP firmware client instance.
114 * @work_ishtp_reset: Work queue reset handling.
125 * Used for passing firmware response information between
136 * ish_evt_handler - ISH to AP event handler
143 struct cros_ec_device *ec_dev = client_data->ec_dev; in ish_evt_handler()
152 * ish_send() - Send message from host to firmware
155 * @out_msg: Message buffer to be sent to firmware
171 struct ishtp_cl *cros_ish_cl = client_data->cros_ish_cl; in ish_send()
175 __func__, out_hdr->channel, out_hdr->status); in ish_send()
178 client_data->response.data = in_msg; in ish_send()
179 client_data->response.max_size = in_size; in ish_send()
180 client_data->response.error = 0; in ish_send()
181 client_data->response.token = next_token++; in ish_send()
182 client_data->response.received = false; in ish_send()
184 out_hdr->token = client_data->response.token; in ish_send()
193 wait_event_interruptible_timeout(client_data->response.wait_queue, in ish_send()
194 client_data->response.received, in ish_send()
196 if (!client_data->response.received) { in ish_send()
199 return -ETIMEDOUT; in ish_send()
202 if (client_data->response.error < 0) in ish_send()
203 return client_data->response.error; in ish_send()
205 return client_data->response.size; in ish_send()
209 * process_recv() - Received and parse incoming packet
221 size_t data_len = rb_in_proc->buf_idx; in process_recv()
226 (struct cros_ish_in_msg *)rb_in_proc->buffer.data; in process_recv()
228 /* Proceed only if reset or init is not in progress */ in process_recv()
238 * All firmware messages contain a header. Check the buffer size in process_recv()
241 if (!rb_in_proc->buffer.data) { in process_recv()
242 dev_warn(dev, "rb_in_proc->buffer.data returned null"); in process_recv()
243 client_data->response.error = -EBADMSG; in process_recv()
250 client_data->response.error = -EMSGSIZE; in process_recv()
255 in_msg->hdr.channel, in_msg->hdr.status); in process_recv()
257 switch (in_msg->hdr.channel) { in process_recv()
259 if (client_data->response.received) { in process_recv()
261 "Previous firmware message not yet processed\n"); in process_recv()
265 if (client_data->response.token != in_msg->hdr.token) { in process_recv()
268 in_msg->hdr.token); in process_recv()
273 if (!client_data->response.data) { in process_recv()
276 client_data->response.error = -EINVAL; in process_recv()
280 if (data_len > client_data->response.max_size) { in process_recv()
283 data_len, client_data->response.max_size); in process_recv()
284 client_data->response.error = -EMSGSIZE; in process_recv()
288 if (in_msg->hdr.status) { in process_recv()
289 dev_err(dev, "firmware returned status %d\n", in process_recv()
290 in_msg->hdr.status); in process_recv()
291 client_data->response.error = -EIO; in process_recv()
296 client_data->response.size = data_len; in process_recv()
299 * Copy the buffer received in firmware response for the in process_recv()
302 memcpy(client_data->response.data, in process_recv()
303 rb_in_proc->buffer.data, data_len); in process_recv()
311 client_data->response.received = true; in process_recv()
314 wake_up_interruptible(&client_data->response.wait_queue); in process_recv()
326 client_data->ec_dev->last_event_time = timestamp; in process_recv()
327 schedule_work(&client_data->work_ec_evt); in process_recv()
332 dev_err(dev, "Invalid channel=%02d\n", in_msg->hdr.channel); in process_recv()
344 * ish_event_cb() - bus driver callback for incoming message
369 * cros_ish_init() - Init function for ISHTP client
392 /* Connect to firmware client */ in cros_ish_init()
400 rv = -ENOENT; in cros_ish_init()
415 ishtp_register_event_cb(client_data->cl_device, ish_event_cb); in cros_ish_init()
424 * cros_ish_deinit() - Deinit function for ISHTP client
436 /* Disband and free all Tx and Rx client-level rings */ in cros_ish_deinit()
441 * prepare_cros_ec_rx() - Check & prepare receive buffer
458 msg->result = in_msg->ec_response.result; in prepare_cros_ec_rx()
463 if (in_msg->ec_response.data_len > msg->insize) { in prepare_cros_ec_rx()
464 dev_err(ec_dev->dev, "Packet too long (%d bytes, expected %d)", in prepare_cros_ec_rx()
465 in_msg->ec_response.data_len, msg->insize); in prepare_cros_ec_rx()
466 return -ENOSPC; in prepare_cros_ec_rx()
474 for (i = 0; i < in_msg->ec_response.data_len; i++) in prepare_cros_ec_rx()
475 sum += msg->data[i] = ((u8 *)in_msg)[offset + i]; in prepare_cros_ec_rx()
478 dev_dbg(ec_dev->dev, "Bad received packet checksum %d\n", sum); in prepare_cros_ec_rx()
479 return -EBADMSG; in prepare_cros_ec_rx()
489 struct ishtp_cl *cros_ish_cl = ec_dev->priv; in cros_ec_pkt_xfer_ish()
492 struct cros_ish_in_msg *in_msg = (struct cros_ish_in_msg *)ec_dev->din; in cros_ec_pkt_xfer_ish()
494 (struct cros_ish_out_msg *)ec_dev->dout; in cros_ec_pkt_xfer_ish()
495 size_t in_size = sizeof(struct cros_ish_in_msg) + msg->insize; in cros_ec_pkt_xfer_ish()
496 size_t out_size = sizeof(struct cros_ish_out_msg) + msg->outsize; in cros_ec_pkt_xfer_ish()
499 if (in_size > ec_dev->din_size) { in cros_ec_pkt_xfer_ish()
501 "Incoming payload size %zu is too large for ec_dev->din_size %d\n", in cros_ec_pkt_xfer_ish()
502 in_size, ec_dev->din_size); in cros_ec_pkt_xfer_ish()
503 return -EMSGSIZE; in cros_ec_pkt_xfer_ish()
506 if (out_size > ec_dev->dout_size) { in cros_ec_pkt_xfer_ish()
508 "Outgoing payload size %zu is too large for ec_dev->dout_size %d\n", in cros_ec_pkt_xfer_ish()
509 out_size, ec_dev->dout_size); in cros_ec_pkt_xfer_ish()
510 return -EMSGSIZE; in cros_ec_pkt_xfer_ish()
513 /* Proceed only if reset-init is not in progress */ in cros_ec_pkt_xfer_ish()
517 return -EAGAIN; in cros_ec_pkt_xfer_ish()
521 out_msg->hdr.channel = CROS_EC_COMMAND; in cros_ec_pkt_xfer_ish()
522 out_msg->hdr.status = 0; in cros_ec_pkt_xfer_ish()
524 ec_dev->dout += OUT_MSG_EC_REQUEST_PREAMBLE; in cros_ec_pkt_xfer_ish()
526 ec_dev->dout -= OUT_MSG_EC_REQUEST_PREAMBLE; in cros_ec_pkt_xfer_ish()
530 out_msg->ec_request.struct_version, in cros_ec_pkt_xfer_ish()
531 out_msg->ec_request.checksum, in cros_ec_pkt_xfer_ish()
532 out_msg->ec_request.command, in cros_ec_pkt_xfer_ish()
533 out_msg->ec_request.command_version, in cros_ec_pkt_xfer_ish()
534 out_msg->ec_request.data_len); in cros_ec_pkt_xfer_ish()
536 /* Send command to ISH EC firmware and read response */ in cros_ec_pkt_xfer_ish()
547 rv = in_msg->ec_response.data_len; in cros_ec_pkt_xfer_ish()
551 in_msg->ec_response.struct_version, in cros_ec_pkt_xfer_ish()
552 in_msg->ec_response.checksum, in cros_ec_pkt_xfer_ish()
553 in_msg->ec_response.result, in cros_ec_pkt_xfer_ish()
554 in_msg->ec_response.data_len); in cros_ec_pkt_xfer_ish()
557 if (msg->command == EC_CMD_REBOOT_EC) in cros_ec_pkt_xfer_ish()
572 return -ENOMEM; in cros_ec_dev_init()
574 client_data->ec_dev = ec_dev; in cros_ec_dev_init()
575 dev->driver_data = ec_dev; in cros_ec_dev_init()
577 ec_dev->dev = dev; in cros_ec_dev_init()
578 ec_dev->priv = client_data->cros_ish_cl; in cros_ec_dev_init()
579 ec_dev->cmd_xfer = NULL; in cros_ec_dev_init()
580 ec_dev->pkt_xfer = cros_ec_pkt_xfer_ish; in cros_ec_dev_init()
581 ec_dev->phys_name = dev_name(dev); in cros_ec_dev_init()
582 ec_dev->din_size = sizeof(struct cros_ish_in_msg) + in cros_ec_dev_init()
584 ec_dev->dout_size = sizeof(struct cros_ish_out_msg); in cros_ec_dev_init()
598 /* Lock for reset to complete */ in reset_handler()
601 cros_ish_cl = client_data->cros_ish_cl; in reset_handler()
602 cl_device = client_data->cl_device; in reset_handler()
617 client_data->cros_ish_cl = cros_ish_cl; in reset_handler()
622 dev_err(cl_data_to_dev(client_data), "Reset Failed\n"); in reset_handler()
628 client_data->ec_dev->priv = client_data->cros_ish_cl; in reset_handler()
630 dev->driver_data = client_data->ec_dev; in reset_handler()
632 dev_info(cl_data_to_dev(client_data), "Chrome EC ISH reset done\n"); in reset_handler()
638 * cros_ec_ishtp_probe() - ISHTP client driver probe callback
651 return -ENOMEM; in cros_ec_ishtp_probe()
658 rv = -ENOMEM; in cros_ec_ishtp_probe()
664 client_data->cros_ish_cl = cros_ish_cl; in cros_ec_ishtp_probe()
665 client_data->cl_device = cl_device; in cros_ec_ishtp_probe()
667 init_waitqueue_head(&client_data->response.wait_queue); in cros_ec_ishtp_probe()
669 INIT_WORK(&client_data->work_ishtp_reset, in cros_ec_ishtp_probe()
671 INIT_WORK(&client_data->work_ec_evt, in cros_ec_ishtp_probe()
705 * cros_ec_ishtp_remove() - ISHTP client driver remove callback
715 cancel_work_sync(&client_data->work_ishtp_reset); in cros_ec_ishtp_remove()
716 cancel_work_sync(&client_data->work_ec_evt); in cros_ec_ishtp_remove()
724 * cros_ec_ishtp_reset() - ISHTP client driver reset callback
734 schedule_work(&client_data->work_ishtp_reset); in cros_ec_ishtp_reset()
740 * cros_ec_ishtp_suspend() - ISHTP client driver suspend callback
751 return cros_ec_suspend(client_data->ec_dev); in cros_ec_ishtp_suspend()
755 * cros_ec_ishtp_resume() - ISHTP client driver resume callback
766 return cros_ec_resume(client_data->ec_dev); in cros_ec_ishtp_resume()
777 .reset = cros_ec_ishtp_reset,