diff options
| author | Javier Martinez Canillas <javier.martinez@collabora.co.uk> | 2015-02-02 06:26:22 -0500 |
|---|---|---|
| committer | Olof Johansson <olof@lixom.net> | 2015-02-26 18:44:52 -0500 |
| commit | 1b84f2a4cd4a6f517a313261f6f7c8caae5696c6 (patch) | |
| tree | 8e7b0f5a1477c8792a83c7de0b03b8dc0ad737a1 | |
| parent | c517d838eb7d07bbe9507871fab3931deccff539 (diff) | |
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>
| -rw-r--r-- | drivers/i2c/busses/i2c-cros-ec-tunnel.c | 51 | ||||
| -rw-r--r-- | drivers/input/keyboard/cros_ec_keyb.c | 13 | ||||
| -rw-r--r-- | drivers/mfd/cros_ec.c | 15 | ||||
| -rw-r--r-- | include/linux/mfd/cros_ec.h | 8 |
4 files changed, 29 insertions, 58 deletions
diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c index 875c22ae5400..fa8dedd8c3a2 100644 --- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c +++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c | |||
| @@ -182,72 +182,41 @@ 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 | u8 *request = NULL; | ||
| 186 | u8 *response = NULL; | ||
| 187 | int result; | 185 | int result; |
| 188 | struct cros_ec_command msg; | 186 | struct cros_ec_command msg = { }; |
| 189 | 187 | ||
| 190 | request_len = ec_i2c_count_message(i2c_msgs, num); | 188 | request_len = ec_i2c_count_message(i2c_msgs, num); |
| 191 | if (request_len < 0) { | 189 | if (request_len < 0) { |
| 192 | dev_warn(dev, "Error constructing message %d\n", request_len); | 190 | dev_warn(dev, "Error constructing message %d\n", request_len); |
| 193 | result = request_len; | 191 | return request_len; |
| 194 | goto exit; | ||
| 195 | } | 192 | } |
| 193 | |||
| 196 | response_len = ec_i2c_count_response(i2c_msgs, num); | 194 | response_len = ec_i2c_count_response(i2c_msgs, num); |
| 197 | if (response_len < 0) { | 195 | if (response_len < 0) { |
| 198 | /* Unexpected; no errors should come when NULL response */ | 196 | /* Unexpected; no errors should come when NULL response */ |
| 199 | dev_warn(dev, "Error preparing response %d\n", response_len); | 197 | dev_warn(dev, "Error preparing response %d\n", response_len); |
| 200 | result = response_len; | 198 | return response_len; |
| 201 | goto exit; | ||
| 202 | } | ||
| 203 | |||
| 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 | } | 199 | } |
| 222 | 200 | ||
| 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 | if (result) | 202 | if (result) |
| 225 | goto exit; | 203 | return result; |
| 226 | 204 | ||
| 227 | msg.version = 0; | 205 | msg.version = 0; |
| 228 | msg.command = EC_CMD_I2C_PASSTHRU; | 206 | msg.command = EC_CMD_I2C_PASSTHRU; |
| 229 | msg.outdata = request; | ||
| 230 | msg.outsize = request_len; | 207 | msg.outsize = request_len; |
| 231 | msg.indata = response; | ||
| 232 | msg.insize = response_len; | 208 | msg.insize = response_len; |
| 233 | 209 | ||
| 234 | result = cros_ec_cmd_xfer(bus->ec, &msg); | 210 | result = cros_ec_cmd_xfer(bus->ec, &msg); |
| 235 | if (result < 0) | 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 | if (result < 0) | 215 | if (result < 0) |
| 240 | goto exit; | 216 | return result; |
| 241 | 217 | ||
| 242 | /* Indicate success by saying how many messages were sent */ | 218 | /* Indicate success by saying how many messages were sent */ |
| 243 | result = num; | 219 | return 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; | ||
| 251 | } | 220 | } |
| 252 | 221 | ||
| 253 | static u32 ec_i2c_functionality(struct i2c_adapter *adap) | 222 | static u32 ec_i2c_functionality(struct i2c_adapter *adap) |
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index ffa989f2c785..769f8f7f62b7 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c | |||
| @@ -148,16 +148,19 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, | |||
| 148 | 148 | ||
| 149 | static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state) | 149 | static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state) |
| 150 | { | 150 | { |
| 151 | int ret; | ||
| 151 | struct cros_ec_command msg = { | 152 | struct cros_ec_command msg = { |
| 152 | .version = 0, | ||
| 153 | .command = EC_CMD_MKBP_STATE, | 153 | .command = EC_CMD_MKBP_STATE, |
| 154 | .outdata = NULL, | ||
| 155 | .outsize = 0, | ||
| 156 | .indata = kb_state, | ||
| 157 | .insize = ckdev->cols, | 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 | static irqreturn_t cros_ec_keyb_irq(int irq, void *data) | 166 | static irqreturn_t cros_ec_keyb_irq(int irq, void *data) |
diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index fc0c81ef04ff..c872e1b0eaf8 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c | |||
| @@ -74,15 +74,11 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, | |||
| 74 | ret = ec_dev->cmd_xfer(ec_dev, msg); | 74 | ret = ec_dev->cmd_xfer(ec_dev, msg); |
| 75 | if (msg->result == EC_RES_IN_PROGRESS) { | 75 | if (msg->result == EC_RES_IN_PROGRESS) { |
| 76 | int i; | 76 | int i; |
| 77 | struct cros_ec_command status_msg; | 77 | struct cros_ec_command status_msg = { }; |
| 78 | struct ec_response_get_comms_status status; | 78 | struct ec_response_get_comms_status *status; |
| 79 | 79 | ||
| 80 | status_msg.version = 0; | ||
| 81 | status_msg.command = EC_CMD_GET_COMMS_STATUS; | 80 | status_msg.command = EC_CMD_GET_COMMS_STATUS; |
| 82 | status_msg.outdata = NULL; | 81 | status_msg.insize = sizeof(*status); |
| 83 | status_msg.outsize = 0; | ||
| 84 | status_msg.indata = (uint8_t *)&status; | ||
| 85 | status_msg.insize = sizeof(status); | ||
| 86 | 82 | ||
| 87 | /* | 83 | /* |
| 88 | * Query the EC's status until it's no longer busy or | 84 | * Query the EC's status until it's no longer busy or |
| @@ -98,7 +94,10 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, | |||
| 98 | msg->result = status_msg.result; | 94 | msg->result = status_msg.result; |
| 99 | if (status_msg.result != EC_RES_SUCCESS) | 95 | if (status_msg.result != EC_RES_SUCCESS) |
| 100 | break; | 96 | break; |
| 101 | if (!(status.flags & EC_COMMS_STATUS_PROCESSING)) | 97 | |
| 98 | status = (struct ec_response_get_comms_status *) | ||
| 99 | status_msg.indata; | ||
| 100 | if (!(status->flags & EC_COMMS_STATUS_PROCESSING)) | ||
| 102 | break; | 101 | break; |
| 103 | } | 102 | } |
| 104 | } | 103 | } |
diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h index 0e166b92f5b4..71675b14b5ca 100644 --- a/include/linux/mfd/cros_ec.h +++ b/include/linux/mfd/cros_ec.h | |||
| @@ -38,20 +38,20 @@ enum { | |||
| 38 | /* | 38 | /* |
| 39 | * @version: Command version number (often 0) | 39 | * @version: Command version number (often 0) |
| 40 | * @command: Command to send (EC_CMD_...) | 40 | * @command: Command to send (EC_CMD_...) |
| 41 | * @outdata: Outgoing data to EC | ||
| 42 | * @outsize: Outgoing length in bytes | 41 | * @outsize: Outgoing length in bytes |
| 43 | * @indata: Where to put the incoming data from EC | ||
