root/drivers/staging/media/atomisp/pci/runtime/queue/src/queue_access.c
// SPDX-License-Identifier: GPL-2.0
/*
 * Support for Intel Camera Imaging ISP subsystem.
 * Copyright (c) 2010 - 2015, Intel Corporation.
 */

#include "hmm.h"

#include "type_support.h"
#include "queue_access.h"
#include "ia_css_circbuf.h"
#include "sp.h"
#include "assert_support.h"

int ia_css_queue_load(
    struct ia_css_queue *rdesc,
    ia_css_circbuf_desc_t *cb_desc,
    uint32_t ignore_desc_flags)
{
        if (!rdesc || !cb_desc)
                return -EINVAL;

        if (rdesc->location == IA_CSS_QUEUE_LOC_SP) {
                assert(ignore_desc_flags <= QUEUE_IGNORE_DESC_FLAGS_MAX);

                if (0 == (ignore_desc_flags & QUEUE_IGNORE_SIZE_FLAG)) {
                        cb_desc->size = sp_dmem_load_uint8(rdesc->proc_id,
                                                           rdesc->desc.remote.cb_desc_addr
                                                           + offsetof(ia_css_circbuf_desc_t, size));

                        if (cb_desc->size == 0) {
                                /* Adding back the workaround which was removed
                                   while refactoring queues. When reading size
                                   through sp_dmem_load_*, sometimes we get back
                                   the value as zero. This causes division by 0
                                   exception as the size is used in a modular
                                   division operation. */
                                return -EDOM;
                        }
                }

                if (0 == (ignore_desc_flags & QUEUE_IGNORE_START_FLAG))
                        cb_desc->start = sp_dmem_load_uint8(rdesc->proc_id,
                                                            rdesc->desc.remote.cb_desc_addr
                                                            + offsetof(ia_css_circbuf_desc_t, start));

                if (0 == (ignore_desc_flags & QUEUE_IGNORE_END_FLAG))
                        cb_desc->end = sp_dmem_load_uint8(rdesc->proc_id,
                                                          rdesc->desc.remote.cb_desc_addr
                                                          + offsetof(ia_css_circbuf_desc_t, end));

                if (0 == (ignore_desc_flags & QUEUE_IGNORE_STEP_FLAG))
                        cb_desc->step = sp_dmem_load_uint8(rdesc->proc_id,
                                                           rdesc->desc.remote.cb_desc_addr
                                                           + offsetof(ia_css_circbuf_desc_t, step));

        } else if (rdesc->location == IA_CSS_QUEUE_LOC_HOST) {
                /* doing DMA transfer of entire structure */
                hmm_load(rdesc->desc.remote.cb_desc_addr,
                          (void *)cb_desc,
                          sizeof(ia_css_circbuf_desc_t));
        } else if (rdesc->location == IA_CSS_QUEUE_LOC_ISP) {
                /* Not supported yet */
                return -ENOTSUPP;
        }

        return 0;
}

int ia_css_queue_store(
    struct ia_css_queue *rdesc,
    ia_css_circbuf_desc_t *cb_desc,
    uint32_t ignore_desc_flags)
{
        if (!rdesc || !cb_desc)
                return -EINVAL;

        if (rdesc->location == IA_CSS_QUEUE_LOC_SP) {
                assert(ignore_desc_flags <= QUEUE_IGNORE_DESC_FLAGS_MAX);

                if (0 == (ignore_desc_flags & QUEUE_IGNORE_SIZE_FLAG))
                        sp_dmem_store_uint8(rdesc->proc_id,
                                            rdesc->desc.remote.cb_desc_addr
                                            + offsetof(ia_css_circbuf_desc_t, size),
                                            cb_desc->size);

                if (0 == (ignore_desc_flags & QUEUE_IGNORE_START_FLAG))
                        sp_dmem_store_uint8(rdesc->proc_id,
                                            rdesc->desc.remote.cb_desc_addr
                                            + offsetof(ia_css_circbuf_desc_t, start),
                                            cb_desc->start);

                if (0 == (ignore_desc_flags & QUEUE_IGNORE_END_FLAG))
                        sp_dmem_store_uint8(rdesc->proc_id,
                                            rdesc->desc.remote.cb_desc_addr
                                            + offsetof(ia_css_circbuf_desc_t, end),
                                            cb_desc->end);

                if (0 == (ignore_desc_flags & QUEUE_IGNORE_STEP_FLAG))
                        sp_dmem_store_uint8(rdesc->proc_id,
                                            rdesc->desc.remote.cb_desc_addr
                                            + offsetof(ia_css_circbuf_desc_t, step),
                                            cb_desc->step);
        } else if (rdesc->location == IA_CSS_QUEUE_LOC_HOST) {
                /* doing DMA transfer of entire structure */
                hmm_store(rdesc->desc.remote.cb_desc_addr,
                           (void *)cb_desc,
                           sizeof(ia_css_circbuf_desc_t));
        } else if (rdesc->location == IA_CSS_QUEUE_LOC_ISP) {
                /* Not supported yet */
                return -ENOTSUPP;
        }

        return 0;
}

int ia_css_queue_item_load(
    struct ia_css_queue *rdesc,
    u8 position,
    ia_css_circbuf_elem_t *item)
{
        if (!rdesc || !item)
                return -EINVAL;

        if (rdesc->location == IA_CSS_QUEUE_LOC_SP) {
                sp_dmem_load(rdesc->proc_id,
                             rdesc->desc.remote.cb_elems_addr
                             + position * sizeof(ia_css_circbuf_elem_t),
                             item,
                             sizeof(ia_css_circbuf_elem_t));
        } else if (rdesc->location == IA_CSS_QUEUE_LOC_HOST) {
                hmm_load(rdesc->desc.remote.cb_elems_addr
                          + position * sizeof(ia_css_circbuf_elem_t),
                          (void *)item,
                          sizeof(ia_css_circbuf_elem_t));
        } else if (rdesc->location == IA_CSS_QUEUE_LOC_ISP) {
                /* Not supported yet */
                return -ENOTSUPP;
        }

        return 0;
}

int ia_css_queue_item_store(
    struct ia_css_queue *rdesc,
    u8 position,
    ia_css_circbuf_elem_t *item)
{
        if (!rdesc || !item)
                return -EINVAL;

        if (rdesc->location == IA_CSS_QUEUE_LOC_SP) {
                sp_dmem_store(rdesc->proc_id,
                              rdesc->desc.remote.cb_elems_addr
                              + position * sizeof(ia_css_circbuf_elem_t),
                              item,
                              sizeof(ia_css_circbuf_elem_t));
        } else if (rdesc->location == IA_CSS_QUEUE_LOC_HOST) {
                hmm_store(rdesc->desc.remote.cb_elems_addr
                           + position * sizeof(ia_css_circbuf_elem_t),
                           (void *)item,
                           sizeof(ia_css_circbuf_elem_t));
        } else if (rdesc->location == IA_CSS_QUEUE_LOC_ISP) {
                /* Not supported yet */
                return -ENOTSUPP;
        }

        return 0;
}