ramips: rt305x: nuke built-in MTD partition maps
[openwrt.git] / target / linux / ramips / patches-2.6.39 / 002-fix-occassional-kernel-hangs.patch
1 From patchwork Tue Nov  8 14:59:01 2011
2 Content-Type: text/plain; charset="utf-8"
3 MIME-Version: 1.0
4 Content-Transfer-Encoding: 7bit
5 Subject: MIPS: Kernel hangs occasionally during boot.
6 Date: Tue, 08 Nov 2011 13:59:01 -0000
7 From: Al Cooper <alcooperx@gmail.com>
8 X-Patchwork-Id: 2911
9 Message-Id: <1320764341-4275-1-git-send-email-alcooperx@gmail.com>
10 To: ralf@linux-mips.org, linux-mips@linux-mips.org,
11         linux-kernel@vger.kernel.org
12 Cc: "Al Cooper" <alcooperx@gmail.com>
13
14 The Kernel hangs occasionally during boot after
15 "Calibrating delay loop..". This is caused by the
16 c0_compare_int_usable() routine in cevt-r4k.c returning false which
17 causes the system to disable the timer and hang later. The false
18 return happens because the routine is using a series of four calls to
19 irq_disable_hazard() as a delay while it waits for the timer changes
20 to propagate to the cp0 cause register. On newer MIPS cores, like the 74K,
21 the series of irq_disable_hazard() calls turn into ehb instructions and
22 can take as little as a few clock ticks for all 4 instructions. This
23 is not enough of a delay, so the routine thinks the timer is not working.
24 This fix uses up to a max number of cycle counter ticks for the delay
25 and uses back_to_back_c0_hazard() instead of irq_disable_hazard() to
26 handle the hazard condition between cp0 writes and cp0 reads.
27
28 Signed-off-by: Al Cooper <alcooperx@gmail.com>
29
30 ---
31 arch/mips/kernel/cevt-r4k.c |   38 +++++++++++++++++++-------------------
32  1 files changed, 19 insertions(+), 19 deletions(-)
33
34 --- a/arch/mips/kernel/cevt-r4k.c
35 +++ b/arch/mips/kernel/cevt-r4k.c
36 @@ -103,19 +103,10 @@ static int c0_compare_int_pending(void)
37  
38  /*
39   * Compare interrupt can be routed and latched outside the core,
40 - * so a single execution hazard barrier may not be enough to give
41 - * it time to clear as seen in the Cause register.  4 time the
42 - * pipeline depth seems reasonably conservative, and empirically
43 - * works better in configurations with high CPU/bus clock ratios.
44 + * so wait up to worst case number of cycle counter ticks for timer interrupt
45 + * changes to propagate to the cause register.
46   */
47 -
48 -#define compare_change_hazard() \
49 -       do { \
50 -               irq_disable_hazard(); \
51 -               irq_disable_hazard(); \
52 -               irq_disable_hazard(); \
53 -               irq_disable_hazard(); \
54 -       } while (0)
55 +#define COMPARE_INT_SEEN_TICKS 50
56  
57  int c0_compare_int_usable(void)
58  {
59 @@ -126,8 +117,12 @@ int c0_compare_int_usable(void)
60          * IP7 already pending?  Try to clear it by acking the timer.
61          */
62         if (c0_compare_int_pending()) {
63 -               write_c0_compare(read_c0_count());
64 -               compare_change_hazard();
65 +               cnt = read_c0_count();
66 +               write_c0_compare(cnt);
67 +               back_to_back_c0_hazard();
68 +               while (read_c0_count() < (cnt  + COMPARE_INT_SEEN_TICKS))
69 +                       if (!c0_compare_int_pending())
70 +                               break;
71                 if (c0_compare_int_pending())
72                         return 0;
73         }
74 @@ -136,7 +131,7 @@ int c0_compare_int_usable(void)
75                 cnt = read_c0_count();
76                 cnt += delta;
77                 write_c0_compare(cnt);
78 -               compare_change_hazard();
79 +               back_to_back_c0_hazard();
80                 if ((int)(read_c0_count() - cnt) < 0)
81                     break;
82                 /* increase delta if the timer was already expired */
83 @@ -145,12 +140,17 @@ int c0_compare_int_usable(void)
84         while ((int)(read_c0_count() - cnt) <= 0)
85                 ;       /* Wait for expiry  */
86  
87 -       compare_change_hazard();
88 +       while (read_c0_count() < (cnt + COMPARE_INT_SEEN_TICKS))
89 +               if (c0_compare_int_pending())
90 +                       break;
91         if (!c0_compare_int_pending())
92                 return 0;
93 -
94 -       write_c0_compare(read_c0_count());
95 -       compare_change_hazard();
96 +       cnt = read_c0_count();
97 +       write_c0_compare(cnt);
98 +       back_to_back_c0_hazard();
99 +       while (read_c0_count() < (cnt + COMPARE_INT_SEEN_TICKS))
100 +               if (!c0_compare_int_pending())
101 +                       break;
102         if (c0_compare_int_pending())
103                 return 0;
104