| From foo@baz Sun May 27 17:33:38 CEST 2018 |
| From: "Kalderon, Michal" <Michal.Kalderon@cavium.com> |
| Date: Wed, 21 Mar 2018 14:51:50 +0200 |
| Subject: RDMA/qedr: fix QP's ack timeout configuration |
| |
| From: "Kalderon, Michal" <Michal.Kalderon@cavium.com> |
| |
| [ Upstream commit c3594f22302cca5e924e47ec1cc8edd265708f41 ] |
| |
| QPs that were configured with ack timeout value lower than 1 |
| msec will not implement re-transmission timeout. |
| This means that if a packet / ACK were dropped, the QP |
| will not retransmit this packet. |
| |
| This can lead to an application hang. |
| |
| Fixes: cecbcddf6 ("qedr: Add support for QP verbs") |
| Signed-off-by: Michal Kalderon <Michal.Kalderon@cavium.com> |
| Signed-off-by: Ariel Elior <Ariel.Elior@cavium.com> |
| Signed-off-by: Jason Gunthorpe <jgg@mellanox.com> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/infiniband/hw/qedr/verbs.c | 25 +++++++++++++++---------- |
| 1 file changed, 15 insertions(+), 10 deletions(-) |
| |
| --- a/drivers/infiniband/hw/qedr/verbs.c |
| +++ b/drivers/infiniband/hw/qedr/verbs.c |
| @@ -1888,18 +1888,23 @@ int qedr_modify_qp(struct ib_qp *ibqp, s |
| SET_FIELD(qp_params.modify_flags, |
| QED_ROCE_MODIFY_QP_VALID_ACK_TIMEOUT, 1); |
| |
| - qp_params.ack_timeout = attr->timeout; |
| - if (attr->timeout) { |
| - u32 temp; |
| - |
| - temp = 4096 * (1UL << attr->timeout) / 1000 / 1000; |
| - /* FW requires [msec] */ |
| - qp_params.ack_timeout = temp; |
| - } else { |
| - /* Infinite */ |
| + /* The received timeout value is an exponent used like this: |
| + * "12.7.34 LOCAL ACK TIMEOUT |
| + * Value representing the transport (ACK) timeout for use by |
| + * the remote, expressed as: 4.096 * 2^timeout [usec]" |
| + * The FW expects timeout in msec so we need to divide the usec |
| + * result by 1000. We'll approximate 1000~2^10, and 4.096 ~ 2^2, |
| + * so we get: 2^2 * 2^timeout / 2^10 = 2^(timeout - 8). |
| + * The value of zero means infinite so we use a 'max_t' to make |
| + * sure that sub 1 msec values will be configured as 1 msec. |
| + */ |
| + if (attr->timeout) |
| + qp_params.ack_timeout = |
| + 1 << max_t(int, attr->timeout - 8, 0); |
| + else |
| qp_params.ack_timeout = 0; |
| - } |
| } |
| + |
| if (attr_mask & IB_QP_RETRY_CNT) { |
| SET_FIELD(qp_params.modify_flags, |
| QED_ROCE_MODIFY_QP_VALID_RETRY_CNT, 1); |