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