return ret;
 }
 
-static int _mv88e6xxx_port_vlan_map_set(struct dsa_switch *ds, int port,
-                                       u16 output_ports)
+static int _mv88e6xxx_port_based_vlan_map(struct dsa_switch *ds, int port)
 {
        struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+       struct net_device *bridge = ps->ports[port].bridge_dev;
        const u16 mask = (1 << ps->num_ports) - 1;
+       u16 output_ports = 0;
        int reg;
+       int i;
+
+       /* allow CPU port or DSA link(s) to send frames to every port */
+       if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) {
+               output_ports = mask;
+       } else {
+               for (i = 0; i < ps->num_ports; ++i) {
+                       /* allow sending frames to every group member */
+                       if (bridge && ps->ports[i].bridge_dev == bridge)
+                               output_ports |= BIT(i);
+
+                       /* allow sending frames to CPU port and DSA link(s) */
+                       if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
+                               output_ports |= BIT(i);
+               }
+       }
+
+       /* prevent frames from going back out of the port they came in on */
+       output_ports &= ~BIT(port);
 
        reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_BASE_VLAN);
        if (reg < 0)
        if (err)
                goto unlock;
 
+       /* Assign the bridge and remap each port's VLANTable */
        ps->ports[port].bridge_dev = bridge;
+
+       for (i = 0; i < ps->num_ports; ++i) {
+               if (ps->ports[i].bridge_dev == bridge) {
+                       err = _mv88e6xxx_port_based_vlan_map(ds, i);
+                       if (err)
+                               break;
+               }
+       }
+
 unlock:
        mutex_unlock(&ps->smi_mutex);
 
 int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
 {
        struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+       struct net_device *bridge = ps->ports[port].bridge_dev;
        u16 fid;
-       int err;
+       int i, err;
 
        mutex_lock(&ps->smi_mutex);
 
        if (err)
                goto unlock;
 
+       /* Unassign the bridge and remap each port's VLANTable */
        ps->ports[port].bridge_dev = NULL;
+
+       for (i = 0; i < ps->num_ports; ++i) {
+               if (i == port || ps->ports[i].bridge_dev == bridge) {
+                       err = _mv88e6xxx_port_based_vlan_map(ds, i);
+                       if (err)
+                               break;
+               }
+       }
+
 unlock:
        mutex_unlock(&ps->smi_mutex);
 
                goto abort;
 
        /* Port based VLAN map: give each port its own address
-        * database, and allow every port to egress frames on all other ports.
+        * database, and allow bidirectional communication between the
+        * CPU and DSA port(s), and the other ports.
         */
        ret = _mv88e6xxx_port_fid_set(ds, port, port + 1);
        if (ret)
                goto abort;
 
-       reg = BIT(ps->num_ports) - 1; /* all ports */
-       reg &= ~BIT(port); /* except itself */
-       ret = _mv88e6xxx_port_vlan_map_set(ds, port, reg);
+       ret = _mv88e6xxx_port_based_vlan_map(ds, port);
        if (ret)
                goto abort;