From: Valentine Fatiev <valentinef@nvidia.com>
Subject: [PATCH] BACKPORT: include/rdma/ib_umem_odp.h

Change-Id: I78d58a6d3168a47e391d37e440e810f347eaf821
---
 include/rdma/ib_umem_odp.h | 99 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 99 insertions(+)

--- a/include/rdma/ib_umem_odp.h
+++ b/include/rdma/ib_umem_odp.h
@@ -6,16 +6,29 @@
 #ifndef IB_UMEM_ODP_H
 #define IB_UMEM_ODP_H
 
+#include "../../compat/config.h"
+
 #include <rdma/ib_umem.h>
 #include <rdma/ib_verbs.h>
+#ifndef HAVE_MMU_INTERVAL_NOTIFIER
+#include <linux/interval_tree.h>
+#endif
 
 struct ib_umem_odp {
 	struct ib_umem umem;
+#ifdef HAVE_MMU_INTERVAL_NOTIFIER
 	struct mmu_interval_notifier notifier;
 	struct pid *tgid;
+#else
+	struct ib_ucontext_per_mm *per_mm;
+#endif
 
+#if defined(HAVE_MMU_INTERVAL_NOTIFIER) && defined(HAVE_HMM_RANGE_FAULT_SUPPORT)
 	/* An array of the pfns included in the on-demand paging umem. */
 	unsigned long *pfn_list;
+#else
+	struct page		**page_list;
+#endif
 
 	/*
 	 * An array with DMA addresses mapped for pfns in pfn_list.
@@ -31,8 +44,15 @@ struct ib_umem_odp {
 	struct mutex		umem_mutex;
 	void			*private; /* for the HW driver to use. */
 
+#ifndef HAVE_MMU_INTERVAL_NOTIFIER
+	int notifiers_seq;
+	int notifiers_count;
+#endif
 	int npages;
 
+#ifndef HAVE_MMU_INTERVAL_NOTIFIER
+	struct interval_tree_node interval_tree;
+#endif
 	/*
 	 * An implicit odp umem cannot be DMA mapped, has 0 length, and serves
 	 * only as an anchor for the driver to hold onto the per_mm. FIXME:
@@ -41,6 +61,9 @@ struct ib_umem_odp {
 	 */
 	bool is_implicit_odp;
 
+#ifndef HAVE_MMU_INTERVAL_NOTIFIER
+	struct completion	notifier_completion;
+#endif
 	unsigned int		page_shift;
 };
 
@@ -52,13 +75,21 @@ static inline struct ib_umem_odp *to_ib_
 /* Returns the first page of an ODP umem. */
 static inline unsigned long ib_umem_start(struct ib_umem_odp *umem_odp)
 {
+#ifdef HAVE_MMU_INTERVAL_NOTIFIER
 	return umem_odp->notifier.interval_tree.start;
+#else
+	return umem_odp->interval_tree.start;
+#endif
 }
 
 /* Returns the address of the page after the last one of an ODP umem. */
 static inline unsigned long ib_umem_end(struct ib_umem_odp *umem_odp)
 {
+#ifdef HAVE_MMU_INTERVAL_NOTIFIER
 	return umem_odp->notifier.interval_tree.last + 1;
+#else
+	return umem_odp->interval_tree.last + 1;
+#endif
 }
 
 static inline size_t ib_umem_odp_num_pages(struct ib_umem_odp *umem_odp)
@@ -82,28 +113,96 @@ static inline size_t ib_umem_odp_num_pag
 
 #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
 
+#ifdef HAVE_MMU_INTERVAL_NOTIFIER
 struct ib_umem_odp *
 ib_umem_odp_get(struct ib_device *device, unsigned long addr, size_t size,
 		int access, const struct mmu_interval_notifier_ops *ops);
 struct ib_umem_odp *ib_umem_odp_alloc_implicit(struct ib_device *device,
+#else
+struct ib_ucontext_per_mm {
+#ifdef HAVE_MMU_NOTIFIER_OPS_HAS_FREE_NOTIFIER
+	struct mmu_notifier mn;
+	struct pid *tgid;
+#else
+	struct ib_ucontext *context;
+	struct mm_struct *mm;
+ 	struct pid *tgid;
+	bool active;
+#endif
+
+	struct rb_root_cached umem_tree;
+	/* Protects umem_tree */
+	struct rw_semaphore umem_rwsem;
+#ifndef HAVE_MMU_NOTIFIER_OPS_HAS_FREE_NOTIFIER
+	struct mmu_notifier mn;
+	unsigned int odp_mrs_count;
+
+	struct list_head ucontext_list;
+	struct rcu_head rcu;
+#endif
+};
+
+struct ib_umem_odp *ib_umem_odp_get(struct ib_udata *udata, unsigned long addr,
+				    size_t size, int access);
+struct ib_umem_odp *ib_umem_odp_alloc_implicit(struct ib_udata *udata,
+#endif
 					       int access);
+#ifdef HAVE_MMU_INTERVAL_NOTIFIER
 struct ib_umem_odp *
 ib_umem_odp_alloc_child(struct ib_umem_odp *root_umem, unsigned long addr,
 			size_t size,
 			const struct mmu_interval_notifier_ops *ops);
+#else
+struct ib_umem_odp *ib_umem_odp_alloc_child(struct ib_umem_odp *root_umem,
+					    unsigned long addr, size_t size);
+#endif
 void ib_umem_odp_release(struct ib_umem_odp *umem_odp);
 
+#if defined(HAVE_MMU_INTERVAL_NOTIFIER) && defined(HAVE_HMM_RANGE_FAULT_SUPPORT)
 int ib_umem_odp_map_dma_and_lock(struct ib_umem_odp *umem_odp, u64 start_offset,
 				 u64 bcnt, u64 access_mask, bool fault);
+#else
+int ib_umem_odp_map_dma_pages(struct ib_umem_odp *umem_odp, u64 start_offset,
+			      u64 bcnt, u64 access_mask,
+			      unsigned long current_seq);
+#endif
+
 
 void ib_umem_odp_unmap_dma_pages(struct ib_umem_odp *umem_odp, u64 start_offset,
 				 u64 bound);
 
+#ifndef HAVE_MMU_INTERVAL_NOTIFIER
+typedef int (*umem_call_back)(struct ib_umem_odp *item, u64 start, u64 end,
+			      void *cookie);
+int rbt_ib_umem_for_each_in_range(struct rb_root_cached *root,
+				  u64 start, u64 end,
+				  umem_call_back cb,
+#if defined(HAVE_UMEM_NOTIFIER_PARAM_BLOCKABLE) || defined(HAVE_MMU_NOTIFIER_RANGE_STRUCT)
+				  bool blockable,
+#endif
+				  void *cookie);
+
+static inline int ib_umem_mmu_notifier_retry(struct ib_umem_odp *umem_odp,
+					     unsigned long mmu_seq)
+{
+	if (unlikely(umem_odp->notifiers_count))
+		return 1;
+	if (umem_odp->notifiers_seq != mmu_seq)
+		return 1;
+	return 0;
+}
+#endif
 #else /* CONFIG_INFINIBAND_ON_DEMAND_PAGING */
 
+#ifdef HAVE_MMU_INTERVAL_NOTIFIER
 static inline struct ib_umem_odp *
 ib_umem_odp_get(struct ib_device *device, unsigned long addr, size_t size,
 		int access, const struct mmu_interval_notifier_ops *ops)
+#else
+static inline struct ib_umem_odp *ib_umem_odp_get(struct ib_udata *udata,
+						  unsigned long addr,
+						  size_t size, int access)
+#endif
 {
 	return ERR_PTR(-EINVAL);
 }
