usb_c: Add super state to handle Sender Response Timer

Any Power Delivery message state that expects a reply must
start a sender response timer. This change addes a super
state that implements the Sender Response Timer
functionality, from which Power Deleiver messages states
can inherit from.

Signed-off-by: Sam Hurst <sbh1187@gmail.com>
This commit is contained in:
Sam Hurst 2023-01-11 09:28:26 -08:00 committed by Anas Nashif
parent 2b4a6e52d5
commit df117e563a
3 changed files with 100 additions and 125 deletions

View File

@ -654,6 +654,7 @@ static void pe_drs_send_swap_entry(void *obj)
/**
* @brief PE_DRS_Send_Swap Run state
* NOTE: Sender Response Timer is handled in super state.
*/
static void pe_drs_send_swap_run(void *obj)
{
@ -663,11 +664,6 @@ static void pe_drs_send_swap_run(void *obj)
struct protocol_layer_rx_t *prl_rx = data->prl_rx;
union pd_header header;
if (atomic_test_and_clear_bit(pe->flags, PE_FLAGS_TX_COMPLETE)) {
/* Start Sender Response Timer */
usbc_timer_start(&pe->pd_t_sender_response);
}
if (atomic_test_and_clear_bit(pe->flags, PE_FLAGS_MSG_RECEIVED)) {
header = prl_rx->emsg.header;
if (received_control_message(dev, header, PD_CTRL_REJECT)) {
@ -715,22 +711,16 @@ static void pe_drs_send_swap_run(void *obj)
pe_set_state(dev, PE_SNK_READY);
return;
}
/* Transition to PE_SNK_READY on SenderResponseTimer timeout */
if (usbc_timer_expired(&pe->pd_t_sender_response)) {
pe_set_state(dev, PE_SNK_READY);
}
}
/**
* @brief PE_DRS_Send_Swap Exit state
*/
static void pe_drs_send_swap_exit(void *obj)
static void pe_suspend_entry(void *obj)
{
struct policy_engine *pe = (struct policy_engine *)obj;
LOG_INF("PE_SUSPEND");
}
/* Stop Sender Response Timer */
usbc_timer_stop(&pe->pd_t_sender_response);
static void pe_suspend_run(void *obj)
{
/* DO NOTHING */
}
/**
@ -745,7 +735,7 @@ enum pe_soft_reset_submachine_states {
};
/**
* @brief 8.3.3.4.2.1 PE_SNK_Send_Soft_Reset State
* @brief 8.3.3.4.2.2 PE_SNK_Soft_Reset State
*/
static void pe_soft_reset_entry(void *obj)
{
@ -772,8 +762,6 @@ static void pe_soft_reset_run(void *obj)
case PE_SOFT_RESET_RUN_SEND_ACCEPT_MSG:
/* Send Accept message to SOP */
pe_send_ctrl_msg(dev, PD_PACKET_SOP, PD_CTRL_ACCEPT);
/* Start Sender Response Timer */
usbc_timer_start(&pe->pd_t_sender_response);
/* Move to next substate */
pe->submachine = PE_SOFT_RESET_RUN_SEND_ACCEPT_MSG_COMPLETE;
break;
@ -785,13 +773,11 @@ static void pe_soft_reset_run(void *obj)
*/
if (atomic_test_and_clear_bit(pe->flags, PE_FLAGS_TX_COMPLETE)) {
pe_set_state(dev, PE_SNK_WAIT_FOR_CAPABILITIES);
} else if (usbc_timer_expired(&pe->pd_t_sender_response) ||
atomic_test_and_clear_bit(pe->flags, PE_FLAGS_PROTOCOL_ERROR)) {
} else if (atomic_test_and_clear_bit(pe->flags, PE_FLAGS_PROTOCOL_ERROR)) {
/*
* The Policy Engine Shall transition to the
* PE_SRC_Hard_Reset state when:
* 1: A SenderResponseTimer timeout occurs.
* 2: OR the Protocol Layer indicates that a
* 1: Protocol Layer indicates that a
* transmission error has occurred.
*/
pe_set_state(dev, PE_SNK_HARD_RESET);
@ -800,16 +786,9 @@ static void pe_soft_reset_run(void *obj)
}
}
static void pe_soft_reset_exit(void *obj)
{
struct policy_engine *pe = (struct policy_engine *)obj;
/* Stop Sender Response Timer */
usbc_timer_stop(&pe->pd_t_sender_response);
}
/**
* @brief PE_Send_Soft_Reset Entry State
* NOTE: Sender Response Timer is handled in super state.
*/
static void pe_send_soft_reset_entry(void *obj)
{
@ -848,46 +827,27 @@ static void pe_send_soft_reset_run(void *obj)
/* Inform Device Policy Manager that the message was discarded */
policy_notify(dev, MSG_DISCARDED);
pe_set_state(dev, PE_SNK_READY);
} else if (atomic_test_and_clear_bit(pe->flags, PE_FLAGS_TX_COMPLETE)) {
/* Start SenderResponse timer */
usbc_timer_start(&pe->pd_t_sender_response);
}
/*
* The Policy Engine Shall transition to the PE_SNK_Wait_for_Capabilities
* state when:
* 1: An Accept Message has been received on SOP
*/
else if (atomic_test_and_clear_bit(pe->flags, PE_FLAGS_MSG_RECEIVED)) {
} else if (atomic_test_and_clear_bit(pe->flags, PE_FLAGS_MSG_RECEIVED)) {
/*
* The Policy Engine Shall transition to the PE_SNK_Wait_for_Capabilities
* state when:
* 1: An Accept Message has been received on SOP
*/
header = prl_rx->emsg.header;
if (received_control_message(dev, header, PD_CTRL_ACCEPT)) {
pe_set_state(dev, PE_SNK_WAIT_FOR_CAPABILITIES);
}
}
/*
* The Policy Engine Shall transition to the PE_SNK_Hard_Reset state when:
* 1: A SenderResponseTimer timeout occurs (Handled in pe_report_error function)
* 2: Or the Protocol Layer indicates that a transmission error has occurred
*/
else if (usbc_timer_expired(&pe->pd_t_sender_response) ||
atomic_test_and_clear_bit(pe->flags, PE_FLAGS_PROTOCOL_ERROR)) {
} else if (atomic_test_and_clear_bit(pe->flags, PE_FLAGS_PROTOCOL_ERROR)) {
/*
* The Policy Engine Shall transition to the PE_SNK_Hard_Reset state when:
* 1: A SenderResponseTimer timeout occurs (Handled in Super State)
* 2: Or the Protocol Layer indicates that a transmission error has occurred
*/
pe_set_state(dev, PE_SNK_HARD_RESET);
}
}
/**
* @brief PE_Send_Soft_Reset Exit State
*/
static void pe_send_soft_reset_exit(void *obj)
{
struct policy_engine *pe = (struct policy_engine *)obj;
/* Stop Sender Response Timer */
usbc_timer_stop(&pe->pd_t_sender_response);
}
/**
* @brief 8.3.3.6.2.1 PE_SNK_Send_Not_Supported State
*/
@ -956,23 +916,73 @@ static void pe_chunk_received_run(void *obj)
}
}
/**
* @brief Suspend State
/*
* @brief Super State for any message that requires
* Sender Response Timer functionality
*/
static void pe_suspend_entry(void *obj)
static void pe_sender_response_run(void *obj)
{
LOG_INF("PE_SUSPEND");
struct policy_engine *pe = (struct policy_engine *)obj;
const struct device *dev = pe->dev;
enum usbc_pe_state current_state = pe_get_state(dev);
/* Start the Sender Response Timer after the message is sent */
if (atomic_test_and_clear_bit(pe->flags, PE_FLAGS_TX_COMPLETE)) {
/* Start Sender Response Timer */
usbc_timer_start(&pe->pd_t_sender_response);
}
/* Check if the Sender Response Timer has expired */
if (usbc_timer_expired(&pe->pd_t_sender_response)) {
/*
* Handle Sender Response Timeouts
*/
switch (current_state) {
/* Sink states */
case PE_SNK_SELECT_CAPABILITY:
pe_set_state(dev, PE_SNK_HARD_RESET);
break;
case PE_SNK_GET_SOURCE_CAP:
pe_set_state(dev, PE_SNK_READY);
break;
/*
* Common states:
* Could transition to a Sink or Source states,
* depending on the current Data Role
*/
case PE_SEND_SOFT_RESET:
pe_set_state(dev, PE_SNK_HARD_RESET);
break;
case PE_DRS_SEND_SWAP:
pe_set_state(dev, PE_SNK_READY);
break;
/* This should not happen. Implementation error */
default:
LOG_INF("Unhandled Sender Response Timeout State!");
}
}
}
static void pe_suspend_run(void *obj)
static void pe_sender_response_exit(void *obj)
{
/* DO NOTHING */
struct policy_engine *pe = (struct policy_engine *)obj;
/* Stop Sender Response Timer */
usbc_timer_stop(&pe->pd_t_sender_response);
}
/**
* @brief Policy engine State table
*/
static const struct smf_state pe_states[] = {
/* PE Super States */
[PE_SENDER_RESPONSE_PARENT] = SMF_CREATE_STATE(
NULL,
pe_sender_response_run,
pe_sender_response_exit,
NULL),
[PE_SNK_STARTUP] = SMF_CREATE_STATE(
pe_snk_startup_entry,
pe_snk_startup_run,
@ -996,8 +1006,8 @@ static const struct smf_state pe_states[] = {
[PE_SNK_SELECT_CAPABILITY] = SMF_CREATE_STATE(
pe_snk_select_capability_entry,
pe_snk_select_capability_run,
pe_snk_select_capability_exit,
NULL),
NULL,
&pe_states[PE_SENDER_RESPONSE_PARENT]),
[PE_SNK_READY] = SMF_CREATE_STATE(
pe_snk_ready_entry,
pe_snk_ready_run,
@ -1021,27 +1031,22 @@ static const struct smf_state pe_states[] = {
[PE_SNK_GET_SOURCE_CAP] = SMF_CREATE_STATE(
pe_snk_get_source_cap_entry,
pe_snk_get_source_cap_run,
pe_snk_get_source_cap_exit,
NULL),
NULL,
&pe_states[PE_SENDER_RESPONSE_PARENT]),
[PE_SNK_TRANSITION_SINK] = SMF_CREATE_STATE(
pe_snk_transition_sink_entry,
pe_snk_transition_sink_run,
pe_snk_transition_sink_exit,
NULL),
[PE_SNK_GET_SOURCE_CAP] = SMF_CREATE_STATE(
pe_snk_get_source_cap_entry,
pe_snk_get_source_cap_run,
pe_snk_get_source_cap_exit,
NULL),
[PE_SEND_SOFT_RESET] = SMF_CREATE_STATE(
pe_send_soft_reset_entry,
pe_send_soft_reset_run,
pe_send_soft_reset_exit,
NULL),
NULL,
&pe_states[PE_SENDER_RESPONSE_PARENT]),
[PE_SOFT_RESET] = SMF_CREATE_STATE(
pe_soft_reset_entry,
pe_soft_reset_run,
pe_soft_reset_exit,
NULL,
NULL),
[PE_SEND_NOT_SUPPORTED] = SMF_CREATE_STATE(
pe_send_not_supported_entry,
@ -1056,8 +1061,8 @@ static const struct smf_state pe_states[] = {
[PE_DRS_SEND_SWAP] = SMF_CREATE_STATE(
pe_drs_send_swap_entry,
pe_drs_send_swap_run,
pe_drs_send_swap_exit,
NULL),
NULL,
&pe_states[PE_SENDER_RESPONSE_PARENT]),
[PE_CHUNK_RECEIVED] = SMF_CREATE_STATE(
pe_chunk_received_entry,
pe_chunk_received_run,

View File

@ -64,6 +64,14 @@ enum usbc_pe_state {
/** PE_Suspend. Not part of the PD specification. */
PE_SUSPEND,
/**
* NOTE: The states below should not be called directly. They're used
* internally by the state machine.
*/
/** PE_SENDER_RESPONSE_PARENT. Not part of the PD specification. */
PE_SENDER_RESPONSE_PARENT,
/** Number of PE States */
PE_STATE_COUNT
};

View File

@ -237,6 +237,7 @@ void pe_snk_select_capability_entry(void *obj)
/**
* @brief PE_SNK_Select_Capability Run State
* NOTE: Sender Response Timer is handled in super state.
*/
void pe_snk_select_capability_run(void *obj)
{
@ -259,9 +260,6 @@ void pe_snk_select_capability_run(void *obj)
} else {
pe_set_state(dev, PE_SNK_READY);
}
} else if (atomic_test_and_clear_bit(pe->flags, PE_FLAGS_TX_COMPLETE)) {
/* Start the SenderResponseTimer */
usbc_timer_start(&pe->pd_t_sender_response);
}
if (atomic_test_and_clear_bit(pe->flags, PE_FLAGS_MSG_RECEIVED)) {
@ -321,23 +319,6 @@ void pe_snk_select_capability_run(void *obj)
}
return;
}
/* When the SenderResponseTimer times out, perform a Hard Reset. */
if (usbc_timer_expired(&pe->pd_t_sender_response)) {
policy_notify(dev, PORT_PARTNER_NOT_RESPONSIVE);
pe_set_state(dev, PE_SNK_HARD_RESET);
}
}
/**
* @brief PE_SNK_Select_Capability Exit State
*/
void pe_snk_select_capability_exit(void *obj)
{
struct policy_engine *pe = (struct policy_engine *)obj;
/* Stop SenderResponse Timer */
usbc_timer_stop(&pe->pd_t_sender_response);
}
/**
@ -617,6 +598,7 @@ void pe_snk_transition_to_default_run(void *obj)
/**
* @brief PE_SNK_Get_Source_Cap Entry State
*
*/
void pe_snk_get_source_cap_entry(void *obj)
{
@ -636,6 +618,7 @@ void pe_snk_get_source_cap_entry(void *obj)
/**
* @brief PE_SNK_Get_Source_Cap Run State
* NOTE: Sender Response Timer is handled in super state.
*/
void pe_snk_get_source_cap_run(void *obj)
{
@ -646,10 +629,7 @@ void pe_snk_get_source_cap_run(void *obj)
union pd_header header;
/* Wait until message is sent or dropped */
if (atomic_test_and_clear_bit(pe->flags, PE_FLAGS_TX_COMPLETE)) {
/* The Policy Engine Shall then start the SenderResponseTimer. */
usbc_timer_start(&pe->pd_t_sender_response);
} else if (atomic_test_and_clear_bit(pe->flags, PE_FLAGS_MSG_RECEIVED)) {
if (atomic_test_and_clear_bit(pe->flags, PE_FLAGS_MSG_RECEIVED)) {
/*
* The Policy Engine Shall transition to the PE_SNK_Evaluate_Capability
* State when:
@ -661,27 +641,9 @@ void pe_snk_get_source_cap_run(void *obj)
if (received_control_message(dev, header, PD_DATA_SOURCE_CAP)) {
pe_set_state(dev, PE_SNK_EVALUATE_CAPABILITY);
}
} else if (usbc_timer_expired(&pe->pd_t_sender_response)) {
/*
* The Policy Engine Shall transition to the PE_SNK_Ready state when:
* 1: The SenderResponseTimer times out.
*/
pe_set_state(dev, PE_SNK_READY);
/* Inform the DPM of the sender response timeout */
policy_notify(dev, SENDER_RESPONSE_TIMEOUT);
}
}
/**
* @brief PE_SNK_Get_Source_Cap Exit State
*/
void pe_snk_get_source_cap_exit(void *obj)
{
struct policy_engine *pe = (struct policy_engine *)obj;
usbc_timer_stop(&pe->pd_t_sender_response);
}
/**
* @brief PE_SNK_Give_Sink_Cap Entry state
*/