root/drivers/iommu/iommufd/double_span.h
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES.
 */
#ifndef __IOMMUFD_DOUBLE_SPAN_H
#define __IOMMUFD_DOUBLE_SPAN_H

#include <linux/interval_tree.h>

/*
 * This is a variation of the general interval_tree_span_iter that computes the
 * spans over the union of two different interval trees. Used ranges are broken
 * up and reported based on the tree that provides the interval. The first span
 * always takes priority. Like interval_tree_span_iter it is greedy and the same
 * value of is_used will not repeat on two iteration cycles.
 */
struct interval_tree_double_span_iter {
        struct rb_root_cached *itrees[2];
        struct interval_tree_span_iter spans[2];
        union {
                unsigned long start_hole;
                unsigned long start_used;
        };
        union {
                unsigned long last_hole;
                unsigned long last_used;
        };
        /* 0 = hole, 1 = used span[0], 2 = used span[1], -1 done iteration */
        int is_used;
};

void interval_tree_double_span_iter_update(
        struct interval_tree_double_span_iter *iter);
void interval_tree_double_span_iter_first(
        struct interval_tree_double_span_iter *iter,
        struct rb_root_cached *itree1, struct rb_root_cached *itree2,
        unsigned long first_index, unsigned long last_index);
void interval_tree_double_span_iter_next(
        struct interval_tree_double_span_iter *iter);

static inline bool
interval_tree_double_span_iter_done(struct interval_tree_double_span_iter *state)
{
        return state->is_used == -1;
}

#define interval_tree_for_each_double_span(span, itree1, itree2, first_index, \
                                           last_index)                        \
        for (interval_tree_double_span_iter_first(span, itree1, itree2,       \
                                                  first_index, last_index);   \
             !interval_tree_double_span_iter_done(span);                      \
             interval_tree_double_span_iter_next(span))

#endif