From: Jon Hunter <hidden> Date: 2012-09-05 19:04:22
This series includes several fixes for the OMAP DMTIMER driver and a few
clean-ups to simplify some of the code. This series is based upon 3.6-rc4.
Tested on OMAP5912 OSK, OMAP2420 H4, OMAP3430 Beagle and OMAP4430 Panda.
Testing includes ...
1. Booting kernel on above boards
2. Set date and ensuring time of day is correct after 24 hours
3. Checking the timer counter is incrementing when configuring and starting
a timer
4. Checking the timer overflow interrupt when timer expires.
5. Using different clock sources to operate the timer with.
6. Running a loop test overnight that continually runs test #3 and #4 for
each available timer
Jon Hunter (10):
ARM: OMAP3+: Implement timer workaround for errata i103 and i767
ARM: OMAP: Fix timer posted mode support
ARM: OMAP3: Correct HWMOD DMTIMER SYSC register declarations
ARM: OMAP2/3: Define HWMOD software reset status for DMTIMERs
ARM: OMAP2+: Don't use __omap_dm_timer_reset()
ARM: OMAP: Fix dmtimer reset for timer1
ARM: OMAP: Clean-up dmtimer reset code
ARM: OMAP: Clean-up timer posted mode support
ARM: OMAP: Add dmtimer interrupt disable function
ARM: OMAP: Remove unnecessary call to clk_get()
arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c | 15 ++-
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 41 ++++----
arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 4 +
arch/arm/mach-omap2/timer.c | 27 +++--
arch/arm/plat-omap/dmtimer.c | 109 +++++++++++++-------
arch/arm/plat-omap/include/plat/dmtimer.h | 95 ++++++++++-------
6 files changed, 184 insertions(+), 107 deletions(-)
--
1.7.9.5
From: Jon Hunter <hidden> Date: 2012-09-05 19:04:23
Errata Titles:
i103: Delay needed to read some GP timer, WD timer and sync timer registers
after wakeup (OMAP3/4)
i767: Delay needed to read some GP timer registers after wakeup (OMAP5)
Description (i103/i767):
If a General Purpose Timer (GPTimer) is in posted mode (TSICR [2].POSTED=1),
due to internal resynchronizations, values read in TCRR, TCAR1 and TCAR2
registers right after the timer interface clock (L4) goes from stopped to
active may not return the expected values. The most common event leading to
this situation occurs upon wake up from idle.
GPTimer non-posted synchronization mode is not impacted by this limitation.
Workarounds:
1). Disable posted mode
2). Use static dependency between timer clock domain and MPUSS clock domain
3). Use no-idle mode when the timer is active
Workarounds #2 and #3 are not pratical from a power standpoint and so
workaround #1 has been implemented. Disabling posted mode adds some CPU overhead
for configuring the timers as the CPU has to wait for the write to complete.
However, disabling posted mode guarantees correct operation.
Please note that it is safe to use posted mode for timers if the counter (TCRR)
and capture (TCARx) registers will never be read. An example of this is the
clock-event system timer. This is used by the kernel to schedule events however,
the timers counter is never read and capture registers are not used. Given that
the kernel configures this timer often yet never reads the counter register it
is safe to enable posted mode in this case. Hence, for the timer used for kernel
clock-events, posted mode is enabled by overriding the errata for devices that
are impacted by this defect.
Although both dmtimers and watchdogs are impacted by this defect this patch only
implements the workaround for the dmtimer. Currently the watchdog driver does
not read the counter register and so no workaround is necessary.
Confirmed with Vaibhav Hiremath that this bug also impacts AM33xx devices.
Signed-off-by: Jon Hunter <redacted>
---
arch/arm/mach-omap2/timer.c | 9 +++++++
arch/arm/plat-omap/dmtimer.c | 2 ++
arch/arm/plat-omap/include/plat/dmtimer.h | 39 +++++++++++++++++++++++++++++
3 files changed, 50 insertions(+)
From: Jon Hunter <hidden> Date: 2012-09-05 19:04:24
Currently the dmtimer posted mode is being enabled when the function
__omap_dm_timer_reset() is called. This function is only being called for
OMAP1 timers and OMAP2+ timers that are being used as system timers. Hence,
for OMAP2+ timers that are NOT being used as a system timer, posted mode is
not enabled but the "timer->posted" variable is still set (incorrectly) in
the omap_dm_timer_prepare() function.
This is a regression introduced by commit 3392cdd3 (ARM: OMAP: dmtimer:
switch-over to platform device driver) which changed the code to only call
omap_dm_timer_reset() for OMAP1 devices. Although this is a regression from
the original code it only impacts performance and so is not needed for stable.
Signed-off-by: Jon Hunter <redacted>
---
arch/arm/mach-omap2/timer.c | 3 +--
arch/arm/plat-omap/dmtimer.c | 14 +++++---------
arch/arm/plat-omap/include/plat/dmtimer.h | 9 ++++++++-
3 files changed, 14 insertions(+), 12 deletions(-)
From: Jon Hunter <hidden> Date: 2012-09-05 19:04:25
Currently, the OMAP3 HWMOD data defines two TIOCP_CFG register structures
(referred to as the SYSC register in the HWMOD data) where timers 1, 2 and 10
use one of the defintions and the other timers use the other definition. For
OMAP3 devices the structure of the DMTIMER TIOCP_CFG register is the same for
all 12 instances of the DMTIMER. Please note that this is a difference between
OMAP3 and OMAP4 and could be the source of the confusion.
For OMAP3 devices, the DMTIMER TIOCP_CFG register has the fields,
clock-activity, emufree, idlemode, enwakeup, softreset and autoidle for all
12 timers. Therefore, remove one of the SYSC register definitions for the
DMTIMERs and ensure the appropriate register fields are defined for all
DMTIMERs.
Signed-off-by: Jon Hunter <redacted>
---
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 27 ++++++---------------------
1 file changed, 6 insertions(+), 21 deletions(-)
From: Jon Hunter <hidden> Date: 2012-09-05 19:04:26
For OMAP2/3 devices, the HWMOD data does not define a software reset status
field for the DMTIMERs. Therefore, when HWMOD performs a soft-reset of the
DMTIMER we don't check and wait for the reset to complete. For OMAP2/3 devices,
the software reset status for a DMTIMER can be read from bit 0 of the DMTIMER
TISTAT register (referred to as the SYSS register in HWMOD). Add the
appropriate HWMOD definitions so that HWMOD will check the software reset
status when performing a software reset of the DMTIMER.
Signed-off-by: Jon Hunter <redacted>
---
arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c | 2 +-
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
From: Jon Hunter <hidden> Date: 2012-09-05 19:04:27
Currently OMAP2+ devices are using the function __omap_dm_timer_reset() to
configure the clock-activity, idle, wakeup-enable and auto-idle fields in the
timer OCP_CFG register. The name of the function is mis-leading because this
function does not actually perform a reset of the timer.
For OMAP2+ devices, HWMOD is responsible for reseting and configuring the
timer OCP_CFG register. Therefore, do not use __omap_dm_timer_reset() for
OMAP2+ devices and rely on HWMOD. Furthermore, some timer instances do not
have the fields clock-activity, wakeup-enable and auto-idle and so this
function could configure the OCP_CFG register incorrectly.
Currently HWMOD is not configuring the clock-activity field in the OCP_CFG
register for timers that have this field. Commit 0f0d080 (ARM: OMAP: DMTimer:
Use posted mode) configures the clock-activity field to keep the f-clk enabled
so that the wake-up capability is enabled. Therefore, add the appropriate flags
to the timer HWMOD structures to configure this field in the same way.
For OMAP2/3 devices all dmtimers have the clock-activity field, where as for
OMAP4 devices, only dmtimer 1, 2 and 10 have the clock-activity field.
Verified on OMAP2420 H4, OMAP3430 Beagle and OMAP4430 Panda that HWMOD is
configuring the dmtimer OCP_CFG register as expected for clock-events timer.
Signed-off-by: Jon Hunter <redacted>
---
arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c | 13 +++++++++++++
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 13 +++++++++++++
arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 4 ++++
arch/arm/mach-omap2/timer.c | 1 -
4 files changed, 30 insertions(+), 1 deletion(-)
From: Jon Hunter <hidden> Date: 2012-09-05 19:04:28
In commit e32f7ec2 (ARM: OMAP: Fix 32 kHz timer and modify GP timer to use GPT1)
a fix was added to prevent timer1 being reset in the function
omap_dm_timer_reset() because timer1 was being used as the system timer for
OMAP2 devices. Although timer1 is still used by most OMAP2+ devices as a system
timer, the function omap_dm_timer_reset() is now only being called for OMAP1
devices and OMAP1 does not use timer1 as a system timer. Therefore, remove the
check in omap_dm_timer_reset() so that timer1 is reset for OMAP1 devices.
Signed-off-by: Jon Hunter <redacted>
---
arch/arm/plat-omap/dmtimer.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
From: Jon Hunter <hidden> Date: 2012-09-05 19:04:29
Only OMAP1 devices use the omap_dm_timer_reset() and so require the
omap_dm_timer_wait_for_reset() and __omap_dm_timer_reset() functions.
Therefore combine these into a single function called omap_dm_timer_reset()
and simplify the code.
Please note that for OMAP1 devices, the TIOCP_CFG register does not have the
clock-activity field and so when we reset the timer for an OMAP1 device we
only need to configure the idle-mode field in the TIOCP_CFG register.
Signed-off-by: Jon Hunter <redacted>
---
arch/arm/plat-omap/dmtimer.c | 40 +++++++++++++++++------------
arch/arm/plat-omap/include/plat/dmtimer.h | 19 --------------
2 files changed, 24 insertions(+), 35 deletions(-)
@@ -331,25 +331,6 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)}}-/* Assumes the source clock has been set by caller */-staticinlinevoid__omap_dm_timer_reset(structomap_dm_timer*timer,-intautoidle,intwakeup)-{-u32l;--l=__raw_readl(timer->io_base+OMAP_TIMER_OCP_CFG_OFFSET);-l|=0x02<<3;/* Set to smart-idle mode */-l|=0x2<<8;/* Set clock activity to perserve f-clock on idle */--if(autoidle)-l|=0x1<<0;--if(wakeup)-l|=1<<2;--__raw_writel(l,timer->io_base+OMAP_TIMER_OCP_CFG_OFFSET);-}-staticinlinevoid__omap_dm_timer_enable_posted(structomap_dm_timer*timer){if(timer->posted)
From: Jon Hunter <hidden> Date: 2012-09-05 19:04:30
The dmtimer functions to read and write the dmtimer registers are currently
defined as follows ...
static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
int posted);
static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
u32 reg, u32 val, int posted);
The posted variable indicates if the timer is configured to use the posted mode
when performing register accesses. The posted mode configuration of the dmtimer
is stored in the omap_dm_timer structure that is also being passed to the above
functions and therefore we do not need to pass the posted variable separately.
Therefore, simplify the above functions by removing the posted variable as an
argument as this is not necessary.
Signed-off-by: Jon Hunter <redacted>
---
arch/arm/mach-omap2/timer.c | 14 +++++------
arch/arm/plat-omap/dmtimer.c | 10 ++++----
arch/arm/plat-omap/include/plat/dmtimer.h | 37 +++++++++++++----------------
3 files changed, 29 insertions(+), 32 deletions(-)
@@ -94,7 +94,7 @@ static int omap2_gp_timer_set_next_event(unsigned long cycles,structclock_event_device*evt){__omap_dm_timer_load_start(&clkev,OMAP_TIMER_CTRL_ST,-0xffffffff-cycles,1);+0xffffffff-cycles);return0;}
@@ -112,10 +112,10 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,period-=1;/* Looks like we need to first set the load value separately */__omap_dm_timer_write(&clkev,OMAP_TIMER_LOAD_REG,-0xffffffff-period,1);+0xffffffff-period);__omap_dm_timer_load_start(&clkev,OMAP_TIMER_CTRL_AR|OMAP_TIMER_CTRL_ST,-0xffffffff-period,1);+0xffffffff-period);break;caseCLOCK_EVT_MODE_ONESHOT:break;
@@ -377,7 +377,7 @@ int omap_dm_timer_stop(struct omap_dm_timer *timer)if(!(timer->capability&OMAP_TIMER_NEEDS_RESET))rate=clk_get_rate(timer->fclk);-__omap_dm_timer_stop(timer,timer->posted,rate);+__omap_dm_timer_stop(timer,rate);if(!(timer->capability&OMAP_TIMER_ALWON))timer->ctx_loss_count=
@@ -511,7 +511,7 @@ int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,}l|=OMAP_TIMER_CTRL_ST;-__omap_dm_timer_load_start(timer,l,load,timer->posted);+__omap_dm_timer_load_start(timer,l,load);/* Save the context */timer->context.tclr=l;
@@ -646,7 +646,7 @@ unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)return0;}-return__omap_dm_timer_read_counter(timer,timer->posted);+return__omap_dm_timer_read_counter(timer);}EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
@@ -387,18 +386,18 @@ static inline int __omap_dm_timer_set_source(struct clk *timer_fck,returnret;}-staticinlinevoid__omap_dm_timer_stop(structomap_dm_timer*timer,-intposted,unsignedlongrate)+staticinlinevoid+__omap_dm_timer_stop(structomap_dm_timer*timer,unsignedlongrate){u32l;-l=__omap_dm_timer_read(timer,OMAP_TIMER_CTRL_REG,posted);+l=__omap_dm_timer_read(timer,OMAP_TIMER_CTRL_REG);if(l&OMAP_TIMER_CTRL_ST){l&=~0x1;-__omap_dm_timer_write(timer,OMAP_TIMER_CTRL_REG,l,posted);+__omap_dm_timer_write(timer,OMAP_TIMER_CTRL_REG,l);#ifdef CONFIG_ARCH_OMAP2PLUS/* Readback to make sure write has completed */-__omap_dm_timer_read(timer,OMAP_TIMER_CTRL_REG,posted);+__omap_dm_timer_read(timer,OMAP_TIMER_CTRL_REG);/**Waitforfunctionalclockperiodx3.5tomakesurethat*timerisstopped
From: Jon Hunter <hidden> Date: 2012-09-05 19:04:31
The OMAP dmtimer driver does not currently have a function to disable the
timer interrupts. For some timer instances the timer interrupt enable
function can be used to disable the interrupts because the same interrupt
enable register is used to disable interrupts. However, some timer instances
have separate interrupt enable/disable registers and so this will not work.
Therefore, add a dedicated function to disable interrupts.
Signed-off-by: Jon Hunter <redacted>
---
arch/arm/plat-omap/dmtimer.c | 31 +++++++++++++++++++++++++++++
arch/arm/plat-omap/include/plat/dmtimer.h | 3 ++-
2 files changed, 33 insertions(+), 1 deletion(-)
@@ -612,6 +612,37 @@ int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,}EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);+/**+*omap_dm_timer_set_int_disable-disabletimerinterrupts+*@timer:pointertotimerhandle+*@mask:bitmaskofinterruptstobedisabled+*+*Disablesthespecifiedtimerinterruptsforatimer.+*/+intomap_dm_timer_set_int_disable(structomap_dm_timer*timer,u32mask)+{+u32l=mask;++if(unlikely(!timer))+return-EINVAL;++omap_dm_timer_enable(timer);++if(timer->revision==1)+l=__raw_readl(timer->irq_ena)&~mask;++__raw_writel(l,timer->irq_dis);+l=__omap_dm_timer_read(timer,OMAP_TIMER_WAKEUP_EN_REG)&~mask;+__omap_dm_timer_write(timer,OMAP_TIMER_WAKEUP_EN_REG,l);++/* Save the context */+timer->context.tier&=~mask;+timer->context.twer&=~mask;+omap_dm_timer_disable(timer);+return0;+}+EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_disable);+unsignedintomap_dm_timer_read_status(structomap_dm_timer*timer){unsignedintl;
@@ -130,6 +130,7 @@ int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, iintomap_dm_timer_set_prescaler(structomap_dm_timer*timer,intprescaler);intomap_dm_timer_set_int_enable(structomap_dm_timer*timer,unsignedintvalue);+intomap_dm_timer_set_int_disable(structomap_dm_timer*timer,u32mask);unsignedintomap_dm_timer_read_status(structomap_dm_timer*timer);intomap_dm_timer_write_status(structomap_dm_timer*timer,unsignedintvalue);
From: Jon Hunter <hidden> Date: 2012-09-05 19:04:32
Whenever we call the function omap_dm_timer_set_source() to set the clock
source of a dmtimer we look-up the dmtimer functional clock source by
calling clk_get(). This is not necessary because on requesting a dmtimer
we look-up the functional clock source and store it in the omap_dm_timer
structure. So instead of looking up the clock again used the clock handle
that stored in the omap_dm_timer structure.
Signed-off-by: Jon Hunter <redacted>
---
arch/arm/plat-omap/dmtimer.c | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
@@ -400,7 +400,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source){intret;char*parent_name=NULL;-structclk*fclk,*parent;+structclk*parent;structdmtimer_platform_data*pdata;if(unlikely(!timer))
@@ -419,11 +419,8 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)if(pdata->set_timer_src)returnpdata->set_timer_src(timer->pdev,source);-fclk=clk_get(&timer->pdev->dev,"fck");-if(IS_ERR_OR_NULL(fclk)){-pr_err("%s: fck not found\n",__func__);+if(!timer->fclk)return-EINVAL;-}switch(source){caseOMAP_TIMER_SRC_SYS_CLK:
@@ -442,18 +439,15 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)parent=clk_get(&timer->pdev->dev,parent_name);if(IS_ERR_OR_NULL(parent)){pr_err("%s: %s not found\n",__func__,parent_name);-ret=-EINVAL;-gotoout;+return-EINVAL;}-ret=clk_set_parent(fclk,parent);+ret=clk_set_parent(timer->fclk,parent);if(IS_ERR_VALUE(ret))pr_err("%s: failed to set %s as parent\n",__func__,parent_name);clk_put(parent);-out:-clk_put(fclk);returnret;}
Errata Titles:
i103: Delay needed to read some GP timer, WD timer and sync timer registers
after wakeup (OMAP3/4)
i767: Delay needed to read some GP timer registers after wakeup (OMAP5)
Description (i103/i767):
If a General Purpose Timer (GPTimer) is in posted mode (TSICR [2].POSTED=1),
due to internal resynchronizations, values read in TCRR, TCAR1 and TCAR2
registers right after the timer interface clock (L4) goes from stopped to
active may not return the expected values. The most common event leading to
this situation occurs upon wake up from idle.
GPTimer non-posted synchronization mode is not impacted by this limitation.
Workarounds:
1). Disable posted mode
2). Use static dependency between timer clock domain and MPUSS clock domain
3). Use no-idle mode when the timer is active
Workarounds #2 and #3 are not pratical from a power standpoint and so
workaround #1 has been implemented. Disabling posted mode adds some CPU overhead
for configuring the timers as the CPU has to wait for the write to complete.
However, disabling posted mode guarantees correct operation.
Please note that it is safe to use posted mode for timers if the counter (TCRR)
and capture (TCARx) registers will never be read. An example of this is the
clock-event system timer. This is used by the kernel to schedule events however,
the timers counter is never read and capture registers are not used. Given that
the kernel configures this timer often yet never reads the counter register it
is safe to enable posted mode in this case. Hence, for the timer used for kernel
clock-events, posted mode is enabled by overriding the errata for devices that
are impacted by this defect.
Although both dmtimers and watchdogs are impacted by this defect this patch only
implements the workaround for the dmtimer. Currently the watchdog driver does
not read the counter register and so no workaround is necessary.
Confirmed with Vaibhav Hiremath that this bug also impacts AM33xx devices.
Thanks for pinging me on this and getting it confirmed.
Couple of points,
1. It is confusing to me, as you are passing the errata flag so i expect
api should set it. Why can't we do reverse way, you pass 0 here, since
you don't want to set and pass this flag every other places where you
want to enable this errata.
2. Why can't we enable for all timers? Even though clock-event is anyway
not reading it, but still is is applicable to it, right?
3. Why can't we just simply Add this flag to hwmod_data file and read it
back in omap_timer_init() and omap_dm_timer_init_one(). Wouldn't that be
a good approach to handle it?
Thanks,
Vaibhav
quoted hunk
res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source);
BUG_ON(res);
@@ -305,6 +312,8 @@ static void __init omap2_gptimer_clocksource_init(int gptimer_id, { int res;+ __omap_dm_timer_populate_errata(&clksrc, 0);+ res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source); BUG_ON(res);
Currently the dmtimer posted mode is being enabled when the function
__omap_dm_timer_reset() is called. This function is only being called for
OMAP1 timers and OMAP2+ timers that are being used as system timers. Hence,
for OMAP2+ timers that are NOT being used as a system timer, posted mode is
not enabled but the "timer->posted" variable is still set (incorrectly) in
the omap_dm_timer_prepare() function.
This is a regression introduced by commit 3392cdd3 (ARM: OMAP: dmtimer:
switch-over to platform device driver) which changed the code to only call
omap_dm_timer_reset() for OMAP1 devices. Although this is a regression from
the original code it only impacts performance and so is not needed for stable.
Signed-off-by: Jon Hunter <redacted>
---
arch/arm/mach-omap2/timer.c | 3 +--
arch/arm/plat-omap/dmtimer.c | 14 +++++---------
arch/arm/plat-omap/include/plat/dmtimer.h | 9 ++++++++-
3 files changed, 14 insertions(+), 12 deletions(-)
@@ -150,13 +144,15 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer)}}+omap_dm_timer_enable(timer);+if(timer->capability&OMAP_TIMER_NEEDS_RESET)omap_dm_timer_reset(timer);-ret=omap_dm_timer_set_source(timer,OMAP_TIMER_SRC_32_KHZ);+__omap_dm_timer_enable_posted(timer);+omap_dm_timer_disable(timer);-timer->posted=1;-returnret;+returnomap_dm_timer_set_source(timer,OMAP_TIMER_SRC_32_KHZ);
May be I am speculating here and I know this is tested and supposed to
work, but Isn't it safe to set parent keeping module enables.
I would still recommend you to move is before omap_dm_timer_disable().
There could be devices or hw bugs/issues, may be related to standby/idle
protocol happening underneath module enable/disable.
Thanks,
Vaibhav
The OMAP dmtimer driver does not currently have a function to disable the
timer interrupts. For some timer instances the timer interrupt enable
function can be used to disable the interrupts because the same interrupt
enable register is used to disable interrupts. However, some timer instances
have separate interrupt enable/disable registers and so this will not work.
Therefore, add a dedicated function to disable interrupts.
I think you should clearly specify which timer and which device you are
referring to.
Thanks,
Vaibhav
@@ -612,6 +612,37 @@ int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,}EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);+/**+*omap_dm_timer_set_int_disable-disabletimerinterrupts+*@timer:pointertotimerhandle+*@mask:bitmaskofinterruptstobedisabled+*+*Disablesthespecifiedtimerinterruptsforatimer.+*/+intomap_dm_timer_set_int_disable(structomap_dm_timer*timer,u32mask)+{+u32l=mask;++if(unlikely(!timer))+return-EINVAL;++omap_dm_timer_enable(timer);++if(timer->revision==1)+l=__raw_readl(timer->irq_ena)&~mask;++__raw_writel(l,timer->irq_dis);+l=__omap_dm_timer_read(timer,OMAP_TIMER_WAKEUP_EN_REG)&~mask;+__omap_dm_timer_write(timer,OMAP_TIMER_WAKEUP_EN_REG,l);++/* Save the context */+timer->context.tier&=~mask;+timer->context.twer&=~mask;+omap_dm_timer_disable(timer);+return0;+}+EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_disable);+unsignedintomap_dm_timer_read_status(structomap_dm_timer*timer){unsignedintl;
@@ -130,6 +130,7 @@ int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, iintomap_dm_timer_set_prescaler(structomap_dm_timer*timer,intprescaler);intomap_dm_timer_set_int_enable(structomap_dm_timer*timer,unsignedintvalue);+intomap_dm_timer_set_int_disable(structomap_dm_timer*timer,u32mask);unsignedintomap_dm_timer_read_status(structomap_dm_timer*timer);intomap_dm_timer_write_status(structomap_dm_timer*timer,unsignedintvalue);
This series includes several fixes for the OMAP DMTIMER driver and a few
clean-ups to simplify some of the code. This series is based upon 3.6-rc4.
Tested on OMAP5912 OSK, OMAP2420 H4, OMAP3430 Beagle and OMAP4430 Panda.
Testing includes ...
1. Booting kernel on above boards
2. Set date and ensuring time of day is correct after 24 hours
3. Checking the timer counter is incrementing when configuring and starting
a timer
4. Checking the timer overflow interrupt when timer expires.
5. Using different clock sources to operate the timer with.
6. Running a loop test overnight that continually runs test #3 and #4 for
each available timer
On the other hand I have validated this patch-series on both AM37xEVM
and BeagleBone platform. I used the test code which you shared with me
to validate it.
AM33XX Clock tree needs minor change here,
diff --git a/arch/arm/mach-omap2/clock33xx_data.c
b/arch/arm/mach-omap2/clock33xx_data.c
index a4006b2..daa36a5 100644
From: Jon Hunter <hidden> Date: 2012-09-06 14:06:08
On 09/06/2012 12:07 AM, Vaibhav Hiremath wrote:
On 9/6/2012 12:34 AM, Jon Hunter wrote:
quoted
Errata Titles:
i103: Delay needed to read some GP timer, WD timer and sync timer registers
after wakeup (OMAP3/4)
i767: Delay needed to read some GP timer registers after wakeup (OMAP5)
Description (i103/i767):
If a General Purpose Timer (GPTimer) is in posted mode (TSICR [2].POSTED=1),
due to internal resynchronizations, values read in TCRR, TCAR1 and TCAR2
registers right after the timer interface clock (L4) goes from stopped to
active may not return the expected values. The most common event leading to
this situation occurs upon wake up from idle.
GPTimer non-posted synchronization mode is not impacted by this limitation.
Workarounds:
1). Disable posted mode
2). Use static dependency between timer clock domain and MPUSS clock domain
3). Use no-idle mode when the timer is active
Workarounds #2 and #3 are not pratical from a power standpoint and so
workaround #1 has been implemented. Disabling posted mode adds some CPU overhead
for configuring the timers as the CPU has to wait for the write to complete.
However, disabling posted mode guarantees correct operation.
Please note that it is safe to use posted mode for timers if the counter (TCRR)
and capture (TCARx) registers will never be read. An example of this is the
clock-event system timer. This is used by the kernel to schedule events however,
the timers counter is never read and capture registers are not used. Given that
the kernel configures this timer often yet never reads the counter register it
is safe to enable posted mode in this case. Hence, for the timer used for kernel
clock-events, posted mode is enabled by overriding the errata for devices that
are impacted by this defect.
Although both dmtimers and watchdogs are impacted by this defect this patch only
implements the workaround for the dmtimer. Currently the watchdog driver does
not read the counter register and so no workaround is necessary.
Confirmed with Vaibhav Hiremath that this bug also impacts AM33xx devices.
Thanks for pinging me on this and getting it confirmed.
Couple of points,
1. It is confusing to me, as you are passing the errata flag so i expect
api should set it. Why can't we do reverse way, you pass 0 here, since
you don't want to set and pass this flag every other places where you
want to enable this errata.
Per the design of the __omap_dm_timer_populate_errata function, the 2nd
argument is called override to allow us to override an errata. I am not
a huge fan of this, but I wanted to be explicit in the code that we are
intentionally allowing posted mode for the clock-events timer.
I did not wish to pass the flags we want to set because if there more
flags added in the future then we will have to keep changing the calls
to the populate_errata function to add these.
2. Why can't we enable for all timers? Even though clock-event is anyway
not reading it, but still is is applicable to it, right?
Yes it is still applicable but we never read it so it is ok to override.
If you see Richard W's original patch for enabling posted mode it is to
reduce overhead of programming timers, specifically the clock-events
timer which is program very often.
For other timers, we do not know how they will be used and so by default
we disable posted mode as this is safe.
3. Why can't we just simply Add this flag to hwmod_data file and read it
back in omap_timer_init() and omap_dm_timer_init_one(). Wouldn't that be
a good approach to handle it?
It could be done in this case, but typically I have not seen errata
flags added to HWMOD. One limitation you would have with HWMOD is if an
erratum is only specific to a certain revision of the device. In this
case it is not and so it could work.
In general I think that having errata described by HWMOD would be a good
thing, but if think that should be a longer term goal with agreement
from Benoit and add some general errata helpers to HWMOD.
Cheers
Jon
From: Jon Hunter <hidden> Date: 2012-09-06 14:20:07
On 09/06/2012 07:57 AM, Vaibhav Hiremath wrote:
On 9/6/2012 12:34 AM, Jon Hunter wrote:
quoted
Currently the dmtimer posted mode is being enabled when the function
__omap_dm_timer_reset() is called. This function is only being called for
OMAP1 timers and OMAP2+ timers that are being used as system timers. Hence,
for OMAP2+ timers that are NOT being used as a system timer, posted mode is
not enabled but the "timer->posted" variable is still set (incorrectly) in
the omap_dm_timer_prepare() function.
This is a regression introduced by commit 3392cdd3 (ARM: OMAP: dmtimer:
switch-over to platform device driver) which changed the code to only call
omap_dm_timer_reset() for OMAP1 devices. Although this is a regression from
the original code it only impacts performance and so is not needed for stable.
Signed-off-by: Jon Hunter <redacted>
---
arch/arm/mach-omap2/timer.c | 3 +--
arch/arm/plat-omap/dmtimer.c | 14 +++++---------
arch/arm/plat-omap/include/plat/dmtimer.h | 9 ++++++++-
3 files changed, 14 insertions(+), 12 deletions(-)
@@ -150,13 +144,15 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer)}}+omap_dm_timer_enable(timer);+if(timer->capability&OMAP_TIMER_NEEDS_RESET)omap_dm_timer_reset(timer);-ret=omap_dm_timer_set_source(timer,OMAP_TIMER_SRC_32_KHZ);+__omap_dm_timer_enable_posted(timer);+omap_dm_timer_disable(timer);-timer->posted=1;-returnret;+returnomap_dm_timer_set_source(timer,OMAP_TIMER_SRC_32_KHZ);
May be I am speculating here and I know this is tested and supposed to
work, but Isn't it safe to set parent keeping module enables.
So you would rather change the functional clock while the timer is
enabled/active? So although that we are doing this today, that does not
sound like a good idea to me :-)
I would still recommend you to move is before omap_dm_timer_disable().
There could be devices or hw bugs/issues, may be related to standby/idle
protocol happening underneath module enable/disable.
The register for setting the timer parent clock is located in the
Configuration Module (OMAP1) and PRCM (OMAP2+) and so there is no
requirement to keep the timer active while doing this.
Furthermore, if you look at the omap_dm_timer_set_source() function that
can be called from any driver using the timer, we never enable the timer
when setting the timer clock source. So this way is more consistent with
how the set_source function is implemented.
Cheers
Jon
From: Jon Hunter <hidden> Date: 2012-09-06 14:26:58
On 09/06/2012 07:58 AM, Vaibhav Hiremath wrote:
On 9/6/2012 12:34 AM, Jon Hunter wrote:
quoted
The OMAP dmtimer driver does not currently have a function to disable the
timer interrupts. For some timer instances the timer interrupt enable
function can be used to disable the interrupts because the same interrupt
enable register is used to disable interrupts. However, some timer instances
have separate interrupt enable/disable registers and so this will not work.
Therefore, add a dedicated function to disable interrupts.
I think you should clearly specify which timer and which device you are
referring to.
OMAP4+ devices. For OMAP4 all timers apart from 1, 2 and 10. For OMAP5
all timers.
Jon
From: Jon Hunter <hidden> Date: 2012-09-06 14:30:56
On 09/06/2012 07:58 AM, Vaibhav Hiremath wrote:
On 9/6/2012 12:34 AM, Jon Hunter wrote:
quoted
This series includes several fixes for the OMAP DMTIMER driver and a few
clean-ups to simplify some of the code. This series is based upon 3.6-rc4.
Tested on OMAP5912 OSK, OMAP2420 H4, OMAP3430 Beagle and OMAP4430 Panda.
Testing includes ...
1. Booting kernel on above boards
2. Set date and ensuring time of day is correct after 24 hours
3. Checking the timer counter is incrementing when configuring and starting
a timer
4. Checking the timer overflow interrupt when timer expires.
5. Using different clock sources to operate the timer with.
6. Running a loop test overnight that continually runs test #3 and #4 for
each available timer
On the other hand I have validated this patch-series on both AM37xEVM
and BeagleBone platform. I used the test code which you shared with me
to validate it.
Thanks!
quoted hunk
AM33XX Clock tree needs minor change here,
diff --git a/arch/arm/mach-omap2/clock33xx_data.c
b/arch/arm/mach-omap2/clock33xx_data.c
index a4006b2..daa36a5 100644
From: Jon Hunter <hidden> Date: 2012-09-06 14:42:10
On 09/06/2012 09:06 AM, Jon Hunter wrote:
On 09/06/2012 12:07 AM, Vaibhav Hiremath wrote:
quoted
On 9/6/2012 12:34 AM, Jon Hunter wrote:
quoted
Errata Titles:
i103: Delay needed to read some GP timer, WD timer and sync timer registers
after wakeup (OMAP3/4)
i767: Delay needed to read some GP timer registers after wakeup (OMAP5)
Description (i103/i767):
If a General Purpose Timer (GPTimer) is in posted mode (TSICR [2].POSTED=1),
due to internal resynchronizations, values read in TCRR, TCAR1 and TCAR2
registers right after the timer interface clock (L4) goes from stopped to
active may not return the expected values. The most common event leading to
this situation occurs upon wake up from idle.
GPTimer non-posted synchronization mode is not impacted by this limitation.
Workarounds:
1). Disable posted mode
2). Use static dependency between timer clock domain and MPUSS clock domain
3). Use no-idle mode when the timer is active
Workarounds #2 and #3 are not pratical from a power standpoint and so
workaround #1 has been implemented. Disabling posted mode adds some CPU overhead
for configuring the timers as the CPU has to wait for the write to complete.
However, disabling posted mode guarantees correct operation.
Please note that it is safe to use posted mode for timers if the counter (TCRR)
and capture (TCARx) registers will never be read. An example of this is the
clock-event system timer. This is used by the kernel to schedule events however,
the timers counter is never read and capture registers are not used. Given that
the kernel configures this timer often yet never reads the counter register it
is safe to enable posted mode in this case. Hence, for the timer used for kernel
clock-events, posted mode is enabled by overriding the errata for devices that
are impacted by this defect.
Although both dmtimers and watchdogs are impacted by this defect this patch only
implements the workaround for the dmtimer. Currently the watchdog driver does
not read the counter register and so no workaround is necessary.
Confirmed with Vaibhav Hiremath that this bug also impacts AM33xx devices.
Thanks for pinging me on this and getting it confirmed.
Couple of points,
1. It is confusing to me, as you are passing the errata flag so i expect
api should set it. Why can't we do reverse way, you pass 0 here, since
you don't want to set and pass this flag every other places where you
want to enable this errata.
Per the design of the __omap_dm_timer_populate_errata function, the 2nd
argument is called override to allow us to override an errata. I am not
a huge fan of this, but I wanted to be explicit in the code that we are
intentionally allowing posted mode for the clock-events timer.
I did not wish to pass the flags we want to set because if there more
flags added in the future then we will have to keep changing the calls
to the populate_errata function to add these.
By the way, your proposal could work nicely if we could pass errata
flags from HWMOD. However, I am not sure if Paul or Benoit would go for
this as they want HWMOD data to be auto-generated as much as possible
and so I am not sure how that would work for errata which are not
expected by design ;-)
Cheers
Jon
From: Jon Hunter <hidden> Date: 2012-09-06 15:20:27
On 09/06/2012 09:42 AM, Jon Hunter wrote:
On 09/06/2012 09:06 AM, Jon Hunter wrote:
quoted
On 09/06/2012 12:07 AM, Vaibhav Hiremath wrote:
quoted
On 9/6/2012 12:34 AM, Jon Hunter wrote:
quoted
Errata Titles:
i103: Delay needed to read some GP timer, WD timer and sync timer registers
after wakeup (OMAP3/4)
i767: Delay needed to read some GP timer registers after wakeup (OMAP5)
Description (i103/i767):
If a General Purpose Timer (GPTimer) is in posted mode (TSICR [2].POSTED=1),
due to internal resynchronizations, values read in TCRR, TCAR1 and TCAR2
registers right after the timer interface clock (L4) goes from stopped to
active may not return the expected values. The most common event leading to
this situation occurs upon wake up from idle.
GPTimer non-posted synchronization mode is not impacted by this limitation.
Workarounds:
1). Disable posted mode
2). Use static dependency between timer clock domain and MPUSS clock domain
3). Use no-idle mode when the timer is active
Workarounds #2 and #3 are not pratical from a power standpoint and so
workaround #1 has been implemented. Disabling posted mode adds some CPU overhead
for configuring the timers as the CPU has to wait for the write to complete.
However, disabling posted mode guarantees correct operation.
Please note that it is safe to use posted mode for timers if the counter (TCRR)
and capture (TCARx) registers will never be read. An example of this is the
clock-event system timer. This is used by the kernel to schedule events however,
the timers counter is never read and capture registers are not used. Given that
the kernel configures this timer often yet never reads the counter register it
is safe to enable posted mode in this case. Hence, for the timer used for kernel
clock-events, posted mode is enabled by overriding the errata for devices that
are impacted by this defect.
Although both dmtimers and watchdogs are impacted by this defect this patch only
implements the workaround for the dmtimer. Currently the watchdog driver does
not read the counter register and so no workaround is necessary.
Confirmed with Vaibhav Hiremath that this bug also impacts AM33xx devices.
Thanks for pinging me on this and getting it confirmed.
Couple of points,
1. It is confusing to me, as you are passing the errata flag so i expect
api should set it. Why can't we do reverse way, you pass 0 here, since
you don't want to set and pass this flag every other places where you
want to enable this errata.
Per the design of the __omap_dm_timer_populate_errata function, the 2nd
argument is called override to allow us to override an errata. I am not
a huge fan of this, but I wanted to be explicit in the code that we are
intentionally allowing posted mode for the clock-events timer.
I did not wish to pass the flags we want to set because if there more
flags added in the future then we will have to keep changing the calls
to the populate_errata function to add these.
By the way, your proposal could work nicely if we could pass errata
flags from HWMOD. However, I am not sure if Paul or Benoit would go for
this as they want HWMOD data to be auto-generated as much as possible
and so I am not sure how that would work for errata which are not
expected by design ;-)
Another alternative would be to drop the override argument altogether
and just do something like the following for the clock-events timer ...
From: Jon Hunter <hidden> Date: 2012-09-06 16:01:21
On 09/06/2012 09:20 AM, Jon Hunter wrote:
On 09/06/2012 07:57 AM, Vaibhav Hiremath wrote:
quoted
On 9/6/2012 12:34 AM, Jon Hunter wrote:
quoted
Currently the dmtimer posted mode is being enabled when the function
__omap_dm_timer_reset() is called. This function is only being called for
OMAP1 timers and OMAP2+ timers that are being used as system timers. Hence,
for OMAP2+ timers that are NOT being used as a system timer, posted mode is
not enabled but the "timer->posted" variable is still set (incorrectly) in
the omap_dm_timer_prepare() function.
This is a regression introduced by commit 3392cdd3 (ARM: OMAP: dmtimer:
switch-over to platform device driver) which changed the code to only call
omap_dm_timer_reset() for OMAP1 devices. Although this is a regression from
the original code it only impacts performance and so is not needed for stable.
Signed-off-by: Jon Hunter <redacted>
---
arch/arm/mach-omap2/timer.c | 3 +--
arch/arm/plat-omap/dmtimer.c | 14 +++++---------
arch/arm/plat-omap/include/plat/dmtimer.h | 9 ++++++++-
3 files changed, 14 insertions(+), 12 deletions(-)
@@ -150,13 +144,15 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer)}}+omap_dm_timer_enable(timer);+if(timer->capability&OMAP_TIMER_NEEDS_RESET)omap_dm_timer_reset(timer);-ret=omap_dm_timer_set_source(timer,OMAP_TIMER_SRC_32_KHZ);+__omap_dm_timer_enable_posted(timer);+omap_dm_timer_disable(timer);-timer->posted=1;-returnret;+returnomap_dm_timer_set_source(timer,OMAP_TIMER_SRC_32_KHZ);
May be I am speculating here and I know this is tested and supposed to
work, but Isn't it safe to set parent keeping module enables.
So you would rather change the functional clock while the timer is
enabled/active? So although that we are doing this today, that does not
sound like a good idea to me :-)
Actually, we are not doing this today. If you look at the current code
we are only enabling the timer while doing the soft-reset for omap1
devices. Hence, even in the current code we set the parent while the
timer is not enabled. So there is no actual change here in the sequence.
Cheers
Jon
The dmtimer functions to read and write the dmtimer registers are currently
defined as follows ...
static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
int posted);
static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
u32 reg, u32 val, int posted);
The posted variable indicates if the timer is configured to use the posted mode
when performing register accesses. The posted mode configuration of the dmtimer
is stored in the omap_dm_timer structure that is also being passed to the above
functions and therefore we do not need to pass the posted variable separately.
Therefore, simplify the above functions by removing the posted variable as an
argument as this is not necessary.
I believe the reason for passing the posted flag was to optimize out some
functions from the timer code as that's being run all the time.
Care to check the assembly before and after this patch for the timer
functions with objdump -d to make sure it does not add tons of bloat
there?
Thanks,
Tony
From: Jon Hunter <hidden> Date: 2012-09-10 21:59:36
On 09/07/2012 05:22 PM, Tony Lindgren wrote:
* Jon Hunter [off-list ref] [120905 12:05]:
quoted
The dmtimer functions to read and write the dmtimer registers are currently
defined as follows ...
static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
int posted);
static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
u32 reg, u32 val, int posted);
The posted variable indicates if the timer is configured to use the posted mode
when performing register accesses. The posted mode configuration of the dmtimer
is stored in the omap_dm_timer structure that is also being passed to the above
functions and therefore we do not need to pass the posted variable separately.
Therefore, simplify the above functions by removing the posted variable as an
argument as this is not necessary.
I believe the reason for passing the posted flag was to optimize out some
functions from the timer code as that's being run all the time.
Care to check the assembly before and after this patch for the timer
functions with objdump -d to make sure it does not add tons of bloat
there?
Hi Tony,
Thanks for the details here. I see that makes sense and that the
compiler could take advantage of this as the functions are inlined.
I have taken a look at the disassembled output using objdump as you
mentioned. What I see is ...
1. For dmtimer.c the impact appears negligible, the total number of
lines outputted by objdump only changed by 8 with (1215 lines) and
without (1207 lines) the patch applied.
2. For timer.c the impact is greater. I see that
omap2_gp_timer_set_next_event() increased by 6 instructions from 29
to 35. clocksource_read_cycles() increased by 2 instructions 15 to
17 instructions. dmtimer_read_sched_clock() increased by 2
instructions from 17 to 19. omap2_gp_timer_set_mode() increased by
21 instructions from 102 to 123.
I imagine that we are mainly concerned about
omap2_gp_timer_set_next_event(), clocksource_read_cycles() and
dmtimer_read_sched_clock() as these will be called often. Therefore, I
am not sure if you wish to drop this patch.
By the way, if we do drop this patch, I would then need to fix the
setting of the posted variable in mach-omap2/timer.c for clock-source in
the case where a dmtimer is used. Today the code assumes that for
clock-source and clock-events posted mode is always used. However, with
the errata i103/i767 we will disable posted mode for clock-source on
omap2/3/4/5/am33xx devices.
Cheers
Jon
The dmtimer functions to read and write the dmtimer registers are currently
defined as follows ...
static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
int posted);
static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
u32 reg, u32 val, int posted);
The posted variable indicates if the timer is configured to use the posted mode
when performing register accesses. The posted mode configuration of the dmtimer
is stored in the omap_dm_timer structure that is also being passed to the above
functions and therefore we do not need to pass the posted variable separately.
Therefore, simplify the above functions by removing the posted variable as an
argument as this is not necessary.
I believe the reason for passing the posted flag was to optimize out some
functions from the timer code as that's being run all the time.
Care to check the assembly before and after this patch for the timer
functions with objdump -d to make sure it does not add tons of bloat
there?
Hi Tony,
Thanks for the details here. I see that makes sense and that the
compiler could take advantage of this as the functions are inlined.
I have taken a look at the disassembled output using objdump as you
mentioned. What I see is ...
1. For dmtimer.c the impact appears negligible, the total number of
lines outputted by objdump only changed by 8 with (1215 lines) and
without (1207 lines) the patch applied.
2. For timer.c the impact is greater. I see that
omap2_gp_timer_set_next_event() increased by 6 instructions from 29
to 35. clocksource_read_cycles() increased by 2 instructions 15 to
17 instructions. dmtimer_read_sched_clock() increased by 2
instructions from 17 to 19. omap2_gp_timer_set_mode() increased by
21 instructions from 102 to 123.
I imagine that we are mainly concerned about
omap2_gp_timer_set_next_event(), clocksource_read_cycles() and
dmtimer_read_sched_clock() as these will be called often. Therefore, I
am not sure if you wish to drop this patch.
Well does it at lots of new ldr to the critical code?
By the way, if we do drop this patch, I would then need to fix the
setting of the posted variable in mach-omap2/timer.c for clock-source in
the case where a dmtimer is used. Today the code assumes that for
clock-source and clock-events posted mode is always used. However, with
the errata i103/i767 we will disable posted mode for clock-source on
omap2/3/4/5/am33xx devices.
Yes I see, I guess that means just adding a new systimer entry?
Regards,
Tony
From: Jon Hunter <hidden> Date: 2012-09-11 16:26:07
On 09/10/2012 07:58 PM, Tony Lindgren wrote:
* Jon Hunter [off-list ref] [120910 15:00]:
quoted
On 09/07/2012 05:22 PM, Tony Lindgren wrote:
quoted
* Jon Hunter [off-list ref] [120905 12:05]:
quoted
The dmtimer functions to read and write the dmtimer registers are currently
defined as follows ...
static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
int posted);
static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
u32 reg, u32 val, int posted);
The posted variable indicates if the timer is configured to use the posted mode
when performing register accesses. The posted mode configuration of the dmtimer
is stored in the omap_dm_timer structure that is also being passed to the above
functions and therefore we do not need to pass the posted variable separately.
Therefore, simplify the above functions by removing the posted variable as an
argument as this is not necessary.
I believe the reason for passing the posted flag was to optimize out some
functions from the timer code as that's being run all the time.
Care to check the assembly before and after this patch for the timer
functions with objdump -d to make sure it does not add tons of bloat
there?
Hi Tony,
Thanks for the details here. I see that makes sense and that the
compiler could take advantage of this as the functions are inlined.
I have taken a look at the disassembled output using objdump as you
mentioned. What I see is ...
1. For dmtimer.c the impact appears negligible, the total number of
lines outputted by objdump only changed by 8 with (1215 lines) and
without (1207 lines) the patch applied.
2. For timer.c the impact is greater. I see that
omap2_gp_timer_set_next_event() increased by 6 instructions from 29
to 35. clocksource_read_cycles() increased by 2 instructions 15 to
17 instructions. dmtimer_read_sched_clock() increased by 2
instructions from 17 to 19. omap2_gp_timer_set_mode() increased by
21 instructions from 102 to 123.
I imagine that we are mainly concerned about
omap2_gp_timer_set_next_event(), clocksource_read_cycles() and
dmtimer_read_sched_clock() as these will be called often. Therefore, I
am not sure if you wish to drop this patch.
Well does it at lots of new ldr to the critical code?
For the omap2_gp_timer_set_next_event() function it adds 3 load
instructions, increasing the number of possible loads from 11 to 14.
For the clocksource_read_cycles() function it adds 1 load instruction,
increasing the number of possible loads from 7 to 8.
For the dmtimer_read_sched_clock() function, I don't see any additional
loads, but instructions added are a tst and beq instruction.
quoted
By the way, if we do drop this patch, I would then need to fix the
setting of the posted variable in mach-omap2/timer.c for clock-source in
the case where a dmtimer is used. Today the code assumes that for
clock-source and clock-events posted mode is always used. However, with
the errata i103/i767 we will disable posted mode for clock-source on
omap2/3/4/5/am33xx devices.
Yes I see, I guess that means just adding a new systimer entry?
Actually, I think we can avoid that by not using posted mode for
clock-source timers at all. Posted mode only benefits the clock-events
timers that are configured often.
The benefit of not using posted mode for clock-source timers and setting
the "posted" parameter to 0, will really allow the compiler to optimise
the clocksource_read_cycles() and dmtimer_read_sched_clock() quite a
bit. So this could be a nice optimisation.
Cheers
Jon
The dmtimer functions to read and write the dmtimer registers are currently
defined as follows ...
static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
int posted);
static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
u32 reg, u32 val, int posted);
The posted variable indicates if the timer is configured to use the posted mode
when performing register accesses. The posted mode configuration of the dmtimer
is stored in the omap_dm_timer structure that is also being passed to the above
functions and therefore we do not need to pass the posted variable separately.
Therefore, simplify the above functions by removing the posted variable as an
argument as this is not necessary.
I believe the reason for passing the posted flag was to optimize out some
functions from the timer code as that's being run all the time.
Care to check the assembly before and after this patch for the timer
functions with objdump -d to make sure it does not add tons of bloat
there?
Hi Tony,
Thanks for the details here. I see that makes sense and that the
compiler could take advantage of this as the functions are inlined.
I have taken a look at the disassembled output using objdump as you
mentioned. What I see is ...
1. For dmtimer.c the impact appears negligible, the total number of
lines outputted by objdump only changed by 8 with (1215 lines) and
without (1207 lines) the patch applied.
2. For timer.c the impact is greater. I see that
omap2_gp_timer_set_next_event() increased by 6 instructions from 29
to 35. clocksource_read_cycles() increased by 2 instructions 15 to
17 instructions. dmtimer_read_sched_clock() increased by 2
instructions from 17 to 19. omap2_gp_timer_set_mode() increased by
21 instructions from 102 to 123.
I imagine that we are mainly concerned about
omap2_gp_timer_set_next_event(), clocksource_read_cycles() and
dmtimer_read_sched_clock() as these will be called often. Therefore, I
am not sure if you wish to drop this patch.
Well does it at lots of new ldr to the critical code?
For the omap2_gp_timer_set_next_event() function it adds 3 load
instructions, increasing the number of possible loads from 11 to 14.
For the clocksource_read_cycles() function it adds 1 load instruction,
increasing the number of possible loads from 7 to 8.
For the dmtimer_read_sched_clock() function, I don't see any additional
loads, but instructions added are a tst and beq instruction.
quoted
quoted
By the way, if we do drop this patch, I would then need to fix the
setting of the posted variable in mach-omap2/timer.c for clock-source in
the case where a dmtimer is used. Today the code assumes that for
clock-source and clock-events posted mode is always used. However, with
the errata i103/i767 we will disable posted mode for clock-source on
omap2/3/4/5/am33xx devices.
Yes I see, I guess that means just adding a new systimer entry?
Actually, I think we can avoid that by not using posted mode for
clock-source timers at all. Posted mode only benefits the clock-events
timers that are configured often.
The benefit of not using posted mode for clock-source timers and setting
the "posted" parameter to 0, will really allow the compiler to optimise
the clocksource_read_cycles() and dmtimer_read_sched_clock() quite a
bit. So this could be a nice optimisation.
OK up to you, but maybe run some benchmarks first to figure out what
makes most sense? Updating the timer used to be a bottleneck earlier.
Regards,
Tony
From: Jon Hunter <hidden> Date: 2012-09-13 03:26:47
On 09/11/2012 11:34 AM, Tony Lindgren wrote:
* Jon Hunter [off-list ref] [120911 09:26]:
quoted
On 09/10/2012 07:58 PM, Tony Lindgren wrote:
quoted
* Jon Hunter [off-list ref] [120910 15:00]:
quoted
On 09/07/2012 05:22 PM, Tony Lindgren wrote:
quoted
* Jon Hunter [off-list ref] [120905 12:05]:
quoted
The dmtimer functions to read and write the dmtimer registers are currently
defined as follows ...
static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
int posted);
static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
u32 reg, u32 val, int posted);
The posted variable indicates if the timer is configured to use the posted mode
when performing register accesses. The posted mode configuration of the dmtimer
is stored in the omap_dm_timer structure that is also being passed to the above
functions and therefore we do not need to pass the posted variable separately.
Therefore, simplify the above functions by removing the posted variable as an
argument as this is not necessary.
I believe the reason for passing the posted flag was to optimize out some
functions from the timer code as that's being run all the time.
Care to check the assembly before and after this patch for the timer
functions with objdump -d to make sure it does not add tons of bloat
there?
Hi Tony,
Thanks for the details here. I see that makes sense and that the
compiler could take advantage of this as the functions are inlined.
I have taken a look at the disassembled output using objdump as you
mentioned. What I see is ...
1. For dmtimer.c the impact appears negligible, the total number of
lines outputted by objdump only changed by 8 with (1215 lines) and
without (1207 lines) the patch applied.
2. For timer.c the impact is greater. I see that
omap2_gp_timer_set_next_event() increased by 6 instructions from 29
to 35. clocksource_read_cycles() increased by 2 instructions 15 to
17 instructions. dmtimer_read_sched_clock() increased by 2
instructions from 17 to 19. omap2_gp_timer_set_mode() increased by
21 instructions from 102 to 123.
I imagine that we are mainly concerned about
omap2_gp_timer_set_next_event(), clocksource_read_cycles() and
dmtimer_read_sched_clock() as these will be called often. Therefore, I
am not sure if you wish to drop this patch.
Well does it at lots of new ldr to the critical code?
For the omap2_gp_timer_set_next_event() function it adds 3 load
instructions, increasing the number of possible loads from 11 to 14.
For the clocksource_read_cycles() function it adds 1 load instruction,
increasing the number of possible loads from 7 to 8.
For the dmtimer_read_sched_clock() function, I don't see any additional
loads, but instructions added are a tst and beq instruction.
quoted
quoted
By the way, if we do drop this patch, I would then need to fix the
setting of the posted variable in mach-omap2/timer.c for clock-source in
the case where a dmtimer is used. Today the code assumes that for
clock-source and clock-events posted mode is always used. However, with
the errata i103/i767 we will disable posted mode for clock-source on
omap2/3/4/5/am33xx devices.
Yes I see, I guess that means just adding a new systimer entry?
Actually, I think we can avoid that by not using posted mode for
clock-source timers at all. Posted mode only benefits the clock-events
timers that are configured often.
The benefit of not using posted mode for clock-source timers and setting
the "posted" parameter to 0, will really allow the compiler to optimise
the clocksource_read_cycles() and dmtimer_read_sched_clock() quite a
bit. So this could be a nice optimisation.
OK up to you, but maybe run some benchmarks first to figure out what
makes most sense? Updating the timer used to be a bottleneck earlier.
Ok, let me re-work this. Thanks for the inputs.
Cheers
Jon
On Thu, Sep 06, 2012 at 19:36:08, Hunter, Jon wrote:
On 09/06/2012 12:07 AM, Vaibhav Hiremath wrote:
quoted
On 9/6/2012 12:34 AM, Jon Hunter wrote:
quoted
Errata Titles:
i103: Delay needed to read some GP timer, WD timer and sync timer registers
after wakeup (OMAP3/4)
i767: Delay needed to read some GP timer registers after wakeup (OMAP5)
Description (i103/i767):
If a General Purpose Timer (GPTimer) is in posted mode (TSICR [2].POSTED=1),
due to internal resynchronizations, values read in TCRR, TCAR1 and TCAR2
registers right after the timer interface clock (L4) goes from stopped to
active may not return the expected values. The most common event leading to
this situation occurs upon wake up from idle.
GPTimer non-posted synchronization mode is not impacted by this limitation.
Workarounds:
1). Disable posted mode
2). Use static dependency between timer clock domain and MPUSS clock domain
3). Use no-idle mode when the timer is active
Workarounds #2 and #3 are not pratical from a power standpoint and so
workaround #1 has been implemented. Disabling posted mode adds some CPU overhead
for configuring the timers as the CPU has to wait for the write to complete.
However, disabling posted mode guarantees correct operation.
Please note that it is safe to use posted mode for timers if the counter (TCRR)
and capture (TCARx) registers will never be read. An example of this is the
clock-event system timer. This is used by the kernel to schedule events however,
the timers counter is never read and capture registers are not used. Given that
the kernel configures this timer often yet never reads the counter register it
is safe to enable posted mode in this case. Hence, for the timer used for kernel
clock-events, posted mode is enabled by overriding the errata for devices that
are impacted by this defect.
Although both dmtimers and watchdogs are impacted by this defect this patch only
implements the workaround for the dmtimer. Currently the watchdog driver does
not read the counter register and so no workaround is necessary.
Confirmed with Vaibhav Hiremath that this bug also impacts AM33xx devices.
Thanks for pinging me on this and getting it confirmed.
Couple of points,
1. It is confusing to me, as you are passing the errata flag so i expect
api should set it. Why can't we do reverse way, you pass 0 here, since
you don't want to set and pass this flag every other places where you
want to enable this errata.
Per the design of the __omap_dm_timer_populate_errata function, the 2nd
argument is called override to allow us to override an errata. I am not
a huge fan of this, but I wanted to be explicit in the code that we are
intentionally allowing posted mode for the clock-events timer.
I did not wish to pass the flags we want to set because if there more
flags added in the future then we will have to keep changing the calls
to the populate_errata function to add these.
Isn't that would self-explain himself which flag is going to set without
looking at the implementation?
I do not have any reservations here, it just doesn't seem easily readable to
me.
You can make a call here.
quoted
2. Why can't we enable for all timers? Even though clock-event is anyway
not reading it, but still is is applicable to it, right?
Yes it is still applicable but we never read it so it is ok to override.
If you see Richard W's original patch for enabling posted mode it is to
reduce overhead of programming timers, specifically the clock-events
timer which is program very often.
For other timers, we do not know how they will be used and so by default
we disable posted mode as this is safe.
quoted
3. Why can't we just simply Add this flag to hwmod_data file and read it
back in omap_timer_init() and omap_dm_timer_init_one(). Wouldn't that be
a good approach to handle it?
It could be done in this case, but typically I have not seen errata
flags added to HWMOD.
We are already using it, look at I2C, MMC. And in some cases, we have done
indirect implementation of errata. So I still feel, we should leverage hwmod
info for this, and anyway going forward DT will replace it.
Thanks,
Vaibhav
One limitation you would have with HWMOD is if an
erratum is only specific to a certain revision of the device. In this
case it is not and so it could work.
In general I think that having errata described by HWMOD would be a good
thing, but if think that should be a longer term goal with agreement
from Benoit and add some general errata helpers to HWMOD.
Cheers
Jon
On Thu, Sep 06, 2012 at 21:31:21, Hunter, Jon wrote:
On 09/06/2012 09:20 AM, Jon Hunter wrote:
quoted
On 09/06/2012 07:57 AM, Vaibhav Hiremath wrote:
quoted
On 9/6/2012 12:34 AM, Jon Hunter wrote:
quoted
Currently the dmtimer posted mode is being enabled when the function
__omap_dm_timer_reset() is called. This function is only being called for
OMAP1 timers and OMAP2+ timers that are being used as system timers. Hence,
for OMAP2+ timers that are NOT being used as a system timer, posted mode is
not enabled but the "timer->posted" variable is still set (incorrectly) in
the omap_dm_timer_prepare() function.
This is a regression introduced by commit 3392cdd3 (ARM: OMAP: dmtimer:
switch-over to platform device driver) which changed the code to only call
omap_dm_timer_reset() for OMAP1 devices. Although this is a regression from
the original code it only impacts performance and so is not needed for stable.
Signed-off-by: Jon Hunter <redacted>
---
arch/arm/mach-omap2/timer.c | 3 +--
arch/arm/plat-omap/dmtimer.c | 14 +++++---------
arch/arm/plat-omap/include/plat/dmtimer.h | 9 ++++++++-
3 files changed, 14 insertions(+), 12 deletions(-)
@@ -150,13 +144,15 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer)}}+omap_dm_timer_enable(timer);+if(timer->capability&OMAP_TIMER_NEEDS_RESET)omap_dm_timer_reset(timer);-ret=omap_dm_timer_set_source(timer,OMAP_TIMER_SRC_32_KHZ);+__omap_dm_timer_enable_posted(timer);+omap_dm_timer_disable(timer);-timer->posted=1;-returnret;+returnomap_dm_timer_set_source(timer,OMAP_TIMER_SRC_32_KHZ);
May be I am speculating here and I know this is tested and supposed to
work, but Isn't it safe to set parent keeping module enables.
So you would rather change the functional clock while the timer is
enabled/active? So although that we are doing this today, that does not
sound like a good idea to me :-)
Actually, we are not doing this today. If you look at the current code
we are only enabling the timer while doing the soft-reset for omap1
devices. Hence, even in the current code we set the parent while the
timer is not enabled. So there is no actual change here in the sequence.
Yes, you are absolutely right here. As such there is no change in the
sequence.
Thanks,
Vaibhav
On Thu, Sep 06, 2012 at 20:50:27, Hunter, Jon wrote:
On 09/06/2012 09:42 AM, Jon Hunter wrote:
quoted
On 09/06/2012 09:06 AM, Jon Hunter wrote:
quoted
On 09/06/2012 12:07 AM, Vaibhav Hiremath wrote:
quoted
On 9/6/2012 12:34 AM, Jon Hunter wrote:
quoted
Errata Titles:
i103: Delay needed to read some GP timer, WD timer and sync timer registers
after wakeup (OMAP3/4)
i767: Delay needed to read some GP timer registers after wakeup (OMAP5)
Description (i103/i767):
If a General Purpose Timer (GPTimer) is in posted mode (TSICR [2].POSTED=1),
due to internal resynchronizations, values read in TCRR, TCAR1 and TCAR2
registers right after the timer interface clock (L4) goes from stopped to
active may not return the expected values. The most common event leading to
this situation occurs upon wake up from idle.
GPTimer non-posted synchronization mode is not impacted by this limitation.
Workarounds:
1). Disable posted mode
2). Use static dependency between timer clock domain and MPUSS clock domain
3). Use no-idle mode when the timer is active
Workarounds #2 and #3 are not pratical from a power standpoint and so
workaround #1 has been implemented. Disabling posted mode adds some CPU overhead
for configuring the timers as the CPU has to wait for the write to complete.
However, disabling posted mode guarantees correct operation.
Please note that it is safe to use posted mode for timers if the counter (TCRR)
and capture (TCARx) registers will never be read. An example of this is the
clock-event system timer. This is used by the kernel to schedule events however,
the timers counter is never read and capture registers are not used. Given that
the kernel configures this timer often yet never reads the counter register it
is safe to enable posted mode in this case. Hence, for the timer used for kernel
clock-events, posted mode is enabled by overriding the errata for devices that
are impacted by this defect.
Although both dmtimers and watchdogs are impacted by this defect this patch only
implements the workaround for the dmtimer. Currently the watchdog driver does
not read the counter register and so no workaround is necessary.
Confirmed with Vaibhav Hiremath that this bug also impacts AM33xx devices.
Thanks for pinging me on this and getting it confirmed.
Couple of points,
1. It is confusing to me, as you are passing the errata flag so i expect
api should set it. Why can't we do reverse way, you pass 0 here, since
you don't want to set and pass this flag every other places where you
want to enable this errata.
Per the design of the __omap_dm_timer_populate_errata function, the 2nd
argument is called override to allow us to override an errata. I am not
a huge fan of this, but I wanted to be explicit in the code that we are
intentionally allowing posted mode for the clock-events timer.
I did not wish to pass the flags we want to set because if there more
flags added in the future then we will have to keep changing the calls
to the populate_errata function to add these.
By the way, your proposal could work nicely if we could pass errata
flags from HWMOD. However, I am not sure if Paul or Benoit would go for
this as they want HWMOD data to be auto-generated as much as possible
and so I am not sure how that would work for errata which are not
expected by design ;-)
Another alternative would be to drop the override argument altogether
and just do something like the following for the clock-events timer ...
I would still vote for adding this info to hwmod data, I think that is the
right place for all such hw related information.
Thanks,
Viabhav