1 /*
2  * Copyright (c) 2020 Google LLC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_INCLUDE_MGMT_EC_HOST_CMD_EC_HOST_CMD_H_
8 #define ZEPHYR_INCLUDE_MGMT_EC_HOST_CMD_EC_HOST_CMD_H_
9 
10 /**
11  * @brief EC Host Command Interface
12  * @defgroup ec_host_cmd_interface EC Host Command Interface
13  * @since 2.4
14  * @version 0.1.0
15  * @ingroup io_interfaces
16  * @{
17  */
18 
19 #include <stdint.h>
20 #include <zephyr/kernel.h>
21 #include <zephyr/mgmt/ec_host_cmd/backend.h>
22 #include <zephyr/sys/__assert.h>
23 #include <zephyr/sys/iterable_sections.h>
24 
25 /**
26  * @brief Host command response codes (16-bit).
27  */
28 enum ec_host_cmd_status {
29 	/** Host command was successful. */
30 	EC_HOST_CMD_SUCCESS = 0,
31 	/** The specified command id is not recognized or supported. */
32 	EC_HOST_CMD_INVALID_COMMAND = 1,
33 	/** Generic Error. */
34 	EC_HOST_CMD_ERROR = 2,
35 	/** One of more of the input request parameters is invalid. */
36 	EC_HOST_CMD_INVALID_PARAM = 3,
37 	/** Host command is not permitted. */
38 	EC_HOST_CMD_ACCESS_DENIED = 4,
39 	/** Response was invalid (e.g. not version 3 of header). */
40 	EC_HOST_CMD_INVALID_RESPONSE = 5,
41 	/** Host command id version unsupported. */
42 	EC_HOST_CMD_INVALID_VERSION = 6,
43 	/** Checksum did not match. */
44 	EC_HOST_CMD_INVALID_CHECKSUM = 7,
45 	/** A host command is currently being processed. */
46 	EC_HOST_CMD_IN_PROGRESS = 8,
47 	/** Requested information is currently unavailable. */
48 	EC_HOST_CMD_UNAVAILABLE = 9,
49 	/** Timeout during processing. */
50 	EC_HOST_CMD_TIMEOUT = 10,
51 	/** Data or table overflow. */
52 	EC_HOST_CMD_OVERFLOW = 11,
53 	/** Header is invalid or unsupported (e.g. not version 3 of header). */
54 	EC_HOST_CMD_INVALID_HEADER = 12,
55 	/** Did not receive all expected request data. */
56 	EC_HOST_CMD_REQUEST_TRUNCATED = 13,
57 	/** Response was too big to send within one response packet. */
58 	EC_HOST_CMD_RESPONSE_TOO_BIG = 14,
59 	/** Error on underlying communication bus. */
60 	EC_HOST_CMD_BUS_ERROR = 15,
61 	/** System busy. Should retry later. */
62 	EC_HOST_CMD_BUSY = 16,
63 	/** Header version invalid. */
64 	EC_HOST_CMD_INVALID_HEADER_VERSION = 17,
65 	/** Header CRC invalid. */
66 	EC_HOST_CMD_INVALID_HEADER_CRC = 18,
67 	/** Data CRC invalid. */
68 	EC_HOST_CMD_INVALID_DATA_CRC = 19,
69 	/** Can't resend response. */
70 	EC_HOST_CMD_DUP_UNAVAILABLE = 20,
71 
72 	EC_HOST_CMD_MAX = UINT16_MAX /* Force enum to be 16 bits. */
73 } __packed;
74 
75 enum ec_host_cmd_log_level {
76 	EC_HOST_CMD_DEBUG_OFF, /* No Host Command debug output */
77 	EC_HOST_CMD_DEBUG_NORMAL, /* Normal output mode; skips repeated commands */
78 	EC_HOST_CMD_DEBUG_EVERY, /* Print every command */
79 	EC_HOST_CMD_DEBUG_PARAMS, /* ... and print params for request/response */
80 	EC_HOST_CMD_DEBUG_MODES /* Number of host command debug modes */
81 };
82 
83 enum ec_host_cmd_state {
84 	EC_HOST_CMD_STATE_DISABLED = 0,
85 	EC_HOST_CMD_STATE_RECEIVING,
86 	EC_HOST_CMD_STATE_PROCESSING,
87 	EC_HOST_CMD_STATE_SENDING,
88 };
89 
90 typedef void (*ec_host_cmd_user_cb_t)(const struct ec_host_cmd_rx_ctx *rx_ctx, void *user_data);
91 typedef enum ec_host_cmd_status (*ec_host_cmd_in_progress_cb_t)(void *user_data);
92 
93 struct ec_host_cmd {
94 	struct ec_host_cmd_rx_ctx rx_ctx;
95 	struct ec_host_cmd_tx_buf tx;
96 	struct ec_host_cmd_backend *backend;
97 	/**
98 	 * The backend gives rx_ready (by calling the ec_host_cmd_send_receive function),
99 	 * when data in rx_ctx are ready. The handler takes rx_ready to read data in rx_ctx.
100 	 */
101 	struct k_sem rx_ready;
102 	/** Status of the rx data checked in the ec_host_cmd_send_received function. */
103 	enum ec_host_cmd_status rx_status;
104 	/**
105 	 * User callback after receiving a command. It is called by the ec_host_cmd_send_received
106 	 * function.
107 	 */
108 	ec_host_cmd_user_cb_t user_cb;
109 	void *user_data;
110 	enum ec_host_cmd_state state;
111 #ifdef CONFIG_EC_HOST_CMD_DEDICATED_THREAD
112 	struct k_thread thread;
113 #endif /* CONFIG_EC_HOST_CMD_DEDICATED_THREAD */
114 };
115 
116 /**
117  * @brief Arguments passed into every installed host command handler
118  */
119 struct ec_host_cmd_handler_args {
120 	/** Reserved for compatibility. */
121 	void *reserved;
122 	/** Command identifier. */
123 	uint16_t command;
124 	/**
125 	 * The version of the host command that is being requested. This will
126 	 * be a value that has been static registered as valid for the handler.
127 	 */
128 	uint8_t version;
129 	/** The incoming data that can be cast to the handlers request type. */
130 	const void *input_buf;
131 	/** The number of valid bytes that can be read from @a input_buf. */
132 	uint16_t input_buf_size;
133 	/** The data written to this buffer will be send to the host. */
134 	void *output_buf;
135 	/** Maximum number of bytes that can be written to the @a output_buf. */
136 	uint16_t output_buf_max;
137 	/** Number of bytes of @a output_buf to send to the host. */
138 	uint16_t output_buf_size;
139 };
140 
141 typedef enum ec_host_cmd_status (*ec_host_cmd_handler_cb)(struct ec_host_cmd_handler_args *args);
142 /**
143  * @brief Structure use for statically registering host command handlers
144  */
145 struct ec_host_cmd_handler {
146 	/** Callback routine to process commands that match @a id. */
147 	ec_host_cmd_handler_cb handler;
148 	/** The numerical command id used as the lookup for commands. */
149 	uint16_t id;
150 	/**
151 	 * The bitfield of all versions that the @a handler supports, where
152 	 * each bit value represents that the @a handler supports that version.
153 	 * E.g. BIT(0) corresponds to version 0.
154 	 */
155 	uint16_t version_mask;
156 	/**
157 	 * The minimum @a input_buf_size enforced by the framework before
158 	 * passing to the handler.
159 	 */
160 	uint16_t min_rqt_size;
161 	/**
162 	 * The minimum @a output_buf_size enforced by the framework before
163 	 * passing to the handler.
164 	 */
165 	uint16_t min_rsp_size;
166 };
167 
168 /**
169  * @brief Statically define and register a host command handler.
170  *
171  * Helper macro to statically define and register a host command handler that
172  * has a compile-time-fixed sizes for its both request and response structures.
173  *
174  * @param _id Id of host command to handle request for.
175  * @param _function Name of handler function.
176  * @param _version_mask The bitfield of all versions that the @a _function
177  *        supports. E.g. BIT(0) corresponds to version 0.
178  * @param _request_type The datatype of the request parameters for @a _function.
179  * @param _response_type The datatype of the response parameters for
180  *        @a _function.
181  */
182 #define EC_HOST_CMD_HANDLER(_id, _function, _version_mask, _request_type, _response_type)          \
183 	const STRUCT_SECTION_ITERABLE(ec_host_cmd_handler, __cmd##_id) = {                         \
184 		.handler = _function,                                                              \
185 		.id = _id,                                                                         \
186 		.version_mask = _version_mask,                                                     \
187 		.min_rqt_size = sizeof(_request_type),                                             \
188 		.min_rsp_size = sizeof(_response_type),                                            \
189 	}
190 
191 /**
192  * @brief Statically define and register a host command handler without sizes.
193  *
194  * Helper macro to statically define and register a host command handler whose
195  * request or response structure size is not known as compile time.
196  *
197  * @param _id Id of host command to handle request for.
198  * @param _function Name of handler function.
199  * @param _version_mask The bitfield of all versions that the @a _function
200  *        supports. E.g. BIT(0) corresponds to version 0.
201  */
202 #define EC_HOST_CMD_HANDLER_UNBOUND(_id, _function, _version_mask)                                 \
203 	const STRUCT_SECTION_ITERABLE(ec_host_cmd_handler, __cmd##_id) = {                         \
204 		.handler = _function,                                                              \
205 		.id = _id,                                                                         \
206 		.version_mask = _version_mask,                                                     \
207 		.min_rqt_size = 0,                                                                 \
208 		.min_rsp_size = 0,                                                                 \
209 	}
210 
211 /**
212  * @brief Header for requests from host to embedded controller
213  *
214  * Represent the over-the-wire header in LE format for host command requests.
215  * This represent version 3 of the host command header. The requests are always
216  * sent from host to embedded controller.
217  */
218 struct ec_host_cmd_request_header {
219 	/**
220 	 * Should be 3. The EC will return EC_HOST_CMD_INVALID_HEADER if it
221 	 * receives a header with a version it doesn't know how to parse.
222 	 */
223 	uint8_t prtcl_ver;
224 	/**
225 	 * Checksum of response and data; sum of all bytes including checksum.
226 	 * Should total to 0.
227 	 */
228 	uint8_t checksum;
229 	/** Id of command that is being sent. */
230 	uint16_t cmd_id;
231 	/**
232 	 * Version of the specific @a cmd_id being requested. Valid
233 	 * versions start at 0.
234 	 */
235 	uint8_t cmd_ver;
236 	/** Unused byte in current protocol version; set to 0. */
237 	uint8_t reserved;
238 	/** Length of data which follows this header. */
239 	uint16_t data_len;
240 } __packed;
241 
242 /**
243  * @brief Header for responses from embedded controller to host
244  *
245  * Represent the over-the-wire header in LE format for host command responses.
246  * This represent version 3 of the host command header. Responses are always
247  * sent from embedded controller to host.
248  */
249 struct ec_host_cmd_response_header {
250 	/** Should be 3. */
251 	uint8_t prtcl_ver;
252 	/**
253 	 * Checksum of response and data; sum of all bytes including checksum.
254 	 * Should total to 0.
255 	 */
256 	uint8_t checksum;
257 	/** A @a ec_host_cmd_status response code for specific command. */
258 	uint16_t result;
259 	/** Length of data which follows this header. */
260 	uint16_t data_len;
261 	/** Unused bytes in current protocol version; set to 0. */
262 	uint16_t reserved;
263 } __packed;
264 
265 /**
266  * @brief Initialize the host command subsystem
267  *
268  * This routine initializes the host command subsystem. It includes initialization
269  * of a backend and the handler.
270  * When the application configures the zephyr,host-cmd-espi-backend/zephyr,host-cmd-shi-backend/
271  * zephyr,host-cmd-uart-backend chosen node and @kconfig{CONFIG_EC_HOST_CMD_INITIALIZE_AT_BOOT} is
272  * set, the chosen backend automatically calls this routine at
273  * @kconfig{CONFIG_EC_HOST_CMD_INIT_PRIORITY}. Applications that require a run-time selection of the
274  * backend must set @kconfig{CONFIG_EC_HOST_CMD_INITIALIZE_AT_BOOT} to n and must explicitly call
275  * this routine.
276  *
277  * @param[in] backend        Pointer to the backend structure to initialize.
278  *
279  * @retval 0 if successful
280  */
281 int ec_host_cmd_init(struct ec_host_cmd_backend *backend);
282 
283 /**
284  * @brief Send the host command response
285  *
286  * This routine sends the host command response. It should be used to send IN_PROGRESS status or
287  * if the host command handler doesn't return e.g. reboot command.
288  *
289  * @param[in] status        Host command status to be sent.
290  * @param[in] args          Pointer of a structure passed to the handler.
291  *
292  * @retval 0 if successful.
293  */
294 int ec_host_cmd_send_response(enum ec_host_cmd_status status,
295 			      const struct ec_host_cmd_handler_args *args);
296 
297 /**
298  * @brief Signal a new host command
299  *
300  * Signal that a new host command has been received. The function should be called by a backend
301  * after copying data to the rx buffer and setting the length.
302  */
303 void ec_host_cmd_rx_notify(void);
304 
305 /**
306  * @brief Install a user callback for receiving a host command
307  *
308  * It allows installing a custom procedure needed by a user after receiving a command.
309  *
310  * @param[in] cb          A callback to be installed.
311  * @param[in] user_data   User data to be passed to the callback.
312  */
313 void ec_host_cmd_set_user_cb(ec_host_cmd_user_cb_t cb, void *user_data);
314 
315 /**
316  * @brief Get the main ec host command structure
317  *
318  * This routine returns a pointer to the main host command structure.
319  * It allows the application code to get inside information for any reason e.g.
320  * the host command thread id.
321  *
322  * @retval A pointer to the main host command structure
323  */
324 const struct ec_host_cmd *ec_host_cmd_get_hc(void);
325 
326 #ifndef CONFIG_EC_HOST_CMD_DEDICATED_THREAD
327 /**
328  * @brief The thread function for Host Command subsystem
329  *
330  * This routine calls the Host Command thread entry function. If
331  * @kconfig{CONFIG_EC_HOST_CMD_DEDICATED_THREAD} is not defined, a new thread is not created,
332  * and this function has to be called by application code. It doesn't return.
333  */
334 FUNC_NORETURN void ec_host_cmd_task(void);
335 #endif
336 
337 #ifdef CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS
338 /**
339  * @brief Check if a Host Command that sent EC_HOST_CMD_IN_PROGRESS status has ended.
340  *
341  * A Host Command that sends EC_HOST_CMD_IN_PROGRESS status doesn't send a final result.
342  * The final result can be get with the ec_host_cmd_send_in_progress_status function.
343  *
344  * @retval true if the Host Command endded
345  */
346 bool ec_host_cmd_send_in_progress_ended(void);
347 
348 /**
349  * @brief Get final result of a last Host Command that has sent EC_HOST_CMD_IN_PROGRESS status.
350  *
351  * A Host Command that sends EC_HOST_CMD_IN_PROGRESS status doesn't send a final result.
352  * Get the saved status with this function. The status can be get only once. Further calls return
353  * EC_HOST_CMD_UNAVAILABLE.
354  *
355  * Saving status of Host Commands that send response data is not supported.
356  *
357  * @retval The final status or EC_HOST_CMD_UNAVAILABLE if not available.
358  */
359 enum ec_host_cmd_status ec_host_cmd_send_in_progress_status(void);
360 
361 /**
362  * @brief Continue processing a handler in callback after returning EC_HOST_CMD_IN_PROGRESS.
363  *
364  * A Host Command handler may return the EC_HOST_CMD_IN_PROGRESS, but needs to continue work.
365  * This function should be called before returning EC_HOST_CMD_IN_PROGRESS with a callback that
366  * will be executed. The return status of the callback will be stored and can be get with the
367  * ec_host_cmd_send_in_progress_status function. The ec_host_cmd_send_in_progress_ended function
368  * can be used to check if the callback has ended.
369  *
370  * @param[in] cb          A callback to be called after returning from a command handler.
371  * @param[in] user_data   User data to be passed to the callback.
372  *
373  * @retval EC_HOST_CMD_BUSY if any command is already in progress, EC_HOST_CMD_SUCCESS otherwise
374  */
375 enum ec_host_cmd_status ec_host_cmd_send_in_progress_continue(ec_host_cmd_in_progress_cb_t cb,
376 							      void *user_data);
377 #endif /* CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS */
378 
379 /**
380  * @brief Add a suppressed command.
381  *
382  * Suppressed commands are not logged. Add a command to be suppressed.
383  *
384  * @param[in] cmd_id        A command id to be suppressed.
385  *
386  * @retval 0 if successful, -EIO if exceeded max number of suppressed commands.
387  */
388 int ec_host_cmd_add_suppressed(uint16_t cmd_id);
389 
390 /**
391  * @}
392  */
393 
394 #endif /* ZEPHYR_INCLUDE_MGMT_EC_HOST_CMD_EC_HOST_CMD_H_ */
395