diff options
author | Javier Martinez Canillas <javier.martinez@collabora.co.uk> | 2015-06-09 11:04:42 (GMT) |
---|---|---|
committer | Lee Jones <lee.jones@linaro.org> | 2015-06-15 12:18:19 (GMT) |
commit | a841178445bb72a3d566b4e6ab9d19e9b002eb47 (patch) | |
tree | bdc857e82c9c9e8b49bd5471efa5a954673d58f0 /drivers/mfd/cros_ec.c | |
parent | bb03ffb96c72418d06e75c7b74ea62e04c78d322 (diff) | |
download | linux-a841178445bb72a3d566b4e6ab9d19e9b002eb47.tar.xz |
mfd: cros_ec: Use a zero-length array for command data
Commit 1b84f2a4cd4a ("mfd: cros_ec: Use fixed size arrays to transfer
data with the EC") modified the struct cros_ec_command fields to not
use pointers for the input and output buffers and use fixed length
arrays instead.
This change was made because the cros_ec ioctl API uses that struct
cros_ec_command to allow user-space to send commands to the EC and
to get data from the EC. So using pointers made the API not 64-bit
safe. Unfortunately this approach was not flexible enough for all
the use-cases since there may be a need to send larger commands
on newer versions of the EC command protocol.
So to avoid to choose a constant length that it may be too big for
most commands and thus wasting memory and CPU cycles on copy from
and to user-space or having a size that is too small for some big
commands, use a zero-length array that is both 64-bit safe and
flexible. The same buffer is used for both output and input data
so the maximum of these values should be used to allocate it.
Suggested-by: Gwendal Grignou <gwendal@chromium.org>
Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Acked-by: Lee Jones <lee.jones@linaro.org>
Acked-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/mfd/cros_ec.c')
-rw-r--r-- | drivers/mfd/cros_ec.c | 28 |
1 files changed, 20 insertions, 8 deletions
diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index 1574a93..4a0f6df 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -41,7 +41,7 @@ int cros_ec_prepare_tx(struct cros_ec_device *ec_dev, out[2] = msg->outsize; csum = out[0] + out[1] + out[2]; for (i = 0; i < msg->outsize; i++) - csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->outdata[i]; + csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->data[i]; out[EC_MSG_TX_HEADER_BYTES + msg->outsize] = (uint8_t)(csum & 0xff); return EC_MSG_TX_PROTO_BYTES + msg->outsize; @@ -75,11 +75,20 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, ret = ec_dev->cmd_xfer(ec_dev, msg); if (msg->result == EC_RES_IN_PROGRESS) { int i; - struct cros_ec_command status_msg = { }; + struct cros_ec_command *status_msg; struct ec_response_get_comms_status *status; - status_msg.command = EC_CMD_GET_COMMS_STATUS; - status_msg.insize = sizeof(*status); + status_msg = kmalloc(sizeof(*status_msg) + sizeof(*status), + GFP_KERNEL); + if (!status_msg) { + ret = -ENOMEM; + goto exit; + } + + status_msg->version = 0; + status_msg->command = EC_CMD_GET_COMMS_STATUS; + status_msg->insize = sizeof(*status); + status_msg->outsize = 0; /* * Query the EC's status until it's no longer busy or @@ -88,20 +97,23 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, for (i = 0; i < EC_COMMAND_RETRIES; i++) { usleep_range(10000, 11000); - ret = ec_dev->cmd_xfer(ec_dev, &status_msg); + ret = ec_dev->cmd_xfer(ec_dev, status_msg); if (ret < 0) break; - msg->result = status_msg.result; - if (status_msg.result != EC_RES_SUCCESS) + msg->result = status_msg->result; + if (status_msg->result != EC_RES_SUCCESS) break; status = (struct ec_response_get_comms_status *) - status_msg.indata; + status_msg->data; if (!(status->flags & EC_COMMS_STATUS_PROCESSING)) break; } + + kfree(status_msg); } +exit: mutex_unlock(&ec_dev->lock); return ret; |