From nobody Wed Dec 17 10:00:13 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 27D211F0E37; Fri, 21 Mar 2025 09:52:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1742550765; cv=none; b=nrnuMoVg7sN3UA+iHCYpBVe9z06X8fQFli2W/sm0UwFiU20taH9zOis4BcTRCbcAqXRo4qvWZPSTdFelInbNTLQ90VlXAIvXQ3ffzzV5rGYwzmrf6etXDw1nmfMxpGMzfx6Th5THUlnjD9HxtZSFmrkdGjzMokRi7x1AtQh3PNs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1742550765; c=relaxed/simple; bh=NSVAITNBqV2fChMLATBR7BnFfMZSXgBvEHhNVh9sGMI=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=tJStJngn/cdowe6sMRp+ZXp5QSp+QjPc6U07rjXVXzRft2fNdWgW0SlFEanJx3BJTrRZ9bbyByuQk4XNTOLdT3SpmPobXxJQCXfdWVm/tZ53jFzjqLH9QnX0MI3m5P6/E4igUQDMvLH22o9P/nZ/KMQyADb7/uq5vfoJFN853CM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=liheWtiS; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="liheWtiS" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 90ADAC4CEE3; Fri, 21 Mar 2025 09:52:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1742550764; bh=NSVAITNBqV2fChMLATBR7BnFfMZSXgBvEHhNVh9sGMI=; h=From:To:Cc:Subject:Date:From; b=liheWtiSlemz6WGHszVKHmgrdO5t8mc5pNqvSBtAfZL+XpiKWTQWbQIAcomAKUGZk NeRbbF87LAsjlG8VIbIsBsrOWod1yn0S1VFlAhaLJPh4kBj9yhIu7ACNqSXmixKLjj d3qC4+2YcIHNCkbb4rzw3t4FZW/mvpUAEO1Q0p5+XpPLmUgLjr59Qj/MLJiVKTNbvv ZKuWp0M5MRPsS+hRVGeC6bg3/0q2eJEespSlF9/f/keoJ7ENchU+9AyN4bhwbtcY8S 47Zfn2D5XC0r1V0Oa7jV8cnfHVX+Pn7Lh5Y8Q1H9CbQsqiR2TJ4HeqVomigTjx1FZX ALl+YoqIcYrPw== Received: from johan by xi.lan with local (Exim 4.97.1) (envelope-from ) id 1tvZ3W-0000000053C-26Gm; Fri, 21 Mar 2025 10:52:46 +0100 From: Johan Hovold To: Jeff Johnson Cc: Miaoqing Pan , Steev Klimaszewski , Clayton Craft , Jens Glathe , ath12k@lists.infradead.org, linux-kernel@vger.kernel.org, Johan Hovold , stable@vger.kernel.org Subject: [PATCH] wifi: ath12k: fix ring-buffer corruption Date: Fri, 21 Mar 2025 10:52:19 +0100 Message-ID: <20250321095219.19369-1-johan+linaro@kernel.org> X-Mailer: git-send-email 2.48.1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Users of the Lenovo ThinkPad X13s have reported that Wi-Fi sometimes breaks and the log fills up with errors like: ath11k_pci 0006:01:00.0: HTC Rx: insufficient length, got 1484, expecte= d 1492 ath11k_pci 0006:01:00.0: HTC Rx: insufficient length, got 1460, expecte= d 1484 which based on a quick look at the ath11k driver seemed to indicate some kind of ring-buffer corruption. Miaoqing Pan tracked it down to the host seeing the updated destination ring head pointer before the updated descriptor, and the error handling for that in turn leaves the ring buffer in an inconsistent state. While this has not yet been observed with ath12k, the ring-buffer implementation is very similar to the ath11k one and it suffers from the same bugs. Add the missing memory barrier to make sure that the descriptor is read after the head pointer to address the root cause of the corruption while fixing up the error handling in case there are ever any (ordering) bugs on the device side. Note that the READ_ONCE() are only needed to avoid compiler mischief in case the ring-buffer helpers are ever inlined. Tested-on: WCN7850 hw2.0 WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICON= Z-3 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Cc: stable@vger.kernel.org # 6.3 Link: https://bugzilla.kernel.org/show_bug.cgi?id=3D218623 Link: https://lore.kernel.org/20250310010217.3845141-3-quic_miaoqing@quicin= c.com Cc: Miaoqing Pan Signed-off-by: Johan Hovold Reviewed-by: Miaoqing Pan --- drivers/net/wireless/ath/ath12k/ce.c | 11 +++++------ drivers/net/wireless/ath/ath12k/hal.c | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/ce.c b/drivers/net/wireless/at= h/ath12k/ce.c index be0d669d31fc..740586fe49d1 100644 --- a/drivers/net/wireless/ath/ath12k/ce.c +++ b/drivers/net/wireless/ath/ath12k/ce.c @@ -343,11 +343,10 @@ static int ath12k_ce_completed_recv_next(struct ath12= k_ce_pipe *pipe, goto err; } =20 + /* Make sure descriptor is read after the head pointer. */ + dma_rmb(); + *nbytes =3D ath12k_hal_ce_dst_status_get_length(desc); - if (*nbytes =3D=3D 0) { - ret =3D -EIO; - goto err; - } =20 *skb =3D pipe->dest_ring->skb[sw_index]; pipe->dest_ring->skb[sw_index] =3D NULL; @@ -380,8 +379,8 @@ static void ath12k_ce_recv_process_cb(struct ath12k_ce_= pipe *pipe) dma_unmap_single(ab->dev, ATH12K_SKB_RXCB(skb)->paddr, max_nbytes, DMA_FROM_DEVICE); =20 - if (unlikely(max_nbytes < nbytes)) { - ath12k_warn(ab, "rxed more than expected (nbytes %d, max %d)", + if (unlikely(max_nbytes < nbytes || nbytes =3D=3D 0)) { + ath12k_warn(ab, "unexpected rx length (nbytes %d, max %d)", nbytes, max_nbytes); dev_kfree_skb_any(skb); continue; diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/a= th/ath12k/hal.c index cd59ff8e6c7b..91d5126ca149 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -1962,7 +1962,7 @@ u32 ath12k_hal_ce_dst_status_get_length(struct hal_ce= _srng_dst_status_desc *desc { u32 len; =20 - len =3D le32_get_bits(desc->flags, HAL_CE_DST_STATUS_DESC_FLAGS_LEN); + len =3D le32_get_bits(READ_ONCE(desc->flags), HAL_CE_DST_STATUS_DESC_FLAG= S_LEN); desc->flags &=3D ~cpu_to_le32(HAL_CE_DST_STATUS_DESC_FLAGS_LEN); =20 return len; @@ -2132,7 +2132,7 @@ void ath12k_hal_srng_access_begin(struct ath12k_base = *ab, struct hal_srng *srng) srng->u.src_ring.cached_tp =3D *(volatile u32 *)srng->u.src_ring.tp_addr; else - srng->u.dst_ring.cached_hp =3D *srng->u.dst_ring.hp_addr; + srng->u.dst_ring.cached_hp =3D READ_ONCE(*srng->u.dst_ring.hp_addr); } =20 /* Update cached ring head/tail pointers to HW. ath12k_hal_srng_access_beg= in() --=20 2.48.1