Commit 11a10d4b authored by Venkata Sandeep Dhanalakota's avatar Venkata Sandeep Dhanalakota Committed by Doug Ledford

IB/rdmavt: Adding timer logic to rdmavt

To move common code across target to rdmavt for code reuse.
Reviewed-by: default avatarMike Marciniszyn <mike.marciniszyn@intel.com>
Reviewed-by: default avatarBrian Welty <brian.welty@intel.com>
Signed-off-by: default avatarVenkata Sandeep Dhanalakota <venkata.s.dhanalakota@intel.com>
Signed-off-by: default avatarDennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent 696513e8
...@@ -55,6 +55,46 @@ ...@@ -55,6 +55,46 @@
#include "vt.h" #include "vt.h"
#include "trace.h" #include "trace.h"
static void rvt_rc_timeout(unsigned long arg);
/*
* Convert the AETH RNR timeout code into the number of microseconds.
*/
static const u32 ib_rvt_rnr_table[32] = {
655360, /* 00: 655.36 */
10, /* 01: .01 */
20, /* 02 .02 */
30, /* 03: .03 */
40, /* 04: .04 */
60, /* 05: .06 */
80, /* 06: .08 */
120, /* 07: .12 */
160, /* 08: .16 */
240, /* 09: .24 */
320, /* 0A: .32 */
480, /* 0B: .48 */
640, /* 0C: .64 */
960, /* 0D: .96 */
1280, /* 0E: 1.28 */
1920, /* 0F: 1.92 */
2560, /* 10: 2.56 */
3840, /* 11: 3.84 */
5120, /* 12: 5.12 */
7680, /* 13: 7.68 */
10240, /* 14: 10.24 */
15360, /* 15: 15.36 */
20480, /* 16: 20.48 */
30720, /* 17: 30.72 */
40960, /* 18: 40.96 */
61440, /* 19: 61.44 */
81920, /* 1A: 81.92 */
122880, /* 1B: 122.88 */
163840, /* 1C: 163.84 */
245760, /* 1D: 245.76 */
327680, /* 1E: 327.68 */
491520 /* 1F: 491.52 */
};
/* /*
* Note that it is OK to post send work requests in the SQE and ERR * Note that it is OK to post send work requests in the SQE and ERR
* states; rvt_do_send() will process them and generate error * states; rvt_do_send() will process them and generate error
...@@ -200,7 +240,8 @@ int rvt_driver_qp_init(struct rvt_dev_info *rdi) ...@@ -200,7 +240,8 @@ int rvt_driver_qp_init(struct rvt_dev_info *rdi)
if (!rdi->driver_f.free_all_qps || if (!rdi->driver_f.free_all_qps ||
!rdi->driver_f.qp_priv_alloc || !rdi->driver_f.qp_priv_alloc ||
!rdi->driver_f.qp_priv_free || !rdi->driver_f.qp_priv_free ||
!rdi->driver_f.notify_qp_reset) !rdi->driver_f.notify_qp_reset ||
!rdi->driver_f.notify_restart_rc)
return -EINVAL; return -EINVAL;
/* allocate parent object */ /* allocate parent object */
...@@ -587,6 +628,7 @@ static void rvt_reset_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp, ...@@ -587,6 +628,7 @@ static void rvt_reset_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp,
/* Let drivers flush their waitlist */ /* Let drivers flush their waitlist */
rdi->driver_f.flush_qp_waiters(qp); rdi->driver_f.flush_qp_waiters(qp);
rvt_stop_rc_timers(qp);
qp->s_flags &= ~(RVT_S_TIMER | RVT_S_ANY_WAIT); qp->s_flags &= ~(RVT_S_TIMER | RVT_S_ANY_WAIT);
spin_unlock(&qp->s_lock); spin_unlock(&qp->s_lock);
spin_unlock(&qp->s_hlock); spin_unlock(&qp->s_hlock);
...@@ -594,7 +636,7 @@ static void rvt_reset_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp, ...@@ -594,7 +636,7 @@ static void rvt_reset_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp,
/* Stop the send queue and the retry timer */ /* Stop the send queue and the retry timer */
rdi->driver_f.stop_send_queue(qp); rdi->driver_f.stop_send_queue(qp);
rvt_del_timers_sync(qp);
/* Wait for things to stop */ /* Wait for things to stop */
rdi->driver_f.quiesce_qp(qp); rdi->driver_f.quiesce_qp(qp);
...@@ -730,6 +772,11 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd, ...@@ -730,6 +772,11 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
if (!qp->s_ack_queue) if (!qp->s_ack_queue)
goto bail_qp; goto bail_qp;
} }
/* initialize timers needed for rc qp */
setup_timer(&qp->s_timer, rvt_rc_timeout, (unsigned long)qp);
hrtimer_init(&qp->s_rnr_timer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL);
qp->s_rnr_timer.function = rvt_rc_rnr_retry;
/* /*
* Driver needs to set up it's private QP structure and do any * Driver needs to set up it's private QP structure and do any
...@@ -1906,3 +1953,135 @@ void rvt_rc_error(struct rvt_qp *qp, enum ib_wc_status err) ...@@ -1906,3 +1953,135 @@ void rvt_rc_error(struct rvt_qp *qp, enum ib_wc_status err)
} }
} }
EXPORT_SYMBOL(rvt_rc_error); EXPORT_SYMBOL(rvt_rc_error);
static inline unsigned long rvt_aeth_to_usec(u32 aeth)
{
return ib_rvt_rnr_table[(aeth >> RVT_AETH_CREDIT_SHIFT) &
RVT_AETH_CREDIT_MASK];
}
/*
* rvt_add_retry_timer - add/start a retry timer
* @qp - the QP
* add a retry timer on the QP
*/
void rvt_add_retry_timer(struct rvt_qp *qp)
{
struct ib_qp *ibqp = &qp->ibqp;
struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device);
lockdep_assert_held(&qp->s_lock);
qp->s_flags |= RVT_S_TIMER;
/* 4.096 usec. * (1 << qp->timeout) */
qp->s_timer.expires = jiffies + qp->timeout_jiffies +
rdi->busy_jiffies;
add_timer(&qp->s_timer);
}
EXPORT_SYMBOL(rvt_add_retry_timer);
/**
* rvt_add_rnr_timer - add/start an rnr timer
* @qp - the QP
* @aeth - aeth of RNR timeout, simulated aeth for loopback
* add an rnr timer on the QP
*/
void rvt_add_rnr_timer(struct rvt_qp *qp, u32 aeth)
{
u32 to;
lockdep_assert_held(&qp->s_lock);
qp->s_flags |= RVT_S_WAIT_RNR;
to = rvt_aeth_to_usec(aeth);
hrtimer_start(&qp->s_rnr_timer,
ns_to_ktime(1000 * to), HRTIMER_MODE_REL);
}
EXPORT_SYMBOL(rvt_add_rnr_timer);
/**
* rvt_stop_rc_timers - stop all timers
* @qp - the QP
* stop any pending timers
*/
void rvt_stop_rc_timers(struct rvt_qp *qp)
{
lockdep_assert_held(&qp->s_lock);
/* Remove QP from all timers */
if (qp->s_flags & (RVT_S_TIMER | RVT_S_WAIT_RNR)) {
qp->s_flags &= ~(RVT_S_TIMER | RVT_S_WAIT_RNR);
del_timer(&qp->s_timer);
hrtimer_try_to_cancel(&qp->s_rnr_timer);
}
}
EXPORT_SYMBOL(rvt_stop_rc_timers);
/**
* rvt_stop_rnr_timer - stop an rnr timer
* @qp - the QP
*
* stop an rnr timer and return if the timer
* had been pending.
*/
static int rvt_stop_rnr_timer(struct rvt_qp *qp)
{
int rval = 0;
lockdep_assert_held(&qp->s_lock);
/* Remove QP from rnr timer */
if (qp->s_flags & RVT_S_WAIT_RNR) {
qp->s_flags &= ~RVT_S_WAIT_RNR;
rval = hrtimer_try_to_cancel(&qp->s_rnr_timer);
}
return rval;
}
/**
* rvt_del_timers_sync - wait for any timeout routines to exit
* @qp - the QP
*/
void rvt_del_timers_sync(struct rvt_qp *qp)
{
del_timer_sync(&qp->s_timer);
hrtimer_cancel(&qp->s_rnr_timer);
}
EXPORT_SYMBOL(rvt_del_timers_sync);
/**
* This is called from s_timer for missing responses.
*/
static void rvt_rc_timeout(unsigned long arg)
{
struct rvt_qp *qp = (struct rvt_qp *)arg;
struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device);
unsigned long flags;
spin_lock_irqsave(&qp->r_lock, flags);
spin_lock(&qp->s_lock);
if (qp->s_flags & RVT_S_TIMER) {
qp->s_flags &= ~RVT_S_TIMER;
del_timer(&qp->s_timer);
if (rdi->driver_f.notify_restart_rc)
rdi->driver_f.notify_restart_rc(qp,
qp->s_last_psn + 1,
1);
rdi->driver_f.schedule_send(qp);
}
spin_unlock(&qp->s_lock);
spin_unlock_irqrestore(&qp->r_lock, flags);
}
/*
* This is called from s_timer for RNR timeouts.
*/
enum hrtimer_restart rvt_rc_rnr_retry(struct hrtimer *t)
{
struct rvt_qp *qp = container_of(t, struct rvt_qp, s_rnr_timer);
struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device);
unsigned long flags;
spin_lock_irqsave(&qp->s_lock, flags);
rvt_stop_rnr_timer(qp);
rdi->driver_f.schedule_send(qp);
spin_unlock_irqrestore(&qp->s_lock, flags);
return HRTIMER_NORESTART;
}
EXPORT_SYMBOL(rvt_rc_rnr_retry);
...@@ -335,6 +335,8 @@ struct rvt_driver_provided { ...@@ -335,6 +335,8 @@ struct rvt_driver_provided {
/* Notify driver a mad agent has been removed */ /* Notify driver a mad agent has been removed */
void (*notify_free_mad_agent)(struct rvt_dev_info *rdi, int port_idx); void (*notify_free_mad_agent)(struct rvt_dev_info *rdi, int port_idx);
/* Notify driver to restart rc */
void (*notify_restart_rc)(struct rvt_qp *qp, u32 psn, int wait);
}; };
struct rvt_dev_info { struct rvt_dev_info {
...@@ -483,6 +485,23 @@ static inline struct rvt_qp *rvt_lookup_qpn(struct rvt_dev_info *rdi, ...@@ -483,6 +485,23 @@ static inline struct rvt_qp *rvt_lookup_qpn(struct rvt_dev_info *rdi,
return qp; return qp;
} }
/**
* rvt_mod_retry_timer - mod a retry timer
* @qp - the QP
* Modify a potentially already running retry timer
*/
static inline void rvt_mod_retry_timer(struct rvt_qp *qp)
{
struct ib_qp *ibqp = &qp->ibqp;
struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device);
lockdep_assert_held(&qp->s_lock);
qp->s_flags |= RVT_S_TIMER;
/* 4.096 usec. * (1 << qp->timeout) */
mod_timer(&qp->s_timer, jiffies + qp->timeout_jiffies +
rdi->busy_jiffies);
}
struct rvt_dev_info *rvt_alloc_device(size_t size, int nports); struct rvt_dev_info *rvt_alloc_device(size_t size, int nports);
void rvt_dealloc_device(struct rvt_dev_info *rdi); void rvt_dealloc_device(struct rvt_dev_info *rdi);
int rvt_register_device(struct rvt_dev_info *rvd); int rvt_register_device(struct rvt_dev_info *rvd);
......
...@@ -370,6 +370,7 @@ struct rvt_qp { ...@@ -370,6 +370,7 @@ struct rvt_qp {
struct rvt_sge_state s_ack_rdma_sge; struct rvt_sge_state s_ack_rdma_sge;
struct timer_list s_timer; struct timer_list s_timer;
struct hrtimer s_rnr_timer;
atomic_t local_ops_pending; /* number of fast_reg/local_inv reqs */ atomic_t local_ops_pending; /* number of fast_reg/local_inv reqs */
...@@ -641,5 +642,10 @@ struct rvt_dev_info; ...@@ -641,5 +642,10 @@ struct rvt_dev_info;
void rvt_comm_est(struct rvt_qp *qp); void rvt_comm_est(struct rvt_qp *qp);
int rvt_error_qp(struct rvt_qp *qp, enum ib_wc_status err); int rvt_error_qp(struct rvt_qp *qp, enum ib_wc_status err);
void rvt_rc_error(struct rvt_qp *qp, enum ib_wc_status err); void rvt_rc_error(struct rvt_qp *qp, enum ib_wc_status err);
enum hrtimer_restart rvt_rc_rnr_retry(struct hrtimer *t);
void rvt_add_rnr_timer(struct rvt_qp *qp, u32 aeth);
void rvt_del_timers_sync(struct rvt_qp *qp);
void rvt_stop_rc_timers(struct rvt_qp *qp);
void rvt_add_retry_timer(struct rvt_qp *qp);
#endif /* DEF_RDMAVT_INCQP_H */ #endif /* DEF_RDMAVT_INCQP_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment