Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH v2 8/9] rtc: rv3032: switch to using FIELD_GET_SIGNED()
From: Yury Norov @ 2026-04-27 21:41 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Jonathan Cameron,
	David Lechner, Johannes Berg, David Laight, Nuno Sá,
	Andy Shevchenko, Ping-Ke Shih, Richard Cochran, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Alexandre Belloni, Yury Norov, Rasmus Villemoes, Hans de Goede,
	Linus Walleij, Sakari Ailus, Salah Triki, Achim Gratz,
	Ben Collins, x86, linux-kernel, linux-iio, linux-wireless, netdev,
	linux-rtc
  Cc: Yury Norov
In-Reply-To: <20260427214127.406067-1-ynorov@nvidia.com>

Switch from sign_extend32(FIELD_GET()) to the dedicated
FIELD_GET_SIGNED() and don't calculate the fields length explicitly.

Signed-off-by: Yury Norov <ynorov@nvidia.com>
---
 drivers/rtc/rtc-rv3032.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c
index 6c09da7738e1..6bafdec637ae 100644
--- a/drivers/rtc/rtc-rv3032.c
+++ b/drivers/rtc/rtc-rv3032.c
@@ -376,7 +376,7 @@ static int rv3032_read_offset(struct device *dev, long *offset)
 	if (ret < 0)
 		return ret;
 
-	steps = sign_extend32(FIELD_GET(RV3032_OFFSET_MSK, value), 5);
+	steps = FIELD_GET_SIGNED(RV3032_OFFSET_MSK, value);
 
 	*offset = DIV_ROUND_CLOSEST(steps * OFFSET_STEP_PPT, 1000);
 
-- 
2.51.0


^ permalink raw reply related

* [PATCH v2 7/9] wifi: rtw89: switch to using FIELD_GET_SIGNED()
From: Yury Norov @ 2026-04-27 21:41 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Jonathan Cameron,
	David Lechner, Johannes Berg, David Laight, Nuno Sá,
	Andy Shevchenko, Ping-Ke Shih, Richard Cochran, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Alexandre Belloni, Yury Norov, Rasmus Villemoes, Hans de Goede,
	Linus Walleij, Sakari Ailus, Salah Triki, Achim Gratz,
	Ben Collins, x86, linux-kernel, linux-iio, linux-wireless, netdev,
	linux-rtc
  Cc: Yury Norov
In-Reply-To: <20260427214127.406067-1-ynorov@nvidia.com>

Switch from sign_extend32(FIELD_GET()) to the dedicated
FIELD_GET_SIGNED() and don't calculate the fields length explicitly.

Signed-off-by: Yury Norov <ynorov@nvidia.com>
---
 drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c    | 4 ++--
 drivers/net/wireless/realtek/rtw89/rtw8852b_common.c | 4 ++--
 drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c    | 4 ++--
 drivers/net/wireless/realtek/rtw89/rtw8852c.c        | 4 ++--
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c
index 463399413318..8679b21fd3fd 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c
@@ -334,8 +334,8 @@ static void _check_addc(struct rtw89_dev *rtwdev, enum rtw89_rf_path path)
 
 	for (i = 0; i < ADDC_T_AVG; i++) {
 		tmp = rtw89_phy_read32_mask(rtwdev, R_DBG32_D, MASKDWORD);
-		dc_re += sign_extend32(FIELD_GET(0xfff000, tmp), 11);
-		dc_im += sign_extend32(FIELD_GET(0xfff, tmp), 11);
+		dc_re += FIELD_GET_SIGNED(0xfff000, tmp);
+		dc_im += FIELD_GET_SIGNED(0xfff, tmp);
 	}
 
 	dc_re /= ADDC_T_AVG;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c
index 65b839323e3e..df5fbae50ff5 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c
@@ -206,9 +206,9 @@ static void rtw8852bx_efuse_parsing_tssi(struct rtw89_dev *rtwdev,
 static bool _decode_efuse_gain(u8 data, s8 *high, s8 *low)
 {
 	if (high)
-		*high = sign_extend32(FIELD_GET(GENMASK(7,  4), data), 3);
+		*high = FIELD_GET_SIGNED(GENMASK(7,  4), data);
 	if (low)
-		*low = sign_extend32(FIELD_GET(GENMASK(3,  0), data), 3);
+		*low = FIELD_GET_SIGNED(GENMASK(3,  0), data);
 
 	return data != 0xff;
 }
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c
index 70b1515c00fa..8db6ea475128 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c
@@ -497,8 +497,8 @@ static void _check_addc(struct rtw89_dev *rtwdev, enum rtw89_rf_path path)
 
 	for (i = 0; i < ADDC_T_AVG; i++) {
 		tmp = rtw89_phy_read32_mask(rtwdev, R_DBG32_D, MASKDWORD);
-		dc_re += sign_extend32(FIELD_GET(0xfff000, tmp), 11);
-		dc_im += sign_extend32(FIELD_GET(0xfff, tmp), 11);
+		dc_re += FIELD_GET_SIGNED(0xfff000, tmp);
+		dc_im += FIELD_GET_SIGNED(0xfff, tmp);
 	}
 
 	dc_re /= ADDC_T_AVG;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 40db7e3c0d97..32eecd184b7c 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -517,9 +517,9 @@ static void rtw8852c_efuse_parsing_tssi(struct rtw89_dev *rtwdev,
 static bool _decode_efuse_gain(u8 data, s8 *high, s8 *low)
 {
 	if (high)
-		*high = sign_extend32(FIELD_GET(GENMASK(7,  4), data), 3);
+		*high = FIELD_GET_SIGNED(GENMASK(7, 4), data);
 	if (low)
-		*low = sign_extend32(FIELD_GET(GENMASK(3,  0), data), 3);
+		*low = FIELD_GET_SIGNED(GENMASK(3, 0), data);
 
 	return data != 0xff;
 }
-- 
2.51.0


^ permalink raw reply related

* [PATCH v2 6/9] iio: mcp9600: switch to using FIELD_GET_SIGNED()
From: Yury Norov @ 2026-04-27 21:41 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Jonathan Cameron,
	David Lechner, Johannes Berg, David Laight, Nuno Sá,
	Andy Shevchenko, Ping-Ke Shih, Richard Cochran, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Alexandre Belloni, Yury Norov, Rasmus Villemoes, Hans de Goede,
	Linus Walleij, Sakari Ailus, Salah Triki, Achim Gratz,
	Ben Collins, x86, linux-kernel, linux-iio, linux-wireless, netdev,
	linux-rtc
  Cc: Yury Norov
In-Reply-To: <20260427214127.406067-1-ynorov@nvidia.com>

Switch from sign_extend32(FIELD_GET()) to the dedicated
FIELD_GET_SIGNED() and don't calculate the fields length explicitly.

Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Yury Norov <ynorov@nvidia.com>
---
 drivers/iio/temperature/mcp9600.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c
index aa42c2b1a369..69baf654c9c0 100644
--- a/drivers/iio/temperature/mcp9600.c
+++ b/drivers/iio/temperature/mcp9600.c
@@ -297,7 +297,7 @@ static int mcp9600_read_thresh(struct iio_dev *indio_dev,
 		 * Temperature is stored in two’s complement format in
 		 * bits(15:2), LSB is 0.25 degree celsius.
 		 */
-		*val = sign_extend32(FIELD_GET(MCP9600_ALERT_LIMIT_MASK, ret), 13);
+		*val = FIELD_GET_SIGNED(MCP9600_ALERT_LIMIT_MASK, ret);
 		*val2 = 4;
 		return IIO_VAL_FRACTIONAL;
 	case IIO_EV_INFO_HYSTERESIS:
-- 
2.51.0


^ permalink raw reply related

* [PATCH v2 5/9] iio: pressure: bmp280: switch to using FIELD_GET_SIGNED()
From: Yury Norov @ 2026-04-27 21:41 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Jonathan Cameron,
	David Lechner, Johannes Berg, David Laight, Nuno Sá,
	Andy Shevchenko, Ping-Ke Shih, Richard Cochran, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Alexandre Belloni, Yury Norov, Rasmus Villemoes, Hans de Goede,
	Linus Walleij, Sakari Ailus, Salah Triki, Achim Gratz,
	Ben Collins, x86, linux-kernel, linux-iio, linux-wireless, netdev,
	linux-rtc
  Cc: Yury Norov
In-Reply-To: <20260427214127.406067-1-ynorov@nvidia.com>

Switch from sign_extend32(FIELD_GET()) to the dedicated
FIELD_GET_SIGNED() and don't calculate the fields length explicitly.

Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Yury Norov <ynorov@nvidia.com>
---
 drivers/iio/pressure/bmp280-core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index d983ce9c0b99..f722aea16e0e 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -392,7 +392,7 @@ static int bme280_read_calib(struct bmp280_data *data)
 	h4_lower = FIELD_GET(BME280_COMP_H4_MASK_LOW, tmp_1);
 	calib->H4 = sign_extend32(h4_upper | h4_lower, 11);
 	tmp_3 = get_unaligned_le16(&data->bme280_humid_cal_buf[H5]);
-	calib->H5 = sign_extend32(FIELD_GET(BME280_COMP_H5_MASK, tmp_3), 11);
+	calib->H5 = FIELD_GET_SIGNED(BME280_COMP_H5_MASK, tmp_3);
 	calib->H6 = data->bme280_humid_cal_buf[H6];
 
 	return 0;
-- 
2.51.0


^ permalink raw reply related

* [PATCH v2 4/9] iio: magnetometer: yas530: switch to using FIELD_GET_SIGNED()
From: Yury Norov @ 2026-04-27 21:41 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Jonathan Cameron,
	David Lechner, Johannes Berg, David Laight, Nuno Sá,
	Andy Shevchenko, Ping-Ke Shih, Richard Cochran, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Alexandre Belloni, Yury Norov, Rasmus Villemoes, Hans de Goede,
	Linus Walleij, Sakari Ailus, Salah Triki, Achim Gratz,
	Ben Collins, x86, linux-kernel, linux-iio, linux-wireless, netdev,
	linux-rtc
  Cc: Yury Norov
In-Reply-To: <20260427214127.406067-1-ynorov@nvidia.com>

Switch from sign_extend32(FIELD_GET()) to the dedicated
FIELD_GET_SIGNED() and don't calculate the fields length explicitly.

Reviewed-by: Linus Walleij <linusw@kernel.org>
Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Yury Norov <ynorov@nvidia.com>
---
 drivers/iio/magnetometer/yamaha-yas530.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c
index d49e37edcbed..6a80042602c6 100644
--- a/drivers/iio/magnetometer/yamaha-yas530.c
+++ b/drivers/iio/magnetometer/yamaha-yas530.c
@@ -859,9 +859,9 @@ static int yas530_get_calibration_data(struct yas5xx *yas5xx)
 	c->f[0] = FIELD_GET(GENMASK(22, 21), val);
 	c->f[1] = FIELD_GET(GENMASK(14, 13), val);
 	c->f[2] = FIELD_GET(GENMASK(6, 5), val);
-	c->r[0] = sign_extend32(FIELD_GET(GENMASK(28, 23), val), 5);
-	c->r[1] = sign_extend32(FIELD_GET(GENMASK(20, 15), val), 5);
-	c->r[2] = sign_extend32(FIELD_GET(GENMASK(12, 7), val), 5);
+	c->r[0] = FIELD_GET_SIGNED(GENMASK(28, 23), val);
+	c->r[1] = FIELD_GET_SIGNED(GENMASK(20, 15), val);
+	c->r[2] = FIELD_GET_SIGNED(GENMASK(12, 7), val);
 
 	return 0;
 }
@@ -914,9 +914,9 @@ static int yas532_get_calibration_data(struct yas5xx *yas5xx)
 	c->f[0] = FIELD_GET(GENMASK(24, 23), val);
 	c->f[1] = FIELD_GET(GENMASK(16, 15), val);
 	c->f[2] = FIELD_GET(GENMASK(8, 7), val);
-	c->r[0] = sign_extend32(FIELD_GET(GENMASK(30, 25), val), 5);
-	c->r[1] = sign_extend32(FIELD_GET(GENMASK(22, 17), val), 5);
-	c->r[2] = sign_extend32(FIELD_GET(GENMASK(14, 7), val), 5);
+	c->r[0] = FIELD_GET_SIGNED(GENMASK(30, 25), val);
+	c->r[1] = FIELD_GET_SIGNED(GENMASK(22, 17), val);
+	c->r[2] = FIELD_GET_SIGNED(GENMASK(14, 7), val);
 
 	return 0;
 }
-- 
2.51.0


^ permalink raw reply related

* [PATCH v2 3/9] iio: intel_dc_ti_adc: switch to using FIELD_GET_SIGNED()
From: Yury Norov @ 2026-04-27 21:41 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Jonathan Cameron,
	David Lechner, Johannes Berg, David Laight, Nuno Sá,
	Andy Shevchenko, Ping-Ke Shih, Richard Cochran, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Alexandre Belloni, Yury Norov, Rasmus Villemoes, Hans de Goede,
	Linus Walleij, Sakari Ailus, Salah Triki, Achim Gratz,
	Ben Collins, x86, linux-kernel, linux-iio, linux-wireless, netdev,
	linux-rtc
  Cc: Yury Norov
In-Reply-To: <20260427214127.406067-1-ynorov@nvidia.com>

Switch from sign_extend32(FIELD_GET()) to the dedicated
FIELD_GET_SIGNED() and don't provide the fields length explicitly.

Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Yury Norov <ynorov@nvidia.com>
---
 drivers/iio/adc/intel_dc_ti_adc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/iio/adc/intel_dc_ti_adc.c b/drivers/iio/adc/intel_dc_ti_adc.c
index 0fe34f1c338e..b5afad713e2d 100644
--- a/drivers/iio/adc/intel_dc_ti_adc.c
+++ b/drivers/iio/adc/intel_dc_ti_adc.c
@@ -290,8 +290,8 @@ static int dc_ti_adc_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	info->vbat_zse = sign_extend32(FIELD_GET(DC_TI_VBAT_ZSE, val), 3);
-	info->vbat_ge = sign_extend32(FIELD_GET(DC_TI_VBAT_GE, val), 3);
+	info->vbat_zse = FIELD_GET_SIGNED(DC_TI_VBAT_ZSE, val);
+	info->vbat_ge = FIELD_GET_SIGNED(DC_TI_VBAT_GE, val);
 
 	dev_dbg(dev, "vbat-zse %d vbat-ge %d\n", info->vbat_zse, info->vbat_ge);
 
-- 
2.51.0


^ permalink raw reply related

* [PATCH v2 2/9] x86/extable: switch to using FIELD_GET_SIGNED()
From: Yury Norov @ 2026-04-27 21:41 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Jonathan Cameron,
	David Lechner, Johannes Berg, David Laight, Nuno Sá,
	Andy Shevchenko, Ping-Ke Shih, Richard Cochran, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Alexandre Belloni, Yury Norov, Rasmus Villemoes, Hans de Goede,
	Linus Walleij, Sakari Ailus, Salah Triki, Achim Gratz,
	Ben Collins, x86, linux-kernel, linux-iio, linux-wireless, netdev,
	linux-rtc
  Cc: Yury Norov
In-Reply-To: <20260427214127.406067-1-ynorov@nvidia.com>

The EX_DATA register is laid out such that EX_DATA_IMM occupied MSB.
It's done to make sure that FIELD_GET() will sign-extend the IMM
field during extraction.

To enforce that, all EX_DATA masks are made signed integers. This
works, but relies on the particular implementation of FIELD_GET(),
i.e. masking then shifting, not vice versa; and the particular
placement of the fields in the register.

Switch to using the dedicated FIELD_GET_SIGNED(), and relax those
limitations.

Signed-off-by: Yury Norov <ynorov@nvidia.com>
---
 arch/x86/include/asm/extable_fixup_types.h | 13 ++++---------
 arch/x86/mm/extable.c                      |  2 +-
 2 files changed, 5 insertions(+), 10 deletions(-)

diff --git a/arch/x86/include/asm/extable_fixup_types.h b/arch/x86/include/asm/extable_fixup_types.h
index 906b0d5541e8..fd0cfb472103 100644
--- a/arch/x86/include/asm/extable_fixup_types.h
+++ b/arch/x86/include/asm/extable_fixup_types.h
@@ -2,15 +2,10 @@
 #ifndef _ASM_X86_EXTABLE_FIXUP_TYPES_H
 #define _ASM_X86_EXTABLE_FIXUP_TYPES_H
 
-/*
- * Our IMM is signed, as such it must live at the top end of the word. Also,
- * since C99 hex constants are of ambiguous type, force cast the mask to 'int'
- * so that FIELD_GET() will DTRT and sign extend the value when it extracts it.
- */
-#define EX_DATA_TYPE_MASK		((int)0x000000FF)
-#define EX_DATA_REG_MASK		((int)0x00000F00)
-#define EX_DATA_FLAG_MASK		((int)0x0000F000)
-#define EX_DATA_IMM_MASK		((int)0xFFFF0000)
+#define EX_DATA_TYPE_MASK		(0x000000FF)
+#define EX_DATA_REG_MASK		(0x00000F00)
+#define EX_DATA_FLAG_MASK		(0x0000F000)
+#define EX_DATA_IMM_MASK		(0xFFFF0000)
 
 #define EX_DATA_REG_SHIFT		8
 #define EX_DATA_FLAG_SHIFT		12
diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index 6b9ff1c6cafa..ceb8d03191ab 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -322,7 +322,7 @@ int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code,
 
 	type = FIELD_GET(EX_DATA_TYPE_MASK, e->data);
 	reg  = FIELD_GET(EX_DATA_REG_MASK,  e->data);
-	imm  = FIELD_GET(EX_DATA_IMM_MASK,  e->data);
+	imm  = FIELD_GET_SIGNED(EX_DATA_IMM_MASK, e->data);
 
 	switch (type) {
 	case EX_TYPE_DEFAULT:
-- 
2.51.0


^ permalink raw reply related

* [PATCH v2 1/9] bitfield: add FIELD_GET_SIGNED()
From: Yury Norov @ 2026-04-27 21:41 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Jonathan Cameron,
	David Lechner, Johannes Berg, David Laight, Nuno Sá,
	Andy Shevchenko, Ping-Ke Shih, Richard Cochran, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Alexandre Belloni, Yury Norov, Rasmus Villemoes, Hans de Goede,
	Linus Walleij, Sakari Ailus, Salah Triki, Achim Gratz,
	Ben Collins, x86, linux-kernel, linux-iio, linux-wireless, netdev,
	linux-rtc
  Cc: Yury Norov
In-Reply-To: <20260427214127.406067-1-ynorov@nvidia.com>

The bitfields are designed in assumption that fields contain unsigned
integer values, thus extracting the values from the field implies
zero-extending.

Some drivers need to sign-extend their fields, and currently do it like:

	dc_re += sign_extend32(FIELD_GET(0xfff000, tmp), 11);
	dc_im += sign_extend32(FIELD_GET(0xfff, tmp), 11);

It's error-prone because it relies on user to provide the correct
index of the most significant bit and proper 32 vs 64 function flavor.

Thus, introduce a FIELD_GET_SIGNED(). With the new API, the above
snippet turns into the more convenient:

	dc_re += FIELD_GET_SIGNED(0xfff000, tmp);
	dc_im += FIELD_GET_SIGNED(0xfff, tmp);

It compiles (on x86_64) into just a couple instructions: shl and sar.
When the mask includes MSB, the '<< __builtin_clzll(mask)' part becomes
a NOP, and the compiler only emits a single sar:

   long long foo(long long reg)
  {
    10:   f3 0f 1e fa             endbr64
          return FIELD_GET_SIGNED(GENMASK_ULL(63, 60), reg);
    14:   48 89 f8                mov    %rdi,%rax
    17:   48 c1 f8 3c             sar    $0x3c,%rax
  }

32-bit code generation is equally well. On arm32:

  long long foo(long long reg)
  {
         return FIELD_GET_SIGNED(0x00f00000ULL, reg);
  }

generates:

  foo(long long):
        lsls    r1, r0, #8
        asrs    r0, r1, #28
        asrs    r1, r1, #31
        bx      lr

Signed-off-by: Yury Norov <ynorov@nvidia.com>
---
 include/linux/bitfield.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index 54aeeef1f0ec..cd44013281c7 100644
--- a/include/linux/bitfield.h
+++ b/include/linux/bitfield.h
@@ -178,6 +178,22 @@
 		__FIELD_GET(_mask, _reg, "FIELD_GET: ");		\
 	})
 
+/**
+ * FIELD_GET_SIGNED() - extract a signed bitfield element
+ * @mask: shifted mask defining the field's length and position
+ * @reg:  value of entire bitfield
+ *
+ * Returns the sign-extended field specified by @_mask from the
+ * bitfield passed in as @_reg by masking and shifting it down.
+ */
+#define FIELD_GET_SIGNED(mask, reg)					\
+	({								\
+		__BF_FIELD_CHECK(mask, reg, 0U, "FIELD_GET_SIGNED: ");	\
+		 ((__signed_scalar_typeof(mask))			\
+		  (((long long)(reg) << __builtin_clzll(mask)) >>	\
+		   (__builtin_clzll(mask) + __builtin_ctzll(mask))));	\
+	})
+
 /**
  * FIELD_MODIFY() - modify a bitfield element
  * @_mask: shifted mask defining the field's length and position
-- 
2.51.0


^ permalink raw reply related

* [PATCH v2 0/9] bitfield: add FIELD_GET_SIGNED()
From: Yury Norov @ 2026-04-27 21:41 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Jonathan Cameron,
	David Lechner, Johannes Berg, David Laight, Nuno Sá,
	Andy Shevchenko, Ping-Ke Shih, Richard Cochran, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Alexandre Belloni, Yury Norov, Rasmus Villemoes, Hans de Goede,
	Linus Walleij, Sakari Ailus, Salah Triki, Achim Gratz,
	Ben Collins, x86, linux-kernel, linux-iio, linux-wireless, netdev,
	linux-rtc
  Cc: Yury Norov

The bitfields are designed in assumption that fields contain unsigned
integer values, thus extracting the values from the field implies
zero-extending.

Some drivers need to sign-extend their fields, and currently do it like:

	dc_re += sign_extend32(FIELD_GET(0xfff000, tmp), 11);
	dc_im += sign_extend32(FIELD_GET(0xfff, tmp), 11);

It's error-prone because it relies on user to provide the correct
index of the most significant bit and proper 32 vs 64 function flavor.

Thus, introduce a FIELD_GET_SIGNED(). With the new API, the above
snippet turns into the more convenient:

	dc_re += FIELD_GET_SIGNED(0xfff000, tmp);
	dc_im += FIELD_GET_SIGNED(0xfff, tmp);

It compiles (on x86_64) into just a couple instructions: shl and sar.
When the mask includes MSB, the '<< __builtin_clzll(mask)' part becomes
a NOP, and the compiler only emits a single sar:

   long long foo(long long reg)
  {
    10:   f3 0f 1e fa             endbr64
          return FIELD_GET_SIGNED(GENMASK_ULL(63, 60), reg);
    14:   48 89 f8                mov    %rdi,%rax
    17:   48 c1 f8 3c             sar    $0x3c,%rax
  }

32-bit code generation is equally well. On arm32:

  long long foo(long long reg)
  {
         return FIELD_GET_SIGNED(0x00f00000ULL, reg);
  }

generates:

  foo(long long):
        lsls    r1, r0, #8
        asrs    r0, r1, #28
        asrs    r1, r1, #31
        bx      lr

Immutable branch:

https://github.com/norov/linux/pull/new/fgsv2

v1: https://lore.kernel.org/all/20260417173621.368914-1-ynorov@nvidia.com/
v2:
 - more examples of the new API and code generation (Andy, David);
 - fix #7 FIELD_GET() / FIELD_GET_SIGNED() typo (Ping-Ke);
 - re-indent the macro (Andy, Peter);

Yury Norov (9):
  bitfield: add FIELD_GET_SIGNED()
  x86/extable: switch to using FIELD_GET_SIGNED()
  iio: intel_dc_ti_adc: switch to using FIELD_GET_SIGNED()
  iio: magnetometer: yas530: switch to using FIELD_GET_SIGNED()
  iio: pressure: bmp280: switch to using FIELD_GET_SIGNED()
  iio: mcp9600: switch to using FIELD_GET_SIGNED()
  wifi: rtw89: switch to using FIELD_GET_SIGNED()
  rtc: rv3032: switch to using FIELD_GET_SIGNED()
  ptp: switch to using FIELD_GET_SIGNED()

 arch/x86/include/asm/extable_fixup_types.h       | 13 ++++---------
 arch/x86/mm/extable.c                            |  2 +-
 drivers/iio/adc/intel_dc_ti_adc.c                |  4 ++--
 drivers/iio/magnetometer/yamaha-yas530.c         | 12 ++++++------
 drivers/iio/pressure/bmp280-core.c               |  2 +-
 drivers/iio/temperature/mcp9600.c                |  2 +-
 .../net/wireless/realtek/rtw89/rtw8852a_rfk.c    |  4 ++--
 .../net/wireless/realtek/rtw89/rtw8852b_common.c |  4 ++--
 .../net/wireless/realtek/rtw89/rtw8852b_rfk.c    |  4 ++--
 drivers/net/wireless/realtek/rtw89/rtw8852c.c    |  4 ++--
 drivers/ptp/ptp_fc3.c                            |  4 ++--
 drivers/rtc/rtc-rv3032.c                         |  2 +-
 include/linux/bitfield.h                         | 16 ++++++++++++++++
 13 files changed, 42 insertions(+), 31 deletions(-)

-- 
2.51.0


^ permalink raw reply

* Re: [BUG] wifi: rtw88: Hard system freeze on RTL8821CE when power_save is enabled (LPS/ASPM conflict)
From: Bitterblue Smith @ 2026-04-27 21:30 UTC (permalink / raw)
  To: LB F
  Cc: Ping-Ke Shih, linux-wireless@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <CALdGYqRK+a7-7WEXgp1H-w-1AaQhhbTW9FTWtpmfGN_yXuDGSQ@mail.gmail.com>

On 28/04/2026 00:19, LB F wrote:

> I will continue monitoring over the next few days to confirm long-term
> reliability.
> 
> Best regards, Oleksandr Havrylov

Will you use the Bluetooth headphones again?

^ permalink raw reply

* Re: [RFC PATCH v1 5/9] uaccess: Switch to copy_{to/from}_user_partial() when relevant
From: David Laight @ 2026-04-27 21:29 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Christophe Leroy (CS GROUP), Yury Norov, Andrew Morton,
	Thomas Gleixner, linux-alpha, linux-kernel, linux-snps-arc,
	linux-arm-kernel, linux-mips, linuxppc-dev, kvm, linux-riscv,
	linux-s390, sparclinux, linux-um, dmaengine, linux-efi, linux-fsi,
	amd-gfx, dri-devel, intel-gfx, linux-wpan, netdev, linux-wireless,
	linux-spi, linux-media, linux-staging, linux-serial, linux-usb,
	xen-devel, linux-fsdevel, ocfs2-devel, bpf, kasan-dev, linux-mm,
	linux-x25, rust-for-linux, linux-sound, sound-open-firmware,
	linux-csky, linux-hexagon, loongarch, linux-m68k, linux-openrisc,
	linux-parisc, linux-sh, linux-arch
In-Reply-To: <CAHk-=whC1DZojwdMB1=sJWG2=dsCdfyU8N6tDE1qx50HRZ-WJQ@mail.gmail.com>

On Mon, 27 Apr 2026 12:01:23 -0700
Linus Torvalds <torvalds@linux-foundation.org> wrote:

> On Mon, 27 Apr 2026 at 10:18, Christophe Leroy (CS GROUP)
> <chleroy@kernel.org> wrote:
> >
> > In a subsequent patch, copy_{to/from}_user() will be modified to
> > return -EFAULT when copy fails.  
> 
> Please don't do this.
> 
> This is a maintenance nightmare, and changes pretty much three decades
> of semantics, and will cause *very* subtle backporting issues if
> somebody happens to rely on the old / new behavior.
> 
> I understand the reasoning for the change, but I really don't think
> the pain of creating yet another user copy interface is worth it.
> 
> We already have a lot of different versions of user copies for
> different reasons, and while they all tend to have a good reason (and
> some not-so-good, but historical reasons) for existing, this one
> doesn't seem worth it.
> 
> The main - perhaps only - reason for this "partial" version is that
> you want to do that "automatically inlined and optimized fixed-sized
> case".
> 
> But here's the thing: I think you can already do that. Yes, it
> requires some improvements to unsafe_copy_from_user(), but *that*
> interface doesn't have three decades of history associated with it,
> _and_ you're extending on that one anyway in this series.
> 
> "unsafe_copy_from_user()" is very odd, is meant only for small simple
> copies that can be inlined and it's special-cased for 'objtool' anyway
> (because objtool would have complained about an out-of-line call,
> although it could have been special-cased other ways).
> 
> In other words: unsafe_copy_from_user() is *very* close to what you
> want for that "Oh, I noticed that it's a small fixed-size copy, so I
> want to special-case copy-from-user for that".
> 
> The _only_ issue with unsafe_copy_from_user() is that you can't see
> that there were partial successes. But if *that* was fixed, then this
> whole "create a new copy_from_user interface" issue would just go
> away.
> 
> So please - let's just change unsafe_copy_from_user() to be usable for
> the partial case.
> 
> And the thing is, all the existing unsafe_copy_from_user()
> implementations already effectively *have* the "how much did I not
> copy" internally, and they actually do extra work to hide it, ie they
> have things like that
> 
>         int _i;
> 
> that is "how many bytes have I copied" in the powerpc implementation,
> or the x86 code does
> 
>         size_t __ucu_len = (_len);
> 
> where that "ucu_len" is updated as you go along and is literally the
> "how many bytes are left to copy" return value that is missing from
> this interface.
> 
> So what I would suggest is
> 
>  - introduce a new user accessor helper that is used for *both*
> unsafe_copy_to/from_user() *and* the "inline small constant-sized
> normal copy_to/from_user()" calls
> 
>  - it's the same thing as the existing  unsafe_copy_to/from_user()
> implementation, except it exposes how many bytes are left to be copied
> to the exception label.

I think there is a slight difference in that the normal copy_to_user()
will determine the exact offset of the error by retrying with byte copies.

There is also the issue of misaligned copies.

Then there is the 'bugbear' of hardened user copies.
Chasing down the stack to find whether the kernel buffer crosses
a stack frame is probably more expensive than the copy for the typically
small copies that will use on-stack buffers.

	David

> 
> IOW, it would look something like
> 
>      #define unsafe_copy_to_user_outlen(_dst,_src,_len,label)...
> 
> which is exactly the same as the current unsafe_copy_to_user(),
> *except* it changes "_len" as it does along.
> 
> And then you use that for both the "real" unsafe_copy_user and for the
> "small constant values" case.
> 
> Just as an example, attached is a completely stupid rough draft of a
> patch that does this for x86 and only for unsafe_copy_to_user().
> 
> And I made a very very hacky change to kernel/sys.c to see what the
> code generation looks like.
> 
> This is what it results in on x86 with clang (with all the magic
> .section data edited out):
> 
>         ... edited out the code to generate the times
>         ... this is the actual user copy:
>         # HERE!
>         movabsq $81985529216486895, %rcx        # imm = 0x123456789ABCDEF
>         cmpq    %rcx, %rbx
>         cmovaq  %rcx, %rbx
>         stac
>         movq    %r13, (%rbx)                    # exception to .LBB45_8
>         movq    %r14, 8(%rbx)                   # exception to .LBB45_8
>         movq    %r15, 16(%rbx)                  # exception to .LBB45_8
>         movq    %rax, 24(%rbx)                  # exception to .LBB45_8
>         clac
> .LBB45_6:
>         movq    jiffies(%rip), %rdi
>         callq   jiffies_64_to_clock_t
> .LBB45_7:
>         addq    $16, %rsp
>         popq    %rbx
>         popq    %r12
>         popq    %r13
>         popq    %r14
>         popq    %r15
>         retq
> .LBB45_8:
>         clac
>         movq    $-14, %rax
>         jmp     .LBB45_7
> 
> and notice how the compiler noticed that the 'outlen' isn't actually
> used, and turned the exception label into just a "return -EFAULT" and
> never actually generated any code for updating remaining lengths?
> 
> That actually looks pretty much optimal for a 32-byte user copy.
> 
> And it didn't involve changing the semantics at all.
> 
> Just to check, I changed that "times()" system call to return the
> number of bytes uncopied instead (to emulate the "I actually want to
> know what's left" case), and it generated this:
> 
>         # HERE!
>         movabsq $81985529216486895, %rcx        # imm = 0x123456789ABCDEF
>         cmpq    %rcx, %rbx
>         cmovaq  %rcx, %rbx
>         stac
>         movl    $32, %ecx
>         movq    %r13, (%rbx)                    # exception to .LBB45_7
>         movl    $24, %ecx
>         movq    %r15, 8(%rbx)                   # exception to .LBB45_7
>         movl    $16, %ecx
>         movq    %r14, 16(%rbx)                  # exception to .LBB45_7
>         movl    $8, %ecx
>         movq    %rax, 24(%rbx)                  # exception to .LBB45_7
>         clac
>         xorl    %ecx, %ecx
> .LBB45_8:
>         movq    %rcx, %rax
>         addq    $16, %rsp
>         popq    %rbx
>         popq    %r12
>         popq    %r13
>         popq    %r14
>         popq    %r15
>         retq
> .LBB45_6:
>         movq    jiffies(%rip), %rdi
>         jmp     jiffies_64_to_clock_t           # TAILCALL
> .LBB45_7:
>         clac
>         jmp     .LBB45_8
> 
> so it all seems to work - although obviously the above is *not* the normal case.
> 
> NOTE NOTE NOTE! The attached patch is entirely untested. I obviously
> did some "test code generation" with it, but I only *looked* at the
> result, and maybe it has some fundamental problem that I just didn't
> notice. So treat this as a "how about this approach" patch, not as
> anything more serious than that.
> 
> And the kerrnel/sys.c hack is very obviously just that: a complate
> hack for testing.
> 
> A real patch would do that "for small constant-sized copies, turn
> copy_to_user() automatically into "_small_copy_to_user()".
> 
> The attached is *not* a real patch. Treat it with the contempt it deserves.
> 
>              Linus


^ permalink raw reply

* Re: [BUG] wifi: rtw88: Hard system freeze on RTL8821CE when power_save is enabled (LPS/ASPM conflict)
From: LB F @ 2026-04-27 21:19 UTC (permalink / raw)
  To: Bitterblue Smith
  Cc: Ping-Ke Shih, linux-wireless@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <CALdGYqSS_4yrKn73UHR3zfgJN98wjR71V=pn+1C4pvg2UXGHyA@mail.gmail.com>

Hi Bitterblue,

A follow-up after a full day of intensive stress testing with your RX
descriptor validation patch.

I ran seven automated test phases back-to-back, clearing dmesg before each run:

Power save rapid toggle (0.1s intervals) during heavy download.
Ping flood (10,000 packets) with simultaneous power save toggle.
RF kill flapping (15 rfkill block/unblock cycles).
MTU jitter (switching between 500 and 1500 bytes) under load.
NetworkManager disconnect/reconnect (8 cycles).
S3 suspend/resume (3 cycles via rtcwake, 10s each) under load.
Combined chaos: all of the above simultaneously with random MTU.
Additionally, I manually triggered S4 hibernation while running a
continuous power save toggle loop with a heavy download. The laptop
hibernated, powered off completely, and resumed without errors. I also
did a full reboot and verified the logs from a clean boot.

Result: zero anomalies across all phases. No "drv_info_sz" messages,
no mac80211 warnings, no oops or panics. The single occurrence of the
bug I reported earlier (at 02:59, before I began testing) remains the
only event for the entire day — and it was cleanly handled by the
validation without any impact on stability.

I will continue monitoring over the next few days to confirm long-term
reliability.

Best regards, Oleksandr Havrylov

^ permalink raw reply

* Re: [RFC PATCH v1 2/9] uaccess: Convert INLINE_COPY_{TO/FROM}_USER to kconfig and reduce ifdefery
From: Yury Norov @ 2026-04-27 20:47 UTC (permalink / raw)
  To: Andrew Cooper
  Cc: Christophe Leroy (CS GROUP), Andrew Morton, Linus Torvalds,
	David Laight, Thomas Gleixner, linux-alpha, Yury Norov,
	linux-kernel, linux-snps-arc, linux-arm-kernel, linux-mips,
	linuxppc-dev, kvm, linux-riscv, linux-s390, sparclinux, linux-um,
	dmaengine, linux-efi, linux-fsi, amd-gfx, dri-devel, intel-gfx,
	linux-wpan, netdev, linux-wireless, linux-spi, linux-media,
	linux-staging, linux-serial, linux-usb, xen-devel, linux-fsdevel,
	ocfs2-devel, bpf, kasan-dev, linux-mm, linux-x25, rust-for-linux,
	linux-sound, sound-open-firmware, linux-csky, linux-hexagon,
	loongarch, linux-m68k, linux-openrisc, linux-parisc, linux-sh,
	linux-arch
In-Reply-To: <f54c3c2b-33da-42a0-80b7-0f6615d930ce@citrix.com>

On Mon, Apr 27, 2026 at 09:39:33PM +0100, Andrew Cooper wrote:
> On 27/04/2026 7:39 pm, Yury Norov wrote:
> > On Mon, Apr 27, 2026 at 07:13:43PM +0200, Christophe Leroy (CS GROUP) wrote:
> >> Among the 21 architectures supported by the kernel, 16 define both
> >> INLINE_COPY_TO_USER and INLINE_COPY_FROM_USER while the 5 other ones
> >> don't define any of the two.
> >>
> >> To simplify and reduce risk of mistakes, convert them to a single
> >> kconfig item named CONFIG_ARCH_WANTS_NOINLINE_COPY which will be
> > We've got a special word for it: outline. Can you name it
> > CONFIG_OUTLINE_USERCOPY, or similar?
> 
> You can't swap the "in" for "out" like this.  "out of line" is the
> opposite of "inline" in this context, while "outline" means something
> different and unrelated.

Check KASAN_OUTLINE vs KASAN_INLINE for example

^ permalink raw reply

* Re: [RFC PATCH v1 2/9] uaccess: Convert INLINE_COPY_{TO/FROM}_USER to kconfig and reduce ifdefery
From: Andrew Cooper @ 2026-04-27 20:39 UTC (permalink / raw)
  To: Yury Norov, Christophe Leroy (CS GROUP)
  Cc: Andrew Cooper, Andrew Morton, Linus Torvalds, David Laight,
	Thomas Gleixner, linux-alpha, Yury Norov, linux-kernel,
	linux-snps-arc, linux-arm-kernel, linux-mips, linuxppc-dev, kvm,
	linux-riscv, linux-s390, sparclinux, linux-um, dmaengine,
	linux-efi, linux-fsi, amd-gfx, dri-devel, intel-gfx, linux-wpan,
	netdev, linux-wireless, linux-spi, linux-media, linux-staging,
	linux-serial, linux-usb, xen-devel, linux-fsdevel, ocfs2-devel,
	bpf, kasan-dev, linux-mm, linux-x25, rust-for-linux, linux-sound,
	sound-open-firmware, linux-csky, linux-hexagon, loongarch,
	linux-m68k, linux-openrisc, linux-parisc, linux-sh, linux-arch
In-Reply-To: <ae-tVFVfx72oCC_i@yury>

On 27/04/2026 7:39 pm, Yury Norov wrote:
> On Mon, Apr 27, 2026 at 07:13:43PM +0200, Christophe Leroy (CS GROUP) wrote:
>> Among the 21 architectures supported by the kernel, 16 define both
>> INLINE_COPY_TO_USER and INLINE_COPY_FROM_USER while the 5 other ones
>> don't define any of the two.
>>
>> To simplify and reduce risk of mistakes, convert them to a single
>> kconfig item named CONFIG_ARCH_WANTS_NOINLINE_COPY which will be
> We've got a special word for it: outline. Can you name it
> CONFIG_OUTLINE_USERCOPY, or similar?

You can't swap the "in" for "out" like this.  "out of line" is the
opposite of "inline" in this context, while "outline" means something
different and unrelated.

~Andrew

^ permalink raw reply

* Re: [syzbot] [wireless?] divide error in mac80211_hwsim_link_info_changed (3)
From: Arjan van de Ven @ 2026-04-27 20:29 UTC (permalink / raw)
  To: linux-wireless
  Cc: syzbot+ca7a2759caaa6cd4e3db, johannes, linux-kernel, netdev,
	syzkaller-bugs
In-Reply-To: <69efb8dd.050a0220.18b4f.0006.GAE@google.com>

This email is created by automation to help kernel developers
deal with a large volume of AI generated bug reports by decoding
oopses into more actionable information.


Decoded Backtrace

1. mac80211_hwsim_link_info_changed -- crash site
   (drivers/net/wireless/virtual/mac80211_hwsim.c:2734)

2701  static void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw,
2702  					     struct ieee80211_vif *vif,
2703  					     struct ieee80211_bss_conf *info,
2704  					     u64 changed)
2705  {
2706  	struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
2707  	struct mac80211_hwsim_data *data = hw->priv;
2708  	unsigned int link_id = info->link_id;
2709  	struct mac80211_hwsim_link_data *link_data = &data->link_data[link_id];
        ...
2722  	if (changed & BSS_CHANGED_BEACON_ENABLED) {
2723  		wiphy_dbg(hw->wiphy, "  BCN EN: %d (BI=%u)\n",
2724  			  info->enable_beacon, info->beacon_int);
2725  		vp->bcn_en = info->enable_beacon;
2726  		if (data->started &&
2727  		    !hrtimer_active(&link_data->beacon_timer) &&
2728  		    info->enable_beacon) {
2729  			u64 tsf, until_tbtt;
2730  			u32 bcn_int;
2731  			link_data->beacon_int = info->beacon_int * 1024;
2732  			tsf = mac80211_hwsim_get_tsf(hw, vif);
2733  			bcn_int = link_data->beacon_int;
-> 2734  			until_tbtt = bcn_int - do_div(tsf, bcn_int);  // <- bcn_int=0; RSI=0 -> #DE
2735
2736  			hrtimer_start(&link_data->beacon_timer,
2737  				      ns_to_ktime(until_tbtt * NSEC_PER_USEC),
2738  				      HRTIMER_MODE_REL_SOFT);
2739  		} else if (!info->enable_beacon) {
        ...
2748  				link_data->beacon_int = 0;
        ...
2750  		}
2751  	}

2. drv_link_info_changed -- (net/mac80211/driver-ops.c:497)

460  void drv_link_info_changed(struct ieee80211_local *local,
461  			   struct ieee80211_sub_if_data *sdata,
462  			   struct ieee80211_bss_conf *info,
463  			   int link_id, u64 changed)
464  {
        ...
493  	trace_drv_link_info_changed(local, sdata, info, changed);
494  	if (local->ops->link_info_changed)
495  		local->ops->link_info_changed(&local->hw, &sdata->vif,
496  					      info, changed);
-> 497  	else if (local->ops->bss_info_changed)
498  		local->ops->bss_info_changed(&local->hw, &sdata->vif,
499  					     info, changed);
500  	trace_drv_return_void(local);
501  }

3. ieee80211_offchannel_return -- (net/mac80211/offchannel.c:160)

133  void ieee80211_offchannel_return(struct ieee80211_local *local)
134  {
135  	struct ieee80211_sub_if_data *sdata;
136
137  	lockdep_assert_wiphy(local->hw.wiphy);
        ...
142  	list_for_each_entry(sdata, &local->interfaces, list) {
        ...
157  		if (test_and_clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED,
158  				       &sdata->state)) {
159  			sdata->vif.bss_conf.enable_beacon = true;
-> 160  			ieee80211_link_info_change_notify(
161  				sdata, &sdata->deflink,
162  				BSS_CHANGED_BEACON_ENABLED);
163  		}
164  	}

4. __ieee80211_scan_completed -- (net/mac80211/scan.c:519)

516  	if (!hw_scan && was_scanning) {
517  		ieee80211_configure_filter(local);
518  		drv_sw_scan_complete(local, scan_sdata);
-> 519  		ieee80211_offchannel_return(local);
520  	}

5. cfg80211_wiphy_work -- (net/wireless/core.c:513)
   (workqueue dispatch point for scan completion)


Tentative Analysis

When a software scan completes, __ieee80211_scan_completed calls
ieee80211_offchannel_return, which iterates active interfaces and
re-enables beaconing for any interface that had its beacon stopped
during the scan. It sets bss_conf.enable_beacon = true and issues
a BSS_CHANGED_BEACON_ENABLED notification, but does NOT update
bss_conf.beacon_int.

This notification reaches mac80211_hwsim_link_info_changed. The
condition at lines 2726-2728 (data->started, timer not active,
enable_beacon) is satisfied, so the function enters the beacon
timer setup block at line 2731. It sets link_data->beacon_int =
info->beacon_int * 1024. When info->beacon_int is zero -- which
syzbot achieved by creating an AP interface with beacon_int=0 --
this produces link_data->beacon_int = 0 and bcn_int = 0 (line
2733). The subsequent do_div(tsf, bcn_int) with a zero divisor
triggers the x86 #DE (divide error) exception (RSI = 0, as
confirmed by the register dump).

An identical do_div(tsf, bcn_int) expression in
mac80211_hwsim_config (mac80211_hwsim.c:2635) is protected by a
guard: "if (!data->started || !link_data->beacon_int)" -- this
guard is absent from the BSS_CHANGED_BEACON_ENABLED path.


Potential Solution

Add a zero check for bcn_int immediately after it is loaded from
link_data->beacon_int (line 2733), before the do_div call. A
beacon interval of zero is invalid; when encountered, return
without starting the timer:

    bcn_int = link_data->beacon_int;
    if (!bcn_int)
        return;
    until_tbtt = bcn_int - do_div(tsf, bcn_int);

This mirrors the guard already present in mac80211_hwsim_config
for the same expression. The Fixes tag for the commit would be:

    Fixes: c51f878379b1 ("mac80211_hwsim: fix beacon timing")


More information

Oops-Analysis: http://oops.fenrus.org/reports/lkml/69efb8dd.050a0220.18b4f.0006.GAE_google.com/
Assisted-by: Copilot:claude-sonnet-4.6 linux-kernel-oops-x86.

^ permalink raw reply

* Re: [RFC PATCH v1 9/9] uaccess: Convert small fixed size copy_{to/from}_user() to scoped user access
From: Yury Norov @ 2026-04-27 20:12 UTC (permalink / raw)
  To: Christophe Leroy (CS GROUP)
  Cc: Andrew Morton, Linus Torvalds, David Laight, Thomas Gleixner,
	linux-alpha, Yury Norov, linux-kernel, linux-snps-arc,
	linux-arm-kernel, linux-mips, linuxppc-dev, kvm, linux-riscv,
	linux-s390, sparclinux, linux-um, dmaengine, linux-efi, linux-fsi,
	amd-gfx, dri-devel, intel-gfx, linux-wpan, netdev, linux-wireless,
	linux-spi, linux-media, linux-staging, linux-serial, linux-usb,
	xen-devel, linux-fsdevel, ocfs2-devel, bpf, kasan-dev, linux-mm,
	linux-x25, rust-for-linux, linux-sound, sound-open-firmware,
	linux-csky, linux-hexagon, loongarch, linux-m68k, linux-openrisc,
	linux-parisc, linux-sh, linux-arch
In-Reply-To: <8780eb2ef80575931a339e5225bc80eb13e9be6c.1777306795.git.chleroy@kernel.org>

On Mon, Apr 27, 2026 at 07:13:50PM +0200, Christophe Leroy (CS GROUP) wrote:
> copy_{to/from}_user() is a heavy function optimised for copy of large
> blocs of memory between user and kernel space.
> 
> When the number of bytes to be copied is known at build time and small,
> using scoped user access removes the burden of that optimisation.
> 
> Signed-off-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
> ---
>  include/linux/uaccess.h | 47 +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 47 insertions(+)
> 
> diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
> index 33b7d0f5f808..3ac544527af2 100644
> --- a/include/linux/uaccess.h
> +++ b/include/linux/uaccess.h
> @@ -50,6 +50,8 @@
>   #define mask_user_address(src) (src)
>  #endif
>  
> +#define SMALL_COPY_USER		64

Let's make it L1_CACHE_BYTES, and maybe configurable?


^ permalink raw reply

* Re: [PATCH 3/3] wifi: mt76: remove mt76_get_of_data_from_mtd
From: Conor Dooley @ 2026-04-27 20:04 UTC (permalink / raw)
  To: Rosen Penev
  Cc: devicetree, Felix Fietkau, Lorenzo Bianconi, Ryder Lee,
	Shayne Chen, Sean Wang, Johannes Berg, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Thomas Bogendoerfer,
	open list:MEDIATEK MT76 WIRELESS LAN DRIVER,
	open list:ARM/Mediatek SoC support,
	moderated list:ARM/Mediatek SoC support,
	moderated list:ARM/Mediatek SoC support, open list:MIPS
In-Reply-To: <20260427-safeguard-unthawed-cfb87dc55a32@spud>

[-- Attachment #1: Type: text/plain, Size: 7199 bytes --]

On Mon, Apr 27, 2026 at 09:02:56PM +0100, Conor Dooley wrote:
> On Mon, Apr 27, 2026 at 12:17:04PM -0700, Rosen Penev wrote:
> > On Mon, Apr 27, 2026 at 12:09 PM Conor Dooley <conor@kernel.org> wrote:
> > >
> > > On Sun, Apr 26, 2026 at 08:44:27PM -0700, Rosen Penev wrote:
> > > > mt76_get_of_data_from_mtd has been replaced by
> > > > mt76_get_of_data_from_nvmem in all usages.
> > >
> > > All users in the kernel, but what about other sources of devicetrees?
> > > Those built into firmware etc? Are there none of those too?
> > I'm actively removing those: https://github.com/openwrt/openwrt/pull/23113
> > 
> > Anyway, irrelevant here.
> 
> Hardly, you can't break backwards compatibility with old devicetrees.
> Removing known users from the kernel is one step in that process, but if
> there's devicetrees in other places those cunt too!
> 
> With the moving pieces in this patchset alone it's problematic to move
> this fast, since you're changing the dts user in the same series as
> removing driver support (AFIACT), which means that neither netdev nor
> the platform tree will work with their portion applied.

Well, maybe the platform tree will work, but not the netdev tree unless
I've misunderstood completely.

> 
> > >
> > > Conor.
> > >
> > > >
> > > > Remove it to prevent people from using the deprecated
> > > > mediatek,mtd-eeprom binding.
> > > >
> > > > Signed-off-by: Rosen Penev <rosenp@gmail.com>
> > > > ---
> > > >  drivers/net/wireless/mediatek/mt76/eeprom.c   | 87 -------------------
> > > >  drivers/net/wireless/mediatek/mt76/mt76.h     |  1 -
> > > >  .../wireless/mediatek/mt76/mt7915/eeprom.c    |  4 -
> > > >  3 files changed, 92 deletions(-)
> > > >
> > > > diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c
> > > > index afdb73661866..092804323d81 100644
> > > > --- a/drivers/net/wireless/mediatek/mt76/eeprom.c
> > > > +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c
> > > > @@ -35,89 +35,6 @@ static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len)
> > > >       return 0;
> > > >  }
> > > >
> > > > -int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len)
> > > > -{
> > > > -#ifdef CONFIG_MTD
> > > > -     struct device_node *np = dev->dev->of_node;
> > > > -     struct mtd_info *mtd;
> > > > -     const __be32 *list;
> > > > -     const char *part;
> > > > -     phandle phandle;
> > > > -     size_t retlen;
> > > > -     int size;
> > > > -     int ret;
> > > > -
> > > > -     list = of_get_property(np, "mediatek,mtd-eeprom", &size);
> > > > -     if (!list)
> > > > -             return -ENOENT;
> > > > -
> > > > -     phandle = be32_to_cpup(list++);
> > > > -     if (!phandle)
> > > > -             return -ENOENT;
> > > > -
> > > > -     np = of_find_node_by_phandle(phandle);
> > > > -     if (!np)
> > > > -             return -EINVAL;
> > > > -
> > > > -     part = of_get_property(np, "label", NULL);
> > > > -     if (!part)
> > > > -             part = np->name;
> > > > -
> > > > -     mtd = get_mtd_device_nm(part);
> > > > -     if (IS_ERR(mtd)) {
> > > > -             ret =  PTR_ERR(mtd);
> > > > -             goto out_put_node;
> > > > -     }
> > > > -
> > > > -     if (size <= sizeof(*list)) {
> > > > -             ret = -EINVAL;
> > > > -             goto out_put_node;
> > > > -     }
> > > > -
> > > > -     offset += be32_to_cpup(list);
> > > > -     ret = mtd_read(mtd, offset, len, &retlen, eep);
> > > > -     put_mtd_device(mtd);
> > > > -     if (mtd_is_bitflip(ret))
> > > > -             ret = 0;
> > > > -     if (ret) {
> > > > -             dev_err(dev->dev, "reading EEPROM from mtd %s failed: %i\n",
> > > > -                     part, ret);
> > > > -             goto out_put_node;
> > > > -     }
> > > > -
> > > > -     if (retlen < len) {
> > > > -             ret = -EINVAL;
> > > > -             goto out_put_node;
> > > > -     }
> > > > -
> > > > -     if (of_property_read_bool(dev->dev->of_node, "big-endian")) {
> > > > -             u8 *data = (u8 *)eep;
> > > > -             int i;
> > > > -
> > > > -             /* convert eeprom data in Little Endian */
> > > > -             for (i = 0; i < round_down(len, 2); i += 2)
> > > > -                     put_unaligned_le16(get_unaligned_be16(&data[i]),
> > > > -                                        &data[i]);
> > > > -     }
> > > > -
> > > > -#ifdef CONFIG_NL80211_TESTMODE
> > > > -     dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL);
> > > > -     if (!dev->test_mtd.name) {
> > > > -             ret = -ENOMEM;
> > > > -             goto out_put_node;
> > > > -     }
> > > > -     dev->test_mtd.offset = offset;
> > > > -#endif
> > > > -
> > > > -out_put_node:
> > > > -     of_node_put(np);
> > > > -     return ret;
> > > > -#else
> > > > -     return -ENOENT;
> > > > -#endif
> > > > -}
> > > > -EXPORT_SYMBOL_GPL(mt76_get_of_data_from_mtd);
> > > > -
> > > >  int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep,
> > > >                               const char *cell_name, int len)
> > > >  {
> > > > @@ -163,10 +80,6 @@ static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len)
> > > >       if (!ret)
> > > >               return 0;
> > > >
> > > > -     ret = mt76_get_of_data_from_mtd(dev, eep, 0, len);
> > > > -     if (!ret)
> > > > -             return 0;
> > > > -
> > > >       return mt76_get_of_data_from_nvmem(dev, eep, "eeprom", len);
> > > >  }
> > > >
> > > > diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
> > > > index 527bef97e122..f447ecac664d 100644
> > > > --- a/drivers/net/wireless/mediatek/mt76/mt76.h
> > > > +++ b/drivers/net/wireless/mediatek/mt76/mt76.h
> > > > @@ -1339,7 +1339,6 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str,
> > > >
> > > >  int mt76_eeprom_init(struct mt76_dev *dev, int len);
> > > >  int mt76_eeprom_override(struct mt76_phy *phy);
> > > > -int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len);
> > > >  int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep,
> > > >                               const char *cell_name, int len);
> > > >
> > > > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
> > > > index eb92cbf1a284..c24e1276700b 100644
> > > > --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
> > > > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
> > > > @@ -29,10 +29,6 @@ static int mt7915_eeprom_load_precal(struct mt7915_dev *dev)
> > > >
> > > >       offs = is_mt7915(&dev->mt76) ? MT_EE_PRECAL : MT_EE_PRECAL_V2;
> > > >
> > > > -     ret = mt76_get_of_data_from_mtd(mdev, dev->cal, offs, size);
> > > > -     if (!ret)
> > > > -             return ret;
> > > > -
> > > >       ret = mt76_get_of_data_from_nvmem(mdev, dev->cal, "precal", size);
> > > >       if (!ret)
> > > >               return ret;
> > > > --
> > > > 2.54.0
> > > >



[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH 3/3] wifi: mt76: remove mt76_get_of_data_from_mtd
From: Conor Dooley @ 2026-04-27 20:02 UTC (permalink / raw)
  To: Rosen Penev
  Cc: devicetree, Felix Fietkau, Lorenzo Bianconi, Ryder Lee,
	Shayne Chen, Sean Wang, Johannes Berg, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Thomas Bogendoerfer,
	open list:MEDIATEK MT76 WIRELESS LAN DRIVER,
	open list:ARM/Mediatek SoC support,
	moderated list:ARM/Mediatek SoC support,
	moderated list:ARM/Mediatek SoC support, open list:MIPS
In-Reply-To: <CAKxU2N-mhrhjDEc2MnOvDZC5PpMzj=vRgMemNK4qSQzNQ-=BPQ@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 6681 bytes --]

On Mon, Apr 27, 2026 at 12:17:04PM -0700, Rosen Penev wrote:
> On Mon, Apr 27, 2026 at 12:09 PM Conor Dooley <conor@kernel.org> wrote:
> >
> > On Sun, Apr 26, 2026 at 08:44:27PM -0700, Rosen Penev wrote:
> > > mt76_get_of_data_from_mtd has been replaced by
> > > mt76_get_of_data_from_nvmem in all usages.
> >
> > All users in the kernel, but what about other sources of devicetrees?
> > Those built into firmware etc? Are there none of those too?
> I'm actively removing those: https://github.com/openwrt/openwrt/pull/23113
> 
> Anyway, irrelevant here.

Hardly, you can't break backwards compatibility with old devicetrees.
Removing known users from the kernel is one step in that process, but if
there's devicetrees in other places those cunt too!

With the moving pieces in this patchset alone it's problematic to move
this fast, since you're changing the dts user in the same series as
removing driver support (AFIACT), which means that neither netdev nor
the platform tree will work with their portion applied.

> >
> > Conor.
> >
> > >
> > > Remove it to prevent people from using the deprecated
> > > mediatek,mtd-eeprom binding.
> > >
> > > Signed-off-by: Rosen Penev <rosenp@gmail.com>
> > > ---
> > >  drivers/net/wireless/mediatek/mt76/eeprom.c   | 87 -------------------
> > >  drivers/net/wireless/mediatek/mt76/mt76.h     |  1 -
> > >  .../wireless/mediatek/mt76/mt7915/eeprom.c    |  4 -
> > >  3 files changed, 92 deletions(-)
> > >
> > > diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c
> > > index afdb73661866..092804323d81 100644
> > > --- a/drivers/net/wireless/mediatek/mt76/eeprom.c
> > > +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c
> > > @@ -35,89 +35,6 @@ static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len)
> > >       return 0;
> > >  }
> > >
> > > -int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len)
> > > -{
> > > -#ifdef CONFIG_MTD
> > > -     struct device_node *np = dev->dev->of_node;
> > > -     struct mtd_info *mtd;
> > > -     const __be32 *list;
> > > -     const char *part;
> > > -     phandle phandle;
> > > -     size_t retlen;
> > > -     int size;
> > > -     int ret;
> > > -
> > > -     list = of_get_property(np, "mediatek,mtd-eeprom", &size);
> > > -     if (!list)
> > > -             return -ENOENT;
> > > -
> > > -     phandle = be32_to_cpup(list++);
> > > -     if (!phandle)
> > > -             return -ENOENT;
> > > -
> > > -     np = of_find_node_by_phandle(phandle);
> > > -     if (!np)
> > > -             return -EINVAL;
> > > -
> > > -     part = of_get_property(np, "label", NULL);
> > > -     if (!part)
> > > -             part = np->name;
> > > -
> > > -     mtd = get_mtd_device_nm(part);
> > > -     if (IS_ERR(mtd)) {
> > > -             ret =  PTR_ERR(mtd);
> > > -             goto out_put_node;
> > > -     }
> > > -
> > > -     if (size <= sizeof(*list)) {
> > > -             ret = -EINVAL;
> > > -             goto out_put_node;
> > > -     }
> > > -
> > > -     offset += be32_to_cpup(list);
> > > -     ret = mtd_read(mtd, offset, len, &retlen, eep);
> > > -     put_mtd_device(mtd);
> > > -     if (mtd_is_bitflip(ret))
> > > -             ret = 0;
> > > -     if (ret) {
> > > -             dev_err(dev->dev, "reading EEPROM from mtd %s failed: %i\n",
> > > -                     part, ret);
> > > -             goto out_put_node;
> > > -     }
> > > -
> > > -     if (retlen < len) {
> > > -             ret = -EINVAL;
> > > -             goto out_put_node;
> > > -     }
> > > -
> > > -     if (of_property_read_bool(dev->dev->of_node, "big-endian")) {
> > > -             u8 *data = (u8 *)eep;
> > > -             int i;
> > > -
> > > -             /* convert eeprom data in Little Endian */
> > > -             for (i = 0; i < round_down(len, 2); i += 2)
> > > -                     put_unaligned_le16(get_unaligned_be16(&data[i]),
> > > -                                        &data[i]);
> > > -     }
> > > -
> > > -#ifdef CONFIG_NL80211_TESTMODE
> > > -     dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL);
> > > -     if (!dev->test_mtd.name) {
> > > -             ret = -ENOMEM;
> > > -             goto out_put_node;
> > > -     }
> > > -     dev->test_mtd.offset = offset;
> > > -#endif
> > > -
> > > -out_put_node:
> > > -     of_node_put(np);
> > > -     return ret;
> > > -#else
> > > -     return -ENOENT;
> > > -#endif
> > > -}
> > > -EXPORT_SYMBOL_GPL(mt76_get_of_data_from_mtd);
> > > -
> > >  int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep,
> > >                               const char *cell_name, int len)
> > >  {
> > > @@ -163,10 +80,6 @@ static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len)
> > >       if (!ret)
> > >               return 0;
> > >
> > > -     ret = mt76_get_of_data_from_mtd(dev, eep, 0, len);
> > > -     if (!ret)
> > > -             return 0;
> > > -
> > >       return mt76_get_of_data_from_nvmem(dev, eep, "eeprom", len);
> > >  }
> > >
> > > diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
> > > index 527bef97e122..f447ecac664d 100644
> > > --- a/drivers/net/wireless/mediatek/mt76/mt76.h
> > > +++ b/drivers/net/wireless/mediatek/mt76/mt76.h
> > > @@ -1339,7 +1339,6 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str,
> > >
> > >  int mt76_eeprom_init(struct mt76_dev *dev, int len);
> > >  int mt76_eeprom_override(struct mt76_phy *phy);
> > > -int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len);
> > >  int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep,
> > >                               const char *cell_name, int len);
> > >
> > > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
> > > index eb92cbf1a284..c24e1276700b 100644
> > > --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
> > > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
> > > @@ -29,10 +29,6 @@ static int mt7915_eeprom_load_precal(struct mt7915_dev *dev)
> > >
> > >       offs = is_mt7915(&dev->mt76) ? MT_EE_PRECAL : MT_EE_PRECAL_V2;
> > >
> > > -     ret = mt76_get_of_data_from_mtd(mdev, dev->cal, offs, size);
> > > -     if (!ret)
> > > -             return ret;
> > > -
> > >       ret = mt76_get_of_data_from_nvmem(mdev, dev->cal, "precal", size);
> > >       if (!ret)
> > >               return ret;
> > > --
> > > 2.54.0
> > >

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH] wifi: wfx: handle EPROBE_DEFER with of_get_mac_address
From: Rosen Penev @ 2026-04-27 19:31 UTC (permalink / raw)
  To: Jérôme Pouiller; +Cc: linux-wireless@vger.kernel.org, open list
In-Reply-To: <5416906.31r3eYUQgx@nb0018864>

On Mon, Apr 27, 2026 at 12:49 AM Jérôme Pouiller
<jerome.pouiller@silabs.com> wrote:
>
> Hello Rosen,
>
> On Monday 27 April 2026 07:16:04 Central European Summer Time Rosen Penev wrote:
> >
> > In case nvmem gets used and is not ready in time for probe of wfx,
> > EPROBE_DEFER gets called. Return it so that a proper MAC address can be
> > specified in such a case.
> >
> > Signed-off-by: Rosen Penev <rosenp@gmail.com>
> > ---
> >  drivers/net/wireless/silabs/wfx/main.c | 2 ++
> >  1 file changed, 2 insertions(+)
> >
> > diff --git a/drivers/net/wireless/silabs/wfx/main.c b/drivers/net/wireless/silabs/wfx/main.c
> > index dda36e41eed1..dc40a9bd986d 100644
> > --- a/drivers/net/wireless/silabs/wfx/main.c
> > +++ b/drivers/net/wireless/silabs/wfx/main.c
> > @@ -445,6 +445,8 @@ int wfx_probe(struct wfx_dev *wdev)
> >         for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) {
> >                 eth_zero_addr(wdev->addresses[i].addr);
> >                 err = of_get_mac_address(wdev->dev->of_node, wdev->addresses[i].addr);
> > +               if (err == -EPROBE_DEFER)
> > +                       goto irq_unsubscribe;
> >                 if (!err)
> >                         wdev->addresses[i].addr[ETH_ALEN - 1] += i;
> >                 else
>
> I assume this patch works when WF200 is connected on SPI with reset GPIO
> configured. However, for SDIO and without gpio reset, we can't run the
> device initialisation twice.
>
> I believe the check has to happen before the call to wfx_init_device().
>
> To check it works as expected, can you also test your patch without the
> reset-gpio attribute?
I do not have this hardware.
>
>
> --
> Jérôme Pouiller
>
>

^ permalink raw reply

* Re: [PATCH wireless-next] wifi: rt2x00: check for of_get_mac_address error
From: Rosen Penev @ 2026-04-27 19:29 UTC (permalink / raw)
  To: Stanislaw Gruszka; +Cc: Johannes Berg, linux-wireless, open list
In-Reply-To: <20260427105445.GA2620@wp.pl>

On Mon, Apr 27, 2026 at 3:54 AM Stanislaw Gruszka <stf_xl@wp.pl> wrote:
>
> On Mon, Apr 27, 2026 at 12:45:14PM +0200, Johannes Berg wrote:
> > On Mon, 2026-04-27 at 09:32 +0200, Stanislaw Gruszka wrote:
> > > On Sun, Apr 26, 2026 at 10:16:52PM -0700, Rosen Penev wrote:
> > > > is_valid_ether_addr is already a check of of_get_mac_address, in which
> > > > case it returns an error if false. Just set a random MAC on all errors
> > > > except for EPROBE_DEFER.
> > > >
> > > > Signed-off-by: Rosen Penev <rosenp@gmail.com>
> > > Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
> >
> > Are you sure? I just randomly checked one caller to see what the
> > *eeprom_mac_addr would contain, and I see
> >
> >         mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
> >         rt2x00lib_set_mac_address(rt2x00dev, mac);
> >
> > so that case assumes it can get it from EEPROM and override with OF, but
> > if OF fails then it would still use the EEPROM address as long as it's
> > valid ...
>
> You have right, please drop the patch.
>
> BTW, the code should be changed to move getting the address from OF
> out of _set routine.
Where should it go?
>
> Regards
> Stanislaw

^ permalink raw reply

* [syzbot] [wireless?] divide error in mac80211_hwsim_link_info_changed (3)
From: syzbot @ 2026-04-27 19:28 UTC (permalink / raw)
  To: johannes, linux-kernel, linux-wireless, netdev, syzkaller-bugs

Hello,

syzbot found the following issue on:

HEAD commit:    254f49634ee1 Linux 7.1-rc1
git tree:       upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=13b32348580000
kernel config:  https://syzkaller.appspot.com/x/.config?x=4caf64b1ee83dac0
dashboard link: https://syzkaller.appspot.com/bug?extid=ca7a2759caaa6cd4e3db
compiler:       Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8
userspace arch: i386

Unfortunately, I don't have any reproducer for this issue yet.

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/fd59c3aee25f/disk-254f4963.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/2a93e1c819bd/vmlinux-254f4963.xz
kernel image: https://storage.googleapis.com/syzbot-assets/18c05b34ca3c/bzImage-254f4963.xz

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+ca7a2759caaa6cd4e3db@syzkaller.appspotmail.com

Oops: divide error: 0000 [#1] SMP KASAN PTI
CPU: 1 UID: 0 PID: 193 Comm: kworker/u8:6 Tainted: G             L      syzkaller #0 PREEMPT(full) 
Tainted: [L]=SOFTLOCKUP
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026
Workqueue: events_unbound cfg80211_wiphy_work
RIP: 0010:mac80211_hwsim_link_info_changed+0x476/0xfc0 drivers/net/wireless/virtual/mac80211_hwsim.c:2734
Code: 3c 06 00 49 89 c6 48 8b 7c 24 20 74 0a e8 42 72 26 fb 48 8b 7c 24 20 48 8b 0f 89 ce 4c 89 e0 48 c1 e8 20 74 60 4c 89 e0 31 d2 <48> f7 f6 eb 5d e8 30 37 bb fa 4c 8b 74 24 20 49 8d 7e 10 e8 a2 e4
RSP: 0000:ffffc90002ea7860 EFLAGS: 00010246
RAX: 000650757bb12572 RBX: 0000000000000200 RCX: 0000000000000000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff88806fbe7b98
RBP: ffffc90002ea7958 R08: ffffffff903096f7 R09: 1ffffffff20612de
R10: dffffc0000000000 R11: fffffbfff20612df R12: 000650757bb12572
R13: ffff88806fbe7b18 R14: dffffc0000000000 R15: 1ffff920005d4f18
FS:  0000000000000000(0000) GS:ffff888125393000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00000000f540c000 CR3: 0000000064b3a000 CR4: 00000000003526f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 000000000000000e DR6: 00000000ffff0ff0 DR7: 0000000000000400
Call Trace:
 <TASK>
 drv_link_info_changed+0x505/0x880 net/mac80211/driver-ops.c:-1
 ieee80211_offchannel_return+0x375/0x500 net/mac80211/offchannel.c:160
 __ieee80211_scan_completed+0x75a/0xb40 net/mac80211/scan.c:519
 cfg80211_wiphy_work+0x2cf/0x460 net/wireless/core.c:513
 process_one_work kernel/workqueue.c:3302 [inline]
 process_scheduled_works+0xb5d/0x1860 kernel/workqueue.c:3385
 worker_thread+0xa53/0xfc0 kernel/workqueue.c:3466
 kthread+0x388/0x470 kernel/kthread.c:436
 ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
 </TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:mac80211_hwsim_link_info_changed+0x476/0xfc0 drivers/net/wireless/virtual/mac80211_hwsim.c:2734
Code: 3c 06 00 49 89 c6 48 8b 7c 24 20 74 0a e8 42 72 26 fb 48 8b 7c 24 20 48 8b 0f 89 ce 4c 89 e0 48 c1 e8 20 74 60 4c 89 e0 31 d2 <48> f7 f6 eb 5d e8 30 37 bb fa 4c 8b 74 24 20 49 8d 7e 10 e8 a2 e4
RSP: 0000:ffffc90002ea7860 EFLAGS: 00010246
RAX: 000650757bb12572 RBX: 0000000000000200 RCX: 0000000000000000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff88806fbe7b98
RBP: ffffc90002ea7958 R08: ffffffff903096f7 R09: 1ffffffff20612de
R10: dffffc0000000000 R11: fffffbfff20612df R12: 000650757bb12572
R13: ffff88806fbe7b18 R14: dffffc0000000000 R15: 1ffff920005d4f18
FS:  0000000000000000(0000) GS:ffff888125393000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00000000f7487a54 CR3: 00000000608c4000 CR4: 00000000003526f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 000000000000000e DR6: 00000000ffff0ff0 DR7: 0000000000000400
----------------
Code disassembly (best guess), 3 bytes skipped:
   0:	49 89 c6             	mov    %rax,%r14
   3:	48 8b 7c 24 20       	mov    0x20(%rsp),%rdi
   8:	74 0a                	je     0x14
   a:	e8 42 72 26 fb       	call   0xfb267251
   f:	48 8b 7c 24 20       	mov    0x20(%rsp),%rdi
  14:	48 8b 0f             	mov    (%rdi),%rcx
  17:	89 ce                	mov    %ecx,%esi
  19:	4c 89 e0             	mov    %r12,%rax
  1c:	48 c1 e8 20          	shr    $0x20,%rax
  20:	74 60                	je     0x82
  22:	4c 89 e0             	mov    %r12,%rax
  25:	31 d2                	xor    %edx,%edx
* 27:	48 f7 f6             	div    %rsi <-- trapping instruction
  2a:	eb 5d                	jmp    0x89
  2c:	e8 30 37 bb fa       	call   0xfabb3761
  31:	4c 8b 74 24 20       	mov    0x20(%rsp),%r14
  36:	49 8d 7e 10          	lea    0x10(%r14),%rdi
  3a:	e8                   	.byte 0xe8
  3b:	a2                   	.byte 0xa2
  3c:	e4                   	.byte 0xe4


---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.

If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title

If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)

If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report

If you want to undo deduplication, reply with:
#syz undup

^ permalink raw reply

* Re: [RFC PATCH v1 7/9] x86: Add unsafe_copy_from_user()
From: Yury Norov @ 2026-04-27 19:19 UTC (permalink / raw)
  To: Christophe Leroy (CS GROUP)
  Cc: Andrew Morton, Linus Torvalds, David Laight, Thomas Gleixner,
	linux-alpha, Yury Norov, linux-kernel, linux-snps-arc,
	linux-arm-kernel, linux-mips, linuxppc-dev, kvm, linux-riscv,
	linux-s390, sparclinux, linux-um, dmaengine, linux-efi, linux-fsi,
	amd-gfx, dri-devel, intel-gfx, linux-wpan, netdev, linux-wireless,
	linux-spi, linux-media, linux-staging, linux-serial, linux-usb,
	xen-devel, linux-fsdevel, ocfs2-devel, bpf, kasan-dev, linux-mm,
	linux-x25, rust-for-linux, linux-sound, sound-open-firmware,
	linux-csky, linux-hexagon, loongarch, linux-m68k, linux-openrisc,
	linux-parisc, linux-sh, linux-arch
In-Reply-To: <63a4d0f6-0eb3-48cd-9f98-bf7b223b2606@kernel.org>

On Mon, Apr 27, 2026 at 08:20:38PM +0200, Christophe Leroy (CS GROUP) wrote:
> 
> 
> Le 27/04/2026 à 19:58, Yury Norov a écrit :
> > On Mon, Apr 27, 2026 at 07:13:48PM +0200, Christophe Leroy (CS GROUP) wrote:
> > > At the time being, x86 and arm64 are missing unsafe_copy_from_user().
> > 
> > No, they don't. They (should) rely on a generic implementation from
> > linux/uaccess.h, like every other arch, except for  PPC and RISCV.
> > 
> > But they #define arch_unsafe_get_user, and the unsafe_copy_from_user()
> > becomes undefined conditionally on that.
> > 
> > So please, fix that bug instead of introducing another arch flavor.
> > We'd always choose generic version, unless there's strong evidence
> > that arch one is better.
> 
> But they both implement the exact same unsafe_copy_to_user(). What is the
> difference here ?
>
> Should that function become generic too ?

This is what Linus said when added x86 implementation for copy_from_user()
in c512c69187197:

  Note that it only does this [arch version] for the copying _to_ user space,
  and we still don't have a unsafe version of copy_from_user().
  
  That's partly because we have no current users of it, but also partly
  because the copy_from_user() case is slightly different and cannot
  efficiently be implemented in terms of a unsafe_get_user() loop (because
  gcc can't do asm goto with outputs).

In the unsafe_copy_to_user case, arch versions were justified. Just as
said, I'm not against arch version for unsafe_copy_from_user(), but it
should be explained very well.

^ permalink raw reply

* Re: [PATCH 3/3] wifi: mt76: remove mt76_get_of_data_from_mtd
From: Rosen Penev @ 2026-04-27 19:17 UTC (permalink / raw)
  To: Conor Dooley
  Cc: devicetree, Felix Fietkau, Lorenzo Bianconi, Ryder Lee,
	Shayne Chen, Sean Wang, Johannes Berg, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Thomas Bogendoerfer,
	open list:MEDIATEK MT76 WIRELESS LAN DRIVER,
	open list:ARM/Mediatek SoC support,
	moderated list:ARM/Mediatek SoC support,
	moderated list:ARM/Mediatek SoC support, open list:MIPS
In-Reply-To: <20260427-hug-baboon-d60bb8fdfa51@spud>

On Mon, Apr 27, 2026 at 12:09 PM Conor Dooley <conor@kernel.org> wrote:
>
> On Sun, Apr 26, 2026 at 08:44:27PM -0700, Rosen Penev wrote:
> > mt76_get_of_data_from_mtd has been replaced by
> > mt76_get_of_data_from_nvmem in all usages.
>
> All users in the kernel, but what about other sources of devicetrees?
> Those built into firmware etc? Are there none of those too?
I'm actively removing those: https://github.com/openwrt/openwrt/pull/23113

Anyway, irrelevant here.
>
> Conor.
>
> >
> > Remove it to prevent people from using the deprecated
> > mediatek,mtd-eeprom binding.
> >
> > Signed-off-by: Rosen Penev <rosenp@gmail.com>
> > ---
> >  drivers/net/wireless/mediatek/mt76/eeprom.c   | 87 -------------------
> >  drivers/net/wireless/mediatek/mt76/mt76.h     |  1 -
> >  .../wireless/mediatek/mt76/mt7915/eeprom.c    |  4 -
> >  3 files changed, 92 deletions(-)
> >
> > diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c
> > index afdb73661866..092804323d81 100644
> > --- a/drivers/net/wireless/mediatek/mt76/eeprom.c
> > +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c
> > @@ -35,89 +35,6 @@ static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len)
> >       return 0;
> >  }
> >
> > -int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len)
> > -{
> > -#ifdef CONFIG_MTD
> > -     struct device_node *np = dev->dev->of_node;
> > -     struct mtd_info *mtd;
> > -     const __be32 *list;
> > -     const char *part;
> > -     phandle phandle;
> > -     size_t retlen;
> > -     int size;
> > -     int ret;
> > -
> > -     list = of_get_property(np, "mediatek,mtd-eeprom", &size);
> > -     if (!list)
> > -             return -ENOENT;
> > -
> > -     phandle = be32_to_cpup(list++);
> > -     if (!phandle)
> > -             return -ENOENT;
> > -
> > -     np = of_find_node_by_phandle(phandle);
> > -     if (!np)
> > -             return -EINVAL;
> > -
> > -     part = of_get_property(np, "label", NULL);
> > -     if (!part)
> > -             part = np->name;
> > -
> > -     mtd = get_mtd_device_nm(part);
> > -     if (IS_ERR(mtd)) {
> > -             ret =  PTR_ERR(mtd);
> > -             goto out_put_node;
> > -     }
> > -
> > -     if (size <= sizeof(*list)) {
> > -             ret = -EINVAL;
> > -             goto out_put_node;
> > -     }
> > -
> > -     offset += be32_to_cpup(list);
> > -     ret = mtd_read(mtd, offset, len, &retlen, eep);
> > -     put_mtd_device(mtd);
> > -     if (mtd_is_bitflip(ret))
> > -             ret = 0;
> > -     if (ret) {
> > -             dev_err(dev->dev, "reading EEPROM from mtd %s failed: %i\n",
> > -                     part, ret);
> > -             goto out_put_node;
> > -     }
> > -
> > -     if (retlen < len) {
> > -             ret = -EINVAL;
> > -             goto out_put_node;
> > -     }
> > -
> > -     if (of_property_read_bool(dev->dev->of_node, "big-endian")) {
> > -             u8 *data = (u8 *)eep;
> > -             int i;
> > -
> > -             /* convert eeprom data in Little Endian */
> > -             for (i = 0; i < round_down(len, 2); i += 2)
> > -                     put_unaligned_le16(get_unaligned_be16(&data[i]),
> > -                                        &data[i]);
> > -     }
> > -
> > -#ifdef CONFIG_NL80211_TESTMODE
> > -     dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL);
> > -     if (!dev->test_mtd.name) {
> > -             ret = -ENOMEM;
> > -             goto out_put_node;
> > -     }
> > -     dev->test_mtd.offset = offset;
> > -#endif
> > -
> > -out_put_node:
> > -     of_node_put(np);
> > -     return ret;
> > -#else
> > -     return -ENOENT;
> > -#endif
> > -}
> > -EXPORT_SYMBOL_GPL(mt76_get_of_data_from_mtd);
> > -
> >  int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep,
> >                               const char *cell_name, int len)
> >  {
> > @@ -163,10 +80,6 @@ static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len)
> >       if (!ret)
> >               return 0;
> >
> > -     ret = mt76_get_of_data_from_mtd(dev, eep, 0, len);
> > -     if (!ret)
> > -             return 0;
> > -
> >       return mt76_get_of_data_from_nvmem(dev, eep, "eeprom", len);
> >  }
> >
> > diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
> > index 527bef97e122..f447ecac664d 100644
> > --- a/drivers/net/wireless/mediatek/mt76/mt76.h
> > +++ b/drivers/net/wireless/mediatek/mt76/mt76.h
> > @@ -1339,7 +1339,6 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str,
> >
> >  int mt76_eeprom_init(struct mt76_dev *dev, int len);
> >  int mt76_eeprom_override(struct mt76_phy *phy);
> > -int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len);
> >  int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep,
> >                               const char *cell_name, int len);
> >
> > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
> > index eb92cbf1a284..c24e1276700b 100644
> > --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
> > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
> > @@ -29,10 +29,6 @@ static int mt7915_eeprom_load_precal(struct mt7915_dev *dev)
> >
> >       offs = is_mt7915(&dev->mt76) ? MT_EE_PRECAL : MT_EE_PRECAL_V2;
> >
> > -     ret = mt76_get_of_data_from_mtd(mdev, dev->cal, offs, size);
> > -     if (!ret)
> > -             return ret;
> > -
> >       ret = mt76_get_of_data_from_nvmem(mdev, dev->cal, "precal", size);
> >       if (!ret)
> >               return ret;
> > --
> > 2.54.0
> >

^ permalink raw reply

* Re: [PATCH 3/3] wifi: mt76: remove mt76_get_of_data_from_mtd
From: Conor Dooley @ 2026-04-27 19:09 UTC (permalink / raw)
  To: Rosen Penev
  Cc: devicetree, Felix Fietkau, Lorenzo Bianconi, Ryder Lee,
	Shayne Chen, Sean Wang, Johannes Berg, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Thomas Bogendoerfer,
	open list:MEDIATEK MT76 WIRELESS LAN DRIVER,
	open list:ARM/Mediatek SoC support,
	moderated list:ARM/Mediatek SoC support,
	moderated list:ARM/Mediatek SoC support, open list:MIPS
In-Reply-To: <20260427034427.881389-4-rosenp@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 4793 bytes --]

On Sun, Apr 26, 2026 at 08:44:27PM -0700, Rosen Penev wrote:
> mt76_get_of_data_from_mtd has been replaced by
> mt76_get_of_data_from_nvmem in all usages.

All users in the kernel, but what about other sources of devicetrees?
Those built into firmware etc? Are there none of those too?

Conor.

> 
> Remove it to prevent people from using the deprecated
> mediatek,mtd-eeprom binding.
> 
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
>  drivers/net/wireless/mediatek/mt76/eeprom.c   | 87 -------------------
>  drivers/net/wireless/mediatek/mt76/mt76.h     |  1 -
>  .../wireless/mediatek/mt76/mt7915/eeprom.c    |  4 -
>  3 files changed, 92 deletions(-)
> 
> diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c
> index afdb73661866..092804323d81 100644
> --- a/drivers/net/wireless/mediatek/mt76/eeprom.c
> +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c
> @@ -35,89 +35,6 @@ static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len)
>  	return 0;
>  }
>  
> -int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len)
> -{
> -#ifdef CONFIG_MTD
> -	struct device_node *np = dev->dev->of_node;
> -	struct mtd_info *mtd;
> -	const __be32 *list;
> -	const char *part;
> -	phandle phandle;
> -	size_t retlen;
> -	int size;
> -	int ret;
> -
> -	list = of_get_property(np, "mediatek,mtd-eeprom", &size);
> -	if (!list)
> -		return -ENOENT;
> -
> -	phandle = be32_to_cpup(list++);
> -	if (!phandle)
> -		return -ENOENT;
> -
> -	np = of_find_node_by_phandle(phandle);
> -	if (!np)
> -		return -EINVAL;
> -
> -	part = of_get_property(np, "label", NULL);
> -	if (!part)
> -		part = np->name;
> -
> -	mtd = get_mtd_device_nm(part);
> -	if (IS_ERR(mtd)) {
> -		ret =  PTR_ERR(mtd);
> -		goto out_put_node;
> -	}
> -
> -	if (size <= sizeof(*list)) {
> -		ret = -EINVAL;
> -		goto out_put_node;
> -	}
> -
> -	offset += be32_to_cpup(list);
> -	ret = mtd_read(mtd, offset, len, &retlen, eep);
> -	put_mtd_device(mtd);
> -	if (mtd_is_bitflip(ret))
> -		ret = 0;
> -	if (ret) {
> -		dev_err(dev->dev, "reading EEPROM from mtd %s failed: %i\n",
> -			part, ret);
> -		goto out_put_node;
> -	}
> -
> -	if (retlen < len) {
> -		ret = -EINVAL;
> -		goto out_put_node;
> -	}
> -
> -	if (of_property_read_bool(dev->dev->of_node, "big-endian")) {
> -		u8 *data = (u8 *)eep;
> -		int i;
> -
> -		/* convert eeprom data in Little Endian */
> -		for (i = 0; i < round_down(len, 2); i += 2)
> -			put_unaligned_le16(get_unaligned_be16(&data[i]),
> -					   &data[i]);
> -	}
> -
> -#ifdef CONFIG_NL80211_TESTMODE
> -	dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL);
> -	if (!dev->test_mtd.name) {
> -		ret = -ENOMEM;
> -		goto out_put_node;
> -	}
> -	dev->test_mtd.offset = offset;
> -#endif
> -
> -out_put_node:
> -	of_node_put(np);
> -	return ret;
> -#else
> -	return -ENOENT;
> -#endif
> -}
> -EXPORT_SYMBOL_GPL(mt76_get_of_data_from_mtd);
> -
>  int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep,
>  				const char *cell_name, int len)
>  {
> @@ -163,10 +80,6 @@ static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len)
>  	if (!ret)
>  		return 0;
>  
> -	ret = mt76_get_of_data_from_mtd(dev, eep, 0, len);
> -	if (!ret)
> -		return 0;
> -
>  	return mt76_get_of_data_from_nvmem(dev, eep, "eeprom", len);
>  }
>  
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
> index 527bef97e122..f447ecac664d 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt76.h
> @@ -1339,7 +1339,6 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str,
>  
>  int mt76_eeprom_init(struct mt76_dev *dev, int len);
>  int mt76_eeprom_override(struct mt76_phy *phy);
> -int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len);
>  int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep,
>  				const char *cell_name, int len);
>  
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
> index eb92cbf1a284..c24e1276700b 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
> @@ -29,10 +29,6 @@ static int mt7915_eeprom_load_precal(struct mt7915_dev *dev)
>  
>  	offs = is_mt7915(&dev->mt76) ? MT_EE_PRECAL : MT_EE_PRECAL_V2;
>  
> -	ret = mt76_get_of_data_from_mtd(mdev, dev->cal, offs, size);
> -	if (!ret)
> -		return ret;
> -
>  	ret = mt76_get_of_data_from_nvmem(mdev, dev->cal, "precal", size);
>  	if (!ret)
>  		return ret;
> -- 
> 2.54.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [RFC PATCH v1 5/9] uaccess: Switch to copy_{to/from}_user_partial() when relevant
From: Linus Torvalds @ 2026-04-27 19:01 UTC (permalink / raw)
  To: Christophe Leroy (CS GROUP)
  Cc: Yury Norov, Andrew Morton, David Laight, Thomas Gleixner,
	linux-alpha, linux-kernel, linux-snps-arc, linux-arm-kernel,
	linux-mips, linuxppc-dev, kvm, linux-riscv, linux-s390,
	sparclinux, linux-um, dmaengine, linux-efi, linux-fsi, amd-gfx,
	dri-devel, intel-gfx, linux-wpan, netdev, linux-wireless,
	linux-spi, linux-media, linux-staging, linux-serial, linux-usb,
	xen-devel, linux-fsdevel, ocfs2-devel, bpf, kasan-dev, linux-mm,
	linux-x25, rust-for-linux, linux-sound, sound-open-firmware,
	linux-csky, linux-hexagon, loongarch, linux-m68k, linux-openrisc,
	linux-parisc, linux-sh, linux-arch
In-Reply-To: <289b424e243ba2c4139ea04009cf8b9c448a87ff.1777306795.git.chleroy@kernel.org>

[-- Attachment #1: Type: text/plain, Size: 6419 bytes --]

On Mon, 27 Apr 2026 at 10:18, Christophe Leroy (CS GROUP)
<chleroy@kernel.org> wrote:
>
> In a subsequent patch, copy_{to/from}_user() will be modified to
> return -EFAULT when copy fails.

Please don't do this.

This is a maintenance nightmare, and changes pretty much three decades
of semantics, and will cause *very* subtle backporting issues if
somebody happens to rely on the old / new behavior.

I understand the reasoning for the change, but I really don't think
the pain of creating yet another user copy interface is worth it.

We already have a lot of different versions of user copies for
different reasons, and while they all tend to have a good reason (and
some not-so-good, but historical reasons) for existing, this one
doesn't seem worth it.

The main - perhaps only - reason for this "partial" version is that
you want to do that "automatically inlined and optimized fixed-sized
case".

But here's the thing: I think you can already do that. Yes, it
requires some improvements to unsafe_copy_from_user(), but *that*
interface doesn't have three decades of history associated with it,
_and_ you're extending on that one anyway in this series.

"unsafe_copy_from_user()" is very odd, is meant only for small simple
copies that can be inlined and it's special-cased for 'objtool' anyway
(because objtool would have complained about an out-of-line call,
although it could have been special-cased other ways).

In other words: unsafe_copy_from_user() is *very* close to what you
want for that "Oh, I noticed that it's a small fixed-size copy, so I
want to special-case copy-from-user for that".

The _only_ issue with unsafe_copy_from_user() is that you can't see
that there were partial successes. But if *that* was fixed, then this
whole "create a new copy_from_user interface" issue would just go
away.

So please - let's just change unsafe_copy_from_user() to be usable for
the partial case.

And the thing is, all the existing unsafe_copy_from_user()
implementations already effectively *have* the "how much did I not
copy" internally, and they actually do extra work to hide it, ie they
have things like that

        int _i;

that is "how many bytes have I copied" in the powerpc implementation,
or the x86 code does

        size_t __ucu_len = (_len);

where that "ucu_len" is updated as you go along and is literally the
"how many bytes are left to copy" return value that is missing from
this interface.

So what I would suggest is

 - introduce a new user accessor helper that is used for *both*
unsafe_copy_to/from_user() *and* the "inline small constant-sized
normal copy_to/from_user()" calls

 - it's the same thing as the existing  unsafe_copy_to/from_user()
implementation, except it exposes how many bytes are left to be copied
to the exception label.

IOW, it would look something like

     #define unsafe_copy_to_user_outlen(_dst,_src,_len,label)...

which is exactly the same as the current unsafe_copy_to_user(),
*except* it changes "_len" as it does along.

And then you use that for both the "real" unsafe_copy_user and for the
"small constant values" case.

Just as an example, attached is a completely stupid rough draft of a
patch that does this for x86 and only for unsafe_copy_to_user().

And I made a very very hacky change to kernel/sys.c to see what the
code generation looks like.

This is what it results in on x86 with clang (with all the magic
.section data edited out):

        ... edited out the code to generate the times
        ... this is the actual user copy:
        # HERE!
        movabsq $81985529216486895, %rcx        # imm = 0x123456789ABCDEF
        cmpq    %rcx, %rbx
        cmovaq  %rcx, %rbx
        stac
        movq    %r13, (%rbx)                    # exception to .LBB45_8
        movq    %r14, 8(%rbx)                   # exception to .LBB45_8
        movq    %r15, 16(%rbx)                  # exception to .LBB45_8
        movq    %rax, 24(%rbx)                  # exception to .LBB45_8
        clac
.LBB45_6:
        movq    jiffies(%rip), %rdi
        callq   jiffies_64_to_clock_t
.LBB45_7:
        addq    $16, %rsp
        popq    %rbx
        popq    %r12
        popq    %r13
        popq    %r14
        popq    %r15
        retq
.LBB45_8:
        clac
        movq    $-14, %rax
        jmp     .LBB45_7

and notice how the compiler noticed that the 'outlen' isn't actually
used, and turned the exception label into just a "return -EFAULT" and
never actually generated any code for updating remaining lengths?

That actually looks pretty much optimal for a 32-byte user copy.

And it didn't involve changing the semantics at all.

Just to check, I changed that "times()" system call to return the
number of bytes uncopied instead (to emulate the "I actually want to
know what's left" case), and it generated this:

        # HERE!
        movabsq $81985529216486895, %rcx        # imm = 0x123456789ABCDEF
        cmpq    %rcx, %rbx
        cmovaq  %rcx, %rbx
        stac
        movl    $32, %ecx
        movq    %r13, (%rbx)                    # exception to .LBB45_7
        movl    $24, %ecx
        movq    %r15, 8(%rbx)                   # exception to .LBB45_7
        movl    $16, %ecx
        movq    %r14, 16(%rbx)                  # exception to .LBB45_7
        movl    $8, %ecx
        movq    %rax, 24(%rbx)                  # exception to .LBB45_7
        clac
        xorl    %ecx, %ecx
.LBB45_8:
        movq    %rcx, %rax
        addq    $16, %rsp
        popq    %rbx
        popq    %r12
        popq    %r13
        popq    %r14
        popq    %r15
        retq
.LBB45_6:
        movq    jiffies(%rip), %rdi
        jmp     jiffies_64_to_clock_t           # TAILCALL
.LBB45_7:
        clac
        jmp     .LBB45_8

so it all seems to work - although obviously the above is *not* the normal case.

NOTE NOTE NOTE! The attached patch is entirely untested. I obviously
did some "test code generation" with it, but I only *looked* at the
result, and maybe it has some fundamental problem that I just didn't
notice. So treat this as a "how about this approach" patch, not as
anything more serious than that.

And the kerrnel/sys.c hack is very obviously just that: a complate
hack for testing.

A real patch would do that "for small constant-sized copies, turn
copy_to_user() automatically into "_small_copy_to_user()".

The attached is *not* a real patch. Treat it with the contempt it deserves.

             Linus

[-- Attachment #2: patch.diff --]
[-- Type: text/x-patch, Size: 2637 bytes --]

 arch/x86/include/asm/uaccess.h | 17 +++++++++++------
 include/linux/uaccess.h        | 16 ++++++++++++++++
 kernel/sys.c                   |  3 ++-
 3 files changed, 29 insertions(+), 7 deletions(-)

diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 3a0dd3c2b233..3b2c57c91418 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -606,15 +606,20 @@ _label:									\
 		len -= sizeof(type);						\
 	}
 
-#define unsafe_copy_to_user(_dst,_src,_len,label)			\
+#define unsafe_copy_to_user_outlen(_dst,_src,_len,label)	\
 do {									\
 	char __user *__ucu_dst = (_dst);				\
 	const char *__ucu_src = (_src);					\
-	size_t __ucu_len = (_len);					\
-	unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u64, label);	\
-	unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u32, label);	\
-	unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u16, label);	\
-	unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u8, label);	\
+	unsafe_copy_loop(__ucu_dst, __ucu_src, _len, u64, label);	\
+	unsafe_copy_loop(__ucu_dst, __ucu_src, _len, u32, label);	\
+	unsafe_copy_loop(__ucu_dst, __ucu_src, _len, u16, label);	\
+	unsafe_copy_loop(__ucu_dst, __ucu_src, _len, u8, label);	\
+} while (0)
+
+#define unsafe_copy_to_user(_dst,_src,_len,label)			\
+do {									\
+	size_t __ucu_len = _len;					\
+	unsafe_copy_to_user_outlen(_dst,_src,__ucu_len,label);		\
 } while (0)
 
 #ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index 56328601218c..1a70ef70784c 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -874,4 +874,20 @@ void __noreturn usercopy_abort(const char *name, const char *detail,
 			       unsigned long len);
 #endif
 
+static __always_inline __must_check unsigned long
+_small_copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+	size_t uncopied = n;
+
+	might_fault();
+	if (should_fail_usercopy())
+		return n;
+	instrument_copy_to_user(to, from, n);
+	scoped_user_write_access_size(to, n, failed)
+		unsafe_copy_to_user_outlen(to, from, uncopied, failed);
+	return 0;
+failed:
+       return uncopied;
+}
+
 #endif		/* __LINUX_UACCESS_H__ */
diff --git a/kernel/sys.c b/kernel/sys.c
index 62e842055cc9..65b2d0103a73 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1067,7 +1067,8 @@ SYSCALL_DEFINE1(times, struct tms __user *, tbuf)
 		struct tms tmp;
 
 		do_sys_times(&tmp);
-		if (copy_to_user(tbuf, &tmp, sizeof(struct tms)))
+		asm volatile("# HERE!");
+		if (_small_copy_to_user(tbuf, &tmp, sizeof(struct tms)))
 			return -EFAULT;
 	}
 	force_successful_syscall_return();

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox