Skip to content

Commit 14e14aa

Browse files
Nick CrewsEnric Balletbo i Serra
authored andcommitted
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 <[email protected]> Acked-by: Alexandre Belloni <[email protected]> Signed-off-by: Enric Balletbo i Serra <[email protected]>
1 parent 94d4e7a commit 14e14aa

File tree

5 files changed

+91
-121
lines changed

5 files changed

+91
-121
lines changed

Documentation/ABI/testing/debugfs-wilco-ec

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,30 @@ KernelVersion: 5.1
44
Description:
55
Write and read raw mailbox commands to the EC.
66

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.
1310

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.
1618

1719
Example:
1820
// 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
2024
// View the result. The decoded ASCII result "12/21/18" is
2125
// 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.

drivers/platform/chrome/wilco_ec/debugfs.c

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,7 @@
44
*
55
* Copyright 2019 Google LLC
66
*
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.
328
*/
339

3410
#include <linux/ctype.h>
@@ -136,18 +112,15 @@ static ssize_t raw_write(struct file *file, const char __user *user_buf,
136112
ret = parse_hex_sentence(buf, kcount, request_data, TYPE_AND_DATA_SIZE);
137113
if (ret < 0)
138114
return ret;
139-
/* Need at least two bytes for message type and one for command */
115+
/* Need at least two bytes for message type and one byte of data */
140116
if (ret < 3)
141117
return -EINVAL;
142118

143-
/* Clear response data buffer */
144-
memset(debug_info->raw_data, '\0', EC_MAILBOX_DATA_SIZE_EXTENDED);
145-
146119
msg.type = request_data[0] << 8 | request_data[1];
147-
msg.flags = WILCO_EC_FLAG_RAW;
148-
msg.command = request_data[2];
149-
msg.request_data = ret > 3 ? request_data + 3 : 0;
150-
msg.request_size = ret - 3;
120+
msg.flags = 0;
121+
msg.request_data = request_data + 2;
122+
msg.request_size = ret - 2;
123+
memset(debug_info->raw_data, 0, sizeof(debug_info->raw_data));
151124
msg.response_data = debug_info->raw_data;
152125
msg.response_size = EC_MAILBOX_DATA_SIZE;
153126

@@ -174,7 +147,8 @@ static ssize_t raw_read(struct file *file, char __user *user_buf, size_t count,
174147
fmt_len = hex_dump_to_buffer(debug_info->raw_data,
175148
debug_info->response_size,
176149
16, 1, debug_info->formatted_data,
177-
FORMATTED_BUFFER_SIZE, true);
150+
sizeof(debug_info->formatted_data),
151+
true);
178152
/* Only return response the first time it is read */
179153
debug_info->response_size = 0;
180154
}

drivers/platform/chrome/wilco_ec/mailbox.c

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -92,21 +92,10 @@ static void wilco_ec_prepare(struct wilco_ec_message *msg,
9292
struct wilco_ec_request *rq)
9393
{
9494
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 */
10595
rq->struct_version = EC_MAILBOX_PROTO_VERSION;
10696
rq->mailbox_id = msg->type;
10797
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;
11099

111100
/* Checksum header and data */
112101
rq->checksum = wilco_ec_checksum(rq, sizeof(*rq));
@@ -159,6 +148,12 @@ static int wilco_ec_transfer(struct wilco_ec_device *ec,
159148
return -EIO;
160149
}
161150

151+
/*
152+
* The EC always returns either EC_MAILBOX_DATA_SIZE or
153+
* EC_MAILBOX_DATA_SIZE_EXTENDED bytes of data, so we need to
154+
* calculate the checksum on **all** of this data, even if we
155+
* won't use all of it.
156+
*/
162157
if (msg->flags & WILCO_EC_FLAG_EXTENDED_DATA)
163158
size = EC_MAILBOX_DATA_SIZE_EXTENDED;
164159
else
@@ -173,44 +168,39 @@ static int wilco_ec_transfer(struct wilco_ec_device *ec,
173168
return -EBADMSG;
174169
}
175170

176-
/* Check that the EC reported success */
177-
msg->result = rs->result;
178-
if (msg->result) {
179-
dev_dbg(ec->dev, "bad response: 0x%02x\n", msg->result);
171+
if (rs->result) {
172+
dev_dbg(ec->dev, "EC reported failure: 0x%02x\n", rs->result);
180173
return -EBADMSG;
181174
}
182175

183-
/* Check the returned data size, skipping the header */
184176
if (rs->data_size != size) {
185177
dev_dbg(ec->dev, "unexpected packet size (%u != %zu)",
186178
rs->data_size, size);
187179
return -EMSGSIZE;
188180
}
189181

190-
/* Skip 1 response data byte unless specified */
191-
size = (msg->flags & WILCO_EC_FLAG_RAW_RESPONSE) ? 0 : 1;
192-
if ((ssize_t) rs->data_size - size < msg->response_size) {
193-
dev_dbg(ec->dev, "response data too short (%zd < %zu)",
194-
(ssize_t) rs->data_size - size, msg->response_size);
182+
if (rs->data_size < msg->response_size) {
183+
dev_dbg(ec->dev, "EC didn't return enough data (%u < %zu)",
184+
rs->data_size, msg->response_size);
195185
return -EMSGSIZE;
196186
}
197187

198-
/* Ignore response data bytes as requested */
199-
memcpy(msg->response_data, rs->data + size, msg->response_size);
188+
memcpy(msg->response_data, rs->data, msg->response_size);
200189

201-
/* Return actual amount of data received */
202-
return msg->response_size;
190+
return rs->data_size;
203191
}
204192

205193
/**
206194
* wilco_ec_mailbox() - Send EC request and receive EC response.
207195
* @ec: EC device.
208196
* @msg: EC message data for request and response.
209197
*
210-
* On entry msg->type, msg->flags, msg->command, msg->request_size,
211-
* msg->response_size, and msg->request_data should all be filled in.
198+
* On entry msg->type, msg->request_size, and msg->request_data should all be
199+
* filled in. If desired, msg->flags can be set.
212200
*
213-
* On exit msg->result and msg->response_data will be filled.
201+
* If a response is expected, msg->response_size should be set, and
202+
* msg->response_data should point to a buffer with enough space. On exit
203+
* msg->response_data will be filled.
214204
*
215205
* Return: number of bytes received or negative error code on failure.
216206
*/
@@ -219,9 +209,8 @@ int wilco_ec_mailbox(struct wilco_ec_device *ec, struct wilco_ec_message *msg)
219209
struct wilco_ec_request *rq;
220210
int ret;
221211

222-
dev_dbg(ec->dev, "cmd=%02x type=%04x flags=%02x rslen=%zu rqlen=%zu\n",
223-
msg->command, msg->type, msg->flags, msg->response_size,
224-
msg->request_size);
212+
dev_dbg(ec->dev, "type=%04x flags=%02x rslen=%zu rqlen=%zu\n",
213+
msg->type, msg->flags, msg->response_size, msg->request_size);
225214

226215
mutex_lock(&ec->mailbox_lock);
227216
/* Prepare request packet */

drivers/rtc/rtc-wilco-ec.c

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,20 @@
2121
#define EC_CMOS_TOD_WRITE 0x02
2222
#define EC_CMOS_TOD_READ 0x08
2323

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+
2435
/**
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
2638
* @second: Second value (0..59)
2739
* @minute: Minute value (0..59)
2840
* @hour: Hour value (0..23)
@@ -33,7 +45,8 @@
3345
*
3446
* All values are presented in binary (not BCD).
3547
*/
36-
struct ec_rtc_read {
48+
struct ec_rtc_read_response {
49+
u8 reserved;
3750
u8 second;
3851
u8 minute;
3952
u8 hour;
@@ -44,8 +57,10 @@ struct ec_rtc_read {
4457
} __packed;
4558

4659
/**
47-
* struct ec_rtc_write - Format of RTC sent to the EC.
48-
* @param: EC_CMOS_TOD_WRITE
60+
* struct ec_rtc_write_request - Format of RTC sent to the EC.
61+
* @command: Always EC_COMMAND_CMOS
62+
* @reserved: Unused byte
63+
* @param: Always EC_CMOS_TOD_WRITE
4964
* @century: Century value (full year / 100)
5065
* @year: Year value (full year % 100)
5166
* @month: Month value (1..12)
@@ -57,7 +72,9 @@ struct ec_rtc_read {
5772
*
5873
* All values are presented in BCD.
5974
*/
60-
struct ec_rtc_write {
75+
struct ec_rtc_write_request {
76+
u8 command;
77+
u8 reserved;
6178
u8 param;
6279
u8 century;
6380
u8 year;
@@ -72,19 +89,17 @@ struct ec_rtc_write {
7289
static int wilco_ec_rtc_read(struct device *dev, struct rtc_time *tm)
7390
{
7491
struct wilco_ec_device *ec = dev_get_drvdata(dev->parent);
75-
u8 param = EC_CMOS_TOD_READ;
76-
struct ec_rtc_read rtc;
77-
struct wilco_ec_message msg = {
78-
.type = WILCO_EC_MSG_LEGACY,
79-
.flags = WILCO_EC_FLAG_RAW_RESPONSE,
80-
.command = EC_COMMAND_CMOS,
81-
.request_data = &param,
82-
.request_size = sizeof(param),
83-
.response_data = &rtc,
84-
.response_size = sizeof(rtc),
85-
};
92+
struct ec_rtc_read_response rtc;
93+
struct wilco_ec_message msg;
8694
int ret;
8795

96+
memset(&msg, 0, sizeof(msg));
97+
msg.type = WILCO_EC_MSG_LEGACY;
98+
msg.request_data = &read_rq;
99+
msg.request_size = sizeof(read_rq);
100+
msg.response_data = &rtc;
101+
msg.response_size = sizeof(rtc);
102+
88103
ret = wilco_ec_mailbox(ec, &msg);
89104
if (ret < 0)
90105
return ret;
@@ -106,14 +121,8 @@ static int wilco_ec_rtc_read(struct device *dev, struct rtc_time *tm)
106121
static int wilco_ec_rtc_write(struct device *dev, struct rtc_time *tm)
107122
{
108123
struct wilco_ec_device *ec = dev_get_drvdata(dev->parent);
109-
struct ec_rtc_write rtc;
110-
struct wilco_ec_message msg = {
111-
.type = WILCO_EC_MSG_LEGACY,
112-
.flags = WILCO_EC_FLAG_RAW_RESPONSE,
113-
.command = EC_COMMAND_CMOS,
114-
.request_data = &rtc,
115-
.request_size = sizeof(rtc),
116-
};
124+
struct ec_rtc_write_request rtc;
125+
struct wilco_ec_message msg;
117126
int year = tm->tm_year + 1900;
118127
/*
119128
* Convert from 0=Sunday to 0=Saturday for the EC
@@ -123,6 +132,7 @@ static int wilco_ec_rtc_write(struct device *dev, struct rtc_time *tm)
123132
int wday = tm->tm_wday == 6 ? 0 : tm->tm_wday + 1;
124133
int ret;
125134

135+
rtc.command = EC_COMMAND_CMOS;
126136
rtc.param = EC_CMOS_TOD_WRITE;
127137
rtc.century = bin2bcd(year / 100);
128138
rtc.year = bin2bcd(year % 100);
@@ -133,6 +143,11 @@ static int wilco_ec_rtc_write(struct device *dev, struct rtc_time *tm)
133143
rtc.second = bin2bcd(tm->tm_sec);
134144
rtc.weekday = bin2bcd(wday);
135145

146+
memset(&msg, 0, sizeof(msg));
147+
msg.type = WILCO_EC_MSG_LEGACY;
148+
msg.request_data = &rtc;
149+
msg.request_size = sizeof(rtc);
150+
136151
ret = wilco_ec_mailbox(ec, &msg);
137152
if (ret < 0)
138153
return ret;

0 commit comments

Comments
 (0)