mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 12:42:02 +00:00
7e462c2a8a
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>
235 lines
4.8 KiB
C
235 lines
4.8 KiB
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);
|