root/sys/dev/qat/qat_api/common/utils/lac_lock_free_stack.h
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright(c) 2007-2022 Intel Corporation */
#ifndef LAC_LOCK_FREE_STACK_H_1
#define LAC_LOCK_FREE_STACK_H_1
#include "lac_mem_pools.h"

typedef union {
        struct {
                uint64_t ctr : 16;
                uint64_t ptr : 48;
        };
        uint64_t atomic;
} pointer_t;

typedef struct {
        volatile pointer_t top;
} lock_free_stack_t;

static inline void *
PTR(const uintptr_t addr48)
{
#ifdef __x86_64__
        const int64_t addr64 = addr48 << 16;

        /* Do arithmetic shift to restore kernel canonical address (if not NULL)
         */
        return (void *)(addr64 >> 16);
#else
        return (void *)(addr48);
#endif
}

static inline lac_mem_blk_t *
pop(lock_free_stack_t *stack)
{
        pointer_t old_top;
        pointer_t new_top;
        lac_mem_blk_t *next;

        do {
                old_top.atomic = stack->top.atomic;
                next = PTR(old_top.ptr);
                if (NULL == next)
                        return next;

                new_top.ptr = (uintptr_t)next->pNext;
                new_top.ctr = old_top.ctr + 1;
        } while (!__sync_bool_compare_and_swap(&stack->top.atomic,
                                               old_top.atomic,
                                               new_top.atomic));

        return next;
}

static inline void
push(lock_free_stack_t *stack, lac_mem_blk_t *val)
{
        pointer_t new_top;
        pointer_t old_top;

        do {
                old_top.atomic = stack->top.atomic;
                val->pNext = PTR(old_top.ptr);
                new_top.ptr = (uintptr_t)val;
                new_top.ctr = old_top.ctr + 1;
        } while (!__sync_bool_compare_and_swap(&stack->top.atomic,
                                               old_top.atomic,
                                               new_top.atomic));
}

static inline lock_free_stack_t
_init_stack(void)
{
        lock_free_stack_t stack = { { { 0 } } };
        return stack;
}

static inline lac_mem_blk_t *
top(lock_free_stack_t *stack)
{
        pointer_t old_top = stack->top;
        lac_mem_blk_t *next = PTR(old_top.ptr);
        return next;
}

#endif