[PATCH V3 08/16] i3c: mipi-i3c-hci: Avoid restarting DMA ring after aborting wrong transfer

Adrian Hunter adrian.hunter at intel.com
Thu May 14 22:30:21 PDT 2026


On 12/05/2026 19:50, Frank Li wrote:
> On Mon, May 04, 2026 at 02:33:44PM +0300, Adrian Hunter wrote:
>> Software ABORT of the DMA ring is used to recover from transfer list
>> timeouts, but it is inherently racy.  The intended transfer list may
>> complete just before the ABORT takes effect, causing the subsequent
>> transfer list to be aborted instead.
>>
>> In this case, an incomplete transfer list may remain in the ring and has
>> not yet been processed by hci_dma_dequeue_xfer().  Restarting the DMA
>> ring at that point can lead to unpredictable results.
>>
>> Detect when the next queued transfer is not the first entry of a transfer
>> list and does not belong to the list currently being dequeued.  In that
>> case, skip restarting the DMA ring and defer recovery until a subsequent
>> call to hci_dma_dequeue_xfer(), which will safely restart the ring once
>> the incomplete list is handled.
>>
>> Signed-off-by: Adrian Hunter <adrian.hunter at intel.com>
>> ---
>>
>>
>> Changes in V3:
>>
>> 	None
>>
>> Changes in V2:
>>
>> 	Renamed completing_xfer to final_xfer
>>
>>
>>  drivers/i3c/master/mipi-i3c-hci/dma.c | 15 +++++++++++++++
>>  drivers/i3c/master/mipi-i3c-hci/hci.h |  1 +
>>  2 files changed, 16 insertions(+)
>>
>> diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
>> index 899fdf6555a8..268f54b32101 100644
>> --- a/drivers/i3c/master/mipi-i3c-hci/dma.c
>> +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
>> @@ -503,6 +503,7 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci,
>>  		u32 *ring_data = rh->xfer + rh->xfer_struct_sz * enqueue_ptr;
>>
>>  		xfer->final_xfer = xfer_list + n - 1;
>> +		xfer->xfer_list_pos = i;
>>
>>  		/* store cmd descriptor */
>>  		*ring_data++ = xfer->cmd_desc[0];
>> @@ -669,6 +670,20 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci,
>>  		}
>>  	}
>>
>> +	/*
>> +	 * A software ABORT may race with transfer completion and abort the next
>> +	 * transfer list instead. Detect that case, and do not restart the ring.
>> +	 * It will be handled by a subsequent dequeue.
>> +	 */
>> +	if (!did_unqueue) {
>> +		struct hci_xfer *xfer = rh->src_xfers[rh->done_ptr];
>> +
>> +		if (xfer && xfer->xfer_list_pos && xfer->final_xfer != xfer_list->final_xfer) {
>> +			spin_unlock_irq(&hci->lock);
> 
> Is it possible to use auto cleanup to handle lock()?

No, there are 2 paths that do not return directly after unlocking
and do different things.

> 
> Frank
>> +			return false;
>> +		}
>> +	}
>> +
>>  	/* restart the ring */
>>  	reinit_completion(&rh->op_done);
>>  	mipi_i3c_hci_resume(hci);
>> diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h
>> index f07fc627d4d2..83d4f13a68a3 100644
>> --- a/drivers/i3c/master/mipi-i3c-hci/hci.h
>> +++ b/drivers/i3c/master/mipi-i3c-hci/hci.h
>> @@ -107,6 +107,7 @@ struct hci_xfer {
>>  			struct hci_xfer *final_xfer;
>>  			int ring_number;
>>  			int ring_entry;
>> +			int xfer_list_pos;
>>  		};
>>  	};
>>  };
>> --
>> 2.51.0
>>




More information about the linux-i3c mailing list