diff options
author | Javier Martinez Canillas <javier.martinez@collabora.co.uk> | 2015-06-09 07:04:42 -0400 |
---|---|---|
committer | Lee Jones <lee.jones@linaro.org> | 2015-06-15 08:18:19 -0400 |
commit | a841178445bb72a3d566b4e6ab9d19e9b002eb47 (patch) | |
tree | bdc857e82c9c9e8b49bd5471efa5a954673d58f0 /drivers/i2c | |
parent | bb03ffb96c72418d06e75c7b74ea62e04c78d322 (diff) |
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/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-cros-ec-tunnel.c | 45 |
1 files changed, 30 insertions, 15 deletions
diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c index fa8dedd8c3a2..a0d95ff682ae 100644 --- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c +++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c | |||
@@ -182,8 +182,9 @@ static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[], | |||
182 | const u16 bus_num = bus->remote_bus; | 182 | const u16 bus_num = bus->remote_bus; |
183 | int request_len; | 183 | int request_len; |
184 | int response_len; | 184 | int response_len; |
185 | int alloc_size; | ||
185 | int result; | 186 | int result; |
186 | struct cros_ec_command msg = { }; | 187 | struct cros_ec_command *msg; |
187 | 188 | ||
188 | request_len = ec_i2c_count_message(i2c_msgs, num); | 189 | request_len = ec_i2c_count_message(i2c_msgs, num); |
189 | if (request_len < 0) { | 190 | if (request_len < 0) { |
@@ -198,25 +199,39 @@ static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[], | |||
198 | return response_len; | 199 | return response_len; |
199 | } | 200 | } |
200 | 201 | ||
201 | result = ec_i2c_construct_message(msg.outdata, i2c_msgs, num, bus_num); | 202 | alloc_size = max(request_len, response_len); |
202 | if (result) | 203 | msg = kmalloc(sizeof(*msg) + alloc_size, GFP_KERNEL); |
203 | return result; | 204 | if (!msg) |
205 | return -ENOMEM; | ||
204 | 206 | ||
205 | msg.version = 0; | 207 | result = ec_i2c_construct_message(msg->data, i2c_msgs, num, bus_num); |
206 | msg.command = EC_CMD_I2C_PASSTHRU; | 208 | if (result) { |
207 | msg.outsize = request_len; | 209 | dev_err(dev, "Error constructing EC i2c message %d\n", result); |
208 | msg.insize = response_len; | 210 | goto exit; |
211 | } | ||
209 | 212 | ||
210 | result = cros_ec_cmd_xfer(bus->ec, &msg); | 213 | msg->version = 0; |
211 | if (result < 0) | 214 | msg->command = EC_CMD_I2C_PASSTHRU; |
212 | return result; | 215 | msg->outsize = request_len; |
216 | msg->insize = response_len; | ||
213 | 217 | ||
214 | result = ec_i2c_parse_response(msg.indata, i2c_msgs, &num); | 218 | result = cros_ec_cmd_xfer(bus->ec, msg); |
215 | if (result < 0) | 219 | if (result < 0) { |
216 | return result; | 220 | dev_err(dev, "Error transferring EC i2c message %d\n", result); |
221 | goto exit; | ||
222 | } | ||
223 | |||
224 | result = ec_i2c_parse_response(msg->data, i2c_msgs, &num); | ||
225 | if (result < 0) { | ||
226 | dev_err(dev, "Error parsing EC i2c message %d\n", result); | ||
227 | goto exit; | ||
228 | } | ||
217 | 229 | ||
218 | /* Indicate success by saying how many messages were sent */ | 230 | /* Indicate success by saying how many messages were sent */ |
219 | return num; | 231 | result = num; |
232 | exit: | ||
233 | kfree(msg); | ||
234 | return result; | ||
220 | } | 235 | } |
221 | 236 | ||
222 | static u32 ec_i2c_functionality(struct i2c_adapter *adap) | 237 | static u32 ec_i2c_functionality(struct i2c_adapter *adap) |