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 <dawidn@google.com>
This commit is contained in:
Dawid Niedzwiecki 2022-11-18 12:08:33 +00:00 committed by Carles Cufí
parent b2674a4b34
commit 2d0a784c41
24 changed files with 758 additions and 519 deletions

View file

@ -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:

View file

@ -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";

View file

@ -1,13 +0,0 @@
.. _ec_host_cmd_backend_api:
EC Host Command
###############
Overview
********
API Reference
*************
.. doxygengroup:: ec_host_cmd_backend_interface

View file

@ -15,7 +15,6 @@ Peripherals
dac.rst
display/index.rst
dma.rst
ec_host_cmd.rst
edac/index.rst
eeprom.rst
entropy.rst

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View file

@ -13,6 +13,7 @@ Device Management
smp_transport.rst
dfu.rst
ota.rst
ec_host_cmd.rst
SMP Groups
==========

View file

@ -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

View file

@ -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

View file

@ -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_ */

View file

@ -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 <stdint.h>
#include <zephyr/mgmt/ec_host_cmd/backend.h>
#include <zephyr/sys/__assert.h>
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);
/**
* @}
*/

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -4,103 +4,157 @@
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT zephyr_ec_host_cmd_backend_espi
#include <string.h>
#include <zephyr/device.h>
#include <zephyr/drivers/espi.h>
#include <zephyr/logging/log.h>
#include <zephyr/mgmt/ec_host_cmd/backend.h>
#include <zephyr/mgmt/ec_host_cmd/ec_host_cmd.h>
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

View file

@ -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 <zephyr/device.h>
@ -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_ */

View file

@ -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

View file

@ -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

View file

@ -4,84 +4,83 @@
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT zephyr_sim_ec_host_cmd_backend
#include <errno.h>
#include <zephyr/device.h>
#include <zephyr/mgmt/ec_host_cmd/backend.h>
#include <zephyr/mgmt/ec_host_cmd/ec_host_cmd.h>
#include <string.h>
#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);

View file

@ -6,24 +6,42 @@
#include <zephyr/devicetree.h>
#include <zephyr/kernel.h>
#include <string.h>
#include <zephyr/mgmt/ec_host_cmd/backend.h>
#include <zephyr/logging/log.h>
#include <zephyr/mgmt/ec_host_cmd/ec_host_cmd.h>
#include <zephyr/mgmt/ec_host_cmd/backend.h>
#include <string.h>
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;
}

View file

@ -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

View file

@ -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;
}