From a841178445bb72a3d566b4e6ab9d19e9b002eb47 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 9 Jun 2015 13:04:42 +0200 Subject: 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 Signed-off-by: Javier Martinez Canillas Tested-by: Heiko Stuebner Acked-by: Lee Jones Acked-by: Olof Johansson Signed-off-by: Lee Jones --- drivers/mfd/cros_ec.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'drivers/mfd/cros_ec.c') diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index 1574a9352a6d..4a0f6dfcd376 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; -- cgit