Skip to content

Commit

Permalink
realtek: 5.15: backport VLAN fix
Browse files Browse the repository at this point in the history
With commit a22d359 VLAN handling was fixed for kernel 6.6.
This restored network connectivity of the devices. For easy testing
backport the fix for 5.15 too.

Signed-off-by: Markus Stockhausen <[email protected]>
Link: openwrt#16391
Signed-off-by: Robert Marko <[email protected]>
  • Loading branch information
plappermaul authored and robimarko committed Sep 16, 2024
1 parent 9272d99 commit 35e1324
Showing 1 changed file with 45 additions and 26 deletions.
71 changes: 45 additions & 26 deletions target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,20 @@ static enum dsa_tag_protocol rtl83xx_get_tag_protocol(struct dsa_switch *ds,
return DSA_TAG_PROTO_TRAILER;
}

static void rtl83xx_vlan_set_pvid(struct rtl838x_switch_priv *priv,
int port, int pvid)
{
/* Set both inner and outer PVID of the port */
priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_INNER, pvid);
priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_OUTER, pvid);
priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_INNER,
PBVLAN_MODE_UNTAG_AND_PRITAG);
priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_OUTER,
PBVLAN_MODE_UNTAG_AND_PRITAG);

priv->ports[port].pvid = pvid;
}

/* Initialize all VLANS */
static void rtl83xx_vlan_setup(struct rtl838x_switch_priv *priv)
{
Expand All @@ -132,17 +146,22 @@ static void rtl83xx_vlan_setup(struct rtl838x_switch_priv *priv)
info.l2_tunnel_list_id = -1;
}

/* Initialize all vlans 0-4095 */
for (int i = 0; i < MAX_VLANS; i ++)
/* Initialize normal VLANs 1-4095 */
for (int i = 1; i < MAX_VLANS; i ++)
priv->r->vlan_set_tagged(i, &info);

/* reset PVIDs; defaults to 1 on reset */
/*
* Initialize the special VLAN 0 and reset PVIDs. The CPU port PVID
* is applied to packets from the CPU for untagged destinations,
* regardless if the actual ingress VID. Any port with untagged
* egress VLAN(s) must therefore be a member of VLAN 0 to support
* CPU port as ingress when VLAN filtering is enabled.
*/
for (int i = 0; i <= priv->cpu_port; i++) {
priv->r->vlan_port_pvid_set(i, PBVLAN_TYPE_INNER, 1);
priv->r->vlan_port_pvid_set(i, PBVLAN_TYPE_OUTER, 1);
priv->r->vlan_port_pvidmode_set(i, PBVLAN_TYPE_INNER, PBVLAN_MODE_UNTAG_AND_PRITAG);
priv->r->vlan_port_pvidmode_set(i, PBVLAN_TYPE_OUTER, PBVLAN_MODE_UNTAG_AND_PRITAG);
rtl83xx_vlan_set_pvid(priv, i, 0);
info.tagged_ports |= BIT_ULL(i);
}
priv->r->vlan_set_tagged(0, &info);

/* Set forwarding action based on inner VLAN tag */
for (int i = 0; i < priv->cpu_port; i++)
Expand Down Expand Up @@ -1392,20 +1411,6 @@ static int rtl83xx_vlan_prepare(struct dsa_switch *ds, int port,
return 0;
}

static void rtl83xx_vlan_set_pvid(struct rtl838x_switch_priv *priv,
int port, int pvid)
{
/* Set both inner and outer PVID of the port */
priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_INNER, pvid);
priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_OUTER, pvid);
priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_INNER,
PBVLAN_MODE_UNTAG_AND_PRITAG);
priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_OUTER,
PBVLAN_MODE_UNTAG_AND_PRITAG);

priv->ports[port].pvid = pvid;
}

static int rtl83xx_vlan_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan,
struct netlink_ext_ack *extack)
Expand All @@ -1417,7 +1422,8 @@ static int rtl83xx_vlan_add(struct dsa_switch *ds, int port,
pr_debug("%s port %d, vid %d, flags %x\n",
__func__, port, vlan->vid, vlan->flags);

if(!vlan->vid) return 0;
/* Let no one mess with our special VLAN 0 */
if (!vlan->vid) return 0;

if (vlan->vid > 4095) {
dev_err(priv->dev, "VLAN out of range: %d", vlan->vid);
Expand All @@ -1430,10 +1436,20 @@ static int rtl83xx_vlan_add(struct dsa_switch *ds, int port,

mutex_lock(&priv->reg_mutex);

if (vlan->flags & BRIDGE_VLAN_INFO_PVID)
rtl83xx_vlan_set_pvid(priv, port, vlan->vid);
else if (priv->ports[port].pvid == vlan->vid)
rtl83xx_vlan_set_pvid(priv, port, 0);
/*
* Realtek switches copy frames as-is to/from the CPU. For a proper
* VLAN handling the 12 bit RVID field (= VLAN id) for incoming traffic
* and the 1 bit RVID_SEL field (0 = use inner tag, 1 = use outer tag)
* for outgoing traffic of the CPU tag structure need to be handled. As
* of now no such logic is in place. So for the CPU port keep the fixed
* PVID=0 from initial setup in place and ignore all subsequent settings.
*/
if (port != priv->cpu_port) {
if (vlan->flags & BRIDGE_VLAN_INFO_PVID)
rtl83xx_vlan_set_pvid(priv, port, vlan->vid);
else if (priv->ports[port].pvid == vlan->vid)
rtl83xx_vlan_set_pvid(priv, port, 0);
}

/* Get port memberships of this vlan */
priv->r->vlan_tables_read(vlan->vid, &info);
Expand Down Expand Up @@ -1477,6 +1493,9 @@ static int rtl83xx_vlan_del(struct dsa_switch *ds, int port,
pr_debug("%s: port %d, vid %d, flags %x\n",
__func__, port, vlan->vid, vlan->flags);

/* Let no one mess with our special VLAN 0 */
if (!vlan->vid) return 0;

if (vlan->vid > 4095) {
dev_err(priv->dev, "VLAN out of range: %d", vlan->vid);
return -ENOTSUPP;
Expand Down

0 comments on commit 35e1324

Please sign in to comment.