Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions core_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,12 @@ int mx_sg_locate(struct sg_table *sgt, size_t byte_offset,
return -EINVAL;
}

/* First PRP chunk length within an SG entry starting at intra_off; truncates so subsequent chunks
* land on dma_size boundaries. Returns dma_size when already aligned. Works for arbitrary
* dma_size (compiler folds the modulo to a bitmask when dma_size is a known power of 2). */
/* First PRP chunk length at (sg, intra_off): distance to the next dma_size boundary of the
* mapped DMA address. Computed from sg_dma_address(), not the CPU page offset — the device
* splits by the address it receives, and SWIOTLB may not preserve the low address bits. */
size_t mx_prp_first_chunk_len(struct scatterlist *sg, size_t intra_off, size_t dma_size)
{
size_t off_in_page = (sg->offset + intra_off) & (PAGE_SIZE - 1);
size_t rem = off_in_page % dma_size;
size_t rem = (sg_dma_address(sg) + intra_off) % dma_size;

return rem ? (dma_size - rem) : dma_size;
}
Expand Down
20 changes: 8 additions & 12 deletions core_v2.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,11 +226,6 @@ static const struct mx_queue_ops v2_queue_ops = {
#define SINGLE_DMA_SIZE PAGE_SIZE
#define NUM_OF_DESC_PER_LIST (SINGLE_DMA_SIZE / sizeof(uint64_t))

/* create_mx_command_sg branches on host page count (split_pages_nr) but emits PRP entries of dma_size
* (= SINGLE_DMA_SIZE). Branching is correct only while these match. */
static_assert(SINGLE_DMA_SIZE == PAGE_SIZE,
"v2 PRP branching in create_mx_command_sg assumes SINGLE_DMA_SIZE == PAGE_SIZE");

static struct mx_command *alloc_mx_command(struct mx_transfer *transfer, int opcode)
{
struct mx_command *comm = (struct mx_command *)transfer->cmd_inline;
Expand All @@ -251,9 +246,7 @@ static void *create_mx_command_sg(struct mx_pci_dev *mx_pdev, struct mx_transfer
struct sg_table *sgt = &transfer->sg_ctx->sgt;
struct scatterlist *sg = NULL;
size_t intra_off = 0;
unsigned int slice_offset_in_page =
offset_in_page((uintptr_t)transfer->sg_ctx->user_addr + transfer->sg_byte_offset);
int split_pages_nr = DIV_ROUND_UP(slice_offset_in_page + transfer->size, PAGE_SIZE);
size_t desc_cnt;
int ret;

comm = alloc_mx_command(transfer, opcode);
Expand All @@ -274,19 +267,22 @@ static void *create_mx_command_sg(struct mx_pci_dev *mx_pdev, struct mx_transfer
return NULL;
}

if (split_pages_nr == 1) {
/* Branch on the DMA-side entry count, not host page count (alignments can differ). */
desc_cnt = mx_get_total_desc_count(sg, intra_off, transfer->size, SINGLE_DMA_SIZE, false);

if (desc_cnt == 1) {
comm->prp_entry2 = 0;
} else if (split_pages_nr == 2) {
} else if (desc_cnt == 2) {
size_t first_len = mx_prp_first_chunk_len(sg, intra_off, SINGLE_DMA_SIZE);

/* Second PRP entry points to the page after the first chunk. */
/* Second PRP entry points to the chunk after the first. */
if (intra_off + first_len < sg_dma_len(sg)) {
comm->prp_entry2 = comm->prp_entry1 + first_len;
} else {
struct scatterlist *next = sg_next(sg);

if (!next) {
pr_warn("sg_next NULL in 2-page path (id=%u)\n", transfer->id);
pr_warn("sg_next NULL in 2-entry path (id=%u)\n", transfer->id);
return NULL;
}
comm->prp_entry2 = sg_dma_address(next);
Expand Down
4 changes: 2 additions & 2 deletions mx_dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -423,8 +423,8 @@ uint64_t mx_desc_list_init(struct mx_pci_dev *mx_pdev, struct mx_transfer *trans
int mx_sg_locate(struct sg_table *sgt, size_t byte_offset,
struct scatterlist **out_sg, size_t *out_intra);

/* First PRP chunk length when starting intra_off bytes into an SG entry; truncates so subsequent
* chunks land on dma_size boundaries. Returns dma_size when already aligned. See core_common.c. */
/* First PRP chunk length at (sg, intra_off); splits fall on dma_size boundaries of the mapped
* DMA address. See core_common.c. */
size_t mx_prp_first_chunk_len(struct scatterlist *sg, size_t intra_off, size_t dma_size);

void mx_stop_queue_threads(struct mx_pci_dev *mx_pdev);
Expand Down