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