Skip to content

Commit 95b4d51

Browse files
jwrdegoedegregkh
authored andcommitted
usb: typec: tcpm: Refactor tcpm_handle_vdm_request
Refactor tcpm_handle_vdm_request and its tcpm_pd_svdm helper function so that reporting the results of the vdm to the altmode-driver is separated out into a clear separate step inside tcpm_handle_vdm_request, instead of being scattered over various places inside the tcpm_pd_svdm helper. This is a preparation patch for fixing an AB BA lock inversion between the tcpm code and some altmode drivers. Reviewed-by: Heikki Krogerus <[email protected]> Reviewed-by: Guenter Roeck <[email protected]> Signed-off-by: Hans de Goede <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 8afe9a3 commit 95b4d51

File tree

1 file changed

+48
-28
lines changed

1 file changed

+48
-28
lines changed

drivers/usb/typec/tcpm/tcpm.c

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,14 @@ enum pd_msg_request {
159159
PD_MSG_DATA_SOURCE_CAP,
160160
};
161161

162+
enum adev_actions {
163+
ADEV_NONE = 0,
164+
ADEV_NOTIFY_USB_AND_QUEUE_VDM,
165+
ADEV_QUEUE_VDM,
166+
ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL,
167+
ADEV_ATTENTION,
168+
};
169+
162170
/* Events from low level driver */
163171

164172
#define TCPM_CC_EVENT BIT(0)
@@ -1080,10 +1088,10 @@ static void tcpm_register_partner_altmodes(struct tcpm_port *port)
10801088

10811089
#define supports_modal(port) PD_IDH_MODAL_SUPP((port)->partner_ident.id_header)
10821090

1083-
static int tcpm_pd_svdm(struct tcpm_port *port, const u32 *p, int cnt,
1084-
u32 *response)
1091+
static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
1092+
const u32 *p, int cnt, u32 *response,
1093+
enum adev_actions *adev_action)
10851094
{
1086-
struct typec_altmode *adev;
10871095
struct typec_altmode *pdev;
10881096
struct pd_mode_data *modep;
10891097
int rlen = 0;
@@ -1099,9 +1107,6 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const u32 *p, int cnt,
10991107

11001108
modep = &port->mode_data;
11011109

1102-
adev = typec_match_altmode(port->port_altmode, ALTMODE_DISCOVERY_MAX,
1103-
PD_VDO_VID(p[0]), PD_VDO_OPOS(p[0]));
1104-
11051110
pdev = typec_match_altmode(port->partner_altmode, ALTMODE_DISCOVERY_MAX,
11061111
PD_VDO_VID(p[0]), PD_VDO_OPOS(p[0]));
11071112

@@ -1127,8 +1132,7 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const u32 *p, int cnt,
11271132
break;
11281133
case CMD_ATTENTION:
11291134
/* Attention command does not have response */
1130-
if (adev)
1131-
typec_altmode_attention(adev, p[1]);
1135+
*adev_action = ADEV_ATTENTION;
11321136
return 0;
11331137
default:
11341138
break;
@@ -1182,23 +1186,15 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const u32 *p, int cnt,
11821186
case CMD_ENTER_MODE:
11831187
if (adev && pdev) {
11841188
typec_altmode_update_active(pdev, true);
1185-
1186-
if (typec_altmode_vdm(adev, p[0], &p[1], cnt)) {
1187-
response[0] = VDO(adev->svid, 1,
1188-
CMD_EXIT_MODE);
1189-
response[0] |= VDO_OPOS(adev->mode);
1190-
return 1;
1191-
}
1189+
*adev_action = ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL;
11921190
}
11931191
return 0;
11941192
case CMD_EXIT_MODE:
11951193
if (adev && pdev) {
11961194
typec_altmode_update_active(pdev, false);
1197-
11981195
/* Back to USB Operation */
1199-
WARN_ON(typec_altmode_notify(adev,
1200-
TYPEC_STATE_USB,
1201-
NULL));
1196+
*adev_action = ADEV_NOTIFY_USB_AND_QUEUE_VDM;
1197+
return 0;
12021198
}
12031199
break;
12041200
default:
@@ -1209,11 +1205,8 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const u32 *p, int cnt,
12091205
switch (cmd) {
12101206
case CMD_ENTER_MODE:
12111207
/* Back to USB Operation */
1212-
if (adev)
1213-
WARN_ON(typec_altmode_notify(adev,
1214-
TYPEC_STATE_USB,
1215-
NULL));
1216-
break;
1208+
*adev_action = ADEV_NOTIFY_USB_AND_QUEUE_VDM;
1209+
return 0;
12171210
default:
12181211
break;
12191212
}
@@ -1223,22 +1216,25 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const u32 *p, int cnt,
12231216
}
12241217

12251218
/* Informing the alternate mode drivers about everything */
1226-
if (adev)
1227-
typec_altmode_vdm(adev, p[0], &p[1], cnt);
1228-
1219+
*adev_action = ADEV_QUEUE_VDM;
12291220
return rlen;
12301221
}
12311222

12321223
static void tcpm_handle_vdm_request(struct tcpm_port *port,
12331224
const __le32 *payload, int cnt)
12341225
{
1226+
enum adev_actions adev_action = ADEV_NONE;
1227+
struct typec_altmode *adev;
12351228
u32 p[PD_MAX_PAYLOAD];
12361229
u32 response[8] = { };
12371230
int i, rlen = 0;
12381231

12391232
for (i = 0; i < cnt; i++)
12401233
p[i] = le32_to_cpu(payload[i]);
12411234

1235+
adev = typec_match_altmode(port->port_altmode, ALTMODE_DISCOVERY_MAX,
1236+
PD_VDO_VID(p[0]), PD_VDO_OPOS(p[0]));
1237+
12421238
if (port->vdm_state == VDM_STATE_BUSY) {
12431239
/* If UFP responded busy retry after timeout */
12441240
if (PD_VDO_CMDT(p[0]) == CMDT_RSP_BUSY) {
@@ -1253,7 +1249,31 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port,
12531249
}
12541250

12551251
if (PD_VDO_SVDM(p[0]))
1256-
rlen = tcpm_pd_svdm(port, p, cnt, response);
1252+
rlen = tcpm_pd_svdm(port, adev, p, cnt, response, &adev_action);
1253+
1254+
if (adev) {
1255+
switch (adev_action) {
1256+
case ADEV_NONE:
1257+
break;
1258+
case ADEV_NOTIFY_USB_AND_QUEUE_VDM:
1259+
WARN_ON(typec_altmode_notify(adev, TYPEC_STATE_USB, NULL));
1260+
typec_altmode_vdm(adev, p[0], &p[1], cnt);
1261+
break;
1262+
case ADEV_QUEUE_VDM:
1263+
typec_altmode_vdm(adev, p[0], &p[1], cnt);
1264+
break;
1265+
case ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL:
1266+
if (typec_altmode_vdm(adev, p[0], &p[1], cnt)) {
1267+
response[0] = VDO(adev->svid, 1, CMD_EXIT_MODE);
1268+
response[0] |= VDO_OPOS(adev->mode);
1269+
rlen = 1;
1270+
}
1271+
break;
1272+
case ADEV_ATTENTION:
1273+
typec_altmode_attention(adev, p[1]);
1274+
break;
1275+
}
1276+
}
12571277

12581278
if (rlen > 0)
12591279
tcpm_queue_vdm(port, response[0], &response[1], rlen - 1);

0 commit comments

Comments
 (0)