summaryrefslogtreecommitdiff
path: root/drivers/misc/ocxl
diff options
context:
space:
mode:
authorAlastair D'Silva <alastair@d-silva.org>2019-03-27 08:31:36 +0300
committerMichael Ellerman <mpe@ellerman.id.au>2019-05-02 19:55:02 +0300
commit7e462c2a8a6d00d3c240cac9f5626eff96d8e641 (patch)
tree69ce15c8454f9a2f5f4f660e6f483b4cb07d6f09 /drivers/misc/ocxl
parent060146614643ddc5978c73ffac0329762b4651c9 (diff)
downloadlinux-7e462c2a8a6d00d3c240cac9f5626eff96d8e641.tar.xz
ocxl: Provide global MMIO accessors for external drivers
External drivers that communicate via OpenCAPI will need to make MMIO calls to interact with the devices. Signed-off-by: Alastair D'Silva <alastair@d-silva.org> Reviewed-by: Greg Kurz <groug@kaod.org> Acked-by: Frederic Barrat <fbarrat@linux.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'drivers/misc/ocxl')
-rw-r--r--drivers/misc/ocxl/Makefile2
-rw-r--r--drivers/misc/ocxl/mmio.c234
2 files changed, 235 insertions, 1 deletions
diff --git a/drivers/misc/ocxl/Makefile b/drivers/misc/ocxl/Makefile
index bc4e39bfda7b..d07d1bb8e8d4 100644
--- a/drivers/misc/ocxl/Makefile
+++ b/drivers/misc/ocxl/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
ccflags-$(CONFIG_PPC_WERROR) += -Werror
-ocxl-y += main.o pci.o config.o file.o pasid.o
+ocxl-y += main.o pci.o config.o file.o pasid.o mmio.o
ocxl-y += link.o context.o afu_irq.o sysfs.o trace.o
ocxl-y += core.o
obj-$(CONFIG_OCXL) += ocxl.o
diff --git a/drivers/misc/ocxl/mmio.c b/drivers/misc/ocxl/mmio.c
new file mode 100644
index 000000000000..aae713db4ebe
--- /dev/null
+++ b/drivers/misc/ocxl/mmio.c
@@ -0,0 +1,234 @@
+// 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);