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