From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 46BF248EC6C; Wed, 23 Sep 2026 14:26:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790173611; cv=none; b=JWaQGiEowZzmyid99FCOdOl4ThBorr/CmVGtyugxThWxmBzWMBHcYCoWR/w1J/XwUxDdhOcojLSFN22T0/ai67ue7Qn6OR5Kq3Nukq7n0ABX06I5mjjPhkxEzDHuE2osDweaBt+TgPOMa5aJRyyOoUFG+fbk6zaDmmVCNAuN3hc= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790173611; c=relaxed/simple; bh=x8KNG1/JLR6n7uBgfejx+KK9Gfd8B74C/RiyiH1HNkY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ctPV2D58ivCYzbyw5/PZF6m4XSSpei3548reRSEVOt06nb45Fdx9dHGQcvF5PrB2Vw0bAQLzF/S+Yg2PPgiVqk0XcQPb5X/QcbE9ghPF46JB2KHl+W3UcwRdJUbLomInlOtSqCtbPMM/zWZaexEvcZyL3O5aN2jTpP0s8FTfSuQ= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=g7Y+5pQz; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b="g7Y+5pQz" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AD88F1F000FF; Wed, 23 Sep 2026 14:26:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1790173609; bh=BR74iO8ELvojgXPzqvBeP5g+lSgT27InswQqsC4EOD0=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=g7Y+5pQz4xjv9pYr+JhjkQ/3z0lwF1nJ2syKxQrNi/k4bV1JcUQkn7tCv6R6hBHSw i03BxgK/A6c9XfGxekqrjqks+VpQe5W9BAo/EctghFV+veSs/jTlhrsqylBMYir+CY UkQNs/Nib6WvLfP7FSlvd0cuTe6eOZaaifjyA7ys= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, sashiko-bot , Leon Romanovsky , David Hu , =?UTF-8?q?Christian=20K=C3=B6nig?= Subject: [PATCH 7.2 293/438] dma-buf: Split sgl by largest page-aligned chunk Date: Wed, 23 Sep 2026 16:05:14 +0200 Message-ID: <20260923140652.372761464@linuxfoundation.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260923140644.756254324@linuxfoundation.org> References: <20260923140644.756254324@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore Precedence: bulk X-Mailing-List: patches@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 7.2-stable review patch. If anyone has any objections, please let me know. ------------------ From: David Hu commit 06dd5e1ae8ce4e129791087c8c66594950f0ba03 upstream. Currently, `fill_sg_entry()` splits the scatterlist using `UINT_MAX`. This creates a non-page-aligned DMA length (`0xFFFFFFFF`) for the first entry, resulting in non-page-aligned DMA addresses for all subsequent entries. While the underlying IOMMU mapping may be contiguous, hardware DMA engines often require explicit address alignment (e.g., page, cacheline, or storage sector boundaries). Passing unaligned addresses and lengths can cause explicit failures in DMA descriptor creation or silent data corruption if lower unaligned bits are truncated. In addition, a non-page-aligned sgl length will trigger an edge case in `ib_umem_find_best_pgsz()`. In case of a discontinuity in later buffers, we will have a `va` with lowest bit set to 1. That will lead to `ib_umem_find_best_pgsz()` always return 0, and break the promise to find best page size for the mapping on the NIC side. Fix this by splitting the scatterlist by the largest possible page aligned chunk within `UINT_MAX` (`ALIGN_DOWN(UINT_MAX, PAGE_SIZE)`). This ensures all scatterlist DMA addresses and lengths remain page aligned, while minimizing the total number of sgl entries. Page-aligned entries allow the system to cleanly chunk payloads into PCIe MaxPayloadSize (MPS) (e.g., 128 bytes, 256 bytes, 512 bytes). As a result, this may help reduce TLP fragmentation in P2P transfers and alleviate potential congestion within a logical PCIe switch partition, especially when Relaxed Ordering is not possible due to hardware constraints. Reported-by: sashiko-bot Closes: https://lore.kernel.org/all/20260609165431.778061F00893@smtp.kernel.org/ Fixes: 3aa31a8bb11e ("dma-buf: provide phys_vec to scatter-gather mapping routine") Cc: stable@vger.kernel.org Reviewed-by: Leon Romanovsky Signed-off-by: David Hu Signed-off-by: Christian König Link: https://lore.kernel.org/r/20260901170849.4052816-3-dhu@x6u.co Signed-off-by: Greg Kroah-Hartman --- drivers/dma-buf/dma-buf-mapping.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/dma-buf/dma-buf-mapping.c b/drivers/dma-buf/dma-buf-mapping.c index 80f6ab2f4809..833be519e1e6 100644 --- a/drivers/dma-buf/dma-buf-mapping.c +++ b/drivers/dma-buf/dma-buf-mapping.c @@ -6,16 +6,17 @@ #include #include #include +#include + +#define MAX_SG_ENT_SZ ALIGN_DOWN(UINT_MAX, PAGE_SIZE) static struct scatterlist *fill_sg_entry(struct scatterlist *sgl, size_t length, dma_addr_t addr) { - unsigned int len, nents; - unsigned int i; + size_t len; - nents = DIV_ROUND_UP(length, UINT_MAX); - for (i = 0; i < nents; i++) { - len = min_t(size_t, length, UINT_MAX); + while (length) { + len = min(length, MAX_SG_ENT_SZ); length -= len; /* * DMABUF abuses scatterlist to create a scatterlist @@ -25,8 +26,10 @@ static struct scatterlist *fill_sg_entry(struct scatterlist *sgl, size_t length, * does not require the CPU list for mapping or unmapping. */ sg_set_page(sgl, NULL, 0, 0); - sg_dma_address(sgl) = addr + (dma_addr_t)i * UINT_MAX; + sg_dma_address(sgl) = addr; sg_dma_len(sgl) = len; + addr += len; + /* Unconditionally advance. On last segment, this becomes NULL */ sgl = sg_next(sgl); } @@ -42,7 +45,7 @@ static unsigned int calc_sg_nents(struct dma_iova_state *state, if (!state || !dma_use_iova(state)) { for (i = 0; i < nr_ranges; i++) { - unsigned int added = DIV_ROUND_UP(phys_vec[i].len, UINT_MAX); + unsigned int added = DIV_ROUND_UP(phys_vec[i].len, MAX_SG_ENT_SZ); if (check_add_overflow(nents, added, &nents)) return 0; @@ -53,7 +56,7 @@ static unsigned int calc_sg_nents(struct dma_iova_state *state, * for whole IOVA address space, but we need to make sure * that it fits sg->length, maybe we need more. */ - nents = DIV_ROUND_UP(size, UINT_MAX); + nents = DIV_ROUND_UP(size, MAX_SG_ENT_SZ); } return nents; -- 2.55.0