IB/hfi1: Serialize hrtimer function calls
authorJubin John <jubin.john@intel.com>
Thu, 14 Apr 2016 15:31:53 +0000 (08:31 -0700)
committerDoug Ledford <dledford@redhat.com>
Thu, 28 Apr 2016 20:32:29 +0000 (16:32 -0400)
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: Mike Marciniszyn <mike.marciniszyn@intel.com>
Signed-off-by: Jubin John <jubin.john@intel.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/staging/rdma/hfi1/init.c
drivers/staging/rdma/hfi1/rc.c

index b1582b5a169ee83ae452027aaceca715f370dfb3..502b7cf4647de3afa23bf15f2636d267d35a48da 100644 (file)
@@ -422,9 +422,10 @@ static enum hrtimer_restart cca_timer_fn(struct hrtimer *t)
        struct cca_timer *cca_timer;
        struct hfi1_pportdata *ppd;
        int sl;
-       u16 ccti, ccti_timer, ccti_min;
+       u16 ccti_timer, ccti_min;
        struct cc_state *cc_state;
        unsigned long flags;
+       enum hrtimer_restart ret = HRTIMER_NORESTART;
 
        cca_timer = container_of(t, struct cca_timer, hrtimer);
        ppd = cca_timer->ppd;
@@ -450,24 +451,21 @@ static enum hrtimer_restart cca_timer_fn(struct hrtimer *t)
 
        spin_lock_irqsave(&ppd->cca_timer_lock, flags);
 
-       ccti = cca_timer->ccti;
-
-       if (ccti > ccti_min) {
+       if (cca_timer->ccti > ccti_min) {
                cca_timer->ccti--;
                set_link_ipg(ppd);
        }
 
-       spin_unlock_irqrestore(&ppd->cca_timer_lock, flags);
-
-       rcu_read_unlock();
-
-       if (ccti > ccti_min) {
+       if (cca_timer->ccti > ccti_min) {
                unsigned long nsec = 1024 * ccti_timer;
                /* ccti_timer is in units of 1.024 usec */
                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;
 }
 
 /*
index c6147793bf4b663905807b482aba37feaeb19f1e..792f15eb8efeceeff89cd40e05e4180dace441b2 100644 (file)
@@ -2021,8 +2021,6 @@ void process_becn(struct hfi1_pportdata *ppd, u8 sl, u16 rlid, u32 lqpn,
        if (sl >= OPA_MAX_SLS)
                return;
 
-       cca_timer = &ppd->cca_timer[sl];
-
        cc_state = get_cc_state(ppd);
 
        if (!cc_state)
@@ -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);
 
+       cca_timer = &ppd->cca_timer[sl];
        if (cca_timer->ccti < ccti_limit) {
                if (cca_timer->ccti + ccti_incr <= ccti_limit)
                        cca_timer->ccti += ccti_incr;
@@ -2049,8 +2048,6 @@ void process_becn(struct hfi1_pportdata *ppd, u8 sl, u16 rlid, u32 lqpn,
                set_link_ipg(ppd);
        }
 
-       spin_unlock_irqrestore(&ppd->cca_timer_lock, flags);
-
        ccti = cca_timer->ccti;
 
        if (!hrtimer_active(&cca_timer->hrtimer)) {
@@ -2061,6 +2058,8 @@ void process_becn(struct hfi1_pportdata *ppd, u8 sl, u16 rlid, u32 lqpn,
                              HRTIMER_MODE_REL);
        }
 
+       spin_unlock_irqrestore(&ppd->cca_timer_lock, flags);
+
        if ((trigger_threshold != 0) && (ccti >= trigger_threshold))
                log_cca_event(ppd, sl, rlid, lqpn, rqpn, svc_type);
 }