diff options
author | Tomasz Michalec <tm@semihalf.com> | 2022-03-14 12:21:21 +0100 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2022-03-18 14:21:14 +0000 |
commit | 0ba59b5235353574341d0042a52d945c16999513 (patch) | |
tree | dde43c22c48cff57b4bd73d556918f47867900be /zephyr/emul/tcpc/emul_tcpci_partner_src.c | |
parent | 3f20cb6990a1220b1c1630d46b905fcc77c452f4 (diff) | |
download | chrome-ec-0ba59b5235353574341d0042a52d945c16999513.tar.gz |
zephyr: emul: Resend source capabilities
Resend source capabilities message from TCPC source partner emulator,
when previous message couldn't be send. This is in line with PD
specification.
BUG=b:224927648
BRANCH=none
TEST=zmake configure --test test-drivers
Signed-off-by: Tomasz Michalec <tm@semihalf.com>
Change-Id: I34a6b3d08546f3a17dcad629f4c6f09cd189f15f
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3528403
Reviewed-by: Fabio Baltieri <fabiobaltieri@google.com>
Tested-by: Tomasz Michalec <tmichalec@google.com>
Commit-Queue: Tomasz Michalec <tmichalec@google.com>
Diffstat (limited to 'zephyr/emul/tcpc/emul_tcpci_partner_src.c')
-rw-r--r-- | zephyr/emul/tcpc/emul_tcpci_partner_src.c | 133 |
1 files changed, 125 insertions, 8 deletions
diff --git a/zephyr/emul/tcpc/emul_tcpci_partner_src.c b/zephyr/emul/tcpc/emul_tcpci_partner_src.c index 504b05504f..9e2a90b227 100644 --- a/zephyr/emul/tcpc/emul_tcpci_partner_src.c +++ b/zephyr/emul/tcpc/emul_tcpci_partner_src.c @@ -15,6 +15,44 @@ LOG_MODULE_REGISTER(tcpci_src_emul, CONFIG_TCPCI_EMUL_LOG_LEVEL); #include "emul/tcpc/emul_tcpci.h" #include "usb_pd.h" +/** + * @brief Start source capability timer. Capability message will be send after + * @p time. + * + * @param data Pointer to USB-C source device emulator data + * @param time Time to delay before sending capability message + */ +static void tcpci_src_emul_start_source_capability_custom_time( + struct tcpci_src_emul_data *data, k_timeout_t time) +{ + /* Use reschedule */ + k_work_reschedule(&data->source_capability_timeout, time); +} + +/** + * @brief Start source capability timer. Capability message will be send after + * TCPCI_SOURCE_CAPABILITY_TIMEOUT milliseconds. + * + * @param data Pointer to USB-C source device emulator data + */ +static void tcpci_src_emul_start_source_capability_timer( + struct tcpci_src_emul_data *data) +{ + tcpci_src_emul_start_source_capability_custom_time( + data, TCPCI_SOURCE_CAPABILITY_TIMEOUT); +} + +/** + * @brief Stop source capability timer. Capability message will not be repeated. + * + * @param data Pointer to USB-C source device emulator data + */ +static void tcpci_src_emul_stop_source_capability_timer( + struct tcpci_src_emul_data *data) +{ + k_work_cancel_delayable(&data->source_capability_timeout); +} + /** Check description in emul_tcpci_partner_src.h */ int tcpci_src_emul_send_capability_msg(struct tcpci_src_emul_data *data, struct tcpci_partner_data *common_data, @@ -35,6 +73,34 @@ int tcpci_src_emul_send_capability_msg(struct tcpci_src_emul_data *data, } /** Check description in emul_tcpci_partner_src.h */ +int tcpci_src_emul_send_capability_msg_with_timer( + struct tcpci_src_emul_data *data, + struct tcpci_partner_data *common_data, + uint64_t delay) +{ + int ret; + + if (delay > 0) { + tcpci_src_emul_start_source_capability_custom_time( + data, K_MSEC(delay)); + return TCPCI_EMUL_TX_SUCCESS; + } + + ret = tcpci_src_emul_send_capability_msg(data, common_data, 0); + + if (ret != 0) { + tcpci_src_emul_start_source_capability_timer(data); + } + /* + * If sending message was successful, SenderResponse timer should be + * started. However this will break emulation until RECEIVE_DETECT + * register is properly implemented in TCPCI emulator. + */ + + return TCPCI_EMUL_TX_SUCCESS; +} + +/** Check description in emul_tcpci_partner_src.h */ enum tcpci_partner_handler_res tcpci_src_emul_handle_sop_msg( struct tcpci_src_emul_data *data, struct tcpci_partner_data *common_data, @@ -48,6 +114,8 @@ enum tcpci_partner_handler_res tcpci_src_emul_handle_sop_msg( /* Handle data message */ switch (PD_HEADER_TYPE(header)) { case PD_DATA_REQUEST: + tcpci_partner_stop_sender_response_timer(common_data); + /* TODO(b/224925855): Validate if request can be met */ tcpci_partner_send_control_msg(common_data, PD_CTRL_ACCEPT, 0); /* PS ready after 15 ms */ @@ -65,9 +133,9 @@ enum tcpci_partner_handler_res tcpci_src_emul_handle_sop_msg( 0); return TCPCI_PARTNER_COMMON_MSG_HANDLED; case PD_CTRL_SOFT_RESET: - /* Send capability after 15 ms to establish PD again */ - tcpci_src_emul_send_capability_msg(data, common_data, - 15); + /* Send capability to establish PD again */ + tcpci_src_emul_send_capability_msg_with_timer( + data, common_data, 0); return TCPCI_PARTNER_COMMON_MSG_HANDLED; default: return TCPCI_PARTNER_COMMON_MSG_NOT_HANDLED; @@ -75,14 +143,47 @@ enum tcpci_partner_handler_res tcpci_src_emul_handle_sop_msg( } } +/** + * @brief Handler for repeating SourceCapability message + * + * @param timer Pointer to timer which triggered timeout + */ +static void tcpci_src_emul_source_capability_timeout(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct tcpci_src_emul_data *data = + CONTAINER_OF(dwork, struct tcpci_src_emul_data, + source_capability_timeout); + struct tcpci_partner_data *common_data = data->common_data; + + if (k_mutex_lock(&common_data->transmit_mutex, K_NO_WAIT) != 0) { + /* + * Emulator is probably handling received message, + * try later if timer wasn't stopped. + */ + k_work_submit(work); + return; + } + + /* Make sure that timer isn't stopped */ + if (k_work_busy_get(work) & K_WORK_CANCELING) { + k_mutex_unlock(&common_data->transmit_mutex); + return; + } + + tcpci_src_emul_send_capability_msg_with_timer(data, common_data, 0); + + k_mutex_unlock(&common_data->transmit_mutex); +} + /** Check description in emul_tcpci_partner_src.h */ void tcpci_src_emul_hard_reset(void *data) { struct tcpci_src_emul_data *src_emul_data = data; - /* Send capability after 15 ms to establish PD again */ - tcpci_src_emul_send_capability_msg(src_emul_data, - src_emul_data->common_data, 15); + /* Send capability to establish PD again */ + tcpci_src_emul_send_capability_msg_with_timer( + src_emul_data, src_emul_data->common_data, 0); } /** @@ -176,6 +277,12 @@ static void tcpci_src_emul_rx_consumed_op( tcpci_partner_free_msg(msg); } +/** Check description in emul_tcpci_partner_src.h */ +void tcpci_src_emul_disconnect(struct tcpci_src_emul_data *data) +{ + tcpci_src_emul_stop_source_capability_timer(data); +} + /** * @brief Function called when emulator is disconnected from TCPCI * @@ -190,6 +297,7 @@ static void tcpci_src_emul_disconnect_op( CONTAINER_OF(ops, struct tcpci_src_emul, ops); tcpci_partner_common_disconnect(&src_emul->common_data); + tcpci_src_emul_disconnect(&src_emul->data); } /** Check description in emul_tcpci_partner_src.h */ @@ -209,8 +317,15 @@ int tcpci_src_emul_connect_to_tcpci(struct tcpci_src_emul_data *data, } common_data->tcpci_emul = tcpci_emul; - - return tcpci_src_emul_send_capability_msg(data, common_data, 0); + /* + * It is not required to wait on connection before sending source + * capabilities, but it is permit. Timeout is obligatory for power swap. + */ + tcpci_src_emul_send_capability_msg_with_timer( + data, data->common_data, + TCPCI_SWAP_SOURCE_START_TIMEOUT_MS); + + return 0; } #define PDO_FIXED_FLAGS_MASK \ @@ -322,6 +437,8 @@ void tcpci_src_emul_init_data(struct tcpci_src_emul_data *data, data->pdo[i] = 0; } + k_work_init_delayable(&data->source_capability_timeout, + tcpci_src_emul_source_capability_timeout); data->common_data = common_data; } |