[Letux-kernel] Timers (was Re: [PATCH 00/20] A bunch of JZ4730 fixups for letux-kernel)

H. Nikolaus Schaller hns at goldelico.com
Tue Jan 19 13:35:50 CET 2021


> Am 19.01.2021 um 10:45 schrieb H. Nikolaus Schaller <hns at goldelico.com>:
> 
> 
>> Am 19.01.2021 um 10:15 schrieb H. Nikolaus Schaller <hns at goldelico.com>:
>> 
>> So we have learned that sleep 10 indeed calls hrtimer_nanosleep() resp.
>> do_nanosleep() and there we somehow get the factor 2 compared to what
>> user-space assumes.
>> 
>> We are getting closer...
> 
> ok, starting a hrtimer goes down to clockevents_program_event()
> This uses a struct clock_event_device which controls the real
> hardware.
> 
> Do we have an idea which one we use on the jz4730?
> 
> Seems to be
> 
> https://elixir.bootlin.com/linux/v5.11-rc3/source/drivers/clocksource/ingenic-timer.c#L35
> 
> So we are back at the TCU and OST driver!
> 
> After studying the code I think I got it:
> 
> ingenic_tcu_cevt_set_next()
> 
> There, we are simply writing the next value to TCU_JZ4730_REG_TRDRc
> without taking into account that it is counting backwards. IMHO it must
> be the reverse operation to ingenic_tcu_timer_read() so that
> 
> ingenic_tcu_cevt_set_next(value, ...);
> ingenic_tcu_timer_read();
> 
> should return almost the same value!

Generally a broken hrtimer would also explains some timeout issued with the i2c driver.
If system timers aren't working properly we can't expect wait_for_completion_timeout()
to be precise.

Replacing code by

	regmap_write(tcu->map, TCU_JZ4730_REG_TRDRc(timer->channel), 0xffff - next);
	regmap_write(tcu->map, TCU_JZ4730_REG_TCNTc(timer->channel), 0xffff);

makes the heartbeat blink a little faster. But the sleep still waits twice the time.
So we are missing something else.

Ah, well. TRDR is the *re*load register after timer expires. If we use it as a one-shot
timer its value doesn't care. Rather we should set the TCNT := next ?

I am not exactly sure what the semantics of the next value is. Most likely it should
be the number of clock cycles until the interrupt occurs.

If that is right, the jz4740 will initialize the reload register with the next value
and set the data register to 0 so that the counter counts "next" clocks until it reaches
the reload register value.

For the reverse counting jz4730 we must then initialize the reload register to any
value (don't care or use the same value so that ingenic_tcu_timer_read is correct)
and initialize the counter register to "next". I.e.

	regmap_write(tcu->map, TCU_JZ4730_REG_TRDRc(timer->channel), next);
	regmap_write(tcu->map, TCU_JZ4730_REG_TCNTc(timer->channel), next);

Then the counter will start counting backwards for "next" clock cycles until it
reaches 0.

Yay, thats it!

Boot log time is now monotonic and in correct speed:

[    0.000000] random: get_random_bytes called from start_kernel+0x720/0x960 with crng_init=0
[    0.000000] clocksource: ingenic-timer: mask: 0xffff max_cycles: 0xffff, max_idle_ns: 7910990 ns
[    0.000015] sched_clock: 16 bits at 3686kHz, resolution 271ns, wraps every 8888753ns
[    0.010268] Console: colour dummy device 80x25
[    0.014938] Calibrating delay loop... 334.23 BogoMIPS (lpj=1671168)
[    0.067230] pid_max: default: 32768 minimum: 301
[    0.072849] LSM: Security Framework initializing
[    0.077960] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[    0.085695] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[    0.104984] rcu: Hierarchical SRCU implementation.
[    0.113123] devtmpfs: initialized
[    0.141081] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[    0.153287] futex hash table entries: 256 (order: -1, 3072 bytes, linear)
[    0.168503] pinctrl core: initialized pinctrl subsystem
[    0.178816] regulator-dummy: no parameters, enabled
[    0.191732] NET: Registered protocol family 16
[    0.225011] thermal_sys: Registered thermal governor 'fair_share'
[    0.225096] thermal_sys: Registered thermal governor 'step_wise'
[    0.235097] thermal_sys: Registered thermal governor 'user_space'
[    0.886647] jz4780_dma_probe
[    0.936916] jz4780_dma_probe 1 res=83957f20
[    0.941232] jz4780_dma_probe 1b chn_base=b3020000
[    0.946009] jz4780_dma_probe 1c ctrl_base=b30200f8
[    0.951262] jz4780_dma_probe 2
[    0.954438] jz4780_dma_probe 3
[    0.957563] jz4780_dma_probe 4
[    0.960658] jz4780_dma_probe 5
[    0.964117] jz4780_dma_probe 6
[    0.967227] jz4780_dma_probe 7
[    0.970325] jz4780_dma_probe 8
[    0.973489] jz4780_dma_probe 9
[    0.976965] jz4780_dma_probe 10
[    0.992040] jz4780_dma_probe 11
[    0.995258] jz4780-dma 13020000.dma: JZ4780 DMA controller initialised
[    1.007221] vcc: 3300 mV, enabled
[    1.016350] reg-fixed-voltage regulator at 0: vcc supplying 3300000uV
[    1.025433] vmmc: 3300 mV, disabled
[    1.032428] reg-fixed-voltage regulator at 1: vmmc supplying 3300000uV
[    1.049989] SCSI subsystem initialized
[    1.060351] libata version 3.00 loaded.
[    1.075234] usbcore: registered new interface driver usbfs

Heartbeat is blinking fast, sleep 10 sleeps exactly 10 seconds:

root at letux:~# cat </dev/tcp/time.nist.gov/13 && sleep 10 && cat </dev/tcp/time.nist.gov/13

59233 21-01-19 11:36:50 00 0 0 793.6 UTC(NIST) * 

59233 21-01-19 11:37:00 00 0 0 205.5 UTC(NIST) * 
root at letux:~# 

ntp date sync is working:

root at letux:~# date
Tue Jan 19 12:18:00 UTC 2021
root at letux:~# 

root at letux:~# ./diskspeed 
+++ checking /dev/mmcblk0 +++

And we can check the real MMC data rate (non-DMA):

/dev/mmcblk0:
 Timing O_DIRECT cached reads:    20 MB in  2.02 seconds =   9.90 MB/sec
 Timing O_DIRECT disk reads:  30 MB in  3.04 seconds =   9.87 MB/sec
root at letux:~# 

Only sysbench still gets stuck (or runs forever - or at least more than 50 minutes).

So its time for a git push of the consolidated tree...

BR,
Nikolaus




More information about the Letux-kernel mailing list