diff --git a/drivers/gpu/nvgpu/Makefile.nvgpu b/drivers/gpu/nvgpu/Makefile.nvgpu
index b8a3f0331..16c54849b 100644
--- a/drivers/gpu/nvgpu/Makefile.nvgpu
+++ b/drivers/gpu/nvgpu/Makefile.nvgpu
@@ -40,6 +40,7 @@ nvgpu-y := \
common/nvgpu_common.o \
common/semaphore.o \
common/as.o \
+ common/rbtree.o \
common/vbios/bios.o \
gk20a/gk20a.o \
gk20a/bus_gk20a.o \
diff --git a/drivers/gpu/nvgpu/common/rbtree.c b/drivers/gpu/nvgpu/common/rbtree.c
new file mode 100644
index 000000000..0fcbe86ed
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/rbtree.c
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+
+/*
+ * rotate node x to left
+ */
+static void rotate_left(struct nvgpu_rbtree_node **root,
+ struct nvgpu_rbtree_node *x)
+{
+ struct nvgpu_rbtree_node *y = x->right;
+
+ /* establish x->right link */
+ x->right = y->left;
+ if (y->left)
+ y->left->parent = x;
+
+ /* establish y->parent link */
+ y->parent = x->parent;
+ if (x->parent) {
+ if (x == x->parent->left)
+ x->parent->left = y;
+ else
+ x->parent->right = y;
+ } else {
+ *root = y;
+ }
+
+ /* link x and y */
+ y->left = x;
+ x->parent = y;
+}
+
+/*
+ * rotate node x to right
+ */
+static void rotate_right(struct nvgpu_rbtree_node **root,
+ struct nvgpu_rbtree_node *x)
+{
+ struct nvgpu_rbtree_node *y = x->left;
+
+ /* establish x->left link */
+ x->left = y->right;
+ if (y->right)
+ y->right->parent = x;
+
+ /* establish y->parent link */
+ y->parent = x->parent;
+ if (x->parent) {
+ if (x == x->parent->right)
+ x->parent->right = y;
+ else
+ x->parent->left = y;
+ } else {
+ *root = y;
+ }
+
+ /* link x and y */
+ y->right = x;
+ x->parent = y;
+}
+
+/*
+ * maintain red-black tree balance after inserting node x
+ */
+static void insert_fixup(struct nvgpu_rbtree_node **root,
+ struct nvgpu_rbtree_node *x)
+{
+ /* check red-black properties */
+ while ((x != *root) && x->parent->is_red) {
+ /* we have a violation */
+ if (x->parent == x->parent->parent->left) {
+ struct nvgpu_rbtree_node *y = x->parent->parent->right;
+
+ if (y && y->is_red) {
+ /* uncle is RED */
+ x->parent->is_red = false;
+ y->is_red = false;
+ x->parent->parent->is_red = true;
+ x = x->parent->parent;
+ } else {
+ /* uncle is BLACK */
+ if (x == x->parent->right) {
+ /* make x a left child */
+ x = x->parent;
+ rotate_left(root, x);
+ }
+
+ /* recolor and rotate */
+ x->parent->is_red = false;
+ x->parent->parent->is_red = true;
+ rotate_right(root, x->parent->parent);
+ }
+ } else {
+ /* mirror image of above code */
+ struct nvgpu_rbtree_node *y = x->parent->parent->left;
+
+ if (y && y->is_red) {
+ /* uncle is RED */
+ x->parent->is_red = false;
+ y->is_red = false;
+ x->parent->parent->is_red = true;
+ x = x->parent->parent;
+ } else {
+ /* uncle is BLACK */
+ if (x == x->parent->left) {
+ x = x->parent;
+ rotate_right(root, x);
+ }
+ x->parent->is_red = false;
+ x->parent->parent->is_red = true;
+ rotate_left(root, x->parent->parent);
+ }
+ }
+ }
+
+ (*root)->is_red = false;
+}
+
+void nvgpu_rbtree_insert(struct nvgpu_rbtree_node *new_node,
+ struct nvgpu_rbtree_node **root)
+{
+ struct nvgpu_rbtree_node *curr;
+ struct nvgpu_rbtree_node *parent;
+
+ /* find future parent */
+ curr = *root;
+ parent = NULL;
+
+ while (curr) {
+ parent = curr;
+ if (new_node->key_start < curr->key_start)
+ curr = curr->left;
+ else if (new_node->key_start > curr->key_start)
+ curr = curr->right;
+ else
+ return; /* duplicate entry */
+ }
+
+ /* the caller allocated the node already, just fix the links */
+ new_node->parent = parent;
+ new_node->left = NULL;
+ new_node->right = NULL;
+ new_node->is_red = true;
+
+ /* insert node in tree */
+ if (parent) {
+ if (new_node->key_start < parent->key_start)
+ parent->left = new_node;
+ else
+ parent->right = new_node;
+ } else {
+ *root = new_node;
+ }
+
+ insert_fixup(root, new_node);
+}
+
+/*
+ * maintain red-black tree balance after deleting node x
+ */
+static void _delete_fixup(struct nvgpu_rbtree_node **root,
+ struct nvgpu_rbtree_node *parent_of_x,
+ struct nvgpu_rbtree_node *x)
+{
+ while ((x != *root) && (!x || !x->is_red)) {
+ /*
+ * NULL nodes are sentinel nodes. If we delete a sentinel
+ * node (x==NULL) it must have a parent node (or be the root).
+ * Hence, parent_of_x == NULL with
+ * x==NULL is never possible (tree invariant)
+ */
+
+ if ((parent_of_x != NULL) && (x == parent_of_x->left)) {
+ struct nvgpu_rbtree_node *w = parent_of_x->right;
+
+ if (w && w->is_red) {
+ w->is_red = false;
+ parent_of_x->is_red = true;
+ rotate_left(root, parent_of_x);
+ w = parent_of_x->right;
+ }
+
+ if (!w || ((!w->left || !w->left->is_red)
+ && (!w->right || !w->right->is_red))) {
+ if (w)
+ w->is_red = true;
+ x = parent_of_x;
+ } else {
+ if (!w->right || !w->right->is_red) {
+ w->left->is_red = false;
+ w->is_red = true;
+ rotate_right(root, w);
+ w = parent_of_x->right;
+ }
+ w->is_red = parent_of_x->is_red;
+ parent_of_x->is_red = false;
+ w->right->is_red = false;
+ rotate_left(root, parent_of_x);
+ x = *root;
+ }
+ } else if (parent_of_x != NULL) {
+ struct nvgpu_rbtree_node *w = parent_of_x->left;
+
+ if (w && w->is_red) {
+ w->is_red = false;
+ parent_of_x->is_red = true;
+ rotate_right(root, parent_of_x);
+ w = parent_of_x->left;
+ }
+
+ if (!w || ((!w->right || !w->right->is_red)
+ && (!w->left || !w->left->is_red))) {
+ if (w)
+ w->is_red = true;
+ x = parent_of_x;
+ } else {
+ if (!w->left || !w->left->is_red) {
+ w->right->is_red = false;
+ w->is_red = true;
+ rotate_left(root, w);
+ w = parent_of_x->left;
+ }
+ w->is_red = parent_of_x->is_red;
+ parent_of_x->is_red = false;
+ w->left->is_red = false;
+ rotate_right(root, parent_of_x);
+ x = *root;
+ }
+ }
+ parent_of_x = x->parent;
+ }
+
+ if (x)
+ x->is_red = false;
+}
+
+void nvgpu_rbtree_unlink(struct nvgpu_rbtree_node *node,
+ struct nvgpu_rbtree_node **root)
+{
+ struct nvgpu_rbtree_node *x;
+ struct nvgpu_rbtree_node *y;
+ struct nvgpu_rbtree_node *z;
+ struct nvgpu_rbtree_node *parent_of_x;
+ bool y_was_black;
+
+ z = node;
+
+ /* unlink */
+ if (!z->left || !z->right) {
+ /* y has a SENTINEL node as a child */
+ y = z;
+ } else {
+ /* find tree successor */
+ y = z->right;
+ while (y->left)
+ y = y->left;
+ }
+
+ /* x is y's only child */
+ if (y->left)
+ x = y->left;
+ else
+ x = y->right;
+
+ /* remove y from the parent chain */
+ parent_of_x = y->parent;
+ if (x)
+ x->parent = parent_of_x;
+
+ if (y->parent) {
+ if (y == y->parent->left)
+ y->parent->left = x;
+ else
+ y->parent->right = x;
+ } else {
+ *root = x;
+ }
+
+ y_was_black = !y->is_red;
+ if (y != z) {
+ /* we need to replace z with y so
+ * the memory for z can be freed
+ */
+ y->parent = z->parent;
+ if (z->parent) {
+ if (z == z->parent->left)
+ z->parent->left = y;
+ else
+ z->parent->right = y;
+ } else {
+ *root = y;
+ }
+
+ y->is_red = z->is_red;
+
+ y->left = z->left;
+ if (z->left)
+ z->left->parent = y;
+
+ y->right = z->right;
+ if (z->right)
+ z->right->parent = y;
+
+ if (parent_of_x == z)
+ parent_of_x = y;
+ }
+
+ if (y_was_black)
+ _delete_fixup(root, parent_of_x, x);
+}
+
+void nvgpu_rbtree_search(u64 key_start, struct nvgpu_rbtree_node **node,
+ struct nvgpu_rbtree_node *root)
+{
+ struct nvgpu_rbtree_node *curr = root;
+
+ while (curr) {
+ if (key_start < curr->key_start) {
+ curr = curr->left;
+ } else if (key_start > curr->key_start) {
+ curr = curr->right;
+ } else {
+ *node = curr;
+ return;
+ }
+ }
+
+ *node = NULL;
+}
+
+void nvgpu_rbtree_range_search(u64 key,
+ struct nvgpu_rbtree_node **node,
+ struct nvgpu_rbtree_node *root)
+{
+ struct nvgpu_rbtree_node *curr = root;
+
+ while (curr) {
+ if (key >= curr->key_start &&
+ key < curr->key_end) {
+ *node = curr;
+ return;
+ } else if (key < curr->key_start) {
+ curr = curr->left;
+ } else {
+ curr = curr->right;
+ }
+ }
+
+ *node = NULL;
+}
+
+void nvgpu_rbtree_less_than_search(u64 key_start,
+ struct nvgpu_rbtree_node **node,
+ struct nvgpu_rbtree_node *root)
+{
+ struct nvgpu_rbtree_node *curr = root;
+
+ while (curr) {
+ if (key_start <= curr->key_start) {
+ curr = curr->left;
+ } else {
+ *node = curr;
+ curr = curr->right;
+ }
+ }
+}
+
+void nvgpu_rbtree_enum_start(u64 key_start, struct nvgpu_rbtree_node **node,
+ struct nvgpu_rbtree_node *root)
+{
+ *node = NULL;
+
+ if (root) {
+ struct nvgpu_rbtree_node *curr = root;
+
+ while (curr) {
+ if (key_start < curr->key_start) {
+ *node = curr;
+ curr = curr->left;
+ } else if (key_start > curr->key_start) {
+ curr = curr->right;
+ } else {
+ *node = curr;
+ break;
+ }
+ }
+ }
+}
+
+void nvgpu_rbtree_enum_next(struct nvgpu_rbtree_node **node,
+ struct nvgpu_rbtree_node *root)
+{
+ struct nvgpu_rbtree_node *curr = NULL;
+
+ if (root && *node) {
+ /* if we don't have a right subtree return the parent */
+ curr = *node;
+
+ /* pick the leftmost node of the right subtree ? */
+ if (curr->right) {
+ curr = curr->right;
+ for (; curr->left;)
+ curr = curr->left;
+ } else {
+ /* go up until we find the right inorder node */
+ for (curr = curr->parent; curr; curr = curr->parent) {
+ if (curr->key_start > (*node)->key_start)
+ break;
+ }
+ }
+ }
+
+ *node = curr;
+}
diff --git a/drivers/gpu/nvgpu/include/nvgpu/rbtree.h b/drivers/gpu/nvgpu/include/nvgpu/rbtree.h
new file mode 100644
index 000000000..c29957c2b
--- /dev/null
+++ b/drivers/gpu/nvgpu/include/nvgpu/rbtree.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef __NVGPU_RBTREE_H__
+#define __NVGPU_RBTREE_H__
+
+#include
+
+struct nvgpu_rbtree_node {
+ u64 key_start;
+ u64 key_end;
+
+ bool is_red; /* !IsRed == IsBlack */
+
+ struct nvgpu_rbtree_node *parent;
+ struct nvgpu_rbtree_node *left;
+ struct nvgpu_rbtree_node *right;
+};
+
+/**
+ * nvgpu_rbtree_insert - insert a new node into rbtree
+ *
+ * @new_node Pointer to new node.
+ * @root Pointer to root of tree
+ *
+ * Nodes with duplicate key_start and overlapping ranges
+ * are not allowed
+ */
+void nvgpu_rbtree_insert(struct nvgpu_rbtree_node *new_node,
+ struct nvgpu_rbtree_node **root);
+
+/**
+ * nvgpu_rbtree_unlink - delete a node from rbtree
+ *
+ * @node Pointer to node to be deleted
+ * @root Pointer to root of tree
+ */
+void nvgpu_rbtree_unlink(struct nvgpu_rbtree_node *node,
+ struct nvgpu_rbtree_node **root);
+
+/**
+ * nvgpu_rbtree_search - search a given key in rbtree
+ *
+ * @key_start Key to be searched in rbtree
+ * @node Node pointer to be returned
+ * @root Pointer to root of tree
+ *
+ * This API will match given key against key_start of each node
+ * In case of a hit, node points to a node with given key
+ * In case of a miss, node is NULL
+ */
+void nvgpu_rbtree_search(u64 key_start, struct nvgpu_rbtree_node **node,
+ struct nvgpu_rbtree_node *root);
+
+/**
+ * nvgpu_rbtree_range_search - search a node with key falling in range
+ *
+ * @key Key to be searched in rbtree
+ * @node Node pointer to be returned
+ * @root Pointer to root of tree
+ *
+ * This API will match given key and find a node where key value
+ * falls within range of {start, end} keys
+ * In case of a hit, node points to a node with given key
+ * In case of a miss, node is NULL
+ */
+void nvgpu_rbtree_range_search(u64 key,
+ struct nvgpu_rbtree_node **node,
+ struct nvgpu_rbtree_node *root);
+
+/**
+ * nvgpu_rbtree_less_than_search - search a node with key lesser than given key
+ *
+ * @key_start Key to be searched in rbtree
+ * @node Node pointer to be returned
+ * @root Pointer to root of tree
+ *
+ * This API will match given key and find a node with highest
+ * key value lesser than given key
+ * In case of a hit, node points to a node with given key
+ * In case of a miss, node is NULL
+ */
+void nvgpu_rbtree_less_than_search(u64 key_start,
+ struct nvgpu_rbtree_node **node,
+ struct nvgpu_rbtree_node *root);
+
+/**
+ * nvgpu_rbtree_enum_start - enumerate tree starting at the node with specified value
+ *
+ * @key_start Key value to begin enumeration from
+ * @node Pointer to first node in the tree
+ * @root Pointer to root of tree
+ *
+ * This API returns node pointer pointing to first node in the rbtree
+ */
+void nvgpu_rbtree_enum_start(u64 key_start,
+ struct nvgpu_rbtree_node **node,
+ struct nvgpu_rbtree_node *root);
+
+/**
+ * nvgpu_rbtree_enum_next - find next node in enumeration
+ *
+ * @node Pointer to next node in the tree
+ * @root Pointer to root of tree
+ *
+ * This API returns node pointer pointing to next node in the rbtree
+ */
+void nvgpu_rbtree_enum_next(struct nvgpu_rbtree_node **node,
+ struct nvgpu_rbtree_node *root);
+
+#endif /* __NVGPU_RBTREE_H__ */