* [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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox