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.
74 #define cl_data_to_dev(client_data) ishtp_device((client_data)->cl_device)
77 * The Read-Write Semaphore is used to prevent message TX or RX while
78 * the ishtp client is being initialized or undergoing reset.
80 * The readers are the kernel function calls responsible for IA->ISH
81 * and ISH->AP messaging.
83 * The writers are .reset() and .probe() function.
88 * struct response_info - Encapsulate firmware response related
92 * @data: Copy the data received from firmware here.
95 * @size: Actual size of data received from firmware.
98 * @received: Set to true on receiving a valid firmware response to host command
99 * @wait_queue: Wait queue for host to wait for firmware response.
112 * struct ishtp_cl_data - Encapsulate per ISH TP Client.
114 * @cros_ish_cl: ISHTP firmware client instance.
117 * @work_ishtp_reset: Work queue reset handling.
128 * Used for passing firmware response information between
139 * ish_evt_handler - ISH to AP event handler
147 cros_ec_irq_thread(0, client_data->ec_dev); in ish_evt_handler()
151 * ish_send() - Send message from host to firmware
154 * @out_msg: Message buffer to be sent to firmware
170 struct ishtp_cl *cros_ish_cl = client_data->cros_ish_cl; in ish_send()
174 __func__, out_hdr->channel, out_hdr->status); in ish_send()
177 client_data->response.data = in_msg; in ish_send()
178 client_data->response.max_size = in_size; in ish_send()
179 client_data->response.error = 0; in ish_send()
180 client_data->response.token = next_token++; in ish_send()
181 client_data->response.received = false; in ish_send()
183 out_hdr->token = client_data->response.token; in ish_send()
192 wait_event_interruptible_timeout(client_data->response.wait_queue, in ish_send()
193 client_data->response.received, in ish_send()
195 if (!client_data->response.received) { in ish_send()
198 return -ETIMEDOUT; in ish_send()
201 if (client_data->response.error < 0) in ish_send()
202 return client_data->response.error; in ish_send()
204 return client_data->response.size; in ish_send()
208 * process_recv() - Received and parse incoming packet
220 size_t data_len = rb_in_proc->buf_idx; in process_recv()
225 (struct cros_ish_in_msg *)rb_in_proc->buffer.data; in process_recv()
227 /* Proceed only if reset or init is not in progress */ in process_recv()
237 * All firmware messages contain a header. Check the buffer size in process_recv()
240 if (!rb_in_proc->buffer.data) { in process_recv()
241 dev_warn(dev, "rb_in_proc->buffer.data returned null"); in process_recv()
242 client_data->response.error = -EBADMSG; in process_recv()
249 client_data->response.error = -EMSGSIZE; in process_recv()
254 in_msg->hdr.channel, in_msg->hdr.status); in process_recv()
256 switch (in_msg->hdr.channel) { in process_recv()
258 if (client_data->response.received) { in process_recv()
260 "Previous firmware message not yet processed\n"); in process_recv()
264 if (client_data->response.token != in_msg->hdr.token) { in process_recv()
267 in_msg->hdr.token); in process_recv()
272 if (!client_data->response.data) { in process_recv()
275 client_data->response.error = -EINVAL; in process_recv()
279 if (data_len > client_data->response.max_size) { in process_recv()
282 data_len, client_data->response.max_size); in process_recv()
283 client_data->response.error = -EMSGSIZE; in process_recv()
287 if (in_msg->hdr.status) { in process_recv()
288 dev_err(dev, "firmware returned status %d\n", in process_recv()
289 in_msg->hdr.status); in process_recv()
290 client_data->response.error = -EIO; in process_recv()
295 client_data->response.size = data_len; in process_recv()
298 * Copy the buffer received in firmware response for the in process_recv()
301 memcpy(client_data->response.data, in process_recv()
302 rb_in_proc->buffer.data, data_len); in process_recv()
310 client_data->response.received = true; in process_recv()
313 wake_up_interruptible(&client_data->response.wait_queue); in process_recv()
325 client_data->ec_dev->last_event_time = timestamp; in process_recv()
326 schedule_work(&client_data->work_ec_evt); in process_recv()
331 dev_err(dev, "Invalid channel=%02d\n", in_msg->hdr.channel); in process_recv()
343 * ish_event_cb() - bus driver callback for incoming message
368 * cros_ish_init() - Init function for ISHTP client
370 * @reset: true if called from reset handler
376 static int cros_ish_init(struct ishtp_cl *cros_ish_cl, bool reset) in cros_ish_init() argument
385 reset); in cros_ish_init()
392 ishtp_register_event_cb(client_data->cl_device, ish_event_cb); in cros_ish_init()
396 ishtp_cl_destroy_connection(cros_ish_cl, reset); in cros_ish_init()
401 * cros_ish_deinit() - Deinit function for ISHTP client
410 /* Disband and free all Tx and Rx client-level rings */ in cros_ish_deinit()
415 * prepare_cros_ec_rx() - Check & prepare receive buffer
432 msg->result = in_msg->ec_response.result; in prepare_cros_ec_rx()
437 if (in_msg->ec_response.data_len > msg->insize) { in prepare_cros_ec_rx()
438 dev_err(ec_dev->dev, "Packet too long (%d bytes, expected %d)", in prepare_cros_ec_rx()
439 in_msg->ec_response.data_len, msg->insize); in prepare_cros_ec_rx()
440 return -ENOSPC; in prepare_cros_ec_rx()
448 for (i = 0; i < in_msg->ec_response.data_len; i++) in prepare_cros_ec_rx()
449 sum += msg->data[i] = ((u8 *)in_msg)[offset + i]; in prepare_cros_ec_rx()
452 dev_dbg(ec_dev->dev, "Bad received packet checksum %d\n", sum); in prepare_cros_ec_rx()
453 return -EBADMSG; in prepare_cros_ec_rx()
463 struct ishtp_cl *cros_ish_cl = ec_dev->priv; in cros_ec_pkt_xfer_ish()
466 struct cros_ish_in_msg *in_msg = (struct cros_ish_in_msg *)ec_dev->din; in cros_ec_pkt_xfer_ish()
468 (struct cros_ish_out_msg *)ec_dev->dout; in cros_ec_pkt_xfer_ish()
469 size_t in_size = sizeof(struct cros_ish_in_msg) + msg->insize; in cros_ec_pkt_xfer_ish()
470 size_t out_size = sizeof(struct cros_ish_out_msg) + msg->outsize; in cros_ec_pkt_xfer_ish()
473 if (in_size > ec_dev->din_size) { in cros_ec_pkt_xfer_ish()
475 "Incoming payload size %zu is too large for ec_dev->din_size %d\n", in cros_ec_pkt_xfer_ish()
476 in_size, ec_dev->din_size); in cros_ec_pkt_xfer_ish()
477 return -EMSGSIZE; in cros_ec_pkt_xfer_ish()
480 if (out_size > ec_dev->dout_size) { in cros_ec_pkt_xfer_ish()
482 "Outgoing payload size %zu is too large for ec_dev->dout_size %d\n", in cros_ec_pkt_xfer_ish()
483 out_size, ec_dev->dout_size); in cros_ec_pkt_xfer_ish()
484 return -EMSGSIZE; in cros_ec_pkt_xfer_ish()
487 /* Proceed only if reset-init is not in progress */ in cros_ec_pkt_xfer_ish()
491 return -EAGAIN; in cros_ec_pkt_xfer_ish()
495 out_msg->hdr.channel = CROS_EC_COMMAND; in cros_ec_pkt_xfer_ish()
496 out_msg->hdr.status = 0; in cros_ec_pkt_xfer_ish()
498 ec_dev->dout += OUT_MSG_EC_REQUEST_PREAMBLE; in cros_ec_pkt_xfer_ish()
502 ec_dev->dout -= OUT_MSG_EC_REQUEST_PREAMBLE; in cros_ec_pkt_xfer_ish()
506 out_msg->ec_request.struct_version, in cros_ec_pkt_xfer_ish()
507 out_msg->ec_request.checksum, in cros_ec_pkt_xfer_ish()
508 out_msg->ec_request.command, in cros_ec_pkt_xfer_ish()
509 out_msg->ec_request.command_version, in cros_ec_pkt_xfer_ish()
510 out_msg->ec_request.data_len); in cros_ec_pkt_xfer_ish()
512 /* Send command to ISH EC firmware and read response */ in cros_ec_pkt_xfer_ish()
523 rv = in_msg->ec_response.data_len; in cros_ec_pkt_xfer_ish()
527 in_msg->ec_response.struct_version, in cros_ec_pkt_xfer_ish()
528 in_msg->ec_response.checksum, in cros_ec_pkt_xfer_ish()
529 in_msg->ec_response.result, in cros_ec_pkt_xfer_ish()
530 in_msg->ec_response.data_len); in cros_ec_pkt_xfer_ish()
533 if (msg->command == EC_CMD_REBOOT_EC) in cros_ec_pkt_xfer_ish()
548 return -ENOMEM; in cros_ec_dev_init()
550 client_data->ec_dev = ec_dev; in cros_ec_dev_init()
551 dev->driver_data = ec_dev; in cros_ec_dev_init()
553 ec_dev->dev = dev; in cros_ec_dev_init()
554 ec_dev->priv = client_data->cros_ish_cl; in cros_ec_dev_init()
555 ec_dev->cmd_xfer = NULL; in cros_ec_dev_init()
556 ec_dev->pkt_xfer = cros_ec_pkt_xfer_ish; in cros_ec_dev_init()
557 ec_dev->phys_name = dev_name(dev); in cros_ec_dev_init()
558 ec_dev->din_size = sizeof(struct cros_ish_in_msg) + in cros_ec_dev_init()
560 ec_dev->dout_size = sizeof(struct cros_ish_out_msg); in cros_ec_dev_init()
573 /* Lock for reset to complete */ in reset_handler()
576 cros_ish_cl = client_data->cros_ish_cl; in reset_handler()
582 dev_err(cl_data_to_dev(client_data), "Reset Failed\n"); in reset_handler()
588 client_data->ec_dev->priv = client_data->cros_ish_cl; in reset_handler()
590 dev->driver_data = client_data->ec_dev; in reset_handler()
592 dev_info(cl_data_to_dev(client_data), "Chrome EC ISH reset done\n"); in reset_handler()
598 * cros_ec_ishtp_probe() - ISHTP client driver probe callback
611 return -ENOMEM; in cros_ec_ishtp_probe()
618 rv = -ENOMEM; in cros_ec_ishtp_probe()
624 client_data->cros_ish_cl = cros_ish_cl; in cros_ec_ishtp_probe()
625 client_data->cl_device = cl_device; in cros_ec_ishtp_probe()
627 init_waitqueue_head(&client_data->response.wait_queue); in cros_ec_ishtp_probe()
629 INIT_WORK(&client_data->work_ishtp_reset, in cros_ec_ishtp_probe()
631 INIT_WORK(&client_data->work_ec_evt, in cros_ec_ishtp_probe()
662 * cros_ec_ishtp_remove() - ISHTP client driver remove callback
672 cancel_work_sync(&client_data->work_ishtp_reset); in cros_ec_ishtp_remove()
673 cancel_work_sync(&client_data->work_ec_evt); in cros_ec_ishtp_remove()
679 * cros_ec_ishtp_reset() - ISHTP client driver reset callback
689 schedule_work(&client_data->work_ishtp_reset); in cros_ec_ishtp_reset()
695 * cros_ec_ishtp_suspend() - ISHTP client driver suspend callback
706 return cros_ec_suspend(client_data->ec_dev); in cros_ec_ishtp_suspend()
710 * cros_ec_ishtp_resume() - ISHTP client driver resume callback
721 return cros_ec_resume(client_data->ec_dev); in cros_ec_ishtp_resume()
732 .reset = cros_ec_ishtp_reset,