diff options
-rw-r--r-- | drivers/infiniband/hw/ehca/ehca_classes.h | 9 | ||||
-rw-r--r-- | drivers/infiniband/hw/ehca/ehca_qes.h | 1 | ||||
-rw-r--r-- | drivers/infiniband/hw/ehca/ehca_qp.c | 48 | ||||
-rw-r--r-- | drivers/infiniband/hw/ehca/ehca_reqs.c | 60 |
4 files changed, 92 insertions, 26 deletions
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 0b0618edd645..1ab919f836a8 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h | |||
@@ -156,6 +156,14 @@ struct ehca_mod_qp_parm { | |||
156 | 156 | ||
157 | #define EHCA_MOD_QP_PARM_MAX 4 | 157 | #define EHCA_MOD_QP_PARM_MAX 4 |
158 | 158 | ||
159 | #define QMAP_IDX_MASK 0xFFFFULL | ||
160 | |||
161 | /* struct for tracking if cqes have been reported to the application */ | ||
162 | struct ehca_qmap_entry { | ||
163 | u16 app_wr_id; | ||
164 | u16 reported; | ||
165 | }; | ||
166 | |||
159 | struct ehca_qp { | 167 | struct ehca_qp { |
160 | union { | 168 | union { |
161 | struct ib_qp ib_qp; | 169 | struct ib_qp ib_qp; |
@@ -165,6 +173,7 @@ struct ehca_qp { | |||
165 | enum ehca_ext_qp_type ext_type; | 173 | enum ehca_ext_qp_type ext_type; |
166 | enum ib_qp_state state; | 174 | enum ib_qp_state state; |
167 | struct ipz_queue ipz_squeue; | 175 | struct ipz_queue ipz_squeue; |
176 | struct ehca_qmap_entry *sq_map; | ||
168 | struct ipz_queue ipz_rqueue; | 177 | struct ipz_queue ipz_rqueue; |
169 | struct h_galpas galpas; | 178 | struct h_galpas galpas; |
170 | u32 qkey; | 179 | u32 qkey; |
diff --git a/drivers/infiniband/hw/ehca/ehca_qes.h b/drivers/infiniband/hw/ehca/ehca_qes.h index 818803057ebf..5d28e3e98a20 100644 --- a/drivers/infiniband/hw/ehca/ehca_qes.h +++ b/drivers/infiniband/hw/ehca/ehca_qes.h | |||
@@ -213,6 +213,7 @@ struct ehca_wqe { | |||
213 | #define WC_STATUS_ERROR_BIT 0x80000000 | 213 | #define WC_STATUS_ERROR_BIT 0x80000000 |
214 | #define WC_STATUS_REMOTE_ERROR_FLAGS 0x0000F800 | 214 | #define WC_STATUS_REMOTE_ERROR_FLAGS 0x0000F800 |
215 | #define WC_STATUS_PURGE_BIT 0x10 | 215 | #define WC_STATUS_PURGE_BIT 0x10 |
216 | #define WC_SEND_RECEIVE_BIT 0x80 | ||
216 | 217 | ||
217 | struct ehca_cqe { | 218 | struct ehca_cqe { |
218 | u64 work_request_id; | 219 | u64 work_request_id; |
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index ea13efddf175..b6bcee036734 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c | |||
@@ -412,6 +412,7 @@ static struct ehca_qp *internal_create_qp( | |||
412 | struct ehca_shca *shca = container_of(pd->device, struct ehca_shca, | 412 | struct ehca_shca *shca = container_of(pd->device, struct ehca_shca, |
413 | ib_device); | 413 | ib_device); |
414 | struct ib_ucontext *context = NULL; | 414 | struct ib_ucontext *context = NULL; |
415 | u32 nr_qes; | ||
415 | u64 h_ret; | 416 | u64 h_ret; |
416 | int is_llqp = 0, has_srq = 0; | 417 | int is_llqp = 0, has_srq = 0; |
417 | int qp_type, max_send_sge, max_recv_sge, ret; | 418 | int qp_type, max_send_sge, max_recv_sge, ret; |
@@ -715,6 +716,15 @@ static struct ehca_qp *internal_create_qp( | |||
715 | "and pages ret=%i", ret); | 716 | "and pages ret=%i", ret); |
716 | goto create_qp_exit2; | 717 | goto create_qp_exit2; |
717 | } | 718 | } |
719 | nr_qes = my_qp->ipz_squeue.queue_length / | ||
720 | my_qp->ipz_squeue.qe_size; | ||
721 | my_qp->sq_map = vmalloc(nr_qes * | ||
722 | sizeof(struct ehca_qmap_entry)); | ||
723 | if (!my_qp->sq_map) { | ||
724 | ehca_err(pd->device, "Couldn't allocate squeue " | ||
725 | "map ret=%i", ret); | ||
726 | goto create_qp_exit3; | ||
727 | } | ||
718 | } | 728 | } |
719 | 729 | ||
720 | if (HAS_RQ(my_qp)) { | 730 | if (HAS_RQ(my_qp)) { |
@@ -724,7 +734,7 @@ static struct ehca_qp *internal_create_qp( | |||
724 | if (ret) { | 734 | if (ret) { |
725 | ehca_err(pd->device, "Couldn't initialize rqueue " | 735 | ehca_err(pd->device, "Couldn't initialize rqueue " |
726 | "and pages ret=%i", ret); | 736 | "and pages ret=%i", ret); |
727 | goto create_qp_exit3; | 737 | goto create_qp_exit4; |
728 | } | 738 | } |
729 | } | 739 | } |
730 | 740 | ||
@@ -770,7 +780,7 @@ static struct ehca_qp *internal_create_qp( | |||
770 | if (!my_qp->mod_qp_parm) { | 780 | if (!my_qp->mod_qp_parm) { |
771 | ehca_err(pd->device, | 781 | ehca_err(pd->device, |
772 | "Could not alloc mod_qp_parm"); | 782 | "Could not alloc mod_qp_parm"); |
773 | goto create_qp_exit4; | 783 | goto create_qp_exit5; |
774 | } | 784 | } |
775 | } | 785 | } |
776 | } | 786 | } |
@@ -780,7 +790,7 @@ static struct ehca_qp *internal_create_qp( | |||
780 | h_ret = ehca_define_sqp(shca, my_qp, init_attr); | 790 | h_ret = ehca_define_sqp(shca, my_qp, init_attr); |
781 | if (h_ret != H_SUCCESS) { | 791 | if (h_ret != H_SUCCESS) { |
782 | ret = ehca2ib_return_code(h_ret); | 792 | ret = ehca2ib_return_code(h_ret); |
783 | goto create_qp_exit5; | 793 | goto create_qp_exit6; |
784 | } | 794 | } |
785 | } | 795 | } |
786 | 796 | ||
@@ -789,7 +799,7 @@ static struct ehca_qp *internal_create_qp( | |||
789 | if (ret) { | 799 | if (ret) { |
790 | ehca_err(pd->device, | 800 | ehca_err(pd->device, |
791 | "Couldn't assign qp to send_cq ret=%i", ret); | 801 | "Couldn't assign qp to send_cq ret=%i", ret); |
792 | goto create_qp_exit5; | 802 | goto create_qp_exit6; |
793 | } | 803 | } |
794 | } | 804 | } |
795 | 805 | ||
@@ -815,22 +825,26 @@ static struct ehca_qp *internal_create_qp( | |||
815 | if (ib_copy_to_udata(udata, &resp, sizeof resp)) { | 825 | if (ib_copy_to_udata(udata, &resp, sizeof resp)) { |
816 | ehca_err(pd->device, "Copy to udata failed"); | 826 | ehca_err(pd->device, "Copy to udata failed"); |
817 | ret = -EINVAL; | 827 | ret = -EINVAL; |
818 | goto create_qp_exit6; | 828 | goto create_qp_exit7; |
819 | } | 829 | } |
820 | } | 830 | } |
821 | 831 | ||
822 | return my_qp; | 832 | return my_qp; |
823 | 833 | ||
824 | create_qp_exit6: | 834 | create_qp_exit7: |
825 | ehca_cq_unassign_qp(my_qp->send_cq, my_qp->real_qp_num); | 835 | ehca_cq_unassign_qp(my_qp->send_cq, my_qp->real_qp_num); |
826 | 836 | ||
827 | create_qp_exit5: | 837 | create_qp_exit6: |
828 | kfree(my_qp->mod_qp_parm); | 838 | kfree(my_qp->mod_qp_parm); |
829 | 839 | ||
830 | create_qp_exit4: | 840 | create_qp_exit5: |
831 | if (HAS_RQ(my_qp)) | 841 | if (HAS_RQ(my_qp)) |
832 | ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); | 842 | ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); |
833 | 843 | ||
844 | create_qp_exit4: | ||
845 | if (HAS_SQ(my_qp)) | ||
846 | vfree(my_qp->sq_map); | ||
847 | |||
834 | create_qp_exit3: | 848 | create_qp_exit3: |
835 | if (HAS_SQ(my_qp)) | 849 | if (HAS_SQ(my_qp)) |
836 | ipz_queue_dtor(my_pd, &my_qp->ipz_squeue); | 850 | ipz_queue_dtor(my_pd, &my_qp->ipz_squeue); |
@@ -1534,8 +1548,6 @@ static int internal_modify_qp(struct ib_qp *ibqp, | |||
1534 | if (attr_mask & IB_QP_QKEY) | 1548 | if (attr_mask & IB_QP_QKEY) |
1535 | my_qp->qkey = attr->qkey; | 1549 | my_qp->qkey = attr->qkey; |
1536 | 1550 | ||
1537 | my_qp->state = qp_new_state; | ||
1538 | |||
1539 | modify_qp_exit2: | 1551 | modify_qp_exit2: |
1540 | if (squeue_locked) { /* this means: sqe -> rts */ | 1552 | if (squeue_locked) { /* this means: sqe -> rts */ |
1541 | spin_unlock_irqrestore(&my_qp->spinlock_s, flags); | 1553 | spin_unlock_irqrestore(&my_qp->spinlock_s, flags); |
@@ -1551,6 +1563,8 @@ modify_qp_exit1: | |||
1551 | int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, | 1563 | int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, |
1552 | struct ib_udata *udata) | 1564 | struct ib_udata *udata) |
1553 | { | 1565 | { |
1566 | int ret = 0; | ||
1567 | |||
1554 | struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca, | 1568 | struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca, |
1555 | ib_device); | 1569 | ib_device); |
1556 | struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp); | 1570 | struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp); |
@@ -1597,12 +1611,18 @@ int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, | |||
1597 | attr->qp_state, my_qp->init_attr.port_num, | 1611 | attr->qp_state, my_qp->init_attr.port_num, |
1598 | ibqp->qp_type); | 1612 | ibqp->qp_type); |
1599 | spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); | 1613 | spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); |
1600 | return 0; | 1614 | goto out; |
1601 | } | 1615 | } |
1602 | spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); | 1616 | spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); |
1603 | } | 1617 | } |
1604 | 1618 | ||
1605 | return internal_modify_qp(ibqp, attr, attr_mask, 0); | 1619 | ret = internal_modify_qp(ibqp, attr, attr_mask, 0); |
1620 | |||
1621 | out: | ||
1622 | if ((ret == 0) && (attr_mask & IB_QP_STATE)) | ||
1623 | my_qp->state = attr->qp_state; | ||
1624 | |||
1625 | return ret; | ||
1606 | } | 1626 | } |
1607 | 1627 | ||
1608 | void ehca_recover_sqp(struct ib_qp *sqp) | 1628 | void ehca_recover_sqp(struct ib_qp *sqp) |
@@ -1973,8 +1993,10 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, | |||
1973 | 1993 | ||
1974 | if (HAS_RQ(my_qp)) | 1994 | if (HAS_RQ(my_qp)) |
1975 | ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); | 1995 | ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); |
1976 | if (HAS_SQ(my_qp)) | 1996 | if (HAS_SQ(my_qp)) { |
1977 | ipz_queue_dtor(my_pd, &my_qp->ipz_squeue); | 1997 | ipz_queue_dtor(my_pd, &my_qp->ipz_squeue); |
1998 | vfree(my_qp->sq_map); | ||
1999 | } | ||
1978 | kmem_cache_free(qp_cache, my_qp); | 2000 | kmem_cache_free(qp_cache, my_qp); |
1979 | atomic_dec(&shca->num_qps); | 2001 | atomic_dec(&shca->num_qps); |
1980 | return 0; | 2002 | return 0; |
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c index 898c8b5c38dd..4426d82fe798 100644 --- a/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/drivers/infiniband/hw/ehca/ehca_reqs.c | |||
@@ -139,6 +139,7 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr) | |||
139 | static inline int ehca_write_swqe(struct ehca_qp *qp, | 139 | static inline int ehca_write_swqe(struct ehca_qp *qp, |
140 | struct ehca_wqe *wqe_p, | 140 | struct ehca_wqe *wqe_p, |
141 | const struct ib_send_wr *send_wr, | 141 | const struct ib_send_wr *send_wr, |
142 | u32 sq_map_idx, | ||
142 | int hidden) | 143 | int hidden) |
143 | { | 144 | { |
144 | u32 idx; | 145 | u32 idx; |
@@ -157,7 +158,11 @@ static inline int ehca_write_swqe(struct ehca_qp *qp, | |||
157 | /* clear wqe header until sglist */ | 158 | /* clear wqe header until sglist */ |
158 | memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list)); | 159 | memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list)); |
159 | 160 | ||
160 | wqe_p->work_request_id = send_wr->wr_id; | 161 | wqe_p->work_request_id = send_wr->wr_id & ~QMAP_IDX_MASK; |
162 | wqe_p->work_request_id |= sq_map_idx & QMAP_IDX_MASK; | ||
163 | |||
164 | qp->sq_map[sq_map_idx].app_wr_id = send_wr->wr_id & QMAP_IDX_MASK; | ||
165 | qp->sq_map[sq_map_idx].reported = 0; | ||
161 | 166 | ||
162 | switch (send_wr->opcode) { | 167 | switch (send_wr->opcode) { |
163 | case IB_WR_SEND: | 168 | case IB_WR_SEND: |
@@ -381,6 +386,7 @@ static inline int post_one_send(struct ehca_qp *my_qp, | |||
381 | { | 386 | { |
382 | struct ehca_wqe *wqe_p; | 387 | struct ehca_wqe *wqe_p; |
383 | int ret; | 388 | int ret; |
389 | u32 sq_map_idx; | ||
384 | u64 start_offset = my_qp->ipz_squeue.current_q_offset; | 390 | u64 start_offset = my_qp->ipz_squeue.current_q_offset; |
385 | 391 | ||
386 | /* get pointer next to free WQE */ | 392 | /* get pointer next to free WQE */ |
@@ -393,8 +399,15 @@ static inline int post_one_send(struct ehca_qp *my_qp, | |||
393 | "qp_num=%x", my_qp->ib_qp.qp_num); | 399 | "qp_num=%x", my_qp->ib_qp.qp_num); |
394 | return -ENOMEM; | 400 | return -ENOMEM; |
395 | } | 401 | } |
402 | |||
403 | /* | ||
404 | * Get the index of the WQE in the send queue. The same index is used | ||
405 | * for writing into the sq_map. | ||
406 | */ | ||
407 | sq_map_idx = start_offset / my_qp->ipz_squeue.qe_size; | ||
408 | |||
396 | /* write a SEND WQE into the QUEUE */ | 409 | /* write a SEND WQE into the QUEUE */ |
397 | ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr, hidden); | 410 | ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr, sq_map_idx, hidden); |
398 | /* | 411 | /* |
399 | * if something failed, | 412 | * if something failed, |
400 | * reset the free entry pointer to the start value | 413 | * reset the free entry pointer to the start value |
@@ -589,7 +602,7 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc) | |||
589 | struct ehca_qp *my_qp; | 602 | struct ehca_qp *my_qp; |
590 | int cqe_count = 0, is_error; | 603 | int cqe_count = 0, is_error; |
591 | 604 | ||
592 | poll_cq_one_read_cqe: | 605 | repoll: |
593 | cqe = (struct ehca_cqe *) | 606 | cqe = (struct ehca_cqe *) |
594 | ipz_qeit_get_inc_valid(&my_cq->ipz_queue); | 607 | ipz_qeit_get_inc_valid(&my_cq->ipz_queue); |
595 | if (!cqe) { | 608 | if (!cqe) { |
@@ -617,7 +630,7 @@ poll_cq_one_read_cqe: | |||
617 | ehca_dmp(cqe, 64, "cq_num=%x qp_num=%x", | 630 | ehca_dmp(cqe, 64, "cq_num=%x qp_num=%x", |
618 | my_cq->cq_number, cqe->local_qp_number); | 631 | my_cq->cq_number, cqe->local_qp_number); |
619 | /* ignore this purged cqe */ | 632 | /* ignore this purged cqe */ |
620 | goto poll_cq_one_read_cqe; | 633 | goto repoll; |
621 | } | 634 | } |
622 | spin_lock_irqsave(&qp->spinlock_s, flags); | 635 | spin_lock_irqsave(&qp->spinlock_s, flags); |
623 | purgeflag = qp->sqerr_purgeflag; | 636 | purgeflag = qp->sqerr_purgeflag; |
@@ -636,7 +649,7 @@ poll_cq_one_read_cqe: | |||
636 | * that caused sqe and turn off purge flag | 649 | * that caused sqe and turn off purge flag |
637 | */ | 650 | */ |
638 | qp->sqerr_purgeflag = 0; | 651 | qp->sqerr_purgeflag = 0; |
639 | goto poll_cq_one_read_cqe; | 652 | goto repoll; |
640 | } | 653 | } |
641 | } | 654 | } |
642 | 655 | ||
@@ -654,8 +667,34 @@ poll_cq_one_read_cqe: | |||
654 | my_cq, my_cq->cq_number); | 667 | my_cq, my_cq->cq_number); |
655 | } | 668 | } |
656 | 669 | ||
657 | /* we got a completion! */ | 670 | read_lock(&ehca_qp_idr_lock); |
658 | wc->wr_id = cqe->work_request_id; | 671 | my_qp = idr_find(&ehca_qp_idr, cqe->qp_token); |
672 | read_unlock(&ehca_qp_idr_lock); | ||
673 | if (!my_qp) | ||
674 | goto repoll; | ||
675 | wc->qp = &my_qp->ib_qp; | ||
676 | |||
677 | if (!(cqe->w_completion_flags & WC_SEND_RECEIVE_BIT)) { | ||
678 | struct ehca_qmap_entry *qmap_entry; | ||
679 | /* | ||
680 | * We got a send completion and need to restore the original | ||
681 | * wr_id. | ||
682 | */ | ||
683 | qmap_entry = &my_qp->sq_map[cqe->work_request_id & | ||
684 | QMAP_IDX_MASK]; | ||
685 | |||
686 | if (qmap_entry->reported) { | ||
687 | ehca_warn(cq->device, "Double cqe on qp_num=%#x", | ||
688 | my_qp->real_qp_num); | ||
689 | /* found a double cqe, discard it and read next one */ | ||
690 | goto repoll; | ||
691 | } | ||
692 | wc->wr_id = cqe->work_request_id & ~QMAP_IDX_MASK; | ||
693 | wc->wr_id |= qmap_entry->app_wr_id; | ||
694 | qmap_entry->reported = 1; | ||
695 | } else | ||
696 | /* We got a receive completion. */ | ||
697 | wc->wr_id = cqe->work_request_id; | ||
659 | 698 | ||
660 | /* eval ib_wc_opcode */ | 699 | /* eval ib_wc_opcode */ |
661 | wc->opcode = ib_wc_opcode[cqe->optype]-1; | 700 | wc->opcode = ib_wc_opcode[cqe->optype]-1; |
@@ -667,7 +706,7 @@ poll_cq_one_read_cqe: | |||
667 | ehca_dmp(cqe, 64, "ehca_cq=%p cq_num=%x", | 706 | ehca_dmp(cqe, 64, "ehca_cq=%p cq_num=%x", |
668 | my_cq, my_cq->cq_number); | 707 | my_cq, my_cq->cq_number); |
669 | /* update also queue adder to throw away this entry!!! */ | 708 | /* update also queue adder to throw away this entry!!! */ |
670 | goto poll_cq_one_exit0; | 709 | goto repoll; |
671 | } | 710 | } |
672 | 711 | ||
673 | /* eval ib_wc_status */ | 712 | /* eval ib_wc_status */ |
@@ -678,11 +717,6 @@ poll_cq_one_read_cqe: | |||
678 | } else | 717 | } else |
679 | wc->status = IB_WC_SUCCESS; | 718 | wc->status = IB_WC_SUCCESS; |
680 | 719 | ||
681 | read_lock(&ehca_qp_idr_lock); | ||
682 | my_qp = idr_find(&ehca_qp_idr, cqe->qp_token); | ||
683 | wc->qp = &my_qp->ib_qp; | ||
684 | read_unlock(&ehca_qp_idr_lock); | ||
685 | |||
686 | wc->byte_len = cqe->nr_bytes_transferred; | 720 | wc->byte_len = cqe->nr_bytes_transferred; |
687 | wc->pkey_index = cqe->pkey_index; | 721 | wc->pkey_index = cqe->pkey_index; |
688 | wc->slid = cqe->rlid; | 722 | wc->slid = cqe->rlid; |