Skip to content

Commit 36b7b26

Browse files
svenpeter42gregkh
authored andcommitted
usb: typec: tipd: Clear interrupts first
commit be5ae73 upstream. Right now the interrupt handler first reads all updated status registers and only then clears the interrupts. It's possible that a duplicate interrupt for a changed register or plug state comes in after the interrupts have been processed but before they have been cleared: * plug is inserted, TPS_REG_INT_PLUG_EVENT is set * TPS_REG_INT_EVENT1 is read * tps6598x_handle_plug_event() has run and registered the plug * plug is removed again, TPS_REG_INT_PLUG_EVENT is set (again) * TPS_REG_INT_CLEAR1 is written, TPS_REG_INT_PLUG_EVENT is cleared We then have no plug connected and no pending interrupt but the tipd core still thinks there is a plug. It's possible to trigger this with e.g. a slightly broken Type-C to USB A converter. Fix this by first clearing the interrupts and only then reading the updated registers. Fixes: 45188f2 ("usb: typec: tipd: Add support for Apple CD321X") Fixes: 0a4c005 ("usb: typec: driver for TI TPS6598x USB Power Delivery controllers") Cc: [email protected] Reviewed-by: Heikki Krogerus <[email protected]> Reviewed-by: Neal Gompa <[email protected]> Signed-off-by: Sven Peter <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 9d8bcaf commit 36b7b26

File tree

1 file changed

+11
-13
lines changed

1 file changed

+11
-13
lines changed

drivers/usb/typec/tipd/core.c

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -545,24 +545,23 @@ static irqreturn_t cd321x_interrupt(int irq, void *data)
545545
if (!event)
546546
goto err_unlock;
547547

548+
tps6598x_write64(tps, TPS_REG_INT_CLEAR1, event);
549+
548550
if (!tps6598x_read_status(tps, &status))
549-
goto err_clear_ints;
551+
goto err_unlock;
550552

551553
if (event & APPLE_CD_REG_INT_POWER_STATUS_UPDATE)
552554
if (!tps6598x_read_power_status(tps))
553-
goto err_clear_ints;
555+
goto err_unlock;
554556

555557
if (event & APPLE_CD_REG_INT_DATA_STATUS_UPDATE)
556558
if (!tps6598x_read_data_status(tps))
557-
goto err_clear_ints;
559+
goto err_unlock;
558560

559561
/* Handle plug insert or removal */
560562
if (event & APPLE_CD_REG_INT_PLUG_EVENT)
561563
tps6598x_handle_plug_event(tps, status);
562564

563-
err_clear_ints:
564-
tps6598x_write64(tps, TPS_REG_INT_CLEAR1, event);
565-
566565
err_unlock:
567566
mutex_unlock(&tps->lock);
568567

@@ -668,25 +667,24 @@ static irqreturn_t tps6598x_interrupt(int irq, void *data)
668667
if (!(event1[0] | event1[1] | event2[0] | event2[1]))
669668
goto err_unlock;
670669

670+
tps6598x_block_write(tps, TPS_REG_INT_CLEAR1, event1, intev_len);
671+
tps6598x_block_write(tps, TPS_REG_INT_CLEAR2, event2, intev_len);
672+
671673
if (!tps6598x_read_status(tps, &status))
672-
goto err_clear_ints;
674+
goto err_unlock;
673675

674676
if ((event1[0] | event2[0]) & TPS_REG_INT_POWER_STATUS_UPDATE)
675677
if (!tps6598x_read_power_status(tps))
676-
goto err_clear_ints;
678+
goto err_unlock;
677679

678680
if ((event1[0] | event2[0]) & TPS_REG_INT_DATA_STATUS_UPDATE)
679681
if (!tps6598x_read_data_status(tps))
680-
goto err_clear_ints;
682+
goto err_unlock;
681683

682684
/* Handle plug insert or removal */
683685
if ((event1[0] | event2[0]) & TPS_REG_INT_PLUG_EVENT)
684686
tps6598x_handle_plug_event(tps, status);
685687

686-
err_clear_ints:
687-
tps6598x_block_write(tps, TPS_REG_INT_CLEAR1, event1, intev_len);
688-
tps6598x_block_write(tps, TPS_REG_INT_CLEAR2, event2, intev_len);
689-
690688
err_unlock:
691689
mutex_unlock(&tps->lock);
692690

0 commit comments

Comments
 (0)