From nobody Tue Sep 29 06:58:37 2026 Received: from out-185.mta1.migadu.com (out-185.mta1.migadu.com [95.215.58.185]) (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 A8BFF41DE04 for ; Tue, 11 Aug 2026 09:13:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.185 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786439599; cv=none; b=Sghk4XVcrJ0nusX0Y4UfxXko9giMHxLb40mfWo/ZAMC1UKXjR+DkAhLGZ4+k+k7O0WXk96EKvyCEE770uyesD2bSD7mNnXR4c3jHsTBXzby7ToPhrxSdHSYhbvJf+35YHWfjTJ9cDpTmfIq3j4afbcwfwpSnMRn+/M6MDuSrP44= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786439599; c=relaxed/simple; bh=skDLPIA5lpTzmQkNYeIR+vNdfgVXxuMeyYT2OSW/92A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pU9XKwkeA8Uy6RvToFsjeZvhh4o5pBNnTvHu0HX+hXeklQkv6ysC0yLXBnSZeRi+CVXHuIQdD/XhMAXcpFNi7K795YEF/1exiiIdz1kOo6RERFa2pRYpNslB6iSLyS5jAPK5bV5Yx9tnigE4fTUzoMdRtcJsPp2Y3pQ/1oVRvi4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=k/LFD55M; arc=none smtp.client-ip=95.215.58.185 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="k/LFD55M" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1786439591; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zIDZMZqDN1uS5+Ef/EHX8qRaF9h5xnkFXzTuE9h2rO4=; b=k/LFD55MuafTojUMvV1Y3zHuoCN2Rssa1ERmOz/cnj/M/vD7KxUNVL6TuUWfRCsLKBIMIR 9P0dXIxvMHEh4ee8opN8bOztvSx19QV8Cl0LuF+ullOzyaBzX69v4HKNNQKFPLd5MUOW1W wY8R0mOdMWV9zrx3jZCEVp5/ttWsess= From: luka.gejak@linux.dev To: Ping-Ke Shih , linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Michael Straube , Bitterblue Smith , Peter Robinson , Hans de Goede , Luka Gejak Subject: [PATCH v4 1/7] wifi: rtw88: add the RTL8723B chip type and SDIO helper Date: Tue, 11 Aug 2026 09:11:57 +0000 Message-ID: <20260811091203.26841-2-luka.gejak@linux.dev> In-Reply-To: <20260811091203.26841-1-luka.gejak@linux.dev> References: <20260811091203.26841-1-luka.gejak@linux.dev> 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 X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Luka Gejak The RTL8723B is a 802.11n combo chip whose SDIO variant, RTL8723BS, runs a Realtek vendor firmware that differs from the firmware used by the other rtw88 8723 family devices. Supporting it needs a number of small adjustments spread across the shared core, all of which have to be restricted to this one chip and bus combination. Add the chip type and a helper that tests for it, so the changes that follow can be gated without repeating the chip and bus comparison. Signed-off-by: Luka Gejak Acked-by: Ping-Ke Shih --- drivers/net/wireless/realtek/rtw88/main.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wirele= ss/realtek/rtw88/main.h index c6e981ba7986..8f86f7c12de5 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -194,6 +194,7 @@ enum rtw_chip_type { RTW_CHIP_TYPE_8723D, RTW_CHIP_TYPE_8821C, RTW_CHIP_TYPE_8703B, + RTW_CHIP_TYPE_8723B, RTW_CHIP_TYPE_8821A, RTW_CHIP_TYPE_8812A, RTW_CHIP_TYPE_8814A, @@ -2194,6 +2195,12 @@ static inline bool rtw_chip_has_tx_stbc(struct rtw_d= ev *rtwdev) return rtwdev->chip->tx_stbc; } =20 +static inline bool rtw_is_8723bs(struct rtw_dev *rtwdev) +{ + return rtwdev->chip->id =3D=3D RTW_CHIP_TYPE_8723B && + rtwdev->hci.type =3D=3D RTW_HCI_TYPE_SDIO; +} + static inline u8 rtw_acquire_macid(struct rtw_dev *rtwdev) { unsigned long mac_id; --=20 2.53.0 From nobody Tue Sep 29 06:58:37 2026 Received: from out-189.mta1.migadu.com (mta1.migadu.com [37.59.57.117]) (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 37074426EDA for ; Tue, 11 Aug 2026 09:13:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=37.59.57.117 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786439601; cv=none; b=kKmM2PBCn4rpVkiX7GAvQjcas8nHNSMzf3oxIolbckeBXspA51RZM+eflg+tS1vVgaQANZGGzhMd4c0PxB7Q9INUFCvCEG71BpKPhlTWgzMBIkeGtrqj4oawn+ljaAyF7OzWm3ARZj2Y7Sojc+uO7+FZczblMAcr2yUHBUZtTek= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786439601; c=relaxed/simple; bh=XOpYD6I4JlkbBLnsmaDU2z1GtAYOgs2KWDmPkI4vHbI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ryBh7yMG9z3qj4GGUpurwZy4fvSFd4jPWzq1dY5FuLBJXbWevMm/Shj5kkmaI8EU8uKDXEgwHPYp3RVcmf2W1BY0lE3tl1oigAiyoMfhMMhUv1UmYpj2eLhFn5ZsGeOeQP8H3eQ42mn4Kn56+H9qWHVryVpRRcekH/hFi2oS6tk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=tvq0BwCv; arc=none smtp.client-ip=37.59.57.117 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="tvq0BwCv" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1786439593; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uu7M6NtujFaEuvcioOiMlJdOPXugliUXHR5sYjd60P0=; b=tvq0BwCv+5B1n9iGaRk6O2WjLDDDWy9PFNbS3vYuqymnYHpIL4iL3kXXM0DwybcipZlaUA yL/E8+5gAE9Zpt+b9jlrYGOlPoTbEXZirhZFYF5uB7KRNuOhKwPl1h96V/ti0F4Fpx0wiI HEKjlIao9dnTllgRXIV7cOUYwAjRcGs= From: luka.gejak@linux.dev To: Ping-Ke Shih , linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Michael Straube , Bitterblue Smith , Peter Robinson , Hans de Goede , Luka Gejak Subject: [PATCH v4 2/7] wifi: rtw88: rx: mark zero length packets on RTL8723BS Date: Tue, 11 Aug 2026 09:11:58 +0000 Message-ID: <20260811091203.26841-3-luka.gejak@linux.dev> In-Reply-To: <20260811091203.26841-1-luka.gejak@linux.dev> References: <20260811091203.26841-1-luka.gejak@linux.dev> 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 X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Luka Gejak Like the RTL8703B, the RTL8723BS reports receive descriptors with a zero packet length, which the vendor driver drops outright. rtw88 already flags these as having no PSDU for the RTL8703B, so extend the same handling rather than passing an empty frame up. This is gated on the SDIO interface rather than the chip id, because it has only been observed there; the USB variant is not known to do it. Co-developed-by: Michael Straube Signed-off-by: Michael Straube Signed-off-by: Luka Gejak --- drivers/net/wireless/realtek/rtw88/rx.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/rx.c b/drivers/net/wireless= /realtek/rtw88/rx.c index 01fd299abb7f..a9361ef4b93c 100644 --- a/drivers/net/wireless/realtek/rtw88/rx.c +++ b/drivers/net/wireless/realtek/rtw88/rx.c @@ -253,10 +253,12 @@ static void rtw_rx_fill_rx_status(struct rtw_dev *rtw= dev, =20 rtw_rx_addr_match(rtwdev, pkt_stat, hdr); =20 - /* Rtl8723cs driver checks for size < 14 or size > 8192 and - * simply drops the packet. + /* + * Rtl8723cs and rtl8723bs drivers check for size < 14 or size > 8192 + * and simply drop the packet. */ - if (rtwdev->chip->id =3D=3D RTW_CHIP_TYPE_8703B && pkt_stat->pkt_len =3D= =3D 0) { + if ((rtwdev->chip->id =3D=3D RTW_CHIP_TYPE_8703B || rtw_is_8723bs(rtwdev)= ) && + pkt_stat->pkt_len =3D=3D 0) { rx_status->flag |=3D RX_FLAG_NO_PSDU; rtw_dbg(rtwdev, RTW_DBG_RX, "zero length packet"); } --=20 2.53.0 From nobody Tue Sep 29 06:58:37 2026 Received: from out-179.mta1.migadu.com (out-179.mta1.migadu.com [95.215.58.179]) (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 541574266A0 for ; Tue, 11 Aug 2026 09:13:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786439601; cv=none; b=byjlTDf4RIj3PyKIo3dQ0iSg6P6rvRDZwfFtMjb3fhZKw5qoLLfGQBvQ901Blnrscita9+0RwTeYYbJJFzpVr3yXnAhOERYuem2tbN9/zaImw0DTA1pDiNkNjsuVuSt3DN0MJcBh6tN2BDUeuShgiRUT+va7nZGATqu8+RdXoJA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786439601; c=relaxed/simple; bh=bBMtPwnUaSSmNaOEQTtaDgpifcganP+lIU5ruxDTC7Q=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CCHH14pviVqwRUv8MGfyVc2lUc09aqhaopFHV6Zsfe8TZ3P86my3nP+OuHHcbiOaunE6dysXyB+sfAD5TXDSaDDSFrFKj9yozf5EOQstmoAT0xRI3LXgnQ03YVBZPJT4/3HRr0qgTgLhYYiYBK2cgP2DyKQjD/0Sbrz+du1PhzQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=MRZCAp3r; arc=none smtp.client-ip=95.215.58.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="MRZCAp3r" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1786439594; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6IvYbmBDq80Dbn4/D/hp7UJyeiL7ht7xUCRZybelgYU=; b=MRZCAp3rlTrSojrleiWufvrjChig20JWHZWLgjRtrc6LEXcHvsBZNEwnG68CQC5x9mJ7y/ 8L1r2mpZWIRq67msCbrg9ZUEDZPXg39DmGsZlwO4E+7cBKu6g6vMGgOB66L579FrVVioxQ /IkCUUxan2l7p7ko03cOVCeq43V3jXg= From: luka.gejak@linux.dev To: Ping-Ke Shih , linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Michael Straube , Bitterblue Smith , Peter Robinson , Hans de Goede , Luka Gejak Subject: [PATCH v4 3/7] wifi: rtw88: tx: extend the TX report purge timeout to RTL8723BS Date: Tue, 11 Aug 2026 09:11:59 +0000 Message-ID: <20260811091203.26841-4-luka.gejak@linux.dev> In-Reply-To: <20260811091203.26841-1-luka.gejak@linux.dev> References: <20260811091203.26841-1-luka.gejak@linux.dev> 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 X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Luka Gejak Commit c80788f7c5ae ("wifi: rtw88: increase TX report timeout to fix race condition") raised the purge timeout to 2500 ms for the RTL8723DU, because the firmware can stay off channel during background scans for longer than the 500 ms default, which delays the TX reports and lets the purge timer drop the tracking skbs. The host stack then reads the missing status as loss and collapses TCP throughput. The RTL8723BS runs the same vendor firmware over a slower SDIO host and hits the same race. Testers on ARM SDIO boards see "failed to get tx report from firmware" under load, with the same throughput collapse. Extend the 2500 ms timeout to the RTL8723BS. Reported-by: Peter Robinson Closes: https://lore.kernel.org/all/CALeDE9PgQmpMfDt1DgfLD4tBFGH0MZ7GncV6RU= EOHhHbKF+TdQ@mail.gmail.com/ Signed-off-by: Luka Gejak Acked-by: Ping-Ke Shih --- drivers/net/wireless/realtek/rtw88/tx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless= /realtek/rtw88/tx.c index 9d747a060b98..797c1e0402f2 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -208,8 +208,9 @@ void rtw_tx_report_enqueue(struct rtw_dev *rtwdev, stru= ct sk_buff *skb, u8 sn) __skb_queue_tail(&tx_report->queue, skb); spin_unlock_irqrestore(&tx_report->q_lock, flags); =20 - if (rtwdev->chip->id =3D=3D RTW_CHIP_TYPE_8723D && - rtwdev->hci.type =3D=3D RTW_HCI_TYPE_USB) + if ((rtwdev->chip->id =3D=3D RTW_CHIP_TYPE_8723D && + rtwdev->hci.type =3D=3D RTW_HCI_TYPE_USB) || + rtw_is_8723bs(rtwdev)) timeout =3D msecs_to_jiffies(2500); =20 mod_timer(&tx_report->purge_timer, jiffies + timeout); --=20 2.53.0 From nobody Tue Sep 29 06:58:37 2026 Received: from out-187.mta1.migadu.com (out-187.mta1.migadu.com [95.215.58.187]) (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 9908F429029 for ; Tue, 11 Aug 2026 09:13:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.187 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786439602; cv=none; b=jtLDW5RZaRQJ8hC+oownSe6qY+SvqWLNPOpf1J/kGOMwJONr/8oRgUnx1HtIyD1j8JEVd7XUIo6HCc7ASemTaqCYjWQxHq9GgSmxZ/NYQ2fqiOfzTRl2GKh/kOgw6ULx2F2e+vjJV1/lzvg+K7xNUlzXpjnpfr6TjN6sNzNfWQU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786439602; c=relaxed/simple; bh=aYEhSErMUHMJF+BL3ou4EFarOMEm0VRKpbm8x6XblxQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Nfr6iwfRGKvxl3Je8TCyo/CMg7zFXzkrkgEJedaoqNzbEB9sPpjz9dM0wgpUT7nmAQxXXF80n2EVwTp0CNk072wj6761Q7TyuRmiguP/EHMrcCpNfGHBZft5zOp8YjmhNiyAeHAQiL6vE3iwYJ+16ATJP1A4ddfXp25IJ4FFJnw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=lkTgZXQ5; arc=none smtp.client-ip=95.215.58.187 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="lkTgZXQ5" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1786439596; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mffdGYS1Bb2k8B8GRHwSe8UcsBAOHejNXFPLEXMfCoU=; b=lkTgZXQ50uPJjkUaQzSO59v5uCuD/aleBngw9YwQEfog1++VcXIJlgKn5+Apa5hZ1Cfnzv eMojgLz3tx44jhe5S58eJd8VhSniMx+Jqy29pWrc5FVKiwwvjaBJ15gZIRL2dT5KwQ5GK5 OiCvQ9en0vuNzI9ZgwULe3WWINozBIg= From: luka.gejak@linux.dev To: Ping-Ke Shih , linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Michael Straube , Bitterblue Smith , Peter Robinson , Hans de Goede , Luka Gejak Subject: [PATCH v4 4/7] wifi: rtw88: fw: handle the RTL8723BS management TX reports Date: Tue, 11 Aug 2026 09:12:00 +0000 Message-ID: <20260811091203.26841-5-luka.gejak@linux.dev> In-Reply-To: <20260811091203.26841-1-luka.gejak@linux.dev> References: <20260811091203.26841-1-luka.gejak@linux.dev> 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 X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Luka Gejak The vendor firmware used by the RTL8723BS does not report management frame transmission through C2H_CCX_TX_RPT. It uses event 0x12, and reuses 0x32 for scan probe reports, which rtw88 otherwise treats as a WLAN_RFON event and completes the LPS leave check with. Route both events to the existing TX report handler for this chip, and defer 0x32 to the worker instead of consuming it in the interrupt path, so the reports are decoded and the LPS handshake is left alone. The payload layout is the same as C2H_CCX_TX_RPT, so no separate decode is needed. Without this, testers on ARM SDIO boards see "failed to get tx report from firmware" and "firmware failed to leave lps state" once power save engages under load. Reported-by: Peter Robinson Closes: https://lore.kernel.org/all/CALeDE9PgQmpMfDt1DgfLD4tBFGH0MZ7GncV6RU= EOHhHbKF+TdQ@mail.gmail.com/ Signed-off-by: Luka Gejak --- drivers/net/wireless/realtek/rtw88/fw.c | 20 ++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/fw.h | 5 +++++ 2 files changed, 25 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless= /realtek/rtw88/fw.c index 945fedcd375b..c85c0e3e60a9 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -317,6 +317,15 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, str= uct sk_buff *skb) case C2H_CCX_TX_RPT: rtw_tx_report_handle(rtwdev, skb, C2H_CCX_TX_RPT); break; + case C2H_VENDOR_TX_RPT: + case C2H_WLAN_RFON: + /* + * The RTL8723BS firmware reports management TX through these + * two events instead, using the same payload layout. + */ + if (rtw_is_8723bs(rtwdev)) + rtw_tx_report_handle(rtwdev, skb, C2H_CCX_TX_RPT); + break; case C2H_BT_INFO: rtw_coex_bt_info_notify(rtwdev, c2h->payload, len); break; @@ -365,6 +374,17 @@ void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev,= u32 pkt_offset, rtw_coex_info_response(rtwdev, skb); break; case C2H_WLAN_RFON: + /* + * On 8723BS SDIO with v41 firmware, C2H 0x32 carries a scan TX + * report, not a WLAN_RFON event: defer it to + * rtw_fw_c2h_cmd_handle(). + */ + if (rtw_is_8723bs(rtwdev)) { + *((u32 *)skb->cb) =3D pkt_offset; + skb_queue_tail(&rtwdev->c2h_queue, skb); + ieee80211_queue_work(rtwdev->hw, &rtwdev->c2h_work); + break; + } complete(&rtwdev->lps_leave_check); dev_kfree_skb_any(skb); break; diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless= /realtek/rtw88/fw.h index 48ad9ceab6ea..bdda78dc6462 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -54,6 +54,11 @@ enum rtw_c2h_cmd_id { C2H_BT_MP_INFO =3D 0x0b, C2H_BT_HID_INFO =3D 0x45, C2H_RA_RPT =3D 0x0c, + /* + * 8723BS SDIO vendor v41 firmware management TX report (0x32 is + * reported as C2H_WLAN_RFON, handled per-chip in the C2H dispatch). + */ + C2H_VENDOR_TX_RPT =3D 0x12, C2H_HW_FEATURE_REPORT =3D 0x19, C2H_WLAN_INFO =3D 0x27, C2H_WLAN_RFON =3D 0x32, --=20 2.53.0 From nobody Tue Sep 29 06:58:37 2026 Received: from out-176.mta1.migadu.com (out-176.mta1.migadu.com [95.215.58.176]) (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 4FA5942BE8A for ; Tue, 11 Aug 2026 09:13:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786439605; cv=none; b=oPnSeQQS/j/y5IUQsYGZgAMO8ziUAeTatztaNNgD/onLGx0szWXFRncPUjF0PShVnqjl0EhdPaPfZpC5G/SIRokwkt9fqE5tyHq28tfxzMeGF2gSQqxHXBMJoVj5tLk+mXcj2u1Cw6pbE17NHp7zyo1i36nKBC4XSZq5SLCbZLU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786439605; c=relaxed/simple; bh=NJrR/+i95JFWhQ4HkovqcpmiGxg9CTp4mo5BrLLJPFA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ICPwrTzMGnW+wpLccYnVq5mjzt4lZH/qE7Hnf6zx1qygowrIpvhCK6Bt42sAyhkJcAGa2XxgIEIlQ8l+ORghnoVYQr0RFJahJHCVk/Yyha7KWu+oosXOyR4+c4v/I/b4HQ7yaVA7rIG3viWT0KRpHZNgTOXEX7wTd9DJpuArW8I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=DYTpw8xK; arc=none smtp.client-ip=95.215.58.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="DYTpw8xK" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1786439600; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=X2DhhpwXyHQn5+blStytz7OvL7oLCOmNYnbEC1JAZsc=; b=DYTpw8xKr16pSERDPRXOVU9k54R78TWziF14A8dbnROWbQRYe0YztiNspA/aiGLF6rzOlm dqzeCyOm9OawMVVSK9eIORb6qA3tFXrN87bhx8ExNM8A1VR3P5K8dI1c2X0mpaolAZOIqi P16zRGDr1e40AlDedfqplp6z+AUyLII= From: luka.gejak@linux.dev To: Ping-Ke Shih , linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Michael Straube , Bitterblue Smith , Peter Robinson , Hans de Goede , Luka Gejak Subject: [PATCH v4 5/7] wifi: rtw88: sdio: track free TX pages and OQT credits for RTL8723BS Date: Tue, 11 Aug 2026 09:12:01 +0000 Message-ID: <20260811091203.26841-6-luka.gejak@linux.dev> In-Reply-To: <20260811091203.26841-1-luka.gejak@linux.dev> References: <20260811091203.26841-1-luka.gejak@linux.dev> 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 X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Luka Gejak The RTL8723BS reports free TX page counts that the generic 8051 path reads back from the chip on every transfer, which is both slow over SDIO and unreliable on this part: the register frequently reads back zero while pages are in fact available. It also gates transmission on a free count in the SDIO output queue, REG_SDIO_OQT_FREE_PG, which rtw88 does not track at all. That count is how many more descriptors the SDIO engine can accept, and the chip discards writes that arrive with none left. Mirror the vendor driver and keep the per-queue and public page counts in software, seeded at start and resynchronised from the chip only when the cached counts say there is not enough room. Wait for a free output queue entry before writing, and account for the pages consumed after a successful transfer. Transfers also have to be padded up to the SDIO block size for this chip rather than using the generic alignment, so size the write separately from the frame and trim the skb back afterwards. Measured on RTL8723BS hardware against an iperf3 server one hop behind the AP, with the wlan0 byte counters as ground truth. On the generic path the association completes but no data passes at all: TCP and UDP both measure 0 bit/s in either direction. With this patch TCP is 25.3 Mbit/s up and 37.3 Mbit/s down, and UDP is 25.0 Mbit/s up at 0% loss. Signed-off-by: Luka Gejak --- drivers/net/wireless/realtek/rtw88/sdio.c | 245 ++++++++++++++++++++-- drivers/net/wireless/realtek/rtw88/sdio.h | 10 + 2 files changed, 243 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wirele= ss/realtek/rtw88/sdio.c index 5b40d74b16ee..493eda559607 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -20,6 +20,7 @@ #include "tx.h" =20 #define RTW_SDIO_INDIRECT_RW_RETRIES 50 +#define RTW_SDIO_OQT_TIMEOUT_MS 1000 =20 static bool rtw_sdio_is_bus_addr(u32 addr) { @@ -548,12 +549,122 @@ static int rtw_sdio_read_port(struct rtw_dev *rtwdev= , u8 *buf, size_t count) return ret; } =20 +/* + * The cached free page counters are a fast path hint only. They are writt= en + * from the single threaded TX work and, for H2C and reserved page writes, + * from process context, so they are atomic_t; whenever they claim there is + * not enough room they are resynchronised from the chip before the caller + * gives up, which also absorbs a lost update. + */ +static void rtw_sdio_8723bs_store_free_txpg(struct rtw_dev *rtwdev, + u32 free_txpg) +{ + struct rtw_sdio *rtwsdio =3D (struct rtw_sdio *)rtwdev->priv; + + atomic_set(&rtwsdio->free_pg_high, + u32_get_bits(free_txpg, BIT_FREE_TXPG_HIGH)); + atomic_set(&rtwsdio->free_pg_normal, + u32_get_bits(free_txpg, BIT_FREE_TXPG_NORMAL)); + atomic_set(&rtwsdio->free_pg_low, + u32_get_bits(free_txpg, BIT_FREE_TXPG_LOW)); + atomic_set(&rtwsdio->free_pg_pub, + u32_get_bits(free_txpg, BIT_FREE_TXPG_PUB)); +} + +static void rtw_sdio_8723bs_init_free_txpg(struct rtw_dev *rtwdev) +{ + struct rtw_sdio *rtwsdio =3D (struct rtw_sdio *)rtwdev->priv; + const struct rtw_page_table *pg_tbl; + u32 free_txpg; + u16 pubq_num; + + free_txpg =3D rtw_read32(rtwdev, REG_SDIO_FREE_TXPG); + if (free_txpg) { + rtw_sdio_8723bs_store_free_txpg(rtwdev, free_txpg); + } else { + pg_tbl =3D &rtwdev->chip->page_table[0]; + pubq_num =3D rtwdev->fifo.acq_pg_num - pg_tbl->hq_num - + pg_tbl->lq_num - pg_tbl->nq_num - pg_tbl->exq_num - + pg_tbl->gapq_num; + + atomic_set(&rtwsdio->free_pg_high, pg_tbl->hq_num); + atomic_set(&rtwsdio->free_pg_normal, pg_tbl->nq_num); + atomic_set(&rtwsdio->free_pg_low, pg_tbl->lq_num); + atomic_set(&rtwsdio->free_pg_pub, pubq_num); + } + + atomic_set(&rtwsdio->tx_oqt_free, + rtw_read8(rtwdev, REG_SDIO_OQT_FREE_PG)); +} + +static void rtw_sdio_8723bs_sync_free_txpg(struct rtw_dev *rtwdev) +{ + u32 free_txpg =3D rtw_read32(rtwdev, REG_SDIO_FREE_TXPG); + + if (free_txpg) + rtw_sdio_8723bs_store_free_txpg(rtwdev, free_txpg); +} + +/* + * Sum of the queue's dedicated counter and the public pool, clamped at ze= ro: + * a lost update between the check below and rtw_sdio_8723bs_consume_txpg() + * can briefly drive a counter negative, and letting that wrap would hide = the + * shortage instead of triggering a resync from the chip. + */ +static unsigned int rtw_sdio_8723bs_pages_free(struct rtw_dev *rtwdev, + atomic_t *dedicated) +{ + struct rtw_sdio *rtwsdio =3D (struct rtw_sdio *)rtwdev->priv; + int free; + + free =3D atomic_read(dedicated) + atomic_read(&rtwsdio->free_pg_pub); + + return free > 0 ? free : 0; +} + +static atomic_t *rtw_sdio_8723bs_free_txpg(struct rtw_dev *rtwdev, u8 queu= e) +{ + struct rtw_sdio *rtwsdio =3D (struct rtw_sdio *)rtwdev->priv; + + switch (queue) { + case RTW_TX_QUEUE_VI: + return &rtwsdio->free_pg_normal; + case RTW_TX_QUEUE_BE: + case RTW_TX_QUEUE_BK: + return &rtwsdio->free_pg_low; + case RTW_TX_QUEUE_BCN: + case RTW_TX_QUEUE_H2C: + case RTW_TX_QUEUE_HI0: + case RTW_TX_QUEUE_MGMT: + case RTW_TX_QUEUE_VO: + return &rtwsdio->free_pg_high; + default: + return NULL; + } +} + static int rtw_sdio_check_free_txpg(struct rtw_dev *rtwdev, u8 queue, size_t count) { unsigned int pages_free, pages_needed; =20 - if (rtw_chip_wcpu_8051(rtwdev)) { + if (rtw_is_8723bs(rtwdev)) { + atomic_t *dedicated; + + dedicated =3D rtw_sdio_8723bs_free_txpg(rtwdev, queue); + if (!dedicated) { + rtw_warn(rtwdev, "Unknown mapping for queue %u\n", queue); + return -EINVAL; + } + + pages_free =3D rtw_sdio_8723bs_pages_free(rtwdev, dedicated); + pages_needed =3D DIV_ROUND_UP(count, rtwdev->chip->page_size); + if (pages_needed <=3D pages_free) + return 0; + + rtw_sdio_8723bs_sync_free_txpg(rtwdev); + pages_free =3D rtw_sdio_8723bs_pages_free(rtwdev, dedicated); + } else if (rtw_chip_wcpu_8051(rtwdev)) { u32 free_txpg; =20 free_txpg =3D rtw_sdio_read32(rtwdev, REG_SDIO_FREE_TXPG); @@ -632,44 +743,123 @@ static int rtw_sdio_check_free_txpg(struct rtw_dev *= rtwdev, u8 queue, return 0; } =20 +static int rtw_sdio_8723bs_wait_tx_oqt(struct rtw_dev *rtwdev) +{ + struct rtw_sdio *rtwsdio =3D (struct rtw_sdio *)rtwdev->priv; + u8 free; + int i; + + if (atomic_add_unless(&rtwsdio->tx_oqt_free, -1, 0)) + return 0; + + for (i =3D 0; i < RTW_SDIO_OQT_TIMEOUT_MS; i++) { + free =3D rtw_read8(rtwdev, REG_SDIO_OQT_FREE_PG); + if (free) { + atomic_set(&rtwsdio->tx_oqt_free, free - 1); + return 0; + } + usleep_range(1000, 2000); + } + + return -EBUSY; +} + +static void rtw_sdio_8723bs_consume_txpg(struct rtw_dev *rtwdev, u8 queue, + unsigned int pages) +{ + struct rtw_sdio *rtwsdio =3D (struct rtw_sdio *)rtwdev->priv; + atomic_t *dedicated; + unsigned int taken; + int free; + + dedicated =3D rtw_sdio_8723bs_free_txpg(rtwdev, queue); + if (!dedicated) + return; + + free =3D atomic_read(dedicated); + taken =3D min_t(unsigned int, pages, free > 0 ? free : 0); + atomic_sub(taken, dedicated); + + pages -=3D taken; + if (pages && atomic_sub_return(pages, &rtwsdio->free_pg_pub) < 0) + atomic_set(&rtwsdio->free_pg_pub, 0); +} + static int rtw_sdio_write_port(struct rtw_dev *rtwdev, struct sk_buff *skb, enum rtw_tx_queue_type queue) { struct rtw_sdio *rtwsdio =3D (struct rtw_sdio *)rtwdev->priv; + bool rtl8723bs =3D rtw_is_8723bs(rtwdev); + unsigned int orig_len =3D skb->len; + unsigned int pages; + size_t write_size; bool bus_claim; size_t txsize; u32 txaddr; int ret; =20 - txaddr =3D rtw_sdio_get_tx_addr(rtwdev, skb->len, queue); - if (!txaddr) - return -EINVAL; + if (rtl8723bs) { + txsize =3D round_up(orig_len, 4); + write_size =3D txsize > RTW_SDIO_BLOCK_SIZE ? + round_up(txsize, RTW_SDIO_BLOCK_SIZE) : txsize; + } else { + txsize =3D sdio_align_size(rtwsdio->sdio_func, orig_len); + write_size =3D txsize; + } =20 - txsize =3D sdio_align_size(rtwsdio->sdio_func, skb->len); + if (write_size > orig_len) { + unsigned int padding =3D write_size - orig_len; + + if (skb_tailroom(skb) < padding) { + ret =3D pskb_expand_head(skb, 0, + padding - skb_tailroom(skb), + GFP_KERNEL); + if (ret) + return ret; + } + skb_put_zero(skb, padding); + } + + txaddr =3D rtw_sdio_get_tx_addr(rtwdev, txsize, queue); + if (!txaddr) { + ret =3D -EINVAL; + goto out_trim; + } =20 ret =3D rtw_sdio_check_free_txpg(rtwdev, queue, txsize); if (ret) - return ret; + goto out_trim; + + if (rtl8723bs) { + ret =3D rtw_sdio_8723bs_wait_tx_oqt(rtwdev); + if (ret) + goto out_trim; + } =20 if (!IS_ALIGNED((unsigned long)skb->data, RTW_SDIO_DATA_PTR_ALIGN)) rtw_warn(rtwdev, "Got unaligned SKB in %s() for queue %u\n", __func__, queue); =20 bus_claim =3D rtw_sdio_bus_claim_needed(rtwsdio); - if (bus_claim) sdio_claim_host(rtwsdio->sdio_func); - - ret =3D sdio_memcpy_toio(rtwsdio->sdio_func, txaddr, skb->data, txsize); - + ret =3D sdio_memcpy_toio(rtwsdio->sdio_func, txaddr, skb->data, + write_size); if (bus_claim) sdio_release_host(rtwsdio->sdio_func); =20 - if (ret) + if (ret) { rtw_warn(rtwdev, "Failed to write %zu byte(s) to SDIO port 0x%08x", - txsize, txaddr); + write_size, txaddr); + } else if (rtl8723bs) { + pages =3D DIV_ROUND_UP(txsize, rtwdev->chip->page_size); + rtw_sdio_8723bs_consume_txpg(rtwdev, queue, pages); + } =20 +out_trim: + if (write_size > orig_len) + skb_trim(skb, orig_len); return ret; } =20 @@ -749,8 +939,39 @@ static int rtw_sdio_setup(struct rtw_dev *rtwdev) return 0; } =20 +static void rtw_sdio_8723bs_check_rqpn(struct rtw_dev *rtwdev) +{ + const struct rtw_chip_info *chip =3D rtwdev->chip; + struct rtw_fifo_conf *fifo =3D &rtwdev->fifo; + const struct rtw_page_table *pg_tbl; + u16 reserved_num; + u32 free_txpg; + u16 pubq_num; + + free_txpg =3D rtw_read32(rtwdev, REG_SDIO_FREE_TXPG); + if (free_txpg || !fifo->acq_pg_num) + return; + + pg_tbl =3D &chip->page_table[0]; + reserved_num =3D pg_tbl->hq_num + pg_tbl->lq_num + pg_tbl->nq_num + + pg_tbl->exq_num + pg_tbl->gapq_num; + if (fifo->acq_pg_num <=3D reserved_num) + return; + + pubq_num =3D fifo->acq_pg_num - reserved_num; + rtw_write32(rtwdev, REG_RQPN_NPQ, + BIT_RQPN_NE(pg_tbl->nq_num, pg_tbl->exq_num)); + rtw_write32(rtwdev, REG_RQPN, + BIT_RQPN_HLP(pg_tbl->hq_num, pg_tbl->lq_num, pubq_num)); +} + static int rtw_sdio_start(struct rtw_dev *rtwdev) { + if (rtw_is_8723bs(rtwdev)) { + rtw_sdio_8723bs_check_rqpn(rtwdev); + rtw_sdio_8723bs_init_free_txpg(rtwdev); + } + rtw_sdio_enable_rx_aggregation(rtwdev); rtw_sdio_enable_interrupt(rtwdev); =20 diff --git a/drivers/net/wireless/realtek/rtw88/sdio.h b/drivers/net/wirele= ss/realtek/rtw88/sdio.h index 457e8b02380e..5b000cb8fac2 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.h +++ b/drivers/net/wireless/realtek/rtw88/sdio.h @@ -86,6 +86,10 @@ #define REG_SDIO_OQT_FREE_PG (SDIO_LOCAL_OFFSET + 0x001E) /* Free Tx Buffer Page */ #define REG_SDIO_FREE_TXPG (SDIO_LOCAL_OFFSET + 0x0020) +#define BIT_FREE_TXPG_HIGH GENMASK(7, 0) +#define BIT_FREE_TXPG_NORMAL GENMASK(15, 8) +#define BIT_FREE_TXPG_LOW GENMASK(23, 16) +#define BIT_FREE_TXPG_PUB GENMASK(31, 24) /* HCI Current Power Mode 1 */ #define REG_SDIO_HCPWM1 (SDIO_LOCAL_OFFSET + 0x0024) /* HCI Current Power Mode 2 */ @@ -159,6 +163,12 @@ struct rtw_sdio { struct workqueue_struct *txwq; struct rtw_sdio_work_data *tx_handler_data; struct sk_buff_head tx_queue[RTK_MAX_TX_QUEUE_NUM]; + + atomic_t free_pg_high; + atomic_t free_pg_normal; + atomic_t free_pg_low; + atomic_t free_pg_pub; + atomic_t tx_oqt_free; }; =20 extern const struct dev_pm_ops rtw_sdio_pm_ops; --=20 2.53.0 From nobody Tue Sep 29 06:58:37 2026 Received: from out-176.mta1.migadu.com (out-176.mta1.migadu.com [95.215.58.176]) (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 B5DAA42C4F7 for ; Tue, 11 Aug 2026 09:13:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786439605; cv=none; b=NnLN2HZCjVLpkS7mwvmJo9pch/3iLfIBZJ6yVKpVe42YEYcmZM/+KF8G+wzTrYevRDe2DnPVMrytpD6S2FFkQkC7MZaJKutDEX3rOSbEI0s7ZZ1d6ZuLmjWMrPNgtClrHlPEqXsIwkTYMWlmaDDNGc42N23B5jrU0FFEqFiqdBk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786439605; c=relaxed/simple; bh=rEE4gqZFJf29ue+t4EEcM52kwqIY0z6FhdUzrC6NT1E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Ll+p6vvQFioQdA9TxRM/lrgaT8WF+5yWSdqxHkr1eTS+yBQMtF4z9OkYyvW/xCQknyScxWbmjbzH2ddVmMNfH+j/JrJyBCcVkT37+JxTIBkX1Tlqz33uBJ1h/NdLkKLskgxBUmSFiznUuPaflrAD3eylLg/2M8bOBPN4js6KgnY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=jGRsiNQn; arc=none smtp.client-ip=95.215.58.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="jGRsiNQn" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1786439601; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=h7MJtAjQAOaOAkraoSS6YFuQZnoQa2WjaghOUTADB+M=; b=jGRsiNQn+4HWpxk1OncK4VJsxs+RGnsmKt5hDJzTfcweCULWFmO8xLXKXob+Zxu71vXrhU 8KNB6S1RZhe+DJk60e2qyGIuuQXDLxD+bhaJY+st4rviQt9nSpKdoHI1mD8l0Xn+BOSU9u jQtFoCgSWtNAix+6arAi1k/Qiw4qE80= From: luka.gejak@linux.dev To: Ping-Ke Shih , linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Michael Straube , Bitterblue Smith , Peter Robinson , Hans de Goede , Luka Gejak Subject: [PATCH v4 6/7] wifi: rtw88: sdio: set up RX aggregation and interrupts for RTL8723BS Date: Tue, 11 Aug 2026 09:12:02 +0000 Message-ID: <20260811091203.26841-7-luka.gejak@linux.dev> In-Reply-To: <20260811091203.26841-1-luka.gejak@linux.dev> References: <20260811091203.26841-1-luka.gejak@linux.dev> 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 X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Luka Gejak Enable the existing RX aggregation setup for this chip and select the larger DMA burst count it needs. The RTL8723BS does not raise CPWM1, so leave that source out of its interrupt mask, and set the SDIO TX control bit the vendor driver uses to have transfers always recognised. The chip also keeps raising the interrupt after resume if undefined status bits are written back when acknowledging, so acknowledge only the defined and unmasked bits. That is scoped to this chip; the other SDIO parts keep writing the status word back unchanged. Signed-off-by: Luka Gejak --- drivers/net/wireless/realtek/rtw88/sdio.c | 29 ++++++++++++++++++++++- drivers/net/wireless/realtek/rtw88/sdio.h | 9 +++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wirele= ss/realtek/rtw88/sdio.c index 493eda559607..e9f0d23113f3 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -867,7 +867,11 @@ static void rtw_sdio_init(struct rtw_dev *rtwdev) { struct rtw_sdio *rtwsdio =3D (struct rtw_sdio *)rtwdev->priv; =20 - rtwsdio->irq_mask =3D REG_SDIO_HIMR_RX_REQUEST | REG_SDIO_HIMR_CPWM1; + if (rtw_is_8723bs(rtwdev)) + rtwsdio->irq_mask =3D REG_SDIO_HIMR_RX_REQUEST; + else + rtwsdio->irq_mask =3D REG_SDIO_HIMR_RX_REQUEST | + REG_SDIO_HIMR_CPWM1; } =20 static void rtw_sdio_enable_rx_aggregation(struct rtw_dev *rtwdev) @@ -875,6 +879,7 @@ static void rtw_sdio_enable_rx_aggregation(struct rtw_d= ev *rtwdev) u8 size, timeout; =20 switch (rtwdev->chip->id) { + case RTW_CHIP_TYPE_8723B: case RTW_CHIP_TYPE_8703B: case RTW_CHIP_TYPE_8821A: case RTW_CHIP_TYPE_8812A: @@ -902,6 +907,8 @@ static void rtw_sdio_enable_rx_aggregation(struct rtw_d= ev *rtwdev) FIELD_PREP(BIT_DMA_AGG_TO_V1, timeout)); =20 rtw_write8_set(rtwdev, REG_RXDMA_MODE, BIT_DMA_MODE); + if (rtw_is_8723bs(rtwdev)) + rtw_write8_mask(rtwdev, REG_RXDMA_MODE, BIT_DMA_BURST_CNT, 0x3); } =20 static void rtw_sdio_enable_interrupt(struct rtw_dev *rtwdev) @@ -967,12 +974,22 @@ static void rtw_sdio_8723bs_check_rqpn(struct rtw_dev= *rtwdev) =20 static int rtw_sdio_start(struct rtw_dev *rtwdev) { + u32 clear; + if (rtw_is_8723bs(rtwdev)) { rtw_sdio_8723bs_check_rqpn(rtwdev); rtw_sdio_8723bs_init_free_txpg(rtwdev); } =20 rtw_sdio_enable_rx_aggregation(rtwdev); + + if (rtw_is_8723bs(rtwdev)) { + clear =3D rtw_read32(rtwdev, REG_SDIO_HISR) & + RTW_SDIO_HISR_CLEAR_MASK; + if (clear) + rtw_write32(rtwdev, REG_SDIO_HISR, clear); + } + rtw_sdio_enable_interrupt(rtwdev); =20 return 0; @@ -1052,6 +1069,8 @@ static void rtw_sdio_interface_cfg(struct rtw_dev *rt= wdev) =20 val =3D rtw_read32(rtwdev, REG_SDIO_TX_CTRL); val &=3D 0xfff8; + if (rtw_is_8723bs(rtwdev)) + val |=3D BIT_SDIO_TX_CTRL_ALWAYS_RECOGNIZE; rtw_write32(rtwdev, REG_SDIO_TX_CTRL, val); } =20 @@ -1316,6 +1335,14 @@ static void rtw_sdio_handle_interrupt(struct sdio_fu= nc *sdio_func) rtw_sdio_rx_isr(rtwdev); } =20 + /* + * RTL8723BS keeps raising the interrupt after resume if undefined + * status bits are written back, so acknowledge only the bits that are + * both defined and unmasked. Other chips keep the existing behaviour. + */ + if (rtw_is_8723bs(rtwdev)) + hisr &=3D rtwsdio->irq_mask & RTW_SDIO_HISR_CLEAR_MASK; + rtw_write32(rtwdev, REG_SDIO_HISR, hisr); =20 rtwsdio->irq_thread =3D NULL; diff --git a/drivers/net/wireless/realtek/rtw88/sdio.h b/drivers/net/wirele= ss/realtek/rtw88/sdio.h index 5b000cb8fac2..7474a7511811 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.h +++ b/drivers/net/wireless/realtek/rtw88/sdio.h @@ -22,6 +22,7 @@ =20 /* SDIO Tx Control */ #define REG_SDIO_TX_CTRL (SDIO_LOCAL_OFFSET + 0x0000) +#define BIT_SDIO_TX_CTRL_ALWAYS_RECOGNIZE BIT(4) =20 /*SDIO status timeout*/ #define REG_SDIO_TIMEOUT (SDIO_LOCAL_OFFSET + 0x0002) @@ -77,6 +78,14 @@ /* the following two are RTL8188 SDIO Specific */ #define REG_SDIO_HISR_MCU_ERR BIT(28) #define REG_SDIO_HISR_TSF_BIT32_TOGGLE BIT(29) +#define RTW_SDIO_HISR_CLEAR_MASK \ + (REG_SDIO_HISR_TXERR | REG_SDIO_HISR_RXERR | \ + REG_SDIO_HISR_TXFOVW | REG_SDIO_HISR_RXFOVW | \ + REG_SDIO_HISR_TXBCNOK | REG_SDIO_HISR_TXBCNERR | \ + REG_SDIO_HISR_C2HCMD | REG_SDIO_HISR_CPWM1 | \ + REG_SDIO_HISR_CPWM2 | REG_SDIO_HISR_HSISR_IND | \ + REG_SDIO_HISR_GTINT3_IND | REG_SDIO_HISR_GTINT4_IND | \ + REG_SDIO_HISR_PSTIMEOUT | REG_SDIO_HISR_OCPINT) =20 /* HCI Current Power Mode */ #define REG_SDIO_HCPWM (SDIO_LOCAL_OFFSET + 0x0019) --=20 2.53.0 From nobody Tue Sep 29 06:58:37 2026 Received: from out-188.mta1.migadu.com (out-188.mta1.migadu.com [95.215.58.188]) (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 775F1429038 for ; Tue, 11 Aug 2026 09:13:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.188 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786439607; cv=none; b=KsD3WXNXJGueDsdAtlWDfdJiLkUzBrmEqv5hykmdzjURW+frGKlN+3f0hkHiZb3y4fHQojTg8co1Uz76QrTaO6t6TkcPtaJEAstt0Q5c18jYCnvKz7lxaKb6hxhg3eJYM2RPYl2O3qX8155OpWVuDRb3mWaa5LB+i8eNRMqPVLs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786439607; c=relaxed/simple; bh=K5DhDpEvJu90Y04wIBIywmK4wY4b7jgNvyGEKrV5fk4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tLhrtopTXAzT6ZX+ue/yLyLd3A5sSC+YPQouIKx/GpYUn+SiCh26+yzq3vwxKwA4rNcbaQFzRGjAESYMBGx9Nu5DpubOEe65LRI+bioG0qyc9k3G4s5Z9ewe01Pr4nyFu62sPbgAYwKyb1YGYozhSjQjZbHGS5QIkZDIPlAxLlw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=TqA8MRao; arc=none smtp.client-ip=95.215.58.188 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="TqA8MRao" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1786439603; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=AD8gjGRLSA+fVJBpF87ms2XwGjKH4KsmjH943OlVjMY=; b=TqA8MRaobeG7IFCTk39juy/g2uOjHm2V8rzcCZFGroeSgnNofnDCr8x5emqf3Lp716QXmp 35Wo/PGi71aciqBWfaEAiTxrc0aji9MhK3sWUtdmxpJbhFz0b5Fw9JE0fbMt674I9KoTau qWFF9FLEwVNZkgriEaeVp+Mc8hUQCnw= From: luka.gejak@linux.dev To: Ping-Ke Shih , linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Michael Straube , Bitterblue Smith , Peter Robinson , Hans de Goede , Luka Gejak Subject: [PATCH v4 7/7] wifi: rtw88: sdio: add TX back-pressure and retry on page starvation Date: Tue, 11 Aug 2026 09:12:03 +0000 Message-ID: <20260811091203.26841-8-luka.gejak@linux.dev> In-Reply-To: <20260811091203.26841-1-luka.gejak@linux.dev> References: <20260811091203.26841-1-luka.gejak@linux.dev> 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 X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Luka Gejak Two problems show up on RTL8723BS uplink. The per-AC software FIFO is unbounded, so mac80211 keeps handing frames down until latency collapses under load. And when the chip runs out of free TX pages the queue is simply abandoned for that pass, which stalls the AC until something else kicks the worker. Stop the mac80211 queue once a data AC fills past a high watermark and wake it from the drain path when it falls back to a low one. Convert the TX work item to a delayed work so a temporary page shortage can be retried shortly afterwards instead of stalling, and cancel it on teardown. Measured on RTL8723BS hardware, uplink goes from 11.9 Mbit/s with 204 TCP retransmits to 20.1 Mbit/s with 2. Signed-off-by: Luka Gejak --- drivers/net/wireless/realtek/rtw88/sdio.c | 99 ++++++++++++++++++++--- drivers/net/wireless/realtek/rtw88/sdio.h | 3 +- 2 files changed, 91 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wirele= ss/realtek/rtw88/sdio.c index e9f0d23113f3..ed1bed8ea144 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -22,6 +22,16 @@ #define RTW_SDIO_INDIRECT_RW_RETRIES 50 #define RTW_SDIO_OQT_TIMEOUT_MS 1000 =20 +/* + * 8723BS SDIO TX FIFO back-pressure watermarks: stop the mac80211 queue o= nce + * the per-AC software FIFO fills past the high watermark, and wake it fro= m the + * TX drain path once it falls back to the low one. Bounds the queueing la= tency + * that otherwise causes uplink bufferbloat / congestion collapse. + */ +#define RTW_SDIO_TX_FIFO_HIWATER 16 +#define RTW_SDIO_TX_FIFO_LOWATER 8 +#define RTW_SDIO_TX_RETRY_DELAY msecs_to_jiffies(1) + static bool rtw_sdio_is_bus_addr(u32 addr) { return !!(addr & RTW_SDIO_BUS_MSK); @@ -1053,7 +1063,11 @@ static void rtw_sdio_tx_kick_off(struct rtw_dev *rtw= dev) { struct rtw_sdio *rtwsdio =3D (struct rtw_sdio *)rtwdev->priv; =20 - queue_work(rtwsdio->txwq, &rtwsdio->tx_handler_data->work); + /* + * A retry may already be pending with a delay; re-arm it so a newly + * queued frame is not held back by it. + */ + mod_delayed_work(rtwsdio->txwq, &rtwsdio->tx_handler_data->work, 0); } =20 static void rtw_sdio_link_ps(struct rtw_dev *rtwdev, bool enter) @@ -1177,6 +1191,19 @@ static int rtw_sdio_tx_write(struct rtw_dev *rtwdev, =20 skb_queue_tail(&rtwsdio->tx_queue[queue], skb); =20 + /* + * Back-pressure on the data ACs (BK/BE/VI/VO): once the FIFO fills past + * the high watermark, stop the corresponding mac80211 queue so it stops + * handing us frames, bounding the queueing latency. Resumed from the TX + * drain path once the FIFO drains below the low watermark. + */ + if (rtw_is_8723bs(rtwdev) && queue < RTW_TX_QUEUE_BCN && + !rtwsdio->queue_stopped[queue] && + skb_queue_len(&rtwsdio->tx_queue[queue]) >=3D RTW_SDIO_TX_FIFO_HIWATE= R) { + rtwsdio->queue_stopped[queue] =3D true; + ieee80211_stop_queue(rtwdev->hw, skb_get_queue_mapping(skb)); + } + return 0; } =20 @@ -1479,43 +1506,92 @@ static void rtw_sdio_indicate_tx_status(struct rtw_= dev *rtwdev, ieee80211_tx_status_irqsafe(hw, skb); } =20 -static void rtw_sdio_process_tx_queue(struct rtw_dev *rtwdev, - enum rtw_tx_queue_type queue) +/* + * Send one frame from @queue. Returns 1 when a frame was written, 0 when = the + * queue was empty and a negative errno when the write failed, in which ca= se + * the frame is put back at the head of the queue. + */ +static int rtw_sdio_process_tx_queue(struct rtw_dev *rtwdev, + enum rtw_tx_queue_type queue) { struct rtw_sdio *rtwsdio =3D (struct rtw_sdio *)rtwdev->priv; struct sk_buff *skb; + u16 q_map; int ret; =20 skb =3D skb_dequeue(&rtwsdio->tx_queue[queue]); if (!skb) - return; + return 0; =20 + q_map =3D skb_get_queue_mapping(skb); ret =3D rtw_sdio_write_port(rtwdev, skb, queue); if (ret) { skb_queue_head(&rtwsdio->tx_queue[queue], skb); - return; + return ret; } =20 rtw_sdio_indicate_tx_status(rtwdev, skb); + + if (rtw_is_8723bs(rtwdev) && queue < RTW_TX_QUEUE_BCN && + rtwsdio->queue_stopped[queue] && + skb_queue_len(&rtwsdio->tx_queue[queue]) <=3D + RTW_SDIO_TX_FIFO_LOWATER) { + rtwsdio->queue_stopped[queue] =3D false; + ieee80211_wake_queue(rtwdev->hw, q_map); + } + + return 1; } =20 static void rtw_sdio_tx_handler(struct work_struct *work) { struct rtw_sdio_work_data *work_data =3D - container_of(work, struct rtw_sdio_work_data, work); + container_of(to_delayed_work(work), struct rtw_sdio_work_data, + work); struct rtw_sdio *rtwsdio; struct rtw_dev *rtwdev; - int limit, queue; + int limit, queue, ret; + bool rtl8723bs; =20 rtwdev =3D work_data->rtwdev; rtwsdio =3D (struct rtw_sdio *)rtwdev->priv; + rtl8723bs =3D rtw_is_8723bs(rtwdev); =20 if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_TX_WAKE)) rtw_sdio_deep_ps_leave(rtwdev); =20 for (queue =3D RTK_MAX_TX_QUEUE_NUM - 1; queue >=3D 0; queue--) { for (limit =3D 0; limit < 1000; limit++) { - rtw_sdio_process_tx_queue(rtwdev, queue); + ret =3D rtw_sdio_process_tx_queue(rtwdev, queue); + if (ret =3D=3D 0) + break; + + if (ret < 0) { + /* + * A page shortage is transient: leave the + * frame queued and come back shortly instead + * of stalling this AC until something else + * kicks the worker. + */ + if (rtl8723bs && ret =3D=3D -EBUSY) { + queue_delayed_work(rtwsdio->txwq, + &work_data->work, + RTW_SDIO_TX_RETRY_DELAY); + return; + } + break; + } + + /* + * Restart from the highest priority queue after every + * management frame so the join sequence is not held up + * behind a data backlog. + */ + if (rtl8723bs && queue =3D=3D RTW_TX_QUEUE_MGMT) { + queue_delayed_work(rtwsdio->txwq, + &work_data->work, 0); + return; + } =20 if (skb_queue_empty(&rtwsdio->tx_queue[queue])) break; @@ -1542,14 +1618,16 @@ static int rtw_sdio_init_tx(struct rtw_dev *rtwdev) return -ENOMEM; } =20 - for (i =3D 0; i < RTK_MAX_TX_QUEUE_NUM; i++) + for (i =3D 0; i < RTK_MAX_TX_QUEUE_NUM; i++) { skb_queue_head_init(&rtwsdio->tx_queue[i]); + rtwsdio->queue_stopped[i] =3D false; + } rtwsdio->tx_handler_data =3D kmalloc_obj(*rtwsdio->tx_handler_data); if (!rtwsdio->tx_handler_data) goto err_destroy_wq; =20 rtwsdio->tx_handler_data->rtwdev =3D rtwdev; - INIT_WORK(&rtwsdio->tx_handler_data->work, rtw_sdio_tx_handler); + INIT_DELAYED_WORK(&rtwsdio->tx_handler_data->work, rtw_sdio_tx_handler); =20 return 0; =20 @@ -1563,6 +1641,7 @@ static void rtw_sdio_deinit_tx(struct rtw_dev *rtwdev) struct rtw_sdio *rtwsdio =3D (struct rtw_sdio *)rtwdev->priv; int i; =20 + cancel_delayed_work_sync(&rtwsdio->tx_handler_data->work); destroy_workqueue(rtwsdio->txwq); kfree(rtwsdio->tx_handler_data); =20 diff --git a/drivers/net/wireless/realtek/rtw88/sdio.h b/drivers/net/wirele= ss/realtek/rtw88/sdio.h index 7474a7511811..2f1b67f4bbc7 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.h +++ b/drivers/net/wireless/realtek/rtw88/sdio.h @@ -156,7 +156,7 @@ struct rtw_sdio_tx_data { }; =20 struct rtw_sdio_work_data { - struct work_struct work; + struct delayed_work work; struct rtw_dev *rtwdev; }; =20 @@ -172,6 +172,7 @@ struct rtw_sdio { struct workqueue_struct *txwq; struct rtw_sdio_work_data *tx_handler_data; struct sk_buff_head tx_queue[RTK_MAX_TX_QUEUE_NUM]; + bool queue_stopped[RTK_MAX_TX_QUEUE_NUM]; =20 atomic_t free_pg_high; atomic_t free_pg_normal; --=20 2.53.0