Skip to content

Commit 9552f27

Browse files
svenpeter42jannau
authored andcommitted
usb: typec: tipd: Clear interrupts first
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: stable <stable@kernel.org> Signed-off-by: Sven Peter <sven@svenpeter.dev>
1 parent ee6cb78 commit 9552f27

1 file changed

Lines changed: 11 additions & 13 deletions

File tree

drivers/usb/typec/tipd/core.c

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

553+
tps6598x_write64(tps, TPS_REG_INT_CLEAR1, event);
554+
553555
if (!tps6598x_read_status(tps, &status))
554-
goto err_clear_ints;
556+
goto err_unlock;
555557

556558
if (event & APPLE_CD_REG_INT_POWER_STATUS_UPDATE)
557559
if (!tps6598x_read_power_status(tps))
558-
goto err_clear_ints;
560+
goto err_unlock;
559561

560562
if (event & APPLE_CD_REG_INT_DATA_STATUS_UPDATE)
561563
if (!tps6598x_read_data_status(tps))
562-
goto err_clear_ints;
564+
goto err_unlock;
563565

564566
/* Handle plug insert or removal */
565567
if (event & APPLE_CD_REG_INT_PLUG_EVENT)
566568
tps6598x_handle_plug_event(tps, status);
567569

568-
err_clear_ints:
569-
tps6598x_write64(tps, TPS_REG_INT_CLEAR1, event);
570-
571570
err_unlock:
572571
mutex_unlock(&tps->lock);
573572

@@ -673,25 +672,24 @@ static irqreturn_t tps6598x_interrupt(int irq, void *data)
673672
if (!(event1[0] | event1[1] | event2[0] | event2[1]))
674673
goto err_unlock;
675674

675+
tps6598x_block_write(tps, TPS_REG_INT_CLEAR1, event1, intev_len);
676+
tps6598x_block_write(tps, TPS_REG_INT_CLEAR2, event2, intev_len);
677+
676678
if (!tps6598x_read_status(tps, &status))
677-
goto err_clear_ints;
679+
goto err_unlock;
678680

679681
if ((event1[0] | event2[0]) & TPS_REG_INT_POWER_STATUS_UPDATE)
680682
if (!tps6598x_read_power_status(tps))
681-
goto err_clear_ints;
683+
goto err_unlock;
682684

683685
if ((event1[0] | event2[0]) & TPS_REG_INT_DATA_STATUS_UPDATE)
684686
if (!tps6598x_read_data_status(tps))
685-
goto err_clear_ints;
687+
goto err_unlock;
686688

687689
/* Handle plug insert or removal */
688690
if ((event1[0] | event2[0]) & TPS_REG_INT_PLUG_EVENT)
689691
tps6598x_handle_plug_event(tps, status);
690692

691-
err_clear_ints:
692-
tps6598x_block_write(tps, TPS_REG_INT_CLEAR1, event1, intev_len);
693-
tps6598x_block_write(tps, TPS_REG_INT_CLEAR2, event2, intev_len);
694-
695693
err_unlock:
696694
mutex_unlock(&tps->lock);
697695

0 commit comments

Comments
 (0)