From: "Jens Emil Schulz Østergaard" <jensemil.schulzostergaard@microchip.com>
To: <UNGLinuxDriver@microchip.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>,
Simon Horman <horms@kernel.org>, Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Woojung Huh <woojung.huh@microchip.com>,
Russell King <linux@armlinux.org.uk>,
Steen Hegelund <Steen.Hegelund@microchip.com>,
Daniel Machon <daniel.machon@microchip.com>
Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
devicetree@vger.kernel.org,
"Jens Emil Schulz Østergaard"
<jensemil.schulzostergaard@microchip.com>
Subject: [PATCH net-next v3 6/9] net: dsa: lan9645x: add vlan support
Date: Fri, 10 Apr 2026 13:48:42 +0200 [thread overview]
Message-ID: <20260410-dsa_lan9645x_switch_driver_base-v3-6-aadc8595306d@microchip.com> (raw)
In-Reply-To: <20260410-dsa_lan9645x_switch_driver_base-v3-0-aadc8595306d@microchip.com>
Add support for vlanaware bridge. We reserve vid 4095 for standalone
mode, to implement fdb-isolation. A vlan-unaware bridge uses vid 0.
Reviewed-by: Steen Hegelund <Steen.Hegelund@microchip.com>
Signed-off-by: Jens Emil Schulz Østergaard <jensemil.schulzostergaard@microchip.com>
---
Changes in v3:
- use SET register macros in vlan_hw_wr
- add vlan id bounds check to vlan_del
- return vlan_hw_wr timeout err on init
- move cpu vlan action after bounds check
Changes in v2:
- redesign based on selftests which rely on changing vlan_default_pvid.
Our HW limitations were too forward. Following Vladimirs changes to
ocelot VLAN implementation, we now dynamically change egress tag
configuration, allowing more states.
- selftests are passing, except an expected failure w.r.t ctag/stag
conformance, which is a hw limitation.
---
drivers/net/dsa/microchip/lan9645x/Makefile | 1 +
drivers/net/dsa/microchip/lan9645x/lan9645x_main.c | 49 +++
drivers/net/dsa/microchip/lan9645x/lan9645x_main.h | 28 ++
drivers/net/dsa/microchip/lan9645x/lan9645x_port.c | 3 +
drivers/net/dsa/microchip/lan9645x/lan9645x_vlan.c | 378 +++++++++++++++++++++
5 files changed, 459 insertions(+)
diff --git a/drivers/net/dsa/microchip/lan9645x/Makefile b/drivers/net/dsa/microchip/lan9645x/Makefile
index 7cc0ae0ada40..e049114b3563 100644
--- a/drivers/net/dsa/microchip/lan9645x/Makefile
+++ b/drivers/net/dsa/microchip/lan9645x/Makefile
@@ -6,3 +6,4 @@ mchp-lan9645x-objs := \
lan9645x_npi.o \
lan9645x_phylink.o \
lan9645x_port.o \
+ lan9645x_vlan.o \
diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c
index e709396c2298..adbdf2007e9f 100644
--- a/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c
@@ -156,6 +156,9 @@ static int lan9645x_setup(struct dsa_switch *ds)
}
mutex_init(&lan9645x->fwd_domain_lock);
+ err = lan9645x_vlan_init(lan9645x);
+ if (err)
+ return err;
/* Link Aggregation Mode: NETDEV_LAG_HASH_L2 */
lan_wr(ANA_AGGR_CFG_AC_SMAC_ENA |
@@ -542,11 +545,52 @@ static void lan9645x_port_bridge_leave(struct dsa_switch *ds, int port,
lan9645x->bridge = NULL;
__lan9645x_port_set_host_flood(lan9645x, port);
+ lan9645x_vlan_set_hostmode(p);
lan9645x_update_fwd_mask(lan9645x);
mutex_unlock(&lan9645x->fwd_domain_lock);
}
+static int lan9645x_port_vlan_filtering(struct dsa_switch *ds, int port,
+ bool enabled,
+ struct netlink_ext_ack *extack)
+{
+ struct lan9645x *lan9645x = ds->priv;
+ struct lan9645x_port *p;
+
+ p = lan9645x_to_port(lan9645x, port);
+ p->vlan_aware = enabled;
+ lan9645x_vlan_port_apply(p);
+
+ return 0;
+}
+
+static int lan9645x_port_vlan_add(struct dsa_switch *ds, int port,
+ const struct switchdev_obj_port_vlan *vlan,
+ struct netlink_ext_ack *extack)
+{
+ struct lan9645x *lan9645x = ds->priv;
+ struct lan9645x_port *p;
+ bool pvid, untagged;
+
+ p = lan9645x_to_port(lan9645x, port);
+ pvid = !!(vlan->flags & BRIDGE_VLAN_INFO_PVID);
+ untagged = !!(vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED);
+
+ return lan9645x_vlan_port_add_vlan(p, vlan->vid, pvid, untagged,
+ extack);
+}
+
+static int lan9645x_port_vlan_del(struct dsa_switch *ds, int port,
+ const struct switchdev_obj_port_vlan *vlan)
+{
+ struct lan9645x *lan9645x = ds->priv;
+ struct lan9645x_port *p;
+
+ p = lan9645x_to_port(lan9645x, port);
+ return lan9645x_vlan_port_del_vlan(p, vlan->vid);
+}
+
static const struct dsa_switch_ops lan9645x_switch_ops = {
.get_tag_protocol = lan9645x_get_tag_protocol,
@@ -569,6 +613,11 @@ static const struct dsa_switch_ops lan9645x_switch_ops = {
.port_bridge_leave = lan9645x_port_bridge_leave,
.port_stp_state_set = lan9645x_port_bridge_stp_state_set,
.port_set_host_flood = lan9645x_port_set_host_flood,
+
+ /* VLAN integration */
+ .port_vlan_filtering = lan9645x_port_vlan_filtering,
+ .port_vlan_add = lan9645x_port_vlan_add,
+ .port_vlan_del = lan9645x_port_vlan_del,
};
static int lan9645x_request_target_regmaps(struct lan9645x *lan9645x)
diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_main.h b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.h
index 22576bb8dd52..3c6996e150e4 100644
--- a/drivers/net/dsa/microchip/lan9645x/lan9645x_main.h
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.h
@@ -7,6 +7,7 @@
#include <linux/dsa/lan9645x.h>
#include <linux/if_bridge.h>
+#include <linux/if_vlan.h>
#include <linux/regmap.h>
#include <net/dsa.h>
@@ -150,6 +151,17 @@ enum lan9645x_vlan_port_tag {
LAN9645X_TAG_ALL = 3,
};
+struct lan9645x_vlan {
+ u32 portmask: 10, /* ports 0-8 + CPU_PORT */
+ untagged: 9, /* ports 0-8 */
+ src_chk: 1,
+ mir: 1,
+ lrn_dis: 1,
+ prv_vlan: 1,
+ fld_dis: 1,
+ s_fwd_ena: 1;
+};
+
struct lan9645x {
struct device *dev;
struct dsa_switch *ds;
@@ -174,6 +186,9 @@ struct lan9645x {
u16 bridge_fwd_mask; /* Mask for forwarding bridged ports */
struct mutex fwd_domain_lock; /* lock forwarding configuration */
+ /* VLAN entries */
+ struct lan9645x_vlan vlans[VLAN_N_VID];
+
int num_port_dis;
bool dd_dis;
bool tsn_dis;
@@ -186,6 +201,9 @@ struct lan9645x_port {
u8 stp_state;
bool learn_ena;
+ bool vlan_aware;
+ u16 pvid;
+
bool rx_internal_delay;
bool tx_internal_delay;
};
@@ -349,4 +367,14 @@ void lan9645x_phylink_get_caps(struct lan9645x *lan9645x, int port,
struct phylink_config *c);
void lan9645x_phylink_port_down(struct lan9645x *lan9645x, int port);
+/* VLAN lan9645x_vlan.c */
+int lan9645x_vlan_init(struct lan9645x *lan9645x);
+u16 lan9645x_vlan_unaware_pvid(bool is_bridged);
+void lan9645x_vlan_port_apply(struct lan9645x_port *p);
+int lan9645x_vlan_port_add_vlan(struct lan9645x_port *p, u16 vid, bool pvid,
+ bool untagged,
+ struct netlink_ext_ack *extack);
+int lan9645x_vlan_port_del_vlan(struct lan9645x_port *p, u16 vid);
+void lan9645x_vlan_set_hostmode(struct lan9645x_port *p);
+
#endif /* __LAN9645X_MAIN_H__ */
diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_port.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_port.c
index 394a20ee678f..661cd00465e2 100644
--- a/drivers/net/dsa/microchip/lan9645x/lan9645x_port.c
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_port.c
@@ -189,5 +189,8 @@ int lan9645x_port_setup(struct dsa_switch *ds, int port)
ANA_PORT_CFG_PORTID_VAL,
lan9645x, ANA_PORT_CFG(p->chip_port));
+ if (p->chip_port != lan9645x->npi)
+ lan9645x_vlan_set_hostmode(p);
+
return 0;
}
diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_vlan.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_vlan.c
new file mode 100644
index 000000000000..c38e918a881d
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_vlan.c
@@ -0,0 +1,378 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2026 Microchip Technology Inc.
+ */
+
+#include "lan9645x_main.h"
+
+#define VLANACCESS_CMD_IDLE 0
+#define VLANACCESS_CMD_READ 1
+#define VLANACCESS_CMD_WRITE 2
+#define VLANACCESS_CMD_INIT 3
+
+struct lan9645x_vlan_port_info {
+ int untagged;
+ int tagged;
+ u16 untagged_vid;
+};
+
+/* Calculate VLAN state of a port, across all VLANS. */
+static void lan9645x_vlan_port_get_info(struct lan9645x *lan9645x, int port,
+ struct lan9645x_vlan_port_info *info)
+{
+ u16 vid;
+
+ info->untagged = 0;
+ info->tagged = 0;
+ info->untagged_vid = 0;
+
+ for (vid = 1; vid <= VLAN_MAX; vid++) {
+ struct lan9645x_vlan *v = &lan9645x->vlans[vid];
+
+ if (!(v->portmask & BIT(port)))
+ continue;
+
+ if (v->untagged & BIT(port)) {
+ info->untagged++;
+ info->untagged_vid = vid;
+ } else {
+ info->tagged++;
+ }
+
+ /* VLAN composition is invalid, so break early. */
+ if (info->untagged > 1 && info->tagged)
+ break;
+ }
+}
+
+static int lan9645x_vlan_wait_for_completion(struct lan9645x *lan9645x)
+{
+ u32 val;
+
+ return lan9645x_rd_poll_timeout(lan9645x, ANA_VLANACCESS, val,
+ ANA_VLANACCESS_VLAN_TBL_CMD_GET(val) ==
+ VLANACCESS_CMD_IDLE);
+}
+
+static int lan9645x_vlan_hw_wr(struct lan9645x *lan9645x, u16 vid)
+{
+ struct lan9645x_vlan *v = &lan9645x->vlans[vid];
+ bool cpu_dis = !(v->portmask & BIT(CPU_PORT));
+ u32 val;
+ int err;
+
+ val = ANA_VLANTIDX_VLAN_PGID_CPU_DIS_SET(cpu_dis) |
+ ANA_VLANTIDX_V_INDEX_SET(vid) |
+ ANA_VLANTIDX_VLAN_SEC_FWD_ENA_SET(v->s_fwd_ena) |
+ ANA_VLANTIDX_VLAN_FLOOD_DIS_SET(v->fld_dis) |
+ ANA_VLANTIDX_VLAN_PRIV_VLAN_SET(v->prv_vlan) |
+ ANA_VLANTIDX_VLAN_LEARN_DISABLED_SET(v->lrn_dis) |
+ ANA_VLANTIDX_VLAN_MIRROR_SET(v->mir) |
+ ANA_VLANTIDX_VLAN_SRC_CHK_SET(v->src_chk);
+
+ lan_wr(val, lan9645x, ANA_VLANTIDX);
+ lan_wr(ANA_VLAN_PORT_MASK_VLAN_PORT_MASK_SET(v->portmask),
+ lan9645x, ANA_VLAN_PORT_MASK);
+ lan_wr(ANA_VLANACCESS_VLAN_TBL_CMD_SET(VLANACCESS_CMD_WRITE),
+ lan9645x, ANA_VLANACCESS);
+
+ err = lan9645x_vlan_wait_for_completion(lan9645x);
+ if (err)
+ dev_err(lan9645x->dev, "Vlan set mask failed\n");
+
+ return err;
+}
+
+u16 lan9645x_vlan_unaware_pvid(bool is_bridged)
+{
+ return is_bridged ? UNAWARE_PVID : HOST_PVID;
+}
+
+static u16 lan9645x_vlan_port_get_pvid(struct lan9645x_port *port)
+{
+ bool is_bridged = lan9645x_port_is_bridged(port);
+
+ if (is_bridged && port->vlan_aware)
+ return port->pvid;
+ else
+ return lan9645x_vlan_unaware_pvid(is_bridged);
+}
+
+/* Dynamically choose the egress tagging mode based on the port vlan state:
+ *
+ * Standalone:
+ * TAG_NO_PVID_NO_UNAWARE with PORT_VID=HOST_PVID. This avoids leaking the
+ * internal HOST_PVID tag on ingress mirrored frames while leaving normal
+ * egress frames untagged.
+ *
+ * Bridged, VLAN-aware:
+ * - N untagged, 0 tagged: TAG_DISABLED
+ * - 1 untagged, N tagged: TAG_NO_PVID_NO_UNAWARE
+ * - 0 untagged, N tagged: TAG_ALL
+ *
+ * Bridged, VLAN-unaware:
+ * TAG_DISABLED
+ */
+static void
+lan9645x_vlan_port_apply_egress(struct lan9645x_port *p,
+ struct lan9645x_vlan_port_info *info)
+{
+ struct lan9645x *lan9645x = p->lan9645x;
+ enum lan9645x_vlan_port_tag tag_cfg;
+ u16 port_vid = UNAWARE_PVID;
+
+ if (!lan9645x_port_is_bridged(p)) {
+ tag_cfg = LAN9645X_TAG_NO_PVID_NO_UNAWARE;
+ port_vid = HOST_PVID;
+ } else if (p->vlan_aware) {
+ struct lan9645x_vlan_port_info _info;
+
+ if (!info) {
+ lan9645x_vlan_port_get_info(lan9645x, p->chip_port,
+ &_info);
+ info = &_info;
+ }
+
+ if (info->untagged == 1 && info->tagged) {
+ tag_cfg = LAN9645X_TAG_NO_PVID_NO_UNAWARE;
+ port_vid = info->untagged_vid;
+ } else if (info->untagged) {
+ tag_cfg = LAN9645X_TAG_DISABLED;
+ } else {
+ tag_cfg = LAN9645X_TAG_ALL;
+ }
+ } else {
+ tag_cfg = LAN9645X_TAG_DISABLED;
+ }
+
+ /* TAG_TPID_CFG encoding:
+ *
+ * 0: Use 0x8100.
+ * 1: Use 0x88A8.
+ * 2: Use custom value from PORT_VLAN_CFG.PORT_TPID.
+ * 3: Use PORT_VLAN_CFG.PORT_TPID, unless ingress tag was a C-tag
+ * (EtherType = 0x8100)
+ *
+ * Use 3 and PORT_VLAN_CFG.PORT_TPID=0x88a8 to ensure stags are not
+ * rewritten to ctags on egress.
+ */
+ lan_rmw(REW_TAG_CFG_TAG_TPID_CFG_SET(3) |
+ REW_TAG_CFG_TAG_CFG_SET(tag_cfg),
+ REW_TAG_CFG_TAG_TPID_CFG |
+ REW_TAG_CFG_TAG_CFG,
+ lan9645x, REW_TAG_CFG(p->chip_port));
+
+ lan_rmw(REW_PORT_VLAN_CFG_PORT_TPID_SET(ETH_P_8021AD) |
+ REW_PORT_VLAN_CFG_PORT_VID_SET(port_vid),
+ REW_PORT_VLAN_CFG_PORT_TPID |
+ REW_PORT_VLAN_CFG_PORT_VID,
+ lan9645x, REW_PORT_VLAN_CFG(p->chip_port));
+}
+
+static void lan9645x_vlan_port_apply_ingress(struct lan9645x_port *p)
+{
+ struct lan9645x *lan9645x = p->lan9645x;
+ u16 pvid;
+ u32 val;
+
+ pvid = lan9645x_vlan_port_get_pvid(p);
+
+ /* Default vlan to classify for untagged frames (may be zero) */
+ val = ANA_VLAN_CFG_VLAN_VID_SET(pvid);
+ if (p->vlan_aware)
+ val |= ANA_VLAN_CFG_VLAN_AWARE_ENA_SET(1) |
+ ANA_VLAN_CFG_VLAN_POP_CNT_SET(1);
+
+ lan_rmw(val,
+ ANA_VLAN_CFG_VLAN_VID |
+ ANA_VLAN_CFG_VLAN_AWARE_ENA |
+ ANA_VLAN_CFG_VLAN_POP_CNT,
+ lan9645x, ANA_VLAN_CFG(p->chip_port));
+
+ /* Drop frames with multicast source address */
+ val = ANA_DROP_CFG_DROP_MC_SMAC_ENA_SET(1);
+ if (p->vlan_aware && !pvid)
+ /* If port is vlan-aware and tagged, drop untagged and priority
+ * tagged frames.
+ */
+ val |= ANA_DROP_CFG_DROP_UNTAGGED_ENA_SET(1) |
+ ANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA_SET(1) |
+ ANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA_SET(1);
+
+ lan_wr(val, lan9645x, ANA_DROP_CFG(p->chip_port));
+}
+
+void lan9645x_vlan_port_apply(struct lan9645x_port *p)
+{
+ lan9645x_vlan_port_apply_ingress(p);
+ lan9645x_vlan_port_apply_egress(p, NULL);
+}
+
+static struct lan9645x_vlan *lan9645x_vlan_port_modify(struct lan9645x_port *p,
+ u16 vid, bool pvid,
+ bool untagged)
+{
+ struct lan9645x_vlan *v = &p->lan9645x->vlans[vid];
+
+ if (untagged)
+ v->untagged |= BIT(p->chip_port);
+ else
+ v->untagged &= ~BIT(p->chip_port);
+
+ if (pvid)
+ p->pvid = vid;
+ else if (p->pvid == vid)
+ p->pvid = 0;
+
+ return v;
+}
+
+static int lan9645x_vlan_cpu_add(struct lan9645x_port *p, u16 vid, bool pvid,
+ bool untagged)
+{
+ struct lan9645x_vlan *v;
+
+ v = lan9645x_vlan_port_modify(p, vid, pvid, untagged);
+ v->portmask |= BIT(CPU_PORT) | BIT(p->chip_port);
+ lan9645x_vlan_hw_wr(p->lan9645x, vid);
+ lan9645x_vlan_port_apply_ingress(p);
+
+ return 0;
+}
+
+int lan9645x_vlan_port_add_vlan(struct lan9645x_port *p, u16 vid, bool pvid,
+ bool untagged, struct netlink_ext_ack *extack)
+{
+ struct lan9645x *lan9645x = p->lan9645x;
+ struct lan9645x_vlan_port_info info;
+ struct lan9645x_vlan old_vlan;
+ struct lan9645x_vlan *v;
+ u16 old_pvid;
+
+ /* Kernel VLAN core adds vid 0, which collides with our UNAWARE_PVID.
+ * We handle priority tagged frames by other means.
+ */
+ if (!vid)
+ return 0;
+
+ if (vid > VLAN_MAX) {
+ NL_SET_ERR_MSG_MOD(extack, "VLAN range 4094-4095 reserved.");
+ return -EBUSY;
+ }
+
+ if (p->chip_port == lan9645x->npi)
+ return lan9645x_vlan_cpu_add(p, vid, pvid, untagged);
+
+ old_vlan = lan9645x->vlans[vid];
+ old_pvid = p->pvid;
+
+ v = lan9645x_vlan_port_modify(p, vid, pvid, untagged);
+ v->portmask |= BIT(p->chip_port);
+
+ lan9645x_vlan_port_get_info(lan9645x, p->chip_port, &info);
+
+ if (info.untagged > 1 && info.tagged) {
+ *v = old_vlan;
+ p->pvid = old_pvid;
+ NL_SET_ERR_MSG_MOD(extack, "Only support 1 untagged port VLAN");
+ return -EBUSY;
+ }
+
+ lan9645x_vlan_hw_wr(lan9645x, vid);
+ lan9645x_vlan_port_apply_ingress(p);
+ lan9645x_vlan_port_apply_egress(p, &info);
+
+ return 0;
+}
+
+static int lan9645x_vlan_cpu_del(struct lan9645x_port *p, u16 vid)
+{
+ struct lan9645x_vlan *v;
+
+ v = lan9645x_vlan_port_modify(p, vid, false, false);
+ v->portmask &= ~BIT(CPU_PORT) & ~BIT(p->chip_port);
+ lan9645x_vlan_hw_wr(p->lan9645x, vid);
+ lan9645x_vlan_port_apply_ingress(p);
+
+ return 0;
+}
+
+int lan9645x_vlan_port_del_vlan(struct lan9645x_port *p, u16 vid)
+{
+ struct lan9645x *lan9645x = p->lan9645x;
+ struct lan9645x_vlan *v;
+
+ if (!vid)
+ return 0;
+
+ if (vid > VLAN_MAX)
+ return -EBUSY;
+
+ if (p->chip_port == lan9645x->npi)
+ return lan9645x_vlan_cpu_del(p, vid);
+
+ v = lan9645x_vlan_port_modify(p, vid, false, false);
+ v->portmask &= ~BIT(p->chip_port);
+ lan9645x_vlan_hw_wr(lan9645x, vid);
+ lan9645x_vlan_port_apply(p);
+
+ return 0;
+}
+
+void lan9645x_vlan_set_hostmode(struct lan9645x_port *p)
+{
+ p->vlan_aware = false;
+ lan9645x_vlan_port_apply(p);
+}
+
+int lan9645x_vlan_init(struct lan9645x *lan9645x)
+{
+ u32 all_phys_ports, all_ports;
+ u16 port, vid;
+ int err;
+
+ all_phys_ports = GENMASK(lan9645x->num_phys_ports - 1, 0);
+ all_ports = all_phys_ports | BIT(CPU_PORT);
+
+ /* Clear VLAN table, by default all ports are members of all VLANS */
+ lan_wr(ANA_VLANACCESS_VLAN_TBL_CMD_SET(VLANACCESS_CMD_INIT),
+ lan9645x, ANA_VLANACCESS);
+
+ err = lan9645x_vlan_wait_for_completion(lan9645x);
+ if (err) {
+ dev_err(lan9645x->dev, "Vlan clear table failed\n");
+ return err;
+ }
+
+ for (vid = 1; vid < VLAN_N_VID; vid++) {
+ err = lan9645x_vlan_hw_wr(lan9645x, vid);
+ if (err)
+ return err;
+ }
+
+ /* Set all the ports + cpu to be part of HOST_PVID and UNAWARE_PVID */
+ lan9645x->vlans[HOST_PVID].portmask = all_ports;
+ err = lan9645x_vlan_hw_wr(lan9645x, HOST_PVID);
+ if (err)
+ return err;
+
+ lan9645x->vlans[UNAWARE_PVID].portmask = all_ports;
+ err = lan9645x_vlan_hw_wr(lan9645x, UNAWARE_PVID);
+ if (err)
+ return err;
+
+ /* Configure the CPU port to be vlan aware */
+ lan_wr(ANA_VLAN_CFG_VLAN_VID_SET(UNAWARE_PVID) |
+ ANA_VLAN_CFG_VLAN_AWARE_ENA_SET(1) |
+ ANA_VLAN_CFG_VLAN_POP_CNT_SET(1),
+ lan9645x, ANA_VLAN_CFG(CPU_PORT));
+
+ /* Set vlan ingress filter mask to all ports */
+ lan_wr(all_ports, lan9645x, ANA_VLANMASK);
+
+ for (port = 0; port < lan9645x->num_phys_ports; port++) {
+ lan_wr(0, lan9645x, REW_PORT_VLAN_CFG(port));
+ lan_wr(0, lan9645x, REW_TAG_CFG(port));
+ }
+
+ return 0;
+}
--
2.52.0
next prev parent reply other threads:[~2026-04-10 11:49 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-10 11:48 [PATCH net-next v3 0/9] net: dsa: add DSA support for the LAN9645x switch chip family Jens Emil Schulz Østergaard
2026-04-10 11:48 ` [PATCH net-next v3 1/9] net: dsa: add tag driver for LAN9645X Jens Emil Schulz Østergaard
2026-04-10 11:48 ` [PATCH net-next v3 2/9] dt-bindings: net: lan9645x: add LAN9645X switch bindings Jens Emil Schulz Østergaard
2026-04-10 11:48 ` [PATCH net-next v3 3/9] net: dsa: lan9645x: add autogenerated register macros Jens Emil Schulz Østergaard
2026-04-10 11:48 ` [PATCH net-next v3 4/9] net: dsa: lan9645x: add basic dsa driver for LAN9645X Jens Emil Schulz Østergaard
2026-04-10 11:48 ` [PATCH net-next v3 5/9] net: dsa: lan9645x: add bridge support Jens Emil Schulz Østergaard
2026-04-10 11:48 ` Jens Emil Schulz Østergaard [this message]
2026-04-10 11:48 ` [PATCH net-next v3 7/9] net: dsa: lan9645x: add mac table integration Jens Emil Schulz Østergaard
2026-04-10 11:48 ` [PATCH net-next v3 8/9] net: dsa: lan9645x: add mdb management Jens Emil Schulz Østergaard
2026-04-10 11:48 ` [PATCH net-next v3 9/9] net: dsa: lan9645x: add port statistics Jens Emil Schulz Østergaard
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=20260410-dsa_lan9645x_switch_driver_base-v3-6-aadc8595306d@microchip.com \
--to=jensemil.schulzostergaard@microchip.com \
--cc=Steen.Hegelund@microchip.com \
--cc=UNGLinuxDriver@microchip.com \
--cc=andrew@lunn.ch \
--cc=conor+dt@kernel.org \
--cc=daniel.machon@microchip.com \
--cc=davem@davemloft.net \
--cc=devicetree@vger.kernel.org \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=netdev@vger.kernel.org \
--cc=olteanv@gmail.com \
--cc=pabeni@redhat.com \
--cc=robh@kernel.org \
--cc=woojung.huh@microchip.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