aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/hvapi.c
diff options
context:
space:
mode:
authorSam Ravnborg <sam@ravnborg.org>2008-12-03 06:11:52 -0500
committerDavid S. Miller <davem@davemloft.net>2008-12-04 12:17:21 -0500
commita88b5ba8bd8ac18aad65ee6c6a254e2e74876db3 (patch)
treeeb3d0ffaf53c3f7ec6083752c2097cecd1cb892a /arch/sparc/kernel/hvapi.c
parentd670bd4f803c8b646acd20f3ba21e65458293faf (diff)
sparc,sparc64: unify kernel/
o Move all files from sparc64/kernel/ to sparc/kernel - rename as appropriate o Update sparc/Makefile to the changes o Update sparc/kernel/Makefile to include the sparc64 files NOTE: This commit changes link order on sparc64! Link order had to change for either of sparc32 and sparc64. And assuming sparc64 see more testing than sparc32 change link order on sparc64 where issues will be caught faster. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/kernel/hvapi.c')
-rw-r--r--arch/sparc/kernel/hvapi.c193
1 files changed, 193 insertions, 0 deletions
diff --git a/arch/sparc/kernel/hvapi.c b/arch/sparc/kernel/hvapi.c
new file mode 100644
index 00000000000..1d272c3b574
--- /dev/null
+++ b/arch/sparc/kernel/hvapi.c
@@ -0,0 +1,193 @@
1/* hvapi.c: Hypervisor API management.
2 *
3 * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
4 */
5#include <linux/kernel.h>
6#include <linux/module.h>
7#include <linux/init.h>
8#include <linux/slab.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 */
18struct 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
27static 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_PCI, .flags = FLAG_PRE_API },
33 { .group = HV_GRP_LDOM, },
34 { .group = HV_GRP_SVC_CHAN, .flags = FLAG_PRE_API },
35 { .group = HV_GRP_NCS, .flags = FLAG_PRE_API },
36 { .group = HV_GRP_RNG, },
37 { .group = HV_GRP_NIAG_PERF, .flags = FLAG_PRE_API },
38 { .group = HV_GRP_FIRE_PERF, },
39 { .group = HV_GRP_N2_CPU, },
40 { .group = HV_GRP_NIU, },
41 { .group = HV_GRP_VF_CPU, },
42 { .group = HV_GRP_DIAG, .flags = FLAG_PRE_API },
43};
44
45static DEFINE_SPINLOCK(hvapi_lock);
46
47static struct api_info *__get_info(unsigned long group)
48{
49 int i;
50
51 for (i = 0; i < ARRAY_SIZE(api_table); i++) {
52 if (api_table[i].group == group)
53 return &api_table[i];
54 }
55 return NULL;
56}
57
58static void __get_ref(struct api_info *p)
59{
60 p->refcnt++;
61}
62
63static void __put_ref(struct api_info *p)
64{
65 if (--p->refcnt == 0) {
66 unsigned long ignore;
67
68 sun4v_set_version(p->group, 0, 0, &ignore);
69 p->major = p->minor = 0;
70 }
71}
72
73/* Register a hypervisor API specification. It indicates the
74 * API group and desired major+minor.
75 *
76 * If an existing API registration exists '0' (success) will
77 * be returned if it is compatible with the one being registered.
78 * Otherwise a negative error code will be returned.
79 *
80 * Otherwise an attempt will be made to negotiate the requested
81 * API group/major/minor with the hypervisor, and errors returned
82 * if that does not succeed.
83 */
84int sun4v_hvapi_register(unsigned long group, unsigned long major,
85 unsigned long *minor)
86{
87 struct api_info *p;
88 unsigned long flags;
89 int ret;
90
91 spin_lock_irqsave(&hvapi_lock, flags);
92 p = __get_info(group);
93 ret = -EINVAL;
94 if (p) {
95 if (p->refcnt) {
96 ret = -EINVAL;
97 if (p->major == major) {
98 *minor = p->minor;
99 ret = 0;
100 }
101 } else {
102 unsigned long actual_minor;
103 unsigned long hv_ret;
104
105 hv_ret = sun4v_set_version(group, major, *minor,
106 &actual_minor);
107 ret = -EINVAL;
108 if (hv_ret == HV_EOK) {
109 *minor = actual_minor;
110 p->major = major;
111 p->minor = actual_minor;
112 ret = 0;
113 } else if (hv_ret == HV_EBADTRAP ||
114 hv_ret == HV_ENOTSUPPORTED) {
115 if (p->flags & FLAG_PRE_API) {
116 if (major == 1) {
117 p->major = 1;
118 p->minor = 0;
119 *minor = 0;
120 ret = 0;
121 }
122 }
123 }
124 }
125
126 if (ret == 0)
127 __get_ref(p);
128 }
129 spin_unlock_irqrestore(&hvapi_lock, flags);
130
131 return ret;
132}
133EXPORT_SYMBOL(sun4v_hvapi_register);
134
135void sun4v_hvapi_unregister(unsigned long group)
136{
137 struct api_info *p;
138 unsigned long flags;
139
140 spin_lock_irqsave(&hvapi_lock, flags);
141 p = __get_info(group);
142 if (p)
143 __put_ref(p);
144 spin_unlock_irqrestore(&hvapi_lock, flags);
145}
146EXPORT_SYMBOL(sun4v_hvapi_unregister);
147
148int sun4v_hvapi_get(unsigned long group,
149 unsigned long *major,
150 unsigned long *minor)
151{
152 struct api_info *p;
153 unsigned long flags;
154 int ret;
155
156 spin_lock_irqsave(&hvapi_lock, flags);
157 ret = -EINVAL;
158 p = __get_info(group);
159 if (p && p->refcnt) {
160 *major = p->major;
161 *minor = p->minor;
162 ret = 0;
163 }
164 spin_unlock_irqrestore(&hvapi_lock, flags);
165
166 return ret;
167}
168EXPORT_SYMBOL(sun4v_hvapi_get);
169
170void __init sun4v_hvapi_init(void)
171{
172 unsigned long group, major, minor;
173
174 group = HV_GRP_SUN4V;
175 major = 1;
176 minor = 0;
177 if (sun4v_hvapi_register(group, major, &minor))
178 goto bad;
179
180 group = HV_GRP_CORE;
181 major = 1;
182 minor = 1;
183 if (sun4v_hvapi_register(group, major, &minor))
184 goto bad;
185
186 return;
187
188bad:
189 prom_printf("HVAPI: Cannot register API group "
190 "%lx with major(%u) minor(%u)\n",
191 group, major, minor);
192 prom_halt();
193}