summaryrefslogtreecommitdiff
path: root/drivers/misc/sgi-xp/xp_uv.c
blob: 3faa7eadf679e3c24e6177744c766731890ad462 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * (C) Copyright 2020 Hewlett Packard Enterprise Development LP
 * Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
 */

/*
 * Cross Partition (XP) uv-based functions.
 *
 *      Architecture specific implementation of common functions.
 *
 */

#include <linux/device.h>
#include <asm/uv/uv_hub.h>
#if defined CONFIG_X86_64
#include <asm/uv/bios.h>
#endif
#include "../sgi-gru/grukservices.h"
#include "xp.h"

/*
 * Convert a virtual memory address to a physical memory address.
 */
static unsigned long
xp_pa_uv(void *addr)
{
	return uv_gpa(addr);
}

/*
 * Convert a global physical to socket physical address.
 */
static unsigned long
xp_socket_pa_uv(unsigned long gpa)
{
	return uv_gpa_to_soc_phys_ram(gpa);
}

static enum xp_retval
xp_remote_mmr_read(unsigned long dst_gpa, const unsigned long src_gpa,
		   size_t len)
{
	int ret;
	unsigned long *dst_va = __va(uv_gpa_to_soc_phys_ram(dst_gpa));

	BUG_ON(!uv_gpa_in_mmr_space(src_gpa));
	BUG_ON(len != 8);

	ret = gru_read_gpa(dst_va, src_gpa);
	if (ret == 0)
		return xpSuccess;

	dev_err(xp, "gru_read_gpa() failed, dst_gpa=0x%016lx src_gpa=0x%016lx "
		"len=%ld\n", dst_gpa, src_gpa, len);
	return xpGruCopyError;
}


static enum xp_retval
xp_remote_memcpy_uv(unsigned long dst_gpa, const unsigned long src_gpa,
		    size_t len)
{
	int ret;

	if (uv_gpa_in_mmr_space(src_gpa))
		return xp_remote_mmr_read(dst_gpa, src_gpa, len);

	ret = gru_copy_gpa(dst_gpa, src_gpa, len);
	if (ret == 0)
		return xpSuccess;

	dev_err(xp, "gru_copy_gpa() failed, dst_gpa=0x%016lx src_gpa=0x%016lx "
		"len=%ld\n", dst_gpa, src_gpa, len);
	return xpGruCopyError;
}

static int
xp_cpu_to_nasid_uv(int cpuid)
{
	/* ??? Is this same as sn2 nasid in mach/part bitmaps set up by SAL? */
	return UV_PNODE_TO_NASID(uv_cpu_to_pnode(cpuid));
}

static enum xp_retval
xp_expand_memprotect_uv(unsigned long phys_addr, unsigned long size)
{
	int ret;

#if defined CONFIG_X86_64
	ret = uv_bios_change_memprotect(phys_addr, size, UV_MEMPROT_ALLOW_RW);
	if (ret != BIOS_STATUS_SUCCESS) {
		dev_err(xp, "uv_bios_change_memprotect(,, "
			"UV_MEMPROT_ALLOW_RW) failed, ret=%d\n", ret);
		return xpBiosError;
	}
#else
	#error not a supported configuration
#endif
	return xpSuccess;
}

static enum xp_retval
xp_restrict_memprotect_uv(unsigned long phys_addr, unsigned long size)
{
	int ret;

#if defined CONFIG_X86_64
	ret = uv_bios_change_memprotect(phys_addr, size,
					UV_MEMPROT_RESTRICT_ACCESS);
	if (ret != BIOS_STATUS_SUCCESS) {
		dev_err(xp, "uv_bios_change_memprotect(,, "
			"UV_MEMPROT_RESTRICT_ACCESS) failed, ret=%d\n", ret);
		return xpBiosError;
	}
#else
	#error not a supported configuration
#endif
	return xpSuccess;
}

enum xp_retval
xp_init_uv(void)
{
	WARN_ON(!is_uv_system());
	if (!is_uv_system())
		return xpUnsupported;

	xp_max_npartitions = XP_MAX_NPARTITIONS_UV;
#ifdef CONFIG_X86
	xp_partition_id = sn_partition_id;
	xp_region_size = sn_region_size;
#endif
	xp_pa = xp_pa_uv;
	xp_socket_pa = xp_socket_pa_uv;
	xp_remote_memcpy = xp_remote_memcpy_uv;
	xp_cpu_to_nasid = xp_cpu_to_nasid_uv;
	xp_expand_memprotect = xp_expand_memprotect_uv;
	xp_restrict_memprotect = xp_restrict_memprotect_uv;

	return xpSuccess;
}

void
xp_exit_uv(void)
{
	WARN_ON(!is_uv_system());
}