Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: 9ad9a52cce282 ("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>

authored by

Adrian Hunter and committed by
Alexandre Belloni
f3bcbfe1 fa9586bd

+33 -16
+33 -16
drivers/i3c/master/mipi-i3c-hci/dma.c
··· 439 439 } 440 440 } 441 441 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 + 442 469 static int hci_dma_queue_xfer(struct i3c_hci *hci, 443 470 struct hci_xfer *xfer_list, int n) 444 471 { ··· 473 446 struct hci_rh_data *rh; 474 447 unsigned int i, ring, enqueue_ptr; 475 448 u32 op1_val, op2_val; 449 + int ret; 450 + 451 + ret = hci_dma_map_xfer_list(hci, rings->sysdev, xfer_list, n); 452 + if (ret) 453 + return ret; 476 454 477 455 /* For now we only use ring 0 */ 478 456 ring = 0; ··· 488 456 for (i = 0; i < n; i++) { 489 457 struct hci_xfer *xfer = xfer_list + i; 490 458 u32 *ring_data = rh->xfer + rh->xfer_struct_sz * enqueue_ptr; 491 - enum dma_data_direction dir = xfer->rnw ? DMA_FROM_DEVICE : 492 - DMA_TO_DEVICE; 493 - bool need_bounce; 494 459 495 460 /* store cmd descriptor */ 496 461 *ring_data++ = xfer->cmd_desc[0]; ··· 506 477 507 478 /* 2nd and 3rd words of Data Buffer Descriptor Structure */ 508 479 if (xfer->data) { 509 - need_bounce = device_iommu_mapped(rings->sysdev) && 510 - xfer->rnw && 511 - xfer->data_len != ALIGN(xfer->data_len, 4); 512 - xfer->dma = i3c_master_dma_map_single(rings->sysdev, 513 - xfer->data, 514 - xfer->data_len, 515 - need_bounce, 516 - dir); 517 - if (!xfer->dma) { 518 - hci_dma_unmap_xfer(hci, xfer_list, i); 519 - return -ENOMEM; 520 - } 521 480 *ring_data++ = lower_32_bits(xfer->dma->addr); 522 481 *ring_data++ = upper_32_bits(xfer->dma->addr); 523 482 } else { ··· 528 511 op2_val = rh_reg_read(RING_OPERATION2); 529 512 if (enqueue_ptr == FIELD_GET(RING_OP2_CR_DEQ_PTR, op2_val)) { 530 513 /* the ring is full */ 531 - hci_dma_unmap_xfer(hci, xfer_list, i + 1); 514 + hci_dma_unmap_xfer(hci, xfer_list, n); 532 515 return -EBUSY; 533 516 } 534 517 }