diff options
Diffstat (limited to 'chip/stm32/usart_host_command.c')
-rw-r--r-- | chip/stm32/usart_host_command.c | 616 |
1 files changed, 0 insertions, 616 deletions
diff --git a/chip/stm32/usart_host_command.c b/chip/stm32/usart_host_command.c deleted file mode 100644 index f4d6a65fc4..0000000000 --- a/chip/stm32/usart_host_command.c +++ /dev/null @@ -1,616 +0,0 @@ -/* Copyright 2020 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "common.h" -#include "clock.h" -#include "dma.h" -#include "gpio.h" -#include "hooks.h" -#include "host_command.h" -#include "queue_policies.h" -#include "registers.h" -#include "system.h" -#include "task.h" -#include "usart_rx_dma.h" -#include "usart_host_command.h" -#include "usart-stm32f4.h" -#include "util.h" - -/* Console output macros */ -#define CPRINTS(format, args...) cprints(CC_HOSTCMD, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_HOSTCMD, format, ## args) - -/* - * Timeout to wait for complete request packet - * - * This value determines how long we should wait for entire packet to arrive. - * USART host command handler should wait for at least 75% of - * EC_MSG_DEADLINE_MS, before declaring timeout and dropping the packet. - * - * This timeout should be less than host's driver timeout to make sure that - * last packet can be successfully discarded before AP attempts to resend - * request. AP driver waits for EC_MSG_DEADLINE_MS = 200 before attempting a - * retry. - */ -#define USART_REQ_RX_TIMEOUT (150 * MSEC) - -/* - * Timeout to wait for overrun bytes on USART - * - * This values determines how long call to process_request should be deferred - * in case host is sending extra bytes. This value is based on DMA buffer size. - * - * There is no guarantee that AP will send continuous bytes on usart. Wait - * for USART_DEFERRED_PROCESS_REQ_TIMEOUT_US to check if host is sending - * extra bytes. - * Note: This value affects the response latency. - */ -#define USART_DEFERRED_PROCESS_REQ_TIMEOUT 300 - -/* - * Max data size for a version 3 request/response packet. This is big enough - * to handle a request/response header, flash write offset/size and 512 bytes - * of request payload or 224 bytes of response payload. - */ -#define USART_MAX_REQUEST_SIZE 0x220 -#define USART_MAX_RESPONSE_SIZE 0x100 - -/* - * FIFO size for USART DMA. Should be big enough to handle worst case - * data processing - */ -#define USART_DMA_FIFO_SIZE 0x110 - -/* Local definitions */ - -/* - * Raw USART RX/TX byte buffers. - */ -static uint8_t usart_in_buffer[USART_MAX_REQUEST_SIZE] __aligned(4); -static uint8_t usart_out_buffer[USART_MAX_RESPONSE_SIZE] __aligned(4); - -/* - * Maintain head position of in buffer - * Head always starts with zero and goes up to max bytes. - * Once the buffer contents are read, it should go back to zero. - */ -static uint16_t usart_in_head; - -/* - * Maintain head position of out buffer - * Head always starts from zero and goes up to max bytes. - * Head is moved by tx interrupt handler to response size sent by host command - * task. Once all the bytes are sent (head == tail) both should go back to 0. - */ -static uint16_t usart_out_head; - -/* - * Once the response is ready, get the datalen - */ -static uint16_t usart_out_datalen; - -/* - * Enumeration to maintain different states of incoming request from - * host - */ -static enum uart_host_command_state { - /* - * USART host command handler not enabled. - */ - USART_HOST_CMD_STATE_DISABLED, - - /* - * Ready to receive next request - * This state represents USART layer is initialized and ready to - * receive host request. Once the response is sent, current_state is - * reset to this state to accept next packet. - */ - USART_HOST_CMD_READY_TO_RX, - - /* - * Receiving request - * After first byte is received current_state is moved to receiving - * state until all the header bytes + datalen bytes are received. - * If host_request_timeout was called in this state, it would be - * because of an underrun situation. - */ - USART_HOST_CMD_RECEIVING, - - /* - * Receiving complete - * Once all the header bytes + datalen bytes are received, current_state - * is moved to complete. Ideally, host should wait for response or retry - * timeout before sending anymore bytes, otherwise current_state will - * be moved to overrun to represent extra bytes sent by host. - */ - USART_HOST_CMD_COMPLETE, - - /* - * Processing request - * Once the process_request starts processing usart_in_buffer, - * current_state is moved to processing state. Host should not send - * any bytes in this state as it would be considered contiguous - * request. - */ - USART_HOST_CMD_PROCESSING, - - /* - * Sending response - * Once host task is ready with the response bytes, current_state is - * moved to sending state. - */ - USART_HOST_CMD_SENDING, - - /* - * Received bad data - * If bad packet header is received, current_state is moved to rx_bad - * state and after rx_timeout all the bytes are dropped. - */ - USART_HOST_CMD_RX_BAD, - - /* - * Receiving data overrun bytes - * If extra bytes are received after current_state is in complete, - * host is sending extra bytes which indicates data overrun. - */ - USART_HOST_CMD_RX_OVERRUN, - -} current_state __aligned(4); - -/* - * This diagram is the state machine representation of USART host - * command layer. - * - * This layer is responsible for checking packet integrity of incoming bytes - * on usart transceiver. It will only process packet header to check version, - * data_len. This layer will not process payload bytes. - * - * STATE = USART_HOST_CMD_STATE_DISABLED - * - * Initialize USART and local variables - * - * STATE = USART_HOST_CMD_READY_TO_RX - * - * |<---------- HOST RETRY TIMEOUT = 200 ms ---------->| - * | - * |--------------USART_REQ_RX_TIMEOUT------>| - * | Underrun if request not complete -->| - * | |<-- USART ready to rx - * |____REQUEST____ ____REQUEST____ - * | | | | | | - * | HDR | DATA | | HDR | DATA | - * |_____|_________| |_____|_________| - * | - * |<-- Request packet start - * | - * STATE = USART_HOST_CMD_RECEIVING - * | - * |<-- HDR received, now we will wait for data len bytes - * | - * If bad packet is received, move state to rx_bad - * STATE = USART_HOST_CMD_RX_BAD - * Ignore data processing, print status on console and reset layer ----------- - * | | - * |<-- Request packet end (data rx complete) | - * | | - * If request_timeout is called, it represents packet underrun | - * Ignore data processing, print status on console and reset layer ----------- - * | | - * STATE = USART_HOST_CMD_COMPLETE | - * | | - * |<-- Deferred call to process request | - * | | - * If extra byte is received, move state to overrun | - * STATE = USART_HOST_CMD_RX_OVERRUN | - * Ignore data processing, print status on console and reset layer ----------- - * | | - * -->| |<-- USART_DEFERRED_PROCESS_REQ_TIMEOUT | - * | Start process request | - * | | - * STATE = USART_HOST_CMD_PROCESSING | - * | | - * Send ec_host_request to host command task | - * |<-- Packet sent to host command task | - * >| |<-- host command task process time | - * |<-- host command task ready for response | - * | | - * STATE = USART_HOST_CMD_SENDING | - * | | - * |____RESPONSE____ | - * | | | | - * | HDR | DATA | | - * |_____|__________| | - * | | - * |<-- Response send complete | - * | - * STATE = USART_HOST_CMD_READY_TO_RX <------------------------------ - */ - -/* - * Local function definition - */ -static void usart_host_command_reset(void); -static void usart_host_command_request_timeout(void); -static void usart_host_command_process_request(void); -static void usart_host_command_process_response(struct host_packet *pkt); -/* - * Local variable declaration - */ - -/* - * Configure dma instance for rx - * - * STM32_DMAS_USART1_RX is the DMA channel to be used for reception. This DMA - * channel is for the USART peripheral. - * - * A unnamed, valid, empty usart_rx_dma_state structure is required to manage - * DMA based transmission. - * - * USART_DMA_FIFO_SIZE is size of the valid, unnamed DMA circular buffer. - * This buffer is large enough to process worst case interrupt latency this - * layer can encounter. - */ -static struct usart_rx_dma const usart_host_command_rx_dma = { - .usart_rx = { - .producer_ops = { - .read = NULL, - }, - .init = usart_rx_dma_init, - .interrupt = usart_host_command_rx_dma_interrupt, - .info = USART_RX_DMA_INFO, - }, - .state = &((struct usart_rx_dma_state) {}), - .fifo_buffer = ((uint8_t[USART_DMA_FIFO_SIZE]) {}), - .fifo_size = USART_DMA_FIFO_SIZE, - .channel = STM32_DMAS_USART1_RX, -}; - -/* - * Configure USART structure with hardware, interrupt handlers, baudrate. - */ -static struct usart_config const tl_usart = { - .hw = &CONFIG_UART_HOST_COMMAND_HW, - .rx = &usart_host_command_rx_dma.usart_rx, - .tx = &usart_host_command_tx_interrupt, - .state = &((struct usart_state){}), - .baud = CONFIG_UART_HOST_COMMAND_BAUD_RATE, - .flags = 0, -}; - -/* - * Local function declaration - */ - -/* - * This function will be called only if request rx timed out. - * Drop the packet and put tl state into RX_READY - */ -static void usart_host_command_request_timeout(void) -{ - switch (current_state) { - case USART_HOST_CMD_RECEIVING: - /* If state is receiving then timeout was hit due to underrun */ - CPRINTS("USART HOST CMD ERROR: Request underrun detected."); - break; - - case USART_HOST_CMD_RX_OVERRUN: - /* If state is rx_overrun then timeout was hit because - * process request was cancelled and extra rx bytes were - * dropped - */ - CPRINTS("USART HOST CMD ERROR: Request overrun detected."); - break; - - case USART_HOST_CMD_RX_BAD: - /* If state is rx_bad then packet header was bad and process - * request was cancelled to drop all incoming bytes. - */ - CPRINTS("USART HOST CMD ERROR: Bad packet header detected."); - break; - - default: - CPRINTS("USART HOST CMD ERROR: Request timeout mishandled"); - } - - /* Reset host command layer to accept new request */ - usart_host_command_reset(); -} -DECLARE_DEFERRED(usart_host_command_request_timeout); - -/* - * This function is called from interrupt handler after entire packet is - * received. - */ -static void usart_host_command_process_request(void) -{ - /* Handle usart_in_buffer as ec_host_request */ - struct ec_host_request *ec_request = - (struct ec_host_request *)usart_in_buffer; - - /* Prepare host_packet for host command task */ - static struct host_packet uart_packet; - - /* - * Disable interrupts before processing request to be sent - * to host command task. - */ - interrupt_disable(); - - /* - * In case rx interrupt handler was called in this function's prologue, - * host was trying to send extra byte(s) exactly when - * USART_DEFERRED_PROCESS_REQ_TIMEOUT expired. If state is - * not USART_HOST_CMD_COMPLETE, overrun condition is already - * handled. - */ - if (current_state != USART_HOST_CMD_COMPLETE) { - /* Enable interrupts before exiting this function. */ - interrupt_enable(); - - return; - } - - /* Move current_state to USART_HOST_CMD_PROCESSING */ - current_state = USART_HOST_CMD_PROCESSING; - - /* Enable interrupts as current_state is safely handled. */ - interrupt_enable(); - - /* - * Cancel deferred call to timeout handler as request - * received was good. - */ - hook_call_deferred( - &usart_host_command_request_timeout_data, - -1); - - uart_packet.send_response = usart_host_command_process_response; - uart_packet.request = usart_in_buffer; - uart_packet.request_temp = NULL; - uart_packet.request_max = sizeof(usart_in_buffer); - uart_packet.request_size = - host_request_expected_size(ec_request); - uart_packet.response = usart_out_buffer; - uart_packet.response_max = sizeof(usart_out_buffer); - uart_packet.response_size = 0; - uart_packet.driver_result = EC_RES_SUCCESS; - - /* Process usart_packet */ - host_packet_receive(&uart_packet); -} -DECLARE_DEFERRED(usart_host_command_process_request); - -/* - * This function is called from host command task after it is ready with a - * response. - */ -static void usart_host_command_process_response(struct host_packet *pkt) -{ - /* Disable interrupts before entering critical section. */ - interrupt_disable(); - - /* - * Send host command response in usart_out_buffer via - * tx_interrupt_handler. - * - * Send response if current state is USART_HOST_CMD_PROCESSING - * state. If this layer is in any other state drop response and - * let request timeout handler handle state transitions. - */ - if (current_state != USART_HOST_CMD_PROCESSING) { - /* Enable interrupts before exiting critical section. */ - interrupt_enable(); - - return; - } - - /* Move to sending state. */ - current_state = USART_HOST_CMD_SENDING; - - /* Enable interrupts before exiting critical section. */ - interrupt_enable(); - - usart_out_datalen = pkt->response_size; - usart_out_head = 0; - - /* Start sending response to host via usart tx by - * triggering tx interrupt. - */ - usart_tx_start(&tl_usart); -} - -/* - * This function will drop current request, clear buffers. - */ -static void usart_host_command_reset(void) -{ - /* Cancel deferred call to process_request. */ - hook_call_deferred( - &usart_host_command_process_request_data, - -1); - - /* Cancel deferred call to timeout handler. */ - hook_call_deferred( - &usart_host_command_request_timeout_data, - -1); - - /* - * Disable interrupts before entering critical region - * Operations in this section should be minimum to avoid - * harming the real-time characteristics of the runtime. - */ - interrupt_disable(); - - /* Clear in buffer, head and datalen */ - usart_in_head = 0; - - /* Clear out buffer, head and datalen */ - usart_out_datalen = 0; - usart_out_head = 0; - - /* Move to ready state*/ - current_state = USART_HOST_CMD_READY_TO_RX; - - /* Enable interrupts before exiting critical region - */ - interrupt_enable(); -} - -/* - * Exported functions - */ - -/* - * Initialize USART host command layer. - */ -void usart_host_command_init(void) -{ - /* USART host command layer starts in DISABLED state */ - current_state = USART_HOST_CMD_STATE_DISABLED; - - /* Initialize transport uart */ - usart_init(&tl_usart); - - /* Initialize local variables */ - usart_in_head = 0; - usart_out_head = 0; - usart_out_datalen = 0; - - /* Move to ready state */ - current_state = USART_HOST_CMD_READY_TO_RX; -} - -/* - * Function to handle incoming bytes from DMA interrupt handler - * - */ -size_t usart_host_command_rx_append_data(struct usart_config const *config, - const uint8_t *src, size_t count) -{ - /* Define ec_host_request pointer to process in bytes later*/ - struct ec_host_request *ec_request = - (struct ec_host_request *) usart_in_buffer; - - /* Once the header is received, store the datalen */ - static int usart_in_datalen; - - /* - * Host can send extra bytes than in header data_len - * Only copy valid bytes in buffer - */ - if (current_state == USART_HOST_CMD_READY_TO_RX || - current_state == USART_HOST_CMD_RECEIVING || - (usart_in_head + count) < USART_MAX_REQUEST_SIZE) { - /* Copy all the bytes from DMA FIFO */ - memcpy(usart_in_buffer + usart_in_head, - src, count); - } - - /* - * Add incoming byte count to usart_in_head. - * Even if overflow bytes are not copied in buffer, maintain - * the overflow count so that packet can be dropped later in this - * function. - */ - usart_in_head += count; - - if (current_state == USART_HOST_CMD_READY_TO_RX) { - /* Kick deferred call to request timeout handler */ - hook_call_deferred(&usart_host_command_request_timeout_data, - USART_REQ_RX_TIMEOUT); - - /* Move current state to receiving */ - current_state = USART_HOST_CMD_RECEIVING; - } - - if (usart_in_head >= sizeof(struct ec_host_request)) { - /* Buffer has request header. Check header and get data_len */ - usart_in_datalen = host_request_expected_size(ec_request); - - if (usart_in_datalen == 0 || - usart_in_datalen > USART_MAX_REQUEST_SIZE) { - /* EC host request version not compatible or - * reserved byte is not zero. - */ - current_state = USART_HOST_CMD_RX_BAD; - } else if (usart_in_head == usart_in_datalen) { - /* - * Once all the datalen bytes are received, wait for - * USART_DEFERRED_PROCESS_REQ_TIMEOUT to call - * process_request function. This is to catch overrun - * bytes before processing the packet. - */ - hook_call_deferred( - &usart_host_command_process_request_data, - USART_DEFERRED_PROCESS_REQ_TIMEOUT); - - /* If no data in request, packet is complete */ - current_state = USART_HOST_CMD_COMPLETE; - } else if (usart_in_head > usart_in_datalen) { - /* Cancel deferred call to process_request */ - hook_call_deferred( - &usart_host_command_process_request_data, - -1); - - /* Move state to overrun*/ - current_state = USART_HOST_CMD_RX_OVERRUN; - } - } - - if (current_state == USART_HOST_CMD_PROCESSING) - /* Host should not send data before receiving a response. - * Since the request was already sent to host command task, - * just notify console about this. After response is sent - * dma will be cleared to handle next packet - */ - CPRINTS("USART HOST CMD ERROR: Contiguous packets detected."); - - /* Return count to show all incoming bytes were processed */ - return count; -} - -/* - * This function processes the outgoing bytes from tl usart. - */ -size_t usart_host_command_tx_remove_data(struct usart_config const *config, - uint8_t *dest) -{ - size_t bytes_remaining = 0; - - if (current_state == USART_HOST_CMD_SENDING && - usart_out_datalen != 0) { - /* Calculate byte_remaining in out_buffer */ - bytes_remaining = usart_out_datalen - usart_out_head; - - /* Get char on the head */ - *((uint8_t *) dest) = usart_out_buffer[usart_out_head++]; - - /* If no bytes remaining, reset layer to accept next - * request. - */ - if (bytes_remaining == 0) - usart_host_command_reset(); - } - - /* Return count of bytes remaining in out buffer */ - return bytes_remaining; -} - -/* - * Get protocol information - */ -enum ec_status usart_get_protocol_info(struct host_cmd_handler_args *args) -{ - struct ec_response_get_protocol_info *r = args->response; - - memset(r, 0, sizeof(*r)); - r->protocol_versions |= BIT(3); - r->max_request_packet_size = USART_MAX_REQUEST_SIZE; - r->max_response_packet_size = USART_MAX_RESPONSE_SIZE; - r->flags = EC_PROTOCOL_INFO_IN_PROGRESS_SUPPORTED; - args->response_size = sizeof(*r); - - return EC_RES_SUCCESS; -} |