root/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.c

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

DEFINITIONS

This source file includes following definitions.
  1. mlx5_hv_vhca_create
  2. mlx5_hv_vhca_destroy
  3. mlx5_hv_vhca_invalidate_work
  4. mlx5_hv_vhca_invalidate
  5. mlx5_hv_vhca_agents_control
  6. mlx5_hv_vhca_capabilities
  7. mlx5_hv_vhca_control_agent_invalidate
  8. mlx5_hv_vhca_control_agent_create
  9. mlx5_hv_vhca_control_agent_destroy
  10. mlx5_hv_vhca_init
  11. mlx5_hv_vhca_cleanup
  12. mlx5_hv_vhca_agents_update
  13. mlx5_hv_vhca_agent_create
  14. mlx5_hv_vhca_agent_destroy
  15. mlx5_hv_vhca_data_block_prepare
  16. mlx5_hv_vhca_agent_seq_update
  17. mlx5_hv_vhca_agent_write
  18. mlx5_hv_vhca_agent_priv

   1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
   2 // Copyright (c) 2018 Mellanox Technologies
   3 
   4 #include <linux/hyperv.h>
   5 #include "mlx5_core.h"
   6 #include "lib/hv.h"
   7 #include "lib/hv_vhca.h"
   8 
   9 struct mlx5_hv_vhca {
  10         struct mlx5_core_dev       *dev;
  11         struct workqueue_struct    *work_queue;
  12         struct mlx5_hv_vhca_agent  *agents[MLX5_HV_VHCA_AGENT_MAX];
  13         struct mutex                agents_lock; /* Protect agents array */
  14 };
  15 
  16 struct mlx5_hv_vhca_work {
  17         struct work_struct     invalidate_work;
  18         struct mlx5_hv_vhca   *hv_vhca;
  19         u64                    block_mask;
  20 };
  21 
  22 struct mlx5_hv_vhca_data_block {
  23         u16     sequence;
  24         u16     offset;
  25         u8      reserved[4];
  26         u64     data[15];
  27 };
  28 
  29 struct mlx5_hv_vhca_agent {
  30         enum mlx5_hv_vhca_agent_type     type;
  31         struct mlx5_hv_vhca             *hv_vhca;
  32         void                            *priv;
  33         u16                              seq;
  34         void (*control)(struct mlx5_hv_vhca_agent *agent,
  35                         struct mlx5_hv_vhca_control_block *block);
  36         void (*invalidate)(struct mlx5_hv_vhca_agent *agent,
  37                            u64 block_mask);
  38         void (*cleanup)(struct mlx5_hv_vhca_agent *agent);
  39 };
  40 
  41 struct mlx5_hv_vhca *mlx5_hv_vhca_create(struct mlx5_core_dev *dev)
  42 {
  43         struct mlx5_hv_vhca *hv_vhca = NULL;
  44 
  45         hv_vhca = kzalloc(sizeof(*hv_vhca), GFP_KERNEL);
  46         if (!hv_vhca)
  47                 return ERR_PTR(-ENOMEM);
  48 
  49         hv_vhca->work_queue = create_singlethread_workqueue("mlx5_hv_vhca");
  50         if (!hv_vhca->work_queue) {
  51                 kfree(hv_vhca);
  52                 return ERR_PTR(-ENOMEM);
  53         }
  54 
  55         hv_vhca->dev = dev;
  56         mutex_init(&hv_vhca->agents_lock);
  57 
  58         return hv_vhca;
  59 }
  60 
  61 void mlx5_hv_vhca_destroy(struct mlx5_hv_vhca *hv_vhca)
  62 {
  63         if (IS_ERR_OR_NULL(hv_vhca))
  64                 return;
  65 
  66         destroy_workqueue(hv_vhca->work_queue);
  67         kfree(hv_vhca);
  68 }
  69 
  70 static void mlx5_hv_vhca_invalidate_work(struct work_struct *work)
  71 {
  72         struct mlx5_hv_vhca_work *hwork;
  73         struct mlx5_hv_vhca *hv_vhca;
  74         int i;
  75 
  76         hwork = container_of(work, struct mlx5_hv_vhca_work, invalidate_work);
  77         hv_vhca = hwork->hv_vhca;
  78 
  79         mutex_lock(&hv_vhca->agents_lock);
  80         for (i = 0; i < MLX5_HV_VHCA_AGENT_MAX; i++) {
  81                 struct mlx5_hv_vhca_agent *agent = hv_vhca->agents[i];
  82 
  83                 if (!agent || !agent->invalidate)
  84                         continue;
  85 
  86                 if (!(BIT(agent->type) & hwork->block_mask))
  87                         continue;
  88 
  89                 agent->invalidate(agent, hwork->block_mask);
  90         }
  91         mutex_unlock(&hv_vhca->agents_lock);
  92 
  93         kfree(hwork);
  94 }
  95 
  96 void mlx5_hv_vhca_invalidate(void *context, u64 block_mask)
  97 {
  98         struct mlx5_hv_vhca *hv_vhca = (struct mlx5_hv_vhca *)context;
  99         struct mlx5_hv_vhca_work *work;
 100 
 101         work = kzalloc(sizeof(*work), GFP_ATOMIC);
 102         if (!work)
 103                 return;
 104 
 105         INIT_WORK(&work->invalidate_work, mlx5_hv_vhca_invalidate_work);
 106         work->hv_vhca    = hv_vhca;
 107         work->block_mask = block_mask;
 108 
 109         queue_work(hv_vhca->work_queue, &work->invalidate_work);
 110 }
 111 
 112 #define AGENT_MASK(type) (type ? BIT(type - 1) : 0 /* control */)
 113 
 114 static void mlx5_hv_vhca_agents_control(struct mlx5_hv_vhca *hv_vhca,
 115                                         struct mlx5_hv_vhca_control_block *block)
 116 {
 117         int i;
 118 
 119         for (i = 0; i < MLX5_HV_VHCA_AGENT_MAX; i++) {
 120                 struct mlx5_hv_vhca_agent *agent = hv_vhca->agents[i];
 121 
 122                 if (!agent || !agent->control)
 123                         continue;
 124 
 125                 if (!(AGENT_MASK(agent->type) & block->control))
 126                         continue;
 127 
 128                 agent->control(agent, block);
 129         }
 130 }
 131 
 132 static void mlx5_hv_vhca_capabilities(struct mlx5_hv_vhca *hv_vhca,
 133                                       u32 *capabilities)
 134 {
 135         int i;
 136 
 137         for (i = 0; i < MLX5_HV_VHCA_AGENT_MAX; i++) {
 138                 struct mlx5_hv_vhca_agent *agent = hv_vhca->agents[i];
 139 
 140                 if (agent)
 141                         *capabilities |= AGENT_MASK(agent->type);
 142         }
 143 }
 144 
 145 static void
 146 mlx5_hv_vhca_control_agent_invalidate(struct mlx5_hv_vhca_agent *agent,
 147                                       u64 block_mask)
 148 {
 149         struct mlx5_hv_vhca *hv_vhca = agent->hv_vhca;
 150         struct mlx5_core_dev *dev = hv_vhca->dev;
 151         struct mlx5_hv_vhca_control_block *block;
 152         u32 capabilities = 0;
 153         int err;
 154 
 155         block = kzalloc(sizeof(*block), GFP_KERNEL);
 156         if (!block)
 157                 return;
 158 
 159         err = mlx5_hv_read_config(dev, block, sizeof(*block), 0);
 160         if (err)
 161                 goto free_block;
 162 
 163         mlx5_hv_vhca_capabilities(hv_vhca, &capabilities);
 164 
 165         /* In case no capabilities, send empty block in return */
 166         if (!capabilities) {
 167                 memset(block, 0, sizeof(*block));
 168                 goto write;
 169         }
 170 
 171         if (block->capabilities != capabilities)
 172                 block->capabilities = capabilities;
 173 
 174         if (block->control & ~capabilities)
 175                 goto free_block;
 176 
 177         mlx5_hv_vhca_agents_control(hv_vhca, block);
 178         block->command_ack = block->command;
 179 
 180 write:
 181         mlx5_hv_write_config(dev, block, sizeof(*block), 0);
 182 
 183 free_block:
 184         kfree(block);
 185 }
 186 
 187 static struct mlx5_hv_vhca_agent *
 188 mlx5_hv_vhca_control_agent_create(struct mlx5_hv_vhca *hv_vhca)
 189 {
 190         return mlx5_hv_vhca_agent_create(hv_vhca, MLX5_HV_VHCA_AGENT_CONTROL,
 191                                          NULL,
 192                                          mlx5_hv_vhca_control_agent_invalidate,
 193                                          NULL, NULL);
 194 }
 195 
 196 static void mlx5_hv_vhca_control_agent_destroy(struct mlx5_hv_vhca_agent *agent)
 197 {
 198         mlx5_hv_vhca_agent_destroy(agent);
 199 }
 200 
 201 int mlx5_hv_vhca_init(struct mlx5_hv_vhca *hv_vhca)
 202 {
 203         struct mlx5_hv_vhca_agent *agent;
 204         int err;
 205 
 206         if (IS_ERR_OR_NULL(hv_vhca))
 207                 return IS_ERR_OR_NULL(hv_vhca);
 208 
 209         err = mlx5_hv_register_invalidate(hv_vhca->dev, hv_vhca,
 210                                           mlx5_hv_vhca_invalidate);
 211         if (err)
 212                 return err;
 213 
 214         agent = mlx5_hv_vhca_control_agent_create(hv_vhca);
 215         if (IS_ERR_OR_NULL(agent)) {
 216                 mlx5_hv_unregister_invalidate(hv_vhca->dev);
 217                 return IS_ERR_OR_NULL(agent);
 218         }
 219 
 220         hv_vhca->agents[MLX5_HV_VHCA_AGENT_CONTROL] = agent;
 221 
 222         return 0;
 223 }
 224 
 225 void mlx5_hv_vhca_cleanup(struct mlx5_hv_vhca *hv_vhca)
 226 {
 227         struct mlx5_hv_vhca_agent *agent;
 228         int i;
 229 
 230         if (IS_ERR_OR_NULL(hv_vhca))
 231                 return;
 232 
 233         agent = hv_vhca->agents[MLX5_HV_VHCA_AGENT_CONTROL];
 234         if (agent)
 235                 mlx5_hv_vhca_control_agent_destroy(agent);
 236 
 237         mutex_lock(&hv_vhca->agents_lock);
 238         for (i = 0; i < MLX5_HV_VHCA_AGENT_MAX; i++)
 239                 WARN_ON(hv_vhca->agents[i]);
 240 
 241         mutex_unlock(&hv_vhca->agents_lock);
 242 
 243         mlx5_hv_unregister_invalidate(hv_vhca->dev);
 244 }
 245 
 246 static void mlx5_hv_vhca_agents_update(struct mlx5_hv_vhca *hv_vhca)
 247 {
 248         mlx5_hv_vhca_invalidate(hv_vhca, BIT(MLX5_HV_VHCA_AGENT_CONTROL));
 249 }
 250 
 251 struct mlx5_hv_vhca_agent *
 252 mlx5_hv_vhca_agent_create(struct mlx5_hv_vhca *hv_vhca,
 253                           enum mlx5_hv_vhca_agent_type type,
 254                           void (*control)(struct mlx5_hv_vhca_agent*,
 255                                           struct mlx5_hv_vhca_control_block *block),
 256                           void (*invalidate)(struct mlx5_hv_vhca_agent*,
 257                                              u64 block_mask),
 258                           void (*cleaup)(struct mlx5_hv_vhca_agent *agent),
 259                           void *priv)
 260 {
 261         struct mlx5_hv_vhca_agent *agent;
 262 
 263         if (IS_ERR_OR_NULL(hv_vhca))
 264                 return ERR_PTR(-ENOMEM);
 265 
 266         if (type >= MLX5_HV_VHCA_AGENT_MAX)
 267                 return ERR_PTR(-EINVAL);
 268 
 269         mutex_lock(&hv_vhca->agents_lock);
 270         if (hv_vhca->agents[type]) {
 271                 mutex_unlock(&hv_vhca->agents_lock);
 272                 return ERR_PTR(-EINVAL);
 273         }
 274         mutex_unlock(&hv_vhca->agents_lock);
 275 
 276         agent = kzalloc(sizeof(*agent), GFP_KERNEL);
 277         if (!agent)
 278                 return ERR_PTR(-ENOMEM);
 279 
 280         agent->type      = type;
 281         agent->hv_vhca   = hv_vhca;
 282         agent->priv      = priv;
 283         agent->control   = control;
 284         agent->invalidate = invalidate;
 285         agent->cleanup   = cleaup;
 286 
 287         mutex_lock(&hv_vhca->agents_lock);
 288         hv_vhca->agents[type] = agent;
 289         mutex_unlock(&hv_vhca->agents_lock);
 290 
 291         mlx5_hv_vhca_agents_update(hv_vhca);
 292 
 293         return agent;
 294 }
 295 
 296 void mlx5_hv_vhca_agent_destroy(struct mlx5_hv_vhca_agent *agent)
 297 {
 298         struct mlx5_hv_vhca *hv_vhca = agent->hv_vhca;
 299 
 300         mutex_lock(&hv_vhca->agents_lock);
 301 
 302         if (WARN_ON(agent != hv_vhca->agents[agent->type])) {
 303                 mutex_unlock(&hv_vhca->agents_lock);
 304                 return;
 305         }
 306 
 307         hv_vhca->agents[agent->type] = NULL;
 308         mutex_unlock(&hv_vhca->agents_lock);
 309 
 310         if (agent->cleanup)
 311                 agent->cleanup(agent);
 312 
 313         kfree(agent);
 314 
 315         mlx5_hv_vhca_agents_update(hv_vhca);
 316 }
 317 
 318 static int mlx5_hv_vhca_data_block_prepare(struct mlx5_hv_vhca_agent *agent,
 319                                            struct mlx5_hv_vhca_data_block *data_block,
 320                                            void *src, int len, int *offset)
 321 {
 322         int bytes = min_t(int, (int)sizeof(data_block->data), len);
 323 
 324         data_block->sequence = agent->seq;
 325         data_block->offset   = (*offset)++;
 326         memcpy(data_block->data, src, bytes);
 327 
 328         return bytes;
 329 }
 330 
 331 static void mlx5_hv_vhca_agent_seq_update(struct mlx5_hv_vhca_agent *agent)
 332 {
 333         agent->seq++;
 334 }
 335 
 336 int mlx5_hv_vhca_agent_write(struct mlx5_hv_vhca_agent *agent,
 337                              void *buf, int len)
 338 {
 339         int offset = agent->type * HV_CONFIG_BLOCK_SIZE_MAX;
 340         int block_offset = 0;
 341         int total = 0;
 342         int err;
 343 
 344         while (len) {
 345                 struct mlx5_hv_vhca_data_block data_block = {0};
 346                 int bytes;
 347 
 348                 bytes = mlx5_hv_vhca_data_block_prepare(agent, &data_block,
 349                                                         buf + total,
 350                                                         len, &block_offset);
 351                 if (!bytes)
 352                         return -ENOMEM;
 353 
 354                 err = mlx5_hv_write_config(agent->hv_vhca->dev, &data_block,
 355                                            sizeof(data_block), offset);
 356                 if (err)
 357                         return err;
 358 
 359                 total += bytes;
 360                 len   -= bytes;
 361         }
 362 
 363         mlx5_hv_vhca_agent_seq_update(agent);
 364 
 365         return 0;
 366 }
 367 
 368 void *mlx5_hv_vhca_agent_priv(struct mlx5_hv_vhca_agent *agent)
 369 {
 370         return agent->priv;
 371 }

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