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