Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* hvapi.c: Hypervisor API management.
0003  *
0004  * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
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 /* If the hypervisor indicates that the API setting
0014  * calls are unsupported, by returning HV_EBADTRAP or
0015  * HV_ENOTSUPPORTED, we assume that API groups with the
0016  * PRE_API flag set are major 1 minor 0.
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 /* Register a hypervisor API specification.  It indicates the
0086  * API group and desired major+minor.
0087  *
0088  * If an existing API registration exists '0' (success) will
0089  * be returned if it is compatible with the one being registered.
0090  * Otherwise a negative error code will be returned.
0091  *
0092  * Otherwise an attempt will be made to negotiate the requested
0093  * API group/major/minor with the hypervisor, and errors returned
0094  * if that does not succeed.
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 }