From 2243472e9d98c3ca0cb735f96ad48a7b59bdb34d Mon Sep 17 00:00:00 2001 From: Easwar Hariharan Date: Mon, 7 Mar 2016 11:35:03 -0800 Subject: [PATCH] IB/hfi1: Improve LED beaconing The current LED beaconing code is unclear and uses the timer handler to turn off the timer. This patch simplifies the code by removing the special semantics of timeon = timeoff = 0 being interpreted as a request to turn off the beaconing. Reviewed-by: Ira Weiny Reviewed-by: Dennis Dalessandro Signed-off-by: Easwar Hariharan Signed-off-by: Jubin John Signed-off-by: Doug Ledford --- drivers/staging/rdma/hfi1/driver.c | 59 +++++++++++++----------------- drivers/staging/rdma/hfi1/hfi.h | 10 ++--- drivers/staging/rdma/hfi1/mad.c | 20 +++++----- 3 files changed, 38 insertions(+), 51 deletions(-) diff --git a/drivers/staging/rdma/hfi1/driver.c b/drivers/staging/rdma/hfi1/driver.c index 45818646eb99..914beedb556b 100644 --- a/drivers/staging/rdma/hfi1/driver.c +++ b/drivers/staging/rdma/hfi1/driver.c @@ -1170,18 +1170,20 @@ void shutdown_led_override(struct hfi1_pportdata *ppd) struct hfi1_devdata *dd = ppd->dd; /* - * This pairs with the memory barrier implied by the atomic_dec in - * hfi1_set_led_override to ensure that we read the correct state of - * LED beaconing represented by led_override_timer_active + * This pairs with the memory barrier in hfi1_start_led_override to + * ensure that we read the correct state of LED beaconing represented + * by led_override_timer_active */ - smp_mb(); + smp_rmb(); if (atomic_read(&ppd->led_override_timer_active)) { del_timer_sync(&ppd->led_override_timer); atomic_set(&ppd->led_override_timer_active, 0); + /* Ensure the atomic_set is visible to all CPUs */ + smp_wmb(); } - /* Shut off LEDs after we are sure timer is not running */ - setextled(dd, 0); + /* Hand control of the LED to the DC for normal operation */ + write_csr(dd, DCC_CFG_LED_CNTRL, 0); } static void run_led_override(unsigned long opaque) @@ -1195,59 +1197,48 @@ static void run_led_override(unsigned long opaque) return; phase_idx = ppd->led_override_phase & 1; + setextled(dd, phase_idx); timeout = ppd->led_override_vals[phase_idx]; + /* Set up for next phase */ ppd->led_override_phase = !ppd->led_override_phase; - /* - * don't re-fire the timer if user asked for it to be off; we let - * it fire one more time after they turn it off to simplify - */ - if (ppd->led_override_vals[0] || ppd->led_override_vals[1]) { - mod_timer(&ppd->led_override_timer, jiffies + timeout); - } else { - /* Hand control of the LED to the DC for normal operation */ - write_csr(dd, DCC_CFG_LED_CNTRL, 0); - /* Record that we did not re-fire the timer */ - atomic_dec(&ppd->led_override_timer_active); - } + mod_timer(&ppd->led_override_timer, jiffies + timeout); } /* * To have the LED blink in a particular pattern, provide timeon and timeoff - * in milliseconds. To turn off custom blinking and return to normal operation, - * provide timeon = timeoff = 0. + * in milliseconds. + * To turn off custom blinking and return to normal operation, use + * shutdown_led_override() */ -void hfi1_set_led_override(struct hfi1_pportdata *ppd, unsigned int timeon, - unsigned int timeoff) +void hfi1_start_led_override(struct hfi1_pportdata *ppd, unsigned int timeon, + unsigned int timeoff) { - struct hfi1_devdata *dd = ppd->dd; - - if (!(dd->flags & HFI1_INITTED)) + if (!(ppd->dd->flags & HFI1_INITTED)) return; /* Convert to jiffies for direct use in timer */ ppd->led_override_vals[0] = msecs_to_jiffies(timeoff); ppd->led_override_vals[1] = msecs_to_jiffies(timeon); - ppd->led_override_phase = 1; /* Arbitrarily start from LED on phase */ + + /* Arbitrarily start from LED on phase */ + ppd->led_override_phase = 1; /* * If the timer has not already been started, do so. Use a "quick" - * timeout so the function will be called soon, to look at our request. + * timeout so the handler will be called soon to look at our request. */ - if (atomic_inc_return(&ppd->led_override_timer_active) == 1) { - /* Need to start timer */ + if (!timer_pending(&ppd->led_override_timer)) { setup_timer(&ppd->led_override_timer, run_led_override, (unsigned long)ppd); - ppd->led_override_timer.expires = jiffies + 1; add_timer(&ppd->led_override_timer); - } else { - if (ppd->led_override_vals[0] || ppd->led_override_vals[1]) - mod_timer(&ppd->led_override_timer, jiffies + 1); - atomic_dec(&ppd->led_override_timer_active); + atomic_set(&ppd->led_override_timer_active, 1); + /* Ensure the atomic_set is visible to all CPUs */ + smp_wmb(); } } diff --git a/drivers/staging/rdma/hfi1/hfi.h b/drivers/staging/rdma/hfi1/hfi.h index 035a151d2d5c..572288308406 100644 --- a/drivers/staging/rdma/hfi1/hfi.h +++ b/drivers/staging/rdma/hfi1/hfi.h @@ -1623,13 +1623,9 @@ void hfi1_free_devdata(struct hfi1_devdata *); void cc_state_reclaim(struct rcu_head *rcu); struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev, size_t extra); -void hfi1_set_led_override(struct hfi1_pportdata *ppd, unsigned int timeon, - unsigned int timeoff); -/* - * Only to be used for driver unload or device reset where we cannot allow - * the timer to fire even the one extra time, else use hfi1_set_led_override - * with timeon = timeoff = 0 - */ +/* LED beaconing functions */ +void hfi1_start_led_override(struct hfi1_pportdata *ppd, unsigned int timeon, + unsigned int timeoff); void shutdown_led_override(struct hfi1_pportdata *ppd); #define HFI1_CREDIT_RETURN_RATE (100) diff --git a/drivers/staging/rdma/hfi1/mad.c b/drivers/staging/rdma/hfi1/mad.c index 5925798db4d1..0ec748e7e7b6 100644 --- a/drivers/staging/rdma/hfi1/mad.c +++ b/drivers/staging/rdma/hfi1/mad.c @@ -583,11 +583,11 @@ static int __subn_get_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data, pi->port_states.ledenable_offlinereason |= ppd->is_sm_config_started << 5; /* - * This pairs with the memory barrier implied by the atomic_dec in - * hfi1_set_led_override to ensure that we read the correct state of - * LED beaconing represented by led_override_timer_active + * This pairs with the memory barrier in hfi1_start_led_override to + * ensure that we read the correct state of LED beaconing represented + * by led_override_timer_active */ - smp_mb(); + smp_rmb(); is_beaconing_active = !!atomic_read(&ppd->led_override_timer_active); pi->port_states.ledenable_offlinereason |= is_beaconing_active << 6; pi->port_states.ledenable_offlinereason |= @@ -3598,11 +3598,11 @@ static int __subn_get_opa_led_info(struct opa_smp *smp, u32 am, u8 *data, } /* - * This pairs with the memory barrier implied by the atomic_dec in - * hfi1_set_led_override to ensure that we read the correct state of - * LED beaconing represented by led_override_timer_active + * This pairs with the memory barrier in hfi1_start_led_override to + * ensure that we read the correct state of LED beaconing represented + * by led_override_timer_active */ - smp_mb(); + smp_rmb(); is_beaconing_active = !!atomic_read(&ppd->led_override_timer_active); p->rsvd_led_mask = cpu_to_be32(is_beaconing_active << OPA_LED_SHIFT); @@ -3627,9 +3627,9 @@ static int __subn_set_opa_led_info(struct opa_smp *smp, u32 am, u8 *data, } if (on) - hfi1_set_led_override(dd->pport, 2000, 1500); + hfi1_start_led_override(dd->pport, 2000, 1500); else - hfi1_set_led_override(dd->pport, 0, 0); + shutdown_led_override(dd->pport); return __subn_get_opa_led_info(smp, am, data, ibdev, port, resp_len); } -- 2.39.5