// SPDX-License-Identifier: GPL-2.0 /* * Kunit tests for ChromeOS Embedded Controller protocol. */ #include #include #include #include #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");