Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Javier Martinez Canillas and committed by
Lee Jones
a8411784 bb03ffb9

+318 -175
+30 -15
drivers/i2c/busses/i2c-cros-ec-tunnel.c
··· 182 182 const u16 bus_num = bus->remote_bus; 183 183 int request_len; 184 184 int response_len; 185 + int alloc_size; 185 186 int result; 186 - struct cros_ec_command msg = { }; 187 + struct cros_ec_command *msg; 187 188 188 189 request_len = ec_i2c_count_message(i2c_msgs, num); 189 190 if (request_len < 0) { ··· 199 198 return response_len; 200 199 } 201 200 202 - result = ec_i2c_construct_message(msg.outdata, i2c_msgs, num, bus_num); 203 - if (result) 204 - return result; 201 + alloc_size = max(request_len, response_len); 202 + msg = kmalloc(sizeof(*msg) + alloc_size, GFP_KERNEL); 203 + if (!msg) 204 + return -ENOMEM; 205 205 206 - msg.version = 0; 207 - msg.command = EC_CMD_I2C_PASSTHRU; 208 - msg.outsize = request_len; 209 - msg.insize = response_len; 206 + result = ec_i2c_construct_message(msg->data, i2c_msgs, num, bus_num); 207 + if (result) { 208 + dev_err(dev, "Error constructing EC i2c message %d\n", result); 209 + goto exit; 210 + } 210 211 211 - result = cros_ec_cmd_xfer(bus->ec, &msg); 212 - if (result < 0) 213 - return result; 212 + msg->version = 0; 213 + msg->command = EC_CMD_I2C_PASSTHRU; 214 + msg->outsize = request_len; 215 + msg->insize = response_len; 214 216 215 - result = ec_i2c_parse_response(msg.indata, i2c_msgs, &num); 216 - if (result < 0) 217 - return result; 217 + result = cros_ec_cmd_xfer(bus->ec, msg); 218 + if (result < 0) { 219 + dev_err(dev, "Error transferring EC i2c message %d\n", result); 220 + goto exit; 221 + } 222 + 223 + result = ec_i2c_parse_response(msg->data, i2c_msgs, &num); 224 + if (result < 0) { 225 + dev_err(dev, "Error parsing EC i2c message %d\n", result); 226 + goto exit; 227 + } 218 228 219 229 /* Indicate success by saying how many messages were sent */ 220 - return num; 230 + result = num; 231 + exit: 232 + kfree(msg); 233 + return result; 221 234 } 222 235 223 236 static u32 ec_i2c_functionality(struct i2c_adapter *adap)
+19 -10
drivers/input/keyboard/cros_ec_keyb.c
··· 148 148 149 149 static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state) 150 150 { 151 - int ret; 152 - struct cros_ec_command msg = { 153 - .command = EC_CMD_MKBP_STATE, 154 - .insize = ckdev->cols, 155 - }; 151 + int ret = 0; 152 + struct cros_ec_command *msg; 156 153 157 - ret = cros_ec_cmd_xfer(ckdev->ec, &msg); 158 - if (ret < 0) 159 - return ret; 154 + msg = kmalloc(sizeof(*msg) + ckdev->cols, GFP_KERNEL); 155 + if (!msg) 156 + return -ENOMEM; 160 157 161 - memcpy(kb_state, msg.indata, ckdev->cols); 158 + msg->version = 0; 159 + msg->command = EC_CMD_MKBP_STATE; 160 + msg->insize = ckdev->cols; 161 + msg->outsize = 0; 162 162 163 - return 0; 163 + ret = cros_ec_cmd_xfer(ckdev->ec, msg); 164 + if (ret < 0) { 165 + dev_err(ckdev->dev, "Error transferring EC message %d\n", ret); 166 + goto exit; 167 + } 168 + 169 + memcpy(kb_state, msg->data, ckdev->cols); 170 + exit: 171 + kfree(msg); 172 + return ret; 164 173 } 165 174 166 175 static irqreturn_t cros_ec_keyb_irq(int irq, void *data)
+20 -8
drivers/mfd/cros_ec.c
··· 41 41 out[2] = msg->outsize; 42 42 csum = out[0] + out[1] + out[2]; 43 43 for (i = 0; i < msg->outsize; i++) 44 - csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->outdata[i]; 44 + csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->data[i]; 45 45 out[EC_MSG_TX_HEADER_BYTES + msg->outsize] = (uint8_t)(csum & 0xff); 46 46 47 47 return EC_MSG_TX_PROTO_BYTES + msg->outsize; ··· 75 75 ret = ec_dev->cmd_xfer(ec_dev, msg); 76 76 if (msg->result == EC_RES_IN_PROGRESS) { 77 77 int i; 78 - struct cros_ec_command status_msg = { }; 78 + struct cros_ec_command *status_msg; 79 79 struct ec_response_get_comms_status *status; 80 80 81 - status_msg.command = EC_CMD_GET_COMMS_STATUS; 82 - status_msg.insize = sizeof(*status); 81 + status_msg = kmalloc(sizeof(*status_msg) + sizeof(*status), 82 + GFP_KERNEL); 83 + if (!status_msg) { 84 + ret = -ENOMEM; 85 + goto exit; 86 + } 87 + 88 + status_msg->version = 0; 89 + status_msg->command = EC_CMD_GET_COMMS_STATUS; 90 + status_msg->insize = sizeof(*status); 91 + status_msg->outsize = 0; 83 92 84 93 /* 85 94 * Query the EC's status until it's no longer busy or ··· 97 88 for (i = 0; i < EC_COMMAND_RETRIES; i++) { 98 89 usleep_range(10000, 11000); 99 90 100 - ret = ec_dev->cmd_xfer(ec_dev, &status_msg); 91 + ret = ec_dev->cmd_xfer(ec_dev, status_msg); 101 92 if (ret < 0) 102 93 break; 103 94 104 - msg->result = status_msg.result; 105 - if (status_msg.result != EC_RES_SUCCESS) 95 + msg->result = status_msg->result; 96 + if (status_msg->result != EC_RES_SUCCESS) 106 97 break; 107 98 108 99 status = (struct ec_response_get_comms_status *) 109 - status_msg.indata; 100 + status_msg->data; 110 101 if (!(status->flags & EC_COMMS_STATUS_PROCESSING)) 111 102 break; 112 103 } 104 + 105 + kfree(status_msg); 113 106 } 107 + exit: 114 108 mutex_unlock(&ec_dev->lock); 115 109 116 110 return ret;
+2 -2
drivers/mfd/cros_ec_i2c.c
··· 76 76 /* copy message payload and compute checksum */ 77 77 sum = out_buf[0] + out_buf[1] + out_buf[2]; 78 78 for (i = 0; i < msg->outsize; i++) { 79 - out_buf[3 + i] = msg->outdata[i]; 79 + out_buf[3 + i] = msg->data[i]; 80 80 sum += out_buf[3 + i]; 81 81 } 82 82 out_buf[3 + msg->outsize] = sum; ··· 109 109 /* copy response packet payload and compute checksum */ 110 110 sum = in_buf[0] + in_buf[1]; 111 111 for (i = 0; i < len; i++) { 112 - msg->indata[i] = in_buf[2 + i]; 112 + msg->data[i] = in_buf[2 + i]; 113 113 sum += in_buf[2 + i]; 114 114 } 115 115 dev_dbg(ec_dev->dev, "packet: %*ph, sum = %02x\n",
+1 -1
drivers/mfd/cros_ec_spi.c
··· 299 299 for (i = 0; i < len; i++) { 300 300 sum += ptr[i + 2]; 301 301 if (ec_msg->insize) 302 - ec_msg->indata[i] = ptr[i + 2]; 302 + ec_msg->data[i] = ptr[i + 2]; 303 303 } 304 304 sum &= 0xff; 305 305
+43 -24
drivers/platform/chrome/cros_ec_dev.c
··· 20 20 #include <linux/fs.h> 21 21 #include <linux/module.h> 22 22 #include <linux/platform_device.h> 23 + #include <linux/slab.h> 23 24 #include <linux/uaccess.h> 24 25 25 26 #include "cros_ec_dev.h" ··· 37 36 static const char * const current_image_name[] = { 38 37 "unknown", "read-only", "read-write", "invalid", 39 38 }; 40 - struct cros_ec_command msg = { 41 - .version = 0, 42 - .command = EC_CMD_GET_VERSION, 43 - .outdata = { 0 }, 44 - .outsize = 0, 45 - .indata = { 0 }, 46 - .insize = sizeof(*resp), 47 - }; 39 + struct cros_ec_command *msg; 48 40 int ret; 49 41 50 - ret = cros_ec_cmd_xfer(ec, &msg); 51 - if (ret < 0) 52 - return ret; 42 + msg = kmalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL); 43 + if (!msg) 44 + return -ENOMEM; 53 45 54 - if (msg.result != EC_RES_SUCCESS) { 46 + msg->version = 0; 47 + msg->command = EC_CMD_GET_VERSION; 48 + msg->insize = sizeof(*resp); 49 + msg->outsize = 0; 50 + 51 + ret = cros_ec_cmd_xfer(ec, msg); 52 + if (ret < 0) 53 + goto exit; 54 + 55 + if (msg->result != EC_RES_SUCCESS) { 55 56 snprintf(str, maxlen, 56 57 "%s\nUnknown EC version: EC returned %d\n", 57 - CROS_EC_DEV_VERSION, msg.result); 58 - return 0; 58 + CROS_EC_DEV_VERSION, msg->result); 59 + ret = -EINVAL; 60 + goto exit; 59 61 } 60 62 61 - resp = (struct ec_response_get_version *)msg.indata; 63 + resp = (struct ec_response_get_version *)msg->data; 62 64 if (resp->current_image >= ARRAY_SIZE(current_image_name)) 63 65 resp->current_image = 3; /* invalid */ 64 66 ··· 69 65 resp->version_string_ro, resp->version_string_rw, 70 66 current_image_name[resp->current_image]); 71 67 72 - return 0; 68 + ret = 0; 69 + exit: 70 + kfree(msg); 71 + return ret; 73 72 } 74 73 75 74 /* Device file ops */ ··· 117 110 static long ec_device_ioctl_xcmd(struct cros_ec_device *ec, void __user *arg) 118 111 { 119 112 long ret; 120 - struct cros_ec_command s_cmd = { }; 113 + struct cros_ec_command u_cmd; 114 + struct cros_ec_command *s_cmd; 121 115 122 - if (copy_from_user(&s_cmd, arg, sizeof(s_cmd))) 116 + if (copy_from_user(&u_cmd, arg, sizeof(u_cmd))) 123 117 return -EFAULT; 124 118 125 - ret = cros_ec_cmd_xfer(ec, &s_cmd); 119 + s_cmd = kmalloc(sizeof(*s_cmd) + max(u_cmd.outsize, u_cmd.insize), 120 + GFP_KERNEL); 121 + if (!s_cmd) 122 + return -ENOMEM; 123 + 124 + if (copy_from_user(s_cmd, arg, sizeof(*s_cmd) + u_cmd.outsize)) { 125 + ret = -EFAULT; 126 + goto exit; 127 + } 128 + 129 + ret = cros_ec_cmd_xfer(ec, s_cmd); 126 130 /* Only copy data to userland if data was received. */ 127 131 if (ret < 0) 128 - return ret; 132 + goto exit; 129 133 130 - if (copy_to_user(arg, &s_cmd, sizeof(s_cmd))) 131 - return -EFAULT; 132 - 133 - return 0; 134 + if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + u_cmd.insize)) 135 + ret = -EFAULT; 136 + exit: 137 + kfree(s_cmd); 138 + return ret; 134 139 } 135 140 136 141 static long ec_device_ioctl_readmem(struct cros_ec_device *ec, void __user *arg)
+103 -49
drivers/platform/chrome/cros_ec_lightbar.c
··· 31 31 #include <linux/sched.h> 32 32 #include <linux/types.h> 33 33 #include <linux/uaccess.h> 34 + #include <linux/slab.h> 34 35 35 36 #include "cros_ec_dev.h" 36 37 ··· 92 91 return ret; 93 92 } 94 93 95 - #define INIT_MSG(P, R) { \ 96 - .command = EC_CMD_LIGHTBAR_CMD, \ 97 - .outsize = sizeof(*P), \ 98 - .insize = sizeof(*R), \ 99 - } 94 + static struct cros_ec_command *alloc_lightbar_cmd_msg(void) 95 + { 96 + struct cros_ec_command *msg; 97 + int len; 98 + 99 + len = max(sizeof(struct ec_params_lightbar), 100 + sizeof(struct ec_response_lightbar)); 101 + 102 + msg = kmalloc(sizeof(*msg) + len, GFP_KERNEL); 103 + if (!msg) 104 + return NULL; 105 + 106 + msg->version = 0; 107 + msg->command = EC_CMD_LIGHTBAR_CMD; 108 + msg->outsize = sizeof(struct ec_params_lightbar); 109 + msg->insize = sizeof(struct ec_response_lightbar); 110 + 111 + return msg; 112 + } 100 113 101 114 static int get_lightbar_version(struct cros_ec_device *ec, 102 115 uint32_t *ver_ptr, uint32_t *flg_ptr) 103 116 { 104 117 struct ec_params_lightbar *param; 105 118 struct ec_response_lightbar *resp; 106 - struct cros_ec_command msg = INIT_MSG(param, resp); 119 + struct cros_ec_command *msg; 107 120 int ret; 108 121 109 - param = (struct ec_params_lightbar *)msg.outdata; 110 - param->cmd = LIGHTBAR_CMD_VERSION; 111 - ret = cros_ec_cmd_xfer(ec, &msg); 112 - if (ret < 0) 122 + msg = alloc_lightbar_cmd_msg(); 123 + if (!msg) 113 124 return 0; 114 125 115 - switch (msg.result) { 126 + param = (struct ec_params_lightbar *)msg->data; 127 + param->cmd = LIGHTBAR_CMD_VERSION; 128 + ret = cros_ec_cmd_xfer(ec, msg); 129 + if (ret < 0) { 130 + ret = 0; 131 + goto exit; 132 + } 133 + 134 + switch (msg->result) { 116 135 case EC_RES_INVALID_PARAM: 117 136 /* Pixel had no version command. */ 118 137 if (ver_ptr) 119 138 *ver_ptr = 0; 120 139 if (flg_ptr) 121 140 *flg_ptr = 0; 122 - return 1; 141 + ret = 1; 142 + goto exit; 123 143 124 144 case EC_RES_SUCCESS: 125 - resp = (struct ec_response_lightbar *)msg.indata; 145 + resp = (struct ec_response_lightbar *)msg->data; 126 146 127 147 /* Future devices w/lightbars should implement this command */ 128 148 if (ver_ptr) 129 149 *ver_ptr = resp->version.num; 130 150 if (flg_ptr) 131 151 *flg_ptr = resp->version.flags; 132 - return 1; 152 + ret = 1; 153 + goto exit; 133 154 } 134 155 135 156 /* Anything else (ie, EC_RES_INVALID_COMMAND) - no lightbar */ 136 - return 0; 157 + ret = 0; 158 + exit: 159 + kfree(msg); 160 + return ret; 137 161 } 138 162 139 163 static ssize_t version_show(struct device *dev, 140 164 struct device_attribute *attr, char *buf) 141 165 { 142 - uint32_t version, flags; 166 + uint32_t version = 0, flags = 0; 143 167 struct cros_ec_device *ec = dev_get_drvdata(dev); 144 168 int ret; 145 169 ··· 184 158 const char *buf, size_t count) 185 159 { 186 160 struct ec_params_lightbar *param; 187 - struct ec_response_lightbar *resp; 188 - struct cros_ec_command msg = INIT_MSG(param, resp); 161 + struct cros_ec_command *msg; 189 162 int ret; 190 163 unsigned int val; 191 164 struct cros_ec_device *ec = dev_get_drvdata(dev); ··· 192 167 if (kstrtouint(buf, 0, &val)) 193 168 return -EINVAL; 194 169 195 - param = (struct ec_params_lightbar *)msg.outdata; 170 + msg = alloc_lightbar_cmd_msg(); 171 + if (!msg) 172 + return -ENOMEM; 173 + 174 + param = (struct ec_params_lightbar *)msg->data; 196 175 param->cmd = LIGHTBAR_CMD_BRIGHTNESS; 197 176 param->brightness.num = val; 198 177 ret = lb_throttle(); 199 178 if (ret) 200 - return ret; 179 + goto exit; 201 180 202 - ret = cros_ec_cmd_xfer(ec, &msg); 181 + ret = cros_ec_cmd_xfer(ec, msg); 203 182 if (ret < 0) 204 - return ret; 183 + goto exit; 205 184 206 - if (msg.result != EC_RES_SUCCESS) 207 - return -EINVAL; 185 + if (msg->result != EC_RES_SUCCESS) { 186 + ret = -EINVAL; 187 + goto exit; 188 + } 208 189 209 - return count; 190 + ret = count; 191 + exit: 192 + kfree(msg); 193 + return ret; 210 194 } 211 195 212 196 ··· 230 196 const char *buf, size_t count) 231 197 { 232 198 struct ec_params_lightbar *param; 233 - struct ec_response_lightbar *resp; 234 - struct cros_ec_command msg = INIT_MSG(param, resp); 199 + struct cros_ec_command *msg; 235 200 struct cros_ec_device *ec = dev_get_drvdata(dev); 236 201 unsigned int val[4]; 237 202 int ret, i = 0, j = 0, ok = 0; 203 + 204 + msg = alloc_lightbar_cmd_msg(); 205 + if (!msg) 206 + return -ENOMEM; 238 207 239 208 do { 240 209 /* Skip any whitespace */ ··· 252 215 return -EINVAL; 253 216 254 217 if (i == 4) { 255 - param = (struct ec_params_lightbar *)msg.outdata; 218 + param = (struct ec_params_lightbar *)msg->data; 256 219 param->cmd = LIGHTBAR_CMD_RGB; 257 220 param->rgb.led = val[0]; 258 221 param->rgb.red = val[1]; ··· 268 231 return ret; 269 232 } 270 233 271 - ret = cros_ec_cmd_xfer(ec, &msg); 234 + ret = cros_ec_cmd_xfer(ec, msg); 272 235 if (ret < 0) 273 - return ret; 236 + goto exit; 274 237 275 - if (msg.result != EC_RES_SUCCESS) 276 - return -EINVAL; 238 + if (msg->result != EC_RES_SUCCESS) { 239 + ret = -EINVAL; 240 + goto exit; 241 + } 277 242 278 243 i = 0; 279 244 ok = 1; ··· 287 248 288 249 } while (*buf); 289 250 251 + exit: 252 + kfree(msg); 290 253 return (ok && i == 0) ? count : -EINVAL; 291 254 } 292 255 ··· 302 261 { 303 262 struct ec_params_lightbar *param; 304 263 struct ec_response_lightbar *resp; 305 - struct cros_ec_command msg = INIT_MSG(param, resp); 264 + struct cros_ec_command *msg; 306 265 int ret; 307 266 struct cros_ec_device *ec = dev_get_drvdata(dev); 308 267 309 - param = (struct ec_params_lightbar *)msg.outdata; 268 + msg = alloc_lightbar_cmd_msg(); 269 + if (!msg) 270 + return -ENOMEM; 271 + 272 + param = (struct ec_params_lightbar *)msg->data; 310 273 param->cmd = LIGHTBAR_CMD_GET_SEQ; 311 274 ret = lb_throttle(); 312 275 if (ret) 313 - return ret; 276 + goto exit; 314 277 315 - ret = cros_ec_cmd_xfer(ec, &msg); 278 + ret = cros_ec_cmd_xfer(ec, msg); 316 279 if (ret < 0) 317 - return ret; 280 + goto exit; 318 281 319 - if (msg.result != EC_RES_SUCCESS) 320 - return scnprintf(buf, PAGE_SIZE, 321 - "ERROR: EC returned %d\n", msg.result); 282 + if (msg->result != EC_RES_SUCCESS) { 283 + ret = scnprintf(buf, PAGE_SIZE, 284 + "ERROR: EC returned %d\n", msg->result); 285 + goto exit; 286 + } 322 287 323 - resp = (struct ec_response_lightbar *)msg.indata; 288 + resp = (struct ec_response_lightbar *)msg->data; 324 289 if (resp->get_seq.num >= ARRAY_SIZE(seqname)) 325 - return scnprintf(buf, PAGE_SIZE, "%d\n", resp->get_seq.num); 290 + ret = scnprintf(buf, PAGE_SIZE, "%d\n", resp->get_seq.num); 326 291 else 327 - return scnprintf(buf, PAGE_SIZE, "%s\n", 328 - seqname[resp->get_seq.num]); 292 + ret = scnprintf(buf, PAGE_SIZE, "%s\n", 293 + seqname[resp->get_seq.num]); 294 + 295 + exit: 296 + kfree(msg); 297 + return ret; 329 298 } 330 299 331 300 static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, 332 301 const char *buf, size_t count) 333 302 { 334 303 struct ec_params_lightbar *param; 335 - struct ec_response_lightbar *resp; 336 - struct cros_ec_command msg = INIT_MSG(param, resp); 304 + struct cros_ec_command *msg; 337 305 unsigned int num; 338 306 int ret, len; 339 307 struct cros_ec_device *ec = dev_get_drvdata(dev); 308 + 309 + msg = alloc_lightbar_cmd_msg(); 310 + if (!msg) 311 + return -ENOMEM; 340 312 341 313 for (len = 0; len < count; len++) 342 314 if (!isalnum(buf[len])) ··· 365 311 return ret; 366 312 } 367 313 368 - param = (struct ec_params_lightbar *)msg.outdata; 314 + param = (struct ec_params_lightbar *)msg->data; 369 315 param->cmd = LIGHTBAR_CMD_SEQ; 370 316 param->seq.num = num; 371 317 ret = lb_throttle(); 372 318 if (ret) 373 319 return ret; 374 320 375 - ret = cros_ec_cmd_xfer(ec, &msg); 321 + ret = cros_ec_cmd_xfer(ec, msg); 376 322 if (ret < 0) 377 323 return ret; 378 324 379 - if (msg.result != EC_RES_SUCCESS) 325 + if (msg->result != EC_RES_SUCCESS) 380 326 return -EINVAL; 381 327 382 328 return count;
+4 -4
drivers/platform/chrome/cros_ec_lpc.c
··· 73 73 74 74 /* Copy data and update checksum */ 75 75 for (i = 0; i < msg->outsize; i++) { 76 - outb(msg->outdata[i], EC_LPC_ADDR_HOST_PARAM + i); 77 - csum += msg->outdata[i]; 76 + outb(msg->data[i], EC_LPC_ADDR_HOST_PARAM + i); 77 + csum += msg->data[i]; 78 78 } 79 79 80 80 /* Finalize checksum and write args */ ··· 129 129 130 130 /* Read response and update checksum */ 131 131 for (i = 0; i < args.data_size; i++) { 132 - msg->indata[i] = inb(EC_LPC_ADDR_HOST_PARAM + i); 133 - csum += msg->indata[i]; 132 + msg->data[i] = inb(EC_LPC_ADDR_HOST_PARAM + i); 133 + csum += msg->data[i]; 134 134 } 135 135 136 136 /* Verify checksum */
+94 -58
drivers/platform/chrome/cros_ec_sysfs.c
··· 29 29 #include <linux/module.h> 30 30 #include <linux/platform_device.h> 31 31 #include <linux/printk.h> 32 + #include <linux/slab.h> 32 33 #include <linux/stat.h> 33 34 #include <linux/types.h> 34 35 #include <linux/uaccess.h> ··· 67 66 {"hibernate", EC_REBOOT_HIBERNATE, 0}, 68 67 {"at-shutdown", -1, EC_REBOOT_FLAG_ON_AP_SHUTDOWN}, 69 68 }; 70 - struct cros_ec_command msg = { 0 }; 71 - struct ec_params_reboot_ec *param = 72 - (struct ec_params_reboot_ec *)msg.outdata; 69 + struct cros_ec_command *msg; 70 + struct ec_params_reboot_ec *param; 73 71 int got_cmd = 0, offset = 0; 74 72 int i; 75 73 int ret; 76 74 struct cros_ec_device *ec = dev_get_drvdata(dev); 75 + 76 + msg = kmalloc(sizeof(*msg) + sizeof(*param), GFP_KERNEL); 77 + if (!msg) 78 + return -ENOMEM; 79 + 80 + param = (struct ec_params_reboot_ec *)msg->data; 77 81 78 82 param->flags = 0; 79 83 while (1) { ··· 106 100 offset++; 107 101 } 108 102 109 - if (!got_cmd) 110 - return -EINVAL; 111 - 112 - msg.command = EC_CMD_REBOOT_EC; 113 - msg.outsize = sizeof(param); 114 - ret = cros_ec_cmd_xfer(ec, &msg); 115 - if (ret < 0) 116 - return ret; 117 - if (msg.result != EC_RES_SUCCESS) { 118 - dev_dbg(ec->dev, "EC result %d\n", msg.result); 119 - return -EINVAL; 103 + if (!got_cmd) { 104 + count = -EINVAL; 105 + goto exit; 120 106 } 121 107 108 + msg->version = 0; 109 + msg->command = EC_CMD_REBOOT_EC; 110 + msg->outsize = sizeof(*param); 111 + msg->insize = 0; 112 + ret = cros_ec_cmd_xfer(ec, msg); 113 + if (ret < 0) { 114 + count = ret; 115 + goto exit; 116 + } 117 + if (msg->result != EC_RES_SUCCESS) { 118 + dev_dbg(ec->dev, "EC result %d\n", msg->result); 119 + count = -EINVAL; 120 + } 121 + exit: 122 + kfree(msg); 122 123 return count; 123 124 } 124 125 ··· 136 123 struct ec_response_get_version *r_ver; 137 124 struct ec_response_get_chip_info *r_chip; 138 125 struct ec_response_board_version *r_board; 139 - struct cros_ec_command msg = { 0 }; 126 + struct cros_ec_command *msg; 140 127 int ret; 141 128 int count = 0; 142 129 struct cros_ec_device *ec = dev_get_drvdata(dev); 143 130 144 - /* Get versions. RW may change. */ 145 - msg.command = EC_CMD_GET_VERSION; 146 - msg.insize = sizeof(*r_ver); 147 - ret = cros_ec_cmd_xfer(ec, &msg); 148 - if (ret < 0) 149 - return ret; 150 - if (msg.result != EC_RES_SUCCESS) 151 - return scnprintf(buf, PAGE_SIZE, 152 - "ERROR: EC returned %d\n", msg.result); 131 + msg = kmalloc(sizeof(*msg) + EC_HOST_PARAM_SIZE, GFP_KERNEL); 132 + if (!msg) 133 + return -ENOMEM; 153 134 154 - r_ver = (struct ec_response_get_version *)msg.indata; 135 + /* Get versions. RW may change. */ 136 + msg->version = 0; 137 + msg->command = EC_CMD_GET_VERSION; 138 + msg->insize = sizeof(*r_ver); 139 + msg->outsize = 0; 140 + ret = cros_ec_cmd_xfer(ec, msg); 141 + if (ret < 0) { 142 + count = ret; 143 + goto exit; 144 + } 145 + if (msg->result != EC_RES_SUCCESS) { 146 + count = scnprintf(buf, PAGE_SIZE, 147 + "ERROR: EC returned %d\n", msg->result); 148 + goto exit; 149 + } 150 + 151 + r_ver = (struct ec_response_get_version *)msg->data; 155 152 /* Strings should be null-terminated, but let's be sure. */ 156 153 r_ver->version_string_ro[sizeof(r_ver->version_string_ro) - 1] = '\0'; 157 154 r_ver->version_string_rw[sizeof(r_ver->version_string_rw) - 1] = '\0'; ··· 175 152 image_names[r_ver->current_image] : "?")); 176 153 177 154 /* Get build info. */ 178 - msg.command = EC_CMD_GET_BUILD_INFO; 179 - msg.insize = sizeof(msg.indata); 180 - ret = cros_ec_cmd_xfer(ec, &msg); 155 + msg->command = EC_CMD_GET_BUILD_INFO; 156 + msg->insize = EC_HOST_PARAM_SIZE; 157 + ret = cros_ec_cmd_xfer(ec, msg); 181 158 if (ret < 0) 182 159 count += scnprintf(buf + count, PAGE_SIZE - count, 183 160 "Build info: XFER ERROR %d\n", ret); 184 - else if (msg.result != EC_RES_SUCCESS) 161 + else if (msg->result != EC_RES_SUCCESS) 185 162 count += scnprintf(buf + count, PAGE_SIZE - count, 186 - "Build info: EC error %d\n", msg.result); 163 + "Build info: EC error %d\n", msg->result); 187 164 else { 188 - msg.indata[sizeof(msg.indata) - 1] = '\0'; 165 + msg->data[sizeof(msg->data) - 1] = '\0'; 189 166 count += scnprintf(buf + count, PAGE_SIZE - count, 190 - "Build info: %s\n", msg.indata); 167 + "Build info: %s\n", msg->data); 191 168 } 192 169 193 170 /* Get chip info. */ 194 - msg.command = EC_CMD_GET_CHIP_INFO; 195 - msg.insize = sizeof(*r_chip); 196 - ret = cros_ec_cmd_xfer(ec, &msg); 171 + msg->command = EC_CMD_GET_CHIP_INFO; 172 + msg->insize = sizeof(*r_chip); 173 + ret = cros_ec_cmd_xfer(ec, msg); 197 174 if (ret < 0) 198 175 count += scnprintf(buf + count, PAGE_SIZE - count, 199 176 "Chip info: XFER ERROR %d\n", ret); 200 - else if (msg.result != EC_RES_SUCCESS) 177 + else if (msg->result != EC_RES_SUCCESS) 201 178 count += scnprintf(buf + count, PAGE_SIZE - count, 202 - "Chip info: EC error %d\n", msg.result); 179 + "Chip info: EC error %d\n", msg->result); 203 180 else { 204 - r_chip = (struct ec_response_get_chip_info *)msg.indata; 181 + r_chip = (struct ec_response_get_chip_info *)msg->data; 205 182 206 183 r_chip->vendor[sizeof(r_chip->vendor) - 1] = '\0'; 207 184 r_chip->name[sizeof(r_chip->name) - 1] = '\0'; ··· 215 192 } 216 193 217 194 /* Get board version */ 218 - msg.command = EC_CMD_GET_BOARD_VERSION; 219 - msg.insize = sizeof(*r_board); 220 - ret = cros_ec_cmd_xfer(ec, &msg); 195 + msg->command = EC_CMD_GET_BOARD_VERSION; 196 + msg->insize = sizeof(*r_board); 197 + ret = cros_ec_cmd_xfer(ec, msg); 221 198 if (ret < 0) 222 199 count += scnprintf(buf + count, PAGE_SIZE - count, 223 200 "Board version: XFER ERROR %d\n", ret); 224 - else if (msg.result != EC_RES_SUCCESS) 201 + else if (msg->result != EC_RES_SUCCESS) 225 202 count += scnprintf(buf + count, PAGE_SIZE - count, 226 - "Board version: EC error %d\n", msg.result); 203 + "Board version: EC error %d\n", msg->result); 227 204 else { 228 - r_board = (struct ec_response_board_version *)msg.indata; 205 + r_board = (struct ec_response_board_version *)msg->data; 229 206 230 207 count += scnprintf(buf + count, PAGE_SIZE - count, 231 208 "Board version: %d\n", 232 209 r_board->board_version); 233 210 } 234 211 212 + exit: 213 + kfree(msg); 235 214 return count; 236 215 } 237 216 ··· 241 216 struct device_attribute *attr, char *buf) 242 217 { 243 218 struct ec_response_flash_info *resp; 244 - struct cros_ec_command msg = { 0 }; 219 + struct cros_ec_command *msg; 245 220 int ret; 246 221 struct cros_ec_device *ec = dev_get_drvdata(dev); 247 222 223 + msg = kmalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL); 224 + if (!msg) 225 + return -ENOMEM; 226 + 248 227 /* The flash info shouldn't ever change, but ask each time anyway. */ 249 - msg.command = EC_CMD_FLASH_INFO; 250 - msg.insize = sizeof(*resp); 251 - ret = cros_ec_cmd_xfer(ec, &msg); 228 + msg->version = 0; 229 + msg->command = EC_CMD_FLASH_INFO; 230 + msg->insize = sizeof(*resp); 231 + msg->outsize = 0; 232 + ret = cros_ec_cmd_xfer(ec, msg); 252 233 if (ret < 0) 253 - return ret; 254 - if (msg.result != EC_RES_SUCCESS) 255 - return scnprintf(buf, PAGE_SIZE, 256 - "ERROR: EC returned %d\n", msg.result); 234 + goto exit; 235 + if (msg->result != EC_RES_SUCCESS) { 236 + ret = scnprintf(buf, PAGE_SIZE, 237 + "ERROR: EC returned %d\n", msg->result); 238 + goto exit; 239 + } 257 240 258 - resp = (struct ec_response_flash_info *)msg.indata; 241 + resp = (struct ec_response_flash_info *)msg->data; 259 242 260 - return scnprintf(buf, PAGE_SIZE, 261 - "FlashSize %d\nWriteSize %d\n" 262 - "EraseSize %d\nProtectSize %d\n", 263 - resp->flash_size, resp->write_block_size, 264 - resp->erase_block_size, resp->protect_block_size); 243 + ret = scnprintf(buf, PAGE_SIZE, 244 + "FlashSize %d\nWriteSize %d\n" 245 + "EraseSize %d\nProtectSize %d\n", 246 + resp->flash_size, resp->write_block_size, 247 + resp->erase_block_size, resp->protect_block_size); 248 + exit: 249 + kfree(msg); 250 + return ret; 265 251 } 266 252 267 253 /* Module initialization */
+2 -4
include/linux/mfd/cros_ec.h
··· 42 42 * @outsize: Outgoing length in bytes 43 43 * @insize: Max number of bytes to accept from EC 44 44 * @result: EC's response to the command (separate from communication failure) 45 - * @outdata: Outgoing data to EC 46 - * @indata: Where to put the incoming data from EC 45 + * @data: Where to put the incoming data from EC and outgoing data to EC 47 46 */ 48 47 struct cros_ec_command { 49 48 uint32_t version; ··· 50 51 uint32_t outsize; 51 52 uint32_t insize; 52 53 uint32_t result; 53 - uint8_t outdata[EC_PROTO2_MAX_PARAM_SIZE]; 54 - uint8_t indata[EC_PROTO2_MAX_PARAM_SIZE]; 54 + uint8_t data[0]; 55 55 }; 56 56 57 57 /**