IB/mlx4: Request alias GUID on demand
[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 void 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 /* set to run immediately */
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;
170 unlock:
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 * Whenever new GUID is set/unset (guid table change) create event and
179 * notify the relevant slave (master also should be notified).
180 * If the GUID value is not as we have in the cache the slave will not be
181 * updated; in this case it waits for the smp_snoop or the port management
182 * event to call the function and to update the slave.
183 * block_number - the index of the block (16 blocks available)
184 * port_number - 1 or 2
185 */
186 void 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;
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 /*calculate the slaves and notify them*/
212 for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
213 /* the location of the specific index runs from bits 4..11 */
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 tmp_cur_ag = *(__be64 *)&p_data[i * GUID_REC_SIZE];
221 form_cache_ag = get_cached_alias_guid(dev, port_num,
222 (NUM_ALIAS_GUID_IN_REC * block_num) + i);
223 /*
224 * Check if guid is not the same as in the cache,
225 * If it is different, wait for the snoop_smp or the port mgmt
226 * change event to update the slave on its port state change
227 */
228 if (tmp_cur_ag != form_cache_ag)
229 continue;
230
231 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
232 required_value = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE];
233
234 if (required_value == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
235 required_value = 0;
236
237 if (tmp_cur_ag == required_value) {
238 rec->guid_indexes = rec->guid_indexes &
239 ~mlx4_ib_get_aguid_comp_mask_from_ix(i);
240 } else {
241 /* may notify port down if value is 0 */
242 if (tmp_cur_ag != MLX4_NOT_SET_GUID) {
243 spin_unlock_irqrestore(&dev->sriov.
244 alias_guid.ag_work_lock, flags);
245 continue;
246 }
247 }
248 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock,
249 flags);
250 mlx4_gen_guid_change_eqe(dev->dev, slave_id, port_num);
251 /*2 cases: Valid GUID, and Invalid Guid*/
252
253 if (tmp_cur_ag != MLX4_NOT_SET_GUID) { /*valid GUID*/
254 prev_state = mlx4_get_slave_port_state(dev->dev, slave_id, port_num);
255 new_state = set_and_calc_slave_port_state(dev->dev, slave_id, port_num,
256 MLX4_PORT_STATE_IB_PORT_STATE_EVENT_GID_VALID,
257 &gen_event);
258 pr_debug("slave: %d, port: %d prev_port_state: %d,"
259 " new_port_state: %d, gen_event: %d\n",
260 slave_id, port_num, prev_state, new_state, gen_event);
261 if (gen_event == SLAVE_PORT_GEN_EVENT_UP) {
262 pr_debug("sending PORT_UP event to slave: %d, port: %d\n",
263 slave_id, port_num);
264 mlx4_gen_port_state_change_eqe(dev->dev, slave_id,
265 port_num, MLX4_PORT_CHANGE_SUBTYPE_ACTIVE);
266 }
267 } else { /* request to invalidate GUID */
268 set_and_calc_slave_port_state(dev->dev, slave_id, port_num,
269 MLX4_PORT_STATE_IB_EVENT_GID_INVALID,
270 &gen_event);
271 if (gen_event == SLAVE_PORT_GEN_EVENT_DOWN) {
272 pr_debug("sending PORT DOWN event to slave: %d, port: %d\n",
273 slave_id, port_num);
274 mlx4_gen_port_state_change_eqe(dev->dev,
275 slave_id,
276 port_num,
277 MLX4_PORT_CHANGE_SUBTYPE_DOWN);
278 }
279 }
280 }
281 }
282
283 static void aliasguid_query_handler(int status,
284 struct ib_sa_guidinfo_rec *guid_rec,
285 void *context)
286 {
287 struct mlx4_ib_dev *dev;
288 struct mlx4_alias_guid_work_context *cb_ctx = context;
289 u8 port_index ;
290 int i;
291 struct mlx4_sriov_alias_guid_info_rec_det *rec;
292 unsigned long flags, flags1;
293 ib_sa_comp_mask declined_guid_indexes = 0;
294 ib_sa_comp_mask applied_guid_indexes = 0;
295 unsigned int resched_delay_sec = 0;
296
297 if (!context)
298 return;
299
300 dev = cb_ctx->dev;
301 port_index = cb_ctx->port - 1;
302 rec = &dev->sriov.alias_guid.ports_guid[port_index].
303 all_rec_per_port[cb_ctx->block_num];
304
305 if (status) {
306 pr_debug("(port: %d) failed: status = %d\n",
307 cb_ctx->port, status);
308 rec->time_to_run = ktime_get_real_ns() + 1 * NSEC_PER_SEC;
309 goto out;
310 }
311
312 if (guid_rec->block_num != cb_ctx->block_num) {
313 pr_err("block num mismatch: %d != %d\n",
314 cb_ctx->block_num, guid_rec->block_num);
315 goto out;
316 }
317
318 pr_debug("lid/port: %d/%d, block_num: %d\n",
319 be16_to_cpu(guid_rec->lid), cb_ctx->port,
320 guid_rec->block_num);
321
322 rec = &dev->sriov.alias_guid.ports_guid[port_index].
323 all_rec_per_port[guid_rec->block_num];
324
325 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
326 for (i = 0 ; i < NUM_ALIAS_GUID_IN_REC; i++) {
327 __be64 sm_response, required_val;
328
329 if (!(cb_ctx->guid_indexes &
330 mlx4_ib_get_aguid_comp_mask_from_ix(i)))
331 continue;
332 sm_response = *(__be64 *)&guid_rec->guid_info_list
333 [i * GUID_REC_SIZE];
334 required_val = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE];
335 if (cb_ctx->method == MLX4_GUID_INFO_RECORD_DELETE) {
336 if (required_val ==
337 cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
338 goto next_entry;
339
340 /* A new value was set till we got the response */
341 pr_debug("need to set new value %llx, record num %d, block_num:%d\n",
342 be64_to_cpu(required_val),
343 i, guid_rec->block_num);
344 goto entry_declined;
345 }
346
347 /* check if the SM didn't assign one of the records.
348 * if it didn't, re-ask for.
349 */
350 if (sm_response == MLX4_NOT_SET_GUID) {
351 if (rec->guids_retry_schedule[i] == 0)
352 mlx4_ib_warn(&dev->ib_dev,
353 "%s:Record num %d in block_num: %d was declined by SM\n",
354 __func__, i,
355 guid_rec->block_num);
356 goto entry_declined;
357 } else {
358 /* properly assigned record. */
359 /* We save the GUID we just got from the SM in the
360 * admin_guid in order to be persistent, and in the
361 * request from the sm the process will ask for the same GUID */
362 if (required_val &&
363 sm_response != required_val) {
364 /* Warn only on first retry */
365 if (rec->guids_retry_schedule[i] == 0)
366 mlx4_ib_warn(&dev->ib_dev, "%s: Failed to set"
367 " admin guid after SysAdmin "
368 "configuration. "
369 "Record num %d in block_num:%d "
370 "was declined by SM, "
371 "new val(0x%llx) was kept, SM returned (0x%llx)\n",
372 __func__, i,
373 guid_rec->block_num,
374 be64_to_cpu(required_val),
375 be64_to_cpu(sm_response));
376 goto entry_declined;
377 } else {
378 *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] =
379 sm_response;
380 if (required_val == 0)
381 mlx4_set_admin_guid(dev->dev,
382 sm_response,
383 (guid_rec->block_num
384 * NUM_ALIAS_GUID_IN_REC) + i,
385 cb_ctx->port);
386 goto next_entry;
387 }
388 }
389 entry_declined:
390 declined_guid_indexes |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
391 rec->guids_retry_schedule[i] =
392 (rec->guids_retry_schedule[i] == 0) ? 1 :
393 min((unsigned int)60,
394 rec->guids_retry_schedule[i] * 2);
395 /* using the minimum value among all entries in that record */
396 resched_delay_sec = (resched_delay_sec == 0) ?
397 rec->guids_retry_schedule[i] :
398 min(resched_delay_sec,
399 rec->guids_retry_schedule[i]);
400 continue;
401
402 next_entry:
403 rec->guids_retry_schedule[i] = 0;
404 }
405
406 applied_guid_indexes = cb_ctx->guid_indexes & ~declined_guid_indexes;
407 if (declined_guid_indexes ||
408 rec->guid_indexes & ~(applied_guid_indexes)) {
409 pr_debug("record=%d wasn't fully set, guid_indexes=0x%llx applied_indexes=0x%llx, declined_indexes=0x%llx\n",
410 guid_rec->block_num,
411 be64_to_cpu((__force __be64)rec->guid_indexes),
412 be64_to_cpu((__force __be64)applied_guid_indexes),
413 be64_to_cpu((__force __be64)declined_guid_indexes));
414 rec->time_to_run = ktime_get_real_ns() +
415 resched_delay_sec * NSEC_PER_SEC;
416 } else {
417 rec->status = MLX4_GUID_INFO_STATUS_SET;
418 }
419 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
420 /*
421 The func is call here to close the cases when the
422 sm doesn't send smp, so in the sa response the driver
423 notifies the slave.
424 */
425 mlx4_ib_notify_slaves_on_guid_change(dev, guid_rec->block_num,
426 cb_ctx->port,
427 guid_rec->guid_info_list);
428 out:
429 spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
430 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
431 if (!dev->sriov.is_going_down) {
432 get_low_record_time_index(dev, port_index, &resched_delay_sec);
433 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port_index].wq,
434 &dev->sriov.alias_guid.ports_guid[port_index].
435 alias_guid_work,
436 msecs_to_jiffies(resched_delay_sec * 1000));
437 }
438 if (cb_ctx->sa_query) {
439 list_del(&cb_ctx->list);
440 kfree(cb_ctx);
441 } else
442 complete(&cb_ctx->done);
443 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
444 spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
445 }
446
447 static void invalidate_guid_record(struct mlx4_ib_dev *dev, u8 port, int index)
448 {
449 int i;
450 u64 cur_admin_val;
451 ib_sa_comp_mask comp_mask = 0;
452
453 dev->sriov.alias_guid.ports_guid[port - 1].all_rec_per_port[index].status
454 = MLX4_GUID_INFO_STATUS_SET;
455
456 /* calculate the comp_mask for that record.*/
457 for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
458 cur_admin_val =
459 *(u64 *)&dev->sriov.alias_guid.ports_guid[port - 1].
460 all_rec_per_port[index].all_recs[GUID_REC_SIZE * i];
461 /*
462 check the admin value: if it's for delete (~00LL) or
463 it is the first guid of the first record (hw guid) or
464 the records is not in ownership of the sysadmin and the sm doesn't
465 need to assign GUIDs, then don't put it up for assignment.
466 */
467 if (MLX4_GUID_FOR_DELETE_VAL == cur_admin_val ||
468 (!index && !i))
469 continue;
470 comp_mask |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
471 }
472 dev->sriov.alias_guid.ports_guid[port - 1].
473 all_rec_per_port[index].guid_indexes |= comp_mask;
474 if (dev->sriov.alias_guid.ports_guid[port - 1].
475 all_rec_per_port[index].guid_indexes)
476 dev->sriov.alias_guid.ports_guid[port - 1].
477 all_rec_per_port[index].status = MLX4_GUID_INFO_STATUS_IDLE;
478
479 }
480
481 static int set_guid_rec(struct ib_device *ibdev,
482 struct mlx4_next_alias_guid_work *rec)
483 {
484 int err;
485 struct mlx4_ib_dev *dev = to_mdev(ibdev);
486 struct ib_sa_guidinfo_rec guid_info_rec;
487 ib_sa_comp_mask comp_mask;
488 struct ib_port_attr attr;
489 struct mlx4_alias_guid_work_context *callback_context;
490 unsigned long resched_delay, flags, flags1;
491 u8 port = rec->port + 1;
492 int index = rec->block_num;
493 struct mlx4_sriov_alias_guid_info_rec_det *rec_det = &rec->rec_det;
494 struct list_head *head =
495 &dev->sriov.alias_guid.ports_guid[port - 1].cb_list;
496
497 err = __mlx4_ib_query_port(ibdev, port, &attr, 1);
498 if (err) {
499 pr_debug("mlx4_ib_query_port failed (err: %d), port: %d\n",
500 err, port);
501 return err;
502 }
503 /*check the port was configured by the sm, otherwise no need to send */
504 if (attr.state != IB_PORT_ACTIVE) {
505 pr_debug("port %d not active...rescheduling\n", port);
506 resched_delay = 5 * HZ;
507 err = -EAGAIN;
508 goto new_schedule;
509 }
510
511 callback_context = kmalloc(sizeof *callback_context, GFP_KERNEL);
512 if (!callback_context) {
513 err = -ENOMEM;
514 resched_delay = HZ * 5;
515 goto new_schedule;
516 }
517 callback_context->port = port;
518 callback_context->dev = dev;
519 callback_context->block_num = index;
520 callback_context->guid_indexes = rec_det->guid_indexes;
521 callback_context->method = rec->method;
522
523 memset(&guid_info_rec, 0, sizeof (struct ib_sa_guidinfo_rec));
524
525 guid_info_rec.lid = cpu_to_be16(attr.lid);
526 guid_info_rec.block_num = index;
527
528 memcpy(guid_info_rec.guid_info_list, rec_det->all_recs,
529 GUID_REC_SIZE * NUM_ALIAS_GUID_IN_REC);
530 comp_mask = IB_SA_GUIDINFO_REC_LID | IB_SA_GUIDINFO_REC_BLOCK_NUM |
531 rec_det->guid_indexes;
532
533 init_completion(&callback_context->done);
534 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
535 list_add_tail(&callback_context->list, head);
536 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
537
538 callback_context->query_id =
539 ib_sa_guid_info_rec_query(dev->sriov.alias_guid.sa_client,
540 ibdev, port, &guid_info_rec,
541 comp_mask, rec->method, 1000,
542 GFP_KERNEL, aliasguid_query_handler,
543 callback_context,
544 &callback_context->sa_query);
545 if (callback_context->query_id < 0) {
546 pr_debug("ib_sa_guid_info_rec_query failed, query_id: "
547 "%d. will reschedule to the next 1 sec.\n",
548 callback_context->query_id);
549 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
550 list_del(&callback_context->list);
551 kfree(callback_context);
552 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
553 resched_delay = 1 * HZ;
554 err = -EAGAIN;
555 goto new_schedule;
556 }
557 err = 0;
558 goto out;
559
560 new_schedule:
561 spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
562 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
563 invalidate_guid_record(dev, port, index);
564 if (!dev->sriov.is_going_down) {
565 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq,
566 &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work,
567 resched_delay);
568 }
569 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
570 spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
571
572 out:
573 return err;
574 }
575
576 static void mlx4_ib_guid_port_init(struct mlx4_ib_dev *dev, int port)
577 {
578 int j, k, entry;
579 __be64 guid;
580
581 /*Check if the SM doesn't need to assign the GUIDs*/
582 for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
583 for (k = 0; k < NUM_ALIAS_GUID_IN_REC; k++) {
584 entry = j * NUM_ALIAS_GUID_IN_REC + k;
585 /* no request for the 0 entry (hw guid) */
586 if (!entry || entry > dev->dev->persist->num_vfs ||
587 !mlx4_is_slave_active(dev->dev, entry))
588 continue;
589 guid = mlx4_get_admin_guid(dev->dev, entry, port);
590 *(__be64 *)&dev->sriov.alias_guid.ports_guid[port - 1].
591 all_rec_per_port[j].all_recs
592 [GUID_REC_SIZE * k] = guid;
593 pr_debug("guid was set, entry=%d, val=0x%llx, port=%d\n",
594 entry,
595 be64_to_cpu(guid),
596 port);
597 }
598 }
599 }
600 void mlx4_ib_invalidate_all_guid_record(struct mlx4_ib_dev *dev, int port)
601 {
602 int i;
603 unsigned long flags, flags1;
604
605 pr_debug("port %d\n", port);
606
607 spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
608 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
609
610 if (dev->sriov.alias_guid.ports_guid[port - 1].state_flags &
611 GUID_STATE_NEED_PORT_INIT) {
612 mlx4_ib_guid_port_init(dev, port);
613 dev->sriov.alias_guid.ports_guid[port - 1].state_flags &=
614 (~GUID_STATE_NEED_PORT_INIT);
615 }
616 for (i = 0; i < NUM_ALIAS_GUID_REC_IN_PORT; i++)
617 invalidate_guid_record(dev, port, i);
618
619 if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) {
620 /*
621 make sure no work waits in the queue, if the work is already
622 queued(not on the timer) the cancel will fail. That is not a problem
623 because we just want the work started.
624 */
625 cancel_delayed_work(&dev->sriov.alias_guid.
626 ports_guid[port - 1].alias_guid_work);
627 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq,
628 &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work,
629 0);
630 }
631 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
632 spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
633 }
634
635 static void set_required_record(struct mlx4_ib_dev *dev, u8 port,
636 struct mlx4_next_alias_guid_work *next_rec,
637 int record_index)
638 {
639 int i;
640 int lowset_time_entry = -1;
641 int lowest_time = 0;
642 ib_sa_comp_mask delete_guid_indexes = 0;
643 ib_sa_comp_mask set_guid_indexes = 0;
644 struct mlx4_sriov_alias_guid_info_rec_det *rec =
645 &dev->sriov.alias_guid.ports_guid[port].
646 all_rec_per_port[record_index];
647
648 for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
649 if (!(rec->guid_indexes &
650 mlx4_ib_get_aguid_comp_mask_from_ix(i)))
651 continue;
652
653 if (*(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] ==
654 cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
655 delete_guid_indexes |=
656 mlx4_ib_get_aguid_comp_mask_from_ix(i);
657 else
658 set_guid_indexes |=
659 mlx4_ib_get_aguid_comp_mask_from_ix(i);
660
661 if (lowset_time_entry == -1 || rec->guids_retry_schedule[i] <=
662 lowest_time) {
663 lowset_time_entry = i;
664 lowest_time = rec->guids_retry_schedule[i];
665 }
666 }
667
668 memcpy(&next_rec->rec_det, rec, sizeof(*rec));
669 next_rec->port = port;
670 next_rec->block_num = record_index;
671
672 if (*(__be64 *)&rec->all_recs[lowset_time_entry * GUID_REC_SIZE] ==
673 cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) {
674 next_rec->rec_det.guid_indexes = delete_guid_indexes;
675 next_rec->method = MLX4_GUID_INFO_RECORD_DELETE;
676 } else {
677 next_rec->rec_det.guid_indexes = set_guid_indexes;
678 next_rec->method = MLX4_GUID_INFO_RECORD_SET;
679 }
680 }
681
682 /* return index of record that should be updated based on lowest
683 * rescheduled time
684 */
685 static int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port,
686 int *resched_delay_sec)
687 {
688 int record_index = -1;
689 u64 low_record_time = 0;
690 struct mlx4_sriov_alias_guid_info_rec_det rec;
691 int j;
692
693 for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
694 rec = dev->sriov.alias_guid.ports_guid[port].
695 all_rec_per_port[j];
696 if (rec.status == MLX4_GUID_INFO_STATUS_IDLE &&
697 rec.guid_indexes) {
698 if (record_index == -1 ||
699 rec.time_to_run < low_record_time) {
700 record_index = j;
701 low_record_time = rec.time_to_run;
702 }
703 }
704 }
705 if (resched_delay_sec) {
706 u64 curr_time = ktime_get_real_ns();
707
708 *resched_delay_sec = (low_record_time < curr_time) ? 0 :
709 div_u64((low_record_time - curr_time), NSEC_PER_SEC);
710 }
711
712 return record_index;
713 }
714
715 /* The function returns the next record that was
716 * not configured (or failed to be configured) */
717 static int get_next_record_to_update(struct mlx4_ib_dev *dev, u8 port,
718 struct mlx4_next_alias_guid_work *rec)
719 {
720 unsigned long flags;
721 int record_index;
722 int ret = 0;
723
724 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
725 record_index = get_low_record_time_index(dev, port, NULL);
726
727 if (record_index < 0) {
728 ret = -ENOENT;
729 goto out;
730 }
731
732 set_required_record(dev, port, rec, record_index);
733 out:
734 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
735 return ret;
736 }
737
738 static void alias_guid_work(struct work_struct *work)
739 {
740 struct delayed_work *delay = to_delayed_work(work);
741 int ret = 0;
742 struct mlx4_next_alias_guid_work *rec;
743 struct mlx4_sriov_alias_guid_port_rec_det *sriov_alias_port =
744 container_of(delay, struct mlx4_sriov_alias_guid_port_rec_det,
745 alias_guid_work);
746 struct mlx4_sriov_alias_guid *sriov_alias_guid = sriov_alias_port->parent;
747 struct mlx4_ib_sriov *ib_sriov = container_of(sriov_alias_guid,
748 struct mlx4_ib_sriov,
749 alias_guid);
750 struct mlx4_ib_dev *dev = container_of(ib_sriov, struct mlx4_ib_dev, sriov);
751
752 rec = kzalloc(sizeof *rec, GFP_KERNEL);
753 if (!rec) {
754 pr_err("alias_guid_work: No Memory\n");
755 return;
756 }
757
758 pr_debug("starting [port: %d]...\n", sriov_alias_port->port + 1);
759 ret = get_next_record_to_update(dev, sriov_alias_port->port, rec);
760 if (ret) {
761 pr_debug("No more records to update.\n");
762 goto out;
763 }
764
765 set_guid_rec(&dev->ib_dev, rec);
766 out:
767 kfree(rec);
768 }
769
770
771 void mlx4_ib_init_alias_guid_work(struct mlx4_ib_dev *dev, int port)
772 {
773 unsigned long flags, flags1;
774
775 if (!mlx4_is_master(dev->dev))
776 return;
777 spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
778 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
779 if (!dev->sriov.is_going_down) {
780 /* If there is pending one should cancell then run, otherwise
781 * won't run till previous one is ended as same work
782 * struct is used.
783 */
784 cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[port].
785 alias_guid_work);
786 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port].wq,
787 &dev->sriov.alias_guid.ports_guid[port].alias_guid_work, 0);
788 }
789 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
790 spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
791 }
792
793 void mlx4_ib_destroy_alias_guid_service(struct mlx4_ib_dev *dev)
794 {
795 int i;
796 struct mlx4_ib_sriov *sriov = &dev->sriov;
797 struct mlx4_alias_guid_work_context *cb_ctx;
798 struct mlx4_sriov_alias_guid_port_rec_det *det;
799 struct ib_sa_query *sa_query;
800 unsigned long flags;
801
802 for (i = 0 ; i < dev->num_ports; i++) {
803 cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work);
804 det = &sriov->alias_guid.ports_guid[i];
805 spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags);
806 while (!list_empty(&det->cb_list)) {
807 cb_ctx = list_entry(det->cb_list.next,
808 struct mlx4_alias_guid_work_context,
809 list);
810 sa_query = cb_ctx->sa_query;
811 cb_ctx->sa_query = NULL;
812 list_del(&cb_ctx->list);
813 spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags);
814 ib_sa_cancel_query(cb_ctx->query_id, sa_query);
815 wait_for_completion(&cb_ctx->done);
816 kfree(cb_ctx);
817 spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags);
818 }
819 spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags);
820 }
821 for (i = 0 ; i < dev->num_ports; i++) {
822 flush_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
823 destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
824 }
825 ib_sa_unregister_client(dev->sriov.alias_guid.sa_client);
826 kfree(dev->sriov.alias_guid.sa_client);
827 }
828
829 int mlx4_ib_init_alias_guid_service(struct mlx4_ib_dev *dev)
830 {
831 char alias_wq_name[15];
832 int ret = 0;
833 int i, j;
834 union ib_gid gid;
835
836 if (!mlx4_is_master(dev->dev))
837 return 0;
838 dev->sriov.alias_guid.sa_client =
839 kzalloc(sizeof *dev->sriov.alias_guid.sa_client, GFP_KERNEL);
840 if (!dev->sriov.alias_guid.sa_client)
841 return -ENOMEM;
842
843 ib_sa_register_client(dev->sriov.alias_guid.sa_client);
844
845 spin_lock_init(&dev->sriov.alias_guid.ag_work_lock);
846
847 for (i = 1; i <= dev->num_ports; ++i) {
848 if (dev->ib_dev.query_gid(&dev->ib_dev , i, 0, &gid)) {
849 ret = -EFAULT;
850 goto err_unregister;
851 }
852 }
853
854 for (i = 0 ; i < dev->num_ports; i++) {
855 memset(&dev->sriov.alias_guid.ports_guid[i], 0,
856 sizeof (struct mlx4_sriov_alias_guid_port_rec_det));
857 dev->sriov.alias_guid.ports_guid[i].state_flags |=
858 GUID_STATE_NEED_PORT_INIT;
859 for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
860 /* mark each val as it was deleted */
861 memset(dev->sriov.alias_guid.ports_guid[i].
862 all_rec_per_port[j].all_recs, 0xFF,
863 sizeof(dev->sriov.alias_guid.ports_guid[i].
864 all_rec_per_port[j].all_recs));
865 }
866 INIT_LIST_HEAD(&dev->sriov.alias_guid.ports_guid[i].cb_list);
867 /*prepare the records, set them to be allocated by sm*/
868 if (mlx4_ib_sm_guid_assign)
869 for (j = 1; j < NUM_ALIAS_GUID_PER_PORT; j++)
870 mlx4_set_admin_guid(dev->dev, 0, j, i + 1);
871 for (j = 0 ; j < NUM_ALIAS_GUID_REC_IN_PORT; j++)
872 invalidate_guid_record(dev, i + 1, j);
873
874 dev->sriov.alias_guid.ports_guid[i].parent = &dev->sriov.alias_guid;
875 dev->sriov.alias_guid.ports_guid[i].port = i;
876
877 snprintf(alias_wq_name, sizeof alias_wq_name, "alias_guid%d", i);
878 dev->sriov.alias_guid.ports_guid[i].wq =
879 create_singlethread_workqueue(alias_wq_name);
880 if (!dev->sriov.alias_guid.ports_guid[i].wq) {
881 ret = -ENOMEM;
882 goto err_thread;
883 }
884 INIT_DELAYED_WORK(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work,
885 alias_guid_work);
886 }
887 return 0;
888
889 err_thread:
890 for (--i; i >= 0; i--) {
891 destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
892 dev->sriov.alias_guid.ports_guid[i].wq = NULL;
893 }
894
895 err_unregister:
896 ib_sa_unregister_client(dev->sriov.alias_guid.sa_client);
897 kfree(dev->sriov.alias_guid.sa_client);
898 dev->sriov.alias_guid.sa_client = NULL;
899 pr_err("init_alias_guid_service: Failed. (ret:%d)\n", ret);
900 return ret;
901 }
This page took 0.057436 seconds and 5 git commands to generate.