IB/mlx4: Change init flow to request alias GUIDs for active VFs
[deliverable/linux.git] / drivers / infiniband / hw / mlx4 / alias_GUID.c
1 /*
2 * Copyright (c) 2012 Mellanox Technologies. All rights reserved.
3 *
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
9 *
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions are met:
13 *
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 */
32 /***********************************************************/
33 /*This file support the handling of the Alias GUID feature. */
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 The driver keeps the current state of all guids, as they are in the HW.
50 Whenever we receive an smp mad GUIDInfo record, the data will be cached.
51 */
52
53 struct 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
65 struct 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
72 static int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port,
73 int *resched_delay_sec);
74
75 void 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 /* The location of the specific index starts from bit number 4
93 * until bit num 11 */
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 /* cache the guid: */
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
111 static __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
121 ib_sa_comp_mask mlx4_ib_get_aguid_comp_mask_from_ix(int index)
122 {
123 return IB_SA_COMP_MASK(4 + index);
124 }
125
126 /*
127 * Whenever new GUID is set/unset (guid table change) create event and
128 * notify the relevant slave (master also should be notified).
129 * If the GUID value is not as we have in the cache the slave will not be
130 * updated; in this case it waits for the smp_snoop or the port management
131 * event to call the function and to update the slave.
132 * block_number - the index of the block (16 blocks available)
133 * port_number - 1 or 2
134 */
135 void mlx4_ib_notify_slaves_on_guid_change(struct mlx4_ib_dev *dev,
136 int block_num, u8 port_num,
137 u8 *p_data)
138 {
139 int i;
140 u64 guid_indexes;
141 int slave_id;
142 enum slave_port_state new_state;
143 enum slave_port_state prev_state;
144 __be64 tmp_cur_ag, form_cache_ag;
145 enum slave_port_gen_event gen_event;
146 struct mlx4_sriov_alias_guid_info_rec_det *rec;
147 unsigned long flags;
148 __be64 required_value;
149
150 if (!mlx4_is_master(dev->dev))
151 return;
152
153 rec = &dev->sriov.alias_guid.ports_guid[port_num - 1].
154 all_rec_per_port[block_num];
155 guid_indexes = be64_to_cpu((__force __be64) dev->sriov.alias_guid.
156 ports_guid[port_num - 1].
157 all_rec_per_port[block_num].guid_indexes);
158 pr_debug("port: %d, guid_indexes: 0x%llx\n", port_num, guid_indexes);
159
160 /*calculate the slaves and notify them*/
161 for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
162 /* the location of the specific index runs from bits 4..11 */
163 if (!(test_bit(i + 4, (unsigned long *)&guid_indexes)))
164 continue;
165
166 slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ;
167 if (slave_id >= dev->dev->persist->num_vfs + 1)
168 return;
169 tmp_cur_ag = *(__be64 *)&p_data[i * GUID_REC_SIZE];
170 form_cache_ag = get_cached_alias_guid(dev, port_num,
171 (NUM_ALIAS_GUID_IN_REC * block_num) + i);
172 /*
173 * Check if guid is not the same as in the cache,
174 * If it is different, wait for the snoop_smp or the port mgmt
175 * change event to update the slave on its port state change
176 */
177 if (tmp_cur_ag != form_cache_ag)
178 continue;
179
180 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
181 required_value = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE];
182
183 if (required_value == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
184 required_value = 0;
185
186 if (tmp_cur_ag == required_value) {
187 rec->guid_indexes = rec->guid_indexes &
188 ~mlx4_ib_get_aguid_comp_mask_from_ix(i);
189 } else {
190 /* may notify port down if value is 0 */
191 if (tmp_cur_ag != MLX4_NOT_SET_GUID) {
192 spin_unlock_irqrestore(&dev->sriov.
193 alias_guid.ag_work_lock, flags);
194 continue;
195 }
196 }
197 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock,
198 flags);
199 mlx4_gen_guid_change_eqe(dev->dev, slave_id, port_num);
200 /*2 cases: Valid GUID, and Invalid Guid*/
201
202 if (tmp_cur_ag != MLX4_NOT_SET_GUID) { /*valid GUID*/
203 prev_state = mlx4_get_slave_port_state(dev->dev, slave_id, port_num);
204 new_state = set_and_calc_slave_port_state(dev->dev, slave_id, port_num,
205 MLX4_PORT_STATE_IB_PORT_STATE_EVENT_GID_VALID,
206 &gen_event);
207 pr_debug("slave: %d, port: %d prev_port_state: %d,"
208 " new_port_state: %d, gen_event: %d\n",
209 slave_id, port_num, prev_state, new_state, gen_event);
210 if (gen_event == SLAVE_PORT_GEN_EVENT_UP) {
211 pr_debug("sending PORT_UP event to slave: %d, port: %d\n",
212 slave_id, port_num);
213 mlx4_gen_port_state_change_eqe(dev->dev, slave_id,
214 port_num, MLX4_PORT_CHANGE_SUBTYPE_ACTIVE);
215 }
216 } else { /* request to invalidate GUID */
217 set_and_calc_slave_port_state(dev->dev, slave_id, port_num,
218 MLX4_PORT_STATE_IB_EVENT_GID_INVALID,
219 &gen_event);
220 if (gen_event == SLAVE_PORT_GEN_EVENT_DOWN) {
221 pr_debug("sending PORT DOWN event to slave: %d, port: %d\n",
222 slave_id, port_num);
223 mlx4_gen_port_state_change_eqe(dev->dev,
224 slave_id,
225 port_num,
226 MLX4_PORT_CHANGE_SUBTYPE_DOWN);
227 }
228 }
229 }
230 }
231
232 static void aliasguid_query_handler(int status,
233 struct ib_sa_guidinfo_rec *guid_rec,
234 void *context)
235 {
236 struct mlx4_ib_dev *dev;
237 struct mlx4_alias_guid_work_context *cb_ctx = context;
238 u8 port_index ;
239 int i;
240 struct mlx4_sriov_alias_guid_info_rec_det *rec;
241 unsigned long flags, flags1;
242 ib_sa_comp_mask declined_guid_indexes = 0;
243 ib_sa_comp_mask applied_guid_indexes = 0;
244 unsigned int resched_delay_sec = 0;
245
246 if (!context)
247 return;
248
249 dev = cb_ctx->dev;
250 port_index = cb_ctx->port - 1;
251 rec = &dev->sriov.alias_guid.ports_guid[port_index].
252 all_rec_per_port[cb_ctx->block_num];
253
254 if (status) {
255 pr_debug("(port: %d) failed: status = %d\n",
256 cb_ctx->port, status);
257 rec->time_to_run = ktime_get_real_ns() + 1 * NSEC_PER_SEC;
258 goto out;
259 }
260
261 if (guid_rec->block_num != cb_ctx->block_num) {
262 pr_err("block num mismatch: %d != %d\n",
263 cb_ctx->block_num, guid_rec->block_num);
264 goto out;
265 }
266
267 pr_debug("lid/port: %d/%d, block_num: %d\n",
268 be16_to_cpu(guid_rec->lid), cb_ctx->port,
269 guid_rec->block_num);
270
271 rec = &dev->sriov.alias_guid.ports_guid[port_index].
272 all_rec_per_port[guid_rec->block_num];
273
274 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
275 for (i = 0 ; i < NUM_ALIAS_GUID_IN_REC; i++) {
276 __be64 sm_response, required_val;
277
278 if (!(cb_ctx->guid_indexes &
279 mlx4_ib_get_aguid_comp_mask_from_ix(i)))
280 continue;
281 sm_response = *(__be64 *)&guid_rec->guid_info_list
282 [i * GUID_REC_SIZE];
283 required_val = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE];
284 if (cb_ctx->method == MLX4_GUID_INFO_RECORD_DELETE) {
285 if (required_val ==
286 cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
287 goto next_entry;
288
289 /* A new value was set till we got the response */
290 pr_debug("need to set new value %llx, record num %d, block_num:%d\n",
291 be64_to_cpu(required_val),
292 i, guid_rec->block_num);
293 goto entry_declined;
294 }
295
296 /* check if the SM didn't assign one of the records.
297 * if it didn't, re-ask for.
298 */
299 if (sm_response == MLX4_NOT_SET_GUID) {
300 if (rec->guids_retry_schedule[i] == 0)
301 mlx4_ib_warn(&dev->ib_dev,
302 "%s:Record num %d in block_num: %d was declined by SM\n",
303 __func__, i,
304 guid_rec->block_num);
305 goto entry_declined;
306 } else {
307 /* properly assigned record. */
308 /* We save the GUID we just got from the SM in the
309 * admin_guid in order to be persistent, and in the
310 * request from the sm the process will ask for the same GUID */
311 if (required_val &&
312 sm_response != required_val) {
313 /* Warn only on first retry */
314 if (rec->guids_retry_schedule[i] == 0)
315 mlx4_ib_warn(&dev->ib_dev, "%s: Failed to set"
316 " admin guid after SysAdmin "
317 "configuration. "
318 "Record num %d in block_num:%d "
319 "was declined by SM, "
320 "new val(0x%llx) was kept, SM returned (0x%llx)\n",
321 __func__, i,
322 guid_rec->block_num,
323 be64_to_cpu(required_val),
324 be64_to_cpu(sm_response));
325 goto entry_declined;
326 } else {
327 *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] =
328 sm_response;
329 if (required_val == 0)
330 mlx4_set_admin_guid(dev->dev,
331 sm_response,
332 (guid_rec->block_num
333 * NUM_ALIAS_GUID_IN_REC) + i,
334 cb_ctx->port);
335 goto next_entry;
336 }
337 }
338 entry_declined:
339 declined_guid_indexes |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
340 rec->guids_retry_schedule[i] =
341 (rec->guids_retry_schedule[i] == 0) ? 1 :
342 min((unsigned int)60,
343 rec->guids_retry_schedule[i] * 2);
344 /* using the minimum value among all entries in that record */
345 resched_delay_sec = (resched_delay_sec == 0) ?
346 rec->guids_retry_schedule[i] :
347 min(resched_delay_sec,
348 rec->guids_retry_schedule[i]);
349 continue;
350
351 next_entry:
352 rec->guids_retry_schedule[i] = 0;
353 }
354
355 applied_guid_indexes = cb_ctx->guid_indexes & ~declined_guid_indexes;
356 if (declined_guid_indexes ||
357 rec->guid_indexes & ~(applied_guid_indexes)) {
358 pr_debug("record=%d wasn't fully set, guid_indexes=0x%llx applied_indexes=0x%llx, declined_indexes=0x%llx\n",
359 guid_rec->block_num,
360 be64_to_cpu((__force __be64)rec->guid_indexes),
361 be64_to_cpu((__force __be64)applied_guid_indexes),
362 be64_to_cpu((__force __be64)declined_guid_indexes));
363 rec->time_to_run = ktime_get_real_ns() +
364 resched_delay_sec * NSEC_PER_SEC;
365 } else {
366 rec->status = MLX4_GUID_INFO_STATUS_SET;
367 }
368 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
369 /*
370 The func is call here to close the cases when the
371 sm doesn't send smp, so in the sa response the driver
372 notifies the slave.
373 */
374 mlx4_ib_notify_slaves_on_guid_change(dev, guid_rec->block_num,
375 cb_ctx->port,
376 guid_rec->guid_info_list);
377 out:
378 spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
379 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
380 if (!dev->sriov.is_going_down) {
381 get_low_record_time_index(dev, port_index, &resched_delay_sec);
382 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port_index].wq,
383 &dev->sriov.alias_guid.ports_guid[port_index].
384 alias_guid_work,
385 msecs_to_jiffies(resched_delay_sec * 1000));
386 }
387 if (cb_ctx->sa_query) {
388 list_del(&cb_ctx->list);
389 kfree(cb_ctx);
390 } else
391 complete(&cb_ctx->done);
392 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
393 spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
394 }
395
396 static void invalidate_guid_record(struct mlx4_ib_dev *dev, u8 port, int index)
397 {
398 int i;
399 u64 cur_admin_val;
400 ib_sa_comp_mask comp_mask = 0;
401
402 dev->sriov.alias_guid.ports_guid[port - 1].all_rec_per_port[index].status
403 = MLX4_GUID_INFO_STATUS_SET;
404
405 /* calculate the comp_mask for that record.*/
406 for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
407 cur_admin_val =
408 *(u64 *)&dev->sriov.alias_guid.ports_guid[port - 1].
409 all_rec_per_port[index].all_recs[GUID_REC_SIZE * i];
410 /*
411 check the admin value: if it's for delete (~00LL) or
412 it is the first guid of the first record (hw guid) or
413 the records is not in ownership of the sysadmin and the sm doesn't
414 need to assign GUIDs, then don't put it up for assignment.
415 */
416 if (MLX4_GUID_FOR_DELETE_VAL == cur_admin_val ||
417 (!index && !i))
418 continue;
419 comp_mask |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
420 }
421 dev->sriov.alias_guid.ports_guid[port - 1].
422 all_rec_per_port[index].guid_indexes |= comp_mask;
423 if (dev->sriov.alias_guid.ports_guid[port - 1].
424 all_rec_per_port[index].guid_indexes)
425 dev->sriov.alias_guid.ports_guid[port - 1].
426 all_rec_per_port[index].status = MLX4_GUID_INFO_STATUS_IDLE;
427
428 }
429
430 static int set_guid_rec(struct ib_device *ibdev,
431 struct mlx4_next_alias_guid_work *rec)
432 {
433 int err;
434 struct mlx4_ib_dev *dev = to_mdev(ibdev);
435 struct ib_sa_guidinfo_rec guid_info_rec;
436 ib_sa_comp_mask comp_mask;
437 struct ib_port_attr attr;
438 struct mlx4_alias_guid_work_context *callback_context;
439 unsigned long resched_delay, flags, flags1;
440 u8 port = rec->port + 1;
441 int index = rec->block_num;
442 struct mlx4_sriov_alias_guid_info_rec_det *rec_det = &rec->rec_det;
443 struct list_head *head =
444 &dev->sriov.alias_guid.ports_guid[port - 1].cb_list;
445
446 err = __mlx4_ib_query_port(ibdev, port, &attr, 1);
447 if (err) {
448 pr_debug("mlx4_ib_query_port failed (err: %d), port: %d\n",
449 err, port);
450 return err;
451 }
452 /*check the port was configured by the sm, otherwise no need to send */
453 if (attr.state != IB_PORT_ACTIVE) {
454 pr_debug("port %d not active...rescheduling\n", port);
455 resched_delay = 5 * HZ;
456 err = -EAGAIN;
457 goto new_schedule;
458 }
459
460 callback_context = kmalloc(sizeof *callback_context, GFP_KERNEL);
461 if (!callback_context) {
462 err = -ENOMEM;
463 resched_delay = HZ * 5;
464 goto new_schedule;
465 }
466 callback_context->port = port;
467 callback_context->dev = dev;
468 callback_context->block_num = index;
469 callback_context->guid_indexes = rec_det->guid_indexes;
470 callback_context->method = rec->method;
471
472 memset(&guid_info_rec, 0, sizeof (struct ib_sa_guidinfo_rec));
473
474 guid_info_rec.lid = cpu_to_be16(attr.lid);
475 guid_info_rec.block_num = index;
476
477 memcpy(guid_info_rec.guid_info_list, rec_det->all_recs,
478 GUID_REC_SIZE * NUM_ALIAS_GUID_IN_REC);
479 comp_mask = IB_SA_GUIDINFO_REC_LID | IB_SA_GUIDINFO_REC_BLOCK_NUM |
480 rec_det->guid_indexes;
481
482 init_completion(&callback_context->done);
483 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
484 list_add_tail(&callback_context->list, head);
485 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
486
487 callback_context->query_id =
488 ib_sa_guid_info_rec_query(dev->sriov.alias_guid.sa_client,
489 ibdev, port, &guid_info_rec,
490 comp_mask, rec->method, 1000,
491 GFP_KERNEL, aliasguid_query_handler,
492 callback_context,
493 &callback_context->sa_query);
494 if (callback_context->query_id < 0) {
495 pr_debug("ib_sa_guid_info_rec_query failed, query_id: "
496 "%d. will reschedule to the next 1 sec.\n",
497 callback_context->query_id);
498 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
499 list_del(&callback_context->list);
500 kfree(callback_context);
501 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
502 resched_delay = 1 * HZ;
503 err = -EAGAIN;
504 goto new_schedule;
505 }
506 err = 0;
507 goto out;
508
509 new_schedule:
510 spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
511 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
512 invalidate_guid_record(dev, port, index);
513 if (!dev->sriov.is_going_down) {
514 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq,
515 &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work,
516 resched_delay);
517 }
518 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
519 spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
520
521 out:
522 return err;
523 }
524
525 static void mlx4_ib_guid_port_init(struct mlx4_ib_dev *dev, int port)
526 {
527 int j, k, entry;
528 __be64 guid;
529
530 /*Check if the SM doesn't need to assign the GUIDs*/
531 for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
532 for (k = 0; k < NUM_ALIAS_GUID_IN_REC; k++) {
533 entry = j * NUM_ALIAS_GUID_IN_REC + k;
534 /* no request for the 0 entry (hw guid) */
535 if (!entry || entry > dev->dev->persist->num_vfs ||
536 !mlx4_is_slave_active(dev->dev, entry))
537 continue;
538 guid = mlx4_get_admin_guid(dev->dev, entry, port);
539 *(__be64 *)&dev->sriov.alias_guid.ports_guid[port - 1].
540 all_rec_per_port[j].all_recs
541 [GUID_REC_SIZE * k] = guid;
542 pr_debug("guid was set, entry=%d, val=0x%llx, port=%d\n",
543 entry,
544 be64_to_cpu(guid),
545 port);
546 }
547 }
548 }
549 void mlx4_ib_invalidate_all_guid_record(struct mlx4_ib_dev *dev, int port)
550 {
551 int i;
552 unsigned long flags, flags1;
553
554 pr_debug("port %d\n", port);
555
556 spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
557 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
558
559 if (dev->sriov.alias_guid.ports_guid[port - 1].state_flags &
560 GUID_STATE_NEED_PORT_INIT) {
561 mlx4_ib_guid_port_init(dev, port);
562 dev->sriov.alias_guid.ports_guid[port - 1].state_flags &=
563 (~GUID_STATE_NEED_PORT_INIT);
564 }
565 for (i = 0; i < NUM_ALIAS_GUID_REC_IN_PORT; i++)
566 invalidate_guid_record(dev, port, i);
567
568 if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) {
569 /*
570 make sure no work waits in the queue, if the work is already
571 queued(not on the timer) the cancel will fail. That is not a problem
572 because we just want the work started.
573 */
574 cancel_delayed_work(&dev->sriov.alias_guid.
575 ports_guid[port - 1].alias_guid_work);
576 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq,
577 &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work,
578 0);
579 }
580 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
581 spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
582 }
583
584 static void set_required_record(struct mlx4_ib_dev *dev, u8 port,
585 struct mlx4_next_alias_guid_work *next_rec,
586 int record_index)
587 {
588 int i;
589 int lowset_time_entry = -1;
590 int lowest_time = 0;
591 ib_sa_comp_mask delete_guid_indexes = 0;
592 ib_sa_comp_mask set_guid_indexes = 0;
593 struct mlx4_sriov_alias_guid_info_rec_det *rec =
594 &dev->sriov.alias_guid.ports_guid[port].
595 all_rec_per_port[record_index];
596
597 for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
598 if (!(rec->guid_indexes &
599 mlx4_ib_get_aguid_comp_mask_from_ix(i)))
600 continue;
601
602 if (*(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] ==
603 cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
604 delete_guid_indexes |=
605 mlx4_ib_get_aguid_comp_mask_from_ix(i);
606 else
607 set_guid_indexes |=
608 mlx4_ib_get_aguid_comp_mask_from_ix(i);
609
610 if (lowset_time_entry == -1 || rec->guids_retry_schedule[i] <=
611 lowest_time) {
612 lowset_time_entry = i;
613 lowest_time = rec->guids_retry_schedule[i];
614 }
615 }
616
617 memcpy(&next_rec->rec_det, rec, sizeof(*rec));
618 next_rec->port = port;
619 next_rec->block_num = record_index;
620
621 if (*(__be64 *)&rec->all_recs[lowset_time_entry * GUID_REC_SIZE] ==
622 cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) {
623 next_rec->rec_det.guid_indexes = delete_guid_indexes;
624 next_rec->method = MLX4_GUID_INFO_RECORD_DELETE;
625 } else {
626 next_rec->rec_det.guid_indexes = set_guid_indexes;
627 next_rec->method = MLX4_GUID_INFO_RECORD_SET;
628 }
629 }
630
631 /* return index of record that should be updated based on lowest
632 * rescheduled time
633 */
634 static int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port,
635 int *resched_delay_sec)
636 {
637 int record_index = -1;
638 u64 low_record_time = 0;
639 struct mlx4_sriov_alias_guid_info_rec_det rec;
640 int j;
641
642 for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
643 rec = dev->sriov.alias_guid.ports_guid[port].
644 all_rec_per_port[j];
645 if (rec.status == MLX4_GUID_INFO_STATUS_IDLE &&
646 rec.guid_indexes) {
647 if (record_index == -1 ||
648 rec.time_to_run < low_record_time) {
649 record_index = j;
650 low_record_time = rec.time_to_run;
651 }
652 }
653 }
654 if (resched_delay_sec) {
655 u64 curr_time = ktime_get_real_ns();
656
657 *resched_delay_sec = (low_record_time < curr_time) ? 0 :
658 div_u64((low_record_time - curr_time), NSEC_PER_SEC);
659 }
660
661 return record_index;
662 }
663
664 /* The function returns the next record that was
665 * not configured (or failed to be configured) */
666 static int get_next_record_to_update(struct mlx4_ib_dev *dev, u8 port,
667 struct mlx4_next_alias_guid_work *rec)
668 {
669 unsigned long flags;
670 int record_index;
671 int ret = 0;
672
673 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
674 record_index = get_low_record_time_index(dev, port, NULL);
675
676 if (record_index < 0) {
677 ret = -ENOENT;
678 goto out;
679 }
680
681 set_required_record(dev, port, rec, record_index);
682 out:
683 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
684 return ret;
685 }
686
687 static void alias_guid_work(struct work_struct *work)
688 {
689 struct delayed_work *delay = to_delayed_work(work);
690 int ret = 0;
691 struct mlx4_next_alias_guid_work *rec;
692 struct mlx4_sriov_alias_guid_port_rec_det *sriov_alias_port =
693 container_of(delay, struct mlx4_sriov_alias_guid_port_rec_det,
694 alias_guid_work);
695 struct mlx4_sriov_alias_guid *sriov_alias_guid = sriov_alias_port->parent;
696 struct mlx4_ib_sriov *ib_sriov = container_of(sriov_alias_guid,
697 struct mlx4_ib_sriov,
698 alias_guid);
699 struct mlx4_ib_dev *dev = container_of(ib_sriov, struct mlx4_ib_dev, sriov);
700
701 rec = kzalloc(sizeof *rec, GFP_KERNEL);
702 if (!rec) {
703 pr_err("alias_guid_work: No Memory\n");
704 return;
705 }
706
707 pr_debug("starting [port: %d]...\n", sriov_alias_port->port + 1);
708 ret = get_next_record_to_update(dev, sriov_alias_port->port, rec);
709 if (ret) {
710 pr_debug("No more records to update.\n");
711 goto out;
712 }
713
714 set_guid_rec(&dev->ib_dev, rec);
715 out:
716 kfree(rec);
717 }
718
719
720 void mlx4_ib_init_alias_guid_work(struct mlx4_ib_dev *dev, int port)
721 {
722 unsigned long flags, flags1;
723
724 if (!mlx4_is_master(dev->dev))
725 return;
726 spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
727 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
728 if (!dev->sriov.is_going_down) {
729 /* If there is pending one should cancell then run, otherwise
730 * won't run till previous one is ended as same work
731 * struct is used.
732 */
733 cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[port].
734 alias_guid_work);
735 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port].wq,
736 &dev->sriov.alias_guid.ports_guid[port].alias_guid_work, 0);
737 }
738 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
739 spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
740 }
741
742 void mlx4_ib_destroy_alias_guid_service(struct mlx4_ib_dev *dev)
743 {
744 int i;
745 struct mlx4_ib_sriov *sriov = &dev->sriov;
746 struct mlx4_alias_guid_work_context *cb_ctx;
747 struct mlx4_sriov_alias_guid_port_rec_det *det;
748 struct ib_sa_query *sa_query;
749 unsigned long flags;
750
751 for (i = 0 ; i < dev->num_ports; i++) {
752 cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work);
753 det = &sriov->alias_guid.ports_guid[i];
754 spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags);
755 while (!list_empty(&det->cb_list)) {
756 cb_ctx = list_entry(det->cb_list.next,
757 struct mlx4_alias_guid_work_context,
758 list);
759 sa_query = cb_ctx->sa_query;
760 cb_ctx->sa_query = NULL;
761 list_del(&cb_ctx->list);
762 spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags);
763 ib_sa_cancel_query(cb_ctx->query_id, sa_query);
764 wait_for_completion(&cb_ctx->done);
765 kfree(cb_ctx);
766 spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags);
767 }
768 spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags);
769 }
770 for (i = 0 ; i < dev->num_ports; i++) {
771 flush_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
772 destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
773 }
774 ib_sa_unregister_client(dev->sriov.alias_guid.sa_client);
775 kfree(dev->sriov.alias_guid.sa_client);
776 }
777
778 int mlx4_ib_init_alias_guid_service(struct mlx4_ib_dev *dev)
779 {
780 char alias_wq_name[15];
781 int ret = 0;
782 int i, j;
783 union ib_gid gid;
784
785 if (!mlx4_is_master(dev->dev))
786 return 0;
787 dev->sriov.alias_guid.sa_client =
788 kzalloc(sizeof *dev->sriov.alias_guid.sa_client, GFP_KERNEL);
789 if (!dev->sriov.alias_guid.sa_client)
790 return -ENOMEM;
791
792 ib_sa_register_client(dev->sriov.alias_guid.sa_client);
793
794 spin_lock_init(&dev->sriov.alias_guid.ag_work_lock);
795
796 for (i = 1; i <= dev->num_ports; ++i) {
797 if (dev->ib_dev.query_gid(&dev->ib_dev , i, 0, &gid)) {
798 ret = -EFAULT;
799 goto err_unregister;
800 }
801 }
802
803 for (i = 0 ; i < dev->num_ports; i++) {
804 memset(&dev->sriov.alias_guid.ports_guid[i], 0,
805 sizeof (struct mlx4_sriov_alias_guid_port_rec_det));
806 dev->sriov.alias_guid.ports_guid[i].state_flags |=
807 GUID_STATE_NEED_PORT_INIT;
808 for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
809 /* mark each val as it was deleted */
810 memset(dev->sriov.alias_guid.ports_guid[i].
811 all_rec_per_port[j].all_recs, 0xFF,
812 sizeof(dev->sriov.alias_guid.ports_guid[i].
813 all_rec_per_port[j].all_recs));
814 }
815 INIT_LIST_HEAD(&dev->sriov.alias_guid.ports_guid[i].cb_list);
816 /*prepare the records, set them to be allocated by sm*/
817 if (mlx4_ib_sm_guid_assign)
818 for (j = 1; j < NUM_ALIAS_GUID_PER_PORT; j++)
819 mlx4_set_admin_guid(dev->dev, 0, j, i + 1);
820 for (j = 0 ; j < NUM_ALIAS_GUID_REC_IN_PORT; j++)
821 invalidate_guid_record(dev, i + 1, j);
822
823 dev->sriov.alias_guid.ports_guid[i].parent = &dev->sriov.alias_guid;
824 dev->sriov.alias_guid.ports_guid[i].port = i;
825
826 snprintf(alias_wq_name, sizeof alias_wq_name, "alias_guid%d", i);
827 dev->sriov.alias_guid.ports_guid[i].wq =
828 create_singlethread_workqueue(alias_wq_name);
829 if (!dev->sriov.alias_guid.ports_guid[i].wq) {
830 ret = -ENOMEM;
831 goto err_thread;
832 }
833 INIT_DELAYED_WORK(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work,
834 alias_guid_work);
835 }
836 return 0;
837
838 err_thread:
839 for (--i; i >= 0; i--) {
840 destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
841 dev->sriov.alias_guid.ports_guid[i].wq = NULL;
842 }
843
844 err_unregister:
845 ib_sa_unregister_client(dev->sriov.alias_guid.sa_client);
846 kfree(dev->sriov.alias_guid.sa_client);
847 dev->sriov.alias_guid.sa_client = NULL;
848 pr_err("init_alias_guid_service: Failed. (ret:%d)\n", ret);
849 return ret;
850 }
This page took 0.04744 seconds and 5 git commands to generate.