From: David Yang <mmyangfl@gmail.com>
To: netdev@vger.kernel.org
Cc: David Yang <mmyangfl@gmail.com>, Andrew Lunn <andrew@lunn.ch>,
Vladimir Oltean <olteanv@gmail.com>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
linux-kernel@vger.kernel.org
Subject: [RFC net-next 2/4] net: dsa: motorcomm: Split SMI module
Date: Fri, 19 Jun 2026 04:26:30 +0800 [thread overview]
Message-ID: <20260618202716.2166450-3-mmyangfl@gmail.com> (raw)
In-Reply-To: <20260618202716.2166450-1-mmyangfl@gmail.com>
SMI operations is going to be used across different modules.
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/motorcomm/Makefile | 1 +
drivers/net/dsa/motorcomm/chip.c | 207 +----------------------------
drivers/net/dsa/motorcomm/smi.c | 155 +++++++++++++++++++++
drivers/net/dsa/motorcomm/smi.h | 88 ++++++++++++
4 files changed, 245 insertions(+), 206 deletions(-)
create mode 100644 drivers/net/dsa/motorcomm/smi.c
create mode 100644 drivers/net/dsa/motorcomm/smi.h
diff --git a/drivers/net/dsa/motorcomm/Makefile b/drivers/net/dsa/motorcomm/Makefile
index bf99feb4c454..9fa24929007c 100644
--- a/drivers/net/dsa/motorcomm/Makefile
+++ b/drivers/net/dsa/motorcomm/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o
yt921x-objs := chip.o
+yt921x-objs += smi.o
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index f070732845eb..6dee25b6754a 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -13,7 +13,6 @@
#include <linux/if_bridge.h>
#include <linux/if_hsr.h>
#include <linux/if_vlan.h>
-#include <linux/iopoll.h>
#include <linux/mdio.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -27,6 +26,7 @@
#include <net/pkt_cls.h>
#include "chip.h"
+#include "smi.h"
struct yt921x_mib_desc {
unsigned int size;
@@ -155,9 +155,6 @@ static const struct yt921x_info yt921x_infos[] = {
#define YT921X_VID_UNWARE 4095
-#define YT921X_POLL_SLEEP_US 10000
-#define YT921X_POLL_TIMEOUT_US 100000
-
/* The interval should be small enough to avoid overflow of 32bit MIBs.
*
* Until we can read MIBs from stats64 call directly (i.e. sleep
@@ -196,208 +193,6 @@ static u32 ethaddr_lo2_to_u32(const unsigned char *addr)
return (addr[4] << 8) | addr[5];
}
-static int yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp)
-{
- WARN_ON(!mutex_is_locked(&priv->reg_lock));
-
- return priv->reg_ops->read(priv->reg_ctx, reg, valp);
-}
-
-static int yt921x_reg_write(struct yt921x_priv *priv, u32 reg, u32 val)
-{
- WARN_ON(!mutex_is_locked(&priv->reg_lock));
-
- return priv->reg_ops->write(priv->reg_ctx, reg, val);
-}
-
-static int
-yt921x_reg_wait(struct yt921x_priv *priv, u32 reg, u32 mask, u32 *valp)
-{
- u32 val;
- int res;
- int ret;
-
- ret = read_poll_timeout(yt921x_reg_read, res,
- res || (val & mask) == *valp,
- YT921X_POLL_SLEEP_US, YT921X_POLL_TIMEOUT_US,
- false, priv, reg, &val);
- if (ret)
- return ret;
- if (res)
- return res;
-
- *valp = val;
- return 0;
-}
-
-static int
-yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask, u32 val)
-{
- int res;
- u32 v;
- u32 u;
-
- res = yt921x_reg_read(priv, reg, &v);
- if (res)
- return res;
-
- u = v;
- u &= ~mask;
- u |= val;
- if (u == v)
- return 0;
-
- return yt921x_reg_write(priv, reg, u);
-}
-
-static int yt921x_reg_set_bits(struct yt921x_priv *priv, u32 reg, u32 mask)
-{
- return yt921x_reg_update_bits(priv, reg, 0, mask);
-}
-
-static int yt921x_reg_clear_bits(struct yt921x_priv *priv, u32 reg, u32 mask)
-{
- return yt921x_reg_update_bits(priv, reg, mask, 0);
-}
-
-static int
-yt921x_reg_toggle_bits(struct yt921x_priv *priv, u32 reg, u32 mask, bool set)
-{
- return yt921x_reg_update_bits(priv, reg, mask, !set ? 0 : mask);
-}
-
-/* Some multi-word registers, like VLANn_CTRL, should be treated as a single
- * long register. More specifically, writes to parts of its words won't become
- * visible, until the last word is written.
- *
- * Here we require full read and write operations over these registers to
- * eliminate potential issues, although partial reads/writes are also possible.
- */
-
-static void update_ctrls_unaligned(u32 *lo, u32 *hi, u64 mask, u64 val)
-{
- *lo &= ~lower_32_bits(mask);
- *hi &= ~upper_32_bits(mask);
- *lo |= lower_32_bits(val);
- *hi |= upper_32_bits(val);
-}
-
-static int
-yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
- unsigned int num_regs)
-{
- int res;
-
- for (unsigned int i = 0; i < num_regs; i++) {
- res = yt921x_reg_read(priv, reg + 4 * i, &vals[i]);
- if (res)
- return res;
- }
-
- return 0;
-}
-
-static int
-yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,
- unsigned int num_regs)
-{
- int res;
-
- for (unsigned int i = 0; i < num_regs; i++) {
- res = yt921x_reg_write(priv, reg + 4 * i, vals[i]);
- if (res)
- return res;
- }
-
- return 0;
-}
-
-static int
-yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
- const u32 *vals, unsigned int num_regs)
-{
- bool changed = false;
- u32 vs[4];
- int res;
-
- BUILD_BUG_ON(num_regs > ARRAY_SIZE(vs));
-
- res = yt921x_regs_read(priv, reg, vs, num_regs);
- if (res)
- return res;
-
- for (unsigned int i = 0; i < num_regs; i++) {
- u32 u = vs[i];
-
- u &= ~masks[i];
- u |= vals[i];
- if (u != vs[i])
- changed = true;
-
- vs[i] = u;
- }
-
- if (!changed)
- return 0;
-
- return yt921x_regs_write(priv, reg, vs, num_regs);
-}
-
-static int
-yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
- unsigned int num_regs)
-{
- bool changed = false;
- u32 vs[4];
- int res;
-
- BUILD_BUG_ON(num_regs > ARRAY_SIZE(vs));
-
- res = yt921x_regs_read(priv, reg, vs, num_regs);
- if (res)
- return res;
-
- for (unsigned int i = 0; i < num_regs; i++) {
- u32 u = vs[i];
-
- u &= ~masks[i];
- if (u != vs[i])
- changed = true;
-
- vs[i] = u;
- }
-
- if (!changed)
- return 0;
-
- return yt921x_regs_write(priv, reg, vs, num_regs);
-}
-
-static int
-yt921x_reg64_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
-{
- return yt921x_regs_write(priv, reg, vals, 2);
-}
-
-static int
-yt921x_reg64_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
- const u32 *vals)
-{
- return yt921x_regs_update_bits(priv, reg, masks, vals, 2);
-}
-
-static int
-yt921x_reg64_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks)
-{
- return yt921x_regs_clear_bits(priv, reg, masks, 2);
-}
-
-static int
-yt921x_reg96_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
-{
- return yt921x_regs_write(priv, reg, vals, 3);
-}
-
static int yt921x_reg_mdio_read(void *context, u32 reg, u32 *valp)
{
struct yt921x_reg_mdio *mdio = context;
diff --git a/drivers/net/dsa/motorcomm/smi.c b/drivers/net/dsa/motorcomm/smi.c
new file mode 100644
index 000000000000..93e6c0f7e562
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/smi.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#include <linux/iopoll.h>
+
+#include "chip.h"
+#include "smi.h"
+
+#define YT921X_POLL_SLEEP_US 10000
+#define YT921X_POLL_TIMEOUT_US 100000
+
+int yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp)
+{
+ WARN_ON(!mutex_is_locked(&priv->reg_lock));
+
+ return priv->reg_ops->read(priv->reg_ctx, reg, valp);
+}
+
+int yt921x_reg_write(struct yt921x_priv *priv, u32 reg, u32 val)
+{
+ WARN_ON(!mutex_is_locked(&priv->reg_lock));
+
+ return priv->reg_ops->write(priv->reg_ctx, reg, val);
+}
+
+int yt921x_reg_wait(struct yt921x_priv *priv, u32 reg, u32 mask, u32 *valp)
+{
+ u32 val;
+ int res;
+ int ret;
+
+ ret = read_poll_timeout(yt921x_reg_read, res,
+ res || (val & mask) == *valp,
+ YT921X_POLL_SLEEP_US, YT921X_POLL_TIMEOUT_US,
+ false, priv, reg, &val);
+ if (ret)
+ return ret;
+ if (res)
+ return res;
+
+ *valp = val;
+ return 0;
+}
+
+int yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask, u32 val)
+{
+ int res;
+ u32 v;
+ u32 u;
+
+ res = yt921x_reg_read(priv, reg, &v);
+ if (res)
+ return res;
+
+ u = v;
+ u &= ~mask;
+ u |= val;
+ if (u == v)
+ return 0;
+
+ return yt921x_reg_write(priv, reg, u);
+}
+
+int
+yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
+ unsigned int num_regs)
+{
+ int res;
+
+ for (unsigned int i = 0; i < num_regs; i++) {
+ res = yt921x_reg_read(priv, reg + 4 * i, &vals[i]);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+int
+yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,
+ unsigned int num_regs)
+{
+ int res;
+
+ for (unsigned int i = 0; i < num_regs; i++) {
+ res = yt921x_reg_write(priv, reg + 4 * i, vals[i]);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+int
+yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+ const u32 *vals, unsigned int num_regs)
+{
+ bool changed = false;
+ u32 vs[4];
+ int res;
+
+ WARN_ON_ONCE(num_regs > ARRAY_SIZE(vs));
+
+ res = yt921x_regs_read(priv, reg, vs, num_regs);
+ if (res)
+ return res;
+
+ for (unsigned int i = 0; i < num_regs; i++) {
+ u32 u = vs[i];
+
+ u &= ~masks[i];
+ u |= vals[i];
+ if (u != vs[i])
+ changed = true;
+
+ vs[i] = u;
+ }
+
+ if (!changed)
+ return 0;
+
+ return yt921x_regs_write(priv, reg, vs, num_regs);
+}
+
+int
+yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+ unsigned int num_regs)
+{
+ bool changed = false;
+ u32 vs[4];
+ int res;
+
+ WARN_ON_ONCE(num_regs > ARRAY_SIZE(vs));
+
+ res = yt921x_regs_read(priv, reg, vs, num_regs);
+ if (res)
+ return res;
+
+ for (unsigned int i = 0; i < num_regs; i++) {
+ u32 u = vs[i];
+
+ u &= ~masks[i];
+ if (u != vs[i])
+ changed = true;
+
+ vs[i] = u;
+ }
+
+ if (!changed)
+ return 0;
+
+ return yt921x_regs_write(priv, reg, vs, num_regs);
+}
diff --git a/drivers/net/dsa/motorcomm/smi.h b/drivers/net/dsa/motorcomm/smi.h
new file mode 100644
index 000000000000..2e956065eb90
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/smi.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#ifndef _YT_SMI_H
+#define _YT_SMI_H
+
+#include <linux/types.h>
+#include <linux/wordpart.h>
+
+struct yt921x_priv;
+
+int yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp);
+int yt921x_reg_write(struct yt921x_priv *priv, u32 reg, u32 val);
+int yt921x_reg_wait(struct yt921x_priv *priv, u32 reg, u32 mask, u32 *valp);
+int yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask,
+ u32 val);
+
+static inline int
+yt921x_reg_set_bits(struct yt921x_priv *priv, u32 reg, u32 mask)
+{
+ return yt921x_reg_update_bits(priv, reg, 0, mask);
+}
+
+static inline int
+yt921x_reg_clear_bits(struct yt921x_priv *priv, u32 reg, u32 mask)
+{
+ return yt921x_reg_update_bits(priv, reg, mask, 0);
+}
+
+static inline int
+yt921x_reg_toggle_bits(struct yt921x_priv *priv, u32 reg, u32 mask, bool set)
+{
+ return yt921x_reg_update_bits(priv, reg, mask, !set ? 0 : mask);
+}
+
+/* Some multi-word registers, like VLANn_CTRL, should be treated as a single
+ * long register. More specifically, writes to parts of its words won't become
+ * visible, until the last word is written.
+ *
+ * Here we require full read and write operations over these registers to
+ * eliminate potential issues, although partial reads/writes are also possible.
+ */
+
+static inline void update_ctrls_unaligned(u32 *lo, u32 *hi, u64 mask, u64 val)
+{
+ *lo &= ~lower_32_bits(mask);
+ *hi &= ~upper_32_bits(mask);
+ *lo |= lower_32_bits(val);
+ *hi |= upper_32_bits(val);
+}
+
+int yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
+ unsigned int num_regs);
+int yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,
+ unsigned int num_regs);
+int yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+ const u32 *vals, unsigned int num_regs);
+int yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+ unsigned int num_regs);
+
+static inline int
+yt921x_reg64_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
+{
+ return yt921x_regs_write(priv, reg, vals, 2);
+}
+
+static inline int
+yt921x_reg64_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+ const u32 *vals)
+{
+ return yt921x_regs_update_bits(priv, reg, masks, vals, 2);
+}
+
+static inline int
+yt921x_reg64_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks)
+{
+ return yt921x_regs_clear_bits(priv, reg, masks, 2);
+}
+
+static inline int
+yt921x_reg96_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
+{
+ return yt921x_regs_write(priv, reg, vals, 3);
+}
+
+#endif
--
2.53.0
next prev parent reply other threads:[~2026-06-18 20:27 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-18 20:26 [RFC net-next 0/4] net: dsa: motorcomm: Add LED support David Yang
2026-06-18 20:26 ` [RFC net-next 1/4] net: dsa: motorcomm: Move to subdirectory David Yang
2026-06-18 20:26 ` David Yang [this message]
2026-06-18 20:26 ` [RFC net-next 3/4] net: dsa: motorcomm: Dynamically allocate port structures David Yang
2026-06-18 20:26 ` [RFC net-next 4/4] net: dsa: motorcomm: Add LED support David Yang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260618202716.2166450-3-mmyangfl@gmail.com \
--to=mmyangfl@gmail.com \
--cc=andrew@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=olteanv@gmail.com \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox