ramips: fix clock skew
authorJohn Crispin <john@phrozen.org>
Thu, 29 Jun 2017 16:33:08 +0000 (18:33 +0200)
committerJohn Crispin <john@phrozen.org>
Thu, 29 Jun 2017 18:03:16 +0000 (20:03 +0200)
The MT7621 seems to have a power-on issue where one of the cores comes up
at a wrong speed. fix this by recalibrating the delay loop after all 4 cores
were powered up properly.

Signed-off-by: John Crispin <john@phrozen.org>
target/linux/ramips/patches-4.4/100-mt7621-core-detect-hack.patch
target/linux/ramips/patches-4.4/101-mt7621-timer.patch [new file with mode: 0644]

index 4049d131bbb70702917a01f8e33b3da99edf8509..be05e1be08d44e5d82c6e85348f39722ee398809 100644 (file)
@@ -5,8 +5,10 @@ Add a hack to detect missing cores.
 
 Signed-off-by: Felix Fietkau <nbd@nbd.name>
 
---- a/arch/mips/kernel/smp-cps.c
-+++ b/arch/mips/kernel/smp-cps.c
+Index: linux-4.4.74/arch/mips/kernel/smp-cps.c
+===================================================================
+--- linux-4.4.74.orig/arch/mips/kernel/smp-cps.c
++++ linux-4.4.74/arch/mips/kernel/smp-cps.c
 @@ -44,6 +44,11 @@ static unsigned core_vpe_count(unsigned
        return (cfg >> CM_GCR_Cx_CONFIG_PVPE_SHF) + 1;
  }
@@ -28,8 +30,10 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
                core_vpes = core_vpe_count(c);
                pr_cont("%c%u", c ? ',' : '{', core_vpes);
  
---- a/arch/mips/ralink/mt7621.c
-+++ b/arch/mips/ralink/mt7621.c
+Index: linux-4.4.74/arch/mips/ralink/mt7621.c
+===================================================================
+--- linux-4.4.74.orig/arch/mips/ralink/mt7621.c
++++ linux-4.4.74/arch/mips/ralink/mt7621.c
 @@ -20,6 +20,7 @@
  #include <asm/mips-cpc.h>
  #include <asm/mach-ralink/ralink_regs.h>
diff --git a/target/linux/ramips/patches-4.4/101-mt7621-timer.patch b/target/linux/ramips/patches-4.4/101-mt7621-timer.patch
new file mode 100644 (file)
index 0000000..d266103
--- /dev/null
@@ -0,0 +1,192 @@
+Index: linux-4.4.74/arch/mips/include/asm/smp.h
+===================================================================
+--- linux-4.4.74.orig/arch/mips/include/asm/smp.h
++++ linux-4.4.74/arch/mips/include/asm/smp.h
+@@ -16,12 +16,14 @@
+ #include <linux/smp.h>
+ #include <linux/threads.h>
+ #include <linux/cpumask.h>
++#include <linux/cache.h>
+ #include <linux/atomic.h>
+ #include <asm/smp-ops.h>
++#include <asm/percpu.h>
+ extern int smp_num_siblings;
+-extern cpumask_t cpu_sibling_map[];
++DECLARE_PER_CPU_SHARED_ALIGNED(cpumask_t, cpu_sibling_map);
+ extern cpumask_t cpu_core_map[];
+ extern cpumask_t cpu_foreign_map;
+Index: linux-4.4.74/arch/mips/kernel/proc.c
+===================================================================
+--- linux-4.4.74.orig/arch/mips/kernel/proc.c
++++ linux-4.4.74/arch/mips/kernel/proc.c
+@@ -134,6 +134,14 @@ static int show_cpuinfo(struct seq_file
+       seq_printf(m, "package\t\t\t: %d\n", cpu_data[n].package);
+       seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core);
++#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
++      if (cpu_has_mipsmt) {
++              seq_printf(m, "VPE\t\t\t: %d\n", cpu_data[n].vpe_id);
++#if defined(CONFIG_MIPS_MT_SMTC)
++              seq_printf(m, "TC\t\t\t: %d\n", cpu_data[n].tc_id);
++#endif
++      }
++#endif
+       sprintf(fmt, "VCE%%c exceptions\t\t: %s\n",
+                     cpu_has_vce ? "%u" : "not available");
+       seq_printf(m, fmt, 'D', vced_count);
+Index: linux-4.4.74/arch/mips/kernel/smp-cmp.c
+===================================================================
+--- linux-4.4.74.orig/arch/mips/kernel/smp-cmp.c
++++ linux-4.4.74/arch/mips/kernel/smp-cmp.c
+@@ -43,9 +43,19 @@ static void cmp_init_secondary(void)
+ {
+       struct cpuinfo_mips *c __maybe_unused = &current_cpu_data;
++#ifdef CONFIG_SOC_MT7621
++      if(cpu_has_veic) {
++              change_c0_status(ST0_IM, 0);
++      } else {
++              change_c0_status(ST0_IM, STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6 | STATUSF_IP7);
++      }
++#else
+       /* Assume GIC is present */
+       change_c0_status(ST0_IM, STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 |
+                                STATUSF_IP5 | STATUSF_IP6 | STATUSF_IP7);
++#endif
++
++      c->core = (read_c0_ebase() & 0x3ff) >> (fls(smp_num_siblings)-1);
+       /* Enable per-cpu interrupts: platform specific */
+Index: linux-4.4.74/arch/mips/kernel/smp.c
+===================================================================
+--- linux-4.4.74.orig/arch/mips/kernel/smp.c
++++ linux-4.4.74/arch/mips/kernel/smp.c
+@@ -57,8 +57,8 @@ int smp_num_siblings = 1;
+ EXPORT_SYMBOL(smp_num_siblings);
+ /* representing the TCs (or siblings in Intel speak) of each logical CPU */
+-cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
+-EXPORT_SYMBOL(cpu_sibling_map);
++DEFINE_PER_CPU_SHARED_ALIGNED(struct cpumask, cpu_sibling_map);
++EXPORT_PER_CPU_SYMBOL(cpu_sibling_map);
+ /* representing the core map of multi-core chips of each logical CPU */
+ cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
+@@ -89,12 +89,13 @@ static inline void set_cpu_sibling_map(i
+               for_each_cpu(i, &cpu_sibling_setup_map) {
+                       if (cpu_data[cpu].package == cpu_data[i].package &&
+                                   cpu_data[cpu].core == cpu_data[i].core) {
+-                              cpumask_set_cpu(i, &cpu_sibling_map[cpu]);
+-                              cpumask_set_cpu(cpu, &cpu_sibling_map[i]);
++                                      cpumask_set_cpu(i, &per_cpu(cpu_sibling_map, cpu));
++                                      cpumask_set_cpu(cpu, &per_cpu(cpu_sibling_map, i));
++
+                       }
+               }
+       } else
+-              cpumask_set_cpu(cpu, &cpu_sibling_map[cpu]);
++              cpumask_set_cpu(cpu, &per_cpu(cpu_sibling_map, cpu));
+ }
+ static inline void set_cpu_core_map(int cpu)
+Index: linux-4.4.74/arch/mips/ralink/mt7621.c
+===================================================================
+--- linux-4.4.74.orig/arch/mips/ralink/mt7621.c
++++ linux-4.4.74/arch/mips/ralink/mt7621.c
+@@ -21,6 +21,7 @@
+ #include <asm/mach-ralink/ralink_regs.h>
+ #include <asm/mach-ralink/mt7621.h>
+ #include <asm/mips-boards/launch.h>
++#include <asm/delay.h>
+ #include <pinmux.h>
+@@ -178,6 +179,58 @@ bool plat_cpu_core_present(int core)
+       return true;
+ }
++#define LPS_PREC 8
++/*
++*  Re-calibration lpj(loop-per-jiffy).
++*  (derived from kernel/calibrate.c)
++*/
++static int udelay_recal(void)
++{
++      unsigned int i, lpj = 0;
++      unsigned long ticks, loopbit;
++      int lps_precision = LPS_PREC;
++
++      lpj = (1<<12);
++
++      while ((lpj <<= 1) != 0) {
++              /* wait for "start of" clock tick */
++              ticks = jiffies;
++              while (ticks == jiffies)
++                      /* nothing */;
++
++              /* Go .. */
++              ticks = jiffies;
++              __delay(lpj);
++              ticks = jiffies - ticks;
++              if (ticks)
++                      break;
++      }
++
++      /*
++       * Do a binary approximation to get lpj set to
++       * equal one clock (up to lps_precision bits)
++       */
++      lpj >>= 1;
++      loopbit = lpj;
++      while (lps_precision-- && (loopbit >>= 1)) {
++              lpj |= loopbit;
++              ticks = jiffies;
++              while (ticks == jiffies)
++                      /* nothing */;
++              ticks = jiffies;
++              __delay(lpj);
++              if (jiffies != ticks)   /* longer than 1 tick */
++                      lpj &= ~loopbit;
++      }
++      printk(KERN_INFO "%d CPUs re-calibrate udelay(lpj = %d)\n", NR_CPUS, lpj);
++
++      for(i=0; i< NR_CPUS; i++)
++              cpu_data[i].udelay_val = lpj;
++
++      return 0;
++}
++device_initcall(udelay_recal);
++
+ void prom_soc_init(struct ralink_soc_info *soc_info)
+ {
+       void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE);
+Index: linux-4.4.74/arch/mips/include/asm/topology.h
+===================================================================
+--- linux-4.4.74.orig/arch/mips/include/asm/topology.h
++++ linux-4.4.74/arch/mips/include/asm/topology.h
+@@ -15,7 +15,7 @@
+ #define topology_physical_package_id(cpu)     (cpu_data[cpu].package)
+ #define topology_core_id(cpu)                 (cpu_data[cpu].core)
+ #define topology_core_cpumask(cpu)            (&cpu_core_map[cpu])
+-#define topology_sibling_cpumask(cpu)         (&cpu_sibling_map[cpu])
++#define topology_sibling_cpumask(cpu)         (&per_cpu(cpu_sibling_map, cpu))
+ #endif
+ #endif /* __ASM_TOPOLOGY_H */
+Index: linux-4.4.74/arch/mips/mm/c-r4k.c
+===================================================================
+--- linux-4.4.74.orig/arch/mips/mm/c-r4k.c
++++ linux-4.4.74/arch/mips/mm/c-r4k.c
+@@ -103,7 +103,7 @@ static inline void r4k_on_each_cpu(unsig
+               /* exclude sibling CPUs */
+               cpumask_andnot(&mask, &cpu_foreign_map,
+-                             &cpu_sibling_map[smp_processor_id()]);
++                             &per_cpu(cpu_sibling_map, smp_processor_id()));
+               smp_call_function_many(&mask, func, info, 1);
+       }
+ #endif