/* * EC sends contiguous bytes of response packet on UART AP RX. * TTY driver in AP accumulates incoming bytes and calls the registered callback * function. Byte count can range from 1 to MAX bytes supported by EC. * This driver should wait for long time for all callbacks to be processed. * Considering the worst case scenario, wait for 500 msec. This timeout should * account for max latency and some additional guard time. * Best case: Entire packet is received in ~200 ms, wait queue will be released * and packet will be processed. * Worst case: TTY driver sends bytes in multiple callbacks. In this case this * driver will wait for ~1 sec beyond which it will timeout. * This timeout value should not exceed ~500 msec because in case if * EC_CMD_REBOOT_EC sent, high level driver should be able to intercept EC * in RO.
*/ #define EC_MSG_DEADLINE_MS 500
/** * struct response_info - Encapsulate EC response related * information for passing between function * cros_ec_uart_pkt_xfer() and cros_ec_uart_rx_bytes() * callback. * @data: Copy the data received from EC here. * @max_size: Max size allocated for the @data buffer. If the * received data exceeds this value, we log an error. * @size: Actual size of data received from EC. This is also * used to accumulate byte count with response is received * in dma chunks. * @exp_len: Expected bytes of response from EC including header. * @status: Re-init to 0 before sending a cmd. Updated to 1 when * a response is successfully received, or an error number * on failure. * @wait_queue: Wait queue EC response where the cros_ec sends request * to EC and waits
*/ struct response_info { void *data;
size_t max_size;
size_t size;
size_t exp_len; int status;
wait_queue_head_t wait_queue;
};
/** * struct cros_ec_uart - information about a uart-connected EC * * @serdev: serdev uart device we are connected to. * @baudrate: UART baudrate of attached EC device. * @flowcontrol: UART flowcontrol of attached device. * @irq: Linux IRQ number of associated serial device. * @response: Response info passing between cros_ec_uart_pkt_xfer() * and cros_ec_uart_rx_bytes()
*/ struct cros_ec_uart { struct serdev_device *serdev;
u32 baudrate;
u8 flowcontrol;
u32 irq; struct response_info response;
};
/* Check if bytes were sent out of band */ if (!resp->data) { /* Discard all bytes */
dev_warn(ec_dev->dev, "Bytes received out of band, dropping them.\n"); return count;
}
/* * Check if incoming bytes + resp->size is greater than allocated * buffer in din by cros_ec. This will ensure that if EC sends more * bytes than max_size, waiting process will be notified with an error.
*/ if (resp->size + count > resp->max_size) {
resp->status = -EMSGSIZE;
wake_up(&resp->wait_queue); return count;
}
memcpy(resp->data + resp->size, data, count);
resp->size += count;
/* Read data_len if we received response header and if exp_len was not read before. */ if (resp->size >= sizeof(*host_response) && resp->exp_len == 0) {
host_response = (struct ec_host_response *)resp->data;
resp->exp_len = host_response->data_len + sizeof(*host_response);
}
/* If driver received response header and payload from EC, wake up the wait queue. */ if (resp->size >= sizeof(*host_response) && resp->size == resp->exp_len) {
resp->status = 1;
wake_up(&resp->wait_queue);
}
ret = serdev_device_write_buf(serdev, ec_dev->dout, len); if (ret < 0 || ret < len) {
dev_err(ec_dev->dev, "Unable to write data\n"); if (ret >= 0)
ret = -EIO; gotoexit;
}
ret = wait_event_timeout(resp->wait_queue, resp->status,
msecs_to_jiffies(EC_MSG_DEADLINE_MS)); if (ret == 0) {
dev_warn(ec_dev->dev, "Timed out waiting for response.\n");
ret = -ETIMEDOUT; gotoexit;
}
if (resp->status < 0) {
ret = resp->status;
dev_warn(ec_dev->dev, "Error response received: %d\n", ret); gotoexit;
}
if (host_response->data_len > ec_msg->insize) {
dev_err(ec_dev->dev, "Resp too long (%d bytes, expected %d)\n",
host_response->data_len, ec_msg->insize);
ret = -ENOSPC; gotoexit;
}
/* Validate checksum */
sum = 0; for (i = 0; i < sizeof(*host_response) + host_response->data_len; i++)
sum += ec_dev->din[i];
if (sum) {
dev_err(ec_dev->dev, "Bad packet checksum calculated %x\n", sum);
ret = -EBADMSG; gotoexit;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.