162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright(c) 2017 IBM Corporation. All rights reserved.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/string.h>
762306a36Sopenharmony_ci#include <linux/export.h>
862306a36Sopenharmony_ci#include <linux/uaccess.h>
962306a36Sopenharmony_ci#include <linux/libnvdimm.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <asm/cacheflush.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic inline void __clean_pmem_range(unsigned long start, unsigned long stop)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	unsigned long shift = l1_dcache_shift();
1662306a36Sopenharmony_ci	unsigned long bytes = l1_dcache_bytes();
1762306a36Sopenharmony_ci	void *addr = (void *)(start & ~(bytes - 1));
1862306a36Sopenharmony_ci	unsigned long size = stop - (unsigned long)addr + (bytes - 1);
1962306a36Sopenharmony_ci	unsigned long i;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci	for (i = 0; i < size >> shift; i++, addr += bytes)
2262306a36Sopenharmony_ci		asm volatile(PPC_DCBSTPS(%0, %1): :"i"(0), "r"(addr): "memory");
2362306a36Sopenharmony_ci}
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic inline void __flush_pmem_range(unsigned long start, unsigned long stop)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	unsigned long shift = l1_dcache_shift();
2862306a36Sopenharmony_ci	unsigned long bytes = l1_dcache_bytes();
2962306a36Sopenharmony_ci	void *addr = (void *)(start & ~(bytes - 1));
3062306a36Sopenharmony_ci	unsigned long size = stop - (unsigned long)addr + (bytes - 1);
3162306a36Sopenharmony_ci	unsigned long i;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	for (i = 0; i < size >> shift; i++, addr += bytes)
3462306a36Sopenharmony_ci		asm volatile(PPC_DCBFPS(%0, %1): :"i"(0), "r"(addr): "memory");
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic inline void clean_pmem_range(unsigned long start, unsigned long stop)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	if (cpu_has_feature(CPU_FTR_ARCH_207S))
4062306a36Sopenharmony_ci		return __clean_pmem_range(start, stop);
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic inline void flush_pmem_range(unsigned long start, unsigned long stop)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	if (cpu_has_feature(CPU_FTR_ARCH_207S))
4662306a36Sopenharmony_ci		return __flush_pmem_range(start, stop);
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/*
5062306a36Sopenharmony_ci * CONFIG_ARCH_HAS_PMEM_API symbols
5162306a36Sopenharmony_ci */
5262306a36Sopenharmony_civoid arch_wb_cache_pmem(void *addr, size_t size)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	unsigned long start = (unsigned long) addr;
5562306a36Sopenharmony_ci	clean_pmem_range(start, start + size);
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(arch_wb_cache_pmem);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_civoid arch_invalidate_pmem(void *addr, size_t size)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	unsigned long start = (unsigned long) addr;
6262306a36Sopenharmony_ci	flush_pmem_range(start, start + size);
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(arch_invalidate_pmem);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/*
6762306a36Sopenharmony_ci * CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE symbols
6862306a36Sopenharmony_ci */
6962306a36Sopenharmony_cilong __copy_from_user_flushcache(void *dest, const void __user *src,
7062306a36Sopenharmony_ci		unsigned size)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	unsigned long copied, start = (unsigned long) dest;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	copied = __copy_from_user(dest, src, size);
7562306a36Sopenharmony_ci	clean_pmem_range(start, start + size);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	return copied;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_civoid memcpy_flushcache(void *dest, const void *src, size_t size)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	unsigned long start = (unsigned long) dest;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	memcpy(dest, src, size);
8562306a36Sopenharmony_ci	clean_pmem_range(start, start + size);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ciEXPORT_SYMBOL(memcpy_flushcache);
88