Skip to content

Commit f3bcbfe

Browse files
ahunter6alexandrebelloni
authored andcommitted
i3c: mipi-i3c-hci: Factor out DMA mapping from queuing path
Prepare for fixing a race in the DMA ring enqueue path when handling parallel transfers. Move all DMA mapping out of hci_dma_queue_xfer() and into a new helper that performs the mapping up front. This refactoring allows the upcoming fix to extend the spinlock coverage around the enqueue operation without performing DMA mapping under the spinlock. No functional change is intended in this patch. Fixes: 9ad9a52 ("i3c/master: introduce the mipi-i3c-hci driver") Cc: stable@vger.kernel.org Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Reviewed-by: Frank Li <Frank.Li@nxp.com> Link: https://patch.msgid.link/20260306072451.11131-4-adrian.hunter@intel.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
1 parent fa9586b commit f3bcbfe

1 file changed

Lines changed: 33 additions & 16 deletions

File tree

  • drivers/i3c/master/mipi-i3c-hci

drivers/i3c/master/mipi-i3c-hci/dma.c

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -439,13 +439,45 @@ static void hci_dma_unmap_xfer(struct i3c_hci *hci,
439439
}
440440
}
441441

442+
static struct i3c_dma *hci_dma_map_xfer(struct device *dev, struct hci_xfer *xfer)
443+
{
444+
enum dma_data_direction dir = xfer->rnw ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
445+
bool need_bounce = device_iommu_mapped(dev) && xfer->rnw && (xfer->data_len & 3);
446+
447+
return i3c_master_dma_map_single(dev, xfer->data, xfer->data_len, need_bounce, dir);
448+
}
449+
450+
static int hci_dma_map_xfer_list(struct i3c_hci *hci, struct device *dev,
451+
struct hci_xfer *xfer_list, int n)
452+
{
453+
for (int i = 0; i < n; i++) {
454+
struct hci_xfer *xfer = xfer_list + i;
455+
456+
if (!xfer->data)
457+
continue;
458+
459+
xfer->dma = hci_dma_map_xfer(dev, xfer);
460+
if (!xfer->dma) {
461+
hci_dma_unmap_xfer(hci, xfer_list, i);
462+
return -ENOMEM;
463+
}
464+
}
465+
466+
return 0;
467+
}
468+
442469
static int hci_dma_queue_xfer(struct i3c_hci *hci,
443470
struct hci_xfer *xfer_list, int n)
444471
{
445472
struct hci_rings_data *rings = hci->io_data;
446473
struct hci_rh_data *rh;
447474
unsigned int i, ring, enqueue_ptr;
448475
u32 op1_val, op2_val;
476+
int ret;
477+
478+
ret = hci_dma_map_xfer_list(hci, rings->sysdev, xfer_list, n);
479+
if (ret)
480+
return ret;
449481

450482
/* For now we only use ring 0 */
451483
ring = 0;
@@ -456,9 +488,6 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci,
456488
for (i = 0; i < n; i++) {
457489
struct hci_xfer *xfer = xfer_list + i;
458490
u32 *ring_data = rh->xfer + rh->xfer_struct_sz * enqueue_ptr;
459-
enum dma_data_direction dir = xfer->rnw ? DMA_FROM_DEVICE :
460-
DMA_TO_DEVICE;
461-
bool need_bounce;
462491

463492
/* store cmd descriptor */
464493
*ring_data++ = xfer->cmd_desc[0];
@@ -477,18 +506,6 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci,
477506

478507
/* 2nd and 3rd words of Data Buffer Descriptor Structure */
479508
if (xfer->data) {
480-
need_bounce = device_iommu_mapped(rings->sysdev) &&
481-
xfer->rnw &&
482-
xfer->data_len != ALIGN(xfer->data_len, 4);
483-
xfer->dma = i3c_master_dma_map_single(rings->sysdev,
484-
xfer->data,
485-
xfer->data_len,
486-
need_bounce,
487-
dir);
488-
if (!xfer->dma) {
489-
hci_dma_unmap_xfer(hci, xfer_list, i);
490-
return -ENOMEM;
491-
}
492509
*ring_data++ = lower_32_bits(xfer->dma->addr);
493510
*ring_data++ = upper_32_bits(xfer->dma->addr);
494511
} else {
@@ -511,7 +528,7 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci,
511528
op2_val = rh_reg_read(RING_OPERATION2);
512529
if (enqueue_ptr == FIELD_GET(RING_OP2_CR_DEQ_PTR, op2_val)) {
513530
/* the ring is full */
514-
hci_dma_unmap_xfer(hci, xfer_list, i + 1);
531+
hci_dma_unmap_xfer(hci, xfer_list, n);
515532
return -EBUSY;
516533
}
517534
}

0 commit comments

Comments
 (0)