Skip to content

Commit 9548742

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 3e96cd2 commit 9548742

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
@@ -491,24 +491,23 @@ static irqreturn_t cd321x_interrupt(int irq, void *data)
491491
if (!event)
492492
goto err_unlock;
493493

494+
tps6598x_write64(tps, TPS_REG_INT_CLEAR1, event);
495+
494496
if (!tps6598x_read_status(tps, &status))
495-
goto err_clear_ints;
497+
goto err_unlock;
496498

497499
if (event & APPLE_CD_REG_INT_POWER_STATUS_UPDATE)
498500
if (!tps6598x_read_power_status(tps))
499-
goto err_clear_ints;
501+
goto err_unlock;
500502

501503
if (event & APPLE_CD_REG_INT_DATA_STATUS_UPDATE)
502504
if (!tps6598x_read_data_status(tps))
503-
goto err_clear_ints;
505+
goto err_unlock;
504506

505507
/* Handle plug insert or removal */
506508
if (event & APPLE_CD_REG_INT_PLUG_EVENT)
507509
tps6598x_handle_plug_event(tps, status);
508510

509-
err_clear_ints:
510-
tps6598x_write64(tps, TPS_REG_INT_CLEAR1, event);
511-
512511
err_unlock:
513512
mutex_unlock(&tps->lock);
514513

@@ -555,25 +554,24 @@ static irqreturn_t tps6598x_interrupt(int irq, void *data)
555554
if (!(event1[0] | event1[1] | event2[0] | event2[1]))
556555
goto err_unlock;
557556

557+
tps6598x_block_write(tps, TPS_REG_INT_CLEAR1, event1, intev_len);
558+
tps6598x_block_write(tps, TPS_REG_INT_CLEAR2, event2, intev_len);
559+
558560
if (!tps6598x_read_status(tps, &status))
559-
goto err_clear_ints;
561+
goto err_unlock;
560562

561563
if ((event1[0] | event2[0]) & TPS_REG_INT_POWER_STATUS_UPDATE)
562564
if (!tps6598x_read_power_status(tps))
563-
goto err_clear_ints;
565+
goto err_unlock;
564566

565567
if ((event1[0] | event2[0]) & TPS_REG_INT_DATA_STATUS_UPDATE)
566568
if (!tps6598x_read_data_status(tps))
567-
goto err_clear_ints;
569+
goto err_unlock;
568570

569571
/* Handle plug insert or removal */
570572
if ((event1[0] | event2[0]) & TPS_REG_INT_PLUG_EVENT)
571573
tps6598x_handle_plug_event(tps, status);
572574

573-
err_clear_ints:
574-
tps6598x_block_write(tps, TPS_REG_INT_CLEAR1, event1, intev_len);
575-
tps6598x_block_write(tps, TPS_REG_INT_CLEAR2, event2, intev_len);
576-
577575
err_unlock:
578576
mutex_unlock(&tps->lock);
579577

0 commit comments

Comments
 (0)