From: Valentine Fatiev <valentinef@nvidia.com>
Subject: [PATCH] BACKPORT: drivers/vfio/pci/mlx5/cmd.c

Change-Id: I0386854deb10cc1f4fdd3ec31f0b56b4fe76642a
---
 drivers/vfio/pci/mlx5/cmd.c | 54 +++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

--- a/drivers/vfio/pci/mlx5/cmd.c
+++ b/drivers/vfio/pci/mlx5/cmd.c
@@ -3,6 +3,7 @@
  * Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved
  */
 
+#ifdef HAVE_VFIO_SUPPORT
 #include "cmd.h"
 
 enum { CQ_OK = 0, CQ_EMPTY = -1, CQ_POLL_ERR = -2 };
@@ -846,6 +847,54 @@ void mlx5fv_cmd_clean_migf_resources(str
 	mlx5vf_cmd_dealloc_pd(migf);
 }
 
+#ifndef HAVE_VFIO_COMBINE_IOVA_RANGES
+static void combine_ranges(struct rb_root_cached *root, u32 cur_nodes,
+			   u32 req_nodes)
+{
+	struct interval_tree_node *prev, *curr, *comb_start, *comb_end;
+	unsigned long min_gap;
+	unsigned long curr_gap;
+
+	/* Special shortcut when a single range is required */
+	if (req_nodes == 1) {
+		unsigned long last;
+
+		curr = comb_start = interval_tree_iter_first(root, 0, ULONG_MAX);
+		while (curr) {
+			last = curr->last;
+			prev = curr;
+			curr = interval_tree_iter_next(curr, 0, ULONG_MAX);
+			if (prev != comb_start)
+				interval_tree_remove(prev, root);
+		}
+		comb_start->last = last;
+		return;
+	}
+
+	/* Combine ranges which have the smallest gap */
+	while (cur_nodes > req_nodes) {
+		prev = NULL;
+		min_gap = ULONG_MAX;
+		curr = interval_tree_iter_first(root, 0, ULONG_MAX);
+		while (curr) {
+			if (prev) {
+				curr_gap = curr->start - prev->last;
+				if (curr_gap < min_gap) {
+					min_gap = curr_gap;
+					comb_start = prev;
+					comb_end = curr;
+				}
+			}
+			prev = curr;
+			curr = interval_tree_iter_next(curr, 0, ULONG_MAX);
+		}
+		comb_start->last = comb_end->last;
+		interval_tree_remove(comb_end, root);
+		cur_nodes--;
+	}
+}
+#endif
+
 static int mlx5vf_create_tracker(struct mlx5_core_dev *mdev,
 				 struct mlx5vf_pci_core_device *mvdev,
 				 struct rb_root_cached *ranges, u32 nnodes)
@@ -868,7 +917,11 @@ static int mlx5vf_create_tracker(struct
 	int i;
 
 	if (num_ranges > max_num_range) {
+#ifdef HAVE_VFIO_COMBINE_IOVA_RANGES
 		vfio_combine_iova_ranges(ranges, nnodes, max_num_range);
+#else
+		combine_ranges(ranges, nnodes, max_num_range);
+#endif
 		num_ranges = max_num_range;
 	}
 
@@ -1778,3 +1831,4 @@ end:
 	mlx5vf_state_mutex_unlock(mvdev);
 	return err;
 }
+#endif /* HAVE_VFIO_SUPPORT */
