Skip to content

Commit 8e1ec11

Browse files
Fabrice Gasniergregkh
authored andcommitted
usb: ucsi: stm32: fix command completion handling
Sometimes errors are seen, when doing DR swap, like: [ 24.672481] ucsi-stm32g0-i2c 0-0035: UCSI_GET_PDOS failed (-5) [ 24.720188] ucsi-stm32g0-i2c 0-0035: ucsi_handle_connector_change: GET_CONNECTOR_STATUS failed (-5) There may be some race, which lead to read CCI, before the command complete flag is set, hence returning -EIO. Similar fix has been done also in ucsi_acpi [1]. In case of a spurious or otherwise delayed notification it is possible that CCI still reports the previous completion. The UCSI spec is aware of this and provides two completion bits in CCI, one for normal commands and one for acks. As acks and commands alternate the notification handler can determine if the completion bit is from the current command. To fix this add the ACK_PENDING bit for ucsi_stm32g0 and only complete commands if the completion bit matches. [1] https://lore.kernel.org/lkml/[email protected]/ Fixes: 72849d4 ("usb: typec: ucsi: stm32g0: add support for stm32g0 controller") Signed-off-by: Fabrice Gasnier <[email protected]> Link: https://lore.kernel.org/stable/20240612124656.2305603-1-fabrice.gasnier%40foss.st.com Cc: stable <[email protected]> Reviewed-by: Heikki Krogerus <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 2eabb65 commit 8e1ec11

File tree

1 file changed

+15
-4
lines changed

1 file changed

+15
-4
lines changed

drivers/usb/typec/ucsi/ucsi_stm32g0.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ struct ucsi_stm32g0 {
6565
struct device *dev;
6666
unsigned long flags;
6767
#define COMMAND_PENDING 1
68+
#define ACK_PENDING 2
6869
const char *fw_name;
6970
struct ucsi *ucsi;
7071
bool suspended;
@@ -396,19 +397,28 @@ static int ucsi_stm32g0_sync_write(struct ucsi *ucsi, unsigned int offset, const
396397
size_t len)
397398
{
398399
struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi);
400+
bool ack = UCSI_COMMAND(*(u64 *)val) == UCSI_ACK_CC_CI;
399401
int ret;
400402

401-
set_bit(COMMAND_PENDING, &g0->flags);
403+
if (ack)
404+
set_bit(ACK_PENDING, &g0->flags);
405+
else
406+
set_bit(COMMAND_PENDING, &g0->flags);
402407

403408
ret = ucsi_stm32g0_async_write(ucsi, offset, val, len);
404409
if (ret)
405410
goto out_clear_bit;
406411

407412
if (!wait_for_completion_timeout(&g0->complete, msecs_to_jiffies(5000)))
408413
ret = -ETIMEDOUT;
414+
else
415+
return 0;
409416

410417
out_clear_bit:
411-
clear_bit(COMMAND_PENDING, &g0->flags);
418+
if (ack)
419+
clear_bit(ACK_PENDING, &g0->flags);
420+
else
421+
clear_bit(COMMAND_PENDING, &g0->flags);
412422

413423
return ret;
414424
}
@@ -429,8 +439,9 @@ static irqreturn_t ucsi_stm32g0_irq_handler(int irq, void *data)
429439
if (UCSI_CCI_CONNECTOR(cci))
430440
ucsi_connector_change(g0->ucsi, UCSI_CCI_CONNECTOR(cci));
431441

432-
if (test_bit(COMMAND_PENDING, &g0->flags) &&
433-
cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE))
442+
if (cci & UCSI_CCI_ACK_COMPLETE && test_and_clear_bit(ACK_PENDING, &g0->flags))
443+
complete(&g0->complete);
444+
if (cci & UCSI_CCI_COMMAND_COMPLETE && test_and_clear_bit(COMMAND_PENDING, &g0->flags))
434445
complete(&g0->complete);
435446

436447
return IRQ_HANDLED;

0 commit comments

Comments
 (0)