162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
362306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
462306a36Sopenharmony_ci * for more details.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * (C) Copyright 2020 Hewlett Packard Enterprise Development LP
762306a36Sopenharmony_ci * Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci/*
1162306a36Sopenharmony_ci * Cross Partition (XP) uv-based functions.
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci *      Architecture specific implementation of common functions.
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/device.h>
1862306a36Sopenharmony_ci#include <asm/uv/uv_hub.h>
1962306a36Sopenharmony_ci#if defined CONFIG_X86_64
2062306a36Sopenharmony_ci#include <asm/uv/bios.h>
2162306a36Sopenharmony_ci#elif defined CONFIG_IA64_SGI_UV
2262306a36Sopenharmony_ci#include <asm/sn/sn_sal.h>
2362306a36Sopenharmony_ci#endif
2462306a36Sopenharmony_ci#include "../sgi-gru/grukservices.h"
2562306a36Sopenharmony_ci#include "xp.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/*
2862306a36Sopenharmony_ci * Convert a virtual memory address to a physical memory address.
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_cistatic unsigned long
3162306a36Sopenharmony_cixp_pa_uv(void *addr)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	return uv_gpa(addr);
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/*
3762306a36Sopenharmony_ci * Convert a global physical to socket physical address.
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_cistatic unsigned long
4062306a36Sopenharmony_cixp_socket_pa_uv(unsigned long gpa)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	return uv_gpa_to_soc_phys_ram(gpa);
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic enum xp_retval
4662306a36Sopenharmony_cixp_remote_mmr_read(unsigned long dst_gpa, const unsigned long src_gpa,
4762306a36Sopenharmony_ci		   size_t len)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	int ret;
5062306a36Sopenharmony_ci	unsigned long *dst_va = __va(uv_gpa_to_soc_phys_ram(dst_gpa));
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	BUG_ON(!uv_gpa_in_mmr_space(src_gpa));
5362306a36Sopenharmony_ci	BUG_ON(len != 8);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	ret = gru_read_gpa(dst_va, src_gpa);
5662306a36Sopenharmony_ci	if (ret == 0)
5762306a36Sopenharmony_ci		return xpSuccess;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	dev_err(xp, "gru_read_gpa() failed, dst_gpa=0x%016lx src_gpa=0x%016lx "
6062306a36Sopenharmony_ci		"len=%ld\n", dst_gpa, src_gpa, len);
6162306a36Sopenharmony_ci	return xpGruCopyError;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic enum xp_retval
6662306a36Sopenharmony_cixp_remote_memcpy_uv(unsigned long dst_gpa, const unsigned long src_gpa,
6762306a36Sopenharmony_ci		    size_t len)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	int ret;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if (uv_gpa_in_mmr_space(src_gpa))
7262306a36Sopenharmony_ci		return xp_remote_mmr_read(dst_gpa, src_gpa, len);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	ret = gru_copy_gpa(dst_gpa, src_gpa, len);
7562306a36Sopenharmony_ci	if (ret == 0)
7662306a36Sopenharmony_ci		return xpSuccess;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	dev_err(xp, "gru_copy_gpa() failed, dst_gpa=0x%016lx src_gpa=0x%016lx "
7962306a36Sopenharmony_ci		"len=%ld\n", dst_gpa, src_gpa, len);
8062306a36Sopenharmony_ci	return xpGruCopyError;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic int
8462306a36Sopenharmony_cixp_cpu_to_nasid_uv(int cpuid)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	/* ??? Is this same as sn2 nasid in mach/part bitmaps set up by SAL? */
8762306a36Sopenharmony_ci	return UV_PNODE_TO_NASID(uv_cpu_to_pnode(cpuid));
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic enum xp_retval
9162306a36Sopenharmony_cixp_expand_memprotect_uv(unsigned long phys_addr, unsigned long size)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	int ret;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#if defined CONFIG_X86_64
9662306a36Sopenharmony_ci	ret = uv_bios_change_memprotect(phys_addr, size, UV_MEMPROT_ALLOW_RW);
9762306a36Sopenharmony_ci	if (ret != BIOS_STATUS_SUCCESS) {
9862306a36Sopenharmony_ci		dev_err(xp, "uv_bios_change_memprotect(,, "
9962306a36Sopenharmony_ci			"UV_MEMPROT_ALLOW_RW) failed, ret=%d\n", ret);
10062306a36Sopenharmony_ci		return xpBiosError;
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#elif defined CONFIG_IA64_SGI_UV
10462306a36Sopenharmony_ci	u64 nasid_array;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_1,
10762306a36Sopenharmony_ci				   &nasid_array);
10862306a36Sopenharmony_ci	if (ret != 0) {
10962306a36Sopenharmony_ci		dev_err(xp, "sn_change_memprotect(,, "
11062306a36Sopenharmony_ci			"SN_MEMPROT_ACCESS_CLASS_1,) failed ret=%d\n", ret);
11162306a36Sopenharmony_ci		return xpSalError;
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci#else
11462306a36Sopenharmony_ci	#error not a supported configuration
11562306a36Sopenharmony_ci#endif
11662306a36Sopenharmony_ci	return xpSuccess;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic enum xp_retval
12062306a36Sopenharmony_cixp_restrict_memprotect_uv(unsigned long phys_addr, unsigned long size)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	int ret;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci#if defined CONFIG_X86_64
12562306a36Sopenharmony_ci	ret = uv_bios_change_memprotect(phys_addr, size,
12662306a36Sopenharmony_ci					UV_MEMPROT_RESTRICT_ACCESS);
12762306a36Sopenharmony_ci	if (ret != BIOS_STATUS_SUCCESS) {
12862306a36Sopenharmony_ci		dev_err(xp, "uv_bios_change_memprotect(,, "
12962306a36Sopenharmony_ci			"UV_MEMPROT_RESTRICT_ACCESS) failed, ret=%d\n", ret);
13062306a36Sopenharmony_ci		return xpBiosError;
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci#elif defined CONFIG_IA64_SGI_UV
13462306a36Sopenharmony_ci	u64 nasid_array;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_0,
13762306a36Sopenharmony_ci				   &nasid_array);
13862306a36Sopenharmony_ci	if (ret != 0) {
13962306a36Sopenharmony_ci		dev_err(xp, "sn_change_memprotect(,, "
14062306a36Sopenharmony_ci			"SN_MEMPROT_ACCESS_CLASS_0,) failed ret=%d\n", ret);
14162306a36Sopenharmony_ci		return xpSalError;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci#else
14462306a36Sopenharmony_ci	#error not a supported configuration
14562306a36Sopenharmony_ci#endif
14662306a36Sopenharmony_ci	return xpSuccess;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cienum xp_retval
15062306a36Sopenharmony_cixp_init_uv(void)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	WARN_ON(!is_uv_system());
15362306a36Sopenharmony_ci	if (!is_uv_system())
15462306a36Sopenharmony_ci		return xpUnsupported;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	xp_max_npartitions = XP_MAX_NPARTITIONS_UV;
15762306a36Sopenharmony_ci#ifdef CONFIG_X86
15862306a36Sopenharmony_ci	xp_partition_id = sn_partition_id;
15962306a36Sopenharmony_ci	xp_region_size = sn_region_size;
16062306a36Sopenharmony_ci#endif
16162306a36Sopenharmony_ci	xp_pa = xp_pa_uv;
16262306a36Sopenharmony_ci	xp_socket_pa = xp_socket_pa_uv;
16362306a36Sopenharmony_ci	xp_remote_memcpy = xp_remote_memcpy_uv;
16462306a36Sopenharmony_ci	xp_cpu_to_nasid = xp_cpu_to_nasid_uv;
16562306a36Sopenharmony_ci	xp_expand_memprotect = xp_expand_memprotect_uv;
16662306a36Sopenharmony_ci	xp_restrict_memprotect = xp_restrict_memprotect_uv;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	return xpSuccess;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_civoid
17262306a36Sopenharmony_cixp_exit_uv(void)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	WARN_ON(!is_uv_system());
17562306a36Sopenharmony_ci}
176