1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33#include <linux/mlx5/driver.h>
34#include "mlx5_core.h"
35
36static LIST_HEAD(intf_list);
37static LIST_HEAD(mlx5_dev_list);
38
39static DEFINE_MUTEX(mlx5_intf_mutex);
40
41struct mlx5_device_context {
42 struct list_head list;
43 struct mlx5_interface *intf;
44 void *context;
45 unsigned long state;
46};
47
48enum {
49 MLX5_INTERFACE_ADDED,
50 MLX5_INTERFACE_ATTACHED,
51};
52
53void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv)
54{
55 struct mlx5_device_context *dev_ctx;
56 struct mlx5_core_dev *dev = container_of(priv, struct mlx5_core_dev, priv);
57
58 if (!mlx5_lag_intf_add(intf, priv))
59 return;
60
61 dev_ctx = kzalloc(sizeof(*dev_ctx), GFP_KERNEL);
62 if (!dev_ctx)
63 return;
64
65 dev_ctx->intf = intf;
66 dev_ctx->context = intf->add(dev);
67 set_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state);
68 if (intf->attach)
69 set_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state);
70
71 if (dev_ctx->context) {
72 spin_lock_irq(&priv->ctx_lock);
73 list_add_tail(&dev_ctx->list, &priv->ctx_list);
74 spin_unlock_irq(&priv->ctx_lock);
75 } else {
76 kfree(dev_ctx);
77 }
78}
79
80static struct mlx5_device_context *mlx5_get_device(struct mlx5_interface *intf,
81 struct mlx5_priv *priv)
82{
83 struct mlx5_device_context *dev_ctx;
84
85 list_for_each_entry(dev_ctx, &priv->ctx_list, list)
86 if (dev_ctx->intf == intf)
87 return dev_ctx;
88 return NULL;
89}
90
91void mlx5_remove_device(struct mlx5_interface *intf, struct mlx5_priv *priv)
92{
93 struct mlx5_device_context *dev_ctx;
94 struct mlx5_core_dev *dev = container_of(priv, struct mlx5_core_dev, priv);
95
96 dev_ctx = mlx5_get_device(intf, priv);
97 if (!dev_ctx)
98 return;
99
100 spin_lock_irq(&priv->ctx_lock);
101 list_del(&dev_ctx->list);
102 spin_unlock_irq(&priv->ctx_lock);
103
104 if (test_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state))
105 intf->remove(dev, dev_ctx->context);
106
107 kfree(dev_ctx);
108}
109
110static void mlx5_attach_interface(struct mlx5_interface *intf, struct mlx5_priv *priv)
111{
112 struct mlx5_device_context *dev_ctx;
113 struct mlx5_core_dev *dev = container_of(priv, struct mlx5_core_dev, priv);
114
115 dev_ctx = mlx5_get_device(intf, priv);
116 if (!dev_ctx)
117 return;
118
119 if (intf->attach) {
120 if (test_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state))
121 return;
122 intf->attach(dev, dev_ctx->context);
123 set_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state);
124 } else {
125 if (test_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state))
126 return;
127 dev_ctx->context = intf->add(dev);
128 set_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state);
129 }
130}
131
132void mlx5_attach_device(struct mlx5_core_dev *dev)
133{
134 struct mlx5_priv *priv = &dev->priv;
135 struct mlx5_interface *intf;
136
137 mutex_lock(&mlx5_intf_mutex);
138 list_for_each_entry(intf, &intf_list, list)
139 mlx5_attach_interface(intf, priv);
140 mutex_unlock(&mlx5_intf_mutex);
141}
142
143static void mlx5_detach_interface(struct mlx5_interface *intf, struct mlx5_priv *priv)
144{
145 struct mlx5_device_context *dev_ctx;
146 struct mlx5_core_dev *dev = container_of(priv, struct mlx5_core_dev, priv);
147
148 dev_ctx = mlx5_get_device(intf, priv);
149 if (!dev_ctx)
150 return;
151
152 if (intf->detach) {
153 if (!test_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state))
154 return;
155 intf->detach(dev, dev_ctx->context);
156 clear_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state);
157 } else {
158 if (!test_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state))
159 return;
160 intf->remove(dev, dev_ctx->context);
161 clear_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state);
162 }
163}
164
165void mlx5_detach_device(struct mlx5_core_dev *dev)
166{
167 struct mlx5_priv *priv = &dev->priv;
168 struct mlx5_interface *intf;
169
170 mutex_lock(&mlx5_intf_mutex);
171 list_for_each_entry(intf, &intf_list, list)
172 mlx5_detach_interface(intf, priv);
173 mutex_unlock(&mlx5_intf_mutex);
174}
175
176bool mlx5_device_registered(struct mlx5_core_dev *dev)
177{
178 struct mlx5_priv *priv;
179 bool found = false;
180
181 mutex_lock(&mlx5_intf_mutex);
182 list_for_each_entry(priv, &mlx5_dev_list, dev_list)
183 if (priv == &dev->priv)
184 found = true;
185 mutex_unlock(&mlx5_intf_mutex);
186
187 return found;
188}
189
190int mlx5_register_device(struct mlx5_core_dev *dev)
191{
192 struct mlx5_priv *priv = &dev->priv;
193 struct mlx5_interface *intf;
194
195 mutex_lock(&mlx5_intf_mutex);
196 list_add_tail(&priv->dev_list, &mlx5_dev_list);
197 list_for_each_entry(intf, &intf_list, list)
198 mlx5_add_device(intf, priv);
199 mutex_unlock(&mlx5_intf_mutex);
200
201 return 0;
202}
203
204void mlx5_unregister_device(struct mlx5_core_dev *dev)
205{
206 struct mlx5_priv *priv = &dev->priv;
207 struct mlx5_interface *intf;
208
209 mutex_lock(&mlx5_intf_mutex);
210 list_for_each_entry(intf, &intf_list, list)
211 mlx5_remove_device(intf, priv);
212 list_del(&priv->dev_list);
213 mutex_unlock(&mlx5_intf_mutex);
214}
215
216int mlx5_register_interface(struct mlx5_interface *intf)
217{
218 struct mlx5_priv *priv;
219
220 if (!intf->add || !intf->remove)
221 return -EINVAL;
222
223 mutex_lock(&mlx5_intf_mutex);
224 list_add_tail(&intf->list, &intf_list);
225 list_for_each_entry(priv, &mlx5_dev_list, dev_list)
226 mlx5_add_device(intf, priv);
227 mutex_unlock(&mlx5_intf_mutex);
228
229 return 0;
230}
231EXPORT_SYMBOL(mlx5_register_interface);
232
233void mlx5_unregister_interface(struct mlx5_interface *intf)
234{
235 struct mlx5_priv *priv;
236
237 mutex_lock(&mlx5_intf_mutex);
238 list_for_each_entry(priv, &mlx5_dev_list, dev_list)
239 mlx5_remove_device(intf, priv);
240 list_del(&intf->list);
241 mutex_unlock(&mlx5_intf_mutex);
242}
243EXPORT_SYMBOL(mlx5_unregister_interface);
244
245void *mlx5_get_protocol_dev(struct mlx5_core_dev *mdev, int protocol)
246{
247 struct mlx5_priv *priv = &mdev->priv;
248 struct mlx5_device_context *dev_ctx;
249 unsigned long flags;
250 void *result = NULL;
251
252 spin_lock_irqsave(&priv->ctx_lock, flags);
253
254 list_for_each_entry(dev_ctx, &mdev->priv.ctx_list, list)
255 if ((dev_ctx->intf->protocol == protocol) &&
256 dev_ctx->intf->get_dev) {
257 result = dev_ctx->intf->get_dev(dev_ctx->context);
258 break;
259 }
260
261 spin_unlock_irqrestore(&priv->ctx_lock, flags);
262
263 return result;
264}
265EXPORT_SYMBOL(mlx5_get_protocol_dev);
266
267
268void mlx5_add_dev_by_protocol(struct mlx5_core_dev *dev, int protocol)
269{
270 struct mlx5_interface *intf;
271
272 list_for_each_entry(intf, &intf_list, list)
273 if (intf->protocol == protocol) {
274 mlx5_add_device(intf, &dev->priv);
275 break;
276 }
277}
278
279
280void mlx5_remove_dev_by_protocol(struct mlx5_core_dev *dev, int protocol)
281{
282 struct mlx5_interface *intf;
283
284 list_for_each_entry(intf, &intf_list, list)
285 if (intf->protocol == protocol) {
286 mlx5_remove_device(intf, &dev->priv);
287 break;
288 }
289}
290
291static u16 mlx5_gen_pci_id(struct mlx5_core_dev *dev)
292{
293 return (u16)((dev->pdev->bus->number << 8) |
294 PCI_SLOT(dev->pdev->devfn));
295}
296
297
298struct mlx5_core_dev *mlx5_get_next_phys_dev(struct mlx5_core_dev *dev)
299{
300 u16 pci_id = mlx5_gen_pci_id(dev);
301 struct mlx5_core_dev *res = NULL;
302 struct mlx5_core_dev *tmp_dev;
303 struct mlx5_priv *priv;
304
305 list_for_each_entry(priv, &mlx5_dev_list, dev_list) {
306 tmp_dev = container_of(priv, struct mlx5_core_dev, priv);
307 if ((dev != tmp_dev) && (mlx5_gen_pci_id(tmp_dev) == pci_id)) {
308 res = tmp_dev;
309 break;
310 }
311 }
312
313 return res;
314}
315
316void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event,
317 unsigned long param)
318{
319 struct mlx5_priv *priv = &dev->priv;
320 struct mlx5_device_context *dev_ctx;
321 unsigned long flags;
322
323 spin_lock_irqsave(&priv->ctx_lock, flags);
324
325 list_for_each_entry(dev_ctx, &priv->ctx_list, list)
326 if (dev_ctx->intf->event)
327 dev_ctx->intf->event(dev, dev_ctx->context, event, param);
328
329 spin_unlock_irqrestore(&priv->ctx_lock, flags);
330}
331
332void mlx5_dev_list_lock(void)
333{
334 mutex_lock(&mlx5_intf_mutex);
335}
336
337void mlx5_dev_list_unlock(void)
338{
339 mutex_unlock(&mlx5_intf_mutex);
340}
341
342int mlx5_dev_list_trylock(void)
343{
344 return mutex_trylock(&mlx5_intf_mutex);
345}
346