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
144 cros_ec_irq_thread(0, client_data->ec_dev); in ish_evt_handler()
148 * ish_send() - Send message from host to firmware
151 * @out_msg: Message buffer to be sent to firmware
167 struct ishtp_cl *cros_ish_cl = client_data->cros_ish_cl; in ish_send()
171 __func__, out_hdr->channel, out_hdr->status); in ish_send()
174 client_data->response.data = in_msg; in ish_send()
175 client_data->response.max_size = in_size; in ish_send()
176 client_data->response.error = 0; in ish_send()
177 client_data->response.token = next_token++; in ish_send()
178 client_data->response.received = false; in ish_send()
180 out_hdr->token = client_data->response.token; in ish_send()
189 wait_event_interruptible_timeout(client_data->response.wait_queue, in ish_send()
190 client_data->response.received, in ish_send()
192 if (!client_data->response.received) { in ish_send()
195 return -ETIMEDOUT; in ish_send()
198 if (client_data->response.error < 0) in ish_send()
199 return client_data->response.error; in ish_send()
201 return client_data->response.size; in ish_send()
205 * process_recv() - Received and parse incoming packet
217 size_t data_len = rb_in_proc->buf_idx; in process_recv()
222 (struct cros_ish_in_msg *)rb_in_proc->buffer.data; in process_recv()
224 /* Proceed only if reset or init is not in progress */ in process_recv()
234 * All firmware messages contain a header. Check the buffer size in process_recv()
237 if (!rb_in_proc->buffer.data) { in process_recv()
238 dev_warn(dev, "rb_in_proc->buffer.data returned null"); in process_recv()
239 client_data->response.error = -EBADMSG; in process_recv()
246 client_data->response.error = -EMSGSIZE; in process_recv()
251 in_msg->hdr.channel, in_msg->hdr.status); in process_recv()
253 switch (in_msg->hdr.channel) { in process_recv()
255 if (client_data->response.received) { in process_recv()
257 "Previous firmware message not yet processed\n"); in process_recv()
261 if (client_data->response.token != in_msg->hdr.token) { in process_recv()
264 in_msg->hdr.token); in process_recv()
269 if (!client_data->response.data) { in process_recv()
272 client_data->response.error = -EINVAL; in process_recv()
276 if (data_len > client_data->response.max_size) { in process_recv()
279 data_len, client_data->response.max_size); in process_recv()
280 client_data->response.error = -EMSGSIZE; in process_recv()
284 if (in_msg->hdr.status) { in process_recv()
285 dev_err(dev, "firmware returned status %d\n", in process_recv()
286 in_msg->hdr.status); in process_recv()
287 client_data->response.error = -EIO; in process_recv()
292 client_data->response.size = data_len; in process_recv()
295 * Copy the buffer received in firmware response for the in process_recv()
298 memcpy(client_data->response.data, in process_recv()
299 rb_in_proc->buffer.data, data_len); in process_recv()
307 client_data->response.received = true; in process_recv()
310 wake_up_interruptible(&client_data->response.wait_queue); in process_recv()
322 client_data->ec_dev->last_event_time = timestamp; in process_recv()
323 schedule_work(&client_data->work_ec_evt); in process_recv()
328 dev_err(dev, "Invalid channel=%02d\n", in_msg->hdr.channel); in process_recv()
340 * ish_event_cb() - bus driver callback for incoming message
365 * cros_ish_init() - Init function for ISHTP client
388 /* Connect to firmware client */ in cros_ish_init()
396 rv = -ENOENT; in cros_ish_init()
411 ishtp_register_event_cb(client_data->cl_device, ish_event_cb); in cros_ish_init()
420 * cros_ish_deinit() - Deinit function for ISHTP client
432 /* Disband and free all Tx and Rx client-level rings */ in cros_ish_deinit()
437 * prepare_cros_ec_rx() - Check & prepare receive buffer
454 msg->result = in_msg->ec_response.result; in prepare_cros_ec_rx()
459 if (in_msg->ec_response.data_len > msg->insize) { in prepare_cros_ec_rx()
460 dev_err(ec_dev->dev, "Packet too long (%d bytes, expected %d)", in prepare_cros_ec_rx()
461 in_msg->ec_response.data_len, msg->insize); in prepare_cros_ec_rx()
462 return -ENOSPC; in prepare_cros_ec_rx()
470 for (i = 0; i < in_msg->ec_response.data_len; i++) in prepare_cros_ec_rx()
471 sum += msg->data[i] = ((u8 *)in_msg)[offset + i]; in prepare_cros_ec_rx()
474 dev_dbg(ec_dev->dev, "Bad received packet checksum %d\n", sum); in prepare_cros_ec_rx()
475 return -EBADMSG; in prepare_cros_ec_rx()
485 struct ishtp_cl *cros_ish_cl = ec_dev->priv; in cros_ec_pkt_xfer_ish()
488 struct cros_ish_in_msg *in_msg = (struct cros_ish_in_msg *)ec_dev->din; in cros_ec_pkt_xfer_ish()
490 (struct cros_ish_out_msg *)ec_dev->dout; in cros_ec_pkt_xfer_ish()
491 size_t in_size = sizeof(struct cros_ish_in_msg) + msg->insize; in cros_ec_pkt_xfer_ish()
492 size_t out_size = sizeof(struct cros_ish_out_msg) + msg->outsize; in cros_ec_pkt_xfer_ish()
495 if (in_size > ec_dev->din_size) { in cros_ec_pkt_xfer_ish()
497 "Incoming payload size %zu is too large for ec_dev->din_size %d\n", in cros_ec_pkt_xfer_ish()
498 in_size, ec_dev->din_size); in cros_ec_pkt_xfer_ish()
499 return -EMSGSIZE; in cros_ec_pkt_xfer_ish()
502 if (out_size > ec_dev->dout_size) { in cros_ec_pkt_xfer_ish()
504 "Outgoing payload size %zu is too large for ec_dev->dout_size %d\n", in cros_ec_pkt_xfer_ish()
505 out_size, ec_dev->dout_size); in cros_ec_pkt_xfer_ish()
506 return -EMSGSIZE; in cros_ec_pkt_xfer_ish()
509 /* Proceed only if reset-init is not in progress */ in cros_ec_pkt_xfer_ish()
513 return -EAGAIN; in cros_ec_pkt_xfer_ish()
517 out_msg->hdr.channel = CROS_EC_COMMAND; in cros_ec_pkt_xfer_ish()
518 out_msg->hdr.status = 0; in cros_ec_pkt_xfer_ish()
520 ec_dev->dout += OUT_MSG_EC_REQUEST_PREAMBLE; in cros_ec_pkt_xfer_ish()
522 ec_dev->dout -= OUT_MSG_EC_REQUEST_PREAMBLE; in cros_ec_pkt_xfer_ish()
526 out_msg->ec_request.struct_version, in cros_ec_pkt_xfer_ish()
527 out_msg->ec_request.checksum, in cros_ec_pkt_xfer_ish()
528 out_msg->ec_request.command, in cros_ec_pkt_xfer_ish()
529 out_msg->ec_request.command_version, in cros_ec_pkt_xfer_ish()
530 out_msg->ec_request.data_len); in cros_ec_pkt_xfer_ish()
532 /* Send command to ISH EC firmware and read response */ in cros_ec_pkt_xfer_ish()
543 rv = in_msg->ec_response.data_len; in cros_ec_pkt_xfer_ish()
547 in_msg->ec_response.struct_version, in cros_ec_pkt_xfer_ish()
548 in_msg->ec_response.checksum, in cros_ec_pkt_xfer_ish()
549 in_msg->ec_response.result, in cros_ec_pkt_xfer_ish()
550 in_msg->ec_response.data_len); in cros_ec_pkt_xfer_ish()
553 if (msg->command == EC_CMD_REBOOT_EC) in cros_ec_pkt_xfer_ish()
568 return -ENOMEM; in cros_ec_dev_init()
570 client_data->ec_dev = ec_dev; in cros_ec_dev_init()
571 dev->driver_data = ec_dev; in cros_ec_dev_init()
573 ec_dev->dev = dev; in cros_ec_dev_init()
574 ec_dev->priv = client_data->cros_ish_cl; in cros_ec_dev_init()
575 ec_dev->cmd_xfer = NULL; in cros_ec_dev_init()
576 ec_dev->pkt_xfer = cros_ec_pkt_xfer_ish; in cros_ec_dev_init()
577 ec_dev->phys_name = dev_name(dev); in cros_ec_dev_init()
578 ec_dev->din_size = sizeof(struct cros_ish_in_msg) + in cros_ec_dev_init()
580 ec_dev->dout_size = sizeof(struct cros_ish_out_msg); in cros_ec_dev_init()
594 /* Lock for reset to complete */ in reset_handler()
597 cros_ish_cl = client_data->cros_ish_cl; in reset_handler()
598 cl_device = client_data->cl_device; in reset_handler()
613 client_data->cros_ish_cl = cros_ish_cl; in reset_handler()
618 dev_err(cl_data_to_dev(client_data), "Reset Failed\n"); in reset_handler()
624 client_data->ec_dev->priv = client_data->cros_ish_cl; in reset_handler()
626 dev->driver_data = client_data->ec_dev; in reset_handler()
628 dev_info(cl_data_to_dev(client_data), "Chrome EC ISH reset done\n"); in reset_handler()
634 * cros_ec_ishtp_probe() - ISHTP client driver probe callback
647 return -ENOMEM; in cros_ec_ishtp_probe()
654 rv = -ENOMEM; in cros_ec_ishtp_probe()
660 client_data->cros_ish_cl = cros_ish_cl; in cros_ec_ishtp_probe()
661 client_data->cl_device = cl_device; in cros_ec_ishtp_probe()
663 init_waitqueue_head(&client_data->response.wait_queue); in cros_ec_ishtp_probe()
665 INIT_WORK(&client_data->work_ishtp_reset, in cros_ec_ishtp_probe()
667 INIT_WORK(&client_data->work_ec_evt, in cros_ec_ishtp_probe()
701 * cros_ec_ishtp_remove() - ISHTP client driver remove callback
711 cancel_work_sync(&client_data->work_ishtp_reset); in cros_ec_ishtp_remove()
712 cancel_work_sync(&client_data->work_ec_evt); in cros_ec_ishtp_remove()
718 * cros_ec_ishtp_reset() - ISHTP client driver reset callback
728 schedule_work(&client_data->work_ishtp_reset); in cros_ec_ishtp_reset()
734 * cros_ec_ishtp_suspend() - ISHTP client driver suspend callback
745 return cros_ec_suspend(client_data->ec_dev); in cros_ec_ishtp_suspend()
749 * cros_ec_ishtp_resume() - ISHTP client driver resume callback
760 return cros_ec_resume(client_data->ec_dev); in cros_ec_ishtp_resume()
771 .reset = cros_ec_ishtp_reset,