0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 #include <rdma/ib_mad.h>
0036 #include <rdma/ib_smi.h>
0037 #include <rdma/ib_cache.h>
0038 #include <rdma/ib_sa.h>
0039 #include <rdma/ib_pack.h>
0040 #include <linux/mlx4/cmd.h>
0041 #include <linux/init.h>
0042 #include <linux/errno.h>
0043 #include <rdma/ib_user_verbs.h>
0044 #include <linux/delay.h>
0045 #include "mlx4_ib.h"
0046
0047
0048
0049
0050
0051
0052 struct mlx4_alias_guid_work_context {
0053 u8 port;
0054 struct mlx4_ib_dev *dev ;
0055 struct ib_sa_query *sa_query;
0056 struct completion done;
0057 int query_id;
0058 struct list_head list;
0059 int block_num;
0060 ib_sa_comp_mask guid_indexes;
0061 u8 method;
0062 };
0063
0064 struct mlx4_next_alias_guid_work {
0065 u8 port;
0066 u8 block_num;
0067 u8 method;
0068 struct mlx4_sriov_alias_guid_info_rec_det rec_det;
0069 };
0070
0071 static int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port,
0072 int *resched_delay_sec);
0073
0074 void mlx4_ib_update_cache_on_guid_change(struct mlx4_ib_dev *dev, int block_num,
0075 u32 port_num, u8 *p_data)
0076 {
0077 int i;
0078 u64 guid_indexes;
0079 int slave_id;
0080 u32 port_index = port_num - 1;
0081
0082 if (!mlx4_is_master(dev->dev))
0083 return;
0084
0085 guid_indexes = be64_to_cpu((__force __be64) dev->sriov.alias_guid.
0086 ports_guid[port_num - 1].
0087 all_rec_per_port[block_num].guid_indexes);
0088 pr_debug("port: %u, guid_indexes: 0x%llx\n", port_num, guid_indexes);
0089
0090 for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
0091
0092
0093 if (test_bit(i + 4, (unsigned long *)&guid_indexes)) {
0094 slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ;
0095 if (slave_id >= dev->dev->num_slaves) {
0096 pr_debug("The last slave: %d\n", slave_id);
0097 return;
0098 }
0099
0100
0101 memcpy(&dev->sriov.demux[port_index].guid_cache[slave_id],
0102 &p_data[i * GUID_REC_SIZE],
0103 GUID_REC_SIZE);
0104 } else
0105 pr_debug("Guid number: %d in block: %d"
0106 " was not updated\n", i, block_num);
0107 }
0108 }
0109
0110 static __be64 get_cached_alias_guid(struct mlx4_ib_dev *dev, int port, int index)
0111 {
0112 if (index >= NUM_ALIAS_GUID_PER_PORT) {
0113 pr_err("%s: ERROR: asked for index:%d\n", __func__, index);
0114 return (__force __be64) -1;
0115 }
0116 return *(__be64 *)&dev->sriov.demux[port - 1].guid_cache[index];
0117 }
0118
0119
0120 ib_sa_comp_mask mlx4_ib_get_aguid_comp_mask_from_ix(int index)
0121 {
0122 return IB_SA_COMP_MASK(4 + index);
0123 }
0124
0125 void mlx4_ib_slave_alias_guid_event(struct mlx4_ib_dev *dev, int slave,
0126 int port, int slave_init)
0127 {
0128 __be64 curr_guid, required_guid;
0129 int record_num = slave / 8;
0130 int index = slave % 8;
0131 int port_index = port - 1;
0132 unsigned long flags;
0133 int do_work = 0;
0134
0135 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
0136 if (dev->sriov.alias_guid.ports_guid[port_index].state_flags &
0137 GUID_STATE_NEED_PORT_INIT)
0138 goto unlock;
0139 if (!slave_init) {
0140 curr_guid = *(__be64 *)&dev->sriov.
0141 alias_guid.ports_guid[port_index].
0142 all_rec_per_port[record_num].
0143 all_recs[GUID_REC_SIZE * index];
0144 if (curr_guid == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL) ||
0145 !curr_guid)
0146 goto unlock;
0147 required_guid = cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL);
0148 } else {
0149 required_guid = mlx4_get_admin_guid(dev->dev, slave, port);
0150 if (required_guid == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
0151 goto unlock;
0152 }
0153 *(__be64 *)&dev->sriov.alias_guid.ports_guid[port_index].
0154 all_rec_per_port[record_num].
0155 all_recs[GUID_REC_SIZE * index] = required_guid;
0156 dev->sriov.alias_guid.ports_guid[port_index].
0157 all_rec_per_port[record_num].guid_indexes
0158 |= mlx4_ib_get_aguid_comp_mask_from_ix(index);
0159 dev->sriov.alias_guid.ports_guid[port_index].
0160 all_rec_per_port[record_num].status
0161 = MLX4_GUID_INFO_STATUS_IDLE;
0162
0163 dev->sriov.alias_guid.ports_guid[port_index].
0164 all_rec_per_port[record_num].time_to_run = 0;
0165 dev->sriov.alias_guid.ports_guid[port_index].
0166 all_rec_per_port[record_num].
0167 guids_retry_schedule[index] = 0;
0168 do_work = 1;
0169 unlock:
0170 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
0171
0172 if (do_work)
0173 mlx4_ib_init_alias_guid_work(dev, port_index);
0174 }
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185 void mlx4_ib_notify_slaves_on_guid_change(struct mlx4_ib_dev *dev,
0186 int block_num, u32 port_num,
0187 u8 *p_data)
0188 {
0189 int i;
0190 u64 guid_indexes;
0191 int slave_id, slave_port;
0192 enum slave_port_state new_state;
0193 enum slave_port_state prev_state;
0194 __be64 tmp_cur_ag, form_cache_ag;
0195 enum slave_port_gen_event gen_event;
0196 struct mlx4_sriov_alias_guid_info_rec_det *rec;
0197 unsigned long flags;
0198 __be64 required_value;
0199
0200 if (!mlx4_is_master(dev->dev))
0201 return;
0202
0203 rec = &dev->sriov.alias_guid.ports_guid[port_num - 1].
0204 all_rec_per_port[block_num];
0205 guid_indexes = be64_to_cpu((__force __be64) dev->sriov.alias_guid.
0206 ports_guid[port_num - 1].
0207 all_rec_per_port[block_num].guid_indexes);
0208 pr_debug("port: %u, guid_indexes: 0x%llx\n", port_num, guid_indexes);
0209
0210
0211 for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
0212
0213 if (!(test_bit(i + 4, (unsigned long *)&guid_indexes)))
0214 continue;
0215
0216 slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ;
0217 if (slave_id >= dev->dev->persist->num_vfs + 1)
0218 return;
0219
0220 slave_port = mlx4_phys_to_slave_port(dev->dev, slave_id, port_num);
0221 if (slave_port < 0)
0222 continue;
0223
0224 tmp_cur_ag = *(__be64 *)&p_data[i * GUID_REC_SIZE];
0225 form_cache_ag = get_cached_alias_guid(dev, port_num,
0226 (NUM_ALIAS_GUID_IN_REC * block_num) + i);
0227
0228
0229
0230
0231
0232 if (tmp_cur_ag != form_cache_ag)
0233 continue;
0234
0235 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
0236 required_value = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE];
0237
0238 if (required_value == cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
0239 required_value = 0;
0240
0241 if (tmp_cur_ag == required_value) {
0242 rec->guid_indexes = rec->guid_indexes &
0243 ~mlx4_ib_get_aguid_comp_mask_from_ix(i);
0244 } else {
0245
0246 if (tmp_cur_ag != MLX4_NOT_SET_GUID) {
0247 spin_unlock_irqrestore(&dev->sriov.
0248 alias_guid.ag_work_lock, flags);
0249 continue;
0250 }
0251 }
0252 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock,
0253 flags);
0254 mlx4_gen_guid_change_eqe(dev->dev, slave_id, port_num);
0255
0256
0257 if (tmp_cur_ag != MLX4_NOT_SET_GUID) {
0258 prev_state = mlx4_get_slave_port_state(dev->dev, slave_id, port_num);
0259 new_state = set_and_calc_slave_port_state(dev->dev, slave_id, port_num,
0260 MLX4_PORT_STATE_IB_PORT_STATE_EVENT_GID_VALID,
0261 &gen_event);
0262 pr_debug("slave: %d, port: %u prev_port_state: %d,"
0263 " new_port_state: %d, gen_event: %d\n",
0264 slave_id, port_num, prev_state, new_state, gen_event);
0265 if (gen_event == SLAVE_PORT_GEN_EVENT_UP) {
0266 pr_debug("sending PORT_UP event to slave: %d, port: %u\n",
0267 slave_id, port_num);
0268 mlx4_gen_port_state_change_eqe(dev->dev, slave_id,
0269 port_num, MLX4_PORT_CHANGE_SUBTYPE_ACTIVE);
0270 }
0271 } else {
0272 set_and_calc_slave_port_state(dev->dev, slave_id, port_num,
0273 MLX4_PORT_STATE_IB_EVENT_GID_INVALID,
0274 &gen_event);
0275 if (gen_event == SLAVE_PORT_GEN_EVENT_DOWN) {
0276 pr_debug("sending PORT DOWN event to slave: %d, port: %u\n",
0277 slave_id, port_num);
0278 mlx4_gen_port_state_change_eqe(dev->dev,
0279 slave_id,
0280 port_num,
0281 MLX4_PORT_CHANGE_SUBTYPE_DOWN);
0282 }
0283 }
0284 }
0285 }
0286
0287 static void aliasguid_query_handler(int status,
0288 struct ib_sa_guidinfo_rec *guid_rec,
0289 void *context)
0290 {
0291 struct mlx4_ib_dev *dev;
0292 struct mlx4_alias_guid_work_context *cb_ctx = context;
0293 u8 port_index ;
0294 int i;
0295 struct mlx4_sriov_alias_guid_info_rec_det *rec;
0296 unsigned long flags, flags1;
0297 ib_sa_comp_mask declined_guid_indexes = 0;
0298 ib_sa_comp_mask applied_guid_indexes = 0;
0299 unsigned int resched_delay_sec = 0;
0300
0301 if (!context)
0302 return;
0303
0304 dev = cb_ctx->dev;
0305 port_index = cb_ctx->port - 1;
0306 rec = &dev->sriov.alias_guid.ports_guid[port_index].
0307 all_rec_per_port[cb_ctx->block_num];
0308
0309 if (status) {
0310 pr_debug("(port: %d) failed: status = %d\n",
0311 cb_ctx->port, status);
0312 rec->time_to_run = ktime_get_boottime_ns() + 1 * NSEC_PER_SEC;
0313 goto out;
0314 }
0315
0316 if (guid_rec->block_num != cb_ctx->block_num) {
0317 pr_err("block num mismatch: %d != %d\n",
0318 cb_ctx->block_num, guid_rec->block_num);
0319 goto out;
0320 }
0321
0322 pr_debug("lid/port: %d/%d, block_num: %d\n",
0323 be16_to_cpu(guid_rec->lid), cb_ctx->port,
0324 guid_rec->block_num);
0325
0326 rec = &dev->sriov.alias_guid.ports_guid[port_index].
0327 all_rec_per_port[guid_rec->block_num];
0328
0329 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
0330 for (i = 0 ; i < NUM_ALIAS_GUID_IN_REC; i++) {
0331 __be64 sm_response, required_val;
0332
0333 if (!(cb_ctx->guid_indexes &
0334 mlx4_ib_get_aguid_comp_mask_from_ix(i)))
0335 continue;
0336 sm_response = *(__be64 *)&guid_rec->guid_info_list
0337 [i * GUID_REC_SIZE];
0338 required_val = *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE];
0339 if (cb_ctx->method == MLX4_GUID_INFO_RECORD_DELETE) {
0340 if (required_val ==
0341 cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
0342 goto next_entry;
0343
0344
0345 pr_debug("need to set new value %llx, record num %d, block_num:%d\n",
0346 be64_to_cpu(required_val),
0347 i, guid_rec->block_num);
0348 goto entry_declined;
0349 }
0350
0351
0352
0353
0354 if (sm_response == MLX4_NOT_SET_GUID) {
0355 if (rec->guids_retry_schedule[i] == 0)
0356 mlx4_ib_warn(&dev->ib_dev,
0357 "%s:Record num %d in block_num: %d was declined by SM\n",
0358 __func__, i,
0359 guid_rec->block_num);
0360 goto entry_declined;
0361 } else {
0362
0363
0364
0365
0366 if (required_val &&
0367 sm_response != required_val) {
0368
0369 if (rec->guids_retry_schedule[i] == 0)
0370 mlx4_ib_warn(&dev->ib_dev, "%s: Failed to set"
0371 " admin guid after SysAdmin "
0372 "configuration. "
0373 "Record num %d in block_num:%d "
0374 "was declined by SM, "
0375 "new val(0x%llx) was kept, SM returned (0x%llx)\n",
0376 __func__, i,
0377 guid_rec->block_num,
0378 be64_to_cpu(required_val),
0379 be64_to_cpu(sm_response));
0380 goto entry_declined;
0381 } else {
0382 *(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] =
0383 sm_response;
0384 if (required_val == 0)
0385 mlx4_set_admin_guid(dev->dev,
0386 sm_response,
0387 (guid_rec->block_num
0388 * NUM_ALIAS_GUID_IN_REC) + i,
0389 cb_ctx->port);
0390 goto next_entry;
0391 }
0392 }
0393 entry_declined:
0394 declined_guid_indexes |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
0395 rec->guids_retry_schedule[i] =
0396 (rec->guids_retry_schedule[i] == 0) ? 1 :
0397 min((unsigned int)60,
0398 rec->guids_retry_schedule[i] * 2);
0399
0400 resched_delay_sec = (resched_delay_sec == 0) ?
0401 rec->guids_retry_schedule[i] :
0402 min(resched_delay_sec,
0403 rec->guids_retry_schedule[i]);
0404 continue;
0405
0406 next_entry:
0407 rec->guids_retry_schedule[i] = 0;
0408 }
0409
0410 applied_guid_indexes = cb_ctx->guid_indexes & ~declined_guid_indexes;
0411 if (declined_guid_indexes ||
0412 rec->guid_indexes & ~(applied_guid_indexes)) {
0413 pr_debug("record=%d wasn't fully set, guid_indexes=0x%llx applied_indexes=0x%llx, declined_indexes=0x%llx\n",
0414 guid_rec->block_num,
0415 be64_to_cpu((__force __be64)rec->guid_indexes),
0416 be64_to_cpu((__force __be64)applied_guid_indexes),
0417 be64_to_cpu((__force __be64)declined_guid_indexes));
0418 rec->time_to_run = ktime_get_boottime_ns() +
0419 resched_delay_sec * NSEC_PER_SEC;
0420 } else {
0421 rec->status = MLX4_GUID_INFO_STATUS_SET;
0422 }
0423 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
0424
0425
0426
0427
0428
0429 mlx4_ib_notify_slaves_on_guid_change(dev, guid_rec->block_num,
0430 cb_ctx->port,
0431 guid_rec->guid_info_list);
0432 out:
0433 spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
0434 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
0435 if (!dev->sriov.is_going_down) {
0436 get_low_record_time_index(dev, port_index, &resched_delay_sec);
0437 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port_index].wq,
0438 &dev->sriov.alias_guid.ports_guid[port_index].
0439 alias_guid_work,
0440 msecs_to_jiffies(resched_delay_sec * 1000));
0441 }
0442 if (cb_ctx->sa_query) {
0443 list_del(&cb_ctx->list);
0444 kfree(cb_ctx);
0445 } else
0446 complete(&cb_ctx->done);
0447 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
0448 spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
0449 }
0450
0451 static void invalidate_guid_record(struct mlx4_ib_dev *dev, u8 port, int index)
0452 {
0453 int i;
0454 u64 cur_admin_val;
0455 ib_sa_comp_mask comp_mask = 0;
0456
0457 dev->sriov.alias_guid.ports_guid[port - 1].all_rec_per_port[index].status
0458 = MLX4_GUID_INFO_STATUS_SET;
0459
0460
0461 for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
0462 cur_admin_val =
0463 *(u64 *)&dev->sriov.alias_guid.ports_guid[port - 1].
0464 all_rec_per_port[index].all_recs[GUID_REC_SIZE * i];
0465
0466
0467
0468
0469
0470
0471 if (MLX4_GUID_FOR_DELETE_VAL == cur_admin_val ||
0472 (!index && !i))
0473 continue;
0474 comp_mask |= mlx4_ib_get_aguid_comp_mask_from_ix(i);
0475 }
0476 dev->sriov.alias_guid.ports_guid[port - 1].
0477 all_rec_per_port[index].guid_indexes |= comp_mask;
0478 if (dev->sriov.alias_guid.ports_guid[port - 1].
0479 all_rec_per_port[index].guid_indexes)
0480 dev->sriov.alias_guid.ports_guid[port - 1].
0481 all_rec_per_port[index].status = MLX4_GUID_INFO_STATUS_IDLE;
0482
0483 }
0484
0485 static int set_guid_rec(struct ib_device *ibdev,
0486 struct mlx4_next_alias_guid_work *rec)
0487 {
0488 int err;
0489 struct mlx4_ib_dev *dev = to_mdev(ibdev);
0490 struct ib_sa_guidinfo_rec guid_info_rec;
0491 ib_sa_comp_mask comp_mask;
0492 struct ib_port_attr attr;
0493 struct mlx4_alias_guid_work_context *callback_context;
0494 unsigned long resched_delay, flags, flags1;
0495 u8 port = rec->port + 1;
0496 int index = rec->block_num;
0497 struct mlx4_sriov_alias_guid_info_rec_det *rec_det = &rec->rec_det;
0498 struct list_head *head =
0499 &dev->sriov.alias_guid.ports_guid[port - 1].cb_list;
0500
0501 memset(&attr, 0, sizeof(attr));
0502 err = __mlx4_ib_query_port(ibdev, port, &attr, 1);
0503 if (err) {
0504 pr_debug("mlx4_ib_query_port failed (err: %d), port: %d\n",
0505 err, port);
0506 return err;
0507 }
0508
0509 if (attr.state != IB_PORT_ACTIVE) {
0510 pr_debug("port %d not active...rescheduling\n", port);
0511 resched_delay = 5 * HZ;
0512 err = -EAGAIN;
0513 goto new_schedule;
0514 }
0515
0516 callback_context = kmalloc(sizeof *callback_context, GFP_KERNEL);
0517 if (!callback_context) {
0518 err = -ENOMEM;
0519 resched_delay = HZ * 5;
0520 goto new_schedule;
0521 }
0522 callback_context->port = port;
0523 callback_context->dev = dev;
0524 callback_context->block_num = index;
0525 callback_context->guid_indexes = rec_det->guid_indexes;
0526 callback_context->method = rec->method;
0527
0528 memset(&guid_info_rec, 0, sizeof (struct ib_sa_guidinfo_rec));
0529
0530 guid_info_rec.lid = ib_lid_be16(attr.lid);
0531 guid_info_rec.block_num = index;
0532
0533 memcpy(guid_info_rec.guid_info_list, rec_det->all_recs,
0534 GUID_REC_SIZE * NUM_ALIAS_GUID_IN_REC);
0535 comp_mask = IB_SA_GUIDINFO_REC_LID | IB_SA_GUIDINFO_REC_BLOCK_NUM |
0536 rec_det->guid_indexes;
0537
0538 init_completion(&callback_context->done);
0539 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
0540 list_add_tail(&callback_context->list, head);
0541 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
0542
0543 callback_context->query_id =
0544 ib_sa_guid_info_rec_query(dev->sriov.alias_guid.sa_client,
0545 ibdev, port, &guid_info_rec,
0546 comp_mask, rec->method, 1000,
0547 GFP_KERNEL, aliasguid_query_handler,
0548 callback_context,
0549 &callback_context->sa_query);
0550 if (callback_context->query_id < 0) {
0551 pr_debug("ib_sa_guid_info_rec_query failed, query_id: "
0552 "%d. will reschedule to the next 1 sec.\n",
0553 callback_context->query_id);
0554 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
0555 list_del(&callback_context->list);
0556 kfree(callback_context);
0557 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
0558 resched_delay = 1 * HZ;
0559 err = -EAGAIN;
0560 goto new_schedule;
0561 }
0562 err = 0;
0563 goto out;
0564
0565 new_schedule:
0566 spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
0567 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
0568 invalidate_guid_record(dev, port, index);
0569 if (!dev->sriov.is_going_down) {
0570 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq,
0571 &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work,
0572 resched_delay);
0573 }
0574 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
0575 spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
0576
0577 out:
0578 return err;
0579 }
0580
0581 static void mlx4_ib_guid_port_init(struct mlx4_ib_dev *dev, int port)
0582 {
0583 int j, k, entry;
0584 __be64 guid;
0585
0586
0587 for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
0588 for (k = 0; k < NUM_ALIAS_GUID_IN_REC; k++) {
0589 entry = j * NUM_ALIAS_GUID_IN_REC + k;
0590
0591 if (!entry || entry > dev->dev->persist->num_vfs ||
0592 !mlx4_is_slave_active(dev->dev, entry))
0593 continue;
0594 guid = mlx4_get_admin_guid(dev->dev, entry, port);
0595 *(__be64 *)&dev->sriov.alias_guid.ports_guid[port - 1].
0596 all_rec_per_port[j].all_recs
0597 [GUID_REC_SIZE * k] = guid;
0598 pr_debug("guid was set, entry=%d, val=0x%llx, port=%d\n",
0599 entry,
0600 be64_to_cpu(guid),
0601 port);
0602 }
0603 }
0604 }
0605 void mlx4_ib_invalidate_all_guid_record(struct mlx4_ib_dev *dev, int port)
0606 {
0607 int i;
0608 unsigned long flags, flags1;
0609
0610 pr_debug("port %d\n", port);
0611
0612 spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
0613 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
0614
0615 if (dev->sriov.alias_guid.ports_guid[port - 1].state_flags &
0616 GUID_STATE_NEED_PORT_INIT) {
0617 mlx4_ib_guid_port_init(dev, port);
0618 dev->sriov.alias_guid.ports_guid[port - 1].state_flags &=
0619 (~GUID_STATE_NEED_PORT_INIT);
0620 }
0621 for (i = 0; i < NUM_ALIAS_GUID_REC_IN_PORT; i++)
0622 invalidate_guid_record(dev, port, i);
0623
0624 if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) {
0625
0626
0627
0628
0629
0630 cancel_delayed_work(&dev->sriov.alias_guid.
0631 ports_guid[port - 1].alias_guid_work);
0632 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port - 1].wq,
0633 &dev->sriov.alias_guid.ports_guid[port - 1].alias_guid_work,
0634 0);
0635 }
0636 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
0637 spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
0638 }
0639
0640 static void set_required_record(struct mlx4_ib_dev *dev, u8 port,
0641 struct mlx4_next_alias_guid_work *next_rec,
0642 int record_index)
0643 {
0644 int i;
0645 int lowset_time_entry = -1;
0646 int lowest_time = 0;
0647 ib_sa_comp_mask delete_guid_indexes = 0;
0648 ib_sa_comp_mask set_guid_indexes = 0;
0649 struct mlx4_sriov_alias_guid_info_rec_det *rec =
0650 &dev->sriov.alias_guid.ports_guid[port].
0651 all_rec_per_port[record_index];
0652
0653 for (i = 0; i < NUM_ALIAS_GUID_IN_REC; i++) {
0654 if (!(rec->guid_indexes &
0655 mlx4_ib_get_aguid_comp_mask_from_ix(i)))
0656 continue;
0657
0658 if (*(__be64 *)&rec->all_recs[i * GUID_REC_SIZE] ==
0659 cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL))
0660 delete_guid_indexes |=
0661 mlx4_ib_get_aguid_comp_mask_from_ix(i);
0662 else
0663 set_guid_indexes |=
0664 mlx4_ib_get_aguid_comp_mask_from_ix(i);
0665
0666 if (lowset_time_entry == -1 || rec->guids_retry_schedule[i] <=
0667 lowest_time) {
0668 lowset_time_entry = i;
0669 lowest_time = rec->guids_retry_schedule[i];
0670 }
0671 }
0672
0673 memcpy(&next_rec->rec_det, rec, sizeof(*rec));
0674 next_rec->port = port;
0675 next_rec->block_num = record_index;
0676
0677 if (*(__be64 *)&rec->all_recs[lowset_time_entry * GUID_REC_SIZE] ==
0678 cpu_to_be64(MLX4_GUID_FOR_DELETE_VAL)) {
0679 next_rec->rec_det.guid_indexes = delete_guid_indexes;
0680 next_rec->method = MLX4_GUID_INFO_RECORD_DELETE;
0681 } else {
0682 next_rec->rec_det.guid_indexes = set_guid_indexes;
0683 next_rec->method = MLX4_GUID_INFO_RECORD_SET;
0684 }
0685 }
0686
0687
0688
0689
0690 static int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port,
0691 int *resched_delay_sec)
0692 {
0693 int record_index = -1;
0694 u64 low_record_time = 0;
0695 struct mlx4_sriov_alias_guid_info_rec_det rec;
0696 int j;
0697
0698 for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
0699 rec = dev->sriov.alias_guid.ports_guid[port].
0700 all_rec_per_port[j];
0701 if (rec.status == MLX4_GUID_INFO_STATUS_IDLE &&
0702 rec.guid_indexes) {
0703 if (record_index == -1 ||
0704 rec.time_to_run < low_record_time) {
0705 record_index = j;
0706 low_record_time = rec.time_to_run;
0707 }
0708 }
0709 }
0710 if (resched_delay_sec) {
0711 u64 curr_time = ktime_get_boottime_ns();
0712
0713 *resched_delay_sec = (low_record_time < curr_time) ? 0 :
0714 div_u64((low_record_time - curr_time), NSEC_PER_SEC);
0715 }
0716
0717 return record_index;
0718 }
0719
0720
0721
0722 static int get_next_record_to_update(struct mlx4_ib_dev *dev, u8 port,
0723 struct mlx4_next_alias_guid_work *rec)
0724 {
0725 unsigned long flags;
0726 int record_index;
0727 int ret = 0;
0728
0729 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags);
0730 record_index = get_low_record_time_index(dev, port, NULL);
0731
0732 if (record_index < 0) {
0733 ret = -ENOENT;
0734 goto out;
0735 }
0736
0737 set_required_record(dev, port, rec, record_index);
0738 out:
0739 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags);
0740 return ret;
0741 }
0742
0743 static void alias_guid_work(struct work_struct *work)
0744 {
0745 struct delayed_work *delay = to_delayed_work(work);
0746 int ret = 0;
0747 struct mlx4_next_alias_guid_work *rec;
0748 struct mlx4_sriov_alias_guid_port_rec_det *sriov_alias_port =
0749 container_of(delay, struct mlx4_sriov_alias_guid_port_rec_det,
0750 alias_guid_work);
0751 struct mlx4_sriov_alias_guid *sriov_alias_guid = sriov_alias_port->parent;
0752 struct mlx4_ib_sriov *ib_sriov = container_of(sriov_alias_guid,
0753 struct mlx4_ib_sriov,
0754 alias_guid);
0755 struct mlx4_ib_dev *dev = container_of(ib_sriov, struct mlx4_ib_dev, sriov);
0756
0757 rec = kzalloc(sizeof *rec, GFP_KERNEL);
0758 if (!rec)
0759 return;
0760
0761 pr_debug("starting [port: %d]...\n", sriov_alias_port->port + 1);
0762 ret = get_next_record_to_update(dev, sriov_alias_port->port, rec);
0763 if (ret) {
0764 pr_debug("No more records to update.\n");
0765 goto out;
0766 }
0767
0768 set_guid_rec(&dev->ib_dev, rec);
0769 out:
0770 kfree(rec);
0771 }
0772
0773
0774 void mlx4_ib_init_alias_guid_work(struct mlx4_ib_dev *dev, int port)
0775 {
0776 unsigned long flags, flags1;
0777
0778 if (!mlx4_is_master(dev->dev))
0779 return;
0780 spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
0781 spin_lock_irqsave(&dev->sriov.alias_guid.ag_work_lock, flags1);
0782 if (!dev->sriov.is_going_down) {
0783
0784
0785
0786
0787 cancel_delayed_work(&dev->sriov.alias_guid.ports_guid[port].
0788 alias_guid_work);
0789 queue_delayed_work(dev->sriov.alias_guid.ports_guid[port].wq,
0790 &dev->sriov.alias_guid.ports_guid[port].alias_guid_work, 0);
0791 }
0792 spin_unlock_irqrestore(&dev->sriov.alias_guid.ag_work_lock, flags1);
0793 spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
0794 }
0795
0796 void mlx4_ib_destroy_alias_guid_service(struct mlx4_ib_dev *dev)
0797 {
0798 int i;
0799 struct mlx4_ib_sriov *sriov = &dev->sriov;
0800 struct mlx4_alias_guid_work_context *cb_ctx;
0801 struct mlx4_sriov_alias_guid_port_rec_det *det;
0802 struct ib_sa_query *sa_query;
0803 unsigned long flags;
0804
0805 for (i = 0 ; i < dev->num_ports; i++) {
0806 det = &sriov->alias_guid.ports_guid[i];
0807 cancel_delayed_work_sync(&det->alias_guid_work);
0808 spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags);
0809 while (!list_empty(&det->cb_list)) {
0810 cb_ctx = list_entry(det->cb_list.next,
0811 struct mlx4_alias_guid_work_context,
0812 list);
0813 sa_query = cb_ctx->sa_query;
0814 cb_ctx->sa_query = NULL;
0815 list_del(&cb_ctx->list);
0816 spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags);
0817 ib_sa_cancel_query(cb_ctx->query_id, sa_query);
0818 wait_for_completion(&cb_ctx->done);
0819 kfree(cb_ctx);
0820 spin_lock_irqsave(&sriov->alias_guid.ag_work_lock, flags);
0821 }
0822 spin_unlock_irqrestore(&sriov->alias_guid.ag_work_lock, flags);
0823 }
0824 for (i = 0 ; i < dev->num_ports; i++)
0825 destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
0826 ib_sa_unregister_client(dev->sriov.alias_guid.sa_client);
0827 kfree(dev->sriov.alias_guid.sa_client);
0828 }
0829
0830 int mlx4_ib_init_alias_guid_service(struct mlx4_ib_dev *dev)
0831 {
0832 char alias_wq_name[15];
0833 int ret = 0;
0834 int i, j;
0835 union ib_gid gid;
0836
0837 if (!mlx4_is_master(dev->dev))
0838 return 0;
0839 dev->sriov.alias_guid.sa_client =
0840 kzalloc(sizeof *dev->sriov.alias_guid.sa_client, GFP_KERNEL);
0841 if (!dev->sriov.alias_guid.sa_client)
0842 return -ENOMEM;
0843
0844 ib_sa_register_client(dev->sriov.alias_guid.sa_client);
0845
0846 spin_lock_init(&dev->sriov.alias_guid.ag_work_lock);
0847
0848 for (i = 1; i <= dev->num_ports; ++i) {
0849 if (dev->ib_dev.ops.query_gid(&dev->ib_dev, i, 0, &gid)) {
0850 ret = -EFAULT;
0851 goto err_unregister;
0852 }
0853 }
0854
0855 for (i = 0 ; i < dev->num_ports; i++) {
0856 memset(&dev->sriov.alias_guid.ports_guid[i], 0,
0857 sizeof (struct mlx4_sriov_alias_guid_port_rec_det));
0858 dev->sriov.alias_guid.ports_guid[i].state_flags |=
0859 GUID_STATE_NEED_PORT_INIT;
0860 for (j = 0; j < NUM_ALIAS_GUID_REC_IN_PORT; j++) {
0861
0862 memset(dev->sriov.alias_guid.ports_guid[i].
0863 all_rec_per_port[j].all_recs, 0xFF,
0864 sizeof(dev->sriov.alias_guid.ports_guid[i].
0865 all_rec_per_port[j].all_recs));
0866 }
0867 INIT_LIST_HEAD(&dev->sriov.alias_guid.ports_guid[i].cb_list);
0868
0869 if (mlx4_ib_sm_guid_assign)
0870 for (j = 1; j < NUM_ALIAS_GUID_PER_PORT; j++)
0871 mlx4_set_admin_guid(dev->dev, 0, j, i + 1);
0872 for (j = 0 ; j < NUM_ALIAS_GUID_REC_IN_PORT; j++)
0873 invalidate_guid_record(dev, i + 1, j);
0874
0875 dev->sriov.alias_guid.ports_guid[i].parent = &dev->sriov.alias_guid;
0876 dev->sriov.alias_guid.ports_guid[i].port = i;
0877
0878 snprintf(alias_wq_name, sizeof alias_wq_name, "alias_guid%d", i);
0879 dev->sriov.alias_guid.ports_guid[i].wq =
0880 alloc_ordered_workqueue(alias_wq_name, WQ_MEM_RECLAIM);
0881 if (!dev->sriov.alias_guid.ports_guid[i].wq) {
0882 ret = -ENOMEM;
0883 goto err_thread;
0884 }
0885 INIT_DELAYED_WORK(&dev->sriov.alias_guid.ports_guid[i].alias_guid_work,
0886 alias_guid_work);
0887 }
0888 return 0;
0889
0890 err_thread:
0891 for (--i; i >= 0; i--) {
0892 destroy_workqueue(dev->sriov.alias_guid.ports_guid[i].wq);
0893 dev->sriov.alias_guid.ports_guid[i].wq = NULL;
0894 }
0895
0896 err_unregister:
0897 ib_sa_unregister_client(dev->sriov.alias_guid.sa_client);
0898 kfree(dev->sriov.alias_guid.sa_client);
0899 dev->sriov.alias_guid.sa_client = NULL;
0900 pr_err("init_alias_guid_service: Failed. (ret:%d)\n", ret);
0901 return ret;
0902 }