This uses the generic arch_early_time support added in the pervious patch to
define an ARM globaltimer-based implementation that can be selected by a
CONFIG and enabled and configured through Device Tree.

It uses the early time to provide detailed and consistent time information
in your logs.  For example, what used to look like this

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 3.11.0-linaro_fjslt-tracking-bsp2.0.0-rc1+ 
(agr...@build.warmcat.com) (gcc version 4.7.3 20130205 (prerelease) 
(crosstool-NG linaro-1.13.1-4.7-2013.02-01-20130221 - Linaro GCC 2013.02) ) 
#193 SMP PREEMPT Thu Aug 8 09:13:53 CST 2013
[    0.000000] CPU: ARMv7 Processor [412fc092] revision 2 (ARMv7), cr=50c5387d
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing 
instruction cache
[    0.000000] Machine: Fujitsu Semiconductor MB8AC0300-EVB, model: Fujitsu 
MB8AC0300 Evaluation Board
[    0.000000] early_init_dt_add_memory_arch: 40000000 10000000
[    0.000000] cma: CMA: reserved 64 MiB at 4c000000
[    0.000000] Memory policy: ECC disabled, Data cache writealloc
[    0.000000] On node 0 totalpages: 65536
[    0.000000]   Normal zone: 512 pages used for memmap
[    0.000000]   Normal zone: 0 pages reserved
[    0.000000]   Normal zone: 65536 pages, LIFO batch:15
[    0.000000] PERCPU: Embedded 7 pages/cpu @804f4000 s7296 r8192 d13184 u32768
[    0.000000] pcpu-alloc: s7296 r8192 d13184 u32768 alloc=8*4096
[    0.000000] pcpu-alloc: [0] 0 [0] 1
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total 
pages: 65024
[    0.000000] Kernel command line: loglevel=4 mb8ac0300_ts.adjust_y=-40 
console=tty0 console=ttyS0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rw 
rootwait
[    0.000000] PID hash table entries: 1024 (order: 0, 4096 bytes)
[    0.000000] Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
[    0.000000] Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
[    0.000000] Memory: 191100K/262144K available (1734K kernel code, 115K 
rwdata, 716K rodata, 107K init, 236K bss, 71044K reserved, 0K highmem)
[    0.000000] Virtual kernel memory layout:
[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.000000]     fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
[    0.000000]     vmalloc : 0x90800000 - 0xff000000   (1768 MB)
[    0.000000]     lowmem  : 0x80000000 - 0x90000000   ( 256 MB)
[    0.000000]     pkmap   : 0x7fe00000 - 0x80000000   (   2 MB)
[    0.000000]     modules : 0x7f800000 - 0x7fe00000   (   6 MB)
[    0.000000]       .text : 0x80008000 - 0x8026cb28   (2451 kB)
[    0.000000]       .init : 0x8026d000 - 0x80287c80   ( 108 kB)
[    0.000000]       .data : 0x80288000 - 0x802a4ca0   ( 116 kB)
[    0.000000]        .bss : 0x802a4ca0 - 0x802dff74   ( 237 kB)
[    0.000000] Preemptible hierarchical RCU implementation.
[    0.000000]  Dump stacks of tasks blocking RCU-preempt GP.
[    0.000000]  RCU restricting CPUs from NR_CPUS=4 to nr_cpu_ids=2.
[    0.000000] NR_IRQS:16 nr_irqs:16 16
[    0.000000] sched_clock: 32 bits at 41MHz, resolution 24ns, wraps every 
103727ms
[    0.000000] Console: colour dummy device 80x30
[    0.000000] console [tty0] enabled
[    0.000734] Calibrating delay loop... 1318.91 BogoMIPS (lpj=6594560)
...

will look like this

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 3.11.0-linaro_fjslt-tracking-bsp2.0.0-rc1+ 
(agr...@build.warmcat.com) (gcc version 4.7.3 20130205 (prerelease) 
(crosstool-NG linaro-1.13.1-4.7-2013.02-01-20130221 - Linaro GCC 2013.02) ) 
#241 SMP PREEMPT Fri Aug 9 21:33:12 CST 2013
[    0.000000] CPU: ARMv7 Processor [412fc092] revision 2 (ARMv7), cr=50c5387d
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing 
instruction cache
[    0.000000] Machine: Fujitsu Semiconductor MB8AC0300-EVB, model: Fujitsu 
MB8AC0300 Evaluation Board
[    0.000000] early_init_dt_add_memory_arch: 40000000 10000000
[    0.000000] cma: CMA: reserved 64 MiB at 4c000000
[    0.000000] Memory policy: ECC disabled, Data cache writealloc
[    0.008572] On node 0 totalpages: 65536
[    0.008592]   Normal zone: 512 pages used for memmap
[    0.008602]   Normal zone: 0 pages reserved
[    0.008612]   Normal zone: 65536 pages, LIFO batch:15
[    0.030325] PERCPU: Embedded 7 pages/cpu @804f8000 s7296 r8192 d13184 u32768
[    0.030354] pcpu-alloc: s7296 r8192 d13184 u32768 alloc=8*4096
[    0.030366] pcpu-alloc: [0] 0 [0] 1
[    0.030404] Built 1 zonelists in Zone order, mobility grouping on.  Total 
pages: 65024
[    0.030419] Kernel command line: loglevel=4 mb8ac0300_ts.adjust_y=-40 
console=tty0 console=ttyS0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rw 
rootwait
[    0.030632] PID hash table entries: 1024 (order: 0, 4096 bytes)
[    0.030784] Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
[    0.031051] Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
[    0.039034] Memory: 191084K/262144K available (1738K kernel code, 115K 
rwdata, 716K rodata, 107K init, 243K bss, 71060K reserved, 0K highmem)
[    0.039091] Virtual kernel memory layout:
[    0.039091]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.039091]     fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
[    0.039091]     vmalloc : 0x90800000 - 0xff000000   (1768 MB)
[    0.039091]     lowmem  : 0x80000000 - 0x90000000   ( 256 MB)
[    0.039091]     pkmap   : 0x7fe00000 - 0x80000000   (   2 MB)
[    0.039091]     modules : 0x7f800000 - 0x7fe00000   (   6 MB)
[    0.039091]       .text : 0x80008000 - 0x8026db50   (2455 kB)
[    0.039091]       .init : 0x8026e000 - 0x80288c80   ( 108 kB)
[    0.039091]       .data : 0x8028a000 - 0x802a6d20   ( 116 kB)
[    0.039091]        .bss : 0x802a6d20 - 0x802e3bb4   ( 244 kB)
[    0.039335] Preemptible hierarchical RCU implementation.
[    0.039349]  Dump stacks of tasks blocking RCU-preempt GP.
[    0.039360]  RCU restricting CPUs from NR_CPUS=4 to nr_cpu_ids=2.
[    0.039399] NR_IRQS:16 nr_irqs:16 16
[    0.047124] sched_clock: 32 bits at 41MHz, resolution 24ns, wraps every 
103727ms
[    0.047659] Console: colour dummy device 80x30
[    0.047851] console [tty0] enabled
[    0.047896] Calibrating delay loop... 1318.91 BogoMIPS (lpj=6594560)
[    0.137135] pid_max: default: 32768 minimum: 301

By contrast starting time just before the MMU is enabled (which is before we
can reasonably use DT) nets this

[    0.000418] Booting Linux on physical CPU 0x0
[    0.000439] Linux version 3.11.0-linaro_fjslt-tracking-bsp2.0.0-rc1+ 
(agr...@build.warmcat.com) (gcc version 4.7.3 20130205 (prerelease) 
(crosstool-NG linaro-1.13.1-4.7-2013.02-01-20130221 - Linaro GCC 2013.02) ) 
#194 SMP PREEMPT Thu Aug 8 09:16:22 CST 2013
[    0.000468] CPU: ARMv7 Processor [412fc092] revision 2 (ARMv7), cr=50c5387d
[    0.000481] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing 
instruction cache
[    0.000504] Machine: Fujitsu Semiconductor MB8AC0300-EVB, model: Fujitsu 
MB8AC0300 Evaluation Board
[    0.000664] early_init_dt_add_memory_arch: 40000000 10000000
[    0.000824] cma: CMA: reserved 64 MiB at 4c000000
[    0.000838] Memory policy: ECC disabled, Data cache writealloc
[    0.010319] On node 0 totalpages: 65536

The implemented way time starts 1.75ms after the MMU enable code, 3.7%
compared to the 47ms before normal time starts (and the test kernel was
restricted to 256MB memory - it's 344ms (0.5%) before time starts for
2GByte memory on the same machine)

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 3.11.0-linaro_fjslt-tracking-bsp2.0.0-rc1+ 
(agr...@build.warmcat.com) (gcc version 4.7.3 20130205 (prerelease) 
(crosstool-NG linaro-1.13.1-4.7-2013.02-01-20130221 - Linaro GCC 2013.02) ) 
#236 SMP PREEMPT Fri Aug 9 17:24:47 CST 2013
[    0.000000] CPU: ARMv7 Processor [412fc092] revision 2 (ARMv7), cr=50c5387d
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing 
instruction cache
[    0.000000] Machine: Fujitsu Semiconductor MB8AC0300-EVB, model: Fujitsu 
MB8AC0300 Evaluation Board
[    0.000000] cma: CMA: reserved 64 MiB at ab800000
[    0.000000] Memory policy: ECC disabled, Data cache writealloc
[    0.026238] On node 0 totalpages: 524288
[    0.043005] free_area_init_node: node 0, pgdat 802a0000, node_mem_map 
81007000
[    0.043017]   Normal zone: 3568 pages used for memmap
[    0.043027]   Normal zone: 0 pages reserved
[    0.043038]   Normal zone: 456704 pages, LIFO batch:31
[    0.156275]   HighMem zone: 528 pages used for memmap
[    0.156291]   HighMem zone: 67584 pages, LIFO batch:15
[    0.173801] PERCPU: Embedded 7 pages/cpu @82017000 s7296 r8192 d13184 u32768
[    0.173830] pcpu-alloc: s7296 r8192 d13184 u32768 alloc=8*4096
[    0.173840] pcpu-alloc: [0] 0 [0] 1
[    0.173879] Built 1 zonelists in Zone order, mobility grouping on.  Total 
pages: 520720
[    0.173895] Kernel command line: loglevel=4 mb8ac0300_ts.adjust_y=-40 
console=tty0 console=ttyS0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rw 
rootwait
[    0.174128] PID hash table entries: 4096 (order: 2, 16384 bytes)
[    0.175201] Dentry cache hash table entries: 262144 (order: 8, 1048576 bytes)
[    0.177230] Inode-cache hash table entries: 131072 (order: 7, 524288 bytes)
[    0.336193] Memory: 2010448K/2097152K available (1729K kernel code, 115K 
rwdata, 704K rodata, 107K init, 243K bss, 86704K reserved, 270336K highmem)
[    0.336248] Virtual kernel memory layout:
[    0.336248]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.336248]     fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
[    0.336248]     vmalloc : 0xf0000000 - 0xff000000   ( 240 MB)
[    0.336248]     lowmem  : 0x80000000 - 0xef800000   (1784 MB)
[    0.336248]     pkmap   : 0x7fe00000 - 0x80000000   (   2 MB)
[    0.336248]     modules : 0x7f800000 - 0x7fe00000   (   6 MB)
[    0.336248]       .text : 0x80008000 - 0x802689b4   (2435 kB)
[    0.336248]       .init : 0x80269000 - 0x80283c80   ( 108 kB)
[    0.336248]       .data : 0x80284000 - 0x802a0cc0   ( 116 kB)
[    0.336248]        .bss : 0x802a0cc0 - 0x802ddab4   ( 244 kB)
[    0.336493] Preemptible hierarchical RCU implementation.
[    0.336506]  Dump stacks of tasks blocking RCU-preempt GP.
[    0.336518]  RCU restricting CPUs from NR_CPUS=4 to nr_cpu_ids=2.
[    0.336555] NR_IRQS:16 nr_irqs:16 16
[    0.344257] sched_clock: 32 bits at 41MHz, resolution 24ns, wraps every 
103727ms
[    0.344788] Console: colour dummy device 80x30
[    0.344985] console [tty0] enabled
[    0.345045] Calibrating delay loop... 1318.91 BogoMIPS (lpj=6594560)

when normal time starts, it is offset by the corresponding early time, so the 
logs are
monotonic and consistent in time.

To use enable

CONFIG_EARLY_TIME_ARM_GLOBALTIMER=y

A Device Tree stanza like this should be added to the top level description.
The first reg / size pair is the physical address and the second pair the
virtual address.

early-time {
        compatible = "arm,globaltimer";
        reg = <0xf8100000 0x1000>, <0xfd100000 0x1000>;
        freq = <165500000>;
        zero = <1>;
        cpumask = <3>;
};

Signed-off-by: Andy Green <andy.gr...@linaro.org>
---
 arch/arm/Kconfig                  |    4 +
 arch/arm/Kconfig.debug            |   10 ++++
 arch/arm/boot/dts/mb8ac0300eb.dts |    8 +++
 arch/arm/kernel/time.c            |  101 +++++++++++++++++++++++++++++++++++++
 arch/arm/mm/mmu.c                 |   49 ++++++++++++++++++
 5 files changed, 172 insertions(+)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index f3f4bcf..a3b1d75 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -2311,6 +2311,10 @@ config ARM_CPU_SUSPEND
 
 endmenu
 
+config HAS_ARCH_EARLY_TIME
+       bool
+       default n
+
 source "net/Kconfig"
 
 source "drivers/Kconfig"
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index de41088..10b4249 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -900,4 +900,14 @@ config PID_IN_CONTEXTIDR
          additional instructions during context switch. Say Y here only if you
          are planning to use hardware trace tools with this kernel.
 
+config EARLY_TIME_ARM_GLOBALTIMER
+       bool "Enable early Arm globaltimer support"
+       default n
+       select HAS_ARCH_EARLY_TIME
+       help
+         If you have a spare globaltimer in your SoC, you can use it to
+         get accurate log timings starting from very early in boot and
+         before the very first log entry.
+         You'll need to speify some additional gnarly details if enabled.
+
 endmenu
diff --git a/arch/arm/boot/dts/mb8ac0300eb.dts 
b/arch/arm/boot/dts/mb8ac0300eb.dts
index 76878d6..875649b 100644
--- a/arch/arm/boot/dts/mb8ac0300eb.dts
+++ b/arch/arm/boot/dts/mb8ac0300eb.dts
@@ -29,6 +29,14 @@
                linux,initrd-end = <0>;
        };
 
+       early-time {
+               compatible = "arm,globaltimer";
+               reg = <0xf8100000 0x1000>, <0xfd100000 0x1000>;
+               freq = <165500000>;
+               zero = <1>;
+               cpumask = <3>;
+       };
+
        alsa: mb8ac0300_adau1361 {
                compatible = "fujitsu,mb8ac0300_adau1361";
                channel = <0>;
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 98aee32..37b570f 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -25,11 +25,15 @@
 #include <linux/clocksource.h>
 #include <linux/irq.h>
 #include <linux/sched_clock.h>
+#include <linux/of_fdt.h>
 
 #include <asm/thread_info.h>
 #include <asm/stacktrace.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
+#include <asm/mach/map.h>
+#include <asm/io.h>
+#include <asm/div64.h>
 
 #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || \
     defined(CONFIG_NVRAM) || defined(CONFIG_NVRAM_MODULE)
@@ -121,3 +125,100 @@ void __init time_init(void)
        else
                clocksource_of_init();
 }
+
+#ifdef CONFIG_EARLY_TIME_ARM_GLOBALTIMER
+
+static void __iomem *etagt_base;
+static u32 etagt_ps;
+
+#define GLOBALTIMER_CPU_ACCESS_OFS 0x54
+#define GLOBALTIMER_LOW_OFS 0x200
+#define GLOBALTIMER_HIGH_OFS 0x204
+#define GLOBALTIMER_ENABLE_OFS 0x208
+
+void arch_early_time_init(unsigned long node)
+{
+       const u32 *reg;
+       const u32 *freq;
+       const u32 *zero;
+       const u32 *cpumask;
+       unsigned long l;
+       u64 ps = 1024000000000ull;
+
+       /* already checked by caller */
+       reg = of_get_flat_dt_prop(node, "reg", &l);
+       etagt_base = (void __iomem *)be32_to_cpu(reg[2]);
+
+       freq = of_get_flat_dt_prop(node, "freq", &l);
+       if (!freq || l != 4) {
+               pr_err("%s NULL freq or len %lu\n", __func__, l);
+               return;
+       }
+
+       zero = of_get_flat_dt_prop(node, "zero", &l);
+       if (!zero)
+               return;
+
+       cpumask = of_get_flat_dt_prop(node, "cpumask", &l);
+       if (!cpumask)
+               return;
+
+       do_div(ps, be32_to_cpu(*freq));
+       etagt_ps = (u32)ps;
+
+       __raw_writel(be32_to_cpu(*cpumask),
+                       etagt_base + GLOBALTIMER_CPU_ACCESS_OFS);
+       if (be32_to_cpu(*zero)) {
+
+               /* zero the globaltimer */
+
+               __raw_writel(0, etagt_base + GLOBALTIMER_ENABLE_OFS);
+               __raw_writel(0, etagt_base + GLOBALTIMER_LOW_OFS);
+               __raw_writel(0, etagt_base + GLOBALTIMER_HIGH_OFS);
+       }
+       __raw_writel(1, etagt_base + GLOBALTIMER_ENABLE_OFS);
+}
+EXPORT_SYMBOL_GPL(arch_early_time_init);
+
+u64 arch_early_time(u64 normal)
+{
+       u64 ts;
+       static u64 handover;
+
+       /* configured but not enabled in dt */
+
+       if (!etagt_ps)
+               return normal;
+
+       /* if normal time had started already, just return the offset */
+
+       if (handover)
+               return handover + normal;
+
+       /* otherwise find out the early time */
+
+       ts = __raw_readl(etagt_base + GLOBALTIMER_LOW_OFS);
+       ts |= ((u64)__raw_readl(etagt_base + GLOBALTIMER_HIGH_OFS)) << 32;
+
+       /* convert early time to elapsed ps */
+
+       ts = (ts * etagt_ps) >> 10;
+
+       /*
+        * has some normal time appeared?  Let's stop our early time and
+        * keep it for use as an offset, so we get monotonic logs
+        * Subtract the normal time to make the sample above a valid
+        * offset for 0 normal time.
+        */
+
+       if (!handover && normal) {
+               ts -= normal;
+               handover = ts;
+       }
+
+       return ts + normal;
+}
+EXPORT_SYMBOL_GPL(arch_early_time);
+
+#endif
+
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index bf5731e..29f4017 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -17,6 +17,8 @@
 #include <linux/fs.h>
 #include <linux/vmalloc.h>
 #include <linux/sizes.h>
+#include <linux/of_fdt.h>
+#include <linux/time.h>
 
 #include <asm/cp15.h>
 #include <asm/cputype.h>
@@ -1167,6 +1169,49 @@ void __init arm_mm_memblock_reserve(void)
 #endif
 }
 
+#ifdef CONFIG_EARLY_TIME_ARM_GLOBALTIMER
+int __init early_init_dt_scan_earlytime(unsigned long node, const char *uname,
+                                    int depth, void *data)
+{
+       unsigned long l;
+       char *p;
+       struct map_desc map;
+       const u32 *reg;
+
+       pr_debug("search \"early-time\", depth: %d, uname: %s\n", depth, uname);
+
+       if (depth != 1 || strcmp(uname, "early-time"))
+               return 0;
+
+       p = of_get_flat_dt_prop(node, "compatible", &l);
+       if (!p)
+               return 1;
+
+       /* todo use a section to register multiple handlers */
+       if (strcmp(p, "arm,globaltimer"))
+               return 1;
+
+       /* do the mapping here where we can reach create_mapping */
+
+       reg = of_get_flat_dt_prop(node, "reg", &l);
+       if (!reg || l != 16) {
+               pr_err("%s: NULL reg or bad len %lu\n", __func__, l);
+               return 1;
+       }
+
+       map.pfn = __phys_to_pfn(be32_to_cpu(reg[0]));
+       map.virtual = be32_to_cpu(reg[2]);
+       map.length = be32_to_cpu(reg[1]);
+       map.type = MT_DEVICE;
+       create_mapping(&map);
+
+       arch_early_time_init(node);
+
+       /* break now */
+       return 1;
+}
+#endif
+
 /*
  * Set up the device mappings.  Since we clear out the page tables for all
  * mappings above VMALLOC_START, we will remove any debug device mappings.
@@ -1246,6 +1291,10 @@ static void __init devicemaps_init(struct machine_desc 
*mdesc)
                debug_ll_io_init();
        fill_pmd_gaps();
 
+#ifdef CONFIG_EARLY_TIME_ARM_GLOBALTIMER
+       /* early time */
+       of_scan_flat_dt(early_init_dt_scan_earlytime, NULL);
+#endif
        /* Reserve fixed i/o space in VMALLOC region */
        pci_reserve_io();
 


_______________________________________________
linaro-dev mailing list
linaro-dev@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/linaro-dev

Reply via email to