diff options
author | Bryan O'Sullivan <bos@pathscale.com> | 2006-09-28 11:59:57 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2006-09-28 14:16:21 -0400 |
commit | 6022943eb4cb3cb9e43f27f1faeaba38e162d966 (patch) | |
tree | 0c495a94448610e20a4872416b85c8ffdb0f2adf /drivers/infiniband/hw/ipath/ipath_rc.c | |
parent | fd6a79a786b84510d00ee6aa6449a468e6d75dee (diff) |
IB/ipath: Limit # of packets sent without an ACK received
The sender requests an ACK every 1/2 MB to avoid retransmit timeouts that
were causing MVAPICH mod_bw to fail after a predictable number of sends.
Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_rc.c')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_rc.c | 47 |
1 files changed, 29 insertions, 18 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c index a08654042c03..52caa2edf5a4 100644 --- a/drivers/infiniband/hw/ipath/ipath_rc.c +++ b/drivers/infiniband/hw/ipath/ipath_rc.c | |||
@@ -201,6 +201,18 @@ int ipath_make_rc_req(struct ipath_qp *qp, | |||
201 | qp->s_rnr_timeout) | 201 | qp->s_rnr_timeout) |
202 | goto done; | 202 | goto done; |
203 | 203 | ||
204 | /* Limit the number of packets sent without an ACK. */ | ||
205 | if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT) > 0) { | ||
206 | qp->s_wait_credit = 1; | ||
207 | dev->n_rc_stalls++; | ||
208 | spin_lock(&dev->pending_lock); | ||
209 | if (list_empty(&qp->timerwait)) | ||
210 | list_add_tail(&qp->timerwait, | ||
211 | &dev->pending[dev->pending_index]); | ||
212 | spin_unlock(&dev->pending_lock); | ||
213 | goto done; | ||
214 | } | ||
215 | |||
204 | /* header size in 32-bit words LRH+BTH = (8+12)/4. */ | 216 | /* header size in 32-bit words LRH+BTH = (8+12)/4. */ |
205 | hwords = 5; | 217 | hwords = 5; |
206 | bth0 = 0; | 218 | bth0 = 0; |
@@ -221,7 +233,7 @@ int ipath_make_rc_req(struct ipath_qp *qp, | |||
221 | /* Check if send work queue is empty. */ | 233 | /* Check if send work queue is empty. */ |
222 | if (qp->s_tail == qp->s_head) | 234 | if (qp->s_tail == qp->s_head) |
223 | goto done; | 235 | goto done; |
224 | qp->s_psn = wqe->psn = qp->s_next_psn; | 236 | wqe->psn = qp->s_next_psn; |
225 | newreq = 1; | 237 | newreq = 1; |
226 | } | 238 | } |
227 | /* | 239 | /* |
@@ -393,12 +405,6 @@ int ipath_make_rc_req(struct ipath_qp *qp, | |||
393 | ss = &qp->s_sge; | 405 | ss = &qp->s_sge; |
394 | len = qp->s_len; | 406 | len = qp->s_len; |
395 | if (len > pmtu) { | 407 | if (len > pmtu) { |
396 | /* | ||
397 | * Request an ACK every 1/2 MB to avoid retransmit | ||
398 | * timeouts. | ||
399 | */ | ||
400 | if (((wqe->length - len) % (512 * 1024)) == 0) | ||
401 | bth2 |= 1 << 31; | ||
402 | len = pmtu; | 408 | len = pmtu; |
403 | break; | 409 | break; |
404 | } | 410 | } |
@@ -435,12 +441,6 @@ int ipath_make_rc_req(struct ipath_qp *qp, | |||
435 | ss = &qp->s_sge; | 441 | ss = &qp->s_sge; |
436 | len = qp->s_len; | 442 | len = qp->s_len; |
437 | if (len > pmtu) { | 443 | if (len > pmtu) { |
438 | /* | ||
439 | * Request an ACK every 1/2 MB to avoid retransmit | ||
440 | * timeouts. | ||
441 | */ | ||
442 | if (((wqe->length - len) % (512 * 1024)) == 0) | ||
443 | bth2 |= 1 << 31; | ||
444 | len = pmtu; | 444 | len = pmtu; |
445 | break; | 445 | break; |
446 | } | 446 | } |
@@ -498,6 +498,8 @@ int ipath_make_rc_req(struct ipath_qp *qp, | |||
498 | */ | 498 | */ |
499 | goto done; | 499 | goto done; |
500 | } | 500 | } |
501 | if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT - 1) >= 0) | ||
502 | bth2 |= 1 << 31; /* Request ACK. */ | ||
501 | qp->s_len -= len; | 503 | qp->s_len -= len; |
502 | qp->s_hdrwords = hwords; | 504 | qp->s_hdrwords = hwords; |
503 | qp->s_cur_sge = ss; | 505 | qp->s_cur_sge = ss; |
@@ -737,6 +739,15 @@ bail: | |||
737 | return; | 739 | return; |
738 | } | 740 | } |
739 | 741 | ||
742 | static inline void update_last_psn(struct ipath_qp *qp, u32 psn) | ||
743 | { | ||
744 | if (qp->s_wait_credit) { | ||
745 | qp->s_wait_credit = 0; | ||
746 | tasklet_hi_schedule(&qp->s_task); | ||
747 | } | ||
748 | qp->s_last_psn = psn; | ||
749 | } | ||
750 | |||
740 | /** | 751 | /** |
741 | * do_rc_ack - process an incoming RC ACK | 752 | * do_rc_ack - process an incoming RC ACK |
742 | * @qp: the QP the ACK came in on | 753 | * @qp: the QP the ACK came in on |
@@ -805,7 +816,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode) | |||
805 | * The last valid PSN seen is the previous | 816 | * The last valid PSN seen is the previous |
806 | * request's. | 817 | * request's. |
807 | */ | 818 | */ |
808 | qp->s_last_psn = wqe->psn - 1; | 819 | update_last_psn(qp, wqe->psn - 1); |
809 | /* Retry this request. */ | 820 | /* Retry this request. */ |
810 | ipath_restart_rc(qp, wqe->psn, &wc); | 821 | ipath_restart_rc(qp, wqe->psn, &wc); |
811 | /* | 822 | /* |
@@ -864,7 +875,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode) | |||
864 | ipath_get_credit(qp, aeth); | 875 | ipath_get_credit(qp, aeth); |
865 | qp->s_rnr_retry = qp->s_rnr_retry_cnt; | 876 | qp->s_rnr_retry = qp->s_rnr_retry_cnt; |
866 | qp->s_retry = qp->s_retry_cnt; | 877 | qp->s_retry = qp->s_retry_cnt; |
867 | qp->s_last_psn = psn; | 878 | update_last_psn(qp, psn); |
868 | ret = 1; | 879 | ret = 1; |
869 | goto bail; | 880 | goto bail; |
870 | 881 | ||
@@ -883,7 +894,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode) | |||
883 | goto bail; | 894 | goto bail; |
884 | 895 | ||
885 | /* The last valid PSN is the previous PSN. */ | 896 | /* The last valid PSN is the previous PSN. */ |
886 | qp->s_last_psn = psn - 1; | 897 | update_last_psn(qp, psn - 1); |
887 | 898 | ||
888 | dev->n_rc_resends += (int)qp->s_psn - (int)psn; | 899 | dev->n_rc_resends += (int)qp->s_psn - (int)psn; |
889 | 900 | ||
@@ -898,7 +909,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode) | |||
898 | case 3: /* NAK */ | 909 | case 3: /* NAK */ |
899 | /* The last valid PSN seen is the previous request's. */ | 910 | /* The last valid PSN seen is the previous request's. */ |
900 | if (qp->s_last != qp->s_tail) | 911 | if (qp->s_last != qp->s_tail) |
901 | qp->s_last_psn = wqe->psn - 1; | 912 | update_last_psn(qp, wqe->psn - 1); |
902 | switch ((aeth >> IPATH_AETH_CREDIT_SHIFT) & | 913 | switch ((aeth >> IPATH_AETH_CREDIT_SHIFT) & |
903 | IPATH_AETH_CREDIT_MASK) { | 914 | IPATH_AETH_CREDIT_MASK) { |
904 | case 0: /* PSN sequence error */ | 915 | case 0: /* PSN sequence error */ |
@@ -1071,7 +1082,7 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, | |||
1071 | * since we don't want s_sge modified. | 1082 | * since we don't want s_sge modified. |
1072 | */ | 1083 | */ |
1073 | qp->s_len -= pmtu; | 1084 | qp->s_len -= pmtu; |
1074 | qp->s_last_psn = psn; | 1085 | update_last_psn(qp, psn); |
1075 | spin_unlock_irqrestore(&qp->s_lock, flags); | 1086 | spin_unlock_irqrestore(&qp->s_lock, flags); |
1076 | ipath_copy_sge(&qp->s_sge, data, pmtu); | 1087 | ipath_copy_sge(&qp->s_sge, data, pmtu); |
1077 | goto bail; | 1088 | goto bail; |