Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fa2dcebf authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: pd: allow outgoing requests after receiving status payload"

parents 06e5ace9 88f3eec6
Loading
Loading
Loading
Loading
+130 −126
Original line number Diff line number Diff line
@@ -51,7 +51,6 @@ enum usbpd_state {
	PE_SRC_READY,
	PE_SRC_HARD_RESET,
	PE_SRC_SOFT_RESET,
	PE_SRC_SEND_SOFT_RESET,
	PE_SRC_DISCOVERY,
	PE_SRC_TRANSITION_TO_DEFAULT,
	PE_SNK_STARTUP,
@@ -63,7 +62,6 @@ enum usbpd_state {
	PE_SNK_READY,
	PE_SNK_HARD_RESET,
	PE_SNK_SOFT_RESET,
	PE_SNK_SEND_SOFT_RESET,
	PE_SNK_TRANSITION_TO_DEFAULT,
	PE_DRS_SEND_DR_SWAP,
	PE_PRS_SNK_SRC_SEND_SWAP,
@@ -72,6 +70,7 @@ enum usbpd_state {
	PE_PRS_SRC_SNK_SEND_SWAP,
	PE_PRS_SRC_SNK_TRANSITION_TO_OFF,
	PE_PRS_SRC_SNK_WAIT_SOURCE_ON,
	PE_SEND_SOFT_RESET,
	PE_VCS_WAIT_FOR_VCONN,
};

@@ -88,7 +87,6 @@ static const char * const usbpd_state_strings[] = {
	"SRC_Ready",
	"SRC_Hard_Reset",
	"SRC_Soft_Reset",
	"SRC_Send_Soft_Reset",
	"SRC_Discovery",
	"SRC_Transition_to_default",
	"SNK_Startup",
@@ -100,7 +98,6 @@ static const char * const usbpd_state_strings[] = {
	"SNK_Ready",
	"SNK_Hard_Reset",
	"SNK_Soft_Reset",
	"SNK_Send_Soft_Reset",
	"SNK_Transition_to_default",
	"DRS_Send_DR_Swap",
	"PRS_SNK_SRC_Send_Swap",
@@ -109,6 +106,7 @@ static const char * const usbpd_state_strings[] = {
	"PRS_SRC_SNK_Send_Swap",
	"PRS_SRC_SNK_Transition_to_off",
	"PRS_SRC_SNK_Wait_Source_on",
	"Send_Soft_Reset",
	"VCS_Wait_for_VCONN",
};

@@ -1337,7 +1335,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
			/* send Reject */
			ret = pd_send_msg(pd, MSG_REJECT, NULL, 0, SOP_MSG);
			if (ret) {
				usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
				usbpd_set_state(pd, PE_SEND_SOFT_RESET);
				break;
			}

@@ -1358,7 +1356,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
		/* PE_SRC_TRANSITION_SUPPLY pseudo-state */
		ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG);
		if (ret) {
			usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
			usbpd_set_state(pd, PE_SEND_SOFT_RESET);
			break;
		}

@@ -1373,7 +1371,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
		 */
		ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG);
		if (ret) {
			usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
			usbpd_set_state(pd, PE_SEND_SOFT_RESET);
			break;
		}

@@ -1425,8 +1423,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
		kick_sm(pd, 0);
		break;

	case PE_SRC_SEND_SOFT_RESET:
	case PE_SNK_SEND_SOFT_RESET:
	case PE_SEND_SOFT_RESET:
		pd_reset_protocol(pd);

		ret = pd_send_msg(pd, MSG_SOFT_RESET, NULL, 0, SOP_MSG);
@@ -1516,7 +1513,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)

		ret = pd_send_msg(pd, MSG_REQUEST, &pd->rdo, 1, SOP_MSG);
		if (ret) {
			usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
			usbpd_set_state(pd, PE_SEND_SOFT_RESET);
			break;
		}

@@ -1940,9 +1937,7 @@ static void handle_vdm_tx(struct usbpd *pd, enum pd_sop_type sop_type)

			/* retry when hitting PE_SRC/SNK_Ready again */
			if (ret != -EBUSY && sop_type == SOP_MSG)
				usbpd_set_state(pd, pd->current_pr == PR_SRC ?
					PE_SRC_SEND_SOFT_RESET :
					PE_SNK_SEND_SOFT_RESET);
				usbpd_set_state(pd, PE_SEND_SOFT_RESET);

			return;
		}
@@ -2043,9 +2038,7 @@ static void vconn_swap(struct usbpd *pd)

		ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG);
		if (ret) {
			usbpd_set_state(pd, pd->current_pr == PR_SRC ?
					PE_SRC_SEND_SOFT_RESET :
					PE_SNK_SEND_SOFT_RESET);
			usbpd_set_state(pd, PE_SEND_SOFT_RESET);
			return;
		}
	}
@@ -2371,7 +2364,7 @@ static void usbpd_sm(struct work_struct *w)
			usbpd_set_state(pd, PE_SRC_NEGOTIATE_CAPABILITY);
		} else if (rx_msg) {
			usbpd_err(&pd->dev, "Unexpected message received\n");
			usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
			usbpd_set_state(pd, PE_SEND_SOFT_RESET);
		} else {
			usbpd_set_state(pd, PE_SRC_HARD_RESET);
		}
@@ -2386,7 +2379,7 @@ static void usbpd_sm(struct work_struct *w)
					pd->sink_caps, pd->num_sink_caps,
					SOP_MSG);
			if (ret)
				usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
				usbpd_set_state(pd, PE_SEND_SOFT_RESET);
		} else if (IS_DATA(rx_msg, MSG_REQUEST)) {
			pd->rdo = *(u32 *)rx_msg->payload;
			usbpd_set_state(pd, PE_SRC_NEGOTIATE_CAPABILITY);
@@ -2398,7 +2391,7 @@ static void usbpd_sm(struct work_struct *w)

			ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG);
			if (ret) {
				usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
				usbpd_set_state(pd, PE_SEND_SOFT_RESET);
				break;
			}

@@ -2407,7 +2400,7 @@ static void usbpd_sm(struct work_struct *w)
			/* we'll happily accept Src->Sink requests anytime */
			ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG);
			if (ret) {
				usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
				usbpd_set_state(pd, PE_SEND_SOFT_RESET);
				break;
			}

@@ -2416,7 +2409,7 @@ static void usbpd_sm(struct work_struct *w)
		} else if (IS_CTRL(rx_msg, MSG_VCONN_SWAP)) {
			ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG);
			if (ret) {
				usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
				usbpd_set_state(pd, PE_SEND_SOFT_RESET);
				break;
			}

@@ -2428,13 +2421,13 @@ static void usbpd_sm(struct work_struct *w)
			ret = pd_send_msg(pd, MSG_NOT_SUPPORTED, NULL, 0,
					SOP_MSG);
			if (ret)
				usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
				usbpd_set_state(pd, PE_SEND_SOFT_RESET);
			break;
		} else if (pd->send_pr_swap) {
			pd->send_pr_swap = false;
			ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0, SOP_MSG);
			if (ret) {
				usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
				usbpd_set_state(pd, PE_SEND_SOFT_RESET);
				break;
			}

@@ -2444,7 +2437,7 @@ static void usbpd_sm(struct work_struct *w)
			pd->send_dr_swap = false;
			ret = pd_send_msg(pd, MSG_DR_SWAP, NULL, 0, SOP_MSG);
			if (ret) {
				usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
				usbpd_set_state(pd, PE_SEND_SOFT_RESET);
				break;
			}

@@ -2608,7 +2601,7 @@ static void usbpd_sm(struct work_struct *w)
						PE_SNK_WAIT_FOR_CAPABILITIES);
		} else if (rx_msg) {
			usbpd_err(&pd->dev, "Invalid response to sink request\n");
			usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
			usbpd_set_state(pd, PE_SEND_SOFT_RESET);
		} else {
			/* timed out; go to hard reset */
			usbpd_set_state(pd, PE_SNK_HARD_RESET);
@@ -2647,21 +2640,22 @@ static void usbpd_sm(struct work_struct *w)
			pd->src_cap_id++;

			usbpd_set_state(pd, PE_SNK_EVALUATE_CAPABILITY);
			break;
		} else if (IS_CTRL(rx_msg, MSG_GET_SINK_CAP)) {
			ret = pd_send_msg(pd, MSG_SINK_CAPABILITIES,
					pd->sink_caps, pd->num_sink_caps,
					SOP_MSG);
			if (ret)
				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
				usbpd_set_state(pd, PE_SEND_SOFT_RESET);
			break;
		} else if (IS_CTRL(rx_msg, MSG_GET_SOURCE_CAP) &&
				pd->spec_rev == USBPD_REV_20) {
			ret = pd_send_msg(pd, MSG_SOURCE_CAPABILITIES,
					default_src_caps,
					ARRAY_SIZE(default_src_caps), SOP_MSG);
			if (ret) {
				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
			if (ret)
				usbpd_set_state(pd, PE_SEND_SOFT_RESET);
			break;
			}
		} else if (IS_CTRL(rx_msg, MSG_DR_SWAP)) {
			if (pd->vdm_state == MODE_ENTERED) {
				usbpd_set_state(pd, PE_SNK_HARD_RESET);
@@ -2670,17 +2664,18 @@ static void usbpd_sm(struct work_struct *w)

			ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG);
			if (ret) {
				usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
				usbpd_set_state(pd, PE_SEND_SOFT_RESET);
				break;
			}

			dr_swap(pd);
			break;
		} else if (IS_CTRL(rx_msg, MSG_PR_SWAP) &&
				pd->spec_rev == USBPD_REV_20) {
			/* TODO: should we Reject in certain circumstances? */
			ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG);
			if (ret) {
				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
				usbpd_set_state(pd, PE_SEND_SOFT_RESET);
				break;
			}

@@ -2697,57 +2692,22 @@ static void usbpd_sm(struct work_struct *w)
				ret = pd_send_msg(pd, MSG_REJECT, NULL, 0,
						SOP_MSG);
				if (ret)
					usbpd_set_state(pd,
							PE_SNK_SEND_SOFT_RESET);
					usbpd_set_state(pd, PE_SEND_SOFT_RESET);

				break;
			}

			ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG);
			if (ret) {
				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
				usbpd_set_state(pd, PE_SEND_SOFT_RESET);
				break;
			}

			vconn_swap(pd);
			break;
		} else if (IS_DATA(rx_msg, MSG_VDM)) {
			handle_vdm_rx(pd, rx_msg);
		} else if (pd->send_get_src_cap_ext && is_sink_tx_ok(pd)) {
			pd->send_get_src_cap_ext = false;
			ret = pd_send_msg(pd, MSG_GET_SOURCE_CAP_EXTENDED, NULL,
				0, SOP_MSG);
			if (ret) {
				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
				break;
			}
			kick_sm(pd, SENDER_RESPONSE_TIME);
		} else if (rx_msg &&
			IS_EXT(rx_msg, MSG_SOURCE_CAPABILITIES_EXTENDED)) {
			if (rx_msg->data_len != PD_SRC_CAP_EXT_DB_LEN) {
				usbpd_err(&pd->dev, "Invalid src cap ext db\n");
				break;
			}
			memcpy(&pd->src_cap_ext_db, rx_msg->payload,
				sizeof(pd->src_cap_ext_db));
			complete(&pd->is_ready);
		} else if (pd->send_get_pps_status && is_sink_tx_ok(pd)) {
			pd->send_get_pps_status = false;
			ret = pd_send_msg(pd, MSG_GET_PPS_STATUS, NULL,
				0, SOP_MSG);
			if (ret) {
				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
				break;
			}
			kick_sm(pd, SENDER_RESPONSE_TIME);
		} else if (rx_msg &&
			IS_EXT(rx_msg, MSG_PPS_STATUS)) {
			if (rx_msg->data_len != sizeof(pd->pps_status_db)) {
				usbpd_err(&pd->dev, "Invalid pps status db\n");
			break;
			}
			memcpy(&pd->pps_status_db, rx_msg->payload,
				sizeof(pd->pps_status_db));
			complete(&pd->is_ready);
		} else if (IS_DATA(rx_msg, MSG_ALERT)) {
			u32 ado;

@@ -2765,15 +2725,24 @@ static void usbpd_sm(struct work_struct *w)
			 */
			pd->send_get_status = true;
			kick_sm(pd, 150);
		} else if (pd->send_get_status && is_sink_tx_ok(pd)) {
			pd->send_get_status = false;
			ret = pd_send_msg(pd, MSG_GET_STATUS, NULL, 0, SOP_MSG);
			if (ret) {
				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
			break;
		} else if (IS_EXT(rx_msg, MSG_SOURCE_CAPABILITIES_EXTENDED)) {
			if (rx_msg->data_len != PD_SRC_CAP_EXT_DB_LEN) {
				usbpd_err(&pd->dev, "Invalid src cap ext db\n");
				break;
			}
			kick_sm(pd, SENDER_RESPONSE_TIME);
		} else if (rx_msg && IS_EXT(rx_msg, MSG_STATUS)) {
			memcpy(&pd->src_cap_ext_db, rx_msg->payload,
				sizeof(pd->src_cap_ext_db));
			complete(&pd->is_ready);
		} else if (IS_EXT(rx_msg, MSG_PPS_STATUS)) {
			if (rx_msg->data_len != sizeof(pd->pps_status_db)) {
				usbpd_err(&pd->dev, "Invalid pps status db\n");
				break;
			}
			memcpy(&pd->pps_status_db, rx_msg->payload,
				sizeof(pd->pps_status_db));
			complete(&pd->is_ready);
		} else if (IS_EXT(rx_msg, MSG_STATUS)) {
			if (rx_msg->data_len != PD_STATUS_DB_LEN) {
				usbpd_err(&pd->dev, "Invalid status db\n");
				break;
@@ -2781,17 +2750,8 @@ static void usbpd_sm(struct work_struct *w)
			memcpy(&pd->status_db, rx_msg->payload,
				sizeof(pd->status_db));
			kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE);
		} else if (pd->send_get_battery_cap && is_sink_tx_ok(pd)) {
			pd->send_get_battery_cap = false;
			ret = pd_send_ext_msg(pd, MSG_GET_BATTERY_CAP,
				&pd->get_battery_cap_db, 1, SOP_MSG);
			if (ret) {
				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
				break;
			}
			kick_sm(pd, SENDER_RESPONSE_TIME);
		} else if (rx_msg &&
			IS_EXT(rx_msg, MSG_BATTERY_CAPABILITIES)) {
			complete(&pd->is_ready);
		} else if (IS_EXT(rx_msg, MSG_BATTERY_CAPABILITIES)) {
			if (rx_msg->data_len != PD_BATTERY_CAP_DB_LEN) {
				usbpd_err(&pd->dev, "Invalid battery cap db\n");
				break;
@@ -2799,17 +2759,7 @@ static void usbpd_sm(struct work_struct *w)
			memcpy(&pd->battery_cap_db, rx_msg->payload,
				sizeof(pd->battery_cap_db));
			complete(&pd->is_ready);
		} else if (pd->send_get_battery_status && is_sink_tx_ok(pd)) {
			pd->send_get_battery_status = false;
			ret = pd_send_ext_msg(pd, MSG_GET_BATTERY_STATUS,
				&pd->get_battery_status_db, 1, SOP_MSG);
			if (ret) {
				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
				break;
			}
			kick_sm(pd, SENDER_RESPONSE_TIME);
		} else if (rx_msg &&
			IS_EXT(rx_msg, MSG_BATTERY_STATUS)) {
		} else if (IS_EXT(rx_msg, MSG_BATTERY_STATUS)) {
			if (rx_msg->data_len != sizeof(pd->battery_sts_dobj)) {
				usbpd_err(&pd->dev, "Invalid bat sts dobj\n");
				break;
@@ -2822,34 +2772,89 @@ static void usbpd_sm(struct work_struct *w)
			ret = pd_send_msg(pd, MSG_NOT_SUPPORTED, NULL, 0,
					SOP_MSG);
			if (ret)
				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
				usbpd_set_state(pd, PE_SEND_SOFT_RESET);
			break;
		}

		/* handle outgoing requests */
		if (is_sink_tx_ok(pd)) {
			if (pd->send_get_src_cap_ext) {
				pd->send_get_src_cap_ext = false;
				ret = pd_send_msg(pd,
						MSG_GET_SOURCE_CAP_EXTENDED,
						NULL, 0, SOP_MSG);
				if (ret) {
					usbpd_set_state(pd, PE_SEND_SOFT_RESET);
					break;
				}
				kick_sm(pd, SENDER_RESPONSE_TIME);
			} else if (pd->send_get_pps_status) {
				pd->send_get_pps_status = false;
				ret = pd_send_msg(pd, MSG_GET_PPS_STATUS,
						NULL, 0, SOP_MSG);
				if (ret) {
					usbpd_set_state(pd, PE_SEND_SOFT_RESET);
					break;
				}
				kick_sm(pd, SENDER_RESPONSE_TIME);
			} else if (pd->send_get_status) {
				pd->send_get_status = false;
				ret = pd_send_msg(pd, MSG_GET_STATUS, NULL, 0,
						SOP_MSG);
				if (ret) {
					usbpd_set_state(pd, PE_SEND_SOFT_RESET);
					break;
				}
				kick_sm(pd, SENDER_RESPONSE_TIME);
			} else if (pd->send_get_battery_cap) {
				pd->send_get_battery_cap = false;
				ret = pd_send_ext_msg(pd, MSG_GET_BATTERY_CAP,
					&pd->get_battery_cap_db, 1, SOP_MSG);
				if (ret) {
					usbpd_set_state(pd, PE_SEND_SOFT_RESET);
					break;
				}
				kick_sm(pd, SENDER_RESPONSE_TIME);
			} else if (pd->send_get_battery_status) {
				pd->send_get_battery_status = false;
				ret = pd_send_ext_msg(pd,
						MSG_GET_BATTERY_STATUS,
						&pd->get_battery_status_db, 1,
						SOP_MSG);
				if (ret) {
					usbpd_set_state(pd, PE_SEND_SOFT_RESET);
					break;
				}
				kick_sm(pd, SENDER_RESPONSE_TIME);
			} else if (pd->send_request) {
				pd->send_request = false;
				usbpd_set_state(pd, PE_SNK_SELECT_CAPABILITY);
		} else if (pd->send_pr_swap && is_sink_tx_ok(pd)) {
			} else if (pd->send_pr_swap) {
				pd->send_pr_swap = false;
			ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0, SOP_MSG);
				ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0,
						SOP_MSG);
				if (ret) {
				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
					usbpd_set_state(pd, PE_SEND_SOFT_RESET);
					break;
				}

				pd->current_state = PE_PRS_SNK_SRC_SEND_SWAP;
				kick_sm(pd, SENDER_RESPONSE_TIME);
		} else if (pd->send_dr_swap && is_sink_tx_ok(pd)) {
			} else if (pd->send_dr_swap) {
				pd->send_dr_swap = false;
			ret = pd_send_msg(pd, MSG_DR_SWAP, NULL, 0, SOP_MSG);
				ret = pd_send_msg(pd, MSG_DR_SWAP, NULL, 0,
						SOP_MSG);
				if (ret) {
				usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
					usbpd_set_state(pd, PE_SEND_SOFT_RESET);
					break;
				}

				pd->current_state = PE_DRS_SEND_DR_SWAP;
				kick_sm(pd, SENDER_RESPONSE_TIME);
		} else if (is_sink_tx_ok(pd)) {
			} else {
				handle_vdm_tx(pd, SOP_MSG);
			}
		}
		break;

	case PE_SNK_TRANSITION_TO_DEFAULT:
@@ -2872,8 +2877,7 @@ static void usbpd_sm(struct work_struct *w)
				PE_SNK_WAIT_FOR_CAPABILITIES);
		break;

	case PE_SRC_SEND_SOFT_RESET:
	case PE_SNK_SEND_SOFT_RESET:
	case PE_SEND_SOFT_RESET:
		if (IS_CTRL(rx_msg, MSG_ACCEPT)) {
			usbpd_set_state(pd, pd->current_pr == PR_SRC ?
					PE_SRC_SEND_CAPABILITIES :