Commit 5bb3bf24 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tag-chrome-platform-for-v5.20' of...

Merge tag 'tag-chrome-platform-for-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux

Pull chrome platform updates from Tzung-Bi Shih:
 "cros_ec_proto:
   - Leverage Kunit and add Kunit test cases
   - Clean-ups
   - Fix typo

  cros_ec_commands:
   - Fix typo
   - Fix compile errors

  cros_kbd_led_backlight:
   - Support OF match
   - Support EC PWM backend

  cros_ec:
   - Always expose the last resume result to fix sleep hang detection on
     ARM-based chromebooks

  wilco_ec:
   - Fix typo

  cros_ec_typec:
   - Clean-ups
   - Use Type-C framework utilities to manage altmode structs"

* tag 'tag-chrome-platform-for-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux: (59 commits)
  platform/chrome: cros_kunit_util: add default value for `msg->result`
  platform/chrome: merge Kunit utils and test cases
  platform/chrome: cros_kbd_led_backlight: fix build warning
  platform/chrome: cros_ec_proto: add Kunit test for cros_ec_cmd()
  platform/chrome: cros_ec_proto: add Kunit tests for get_sensor_count
  platform/chrome: cros_ec_proto: add Kunit tests for check_features
  platform/chrome: cros_ec_proto: add Kunit tests for get_host_event
  platform/chrome: cros_ec_proto: add Kunit tests for get_next_event
  platform/chrome: cros_ec_proto: add Kunit test for cros_ec_map_error()
  platform/chrome: cros_ec_proto: add Kunit tests for cmd_xfer_status
  platform/chrome: cros_ec_proto: return -EPROTO if empty payload
  platform/chrome: cros_ec_proto: add Kunit test for empty payload
  platform/chrome: cros_ec_proto: return -EAGAIN when retries timed out
  platform/chrome: cros_ec_proto: change Kunit expectation when timed out
  platform/chrome: cros_ec_proto: separate cros_ec_wait_until_complete()
  platform/chrome: cros_ec_proto: separate cros_ec_xfer_command()
  platform/chrome: cros_ec_proto: add Kunit tests for cros_ec_send_command()
  platform/chrome: cros_ec_proto: add Kunit tests for cros_ec_cmd_xfer()
  platform/chrome: cros_ec_proto: add "cros_ec_" prefix to send_command()
  platform/chrome: cros_ec_typec: Register port altmodes
  ...
parents da8d07af afef1e1a
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/chrome/google,cros-kbd-led-backlight.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ChromeOS keyboard backlight LED driver.
maintainers:
- Tzung-Bi Shih <tzungbi@kernel.org>
properties:
compatible:
const: google,cros-kbd-led-backlight
required:
- compatible
additionalProperties: false
examples:
- |
spi0 {
#address-cells = <1>;
#size-cells = <0>;
cros_ec: ec@0 {
compatible = "google,cros-ec-spi";
reg = <0>;
kbd-led-backlight {
compatible = "google,cros-kbd-led-backlight";
};
};
};
......@@ -90,6 +90,9 @@ properties:
pwm:
$ref: "/schemas/pwm/google,cros-ec-pwm.yaml#"
kbd-led-backlight:
$ref: "/schemas/chrome/google,cros-kbd-led-backlight.yaml#"
keyboard-controller:
$ref: "/schemas/input/google,cros-ec-keyb.yaml#"
......
......@@ -250,8 +250,8 @@ static int ec_device_probe(struct platform_device *pdev)
* The PCHG device cannot be detected by sending EC_FEATURE_GET_CMD, but
* it can be detected by querying the number of peripheral chargers.
*/
retval = cros_ec_command(ec->ec_dev, 0, EC_CMD_PCHG_COUNT, NULL, 0,
&pchg_count, sizeof(pchg_count));
retval = cros_ec_cmd(ec->ec_dev, 0, EC_CMD_PCHG_COUNT, NULL, 0,
&pchg_count, sizeof(pchg_count));
if (retval >= 0 && pchg_count.port_count) {
retval = mfd_add_hotplug_devices(ec->dev,
cros_ec_pchg_cells,
......
......@@ -139,7 +139,7 @@ config CROS_EC_PROTO
config CROS_KBD_LED_BACKLIGHT
tristate "Backlight LED support for Chrome OS keyboards"
depends on LEDS_CLASS && ACPI
depends on LEDS_CLASS && (ACPI || CROS_EC)
help
This option enables support for the keyboard backlight LEDs on
select Chrome OS systems.
......@@ -267,4 +267,13 @@ config CHROMEOS_PRIVACY_SCREEN
source "drivers/platform/chrome/wilco_ec/Kconfig"
# Kunit test cases
config CROS_KUNIT
tristate "Kunit tests for ChromeOS" if !KUNIT_ALL_TESTS
depends on KUNIT && CROS_EC
default KUNIT_ALL_TESTS
select CROS_EC_PROTO
help
ChromeOS Kunit tests.
endif # CHROMEOS_PLATFORMS
......@@ -30,3 +30,8 @@ obj-$(CONFIG_CROS_USBPD_LOGGER) += cros_usbpd_logger.o
obj-$(CONFIG_CROS_USBPD_NOTIFY) += cros_usbpd_notify.o
obj-$(CONFIG_WILCO_EC) += wilco_ec/
# Kunit test cases
obj-$(CONFIG_CROS_KUNIT) += cros_kunit.o
cros_kunit-objs := cros_kunit_util.o
cros_kunit-objs += cros_ec_proto_test.o
......@@ -19,9 +19,6 @@
#include "cros_ec.h"
#define CROS_EC_DEV_EC_INDEX 0
#define CROS_EC_DEV_PD_INDEX 1
static struct cros_ec_platform ec_p = {
.ec_name = CROS_EC_DEV_NAME,
.cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_EC_INDEX),
......@@ -135,16 +132,16 @@ static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event)
buf.msg.command = EC_CMD_HOST_SLEEP_EVENT;
ret = cros_ec_cmd_xfer_status(ec_dev, &buf.msg);
/* For now, report failure to transition to S0ix with a warning. */
/* Report failure to transition to system wide suspend with a warning. */
if (ret >= 0 && ec_dev->host_sleep_v1 &&
(sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME)) {
(sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME ||
sleep_event == HOST_SLEEP_EVENT_S3_RESUME)) {
ec_dev->last_resume_result =
buf.u.resp1.resume_response.sleep_transitions;
WARN_ONCE(buf.u.resp1.resume_response.sleep_transitions &
EC_HOST_RESUME_SLEEP_TIMEOUT,
"EC detected sleep transition timeout. Total slp_s0 transitions: %d",
"EC detected sleep transition timeout. Total sleep transitions: %d",
buf.u.resp1.resume_response.sleep_transitions &
EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK);
}
......
......@@ -52,8 +52,8 @@ static int cros_ec_map_error(uint32_t result)
return ret;
}
static int prepare_packet(struct cros_ec_device *ec_dev,
struct cros_ec_command *msg)
static int prepare_tx(struct cros_ec_device *ec_dev,
struct cros_ec_command *msg)
{
struct ec_host_request *request;
u8 *out;
......@@ -85,8 +85,29 @@ static int prepare_packet(struct cros_ec_device *ec_dev,
return sizeof(*request) + msg->outsize;
}
static int send_command(struct cros_ec_device *ec_dev,
struct cros_ec_command *msg)
static int prepare_tx_legacy(struct cros_ec_device *ec_dev,
struct cros_ec_command *msg)
{
u8 *out;
u8 csum;
int i;
if (msg->outsize > EC_PROTO2_MAX_PARAM_SIZE)
return -EINVAL;
out = ec_dev->dout;
out[0] = EC_CMD_VERSION0 + msg->version;
out[1] = msg->command;
out[2] = msg->outsize;
csum = out[0] + out[1] + out[2];
for (i = 0; i < msg->outsize; i++)
csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->data[i];
out[EC_MSG_TX_HEADER_BYTES + msg->outsize] = csum;
return EC_MSG_TX_PROTO_BYTES + msg->outsize;
}
static int cros_ec_xfer_command(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
{
int ret;
int (*xfer_fxn)(struct cros_ec_device *ec, struct cros_ec_command *msg);
......@@ -102,57 +123,68 @@ static int send_command(struct cros_ec_device *ec_dev,
* the EC is trying to use protocol v2, on an underlying
* communication mechanism that does not support v2.
*/
dev_err_once(ec_dev->dev,
"missing EC transfer API, cannot send command\n");
dev_err_once(ec_dev->dev, "missing EC transfer API, cannot send command\n");
return -EIO;
}
trace_cros_ec_request_start(msg);
ret = (*xfer_fxn)(ec_dev, msg);
trace_cros_ec_request_done(msg, ret);
if (msg->result == EC_RES_IN_PROGRESS) {
int i;
struct cros_ec_command *status_msg;
struct ec_response_get_comms_status *status;
status_msg = kmalloc(sizeof(*status_msg) + sizeof(*status),
GFP_KERNEL);
if (!status_msg)
return -ENOMEM;
return ret;
}
status_msg->version = 0;
status_msg->command = EC_CMD_GET_COMMS_STATUS;
status_msg->insize = sizeof(*status);
status_msg->outsize = 0;
static int cros_ec_wait_until_complete(struct cros_ec_device *ec_dev, uint32_t *result)
{
struct {
struct cros_ec_command msg;
struct ec_response_get_comms_status status;
} __packed buf;
struct cros_ec_command *msg = &buf.msg;
struct ec_response_get_comms_status *status = &buf.status;
int ret = 0, i;
/*
* Query the EC's status until it's no longer busy or
* we encounter an error.
*/
for (i = 0; i < EC_COMMAND_RETRIES; i++) {
usleep_range(10000, 11000);
trace_cros_ec_request_start(status_msg);
ret = (*xfer_fxn)(ec_dev, status_msg);
trace_cros_ec_request_done(status_msg, ret);
if (ret == -EAGAIN)
continue;
if (ret < 0)
break;
msg->result = status_msg->result;
if (status_msg->result != EC_RES_SUCCESS)
break;
status = (struct ec_response_get_comms_status *)
status_msg->data;
if (!(status->flags & EC_COMMS_STATUS_PROCESSING))
break;
msg->version = 0;
msg->command = EC_CMD_GET_COMMS_STATUS;
msg->insize = sizeof(*status);
msg->outsize = 0;
/* Query the EC's status until it's no longer busy or we encounter an error. */
for (i = 0; i < EC_COMMAND_RETRIES; ++i) {
usleep_range(10000, 11000);
ret = cros_ec_xfer_command(ec_dev, msg);
if (ret == -EAGAIN)
continue;
if (ret < 0)
return ret;
*result = msg->result;
if (msg->result != EC_RES_SUCCESS)
return ret;
if (ret == 0) {
ret = -EPROTO;
break;
}
kfree(status_msg);
if (!(status->flags & EC_COMMS_STATUS_PROCESSING))
return ret;
}
if (i >= EC_COMMAND_RETRIES)
ret = -EAGAIN;
return ret;
}
static int cros_ec_send_command(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
{
int ret = cros_ec_xfer_command(ec_dev, msg);
if (msg->result == EC_RES_IN_PROGRESS)
ret = cros_ec_wait_until_complete(ec_dev, &msg->result);
return ret;
}
......@@ -161,35 +193,18 @@ static int send_command(struct cros_ec_device *ec_dev,
* @ec_dev: Device to register.
* @msg: Message to write.
*
* This is intended to be used by all ChromeOS EC drivers, but at present
* only SPI uses it. Once LPC uses the same protocol it can start using it.
* I2C could use it now, with a refactor of the existing code.
* This is used by all ChromeOS EC drivers to prepare the outgoing message
* according to different protocol versions.
*
* Return: number of prepared bytes on success or negative error code.
*/
int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
struct cros_ec_command *msg)
{
u8 *out;
u8 csum;
int i;
if (ec_dev->proto_version > 2)
return prepare_packet(ec_dev, msg);
if (msg->outsize > EC_PROTO2_MAX_PARAM_SIZE)
return -EINVAL;
return prepare_tx(ec_dev, msg);
out = ec_dev->dout;
out[0] = EC_CMD_VERSION0 + msg->version;
out[1] = msg->command;
out[2] = msg->outsize;
csum = out[0] + out[1] + out[2];
for (i = 0; i < msg->outsize; i++)
csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->data[i];
out[EC_MSG_TX_HEADER_BYTES + msg->outsize] = csum;
return EC_MSG_TX_PROTO_BYTES + msg->outsize;
return prepare_tx_legacy(ec_dev, msg);
}
EXPORT_SYMBOL(cros_ec_prepare_tx);
......@@ -199,9 +214,12 @@ EXPORT_SYMBOL(cros_ec_prepare_tx);
* @msg: Message to check.
*
* This is used by ChromeOS EC drivers to check the ec_msg->result for
* errors and to warn about them.
* EC_RES_IN_PROGRESS and to warn about them.
*
* Return: 0 on success or negative error code.
* The function should not check for furthermore error codes. Otherwise,
* it would break the ABI.
*
* Return: -EAGAIN if ec_msg->result == EC_RES_IN_PROGRESS. Otherwise, 0.
*/
int cros_ec_check_result(struct cros_ec_device *ec_dev,
struct cros_ec_command *msg)
......@@ -228,59 +246,66 @@ EXPORT_SYMBOL(cros_ec_check_result);
*
* @ec_dev: EC device to call
* @msg: message structure to use
* @mask: result when function returns >=0.
* @mask: result when function returns 0.
*
* LOCKING:
* the caller has ec_dev->lock mutex, or the caller knows there is
* no other command in progress.
*/
static int cros_ec_get_host_event_wake_mask(struct cros_ec_device *ec_dev,
struct cros_ec_command *msg,
uint32_t *mask)
static int cros_ec_get_host_event_wake_mask(struct cros_ec_device *ec_dev, uint32_t *mask)
{
struct cros_ec_command *msg;
struct ec_response_host_event_mask *r;
int ret;
int ret, mapped;
msg = kzalloc(sizeof(*msg) + sizeof(*r), GFP_KERNEL);
if (!msg)
return -ENOMEM;
msg->command = EC_CMD_HOST_EVENT_GET_WAKE_MASK;
msg->version = 0;
msg->outsize = 0;
msg->insize = sizeof(*r);
ret = send_command(ec_dev, msg);
if (ret >= 0) {
if (msg->result == EC_RES_INVALID_COMMAND)
return -EOPNOTSUPP;
if (msg->result != EC_RES_SUCCESS)
return -EPROTO;
ret = cros_ec_send_command(ec_dev, msg);
if (ret < 0)
goto exit;
mapped = cros_ec_map_error(msg->result);
if (mapped) {
ret = mapped;
goto exit;
}
if (ret > 0) {
r = (struct ec_response_host_event_mask *)msg->data;
*mask = r->mask;
if (ret == 0) {
ret = -EPROTO;
goto exit;
}
r = (struct ec_response_host_event_mask *)msg->data;
*mask = r->mask;
ret = 0;
exit:
kfree(msg);
return ret;
}
static int cros_ec_host_command_proto_query(struct cros_ec_device *ec_dev,
int devidx,
struct cros_ec_command *msg)
static int cros_ec_get_proto_info(struct cros_ec_device *ec_dev, int devidx)
{
/*
* Try using v3+ to query for supported protocols. If this
* command fails, fall back to v2. Returns the highest protocol
* supported by the EC.
* Also sets the max request/response/passthru size.
*/
int ret;
struct cros_ec_command *msg;
struct ec_response_get_protocol_info *info;
int ret, mapped;
if (!ec_dev->pkt_xfer)
return -EPROTONOSUPPORT;
ec_dev->proto_version = 3;
if (devidx > 0)
ec_dev->max_passthru = 0;
msg = kzalloc(sizeof(*msg) + sizeof(*info), GFP_KERNEL);
if (!msg)
return -ENOMEM;
memset(msg, 0, sizeof(*msg));
msg->command = EC_CMD_PASSTHRU_OFFSET(devidx) | EC_CMD_GET_PROTOCOL_INFO;
msg->insize = sizeof(struct ec_response_get_protocol_info);
msg->insize = sizeof(*info);
ret = send_command(ec_dev, msg);
ret = cros_ec_send_command(ec_dev, msg);
/*
* Send command once again when timeout occurred.
* Fingerprint MCU (FPMCU) is restarted during system boot which
......@@ -289,68 +314,115 @@ static int cros_ec_host_command_proto_query(struct cros_ec_device *ec_dev,
* attempt because we waited at least EC_MSG_DEADLINE_MS.
*/
if (ret == -ETIMEDOUT)
ret = send_command(ec_dev, msg);
ret = cros_ec_send_command(ec_dev, msg);
if (ret < 0) {
dev_dbg(ec_dev->dev,
"failed to check for EC[%d] protocol version: %d\n",
devidx, ret);
return ret;
goto exit;
}
if (devidx > 0 && msg->result == EC_RES_INVALID_COMMAND)
return -ENODEV;
else if (msg->result != EC_RES_SUCCESS)
return msg->result;
mapped = cros_ec_map_error(msg->result);
if (mapped) {
ret = mapped;
goto exit;
}
return 0;
if (ret == 0) {
ret = -EPROTO;
goto exit;
}
info = (struct ec_response_get_protocol_info *)msg->data;
switch (devidx) {
case CROS_EC_DEV_EC_INDEX:
ec_dev->max_request = info->max_request_packet_size -
sizeof(struct ec_host_request);
ec_dev->max_response = info->max_response_packet_size -
sizeof(struct ec_host_response);
ec_dev->proto_version = min(EC_HOST_REQUEST_VERSION,
fls(info->protocol_versions) - 1);
ec_dev->din_size = info->max_response_packet_size + EC_MAX_RESPONSE_OVERHEAD;
ec_dev->dout_size = info->max_request_packet_size + EC_MAX_REQUEST_OVERHEAD;
dev_dbg(ec_dev->dev, "using proto v%u\n", ec_dev->proto_version);
break;
case CROS_EC_DEV_PD_INDEX:
ec_dev->max_passthru = info->max_request_packet_size -
sizeof(struct ec_host_request);
dev_dbg(ec_dev->dev, "found PD chip\n");
break;
default:
dev_dbg(ec_dev->dev, "unknown passthru index: %d\n", devidx);
break;
}
ret = 0;
exit:
kfree(msg);
return ret;
}
static int cros_ec_host_command_proto_query_v2(struct cros_ec_device *ec_dev)
static int cros_ec_get_proto_info_legacy(struct cros_ec_device *ec_dev)
{
struct cros_ec_command *msg;
struct ec_params_hello *hello_params;
struct ec_response_hello *hello_response;
int ret;
int len = max(sizeof(*hello_params), sizeof(*hello_response));
struct ec_params_hello *params;
struct ec_response_hello *response;
int ret, mapped;
ec_dev->proto_version = 2;
msg = kmalloc(sizeof(*msg) + len, GFP_KERNEL);
msg = kzalloc(sizeof(*msg) + max(sizeof(*params), sizeof(*response)), GFP_KERNEL);
if (!msg)
return -ENOMEM;
msg->version = 0;
msg->command = EC_CMD_HELLO;
hello_params = (struct ec_params_hello *)msg->data;
msg->outsize = sizeof(*hello_params);
hello_response = (struct ec_response_hello *)msg->data;
msg->insize = sizeof(*hello_response);
hello_params->in_data = 0xa0b0c0d0;
msg->insize = sizeof(*response);
msg->outsize = sizeof(*params);
ret = send_command(ec_dev, msg);
params = (struct ec_params_hello *)msg->data;
params->in_data = 0xa0b0c0d0;
ret = cros_ec_send_command(ec_dev, msg);
if (ret < 0) {
dev_dbg(ec_dev->dev,
"EC failed to respond to v2 hello: %d\n",
ret);
dev_dbg(ec_dev->dev, "EC failed to respond to v2 hello: %d\n", ret);
goto exit;
} else if (msg->result != EC_RES_SUCCESS) {
dev_err(ec_dev->dev,
"EC responded to v2 hello with error: %d\n",
msg->result);
ret = msg->result;
}
mapped = cros_ec_map_error(msg->result);
if (mapped) {
ret = mapped;
dev_err(ec_dev->dev, "EC responded to v2 hello with error: %d\n", msg->result);
goto exit;
}
if (ret == 0) {
ret = -EPROTO;
goto exit;
} else if (hello_response->out_data != 0xa1b2c3d4) {
}
response = (struct ec_response_hello *)msg->data;
if (response->out_data != 0xa1b2c3d4) {
dev_err(ec_dev->dev,
"EC responded to v2 hello with bad result: %u\n",
hello_response->out_data);
response->out_data);
ret = -EBADMSG;
goto exit;
}
ret = 0;
ec_dev->max_request = EC_PROTO2_MAX_PARAM_SIZE;
ec_dev->max_response = EC_PROTO2_MAX_PARAM_SIZE;
ec_dev->max_passthru = 0;
ec_dev->pkt_xfer = NULL;
ec_dev->din_size = EC_PROTO2_MSG_BYTES;
ec_dev->dout_size = EC_PROTO2_MSG_BYTES;
exit:
dev_dbg(ec_dev->dev, "falling back to proto v2\n");
ret = 0;
exit:
kfree(msg);
return ret;
}
......@@ -371,13 +443,12 @@ static int cros_ec_host_command_proto_query_v2(struct cros_ec_device *ec_dev)
* the caller has ec_dev->lock mutex or the caller knows there is
* no other command in progress.
*/
static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev,
u16 cmd, u32 *mask)
static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev, u16 cmd, u32 *mask)
{
struct ec_params_get_cmd_versions *pver;
struct ec_response_get_cmd_versions *rver;
struct cros_ec_command *msg;
int ret;
int ret, mapped;
msg = kmalloc(sizeof(*msg) + max(sizeof(*rver), sizeof(*pver)),
GFP_KERNEL);
......@@ -392,14 +463,26 @@ static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev,
pver = (struct ec_params_get_cmd_versions *)msg->data;
pver->cmd = cmd;
ret = send_command(ec_dev, msg);
if (ret > 0) {
rver = (struct ec_response_get_cmd_versions *)msg->data;
*mask = rver->version_mask;
ret = cros_ec_send_command(ec_dev, msg);
if (ret < 0)
goto exit;
mapped = cros_ec_map_error(msg->result);
if (mapped) {
ret = mapped;
goto exit;
}
kfree(msg);
if (ret == 0) {
ret = -EPROTO;
goto exit;
}
rver = (struct ec_response_get_cmd_versions *)msg->data;
*mask = rver->version_mask;
ret = 0;
exit:
kfree(msg);
return ret;
}
......@@ -413,71 +496,17 @@ static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev,
int cros_ec_query_all(struct cros_ec_device *ec_dev)
{
struct device *dev = ec_dev->dev;
struct cros_ec_command *proto_msg;
struct ec_response_get_protocol_info *proto_info;
u32 ver_mask = 0;
u32 ver_mask;
int ret;
proto_msg = kzalloc(sizeof(*proto_msg) + sizeof(*proto_info),
GFP_KERNEL);
if (!proto_msg)
return -ENOMEM;
/* First try sending with proto v3. */
ec_dev->proto_version = 3;
ret = cros_ec_host_command_proto_query(ec_dev, 0, proto_msg);
if (ret == 0) {
proto_info = (struct ec_response_get_protocol_info *)
proto_msg->data;
ec_dev->max_request = proto_info->max_request_packet_size -
sizeof(struct ec_host_request);
ec_dev->max_response = proto_info->max_response_packet_size -
sizeof(struct ec_host_response);
ec_dev->proto_version =
min(EC_HOST_REQUEST_VERSION,
fls(proto_info->protocol_versions) - 1);
dev_dbg(ec_dev->dev,
"using proto v%u\n",
ec_dev->proto_version);
ec_dev->din_size = ec_dev->max_response +
sizeof(struct ec_host_response) +
EC_MAX_RESPONSE_OVERHEAD;
ec_dev->dout_size = ec_dev->max_request +
sizeof(struct ec_host_request) +
EC_MAX_REQUEST_OVERHEAD;
/*
* Check for PD
*/
ret = cros_ec_host_command_proto_query(ec_dev, 1, proto_msg);
if (ret) {
dev_dbg(ec_dev->dev, "no PD chip found: %d\n", ret);
ec_dev->max_passthru = 0;
} else {
dev_dbg(ec_dev->dev, "found PD chip\n");
ec_dev->max_passthru =
proto_info->max_request_packet_size -
sizeof(struct ec_host_request);
}
if (!cros_ec_get_proto_info(ec_dev, CROS_EC_DEV_EC_INDEX)) {
/* Check for PD. */
cros_ec_get_proto_info(ec_dev, CROS_EC_DEV_PD_INDEX);
} else {
/* Try querying with a v2 hello message. */
ec_dev->proto_version = 2;
ret = cros_ec_host_command_proto_query_v2(ec_dev);
if (ret == 0) {
/* V2 hello succeeded. */
dev_dbg(ec_dev->dev, "falling back to proto v2\n");
ec_dev->max_request = EC_PROTO2_MAX_PARAM_SIZE;
ec_dev->max_response = EC_PROTO2_MAX_PARAM_SIZE;
ec_dev->max_passthru = 0;
ec_dev->pkt_xfer = NULL;
ec_dev->din_size = EC_PROTO2_MSG_BYTES;
ec_dev->dout_size = EC_PROTO2_MSG_BYTES;
} else {
ret = cros_ec_get_proto_info_legacy(ec_dev);
if (ret) {
/*
* It's possible for a test to occur too early when
* the EC isn't listening. If this happens, we'll
......@@ -485,7 +514,7 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev)
*/
ec_dev->proto_version = EC_PROTO_VERSION_UNKNOWN;
dev_dbg(ec_dev->dev, "EC query failed: %d\n", ret);
goto exit;
return ret;
}
}
......@@ -506,26 +535,21 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev)
}
/* Probe if MKBP event is supported */
ret = cros_ec_get_host_command_version_mask(ec_dev,
EC_CMD_GET_NEXT_EVENT,
&ver_mask);
if (ret < 0 || ver_mask == 0)
ret = cros_ec_get_host_command_version_mask(ec_dev, EC_CMD_GET_NEXT_EVENT, &ver_mask);
if (ret < 0 || ver_mask == 0) {
ec_dev->mkbp_event_supported = 0;
else
} else {
ec_dev->mkbp_event_supported = fls(ver_mask);
dev_dbg(ec_dev->dev, "MKBP support version %u\n",
ec_dev->mkbp_event_supported - 1);
dev_dbg(ec_dev->dev, "MKBP support version %u\n", ec_dev->mkbp_event_supported - 1);
}
/* Probe if host sleep v1 is supported for S0ix failure detection. */
ret = cros_ec_get_host_command_version_mask(ec_dev,
EC_CMD_HOST_SLEEP_EVENT,
&ver_mask);
ec_dev->host_sleep_v1 = (ret >= 0 && (ver_mask & EC_VER_MASK(1)));
ret = cros_ec_get_host_command_version_mask(ec_dev, EC_CMD_HOST_SLEEP_EVENT, &ver_mask);
ec_dev->host_sleep_v1 = (ret == 0 && (ver_mask & EC_VER_MASK(1)));
/* Get host event wake mask. */
ret = cros_ec_get_host_event_wake_mask(ec_dev, proto_msg,
&ec_dev->host_event_wake_mask);
ret = cros_ec_get_host_event_wake_mask(ec_dev, &ec_dev->host_event_wake_mask);
if (ret < 0) {
/*
* If the EC doesn't support EC_CMD_HOST_EVENT_GET_WAKE_MASK,
......@@ -556,7 +580,6 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev)
ret = 0;
exit:
kfree(proto_msg);
return ret;
}
EXPORT_SYMBOL(cros_ec_query_all);
......@@ -601,7 +624,7 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
msg->insize = ec_dev->max_response;
}
if (msg->command < EC_CMD_PASSTHRU_OFFSET(1)) {
if (msg->command < EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX)) {
if (msg->outsize > ec_dev->max_request) {
dev_err(ec_dev->dev,
"request of size %u is too big (max: %u)\n",
......@@ -621,7 +644,7 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
}
}
ret = send_command(ec_dev, msg);
ret = cros_ec_send_command(ec_dev, msg);
mutex_unlock(&ec_dev->lock);
return ret;
......@@ -852,8 +875,8 @@ bool cros_ec_check_features(struct cros_ec_dev *ec, int feature)
if (features->flags[0] == -1U && features->flags[1] == -1U) {
/* features bitmap not read yet */
ret = cros_ec_command(ec->ec_dev, 0, EC_CMD_GET_FEATURES + ec->cmd_offset,
NULL, 0, features, sizeof(*features));
ret = cros_ec_cmd(ec->ec_dev, 0, EC_CMD_GET_FEATURES + ec->cmd_offset,
NULL, 0, features, sizeof(*features));
if (ret < 0) {
dev_warn(ec->dev, "cannot get EC features: %d\n", ret);
memset(features, 0, sizeof(*features));
......@@ -934,7 +957,7 @@ int cros_ec_get_sensor_count(struct cros_ec_dev *ec)
EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count);
/**
* cros_ec_command - Send a command to the EC.
* cros_ec_cmd - Send a command to the EC.
*
* @ec_dev: EC device
* @version: EC command version
......@@ -946,13 +969,13 @@ EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count);
*
* Return: >= 0 on success, negative error number on failure.
*/
int cros_ec_command(struct cros_ec_device *ec_dev,
unsigned int version,
int command,
void *outdata,
int outsize,
void *indata,
int insize)
int cros_ec_cmd(struct cros_ec_device *ec_dev,
unsigned int version,
int command,
void *outdata,
size_t outsize,
void *indata,
size_t insize)
{
struct cros_ec_command *msg;
int ret;
......@@ -979,4 +1002,4 @@ int cros_ec_command(struct cros_ec_device *ec_dev,
kfree(msg);
return ret;
}
EXPORT_SYMBOL_GPL(cros_ec_command);
EXPORT_SYMBOL_GPL(cros_ec_cmd);
// SPDX-License-Identifier: GPL-2.0
/*
* Kunit tests for ChromeOS Embedded Controller protocol.
*/
#include <kunit/test.h>
#include <asm-generic/unaligned.h>
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
#include "cros_ec.h"
#include "cros_kunit_util.h"
#define BUFSIZE 512
struct cros_ec_proto_test_priv {
struct cros_ec_device ec_dev;
u8 dout[BUFSIZE];
u8 din[BUFSIZE];
struct cros_ec_command *msg;
u8 _msg[BUFSIZE];
};
static void cros_ec_proto_test_prepare_tx_legacy_normal(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct cros_ec_command *msg = priv->msg;
int ret, i;
u8 csum;
ec_dev->proto_version = 2;
msg->command = EC_CMD_HELLO;
msg->outsize = EC_PROTO2_MAX_PARAM_SIZE;
msg->data[0] = 0xde;
msg->data[1] = 0xad;
msg->data[2] = 0xbe;
msg->data[3] = 0xef;
ret = cros_ec_prepare_tx(ec_dev, msg);
KUNIT_EXPECT_EQ(test, ret, EC_MSG_TX_PROTO_BYTES + EC_PROTO2_MAX_PARAM_SIZE);
KUNIT_EXPECT_EQ(test, ec_dev->dout[0], EC_CMD_VERSION0);
KUNIT_EXPECT_EQ(test, ec_dev->dout[1], EC_CMD_HELLO);
KUNIT_EXPECT_EQ(test, ec_dev->dout[2], EC_PROTO2_MAX_PARAM_SIZE);
KUNIT_EXPECT_EQ(test, EC_MSG_TX_HEADER_BYTES, 3);
KUNIT_EXPECT_EQ(test, ec_dev->dout[EC_MSG_TX_HEADER_BYTES + 0], 0xde);
KUNIT_EXPECT_EQ(test, ec_dev->dout[EC_MSG_TX_HEADER_BYTES + 1], 0xad);
KUNIT_EXPECT_EQ(test, ec_dev->dout[EC_MSG_TX_HEADER_BYTES + 2], 0xbe);
KUNIT_EXPECT_EQ(test, ec_dev->dout[EC_MSG_TX_HEADER_BYTES + 3], 0xef);
for (i = 4; i < EC_PROTO2_MAX_PARAM_SIZE; ++i)
KUNIT_EXPECT_EQ(test, ec_dev->dout[EC_MSG_TX_HEADER_BYTES + i], 0);
csum = EC_CMD_VERSION0;
csum += EC_CMD_HELLO;
csum += EC_PROTO2_MAX_PARAM_SIZE;
csum += 0xde;
csum += 0xad;
csum += 0xbe;
csum += 0xef;
KUNIT_EXPECT_EQ(test,
ec_dev->dout[EC_MSG_TX_HEADER_BYTES + EC_PROTO2_MAX_PARAM_SIZE],
csum);
}
static void cros_ec_proto_test_prepare_tx_legacy_bad_msg_outsize(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct cros_ec_command *msg = priv->msg;
int ret;
ec_dev->proto_version = 2;
msg->outsize = EC_PROTO2_MAX_PARAM_SIZE + 1;
ret = cros_ec_prepare_tx(ec_dev, msg);
KUNIT_EXPECT_EQ(test, ret, -EINVAL);
}
static void cros_ec_proto_test_prepare_tx_normal(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct cros_ec_command *msg = priv->msg;
struct ec_host_request *request = (struct ec_host_request *)ec_dev->dout;
int ret, i;
u8 csum;
msg->command = EC_CMD_HELLO;
msg->outsize = 0x88;
msg->data[0] = 0xde;
msg->data[1] = 0xad;
msg->data[2] = 0xbe;
msg->data[3] = 0xef;
ret = cros_ec_prepare_tx(ec_dev, msg);
KUNIT_EXPECT_EQ(test, ret, sizeof(*request) + 0x88);
KUNIT_EXPECT_EQ(test, request->struct_version, EC_HOST_REQUEST_VERSION);
KUNIT_EXPECT_EQ(test, request->command, EC_CMD_HELLO);
KUNIT_EXPECT_EQ(test, request->command_version, 0);
KUNIT_EXPECT_EQ(test, request->data_len, 0x88);
KUNIT_EXPECT_EQ(test, ec_dev->dout[sizeof(*request) + 0], 0xde);
KUNIT_EXPECT_EQ(test, ec_dev->dout[sizeof(*request) + 1], 0xad);
KUNIT_EXPECT_EQ(test, ec_dev->dout[sizeof(*request) + 2], 0xbe);
KUNIT_EXPECT_EQ(test, ec_dev->dout[sizeof(*request) + 3], 0xef);
for (i = 4; i < 0x88; ++i)
KUNIT_EXPECT_EQ(test, ec_dev->dout[sizeof(*request) + i], 0);
csum = EC_HOST_REQUEST_VERSION;
csum += EC_CMD_HELLO;
csum += 0x88;
csum += 0xde;
csum += 0xad;
csum += 0xbe;
csum += 0xef;
KUNIT_EXPECT_EQ(test, request->checksum, (u8)-csum);
}
static void cros_ec_proto_test_prepare_tx_bad_msg_outsize(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct cros_ec_command *msg = priv->msg;
int ret;
msg->outsize = ec_dev->dout_size - sizeof(struct ec_host_request) + 1;
ret = cros_ec_prepare_tx(ec_dev, msg);
KUNIT_EXPECT_EQ(test, ret, -EINVAL);
}
static void cros_ec_proto_test_check_result(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct cros_ec_command *msg = priv->msg;
int ret, i;
static enum ec_status status[] = {
EC_RES_SUCCESS,
EC_RES_INVALID_COMMAND,
EC_RES_ERROR,
EC_RES_INVALID_PARAM,
EC_RES_ACCESS_DENIED,
EC_RES_INVALID_RESPONSE,
EC_RES_INVALID_VERSION,
EC_RES_INVALID_CHECKSUM,
EC_RES_UNAVAILABLE,
EC_RES_TIMEOUT,
EC_RES_OVERFLOW,
EC_RES_INVALID_HEADER,
EC_RES_REQUEST_TRUNCATED,
EC_RES_RESPONSE_TOO_BIG,
EC_RES_BUS_ERROR,
EC_RES_BUSY,
EC_RES_INVALID_HEADER_VERSION,
EC_RES_INVALID_HEADER_CRC,
EC_RES_INVALID_DATA_CRC,
EC_RES_DUP_UNAVAILABLE,
};
for (i = 0; i < ARRAY_SIZE(status); ++i) {
msg->result = status[i];
ret = cros_ec_check_result(ec_dev, msg);
KUNIT_EXPECT_EQ(test, ret, 0);
}
msg->result = EC_RES_IN_PROGRESS;
ret = cros_ec_check_result(ec_dev, msg);
KUNIT_EXPECT_EQ(test, ret, -EAGAIN);
}
static void cros_ec_proto_test_query_all_pretest(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
/*
* cros_ec_query_all() will free din and dout and allocate them again to fit the usage by
* calling devm_kfree() and devm_kzalloc(). Set them to NULL as they aren't managed by
* ec_dev->dev but allocated statically in struct cros_ec_proto_test_priv
* (see cros_ec_proto_test_init()).
*/
ec_dev->din = NULL;
ec_dev->dout = NULL;
}
static void cros_ec_proto_test_query_all_normal(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
/* For cros_ec_get_proto_info() without passthru. */
{
struct ec_response_get_protocol_info *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_get_protocol_info *)mock->o_data;
data->protocol_versions = BIT(3) | BIT(2);
data->max_request_packet_size = 0xbe;
data->max_response_packet_size = 0xef;
}
/* For cros_ec_get_proto_info() with passthru. */
{
struct ec_response_get_protocol_info *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_get_protocol_info *)mock->o_data;
data->max_request_packet_size = 0xbf;
}
/* For cros_ec_get_host_command_version_mask() for MKBP. */
{
struct ec_response_get_cmd_versions *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_get_cmd_versions *)mock->o_data;
data->version_mask = BIT(6) | BIT(5);
}
/* For cros_ec_get_host_command_version_mask() for host sleep v1. */
{
struct ec_response_get_cmd_versions *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_get_cmd_versions *)mock->o_data;
data->version_mask = BIT(1);
}
/* For cros_ec_get_host_event_wake_mask(). */
{
struct ec_response_host_event_mask *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_host_event_mask *)mock->o_data;
data->mask = 0xbeef;
}
cros_ec_proto_test_query_all_pretest(test);
ret = cros_ec_query_all(ec_dev);
KUNIT_EXPECT_EQ(test, ret, 0);
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
KUNIT_EXPECT_EQ(test, ec_dev->max_request, 0xbe - sizeof(struct ec_host_request));
KUNIT_EXPECT_EQ(test, ec_dev->max_response, 0xef - sizeof(struct ec_host_response));
KUNIT_EXPECT_EQ(test, ec_dev->proto_version, 3);
KUNIT_EXPECT_EQ(test, ec_dev->din_size, 0xef + EC_MAX_RESPONSE_OVERHEAD);
KUNIT_EXPECT_EQ(test, ec_dev->dout_size, 0xbe + EC_MAX_REQUEST_OVERHEAD);
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command,
EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) |
EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
KUNIT_EXPECT_EQ(test, ec_dev->max_passthru, 0xbf - sizeof(struct ec_host_request));
}
/* For cros_ec_get_host_command_version_mask() for MKBP. */
{
struct ec_params_get_cmd_versions *data;
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_cmd_versions));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data));
data = (struct ec_params_get_cmd_versions *)mock->i_data;
KUNIT_EXPECT_EQ(test, data->cmd, EC_CMD_GET_NEXT_EVENT);
KUNIT_EXPECT_EQ(test, ec_dev->mkbp_event_supported, 7);
}
/* For cros_ec_get_host_command_version_mask() for host sleep v1. */
{
struct ec_params_get_cmd_versions *data;
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_cmd_versions));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data));
data = (struct ec_params_get_cmd_versions *)mock->i_data;
KUNIT_EXPECT_EQ(test, data->cmd, EC_CMD_HOST_SLEEP_EVENT);
KUNIT_EXPECT_TRUE(test, ec_dev->host_sleep_v1);
}
/* For cros_ec_get_host_event_wake_mask(). */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HOST_EVENT_GET_WAKE_MASK);
KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_host_event_mask));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
KUNIT_EXPECT_EQ(test, ec_dev->host_event_wake_mask, 0xbeef);
}
}
static void cros_ec_proto_test_query_all_no_pd_return_error(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
/* Set some garbage bytes. */
ec_dev->max_passthru = 0xbf;
/* For cros_ec_get_proto_info() without passthru. */
{
struct ec_response_get_protocol_info *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
/*
* Although it doesn't check the value, provides valid sizes so that
* cros_ec_query_all() allocates din and dout correctly.
*/
data = (struct ec_response_get_protocol_info *)mock->o_data;
data->max_request_packet_size = 0xbe;
data->max_response_packet_size = 0xef;
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
cros_ec_proto_test_query_all_pretest(test);
ret = cros_ec_query_all(ec_dev);
KUNIT_EXPECT_EQ(test, ret, 0);
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command,
EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) |
EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
KUNIT_EXPECT_EQ(test, ec_dev->max_passthru, 0);
}
}
static void cros_ec_proto_test_query_all_no_pd_return0(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
/* Set some garbage bytes. */
ec_dev->max_passthru = 0xbf;
/* For cros_ec_get_proto_info() without passthru. */
{
struct ec_response_get_protocol_info *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
/*
* Although it doesn't check the value, provides valid sizes so that
* cros_ec_query_all() allocates din and dout correctly.
*/
data = (struct ec_response_get_protocol_info *)mock->o_data;
data->max_request_packet_size = 0xbe;
data->max_response_packet_size = 0xef;
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_add(test, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
cros_ec_proto_test_query_all_pretest(test);
ret = cros_ec_query_all(ec_dev);
KUNIT_EXPECT_EQ(test, ret, 0);
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command,
EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) |
EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
KUNIT_EXPECT_EQ(test, ec_dev->max_passthru, 0);
}
}
static void cros_ec_proto_test_query_all_legacy_normal_v3_return_error(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For cros_ec_get_proto_info_legacy(). */
{
struct ec_response_hello *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_hello *)mock->o_data;
data->out_data = 0xa1b2c3d4;
}
cros_ec_proto_test_query_all_pretest(test);
ret = cros_ec_query_all(ec_dev);
KUNIT_EXPECT_EQ(test, ret, 0);
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_proto_info_legacy(). */
{
struct ec_params_hello *data;
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HELLO);
KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_hello));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data));
data = (struct ec_params_hello *)mock->i_data;
KUNIT_EXPECT_EQ(test, data->in_data, 0xa0b0c0d0);
KUNIT_EXPECT_EQ(test, ec_dev->proto_version, 2);
KUNIT_EXPECT_EQ(test, ec_dev->max_request, EC_PROTO2_MAX_PARAM_SIZE);
KUNIT_EXPECT_EQ(test, ec_dev->max_response, EC_PROTO2_MAX_PARAM_SIZE);
KUNIT_EXPECT_EQ(test, ec_dev->max_passthru, 0);
KUNIT_EXPECT_PTR_EQ(test, ec_dev->pkt_xfer, NULL);
KUNIT_EXPECT_EQ(test, ec_dev->din_size, EC_PROTO2_MSG_BYTES);
KUNIT_EXPECT_EQ(test, ec_dev->dout_size, EC_PROTO2_MSG_BYTES);
}
}
static void cros_ec_proto_test_query_all_legacy_normal_v3_return0(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_add(test, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For cros_ec_get_proto_info_legacy(). */
{
struct ec_response_hello *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_hello *)mock->o_data;
data->out_data = 0xa1b2c3d4;
}
cros_ec_proto_test_query_all_pretest(test);
ret = cros_ec_query_all(ec_dev);
KUNIT_EXPECT_EQ(test, ret, 0);
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_proto_info_legacy(). */
{
struct ec_params_hello *data;
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HELLO);
KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_hello));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data));
data = (struct ec_params_hello *)mock->i_data;
KUNIT_EXPECT_EQ(test, data->in_data, 0xa0b0c0d0);
KUNIT_EXPECT_EQ(test, ec_dev->proto_version, 2);
KUNIT_EXPECT_EQ(test, ec_dev->max_request, EC_PROTO2_MAX_PARAM_SIZE);
KUNIT_EXPECT_EQ(test, ec_dev->max_response, EC_PROTO2_MAX_PARAM_SIZE);
KUNIT_EXPECT_EQ(test, ec_dev->max_passthru, 0);
KUNIT_EXPECT_PTR_EQ(test, ec_dev->pkt_xfer, NULL);
KUNIT_EXPECT_EQ(test, ec_dev->din_size, EC_PROTO2_MSG_BYTES);
KUNIT_EXPECT_EQ(test, ec_dev->dout_size, EC_PROTO2_MSG_BYTES);
}
}
static void cros_ec_proto_test_query_all_legacy_xfer_error(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For cros_ec_get_proto_info_legacy(). */
{
mock = cros_kunit_ec_xfer_mock_addx(test, -EIO, EC_RES_SUCCESS, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
cros_ec_proto_test_query_all_pretest(test);
ret = cros_ec_query_all(ec_dev);
KUNIT_EXPECT_EQ(test, ret, -EIO);
KUNIT_EXPECT_EQ(test, ec_dev->proto_version, EC_PROTO_VERSION_UNKNOWN);
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_proto_info_legacy(). */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HELLO);
KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_hello));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_hello));
}
}
static void cros_ec_proto_test_query_all_legacy_return_error(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For cros_ec_get_proto_info_legacy(). */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
cros_ec_proto_test_query_all_pretest(test);
ret = cros_ec_query_all(ec_dev);
KUNIT_EXPECT_EQ(test, ret, -EOPNOTSUPP);
KUNIT_EXPECT_EQ(test, ec_dev->proto_version, EC_PROTO_VERSION_UNKNOWN);
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_proto_info_legacy(). */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HELLO);
KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_hello));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_hello));
}
}
static void cros_ec_proto_test_query_all_legacy_data_error(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For cros_ec_get_proto_info_legacy(). */
{
struct ec_response_hello *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_hello *)mock->o_data;
data->out_data = 0xbeefbfbf;
}
cros_ec_proto_test_query_all_pretest(test);
ret = cros_ec_query_all(ec_dev);
KUNIT_EXPECT_EQ(test, ret, -EBADMSG);
KUNIT_EXPECT_EQ(test, ec_dev->proto_version, EC_PROTO_VERSION_UNKNOWN);
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_proto_info_legacy(). */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HELLO);
KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_hello));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_hello));
}
}
static void cros_ec_proto_test_query_all_legacy_return0(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For cros_ec_get_proto_info_legacy(). */
{
mock = cros_kunit_ec_xfer_mock_add(test, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
cros_ec_proto_test_query_all_pretest(test);
ret = cros_ec_query_all(ec_dev);
KUNIT_EXPECT_EQ(test, ret, -EPROTO);
KUNIT_EXPECT_EQ(test, ec_dev->proto_version, EC_PROTO_VERSION_UNKNOWN);
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_proto_info_legacy(). */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HELLO);
KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_hello));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_hello));
}
}
static void cros_ec_proto_test_query_all_no_mkbp(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
/* Set some garbage bytes. */
ec_dev->mkbp_event_supported = 0xbf;
/* For cros_ec_get_proto_info() without passthru. */
{
struct ec_response_get_protocol_info *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
/*
* Although it doesn't check the value, provides valid sizes so that
* cros_ec_query_all() allocates din and dout correctly.
*/
data = (struct ec_response_get_protocol_info *)mock->o_data;
data->max_request_packet_size = 0xbe;
data->max_response_packet_size = 0xef;
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For cros_ec_get_host_command_version_mask() for MKBP. */
{
struct ec_response_get_cmd_versions *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_get_cmd_versions *)mock->o_data;
data->version_mask = 0;
}
cros_ec_proto_test_query_all_pretest(test);
ret = cros_ec_query_all(ec_dev);
KUNIT_EXPECT_EQ(test, ret, 0);
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command,
EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) |
EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_host_command_version_mask() for MKBP. */
{
struct ec_params_get_cmd_versions *data;
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_cmd_versions));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data));
data = (struct ec_params_get_cmd_versions *)mock->i_data;
KUNIT_EXPECT_EQ(test, data->cmd, EC_CMD_GET_NEXT_EVENT);
KUNIT_EXPECT_EQ(test, ec_dev->mkbp_event_supported, 0);
}
}
static void cros_ec_proto_test_query_all_no_mkbp_return_error(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
/* Set some garbage bytes. */
ec_dev->mkbp_event_supported = 0xbf;
/* For cros_ec_get_proto_info() without passthru. */
{
struct ec_response_get_protocol_info *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
/*
* Although it doesn't check the value, provides valid sizes so that
* cros_ec_query_all() allocates din and dout correctly.
*/
data = (struct ec_response_get_protocol_info *)mock->o_data;
data->max_request_packet_size = 0xbe;
data->max_response_packet_size = 0xef;
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For cros_ec_get_host_command_version_mask() for MKBP. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
cros_ec_proto_test_query_all_pretest(test);
ret = cros_ec_query_all(ec_dev);
KUNIT_EXPECT_EQ(test, ret, 0);
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command,
EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) |
EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_host_command_version_mask() for MKBP. */
{
struct ec_params_get_cmd_versions *data;
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_cmd_versions));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data));
data = (struct ec_params_get_cmd_versions *)mock->i_data;
KUNIT_EXPECT_EQ(test, data->cmd, EC_CMD_GET_NEXT_EVENT);
KUNIT_EXPECT_EQ(test, ec_dev->mkbp_event_supported, 0);
}
}
static void cros_ec_proto_test_query_all_no_mkbp_return0(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
/* Set some garbage bytes. */
ec_dev->mkbp_event_supported = 0xbf;
/* For cros_ec_get_proto_info() without passthru. */
{
struct ec_response_get_protocol_info *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
/*
* Although it doesn't check the value, provides valid sizes so that
* cros_ec_query_all() allocates din and dout correctly.
*/
data = (struct ec_response_get_protocol_info *)mock->o_data;
data->max_request_packet_size = 0xbe;
data->max_response_packet_size = 0xef;
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For cros_ec_get_host_command_version_mask() for MKBP. */
{
mock = cros_kunit_ec_xfer_mock_add(test, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
cros_ec_proto_test_query_all_pretest(test);
ret = cros_ec_query_all(ec_dev);
KUNIT_EXPECT_EQ(test, ret, 0);
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command,
EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) |
EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_host_command_version_mask() for MKBP. */
{
struct ec_params_get_cmd_versions *data;
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_cmd_versions));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data));
data = (struct ec_params_get_cmd_versions *)mock->i_data;
KUNIT_EXPECT_EQ(test, data->cmd, EC_CMD_GET_NEXT_EVENT);
KUNIT_EXPECT_EQ(test, ec_dev->mkbp_event_supported, 0);
}
}
static void cros_ec_proto_test_query_all_no_host_sleep(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
/* Set some garbage bytes. */
ec_dev->host_sleep_v1 = true;
/* For cros_ec_get_proto_info() without passthru. */
{
struct ec_response_get_protocol_info *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
/*
* Although it doesn't check the value, provides valid sizes so that
* cros_ec_query_all() allocates din and dout correctly.
*/
data = (struct ec_response_get_protocol_info *)mock->o_data;
data->max_request_packet_size = 0xbe;
data->max_response_packet_size = 0xef;
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For cros_ec_get_host_command_version_mask() for MKBP. */
{
mock = cros_kunit_ec_xfer_mock_add(test, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For cros_ec_get_host_command_version_mask() for host sleep v1. */
{
struct ec_response_get_cmd_versions *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_get_cmd_versions *)mock->o_data;
data->version_mask = 0;
}
cros_ec_proto_test_query_all_pretest(test);
ret = cros_ec_query_all(ec_dev);
KUNIT_EXPECT_EQ(test, ret, 0);
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command,
EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) |
EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_host_command_version_mask() for MKBP. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_cmd_versions));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_get_cmd_versions));
}
/* For cros_ec_get_host_command_version_mask() for host sleep v1. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_cmd_versions));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_get_cmd_versions));
KUNIT_EXPECT_FALSE(test, ec_dev->host_sleep_v1);
}
}
static void cros_ec_proto_test_query_all_no_host_sleep_return0(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
/* Set some garbage bytes. */
ec_dev->host_sleep_v1 = true;
/* For cros_ec_get_proto_info() without passthru. */
{
struct ec_response_get_protocol_info *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
/*
* Although it doesn't check the value, provides valid sizes so that
* cros_ec_query_all() allocates din and dout correctly.
*/
data = (struct ec_response_get_protocol_info *)mock->o_data;
data->max_request_packet_size = 0xbe;
data->max_response_packet_size = 0xef;
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For cros_ec_get_host_command_version_mask() for MKBP. */
{
struct ec_response_get_cmd_versions *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
/* In order to pollute next cros_ec_get_host_command_version_mask(). */
data = (struct ec_response_get_cmd_versions *)mock->o_data;
data->version_mask = 0xbeef;
}
/* For cros_ec_get_host_command_version_mask() for host sleep v1. */
{
mock = cros_kunit_ec_xfer_mock_add(test, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
cros_ec_proto_test_query_all_pretest(test);
ret = cros_ec_query_all(ec_dev);
KUNIT_EXPECT_EQ(test, ret, 0);
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command,
EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) |
EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_host_command_version_mask() for MKBP. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_cmd_versions));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_get_cmd_versions));
}
/* For cros_ec_get_host_command_version_mask() for host sleep v1. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_cmd_versions));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_get_cmd_versions));
KUNIT_EXPECT_FALSE(test, ec_dev->host_sleep_v1);
}
}
static void cros_ec_proto_test_query_all_default_wake_mask_return_error(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
/* Set some garbage bytes. */
ec_dev->host_event_wake_mask = U32_MAX;
/* For cros_ec_get_proto_info() without passthru. */
{
struct ec_response_get_protocol_info *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
/*
* Although it doesn't check the value, provides valid sizes so that
* cros_ec_query_all() allocates din and dout correctly.
*/
data = (struct ec_response_get_protocol_info *)mock->o_data;
data->max_request_packet_size = 0xbe;
data->max_response_packet_size = 0xef;
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For cros_ec_get_host_command_version_mask() for MKBP. */
{
mock = cros_kunit_ec_xfer_mock_add(test, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For cros_ec_get_host_command_version_mask() for host sleep v1. */
{
mock = cros_kunit_ec_xfer_mock_add(test, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For cros_ec_get_host_event_wake_mask(). */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
cros_ec_proto_test_query_all_pretest(test);
ret = cros_ec_query_all(ec_dev);
KUNIT_EXPECT_EQ(test, ret, 0);
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command,
EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) |
EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_host_command_version_mask() for MKBP. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_cmd_versions));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_get_cmd_versions));
}
/* For cros_ec_get_host_command_version_mask() for host sleep v1. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_cmd_versions));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_get_cmd_versions));
}
/* For cros_ec_get_host_event_wake_mask(). */
{
u32 mask;
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HOST_EVENT_GET_WAKE_MASK);
KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_host_event_mask));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
mask = ec_dev->host_event_wake_mask;
KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_CLOSED), 0);
KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_AC_DISCONNECTED), 0);
KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_LOW), 0);
KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_CRITICAL), 0);
KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY), 0);
KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_PD_MCU), 0);
KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_STATUS), 0);
}
}
static void cros_ec_proto_test_query_all_default_wake_mask_return0(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
/* Set some garbage bytes. */
ec_dev->host_event_wake_mask = U32_MAX;
/* For cros_ec_get_proto_info() without passthru. */
{
struct ec_response_get_protocol_info *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
/*
* Although it doesn't check the value, provides valid sizes so that
* cros_ec_query_all() allocates din and dout correctly.
*/
data = (struct ec_response_get_protocol_info *)mock->o_data;
data->max_request_packet_size = 0xbe;
data->max_response_packet_size = 0xef;
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For cros_ec_get_host_command_version_mask() for MKBP. */
{
mock = cros_kunit_ec_xfer_mock_add(test, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For cros_ec_get_host_command_version_mask() for host sleep v1. */
{
mock = cros_kunit_ec_xfer_mock_add(test, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For get_host_event_wake_mask(). */
{
mock = cros_kunit_ec_xfer_mock_add(test, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
cros_ec_proto_test_query_all_pretest(test);
ret = cros_ec_query_all(ec_dev);
KUNIT_EXPECT_EQ(test, ret, 0);
/* For cros_ec_get_proto_info() without passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_proto_info() with passthru. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command,
EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) |
EC_CMD_GET_PROTOCOL_INFO);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_protocol_info));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
/* For cros_ec_get_host_command_version_mask() for MKBP. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_cmd_versions));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_get_cmd_versions));
}
/* For cros_ec_get_host_command_version_mask() for host sleep v1. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_cmd_versions));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_get_cmd_versions));
}
/* For get_host_event_wake_mask(). */
{
u32 mask;
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HOST_EVENT_GET_WAKE_MASK);
KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_host_event_mask));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
mask = ec_dev->host_event_wake_mask;
KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_CLOSED), 0);
KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_AC_DISCONNECTED), 0);
KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_LOW), 0);
KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_CRITICAL), 0);
KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY), 0);
KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_PD_MCU), 0);
KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_STATUS), 0);
}
}
static void cros_ec_proto_test_cmd_xfer_normal(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
struct {
struct cros_ec_command msg;
u8 data[0x100];
} __packed buf;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
ec_dev->max_passthru = 0xdd;
buf.msg.version = 0;
buf.msg.command = EC_CMD_HELLO;
buf.msg.insize = 4;
buf.msg.outsize = 2;
buf.data[0] = 0x55;
buf.data[1] = 0xaa;
{
u8 *data;
mock = cros_kunit_ec_xfer_mock_add(test, 4);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (u8 *)mock->o_data;
data[0] = 0xaa;
data[1] = 0x55;
data[2] = 0xcc;
data[3] = 0x33;
}
ret = cros_ec_cmd_xfer(ec_dev, &buf.msg);
KUNIT_EXPECT_EQ(test, ret, 4);
{
u8 *data;
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HELLO);
KUNIT_EXPECT_EQ(test, mock->msg.insize, 4);
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 2);
data = (u8 *)mock->i_data;
KUNIT_EXPECT_EQ(test, data[0], 0x55);
KUNIT_EXPECT_EQ(test, data[1], 0xaa);
KUNIT_EXPECT_EQ(test, buf.data[0], 0xaa);
KUNIT_EXPECT_EQ(test, buf.data[1], 0x55);
KUNIT_EXPECT_EQ(test, buf.data[2], 0xcc);
KUNIT_EXPECT_EQ(test, buf.data[3], 0x33);
}
}
static void cros_ec_proto_test_cmd_xfer_excess_msg_insize(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
struct {
struct cros_ec_command msg;
u8 data[0x100];
} __packed buf;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
ec_dev->max_passthru = 0xdd;
buf.msg.version = 0;
buf.msg.command = EC_CMD_HELLO;
buf.msg.insize = 0xee + 1;
buf.msg.outsize = 2;
{
mock = cros_kunit_ec_xfer_mock_add(test, 0xcc);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
ret = cros_ec_cmd_xfer(ec_dev, &buf.msg);
KUNIT_EXPECT_EQ(test, ret, 0xcc);
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HELLO);
KUNIT_EXPECT_EQ(test, mock->msg.insize, 0xee);
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 2);
}
}
static void cros_ec_proto_test_cmd_xfer_excess_msg_outsize_without_passthru(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
int ret;
struct {
struct cros_ec_command msg;
u8 data[0x100];
} __packed buf;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
ec_dev->max_passthru = 0xdd;
buf.msg.version = 0;
buf.msg.command = EC_CMD_HELLO;
buf.msg.insize = 4;
buf.msg.outsize = 0xff + 1;
ret = cros_ec_cmd_xfer(ec_dev, &buf.msg);
KUNIT_EXPECT_EQ(test, ret, -EMSGSIZE);
}
static void cros_ec_proto_test_cmd_xfer_excess_msg_outsize_with_passthru(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
int ret;
struct {
struct cros_ec_command msg;
u8 data[0x100];
} __packed buf;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
ec_dev->max_passthru = 0xdd;
buf.msg.version = 0;
buf.msg.command = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) + EC_CMD_HELLO;
buf.msg.insize = 4;
buf.msg.outsize = 0xdd + 1;
ret = cros_ec_cmd_xfer(ec_dev, &buf.msg);
KUNIT_EXPECT_EQ(test, ret, -EMSGSIZE);
}
static void cros_ec_proto_test_cmd_xfer_protocol_v3_normal(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
int ret;
struct cros_ec_command msg;
memset(&msg, 0, sizeof(msg));
ec_dev->proto_version = 3;
ec_dev->cmd_xfer = cros_kunit_ec_cmd_xfer_mock;
ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock;
ret = cros_ec_cmd_xfer(ec_dev, &msg);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_EQ(test, cros_kunit_ec_cmd_xfer_mock_called, 0);
KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 1);
}
static void cros_ec_proto_test_cmd_xfer_protocol_v3_no_op(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
int ret;
struct cros_ec_command msg;
memset(&msg, 0, sizeof(msg));
ec_dev->proto_version = 3;
ec_dev->cmd_xfer = cros_kunit_ec_cmd_xfer_mock;
ec_dev->pkt_xfer = NULL;
ret = cros_ec_cmd_xfer(ec_dev, &msg);
KUNIT_EXPECT_EQ(test, ret, -EIO);
}
static void cros_ec_proto_test_cmd_xfer_protocol_v2_normal(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
int ret;
struct cros_ec_command msg;
memset(&msg, 0, sizeof(msg));
ec_dev->proto_version = 2;
ec_dev->cmd_xfer = cros_kunit_ec_cmd_xfer_mock;
ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock;
ret = cros_ec_cmd_xfer(ec_dev, &msg);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_EQ(test, cros_kunit_ec_cmd_xfer_mock_called, 1);
KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 0);
}
static void cros_ec_proto_test_cmd_xfer_protocol_v2_no_op(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
int ret;
struct cros_ec_command msg;
memset(&msg, 0, sizeof(msg));
ec_dev->proto_version = 2;
ec_dev->cmd_xfer = NULL;
ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock;
ret = cros_ec_cmd_xfer(ec_dev, &msg);
KUNIT_EXPECT_EQ(test, ret, -EIO);
}
static void cros_ec_proto_test_cmd_xfer_in_progress_normal(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
struct cros_ec_command msg;
memset(&msg, 0, sizeof(msg));
ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock;
/* For the first host command to return EC_RES_IN_PROGRESS. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_IN_PROGRESS, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For EC_CMD_GET_COMMS_STATUS. */
{
struct ec_response_get_comms_status *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_get_comms_status *)mock->o_data;
data->flags = 0;
}
ret = cros_ec_cmd_xfer(ec_dev, &msg);
KUNIT_EXPECT_EQ(test, ret, sizeof(struct ec_response_get_comms_status));
KUNIT_EXPECT_EQ(test, msg.result, EC_RES_SUCCESS);
/* For the first host command to return EC_RES_IN_PROGRESS. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
}
/* For EC_CMD_GET_COMMS_STATUS. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_COMMS_STATUS);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_comms_status));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 2);
}
static void cros_ec_proto_test_cmd_xfer_in_progress_retries_eagain(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
struct cros_ec_command msg;
memset(&msg, 0, sizeof(msg));
ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock;
/* For the first host command to return EC_RES_IN_PROGRESS. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_IN_PROGRESS, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For EC_CMD_GET_COMMS_STATUS EC_COMMAND_RETRIES times. */
cros_kunit_ec_xfer_mock_default_ret = -EAGAIN;
ret = cros_ec_cmd_xfer(ec_dev, &msg);
KUNIT_EXPECT_EQ(test, ret, -EAGAIN);
/* For EC_CMD_GET_COMMS_STATUS EC_COMMAND_RETRIES times. */
KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 51);
}
static void cros_ec_proto_test_cmd_xfer_in_progress_retries_status_processing(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
struct cros_ec_command msg;
memset(&msg, 0, sizeof(msg));
ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock;
/* For the first host command to return EC_RES_IN_PROGRESS. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_IN_PROGRESS, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For EC_CMD_GET_COMMS_STATUS EC_COMMAND_RETRIES times. */
{
struct ec_response_get_comms_status *data;
int i;
for (i = 0; i < 50; ++i) {
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_get_comms_status *)mock->o_data;
data->flags |= EC_COMMS_STATUS_PROCESSING;
}
}
ret = cros_ec_cmd_xfer(ec_dev, &msg);
KUNIT_EXPECT_EQ(test, ret, -EAGAIN);
/* For EC_CMD_GET_COMMS_STATUS EC_COMMAND_RETRIES times. */
KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 51);
}
static void cros_ec_proto_test_cmd_xfer_in_progress_xfer_error(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
struct cros_ec_command msg;
memset(&msg, 0, sizeof(msg));
/* For the first host command to return EC_RES_IN_PROGRESS. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_IN_PROGRESS, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For EC_CMD_GET_COMMS_STATUS. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, -EIO, EC_RES_SUCCESS, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
ret = cros_ec_cmd_xfer(ec_dev, &msg);
KUNIT_EXPECT_EQ(test, ret, -EIO);
}
static void cros_ec_proto_test_cmd_xfer_in_progress_return_error(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
struct cros_ec_command msg;
memset(&msg, 0, sizeof(msg));
ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock;
/* For the first host command to return EC_RES_IN_PROGRESS. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_IN_PROGRESS, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For EC_CMD_GET_COMMS_STATUS. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
ret = cros_ec_cmd_xfer(ec_dev, &msg);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_EQ(test, msg.result, EC_RES_INVALID_COMMAND);
KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 2);
}
static void cros_ec_proto_test_cmd_xfer_in_progress_return0(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
struct cros_ec_command msg;
memset(&msg, 0, sizeof(msg));
ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock;
/* For the first host command to return EC_RES_IN_PROGRESS. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_IN_PROGRESS, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For EC_CMD_GET_COMMS_STATUS. */
{
mock = cros_kunit_ec_xfer_mock_add(test, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
ret = cros_ec_cmd_xfer(ec_dev, &msg);
KUNIT_EXPECT_EQ(test, ret, -EPROTO);
KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 2);
}
static void cros_ec_proto_test_cmd_xfer_status_normal(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
struct cros_ec_command msg;
memset(&msg, 0, sizeof(msg));
/* For cros_ec_cmd_xfer(). */
{
mock = cros_kunit_ec_xfer_mock_add(test, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
ret = cros_ec_cmd_xfer_status(ec_dev, &msg);
KUNIT_EXPECT_EQ(test, ret, 0);
}
static void cros_ec_proto_test_cmd_xfer_status_xfer_error(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
struct cros_ec_command msg;
memset(&msg, 0, sizeof(msg));
/* For cros_ec_cmd_xfer(). */
{
mock = cros_kunit_ec_xfer_mock_addx(test, -EPROTO, EC_RES_SUCCESS, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
ret = cros_ec_cmd_xfer_status(ec_dev, &msg);
KUNIT_EXPECT_EQ(test, ret, -EPROTO);
}
static void cros_ec_proto_test_cmd_xfer_status_return_error(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret, i;
struct cros_ec_command msg;
static const int map[] = {
[EC_RES_SUCCESS] = 0,
[EC_RES_INVALID_COMMAND] = -EOPNOTSUPP,
[EC_RES_ERROR] = -EIO,
[EC_RES_INVALID_PARAM] = -EINVAL,
[EC_RES_ACCESS_DENIED] = -EACCES,
[EC_RES_INVALID_RESPONSE] = -EPROTO,
[EC_RES_INVALID_VERSION] = -ENOPROTOOPT,
[EC_RES_INVALID_CHECKSUM] = -EBADMSG,
/*
* EC_RES_IN_PROGRESS is special because cros_ec_send_command() has extra logic to
* handle it. Note that default cros_kunit_ec_xfer_mock_default_ret == 0 thus
* cros_ec_xfer_command() in cros_ec_wait_until_complete() returns 0. As a result,
* it returns -EPROTO without calling cros_ec_map_error().
*/
[EC_RES_IN_PROGRESS] = -EPROTO,
[EC_RES_UNAVAILABLE] = -ENODATA,
[EC_RES_TIMEOUT] = -ETIMEDOUT,
[EC_RES_OVERFLOW] = -EOVERFLOW,
[EC_RES_INVALID_HEADER] = -EBADR,
[EC_RES_REQUEST_TRUNCATED] = -EBADR,
[EC_RES_RESPONSE_TOO_BIG] = -EFBIG,
[EC_RES_BUS_ERROR] = -EFAULT,
[EC_RES_BUSY] = -EBUSY,
[EC_RES_INVALID_HEADER_VERSION] = -EBADMSG,
[EC_RES_INVALID_HEADER_CRC] = -EBADMSG,
[EC_RES_INVALID_DATA_CRC] = -EBADMSG,
[EC_RES_DUP_UNAVAILABLE] = -ENODATA,
};
memset(&msg, 0, sizeof(msg));
for (i = 0; i < ARRAY_SIZE(map); ++i) {
mock = cros_kunit_ec_xfer_mock_addx(test, 0, i, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
ret = cros_ec_cmd_xfer_status(ec_dev, &msg);
KUNIT_EXPECT_EQ(test, ret, map[i]);
}
}
static void cros_ec_proto_test_get_next_event_no_mkbp_event(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
bool wake_event, more_events;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
ec_dev->mkbp_event_supported = 0;
/* Set some garbage bytes. */
wake_event = false;
more_events = true;
/* For get_keyboard_state_event(). */
{
union ec_response_get_next_data_v1 *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (union ec_response_get_next_data_v1 *)mock->o_data;
data->host_event = 0xbeef;
}
ret = cros_ec_get_next_event(ec_dev, &wake_event, &more_events);
KUNIT_EXPECT_EQ(test, ret, sizeof(union ec_response_get_next_data_v1));
KUNIT_EXPECT_EQ(test, ec_dev->event_data.event_type, EC_MKBP_EVENT_KEY_MATRIX);
KUNIT_EXPECT_EQ(test, ec_dev->event_data.data.host_event, 0xbeef);
KUNIT_EXPECT_TRUE(test, wake_event);
KUNIT_EXPECT_FALSE(test, more_events);
/* For get_keyboard_state_event(). */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_MKBP_STATE);
KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(union ec_response_get_next_data_v1));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
}
static void cros_ec_proto_test_get_next_event_mkbp_event_ec_suspended(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
int ret;
ec_dev->mkbp_event_supported = 1;
ec_dev->suspended = true;
ret = cros_ec_get_next_event(ec_dev, NULL, NULL);
KUNIT_EXPECT_EQ(test, ret, -EHOSTDOWN);
}
static void cros_ec_proto_test_get_next_event_mkbp_event_version0(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
bool wake_event, more_events;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
ec_dev->mkbp_event_supported = 1;
/* Set some garbage bytes. */
wake_event = true;
more_events = false;
/* For get_next_event_xfer(). */
{
struct ec_response_get_next_event *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_get_next_event *)mock->o_data;
data->event_type = EC_MKBP_EVENT_SENSOR_FIFO | EC_MKBP_HAS_MORE_EVENTS;
data->data.sysrq = 0xbeef;
}
ret = cros_ec_get_next_event(ec_dev, &wake_event, &more_events);
KUNIT_EXPECT_EQ(test, ret, sizeof(struct ec_response_get_next_event));
KUNIT_EXPECT_EQ(test, ec_dev->event_data.event_type, EC_MKBP_EVENT_SENSOR_FIFO);
KUNIT_EXPECT_EQ(test, ec_dev->event_data.data.sysrq, 0xbeef);
KUNIT_EXPECT_FALSE(test, wake_event);
KUNIT_EXPECT_TRUE(test, more_events);
/* For get_next_event_xfer(). */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_NEXT_EVENT);
KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_get_next_event));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
}
static void cros_ec_proto_test_get_next_event_mkbp_event_version2(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
bool wake_event, more_events;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
ec_dev->mkbp_event_supported = 3;
/* Set some garbage bytes. */
wake_event = false;
more_events = true;
/* For get_next_event_xfer(). */
{
struct ec_response_get_next_event_v1 *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_get_next_event_v1 *)mock->o_data;
data->event_type = EC_MKBP_EVENT_FINGERPRINT;
data->data.sysrq = 0xbeef;
}
ret = cros_ec_get_next_event(ec_dev, &wake_event, &more_events);
KUNIT_EXPECT_EQ(test, ret, sizeof(struct ec_response_get_next_event_v1));
KUNIT_EXPECT_EQ(test, ec_dev->event_data.event_type, EC_MKBP_EVENT_FINGERPRINT);
KUNIT_EXPECT_EQ(test, ec_dev->event_data.data.sysrq, 0xbeef);
KUNIT_EXPECT_TRUE(test, wake_event);
KUNIT_EXPECT_FALSE(test, more_events);
/* For get_next_event_xfer(). */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 2);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_NEXT_EVENT);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_next_event_v1));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
}
static void cros_ec_proto_test_get_next_event_mkbp_event_host_event_rtc(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
bool wake_event;
struct ec_response_get_next_event_v1 *data;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
ec_dev->mkbp_event_supported = 3;
ec_dev->host_event_wake_mask = U32_MAX;
/* Set some garbage bytes. */
wake_event = true;
/* For get_next_event_xfer(). */
{
mock = cros_kunit_ec_xfer_mock_add(test,
sizeof(data->event_type) +
sizeof(data->data.host_event));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_get_next_event_v1 *)mock->o_data;
data->event_type = EC_MKBP_EVENT_HOST_EVENT;
put_unaligned_le32(EC_HOST_EVENT_MASK(EC_HOST_EVENT_RTC), &data->data.host_event);
}
ret = cros_ec_get_next_event(ec_dev, &wake_event, NULL);
KUNIT_EXPECT_EQ(test, ret, sizeof(data->event_type) + sizeof(data->data.host_event));
KUNIT_EXPECT_EQ(test, ec_dev->event_data.event_type, EC_MKBP_EVENT_HOST_EVENT);
KUNIT_EXPECT_FALSE(test, wake_event);
/* For get_next_event_xfer(). */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 2);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_NEXT_EVENT);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_next_event_v1));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
}
static void cros_ec_proto_test_get_next_event_mkbp_event_host_event_masked(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
bool wake_event;
struct ec_response_get_next_event_v1 *data;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
ec_dev->mkbp_event_supported = 3;
ec_dev->host_event_wake_mask = U32_MAX & ~EC_HOST_EVENT_MASK(EC_HOST_EVENT_AC_DISCONNECTED);
/* Set some garbage bytes. */
wake_event = true;
/* For get_next_event_xfer(). */
{
mock = cros_kunit_ec_xfer_mock_add(test,
sizeof(data->event_type) +
sizeof(data->data.host_event));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_get_next_event_v1 *)mock->o_data;
data->event_type = EC_MKBP_EVENT_HOST_EVENT;
put_unaligned_le32(EC_HOST_EVENT_MASK(EC_HOST_EVENT_AC_DISCONNECTED),
&data->data.host_event);
}
ret = cros_ec_get_next_event(ec_dev, &wake_event, NULL);
KUNIT_EXPECT_EQ(test, ret, sizeof(data->event_type) + sizeof(data->data.host_event));
KUNIT_EXPECT_EQ(test, ec_dev->event_data.event_type, EC_MKBP_EVENT_HOST_EVENT);
KUNIT_EXPECT_FALSE(test, wake_event);
/* For get_next_event_xfer(). */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 2);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_NEXT_EVENT);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_get_next_event_v1));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
}
static void cros_ec_proto_test_get_host_event_no_mkbp_event(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
int ret;
ec_dev->mkbp_event_supported = 0;
ret = cros_ec_get_host_event(ec_dev);
KUNIT_EXPECT_EQ(test, ret, 0);
}
static void cros_ec_proto_test_get_host_event_not_host_event(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
int ret;
ec_dev->mkbp_event_supported = 1;
ec_dev->event_data.event_type = EC_MKBP_EVENT_FINGERPRINT;
ret = cros_ec_get_host_event(ec_dev);
KUNIT_EXPECT_EQ(test, ret, 0);
}
static void cros_ec_proto_test_get_host_event_wrong_event_size(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
int ret;
ec_dev->mkbp_event_supported = 1;
ec_dev->event_data.event_type = EC_MKBP_EVENT_HOST_EVENT;
ec_dev->event_size = 0xff;
ret = cros_ec_get_host_event(ec_dev);
KUNIT_EXPECT_EQ(test, ret, 0);
}
static void cros_ec_proto_test_get_host_event_normal(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
int ret;
ec_dev->mkbp_event_supported = 1;
ec_dev->event_data.event_type = EC_MKBP_EVENT_HOST_EVENT;
ec_dev->event_size = sizeof(ec_dev->event_data.data.host_event);
put_unaligned_le32(EC_HOST_EVENT_MASK(EC_HOST_EVENT_RTC),
&ec_dev->event_data.data.host_event);
ret = cros_ec_get_host_event(ec_dev);
KUNIT_EXPECT_EQ(test, ret, EC_HOST_EVENT_MASK(EC_HOST_EVENT_RTC));
}
static void cros_ec_proto_test_check_features_cached(struct kunit *test)
{
int ret, i;
struct cros_ec_dev ec;
ec.features.flags[0] = EC_FEATURE_MASK_0(EC_FEATURE_FINGERPRINT);
ec.features.flags[1] = EC_FEATURE_MASK_0(EC_FEATURE_SCP);
for (i = 0; i < EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK; ++i) {
ret = cros_ec_check_features(&ec, i);
switch (i) {
case EC_FEATURE_FINGERPRINT:
case EC_FEATURE_SCP:
KUNIT_EXPECT_TRUE(test, ret);
break;
default:
KUNIT_EXPECT_FALSE(test, ret);
break;
}
}
}
static void cros_ec_proto_test_check_features_not_cached(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret, i;
struct cros_ec_dev ec;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
ec.ec_dev = ec_dev;
ec.dev = ec_dev->dev;
ec.cmd_offset = 0;
ec.features.flags[0] = -1;
ec.features.flags[1] = -1;
/* For EC_CMD_GET_FEATURES. */
{
struct ec_response_get_features *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_get_features *)mock->o_data;
data->flags[0] = EC_FEATURE_MASK_0(EC_FEATURE_FINGERPRINT);
data->flags[1] = EC_FEATURE_MASK_0(EC_FEATURE_SCP);
}
for (i = 0; i < EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK; ++i) {
ret = cros_ec_check_features(&ec, i);
switch (i) {
case EC_FEATURE_FINGERPRINT:
case EC_FEATURE_SCP:
KUNIT_EXPECT_TRUE(test, ret);
break;
default:
KUNIT_EXPECT_FALSE(test, ret);
break;
}
}
/* For EC_CMD_GET_FEATURES. */
{
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_FEATURES);
KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_get_features));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0);
}
}
static void cros_ec_proto_test_get_sensor_count_normal(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
struct cros_ec_dev ec;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
ec.ec_dev = ec_dev;
ec.dev = ec_dev->dev;
ec.cmd_offset = 0;
/* For EC_CMD_MOTION_SENSE_CMD. */
{
struct ec_response_motion_sense *data;
mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data));
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (struct ec_response_motion_sense *)mock->o_data;
data->dump.sensor_count = 0xbf;
}
ret = cros_ec_get_sensor_count(&ec);
KUNIT_EXPECT_EQ(test, ret, 0xbf);
/* For EC_CMD_MOTION_SENSE_CMD. */
{
struct ec_params_motion_sense *data;
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 1);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_MOTION_SENSE_CMD);
KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_motion_sense));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data));
data = (struct ec_params_motion_sense *)mock->i_data;
KUNIT_EXPECT_EQ(test, data->cmd, MOTIONSENSE_CMD_DUMP);
}
}
static void cros_ec_proto_test_get_sensor_count_xfer_error(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
struct cros_ec_dev ec;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
ec.ec_dev = ec_dev;
ec.dev = ec_dev->dev;
ec.cmd_offset = 0;
/* For EC_CMD_MOTION_SENSE_CMD. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, -EPROTO, EC_RES_SUCCESS, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
ret = cros_ec_get_sensor_count(&ec);
KUNIT_EXPECT_EQ(test, ret, -EPROTO);
/* For EC_CMD_MOTION_SENSE_CMD. */
{
struct ec_params_motion_sense *data;
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 1);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_MOTION_SENSE_CMD);
KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_motion_sense));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data));
data = (struct ec_params_motion_sense *)mock->i_data;
KUNIT_EXPECT_EQ(test, data->cmd, MOTIONSENSE_CMD_DUMP);
}
}
static void cros_ec_proto_test_get_sensor_count_legacy(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret, i;
struct cros_ec_dev ec;
struct {
u8 readmem_data;
int expected_result;
} test_data[] = {
{ 0, 0 },
{ EC_MEMMAP_ACC_STATUS_PRESENCE_BIT, 2 },
};
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
ec_dev->cmd_readmem = cros_kunit_readmem_mock;
ec.ec_dev = ec_dev;
ec.dev = ec_dev->dev;
ec.cmd_offset = 0;
for (i = 0; i < ARRAY_SIZE(test_data); ++i) {
/* For EC_CMD_MOTION_SENSE_CMD. */
{
mock = cros_kunit_ec_xfer_mock_addx(test, -EPROTO, EC_RES_SUCCESS, 0);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
}
/* For readmem. */
{
cros_kunit_readmem_mock_data = kunit_kzalloc(test, 1, GFP_KERNEL);
KUNIT_ASSERT_PTR_NE(test, cros_kunit_readmem_mock_data, NULL);
cros_kunit_readmem_mock_data[0] = test_data[i].readmem_data;
cros_kunit_ec_xfer_mock_default_ret = 1;
}
ret = cros_ec_get_sensor_count(&ec);
KUNIT_EXPECT_EQ(test, ret, test_data[i].expected_result);
/* For EC_CMD_MOTION_SENSE_CMD. */
{
struct ec_params_motion_sense *data;
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 1);
KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_MOTION_SENSE_CMD);
KUNIT_EXPECT_EQ(test, mock->msg.insize,
sizeof(struct ec_response_motion_sense));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data));
data = (struct ec_params_motion_sense *)mock->i_data;
KUNIT_EXPECT_EQ(test, data->cmd, MOTIONSENSE_CMD_DUMP);
}
/* For readmem. */
{
KUNIT_EXPECT_EQ(test, cros_kunit_readmem_mock_offset, EC_MEMMAP_ACC_STATUS);
}
}
}
static void cros_ec_proto_test_ec_cmd(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
u8 out[3], in[2];
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
out[0] = 0xdd;
out[1] = 0xcc;
out[2] = 0xbb;
{
u8 *data;
mock = cros_kunit_ec_xfer_mock_add(test, 2);
KUNIT_ASSERT_PTR_NE(test, mock, NULL);
data = (u8 *)mock->o_data;
data[0] = 0xaa;
data[1] = 0x99;
}
ret = cros_ec_cmd(ec_dev, 0x88, 0x77, out, ARRAY_SIZE(out), in, ARRAY_SIZE(in));
KUNIT_EXPECT_EQ(test, ret, 2);
{
u8 *data;
mock = cros_kunit_ec_xfer_mock_next();
KUNIT_EXPECT_PTR_NE(test, mock, NULL);
KUNIT_EXPECT_EQ(test, mock->msg.version, 0x88);
KUNIT_EXPECT_EQ(test, mock->msg.command, 0x77);
KUNIT_EXPECT_EQ(test, mock->msg.insize, ARRAY_SIZE(in));
KUNIT_EXPECT_EQ(test, mock->msg.outsize, ARRAY_SIZE(out));
data = (u8 *)mock->i_data;
KUNIT_EXPECT_EQ(test, data[0], 0xdd);
KUNIT_EXPECT_EQ(test, data[1], 0xcc);
KUNIT_EXPECT_EQ(test, data[2], 0xbb);
}
}
static void cros_ec_proto_test_release(struct device *dev)
{
}
static int cros_ec_proto_test_init(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv;
struct cros_ec_device *ec_dev;
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
test->priv = priv;
ec_dev = &priv->ec_dev;
ec_dev->dout = (u8 *)priv->dout;
ec_dev->dout_size = ARRAY_SIZE(priv->dout);
ec_dev->din = (u8 *)priv->din;
ec_dev->din_size = ARRAY_SIZE(priv->din);
ec_dev->proto_version = EC_HOST_REQUEST_VERSION;
ec_dev->dev = kunit_kzalloc(test, sizeof(*ec_dev->dev), GFP_KERNEL);
if (!ec_dev->dev)
return -ENOMEM;
device_initialize(ec_dev->dev);
dev_set_name(ec_dev->dev, "cros_ec_proto_test");
ec_dev->dev->release = cros_ec_proto_test_release;
ec_dev->cmd_xfer = cros_kunit_ec_xfer_mock;
ec_dev->pkt_xfer = cros_kunit_ec_xfer_mock;
priv->msg = (struct cros_ec_command *)priv->_msg;
cros_kunit_mock_reset();
return 0;
}
static void cros_ec_proto_test_exit(struct kunit *test)
{
struct cros_ec_proto_test_priv *priv = test->priv;
struct cros_ec_device *ec_dev = &priv->ec_dev;
put_device(ec_dev->dev);
}
static struct kunit_case cros_ec_proto_test_cases[] = {
KUNIT_CASE(cros_ec_proto_test_prepare_tx_legacy_normal),
KUNIT_CASE(cros_ec_proto_test_prepare_tx_legacy_bad_msg_outsize),
KUNIT_CASE(cros_ec_proto_test_prepare_tx_normal),
KUNIT_CASE(cros_ec_proto_test_prepare_tx_bad_msg_outsize),
KUNIT_CASE(cros_ec_proto_test_check_result),
KUNIT_CASE(cros_ec_proto_test_query_all_normal),
KUNIT_CASE(cros_ec_proto_test_query_all_no_pd_return_error),
KUNIT_CASE(cros_ec_proto_test_query_all_no_pd_return0),
KUNIT_CASE(cros_ec_proto_test_query_all_legacy_normal_v3_return_error),
KUNIT_CASE(cros_ec_proto_test_query_all_legacy_normal_v3_return0),
KUNIT_CASE(cros_ec_proto_test_query_all_legacy_xfer_error),
KUNIT_CASE(cros_ec_proto_test_query_all_legacy_return_error),
KUNIT_CASE(cros_ec_proto_test_query_all_legacy_data_error),
KUNIT_CASE(cros_ec_proto_test_query_all_legacy_return0),
KUNIT_CASE(cros_ec_proto_test_query_all_no_mkbp),
KUNIT_CASE(cros_ec_proto_test_query_all_no_mkbp_return_error),
KUNIT_CASE(cros_ec_proto_test_query_all_no_mkbp_return0),
KUNIT_CASE(cros_ec_proto_test_query_all_no_host_sleep),
KUNIT_CASE(cros_ec_proto_test_query_all_no_host_sleep_return0),
KUNIT_CASE(cros_ec_proto_test_query_all_default_wake_mask_return_error),
KUNIT_CASE(cros_ec_proto_test_query_all_default_wake_mask_return0),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_normal),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_excess_msg_insize),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_excess_msg_outsize_without_passthru),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_excess_msg_outsize_with_passthru),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_protocol_v3_normal),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_protocol_v3_no_op),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_protocol_v2_normal),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_protocol_v2_no_op),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_normal),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_retries_eagain),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_retries_status_processing),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_xfer_error),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_return_error),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_return0),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_status_normal),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_status_xfer_error),
KUNIT_CASE(cros_ec_proto_test_cmd_xfer_status_return_error),
KUNIT_CASE(cros_ec_proto_test_get_next_event_no_mkbp_event),
KUNIT_CASE(cros_ec_proto_test_get_next_event_mkbp_event_ec_suspended),
KUNIT_CASE(cros_ec_proto_test_get_next_event_mkbp_event_version0),
KUNIT_CASE(cros_ec_proto_test_get_next_event_mkbp_event_version2),
KUNIT_CASE(cros_ec_proto_test_get_next_event_mkbp_event_host_event_rtc),
KUNIT_CASE(cros_ec_proto_test_get_next_event_mkbp_event_host_event_masked),
KUNIT_CASE(cros_ec_proto_test_get_host_event_no_mkbp_event),
KUNIT_CASE(cros_ec_proto_test_get_host_event_not_host_event),
KUNIT_CASE(cros_ec_proto_test_get_host_event_wrong_event_size),
KUNIT_CASE(cros_ec_proto_test_get_host_event_normal),
KUNIT_CASE(cros_ec_proto_test_check_features_cached),
KUNIT_CASE(cros_ec_proto_test_check_features_not_cached),
KUNIT_CASE(cros_ec_proto_test_get_sensor_count_normal),
KUNIT_CASE(cros_ec_proto_test_get_sensor_count_xfer_error),
KUNIT_CASE(cros_ec_proto_test_get_sensor_count_legacy),
KUNIT_CASE(cros_ec_proto_test_ec_cmd),
{}
};
static struct kunit_suite cros_ec_proto_test_suite = {
.name = "cros_ec_proto_test",
.init = cros_ec_proto_test_init,
.exit = cros_ec_proto_test_exit,
.test_cases = cros_ec_proto_test_cases,
};
kunit_test_suite(cros_ec_proto_test_suite);
MODULE_LICENSE("GPL");
......@@ -30,8 +30,8 @@ TRACE_EVENT(cros_ec_request_start,
),
TP_fast_assign(
__entry->version = cmd->version;
__entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(1);
__entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(1);
__entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX);
__entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX);
__entry->outsize = cmd->outsize;
__entry->insize = cmd->insize;
),
......@@ -55,8 +55,8 @@ TRACE_EVENT(cros_ec_request_done,
),
TP_fast_assign(
__entry->version = cmd->version;
__entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(1);
__entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(1);
__entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX);
__entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX);
__entry->outsize = cmd->outsize;
__entry->insize = cmd->insize;
__entry->result = cmd->result;
......
......@@ -25,6 +25,8 @@
#define DRV_NAME "cros-ec-typec"
#define DP_PORT_VDO (BIT(DP_PIN_ASSIGN_C) | BIT(DP_PIN_ASSIGN_D) | DP_CAP_DFP_D)
/* Supported alt modes. */
enum {
CROS_EC_ALTMODE_DP = 0,
......@@ -60,8 +62,7 @@ struct cros_typec_port {
uint8_t mux_flags;
uint8_t role;
/* Port alt modes. */
struct typec_altmode p_altmode[CROS_EC_ALTMODE_MAX];
struct typec_altmode *port_altmode[CROS_EC_ALTMODE_MAX];
/* Flag indicating that PD partner discovery data parsing is completed. */
bool sop_disc_done;
......@@ -254,6 +255,14 @@ static void cros_typec_remove_cable(struct cros_typec_data *typec,
port->sop_prime_disc_done = false;
}
static void cros_typec_unregister_port_altmodes(struct cros_typec_port *port)
{
int i;
for (i = 0; i < CROS_EC_ALTMODE_MAX; i++)
typec_unregister_altmode(port->port_altmode[i]);
}
static void cros_unregister_ports(struct cros_typec_data *typec)
{
int i;
......@@ -268,34 +277,49 @@ static void cros_unregister_ports(struct cros_typec_data *typec)
usb_role_switch_put(typec->ports[i]->role_sw);
typec_switch_put(typec->ports[i]->ori_sw);
typec_mux_put(typec->ports[i]->mux);
cros_typec_unregister_port_altmodes(typec->ports[i]);
typec_unregister_port(typec->ports[i]->port);
}
}
/*
* Fake the alt mode structs until we actually start registering Type C port
* and partner alt modes.
* Register port alt modes with known values till we start retrieving
* port capabilities from the EC.
*/
static void cros_typec_register_port_altmodes(struct cros_typec_data *typec,
static int cros_typec_register_port_altmodes(struct cros_typec_data *typec,
int port_num)
{
struct cros_typec_port *port = typec->ports[port_num];
struct typec_altmode_desc desc;
struct typec_altmode *amode;
/* All PD capable CrOS devices are assumed to support DP altmode. */
port->p_altmode[CROS_EC_ALTMODE_DP].svid = USB_TYPEC_DP_SID;
port->p_altmode[CROS_EC_ALTMODE_DP].mode = USB_TYPEC_DP_MODE;
desc.svid = USB_TYPEC_DP_SID,
desc.mode = USB_TYPEC_DP_MODE,
desc.vdo = DP_PORT_VDO,
amode = typec_port_register_altmode(port->port, &desc);
if (IS_ERR(amode))
return PTR_ERR(amode);
port->port_altmode[CROS_EC_ALTMODE_DP] = amode;
/*
* Register TBT compatibility alt mode. The EC will not enter the mode
* if it doesn't support it, so it's safe to register it unconditionally
* here for now.
*/
port->p_altmode[CROS_EC_ALTMODE_TBT].svid = USB_TYPEC_TBT_SID;
port->p_altmode[CROS_EC_ALTMODE_TBT].mode = TYPEC_ANY_MODE;
memset(&desc, 0, sizeof(desc));
desc.svid = USB_TYPEC_TBT_SID,
desc.mode = TYPEC_ANY_MODE,
amode = typec_port_register_altmode(port->port, &desc);
if (IS_ERR(amode))
return PTR_ERR(amode);
port->port_altmode[CROS_EC_ALTMODE_TBT] = amode;
port->state.alt = NULL;
port->state.mode = TYPEC_STATE_USB;
port->state.data = NULL;
return 0;
}
static int cros_typec_init_ports(struct cros_typec_data *typec)
......@@ -352,8 +376,8 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
cros_port->port = typec_register_port(dev, cap);
if (IS_ERR(cros_port->port)) {
dev_err(dev, "Failed to register port %d\n", port_num);
ret = PTR_ERR(cros_port->port);
dev_err_probe(dev, ret, "Failed to register port %d\n", port_num);
goto unregister_ports;
}
......@@ -362,7 +386,11 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
dev_dbg(dev, "No switch control for port %d\n",
port_num);
cros_typec_register_port_altmodes(typec, port_num);
ret = cros_typec_register_port_altmodes(typec, port_num);
if (ret) {
dev_err(dev, "Failed to register port altmodes\n");
goto unregister_ports;
}
cros_port->disc_data = devm_kzalloc(dev, EC_PROTO2_MAX_RESPONSE_SIZE, GFP_KERNEL);
if (!cros_port->disc_data) {
......@@ -431,7 +459,7 @@ static int cros_typec_enable_tbt(struct cros_typec_data *typec,
data.enter_vdo |= TBT_ENTER_MODE_ACTIVE_CABLE;
if (!port->state.alt) {
port->state.alt = &port->p_altmode[CROS_EC_ALTMODE_TBT];
port->state.alt = port->port_altmode[CROS_EC_ALTMODE_TBT];
ret = cros_typec_usb_safe_state(port);
if (ret)
return ret;
......@@ -473,7 +501,7 @@ static int cros_typec_enable_dp(struct cros_typec_data *typec,
/* Configuration VDO. */
dp_data.conf = DP_CONF_SET_PIN_ASSIGN(pd_ctrl->dp_mode);
if (!port->state.alt) {
port->state.alt = &port->p_altmode[CROS_EC_ALTMODE_DP];
port->state.alt = port->port_altmode[CROS_EC_ALTMODE_DP];
ret = cros_typec_usb_safe_state(port);
if (ret)
return ret;
......@@ -525,8 +553,8 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
enum typec_orientation orientation;
int ret;
ret = cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_MUX_INFO,
&req, sizeof(req), &resp, sizeof(resp));
ret = cros_ec_cmd(typec->ec, 0, EC_CMD_USB_PD_MUX_INFO,
&req, sizeof(req), &resp, sizeof(resp));
if (ret < 0) {
dev_warn(typec->dev, "Failed to get mux info for port: %d, err = %d\n",
port_num, ret);
......@@ -585,8 +613,8 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
/* Sending Acknowledgment to EC */
mux_ack.port = port_num;
if (cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_MUX_ACK, &mux_ack,
sizeof(mux_ack), NULL, 0) < 0)
if (cros_ec_cmd(typec->ec, 0, EC_CMD_USB_PD_MUX_ACK, &mux_ack,
sizeof(mux_ack), NULL, 0) < 0)
dev_warn(typec->dev,
"Failed to send Mux ACK to EC for port: %d\n",
port_num);
......@@ -754,8 +782,8 @@ static int cros_typec_handle_sop_prime_disc(struct cros_typec_data *typec, int p
int ret = 0;
memset(disc, 0, EC_PROTO2_MAX_RESPONSE_SIZE);
ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req),
disc, EC_PROTO2_MAX_RESPONSE_SIZE);
ret = cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req),
disc, EC_PROTO2_MAX_RESPONSE_SIZE);
if (ret < 0) {
dev_err(typec->dev, "Failed to get SOP' discovery data for port: %d\n", port_num);
goto sop_prime_disc_exit;
......@@ -837,8 +865,8 @@ static int cros_typec_handle_sop_disc(struct cros_typec_data *typec, int port_nu
typec_partner_set_pd_revision(port->partner, pd_revision);
memset(sop_disc, 0, EC_PROTO2_MAX_RESPONSE_SIZE);
ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req),
sop_disc, EC_PROTO2_MAX_RESPONSE_SIZE);
ret = cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req),
sop_disc, EC_PROTO2_MAX_RESPONSE_SIZE);
if (ret < 0) {
dev_err(typec->dev, "Failed to get SOP discovery data for port: %d\n", port_num);
goto disc_exit;
......@@ -870,8 +898,8 @@ static int cros_typec_send_clear_event(struct cros_typec_data *typec, int port_n
.clear_events_mask = events_mask,
};
return cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_CONTROL, &req,
sizeof(req), NULL, 0);
return cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_CONTROL, &req,
sizeof(req), NULL, 0);
}
static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num)
......@@ -882,8 +910,8 @@ static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num
};
int ret;
ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_STATUS, &req, sizeof(req),
&resp, sizeof(resp));
ret = cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_STATUS, &req, sizeof(req),
&resp, sizeof(resp));
if (ret < 0) {
dev_warn(typec->dev, "EC_CMD_TYPEC_STATUS failed for port: %d\n", port_num);
return;
......@@ -960,9 +988,9 @@ static int cros_typec_port_update(struct cros_typec_data *typec, int port_num)
req.mux = USB_PD_CTRL_MUX_NO_CHANGE;
req.swap = USB_PD_CTRL_SWAP_NONE;
ret = cros_ec_command(typec->ec, typec->pd_ctrl_ver,
EC_CMD_USB_PD_CONTROL, &req, sizeof(req),
&resp, sizeof(resp));
ret = cros_ec_cmd(typec->ec, typec->pd_ctrl_ver,
EC_CMD_USB_PD_CONTROL, &req, sizeof(req),
&resp, sizeof(resp));
if (ret < 0)
return ret;
......@@ -997,9 +1025,8 @@ static int cros_typec_get_cmd_version(struct cros_typec_data *typec)
/* We're interested in the PD control command version. */
req_v1.cmd = EC_CMD_USB_PD_CONTROL;
ret = cros_ec_command(typec->ec, 1, EC_CMD_GET_CMD_VERSIONS,
&req_v1, sizeof(req_v1), &resp,
sizeof(resp));
ret = cros_ec_cmd(typec->ec, 1, EC_CMD_GET_CMD_VERSIONS,
&req_v1, sizeof(req_v1), &resp, sizeof(resp));
if (ret < 0)
return ret;
......@@ -1090,8 +1117,8 @@ static int cros_typec_probe(struct platform_device *pdev)
typec->typec_cmd_supported = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_CMD);
typec->needs_mux_ack = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK);
ret = cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_PORTS, NULL, 0,
&resp, sizeof(resp));
ret = cros_ec_cmd(typec->ec, 0, EC_CMD_USB_PD_PORTS, NULL, 0,
&resp, sizeof(resp));
if (ret < 0)
return ret;
......
......@@ -4,24 +4,60 @@
// Copyright (C) 2012 Google, Inc.
#include <linux/acpi.h>
#include <linux/leds.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
struct keyboard_led {
struct led_classdev cdev;
struct cros_ec_device *ec;
};
/**
* struct keyboard_led_drvdata - keyboard LED driver data.
* @init: Init function.
* @brightness_get: Get LED brightness level.
* @brightness_set: Set LED brightness level. Must not sleep.
* @brightness_set_blocking: Set LED brightness level. It can block the
* caller for the time required for accessing a
* LED device register
* @max_brightness: Maximum brightness.
*
* See struct led_classdev in include/linux/leds.h for more details.
*/
struct keyboard_led_drvdata {
int (*init)(struct platform_device *pdev);
enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
void (*brightness_set)(struct led_classdev *led_cdev,
enum led_brightness brightness);
int (*brightness_set_blocking)(struct led_classdev *led_cdev,
enum led_brightness brightness);
enum led_brightness max_brightness;
};
#define KEYBOARD_BACKLIGHT_MAX 100
#ifdef CONFIG_ACPI
/* Keyboard LED ACPI Device must be defined in firmware */
#define ACPI_KEYBOARD_BACKLIGHT_DEVICE "\\_SB.KBLT"
#define ACPI_KEYBOARD_BACKLIGHT_READ ACPI_KEYBOARD_BACKLIGHT_DEVICE ".KBQC"
#define ACPI_KEYBOARD_BACKLIGHT_WRITE ACPI_KEYBOARD_BACKLIGHT_DEVICE ".KBCM"
#define ACPI_KEYBOARD_BACKLIGHT_MAX 100
static void keyboard_led_set_brightness(struct led_classdev *cdev,
enum led_brightness brightness)
static void keyboard_led_set_brightness_acpi(struct led_classdev *cdev,
enum led_brightness brightness)
{
union acpi_object param;
struct acpi_object_list input;
......@@ -40,7 +76,7 @@ static void keyboard_led_set_brightness(struct led_classdev *cdev,
}
static enum led_brightness
keyboard_led_get_brightness(struct led_classdev *cdev)
keyboard_led_get_brightness_acpi(struct led_classdev *cdev)
{
unsigned long long brightness;
acpi_status status;
......@@ -56,12 +92,10 @@ keyboard_led_get_brightness(struct led_classdev *cdev)
return brightness;
}
static int keyboard_led_probe(struct platform_device *pdev)
static int keyboard_led_init_acpi(struct platform_device *pdev)
{
struct led_classdev *cdev;
acpi_handle handle;
acpi_status status;
int error;
/* Look for the keyboard LED ACPI Device */
status = acpi_get_handle(ACPI_ROOT_OBJECT,
......@@ -73,33 +107,151 @@ static int keyboard_led_probe(struct platform_device *pdev)
return -ENXIO;
}
cdev = devm_kzalloc(&pdev->dev, sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return 0;
}
static const struct keyboard_led_drvdata keyboard_led_drvdata_acpi = {
.init = keyboard_led_init_acpi,
.brightness_set = keyboard_led_set_brightness_acpi,
.brightness_get = keyboard_led_get_brightness_acpi,
.max_brightness = KEYBOARD_BACKLIGHT_MAX,
};
#endif /* CONFIG_ACPI */
#if IS_ENABLED(CONFIG_CROS_EC)
static int
keyboard_led_set_brightness_ec_pwm(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct {
struct cros_ec_command msg;
struct ec_params_pwm_set_keyboard_backlight params;
} __packed buf;
struct ec_params_pwm_set_keyboard_backlight *params = &buf.params;
struct cros_ec_command *msg = &buf.msg;
struct keyboard_led *keyboard_led = container_of(cdev, struct keyboard_led, cdev);
memset(&buf, 0, sizeof(buf));
msg->command = EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT;
msg->outsize = sizeof(*params);
params->percent = brightness;
return cros_ec_cmd_xfer_status(keyboard_led->ec, msg);
}
static enum led_brightness
keyboard_led_get_brightness_ec_pwm(struct led_classdev *cdev)
{
struct {
struct cros_ec_command msg;
struct ec_response_pwm_get_keyboard_backlight resp;
} __packed buf;
struct ec_response_pwm_get_keyboard_backlight *resp = &buf.resp;
struct cros_ec_command *msg = &buf.msg;
struct keyboard_led *keyboard_led = container_of(cdev, struct keyboard_led, cdev);
int ret;
memset(&buf, 0, sizeof(buf));
msg->command = EC_CMD_PWM_GET_KEYBOARD_BACKLIGHT;
msg->insize = sizeof(*resp);
ret = cros_ec_cmd_xfer_status(keyboard_led->ec, msg);
if (ret < 0)
return ret;
return resp->percent;
}
static int keyboard_led_init_ec_pwm(struct platform_device *pdev)
{
struct keyboard_led *keyboard_led = platform_get_drvdata(pdev);
keyboard_led->ec = dev_get_drvdata(pdev->dev.parent);
if (!keyboard_led->ec) {
dev_err(&pdev->dev, "no parent EC device\n");
return -EINVAL;
}
return 0;
}
static const __maybe_unused struct keyboard_led_drvdata keyboard_led_drvdata_ec_pwm = {
.init = keyboard_led_init_ec_pwm,
.brightness_set_blocking = keyboard_led_set_brightness_ec_pwm,
.brightness_get = keyboard_led_get_brightness_ec_pwm,
.max_brightness = KEYBOARD_BACKLIGHT_MAX,
};
#else /* IS_ENABLED(CONFIG_CROS_EC) */
static const __maybe_unused struct keyboard_led_drvdata keyboard_led_drvdata_ec_pwm = {};
#endif /* IS_ENABLED(CONFIG_CROS_EC) */
static int keyboard_led_probe(struct platform_device *pdev)
{
const struct keyboard_led_drvdata *drvdata;
struct keyboard_led *keyboard_led;
int error;
drvdata = device_get_match_data(&pdev->dev);
if (!drvdata)
return -EINVAL;
keyboard_led = devm_kzalloc(&pdev->dev, sizeof(*keyboard_led), GFP_KERNEL);
if (!keyboard_led)
return -ENOMEM;
platform_set_drvdata(pdev, keyboard_led);
if (drvdata->init) {
error = drvdata->init(pdev);
if (error)
return error;
}
cdev->name = "chromeos::kbd_backlight";
cdev->max_brightness = ACPI_KEYBOARD_BACKLIGHT_MAX;
cdev->flags |= LED_CORE_SUSPENDRESUME;
cdev->brightness_set = keyboard_led_set_brightness;
cdev->brightness_get = keyboard_led_get_brightness;
keyboard_led->cdev.name = "chromeos::kbd_backlight";
keyboard_led->cdev.flags |= LED_CORE_SUSPENDRESUME;
keyboard_led->cdev.max_brightness = drvdata->max_brightness;
keyboard_led->cdev.brightness_set = drvdata->brightness_set;
keyboard_led->cdev.brightness_set_blocking = drvdata->brightness_set_blocking;
keyboard_led->cdev.brightness_get = drvdata->brightness_get;
error = devm_led_classdev_register(&pdev->dev, cdev);
error = devm_led_classdev_register(&pdev->dev, &keyboard_led->cdev);
if (error)
return error;
return 0;
}
static const struct acpi_device_id keyboard_led_id[] = {
{ "GOOG0002", 0 },
#ifdef CONFIG_ACPI
static const struct acpi_device_id keyboard_led_acpi_match[] = {
{ "GOOG0002", (kernel_ulong_t)&keyboard_led_drvdata_acpi },
{ }
};
MODULE_DEVICE_TABLE(acpi, keyboard_led_id);
MODULE_DEVICE_TABLE(acpi, keyboard_led_acpi_match);
#endif
#ifdef CONFIG_OF
static const struct of_device_id keyboard_led_of_match[] = {
{
.compatible = "google,cros-kbd-led-backlight",
.data = &keyboard_led_drvdata_ec_pwm,
},
{}
};
MODULE_DEVICE_TABLE(of, keyboard_led_of_match);
#endif
static struct platform_driver keyboard_led_driver = {
.driver = {
.name = "chromeos-keyboard-leds",
.acpi_match_table = ACPI_PTR(keyboard_led_id),
.acpi_match_table = ACPI_PTR(keyboard_led_acpi_match),
.of_match_table = of_match_ptr(keyboard_led_of_match),
},
.probe = keyboard_led_probe,
};
......
// SPDX-License-Identifier: GPL-2.0
/*
* CrOS Kunit tests utilities.
*/
#include <kunit/test.h>
#include <linux/list.h>
#include <linux/minmax.h>
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
#include "cros_ec.h"
#include "cros_kunit_util.h"
int cros_kunit_ec_xfer_mock_default_result;
int cros_kunit_ec_xfer_mock_default_ret;
int cros_kunit_ec_cmd_xfer_mock_called;
int cros_kunit_ec_pkt_xfer_mock_called;
static struct list_head cros_kunit_ec_xfer_mock_in;
static struct list_head cros_kunit_ec_xfer_mock_out;
int cros_kunit_ec_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
{
struct ec_xfer_mock *mock;
mock = list_first_entry_or_null(&cros_kunit_ec_xfer_mock_in, struct ec_xfer_mock, list);
if (!mock) {
msg->result = cros_kunit_ec_xfer_mock_default_result;
return cros_kunit_ec_xfer_mock_default_ret;
}
list_del(&mock->list);
memcpy(&mock->msg, msg, sizeof(*msg));
if (msg->outsize) {
mock->i_data = kunit_kzalloc(mock->test, msg->outsize, GFP_KERNEL);
if (mock->i_data)
memcpy(mock->i_data, msg->data, msg->outsize);
}
msg->result = mock->result;
if (msg->insize)
memcpy(msg->data, mock->o_data, min(msg->insize, mock->o_data_len));
list_add_tail(&mock->list, &cros_kunit_ec_xfer_mock_out);
return mock->ret;
}
int cros_kunit_ec_cmd_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
{
++cros_kunit_ec_cmd_xfer_mock_called;
return cros_kunit_ec_xfer_mock(ec_dev, msg);
}
int cros_kunit_ec_pkt_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
{
++cros_kunit_ec_pkt_xfer_mock_called;
return cros_kunit_ec_xfer_mock(ec_dev, msg);
}
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_add(struct kunit *test, size_t size)
{
return cros_kunit_ec_xfer_mock_addx(test, size, EC_RES_SUCCESS, size);
}
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_addx(struct kunit *test,
int ret, int result, size_t size)
{
struct ec_xfer_mock *mock;
mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL);
if (!mock)
return NULL;
list_add_tail(&mock->list, &cros_kunit_ec_xfer_mock_in);
mock->test = test;
mock->ret = ret;
mock->result = result;
mock->o_data = kunit_kzalloc(test, size, GFP_KERNEL);
if (!mock->o_data)
return NULL;
mock->o_data_len = size;
return mock;
}
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_next(void)
{
struct ec_xfer_mock *mock;
mock = list_first_entry_or_null(&cros_kunit_ec_xfer_mock_out, struct ec_xfer_mock, list);
if (mock)
list_del(&mock->list);
return mock;
}
int cros_kunit_readmem_mock_offset;
u8 *cros_kunit_readmem_mock_data;
int cros_kunit_readmem_mock_ret;
int cros_kunit_readmem_mock(struct cros_ec_device *ec_dev, unsigned int offset,
unsigned int bytes, void *dest)
{
cros_kunit_readmem_mock_offset = offset;
memcpy(dest, cros_kunit_readmem_mock_data, bytes);
return cros_kunit_readmem_mock_ret;
}
void cros_kunit_mock_reset(void)
{
cros_kunit_ec_xfer_mock_default_result = 0;
cros_kunit_ec_xfer_mock_default_ret = 0;
cros_kunit_ec_cmd_xfer_mock_called = 0;
cros_kunit_ec_pkt_xfer_mock_called = 0;
INIT_LIST_HEAD(&cros_kunit_ec_xfer_mock_in);
INIT_LIST_HEAD(&cros_kunit_ec_xfer_mock_out);
cros_kunit_readmem_mock_offset = 0;
cros_kunit_readmem_mock_data = NULL;
cros_kunit_readmem_mock_ret = 0;
}
MODULE_LICENSE("GPL");
/* SPDX-License-Identifier: GPL-2.0 */
/*
* CrOS Kunit tests utilities.
*/
#ifndef _CROS_KUNIT_UTIL_H_
#define _CROS_KUNIT_UTIL_H_
#include <linux/platform_data/cros_ec_proto.h>
struct ec_xfer_mock {
struct list_head list;
struct kunit *test;
/* input */
struct cros_ec_command msg;
void *i_data;
/* output */
int ret;
int result;
void *o_data;
u32 o_data_len;
};
extern int cros_kunit_ec_xfer_mock_default_result;
extern int cros_kunit_ec_xfer_mock_default_ret;
extern int cros_kunit_ec_cmd_xfer_mock_called;
extern int cros_kunit_ec_pkt_xfer_mock_called;
int cros_kunit_ec_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg);
int cros_kunit_ec_cmd_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg);
int cros_kunit_ec_pkt_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg);
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_add(struct kunit *test, size_t size);
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_addx(struct kunit *test,
int ret, int result, size_t size);
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_next(void);
extern int cros_kunit_readmem_mock_offset;
extern u8 *cros_kunit_readmem_mock_data;
extern int cros_kunit_readmem_mock_ret;
int cros_kunit_readmem_mock(struct cros_ec_device *ec_dev, unsigned int offset,
unsigned int bytes, void *dest);
void cros_kunit_mock_reset(void);
#endif
......@@ -71,8 +71,8 @@ static void cros_usbpd_get_event_and_notify(struct device *dev,
}
/* Check for PD host events on EC. */
ret = cros_ec_command(ec_dev, 0, EC_CMD_PD_HOST_EVENT_STATUS,
NULL, 0, &host_event_status, sizeof(host_event_status));
ret = cros_ec_cmd(ec_dev, 0, EC_CMD_PD_HOST_EVENT_STATUS,
NULL, 0, &host_event_status, sizeof(host_event_status));
if (ret < 0) {
dev_warn(dev, "Can't get host event status (err: %d)\n", ret);
goto send_notify;
......
......@@ -343,7 +343,7 @@ static __poll_t event_poll(struct file *filp, poll_table *wait)
*
* Removes the first event from the queue, places it in the passed buffer.
*
* If there are no events in the the queue, then one of two things happens,
* If there are no events in the queue, then one of two things happens,
* depending on if the file was opened in nonblocking mode: If in nonblocking
* mode, then return -EAGAIN to say there's no data. If in blocking mode, then
* block until an event is available.
......
......@@ -22,36 +22,6 @@ struct cros_ec_regulator_data {
u16 num_voltages;
};
static int cros_ec_cmd(struct cros_ec_device *ec, u32 version, u32 command,
void *outdata, u32 outsize, void *indata, u32 insize)
{
struct cros_ec_command *msg;
int ret;
msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL);
if (!msg)
return -ENOMEM;
msg->version = version;
msg->command = command;
msg->outsize = outsize;
msg->insize = insize;
if (outdata && outsize > 0)
memcpy(msg->data, outdata, outsize);
ret = cros_ec_cmd_xfer_status(ec, msg);
if (ret < 0)
goto cleanup;
if (insize)
memcpy(indata, msg->data, insize);
cleanup:
kfree(msg);
return ret;
}
static int cros_ec_regulator_enable(struct regulator_dev *dev)
{
struct cros_ec_regulator_data *data = rdev_get_drvdata(dev);
......@@ -61,7 +31,7 @@ static int cros_ec_regulator_enable(struct regulator_dev *dev)
};
return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd,
sizeof(cmd), NULL, 0);
sizeof(cmd), NULL, 0);
}
static int cros_ec_regulator_disable(struct regulator_dev *dev)
......@@ -73,7 +43,7 @@ static int cros_ec_regulator_disable(struct regulator_dev *dev)
};
return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd,
sizeof(cmd), NULL, 0);
sizeof(cmd), NULL, 0);
}
static int cros_ec_regulator_is_enabled(struct regulator_dev *dev)
......@@ -161,7 +131,7 @@ static int cros_ec_regulator_init_info(struct device *dev,
int ret;
ret = cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_GET_INFO, &cmd,
sizeof(cmd), &resp, sizeof(resp));
sizeof(cmd), &resp, sizeof(resp));
if (ret < 0)
return ret;
......
......@@ -13,8 +13,8 @@
#ifndef __CROS_EC_COMMANDS_H
#define __CROS_EC_COMMANDS_H
#include <linux/bits.h>
#include <linux/types.h>
#define BUILD_ASSERT(_cond)
......@@ -787,7 +787,7 @@ struct ec_host_response {
*
* Packets always start with a request or response header. They are followed
* by data_len bytes of data. If the data_crc_present flag is set, the data
* bytes are followed by a CRC-8 of that data, using using x^8 + x^2 + x + 1
* bytes are followed by a CRC-8 of that data, using x^8 + x^2 + x + 1
* polynomial.
*
* Host algorithm when sending a request q:
......
......@@ -21,6 +21,9 @@
#define CROS_EC_DEV_SCP_NAME "cros_scp"
#define CROS_EC_DEV_TP_NAME "cros_tp"
#define CROS_EC_DEV_EC_INDEX 0
#define CROS_EC_DEV_PD_INDEX 1
/*
* The EC is unresponsive for a time after a reboot command. Add a
* simple delay to make sure that the bus stays locked.
......@@ -231,8 +234,8 @@ bool cros_ec_check_features(struct cros_ec_dev *ec, int feature);
int cros_ec_get_sensor_count(struct cros_ec_dev *ec);
int cros_ec_command(struct cros_ec_device *ec_dev, unsigned int version, int command, void *outdata,
int outsize, void *indata, int insize);
int cros_ec_cmd(struct cros_ec_device *ec_dev, unsigned int version, int command, void *outdata,
size_t outsize, void *indata, size_t insize);
/**
* cros_ec_get_time_ns() - Return time in ns.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment