/* Copyright 2020 The ChromiumOS Authors * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Test USB Protocol Layer module. */ #include "common.h" #include "mock/tcpc_mock.h" #include "mock/tcpm_mock.h" #include "mock/usb_pe_sm_mock.h" #include "mock/usb_tc_sm_mock.h" #include "task.h" #include "tcpm/tcpci.h" #include "tcpm/tcpm.h" #include "test_util.h" #include "timer.h" #include "usb_emsg.h" #include "usb_pd.h" #include "usb_pd_test_util.h" #include "usb_pe_sm.h" #include "usb_prl_sm.h" #include "usb_sm_checks.h" #include "usb_tc_sm.h" #include "util.h" #define PORT0 0 /* Install Mock TCPC and MUX drivers */ const struct tcpc_config_t tcpc_config[CONFIG_USB_PD_PORT_MAX_COUNT] = { { .drv = &mock_tcpc_driver, }, }; static enum pd_power_role get_partner_power_role(int port) { return pd_get_power_role(port) == PD_ROLE_SINK ? PD_ROLE_SOURCE : PD_ROLE_SINK; } static enum pd_data_role get_partner_data_role(int port) { return pd_get_data_role(port) == PD_ROLE_UFP ? PD_ROLE_DFP : PD_ROLE_UFP; } static void enable_prl(int port, int en) { tcpm_set_rx_enable(port, en); mock_tc_port[port].pd_enable = en; task_wait_event(10 * MSEC); prl_set_rev(port, TCPCI_MSG_SOP, mock_tc_port[port].rev); } static int test_receive_control_msg(void) { int port = PORT0; uint16_t header = PD_HEADER(PD_CTRL_DR_SWAP, get_partner_power_role(port), get_partner_data_role(port), mock_tc_port[port].msg_rx_id, 0, mock_tc_port[port].rev, 0); /* Set up the message to be received. */ mock_tcpm_rx_msg(port, header, 0, NULL); /* Process the message. */ task_wait_event(10 * MSEC); /* Check results. */ TEST_NE(mock_pe_port[port].mock_pe_message_received, 0, "%d"); TEST_EQ(header, rx_emsg[port].header, "%d"); TEST_EQ(rx_emsg[port].len, 0, "%d"); TEST_LE(mock_pe_port[port].mock_pe_error, 0, "%d"); TEST_EQ(mock_pe_port[port].mock_pe_message_discarded, 0, "%d"); TEST_EQ(mock_pe_port[port].mock_got_soft_reset, 0, "%d"); TEST_EQ(mock_pe_port[port].mock_pe_got_hard_reset, 0, "%d"); TEST_EQ(mock_pe_port[port].mock_pe_hard_reset_sent, 0, "%d"); return EC_SUCCESS; } static int test_send_control_msg(void) { int port = PORT0; /* Set up the message to be sent. */ prl_send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_ACCEPT); task_wait_event(MSEC); /* Simulate the TX complete that the PD_INT handler would signal */ pd_transmit_complete(port, TCPC_TX_COMPLETE_SUCCESS); task_wait_event(10 * MSEC); /* Check results. */ TEST_NE(mock_pe_port[port].mock_pe_message_sent, 0, "%d"); TEST_LE(mock_pe_port[port].mock_pe_error, 0, "%d"); TEST_EQ(mock_pe_port[port].mock_pe_message_discarded, 0, "%d"); TEST_EQ(mock_pe_port[port].mock_got_soft_reset, 0, "%d"); TEST_EQ(mock_pe_port[port].mock_pe_got_hard_reset, 0, "%d"); TEST_EQ(mock_pe_port[port].mock_pe_hard_reset_sent, 0, "%d"); return EC_SUCCESS; } static int test_discard_queued_tx_when_rx_happens(void) { int port = PORT0; uint16_t header = PD_HEADER(PD_CTRL_DR_SWAP, get_partner_power_role(port), get_partner_data_role(port), mock_tc_port[port].msg_rx_id, 0, mock_tc_port[port].rev, 0); uint8_t *buf = tx_emsg[port].buf; uint8_t len = 8; uint8_t i = 0; /* Set up the message to be sent. */ for (i = 0; i < len; i++) buf[i] = (uint8_t)i; tx_emsg[port].len = len; prl_send_data_msg(port, TCPCI_MSG_SOP, PD_DATA_SOURCE_CAP); /* Set up the message to be received. */ mock_tcpm_rx_msg(port, header, 0, NULL); /* Process the message. */ task_wait_event(10 * MSEC); /* Check results. Source should have discarded its message queued up * to TX, and should have received the message from the sink. */ TEST_NE(mock_pe_port[port].mock_pe_message_discarded, 0, "%d"); TEST_NE(mock_pe_port[port].mock_pe_message_received, 0, "%d"); TEST_EQ(mock_pe_port[port].mock_pe_message_sent, 0, "%d"); TEST_LE(mock_pe_port[port].mock_pe_error, 0, "%d"); TEST_EQ(mock_pe_port[port].mock_got_soft_reset, 0, "%d"); TEST_EQ(mock_pe_port[port].mock_pe_got_hard_reset, 0, "%d"); TEST_EQ(mock_pe_port[port].mock_pe_hard_reset_sent, 0, "%d"); return EC_SUCCESS; } void before_test(void) { mock_tc_port_reset(); mock_tc_port[PORT0].rev = PD_REV30; mock_tc_port[PORT0].power_role = PD_ROLE_SOURCE; mock_tc_port[PORT0].data_role = PD_ROLE_DFP; mock_tcpm_reset(); mock_pe_port_reset(); prl_reset_soft(PORT0); enable_prl(PORT0, 1); } void after_test(void) { enable_prl(PORT0, 0); } void run_test(int argc, const char **argv) { RUN_TEST(test_receive_control_msg); RUN_TEST(test_send_control_msg); RUN_TEST(test_discard_queued_tx_when_rx_happens); /* TODO add tests here */ /* Do basic state machine validity checks last. */ RUN_TEST(test_prl_no_parent_cycles); RUN_TEST(test_prl_all_states_named); test_print_result(); }