mirror of
https://github.com/torvalds/linux.git
synced 2024-12-02 00:51:44 +00:00
usb: typec: tcpm: Properly handle Alert and Status Messages
When receiving Alert Message, if it is not unexpected but is unsupported for some reason, the port should return Not_Supported Message response. Also, according to PD3.0 Spec 6.5.2.1.4 Event Flags Field, the OTP/OVP/OCP flags in the Event Flags field in Status Message no longer require Get_PPS_Status Message to clear them. Thus remove it when receiving Status Message with those flags being set. In addition, add the missing AMS operations for Status Message. Fixes:64f7c494a3
("typec: tcpm: Add support for sink PPS related messages") Fixes:0908c5aca3
("usb: typec: tcpm: AMS and Collision Avoidance") Signed-off-by: Kyle Tso <kyletso@google.com> Link: https://lore.kernel.org/r/20210531164928.2368606-1-kyletso@google.com Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
4d2aa178d2
commit
063933f47a
@ -2188,20 +2188,25 @@ static void tcpm_handle_alert(struct tcpm_port *port, const __le32 *payload,
|
|||||||
|
|
||||||
if (!type) {
|
if (!type) {
|
||||||
tcpm_log(port, "Alert message received with no type");
|
tcpm_log(port, "Alert message received with no type");
|
||||||
|
tcpm_queue_message(port, PD_MSG_CTRL_NOT_SUPP);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Just handling non-battery alerts for now */
|
/* Just handling non-battery alerts for now */
|
||||||
if (!(type & USB_PD_ADO_TYPE_BATT_STATUS_CHANGE)) {
|
if (!(type & USB_PD_ADO_TYPE_BATT_STATUS_CHANGE)) {
|
||||||
switch (port->state) {
|
if (port->pwr_role == TYPEC_SOURCE) {
|
||||||
case SRC_READY:
|
port->upcoming_state = GET_STATUS_SEND;
|
||||||
case SNK_READY:
|
tcpm_ams_start(port, GETTING_SOURCE_SINK_STATUS);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Do not check SinkTxOk here in case the Source doesn't set its Rp to
|
||||||
|
* SinkTxOk in time.
|
||||||
|
*/
|
||||||
|
port->ams = GETTING_SOURCE_SINK_STATUS;
|
||||||
tcpm_set_state(port, GET_STATUS_SEND, 0);
|
tcpm_set_state(port, GET_STATUS_SEND, 0);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
tcpm_queue_message(port, PD_MSG_CTRL_WAIT);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
tcpm_queue_message(port, PD_MSG_CTRL_NOT_SUPP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2445,6 +2450,11 @@ static void tcpm_pd_data_request(struct tcpm_port *port,
|
|||||||
tcpm_pd_handle_state(port, BIST_RX, BIST, 0);
|
tcpm_pd_handle_state(port, BIST_RX, BIST, 0);
|
||||||
break;
|
break;
|
||||||
case PD_DATA_ALERT:
|
case PD_DATA_ALERT:
|
||||||
|
if (port->state != SRC_READY && port->state != SNK_READY)
|
||||||
|
tcpm_pd_handle_state(port, port->pwr_role == TYPEC_SOURCE ?
|
||||||
|
SRC_SOFT_RESET_WAIT_SNK_TX : SNK_SOFT_RESET,
|
||||||
|
NONE_AMS, 0);
|
||||||
|
else
|
||||||
tcpm_handle_alert(port, msg->payload, cnt);
|
tcpm_handle_alert(port, msg->payload, cnt);
|
||||||
break;
|
break;
|
||||||
case PD_DATA_BATT_STATUS:
|
case PD_DATA_BATT_STATUS:
|
||||||
@ -2769,24 +2779,16 @@ static void tcpm_pd_ext_msg_request(struct tcpm_port *port,
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case PD_EXT_STATUS:
|
case PD_EXT_STATUS:
|
||||||
/*
|
|
||||||
* If PPS related events raised then get PPS status to clear
|
|
||||||
* (see USB PD 3.0 Spec, 6.5.2.4)
|
|
||||||
*/
|
|
||||||
if (msg->ext_msg.data[USB_PD_EXT_SDB_EVENT_FLAGS] &
|
|
||||||
USB_PD_EXT_SDB_PPS_EVENTS)
|
|
||||||
tcpm_pd_handle_state(port, GET_PPS_STATUS_SEND,
|
|
||||||
GETTING_SOURCE_SINK_STATUS, 0);
|
|
||||||
|
|
||||||
else
|
|
||||||
tcpm_pd_handle_state(port, ready_state(port), NONE_AMS, 0);
|
|
||||||
break;
|
|
||||||
case PD_EXT_PPS_STATUS:
|
case PD_EXT_PPS_STATUS:
|
||||||
/*
|
if (port->ams == GETTING_SOURCE_SINK_STATUS) {
|
||||||
* For now the PPS status message is used to clear events
|
tcpm_ams_finish(port);
|
||||||
* and nothing more.
|
tcpm_set_state(port, ready_state(port), 0);
|
||||||
*/
|
} else {
|
||||||
tcpm_pd_handle_state(port, ready_state(port), NONE_AMS, 0);
|
/* unexpected Status or PPS_Status Message */
|
||||||
|
tcpm_pd_handle_state(port, port->pwr_role == TYPEC_SOURCE ?
|
||||||
|
SRC_SOFT_RESET_WAIT_SNK_TX : SNK_SOFT_RESET,
|
||||||
|
NONE_AMS, 0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case PD_EXT_SOURCE_CAP_EXT:
|
case PD_EXT_SOURCE_CAP_EXT:
|
||||||
case PD_EXT_GET_BATT_CAP:
|
case PD_EXT_GET_BATT_CAP:
|
||||||
|
@ -24,8 +24,4 @@ enum usb_pd_ext_sdb_fields {
|
|||||||
#define USB_PD_EXT_SDB_EVENT_OVP BIT(3)
|
#define USB_PD_EXT_SDB_EVENT_OVP BIT(3)
|
||||||
#define USB_PD_EXT_SDB_EVENT_CF_CV_MODE BIT(4)
|
#define USB_PD_EXT_SDB_EVENT_CF_CV_MODE BIT(4)
|
||||||
|
|
||||||
#define USB_PD_EXT_SDB_PPS_EVENTS (USB_PD_EXT_SDB_EVENT_OCP | \
|
|
||||||
USB_PD_EXT_SDB_EVENT_OTP | \
|
|
||||||
USB_PD_EXT_SDB_EVENT_OVP)
|
|
||||||
|
|
||||||
#endif /* __LINUX_USB_PD_EXT_SDB_H */
|
#endif /* __LINUX_USB_PD_EXT_SDB_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user