0001
0002
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
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
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 }