xref: /dpdk/drivers/bus/dpaa/include/dpaa_rbtree.h (revision d81734caccade4dc17d24d2ffd8b71244d35a69f)
1*d81734caSHemant Agrawal /* SPDX-License-Identifier: BSD-3-Clause
265ebc1beSShreyansh Jain  *
3*d81734caSHemant Agrawal  *   Copyright 2017 NXP
465ebc1beSShreyansh Jain  *
565ebc1beSShreyansh Jain  */
665ebc1beSShreyansh Jain 
765ebc1beSShreyansh Jain #ifndef __DPAA_RBTREE_H
865ebc1beSShreyansh Jain #define __DPAA_RBTREE_H
965ebc1beSShreyansh Jain 
1065ebc1beSShreyansh Jain #include <rte_common.h>
1165ebc1beSShreyansh Jain /************/
1265ebc1beSShreyansh Jain /* RB-trees */
1365ebc1beSShreyansh Jain /************/
1465ebc1beSShreyansh Jain 
1565ebc1beSShreyansh Jain /* Linux has a good RB-tree implementation, that we can't use (GPL). It also has
1665ebc1beSShreyansh Jain  * a flat/hooked-in interface that virtually requires license-contamination in
1765ebc1beSShreyansh Jain  * order to write a caller-compatible implementation. Instead, I've created an
1865ebc1beSShreyansh Jain  * RB-tree encapsulation on top of linux's primitives (it does some of the work
1965ebc1beSShreyansh Jain  * the client logic would normally do), and this gives us something we can
2065ebc1beSShreyansh Jain  * reimplement on LWE. Unfortunately there's no good+free RB-tree
2165ebc1beSShreyansh Jain  * implementations out there that are license-compatible and "flat" (ie. no
2265ebc1beSShreyansh Jain  * dynamic allocation). I did find a malloc-based one that I could convert, but
2365ebc1beSShreyansh Jain  * that will be a task for later on. For now, LWE's RB-tree is implemented using
2465ebc1beSShreyansh Jain  * an ordered linked-list.
2565ebc1beSShreyansh Jain  *
2665ebc1beSShreyansh Jain  * Note, the only linux-esque type is "struct rb_node", because it's used
2765ebc1beSShreyansh Jain  * statically in the exported header, so it can't be opaque. Our version doesn't
2865ebc1beSShreyansh Jain  * include a "rb_parent_color" field because we're doing linked-list instead of
2965ebc1beSShreyansh Jain  * a true rb-tree.
3065ebc1beSShreyansh Jain  */
3165ebc1beSShreyansh Jain 
3265ebc1beSShreyansh Jain struct rb_node {
3365ebc1beSShreyansh Jain 	struct rb_node *prev, *next;
3465ebc1beSShreyansh Jain };
3565ebc1beSShreyansh Jain 
3665ebc1beSShreyansh Jain struct dpa_rbtree {
3765ebc1beSShreyansh Jain 	struct rb_node *head, *tail;
3865ebc1beSShreyansh Jain };
3965ebc1beSShreyansh Jain 
4065ebc1beSShreyansh Jain #define DPAA_RBTREE { NULL, NULL }
dpa_rbtree_init(struct dpa_rbtree * tree)4165ebc1beSShreyansh Jain static inline void dpa_rbtree_init(struct dpa_rbtree *tree)
4265ebc1beSShreyansh Jain {
4365ebc1beSShreyansh Jain 	tree->head = tree->tail = NULL;
4465ebc1beSShreyansh Jain }
4565ebc1beSShreyansh Jain 
4665ebc1beSShreyansh Jain #define QMAN_NODE2OBJ(ptr, type, node_field) \
4765ebc1beSShreyansh Jain 	(type *)((char *)ptr - offsetof(type, node_field))
4865ebc1beSShreyansh Jain 
4965ebc1beSShreyansh Jain #define IMPLEMENT_DPAA_RBTREE(name, type, node_field, val_field) \
5065ebc1beSShreyansh Jain static inline int name##_push(struct dpa_rbtree *tree, type *obj) \
5165ebc1beSShreyansh Jain { \
5265ebc1beSShreyansh Jain 	struct rb_node *node = tree->head; \
5365ebc1beSShreyansh Jain 	if (!node) { \
5465ebc1beSShreyansh Jain 		tree->head = tree->tail = &obj->node_field; \
5565ebc1beSShreyansh Jain 		obj->node_field.prev = obj->node_field.next = NULL; \
5665ebc1beSShreyansh Jain 		return 0; \
5765ebc1beSShreyansh Jain 	} \
5865ebc1beSShreyansh Jain 	while (node) { \
5965ebc1beSShreyansh Jain 		type *item = QMAN_NODE2OBJ(node, type, node_field); \
6065ebc1beSShreyansh Jain 		if (obj->val_field == item->val_field) \
6165ebc1beSShreyansh Jain 			return -EBUSY; \
6265ebc1beSShreyansh Jain 		if (obj->val_field < item->val_field) { \
6365ebc1beSShreyansh Jain 			if (tree->head == node) \
6465ebc1beSShreyansh Jain 				tree->head = &obj->node_field; \
6565ebc1beSShreyansh Jain 			else \
6665ebc1beSShreyansh Jain 				node->prev->next = &obj->node_field; \
6765ebc1beSShreyansh Jain 			obj->node_field.prev = node->prev; \
6865ebc1beSShreyansh Jain 			obj->node_field.next = node; \
6965ebc1beSShreyansh Jain 			node->prev = &obj->node_field; \
7065ebc1beSShreyansh Jain 			return 0; \
7165ebc1beSShreyansh Jain 		} \
7265ebc1beSShreyansh Jain 		node = node->next; \
7365ebc1beSShreyansh Jain 	} \
7465ebc1beSShreyansh Jain 	obj->node_field.prev = tree->tail; \
7565ebc1beSShreyansh Jain 	obj->node_field.next = NULL; \
7665ebc1beSShreyansh Jain 	tree->tail->next = &obj->node_field; \
7765ebc1beSShreyansh Jain 	tree->tail = &obj->node_field; \
7865ebc1beSShreyansh Jain 	return 0; \
7965ebc1beSShreyansh Jain } \
8065ebc1beSShreyansh Jain static inline void name##_del(struct dpa_rbtree *tree, type *obj) \
8165ebc1beSShreyansh Jain { \
8265ebc1beSShreyansh Jain 	if (tree->head == &obj->node_field) { \
8365ebc1beSShreyansh Jain 		if (tree->tail == &obj->node_field) \
8465ebc1beSShreyansh Jain 			/* Only item in the list */ \
8565ebc1beSShreyansh Jain 			tree->head = tree->tail = NULL; \
8665ebc1beSShreyansh Jain 		else { \
8765ebc1beSShreyansh Jain 			/* Is the head, next != NULL */ \
8865ebc1beSShreyansh Jain 			tree->head = tree->head->next; \
8965ebc1beSShreyansh Jain 			tree->head->prev = NULL; \
9065ebc1beSShreyansh Jain 		} \
9165ebc1beSShreyansh Jain 	} else { \
9265ebc1beSShreyansh Jain 		if (tree->tail == &obj->node_field) { \
9365ebc1beSShreyansh Jain 			/* Is the tail, prev != NULL */ \
9465ebc1beSShreyansh Jain 			tree->tail = tree->tail->prev; \
9565ebc1beSShreyansh Jain 			tree->tail->next = NULL; \
9665ebc1beSShreyansh Jain 		} else { \
9765ebc1beSShreyansh Jain 			/* Is neither the head nor the tail */ \
9865ebc1beSShreyansh Jain 			obj->node_field.prev->next = obj->node_field.next; \
9965ebc1beSShreyansh Jain 			obj->node_field.next->prev = obj->node_field.prev; \
10065ebc1beSShreyansh Jain 		} \
10165ebc1beSShreyansh Jain 	} \
10265ebc1beSShreyansh Jain } \
10365ebc1beSShreyansh Jain static inline type *name##_find(struct dpa_rbtree *tree, u32 val) \
10465ebc1beSShreyansh Jain { \
10565ebc1beSShreyansh Jain 	struct rb_node *node = tree->head; \
10665ebc1beSShreyansh Jain 	while (node) { \
10765ebc1beSShreyansh Jain 		type *item = QMAN_NODE2OBJ(node, type, node_field); \
10865ebc1beSShreyansh Jain 		if (val == item->val_field) \
10965ebc1beSShreyansh Jain 			return item; \
11065ebc1beSShreyansh Jain 		if (val < item->val_field) \
11165ebc1beSShreyansh Jain 			return NULL; \
11265ebc1beSShreyansh Jain 		node = node->next; \
11365ebc1beSShreyansh Jain 	} \
11465ebc1beSShreyansh Jain 	return NULL; \
11565ebc1beSShreyansh Jain }
11665ebc1beSShreyansh Jain 
11765ebc1beSShreyansh Jain #endif /* __DPAA_RBTREE_H */
118