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

platform/chrome: wilco_ec: Standardize mailbox interface

The current API for the wilco EC mailbox interface is bad.

It assumes that most messages sent to the EC follow a similar structure,
with a command byte in MBOX[0], followed by a junk byte, followed by
actual data. This doesn't happen in several cases, such as setting the
RTC time, using the raw debugfs interface, and reading or writing
properties such as the Peak Shift policy (this last to be submitted soon).

Similarly for the response message from the EC, the current interface
assumes that the first byte of data is always 0, and the second byte
is unused. However, in both setting and getting the RTC time, in the
debugfs interface, and for reading and writing properties, this isn't
true.

The current way to resolve this is to use WILCO_EC_FLAG_RAW* flags to
specify when and when not to skip these initial bytes in the sent and
received message. They are confusing and used so much that they are
normal, and not exceptions. In addition, the first byte of
response in the debugfs interface is still always skipped, which is
weird, since this raw interface should be giving the entire result.

Additionally, sent messages assume the first byte is a command, and so
struct wilco_ec_message contains the "command" field. In setting or
getting properties however, the first byte is not a command, and so this
field has to be filled with a byte that isn't actually a command. This
is again inconsistent.

wilco_ec_message contains a result field as well, copied from
wilco_ec_response->result. The message result field should be removed:
if the message fails, the cause is already logged, and the callers are
alerted. They will never care about the actual state of the result flag.

These flags and different cases make the wilco_ec_transfer() function,
used in wilco_ec_mailbox(), really gross, dealing with a bunch of
different cases. It's difficult to figure out what it is doing.

Finally, making these assumptions about the structure of a message make
it so that the messages do not correspond well with the specification
for the EC's mailbox interface. For instance, this interface
specification may say that MBOX[9] in the received message contains
some information, but the calling code needs to remember that the first
byte of response is always skipped, and because it didn't set the
RESPONSE_RAW flag, the next byte is also skipped, so this information
is actually contained within wilco_ec_message->response_data[7]. This
makes it difficult to maintain this code in the future.

To fix these problems this patch standardizes the mailbox interface by:
- Removing the WILCO_EC_FLAG_RAW* flags
- Removing the command and reserved_raw bytes from wilco_ec_request
- Removing the mbox0 byte from wilco_ec_response
- Simplifying wilco_ec_transfer() because of these changes
- Gives the callers of wilco_ec_mailbox() the responsibility of exactly
and consistently defining the structure of the mailbox request and
response
- Removing command and result from wilco_ec_message.

This results in the reduction of total code, and makes it much more
maintainable and understandable.

Signed-off-by: Nick Crews <ncrews@chromium.org>
Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>

authored by

Nick Crews and committed by
Enric Balletbo i Serra
14e14aaf 94d4e7af

+91 -121
+21 -11
Documentation/ABI/testing/debugfs-wilco-ec
··· 4 4 Description: 5 5 Write and read raw mailbox commands to the EC. 6 6 7 - For writing: 8 - Bytes 0-1 indicate the message type: 9 - 00 F0 = Execute Legacy Command 10 - 00 F2 = Read/Write NVRAM Property 11 - Byte 2 provides the command code 12 - Bytes 3+ consist of the data passed in the request 7 + You can write a hexadecimal sentence to raw, and that series of 8 + bytes will be sent to the EC. Then, you can read the bytes of 9 + response by reading from raw. 13 10 14 - At least three bytes are required, for the msg type and command, 15 - with additional bytes optional for additional data. 11 + For writing, bytes 0-1 indicate the message type, one of enum 12 + wilco_ec_msg_type. Byte 2+ consist of the data passed in the 13 + request, starting at MBOX[0] 14 + 15 + At least three bytes are required for writing, two for the type 16 + and at least a single byte of data. Only the first 17 + EC_MAILBOX_DATA_SIZE bytes of MBOX will be used. 16 18 17 19 Example: 18 20 // Request EC info type 3 (EC firmware build date) 19 - $ echo 00 f0 38 00 03 00 > raw 21 + // Corresponds with sending type 0x00f0 with 22 + // MBOX = [38, 00, 03, 00] 23 + $ echo 00 f0 38 00 03 00 > /sys/kernel/debug/wilco_ec/raw 20 24 // View the result. The decoded ASCII result "12/21/18" is 21 25 // included after the raw hex. 22 - $ cat raw 23 - 00 31 32 2f 32 31 2f 31 38 00 38 00 01 00 2f 00 .12/21/18.8... 26 + // Corresponds with MBOX = [00, 00, 31, 32, 2f, 32, 31, 38, ...] 27 + $ cat /sys/kernel/debug/wilco_ec/raw 28 + 00 00 31 32 2f 32 31 2f 31 38 00 38 00 01 00 2f 00 ..12/21/18.8... 29 + 30 + Note that the first 32 bytes of the received MBOX[] will be 31 + printed, even if some of the data is junk. It is up to you to 32 + know how many of the first bytes of data are the actual 33 + response.
+8 -34
drivers/platform/chrome/wilco_ec/debugfs.c
··· 4 4 * 5 5 * Copyright 2019 Google LLC 6 6 * 7 - * There is only one attribute used for debugging, called raw. 8 - * You can write a hexadecimal sentence to raw, and that series of bytes 9 - * will be sent to the EC. Then, you can read the bytes of response 10 - * by reading from raw. 11 - * 12 - * For writing: 13 - * Bytes 0-1 indicate the message type: 14 - * 00 F0 = Execute Legacy Command 15 - * 00 F2 = Read/Write NVRAM Property 16 - * Byte 2 provides the command code 17 - * Bytes 3+ consist of the data passed in the request 18 - * 19 - * When referencing the EC interface spec, byte 2 corresponds to MBOX[0], 20 - * byte 3 corresponds to MBOX[1], etc. 21 - * 22 - * At least three bytes are required, for the msg type and command, 23 - * with additional bytes optional for additional data. 24 - * 25 - * Example: 26 - * // Request EC info type 3 (EC firmware build date) 27 - * $ echo 00 f0 38 00 03 00 > raw 28 - * // View the result. The decoded ASCII result "12/21/18" is 29 - * // included after the raw hex. 30 - * $ cat raw 31 - * 00 31 32 2f 32 31 2f 31 38 00 38 00 01 00 2f 00 .12/21/18.8... 7 + * See Documentation/ABI/testing/debugfs-wilco-ec for usage. 32 8 */ 33 9 34 10 #include <linux/ctype.h> ··· 112 136 ret = parse_hex_sentence(buf, kcount, request_data, TYPE_AND_DATA_SIZE); 113 137 if (ret < 0) 114 138 return ret; 115 - /* Need at least two bytes for message type and one for command */ 139 + /* Need at least two bytes for message type and one byte of data */ 116 140 if (ret < 3) 117 141 return -EINVAL; 118 142 119 - /* Clear response data buffer */ 120 - memset(debug_info->raw_data, '\0', EC_MAILBOX_DATA_SIZE_EXTENDED); 121 - 122 143 msg.type = request_data[0] << 8 | request_data[1]; 123 - msg.flags = WILCO_EC_FLAG_RAW; 124 - msg.command = request_data[2]; 125 - msg.request_data = ret > 3 ? request_data + 3 : 0; 126 - msg.request_size = ret - 3; 144 + msg.flags = 0; 145 + msg.request_data = request_data + 2; 146 + msg.request_size = ret - 2; 147 + memset(debug_info->raw_data, 0, sizeof(debug_info->raw_data)); 127 148 msg.response_data = debug_info->raw_data; 128 149 msg.response_size = EC_MAILBOX_DATA_SIZE; 129 150 ··· 147 174 fmt_len = hex_dump_to_buffer(debug_info->raw_data, 148 175 debug_info->response_size, 149 176 16, 1, debug_info->formatted_data, 150 - FORMATTED_BUFFER_SIZE, true); 177 + sizeof(debug_info->formatted_data), 178 + true); 151 179 /* Only return response the first time it is read */ 152 180 debug_info->response_size = 0; 153 181 }
+21 -32
drivers/platform/chrome/wilco_ec/mailbox.c
··· 92 92 struct wilco_ec_request *rq) 93 93 { 94 94 memset(rq, 0, sizeof(*rq)); 95 - 96 - /* Handle messages without trimming bytes from the request */ 97 - if (msg->request_size && msg->flags & WILCO_EC_FLAG_RAW_REQUEST) { 98 - rq->reserved_raw = *(u8 *)msg->request_data; 99 - msg->request_size--; 100 - memmove(msg->request_data, msg->request_data + 1, 101 - msg->request_size); 102 - } 103 - 104 - /* Fill in request packet */ 105 95 rq->struct_version = EC_MAILBOX_PROTO_VERSION; 106 96 rq->mailbox_id = msg->type; 107 97 rq->mailbox_version = EC_MAILBOX_VERSION; 108 - rq->data_size = msg->request_size + EC_MAILBOX_DATA_EXTRA; 109 - rq->command = msg->command; 98 + rq->data_size = msg->request_size; 110 99 111 100 /* Checksum header and data */ 112 101 rq->checksum = wilco_ec_checksum(rq, sizeof(*rq)); ··· 148 159 return -EIO; 149 160 } 150 161 162 + /* 163 + * The EC always returns either EC_MAILBOX_DATA_SIZE or 164 + * EC_MAILBOX_DATA_SIZE_EXTENDED bytes of data, so we need to 165 + * calculate the checksum on **all** of this data, even if we 166 + * won't use all of it. 167 + */ 151 168 if (msg->flags & WILCO_EC_FLAG_EXTENDED_DATA) 152 169 size = EC_MAILBOX_DATA_SIZE_EXTENDED; 153 170 else ··· 168 173 return -EBADMSG; 169 174 } 170 175 171 - /* Check that the EC reported success */ 172 - msg->result = rs->result; 173 - if (msg->result) { 174 - dev_dbg(ec->dev, "bad response: 0x%02x\n", msg->result); 176 + if (rs->result) { 177 + dev_dbg(ec->dev, "EC reported failure: 0x%02x\n", rs->result); 175 178 return -EBADMSG; 176 179 } 177 180 178 - /* Check the returned data size, skipping the header */ 179 181 if (rs->data_size != size) { 180 182 dev_dbg(ec->dev, "unexpected packet size (%u != %zu)", 181 183 rs->data_size, size); 182 184 return -EMSGSIZE; 183 185 } 184 186 185 - /* Skip 1 response data byte unless specified */ 186 - size = (msg->flags & WILCO_EC_FLAG_RAW_RESPONSE) ? 0 : 1; 187 - if ((ssize_t) rs->data_size - size < msg->response_size) { 188 - dev_dbg(ec->dev, "response data too short (%zd < %zu)", 189 - (ssize_t) rs->data_size - size, msg->response_size); 187 + if (rs->data_size < msg->response_size) { 188 + dev_dbg(ec->dev, "EC didn't return enough data (%u < %zu)", 189 + rs->data_size, msg->response_size); 190 190 return -EMSGSIZE; 191 191 } 192 192 193 - /* Ignore response data bytes as requested */ 194 - memcpy(msg->response_data, rs->data + size, msg->response_size); 193 + memcpy(msg->response_data, rs->data, msg->response_size); 195 194 196 - /* Return actual amount of data received */ 197 - return msg->response_size; 195 + return rs->data_size; 198 196 } 199 197 200 198 /** ··· 195 207 * @ec: EC device. 196 208 * @msg: EC message data for request and response. 197 209 * 198 - * On entry msg->type, msg->flags, msg->command, msg->request_size, 199 - * msg->response_size, and msg->request_data should all be filled in. 210 + * On entry msg->type, msg->request_size, and msg->request_data should all be 211 + * filled in. If desired, msg->flags can be set. 200 212 * 201 - * On exit msg->result and msg->response_data will be filled. 213 + * If a response is expected, msg->response_size should be set, and 214 + * msg->response_data should point to a buffer with enough space. On exit 215 + * msg->response_data will be filled. 202 216 * 203 217 * Return: number of bytes received or negative error code on failure. 204 218 */ ··· 209 219 struct wilco_ec_request *rq; 210 220 int ret; 211 221 212 - dev_dbg(ec->dev, "cmd=%02x type=%04x flags=%02x rslen=%zu rqlen=%zu\n", 213 - msg->command, msg->type, msg->flags, msg->response_size, 214 - msg->request_size); 222 + dev_dbg(ec->dev, "type=%04x flags=%02x rslen=%zu rqlen=%zu\n", 223 + msg->type, msg->flags, msg->response_size, msg->request_size); 215 224 216 225 mutex_lock(&ec->mailbox_lock); 217 226 /* Prepare request packet */
+39 -24
drivers/rtc/rtc-wilco-ec.c
··· 21 21 #define EC_CMOS_TOD_WRITE 0x02 22 22 #define EC_CMOS_TOD_READ 0x08 23 23 24 + /* Message sent to the EC to request the current time. */ 25 + struct ec_rtc_read_request { 26 + u8 command; 27 + u8 reserved; 28 + u8 param; 29 + } __packed; 30 + static struct ec_rtc_read_request read_rq = { 31 + .command = EC_COMMAND_CMOS, 32 + .param = EC_CMOS_TOD_READ, 33 + }; 34 + 24 35 /** 25 - * struct ec_rtc_read - Format of RTC returned by EC. 36 + * struct ec_rtc_read_response - Format of RTC returned by EC. 37 + * @reserved: Unused byte 26 38 * @second: Second value (0..59) 27 39 * @minute: Minute value (0..59) 28 40 * @hour: Hour value (0..23) ··· 45 33 * 46 34 * All values are presented in binary (not BCD). 47 35 */ 48 - struct ec_rtc_read { 36 + struct ec_rtc_read_response { 37 + u8 reserved; 49 38 u8 second; 50 39 u8 minute; 51 40 u8 hour; ··· 57 44 } __packed; 58 45 59 46 /** 60 - * struct ec_rtc_write - Format of RTC sent to the EC. 61 - * @param: EC_CMOS_TOD_WRITE 47 + * struct ec_rtc_write_request - Format of RTC sent to the EC. 48 + * @command: Always EC_COMMAND_CMOS 49 + * @reserved: Unused byte 50 + * @param: Always EC_CMOS_TOD_WRITE 62 51 * @century: Century value (full year / 100) 63 52 * @year: Year value (full year % 100) 64 53 * @month: Month value (1..12) ··· 72 57 * 73 58 * All values are presented in BCD. 74 59 */ 75 - struct ec_rtc_write { 60 + struct ec_rtc_write_request { 61 + u8 command; 62 + u8 reserved; 76 63 u8 param; 77 64 u8 century; 78 65 u8 year; ··· 89 72 static int wilco_ec_rtc_read(struct device *dev, struct rtc_time *tm) 90 73 { 91 74 struct wilco_ec_device *ec = dev_get_drvdata(dev->parent); 92 - u8 param = EC_CMOS_TOD_READ; 93 - struct ec_rtc_read rtc; 94 - struct wilco_ec_message msg = { 95 - .type = WILCO_EC_MSG_LEGACY, 96 - .flags = WILCO_EC_FLAG_RAW_RESPONSE, 97 - .command = EC_COMMAND_CMOS, 98 - .request_data = &param, 99 - .request_size = sizeof(param), 100 - .response_data = &rtc, 101 - .response_size = sizeof(rtc), 102 - }; 75 + struct ec_rtc_read_response rtc; 76 + struct wilco_ec_message msg; 103 77 int ret; 78 + 79 + memset(&msg, 0, sizeof(msg)); 80 + msg.type = WILCO_EC_MSG_LEGACY; 81 + msg.request_data = &read_rq; 82 + msg.request_size = sizeof(read_rq); 83 + msg.response_data = &rtc; 84 + msg.response_size = sizeof(rtc); 104 85 105 86 ret = wilco_ec_mailbox(ec, &msg); 106 87 if (ret < 0) ··· 121 106 static int wilco_ec_rtc_write(struct device *dev, struct rtc_time *tm) 122 107 { 123 108 struct wilco_ec_device *ec = dev_get_drvdata(dev->parent); 124 - struct ec_rtc_write rtc; 125 - struct wilco_ec_message msg = { 126 - .type = WILCO_EC_MSG_LEGACY, 127 - .flags = WILCO_EC_FLAG_RAW_RESPONSE, 128 - .command = EC_COMMAND_CMOS, 129 - .request_data = &rtc, 130 - .request_size = sizeof(rtc), 131 - }; 109 + struct ec_rtc_write_request rtc; 110 + struct wilco_ec_message msg; 132 111 int year = tm->tm_year + 1900; 133 112 /* 134 113 * Convert from 0=Sunday to 0=Saturday for the EC ··· 132 123 int wday = tm->tm_wday == 6 ? 0 : tm->tm_wday + 1; 133 124 int ret; 134 125 126 + rtc.command = EC_COMMAND_CMOS; 135 127 rtc.param = EC_CMOS_TOD_WRITE; 136 128 rtc.century = bin2bcd(year / 100); 137 129 rtc.year = bin2bcd(year % 100); ··· 142 132 rtc.minute = bin2bcd(tm->tm_min); 143 133 rtc.second = bin2bcd(tm->tm_sec); 144 134 rtc.weekday = bin2bcd(wday); 135 + 136 + memset(&msg, 0, sizeof(msg)); 137 + msg.type = WILCO_EC_MSG_LEGACY; 138 + msg.request_data = &rtc; 139 + msg.request_size = sizeof(rtc); 145 140 146 141 ret = wilco_ec_mailbox(ec, &msg); 147 142 if (ret < 0)
+2 -20
include/linux/platform_data/wilco-ec.h
··· 14 14 /* Message flags for using the mailbox() interface */ 15 15 #define WILCO_EC_FLAG_NO_RESPONSE BIT(0) /* EC does not respond */ 16 16 #define WILCO_EC_FLAG_EXTENDED_DATA BIT(1) /* EC returns 256 data bytes */ 17 - #define WILCO_EC_FLAG_RAW_REQUEST BIT(2) /* Do not trim request data */ 18 - #define WILCO_EC_FLAG_RAW_RESPONSE BIT(3) /* Do not trim response data */ 19 - #define WILCO_EC_FLAG_RAW (WILCO_EC_FLAG_RAW_REQUEST | \ 20 - WILCO_EC_FLAG_RAW_RESPONSE) 21 17 22 18 /* Normal commands have a maximum 32 bytes of data */ 23 19 #define EC_MAILBOX_DATA_SIZE 32 ··· 52 56 * @mailbox_id: Mailbox identifier, specifies the command set. 53 57 * @mailbox_version: Mailbox interface version %EC_MAILBOX_VERSION 54 58 * @reserved: Set to zero. 55 - * @data_size: Length of request, data + last 2 bytes of the header. 56 - * @command: Mailbox command code, unique for each mailbox_id set. 57 - * @reserved_raw: Set to zero for most commands, but is used by 58 - * some command types and for raw commands. 59 + * @data_size: Length of following data. 59 60 */ 60 61 struct wilco_ec_request { 61 62 u8 struct_version; ··· 61 68 u8 mailbox_version; 62 69 u8 reserved; 63 70 u16 data_size; 64 - u8 command; 65 - u8 reserved_raw; 66 71 } __packed; 67 72 68 73 /** ··· 70 79 * @result: Result code from the EC. Non-zero indicates an error. 71 80 * @data_size: Length of the response data buffer. 72 81 * @reserved: Set to zero. 73 - * @mbox0: EC returned data at offset 0 is unused (always 0) so this byte 74 - * is treated as part of the header instead of the data. 75 82 * @data: Response data buffer. Max size is %EC_MAILBOX_DATA_SIZE_EXTENDED. 76 83 */ 77 84 struct wilco_ec_response { ··· 78 89 u16 result; 79 90 u16 data_size; 80 91 u8 reserved[2]; 81 - u8 mbox0; 82 92 u8 data[0]; 83 93 } __packed; 84 94 ··· 99 111 * struct wilco_ec_message - Request and response message. 100 112 * @type: Mailbox message type. 101 113 * @flags: Message flags, e.g. %WILCO_EC_FLAG_NO_RESPONSE. 102 - * @command: Mailbox command code. 103 - * @result: Result code from the EC. Non-zero indicates an error. 104 114 * @request_size: Number of bytes to send to the EC. 105 115 * @request_data: Buffer containing the request data. 106 - * @response_size: Number of bytes expected from the EC. 107 - * This is 32 by default and 256 if the flag 108 - * is set for %WILCO_EC_FLAG_EXTENDED_DATA 116 + * @response_size: Number of bytes to read from EC. 109 117 * @response_data: Buffer containing the response data, should be 110 118 * response_size bytes and allocated by caller. 111 119 */ 112 120 struct wilco_ec_message { 113 121 enum wilco_ec_msg_type type; 114 122 u8 flags; 115 - u8 command; 116 - u8 result; 117 123 size_t request_size; 118 124 void *request_data; 119 125 size_t response_size;