Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/sparc/kernel/hvapi.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0
2
/* hvapi.c: Hypervisor API management.
3
*
4
* Copyright (C) 2007 David S. Miller <[email protected]>
5
*/
6
#include <linux/kernel.h>
7
#include <linux/export.h>
8
#include <linux/init.h>
9
10
#include <asm/hypervisor.h>
11
#include <asm/oplib.h>
12
13
/* If the hypervisor indicates that the API setting
14
* calls are unsupported, by returning HV_EBADTRAP or
15
* HV_ENOTSUPPORTED, we assume that API groups with the
16
* PRE_API flag set are major 1 minor 0.
17
*/
18
struct api_info {
19
unsigned long group;
20
unsigned long major;
21
unsigned long minor;
22
unsigned int refcnt;
23
unsigned int flags;
24
#define FLAG_PRE_API 0x00000001
25
};
26
27
static struct api_info api_table[] = {
28
{ .group = HV_GRP_SUN4V, .flags = FLAG_PRE_API },
29
{ .group = HV_GRP_CORE, .flags = FLAG_PRE_API },
30
{ .group = HV_GRP_INTR, },
31
{ .group = HV_GRP_SOFT_STATE, },
32
{ .group = HV_GRP_TM, },
33
{ .group = HV_GRP_PCI, .flags = FLAG_PRE_API },
34
{ .group = HV_GRP_LDOM, },
35
{ .group = HV_GRP_SVC_CHAN, .flags = FLAG_PRE_API },
36
{ .group = HV_GRP_NCS, .flags = FLAG_PRE_API },
37
{ .group = HV_GRP_RNG, },
38
{ .group = HV_GRP_PBOOT, },
39
{ .group = HV_GRP_TPM, },
40
{ .group = HV_GRP_SDIO, },
41
{ .group = HV_GRP_SDIO_ERR, },
42
{ .group = HV_GRP_REBOOT_DATA, },
43
{ .group = HV_GRP_ATU, .flags = FLAG_PRE_API },
44
{ .group = HV_GRP_DAX, },
45
{ .group = HV_GRP_NIAG_PERF, .flags = FLAG_PRE_API },
46
{ .group = HV_GRP_FIRE_PERF, },
47
{ .group = HV_GRP_N2_CPU, },
48
{ .group = HV_GRP_NIU, },
49
{ .group = HV_GRP_VF_CPU, },
50
{ .group = HV_GRP_KT_CPU, },
51
{ .group = HV_GRP_VT_CPU, },
52
{ .group = HV_GRP_T5_CPU, },
53
{ .group = HV_GRP_DIAG, .flags = FLAG_PRE_API },
54
{ .group = HV_GRP_M7_PERF, },
55
};
56
57
static DEFINE_SPINLOCK(hvapi_lock);
58
59
static struct api_info *__get_info(unsigned long group)
60
{
61
int i;
62
63
for (i = 0; i < ARRAY_SIZE(api_table); i++) {
64
if (api_table[i].group == group)
65
return &api_table[i];
66
}
67
return NULL;
68
}
69
70
static void __get_ref(struct api_info *p)
71
{
72
p->refcnt++;
73
}
74
75
static void __put_ref(struct api_info *p)
76
{
77
if (--p->refcnt == 0) {
78
unsigned long ignore;
79
80
sun4v_set_version(p->group, 0, 0, &ignore);
81
p->major = p->minor = 0;
82
}
83
}
84
85
/* Register a hypervisor API specification. It indicates the
86
* API group and desired major+minor.
87
*
88
* If an existing API registration exists '0' (success) will
89
* be returned if it is compatible with the one being registered.
90
* Otherwise a negative error code will be returned.
91
*
92
* Otherwise an attempt will be made to negotiate the requested
93
* API group/major/minor with the hypervisor, and errors returned
94
* if that does not succeed.
95
*/
96
int sun4v_hvapi_register(unsigned long group, unsigned long major,
97
unsigned long *minor)
98
{
99
struct api_info *p;
100
unsigned long flags;
101
int ret;
102
103
spin_lock_irqsave(&hvapi_lock, flags);
104
p = __get_info(group);
105
ret = -EINVAL;
106
if (p) {
107
if (p->refcnt) {
108
ret = -EINVAL;
109
if (p->major == major) {
110
*minor = p->minor;
111
ret = 0;
112
}
113
} else {
114
unsigned long actual_minor;
115
unsigned long hv_ret;
116
117
hv_ret = sun4v_set_version(group, major, *minor,
118
&actual_minor);
119
ret = -EINVAL;
120
if (hv_ret == HV_EOK) {
121
*minor = actual_minor;
122
p->major = major;
123
p->minor = actual_minor;
124
ret = 0;
125
} else if (hv_ret == HV_EBADTRAP ||
126
hv_ret == HV_ENOTSUPPORTED) {
127
if (p->flags & FLAG_PRE_API) {
128
if (major == 1) {
129
p->major = 1;
130
p->minor = 0;
131
*minor = 0;
132
ret = 0;
133
}
134
}
135
}
136
}
137
138
if (ret == 0)
139
__get_ref(p);
140
}
141
spin_unlock_irqrestore(&hvapi_lock, flags);
142
143
return ret;
144
}
145
EXPORT_SYMBOL(sun4v_hvapi_register);
146
147
void sun4v_hvapi_unregister(unsigned long group)
148
{
149
struct api_info *p;
150
unsigned long flags;
151
152
spin_lock_irqsave(&hvapi_lock, flags);
153
p = __get_info(group);
154
if (p)
155
__put_ref(p);
156
spin_unlock_irqrestore(&hvapi_lock, flags);
157
}
158
EXPORT_SYMBOL(sun4v_hvapi_unregister);
159
160
int sun4v_hvapi_get(unsigned long group,
161
unsigned long *major,
162
unsigned long *minor)
163
{
164
struct api_info *p;
165
unsigned long flags;
166
int ret;
167
168
spin_lock_irqsave(&hvapi_lock, flags);
169
ret = -EINVAL;
170
p = __get_info(group);
171
if (p && p->refcnt) {
172
*major = p->major;
173
*minor = p->minor;
174
ret = 0;
175
}
176
spin_unlock_irqrestore(&hvapi_lock, flags);
177
178
return ret;
179
}
180
EXPORT_SYMBOL(sun4v_hvapi_get);
181
182
void __init sun4v_hvapi_init(void)
183
{
184
unsigned long group, major, minor;
185
186
group = HV_GRP_SUN4V;
187
major = 1;
188
minor = 0;
189
if (sun4v_hvapi_register(group, major, &minor))
190
goto bad;
191
192
group = HV_GRP_CORE;
193
major = 1;
194
minor = 6;
195
if (sun4v_hvapi_register(group, major, &minor))
196
goto bad;
197
198
return;
199
200
bad:
201
prom_printf("HVAPI: Cannot register API group "
202
"%lx with major(%lu) minor(%lu)\n",
203
group, major, minor);
204
prom_halt();
205
}
206
207