1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
250aadb33SDmitri Tikhonov/*
350aadb33SDmitri Tikhonov * lsquic_spi.c - implementation of Stream Priority Iterator.
450aadb33SDmitri Tikhonov */
550aadb33SDmitri Tikhonov
650aadb33SDmitri Tikhonov#include <assert.h>
750aadb33SDmitri Tikhonov#include <inttypes.h>
850aadb33SDmitri Tikhonov#include <stdint.h>
950aadb33SDmitri Tikhonov#include <stdlib.h>
10c51ce338SDmitri Tikhonov#include <string.h>
1150aadb33SDmitri Tikhonov#include <sys/queue.h>
1250aadb33SDmitri Tikhonov#include <sys/types.h>
13461e84d8SAmol Deshpande#ifdef WIN32
14461e84d8SAmol Deshpande#include <vc_compat.h>
15461e84d8SAmol Deshpande#endif
1650aadb33SDmitri Tikhonov
1750aadb33SDmitri Tikhonov#include "lsquic_types.h"
1850aadb33SDmitri Tikhonov#include "lsquic_int_types.h"
1950aadb33SDmitri Tikhonov#include "lsquic_sfcw.h"
205392f7a3SLiteSpeed Tech#include "lsquic_varint.h"
215392f7a3SLiteSpeed Tech#include "lsquic_hq.h"
225392f7a3SLiteSpeed Tech#include "lsquic_hash.h"
2350aadb33SDmitri Tikhonov#include "lsquic_stream.h"
24fbc6cc04SDmitri Tikhonov#include "lsquic_conn_flow.h"
25fbc6cc04SDmitri Tikhonov#include "lsquic_rtt.h"
26fbc6cc04SDmitri Tikhonov#include "lsquic_conn_public.h"
2750aadb33SDmitri Tikhonov#include "lsquic_spi.h"
2850aadb33SDmitri Tikhonov
2950aadb33SDmitri Tikhonov#define LSQUIC_LOGGER_MODULE LSQLM_SPI
305392f7a3SLiteSpeed Tech#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(iter->spi_conn)
3150aadb33SDmitri Tikhonov#include "lsquic_logger.h"
3250aadb33SDmitri Tikhonov
33461e84d8SAmol Deshpande#define SPI_DEBUG(fmt, ...) LSQ_DEBUG("%s: " fmt, iter->spi_name, __VA_ARGS__)
3450aadb33SDmitri Tikhonov
3550aadb33SDmitri Tikhonov#define NEXT_STREAM(stream, off) \
3650aadb33SDmitri Tikhonov    (* (struct lsquic_stream **) ((unsigned char *) (stream) + (off)))
3750aadb33SDmitri Tikhonov
3850aadb33SDmitri Tikhonov
3950aadb33SDmitri Tikhonovstatic void
4050aadb33SDmitri Tikhonovadd_stream_to_spi (struct stream_prio_iter *iter, lsquic_stream_t *stream)
4150aadb33SDmitri Tikhonov{
4250aadb33SDmitri Tikhonov    unsigned set, bit;
4350aadb33SDmitri Tikhonov    set = stream->sm_priority >> 6;
4450aadb33SDmitri Tikhonov    bit = stream->sm_priority & 0x3F;
4550aadb33SDmitri Tikhonov    if (!(iter->spi_set[set] & (1ULL << bit)))
4650aadb33SDmitri Tikhonov    {
4750aadb33SDmitri Tikhonov        iter->spi_set[set] |= 1ULL << bit;
4850aadb33SDmitri Tikhonov        TAILQ_INIT(&iter->spi_streams[ stream->sm_priority ]);
4950aadb33SDmitri Tikhonov    }
5050aadb33SDmitri Tikhonov    TAILQ_INSERT_TAIL(&iter->spi_streams[ stream->sm_priority ],
5150aadb33SDmitri Tikhonov                                                stream, next_prio_stream);
52a0e1aeeeSDmitri Tikhonov    ++iter->spi_n_added;
5350aadb33SDmitri Tikhonov}
5450aadb33SDmitri Tikhonov
5550aadb33SDmitri Tikhonov
5650aadb33SDmitri Tikhonovvoid
57fbc6cc04SDmitri Tikhonovlsquic_spi_init (void *iter_p, struct lsquic_stream *first,
585392f7a3SLiteSpeed Tech         struct lsquic_stream *last, uintptr_t next_ptr_offset,
59fbc6cc04SDmitri Tikhonov         struct lsquic_conn_public *conn_pub,
605392f7a3SLiteSpeed Tech         const char *name,
615392f7a3SLiteSpeed Tech         int (*filter)(void *filter_ctx, struct lsquic_stream *),
625392f7a3SLiteSpeed Tech         void *filter_ctx)
6350aadb33SDmitri Tikhonov{
64fbc6cc04SDmitri Tikhonov    struct stream_prio_iter *const iter = iter_p;
6550aadb33SDmitri Tikhonov    struct lsquic_stream *stream;
6650aadb33SDmitri Tikhonov    unsigned count;
6750aadb33SDmitri Tikhonov
68fbc6cc04SDmitri Tikhonov    iter->spi_conn          = conn_pub->lconn;
6950aadb33SDmitri Tikhonov    iter->spi_name          = name ? name : "UNSET";
7050aadb33SDmitri Tikhonov    iter->spi_set[0]        = 0;
7150aadb33SDmitri Tikhonov    iter->spi_set[1]        = 0;
7250aadb33SDmitri Tikhonov    iter->spi_set[2]        = 0;
7350aadb33SDmitri Tikhonov    iter->spi_set[3]        = 0;
7450aadb33SDmitri Tikhonov    iter->spi_cur_prio      = 0;
7550aadb33SDmitri Tikhonov    iter->spi_next_stream   = NULL;
76a0e1aeeeSDmitri Tikhonov    iter->spi_n_added       = 0;
7750aadb33SDmitri Tikhonov
7850aadb33SDmitri Tikhonov    stream = first;
7950aadb33SDmitri Tikhonov    count = 0;
8050aadb33SDmitri Tikhonov
8119f667fbSDmitri Tikhonov    if (filter)
8219f667fbSDmitri Tikhonov        while (1)
8319f667fbSDmitri Tikhonov        {
8419f667fbSDmitri Tikhonov            if (filter(filter_ctx, stream))
8519f667fbSDmitri Tikhonov            {
8619f667fbSDmitri Tikhonov                add_stream_to_spi(iter, stream);
8719f667fbSDmitri Tikhonov                ++count;
8819f667fbSDmitri Tikhonov            }
8919f667fbSDmitri Tikhonov            if (stream == last)
9019f667fbSDmitri Tikhonov                break;
9119f667fbSDmitri Tikhonov            stream = NEXT_STREAM(stream, next_ptr_offset);
9219f667fbSDmitri Tikhonov        }
9319f667fbSDmitri Tikhonov    else
9419f667fbSDmitri Tikhonov        while (1)
9519f667fbSDmitri Tikhonov        {
9619f667fbSDmitri Tikhonov            add_stream_to_spi(iter, stream);
9719f667fbSDmitri Tikhonov            ++count;
9819f667fbSDmitri Tikhonov            if (stream == last)
9919f667fbSDmitri Tikhonov                break;
10019f667fbSDmitri Tikhonov            stream = NEXT_STREAM(stream, next_ptr_offset);
10119f667fbSDmitri Tikhonov        }
102c51ce338SDmitri Tikhonov
10350aadb33SDmitri Tikhonov    if (count > 2)
10450aadb33SDmitri Tikhonov        SPI_DEBUG("initialized; # elems: %u; sets: [ %016"PRIX64", %016"PRIX64
10550aadb33SDmitri Tikhonov            ", %016"PRIX64", %016"PRIX64" ]", count, iter->spi_set[0],
10650aadb33SDmitri Tikhonov            iter->spi_set[1], iter->spi_set[2], iter->spi_set[3]);
10750aadb33SDmitri Tikhonov}
10850aadb33SDmitri Tikhonov
10950aadb33SDmitri Tikhonov
11050aadb33SDmitri Tikhonovstatic int
11150aadb33SDmitri Tikhonovfind_and_set_lowest_priority (struct stream_prio_iter *iter)
11250aadb33SDmitri Tikhonov{
11350aadb33SDmitri Tikhonov    unsigned set, prio;
11450aadb33SDmitri Tikhonov    uint64_t mask;
11550aadb33SDmitri Tikhonov
11650aadb33SDmitri Tikhonov    for (set = 0, prio = 0; set < 4; ++set, prio += 64)
11750aadb33SDmitri Tikhonov        if (iter->spi_set[ set ])
11850aadb33SDmitri Tikhonov            break;
11950aadb33SDmitri Tikhonov
1208ca33e0eSDmitri Tikhonov    if (set >= 4)
12150aadb33SDmitri Tikhonov    {
12250aadb33SDmitri Tikhonov        //SPI_DEBUG("%s: cannot find any", __func__);
12350aadb33SDmitri Tikhonov        return -1;
12450aadb33SDmitri Tikhonov    }
12550aadb33SDmitri Tikhonov
12650aadb33SDmitri Tikhonov    mask = iter->spi_set[set];
12750aadb33SDmitri Tikhonov    if (!(mask & ((1ULL << 32) - 1))) { prio += 32; mask >>= 32; }
12850aadb33SDmitri Tikhonov    if (!(mask & ((1ULL << 16) - 1))) { prio += 16; mask >>= 16; }
12950aadb33SDmitri Tikhonov    if (!(mask & ((1ULL <<  8) - 1))) { prio +=  8; mask >>=  8; }
13050aadb33SDmitri Tikhonov    if (!(mask & ((1ULL <<  4) - 1))) { prio +=  4; mask >>=  4; }
13150aadb33SDmitri Tikhonov    if (!(mask & ((1ULL <<  2) - 1))) { prio +=  2; mask >>=  2; }
13250aadb33SDmitri Tikhonov    if (!(mask & ((1ULL <<  1) - 1))) { prio +=  1;              }
13350aadb33SDmitri Tikhonov
13450aadb33SDmitri Tikhonov#ifndef NDEBUG
13550aadb33SDmitri Tikhonov    unsigned bit;
13650aadb33SDmitri Tikhonov    set = prio >> 6;
13750aadb33SDmitri Tikhonov    bit = prio & 0x3F;
13850aadb33SDmitri Tikhonov    assert(iter->spi_set[ set ] & (1ULL << bit));
13950aadb33SDmitri Tikhonov#endif
14050aadb33SDmitri Tikhonov
14150aadb33SDmitri Tikhonov    SPI_DEBUG("%s: prio %u -> %u", __func__, iter->spi_cur_prio, prio);
1422d296031SDmitri Tikhonov    iter->spi_cur_prio = (unsigned char) prio;
14350aadb33SDmitri Tikhonov    return 0;
14450aadb33SDmitri Tikhonov}
14550aadb33SDmitri Tikhonov
14650aadb33SDmitri Tikhonov
14750aadb33SDmitri Tikhonovstatic int
14850aadb33SDmitri Tikhonovfind_and_set_next_priority (struct stream_prio_iter *iter)
14950aadb33SDmitri Tikhonov{
15050aadb33SDmitri Tikhonov    unsigned set, bit, prio;
15150aadb33SDmitri Tikhonov    uint64_t mask;
15250aadb33SDmitri Tikhonov
15350aadb33SDmitri Tikhonov    /* Examine values in the same set first */
15450aadb33SDmitri Tikhonov    set = iter->spi_cur_prio >> 6;
15550aadb33SDmitri Tikhonov    bit = iter->spi_cur_prio & 0x3F;
15650aadb33SDmitri Tikhonov    prio = 64 * set;
15750aadb33SDmitri Tikhonov
15850aadb33SDmitri Tikhonov    if (bit < 63)
15950aadb33SDmitri Tikhonov    {
16050aadb33SDmitri Tikhonov        mask = iter->spi_set[set];
16150aadb33SDmitri Tikhonov        mask &= ~((1ULL << (bit + 1)) - 1);
16250aadb33SDmitri Tikhonov        if (mask)
16350aadb33SDmitri Tikhonov            goto calc_priority;
16450aadb33SDmitri Tikhonov    }
16550aadb33SDmitri Tikhonov
16650aadb33SDmitri Tikhonov    ++set;
16750aadb33SDmitri Tikhonov    prio += 64;
16850aadb33SDmitri Tikhonov    for (; set < 4; ++set, prio += 64)
16950aadb33SDmitri Tikhonov        if (iter->spi_set[ set ])
17050aadb33SDmitri Tikhonov            break;
17150aadb33SDmitri Tikhonov
17203fb9352SDmitri Tikhonov    if (set >= 4)
17350aadb33SDmitri Tikhonov    {
17450aadb33SDmitri Tikhonov        //SPI_DEBUG("%s: cannot find any", __func__);
17550aadb33SDmitri Tikhonov        return -1;
17650aadb33SDmitri Tikhonov    }
17750aadb33SDmitri Tikhonov
17850aadb33SDmitri Tikhonov    mask = iter->spi_set[set];
17950aadb33SDmitri Tikhonov
18050aadb33SDmitri Tikhonov  calc_priority:
18150aadb33SDmitri Tikhonov    if (!(mask & ((1ULL << 32) - 1))) { prio += 32; mask >>= 32; }
18250aadb33SDmitri Tikhonov    if (!(mask & ((1ULL << 16) - 1))) { prio += 16; mask >>= 16; }
18350aadb33SDmitri Tikhonov    if (!(mask & ((1ULL <<  8) - 1))) { prio +=  8; mask >>=  8; }
18450aadb33SDmitri Tikhonov    if (!(mask & ((1ULL <<  4) - 1))) { prio +=  4; mask >>=  4; }
18550aadb33SDmitri Tikhonov    if (!(mask & ((1ULL <<  2) - 1))) { prio +=  2; mask >>=  2; }
18650aadb33SDmitri Tikhonov    if (!(mask & ((1ULL <<  1) - 1))) { prio +=  1;              }
18750aadb33SDmitri Tikhonov
18850aadb33SDmitri Tikhonov#ifndef NDEBUG
18950aadb33SDmitri Tikhonov    set = prio >> 6;
19050aadb33SDmitri Tikhonov    bit = prio & 0x3F;
19150aadb33SDmitri Tikhonov    assert(iter->spi_set[ set ] & (1ULL << bit));
19250aadb33SDmitri Tikhonov#endif
19350aadb33SDmitri Tikhonov
19450aadb33SDmitri Tikhonov    SPI_DEBUG("%s: prio %u -> %u", __func__, iter->spi_cur_prio, prio);
1952d296031SDmitri Tikhonov    iter->spi_cur_prio = (unsigned char) prio;
19650aadb33SDmitri Tikhonov    return 0;
19750aadb33SDmitri Tikhonov}
19850aadb33SDmitri Tikhonov
19950aadb33SDmitri Tikhonov
20050aadb33SDmitri Tikhonovlsquic_stream_t *
201fbc6cc04SDmitri Tikhonovlsquic_spi_first (void *iter_p)
20250aadb33SDmitri Tikhonov{
203fbc6cc04SDmitri Tikhonov    struct stream_prio_iter *const iter = iter_p;
20450aadb33SDmitri Tikhonov    lsquic_stream_t *stream;
20550aadb33SDmitri Tikhonov    unsigned set, bit;
20650aadb33SDmitri Tikhonov
20750aadb33SDmitri Tikhonov    iter->spi_cur_prio = 0;
20850aadb33SDmitri Tikhonov    set = iter->spi_cur_prio >> 6;
20950aadb33SDmitri Tikhonov    bit = iter->spi_cur_prio & 0x3F;
21050aadb33SDmitri Tikhonov
21150aadb33SDmitri Tikhonov    if (!(iter->spi_set[set] & (1ULL << bit)))
21250aadb33SDmitri Tikhonov    {
21350aadb33SDmitri Tikhonov        if (0 != find_and_set_lowest_priority(iter))
21450aadb33SDmitri Tikhonov        {
21550aadb33SDmitri Tikhonov            SPI_DEBUG("%s: return NULL", __func__);
21650aadb33SDmitri Tikhonov            return NULL;
21750aadb33SDmitri Tikhonov        }
21850aadb33SDmitri Tikhonov    }
21950aadb33SDmitri Tikhonov
22050aadb33SDmitri Tikhonov    stream = TAILQ_FIRST(&iter->spi_streams[ iter->spi_cur_prio ]);
22150aadb33SDmitri Tikhonov    iter->spi_next_stream = TAILQ_NEXT(stream, next_prio_stream);
2225392f7a3SLiteSpeed Tech    if (LSQ_LOG_ENABLED(LSQ_LOG_DEBUG) && !lsquic_stream_is_critical(stream))
2235392f7a3SLiteSpeed Tech        SPI_DEBUG("%s: return stream %"PRIu64", priority %u", __func__,
2245392f7a3SLiteSpeed Tech                                            stream->id, iter->spi_cur_prio);
22550aadb33SDmitri Tikhonov    return stream;
22650aadb33SDmitri Tikhonov}
22750aadb33SDmitri Tikhonov
22850aadb33SDmitri Tikhonov
22950aadb33SDmitri Tikhonovlsquic_stream_t *
230fbc6cc04SDmitri Tikhonovlsquic_spi_next (void *iter_p)
23150aadb33SDmitri Tikhonov{
232fbc6cc04SDmitri Tikhonov    struct stream_prio_iter *const iter = iter_p;
23350aadb33SDmitri Tikhonov    lsquic_stream_t *stream;
23450aadb33SDmitri Tikhonov
23550aadb33SDmitri Tikhonov    stream = iter->spi_next_stream;
23650aadb33SDmitri Tikhonov    if (stream)
23750aadb33SDmitri Tikhonov    {
23850aadb33SDmitri Tikhonov        iter->spi_next_stream = TAILQ_NEXT(stream, next_prio_stream);
2395392f7a3SLiteSpeed Tech        if (LSQ_LOG_ENABLED(LSQ_LOG_DEBUG) && !lsquic_stream_is_critical(stream))
2405392f7a3SLiteSpeed Tech            SPI_DEBUG("%s: return stream %"PRIu64", priority %u", __func__,
2415392f7a3SLiteSpeed Tech                                            stream->id, iter->spi_cur_prio);
24250aadb33SDmitri Tikhonov        return stream;
24350aadb33SDmitri Tikhonov    }
24450aadb33SDmitri Tikhonov
24550aadb33SDmitri Tikhonov    if (0 != find_and_set_next_priority(iter))
24650aadb33SDmitri Tikhonov    {
24750aadb33SDmitri Tikhonov        //SPI_DEBUG("%s: return NULL", __func__);
24850aadb33SDmitri Tikhonov        return NULL;
24950aadb33SDmitri Tikhonov    }
25050aadb33SDmitri Tikhonov
25150aadb33SDmitri Tikhonov    stream = TAILQ_FIRST(&iter->spi_streams[ iter->spi_cur_prio ]);
25250aadb33SDmitri Tikhonov    iter->spi_next_stream = TAILQ_NEXT(stream, next_prio_stream);
25350aadb33SDmitri Tikhonov
2545392f7a3SLiteSpeed Tech    if (LSQ_LOG_ENABLED(LSQ_LOG_DEBUG) && !lsquic_stream_is_critical(stream))
2555392f7a3SLiteSpeed Tech        SPI_DEBUG("%s: return stream %"PRIu64", priority %u", __func__,
2565392f7a3SLiteSpeed Tech                                            stream->id, iter->spi_cur_prio);
25750aadb33SDmitri Tikhonov    return stream;
25850aadb33SDmitri Tikhonov}
25950aadb33SDmitri Tikhonov
26050aadb33SDmitri Tikhonov
261c51ce338SDmitri Tikhonovstatic int
262c51ce338SDmitri Tikhonovhave_non_critical_streams (const struct stream_prio_iter *iter)
263c51ce338SDmitri Tikhonov{
264c51ce338SDmitri Tikhonov    const struct lsquic_stream *stream;
265c51ce338SDmitri Tikhonov    TAILQ_FOREACH(stream, &iter->spi_streams[ iter->spi_cur_prio ],
266c51ce338SDmitri Tikhonov                                                        next_prio_stream)
267c51ce338SDmitri Tikhonov        if (!lsquic_stream_is_critical(stream))
268c51ce338SDmitri Tikhonov            return 1;
269c51ce338SDmitri Tikhonov    return 0;
270c51ce338SDmitri Tikhonov}
271c51ce338SDmitri Tikhonov
272c51ce338SDmitri Tikhonov
273a0e1aeeeSDmitri Tikhonov#if __GNUC__
274a0e1aeeeSDmitri Tikhonov#   define popcount __builtin_popcountll
275a0e1aeeeSDmitri Tikhonov#else
276a0e1aeeeSDmitri Tikhonovstatic int
277a0e1aeeeSDmitri Tikhonovpopcount (unsigned long long v)
278a0e1aeeeSDmitri Tikhonov{
279a0e1aeeeSDmitri Tikhonov    int count, i;
280a0e1aeeeSDmitri Tikhonov    for (i = 0, count = 0; i < sizeof(v) * 8; ++i)
281a0e1aeeeSDmitri Tikhonov        if (v & (1 << i))
282a0e1aeeeSDmitri Tikhonov            ++count;
283a0e1aeeeSDmitri Tikhonov    return count;
284a0e1aeeeSDmitri Tikhonov}
285a0e1aeeeSDmitri Tikhonov
286a0e1aeeeSDmitri Tikhonov
287a0e1aeeeSDmitri Tikhonov#endif
288a0e1aeeeSDmitri Tikhonov
289a0e1aeeeSDmitri Tikhonov
290a0e1aeeeSDmitri Tikhonovstatic int
291a0e1aeeeSDmitri Tikhonovspi_has_more_than_one_queue (const struct stream_prio_iter *iter)
292a0e1aeeeSDmitri Tikhonov{
293a0e1aeeeSDmitri Tikhonov    unsigned i;
294a0e1aeeeSDmitri Tikhonov    int count;
295a0e1aeeeSDmitri Tikhonov
296a0e1aeeeSDmitri Tikhonov    if (iter->spi_n_added < 2)
297a0e1aeeeSDmitri Tikhonov        return 0;
298a0e1aeeeSDmitri Tikhonov
299a0e1aeeeSDmitri Tikhonov    count = 0;
300a0e1aeeeSDmitri Tikhonov    for (i = 0; i < sizeof(iter->spi_set) / sizeof(iter->spi_set[0]); ++i)
301a0e1aeeeSDmitri Tikhonov    {
302a0e1aeeeSDmitri Tikhonov        count += popcount(iter->spi_set[i]);
303a0e1aeeeSDmitri Tikhonov        if (count > 1)
304a0e1aeeeSDmitri Tikhonov            return 1;
305a0e1aeeeSDmitri Tikhonov    }
306a0e1aeeeSDmitri Tikhonov
307a0e1aeeeSDmitri Tikhonov    return 0;
308a0e1aeeeSDmitri Tikhonov}
309a0e1aeeeSDmitri Tikhonov
310a0e1aeeeSDmitri Tikhonov
311c51ce338SDmitri Tikhonovstatic void
312fbc6cc04SDmitri Tikhonovspi_drop_high_or_non_high (void *iter_p, int drop_high)
313c51ce338SDmitri Tikhonov{
314fbc6cc04SDmitri Tikhonov    struct stream_prio_iter *const iter = iter_p;
315c51ce338SDmitri Tikhonov    uint64_t new_set[ sizeof(iter->spi_set) / sizeof(iter->spi_set[0]) ];
316c51ce338SDmitri Tikhonov    unsigned bit, set, n;
317c51ce338SDmitri Tikhonov
318a0e1aeeeSDmitri Tikhonov    if (!spi_has_more_than_one_queue(iter))
319a0e1aeeeSDmitri Tikhonov        return;
320a0e1aeeeSDmitri Tikhonov
321c51ce338SDmitri Tikhonov    memset(new_set, 0, sizeof(new_set));
322c51ce338SDmitri Tikhonov
323c51ce338SDmitri Tikhonov    find_and_set_lowest_priority(iter);
324c51ce338SDmitri Tikhonov    set = iter->spi_cur_prio >> 6;
325c51ce338SDmitri Tikhonov    bit = iter->spi_cur_prio & 0x3F;
326c51ce338SDmitri Tikhonov    new_set[set] |= 1ULL << bit;
327c51ce338SDmitri Tikhonov
328c51ce338SDmitri Tikhonov    if (!have_non_critical_streams(iter))
329c51ce338SDmitri Tikhonov    {
330c51ce338SDmitri Tikhonov        ++iter->spi_cur_prio;
331c51ce338SDmitri Tikhonov        find_and_set_lowest_priority(iter);
332c51ce338SDmitri Tikhonov        set = iter->spi_cur_prio >> 6;
333c51ce338SDmitri Tikhonov        bit = iter->spi_cur_prio & 0x3F;
334c51ce338SDmitri Tikhonov        new_set[set] |= 1ULL << bit;
335c51ce338SDmitri Tikhonov    }
336c51ce338SDmitri Tikhonov
337c51ce338SDmitri Tikhonov    for (n = 0; n < sizeof(new_set) / sizeof(new_set[0]); ++n)
338c51ce338SDmitri Tikhonov        if (drop_high)
339c51ce338SDmitri Tikhonov            iter->spi_set[n] &= ~new_set[n];
340c51ce338SDmitri Tikhonov        else
341c51ce338SDmitri Tikhonov            iter->spi_set[n] = new_set[n];
342c51ce338SDmitri Tikhonov}
343c51ce338SDmitri Tikhonov
344c51ce338SDmitri Tikhonov
345c51ce338SDmitri Tikhonovvoid
346fbc6cc04SDmitri Tikhonovlsquic_spi_drop_high (void *iter_p)
347c51ce338SDmitri Tikhonov{
348fbc6cc04SDmitri Tikhonov    struct stream_prio_iter *const iter = iter_p;
349c51ce338SDmitri Tikhonov    spi_drop_high_or_non_high(iter, 1);
350c51ce338SDmitri Tikhonov}
351c51ce338SDmitri Tikhonov
352c51ce338SDmitri Tikhonov
35350aadb33SDmitri Tikhonovvoid
354fbc6cc04SDmitri Tikhonovlsquic_spi_drop_non_high (void *iter_p)
35550aadb33SDmitri Tikhonov{
356fbc6cc04SDmitri Tikhonov    struct stream_prio_iter *const iter = iter_p;
357c51ce338SDmitri Tikhonov    spi_drop_high_or_non_high(iter, 0);
35850aadb33SDmitri Tikhonov}
359fbc6cc04SDmitri Tikhonov
360fbc6cc04SDmitri Tikhonov
361fbc6cc04SDmitri Tikhonovvoid
362fbc6cc04SDmitri Tikhonovlsquic_spi_cleanup (void *iter_p)
363fbc6cc04SDmitri Tikhonov{
364fbc6cc04SDmitri Tikhonov}
365