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 <pgeorgi@chromium.org> Original-Commit-Id: c7224426e1d0bcf06ed010131a2462a6ca201d8b Original-Change-Id: Iad6cce566a253ca72e6f5009a97235ece0a6c1b5 Original-Signed-off-by: Aaron Durbin <adurbin@chromium.org> Original-Reviewed-on: https://chromium-review.googlesource.com/211138 Original-Reviewed-by: Furquan Shaikh <furquan@chromium.org> Reviewed-on: http://review.coreboot.org/8827 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
parent
3e49738baa
commit
828272767d
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue