mirror of
https://review.coreboot.org/flashrom.git
synced 2025-04-27 15:12:36 +02:00
raiden_debug_spi.c: Add USB context states and helper functions
Add context states to handle the USB packets, these allow us to simplify the process of loading data from the transmit buffer into a USB packets' data section and from a USB packet to it's receive buffers. These will also keep track of the size of the USB packet allowing a simpler interface to transmit them. Helper functions have been added to help with copying data between the transmit and receive context states to and from the USB packets. BUG=b:139058552 BRANCH=none TEST=Manual testing of ServoMicro and Flashrom when performing reads, writes, and verification of the EC firmware on Nami. TEST=Builds Signed-off-by: Brian J. Nemec <bnemec@chromium.com> Change-Id: Id7b598b39923b4b8c1b6905e5d5c5a2be4078f96 Reviewed-on: https://review.coreboot.org/c/flashrom/+/43550 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Angel Pons <th3fanbus@gmail.com> Reviewed-by: Edward O'Callaghan <quasisec@chromium.org>
This commit is contained in:
parent
ce80d18973
commit
7ac57c77be
@ -145,6 +145,25 @@ enum {
|
||||
GOOGLE_RAIDEN_SPI_PROTOCOL_V2 = 0x02,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* The host failed to transfer the data with no libusb error. */
|
||||
USB_SPI_HOST_TX_BAD_TRANSFER = 0x10001,
|
||||
/* The number of bytes written did not match expected. */
|
||||
USB_SPI_HOST_TX_WRITE_FAILURE = 0x10002,
|
||||
|
||||
/* We did not receive the expected USB packet. */
|
||||
USB_SPI_HOST_RX_UNEXPECTED_PACKET = 0x11001,
|
||||
/* We received a continue packet with an invalid data index. */
|
||||
USB_SPI_HOST_RX_BAD_DATA_INDEX = 0x11002,
|
||||
/* We received too much data. */
|
||||
USB_SPI_HOST_RX_DATA_OVERFLOW = 0x11003,
|
||||
/* The number of bytes read did not match expected. */
|
||||
USB_SPI_HOST_RX_READ_FAILURE = 0x11004,
|
||||
|
||||
/* We were unable to configure the device. */
|
||||
USB_SPI_HOST_INIT_FAILURE = 0x12001,
|
||||
};
|
||||
|
||||
enum usb_spi_error {
|
||||
USB_SPI_SUCCESS = 0x0000,
|
||||
USB_SPI_TIMEOUT = 0x0001,
|
||||
@ -172,9 +191,9 @@ enum raiden_debug_spi_request {
|
||||
* See crbug.com/952494. Retry mechanisms have been implemented to recover
|
||||
* from these rare failures allowing the process to continue.
|
||||
*/
|
||||
#define WRITE_RETRY_ATTEMPTS (3)
|
||||
#define READ_RETRY_ATTEMPTS (3)
|
||||
#define RETRY_INTERVAL_US (100 * 1000)
|
||||
#define WRITE_RETRY_ATTEMPTS (3)
|
||||
#define READ_RETRY_ATTEMPTS (3)
|
||||
#define RETRY_INTERVAL_US (100 * 1000)
|
||||
|
||||
/*
|
||||
* This timeout is so large because the Raiden SPI timeout is 800ms.
|
||||
@ -203,6 +222,27 @@ struct usb_spi_response_v1 {
|
||||
uint8_t data[PAYLOAD_SIZE_V1];
|
||||
} __attribute__((packed));
|
||||
|
||||
union usb_spi_packet_v1 {
|
||||
struct usb_spi_command_v1 command;
|
||||
struct usb_spi_response_v1 response;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct usb_spi_packet_ctx {
|
||||
union {
|
||||
uint8_t bytes[USB_MAX_PACKET_SIZE];
|
||||
union usb_spi_packet_v1 packet_v1;
|
||||
};
|
||||
/*
|
||||
* By storing the number of bytes in the header and knowing that the
|
||||
* USB data packets are all 64B long, we are able to use the header
|
||||
* size to store the offset of the buffer and it's size without
|
||||
* duplicating variables that can go out of sync.
|
||||
*/
|
||||
size_t header_size;
|
||||
/* Number of bytes in the packet */
|
||||
size_t packet_size;
|
||||
};
|
||||
|
||||
struct usb_spi_transmit_ctx {
|
||||
/* Buffer we are reading data from. */
|
||||
const uint8_t *buffer;
|
||||
@ -255,53 +295,150 @@ static const struct raiden_debug_spi_data *
|
||||
}
|
||||
|
||||
/*
|
||||
* Version 1 Protocol: Responsible for constructing the packet to start
|
||||
* a USB SPI transfer. Write and read counts and payloads to write from
|
||||
* the write_buffer are transmitted to the device.
|
||||
* Read data into the receive buffer.
|
||||
*
|
||||
* @param flash Flash context storing SPI capabilities and USB device
|
||||
* information.
|
||||
* @param dst Destination receive context we are writing data to.
|
||||
* @param src Source packet context we are reading data from.
|
||||
*
|
||||
* @returns status code 0 on success.
|
||||
* USB_SPI_HOST_RX_DATA_OVERFLOW if the source packet is too
|
||||
* large to fit in read buffer.
|
||||
*/
|
||||
static int read_usb_packet(struct usb_spi_receive_ctx *dst,
|
||||
const struct usb_spi_packet_ctx *src)
|
||||
{
|
||||
size_t max_read_length = dst->receive_size - dst->receive_index;
|
||||
size_t bytes_in_buffer = src->packet_size - src->header_size;
|
||||
const uint8_t *packet_buffer = src->bytes + src->header_size;
|
||||
|
||||
if (bytes_in_buffer > max_read_length) {
|
||||
/*
|
||||
* An error occurred, we should not receive more data than
|
||||
* the buffer can support.
|
||||
*/
|
||||
msg_perr("Raiden: Receive packet overflowed\n"
|
||||
" bytes_in_buffer = %zu\n"
|
||||
" max_read_length = %zu\n"
|
||||
" receive_index = %zu\n"
|
||||
" receive_size = %zu\n",
|
||||
bytes_in_buffer, max_read_length,
|
||||
dst->receive_size, dst->receive_index);
|
||||
return USB_SPI_HOST_RX_DATA_OVERFLOW;
|
||||
}
|
||||
memcpy(dst->buffer + dst->receive_index, packet_buffer,
|
||||
bytes_in_buffer);
|
||||
|
||||
dst->receive_index += bytes_in_buffer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill the USB packet with data from the transmit buffer.
|
||||
*
|
||||
* @param dst Destination packet context we are writing data to.
|
||||
* @param src Source transmit context we are reading data from.
|
||||
*/
|
||||
static void fill_usb_packet(struct usb_spi_packet_ctx *dst,
|
||||
struct usb_spi_transmit_ctx *src)
|
||||
{
|
||||
size_t transmit_size = src->transmit_size - src->transmit_index;
|
||||
size_t max_buffer_size = USB_MAX_PACKET_SIZE - dst->header_size;
|
||||
uint8_t *packet_buffer = dst->bytes + dst->header_size;
|
||||
|
||||
if (transmit_size > max_buffer_size)
|
||||
transmit_size = max_buffer_size;
|
||||
|
||||
memcpy(packet_buffer, src->buffer + src->transmit_index, transmit_size);
|
||||
|
||||
dst->packet_size = dst->header_size + transmit_size;
|
||||
src->transmit_index += transmit_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive the data from the device USB endpoint and store in the packet.
|
||||
*
|
||||
* @param ctx_data Raiden SPI config.
|
||||
* @param packet Destination packet used to store the endpoint data.
|
||||
*
|
||||
* @returns Returns status code with 0 on success.
|
||||
*/
|
||||
static int receive_packet(const struct raiden_debug_spi_data *ctx_data,
|
||||
struct usb_spi_packet_ctx *packet)
|
||||
{
|
||||
int received;
|
||||
int status = LIBUSB(libusb_bulk_transfer(ctx_data->dev->handle,
|
||||
ctx_data->in_ep,
|
||||
packet->bytes,
|
||||
USB_MAX_PACKET_SIZE,
|
||||
&received,
|
||||
TRANSFER_TIMEOUT_MS));
|
||||
packet->packet_size = received;
|
||||
if (status) {
|
||||
msg_perr("Raiden: IN transfer failed\n"
|
||||
" received = %d\n"
|
||||
" status = 0x%05x\n",
|
||||
received, status);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transmit data from the packet to the device's USB endpoint.
|
||||
*
|
||||
* @param ctx_data Raiden SPI config.
|
||||
* @param packet Source packet we will write to the endpoint data.
|
||||
*
|
||||
* @returns Returns status code with 0 on success.
|
||||
*/
|
||||
static int transmit_packet(const struct raiden_debug_spi_data *ctx_data,
|
||||
struct usb_spi_packet_ctx *packet)
|
||||
{
|
||||
int transferred;
|
||||
int status = LIBUSB(libusb_bulk_transfer(ctx_data->dev->handle,
|
||||
ctx_data->out_ep,
|
||||
packet->bytes,
|
||||
packet->packet_size,
|
||||
&transferred,
|
||||
TRANSFER_TIMEOUT_MS));
|
||||
if (status || (size_t)transferred != packet->packet_size) {
|
||||
if (!status) {
|
||||
/* No error was reported, but we didn't transmit the data expected. */
|
||||
status = USB_SPI_HOST_TX_BAD_TRANSFER;
|
||||
}
|
||||
msg_perr("Raiden: OUT transfer failed\n"
|
||||
" transferred = %d\n"
|
||||
" packet_size = %zu\n"
|
||||
" status = 0x%05x\n",
|
||||
transferred, packet->packet_size, status);
|
||||
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Version 1 protocol command to start a USB SPI transfer and write the payload.
|
||||
*
|
||||
* @param ctx_data Raiden SPI config.
|
||||
* @param write Write context of data to transmit and write payload.
|
||||
* @param read Read context of data to receive and read buffer.
|
||||
*
|
||||
* @returns Returns status code with 0 on success.
|
||||
*/
|
||||
static int write_command_v1(const struct flashctx *flash,
|
||||
static int write_command_v1(const struct raiden_debug_spi_data *ctx_data,
|
||||
struct usb_spi_transmit_ctx *write,
|
||||
struct usb_spi_receive_ctx *read)
|
||||
{
|
||||
struct usb_spi_packet_ctx command = {
|
||||
.header_size = offsetof(struct usb_spi_command_v1, data),
|
||||
.packet_v1.command.write_count = write->transmit_size,
|
||||
.packet_v1.command.read_count = read->receive_size
|
||||
};
|
||||
|
||||
int transferred;
|
||||
int ret;
|
||||
struct usb_spi_command_v1 command_packet;
|
||||
const struct raiden_debug_spi_data * ctx_data = get_raiden_data_from_context(flash);
|
||||
/* Reset the write context to the start. */
|
||||
write->transmit_index = 0;
|
||||
|
||||
command_packet.write_count = write->transmit_size;
|
||||
command_packet.read_count = read->receive_size;
|
||||
|
||||
memcpy(command_packet.data, write->buffer, write->transmit_size);
|
||||
|
||||
ret = LIBUSB(libusb_bulk_transfer(ctx_data->dev->handle,
|
||||
ctx_data->out_ep,
|
||||
(void*)&command_packet,
|
||||
write->transmit_size + PACKET_HEADER_SIZE,
|
||||
&transferred,
|
||||
TRANSFER_TIMEOUT_MS));
|
||||
if (ret != 0) {
|
||||
msg_perr("Raiden: OUT transfer failed\n"
|
||||
" write_count = %zu\n"
|
||||
" read_count = %zu\n",
|
||||
write->transmit_size, read->receive_size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((unsigned) transferred != write->transmit_size + PACKET_HEADER_SIZE) {
|
||||
msg_perr("Raiden: Write failure (wrote %d, expected %zu)\n",
|
||||
transferred, write->transmit_size + PACKET_HEADER_SIZE);
|
||||
return 0x10001;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fill_usb_packet(&command, write);
|
||||
return transmit_packet(ctx_data, &command);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -309,45 +446,34 @@ static int write_command_v1(const struct flashctx *flash,
|
||||
* transfer. Status codes from the transfer and any read payload are copied
|
||||
* to the read_buffer.
|
||||
*
|
||||
* @param flash Flash context storing SPI capabilities and USB device
|
||||
* information.
|
||||
* @param ctx_data Raiden SPI config.
|
||||
* @param write Write context of data to transmit and write payload.
|
||||
* @param read Read context of data to receive and read buffer.
|
||||
*
|
||||
* @returns Returns status code with 0 on success.
|
||||
*/
|
||||
static int read_response_v1(const struct flashctx *flash,
|
||||
static int read_response_v1(const struct raiden_debug_spi_data *ctx_data,
|
||||
struct usb_spi_transmit_ctx *write,
|
||||
struct usb_spi_receive_ctx *read)
|
||||
{
|
||||
int transferred;
|
||||
int ret;
|
||||
struct usb_spi_response_v1 response_packet;
|
||||
const struct raiden_debug_spi_data * ctx_data = get_raiden_data_from_context(flash);
|
||||
int status;
|
||||
struct usb_spi_packet_ctx response;
|
||||
|
||||
ret = LIBUSB(libusb_bulk_transfer(ctx_data->dev->handle,
|
||||
ctx_data->in_ep,
|
||||
(void*)&response_packet,
|
||||
read->receive_size + PACKET_HEADER_SIZE,
|
||||
&transferred,
|
||||
TRANSFER_TIMEOUT_MS));
|
||||
if (ret != 0) {
|
||||
msg_perr("Raiden: IN transfer failed\n"
|
||||
" write_count = %zu\n"
|
||||
" read_count = %zu\n",
|
||||
write->transmit_size, read->receive_size);
|
||||
return ret;
|
||||
/* Reset the read context to the start. */
|
||||
read->receive_index = 0;
|
||||
|
||||
status = receive_packet(ctx_data, &response);
|
||||
if (status) {
|
||||
/* Return the transfer error since the status_code is unreliable */
|
||||
return status;
|
||||
}
|
||||
|
||||
if ((unsigned) transferred != read->receive_size + PACKET_HEADER_SIZE) {
|
||||
msg_perr("Raiden: Read failure (read %d, expected %zu)\n",
|
||||
transferred, read->receive_size + PACKET_HEADER_SIZE);
|
||||
return 0x10002;
|
||||
if (response.packet_v1.response.status_code) {
|
||||
return response.packet_v1.response.status_code;
|
||||
}
|
||||
response.header_size = offsetof(struct usb_spi_response_v1, data);
|
||||
|
||||
memcpy(read->buffer, response_packet.data, read->receive_size);
|
||||
|
||||
return response_packet.status_code;
|
||||
status = read_usb_packet(read, &response);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -380,6 +506,7 @@ static int send_command_v1(const struct flashctx *flash,
|
||||
.buffer = read_buffer,
|
||||
.receive_size = read_count
|
||||
};
|
||||
const struct raiden_debug_spi_data *ctx_data = get_raiden_data_from_context(flash);
|
||||
|
||||
if (write_count > PAYLOAD_SIZE_V1) {
|
||||
msg_perr("Raiden: Invalid write count\n"
|
||||
@ -401,7 +528,13 @@ static int send_command_v1(const struct flashctx *flash,
|
||||
write_attempt++) {
|
||||
|
||||
|
||||
status = write_command_v1(flash, &write_ctx, &read_ctx);
|
||||
status = write_command_v1(ctx_data, &write_ctx, &read_ctx);
|
||||
|
||||
if (!status &&
|
||||
(write_ctx.transmit_index != write_ctx.transmit_size)) {
|
||||
/* No errors were reported, but write is incomplete. */
|
||||
status = USB_SPI_HOST_TX_WRITE_FAILURE;
|
||||
}
|
||||
|
||||
if (status) {
|
||||
/* Write operation failed. */
|
||||
@ -424,7 +557,17 @@ static int send_command_v1(const struct flashctx *flash,
|
||||
for (unsigned int read_attempt = 0; read_attempt < READ_RETRY_ATTEMPTS;
|
||||
read_attempt++) {
|
||||
|
||||
status = read_response_v1(flash, &write_ctx, &read_ctx);
|
||||
status = read_response_v1(ctx_data, &write_ctx, &read_ctx);
|
||||
|
||||
if (!status) {
|
||||
if (read_ctx.receive_size == read_ctx.receive_index) {
|
||||
/* Successful transfer. */
|
||||
return status;
|
||||
} else {
|
||||
/* Report the error from the failed read. */
|
||||
status = USB_SPI_HOST_RX_READ_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (status) {
|
||||
/* Read operation failed. */
|
||||
@ -442,9 +585,6 @@ static int send_command_v1(const struct flashctx *flash,
|
||||
return status;
|
||||
}
|
||||
programmer_delay(RETRY_INTERVAL_US);
|
||||
} else {
|
||||
/* We were successful at performing the SPI transfer. */
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user