From 828272767d067cc215ff6c7dc93bd731a1a61765 Mon Sep 17 00:00:00 2001 From: Aaron Durbin Date: Wed, 6 Aug 2014 14:34:57 -0500 Subject: [PATCH] chromeec: allow transport implementation to provide buffers for proto v3 Depending on the transport mechanism for proto v3 different bytes need to be send and/or read before the request and response. Depending on the software and/or controller interface that requirement leads to needing to copy data into temporary buffers. Avoid this by allowing the transport mechanism to provide the request and response buffers. BUG=chrome-os-partner:31148 BRANCH=None TEST=Built for rush and ryu. Ran on ryu with i2c implementation. Also built for rambi to check x86 systems. Change-Id: I35d4d69bd1fa900fc0cfe3822496f381405bdcb1 Signed-off-by: Patrick Georgi Original-Commit-Id: c7224426e1d0bcf06ed010131a2462a6ca201d8b Original-Change-Id: Iad6cce566a253ca72e6f5009a97235ece0a6c1b5 Original-Signed-off-by: Aaron Durbin Original-Reviewed-on: https://chromium-review.googlesource.com/211138 Original-Reviewed-by: Furquan Shaikh Reviewed-on: http://review.coreboot.org/8827 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/ec/google/chromeec/crosec_proto.c | 23 ++++++++++++++++------- src/ec/google/chromeec/ec.h | 21 +++++++++++++++++---- src/ec/google/chromeec/ec_spi.c | 27 ++++++++++++++++++++++----- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/src/ec/google/chromeec/crosec_proto.c b/src/ec/google/chromeec/crosec_proto.c index 42c7c2e35d..55a707db17 100644 --- a/src/ec/google/chromeec/crosec_proto.c +++ b/src/ec/google/chromeec/crosec_proto.c @@ -27,6 +27,11 @@ #include "ec_message.h" /* Common utilities */ +void * __attribute__((weak)) crosec_get_buffer(size_t size, int req) +{ + printk(BIOS_DEBUG, "crosec_get_buffer() implementation required.\n"); + return NULL; +} /* Dumps EC command / response data into debug output. * @@ -208,23 +213,27 @@ static int send_command_proto3(struct chromeec_command *cec_command, { int out_bytes, in_bytes; int rv; - struct ec_command_v3 cmd = { {0}, }; - struct ec_response_v3 resp = { {0}, }; + struct ec_command_v3 *cmd; + struct ec_response_v3 *resp; + + if ((cmd = crosec_get_buffer(sizeof(*cmd), 1)) == NULL) + return -EC_RES_ERROR; + if ((resp = crosec_get_buffer(sizeof(*resp), 0)) == NULL) + return -EC_RES_ERROR; /* Create request packet */ - out_bytes = create_proto3_request(cec_command, &cmd); + out_bytes = create_proto3_request(cec_command, cmd); if (out_bytes < 0) { return out_bytes; } /* Prepare response buffer */ - in_bytes = prepare_proto3_response_buffer(cec_command, &resp); + in_bytes = prepare_proto3_response_buffer(cec_command, resp); if (in_bytes < 0) { return in_bytes; } - rv = crosec_io((uint8_t *)&cmd, out_bytes, (uint8_t *)&resp, in_bytes, - context); + rv = crosec_io(out_bytes, in_bytes, context); if (rv != 0) { printk(BIOS_ERR, "%s: failed to complete I/O: Err = %#x.", __func__, rv >= 0 ? rv : -rv); @@ -232,7 +241,7 @@ static int send_command_proto3(struct chromeec_command *cec_command, } /* Process the response */ - return handle_proto3_response(&resp, cec_command); + return handle_proto3_response(resp, cec_command); } static int crosec_command_proto_v3(struct chromeec_command *cec_command, diff --git a/src/ec/google/chromeec/ec.h b/src/ec/google/chromeec/ec.h index a1c59b8dc5..e0db8c17ee 100644 --- a/src/ec/google/chromeec/ec.h +++ b/src/ec/google/chromeec/ec.h @@ -69,10 +69,23 @@ struct chromeec_command { * actual received size out */ }; -/* internal standard implementation for EC command protocols. */ -typedef int (*crosec_io_t)(uint8_t *write_bytes, size_t write_size, - uint8_t *read_bytes, size_t read_size, - void *context); +/* + * There are transport level constraints for sending protov3 packets. Because + * of this provide a way for the generic protocol layer to request buffers + * so that there is zero copying being done through the layers. + * + * Request the buffer provided the size. If 'req' is non-zero then the + * buffer requested is for EC requests. Otherwise it's for responses. Return + * non-NULL on success, NULL on error. + */ +void *crosec_get_buffer(size_t size, int req); + +/* + * The lower level transport works on the buffers handed out to the + * upper level. Therefore, only the size of the request and response + * are required. + */ +typedef int (*crosec_io_t)(size_t req_size, size_t resp_size, void *context); int crosec_command_proto(struct chromeec_command *cec_command, crosec_io_t crosec_io, void *context); diff --git a/src/ec/google/chromeec/ec_spi.c b/src/ec/google/chromeec/ec_spi.c index f1bdd3caaa..6107836153 100644 --- a/src/ec/google/chromeec/ec_spi.c +++ b/src/ec/google/chromeec/ec_spi.c @@ -25,15 +25,32 @@ static const uint8_t EcFramingByte = 0xec; -static int crosec_spi_io(uint8_t *write_bytes, size_t write_size, - uint8_t *read_bytes, size_t read_size, - void *context) +#define PROTO3_MAX_PACKET_SIZE 268 + +static uint8_t req_buf[PROTO3_MAX_PACKET_SIZE]; +static uint8_t resp_buf[PROTO3_MAX_PACKET_SIZE]; + +void *crosec_get_buffer(size_t size, int req) +{ + if (size > PROTO3_MAX_PACKET_SIZE) { + printk(BIOS_DEBUG, "Proto v3 buffer request too large: %zu!\n", + size); + return NULL; + } + + if (req) + return req_buf; + else + return resp_buf; +} + +static int crosec_spi_io(size_t req_size, size_t resp_size, void *context) { struct spi_slave *slave = (struct spi_slave *)context; spi_claim_bus(slave); - if (spi_xfer(slave, write_bytes, write_size, NULL, 0)) { + if (spi_xfer(slave, req_buf, req_size, NULL, 0)) { printk(BIOS_ERR, "%s: Failed to send request.\n", __func__); spi_release_bus(slave); return -1; @@ -64,7 +81,7 @@ static int crosec_spi_io(uint8_t *write_bytes, size_t write_size, } } - if (spi_xfer(slave, NULL, 0, read_bytes, read_size)) { + if (spi_xfer(slave, NULL, 0, resp_buf, resp_size)) { printk(BIOS_ERR, "%s: Failed to receive response.\n", __func__); spi_release_bus(slave); return -1;