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

mfd: cros_ec: Use fixed size arrays to transfer data with the EC

The struct cros_ec_command will be used as an ioctl() argument for the
API to control the ChromeOS EC from user-space. So the data structure
has to be 64-bit safe to make it compatible between 32 and 64 avoiding
the need for a compat ioctl interface. Since pointers are self-aligned
to different byte boundaries, use fixed size arrays instead of pointers
for transferring ingoing and outgoing data with the Embedded Controller.

Also, re-arrange struct members by decreasing alignment requirements to
reduce the needing padding size.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Acked-by: Lee Jones <lee.jones@linaro.org>
Tested-by: Gwendal Grignou <gwendal@chromium.org>
Reviewed-by: Gwendal Grignou <gwendal@chromium.org>
Signed-off-by: Olof Johansson <olof@lixom.net>

authored by

Javier Martinez Canillas and committed by
Olof Johansson
1b84f2a4 c517d838

+29 -58
+10 -41
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 - u8 *request = NULL; 186 - u8 *response = NULL; 187 185 int result; 188 - struct cros_ec_command msg; 186 + struct cros_ec_command msg = { }; 189 187 190 188 request_len = ec_i2c_count_message(i2c_msgs, num); 191 189 if (request_len < 0) { 192 190 dev_warn(dev, "Error constructing message %d\n", request_len); 193 - result = request_len; 194 - goto exit; 191 + return request_len; 195 192 } 193 + 196 194 response_len = ec_i2c_count_response(i2c_msgs, num); 197 195 if (response_len < 0) { 198 196 /* Unexpected; no errors should come when NULL response */ 199 197 dev_warn(dev, "Error preparing response %d\n", response_len); 200 - result = response_len; 201 - goto exit; 198 + return response_len; 202 199 } 203 200 204 - if (request_len <= ARRAY_SIZE(bus->request_buf)) { 205 - request = bus->request_buf; 206 - } else { 207 - request = kzalloc(request_len, GFP_KERNEL); 208 - if (request == NULL) { 209 - result = -ENOMEM; 210 - goto exit; 211 - } 212 - } 213 - if (response_len <= ARRAY_SIZE(bus->response_buf)) { 214 - response = bus->response_buf; 215 - } else { 216 - response = kzalloc(response_len, GFP_KERNEL); 217 - if (response == NULL) { 218 - result = -ENOMEM; 219 - goto exit; 220 - } 221 - } 222 - 223 - result = ec_i2c_construct_message(request, i2c_msgs, num, bus_num); 201 + result = ec_i2c_construct_message(msg.outdata, i2c_msgs, num, bus_num); 224 202 if (result) 225 - goto exit; 203 + return result; 226 204 227 205 msg.version = 0; 228 206 msg.command = EC_CMD_I2C_PASSTHRU; 229 - msg.outdata = request; 230 207 msg.outsize = request_len; 231 - msg.indata = response; 232 208 msg.insize = response_len; 233 209 234 210 result = cros_ec_cmd_xfer(bus->ec, &msg); 235 211 if (result < 0) 236 - goto exit; 212 + return result; 237 213 238 - result = ec_i2c_parse_response(response, i2c_msgs, &num); 214 + result = ec_i2c_parse_response(msg.indata, i2c_msgs, &num); 239 215 if (result < 0) 240 - goto exit; 216 + return result; 241 217 242 218 /* Indicate success by saying how many messages were sent */ 243 - result = num; 244 - exit: 245 - if (request != bus->request_buf) 246 - kfree(request); 247 - if (response != bus->response_buf) 248 - kfree(response); 249 - 250 - return result; 219 + return num; 251 220 } 252 221 253 222 static u32 ec_i2c_functionality(struct i2c_adapter *adap)
+8 -5
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; 151 152 struct cros_ec_command msg = { 152 - .version = 0, 153 153 .command = EC_CMD_MKBP_STATE, 154 - .outdata = NULL, 155 - .outsize = 0, 156 - .indata = kb_state, 157 154 .insize = ckdev->cols, 158 155 }; 159 156 160 - return cros_ec_cmd_xfer(ckdev->ec, &msg); 157 + ret = cros_ec_cmd_xfer(ckdev->ec, &msg); 158 + if (ret < 0) 159 + return ret; 160 + 161 + memcpy(kb_state, msg.indata, ckdev->cols); 162 + 163 + return 0; 161 164 } 162 165 163 166 static irqreturn_t cros_ec_keyb_irq(int irq, void *data)
+7 -8
drivers/mfd/cros_ec.c
··· 74 74 ret = ec_dev->cmd_xfer(ec_dev, msg); 75 75 if (msg->result == EC_RES_IN_PROGRESS) { 76 76 int i; 77 - struct cros_ec_command status_msg; 78 - struct ec_response_get_comms_status status; 77 + struct cros_ec_command status_msg = { }; 78 + struct ec_response_get_comms_status *status; 79 79 80 - status_msg.version = 0; 81 80 status_msg.command = EC_CMD_GET_COMMS_STATUS; 82 - status_msg.outdata = NULL; 83 - status_msg.outsize = 0; 84 - status_msg.indata = (uint8_t *)&status; 85 - status_msg.insize = sizeof(status); 81 + status_msg.insize = sizeof(*status); 86 82 87 83 /* 88 84 * Query the EC's status until it's no longer busy or ··· 94 98 msg->result = status_msg.result; 95 99 if (status_msg.result != EC_RES_SUCCESS) 96 100 break; 97 - if (!(status.flags & EC_COMMS_STATUS_PROCESSING)) 101 + 102 + status = (struct ec_response_get_comms_status *) 103 + status_msg.indata; 104 + if (!(status->flags & EC_COMMS_STATUS_PROCESSING)) 98 105 break; 99 106 } 100 107 }
+4 -4
include/linux/mfd/cros_ec.h
··· 38 38 /* 39 39 * @version: Command version number (often 0) 40 40 * @command: Command to send (EC_CMD_...) 41 - * @outdata: Outgoing data to EC 42 41 * @outsize: Outgoing length in bytes 43 - * @indata: Where to put the incoming data from EC 44 42 * @insize: Max number of bytes to accept from EC 45 43 * @result: EC's response to the command (separate from communication failure) 44 + * @outdata: Outgoing data to EC 45 + * @indata: Where to put the incoming data from EC 46 46 */ 47 47 struct cros_ec_command { 48 48 uint32_t version; 49 49 uint32_t command; 50 - uint8_t *outdata; 51 50 uint32_t outsize; 52 - uint8_t *indata; 53 51 uint32_t insize; 54 52 uint32_t result; 53 + uint8_t outdata[EC_PROTO2_MAX_PARAM_SIZE]; 54 + uint8_t indata[EC_PROTO2_MAX_PARAM_SIZE]; 55 55 }; 56 56 57 57 /**