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
34
35#include <rdma/ib_mad.h>
36#include <rdma/ib_smi.h>
37#include <rdma/ib_cache.h>
38#include <rdma/ib_sa.h>
39#include <rdma/ib_pack.h>
40#include <linux/mlx4/cmd.h>
41#include <linux/module.h>
42#include <linux/init.h>
43#include <linux/errno.h>
44#include <rdma/ib_user_verbs.h>
45#include <linux/delay.h>
46#include "mlx4_ib.h"
47
48
49
50
51
52
53struct mlx4_alias_guid_work_context {
54 u8 port;
55 struct mlx4_ib_dev *dev ;
56 struct ib_sa_query *sa_query;
57 struct completion done;
58 int query_id;
59 struct list_head list;
60 int block_num;
61 ib_sa_comp_mask guid_indexes;
62 u8 method;
63};
64
65struct mlx4_next_alias_guid_work {
66 u8 port;
67 u8 block_num;
68 u8 method;
69 struct mlx4_sriov_alias_guid_info_rec_det rec_det;
70};
71
72static int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port,
73 int *resched_delay_sec);
74
75void mlx4_ib_update_cache_on_guid_change(struct mlx4_ib_dev *dev, int block_num,
76 u8 port_num, u8 *p_data)
77{
78 int i;
79 u64 guid_indexes;
80 int slave_id;
81 int port_index = port_num - 1;
82
83 if (!mlx4_is_master(dev->dev))
84 return;
85
86 guid_indexes = be64_to_cpu((__force __be64) dev->sriov.alias_guid.
87 ports_guid[port_num - 1].
88 all_rec_per_port[block_num].guid_indexes);
89 pr_debug("port: %d, guid_indexes: 0x%llx\n", port_num, guid_indexes);
90
91 for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
92
93
94 if (test_bit(i + 4, (unsigned long *)&guid_indexes)) {
95 slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ;
96 if (slave_id >= dev->dev->num_slaves) {
97 pr_debug("The last slave: %d\n", slave_id);
98 return;
99 }
100
101
102 memcpy(&dev->sriov.demux[port_index].guid_cache[slave_id],
103 &p_data[i * GUID_REC_SIZE],
104 GUID_REC_SIZE);
105 } else
106 pr_debug("Guid number: %d in block: %d"
107 " was not updated\n", i, block_num);
108 }
109}
110
111static __be64 get_cached_alias_guid(struct mlx4_ib_dev *dev, int port, int index)
112{
113 if (index >= NUM_ALIAS_GUID_PER_PORT) {
114 pr_err("%s: ERROR: asked for index:%d\n", __func__, index);
115 return (__force __be64) -1;
116 }
117 return *(__be64 *)&dev->sriov.demux[port - 1].guid_cache[index];
118}
119
120
121ib_sa_comp_mask mlx4_ib_get_aguid_comp_mask_from_ix(int index)
122{
123 return IB_SA_COMP_MASK(4 + index);
124}
125
126void mlx4_ib_slave_alias_guid_event(struct mlx4_ib_dev *dev, int slave,
127 int port, int slave_init)
128{
129 __be64 curr_guid, required_guid;
130 int record_num = slave / 8;
131 int index = slave % 8;
132 int port_index = port - 1;
133 unsigned long flags;
134 int do_work = 0;
135
136 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
137 if (dev->sriov.alias_guid.ports_guid[port_index].state_flags &
138 GUID_STATE_NEED_PORT_INIT)
139 goto unlock;
140 if (!slave_init) {
141 curr_guid = *(__be64 *)&dev->sriov.
142 alias_guid.ports_guid[port_index].
143 all_rec_per_port[record_num].
144 all_recs[GUID_REC_SIZE * index];
145 if (curr_guid == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL) ||
146 !curr_guid)
147 goto unlock;
148 required_guid = cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL);
149 } else {
150 required_guid = mlx4_get_admin_guid(dev->dev, slave, port);
151 if (required_guid == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
152 goto unlock;
153 }
154 *(__be64 *)&dev->sriov.alias_guid.ports_guid[port_index].
155 all_rec_per_port[record_num].
156 all_recs[GUID_REC_SIZE * index] = required_guid;
157 dev->sriov.alias_guid.ports_guid[port_index].
158 all_rec_per_port[record_num].guid_indexes
159 |= mlx4_ib_get_aguid_comp_mask_from_ix(index);
160 dev->sriov.alias_guid.ports_guid[port_index].
161 all_rec_per_port[record_num].status
162 = MLX4_GUID_INFO_STATUS_IDLE;
163
164 dev->sriov.alias_guid.ports_guid[port_index].
165 all_rec_per_port[record_num].time_to_run = 0;
166 dev->sriov.alias_guid.ports_guid[port_index].
167 all_rec_per_port[record_num].
168 guids_retry_schedule[index] = 0;
169 do_work = 1;
170unlock:
171 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
172
173 if (do_work)
174 mlx4_ib_init_alias_guid_work(dev, port_index);
175}
176
177
178
179
180
181
182
183
184
185
186void mlx4_ib_notify_slaves_on_guid_change(struct mlx4_ib_dev *dev,
187 int block_num, u8 port_num,
188 u8 *p_data)
189{
190 int i;
191 u64 guid_indexes;
192 int slave_id, slave_port;
193 enum slave_port_state new_state;
194 enum slave_port_state prev_state;
195 __be64 tmp_cur_ag, form_cache_ag;
196 enum slave_port_gen_event gen_event;
197 struct mlx4_sriov_alias_guid_info_rec_det *rec;
198 unsigned long flags;
199 __be64 required_value;
200
201 if (!mlx4_is_master(dev->dev))
202 return;
203
204 rec = &dev->sriov.alias_guid.ports_guid[port_num - 1].
205 all_rec_per_port[block_num];
206 guid_indexes = be64_to_cpu((__force __be64) dev->sriov.alias_guid.
207 ports_guid[port_num - 1].
208 all_rec_per_port[block_num].guid_indexes);
209 pr_debug("port: %d, guid_indexes: 0x%llx\n", port_num, guid_indexes);
210
211
212 for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
213
214 if (!(test_bit(i + 4, (unsigned long *)&guid_indexes)))
215 continue;
216
217 slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ;
218 if (slave_id >= dev->dev->persist->num_vfs + 1)
219 return;
220
221 slave_port = mlx4_phys_to_slave_port(dev->dev, slave_id, port_num);
222 if (slave_port < 0)
223 continue;
224
225 tmp_cur_ag = *(__be64 *)&p_data[i * GUID_REC_SIZE];
226 form_cache_ag = get_cached_alias_guid(dev, port_num,
227 (NUM_ALIAS_GUID_IN_REC * block_num) + i);
228
229
230
231
232
233 if (tmp_cur_ag != form_cache_ag)
234 continue;
235
236 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
237 required_value = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE];
238
239 if (required_value == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
240 required_value = 0;
241
242 if (tmp_cur_ag == required_value) {
243 rec->guid_indexes = rec->guid_indexes &
244 ~mlx4_ib_get_aguid_comp_mask_from_ix(i);
245 } else {
246
247 if (tmp_cur_ag != MLX4_NOT_SET_GUID) {
248 spin_unlock_irqrestore(&dev->sriov.
249 alias_guid.ag_work_lock, flags);
250 continue;
251 }
252 }
253 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock,
254 flags);
255 mlx4_gen_guid_change_eqe(dev->dev, slave_id, port_num);
256
257
258 if (tmp_cur_ag != MLX4_NOT_SET_GUID) {
259 prev_state = mlx4_get_slave_port_state(dev->dev, slave_id, port_num);
260 new_state = set_and_calc_slave_port_state(dev->dev, slave_id, port_num,
261 MLX4_PORT_STATE_IB_PORT_STATE_EVENT_GID_VALID,
262 &gen_event);
263 pr_debug("slave: %d, port: %d prev_port_state: %d,"
264 " new_port_state: %d, gen_event: %d\n",
265 slave_id, port_num, prev_state, new_state, gen_event);
266 if (gen_event == SLAVE_PORT_GEN_EVENT_UP) {
267 pr_debug("sending PORT_UP event to slave: %d, port: %d\n",
268 slave_id, port_num);
269 mlx4_gen_port_state_change_eqe(dev->dev, slave_id,
270 port_num, MLX4_PORT_CHANGE_SUBTYPE_ACTIVE);
271 }
272 } else {
273 set_and_calc_slave_port_state(dev->dev, slave_id, port_num,
274 MLX4_PORT_STATE_IB_EVENT_GID_INVALID,
275 &gen_event);
276 if (gen_event == SLAVE_PORT_GEN_EVENT_DOWN) {
277 pr_debug("sending PORT DOWN event to slave: %d, port: %d\n",
278 slave_id, port_num);
279 mlx4_gen_port_state_change_eqe(dev->dev,
280 slave_id,
281 port_num,
282 MLX4_PORT_CHANGE_SUBTYPE_DOWN);
283 }
284 }
285 }
286}
287
288static void aliasguid_query_handler(int status,
289 struct ib_sa_guidinfo_rec *guid_rec,
290 void *context)
291{
292 struct mlx4_ib_dev *dev;
293 struct mlx4_alias_guid_work_context *cb_ctx = context;
294 u8 port_index ;
295 int i;
296 struct mlx4_sriov_alias_guid_info_rec_det *rec;
297 unsigned long flags, flags1;
298 ib_sa_comp_mask declined_guid_indexes = 0;
299 ib_sa_comp_mask applied_guid_indexes = 0;
300 unsigned int resched_delay_sec = 0;
301
302 if (!context)
303 return;
304
305 dev = cb_ctx->dev;
306 port_index = cb_ctx->port - 1;
307 rec = &dev->sriov.alias_guid.ports_guid[port_index].
308 all_rec_per_port[cb_ctx->block_num];
309
310 if (status) {
311 pr_debug("(port: %d) failed: status = %d\n",
312 cb_ctx->port, status);
313 rec->time_to_run = ktime_get_boot_ns() + 1 * NSEC_PER_SEC;
314 goto out;
315 }
316
317 if (guid_rec->block_num != cb_ctx->block_num) {
318 pr_err("block num mismatch: %d != %d\n",
319 cb_ctx->block_num, guid_rec->block_num);
320 goto out;
321 }
322
323 pr_debug("lid/port: %d/%d, block_num: %d\n",
324 be16_to_cpu(guid_rec->lid), cb_ctx->port,
325 guid_rec->block_num);
326
327 rec = &dev->sriov.alias_guid.ports_guid[port_index].
328 all_rec_per_port[guid_rec->block_num];
329
330 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
331 for (i = 0 ; i < NUM_ALIAS_GUID_IN_REC; i++) {
332 __be64 sm_response, required_val;
333
334 if (!(cb_ctx->guid_indexes &
335 mlx4_ib_get_aguid_comp_mask_from_ix(i)))
336 continue;
337 sm_response = *(__be64 *)&guid_rec->guid_info_list
338 [i * GUID_REC_SIZE];
339 required_val = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE];
340 if (cb_ctx->method == MLX4_GUID_INFO_RECORD_DELETE) {
341 if (required_val ==
342 cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
343 goto next_entry;
344
345
346 pr_debug("need to set new value %llx, record num %d, block_num:%d\n",
347 be64_to_cpu(required_val),
348 i, guid_rec->block_num);
349 goto entry_declined;
350 }
351
352
353
354
355 if (sm_response == MLX4_NOT_SET_GUID) {
356 if (rec->guids_retry_schedule[i] == 0)
357 mlx4_ib_warn(&dev->ib_dev,
358 "%s:Record num %d in block_num: %d was declined by SM\n",
359 __func__, i,
360 guid_rec->block_num);
361 goto entry_declined;
362 } else {
363
364
365
366
367 if (required_val &&
368 sm_response != required_val) {
369
370 if (rec->guids_retry_schedule[i] == 0)
371 mlx4_ib_warn(&dev->ib_dev, "%s: Failed to set"
372 " admin guid after SysAdmin "
373 "configuration. "
374 "Record num %d in block_num:%d "
375 "was declined by SM, "
376 "new val(0x%llx) was kept, SM returned (0x%llx)\n",
377 __func__, i,
378 guid_rec->block_num,
379 be64_to_cpu(required_val),
380 be64_to_cpu(sm_response));
381 goto entry_declined;
382 } else {
383 *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] =
384 sm_response;
385 if (required_val == 0)
386 mlx4_set_admin_guid(dev->dev,
387 sm_response,
388 (guid_rec->block_num
389 * NUM_ALIAS_GUID_IN_REC) + i,
390 cb_ctx->port);
391 goto next_entry;
392 }
393 }
394entry_declined:
395 declined_guid_indexes |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
396 rec->guids_retry_schedule[i] =
397 (rec->guids_retry_schedule[i] == 0) ? 1 :
398 min((unsigned int)60,
399 rec->guids_retry_schedule[i] * 2);
400
401 resched_delay_sec = (resched_delay_sec == 0) ?
402 rec->guids_retry_schedule[i] :
403 min(resched_delay_sec,
404 rec->guids_retry_schedule[i]);
405 continue;
406
407next_entry:
408 rec->guids_retry_schedule[i] = 0;
409 }
410
411 applied_guid_indexes = cb_ctx->guid_indexes & ~declined_guid_indexes;
412 if (declined_guid_indexes ||
413 rec->guid_indexes & ~(applied_guid_indexes)) {
414 pr_debug("record=%d wasn't fully set, guid_indexes=0x%llx applied_indexes=0x%llx, declined_indexes=0x%llx\n",
415 guid_rec->block_num,
416 be64_to_cpu((__force __be64)rec->guid_indexes),
417 be64_to_cpu((__force __be64)applied_guid_indexes),
418 be64_to_cpu((__force __be64)declined_guid_indexes));
419 rec->time_to_run = ktime_get_boot_ns() +
420 resched_delay_sec * NSEC_PER_SEC;
421 } else {
422 rec->status = MLX4_GUID_INFO_STATUS_SET;
423 }
424 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
425
426
427
428
429
430 mlx4_ib_notify_slaves_on_guid_change(dev, guid_rec->block_num,
431 cb_ctx->port,
432 guid_rec->guid_info_list);
433out:
434 spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
435 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
436 if (!dev->sriov.is_going_down) {
437 get_low_record_time_index(dev, port_index, &resched_delay_sec);
438 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port_index].wq,
439 &dev->sriov.alias_guid.ports_guid[port_index].
440 alias_guid_work,
441 msecs_to_jiffies(resched_delay_sec * 1000));
442 }
443 if (cb_ctx->sa_query) {
444 list_del(&cb_ctx->list);
445 kfree(cb_ctx);
446 } else
447 complete(&cb_ctx->done);
448 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
449 spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
450}
451
452static void invalidate_guid_record(struct mlx4_ib_dev *dev, u8 port, int index)
453{
454 int i;
455 u64 cur_admin_val;
456 ib_sa_comp_mask comp_mask = 0;
457
458 dev->sriov.alias_guid.ports_guid[port - 1].all_rec_per_port[index].status
459 = MLX4_GUID_INFO_STATUS_SET;
460
461
462 for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
463 cur_admin_val =
464 *(u64 *)&dev->sriov.alias_guid.ports_guid[port - 1].
465 all_rec_per_port[index].all_recs[GUID_REC_SIZE * i];
466
467
468
469
470
471
472 if (MLX4_GUID_FOR_DELETE_VAL == cur_admin_val ||
473 (!index && !i))
474 continue;
475 comp_mask |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
476 }
477 dev->sriov.alias_guid.ports_guid[port - 1].
478 all_rec_per_port[index].guid_indexes |= comp_mask;
479 if (dev->sriov.alias_guid.ports_guid[port - 1].
480 all_rec_per_port[index].guid_indexes)
481 dev->sriov.alias_guid.ports_guid[port - 1].
482 all_rec_per_port[index].status = MLX4_GUID_INFO_STATUS_IDLE;
483
484}
485
486static int set_guid_rec(struct ib_device *ibdev,
487 struct mlx4_next_alias_guid_work *rec)
488{
489 int err;
490 struct mlx4_ib_dev *dev = to_mdev(ibdev);
491 struct ib_sa_guidinfo_rec guid_info_rec;
492 ib_sa_comp_mask comp_mask;
493 struct ib_port_attr attr;
494 struct mlx4_alias_guid_work_context *callback_context;
495 unsigned long resched_delay, flags, flags1;
496 u8 port = rec->port + 1;
497 int index = rec->block_num;
498 struct mlx4_sriov_alias_guid_info_rec_det *rec_det = &rec->rec_det;
499 struct list_head *head =
500 &dev->sriov.alias_guid.ports_guid[port - 1].cb_list;
501
502 err = __mlx4_ib_query_port(ibdev, port, &attr, 1);
503 if (err) {
504 pr_debug("mlx4_ib_query_port failed (err: %d), port: %d\n",
505 err, port);
506 return err;
507 }
508
509 if (attr.state != IB_PORT_ACTIVE) {
510 pr_debug("port %d not active...rescheduling\n", port);
511 resched_delay = 5 * HZ;
512 err = -EAGAIN;
513 goto new_schedule;
514 }
515
516 callback_context = kmalloc(sizeof *callback_context, GFP_KERNEL);
517 if (!callback_context) {
518 err = -ENOMEM;
519 resched_delay = HZ * 5;
520 goto new_schedule;
521 }
522 callback_context->port = port;
523 callback_context->dev = dev;
524 callback_context->block_num = index;
525 callback_context->guid_indexes = rec_det->guid_indexes;
526 callback_context->method = rec->method;
527
528 memset(&guid_info_rec, 0, sizeof (struct ib_sa_guidinfo_rec));
529
530 guid_info_rec.lid = cpu_to_be16(attr.lid);
531 guid_info_rec.block_num = index;
532
533 memcpy(guid_info_rec.guid_info_list, rec_det->all_recs,
534 GUID_REC_SIZE * NUM_ALIAS_GUID_IN_REC);
535 comp_mask = IB_SA_GUIDINFO_REC_LID | IB_SA_GUIDINFO_REC_BLOCK_NUM |
536 rec_det->guid_indexes;
537
538 init_completion(&callback_context->done);
539 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
540 list_add_tail(&callback_context->list, head);
541 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
542
543 callback_context->query_id =
544 ib_sa_guid_info_rec_query(dev->sriov.alias_guid.sa_client,
545 ibdev, port, &guid_info_rec,
546 comp_mask, rec->method, 1000,
547 GFP_KERNEL, aliasguid_query_handler,
548 callback_context,
549 &callback_context->sa_query);
550 if (callback_context->query_id < 0) {
551 pr_debug("ib_sa_guid_info_rec_query failed, query_id: "
552 "%d. will reschedule to the next 1 sec.\n",
553 callback_context->query_id);
554 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
555 list_del(&callback_context->list);
556 kfree(callback_context);
557 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
558 resched_delay = 1 * HZ;
559 err = -EAGAIN;
560 goto new_schedule;
561 }
562 err = 0;
563 goto out;
564
565new_schedule:
566 spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
567 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
568 invalidate_guid_record(dev, port, index);
569 if (!dev->sriov.is_going_down) {
570 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq,
571 &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work,
572 resched_delay);
573 }
574 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
575 spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
576
577out:
578 return err;
579}
580
581static void mlx4_ib_guid_port_init(struct mlx4_ib_dev *dev, int port)
582{
583 int j, k, entry;
584 __be64 guid;
585
586
587 for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
588 for (k = 0; k < NUM_ALIAS_GUID_IN_REC; k++) {
589 entry = j * NUM_ALIAS_GUID_IN_REC + k;
590
591 if (!entry || entry > dev->dev->persist->num_vfs ||
592 !mlx4_is_slave_active(dev->dev, entry))
593 continue;
594 guid = mlx4_get_admin_guid(dev->dev, entry, port);
595 *(__be64 *)&dev->sriov.alias_guid.ports_guid[port - 1].
596 all_rec_per_port[j].all_recs
597 [GUID_REC_SIZE * k] = guid;
598 pr_debug("guid was set, entry=%d, val=0x%llx, port=%d\n",
599 entry,
600 be64_to_cpu(guid),
601 port);
602 }
603 }
604}
605void mlx4_ib_invalidate_all_guid_record(struct mlx4_ib_dev *dev, int port)
606{
607 int i;
608 unsigned long flags, flags1;
609
610 pr_debug("port %d\n", port);
611
612 spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
613 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
614
615 if (dev->sriov.alias_guid.ports_guid[port - 1].state_flags &
616 GUID_STATE_NEED_PORT_INIT) {
617 mlx4_ib_guid_port_init(dev, port);
618 dev->sriov.alias_guid.ports_guid[port - 1].state_flags &=
619 (~GUID_STATE_NEED_PORT_INIT);
620 }
621 for (i = 0; i < NUM_ALIAS_GUID_REC_IN_PORT; i++)
622 invalidate_guid_record(dev, port, i);
623
624 if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) {
625
626
627
628
629
630 cancel_delayed_work(&dev->sriov.alias_guid.
631 ports_guid[port - 1].alias_guid_work);
632 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq,
633 &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work,
634 0);
635 }
636 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
637 spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
638}
639
640static void set_required_record(struct mlx4_ib_dev *dev, u8 port,
641 struct mlx4_next_alias_guid_work *next_rec,
642 int record_index)
643{
644 int i;
645 int lowset_time_entry = -1;
646 int lowest_time = 0;
647 ib_sa_comp_mask delete_guid_indexes = 0;
648 ib_sa_comp_mask set_guid_indexes = 0;
649 struct mlx4_sriov_alias_guid_info_rec_det *rec =
650 &dev->sriov.alias_guid.ports_guid[port].
651 all_rec_per_port[record_index];
652
653 for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
654 if (!(rec->guid_indexes &
655 mlx4_ib_get_aguid_comp_mask_from_ix(i)))
656 continue;
657
658 if (*(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] ==
659 cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
660 delete_guid_indexes |=
661 mlx4_ib_get_aguid_comp_mask_from_ix(i);
662 else
663 set_guid_indexes |=
664 mlx4_ib_get_aguid_comp_mask_from_ix(i);
665
666 if (lowset_time_entry == -1 || rec->guids_retry_schedule[i] <=
667 lowest_time) {
668 lowset_time_entry = i;
669 lowest_time = rec->guids_retry_schedule[i];
670 }
671 }
672
673 memcpy(&next_rec->rec_det, rec, sizeof(*rec));
674 next_rec->port = port;
675 next_rec->block_num = record_index;
676
677 if (*(__be64 *)&rec->all_recs[lowset_time_entry * GUID_REC_SIZE] ==
678 cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) {
679 next_rec->rec_det.guid_indexes = delete_guid_indexes;
680 next_rec->method = MLX4_GUID_INFO_RECORD_DELETE;
681 } else {
682 next_rec->rec_det.guid_indexes = set_guid_indexes;
683 next_rec->method = MLX4_GUID_INFO_RECORD_SET;
684 }
685}
686
687
688
689
690static int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port,
691 int *resched_delay_sec)
692{
693 int record_index = -1;
694 u64 low_record_time = 0;
695 struct mlx4_sriov_alias_guid_info_rec_det rec;
696 int j;
697
698 for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
699 rec = dev->sriov.alias_guid.ports_guid[port].
700 all_rec_per_port[j];
701 if (rec.status == MLX4_GUID_INFO_STATUS_IDLE &&
702 rec.guid_indexes) {
703 if (record_index == -1 ||
704 rec.time_to_run < low_record_time) {
705 record_index = j;
706 low_record_time = rec.time_to_run;
707 }
708 }
709 }
710 if (resched_delay_sec) {
711 u64 curr_time = ktime_get_boot_ns();
712
713 *resched_delay_sec = (low_record_time < curr_time) ? 0 :
714 div_u64((low_record_time - curr_time), NSEC_PER_SEC);
715 }
716
717 return record_index;
718}
719
720
721
722static int get_next_record_to_update(struct mlx4_ib_dev *dev, u8 port,
723 struct mlx4_next_alias_guid_work *rec)
724{
725 unsigned long flags;
726 int record_index;
727 int ret = 0;
728
729 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
730 record_index = get_low_record_time_index(dev, port, NULL);
731
732 if (record_index < 0) {
733 ret = -ENOENT;
734 goto out;
735 }
736
737 set_required_record(dev, port, rec, record_index);
738out:
739 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
740 return ret;
741}
742
743static void alias_guid_work(struct work_struct *work)
744{
745 struct delayed_work *delay = to_delayed_work(work);
746 int ret = 0;
747 struct mlx4_next_alias_guid_work *rec;
748 struct mlx4_sriov_alias_guid_port_rec_det *sriov_alias_port =
749 container_of(delay, struct mlx4_sriov_alias_guid_port_rec_det,
750 alias_guid_work);
751 struct mlx4_sriov_alias_guid *sriov_alias_guid = sriov_alias_port->parent;
752 struct mlx4_ib_sriov *ib_sriov = container_of(sriov_alias_guid,
753 struct mlx4_ib_sriov,
754 alias_guid);
755 struct mlx4_ib_dev *dev = container_of(ib_sriov, struct mlx4_ib_dev, sriov);
756
757 rec = kzalloc(sizeof *rec, GFP_KERNEL);
758 if (!rec)
759 return;
760
761 pr_debug("starting [port: %d]...\n", sriov_alias_port->port + 1);
762 ret = get_next_record_to_update(dev, sriov_alias_port->port, rec);
763 if (ret) {
764 pr_debug("No more records to update.\n");
765 goto out;
766 }
767
768 set_guid_rec(&dev->ib_dev, rec);
769out:
770 kfree(rec);
771}
772
773
774void mlx4_ib_init_alias_guid_work(struct mlx4_ib_dev *dev, int port)
775{
776 unsigned long flags, flags1;
777
778 if (!mlx4_is_master(dev->dev))
779 return;
780 spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
781 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
782 if (!dev->sriov.is_going_down) {
783
784
785
786
787 cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[port].
788 alias_guid_work);
789 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port].wq,
790 &dev->sriov.alias_guid.ports_guid[port].alias_guid_work, 0);
791 }
792 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
793 spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
794}
795
796void mlx4_ib_destroy_alias_guid_service(struct mlx4_ib_dev *dev)
797{
798 int i;
799 struct mlx4_ib_sriov *sriov = &dev->sriov;
800 struct mlx4_alias_guid_work_context *cb_ctx;
801 struct mlx4_sriov_alias_guid_port_rec_det *det;
802 struct ib_sa_query *sa_query;
803 unsigned long flags;
804
805 for (i = 0 ; i < dev->num_ports; i++) {
806 cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work);
807 det = &sriov->alias_guid.ports_guid[i];
808 spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags);
809 while (!list_empty(&det->cb_list)) {
810 cb_ctx = list_entry(det->cb_list.next,
811 struct mlx4_alias_guid_work_context,
812 list);
813 sa_query = cb_ctx->sa_query;
814 cb_ctx->sa_query = NULL;
815 list_del(&cb_ctx->list);
816 spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags);
817 ib_sa_cancel_query(cb_ctx->query_id, sa_query);
818 wait_for_completion(&cb_ctx->done);
819 kfree(cb_ctx);
820 spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags);
821 }
822 spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags);
823 }
824 for (i = 0 ; i < dev->num_ports; i++) {
825 flush_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
826 destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
827 }
828 ib_sa_unregister_client(dev->sriov.alias_guid.sa_client);
829 kfree(dev->sriov.alias_guid.sa_client);
830}
831
832int mlx4_ib_init_alias_guid_service(struct mlx4_ib_dev *dev)
833{
834 char alias_wq_name[15];
835 int ret = 0;
836 int i, j;
837 union ib_gid gid;
838
839 if (!mlx4_is_master(dev->dev))
840 return 0;
841 dev->sriov.alias_guid.sa_client =
842 kzalloc(sizeof *dev->sriov.alias_guid.sa_client, GFP_KERNEL);
843 if (!dev->sriov.alias_guid.sa_client)
844 return -ENOMEM;
845
846 ib_sa_register_client(dev->sriov.alias_guid.sa_client);
847
848 spin_lock_init(&dev->sriov.alias_guid.ag_work_lock);
849
850 for (i = 1; i <= dev->num_ports; ++i) {
851 if (dev->ib_dev.query_gid(&dev->ib_dev , i, 0, &gid)) {
852 ret = -EFAULT;
853 goto err_unregister;
854 }
855 }
856
857 for (i = 0 ; i < dev->num_ports; i++) {
858 memset(&dev->sriov.alias_guid.ports_guid[i], 0,
859 sizeof (struct mlx4_sriov_alias_guid_port_rec_det));
860 dev->sriov.alias_guid.ports_guid[i].state_flags |=
861 GUID_STATE_NEED_PORT_INIT;
862 for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
863
864 memset(dev->sriov.alias_guid.ports_guid[i].
865 all_rec_per_port[j].all_recs, 0xFF,
866 sizeof(dev->sriov.alias_guid.ports_guid[i].
867 all_rec_per_port[j].all_recs));
868 }
869 INIT_LIST_HEAD(&dev->sriov.alias_guid.ports_guid[i].cb_list);
870
871 if (mlx4_ib_sm_guid_assign)
872 for (j = 1; j < NUM_ALIAS_GUID_PER_PORT; j++)
873 mlx4_set_admin_guid(dev->dev, 0, j, i + 1);
874 for (j = 0 ; j < NUM_ALIAS_GUID_REC_IN_PORT; j++)
875 invalidate_guid_record(dev, i + 1, j);
876
877 dev->sriov.alias_guid.ports_guid[i].parent = &dev->sriov.alias_guid;
878 dev->sriov.alias_guid.ports_guid[i].port = i;
879
880 snprintf(alias_wq_name, sizeof alias_wq_name, "alias_guid%d", i);
881 dev->sriov.alias_guid.ports_guid[i].wq =
882 alloc_ordered_workqueue(alias_wq_name, WQ_MEM_RECLAIM);
883 if (!dev->sriov.alias_guid.ports_guid[i].wq) {
884 ret = -ENOMEM;
885 goto err_thread;
886 }
887 INIT_DELAYED_WORK(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work,
888 alias_guid_work);
889 }
890 return 0;
891
892err_thread:
893 for (--i; i >= 0; i--) {
894 destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
895 dev->sriov.alias_guid.ports_guid[i].wq = NULL;
896 }
897
898err_unregister:
899 ib_sa_unregister_client(dev->sriov.alias_guid.sa_client);
900 kfree(dev->sriov.alias_guid.sa_client);
901 dev->sriov.alias_guid.sa_client = NULL;
902 pr_err("init_alias_guid_service: Failed. (ret:%d)\n", ret);
903 return ret;
904}
905