]> nv-tegra.nvidia Code Review - linux-4.9.git/commitdiff
memory: tegra: avoid divide-by-zero during boot on TX1
authorStephen Warren <swarren@nvidia.com>
Thu, 11 Oct 2018 20:39:04 +0000 (14:39 -0600)
committermobile promotions <svcmobile_promotions@nvidia.com>
Fri, 19 Oct 2018 00:22:02 +0000 (17:22 -0700)
gcc 7.3 detects a code-path that can perform a divide-by-zero and replaces
this with an explicit "brk #0x3e8" (i.e. "brk #1000") instruction, which
causes a crash if the code is executed. This happens in the EMC driver
when Jetson TX1 is booting:

Unexpected kernel BRK exception at EL1
Unhandled debug exception: ptrace BRK handler (0xf20003e8) at 0x0000000000000000

This occurs because update_clock_tree_delay() always calculates "cval" in
various code-paths, but has only calculated the inputs to cval's
calculation in certain cases, hence causing divide-by-zero to occur in
other cases. This patch skips the calculation of cval except in the cases
where the input values have been calculated. This is acceptable since the
value of cval is only used in those same cases.

Bug 200442298

Change-Id: I9d3f67d9e59e8b432c93b3785129c05a89e3de5f
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1924870
(cherry picked from commit 0d2b169473775719a6e1721287f7037953ef3699 in dev-kernel-4.9)
Reviewed-on: https://git-master.nvidia.com/r/1929075
Reviewed-by: Aleksandr Frid <afrid@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
drivers/memory/tegra/tegra210-emc-cc-r21021.c

index cc4749e94cf852801d617ac6366798fca1613edb..c4c5757a4767463e1630a4b27fe962b66ae5f722 100644 (file)
@@ -130,7 +130,7 @@ static u32 update_clock_tree_delay(struct emc_table *last_timing,
        u32 mrr_req = 0, mrr_data = 0;
        u32 temp0_0 = 0, temp0_1 = 0, temp1_0 = 0, temp1_1 = 0;
        s32 tdel = 0, tmdel = 0, adel = 0;
-       u32 cval;
+       u32 cval = 0;
        u32 last_timing_rate_mhz = last_timing->rate / 1000;
        u32 next_timing_rate_mhz = next_timing->rate / 1000;
        int dvfs_pt1 = type == DVFS_PT1;
@@ -195,8 +195,10 @@ static u32 update_clock_tree_delay(struct emc_table *last_timing,
                }
        }
 
-       cval = (1000000 * tegra210_actual_osc_clocks(last_timing->run_clocks)) /
-               (last_timing_rate_mhz * 2 * temp0_0);
+       if (dvfs_pt1 || periodic_training_update)
+               cval = (1000000 * tegra210_actual_osc_clocks(
+                                       last_timing->run_clocks)) /
+                       (last_timing_rate_mhz * 2 * temp0_0);
 
        if (dvfs_pt1)
                __INCREMENT_PTFV(C0D0U0, cval);
@@ -216,8 +218,10 @@ static u32 update_clock_tree_delay(struct emc_table *last_timing,
                                __MOVAVG_AC(next_timing, C0D0U0);
        }
 
-       cval = (1000000 * tegra210_actual_osc_clocks(last_timing->run_clocks)) /
-               (last_timing_rate_mhz * 2 * temp0_1);
+       if (dvfs_pt1 || periodic_training_update)
+               cval = (1000000 * tegra210_actual_osc_clocks(
+                                       last_timing->run_clocks)) /
+                       (last_timing_rate_mhz * 2 * temp0_1);
 
        if (dvfs_pt1)
                __INCREMENT_PTFV(C0D0U1, cval);
@@ -241,8 +245,10 @@ static u32 update_clock_tree_delay(struct emc_table *last_timing,
        }
 
        if (channel_mode == DUAL_CHANNEL) {
-               cval = (1000000 * tegra210_actual_osc_clocks(last_timing->run_clocks)) /
-                       (last_timing_rate_mhz * 2 * temp1_0);
+               if (dvfs_pt1 || periodic_training_update)
+                       cval = (1000000 * tegra210_actual_osc_clocks(
+                                               last_timing->run_clocks)) /
+                               (last_timing_rate_mhz * 2 * temp1_0);
                if (dvfs_pt1)
                        __INCREMENT_PTFV(C1D0U0, cval);
                else if (dvfs_update)
@@ -264,8 +270,10 @@ static u32 update_clock_tree_delay(struct emc_table *last_timing,
                                        __MOVAVG_AC(next_timing, C1D0U0);
                }
 
-               cval = (1000000 * tegra210_actual_osc_clocks(last_timing->run_clocks)) /
-                       (last_timing_rate_mhz * 2 * temp1_1);
+               if (dvfs_pt1 || periodic_training_update)
+                       cval = (1000000 * tegra210_actual_osc_clocks(
+                                               last_timing->run_clocks)) /
+                               (last_timing_rate_mhz * 2 * temp1_1);
                if (dvfs_pt1)
                        __INCREMENT_PTFV(C1D0U1, cval);
                else if (dvfs_update)
@@ -349,8 +357,10 @@ static u32 update_clock_tree_delay(struct emc_table *last_timing,
                }
        }
 
-       cval = (1000000 * tegra210_actual_osc_clocks(last_timing->run_clocks)) /
-               (last_timing_rate_mhz * 2 * temp0_0);
+       if (dvfs_pt1 || periodic_training_update)
+               cval = (1000000 * tegra210_actual_osc_clocks(
+                                       last_timing->run_clocks)) /
+                       (last_timing_rate_mhz * 2 * temp0_0);
 
        if (dvfs_pt1)
                __INCREMENT_PTFV(C0D1U0, cval);
@@ -372,8 +382,10 @@ static u32 update_clock_tree_delay(struct emc_table *last_timing,
                                __MOVAVG_AC(next_timing, C0D1U0);
        }
 
-       cval = (1000000 * tegra210_actual_osc_clocks(last_timing->run_clocks)) /
-               (last_timing_rate_mhz * 2 * temp0_1);
+       if (dvfs_pt1 || periodic_training_update)
+               cval = (1000000 * tegra210_actual_osc_clocks(
+                                       last_timing->run_clocks)) /
+                       (last_timing_rate_mhz * 2 * temp0_1);
 
        if (dvfs_pt1)
                __INCREMENT_PTFV(C0D1U1, cval);
@@ -396,8 +408,10 @@ static u32 update_clock_tree_delay(struct emc_table *last_timing,
        }
 
        if (channel_mode == DUAL_CHANNEL) {
-               cval = (1000000 * tegra210_actual_osc_clocks(last_timing->run_clocks)) /
-                       (last_timing_rate_mhz * 2 * temp1_0);
+               if (dvfs_pt1 || periodic_training_update)
+                       cval = (1000000 * tegra210_actual_osc_clocks(
+                                               last_timing->run_clocks)) /
+                               (last_timing_rate_mhz * 2 * temp1_0);
 
                if (dvfs_pt1)
                        __INCREMENT_PTFV(C1D1U0, cval);
@@ -419,8 +433,10 @@ static u32 update_clock_tree_delay(struct emc_table *last_timing,
                                        __MOVAVG_AC(next_timing, C1D1U0);
                }
 
-               cval = (1000000 * tegra210_actual_osc_clocks(last_timing->run_clocks)) /
-                       (last_timing_rate_mhz * 2 * temp1_1);
+               if (dvfs_pt1 || periodic_training_update)
+                       cval = (1000000 * tegra210_actual_osc_clocks(
+                                               last_timing->run_clocks)) /
+                               (last_timing_rate_mhz * 2 * temp1_1);
 
                if (dvfs_pt1)
                        __INCREMENT_PTFV(C1D1U1, cval);