forked from mirrors/linux
		
	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>
		
			
				
	
	
		
			234 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			234 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);
 |