1 // SPDX-License-Identifier: GPL-2.0
2 /* hvapi.c: Hypervisor API management.
4 * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
6 #include <linux/kernel.h>
7 #include <linux/export.h>
8 #include <linux/init.h>
10 #include <asm/hypervisor.h>
11 #include <asm/oplib.h>
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.
24 #define FLAG_PRE_API 0x00000001
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
, },
57 static DEFINE_SPINLOCK(hvapi_lock
);
59 static struct api_info
*__get_info(unsigned long group
)
63 for (i
= 0; i
< ARRAY_SIZE(api_table
); i
++) {
64 if (api_table
[i
].group
== group
)
70 static void __get_ref(struct api_info
*p
)
75 static void __put_ref(struct api_info
*p
)
77 if (--p
->refcnt
== 0) {
80 sun4v_set_version(p
->group
, 0, 0, &ignore
);
81 p
->major
= p
->minor
= 0;
85 /* Register a hypervisor API specification. It indicates the
86 * API group and desired major+minor.
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.
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.
96 int sun4v_hvapi_register(unsigned long group
, unsigned long major
,
103 spin_lock_irqsave(&hvapi_lock
, flags
);
104 p
= __get_info(group
);
109 if (p
->major
== major
) {
114 unsigned long actual_minor
;
115 unsigned long hv_ret
;
117 hv_ret
= sun4v_set_version(group
, major
, *minor
,
120 if (hv_ret
== HV_EOK
) {
121 *minor
= actual_minor
;
123 p
->minor
= actual_minor
;
125 } else if (hv_ret
== HV_EBADTRAP
||
126 hv_ret
== HV_ENOTSUPPORTED
) {
127 if (p
->flags
& FLAG_PRE_API
) {
141 spin_unlock_irqrestore(&hvapi_lock
, flags
);
145 EXPORT_SYMBOL(sun4v_hvapi_register
);
147 void sun4v_hvapi_unregister(unsigned long group
)
152 spin_lock_irqsave(&hvapi_lock
, flags
);
153 p
= __get_info(group
);
156 spin_unlock_irqrestore(&hvapi_lock
, flags
);
158 EXPORT_SYMBOL(sun4v_hvapi_unregister
);
160 int sun4v_hvapi_get(unsigned long group
,
161 unsigned long *major
,
162 unsigned long *minor
)
168 spin_lock_irqsave(&hvapi_lock
, flags
);
170 p
= __get_info(group
);
171 if (p
&& p
->refcnt
) {
176 spin_unlock_irqrestore(&hvapi_lock
, flags
);
180 EXPORT_SYMBOL(sun4v_hvapi_get
);
182 void __init
sun4v_hvapi_init(void)
184 unsigned long group
, major
, minor
;
186 group
= HV_GRP_SUN4V
;
189 if (sun4v_hvapi_register(group
, major
, &minor
))
195 if (sun4v_hvapi_register(group
, major
, &minor
))
201 prom_printf("HVAPI: Cannot register API group "
202 "%lx with major(%lu) minor(%lu)\n",
203 group
, major
, minor
);