From 2d0a784c4173ce213009fbf257cb82888c9b79bf Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Fri, 18 Nov 2022 12:08:33 +0000 Subject: [PATCH] subsys/mgmt/ec_host_cmd: rework Host Command support Rework the Host Command support. It includes: -change API to backend -change a way of defining rx and tx buffers -fix synchronization between the handler and backend layer -simplify the HC handler Signed-off-by: Dawid Niedzwiecki --- MAINTAINERS.yml | 11 + boards/posix/native_posix/native_posix.dts | 6 - doc/hardware/peripherals/ec_host_cmd.rst | 13 - doc/hardware/peripherals/index.rst | 1 - doc/services/device_mgmt/ec_host_cmd.png | Bin 0 -> 7735 bytes doc/services/device_mgmt/ec_host_cmd.rst | 67 ++++ doc/services/device_mgmt/ec_host_cmd_shi.png | Bin 0 -> 6540 bytes doc/services/device_mgmt/index.rst | 1 + .../zephyr,ec-host-cmd-periph-espi.yaml | 15 - .../zephyr,sim-ec-host-cmd-periph.yaml | 7 - include/zephyr/mgmt/ec_host_cmd/backend.h | 135 +++++--- include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h | 106 +++--- include/zephyr/mgmt/ec_host_cmd/simulator.h | 5 +- subsys/mgmt/ec_host_cmd/CMakeLists.txt | 3 +- subsys/mgmt/ec_host_cmd/Kconfig | 49 ++- subsys/mgmt/ec_host_cmd/backends/Kconfig | 26 +- .../backends/ec_host_cmd_backend_espi.c | 176 ++++++---- .../backends/ec_host_cmd_backend_shi.h | 6 +- .../backends/ec_host_cmd_backend_shi_ite.c | 118 ++++--- .../backends/ec_host_cmd_backend_shi_npcx.c | 109 +++--- .../backends/ec_host_cmd_backend_simulator.c | 79 +++-- subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c | 326 ++++++++++-------- tests/subsys/mgmt/ec_host_cmd/prj.conf | 1 - tests/subsys/mgmt/ec_host_cmd/src/main.c | 17 +- 24 files changed, 758 insertions(+), 519 deletions(-) delete mode 100644 doc/hardware/peripherals/ec_host_cmd.rst create mode 100644 doc/services/device_mgmt/ec_host_cmd.png create mode 100644 doc/services/device_mgmt/ec_host_cmd.rst create mode 100644 doc/services/device_mgmt/ec_host_cmd_shi.png delete mode 100644 dts/bindings/ec_host_cmd_backend/zephyr,ec-host-cmd-periph-espi.yaml delete mode 100644 dts/bindings/ec_host_cmd_backend/zephyr,sim-ec-host-cmd-periph.yaml diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 174baa5705..bc180535cb 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1314,6 +1314,17 @@ Release Notes: labels: - "area: Virtualization" +EC Host Commands: + status: maintained + maintainers: + - semihalf-niedzwiecki-dawid + files: + - subsys/mgmt/ec_host_cmd/ + - include/zephyr/mgmt/ec_host_cmd/ + - tests/subsys/mgmt/ec_host_cmd/ + labels: + - "area: ec_host_cmd" + Xen Platform: status: maintained maintainers: diff --git a/boards/posix/native_posix/native_posix.dts b/boards/posix/native_posix/native_posix.dts index c4c7a6aa4f..aa11130a73 100644 --- a/boards/posix/native_posix/native_posix.dts +++ b/boards/posix/native_posix/native_posix.dts @@ -20,7 +20,6 @@ zephyr,flash = &flash0; zephyr,entropy = &rng; zephyr,flash-controller = &flashcontroller0; - zephyr,ec-host-interface = &hcp; zephyr,display = &sdl_dc; zephyr,canbus = &can_loopback0; zephyr,keyboard-scan = &sdl_kscan; @@ -156,11 +155,6 @@ compatible = "zephyr,native-posix-counter"; }; - hcp: ec-host-cmd-backend { - status = "okay"; - compatible = "zephyr,sim-ec-host-cmd-backend"; - }; - gpio0: gpio@800 { status = "okay"; compatible = "zephyr,gpio-emul"; diff --git a/doc/hardware/peripherals/ec_host_cmd.rst b/doc/hardware/peripherals/ec_host_cmd.rst deleted file mode 100644 index 90c55b72b0..0000000000 --- a/doc/hardware/peripherals/ec_host_cmd.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. _ec_host_cmd_backend_api: - -EC Host Command -############### - -Overview -******** - - -API Reference -************* - -.. doxygengroup:: ec_host_cmd_backend_interface diff --git a/doc/hardware/peripherals/index.rst b/doc/hardware/peripherals/index.rst index 6d02e72562..8d860cc2c9 100644 --- a/doc/hardware/peripherals/index.rst +++ b/doc/hardware/peripherals/index.rst @@ -15,7 +15,6 @@ Peripherals dac.rst display/index.rst dma.rst - ec_host_cmd.rst edac/index.rst eeprom.rst entropy.rst diff --git a/doc/services/device_mgmt/ec_host_cmd.png b/doc/services/device_mgmt/ec_host_cmd.png new file mode 100644 index 0000000000000000000000000000000000000000..70def63de2e6e79b2ef999fb3a23a46f034a0d4c GIT binary patch literal 7735 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 literal 0 HcmV?d00001 diff --git a/doc/services/device_mgmt/ec_host_cmd.rst b/doc/services/device_mgmt/ec_host_cmd.rst new file mode 100644 index 0000000000..a20193ae65 --- /dev/null +++ b/doc/services/device_mgmt/ec_host_cmd.rst @@ -0,0 +1,67 @@ +.. _ec_host_cmd_backend_api: + +EC Host Command +############### + +Overview +******** +The host command protocol defines the interface for a host, or application processor, to +communicate with a target embedded controller (EC). The EC Host command subsystem implements the +target side of the protocol, generating responses to commands sent by the host. The host command +protocol interface supports multiple versions, but this subsystem implementation only support +protocol version 3. + +Architecture +************ +The Host Command subsystem contains a few components: + * Backend + * General handler + * Command handler + +The backend is a layer between a peripheral driver and the general handler. It is responsible for +sending and receiving commands via chosen peripheral. + +The general handler validates data from the backend e.g. check sizes, checksum, etc. If the command +is valid and the user has provided a handler for a received command id, the command handler is +called. + +.. image:: ec_host_cmd.png + :align: center + +SHI (Serial Host Interface) is different to this because it is used olny for communication with a +host. SHI does not have API itself, thus the backend and peripheral driver layers are combined into +one backend layer. + +.. image:: ec_host_cmd_shi.png + :align: center + +The supported backend and peripheral drivers: + * Simulator + * SHI - ITE and NPCX + * eSPI - any eSPI slave driver that support :kconfig:option:`CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD` and + :kconfig:option:`CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE` + +Initialization +************** + +If the application configures the ``zephyr,host-cmd-backend`` chosen node, then the backend +automatically initializes the host command subsystem by calling :c:func:`ec_host_cmd_init`. + +If ``zephyr,host-cmd-backend`` is not chosen, the :c:func:`ec_host_cmd_init` function should be +called by application code. This way of initialization is useful if a backend is chosen in runtime +based on e.g. GPIO state. + +Buffers +******* + +The host command communication requires buffers for rx and tx. The buffers are be provided by the +general handler if :kconfig:option:`CONFIG_EC_HOST_CMD_HANDLER_RX_BUFFER` > 0 for rx buffer and +:kconfig:option:`CONFIG_EC_HOST_CMD_HANDLER_TX_BUFFER` > 0 for the tx buffer. The shared buffers are +useful for applications that use multiple backends. Defining separate buffers by every backend would +increase the memory usage. However, some buffers can be defined by a peripheral driver e.g. eSPI. +These ones should be reused as much as possible. + +API Reference +************* + +.. doxygengroup:: ec_host_cmd_interface diff --git a/doc/services/device_mgmt/ec_host_cmd_shi.png b/doc/services/device_mgmt/ec_host_cmd_shi.png new file mode 100644 index 0000000000000000000000000000000000000000..71b18a021f045a5f4482c1b224d089c1dfb51c32 GIT binary patch literal 6540 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 a^^uZquVAsgE@^kAg49&BmES5^Mg9jh*AX57 literal 0 HcmV?d00001 diff --git a/doc/services/device_mgmt/index.rst b/doc/services/device_mgmt/index.rst index 58f00b0af8..e50acf7248 100644 --- a/doc/services/device_mgmt/index.rst +++ b/doc/services/device_mgmt/index.rst @@ -13,6 +13,7 @@ Device Management smp_transport.rst dfu.rst ota.rst + ec_host_cmd.rst SMP Groups ========== diff --git a/dts/bindings/ec_host_cmd_backend/zephyr,ec-host-cmd-periph-espi.yaml b/dts/bindings/ec_host_cmd_backend/zephyr,ec-host-cmd-periph-espi.yaml deleted file mode 100644 index 603aeaa3d4..0000000000 --- a/dts/bindings/ec_host_cmd_backend/zephyr,ec-host-cmd-periph-espi.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -description: Host Command Backend using the eSPI bus - -compatible: "zephyr,ec-host-cmd-backend-espi" - -include: base.yaml - -properties: - bus: - required: true - type: phandle - description: - Phandle to the eSPI bus which will be used for communication with AP - by the host commands subsystem diff --git a/dts/bindings/ec_host_cmd_backend/zephyr,sim-ec-host-cmd-periph.yaml b/dts/bindings/ec_host_cmd_backend/zephyr,sim-ec-host-cmd-periph.yaml deleted file mode 100644 index 7c90bc63d7..0000000000 --- a/dts/bindings/ec_host_cmd_backend/zephyr,sim-ec-host-cmd-periph.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -description: Simulated Host Command Peripheral - -compatible: "zephyr,sim-ec-host-cmd-backend" - -include: base.yaml diff --git a/include/zephyr/mgmt/ec_host_cmd/backend.h b/include/zephyr/mgmt/ec_host_cmd/backend.h index f6a63f2fbd..1090370108 100644 --- a/include/zephyr/mgmt/ec_host_cmd/backend.h +++ b/include/zephyr/mgmt/ec_host_cmd/backend.h @@ -21,47 +21,88 @@ extern "C" { #endif +struct ec_host_cmd_backend { + /** API provided by the backed. */ + const struct ec_host_cmd_backend_api *api; + /** Context for the backed. */ + void *ctx; +}; + /** - * @brief Host Command Backend API - * @defgroup ec_host_cmd_backend Host Command Backend API + * @brief EC Host Command Interface + * @defgroup ec_host_cmd_interface EC Host Command Interface * @ingroup io_interfaces * @{ */ /** - * @brief Context for host command backend and framework to pass rx data + * @brief Context for host command backend and handler to pass rx data. */ struct ec_host_cmd_rx_ctx { - /** Buffer written to by device (when dev_owns) and read from by - * command framework and handler (when handler_owns). Buffer is owned - * by devices and lives as long as device is valid. Device will never - * read from this buffer (for security reasons). + /** + * Buffer to hold received data. The buffer is provided by the handler if + * CONFIG_EC_HOST_CMD_HANDLER_RX_BUFFER > 0. Otherwise, the backend should provide + * the buffer on its own and overwrites @a buf pointer in the init function. */ uint8_t *buf; - /** Number of bytes written to @a buf by device (when dev_owns). */ - size_t *len; - /** Device will take when it needs to write to @a buf and @a size. */ - struct k_sem *dev_owns; - /** Handler will take so it can read @a buf and @a size */ - struct k_sem *handler_owns; + /** Number of bytes written to @a buf by backend. */ + size_t len; + /** + * The backend gives @a handler_owns, when data in @a buf are ready. + * The handler takes @a handler_owns to read data in @a buf. + */ + struct k_sem handler_owns; }; /** - * @brief Context for host command backend and framework to pass tx data + * @brief Context for host command backend and handler to pass tx data */ struct ec_host_cmd_tx_buf { - /** Data to write to the host */ + /** + * Data to write to the host The buffer is provided by the handler if + * CONFIG_EC_HOST_CMD_HANDLER_TX_BUFFER > 0. Otherwise, the backend should provide + * the buffer on its own and overwrites @a buf pointer and @a len_max + * in the init function. + */ void *buf; - /** Number of bytes to write from @a buf */ + /** Number of bytes to write from @a buf. */ size_t len; + /** Size of @a buf. */ + size_t len_max; }; -typedef int (*ec_host_cmd_backend_api_init)( - const struct device *dev, struct ec_host_cmd_rx_ctx *rx_ctx); +/** + * @brief Initialize a host command backend + * + * This routine initializes a host command backend. It includes initialization + * a device used to communication and setting up buffers. + * This function is called by the ec_host_cmd_init function. + * + * @param[in] backend Pointer to the backend structure for the driver instance. + * @param[in,out] rx_ctx Pointer to the receive context object. These objects are used to receive + * data from the driver when the host sends data. The buf member can be + * assigned by the backend. + * @param[in,out] tx Pointer to the transmit buffer object. The buf and len_max members can be + * assigned by the backend. These objects are used to send data by the + * backend with the ec_host_cmd_backend_api_send function. + * + * @retval 0 if successful + */ +typedef int (*ec_host_cmd_backend_api_init)(const struct ec_host_cmd_backend *backend, + struct ec_host_cmd_rx_ctx *rx_ctx, + struct ec_host_cmd_tx_buf *tx); -typedef int (*ec_host_cmd_backend_api_send)( - const struct device *dev, - const struct ec_host_cmd_tx_buf *tx_buf); +/** + * @brief Sends data to the host + * + * Sends data from tx buf that was passed via ec_host_cmd_backend_api_init + * function. + * + * @param backend Pointer to the backed to send data. + * + * @retval 0 if successful. + */ +typedef int (*ec_host_cmd_backend_api_send)(const struct ec_host_cmd_backend *backend); __subsystem struct ec_host_cmd_backend_api { ec_host_cmd_backend_api_init init; @@ -69,50 +110,30 @@ __subsystem struct ec_host_cmd_backend_api { }; /** - * @brief Initialize a host command device + * @brief Get the eSPI Host Command backend pointer * - * This routine initializes a host command device, prior to its first use. The - * receive context object are an output of this function and are valid - * for the lifetime of this device. The RX context is used by the client to - * receive data from the host. + * Get the eSPI pointer backend and pass a pointer to eSPI device instance that will be used for + * the Host Command communication. * - * @param dev Pointer to the device structure for the driver instance. - * @param rx_ctx [out] The receiving context object that are valid for the - * lifetime of the device. These objects are used to receive data - * from the driver when the host send data. + * @param dev Pointer to eSPI device instance. * - * @retval 0 if successful + * @retval The eSPI backend pointer. */ -static inline int -ec_host_cmd_backend_init(const struct device *dev, - struct ec_host_cmd_rx_ctx *rx_ctx) -{ - const struct ec_host_cmd_backend_api *api = - (const struct ec_host_cmd_backend_api *)dev->api; - - return api->init(dev, rx_ctx); -} +struct ec_host_cmd_backend *ec_host_cmd_backend_get_espi(const struct device *dev); /** - * @brief Sends the specified data to the host + * @brief Get the SHI NPCX Host Command backend pointer * - * Sends the data specified in @a tx_buf to the host over the host communication - * bus. - * - * @param dev Pointer to the device structure for the driver instance. - * @param tx_buf The data to transmit to the host. - * - * @retval 0 if successful + * @retval the SHI NPCX backend pointer */ -static inline int ec_host_cmd_backend_send( - const struct device *dev, - const struct ec_host_cmd_tx_buf *tx_buf) -{ - const struct ec_host_cmd_backend_api *api = - (const struct ec_host_cmd_backend_api *)dev->api; +struct ec_host_cmd_backend *ec_host_cmd_backend_get_shi_npcx(void); - return api->send(dev, tx_buf); -} +/** + * @brief Get the SHI ITE Host Command backend pointer + * + * @retval the SHI ITE backend pointer + */ +struct ec_host_cmd_backend *ec_host_cmd_backend_get_shi_ite(void); /** * @} @@ -122,4 +143,4 @@ static inline int ec_host_cmd_backend_send( } #endif -#endif /* ZEPHYR_INCLUDE_MGMT_EC_HOST_CMD_BACKEND_H_ */ +#endif /* ZEPHYR_INCLUDE_MGMT_EC_HOST_CMD_EC_HOST_CMD_BACKEND_H_ */ diff --git a/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h b/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h index 937893fe6b..2ecffb9363 100644 --- a/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h +++ b/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h @@ -9,14 +9,23 @@ /** * @brief EC Host Command Interface - * @defgroup ec_host_cmd_backend_interface EC Host Command Interface + * @defgroup ec_host_cmd_interface EC Host Command Interface * @ingroup io_interfaces * @{ */ #include +#include #include +struct ec_host_cmd { + struct ec_host_cmd_rx_ctx rx_ctx; + struct ec_host_cmd_tx_buf tx; + struct ec_host_cmd_backend *backend; + struct k_thread *thread; + k_thread_stack_t *stack; +}; + /** * @brief Arguments passed into every installed host command handler */ @@ -29,21 +38,20 @@ struct ec_host_cmd_handler_args { * The version of the host command that is being requested. This will * be a value that has been static registered as valid for the handler. */ - const uint8_t version; + uint8_t version; /** The incoming data that can be cast to the handlers request type. */ - const void *const input_buf; + const void *input_buf; /** The number of valid bytes that can be read from @a input_buf. */ - const uint16_t input_buf_size; + uint16_t input_buf_size; /** The data written to this buffer will be send to the host. */ - void *const output_buf; + void *output_buf; /** Maximum number of bytes that can be written to the @a output_buf. */ uint16_t output_buf_max; /** Number of bytes of @a output_buf to send to the host. */ uint16_t output_buf_size; }; -typedef enum ec_host_cmd_status (*ec_host_cmd_handler_cb)( - struct ec_host_cmd_handler_args *args); +typedef enum ec_host_cmd_status (*ec_host_cmd_handler_cb)(struct ec_host_cmd_handler_args *args); /** * @brief Structure use for statically registering host command handlers */ @@ -52,23 +60,25 @@ struct ec_host_cmd_handler { ec_host_cmd_handler_cb handler; /** The numerical command id used as the lookup for commands. */ uint16_t id; - /** The bitfield of all versions that the @a handler supports, where - * each bit value represents that the @a handler supports that version. - * E.g. BIT(0) corresponds to version 0. + /** + * The bitfield of all versions that the @a handler supports, where + * each bit value represents that the @a handler supports that version. + * E.g. BIT(0) corresponds to version 0. */ uint16_t version_mask; - /** The minimum @a input_buf_size enforced by the framework before - * passing to the handler. + /** + * The minimum @a input_buf_size enforced by the framework before + * passing to the handler. */ uint16_t min_rqt_size; - /** The minimum @a output_buf_size enforced by the framework before - * passing to the handler. + /** + * The minimum @a output_buf_size enforced by the framework before + * passing to the handler. */ uint16_t min_rsp_size; }; /** - * * @brief Statically define and register a host command handler. * * Helper macro to statically define and register a host command handler that @@ -82,18 +92,16 @@ struct ec_host_cmd_handler { * @param _response_type The datatype of the response parameters for * @a _function. */ -#define EC_HOST_CMD_HANDLER(_id, _function, _version_mask, _request_type, \ - _response_type) \ - const STRUCT_SECTION_ITERABLE(ec_host_cmd_handler, __cmd##_id) = { \ - .id = _id, \ - .handler = _function, \ - .version_mask = _version_mask, \ - .min_rqt_size = sizeof(_request_type), \ - .min_rsp_size = sizeof(_response_type), \ +#define EC_HOST_CMD_HANDLER(_id, _function, _version_mask, _request_type, _response_type) \ + const STRUCT_SECTION_ITERABLE(ec_host_cmd_handler, __cmd##_id) = { \ + .id = _id, \ + .handler = _function, \ + .version_mask = _version_mask, \ + .min_rqt_size = sizeof(_request_type), \ + .min_rsp_size = sizeof(_response_type), \ } /** - * * @brief Statically define and register a host command handler without sizes. * * Helper macro to statically define and register a host command handler whose @@ -104,13 +112,13 @@ struct ec_host_cmd_handler { * @param _version_mask The bitfield of all versions that the @a _function * supports. E.g. BIT(0) corresponds to version 0. */ -#define EC_HOST_CMD_HANDLER_UNBOUND(_id, _function, _version_mask) \ - const STRUCT_SECTION_ITERABLE(ec_host_cmd_handler, __cmd##_id) = { \ - .id = _id, \ - .handler = _function, \ - .version_mask = _version_mask, \ - .min_rqt_size = 0, \ - .min_rsp_size = 0, \ +#define EC_HOST_CMD_HANDLER_UNBOUND(_id, _function, _version_mask) \ + const STRUCT_SECTION_ITERABLE(ec_host_cmd_handler, __cmd##_id) = { \ + .id = _id, \ + .handler = _function, \ + .version_mask = _version_mask, \ + .min_rqt_size = 0, \ + .min_rsp_size = 0, \ } /** @@ -121,18 +129,21 @@ struct ec_host_cmd_handler { * sent from host to embedded controller. */ struct ec_host_cmd_request_header { - /** Should be 3. The EC will return EC_HOST_CMD_INVALID_HEADER if it - * receives a header with a version it doesn't know how to parse. + /** + * Should be 3. The EC will return EC_HOST_CMD_INVALID_HEADER if it + * receives a header with a version it doesn't know how to parse. */ uint8_t prtcl_ver; - /** Checksum of response and data; sum of all bytes including checksum. - * Should total to 0. + /** + * Checksum of response and data; sum of all bytes including checksum. + * Should total to 0. */ uint8_t checksum; /** Id of command that is being sent. */ uint16_t cmd_id; - /** Version of the specific @a cmd_id being requested. Valid - * versions start at 0. + /** + * Version of the specific @a cmd_id being requested. Valid + * versions start at 0. */ uint8_t cmd_ver; /** Unused byte in current protocol version; set to 0. */ @@ -151,8 +162,9 @@ struct ec_host_cmd_request_header { struct ec_host_cmd_response_header { /** Should be 3. */ uint8_t prtcl_ver; - /** Checksum of response and data; sum of all bytes including checksum. - * Should total to 0. + /** + * Checksum of response and data; sum of all bytes including checksum. + * Should total to 0. */ uint8_t checksum; /** A @a ec_host_cmd_status response code for specific command. */ @@ -213,6 +225,22 @@ enum ec_host_cmd_status { EC_HOST_CMD_MAX = UINT16_MAX /* Force enum to be 16 bits. */ } __packed; +/** + * @brief Initialize the host command subsystem + * + * This routine initializes the host command subsystem. It includes initialization + * of a backend and the handler. + * When the application configures the zephyr,host-cmd-backend chosen node, the chosen backend + * automatically calls this routine at CONFIG_EC_HOST_CMD_INIT_PRIORITY. + * Applications that require a run-time selection of the backend must leave + * zephyr,host-cmd-backend undefined and must explicitly call this routine. + * + * @param[in] backend Pointer to the backend structure to initialize. + * + * @retval 0 if successful + */ +int ec_host_cmd_init(struct ec_host_cmd_backend *backend); + /** * @} */ diff --git a/include/zephyr/mgmt/ec_host_cmd/simulator.h b/include/zephyr/mgmt/ec_host_cmd/simulator.h index 083229fb1b..7b44259afe 100644 --- a/include/zephyr/mgmt/ec_host_cmd/simulator.h +++ b/include/zephyr/mgmt/ec_host_cmd/simulator.h @@ -25,8 +25,11 @@ * will override the first callback installation. * * @param cb Callback that is called when device would send data to host. + * @param tx_buf Pointer of a pointer to the tx buf structure where data will + * be sent. */ -void ec_host_cmd_backend_sim_install_send_cb(ec_host_cmd_backend_api_send cb); +void ec_host_cmd_backend_sim_install_send_cb(ec_host_cmd_backend_api_send cb, + struct ec_host_cmd_tx_buf **tx_buf); /** * @brief Simulate receiving data from host as passed in to this function diff --git a/subsys/mgmt/ec_host_cmd/CMakeLists.txt b/subsys/mgmt/ec_host_cmd/CMakeLists.txt index eeaafe774a..d37d4c70fb 100644 --- a/subsys/mgmt/ec_host_cmd/CMakeLists.txt +++ b/subsys/mgmt/ec_host_cmd/CMakeLists.txt @@ -1,6 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_library() + zephyr_library_sources(ec_host_cmd_handler.c) -add_subdirectory_ifdef(CONFIG_EC_HOST_CMD_BACKEND backends) +add_subdirectory(backends) diff --git a/subsys/mgmt/ec_host_cmd/Kconfig b/subsys/mgmt/ec_host_cmd/Kconfig index 1b84864fb9..d2582d6f08 100644 --- a/subsys/mgmt/ec_host_cmd/Kconfig +++ b/subsys/mgmt/ec_host_cmd/Kconfig @@ -9,20 +9,39 @@ config EC_HOST_CMD bool "Support Embedded Controller host command handler subsystem" help Enable host command processing for embedded controllers on notebook - computers. Enabling this option requires specifying a chosen - zephyr,ec-host-interface device as the ec host command backend that - receive incoming host command requests to process. + computers. if EC_HOST_CMD +module = EC_HC +module-str = ec-host-commands +source "subsys/logging/Kconfig.template.log_config" + config EC_HOST_CMD_HANDLER_STACK_SIZE int "Stack size for the EC host command handler thread" default 800 config EC_HOST_CMD_HANDLER_TX_BUFFER int "Buffer size in bytes for TX buffer shared by all EC host commands" - default EC_HOST_CMD_BACKEND_SHI_MAX_RESPONSE if EC_HOST_CMD_BACKEND_SHI + default 0 if EC_HOST_CMD_BACKEND_ESPI + default 0 if EC_HOST_CMD_BACKEND_SHI default 256 + help + Buffer size in bytes for TX buffer defined by the host command handler. + Some backend layers can define their own buffer, so the size can be zero to + avoid duplicating buffers. If multiple backends are used, the size has to be + set by user to the largest one. + +config EC_HOST_CMD_HANDLER_RX_BUFFER + int "Buffer size in bytes for RX buffer shared by all EC host commands" + default 256 if EC_HOST_CMD_BACKEND_ESPI + default 0 if EC_HOST_CMD_BACKEND_SHI + default 256 + help + Buffer size in bytes for TX buffer defined by the host command handler. + Some backend layers can define their own buffer, so the size can be zero to + avoid duplicating buffers. If multiple backends are used, the size has to be + set by user to the largest one. config EC_HOST_CMD_HANDLER_PRIO int "Priority of host command task" @@ -33,8 +52,28 @@ config EC_HOST_CMD_HANDLER_PRIO process the command on time and the AP will abort the waiting for response and be unable to boot the system properly. -source "subsys/mgmt/ec_host_cmd/backends/Kconfig" +config EC_HOST_CMD_INIT_PRIORITY + int "Initialization priority" + default 60 + range 0 99 + help + Initialization priority for Host Command. It must be higher than the initialization + priority of the used backend device. + +config EC_HOST_CMD_HANDLER_TX_BUFFER_DEF + bool + default y if EC_HOST_CMD_HANDLER_TX_BUFFER > 0 + help + The handler defines common tx buffer + +config EC_HOST_CMD_HANDLER_RX_BUFFER_DEF + bool + default y if EC_HOST_CMD_HANDLER_RX_BUFFER > 0 + help + The handler defines common rx buffer endif # EC_HOST_CMD +source "subsys/mgmt/ec_host_cmd/backends/Kconfig" + endmenu diff --git a/subsys/mgmt/ec_host_cmd/backends/Kconfig b/subsys/mgmt/ec_host_cmd/backends/Kconfig index 846f07fc28..127d59edb0 100644 --- a/subsys/mgmt/ec_host_cmd/backends/Kconfig +++ b/subsys/mgmt/ec_host_cmd/backends/Kconfig @@ -1,26 +1,11 @@ +# Host Command backend configs + # Copyright (c) 2020 Google LLC # SPDX-License-Identifier: Apache-2.0 -menuconfig EC_HOST_CMD_BACKEND - bool "Embedded Controller Host Command backend support" - depends on EC_HOST_CMD - help - Enable the embedded controller host command backend driver. This - is needed by the EC host command framework to send and receive data - on the appropriate EC host bus. - -if EC_HOST_CMD_BACKEND - -module = EC_HC -module-str = ec-host-commands -source "subsys/logging/Kconfig.template.log_config" - -choice EC_HOST_CMD_BACKEND_TYPE - prompt "Host commands backend" - config EC_HOST_CMD_BACKEND_SIMULATOR bool "Embedded Controller Host Command Backend Simulator" - depends on DT_HAS_ZEPHYR_SIM_EC_HOST_CMD_BACKEND_ENABLED + depends on SOC_POSIX help Enable the EC host command simulator. @@ -28,7 +13,6 @@ config EC_HOST_CMD_BACKEND_ESPI bool "Host commands support using eSPI bus" depends on ESPI_PERIPHERAL_EC_HOST_CMD depends on ESPI_PERIPHERAL_CUSTOM_OPCODE - depends on DT_HAS_ZEPHYR_EC_HOST_CMD_BACKEND_ESPI_ENABLED help Enable support for Embedded Controller host commands using the eSPI bus. @@ -39,8 +23,6 @@ config EC_HOST_CMD_BACKEND_SHI Enable support for Embedded Controller host commands using the Serial Host Interface. -endchoice - if EC_HOST_CMD_BACKEND_SHI choice EC_HOST_CMD_BACKEND_SHI_DRIVER @@ -83,5 +65,3 @@ config EC_HOST_CMD_BACKEND_SHI_MAX_RESPONSE command, flash read offset/size, and 512 bytes of flash data. endif # EC_HOST_CMD_BACKEND_SHI - -endif # EC_HOST_CMD_BACKEND diff --git a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_espi.c b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_espi.c index bcb50f3be8..a7ca10cacc 100644 --- a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_espi.c +++ b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_espi.c @@ -4,103 +4,157 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT zephyr_ec_host_cmd_backend_espi - #include #include #include +#include #include #include -BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "Invalid number of eSPI backends"); +LOG_MODULE_REGISTER(host_cmd_espi, CONFIG_EC_HC_LOG_LEVEL); -#define ESPI_BUS DT_PHANDLE(DT_DRV_INST(0), bus) -#define ESPI_DEVICE DEVICE_DT_GET(ESPI_BUS) +#define RX_HEADER_SIZE (sizeof(struct ec_host_cmd_request_header)) -struct ec_host_cmd_backend_espi_data { - struct k_sem handler_owns; - struct k_sem dev_owns; - uint32_t rx_buffer_len; - struct espi_callback espi_cb; - uint8_t *espi_shm; +/* eSPI Host Command state */ +enum ec_host_cmd_espi_state { + /* Interface is disabled */ + ESPI_STATE_DISABLED, + /* Ready to receive next request */ + ESPI_STATE_READY_TO_RECV, + /* Processing request */ + ESPI_STATE_PROCESSING, + /* Processing request */ + ESPI_STATE_SENDING, + ESPI_STATE_COUNT, }; -static void ec_host_cmd_backend_espi_handler(const struct device *dev, struct espi_callback *cb, - struct espi_event espi_evt) +struct ec_host_cmd_espi_ctx { + /* eSPI device instance */ + const struct device *espi_dev; + /* Context for read operation */ + struct ec_host_cmd_rx_ctx *rx_ctx; + /* Transmit buffer */ + struct ec_host_cmd_tx_buf *tx; + /* eSPI callback */ + struct espi_callback espi_cb; + /* eSPI Host Command state */ + enum ec_host_cmd_espi_state state; +}; + +#define EC_HOST_CMD_ESPI_DEFINE(_name) \ + static struct ec_host_cmd_espi_ctx _name##_hc_espi; \ + struct ec_host_cmd_backend _name = { \ + .api = &ec_host_cmd_api, \ + .ctx = (struct ec_host_cmd_espi_ctx *)&_name##_hc_espi, \ + } + +static void espi_handler(const struct device *dev, struct espi_callback *cb, + struct espi_event espi_evt) { - struct ec_host_cmd_backend_espi_data *data = - CONTAINER_OF(cb, struct ec_host_cmd_backend_espi_data, espi_cb); + struct ec_host_cmd_espi_ctx *hc_espi = + CONTAINER_OF(cb, struct ec_host_cmd_espi_ctx, espi_cb); uint16_t event_type = (uint16_t)espi_evt.evt_details; + /* tx stores the shared memory buf pointer and size, so use it */ + const struct ec_host_cmd_request_header *rx_header = hc_espi->tx->buf; + const size_t shared_size = hc_espi->tx->len_max; + const uint16_t rx_valid_data_size = rx_header->data_len + RX_HEADER_SIZE; if (event_type != ESPI_PERIPHERAL_EC_HOST_CMD) { return; } - if (k_sem_take(&data->dev_owns, K_NO_WAIT) != 0) { - int res = EC_HOST_CMD_IN_PROGRESS; - - espi_write_lpc_request(ESPI_DEVICE, ECUSTOM_HOST_CMD_SEND_RESULT, &res); + /* Make sure we've received a Host Command in a good state not to override buffers for + * a Host Command that is currently being processed. There is a moment between sending + * a response and setting state to ESPI_STATE_READY_TO_RECV when we can receive a new + * host command, so accept the sending state as well. + */ + if (hc_espi->state != ESPI_STATE_READY_TO_RECV && hc_espi->state != ESPI_STATE_SENDING) { + LOG_ERR("Received HC in bad state"); return; } - k_sem_give(&data->handler_owns); -} - -int ec_host_cmd_backend_espi_init(const struct device *dev, struct ec_host_cmd_rx_ctx *rx_ctx) -{ - struct ec_host_cmd_backend_espi_data *data = dev->data; - - if (rx_ctx == NULL) { - return -EINVAL; + /* Only support version 3 and make sure the number of bytes to copy is not + * bigger than rx buf size or the shared memory size + */ + if (rx_header->prtcl_ver != 3 || + rx_valid_data_size > CONFIG_EC_HOST_CMD_HANDLER_RX_BUFFER || + rx_valid_data_size > shared_size) { + memcpy(hc_espi->rx_ctx->buf, (void *)rx_header, RX_HEADER_SIZE); + hc_espi->rx_ctx->len = RX_HEADER_SIZE; + } else { + memcpy(hc_espi->rx_ctx->buf, (void *)rx_header, rx_valid_data_size); + hc_espi->rx_ctx->len = rx_valid_data_size; } - rx_ctx->buf = data->espi_shm; - rx_ctx->len = &data->rx_buffer_len; - rx_ctx->dev_owns = &data->dev_owns; - rx_ctx->handler_owns = &data->handler_owns; + /* Even in case of errors, let the general handler send response */ + hc_espi->state = ESPI_STATE_PROCESSING; + k_sem_give(&hc_espi->rx_ctx->handler_owns); +} + +static int ec_host_cmd_espi_init(const struct ec_host_cmd_backend *backend, + struct ec_host_cmd_rx_ctx *rx_ctx, struct ec_host_cmd_tx_buf *tx) +{ + struct ec_host_cmd_espi_ctx *hc_espi = (struct ec_host_cmd_espi_ctx *)backend->ctx; + + hc_espi->state = ESPI_STATE_DISABLED; + + if (!device_is_ready(hc_espi->espi_dev)) { + return -ENODEV; + } + + hc_espi->rx_ctx = rx_ctx; + hc_espi->tx = tx; + + espi_init_callback(&hc_espi->espi_cb, espi_handler, ESPI_BUS_PERIPHERAL_NOTIFICATION); + espi_add_callback(hc_espi->espi_dev, &hc_espi->espi_cb); + /* Use shared memory as the tx buffer */ + espi_read_lpc_request(hc_espi->espi_dev, ECUSTOM_HOST_CMD_GET_PARAM_MEMORY, + (uint32_t *)&tx->buf); + espi_read_lpc_request(hc_espi->espi_dev, ECUSTOM_HOST_CMD_GET_PARAM_MEMORY_SIZE, + &tx->len_max); + + hc_espi->state = ESPI_STATE_READY_TO_RECV; return 0; } -int ec_host_cmd_backend_espi_send(const struct device *dev, - const struct ec_host_cmd_tx_buf *buf) +static int ec_host_cmd_espi_send(const struct ec_host_cmd_backend *backend) { - struct ec_host_cmd_backend_espi_data *data = dev->data; - struct ec_host_cmd_response_header *resp_hdr = buf->buf; + struct ec_host_cmd_espi_ctx *hc_espi = (struct ec_host_cmd_espi_ctx *)backend->ctx; + struct ec_host_cmd_response_header *resp_hdr = hc_espi->tx->buf; uint32_t result = resp_hdr->result; + int ret; - memcpy(data->espi_shm, buf->buf, buf->len); + hc_espi->state = ESPI_STATE_SENDING; - return espi_write_lpc_request(ESPI_DEVICE, ECUSTOM_HOST_CMD_SEND_RESULT, &result); + /* Data to transfer are already in the tx buffer (shared memory) */ + ret = espi_write_lpc_request(hc_espi->espi_dev, ECUSTOM_HOST_CMD_SEND_RESULT, &result); + hc_espi->state = ESPI_STATE_READY_TO_RECV; + + return ret; } static const struct ec_host_cmd_backend_api ec_host_cmd_api = { - .init = &ec_host_cmd_backend_espi_init, - .send = &ec_host_cmd_backend_espi_send, + .init = &ec_host_cmd_espi_init, + .send = &ec_host_cmd_espi_send, }; -static int ec_host_cmd_espi_init(const struct device *dev) +EC_HOST_CMD_ESPI_DEFINE(ec_host_cmd_espi); +struct ec_host_cmd_backend *ec_host_cmd_backend_get_espi(const struct device *dev) { - struct ec_host_cmd_backend_espi_data *data = dev->data; - - /* Allow writing to rx buff at startup and block on reading. */ - k_sem_init(&data->handler_owns, 0, 1); - k_sem_init(&data->dev_owns, 1, 1); - - espi_init_callback(&data->espi_cb, ec_host_cmd_backend_espi_handler, - ESPI_BUS_PERIPHERAL_NOTIFICATION); - espi_add_callback(ESPI_DEVICE, &data->espi_cb); - - espi_read_lpc_request(ESPI_DEVICE, ECUSTOM_HOST_CMD_GET_PARAM_MEMORY, - (uint32_t *)&data->espi_shm); - espi_read_lpc_request(ESPI_DEVICE, ECUSTOM_HOST_CMD_GET_PARAM_MEMORY_SIZE, - &data->rx_buffer_len); - - return 0; + ((struct ec_host_cmd_espi_ctx *)(ec_host_cmd_espi.ctx))->espi_dev = dev; + return &ec_host_cmd_espi; } -/* Assume only one backend */ -static struct ec_host_cmd_backend_espi_data espi_data; -DEVICE_DT_INST_DEFINE(0, ec_host_cmd_espi_init, NULL, &espi_data, NULL, POST_KERNEL, - CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &ec_host_cmd_api); +#if DT_NODE_EXISTS(DT_CHOSEN(zephyr_host_cmd_backend)) +static int host_cmd_init(const struct device *arg) +{ + ARG_UNUSED(arg); + const struct device *const dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_host_cmd_backend)); + + ec_host_cmd_init(ec_host_cmd_backend_get_espi(dev)); + return 0; +} +SYS_INIT(host_cmd_init, POST_KERNEL, CONFIG_EC_HOST_CMD_INIT_PRIORITY); +#endif diff --git a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi.h b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi.h index ab00816105..46a7aba0f9 100644 --- a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi.h +++ b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_DRIVERS_EC_HOST_CMD_BACKEND_SHI_H_ -#define ZEPHYR_DRIVERS_EC_HOST_CMD_BACKEND_SHI_H_ +#ifndef ZEPHYR_SUBSYS_MGMT_EC_HOST_CMD_BACKENDS_EC_HOST_CMD_BACKEND_SHI_H_ +#define ZEPHYR_SUBSYS_MGMT_EC_HOST_CMD_BACKENDS_EC_HOST_CMD_BACKEND_SHI_H_ #include @@ -98,4 +98,4 @@ /* Supported version of host commands protocol. */ #define EC_HOST_REQUEST_VERSION 3 -#endif /* ZEPHYR_DRIVERS_EC_HOST_CMD_BACKEND_SHI_H_ */ +#endif /* ZEPHYR_SUBSYS_MGMT_EC_HOST_CMD_BACKENDS_EC_HOST_CMD_BACKEND_SHI_H_ */ diff --git a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_ite.c b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_ite.c index 51e6994a16..c1f2f72e47 100644 --- a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_ite.c +++ b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_ite.c @@ -30,8 +30,6 @@ LOG_MODULE_REGISTER(host_cmd_shi_ite, CONFIG_EC_HC_LOG_LEVEL); #define SHI_MAX_RESPONSE_SIZE \ (SPI_TX_MAX_FIFO_SIZE - EC_SHI_PREAMBLE_LENGTH - EC_SHI_PAST_END_LENGTH) -BUILD_ASSERT(CONFIG_EC_HOST_CMD_HANDLER_TX_BUFFER == SHI_MAX_RESPONSE_SIZE, - "EC HC TX has different size than SHI TX response size"); BUILD_ASSERT(CONFIG_EC_HOST_CMD_BACKEND_SHI_MAX_REQUEST <= SPI_RX_MAX_FIFO_SIZE, "SHI max request size is too big"); BUILD_ASSERT(CONFIG_EC_HOST_CMD_BACKEND_SHI_MAX_RESPONSE <= SHI_MAX_RESPONSE_SIZE, @@ -65,18 +63,22 @@ struct shi_it8xxx2_cfg { }; struct shi_it8xxx2_data { - /* Backend data */ - struct k_sem handler_owns; - struct k_sem dev_owns; + /* Peripheral data */ + struct ec_host_cmd_rx_ctx *rx_ctx; + struct ec_host_cmd_tx_buf *tx; struct gpio_callback cs_cb; /* Current state */ enum shi_state_machine shi_state; /* Buffers */ - uint32_t in_msg_size; uint8_t in_msg[SPI_RX_MAX_FIFO_SIZE] __aligned(4); uint8_t out_msg[SPI_TX_MAX_FIFO_SIZE] __aligned(4); }; +struct ec_host_cmd_shi_ite_ctx { + /* SHI device instance */ + const struct device *dev; +}; + static const uint8_t out_preamble[EC_SHI_PREAMBLE_LENGTH] = { EC_SHI_PROCESSING, EC_SHI_PROCESSING, @@ -92,6 +94,13 @@ static const int shi_ite_response_state[] = { }; BUILD_ASSERT(ARRAY_SIZE(shi_ite_response_state) == SHI_STATE_COUNT); +#define EC_HOST_CMD_SHI_ITE_DEFINE(_name) \ + static struct ec_host_cmd_shi_ite_ctx _name##_hc_shi_ite; \ + struct ec_host_cmd_backend _name = { \ + .api = &ec_host_cmd_api, \ + .ctx = (struct ec_host_cmd_shi_ite_ctx *)&_name##_hc_shi_ite, \ + } + static void shi_ite_set_state(struct shi_it8xxx2_data *data, int state) { /* SPI peripheral state machine */ @@ -170,10 +179,10 @@ static void shi_ite_response_host_data(const struct device *dev, uint8_t *out_ms * Some commands can continue for a while. This function is called by * host_command when it completes. */ -static int shi_ite_backend_send(const struct device *dev, - const struct ec_host_cmd_tx_buf *buf) +static int shi_ite_backend_send(const struct ec_host_cmd_backend *backend) { - struct shi_it8xxx2_data *data = dev->data; + struct ec_host_cmd_shi_ite_ctx *hc_shi = (struct ec_host_cmd_shi_ite_ctx *)backend->ctx; + struct shi_it8xxx2_data *data = hc_shi->dev->data; int tx_size; if (data->shi_state != SHI_STATE_PROCESSING) { @@ -184,18 +193,17 @@ static int shi_ite_backend_send(const struct device *dev, /* Copy preamble */ memcpy(data->out_msg, out_preamble, sizeof(out_preamble)); - /* Copy data */ - memcpy(data->out_msg + sizeof(out_preamble), buf->buf, buf->len); + /* Data to sent are already at "out_msg + sizeof(out_preamble)" memory address(tx buf + * assigned in the init function), prepared by the handler. + * Append our past-end byte, which we reserved space for. + */ + memset(&data->out_msg[sizeof(out_preamble) + data->tx->len], EC_SHI_PAST_END, + EC_SHI_PAST_END_LENGTH); - /* Append our past-end byte, which we reserved space for. */ - for (int i = 0; i < EC_SHI_PAST_END_LENGTH; i++) { - data->out_msg[sizeof(out_preamble) + buf->len + i] = EC_SHI_PAST_END; - } - - tx_size = buf->len + EC_SHI_PREAMBLE_LENGTH + EC_SHI_PAST_END_LENGTH; + tx_size = data->tx->len + EC_SHI_PREAMBLE_LENGTH + EC_SHI_PAST_END_LENGTH; /* Transmit the reply */ - shi_ite_response_host_data(dev, data->out_msg, tx_size); + shi_ite_response_host_data(hc_shi->dev, data->out_msg, tx_size); return 0; } @@ -238,24 +246,24 @@ static void shi_ite_parse_header(const struct device *dev) struct shi_it8xxx2_data *data = dev->data; struct ec_host_cmd_request_header *r = (struct ec_host_cmd_request_header *)data->in_msg; - /* Store request data from Rx FIFO to in_msg buffer */ + /* Store request data from Rx FIFO to in_msg buffer (rx_ctx->buf) */ shi_ite_host_request_data(data->in_msg, sizeof(*r)); /* Protocol version 3 */ - if (data->in_msg[0] == EC_HOST_REQUEST_VERSION) { + if (r->prtcl_ver == EC_HOST_REQUEST_VERSION) { /* Check how big the packet should be */ - data->in_msg_size = shi_ite_host_request_expected_size(r); + data->rx_ctx->len = shi_ite_host_request_expected_size(r); - if (data->in_msg_size == 0 || data->in_msg_size > sizeof(data->in_msg)) { - shi_ite_bad_received_data(dev, data->in_msg_size); + if (data->rx_ctx->len == 0 || data->rx_ctx->len > sizeof(data->in_msg)) { + shi_ite_bad_received_data(dev, data->rx_ctx->len); return; } /* Store request data from Rx FIFO to in_msg buffer */ - shi_ite_host_request_data(data->in_msg + sizeof(*r), - data->in_msg_size - sizeof(*r)); + shi_ite_host_request_data(data->rx_ctx->buf + sizeof(*r), + data->rx_ctx->len - sizeof(*r)); - k_sem_give(&data->handler_owns); + k_sem_give(&data->rx_ctx->handler_owns); } else { /* Invalid version number */ LOG_ERR("Invalid version number"); @@ -396,17 +404,6 @@ static int shi_ite_init_registers(const struct device *dev) return 0; } -static int shi_ite_init_backend(const struct device *dev) -{ - struct shi_it8xxx2_data *data = dev->data; - - /* Allow writing to rx buff at startup and block on reading. */ - k_sem_init(&data->handler_owns, 0, 1); - k_sem_init(&data->dev_owns, 1, 1); - - return 0; -} - static int shi_ite_init(const struct device *dev) { const struct shi_it8xxx2_cfg *cfg = dev->config; @@ -418,11 +415,6 @@ static int shi_ite_init(const struct device *dev) return ret; } - ret = shi_ite_init_backend(dev); - if (ret) { - return ret; - } - /* Configure the SPI chip select */ ret = gpio_pin_configure(cfg->cs.port, cfg->cs.pin, GPIO_INPUT | cfg->cs.dt_flags); if (ret < 0) { @@ -447,15 +439,24 @@ static int shi_ite_init(const struct device *dev) return pm_device_runtime_enable(dev); } -static int shi_ite_backend_init_context(const struct device *dev, - struct ec_host_cmd_rx_ctx *rx_ctx) +static int shi_ite_backend_init(const struct ec_host_cmd_backend *backend, + struct ec_host_cmd_rx_ctx *rx_ctx, struct ec_host_cmd_tx_buf *tx) { - struct shi_it8xxx2_data *data = dev->data; + struct ec_host_cmd_shi_ite_ctx *hc_shi = (struct ec_host_cmd_shi_ite_ctx *)backend->ctx; + struct shi_it8xxx2_data *data; + + hc_shi->dev = DEVICE_DT_INST_GET(0); + if (!device_is_ready(hc_shi->dev)) { + return -ENODEV; + } + + data = hc_shi->dev->data; + data->rx_ctx = rx_ctx; + data->tx = tx; - rx_ctx->dev_owns = &data->dev_owns; - rx_ctx->handler_owns = &data->handler_owns; rx_ctx->buf = data->in_msg; - rx_ctx->len = &data->in_msg_size; + tx->buf = data->out_msg + sizeof(out_preamble); + data->tx->len_max = sizeof(data->out_msg) - EC_SHI_PREAMBLE_LENGTH - EC_SHI_PAST_END_LENGTH; return 0; } @@ -488,7 +489,7 @@ static int shi_ite_pm_cb(const struct device *dev, enum pm_device_action action) PM_DEVICE_DT_INST_DEFINE(0, shi_ite_pm_cb); static const struct ec_host_cmd_backend_api ec_host_cmd_api = { - .init = shi_ite_backend_init_context, + .init = shi_ite_backend_init, .send = shi_ite_backend_send, }; @@ -499,8 +500,25 @@ static const struct shi_it8xxx2_cfg shi_cfg = { static struct shi_it8xxx2_data shi_data = { .shi_state = SHI_STATE_DISABLED, - .in_msg_size = 0, }; DEVICE_DT_INST_DEFINE(0, shi_ite_init, PM_DEVICE_DT_INST_GET(0), &shi_data, &shi_cfg, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &ec_host_cmd_api); + +EC_HOST_CMD_SHI_ITE_DEFINE(ec_host_cmd_shi_ite); + +struct ec_host_cmd_backend *ec_host_cmd_backend_get_shi_ite(void) +{ + return &ec_host_cmd_shi_ite; +} + +#if DT_NODE_EXISTS(DT_CHOSEN(zephyr_host_cmd_backend)) +static int host_cmd_init(const struct device *arg) +{ + ARG_UNUSED(arg); + + ec_host_cmd_init(ec_host_cmd_backend_get_shi_ite()); + return 0; +} +SYS_INIT(host_cmd_init, POST_KERNEL, CONFIG_EC_HOST_CMD_INIT_PRIORITY); +#endif diff --git a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c index 13d31c170e..b5e73a2cd3 100644 --- a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c +++ b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c @@ -109,9 +109,8 @@ struct shi_npcx_config { }; struct shi_npcx_data { - /* Handler mutexes */ - struct k_sem handler_owns; - struct k_sem dev_owns; + struct ec_host_cmd_rx_ctx *rx_ctx; + struct ec_host_cmd_tx_buf *tx; /* Communication status */ enum shi_npcx_state state; enum shi_npcx_state last_error_state; @@ -119,7 +118,6 @@ struct shi_npcx_data { uint8_t *tx_msg; /* Entry pointer of msg tx buffer */ volatile uint8_t *rx_buf; /* Entry pointer of receive buffer */ volatile uint8_t *tx_buf; /* Entry pointer of transmit buffer */ - uint32_t sz_received; /* Size of received data in bytes */ uint16_t sz_sending; /* Size of sending data in bytes */ uint16_t sz_request; /* Request bytes need to receive */ uint16_t sz_response; /* Response bytes need to receive */ @@ -131,6 +129,18 @@ struct shi_npcx_data { uint8_t in_msg[CONFIG_EC_HOST_CMD_BACKEND_SHI_MAX_REQUEST] __aligned(4); }; +struct ec_host_cmd_shi_npcx_ctx { + /* SHI device instance */ + const struct device *dev; +}; + +#define EC_HOST_CMD_SHI_NPCX_DEFINE(_name) \ + static struct ec_host_cmd_shi_npcx_ctx _name##_hc_shi_npcx; \ + struct ec_host_cmd_backend _name = { \ + .api = &ec_host_cmd_api, \ + .ctx = (struct ec_host_cmd_shi_npcx_ctx *)&_name##_hc_shi_npcx, \ + } + /* Forward declaration */ static void shi_npcx_reset_prepare(const struct device *dev); @@ -188,7 +198,7 @@ static int shi_npcx_read_inbuf_wait(const struct device *dev, uint32_t szbytes) struct shi_reg *const inst = HAL_INSTANCE(dev); /* Copy data to msg buffer from input buffer */ - for (uint32_t i = 0; i < szbytes; i++, data->sz_received++) { + for (uint32_t i = 0; i < szbytes; i++, data->rx_ctx->len++) { /* * If input buffer pointer equals pointer which wants to read, * it means data is not ready. @@ -255,7 +265,7 @@ static void shi_npcx_bad_received_data(const struct device *dev) LOG_ERR("SHI bad data recv"); LOG_DBG("BAD-"); - LOG_HEXDUMP_DBG(data->in_msg, data->sz_received, "in_msg="); + LOG_HEXDUMP_DBG(data->in_msg, data->rx_ctx->len, "in_msg="); /* Reset shi's state machine for error recovery */ shi_npcx_reset_prepare(dev); @@ -316,14 +326,14 @@ static void shi_npcx_handle_host_package(const struct device *dev) struct shi_npcx_data *data = dev->data; struct shi_reg *const inst = HAL_INSTANCE(dev); uint32_t sz_inbuf_int = data->sz_request / SHI_IBUF_HALF_SIZE; - uint32_t cnt_inbuf_int = data->sz_received / SHI_IBUF_HALF_SIZE; + uint32_t cnt_inbuf_int = data->rx_ctx->len / SHI_IBUF_HALF_SIZE; if (sz_inbuf_int - cnt_inbuf_int) { /* Need to receive data from buffer */ return; } - uint32_t remain_bytes = data->sz_request - data->sz_received; + uint32_t remain_bytes = data->sz_request - data->rx_ctx->len; /* Read remaining bytes from input buffer */ if (!shi_npcx_read_inbuf_wait(dev, remain_bytes)) { @@ -339,7 +349,7 @@ static void shi_npcx_handle_host_package(const struct device *dev) data->out_msg[0] = EC_SHI_FRAME_START; /* Wake-up the HC handler thread */ - k_sem_give(&data->handler_owns); + k_sem_give(&data->rx_ctx->handler_owns); } static int shi_npcx_host_request_expected_size(const struct ec_host_cmd_request_header *r) @@ -437,8 +447,8 @@ static void shi_npcx_read_half_inbuf(const struct device *dev) do { /* Restore data to msg buffer */ *data->rx_msg++ = *data->rx_buf++; - data->sz_received++; - } while (data->sz_received % SHI_IBUF_HALF_SIZE && data->sz_received != data->sz_request); + data->rx_ctx->len++; + } while (data->rx_ctx->len % SHI_IBUF_HALF_SIZE && data->rx_ctx->len != data->sz_request); } /* @@ -677,7 +687,7 @@ static void shi_npcx_reset_prepare(const struct device *dev) data->tx_msg = data->out_msg; data->rx_buf = inst->IBUF; data->tx_buf = inst->OBUF; - data->sz_received = 0; + data->rx_ctx->len = 0; data->sz_sending = 0; data->sz_request = 0; data->sz_response = 0; @@ -841,17 +851,6 @@ static int shi_npcx_init_registers(const struct device *dev) return ret; } -static int shi_npcx_init_backend(const struct device *dev) -{ - struct shi_npcx_data *data = dev->data; - - /* Allow writing to rx buff at startup and block on reading. */ - k_sem_init(&data->handler_owns, 0, 1); - k_sem_init(&data->dev_owns, 1, 1); - - return 0; -} - static int shi_npcx_init(const struct device *dev) { int ret; @@ -860,33 +859,37 @@ static int shi_npcx_init(const struct device *dev) if (ret) { return ret; } - - ret = shi_npcx_init_backend(dev); - if (ret) { - return ret; - } - pm_device_init_suspended(dev); + return pm_device_runtime_enable(dev); } -static int shi_npcx_backend_init_context(const struct device *dev, - struct ec_host_cmd_rx_ctx *rx_ctx) +static int shi_npcx_backend_init(const struct ec_host_cmd_backend *backend, + struct ec_host_cmd_rx_ctx *rx_ctx, struct ec_host_cmd_tx_buf *tx) { - struct shi_npcx_data *data = dev->data; + struct ec_host_cmd_shi_npcx_ctx *hc_shi = (struct ec_host_cmd_shi_npcx_ctx *)backend->ctx; + struct shi_npcx_data *data; + + hc_shi->dev = DEVICE_DT_INST_GET(0); + if (!device_is_ready(hc_shi->dev)) { + return -ENODEV; + } + + data = hc_shi->dev->data; + data->rx_ctx = rx_ctx; + data->tx = tx; - rx_ctx->dev_owns = &data->dev_owns; - rx_ctx->handler_owns = &data->handler_owns; rx_ctx->buf = data->in_msg; - rx_ctx->len = &data->sz_received; + tx->buf = data->out_msg_padded + SHI_OUT_START_PAD; + tx->len_max = CONFIG_EC_HOST_CMD_BACKEND_SHI_MAX_RESPONSE; return 0; } -static int shi_npcx_backend_send(const struct device *dev, - const struct ec_host_cmd_tx_buf *in_buf) +static int shi_npcx_backend_send(const struct ec_host_cmd_backend *backend) { - struct shi_npcx_data *data = dev->data; + struct ec_host_cmd_shi_npcx_ctx *hc_shi = (struct ec_host_cmd_shi_npcx_ctx *)backend->ctx; + struct shi_npcx_data *data = hc_shi->dev->data; uint8_t *out_buf = data->out_msg + EC_SHI_FRAME_START_LENGTH; /* @@ -897,17 +900,15 @@ static int shi_npcx_backend_send(const struct device *dev, */ __disable_irq(); - memcpy(out_buf, in_buf->buf, in_buf->len); - if (data->state == SHI_STATE_PROCESSING) { /* Append our past-end byte, which we reserved space for. */ - ((uint8_t *)out_buf)[in_buf->len] = EC_SHI_PAST_END; + ((uint8_t *)out_buf)[data->tx->len] = EC_SHI_PAST_END; /* Computing sending bytes of response */ - data->sz_response = in_buf->len + EC_SHI_PROTO3_OVERHEAD; + data->sz_response = data->tx->len + EC_SHI_PROTO3_OVERHEAD; /* Start to fill output buffer with msg buffer */ - shi_npcx_write_first_pkg_outbuf(dev, data->sz_response); + shi_npcx_write_first_pkg_outbuf(hc_shi->dev, data->sz_response); /* Transmit the reply */ data->state = SHI_STATE_SENDING; @@ -918,7 +919,7 @@ static int shi_npcx_backend_send(const struct device *dev, * the transaction, and won't be listening for a response. * Reset state machine for next transaction. */ - shi_npcx_reset_prepare(dev); + shi_npcx_reset_prepare(hc_shi->dev); LOG_DBG("END\n"); } else { LOG_ERR("Unexpected state %d in response handler", data->state); @@ -929,7 +930,7 @@ static int shi_npcx_backend_send(const struct device *dev, } static const struct ec_host_cmd_backend_api ec_host_cmd_api = { - .init = shi_npcx_backend_init_context, + .init = shi_npcx_backend_init, .send = shi_npcx_backend_send, }; @@ -974,3 +975,21 @@ static struct shi_npcx_data shi_data = { DEVICE_DT_INST_DEFINE(0, shi_npcx_init, PM_DEVICE_DT_INST_GET(0), &shi_data, &shi_cfg, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &ec_host_cmd_api); + +EC_HOST_CMD_SHI_NPCX_DEFINE(ec_host_cmd_shi_npcx); + +struct ec_host_cmd_backend *ec_host_cmd_backend_get_shi_npcx(void) +{ + return &ec_host_cmd_shi_npcx; +} + +#if DT_NODE_EXISTS(DT_CHOSEN(zephyr_host_cmd_backend)) +static int host_cmd_init(const struct device *arg) +{ + ARG_UNUSED(arg); + + ec_host_cmd_init(ec_host_cmd_backend_get_shi_npcx()); + return 0; +} +SYS_INIT(host_cmd_init, POST_KERNEL, CONFIG_EC_HOST_CMD_INIT_PRIORITY); +#endif diff --git a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_simulator.c b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_simulator.c index ae5f80f719..b18022d29c 100644 --- a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_simulator.c +++ b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_simulator.c @@ -4,84 +4,83 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT zephyr_sim_ec_host_cmd_backend - #include #include #include +#include #include #ifndef CONFIG_ARCH_POSIX #error Simulator only valid on posix #endif -static uint8_t rx_buffer[256]; -static size_t rx_buffer_len; +struct ec_host_cmd_sim_ctx { + struct ec_host_cmd_rx_ctx *rx_ctx; + struct ec_host_cmd_tx_buf *tx; +}; -/* Allow writing to rx buff at startup and block on reading. */ -static K_SEM_DEFINE(handler_owns, 0, 1); -static K_SEM_DEFINE(dev_owns, 1, 1); +#define EC_HOST_CMD_SIM_DEFINE(_name) \ + static struct ec_host_cmd_sim_ctx _name##_hc_sim; \ + struct ec_host_cmd_backend _name = { \ + .api = &ec_host_cmd_api, \ + .ctx = (struct ec_host_cmd_sim_ctx *)&_name##_hc_sim, \ + } static ec_host_cmd_backend_api_send tx; -int ec_host_cmd_backend_sim_init(const struct device *dev, - struct ec_host_cmd_rx_ctx *rx_ctx) +static int ec_host_cmd_sim_init(const struct ec_host_cmd_backend *backend, + struct ec_host_cmd_rx_ctx *rx_ctx, + struct ec_host_cmd_tx_buf *tx_buf) { - if (rx_ctx == NULL) { - return -EINVAL; - } + struct ec_host_cmd_sim_ctx *hc_sim = (struct ec_host_cmd_sim_ctx *)backend->ctx; - rx_ctx->buf = rx_buffer; - rx_ctx->len = &rx_buffer_len; - rx_ctx->dev_owns = &dev_owns; - rx_ctx->handler_owns = &handler_owns; + hc_sim->rx_ctx = rx_ctx; + hc_sim->tx = tx_buf; return 0; } -int ec_host_cmd_backend_sim_send(const struct device *dev, - const struct ec_host_cmd_tx_buf *buf) +static int ec_host_cmd_sim_send(const struct ec_host_cmd_backend *backend) { if (tx != NULL) { - return tx(dev, buf); + return tx(backend); } return 0; } -void ec_host_cmd_backend_sim_install_send_cb(ec_host_cmd_backend_api_send cb) +static const struct ec_host_cmd_backend_api ec_host_cmd_api = { + .init = &ec_host_cmd_sim_init, + .send = &ec_host_cmd_sim_send, +}; +EC_HOST_CMD_SIM_DEFINE(ec_host_cmd_sim); + +void ec_host_cmd_backend_sim_install_send_cb(ec_host_cmd_backend_api_send cb, + struct ec_host_cmd_tx_buf **tx_buf) { + struct ec_host_cmd_sim_ctx *hc_sim = (struct ec_host_cmd_sim_ctx *)ec_host_cmd_sim.ctx; + *tx_buf = hc_sim->tx; tx = cb; } int ec_host_cmd_backend_sim_data_received(const uint8_t *buffer, size_t len) { - if (sizeof(rx_buffer) < len) { - return -ENOMEM; - } - if (k_sem_take(&dev_owns, K_NO_WAIT) != 0) { - return -EBUSY; - } + struct ec_host_cmd_sim_ctx *hc_sim = (struct ec_host_cmd_sim_ctx *)ec_host_cmd_sim.ctx; - memcpy(rx_buffer, buffer, len); - rx_buffer_len = len; + memcpy(hc_sim->rx_ctx->buf, buffer, len); + hc_sim->rx_ctx->len = len; + + k_sem_give(&hc_sim->rx_ctx->handler_owns); - k_sem_give(&handler_owns); return 0; } -static const struct ec_host_cmd_backend_api ec_host_cmd_api = { - .init = &ec_host_cmd_backend_sim_init, - .send = &ec_host_cmd_backend_sim_send, -}; - -static int ec_host_cmd_sim_init(const struct device *dev) +static int host_cmd_init(const struct device *arg) { + ARG_UNUSED(arg); + + ec_host_cmd_init(&ec_host_cmd_sim); return 0; } - -/* Assume only one simulator */ -DEVICE_DT_INST_DEFINE(0, ec_host_cmd_sim_init, NULL, - NULL, NULL, POST_KERNEL, - CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &ec_host_cmd_api); +SYS_INIT(host_cmd_init, POST_KERNEL, CONFIG_EC_HOST_CMD_INIT_PRIORITY); diff --git a/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c b/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c index 070c3a9c92..1a653d196b 100644 --- a/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c +++ b/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c @@ -6,24 +6,42 @@ #include #include -#include -#include +#include #include +#include +#include -BUILD_ASSERT(DT_HAS_CHOSEN(zephyr_ec_host_interface), - "Must choose zephyr,ec-host-interface in device tree"); - -#define DT_HOST_CMD_DEV DT_CHOSEN(zephyr_ec_host_interface) +LOG_MODULE_REGISTER(host_cmd_handler, CONFIG_EC_HC_LOG_LEVEL); #define RX_HEADER_SIZE (sizeof(struct ec_host_cmd_request_header)) #define TX_HEADER_SIZE (sizeof(struct ec_host_cmd_response_header)) -/** - * Used by host command handlers for their response before going over wire. - * Host commands handlers will cast this to respective response structures that may have fields of - * uint32_t or uint64_t, so this buffer must be aligned to protect against the unaligned access. - */ -static uint8_t tx_buffer[CONFIG_EC_HOST_CMD_HANDLER_TX_BUFFER] __aligned(8); +#define EC_HOST_CMD_DEFINE(_name) \ + COND_CODE_1(CONFIG_EC_HOST_CMD_HANDLER_RX_BUFFER_DEF, \ + (static uint8_t _name##_rx_buffer[CONFIG_EC_HOST_CMD_HANDLER_RX_BUFFER];), ()) \ + COND_CODE_1(CONFIG_EC_HOST_CMD_HANDLER_TX_BUFFER_DEF, \ + (static uint8_t _name##_tx_buffer[CONFIG_EC_HOST_CMD_HANDLER_TX_BUFFER];), ()) \ + static K_KERNEL_STACK_DEFINE(_name##stack, CONFIG_EC_HOST_CMD_HANDLER_STACK_SIZE); \ + static struct k_thread _name##thread; \ + static struct ec_host_cmd _name = { \ + .rx_ctx = \ + { \ + .buf = COND_CODE_1(CONFIG_EC_HOST_CMD_HANDLER_RX_BUFFER_DEF, \ + (_name##_rx_buffer), (NULL)), \ + }, \ + .tx = \ + { \ + .buf = COND_CODE_1(CONFIG_EC_HOST_CMD_HANDLER_TX_BUFFER_DEF, \ + (_name##_tx_buffer), (NULL)), \ + .len_max = \ + COND_CODE_1(CONFIG_EC_HOST_CMD_HANDLER_TX_BUFFER_DEF, \ + (CONFIG_EC_HOST_CMD_HANDLER_TX_BUFFER), (0)), \ + }, \ + .thread = &_name##thread, \ + .stack = _name##stack, \ + } + +EC_HOST_CMD_DEFINE(ec_host_cmd); static uint8_t cal_checksum(const uint8_t *const buffer, const uint16_t size) { @@ -35,94 +53,128 @@ static uint8_t cal_checksum(const uint8_t *const buffer, const uint16_t size) return (uint8_t)(-checksum); } -static void send_error_response(const struct device *const ec_host_cmd_dev, - const enum ec_host_cmd_status error) +static void send_error_response(const struct ec_host_cmd_backend *backend, + struct ec_host_cmd_tx_buf *tx, const enum ec_host_cmd_status error) { - struct ec_host_cmd_response_header *const tx_header = (void *)tx_buffer; + struct ec_host_cmd_response_header *const tx_header = (void *)tx->buf; tx_header->prtcl_ver = 3; tx_header->result = error; tx_header->data_len = 0; tx_header->reserved = 0; tx_header->checksum = 0; - tx_header->checksum = cal_checksum(tx_buffer, TX_HEADER_SIZE); + tx_header->checksum = cal_checksum((uint8_t *)tx_header, TX_HEADER_SIZE); - const struct ec_host_cmd_tx_buf tx = { - .buf = tx_buffer, - .len = TX_HEADER_SIZE, - }; - ec_host_cmd_backend_send(ec_host_cmd_dev, &tx); + tx->len = TX_HEADER_SIZE; + + backend->api->send(backend); } -static void handle_host_cmds_entry(void *arg1, void *arg2, void *arg3) +static enum ec_host_cmd_status verify_rx(struct ec_host_cmd_rx_ctx *rx) { - ARG_UNUSED(arg1); - ARG_UNUSED(arg2); - ARG_UNUSED(arg3); - const struct device *const ec_host_cmd_dev = DEVICE_DT_GET(DT_HOST_CMD_DEV); - struct ec_host_cmd_rx_ctx rx; - - if (!device_is_ready(ec_host_cmd_dev)) { - return; + /* rx buf and len now have valid incoming data */ + if (rx->len < RX_HEADER_SIZE) { + return EC_HOST_CMD_REQUEST_TRUNCATED; } - ec_host_cmd_backend_init(ec_host_cmd_dev, &rx); + const struct ec_host_cmd_request_header *rx_header = + (struct ec_host_cmd_request_header *)rx->buf; + + /* Only support version 3 */ + if (rx_header->prtcl_ver != 3) { + return EC_HOST_CMD_INVALID_HEADER; + } + + const uint16_t rx_valid_data_size = rx_header->data_len + RX_HEADER_SIZE; + /* + * Ensure we received at least as much data as is expected. + * It is okay to receive more since some hardware interfaces + * add on extra padding bytes at the end. + */ + if (rx->len < rx_valid_data_size) { + return EC_HOST_CMD_REQUEST_TRUNCATED; + } + + /* Validate checksum */ + if (cal_checksum((uint8_t *)rx_header, rx_valid_data_size) != 0) { + return EC_HOST_CMD_INVALID_CHECKSUM; + } + + return EC_HOST_CMD_SUCCESS; +} + +static enum ec_host_cmd_status validate_handler(const struct ec_host_cmd_handler *handler, + const struct ec_host_cmd_handler_args *args) +{ + if (handler->min_rqt_size > args->input_buf_size) { + return EC_HOST_CMD_REQUEST_TRUNCATED; + } + + if (handler->min_rsp_size > args->output_buf_max) { + return EC_HOST_CMD_INVALID_RESPONSE; + } + + if (args->version > sizeof(handler->version_mask) || + !(handler->version_mask & BIT(args->version))) { + return EC_HOST_CMD_INVALID_VERSION; + } + + return EC_HOST_CMD_SUCCESS; +} + +static enum ec_host_cmd_status prepare_response(struct ec_host_cmd_tx_buf *tx, uint16_t len) +{ + struct ec_host_cmd_response_header *const tx_header = (void *)tx->buf; + + tx_header->prtcl_ver = 3; + tx_header->result = EC_HOST_CMD_SUCCESS; + tx_header->data_len = len; + tx_header->reserved = 0; + + const uint16_t tx_valid_data_size = tx_header->data_len + TX_HEADER_SIZE; + + if (tx_valid_data_size > tx->len_max) { + return EC_HOST_CMD_INVALID_RESPONSE; + } + + /* Calculate checksum */ + tx_header->checksum = 0; + tx_header->checksum = cal_checksum(tx->buf, tx_valid_data_size); + + tx->len = tx_valid_data_size; + + return EC_HOST_CMD_SUCCESS; +} + +static void ec_host_cmd_thread(void *hc_handle, void *arg2, void *arg3) +{ + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + enum ec_host_cmd_status status; + struct ec_host_cmd *hc = (struct ec_host_cmd *)hc_handle; + struct ec_host_cmd_rx_ctx *rx = &hc->rx_ctx; + struct ec_host_cmd_tx_buf *tx = &hc->tx; + const struct ec_host_cmd_handler *found_handler; + const struct ec_host_cmd_request_header *const rx_header = (void *)rx->buf; + /* The pointer to rx buffer is constant during communication */ + struct ec_host_cmd_handler_args args = { + .output_buf = (uint8_t *)tx->buf + TX_HEADER_SIZE, + .output_buf_max = tx->len_max - TX_HEADER_SIZE, + .input_buf = rx->buf + RX_HEADER_SIZE, + .reserved = NULL, + }; while (1) { - /* We have finished reading from RX buffer, so allow another - * incoming msg. - */ - k_sem_give(rx.dev_owns); + /* Wait until RX messages is received on host interface */ + k_sem_take(&rx->handler_owns, K_FOREVER); - /* Wait until and RX messages is received on host interface */ - if (k_sem_take(rx.handler_owns, K_FOREVER) < 0) { - /* This code path should never occur due to the nature of - * k_sem_take with K_FOREVER - */ - send_error_response(ec_host_cmd_dev, - EC_HOST_CMD_ERROR); + status = verify_rx(rx); + if (status != EC_HOST_CMD_SUCCESS) { + send_error_response(hc->backend, tx, status); continue; } - /* rx buf and len now have valid incoming data */ - if (*rx.len < RX_HEADER_SIZE) { - send_error_response(ec_host_cmd_dev, - EC_HOST_CMD_REQUEST_TRUNCATED); - continue; - } - - const struct ec_host_cmd_request_header *const rx_header = - (void *)rx.buf; - - /* Only support version 3 */ - if (rx_header->prtcl_ver != 3) { - send_error_response(ec_host_cmd_dev, - EC_HOST_CMD_INVALID_HEADER); - continue; - } - - const uint16_t rx_valid_data_size = - rx_header->data_len + RX_HEADER_SIZE; - /* - * Ensure we received at least as much data as is expected. - * It is okay to receive more since some hardware interfaces - * add on extra padding bytes at the end. - */ - if (*rx.len < rx_valid_data_size) { - send_error_response(ec_host_cmd_dev, - EC_HOST_CMD_REQUEST_TRUNCATED); - continue; - } - - /* Validate checksum */ - if (cal_checksum(rx.buf, rx_valid_data_size) != 0) { - send_error_response(ec_host_cmd_dev, - EC_HOST_CMD_INVALID_CHECKSUM); - continue; - } - - const struct ec_host_cmd_handler *found_handler = NULL; - + found_handler = NULL; STRUCT_SECTION_FOREACH(ec_host_cmd_handler, handler) { if (handler->id == rx_header->cmd_id) { @@ -133,79 +185,71 @@ static void handle_host_cmds_entry(void *arg1, void *arg2, void *arg3) /* No handler in this image for requested command */ if (found_handler == NULL) { - send_error_response(ec_host_cmd_dev, - EC_HOST_CMD_INVALID_COMMAND); + send_error_response(hc->backend, tx, EC_HOST_CMD_INVALID_COMMAND); continue; } - struct ec_host_cmd_handler_args args = { - .reserved = NULL, - .command = rx_header->cmd_id, - .version = rx_header->cmd_ver, - .input_buf = rx.buf + RX_HEADER_SIZE, - .input_buf_size = rx_header->data_len, - .output_buf = tx_buffer + TX_HEADER_SIZE, - .output_buf_max = sizeof(tx_buffer) - TX_HEADER_SIZE, - .output_buf_size = 0, - }; + args.command = rx_header->cmd_id; + args.version = rx_header->cmd_ver; + args.input_buf_size = rx_header->data_len; + args.output_buf_size = 0; - if (found_handler->min_rqt_size > args.input_buf_size) { - send_error_response(ec_host_cmd_dev, - EC_HOST_CMD_REQUEST_TRUNCATED); + status = validate_handler(found_handler, &args); + if (status != EC_HOST_CMD_SUCCESS) { + send_error_response(hc->backend, tx, status); continue; } - if (found_handler->min_rsp_size > args.output_buf_max) { - send_error_response(ec_host_cmd_dev, - EC_HOST_CMD_INVALID_RESPONSE); + status = found_handler->handler(&args); + if (status != EC_HOST_CMD_SUCCESS) { + send_error_response(hc->backend, tx, status); continue; } - if (args.version > sizeof(found_handler->version_mask) || - !(found_handler->version_mask & BIT(args.version))) { - send_error_response(ec_host_cmd_dev, - EC_HOST_CMD_INVALID_VERSION); + status = prepare_response(tx, args.output_buf_size); + if (status != EC_HOST_CMD_SUCCESS) { + send_error_response(hc->backend, tx, status); continue; } - const enum ec_host_cmd_status handler_rv = - found_handler->handler(&args); - - if (handler_rv != EC_HOST_CMD_SUCCESS) { - send_error_response(ec_host_cmd_dev, handler_rv); - continue; - } - - struct ec_host_cmd_response_header *const tx_header = - (void *)tx_buffer; - - tx_header->prtcl_ver = 3; - tx_header->result = EC_HOST_CMD_SUCCESS; - tx_header->data_len = args.output_buf_size; - tx_header->reserved = 0; - - const uint16_t tx_valid_data_size = - tx_header->data_len + TX_HEADER_SIZE; - if (tx_valid_data_size > sizeof(tx_buffer)) { - send_error_response(ec_host_cmd_dev, - EC_HOST_CMD_INVALID_RESPONSE); - continue; - } - - /* Calculate checksum */ - tx_header->checksum = 0; - tx_header->checksum = - cal_checksum(tx_buffer, tx_valid_data_size); - - const struct ec_host_cmd_tx_buf tx = { - .buf = tx_buffer, - .len = tx_valid_data_size, - }; - - ec_host_cmd_backend_send(ec_host_cmd_dev, &tx); + hc->backend->api->send(hc->backend); } } -K_THREAD_DEFINE(ec_host_cmd_handler_tid, CONFIG_EC_HOST_CMD_HANDLER_STACK_SIZE, - handle_host_cmds_entry, NULL, NULL, NULL, - CONFIG_EC_HOST_CMD_HANDLER_PRIO, 0, 0); +int ec_host_cmd_init(struct ec_host_cmd_backend *backend) +{ + struct ec_host_cmd *hc = &ec_host_cmd; + int ret; + uint8_t *handler_tx_buf, *handler_rx_buf; + + hc->backend = backend; + + /* Allow writing to rx buff at startup */ + k_sem_init(&hc->rx_ctx.handler_owns, 0, 1); + + handler_tx_buf = hc->tx.buf; + handler_rx_buf = hc->rx_ctx.buf; + + ret = backend->api->init(backend, &hc->rx_ctx, &hc->tx); + + if (ret != 0) { + return ret; + } + + if (!hc->tx.buf | !hc->rx_ctx.buf) { + LOG_ERR("No buffer for Host Command communication"); + return -EIO; + } + + if ((handler_tx_buf && (handler_tx_buf != hc->tx.buf)) || + (handler_rx_buf && (handler_rx_buf != hc->rx_ctx.buf))) { + LOG_WRN("Host Command handler provided unused buffer"); + } + + k_thread_create(hc->thread, hc->stack, CONFIG_EC_HOST_CMD_HANDLER_STACK_SIZE, + ec_host_cmd_thread, (void *)hc, NULL, NULL, CONFIG_EC_HOST_CMD_HANDLER_PRIO, + 0, K_NO_WAIT); + k_thread_name_set(hc->thread, "ec_host_cmd"); + + return 0; +} diff --git a/tests/subsys/mgmt/ec_host_cmd/prj.conf b/tests/subsys/mgmt/ec_host_cmd/prj.conf index 693f8a1af6..bca1ca5455 100644 --- a/tests/subsys/mgmt/ec_host_cmd/prj.conf +++ b/tests/subsys/mgmt/ec_host_cmd/prj.conf @@ -1,5 +1,4 @@ CONFIG_EC_HOST_CMD=y -CONFIG_EC_HOST_CMD_BACKEND=y CONFIG_EC_HOST_CMD_BACKEND_SIMULATOR=y CONFIG_ZTEST=y CONFIG_ZTEST_NEW_API=y diff --git a/tests/subsys/mgmt/ec_host_cmd/src/main.c b/tests/subsys/mgmt/ec_host_cmd/src/main.c index 4fa3dd2d0b..5f19068470 100644 --- a/tests/subsys/mgmt/ec_host_cmd/src/main.c +++ b/tests/subsys/mgmt/ec_host_cmd/src/main.c @@ -10,13 +10,10 @@ /* Variables used to record what is "sent" to host for verification. */ K_SEM_DEFINE(send_called, 0, 1); -struct ec_host_cmd_tx_buf sent; +struct ec_host_cmd_tx_buf *sent; -static int host_send(const struct device *const dev, - const struct ec_host_cmd_tx_buf *const buf) +static int host_send(const struct ec_host_cmd_backend *backend) { - sent.len = buf->len; - sent.buf = buf->buf; k_sem_give(&send_called); return 0; } @@ -124,8 +121,8 @@ static void verify_tx_data(void) { update_dut_to_host_checksum(); - zassert_equal(sent.len, expected_tx_size(), "Sent bytes did not match"); - zassert_mem_equal(sent.buf, expected_dut_to_host, expected_tx_size(), + zassert_equal(sent->len, expected_tx_size(), "Sent bytes did not match"); + zassert_mem_equal(sent->buf, expected_dut_to_host, expected_tx_size(), "Sent buffer did not match"); } @@ -137,8 +134,8 @@ static void verify_tx_error(enum ec_host_cmd_status error) expected_dut_to_host->header.reserved = 0; update_dut_to_host_checksum(); - zassert_equal(sent.len, expected_tx_size(), "Sent bytes did not match"); - zassert_mem_equal(sent.buf, expected_dut_to_host, expected_tx_size(), + zassert_equal(sent->len, expected_tx_size(), "Sent bytes did not match"); + zassert_mem_equal(sent->buf, expected_dut_to_host, expected_tx_size(), "Sent buffer did not match"); } @@ -439,7 +436,7 @@ ZTEST(ec_host_cmd, test_response_always_too_big) static void *ec_host_cmd_tests_setup(void) { - ec_host_cmd_backend_sim_install_send_cb(host_send); + ec_host_cmd_backend_sim_install_send_cb(host_send, &sent); return NULL; }