0001
0002
0003
0004
0005
0006 #include <linux/kernel.h>
0007 #include <linux/export.h>
0008 #include <linux/init.h>
0009
0010 #include <asm/hypervisor.h>
0011 #include <asm/oplib.h>
0012
0013
0014
0015
0016
0017
0018 struct api_info {
0019 unsigned long group;
0020 unsigned long major;
0021 unsigned long minor;
0022 unsigned int refcnt;
0023 unsigned int flags;
0024 #define FLAG_PRE_API 0x00000001
0025 };
0026
0027 static struct api_info api_table[] = {
0028 { .group = HV_GRP_SUN4V, .flags = FLAG_PRE_API },
0029 { .group = HV_GRP_CORE, .flags = FLAG_PRE_API },
0030 { .group = HV_GRP_INTR, },
0031 { .group = HV_GRP_SOFT_STATE, },
0032 { .group = HV_GRP_TM, },
0033 { .group = HV_GRP_PCI, .flags = FLAG_PRE_API },
0034 { .group = HV_GRP_LDOM, },
0035 { .group = HV_GRP_SVC_CHAN, .flags = FLAG_PRE_API },
0036 { .group = HV_GRP_NCS, .flags = FLAG_PRE_API },
0037 { .group = HV_GRP_RNG, },
0038 { .group = HV_GRP_PBOOT, },
0039 { .group = HV_GRP_TPM, },
0040 { .group = HV_GRP_SDIO, },
0041 { .group = HV_GRP_SDIO_ERR, },
0042 { .group = HV_GRP_REBOOT_DATA, },
0043 { .group = HV_GRP_ATU, .flags = FLAG_PRE_API },
0044 { .group = HV_GRP_DAX, },
0045 { .group = HV_GRP_NIAG_PERF, .flags = FLAG_PRE_API },
0046 { .group = HV_GRP_FIRE_PERF, },
0047 { .group = HV_GRP_N2_CPU, },
0048 { .group = HV_GRP_NIU, },
0049 { .group = HV_GRP_VF_CPU, },
0050 { .group = HV_GRP_KT_CPU, },
0051 { .group = HV_GRP_VT_CPU, },
0052 { .group = HV_GRP_T5_CPU, },
0053 { .group = HV_GRP_DIAG, .flags = FLAG_PRE_API },
0054 { .group = HV_GRP_M7_PERF, },
0055 };
0056
0057 static DEFINE_SPINLOCK(hvapi_lock);
0058
0059 static struct api_info *__get_info(unsigned long group)
0060 {
0061 int i;
0062
0063 for (i = 0; i < ARRAY_SIZE(api_table); i++) {
0064 if (api_table[i].group == group)
0065 return &api_table[i];
0066 }
0067 return NULL;
0068 }
0069
0070 static void __get_ref(struct api_info *p)
0071 {
0072 p->refcnt++;
0073 }
0074
0075 static void __put_ref(struct api_info *p)
0076 {
0077 if (--p->refcnt == 0) {
0078 unsigned long ignore;
0079
0080 sun4v_set_version(p->group, 0, 0, &ignore);
0081 p->major = p->minor = 0;
0082 }
0083 }
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096 int sun4v_hvapi_register(unsigned long group, unsigned long major,
0097 unsigned long *minor)
0098 {
0099 struct api_info *p;
0100 unsigned long flags;
0101 int ret;
0102
0103 spin_lock_irqsave(&hvapi_lock, flags);
0104 p = __get_info(group);
0105 ret = -EINVAL;
0106 if (p) {
0107 if (p->refcnt) {
0108 ret = -EINVAL;
0109 if (p->major == major) {
0110 *minor = p->minor;
0111 ret = 0;
0112 }
0113 } else {
0114 unsigned long actual_minor;
0115 unsigned long hv_ret;
0116
0117 hv_ret = sun4v_set_version(group, major, *minor,
0118 &actual_minor);
0119 ret = -EINVAL;
0120 if (hv_ret == HV_EOK) {
0121 *minor = actual_minor;
0122 p->major = major;
0123 p->minor = actual_minor;
0124 ret = 0;
0125 } else if (hv_ret == HV_EBADTRAP ||
0126 hv_ret == HV_ENOTSUPPORTED) {
0127 if (p->flags & FLAG_PRE_API) {
0128 if (major == 1) {
0129 p->major = 1;
0130 p->minor = 0;
0131 *minor = 0;
0132 ret = 0;
0133 }
0134 }
0135 }
0136 }
0137
0138 if (ret == 0)
0139 __get_ref(p);
0140 }
0141 spin_unlock_irqrestore(&hvapi_lock, flags);
0142
0143 return ret;
0144 }
0145 EXPORT_SYMBOL(sun4v_hvapi_register);
0146
0147 void sun4v_hvapi_unregister(unsigned long group)
0148 {
0149 struct api_info *p;
0150 unsigned long flags;
0151
0152 spin_lock_irqsave(&hvapi_lock, flags);
0153 p = __get_info(group);
0154 if (p)
0155 __put_ref(p);
0156 spin_unlock_irqrestore(&hvapi_lock, flags);
0157 }
0158 EXPORT_SYMBOL(sun4v_hvapi_unregister);
0159
0160 int sun4v_hvapi_get(unsigned long group,
0161 unsigned long *major,
0162 unsigned long *minor)
0163 {
0164 struct api_info *p;
0165 unsigned long flags;
0166 int ret;
0167
0168 spin_lock_irqsave(&hvapi_lock, flags);
0169 ret = -EINVAL;
0170 p = __get_info(group);
0171 if (p && p->refcnt) {
0172 *major = p->major;
0173 *minor = p->minor;
0174 ret = 0;
0175 }
0176 spin_unlock_irqrestore(&hvapi_lock, flags);
0177
0178 return ret;
0179 }
0180 EXPORT_SYMBOL(sun4v_hvapi_get);
0181
0182 void __init sun4v_hvapi_init(void)
0183 {
0184 unsigned long group, major, minor;
0185
0186 group = HV_GRP_SUN4V;
0187 major = 1;
0188 minor = 0;
0189 if (sun4v_hvapi_register(group, major, &minor))
0190 goto bad;
0191
0192 group = HV_GRP_CORE;
0193 major = 1;
0194 minor = 6;
0195 if (sun4v_hvapi_register(group, major, &minor))
0196 goto bad;
0197
0198 return;
0199
0200 bad:
0201 prom_printf("HVAPI: Cannot register API group "
0202 "%lx with major(%lu) minor(%lu)\n",
0203 group, major, minor);
0204 prom_halt();
0205 }