* [PATCH] clk: sunxi-ng: div: implement set_rate_and_parent
From: Aureal @ 2026-07-19 15:31 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Chen-Yu Tsai, Jernej Skrabec,
Samuel Holland
Cc: Brian Masney, linux-clk, linux-arm-kernel, linux-sunxi,
linux-kernel, Juan Manuel López Carrillo
From: Juan Manuel López Carrillo <juanmanuellopezcarrillo@gmail.com>
When a rate change on a ccu_div clock also switches its parent, the
clk core, in the absence of a .set_rate_and_parent op, programs the
parent first and the divider second. If the new parent is faster than
the old one, the clock transiently runs at new_parent_rate/old_divider
between the two register writes, overshooting both the old and the
requested rate and potentially violating the consumer's maximum
allowed frequency.
This is not theoretical. On the Allwinner A523/T527 the GPU clock is
a ccu_div muxing between pll-gpu and the fixed pll-periph0 outputs:
going from 600 MHz (pll-periph0-600M, M=1) down to 400 or 200 MHz
(both derived from pll-periph0-800M) makes the Mali G57 run at 800 MHz
for the window between the two writes, 33% above the vendor's maximum
operating point. Observed and validated on an Orange Pi 4A (T527)
with a downstream GPU devfreq setup; mainline does not yet describe
GPU OPPs for this SoC, but any ccu_div consumer whose set_rate ends up
crossing parents is affected.
Implement .set_rate_and_parent with the same ordering rule as
clk_composite_set_rate_and_parent(): if keeping the current divider
while switching the mux would overshoot the requested rate, program
the divider first, otherwise switch the mux first. The intermediate
rate then never exceeds both the old and the new rate.
Clocks using a prediv feature keep the historical mux-then-divider
order: the prediv helpers look the prediv up by the current parent,
which is ambiguous while both are changing.
Fixes: e9b93213103f ("clk: sunxi-ng: Add divider")
Signed-off-by: Juan Manuel López Carrillo <juanmanuellopezcarrillo@gmail.com>
---
Note: this touches the same area of ccu_div.c as patch 2/4 of the
pending series "clk: sun6i-rtc: Add support for Allwinner A733 SoC" v5
(<20260717-a733-rtc-v5-2-3874cc26abf7@baylibre.com>), which adds
ccu_rodiv_ops right after ccu_div_ops. The conflict is trivial
(context only); happy to rebase on top of it if it lands first.
drivers/clk/sunxi-ng/ccu_div.c | 36 ++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/drivers/clk/sunxi-ng/ccu_div.c b/drivers/clk/sunxi-ng/ccu_div.c
index 62d680ccb..9024bcd8c 100644
--- a/drivers/clk/sunxi-ng/ccu_div.c
+++ b/drivers/clk/sunxi-ng/ccu_div.c
@@ -130,6 +130,41 @@ static int ccu_div_set_parent(struct clk_hw *hw, u8 index)
return ccu_mux_helper_set_parent(&cd->common, &cd->mux, index);
}
+static int ccu_div_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate, u8 index)
+{
+ struct ccu_div *cd = hw_to_ccu_div(hw);
+
+ /*
+ * The predivider helpers look it up through the current parent,
+ * which is ambiguous while both the parent and the divider are
+ * changing, so keep the mux-then-divider order the core would
+ * have used for those clocks.
+ */
+ if (cd->common.features & (CCU_FEATURE_VARIABLE_PREDIV |
+ CCU_FEATURE_FIXED_PREDIV |
+ CCU_FEATURE_ALL_PREDIV)) {
+ ccu_div_set_parent(hw, index);
+ return ccu_div_set_rate(hw, rate, parent_rate);
+ }
+
+ /*
+ * Same ordering rule as clk_composite_set_rate_and_parent(): if
+ * switching the mux with the current divider would overshoot the
+ * requested rate, program the divider first, so the intermediate
+ * rate never exceeds both the old and the new rate.
+ */
+ if (ccu_div_recalc_rate(hw, parent_rate) > rate) {
+ ccu_div_set_rate(hw, rate, parent_rate);
+ ccu_div_set_parent(hw, index);
+ } else {
+ ccu_div_set_parent(hw, index);
+ ccu_div_set_rate(hw, rate, parent_rate);
+ }
+
+ return 0;
+}
+
const struct clk_ops ccu_div_ops = {
.disable = ccu_div_disable,
.enable = ccu_div_enable,
@@ -141,5 +176,6 @@ const struct clk_ops ccu_div_ops = {
.determine_rate = ccu_div_determine_rate,
.recalc_rate = ccu_div_recalc_rate,
.set_rate = ccu_div_set_rate,
+ .set_rate_and_parent = ccu_div_set_rate_and_parent,
};
EXPORT_SYMBOL_NS_GPL(ccu_div_ops, "SUNXI_CCU");
base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda
--
2.47.3
^ permalink raw reply related
* Re: [PATCH] clk: sunxi-ng: div: implement set_rate_and_parent
From: Chen-Yu Tsai @ 2026-07-19 15:56 UTC (permalink / raw)
To: Aureal
Cc: Michael Turquette, Stephen Boyd, Jernej Skrabec, Samuel Holland,
Brian Masney, linux-clk, linux-arm-kernel, linux-sunxi,
linux-kernel, André Przywara
In-Reply-To: <20260719153122.892013-1-juanmanuellopezcarrillo@gmail.com>
On Sun, Jul 19, 2026 at 11:31 PM Aureal
<juanmanuellopezcarrillo@gmail.com> wrote:
>
> From: Juan Manuel López Carrillo <juanmanuellopezcarrillo@gmail.com>
>
> When a rate change on a ccu_div clock also switches its parent, the
> clk core, in the absence of a .set_rate_and_parent op, programs the
> parent first and the divider second. If the new parent is faster than
> the old one, the clock transiently runs at new_parent_rate/old_divider
> between the two register writes, overshooting both the old and the
> requested rate and potentially violating the consumer's maximum
> allowed frequency.
>
> This is not theoretical. On the Allwinner A523/T527 the GPU clock is
> a ccu_div muxing between pll-gpu and the fixed pll-periph0 outputs:
> going from 600 MHz (pll-periph0-600M, M=1) down to 400 or 200 MHz
> (both derived from pll-periph0-800M) makes the Mali G57 run at 800 MHz
> for the window between the two writes, 33% above the vendor's maximum
> operating point. Observed and validated on an Orange Pi 4A (T527)
> with a downstream GPU devfreq setup; mainline does not yet describe
> GPU OPPs for this SoC, but any ccu_div consumer whose set_rate ends up
> crossing parents is affected.
>
> Implement .set_rate_and_parent with the same ordering rule as
> clk_composite_set_rate_and_parent(): if keeping the current divider
> while switching the mux would overshoot the requested rate, program
> the divider first, otherwise switch the mux first. The intermediate
> rate then never exceeds both the old and the new rate.
>
> Clocks using a prediv feature keep the historical mux-then-divider
> order: the prediv helpers look the prediv up by the current parent,
> which is ambiguous while both are changing.
>
> Fixes: e9b93213103f ("clk: sunxi-ng: Add divider")
> Signed-off-by: Juan Manuel López Carrillo <juanmanuellopezcarrillo@gmail.com>
Reviewed-by: Chen-Yu Tsai <wens@kernel.org>
So the patch itself is OK, but I think there is also something wrong
with the GPU mod clock. The GPU clock is not a standard divider, but
actually a fractional one. The formula for the output is
Clock Source * ((16-M)/16)
with M being 0~15.
And we're also missing a notifier to switch the GPU clock away from
the PLL while the PLL is being changed.
Do you plan on implementing GPU DVFS on mainline?
> ---
> Note: this touches the same area of ccu_div.c as patch 2/4 of the
> pending series "clk: sun6i-rtc: Add support for Allwinner A733 SoC" v5
> (<20260717-a733-rtc-v5-2-3874cc26abf7@baylibre.com>), which adds
> ccu_rodiv_ops right after ccu_div_ops. The conflict is trivial
> (context only); happy to rebase on top of it if it lands first.
That is manageable. Thanks for the heads up.
ChenYu
>
> drivers/clk/sunxi-ng/ccu_div.c | 36 ++++++++++++++++++++++++++++++++++
> 1 file changed, 36 insertions(+)
>
> diff --git a/drivers/clk/sunxi-ng/ccu_div.c b/drivers/clk/sunxi-ng/ccu_div.c
> index 62d680ccb..9024bcd8c 100644
> --- a/drivers/clk/sunxi-ng/ccu_div.c
> +++ b/drivers/clk/sunxi-ng/ccu_div.c
> @@ -130,6 +130,41 @@ static int ccu_div_set_parent(struct clk_hw *hw, u8 index)
> return ccu_mux_helper_set_parent(&cd->common, &cd->mux, index);
> }
>
> +static int ccu_div_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate, u8 index)
> +{
> + struct ccu_div *cd = hw_to_ccu_div(hw);
> +
> + /*
> + * The predivider helpers look it up through the current parent,
> + * which is ambiguous while both the parent and the divider are
> + * changing, so keep the mux-then-divider order the core would
> + * have used for those clocks.
> + */
> + if (cd->common.features & (CCU_FEATURE_VARIABLE_PREDIV |
> + CCU_FEATURE_FIXED_PREDIV |
> + CCU_FEATURE_ALL_PREDIV)) {
> + ccu_div_set_parent(hw, index);
> + return ccu_div_set_rate(hw, rate, parent_rate);
> + }
> +
> + /*
> + * Same ordering rule as clk_composite_set_rate_and_parent(): if
> + * switching the mux with the current divider would overshoot the
> + * requested rate, program the divider first, so the intermediate
> + * rate never exceeds both the old and the new rate.
> + */
> + if (ccu_div_recalc_rate(hw, parent_rate) > rate) {
> + ccu_div_set_rate(hw, rate, parent_rate);
> + ccu_div_set_parent(hw, index);
> + } else {
> + ccu_div_set_parent(hw, index);
> + ccu_div_set_rate(hw, rate, parent_rate);
> + }
> +
> + return 0;
> +}
> +
> const struct clk_ops ccu_div_ops = {
> .disable = ccu_div_disable,
> .enable = ccu_div_enable,
> @@ -141,5 +176,6 @@ const struct clk_ops ccu_div_ops = {
> .determine_rate = ccu_div_determine_rate,
> .recalc_rate = ccu_div_recalc_rate,
> .set_rate = ccu_div_set_rate,
> + .set_rate_and_parent = ccu_div_set_rate_and_parent,
> };
> EXPORT_SYMBOL_NS_GPL(ccu_div_ops, "SUNXI_CCU");
>
> base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda
> --
> 2.47.3
>
^ permalink raw reply
* [PATCH 0/4] serial: fix console lifetime bugs on failed bind and removal
From: Karl Mehltretter @ 2026-07-19 16:08 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: Karl Mehltretter, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, linux-serial, linux-kernel, imx, linux-arm-kernel
This series fixes serial/tty lifetime bugs found while injecting
allocation failures into the UART bind path. The failures were
reproduced on QEMU's raspi1ap (amba-pl011) and mcimx6ul-evk (imx)
machines.
The first three patches fix shared serial/tty error paths: move
fallible port allocations before console registration, clear state
after failed uart_driver registration, and track whether a live cdev
is registered. The final patch fixes the lifetime of the i.MX driver's
private console-port table on probe failure and removal.
The i.MX probe-failure fix spans patches 1 and 4. Serial core must not
return an error while leaving the console registered, and the i.MX
driver must clear its table entry before the failed probe frees the
port.
With all four patches applied, fail-nth sweeps of the console UART bind
path completed on both machines without a KASAN report or oops. Every
failed bind left the console unregistered, and the i.MX unbind/rebind
reproducer also ran cleanly.
This follows up on the discussion here:
https://lore.kernel.org/r/alyjOGyTd19Obemi@MacBook-Pro-von-Karl
Karl Mehltretter (4):
serial: core: do fallible allocations before the console can be
registered
serial: core: clear freed pointers on uart_register_driver() failure
tty: don't oops in tty_unregister_device() when no cdev is registered
serial: imx: clear imx_uart_ports[] entry on probe failure and removal
drivers/tty/serial/imx.c | 4 ++++
drivers/tty/serial/serial_core.c | 33 ++++++++++++++++++-------------
drivers/tty/tty_io.c | 6 ++++--
3 files changed, 27 insertions(+), 16 deletions(-)
--
2.53.0
^ permalink raw reply
* [PATCH 1/4] serial: core: do fallible allocations before the console can be registered
From: Karl Mehltretter @ 2026-07-19 16:08 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: Karl Mehltretter, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, linux-serial, linux-kernel, imx, linux-arm-kernel,
stable
In-Reply-To: <20260719160812.35407-1-kmehltretter@gmail.com>
serial_core_add_one_port() allocates uport->tty_groups after
uart_configure_port() has already registered the port's console. If
that allocation fails, the function returns -ENOMEM with the console
still registered, and the driver's probe error path then tears down
the port state the console callbacks depend on.
Reproduced with fault injection on qemu's raspi1ap board. Failing the
tty_groups allocation during a PL011 sysfs bind makes
uart_add_one_port() return -ENOMEM. pl011_register_port() then clears
amba_ports[0], but ttyAMA0 remains registered as a console. The nbcon
printer thread dereferences the NULL entry and oopses:
Unhandled fault: page domain fault (0x01b) at 0x00000178
CPU: 0 UID: 0 PID: 43 Comm: pr/ttyAMA0 Not tainted 7.2.0-rc3+ #1
PC is at pl011_console_write_thread+0x2c/0x168
This is not PL011-specific: the failing allocation is in serial core,
after uart_configure_port() has registered the console, so any console
UART driver is exposed. On i.MX the retained console references a
devm-allocated port that the failed probe frees, causing a
use-after-free. Reproduced on qemu's mcimx6ul-evk using the same
fail-nth harness under KASAN:
BUG: KASAN: slab-use-after-free in imx_uart_console_write_thread+0x50/0x278
Read of size 4 at addr c5246048 by task pr/ttymxc0/63
imx_uart_console_write_thread from nbcon_emit_next_record+0x360/0x50c
nbcon_emit_next_record from nbcon_emit_one+0x140/0x184
Allocated by task 1:
devm_kmalloc from imx_uart_probe+0x90/0xa5c
Freed by task 1:
devres_release_all from device_unbind_cleanup+0x38/0xdc
device_unbind_cleanup from really_probe+0x2b4/0x388
The pre-existing kasprintf() failure path has a related problem: it
returns with state->uart_port already pointing at a port whose probe
is about to unwind and free it.
Reorder the function so the uport->name and uport->tty_groups
allocations both happen before the port is linked into the driver
state table and before uart_configure_port() registers the console:
1. Allocate uport->name.
2. Allocate the tty_groups array with room for three entries
unconditionally (serial core group, optional driver group, NULL
terminator). The optional group cannot be examined at this point:
config_port() may only supply uport->attr_group during
uart_configure_port(), e.g. 8250 sets it after autodetection.
3. Only then link the port into the driver state table and run
uart_configure_port().
4. Fill in the optional attr_group slot afterwards.
A fail-nth sweep over the whole bind path on both boards left the
console unregistered after every failed bind and did not reproduce the
i.MX use-after-free.
Fixes: 266dcff03eed ("Serial: allow port drivers to have a default attribute group")
Fixes: f7048b15900f ("tty: serial_core: Add name field to uart_port struct")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-fable-5
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
---
drivers/tty/serial/serial_core.c | 31 +++++++++++++++++--------------
1 file changed, 17 insertions(+), 14 deletions(-)
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index a530ad372b43..887b1dd80ad2 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -3056,7 +3056,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
struct uart_state *state;
struct tty_port *port;
struct device *tty_dev;
- int num_groups;
if (uport->line >= drv->nr)
return -EINVAL;
@@ -3068,6 +3067,23 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
if (state->uart_port)
return -EINVAL;
+ uport->name = kasprintf(GFP_KERNEL, "%s%u", drv->dev_name,
+ drv->tty_driver->name_base + uport->line);
+ if (!uport->name)
+ return -ENOMEM;
+
+ /*
+ * uart_configure_port() may set uport->attr_group and register the
+ * console. Allocate room for both groups and a NULL terminator first.
+ */
+ uport->tty_groups = kzalloc_objs(*uport->tty_groups, 3);
+ if (!uport->tty_groups) {
+ kfree(uport->name);
+ uport->name = NULL;
+ return -ENOMEM;
+ }
+ uport->tty_groups[0] = &tty_dev_attr_group;
+
/* Link the port to the driver state table and vice versa */
atomic_set(&state->refcount, 1);
init_waitqueue_head(&state->remove_wait);
@@ -3084,10 +3100,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
state->pm_state = UART_PM_STATE_UNDEFINED;
uart_port_set_cons(uport, drv->cons);
uport->minor = drv->tty_driver->minor_start + uport->line;
- uport->name = kasprintf(GFP_KERNEL, "%s%u", drv->dev_name,
- drv->tty_driver->name_base + uport->line);
- if (!uport->name)
- return -ENOMEM;
if (uport->cons && uport->dev)
of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
@@ -3102,15 +3114,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
port->console = uart_console(uport);
- num_groups = 2;
- if (uport->attr_group)
- num_groups++;
-
- uport->tty_groups = kzalloc_objs(*uport->tty_groups, num_groups);
- if (!uport->tty_groups)
- return -ENOMEM;
-
- uport->tty_groups[0] = &tty_dev_attr_group;
if (uport->attr_group)
uport->tty_groups[1] = uport->attr_group;
--
2.53.0
^ permalink raw reply related
* [PATCH 4/4] serial: imx: clear imx_uart_ports[] entry on probe failure and removal
From: Karl Mehltretter @ 2026-07-19 16:08 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: Karl Mehltretter, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, linux-serial, linux-kernel, imx, linux-arm-kernel,
stable
In-Reply-To: <20260719160812.35407-1-kmehltretter@gmail.com>
imx_uart_probe() stores the port in imx_uart_ports[] before calling
uart_add_one_port() because console setup during that call uses the
table. The entry remains set if uart_add_one_port() fails.
imx_uart_remove() also leaves it set after uart_remove_one_port().
sport is devm-allocated, so a failed probe or unbind frees it while
imx_uart_ports[] still points to it. A later sibling probe can register
the shared console with the old preferred index and dereference the
stale entry in imx_uart_console_setup().
Reproduced on qemu's mcimx6ul-evk by unbinding a sibling UART, unbinding
the console UART and rebinding the sibling:
BUG: KASAN: slab-use-after-free in imx_uart_console_setup+0xd0/0x3d8
Read of size 4 at addr c49ad9d4 by task init/1
Call trace:
...
imx_uart_console_setup from try_enable_preferred_console+0x158/0x1f8
try_enable_preferred_console from register_console+0x1cc/0x80c
register_console from serial_core_register_port+0xe58/0xeb0
...
Freed by task 1:
...
devres_release_all+0x100/0x18c
device_unbind_cleanup+0x38/0xdc
device_release_driver_internal+0x230/0x288
unbind_store+0x64/0xa8
...
The entry must remain visible while uart_add_one_port() and
uart_remove_one_port() run. Clear it when adding the port fails and
after removing the port. Save the line index before removal because the
uart_port is no longer valid afterward.
The probe-failure cleanup relies on the preceding serial-core change
"serial: core: do fallible allocations before the console can be
registered", which ensures that uart_add_one_port() cannot fail after
registering the console. For complete coverage, both changes should be
backported together.
Fixes: dbff4e9ea2e8 ("IMX UART: remove statically initialized tables")
Fixes: 9f322ad064f9 ("imx: serial: handle initialisation failure correctly")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-fable-5
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
---
drivers/tty/serial/imx.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 251a50c8aa38..617c35772056 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -2637,6 +2637,8 @@ static int imx_uart_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, sport);
ret = uart_add_one_port(&imx_uart_uart_driver, &sport->port);
+ if (ret)
+ imx_uart_ports[sport->port.line] = NULL;
err_clk:
clk_disable_unprepare(sport->clk_ipg);
@@ -2647,8 +2649,10 @@ static int imx_uart_probe(struct platform_device *pdev)
static void imx_uart_remove(struct platform_device *pdev)
{
struct imx_port *sport = platform_get_drvdata(pdev);
+ unsigned int line = sport->port.line;
uart_remove_one_port(&imx_uart_uart_driver, &sport->port);
+ imx_uart_ports[line] = NULL;
}
static void imx_uart_restore_context(struct imx_port *sport)
--
2.53.0
^ permalink raw reply related
* Re: [PATCH net-next] net: stmmac: Simplify ioctl handling
From: Andrew Lunn @ 2026-07-19 16:13 UTC (permalink / raw)
To: Maxime Chevallier
Cc: Andrew Lunn, Jakub Kicinski, davem, Eric Dumazet, Paolo Abeni,
Simon Horman, Maxime Coquelin, Alexandre Torgue, Russell King,
thomas.petazzoni, Alexis Lothoré, netdev, linux-kernel,
linux-arm-kernel, linux-stm32
In-Reply-To: <20260718143848.677531-1-maxime.chevallier@bootlin.com>
> Looking at this, I'm wondering if we can't just get rid of SIOCSHWTSTAMP
> handling in phy_mii_ioctl(). Looks like we can ?
I'm not sure about that. We need Richards input.
The code in phy_mii_ioctl() allows the MAC to be bypassed, it goes
straight to a PHY based stamper. It could be the MAC has no idea the
PHY has this capability, so it has not implemented the .ndo?
It might be we need to hoist the code from phy_mii_ioctl() into
dev_{sg}et_hwtstamp()?
Andrew
^ permalink raw reply
* Re: [PATCH] ARM: select HAVE_POSIX_CPU_TIMERS_TASK_WORK
From: Arnd Bergmann @ 2026-07-19 16:15 UTC (permalink / raw)
To: Karl Mehltretter, Russell King, Sebastian Andrzej Siewior
Cc: linux-rt-devel, linux-arm-kernel
In-Reply-To: <20260718214515.11275-1-kmehltretter@gmail.com>
On Sat, Jul 18, 2026, at 23:45, Karl Mehltretter wrote:
> Commit c6e61c06d606 ("ARM: 9463/1: Allow to enable RT") enabled PREEMPT_RT
> on ARM but did not select HAVE_POSIX_CPU_TIMERS_TASK_WORK. This leaves
> CONFIG_POSIX_CPU_TIMERS_TASK_WORK disabled, so CPU timers expire in hard
> IRQ context.
>
> On PREEMPT_RT this makes run_posix_cpu_timers() take the sleeping
> sighand->siglock:
>
> BUG: sleeping function called from invalid context at spinlock_rt.c:48
> rt_spin_lock from lock_task_sighand
> lock_task_sighand from run_posix_cpu_timers
> run_posix_cpu_timers from update_process_times
>
> ARM handles TIF_NOTIFY_RESUME on all return-to-user paths, including v7-M.
> ARM32 KVM host support was removed by commit 541ad0150ca4 ("arm: Remove
> 32bit KVM host support"), so the select need not be conditional on KVM.
>
> Select it to defer POSIX CPU timer expiry to task context.
>
> Reproduced with setrlimit(RLIMIT_CPU, ...) and a busy loop. The same path
> is used by setitimer(ITIMER_PROF or ITIMER_VIRTUAL) and POSIX CPU timers
> created with timer_create().
>
> Fixes: c6e61c06d606 ("ARM: 9463/1: Allow to enable RT")
> Assisted-by: Claude:claude-fable-5
> Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
Indeed selecting HAVE_POSIX_CPU_TIMERS_TASK_WORK was previously
part of the RT patch [1] set but got lost during one of the
updates before the patch got merged.
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
> Found with a self-hosted syzkaller instance patched to fuzz kernels on
> QEMU's versatilepb machine (ARM926EJ-S, ARMv5TE). Runtime-tested before
> and after the change on that setup
Good to hear that this configuration works with your patch,
I don't think many people have tested ARMv5 RT recently.
Arnd
[1] https://lore.kernel.org/all/20251030152253.tK-rY89Y@linutronix.de/
^ permalink raw reply
* [PATCH] KVM: arm64: Update Fuad Tabba's email address
From: Fuad Tabba @ 2026-07-19 16:32 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton; +Cc: kvmarm, linux-arm-kernel, linux-kernel, tabba
Switch my KVM/arm64 reviewer entry to fuad.tabba@linux.dev, my canonical
address for kernel work, and add a .mailmap entry so the existing
tabba@google.com commits map onto it.
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
.mailmap | 1 +
MAINTAINERS | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/.mailmap b/.mailmap
index 735470e21075b..91003fb861367 100644
--- a/.mailmap
+++ b/.mailmap
@@ -291,6 +291,7 @@ Frank Rowand <frowand.list@gmail.com> <frank.rowand@sony.com>
Frank Rowand <frowand.list@gmail.com> <frank.rowand@sonymobile.com>
Frank Rowand <frowand.list@gmail.com> <frowand@mvista.com>
Frank Zago <fzago@systemfabricworks.com>
+Fuad Tabba <fuad.tabba@linux.dev> <tabba@google.com>
Gao Xiang <xiang@kernel.org> <gaoxiang25@huawei.com>
Gao Xiang <xiang@kernel.org> <hsiangkao@aol.com>
Gao Xiang <xiang@kernel.org> <hsiangkao@linux.alibaba.com>
diff --git a/MAINTAINERS b/MAINTAINERS
index a674e36529f75..5ab6fc1504267 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14192,7 +14192,7 @@ F: virt/kvm/*
KERNEL VIRTUAL MACHINE FOR ARM64 (KVM/arm64)
M: Marc Zyngier <maz@kernel.org>
M: Oliver Upton <oupton@kernel.org>
-R: Fuad Tabba <tabba@google.com>
+R: Fuad Tabba <fuad.tabba@linux.dev>
R: Joey Gouly <joey.gouly@arm.com>
R: Steffen Eiden <seiden@linux.ibm.com>
R: Suzuki K Poulose <suzuki.poulose@arm.com>
--
2.39.5
^ permalink raw reply related
* [PATCH net-next v4 0/8] net: dsa: mt7530: modernise register access and add two DSA ops
From: Daniel Golle @ 2026-07-19 17:33 UTC (permalink / raw)
To: Chester A. Unal, Daniel Golle, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Matthias Brugger, AngeloGioacchino Del Regno, Russell King,
netdev, linux-kernel, linux-arm-kernel, linux-mediatek
The mt7530 driver carries its own register accessors that predate the
regmap conversion and now largely duplicate what regmap already
provides, including locking. Most of this series removes that layer.
It first moves the MDIO bus locking into the switch regmap via
.lock/.unlock callbacks, matching the PCS regmaps, so any path reaching
the regmap is serialised automatically. With the wrappers no longer
adding locking, the thin mt7530_mii_* indirection is folded away and the
remaining accessors are replaced mechanically with the plain regmap API,
using the coccinelle semantic patches included in the commit messages.
Open-coded register fields are then converted to FIELD_GET/FIELD_PREP.
None of this is intended to change behaviour.
The last two patches implement .port_fast_age, which flushes dynamically
learned MAC entries on topology changes, and .port_change_conduit, which
moves a user port's CPU-port affinity at runtime.
v3 of this series arrived too close to the end of the last development
cycle and was deferred, hence this respin on top of current net-next.
---
v4:
* rebase onto current net-next
* 5/8: zero the read-back buffer in mt7530_regmap_read() instead of
initialising the result variables at every call site, as suggested
by Jakub
* 6/8: keep MT753X_CTRL_PHY_ADDR() as plain address arithmetic rather
than converting it to FIELD_PREP() as suggested in review: the macro
computes the MDIO bus address of the switch PHYs, used as the addr
argument of bus->read/write and as an iterator base in
mt7530_setup_mdio(), not a hardware register field
v3:
* 5/8: initialise register read-back variables to 0 so a failed
regmap_read keeps the previous read-as-zero behaviour, and use u32
for the value in mt7530_setup_port5
* 6/8: name the age timer field AGE_TIMER_MASK and document the
corrected ATC_HASH/VTCR_VID field macros
* 7/8: serialise the port_fast_age ATC flush under reg_mutex and log
on timeout, align a define, and correct the commit message which
wrongly claimed per-port parity with b53/realtek
* 8/8: populate the netlink extack on rejection and refuse a conduit
that lives on a different switch
v2:
* fix stray 'static void' left-over in 4/8 which had a fix accidentally
folded into 5/8 (byte-identical state at 8/8, but bisectability is
restored)
* extend port_change_conduit op commit message
Daniel Golle (8):
net: dsa: mt7530: move MDIO bus locking into regmap
net: dsa: mt7530: fold mt7530_mii_write/read into mt7530_write/read
net: dsa: mt7530: replace mt7530_write with regmap_write
net: dsa: mt7530: replace mt7530_rmw/set/clear with regmap API
net: dsa: mt7530: replace mt7530_read with regmap_read
net: dsa: mt7530: convert to use field accessor macros
net: dsa: mt7530: implement port_fast_age
net: dsa: mt7530: implement port_change_conduit op
drivers/net/dsa/mt7530-mdio.c | 12 +-
drivers/net/dsa/mt7530.c | 809 +++++++++++++++++-----------------
drivers/net/dsa/mt7530.h | 209 +++++----
3 files changed, 537 insertions(+), 493 deletions(-)
base-commit: ce6b4d3216b63f902bb8e9695ee6c10c83415f65
--
2.55.0
^ permalink raw reply
* [PATCH net-next v4 1/8] net: dsa: mt7530: move MDIO bus locking into regmap
From: Daniel Golle @ 2026-07-19 17:53 UTC (permalink / raw)
To: Chester A. Unal, Daniel Golle, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Matthias Brugger, AngeloGioacchino Del Regno, Russell King,
netdev, linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <cover.1784481922.git.daniel@makrotopia.org>
The switch register regmap was created with .disable_locking = true,
relying on callers to manually lock the MDIO bus. Move the locking
into the regmap using .lock/.unlock callbacks, matching the PCS
regmaps that already do this. This allows any code path reaching the
regmap to be automatically protected.
With regmap handling bus locking, the manual mt7530_mutex_lock/unlock
wrappers in mt7530_write(), _mt7530_read(), mt7530_rmw() and
mt7530_port_change_mtu() become redundant and are removed.
The MT7531 indirect PHY access functions need serialization of their
multi-step register sequences, but no longer need to hold bus->mdio_lock
across the whole operation. Switch them to reg_mutex.
core_write()/core_rmw() are the only remaining callers of
mt7530_mutex_lock(). They access TRGMII core PHY registers via the
clause 22 MMD indirect protocol -- a separate register space that
bypasses regmap and needs manual bus->mdio_lock protection.
Generated using the following semantic patch:
// Remove mt7530_mutex_lock/unlock around single regmap-based calls.
@@
expression priv, reg, val;
@@
{
- mt7530_mutex_lock(priv);
-
mt7530_mii_write(priv, reg, val);
-
- mt7530_mutex_unlock(priv);
}
@@
expression priv, reg, mask, set;
@@
{
- mt7530_mutex_lock(priv);
-
regmap_update_bits(priv->regmap, reg, mask, set);
-
- mt7530_mutex_unlock(priv);
}
@@
expression p;
identifier val;
@@
{
- u32 val;
- mt7530_mutex_lock(p->priv);
- val = mt7530_mii_read(p->priv, p->reg);
- mt7530_mutex_unlock(p->priv);
- return val;
+ return mt7530_mii_read(p->priv, p->reg);
}
@@
expression priv;
@@
- mt7530_mutex_lock(priv);
val = mt7530_mii_read(priv, MT7530_GMACCR);
...
mt7530_mii_write(priv, MT7530_GMACCR, val);
- mt7530_mutex_unlock(priv);
@@
expression priv, port;
@@
INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
- mt7530_mutex_lock(priv);
+ mutex_lock(&priv->reg_mutex);
@@
expression priv;
@@
out:
- mt7530_mutex_unlock(priv);
+ mutex_unlock(&priv->reg_mutex);
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mt7530-mdio.c | 9 ++++++---
drivers/net/dsa/mt7530.c | 38 +++++++++--------------------------
2 files changed, 15 insertions(+), 32 deletions(-)
diff --git a/drivers/net/dsa/mt7530-mdio.c b/drivers/net/dsa/mt7530-mdio.c
index 11ea924a9f35..f7c8eeb27211 100644
--- a/drivers/net/dsa/mt7530-mdio.c
+++ b/drivers/net/dsa/mt7530-mdio.c
@@ -141,12 +141,14 @@ static const struct regmap_config regmap_config = {
.val_bits = 32,
.reg_stride = 4,
.max_register = MT7530_CREV,
- .disable_locking = true,
+ .lock = mt7530_mdio_regmap_lock,
+ .unlock = mt7530_mdio_regmap_unlock,
};
static int
mt7530_probe(struct mdio_device *mdiodev)
{
+ struct regmap_config rc = regmap_config;
struct mt7530_priv *priv;
struct device_node *dn;
int ret;
@@ -200,8 +202,9 @@ mt7530_probe(struct mdio_device *mdiodev)
return PTR_ERR(priv->io_pwr);
}
- priv->regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus, priv,
- ®map_config);
+ rc.lock_arg = &priv->bus->mdio_lock;
+ priv->regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus,
+ priv, &rc);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 3c2a3029b10c..5f56a423b147 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -184,11 +184,7 @@ mt7530_mii_read(struct mt7530_priv *priv, u32 reg)
static void
mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)
{
- mt7530_mutex_lock(priv);
-
mt7530_mii_write(priv, reg, val);
-
- mt7530_mutex_unlock(priv);
}
static u32
@@ -200,15 +196,7 @@ _mt7530_unlocked_read(struct mt7530_dummy_poll *p)
static u32
_mt7530_read(struct mt7530_dummy_poll *p)
{
- u32 val;
-
- mt7530_mutex_lock(p->priv);
-
- val = mt7530_mii_read(p->priv, p->reg);
-
- mt7530_mutex_unlock(p->priv);
-
- return val;
+ return mt7530_mii_read(p->priv, p->reg);
}
static u32
@@ -224,11 +212,7 @@ static void
mt7530_rmw(struct mt7530_priv *priv, u32 reg,
u32 mask, u32 set)
{
- mt7530_mutex_lock(priv);
-
regmap_update_bits(priv->regmap, reg, mask, set);
-
- mt7530_mutex_unlock(priv);
}
static void
@@ -555,7 +539,7 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
- mt7530_mutex_lock(priv);
+ mutex_lock(&priv->reg_mutex);
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
@@ -588,7 +572,7 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
ret = val & MT7531_MDIO_RW_DATA_MASK;
out:
- mt7530_mutex_unlock(priv);
+ mutex_unlock(&priv->reg_mutex);
return ret;
}
@@ -603,7 +587,7 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
- mt7530_mutex_lock(priv);
+ mutex_lock(&priv->reg_mutex);
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
@@ -635,7 +619,7 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
}
out:
- mt7530_mutex_unlock(priv);
+ mutex_unlock(&priv->reg_mutex);
return ret;
}
@@ -649,7 +633,7 @@ mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
- mt7530_mutex_lock(priv);
+ mutex_lock(&priv->reg_mutex);
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
@@ -672,7 +656,7 @@ mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
ret = val & MT7531_MDIO_RW_DATA_MASK;
out:
- mt7530_mutex_unlock(priv);
+ mutex_unlock(&priv->reg_mutex);
return ret;
}
@@ -687,7 +671,7 @@ mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
- mt7530_mutex_lock(priv);
+ mutex_lock(&priv->reg_mutex);
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
!(reg & MT7531_PHY_ACS_ST), 20, 100000);
@@ -709,7 +693,7 @@ mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
}
out:
- mt7530_mutex_unlock(priv);
+ mutex_unlock(&priv->reg_mutex);
return ret;
}
@@ -1444,8 +1428,6 @@ mt7530_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
if (!dsa_is_cpu_port(ds, port))
return 0;
- mt7530_mutex_lock(priv);
-
val = mt7530_mii_read(priv, MT7530_GMACCR);
val &= ~MAX_RX_PKT_LEN_MASK;
@@ -1465,8 +1447,6 @@ mt7530_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
mt7530_mii_write(priv, MT7530_GMACCR, val);
- mt7530_mutex_unlock(priv);
-
return 0;
}
--
2.55.0
^ permalink raw reply related
* [PATCH net-next v4 2/8] net: dsa: mt7530: fold mt7530_mii_write/read into mt7530_write/read
From: Daniel Golle @ 2026-07-19 17:53 UTC (permalink / raw)
To: Chester A. Unal, Daniel Golle, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Matthias Brugger, AngeloGioacchino Del Regno, Russell King,
netdev, linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <cover.1784481922.git.daniel@makrotopia.org>
With the lock wrappers removed in the previous commit, mt7530_write()
was a trivial wrapper around mt7530_mii_write(), and mt7530_read()
around mt7530_mii_read() via _mt7530_read(). Fold the function bodies
and eliminate the intermediate functions.
The _mt7530_unlocked_read() and _mt7530_read() poll helpers, which
existed as locked/unlocked variants for readx_poll_timeout(), are
consolidated into a single mt7530_mii_poll() that calls mt7530_read().
Callers are updated using the following semantic patch:
@@
expression E1, E2, E3;
@@
-mt7530_mii_write(E1, E2, E3)
+mt7530_write(E1, E2, E3)
@@
expression E1, E2;
@@
-mt7530_mii_read(E1, E2)
+mt7530_read(E1, E2)
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mt7530.c | 78 ++++++++++++++--------------------------
1 file changed, 27 insertions(+), 51 deletions(-)
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 5f56a423b147..9ccc848195cf 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -150,22 +150,19 @@ core_clear(struct mt7530_priv *priv, u32 reg, u32 val)
core_rmw(priv, reg, val, 0);
}
-static int
-mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val)
+static void
+mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)
{
int ret;
ret = regmap_write(priv->regmap, reg, val);
-
if (ret < 0)
dev_err(priv->dev,
"failed to write mt7530 register\n");
-
- return ret;
}
static u32
-mt7530_mii_read(struct mt7530_priv *priv, u32 reg)
+mt7530_read(struct mt7530_priv *priv, u32 reg)
{
int ret;
u32 val;
@@ -181,31 +178,10 @@ mt7530_mii_read(struct mt7530_priv *priv, u32 reg)
return val;
}
-static void
-mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)
-{
- mt7530_mii_write(priv, reg, val);
-}
-
static u32
-_mt7530_unlocked_read(struct mt7530_dummy_poll *p)
+mt7530_mii_poll(struct mt7530_dummy_poll *p)
{
- return mt7530_mii_read(p->priv, p->reg);
-}
-
-static u32
-_mt7530_read(struct mt7530_dummy_poll *p)
-{
- return mt7530_mii_read(p->priv, p->reg);
-}
-
-static u32
-mt7530_read(struct mt7530_priv *priv, u32 reg)
-{
- struct mt7530_dummy_poll p;
-
- INIT_MT7530_DUMMY_POLL(&p, priv, reg);
- return _mt7530_read(&p);
+ return mt7530_read(p->priv, p->reg);
}
static void
@@ -239,7 +215,7 @@ mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp)
mt7530_write(priv, MT7530_ATC, val);
INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_ATC);
- ret = readx_poll_timeout(_mt7530_read, &p, val,
+ ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
!(val & ATC_BUSY), 20, 20000);
if (ret < 0) {
dev_err(priv->dev, "reset timeout\n");
@@ -541,7 +517,7 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
mutex_lock(&priv->reg_mutex);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+ ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
@@ -550,9 +526,9 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
reg = MT7531_MDIO_CL45_ADDR | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_DEV_ADDR(devad) | regnum;
- mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
+ mt7530_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+ ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
@@ -561,9 +537,9 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
reg = MT7531_MDIO_CL45_READ | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_DEV_ADDR(devad);
- mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
+ mt7530_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+ ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
@@ -589,7 +565,7 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
mutex_lock(&priv->reg_mutex);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+ ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
@@ -598,9 +574,9 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
reg = MT7531_MDIO_CL45_ADDR | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_DEV_ADDR(devad) | regnum;
- mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
+ mt7530_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+ ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
@@ -609,9 +585,9 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
reg = MT7531_MDIO_CL45_WRITE | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_DEV_ADDR(devad) | data;
- mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
+ mt7530_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+ ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
@@ -635,7 +611,7 @@ mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
mutex_lock(&priv->reg_mutex);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+ ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
@@ -645,9 +621,9 @@ mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
val = MT7531_MDIO_CL22_READ | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_REG_ADDR(regnum);
- mt7530_mii_write(priv, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST);
+ mt7530_write(priv, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+ ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
@@ -673,7 +649,7 @@ mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
mutex_lock(&priv->reg_mutex);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
+ ret = readx_poll_timeout(mt7530_mii_poll, &p, reg,
!(reg & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
@@ -683,9 +659,9 @@ mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
reg = MT7531_MDIO_CL22_WRITE | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_REG_ADDR(regnum) | data;
- mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
+ mt7530_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
+ ret = readx_poll_timeout(mt7530_mii_poll, &p, reg,
!(reg & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
@@ -1428,7 +1404,7 @@ mt7530_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
if (!dsa_is_cpu_port(ds, port))
return 0;
- val = mt7530_mii_read(priv, MT7530_GMACCR);
+ val = mt7530_read(priv, MT7530_GMACCR);
val &= ~MAX_RX_PKT_LEN_MASK;
/* RX length also includes Ethernet header, MTK tag, and FCS length */
@@ -1445,7 +1421,7 @@ mt7530_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
val |= MAX_RX_PKT_LEN_JUMBO;
}
- mt7530_mii_write(priv, MT7530_GMACCR, val);
+ mt7530_write(priv, MT7530_GMACCR, val);
return 0;
}
@@ -1614,7 +1590,7 @@ mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid)
mt7530_write(priv, MT7530_VTCR, val);
INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_VTCR);
- ret = readx_poll_timeout(_mt7530_read, &p, val,
+ ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
!(val & VTCR_BUSY), 20, 20000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
@@ -2465,7 +2441,7 @@ mt7530_setup(struct dsa_switch *ds)
/* Waiting for MT7530 got to stable */
INIT_MT7530_DUMMY_POLL(&p, priv, MT753X_TRAP);
- ret = readx_poll_timeout(_mt7530_read, &p, val, val != 0,
+ ret = readx_poll_timeout(mt7530_mii_poll, &p, val, val != 0,
20, 1000000);
if (ret < 0) {
dev_err(priv->dev, "reset timeout\n");
@@ -2706,7 +2682,7 @@ mt7531_setup(struct dsa_switch *ds)
/* Waiting for MT7530 got to stable */
INIT_MT7530_DUMMY_POLL(&p, priv, MT753X_TRAP);
- ret = readx_poll_timeout(_mt7530_read, &p, val, val != 0,
+ ret = readx_poll_timeout(mt7530_mii_poll, &p, val, val != 0,
20, 1000000);
if (ret < 0) {
dev_err(priv->dev, "reset timeout\n");
--
2.55.0
^ permalink raw reply related
* [PATCH net-next v4 3/8] net: dsa: mt7530: replace mt7530_write with regmap_write
From: Daniel Golle @ 2026-07-19 17:53 UTC (permalink / raw)
To: Chester A. Unal, Daniel Golle, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Matthias Brugger, AngeloGioacchino Del Regno, Russell King,
netdev, linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <cover.1784481922.git.daniel@makrotopia.org>
Replace all mt7530_write() calls with direct regmap_write() calls
and remove the wrapper function. The per-call error logging is
dropped -- regmap has its own tracing infrastructure.
Generated using the following semantic patch:
@@
expression priv, reg, val;
@@
-mt7530_write(priv, reg, val)
+regmap_write(priv->regmap, reg, val)
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mt7530.c | 126 ++++++++++++++++++---------------------
1 file changed, 59 insertions(+), 67 deletions(-)
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 9ccc848195cf..ce4efcf1b3e6 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -150,16 +150,6 @@ core_clear(struct mt7530_priv *priv, u32 reg, u32 val)
core_rmw(priv, reg, val, 0);
}
-static void
-mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)
-{
- int ret;
-
- ret = regmap_write(priv->regmap, reg, val);
- if (ret < 0)
- dev_err(priv->dev,
- "failed to write mt7530 register\n");
-}
static u32
mt7530_read(struct mt7530_priv *priv, u32 reg)
@@ -212,7 +202,7 @@ mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp)
/* Set the command operating upon the MAC address entries */
val = ATC_BUSY | ATC_MAT(0) | cmd;
- mt7530_write(priv, MT7530_ATC, val);
+ regmap_write(priv->regmap, MT7530_ATC, val);
INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_ATC);
ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
@@ -288,7 +278,7 @@ mt7530_fdb_write(struct mt7530_priv *priv, u16 vid,
/* Write array into the ARL table */
for (i = 0; i < 3; i++)
- mt7530_write(priv, MT7530_ATA1 + (i * 4), reg[i]);
+ regmap_write(priv->regmap, MT7530_ATA1 + (i * 4), reg[i]);
}
/* Set up switch core clock for MT7530 */
@@ -406,27 +396,27 @@ mt7531_pll_setup(struct mt7530_priv *priv)
/* Step 1 : Disable MT7531 COREPLL */
val = mt7530_read(priv, MT7531_PLLGP_EN);
val &= ~EN_COREPLL;
- mt7530_write(priv, MT7531_PLLGP_EN, val);
+ regmap_write(priv->regmap, MT7531_PLLGP_EN, val);
/* Step 2: switch to XTAL output */
val = mt7530_read(priv, MT7531_PLLGP_EN);
val |= SW_CLKSW;
- mt7530_write(priv, MT7531_PLLGP_EN, val);
+ regmap_write(priv->regmap, MT7531_PLLGP_EN, val);
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val &= ~RG_COREPLL_EN;
- mt7530_write(priv, MT7531_PLLGP_CR0, val);
+ regmap_write(priv->regmap, MT7531_PLLGP_CR0, val);
/* Step 3: disable PLLGP and enable program PLLGP */
val = mt7530_read(priv, MT7531_PLLGP_EN);
val |= SW_PLLGP;
- mt7530_write(priv, MT7531_PLLGP_EN, val);
+ regmap_write(priv->regmap, MT7531_PLLGP_EN, val);
/* Step 4: program COREPLL output frequency to 500MHz */
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val &= ~RG_COREPLL_POSDIV_M;
val |= 2 << RG_COREPLL_POSDIV_S;
- mt7530_write(priv, MT7531_PLLGP_CR0, val);
+ regmap_write(priv->regmap, MT7531_PLLGP_CR0, val);
usleep_range(25, 35);
switch (xtal) {
@@ -434,42 +424,42 @@ mt7531_pll_setup(struct mt7530_priv *priv)
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val &= ~RG_COREPLL_SDM_PCW_M;
val |= 0x140000 << RG_COREPLL_SDM_PCW_S;
- mt7530_write(priv, MT7531_PLLGP_CR0, val);
+ regmap_write(priv->regmap, MT7531_PLLGP_CR0, val);
break;
case MT7531_XTAL_FSEL_40MHZ:
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val &= ~RG_COREPLL_SDM_PCW_M;
val |= 0x190000 << RG_COREPLL_SDM_PCW_S;
- mt7530_write(priv, MT7531_PLLGP_CR0, val);
+ regmap_write(priv->regmap, MT7531_PLLGP_CR0, val);
break;
}
/* Set feedback divide ratio update signal to high */
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val |= RG_COREPLL_SDM_PCW_CHG;
- mt7530_write(priv, MT7531_PLLGP_CR0, val);
+ regmap_write(priv->regmap, MT7531_PLLGP_CR0, val);
/* Wait for at least 16 XTAL clocks */
usleep_range(10, 20);
/* Step 5: set feedback divide ratio update signal to low */
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val &= ~RG_COREPLL_SDM_PCW_CHG;
- mt7530_write(priv, MT7531_PLLGP_CR0, val);
+ regmap_write(priv->regmap, MT7531_PLLGP_CR0, val);
/* Enable 325M clock for SGMII */
- mt7530_write(priv, MT7531_ANA_PLLGP_CR5, 0xad0000);
+ regmap_write(priv->regmap, MT7531_ANA_PLLGP_CR5, 0xad0000);
/* Enable 250SSC clock for RGMII */
- mt7530_write(priv, MT7531_ANA_PLLGP_CR2, 0x4f40000);
+ regmap_write(priv->regmap, MT7531_ANA_PLLGP_CR2, 0x4f40000);
/* Step 6: Enable MT7531 PLL */
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val |= RG_COREPLL_EN;
- mt7530_write(priv, MT7531_PLLGP_CR0, val);
+ regmap_write(priv->regmap, MT7531_PLLGP_CR0, val);
val = mt7530_read(priv, MT7531_PLLGP_EN);
val |= EN_COREPLL;
- mt7530_write(priv, MT7531_PLLGP_EN, val);
+ regmap_write(priv->regmap, MT7531_PLLGP_EN, val);
usleep_range(25, 35);
}
@@ -478,8 +468,8 @@ mt7530_mib_reset(struct dsa_switch *ds)
{
struct mt7530_priv *priv = ds->priv;
- mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_FLUSH);
- mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_ACTIVATE);
+ regmap_write(priv->regmap, MT7530_MIB_CCR, CCR_MIB_FLUSH);
+ regmap_write(priv->regmap, MT7530_MIB_CCR, CCR_MIB_ACTIVATE);
}
static int mt7530_phy_read_c22(struct mt7530_priv *priv, int port, int regnum)
@@ -526,7 +516,7 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
reg = MT7531_MDIO_CL45_ADDR | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_DEV_ADDR(devad) | regnum;
- mt7530_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
+ regmap_write(priv->regmap, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
@@ -537,7 +527,7 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
reg = MT7531_MDIO_CL45_READ | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_DEV_ADDR(devad);
- mt7530_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
+ regmap_write(priv->regmap, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
@@ -574,7 +564,7 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
reg = MT7531_MDIO_CL45_ADDR | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_DEV_ADDR(devad) | regnum;
- mt7530_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
+ regmap_write(priv->regmap, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
@@ -585,7 +575,7 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
reg = MT7531_MDIO_CL45_WRITE | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_DEV_ADDR(devad) | data;
- mt7530_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
+ regmap_write(priv->regmap, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
@@ -621,7 +611,7 @@ mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
val = MT7531_MDIO_CL22_READ | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_REG_ADDR(regnum);
- mt7530_write(priv, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST);
+ regmap_write(priv->regmap, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST);
ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
@@ -659,7 +649,7 @@ mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
reg = MT7531_MDIO_CL22_WRITE | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_REG_ADDR(regnum) | data;
- mt7530_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
+ regmap_write(priv->regmap, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
ret = readx_poll_timeout(mt7530_mii_poll, &p, reg,
!(reg & MT7531_PHY_ACS_ST), 20, 100000);
@@ -1012,7 +1002,8 @@ mt7530_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
}
}
- mt7530_write(priv, MT7530_AAC, AGE_CNT(age_count) | AGE_UNIT(age_unit));
+ regmap_write(priv->regmap, MT7530_AAC,
+ AGE_CNT(age_count) | AGE_UNIT(age_unit));
return 0;
}
@@ -1050,7 +1041,7 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface)
/* MUX_PHY_P4: P4 -> P5 -> SoC MAC */
case MUX_PHY_P4:
/* Setup the MAC by default for the cpu port */
- mt7530_write(priv, MT753X_PMCR_P(5), 0x56300);
+ regmap_write(priv->regmap, MT753X_PMCR_P(5), 0x56300);
break;
/* GMAC5: P5 -> SoC MAC or external PHY */
@@ -1064,7 +1055,8 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface)
val |= MT7530_P5_RGMII_MODE;
/* P5 RGMII RX Clock Control: delay setting for 1000M */
- mt7530_write(priv, MT7530_P5RGMIIRXCR, CSR_RGMII_EDGE_ALIGN);
+ regmap_write(priv->regmap, MT7530_P5RGMIIRXCR,
+ CSR_RGMII_EDGE_ALIGN);
/* Don't set delay in DSA mode */
if (!dsa_is_dsa_port(priv->ds, 5) &&
@@ -1073,15 +1065,15 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface)
tx_delay = 4; /* n * 0.5 ns */
/* P5 RGMII TX Clock Control: delay x */
- mt7530_write(priv, MT7530_P5RGMIITXCR,
+ regmap_write(priv->regmap, MT7530_P5RGMIITXCR,
CSR_RGMII_TXC_CFG(0x10 + tx_delay));
/* reduce P5 RGMII Tx driving, 8mA */
- mt7530_write(priv, MT7530_IO_DRV_CR,
+ regmap_write(priv->regmap, MT7530_IO_DRV_CR,
P5_IO_CLK_DRV(1) | P5_IO_DATA_DRV(1));
}
- mt7530_write(priv, MT753X_MTRAP, val);
+ regmap_write(priv->regmap, MT753X_MTRAP, val);
dev_dbg(ds->dev, "Setup P5, HWTRAP=0x%x, mode=%s, phy-mode=%s\n", val,
mt7530_p5_mode_str(priv->p5_mode), phy_modes(interface));
@@ -1303,8 +1295,7 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port)
struct mt7530_priv *priv = ds->priv;
/* Enable Mediatek header mode on the cpu port */
- mt7530_write(priv, MT7530_PVC_P(port),
- PORT_SPEC_TAG);
+ regmap_write(priv->regmap, MT7530_PVC_P(port), PORT_SPEC_TAG);
/* Enable flooding on the CPU port */
mt7530_set(priv, MT753X_MFC, BC_FFP(BIT(port)) | UNM_FFP(BIT(port)) |
@@ -1321,7 +1312,7 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port)
/* CPU port gets connected to all user ports of
* the switch.
*/
- mt7530_write(priv, MT7530_PCR_P(port),
+ regmap_write(priv->regmap, MT7530_PCR_P(port),
PCR_MATRIX(dsa_user_ports(priv->ds)));
/* Set to fallback mode for independent VLAN learning */
@@ -1421,7 +1412,7 @@ mt7530_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
val |= MAX_RX_PKT_LEN_JUMBO;
}
- mt7530_write(priv, MT7530_GMACCR, val);
+ regmap_write(priv->regmap, MT7530_GMACCR, val);
return 0;
}
@@ -1587,7 +1578,7 @@ mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid)
int ret;
val = VTCR_BUSY | VTCR_FUNC(cmd) | vid;
- mt7530_write(priv, MT7530_VTCR, val);
+ regmap_write(priv->regmap, MT7530_VTCR, val);
INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_VTCR);
ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
@@ -1616,8 +1607,8 @@ mt7530_setup_vlan0(struct mt7530_priv *priv)
*/
val = IVL_MAC | EG_CON | PORT_MEM(MT7530_ALL_MEMBERS) | FID(FID_BRIDGED) |
VLAN_VALID;
- mt7530_write(priv, MT7530_VAWD1, val);
- mt7530_write(priv, MT7530_VAWD2, 0);
+ regmap_write(priv->regmap, MT7530_VAWD1, val);
+ regmap_write(priv->regmap, MT7530_VAWD2, 0);
return mt7530_vlan_cmd(priv, MT7530_VTCR_WR_VID, 0);
}
@@ -1887,7 +1878,7 @@ mt7530_hw_vlan_add(struct mt7530_priv *priv,
*/
val = IVL_MAC | VTAG_EN | PORT_MEM(new_members) | FID(FID_BRIDGED) |
VLAN_VALID;
- mt7530_write(priv, MT7530_VAWD1, val);
+ regmap_write(priv->regmap, MT7530_VAWD1, val);
/* Decide whether adding tag or not for those outgoing packets from the
* port inside the VLAN.
@@ -1926,10 +1917,10 @@ mt7530_hw_vlan_del(struct mt7530_priv *priv,
if (new_members) {
val = IVL_MAC | VTAG_EN | PORT_MEM(new_members) |
VLAN_VALID;
- mt7530_write(priv, MT7530_VAWD1, val);
+ regmap_write(priv->regmap, MT7530_VAWD1, val);
} else {
- mt7530_write(priv, MT7530_VAWD1, 0);
- mt7530_write(priv, MT7530_VAWD2, 0);
+ regmap_write(priv->regmap, MT7530_VAWD1, 0);
+ regmap_write(priv->regmap, MT7530_VAWD2, 0);
}
}
@@ -2070,7 +2061,7 @@ static int mt753x_port_mirror_add(struct dsa_switch *ds, int port,
val |= MT753X_MIRROR_EN(priv->id);
val &= ~MT753X_MIRROR_PORT_MASK(priv->id);
val |= MT753X_MIRROR_PORT_SET(priv->id, mirror->to_local_port);
- mt7530_write(priv, MT753X_MIRROR_REG(priv->id), val);
+ regmap_write(priv->regmap, MT753X_MIRROR_REG(priv->id), val);
val = mt7530_read(priv, MT7530_PCR_P(port));
if (ingress) {
@@ -2080,7 +2071,7 @@ static int mt753x_port_mirror_add(struct dsa_switch *ds, int port,
val |= PORT_TX_MIR;
priv->mirror_tx |= BIT(port);
}
- mt7530_write(priv, MT7530_PCR_P(port), val);
+ regmap_write(priv->regmap, MT7530_PCR_P(port), val);
return 0;
}
@@ -2099,12 +2090,12 @@ static void mt753x_port_mirror_del(struct dsa_switch *ds, int port,
val &= ~PORT_TX_MIR;
priv->mirror_tx &= ~BIT(port);
}
- mt7530_write(priv, MT7530_PCR_P(port), val);
+ regmap_write(priv->regmap, MT7530_PCR_P(port), val);
if (!priv->mirror_rx && !priv->mirror_tx) {
val = mt7530_read(priv, MT753X_MIRROR_REG(priv->id));
val &= ~MT753X_MIRROR_EN(priv->id);
- mt7530_write(priv, MT753X_MIRROR_REG(priv->id), val);
+ regmap_write(priv->regmap, MT753X_MIRROR_REG(priv->id), val);
}
}
@@ -2202,9 +2193,9 @@ mt7530_setup_gpio(struct mt7530_priv *priv)
if (!gc)
return -ENOMEM;
- mt7530_write(priv, MT7530_LED_GPIO_OE, 0);
- mt7530_write(priv, MT7530_LED_GPIO_DIR, 0);
- mt7530_write(priv, MT7530_LED_IO_MODE, 0);
+ regmap_write(priv->regmap, MT7530_LED_GPIO_OE, 0);
+ regmap_write(priv->regmap, MT7530_LED_GPIO_DIR, 0);
+ regmap_write(priv->regmap, MT7530_LED_IO_MODE, 0);
gc->label = "mt7530";
gc->parent = dev;
@@ -2462,13 +2453,12 @@ mt7530_setup(struct dsa_switch *ds)
}
/* Reset the switch through internal reset */
- mt7530_write(priv, MT7530_SYS_CTRL,
- SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
- SYS_CTRL_REG_RST);
+ regmap_write(priv->regmap, MT7530_SYS_CTRL,
+ SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST | SYS_CTRL_REG_RST);
/* Lower Tx driving for TRGMII path */
for (i = 0; i < NUM_TRGMII_CTRL; i++)
- mt7530_write(priv, MT7530_TRGMII_TD_ODT(i),
+ regmap_write(priv->regmap, MT7530_TRGMII_TD_ODT(i),
TD_DM_DRVP(8) | TD_DM_DRVN(8));
for (i = 0; i < NUM_TRGMII_CTRL; i++)
@@ -2647,7 +2637,7 @@ mt7531_setup_common(struct dsa_switch *ds)
/* Enable Special Tag for rx frames */
if (priv->id == ID_EN7581 || priv->id == ID_AN7583)
- mt7530_write(priv, MT753X_CPORT_SPTAG_CFG,
+ regmap_write(priv->regmap, MT753X_CPORT_SPTAG_CFG,
CPORT_SW2FE_STAG_EN | CPORT_FE2SW_STAG_EN);
/* Flush the FDB table */
@@ -2705,10 +2695,12 @@ mt7531_setup(struct dsa_switch *ds)
/* Force link down on all ports before internal reset */
for (i = 0; i < priv->ds->num_ports; i++)
- mt7530_write(priv, MT753X_PMCR_P(i), MT7531_FORCE_MODE_LNK);
+ regmap_write(priv->regmap, MT753X_PMCR_P(i),
+ MT7531_FORCE_MODE_LNK);
/* Reset the switch through internal reset */
- mt7530_write(priv, MT7530_SYS_CTRL, SYS_CTRL_SW_RST | SYS_CTRL_REG_RST);
+ regmap_write(priv->regmap, MT7530_SYS_CTRL,
+ SYS_CTRL_SW_RST | SYS_CTRL_REG_RST);
if (!priv->p5_sgmii) {
mt7531_pll_setup(priv);
@@ -2917,7 +2909,7 @@ static void mt7531_rgmii_setup(struct mt7530_priv *priv,
}
}
- mt7530_write(priv, MT7531_CLKGEN_CTRL, val);
+ regmap_write(priv->regmap, MT7531_CLKGEN_CTRL, val);
}
static void
@@ -3254,7 +3246,7 @@ static int mt753x_tc_setup_qdisc_tbf(struct dsa_switch *ds, int port,
FIELD_PREP(ERLCR_EXP_MASK, tick) |
ERLCR_TBF_MODE_MASK |
FIELD_PREP(ERLCR_MANT_MASK, 0xf);
- mt7530_write(priv, MT753X_ERLCR_P(port), val);
+ regmap_write(priv->regmap, MT753X_ERLCR_P(port), val);
break;
}
default:
@@ -3296,7 +3288,7 @@ static int mt7988_setup(struct dsa_switch *ds)
FIELD_PREP(AN7583_CSR_ETHER_AFE_PWD, 0));
/* Reset the switch PHYs */
- mt7530_write(priv, MT7530_SYS_CTRL, SYS_CTRL_PHY_RST);
+ regmap_write(priv->regmap, MT7530_SYS_CTRL, SYS_CTRL_PHY_RST);
return mt7531_setup_common(ds);
}
--
2.55.0
^ permalink raw reply related
* [PATCH net-next v4 4/8] net: dsa: mt7530: replace mt7530_rmw/set/clear with regmap API
From: Daniel Golle @ 2026-07-19 17:53 UTC (permalink / raw)
To: Chester A. Unal, Daniel Golle, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Matthias Brugger, AngeloGioacchino Del Regno, Russell King,
netdev, linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <cover.1784481922.git.daniel@makrotopia.org>
Replace all mt7530_rmw() calls with regmap_update_bits(), mt7530_set()
with regmap_set_bits(), and mt7530_clear() with regmap_clear_bits().
Remove the wrapper function definitions.
Generated using the following semantic patch:
@@
expression priv, reg, mask, set;
@@
-mt7530_rmw(priv, reg, mask, set)
+regmap_update_bits(priv->regmap, reg, mask, set)
@@
expression priv, reg, val;
@@
-mt7530_set(priv, reg, val)
+regmap_set_bits(priv->regmap, reg, val)
@@
expression priv, reg, val;
@@
-mt7530_clear(priv, reg, val)
+regmap_clear_bits(priv->regmap, reg, val)
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/dsa/mt7530.c | 359 ++++++++++++++++++++-------------------
1 file changed, 182 insertions(+), 177 deletions(-)
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index ce4efcf1b3e6..fe7e4ab5ae9c 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -174,25 +174,6 @@ mt7530_mii_poll(struct mt7530_dummy_poll *p)
return mt7530_read(p->priv, p->reg);
}
-static void
-mt7530_rmw(struct mt7530_priv *priv, u32 reg,
- u32 mask, u32 set)
-{
- regmap_update_bits(priv->regmap, reg, mask, set);
-}
-
-static void
-mt7530_set(struct mt7530_priv *priv, u32 reg, u32 val)
-{
- mt7530_rmw(priv, reg, val, val);
-}
-
-static void
-mt7530_clear(struct mt7530_priv *priv, u32 reg, u32 val)
-{
- mt7530_rmw(priv, reg, val, 0);
-}
-
static int
mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp)
{
@@ -332,12 +313,13 @@ mt7530_setup_port6(struct dsa_switch *ds, phy_interface_t interface)
core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN);
if (interface == PHY_INTERFACE_MODE_RGMII) {
- mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK,
- P6_INTF_MODE(0));
+ regmap_update_bits(priv->regmap, MT7530_P6ECR,
+ P6_INTF_MODE_MASK, P6_INTF_MODE(0));
return;
}
- mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK, P6_INTF_MODE(1));
+ regmap_update_bits(priv->regmap, MT7530_P6ECR, P6_INTF_MODE_MASK,
+ P6_INTF_MODE(1));
xtal = mt7530_read(priv, MT753X_MTRAP) & MT7530_XTAL_MASK;
@@ -1258,35 +1240,35 @@ mt753x_trap_frames(struct mt7530_priv *priv)
* switch egress VLAN tag processing. This preserves VLAN tags
* for reception on VLAN sub-interfaces.
*/
- mt7530_rmw(priv, MT753X_BPC,
- PAE_BPDU_FR | PAE_EG_TAG_MASK | PAE_PORT_FW_MASK |
- BPDU_EG_TAG_MASK | BPDU_PORT_FW_MASK,
- PAE_BPDU_FR | PAE_EG_TAG(MT7530_VLAN_EG_DISABLED) |
- PAE_PORT_FW(TO_CPU_FW_CPU_ONLY) |
- BPDU_EG_TAG(MT7530_VLAN_EG_DISABLED) |
- TO_CPU_FW_CPU_ONLY);
+ regmap_update_bits(priv->regmap, MT753X_BPC,
+ PAE_BPDU_FR | PAE_EG_TAG_MASK | PAE_PORT_FW_MASK |
+ BPDU_EG_TAG_MASK | BPDU_PORT_FW_MASK,
+ PAE_BPDU_FR | PAE_EG_TAG(MT7530_VLAN_EG_DISABLED) |
+ PAE_PORT_FW(TO_CPU_FW_CPU_ONLY) |
+ BPDU_EG_TAG(MT7530_VLAN_EG_DISABLED) |
+ TO_CPU_FW_CPU_ONLY);
/* Trap frames with :01 and :02 MAC DAs to the CPU port(s) and
* egress them with EG_TAG disabled.
*/
- mt7530_rmw(priv, MT753X_RGAC1,
- R02_BPDU_FR | R02_EG_TAG_MASK | R02_PORT_FW_MASK |
- R01_BPDU_FR | R01_EG_TAG_MASK | R01_PORT_FW_MASK,
- R02_BPDU_FR | R02_EG_TAG(MT7530_VLAN_EG_DISABLED) |
- R02_PORT_FW(TO_CPU_FW_CPU_ONLY) | R01_BPDU_FR |
- R01_EG_TAG(MT7530_VLAN_EG_DISABLED) |
- TO_CPU_FW_CPU_ONLY);
+ regmap_update_bits(priv->regmap, MT753X_RGAC1,
+ R02_BPDU_FR | R02_EG_TAG_MASK | R02_PORT_FW_MASK |
+ R01_BPDU_FR | R01_EG_TAG_MASK | R01_PORT_FW_MASK,
+ R02_BPDU_FR | R02_EG_TAG(MT7530_VLAN_EG_DISABLED) |
+ R02_PORT_FW(TO_CPU_FW_CPU_ONLY) | R01_BPDU_FR |
+ R01_EG_TAG(MT7530_VLAN_EG_DISABLED) |
+ TO_CPU_FW_CPU_ONLY);
/* Trap frames with :03 and :0E MAC DAs to the CPU port(s) and
* egress them with EG_TAG disabled.
*/
- mt7530_rmw(priv, MT753X_RGAC2,
- R0E_BPDU_FR | R0E_EG_TAG_MASK | R0E_PORT_FW_MASK |
- R03_BPDU_FR | R03_EG_TAG_MASK | R03_PORT_FW_MASK,
- R0E_BPDU_FR | R0E_EG_TAG(MT7530_VLAN_EG_DISABLED) |
- R0E_PORT_FW(TO_CPU_FW_CPU_ONLY) | R03_BPDU_FR |
- R03_EG_TAG(MT7530_VLAN_EG_DISABLED) |
- TO_CPU_FW_CPU_ONLY);
+ regmap_update_bits(priv->regmap, MT753X_RGAC2,
+ R0E_BPDU_FR | R0E_EG_TAG_MASK | R0E_PORT_FW_MASK |
+ R03_BPDU_FR | R03_EG_TAG_MASK | R03_PORT_FW_MASK,
+ R0E_BPDU_FR | R0E_EG_TAG(MT7530_VLAN_EG_DISABLED) |
+ R0E_PORT_FW(TO_CPU_FW_CPU_ONLY) | R03_BPDU_FR |
+ R03_EG_TAG(MT7530_VLAN_EG_DISABLED) |
+ TO_CPU_FW_CPU_ONLY);
}
static void
@@ -1298,8 +1280,8 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port)
regmap_write(priv->regmap, MT7530_PVC_P(port), PORT_SPEC_TAG);
/* Enable flooding on the CPU port */
- mt7530_set(priv, MT753X_MFC, BC_FFP(BIT(port)) | UNM_FFP(BIT(port)) |
- UNU_FFP(BIT(port)));
+ regmap_set_bits(priv->regmap, MT753X_MFC,
+ BC_FFP(BIT(port)) | UNM_FFP(BIT(port)) | UNU_FFP(BIT(port)));
/* Add the CPU port to the CPU port bitmap for MT7531 and the switch on
* the MT7988 SoC. Trapped frames will be forwarded to the CPU port that
@@ -1307,7 +1289,8 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port)
*/
if (priv->id == ID_MT7531 || priv->id == ID_MT7988 ||
priv->id == ID_EN7581 || priv->id == ID_AN7583)
- mt7530_set(priv, MT7531_CFC, MT7531_CPU_PMAP(BIT(port)));
+ regmap_set_bits(priv->regmap, MT7531_CFC,
+ MT7531_CPU_PMAP(BIT(port)));
/* CPU port gets connected to all user ports of
* the switch.
@@ -1316,8 +1299,8 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port)
PCR_MATRIX(dsa_user_ports(priv->ds)));
/* Set to fallback mode for independent VLAN learning */
- mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
- MT7530_PORT_FALLBACK_MODE);
+ regmap_update_bits(priv->regmap, MT7530_PCR_P(port),
+ PCR_PORT_VLAN_MASK, MT7530_PORT_FALLBACK_MODE);
}
static int
@@ -1339,8 +1322,8 @@ mt7530_port_enable(struct dsa_switch *ds, int port,
priv->ports[port].pm |= PCR_MATRIX(BIT(cpu_dp->index));
}
priv->ports[port].enable = true;
- mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
- priv->ports[port].pm);
+ regmap_update_bits(priv->regmap, MT7530_PCR_P(port), PCR_MATRIX_MASK,
+ priv->ports[port].pm);
mutex_unlock(&priv->reg_mutex);
@@ -1348,9 +1331,9 @@ mt7530_port_enable(struct dsa_switch *ds, int port,
return 0;
if (port == 5)
- mt7530_clear(priv, MT753X_MTRAP, MT7530_P5_DIS);
+ regmap_clear_bits(priv->regmap, MT753X_MTRAP, MT7530_P5_DIS);
else if (port == 6)
- mt7530_clear(priv, MT753X_MTRAP, MT7530_P6_DIS);
+ regmap_clear_bits(priv->regmap, MT753X_MTRAP, MT7530_P6_DIS);
return 0;
}
@@ -1366,8 +1349,8 @@ mt7530_port_disable(struct dsa_switch *ds, int port)
* enablement for the port.
*/
priv->ports[port].enable = false;
- mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
- PCR_MATRIX_CLR);
+ regmap_update_bits(priv->regmap, MT7530_PCR_P(port), PCR_MATRIX_MASK,
+ PCR_MATRIX_CLR);
mutex_unlock(&priv->reg_mutex);
@@ -1376,9 +1359,9 @@ mt7530_port_disable(struct dsa_switch *ds, int port)
/* Do not set MT7530_P5_DIS when port 5 is being used for PHY muxing. */
if (port == 5 && priv->p5_mode == GMAC5)
- mt7530_set(priv, MT753X_MTRAP, MT7530_P5_DIS);
+ regmap_set_bits(priv->regmap, MT753X_MTRAP, MT7530_P5_DIS);
else if (port == 6)
- mt7530_set(priv, MT753X_MTRAP, MT7530_P6_DIS);
+ regmap_set_bits(priv->regmap, MT753X_MTRAP, MT7530_P6_DIS);
}
static int
@@ -1448,8 +1431,9 @@ mt7530_stp_state_set(struct dsa_switch *ds, int port, u8 state)
break;
}
- mt7530_rmw(priv, MT7530_SSP_P(port), FID_PST_MASK(FID_BRIDGED),
- FID_PST(FID_BRIDGED, stp_state));
+ regmap_update_bits(priv->regmap, MT7530_SSP_P(port),
+ FID_PST_MASK(FID_BRIDGED),
+ FID_PST(FID_BRIDGED, stp_state));
}
static void mt7530_update_port_member(struct mt7530_priv *priv, int port,
@@ -1488,8 +1472,9 @@ static void mt7530_update_port_member(struct mt7530_priv *priv, int port,
}
if (other_p->enable)
- mt7530_rmw(priv, MT7530_PCR_P(other_port),
- PCR_MATRIX_MASK, other_p->pm);
+ regmap_update_bits(priv->regmap,
+ MT7530_PCR_P(other_port),
+ PCR_MATRIX_MASK, other_p->pm);
}
/* Add/remove the all other ports to this port matrix. For !join
@@ -1498,7 +1483,8 @@ static void mt7530_update_port_member(struct mt7530_priv *priv, int port,
*/
p->pm = PCR_MATRIX(port_bitmap);
if (priv->ports[port].enable)
- mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, p->pm);
+ regmap_update_bits(priv->regmap, MT7530_PCR_P(port),
+ PCR_MATRIX_MASK, p->pm);
}
static int
@@ -1521,20 +1507,23 @@ mt7530_port_bridge_flags(struct dsa_switch *ds, int port,
struct mt7530_priv *priv = ds->priv;
if (flags.mask & BR_LEARNING)
- mt7530_rmw(priv, MT7530_PSC_P(port), SA_DIS,
- flags.val & BR_LEARNING ? 0 : SA_DIS);
+ regmap_update_bits(priv->regmap, MT7530_PSC_P(port), SA_DIS,
+ flags.val & BR_LEARNING ? 0 : SA_DIS);
if (flags.mask & BR_FLOOD)
- mt7530_rmw(priv, MT753X_MFC, UNU_FFP(BIT(port)),
- flags.val & BR_FLOOD ? UNU_FFP(BIT(port)) : 0);
+ regmap_update_bits(priv->regmap, MT753X_MFC,
+ UNU_FFP(BIT(port)),
+ flags.val & BR_FLOOD ? UNU_FFP(BIT(port)) : 0);
if (flags.mask & BR_MCAST_FLOOD)
- mt7530_rmw(priv, MT753X_MFC, UNM_FFP(BIT(port)),
- flags.val & BR_MCAST_FLOOD ? UNM_FFP(BIT(port)) : 0);
+ regmap_update_bits(priv->regmap, MT753X_MFC,
+ UNM_FFP(BIT(port)),
+ flags.val & BR_MCAST_FLOOD ? UNM_FFP(BIT(port)) : 0);
if (flags.mask & BR_BCAST_FLOOD)
- mt7530_rmw(priv, MT753X_MFC, BC_FFP(BIT(port)),
- flags.val & BR_BCAST_FLOOD ? BC_FFP(BIT(port)) : 0);
+ regmap_update_bits(priv->regmap, MT753X_MFC,
+ BC_FFP(BIT(port)),
+ flags.val & BR_BCAST_FLOOD ? BC_FFP(BIT(port)) : 0);
if (flags.mask & BR_ISOLATED) {
struct dsa_port *dp = dsa_to_port(ds, port);
@@ -1562,8 +1551,8 @@ mt7530_port_bridge_join(struct dsa_switch *ds, int port,
mt7530_update_port_member(priv, port, bridge.dev, true);
/* Set to fallback mode for independent VLAN learning */
- mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
- MT7530_PORT_FALLBACK_MODE);
+ regmap_update_bits(priv->regmap, MT7530_PCR_P(port),
+ PCR_PORT_VLAN_MASK, MT7530_PORT_FALLBACK_MODE);
mutex_unlock(&priv->reg_mutex);
@@ -1624,18 +1613,19 @@ mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port)
* bridge. Don't set standalone ports to fallback mode.
*/
if (dsa_port_bridge_dev_get(dsa_to_port(ds, port)))
- mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
- MT7530_PORT_FALLBACK_MODE);
-
- mt7530_rmw(priv, MT7530_PVC_P(port),
- VLAN_ATTR_MASK | PVC_EG_TAG_MASK | ACC_FRM_MASK,
- VLAN_ATTR(MT7530_VLAN_TRANSPARENT) |
- PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT) |
- MT7530_VLAN_ACC_ALL);
+ regmap_update_bits(priv->regmap, MT7530_PCR_P(port),
+ PCR_PORT_VLAN_MASK,
+ MT7530_PORT_FALLBACK_MODE);
+
+ regmap_update_bits(priv->regmap, MT7530_PVC_P(port),
+ VLAN_ATTR_MASK | PVC_EG_TAG_MASK | ACC_FRM_MASK,
+ VLAN_ATTR(MT7530_VLAN_TRANSPARENT) |
+ PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT) |
+ MT7530_VLAN_ACC_ALL);
/* Set PVID to 0 */
- mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK,
- G0_PORT_VID_DEF);
+ regmap_update_bits(priv->regmap, MT7530_PPBV1_P(port),
+ G0_PORT_VID_MASK, G0_PORT_VID_DEF);
for (i = 0; i < priv->ds->num_ports; i++) {
if (i == port)
@@ -1666,24 +1656,27 @@ mt7530_port_set_vlan_aware(struct dsa_switch *ds, int port)
* table lookup.
*/
if (dsa_is_user_port(ds, port)) {
- mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
- MT7530_PORT_SECURITY_MODE);
- mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK,
- G0_PORT_VID(priv->ports[port].pvid));
+ regmap_update_bits(priv->regmap, MT7530_PCR_P(port),
+ PCR_PORT_VLAN_MASK,
+ MT7530_PORT_SECURITY_MODE);
+ regmap_update_bits(priv->regmap, MT7530_PPBV1_P(port),
+ G0_PORT_VID_MASK,
+ G0_PORT_VID(priv->ports[port].pvid));
/* Only accept tagged frames if PVID is not set */
if (!priv->ports[port].pvid)
- mt7530_rmw(priv, MT7530_PVC_P(port), ACC_FRM_MASK,
- MT7530_VLAN_ACC_TAGGED);
+ regmap_update_bits(priv->regmap, MT7530_PVC_P(port),
+ ACC_FRM_MASK,
+ MT7530_VLAN_ACC_TAGGED);
/* Set the port as a user port which is to be able to recognize
* VID from incoming packets before fetching entry within the
* VLAN table.
*/
- mt7530_rmw(priv, MT7530_PVC_P(port),
- VLAN_ATTR_MASK | PVC_EG_TAG_MASK,
- VLAN_ATTR(MT7530_VLAN_USER) |
- PVC_EG_TAG(MT7530_VLAN_EG_DISABLED));
+ regmap_update_bits(priv->regmap, MT7530_PVC_P(port),
+ VLAN_ATTR_MASK | PVC_EG_TAG_MASK,
+ VLAN_ATTR(MT7530_VLAN_USER) |
+ PVC_EG_TAG(MT7530_VLAN_EG_DISABLED));
} else {
/* Also set CPU ports to the "user" VLAN port attribute, to
* allow VLAN classification, but keep the EG_TAG attribute as
@@ -1692,8 +1685,9 @@ mt7530_port_set_vlan_aware(struct dsa_switch *ds, int port)
* are forwarded to user ports as tagged, and untagged as
* untagged.
*/
- mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK,
- VLAN_ATTR(MT7530_VLAN_USER));
+ regmap_update_bits(priv->regmap, MT7530_PVC_P(port),
+ VLAN_ATTR_MASK,
+ VLAN_ATTR(MT7530_VLAN_USER));
}
}
@@ -1711,8 +1705,8 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
* back to the default as is at initial boot which is a VLAN-unaware
* port.
*/
- mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
- MT7530_PORT_MATRIX_MODE);
+ regmap_update_bits(priv->regmap, MT7530_PCR_P(port),
+ PCR_PORT_VLAN_MASK, MT7530_PORT_MATRIX_MODE);
mutex_unlock(&priv->reg_mutex);
}
@@ -1893,9 +1887,9 @@ mt7530_hw_vlan_add(struct mt7530_priv *priv,
val = MT7530_VLAN_EGRESS_UNTAG;
else
val = MT7530_VLAN_EGRESS_TAG;
- mt7530_rmw(priv, MT7530_VAWD2,
- ETAG_CTRL_P_MASK(entry->port),
- ETAG_CTRL_P(entry->port, val));
+ regmap_update_bits(priv->regmap, MT7530_VAWD2,
+ ETAG_CTRL_P_MASK(entry->port),
+ ETAG_CTRL_P(entry->port, val));
}
static void
@@ -1973,25 +1967,26 @@ mt7530_port_vlan_add(struct dsa_switch *ds, int port,
priv->ports[port].pvid = vlan->vid;
/* Accept all frames if PVID is set */
- mt7530_rmw(priv, MT7530_PVC_P(port), ACC_FRM_MASK,
- MT7530_VLAN_ACC_ALL);
+ regmap_update_bits(priv->regmap, MT7530_PVC_P(port),
+ ACC_FRM_MASK, MT7530_VLAN_ACC_ALL);
/* Only configure PVID if VLAN filtering is enabled */
if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port)))
- mt7530_rmw(priv, MT7530_PPBV1_P(port),
- G0_PORT_VID_MASK,
- G0_PORT_VID(vlan->vid));
+ regmap_update_bits(priv->regmap, MT7530_PPBV1_P(port),
+ G0_PORT_VID_MASK,
+ G0_PORT_VID(vlan->vid));
} else if (vlan->vid && priv->ports[port].pvid == vlan->vid) {
/* This VLAN is overwritten without PVID, so unset it */
priv->ports[port].pvid = G0_PORT_VID_DEF;
/* Only accept tagged frames if the port is VLAN-aware */
if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port)))
- mt7530_rmw(priv, MT7530_PVC_P(port), ACC_FRM_MASK,
- MT7530_VLAN_ACC_TAGGED);
+ regmap_update_bits(priv->regmap, MT7530_PVC_P(port),
+ ACC_FRM_MASK,
+ MT7530_VLAN_ACC_TAGGED);
- mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK,
- G0_PORT_VID_DEF);
+ regmap_update_bits(priv->regmap, MT7530_PPBV1_P(port),
+ G0_PORT_VID_MASK, G0_PORT_VID_DEF);
}
mutex_unlock(&priv->reg_mutex);
@@ -2025,11 +2020,12 @@ mt7530_port_vlan_del(struct dsa_switch *ds, int port,
/* Only accept tagged frames if the port is VLAN-aware */
if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port)))
- mt7530_rmw(priv, MT7530_PVC_P(port), ACC_FRM_MASK,
- MT7530_VLAN_ACC_TAGGED);
+ regmap_update_bits(priv->regmap, MT7530_PVC_P(port),
+ ACC_FRM_MASK,
+ MT7530_VLAN_ACC_TAGGED);
- mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK,
- G0_PORT_VID_DEF);
+ regmap_update_bits(priv->regmap, MT7530_PPBV1_P(port),
+ G0_PORT_VID_MASK, G0_PORT_VID_DEF);
}
@@ -2136,9 +2132,9 @@ mt7530_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
u32 bit = mt7530_gpio_to_bit(offset);
if (value)
- mt7530_set(priv, MT7530_LED_GPIO_DATA, bit);
+ regmap_set_bits(priv->regmap, MT7530_LED_GPIO_DATA, bit);
else
- mt7530_clear(priv, MT7530_LED_GPIO_DATA, bit);
+ regmap_clear_bits(priv->regmap, MT7530_LED_GPIO_DATA, bit);
return 0;
}
@@ -2159,8 +2155,8 @@ mt7530_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
struct mt7530_priv *priv = gpiochip_get_data(gc);
u32 bit = mt7530_gpio_to_bit(offset);
- mt7530_clear(priv, MT7530_LED_GPIO_OE, bit);
- mt7530_clear(priv, MT7530_LED_GPIO_DIR, bit);
+ regmap_clear_bits(priv->regmap, MT7530_LED_GPIO_OE, bit);
+ regmap_clear_bits(priv->regmap, MT7530_LED_GPIO_DIR, bit);
return 0;
}
@@ -2171,14 +2167,14 @@ mt7530_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int valu
struct mt7530_priv *priv = gpiochip_get_data(gc);
u32 bit = mt7530_gpio_to_bit(offset);
- mt7530_set(priv, MT7530_LED_GPIO_DIR, bit);
+ regmap_set_bits(priv->regmap, MT7530_LED_GPIO_DIR, bit);
if (value)
- mt7530_set(priv, MT7530_LED_GPIO_DATA, bit);
+ regmap_set_bits(priv->regmap, MT7530_LED_GPIO_DATA, bit);
else
- mt7530_clear(priv, MT7530_LED_GPIO_DATA, bit);
+ regmap_clear_bits(priv->regmap, MT7530_LED_GPIO_DATA, bit);
- mt7530_set(priv, MT7530_LED_GPIO_OE, bit);
+ regmap_set_bits(priv->regmap, MT7530_LED_GPIO_OE, bit);
return 0;
}
@@ -2284,7 +2280,8 @@ mt7530_setup_irq(struct mt7530_priv *priv)
/* This register must be set for MT7530 to properly fire interrupts */
if (priv->id == ID_MT7530 || priv->id == ID_MT7621)
- mt7530_set(priv, MT7530_TOP_SIG_CTRL, TOP_SIG_CTRL_NORMAL);
+ regmap_set_bits(priv->regmap, MT7530_TOP_SIG_CTRL,
+ TOP_SIG_CTRL_NORMAL);
ret = devm_regmap_add_irq_chip_fwnode(dev, dev_fwnode(dev),
priv->regmap, irq,
@@ -2462,14 +2459,15 @@ mt7530_setup(struct dsa_switch *ds)
TD_DM_DRVP(8) | TD_DM_DRVN(8));
for (i = 0; i < NUM_TRGMII_CTRL; i++)
- mt7530_rmw(priv, MT7530_TRGMII_RD(i),
- RD_TAP_MASK, RD_TAP(16));
+ regmap_update_bits(priv->regmap, MT7530_TRGMII_RD(i),
+ RD_TAP_MASK, RD_TAP(16));
/* Allow modifying the trap and directly access PHY registers via the
* MDIO bus the switch is on.
*/
- mt7530_rmw(priv, MT753X_MTRAP, MT7530_CHG_TRAP |
- MT7530_PHY_INDIRECT_ACCESS, MT7530_CHG_TRAP);
+ regmap_update_bits(priv->regmap, MT753X_MTRAP,
+ MT7530_CHG_TRAP | MT7530_PHY_INDIRECT_ACCESS,
+ MT7530_CHG_TRAP);
if ((val & MT7530_XTAL_MASK) == MT7530_XTAL_40MHZ)
mt7530_pll_setup(priv);
@@ -2483,17 +2481,16 @@ mt7530_setup(struct dsa_switch *ds)
/* Clear link settings and enable force mode to force link down
* on all ports until they're enabled later.
*/
- mt7530_rmw(priv, MT753X_PMCR_P(i),
- PMCR_LINK_SETTINGS_MASK |
- MT753X_FORCE_MODE(priv->id),
- MT753X_FORCE_MODE(priv->id));
+ regmap_update_bits(priv->regmap, MT753X_PMCR_P(i),
+ PMCR_LINK_SETTINGS_MASK | MT753X_FORCE_MODE(priv->id),
+ MT753X_FORCE_MODE(priv->id));
/* Disable forwarding by default on all ports */
- mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
- PCR_MATRIX_CLR);
+ regmap_update_bits(priv->regmap, MT7530_PCR_P(i),
+ PCR_MATRIX_MASK, PCR_MATRIX_CLR);
/* Disable learning by default on all ports */
- mt7530_set(priv, MT7530_PSC_P(i), SA_DIS);
+ regmap_set_bits(priv->regmap, MT7530_PSC_P(i), SA_DIS);
if (dsa_is_cpu_port(ds, i)) {
mt753x_cpu_port_enable(ds, i);
@@ -2501,16 +2498,17 @@ mt7530_setup(struct dsa_switch *ds)
mt7530_port_disable(ds, i);
/* Set default PVID to 0 on all user ports */
- mt7530_rmw(priv, MT7530_PPBV1_P(i), G0_PORT_VID_MASK,
- G0_PORT_VID_DEF);
+ regmap_update_bits(priv->regmap, MT7530_PPBV1_P(i),
+ G0_PORT_VID_MASK, G0_PORT_VID_DEF);
}
/* Enable consistent egress tag */
- mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,
- PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
+ regmap_update_bits(priv->regmap, MT7530_PVC_P(i),
+ PVC_EG_TAG_MASK,
+ PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
}
/* Allow mirroring frames received on the local port (monitor port). */
- mt7530_set(priv, MT753X_AGC, LOCAL_EN);
+ regmap_set_bits(priv->regmap, MT753X_AGC, LOCAL_EN);
/* Setup VLAN ID 0 for VLAN-unaware bridges */
ret = mt7530_setup_vlan0(priv);
@@ -2557,7 +2555,8 @@ mt7530_setup(struct dsa_switch *ds)
if (priv->p5_mode == MUX_PHY_P0 ||
priv->p5_mode == MUX_PHY_P4) {
- mt7530_clear(priv, MT753X_MTRAP, MT7530_P5_DIS);
+ regmap_clear_bits(priv->regmap, MT753X_MTRAP,
+ MT7530_P5_DIS);
mt7530_setup_port5(ds, interface);
}
}
@@ -2596,26 +2595,26 @@ mt7531_setup_common(struct dsa_switch *ds)
mt7530_mib_reset(ds);
/* Disable flooding on all ports */
- mt7530_clear(priv, MT753X_MFC, BC_FFP_MASK | UNM_FFP_MASK |
- UNU_FFP_MASK);
+ regmap_clear_bits(priv->regmap, MT753X_MFC,
+ BC_FFP_MASK | UNM_FFP_MASK | UNU_FFP_MASK);
for (i = 0; i < priv->ds->num_ports; i++) {
/* Clear link settings and enable force mode to force link down
* on all ports until they're enabled later.
*/
- mt7530_rmw(priv, MT753X_PMCR_P(i),
- PMCR_LINK_SETTINGS_MASK |
- MT753X_FORCE_MODE(priv->id),
- MT753X_FORCE_MODE(priv->id));
+ regmap_update_bits(priv->regmap, MT753X_PMCR_P(i),
+ PMCR_LINK_SETTINGS_MASK | MT753X_FORCE_MODE(priv->id),
+ MT753X_FORCE_MODE(priv->id));
/* Disable forwarding by default on all ports */
- mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
- PCR_MATRIX_CLR);
+ regmap_update_bits(priv->regmap, MT7530_PCR_P(i),
+ PCR_MATRIX_MASK, PCR_MATRIX_CLR);
/* Disable learning by default on all ports */
- mt7530_set(priv, MT7530_PSC_P(i), SA_DIS);
+ regmap_set_bits(priv->regmap, MT7530_PSC_P(i), SA_DIS);
- mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR);
+ regmap_set_bits(priv->regmap, MT7531_DBG_CNT(i),
+ MT7531_DIS_CLR);
if (dsa_is_cpu_port(ds, i)) {
mt753x_cpu_port_enable(ds, i);
@@ -2623,17 +2622,18 @@ mt7531_setup_common(struct dsa_switch *ds)
mt7530_port_disable(ds, i);
/* Set default PVID to 0 on all user ports */
- mt7530_rmw(priv, MT7530_PPBV1_P(i), G0_PORT_VID_MASK,
- G0_PORT_VID_DEF);
+ regmap_update_bits(priv->regmap, MT7530_PPBV1_P(i),
+ G0_PORT_VID_MASK, G0_PORT_VID_DEF);
}
/* Enable consistent egress tag */
- mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,
- PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
+ regmap_update_bits(priv->regmap, MT7530_PVC_P(i),
+ PVC_EG_TAG_MASK,
+ PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
}
/* Allow mirroring frames received on the local port (monitor port). */
- mt7530_set(priv, MT753X_AGC, LOCAL_EN);
+ regmap_set_bits(priv->regmap, MT753X_AGC, LOCAL_EN);
/* Enable Special Tag for rx frames */
if (priv->id == ID_EN7581 || priv->id == ID_AN7583)
@@ -2709,14 +2709,16 @@ mt7531_setup(struct dsa_switch *ds)
* MT7531AE. Set the GPIO 11-12 pins to function as MDC and MDIO
* to expose the MDIO bus of the switch.
*/
- mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO11_RG_RXD2_MASK,
- MT7531_EXT_P_MDC_11);
- mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO12_RG_RXD3_MASK,
- MT7531_EXT_P_MDIO_12);
+ regmap_update_bits(priv->regmap, MT7531_GPIO_MODE1,
+ MT7531_GPIO11_RG_RXD2_MASK,
+ MT7531_EXT_P_MDC_11);
+ regmap_update_bits(priv->regmap, MT7531_GPIO_MODE1,
+ MT7531_GPIO12_RG_RXD3_MASK,
+ MT7531_EXT_P_MDIO_12);
}
- mt7530_rmw(priv, MT7531_GPIO_MODE0, MT7531_GPIO0_MASK,
- MT7531_GPIO0_INTERRUPT);
+ regmap_update_bits(priv->regmap, MT7531_GPIO_MODE0, MT7531_GPIO0_MASK,
+ MT7531_GPIO0_INTERRUPT);
/* Enable Energy-Efficient Ethernet (EEE) and PHY core PLL, since
* phy_device has not yet been created provided for
@@ -2962,7 +2964,8 @@ mt753x_phylink_mac_config(struct phylink_config *config, unsigned int mode,
/* Are we connected to external phy */
if (port == 5 && dsa_is_user_port(ds, 5))
- mt7530_set(priv, MT753X_PMCR_P(port), PMCR_EXT_PHY);
+ regmap_set_bits(priv->regmap, MT753X_PMCR_P(port),
+ PMCR_EXT_PHY);
}
static void mt753x_phylink_mac_link_down(struct phylink_config *config,
@@ -2972,7 +2975,8 @@ static void mt753x_phylink_mac_link_down(struct phylink_config *config,
struct dsa_port *dp = dsa_phylink_to_port(config);
struct mt7530_priv *priv = dp->ds->priv;
- mt7530_clear(priv, MT753X_PMCR_P(dp->index), PMCR_LINK_SETTINGS_MASK);
+ regmap_clear_bits(priv->regmap, MT753X_PMCR_P(dp->index),
+ PMCR_LINK_SETTINGS_MASK);
}
static void mt753x_phylink_mac_link_up(struct phylink_config *config,
@@ -3006,7 +3010,7 @@ static void mt753x_phylink_mac_link_up(struct phylink_config *config,
mcr |= PMCR_FORCE_RX_FC_EN;
}
- mt7530_set(priv, MT753X_PMCR_P(dp->index), mcr);
+ regmap_set_bits(priv->regmap, MT753X_PMCR_P(dp->index), mcr);
}
static void mt753x_phylink_mac_disable_tx_lpi(struct phylink_config *config)
@@ -3014,8 +3018,8 @@ static void mt753x_phylink_mac_disable_tx_lpi(struct phylink_config *config)
struct dsa_port *dp = dsa_phylink_to_port(config);
struct mt7530_priv *priv = dp->ds->priv;
- mt7530_clear(priv, MT753X_PMCR_P(dp->index),
- PMCR_FORCE_EEE1G | PMCR_FORCE_EEE100);
+ regmap_clear_bits(priv->regmap, MT753X_PMCR_P(dp->index),
+ PMCR_FORCE_EEE1G | PMCR_FORCE_EEE100);
}
static int mt753x_phylink_mac_enable_tx_lpi(struct phylink_config *config,
@@ -3036,11 +3040,11 @@ static int mt753x_phylink_mac_enable_tx_lpi(struct phylink_config *config,
else
val = LPI_THRESH_MASK;
- mt7530_rmw(priv, MT753X_PMEEECR_P(dp->index),
- LPI_THRESH_MASK | LPI_MODE_EN, val);
+ regmap_update_bits(priv->regmap, MT753X_PMEEECR_P(dp->index),
+ LPI_THRESH_MASK | LPI_MODE_EN, val);
- mt7530_set(priv, MT753X_PMCR_P(dp->index),
- PMCR_FORCE_EEE1G | PMCR_FORCE_EEE100);
+ regmap_set_bits(priv->regmap, MT753X_PMCR_P(dp->index),
+ PMCR_FORCE_EEE1G | PMCR_FORCE_EEE100);
return 0;
}
@@ -3217,7 +3221,8 @@ mt753x_conduit_state_change(struct dsa_switch *ds,
MT7530_CPU_PORT(__ffs(priv->active_cpu_ports));
}
- mt7530_rmw(priv, MT753X_MFC, MT7530_CPU_EN | MT7530_CPU_PORT_MASK, val);
+ regmap_update_bits(priv->regmap, MT753X_MFC,
+ MT7530_CPU_EN | MT7530_CPU_PORT_MASK, val);
}
static int mt753x_tc_setup_qdisc_tbf(struct dsa_switch *ds, int port,
@@ -3234,8 +3239,8 @@ static int mt753x_tc_setup_qdisc_tbf(struct dsa_switch *ds, int port,
case TC_TBF_DESTROY: {
u32 val, tick;
- mt7530_rmw(priv, MT753X_GERLCR, EGR_BC_MASK,
- EGR_BC_CRC_IPG_PREAMBLE);
+ regmap_update_bits(priv->regmap, MT753X_GERLCR, EGR_BC_MASK,
+ EGR_BC_CRC_IPG_PREAMBLE);
/* if rate is greater than 10Mbps tick is 1/32 ms,
* 1ms otherwise
@@ -3279,13 +3284,13 @@ static int mt7988_setup(struct dsa_switch *ds)
/* AN7583 require additional tweak to CONN_CFG */
if (priv->id == ID_AN7583)
- mt7530_rmw(priv, AN7583_GEPHY_CONN_CFG,
- AN7583_CSR_DPHY_CKIN_SEL |
- AN7583_CSR_PHY_CORE_REG_CLK_SEL |
- AN7583_CSR_ETHER_AFE_PWD,
- AN7583_CSR_DPHY_CKIN_SEL |
- AN7583_CSR_PHY_CORE_REG_CLK_SEL |
- FIELD_PREP(AN7583_CSR_ETHER_AFE_PWD, 0));
+ regmap_update_bits(priv->regmap, AN7583_GEPHY_CONN_CFG,
+ AN7583_CSR_DPHY_CKIN_SEL |
+ AN7583_CSR_PHY_CORE_REG_CLK_SEL |
+ AN7583_CSR_ETHER_AFE_PWD,
+ AN7583_CSR_DPHY_CKIN_SEL |
+ AN7583_CSR_PHY_CORE_REG_CLK_SEL |
+ FIELD_PREP(AN7583_CSR_ETHER_AFE_PWD, 0));
/* Reset the switch PHYs */
regmap_write(priv->regmap, MT7530_SYS_CTRL, SYS_CTRL_PHY_RST);
--
2.55.0
^ permalink raw reply related
* [PATCH net-next v4 5/8] net: dsa: mt7530: replace mt7530_read with regmap_read
From: Daniel Golle @ 2026-07-19 17:53 UTC (permalink / raw)
To: Chester A. Unal, Daniel Golle, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Matthias Brugger, AngeloGioacchino Del Regno, Russell King,
netdev, linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <cover.1784481922.git.daniel@makrotopia.org>
Replace all mt7530_read() calls with direct regmap_read() calls and
remove the wrapper function. The wrapper returned 0 on failed reads;
preserve that behaviour by zeroing the read-back buffer at the start of
mt7530_regmap_read(), so callers that do not check the return code keep
seeing a deterministic value. The WARN_ON_ONCE error logging is dropped.
Most callsites follow the val = mt7530_read(priv, reg) pattern and are
converted mechanically using the following semantic patch:
@@
expression priv, reg;
identifier val;
@@
-val = mt7530_read(priv, reg);
+regmap_read(priv->regmap, reg, &val);
Remaining inline uses are converted by hand.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v4:
* zero the read-back buffer in mt7530_regmap_read() instead of
initializing the result variables at every call site
v3:
* init read-back variables to 0 to preserve the old read-failure
behaviour
* use u32 for val in mt7530_setup_port5
---
drivers/net/dsa/mt7530-mdio.c | 3 +
drivers/net/dsa/mt7530.c | 115 +++++++++++++++++-----------------
2 files changed, 60 insertions(+), 58 deletions(-)
diff --git a/drivers/net/dsa/mt7530-mdio.c b/drivers/net/dsa/mt7530-mdio.c
index f7c8eeb27211..b1178924eb06 100644
--- a/drivers/net/dsa/mt7530-mdio.c
+++ b/drivers/net/dsa/mt7530-mdio.c
@@ -48,6 +48,9 @@ mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
u16 page, r, lo, hi;
int ret;
+ /* Callers do not check for errors, keep the value deterministic */
+ *val = 0;
+
page = (reg >> 6) & 0x3ff;
r = (reg >> 2) & 0xf;
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index fe7e4ab5ae9c..26c7f3de4e1a 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -152,28 +152,15 @@ core_clear(struct mt7530_priv *priv, u32 reg, u32 val)
static u32
-mt7530_read(struct mt7530_priv *priv, u32 reg)
+mt7530_mii_poll(struct mt7530_dummy_poll *p)
{
- int ret;
u32 val;
- ret = regmap_read(priv->regmap, reg, &val);
- if (ret) {
- WARN_ON_ONCE(1);
- dev_err(priv->dev,
- "failed to read mt7530 register\n");
- return 0;
- }
+ regmap_read(p->priv->regmap, p->reg, &val);
return val;
}
-static u32
-mt7530_mii_poll(struct mt7530_dummy_poll *p)
-{
- return mt7530_read(p->priv, p->reg);
-}
-
static int
mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp)
{
@@ -196,7 +183,7 @@ mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp)
/* Additional sanity for read command if the specified
* entry is invalid
*/
- val = mt7530_read(priv, MT7530_ATC);
+ regmap_read(priv->regmap, MT7530_ATC, &val);
if ((cmd == MT7530_FDB_READ) && (val & ATC_INVALID))
return -EINVAL;
@@ -214,7 +201,8 @@ mt7530_fdb_read(struct mt7530_priv *priv, struct mt7530_fdb *fdb)
/* Read from ARL table into an array */
for (i = 0; i < 3; i++) {
- reg[i] = mt7530_read(priv, MT7530_TSRA1 + (i * 4));
+ regmap_read(priv->regmap, MT7530_TSRA1 + (i * 4),
+ ®[i]);
dev_dbg(priv->dev, "%s(%d) reg[%d]=0x%x\n",
__func__, __LINE__, i, reg[i]);
@@ -321,7 +309,8 @@ mt7530_setup_port6(struct dsa_switch *ds, phy_interface_t interface)
regmap_update_bits(priv->regmap, MT7530_P6ECR, P6_INTF_MODE_MASK,
P6_INTF_MODE(1));
- xtal = mt7530_read(priv, MT753X_MTRAP) & MT7530_XTAL_MASK;
+ regmap_read(priv->regmap, MT753X_MTRAP, &xtal);
+ xtal &= MT7530_XTAL_MASK;
if (xtal == MT7530_XTAL_25MHZ)
ssc_delta = 0x57;
@@ -365,9 +354,9 @@ mt7531_pll_setup(struct mt7530_priv *priv)
u32 hwstrap;
u32 val;
- val = mt7530_read(priv, MT7531_CREV);
- top_sig = mt7530_read(priv, MT7531_TOP_SIG_SR);
- hwstrap = mt7530_read(priv, MT753X_TRAP);
+ regmap_read(priv->regmap, MT7531_CREV, &val);
+ regmap_read(priv->regmap, MT7531_TOP_SIG_SR, &top_sig);
+ regmap_read(priv->regmap, MT753X_TRAP, &hwstrap);
if ((val & CHIP_REV_M) > 0)
xtal = (top_sig & PAD_MCM_SMI_EN) ? MT7531_XTAL_FSEL_40MHZ :
MT7531_XTAL_FSEL_25MHZ;
@@ -376,26 +365,26 @@ mt7531_pll_setup(struct mt7530_priv *priv)
MT7531_XTAL_FSEL_40MHZ;
/* Step 1 : Disable MT7531 COREPLL */
- val = mt7530_read(priv, MT7531_PLLGP_EN);
+ regmap_read(priv->regmap, MT7531_PLLGP_EN, &val);
val &= ~EN_COREPLL;
regmap_write(priv->regmap, MT7531_PLLGP_EN, val);
/* Step 2: switch to XTAL output */
- val = mt7530_read(priv, MT7531_PLLGP_EN);
+ regmap_read(priv->regmap, MT7531_PLLGP_EN, &val);
val |= SW_CLKSW;
regmap_write(priv->regmap, MT7531_PLLGP_EN, val);
- val = mt7530_read(priv, MT7531_PLLGP_CR0);
+ regmap_read(priv->regmap, MT7531_PLLGP_CR0, &val);
val &= ~RG_COREPLL_EN;
regmap_write(priv->regmap, MT7531_PLLGP_CR0, val);
/* Step 3: disable PLLGP and enable program PLLGP */
- val = mt7530_read(priv, MT7531_PLLGP_EN);
+ regmap_read(priv->regmap, MT7531_PLLGP_EN, &val);
val |= SW_PLLGP;
regmap_write(priv->regmap, MT7531_PLLGP_EN, val);
/* Step 4: program COREPLL output frequency to 500MHz */
- val = mt7530_read(priv, MT7531_PLLGP_CR0);
+ regmap_read(priv->regmap, MT7531_PLLGP_CR0, &val);
val &= ~RG_COREPLL_POSDIV_M;
val |= 2 << RG_COREPLL_POSDIV_S;
regmap_write(priv->regmap, MT7531_PLLGP_CR0, val);
@@ -403,13 +392,13 @@ mt7531_pll_setup(struct mt7530_priv *priv)
switch (xtal) {
case MT7531_XTAL_FSEL_25MHZ:
- val = mt7530_read(priv, MT7531_PLLGP_CR0);
+ regmap_read(priv->regmap, MT7531_PLLGP_CR0, &val);
val &= ~RG_COREPLL_SDM_PCW_M;
val |= 0x140000 << RG_COREPLL_SDM_PCW_S;
regmap_write(priv->regmap, MT7531_PLLGP_CR0, val);
break;
case MT7531_XTAL_FSEL_40MHZ:
- val = mt7530_read(priv, MT7531_PLLGP_CR0);
+ regmap_read(priv->regmap, MT7531_PLLGP_CR0, &val);
val &= ~RG_COREPLL_SDM_PCW_M;
val |= 0x190000 << RG_COREPLL_SDM_PCW_S;
regmap_write(priv->regmap, MT7531_PLLGP_CR0, val);
@@ -417,14 +406,14 @@ mt7531_pll_setup(struct mt7530_priv *priv)
}
/* Set feedback divide ratio update signal to high */
- val = mt7530_read(priv, MT7531_PLLGP_CR0);
+ regmap_read(priv->regmap, MT7531_PLLGP_CR0, &val);
val |= RG_COREPLL_SDM_PCW_CHG;
regmap_write(priv->regmap, MT7531_PLLGP_CR0, val);
/* Wait for at least 16 XTAL clocks */
usleep_range(10, 20);
/* Step 5: set feedback divide ratio update signal to low */
- val = mt7530_read(priv, MT7531_PLLGP_CR0);
+ regmap_read(priv->regmap, MT7531_PLLGP_CR0, &val);
val &= ~RG_COREPLL_SDM_PCW_CHG;
regmap_write(priv->regmap, MT7531_PLLGP_CR0, val);
@@ -435,11 +424,11 @@ mt7531_pll_setup(struct mt7530_priv *priv)
regmap_write(priv->regmap, MT7531_ANA_PLLGP_CR2, 0x4f40000);
/* Step 6: Enable MT7531 PLL */
- val = mt7530_read(priv, MT7531_PLLGP_CR0);
+ regmap_read(priv->regmap, MT7531_PLLGP_CR0, &val);
val |= RG_COREPLL_EN;
regmap_write(priv->regmap, MT7531_PLLGP_CR0, val);
- val = mt7530_read(priv, MT7531_PLLGP_EN);
+ regmap_read(priv->regmap, MT7531_PLLGP_EN, &val);
val |= EN_COREPLL;
regmap_write(priv->regmap, MT7531_PLLGP_EN, val);
usleep_range(25, 35);
@@ -698,11 +687,11 @@ mt7530_read_port_stats(struct mt7530_priv *priv, int port,
{
u32 val, reg = MT7530_PORT_MIB_COUNTER(port) + offset;
- val = mt7530_read(priv, reg);
+ regmap_read(priv->regmap, reg, &val);
*data = val;
if (size == 2) {
- val = mt7530_read(priv, reg + 4);
+ regmap_read(priv->regmap, reg + 4, &val);
*data |= (u64)val << 32;
}
}
@@ -1006,11 +995,11 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface)
{
struct mt7530_priv *priv = ds->priv;
u8 tx_delay = 0;
- int val;
+ u32 val;
mutex_lock(&priv->reg_mutex);
- val = mt7530_read(priv, MT753X_MTRAP);
+ regmap_read(priv->regmap, MT753X_MTRAP, &val);
val &= ~MT7530_P5_PHY0_SEL & ~MT7530_P5_MAC_SEL & ~MT7530_P5_RGMII_MODE;
@@ -1378,7 +1367,7 @@ mt7530_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
if (!dsa_is_cpu_port(ds, port))
return 0;
- val = mt7530_read(priv, MT7530_GMACCR);
+ regmap_read(priv->regmap, MT7530_GMACCR, &val);
val &= ~MAX_RX_PKT_LEN_MASK;
/* RX length also includes Ethernet header, MTK tag, and FCS length */
@@ -1577,7 +1566,7 @@ mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid)
return ret;
}
- val = mt7530_read(priv, MT7530_VTCR);
+ regmap_read(priv->regmap, MT7530_VTCR, &val);
if (val & VTCR_INVALID) {
dev_err(priv->dev, "read VTCR invalid\n");
return -EINVAL;
@@ -1789,14 +1778,16 @@ mt7530_port_mdb_add(struct dsa_switch *ds, int port,
const u8 *addr = mdb->addr;
u16 vid = mdb->vid;
u8 port_mask = 0;
+ u32 val;
int ret;
mutex_lock(&priv->reg_mutex);
mt7530_fdb_write(priv, vid, 0, addr, 0, STATIC_EMP);
- if (!mt7530_fdb_cmd(priv, MT7530_FDB_READ, NULL))
- port_mask = (mt7530_read(priv, MT7530_ATRD) >> PORT_MAP)
- & PORT_MAP_MASK;
+ if (!mt7530_fdb_cmd(priv, MT7530_FDB_READ, NULL)) {
+ regmap_read(priv->regmap, MT7530_ATRD, &val);
+ port_mask = (val >> PORT_MAP) & PORT_MAP_MASK;
+ }
port_mask |= BIT(port);
mt7530_fdb_write(priv, vid, port_mask, addr, -1, STATIC_ENT);
@@ -1816,14 +1807,16 @@ mt7530_port_mdb_del(struct dsa_switch *ds, int port,
const u8 *addr = mdb->addr;
u16 vid = mdb->vid;
u8 port_mask = 0;
+ u32 val;
int ret;
mutex_lock(&priv->reg_mutex);
mt7530_fdb_write(priv, vid, 0, addr, 0, STATIC_EMP);
- if (!mt7530_fdb_cmd(priv, MT7530_FDB_READ, NULL))
- port_mask = (mt7530_read(priv, MT7530_ATRD) >> PORT_MAP)
- & PORT_MAP_MASK;
+ if (!mt7530_fdb_cmd(priv, MT7530_FDB_READ, NULL)) {
+ regmap_read(priv->regmap, MT7530_ATRD, &val);
+ port_mask = (val >> PORT_MAP) & PORT_MAP_MASK;
+ }
port_mask &= ~BIT(port);
mt7530_fdb_write(priv, vid, port_mask, addr, -1,
@@ -1901,7 +1894,7 @@ mt7530_hw_vlan_del(struct mt7530_priv *priv,
new_members = entry->old_members & ~BIT(entry->port);
- val = mt7530_read(priv, MT7530_VAWD1);
+ regmap_read(priv->regmap, MT7530_VAWD1, &val);
if (!(val & VLAN_VALID)) {
dev_err(priv->dev,
"Cannot be deleted due to invalid entry\n");
@@ -1928,7 +1921,7 @@ mt7530_hw_vlan_update(struct mt7530_priv *priv, u16 vid,
/* Fetch entry */
mt7530_vlan_cmd(priv, MT7530_VTCR_RD_VID, vid);
- val = mt7530_read(priv, MT7530_VAWD1);
+ regmap_read(priv->regmap, MT7530_VAWD1, &val);
entry->old_members = (val >> PORT_MEM_SHFT) & PORT_MEM_MASK;
@@ -2046,7 +2039,7 @@ static int mt753x_port_mirror_add(struct dsa_switch *ds, int port,
if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port))
return -EEXIST;
- val = mt7530_read(priv, MT753X_MIRROR_REG(priv->id));
+ regmap_read(priv->regmap, MT753X_MIRROR_REG(priv->id), &val);
/* MT7530 only supports one monitor port */
monitor_port = MT753X_MIRROR_PORT_GET(priv->id, val);
@@ -2059,7 +2052,7 @@ static int mt753x_port_mirror_add(struct dsa_switch *ds, int port,
val |= MT753X_MIRROR_PORT_SET(priv->id, mirror->to_local_port);
regmap_write(priv->regmap, MT753X_MIRROR_REG(priv->id), val);
- val = mt7530_read(priv, MT7530_PCR_P(port));
+ regmap_read(priv->regmap, MT7530_PCR_P(port), &val);
if (ingress) {
val |= PORT_RX_MIR;
priv->mirror_rx |= BIT(port);
@@ -2078,7 +2071,7 @@ static void mt753x_port_mirror_del(struct dsa_switch *ds, int port,
struct mt7530_priv *priv = ds->priv;
u32 val;
- val = mt7530_read(priv, MT7530_PCR_P(port));
+ regmap_read(priv->regmap, MT7530_PCR_P(port), &val);
if (mirror->ingress) {
val &= ~PORT_RX_MIR;
priv->mirror_rx &= ~BIT(port);
@@ -2089,7 +2082,7 @@ static void mt753x_port_mirror_del(struct dsa_switch *ds, int port,
regmap_write(priv->regmap, MT7530_PCR_P(port), val);
if (!priv->mirror_rx && !priv->mirror_tx) {
- val = mt7530_read(priv, MT753X_MIRROR_REG(priv->id));
+ regmap_read(priv->regmap, MT753X_MIRROR_REG(priv->id), &val);
val &= ~MT753X_MIRROR_EN(priv->id);
regmap_write(priv->regmap, MT753X_MIRROR_REG(priv->id), val);
}
@@ -2121,8 +2114,11 @@ mt7530_gpio_get(struct gpio_chip *gc, unsigned int offset)
{
struct mt7530_priv *priv = gpiochip_get_data(gc);
u32 bit = mt7530_gpio_to_bit(offset);
+ u32 val;
+
+ regmap_read(priv->regmap, MT7530_LED_GPIO_DATA, &val);
- return !!(mt7530_read(priv, MT7530_LED_GPIO_DATA) & bit);
+ return !!(val & bit);
}
static int
@@ -2144,8 +2140,11 @@ mt7530_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
{
struct mt7530_priv *priv = gpiochip_get_data(gc);
u32 bit = mt7530_gpio_to_bit(offset);
+ u32 val;
+
+ regmap_read(priv->regmap, MT7530_LED_GPIO_DIR, &val);
- return (mt7530_read(priv, MT7530_LED_GPIO_DIR) & bit) ?
+ return (val & bit) ?
GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
}
@@ -2436,7 +2435,7 @@ mt7530_setup(struct dsa_switch *ds)
return ret;
}
- id = mt7530_read(priv, MT7530_CREV);
+ regmap_read(priv->regmap, MT7530_CREV, &id);
id >>= CHIP_NAME_SHIFT;
if (id != MT7530_ID) {
dev_err(priv->dev, "chip %x can't be supported\n", id);
@@ -2679,7 +2678,7 @@ mt7531_setup(struct dsa_switch *ds)
return ret;
}
- id = mt7530_read(priv, MT7531_CREV);
+ regmap_read(priv->regmap, MT7531_CREV, &id);
id >>= CHIP_NAME_SHIFT;
if (id != MT7531_ID) {
@@ -2690,7 +2689,7 @@ mt7531_setup(struct dsa_switch *ds)
/* MT7531AE has got two SGMII units. One for port 5, one for port 6.
* MT7531BE has got only one SGMII unit which is for port 6.
*/
- val = mt7530_read(priv, MT7531_TOP_SIG_SR);
+ regmap_read(priv->regmap, MT7531_TOP_SIG_SR, &val);
priv->p5_sgmii = !!(val & PAD_DUAL_SGMII_EN);
/* Force link down on all ports before internal reset */
@@ -2880,7 +2879,7 @@ static void mt7531_rgmii_setup(struct mt7530_priv *priv,
{
u32 val;
- val = mt7530_read(priv, MT7531_CLKGEN_CTRL);
+ regmap_read(priv->regmap, MT7531_CLKGEN_CTRL, &val);
val |= GP_CLK_EN;
val &= ~GP_MODE_MASK;
val |= GP_MODE(MT7531_GP_MODE_RGMII);
@@ -3059,7 +3058,7 @@ static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port,
config->lpi_capabilities = MAC_100FD | MAC_1000FD | MAC_2500FD;
- eeecr = mt7530_read(priv, MT753X_PMEEECR_P(port));
+ regmap_read(priv->regmap, MT753X_PMEEECR_P(port), &eeecr);
/* tx_lpi_timer should be in microseconds. The time units for
* LPI threshold are unspecified.
*/
@@ -3087,7 +3086,7 @@ static void mt7530_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
int port = pcs_to_mt753x_pcs(pcs)->port;
u32 pmsr;
- pmsr = mt7530_read(priv, MT7530_PMSR_P(port));
+ regmap_read(priv->regmap, MT7530_PMSR_P(port), &pmsr);
state->link = (pmsr & PMSR_LINK);
state->an_complete = state->link;
--
2.55.0
^ permalink raw reply related
* [PATCH net-next v4 6/8] net: dsa: mt7530: convert to use field accessor macros
From: Daniel Golle @ 2026-07-19 17:54 UTC (permalink / raw)
To: Chester A. Unal, Daniel Golle, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Matthias Brugger, AngeloGioacchino Del Regno, Russell King,
netdev, linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <cover.1784481922.git.daniel@makrotopia.org>
Use FIELD_GET and FIELD_PREP instead of open-coding register fields.
Replace 0x1f constant with (PHY_MAX_ADDR - 1).
Some field macros (ATC_HASH and VTCR_VID) were previously defined as
object-like macros referencing an undeclared 'x' and were therefore
unusable; convert them into proper FIELD_PREP() accessors. The masks are
equivalent to the open-coded values they replace, so there is no
functional change.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v3:
* name the age timer field AGE_TIMER_MASK instead of AGE_TIMER_RD_MASK
* note the corrected ATC_HASH/VTCR_VID macros in the commit message
---
drivers/net/dsa/mt7530.c | 64 ++++++------
drivers/net/dsa/mt7530.h | 208 ++++++++++++++++++++++-----------------
2 files changed, 148 insertions(+), 124 deletions(-)
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 26c7f3de4e1a..f7643b86f3c4 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -208,16 +208,16 @@ mt7530_fdb_read(struct mt7530_priv *priv, struct mt7530_fdb *fdb)
__func__, __LINE__, i, reg[i]);
}
- fdb->vid = (reg[1] >> CVID) & CVID_MASK;
- fdb->aging = (reg[2] >> AGE_TIMER) & AGE_TIMER_MASK;
- fdb->port_mask = (reg[2] >> PORT_MAP) & PORT_MAP_MASK;
- fdb->mac[0] = (reg[0] >> MAC_BYTE_0) & MAC_BYTE_MASK;
- fdb->mac[1] = (reg[0] >> MAC_BYTE_1) & MAC_BYTE_MASK;
- fdb->mac[2] = (reg[0] >> MAC_BYTE_2) & MAC_BYTE_MASK;
- fdb->mac[3] = (reg[0] >> MAC_BYTE_3) & MAC_BYTE_MASK;
- fdb->mac[4] = (reg[1] >> MAC_BYTE_4) & MAC_BYTE_MASK;
- fdb->mac[5] = (reg[1] >> MAC_BYTE_5) & MAC_BYTE_MASK;
- fdb->noarp = ((reg[2] >> ENT_STATUS) & ENT_STATUS_MASK) == STATIC_ENT;
+ fdb->vid = FIELD_GET(CVID_MASK, reg[1]);
+ fdb->aging = FIELD_GET(AGE_TIMER_MASK, reg[2]);
+ fdb->port_mask = FIELD_GET(PORT_MAP_MASK, reg[2]);
+ fdb->mac[0] = FIELD_GET(MAC_BYTE_0_MASK, reg[0]);
+ fdb->mac[1] = FIELD_GET(MAC_BYTE_1_MASK, reg[0]);
+ fdb->mac[2] = FIELD_GET(MAC_BYTE_2_MASK, reg[0]);
+ fdb->mac[3] = FIELD_GET(MAC_BYTE_3_MASK, reg[0]);
+ fdb->mac[4] = FIELD_GET(MAC_BYTE_4_MASK, reg[1]);
+ fdb->mac[5] = FIELD_GET(MAC_BYTE_5_MASK, reg[1]);
+ fdb->noarp = FIELD_GET(ENT_STATUS_MASK, reg[2]) == STATIC_ENT;
}
static void
@@ -228,22 +228,22 @@ mt7530_fdb_write(struct mt7530_priv *priv, u16 vid,
u32 reg[3] = { 0 };
int i;
- reg[1] |= vid & CVID_MASK;
+ reg[1] |= FIELD_PREP(CVID_MASK, vid);
reg[1] |= ATA2_IVL;
reg[1] |= ATA2_FID(FID_BRIDGED);
- reg[2] |= (aging & AGE_TIMER_MASK) << AGE_TIMER;
- reg[2] |= (port_mask & PORT_MAP_MASK) << PORT_MAP;
+ reg[2] |= FIELD_PREP(AGE_TIMER_MASK, aging);
+ reg[2] |= FIELD_PREP(PORT_MAP_MASK, port_mask);
/* STATIC_ENT indicate that entry is static wouldn't
* be aged out and STATIC_EMP specified as erasing an
* entry
*/
- reg[2] |= (type & ENT_STATUS_MASK) << ENT_STATUS;
- reg[1] |= mac[5] << MAC_BYTE_5;
- reg[1] |= mac[4] << MAC_BYTE_4;
- reg[0] |= mac[3] << MAC_BYTE_3;
- reg[0] |= mac[2] << MAC_BYTE_2;
- reg[0] |= mac[1] << MAC_BYTE_1;
- reg[0] |= mac[0] << MAC_BYTE_0;
+ reg[2] |= FIELD_PREP(ENT_STATUS_MASK, type);
+ reg[1] |= FIELD_PREP(MAC_BYTE_5_MASK, mac[5]);
+ reg[1] |= FIELD_PREP(MAC_BYTE_4_MASK, mac[4]);
+ reg[0] |= FIELD_PREP(MAC_BYTE_3_MASK, mac[3]);
+ reg[0] |= FIELD_PREP(MAC_BYTE_2_MASK, mac[2]);
+ reg[0] |= FIELD_PREP(MAC_BYTE_1_MASK, mac[1]);
+ reg[0] |= FIELD_PREP(MAC_BYTE_0_MASK, mac[0]);
/* Write array into the ARL table */
for (i = 0; i < 3; i++)
@@ -385,22 +385,22 @@ mt7531_pll_setup(struct mt7530_priv *priv)
/* Step 4: program COREPLL output frequency to 500MHz */
regmap_read(priv->regmap, MT7531_PLLGP_CR0, &val);
- val &= ~RG_COREPLL_POSDIV_M;
- val |= 2 << RG_COREPLL_POSDIV_S;
+ val &= ~RG_COREPLL_POSDIV_MASK;
+ val |= RG_COREPLL_POSDIV(2);
regmap_write(priv->regmap, MT7531_PLLGP_CR0, val);
usleep_range(25, 35);
switch (xtal) {
case MT7531_XTAL_FSEL_25MHZ:
regmap_read(priv->regmap, MT7531_PLLGP_CR0, &val);
- val &= ~RG_COREPLL_SDM_PCW_M;
- val |= 0x140000 << RG_COREPLL_SDM_PCW_S;
+ val &= ~RG_COREPLL_SDM_PCW_MASK;
+ val |= RG_COREPLL_SDM_PCW(0x140000);
regmap_write(priv->regmap, MT7531_PLLGP_CR0, val);
break;
case MT7531_XTAL_FSEL_40MHZ:
regmap_read(priv->regmap, MT7531_PLLGP_CR0, &val);
- val &= ~RG_COREPLL_SDM_PCW_M;
- val |= 0x190000 << RG_COREPLL_SDM_PCW_S;
+ val &= ~RG_COREPLL_SDM_PCW_MASK;
+ val |= RG_COREPLL_SDM_PCW(0x190000);
regmap_write(priv->regmap, MT7531_PLLGP_CR0, val);
break;
}
@@ -1555,7 +1555,7 @@ mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid)
u32 val;
int ret;
- val = VTCR_BUSY | VTCR_FUNC(cmd) | vid;
+ val = VTCR_BUSY | VTCR_FUNC(cmd) | VTCR_VID(vid);
regmap_write(priv->regmap, MT7530_VTCR, val);
INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_VTCR);
@@ -1786,7 +1786,7 @@ mt7530_port_mdb_add(struct dsa_switch *ds, int port,
mt7530_fdb_write(priv, vid, 0, addr, 0, STATIC_EMP);
if (!mt7530_fdb_cmd(priv, MT7530_FDB_READ, NULL)) {
regmap_read(priv->regmap, MT7530_ATRD, &val);
- port_mask = (val >> PORT_MAP) & PORT_MAP_MASK;
+ port_mask = FIELD_GET(PORT_MAP_MASK, val);
}
port_mask |= BIT(port);
@@ -1815,7 +1815,7 @@ mt7530_port_mdb_del(struct dsa_switch *ds, int port,
mt7530_fdb_write(priv, vid, 0, addr, 0, STATIC_EMP);
if (!mt7530_fdb_cmd(priv, MT7530_FDB_READ, NULL)) {
regmap_read(priv->regmap, MT7530_ATRD, &val);
- port_mask = (val >> PORT_MAP) & PORT_MAP_MASK;
+ port_mask = FIELD_GET(PORT_MAP_MASK, val);
}
port_mask &= ~BIT(port);
@@ -1923,7 +1923,7 @@ mt7530_hw_vlan_update(struct mt7530_priv *priv, u16 vid,
regmap_read(priv->regmap, MT7530_VAWD1, &val);
- entry->old_members = (val >> PORT_MEM_SHFT) & PORT_MEM_MASK;
+ entry->old_members = FIELD_GET(PORT_MEM_MASK, val);
/* Manipulate entry */
vlan_op(priv, entry);
@@ -2436,7 +2436,7 @@ mt7530_setup(struct dsa_switch *ds)
}
regmap_read(priv->regmap, MT7530_CREV, &id);
- id >>= CHIP_NAME_SHIFT;
+ id = FIELD_GET(CHIP_NAME_MASK, id);
if (id != MT7530_ID) {
dev_err(priv->dev, "chip %x can't be supported\n", id);
return -ENODEV;
@@ -2679,7 +2679,7 @@ mt7531_setup(struct dsa_switch *ds)
}
regmap_read(priv->regmap, MT7531_CREV, &id);
- id >>= CHIP_NAME_SHIFT;
+ id = FIELD_GET(CHIP_NAME_MASK, id);
if (id != MT7531_ID) {
dev_err(priv->dev, "chip %x can't be supported\n", id);
diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h
index dd33b0df3419..804c2e0991a0 100644
--- a/drivers/net/dsa/mt7530.h
+++ b/drivers/net/dsa/mt7530.h
@@ -6,6 +6,8 @@
#ifndef __MT7530_H
#define __MT7530_H
+#include <linux/bitfield.h>
+
#define MT7530_NUM_PORTS 7
#define MT7530_NUM_PHYS 5
#define MT7530_NUM_FDB_RECORDS 2048
@@ -146,19 +148,22 @@ enum mt753x_to_cpu_fw {
#define STATIC_ENT 3
#define MT7530_ATA2 0x78
#define ATA2_IVL BIT(15)
-#define ATA2_FID(x) (((x) & 0x7) << 12)
+#define ATA2_FID_MASK GENMASK(14, 12)
+#define ATA2_FID(x) FIELD_PREP(ATA2_FID_MASK, x)
/* Register for address table write data */
#define MT7530_ATWD 0x7c
/* Register for address table control */
#define MT7530_ATC 0x80
-#define ATC_HASH (((x) & 0xfff) << 16)
+#define ATC_HASH_MASK GENMASK(27, 16)
+#define ATC_HASH(x) FIELD_PREP(ATC_HASH_MASK, x)
#define ATC_BUSY BIT(15)
#define ATC_SRCH_END BIT(14)
#define ATC_SRCH_HIT BIT(13)
#define ATC_INVALID BIT(12)
-#define ATC_MAT(x) (((x) & 0xf) << 8)
+#define ATC_MAT_MASK GENMASK(11, 8)
+#define ATC_MAT(x) FIELD_PREP(ATC_MAT_MASK, x)
#define ATC_MAT_MACTAB ATC_MAT(0)
enum mt7530_fdb_cmd {
@@ -171,32 +176,29 @@ enum mt7530_fdb_cmd {
/* Registers for table search read address */
#define MT7530_TSRA1 0x84
-#define MAC_BYTE_0 24
-#define MAC_BYTE_1 16
-#define MAC_BYTE_2 8
-#define MAC_BYTE_3 0
-#define MAC_BYTE_MASK 0xff
+#define MAC_BYTE_0_MASK GENMASK(31, 24)
+#define MAC_BYTE_1_MASK GENMASK(23, 16)
+#define MAC_BYTE_2_MASK GENMASK(15, 8)
+#define MAC_BYTE_3_MASK GENMASK(7, 0)
#define MT7530_TSRA2 0x88
-#define MAC_BYTE_4 24
-#define MAC_BYTE_5 16
-#define CVID 0
-#define CVID_MASK 0xfff
+#define MAC_BYTE_4_MASK GENMASK(31, 24)
+#define MAC_BYTE_5_MASK GENMASK(23, 16)
+#define CVID_MASK GENMASK(11, 0)
#define MT7530_ATRD 0x8C
-#define AGE_TIMER 24
-#define AGE_TIMER_MASK 0xff
-#define PORT_MAP 4
-#define PORT_MAP_MASK 0xff
-#define ENT_STATUS 2
-#define ENT_STATUS_MASK 0x3
+#define AGE_TIMER_MASK GENMASK(31, 24)
+#define PORT_MAP_MASK GENMASK(11, 4)
+#define ENT_STATUS_MASK GENMASK(3, 2)
/* Register for vlan table control */
#define MT7530_VTCR 0x90
#define VTCR_BUSY BIT(31)
#define VTCR_INVALID BIT(16)
-#define VTCR_FUNC(x) (((x) & 0xf) << 12)
-#define VTCR_VID ((x) & 0xfff)
+#define VTCR_FUNC_MASK GENMASK(15, 12)
+#define VTCR_FUNC(x) FIELD_PREP(VTCR_FUNC_MASK, x)
+#define VTCR_VID_MASK GENMASK(11, 0)
+#define VTCR_VID(x) FIELD_PREP(VTCR_VID_MASK, x)
enum mt7530_vlan_cmd {
/* Read/Write the specified VID entry from VAWD register based
@@ -216,13 +218,13 @@ enum mt7530_vlan_cmd {
/* Per VLAN Egress Tag Control */
#define VTAG_EN BIT(28)
/* VLAN Member Control */
-#define PORT_MEM(x) (((x) & 0xff) << 16)
+#define PORT_MEM_MASK GENMASK(23, 16)
+#define PORT_MEM(x) FIELD_PREP(PORT_MEM_MASK, x)
/* Filter ID */
-#define FID(x) (((x) & 0x7) << 1)
+#define FID_MASK GENMASK(3, 1)
+#define FID(x) FIELD_PREP(FID_MASK, x)
/* VLAN Entry Valid */
#define VLAN_VALID BIT(0)
-#define PORT_MEM_SHFT 16
-#define PORT_MEM_MASK 0xff
enum mt7530_fid {
FID_STANDALONE = 0,
@@ -247,11 +249,11 @@ enum mt7530_vlan_egress_attr {
/* Age count */
#define AGE_CNT_MASK GENMASK(19, 12)
#define AGE_CNT_MAX 0xff
-#define AGE_CNT(x) (AGE_CNT_MASK & ((x) << 12))
+#define AGE_CNT(x) FIELD_PREP(AGE_CNT_MASK, x)
/* Age unit */
#define AGE_UNIT_MASK GENMASK(11, 0)
#define AGE_UNIT_MAX 0xfff
-#define AGE_UNIT(x) (AGE_UNIT_MASK & (x))
+#define AGE_UNIT(x) FIELD_PREP(AGE_UNIT_MASK, x)
#define MT753X_ERLCR_P(x) (0x1040 + ((x) * 0x100))
#define ERLCR_CIR_MASK GENMASK(31, 16)
@@ -282,30 +284,31 @@ enum mt7530_stp_state {
#define MT7530_PCR_P(x) (0x2004 + ((x) * 0x100))
#define PORT_TX_MIR BIT(9)
#define PORT_RX_MIR BIT(8)
-#define PORT_VLAN(x) ((x) & 0x3)
+#define PCR_PORT_VLAN_MASK GENMASK(1, 0)
enum mt7530_port_mode {
/* Port Matrix Mode: Frames are forwarded by the PCR_MATRIX members. */
- MT7530_PORT_MATRIX_MODE = PORT_VLAN(0),
+ MT7530_PORT_MATRIX_MODE = 0,
/* Fallback Mode: Forward received frames with ingress ports that do
* not belong to the VLAN member. Frames whose VID is not listed on
* the VLAN table are forwarded by the PCR_MATRIX members.
*/
- MT7530_PORT_FALLBACK_MODE = PORT_VLAN(1),
+ MT7530_PORT_FALLBACK_MODE = 1,
/* Security Mode: Discard any frame due to ingress membership
* violation or VID missed on the VLAN table.
*/
- MT7530_PORT_SECURITY_MODE = PORT_VLAN(3),
+ MT7530_PORT_SECURITY_MODE = 3,
};
-#define PCR_MATRIX(x) (((x) & 0xff) << 16)
-#define PORT_PRI(x) (((x) & 0x7) << 24)
-#define EG_TAG(x) (((x) & 0x3) << 28)
-#define PCR_MATRIX_MASK PCR_MATRIX(0xff)
+#define PCR_MATRIX_MASK GENMASK(23, 16)
+#define PCR_MATRIX(x) FIELD_PREP(PCR_MATRIX_MASK, x)
+#define PORT_PRI_MASK GENMASK(26, 24)
+#define PORT_PRI(x) FIELD_PREP(PORT_PRI_MASK, x)
+#define EG_TAG_MASK GENMASK(29, 28)
+#define EG_TAG(x) FIELD_PREP(EG_TAG_MASK, x)
#define PCR_MATRIX_CLR PCR_MATRIX(0)
-#define PCR_PORT_VLAN_MASK PORT_VLAN(3)
/* Register for port security control */
#define MT7530_PSC_P(x) (0x200c + ((x) * 0x100))
@@ -314,10 +317,10 @@ enum mt7530_port_mode {
/* Register for port vlan control */
#define MT7530_PVC_P(x) (0x2010 + ((x) * 0x100))
#define PORT_SPEC_TAG BIT(5)
-#define PVC_EG_TAG(x) (((x) & 0x7) << 8)
-#define PVC_EG_TAG_MASK PVC_EG_TAG(7)
-#define VLAN_ATTR(x) (((x) & 0x3) << 6)
-#define VLAN_ATTR_MASK VLAN_ATTR(3)
+#define PVC_EG_TAG_MASK GENMASK(10, 8)
+#define PVC_EG_TAG(x) FIELD_PREP(PVC_EG_TAG_MASK, x)
+#define VLAN_ATTR_MASK GENMASK(7, 6)
+#define VLAN_ATTR(x) FIELD_PREP(VLAN_ATTR_MASK, x)
#define ACC_FRM_MASK GENMASK(1, 0)
enum mt7530_vlan_port_eg_tag {
@@ -337,12 +340,13 @@ enum mt7530_vlan_port_acc_frm {
MT7530_VLAN_ACC_UNTAGGED = 2,
};
-#define STAG_VPID (((x) & 0xffff) << 16)
+#define STAG_VPID_MASK GENMASK(31, 16)
+#define STAG_VPID(x) FIELD_PREP(STAG_VPID_MASK, x)
/* Register for port port-and-protocol based vlan 1 control */
#define MT7530_PPBV1_P(x) (0x2014 + ((x) * 0x100))
-#define G0_PORT_VID(x) (((x) & 0xfff) << 0)
-#define G0_PORT_VID_MASK G0_PORT_VID(0xfff)
+#define G0_PORT_VID_MASK GENMASK(11, 0)
+#define G0_PORT_VID(x) FIELD_PREP(G0_PORT_VID_MASK, x)
#define G0_PORT_VID_DEF G0_PORT_VID(0)
/* Register for port MAC control register */
@@ -418,8 +422,8 @@ enum mt7530_vlan_port_acc_frm {
#define MT7531_DIS_CLR BIT(31)
#define MT7530_GMACCR 0x30e0
-#define MAX_RX_JUMBO(x) ((x) << 2)
#define MAX_RX_JUMBO_MASK GENMASK(5, 2)
+#define MAX_RX_JUMBO(x) FIELD_PREP(MAX_RX_JUMBO_MASK, x)
#define MAX_RX_PKT_LEN_MASK GENMASK(1, 0)
#define MAX_RX_PKT_LEN_1522 0x0
#define MAX_RX_PKT_LEN_1536 0x1
@@ -505,16 +509,16 @@ enum mt7530_vlan_port_acc_frm {
/* Register for PHY Indirect Access Control */
#define MT7531_PHY_IAC 0x701C
#define MT7531_PHY_ACS_ST BIT(31)
-#define MT7531_MDIO_REG_ADDR_MASK (0x1f << 25)
-#define MT7531_MDIO_PHY_ADDR_MASK (0x1f << 20)
-#define MT7531_MDIO_CMD_MASK (0x3 << 18)
-#define MT7531_MDIO_ST_MASK (0x3 << 16)
-#define MT7531_MDIO_RW_DATA_MASK (0xffff)
-#define MT7531_MDIO_REG_ADDR(x) (((x) & 0x1f) << 25)
-#define MT7531_MDIO_DEV_ADDR(x) (((x) & 0x1f) << 25)
-#define MT7531_MDIO_PHY_ADDR(x) (((x) & 0x1f) << 20)
-#define MT7531_MDIO_CMD(x) (((x) & 0x3) << 18)
-#define MT7531_MDIO_ST(x) (((x) & 0x3) << 16)
+#define MT7531_MDIO_REG_ADDR_MASK GENMASK(29, 25)
+#define MT7531_MDIO_PHY_ADDR_MASK GENMASK(24, 20)
+#define MT7531_MDIO_CMD_MASK GENMASK(19, 18)
+#define MT7531_MDIO_ST_MASK GENMASK(17, 16)
+#define MT7531_MDIO_RW_DATA_MASK GENMASK(15, 0)
+#define MT7531_MDIO_REG_ADDR(x) FIELD_PREP(MT7531_MDIO_REG_ADDR_MASK, x)
+#define MT7531_MDIO_DEV_ADDR(x) FIELD_PREP(MT7531_MDIO_REG_ADDR_MASK, x)
+#define MT7531_MDIO_PHY_ADDR(x) FIELD_PREP(MT7531_MDIO_PHY_ADDR_MASK, x)
+#define MT7531_MDIO_CMD(x) FIELD_PREP(MT7531_MDIO_CMD_MASK, x)
+#define MT7531_MDIO_ST(x) FIELD_PREP(MT7531_MDIO_ST_MASK, x)
enum mt7531_phy_iac_cmd {
MT7531_MDIO_ADDR = 0,
@@ -542,14 +546,14 @@ enum mt7531_mdio_st {
/* Register for RGMII clock phase */
#define MT7531_CLKGEN_CTRL 0x7500
-#define CLK_SKEW_OUT(x) (((x) & 0x3) << 8)
#define CLK_SKEW_OUT_MASK GENMASK(9, 8)
-#define CLK_SKEW_IN(x) (((x) & 0x3) << 6)
+#define CLK_SKEW_OUT(x) FIELD_PREP(CLK_SKEW_OUT_MASK, x)
#define CLK_SKEW_IN_MASK GENMASK(7, 6)
+#define CLK_SKEW_IN(x) FIELD_PREP(CLK_SKEW_IN_MASK, x)
#define RXCLK_NO_DELAY BIT(5)
#define TXCLK_NO_REVERSE BIT(4)
-#define GP_MODE(x) (((x) & 0x3) << 1)
#define GP_MODE_MASK GENMASK(2, 1)
+#define GP_MODE(x) FIELD_PREP(GP_MODE_MASK, x)
#define GP_CLK_EN BIT(0)
enum mt7531_gp_mode {
@@ -599,8 +603,10 @@ enum mt7531_xtal_fsel {
#define PAD_MCM_SMI_EN BIT(0)
#define MT7530_IO_DRV_CR 0x7810
-#define P5_IO_CLK_DRV(x) ((x) & 0x3)
-#define P5_IO_DATA_DRV(x) (((x) & 0x3) << 4)
+#define P5_IO_CLK_DRV_MASK GENMASK(1, 0)
+#define P5_IO_CLK_DRV(x) FIELD_PREP(P5_IO_CLK_DRV_MASK, x)
+#define P5_IO_DATA_DRV_MASK GENMASK(5, 4)
+#define P5_IO_DATA_DRV(x) FIELD_PREP(P5_IO_DATA_DRV_MASK, x)
#define MT7531_CHIP_REV 0x781C
@@ -610,15 +616,15 @@ enum mt7531_xtal_fsel {
#define SW_PLLGP BIT(0)
#define MT7530_P6ECR 0x7830
-#define P6_INTF_MODE_MASK 0x3
-#define P6_INTF_MODE(x) ((x) & 0x3)
+#define P6_INTF_MODE_MASK GENMASK(1, 0)
+#define P6_INTF_MODE(x) FIELD_PREP(P6_INTF_MODE_MASK, x)
#define MT7531_PLLGP_CR0 0x78a8
#define RG_COREPLL_EN BIT(22)
-#define RG_COREPLL_POSDIV_S 23
-#define RG_COREPLL_POSDIV_M 0x3800000
-#define RG_COREPLL_SDM_PCW_S 1
-#define RG_COREPLL_SDM_PCW_M 0x3ffffe
+#define RG_COREPLL_POSDIV_MASK GENMASK(25, 23)
+#define RG_COREPLL_POSDIV(x) FIELD_PREP(RG_COREPLL_POSDIV_MASK, x)
+#define RG_COREPLL_SDM_PCW_MASK GENMASK(21, 1)
+#define RG_COREPLL_SDM_PCW(x) FIELD_PREP(RG_COREPLL_SDM_PCW_MASK, x)
#define RG_COREPLL_SDM_PCW_CHG BIT(0)
/* Registers for RGMII and SGMII PLL clock */
@@ -629,10 +635,10 @@ enum mt7531_xtal_fsel {
#define MT7530_TRGMII_RCK_CTRL 0x7a00
#define RX_RST BIT(31)
#define RXC_DQSISEL BIT(30)
-#define DQSI1_TAP_MASK (0x7f << 8)
-#define DQSI0_TAP_MASK 0x7f
-#define DQSI1_TAP(x) (((x) & 0x7f) << 8)
-#define DQSI0_TAP(x) ((x) & 0x7f)
+#define DQSI1_TAP_MASK GENMASK(14, 8)
+#define DQSI0_TAP_MASK GENMASK(6, 0)
+#define DQSI1_TAP(x) FIELD_PREP(DQSI1_TAP_MASK, x)
+#define DQSI0_TAP(x) FIELD_PREP(DQSI0_TAP_MASK, x)
#define MT7530_TRGMII_RCK_RTT 0x7a04
#define DQS1_GATE BIT(31)
@@ -641,8 +647,8 @@ enum mt7531_xtal_fsel {
#define MT7530_TRGMII_RD(x) (0x7a10 + (x) * 8)
#define BSLIP_EN BIT(31)
#define EDGE_CHK BIT(30)
-#define RD_TAP_MASK 0x7f
-#define RD_TAP(x) ((x) & 0x7f)
+#define RD_TAP_MASK GENMASK(6, 0)
+#define RD_TAP(x) FIELD_PREP(RD_TAP_MASK, x)
#define MT7530_TRGMII_TXCTRL 0x7a40
#define TRAIN_TXEN BIT(31)
@@ -650,18 +656,23 @@ enum mt7531_xtal_fsel {
#define TX_RST BIT(28)
#define MT7530_TRGMII_TD_ODT(i) (0x7a54 + 8 * (i))
-#define TD_DM_DRVP(x) ((x) & 0xf)
-#define TD_DM_DRVN(x) (((x) & 0xf) << 4)
+#define TD_DM_DRVP_MASK GENMASK(3, 0)
+#define TD_DM_DRVP(x) FIELD_PREP(TD_DM_DRVP_MASK, x)
+#define TD_DM_DRVN_MASK GENMASK(7, 4)
+#define TD_DM_DRVN(x) FIELD_PREP(TD_DM_DRVN_MASK, x)
#define MT7530_TRGMII_TCK_CTRL 0x7a78
-#define TCK_TAP(x) (((x) & 0xf) << 8)
+#define TCK_TAP_MASK GENMASK(11, 8)
+#define TCK_TAP(x) FIELD_PREP(TCK_TAP_MASK, x)
#define MT7530_P5RGMIIRXCR 0x7b00
#define CSR_RGMII_EDGE_ALIGN BIT(8)
-#define CSR_RGMII_RXC_0DEG_CFG(x) ((x) & 0xf)
+#define CSR_RGMII_RXC_0DEG_CFG_MASK GENMASK(3, 0)
+#define CSR_RGMII_RXC_0DEG_CFG(x) FIELD_PREP(CSR_RGMII_RXC_0DEG_CFG_MASK, x)
#define MT7530_P5RGMIITXCR 0x7b04
-#define CSR_RGMII_TXC_CFG(x) ((x) & 0x1f)
+#define CSR_RGMII_TXC_CFG_MASK GENMASK(4, 0)
+#define CSR_RGMII_TXC_CFG(x) FIELD_PREP(CSR_RGMII_TXC_CFG_MASK, x)
/* Registers for GPIO mode */
#define MT7531_GPIO_MODE0 0x7c0c
@@ -670,9 +681,9 @@ enum mt7531_xtal_fsel {
#define MT7531_GPIO_MODE1 0x7c10
#define MT7531_GPIO11_RG_RXD2_MASK GENMASK(15, 12)
-#define MT7531_EXT_P_MDC_11 (2 << 12)
+#define MT7531_EXT_P_MDC_11 FIELD_PREP(MT7531_GPIO11_RG_RXD2_MASK, 2)
#define MT7531_GPIO12_RG_RXD3_MASK GENMASK(19, 16)
-#define MT7531_EXT_P_MDIO_12 (2 << 16)
+#define MT7531_EXT_P_MDIO_12 FIELD_PREP(MT7531_GPIO12_RG_RXD3_MASK, 2)
#define MT753X_CPORT_SPTAG_CFG 0x7c10
#define CPORT_SW2FE_STAG_EN BIT(1)
@@ -704,7 +715,7 @@ enum mt7531_xtal_fsel {
#define MT7530_LED_GPIO_DATA 0x7d18
#define MT7530_CREV 0x7ffc
-#define CHIP_NAME_SHIFT 16
+#define CHIP_NAME_MASK GENMASK(31, 16)
#define MT7530_ID 0x7530
#define MT7531_CREV 0x781C
@@ -716,10 +727,13 @@ enum mt7531_xtal_fsel {
#define RG_SYSPLL_EN_NORMAL BIT(15)
#define RG_SYSPLL_VODEN BIT(14)
#define RG_SYSPLL_LF BIT(13)
-#define RG_SYSPLL_RST_DLY(x) (((x) & 0x3) << 12)
+#define RG_SYSPLL_RST_DLY_MASK GENMASK(13, 12)
+#define RG_SYSPLL_RST_DLY(x) FIELD_PREP(RG_SYSPLL_RST_DLY_MASK, x)
#define RG_SYSPLL_LVROD_EN BIT(10)
-#define RG_SYSPLL_PREDIV(x) (((x) & 0x3) << 8)
-#define RG_SYSPLL_POSDIV(x) (((x) & 0x3) << 5)
+#define RG_SYSPLL_PREDIV_MASK GENMASK(9, 8)
+#define RG_SYSPLL_PREDIV(x) FIELD_PREP(RG_SYSPLL_PREDIV_MASK, x)
+#define RG_SYSPLL_POSDIV_MASK GENMASK(6, 5)
+#define RG_SYSPLL_POSDIV(x) FIELD_PREP(RG_SYSPLL_POSDIV_MASK, x)
#define RG_SYSPLL_FBKSEL BIT(4)
#define RT_SYSPLL_EN_AFE_OLT BIT(0)
@@ -731,38 +745,48 @@ enum mt7531_xtal_fsel {
#define MT7531_PHY_PLL_OFF BIT(5)
#define MT7531_PHY_PLL_BYPASS_MODE BIT(4)
-#define MT753X_CTRL_PHY_ADDR(addr) ((addr + 1) & 0x1f)
+#define MT753X_CTRL_PHY_ADDR(addr) (((addr) + 1) & (PHY_MAX_ADDR - 1))
#define CORE_PLL_GROUP5 0x404
-#define RG_LCDDS_PCW_NCPO1(x) ((x) & 0xffff)
+#define RG_LCDDS_PCW_NCPO1_MASK GENMASK(15, 0)
+#define RG_LCDDS_PCW_NCPO1(x) FIELD_PREP(RG_LCDDS_PCW_NCPO1_MASK, x)
#define CORE_PLL_GROUP6 0x405
-#define RG_LCDDS_PCW_NCPO0(x) ((x) & 0xffff)
+#define RG_LCDDS_PCW_NCPO0_MASK GENMASK(15, 0)
+#define RG_LCDDS_PCW_NCPO0(x) FIELD_PREP(RG_LCDDS_PCW_NCPO0_MASK, x)
#define CORE_PLL_GROUP7 0x406
#define RG_LCDDS_PWDB BIT(15)
#define RG_LCDDS_ISO_EN BIT(13)
-#define RG_LCCDS_C(x) (((x) & 0x7) << 4)
+#define RG_LCCDS_C_MASK GENMASK(6, 4)
+#define RG_LCCDS_C(x) FIELD_PREP(RG_LCCDS_C_MASK, x)
#define RG_LCDDS_PCW_NCPO_CHG BIT(3)
#define CORE_PLL_GROUP10 0x409
-#define RG_LCDDS_SSC_DELTA(x) ((x) & 0xfff)
+#define RG_LCDDS_SSC_DELTA_MASK GENMASK(11, 0)
+#define RG_LCDDS_SSC_DELTA(x) FIELD_PREP(RG_LCDDS_SSC_DELTA_MASK, x)
#define CORE_PLL_GROUP11 0x40a
-#define RG_LCDDS_SSC_DELTA1(x) ((x) & 0xfff)
+#define RG_LCDDS_SSC_DELTA1_MASK GENMASK(11, 0)
+#define RG_LCDDS_SSC_DELTA1(x) FIELD_PREP(RG_LCDDS_SSC_DELTA1_MASK, x)
#define CORE_GSWPLL_GRP1 0x40d
-#define RG_GSWPLL_PREDIV(x) (((x) & 0x3) << 14)
-#define RG_GSWPLL_POSDIV_200M(x) (((x) & 0x3) << 12)
+#define RG_GSWPLL_PREDIV_MASK GENMASK(15, 14)
+#define RG_GSWPLL_PREDIV(x) FIELD_PREP(RG_GSWPLL_PREDIV_MASK, x)
+#define RG_GSWPLL_POSDIV_200M_MASK GENMASK(13, 12)
+#define RG_GSWPLL_POSDIV_200M(x) FIELD_PREP(RG_GSWPLL_POSDIV_200M_MASK, x)
#define RG_GSWPLL_EN_PRE BIT(11)
#define RG_GSWPLL_FBKSEL BIT(10)
#define RG_GSWPLL_BP BIT(9)
#define RG_GSWPLL_BR BIT(8)
-#define RG_GSWPLL_FBKDIV_200M(x) ((x) & 0xff)
+#define RG_GSWPLL_FBKDIV_200M_MASK GENMASK(7, 0)
+#define RG_GSWPLL_FBKDIV_200M(x) FIELD_PREP(RG_GSWPLL_FBKDIV_200M_MASK, x)
#define CORE_GSWPLL_GRP2 0x40e
-#define RG_GSWPLL_POSDIV_500M(x) (((x) & 0x3) << 8)
-#define RG_GSWPLL_FBKDIV_500M(x) ((x) & 0xff)
+#define RG_GSWPLL_POSDIV_500M_MASK GENMASK(9, 8)
+#define RG_GSWPLL_POSDIV_500M(x) FIELD_PREP(RG_GSWPLL_POSDIV_500M_MASK, x)
+#define RG_GSWPLL_FBKDIV_500M_MASK GENMASK(7, 0)
+#define RG_GSWPLL_FBKDIV_500M(x) FIELD_PREP(RG_GSWPLL_FBKDIV_500M_MASK, x)
#define CORE_TRGMII_GSW_CLK_CG 0x410
#define REG_GSWCK_EN BIT(0)
--
2.55.0
^ permalink raw reply related
* [PATCH net-next v4 7/8] net: dsa: mt7530: implement port_fast_age
From: Daniel Golle @ 2026-07-19 17:54 UTC (permalink / raw)
To: Chester A. Unal, Daniel Golle, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Matthias Brugger, AngeloGioacchino Del Regno, Russell King,
netdev, linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <cover.1784481922.git.daniel@makrotopia.org>
Implement the .port_fast_age DSA operation by flushing all non-static
(dynamically learned) MAC address entries from the address table.
The switch does not offer a combined "non-static AND per-port" match
mode, so the flush is global and the port argument is not used. Unlike
b53 and realtek, which flush the dynamic entries of the affected port
only, an STP topology change on one port therefore also flushes the
dynamically learned entries of the other ports; they are quickly
relearned.
Access the address table control register under priv->reg_mutex, as done
by all other ATC users (FDB and MDB add/del/dump), to serialise the
write-then-poll command sequence, and log a message should the flush
time out.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v3:
* take reg_mutex around the ATC flush and log on timeout
* align the ATC_MAT_NON_STATIC_MAC define
* correct the commit message which wrongly claimed per-port parity
with b53/realtek
---
drivers/net/dsa/mt7530.c | 23 +++++++++++++++++++++++
drivers/net/dsa/mt7530.h | 1 +
2 files changed, 24 insertions(+)
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index f7643b86f3c4..52b549d7ee22 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -193,6 +193,28 @@ mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp)
return 0;
}
+static void mt7530_port_fast_age(struct dsa_switch *ds, int port)
+{
+ struct mt7530_priv *priv = ds->priv;
+ struct mt7530_dummy_poll p;
+ u32 val;
+ int ret;
+
+ mutex_lock(&priv->reg_mutex);
+
+ /* Flush all non-static MAC address entries */
+ val = ATC_BUSY | ATC_MAT_NON_STATIC_MAC | MT7530_FDB_FLUSH;
+ regmap_write(priv->regmap, MT7530_ATC, val);
+
+ INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_ATC);
+ ret = readx_poll_timeout(mt7530_mii_poll, &p, val,
+ !(val & ATC_BUSY), 20, 20000);
+ if (ret < 0)
+ dev_err(priv->dev, "fast age timeout\n");
+
+ mutex_unlock(&priv->reg_mutex);
+}
+
static void
mt7530_fdb_read(struct mt7530_priv *priv, struct mt7530_fdb *fdb)
{
@@ -3319,6 +3341,7 @@ static const struct dsa_switch_ops mt7530_switch_ops = {
.port_bridge_flags = mt7530_port_bridge_flags,
.port_bridge_join = mt7530_port_bridge_join,
.port_bridge_leave = mt7530_port_bridge_leave,
+ .port_fast_age = mt7530_port_fast_age,
.port_fdb_add = mt7530_port_fdb_add,
.port_fdb_del = mt7530_port_fdb_del,
.port_fdb_dump = mt7530_port_fdb_dump,
diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h
index 804c2e0991a0..241e3d460357 100644
--- a/drivers/net/dsa/mt7530.h
+++ b/drivers/net/dsa/mt7530.h
@@ -165,6 +165,7 @@ enum mt753x_to_cpu_fw {
#define ATC_MAT_MASK GENMASK(11, 8)
#define ATC_MAT(x) FIELD_PREP(ATC_MAT_MASK, x)
#define ATC_MAT_MACTAB ATC_MAT(0)
+#define ATC_MAT_NON_STATIC_MAC ATC_MAT(4)
enum mt7530_fdb_cmd {
MT7530_FDB_READ = 0,
--
2.55.0
^ permalink raw reply related
* [PATCH net-next v4 8/8] net: dsa: mt7530: implement port_change_conduit op
From: Daniel Golle @ 2026-07-19 17:54 UTC (permalink / raw)
To: Chester A. Unal, Daniel Golle, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Matthias Brugger, AngeloGioacchino Del Regno, Russell King,
netdev, linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <cover.1784481922.git.daniel@makrotopia.org>
Allow changing the CPU port affinity of user ports at runtime via the
IFLA_DSA_CONDUIT netlink attribute. This updates the port matrix to
forward to the new CPU port instead of the old one.
Limit the operation to MT7531. There, trapped link-local frames follow
the per-port affinity, as the MT7531_CPU_PMAP destination mask is
further restricted by the port matrix. A conduit change is hence fully
honoured by the hardware, for regular traffic as well as for trapped
frames.
The MT7530 switch, including the variant embedded in the MT7621 SoC,
instead traps frames to the single CPU port set in the CPU_PORT field
of the MFC register, regardless of the affinity of the inbound user
port. With user ports affine to different CPU ports there is no
correct value for that field, so per-port CPU affinity cannot be fully
implemented for trapped frames. Routing a WAN port via the second SoC
GMAC is conventionally covered by the PHY muxing feature on these
switches, which bypasses the switch fabric and does not involve a CPU
port at all.
The switches on the MT7988, EN7581 and AN7583 SoCs only have a
single CPU port, leaving no other conduit to change to.
As the op lives in the shared mt7530_switch_ops, populate the extack
when rejecting the unsupported variants instead of returning a bare
-EOPNOTSUPP. Also reject a conduit that belongs to a different switch
in the tree, whose port index has no meaning in the local port matrix.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Acked-by: Chester A. Unal <chester.a.unal@arinc9.com>
---
v3:
* populate the netlink extack on rejection
* refuse a conduit that lives on a different switch
drivers/net/dsa/mt7530.c | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 52b549d7ee22..6fe6783dfe3f 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -3213,6 +3213,43 @@ static int mt753x_set_mac_eee(struct dsa_switch *ds, int port,
return 0;
}
+static int
+mt753x_port_change_conduit(struct dsa_switch *ds, int port,
+ struct net_device *conduit,
+ struct netlink_ext_ack *extack)
+{
+ struct dsa_port *new_cpu_dp = conduit->dsa_ptr;
+ struct dsa_port *dp = dsa_to_port(ds, port);
+ struct mt7530_priv *priv = ds->priv;
+
+ if (priv->id != ID_MT7531) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Changing DSA conduit is only supported on MT7531");
+ return -EOPNOTSUPP;
+ }
+
+ if (new_cpu_dp->ds != ds) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Cannot assign a conduit on a different switch");
+ return -EOPNOTSUPP;
+ }
+
+ mutex_lock(&priv->reg_mutex);
+
+ /* dp->cpu_dp still points to the old CPU port */
+ priv->ports[port].pm &= ~PCR_MATRIX(BIT(dp->cpu_dp->index));
+ priv->ports[port].pm |= PCR_MATRIX(BIT(new_cpu_dp->index));
+ if (priv->ports[port].enable)
+ regmap_update_bits(priv->regmap, MT7530_PCR_P(port),
+ PCR_MATRIX_MASK, priv->ports[port].pm);
+
+ mutex_unlock(&priv->reg_mutex);
+
+ mt7530_port_fast_age(ds, port);
+
+ return 0;
+}
+
static void
mt753x_conduit_state_change(struct dsa_switch *ds,
const struct net_device *conduit,
@@ -3324,6 +3361,7 @@ static const struct dsa_switch_ops mt7530_switch_ops = {
.setup = mt753x_setup,
.teardown = mt753x_teardown,
.preferred_default_local_cpu_port = mt753x_preferred_default_local_cpu_port,
+ .port_change_conduit = mt753x_port_change_conduit,
.get_strings = mt7530_get_strings,
.get_ethtool_stats = mt7530_get_ethtool_stats,
.get_sset_count = mt7530_get_sset_count,
--
2.55.0
^ permalink raw reply related
* [PATCH v6 0/3] KVM: selftests: arm64: Improve diagnostics from set_id_regs
From: Mark Brown @ 2026-07-19 19:24 UTC (permalink / raw)
To: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Paolo Bonzini,
Shuah Khan, Oliver Upton
Cc: Ben Horgan, linux-arm-kernel, kvmarm, kvm, linux-kselftest,
linux-kernel, Mark Brown
While debugging issues related to aarch64 only systems I ran into
speedbumps due to the lack of detail in the results reported when the
guest register read and reset value preservation tests were run, they
generated an immediately fatal assert without indicating which register
was being tested. Update these tests to non-fatally report a standard
kselftest result per register, making it much easier to see what the
problem being reported is.
A similar issue exists with the validation of the individual bitfields
in registers due to the use of immediately fatal asserts. Update those
asserts to be standard kselftest reports.
Signed-off-by: Mark Brown <broonie@kernel.org>
---
Changes in v6:
- Rebase onto v7.2-rc3.
- Drop changes to handling of aarch32 related registers on 64 bit only
systems, an in kernel solution is preferred for those.
- Use a define to count the non-test_regs registers.
- Link to v5: https://patch.msgid.link/20260317-kvm-arm64-set-id-regs-aarch64-v5-0-a60f2b956e22@kernel.org
Changes in v5:
- Rebase onto v7.0-rc1.
- Link to v4: https://patch.msgid.link/20260106-kvm-arm64-set-id-regs-aarch64-v4-0-c7ef4551afb3@kernel.org
Changes in v4:
- Correct check for 32 bit ID registers.
- Link to v3: https://patch.msgid.link/20251219-kvm-arm64-set-id-regs-aarch64-v3-0-bfa474ec3218@kernel.org
Changes in v3:
- Rebase onto v6.19-rc1.
- Link to v2: https://patch.msgid.link/20251114-kvm-arm64-set-id-regs-aarch64-v2-0-672f214f41bf@kernel.org
Changes in v2:
- Add a fix for spurious failures with 64 bit only guests.
- Link to v1: https://patch.msgid.link/20251030-kvm-arm64-set-id-regs-aarch64-v1-0-96fe0d2b178e@kernel.org
---
Mark Brown (3):
KVM: selftests: arm64: Report set_id_reg reads of test registers as tests
KVM: selftests: arm64: Report register reset tests individually
KVM: selftests: arm64: Make set_id_regs bitfield validatity checks non-fatal
tools/testing/selftests/kvm/arm64/set_id_regs.c | 121 ++++++++++++++++++------
1 file changed, 91 insertions(+), 30 deletions(-)
---
base-commit: a13c140cc289c0b7b3770bce5b3ad42ab35074aa
change-id: 20251028-kvm-arm64-set-id-regs-aarch64-ebb77969401c
Best regards,
--
Mark Brown <broonie@kernel.org>
^ permalink raw reply
* [PATCH v6 2/3] KVM: selftests: arm64: Report register reset tests individually
From: Mark Brown @ 2026-07-19 19:24 UTC (permalink / raw)
To: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Paolo Bonzini,
Shuah Khan, Oliver Upton
Cc: Ben Horgan, linux-arm-kernel, kvmarm, kvm, linux-kselftest,
linux-kernel, Mark Brown
In-Reply-To: <20260719-kvm-arm64-set-id-regs-aarch64-v6-0-724287f5f108@kernel.org>
set_id_regs tests that registers have their values preserved over reset.
Currently it reports all registers in a single test with an instantly fatal
assert which isn't great for diagnostics, it's hard to tell which register
failed or if it's just one register. Change this to report each register as
a separate test so that it's clear from the program output which registers
have problems.
Reviewed-by: Ben Horgan <ben.horgan@arm.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
tools/testing/selftests/kvm/arm64/set_id_regs.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c
index db6414a93ad3..3aa8886e8b70 100644
--- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
+++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
@@ -819,13 +819,21 @@ static void test_vcpu_non_ftr_id_regs(struct kvm_vcpu *vcpu)
static void test_assert_id_reg_unchanged(struct kvm_vcpu *vcpu, u32 encoding)
{
size_t idx = encoding_to_range_idx(encoding);
- u64 observed;
+ u64 observed, expected;
+ bool pass;
observed = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(encoding));
- TEST_ASSERT_EQ(reset_mutable_bits(encoding, test_reg_vals[idx]),
- reset_mutable_bits(encoding, observed));
+ observed = reset_mutable_bits(encoding, observed);
+ expected = reset_mutable_bits(encoding, test_reg_vals[idx]);
+ pass = expected == observed;
+ if (!pass)
+ ksft_print_msg("%lx != %lx\n", expected, observed);
+ ksft_test_result(pass, "%s unchanged by reset\n",
+ get_reg_name(encoding));
}
+#define ID_REG_RESET_UNCHANGED_TEST (ARRAY_SIZE(test_regs) + NUM_EXTRA_REGS)
+
static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu)
{
/*
@@ -843,8 +851,6 @@ static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu)
test_assert_id_reg_unchanged(vcpu, SYS_MIDR_EL1);
test_assert_id_reg_unchanged(vcpu, SYS_REVIDR_EL1);
test_assert_id_reg_unchanged(vcpu, SYS_AIDR_EL1);
-
- ksft_test_result_pass("%s\n", __func__);
}
int main(void)
@@ -872,7 +878,8 @@ int main(void)
ksft_print_header();
- test_cnt = 3 + MPAM_IDREG_TEST + MTE_IDREG_TEST + GUEST_READ_TEST;
+ test_cnt = 2 + MPAM_IDREG_TEST + MTE_IDREG_TEST + GUEST_READ_TEST +
+ ID_REG_RESET_UNCHANGED_TEST;
for (i = 0; i < ARRAY_SIZE(test_regs); i++)
for (j = 0; test_regs[i].ftr_bits[j].type != FTR_END; j++)
test_cnt++;
--
2.47.3
^ permalink raw reply related
* [PATCH v6 1/3] KVM: selftests: arm64: Report set_id_reg reads of test registers as tests
From: Mark Brown @ 2026-07-19 19:24 UTC (permalink / raw)
To: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Paolo Bonzini,
Shuah Khan, Oliver Upton
Cc: Ben Horgan, linux-arm-kernel, kvmarm, kvm, linux-kselftest,
linux-kernel, Mark Brown
In-Reply-To: <20260719-kvm-arm64-set-id-regs-aarch64-v6-0-724287f5f108@kernel.org>
Currently when we run guest code to validate that the values we wrote to
the registers are seen by the guest we assert that these values match using
a KVM selftests level assert, resulting in unclear diagnostics if the test
fails. Replace this assert with reporting a kselftest test per register.
In order to support getting the names of the registers we repaint the array
of ID_ registers to store the names and open code the rest.
Reviewed-by: Ben Horgan <ben.horgan@arm.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
tools/testing/selftests/kvm/arm64/set_id_regs.c | 82 +++++++++++++++++++------
1 file changed, 63 insertions(+), 19 deletions(-)
diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c
index 7429a1055df5..db6414a93ad3 100644
--- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
+++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
@@ -43,6 +43,7 @@ struct reg_ftr_bits {
};
struct test_feature_reg {
+ const char *name;
u32 reg;
const struct reg_ftr_bits *ftr_bits;
};
@@ -227,30 +228,32 @@ static const struct reg_ftr_bits ftr_id_aa64zfr0_el1[] = {
#define TEST_REG(id, table) \
{ \
- .reg = id, \
+ .name = #id, \
+ .reg = SYS_ ## id, \
.ftr_bits = &((table)[0]), \
}
static struct test_feature_reg test_regs[] = {
- TEST_REG(SYS_ID_AA64DFR0_EL1, ftr_id_aa64dfr0_el1),
- TEST_REG(SYS_ID_DFR0_EL1, ftr_id_dfr0_el1),
- TEST_REG(SYS_ID_AA64ISAR0_EL1, ftr_id_aa64isar0_el1),
- TEST_REG(SYS_ID_AA64ISAR1_EL1, ftr_id_aa64isar1_el1),
- TEST_REG(SYS_ID_AA64ISAR2_EL1, ftr_id_aa64isar2_el1),
- TEST_REG(SYS_ID_AA64ISAR3_EL1, ftr_id_aa64isar3_el1),
- TEST_REG(SYS_ID_AA64PFR0_EL1, ftr_id_aa64pfr0_el1),
- TEST_REG(SYS_ID_AA64PFR1_EL1, ftr_id_aa64pfr1_el1),
- TEST_REG(SYS_ID_AA64MMFR0_EL1, ftr_id_aa64mmfr0_el1),
- TEST_REG(SYS_ID_AA64MMFR1_EL1, ftr_id_aa64mmfr1_el1),
- TEST_REG(SYS_ID_AA64MMFR2_EL1, ftr_id_aa64mmfr2_el1),
- TEST_REG(SYS_ID_AA64MMFR3_EL1, ftr_id_aa64mmfr3_el1),
- TEST_REG(SYS_ID_AA64ZFR0_EL1, ftr_id_aa64zfr0_el1),
+ TEST_REG(ID_AA64DFR0_EL1, ftr_id_aa64dfr0_el1),
+ TEST_REG(ID_DFR0_EL1, ftr_id_dfr0_el1),
+ TEST_REG(ID_AA64ISAR0_EL1, ftr_id_aa64isar0_el1),
+ TEST_REG(ID_AA64ISAR1_EL1, ftr_id_aa64isar1_el1),
+ TEST_REG(ID_AA64ISAR2_EL1, ftr_id_aa64isar2_el1),
+ TEST_REG(ID_AA64ISAR3_EL1, ftr_id_aa64isar3_el1),
+ TEST_REG(ID_AA64PFR0_EL1, ftr_id_aa64pfr0_el1),
+ TEST_REG(ID_AA64PFR1_EL1, ftr_id_aa64pfr1_el1),
+ TEST_REG(ID_AA64MMFR0_EL1, ftr_id_aa64mmfr0_el1),
+ TEST_REG(ID_AA64MMFR1_EL1, ftr_id_aa64mmfr1_el1),
+ TEST_REG(ID_AA64MMFR2_EL1, ftr_id_aa64mmfr2_el1),
+ TEST_REG(ID_AA64MMFR3_EL1, ftr_id_aa64mmfr3_el1),
+ TEST_REG(ID_AA64ZFR0_EL1, ftr_id_aa64zfr0_el1),
};
#define GUEST_REG_SYNC(id) GUEST_SYNC_ARGS(0, id, read_sysreg_s(id), 0, 0);
static void guest_code(void)
{
+ /* Registers in test_regs array */
GUEST_REG_SYNC(SYS_ID_AA64DFR0_EL1);
GUEST_REG_SYNC(SYS_ID_DFR0_EL1);
GUEST_REG_SYNC(SYS_ID_AA64ISAR0_EL1);
@@ -264,6 +267,8 @@ static void guest_code(void)
GUEST_REG_SYNC(SYS_ID_AA64MMFR2_EL1);
GUEST_REG_SYNC(SYS_ID_AA64MMFR3_EL1);
GUEST_REG_SYNC(SYS_ID_AA64ZFR0_EL1);
+
+ /* Additional registers counted in NUM_EXTRA_REGS */
GUEST_REG_SYNC(SYS_MPIDR_EL1);
GUEST_REG_SYNC(SYS_CLIDR_EL1);
GUEST_REG_SYNC(SYS_CTR_EL0);
@@ -274,6 +279,35 @@ static void guest_code(void)
GUEST_DONE();
}
+#define NUM_EXTRA_REGS 6
+#define GUEST_READ_TEST (ARRAY_SIZE(test_regs) + NUM_EXTRA_REGS)
+
+static const char *get_reg_name(u64 id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(test_regs); i++)
+ if (test_regs[i].reg == id)
+ return test_regs[i].name;
+
+ switch (id) {
+ case SYS_MPIDR_EL1:
+ return "MPIDR_EL1";
+ case SYS_CLIDR_EL1:
+ return "CLIDR_EL1";
+ case SYS_CTR_EL0:
+ return "CTR_EL0";
+ case SYS_MIDR_EL1:
+ return "MIDR_EL1";
+ case SYS_REVIDR_EL1:
+ return "REVIDR_EL1";
+ case SYS_AIDR_EL1:
+ return "AIDR_EL1";
+ default:
+ TEST_FAIL("Unknown register");
+ }
+}
+
/* Return a safe value to a given ftr_bits an ftr value */
u64 get_safe_value(const struct reg_ftr_bits *ftr_bits, u64 ftr)
{
@@ -674,7 +708,8 @@ static void test_guest_reg_read(struct kvm_vcpu *vcpu)
struct ucall uc;
while (!done) {
- u64 val;
+ u64 reg_id, expected_val, guest_val;
+ bool match;
vcpu_run(vcpu);
@@ -683,11 +718,20 @@ static void test_guest_reg_read(struct kvm_vcpu *vcpu)
REPORT_GUEST_ASSERT(uc);
break;
case UCALL_SYNC:
- val = test_reg_vals[encoding_to_range_idx(uc.args[2])];
- val = reset_mutable_bits(uc.args[2], val);
+ expected_val = test_reg_vals[encoding_to_range_idx(uc.args[2])];
+ expected_val = reset_mutable_bits(uc.args[2], expected_val);
/* Make sure the written values are seen by guest */
- TEST_ASSERT_EQ(val, reset_mutable_bits(uc.args[2], uc.args[3]));
+ reg_id = uc.args[2];
+ guest_val = reset_mutable_bits(uc.args[2], uc.args[3]);
+
+ match = expected_val == guest_val;
+ if (!match)
+ ksft_print_msg("%lx != %lx\n",
+ expected_val, guest_val);
+ ksft_test_result(match,
+ "%s value seen in guest\n",
+ get_reg_name(reg_id));
break;
case UCALL_DONE:
done = true;
@@ -828,7 +872,7 @@ int main(void)
ksft_print_header();
- test_cnt = 3 + MPAM_IDREG_TEST + MTE_IDREG_TEST;
+ test_cnt = 3 + MPAM_IDREG_TEST + MTE_IDREG_TEST + GUEST_READ_TEST;
for (i = 0; i < ARRAY_SIZE(test_regs); i++)
for (j = 0; test_regs[i].ftr_bits[j].type != FTR_END; j++)
test_cnt++;
--
2.47.3
^ permalink raw reply related
* [PATCH v6 3/3] KVM: selftests: arm64: Make set_id_regs bitfield validatity checks non-fatal
From: Mark Brown @ 2026-07-19 19:24 UTC (permalink / raw)
To: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Paolo Bonzini,
Shuah Khan, Oliver Upton
Cc: Ben Horgan, linux-arm-kernel, kvmarm, kvm, linux-kselftest,
linux-kernel, Mark Brown
In-Reply-To: <20260719-kvm-arm64-set-id-regs-aarch64-v6-0-724287f5f108@kernel.org>
Currently when set_id_regs encounters a problem checking validation of
writes to feature registers it uses an immediately fatal assert to report
the problem. This is not idiomatic for kselftest, and it is also not great
for usability. The affected bitfield is not clearly reported and further
tests do not have their results reported.
Switch to using standard kselftest result reporting for the two asserts
we do, these are non-fatal asserts so allow the program to continue and the
test names include the affected field.
Reviewed-by: Ben Horgan <ben.horgan@arm.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
tools/testing/selftests/kvm/arm64/set_id_regs.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c
index 3aa8886e8b70..385e1f1c0133 100644
--- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
+++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
@@ -422,6 +422,7 @@ static u64 test_reg_set_success(struct kvm_vcpu *vcpu, u64 reg,
u8 shift = ftr_bits->shift;
u64 mask = ftr_bits->mask;
u64 val, new_val, ftr;
+ bool match;
val = vcpu_get_reg(vcpu, reg);
ftr = (val & mask) >> shift;
@@ -434,7 +435,10 @@ static u64 test_reg_set_success(struct kvm_vcpu *vcpu, u64 reg,
vcpu_set_reg(vcpu, reg, val);
new_val = vcpu_get_reg(vcpu, reg);
- TEST_ASSERT_EQ(new_val, val);
+ match = new_val == val;
+ if (!match)
+ ksft_print_msg("%lx != %lx\n", new_val, val);
+ ksft_test_result(match, "%s valid write succeeded\n", ftr_bits->name);
return new_val;
}
@@ -446,6 +450,7 @@ static void test_reg_set_fail(struct kvm_vcpu *vcpu, u64 reg,
u64 mask = ftr_bits->mask;
u64 val, old_val, ftr;
int r;
+ bool match;
val = vcpu_get_reg(vcpu, reg);
ftr = (val & mask) >> shift;
@@ -462,7 +467,10 @@ static void test_reg_set_fail(struct kvm_vcpu *vcpu, u64 reg,
"Unexpected KVM_SET_ONE_REG error: r=%d, errno=%d", r, errno);
val = vcpu_get_reg(vcpu, reg);
- TEST_ASSERT_EQ(val, old_val);
+ match = val == old_val;
+ if (!match)
+ ksft_print_msg("%lx != %lx\n", val, old_val);
+ ksft_test_result(match, "%s invalid write rejected\n", ftr_bits->name);
}
static u64 test_reg_vals[KVM_ARM_FEATURE_ID_RANGE_SIZE];
@@ -502,7 +510,11 @@ static void test_vm_ftr_id_regs(struct kvm_vcpu *vcpu, bool aarch64_only)
for (int j = 0; ftr_bits[j].type != FTR_END; j++) {
/* Skip aarch32 reg on aarch64 only system, since they are RAZ/WI. */
if (aarch64_only && sys_reg_CRm(reg_id) < 4) {
- ksft_test_result_skip("%s on AARCH64 only system\n",
+ ksft_print_msg("%s on AARCH64 only system\n",
+ ftr_bits[j].name);
+ ksft_test_result_skip("%s invalid write rejected\n",
+ ftr_bits[j].name);
+ ksft_test_result_skip("%s valid write succeeded\n",
ftr_bits[j].name);
continue;
}
@@ -514,8 +526,6 @@ static void test_vm_ftr_id_regs(struct kvm_vcpu *vcpu, bool aarch64_only)
test_reg_vals[idx] = test_reg_set_success(vcpu, reg,
&ftr_bits[j]);
-
- ksft_test_result_pass("%s\n", ftr_bits[j].name);
}
}
}
@@ -882,7 +892,7 @@ int main(void)
ID_REG_RESET_UNCHANGED_TEST;
for (i = 0; i < ARRAY_SIZE(test_regs); i++)
for (j = 0; test_regs[i].ftr_bits[j].type != FTR_END; j++)
- test_cnt++;
+ test_cnt += 2;
ksft_set_plan(test_cnt);
--
2.47.3
^ permalink raw reply related
* Re: [PATCH v7 2/3] iommu/arm-smmu-v3: Introduce CFGI/TLBI-repeat workaround infrastructure
From: Nicolin Chen @ 2026-07-19 20:37 UTC (permalink / raw)
To: Jason Gunthorpe
Cc: Ashish Mhetre, catalin.marinas, will, corbet, skhan, robin.murphy,
joro, linux-arm-kernel, linux-doc, linux-kernel, iommu,
linux-tegra
In-Reply-To: <20260718164548.GI701389@ziepe.ca>
On Sat, Jul 18, 2026 at 01:45:48PM -0300, Jason Gunthorpe wrote:
> On Fri, Jul 17, 2026 at 02:16:53PM -0700, Nicolin Chen wrote:
> > Given the use cases on Tegra264, instead of patching the iommufd
> > path as this patch does, perhaps we should simply spit a WARN in
> > arm_vsmmu_init():
>
> Nope, in this case you need to make the errata discoverable through
> the viommu info so the VMM can validate the right DT is used, or apply
> the WAR itself before submitting commands to the kernel.
OK.
> Some kind of new flag in the viommu struct I guess
struct iommu_hw_info_arm_smmuv3 has an unused "flags" field:
/**
* enum iommu_hw_info_smmuv3_flags - Flags for ARM SMMUv3 hw_info
* @IOMMU_HW_INFO_SMMUV3_ERRATA_REPEAT_TLBI_CFGI: If set, user space must issue
* TLBI/CFGI+SYNC commands twice
* due to a hardware erratum:
* <link-to-erratum>
*/
enum iommu_hw_info_smmuv3_flags {
IOMMU_HW_INFO_SMMUV3_ERRATA_REPEAT_TLBI_CFGI = 1 << 0,
};
Thanks
Nicolin
^ permalink raw reply
* Re: [PATCH v8 0/9] iommu/arm-smmu-v3: Adopt the crashed kernel's stream table for kdump
From: Nicolin Chen @ 2026-07-19 20:59 UTC (permalink / raw)
To: Jason Gunthorpe
Cc: Pranjal Shrivastava, will, robin.murphy, joro, kevin.tian,
smostafa, linux-arm-kernel, iommu, linux-kernel, jamien
In-Reply-To: <20260718162052.GF699082@nvidia.com>
On Sat, Jul 18, 2026 at 01:20:52PM -0300, Jason Gunthorpe wrote:
> On Fri, Jul 17, 2026 at 09:43:24PM +0000, Pranjal Shrivastava wrote:
>
> > However, looking at your approach, I think I can slightly rework my
> > preservation logic and instead of bloating the KHO ABI with physical
> > addresses, I could re-use your exact table-walking logic during probe
> > to parse the live L1/L2 structures directly from registers, identify
> > the valid tables, and kho/dma_restore them. There could me small
> > differences though, for example instead of memremap stuff, we'd have to
> > use the kho/dma_restore API (which can be done by passing some op like
> > the data structure writers we have?) Similarly, maybe reserving ASID/VMID
> > can be potentially re-used as well..
>
> I think this will be true for all the iommu drivers as they pretty
> much all have this same kind of kdumpish adoption logic in one way or
> another.
>
> > for KHO), I wanted to start a discussion to see if it makes sense to
> > factor this common code out into an arm-smmu-v3-kexec.c (or similar)?
>
> Yeah maybe so
>
> It sounds great this helps the live update project as well!
I agree. I think the final layout can be:
# Kconfig
config ARM_SMMU_V3_KEXEC
- def_bool CRASH_DUMP
+ def_bool CRASH_DUMP || IOMMU_LIVEUPDATE
# Makefile
arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_KEXEC) += arm-smmu-v3-kexec.o
arm_smmu_v3-$(CONFIG_CRASH_DUMP) += arm-smmu-v3-kdump.o
+arm_smmu_v3-$(CONFIG_IOMMU_LIVEUPDATE) += arm-smmu-v3-liveupdate.o
Nicolin
^ permalink raw reply
* Re: [PATCH] clk: sunxi-ng: div: implement set_rate_and_parent
From: Juan Manuel @ 2026-07-19 21:09 UTC (permalink / raw)
To: wens
Cc: Michael Turquette, Stephen Boyd, Jernej Skrabec, Samuel Holland,
Brian Masney, linux-clk, linux-arm-kernel, linux-sunxi,
linux-kernel, André Przywara
In-Reply-To: <CAGb2v64Mdq-+C2e6GGHEN_n_H6QEEd66zp6O2W9y--58L=5yzQ@mail.gmail.com>
> Reviewed-by: Chen-Yu Tsai <wens@kernel.org>
Thanks a lot for the quick review!
> So the patch itself is OK, but I think there is also something wrong
> with the GPU mod clock. The GPU clock is not a standard divider, but
> actually a fractional one. The formula for the output is
>
> Clock Source * ((16-M)/16)
>
> with M being 0~15.
You were right, and it was worse than I expected. I checked the T527
user manual (v0.92, section 2.7.6.58: "FACTOR_M: mask M cycles at 16
cycles") and then measured it on the Orange Pi 4A, forcing each OPP
and reading the real GPU frequency with the Mali cycle counter. With
the current linear model:
OPP request programmed measured
150 MHz 600M, M=3 ~487 MHz
200 MHz 800M, M=3 648 MHz
300 MHz 600M, M=1 560 MHz
400 MHz 800M, M=1 749 MHz
600 MHz 600M, M=0 599 MHz
so every OPP below 600 MHz silently overclocks (thermal throttling to
"400 MHz" actually raises the clock to 750 MHz). Interestingly the
vendor BSP models this register as a linear divider too, so the
vendor kernel has the same mislabelling; it also removed the 800M
parent from its parent list citing GPU job faults.
I have a fix working: a small ccu type implementing the cycle-masking
semantics, with the A523 GPU clock switched over to it, the 800M
parent dropped from the selectable parents, and the OPP table for the
Orange Pi 4A. Re-measured with the same cycle-counter method the five
OPPs now come out at 149/199/300/399/597 MHz from the intended
parents. I'll send it as a follow-up series referencing this thread.
> And we're also missing a notifier to switch the GPU clock away from
> the PLL while the PLL is being changed.
Agreed — the series also registers the existing sunxi-ng mux notifier
on pll-gpu (cpux precedent), parking the GPU on pll-periph0-600M
during PLL rate changes. The manual states the mux switch is
glitch-free. Nothing retunes pll-gpu at runtime yet with the standard
OPPs, but the higher speed-bin operating points (648-792 MHz) will
need it as a live parent.
> Do you plan on implementing GPU DVFS on mainline?
Yes — see above; the series is on its way. The speed-bin OPPs (SID
efuse gated) are left for a follow-up. Happy to test any related
series on this board in the meantime.
Juan Manuel
^ permalink raw reply
* [PATCH v1 0/4] clk: sunxi-ng: fix the A523/T527 GPU clock model, enable GPU DVFS
From: Juan Manuel López Carrillo @ 2026-07-19 21:13 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Chen-Yu Tsai, Jernej Skrabec,
Samuel Holland
Cc: Brian Masney, Andre Przywara, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-clk, linux-sunxi, linux-arm-kernel,
devicetree, linux-kernel, Juan Manuel López Carrillo
This series follows up on the discussion in [1], where Chen-Yu pointed
out that the A523/T527 GPU mod clock is not a standard divider but a
fractional one: GPU_CLK = Clock Source * ((16-M)/16), with M 0-15.
I checked this against the T527 user manual (v0.92, section 2.7.6.58,
"FACTOR_M: mask M cycles at 16 cycles") and verified it on hardware:
with the current linear model, forcing each OPP on an Orange Pi 4A and
measuring the real GPU frequency with the Mali cycle counter gives
OPP request programmed measured
150 MHz 600M, M=3 ~487 MHz
200 MHz 800M, M=3 648 MHz
300 MHz 600M, M=1 560 MHz
400 MHz 800M, M=1 749 MHz
600 MHz 600M, M=0 599 MHz
so every OPP below 600 MHz silently overclocks, up to 25% above the
vendor ceiling, and thermal throttling to "400 MHz" actually raises
the GPU frequency.
Patch 1 adds a small ccu type implementing the cycle-masking
semantics. Patch 2 switches the A523 GPU clock to it, drops
pll-periph0-800M from the selectable parents (the vendor BSP removed
it citing GPU job faults) and drops CLK_SET_RATE_PARENT (pll-gpu loses
its CLK_SET_RATE_GATE protection once the GPU runs from a periph
output). Patch 3 registers the existing sunxi-ng mux notifier so the
GPU is parked on pll-periph0-600M while pll-gpu changes rate, as
Chen-Yu suggested in the same thread. Patch 4 adds the BSP operating
points to the Orange Pi 4A DT, which enables panfrost devfreq.
With the series applied the same cycle-counter measurement reads
149/199/300/399/597 MHz for the five OPPs, all from the intended
parents, and devfreq scaling plus thermal throttling (emulated
temperature) behave correctly under load.
The higher speed-bin operating points of the BSP (648-792 MHz, gated
by a SID efuse bin, running from pll-gpu) are left for a follow-up.
[1] https://lore.kernel.org/linux-sunxi/20260719153122.892013-1-juanmanuellopezcarrillo@gmail.com/
Juan Manuel López Carrillo (4):
clk: sunxi-ng: add cycle-masking divider (maskdiv) clock type
clk: sunxi-ng: sun55i-a523: GPU clock divider is fractional, not
linear
clk: sunxi-ng: sun55i-a523: reparent GPU while pll-gpu changes rate
arm64: dts: allwinner: t527-orangepi-4a: add GPU OPP table
.../dts/allwinner/sun55i-t527-orangepi-4a.dts | 30 +++
drivers/clk/sunxi-ng/Makefile | 1 +
drivers/clk/sunxi-ng/ccu-sun55i-a523.c | 47 ++++-
drivers/clk/sunxi-ng/ccu_maskdiv.c | 199 ++++++++++++++++++
drivers/clk/sunxi-ng/ccu_maskdiv.h | 71 +++++++
5 files changed, 342 insertions(+), 6 deletions(-)
create mode 100644 drivers/clk/sunxi-ng/ccu_maskdiv.c
create mode 100644 drivers/clk/sunxi-ng/ccu_maskdiv.h
--
2.47.3
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox