Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/platform/uv/bios_uv.c
26471 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* BIOS run time interface routines.
4
*
5
* (C) Copyright 2020 Hewlett Packard Enterprise Development LP
6
* Copyright (C) 2007-2017 Silicon Graphics, Inc. All rights reserved.
7
* Copyright (c) Russ Anderson <[email protected]>
8
*/
9
10
#include <linux/efi.h>
11
#include <linux/export.h>
12
#include <linux/slab.h>
13
#include <asm/efi.h>
14
#include <linux/io.h>
15
#include <asm/pgalloc.h>
16
#include <asm/uv/bios.h>
17
#include <asm/uv/uv_hub.h>
18
19
unsigned long uv_systab_phys __ro_after_init = EFI_INVALID_TABLE_ADDR;
20
21
struct uv_systab *uv_systab;
22
23
static s64 __uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3,
24
u64 a4, u64 a5)
25
{
26
struct uv_systab *tab = uv_systab;
27
s64 ret;
28
29
if (!tab || !tab->function)
30
/*
31
* BIOS does not support UV systab
32
*/
33
return BIOS_STATUS_UNIMPLEMENTED;
34
35
ret = efi_call_virt_pointer(tab, function, (u64)which, a1, a2, a3, a4, a5);
36
37
return ret;
38
}
39
40
static s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4,
41
u64 a5)
42
{
43
s64 ret;
44
45
if (down_interruptible(&__efi_uv_runtime_lock))
46
return BIOS_STATUS_ABORT;
47
48
ret = __uv_bios_call(which, a1, a2, a3, a4, a5);
49
up(&__efi_uv_runtime_lock);
50
51
return ret;
52
}
53
54
static s64 uv_bios_call_irqsave(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3,
55
u64 a4, u64 a5)
56
{
57
unsigned long bios_flags;
58
s64 ret;
59
60
if (down_interruptible(&__efi_uv_runtime_lock))
61
return BIOS_STATUS_ABORT;
62
63
local_irq_save(bios_flags);
64
ret = __uv_bios_call(which, a1, a2, a3, a4, a5);
65
local_irq_restore(bios_flags);
66
67
up(&__efi_uv_runtime_lock);
68
69
return ret;
70
}
71
72
long sn_partition_id;
73
EXPORT_SYMBOL_GPL(sn_partition_id);
74
long sn_coherency_id;
75
EXPORT_SYMBOL_GPL(sn_coherency_id);
76
long sn_region_size;
77
EXPORT_SYMBOL_GPL(sn_region_size);
78
long system_serial_number;
79
int uv_type;
80
81
s64 uv_bios_get_sn_info(int fc, int *uvtype, long *partid, long *coher,
82
long *region, long *ssn)
83
{
84
s64 ret;
85
u64 v0, v1;
86
union partition_info_u part;
87
88
ret = uv_bios_call_irqsave(UV_BIOS_GET_SN_INFO, fc,
89
(u64)(&v0), (u64)(&v1), 0, 0);
90
if (ret != BIOS_STATUS_SUCCESS)
91
return ret;
92
93
part.val = v0;
94
if (uvtype)
95
*uvtype = part.hub_version;
96
if (partid)
97
*partid = part.partition_id;
98
if (coher)
99
*coher = part.coherence_id;
100
if (region)
101
*region = part.region_size;
102
if (ssn)
103
*ssn = v1;
104
return ret;
105
}
106
107
int
108
uv_bios_mq_watchlist_alloc(unsigned long addr, unsigned int mq_size,
109
unsigned long *intr_mmr_offset)
110
{
111
u64 watchlist;
112
s64 ret;
113
114
/*
115
* bios returns watchlist number or negative error number.
116
*/
117
ret = (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_ALLOC, addr,
118
mq_size, (u64)intr_mmr_offset,
119
(u64)&watchlist, 0);
120
if (ret < BIOS_STATUS_SUCCESS)
121
return ret;
122
123
return watchlist;
124
}
125
EXPORT_SYMBOL_GPL(uv_bios_mq_watchlist_alloc);
126
127
int
128
uv_bios_mq_watchlist_free(int blade, int watchlist_num)
129
{
130
return (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_FREE,
131
blade, watchlist_num, 0, 0, 0);
132
}
133
EXPORT_SYMBOL_GPL(uv_bios_mq_watchlist_free);
134
135
s64
136
uv_bios_change_memprotect(u64 paddr, u64 len, enum uv_memprotect perms)
137
{
138
return uv_bios_call_irqsave(UV_BIOS_MEMPROTECT, paddr, len,
139
perms, 0, 0);
140
}
141
EXPORT_SYMBOL_GPL(uv_bios_change_memprotect);
142
143
s64
144
uv_bios_reserved_page_pa(u64 buf, u64 *cookie, u64 *addr, u64 *len)
145
{
146
return uv_bios_call_irqsave(UV_BIOS_GET_PARTITION_ADDR, (u64)cookie,
147
(u64)addr, buf, (u64)len, 0);
148
}
149
EXPORT_SYMBOL_GPL(uv_bios_reserved_page_pa);
150
151
s64 uv_bios_freq_base(u64 clock_type, u64 *ticks_per_second)
152
{
153
return uv_bios_call(UV_BIOS_FREQ_BASE, clock_type,
154
(u64)ticks_per_second, 0, 0, 0);
155
}
156
157
/*
158
* uv_bios_set_legacy_vga_target - Set Legacy VGA I/O Target
159
* @decode: true to enable target, false to disable target
160
* @domain: PCI domain number
161
* @bus: PCI bus number
162
*
163
* Returns:
164
* 0: Success
165
* -EINVAL: Invalid domain or bus number
166
* -ENOSYS: Capability not available
167
* -EBUSY: Legacy VGA I/O cannot be retargeted at this time
168
*/
169
int uv_bios_set_legacy_vga_target(bool decode, int domain, int bus)
170
{
171
return uv_bios_call(UV_BIOS_SET_LEGACY_VGA_TARGET,
172
(u64)decode, (u64)domain, (u64)bus, 0, 0);
173
}
174
175
extern s64 uv_bios_get_master_nasid(u64 size, u64 *master_nasid)
176
{
177
return uv_bios_call(UV_BIOS_EXTRA, 0, UV_BIOS_EXTRA_MASTER_NASID, 0,
178
size, (u64)master_nasid);
179
}
180
EXPORT_SYMBOL_GPL(uv_bios_get_master_nasid);
181
182
extern s64 uv_bios_get_heapsize(u64 nasid, u64 size, u64 *heap_size)
183
{
184
return uv_bios_call(UV_BIOS_EXTRA, nasid, UV_BIOS_EXTRA_GET_HEAPSIZE,
185
0, size, (u64)heap_size);
186
}
187
EXPORT_SYMBOL_GPL(uv_bios_get_heapsize);
188
189
extern s64 uv_bios_install_heap(u64 nasid, u64 heap_size, u64 *bios_heap)
190
{
191
return uv_bios_call(UV_BIOS_EXTRA, nasid, UV_BIOS_EXTRA_INSTALL_HEAP,
192
0, heap_size, (u64)bios_heap);
193
}
194
EXPORT_SYMBOL_GPL(uv_bios_install_heap);
195
196
extern s64 uv_bios_obj_count(u64 nasid, u64 size, u64 *objcnt)
197
{
198
return uv_bios_call(UV_BIOS_EXTRA, nasid, UV_BIOS_EXTRA_OBJECT_COUNT,
199
0, size, (u64)objcnt);
200
}
201
EXPORT_SYMBOL_GPL(uv_bios_obj_count);
202
203
extern s64 uv_bios_enum_objs(u64 nasid, u64 size, u64 *objbuf)
204
{
205
return uv_bios_call(UV_BIOS_EXTRA, nasid, UV_BIOS_EXTRA_ENUM_OBJECTS,
206
0, size, (u64)objbuf);
207
}
208
EXPORT_SYMBOL_GPL(uv_bios_enum_objs);
209
210
extern s64 uv_bios_enum_ports(u64 nasid, u64 obj_id, u64 size, u64 *portbuf)
211
{
212
return uv_bios_call(UV_BIOS_EXTRA, nasid, UV_BIOS_EXTRA_ENUM_PORTS,
213
obj_id, size, (u64)portbuf);
214
}
215
EXPORT_SYMBOL_GPL(uv_bios_enum_ports);
216
217
extern s64 uv_bios_get_geoinfo(u64 nasid, u64 size, u64 *buf)
218
{
219
return uv_bios_call(UV_BIOS_GET_GEOINFO, nasid, (u64)buf, size, 0, 0);
220
}
221
EXPORT_SYMBOL_GPL(uv_bios_get_geoinfo);
222
223
extern s64 uv_bios_get_pci_topology(u64 size, u64 *buf)
224
{
225
return uv_bios_call(UV_BIOS_GET_PCI_TOPOLOGY, (u64)buf, size, 0, 0, 0);
226
}
227
EXPORT_SYMBOL_GPL(uv_bios_get_pci_topology);
228
229
unsigned long get_uv_systab_phys(bool msg)
230
{
231
if ((uv_systab_phys == EFI_INVALID_TABLE_ADDR) ||
232
!uv_systab_phys || efi_runtime_disabled()) {
233
if (msg)
234
pr_crit("UV: UVsystab: missing\n");
235
return 0;
236
}
237
return uv_systab_phys;
238
}
239
240
int uv_bios_init(void)
241
{
242
unsigned long uv_systab_phys_addr;
243
244
uv_systab = NULL;
245
uv_systab_phys_addr = get_uv_systab_phys(1);
246
if (!uv_systab_phys_addr)
247
return -EEXIST;
248
249
uv_systab = ioremap(uv_systab_phys_addr, sizeof(struct uv_systab));
250
if (!uv_systab || strncmp(uv_systab->signature, UV_SYSTAB_SIG, 4)) {
251
pr_err("UV: UVsystab: bad signature!\n");
252
iounmap(uv_systab);
253
return -EINVAL;
254
}
255
256
/* Starting with UV4 the UV systab size is variable */
257
if (uv_systab->revision >= UV_SYSTAB_VERSION_UV4) {
258
int size = uv_systab->size;
259
260
iounmap(uv_systab);
261
uv_systab = ioremap(uv_systab_phys_addr, size);
262
if (!uv_systab) {
263
pr_err("UV: UVsystab: ioremap(%d) failed!\n", size);
264
return -EFAULT;
265
}
266
}
267
pr_info("UV: UVsystab: Revision:%x\n", uv_systab->revision);
268
return 0;
269
}
270
271