diff options
author | Naresh Gottumukkala <bgottumukkala@emulex.com> | 2013-08-26 05:57:41 -0400 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2013-09-03 00:17:54 -0400 |
commit | c88bd03ffccdb069fd9541bea347bdab8f4e7e6a (patch) | |
tree | db276771ea7ac959dcd4159b1c6077f69eadd2e6 /drivers/infiniband | |
parent | d3cb6c0b2a0d9f507fff8d7c74b2b334d6751bee (diff) |
RDMA/ocrdma: Fix to work with even a single MSI-X vector
There are cases like SRIOV where can get only one MSI-X vector
allocated for RoCE. In that case we need to use the vector for both
data plane and control plane. We need to use EQ create version V2.
Signed-off-by: Naresh Gottumukkala <bgottumukkala@emulex.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/hw/ocrdma/ocrdma.h | 3 | ||||
-rw-r--r-- | drivers/infiniband/hw/ocrdma/ocrdma_hw.c | 133 |
2 files changed, 36 insertions, 100 deletions
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma.h b/drivers/infiniband/hw/ocrdma/ocrdma.h index 634c2e18521b..9cc966ab3b5a 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma.h +++ b/drivers/infiniband/hw/ocrdma/ocrdma.h | |||
@@ -132,8 +132,7 @@ struct ocrdma_dev { | |||
132 | struct ocrdma_cq **cq_tbl; | 132 | struct ocrdma_cq **cq_tbl; |
133 | struct ocrdma_qp **qp_tbl; | 133 | struct ocrdma_qp **qp_tbl; |
134 | 134 | ||
135 | struct ocrdma_eq meq; | 135 | struct ocrdma_eq *eq_tbl; |
136 | struct ocrdma_eq *qp_eq_tbl; | ||
137 | int eq_cnt; | 136 | int eq_cnt; |
138 | u16 base_eqid; | 137 | u16 base_eqid; |
139 | u16 max_eq; | 138 | u16 max_eq; |
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c index 6a62b2372fba..1b14ef811b36 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c | |||
@@ -364,22 +364,6 @@ static void ocrdma_build_q_pages(struct ocrdma_pa *q_pa, int cnt, | |||
364 | } | 364 | } |
365 | } | 365 | } |
366 | 366 | ||
367 | static void ocrdma_assign_eq_vect_gen2(struct ocrdma_dev *dev, | ||
368 | struct ocrdma_eq *eq) | ||
369 | { | ||
370 | /* assign vector and update vector id for next EQ */ | ||
371 | eq->vector = dev->nic_info.msix.start_vector; | ||
372 | dev->nic_info.msix.start_vector += 1; | ||
373 | } | ||
374 | |||
375 | static void ocrdma_free_eq_vect_gen2(struct ocrdma_dev *dev) | ||
376 | { | ||
377 | /* this assumes that EQs are freed in exactly reverse order | ||
378 | * as its allocation. | ||
379 | */ | ||
380 | dev->nic_info.msix.start_vector -= 1; | ||
381 | } | ||
382 | |||
383 | static int ocrdma_mbx_delete_q(struct ocrdma_dev *dev, struct ocrdma_queue_info *q, | 367 | static int ocrdma_mbx_delete_q(struct ocrdma_dev *dev, struct ocrdma_queue_info *q, |
384 | int queue_type) | 368 | int queue_type) |
385 | { | 369 | { |
@@ -420,11 +404,8 @@ static int ocrdma_mbx_create_eq(struct ocrdma_dev *dev, struct ocrdma_eq *eq) | |||
420 | memset(cmd, 0, sizeof(*cmd)); | 404 | memset(cmd, 0, sizeof(*cmd)); |
421 | ocrdma_init_mch(&cmd->req, OCRDMA_CMD_CREATE_EQ, OCRDMA_SUBSYS_COMMON, | 405 | ocrdma_init_mch(&cmd->req, OCRDMA_CMD_CREATE_EQ, OCRDMA_SUBSYS_COMMON, |
422 | sizeof(*cmd)); | 406 | sizeof(*cmd)); |
423 | if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) | ||
424 | cmd->req.rsvd_version = 0; | ||
425 | else | ||
426 | cmd->req.rsvd_version = 2; | ||
427 | 407 | ||
408 | cmd->req.rsvd_version = 2; | ||
428 | cmd->num_pages = 4; | 409 | cmd->num_pages = 4; |
429 | cmd->valid = OCRDMA_CREATE_EQ_VALID; | 410 | cmd->valid = OCRDMA_CREATE_EQ_VALID; |
430 | cmd->cnt = 4 << OCRDMA_CREATE_EQ_CNT_SHIFT; | 411 | cmd->cnt = 4 << OCRDMA_CREATE_EQ_CNT_SHIFT; |
@@ -435,12 +416,7 @@ static int ocrdma_mbx_create_eq(struct ocrdma_dev *dev, struct ocrdma_eq *eq) | |||
435 | NULL); | 416 | NULL); |
436 | if (!status) { | 417 | if (!status) { |
437 | eq->q.id = rsp->vector_eqid & 0xffff; | 418 | eq->q.id = rsp->vector_eqid & 0xffff; |
438 | if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) { | 419 | eq->vector = (rsp->vector_eqid >> 16) & 0xffff; |
439 | ocrdma_assign_eq_vect_gen2(dev, eq); | ||
440 | } else { | ||
441 | eq->vector = (rsp->vector_eqid >> 16) & 0xffff; | ||
442 | dev->nic_info.msix.start_vector += 1; | ||
443 | } | ||
444 | eq->q.created = true; | 420 | eq->q.created = true; |
445 | } | 421 | } |
446 | return status; | 422 | return status; |
@@ -483,8 +459,6 @@ static void _ocrdma_destroy_eq(struct ocrdma_dev *dev, struct ocrdma_eq *eq) | |||
483 | { | 459 | { |
484 | if (eq->q.created) { | 460 | if (eq->q.created) { |
485 | ocrdma_mbx_delete_q(dev, &eq->q, QTYPE_EQ); | 461 | ocrdma_mbx_delete_q(dev, &eq->q, QTYPE_EQ); |
486 | if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) | ||
487 | ocrdma_free_eq_vect_gen2(dev); | ||
488 | ocrdma_free_q(dev, &eq->q); | 462 | ocrdma_free_q(dev, &eq->q); |
489 | } | 463 | } |
490 | } | 464 | } |
@@ -503,13 +477,12 @@ static void ocrdma_destroy_eq(struct ocrdma_dev *dev, struct ocrdma_eq *eq) | |||
503 | _ocrdma_destroy_eq(dev, eq); | 477 | _ocrdma_destroy_eq(dev, eq); |
504 | } | 478 | } |
505 | 479 | ||
506 | static void ocrdma_destroy_qp_eqs(struct ocrdma_dev *dev) | 480 | static void ocrdma_destroy_eqs(struct ocrdma_dev *dev) |
507 | { | 481 | { |
508 | int i; | 482 | int i; |
509 | 483 | ||
510 | /* deallocate the data path eqs */ | ||
511 | for (i = 0; i < dev->eq_cnt; i++) | 484 | for (i = 0; i < dev->eq_cnt; i++) |
512 | ocrdma_destroy_eq(dev, &dev->qp_eq_tbl[i]); | 485 | ocrdma_destroy_eq(dev, &dev->eq_tbl[i]); |
513 | } | 486 | } |
514 | 487 | ||
515 | static int ocrdma_mbx_mq_cq_create(struct ocrdma_dev *dev, | 488 | static int ocrdma_mbx_mq_cq_create(struct ocrdma_dev *dev, |
@@ -598,7 +571,7 @@ static int ocrdma_create_mq(struct ocrdma_dev *dev) | |||
598 | if (status) | 571 | if (status) |
599 | goto alloc_err; | 572 | goto alloc_err; |
600 | 573 | ||
601 | status = ocrdma_mbx_mq_cq_create(dev, &dev->mq.cq, &dev->meq.q); | 574 | status = ocrdma_mbx_mq_cq_create(dev, &dev->mq.cq, &dev->eq_tbl[0].q); |
602 | if (status) | 575 | if (status) |
603 | goto mbx_cq_free; | 576 | goto mbx_cq_free; |
604 | 577 | ||
@@ -1304,19 +1277,19 @@ static u16 ocrdma_bind_eq(struct ocrdma_dev *dev) | |||
1304 | u16 eq_id; | 1277 | u16 eq_id; |
1305 | 1278 | ||
1306 | mutex_lock(&dev->dev_lock); | 1279 | mutex_lock(&dev->dev_lock); |
1307 | cq_cnt = dev->qp_eq_tbl[0].cq_cnt; | 1280 | cq_cnt = dev->eq_tbl[0].cq_cnt; |
1308 | eq_id = dev->qp_eq_tbl[0].q.id; | 1281 | eq_id = dev->eq_tbl[0].q.id; |
1309 | /* find the EQ which is has the least number of | 1282 | /* find the EQ which is has the least number of |
1310 | * CQs associated with it. | 1283 | * CQs associated with it. |
1311 | */ | 1284 | */ |
1312 | for (i = 0; i < dev->eq_cnt; i++) { | 1285 | for (i = 0; i < dev->eq_cnt; i++) { |
1313 | if (dev->qp_eq_tbl[i].cq_cnt < cq_cnt) { | 1286 | if (dev->eq_tbl[i].cq_cnt < cq_cnt) { |
1314 | cq_cnt = dev->qp_eq_tbl[i].cq_cnt; | 1287 | cq_cnt = dev->eq_tbl[i].cq_cnt; |
1315 | eq_id = dev->qp_eq_tbl[i].q.id; | 1288 | eq_id = dev->eq_tbl[i].q.id; |
1316 | selected_eq = i; | 1289 | selected_eq = i; |
1317 | } | 1290 | } |
1318 | } | 1291 | } |
1319 | dev->qp_eq_tbl[selected_eq].cq_cnt += 1; | 1292 | dev->eq_tbl[selected_eq].cq_cnt += 1; |
1320 | mutex_unlock(&dev->dev_lock); | 1293 | mutex_unlock(&dev->dev_lock); |
1321 | return eq_id; | 1294 | return eq_id; |
1322 | } | 1295 | } |
@@ -1327,9 +1300,9 @@ static void ocrdma_unbind_eq(struct ocrdma_dev *dev, u16 eq_id) | |||
1327 | 1300 | ||
1328 | mutex_lock(&dev->dev_lock); | 1301 | mutex_lock(&dev->dev_lock); |
1329 | for (i = 0; i < dev->eq_cnt; i++) { | 1302 | for (i = 0; i < dev->eq_cnt; i++) { |
1330 | if (dev->qp_eq_tbl[i].q.id != eq_id) | 1303 | if (dev->eq_tbl[i].q.id != eq_id) |
1331 | continue; | 1304 | continue; |
1332 | dev->qp_eq_tbl[i].cq_cnt -= 1; | 1305 | dev->eq_tbl[i].cq_cnt -= 1; |
1333 | break; | 1306 | break; |
1334 | } | 1307 | } |
1335 | mutex_unlock(&dev->dev_lock); | 1308 | mutex_unlock(&dev->dev_lock); |
@@ -2434,38 +2407,7 @@ int ocrdma_free_av(struct ocrdma_dev *dev, struct ocrdma_ah *ah) | |||
2434 | return 0; | 2407 | return 0; |
2435 | } | 2408 | } |
2436 | 2409 | ||
2437 | static int ocrdma_create_mq_eq(struct ocrdma_dev *dev) | 2410 | static int ocrdma_create_eqs(struct ocrdma_dev *dev) |
2438 | { | ||
2439 | int status; | ||
2440 | int irq; | ||
2441 | unsigned long flags = 0; | ||
2442 | int num_eq = 0; | ||
2443 | |||
2444 | if (dev->nic_info.intr_mode == BE_INTERRUPT_MODE_INTX) { | ||
2445 | flags = IRQF_SHARED; | ||
2446 | } else { | ||
2447 | num_eq = dev->nic_info.msix.num_vectors - | ||
2448 | dev->nic_info.msix.start_vector; | ||
2449 | /* minimum two vectors/eq are required for rdma to work. | ||
2450 | * one for control path and one for data path. | ||
2451 | */ | ||
2452 | if (num_eq < 2) | ||
2453 | return -EBUSY; | ||
2454 | } | ||
2455 | |||
2456 | status = ocrdma_create_eq(dev, &dev->meq, OCRDMA_EQ_LEN); | ||
2457 | if (status) | ||
2458 | return status; | ||
2459 | sprintf(dev->meq.irq_name, "ocrdma_mq%d", dev->id); | ||
2460 | irq = ocrdma_get_irq(dev, &dev->meq); | ||
2461 | status = request_irq(irq, ocrdma_irq_handler, flags, dev->meq.irq_name, | ||
2462 | &dev->meq); | ||
2463 | if (status) | ||
2464 | _ocrdma_destroy_eq(dev, &dev->meq); | ||
2465 | return status; | ||
2466 | } | ||
2467 | |||
2468 | static int ocrdma_create_qp_eqs(struct ocrdma_dev *dev) | ||
2469 | { | 2411 | { |
2470 | int num_eq, i, status = 0; | 2412 | int num_eq, i, status = 0; |
2471 | int irq; | 2413 | int irq; |
@@ -2480,46 +2422,43 @@ static int ocrdma_create_qp_eqs(struct ocrdma_dev *dev) | |||
2480 | num_eq = min_t(u32, num_eq, num_online_cpus()); | 2422 | num_eq = min_t(u32, num_eq, num_online_cpus()); |
2481 | } | 2423 | } |
2482 | 2424 | ||
2483 | dev->qp_eq_tbl = kzalloc(sizeof(struct ocrdma_eq) * num_eq, GFP_KERNEL); | 2425 | if (!num_eq) |
2484 | if (!dev->qp_eq_tbl) | 2426 | return -EINVAL; |
2427 | |||
2428 | dev->eq_tbl = kzalloc(sizeof(struct ocrdma_eq) * num_eq, GFP_KERNEL); | ||
2429 | if (!dev->eq_tbl) | ||
2485 | return -ENOMEM; | 2430 | return -ENOMEM; |
2486 | 2431 | ||
2487 | for (i = 0; i < num_eq; i++) { | 2432 | for (i = 0; i < num_eq; i++) { |
2488 | status = ocrdma_create_eq(dev, &dev->qp_eq_tbl[i], | 2433 | status = ocrdma_create_eq(dev, &dev->eq_tbl[i], |
2489 | OCRDMA_EQ_LEN); | 2434 | OCRDMA_EQ_LEN); |
2490 | if (status) { | 2435 | if (status) { |
2491 | status = -EINVAL; | 2436 | status = -EINVAL; |
2492 | break; | 2437 | break; |
2493 | } | 2438 | } |
2494 | sprintf(dev->qp_eq_tbl[i].irq_name, "ocrdma_qp%d-%d", | 2439 | sprintf(dev->eq_tbl[i].irq_name, "ocrdma%d-%d", |
2495 | dev->id, i); | 2440 | dev->id, i); |
2496 | irq = ocrdma_get_irq(dev, &dev->qp_eq_tbl[i]); | 2441 | irq = ocrdma_get_irq(dev, &dev->eq_tbl[i]); |
2497 | status = request_irq(irq, ocrdma_irq_handler, flags, | 2442 | status = request_irq(irq, ocrdma_irq_handler, flags, |
2498 | dev->qp_eq_tbl[i].irq_name, | 2443 | dev->eq_tbl[i].irq_name, |
2499 | &dev->qp_eq_tbl[i]); | 2444 | &dev->eq_tbl[i]); |
2500 | if (status) { | 2445 | if (status) |
2501 | _ocrdma_destroy_eq(dev, &dev->qp_eq_tbl[i]); | 2446 | goto done; |
2502 | status = -EINVAL; | ||
2503 | break; | ||
2504 | } | ||
2505 | dev->eq_cnt += 1; | 2447 | dev->eq_cnt += 1; |
2506 | } | 2448 | } |
2507 | /* one eq is sufficient for data path to work */ | 2449 | /* one eq is sufficient for data path to work */ |
2508 | if (dev->eq_cnt >= 1) | 2450 | return 0; |
2509 | return 0; | 2451 | done: |
2510 | ocrdma_destroy_qp_eqs(dev); | 2452 | ocrdma_destroy_eqs(dev); |
2511 | return status; | 2453 | return status; |
2512 | } | 2454 | } |
2513 | 2455 | ||
2514 | int ocrdma_init_hw(struct ocrdma_dev *dev) | 2456 | int ocrdma_init_hw(struct ocrdma_dev *dev) |
2515 | { | 2457 | { |
2516 | int status; | 2458 | int status; |
2517 | /* set up control path eq */ | 2459 | |
2518 | status = ocrdma_create_mq_eq(dev); | 2460 | /* create the eqs */ |
2519 | if (status) | 2461 | status = ocrdma_create_eqs(dev); |
2520 | return status; | ||
2521 | /* set up data path eq */ | ||
2522 | status = ocrdma_create_qp_eqs(dev); | ||
2523 | if (status) | 2462 | if (status) |
2524 | goto qpeq_err; | 2463 | goto qpeq_err; |
2525 | status = ocrdma_create_mq(dev); | 2464 | status = ocrdma_create_mq(dev); |
@@ -2542,9 +2481,8 @@ int ocrdma_init_hw(struct ocrdma_dev *dev) | |||
2542 | conf_err: | 2481 | conf_err: |
2543 | ocrdma_destroy_mq(dev); | 2482 | ocrdma_destroy_mq(dev); |
2544 | mq_err: | 2483 | mq_err: |
2545 | ocrdma_destroy_qp_eqs(dev); | 2484 | ocrdma_destroy_eqs(dev); |
2546 | qpeq_err: | 2485 | qpeq_err: |
2547 | ocrdma_destroy_eq(dev, &dev->meq); | ||
2548 | pr_err("%s() status=%d\n", __func__, status); | 2486 | pr_err("%s() status=%d\n", __func__, status); |
2549 | return status; | 2487 | return status; |
2550 | } | 2488 | } |
@@ -2553,10 +2491,9 @@ void ocrdma_cleanup_hw(struct ocrdma_dev *dev) | |||
2553 | { | 2491 | { |
2554 | ocrdma_mbx_delete_ah_tbl(dev); | 2492 | ocrdma_mbx_delete_ah_tbl(dev); |
2555 | 2493 | ||
2556 | /* cleanup the data path eqs */ | 2494 | /* cleanup the eqs */ |
2557 | ocrdma_destroy_qp_eqs(dev); | 2495 | ocrdma_destroy_eqs(dev); |
2558 | 2496 | ||
2559 | /* cleanup the control path */ | 2497 | /* cleanup the control path */ |
2560 | ocrdma_destroy_mq(dev); | 2498 | ocrdma_destroy_mq(dev); |
2561 | ocrdma_destroy_eq(dev, &dev->meq); | ||
2562 | } | 2499 | } |