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 | |
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')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_qp.c | 3 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_rc.c | 47 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_verbs.c | 3 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_verbs.h | 4 |
4 files changed, 37 insertions, 20 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c index 224b0f40767f..ecfaca7a571b 100644 --- a/drivers/infiniband/hw/ipath/ipath_qp.c +++ b/drivers/infiniband/hw/ipath/ipath_qp.c | |||
@@ -342,6 +342,7 @@ static void ipath_reset_qp(struct ipath_qp *qp) | |||
342 | qp->s_last = 0; | 342 | qp->s_last = 0; |
343 | qp->s_ssn = 1; | 343 | qp->s_ssn = 1; |
344 | qp->s_lsn = 0; | 344 | qp->s_lsn = 0; |
345 | qp->s_wait_credit = 0; | ||
345 | if (qp->r_rq.wq) { | 346 | if (qp->r_rq.wq) { |
346 | qp->r_rq.wq->head = 0; | 347 | qp->r_rq.wq->head = 0; |
347 | qp->r_rq.wq->tail = 0; | 348 | qp->r_rq.wq->tail = 0; |
@@ -516,7 +517,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
516 | qp->remote_qpn = attr->dest_qp_num; | 517 | qp->remote_qpn = attr->dest_qp_num; |
517 | 518 | ||
518 | if (attr_mask & IB_QP_SQ_PSN) { | 519 | if (attr_mask & IB_QP_SQ_PSN) { |
519 | qp->s_next_psn = attr->sq_psn; | 520 | qp->s_psn = qp->s_next_psn = attr->sq_psn; |
520 | qp->s_last_psn = qp->s_next_psn - 1; | 521 | qp->s_last_psn = qp->s_next_psn - 1; |
521 | } | 522 | } |
522 | 523 | ||
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; |
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index b8381c5e72bd..a4bf870c5e31 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c | |||
@@ -1683,6 +1683,7 @@ static ssize_t show_stats(struct class_device *cdev, char *buf) | |||
1683 | "RC OTH NAKs %d\n" | 1683 | "RC OTH NAKs %d\n" |
1684 | "RC timeouts %d\n" | 1684 | "RC timeouts %d\n" |
1685 | "RC RDMA dup %d\n" | 1685 | "RC RDMA dup %d\n" |
1686 | "RC stalls %d\n" | ||
1686 | "piobuf wait %d\n" | 1687 | "piobuf wait %d\n" |
1687 | "no piobuf %d\n" | 1688 | "no piobuf %d\n" |
1688 | "PKT drops %d\n" | 1689 | "PKT drops %d\n" |
@@ -1690,7 +1691,7 @@ static ssize_t show_stats(struct class_device *cdev, char *buf) | |||
1690 | dev->n_rc_resends, dev->n_rc_qacks, dev->n_rc_acks, | 1691 | dev->n_rc_resends, dev->n_rc_qacks, dev->n_rc_acks, |
1691 | dev->n_seq_naks, dev->n_rdma_seq, dev->n_rnr_naks, | 1692 | dev->n_seq_naks, dev->n_rdma_seq, dev->n_rnr_naks, |
1692 | dev->n_other_naks, dev->n_timeouts, | 1693 | dev->n_other_naks, dev->n_timeouts, |
1693 | dev->n_rdma_dup_busy, dev->n_piowait, | 1694 | dev->n_rdma_dup_busy, dev->n_rc_stalls, dev->n_piowait, |
1694 | dev->n_no_piobuf, dev->n_pkt_drops, dev->n_wqe_errs); | 1695 | dev->n_no_piobuf, dev->n_pkt_drops, dev->n_wqe_errs); |
1695 | for (i = 0; i < ARRAY_SIZE(dev->opstats); i++) { | 1696 | for (i = 0; i < ARRAY_SIZE(dev->opstats); i++) { |
1696 | const struct ipath_opcode_stats *si = &dev->opstats[i]; | 1697 | const struct ipath_opcode_stats *si = &dev->opstats[i]; |
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h index 09bbb3f9a217..3fffaa02e669 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/drivers/infiniband/hw/ipath/ipath_verbs.h | |||
@@ -370,6 +370,7 @@ struct ipath_qp { | |||
370 | u8 s_rnr_retry_cnt; | 370 | u8 s_rnr_retry_cnt; |
371 | u8 s_retry; /* requester retry counter */ | 371 | u8 s_retry; /* requester retry counter */ |
372 | u8 s_rnr_retry; /* requester RNR retry counter */ | 372 | u8 s_rnr_retry; /* requester RNR retry counter */ |
373 | u8 s_wait_credit; /* limit number of unacked packets sent */ | ||
373 | u8 s_pkey_index; /* PKEY index to use */ | 374 | u8 s_pkey_index; /* PKEY index to use */ |
374 | u8 timeout; /* Timeout for this QP */ | 375 | u8 timeout; /* Timeout for this QP */ |
375 | enum ib_mtu path_mtu; | 376 | enum ib_mtu path_mtu; |
@@ -393,6 +394,8 @@ struct ipath_qp { | |||
393 | #define IPATH_S_BUSY 0 | 394 | #define IPATH_S_BUSY 0 |
394 | #define IPATH_S_SIGNAL_REQ_WR 1 | 395 | #define IPATH_S_SIGNAL_REQ_WR 1 |
395 | 396 | ||
397 | #define IPATH_PSN_CREDIT 2048 | ||
398 | |||
396 | /* | 399 | /* |
397 | * Since struct ipath_swqe is not a fixed size, we can't simply index into | 400 | * Since struct ipath_swqe is not a fixed size, we can't simply index into |
398 | * struct ipath_qp.s_wq. This function does the array index computation. | 401 | * struct ipath_qp.s_wq. This function does the array index computation. |
@@ -521,6 +524,7 @@ struct ipath_ibdev { | |||
521 | u32 n_rnr_naks; | 524 | u32 n_rnr_naks; |
522 | u32 n_other_naks; | 525 | u32 n_other_naks; |
523 | u32 n_timeouts; | 526 | u32 n_timeouts; |
527 | u32 n_rc_stalls; | ||
524 | u32 n_pkt_drops; | 528 | u32 n_pkt_drops; |
525 | u32 n_vl15_dropped; | 529 | u32 n_vl15_dropped; |
526 | u32 n_wqe_errs; | 530 | u32 n_wqe_errs; |