static int icssg_prueth_add_mcast(struct net_device *ndev, const u8 *addr)
 {
-       struct prueth_emac *emac = netdev_priv(ndev);
-       int port_mask = BIT(emac->port_id);
+       struct net_device *real_dev;
+       struct prueth_emac *emac;
+       int port_mask;
+       u8 vlan_id;
 
-       port_mask |= icssg_fdb_lookup(emac, addr, 0);
-       icssg_fdb_add_del(emac, addr, 0, port_mask, true);
-       icssg_vtbl_modify(emac, 0, port_mask, port_mask, true);
+       vlan_id = is_vlan_dev(ndev) ? vlan_dev_vlan_id(ndev) : PRUETH_DFLT_VLAN_MAC;
+       real_dev = is_vlan_dev(ndev) ? vlan_dev_real_dev(ndev) : ndev;
+       emac = netdev_priv(real_dev);
+
+       port_mask = BIT(emac->port_id) | icssg_fdb_lookup(emac, addr, vlan_id);
+       icssg_fdb_add_del(emac, addr, vlan_id, port_mask, true);
+       icssg_vtbl_modify(emac, vlan_id, port_mask, port_mask, true);
 
        return 0;
 }
 
 static int icssg_prueth_del_mcast(struct net_device *ndev, const u8 *addr)
 {
-       struct prueth_emac *emac = netdev_priv(ndev);
-       int port_mask = BIT(emac->port_id);
+       struct net_device *real_dev;
+       struct prueth_emac *emac;
        int other_port_mask;
+       int port_mask;
+       u8 vlan_id;
+
+       vlan_id = is_vlan_dev(ndev) ? vlan_dev_vlan_id(ndev) : PRUETH_DFLT_VLAN_MAC;
+       real_dev = is_vlan_dev(ndev) ? vlan_dev_real_dev(ndev) : ndev;
+       emac = netdev_priv(real_dev);
 
-       other_port_mask = port_mask ^ icssg_fdb_lookup(emac, addr, 0);
+       port_mask = BIT(emac->port_id);
+       other_port_mask = port_mask ^ icssg_fdb_lookup(emac, addr, vlan_id);
 
-       icssg_fdb_add_del(emac, addr, 0, port_mask, false);
-       icssg_vtbl_modify(emac, 0, port_mask, port_mask, false);
+       icssg_fdb_add_del(emac, addr, vlan_id, port_mask, false);
+       icssg_vtbl_modify(emac, vlan_id, port_mask, port_mask, false);
 
        if (other_port_mask) {
-               icssg_fdb_add_del(emac, addr, 0, other_port_mask, true);
-               icssg_vtbl_modify(emac, 0, other_port_mask, other_port_mask, true);
+               icssg_fdb_add_del(emac, addr, vlan_id, other_port_mask, true);
+               icssg_vtbl_modify(emac, vlan_id, other_port_mask,
+                                 other_port_mask, true);
        }
 
        return 0;
        return 0;
 }
 
+static int icssg_update_vlan_mcast(struct net_device *vdev, int vid,
+                                  void *args)
+{
+       struct prueth_emac *emac = args;
+
+       if (!vdev || !vid)
+               return 0;
+
+       netif_addr_lock_bh(vdev);
+       __hw_addr_sync_multiple(&emac->vlan_mcast_list[vid], &vdev->mc,
+                               vdev->addr_len);
+       netif_addr_unlock_bh(vdev);
+
+       __hw_addr_sync_dev(&emac->vlan_mcast_list[vid], vdev,
+                          icssg_prueth_add_mcast, icssg_prueth_del_mcast);
+
+       return 0;
+}
+
 /**
  * emac_ndo_open - EMAC device open
  * @ndev: network adapter device
                return;
        }
 
-       if (emac->prueth->is_hsr_offload_mode)
+       if (emac->prueth->is_hsr_offload_mode) {
                __dev_mc_sync(ndev, icssg_prueth_hsr_add_mcast,
                              icssg_prueth_hsr_del_mcast);
-       else
+       } else {
                __dev_mc_sync(ndev, icssg_prueth_add_mcast,
                              icssg_prueth_del_mcast);
+               if (rtnl_trylock()) {
+                       vlan_for_each(ndev, icssg_update_vlan_mcast, emac);
+                       rtnl_unlock();
+               }
+       }
 }
 
 /**
        if (prueth->is_hsr_offload_mode)
                port_mask |= BIT(PRUETH_PORT_HOST);
 
+       __hw_addr_init(&emac->vlan_mcast_list[vid]);
        netdev_dbg(emac->ndev, "VID add vid:%u port_mask:%X untag_mask %X\n",
                   vid, port_mask, untag_mask);