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

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

DEFINITIONS

This source file includes following definitions.
  1. mlx5_devcom_list_alloc
  2. mlx5_devcom_alloc
  3. mlx5_devcom_register_device
  4. mlx5_devcom_unregister_device
  5. mlx5_devcom_register_component
  6. mlx5_devcom_unregister_component
  7. mlx5_devcom_send_event
  8. mlx5_devcom_set_paired
  9. mlx5_devcom_is_paired
  10. mlx5_devcom_get_peer_data
  11. mlx5_devcom_release_peer_data

   1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
   2 /* Copyright (c) 2018 Mellanox Technologies */
   3 
   4 #include <linux/mlx5/vport.h>
   5 #include "lib/devcom.h"
   6 
   7 static LIST_HEAD(devcom_list);
   8 
   9 #define devcom_for_each_component(priv, comp, iter) \
  10         for (iter = 0; \
  11              comp = &(priv)->components[iter], iter < MLX5_DEVCOM_NUM_COMPONENTS; \
  12              iter++)
  13 
  14 struct mlx5_devcom_component {
  15         struct {
  16                 void *data;
  17         } device[MLX5_MAX_PORTS];
  18 
  19         mlx5_devcom_event_handler_t handler;
  20         struct rw_semaphore sem;
  21         bool paired;
  22 };
  23 
  24 struct mlx5_devcom_list {
  25         struct list_head list;
  26 
  27         struct mlx5_devcom_component components[MLX5_DEVCOM_NUM_COMPONENTS];
  28         struct mlx5_core_dev *devs[MLX5_MAX_PORTS];
  29 };
  30 
  31 struct mlx5_devcom {
  32         struct mlx5_devcom_list *priv;
  33         int idx;
  34 };
  35 
  36 static struct mlx5_devcom_list *mlx5_devcom_list_alloc(void)
  37 {
  38         struct mlx5_devcom_component *comp;
  39         struct mlx5_devcom_list *priv;
  40         int i;
  41 
  42         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  43         if (!priv)
  44                 return NULL;
  45 
  46         devcom_for_each_component(priv, comp, i)
  47                 init_rwsem(&comp->sem);
  48 
  49         return priv;
  50 }
  51 
  52 static struct mlx5_devcom *mlx5_devcom_alloc(struct mlx5_devcom_list *priv,
  53                                              u8 idx)
  54 {
  55         struct mlx5_devcom *devcom;
  56 
  57         devcom = kzalloc(sizeof(*devcom), GFP_KERNEL);
  58         if (!devcom)
  59                 return NULL;
  60 
  61         devcom->priv = priv;
  62         devcom->idx = idx;
  63         return devcom;
  64 }
  65 
  66 /* Must be called with intf_mutex held */
  67 struct mlx5_devcom *mlx5_devcom_register_device(struct mlx5_core_dev *dev)
  68 {
  69         struct mlx5_devcom_list *priv = NULL, *iter;
  70         struct mlx5_devcom *devcom = NULL;
  71         bool new_priv = false;
  72         u64 sguid0, sguid1;
  73         int idx, i;
  74 
  75         if (!mlx5_core_is_pf(dev))
  76                 return NULL;
  77 
  78         sguid0 = mlx5_query_nic_system_image_guid(dev);
  79         list_for_each_entry(iter, &devcom_list, list) {
  80                 struct mlx5_core_dev *tmp_dev = NULL;
  81 
  82                 idx = -1;
  83                 for (i = 0; i < MLX5_MAX_PORTS; i++) {
  84                         if (iter->devs[i])
  85                                 tmp_dev = iter->devs[i];
  86                         else
  87                                 idx = i;
  88                 }
  89 
  90                 if (idx == -1)
  91                         continue;
  92 
  93                 sguid1 = mlx5_query_nic_system_image_guid(tmp_dev);
  94                 if (sguid0 != sguid1)
  95                         continue;
  96 
  97                 priv = iter;
  98                 break;
  99         }
 100 
 101         if (!priv) {
 102                 priv = mlx5_devcom_list_alloc();
 103                 if (!priv)
 104                         return ERR_PTR(-ENOMEM);
 105 
 106                 idx = 0;
 107                 new_priv = true;
 108         }
 109 
 110         priv->devs[idx] = dev;
 111         devcom = mlx5_devcom_alloc(priv, idx);
 112         if (!devcom) {
 113                 kfree(priv);
 114                 return ERR_PTR(-ENOMEM);
 115         }
 116 
 117         if (new_priv)
 118                 list_add(&priv->list, &devcom_list);
 119 
 120         return devcom;
 121 }
 122 
 123 /* Must be called with intf_mutex held */
 124 void mlx5_devcom_unregister_device(struct mlx5_devcom *devcom)
 125 {
 126         struct mlx5_devcom_list *priv;
 127         int i;
 128 
 129         if (IS_ERR_OR_NULL(devcom))
 130                 return;
 131 
 132         priv = devcom->priv;
 133         priv->devs[devcom->idx] = NULL;
 134 
 135         kfree(devcom);
 136 
 137         for (i = 0; i < MLX5_MAX_PORTS; i++)
 138                 if (priv->devs[i])
 139                         break;
 140 
 141         if (i != MLX5_MAX_PORTS)
 142                 return;
 143 
 144         list_del(&priv->list);
 145         kfree(priv);
 146 }
 147 
 148 void mlx5_devcom_register_component(struct mlx5_devcom *devcom,
 149                                     enum mlx5_devcom_components id,
 150                                     mlx5_devcom_event_handler_t handler,
 151                                     void *data)
 152 {
 153         struct mlx5_devcom_component *comp;
 154 
 155         if (IS_ERR_OR_NULL(devcom))
 156                 return;
 157 
 158         WARN_ON(!data);
 159 
 160         comp = &devcom->priv->components[id];
 161         down_write(&comp->sem);
 162         comp->handler = handler;
 163         comp->device[devcom->idx].data = data;
 164         up_write(&comp->sem);
 165 }
 166 
 167 void mlx5_devcom_unregister_component(struct mlx5_devcom *devcom,
 168                                       enum mlx5_devcom_components id)
 169 {
 170         struct mlx5_devcom_component *comp;
 171 
 172         if (IS_ERR_OR_NULL(devcom))
 173                 return;
 174 
 175         comp = &devcom->priv->components[id];
 176         down_write(&comp->sem);
 177         comp->device[devcom->idx].data = NULL;
 178         up_write(&comp->sem);
 179 }
 180 
 181 int mlx5_devcom_send_event(struct mlx5_devcom *devcom,
 182                            enum mlx5_devcom_components id,
 183                            int event,
 184                            void *event_data)
 185 {
 186         struct mlx5_devcom_component *comp;
 187         int err = -ENODEV, i;
 188 
 189         if (IS_ERR_OR_NULL(devcom))
 190                 return err;
 191 
 192         comp = &devcom->priv->components[id];
 193         down_write(&comp->sem);
 194         for (i = 0; i < MLX5_MAX_PORTS; i++)
 195                 if (i != devcom->idx && comp->device[i].data) {
 196                         err = comp->handler(event, comp->device[i].data,
 197                                             event_data);
 198                         break;
 199                 }
 200 
 201         up_write(&comp->sem);
 202         return err;
 203 }
 204 
 205 void mlx5_devcom_set_paired(struct mlx5_devcom *devcom,
 206                             enum mlx5_devcom_components id,
 207                             bool paired)
 208 {
 209         struct mlx5_devcom_component *comp;
 210 
 211         comp = &devcom->priv->components[id];
 212         WARN_ON(!rwsem_is_locked(&comp->sem));
 213 
 214         comp->paired = paired;
 215 }
 216 
 217 bool mlx5_devcom_is_paired(struct mlx5_devcom *devcom,
 218                            enum mlx5_devcom_components id)
 219 {
 220         if (IS_ERR_OR_NULL(devcom))
 221                 return false;
 222 
 223         return devcom->priv->components[id].paired;
 224 }
 225 
 226 void *mlx5_devcom_get_peer_data(struct mlx5_devcom *devcom,
 227                                 enum mlx5_devcom_components id)
 228 {
 229         struct mlx5_devcom_component *comp;
 230         int i;
 231 
 232         if (IS_ERR_OR_NULL(devcom))
 233                 return NULL;
 234 
 235         comp = &devcom->priv->components[id];
 236         down_read(&comp->sem);
 237         if (!comp->paired) {
 238                 up_read(&comp->sem);
 239                 return NULL;
 240         }
 241 
 242         for (i = 0; i < MLX5_MAX_PORTS; i++)
 243                 if (i != devcom->idx)
 244                         break;
 245 
 246         return comp->device[i].data;
 247 }
 248 
 249 void mlx5_devcom_release_peer_data(struct mlx5_devcom *devcom,
 250                                    enum mlx5_devcom_components id)
 251 {
 252         struct mlx5_devcom_component *comp = &devcom->priv->components[id];
 253 
 254         up_read(&comp->sem);
 255 }

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