data &= ~PORT_VLAN_MEMBERSHIP;
        data |= (member & dev->port_mask);
        ksz_pwrite8(dev, port, P_MIRROR_CTRL, data);
-       dev->ports[port].member = member;
 }
 
 static void ksz8_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
 {
        struct ksz_device *dev = ds->priv;
-       int forward = dev->member;
        struct ksz_port *p;
-       int member = -1;
        u8 data;
 
-       p = &dev->ports[port];
-
        ksz_pread8(dev, port, P_STP_CTRL, &data);
        data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE);
 
        switch (state) {
        case BR_STATE_DISABLED:
                data |= PORT_LEARN_DISABLE;
-               if (port < dev->phy_port_cnt)
-                       member = 0;
                break;
        case BR_STATE_LISTENING:
                data |= (PORT_RX_ENABLE | PORT_LEARN_DISABLE);
-               if (port < dev->phy_port_cnt &&
-                   p->stp_state == BR_STATE_DISABLED)
-                       member = dev->host_mask | p->vid_member;
                break;
        case BR_STATE_LEARNING:
                data |= PORT_RX_ENABLE;
                break;
        case BR_STATE_FORWARDING:
                data |= (PORT_TX_ENABLE | PORT_RX_ENABLE);
-
-               /* This function is also used internally. */
-               if (port == dev->cpu_port)
-                       break;
-
-               /* Port is a member of a bridge. */
-               if (dev->br_member & BIT(port)) {
-                       dev->member |= BIT(port);
-                       member = dev->member;
-               } else {
-                       member = dev->host_mask | p->vid_member;
-               }
                break;
        case BR_STATE_BLOCKING:
                data |= PORT_LEARN_DISABLE;
-               if (port < dev->phy_port_cnt &&
-                   p->stp_state == BR_STATE_DISABLED)
-                       member = dev->host_mask | p->vid_member;
                break;
        default:
                dev_err(ds->dev, "invalid STP state: %d\n", state);
        }
 
        ksz_pwrite8(dev, port, P_STP_CTRL, data);
+
+       p = &dev->ports[port];
        p->stp_state = state;
-       /* Port membership may share register with STP state. */
-       if (member >= 0 && member != p->member)
-               ksz8_cfg_port_member(dev, port, (u8)member);
-
-       /* Check if forwarding needs to be updated. */
-       if (state != BR_STATE_FORWARDING) {
-               if (dev->br_member & BIT(port))
-                       dev->member &= ~BIT(port);
-       }
 
-       /* When topology has changed the function ksz_update_port_member
-        * should be called to modify port forwarding behavior.
-        */
-       if (forward != dev->member)
-               ksz_update_port_member(dev, port);
+       ksz_update_port_member(dev, port);
 }
 
 static void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port)
 
 static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
 {
-       struct ksz_port *p = &dev->ports[port];
+       struct dsa_switch *ds = dev->ds;
        struct ksz8 *ksz8 = dev->priv;
        const u32 *masks;
        u8 member;
                if (!ksz_is_ksz88x3(dev))
                        ksz8795_cpu_interface_select(dev, port);
 
-               member = dev->port_mask;
+               member = dsa_user_ports(ds);
        } else {
-               member = dev->host_mask | p->vid_member;
+               member = BIT(dsa_upstream_port(ds, port));
        }
+
        ksz8_cfg_port_member(dev, port, member);
 }
 
        ksz_cfg(dev, regs[S_TAIL_TAG_CTRL], masks[SW_TAIL_TAG_ENABLE], true);
 
        p = &dev->ports[dev->cpu_port];
-       p->vid_member = dev->port_mask;
        p->on = 1;
 
        ksz8_port_setup(dev, dev->cpu_port, true);
-       dev->member = dev->host_mask;
 
        for (i = 0; i < dev->phy_port_cnt; i++) {
                p = &dev->ports[i];
 
-               /* Initialize to non-zero so that ksz_cfg_port_member() will
-                * be called.
-                */
-               p->vid_member = BIT(i);
-               p->member = dev->port_mask;
                ksz8_port_stp_state_set(ds, i, BR_STATE_DISABLED);
 
                /* Last port may be disabled. */
 
                                    u8 member)
 {
        ksz_pwrite32(dev, port, REG_PORT_VLAN_MEMBERSHIP__4, member);
-       dev->ports[port].member = member;
 }
 
 static void ksz9477_port_stp_state_set(struct dsa_switch *ds, int port,
        struct ksz_device *dev = ds->priv;
        struct ksz_port *p = &dev->ports[port];
        u8 data;
-       int member = -1;
-       int forward = dev->member;
 
        ksz_pread8(dev, port, P_STP_CTRL, &data);
        data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE);
        switch (state) {
        case BR_STATE_DISABLED:
                data |= PORT_LEARN_DISABLE;
-               if (port != dev->cpu_port)
-                       member = 0;
                break;
        case BR_STATE_LISTENING:
                data |= (PORT_RX_ENABLE | PORT_LEARN_DISABLE);
-               if (port != dev->cpu_port &&
-                   p->stp_state == BR_STATE_DISABLED)
-                       member = dev->host_mask | p->vid_member;
                break;
        case BR_STATE_LEARNING:
                data |= PORT_RX_ENABLE;
                break;
        case BR_STATE_FORWARDING:
                data |= (PORT_TX_ENABLE | PORT_RX_ENABLE);
-
-               /* This function is also used internally. */
-               if (port == dev->cpu_port)
-                       break;
-
-               member = dev->host_mask | p->vid_member;
-               mutex_lock(&dev->dev_mutex);
-
-               /* Port is a member of a bridge. */
-               if (dev->br_member & (1 << port)) {
-                       dev->member |= (1 << port);
-                       member = dev->member;
-               }
-               mutex_unlock(&dev->dev_mutex);
                break;
        case BR_STATE_BLOCKING:
                data |= PORT_LEARN_DISABLE;
-               if (port != dev->cpu_port &&
-                   p->stp_state == BR_STATE_DISABLED)
-                       member = dev->host_mask | p->vid_member;
                break;
        default:
                dev_err(ds->dev, "invalid STP state: %d\n", state);
 
        ksz_pwrite8(dev, port, P_STP_CTRL, data);
        p->stp_state = state;
-       mutex_lock(&dev->dev_mutex);
-       /* Port membership may share register with STP state. */
-       if (member >= 0 && member != p->member)
-               ksz9477_cfg_port_member(dev, port, (u8)member);
-
-       /* Check if forwarding needs to be updated. */
-       if (state != BR_STATE_FORWARDING) {
-               if (dev->br_member & (1 << port))
-                       dev->member &= ~(1 << port);
-       }
 
-       /* When topology has changed the function ksz_update_port_member
-        * should be called to modify port forwarding behavior.
-        */
-       if (forward != dev->member)
-               ksz_update_port_member(dev, port);
-       mutex_unlock(&dev->dev_mutex);
+       ksz_update_port_member(dev, port);
 }
 
 static void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port)
 
 static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
 {
-       u8 data8;
-       u8 member;
-       u16 data16;
        struct ksz_port *p = &dev->ports[port];
+       struct dsa_switch *ds = dev->ds;
+       u8 data8, member;
+       u16 data16;
 
        /* enable tag tail for host port */
        if (cpu_port)
                ksz_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, data8);
                p->phydev.duplex = 1;
        }
-       mutex_lock(&dev->dev_mutex);
+
        if (cpu_port)
-               member = dev->port_mask;
+               member = dsa_user_ports(ds);
        else
-               member = dev->host_mask | p->vid_member;
-       mutex_unlock(&dev->dev_mutex);
+               member = BIT(dsa_upstream_port(ds, port));
+
        ksz9477_cfg_port_member(dev, port, member);
 
        /* clear pending interrupts */
                        const char *prev_mode;
 
                        dev->cpu_port = i;
-                       dev->host_mask = (1 << dev->cpu_port);
-                       dev->port_mask |= dev->host_mask;
                        p = &dev->ports[i];
 
                        /* Read from XMII register to determine host port
 
                        /* enable cpu port */
                        ksz9477_port_setup(dev, i, true);
-                       p->vid_member = dev->port_mask;
                        p->on = 1;
                }
        }
 
-       dev->member = dev->host_mask;
-
        for (i = 0; i < dev->port_cnt; i++) {
                if (i == dev->cpu_port)
                        continue;
                p = &dev->ports[i];
 
-               /* Initialize to non-zero so that ksz_cfg_port_member() will
-                * be called.
-                */
-               p->vid_member = (1 << i);
-               p->member = dev->port_mask;
                ksz9477_port_stp_state_set(ds, i, BR_STATE_DISABLED);
                p->on = 1;
                if (i < dev->phy_port_cnt)
 
 
 void ksz_update_port_member(struct ksz_device *dev, int port)
 {
-       struct ksz_port *p;
+       struct ksz_port *p = &dev->ports[port];
+       struct dsa_switch *ds = dev->ds;
+       u8 port_member = 0, cpu_port;
+       const struct dsa_port *dp;
        int i;
 
-       for (i = 0; i < dev->port_cnt; i++) {
-               if (i == port || i == dev->cpu_port)
+       if (!dsa_is_user_port(ds, port))
+               return;
+
+       dp = dsa_to_port(ds, port);
+       cpu_port = BIT(dsa_upstream_port(ds, port));
+
+       for (i = 0; i < ds->num_ports; i++) {
+               const struct dsa_port *other_dp = dsa_to_port(ds, i);
+               struct ksz_port *other_p = &dev->ports[i];
+               u8 val = 0;
+
+               if (!dsa_is_user_port(ds, i))
                        continue;
-               p = &dev->ports[i];
-               if (!(dev->member & (1 << i)))
+               if (port == i)
+                       continue;
+               if (!dp->bridge_dev || dp->bridge_dev != other_dp->bridge_dev)
                        continue;
 
-               /* Port is a member of the bridge and is forwarding. */
-               if (p->stp_state == BR_STATE_FORWARDING &&
-                   p->member != dev->member)
-                       dev->dev_ops->cfg_port_member(dev, i, dev->member);
+               if (other_p->stp_state == BR_STATE_FORWARDING &&
+                   p->stp_state == BR_STATE_FORWARDING) {
+                       val |= BIT(port);
+                       port_member |= BIT(i);
+               }
+
+               dev->dev_ops->cfg_port_member(dev, i, val | cpu_port);
        }
+
+       dev->dev_ops->cfg_port_member(dev, port, port_member | cpu_port);
 }
 EXPORT_SYMBOL_GPL(ksz_update_port_member);
 
 int ksz_port_bridge_join(struct dsa_switch *ds, int port,
                         struct net_device *br)
 {
-       struct ksz_device *dev = ds->priv;
-
-       mutex_lock(&dev->dev_mutex);
-       dev->br_member |= (1 << port);
-       mutex_unlock(&dev->dev_mutex);
-
        /* port_stp_state_set() will be called after to put the port in
         * appropriate state so there is no need to do anything.
         */
 void ksz_port_bridge_leave(struct dsa_switch *ds, int port,
                           struct net_device *br)
 {
-       struct ksz_device *dev = ds->priv;
-
-       mutex_lock(&dev->dev_mutex);
-       dev->br_member &= ~(1 << port);
-       dev->member &= ~(1 << port);
-       mutex_unlock(&dev->dev_mutex);
-
        /* port_stp_state_set() will be called after to put the port in
         * forwarding state so there is no need to do anything.
         */
 
 };
 
 struct ksz_port {
-       u16 member;
-       u16 vid_member;
        bool remove_tag;                /* Remove Tag flag set, for ksz8795 only */
        int stp_state;
        struct phy_device phydev;
        struct ksz_port *ports;
        struct delayed_work mib_read;
        unsigned long mib_read_interval;
-       u16 br_member;
-       u16 member;
        u16 mirror_rx;
        u16 mirror_tx;
        u32 features;                   /* chip specific features */