2019-05-19 20:08:55 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2012-01-23 14:23:33 +08:00
|
|
|
/*
|
|
|
|
* linux/arch/m68k/kernel/time.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
|
|
|
|
*
|
|
|
|
* This file contains the m68k-specific time handling details.
|
|
|
|
* Most of the stuff is located in the machine specific files.
|
|
|
|
*
|
|
|
|
* 1997-09-10 Updated NTP code according to technical memorandum Jan '96
|
|
|
|
* "A Kernel Model for Precision Timekeeping" by Dave Mills
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/errno.h>
|
2014-07-11 00:03:17 +08:00
|
|
|
#include <linux/export.h>
|
2012-01-23 14:23:33 +08:00
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/sched.h>
|
2017-02-08 15:45:17 +08:00
|
|
|
#include <linux/sched/loadavg.h>
|
2012-01-23 14:23:33 +08:00
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/param.h>
|
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/rtc.h>
|
|
|
|
#include <linux/platform_device.h>
|
|
|
|
|
|
|
|
#include <asm/machdep.h>
|
|
|
|
#include <asm/io.h>
|
|
|
|
#include <asm/irq_regs.h>
|
|
|
|
|
|
|
|
#include <linux/time.h>
|
|
|
|
#include <linux/timex.h>
|
|
|
|
#include <linux/profile.h>
|
|
|
|
|
2013-10-18 19:10:08 +08:00
|
|
|
|
|
|
|
unsigned long (*mach_random_get_entropy)(void);
|
2014-07-11 00:03:17 +08:00
|
|
|
EXPORT_SYMBOL_GPL(mach_random_get_entropy);
|
2013-10-18 19:10:08 +08:00
|
|
|
|
|
|
|
|
2012-01-23 14:23:33 +08:00
|
|
|
/*
|
|
|
|
* timer_interrupt() needs to keep up the real-time clock,
|
|
|
|
* as well as call the "xtime_update()" routine every clocktick
|
|
|
|
*/
|
|
|
|
static irqreturn_t timer_interrupt(int irq, void *dummy)
|
|
|
|
{
|
|
|
|
xtime_update(1);
|
|
|
|
update_process_times(user_mode(get_irq_regs()));
|
|
|
|
profile_tick(CPU_PROFILING);
|
|
|
|
|
|
|
|
#ifdef CONFIG_HEARTBEAT
|
|
|
|
/* use power LED as a heartbeat instead -- much more useful
|
|
|
|
for debugging -- based on the version for PReP by Cort */
|
|
|
|
/* acts like an actual heart beat -- ie thump-thump-pause... */
|
|
|
|
if (mach_heartbeat) {
|
|
|
|
static unsigned cnt = 0, period = 0, dist = 0;
|
|
|
|
|
|
|
|
if (cnt == 0 || cnt == dist)
|
|
|
|
mach_heartbeat( 1 );
|
|
|
|
else if (cnt == 7 || cnt == dist+7)
|
|
|
|
mach_heartbeat( 0 );
|
|
|
|
|
|
|
|
if (++cnt > period) {
|
|
|
|
cnt = 0;
|
|
|
|
/* The hyperbolic function below modifies the heartbeat period
|
|
|
|
* length in dependency of the current (5min) load. It goes
|
|
|
|
* through the points f(0)=126, f(1)=86, f(5)=51,
|
|
|
|
* f(inf)->30. */
|
|
|
|
period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
|
|
|
|
dist = period / 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_HEARTBEAT */
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
}
|
|
|
|
|
2018-04-23 16:52:28 +08:00
|
|
|
#ifdef CONFIG_M68KCLASSIC
|
|
|
|
#if !IS_BUILTIN(CONFIG_RTC_DRV_GENERIC)
|
|
|
|
void read_persistent_clock64(struct timespec64 *ts)
|
2012-01-23 14:23:33 +08:00
|
|
|
{
|
|
|
|
struct rtc_time time;
|
m68k: Fix off-by-one calendar month
This fixes a bug in read_persistent_clock() which causes the system
clock to lag the Real Time Clock by one month. The problem was noticed
on a Mac, but theoretically it must also affect Atari, BVME6000 and Q40.
The tm_mon value in the struct rtc_time passed to mach_hwclk() is
zero-based, and atari_mste_hwclk(), atari_tt_hwclk(), bvme6000_hwclk(),
mac_hwclk() and q40_hwclk() all make this adjustment. Unfortunately,
dn_dummy_hwclk(), mvme147_hwclk(), mvme16x_hwclk(), sun3_hwclk() and
sun3x_hwclk() fail to decrement tm_mon. Also m68328_hwclk() assumes
a one-based tm_mon.
Bring these platforms into line and fix read_persistent_clock() so it
works correctly on all m68k platforms.
The datasheets for the RTC devices found on the affected platforms
all confirm that the year is stored as a value in the range 0-99 and
the month is stored as a value in the range 1-12. Please refer to the
datasheets for MC146818 (Apollo), DS1643 (MVME), ICM7170 (Sun 3)
and M48T02 (Sun 3x).
Reported-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
2018-04-23 09:02:57 +08:00
|
|
|
|
2012-01-23 14:23:33 +08:00
|
|
|
ts->tv_sec = 0;
|
|
|
|
ts->tv_nsec = 0;
|
|
|
|
|
m68k: Fix off-by-one calendar month
This fixes a bug in read_persistent_clock() which causes the system
clock to lag the Real Time Clock by one month. The problem was noticed
on a Mac, but theoretically it must also affect Atari, BVME6000 and Q40.
The tm_mon value in the struct rtc_time passed to mach_hwclk() is
zero-based, and atari_mste_hwclk(), atari_tt_hwclk(), bvme6000_hwclk(),
mac_hwclk() and q40_hwclk() all make this adjustment. Unfortunately,
dn_dummy_hwclk(), mvme147_hwclk(), mvme16x_hwclk(), sun3_hwclk() and
sun3x_hwclk() fail to decrement tm_mon. Also m68328_hwclk() assumes
a one-based tm_mon.
Bring these platforms into line and fix read_persistent_clock() so it
works correctly on all m68k platforms.
The datasheets for the RTC devices found on the affected platforms
all confirm that the year is stored as a value in the range 0-99 and
the month is stored as a value in the range 1-12. Please refer to the
datasheets for MC146818 (Apollo), DS1643 (MVME), ICM7170 (Sun 3)
and M48T02 (Sun 3x).
Reported-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
2018-04-23 09:02:57 +08:00
|
|
|
if (!mach_hwclk)
|
|
|
|
return;
|
2012-01-23 14:23:33 +08:00
|
|
|
|
m68k: Fix off-by-one calendar month
This fixes a bug in read_persistent_clock() which causes the system
clock to lag the Real Time Clock by one month. The problem was noticed
on a Mac, but theoretically it must also affect Atari, BVME6000 and Q40.
The tm_mon value in the struct rtc_time passed to mach_hwclk() is
zero-based, and atari_mste_hwclk(), atari_tt_hwclk(), bvme6000_hwclk(),
mac_hwclk() and q40_hwclk() all make this adjustment. Unfortunately,
dn_dummy_hwclk(), mvme147_hwclk(), mvme16x_hwclk(), sun3_hwclk() and
sun3x_hwclk() fail to decrement tm_mon. Also m68328_hwclk() assumes
a one-based tm_mon.
Bring these platforms into line and fix read_persistent_clock() so it
works correctly on all m68k platforms.
The datasheets for the RTC devices found on the affected platforms
all confirm that the year is stored as a value in the range 0-99 and
the month is stored as a value in the range 1-12. Please refer to the
datasheets for MC146818 (Apollo), DS1643 (MVME), ICM7170 (Sun 3)
and M48T02 (Sun 3x).
Reported-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
2018-04-23 09:02:57 +08:00
|
|
|
mach_hwclk(0, &time);
|
|
|
|
|
2018-04-23 16:52:28 +08:00
|
|
|
ts->tv_sec = mktime64(time.tm_year + 1900, time.tm_mon + 1, time.tm_mday,
|
|
|
|
time.tm_hour, time.tm_min, time.tm_sec);
|
2012-01-23 14:23:33 +08:00
|
|
|
}
|
2018-04-23 16:52:28 +08:00
|
|
|
#endif
|
2012-01-23 14:23:33 +08:00
|
|
|
|
2018-04-23 16:52:28 +08:00
|
|
|
#if IS_ENABLED(CONFIG_RTC_DRV_GENERIC)
|
2016-05-31 02:57:57 +08:00
|
|
|
static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm)
|
|
|
|
{
|
|
|
|
mach_hwclk(0, tm);
|
2018-02-22 05:37:24 +08:00
|
|
|
return 0;
|
2016-05-31 02:57:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int rtc_generic_set_time(struct device *dev, struct rtc_time *tm)
|
|
|
|
{
|
|
|
|
if (mach_hwclk(1, tm) < 0)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-05-31 02:57:58 +08:00
|
|
|
static int rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct rtc_pll_info pll;
|
|
|
|
struct rtc_pll_info __user *argp = (void __user *)arg;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case RTC_PLL_GET:
|
|
|
|
if (!mach_get_rtc_pll || mach_get_rtc_pll(&pll))
|
|
|
|
return -EINVAL;
|
|
|
|
return copy_to_user(argp, &pll, sizeof pll) ? -EFAULT : 0;
|
|
|
|
|
|
|
|
case RTC_PLL_SET:
|
|
|
|
if (!mach_set_rtc_pll)
|
|
|
|
return -EINVAL;
|
|
|
|
if (!capable(CAP_SYS_TIME))
|
|
|
|
return -EACCES;
|
|
|
|
if (copy_from_user(&pll, argp, sizeof(pll)))
|
|
|
|
return -EFAULT;
|
|
|
|
return mach_set_rtc_pll(&pll);
|
|
|
|
}
|
|
|
|
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
}
|
|
|
|
|
2016-05-31 02:57:57 +08:00
|
|
|
static const struct rtc_class_ops generic_rtc_ops = {
|
2016-05-31 02:57:58 +08:00
|
|
|
.ioctl = rtc_ioctl,
|
2016-05-31 02:57:57 +08:00
|
|
|
.read_time = rtc_generic_get_time,
|
|
|
|
.set_time = rtc_generic_set_time,
|
|
|
|
};
|
2012-01-23 14:23:33 +08:00
|
|
|
|
|
|
|
static int __init rtc_init(void)
|
|
|
|
{
|
|
|
|
struct platform_device *pdev;
|
|
|
|
|
|
|
|
if (!mach_hwclk)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2016-05-31 02:57:57 +08:00
|
|
|
pdev = platform_device_register_data(NULL, "rtc-generic", -1,
|
|
|
|
&generic_rtc_ops,
|
|
|
|
sizeof(generic_rtc_ops));
|
2013-07-15 09:50:32 +08:00
|
|
|
return PTR_ERR_OR_ZERO(pdev);
|
2012-01-23 14:23:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
module_init(rtc_init);
|
2018-04-23 16:52:28 +08:00
|
|
|
#endif /* CONFIG_RTC_DRV_GENERIC */
|
|
|
|
#endif /* CONFIG M68KCLASSIC */
|
time: convert arch_gettimeoffset to a pointer
Currently, whenever CONFIG_ARCH_USES_GETTIMEOFFSET is enabled, each
arch core provides a single implementation of arch_gettimeoffset(). In
many cases, different sub-architectures, different machines, or
different timer providers exist, and so the arch ends up implementing
arch_gettimeoffset() as a call-through-pointer anyway. Examples are
ARM, Cris, M68K, and it's arguable that the remaining architectures,
M32R and Blackfin, should be doing this anyway.
Modify arch_gettimeoffset so that it itself is a function pointer, which
the arch initializes. This will allow later changes to move the
initialization of this function into individual machine support or timer
drivers. This is particularly useful for code in drivers/clocksource
which should rely on an arch-independant mechanism to register their
implementation of arch_gettimeoffset().
This patch also converts the Cris architecture to set arch_gettimeoffset
directly to the final implementation in time_init(), because Cris already
had separate time_init() functions per sub-architecture. M68K and ARM
are converted to set arch_gettimeoffset to the final implementation in
later patches, because they already have function pointers in place for
this purpose.
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: Mikael Starvik <starvik@axis.com>
Cc: Hirokazu Takata <takata@linux-m32r.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Jesper Nilsson <jesper.nilsson@axis.com>
Acked-by: John Stultz <johnstul@us.ibm.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2012-11-08 08:58:54 +08:00
|
|
|
|
|
|
|
void __init time_init(void)
|
|
|
|
{
|
|
|
|
mach_sched_init(timer_interrupt);
|
|
|
|
}
|