* Re: [PATCH v3 3/3] wifi: carl9170: fix buffer overflow in rx_stream failover path
From: Jeff Johnson @ 2026-07-01 18:32 UTC (permalink / raw)
To: Tristan Madani, Christian Lamparter
Cc: Johannes Berg, linux-wireless, linux-kernel, Tristan Madani
In-Reply-To: <20260421134929.325662-4-tristmd@gmail.com>
On 4/21/2026 6:49 AM, Tristan Madani wrote:
> From: Tristan Madani <tristan@talencesecurity.com>
>
> The failover continuation in carl9170_rx_stream() copies the full tlen
> from the second USB transfer instead of capping at rx_failover_missing
> bytes. When both transfers are near maximum size, the total exceeds the
> 65535-byte failover SKB, triggering skb_over_panic.
>
> Limit the copy size to the missing byte count.
>
> Fixes: a84fab3cbfdc ("carl9170: 802.11 rx/tx processing and usb backend")
> Signed-off-by: Tristan Madani <tristan@talencesecurity.com>
> ---
> Changes in v3:
> - Regenerated from wireless-next with proper git format-patch.
>
> Changes in v2:
> - Use min_t() instead of separate if-check, per Christian Lamparter.
>
> drivers/net/wireless/ath/carl9170/rx.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
> index f6855efc05c0f..ccadc46385240 100644
> --- a/drivers/net/wireless/ath/carl9170/rx.c
> +++ b/drivers/net/wireless/ath/carl9170/rx.c
> @@ -918,7 +918,9 @@ static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len)
> }
> }
>
> - skb_put_data(ar->rx_failover, tbuf, tlen);
> + skb_put_data(ar->rx_failover, tbuf,
> + min_t(unsigned int, tlen,
checkpatch complains:
CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
no need to repost for this, I can fix when applying
> + ar->rx_failover_missing));
> ar->rx_failover_missing -= tlen;
>
> if (ar->rx_failover_missing <= 0) {
^ permalink raw reply
* [PATCH ath-next v2] wifi: ath12k: Set IEEE80211_OFFLOAD_ENCAP_4ADDR after tx_encap_type vdev param
From: Tamizh Chelvam Raja @ 2026-07-01 18:24 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless, Tamizh Chelvam Raja
Currently, IEEE80211_OFFLOAD_ENCAP_4ADDR is set when
IEEE80211_OFFLOAD_ENCAP_ENABLED is present in vif->offload_flags
at the beginning of ath12k_mac_update_vif_offload().
However, if the WMI vdev set_param for tx_encap_type fails,
IEEE80211_OFFLOAD_ENCAP_ENABLED is cleared but
IEEE80211_OFFLOAD_ENCAP_4ADDR remains set, leaving the flags in
an inconsistent state.
Fix this by setting IEEE80211_OFFLOAD_ENCAP_4ADDR only after the
tx_encap_type has been configured via the WMI vdev set parameter.
Compile tested only.
Fixes: 729cad3c3c9e ("wifi: ath12k: Add 4-address mode support for eth offload")
Signed-off-by: Tamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
---
v2:
* Rebased of top ToT
drivers/net/wireless/ath/ath12k/mac.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 16339469c24c..edd5b8c3df34 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -10118,16 +10118,15 @@ static void ath12k_mac_update_vif_offload(struct ath12k_link_vif *arvif)
vif->type != NL80211_IFTYPE_AP)
vif->offload_flags &= ~(IEEE80211_OFFLOAD_ENCAP_ENABLED |
IEEE80211_OFFLOAD_DECAP_ENABLED |
- IEEE80211_OFFLOAD_ENCAP_MCAST);
+ IEEE80211_OFFLOAD_ENCAP_MCAST |
+ IEEE80211_OFFLOAD_ENCAP_4ADDR);
- if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) {
+ if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
ahvif->dp_vif.tx_encap_type = ATH12K_HW_TXRX_ETHERNET;
- vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
- } else if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) {
+ else if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags))
ahvif->dp_vif.tx_encap_type = ATH12K_HW_TXRX_RAW;
- } else {
+ else
ahvif->dp_vif.tx_encap_type = ATH12K_HW_TXRX_NATIVE_WIFI;
- }
ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
param_id, ahvif->dp_vif.tx_encap_type);
@@ -10138,7 +10137,8 @@ static void ath12k_mac_update_vif_offload(struct ath12k_link_vif *arvif)
}
if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
- vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_MCAST;
+ vif->offload_flags |= (IEEE80211_OFFLOAD_ENCAP_MCAST |
+ IEEE80211_OFFLOAD_ENCAP_4ADDR);
param_id = WMI_VDEV_PARAM_RX_DECAP_TYPE;
if (vif->offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED)
base-commit: 913998f903fb1432c0046c33003db38a9e8bedb1
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v3 0/3] wifi: carl9170: firmware trust boundary hardening
From: Jeff Johnson @ 2026-07-01 17:47 UTC (permalink / raw)
To: Tristan Madani, Christian Lamparter
Cc: Johannes Berg, linux-wireless, linux-kernel, Tristan Madani
In-Reply-To: <20260421134929.325662-1-tristmd@gmail.com>
On 4/21/2026 6:49 AM, Tristan Madani wrote:
> From: Tristan Madani <tristan@talencesecurity.com>
>
> This series adds missing bounds checks for firmware-controlled fields
> in the carl9170 USB driver.
>
> Patch 1 bounds the cmd callback memcpy to prevent heap overflow from
> an oversized firmware response. Patch 2 fixes an off-by-two in the TX
> status handler. Patch 3 caps the failover copy to rx_failover_missing
> bytes, using min_t per Christian Lamparter.
>
> Changes in v3:
> - Regenerated from wireless-next with proper git format-patch.
>
> Changes in v2:
> - Use min_t() instead of separate if-check in patch 3, per
> Christian Lamparter.
>
> Tristan Madani (3):
> wifi: carl9170: bound memcpy length in cmd callback to prevent OOB
> read
> wifi: carl9170: fix OOB read from off-by-two in TX status handler
> wifi: carl9170: fix buffer overflow in rx_stream failover path
>
> drivers/net/wireless/ath/carl9170/rx.c | 7 +++++--
> drivers/net/wireless/ath/carl9170/tx.c | 2 +-
> 2 files changed, 6 insertions(+), 3 deletions(-)
>
Christian, will you be able to review this series?
I'll take it once I get reviewed-by or acked-by tags.
And then we can ignore the dups from others.
/jeff
^ permalink raw reply
* Re: ath11k: BigEndian platform support?
From: Jeff Johnson @ 2026-07-01 17:08 UTC (permalink / raw)
To: Alexander Wilhelm, Jeff Johnson; +Cc: ath11k, ath12k, linux-wireless
In-Reply-To: <akIuPiYGXDbDWLGZ@FUE-ALEWI-WINX>
On 6/29/2026 1:35 AM, Alexander Wilhelm wrote:
> On Tue, Jul 11, 2023 at 11:49:54AM +0300, Kalle Valo wrote:
>> Alexander Wilhelm <alexander.wilhelm@westermo.com> writes:
>>
>>> I am trying to get the QCN9074 module to work on a BigEndian PowerPC
>>> platform. My question would be, has anyone done it yet? If not, what
>>> kind of effort would you estimate for porting or are there any
>>> firmware limitations?
>>
>> This is a good question. The short answer is that it _might_ work with
>> QCN9074 but AFAIK nobody has tested it and I'm not really optimistic.
>>
>> The long answer is that the big endian support in ath11k is implemented
>> in a weird way which I regret big time. The idea is that the firmware
>> does the translation instead of ath11k driver with this flag:
>>
>> /* Host software's Copy Engine configuration. */
>> #ifdef __BIG_ENDIAN
>> #define CE_ATTR_FLAGS CE_ATTR_BYTE_SWAP_DATA
>> #else
>> #define CE_ATTR_FLAGS 0
>> #endif
>>
>> But later I was told that not all firmware branches actually support
>> this feature, sigh. To my knowledge QCA6390 and WCN6855 firmwares do not
>> support this CE_ATTR_BYTE_SWAP_DATA but I'm hoping QCN9074 firmware
>> would support it. Grep for BIG_ENDIAN to see more big endian specific
>> changes.
>>
>> In ath12k the endian support was implemented in a proper way using
>> __le32 type family and cpu_to_le32() & co macros, but it's also
>> untested. It's on my todo list to convert ath11k to do the same but no
>> idea when I'm able to work on it. Patches very welcome.
>>
>> Do let me know if you test ath11k on big endian, I'm very curious to
>> know the results.
>
> Hello Jeff and the `ath` developers,
>
> there are still a number of pending patch requests from my side for `ath12k`
> addressing various big endian issues. I assume there may still be gaps that I
> did not uncover during my testing. Nevertheless, `ath12k` is now running stable
> for me in both AP and STA modes, so I have started to look into `ath11k`.
Let me start by addressing ath12k. I have been sitting on your patches because
internally there has been a lot of discussion on this topic. Just this week I
convinced Those That Need Convincing (tm) that your changes are consistent
with the approach that was taken with the rest of ath12k to have the host
driver responsible for all byte swapping. So I'll finally be taking those patches.
HOWEVER, Qualcomm is trying to transition all of our products to be based upon
the upstream driver, and the team responsible for enterprise access points
believes that their KPIs on Big Endian platforms cannot be met with software
byte swapping (my understanding is they currently use hardware swapping in
their out-of-tree driver). So it is possible that ath12k will need to
transition to hardware swapping in the future to meet that need.
I just wanted to share that bit.
Your proposal for ath11k still needs to be discussed, but there is obviously
concern about introducing regressions to code. There will also be impacts on
projects like QSDK and OpenWrt, which are based upon applying patches to the
existing driver, if large portions of ath11k are rewritten.
/jeff
^ permalink raw reply
* [PATCH] wifi: ath: avoid repeated divisions in DFS PRI detector
From: frank0988 @ 2026-07-01 17:04 UTC (permalink / raw)
To: Jeff Johnson; +Cc: linux-wireless, linux-kernel, frank0988
pde_get_multiple() is called repeatedly with the same PRI (Pulse
Repetition Interval) value while validating candidate and existing PRI
sequences.
Cache the reciprocal value for each sequence structure and leverage
reciprocal_divide() in the hot path. This keeps the existing matching
logic and tolerance checks intact while replacing expensive hardware
integer divisions with low-cost multiply-and-shift operations.
Testing with a userspace model of the same detector logic demonstrated
identical detector states and outputs across 100 verification traces.
To eliminate memory allocator noise, an isolated micro-benchmark using
a static object pool showed that the reciprocal variant reduces CPU
cycles by approximately 3.4%.
Signed-off-by: frank0988 <frank0988855428@gmail.com>
---
drivers/net/wireless/ath/dfs_pri_detector.c | 14 +++++++++++---
drivers/net/wireless/ath/dfs_pri_detector.h | 3 +++
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ath/dfs_pri_detector.c b/drivers/net/wireless/ath/dfs_pri_detector.c
index 388f9d1913bd..520fd1567a0b 100644
--- a/drivers/net/wireless/ath/dfs_pri_detector.c
+++ b/drivers/net/wireless/ath/dfs_pri_detector.c
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/reciprocal_div.h>
#include "ath.h"
#include "dfs_pattern_detector.h"
@@ -41,7 +42,9 @@ struct pulse_elem {
* pde_get_multiple() - get number of multiples considering a given tolerance
* Return value: factor if abs(val - factor*fraction) <= tolerance, 0 otherwise
*/
-static u32 pde_get_multiple(u32 val, u32 fraction, u32 tolerance)
+static u32 pde_get_multiple(u32 val, u32 fraction,
+ struct reciprocal_value fraction_recip,
+ u32 tolerance)
{
u32 remainder;
u32 factor;
@@ -56,8 +59,8 @@ static u32 pde_get_multiple(u32 val, u32 fraction, u32 tolerance)
/* val and fraction are within tolerance */
return 1;
- factor = val / fraction;
- remainder = val % fraction;
+ factor = reciprocal_divide(val, fraction_recip);
+ remainder = val - factor * fraction;
if (remainder > tolerance) {
/* no exact match */
if ((fraction - remainder) <= tolerance)
@@ -247,6 +250,9 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde,
ps.last_ts = ts;
ps.pri = GET_PRI_TO_USE(pde->rs->pri_min,
pde->rs->pri_max, ts - p->ts);
+ ps.pri_recip = (struct reciprocal_value){};
+ if (ps.pri)
+ ps.pri_recip = reciprocal_value(ps.pri);
ps.dur = ps.pri * (pde->rs->ppb - 1)
+ 2 * pde->rs->max_pri_tolerance;
@@ -261,6 +267,7 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde,
break;
/* check if pulse match (multi)PRI */
factor = pde_get_multiple(ps.last_ts - p2->ts, ps.pri,
+ ps.pri_recip,
pde->rs->max_pri_tolerance);
if (factor > 0) {
ps.count++;
@@ -318,6 +325,7 @@ pseq_handler_add_to_existing_seqs(struct pri_detector *pde, u64 ts)
delta_ts = ts - ps->last_ts;
factor = pde_get_multiple(delta_ts, ps->pri,
+ ps->pri_recip,
pde->rs->max_pri_tolerance);
if (factor > 0) {
ps->last_ts = ts;
diff --git a/drivers/net/wireless/ath/dfs_pri_detector.h b/drivers/net/wireless/ath/dfs_pri_detector.h
index 86339f2b4d3a..c519466cff8b 100644
--- a/drivers/net/wireless/ath/dfs_pri_detector.h
+++ b/drivers/net/wireless/ath/dfs_pri_detector.h
@@ -18,6 +18,7 @@
#define DFS_PRI_DETECTOR_H
#include <linux/list.h>
+#include <linux/reciprocal_div.h>
extern struct ath_dfs_pool_stats global_dfs_pool_stats;
@@ -25,6 +26,7 @@ extern struct ath_dfs_pool_stats global_dfs_pool_stats;
* struct pri_sequence - sequence of pulses matching one PRI
* @head: list_head
* @pri: pulse repetition interval (PRI) in usecs
+ * @pri_recip: cached reciprocal value for PRI divisions
* @dur: duration of sequence in usecs
* @count: number of pulses in this sequence
* @count_falses: number of not matching pulses in this sequence
@@ -35,6 +37,7 @@ extern struct ath_dfs_pool_stats global_dfs_pool_stats;
struct pri_sequence {
struct list_head head;
u32 pri;
+ struct reciprocal_value pri_recip;
u32 dur;
u32 count;
u32 count_falses;
--
2.53.0
^ permalink raw reply related
* Re: [PATCH 3/4] mwifiex: debugfs: use kzalloc() to allocate formatting buffers
From: Francesco Dolcini @ 2026-07-01 16:24 UTC (permalink / raw)
To: Mike Rapoport (Microsoft), Jeff Chen
Cc: Johannes Berg, Brian Norris, Francesco Dolcini, Jakub Kicinski,
b43-dev, libertas-dev, linux-kernel, linux-mm, linux-wireless,
netdev
In-Reply-To: <20260701-b4-drivers-wireless-v1-3-60264cdf2efe@kernel.org>
+Jeff
Jeff: this is relevant also for nxpwifi.
On Wed, Jul 01, 2026 at 04:59:12PM +0300, Mike Rapoport (Microsoft) wrote:
> mwifiex debugfs functions allocate buffers for formatting debug output
> text using get_zeroed_page().
>
> These buffers can be allocated with kmalloc() as there's nothing special
> about them to go directly to the page allocator.
>
> kmalloc() provides a better API that does not require ugly casts and
> kfree() does not need to know the size of the freed object.
>
> Performance difference between kmalloc() and __get_free_pages() is not
> measurable as both allocators take an object/page from a per-CPU list for
> fast path allocations.
>
> For the slow path the performance is anyway determined by the amount of
> reclaim involved rather than by what allocator is used.
>
> Replace use of get_zeroed_page() with kzalloc() and free_page() with
> kfree().
>
> Link: https://lore.kernel.org/all/635405e4-9423-4a25-a6e7-e03c8ea0bcbe@redhat.com
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Reviewed-by: Francesco Dolcini <francesco.dolcini@toradex.com>
^ permalink raw reply
* Re: [PATCH v4] wifi: ath6kl: fix OOB access from firmware ADDBA window size
From: Jeff Johnson @ 2026-07-01 16:24 UTC (permalink / raw)
To: Tristan Madani, linux-wireless, linux-kernel
Cc: Johannes Berg, Tristan Madani, Vasanthakumar Thiagarajan
In-Reply-To: <34ad2c6a-b9c3-4f99-97a7-e58fb22e2e78@oss.qualcomm.com>
On 6/28/2026 9:57 PM, Vasanthakumar Thiagarajan wrote:
>
>
> On 6/26/2026 5:34 AM, Tristan Madani wrote:
>> aggr_recv_addba_req_evt() logs a debug message when the firmware-supplied
>> win_sz is outside [AGGR_WIN_SZ_MIN, AGGR_WIN_SZ_MAX] but does not
>> return. The out-of-range win_sz is then used in TID_WINDOW_SZ() to
>> compute a kzalloc size and stored in rxtid->hold_q_sz, leading to
>> zero-size or overflowed allocations and subsequent out-of-bounds access.
>>
>> Clean up any previously active aggregation session for the TID first,
>> then return early when win_sz is out of the valid range, instead of
>> proceeding with a broken allocation size.
>>
>> Fixes: bdcd81707973 ("Add ath6kl cleaned up driver")
>> Cc: stable@vger.kernel.org
>> Suggested-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
>
> You can remove my suggested-by as I only provided review comments on your patch.
>
>> Signed-off-by: Tristan Madani <tristan@talencesecurity.com>
>
> With the above comment addressed,
>
> Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Can you repost a v5. I can't take this one since:
WARNING:FROM_SIGN_OFF_MISMATCH: From:/Signed-off-by: email address mismatch:
'From: Tristan Madani <tristmd@gmail.com>' != 'Signed-off-by: Tristan Madani
<tristan@talencesecurity.com>'
You missed adding the From: tag in v4
^ permalink raw reply
* [PATCH v7 9/9] arm64: dts: qcom: arduino-imola: Describe NVMEM layout for WiFi/BT addresses
From: Loic Poulain @ 2026-07-01 16:00 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
Russell King, Saravana Kannan, Christian Marangi
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Loic Poulain, Konrad Dybcio, Bartosz Golaszewski
In-Reply-To: <20260701-block-as-nvmem-v7-0-3fe8205ef0a8@oss.qualcomm.com>
On Arduino Uno-Q, the eMMC boot1 partition is factory provisioned
with device-specific information such as the WiFi MAC address
and the Bluetooth BD address. This partition can serve as an
alternative to additional non-volatile memory, such as a
dedicated EEPROM.
The eMMC boot partitions are typically good candidates, as they
are relatively small, read-only by default (and can be enforced
as hardware read-only), and are not affected by board reflashing
procedures, which generally target the eMMC user or GP partitions.
Describe the corresponding nvmem-layout for the WiFi and Bluetooth
addresses, and point the WiFi and Bluetooth nodes to the appropriate
NVMEM cells to retrieve them.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts | 32 ++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts b/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts
index bf088fa9807f040f0c8f405f9111b01790b09377..38839b8a361e76f6c1989924b16095b9d8815f66 100644
--- a/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts
+++ b/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts
@@ -409,7 +409,33 @@ &sdhc_1 {
no-sdio;
no-sd;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
status = "okay";
+
+ card@0 {
+ compatible = "mmc-card";
+ reg = <0>;
+
+ partitions-boot1 {
+ compatible = "fixed-layout";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ wifi_mac_addr: mac-addr@4400 {
+ compatible = "mac-base";
+ reg = <0x4400 0x6>;
+ #nvmem-cell-cells = <1>;
+ };
+
+ bd_addr: bd-addr@5400 {
+ compatible = "mac-base";
+ reg = <0x5400 0x6>;
+ #nvmem-cell-cells = <1>;
+ };
+ };
+ };
};
&spi5 {
@@ -512,6 +538,9 @@ bluetooth {
vddch0-supply = <&pm4125_l22>;
enable-gpios = <&tlmm 87 GPIO_ACTIVE_HIGH>;
max-speed = <3000000>;
+
+ nvmem-cells = <&bd_addr 0>;
+ nvmem-cell-names = "local-bd-address";
};
};
@@ -557,6 +586,9 @@ &wifi {
qcom,ath10k-calibration-variant = "ArduinoImola";
firmware-name = "qcm2290";
+ nvmem-cells = <&wifi_mac_addr 0>;
+ nvmem-cell-names = "mac-address";
+
status = "okay";
};
--
2.34.1
^ permalink raw reply related
* [PATCH v7 8/9] Bluetooth: qca: Set NVMEM BD address quirks when address is invalid
From: Loic Poulain @ 2026-07-01 16:00 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
Russell King, Saravana Kannan, Christian Marangi
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Loic Poulain, Bartosz Golaszewski
In-Reply-To: <20260701-block-as-nvmem-v7-0-3fe8205ef0a8@oss.qualcomm.com>
When the controller BD address is invalid (zero or default),
set the NVMEM quirks to allow retrieving the address from a
'local-bd-address' NVMEM cell. The BD address is often stored
alongside the WiFi MAC address in big-endian format, so also
set the big-endian quirk.
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
drivers/bluetooth/btqca.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index dda76365726f0bfe0e80e05fe04859fa4f0592e1..df33eacfd29fa680f393f90215150743e6001d5b 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -721,8 +721,11 @@ static int qca_check_bdaddr(struct hci_dev *hdev, const struct qca_fw_config *co
}
bda = (struct hci_rp_read_bd_addr *)skb->data;
- if (!bacmp(&bda->bdaddr, &config->bdaddr))
+ if (!bacmp(&bda->bdaddr, &config->bdaddr)) {
hci_set_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY);
+ hci_set_quirk(hdev, HCI_QUIRK_USE_BDADDR_NVMEM);
+ hci_set_quirk(hdev, HCI_QUIRK_BDADDR_NVMEM_BE);
+ }
kfree_skb(skb);
--
2.34.1
^ permalink raw reply related
* [PATCH v7 7/9] Bluetooth: hci_sync: Add NVMEM-backed BD address retrieval
From: Loic Poulain @ 2026-07-01 16:00 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
Russell King, Saravana Kannan, Christian Marangi
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Loic Poulain, Bartosz Golaszewski, Piotr Kwapulinski
In-Reply-To: <20260701-block-as-nvmem-v7-0-3fe8205ef0a8@oss.qualcomm.com>
Some devices store the Bluetooth BD address in non-volatile
memory, which can be accessed through the NVMEM framework.
Similar to Ethernet or WiFi MAC addresses, add support for
reading the BD address from a 'local-bd-address' NVMEM cell.
As with the device-tree provided BD address, add a quirk to
indicate whether a device or platform should attempt to read
the address from NVMEM when no valid in-chip address is present.
Also add a quirk to indicate if the address is stored in
big-endian byte order.
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
include/net/bluetooth/hci.h | 18 ++++++++++++++++++
net/bluetooth/hci_sync.c | 41 ++++++++++++++++++++++++++++++++++++++++-
2 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 572b1c620c5d653a1fe10b26c1b0ba33e8f4968f..7686466d1109253b0d75edeb5f6a99fb98ce4cc6 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -164,6 +164,24 @@ enum {
*/
HCI_QUIRK_BDADDR_PROPERTY_BROKEN,
+ /* When this quirk is set, the public Bluetooth address
+ * initially reported by HCI Read BD Address command
+ * is considered invalid. The public BD Address can be
+ * retrieved via a 'local-bd-address' NVMEM cell.
+ *
+ * This quirk can be set before hci_register_dev is called or
+ * during the hdev->setup vendor callback.
+ */
+ HCI_QUIRK_USE_BDADDR_NVMEM,
+
+ /* When this quirk is set, the Bluetooth Device Address provided by
+ * the 'local-bd-address' NVMEM is stored in big-endian order.
+ *
+ * This quirk can be set before hci_register_dev is called or
+ * during the hdev->setup vendor callback.
+ */
+ HCI_QUIRK_BDADDR_NVMEM_BE,
+
/* When this quirk is set, the duplicate filtering during
* scanning is based on Bluetooth devices addresses. To allow
* RSSI based updates, restart scanning if needed.
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index fd3aacdea512a37c22b9a2be90c89ddca4b4d99f..56248d4abcb5b1d9993962a9f6bf60bf865b8d7b 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -7,6 +7,7 @@
*/
#include <linux/property.h>
+#include <linux/of_net.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -3588,6 +3589,39 @@ int hci_powered_update_sync(struct hci_dev *hdev)
return 0;
}
+/**
+ * hci_dev_get_bd_addr_from_nvmem - Get the Bluetooth Device Address
+ * (BD_ADDR) for a HCI device from
+ * an NVMEM cell.
+ * @hdev: The HCI device
+ *
+ * Search for 'local-bd-address' NVMEM cell in the device firmware node.
+ *
+ * All-zero BD addresses are rejected (unprovisioned).
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+static int hci_dev_get_bd_addr_from_nvmem(struct hci_dev *hdev)
+{
+ struct device_node *np = dev_of_node(hdev->dev.parent);
+ u8 ba[sizeof(bdaddr_t)];
+ int err;
+
+ if (!np)
+ return -ENODEV;
+
+ err = of_get_nvmem_eui48(np, "local-bd-address", ba);
+ if (err)
+ return err;
+
+ if (hci_test_quirk(hdev, HCI_QUIRK_BDADDR_NVMEM_BE))
+ baswap(&hdev->public_addr, (bdaddr_t *)ba);
+ else
+ bacpy(&hdev->public_addr, (bdaddr_t *)ba);
+
+ return 0;
+}
+
/**
* hci_dev_get_bd_addr_from_property - Get the Bluetooth Device Address
* (BD_ADDR) for a HCI device from
@@ -5042,12 +5076,17 @@ static int hci_dev_setup_sync(struct hci_dev *hdev)
* its setup callback.
*/
invalid_bdaddr = hci_test_quirk(hdev, HCI_QUIRK_INVALID_BDADDR) ||
- hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY);
+ hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY) ||
+ hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_NVMEM);
if (!ret) {
if (hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY) &&
!bacmp(&hdev->public_addr, BDADDR_ANY))
hci_dev_get_bd_addr_from_property(hdev);
+ if (hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_NVMEM) &&
+ !bacmp(&hdev->public_addr, BDADDR_ANY))
+ hci_dev_get_bd_addr_from_nvmem(hdev);
+
if (invalid_bdaddr && bacmp(&hdev->public_addr, BDADDR_ANY) &&
hdev->set_bdaddr) {
ret = hdev->set_bdaddr(hdev, &hdev->public_addr);
--
2.34.1
^ permalink raw reply related
* [PATCH v7 6/9] net: of_net: Add of_get_nvmem_eui48() helper for EUI-48 lookup
From: Loic Poulain @ 2026-07-01 16:00 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
Russell King, Saravana Kannan, Christian Marangi
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Loic Poulain, Bartosz Golaszewski
In-Reply-To: <20260701-block-as-nvmem-v7-0-3fe8205ef0a8@oss.qualcomm.com>
Factor out the common NVMEM EUI-48 retrieval logic from
of_get_mac_address_nvmem() into a new of_get_nvmem_eui48() helper that
accepts the NVMEM cell name as a parameter. This allows other subsystems
(e.g. Bluetooth) to reuse the same lookup-validate-copy pattern with a
different cell name, without duplicating code.
of_get_mac_address_nvmem() is updated to call of_get_nvmem_eui48() with
"mac-address", preserving its existing behavior.
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
include/linux/of_net.h | 7 +++++++
net/core/of_net.c | 49 +++++++++++++++++++++++++++++++++++++------------
2 files changed, 44 insertions(+), 12 deletions(-)
diff --git a/include/linux/of_net.h b/include/linux/of_net.h
index d88715a0b3a52f87af23d47791bea3baf5be5200..7854ba555d9a55f3d020a37fe00a27ae52e0e5dc 100644
--- a/include/linux/of_net.h
+++ b/include/linux/of_net.h
@@ -15,6 +15,7 @@ struct net_device;
extern int of_get_phy_mode(struct device_node *np, phy_interface_t *interface);
extern int of_get_mac_address(struct device_node *np, u8 *mac);
extern int of_get_mac_address_nvmem(struct device_node *np, u8 *mac);
+int of_get_nvmem_eui48(struct device_node *np, const char *cell_name, u8 *addr);
int of_get_ethdev_address(struct device_node *np, struct net_device *dev);
extern struct net_device *of_find_net_device_by_node(struct device_node *np);
#else
@@ -34,6 +35,12 @@ static inline int of_get_mac_address_nvmem(struct device_node *np, u8 *mac)
return -ENODEV;
}
+static inline int of_get_nvmem_eui48(struct device_node *np,
+ const char *cell_name, u8 *addr)
+{
+ return -ENODEV;
+}
+
static inline int of_get_ethdev_address(struct device_node *np, struct net_device *dev)
{
return -ENODEV;
diff --git a/net/core/of_net.c b/net/core/of_net.c
index 93ea425b9248a23f4f95a336e9cdbf0053248e32..11c1acca151266ac9287457b4050a54b08e2b5f5 100644
--- a/net/core/of_net.c
+++ b/net/core/of_net.c
@@ -61,9 +61,7 @@ static int of_get_mac_addr(struct device_node *np, const char *name, u8 *addr)
int of_get_mac_address_nvmem(struct device_node *np, u8 *addr)
{
struct platform_device *pdev = of_find_device_by_node(np);
- struct nvmem_cell *cell;
- const void *mac;
- size_t len;
+ u8 mac[ETH_ALEN] __aligned(sizeof(u16));
int ret;
/* Try lookup by device first, there might be a nvmem_cell_lookup
@@ -75,27 +73,54 @@ int of_get_mac_address_nvmem(struct device_node *np, u8 *addr)
return ret;
}
- cell = of_nvmem_cell_get(np, "mac-address");
+ ret = of_get_nvmem_eui48(np, "mac-address", mac);
+ if (ret)
+ return ret;
+
+ if (!is_valid_ether_addr(mac))
+ return -EINVAL;
+
+ ether_addr_copy(addr, mac);
+ return 0;
+}
+EXPORT_SYMBOL(of_get_mac_address_nvmem);
+
+/**
+ * of_get_nvmem_eui48 - Read a 6-byte EUI-48 address from a named NVMEM cell.
+ * @np: Device node to look up the NVMEM cell from.
+ * @cell_name: Name of the NVMEM cell (e.g. "mac-address", "local-bd-address").
+ * @addr: Output buffer for the 6-byte address.
+ *
+ * Reads the named NVMEM cell and validates that it contains a non-zero 6-byte
+ * address. Returns 0 on success, negative errno on failure.
+ */
+int of_get_nvmem_eui48(struct device_node *np, const char *cell_name, u8 *addr)
+{
+ struct nvmem_cell *cell;
+ const void *eui48;
+ size_t len;
+
+ cell = of_nvmem_cell_get(np, cell_name);
if (IS_ERR(cell))
return PTR_ERR(cell);
- mac = nvmem_cell_read(cell, &len);
+ eui48 = nvmem_cell_read(cell, &len);
nvmem_cell_put(cell);
- if (IS_ERR(mac))
- return PTR_ERR(mac);
+ if (IS_ERR(eui48))
+ return PTR_ERR(eui48);
- if (len != ETH_ALEN || !is_valid_ether_addr(mac)) {
- kfree(mac);
+ if (len != ETH_ALEN || !memchr_inv(eui48, 0, ETH_ALEN)) {
+ kfree(eui48);
return -EINVAL;
}
- memcpy(addr, mac, ETH_ALEN);
- kfree(mac);
+ memcpy(addr, eui48, ETH_ALEN);
+ kfree(eui48);
return 0;
}
-EXPORT_SYMBOL(of_get_mac_address_nvmem);
+EXPORT_SYMBOL_GPL(of_get_nvmem_eui48);
/**
* of_get_mac_address()
--
2.34.1
^ permalink raw reply related
* [PATCH v7 3/9] dt-bindings: bluetooth: qcom: Add NVMEM BD address cell
From: Loic Poulain @ 2026-07-01 16:00 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
Russell King, Saravana Kannan, Christian Marangi
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Loic Poulain, Bartosz Golaszewski
In-Reply-To: <20260701-block-as-nvmem-v7-0-3fe8205ef0a8@oss.qualcomm.com>
Add support for an NVMEM cell provider for "local-bd-address",
allowing the Bluetooth stack to retrieve controller's BD address
from non-volatile storage such as an EEPROM or an eMMC partition.
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
.../devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml
index c8e9c55c1afb4c8e05ba2dae41ce2db4194b4a0f..7cb28f30c9af032082f23311f2fc89a32f266f17 100644
--- a/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml
+++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml
@@ -22,4 +22,13 @@ properties:
description:
boot firmware is incorrectly passing the address in big-endian order
+ nvmem-cells:
+ maxItems: 1
+ description:
+ Nvmem data cell that contains a 6 byte BD address with the most
+ significant byte first (big-endian).
+
+ nvmem-cell-names:
+ const: local-bd-address
+
additionalProperties: true
--
2.34.1
^ permalink raw reply related
* [PATCH v7 5/9] block: implement NVMEM provider
From: Loic Poulain @ 2026-07-01 16:00 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
Russell King, Saravana Kannan, Christian Marangi
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Loic Poulain, Bartosz Golaszewski
In-Reply-To: <20260701-block-as-nvmem-v7-0-3fe8205ef0a8@oss.qualcomm.com>
From: Daniel Golle <daniel@makrotopia.org>
On embedded devices using an eMMC it is common that one or more partitions
on the eMMC are used to store MAC addresses and Wi-Fi calibration EEPROM
data. Allow referencing the partition in device tree for the kernel and
Wi-Fi drivers accessing it via the NVMEM layer.
NVMEM is registered for a block device whose OF node describes an NVMEM
layout, either via an "nvmem-layout" child or by being a "fixed-layout"
node itself (e.g. an eMMC boot partition associated through its mmc-card
node).
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Co-developed-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
block/Kconfig | 9 ++++
block/Makefile | 1 +
block/blk-nvmem.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++
block/blk.h | 8 ++++
block/genhd.c | 4 ++
include/linux/blk_types.h | 4 ++
6 files changed, 135 insertions(+)
diff --git a/block/Kconfig b/block/Kconfig
index 15027963472d7b40e27b9097a5993c457b5b3054..0b33747e16dc33473683706f75c92bdf8b648f7c 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -209,6 +209,15 @@ config BLK_INLINE_ENCRYPTION_FALLBACK
by falling back to the kernel crypto API when inline
encryption hardware is not present.
+config BLK_NVMEM
+ bool "Block device NVMEM provider"
+ depends on OF
+ depends on NVMEM
+ help
+ Allow block devices (or partitions) to act as NVMEM providers,
+ typically used with eMMC to store MAC addresses or Wi-Fi
+ calibration data on embedded devices.
+
source "block/partitions/Kconfig"
config BLK_PM
diff --git a/block/Makefile b/block/Makefile
index 7dce2e44276c4274c11a0a61121c83d9c43d6e0c..d7ac389e71902bc091a8800ea266190a43b3e63d 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -36,3 +36,4 @@ obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += blk-crypto.o blk-crypto-profile.o \
blk-crypto-sysfs.o
obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o
obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED) += holder.o
+obj-$(CONFIG_BLK_NVMEM) += blk-nvmem.o
diff --git a/block/blk-nvmem.c b/block/blk-nvmem.c
new file mode 100644
index 0000000000000000000000000000000000000000..49e9b5d4410d5e935c4ad9674c6909453fe027ff
--- /dev/null
+++ b/block/blk-nvmem.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * block device NVMEM provider
+ *
+ * Copyright (c) 2024 Daniel Golle <daniel@makrotopia.org>
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * Useful on devices using a partition on an eMMC for MAC addresses or
+ * Wi-Fi calibration EEPROM data.
+ */
+
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/file.h>
+#include <linux/nvmem-provider.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/pagemap.h>
+#include <linux/property.h>
+
+#include "blk.h"
+
+static int blk_nvmem_reg_read(void *priv, unsigned int from, void *val, size_t bytes)
+{
+ dev_t devt = (dev_t)(uintptr_t)priv;
+ size_t bytes_left = bytes;
+ loff_t pos = from;
+ int ret = 0;
+
+ struct file *bdev_file __free(fput) =
+ bdev_file_open_by_dev(devt, BLK_OPEN_READ, NULL, NULL);
+ if (IS_ERR(bdev_file))
+ return PTR_ERR(bdev_file);
+
+ while (bytes_left) {
+ pgoff_t f_index = pos >> PAGE_SHIFT;
+ struct folio *folio;
+ size_t folio_off;
+ size_t to_read;
+
+ folio = read_mapping_folio(bdev_file->f_mapping, f_index, NULL);
+ if (IS_ERR(folio)) {
+ ret = PTR_ERR(folio);
+ break;
+ }
+
+ folio_off = offset_in_folio(folio, pos);
+ to_read = min(bytes_left, folio_size(folio) - folio_off);
+ memcpy_from_folio(val, folio, folio_off, to_read);
+ pos += to_read;
+ bytes_left -= to_read;
+ val += to_read;
+ folio_put(folio);
+ }
+
+ return ret;
+}
+
+int blk_nvmem_add(struct block_device *bdev)
+{
+ struct device *dev = &bdev->bd_device;
+ struct nvmem_config config = {};
+
+ /* skip devices which do not have a device tree node */
+ if (!dev_of_node(dev))
+ return 0;
+
+ /* skip devices without an nvmem layout defined */
+ struct device_node *child __free(device_node) =
+ of_get_child_by_name(dev_of_node(dev), "nvmem-layout");
+ if (!child && !of_device_is_compatible(dev_of_node(dev), "fixed-layout"))
+ return 0;
+
+ /*
+ * skip block device too large to be represented as NVMEM devices,
+ * nvmem_config.size is a signed int
+ */
+ if (bdev_nr_bytes(bdev) > INT_MAX) {
+ dev_warn(dev, "block device too large to be an NVMEM provider\n");
+ return 0;
+ }
+
+ config.id = NVMEM_DEVID_NONE;
+ config.dev = dev;
+ config.name = dev_name(dev);
+ config.owner = THIS_MODULE;
+ config.priv = (void *)(uintptr_t)dev->devt;
+ config.reg_read = blk_nvmem_reg_read;
+ config.size = bdev_nr_bytes(bdev);
+ config.word_size = 1;
+ config.stride = 1;
+ config.read_only = true;
+ config.root_only = true;
+ config.ignore_wp = true;
+ config.of_node = to_of_node(dev->fwnode);
+
+ bdev->bd_nvmem = nvmem_register(&config);
+ if (IS_ERR(bdev->bd_nvmem))
+ return dev_err_probe(dev, PTR_ERR(bdev->bd_nvmem),
+ "Failed to register NVMEM device\n");
+
+ return 0;
+}
+
+void blk_nvmem_del(struct block_device *bdev)
+{
+ nvmem_unregister(bdev->bd_nvmem);
+ bdev->bd_nvmem = NULL;
+}
diff --git a/block/blk.h b/block/blk.h
index ec4674cdf2ead4fd259ff5fc42401f591e684ee9..ed0c10168ba7be10855509637f824a9cea2b9ccb 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -757,4 +757,12 @@ static inline void blk_debugfs_unlock(struct request_queue *q,
memalloc_noio_restore(memflags);
}
+#ifdef CONFIG_BLK_NVMEM
+int blk_nvmem_add(struct block_device *bdev);
+void blk_nvmem_del(struct block_device *bdev);
+#else
+static inline int blk_nvmem_add(struct block_device *bdev) { return 0; }
+static inline void blk_nvmem_del(struct block_device *bdev) {}
+#endif
+
#endif /* BLK_INTERNAL_H */
diff --git a/block/genhd.c b/block/genhd.c
index 7d6854fd28e95ae9134309679a7c6a937f5b7db8..1b2382de6fb30c1e5f60f45c04dc03ed3bf5d5f2 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -421,6 +421,8 @@ static void add_disk_final(struct gendisk *disk)
*/
dev_set_uevent_suppress(ddev, 0);
disk_uevent(disk, KOBJ_ADD);
+
+ blk_nvmem_add(disk->part0);
}
blk_apply_bdi_limits(disk->bdi, &disk->queue->limits);
@@ -704,6 +706,8 @@ static void __del_gendisk(struct gendisk *disk)
disk_del_events(disk);
+ blk_nvmem_del(disk->part0);
+
/*
* Prevent new openers by unlinked the bdev inode.
*/
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 8808ee76e73c09e0ceaac41ba59e86fb0c4efc64..6ed173c649025b95cce9253b27f68f2c7dbab8eb 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -15,6 +15,7 @@
struct bio_set;
struct bio;
struct bio_integrity_payload;
+struct nvmem_device;
struct page;
struct io_context;
struct cgroup_subsys_state;
@@ -73,6 +74,9 @@ struct block_device {
int bd_writers;
#ifdef CONFIG_SECURITY
void *bd_security;
+#endif
+#ifdef CONFIG_BLK_NVMEM
+ struct nvmem_device *bd_nvmem;
#endif
/*
* keep this out-of-line as it's both big and not needed in the fast
--
2.34.1
^ permalink raw reply related
* [PATCH v7 4/9] nvmem: layouts: Support fixed-layout as the nvmem device node itself
From: Loic Poulain @ 2026-07-01 16:00 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
Russell King, Saravana Kannan, Christian Marangi
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Loic Poulain
In-Reply-To: <20260701-block-as-nvmem-v7-0-3fe8205ef0a8@oss.qualcomm.com>
of_nvmem_layout_get_container() only looks for a child node named
"nvmem-layout" to locate the cell definitions. This does not cover
providers whose device tree node is itself the fixed-layout container,
such as an eMMC boot partition block device whose fwnode points directly
at a "fixed-layout" compatible partitions node.
When no "nvmem-layout" child is present, fall back to returning the nvmem
device node itself if it is compatible with "fixed-layout", so that its
cells are parsed by nvmem_add_cells_from_fixed_layout().
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
drivers/nvmem/layouts.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/nvmem/layouts.c b/drivers/nvmem/layouts.c
index b90584e1b99eab4217cbe7ec48373e18a7caf0dc..efa631ce7283bdd6c8ecda75915911b5e3a33c99 100644
--- a/drivers/nvmem/layouts.c
+++ b/drivers/nvmem/layouts.c
@@ -167,7 +167,18 @@ static int nvmem_layout_bus_populate(struct nvmem_device *nvmem,
struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
{
- return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
+ struct device_node *np;
+
+ /* Search for nvmem-layout child */
+ np = of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
+ if (np)
+ return np;
+
+ /* The nvmem of_node is itself a fixed-layout node */
+ if (of_device_is_compatible(nvmem->dev.of_node, "fixed-layout"))
+ return of_node_get(nvmem->dev.of_node);
+
+ return NULL;
}
EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container);
--
2.34.1
^ permalink raw reply related
* [PATCH v7 1/9] dt-bindings: mmc: Document fixed-layout NVMEM provider support
From: Loic Poulain @ 2026-07-01 16:00 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
Russell King, Saravana Kannan, Christian Marangi
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Loic Poulain
In-Reply-To: <20260701-block-as-nvmem-v7-0-3fe8205ef0a8@oss.qualcomm.com>
Allow an eMMC hardware partition node to describe an NVMEM layout so the
partition can be exposed as an NVMEM provider. This lets a partition
(e.g. an eMMC boot partition) store device-specific information such as a
WiFi MAC address or a Bluetooth BD address and reference it through NVMEM
cells.
Accept "fixed-layout" as the partition node compatible, in addition to
"fixed-partitions", so the layout can be described directly on the
partition node.
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
.../devicetree/bindings/mmc/mmc-card.yaml | 23 +++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/mmc/mmc-card.yaml b/Documentation/devicetree/bindings/mmc/mmc-card.yaml
index a61d6c96df759102f9c1fbfd548b026a77921cae..0422894508478c8d0ca68292b58a5fdbee218358 100644
--- a/Documentation/devicetree/bindings/mmc/mmc-card.yaml
+++ b/Documentation/devicetree/bindings/mmc/mmc-card.yaml
@@ -38,7 +38,9 @@ patternProperties:
properties:
compatible:
contains:
- const: fixed-partitions
+ enum:
+ - fixed-partitions
+ - fixed-layout
required:
- compatible
@@ -86,6 +88,25 @@ examples:
read-only;
};
};
+
+ partitions-boot2 {
+ compatible = "fixed-layout";
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ mac-addr@4400 {
+ compatible = "mac-base";
+ reg = <0x4400 0x6>;
+ #nvmem-cell-cells = <1>;
+ };
+
+ bd-addr@5400 {
+ compatible = "mac-base";
+ reg = <0x5400 0x6>;
+ #nvmem-cell-cells = <1>;
+ };
+ };
};
};
--
2.34.1
^ permalink raw reply related
* [PATCH v7 2/9] dt-bindings: net: wireless: qcom,ath10k: Document NVMEM cells
From: Loic Poulain @ 2026-07-01 16:00 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
Russell King, Saravana Kannan, Christian Marangi
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Loic Poulain, Bartosz Golaszewski, Krzysztof Kozlowski
In-Reply-To: <20260701-block-as-nvmem-v7-0-3fe8205ef0a8@oss.qualcomm.com>
Document the NVMEM cells supported by the ath10k driver, the
mac-address, pre-calibration data, and calibration data.
Since such data may also originate from chipset OTP or be supplied
via other device tree structures. All of these cells are optional
and can be provided independently, in any combination.
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
.../devicetree/bindings/net/wireless/qcom,ath10k.yaml | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml
index c21d66c7cd558ab792524be9afec8b79272d1c87..878c5d833a9cb073520c256c1b72d0f1489e7f4a 100644
--- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml
@@ -92,6 +92,22 @@ properties:
ieee80211-freq-limit: true
+ nvmem-cells:
+ minItems: 1
+ maxItems: 3
+ description:
+ References to nvmem cells for MAC address and/or calibration data.
+ Supported cell names are mac-address, calibration, and pre-calibration.
+
+ nvmem-cell-names:
+ minItems: 1
+ maxItems: 3
+ items:
+ enum:
+ - mac-address
+ - calibration
+ - pre-calibration
+
qcom,calibration-data:
$ref: /schemas/types.yaml#/definitions/uint8-array
description:
--
2.34.1
^ permalink raw reply related
* [PATCH v7 0/9] Support for block device NVMEM providers
From: Loic Poulain @ 2026-07-01 16:00 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
Russell King, Saravana Kannan, Christian Marangi
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Loic Poulain, Bartosz Golaszewski, Krzysztof Kozlowski,
Piotr Kwapulinski, Konrad Dybcio
On embedded devices, it is common for factory provisioning to store
device-specific information, such as Ethernet or WiFi MAC addresses,
in a dedicated area of an eMMC partition. This avoids the need for
and additional EEPROM/OTP and leverages the persistence of eMMC.
One example is the Arduino UNO-Q, where the WiFi MAC address and the
Bluetooth Device address are stored in the eMMC Boot1 partition.
Until now, accessing this information required a custom bootloader
to read the data and inject it into the Device Tree before handing
control over to the kernel. This approach is fragile and leads to
device-specific workarounds.
Rather than adding a new NVMEM provider specifically to the eMMC
subsystem, the new support operates at the block layer, allowing any
block device to behave like other non-volatile memories such as EEPROM
or OTP.
This series builds on earlier work by Daniel Golle that enables block
devices to act as NVMEM providers:
https://lore.kernel.org/all/6061aa4201030b9bb2f8d03ef32a564fdb786ed1.1709667858.git.daniel@makrotopia.org/
It also introduces an NVMEM layout description for the Arduino UNO-Q,
allowing device-specific data stored in the eMMC Boot1 partition to
be accessed in a standard way.
WiFi and Ethernet already support retrieving MAC addresses from NVMEM.
Bluetooth requires similar support, which is also addressed.
Note that this is currently limited to MMC-backed block devices, as
only the MMC core associates a firmware node with the block device
(add_disk_fwnode). This can be easily extended in the future to
support additional block drivers.
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
Changes in v7:
- Rework bindings/dts so that the eMMC boot partition can be a nvmem fixed-layout
and not a child of fixed-partition. (Rob)
- Add Support for fixed-layout as the nvmem device node itself
- Remove "block: partitions: of: Skip child nodes without reg property"
This is no more required in this series and will be submitted separately (Rob)
- Add missing linux/cleanup.h and linux/device.h includes (Bartosz)
- simplify nvmem_register() error path using dev_err_probe() (Bartosz)
- nvmem_device forward declaration to blk_types.h (Bartosz)
- Add hci_dev_get_bd_addr_from_nvmem() kernel-doc for return value (Piotr)
- Link to v6: https://lore.kernel.org/r/20260629-block-as-nvmem-v6-0-f02513dcd46d@oss.qualcomm.com
Changes in v6:
- blk_nvmem_add() returns int, error properly propagated (Bartosz)
- Redundant if (bdev->bd_nvmem) guard removed in blk_nvmem_del() (Bartosz)
- Size guard changed from UINT_MAX → INT_MAX to avoid signed overflow in config.size (sashiko)
- BLK_OPEN_RESTRICT_WRITES removed from blk_nvmem_reg_read() (sashiko)
- Link to v5: https://lore.kernel.org/r/20260612-block-as-nvmem-v5-0-95e0b30fff90@oss.qualcomm.com
Changes in v5:
- Fixed ath10k binding issue + extended commit message (Krzysztof)
- Moved blk-nvmem handling to block core instead of a class_interface
This allows correct/robust integration with block device life cycle (Bartosz).
- block: partitions: of: Skip child nodes without reg property (sashiko)
- Link to v4: https://lore.kernel.org/r/20260609-block-as-nvmem-v4-0-45712e6b22c6@oss.qualcomm.com
Changes in v4:
- Fix squash issue (dts commit incorrectly squashed) (Konrad)
- Use devres for nvmem resources (Bartosz)
- use __free() destructor helper when possible (Bartosz)
- Fix value return checking for bdev_file_open_by_dev
- Link to v3: https://lore.kernel.org/r/20260608-block-as-nvmem-v3-0-82681f50aa35@oss.qualcomm.com
Changes in v3:
- Fixed missing 'fixed-partitions' compatible in partition (Rob)
- Fixed clashing nvmem cells, document calibration along mac (Sashiko)
- Remove workaround to handle dangling nvmem references after
unregistering, this is a generic nvmem framework issue handled
in Bartosz's series:
https://lore.kernel.org/all/20260429-nvmem-unbind-v3-0-2a694f95395b@oss.qualcomm.com/
- Validate mac (is_valid_ether_addr) before copying to output buffer
- Link to v2: https://lore.kernel.org/r/20260507-block-as-nvmem-v2-0-bf17edd5134e@oss.qualcomm.com
Changes in v2:
- Fix example nvmem-layout cells to use compatible = "mac-base"
- Squash WiFi MAC and Bluetooth BD address consumer patches into the nvmem layout patch
- Fix possible use-after-free in blk-nvmem: bnv (nvmem priv) linked to nvmem lifetime
- Simplify nvmem-cell-names from items: - const: to plain const:
- Factor out common NVMEM EUI-48 retrieval logic
- Reorder changes
- Link to v1: https://lore.kernel.org/r/20260428-block-as-nvmem-v1-0-6ad23e75190a@oss.qualcomm.com
---
Daniel Golle (1):
block: implement NVMEM provider
Loic Poulain (8):
dt-bindings: mmc: Document fixed-layout NVMEM provider support
dt-bindings: net: wireless: qcom,ath10k: Document NVMEM cells
dt-bindings: bluetooth: qcom: Add NVMEM BD address cell
nvmem: layouts: Support fixed-layout as the nvmem device node itself
net: of_net: Add of_get_nvmem_eui48() helper for EUI-48 lookup
Bluetooth: hci_sync: Add NVMEM-backed BD address retrieval
Bluetooth: qca: Set NVMEM BD address quirks when address is invalid
arm64: dts: qcom: arduino-imola: Describe NVMEM layout for WiFi/BT addresses
.../devicetree/bindings/mmc/mmc-card.yaml | 23 ++++-
.../net/bluetooth/qcom,bluetooth-common.yaml | 9 ++
.../bindings/net/wireless/qcom,ath10k.yaml | 16 +++
arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts | 32 ++++++
block/Kconfig | 9 ++
block/Makefile | 1 +
block/blk-nvmem.c | 109 +++++++++++++++++++++
block/blk.h | 8 ++
block/genhd.c | 4 +
drivers/bluetooth/btqca.c | 5 +-
drivers/nvmem/layouts.c | 13 ++-
include/linux/blk_types.h | 4 +
include/linux/of_net.h | 7 ++
include/net/bluetooth/hci.h | 18 ++++
net/bluetooth/hci_sync.c | 41 +++++++-
net/core/of_net.c | 49 ++++++---
16 files changed, 332 insertions(+), 16 deletions(-)
---
base-commit: c58ba8c7e9ab26b5e8d91f8ca0e0a16c2ae318e9
change-id: 20260428-block-as-nvmem-4b308e8bda9a
Best regards,
--
Loic Poulain <loic.poulain@oss.qualcomm.com>
^ permalink raw reply
* [PATCH] dt-bindings: wireless: ath12k: allow calibration variant for WCN7850
From: Ernest Van Hoecke @ 2026-07-01 15:42 UTC (permalink / raw)
To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Jeff Johnson
Cc: Jeff Johnson, Andrew LaMarche, linux-wireless, devicetree, ath12k,
linux-kernel, Ernest Van Hoecke
From: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>
qcom,calibration-variant selects board-specific calibration data for
systems where the bus and device IDs are not unique.
This is not specific to WSI-capable QCN9274 devices. The WSI binding
already allows the property, so allow it in the WCN7850 PCI binding too.
Signed-off-by: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>
---
Document qcom,calibration-variant in the WCN7850 PCI binding. The
generic property is already documented for ath12k WSI devices in
qcom,ath12k-wsi.yaml, and selecting board-specific calibration data is
not specific to WSI-capable QCN9274 designs.
This complements Andrew LaMarche's ath12k driver series, which adds
driver support for reading qcom,calibration-variant from the device tree
and drops the deprecated qcom,ath12k-calibration-variant from the WSI
binding:
https://lore.kernel.org/ath12k/20260630133001.1426824-1-andrewjlamarche@gmail.com/T/#t
That series makes the generic property effective in the driver while
this patch closes the schema gap for WCN7850 devices.
---
Documentation/devicetree/bindings/net/wireless/qcom,ath12k.yaml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath12k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath12k.yaml
index dc68dd59988f..cf3e1fd99c12 100644
--- a/Documentation/devicetree/bindings/net/wireless/qcom,ath12k.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath12k.yaml
@@ -54,6 +54,12 @@ properties:
vddpcie1p8-supply:
description: VDD_PCIE_1P8 supply regulator handle
+ qcom,calibration-variant:
+ $ref: /schemas/types.yaml#/definitions/string
+ description:
+ String to uniquely identify variant of the calibration data for designs
+ with colliding bus and device ids
+
required:
- compatible
- reg
---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260701-ath12k-calibration-variant-b7850f7ffd7c
Best regards,
--
Ernest Van Hoecke <ernest.vanhoecke@toradex.com>
^ permalink raw reply related
* Re: [PATCH 0/4] usb: fix UAF related to dynamic ID
From: Manuel Ebner @ 2026-07-01 15:02 UTC (permalink / raw)
To: Danilo Krummrich
Cc: Gary Guo, Greg Kroah-Hartman, Rafael J. Wysocki,
Toke Høiland-Jørgensen, Johan Hovold, linux-wireless,
linux-kernel, linux-usb, driver-core
In-Reply-To: <DJMFC6N91KK9.6Y2UKU1Q0TWA@kernel.org>
On Tue, 2026-06-30 at 15:39 +0200, Danilo Krummrich wrote:
> Hi Manuel,
>
> On Tue Jun 30, 2026 at 3:26 PM CEST, Manuel Ebner wrote:
> > On Tue, 2026-06-30 at 12:38 +0100, Gary Guo wrote:
> > > [...]
> > >
> > > Signed-off-by: Gary Guo <gary@garyguo.net>
> >
> > For all four patches:
> > LGTM.
> >
> > I guess I'm not in a position to Acked-by or Reviewed-by.
>
> I don't know your background and I don't want to make any assumptions, so please
> don't interpret anything in my attempt to clarify a bit.
>
> As documented in [1] "any interested reviewer (who has done the work and is a
> person with known identity) can offer a Reviewed-by tag for a patch".
>
> An offer from anyone who has done this work is much appreciated.
>
Then you can add my
Reviewed-by: Manuel Ebner <manuelebner@mailbox.org>
to all 4 patches.
Manuel
> Acked-by is usually used by stakeholders of the code (most commonly maintainers)
> to indicate acceptance, e.g. for patch routing purposes. There are more details
> in [2].
>
> [1]
> https://docs.kernel.org/process/submitting-patches.html#reviewer-s-statement-of-oversight
> [2]
> https://docs.kernel.org/process/submitting-patches.html#when-to-use-acked-by-cc-and-co-developed-by
^ permalink raw reply
* Re: rtw89: RTL8852BE P2P-device iftype and STA+P2P interface combination
From: Doug Brewer @ 2026-07-01 14:06 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <CAG0V13T_Ujautadyaqxjy_8zqWFbz1JiRp9bpWO-T7Gy9O+mnA@mail.gmail.com>
On Wed, Jul 1, 2026 at 2:40 PM Doug Brewer wrote:
>
> On Tue, Jun 30, 2026 at 8:51 AM Ping-Ke Shih wrote:
> >
> > Doug Brewer wrote:
> > > On Mon, Jun 29, 2026 at 10:10 AM Ping-Ke Shih wrote:
> > > >
> > > > Doug Brewer wrote:
> > > > > Hi,
> > > > >
> > > > > I'm experimenting with Wi-Fi Display (Miracast sink) concurrent with an
> > > > > STA connection on an RTL8852BE (PCIe) using the mainline rtw89 driver
> > > > > (kernel 6.18.37).
> > > > >
> > > > > iw phy reports:
> > > > > Supported interface modes:
> > > > > * managed, AP, P2P-client, P2P-GO
> > > > > (no P2P-device)
> > > > > interface combinations are not supported
> > > > >
> > > > > In practice this blocks the standard P2P flow: there is no P2P-device
> > > > > iftype for a dedicated discovery context, and no advertised interface
> > > > > combination for managed + P2P-client coexistence.
> > > > >
> > > > > My questions:
> > > > > 1. is P2P-device iftype support planned for rtw89 on RTL885x? Is there a
> > > > > known technical blocker, or is it simply not yet implemented?
> > > >
> > > > We are planning to add P2P-device iftype. It needs to consider the cases of
> > > > channel context, conditions of power save, and etc. It will take some time.
> > > >
> > > > I think it would be okay that you use STA interface to do P2P negotiation,
> > > > and then create P2P-client or P2P-GO iftype then.
> > > >
> > > > > 2. would advertising a managed + P2P-client interface combination
> > > > > (single channel) be feasible on the current rtw89?
> > > >
> > > > This is a SCC which is supported.
> > > >
> > > > > 3. is MCC (#channels > 1) on the roadmap, or considered out of scope?
> > > >
> > > > Current support MCC as well. However, we are cooking new firmware to support
> > > > hw_scan with two operation channels -- which doesn't matter if you don't need
> > > > to do scan when MCC is operating.
> > >
> > > Thanks for the suggestion. I tried using the STA interface for P2P
> > > negotiation, and wanted to share what I found.
> > >
> > > With the STA connected (2.4GHz ch11) and an active p2p_connect, a
> > > wpa_supplicant -dd trace shows GO negotiation getting fairly far:
> > >
> > > Peer's GO-NEG Request is received
> > > send the GO-NEG Response on ch11, peer ACKs it (TX ack=1)
> > > State goes GO_NEG -> CONNECT
> > > then time out waiting for the GO-NEG Confirm, status=-1
> > >
> > > I select ch11 as the P2P operating channel (same as STA, SCC), while
> > > the peer's operating preference is 5GHz ch149. It looks like after we TX
> > > the Response, the radio doesn't stay on ch11 to listen for the Confirm,
> > > so the frame is missed -- presumably because the single radio is serving
> > > the STA connection.
> >
> > So, peer doesn't stay ch11 to complete he negotiation, right?
> >
> > What is the peer device you are using? Can you setup another RTL8852BE?
> > I suggest running simple scenario first to dig cause.
> >
> > 1. two peers make P2P group without any STA connection
> > 2. RTL8852BE with a STA connection, and peer without connection.
> >
> > >
> > > Aalso tested with the STA on 5GHz (ch149); the result is the same
> > > GO-NEG Confirm timeout.
> > >
> > > Is this the channel-context issue that P2P-device iftype will address?
> > > And with the current driver, is there any way to keep the P2P listen
> > > context on the operating channel during GO negotiation while STA is up?
> >
> > Before P2P negotiation completion, there is only one channel context.
> > The second interface (GC or GO) is created when the P2P role is decided
> > by P2P negotiation.
> >
> > You need to check supplicant log about channels on both peers. I think
> > remain-on-channel is the method supplicant switch channel to send
> > negotiation frames and to stay on listen channel.
> >
> > >
> > > (FWIW, passing an explicit freq= to p2p_connect is rejected with FAIL,
> > > whether or not it matches the STA channel.)
> >
> > Not sure why. In our side, it seems work.
> >
> >
> > I'd share a pair of wpa_supplicant .conf and wpa_cli commands we are testing
> > for reference.
>
> Great progress using your test conf and a second RTL8852BE. Results:
>
> Two RTL8852BE peers, no STA — P2P connects fine (GO/client, group formed,
> 4-way HS completed).
>
> One RTL8852BE with STA on 5GHz ch149, the other RTL8852BE with no STA,
> also succeeds. The GO comes up on ch153 while the STA stays on ch149 (so MCC),
> group formed, client connected. Both sides confirmed via iw dev
> (GO on ch153 + STA on ch149; peer client on ch153).
>
> So STA + P2P coexistence, including MCC, works fine between two 8852BE peers.
>
> p2p_no_group_iface=1 in your conf may have contributed, P2P runs on the main
> interface instead of a separate group interface.
>
> Thank you very much for the test conf and guidance.
One more update. Two RTL8852BE peers (STA + P2P) work reliably, as
reported.
However, with a Samsung phone as the peer, GO negotiation is
inconsistent — using your conf (including p2p_no_group_iface=1), the same
setup sometimes completes and sometimes fails with GO-NEG Confirm timeout
(status=-1).
Do you have any suggestion for this case with a real phone peer?
Thank you again for the guidance.
Regards,
Doug
^ permalink raw reply
* [PATCH] wifi: mt76: Fix missing barrier after initialization check in ath9k_wmi_event_tasklet()
From: Thomas Fourier @ 2026-07-01 13:57 UTC (permalink / raw)
Cc: Thomas Fourier, Toke Høiland-Jørgensen, Kalle Valo,
Tetsuo Handa, linux-wireless, linux-kernel
The write memory barrier in ath9k_htc_probe_device() before writing to
priv->initialized, so it seems like one is also needed after reading it,
but seems like there is none after reading priv->initialized.
Add a read barrier after reading the priv->initialized flag to prevent
reordering of reads.
Fixes: 8b3046abc99e ("ath9k_htc: fix NULL pointer dereference at ath9k_htc_tx_get_packet()")
Signed-off-by: Thomas Fourier <fourier.thomas@gmail.com>
---
drivers/net/wireless/ath/ath9k/wmi.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index 284e8c13b043..1e28599a6146 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -160,6 +160,11 @@ void ath9k_wmi_event_tasklet(struct tasklet_struct *t)
kfree_skb(skb);
continue;
}
+ /*
+ * Make sure ath9k_htc_probe_device() initialization is
+ * committed to memory before processing skb.
+ */
+ smp_rmb();
hdr = (struct wmi_cmd_hdr *) skb->data;
cmd_id = be16_to_cpu(hdr->command_id);
--
2.43.0
^ permalink raw reply related
* [PATCH 4/4] wlcore: allocate aggregation and firmware log buffers with kzalloc()
From: Mike Rapoport (Microsoft) @ 2026-07-01 13:59 UTC (permalink / raw)
To: Johannes Berg
Cc: Brian Norris, Francesco Dolcini, Jakub Kicinski, Mike Rapoport,
b43-dev, libertas-dev, linux-kernel, linux-mm, linux-wireless,
netdev
In-Reply-To: <20260701-b4-drivers-wireless-v1-0-60264cdf2efe@kernel.org>
wlcore_alloc_hw() uses __get_free_pages() to allocate TX aggregation
and firmware log buffers used for software data staging.
These buffer can be allocated with kmalloc() as there's nothing special
about them to go directly to the page allocator.
kmalloc() provides a better API that does not require ugly casts and
kfree() does not need to know the size of the freed object.
Performance difference between kmalloc() and __get_free_pages() is not
measurable as both allocators take an object/page from a per-CPU list for
fast path allocations.
For the slow path the performance is anyway determined by the amount of
reclaim involved rather than by what allocator is used.
Replace use of __get_free_pages() with kzalloc() and free_pages() with
kfree().
Link: https://lore.kernel.org/all/635405e4-9423-4a25-a6e7-e03c8ea0bcbe@redhat.com
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
drivers/net/wireless/ti/wlcore/main.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index be583ae331c0..5595f7a1fc0c 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -6354,7 +6354,6 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
struct ieee80211_hw *hw;
struct wl1271 *wl;
int i, j, ret;
- unsigned int order;
hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
if (!hw) {
@@ -6434,8 +6433,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
mutex_init(&wl->flush_mutex);
init_completion(&wl->nvs_loading_complete);
- order = get_order(aggr_buf_size);
- wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
+ wl->aggr_buf = kmalloc(round_up(aggr_buf_size, PAGE_SIZE), GFP_KERNEL);
if (!wl->aggr_buf) {
ret = -ENOMEM;
goto err_wq;
@@ -6449,7 +6447,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
}
/* Allocate one page for the FW log */
- wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
+ wl->fwlog = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!wl->fwlog) {
ret = -ENOMEM;
goto err_dummy_packet;
@@ -6474,13 +6472,13 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
kfree(wl->mbox);
err_fwlog:
- free_page((unsigned long)wl->fwlog);
+ kfree(wl->fwlog);
err_dummy_packet:
dev_kfree_skb(wl->dummy_packet);
err_aggr:
- free_pages((unsigned long)wl->aggr_buf, order);
+ kfree(wl->aggr_buf);
err_wq:
destroy_workqueue(wl->freezable_wq);
@@ -6509,9 +6507,9 @@ int wlcore_free_hw(struct wl1271 *wl)
kfree(wl->buffer_32);
kfree(wl->mbox);
- free_page((unsigned long)wl->fwlog);
+ kfree(wl->fwlog);
dev_kfree_skb(wl->dummy_packet);
- free_pages((unsigned long)wl->aggr_buf, get_order(wl->aggr_buf_size));
+ kfree(wl->aggr_buf);
wl1271_debugfs_exit(wl);
--
2.53.0
^ permalink raw reply related
* [PATCH 3/4] mwifiex: debugfs: use kzalloc() to allocate formatting buffers
From: Mike Rapoport (Microsoft) @ 2026-07-01 13:59 UTC (permalink / raw)
To: Johannes Berg
Cc: Brian Norris, Francesco Dolcini, Jakub Kicinski, Mike Rapoport,
b43-dev, libertas-dev, linux-kernel, linux-mm, linux-wireless,
netdev
In-Reply-To: <20260701-b4-drivers-wireless-v1-0-60264cdf2efe@kernel.org>
mwifiex debugfs functions allocate buffers for formatting debug output
text using get_zeroed_page().
These buffers can be allocated with kmalloc() as there's nothing special
about them to go directly to the page allocator.
kmalloc() provides a better API that does not require ugly casts and
kfree() does not need to know the size of the freed object.
Performance difference between kmalloc() and __get_free_pages() is not
measurable as both allocators take an object/page from a per-CPU list for
fast path allocations.
For the slow path the performance is anyway determined by the amount of
reclaim involved rather than by what allocator is used.
Replace use of get_zeroed_page() with kzalloc() and free_page() with
kfree().
Link: https://lore.kernel.org/all/635405e4-9423-4a25-a6e7-e03c8ea0bcbe@redhat.com
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
drivers/net/wireless/marvell/mwifiex/debugfs.c | 62 +++++++++++---------------
1 file changed, 27 insertions(+), 35 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c
index 9deaf59dcb62..573768b6ad91 100644
--- a/drivers/net/wireless/marvell/mwifiex/debugfs.c
+++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c
@@ -6,6 +6,7 @@
*/
#include <linux/debugfs.h>
+#include <linux/slab.h>
#include "main.h"
#include "11n.h"
@@ -67,8 +68,8 @@ mwifiex_info_read(struct file *file, char __user *ubuf,
struct net_device *netdev = priv->netdev;
struct netdev_hw_addr *ha;
struct netdev_queue *txq;
- unsigned long page = get_zeroed_page(GFP_KERNEL);
- char *p = (char *) page, fmt[64];
+ char *page = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ char *p = page, fmt[64];
struct mwifiex_bss_info info;
ssize_t ret;
int i = 0;
@@ -133,11 +134,10 @@ mwifiex_info_read(struct file *file, char __user *ubuf,
}
p += sprintf(p, "\n");
- ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
- (unsigned long) p - page);
+ ret = simple_read_from_buffer(ubuf, count, ppos, page, p - page);
free_and_exit:
- free_page(page);
+ kfree(page);
return ret;
}
@@ -168,8 +168,8 @@ mwifiex_getlog_read(struct file *file, char __user *ubuf,
{
struct mwifiex_private *priv =
(struct mwifiex_private *) file->private_data;
- unsigned long page = get_zeroed_page(GFP_KERNEL);
- char *p = (char *) page;
+ char *page = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ char *p = page;
ssize_t ret;
struct mwifiex_ds_get_stats stats;
@@ -220,11 +220,10 @@ mwifiex_getlog_read(struct file *file, char __user *ubuf,
stats.bcn_miss_cnt);
- ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
- (unsigned long) p - page);
+ ret = simple_read_from_buffer(ubuf, count, ppos, page, p - page);
free_and_exit:
- free_page(page);
+ kfree(page);
return ret;
}
@@ -247,8 +246,8 @@ mwifiex_histogram_read(struct file *file, char __user *ubuf,
ssize_t ret;
struct mwifiex_histogram_data *phist_data;
int i, value;
- unsigned long page = get_zeroed_page(GFP_KERNEL);
- char *p = (char *)page;
+ char *page = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ char *p = page;
if (!p)
return -ENOMEM;
@@ -309,11 +308,10 @@ mwifiex_histogram_read(struct file *file, char __user *ubuf,
i, value);
}
- ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page,
- (unsigned long)p - page);
+ ret = simple_read_from_buffer(ubuf, count, ppos, page, p - page);
free_and_exit:
- free_page(page);
+ kfree(page);
return ret;
}
@@ -383,8 +381,8 @@ mwifiex_debug_read(struct file *file, char __user *ubuf,
{
struct mwifiex_private *priv =
(struct mwifiex_private *) file->private_data;
- unsigned long page = get_zeroed_page(GFP_KERNEL);
- char *p = (char *) page;
+ char *page = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ char *p = page;
ssize_t ret;
if (!p)
@@ -396,11 +394,10 @@ mwifiex_debug_read(struct file *file, char __user *ubuf,
p += mwifiex_debug_info_to_buffer(priv, p, &info);
- ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
- (unsigned long) p - page);
+ ret = simple_read_from_buffer(ubuf, count, ppos, page, p - page);
free_and_exit:
- free_page(page);
+ kfree(page);
return ret;
}
@@ -457,8 +454,7 @@ mwifiex_regrdwr_read(struct file *file, char __user *ubuf,
{
struct mwifiex_private *priv =
(struct mwifiex_private *) file->private_data;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *) addr;
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
int pos = 0, ret = 0;
u32 reg_value;
@@ -497,7 +493,7 @@ mwifiex_regrdwr_read(struct file *file, char __user *ubuf,
ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
done:
- free_page(addr);
+ kfree(buf);
return ret;
}
@@ -511,8 +507,7 @@ mwifiex_debug_mask_read(struct file *file, char __user *ubuf,
{
struct mwifiex_private *priv =
(struct mwifiex_private *)file->private_data;
- unsigned long page = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)page;
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
size_t ret = 0;
int pos = 0;
@@ -523,7 +518,7 @@ mwifiex_debug_mask_read(struct file *file, char __user *ubuf,
priv->adapter->debug_mask);
ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
- free_page(page);
+ kfree(buf);
return ret;
}
@@ -652,8 +647,7 @@ mwifiex_memrw_read(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
struct mwifiex_private *priv = (void *)file->private_data;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
int ret, pos = 0;
if (!buf)
@@ -663,7 +657,7 @@ mwifiex_memrw_read(struct file *file, char __user *ubuf,
priv->mem_rw.value);
ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
- free_page(addr);
+ kfree(buf);
return ret;
}
@@ -719,8 +713,7 @@ mwifiex_rdeeprom_read(struct file *file, char __user *ubuf,
{
struct mwifiex_private *priv =
(struct mwifiex_private *) file->private_data;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *) addr;
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
int pos, ret, i;
u8 value[MAX_EEPROM_DATA];
@@ -749,7 +742,7 @@ mwifiex_rdeeprom_read(struct file *file, char __user *ubuf,
done:
ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
out_free:
- free_page(addr);
+ kfree(buf);
return ret;
}
@@ -820,8 +813,7 @@ mwifiex_hscfg_read(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
struct mwifiex_private *priv = (void *)file->private_data;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
int pos, ret;
struct mwifiex_ds_hs_cfg hscfg;
@@ -836,7 +828,7 @@ mwifiex_hscfg_read(struct file *file, char __user *ubuf,
ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
- free_page(addr);
+ kfree(buf);
return ret;
}
--
2.53.0
^ permalink raw reply related
* [PATCH 2/4] libertas: debugfs: use kzalloc() to allocate formatting buffers
From: Mike Rapoport (Microsoft) @ 2026-07-01 13:59 UTC (permalink / raw)
To: Johannes Berg
Cc: Brian Norris, Francesco Dolcini, Jakub Kicinski, Mike Rapoport,
b43-dev, libertas-dev, linux-kernel, linux-mm, linux-wireless,
netdev
In-Reply-To: <20260701-b4-drivers-wireless-v1-0-60264cdf2efe@kernel.org>
libertas debugfs functions allocate buffers for formatting debug
output text using get_zeroed_page().
These buffers can be allocated with kmalloc() as there's nothing special
about them to go directly to the page allocator.
kmalloc() provides a better API that does not require ugly casts and
kfree() does not need to know the size of the freed object.
Performance difference between kmalloc() and __get_free_pages() is not
measurable as both allocators take an object/page from a per-CPU list for
fast path allocations.
For the slow path the performance is anyway determined by the amount of
reclaim involved rather than by what allocator is used.
Replace use of get_zeroed_page() with kzalloc() and free_page() with
kfree().
Link: https://lore.kernel.org/all/635405e4-9423-4a25-a6e7-e03c8ea0bcbe@redhat.com
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
drivers/net/wireless/marvell/libertas/debugfs.c | 39 ++++++++++---------------
1 file changed, 16 insertions(+), 23 deletions(-)
diff --git a/drivers/net/wireless/marvell/libertas/debugfs.c b/drivers/net/wireless/marvell/libertas/debugfs.c
index 9ebd69134940..9428f954837a 100644
--- a/drivers/net/wireless/marvell/libertas/debugfs.c
+++ b/drivers/net/wireless/marvell/libertas/debugfs.c
@@ -35,8 +35,7 @@ static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
{
struct lbs_private *priv = file->private_data;
size_t pos = 0;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
ssize_t res;
if (!buf)
return -ENOMEM;
@@ -48,7 +47,7 @@ static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
- free_page(addr);
+ kfree(buf);
return res;
}
@@ -96,8 +95,7 @@ static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
ssize_t ret;
size_t pos = 0;
struct sleep_params sp;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -113,7 +111,7 @@ static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
out_unlock:
- free_page(addr);
+ kfree(buf);
return ret;
}
@@ -165,8 +163,7 @@ static ssize_t lbs_host_sleep_read(struct file *file, char __user *userbuf,
struct lbs_private *priv = file->private_data;
ssize_t ret;
size_t pos = 0;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -174,7 +171,7 @@ static ssize_t lbs_host_sleep_read(struct file *file, char __user *userbuf,
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
- free_page(addr);
+ kfree(buf);
return ret;
}
@@ -228,7 +225,7 @@ static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
u8 freq;
int events = 0;
- buf = (char *)get_zeroed_page(GFP_KERNEL);
+ buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -261,7 +258,7 @@ static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
kfree(subscribed);
out_page:
- free_page((unsigned long)buf);
+ kfree(buf);
return ret;
}
@@ -436,8 +433,7 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
struct lbs_private *priv = file->private_data;
ssize_t pos = 0;
int ret;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
u32 val = 0;
if (!buf)
@@ -450,7 +446,7 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
priv->mac_offset, val);
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
}
- free_page(addr);
+ kfree(buf);
return ret;
}
@@ -506,8 +502,7 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
struct lbs_private *priv = file->private_data;
ssize_t pos = 0;
int ret;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
u32 val;
if (!buf)
@@ -520,7 +515,7 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
priv->bbp_offset, val);
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
}
- free_page(addr);
+ kfree(buf);
return ret;
}
@@ -578,8 +573,7 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
struct lbs_private *priv = file->private_data;
ssize_t pos = 0;
int ret;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
u32 val;
if (!buf)
@@ -592,7 +586,7 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
priv->rf_offset, val);
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
}
- free_page(addr);
+ kfree(buf);
return ret;
}
@@ -812,8 +806,7 @@ static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
char *p;
int i;
struct debug_data *d;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -836,7 +829,7 @@ static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
- free_page(addr);
+ kfree(buf);
return res;
}
--
2.53.0
^ permalink raw reply related
* [PATCH 1/4] b43, b43legacy: debugfs: use kzalloc() to allocate formatting buffers
From: Mike Rapoport (Microsoft) @ 2026-07-01 13:59 UTC (permalink / raw)
To: Johannes Berg
Cc: Brian Norris, Francesco Dolcini, Jakub Kicinski, Mike Rapoport,
b43-dev, libertas-dev, linux-kernel, linux-mm, linux-wireless,
netdev
In-Reply-To: <20260701-b4-drivers-wireless-v1-0-60264cdf2efe@kernel.org>
b43* debugfs functions allocate 16 KiB buffers for formatting debug output
text using __get_free_pages().
kzalloc() provides a better API that does not require ugly casts and
kfree() does not need to know the size of the freed object and for 16 Kib
allocation kzalloc() will anyway delegate it to buddy.
Replace use of __get_free_pages() with kzalloc().
Link: https://lore.kernel.org/all/635405e4-9423-4a25-a6e7-e03c8ea0bcbe@redhat.com
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
drivers/net/wireless/broadcom/b43/debugfs.c | 12 +++++-------
drivers/net/wireless/broadcom/b43legacy/debugfs.c | 12 +++++-------
2 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/drivers/net/wireless/broadcom/b43/debugfs.c b/drivers/net/wireless/broadcom/b43/debugfs.c
index acddae68947a..31a1ff00c1a4 100644
--- a/drivers/net/wireless/broadcom/b43/debugfs.c
+++ b/drivers/net/wireless/broadcom/b43/debugfs.c
@@ -495,7 +495,6 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
ssize_t ret;
char *buf;
const size_t bufsize = 1024 * 16; /* 16 kiB buffer */
- const size_t buforder = get_order(bufsize);
int err = 0;
if (!count)
@@ -518,15 +517,14 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
dfile = fops_to_dfs_file(dev, dfops);
if (!dfile->buffer) {
- buf = (char *)__get_free_pages(GFP_KERNEL, buforder);
+ buf = kzalloc(bufsize, GFP_KERNEL);
if (!buf) {
err = -ENOMEM;
goto out_unlock;
}
- memset(buf, 0, bufsize);
ret = dfops->read(dev, buf, bufsize);
if (ret <= 0) {
- free_pages((unsigned long)buf, buforder);
+ kfree(buf);
err = ret;
goto out_unlock;
}
@@ -538,7 +536,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
dfile->buffer,
dfile->data_len);
if (*ppos >= dfile->data_len) {
- free_pages((unsigned long)dfile->buffer, buforder);
+ kfree(dfile->buffer);
dfile->buffer = NULL;
dfile->data_len = 0;
}
@@ -577,7 +575,7 @@ static ssize_t b43_debugfs_write(struct file *file,
goto out_unlock;
}
- buf = (char *)get_zeroed_page(GFP_KERNEL);
+ buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf) {
err = -ENOMEM;
goto out_unlock;
@@ -591,7 +589,7 @@ static ssize_t b43_debugfs_write(struct file *file,
goto out_freepage;
out_freepage:
- free_page((unsigned long)buf);
+ kfree(buf);
out_unlock:
mutex_unlock(&dev->wl->mutex);
diff --git a/drivers/net/wireless/broadcom/b43legacy/debugfs.c b/drivers/net/wireless/broadcom/b43legacy/debugfs.c
index 3ad99124d522..a04d90d7307c 100644
--- a/drivers/net/wireless/broadcom/b43legacy/debugfs.c
+++ b/drivers/net/wireless/broadcom/b43legacy/debugfs.c
@@ -192,7 +192,6 @@ static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf,
ssize_t ret;
char *buf;
const size_t bufsize = 1024 * 16; /* 16 KiB buffer */
- const size_t buforder = get_order(bufsize);
int err = 0;
if (!count)
@@ -215,12 +214,11 @@ static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf,
dfile = fops_to_dfs_file(dev, dfops);
if (!dfile->buffer) {
- buf = (char *)__get_free_pages(GFP_KERNEL, buforder);
+ buf = kzalloc(bufsize, GFP_KERNEL);
if (!buf) {
err = -ENOMEM;
goto out_unlock;
}
- memset(buf, 0, bufsize);
if (dfops->take_irqlock) {
spin_lock_irq(&dev->wl->irq_lock);
ret = dfops->read(dev, buf, bufsize);
@@ -228,7 +226,7 @@ static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf,
} else
ret = dfops->read(dev, buf, bufsize);
if (ret <= 0) {
- free_pages((unsigned long)buf, buforder);
+ kfree(buf);
err = ret;
goto out_unlock;
}
@@ -240,7 +238,7 @@ static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf,
dfile->buffer,
dfile->data_len);
if (*ppos >= dfile->data_len) {
- free_pages((unsigned long)dfile->buffer, buforder);
+ kfree(dfile->buffer);
dfile->buffer = NULL;
dfile->data_len = 0;
}
@@ -279,7 +277,7 @@ static ssize_t b43legacy_debugfs_write(struct file *file,
goto out_unlock;
}
- buf = (char *)get_zeroed_page(GFP_KERNEL);
+ buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf) {
err = -ENOMEM;
goto out_unlock;
@@ -298,7 +296,7 @@ static ssize_t b43legacy_debugfs_write(struct file *file,
goto out_freepage;
out_freepage:
- free_page((unsigned long)buf);
+ kfree(buf);
out_unlock:
mutex_unlock(&dev->wl->mutex);
--
2.53.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox