root/arch/sparc/kernel/hvapi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __get_info
  2. __get_ref
  3. __put_ref
  4. sun4v_hvapi_register
  5. sun4v_hvapi_unregister
  6. sun4v_hvapi_get
  7. sun4v_hvapi_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /* hvapi.c: Hypervisor API management.
   3  *
   4  * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
   5  */
   6 #include <linux/kernel.h>
   7 #include <linux/export.h>
   8 #include <linux/init.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  */
  18 struct 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 
  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,                              },
  55 };
  56 
  57 static DEFINE_SPINLOCK(hvapi_lock);
  58 
  59 static struct api_info *__get_info(unsigned long group)
  60 {
  61         int i;
  62 
  63         for (i = 0; i < ARRAY_SIZE(api_table); i++) {
  64                 if (api_table[i].group == group)
  65                         return &api_table[i];
  66         }
  67         return NULL;
  68 }
  69 
  70 static void __get_ref(struct api_info *p)
  71 {
  72         p->refcnt++;
  73 }
  74 
  75 static void __put_ref(struct api_info *p)
  76 {
  77         if (--p->refcnt == 0) {
  78                 unsigned long ignore;
  79 
  80                 sun4v_set_version(p->group, 0, 0, &ignore);
  81                 p->major = p->minor = 0;
  82         }
  83 }
  84 
  85 /* Register a hypervisor API specification.  It indicates the
  86  * API group and desired major+minor.
  87  *
  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.
  91  *
  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.
  95  */
  96 int sun4v_hvapi_register(unsigned long group, unsigned long major,
  97                          unsigned long *minor)
  98 {
  99         struct api_info *p;
 100         unsigned long flags;
 101         int ret;
 102 
 103         spin_lock_irqsave(&hvapi_lock, flags);
 104         p = __get_info(group);
 105         ret = -EINVAL;
 106         if (p) {
 107                 if (p->refcnt) {
 108                         ret = -EINVAL;
 109                         if (p->major == major) {
 110                                 *minor = p->minor;
 111                                 ret = 0;
 112                         }
 113                 } else {
 114                         unsigned long actual_minor;
 115                         unsigned long hv_ret;
 116 
 117                         hv_ret = sun4v_set_version(group, major, *minor,
 118                                                    &actual_minor);
 119                         ret = -EINVAL;
 120                         if (hv_ret == HV_EOK) {
 121                                 *minor = actual_minor;
 122                                 p->major = major;
 123                                 p->minor = actual_minor;
 124                                 ret = 0;
 125                         } else if (hv_ret == HV_EBADTRAP ||
 126                                    hv_ret == HV_ENOTSUPPORTED) {
 127                                 if (p->flags & FLAG_PRE_API) {
 128                                         if (major == 1) {
 129                                                 p->major = 1;
 130                                                 p->minor = 0;
 131                                                 *minor = 0;
 132                                                 ret = 0;
 133                                         }
 134                                 }
 135                         }
 136                 }
 137 
 138                 if (ret == 0)
 139                         __get_ref(p);
 140         }
 141         spin_unlock_irqrestore(&hvapi_lock, flags);
 142 
 143         return ret;
 144 }
 145 EXPORT_SYMBOL(sun4v_hvapi_register);
 146 
 147 void sun4v_hvapi_unregister(unsigned long group)
 148 {
 149         struct api_info *p;
 150         unsigned long flags;
 151 
 152         spin_lock_irqsave(&hvapi_lock, flags);
 153         p = __get_info(group);
 154         if (p)
 155                 __put_ref(p);
 156         spin_unlock_irqrestore(&hvapi_lock, flags);
 157 }
 158 EXPORT_SYMBOL(sun4v_hvapi_unregister);
 159 
 160 int sun4v_hvapi_get(unsigned long group,
 161                     unsigned long *major,
 162                     unsigned long *minor)
 163 {
 164         struct api_info *p;
 165         unsigned long flags;
 166         int ret;
 167 
 168         spin_lock_irqsave(&hvapi_lock, flags);
 169         ret = -EINVAL;
 170         p = __get_info(group);
 171         if (p && p->refcnt) {
 172                 *major = p->major;
 173                 *minor = p->minor;
 174                 ret = 0;
 175         }
 176         spin_unlock_irqrestore(&hvapi_lock, flags);
 177 
 178         return ret;
 179 }
 180 EXPORT_SYMBOL(sun4v_hvapi_get);
 181 
 182 void __init sun4v_hvapi_init(void)
 183 {
 184         unsigned long group, major, minor;
 185 
 186         group = HV_GRP_SUN4V;
 187         major = 1;
 188         minor = 0;
 189         if (sun4v_hvapi_register(group, major, &minor))
 190                 goto bad;
 191 
 192         group = HV_GRP_CORE;
 193         major = 1;
 194         minor = 6;
 195         if (sun4v_hvapi_register(group, major, &minor))
 196                 goto bad;
 197 
 198         return;
 199 
 200 bad:
 201         prom_printf("HVAPI: Cannot register API group "
 202                     "%lx with major(%lu) minor(%lu)\n",
 203                     group, major, minor);
 204         prom_halt();
 205 }

/* [<][>][^][v][top][bottom][index][help] */