Re: [RFC PATCH 13/13] m68k: mvme16x: Convert to clocksource APIy

2018-11-18 Thread Thomas Gleixner
Finn,

On Wed, 14 Nov 2018, Finn Thain wrote:
> On Tue, 13 Nov 2018, Thomas Gleixner wrote:
> > Urgh. Then you have more serious trouble. If the interrupting handler 
> > calls any of the time accessor functions then you can actually live lock 
> > when the interrupt happens in the middle of the write locked section of 
> > the core timekeeping update.
> 
> Does this apply to arch_gettimeoffset also? If so, that would mean another 
> bug fix patch for -stable...

arch_gettimeoffset() can be called from any context. The only interrupt
which can affect it is the timer interrupt. As m68k are all UP machines
this is not a problem because:

  ktime_get()
 do {
seq = read_seqcount_begin(tk.seq);
nsec =  + arch_gettimeoffset();
 } while (seqcount_retry(tk.seq);

and the timer interrupt does:

  arch_timeoffset += value;
  ...
xtime_update()
  ...
write_seqcount_begin(tk.seq);

write_seqcount_end(tk.seq);

So where ever the timer interrupt hits inside of ktime_get() or any other
accessor the seqcount will make it retry, so the result is always
consistent.

For SMP that would be a different story.

> > So you really want to disable interrupts across the whole timer 
> > interrupt function or make sure that the timer interrupt is the highest 
> > priority one on the system.
> > 
> 
> The timer interrupt priority isn't always what one would hope. 
> 
> But I can certainly disable interrupts for timer_interrupt() execution 
> (that is, xtime_update() etc.)

Oh yes, you should.

Thanks,

tglx


[RFC PATCH v2 05/14] m68k: Drop ARCH_USES_GETTIMEOFFSET

2018-11-18 Thread Finn Thain
The functions that implement arch_gettimeoffset are re-used by
new clocksource drivers in subsequent patches.

Signed-off-by: Finn Thain 
Acked-by: Linus Walleij 
---
 arch/m68k/Kconfig   | 1 -
 arch/m68k/amiga/config.c| 3 ---
 arch/m68k/atari/config.c| 2 --
 arch/m68k/bvme6000/config.c | 2 --
 arch/m68k/hp300/config.c| 1 -
 arch/m68k/hp300/time.h  | 1 -
 arch/m68k/mac/config.c  | 3 ---
 arch/m68k/mvme147/config.c  | 2 --
 arch/m68k/mvme16x/config.c  | 2 --
 9 files changed, 17 deletions(-)

diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 070553791e97..cc62660a5760 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -19,7 +19,6 @@ config M68K
select GENERIC_STRNCPY_FROM_USER if MMU
select GENERIC_STRNLEN_USER if MMU
select ARCH_WANT_IPC_PARSE_VERSION
-   select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE
select HAVE_FUTEX_CMPXCHG if MMU && FUTEX
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_REL
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index 65f63a457130..d4976c1aa0cc 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -95,8 +95,6 @@ static char amiga_model_name[13] = "Amiga ";
 static void amiga_sched_init(irq_handler_t handler);
 static void amiga_get_model(char *model);
 static void amiga_get_hardware_list(struct seq_file *m);
-/* amiga specific timer functions */
-static u32 amiga_gettimeoffset(void);
 extern void amiga_mksound(unsigned int count, unsigned int ticks);
 static void amiga_reset(void);
 extern void amiga_init_sound(void);
@@ -386,7 +384,6 @@ void __init config_amiga(void)
mach_init_IRQ= amiga_init_IRQ;
mach_get_model   = amiga_get_model;
mach_get_hardware_list = amiga_get_hardware_list;
-   arch_gettimeoffset   = amiga_gettimeoffset;
 
/*
 * default MAX_DMA=0x on all machines. If we don't do so, the 
SCSI
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index bd96702a1ad0..89e65be2655f 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -78,7 +78,6 @@ static void atari_heartbeat(int on);
 
 /* atari specific timer functions (in time.c) */
 extern void atari_sched_init(irq_handler_t);
-extern u32 atari_gettimeoffset(void);
 extern int atari_mste_hwclk (int, struct rtc_time *);
 extern int atari_tt_hwclk (int, struct rtc_time *);
 
@@ -205,7 +204,6 @@ void __init config_atari(void)
mach_init_IRQ= atari_init_IRQ;
mach_get_model   = atari_get_model;
mach_get_hardware_list = atari_get_hardware_list;
-   arch_gettimeoffset   = atari_gettimeoffset;
mach_reset   = atari_reset;
mach_max_dma_address = 0xff;
 #if IS_ENABLED(CONFIG_INPUT_M68K_BEEP)
diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
index d1de3cb1f8fe..c27c104ac7e7 100644
--- a/arch/m68k/bvme6000/config.c
+++ b/arch/m68k/bvme6000/config.c
@@ -39,7 +39,6 @@
 
 static void bvme6000_get_model(char *model);
 extern void bvme6000_sched_init(irq_handler_t handler);
-extern u32 bvme6000_gettimeoffset(void);
 extern int bvme6000_hwclk (int, struct rtc_time *);
 extern void bvme6000_reset (void);
 void bvme6000_set_vectors (void);
@@ -105,7 +104,6 @@ void __init config_bvme6000(void)
 mach_max_dma_address = 0x;
 mach_sched_init  = bvme6000_sched_init;
 mach_init_IRQ= bvme6000_init_IRQ;
-arch_gettimeoffset   = bvme6000_gettimeoffset;
 mach_hwclk   = bvme6000_hwclk;
 mach_reset  = bvme6000_reset;
 mach_get_model   = bvme6000_get_model;
diff --git a/arch/m68k/hp300/config.c b/arch/m68k/hp300/config.c
index a19bcd23f80b..a161d44fd20b 100644
--- a/arch/m68k/hp300/config.c
+++ b/arch/m68k/hp300/config.c
@@ -254,7 +254,6 @@ void __init config_hp300(void)
mach_sched_init  = hp300_sched_init;
mach_init_IRQ= hp300_init_IRQ;
mach_get_model   = hp300_get_model;
-   arch_gettimeoffset   = hp300_gettimeoffset;
mach_hwclk   = hp300_hwclk;
mach_get_ss  = hp300_get_ss;
mach_reset   = hp300_reset;
diff --git a/arch/m68k/hp300/time.h b/arch/m68k/hp300/time.h
index f5583ec4033d..1d77b55cc72a 100644
--- a/arch/m68k/hp300/time.h
+++ b/arch/m68k/hp300/time.h
@@ -1,2 +1 @@
 extern void hp300_sched_init(irq_handler_t vector);
-extern u32 hp300_gettimeoffset(void);
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index cd9317d53276..11be08f4f750 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -54,8 +54,6 @@ struct mac_booter_data mac_bi_data;
 /* The phys. video addr. - might be bogus on some machines */
 static unsigned long mac_orig_videoaddr;
 
-/* Mac specific timer functions */
-extern u32 mac_gettimeoffset(void);
 extern int mac_hwclk(int, struct rtc_time *);
 extern void iop_preinit(void);
 extern void iop_init(void);
@@ -155,7 +153,6 @@ void __init c

[RFC PATCH v2 04/14] m68k: apollo, q40, sun3, sun3x: Remove arch_gettimeoffset implementations

2018-11-18 Thread Finn Thain
These dummy implementations are no better than
default_arch_gettimeoffset() so remove them.

Signed-off-by: Finn Thain 
---
 arch/m68k/apollo/config.c | 7 ---
 arch/m68k/q40/config.c| 9 -
 arch/m68k/sun3/config.c   | 2 --
 arch/m68k/sun3/intersil.c | 7 ---
 arch/m68k/sun3x/config.c  | 1 -
 arch/m68k/sun3x/time.c| 5 -
 arch/m68k/sun3x/time.h| 1 -
 7 files changed, 32 deletions(-)

diff --git a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c
index aef8d42e078d..7d168e6dfb01 100644
--- a/arch/m68k/apollo/config.c
+++ b/arch/m68k/apollo/config.c
@@ -29,7 +29,6 @@ u_long apollo_model;
 
 extern void dn_sched_init(irq_handler_t handler);
 extern void dn_init_IRQ(void);
-extern u32 dn_gettimeoffset(void);
 extern int dn_dummy_hwclk(int, struct rtc_time *);
 extern void dn_dummy_reset(void);
 #ifdef CONFIG_HEARTBEAT
@@ -152,7 +151,6 @@ void __init config_apollo(void)
 
mach_sched_init=dn_sched_init; /* */
mach_init_IRQ=dn_init_IRQ;
-   arch_gettimeoffset   = dn_gettimeoffset;
mach_max_dma_address = 0x;
mach_hwclk   = dn_dummy_hwclk; /* */
mach_reset   = dn_dummy_reset;  /* */
@@ -205,11 +203,6 @@ void dn_sched_init(irq_handler_t timer_routine)
pr_err("Couldn't register timer interrupt\n");
 }
 
-u32 dn_gettimeoffset(void)
-{
-   return 0xdeadbeef;
-}
-
 int dn_dummy_hwclk(int op, struct rtc_time *t) {
 
 
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
index 96810d91da2b..e63eb5f06999 100644
--- a/arch/m68k/q40/config.c
+++ b/arch/m68k/q40/config.c
@@ -40,7 +40,6 @@ extern void q40_init_IRQ(void);
 static void q40_get_model(char *model);
 extern void q40_sched_init(irq_handler_t handler);
 
-static u32 q40_gettimeoffset(void);
 static int q40_hwclk(int, struct rtc_time *);
 static unsigned int q40_get_ss(void);
 static int q40_get_rtc_pll(struct rtc_pll_info *pll);
@@ -169,7 +168,6 @@ void __init config_q40(void)
mach_sched_init = q40_sched_init;
 
mach_init_IRQ = q40_init_IRQ;
-   arch_gettimeoffset = q40_gettimeoffset;
mach_hwclk = q40_hwclk;
mach_get_ss = q40_get_ss;
mach_get_rtc_pll = q40_get_rtc_pll;
@@ -201,13 +199,6 @@ int __init q40_parse_bootinfo(const struct bi_record *rec)
return 1;
 }
 
-
-static u32 q40_gettimeoffset(void)
-{
-   return 5000 * (ql_ticks != 0) * 1000;
-}
-
-
 /*
  * Looks like op is non-zero for setting the clock, and zero for
  * reading the clock.
diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c
index 79a2bb857906..867e68d92c71 100644
--- a/arch/m68k/sun3/config.c
+++ b/arch/m68k/sun3/config.c
@@ -37,7 +37,6 @@
 
 char sun3_reserved_pmeg[SUN3_PMEGS_NUM];
 
-extern u32 sun3_gettimeoffset(void);
 static void sun3_sched_init(irq_handler_t handler);
 extern void sun3_get_model (char* model);
 extern int sun3_hwclk(int set, struct rtc_time *t);
@@ -138,7 +137,6 @@ void __init config_sun3(void)
 mach_sched_init  =  sun3_sched_init;
 mach_init_IRQ=  sun3_init_IRQ;
 mach_reset   =  sun3_reboot;
-   arch_gettimeoffset   =  sun3_gettimeoffset;
mach_get_model   =  sun3_get_model;
mach_hwclk   =  sun3_hwclk;
mach_halt=  sun3_halt;
diff --git a/arch/m68k/sun3/intersil.c b/arch/m68k/sun3/intersil.c
index d911070af02a..8fc74864de81 100644
--- a/arch/m68k/sun3/intersil.c
+++ b/arch/m68k/sun3/intersil.c
@@ -22,13 +22,6 @@
 #define STOP_VAL (INTERSIL_STOP | INTERSIL_INT_ENABLE | INTERSIL_24H_MODE)
 #define START_VAL (INTERSIL_RUN | INTERSIL_INT_ENABLE | INTERSIL_24H_MODE)
 
-/* does this need to be implemented? */
-u32 sun3_gettimeoffset(void)
-{
-  return 1000;
-}
-
-
 /* get/set hwclock */
 
 int sun3_hwclk(int set, struct rtc_time *t)
diff --git a/arch/m68k/sun3x/config.c b/arch/m68k/sun3x/config.c
index 33d3a1c6fba0..03ce7f9facfe 100644
--- a/arch/m68k/sun3x/config.c
+++ b/arch/m68k/sun3x/config.c
@@ -49,7 +49,6 @@ void __init config_sun3x(void)
mach_sched_init  = sun3x_sched_init;
mach_init_IRQ= sun3_init_IRQ;
 
-   arch_gettimeoffset   = sun3x_gettimeoffset;
mach_reset   = sun3x_reboot;
 
mach_hwclk   = sun3x_hwclk;
diff --git a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c
index 3c8a86d08508..9163294b0fb6 100644
--- a/arch/m68k/sun3x/time.c
+++ b/arch/m68k/sun3x/time.c
@@ -73,11 +73,6 @@ int sun3x_hwclk(int set, struct rtc_time *t)
 
return 0;
 }
-/* Not much we can do here */
-u32 sun3x_gettimeoffset(void)
-{
-return 0L;
-}
 
 #if 0
 static irqreturn_t sun3x_timer_tick(int irq, void *dev_id)
diff --git a/arch/m68k/sun3x/time.h b/arch/m68k/sun3x/time.h
index 496f406412ad..86ce78bb3c28 100644
--- a/arch/m68k/sun3x/time.h
+++ b/arch/m68k/sun3x/time.h
@@ -3,7 +3,6 @@
 #define SUN3X_TIME_H
 
 extern int sun3x_hwclk(int set, struct rtc_time *t);
-u32 sun3x_gettimeoffset(void);
 void sun3x_sched_init(irq_handler_t vector);
 

[RFC PATCH v2 11/14] m68k: mvme147: Convert to clocksource API

2018-11-18 Thread Finn Thain
Add a platform clocksource by adapting the existing arch_gettimeoffset
implementation.

Signed-off-by: Finn Thain 
Acked-by: Linus Walleij 
---
Changed since v1:
 - Moved clk_total access to within the irq lock.
 - Use type u32 for tick counter.
---
 arch/m68k/include/asm/mvme147hw.h |  1 -
 arch/m68k/mvme147/config.c| 38 ++-
 2 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/arch/m68k/include/asm/mvme147hw.h 
b/arch/m68k/include/asm/mvme147hw.h
index 9c7ff67c5ffd..7c3dd513128e 100644
--- a/arch/m68k/include/asm/mvme147hw.h
+++ b/arch/m68k/include/asm/mvme147hw.h
@@ -66,7 +66,6 @@ struct pcc_regs {
 #define PCC_INT_ENAB   0x08
 
 #define PCC_TIMER_INT_CLR  0x80
-#define PCC_TIMER_PRELOAD  63936l
 
 #define PCC_LEVEL_ABORT0x07
 #define PCC_LEVEL_SERIAL   0x04
diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
index 4ef4faa5ed8b..82b53b5ca82b 100644
--- a/arch/m68k/mvme147/config.c
+++ b/arch/m68k/mvme147/config.c
@@ -17,6 +17,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -92,6 +93,21 @@ void __init config_mvme147(void)
vme_brdtype = VME_TYPE_MVME147;
 }
 
+static u64 mvme147_read_clk(struct clocksource *cs);
+
+static struct clocksource mvme147_clk = {
+   .name   = "pcc",
+   .rating = 250,
+   .read   = mvme147_read_clk,
+   .mask   = CLOCKSOURCE_MASK(32),
+   .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static u32 clk_total;
+
+#define PCC_TIMER_CLOCK_FREQ 16
+#define PCC_TIMER_CYCLES (PCC_TIMER_CLOCK_FREQ / HZ)
+#define PCC_TIMER_PRELOAD(0x1 - PCC_TIMER_CYCLES)
 
 /* Using pcc tick timer 1 */
 
@@ -103,6 +119,7 @@ static irqreturn_t mvme147_timer_int (int irq, void *dev_id)
local_irq_save(flags);
m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR;
m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1;
+   clk_total += PCC_TIMER_CYCLES;
timer_routine(0, NULL);
local_irq_restore(flags);
 
@@ -112,32 +129,41 @@ static irqreturn_t mvme147_timer_int (int irq, void 
*dev_id)
 
 void mvme147_sched_init (irq_handler_t timer_routine)
 {
-   if (request_irq(PCC_IRQ_TIMER1, mvme147_timer_int, 0, "timer 1",
-   timer_routine))
+   if (request_irq(PCC_IRQ_TIMER1, mvme147_timer_int, IRQF_TIMER,
+   "timer 1", timer_routine))
pr_err("Couldn't register timer interrupt\n");
 
/* Init the clock with a value */
-   /* our clock goes off every 6.25us */
+   /* The clock counter increments until 0x then reloads */
m147_pcc->t1_preload = PCC_TIMER_PRELOAD;
m147_pcc->t1_cntrl = 0x0;   /* clear timer */
m147_pcc->t1_cntrl = 0x3;   /* start timer */
m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR;  /* clear pending ints */
m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1;
+
+   clocksource_register_hz(&mvme147_clk, PCC_TIMER_CLOCK_FREQ);
 }
 
-/* This is always executed with interrupts disabled.  */
 /* XXX There are race hazards in this code XXX */
-u32 mvme147_gettimeoffset(void)
+static u64 mvme147_read_clk(struct clocksource *cs)
 {
+   unsigned long flags;
volatile unsigned short *cp = (volatile unsigned short *)0xfffe1012;
unsigned short n;
+   u32 ticks;
+
+   local_irq_save(flags);
 
n = *cp;
while (n != *cp)
n = *cp;
 
n -= PCC_TIMER_PRELOAD;
-   return ((unsigned long)n * 25 / 4) * 1000;
+   ticks = clk_total + n;
+
+   local_irq_restore(flags);
+
+   return ticks;
 }
 
 static int bcd2int (unsigned char b)
-- 
2.18.1



[RFC PATCH v2 01/14] m68k: Call timer_interrupt() with interrupts disabled

2018-11-18 Thread Finn Thain
Some platforms execute their timer handler with the interrupt priority
level below 6. That means the handler could be interrupted by another
driver and this could lead to re-entry of the timer core.

Avoid this by use of local_irq_save/restore for timer interrupt dispatch.
This provides mutual exclusion around the timer interrupt flag access
which is needed later in this series for the clocksource coversion.

Reported-by: Thomas Gleixner 
Link: 
http://lkml.kernel.org/r/alpine.deb.2.21.1811131407120.2...@nanos.tec.linutronix.de
Signed-off-by: Finn Thain 
---
I've only checked 680x0 MMU platforms for this issue.
---
 arch/m68k/amiga/cia.c   | 10 ++
 arch/m68k/atari/ataints.c   |  4 ++--
 arch/m68k/atari/time.c  | 15 ++-
 arch/m68k/bvme6000/config.c | 18 +-
 arch/m68k/hp300/time.c  | 10 --
 arch/m68k/mac/via.c | 17 +
 arch/m68k/mvme147/config.c  | 18 ++
 arch/m68k/mvme16x/config.c  | 19 ++-
 arch/m68k/q40/q40ints.c |  7 ++-
 arch/m68k/sun3/sun3ints.c   |  3 +++
 arch/m68k/sun3x/time.c  | 16 ++--
 11 files changed, 99 insertions(+), 38 deletions(-)

diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c
index 2081b8cd5591..b65665160711 100644
--- a/arch/m68k/amiga/cia.c
+++ b/arch/m68k/amiga/cia.c
@@ -88,10 +88,20 @@ static irqreturn_t cia_handler(int irq, void *dev_id)
struct ciabase *base = dev_id;
int mach_irq;
unsigned char ints;
+   unsigned long flags;
 
+   /* Interrupts get disabled while the timer irq flag is cleared and
+* the timer interrupt serviced.
+*/
+   local_irq_save(flags);
mach_irq = base->cia_irq;
ints = cia_set_irq(base, CIA_ICR_ALL);
amiga_custom.intreq = base->int_mask;
+   if (ints & 1) {
+   generic_handle_irq(mach_irq);
+   mach_irq++, ints >>= 1;
+   }
+   local_irq_restore(flags);
for (; ints; mach_irq++, ints >>= 1) {
if (ints & 1)
generic_handle_irq(mach_irq);
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
index 3d2b63bedf05..56f02ea2c248 100644
--- a/arch/m68k/atari/ataints.c
+++ b/arch/m68k/atari/ataints.c
@@ -142,7 +142,7 @@ struct mfptimerbase {
.name   = "MFP Timer D"
 };
 
-static irqreturn_t mfptimer_handler(int irq, void *dev_id)
+static irqreturn_t mfp_timer_d_handler(int irq, void *dev_id)
 {
struct mfptimerbase *base = dev_id;
int mach_irq;
@@ -344,7 +344,7 @@ void __init atari_init_IRQ(void)
st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 0xf0) | 0x6;
 
/* request timer D dispatch handler */
-   if (request_irq(IRQ_MFP_TIMD, mfptimer_handler, IRQF_SHARED,
+   if (request_irq(IRQ_MFP_TIMD, mfp_timer_d_handler, IRQF_SHARED,
stmfp_base.name, &stmfp_base))
pr_err("Couldn't register %s interrupt\n", stmfp_base.name);
 
diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c
index 9cca64286464..fafa20f75ab9 100644
--- a/arch/m68k/atari/time.c
+++ b/arch/m68k/atari/time.c
@@ -24,6 +24,18 @@
 DEFINE_SPINLOCK(rtc_lock);
 EXPORT_SYMBOL_GPL(rtc_lock);
 
+static irqreturn_t mfp_timer_c_handler(int irq, void *dev_id)
+{
+   irq_handler_t timer_routine = dev_id;
+   unsigned long flags;
+
+   local_irq_save(flags);
+   timer_routine(0, NULL);
+   local_irq_restore(flags);
+
+   return IRQ_HANDLED;
+}
+
 void __init
 atari_sched_init(irq_handler_t timer_routine)
 {
@@ -32,7 +44,8 @@ atari_sched_init(irq_handler_t timer_routine)
 /* start timer C, div = 1:100 */
 st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60;
 /* install interrupt service routine for MFP Timer C */
-if (request_irq(IRQ_MFP_TIMC, timer_routine, 0, "timer", timer_routine))
+if (request_irq(IRQ_MFP_TIMC, mfp_timer_c_handler, 0, "timer",
+timer_routine))
pr_err("Couldn't register timer interrupt\n");
 }
 
diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
index 143ee9fa3893..d1de3cb1f8fe 100644
--- a/arch/m68k/bvme6000/config.c
+++ b/arch/m68k/bvme6000/config.c
@@ -44,11 +44,6 @@ extern int bvme6000_hwclk (int, struct rtc_time *);
 extern void bvme6000_reset (void);
 void bvme6000_set_vectors (void);
 
-/* Save tick handler routine pointer, will point to xtime_update() in
- * kernel/timer/timekeeping.c, called via bvme6000_process_int() */
-
-static irq_handler_t tick_handler;
-
 
 int __init bvme6000_parse_bootinfo(const struct bi_record *bi)
 {
@@ -157,12 +152,18 @@ irqreturn_t bvme6000_abort_int (int irq, void *dev_id)
 
 static irqreturn_t bvme6000_timer_int (int irq, void *dev_id)
 {
+irq_handler_t timer_routine = dev_id;
+unsigned long flags;
 volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
-unsigned char msr = rtc->msr & 0xc0;
+unsigned char msr;
 
+local_irq_save(flags);
+msr = rtc->ms

[RFC PATCH v2 13/14] m68k: mvme16x: Convert to clocksource API

2018-11-18 Thread Finn Thain
Add a platform clocksource by adapting the existing arch_gettimeoffset
implementation.

Signed-off-by: Finn Thain 
Acked-by: Linus Walleij 
---
Changed since v1:
 - Moved clk_total access to within the irq lock.
---
 arch/m68k/mvme16x/config.c | 39 +++---
 1 file changed, 32 insertions(+), 7 deletions(-)

diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
index 8bafa6a37593..2c109ee2a1a5 100644
--- a/arch/m68k/mvme16x/config.c
+++ b/arch/m68k/mvme16x/config.c
@@ -19,6 +19,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -343,6 +344,21 @@ static irqreturn_t mvme16x_abort_int (int irq, void 
*dev_id)
return IRQ_HANDLED;
 }
 
+static u64 mvme16x_read_clk(struct clocksource *cs);
+
+static struct clocksource mvme16x_clk = {
+   .name   = "pcc",
+   .rating = 250,
+   .read   = mvme16x_read_clk,
+   .mask   = CLOCKSOURCE_MASK(32),
+   .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static u32 clk_total;
+
+#define PCC_TIMER_CLOCK_FREQ 100
+#define PCC_TIMER_CYCLES (PCC_TIMER_CLOCK_FREQ / HZ)
+
 static irqreturn_t mvme16x_timer_int (int irq, void *dev_id)
 {
irq_handler_t timer_routine = dev_id;
@@ -350,6 +366,7 @@ static irqreturn_t mvme16x_timer_int (int irq, void *dev_id)
 
local_irq_save(flags);
*(volatile unsigned char *)0xfff4201b |= 8;
+   clk_total += PCC_TIMER_CYCLES;
timer_routine(0, NULL);
local_irq_restore(flags);
 
@@ -363,13 +380,15 @@ void mvme16x_sched_init (irq_handler_t timer_routine)
 
 /* Using PCCchip2 or MC2 chip tick timer 1 */
 *(volatile unsigned long *)0xfff42008 = 0;
-*(volatile unsigned long *)0xfff42004 = 1; /* 10ms */
+*(volatile unsigned long *)0xfff42004 = PCC_TIMER_CYCLES;
 *(volatile unsigned char *)0xfff42017 |= 3;
 *(volatile unsigned char *)0xfff4201b = 0x16;
-if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, 0,
-"timer", timer_routine))
+if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, IRQF_TIMER, "timer",
+timer_routine))
panic ("Couldn't register timer int");
 
+clocksource_register_hz(&mvme16x_clk, PCC_TIMER_CLOCK_FREQ);
+
 if (brdno == 0x0162 || brdno == 0x172)
irq = MVME162_IRQ_ABORT;
 else
@@ -379,11 +398,17 @@ void mvme16x_sched_init (irq_handler_t timer_routine)
panic ("Couldn't register abort int");
 }
 
-
-/* This is always executed with interrupts disabled.  */
-u32 mvme16x_gettimeoffset(void)
+static u64 mvme16x_read_clk(struct clocksource *cs)
 {
-return (*(volatile u32 *)0xfff42008) * 1000;
+   unsigned long flags;
+   u32 ticks;
+
+   local_irq_save(flags);
+   ticks = *(volatile u32 *)0xfff42008;
+   ticks += clk_total;
+   local_irq_restore(flags);
+
+   return ticks;
 }
 
 int bcd2int (unsigned char b)
-- 
2.18.1



[RFC PATCH v2 08/14] m68k: bvme6000: Convert to clocksource API

2018-11-18 Thread Finn Thain
Add a platform clocksource by adapting the existing arch_gettimeoffset
implementation.

Signed-off-by: Finn Thain 
Acked-by: Linus Walleij 
---
Changed since v1:
 - Moved clk_total access to within the irq lock.
---
 arch/m68k/bvme6000/config.c | 52 +++--
 1 file changed, 38 insertions(+), 14 deletions(-)

diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
index c27c104ac7e7..9691d741e9dc 100644
--- a/arch/m68k/bvme6000/config.c
+++ b/arch/m68k/bvme6000/config.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -147,6 +148,21 @@ irqreturn_t bvme6000_abort_int (int irq, void *dev_id)
return IRQ_HANDLED;
 }
 
+static u64 bvme6000_read_clk(struct clocksource *cs);
+
+static struct clocksource bvme6000_clk = {
+   .name   = "rtc",
+   .rating = 250,
+   .read   = bvme6000_read_clk,
+   .mask   = CLOCKSOURCE_MASK(32),
+   .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static u32 clk_total;
+
+#define RTC_TIMER_CLOCK_FREQ 800
+#define RTC_TIMER_CYCLES (RTC_TIMER_CLOCK_FREQ / HZ)
+#define RTC_TIMER_COUNT  ((RTC_TIMER_CYCLES / 2) - 1)
 
 static irqreturn_t bvme6000_timer_int (int irq, void *dev_id)
 {
@@ -158,6 +174,7 @@ static irqreturn_t bvme6000_timer_int (int irq, void 
*dev_id)
 local_irq_save(flags);
 msr = rtc->msr & 0xc0;
 rtc->msr = msr | 0x20; /* Ack the interrupt */
+clk_total += RTC_TIMER_CYCLES;
 timer_routine(0, NULL);
 local_irq_restore(flags);
 
@@ -180,13 +197,13 @@ void bvme6000_sched_init (irq_handler_t timer_routine)
 
 rtc->msr = 0;  /* Ensure timer registers accessible */
 
-if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, 0,
-   "timer", timer_routine))
+if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, IRQF_TIMER, "timer",
+timer_routine))
panic ("Couldn't register timer int");
 
 rtc->t1cr_omr = 0x04;  /* Mode 2, ext clk */
-rtc->t1msb = 3 >> 8;
-rtc->t1lsb = 3 & 0xff;
+rtc->t1msb = RTC_TIMER_COUNT >> 8;
+rtc->t1lsb = RTC_TIMER_COUNT & 0xff;
 rtc->irr_icr1 &= 0xef; /* Route timer 1 to INTR pin */
 rtc->msr = 0x40;   /* Access int.cntrl, etc */
 rtc->pfr_icr0 = 0x80;  /* Just timer 1 ints enabled */
@@ -198,14 +215,14 @@ void bvme6000_sched_init (irq_handler_t timer_routine)
 
 rtc->msr = msr;
 
+clocksource_register_hz(&bvme6000_clk, RTC_TIMER_CLOCK_FREQ);
+
 if (request_irq(BVME_IRQ_ABORT, bvme6000_abort_int, 0,
"abort", bvme6000_abort_int))
panic ("Couldn't register abort int");
 }
 
 
-/* This is always executed with interrupts disabled.  */
-
 /*
  * NOTE:  Don't accept any readings within 5us of rollover, as
  * the T1INT bit may be a little slow getting set.  There is also
@@ -213,14 +230,18 @@ void bvme6000_sched_init (irq_handler_t timer_routine)
  * results...
  */
 
-u32 bvme6000_gettimeoffset(void)
+static u64 bvme6000_read_clk(struct clocksource *cs)
 {
+unsigned long flags;
 volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
 volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE;
-unsigned char msr = rtc->msr & 0xc0;
+unsigned char msr;
 unsigned char t1int, t1op;
 u32 v = 80, ov;
 
+local_irq_save(flags);
+
+msr = rtc->msr & 0xc0;
 rtc->msr = 0;  /* Ensure timer registers accessible */
 
 do {
@@ -233,17 +254,20 @@ u32 bvme6000_gettimeoffset(void)
 } while (t1int != (rtc->msr & 0x20) ||
t1op != (pit->pcdr & 0x04) ||
abs(ov-v) > 80 ||
-   v > 39960);
+   v > RTC_TIMER_COUNT - (RTC_TIMER_COUNT / 100));
 
-v = 3 - v;
+v = RTC_TIMER_COUNT - v;
 if (!t1op) /* If in second half cycle.. */
-   v += 4;
-v /= 8;/* Convert ticks to microseconds */
+   v += RTC_TIMER_CYCLES / 2;
 if (t1int)
-   v += 1; /* Int pending, + 10ms */
+   v += RTC_TIMER_CYCLES;
 rtc->msr = msr;
 
-return v * 1000;
+v += clk_total;
+
+local_irq_restore(flags);
+
+return v;
 }
 
 /*
-- 
2.18.1



[RFC PATCH v2 09/14] m68k: hp300: Remove hp300_gettimeoffset()

2018-11-18 Thread Finn Thain
hp300_gettimeoffset() never checks the timer interrupt flag and will
fail to notice when the timer counter gets reloaded. That means the
clock could jump backwards.

Remove this code and leave this platform on the 'jiffies' clocksource.
Note that this amounts to a regression in clock precision. However,
adopting the 'jiffies' clocksource does resolve the monotonicity issue.

Signed-off-by: Finn Thain 
---
hp300_gettimeoffset() cannot be used in a clocksource conversion
unless it can be made monotonic. I can't fix this without knowing the
details of the timer implementation, such as the relationship between
the timer count and the interrupt flag.
---
 arch/m68k/hp300/time.c | 19 ---
 1 file changed, 19 deletions(-)

diff --git a/arch/m68k/hp300/time.c b/arch/m68k/hp300/time.c
index d30b03ea93a2..37cccdb46def 100644
--- a/arch/m68k/hp300/time.c
+++ b/arch/m68k/hp300/time.c
@@ -31,9 +31,6 @@
 #defineCLKMSB2 0x9
 #defineCLKMSB3 0xD
 
-/* This is for machines which generate the exact clock. */
-#define USECS_PER_JIFFY (100/HZ)
-
 #define INTVAL ((1 / 4) - 1)
 
 static irqreturn_t hp300_tick(int irq, void *dev_id)
@@ -53,22 +50,6 @@ static irqreturn_t hp300_tick(int irq, void *dev_id)
return IRQ_HANDLED;
 }
 
-u32 hp300_gettimeoffset(void)
-{
-  /* Read current timer 1 value */
-  unsigned char lsb, msb1, msb2;
-  unsigned short ticks;
-
-  msb1 = in_8(CLOCKBASE + 5);
-  lsb = in_8(CLOCKBASE + 7);
-  msb2 = in_8(CLOCKBASE + 5);
-  if (msb1 != msb2)
-/* A carry happened while we were reading.  Read it again */
-lsb = in_8(CLOCKBASE + 7);
-  ticks = INTVAL - ((msb2 << 8) | lsb);
-  return ((USECS_PER_JIFFY * ticks) / INTVAL) * 1000;
-}
-
 void __init hp300_sched_init(irq_handler_t vector)
 {
   out_8(CLOCKBASE + CLKCR2, 0x1);  /* select CR1 */
-- 
2.18.1



[RFC PATCH v2 12/14] m68k: mvme147: Handle timer counter overflow

2018-11-18 Thread Finn Thain
Reading the timer counter races with timer overflow (and the
corresponding interrupt). This is resolved by reading the overflow
register and taking this value into account. The interrupt handler
must clear the overflow register when it eventually executes.

Suggested-by: Thomas Gleixner 
Signed-off-by: Finn Thain 
---
TODO: find a spare counter for the clocksource, rather than hanging
it off the HZ timer.
---
 arch/m68k/include/asm/mvme147hw.h |  1 +
 arch/m68k/mvme147/config.c| 23 +++
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/arch/m68k/include/asm/mvme147hw.h 
b/arch/m68k/include/asm/mvme147hw.h
index 7c3dd513128e..257b29184af9 100644
--- a/arch/m68k/include/asm/mvme147hw.h
+++ b/arch/m68k/include/asm/mvme147hw.h
@@ -66,6 +66,7 @@ struct pcc_regs {
 #define PCC_INT_ENAB   0x08
 
 #define PCC_TIMER_INT_CLR  0x80
+#define PCC_TIMER_CLR_OVF  0x04
 
 #define PCC_LEVEL_ABORT0x07
 #define PCC_LEVEL_SERIAL   0x04
diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
index 82b53b5ca82b..545a1fe0e119 100644
--- a/arch/m68k/mvme147/config.c
+++ b/arch/m68k/mvme147/config.c
@@ -118,7 +118,7 @@ static irqreturn_t mvme147_timer_int (int irq, void *dev_id)
 
local_irq_save(flags);
m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR;
-   m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1;
+   m147_pcc->t1_cntrl = PCC_TIMER_CLR_OVF;
clk_total += PCC_TIMER_CYCLES;
timer_routine(0, NULL);
local_irq_restore(flags);
@@ -144,23 +144,22 @@ void mvme147_sched_init (irq_handler_t timer_routine)
clocksource_register_hz(&mvme147_clk, PCC_TIMER_CLOCK_FREQ);
 }
 
-/* XXX There are race hazards in this code XXX */
 static u64 mvme147_read_clk(struct clocksource *cs)
 {
unsigned long flags;
-   volatile unsigned short *cp = (volatile unsigned short *)0xfffe1012;
-   unsigned short n;
+   u8 overflow, tmp;
+   u16 count;
u32 ticks;
 
local_irq_save(flags);
-
-   n = *cp;
-   while (n != *cp)
-   n = *cp;
-
-   n -= PCC_TIMER_PRELOAD;
-   ticks = clk_total + n;
-
+   tmp = m147_pcc->t1_cntrl >> 4;
+   count = m147_pcc->t1_count;
+   overflow = m147_pcc->t1_cntrl >> 4;
+   if (overflow != tmp)
+   count = m147_pcc->t1_count;
+   count -= PCC_TIMER_PRELOAD;
+   ticks = count + overflow * PCC_TIMER_CYCLES;
+   ticks += clk_total;
local_irq_restore(flags);
 
return ticks;
-- 
2.18.1



[RFC PATCH v2 02/14] m68k: mac: Fix VIA timer counter accesses

2018-11-18 Thread Finn Thain
This resolves some bugs that affect VIA timer counter accesses.
Avoid lost interrupts caused by reading the counter low byte register.
Make allowance for the fact that the counter will be decremented to
0x before being reloaded.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Finn Thain 
---
Changed since v1:
 - Test the timer interrupt flag unconditionally.
 - Drop some extraneous clean up.
 - Don't try to recover from lost timer interrupts. Don't lose them
in the first place. That means giving up on the timer counter low byte.
The extra precision is probably not worth the extra complexity and
I couldn't make it work anyway.
---
 arch/m68k/mac/via.c | 105 +++-
 1 file changed, 56 insertions(+), 49 deletions(-)

diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
index 2ab85b6eb4fe..d1dbf9017300 100644
--- a/arch/m68k/mac/via.c
+++ b/arch/m68k/mac/via.c
@@ -54,16 +54,6 @@ static __u8 rbv_clear;
 
 static int gIER,gIFR,gBufA,gBufB;
 
-/*
- * Timer defs.
- */
-
-#define TICK_SIZE  1
-#define MAC_CLOCK_TICK (783300/HZ) /* ticks per HZ */
-#define MAC_CLOCK_LOW  (MAC_CLOCK_TICK&0xFF)
-#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8)
-
-
 /*
  * On Macs with a genuine VIA chip there is no way to mask an individual slot
  * interrupt. This limitation also seems to apply to VIA clone logic cores in
@@ -267,22 +257,6 @@ void __init via_init(void)
}
 }
 
-/*
- * Start the 100 Hz clock
- */
-
-void __init via_init_clock(irq_handler_t func)
-{
-   via1[vACR] |= 0x40;
-   via1[vT1LL] = MAC_CLOCK_LOW;
-   via1[vT1LH] = MAC_CLOCK_HIGH;
-   via1[vT1CL] = MAC_CLOCK_LOW;
-   via1[vT1CH] = MAC_CLOCK_HIGH;
-
-   if (request_irq(IRQ_MAC_TIMER_1, func, 0, "timer", func))
-   pr_err("Couldn't register %s interrupt\n", "timer");
-}
-
 /*
  * Debugging dump, used in various places to see what's going on.
  */
@@ -310,29 +284,6 @@ void via_debug_dump(void)
}
 }
 
-/*
- * This is always executed with interrupts disabled.
- *
- * TBI: get time offset between scheduling timer ticks
- */
-
-u32 mac_gettimeoffset(void)
-{
-   unsigned long ticks, offset = 0;
-
-   /* read VIA1 timer 2 current value */
-   ticks = via1[vT1CL] | (via1[vT1CH] << 8);
-   /* The probability of underflow is less than 2% */
-   if (ticks > MAC_CLOCK_TICK - MAC_CLOCK_TICK / 50)
-   /* Check for pending timer interrupt in VIA1 IFR */
-   if (via1[vIFR] & 0x40) offset = TICK_SIZE;
-
-   ticks = MAC_CLOCK_TICK - ticks;
-   ticks = ticks * 1L / MAC_CLOCK_TICK;
-
-   return (ticks + offset) * 1000;
-}
-
 /*
  * Flush the L2 cache on Macs that have it by flipping
  * the system into 24-bit mode for an instant.
@@ -618,3 +569,59 @@ int via2_scsi_drq_pending(void)
return via2[gIFR] & (1 << IRQ_IDX(IRQ_MAC_SCSIDRQ));
 }
 EXPORT_SYMBOL(via2_scsi_drq_pending);
+
+/* timer and clock source */
+
+#define VIA_CLOCK_FREQ 783360/* VIA "phase 2" clock in Hz 
*/
+#define VIA_TIMER_INTERVAL (100 / HZ)/* microseconds per jiffy */
+#define VIA_TIMER_CYCLES   (VIA_CLOCK_FREQ / HZ) /* clock cycles per jiffy */
+
+#define VIA_TC (VIA_TIMER_CYCLES - 2) /* including 0 and -1 */
+#define VIA_TC_LOW (VIA_TC & 0xFF)
+#define VIA_TC_HIGH(VIA_TC >> 8)
+
+void __init via_init_clock(irq_handler_t timer_routine)
+{
+   if (request_irq(IRQ_MAC_TIMER_1, timer_routine, 0, "timer", NULL)) {
+   pr_err("Couldn't register %s interrupt\n", "timer");
+   return;
+   }
+
+   via1[vT1LL] = VIA_TC_LOW;
+   via1[vT1LH] = VIA_TC_HIGH;
+   via1[vT1CL] = VIA_TC_LOW;
+   via1[vT1CH] = VIA_TC_HIGH;
+   via1[vACR] |= 0x40;
+}
+
+u32 mac_gettimeoffset(void)
+{
+   unsigned long flags;
+   u8 count_high;
+   u16 count, offset = 0;
+
+   /*
+* Timer counter wrap-around is detected with the timer interrupt flag
+* but reading the counter low byte (vT1CL) would reset the flag.
+* Also, accessing both counter registers is essentially a data race.
+* These problems are avoided by ignoring the low byte. Clock accuracy
+* is 256 times worse (error can reach 0.327 ms) but CPU overhead is
+* reduced by avoiding slow VIA register accesses.
+*/
+
+   local_irq_save(flags);
+   count_high = via1[vT1CH];
+   if (count_high == 0xFF) {
+   count_high = 0;
+   while (via1[vT1CH] == 0xFF)
+   /* spin */;
+   }
+   if (via1[vIFR] & VIA_TIMER_1_INT)
+   offset = VIA_TIMER_CYCLES;
+   local_irq_restore(flags);
+
+   count = count_high << 8;
+   count = VIA_TIMER_CYCLES - count + offset;
+
+   return ((count * VIA_TIMER_INTERVAL) / VIA_TIMER_CYCLES) * 1000;
+}
-- 
2.18.1



[RFC PATCH v2 07/14] m68k: atari: Convert to clocksource API

2018-11-18 Thread Finn Thain
Add a platform clocksource by adapting the existing arch_gettimeoffset
implementation.

Normally the MFP timer C interrupt flag would be used to check for
timer counter wrap-around. Unfortunately, that flag gets cleared by the
MFP itself (due to automatic EOI mode). This means that
mfp_timer_c_handler() and atari_read_clk() must race when accounting
for counter wrap-around.

That problem is avoided here by effectively stopping the clock when it
might otherwise jump backwards. This harms clock accuracy; the result
is not much better than the jiffies clocksource. Also, clock error is
no longer uniformly distributed.

Signed-off-by: Finn Thain 
Acked-by: Linus Walleij 
---
TODO: find a spare counter for the clocksource, rather than hanging
it off the HZ timer.

It would be simpler to adopt the 'jiffies' clocksource here
(c.f. patch for the hp300 platform in this series).

Changed since v1:
 - Moved clk_total access to within the irq lock.
 - Renamed mfp_timer_handler and mfptimer_handler.
 - Avoid accessing the timer interrupt flag in atari_read_clk(). To
get monotonicity, keep track of the previous timer counter value.
---
 arch/m68k/atari/time.c | 48 +++---
 1 file changed, 31 insertions(+), 17 deletions(-)

diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c
index fafa20f75ab9..914832e55ec5 100644
--- a/arch/m68k/atari/time.c
+++ b/arch/m68k/atari/time.c
@@ -16,6 +16,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -24,12 +25,27 @@
 DEFINE_SPINLOCK(rtc_lock);
 EXPORT_SYMBOL_GPL(rtc_lock);
 
+static u64 atari_read_clk(struct clocksource *cs);
+
+static struct clocksource atari_clk = {
+   .name   = "mfp",
+   .rating = 100,
+   .read   = atari_read_clk,
+   .mask   = CLOCKSOURCE_MASK(32),
+   .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static u32 clk_total;
+static u32 last_timer_count;
+
 static irqreturn_t mfp_timer_c_handler(int irq, void *dev_id)
 {
irq_handler_t timer_routine = dev_id;
unsigned long flags;
 
local_irq_save(flags);
+   last_timer_count = st_mfp.tim_dt_c;
+   clk_total += INT_TICKS;
timer_routine(0, NULL);
local_irq_restore(flags);
 
@@ -44,32 +60,30 @@ atari_sched_init(irq_handler_t timer_routine)
 /* start timer C, div = 1:100 */
 st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60;
 /* install interrupt service routine for MFP Timer C */
-if (request_irq(IRQ_MFP_TIMC, mfp_timer_c_handler, 0, "timer",
+if (request_irq(IRQ_MFP_TIMC, mfp_timer_c_handler, IRQF_TIMER, "timer",
 timer_routine))
pr_err("Couldn't register timer interrupt\n");
+
+clocksource_register_hz(&atari_clk, INT_CLK);
 }
 
 /* ++andreas: gettimeoffset fixed to check for pending interrupt */
 
-#define TICK_SIZE 1
-
-/* This is always executed with interrupts disabled.  */
-u32 atari_gettimeoffset(void)
+static u64 atari_read_clk(struct clocksource *cs)
 {
-  u32 ticks, offset = 0;
-
-  /* read MFP timer C current value */
-  ticks = st_mfp.tim_dt_c;
-  /* The probability of underflow is less than 2% */
-  if (ticks > INT_TICKS - INT_TICKS / 50)
-/* Check for pending timer interrupt */
-if (st_mfp.int_pn_b & (1 << 5))
-  offset = TICK_SIZE;
+   unsigned long flags;
+   u32 ticks;
 
-  ticks = INT_TICKS - ticks;
-  ticks = ticks * 1L / INT_TICKS;
+   local_irq_save(flags);
+   ticks = st_mfp.tim_dt_c;
+   if (ticks > last_timer_count) /* timer wrapped since last interrupt */
+   ticks = last_timer_count;
+   last_timer_count = ticks;
+   ticks = INT_TICKS - ticks;
+   ticks += clk_total;
+   local_irq_restore(flags);
 
-  return (ticks + offset) * 1000;
+   return ticks;
 }
 
 
-- 
2.18.1



[RFC PATCH v2 14/14] m68k: mvme16x: Handle timer counter overflow

2018-11-18 Thread Finn Thain
Reading the timer counter races with timer overflow (and the
corresponding interrupt). This is resolved by reading the overflow
register and taking this value into account. The interrupt handler
must clear the overflow register when it eventually executes.

Suggested-by: Thomas Gleixner 
Signed-off-by: Finn Thain 
---
TODO: find a spare counter for the clocksource, rather than hanging
it off the HZ timer.
---
 arch/m68k/mvme16x/config.c | 45 +++---
 1 file changed, 32 insertions(+), 13 deletions(-)

diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
index 2c109ee2a1a5..9bc2da69f80c 100644
--- a/arch/m68k/mvme16x/config.c
+++ b/arch/m68k/mvme16x/config.c
@@ -115,11 +115,11 @@ static void __init mvme16x_init_IRQ (void)
m68k_setup_user_interrupt(VEC_USER, 192);
 }
 
-#define pcc2chip   ((volatile u_char *)0xfff42000)
-#define PccSCCMICR 0x1d
-#define PccSCCTICR 0x1e
-#define PccSCCRICR 0x1f
-#define PccTPIACKR 0x25
+#define PCC2CHIP   (0xfff42000)
+#define PCCSCCMICR (PCC2CHIP + 0x1d)
+#define PCCSCCTICR (PCC2CHIP + 0x1e)
+#define PCCSCCRICR (PCC2CHIP + 0x1f)
+#define PCCTPIACKR (PCC2CHIP + 0x25)
 
 #ifdef CONFIG_EARLY_PRINTK
 
@@ -227,10 +227,10 @@ void mvme16x_cons_write(struct console *co, const char 
*str, unsigned count)
base_addr[CyIER] = CyTxMpty;
 
while (1) {
-   if (pcc2chip[PccSCCTICR] & 0x20)
+   if (in_8(PCCSCCTICR) & 0x20)
{
/* We have a Tx int. Acknowledge it */
-   sink = pcc2chip[PccTPIACKR];
+   sink = in_8(PCCTPIACKR);
if ((base_addr[CyLICR] >> 2) == port) {
if (i == count) {
/* Last char of string is now output */
@@ -359,13 +359,26 @@ static u32 clk_total;
 #define PCC_TIMER_CLOCK_FREQ 100
 #define PCC_TIMER_CYCLES (PCC_TIMER_CLOCK_FREQ / HZ)
 
+#define PCCTCMP1 (PCC2CHIP + 0x04)
+#define PCCTCNT1 (PCC2CHIP + 0x08)
+#define PCCTOVR1 (PCC2CHIP + 0x17)
+#define PCCTIC1  (PCC2CHIP + 0x1b)
+
+#define PCCTOVR1_TIC_EN  0x01
+#define PCCTOVR1_COC_EN  0x02
+#define PCCTOVR1_OVR_CLR 0x04
+
+#define PCCTIC1_INT_CLR  0x08
+#define PCCTIC1_INT_EN   0x10
+
 static irqreturn_t mvme16x_timer_int (int irq, void *dev_id)
 {
irq_handler_t timer_routine = dev_id;
unsigned long flags;
 
local_irq_save(flags);
-   *(volatile unsigned char *)0xfff4201b |= 8;
+   out_8(PCCTIC1, in_8(PCCTIC1) | PCCTIC1_INT_CLR);
+   out_8(PCCTOVR1, PCCTOVR1_OVR_CLR);
clk_total += PCC_TIMER_CYCLES;
timer_routine(0, NULL);
local_irq_restore(flags);
@@ -379,10 +392,10 @@ void mvme16x_sched_init (irq_handler_t timer_routine)
 int irq;
 
 /* Using PCCchip2 or MC2 chip tick timer 1 */
-*(volatile unsigned long *)0xfff42008 = 0;
-*(volatile unsigned long *)0xfff42004 = PCC_TIMER_CYCLES;
-*(volatile unsigned char *)0xfff42017 |= 3;
-*(volatile unsigned char *)0xfff4201b = 0x16;
+out_be32(PCCTCNT1, 0);
+out_be32(PCCTCMP1, PCC_TIMER_CYCLES);
+out_8(PCCTOVR1, in_8(PCCTOVR1) | PCCTOVR1_TIC_EN | PCCTOVR1_COC_EN);
+out_8(PCCTIC1, PCCTIC1_INT_EN | 6);
 if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, IRQF_TIMER, "timer",
 timer_routine))
panic ("Couldn't register timer int");
@@ -401,10 +414,16 @@ void mvme16x_sched_init (irq_handler_t timer_routine)
 static u64 mvme16x_read_clk(struct clocksource *cs)
 {
unsigned long flags;
+   u8 overflow, tmp;
u32 ticks;
 
local_irq_save(flags);
-   ticks = *(volatile u32 *)0xfff42008;
+   tmp = in_8(PCCTOVR1) >> 4;
+   ticks = in_be32(PCCTCNT1);
+   overflow = in_8(PCCTOVR1) >> 4;
+   if (overflow != tmp)
+   ticks = in_be32(PCCTCNT1);
+   ticks += overflow * PCC_TIMER_CYCLES;
ticks += clk_total;
local_irq_restore(flags);
 
-- 
2.18.1



[RFC PATCH v2 10/14] m68k: mac: Convert to clocksource API

2018-11-18 Thread Finn Thain
Add a platform clocksource by adapting the existing arch_gettimeoffset
implementation.

Signed-off-by: Finn Thain 
Acked-by: Linus Walleij 
Tested-by: Stan Johnson 
---
Changed since v1:
 - Moved clk_total access to within the irq lock.
 - Use type u32 for tick counter.
---
 arch/m68k/mac/via.c | 46 -
 1 file changed, 37 insertions(+), 9 deletions(-)

diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
index d1dbf9017300..de59a5cb4250 100644
--- a/arch/m68k/mac/via.c
+++ b/arch/m68k/mac/via.c
@@ -23,6 +23,7 @@
  *
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -573,16 +574,40 @@ EXPORT_SYMBOL(via2_scsi_drq_pending);
 /* timer and clock source */
 
 #define VIA_CLOCK_FREQ 783360/* VIA "phase 2" clock in Hz 
*/
-#define VIA_TIMER_INTERVAL (100 / HZ)/* microseconds per jiffy */
 #define VIA_TIMER_CYCLES   (VIA_CLOCK_FREQ / HZ) /* clock cycles per jiffy */
 
 #define VIA_TC (VIA_TIMER_CYCLES - 2) /* including 0 and -1 */
 #define VIA_TC_LOW (VIA_TC & 0xFF)
 #define VIA_TC_HIGH(VIA_TC >> 8)
 
+static u64 mac_read_clk(struct clocksource *cs);
+
+static struct clocksource mac_clk = {
+   .name   = "via1",
+   .rating = 250,
+   .read   = mac_read_clk,
+   .mask   = CLOCKSOURCE_MASK(32),
+   .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static u32 clk_total;
+static u32 clk_offset;
+
+static irqreturn_t via_timer_handler(int irq, void *dev_id)
+{
+   irq_handler_t timer_routine = dev_id;
+
+   clk_total += VIA_TIMER_CYCLES;
+   clk_offset = 0;
+   timer_routine(0, NULL);
+
+   return IRQ_HANDLED;
+}
+
 void __init via_init_clock(irq_handler_t timer_routine)
 {
-   if (request_irq(IRQ_MAC_TIMER_1, timer_routine, 0, "timer", NULL)) {
+   if (request_irq(IRQ_MAC_TIMER_1, via_timer_handler, IRQF_TIMER, "timer",
+   timer_routine)) {
pr_err("Couldn't register %s interrupt\n", "timer");
return;
}
@@ -592,13 +617,16 @@ void __init via_init_clock(irq_handler_t timer_routine)
via1[vT1CL] = VIA_TC_LOW;
via1[vT1CH] = VIA_TC_HIGH;
via1[vACR] |= 0x40;
+
+   clocksource_register_hz(&mac_clk, VIA_CLOCK_FREQ);
 }
 
-u32 mac_gettimeoffset(void)
+static u64 mac_read_clk(struct clocksource *cs)
 {
unsigned long flags;
u8 count_high;
-   u16 count, offset = 0;
+   u16 count;
+   u32 ticks;
 
/*
 * Timer counter wrap-around is detected with the timer interrupt flag
@@ -617,11 +645,11 @@ u32 mac_gettimeoffset(void)
/* spin */;
}
if (via1[vIFR] & VIA_TIMER_1_INT)
-   offset = VIA_TIMER_CYCLES;
-   local_irq_restore(flags);
-
+   clk_offset = VIA_TIMER_CYCLES;
count = count_high << 8;
-   count = VIA_TIMER_CYCLES - count + offset;
+   ticks = VIA_TIMER_CYCLES - count;
+   ticks += clk_offset + clk_total;
+   local_irq_restore(flags);
 
-   return ((count * VIA_TIMER_INTERVAL) / VIA_TIMER_CYCLES) * 1000;
+   return ticks;
 }
-- 
2.18.1



[RFC PATCH v2 03/14] m68k: mac: Clean up unused timer definitions

2018-11-18 Thread Finn Thain
Signed-off-by: Finn Thain 
---
 arch/m68k/include/asm/macints.h | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/arch/m68k/include/asm/macints.h b/arch/m68k/include/asm/macints.h
index cddb2d3ea49b..4da172bd048c 100644
--- a/arch/m68k/include/asm/macints.h
+++ b/arch/m68k/include/asm/macints.h
@@ -121,7 +121,4 @@
 #define SLOT2IRQ(x)  (x + 47)
 #define IRQ2SLOT(x)  (x - 47)
 
-#define INT_CLK   24576/* CLK while int_clk =2.456MHz and divide = 
100 */
-#define INT_TICKS 246  /* to make sched_time = 99.902... HZ */
-
 #endif /* asm/macints.h */
-- 
2.18.1



[RFC PATCH v2 06/14] m68k: amiga: Convert to clocksource API

2018-11-18 Thread Finn Thain
Add a platform clocksource by adapting the existing arch_gettimeoffset
implementation.

Signed-off-by: Finn Thain 
Acked-by: Linus Walleij 
---
Changed since v1:
 - Moved clk_total access to within the irq lock.
---
 arch/m68k/amiga/config.c | 43 
 1 file changed, 35 insertions(+), 8 deletions(-)

diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index d4976c1aa0cc..c498f8419c87 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -17,6 +17,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -461,7 +462,28 @@ void __init config_amiga(void)
*(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80;
 }
 
+static u64 amiga_read_clk(struct clocksource *cs);
+
+static struct clocksource amiga_clk = {
+   .name   = "ciab",
+   .rating = 250,
+   .read   = amiga_read_clk,
+   .mask   = CLOCKSOURCE_MASK(32),
+   .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
 static unsigned short jiffy_ticks;
+static u32 clk_total;
+
+static irqreturn_t ciab_timer_handler(int irq, void *dev_id)
+{
+   irq_handler_t timer_routine = dev_id;
+
+   clk_total += jiffy_ticks;
+   timer_routine(0, NULL);
+
+   return IRQ_HANDLED;
+}
 
 static void __init amiga_sched_init(irq_handler_t timer_routine)
 {
@@ -481,20 +503,23 @@ static void __init amiga_sched_init(irq_handler_t 
timer_routine)
 * Please don't change this to use ciaa, as it interferes with the
 * SCSI code. We'll have to take a look at this later
 */
-   if (request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, 0, "timer", NULL))
+   if (request_irq(IRQ_AMIGA_CIAB_TA, ciab_timer_handler, IRQF_TIMER,
+   "timer", timer_routine))
pr_err("Couldn't register timer interrupt\n");
/* start timer */
ciab.cra |= 0x11;
-}
 
-#define TICK_SIZE 1
+   clocksource_register_hz(&amiga_clk, amiga_eclock);
+}
 
-/* This is always executed with interrupts disabled.  */
-static u32 amiga_gettimeoffset(void)
+static u64 amiga_read_clk(struct clocksource *cs)
 {
+   unsigned long flags;
unsigned short hi, lo, hi2;
u32 ticks, offset = 0;
 
+   local_irq_save(flags);
+
/* read CIA B timer A current value */
hi  = ciab.tahi;
lo  = ciab.talo;
@@ -510,12 +535,14 @@ static u32 amiga_gettimeoffset(void)
if (ticks > jiffy_ticks / 2)
/* check for pending interrupt */
if (cia_set_irq(&ciab_base, 0) & CIA_ICR_TA)
-   offset = 1;
+   offset = jiffy_ticks;
 
ticks = jiffy_ticks - ticks;
-   ticks = (1 * ticks) / jiffy_ticks;
+   ticks += offset + clk_total;
+
+   local_irq_restore(flags);
 
-   return (ticks + offset) * 1000;
+   return ticks;
 }
 
 static void amiga_reset(void)  __noreturn;
-- 
2.18.1



[RFC PATCH v2 00/14] m68k: Drop arch_gettimeoffset and adopt clocksource API

2018-11-18 Thread Finn Thain
This series removes "select ARCH_USES_GETTIMEOFFSET" from arch/m68k
and converts users of arch_gettimeoffset to the clocksource API.
Various bugs are fixed along the way.

Those platforms which do not actually implement arch_gettimeoffset
(apollo, q40, sun3, sun3x) use the "jiffies" clocksource by default.

The atari and hp300 platforms have an arch_gettimeoffset() implementation
which can't readily be converted to a clocksource. Getting a workable
clocksource on these platforms will require the insight of a platform
expert.

The difficulty with these patches is the use of the timer interrupt to
update the counter for the clock source. The timer interrupt handler races
with clocksource read method, and both of those functions race with the
timer hardware.

Hence, more testing and code review would be appreciated.

Changed since v1:

 - Dropped patches 1/13 and 2/13. These were a failed attempt to fix
5cfc8ee0bb51 and 4ad4c76b7afb. By adopting the clocksource API we can fix
this issue in mainline. By backporting this series we can fix it for -stable
(for m68k at least).

 - Dropped patch "m68k: hp300: Convert to clocksource API" and added
patch "m68k: hp300: Remove hp300_gettimeoffset".

 - Added a new patch to address an old m68k bug pointed out by Thomas
Gleixner. The bug can arise when a timer interrupt handler gets interrupted.

 - Added new patches to address old mvme16x and mvme147 bugs pointed out
by Thomas Gleixner. The bug could cause the clock to jump backwards.

 - Various other changes summarized in the relevant patches.


Finn Thain (14):
  m68k: Call timer_interrupt() with interrupts disabled
  m68k: mac: Fix VIA timer counter accesses
  m68k: mac: Clean up unused timer definitions
  m68k: apollo, q40, sun3, sun3x: Remove arch_gettimeoffset
implementations
  m68k: Drop ARCH_USES_GETTIMEOFFSET
  m68k: amiga: Convert to clocksource API
  m68k: atari: Convert to clocksource API
  m68k: bvme6000: Convert to clocksource API
  m68k: hp300: Remove hp300_gettimeoffset()
  m68k: mac: Convert to clocksource API
  m68k: mvme147: Convert to clocksource API
  m68k: mvme147: Handle timer counter overflow
  m68k: mvme16x: Convert to clocksource API
  m68k: mvme16x: Handle timer counter overflow

 arch/m68k/Kconfig |   1 -
 arch/m68k/amiga/cia.c |  10 ++
 arch/m68k/amiga/config.c  |  46 ++---
 arch/m68k/apollo/config.c |   7 --
 arch/m68k/atari/ataints.c |   4 +-
 arch/m68k/atari/config.c  |   2 -
 arch/m68k/atari/time.c|  65 +
 arch/m68k/bvme6000/config.c   |  70 +-
 arch/m68k/hp300/config.c  |   1 -
 arch/m68k/hp300/time.c|  29 ++
 arch/m68k/hp300/time.h|   1 -
 arch/m68k/include/asm/macints.h   |   3 -
 arch/m68k/include/asm/mvme147hw.h |   2 +-
 arch/m68k/mac/config.c|   3 -
 arch/m68k/mac/via.c   | 150 --
 arch/m68k/mvme147/config.c|  73 ++-
 arch/m68k/mvme16x/config.c|  97 +--
 arch/m68k/q40/config.c|   9 --
 arch/m68k/q40/q40ints.c   |   7 +-
 arch/m68k/sun3/config.c   |   2 -
 arch/m68k/sun3/intersil.c |   7 --
 arch/m68k/sun3/sun3ints.c |   3 +
 arch/m68k/sun3x/config.c  |   1 -
 arch/m68k/sun3x/time.c|  21 ++---
 arch/m68k/sun3x/time.h|   1 -
 25 files changed, 387 insertions(+), 228 deletions(-)

-- 
2.18.1



Re: m68k using deprecated internal APIs?

2018-11-18 Thread Geert Uytterhoeven
Hi Linus,

On Fri, Nov 16, 2018 at 10:33 PM Linus Walleij  wrote:
> On Fri, Nov 16, 2018 at 8:44 PM Geert Uytterhoeven  
> wrote:
> > On Fri, Nov 16, 2018 at 12:13 PM Linus Walleij  
> > wrote:
> > > I mean that whole thing should go away by abstracting those LEDs
> > > (for the systems that have them) using the struct led_classdev,
> > > populating a proper platform device for it and instantiate using
> > > a driver in drivers/leds/*, and the function to provide the heartbeat
> > > be replaced with the existing heartbeat trigger in
> > > drivers/leds/trigger/ledtrig-heartbeat.c assigned as default
> > > trigger for that LED.
> > >
> > > I think that is WAY out of the focus for your current work (which,
> > > by the way, is a piece of art) but more something for the m68k
> > > maintainers to look into.
> >
> > Just going with struct led_classdev is probably doable.
>
> Would be nice.
>
> > Going for the full monty, using leds-gpio, probably requires moving m68k
> > to DT.  Which would not be that ... uninteresting ;-)
>
> If the line with the LED is not general purpose but an actual register
> bit for the LED it should not be using legs-gpio anyway.

On Amiga, the line is connected to a CIA.
In modern parlor, that would be a system-controller, providing a GPIO
controller, SPI (microwire) controller, clock controller, clock source,
two clock events, and an interrupt controller.

> But something similar to Russells neat drivers/gpio/gpio-reg.c
> but for LED classdevs in drivers/leds/leds-reg.c would be
> a really tempting option I think.

Thanks, I'll have a look...

Gr{oetje,eeting}s,

Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- ge...@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds