]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: dsa: yt921x: Refactor long register helpers
authorDavid Yang <mmyangfl@gmail.com>
Thu, 30 Apr 2026 11:45:25 +0000 (19:45 +0800)
committerJakub Kicinski <kuba@kernel.org>
Sat, 2 May 2026 17:38:58 +0000 (10:38 -0700)
Dealing long registers with u64 is good, until you realize there are
longer 96-bit registers.

Refactor reg64 helpers to use u32 arrays instead of u64 values, in
preparation for 96-bit registers. We do not keep the separate u64
version for reg64 to avoid duplicated wrappers, although it looks better
when dealing with reg64 *only*.

Helpers for reg96 should be added when they are actually used to avoid
function unused warnings.

Signed-off-by: David Yang <mmyangfl@gmail.com>
Link: https://patch.msgid.link/20260430114529.3536911-3-mmyangfl@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/dsa/yt921x.c
drivers/net/dsa/yt921x.h

index 5b66109ecc235daf182588477498bde5a7453f31..c9ae95704fdc8fcf8069842860197f0c878c5596 100644 (file)
@@ -255,63 +255,122 @@ 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 registers, like VLANn_CTRL, should always be written in 64-bit, even if
- * you are to write only the lower / upper 32 bits.
+/* 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.
  *
- * There is no such restriction for reading, but we still provide 64-bit read
- * wrappers so that we always handle u64 values.
+ * Here we require full read and write operations over these registers to
+ * eliminate potential issues, although partial reads/writes are also possible.
  */
 
-static int yt921x_reg64_read(struct yt921x_priv *priv, u32 reg, u64 *valp)
+static int
+yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
+                unsigned int num_regs)
 {
-       u32 lo;
-       u32 hi;
        int res;
 
-       res = yt921x_reg_read(priv, reg, &lo);
-       if (res)
-               return res;
-       res = yt921x_reg_read(priv, reg + 4, &hi);
-       if (res)
-               return 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;
+       }
 
-       *valp = ((u64)hi << 32) | lo;
        return 0;
 }
 
-static int yt921x_reg64_write(struct yt921x_priv *priv, u32 reg, u64 val)
+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;
 
-       res = yt921x_reg_write(priv, reg, (u32)val);
+       BUILD_BUG_ON(num_regs > ARRAY_SIZE(vs));
+
+       res = yt921x_regs_read(priv, reg, vs, num_regs);
        if (res)
                return res;
-       return yt921x_reg_write(priv, reg + 4, (u32)(val >> 32));
+
+       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_reg64_update_bits(struct yt921x_priv *priv, u32 reg, u64 mask, u64 val)
+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;
-       u64 v;
-       u64 u;
 
-       res = yt921x_reg64_read(priv, reg, &v);
+       BUILD_BUG_ON(num_regs > ARRAY_SIZE(vs));
+
+       res = yt921x_regs_read(priv, reg, vs, num_regs);
        if (res)
                return res;
 
-       u = v;
-       u &= ~mask;
-       u |= val;
-       if (u == v)
+       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_reg64_write(priv, reg, u);
+       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_clear_bits(struct yt921x_priv *priv, u32 reg, u64 mask)
+static int
+yt921x_reg64_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+                        const u32 *vals)
 {
-       return yt921x_reg64_update_bits(priv, reg, mask, 0);
+       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_reg_mdio_read(void *context, u32 reg, u32 *valp)
@@ -1844,33 +1903,31 @@ yt921x_vlan_filtering(struct yt921x_priv *priv, int port, bool vlan_filtering)
        return 0;
 }
 
-static int
-yt921x_vlan_del(struct yt921x_priv *priv, int port, u16 vid)
+static int yt921x_vlan_del(struct yt921x_priv *priv, int port, u16 vid)
 {
-       u64 mask64;
+       u32 masks[2];
 
-       mask64 = YT921X_VLAN_CTRL_PORTS(port) |
-                YT921X_VLAN_CTRL_UNTAG_PORTn(port);
+       masks[0] = YT921X_VLAN_CTRLa_PORTn(port);
+       masks[1] = YT921X_VLAN_CTRLb_UNTAG_PORTn(port);
 
-       return yt921x_reg64_clear_bits(priv, YT921X_VLANn_CTRL(vid), mask64);
+       return yt921x_reg64_clear_bits(priv, YT921X_VLANn_CTRL(vid), masks);
 }
 
 static int
 yt921x_vlan_add(struct yt921x_priv *priv, int port, u16 vid, bool untagged)
 {
-       u64 mask64;
-       u64 ctrl64;
+       u32 masks[2];
+       u32 ctrls[2];
 
-       mask64 = YT921X_VLAN_CTRL_PORTn(port) |
-                YT921X_VLAN_CTRL_PORTS(priv->cpu_ports_mask);
-       ctrl64 = mask64;
+       masks[0] = YT921X_VLAN_CTRLa_PORTn(port) |
+                  YT921X_VLAN_CTRLa_PORTS(priv->cpu_ports_mask);
+       ctrls[0] = masks[0];
 
-       mask64 |= YT921X_VLAN_CTRL_UNTAG_PORTn(port);
-       if (untagged)
-               ctrl64 |= YT921X_VLAN_CTRL_UNTAG_PORTn(port);
+       masks[1] = YT921X_VLAN_CTRLb_UNTAG_PORTn(port);
+       ctrls[1] = untagged ? masks[1] : 0;
 
        return yt921x_reg64_update_bits(priv, YT921X_VLANn_CTRL(vid),
-                                       mask64, ctrl64);
+                                       masks, ctrls);
 }
 
 static int
@@ -2318,8 +2375,8 @@ yt921x_dsa_vlan_msti_set(struct dsa_switch *ds, struct dsa_bridge bridge,
                         const struct switchdev_vlan_msti *msti)
 {
        struct yt921x_priv *priv = to_yt921x_priv(ds);
-       u64 mask64;
-       u64 ctrl64;
+       u32 masks[2];
+       u32 ctrls[2];
        int res;
 
        if (!msti->vid)
@@ -2327,12 +2384,14 @@ yt921x_dsa_vlan_msti_set(struct dsa_switch *ds, struct dsa_bridge bridge,
        if (!msti->msti || msti->msti >= YT921X_MSTI_NUM)
                return -EINVAL;
 
-       mask64 = YT921X_VLAN_CTRL_STP_ID_M;
-       ctrl64 = YT921X_VLAN_CTRL_STP_ID(msti->msti);
+       masks[0] = 0;
+       ctrls[0] = 0;
+       masks[1] = YT921X_VLAN_CTRLb_STP_ID_M;
+       ctrls[1] = YT921X_VLAN_CTRLb_STP_ID(msti->msti);
 
        mutex_lock(&priv->reg_lock);
        res = yt921x_reg64_update_bits(priv, YT921X_VLANn_CTRL(msti->vid),
-                                      mask64, ctrl64);
+                                      masks, ctrls);
        mutex_unlock(&priv->reg_lock);
 
        return res;
@@ -3083,7 +3142,7 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)
 {
        struct dsa_switch *ds = &priv->ds;
        unsigned long cpu_ports_mask;
-       u64 ctrl64;
+       u32 ctrls[2];
        u32 ctrl;
        int port;
        int res;
@@ -3144,8 +3203,9 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)
        /* Tagged VID 0 should be treated as untagged, which confuses the
         * hardware a lot
         */
-       ctrl64 = YT921X_VLAN_CTRL_LEARN_DIS | YT921X_VLAN_CTRL_PORTS_M;
-       res = yt921x_reg64_write(priv, YT921X_VLANn_CTRL(0), ctrl64);
+       ctrls[0] = YT921X_VLAN_CTRLa_LEARN_DIS | YT921X_VLAN_CTRLa_PORTS_M;
+       ctrls[1] = 0;
+       res = yt921x_reg64_write(priv, YT921X_VLANn_CTRL(0), ctrls);
        if (res)
                return res;
 
index 3f129b8d403fa6e8a30ea8d9c6024ea7081b9e53..4989d87c2492e67fd9d7d959aa3aafdae33083a9 100644 (file)
@@ -429,24 +429,24 @@ enum yt921x_app_selector {
 #define  YT921X_FDB_HW_FLUSH_ON_LINKDOWN       BIT(0)
 
 #define YT921X_VLANn_CTRL(vlan)                (0x188000 + 8 * (vlan))
-#define  YT921X_VLAN_CTRL_UNTAG_PORTS_M                GENMASK_ULL(50, 40)
-#define   YT921X_VLAN_CTRL_UNTAG_PORTS(x)              FIELD_PREP(YT921X_VLAN_CTRL_UNTAG_PORTS_M, (x))
-#define  YT921X_VLAN_CTRL_UNTAG_PORTn(port)    BIT_ULL((port) + 40)
-#define  YT921X_VLAN_CTRL_STP_ID_M             GENMASK_ULL(39, 36)
-#define   YT921X_VLAN_CTRL_STP_ID(x)                   FIELD_PREP(YT921X_VLAN_CTRL_STP_ID_M, (x))
-#define  YT921X_VLAN_CTRL_SVLAN_EN             BIT_ULL(35)
-#define  YT921X_VLAN_CTRL_FID_M                        GENMASK_ULL(34, 23)
-#define   YT921X_VLAN_CTRL_FID(x)                      FIELD_PREP(YT921X_VLAN_CTRL_FID_M, (x))
-#define  YT921X_VLAN_CTRL_LEARN_DIS            BIT_ULL(22)
-#define  YT921X_VLAN_CTRL_PRIO_EN              BIT_ULL(21)
-#define  YT921X_VLAN_CTRL_PRIO_M               GENMASK_ULL(20, 18)
-#define   YT921X_VLAN_CTRL_PRIO(x)                     FIELD_PREP(YT921X_VLAN_CTRL_PRIO_M, (x))
-#define  YT921X_VLAN_CTRL_PORTS_M              GENMASK_ULL(17, 7)
-#define   YT921X_VLAN_CTRL_PORTS(x)                    FIELD_PREP(YT921X_VLAN_CTRL_PORTS_M, (x))
-#define  YT921X_VLAN_CTRL_PORTn(port)          BIT_ULL((port) + 7)
-#define  YT921X_VLAN_CTRL_BYPASS_1X_AC         BIT_ULL(6)
-#define  YT921X_VLAN_CTRL_METER_EN             BIT_ULL(5)
-#define  YT921X_VLAN_CTRL_METER_ID_M           GENMASK_ULL(4, 0)
+#define  YT921X_VLAN_CTRLb_UNTAG_PORTS_M       GENMASK(18, 8)
+#define   YT921X_VLAN_CTRLb_UNTAG_PORTS(x)             FIELD_PREP(YT921X_VLAN_CTRLb_UNTAG_PORTS_M, (x))
+#define  YT921X_VLAN_CTRLb_UNTAG_PORTn(port)   BIT((port) + 8)
+#define  YT921X_VLAN_CTRLb_STP_ID_M            GENMASK(7, 4)
+#define   YT921X_VLAN_CTRLb_STP_ID(x)                  FIELD_PREP(YT921X_VLAN_CTRLb_STP_ID_M, (x))
+#define  YT921X_VLAN_CTRLb_SVLAN_EN            BIT(3)
+#define  YT921X_VLAN_CTRLab_FID_M              GENMASK_ULL(34, 23)
+#define   YT921X_VLAN_CTRLab_FID(x)                    FIELD_PREP(YT921X_VLAN_CTRLab_FID_M, (x))
+#define  YT921X_VLAN_CTRLa_LEARN_DIS           BIT(22)
+#define  YT921X_VLAN_CTRLa_PRIO_EN             BIT(21)
+#define  YT921X_VLAN_CTRLa_PRIO_M              GENMASK(20, 18)
+#define   YT921X_VLAN_CTRLa_PRIO(x)                    FIELD_PREP(YT921X_VLAN_CTRLa_PRIO_M, (x))
+#define  YT921X_VLAN_CTRLa_PORTS_M             GENMASK(17, 7)
+#define   YT921X_VLAN_CTRLa_PORTS(x)                   FIELD_PREP(YT921X_VLAN_CTRLa_PORTS_M, (x))
+#define  YT921X_VLAN_CTRLa_PORTn(port)         BIT((port) + 7)
+#define  YT921X_VLAN_CTRLa_BYPASS_1X_AC                BIT(6)
+#define  YT921X_VLAN_CTRLa_METER_EN            BIT(5)
+#define  YT921X_VLAN_CTRLa_METER_ID_M          GENMASK(4, 0)
 
 #define YT921X_TPID_IGRn(x)            (0x210000 + 4 * (x))    /* [0, 3] */
 #define  YT921X_TPID_IGR_TPID_M                        GENMASK(15, 0)