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

Configure Feed

Select the types of activity you want to include in your feed.

usb: typec: ucsi: Wait for the USB role switches

When role switch module probe late than ucsi module,
fwnode_usb_role_switch_get() will return -EPROBE_DEFER,
it is better to restart ucsi init work to find
it again every 100ms, total wait time is 10 second.

It also means change ucsi init work to delayed_work.

Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Linyu Yuan <quic_linyyuan@quicinc.com>
Link: https://lore.kernel.org/r/1650881886-25530-3-git-send-email-quic_linyyuan@quicinc.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Linyu Yuan and committed by
Greg Kroah-Hartman
3c162511 87d0e2f4

+25 -13
+20 -12
drivers/usb/typec/ucsi/ucsi.c
··· 1053 1053 con->num = index + 1; 1054 1054 con->ucsi = ucsi; 1055 1055 1056 + cap->fwnode = ucsi_find_fwnode(con); 1057 + con->usb_role_sw = fwnode_usb_role_switch_get(cap->fwnode); 1058 + if (IS_ERR(con->usb_role_sw)) { 1059 + dev_err(ucsi->dev, "con%d: failed to get usb role switch\n", 1060 + con->num); 1061 + return PTR_ERR(con->usb_role_sw); 1062 + } 1063 + 1056 1064 /* Delay other interactions with the con until registration is complete */ 1057 1065 mutex_lock(&con->lock); 1058 1066 ··· 1096 1088 if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY) 1097 1089 *accessory = TYPEC_ACCESSORY_DEBUG; 1098 1090 1099 - cap->fwnode = ucsi_find_fwnode(con); 1100 1091 cap->driver_data = con; 1101 1092 cap->ops = &ucsi_ops; 1102 1093 ··· 1151 1144 ucsi_pwr_opmode_change(con); 1152 1145 ucsi_register_partner(con); 1153 1146 ucsi_port_psy_changed(con); 1154 - } 1155 - 1156 - con->usb_role_sw = fwnode_usb_role_switch_get(cap->fwnode); 1157 - if (IS_ERR(con->usb_role_sw)) { 1158 - dev_err(ucsi->dev, "con%d: failed to get usb role switch\n", 1159 - con->num); 1160 - con->usb_role_sw = NULL; 1161 1147 } 1162 1148 1163 1149 /* Only notify USB controller if partner supports USB data */ ··· 1285 1285 1286 1286 static void ucsi_init_work(struct work_struct *work) 1287 1287 { 1288 - struct ucsi *ucsi = container_of(work, struct ucsi, work); 1288 + struct ucsi *ucsi = container_of(work, struct ucsi, work.work); 1289 1289 int ret; 1290 1290 1291 1291 ret = ucsi_init(ucsi); 1292 1292 if (ret) 1293 1293 dev_err(ucsi->dev, "PPM init failed (%d)\n", ret); 1294 + 1295 + if (ret == -EPROBE_DEFER) { 1296 + if (ucsi->work_count++ > UCSI_ROLE_SWITCH_WAIT_COUNT) 1297 + return; 1298 + 1299 + queue_delayed_work(system_long_wq, &ucsi->work, 1300 + UCSI_ROLE_SWITCH_INTERVAL); 1301 + } 1294 1302 } 1295 1303 1296 1304 /** ··· 1338 1330 if (!ucsi) 1339 1331 return ERR_PTR(-ENOMEM); 1340 1332 1341 - INIT_WORK(&ucsi->work, ucsi_init_work); 1333 + INIT_DELAYED_WORK(&ucsi->work, ucsi_init_work); 1342 1334 mutex_init(&ucsi->ppm_lock); 1343 1335 ucsi->dev = dev; 1344 1336 ucsi->ops = ops; ··· 1373 1365 if (!ucsi->version) 1374 1366 return -ENODEV; 1375 1367 1376 - queue_work(system_long_wq, &ucsi->work); 1368 + queue_delayed_work(system_long_wq, &ucsi->work, 0); 1377 1369 1378 1370 return 0; 1379 1371 } ··· 1390 1382 u64 cmd = UCSI_SET_NOTIFICATION_ENABLE; 1391 1383 1392 1384 /* Make sure that we are not in the middle of driver initialization */ 1393 - cancel_work_sync(&ucsi->work); 1385 + cancel_delayed_work_sync(&ucsi->work); 1394 1386 1395 1387 /* Disable notifications */ 1396 1388 ucsi->ops->async_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd));
+5 -1
drivers/usb/typec/ucsi/ucsi.h
··· 287 287 struct ucsi_capability cap; 288 288 struct ucsi_connector *connector; 289 289 290 - struct work_struct work; 290 + struct delayed_work work; 291 + int work_count; 292 + #define UCSI_ROLE_SWITCH_RETRY_PER_HZ 10 293 + #define UCSI_ROLE_SWITCH_INTERVAL (HZ / UCSI_ROLE_SWITCH_RETRY_PER_HZ) 294 + #define UCSI_ROLE_SWITCH_WAIT_COUNT (10 * UCSI_ROLE_SWITCH_RETRY_PER_HZ) 291 295 292 296 /* PPM Communication lock */ 293 297 struct mutex ppm_lock;