Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: typec: tcpm: Protocol Error handling

PD3.0 Spec 6.8.1 describes how to handle Protocol Error. There are
general rules defined in Table 6-61 which regulate incoming Message
handling. If the incoming Message is unexpected, unsupported, or
unrecognized, Protocol Error occurs. Follow the rules to handle these
situations. Also consider PD2.0 connection (PD2.0 Spec Table 6-36) for
backward compatibilities.

To know the types of AMS in all the recipient's states, identify those
AMS who are initiated by the port partner but not yet recorded in the
current code.

Besides, introduce a new state CHUNK_NOT_SUPP to delay the NOT_SUPPORTED
message after receiving a chunked message.

Tested-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Kyle Tso <kyletso@google.com>
Link: https://lore.kernel.org/r/20210114145053.1952756-3-kyletso@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Kyle Tso and committed by
Greg Kroah-Hartman
8dea75e1 0908c5ac

+246 -90
+245 -90
drivers/usb/typec/tcpm/tcpm.c
··· 143 143 S(PORT_RESET), \ 144 144 S(PORT_RESET_WAIT_OFF), \ 145 145 \ 146 - S(AMS_START) 146 + S(AMS_START), \ 147 + S(CHUNK_NOT_SUPP) 147 148 148 149 #define FOREACH_AMS(S) \ 149 150 S(NONE_AMS), \ ··· 434 433 /* Collision Avoidance and Atomic Message Sequence */ 435 434 enum tcpm_state upcoming_state; 436 435 enum tcpm_ams ams; 436 + enum tcpm_ams next_ams; 437 437 bool in_ams; 438 438 439 439 #ifdef CONFIG_DEBUG_FS ··· 1215 1213 1216 1214 tcpm_log(port, "AMS %s start", tcpm_ams_str[ams]); 1217 1215 1218 - if (!tcpm_ams_interruptible(port) && ams != HARD_RESET) { 1216 + if (!tcpm_ams_interruptible(port) && 1217 + !(ams == HARD_RESET || ams == SOFT_RESET_AMS)) { 1219 1218 port->upcoming_state = INVALID_STATE; 1220 1219 tcpm_log(port, "AMS %s not interruptible, aborting", 1221 1220 tcpm_ams_str[port->ams]); ··· 1234 1231 tcpm_set_state(port, HARD_RESET_START, 0); 1235 1232 return ret; 1236 1233 } else if (ams == SOFT_RESET_AMS) { 1237 - if (!port->explicit_contract) { 1238 - port->upcoming_state = INVALID_STATE; 1234 + if (!port->explicit_contract) 1239 1235 tcpm_set_cc(port, tcpm_rp_cc(port)); 1240 - return ret; 1241 - } 1236 + tcpm_set_state(port, SOFT_RESET_SEND, 0); 1237 + return ret; 1242 1238 } else if (tcpm_vdm_ams(port)) { 1243 1239 /* tSinkTx is enforced in vdm_run_state_machine */ 1244 1240 if (port->negotiated_rev >= PD_REV30) ··· 1454 1452 case CMDT_INIT: 1455 1453 switch (cmd) { 1456 1454 case CMD_DISCOVER_IDENT: 1455 + if (PD_VDO_VID(p[0]) != USB_SID_PD) 1456 + break; 1457 + 1457 1458 /* 6.4.4.3.1: Only respond as UFP (device) */ 1458 1459 if (port->data_role == TYPEC_DEVICE && 1459 1460 port->nr_snk_vdo) { ··· 1542 1537 return 0; 1543 1538 } 1544 1539 break; 1540 + case VDO_CMD_VENDOR(0) ... VDO_CMD_VENDOR(15): 1541 + break; 1545 1542 default: 1543 + /* Unrecognized SVDM */ 1544 + response[0] = p[0] | VDO_CMDT(CMDT_RSP_NAK); 1545 + rlen = 1; 1546 1546 break; 1547 1547 } 1548 1548 break; 1549 1549 case CMDT_RSP_NAK: 1550 1550 tcpm_ams_finish(port); 1551 1551 switch (cmd) { 1552 + case CMD_DISCOVER_IDENT: 1553 + case CMD_DISCOVER_SVID: 1554 + case CMD_DISCOVER_MODES: 1555 + case VDO_CMD_VENDOR(0) ... VDO_CMD_VENDOR(15): 1556 + break; 1552 1557 case CMD_ENTER_MODE: 1553 1558 /* Back to USB Operation */ 1554 1559 *adev_action = ADEV_NOTIFY_USB_AND_QUEUE_VDM; 1555 1560 return 0; 1556 1561 default: 1562 + /* Unrecognized SVDM */ 1563 + response[0] = p[0] | VDO_CMDT(CMDT_RSP_NAK); 1564 + rlen = 1; 1557 1565 break; 1558 1566 } 1559 1567 break; 1560 1568 default: 1569 + response[0] = p[0] | VDO_CMDT(CMDT_RSP_NAK); 1570 + rlen = 1; 1561 1571 break; 1562 1572 } 1563 1573 ··· 1608 1588 port->vdm_state = VDM_STATE_DONE; 1609 1589 } 1610 1590 1611 - if (PD_VDO_SVDM(p[0])) 1591 + if (PD_VDO_SVDM(p[0])) { 1612 1592 rlen = tcpm_pd_svdm(port, adev, p, cnt, response, &adev_action); 1593 + } else { 1594 + if (port->negotiated_rev >= PD_REV30) 1595 + tcpm_queue_message(port, PD_MSG_CTRL_NOT_SUPP); 1596 + } 1613 1597 1614 1598 /* 1615 1599 * We are done with any state stored in the port struct now, except ··· 2063 2039 return ret; 2064 2040 } 2065 2041 2042 + static void tcpm_pd_handle_state(struct tcpm_port *port, 2043 + enum tcpm_state state, 2044 + enum tcpm_ams ams, 2045 + unsigned int delay_ms) 2046 + { 2047 + switch (port->state) { 2048 + case SRC_READY: 2049 + case SNK_READY: 2050 + port->ams = ams; 2051 + tcpm_set_state(port, state, delay_ms); 2052 + break; 2053 + /* 8.3.3.4.1.1 and 6.8.1 power transitioning */ 2054 + case SNK_TRANSITION_SINK: 2055 + case SNK_TRANSITION_SINK_VBUS: 2056 + case SRC_TRANSITION_SUPPLY: 2057 + tcpm_set_state(port, HARD_RESET_SEND, 0); 2058 + break; 2059 + default: 2060 + if (!tcpm_ams_interruptible(port)) { 2061 + tcpm_set_state(port, port->pwr_role == TYPEC_SOURCE ? 2062 + SRC_SOFT_RESET_WAIT_SNK_TX : 2063 + SNK_SOFT_RESET, 2064 + 0); 2065 + } else { 2066 + /* process the Message 6.8.1 */ 2067 + port->upcoming_state = state; 2068 + port->next_ams = ams; 2069 + tcpm_set_state(port, ready_state(port), delay_ms); 2070 + } 2071 + break; 2072 + } 2073 + } 2074 + 2075 + static void tcpm_pd_handle_msg(struct tcpm_port *port, 2076 + enum pd_msg_request message, 2077 + enum tcpm_ams ams) 2078 + { 2079 + switch (port->state) { 2080 + case SRC_READY: 2081 + case SNK_READY: 2082 + port->ams = ams; 2083 + tcpm_queue_message(port, message); 2084 + break; 2085 + /* PD 3.0 Spec 8.3.3.4.1.1 and 6.8.1 */ 2086 + case SNK_TRANSITION_SINK: 2087 + case SNK_TRANSITION_SINK_VBUS: 2088 + case SRC_TRANSITION_SUPPLY: 2089 + tcpm_set_state(port, HARD_RESET_SEND, 0); 2090 + break; 2091 + default: 2092 + if (!tcpm_ams_interruptible(port)) { 2093 + tcpm_set_state(port, port->pwr_role == TYPEC_SOURCE ? 2094 + SRC_SOFT_RESET_WAIT_SNK_TX : 2095 + SNK_SOFT_RESET, 2096 + 0); 2097 + } else { 2098 + port->next_ams = ams; 2099 + tcpm_set_state(port, ready_state(port), 0); 2100 + /* 6.8.1 process the Message */ 2101 + tcpm_queue_message(port, message); 2102 + } 2103 + break; 2104 + } 2105 + } 2106 + 2066 2107 static void tcpm_pd_data_request(struct tcpm_port *port, 2067 2108 const struct pd_message *msg) 2068 2109 { ··· 2141 2052 2142 2053 switch (type) { 2143 2054 case PD_DATA_SOURCE_CAP: 2144 - if (port->pwr_role != TYPEC_SINK) 2145 - break; 2146 - 2147 2055 for (i = 0; i < cnt; i++) 2148 2056 port->source_caps[i] = le32_to_cpu(msg->payload[i]); 2149 2057 ··· 2156 2070 * to comply with 6.2.1.1.5 of the USB PD 3.0 spec. We don't 2157 2071 * support Rev 1.0 so just do nothing in that scenario. 2158 2072 */ 2159 - if (rev == PD_REV10) 2073 + if (rev == PD_REV10) { 2074 + if (port->ams == GET_SOURCE_CAPABILITIES) 2075 + tcpm_ams_finish(port); 2160 2076 break; 2077 + } 2161 2078 2162 2079 if (rev < PD_MAX_REV) 2163 2080 port->negotiated_rev = rev; 2164 2081 2082 + if (port->pwr_role == TYPEC_SOURCE) { 2083 + if (port->ams == GET_SOURCE_CAPABILITIES) 2084 + tcpm_pd_handle_state(port, SRC_READY, NONE_AMS, 0); 2085 + /* Unexpected Source Capabilities */ 2086 + else 2087 + tcpm_pd_handle_msg(port, 2088 + port->negotiated_rev < PD_REV30 ? 2089 + PD_MSG_CTRL_REJECT : 2090 + PD_MSG_CTRL_NOT_SUPP, 2091 + NONE_AMS); 2092 + } else if (port->state == SNK_WAIT_CAPABILITIES) { 2165 2093 /* 2166 2094 * This message may be received even if VBUS is not 2167 2095 * present. This is quite unexpected; see USB PD ··· 2189 2089 * but be prepared to keep waiting for VBUS after it was 2190 2090 * handled. 2191 2091 */ 2192 - tcpm_set_state(port, SNK_NEGOTIATE_CAPABILITIES, 0); 2092 + port->ams = POWER_NEGOTIATION; 2093 + tcpm_set_state(port, SNK_NEGOTIATE_CAPABILITIES, 0); 2094 + } else { 2095 + if (port->ams == GET_SOURCE_CAPABILITIES) 2096 + tcpm_ams_finish(port); 2097 + tcpm_pd_handle_state(port, SNK_NEGOTIATE_CAPABILITIES, 2098 + POWER_NEGOTIATION, 0); 2099 + } 2193 2100 break; 2194 2101 case PD_DATA_REQUEST: 2195 - if (port->pwr_role != TYPEC_SOURCE || 2196 - cnt != 1) { 2197 - tcpm_queue_message(port, PD_MSG_CTRL_REJECT); 2198 - break; 2199 - } 2200 - 2201 2102 /* 2202 2103 * Adjust revision in subsequent message headers, as required, 2203 2104 * to comply with 6.2.1.1.5 of the USB PD 3.0 spec. We don't 2204 2105 * support Rev 1.0 so just reject in that scenario. 2205 2106 */ 2206 2107 if (rev == PD_REV10) { 2207 - tcpm_queue_message(port, PD_MSG_CTRL_REJECT); 2108 + tcpm_pd_handle_msg(port, 2109 + port->negotiated_rev < PD_REV30 ? 2110 + PD_MSG_CTRL_REJECT : 2111 + PD_MSG_CTRL_NOT_SUPP, 2112 + NONE_AMS); 2208 2113 break; 2209 2114 } 2210 2115 2211 2116 if (rev < PD_MAX_REV) 2212 2117 port->negotiated_rev = rev; 2213 2118 2119 + if (port->pwr_role != TYPEC_SOURCE || cnt != 1) { 2120 + tcpm_pd_handle_msg(port, 2121 + port->negotiated_rev < PD_REV30 ? 2122 + PD_MSG_CTRL_REJECT : 2123 + PD_MSG_CTRL_NOT_SUPP, 2124 + NONE_AMS); 2125 + break; 2126 + } 2127 + 2214 2128 port->sink_request = le32_to_cpu(msg->payload[0]); 2215 - tcpm_set_state(port, SRC_NEGOTIATE_CAPABILITIES, 0); 2129 + if (port->state == SRC_SEND_CAPABILITIES) 2130 + tcpm_set_state(port, SRC_NEGOTIATE_CAPABILITIES, 0); 2131 + else 2132 + tcpm_pd_handle_state(port, SRC_NEGOTIATE_CAPABILITIES, 2133 + POWER_NEGOTIATION, 0); 2216 2134 break; 2217 2135 case PD_DATA_SINK_CAP: 2218 2136 /* We don't do anything with this at the moment... */ ··· 2251 2133 2252 2134 port->nr_sink_caps = cnt; 2253 2135 port->sink_cap_done = true; 2254 - tcpm_set_state(port, SNK_READY, 0); 2136 + if (port->ams == GET_SINK_CAPABILITIES) 2137 + tcpm_pd_handle_state(port, ready_state(port), NONE_AMS, 0); 2138 + /* Unexpected Sink Capabilities */ 2139 + else 2140 + tcpm_pd_handle_msg(port, 2141 + port->negotiated_rev < PD_REV30 ? 2142 + PD_MSG_CTRL_REJECT : 2143 + PD_MSG_CTRL_NOT_SUPP, 2144 + NONE_AMS); 2255 2145 break; 2256 2146 case PD_DATA_VENDOR_DEF: 2257 2147 tcpm_handle_vdm_request(port, msg->payload, cnt); 2258 2148 break; 2259 2149 case PD_DATA_BIST: 2260 - if (port->state == SRC_READY || port->state == SNK_READY) { 2261 - port->bist_request = le32_to_cpu(msg->payload[0]); 2262 - tcpm_set_state(port, BIST_RX, 0); 2263 - } 2150 + port->bist_request = le32_to_cpu(msg->payload[0]); 2151 + tcpm_pd_handle_state(port, BIST_RX, BIST, 0); 2264 2152 break; 2265 2153 case PD_DATA_ALERT: 2266 2154 tcpm_handle_alert(port, msg->payload, cnt); ··· 2274 2150 case PD_DATA_BATT_STATUS: 2275 2151 case PD_DATA_GET_COUNTRY_INFO: 2276 2152 /* Currently unsupported */ 2277 - tcpm_queue_message(port, PD_MSG_CTRL_NOT_SUPP); 2153 + tcpm_pd_handle_msg(port, port->negotiated_rev < PD_REV30 ? 2154 + PD_MSG_CTRL_REJECT : 2155 + PD_MSG_CTRL_NOT_SUPP, 2156 + NONE_AMS); 2278 2157 break; 2279 2158 default: 2280 - tcpm_log(port, "Unhandled data message type %#x", type); 2159 + tcpm_pd_handle_msg(port, port->negotiated_rev < PD_REV30 ? 2160 + PD_MSG_CTRL_REJECT : 2161 + PD_MSG_CTRL_NOT_SUPP, 2162 + NONE_AMS); 2163 + tcpm_log(port, "Unrecognized data message type %#x", type); 2281 2164 break; 2282 2165 } 2283 2166 } ··· 2309 2178 case PD_CTRL_PING: 2310 2179 break; 2311 2180 case PD_CTRL_GET_SOURCE_CAP: 2312 - switch (port->state) { 2313 - case SRC_READY: 2314 - case SNK_READY: 2315 - tcpm_queue_message(port, PD_MSG_DATA_SOURCE_CAP); 2316 - break; 2317 - default: 2318 - tcpm_queue_message(port, PD_MSG_CTRL_REJECT); 2319 - break; 2320 - } 2181 + tcpm_pd_handle_msg(port, PD_MSG_DATA_SOURCE_CAP, GET_SOURCE_CAPABILITIES); 2321 2182 break; 2322 2183 case PD_CTRL_GET_SINK_CAP: 2323 - switch (port->state) { 2324 - case SRC_READY: 2325 - case SNK_READY: 2326 - tcpm_queue_message(port, PD_MSG_DATA_SINK_CAP); 2327 - break; 2328 - default: 2329 - tcpm_queue_message(port, PD_MSG_CTRL_REJECT); 2330 - break; 2331 - } 2184 + tcpm_pd_handle_msg(port, PD_MSG_DATA_SINK_CAP, GET_SINK_CAPABILITIES); 2332 2185 break; 2333 2186 case PD_CTRL_GOTO_MIN: 2334 2187 break; ··· 2351 2236 tcpm_set_state(port, FR_SWAP_SNK_SRC_NEW_SINK_READY, 0); 2352 2237 break; 2353 2238 default: 2239 + tcpm_pd_handle_state(port, 2240 + port->pwr_role == TYPEC_SOURCE ? 2241 + SRC_SOFT_RESET_WAIT_SNK_TX : 2242 + SNK_SOFT_RESET, 2243 + NONE_AMS, 0); 2354 2244 break; 2355 2245 } 2356 2246 break; ··· 2402 2282 tcpm_set_state(port, ready_state(port), 0); 2403 2283 break; 2404 2284 default: 2285 + tcpm_pd_handle_state(port, 2286 + port->pwr_role == TYPEC_SOURCE ? 2287 + SRC_SOFT_RESET_WAIT_SNK_TX : 2288 + SNK_SOFT_RESET, 2289 + NONE_AMS, 0); 2405 2290 break; 2406 2291 } 2407 2292 break; ··· 2423 2298 tcpm_set_state(port, SNK_TRANSITION_SINK, 0); 2424 2299 break; 2425 2300 case SOFT_RESET_SEND: 2426 - port->message_id = 0; 2427 - port->rx_msgid = -1; 2428 2301 if (port->ams == SOFT_RESET_AMS) 2429 2302 tcpm_ams_finish(port); 2430 2303 if (port->pwr_role == TYPEC_SOURCE) { ··· 2445 2322 tcpm_set_state(port, FR_SWAP_SNK_SRC_TRANSITION_TO_OFF, 0); 2446 2323 break; 2447 2324 default: 2325 + tcpm_pd_handle_state(port, 2326 + port->pwr_role == TYPEC_SOURCE ? 2327 + SRC_SOFT_RESET_WAIT_SNK_TX : 2328 + SNK_SOFT_RESET, 2329 + NONE_AMS, 0); 2448 2330 break; 2449 2331 } 2450 2332 break; 2451 2333 case PD_CTRL_SOFT_RESET: 2334 + port->ams = SOFT_RESET_AMS; 2452 2335 tcpm_set_state(port, SOFT_RESET, 0); 2453 2336 break; 2454 2337 case PD_CTRL_DR_SWAP: 2455 - if (port->typec_caps.data != TYPEC_PORT_DRD) { 2456 - tcpm_queue_message(port, PD_MSG_CTRL_REJECT); 2457 - break; 2458 - } 2459 2338 /* 2460 2339 * XXX 2461 2340 * 6.3.9: If an alternate mode is active, a request to swap 2462 2341 * alternate modes shall trigger a port reset. 2463 2342 */ 2464 - switch (port->state) { 2465 - case SRC_READY: 2466 - case SNK_READY: 2467 - tcpm_set_state(port, DR_SWAP_ACCEPT, 0); 2468 - break; 2469 - default: 2470 - tcpm_queue_message(port, PD_MSG_CTRL_WAIT); 2471 - break; 2472 - } 2343 + if (port->typec_caps.data != TYPEC_PORT_DRD) 2344 + tcpm_pd_handle_msg(port, 2345 + port->negotiated_rev < PD_REV30 ? 2346 + PD_MSG_CTRL_REJECT : 2347 + PD_MSG_CTRL_NOT_SUPP, 2348 + NONE_AMS); 2349 + else 2350 + tcpm_pd_handle_state(port, DR_SWAP_ACCEPT, DATA_ROLE_SWAP, 0); 2473 2351 break; 2474 2352 case PD_CTRL_PR_SWAP: 2475 - if (port->port_type != TYPEC_PORT_DRP) { 2476 - tcpm_queue_message(port, PD_MSG_CTRL_REJECT); 2477 - break; 2478 - } 2479 - switch (port->state) { 2480 - case SRC_READY: 2481 - case SNK_READY: 2482 - tcpm_set_state(port, PR_SWAP_ACCEPT, 0); 2483 - break; 2484 - default: 2485 - tcpm_queue_message(port, PD_MSG_CTRL_WAIT); 2486 - break; 2487 - } 2353 + if (port->port_type != TYPEC_PORT_DRP) 2354 + tcpm_pd_handle_msg(port, 2355 + port->negotiated_rev < PD_REV30 ? 2356 + PD_MSG_CTRL_REJECT : 2357 + PD_MSG_CTRL_NOT_SUPP, 2358 + NONE_AMS); 2359 + else 2360 + tcpm_pd_handle_state(port, PR_SWAP_ACCEPT, POWER_ROLE_SWAP, 0); 2488 2361 break; 2489 2362 case PD_CTRL_VCONN_SWAP: 2490 - switch (port->state) { 2491 - case SRC_READY: 2492 - case SNK_READY: 2493 - tcpm_set_state(port, VCONN_SWAP_ACCEPT, 0); 2494 - break; 2495 - default: 2496 - tcpm_queue_message(port, PD_MSG_CTRL_WAIT); 2497 - break; 2498 - } 2363 + tcpm_pd_handle_state(port, VCONN_SWAP_ACCEPT, VCONN_SWAP, 0); 2499 2364 break; 2500 2365 case PD_CTRL_GET_SOURCE_CAP_EXT: 2501 2366 case PD_CTRL_GET_STATUS: ··· 2491 2380 case PD_CTRL_GET_PPS_STATUS: 2492 2381 case PD_CTRL_GET_COUNTRY_CODES: 2493 2382 /* Currently not supported */ 2494 - tcpm_queue_message(port, PD_MSG_CTRL_NOT_SUPP); 2383 + tcpm_pd_handle_msg(port, 2384 + port->negotiated_rev < PD_REV30 ? 2385 + PD_MSG_CTRL_REJECT : 2386 + PD_MSG_CTRL_NOT_SUPP, 2387 + NONE_AMS); 2495 2388 break; 2496 2389 default: 2497 - tcpm_log(port, "Unhandled ctrl message type %#x", type); 2390 + tcpm_pd_handle_msg(port, 2391 + port->negotiated_rev < PD_REV30 ? 2392 + PD_MSG_CTRL_REJECT : 2393 + PD_MSG_CTRL_NOT_SUPP, 2394 + NONE_AMS); 2395 + tcpm_log(port, "Unrecognized ctrl message type %#x", type); 2498 2396 break; 2499 2397 } 2500 2398 } ··· 2515 2395 unsigned int data_size = pd_ext_header_data_size_le(msg->ext_msg.header); 2516 2396 2517 2397 if (!(msg->ext_msg.header & PD_EXT_HDR_CHUNKED)) { 2398 + tcpm_pd_handle_msg(port, PD_MSG_CTRL_NOT_SUPP, NONE_AMS); 2518 2399 tcpm_log(port, "Unchunked extended messages unsupported"); 2519 2400 return; 2520 2401 } 2521 2402 2522 2403 if (data_size > PD_EXT_MAX_CHUNK_DATA) { 2404 + tcpm_pd_handle_state(port, CHUNK_NOT_SUPP, NONE_AMS, PD_T_CHUNK_NOT_SUPP); 2523 2405 tcpm_log(port, "Chunk handling not yet supported"); 2524 2406 return; 2525 2407 } ··· 2534 2412 */ 2535 2413 if (msg->ext_msg.data[USB_PD_EXT_SDB_EVENT_FLAGS] & 2536 2414 USB_PD_EXT_SDB_PPS_EVENTS) 2537 - tcpm_set_state(port, GET_PPS_STATUS_SEND, 0); 2415 + tcpm_pd_handle_state(port, GET_PPS_STATUS_SEND, 2416 + GETTING_SOURCE_SINK_STATUS, 0); 2417 + 2538 2418 else 2539 - tcpm_set_state(port, ready_state(port), 0); 2419 + tcpm_pd_handle_state(port, ready_state(port), NONE_AMS, 0); 2540 2420 break; 2541 2421 case PD_EXT_PPS_STATUS: 2542 2422 /* 2543 2423 * For now the PPS status message is used to clear events 2544 2424 * and nothing more. 2545 2425 */ 2546 - tcpm_set_state(port, ready_state(port), 0); 2426 + tcpm_pd_handle_state(port, ready_state(port), NONE_AMS, 0); 2547 2427 break; 2548 2428 case PD_EXT_SOURCE_CAP_EXT: 2549 2429 case PD_EXT_GET_BATT_CAP: ··· 2559 2435 case PD_EXT_FW_UPDATE_RESPONSE: 2560 2436 case PD_EXT_COUNTRY_INFO: 2561 2437 case PD_EXT_COUNTRY_CODES: 2562 - tcpm_queue_message(port, PD_MSG_CTRL_NOT_SUPP); 2438 + tcpm_pd_handle_msg(port, PD_MSG_CTRL_NOT_SUPP, NONE_AMS); 2563 2439 break; 2564 2440 default: 2565 - tcpm_log(port, "Unhandled extended message type %#x", type); 2441 + tcpm_pd_handle_msg(port, PD_MSG_CTRL_NOT_SUPP, NONE_AMS); 2442 + tcpm_log(port, "Unrecognized extended message type %#x", type); 2566 2443 break; 2567 2444 } 2568 2445 } ··· 2676 2551 tcpm_pd_send_control(port, PD_CTRL_NOT_SUPP); 2677 2552 break; 2678 2553 case PD_MSG_DATA_SINK_CAP: 2679 - tcpm_pd_send_sink_caps(port); 2554 + ret = tcpm_pd_send_sink_caps(port); 2555 + if (ret < 0) { 2556 + tcpm_log(port, "Unable to send snk caps, ret=%d", ret); 2557 + tcpm_set_state(port, SNK_SOFT_RESET, 0); 2558 + } 2559 + tcpm_ams_finish(port); 2680 2560 break; 2681 2561 case PD_MSG_DATA_SOURCE_CAP: 2682 2562 ret = tcpm_pd_send_source_caps(port); ··· 2691 2561 ret); 2692 2562 tcpm_set_state(port, SOFT_RESET_SEND, 0); 2693 2563 } else if (port->pwr_role == TYPEC_SOURCE) { 2564 + tcpm_ams_finish(port); 2694 2565 tcpm_set_state(port, HARD_RESET_SEND, 2695 2566 PD_T_SENDER_RESPONSE); 2567 + } else { 2568 + tcpm_ams_finish(port); 2696 2569 } 2697 2570 break; 2698 2571 default: ··· 3714 3581 3715 3582 if (port->ams != NONE_AMS) 3716 3583 tcpm_ams_finish(port); 3584 + if (port->next_ams != NONE_AMS) { 3585 + port->ams = port->next_ams; 3586 + port->next_ams = NONE_AMS; 3587 + } 3588 + 3717 3589 /* 3718 3590 * If previous AMS is interrupted, switch to the upcoming 3719 3591 * state. ··· 3959 3821 3960 3822 if (port->ams != NONE_AMS) 3961 3823 tcpm_ams_finish(port); 3824 + if (port->next_ams != NONE_AMS) { 3825 + port->ams = port->next_ams; 3826 + port->next_ams = NONE_AMS; 3827 + } 3828 + 3962 3829 /* 3963 3830 * If previous AMS is interrupted, switch to the upcoming 3964 3831 * state. ··· 4111 3968 port->message_id = 0; 4112 3969 port->rx_msgid = -1; 4113 3970 tcpm_pd_send_control(port, PD_CTRL_ACCEPT); 3971 + tcpm_ams_finish(port); 4114 3972 if (port->pwr_role == TYPEC_SOURCE) { 4115 3973 port->upcoming_state = SRC_SEND_CAPABILITIES; 4116 3974 tcpm_ams_start(port, POWER_NEGOTIATION); ··· 4148 4004 break; 4149 4005 case DR_SWAP_SEND_TIMEOUT: 4150 4006 tcpm_swap_complete(port, -ETIMEDOUT); 4007 + tcpm_ams_finish(port); 4151 4008 tcpm_set_state(port, ready_state(port), 0); 4152 4009 break; 4153 4010 case DR_SWAP_CHANGE_DR: ··· 4161 4016 TYPEC_HOST); 4162 4017 port->send_discover = true; 4163 4018 } 4019 + tcpm_ams_finish(port); 4164 4020 tcpm_set_state(port, ready_state(port), 0); 4165 4021 break; 4166 4022 ··· 4289 4143 4290 4144 case VCONN_SWAP_ACCEPT: 4291 4145 tcpm_pd_send_control(port, PD_CTRL_ACCEPT); 4146 + tcpm_ams_finish(port); 4292 4147 tcpm_set_state(port, VCONN_SWAP_START, 0); 4293 4148 break; 4294 4149 case VCONN_SWAP_SEND: ··· 4406 4259 upcoming_state = port->upcoming_state; 4407 4260 port->upcoming_state = INVALID_STATE; 4408 4261 tcpm_set_state(port, upcoming_state, 0); 4262 + break; 4263 + 4264 + /* Chunk state */ 4265 + case CHUNK_NOT_SUPP: 4266 + tcpm_pd_send_control(port, PD_CTRL_NOT_SUPP); 4267 + tcpm_set_state(port, port->pwr_role == TYPEC_SOURCE ? SRC_READY : SNK_READY, 0); 4409 4268 break; 4410 4269 default: 4411 4270 WARN(1, "Unexpected port state %d\n", port->state); ··· 4842 4689 4843 4690 if (port->ams != NONE_AMS) 4844 4691 port->ams = NONE_AMS; 4692 + if (port->hard_reset_count < PD_N_HARD_RESET_COUNT) 4693 + port->ams = HARD_RESET; 4845 4694 /* 4846 4695 * If we keep receiving hard reset requests, executing the hard reset 4847 4696 * must have failed. Revert to error recovery if that happens.
+1
include/linux/usb/pd.h
··· 480 480 #define PD_T_SWAP_SRC_START 20 /* Minimum of 20ms */ 481 481 #define PD_T_BIST_CONT_MODE 50 /* 30 - 60 ms */ 482 482 #define PD_T_SINK_TX 16 /* 16 - 20 ms */ 483 + #define PD_T_CHUNK_NOT_SUPP 42 /* 40 - 50 ms */ 483 484 484 485 #define PD_T_DRP_TRY 100 /* 75 - 150 ms */ 485 486 #define PD_T_DRP_TRYWAIT 600 /* 400 - 800 ms */