Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
0002 /* Copyright (c) 2018 Mellanox Technologies */
0003 
0004 #include <linux/mlx5/vport.h>
0005 #include "lib/devcom.h"
0006 
0007 static LIST_HEAD(devcom_list);
0008 
0009 #define devcom_for_each_component(priv, comp, iter) \
0010     for (iter = 0; \
0011          comp = &(priv)->components[iter], iter < MLX5_DEVCOM_NUM_COMPONENTS; \
0012          iter++)
0013 
0014 struct mlx5_devcom_component {
0015     struct {
0016         void *data;
0017     } device[MLX5_DEVCOM_PORTS_SUPPORTED];
0018 
0019     mlx5_devcom_event_handler_t handler;
0020     struct rw_semaphore sem;
0021     bool paired;
0022 };
0023 
0024 struct mlx5_devcom_list {
0025     struct list_head list;
0026 
0027     struct mlx5_devcom_component components[MLX5_DEVCOM_NUM_COMPONENTS];
0028     struct mlx5_core_dev *devs[MLX5_DEVCOM_PORTS_SUPPORTED];
0029 };
0030 
0031 struct mlx5_devcom {
0032     struct mlx5_devcom_list *priv;
0033     int idx;
0034 };
0035 
0036 static struct mlx5_devcom_list *mlx5_devcom_list_alloc(void)
0037 {
0038     struct mlx5_devcom_component *comp;
0039     struct mlx5_devcom_list *priv;
0040     int i;
0041 
0042     priv = kzalloc(sizeof(*priv), GFP_KERNEL);
0043     if (!priv)
0044         return NULL;
0045 
0046     devcom_for_each_component(priv, comp, i)
0047         init_rwsem(&comp->sem);
0048 
0049     return priv;
0050 }
0051 
0052 static struct mlx5_devcom *mlx5_devcom_alloc(struct mlx5_devcom_list *priv,
0053                          u8 idx)
0054 {
0055     struct mlx5_devcom *devcom;
0056 
0057     devcom = kzalloc(sizeof(*devcom), GFP_KERNEL);
0058     if (!devcom)
0059         return NULL;
0060 
0061     devcom->priv = priv;
0062     devcom->idx = idx;
0063     return devcom;
0064 }
0065 
0066 /* Must be called with intf_mutex held */
0067 struct mlx5_devcom *mlx5_devcom_register_device(struct mlx5_core_dev *dev)
0068 {
0069     struct mlx5_devcom_list *priv = NULL, *iter;
0070     struct mlx5_devcom *devcom = NULL;
0071     bool new_priv = false;
0072     u64 sguid0, sguid1;
0073     int idx, i;
0074 
0075     if (!mlx5_core_is_pf(dev))
0076         return NULL;
0077     if (MLX5_CAP_GEN(dev, num_lag_ports) != MLX5_DEVCOM_PORTS_SUPPORTED)
0078         return NULL;
0079 
0080     sguid0 = mlx5_query_nic_system_image_guid(dev);
0081     list_for_each_entry(iter, &devcom_list, list) {
0082         struct mlx5_core_dev *tmp_dev = NULL;
0083 
0084         idx = -1;
0085         for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++) {
0086             if (iter->devs[i])
0087                 tmp_dev = iter->devs[i];
0088             else
0089                 idx = i;
0090         }
0091 
0092         if (idx == -1)
0093             continue;
0094 
0095         sguid1 = mlx5_query_nic_system_image_guid(tmp_dev);
0096         if (sguid0 != sguid1)
0097             continue;
0098 
0099         priv = iter;
0100         break;
0101     }
0102 
0103     if (!priv) {
0104         priv = mlx5_devcom_list_alloc();
0105         if (!priv)
0106             return ERR_PTR(-ENOMEM);
0107 
0108         idx = 0;
0109         new_priv = true;
0110     }
0111 
0112     priv->devs[idx] = dev;
0113     devcom = mlx5_devcom_alloc(priv, idx);
0114     if (!devcom) {
0115         kfree(priv);
0116         return ERR_PTR(-ENOMEM);
0117     }
0118 
0119     if (new_priv)
0120         list_add(&priv->list, &devcom_list);
0121 
0122     return devcom;
0123 }
0124 
0125 /* Must be called with intf_mutex held */
0126 void mlx5_devcom_unregister_device(struct mlx5_devcom *devcom)
0127 {
0128     struct mlx5_devcom_list *priv;
0129     int i;
0130 
0131     if (IS_ERR_OR_NULL(devcom))
0132         return;
0133 
0134     priv = devcom->priv;
0135     priv->devs[devcom->idx] = NULL;
0136 
0137     kfree(devcom);
0138 
0139     for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++)
0140         if (priv->devs[i])
0141             break;
0142 
0143     if (i != MLX5_DEVCOM_PORTS_SUPPORTED)
0144         return;
0145 
0146     list_del(&priv->list);
0147     kfree(priv);
0148 }
0149 
0150 void mlx5_devcom_register_component(struct mlx5_devcom *devcom,
0151                     enum mlx5_devcom_components id,
0152                     mlx5_devcom_event_handler_t handler,
0153                     void *data)
0154 {
0155     struct mlx5_devcom_component *comp;
0156 
0157     if (IS_ERR_OR_NULL(devcom))
0158         return;
0159 
0160     WARN_ON(!data);
0161 
0162     comp = &devcom->priv->components[id];
0163     down_write(&comp->sem);
0164     comp->handler = handler;
0165     comp->device[devcom->idx].data = data;
0166     up_write(&comp->sem);
0167 }
0168 
0169 void mlx5_devcom_unregister_component(struct mlx5_devcom *devcom,
0170                       enum mlx5_devcom_components id)
0171 {
0172     struct mlx5_devcom_component *comp;
0173 
0174     if (IS_ERR_OR_NULL(devcom))
0175         return;
0176 
0177     comp = &devcom->priv->components[id];
0178     down_write(&comp->sem);
0179     comp->device[devcom->idx].data = NULL;
0180     up_write(&comp->sem);
0181 }
0182 
0183 int mlx5_devcom_send_event(struct mlx5_devcom *devcom,
0184                enum mlx5_devcom_components id,
0185                int event,
0186                void *event_data)
0187 {
0188     struct mlx5_devcom_component *comp;
0189     int err = -ENODEV, i;
0190 
0191     if (IS_ERR_OR_NULL(devcom))
0192         return err;
0193 
0194     comp = &devcom->priv->components[id];
0195     down_write(&comp->sem);
0196     for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++)
0197         if (i != devcom->idx && comp->device[i].data) {
0198             err = comp->handler(event, comp->device[i].data,
0199                         event_data);
0200             break;
0201         }
0202 
0203     up_write(&comp->sem);
0204     return err;
0205 }
0206 
0207 void mlx5_devcom_set_paired(struct mlx5_devcom *devcom,
0208                 enum mlx5_devcom_components id,
0209                 bool paired)
0210 {
0211     struct mlx5_devcom_component *comp;
0212 
0213     comp = &devcom->priv->components[id];
0214     WARN_ON(!rwsem_is_locked(&comp->sem));
0215 
0216     comp->paired = paired;
0217 }
0218 
0219 bool mlx5_devcom_is_paired(struct mlx5_devcom *devcom,
0220                enum mlx5_devcom_components id)
0221 {
0222     if (IS_ERR_OR_NULL(devcom))
0223         return false;
0224 
0225     return devcom->priv->components[id].paired;
0226 }
0227 
0228 void *mlx5_devcom_get_peer_data(struct mlx5_devcom *devcom,
0229                 enum mlx5_devcom_components id)
0230 {
0231     struct mlx5_devcom_component *comp;
0232     int i;
0233 
0234     if (IS_ERR_OR_NULL(devcom))
0235         return NULL;
0236 
0237     comp = &devcom->priv->components[id];
0238     down_read(&comp->sem);
0239     if (!comp->paired) {
0240         up_read(&comp->sem);
0241         return NULL;
0242     }
0243 
0244     for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++)
0245         if (i != devcom->idx)
0246             break;
0247 
0248     return comp->device[i].data;
0249 }
0250 
0251 void mlx5_devcom_release_peer_data(struct mlx5_devcom *devcom,
0252                    enum mlx5_devcom_components id)
0253 {
0254     struct mlx5_devcom_component *comp = &devcom->priv->components[id];
0255 
0256     up_read(&comp->sem);
0257 }