root/drivers/misc/ocxl/mmio.c
// SPDX-License-Identifier: GPL-2.0+
// Copyright 2019 IBM Corp.
#include <linux/sched/mm.h>
#include "trace.h"
#include "ocxl_internal.h"

int ocxl_global_mmio_read32(struct ocxl_afu *afu, size_t offset,
                                enum ocxl_endian endian, u32 *val)
{
        if (offset > afu->config.global_mmio_size - 4)
                return -EINVAL;

#ifdef __BIG_ENDIAN__
        if (endian == OCXL_HOST_ENDIAN)
                endian = OCXL_BIG_ENDIAN;
#endif

        switch (endian) {
        case OCXL_BIG_ENDIAN:
                *val = readl_be((char *)afu->global_mmio_ptr + offset);
                break;

        default:
                *val = readl((char *)afu->global_mmio_ptr + offset);
                break;
        }

        return 0;
}
EXPORT_SYMBOL_GPL(ocxl_global_mmio_read32);

int ocxl_global_mmio_read64(struct ocxl_afu *afu, size_t offset,
                                enum ocxl_endian endian, u64 *val)
{
        if (offset > afu->config.global_mmio_size - 8)
                return -EINVAL;

#ifdef __BIG_ENDIAN__
        if (endian == OCXL_HOST_ENDIAN)
                endian = OCXL_BIG_ENDIAN;
#endif

        switch (endian) {
        case OCXL_BIG_ENDIAN:
                *val = readq_be((char *)afu->global_mmio_ptr + offset);
                break;

        default:
                *val = readq((char *)afu->global_mmio_ptr + offset);
                break;
        }

        return 0;
}
EXPORT_SYMBOL_GPL(ocxl_global_mmio_read64);

int ocxl_global_mmio_write32(struct ocxl_afu *afu, size_t offset,
                                enum ocxl_endian endian, u32 val)
{
        if (offset > afu->config.global_mmio_size - 4)
                return -EINVAL;

#ifdef __BIG_ENDIAN__
        if (endian == OCXL_HOST_ENDIAN)
                endian = OCXL_BIG_ENDIAN;
#endif

        switch (endian) {
        case OCXL_BIG_ENDIAN:
                writel_be(val, (char *)afu->global_mmio_ptr + offset);
                break;

        default:
                writel(val, (char *)afu->global_mmio_ptr + offset);
                break;
        }


        return 0;
}
EXPORT_SYMBOL_GPL(ocxl_global_mmio_write32);

int ocxl_global_mmio_write64(struct ocxl_afu *afu, size_t offset,
                                enum ocxl_endian endian, u64 val)
{
        if (offset > afu->config.global_mmio_size - 8)
                return -EINVAL;

#ifdef __BIG_ENDIAN__
        if (endian == OCXL_HOST_ENDIAN)
                endian = OCXL_BIG_ENDIAN;
#endif

        switch (endian) {
        case OCXL_BIG_ENDIAN:
                writeq_be(val, (char *)afu->global_mmio_ptr + offset);
                break;

        default:
                writeq(val, (char *)afu->global_mmio_ptr + offset);
                break;
        }


        return 0;
}
EXPORT_SYMBOL_GPL(ocxl_global_mmio_write64);

int ocxl_global_mmio_set32(struct ocxl_afu *afu, size_t offset,
                                enum ocxl_endian endian, u32 mask)
{
        u32 tmp;

        if (offset > afu->config.global_mmio_size - 4)
                return -EINVAL;

#ifdef __BIG_ENDIAN__
        if (endian == OCXL_HOST_ENDIAN)
                endian = OCXL_BIG_ENDIAN;
#endif

        switch (endian) {
        case OCXL_BIG_ENDIAN:
                tmp = readl_be((char *)afu->global_mmio_ptr + offset);
                tmp |= mask;
                writel_be(tmp, (char *)afu->global_mmio_ptr + offset);
                break;

        default:
                tmp = readl((char *)afu->global_mmio_ptr + offset);
                tmp |= mask;
                writel(tmp, (char *)afu->global_mmio_ptr + offset);
                break;
        }

        return 0;
}
EXPORT_SYMBOL_GPL(ocxl_global_mmio_set32);

int ocxl_global_mmio_set64(struct ocxl_afu *afu, size_t offset,
                                enum ocxl_endian endian, u64 mask)
{
        u64 tmp;

        if (offset > afu->config.global_mmio_size - 8)
                return -EINVAL;

#ifdef __BIG_ENDIAN__
        if (endian == OCXL_HOST_ENDIAN)
                endian = OCXL_BIG_ENDIAN;
#endif

        switch (endian) {
        case OCXL_BIG_ENDIAN:
                tmp = readq_be((char *)afu->global_mmio_ptr + offset);
                tmp |= mask;
                writeq_be(tmp, (char *)afu->global_mmio_ptr + offset);
                break;

        default:
                tmp = readq((char *)afu->global_mmio_ptr + offset);
                tmp |= mask;
                writeq(tmp, (char *)afu->global_mmio_ptr + offset);
                break;
        }

        return 0;
}
EXPORT_SYMBOL_GPL(ocxl_global_mmio_set64);

int ocxl_global_mmio_clear32(struct ocxl_afu *afu, size_t offset,
                                enum ocxl_endian endian, u32 mask)
{
        u32 tmp;

        if (offset > afu->config.global_mmio_size - 4)
                return -EINVAL;

#ifdef __BIG_ENDIAN__
        if (endian == OCXL_HOST_ENDIAN)
                endian = OCXL_BIG_ENDIAN;
#endif

        switch (endian) {
        case OCXL_BIG_ENDIAN:
                tmp = readl_be((char *)afu->global_mmio_ptr + offset);
                tmp &= ~mask;
                writel_be(tmp, (char *)afu->global_mmio_ptr + offset);
                break;

        default:
                tmp = readl((char *)afu->global_mmio_ptr + offset);
                tmp &= ~mask;
                writel(tmp, (char *)afu->global_mmio_ptr + offset);
                break;
        }


        return 0;
}
EXPORT_SYMBOL_GPL(ocxl_global_mmio_clear32);

int ocxl_global_mmio_clear64(struct ocxl_afu *afu, size_t offset,
                                enum ocxl_endian endian, u64 mask)
{
        u64 tmp;

        if (offset > afu->config.global_mmio_size - 8)
                return -EINVAL;

#ifdef __BIG_ENDIAN__
        if (endian == OCXL_HOST_ENDIAN)
                endian = OCXL_BIG_ENDIAN;
#endif

        switch (endian) {
        case OCXL_BIG_ENDIAN:
                tmp = readq_be((char *)afu->global_mmio_ptr + offset);
                tmp &= ~mask;
                writeq_be(tmp, (char *)afu->global_mmio_ptr + offset);
                break;

        default:
                tmp = readq((char *)afu->global_mmio_ptr + offset);
                tmp &= ~mask;
                writeq(tmp, (char *)afu->global_mmio_ptr + offset);
                break;
        }

        writeq(tmp, (char *)afu->global_mmio_ptr + offset);

        return 0;
}
EXPORT_SYMBOL_GPL(ocxl_global_mmio_clear64);