Many parts of DPDK will fail with divide by zero and
other errors if the initialization logic ever TSC hz was ever
determined to be zero. This might happen on a broken get_tsc_freq_arch()
or bad emulation in QEMU.

If TSC hz is zero, log the error and propagate back to
fail rte_eal_init().

This fix doesn't need to go to stable since it is a purely
theoretical problem; we aren't getting divide by zero reports
from users.

Also, clarify that DPDK TSC is stable and the same for all lcore's.
The comment in rte_cycles.h implied that it could be different per lcore.

Fixes: 040cf8a41187 ("eal: deduplicate timer functions")

Signed-off-by: Stephen Hemminger <[email protected]>
Acked-by: Bruce Richardson <[email protected]>
---
v3 - rename set_tsc_freq to init_tsc_freq

 lib/eal/common/eal_common_timer.c    | 19 +++++++++++++++----
 lib/eal/common/eal_private.h         |  2 +-
 lib/eal/freebsd/eal_timer.c          |  3 +--
 lib/eal/include/generic/rte_cycles.h |  2 +-
 lib/eal/linux/eal_timer.c            |  3 +--
 lib/eal/windows/eal_timer.c          |  3 +--
 6 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/lib/eal/common/eal_common_timer.c 
b/lib/eal/common/eal_common_timer.c
index bbf8b8b11b..67ede70c62 100644
--- a/lib/eal/common/eal_common_timer.c
+++ b/lib/eal/common/eal_common_timer.c
@@ -52,8 +52,8 @@ estimate_tsc_freq(void)
        return RTE_ALIGN_MUL_NEAR(rte_rdtsc() - start, CYC_PER_10MHZ);
 }
 
-void
-set_tsc_freq(void)
+int
+init_tsc_freq(void)
 {
        struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
        uint64_t freq;
@@ -65,18 +65,29 @@ set_tsc_freq(void)
                 * systems where arch-specific frequency detection is not
                 * available.
                 */
+               if (mcfg->tsc_hz == 0) {
+                       EAL_LOG(ERR, "Primary process TSC frequency is zero");
+                       return -1;
+               }
+
                eal_tsc_resolution_hz = mcfg->tsc_hz;
-               return;
+               return 0;
        }
 
        freq = get_tsc_freq_arch();
        freq = get_tsc_freq(freq);
-       if (!freq)
+       if (freq == 0) {
                freq = estimate_tsc_freq();
+               if (freq == 0) {
+                       EAL_LOG(ERR, "TSC frequency is too slow");
+                       return -1;
+               }
+       }
 
        EAL_LOG(DEBUG, "TSC frequency is ~%" PRIu64 " KHz", freq / 1000);
        eal_tsc_resolution_hz = freq;
        mcfg->tsc_hz = freq;
+       return 0;
 }
 
 RTE_EXPORT_SYMBOL(rte_delay_us_callback_register)
diff --git a/lib/eal/common/eal_private.h b/lib/eal/common/eal_private.h
index 6340bab8be..7da3783c9e 100644
--- a/lib/eal/common/eal_private.h
+++ b/lib/eal/common/eal_private.h
@@ -409,7 +409,7 @@ int eal_cpu_detected(unsigned lcore_id);
  *
  * This function is private to the EAL.
  */
-void set_tsc_freq(void);
+int init_tsc_freq(void);
 
 /**
  * Get precise TSC frequency from system
diff --git a/lib/eal/freebsd/eal_timer.c b/lib/eal/freebsd/eal_timer.c
index d21ffa2694..b966c30258 100644
--- a/lib/eal/freebsd/eal_timer.c
+++ b/lib/eal/freebsd/eal_timer.c
@@ -65,6 +65,5 @@ get_tsc_freq(uint64_t arch_hz)
 int
 rte_eal_timer_init(void)
 {
-       set_tsc_freq();
-       return 0;
+       return init_tsc_freq();
 }
diff --git a/lib/eal/include/generic/rte_cycles.h 
b/lib/eal/include/generic/rte_cycles.h
index 7cfd51f0eb..f8e1cde332 100644
--- a/lib/eal/include/generic/rte_cycles.h
+++ b/lib/eal/include/generic/rte_cycles.h
@@ -34,7 +34,7 @@ extern enum timer_source eal_timer_source;
  * Get the measured frequency of the RDTSC counter
  *
  * @return
- *   The TSC frequency for this lcore
+ *   The TSC frequency for all lcores, always non-zero
  */
 uint64_t
 rte_get_tsc_hz(void);
diff --git a/lib/eal/linux/eal_timer.c b/lib/eal/linux/eal_timer.c
index 39f975b6b9..c425ea4ed8 100644
--- a/lib/eal/linux/eal_timer.c
+++ b/lib/eal/linux/eal_timer.c
@@ -99,6 +99,5 @@ rte_eal_timer_init(void)
 
        eal_timer_source = EAL_TIMER_TSC;
 
-       set_tsc_freq();
-       return 0;
+       return init_tsc_freq();
 }
diff --git a/lib/eal/windows/eal_timer.c b/lib/eal/windows/eal_timer.c
index 33cbac6a03..1e381ad673 100644
--- a/lib/eal/windows/eal_timer.c
+++ b/lib/eal/windows/eal_timer.c
@@ -94,6 +94,5 @@ get_tsc_freq(uint64_t arch_hz)
 int
 rte_eal_timer_init(void)
 {
-       set_tsc_freq();
-       return 0;
+       return init_tsc_freq();
 }
-- 
2.53.0

Reply via email to