Commit d35cf744 authored by Jubin John's avatar Jubin John Committed by Doug Ledford

IB/hfi1: Serialize hrtimer function calls

hrtimer functions do not guarantee serialization, so we extend the
cca_timer_lock to cover the hrtimer_forward_now() in the hrtimer
callback handler and the hrtimer_start() in process_becn(). This
prevents races between these 2 functions to update the hrtimer state
leading to problems such as:
kernel BUG at kernel/hrtimer.c:1282!
encountered during validation of the CCA feature.
Reviewed-by: default avatarMike Marciniszyn <mike.marciniszyn@intel.com>
Signed-off-by: default avatarJubin John <jubin.john@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent 1cbaa670
...@@ -422,9 +422,10 @@ static enum hrtimer_restart cca_timer_fn(struct hrtimer *t) ...@@ -422,9 +422,10 @@ static enum hrtimer_restart cca_timer_fn(struct hrtimer *t)
struct cca_timer *cca_timer; struct cca_timer *cca_timer;
struct hfi1_pportdata *ppd; struct hfi1_pportdata *ppd;
int sl; int sl;
u16 ccti, ccti_timer, ccti_min; u16 ccti_timer, ccti_min;
struct cc_state *cc_state; struct cc_state *cc_state;
unsigned long flags; unsigned long flags;
enum hrtimer_restart ret = HRTIMER_NORESTART;
cca_timer = container_of(t, struct cca_timer, hrtimer); cca_timer = container_of(t, struct cca_timer, hrtimer);
ppd = cca_timer->ppd; ppd = cca_timer->ppd;
...@@ -450,24 +451,21 @@ static enum hrtimer_restart cca_timer_fn(struct hrtimer *t) ...@@ -450,24 +451,21 @@ static enum hrtimer_restart cca_timer_fn(struct hrtimer *t)
spin_lock_irqsave(&ppd->cca_timer_lock, flags); spin_lock_irqsave(&ppd->cca_timer_lock, flags);
ccti = cca_timer->ccti; if (cca_timer->ccti > ccti_min) {
if (ccti > ccti_min) {
cca_timer->ccti--; cca_timer->ccti--;
set_link_ipg(ppd); set_link_ipg(ppd);
} }
spin_unlock_irqrestore(&ppd->cca_timer_lock, flags); if (cca_timer->ccti > ccti_min) {
rcu_read_unlock();
if (ccti > ccti_min) {
unsigned long nsec = 1024 * ccti_timer; unsigned long nsec = 1024 * ccti_timer;
/* ccti_timer is in units of 1.024 usec */ /* ccti_timer is in units of 1.024 usec */
hrtimer_forward_now(t, ns_to_ktime(nsec)); hrtimer_forward_now(t, ns_to_ktime(nsec));
return HRTIMER_RESTART; ret = HRTIMER_RESTART;
} }
return HRTIMER_NORESTART;
spin_unlock_irqrestore(&ppd->cca_timer_lock, flags);
rcu_read_unlock();
return ret;
} }
/* /*
......
...@@ -2021,8 +2021,6 @@ void process_becn(struct hfi1_pportdata *ppd, u8 sl, u16 rlid, u32 lqpn, ...@@ -2021,8 +2021,6 @@ void process_becn(struct hfi1_pportdata *ppd, u8 sl, u16 rlid, u32 lqpn,
if (sl >= OPA_MAX_SLS) if (sl >= OPA_MAX_SLS)
return; return;
cca_timer = &ppd->cca_timer[sl];
cc_state = get_cc_state(ppd); cc_state = get_cc_state(ppd);
if (!cc_state) if (!cc_state)
...@@ -2041,6 +2039,7 @@ void process_becn(struct hfi1_pportdata *ppd, u8 sl, u16 rlid, u32 lqpn, ...@@ -2041,6 +2039,7 @@ void process_becn(struct hfi1_pportdata *ppd, u8 sl, u16 rlid, u32 lqpn,
spin_lock_irqsave(&ppd->cca_timer_lock, flags); spin_lock_irqsave(&ppd->cca_timer_lock, flags);
cca_timer = &ppd->cca_timer[sl];
if (cca_timer->ccti < ccti_limit) { if (cca_timer->ccti < ccti_limit) {
if (cca_timer->ccti + ccti_incr <= ccti_limit) if (cca_timer->ccti + ccti_incr <= ccti_limit)
cca_timer->ccti += ccti_incr; cca_timer->ccti += ccti_incr;
...@@ -2049,8 +2048,6 @@ void process_becn(struct hfi1_pportdata *ppd, u8 sl, u16 rlid, u32 lqpn, ...@@ -2049,8 +2048,6 @@ void process_becn(struct hfi1_pportdata *ppd, u8 sl, u16 rlid, u32 lqpn,
set_link_ipg(ppd); set_link_ipg(ppd);
} }
spin_unlock_irqrestore(&ppd->cca_timer_lock, flags);
ccti = cca_timer->ccti; ccti = cca_timer->ccti;
if (!hrtimer_active(&cca_timer->hrtimer)) { if (!hrtimer_active(&cca_timer->hrtimer)) {
...@@ -2061,6 +2058,8 @@ void process_becn(struct hfi1_pportdata *ppd, u8 sl, u16 rlid, u32 lqpn, ...@@ -2061,6 +2058,8 @@ void process_becn(struct hfi1_pportdata *ppd, u8 sl, u16 rlid, u32 lqpn,
HRTIMER_MODE_REL); HRTIMER_MODE_REL);
} }
spin_unlock_irqrestore(&ppd->cca_timer_lock, flags);
if ((trigger_threshold != 0) && (ccti >= trigger_threshold)) if ((trigger_threshold != 0) && (ccti >= trigger_threshold))
log_cca_event(ppd, sl, rlid, lqpn, rqpn, svc_type); log_cca_event(ppd, sl, rlid, lqpn, rqpn, svc_type);
} }
......
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