// 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); 
 |