diff options
| -rw-r--r-- | drivers/staging/typec/pd.h | 10 | ||||
| -rw-r--r-- | drivers/staging/typec/tcpm.c | 29 |
2 files changed, 39 insertions, 0 deletions
diff --git a/drivers/staging/typec/pd.h b/drivers/staging/typec/pd.h index 8d97bdb95f23..510ef7279900 100644 --- a/drivers/staging/typec/pd.h +++ b/drivers/staging/typec/pd.h | |||
| @@ -92,6 +92,16 @@ static inline unsigned int pd_header_type_le(__le16 header) | |||
| 92 | return pd_header_type(le16_to_cpu(header)); | 92 | return pd_header_type(le16_to_cpu(header)); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | static inline unsigned int pd_header_msgid(u16 header) | ||
| 96 | { | ||
| 97 | return (header >> PD_HEADER_ID_SHIFT) & PD_HEADER_ID_MASK; | ||
| 98 | } | ||
| 99 | |||
| 100 | static inline unsigned int pd_header_msgid_le(__le16 header) | ||
| 101 | { | ||
| 102 | return pd_header_msgid(le16_to_cpu(header)); | ||
| 103 | } | ||
| 104 | |||
| 95 | #define PD_MAX_PAYLOAD 7 | 105 | #define PD_MAX_PAYLOAD 7 |
| 96 | 106 | ||
| 97 | struct pd_message { | 107 | struct pd_message { |
diff --git a/drivers/staging/typec/tcpm.c b/drivers/staging/typec/tcpm.c index abba655ba00a..c5d8b129c4f4 100644 --- a/drivers/staging/typec/tcpm.c +++ b/drivers/staging/typec/tcpm.c | |||
| @@ -238,6 +238,7 @@ struct tcpm_port { | |||
| 238 | unsigned int hard_reset_count; | 238 | unsigned int hard_reset_count; |
| 239 | bool pd_capable; | 239 | bool pd_capable; |
| 240 | bool explicit_contract; | 240 | bool explicit_contract; |
| 241 | unsigned int rx_msgid; | ||
| 241 | 242 | ||
| 242 | /* Partner capabilities/requests */ | 243 | /* Partner capabilities/requests */ |
| 243 | u32 sink_request; | 244 | u32 sink_request; |
| @@ -1415,6 +1416,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, | |||
| 1415 | break; | 1416 | break; |
| 1416 | case SOFT_RESET_SEND: | 1417 | case SOFT_RESET_SEND: |
| 1417 | port->message_id = 0; | 1418 | port->message_id = 0; |
| 1419 | port->rx_msgid = -1; | ||
| 1418 | if (port->pwr_role == TYPEC_SOURCE) | 1420 | if (port->pwr_role == TYPEC_SOURCE) |
| 1419 | next_state = SRC_SEND_CAPABILITIES; | 1421 | next_state = SRC_SEND_CAPABILITIES; |
| 1420 | else | 1422 | else |
| @@ -1503,6 +1505,22 @@ static void tcpm_pd_rx_handler(struct work_struct *work) | |||
| 1503 | port->attached); | 1505 | port->attached); |
| 1504 | 1506 | ||
| 1505 | if (port->attached) { | 1507 | if (port->attached) { |
| 1508 | enum pd_ctrl_msg_type type = pd_header_type_le(msg->header); | ||
| 1509 | unsigned int msgid = pd_header_msgid_le(msg->header); | ||
| 1510 | |||
| 1511 | /* | ||
| 1512 | * USB PD standard, 6.6.1.2: | ||
| 1513 | * "... if MessageID value in a received Message is the | ||
| 1514 | * same as the stored value, the receiver shall return a | ||
| 1515 | * GoodCRC Message with that MessageID value and drop | ||
| 1516 | * the Message (this is a retry of an already received | ||
| 1517 | * Message). Note: this shall not apply to the Soft_Reset | ||
| 1518 | * Message which always has a MessageID value of zero." | ||
| 1519 | */ | ||
| 1520 | if (msgid == port->rx_msgid && type != PD_CTRL_SOFT_RESET) | ||
| 1521 | goto done; | ||
| 1522 | port->rx_msgid = msgid; | ||
| 1523 | |||
| 1506 | /* | 1524 | /* |
| 1507 | * If both ends believe to be DFP/host, we have a data role | 1525 | * If both ends believe to be DFP/host, we have a data role |
| 1508 | * mismatch. | 1526 | * mismatch. |
| @@ -1520,6 +1538,7 @@ static void tcpm_pd_rx_handler(struct work_struct *work) | |||
| 1520 | } | 1538 | } |
| 1521 | } | 1539 | } |
| 1522 | 1540 | ||
| 1541 | done: | ||
| 1523 | mutex_unlock(&port->lock); | 1542 | mutex_unlock(&port->lock); |
| 1524 | kfree(event); | 1543 | kfree(event); |
| 1525 | } | 1544 | } |
| @@ -1957,6 +1976,12 @@ static void tcpm_reset_port(struct tcpm_port *port) | |||
| 1957 | port->attached = false; | 1976 | port->attached = false; |
| 1958 | port->pd_capable = false; | 1977 | port->pd_capable = false; |
| 1959 | 1978 | ||
| 1979 | /* | ||
| 1980 | * First Rx ID should be 0; set this to a sentinel of -1 so that | ||
| 1981 | * we can check tcpm_pd_rx_handler() if we had seen it before. | ||
| 1982 | */ | ||
| 1983 | port->rx_msgid = -1; | ||
| 1984 | |||
| 1960 | port->tcpc->set_pd_rx(port->tcpc, false); | 1985 | port->tcpc->set_pd_rx(port->tcpc, false); |
| 1961 | tcpm_init_vbus(port); /* also disables charging */ | 1986 | tcpm_init_vbus(port); /* also disables charging */ |
| 1962 | tcpm_init_vconn(port); | 1987 | tcpm_init_vconn(port); |
| @@ -2170,6 +2195,7 @@ static void run_state_machine(struct tcpm_port *port) | |||
| 2170 | port->pwr_opmode = TYPEC_PWR_MODE_USB; | 2195 | port->pwr_opmode = TYPEC_PWR_MODE_USB; |
| 2171 | port->caps_count = 0; | 2196 | port->caps_count = 0; |
| 2172 | port->message_id = 0; | 2197 | port->message_id = 0; |
| 2198 | port->rx_msgid = -1; | ||
| 2173 | port->explicit_contract = false; | 2199 | port->explicit_contract = false; |
| 2174 | tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0); | 2200 | tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0); |
| 2175 | break; | 2201 | break; |
| @@ -2329,6 +2355,7 @@ static void run_state_machine(struct tcpm_port *port) | |||
| 2329 | typec_set_pwr_opmode(port->typec_port, TYPEC_PWR_MODE_USB); | 2355 | typec_set_pwr_opmode(port->typec_port, TYPEC_PWR_MODE_USB); |
| 2330 | port->pwr_opmode = TYPEC_PWR_MODE_USB; | 2356 | port->pwr_opmode = TYPEC_PWR_MODE_USB; |
| 2331 | port->message_id = 0; | 2357 | port->message_id = 0; |
| 2358 | port->rx_msgid = -1; | ||
| 2332 | port->explicit_contract = false; | 2359 | port->explicit_contract = false; |
| 2333 | tcpm_set_state(port, SNK_DISCOVERY, 0); | 2360 | tcpm_set_state(port, SNK_DISCOVERY, 0); |
| 2334 | break; | 2361 | break; |
| @@ -2496,6 +2523,7 @@ static void run_state_machine(struct tcpm_port *port) | |||
| 2496 | /* Soft_Reset states */ | 2523 | /* Soft_Reset states */ |
| 2497 | case SOFT_RESET: | 2524 | case SOFT_RESET: |
| 2498 | port->message_id = 0; | 2525 | port->message_id = 0; |
| 2526 | port->rx_msgid = -1; | ||
| 2499 | tcpm_pd_send_control(port, PD_CTRL_ACCEPT); | 2527 | tcpm_pd_send_control(port, PD_CTRL_ACCEPT); |
| 2500 | if (port->pwr_role == TYPEC_SOURCE) | 2528 | if (port->pwr_role == TYPEC_SOURCE) |
| 2501 | tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0); | 2529 | tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0); |
| @@ -2504,6 +2532,7 @@ static void run_state_machine(struct tcpm_port *port) | |||
| 2504 | break; | 2532 | break; |
| 2505 | case SOFT_RESET_SEND: | 2533 | case SOFT_RESET_SEND: |
| 2506 | port->message_id = 0; | 2534 | port->message_id = 0; |
| 2535 | port->rx_msgid = -1; | ||
| 2507 | if (tcpm_pd_send_control(port, PD_CTRL_SOFT_RESET)) | 2536 | if (tcpm_pd_send_control(port, PD_CTRL_SOFT_RESET)) |
| 2508 | tcpm_set_state_cond(port, hard_reset_state(port), 0); | 2537 | tcpm_set_state_cond(port, hard_reset_state(port), 0); |
| 2509 | else | 2538 | else |
