From: Guenter Roeck <linux@roeck-us.net>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Badhri Jagan Sridharan <Badhri@google.com>,
devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org,
Guenter Roeck <linux@roeck-us.net>
Subject: [PATCH 6/7] staging: typec: tcpm: Improve role swap with non PD capable partners
Date: Thu, 10 Aug 2017 21:15:44 -0700 [thread overview]
Message-ID: <1502424945-19969-6-git-send-email-linux@roeck-us.net> (raw)
In-Reply-To: <1502424945-19969-1-git-send-email-linux@roeck-us.net>
If the partner is not PD capable, we can not use a power role set request
to swap roles. Use the data role set request instead.
Also, if a partner is not PD capable, it does not really make sense to send
a PD message to trigger a role swap. On top of that, we should really wait
for the attempted role change to complete. Otherwise, it may well be that
user space requests another role change immediately afterwards which will
fail because the port is not yet in ready state.
Trigger the role swap from data role change requests and introduce new
state PORT_RESET and use it to solve the problem. This new state is
mostly identical to ERROR_RECOVERY, only it does not cause a pending
role change to fail. Use this new state also when initializing the driver.
Rename ERROR_RECOVERY_WAIT_OFF to PORT_RESET_WAIT_OFF to better reflect
its new meaning.
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
drivers/staging/typec/tcpm.c | 60 +++++++++++++++++++++++++-------------------
1 file changed, 34 insertions(+), 26 deletions(-)
diff --git a/drivers/staging/typec/tcpm.c b/drivers/staging/typec/tcpm.c
index 515bec1807d7..e0f71aeb4ed3 100644
--- a/drivers/staging/typec/tcpm.c
+++ b/drivers/staging/typec/tcpm.c
@@ -115,7 +115,8 @@
S(BIST_RX), \
\
S(ERROR_RECOVERY), \
- S(ERROR_RECOVERY_WAIT_OFF)
+ S(PORT_RESET), \
+ S(PORT_RESET_WAIT_OFF)
#define GENERATE_ENUM(e) e
#define GENERATE_STRING(s) #s
@@ -230,6 +231,7 @@ struct tcpm_port {
struct mutex swap_lock; /* swap command lock */
bool swap_pending;
+ bool non_pd_role_swap;
struct completion swap_complete;
int swap_status;
@@ -2124,6 +2126,7 @@ static void tcpm_swap_complete(struct tcpm_port *port, int result)
if (port->swap_pending) {
port->swap_status = result;
port->swap_pending = false;
+ port->non_pd_role_swap = false;
complete(&port->swap_complete);
}
}
@@ -2138,7 +2141,8 @@ static void run_state_machine(struct tcpm_port *port)
break;
/* SRC states */
case SRC_UNATTACHED:
- tcpm_swap_complete(port, -ENOTCONN);
+ if (!port->non_pd_role_swap)
+ tcpm_swap_complete(port, -ENOTCONN);
tcpm_src_detach(port);
if (tcpm_start_drp_toggling(port)) {
tcpm_set_state(port, DRP_TOGGLING, 0);
@@ -2293,7 +2297,8 @@ static void run_state_machine(struct tcpm_port *port)
/* SNK states */
case SNK_UNATTACHED:
- tcpm_swap_complete(port, -ENOTCONN);
+ if (!port->non_pd_role_swap)
+ tcpm_swap_complete(port, -ENOTCONN);
tcpm_snk_detach(port);
if (tcpm_start_drp_toggling(port)) {
tcpm_set_state(port, DRP_TOGGLING, 0);
@@ -2704,13 +2709,15 @@ static void run_state_machine(struct tcpm_port *port)
break;
case ERROR_RECOVERY:
tcpm_swap_complete(port, -EPROTO);
+ tcpm_set_state(port, PORT_RESET, 0);
+ break;
+ case PORT_RESET:
tcpm_reset_port(port);
-
tcpm_set_cc(port, TYPEC_CC_OPEN);
- tcpm_set_state(port, ERROR_RECOVERY_WAIT_OFF,
+ tcpm_set_state(port, PORT_RESET_WAIT_OFF,
PD_T_ERROR_RECOVERY);
break;
- case ERROR_RECOVERY_WAIT_OFF:
+ case PORT_RESET_WAIT_OFF:
tcpm_set_state(port,
tcpm_default_state(port),
port->vbus_present ? PD_T_PS_SOURCE_OFF : 0);
@@ -3042,7 +3049,7 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
/* Do nothing, expected */
break;
- case ERROR_RECOVERY_WAIT_OFF:
+ case PORT_RESET_WAIT_OFF:
tcpm_set_state(port, tcpm_default_state(port), 0);
break;
@@ -3139,7 +3146,7 @@ static int tcpm_dr_set(const struct typec_capability *cap,
mutex_lock(&port->swap_lock);
mutex_lock(&port->lock);
- if (port->typec_caps.type != TYPEC_PORT_DRP || !port->pd_capable) {
+ if (port->typec_caps.type != TYPEC_PORT_DRP) {
ret = -EINVAL;
goto port_unlock;
}
@@ -3160,10 +3167,26 @@ static int tcpm_dr_set(const struct typec_capability *cap,
* Reject data role swap request in this case.
*/
+ if (!port->pd_capable) {
+ /*
+ * If the partner is not PD capable, reset the port to
+ * trigger a role change. This can only work if a preferred
+ * role is configured, and if it matches the requested role.
+ */
+ if (port->try_role == TYPEC_NO_PREFERRED_ROLE ||
+ port->try_role == port->pwr_role) {
+ ret = -EINVAL;
+ goto port_unlock;
+ }
+ port->non_pd_role_swap = true;
+ tcpm_set_state(port, PORT_RESET, 0);
+ } else {
+ tcpm_set_state(port, DR_SWAP_SEND, 0);
+ }
+
port->swap_status = 0;
port->swap_pending = true;
reinit_completion(&port->swap_complete);
- tcpm_set_state(port, DR_SWAP_SEND, 0);
mutex_unlock(&port->lock);
if (!wait_for_completion_timeout(&port->swap_complete,
@@ -3172,6 +3195,7 @@ static int tcpm_dr_set(const struct typec_capability *cap,
else
ret = port->swap_status;
+ port->non_pd_role_swap = false;
goto swap_unlock;
port_unlock:
@@ -3204,22 +3228,6 @@ static int tcpm_pr_set(const struct typec_capability *cap,
goto port_unlock;
}
- if (!port->pd_capable) {
- /*
- * If the partner is not PD capable, reset the port to
- * trigger a role change. This can only work if a preferred
- * role is configured, and if it matches the requested role.
- */
- if (port->try_role == TYPEC_NO_PREFERRED_ROLE ||
- port->try_role == port->pwr_role) {
- ret = -EINVAL;
- goto port_unlock;
- }
- tcpm_set_state(port, HARD_RESET_SEND, 0);
- ret = 0;
- goto port_unlock;
- }
-
port->swap_status = 0;
port->swap_pending = true;
reinit_completion(&port->swap_complete);
@@ -3325,7 +3333,7 @@ static void tcpm_init(struct tcpm_port *port)
* Some adapters need a clean slate at startup, and won't recover
* otherwise. So do not try to be fancy and force a clean disconnect.
*/
- tcpm_set_state(port, ERROR_RECOVERY, 0);
+ tcpm_set_state(port, PORT_RESET, 0);
}
void tcpm_tcpc_reset(struct tcpm_port *port)
--
2.7.4
next prev parent reply other threads:[~2017-08-11 4:15 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-08-11 4:15 [PATCH 1/7] staging: typec: tcpm: Constify alternate modes Guenter Roeck
2017-08-11 4:15 ` [PATCH 2/7] staging: typec: tcpm: Report role swap complete after entering READY state Guenter Roeck
2017-08-11 4:15 ` [PATCH 3/7] staging: typec: tcpm: Set default state after error recovery based on port type Guenter Roeck
2017-08-11 4:15 ` [PATCH 4/7] staging: typec: tcpm: Select default state " Guenter Roeck
2017-08-11 4:15 ` [PATCH 5/7] staging: typec: tcpm: Add timeout when waiting for role swap completion Guenter Roeck
2017-08-11 4:15 ` Guenter Roeck [this message]
2017-08-11 4:15 ` [PATCH 7/7] staging: typec: tcpm: Check cc status before entering SRC_TRY_DEBOUCE Guenter Roeck
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1502424945-19969-6-git-send-email-linux@roeck-us.net \
--to=linux@roeck-us.net \
--cc=Badhri@google.com \
--cc=devel@driverdev.osuosl.org \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox