diff options
Diffstat (limited to 'drivers/infiniband/hw/ehca/ehca_reqs.c')
-rw-r--r-- | drivers/infiniband/hw/ehca/ehca_reqs.c | 211 |
1 files changed, 184 insertions, 27 deletions
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c index 4426d82fe798..64928079eafa 100644 --- a/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/drivers/infiniband/hw/ehca/ehca_reqs.c | |||
@@ -53,9 +53,25 @@ | |||
53 | /* in RC traffic, insert an empty RDMA READ every this many packets */ | 53 | /* in RC traffic, insert an empty RDMA READ every this many packets */ |
54 | #define ACK_CIRC_THRESHOLD 2000000 | 54 | #define ACK_CIRC_THRESHOLD 2000000 |
55 | 55 | ||
56 | static u64 replace_wr_id(u64 wr_id, u16 idx) | ||
57 | { | ||
58 | u64 ret; | ||
59 | |||
60 | ret = wr_id & ~QMAP_IDX_MASK; | ||
61 | ret |= idx & QMAP_IDX_MASK; | ||
62 | |||
63 | return ret; | ||
64 | } | ||
65 | |||
66 | static u16 get_app_wr_id(u64 wr_id) | ||
67 | { | ||
68 | return wr_id & QMAP_IDX_MASK; | ||
69 | } | ||
70 | |||
56 | static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue, | 71 | static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue, |
57 | struct ehca_wqe *wqe_p, | 72 | struct ehca_wqe *wqe_p, |
58 | struct ib_recv_wr *recv_wr) | 73 | struct ib_recv_wr *recv_wr, |
74 | u32 rq_map_idx) | ||
59 | { | 75 | { |
60 | u8 cnt_ds; | 76 | u8 cnt_ds; |
61 | if (unlikely((recv_wr->num_sge < 0) || | 77 | if (unlikely((recv_wr->num_sge < 0) || |
@@ -69,7 +85,7 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue, | |||
69 | /* clear wqe header until sglist */ | 85 | /* clear wqe header until sglist */ |
70 | memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list)); | 86 | memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list)); |
71 | 87 | ||
72 | wqe_p->work_request_id = recv_wr->wr_id; | 88 | wqe_p->work_request_id = replace_wr_id(recv_wr->wr_id, rq_map_idx); |
73 | wqe_p->nr_of_data_seg = recv_wr->num_sge; | 89 | wqe_p->nr_of_data_seg = recv_wr->num_sge; |
74 | 90 | ||
75 | for (cnt_ds = 0; cnt_ds < recv_wr->num_sge; cnt_ds++) { | 91 | for (cnt_ds = 0; cnt_ds < recv_wr->num_sge; cnt_ds++) { |
@@ -146,6 +162,7 @@ static inline int ehca_write_swqe(struct ehca_qp *qp, | |||
146 | u64 dma_length; | 162 | u64 dma_length; |
147 | struct ehca_av *my_av; | 163 | struct ehca_av *my_av; |
148 | u32 remote_qkey = send_wr->wr.ud.remote_qkey; | 164 | u32 remote_qkey = send_wr->wr.ud.remote_qkey; |
165 | struct ehca_qmap_entry *qmap_entry = &qp->sq_map.map[sq_map_idx]; | ||
149 | 166 | ||
150 | if (unlikely((send_wr->num_sge < 0) || | 167 | if (unlikely((send_wr->num_sge < 0) || |
151 | (send_wr->num_sge > qp->ipz_squeue.act_nr_of_sg))) { | 168 | (send_wr->num_sge > qp->ipz_squeue.act_nr_of_sg))) { |
@@ -158,11 +175,10 @@ static inline int ehca_write_swqe(struct ehca_qp *qp, | |||
158 | /* clear wqe header until sglist */ | 175 | /* clear wqe header until sglist */ |
159 | memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list)); | 176 | memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list)); |
160 | 177 | ||
161 | wqe_p->work_request_id = send_wr->wr_id & ~QMAP_IDX_MASK; | 178 | wqe_p->work_request_id = replace_wr_id(send_wr->wr_id, sq_map_idx); |
162 | wqe_p->work_request_id |= sq_map_idx & QMAP_IDX_MASK; | ||
163 | 179 | ||
164 | qp->sq_map[sq_map_idx].app_wr_id = send_wr->wr_id & QMAP_IDX_MASK; | 180 | qmap_entry->app_wr_id = get_app_wr_id(send_wr->wr_id); |
165 | qp->sq_map[sq_map_idx].reported = 0; | 181 | qmap_entry->reported = 0; |
166 | 182 | ||
167 | switch (send_wr->opcode) { | 183 | switch (send_wr->opcode) { |
168 | case IB_WR_SEND: | 184 | case IB_WR_SEND: |
@@ -496,7 +512,9 @@ static int internal_post_recv(struct ehca_qp *my_qp, | |||
496 | struct ehca_wqe *wqe_p; | 512 | struct ehca_wqe *wqe_p; |
497 | int wqe_cnt = 0; | 513 | int wqe_cnt = 0; |
498 | int ret = 0; | 514 | int ret = 0; |
515 | u32 rq_map_idx; | ||
499 | unsigned long flags; | 516 | unsigned long flags; |
517 | struct ehca_qmap_entry *qmap_entry; | ||
500 | 518 | ||
501 | if (unlikely(!HAS_RQ(my_qp))) { | 519 | if (unlikely(!HAS_RQ(my_qp))) { |
502 | ehca_err(dev, "QP has no RQ ehca_qp=%p qp_num=%x ext_type=%d", | 520 | ehca_err(dev, "QP has no RQ ehca_qp=%p qp_num=%x ext_type=%d", |
@@ -524,8 +542,15 @@ static int internal_post_recv(struct ehca_qp *my_qp, | |||
524 | } | 542 | } |
525 | goto post_recv_exit0; | 543 | goto post_recv_exit0; |
526 | } | 544 | } |
545 | /* | ||
546 | * Get the index of the WQE in the recv queue. The same index | ||
547 | * is used for writing into the rq_map. | ||
548 | */ | ||
549 | rq_map_idx = start_offset / my_qp->ipz_rqueue.qe_size; | ||
550 | |||
527 | /* write a RECV WQE into the QUEUE */ | 551 | /* write a RECV WQE into the QUEUE */ |
528 | ret = ehca_write_rwqe(&my_qp->ipz_rqueue, wqe_p, cur_recv_wr); | 552 | ret = ehca_write_rwqe(&my_qp->ipz_rqueue, wqe_p, cur_recv_wr, |
553 | rq_map_idx); | ||
529 | /* | 554 | /* |
530 | * if something failed, | 555 | * if something failed, |
531 | * reset the free entry pointer to the start value | 556 | * reset the free entry pointer to the start value |
@@ -540,6 +565,11 @@ static int internal_post_recv(struct ehca_qp *my_qp, | |||
540 | } | 565 | } |
541 | goto post_recv_exit0; | 566 | goto post_recv_exit0; |
542 | } | 567 | } |
568 | |||
569 | qmap_entry = &my_qp->rq_map.map[rq_map_idx]; | ||
570 | qmap_entry->app_wr_id = get_app_wr_id(cur_recv_wr->wr_id); | ||
571 | qmap_entry->reported = 0; | ||
572 | |||
543 | wqe_cnt++; | 573 | wqe_cnt++; |
544 | } /* eof for cur_recv_wr */ | 574 | } /* eof for cur_recv_wr */ |
545 | 575 | ||
@@ -596,10 +626,12 @@ static const u8 ib_wc_opcode[255] = { | |||
596 | /* internal function to poll one entry of cq */ | 626 | /* internal function to poll one entry of cq */ |
597 | static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc) | 627 | static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc) |
598 | { | 628 | { |
599 | int ret = 0; | 629 | int ret = 0, qmap_tail_idx; |
600 | struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); | 630 | struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); |
601 | struct ehca_cqe *cqe; | 631 | struct ehca_cqe *cqe; |
602 | struct ehca_qp *my_qp; | 632 | struct ehca_qp *my_qp; |
633 | struct ehca_qmap_entry *qmap_entry; | ||
634 | struct ehca_queue_map *qmap; | ||
603 | int cqe_count = 0, is_error; | 635 | int cqe_count = 0, is_error; |
604 | 636 | ||
605 | repoll: | 637 | repoll: |
@@ -674,27 +706,52 @@ repoll: | |||
674 | goto repoll; | 706 | goto repoll; |
675 | wc->qp = &my_qp->ib_qp; | 707 | wc->qp = &my_qp->ib_qp; |
676 | 708 | ||
677 | if (!(cqe->w_completion_flags & WC_SEND_RECEIVE_BIT)) { | 709 | if (is_error) { |
678 | struct ehca_qmap_entry *qmap_entry; | ||
679 | /* | 710 | /* |
680 | * We got a send completion and need to restore the original | 711 | * set left_to_poll to 0 because in error state, we will not |
681 | * wr_id. | 712 | * get any additional CQEs |
682 | */ | 713 | */ |
683 | qmap_entry = &my_qp->sq_map[cqe->work_request_id & | 714 | ehca_add_to_err_list(my_qp, 1); |
684 | QMAP_IDX_MASK]; | 715 | my_qp->sq_map.left_to_poll = 0; |
685 | 716 | ||
686 | if (qmap_entry->reported) { | 717 | if (HAS_RQ(my_qp)) |
687 | ehca_warn(cq->device, "Double cqe on qp_num=%#x", | 718 | ehca_add_to_err_list(my_qp, 0); |
688 | my_qp->real_qp_num); | 719 | my_qp->rq_map.left_to_poll = 0; |
689 | /* found a double cqe, discard it and read next one */ | 720 | } |
690 | goto repoll; | 721 | |
691 | } | 722 | qmap_tail_idx = get_app_wr_id(cqe->work_request_id); |
692 | wc->wr_id = cqe->work_request_id & ~QMAP_IDX_MASK; | 723 | if (!(cqe->w_completion_flags & WC_SEND_RECEIVE_BIT)) |
693 | wc->wr_id |= qmap_entry->app_wr_id; | 724 | /* We got a send completion. */ |
694 | qmap_entry->reported = 1; | 725 | qmap = &my_qp->sq_map; |
695 | } else | 726 | else |
696 | /* We got a receive completion. */ | 727 | /* We got a receive completion. */ |
697 | wc->wr_id = cqe->work_request_id; | 728 | qmap = &my_qp->rq_map; |
729 | |||
730 | qmap_entry = &qmap->map[qmap_tail_idx]; | ||
731 | if (qmap_entry->reported) { | ||
732 | ehca_warn(cq->device, "Double cqe on qp_num=%#x", | ||
733 | my_qp->real_qp_num); | ||
734 | /* found a double cqe, discard it and read next one */ | ||
735 | goto repoll; | ||
736 | } | ||
737 | |||
738 | wc->wr_id = replace_wr_id(cqe->work_request_id, qmap_entry->app_wr_id); | ||
739 | qmap_entry->reported = 1; | ||
740 | |||
741 | /* this is a proper completion, we need to advance the tail pointer */ | ||
742 | if (++qmap->tail == qmap->entries) | ||
743 | qmap->tail = 0; | ||
744 | |||
745 | /* if left_to_poll is decremented to 0, add the QP to the error list */ | ||
746 | if (qmap->left_to_poll > 0) { | ||
747 | qmap->left_to_poll--; | ||
748 | if ((my_qp->sq_map.left_to_poll == 0) && | ||
749 | (my_qp->rq_map.left_to_poll == 0)) { | ||
750 | ehca_add_to_err_list(my_qp, 1); | ||
751 | if (HAS_RQ(my_qp)) | ||
752 | ehca_add_to_err_list(my_qp, 0); | ||
753 | } | ||
754 | } | ||
698 | 755 | ||
699 | /* eval ib_wc_opcode */ | 756 | /* eval ib_wc_opcode */ |
700 | wc->opcode = ib_wc_opcode[cqe->optype]-1; | 757 | wc->opcode = ib_wc_opcode[cqe->optype]-1; |
@@ -733,13 +790,88 @@ poll_cq_one_exit0: | |||
733 | return ret; | 790 | return ret; |
734 | } | 791 | } |
735 | 792 | ||
793 | static int generate_flush_cqes(struct ehca_qp *my_qp, struct ib_cq *cq, | ||
794 | struct ib_wc *wc, int num_entries, | ||
795 | struct ipz_queue *ipz_queue, int on_sq) | ||
796 | { | ||
797 | int nr = 0; | ||
798 | struct ehca_wqe *wqe; | ||
799 | u64 offset; | ||
800 | struct ehca_queue_map *qmap; | ||
801 | struct ehca_qmap_entry *qmap_entry; | ||
802 | |||
803 | if (on_sq) | ||
804 | qmap = &my_qp->sq_map; | ||
805 | else | ||
806 | qmap = &my_qp->rq_map; | ||
807 | |||
808 | qmap_entry = &qmap->map[qmap->tail]; | ||
809 | |||
810 | while ((nr < num_entries) && (qmap_entry->reported == 0)) { | ||
811 | /* generate flush CQE */ | ||
812 | memset(wc, 0, sizeof(*wc)); | ||
813 | |||
814 | offset = qmap->tail * ipz_queue->qe_size; | ||
815 | wqe = (struct ehca_wqe *)ipz_qeit_calc(ipz_queue, offset); | ||
816 | if (!wqe) { | ||
817 | ehca_err(cq->device, "Invalid wqe offset=%#lx on " | ||
818 | "qp_num=%#x", offset, my_qp->real_qp_num); | ||
819 | return nr; | ||
820 | } | ||
821 | |||
822 | wc->wr_id = replace_wr_id(wqe->work_request_id, | ||
823 | qmap_entry->app_wr_id); | ||
824 | |||
825 | if (on_sq) { | ||
826 | switch (wqe->optype) { | ||
827 | case WQE_OPTYPE_SEND: | ||
828 | wc->opcode = IB_WC_SEND; | ||
829 | break; | ||
830 | case WQE_OPTYPE_RDMAWRITE: | ||
831 | wc->opcode = IB_WC_RDMA_WRITE; | ||
832 | break; | ||
833 | case WQE_OPTYPE_RDMAREAD: | ||
834 | wc->opcode = IB_WC_RDMA_READ; | ||
835 | break; | ||
836 | default: | ||
837 | ehca_err(cq->device, "Invalid optype=%x", | ||
838 | wqe->optype); | ||
839 | return nr; | ||
840 | } | ||
841 | } else | ||
842 | wc->opcode = IB_WC_RECV; | ||
843 | |||
844 | if (wqe->wr_flag & WQE_WRFLAG_IMM_DATA_PRESENT) { | ||
845 | wc->ex.imm_data = wqe->immediate_data; | ||
846 | wc->wc_flags |= IB_WC_WITH_IMM; | ||
847 | } | ||
848 | |||
849 | wc->status = IB_WC_WR_FLUSH_ERR; | ||
850 | |||
851 | wc->qp = &my_qp->ib_qp; | ||
852 | |||
853 | /* mark as reported and advance tail pointer */ | ||
854 | qmap_entry->reported = 1; | ||
855 | if (++qmap->tail == qmap->entries) | ||
856 | qmap->tail = 0; | ||
857 | qmap_entry = &qmap->map[qmap->tail]; | ||
858 | |||
859 | wc++; nr++; | ||
860 | } | ||
861 | |||
862 | return nr; | ||
863 | |||
864 | } | ||
865 | |||
736 | int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc) | 866 | int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc) |
737 | { | 867 | { |
738 | struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); | 868 | struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); |
739 | int nr; | 869 | int nr; |
870 | struct ehca_qp *err_qp; | ||
740 | struct ib_wc *current_wc = wc; | 871 | struct ib_wc *current_wc = wc; |
741 | int ret = 0; | 872 | int ret = 0; |
742 | unsigned long flags; | 873 | unsigned long flags; |
874 | int entries_left = num_entries; | ||
743 | 875 | ||
744 | if (num_entries < 1) { | 876 | if (num_entries < 1) { |
745 | ehca_err(cq->device, "Invalid num_entries=%d ehca_cq=%p " | 877 | ehca_err(cq->device, "Invalid num_entries=%d ehca_cq=%p " |
@@ -749,15 +881,40 @@ int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc) | |||
749 | } | 881 | } |
750 | 882 | ||
751 | spin_lock_irqsave(&my_cq->spinlock, flags); | 883 | spin_lock_irqsave(&my_cq->spinlock, flags); |
752 | for (nr = 0; nr < num_entries; nr++) { | 884 | |
885 | /* generate flush cqes for send queues */ | ||
886 | list_for_each_entry(err_qp, &my_cq->sqp_err_list, sq_err_node) { | ||
887 | nr = generate_flush_cqes(err_qp, cq, current_wc, entries_left, | ||
888 | &err_qp->ipz_squeue, 1); | ||
889 | entries_left -= nr; | ||
890 | current_wc += nr; | ||
891 | |||
892 | if (entries_left == 0) | ||
893 | break; | ||
894 | } | ||
895 | |||
896 | /* generate flush cqes for receive queues */ | ||
897 | list_for_each_entry(err_qp, &my_cq->rqp_err_list, rq_err_node) { | ||
898 | nr = generate_flush_cqes(err_qp, cq, current_wc, entries_left, | ||
899 | &err_qp->ipz_rqueue, 0); | ||
900 | entries_left -= nr; | ||
901 | current_wc += nr; | ||
902 | |||
903 | if (entries_left == 0) | ||
904 | break; | ||
905 | } | ||
906 | |||
907 | for (nr = 0; nr < entries_left; nr++) { | ||
753 | ret = ehca_poll_cq_one(cq, current_wc); | 908 | ret = ehca_poll_cq_one(cq, current_wc); |
754 | if (ret) | 909 | if (ret) |
755 | break; | 910 | break; |
756 | current_wc++; | 911 | current_wc++; |
757 | } /* eof for nr */ | 912 | } /* eof for nr */ |
913 | entries_left -= nr; | ||
914 | |||
758 | spin_unlock_irqrestore(&my_cq->spinlock, flags); | 915 | spin_unlock_irqrestore(&my_cq->spinlock, flags); |
759 | if (ret == -EAGAIN || !ret) | 916 | if (ret == -EAGAIN || !ret) |
760 | ret = nr; | 917 | ret = num_entries - entries_left; |
761 | 918 | ||
762 | poll_cq_exit0: | 919 | poll_cq_exit0: |
763 | return ret; | 920 | return ret; |