* [RFD] Time rework [take #2]
@ 2007-06-14 10:19 Franck Bui-Huu
2007-06-14 10:19 ` [PATCH 1/5] Use generic NTP code for all MIPS platforms Franck Bui-Huu
` (4 more replies)
0 siblings, 5 replies; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-14 10:19 UTC (permalink / raw)
To: linux-mips
OK, I don't get any feedbacks since my original post but I had time to
make some changes...
It's now based on "linux-2.6.22-rc4-357-g7518784", with a part of Ralf's
linux-time patches.
I'd like to port some 'interesting' platforms as a proof of
concept. Could anybody name them ? I'd like to port a platform that
uses the 'hpt' as clock source and timer. A second one that uses the
hpt only as a timer, and a third one that doesn't uses it at all. A
small description can help too...
Thanks
Franck
---
arch/mips/Kconfig | 13 +
arch/mips/au1000/common/irq.c | 3 +-
arch/mips/au1000/common/setup.c | 2 -
arch/mips/au1000/common/time.c | 44 ---
arch/mips/basler/excite/excite_setup.c | 5 +-
arch/mips/ddb5xxx/common/rtc_ds1386.c | 10 +-
arch/mips/ddb5xxx/ddb5477/setup.c | 4 +-
arch/mips/dec/setup.c | 4 -
arch/mips/dec/time.c | 12 +-
arch/mips/emma2rh/markeins/setup.c | 4 +-
arch/mips/gt64120/wrppmc/setup.c | 4 -
arch/mips/gt64120/wrppmc/time.c | 2 +-
arch/mips/jmr3927/rbhma3100/setup.c | 4 +-
arch/mips/kernel/Makefile | 2 +
arch/mips/kernel/hpt.c | 294 ++++++++++++++++++
arch/mips/kernel/process.c | 2 +
arch/mips/kernel/smp.c | 1 +
arch/mips/kernel/smtc.c | 2 +-
arch/mips/kernel/time.c | 468 ++--------------------------
arch/mips/lasat/ds1603.c | 6 +-
arch/mips/lasat/ds1603.h | 2 -
arch/mips/lasat/setup.c | 6 +-
arch/mips/lasat/sysctl.c | 59 ----
arch/mips/lib/Makefile | 2 +-
arch/mips/lib/time.c | 52 ++++
arch/mips/mips-boards/atlas/atlas_setup.c | 5 -
arch/mips/mips-boards/generic/time.c | 101 +------
arch/mips/mips-boards/malta/malta_setup.c | 4 -
arch/mips/mips-boards/sead/sead_setup.c | 3 -
arch/mips/mips-boards/sim/sim_setup.c | 3 -
arch/mips/mips-boards/sim/sim_time.c | 72 +-----
arch/mips/momentum/ocelot_3/setup.c | 12 +-
arch/mips/momentum/ocelot_c/setup.c | 15 +-
arch/mips/philips/pnx8550/common/setup.c | 3 -
arch/mips/philips/pnx8550/common/time.c | 7 +-
arch/mips/pmc-sierra/yosemite/setup.c | 18 +-
arch/mips/sgi-ip22/ip22-int.c | 3 +-
arch/mips/sgi-ip22/ip22-setup.c | 2 -
arch/mips/sgi-ip22/ip22-time.c | 25 +--
arch/mips/sgi-ip27/ip27-init.c | 3 -
arch/mips/sgi-ip27/ip27-timer.c | 24 +--
arch/mips/sgi-ip32/ip32-setup.c | 12 +-
arch/mips/sibyte/bcm1480/time.c | 13 +-
arch/mips/sibyte/sb1250/time.c | 13 +-
arch/mips/sibyte/swarm/setup.c | 48 +++-
arch/mips/sibyte/swarm/time.c | 244 ---------------
arch/mips/sni/a20r.c | 1 -
arch/mips/sni/ds1216.c | 4 +-
arch/mips/sni/pcimt.c | 3 -
arch/mips/sni/pcit.c | 3 -
arch/mips/sni/rm200.c | 2 -
arch/mips/sni/time.c | 2 +-
arch/mips/tx4927/common/tx4927_setup.c | 9 +-
arch/mips/tx4938/common/rtc_rx5c348.c | 10 +-
arch/mips/tx4938/common/setup.c | 9 -
arch/mips/tx4938/toshiba_rbtx4938/setup.c | 4 +-
arch/mips/vr41xx/common/init.c | 8 +-
include/asm-mips/hpt.h | 16 +
include/asm-mips/rtc.h | 6 +-
include/asm-mips/time.h | 51 +---
60 files changed, 516 insertions(+), 1249 deletions(-)
create mode 100644 arch/mips/kernel/hpt.c
create mode 100644 arch/mips/lib/time.c
delete mode 100644 arch/mips/sibyte/swarm/time.c
create mode 100644 include/asm-mips/hpt.h
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH 1/5] Use generic NTP code for all MIPS platforms
2007-06-14 10:19 [RFD] Time rework [take #2] Franck Bui-Huu
@ 2007-06-14 10:19 ` Franck Bui-Huu
2007-06-14 10:19 ` [PATCH 2/5] Remove unused time.c for swarm Franck Bui-Huu
` (3 subsequent siblings)
4 siblings, 0 replies; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-14 10:19 UTC (permalink / raw)
To: linux-mips; +Cc: Ralf Baechle
From: Ralf Baechle <ralf@linux-mips.org>
---
arch/mips/Kconfig | 4 ++++
arch/mips/kernel/time.c | 24 ++++--------------------
arch/mips/sgi-ip27/ip27-timer.c | 18 ------------------
3 files changed, 8 insertions(+), 38 deletions(-)
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index da253bc..7bcf38d 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -723,6 +723,10 @@ config GENERIC_TIME
bool
default y
+config GENERIC_CMOS_UPDATE
+ bool
+ default y
+
config SCHED_NO_NO_OMIT_FRAME_POINTER
bool
default y
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 7def1ff..376e127 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -66,6 +66,10 @@ unsigned long (*rtc_mips_get_time)(void) = null_rtc_get_time;
int (*rtc_mips_set_time)(unsigned long) = null_rtc_set_time;
int (*rtc_mips_set_mmss)(unsigned long);
+int update_persistent_clock(struct timespec now)
+{
+ return rtc_mips_set_mmss(now.tv_sec);
+}
/* how many counter cycles in a jiffy */
static unsigned long cycles_per_jiffy __read_mostly;
@@ -124,9 +128,6 @@ static void __init c0_hpt_timer_init(void)
int (*mips_timer_state)(void);
void (*mips_timer_ack)(void);
-/* last time when xtime and rtc are sync'ed up */
-static long last_rtc_update;
-
/*
* local_timer_interrupt() does profiling and process accounting
* on a per-CPU basis.
@@ -158,23 +159,6 @@ irqreturn_t timer_interrupt(int irq, void *dev_id)
*/
do_timer(1);
- /*
- * If we have an externally synchronized Linux clock, then update
- * CMOS clock accordingly every ~11 minutes. rtc_mips_set_time() has to be
- * called as close as possible to 500 ms before the new second starts.
- */
- if (ntp_synced() &&
- xtime.tv_sec > last_rtc_update + 660 &&
- (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
- (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
- if (rtc_mips_set_mmss(xtime.tv_sec) == 0) {
- last_rtc_update = xtime.tv_sec;
- } else {
- /* do it again in 60 s */
- last_rtc_update = xtime.tv_sec - 600;
- }
- }
-
write_sequnlock(&xtime_lock);
/*
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c
index 8c3c78c..3134616 100644
--- a/arch/mips/sgi-ip27/ip27-timer.c
+++ b/arch/mips/sgi-ip27/ip27-timer.c
@@ -40,7 +40,6 @@
#define TICK_SIZE (tick_nsec / 1000)
static unsigned long ct_cur[NR_CPUS]; /* What counter should be at next timer irq */
-static long last_rtc_update; /* Last time the rtc clock got updated */
#if 0
static int set_rtc_mmss(unsigned long nowtime)
@@ -113,23 +112,6 @@ again:
update_process_times(user_mode(get_irq_regs()));
- /*
- * If we have an externally synchronized Linux clock, then update
- * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
- * called as close as possible to when a second starts.
- */
- if (ntp_synced() &&
- xtime.tv_sec > last_rtc_update + 660 &&
- (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
- (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
- if (rtc_mips_set_time(xtime.tv_sec) == 0) {
- last_rtc_update = xtime.tv_sec;
- } else {
- last_rtc_update = xtime.tv_sec - 600;
- /* do it again in 60 s */
- }
- }
-
write_sequnlock(&xtime_lock);
irq_exit();
}
--
1.5.2.1
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH 2/5] Remove unused time.c for swarm
2007-06-14 10:19 [RFD] Time rework [take #2] Franck Bui-Huu
2007-06-14 10:19 ` [PATCH 1/5] Use generic NTP code for all MIPS platforms Franck Bui-Huu
@ 2007-06-14 10:19 ` Franck Bui-Huu
2007-06-14 10:19 ` [PATCH 3/5] Deforest the function pointer jungle in the time code Franck Bui-Huu
` (2 subsequent siblings)
4 siblings, 0 replies; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-14 10:19 UTC (permalink / raw)
To: linux-mips; +Cc: Yoichi Yuasa
From: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
---
arch/mips/sibyte/swarm/time.c | 244 -----------------------------------------
1 files changed, 0 insertions(+), 244 deletions(-)
delete mode 100644 arch/mips/sibyte/swarm/time.c
diff --git a/arch/mips/sibyte/swarm/time.c b/arch/mips/sibyte/swarm/time.c
deleted file mode 100644
index 97c73c7..0000000
--- a/arch/mips/sibyte/swarm/time.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright (C) 2000, 2001 Broadcom Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- * Time routines for the swarm board. We pass all the hard stuff
- * through to the sb1250 handling code. Only thing we really keep
- * track of here is what time of day we think it is. And we don't
- * really even do a good job of that...
- */
-
-
-#include <linux/bcd.h>
-#include <linux/init.h>
-#include <linux/time.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <asm/system.h>
-#include <asm/addrspace.h>
-#include <asm/io.h>
-
-#include <asm/sibyte/sb1250.h>
-#include <asm/sibyte/sb1250_regs.h>
-#include <asm/sibyte/sb1250_smbus.h>
-
-static unsigned long long sec_bias = 0;
-static unsigned int usec_bias = 0;
-
-/* Xicor 1241 definitions */
-
-/*
- * Register bits
- */
-
-#define X1241REG_SR_BAT 0x80 /* currently on battery power */
-#define X1241REG_SR_RWEL 0x04 /* r/w latch is enabled, can write RTC */
-#define X1241REG_SR_WEL 0x02 /* r/w latch is unlocked, can enable r/w now */
-#define X1241REG_SR_RTCF 0x01 /* clock failed */
-#define X1241REG_BL_BP2 0x80 /* block protect 2 */
-#define X1241REG_BL_BP1 0x40 /* block protect 1 */
-#define X1241REG_BL_BP0 0x20 /* block protect 0 */
-#define X1241REG_BL_WD1 0x10
-#define X1241REG_BL_WD0 0x08
-#define X1241REG_HR_MIL 0x80 /* military time format */
-
-/*
- * Register numbers
- */
-
-#define X1241REG_BL 0x10 /* block protect bits */
-#define X1241REG_INT 0x11 /* */
-#define X1241REG_SC 0x30 /* Seconds */
-#define X1241REG_MN 0x31 /* Minutes */
-#define X1241REG_HR 0x32 /* Hours */
-#define X1241REG_DT 0x33 /* Day of month */
-#define X1241REG_MO 0x34 /* Month */
-#define X1241REG_YR 0x35 /* Year */
-#define X1241REG_DW 0x36 /* Day of Week */
-#define X1241REG_Y2K 0x37 /* Year 2K */
-#define X1241REG_SR 0x3F /* Status register */
-
-#define X1241_CCR_ADDRESS 0x6F
-
-#define SMB_CSR(reg) (IOADDR(A_SMB_REGISTER(1, reg)))
-
-static int xicor_read(uint8_t addr)
-{
- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
- ;
-
- __raw_writeq((addr >> 8) & 0x7, SMB_CSR(R_SMB_CMD));
- __raw_writeq(addr & 0xff, SMB_CSR(R_SMB_DATA));
- __raw_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR2BYTE,
- SMB_CSR(R_SMB_START));
-
- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
- ;
-
- __raw_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_RD1BYTE,
- SMB_CSR(R_SMB_START));
-
- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
- ;
-
- if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) {
- /* Clear error bit by writing a 1 */
- __raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
- return -1;
- }
-
- return (__raw_readq(SMB_CSR(R_SMB_DATA)) & 0xff);
-}
-
-static int xicor_write(uint8_t addr, int b)
-{
- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
- ;
-
- __raw_writeq(addr, SMB_CSR(R_SMB_CMD));
- __raw_writeq((addr & 0xff) | ((b & 0xff) << 8), SMB_CSR(R_SMB_DATA));
- __raw_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR3BYTE,
- SMB_CSR(R_SMB_START));
-
- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
- ;
-
- if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) {
- /* Clear error bit by writing a 1 */
- __raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
- return -1;
- } else {
- return 0;
- }
-}
-
-/*
- * In order to set the CMOS clock precisely, set_rtc_mmss has to be
- * called 500 ms after the second nowtime has started, because when
- * nowtime is written into the registers of the CMOS clock, it will
- * jump to the next second precisely 500 ms later. Check the Motorola
- * MC146818A or Dallas DS12887 data sheet for details.
- *
- * BUG: This routine does not handle hour overflow properly; it just
- * sets the minutes. Usually you'll only notice that after reboot!
- */
-int set_rtc_mmss(unsigned long nowtime)
-{
- int retval = 0;
- int real_seconds, real_minutes, cmos_minutes;
-
- cmos_minutes = xicor_read(X1241REG_MN);
- cmos_minutes = BCD2BIN(cmos_minutes);
-
- /*
- * since we're only adjusting minutes and seconds,
- * don't interfere with hour overflow. This avoids
- * messing with unknown time zones but requires your
- * RTC not to be off by more than 15 minutes
- */
- real_seconds = nowtime % 60;
- real_minutes = nowtime / 60;
- if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
- real_minutes += 30; /* correct for half hour time zone */
- real_minutes %= 60;
-
- /* unlock writes to the CCR */
- xicor_write(X1241REG_SR, X1241REG_SR_WEL);
- xicor_write(X1241REG_SR, X1241REG_SR_WEL | X1241REG_SR_RWEL);
-
- if (abs(real_minutes - cmos_minutes) < 30) {
- real_seconds = BIN2BCD(real_seconds);
- real_minutes = BIN2BCD(real_minutes);
- xicor_write(X1241REG_SC, real_seconds);
- xicor_write(X1241REG_MN, real_minutes);
- } else {
- printk(KERN_WARNING
- "set_rtc_mmss: can't update from %d to %d\n",
- cmos_minutes, real_minutes);
- retval = -1;
- }
-
- xicor_write(X1241REG_SR, 0);
-
- printk("set_rtc_mmss: %02d:%02d\n", real_minutes, real_seconds);
-
- return retval;
-}
-
-static unsigned long __init get_swarm_time(void)
-{
- unsigned int year, mon, day, hour, min, sec, y2k;
-
- sec = xicor_read(X1241REG_SC);
- min = xicor_read(X1241REG_MN);
- hour = xicor_read(X1241REG_HR);
-
- if (hour & X1241REG_HR_MIL) {
- hour &= 0x3f;
- } else {
- if (hour & 0x20)
- hour = (hour & 0xf) + 0x12;
- }
-
- sec = BCD2BIN(sec);
- min = BCD2BIN(min);
- hour = BCD2BIN(hour);
-
- day = xicor_read(X1241REG_DT);
- mon = xicor_read(X1241REG_MO);
- year = xicor_read(X1241REG_YR);
- y2k = xicor_read(X1241REG_Y2K);
-
- day = BCD2BIN(day);
- mon = BCD2BIN(mon);
- year = BCD2BIN(year);
- y2k = BCD2BIN(y2k);
-
- year += (y2k * 100);
-
- return mktime(year, mon, day, hour, min, sec);
-}
-
-/*
- * Bring up the timer at 100 Hz.
- */
-void __init swarm_time_init(void)
-{
- unsigned int flags;
- int status;
-
- /* Set up the scd general purpose timer 0 to cpu 0 */
- sb1250_time_init();
-
- /* Establish communication with the Xicor 1241 RTC */
- /* XXXKW how do I share the SMBus with the I2C subsystem? */
-
- __raw_writeq(K_SMB_FREQ_400KHZ, SMB_CSR(R_SMB_FREQ));
- __raw_writeq(0, SMB_CSR(R_SMB_CONTROL));
-
- if ((status = xicor_read(X1241REG_SR_RTCF)) < 0) {
- printk("x1241: couldn't detect on SWARM SMBus 1\n");
- } else {
- if (status & X1241REG_SR_RTCF)
- printk("x1241: battery failed -- time is probably wrong\n");
- write_seqlock_irqsave(&xtime_lock, flags);
- xtime.tv_sec = get_swarm_time();
- xtime.tv_nsec = 0;
- write_sequnlock_irqrestore(&xtime_lock, flags);
- }
-}
--
1.5.2.1
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-14 10:19 [RFD] Time rework [take #2] Franck Bui-Huu
2007-06-14 10:19 ` [PATCH 1/5] Use generic NTP code for all MIPS platforms Franck Bui-Huu
2007-06-14 10:19 ` [PATCH 2/5] Remove unused time.c for swarm Franck Bui-Huu
@ 2007-06-14 10:19 ` Franck Bui-Huu
2007-06-14 11:17 ` Thomas Bogendoerfer
2007-06-14 10:20 ` [PATCH 4/5] Consolidate all variants of MIPS cp0 timer interrupt handlers Franck Bui-Huu
2007-06-14 10:20 ` [PATCH 5/5] Implement clockevents for R4000-style cp0 timer Franck Bui-Huu
4 siblings, 1 reply; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-14 10:19 UTC (permalink / raw)
To: linux-mips; +Cc: Ralf Baechle
From: Ralf Baechle <ralf@linux-mips.org>
Hard to follow who is pointing what to where and why so it's simply getting
in the way of the time code renovation.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
arch/mips/au1000/common/setup.c | 2 -
arch/mips/au1000/common/time.c | 4 --
arch/mips/basler/excite/excite_setup.c | 5 +--
arch/mips/ddb5xxx/common/rtc_ds1386.c | 10 +----
arch/mips/ddb5xxx/ddb5477/setup.c | 4 +-
arch/mips/dec/setup.c | 4 --
arch/mips/dec/time.c | 12 ++----
arch/mips/emma2rh/markeins/setup.c | 4 +-
arch/mips/gt64120/wrppmc/setup.c | 4 --
arch/mips/gt64120/wrppmc/time.c | 2 +-
arch/mips/jmr3927/rbhma3100/setup.c | 4 +-
arch/mips/kernel/time.c | 41 ++++++--------------
arch/mips/lasat/ds1603.c | 6 +-
arch/mips/lasat/ds1603.h | 2 -
arch/mips/lasat/setup.c | 6 +--
arch/mips/lasat/sysctl.c | 59 -----------------------------
arch/mips/mips-boards/atlas/atlas_setup.c | 5 --
arch/mips/mips-boards/generic/time.c | 4 +-
arch/mips/mips-boards/malta/malta_setup.c | 4 --
arch/mips/mips-boards/sead/sead_setup.c | 3 -
arch/mips/mips-boards/sim/sim_setup.c | 3 -
arch/mips/mips-boards/sim/sim_time.c | 2 +-
arch/mips/momentum/ocelot_3/setup.c | 12 +----
arch/mips/momentum/ocelot_c/setup.c | 15 ++-----
arch/mips/philips/pnx8550/common/setup.c | 3 -
arch/mips/philips/pnx8550/common/time.c | 7 ++-
arch/mips/pmc-sierra/yosemite/setup.c | 18 +-------
arch/mips/sgi-ip22/ip22-setup.c | 2 -
arch/mips/sgi-ip22/ip22-time.c | 15 +------
arch/mips/sgi-ip27/ip27-init.c | 3 -
arch/mips/sgi-ip27/ip27-timer.c | 6 +--
arch/mips/sgi-ip32/ip32-setup.c | 12 +++---
arch/mips/sibyte/swarm/setup.c | 48 +++++++++++++++++------
arch/mips/sni/a20r.c | 1 -
arch/mips/sni/ds1216.c | 4 +-
arch/mips/sni/pcimt.c | 3 -
arch/mips/sni/pcit.c | 3 -
arch/mips/sni/rm200.c | 2 -
arch/mips/sni/time.c | 2 +-
arch/mips/tx4927/common/tx4927_setup.c | 9 +----
arch/mips/tx4938/common/rtc_rx5c348.c | 10 +----
arch/mips/tx4938/common/setup.c | 9 ----
arch/mips/tx4938/toshiba_rbtx4938/setup.c | 4 +-
arch/mips/vr41xx/common/init.c | 8 +---
include/asm-mips/rtc.h | 6 +-
include/asm-mips/time.h | 12 ++----
46 files changed, 106 insertions(+), 298 deletions(-)
diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c
index 13fe187..646d7aa 100644
--- a/arch/mips/au1000/common/setup.c
+++ b/arch/mips/au1000/common/setup.c
@@ -50,7 +50,6 @@ extern void au1000_halt(void);
extern void au1000_power_off(void);
extern void au1x_time_init(void);
extern void au1x_timer_setup(struct irqaction *irq);
-extern void au1xxx_time_init(void);
extern void set_cpuspec(void);
void __init plat_mem_setup(void)
@@ -121,7 +120,6 @@ void __init plat_mem_setup(void)
_machine_restart = au1000_restart;
_machine_halt = au1000_halt;
pm_power_off = au1000_power_off;
- board_time_init = au1xxx_time_init;
/* IO/MEM resources. */
set_io_port_base(0);
diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c
index fa1c62f..b32bf46 100644
--- a/arch/mips/au1000/common/time.c
+++ b/arch/mips/au1000/common/time.c
@@ -358,7 +358,3 @@ void __init plat_timer_setup(struct irqaction *irq)
#endif
}
-
-void __init au1xxx_time_init(void)
-{
-}
diff --git a/arch/mips/basler/excite/excite_setup.c b/arch/mips/basler/excite/excite_setup.c
index 2f0e4c0..bf7e543 100644
--- a/arch/mips/basler/excite/excite_setup.c
+++ b/arch/mips/basler/excite/excite_setup.c
@@ -67,7 +67,7 @@ DEFINE_SPINLOCK(titan_lock);
int titan_irqflags;
-static void excite_timer_init(void)
+void __init plat_time_init(void)
{
const u32 modebit5 = ocd_readl(0x00e4);
unsigned int
@@ -260,9 +260,6 @@ void __init plat_mem_setup(void)
/* Announce RAM to system */
add_memory_region(0x00000000, memsize, BOOT_MEM_RAM);
- /* Set up timer initialization hooks */
- board_time_init = excite_timer_init;
-
/* Set up the peripheral address map */
*(boot_ocd_base + (LKB9 / sizeof (u32))) = 0;
*(boot_ocd_base + (LKB10 / sizeof (u32))) = 0;
diff --git a/arch/mips/ddb5xxx/common/rtc_ds1386.c b/arch/mips/ddb5xxx/common/rtc_ds1386.c
index 5dc34da..80f8e74 100644
--- a/arch/mips/ddb5xxx/common/rtc_ds1386.c
+++ b/arch/mips/ddb5xxx/common/rtc_ds1386.c
@@ -35,8 +35,7 @@
static unsigned long rtc_base;
-static unsigned long
-rtc_ds1386_get_time(void)
+unsigned long read_persistent_clock(void)
{
u8 byte;
u8 temp;
@@ -77,8 +76,7 @@ rtc_ds1386_get_time(void)
return mktime(year, month, day, hour, minute, second);
}
-static int
-rtc_ds1386_set_time(unsigned long t)
+static int rtc_mips_set_time(unsigned long t)
{
struct rtc_time tm;
u8 byte;
@@ -163,8 +161,4 @@ rtc_ds1386_init(unsigned long base)
byte = READ_RTC(0xB);
byte |= 0x80;
WRITE_RTC(0xB, byte);
-
- /* set the function pointers */
- rtc_mips_get_time = rtc_ds1386_get_time;
- rtc_mips_set_time = rtc_ds1386_set_time;
}
diff --git a/arch/mips/ddb5xxx/ddb5477/setup.c b/arch/mips/ddb5xxx/ddb5477/setup.c
index f0cc0e8..c276e94 100644
--- a/arch/mips/ddb5xxx/ddb5477/setup.c
+++ b/arch/mips/ddb5xxx/ddb5477/setup.c
@@ -121,7 +121,7 @@ static unsigned int __init detect_bus_frequency(unsigned long rtc_base)
return freq;
}
-static void __init ddb_time_init(void)
+void __init plat_time_init(void)
{
unsigned long rtc_base;
unsigned int i;
@@ -176,8 +176,6 @@ void __init plat_mem_setup(void)
set_io_port_base(KSEG1ADDR(DDB_PCI_IO_BASE));
- board_time_init = ddb_time_init;
-
_machine_restart = ddb_machine_restart;
_machine_halt = ddb_machine_halt;
pm_power_off = ddb_machine_power_off;
diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c
index b8a5e75..4ed83b4 100644
--- a/arch/mips/dec/setup.c
+++ b/arch/mips/dec/setup.c
@@ -145,13 +145,9 @@ static void __init dec_be_init(void)
}
}
-
-extern void dec_time_init(void);
-
void __init plat_mem_setup(void)
{
board_be_init = dec_be_init;
- board_time_init = dec_time_init;
wbflush_setup();
diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c
index 8b7e0c1..2c6dc89 100644
--- a/arch/mips/dec/time.c
+++ b/arch/mips/dec/time.c
@@ -36,7 +36,7 @@
#include <asm/dec/ioasic_addrs.h>
#include <asm/dec/machtype.h>
-static unsigned long dec_rtc_get_time(void)
+unsigned long read_persistent_clock(void)
{
unsigned int year, mon, day, hour, min, sec, real_year;
unsigned long flags;
@@ -75,13 +75,13 @@ static unsigned long dec_rtc_get_time(void)
}
/*
- * In order to set the CMOS clock precisely, dec_rtc_set_mmss has to
+ * In order to set the CMOS clock precisely, rtc_mips_set_mmss has to
* be called 500 ms after the second nowtime has started, because when
* nowtime is written into the registers of the CMOS clock, it will
* jump to the next second precisely 500 ms later. Check the Dallas
* DS1287 data sheet for details.
*/
-static int dec_rtc_set_mmss(unsigned long nowtime)
+int rtc_mips_set_mmss(unsigned long nowtime)
{
int retval = 0;
int real_seconds, real_minutes, cmos_minutes;
@@ -140,7 +140,6 @@ static int dec_rtc_set_mmss(unsigned long nowtime)
return retval;
}
-
static int dec_timer_state(void)
{
return (CMOS_READ(RTC_REG_C) & RTC_PF) != 0;
@@ -161,11 +160,8 @@ static cycle_t dec_ioasic_hpt_read(void)
}
-void __init dec_time_init(void)
+void __init plat_time_init(void)
{
- rtc_mips_get_time = dec_rtc_get_time;
- rtc_mips_set_mmss = dec_rtc_set_mmss;
-
mips_timer_state = dec_timer_state;
mips_timer_ack = dec_timer_ack;
diff --git a/arch/mips/emma2rh/markeins/setup.c b/arch/mips/emma2rh/markeins/setup.c
index 2f060e1..5e1da53 100644
--- a/arch/mips/emma2rh/markeins/setup.c
+++ b/arch/mips/emma2rh/markeins/setup.c
@@ -88,7 +88,7 @@ static unsigned int __init detect_bus_frequency(unsigned long rtc_base)
return clock[reg];
}
-static void __init emma2rh_time_init(void)
+void __init plat_time_init(void)
{
u32 reg;
if (bus_frequency == 0)
@@ -124,8 +124,6 @@ void __init plat_mem_setup(void)
set_io_port_base(KSEG1ADDR(EMMA2RH_PCI_IO_BASE));
- board_time_init = emma2rh_time_init;
-
_machine_restart = markeins_machine_restart;
_machine_halt = markeins_machine_halt;
pm_power_off = markeins_machine_power_off;
diff --git a/arch/mips/gt64120/wrppmc/setup.c b/arch/mips/gt64120/wrppmc/setup.c
index 121188d..46abb59 100644
--- a/arch/mips/gt64120/wrppmc/setup.c
+++ b/arch/mips/gt64120/wrppmc/setup.c
@@ -125,7 +125,6 @@ static void wrppmc_setup_serial(void)
void __init plat_mem_setup(void)
{
- extern void wrppmc_time_init(void);
extern void wrppmc_machine_restart(char *command);
extern void wrppmc_machine_halt(void);
extern void wrppmc_machine_power_off(void);
@@ -134,9 +133,6 @@ void __init plat_mem_setup(void)
_machine_halt = wrppmc_machine_halt;
pm_power_off = wrppmc_machine_power_off;
- /* Use MIPS Count/Compare Timer */
- board_time_init = wrppmc_time_init;
-
/* This makes the operations of 'in/out[bwl]' to the
* physical address ( < KSEG0) can work via KSEG1
*/
diff --git a/arch/mips/gt64120/wrppmc/time.c b/arch/mips/gt64120/wrppmc/time.c
index 5b44085..faf164e 100644
--- a/arch/mips/gt64120/wrppmc/time.c
+++ b/arch/mips/gt64120/wrppmc/time.c
@@ -38,7 +38,7 @@ void __init plat_timer_setup(struct irqaction *irq)
* NOTE: We disable all GT64120 timers, and use MIPS processor internal
* timer as the source of kernel clock tick.
*/
-void __init wrppmc_time_init(void)
+void __init plat_time_init(void)
{
/* Disable GT64120 timers */
GT_WRITE(GT_TC_CONTROL_OFS, 0x00);
diff --git a/arch/mips/jmr3927/rbhma3100/setup.c b/arch/mips/jmr3927/rbhma3100/setup.c
index 8303001..285adf6 100644
--- a/arch/mips/jmr3927/rbhma3100/setup.c
+++ b/arch/mips/jmr3927/rbhma3100/setup.c
@@ -109,7 +109,7 @@ static void jmr3927_timer_ack(void)
jmr3927_tmrptr->tisr = 0; /* ack interrupt */
}
-static void __init jmr3927_time_init(void)
+void __init plat_time_init(void)
{
clocksource_mips.read = jmr3927_hpt_read;
mips_timer_ack = jmr3927_timer_ack;
@@ -141,8 +141,6 @@ void __init plat_mem_setup(void)
set_io_port_base(JMR3927_PORT_BASE + JMR3927_PCIIO);
- board_time_init = jmr3927_time_init;
-
_machine_restart = jmr3927_machine_restart;
_machine_halt = jmr3927_machine_halt;
pm_power_off = jmr3927_machine_power_off;
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 376e127..d176e91 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -49,23 +49,16 @@
*/
DEFINE_SPINLOCK(rtc_lock);
-/*
- * By default we provide the null RTC ops
- */
-static unsigned long null_rtc_get_time(void)
+int __attribute__((weak)) rtc_mips_set_time(unsigned long sec)
{
- return mktime(2000, 1, 1, 0, 0, 0);
+ return 0;
}
-static int null_rtc_set_time(unsigned long sec)
+int __attribute__((weak)) rtc_mips_set_mmss(unsigned long nowtime)
{
- return 0;
+ return rtc_mips_set_time(nowtime);
}
-unsigned long (*rtc_mips_get_time)(void) = null_rtc_get_time;
-int (*rtc_mips_set_time)(unsigned long) = null_rtc_set_time;
-int (*rtc_mips_set_mmss)(unsigned long);
-
int update_persistent_clock(struct timespec now)
{
return rtc_mips_set_mmss(now.tv_sec);
@@ -241,21 +234,18 @@ asmlinkage void ll_local_timer_interrupt(int irq)
/*
* time_init() - it does the following things.
*
- * 1) board_time_init() -
+ * 1) plat_time_init() -
* a) (optional) set up RTC routines,
* b) (optional) calibrate and set the mips_hpt_frequency
* (only needed if you intended to use cpu counter as timer interrupt
* source)
- * 2) setup xtime based on rtc_mips_get_time().
- * 3) calculate a couple of cached variables for later usage
- * 4) plat_timer_setup() -
+ * 2) calculate a couple of cached variables for later usage
+ * 3) plat_timer_setup() -
* a) (optional) over-write any choices made above by time_init().
* b) machine specific code should setup the timer irqaction.
* c) enable the timer interrupt
*/
-void (*board_time_init)(void);
-
unsigned int mips_hpt_frequency;
static struct irqaction timer_irqaction = {
@@ -335,19 +325,13 @@ static void __init init_mips_clocksource(void)
clocksource_register(&clocksource_mips);
}
-void __init time_init(void)
+void __init __weak plat_time_init(void)
{
- if (board_time_init)
- board_time_init();
-
- if (!rtc_mips_set_mmss)
- rtc_mips_set_mmss = rtc_mips_set_time;
-
- xtime.tv_sec = rtc_mips_get_time();
- xtime.tv_nsec = 0;
+}
- set_normalized_timespec(&wall_to_monotonic,
- -xtime.tv_sec, -xtime.tv_nsec);
+void __init time_init(void)
+{
+ plat_time_init();
/* Choose appropriate high precision timer routines. */
if (!cpu_has_counter && !clocksource_mips.read)
@@ -456,4 +440,3 @@ void to_tm(unsigned long tim, struct rtc_time *tm)
EXPORT_SYMBOL(rtc_lock);
EXPORT_SYMBOL(to_tm);
EXPORT_SYMBOL(rtc_mips_set_time);
-EXPORT_SYMBOL(rtc_mips_get_time);
diff --git a/arch/mips/lasat/ds1603.c b/arch/mips/lasat/ds1603.c
index 7dced67..53207de 100644
--- a/arch/mips/lasat/ds1603.c
+++ b/arch/mips/lasat/ds1603.c
@@ -135,8 +135,7 @@ static void rtc_end_op(void)
lasat_ndelay(1000);
}
-/* interface */
-unsigned long ds1603_read(void)
+unsigned long read_persistent_clock(void)
{
unsigned long word;
unsigned long flags;
@@ -147,10 +146,11 @@ unsigned long ds1603_read(void)
word = rtc_read_word();
rtc_end_op();
spin_unlock_irqrestore(&rtc_lock, flags);
+
return word;
}
-int ds1603_set(unsigned long time)
+int rtc_mips_set_time(unsigned long time)
{
unsigned long flags;
diff --git a/arch/mips/lasat/ds1603.h b/arch/mips/lasat/ds1603.h
index c2e5c76..2da3704 100644
--- a/arch/mips/lasat/ds1603.h
+++ b/arch/mips/lasat/ds1603.h
@@ -20,8 +20,6 @@ struct ds_defs {
extern struct ds_defs *ds1603;
-unsigned long ds1603_read(void);
-int ds1603_set(unsigned long);
void ds1603_set_trimmer(unsigned int);
void ds1603_enable(void);
void ds1603_disable(void);
diff --git a/arch/mips/lasat/setup.c b/arch/mips/lasat/setup.c
index 488007f..ef630e7 100644
--- a/arch/mips/lasat/setup.c
+++ b/arch/mips/lasat/setup.c
@@ -109,7 +109,7 @@ static struct notifier_block lasat_panic_block[] =
{ lasat_panic_prom_monitor, NULL, INT_MIN }
};
-static void lasat_time_init(void)
+void __init plat_time_init(void)
{
mips_hpt_frequency = lasat_board_info.li_cpu_hz / 2;
}
@@ -164,12 +164,8 @@ void __init plat_mem_setup(void)
lasat_reboot_setup();
- board_time_init = lasat_time_init;
-
#ifdef CONFIG_DS1603
ds1603 = &ds_defs[mips_machtype];
- rtc_mips_get_time = ds1603_read;
- rtc_mips_set_time = ds1603_set;
#endif
#ifdef DYNAMIC_SERIAL_INIT
diff --git a/arch/mips/lasat/sysctl.c b/arch/mips/lasat/sysctl.c
index 699ab18..58e2fec 100644
--- a/arch/mips/lasat/sysctl.c
+++ b/arch/mips/lasat/sysctl.c
@@ -92,30 +92,6 @@ int proc_dolasatint(ctl_table *table, int write, struct file *filp,
static int rtctmp;
-#ifdef CONFIG_DS1603
-/* proc function to read/write RealTime Clock */
-int proc_dolasatrtc(ctl_table *table, int write, struct file *filp,
- void *buffer, size_t *lenp, loff_t *ppos)
-{
- int r;
- mutex_lock(&lasat_info_mutex);
- if (!write) {
- rtctmp = ds1603_read();
- /* check for time < 0 and set to 0 */
- if (rtctmp < 0)
- rtctmp = 0;
- }
- r = proc_dointvec(table, write, filp, buffer, lenp, ppos);
- if ( (!write) || r) {
- mutex_unlock(&lasat_info_mutex);
- return r;
- }
- ds1603_set(rtctmp);
- mutex_unlock(&lasat_info_mutex);
- return 0;
-}
-#endif
-
/* Sysctl for setting the IP addresses */
int sysctl_lasat_intvec(ctl_table *table, int *name, int nlen,
void *oldval, size_t *oldlenp,
@@ -135,30 +111,6 @@ int sysctl_lasat_intvec(ctl_table *table, int *name, int nlen,
return 1;
}
-#ifdef CONFIG_DS1603
-/* Same for RTC */
-int sysctl_lasat_rtc(ctl_table *table, int *name, int nlen,
- void *oldval, size_t *oldlenp,
- void *newval, size_t newlen)
-{
- int r;
- mutex_lock(&lasat_info_mutex);
- rtctmp = ds1603_read();
- if (rtctmp < 0)
- rtctmp = 0;
- r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen);
- if (r < 0) {
- mutex_unlock(&lasat_info_mutex);
- return r;
- }
- if (newval && newlen) {
- ds1603_set(rtctmp);
- }
- mutex_unlock(&lasat_info_mutex);
- return 1;
-}
-#endif
-
#ifdef CONFIG_INET
static char lasat_bcastaddr[16];
@@ -385,17 +337,6 @@ static ctl_table lasat_table[] = {
.proc_handler = &proc_dointvec,
.strategy = &sysctl_intvec
},
-#ifdef CONFIG_DS1603
- {
- .ctl_name = CTL_UNNUMBERED,
- .procname = "rtc",
- .data = &rtctmp,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dolasatrtc,
- .strategy = &sysctl_lasat_rtc
- },
-#endif
{
.ctl_name = CTL_UNNUMBERED,
.procname = "namestr",
diff --git a/arch/mips/mips-boards/atlas/atlas_setup.c b/arch/mips/mips-boards/atlas/atlas_setup.c
index 1cc6ebb..d96b426 100644
--- a/arch/mips/mips-boards/atlas/atlas_setup.c
+++ b/arch/mips/mips-boards/atlas/atlas_setup.c
@@ -34,8 +34,6 @@
#include <asm/traps.h>
extern void mips_reboot_setup(void);
-extern void mips_time_init(void);
-extern unsigned long mips_rtc_get_time(void);
#ifdef CONFIG_KGDB
extern void kgdb_config(void);
@@ -62,9 +60,6 @@ void __init plat_mem_setup(void)
kgdb_config();
#endif
mips_reboot_setup();
-
- board_time_init = mips_time_init;
- rtc_mips_get_time = mips_rtc_get_time;
}
static void __init serial_init(void)
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
index 8f1000f..67a0718 100644
--- a/arch/mips/mips-boards/generic/time.c
+++ b/arch/mips/mips-boards/generic/time.c
@@ -224,12 +224,12 @@ static unsigned int __init estimate_cpu_frequency(void)
return count;
}
-unsigned long __init mips_rtc_get_time(void)
+unsigned long read_persistent_clock(void)
{
return mc146818_get_cmos_time();
}
-void __init mips_time_init(void)
+void __init plat_time_init(void)
{
unsigned int est_freq;
diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c
index 8f1b78d..a5a5a43 100644
--- a/arch/mips/mips-boards/malta/malta_setup.c
+++ b/arch/mips/mips-boards/malta/malta_setup.c
@@ -36,7 +36,6 @@
#endif
extern void mips_reboot_setup(void);
-extern void mips_time_init(void);
extern unsigned long mips_rtc_get_time(void);
#ifdef CONFIG_KGDB
@@ -185,7 +184,4 @@ void __init plat_mem_setup(void)
#endif
#endif
mips_reboot_setup();
-
- board_time_init = mips_time_init;
- rtc_mips_get_time = mips_rtc_get_time;
}
diff --git a/arch/mips/mips-boards/sead/sead_setup.c b/arch/mips/mips-boards/sead/sead_setup.c
index 811aba1..bc05054 100644
--- a/arch/mips/mips-boards/sead/sead_setup.c
+++ b/arch/mips/mips-boards/sead/sead_setup.c
@@ -34,7 +34,6 @@
#include <asm/time.h>
extern void mips_reboot_setup(void);
-extern void mips_time_init(void);
static void __init serial_init(void);
@@ -51,8 +50,6 @@ void __init plat_mem_setup(void)
serial_init ();
- board_time_init = mips_time_init;
-
mips_reboot_setup();
}
diff --git a/arch/mips/mips-boards/sim/sim_setup.c b/arch/mips/mips-boards/sim/sim_setup.c
index b705f09..e05c1c2 100644
--- a/arch/mips/mips-boards/sim/sim_setup.c
+++ b/arch/mips/mips-boards/sim/sim_setup.c
@@ -35,8 +35,6 @@
#include <asm/mips-boards/sim.h>
#include <asm/mips-boards/simint.h>
-
-extern void sim_time_init(void);
static void __init serial_init(void);
unsigned int _isbonito = 0;
@@ -54,7 +52,6 @@ void __init plat_mem_setup(void)
serial_init();
- board_time_init = sim_time_init;
pr_info("Linux started...\n");
#ifdef CONFIG_MIPS_MT_SMP
diff --git a/arch/mips/mips-boards/sim/sim_time.c b/arch/mips/mips-boards/sim/sim_time.c
index d3a21c7..f8b8dff 100644
--- a/arch/mips/mips-boards/sim/sim_time.c
+++ b/arch/mips/mips-boards/sim/sim_time.c
@@ -146,7 +146,7 @@ static unsigned int __init estimate_cpu_frequency(void)
return count;
}
-void __init sim_time_init(void)
+void __init plat_time_init(void)
{
unsigned int est_freq, flags;
diff --git a/arch/mips/momentum/ocelot_3/setup.c b/arch/mips/momentum/ocelot_3/setup.c
index ff0829f..fd3372d 100644
--- a/arch/mips/momentum/ocelot_3/setup.c
+++ b/arch/mips/momentum/ocelot_3/setup.c
@@ -98,7 +98,6 @@ extern void momenco_ocelot_restart(char *command);
extern void momenco_ocelot_halt(void);
extern void momenco_ocelot_power_off(void);
-void momenco_time_init(void);
static char reset_reason;
void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
@@ -131,7 +130,7 @@ void setup_wired_tlb_entries(void)
add_wired_entry(ENTRYLO(0xfc000000), ENTRYLO(0xfd000000), (signed)0xfc000000, PM_16M);
}
-unsigned long m48t37y_get_time(void)
+unsigned long read_persistent_clock(void)
{
unsigned int year, month, day, hour, min, sec;
unsigned long flags;
@@ -158,7 +157,7 @@ unsigned long m48t37y_get_time(void)
return mktime(year, month, day, hour, min, sec);
}
-int m48t37y_set_time(unsigned long sec)
+int rtc_mips_set_time(unsigned long sec)
{
struct rtc_time tm;
unsigned long flags;
@@ -201,7 +200,7 @@ void __init plat_timer_setup(struct irqaction *irq)
setup_irq(7, irq); /* Timer interrupt, unmask status IM7 */
}
-void momenco_time_init(void)
+void __init plat_time_init(void)
{
setup_wired_tlb_entries();
@@ -210,9 +209,6 @@ void momenco_time_init(void)
* the Rm7900 and the Rm7065C
*/
mips_hpt_frequency = cpu_clock / 2;
-
- rtc_mips_get_time = m48t37y_get_time;
- rtc_mips_set_time = m48t37y_set_time;
}
/*
@@ -315,8 +311,6 @@ void __init plat_mem_setup(void)
{
unsigned int tmpword;
- board_time_init = momenco_time_init;
-
_machine_restart = momenco_ocelot_restart;
_machine_halt = momenco_ocelot_halt;
pm_power_off = momenco_ocelot_power_off;
diff --git a/arch/mips/momentum/ocelot_c/setup.c b/arch/mips/momentum/ocelot_c/setup.c
index 0b6b233..68b8236 100644
--- a/arch/mips/momentum/ocelot_c/setup.c
+++ b/arch/mips/momentum/ocelot_c/setup.c
@@ -76,8 +76,6 @@ extern void momenco_ocelot_restart(char *command);
extern void momenco_ocelot_halt(void);
extern void momenco_ocelot_power_off(void);
-void momenco_time_init(void);
-
static char reset_reason;
void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, unsigned long entryhi, unsigned long pagemask);
@@ -130,7 +128,7 @@ void PMON_v2_setup(void)
#endif
}
-unsigned long m48t37y_get_time(void)
+unsigned long read_persistent_clock(void)
{
#ifdef CONFIG_64BIT
unsigned char *rtc_base = (unsigned char*)0xfffffffffc800000;
@@ -162,7 +160,7 @@ unsigned long m48t37y_get_time(void)
return mktime(year, month, day, hour, min, sec);
}
-int m48t37y_set_time(unsigned long sec)
+int rtc_mips_set_time(unsigned long sec)
{
#ifdef CONFIG_64BIT
unsigned char* rtc_base = (unsigned char*)0xfffffffffc800000;
@@ -210,7 +208,7 @@ void __init plat_timer_setup(struct irqaction *irq)
setup_irq(7, irq);
}
-void momenco_time_init(void)
+void __init plat_time_init(void)
{
#ifdef CONFIG_CPU_SR71000
mips_hpt_frequency = cpu_clock;
@@ -219,18 +217,13 @@ void momenco_time_init(void)
#else
#error Unknown CPU for this board
#endif
- printk("momenco_time_init cpu_clock=%d\n", cpu_clock);
-
- rtc_mips_get_time = m48t37y_get_time;
- rtc_mips_set_time = m48t37y_set_time;
+ printk("plat_time_init cpu_clock=%d\n", cpu_clock);
}
void __init plat_mem_setup(void)
{
unsigned int tmpword;
- board_time_init = momenco_time_init;
-
_machine_restart = momenco_ocelot_restart;
_machine_halt = momenco_ocelot_halt;
pm_power_off = momenco_ocelot_power_off;
diff --git a/arch/mips/philips/pnx8550/common/setup.c b/arch/mips/philips/pnx8550/common/setup.c
index 5bd7374..2ce298f 100644
--- a/arch/mips/philips/pnx8550/common/setup.c
+++ b/arch/mips/philips/pnx8550/common/setup.c
@@ -47,7 +47,6 @@ extern void pnx8550_machine_halt(void);
extern void pnx8550_machine_power_off(void);
extern struct resource ioport_resource;
extern struct resource iomem_resource;
-extern void pnx8550_time_init(void);
extern void rs_kgdb_hook(int tty_no);
extern char *prom_getcmdline(void);
@@ -104,8 +103,6 @@ void __init plat_mem_setup(void)
_machine_halt = pnx8550_machine_halt;
pm_power_off = pnx8550_machine_power_off;
- board_time_init = pnx8550_time_init;
-
/* Clear the Global 2 Register, PCI Inta Output Enable Registers
Bit 1:Enable DAC Powerdown
-> 0:DACs are enabled and are working normally
diff --git a/arch/mips/philips/pnx8550/common/time.c b/arch/mips/philips/pnx8550/common/time.c
index 68def38..e818fd0 100644
--- a/arch/mips/philips/pnx8550/common/time.c
+++ b/arch/mips/philips/pnx8550/common/time.c
@@ -1,6 +1,7 @@
/*
* Copyright 2001, 2002, 2003 MontaVista Software Inc.
* Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org)
*
* Common time service routines for MIPS machines. See
* Documents/MIPS/README.txt.
@@ -46,16 +47,16 @@ static void timer_ack(void)
}
/*
- * pnx8550_time_init() - it does the following things:
+ * plat_time_init() - it does the following things:
*
- * 1) board_time_init() -
+ * 1) plat_time_init() -
* a) (optional) set up RTC routines,
* b) (optional) calibrate and set the mips_hpt_frequency
* (only needed if you intended to use cpu counter as timer interrupt
* source)
*/
-void pnx8550_time_init(void)
+__init void plat_time_init(void)
{
unsigned int n;
unsigned int m;
diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c
index 6a6e15e..902ace8 100644
--- a/arch/mips/pmc-sierra/yosemite/setup.c
+++ b/arch/mips/pmc-sierra/yosemite/setup.c
@@ -69,7 +69,7 @@ void __init bus_error_init(void)
}
-unsigned long m48t37y_get_time(void)
+unsigned long read_persistent_clock(void)
{
unsigned int year, month, day, hour, min, sec;
unsigned long flags;
@@ -94,7 +94,7 @@ unsigned long m48t37y_get_time(void)
return mktime(year, month, day, hour, min, sec);
}
-int m48t37y_set_time(unsigned long sec)
+int rtc_mips_set_time(unsigned long sec)
{
struct rtc_time tm;
unsigned long flags;
@@ -137,7 +137,7 @@ void __init plat_timer_setup(struct irqaction *irq)
setup_irq(7, irq);
}
-void yosemite_time_init(void)
+void __init plat_time_init(void)
{
mips_hpt_frequency = cpu_clock / 2;
mips_hpt_frequency = 33000000 * 3 * 5;
@@ -197,17 +197,6 @@ static void __init py_rtc_setup(void)
m48t37_base = ioremap(YOSEMITE_RTC_BASE, YOSEMITE_RTC_SIZE);
if (!m48t37_base)
printk(KERN_ERR "Mapping the RTC failed\n");
-
- rtc_mips_get_time = m48t37y_get_time;
- rtc_mips_set_time = m48t37y_set_time;
-
- write_seqlock(&xtime_lock);
- xtime.tv_sec = m48t37y_get_time();
- xtime.tv_nsec = 0;
-
- set_normalized_timespec(&wall_to_monotonic,
- -xtime.tv_sec, -xtime.tv_nsec);
- write_sequnlock(&xtime_lock);
}
/* Not only time init but that's what the hook it's called through is named */
@@ -220,7 +209,6 @@ static void __init py_late_time_init(void)
void __init plat_mem_setup(void)
{
- board_time_init = yosemite_time_init;
late_time_init = py_late_time_init;
/* Add memory regions */
diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c
index 25097ec..35bdf83 100644
--- a/arch/mips/sgi-ip22/ip22-setup.c
+++ b/arch/mips/sgi-ip22/ip22-setup.c
@@ -50,7 +50,6 @@ void ip22_do_break(void)
EXPORT_SYMBOL(ip22_do_break);
extern void ip22_be_init(void) __init;
-extern void ip22_time_init(void) __init;
void __init plat_mem_setup(void)
{
@@ -58,7 +57,6 @@ void __init plat_mem_setup(void)
char *cserial;
board_be_init = ip22_be_init;
- ip22_time_init();
/* Init the INDY HPC I/O controller. Need to call this before
* fucking with the memory controller because it needs to know the
diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c
index 8e88a44..77f0c30 100644
--- a/arch/mips/sgi-ip22/ip22-time.c
+++ b/arch/mips/sgi-ip22/ip22-time.c
@@ -32,7 +32,7 @@
* note that mktime uses month from 1 to 12 while to_tm
* uses 0 to 11.
*/
-static unsigned long indy_rtc_get_time(void)
+unsigned long read_persistent_clock(void)
{
unsigned int yrs, mon, day, hrs, min, sec;
unsigned int save_control;
@@ -60,7 +60,7 @@ static unsigned long indy_rtc_get_time(void)
return mktime(yrs + 1900, mon, day, hrs, min, sec);
}
-static int indy_rtc_set_time(unsigned long tim)
+int rtc_mips_set_time(unsigned long tim)
{
struct rtc_time tm;
unsigned int save_control;
@@ -128,7 +128,7 @@ static unsigned long dosample(void)
/*
* Here we need to calibrate the cycle counter to at least be close.
*/
-static __init void indy_time_init(void)
+__init void plat_time_init(void)
{
unsigned long r4k_ticks[3];
unsigned long r4k_tick;
@@ -207,12 +207,3 @@ void __init plat_timer_setup(struct irqaction *irq)
/* setup irqaction */
setup_irq(SGI_TIMER_IRQ, irq);
}
-
-void __init ip22_time_init(void)
-{
- /* setup hookup functions */
- rtc_mips_get_time = indy_rtc_get_time;
- rtc_mips_set_time = indy_rtc_set_time;
-
- board_time_init = indy_time_init;
-}
diff --git a/arch/mips/sgi-ip27/ip27-init.c b/arch/mips/sgi-ip27/ip27-init.c
index 74158d3..8427231 100644
--- a/arch/mips/sgi-ip27/ip27-init.c
+++ b/arch/mips/sgi-ip27/ip27-init.c
@@ -191,7 +191,6 @@ static inline void ioc3_eth_init(void)
ioc3->eier = 0;
}
-extern void ip27_time_init(void);
extern void ip27_reboot_setup(void);
void __init plat_mem_setup(void)
@@ -238,6 +237,4 @@ void __init plat_mem_setup(void)
per_cpu_init();
set_io_port_base(IO_BASE);
-
- board_time_init = ip27_time_init;
}
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c
index 3134616..9c1700e 100644
--- a/arch/mips/sgi-ip27/ip27-timer.c
+++ b/arch/mips/sgi-ip27/ip27-timer.c
@@ -123,7 +123,7 @@ again:
#include <asm/sn/sn0/hubio.h>
#include <asm/pci/bridge.h>
-static __init unsigned long get_m48t35_time(void)
+unsigned long read_persistent_clock(void)
{
unsigned int year, month, date, hour, min, sec;
struct m48t35_rtc *rtc;
@@ -205,12 +205,10 @@ static cycle_t ip27_hpt_read(void)
return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT);
}
-void __init ip27_time_init(void)
+void __init plat_time_init(void)
{
clocksource_mips.read = ip27_hpt_read;
mips_hpt_frequency = CYCLES_PER_SEC;
- xtime.tv_sec = get_m48t35_time();
- xtime.tv_nsec = 0;
}
void __init cpu_time_init(void)
diff --git a/arch/mips/sgi-ip32/ip32-setup.c b/arch/mips/sgi-ip32/ip32-setup.c
index 57708fe..f3aa4cf 100644
--- a/arch/mips/sgi-ip32/ip32-setup.c
+++ b/arch/mips/sgi-ip32/ip32-setup.c
@@ -68,10 +68,15 @@ static inline void str2eaddr(unsigned char *ea, unsigned char *str)
#include <linux/serial_core.h>
#endif /* CONFIG_SERIAL_8250 */
+unsigned long read_persistent_clock(void)
+{
+ return mc146818_get_cmos_time();
+}
+
/* An arbitrary time; this can be decreased if reliability looks good */
#define WAIT_MS 10
-void __init ip32_time_init(void)
+void __init plat_time_init(void)
{
printk(KERN_INFO "Calibrating system timer... ");
write_c0_count(0);
@@ -91,11 +96,6 @@ void __init plat_mem_setup(void)
{
board_be_init = ip32_be_init;
- rtc_mips_get_time = mc146818_get_cmos_time;
- rtc_mips_set_mmss = mc146818_set_rtc_mmss;
-
- board_time_init = ip32_time_init;
-
#ifdef CONFIG_SERIAL_8250
{
static struct uart_port o2_serial[2];
diff --git a/arch/mips/sibyte/swarm/setup.c b/arch/mips/sibyte/swarm/setup.c
index 83572d8..9988cea 100644
--- a/arch/mips/sibyte/swarm/setup.c
+++ b/arch/mips/sibyte/swarm/setup.c
@@ -69,7 +69,7 @@ const char *get_system_type(void)
return "SiByte " SIBYTE_BOARD_NAME;
}
-void __init swarm_time_init(void)
+void __init plat_time_init(void)
{
#if defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
/* Setup HPT */
@@ -104,6 +104,36 @@ int swarm_be_handler(struct pt_regs *regs, int is_fixup)
return (is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL);
}
+enum swarm_rtc_type {
+ RTC_NONE,
+ RTC_XICOR,
+ RTC_M4LT81
+};
+
+enum swarm_rtc_type swarm_rtc_type;
+
+unsigned long read_persistent_clock(void)
+{
+ switch (swarm_rtc_type) {
+ case RTC_XICOR:
+ return xicor_get_time(void);
+
+ case RTC_M4LT81:
+ return m41t81_get_time(void);
+ }
+}
+
+static int rtc_mips_set_time(unsigned long sec)
+{
+ switch (swarm_rtc_type) {
+ case RTC_XICOR:
+ return xicor_set_time(sec);
+
+ case RTC_M4LT81:
+ return m41t81_set_time(sec);
+ }
+}
+
void __init plat_mem_setup(void)
{
#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
@@ -116,20 +146,12 @@ void __init plat_mem_setup(void)
panic_timeout = 5; /* For debug. */
- board_time_init = swarm_time_init;
board_be_handler = swarm_be_handler;
- if (xicor_probe()) {
- printk("swarm setup: Xicor 1241 RTC detected.\n");
- rtc_mips_get_time = xicor_get_time;
- rtc_mips_set_time = xicor_set_time;
- }
-
- if (m41t81_probe()) {
- printk("swarm setup: M41T81 RTC detected.\n");
- rtc_mips_get_time = m41t81_get_time;
- rtc_mips_set_time = m41t81_set_time;
- }
+ if (xicor_probe())
+ swarm_rtc_type = RTC_XICOR;
+ if (m41t81_probe())
+ swarm_rtc_type = RTC_M4LT81;
printk("This kernel optimized for "
#ifdef CONFIG_SIMULATION
diff --git a/arch/mips/sni/a20r.c b/arch/mips/sni/a20r.c
index 31ab80f..b311ccd 100644
--- a/arch/mips/sni/a20r.c
+++ b/arch/mips/sni/a20r.c
@@ -206,7 +206,6 @@ void __init sni_a20r_irq_init(void)
void sni_a20r_init(void)
{
ds1216_base = (volatile unsigned char *) SNI_DS1216_A20R_BASE;
- rtc_mips_get_time = ds1216_get_cmos_time;
}
static int __init snirm_a20r_setup_devinit(void)
diff --git a/arch/mips/sni/ds1216.c b/arch/mips/sni/ds1216.c
index 1d92732..440d26f 100644
--- a/arch/mips/sni/ds1216.c
+++ b/arch/mips/sni/ds1216.c
@@ -48,7 +48,7 @@ static void ds1216_switch_ds_to_clock(void)
}
}
-unsigned long ds1216_get_cmos_time(void)
+unsigned long read_persistent_clock(void)
{
unsigned char *rdbuf;
unsigned int year, month, date, hour, min, sec;
@@ -74,7 +74,7 @@ unsigned long ds1216_get_cmos_time(void)
return mktime(year, month, date, hour, min, sec);
}
-int ds1216_set_rtc_mmss(unsigned long nowtime)
+int rtc_mips_set_mmss(unsigned long nowtime)
{
printk("ds1216_set_rtc_mmss called but not implemented\n");
return -1;
diff --git a/arch/mips/sni/pcimt.c b/arch/mips/sni/pcimt.c
index 97b2343..a709e79 100644
--- a/arch/mips/sni/pcimt.c
+++ b/arch/mips/sni/pcimt.c
@@ -294,9 +294,6 @@ void sni_pcimt_init(void)
{
sni_pcimt_detect();
sni_pcimt_sc_init();
- rtc_mips_get_time = mc146818_get_cmos_time;
- rtc_mips_set_time = mc146818_set_rtc_mmss;
- board_time_init = sni_cpu_time_init;
ioport_resource.end = sni_io_resource.end;
#ifdef CONFIG_PCI
PCIBIOS_MIN_IO = 0x9000;
diff --git a/arch/mips/sni/pcit.c b/arch/mips/sni/pcit.c
index 00d151f..8d992c5 100644
--- a/arch/mips/sni/pcit.c
+++ b/arch/mips/sni/pcit.c
@@ -245,9 +245,6 @@ void __init sni_pcit_cplus_irq_init(void)
void sni_pcit_init(void)
{
- rtc_mips_get_time = mc146818_get_cmos_time;
- rtc_mips_set_time = mc146818_set_rtc_mmss;
- board_time_init = sni_cpu_time_init;
ioport_resource.end = sni_io_resource.end;
#ifdef CONFIG_PCI
PCIBIOS_MIN_IO = 0x9000;
diff --git a/arch/mips/sni/rm200.c b/arch/mips/sni/rm200.c
index b82ff12..5ff6b35 100644
--- a/arch/mips/sni/rm200.c
+++ b/arch/mips/sni/rm200.c
@@ -181,6 +181,4 @@ void sni_rm200_init(void)
set_io_port_base(SNI_PORT_BASE + 0x02000000);
ioport_resource.end += 0x02000000;
ds1216_base = (volatile unsigned char *) SNI_DS1216_RM200_BASE;
- rtc_mips_get_time = ds1216_get_cmos_time;
- board_time_init = sni_cpu_time_init;
}
diff --git a/arch/mips/sni/time.c b/arch/mips/sni/time.c
index 20028fc..3d5bfa0 100644
--- a/arch/mips/sni/time.c
+++ b/arch/mips/sni/time.c
@@ -71,7 +71,7 @@ static __init unsigned long dosample(void)
/*
* Here we need to calibrate the cycle counter to at least be close.
*/
-__init void sni_cpu_time_init(void)
+void __init plat_time_init(void)
{
unsigned long r4k_ticks[3];
unsigned long r4k_tick;
diff --git a/arch/mips/tx4927/common/tx4927_setup.c b/arch/mips/tx4927/common/tx4927_setup.c
index c8e49fe..a141f44 100644
--- a/arch/mips/tx4927/common/tx4927_setup.c
+++ b/arch/mips/tx4927/common/tx4927_setup.c
@@ -49,14 +49,11 @@
#undef DEBUG
-void __init tx4927_time_init(void);
void dump_cp0(char *key);
void __init plat_mem_setup(void)
{
- board_time_init = tx4927_time_init;
-
#ifdef CONFIG_TOSHIBA_RBTX4927
{
extern void toshiba_rbtx4927_setup(void);
@@ -65,20 +62,16 @@ void __init plat_mem_setup(void)
#endif
}
-void __init tx4927_time_init(void)
+void __init plat_time_init(void)
{
-
#ifdef CONFIG_TOSHIBA_RBTX4927
{
extern void toshiba_rbtx4927_time_init(void);
toshiba_rbtx4927_time_init();
}
#endif
-
- return;
}
-
void __init plat_timer_setup(struct irqaction *irq)
{
setup_irq(TX4927_IRQ_CPU_TIMER, irq);
diff --git a/arch/mips/tx4938/common/rtc_rx5c348.c b/arch/mips/tx4938/common/rtc_rx5c348.c
index 07f782f..ad83308 100644
--- a/arch/mips/tx4938/common/rtc_rx5c348.c
+++ b/arch/mips/tx4938/common/rtc_rx5c348.c
@@ -80,8 +80,7 @@ spi_rtc_io(unsigned char *inbuf, unsigned char *outbuf, unsigned int count)
/* RTC-dependent code for time.c */
-static int
-rtc_rx5c348_set_time(unsigned long t)
+int rtc_mips_set_time(unsigned long t)
{
unsigned char inbuf[8];
struct rtc_time tm;
@@ -129,8 +128,7 @@ rtc_rx5c348_set_time(unsigned long t)
return spi_rtc_io(inbuf, NULL, 8);
}
-static unsigned long
-rtc_rx5c348_get_time(void)
+unsigned long read_persistent_clock(void)
{
unsigned char inbuf[8], outbuf[8];
unsigned int year, month, day, hour, minute, second;
@@ -185,8 +183,4 @@ rtc_rx5c348_init(int chipid)
spi_rtc_io(inbuf, outbuf, 2);
if (outbuf[1] & Rx5C348_BIT_24H)
srtc_24h = 1;
-
- /* set the function pointers */
- rtc_mips_get_time = rtc_rx5c348_get_time;
- rtc_mips_set_time = rtc_rx5c348_set_time;
}
diff --git a/arch/mips/tx4938/common/setup.c b/arch/mips/tx4938/common/setup.c
index 142abf4..ab40822 100644
--- a/arch/mips/tx4938/common/setup.c
+++ b/arch/mips/tx4938/common/setup.c
@@ -34,25 +34,16 @@
#include <asm/tx4938/rbtx4938.h>
extern void toshiba_rbtx4938_setup(void);
-extern void rbtx4938_time_init(void);
void __init tx4938_setup(void);
-void __init tx4938_time_init(void);
void dump_cp0(char *key);
void __init
plat_mem_setup(void)
{
- board_time_init = tx4938_time_init;
toshiba_rbtx4938_setup();
}
-void __init
-tx4938_time_init(void)
-{
- rbtx4938_time_init();
-}
-
void __init plat_timer_setup(struct irqaction *irq)
{
setup_irq(TX4938_IRQ_CPU_TIMER, irq);
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/setup.c b/arch/mips/tx4938/toshiba_rbtx4938/setup.c
index f5d1ce7..f55117d 100644
--- a/arch/mips/tx4938/toshiba_rbtx4938/setup.c
+++ b/arch/mips/tx4938/toshiba_rbtx4938/setup.c
@@ -36,7 +36,6 @@
#include <linux/serial_core.h>
#endif
-extern void rbtx4938_time_init(void) __init;
extern char * __init prom_getcmdline(void);
static inline void tx4938_report_pcic_status1(struct tx4938_pcic_reg *pcicptr);
@@ -897,7 +896,8 @@ void tx4938_report_pcic_status(void)
* interrupt running at 100HZ. */
extern void __init rtc_rx5c348_init(int chipid);
-void __init rbtx4938_time_init(void)
+
+void __init plat_time_init(void)
{
rtc_rx5c348_init(RBTX4938_SRTC_CHIPID);
mips_hpt_frequency = txx9_cpu_clock / 2;
diff --git a/arch/mips/vr41xx/common/init.c b/arch/mips/vr41xx/common/init.c
index 4f97e0b..407cec2 100644
--- a/arch/mips/vr41xx/common/init.c
+++ b/arch/mips/vr41xx/common/init.c
@@ -36,7 +36,7 @@ static void __init iomem_resource_init(void)
iomem_resource.end = IO_MEM_RESOURCE_END;
}
-static void __init setup_timer_frequency(void)
+void __init plat_time_init(void)
{
unsigned long tclock;
@@ -53,16 +53,10 @@ void __init plat_timer_setup(struct irqaction *irq)
setup_irq(TIMER_IRQ, irq);
}
-static void __init timer_init(void)
-{
- board_time_init = setup_timer_frequency;
-}
-
void __init plat_mem_setup(void)
{
vr41xx_calculate_clock_frequency();
- timer_init();
iomem_resource_init();
}
diff --git a/include/asm-mips/rtc.h b/include/asm-mips/rtc.h
index 82ad401..9da3821 100644
--- a/include/asm-mips/rtc.h
+++ b/include/asm-mips/rtc.h
@@ -1,10 +1,9 @@
/*
- * include/asm-mips/rtc.h
- *
* (Really an interface for drivers/char/genrtc.c)
*
* Copyright (C) 2004 MontaVista Software Inc.
* Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org)
*
* Please read the COPYING file for all license details.
*/
@@ -32,7 +31,7 @@ static inline unsigned int get_rtc_time(struct rtc_time *time)
{
unsigned long nowtime;
- nowtime = rtc_mips_get_time();
+ nowtime = read_persistent_clock();
to_tm(nowtime, time);
time->tm_year -= 1900;
@@ -57,6 +56,7 @@ static inline unsigned int get_rtc_ss(void)
struct rtc_time h;
get_rtc_time(&h);
+
return h.tm_sec;
}
diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h
index a632cef..74ab331 100644
--- a/include/asm-mips/time.h
+++ b/include/asm-mips/time.h
@@ -26,15 +26,13 @@
extern spinlock_t rtc_lock;
/*
- * RTC ops. By default, they point to no-RTC functions.
- * rtc_mips_get_time - mktime(year, mon, day, hour, min, sec) in seconds.
+ * RTC ops. By default, they point to weak no-op RTC functions.
* rtc_mips_set_time - reverse the above translation and set time to RTC.
* rtc_mips_set_mmss - similar to rtc_set_time, but only min and sec need
* to be set. Used by RTC sync-up.
*/
-extern unsigned long (*rtc_mips_get_time)(void);
-extern int (*rtc_mips_set_time)(unsigned long);
-extern int (*rtc_mips_set_mmss)(unsigned long);
+extern int rtc_mips_set_time(unsigned long);
+extern int rtc_mips_set_mmss(unsigned long);
/*
* Timer interrupt functions.
@@ -75,11 +73,9 @@ extern asmlinkage void ll_local_timer_interrupt(int irq);
/*
* board specific routines required by time_init().
- * board_time_init is defaulted to NULL and can remain so.
- * plat_timer_setup must be setup properly in machine setup routine.
*/
struct irqaction;
-extern void (*board_time_init)(void);
+extern void plat_time_init(void);
extern void plat_timer_setup(struct irqaction *irq);
/*
--
1.5.2.1
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH 4/5] Consolidate all variants of MIPS cp0 timer interrupt handlers.
2007-06-14 10:19 [RFD] Time rework [take #2] Franck Bui-Huu
` (2 preceding siblings ...)
2007-06-14 10:19 ` [PATCH 3/5] Deforest the function pointer jungle in the time code Franck Bui-Huu
@ 2007-06-14 10:20 ` Franck Bui-Huu
2007-06-14 10:20 ` [PATCH 5/5] Implement clockevents for R4000-style cp0 timer Franck Bui-Huu
4 siblings, 0 replies; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-14 10:20 UTC (permalink / raw)
To: linux-mips; +Cc: Ralf Baechle
From: Ralf Baechle <ralf@linux-mips.org>
---
arch/mips/au1000/common/irq.c | 3 +-
arch/mips/au1000/common/time.c | 40 --------------
arch/mips/kernel/smtc.c | 2 +-
arch/mips/kernel/time.c | 81 +++++++++++++++++++++++++---
arch/mips/mips-boards/generic/time.c | 97 ----------------------------------
arch/mips/mips-boards/sim/sim_time.c | 70 ------------------------
arch/mips/sgi-ip22/ip22-int.c | 3 +-
arch/mips/sgi-ip22/ip22-time.c | 10 ----
arch/mips/sibyte/bcm1480/time.c | 13 +----
arch/mips/sibyte/sb1250/time.c | 13 +----
include/asm-mips/time.h | 5 +-
11 files changed, 80 insertions(+), 257 deletions(-)
diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c
index ea6e99f..cb33d9e 100644
--- a/arch/mips/au1000/common/irq.c
+++ b/arch/mips/au1000/common/irq.c
@@ -67,7 +67,6 @@
extern void set_debug_traps(void);
extern irq_cpustat_t irq_stat [NR_CPUS];
-extern void mips_timer_interrupt(void);
static void setup_local_irq(unsigned int irq, int type, int int_req);
static void end_irq(unsigned int irq_nr);
@@ -646,7 +645,7 @@ asmlinkage void plat_irq_dispatch(void)
unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
if (pending & CAUSEF_IP7)
- mips_timer_interrupt();
+ ll_timer_interrupt(63);
else if (pending & CAUSEF_IP2)
intc0_req0_irqdispatch();
else if (pending & CAUSEF_IP3)
diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c
index b32bf46..7028025 100644
--- a/arch/mips/au1000/common/time.c
+++ b/arch/mips/au1000/common/time.c
@@ -64,48 +64,8 @@ static unsigned long last_pc0, last_match20;
static DEFINE_SPINLOCK(time_lock);
-static inline void ack_r4ktimer(unsigned long newval)
-{
- write_c0_compare(newval);
-}
-
-/*
- * There are a lot of conceptually broken versions of the MIPS timer interrupt
- * handler floating around. This one is rather different, but the algorithm
- * is provably more robust.
- */
unsigned long wtimer;
-void mips_timer_interrupt(void)
-{
- int irq = 63;
-
- irq_enter();
- kstat_this_cpu.irqs[irq]++;
-
- if (r4k_offset == 0)
- goto null;
-
- do {
- kstat_this_cpu.irqs[irq]++;
- do_timer(1);
-#ifndef CONFIG_SMP
- update_process_times(user_mode(get_irq_regs()));
-#endif
- r4k_cur += r4k_offset;
- ack_r4ktimer(r4k_cur);
-
- } while (((unsigned long)read_c0_count()
- - r4k_cur) < 0x7fffffff);
-
- irq_exit();
- return;
-
-null:
- ack_r4ktimer(0);
- irq_exit();
-}
-
#ifdef CONFIG_PM
irqreturn_t counter0_irq(int irq, void *dev_id)
{
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index 21eb599..8b95808 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -828,7 +828,7 @@ void ipi_decode(struct smtc_ipi *pipi)
#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG
clock_hang_reported[dest_copy] = 0;
#endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */
- local_timer_interrupt(0, NULL);
+ local_timer_interrupt(0);
irq_exit();
break;
case LINUX_SMP_IPI:
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index d176e91..a75d63b 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -131,7 +131,7 @@ void (*mips_timer_ack)(void);
* a broadcasted inter-processor interrupt which itself is triggered
* by the global timer interrupt.
*/
-void local_timer_interrupt(int irq, void *dev_id)
+void local_timer_interrupt(int irq)
{
profile_tick(CPU_PROFILING);
update_process_times(user_mode(get_irq_regs()));
@@ -161,7 +161,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id)
* In SMP mode, local_timer_interrupt() is invoked by appropriate
* low-level local timer interrupt handler.
*/
- local_timer_interrupt(irq, dev_id);
+ local_timer_interrupt(irq);
return IRQ_HANDLED;
}
@@ -171,9 +171,10 @@ int null_perf_irq(void)
return 0;
}
+EXPORT_SYMBOL(null_perf_irq);
+
int (*perf_irq)(void) = null_perf_irq;
-EXPORT_SYMBOL(null_perf_irq);
EXPORT_SYMBOL(perf_irq);
/*
@@ -186,7 +187,7 @@ EXPORT_SYMBOL(mipsxx_perfcount_irq);
* Possibly handle a performance counter interrupt.
* Return true if the timer interrupt should not be checked
*/
-static inline int handle_perf_irq (int r2)
+static inline int handle_perf_irq(int r2)
{
/*
* The performance counter overflow interrupt may be shared with the
@@ -200,25 +201,89 @@ static inline int handle_perf_irq (int r2)
!r2;
}
-asmlinkage void ll_timer_interrupt(int irq)
+extern void smtc_timer_broadcast(int);
+
+void ll_timer_interrupt(int irq)
{
+ int cpu = smp_processor_id();
int r2 = cpu_has_mips_r2;
irq_enter();
kstat_this_cpu.irqs[irq]++;
+#ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * In an SMTC system, one Count/Compare set exists per VPE.
+ * Which TC within a VPE gets the interrupt is essentially
+ * random - we only know that it shouldn't be one with
+ * IXMT set. Whichever TC gets the interrupt needs to
+ * send special interprocessor interrupts to the other
+ * TCs to make sure that they schedule, etc.
+ *
+ * That code is specific to the SMTC kernel, not to
+ * the a particular platform, so it's invoked from
+ * the general MIPS timer_interrupt routine.
+ */
+
+ /*
+ * We could be here due to timer interrupt,
+ * perf counter overflow, or both.
+ */
+ (void) handle_perf_irq(1);
+
+ if (read_c0_cause() & (1 << 30)) {
+ /*
+ * There are things we only want to do once per tick
+ * in an "MP" system. One TC of each VPE will take
+ * the actual timer interrupt. The others will get
+ * timer broadcast IPIs. We use whoever it is that takes
+ * the tick on VPE 0 to run the full timer_interrupt().
+ */
+ if (cpu_data[cpu].vpe_id == 0) {
+ timer_interrupt(irq, NULL);
+ } else {
+ write_c0_compare(read_c0_count() +
+ (mips_hpt_frequency/HZ));
+ local_timer_interrupt(irq);
+ }
+ smtc_timer_broadcast(cpu_data[cpu].vpe_id);
+ }
+#else /* CONFIG_MIPS_MT_SMTC */
if (handle_perf_irq(r2))
goto out;
if (r2 && ((read_c0_cause() & (1 << 30)) == 0))
goto out;
- timer_interrupt(irq, NULL);
-
+ if (cpu == 0) {
+ /*
+ * CPU 0 handles the global timer interrupt job and process
+ * accounting resets count/compare registers to trigger next
+ * timer int.
+ */
+ timer_interrupt(irq, NULL);
+ } else {
+ /* Everyone else needs to reset the timer int here as
+ ll_local_timer_interrupt doesn't */
+ /*
+ * FIXME: need to cope with counter underflow.
+ * More support needs to be added to kernel/time for
+ * counter/timer interrupts on multiple CPU's
+ */
+ write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ));
+
+ /*
+ * Other CPUs should do profiling and process accounting
+ */
+ local_timer_interrupt(irq);
+ }
out:
+#endif /* CONFIG_MIPS_MT_SMTC */
+
irq_exit();
}
+
asmlinkage void ll_local_timer_interrupt(int irq)
{
irq_enter();
@@ -226,7 +291,7 @@ asmlinkage void ll_local_timer_interrupt(int irq)
kstat_this_cpu.irqs[irq]++;
/* we keep interrupt disabled all the time */
- local_timer_interrupt(irq, NULL);
+ local_timer_interrupt(irq);
irq_exit();
}
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
index 67a0718..1470318 100644
--- a/arch/mips/mips-boards/generic/time.c
+++ b/arch/mips/mips-boards/generic/time.c
@@ -75,101 +75,6 @@ extern int null_perf_irq(void);
extern int (*perf_irq)(void);
/*
- * Possibly handle a performance counter interrupt.
- * Return true if the timer interrupt should not be checked
- */
-static inline int handle_perf_irq (int r2)
-{
- /*
- * The performance counter overflow interrupt may be shared with the
- * timer interrupt (mipsxx_perfcount_irq < 0). If it is and a
- * performance counter has overflowed (perf_irq() == IRQ_HANDLED)
- * and we can't reliably determine if a counter interrupt has also
- * happened (!r2) then don't check for a timer interrupt.
- */
- return (mipsxx_perfcount_irq < 0) &&
- perf_irq() == IRQ_HANDLED &&
- !r2;
-}
-
-irqreturn_t mips_timer_interrupt(int irq, void *dev_id)
-{
- int cpu = smp_processor_id();
-
-#ifdef CONFIG_MIPS_MT_SMTC
- /*
- * In an SMTC system, one Count/Compare set exists per VPE.
- * Which TC within a VPE gets the interrupt is essentially
- * random - we only know that it shouldn't be one with
- * IXMT set. Whichever TC gets the interrupt needs to
- * send special interprocessor interrupts to the other
- * TCs to make sure that they schedule, etc.
- *
- * That code is specific to the SMTC kernel, not to
- * the a particular platform, so it's invoked from
- * the general MIPS timer_interrupt routine.
- */
-
- /*
- * We could be here due to timer interrupt,
- * perf counter overflow, or both.
- */
- (void) handle_perf_irq(1);
-
- if (read_c0_cause() & (1 << 30)) {
- /*
- * There are things we only want to do once per tick
- * in an "MP" system. One TC of each VPE will take
- * the actual timer interrupt. The others will get
- * timer broadcast IPIs. We use whoever it is that takes
- * the tick on VPE 0 to run the full timer_interrupt().
- */
- if (cpu_data[cpu].vpe_id == 0) {
- timer_interrupt(irq, NULL);
- } else {
- write_c0_compare(read_c0_count() +
- (mips_hpt_frequency/HZ));
- local_timer_interrupt(irq, dev_id);
- }
- smtc_timer_broadcast(cpu_data[cpu].vpe_id);
- }
-#else /* CONFIG_MIPS_MT_SMTC */
- int r2 = cpu_has_mips_r2;
-
- if (handle_perf_irq(r2))
- goto out;
-
- if (r2 && ((read_c0_cause() & (1 << 30)) == 0))
- goto out;
-
- if (cpu == 0) {
- /*
- * CPU 0 handles the global timer interrupt job and process
- * accounting resets count/compare registers to trigger next
- * timer int.
- */
- timer_interrupt(irq, NULL);
- } else {
- /* Everyone else needs to reset the timer int here as
- ll_local_timer_interrupt doesn't */
- /*
- * FIXME: need to cope with counter underflow.
- * More support needs to be added to kernel/time for
- * counter/timer interrupts on multiple CPU's
- */
- write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ));
-
- /*
- * Other CPUs should do profiling and process accounting
- */
- local_timer_interrupt(irq, dev_id);
- }
-out:
-#endif /* CONFIG_MIPS_MT_SMTC */
- return IRQ_HANDLED;
-}
-
-/*
* Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect
*/
static unsigned int __init estimate_cpu_frequency(void)
@@ -315,8 +220,6 @@ void __init plat_timer_setup(struct irqaction *irq)
mips_cpu_timer_irq = MIPSCPU_INT_BASE + hwint;
}
- /* we are using the cpu counter for timer interrupts */
- irq->handler = mips_timer_interrupt; /* we use our own handler */
#ifdef CONFIG_MIPS_MT_SMTC
setup_irq_smtc(mips_cpu_timer_irq, irq, 0x100 << hwint);
#else
diff --git a/arch/mips/mips-boards/sim/sim_time.c b/arch/mips/mips-boards/sim/sim_time.c
index f8b8dff..32f2097 100644
--- a/arch/mips/mips-boards/sim/sim_time.c
+++ b/arch/mips/mips-boards/sim/sim_time.c
@@ -25,75 +25,6 @@
unsigned long cpu_khz;
-irqreturn_t sim_timer_interrupt(int irq, void *dev_id)
-{
-#ifdef CONFIG_SMP
- int cpu = smp_processor_id();
-
- /*
- * CPU 0 handles the global timer interrupt job
- * resets count/compare registers to trigger next timer int.
- */
-#ifndef CONFIG_MIPS_MT_SMTC
- if (cpu == 0) {
- timer_interrupt(irq, dev_id);
- }
- else {
- /* Everyone else needs to reset the timer int here as
- ll_local_timer_interrupt doesn't */
- /*
- * FIXME: need to cope with counter underflow.
- * More support needs to be added to kernel/time for
- * counter/timer interrupts on multiple CPU's
- */
- write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ));
- }
-#else /* SMTC */
- /*
- * In SMTC system, one Count/Compare set exists per VPE.
- * Which TC within a VPE gets the interrupt is essentially
- * random - we only know that it shouldn't be one with
- * IXMT set. Whichever TC gets the interrupt needs to
- * send special interprocessor interrupts to the other
- * TCs to make sure that they schedule, etc.
- *
- * That code is specific to the SMTC kernel, not to
- * the simulation platform, so it's invoked from
- * the general MIPS timer_interrupt routine.
- *
- * We have a problem in that the interrupt vector code
- * had to turn off the timer IM bit to avoid redundant
- * entries, but we may never get to mips_cpu_irq_end
- * to turn it back on again if the scheduler gets
- * involved. So we clear the pending timer here,
- * and re-enable the mask...
- */
-
- int vpflags = dvpe();
- write_c0_compare (read_c0_count() - 1);
- clear_c0_cause(0x100 << MIPSCPU_INT_CPUCTR);
- set_c0_status(0x100 << MIPSCPU_INT_CPUCTR);
- irq_enable_hazard();
- evpe(vpflags);
-
- if(cpu_data[cpu].vpe_id == 0) timer_interrupt(irq, dev_id);
- else write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ));
- smtc_timer_broadcast(cpu_data[cpu].vpe_id);
-
-#endif /* CONFIG_MIPS_MT_SMTC */
-
- /*
- * every CPU should do profiling and process accounting
- */
- local_timer_interrupt (irq, dev_id);
- return IRQ_HANDLED;
-#else
- return timer_interrupt (irq, dev_id);
-#endif
-}
-
-
-
/*
* Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect
*/
@@ -188,7 +119,6 @@ void __init plat_timer_setup(struct irqaction *irq)
}
/* we are using the cpu counter for timer interrupts */
- irq->handler = sim_timer_interrupt;
setup_irq(mips_cpu_timer_irq, irq);
#ifdef CONFIG_SMP
diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c
index 1834832..790ccc5 100644
--- a/arch/mips/sgi-ip22/ip22-int.c
+++ b/arch/mips/sgi-ip22/ip22-int.c
@@ -204,7 +204,6 @@ static struct irqaction map1_cascade = {
#define SGI_INTERRUPTS SGINT_LOCAL3
#endif
-extern void indy_r4k_timer_interrupt(void);
extern void indy_8254timer_irq(void);
/*
@@ -243,7 +242,7 @@ asmlinkage void plat_irq_dispatch(void)
* First we check for r4k counter/timer IRQ.
*/
if (pending & CAUSEF_IP7)
- indy_r4k_timer_interrupt();
+ ll_timer_interrupt(SGI_TIMER_IRQ);
else if (pending & CAUSEF_IP2)
indy_local0_irqdispatch();
else if (pending & CAUSEF_IP3)
diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c
index 77f0c30..7f4e3b1 100644
--- a/arch/mips/sgi-ip22/ip22-time.c
+++ b/arch/mips/sgi-ip22/ip22-time.c
@@ -189,16 +189,6 @@ void indy_8254timer_irq(void)
irq_exit();
}
-void indy_r4k_timer_interrupt(void)
-{
- int irq = SGI_TIMER_IRQ;
-
- irq_enter();
- kstat_this_cpu.irqs[irq]++;
- timer_interrupt(irq, NULL);
- irq_exit();
-}
-
void __init plat_timer_setup(struct irqaction *irq)
{
/* over-write the handler, we use our own way */
diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c
index 6f3f71b..8519091 100644
--- a/arch/mips/sibyte/bcm1480/time.c
+++ b/arch/mips/sibyte/bcm1480/time.c
@@ -103,18 +103,7 @@ void bcm1480_timer_interrupt(void)
__raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS,
IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
- if (cpu == 0) {
- /*
- * CPU 0 handles the global timer interrupt job
- */
- ll_timer_interrupt(irq);
- }
- else {
- /*
- * other CPUs should just do profiling and process accounting
- */
- ll_local_timer_interrupt(irq);
- }
+ ll_timer_interrupt(irq);
}
static cycle_t bcm1480_hpt_read(void)
diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c
index 2efffe1..5bb83cd 100644
--- a/arch/mips/sibyte/sb1250/time.c
+++ b/arch/mips/sibyte/sb1250/time.c
@@ -125,18 +125,7 @@ void sb1250_timer_interrupt(void)
____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
- if (cpu == 0) {
- /*
- * CPU 0 handles the global timer interrupt job
- */
- ll_timer_interrupt(irq);
- }
- else {
- /*
- * other CPUs should just do profiling and process accounting
- */
- ll_local_timer_interrupt(irq);
- }
+ ll_timer_interrupt(irq);
}
/*
diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h
index 74ab331..9a49a93 100644
--- a/include/asm-mips/time.h
+++ b/include/asm-mips/time.h
@@ -63,13 +63,12 @@ extern irqreturn_t timer_interrupt(int irq, void *dev_id);
/*
* the corresponding low-level timer interrupt routine.
*/
-extern asmlinkage void ll_timer_interrupt(int irq);
+extern void ll_timer_interrupt(int irq);
/*
* profiling and process accouting is done separately in local_timer_interrupt
*/
-extern void local_timer_interrupt(int irq, void *dev_id);
-extern asmlinkage void ll_local_timer_interrupt(int irq);
+extern void local_timer_interrupt(int irq);
/*
* board specific routines required by time_init().
--
1.5.2.1
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH 5/5] Implement clockevents for R4000-style cp0 timer
2007-06-14 10:19 [RFD] Time rework [take #2] Franck Bui-Huu
` (3 preceding siblings ...)
2007-06-14 10:20 ` [PATCH 4/5] Consolidate all variants of MIPS cp0 timer interrupt handlers Franck Bui-Huu
@ 2007-06-14 10:20 ` Franck Bui-Huu
2007-06-14 12:29 ` Atsushi Nemoto
4 siblings, 1 reply; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-14 10:20 UTC (permalink / raw)
To: linux-mips
Signed-off-by: Franck Bui-Huu <fbuihuu@gmail.com>
---
arch/mips/Kconfig | 9 +
arch/mips/kernel/Makefile | 2 +
arch/mips/kernel/hpt.c | 294 ++++++++++++++++++++++++++
arch/mips/kernel/process.c | 2 +
arch/mips/kernel/smp.c | 1 +
arch/mips/kernel/time.c | 500 +++-----------------------------------------
arch/mips/lib/Makefile | 2 +-
arch/mips/lib/time.c | 52 +++++
include/asm-mips/hpt.h | 16 ++
include/asm-mips/time.h | 38 +----
10 files changed, 413 insertions(+), 503 deletions(-)
create mode 100644 arch/mips/kernel/hpt.c
create mode 100644 arch/mips/lib/time.c
create mode 100644 include/asm-mips/hpt.h
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 7bcf38d..af073f3 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -723,6 +723,14 @@ config GENERIC_TIME
bool
default y
+config GENERIC_CLOCKEVENTS
+ bool
+ default y
+
+config HPT_TIMER
+ bool
+ default y
+
config GENERIC_CMOS_UPDATE
bool
default y
@@ -1741,6 +1749,7 @@ config HZ
default 1000 if HZ_1000
default 1024 if HZ_1024
+source "kernel/time/Kconfig"
source "kernel/Kconfig.preempt"
config MIPS_INSANE_LARGE
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 4924626..7cc807c 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -11,6 +11,8 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \
binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \
irix5sys.o sysirix.o
+obj-$(CONFIG_HPT_TIMER) += hpt.o
+
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_MODULES) += mips_ksyms.o module.o
diff --git a/arch/mips/kernel/hpt.c b/arch/mips/kernel/hpt.c
new file mode 100644
index 0000000..0b5dbce
--- /dev/null
+++ b/arch/mips/kernel/hpt.c
@@ -0,0 +1,294 @@
+#include <linux/kernel_stat.h>
+#include <linux/spinlock.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+
+#include <asm/time.h>
+#include <asm/hpt.h>
+
+
+#define MIPS_HPT_NAME "MIPS-HPT"
+
+/*
+ * FIXME: Is it really needed ? Can it be 'static at least ?
+ */
+unsigned int mips_hpt_frequency __read_mostly;
+
+/*
+ * hpt can be disabled by boot command line
+ */
+static int hpt_disabled __initdata;
+
+static int __init nohpt_setup(char *str)
+{
+ hpt_disabled = 1;
+ return 0;
+}
+early_param("nohpt", nohpt_setup);
+
+/*
+ * cp0 hpt operations. Can be overriden by platform code
+ */
+void __weak mips_hpt_ack(void)
+{
+ write_c0_compare(read_c0_compare());
+}
+
+cycle_t __weak mips_hpt_read(void)
+{
+ return read_c0_count();
+}
+
+/*
+ * Clocksource
+ */
+struct clocksource hpt_clocksource = {
+ .name = MIPS_HPT_NAME,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .read = mips_hpt_read,
+};
+
+static int mips_hpt_rating(unsigned freq)
+{
+ return 200 + freq / 10000000;
+}
+
+static void __init setup_hpt_clocksource(unsigned freq)
+{
+ u64 mult;
+ unsigned shift = 0;
+
+ for (shift = 32; shift > 0; shift--) {
+ mult = (u64)NSEC_PER_SEC << shift;
+ do_div(mult, freq);
+ if ((mult >> 32) == 0)
+ break;
+ }
+
+ hpt_clocksource.shift = shift;
+ hpt_clocksource.mult = mult;
+ hpt_clocksource.rating = mips_hpt_rating(freq);
+
+ clocksource_register(&hpt_clocksource);
+}
+
+/*
+ * High precision timer functions for a R4k-compatible timer.
+ */
+
+static int mips_hpt_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ unsigned int cnt;
+
+ BUG_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
+
+ /* interrupt ack is done by setting up the next event */
+ cnt = read_c0_count();
+ cnt += delta;
+ write_c0_compare(cnt);
+
+ return ((long)(read_c0_count() - cnt ) > 0) ? -ETIME : 0;
+}
+
+static void mips_hpt_setup(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ /* nothing to do */
+}
+
+static struct clock_event_device hpt_clockevent = {
+ .name = MIPS_HPT_NAME,
+ .mode = CLOCK_EVT_MODE_UNUSED,
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .shift = 32,
+ .set_mode = mips_hpt_setup,
+ .set_next_event = mips_hpt_set_next_event,
+ .irq = -1,
+};
+
+static DEFINE_PER_CPU(struct clock_event_device, hpt_clock_events);
+
+static void __init finalize_hpt_clockevent(unsigned freq)
+{
+ hpt_clockevent.mult = div_sc(freq, NSEC_PER_SEC, 32);
+ hpt_clockevent.max_delta_ns = clockevent_delta2ns(-1, &hpt_clockevent);
+ hpt_clockevent.min_delta_ns = clockevent_delta2ns(+1, &hpt_clockevent);
+ hpt_clockevent.rating = mips_hpt_rating(freq);
+}
+
+void __init setup_hpt_clockevent(void)
+{
+ struct clock_event_device *cd;
+
+ if (hpt_disabled)
+ return;
+
+ cd = &__get_cpu_var(hpt_clock_events);
+
+ memcpy(cd, &hpt_clockevent, sizeof(*cd));
+ cd->cpumask = cpumask_of_cpu(smp_processor_id());
+
+ clockevents_register_device(cd);
+}
+
+/*
+ * Performance counter IRQ or -1 if shared with timer
+ */
+int mipsxx_perfcount_irq;
+
+int null_perf_irq(void)
+{
+ return 0;
+}
+
+int (*perf_irq)(void) = null_perf_irq;
+
+EXPORT_SYMBOL(mipsxx_perfcount_irq);
+EXPORT_SYMBOL(null_perf_irq);
+EXPORT_SYMBOL(perf_irq);
+
+/*
+ * Possibly handle a performance counter interrupt.
+ * Return true if the timer interrupt should not be checked
+ */
+static inline int handle_perf_irq (int r2)
+{
+ /*
+ * The performance counter overflow interrupt may be shared with the
+ * timer interrupt (mipsxx_perfcount_irq < 0). If it is and a
+ * performance counter has overflowed (perf_irq() == IRQ_HANDLED)
+ * and we can't reliably determine if a counter interrupt has also
+ * happened (!r2) then don't check for a timer interrupt.
+ */
+ return mipsxx_perfcount_irq < 0 &&
+ perf_irq() == IRQ_HANDLED &&
+ !r2;
+}
+
+static irqreturn_t hpt_interrupt(int irq, void *dev_id)
+{
+ const int r2 = cpu_has_mips_r2;
+ struct clock_event_device *cd;
+
+ /*
+ * Suckage alert:
+ * Before R2 of the architecture there was no way to see if a
+ * performance counter interrupt was pending, so we have to run
+ * the performance counter interrupt handler anyway.
+ */
+ if (handle_perf_irq(r2))
+ goto out;
+
+ /*
+ * The same applies to performance counter interrupts. But with the
+ * above we now know that the reason we got here must be a timer
+ * interrupt. Being the paranoiacs we are we check anyway.
+ */
+ if (!r2 || (read_c0_cause() & (1 << 30))) {
+ /*
+ * We always ack the counter since we never shuts it down.
+ * Therefore we can get interrupts whereas the hpt clock
+ * event device has been disabled.
+ */
+ mips_hpt_ack();
+
+ cd = &__get_cpu_var(hpt_clock_events);
+
+ if (cd->mode != CLOCK_EVT_MODE_SHUTDOWN)
+ cd->event_handler(cd);
+ }
+out:
+ return IRQ_HANDLED;
+}
+
+struct irqaction hpt_irqaction = {
+ .handler = hpt_interrupt,
+ .flags = IRQF_DISABLED | IRQF_PERCPU,
+ .name = MIPS_HPT_NAME,
+};
+
+
+/*
+ * These 2 functions are used by platforms which uses the hpt as
+ * timer.
+ */
+void __init setup_hpt_timer(unsigned freq, unsigned irq)
+{
+ if (!cpu_has_counter || hpt_disabled)
+ return;
+ if (freq == 0)
+ return;
+
+ BUG_ON(freq != mips_hpt_frequency);
+
+ finalize_hpt_clockevent(freq);
+ setup_hpt_clockevent();
+
+ /* Enable hpt interrupt. */
+ setup_irq(irq, &hpt_irqaction);
+
+ printk("Using %u.%03u MHz high precision timer.\n",
+ ((freq + 500) / 1000) / 1000,
+ ((freq + 500) / 1000) % 1000);
+}
+
+void __init setup_hpt_clock(unsigned freq)
+{
+ if (!cpu_has_counter || hpt_disabled)
+ return;
+ if (freq == 0)
+ return;
+
+ /* FIXME: shouldn't get rid of mips_hpt_frequency ? */
+ mips_hpt_frequency = freq;
+
+ setup_hpt_clocksource(freq);
+}
+
+/*
+ * If you don't know your hpt frequency and you have another
+ * timer you can use this helper to determinate the hpt freq.
+ */
+unsigned int __init calibrate_hpt(int (*timer_state)(void))
+{
+ cycle_t freq, start, end, count, hz;
+
+ const int loops = HZ / 10;
+ int log_2_loops = 0;
+ int i;
+
+ /*
+ * We want to calibrate for 0.1s, but to avoid a 64-bit
+ * division we round the number of loops up to the nearest
+ * power of 2.
+ */
+ while (loops > 1 << log_2_loops)
+ log_2_loops++;
+ i = 1 << log_2_loops;
+
+ /*
+ * Wait for a rising edge of the timer interrupt.
+ */
+ while (timer_state());
+ while (!timer_state());
+
+ /*
+ * Now see how many high precision timer ticks happen
+ * during the calculated number of periods between timer
+ * interrupts.
+ */
+ start = mips_hpt_read();
+ do {
+ while (timer_state());
+ while (!timer_state());
+ } while (--i);
+ end = mips_hpt_read();
+
+ count = end - start;
+ hz = HZ;
+ freq = count * hz;
+
+ return freq >> log_2_loops;
+}
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 6bdfb5a..b75aa6c 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -50,6 +50,7 @@ ATTRIB_NORET void cpu_idle(void)
{
/* endless idle loop with no priority at all */
while (1) {
+ tick_nohz_stop_sched_tick();
while (!need_resched()) {
#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG
extern void smtc_idle_loop_hook(void);
@@ -59,6 +60,7 @@ ATTRIB_NORET void cpu_idle(void)
if (cpu_wait)
(*cpu_wait)();
}
+ tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
schedule();
preempt_disable();
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 67edfa7..0d84d70 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -79,6 +79,7 @@ asmlinkage __cpuinit void start_secondary(void)
cpu_probe();
cpu_report();
per_cpu_trap_init();
+ setup_hpt_clockevent();
prom_init_secondary();
/*
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index a75d63b..3d0a575 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -1,507 +1,75 @@
-/*
- * Copyright 2001 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- * Copyright (c) 2003, 2004 Maciej W. Rozycki
- *
- * Common time service routines for MIPS machines. See
- * Documentation/mips/time.README.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/param.h>
-#include <linux/time.h>
-#include <linux/timex.h>
-#include <linux/smp.h>
#include <linux/kernel_stat.h>
#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <asm/bootinfo.h>
-#include <asm/cache.h>
-#include <asm/compiler.h>
-#include <asm/cpu.h>
-#include <asm/cpu-features.h>
-#include <asm/div64.h>
-#include <asm/sections.h>
#include <asm/time.h>
+#include <asm/hpt.h>
/*
- * The integer part of the number of usecs per jiffy is taken from tick,
- * but the fractional part is not recorded, so we calculate it using the
- * initial value of HZ. This aids systems where tick isn't really an
- * integer (e.g. for HZ = 128).
- */
-#define USECS_PER_JIFFY TICK_SIZE
-#define USECS_PER_JIFFY_FRAC ((unsigned long)(u32)((1000000ULL << 32) / HZ))
-
-#define TICK_SIZE (tick_nsec / 1000)
-
-/*
- * forward reference
+ * RTC. By default we provide the null RTC hooks
*/
DEFINE_SPINLOCK(rtc_lock);
+EXPORT_SYMBOL(rtc_lock);
-int __attribute__((weak)) rtc_mips_set_time(unsigned long sec)
-{
- return 0;
-}
-
-int __attribute__((weak)) rtc_mips_set_mmss(unsigned long nowtime)
-{
- return rtc_mips_set_time(nowtime);
-}
-
-int update_persistent_clock(struct timespec now)
-{
- return rtc_mips_set_mmss(now.tv_sec);
-}
-
-/* how many counter cycles in a jiffy */
-static unsigned long cycles_per_jiffy __read_mostly;
-
-/* expirelo is the count value for next CPU timer interrupt */
-static unsigned int expirelo;
-
-
-/*
- * Null timer ack for systems not needing one (e.g. i8254).
- */
-static void null_timer_ack(void) { /* nothing */ }
-
-/*
- * Null high precision timer functions for systems lacking one.
- */
-static cycle_t null_hpt_read(void)
+unsigned long __weak mips_rtc_get_time(void)
{
return 0;
}
-/*
- * Timer ack for an R4k-compatible timer of a known frequency.
- */
-static void c0_timer_ack(void)
+int __weak mips_rtc_set_time(unsigned long sec)
{
- unsigned int count;
-
- /* Ack this timer interrupt and set the next one. */
- expirelo += cycles_per_jiffy;
- write_c0_compare(expirelo);
-
- /* Check to see if we have missed any timer interrupts. */
- while (((count = read_c0_count()) - expirelo) < 0x7fffffff) {
- /* missed_timer_count++; */
- expirelo = count + cycles_per_jiffy;
- write_c0_compare(expirelo);
- }
+ return rtc_mips_set_time(sec);
}
-/*
- * High precision timer functions for a R4k-compatible timer.
- */
-static cycle_t c0_hpt_read(void)
-{
- return read_c0_count();
-}
+int __weak mips_rtc_set_mmss(unsigned long time)
+ {
+ return mips_rtc_set_time(time);
+ }
-/* For use both as a high precision timer and an interrupt source. */
-static void __init c0_hpt_timer_init(void)
+int update_persistent_clock(struct timespec now)
{
- expirelo = read_c0_count() + cycles_per_jiffy;
- write_c0_compare(expirelo);
+ return mips_rtc_set_mmss(now.tv_sec);
}
-int (*mips_timer_state)(void);
-void (*mips_timer_ack)(void);
-
+#if 0
/*
- * local_timer_interrupt() does profiling and process accounting
- * on a per-CPU basis.
- *
- * In UP mode, it is invoked from the (global) timer_interrupt.
- *
- * In SMP mode, it might invoked by per-CPU timer interrupt, or
- * a broadcasted inter-processor interrupt which itself is triggered
- * by the global timer interrupt.
+ * FIXME: we need to init rtc earlier since timekeeping_init()
+ * is called before time_init().
*/
-void local_timer_interrupt(int irq)
+unsigned long read_persistent_clock(void)
{
- profile_tick(CPU_PROFILING);
- update_process_times(user_mode(get_irq_regs()));
+ return mips_rtc_get_time();
}
+#endif
-/*
- * High-level timer interrupt service routines. This function
- * is set as irqaction->handler and is invoked through do_IRQ.
- */
-irqreturn_t timer_interrupt(int irq, void *dev_id)
+/* only during transition period */
+unsigned long rtc_mips_get_time(void)
{
- write_seqlock(&xtime_lock);
-
- mips_timer_ack();
-
- /*
- * call the generic timer interrupt handling
- */
- do_timer(1);
-
- write_sequnlock(&xtime_lock);
-
- /*
- * In UP mode, we call local_timer_interrupt() to do profiling
- * and process accouting.
- *
- * In SMP mode, local_timer_interrupt() is invoked by appropriate
- * low-level local timer interrupt handler.
- */
- local_timer_interrupt(irq);
-
- return IRQ_HANDLED;
+ return mips_rtc_get_time();
}
+EXPORT_SYMBOL(rtc_mips_get_time);
-int null_perf_irq(void)
+int rtc_mips_set_time(unsigned long sec)
{
- return 0;
-}
-
-EXPORT_SYMBOL(null_perf_irq);
-
-int (*perf_irq)(void) = null_perf_irq;
-
-EXPORT_SYMBOL(perf_irq);
-
-/*
- * Performance counter IRQ or -1 if shared with timer
- */
-int mipsxx_perfcount_irq;
-EXPORT_SYMBOL(mipsxx_perfcount_irq);
-
-/*
- * Possibly handle a performance counter interrupt.
- * Return true if the timer interrupt should not be checked
- */
-static inline int handle_perf_irq(int r2)
-{
- /*
- * The performance counter overflow interrupt may be shared with the
- * timer interrupt (mipsxx_perfcount_irq < 0). If it is and a
- * performance counter has overflowed (perf_irq() == IRQ_HANDLED)
- * and we can't reliably determine if a counter interrupt has also
- * happened (!r2) then don't check for a timer interrupt.
- */
- return (mipsxx_perfcount_irq < 0) &&
- perf_irq() == IRQ_HANDLED &&
- !r2;
-}
-
-extern void smtc_timer_broadcast(int);
-
-void ll_timer_interrupt(int irq)
-{
- int cpu = smp_processor_id();
- int r2 = cpu_has_mips_r2;
-
- irq_enter();
- kstat_this_cpu.irqs[irq]++;
-
-#ifdef CONFIG_MIPS_MT_SMTC
- /*
- * In an SMTC system, one Count/Compare set exists per VPE.
- * Which TC within a VPE gets the interrupt is essentially
- * random - we only know that it shouldn't be one with
- * IXMT set. Whichever TC gets the interrupt needs to
- * send special interprocessor interrupts to the other
- * TCs to make sure that they schedule, etc.
- *
- * That code is specific to the SMTC kernel, not to
- * the a particular platform, so it's invoked from
- * the general MIPS timer_interrupt routine.
- */
-
- /*
- * We could be here due to timer interrupt,
- * perf counter overflow, or both.
- */
- (void) handle_perf_irq(1);
-
- if (read_c0_cause() & (1 << 30)) {
- /*
- * There are things we only want to do once per tick
- * in an "MP" system. One TC of each VPE will take
- * the actual timer interrupt. The others will get
- * timer broadcast IPIs. We use whoever it is that takes
- * the tick on VPE 0 to run the full timer_interrupt().
- */
- if (cpu_data[cpu].vpe_id == 0) {
- timer_interrupt(irq, NULL);
- } else {
- write_c0_compare(read_c0_count() +
- (mips_hpt_frequency/HZ));
- local_timer_interrupt(irq);
- }
- smtc_timer_broadcast(cpu_data[cpu].vpe_id);
- }
-#else /* CONFIG_MIPS_MT_SMTC */
- if (handle_perf_irq(r2))
- goto out;
-
- if (r2 && ((read_c0_cause() & (1 << 30)) == 0))
- goto out;
-
- if (cpu == 0) {
- /*
- * CPU 0 handles the global timer interrupt job and process
- * accounting resets count/compare registers to trigger next
- * timer int.
- */
- timer_interrupt(irq, NULL);
- } else {
- /* Everyone else needs to reset the timer int here as
- ll_local_timer_interrupt doesn't */
- /*
- * FIXME: need to cope with counter underflow.
- * More support needs to be added to kernel/time for
- * counter/timer interrupts on multiple CPU's
- */
- write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ));
-
- /*
- * Other CPUs should do profiling and process accounting
- */
- local_timer_interrupt(irq);
- }
-out:
-#endif /* CONFIG_MIPS_MT_SMTC */
-
- irq_exit();
-}
-
-
-asmlinkage void ll_local_timer_interrupt(int irq)
-{
- irq_enter();
- if (smp_processor_id() != 0)
- kstat_this_cpu.irqs[irq]++;
-
- /* we keep interrupt disabled all the time */
- local_timer_interrupt(irq);
-
- irq_exit();
+ return mips_rtc_set_time(sec);
}
+EXPORT_SYMBOL(rtc_mips_set_time);
/*
- * time_init() - it does the following things.
- *
- * 1) plat_time_init() -
- * a) (optional) set up RTC routines,
- * b) (optional) calibrate and set the mips_hpt_frequency
- * (only needed if you intended to use cpu counter as timer interrupt
- * source)
- * 2) calculate a couple of cached variables for later usage
- * 3) plat_timer_setup() -
- * a) (optional) over-write any choices made above by time_init().
- * b) machine specific code should setup the timer irqaction.
- * c) enable the timer interrupt
+ * Basically it calls platform hooks to set up
+ * a) RTC
+ * b) a timer
*/
-
-unsigned int mips_hpt_frequency;
-
-static struct irqaction timer_irqaction = {
- .handler = timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_PERCPU,
- .name = "timer",
-};
-
-static unsigned int __init calibrate_hpt(void)
-{
- cycle_t frequency, hpt_start, hpt_end, hpt_count, hz;
-
- const int loops = HZ / 10;
- int log_2_loops = 0;
- int i;
-
- /*
- * We want to calibrate for 0.1s, but to avoid a 64-bit
- * division we round the number of loops up to the nearest
- * power of 2.
- */
- while (loops > 1 << log_2_loops)
- log_2_loops++;
- i = 1 << log_2_loops;
-
- /*
- * Wait for a rising edge of the timer interrupt.
- */
- while (mips_timer_state());
- while (!mips_timer_state());
-
- /*
- * Now see how many high precision timer ticks happen
- * during the calculated number of periods between timer
- * interrupts.
- */
- hpt_start = clocksource_mips.read();
- do {
- while (mips_timer_state());
- while (!mips_timer_state());
- } while (--i);
- hpt_end = clocksource_mips.read();
-
- hpt_count = (hpt_end - hpt_start) & clocksource_mips.mask;
- hz = HZ;
- frequency = hpt_count * hz;
-
- return frequency >> log_2_loops;
-}
-
-struct clocksource clocksource_mips = {
- .name = "MIPS",
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static void __init init_mips_clocksource(void)
-{
- u64 temp;
- u32 shift;
-
- if (!mips_hpt_frequency || clocksource_mips.read == null_hpt_read)
- return;
-
- /* Calclate a somewhat reasonable rating value */
- clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
- /* Find a shift value */
- for (shift = 32; shift > 0; shift--) {
- temp = (u64) NSEC_PER_SEC << shift;
- do_div(temp, mips_hpt_frequency);
- if ((temp >> 32) == 0)
- break;
- }
- clocksource_mips.shift = shift;
- clocksource_mips.mult = (u32)temp;
-
- clocksource_register(&clocksource_mips);
-}
-
-void __init __weak plat_time_init(void)
-{
-}
-
void __init time_init(void)
{
- plat_time_init();
-
- /* Choose appropriate high precision timer routines. */
- if (!cpu_has_counter && !clocksource_mips.read)
- /* No high precision timer -- sorry. */
- clocksource_mips.read = null_hpt_read;
- else if (!mips_hpt_frequency && !mips_timer_state) {
- /* A high precision timer of unknown frequency. */
- if (!clocksource_mips.read)
- /* No external high precision timer -- use R4k. */
- clocksource_mips.read = c0_hpt_read;
- } else {
- /* We know counter frequency. Or we can get it. */
- if (!clocksource_mips.read) {
- /* No external high precision timer -- use R4k. */
- clocksource_mips.read = c0_hpt_read;
-
- if (!mips_timer_state) {
- /* No external timer interrupt -- use R4k. */
- mips_timer_ack = c0_timer_ack;
- /* Calculate cache parameters. */
- cycles_per_jiffy =
- (mips_hpt_frequency + HZ / 2) / HZ;
- /*
- * This sets up the high precision
- * timer for the first interrupt.
- */
- c0_hpt_timer_init();
- }
- }
- if (!mips_hpt_frequency)
- mips_hpt_frequency = calibrate_hpt();
-
- /* Report the high precision timer rate for a reference. */
- printk("Using %u.%03u MHz high precision timer.\n",
- ((mips_hpt_frequency + 500) / 1000) / 1000,
- ((mips_hpt_frequency + 500) / 1000) % 1000);
- }
-
- if (!mips_timer_ack)
- /* No timer interrupt ack (e.g. i8254). */
- mips_timer_ack = null_timer_ack;
-
/*
- * Call board specific timer interrupt setup.
- *
- * this pointer must be setup in machine setup routine.
- *
- * Even if a machine chooses to use a low-level timer interrupt,
- * it still needs to setup the timer_irqaction.
- * In that case, it might be better to set timer_irqaction.handler
- * to be NULL function so that we are sure the high-level code
- * is not invoked accidentally.
+ * Mandatory platform hook. It basically setup the RTC.
+ * FIXME: shouldn't we call these before calling
+ * timekeeping_init() ?
*/
- plat_timer_setup(&timer_irqaction);
-
- init_mips_clocksource();
-}
-
-#define FEBRUARY 2
-#define STARTOFTIME 1970
-#define SECDAY 86400L
-#define SECYR (SECDAY * 365)
-#define leapyear(y) ((!((y) % 4) && ((y) % 100)) || !((y) % 400))
-#define days_in_year(y) (leapyear(y) ? 366 : 365)
-#define days_in_month(m) (month_days[(m) - 1])
-
-static int month_days[12] = {
- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-
-void to_tm(unsigned long tim, struct rtc_time *tm)
-{
- long hms, day, gday;
- int i;
-
- gday = day = tim / SECDAY;
- hms = tim % SECDAY;
-
- /* Hours, minutes, seconds are easy */
- tm->tm_hour = hms / 3600;
- tm->tm_min = (hms % 3600) / 60;
- tm->tm_sec = (hms % 3600) % 60;
-
- /* Number of years in days */
- for (i = STARTOFTIME; day >= days_in_year(i); i++)
- day -= days_in_year(i);
- tm->tm_year = i;
-
- /* Number of months in days left */
- if (leapyear(tm->tm_year))
- days_in_month(FEBRUARY) = 29;
- for (i = 1; day >= days_in_month(i); i++)
- day -= days_in_month(i);
- days_in_month(FEBRUARY) = 28;
- tm->tm_mon = i - 1; /* tm_mon starts from 0 to 11 */
-
- /* Days are what is left over (+1) from all that. */
- tm->tm_mday = day + 1;
+ plat_time_init();
/*
- * Determine the day of week
+ * Platform can setup a new timer, hpt timer or both...
*/
- tm->tm_wday = (gday + 4) % 7; /* 1970/1/1 was Thursday */
+ plat_timer_setup();
}
-
-EXPORT_SYMBOL(rtc_lock);
-EXPORT_SYMBOL(to_tm);
-EXPORT_SYMBOL(rtc_mips_set_time);
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index 5dad13e..447e803 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -3,7 +3,7 @@
#
lib-y += csum_partial.o memcpy.o memcpy-inatomic.o memset.o strlen_user.o \
- strncpy_user.o strnlen_user.o uncached.o
+ strncpy_user.o strnlen_user.o time.o uncached.o
obj-y += iomap.o
obj-$(CONFIG_PCI) += iomap-pci.o
diff --git a/arch/mips/lib/time.c b/arch/mips/lib/time.c
new file mode 100644
index 0000000..e561050
--- /dev/null
+++ b/arch/mips/lib/time.c
@@ -0,0 +1,52 @@
+#include <asm/time.h>
+
+/*
+ * to_tm(). FIXME: should be shared with all archs...
+ */
+#define FEBRUARY 2
+#define STARTOFTIME 1970
+#define SECDAY 86400L
+#define SECYR (SECDAY * 365)
+#define leapyear(y) ((!((y) % 4) && ((y) % 100)) || !((y) % 400))
+#define days_in_year(y) (leapyear(y) ? 366 : 365)
+#define days_in_month(m) (month_days[(m) - 1])
+
+static int month_days[12] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+void to_tm(unsigned long tim, struct rtc_time *tm)
+{
+ long hms, day, gday;
+ int i;
+
+ gday = day = tim / SECDAY;
+ hms = tim % SECDAY;
+
+ /* Hours, minutes, seconds are easy */
+ tm->tm_hour = hms / 3600;
+ tm->tm_min = (hms % 3600) / 60;
+ tm->tm_sec = (hms % 3600) % 60;
+
+ /* Number of years in days */
+ for (i = STARTOFTIME; day >= days_in_year(i); i++)
+ day -= days_in_year(i);
+ tm->tm_year = i;
+
+ /* Number of months in days left */
+ if (leapyear(tm->tm_year))
+ days_in_month(FEBRUARY) = 29;
+ for (i = 1; day >= days_in_month(i); i++)
+ day -= days_in_month(i);
+ days_in_month(FEBRUARY) = 28;
+ tm->tm_mon = i - 1; /* tm_mon starts from 0 to 11 */
+
+ /* Days are what is left over (+1) from all that. */
+ tm->tm_mday = day + 1;
+
+ /*
+ * Determine the day of week
+ */
+ tm->tm_wday = (gday + 4) % 7; /* 1970/1/1 was Thursday */
+}
+EXPORT_SYMBOL(to_tm);
diff --git a/include/asm-mips/hpt.h b/include/asm-mips/hpt.h
new file mode 100644
index 0000000..08f7650
--- /dev/null
+++ b/include/asm-mips/hpt.h
@@ -0,0 +1,16 @@
+#ifndef _ASM_HPT_H
+#define _ASM_HPT_H
+
+/*
+ * mips_hpt_frequency - must be set if you intend to use an R4k-compatible
+ * counter as a timer interrupt source; otherwise it can be set up
+ * automagically with an aid of mips_timer_state.
+ */
+extern unsigned int mips_hpt_frequency;
+
+
+extern void setup_hpt_clock(unsigned freq);
+extern void setup_hpt_timer(unsigned freq, unsigned irq);
+extern unsigned calibrate_hpt(int (*timer_state)(void));
+
+#endif /* _ASM_HPT_H */
diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h
index 9a49a93..e63e51a 100644
--- a/include/asm-mips/time.h
+++ b/include/asm-mips/time.h
@@ -16,12 +16,7 @@
#ifndef _ASM_TIME_H
#define _ASM_TIME_H
-#include <linux/interrupt.h>
-#include <linux/linkage.h>
-#include <linux/ptrace.h>
#include <linux/rtc.h>
-#include <linux/spinlock.h>
-#include <linux/clocksource.h>
extern spinlock_t rtc_lock;
@@ -43,12 +38,6 @@ extern int (*mips_timer_state)(void);
extern void (*mips_timer_ack)(void);
/*
- * High precision timer clocksource.
- * If .read is NULL, an R4k-compatible timer setup is attempted.
- */
-extern struct clocksource clocksource_mips;
-
-/*
* to_tm() converts system time back to (year, mon, day, hour, min, sec).
* It is intended to help implement rtc_set_time() functions.
* Copied from PPC implementation.
@@ -56,32 +45,9 @@ extern struct clocksource clocksource_mips;
extern void to_tm(unsigned long tim, struct rtc_time *tm);
/*
- * high-level timer interrupt routines.
- */
-extern irqreturn_t timer_interrupt(int irq, void *dev_id);
-
-/*
- * the corresponding low-level timer interrupt routine.
+ * board specific hooks called by time_init().
*/
-extern void ll_timer_interrupt(int irq);
-
-/*
- * profiling and process accouting is done separately in local_timer_interrupt
- */
-extern void local_timer_interrupt(int irq);
-
-/*
- * board specific routines required by time_init().
- */
-struct irqaction;
extern void plat_time_init(void);
-extern void plat_timer_setup(struct irqaction *irq);
-
-/*
- * mips_hpt_frequency - must be set if you intend to use an R4k-compatible
- * counter as a timer interrupt source; otherwise it can be set up
- * automagically with an aid of mips_timer_state.
- */
-extern unsigned int mips_hpt_frequency;
+extern void plat_timer_setup(void);
#endif /* _ASM_TIME_H */
--
1.5.2.1
^ permalink raw reply related [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-14 10:19 ` [PATCH 3/5] Deforest the function pointer jungle in the time code Franck Bui-Huu
@ 2007-06-14 11:17 ` Thomas Bogendoerfer
2007-06-14 13:43 ` Franck Bui-Huu
0 siblings, 1 reply; 56+ messages in thread
From: Thomas Bogendoerfer @ 2007-06-14 11:17 UTC (permalink / raw)
To: Franck Bui-Huu; +Cc: linux-mips, Ralf Baechle
On Thu, Jun 14, 2007 at 12:19:59PM +0200, Franck Bui-Huu wrote:
> arch/mips/sni/a20r.c | 1 -
> arch/mips/sni/ds1216.c | 4 +-
> arch/mips/sni/pcimt.c | 3 -
> arch/mips/sni/pcit.c | 3 -
> arch/mips/sni/rm200.c | 2 -
> arch/mips/sni/time.c | 2 +-
the SNI part is broken and can't work that way.
1. SNI used two different RTC chips (ds126 and mc146818) and it's no big
deal support them in just one kernel with the current framework
2. One line of SNI machines (a20r) can't use the cp0 counter, so it's not
a really good idea to calibrate it
Thomas.
--
Crap can work. Given enough thrust pigs will fly, but it's not necessary a
good idea. [ RFC1925, 2.3 ]
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 5/5] Implement clockevents for R4000-style cp0 timer
2007-06-14 10:20 ` [PATCH 5/5] Implement clockevents for R4000-style cp0 timer Franck Bui-Huu
@ 2007-06-14 12:29 ` Atsushi Nemoto
2007-06-14 13:00 ` Franck Bui-Huu
2007-06-17 0:04 ` Ralf Baechle
0 siblings, 2 replies; 56+ messages in thread
From: Atsushi Nemoto @ 2007-06-14 12:29 UTC (permalink / raw)
To: vagabon.xyz; +Cc: linux-mips
On Thu, 14 Jun 2007 12:20:01 +0200, Franck Bui-Huu <vagabon.xyz@gmail.com> wrote:
> create mode 100644 arch/mips/lib/time.c
I think this to_tm() cleanup should be done in separate patch.
Maybe selecting RTC_LIB in Kconfig and replace all to_tm() calls with
rtc_time_to_tm(tim, tm);
tm->tm_year += 1900;
would be enough.
---
Atsushi Nemoto
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 5/5] Implement clockevents for R4000-style cp0 timer
2007-06-14 12:29 ` Atsushi Nemoto
@ 2007-06-14 13:00 ` Franck Bui-Huu
2007-06-17 0:04 ` Ralf Baechle
1 sibling, 0 replies; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-14 13:00 UTC (permalink / raw)
To: Atsushi Nemoto; +Cc: linux-mips
Hi Atsushi,
On 6/14/07, Atsushi Nemoto <anemo@mba.ocn.ne.jp> wrote:
> On Thu, 14 Jun 2007 12:20:01 +0200, Franck Bui-Huu <vagabon.xyz@gmail.com> wrote:
> > create mode 100644 arch/mips/lib/time.c
>
> I think this to_tm() cleanup should be done in separate patch.
>
I think so.
Actually that was something Ralf already did and I wanted to reuse.
I'll do that but for now I would like to know if this patch is the
right way to go...
Anyway thanks for noticing.
> Maybe selecting RTC_LIB in Kconfig and replace all to_tm() calls with
>
> rtc_time_to_tm(tim, tm);
> tm->tm_year += 1900;
>
> would be enough.
>
I dunno, but I think that could be part of another patchset if you don't mind.
--
Franck
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-14 11:17 ` Thomas Bogendoerfer
@ 2007-06-14 13:43 ` Franck Bui-Huu
2007-06-14 14:09 ` Maciej W. Rozycki
0 siblings, 1 reply; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-14 13:43 UTC (permalink / raw)
To: Thomas Bogendoerfer; +Cc: linux-mips, Ralf Baechle
Hi,
On 6/14/07, Thomas Bogendoerfer <tsbogend@alpha.franken.de> wrote:
> On Thu, Jun 14, 2007 at 12:19:59PM +0200, Franck Bui-Huu wrote:
> > arch/mips/sni/a20r.c | 1 -
> > arch/mips/sni/ds1216.c | 4 +-
> > arch/mips/sni/pcimt.c | 3 -
> > arch/mips/sni/pcit.c | 3 -
> > arch/mips/sni/rm200.c | 2 -
> > arch/mips/sni/time.c | 2 +-
>
> the SNI part is broken and can't work that way.
>
I don't get you there. Are you talking about patch 3/5 (you're
replying on this one) or the patch 5/5 ?
patch #3 is only clean up, so it shouldn't break anything....
patch #5 does not migrate any platforms, so it's actually broken for
all current platforms.
> 1. SNI used two different RTC chips (ds126 and mc146818) and it's no big
> deal support them in just one kernel with the current framework
That's the point now, if the current implementation can fit well with
all platforms.
> 2. One line of SNI machines (a20r) can't use the cp0 counter, so it's not
> a really good idea to calibrate it
>
The current code doesn't automatically calibrate any hpt. It was
really hard to guess which ones need that so now if you need to
calibrate your hpt, then you have to call calibrate_hpt().
Thanks
--
Franck
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-14 13:43 ` Franck Bui-Huu
@ 2007-06-14 14:09 ` Maciej W. Rozycki
2007-06-14 14:31 ` Franck Bui-Huu
2007-06-14 15:52 ` Franck Bui-Huu
0 siblings, 2 replies; 56+ messages in thread
From: Maciej W. Rozycki @ 2007-06-14 14:09 UTC (permalink / raw)
To: Franck Bui-Huu; +Cc: Thomas Bogendoerfer, linux-mips, Ralf Baechle
On Thu, 14 Jun 2007, Franck Bui-Huu wrote:
> The current code doesn't automatically calibrate any hpt. It was
> really hard to guess which ones need that so now if you need to
> calibrate your hpt, then you have to call calibrate_hpt().
You are wrong -- calibration is currently automatic if a platform
provides a HPT, but has not set up its frequency:
if (!mips_hpt_frequency)
mips_hpt_frequency = calibrate_hpt();
Which should normally be the case unless there is no way to do
calibration, when a platform can provide a hardcoded value. There is
nothing to guess here.
I'll have a look at your patches, but I hope you have got about the most
interesting configuration right, which is the DEC platform, where you can
have one of these:
1. No HPT at all.
2. HPT in the chipset.
3. HPT in CP0.
depending on the configuration as determined at the run time, with no
predefined frequency in the cases #2 and #3.
Maciej
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-14 14:09 ` Maciej W. Rozycki
@ 2007-06-14 14:31 ` Franck Bui-Huu
2007-06-14 16:33 ` Maciej W. Rozycki
2007-06-14 15:52 ` Franck Bui-Huu
1 sibling, 1 reply; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-14 14:31 UTC (permalink / raw)
To: Maciej W. Rozycki; +Cc: Thomas Bogendoerfer, linux-mips, Ralf Baechle
Hi,
On 6/14/07, Maciej W. Rozycki <macro@linux-mips.org> wrote:
> On Thu, 14 Jun 2007, Franck Bui-Huu wrote:
>
> > The current code doesn't automatically calibrate any hpt. It was
> > really hard to guess which ones need that so now if you need to
> > calibrate your hpt, then you have to call calibrate_hpt().
>
> You are wrong -- calibration is currently automatic if a platform
> provides a HPT, but has not set up its frequency:
Well it all depends on what you call "current" code... My own fault I
should have said "new" instead of "current", sorry.
> Which should normally be the case unless there is no way to do
> calibration, when a platform can provide a hardcoded value. There is
> nothing to guess here.
>
Are you sure it's the normal case? I would say that only DEC needs
that calibration:
Doing the following on the _current_ tree:
$ git grep -l mips_timer_state arch/mips
arch/mips/dec/time.c
arch/mips/kernel/time.c
> I'll have a look at your patches, but I hope you have got about the most
> interesting configuration right, which is the DEC platform, where you can
> have one of these:
As I said, all platforms haven't been migrated, but DEC seems an
interesting one to migrate. I'll try to do it and see if you can
accept such changes.
>
> 1. No HPT at all.
>
> 2. HPT in the chipset.
>
> 3. HPT in CP0.
>
> depending on the configuration as determined at the run time, with no
> predefined frequency in the cases #2 and #3.
>
Good to know.
Thanks
--
Franck
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-14 14:09 ` Maciej W. Rozycki
2007-06-14 14:31 ` Franck Bui-Huu
@ 2007-06-14 15:52 ` Franck Bui-Huu
2007-06-14 16:45 ` Maciej W. Rozycki
1 sibling, 1 reply; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-14 15:52 UTC (permalink / raw)
To: Maciej W. Rozycki; +Cc: Thomas Bogendoerfer, linux-mips, Ralf Baechle
Maciej W. Rozycki wrote:
> I'll have a look at your patches, but I hope you have got about the most
> interesting configuration right, which is the DEC platform
hmm, I looked at arch/mips/dec/time.c, and I'm not sure to understand it.
Could you give me more info ?
To be sure we're taking about the same thing, I'm calling "hpt" the timer
in CP0 _only_. If you have others timers let's call them "timer".
> where you can have one of these:
>
> 1. No HPT at all.
>
What's generating the tick interrupt in this case ?
> 2. HPT in the chipset.
>
What do you mean by chipset ? the DS1287 ?
> 3. HPT in CP0.
>
Reading the dec code, it seems that whatever the case, you don't use
the hpt cp0 as tick interrupt source. It's only use as a clock source.
If so, why ?
--
Franck
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-14 14:31 ` Franck Bui-Huu
@ 2007-06-14 16:33 ` Maciej W. Rozycki
2007-06-14 16:54 ` Maciej W. Rozycki
2007-06-15 8:59 ` Franck Bui-Huu
0 siblings, 2 replies; 56+ messages in thread
From: Maciej W. Rozycki @ 2007-06-14 16:33 UTC (permalink / raw)
To: Franck Bui-Huu; +Cc: Thomas Bogendoerfer, linux-mips, Ralf Baechle
On Thu, 14 Jun 2007, Franck Bui-Huu wrote:
> > Which should normally be the case unless there is no way to do
> > calibration, when a platform can provide a hardcoded value. There is
> > nothing to guess here.
> >
>
> Are you sure it's the normal case? I would say that only DEC needs
> that calibration:
>
> Doing the following on the _current_ tree:
>
> $ git grep -l mips_timer_state arch/mips
> arch/mips/dec/time.c
> arch/mips/kernel/time.c
Well, many platforms have some sort of external timer interrupt sources
(like an 8254 or an DS1287 or even a more sophisticated timer; sometimes
integrated in the south bridge and collecting dust there), but people tend
to follow the path of least resistance and use the CP0 timer, even though
it is is a valuable resource that may be used for some other purposes. I
think the issue has been raised here many times already. The CP0 timer
has its problems too as it is one-shot only and needs complicated recovery
if an interrupt is missed -- see c0_timer_ack().
Please note that this generic calibration code may be used for
calibrating the CP0 timer too -- all that you need is defining
mips_timer_state appropriately, i.e. to flip at the HZ rate (it may be
based on one of the south bridge choices mentioned above or some
free-running counter for example), but people seem to prefer to write
their own code for some reason. ;-)
> > 1. No HPT at all.
> >
> > 2. HPT in the chipset.
> >
> > 3. HPT in CP0.
> >
> > depending on the configuration as determined at the run time, with no
> > predefined frequency in the cases #2 and #3.
> >
>
> Good to know.
And FYI for DEC CP0 is meant to be the last resort (current code does not
get it exactly right, I know -- I forgot to look at it at some point) as
there is exactly one platform that has no HPT in the chipset and uses an
R4k processor at the same time (the 5000/150 for those that care -- the
free-running counter was added in a later revision of the IOASIC). All
the others either have a HPT in the chipset or only support R3k-class
processors with no CP0 timer.
Maciej
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-14 15:52 ` Franck Bui-Huu
@ 2007-06-14 16:45 ` Maciej W. Rozycki
0 siblings, 0 replies; 56+ messages in thread
From: Maciej W. Rozycki @ 2007-06-14 16:45 UTC (permalink / raw)
To: Franck Bui-Huu; +Cc: Thomas Bogendoerfer, linux-mips, Ralf Baechle
On Thu, 14 Jun 2007, Franck Bui-Huu wrote:
> > I'll have a look at your patches, but I hope you have got about the most
> > interesting configuration right, which is the DEC platform
>
> hmm, I looked at arch/mips/dec/time.c, and I'm not sure to understand it.
> Could you give me more info ?
Whatever you like!
> To be sure we're taking about the same thing, I'm calling "hpt" the timer
> in CP0 _only_. If you have others timers let's call them "timer".
We can agree on it for the purpose of this consideration, but otherwise
HPT is meant to mean a High-Precision Counter, that is a counter that
improves the resolution (precision) of that given by the timer interrupt
itself. This is how current code interpretes the name too.
> > where you can have one of these:
> >
> > 1. No HPT at all.
> >
>
> What's generating the tick interrupt in this case ?
For DEC an external DS1287 is always the timer interrupt source. In this
case this is the resolution you can get from gettimeofday() -- not
terribly impressive.
> > 2. HPT in the chipset.
> >
>
> What do you mean by chipset ? the DS1287 ?
This is one of the motherboard components, called IOASIC. Starting from
a certain revision this chip includes a 32-bit free-running counter
(timer) that is clocked from the TURBOchannel (the peripheral bus used in
these systems) clock, which varies across systems, but is somewhere
between 12.5MHz and 25MHz.
Obviously the DS1287 does not include any kind of readable timer that
could improve the resolution of the timer interrupt -- otherwise this
whole complication would be a non-issue.
> > 3. HPT in CP0.
> >
>
> Reading the dec code, it seems that whatever the case, you don't use
> the hpt cp0 as tick interrupt source. It's only use as a clock source.
> If so, why ?
That is correct and there is no reason to use the CP0 timer interrupt as
it has its issues (as mentioned in the other mail) and all the DEC systems
that we support have a DS1287 chip that can generate a timer interrupt
just fine. The CP0 counter register is only used as a 32-bit free-running
counter (timer) to improve the resolution of time recorded by timer
interrupts.
Maciej
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-14 16:33 ` Maciej W. Rozycki
@ 2007-06-14 16:54 ` Maciej W. Rozycki
2007-06-15 8:59 ` Franck Bui-Huu
1 sibling, 0 replies; 56+ messages in thread
From: Maciej W. Rozycki @ 2007-06-14 16:54 UTC (permalink / raw)
To: Franck Bui-Huu; +Cc: Thomas Bogendoerfer, linux-mips, Ralf Baechle
On Thu, 14 Jun 2007, Maciej W. Rozycki wrote:
> Please note that this generic calibration code may be used for
> calibrating the CP0 timer too -- all that you need is defining
> mips_timer_state appropriately, i.e. to flip at the HZ rate (it may be
> based on one of the south bridge choices mentioned above or some
> free-running counter for example), but people seem to prefer to write
> their own code for some reason. ;-)
To clarify myself -- the return value of mips_timer_state() has to flip
regularly, once each way per HZ. The duty cycle does not have to be 50%
-- any will do.
Maciej
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-14 16:33 ` Maciej W. Rozycki
2007-06-14 16:54 ` Maciej W. Rozycki
@ 2007-06-15 8:59 ` Franck Bui-Huu
2007-06-15 11:07 ` Maciej W. Rozycki
2007-06-15 13:49 ` Ralf Baechle
1 sibling, 2 replies; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-15 8:59 UTC (permalink / raw)
To: Maciej W. Rozycki; +Cc: Thomas Bogendoerfer, linux-mips, Ralf Baechle
Hi,
Maciej W. Rozycki wrote:
>
> Well, many platforms have some sort of external timer interrupt sources
> (like an 8254 or an DS1287 or even a more sophisticated timer; sometimes
> integrated in the south bridge and collecting dust there), but people tend
> to follow the path of least resistance and use the CP0 timer, even though
> it is is a valuable resource that may be used for some other purposes. I
Which other purposes ? CP0 hpt gives generally the highest precision for
a given platform, and it seems to be your case too. I don't see which other
better purpose it can deserve other than hrtimer, tick interrupt...
> think the issue has been raised here many times already. The CP0 timer
> has its problems too as it is one-shot only and needs complicated recovery
> if an interrupt is missed -- see c0_timer_ack().
Well I would say that because it's one-shot, it's a good timer to choose.
I don't see how you can have hrtimer support if you choose a periodic
timer...
And missed interrupts doens't seem a big deal, and the new kernel time
subsystem handle them for us already.
>
> Please note that this generic calibration code may be used for
> calibrating the CP0 timer too -- all that you need is defining
Actually the current patchset breaks it since it changes the calibration
code to be used only for the cp0 hpt calibration. I'll change that.
> mips_timer_state appropriately, i.e. to flip at the HZ rate (it may be
> based on one of the south bridge choices mentioned above or some
> free-running counter for example), but people seem to prefer to write
> their own code for some reason. ;-)
Do you have any examples in mind which rewrite their own calibration
code ? I'm too lazy to search into all board code.
>
>>> 1. No HPT at all.
>>>
>>> 2. HPT in the chipset.
>>>
>>> 3. HPT in CP0.
>>>
>>> depending on the configuration as determined at the run time, with no
>>> predefined frequency in the cases #2 and #3.
>>>
>> Good to know.
>
> And FYI for DEC CP0 is meant to be the last resort (current code does not
Again IMHO it should be the first choice if possible.
--
Franck
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-15 8:59 ` Franck Bui-Huu
@ 2007-06-15 11:07 ` Maciej W. Rozycki
2007-06-15 13:26 ` Ralf Baechle
2007-06-15 14:35 ` Sergei Shtylyov
2007-06-15 13:49 ` Ralf Baechle
1 sibling, 2 replies; 56+ messages in thread
From: Maciej W. Rozycki @ 2007-06-15 11:07 UTC (permalink / raw)
To: Franck Bui-Huu; +Cc: Thomas Bogendoerfer, linux-mips, Ralf Baechle
On Fri, 15 Jun 2007, Franck Bui-Huu wrote:
> > Well, many platforms have some sort of external timer interrupt sources
> > (like an 8254 or an DS1287 or even a more sophisticated timer; sometimes
> > integrated in the south bridge and collecting dust there), but people tend
> > to follow the path of least resistance and use the CP0 timer, even though
> > it is is a valuable resource that may be used for some other purposes. I
>
> Which other purposes ? CP0 hpt gives generally the highest precision for
> a given platform, and it seems to be your case too. I don't see which other
> better purpose it can deserve other than hrtimer, tick interrupt...
One better purpose could be using it as a backend timer for setitimer().
Or just a general timer device ("/dev/counter") with some operations to
make use of it. I think there were some ideas quoted on this list.
For real time you do not need a precision of one or two CPU clocks -- it
will be lost in the overhead of the gettimeofday() syscall, any cache
activity will flush the precision down the drain, any branch
unpredictability will ruin it, etc. An actual resolution of 1us will be
excellent already. Try running `ntpd' on your platform of choice using a
reasonable time reference source and see how it behaves.
And last but not least for real time you do want to select the source
that has the best frequency stability and not necessarily the highest
frequency. For DEC the IOASIC timer has reportedly the best stability and
was actually used by David L. Mills for his work on `ntpd'. Perhaps the
temperature around the oscillator used for it changes the least.
Similarly the Dallas Semiconductor real time clocks have very good
frequency characteristics (quite unsurprisingly in my opinion).
The issues around timekeeping have been beaten to death on many
discussion forums -- I guess many of them may be quite easily reached with
the right keywords and your favourite search engine.
> > think the issue has been raised here many times already. The CP0 timer
> > has its problems too as it is one-shot only and needs complicated recovery
> > if an interrupt is missed -- see c0_timer_ack().
>
> Well I would say that because it's one-shot, it's a good timer to choose.
I fail to get your point, sorry -- could you please elaborate?
> I don't see how you can have hrtimer support if you choose a periodic
> timer...
Well, periodic timers do seem to work somehow for everybody else with no
hassle whatsoever, starting from the DEC code I referred to and including
other platforms, like the i386, which uses the 8254 for the timer
interrupt and as a HPT, by default, the very same counter or the TSC in
the CPU if available or, I think, some chipset timer, because some
brilliant soul decided to break the TSC at one point.
Note that the 8254 can be reprogrammed into a one-shot mode, but somehow
nobody does it. ;-) Similarly for the local APIC timer that is used for
scheduling on i386 systems (if available).
> And missed interrupts doens't seem a big deal, and the new kernel time
> subsystem handle them for us already.
Well, creating problems, because they can be solved seems not the way to
go for me. Just my opinion, though.
> > mips_timer_state appropriately, i.e. to flip at the HZ rate (it may be
> > based on one of the south bridge choices mentioned above or some
> > free-running counter for example), but people seem to prefer to write
> > their own code for some reason. ;-)
>
> Do you have any examples in mind which rewrite their own calibration
> code ? I'm too lazy to search into all board code.
See arch/mips/mips-boards/generic/time.c for example. Or any platform
that uses the CP0 timer interrupt and has a configurable CPU frequency --
you can find them easily by looking for ones that calculate
mips_hpt_frequency rather than set it to a fixed value.
> > And FYI for DEC CP0 is meant to be the last resort (current code does not
>
> Again IMHO it should be the first choice if possible.
Please search the list archive for the discussion about why it is not the
best idea. I think there were at least two discussions actually -- one
around the time the current code was created.
Maciej
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-15 11:07 ` Maciej W. Rozycki
@ 2007-06-15 13:26 ` Ralf Baechle
2007-06-15 14:08 ` Maciej W. Rozycki
2007-06-15 14:24 ` Franck Bui-Huu
2007-06-15 14:35 ` Sergei Shtylyov
1 sibling, 2 replies; 56+ messages in thread
From: Ralf Baechle @ 2007-06-15 13:26 UTC (permalink / raw)
To: Maciej W. Rozycki; +Cc: Franck Bui-Huu, Thomas Bogendoerfer, linux-mips
On Fri, Jun 15, 2007 at 12:07:05PM +0100, Maciej W. Rozycki wrote:
> > Which other purposes ? CP0 hpt gives generally the highest precision for
> > a given platform, and it seems to be your case too. I don't see which other
> > better purpose it can deserve other than hrtimer, tick interrupt...
>
> One better purpose could be using it as a backend timer for setitimer().
> Or just a general timer device ("/dev/counter") with some operations to
> make use of it. I think there were some ideas quoted on this list.
>
> For real time you do not need a precision of one or two CPU clocks -- it
> will be lost in the overhead of the gettimeofday() syscall, any cache
> activity will flush the precision down the drain, any branch
> unpredictability will ruin it, etc. An actual resolution of 1us will be
> excellent already. Try running `ntpd' on your platform of choice using a
> reasonable time reference source and see how it behaves.
>
> And last but not least for real time you do want to select the source
> that has the best frequency stability and not necessarily the highest
> frequency. For DEC the IOASIC timer has reportedly the best stability and
> was actually used by David L. Mills for his work on `ntpd'. Perhaps the
> temperature around the oscillator used for it changes the least.
> Similarly the Dallas Semiconductor real time clocks have very good
> frequency characteristics (quite unsurprisingly in my opinion).
>
> The issues around timekeeping have been beaten to death on many
> discussion forums -- I guess many of them may be quite easily reached with
> the right keywords and your favourite search engine.
The cp0 timer may have disadvantages but it certainly is the timer with
the lowest overhead to program, usually the timer with the highest
resolution. Unless in the rare cases where cp0 cannot be used because
it cannot trigger interrupts or the CPU clock is variable I think it will
always be the clockevent device of choice.
You still need a decent clocksource and for that one it's much more
important to have something that provides good long term stability. So
if you happen to have a system where the external timer tends to be
superior, by all means go for it. All it takes is to assign it a higher
rating and the kernel will pick it.
> > I don't see how you can have hrtimer support if you choose a periodic
> > timer...
>
> Well, periodic timers do seem to work somehow for everybody else with no
> hassle whatsoever, starting from the DEC code I referred to and including
> other platforms, like the i386, which uses the 8254 for the timer
> interrupt and as a HPT, by default, the very same counter or the TSC in
> the CPU if available or, I think, some chipset timer, because some
> brilliant soul decided to break the TSC at one point.
The tickless kernel needs something that can be used as oneshoot timer.
> Note that the 8254 can be reprogrammed into a one-shot mode, but somehow
> nobody does it. ;-) Similarly for the local APIC timer that is used for
> scheduling on i386 systems (if available).
Actually modern i386 kernels use it in both modes. But this can't help
over the fact that the i8253/i8254 is a horrible chip with extremly slow
access times so it's only used as the fallback when everything else fails.
> See arch/mips/mips-boards/generic/time.c for example. Or any platform
> that uses the CP0 timer interrupt and has a configurable CPU frequency --
> you can find them easily by looking for ones that calculate
> mips_hpt_frequency rather than set it to a fixed value.
For some reason the calibration turned out to be rather trick on Indys, so
arch/mips/sgi-ip22/ip22-time.c's plat_time_init is a well working example
for calibration of the cp0 timer against a timer of know speed.
Ralf
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-15 8:59 ` Franck Bui-Huu
2007-06-15 11:07 ` Maciej W. Rozycki
@ 2007-06-15 13:49 ` Ralf Baechle
2007-06-15 14:42 ` Sergei Shtylyov
2007-06-17 13:36 ` Franck Bui-Huu
1 sibling, 2 replies; 56+ messages in thread
From: Ralf Baechle @ 2007-06-15 13:49 UTC (permalink / raw)
To: Franck Bui-Huu; +Cc: Maciej W. Rozycki, Thomas Bogendoerfer, linux-mips
On Fri, Jun 15, 2007 at 10:59:00AM +0200, Franck Bui-Huu wrote:
> > Please note that this generic calibration code may be used for
> >calibrating the CP0 timer too -- all that you need is defining
>
> Actually the current patchset breaks it since it changes the calibration
> code to be used only for the cp0 hpt calibration. I'll change that.
To many this really fun it also needs to become possible to calibrate
each processor's clock individually - not all MIPS MP systems run their
clocks at the same rate.
Ralf
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-15 13:26 ` Ralf Baechle
@ 2007-06-15 14:08 ` Maciej W. Rozycki
2007-06-15 14:21 ` Ralf Baechle
2007-06-15 14:24 ` Franck Bui-Huu
1 sibling, 1 reply; 56+ messages in thread
From: Maciej W. Rozycki @ 2007-06-15 14:08 UTC (permalink / raw)
To: Ralf Baechle; +Cc: Franck Bui-Huu, Thomas Bogendoerfer, linux-mips
On Fri, 15 Jun 2007, Ralf Baechle wrote:
> The cp0 timer may have disadvantages but it certainly is the timer with
> the lowest overhead to program, usually the timer with the highest
> resolution. Unless in the rare cases where cp0 cannot be used because
> it cannot trigger interrupts or the CPU clock is variable I think it will
> always be the clockevent device of choice.
No argument about the overhead or the resolution, but these are the kinds
of properties that make it more appropriate for other purposes like
profiling or other short interval measurements, not necessarily for
timekeeping.
> The tickless kernel needs something that can be used as oneshoot timer.
A periodic timer typically works here just fine -- just "forget" about
the future shots. ;-) Even the miserable 8254/8259 combination is fine as
the former in the mode #2 only deasserts its output for its one input
clock, so the latter will only miss an interrupt if it has been on hold
for much too long anyway. With an interrupt controller that implements
real edge-triggered inputs even this single clock is not an issue.
> > Note that the 8254 can be reprogrammed into a one-shot mode, but somehow
> > nobody does it. ;-) Similarly for the local APIC timer that is used for
> > scheduling on i386 systems (if available).
>
> Actually modern i386 kernels use it in both modes. But this can't help
Oh really? How many clone chipset bugs has it triggered? ;-)
> over the fact that the i8253/i8254 is a horrible chip with extremly slow
> access times so it's only used as the fallback when everything else fails.
The chip is typically in the south bridge these days, so the access time
is not as bad itself as it used to be when it was a discrete one somewhere
on the x-bus, but the actual problem is the typical Intel baroque way of
accessing the counter: ask it to latch the current value, then issue two
reads to retrieve the two halves of the counter, plus check the lower half
has not overflown into the upper one meanwhile in case the latch command
did not work because of a chipset bug. ;-)
Maciej
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-15 14:08 ` Maciej W. Rozycki
@ 2007-06-15 14:21 ` Ralf Baechle
0 siblings, 0 replies; 56+ messages in thread
From: Ralf Baechle @ 2007-06-15 14:21 UTC (permalink / raw)
To: Maciej W. Rozycki; +Cc: Franck Bui-Huu, Thomas Bogendoerfer, linux-mips
On Fri, Jun 15, 2007 at 03:08:14PM +0100, Maciej W. Rozycki wrote:
> > The tickless kernel needs something that can be used as oneshoot timer.
>
> A periodic timer typically works here just fine -- just "forget" about
> the future shots. ;-)
That's pretty much how for example on an R1 core the compare interrupt
has to be used - IE7 is shared with the performance counter so can't be
disabled and as the result if the cp0 clockevent device is unused we will
get one useless but also harmless interrupt every 2^32 cycles.
> Even the miserable 8254/8259 combination is fine as
> the former in the mode #2 only deasserts its output for its one input
> clock, so the latter will only miss an interrupt if it has been on hold
> for much too long anyway. With an interrupt controller that implements
> real edge-triggered inputs even this single clock is not an issue.
>
> > > Note that the 8254 can be reprogrammed into a one-shot mode, but somehow
> > > nobody does it. ;-) Similarly for the local APIC timer that is used for
> > > scheduling on i386 systems (if available).
> >
> > Actually modern i386 kernels use it in both modes. But this can't help
>
> Oh really? How many clone chipset bugs has it triggered? ;-)
I'm sure you couldn't miss the screaming on linux-kernel ;-)
> > over the fact that the i8253/i8254 is a horrible chip with extremly slow
> > access times so it's only used as the fallback when everything else fails.
>
> The chip is typically in the south bridge these days, so the access time
> is not as bad itself as it used to be when it was a discrete one somewhere
> on the x-bus, but the actual problem is the typical Intel baroque way of
> accessing the counter: ask it to latch the current value, then issue two
> reads to retrieve the two halves of the counter, plus check the lower half
> has not overflown into the upper one meanwhile in case the latch command
> did not work because of a chipset bug. ;-)
Actually these days it seems to be living inside the southbridge behind
an extremly slow interface which is optimized for minimum connections to
the rest of the southbridge. So I'm told the access time is still around
2µs which is basically as crappy as it always has been.
Ralf
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-15 13:26 ` Ralf Baechle
2007-06-15 14:08 ` Maciej W. Rozycki
@ 2007-06-15 14:24 ` Franck Bui-Huu
2007-06-15 14:38 ` Ralf Baechle
1 sibling, 1 reply; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-15 14:24 UTC (permalink / raw)
To: Ralf Baechle; +Cc: Maciej W. Rozycki, Thomas Bogendoerfer, linux-mips
On 6/15/07, Ralf Baechle <ralf@linux-mips.org> wrote:
>
> For some reason the calibration turned out to be rather trick on Indys, so
> arch/mips/sgi-ip22/ip22-time.c's plat_time_init is a well working example
> for calibration of the cp0 timer against a timer of know speed.
>
Do you think it's possible to work out a common version of this
calibration without to many hacks ? Or should we simply move the
current generic one into the dec code and resolve this point later ?
--
Franck
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-15 11:07 ` Maciej W. Rozycki
2007-06-15 13:26 ` Ralf Baechle
@ 2007-06-15 14:35 ` Sergei Shtylyov
1 sibling, 0 replies; 56+ messages in thread
From: Sergei Shtylyov @ 2007-06-15 14:35 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: Franck Bui-Huu, Thomas Bogendoerfer, linux-mips, Ralf Baechle
Maciej W. Rozycki wrote:
>>I don't see how you can have hrtimer support if you choose a periodic
>>timer...
> Well, periodic timers do seem to work somehow for everybody else with no
> hassle whatsoever,
Except the purely periodic timers can't serve as HRT (unless one cheats
and also declares them as one-shot).
> starting from the DEC code I referred to and including
> other platforms, like the i386, which uses the 8254 for the timer
> interrupt and as a HPT, by default, the very same counter or the TSC in
What do you mean by HPT -- clocksource?
> the CPU if available or, I think, some chipset timer, because some
Weel there was ACPI timer (32-bit free running counter, IIRC) -- but
somehow I was unable to find the code for it in the current source. And there
is HPET which is indeed preferred over broken TSC.
> brilliant soul decided to break the TSC at one point.
> Note that the 8254 can be reprogrammed into a one-shot mode, but somehow
> nobody does it. ;-)
Well, hrtimers can do it but the LAPIC timer is preferred over 8254.
> Similarly for the local APIC timer that is used for
> scheduling on i386 systems (if available).
LAPIC timer is also used for HRT, i.e. in one-shot mode (simply because
it's the best choice for such purpose -- HRTs are per-CPU).
>>>mips_timer_state appropriately, i.e. to flip at the HZ rate (it may be
>>>based on one of the south bridge choices mentioned above or some
>>>free-running counter for example), but people seem to prefer to write
>>>their own code for some reason. ;-)
>>Do you have any examples in mind which rewrite their own calibration
>>code ? I'm too lazy to search into all board code.
> See arch/mips/mips-boards/generic/time.c for example. Or any platform
> that uses the CP0 timer interrupt and has a configurable CPU frequency --
> you can find them easily by looking for ones that calculate
> mips_hpt_frequency rather than set it to a fixed value.
Alchemy for one.
> Maciej
WBR, Sergei
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-15 14:24 ` Franck Bui-Huu
@ 2007-06-15 14:38 ` Ralf Baechle
2007-06-15 15:34 ` Franck Bui-Huu
0 siblings, 1 reply; 56+ messages in thread
From: Ralf Baechle @ 2007-06-15 14:38 UTC (permalink / raw)
To: Franck Bui-Huu; +Cc: Maciej W. Rozycki, Thomas Bogendoerfer, linux-mips
On Fri, Jun 15, 2007 at 04:24:36PM +0200, Franck Bui-Huu wrote:
> Do you think it's possible to work out a common version of this
> calibration without to many hacks ? Or should we simply move the
> current generic one into the dec code and resolve this point later ?
I think that this will be pretty easy and only moderately timeconsuming.
Ralf
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-15 13:49 ` Ralf Baechle
@ 2007-06-15 14:42 ` Sergei Shtylyov
2007-06-17 13:36 ` Franck Bui-Huu
1 sibling, 0 replies; 56+ messages in thread
From: Sergei Shtylyov @ 2007-06-15 14:42 UTC (permalink / raw)
To: Ralf Baechle; +Cc: linux-mips
Hello.
Ralf Baechle wrote:
>>>Please note that this generic calibration code may be used for
>>>calibrating the CP0 timer too -- all that you need is defining
>>Actually the current patchset breaks it since it changes the calibration
>>code to be used only for the cp0 hpt calibration. I'll change that.
> To many this really fun it also needs to become possible to calibrate
Huh? :-)
> each processor's clock individually - not all MIPS MP systems run their
> clocks at the same rate.
> Ralf
WBR, Sergei
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-15 14:38 ` Ralf Baechle
@ 2007-06-15 15:34 ` Franck Bui-Huu
0 siblings, 0 replies; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-15 15:34 UTC (permalink / raw)
To: Ralf Baechle; +Cc: Maciej W. Rozycki, linux-mips
On 6/15/07, Ralf Baechle <ralf@linux-mips.org> wrote:
> On Fri, Jun 15, 2007 at 04:24:36PM +0200, Franck Bui-Huu wrote:
>
> > Do you think it's possible to work out a common version of this
> > calibration without to many hacks ? Or should we simply move the
> > current generic one into the dec code and resolve this point later ?
>
> I think that this will be pretty easy and only moderately timeconsuming.
>
Mind to send a patch that will do that ? ;)
--
Franck
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 5/5] Implement clockevents for R4000-style cp0 timer
2007-06-14 12:29 ` Atsushi Nemoto
2007-06-14 13:00 ` Franck Bui-Huu
@ 2007-06-17 0:04 ` Ralf Baechle
2007-06-17 17:23 ` Atsushi Nemoto
2007-06-18 14:22 ` Franck Bui-Huu
1 sibling, 2 replies; 56+ messages in thread
From: Ralf Baechle @ 2007-06-17 0:04 UTC (permalink / raw)
To: Atsushi Nemoto; +Cc: vagabon.xyz, linux-mips
On Thu, Jun 14, 2007 at 09:29:13PM +0900, Atsushi Nemoto wrote:
> I think this to_tm() cleanup should be done in separate patch.
>
> Maybe selecting RTC_LIB in Kconfig and replace all to_tm() calls with
>
> rtc_time_to_tm(tim, tm);
> tm->tm_year += 1900;
>
> would be enough.
Looks good to me, done.
Ralf
[MIPS] Switch from to_tm to rtc_time_to_tm
This replaces the MIPS-specific to_tm function with the generic
rtc_time_to_tm function. The big difference between the two functions is
that rtc_time_to_tm uses epoch 70 while to_tm uses 1970, so the result of
rtc_time_to_tm needs to be fixed up.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/Kconfig | 1
arch/mips/ddb5xxx/common/rtc_ds1386.c | 5 +--
arch/mips/kernel/time.c | 48 ---------------------------------
arch/mips/momentum/jaguar_atx/setup.c | 8 ++++-
arch/mips/momentum/ocelot_3/setup.c | 8 ++++-
arch/mips/momentum/ocelot_c/setup.c | 8 ++++-
arch/mips/pmc-sierra/yosemite/setup.c | 8 ++++-
arch/mips/sgi-ip22/ip22-time.c | 6 ++--
arch/mips/sibyte/swarm/rtc_m41t81.c | 3 +-
arch/mips/sibyte/swarm/rtc_xicor1241.c | 3 +-
arch/mips/tx4938/common/rtc_rx5c348.c | 4 +-
include/asm-mips/time.h | 7 ----
12 files changed, 36 insertions(+), 73 deletions(-)
Index: linux-time/arch/mips/Kconfig
===================================================================
--- linux-time.orig/arch/mips/Kconfig
+++ linux-time/arch/mips/Kconfig
@@ -3,6 +3,7 @@ config MIPS
default y
# Horrible source of confusion. Die, die, die ...
select EMBEDDED
+ select RTC_LIB
mainmenu "Linux/MIPS Kernel Configuration"
Index: linux-time/include/asm-mips/time.h
===================================================================
--- linux-time.orig/include/asm-mips/time.h
+++ linux-time/include/asm-mips/time.h
@@ -49,13 +49,6 @@ extern void (*mips_timer_ack)(void);
extern struct clocksource clocksource_mips;
/*
- * to_tm() converts system time back to (year, mon, day, hour, min, sec).
- * It is intended to help implement rtc_set_time() functions.
- * Copied from PPC implementation.
- */
-extern void to_tm(unsigned long tim, struct rtc_time *tm);
-
-/*
* the corresponding low-level timer interrupt routine.
*/
extern irqreturn_t ll_timer_interrupt(int irq, void *dev_id);
Index: linux-time/arch/mips/momentum/jaguar_atx/setup.c
===================================================================
--- linux-time.orig/arch/mips/momentum/jaguar_atx/setup.c
+++ linux-time/arch/mips/momentum/jaguar_atx/setup.c
@@ -176,8 +176,12 @@ int rtc_mips_set_time(unsigned long sec)
struct rtc_time tm;
unsigned long flags;
- /* convert to a more useful format -- note months count from 0 */
- to_tm(sec, &tm);
+ /*
+ * Convert to a more useful format -- note months count from 0
+ * and years from 1900
+ */
+ rtc_time_to_tm(sec, &tm);
+ tm.tm_year += 1900;
tm.tm_mon += 1;
spin_lock_irqsave(&rtc_lock, flags);
Index: linux-time/arch/mips/tx4938/common/rtc_rx5c348.c
===================================================================
--- linux-time.orig/arch/mips/tx4938/common/rtc_rx5c348.c
+++ linux-time/arch/mips/tx4938/common/rtc_rx5c348.c
@@ -86,8 +86,8 @@ int rtc_mips_set_time(unsigned long t)
struct rtc_time tm;
u8 year, month, day, hour, minute, second, century;
- /* convert */
- to_tm(t, &tm);
+ rtc_time_to_tm(t, &tm); /* convert */
+ tm.tm_year += 1900;
year = tm.tm_year % 100;
month = tm.tm_mon+1; /* tm_mon starts from 0 to 11 */
Index: linux-time/arch/mips/ddb5xxx/common/rtc_ds1386.c
===================================================================
--- linux-time.orig/arch/mips/ddb5xxx/common/rtc_ds1386.c
+++ linux-time/arch/mips/ddb5xxx/common/rtc_ds1386.c
@@ -90,9 +90,8 @@ static int rtc_mips_set_time(unsigned lo
byte &= 0x3f;
WRITE_RTC(0xB, byte);
- /* convert */
- to_tm(t, &tm);
-
+ rtc_time_to_tm(t, &tm); /* convert */
+ tm.tm_year += 1900;
/* check each field one by one */
year = BIN2BCD(tm.tm_year - EPOCH);
Index: linux-time/arch/mips/kernel/time.c
===================================================================
--- linux-time.orig/arch/mips/kernel/time.c
+++ linux-time/arch/mips/kernel/time.c
@@ -431,53 +431,5 @@ void __init time_init(void)
#endif /* CONFIG_MIPS_MT_SMTC */
}
-#define FEBRUARY 2
-#define STARTOFTIME 1970
-#define SECDAY 86400L
-#define SECYR (SECDAY * 365)
-#define leapyear(y) ((!((y) % 4) && ((y) % 100)) || !((y) % 400))
-#define days_in_year(y) (leapyear(y) ? 366 : 365)
-#define days_in_month(m) (month_days[(m) - 1])
-
-static int month_days[12] = {
- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-
-void to_tm(unsigned long tim, struct rtc_time *tm)
-{
- long hms, day, gday;
- int i;
-
- gday = day = tim / SECDAY;
- hms = tim % SECDAY;
-
- /* Hours, minutes, seconds are easy */
- tm->tm_hour = hms / 3600;
- tm->tm_min = (hms % 3600) / 60;
- tm->tm_sec = (hms % 3600) % 60;
-
- /* Number of years in days */
- for (i = STARTOFTIME; day >= days_in_year(i); i++)
- day -= days_in_year(i);
- tm->tm_year = i;
-
- /* Number of months in days left */
- if (leapyear(tm->tm_year))
- days_in_month(FEBRUARY) = 29;
- for (i = 1; day >= days_in_month(i); i++)
- day -= days_in_month(i);
- days_in_month(FEBRUARY) = 28;
- tm->tm_mon = i - 1; /* tm_mon starts from 0 to 11 */
-
- /* Days are what is left over (+1) from all that. */
- tm->tm_mday = day + 1;
-
- /*
- * Determine the day of week
- */
- tm->tm_wday = (gday + 4) % 7; /* 1970/1/1 was Thursday */
-}
-
EXPORT_SYMBOL(rtc_lock);
-EXPORT_SYMBOL(to_tm);
EXPORT_SYMBOL(rtc_mips_set_time);
Index: linux-time/arch/mips/momentum/ocelot_3/setup.c
===================================================================
--- linux-time.orig/arch/mips/momentum/ocelot_3/setup.c
+++ linux-time/arch/mips/momentum/ocelot_3/setup.c
@@ -162,8 +162,12 @@ int rtc_mips_set_time(unsigned long sec)
struct rtc_time tm;
unsigned long flags;
- /* convert to a more useful format -- note months count from 0 */
- to_tm(sec, &tm);
+ /*
+ * Convert to a more useful format -- note months count from 0
+ * and years from 1900
+ */
+ rtc_time_to_tm(sec, &tm);
+ tm.tm_year += 1900;
tm.tm_mon += 1;
spin_lock_irqsave(&rtc_lock, flags);
Index: linux-time/arch/mips/momentum/ocelot_c/setup.c
===================================================================
--- linux-time.orig/arch/mips/momentum/ocelot_c/setup.c
+++ linux-time/arch/mips/momentum/ocelot_c/setup.c
@@ -170,8 +170,12 @@ int rtc_mips_set_time(unsigned long sec)
struct rtc_time tm;
unsigned long flags;
- /* convert to a more useful format -- note months count from 0 */
- to_tm(sec, &tm);
+ /*
+ * Convert to a more useful format -- note months count from 0
+ * and years from 1900
+ */
+ rtc_time_to_tm(sec, &tm);
+ tm.tm_year += 1900;
tm.tm_mon += 1;
spin_lock_irqsave(&rtc_lock, flags);
Index: linux-time/arch/mips/pmc-sierra/yosemite/setup.c
===================================================================
--- linux-time.orig/arch/mips/pmc-sierra/yosemite/setup.c
+++ linux-time/arch/mips/pmc-sierra/yosemite/setup.c
@@ -99,8 +99,12 @@ int rtc_mips_set_time(unsigned long sec)
struct rtc_time tm;
unsigned long flags;
- /* convert to a more useful format -- note months count from 0 */
- to_tm(sec, &tm);
+ /*
+ * Convert to a more useful format -- note months count from 0
+ * and years from 1900
+ */
+ rtc_time_to_tm(sec, &tm);
+ tm.tm_year += 1900;
tm.tm_mon += 1;
spin_lock_irqsave(&rtc_lock, flags);
Index: linux-time/arch/mips/sgi-ip22/ip22-time.c
===================================================================
--- linux-time.orig/arch/mips/sgi-ip22/ip22-time.c
+++ linux-time/arch/mips/sgi-ip22/ip22-time.c
@@ -30,7 +30,7 @@
#include <asm/sgi/ip22.h>
/*
- * note that mktime uses month from 1 to 12 while to_tm
+ * Note that mktime uses month from 1 to 12 while rtc_time_to_tm
* uses 0 to 11.
*/
unsigned long read_persistent_clock(void)
@@ -67,10 +67,10 @@ int rtc_mips_set_time(unsigned long tim)
unsigned int save_control;
unsigned long flags;
- to_tm(tim, &tm);
+ rtc_time_to_tm(tim, &tm);
tm.tm_mon += 1; /* tm_mon starts at zero */
- tm.tm_year -= 1940;
+ tm.tm_year -= 40;
if (tm.tm_year >= 100)
tm.tm_year -= 100;
Index: linux-time/arch/mips/sibyte/swarm/rtc_m41t81.c
===================================================================
--- linux-time.orig/arch/mips/sibyte/swarm/rtc_m41t81.c
+++ linux-time/arch/mips/sibyte/swarm/rtc_m41t81.c
@@ -146,7 +146,8 @@ int m41t81_set_time(unsigned long t)
struct rtc_time tm;
unsigned long flags;
- to_tm(t, &tm);
+ /* Note we don't care about the century */
+ rtc_time_to_tm(t, &tm);
/*
* Note the write order matters as it ensures the correctness.
Index: linux-time/arch/mips/sibyte/swarm/rtc_xicor1241.c
===================================================================
--- linux-time.orig/arch/mips/sibyte/swarm/rtc_xicor1241.c
+++ linux-time/arch/mips/sibyte/swarm/rtc_xicor1241.c
@@ -115,7 +115,8 @@ int xicor_set_time(unsigned long t)
int tmp;
unsigned long flags;
- to_tm(t, &tm);
+ rtc_time_to_tm(t, &tm);
+ tm.tm_year += 1900;
spin_lock_irqsave(&rtc_lock, flags);
/* unlock writes to the CCR */
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-15 13:49 ` Ralf Baechle
2007-06-15 14:42 ` Sergei Shtylyov
@ 2007-06-17 13:36 ` Franck Bui-Huu
2007-06-17 16:14 ` Atsushi Nemoto
2007-06-18 12:41 ` Franck Bui-Huu
1 sibling, 2 replies; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-17 13:36 UTC (permalink / raw)
To: Ralf Baechle, Maciej W. Rozycki; +Cc: Sergei Shtylyov, linux-mips
[-- Attachment #1: Type: text/plain, Size: 2702 bytes --]
On 6/15/07, Ralf Baechle <ralf@linux-mips.org> wrote:
> On Fri, Jun 15, 2007 at 10:59:00AM +0200, Franck Bui-Huu wrote:
>
> > > Please note that this generic calibration code may be used for
> > >calibrating the CP0 timer too -- all that you need is defining
> >
> > Actually the current patchset breaks it since it changes the calibration
> > code to be used only for the cp0 hpt calibration. I'll change that.
>
> To many this really fun it also needs to become possible to calibrate
> each processor's clock individually - not all MIPS MP systems run their
> clocks at the same rate.
>
OK I've updated patch 5/5, taking into account several raised points.
First of all I put the cp0 hpt clock driver into a file named
"hpt-cp0.c". Therefore there should be no more ambiguties on what
we're taking about. Moreover if a platform needs a new hpt clock
driver it could call it "hpt-foo.c". BTW, Ralf, you made such a driver
for 'i8253' device, can we rename it "hpt-i8253.c" ?
The interface should be simple enough to let all platforms do what
they want without any complexities or hacks. It should be also now
possible to read from platform code and easily understand what they
do/need.
For example for DEC, this should result into:
unsigned dec_calibrate_timer(int cpu)
{
<...>
ralf_generic_calibrate_timer(cpu); /* ;) */
<...>
}
void plat_timer_setup(void)
{
setup_ds1287_timer(); /* implemented in hpt-ds1287.c ? */
if (cpu_has_counter) {
struct cp0_hpt_info info;
info.get_freq = dec_calibrate_timer;
info.irq = dec_irq;
setup_cp0_hpt(&info);
} else if (IOASIC) {
setup_hpt_ioasic();
}
}
and with appropriate rating it should do what you want.
Note that 'dec_calibrate_timer' will be called on each cpu the system
has. So it should be possible to calibrate each processor's clock
individually without too much pain.
I have still few questions:
a) mips_hpt_frequency is still used in a few places. I'm not sure it's
a good thing to keep specially since it's broken in it's current form.
For example it doesn't deal with SMP, if a new clock event is loaded
later we'll need to change its value accordingly. Do you think we can
kill it safely ?
b) Are there some weird MIPS CPUs out there which don't read/ack cp0
hpt in the normal way ?
c) the clocksource rating currently depends on the hpt frequency. It's
more important for this kind of device to have the best frequency
stability whereas high frequency is more valuable for a clock event
device. Should we remove this depedency for the clock source rating.
I attached the patch since I can't cut'n past it into GMAIL interface
without space damages (sigh).
Thanks
--
Franck
[-- Attachment #2: 0006-Implement-clockevents-for-R4000-style-cp0-timer.patch --]
[-- Type: text/x-patch, Size: 25389 bytes --]
From 749a00d21ef3e4de4626b49ccc285372897bcd90 Mon Sep 17 00:00:00 2001
From: Franck Bui-Huu <fbuihuu@gmail.com>
Date: Thu, 14 Jun 2007 10:18:07 +0200
Subject: [PATCH 6/6] Implement clockevents for R4000-style cp0 timer
Signed-off-by: Franck Bui-Huu <fbuihuu@gmail.com>
---
arch/mips/Kconfig | 9 +
arch/mips/kernel/Makefile | 2 +
arch/mips/kernel/hpt-cp0.c | 247 ++++++++++++++++++++++++++
arch/mips/kernel/process.c | 3 +
arch/mips/kernel/smp.c | 2 +
arch/mips/kernel/time.c | 417 ++++----------------------------------------
include/asm-mips/hpt.h | 30 +++
include/asm-mips/time.h | 46 ++----
8 files changed, 337 insertions(+), 419 deletions(-)
create mode 100644 arch/mips/kernel/hpt-cp0.c
create mode 100644 include/asm-mips/hpt.h
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 196d90a..9bcfe38 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -704,6 +704,14 @@ config GENERIC_TIME
bool
default y
+config GENERIC_CLOCKEVENTS
+ bool
+ default y
+
+config CP0_HPT_TIMER
+ bool
+ default y
+
config GENERIC_CMOS_UPDATE
bool
default y
@@ -1722,6 +1730,7 @@ config HZ
default 1000 if HZ_1000
default 1024 if HZ_1024
+source "kernel/time/Kconfig"
source "kernel/Kconfig.preempt"
config MIPS_INSANE_LARGE
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 4924626..ffd4352 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -11,6 +11,8 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \
binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \
irix5sys.o sysirix.o
+obj-$(CONFIG_CP0_HPT_TIMER) += hpt-cp0.o
+
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_MODULES) += mips_ksyms.o module.o
diff --git a/arch/mips/kernel/hpt-cp0.c b/arch/mips/kernel/hpt-cp0.c
new file mode 100644
index 0000000..44bb2ad
--- /dev/null
+++ b/arch/mips/kernel/hpt-cp0.c
@@ -0,0 +1,247 @@
+/*
+ * This is a driver for CP0 hpt.
+ */
+#include <linux/kernel_stat.h>
+#include <linux/spinlock.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+
+
+#include <asm/time.h>
+#include <asm/hpt.h>
+
+
+#define MIPS_HPT_NAME "cp0-hpt"
+
+
+static unsigned (*cp0_hpt_get_freq)(int cpu) __initdata;
+static irqreturn_t (*perf_handler)(int irq, void *dev_id) __read_mostly;
+
+
+/*
+ * hpt can be disabled by boot command line
+ */
+static int cp0_hpt_disabled __initdata;
+
+static int __init no_cp0_hpt_setup(char *str)
+{
+ cp0_hpt_disabled = 1;
+ return 0;
+}
+early_param("no-cp0-hpt", no_cp0_hpt_setup);
+
+/*
+ * cp0 hpt operations. Can be overriden by platform code
+ */
+static void cp0_hpt_ack(void)
+{
+ write_c0_compare(read_c0_compare());
+}
+
+static cycle_t cp0_hpt_read(void)
+{
+ return read_c0_count();
+}
+
+/*
+ * Clocksource functions
+ */
+struct clocksource hpt_clocksource = {
+ .name = MIPS_HPT_NAME,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .read = cp0_hpt_read,
+};
+
+/* FIXME: for a clocksource, rating should not depend on frequency,
+ * stability is something more valuable...
+ */
+static int cp0_hpt_rating(unsigned freq)
+{
+ return 200 + freq / 10000000;
+}
+
+static void __init setup_cp0_hpt_clocksource(void)
+{
+ unsigned freq = cp0_hpt_get_freq(smp_processor_id());
+ unsigned shift = 0;
+ u64 mult;
+
+ for (shift = 32; shift > 0; shift--) {
+ mult = (u64)NSEC_PER_SEC << shift;
+ do_div(mult, freq);
+ if ((mult >> 32) == 0)
+ break;
+ }
+
+ hpt_clocksource.shift = shift;
+ hpt_clocksource.mult = mult;
+ hpt_clocksource.rating = cp0_hpt_rating(freq);
+
+ clocksource_register(&hpt_clocksource);
+}
+
+/*
+ * High precision timer functions
+ */
+
+static int cp0_hpt_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ unsigned int cnt;
+
+ BUG_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
+
+ /* interrupt ack is done by setting up the next event */
+ cnt = read_c0_count();
+ cnt += delta;
+ write_c0_compare(cnt);
+
+ return ((long)(read_c0_count() - cnt) > 0L) ? -ETIME : 0;
+}
+
+static void cp0_hpt_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ /*
+ * For now, we can't disable cp0 hpt interrupts. So we
+ * leave them enabled, and ignore them in this mode.
+ * Therefore we will get one useless but also harmless
+ * interrupt every 2^32 cycles...
+ */
+ cp0_hpt_ack();
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* nothing to do */
+ break;
+ case CLOCK_EVT_MODE_PERIODIC:
+ BUG();
+ };
+}
+
+static struct clock_event_device hpt_clockevent = {
+ .name = MIPS_HPT_NAME,
+ .mode = CLOCK_EVT_MODE_UNUSED,
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .shift = 32,
+ .set_mode = cp0_hpt_set_mode,
+ .set_next_event = cp0_hpt_set_next_event,
+ .irq = -1,
+};
+
+static DEFINE_PER_CPU(struct clock_event_device, cp0_hpt_clock_events);
+
+void __init setup_cp0_hpt_clockevent(void)
+{
+ struct clock_event_device *cd;
+ int cpu = smp_processor_id();
+ unsigned freq;
+
+ if (cp0_hpt_disabled)
+ return;
+
+ cd = &__get_cpu_var(cp0_hpt_clock_events);
+
+ memcpy(cd, &hpt_clockevent, sizeof(*cd));
+ cd->max_delta_ns = clockevent_delta2ns(-1, &hpt_clockevent);
+ cd->min_delta_ns = clockevent_delta2ns(+1, &hpt_clockevent);
+
+ freq = cp0_hpt_get_freq(cpu);
+
+ cd->mult = div_sc(freq, NSEC_PER_SEC, cd->shift);
+ cd->rating = cp0_hpt_rating(freq);
+ cd->cpumask = cpumask_of_cpu(cpu);
+
+ clockevents_register_device(cd);
+
+ printk("Using %u.%03u MHz CP0 high precision timer on CPU #%d.\n",
+ ((freq + 500) / 1000) / 1000,
+ ((freq + 500) / 1000) % 1000,
+ cpu);
+}
+
+static irqreturn_t cp0_hpt_interrupt(int irq, void *dev_id)
+{
+ const int r2 = cpu_has_mips_r2;
+ struct clock_event_device *cd;
+
+ /*
+ * Suckage alert:
+ * Before R2 of the architecture there was no way to see if a
+ * performance counter interrupt was pending, so we have to run
+ * the performance counter interrupt handler anyway.
+ */
+ if (perf_handler && perf_handler(irq, dev_id) == IRQ_HANDLED)
+ /*
+ * The performance counter overflow interrupt may be
+ * shared with the timer interrupt. If it is (!r2)
+ * then we can't reliably determine if a counter
+ * interrupt has also happened. So don't check for a
+ * timer interrupt in this case.
+ */
+ if (!r2)
+ goto out;
+
+ /*
+ * The same applies to performance counter interrupts. But with the
+ * above we now know that the reason we got here must be a timer
+ * interrupt. Being the paranoiacs we are we check anyway.
+ */
+ if (!r2 || (read_c0_cause() & (1 << 30))) {
+ cd = &__get_cpu_var(cp0_hpt_clock_events);
+
+ if (likely(cd->mode != CLOCK_EVT_MODE_SHUTDOWN))
+ cd->event_handler(cd);
+ else
+ /*
+ * We ack the counter since we don't shut it
+ * down. Therefore we can get interrupts
+ * whereas the hpt clock event device has been
+ * disabled.
+ */
+ cp0_hpt_ack();
+ }
+out:
+ return IRQ_HANDLED;
+}
+
+struct irqaction hpt_irqaction = {
+ .handler = cp0_hpt_interrupt,
+ .flags = IRQF_DISABLED | IRQF_PERCPU,
+ .name = MIPS_HPT_NAME,
+};
+
+
+/*
+ * This function is used by platforms which use the hpt as clock
+ * source and timer.
+ */
+int __init setup_cp0_hpt(struct cp0_hpt_info *info)
+{
+ if (cp0_hpt_disabled)
+ goto out;
+ if (!cpu_has_counter)
+ goto disable;
+
+ if (info->irq == 0)
+ goto disable;
+ if (info->get_freq == NULL)
+ goto disable;
+
+ cp0_hpt_get_freq = info->get_freq;
+ perf_handler = info->perf_handler;
+
+ setup_cp0_hpt_clocksource();
+ setup_cp0_hpt_clockevent();
+
+ /* Enable hpt interrupt. */
+ setup_irq(info->irq, &hpt_irqaction);
+out:
+ return 0;
+disable:
+ printk(KERN_WARNING "Error when starting CP0 hpt... disabled\n");
+ cp0_hpt_disabled = 1;
+ return -EINVAL;
+}
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 6bdfb5a..23b8858 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -25,6 +25,7 @@
#include <linux/init.h>
#include <linux/completion.h>
#include <linux/kallsyms.h>
+#include <linux/tick.h>
#include <asm/bootinfo.h>
#include <asm/cpu.h>
@@ -50,6 +51,7 @@ ATTRIB_NORET void cpu_idle(void)
{
/* endless idle loop with no priority at all */
while (1) {
+ tick_nohz_stop_sched_tick();
while (!need_resched()) {
#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG
extern void smtc_idle_loop_hook(void);
@@ -59,6 +61,7 @@ ATTRIB_NORET void cpu_idle(void)
if (cpu_wait)
(*cpu_wait)();
}
+ tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
schedule();
preempt_disable();
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 67edfa7..85ad130 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -37,6 +37,7 @@
#include <asm/system.h>
#include <asm/mmu_context.h>
#include <asm/smp.h>
+#include <asm/hpt.h>
#ifdef CONFIG_MIPS_MT_SMTC
#include <asm/mipsmtregs.h>
@@ -79,6 +80,7 @@ asmlinkage __cpuinit void start_secondary(void)
cpu_probe();
cpu_report();
per_cpu_trap_init();
+ setup_cp0_hpt_clockevent(/* calibrate_timer() */);
prom_init_secondary();
/*
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 72df0bf..b7fe3af 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -1,48 +1,16 @@
-/*
- * Copyright 2001 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- * Copyright (c) 2003, 2004 Maciej W. Rozycki
- *
- * Common time service routines for MIPS machines. See
- * Documentation/mips/time.README.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/param.h>
-#include <linux/time.h>
-#include <linux/timex.h>
-#include <linux/smp.h>
#include <linux/kernel_stat.h>
#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
+#include <linux/clocksource.h> /* cycle_t */
-#include <asm/bootinfo.h>
-#include <asm/cache.h>
-#include <asm/compiler.h>
-#include <asm/cpu.h>
-#include <asm/cpu-features.h>
-#include <asm/div64.h>
-#include <asm/sections.h>
#include <asm/time.h>
/*
- * The integer part of the number of usecs per jiffy is taken from tick,
- * but the fractional part is not recorded, so we calculate it using the
- * initial value of HZ. This aids systems where tick isn't really an
- * integer (e.g. for HZ = 128).
+ * This is the freq of the tick timer of the platform. It's not
+ * always a _high_ precision timer as its name suggests.
+ *
+ * FIXME: Is it really needed ? shouldn't it be a per cpu value ?
*/
-#define USECS_PER_JIFFY TICK_SIZE
-#define USECS_PER_JIFFY_FRAC ((unsigned long)(u32)((1000000ULL << 32) / HZ))
-
-#define TICK_SIZE (tick_nsec / 1000)
+unsigned int mips_hpt_frequency __read_mostly;
/*
* RTC. By default we provide the null RTC hooks
@@ -79,264 +47,39 @@ int update_persistent_clock(struct timespec now)
return mips_rtc_set_mmss(now.tv_sec);
}
-/* how many counter cycles in a jiffy */
-static unsigned long cycles_per_jiffy __read_mostly;
-
-/* expirelo is the count value for next CPU timer interrupt */
-static unsigned int expirelo;
-
-
-/*
- * Null timer ack for systems not needing one (e.g. i8254).
- */
-static void null_timer_ack(void) { /* nothing */ }
-
-/*
- * Null high precision timer functions for systems lacking one.
- */
-static cycle_t null_hpt_read(void)
-{
- return 0;
-}
-
-/*
- * Timer ack for an R4k-compatible timer of a known frequency.
- */
-static void c0_timer_ack(void)
-{
- unsigned int count;
-
- /* Ack this timer interrupt and set the next one. */
- expirelo += cycles_per_jiffy;
- write_c0_compare(expirelo);
-
- /* Check to see if we have missed any timer interrupts. */
- while (((count = read_c0_count()) - expirelo) < 0x7fffffff) {
- /* missed_timer_count++; */
- expirelo = count + cycles_per_jiffy;
- write_c0_compare(expirelo);
- }
-}
-
-/*
- * High precision timer functions for a R4k-compatible timer.
- */
-static cycle_t c0_hpt_read(void)
-{
- return read_c0_count();
-}
-
-/* For use both as a high precision timer and an interrupt source. */
-static void __init c0_hpt_timer_init(void)
-{
- expirelo = read_c0_count() + cycles_per_jiffy;
- write_c0_compare(expirelo);
-}
-
-int (*mips_timer_state)(void);
-void (*mips_timer_ack)(void);
-
-/*
- * local_timer_interrupt() does profiling and process accounting
- * on a per-CPU basis.
- *
- * In UP mode, it is invoked from the (global) timer_interrupt.
- *
- * In SMP mode, it might invoked by per-CPU timer interrupt, or
- * a broadcasted inter-processor interrupt which itself is triggered
- * by the global timer interrupt.
- */
-void local_timer_interrupt(int irq)
-{
- profile_tick(CPU_PROFILING);
- update_process_times(user_mode(get_irq_regs()));
-}
-
/*
- * High-level timer interrupt service routines. This function
- * is set as irqaction->handler and is invoked through do_IRQ.
+ * Basically it calls the platform hooks to setup:
+ * a) RTC
+ * b) a timer
*/
-irqreturn_t timer_interrupt(int irq, void *dev_id)
-{
- write_seqlock(&xtime_lock);
-
- mips_timer_ack();
-
- /*
- * call the generic timer interrupt handling
- */
- do_timer(1);
-
- write_sequnlock(&xtime_lock);
-
- /*
- * In UP mode, we call local_timer_interrupt() to do profiling
- * and process accouting.
- *
- * In SMP mode, local_timer_interrupt() is invoked by appropriate
- * low-level local timer interrupt handler.
- */
- local_timer_interrupt(irq);
-
- return IRQ_HANDLED;
-}
-
-int null_perf_irq(void)
-{
- return 0;
-}
-
-EXPORT_SYMBOL(null_perf_irq);
-
-int (*perf_irq)(void) = null_perf_irq;
-
-EXPORT_SYMBOL(perf_irq);
-
-/*
- * Performance counter IRQ or -1 if shared with timer
- */
-int mipsxx_perfcount_irq;
-EXPORT_SYMBOL(mipsxx_perfcount_irq);
-
-/*
- * Possibly handle a performance counter interrupt.
- * Return true if the timer interrupt should not be checked
- */
-static inline int handle_perf_irq(int r2)
-{
- /*
- * The performance counter overflow interrupt may be shared with the
- * timer interrupt (mipsxx_perfcount_irq < 0). If it is and a
- * performance counter has overflowed (perf_irq() == IRQ_HANDLED)
- * and we can't reliably determine if a counter interrupt has also
- * happened (!r2) then don't check for a timer interrupt.
- */
- return (mipsxx_perfcount_irq < 0) &&
- perf_irq() == IRQ_HANDLED &&
- !r2;
-}
-
-extern void smtc_timer_broadcast(int);
-
-void ll_timer_interrupt(int irq)
+void __init time_init(void)
{
- int cpu = smp_processor_id();
- int r2 = cpu_has_mips_r2;
-
- irq_enter();
- kstat_this_cpu.irqs[irq]++;
-
-#ifdef CONFIG_MIPS_MT_SMTC
/*
- * In an SMTC system, one Count/Compare set exists per VPE.
- * Which TC within a VPE gets the interrupt is essentially
- * random - we only know that it shouldn't be one with
- * IXMT set. Whichever TC gets the interrupt needs to
- * send special interprocessor interrupts to the other
- * TCs to make sure that they schedule, etc.
- *
- * That code is specific to the SMTC kernel, not to
- * the a particular platform, so it's invoked from
- * the general MIPS timer_interrupt routine.
+ * Mandatory platform hook. It basically setup the RTC.
+ * FIXME: shouldn't we call these before calling
+ * timekeeping_init() ?
*/
+ plat_time_init();
/*
- * We could be here due to timer interrupt,
- * perf counter overflow, or both.
+ * Platform can setup a new timer, hpt timer...
*/
- (void) handle_perf_irq(1);
-
- if (read_c0_cause() & (1 << 30)) {
- /*
- * There are things we only want to do once per tick
- * in an "MP" system. One TC of each VPE will take
- * the actual timer interrupt. The others will get
- * timer broadcast IPIs. We use whoever it is that takes
- * the tick on VPE 0 to run the full timer_interrupt().
- */
- if (cpu_data[cpu].vpe_id == 0) {
- timer_interrupt(irq, NULL);
- } else {
- write_c0_compare(read_c0_count() +
- (mips_hpt_frequency/HZ));
- local_timer_interrupt(irq);
- }
- smtc_timer_broadcast(cpu_data[cpu].vpe_id);
- }
-#else /* CONFIG_MIPS_MT_SMTC */
- if (handle_perf_irq(r2))
- goto out;
-
- if (r2 && ((read_c0_cause() & (1 << 30)) == 0))
- goto out;
+ plat_timer_setup(&mips_hpt_frequency);
- if (cpu == 0) {
- /*
- * CPU 0 handles the global timer interrupt job and process
- * accounting resets count/compare registers to trigger next
- * timer int.
- */
- timer_interrupt(irq, NULL);
- } else {
- /* Everyone else needs to reset the timer int here as
- ll_local_timer_interrupt doesn't */
- /*
- * FIXME: need to cope with counter underflow.
- * More support needs to be added to kernel/time for
- * counter/timer interrupts on multiple CPU's
- */
- write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ));
-
- /*
- * Other CPUs should do profiling and process accounting
- */
- local_timer_interrupt(irq);
- }
-out:
-#endif /* CONFIG_MIPS_MT_SMTC */
-
- irq_exit();
+ if (mips_hpt_frequency == 0)
+ panic("Tick timer frequency is unknown");
}
-asmlinkage void ll_local_timer_interrupt(int irq)
-{
- irq_enter();
- if (smp_processor_id() != 0)
- kstat_this_cpu.irqs[irq]++;
-
- /* we keep interrupt disabled all the time */
- local_timer_interrupt(irq);
-
- irq_exit();
-}
-
/*
- * time_init() - it does the following things.
- *
- * 1) plat_time_init() -
- * a) (optional) set up RTC routines,
- * b) (optional) calibrate and set the mips_hpt_frequency
- * (only needed if you intended to use cpu counter as timer interrupt
- * source)
- * 2) calculate a couple of cached variables for later usage
- * 3) plat_timer_setup() -
- * a) (optional) over-write any choices made above by time_init().
- * b) machine specific code should setup the timer irqaction.
- * c) enable the timer interrupt
+ * If you don't know timer 'X' frequency and have another timer 'Y'
+ * that flips at HZ rate, you can use this helper to determinate the
+ * timer 'X' freq.
*/
-
-unsigned int mips_hpt_frequency;
-
-static struct irqaction timer_irqaction = {
- .handler = timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_PERCPU,
- .name = "timer",
-};
-
-static unsigned int __init calibrate_hpt(void)
+unsigned __init calibrate_timer(cycle_t (*x_read)(void),
+ int (*y_state)(void))
{
- cycle_t frequency, hpt_start, hpt_end, hpt_count, hz;
+ cycle_t freq, start, end, count, hz;
const int loops = HZ / 10;
int log_2_loops = 0;
@@ -354,118 +97,24 @@ static unsigned int __init calibrate_hpt(void)
/*
* Wait for a rising edge of the timer interrupt.
*/
- while (mips_timer_state());
- while (!mips_timer_state());
+ while (y_state());
+ while (!y_state());
/*
* Now see how many high precision timer ticks happen
* during the calculated number of periods between timer
* interrupts.
*/
- hpt_start = clocksource_mips.read();
+ start = x_read();
do {
- while (mips_timer_state());
- while (!mips_timer_state());
+ while (y_state());
+ while (!y_state());
} while (--i);
- hpt_end = clocksource_mips.read();
+ end = x_read();
- hpt_count = (hpt_end - hpt_start) & clocksource_mips.mask;
+ count = end - start;
hz = HZ;
- frequency = hpt_count * hz;
-
- return frequency >> log_2_loops;
-}
-
-struct clocksource clocksource_mips = {
- .name = "MIPS",
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static void __init init_mips_clocksource(void)
-{
- u64 temp;
- u32 shift;
-
- if (!mips_hpt_frequency || clocksource_mips.read == null_hpt_read)
- return;
-
- /* Calclate a somewhat reasonable rating value */
- clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
- /* Find a shift value */
- for (shift = 32; shift > 0; shift--) {
- temp = (u64) NSEC_PER_SEC << shift;
- do_div(temp, mips_hpt_frequency);
- if ((temp >> 32) == 0)
- break;
- }
- clocksource_mips.shift = shift;
- clocksource_mips.mult = (u32)temp;
-
- clocksource_register(&clocksource_mips);
-}
-
-void __init __weak plat_time_init(void)
-{
-}
-
-void __init time_init(void)
-{
- plat_time_init();
-
- /* Choose appropriate high precision timer routines. */
- if (!cpu_has_counter && !clocksource_mips.read)
- /* No high precision timer -- sorry. */
- clocksource_mips.read = null_hpt_read;
- else if (!mips_hpt_frequency && !mips_timer_state) {
- /* A high precision timer of unknown frequency. */
- if (!clocksource_mips.read)
- /* No external high precision timer -- use R4k. */
- clocksource_mips.read = c0_hpt_read;
- } else {
- /* We know counter frequency. Or we can get it. */
- if (!clocksource_mips.read) {
- /* No external high precision timer -- use R4k. */
- clocksource_mips.read = c0_hpt_read;
-
- if (!mips_timer_state) {
- /* No external timer interrupt -- use R4k. */
- mips_timer_ack = c0_timer_ack;
- /* Calculate cache parameters. */
- cycles_per_jiffy =
- (mips_hpt_frequency + HZ / 2) / HZ;
- /*
- * This sets up the high precision
- * timer for the first interrupt.
- */
- c0_hpt_timer_init();
- }
- }
- if (!mips_hpt_frequency)
- mips_hpt_frequency = calibrate_hpt();
-
- /* Report the high precision timer rate for a reference. */
- printk("Using %u.%03u MHz high precision timer.\n",
- ((mips_hpt_frequency + 500) / 1000) / 1000,
- ((mips_hpt_frequency + 500) / 1000) % 1000);
- }
-
- if (!mips_timer_ack)
- /* No timer interrupt ack (e.g. i8254). */
- mips_timer_ack = null_timer_ack;
-
- /*
- * Call board specific timer interrupt setup.
- *
- * this pointer must be setup in machine setup routine.
- *
- * Even if a machine chooses to use a low-level timer interrupt,
- * it still needs to setup the timer_irqaction.
- * In that case, it might be better to set timer_irqaction.handler
- * to be NULL function so that we are sure the high-level code
- * is not invoked accidentally.
- */
- plat_timer_setup(&timer_irqaction);
+ freq = count * hz;
- init_mips_clocksource();
+ return freq >> log_2_loops;
}
diff --git a/include/asm-mips/hpt.h b/include/asm-mips/hpt.h
new file mode 100644
index 0000000..2b62827
--- /dev/null
+++ b/include/asm-mips/hpt.h
@@ -0,0 +1,30 @@
+#ifndef _ASM_HPT_H
+#define _ASM_HPT_H
+
+#ifdef CONFIG_CP0_HPT_TIMER
+
+struct cp0_hpt_info {
+ /* FIXME: could we let the user override hpt ops ? */
+ /* FIXME: should we add a disable_irq method ? */
+ int irq;
+ unsigned (*get_freq)(int cpu);
+
+ /*
+ * The performance counter overflow irq may be shared with the
+ * hpt interrupt. In that case this handler will be called
+ * during a hpt interrupt.
+ */
+ irqreturn_t (*perf_handler)(int irq, void *dev_id);
+};
+
+
+extern int setup_cp0_hpt(struct cp0_hpt_info *info);
+extern void setup_cp0_hpt_clockevent(void);
+
+#else
+
+static inline void setup_cp0_hpt_clockevent(void) {}
+
+#endif /* CONFIG_CP0_HPT_TIMER */
+
+#endif /* _ASM_HPT_H */
diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h
index 33645ed..781102b 100644
--- a/include/asm-mips/time.h
+++ b/include/asm-mips/time.h
@@ -16,16 +16,18 @@
#ifndef _ASM_TIME_H
#define _ASM_TIME_H
-#include <linux/interrupt.h>
-#include <linux/linkage.h>
-#include <linux/ptrace.h>
+#include <linux/clocksource.h> /* cycle_t */
#include <linux/rtc.h>
-#include <linux/spinlock.h>
-#include <linux/clocksource.h>
extern spinlock_t rtc_lock;
/*
+ * mips_hpt_frequency - must be set by the platform code.
+ * It saves the tick timer frequency.
+ */
+extern unsigned int mips_hpt_frequency;
+
+/*
* RTC ops
*/
extern unsigned long mips_rtc_get_time(void);
@@ -41,12 +43,6 @@ extern int (*mips_timer_state)(void);
extern void (*mips_timer_ack)(void);
/*
- * High precision timer clocksource.
- * If .read is NULL, an R4k-compatible timer setup is attempted.
- */
-extern struct clocksource clocksource_mips;
-
-/*
* to_tm() converts system time back to (year, mon, day, hour, min, sec).
* It is intended to help implement rtc_set_time() functions.
* Copied from PPC implementation.
@@ -54,32 +50,12 @@ extern struct clocksource clocksource_mips;
extern void to_tm(unsigned long tim, struct rtc_time *tm);
/*
- * high-level timer interrupt routines.
- */
-extern irqreturn_t timer_interrupt(int irq, void *dev_id);
-
-/*
- * the corresponding low-level timer interrupt routine.
+ * board specific hooks called by time_init().
*/
-extern void ll_timer_interrupt(int irq);
-
-/*
- * profiling and process accouting is done separately in local_timer_interrupt
- */
-extern void local_timer_interrupt(int irq);
-
-/*
- * board specific routines required by time_init().
- */
-struct irqaction;
extern void plat_time_init(void);
-extern void plat_timer_setup(struct irqaction *irq);
+extern void plat_timer_setup(unsigned *hpt_freq);
-/*
- * mips_hpt_frequency - must be set if you intend to use an R4k-compatible
- * counter as a timer interrupt source; otherwise it can be set up
- * automagically with an aid of mips_timer_state.
- */
-extern unsigned int mips_hpt_frequency;
+extern unsigned calibrate_timer(cycle_t (*x_read)(void),
+ int (*y_state)(void));
#endif /* _ASM_TIME_H */
--
1.5.2.rc3-dirty
^ permalink raw reply related [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-17 13:36 ` Franck Bui-Huu
@ 2007-06-17 16:14 ` Atsushi Nemoto
2007-06-18 9:38 ` Franck Bui-Huu
2007-06-18 12:41 ` Franck Bui-Huu
1 sibling, 1 reply; 56+ messages in thread
From: Atsushi Nemoto @ 2007-06-17 16:14 UTC (permalink / raw)
To: vagabon.xyz; +Cc: ralf, macro, sshtylyov, linux-mips
On Sun, 17 Jun 2007 15:36:53 +0200, "Franck Bui-Huu" <vagabon.xyz@gmail.com> wrote:
> b) Are there some weird MIPS CPUs out there which don't read/ack cp0
> hpt in the normal way ?
PNX8550? Their count/compare interrupt altomatically clears the count
register. Please refer this thread:
http://www.linux-mips.org/archives/linux-mips/2006-12/msg00194.html
I'm not sure this fits new clockevent codes or not.
---
Atsushi Nemoto
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 5/5] Implement clockevents for R4000-style cp0 timer
2007-06-17 0:04 ` Ralf Baechle
@ 2007-06-17 17:23 ` Atsushi Nemoto
2007-06-17 19:25 ` Ralf Baechle
2007-06-18 14:22 ` Franck Bui-Huu
1 sibling, 1 reply; 56+ messages in thread
From: Atsushi Nemoto @ 2007-06-17 17:23 UTC (permalink / raw)
To: ralf; +Cc: vagabon.xyz, linux-mips
On Sun, 17 Jun 2007 01:04:48 +0100, Ralf Baechle <ralf@linux-mips.org> wrote:
> [MIPS] Switch from to_tm to rtc_time_to_tm
>
> This replaces the MIPS-specific to_tm function with the generic
> rtc_time_to_tm function. The big difference between the two functions is
> that rtc_time_to_tm uses epoch 70 while to_tm uses 1970, so the result of
> rtc_time_to_tm needs to be fixed up.
>
> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Thanks, looks good to me except a few things.
> arch/mips/momentum/jaguar_atx/setup.c | 8 ++++-
Zombie? ;)
> arch/mips/momentum/ocelot_c/setup.c | 8 ++++-
Likely zombie?
> include/asm-mips/time.h | 7 ----
> 12 files changed, 36 insertions(+), 73 deletions(-)
And on more.
diff --git a/include/asm-mips/rtc.h b/include/asm-mips/rtc.h
index 82ad401..42d049f 100644
--- a/include/asm-mips/rtc.h
+++ b/include/asm-mips/rtc.h
@@ -33,8 +33,7 @@ static inline unsigned int get_rtc_time(struct rtc_time *time)
unsigned long nowtime;
nowtime = rtc_mips_get_time();
- to_tm(nowtime, time);
- time->tm_year -= 1900;
+ rtc_time_to_tm(nowtime, time);
return RTC_24H;
}
---
Atsushi Nemoto
^ permalink raw reply related [flat|nested] 56+ messages in thread
* Re: [PATCH 5/5] Implement clockevents for R4000-style cp0 timer
2007-06-17 17:23 ` Atsushi Nemoto
@ 2007-06-17 19:25 ` Ralf Baechle
0 siblings, 0 replies; 56+ messages in thread
From: Ralf Baechle @ 2007-06-17 19:25 UTC (permalink / raw)
To: Atsushi Nemoto; +Cc: vagabon.xyz, linux-mips
On Mon, Jun 18, 2007 at 02:23:14AM +0900, Atsushi Nemoto wrote:
> Thanks, looks good to me except a few things.
>
> > arch/mips/momentum/jaguar_atx/setup.c | 8 ++++-
>
> Zombie? ;)
In 2.6.21 that zombie didn't yet have the stake in its heart ;-)
Ralf
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-17 16:14 ` Atsushi Nemoto
@ 2007-06-18 9:38 ` Franck Bui-Huu
2007-06-18 15:51 ` Atsushi Nemoto
0 siblings, 1 reply; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-18 9:38 UTC (permalink / raw)
To: Atsushi Nemoto; +Cc: ralf, macro, sshtylyov, linux-mips
Hi Atsushi,
On 6/17/07, Atsushi Nemoto <anemo@mba.ocn.ne.jp> wrote:
> On Sun, 17 Jun 2007 15:36:53 +0200, "Franck Bui-Huu" <vagabon.xyz@gmail.com> wrote:
> > b) Are there some weird MIPS CPUs out there which don't read/ack cp0
> > hpt in the normal way ?
>
> PNX8550? Their count/compare interrupt altomatically clears the count
> register. Please refer this thread:
>
> http://www.linux-mips.org/archives/linux-mips/2006-12/msg00194.html
>
Oh no, another weirdo :(
What is suprising me is that there's no comment explaining what is
going on in pnx8550/common/time.c...
> I'm not sure this fits new clockevent codes or not.
Not really. What could be done in this case is to use cp0 hpt for
dealing with clock events _only_. I don't think it's an issue if the
count register is automatically cleared in this case.
And it should write it's own clocksource support which would use
different timer.
It shoud result in something like this:
unsigned __init get_freq(int cpu)
{
return 27UL * ((1000000UL * n)/(m * pow2p));
}
void __init plat_timer_init()
{
struct cp0_hpt_info info;
info.get_freq = get_freq;
info.irq = PNX8550_INT_TIMER1;
setup_cp0_hpt(&info, CLKEVT_ONLY);
setup_my_clocksource_using_a_different_timer();
}
Note that 'CLKEVT_ONLY' flag currently doesn't exist.
What do you think ?
--
Franck
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-17 13:36 ` Franck Bui-Huu
2007-06-17 16:14 ` Atsushi Nemoto
@ 2007-06-18 12:41 ` Franck Bui-Huu
2007-06-19 19:25 ` Sergei Shtylyov
1 sibling, 1 reply; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-18 12:41 UTC (permalink / raw)
To: Ralf Baechle
Cc: Maciej W. Rozycki, Sergei Shtylyov, linux-mips, Atsushi Nemoto
Franck Bui-Huu wrote:
> On 6/15/07, Ralf Baechle <ralf@linux-mips.org> wrote:
>> On Fri, Jun 15, 2007 at 10:59:00AM +0200, Franck Bui-Huu wrote:
>>
>> > > Please note that this generic calibration code may be used for
>> > >calibrating the CP0 timer too -- all that you need is defining
>> >
>> > Actually the current patchset breaks it since it changes the
>> calibration
>> > code to be used only for the cp0 hpt calibration. I'll change that.
>>
>> To many this really fun it also needs to become possible to calibrate
>> each processor's clock individually - not all MIPS MP systems run their
>> clocks at the same rate.
>>
>
> OK I've updated patch 5/5, taking into account several raised points.
and for whom interested, here is a working version...
Franck
---
Subject: [PATCH 6/6] Implement clockevents for R4000-style cp0 timer
Signed-off-by: Franck Bui-Huu <fbuihuu@gmail.com>
---
arch/mips/Kconfig | 9 +
arch/mips/kernel/Makefile | 2 +
arch/mips/kernel/hpt-cp0.c | 248 ++++++++++++++++++++++++++
arch/mips/kernel/process.c | 3 +
arch/mips/kernel/smp.c | 2 +
arch/mips/kernel/time.c | 416 ++++----------------------------------------
include/asm-mips/hpt.h | 30 ++++
include/asm-mips/time.h | 40 +----
8 files changed, 330 insertions(+), 420 deletions(-)
create mode 100644 arch/mips/kernel/hpt-cp0.c
create mode 100644 include/asm-mips/hpt.h
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 7bcf38d..d852cb0 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -723,6 +723,14 @@ config GENERIC_TIME
bool
default y
+config GENERIC_CLOCKEVENTS
+ bool
+ default y
+
+config CP0_HPT_TIMER
+ bool
+ default y
+
config GENERIC_CMOS_UPDATE
bool
default y
@@ -1741,6 +1749,7 @@ config HZ
default 1000 if HZ_1000
default 1024 if HZ_1024
+source "kernel/time/Kconfig"
source "kernel/Kconfig.preempt"
config MIPS_INSANE_LARGE
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 4924626..ffd4352 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -11,6 +11,8 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \
binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \
irix5sys.o sysirix.o
+obj-$(CONFIG_CP0_HPT_TIMER) += hpt-cp0.o
+
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_MODULES) += mips_ksyms.o module.o
diff --git a/arch/mips/kernel/hpt-cp0.c b/arch/mips/kernel/hpt-cp0.c
new file mode 100644
index 0000000..8581a20
--- /dev/null
+++ b/arch/mips/kernel/hpt-cp0.c
@@ -0,0 +1,248 @@
+/*
+ * This is a driver for CP0 hpt.
+ */
+#include <linux/kernel_stat.h>
+#include <linux/spinlock.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+
+
+#include <asm/time.h>
+#include <asm/hpt.h>
+
+
+#define MIPS_HPT_NAME "cp0-hpt"
+
+
+static unsigned (*cp0_hpt_get_freq)(int cpu) __initdata;
+static irqreturn_t (*perf_handler)(int irq, void *dev_id) __read_mostly;
+
+
+/*
+ * hpt can be disabled by boot command line
+ */
+static int cp0_hpt_disabled __initdata;
+
+static int __init no_cp0_hpt_setup(char *str)
+{
+ cp0_hpt_disabled = 1;
+ return 0;
+}
+early_param("no-cp0-hpt", no_cp0_hpt_setup);
+
+/*
+ * cp0 hpt operations.
+ */
+static void cp0_hpt_ack(void)
+{
+ write_c0_compare(read_c0_compare());
+}
+
+static cycle_t cp0_hpt_read(void)
+{
+ return read_c0_count();
+}
+
+/*
+ * Clocksource functions
+ */
+struct clocksource hpt_clocksource = {
+ .name = MIPS_HPT_NAME,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .read = cp0_hpt_read,
+};
+
+/*
+ * FIXME: for a clocksource, rating should not depend on frequency,
+ * stability is something more valuable...
+ */
+static int cp0_hpt_rating(unsigned freq)
+{
+ return 200 + freq / 10000000;
+}
+
+static void __init setup_cp0_hpt_clocksource(void)
+{
+ unsigned freq = cp0_hpt_get_freq(smp_processor_id());
+ unsigned shift = 0;
+ u64 mult;
+
+ for (shift = 32; shift > 0; shift--) {
+ mult = (u64)NSEC_PER_SEC << shift;
+ do_div(mult, freq);
+ if ((mult >> 32) == 0)
+ break;
+ }
+
+ hpt_clocksource.shift = shift;
+ hpt_clocksource.mult = mult;
+ hpt_clocksource.rating = cp0_hpt_rating(freq);
+
+ clocksource_register(&hpt_clocksource);
+}
+
+/*
+ * High precision timer functions
+ */
+
+static int cp0_hpt_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ unsigned int cnt;
+
+ BUG_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
+
+ /* interrupt ack is done by setting up the next event */
+ cnt = read_c0_count();
+ cnt += delta;
+ write_c0_compare(cnt);
+
+ return ((long)(read_c0_count() - cnt) > 0L) ? -ETIME : 0;
+}
+
+static void cp0_hpt_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ /*
+ * For now, we can't disable cp0 hpt interrupts. So we
+ * leave them enabled, and ignore them in this mode.
+ * Therefore we will get one useless but also harmless
+ * interrupt every 2^32 cycles...
+ */
+ cp0_hpt_ack();
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* nothing to do */
+ break;
+ case CLOCK_EVT_MODE_PERIODIC:
+ BUG();
+ };
+}
+
+static struct clock_event_device hpt_clockevent __initdata = {
+ .name = MIPS_HPT_NAME,
+ .mode = CLOCK_EVT_MODE_UNUSED,
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .shift = 32,
+ .set_mode = cp0_hpt_set_mode,
+ .set_next_event = cp0_hpt_set_next_event,
+ .irq = -1,
+};
+
+static DEFINE_PER_CPU(struct clock_event_device, cp0_hpt_clock_events);
+
+void __init setup_cp0_hpt_clockevent(void)
+{
+ struct clock_event_device *cd;
+ int cpu = smp_processor_id();
+ unsigned freq;
+
+ if (cp0_hpt_disabled)
+ return;
+
+ cd = &__get_cpu_var(cp0_hpt_clock_events);
+
+ memcpy(cd, &hpt_clockevent, sizeof(*cd));
+
+ freq = cp0_hpt_get_freq(cpu);
+
+ cd->mult = div_sc(freq, NSEC_PER_SEC, cd->shift);
+ cd->rating = cp0_hpt_rating(freq);
+ cd->cpumask = cpumask_of_cpu(cpu);
+
+ cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
+ cd->min_delta_ns = clockevent_delta2ns(0x10, cd);
+
+ clockevents_register_device(cd);
+
+ printk("Using %u.%03u MHz CP0 high precision timer on CPU #%d.\n",
+ ((freq + 500) / 1000) / 1000,
+ ((freq + 500) / 1000) % 1000,
+ cpu);
+}
+
+static irqreturn_t cp0_hpt_interrupt(int irq, void *dev_id)
+{
+ const int r2 = cpu_has_mips_r2;
+ struct clock_event_device *cd;
+
+ /*
+ * Suckage alert:
+ * Before R2 of the architecture there was no way to see if a
+ * performance counter interrupt was pending, so we have to run
+ * the performance counter interrupt handler anyway.
+ */
+ if (perf_handler && perf_handler(irq, dev_id) == IRQ_HANDLED)
+ /*
+ * The performance counter overflow interrupt may be
+ * shared with the timer interrupt. If it is (!r2)
+ * then we can't reliably determine if a counter
+ * interrupt has also happened. So don't check for a
+ * timer interrupt in this case.
+ */
+ if (!r2)
+ goto out;
+
+ /*
+ * The same applies to performance counter interrupts. But with the
+ * above we now know that the reason we got here must be a timer
+ * interrupt. Being the paranoiacs we are we check anyway.
+ */
+ if (!r2 || (read_c0_cause() & (1 << 30))) {
+ /*
+ * We can get interrupts whereas the hpt clock event
+ * device has been disabled since we can't shut it
+ * down. So always ack the timer.
+ */
+ cp0_hpt_ack();
+
+ cd = &__get_cpu_var(cp0_hpt_clock_events);
+ if (likely(cd->mode != CLOCK_EVT_MODE_SHUTDOWN))
+ cd->event_handler(cd);
+ }
+out:
+ return IRQ_HANDLED;
+}
+
+struct irqaction hpt_irqaction = {
+ .handler = cp0_hpt_interrupt,
+ .flags = IRQF_DISABLED | IRQF_PERCPU,
+ .name = MIPS_HPT_NAME,
+};
+
+
+/*
+ * This function is used by platforms which use the hpt as clock
+ * source and timer.
+ */
+int __init setup_cp0_hpt(struct cp0_hpt_info *info)
+{
+ if (cp0_hpt_disabled)
+ goto out;
+ if (!cpu_has_counter)
+ goto disable;
+
+ if (info->irq == 0)
+ goto disable;
+ if (info->get_freq == NULL)
+ goto disable;
+
+ cp0_hpt_get_freq = info->get_freq;
+ perf_handler = info->perf_handler;
+
+ setup_cp0_hpt_clocksource();
+ setup_cp0_hpt_clockevent();
+
+ /* Enable events interrupt. */
+ setup_irq(info->irq, &hpt_irqaction);
+out:
+ return 0;
+disable:
+ printk(KERN_WARNING "Error when starting CP0 hpt... disabled\n");
+ cp0_hpt_disabled = 1;
+ return -EINVAL;
+}
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 6bdfb5a..23b8858 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -25,6 +25,7 @@
#include <linux/init.h>
#include <linux/completion.h>
#include <linux/kallsyms.h>
+#include <linux/tick.h>
#include <asm/bootinfo.h>
#include <asm/cpu.h>
@@ -50,6 +51,7 @@ ATTRIB_NORET void cpu_idle(void)
{
/* endless idle loop with no priority at all */
while (1) {
+ tick_nohz_stop_sched_tick();
while (!need_resched()) {
#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG
extern void smtc_idle_loop_hook(void);
@@ -59,6 +61,7 @@ ATTRIB_NORET void cpu_idle(void)
if (cpu_wait)
(*cpu_wait)();
}
+ tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
schedule();
preempt_disable();
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 67edfa7..85ad130 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -37,6 +37,7 @@
#include <asm/system.h>
#include <asm/mmu_context.h>
#include <asm/smp.h>
+#include <asm/hpt.h>
#ifdef CONFIG_MIPS_MT_SMTC
#include <asm/mipsmtregs.h>
@@ -79,6 +80,7 @@ asmlinkage __cpuinit void start_secondary(void)
cpu_probe();
cpu_report();
per_cpu_trap_init();
+ setup_cp0_hpt_clockevent(/* calibrate_timer() */);
prom_init_secondary();
/*
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 72df0bf..0cc8363 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -1,48 +1,16 @@
-/*
- * Copyright 2001 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- * Copyright (c) 2003, 2004 Maciej W. Rozycki
- *
- * Common time service routines for MIPS machines. See
- * Documentation/mips/time.README.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/param.h>
-#include <linux/time.h>
-#include <linux/timex.h>
-#include <linux/smp.h>
#include <linux/kernel_stat.h>
#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
+#include <linux/clocksource.h> /* cycle_t */
-#include <asm/bootinfo.h>
-#include <asm/cache.h>
-#include <asm/compiler.h>
-#include <asm/cpu.h>
-#include <asm/cpu-features.h>
-#include <asm/div64.h>
-#include <asm/sections.h>
#include <asm/time.h>
/*
- * The integer part of the number of usecs per jiffy is taken from tick,
- * but the fractional part is not recorded, so we calculate it using the
- * initial value of HZ. This aids systems where tick isn't really an
- * integer (e.g. for HZ = 128).
+ * This is the freq of the tick timer of the platform. It's not
+ * always a _high_ precision timer as its name suggests.
+ *
+ * FIXME: Is it really needed ? shouldn't it be a per cpu value ?
*/
-#define USECS_PER_JIFFY TICK_SIZE
-#define USECS_PER_JIFFY_FRAC ((unsigned long)(u32)((1000000ULL << 32) / HZ))
-
-#define TICK_SIZE (tick_nsec / 1000)
+unsigned int mips_hpt_frequency __read_mostly;
/*
* RTC. By default we provide the null RTC hooks
@@ -79,264 +47,36 @@ int update_persistent_clock(struct timespec now)
return mips_rtc_set_mmss(now.tv_sec);
}
-/* how many counter cycles in a jiffy */
-static unsigned long cycles_per_jiffy __read_mostly;
-
-/* expirelo is the count value for next CPU timer interrupt */
-static unsigned int expirelo;
-
-
-/*
- * Null timer ack for systems not needing one (e.g. i8254).
- */
-static void null_timer_ack(void) { /* nothing */ }
-
-/*
- * Null high precision timer functions for systems lacking one.
- */
-static cycle_t null_hpt_read(void)
-{
- return 0;
-}
-
-/*
- * Timer ack for an R4k-compatible timer of a known frequency.
- */
-static void c0_timer_ack(void)
-{
- unsigned int count;
-
- /* Ack this timer interrupt and set the next one. */
- expirelo += cycles_per_jiffy;
- write_c0_compare(expirelo);
-
- /* Check to see if we have missed any timer interrupts. */
- while (((count = read_c0_count()) - expirelo) < 0x7fffffff) {
- /* missed_timer_count++; */
- expirelo = count + cycles_per_jiffy;
- write_c0_compare(expirelo);
- }
-}
-
-/*
- * High precision timer functions for a R4k-compatible timer.
- */
-static cycle_t c0_hpt_read(void)
-{
- return read_c0_count();
-}
-
-/* For use both as a high precision timer and an interrupt source. */
-static void __init c0_hpt_timer_init(void)
-{
- expirelo = read_c0_count() + cycles_per_jiffy;
- write_c0_compare(expirelo);
-}
-
-int (*mips_timer_state)(void);
-void (*mips_timer_ack)(void);
-
-/*
- * local_timer_interrupt() does profiling and process accounting
- * on a per-CPU basis.
- *
- * In UP mode, it is invoked from the (global) timer_interrupt.
- *
- * In SMP mode, it might invoked by per-CPU timer interrupt, or
- * a broadcasted inter-processor interrupt which itself is triggered
- * by the global timer interrupt.
- */
-void local_timer_interrupt(int irq)
-{
- profile_tick(CPU_PROFILING);
- update_process_times(user_mode(get_irq_regs()));
-}
-
-/*
- * High-level timer interrupt service routines. This function
- * is set as irqaction->handler and is invoked through do_IRQ.
- */
-irqreturn_t timer_interrupt(int irq, void *dev_id)
-{
- write_seqlock(&xtime_lock);
-
- mips_timer_ack();
-
- /*
- * call the generic timer interrupt handling
- */
- do_timer(1);
-
- write_sequnlock(&xtime_lock);
-
- /*
- * In UP mode, we call local_timer_interrupt() to do profiling
- * and process accouting.
- *
- * In SMP mode, local_timer_interrupt() is invoked by appropriate
- * low-level local timer interrupt handler.
- */
- local_timer_interrupt(irq);
-
- return IRQ_HANDLED;
-}
-
-int null_perf_irq(void)
-{
- return 0;
-}
-
-EXPORT_SYMBOL(null_perf_irq);
-
-int (*perf_irq)(void) = null_perf_irq;
-
-EXPORT_SYMBOL(perf_irq);
-
-/*
- * Performance counter IRQ or -1 if shared with timer
- */
-int mipsxx_perfcount_irq;
-EXPORT_SYMBOL(mipsxx_perfcount_irq);
-
/*
- * Possibly handle a performance counter interrupt.
- * Return true if the timer interrupt should not be checked
+ * Basically it calls the platform hooks to setup:
+ * a) RTC
+ * b) a timer
*/
-static inline int handle_perf_irq(int r2)
-{
- /*
- * The performance counter overflow interrupt may be shared with the
- * timer interrupt (mipsxx_perfcount_irq < 0). If it is and a
- * performance counter has overflowed (perf_irq() == IRQ_HANDLED)
- * and we can't reliably determine if a counter interrupt has also
- * happened (!r2) then don't check for a timer interrupt.
- */
- return (mipsxx_perfcount_irq < 0) &&
- perf_irq() == IRQ_HANDLED &&
- !r2;
-}
-
-extern void smtc_timer_broadcast(int);
-
-void ll_timer_interrupt(int irq)
+void __init time_init(void)
{
- int cpu = smp_processor_id();
- int r2 = cpu_has_mips_r2;
-
- irq_enter();
- kstat_this_cpu.irqs[irq]++;
-
-#ifdef CONFIG_MIPS_MT_SMTC
/*
- * In an SMTC system, one Count/Compare set exists per VPE.
- * Which TC within a VPE gets the interrupt is essentially
- * random - we only know that it shouldn't be one with
- * IXMT set. Whichever TC gets the interrupt needs to
- * send special interprocessor interrupts to the other
- * TCs to make sure that they schedule, etc.
- *
- * That code is specific to the SMTC kernel, not to
- * the a particular platform, so it's invoked from
- * the general MIPS timer_interrupt routine.
+ * Mandatory platform hook. It basically setup the RTC.
+ * FIXME: shouldn't we call these before calling
+ * timekeeping_init() ?
*/
+ plat_time_init();
/*
- * We could be here due to timer interrupt,
- * perf counter overflow, or both.
+ * Platform can setup a new timer, hpt timer...
*/
- (void) handle_perf_irq(1);
-
- if (read_c0_cause() & (1 << 30)) {
- /*
- * There are things we only want to do once per tick
- * in an "MP" system. One TC of each VPE will take
- * the actual timer interrupt. The others will get
- * timer broadcast IPIs. We use whoever it is that takes
- * the tick on VPE 0 to run the full timer_interrupt().
- */
- if (cpu_data[cpu].vpe_id == 0) {
- timer_interrupt(irq, NULL);
- } else {
- write_c0_compare(read_c0_count() +
- (mips_hpt_frequency/HZ));
- local_timer_interrupt(irq);
- }
- smtc_timer_broadcast(cpu_data[cpu].vpe_id);
- }
-#else /* CONFIG_MIPS_MT_SMTC */
- if (handle_perf_irq(r2))
- goto out;
-
- if (r2 && ((read_c0_cause() & (1 << 30)) == 0))
- goto out;
-
- if (cpu == 0) {
- /*
- * CPU 0 handles the global timer interrupt job and process
- * accounting resets count/compare registers to trigger next
- * timer int.
- */
- timer_interrupt(irq, NULL);
- } else {
- /* Everyone else needs to reset the timer int here as
- ll_local_timer_interrupt doesn't */
- /*
- * FIXME: need to cope with counter underflow.
- * More support needs to be added to kernel/time for
- * counter/timer interrupts on multiple CPU's
- */
- write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ));
-
- /*
- * Other CPUs should do profiling and process accounting
- */
- local_timer_interrupt(irq);
- }
-out:
-#endif /* CONFIG_MIPS_MT_SMTC */
-
- irq_exit();
+ plat_timer_setup();
}
-asmlinkage void ll_local_timer_interrupt(int irq)
-{
- irq_enter();
- if (smp_processor_id() != 0)
- kstat_this_cpu.irqs[irq]++;
-
- /* we keep interrupt disabled all the time */
- local_timer_interrupt(irq);
-
- irq_exit();
-}
-
/*
- * time_init() - it does the following things.
- *
- * 1) plat_time_init() -
- * a) (optional) set up RTC routines,
- * b) (optional) calibrate and set the mips_hpt_frequency
- * (only needed if you intended to use cpu counter as timer interrupt
- * source)
- * 2) calculate a couple of cached variables for later usage
- * 3) plat_timer_setup() -
- * a) (optional) over-write any choices made above by time_init().
- * b) machine specific code should setup the timer irqaction.
- * c) enable the timer interrupt
+ * If you don't know timer 'X' frequency and have another timer 'Y'
+ * that flips at HZ rate, you can use this helper to determinate the
+ * timer 'X' freq.
*/
-
-unsigned int mips_hpt_frequency;
-
-static struct irqaction timer_irqaction = {
- .handler = timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_PERCPU,
- .name = "timer",
-};
-
-static unsigned int __init calibrate_hpt(void)
+unsigned __init calibrate_timer(cycle_t (*x_read)(void),
+ int (*y_state)(void))
{
- cycle_t frequency, hpt_start, hpt_end, hpt_count, hz;
+ cycle_t freq, start, end, count, hz;
const int loops = HZ / 10;
int log_2_loops = 0;
@@ -354,118 +94,24 @@ static unsigned int __init calibrate_hpt(void)
/*
* Wait for a rising edge of the timer interrupt.
*/
- while (mips_timer_state());
- while (!mips_timer_state());
+ while (y_state());
+ while (!y_state());
/*
* Now see how many high precision timer ticks happen
* during the calculated number of periods between timer
* interrupts.
*/
- hpt_start = clocksource_mips.read();
+ start = x_read();
do {
- while (mips_timer_state());
- while (!mips_timer_state());
+ while (y_state());
+ while (!y_state());
} while (--i);
- hpt_end = clocksource_mips.read();
+ end = x_read();
- hpt_count = (hpt_end - hpt_start) & clocksource_mips.mask;
+ count = end - start;
hz = HZ;
- frequency = hpt_count * hz;
-
- return frequency >> log_2_loops;
-}
-
-struct clocksource clocksource_mips = {
- .name = "MIPS",
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static void __init init_mips_clocksource(void)
-{
- u64 temp;
- u32 shift;
-
- if (!mips_hpt_frequency || clocksource_mips.read == null_hpt_read)
- return;
-
- /* Calclate a somewhat reasonable rating value */
- clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
- /* Find a shift value */
- for (shift = 32; shift > 0; shift--) {
- temp = (u64) NSEC_PER_SEC << shift;
- do_div(temp, mips_hpt_frequency);
- if ((temp >> 32) == 0)
- break;
- }
- clocksource_mips.shift = shift;
- clocksource_mips.mult = (u32)temp;
-
- clocksource_register(&clocksource_mips);
-}
-
-void __init __weak plat_time_init(void)
-{
-}
-
-void __init time_init(void)
-{
- plat_time_init();
-
- /* Choose appropriate high precision timer routines. */
- if (!cpu_has_counter && !clocksource_mips.read)
- /* No high precision timer -- sorry. */
- clocksource_mips.read = null_hpt_read;
- else if (!mips_hpt_frequency && !mips_timer_state) {
- /* A high precision timer of unknown frequency. */
- if (!clocksource_mips.read)
- /* No external high precision timer -- use R4k. */
- clocksource_mips.read = c0_hpt_read;
- } else {
- /* We know counter frequency. Or we can get it. */
- if (!clocksource_mips.read) {
- /* No external high precision timer -- use R4k. */
- clocksource_mips.read = c0_hpt_read;
-
- if (!mips_timer_state) {
- /* No external timer interrupt -- use R4k. */
- mips_timer_ack = c0_timer_ack;
- /* Calculate cache parameters. */
- cycles_per_jiffy =
- (mips_hpt_frequency + HZ / 2) / HZ;
- /*
- * This sets up the high precision
- * timer for the first interrupt.
- */
- c0_hpt_timer_init();
- }
- }
- if (!mips_hpt_frequency)
- mips_hpt_frequency = calibrate_hpt();
-
- /* Report the high precision timer rate for a reference. */
- printk("Using %u.%03u MHz high precision timer.\n",
- ((mips_hpt_frequency + 500) / 1000) / 1000,
- ((mips_hpt_frequency + 500) / 1000) % 1000);
- }
-
- if (!mips_timer_ack)
- /* No timer interrupt ack (e.g. i8254). */
- mips_timer_ack = null_timer_ack;
-
- /*
- * Call board specific timer interrupt setup.
- *
- * this pointer must be setup in machine setup routine.
- *
- * Even if a machine chooses to use a low-level timer interrupt,
- * it still needs to setup the timer_irqaction.
- * In that case, it might be better to set timer_irqaction.handler
- * to be NULL function so that we are sure the high-level code
- * is not invoked accidentally.
- */
- plat_timer_setup(&timer_irqaction);
+ freq = count * hz;
- init_mips_clocksource();
+ return freq >> log_2_loops;
}
diff --git a/include/asm-mips/hpt.h b/include/asm-mips/hpt.h
new file mode 100644
index 0000000..2b62827
--- /dev/null
+++ b/include/asm-mips/hpt.h
@@ -0,0 +1,30 @@
+#ifndef _ASM_HPT_H
+#define _ASM_HPT_H
+
+#ifdef CONFIG_CP0_HPT_TIMER
+
+struct cp0_hpt_info {
+ /* FIXME: could we let the user override hpt ops ? */
+ /* FIXME: should we add a disable_irq method ? */
+ int irq;
+ unsigned (*get_freq)(int cpu);
+
+ /*
+ * The performance counter overflow irq may be shared with the
+ * hpt interrupt. In that case this handler will be called
+ * during a hpt interrupt.
+ */
+ irqreturn_t (*perf_handler)(int irq, void *dev_id);
+};
+
+
+extern int setup_cp0_hpt(struct cp0_hpt_info *info);
+extern void setup_cp0_hpt_clockevent(void);
+
+#else
+
+static inline void setup_cp0_hpt_clockevent(void) {}
+
+#endif /* CONFIG_CP0_HPT_TIMER */
+
+#endif /* _ASM_HPT_H */
diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h
index 33645ed..6d8c9b4 100644
--- a/include/asm-mips/time.h
+++ b/include/asm-mips/time.h
@@ -16,12 +16,8 @@
#ifndef _ASM_TIME_H
#define _ASM_TIME_H
-#include <linux/interrupt.h>
-#include <linux/linkage.h>
-#include <linux/ptrace.h>
+#include <linux/clocksource.h> /* cycle_t */
#include <linux/rtc.h>
-#include <linux/spinlock.h>
-#include <linux/clocksource.h>
extern spinlock_t rtc_lock;
@@ -41,12 +37,6 @@ extern int (*mips_timer_state)(void);
extern void (*mips_timer_ack)(void);
/*
- * High precision timer clocksource.
- * If .read is NULL, an R4k-compatible timer setup is attempted.
- */
-extern struct clocksource clocksource_mips;
-
-/*
* to_tm() converts system time back to (year, mon, day, hour, min, sec).
* It is intended to help implement rtc_set_time() functions.
* Copied from PPC implementation.
@@ -54,32 +44,12 @@ extern struct clocksource clocksource_mips;
extern void to_tm(unsigned long tim, struct rtc_time *tm);
/*
- * high-level timer interrupt routines.
- */
-extern irqreturn_t timer_interrupt(int irq, void *dev_id);
-
-/*
- * the corresponding low-level timer interrupt routine.
- */
-extern void ll_timer_interrupt(int irq);
-
-/*
- * profiling and process accouting is done separately in local_timer_interrupt
+ * board specific hooks called by time_init().
*/
-extern void local_timer_interrupt(int irq);
-
-/*
- * board specific routines required by time_init().
- */
-struct irqaction;
extern void plat_time_init(void);
-extern void plat_timer_setup(struct irqaction *irq);
+extern void plat_timer_setup(void);
-/*
- * mips_hpt_frequency - must be set if you intend to use an R4k-compatible
- * counter as a timer interrupt source; otherwise it can be set up
- * automagically with an aid of mips_timer_state.
- */
-extern unsigned int mips_hpt_frequency;
+extern unsigned calibrate_timer(cycle_t (*x_read)(void),
+ int (*y_state)(void));
#endif /* _ASM_TIME_H */
--
1.5.2.2
^ permalink raw reply related [flat|nested] 56+ messages in thread
* Re: [PATCH 5/5] Implement clockevents for R4000-style cp0 timer
2007-06-17 0:04 ` Ralf Baechle
2007-06-17 17:23 ` Atsushi Nemoto
@ 2007-06-18 14:22 ` Franck Bui-Huu
2007-06-18 15:14 ` Ralf Baechle
2007-06-18 15:37 ` Ralf Baechle
1 sibling, 2 replies; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-18 14:22 UTC (permalink / raw)
To: Ralf Baechle; +Cc: Atsushi Nemoto, linux-mips
Ralf Baechle wrote:
> On Thu, Jun 14, 2007 at 09:29:13PM +0900, Atsushi Nemoto wrote:
>
>> I think this to_tm() cleanup should be done in separate patch.
>>
>> Maybe selecting RTC_LIB in Kconfig and replace all to_tm() calls with
>>
>> rtc_time_to_tm(tim, tm);
>> tm->tm_year += 1900;
>>
>> would be enough.
>
> Looks good to me, done.
>
> Ralf
>
> [MIPS] Switch from to_tm to rtc_time_to_tm
>
> This replaces the MIPS-specific to_tm function with the generic
> rtc_time_to_tm function. The big difference between the two functions is
> that rtc_time_to_tm uses epoch 70 while to_tm uses 1970, so the result of
> rtc_time_to_tm needs to be fixed up.
>
> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
>
Since very few boards are using GEN_RTC:
$ git grep -l "GEN_RTC=y" arch/mips/configs/
arch/mips/configs/bigsur_defconfig
arch/mips/configs/yosemite_defconfig
Maybe it's high time to move to RTC_CLASS and let these 2
platforms fix their codes.
BTW, I thought that the following rtc function pointers:
unsigned long (*rtc_mips_get_time)(void) = null_rtc_get_time;
int (*rtc_mips_set_time)(unsigned long) = null_rtc_set_time;
int (*rtc_mips_set_mmss)(unsigned long);
were an interface for _generic_ rtc only. But all the following
platforms don't seem to use the generic rtc though it initialises
these function pointers... Any idea why ?
arch/mips/ddb5xxx/common/rtc_ds1386.c
arch/mips/dec/time.c
arch/mips/lasat/setup.c
arch/mips/mips-boards/atlas/atlas_setup.c
arch/mips/mips-boards/malta/malta_setup.c
arch/mips/momentum/ocelot_3/setup.c
arch/mips/momentum/ocelot_c/setup.c
arch/mips/pmc-sierra/yosemite/setup.c
arch/mips/sgi-ip22/ip22-time.c
arch/mips/sgi-ip32/ip32-setup.c
arch/mips/sibyte/swarm/setup.c
arch/mips/sni/a20r.c
arch/mips/sni/pcimt.c
arch/mips/sni/pcit.c
arch/mips/sni/rm200.c
arch/mips/tx4938/common/rtc_rx5c348.c
And maybe once every platforms will use RTC_CLASS, then we could
implement read_persistent_clock like this:
unsigned long read_persistent_clock(void)
{
struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
struct rtc_time tm;
unsigned long time;
if (rtc == NULL)
return 0;
rtc_read_time(rtc, &tm);
rtc_tm_to_time(&tm, &time);
return time;
}
Here's a patch which simply kills the generic RTC support in MIPS.
---
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 7def1ff..0fcc0e5 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -44,29 +44,6 @@
#define TICK_SIZE (tick_nsec / 1000)
-/*
- * forward reference
- */
-DEFINE_SPINLOCK(rtc_lock);
-
-/*
- * By default we provide the null RTC ops
- */
-static unsigned long null_rtc_get_time(void)
-{
- return mktime(2000, 1, 1, 0, 0, 0);
-}
-
-static int null_rtc_set_time(unsigned long sec)
-{
- return 0;
-}
-
-unsigned long (*rtc_mips_get_time)(void) = null_rtc_get_time;
-int (*rtc_mips_set_time)(unsigned long) = null_rtc_set_time;
-int (*rtc_mips_set_mmss)(unsigned long);
-
-
/* how many counter cycles in a jiffy */
static unsigned long cycles_per_jiffy __read_mostly;
diff --git a/include/asm-mips/rtc.h b/include/asm-mips/rtc.h
deleted file mode 100644
index 82ad401..0000000
--- a/include/asm-mips/rtc.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * include/asm-mips/rtc.h
- *
- * (Really an interface for drivers/char/genrtc.c)
- *
- * Copyright (C) 2004 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- *
- * Please read the COPYING file for all license details.
- */
-
-#ifndef _MIPS_RTC_H
-#define _MIPS_RTC_H
-
-#ifdef __KERNEL__
-
-#include <linux/rtc.h>
-#include <asm/time.h>
-
-#define RTC_PIE 0x40 /* periodic interrupt enable */
-#define RTC_AIE 0x20 /* alarm interrupt enable */
-#define RTC_UIE 0x10 /* update-finished interrupt enable */
-
-/* some dummy definitions */
-#define RTC_BATT_BAD 0x100 /* battery bad */
-#define RTC_SQWE 0x08 /* enable square-wave output */
-#define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
-#define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
-#define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
-
-static inline unsigned int get_rtc_time(struct rtc_time *time)
-{
- unsigned long nowtime;
-
- nowtime = rtc_mips_get_time();
- to_tm(nowtime, time);
- time->tm_year -= 1900;
-
- return RTC_24H;
-}
-
-static inline int set_rtc_time(struct rtc_time *time)
-{
- unsigned long nowtime;
- int ret;
-
- nowtime = mktime(time->tm_year+1900, time->tm_mon+1,
- time->tm_mday, time->tm_hour, time->tm_min,
- time->tm_sec);
- ret = rtc_mips_set_time(nowtime);
-
- return ret;
-}
-
-static inline unsigned int get_rtc_ss(void)
-{
- struct rtc_time h;
-
- get_rtc_time(&h);
- return h.tm_sec;
-}
-
-static inline int get_rtc_pll(struct rtc_pll_info *pll)
-{
- return -EINVAL;
-}
-
-static inline int set_rtc_pll(struct rtc_pll_info *pll)
-{
- return -EINVAL;
-}
-#endif
-#endif
^ permalink raw reply related [flat|nested] 56+ messages in thread
* Re: [PATCH 5/5] Implement clockevents for R4000-style cp0 timer
2007-06-18 14:22 ` Franck Bui-Huu
@ 2007-06-18 15:14 ` Ralf Baechle
2007-06-18 15:38 ` Franck Bui-Huu
2007-06-18 15:37 ` Ralf Baechle
1 sibling, 1 reply; 56+ messages in thread
From: Ralf Baechle @ 2007-06-18 15:14 UTC (permalink / raw)
To: Franck Bui-Huu; +Cc: Atsushi Nemoto, linux-mips
On Mon, Jun 18, 2007 at 04:22:39PM +0200, Franck Bui-Huu wrote:
> were an interface for _generic_ rtc only. But all the following
> platforms don't seem to use the generic rtc though it initialises
> these function pointers... Any idea why ?
Because unless drivers/char/Kconfig is getting changed to prevent that is
is possible to enable CONFIG_GEN_RTC, so this code was necessary for
correctness. Aside I think it did simply propagate through cutnpaste.
That at least was the reason in the 2.4 days when the old kernel
configuration language made it way to painful to deal with such
configurations. These days I think we should rather get rid of genrtc.
Genrtc used to be nice candy but like most sweets long term it results in
caries ;-)
Ralf
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 5/5] Implement clockevents for R4000-style cp0 timer
2007-06-18 14:22 ` Franck Bui-Huu
2007-06-18 15:14 ` Ralf Baechle
@ 2007-06-18 15:37 ` Ralf Baechle
2007-06-19 17:00 ` Sergei Shtylyov
1 sibling, 1 reply; 56+ messages in thread
From: Ralf Baechle @ 2007-06-18 15:37 UTC (permalink / raw)
To: Franck Bui-Huu; +Cc: Atsushi Nemoto, linux-mips
On Mon, Jun 18, 2007 at 04:22:39PM +0200, Franck Bui-Huu wrote:
> Since very few boards are using GEN_RTC:
>
> $ git grep -l "GEN_RTC=y" arch/mips/configs/
> arch/mips/configs/bigsur_defconfig
> arch/mips/configs/yosemite_defconfig
Btw, you missed emma2rh_defconfig which builds GEN_RTC as a module. Silly
because it doesn't initialize rtc_mips_get_time or rtc_mips_set_time so
hasn't possible a chance to work as anything but a dummy rtc.
Ralf
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 5/5] Implement clockevents for R4000-style cp0 timer
2007-06-18 15:14 ` Ralf Baechle
@ 2007-06-18 15:38 ` Franck Bui-Huu
2007-06-18 15:55 ` Franck Bui-Huu
0 siblings, 1 reply; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-18 15:38 UTC (permalink / raw)
To: Ralf Baechle; +Cc: Atsushi Nemoto, linux-mips
Hi Ralf,
On 6/18/07, Ralf Baechle <ralf@linux-mips.org> wrote:
> On Mon, Jun 18, 2007 at 04:22:39PM +0200, Franck Bui-Huu wrote:
>
> > were an interface for _generic_ rtc only. But all the following
> > platforms don't seem to use the generic rtc though it initialises
> > these function pointers... Any idea why ?
>
> Because unless drivers/char/Kconfig is getting changed to prevent that is
> is possible to enable CONFIG_GEN_RTC, so this code was necessary for
> correctness.
Sorry I don't understand...
> Aside I think it did simply propagate through cutnpaste.
> That at least was the reason in the 2.4 days when the old kernel
> configuration language made it way to painful to deal with such
> configurations. These days I think we should rather get rid of genrtc.
I think so...
> Genrtc used to be nice candy but like most sweets long term it results in
> caries ;-)
:)
--
Franck
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-18 9:38 ` Franck Bui-Huu
@ 2007-06-18 15:51 ` Atsushi Nemoto
2007-06-19 7:33 ` Franck Bui-Huu
0 siblings, 1 reply; 56+ messages in thread
From: Atsushi Nemoto @ 2007-06-18 15:51 UTC (permalink / raw)
To: vagabon.xyz; +Cc: ralf, macro, sshtylyov, linux-mips
On Mon, 18 Jun 2007 11:38:28 +0200, "Franck Bui-Huu" <vagabon.xyz@gmail.com> wrote:
> And it should write it's own clocksource support which would use
> different timer.
I suppose so.
> It shoud result in something like this:
>
> unsigned __init get_freq(int cpu)
> {
> return 27UL * ((1000000UL * n)/(m * pow2p));
> }
>
> void __init plat_timer_init()
> {
> struct cp0_hpt_info info;
>
> info.get_freq = get_freq;
> info.irq = PNX8550_INT_TIMER1;
> setup_cp0_hpt(&info, CLKEVT_ONLY);
>
> setup_my_clocksource_using_a_different_timer();
> }
>
> Note that 'CLKEVT_ONLY' flag currently doesn't exist.
>
> What do you think ?
For now, I think bloating generic setup_cp0_hpt() for this particular
chip is not good. The pnx8550 can have customized copy of cp0_hpt
routines. But it's just a thought...
---
Atsushi Nemoto
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 5/5] Implement clockevents for R4000-style cp0 timer
2007-06-18 15:38 ` Franck Bui-Huu
@ 2007-06-18 15:55 ` Franck Bui-Huu
2007-06-18 16:01 ` Ralf Baechle
2007-06-18 17:42 ` Ralf Baechle
0 siblings, 2 replies; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-18 15:55 UTC (permalink / raw)
To: Ralf Baechle; +Cc: Atsushi Nemoto, linux-mips
On 6/18/07, Franck Bui-Huu <vagabon.xyz@gmail.com> wrote:
> Hi Ralf,
>
> On 6/18/07, Ralf Baechle <ralf@linux-mips.org> wrote:
> > On Mon, Jun 18, 2007 at 04:22:39PM +0200, Franck Bui-Huu wrote:
> >
> > > were an interface for _generic_ rtc only. But all the following
> > > platforms don't seem to use the generic rtc though it initialises
> > > these function pointers... Any idea why ?
> >
> > Because unless drivers/char/Kconfig is getting changed to prevent that is
> > is possible to enable CONFIG_GEN_RTC, so this code was necessary for
> > correctness.
>
> Sorry I don't understand...
>
Ok I think I'm understanding now. So you mean that most of the
following platforms:
arch/mips/ddb5xxx/common/rtc_ds1386.c
arch/mips/dec/time.c
arch/mips/lasat/setup.c
arch/mips/mips-boards/atlas/atlas_setup.c
arch/mips/mips-boards/malta/malta_setup.c
arch/mips/momentum/ocelot_3/setup.c
arch/mips/momentum/ocelot_c/setup.c
arch/mips/pmc-sierra/yosemite/setup.c
arch/mips/sgi-ip22/ip22-time.c
arch/mips/sgi-ip32/ip32-setup.c
arch/mips/sibyte/swarm/setup.c
arch/mips/sni/a20r.c
arch/mips/sni/pcimt.c
arch/mips/sni/pcit.c
arch/mips/sni/rm200.c
arch/mips/tx4938/common/rtc_rx5c348.c
implements set and get rtc functions because genrtc can be enabled in
Kconfig ???
If so what about the following patch:
-- 8< --
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 55253a6..e8f3b0c 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -813,7 +813,7 @@ config SGI_IP27_RTC
config GEN_RTC
tristate "Generic /dev/rtc emulation"
- depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV &&
!S390 && !SUPERH
+ depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV &&
!S390 && !SUPERH && !MIPS
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
-- >8 --
and burn all the genrtc platform methods ?
Thanks
--
Franck
^ permalink raw reply related [flat|nested] 56+ messages in thread
* Re: [PATCH 5/5] Implement clockevents for R4000-style cp0 timer
2007-06-18 15:55 ` Franck Bui-Huu
@ 2007-06-18 16:01 ` Ralf Baechle
2007-06-18 17:42 ` Ralf Baechle
1 sibling, 0 replies; 56+ messages in thread
From: Ralf Baechle @ 2007-06-18 16:01 UTC (permalink / raw)
To: Franck Bui-Huu; +Cc: Atsushi Nemoto, linux-mips
On Mon, Jun 18, 2007 at 05:55:28PM +0200, Franck Bui-Huu wrote:
> and burn all the genrtc platform methods ?
Yes, that was my plan.
Ralf
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 5/5] Implement clockevents for R4000-style cp0 timer
2007-06-18 15:55 ` Franck Bui-Huu
2007-06-18 16:01 ` Ralf Baechle
@ 2007-06-18 17:42 ` Ralf Baechle
1 sibling, 0 replies; 56+ messages in thread
From: Ralf Baechle @ 2007-06-18 17:42 UTC (permalink / raw)
To: Franck Bui-Huu; +Cc: Atsushi Nemoto, linux-mips
On Mon, Jun 18, 2007 at 05:55:28PM +0200, Franck Bui-Huu wrote:
> and burn all the genrtc platform methods ?
The same methods are also being used on bootup for reading the RTC and
when NTP synchronized, so basically only <asm/rtc.h> can go. But I just
did that and have updated the
git://git.linux-mips.org/pub/scm/linux-time.git
tree. As usual work in progress.
Ralf
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-18 15:51 ` Atsushi Nemoto
@ 2007-06-19 7:33 ` Franck Bui-Huu
2007-06-19 16:08 ` Atsushi Nemoto
0 siblings, 1 reply; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-19 7:33 UTC (permalink / raw)
To: Atsushi Nemoto; +Cc: ralf, macro, sshtylyov, linux-mips
Hi Atsushi,
On 6/18/07, Atsushi Nemoto <anemo@mba.ocn.ne.jp> wrote:
> On Mon, 18 Jun 2007 11:38:28 +0200, "Franck Bui-Huu" <vagabon.xyz@gmail.com> wrote:
> > What do you think ?
>
> For now, I think bloating generic setup_cp0_hpt() for this particular
> chip is not good. The pnx8550 can have customized copy of cp0_hpt
> routines. But it's just a thought...
>
What do you mean by "pnx8550 can have customized copy of cp0_hpt
routines" ? Do you mean that it should copy the whole clock event
driver ?
It seems to me that using cp0 hpt as a clock event only is a valid usage...
--
Franck
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-19 7:33 ` Franck Bui-Huu
@ 2007-06-19 16:08 ` Atsushi Nemoto
2007-06-19 16:22 ` Sergei Shtylyov
2007-06-19 17:00 ` Franck Bui-Huu
0 siblings, 2 replies; 56+ messages in thread
From: Atsushi Nemoto @ 2007-06-19 16:08 UTC (permalink / raw)
To: vagabon.xyz; +Cc: ralf, macro, sshtylyov, linux-mips
On Tue, 19 Jun 2007 09:33:33 +0200, "Franck Bui-Huu" <vagabon.xyz@gmail.com> wrote:
> What do you mean by "pnx8550 can have customized copy of cp0_hpt
> routines" ? Do you mean that it should copy the whole clock event
> driver ?
>
> It seems to me that using cp0 hpt as a clock event only is a valid usage...
Well, I thought the customized cp0 clockevent codes (custom
.set_next_event routine is needed anyway, isn't it?) would be small
enough. But I did not investigate deeply. If generic cp0 hpt can
handle this beast without much bloating, it would be great.
---
Atsushi Nemoto
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-19 16:08 ` Atsushi Nemoto
@ 2007-06-19 16:22 ` Sergei Shtylyov
2007-06-19 16:55 ` Franck Bui-Huu
2007-06-19 21:58 ` Ralf Baechle
2007-06-19 17:00 ` Franck Bui-Huu
1 sibling, 2 replies; 56+ messages in thread
From: Sergei Shtylyov @ 2007-06-19 16:22 UTC (permalink / raw)
To: vagabon.xyz; +Cc: Atsushi Nemoto, ralf, macro, linux-mips
Atsushi Nemoto wrote:
>>What do you mean by "pnx8550 can have customized copy of cp0_hpt
>>routines" ? Do you mean that it should copy the whole clock event
>>driver ?
>>It seems to me that using cp0 hpt as a clock event only is a valid usage...
> Well, I thought the customized cp0 clockevent codes (custom
> .set_next_event routine is needed anyway, isn't it?) would be small
> enough. But I did not investigate deeply. If generic cp0 hpt can
> handle this beast without much bloating, it would be great.
IMO, the generic code should only have the standard MIPS count/compare
support and let the platform code to initialize it if it choses so and also
register its own specific clock[source|event] devices if it choses so -- i.e
*not* what the current clocksource code does...
> ---
> Atsushi Nemoto
WBR, Sergei
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-19 16:22 ` Sergei Shtylyov
@ 2007-06-19 16:55 ` Franck Bui-Huu
2007-06-19 21:58 ` Ralf Baechle
1 sibling, 0 replies; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-19 16:55 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: Atsushi Nemoto, ralf, macro, linux-mips
On 6/19/07, Sergei Shtylyov <sshtylyov@ru.mvista.com> wrote:
> Atsushi Nemoto wrote:
>
> >>What do you mean by "pnx8550 can have customized copy of cp0_hpt
> >>routines" ? Do you mean that it should copy the whole clock event
> >>driver ?
>
> >>It seems to me that using cp0 hpt as a clock event only is a valid usage...
>
> > Well, I thought the customized cp0 clockevent codes (custom
> > .set_next_event routine is needed anyway, isn't it?) would be small
> > enough. But I did not investigate deeply. If generic cp0 hpt can
> > handle this beast without much bloating, it would be great.
>
> IMO, the generic code should only have the standard MIPS count/compare
> support and let the platform code to initialize it if it choses so and also
> register its own specific clock[source|event] devices if it choses so -- i.e
> *not* what the current clocksource code does...
>
And this is _exactly_ what the new patch 5/5 I sent yesteday does and
what I suggested to DEC and PNX5550 thing...
Please have a look to it (if you have time of course) at:
http://marc.info/?l=linux-mips&m=118217055927261&w=2
CP0 count/compare support is handled in arch/mips/kernel/hpt-cp0.c new
file. Therefore it can be compiled or not easily. And it lets the
platform code initialize it if it wants to. So we can easily now see
which platform is using what, and get rid of the ugly thing in generic
time code trying to detect which hpt the platform is trying to use.
The main issue with this approach is that we need to update a lot of
board code which is a pain because it's currently hard to guess what
it does and platform maintainers seem to be really busy to help in
this area...
Thanks
--
Franck
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-19 16:08 ` Atsushi Nemoto
2007-06-19 16:22 ` Sergei Shtylyov
@ 2007-06-19 17:00 ` Franck Bui-Huu
2007-06-19 17:26 ` Sergei Shtylyov
1 sibling, 1 reply; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-19 17:00 UTC (permalink / raw)
To: Atsushi Nemoto; +Cc: ralf, macro, sshtylyov, linux-mips
On 6/19/07, Atsushi Nemoto <anemo@mba.ocn.ne.jp> wrote:
> On Tue, 19 Jun 2007 09:33:33 +0200, "Franck Bui-Huu" <vagabon.xyz@gmail.com> wrote:
> > What do you mean by "pnx8550 can have customized copy of cp0_hpt
> > routines" ? Do you mean that it should copy the whole clock event
> > driver ?
> >
> > It seems to me that using cp0 hpt as a clock event only is a valid usage...
>
> Well, I thought the customized cp0 clockevent codes (custom
> .set_next_event routine is needed anyway, isn't it?)
I don't think so.
hpt-cp0.c clock event part doesn't care if the counter is cleared when
an interrupt is triggered. It matters only for clock source (well I
think) that's why I suggested to rewrite a clock source driver only
for this platform...
--
Franck
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 5/5] Implement clockevents for R4000-style cp0 timer
2007-06-18 15:37 ` Ralf Baechle
@ 2007-06-19 17:00 ` Sergei Shtylyov
2007-06-20 8:15 ` Ralf Baechle
0 siblings, 1 reply; 56+ messages in thread
From: Sergei Shtylyov @ 2007-06-19 17:00 UTC (permalink / raw)
To: Ralf Baechle; +Cc: Franck Bui-Huu, Atsushi Nemoto, linux-mips
Hello.
Ralf Baechle wrote:
>>Since very few boards are using GEN_RTC:
>> $ git grep -l "GEN_RTC=y" arch/mips/configs/
>> arch/mips/configs/bigsur_defconfig
>> arch/mips/configs/yosemite_defconfig
> Btw, you missed emma2rh_defconfig which builds GEN_RTC as a module. Silly
> because it doesn't initialize rtc_mips_get_time or rtc_mips_set_time so
> hasn't possible a chance to work as anything but a dummy rtc.
EMMA2RH bpard doesn't seem to have an RTC.
> Ralf
WBR, Sergei
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-19 17:00 ` Franck Bui-Huu
@ 2007-06-19 17:26 ` Sergei Shtylyov
2007-06-19 17:31 ` Sergei Shtylyov
2007-06-19 19:34 ` Sergei Shtylyov
0 siblings, 2 replies; 56+ messages in thread
From: Sergei Shtylyov @ 2007-06-19 17:26 UTC (permalink / raw)
To: Franck Bui-Huu; +Cc: Atsushi Nemoto, ralf, macro, linux-mips
Franck Bui-Huu wrote:
>> On Tue, 19 Jun 2007 09:33:33 +0200, "Franck Bui-Huu"
>> <vagabon.xyz@gmail.com> wrote:
>> > What do you mean by "pnx8550 can have customized copy of cp0_hpt
>> > routines" ? Do you mean that it should copy the whole clock event
>> > driver ?
>> > It seems to me that using cp0 hpt as a clock event only is a valid
>> usage...
>> Well, I thought the customized cp0 clockevent codes (custom
>> .set_next_event routine is needed anyway, isn't it?)
> I don't think so.
> hpt-cp0.c clock event part doesn't care if the counter is cleared when
> an interrupt is triggered.
Well, in the generic case it must read back the Count reg. before writing
to the Compare reg. and for PNX8550 this is unnecessary -- but indeed, should
not harm...
> It matters only for clock source (well I
> think) that's why I suggested to rewrite a clock source driver only
> for this platform...
Yeah, this platform certainly *needs* another clocksource than the counter
used for the clock events -- currently it's count/compare 2.
And this platform also *needs* a separate clocksource driver as well since
the PNX8550 counters *do* support auto-reaload mode here -- in fact, this
seems to be the only supported mode from the manual excerpt cited here:
http://www.linux-mips.org/archives/linux-mips/2006-12/msg00194.html
WBR, Sergei
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-19 17:26 ` Sergei Shtylyov
@ 2007-06-19 17:31 ` Sergei Shtylyov
2007-06-19 19:34 ` Sergei Shtylyov
1 sibling, 0 replies; 56+ messages in thread
From: Sergei Shtylyov @ 2007-06-19 17:31 UTC (permalink / raw)
To: Franck Bui-Huu; +Cc: Atsushi Nemoto, ralf, macro, linux-mips
Hello, I wrote:
>>> On Tue, 19 Jun 2007 09:33:33 +0200, "Franck Bui-Huu"
>>> <vagabon.xyz@gmail.com> wrote:
>>> > What do you mean by "pnx8550 can have customized copy of cp0_hpt
>>> > routines" ? Do you mean that it should copy the whole clock event
>>> > driver ?
>>> > It seems to me that using cp0 hpt as a clock event only is a valid
>>> usage...
>>> Well, I thought the customized cp0 clockevent codes (custom
>>> .set_next_event routine is needed anyway, isn't it?)
>> I don't think so.
>> hpt-cp0.c clock event part doesn't care if the counter is cleared when
>> an interrupt is triggered.
> Well, in the generic case it must read back the Count reg. before
> writing to the Compare reg. and for PNX8550 this is unnecessary -- but
> indeed, should not harm...
Well, I was thinking the counter stops at 0 after being clearesd by the
match when writing this, which is not the case. So, ignore this sentese.
WBR, Sergei
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-18 12:41 ` Franck Bui-Huu
@ 2007-06-19 19:25 ` Sergei Shtylyov
2007-06-20 10:24 ` Franck Bui-Huu
0 siblings, 1 reply; 56+ messages in thread
From: Sergei Shtylyov @ 2007-06-19 19:25 UTC (permalink / raw)
To: Franck; +Cc: Ralf Baechle, Maciej W. Rozycki, linux-mips, Atsushi Nemoto
Hello.
Franck Bui-Huu wrote:
> Subject: [PATCH 6/6] Implement clockevents for R4000-style cp0 timer
[...]
> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
> index 7bcf38d..d852cb0 100644
> --- a/arch/mips/Kconfig
> +++ b/arch/mips/Kconfig
> @@ -723,6 +723,14 @@ config GENERIC_TIME
> bool
> default y
>
> +config GENERIC_CLOCKEVENTS
> + bool
> + default y
> +
> +config CP0_HPT_TIMER
I'd suggest just CP0_TIMER...
> + bool
> + default y
> +
> config GENERIC_CMOS_UPDATE
> bool
> default y
[...]
> diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
> index 4924626..ffd4352 100644
> --- a/arch/mips/kernel/Makefile
> +++ b/arch/mips/kernel/Makefile
> @@ -11,6 +11,8 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \
> binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \
> irix5sys.o sysirix.o
>
> +obj-$(CONFIG_CP0_HPT_TIMER) += hpt-cp0.o
cp0-timer.o here too.
> +
> obj-$(CONFIG_STACKTRACE) += stacktrace.o
> obj-$(CONFIG_MODULES) += mips_ksyms.o module.o
>
> diff --git a/arch/mips/kernel/hpt-cp0.c b/arch/mips/kernel/hpt-cp0.c
> new file mode 100644
> index 0000000..8581a20
> --- /dev/null
> +++ b/arch/mips/kernel/hpt-cp0.c
> @@ -0,0 +1,248 @@
> +/*
> + * This is a driver for CP0 hpt.
> + */
> +#include <linux/kernel_stat.h>
> +#include <linux/spinlock.h>
> +#include <linux/clockchips.h>
> +#include <linux/clocksource.h>
> +
> +
> +#include <asm/time.h>
> +#include <asm/hpt.h>
> +
> +
> +#define MIPS_HPT_NAME "cp0-hpt"
I'd named it "cp0-timer" or something.
> +/*
> + * High precision timer functions
> + */
> +
> +static int cp0_hpt_set_next_event(unsigned long delta,
> + struct clock_event_device *evt)
> +{
> + unsigned int cnt;
> +
> + BUG_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
> +
> + /* interrupt ack is done by setting up the next event */
> + cnt = read_c0_count();
> + cnt += delta;
> + write_c0_compare(cnt);
> +
> + return ((long)(read_c0_count() - cnt) > 0L) ? -ETIME : 0;
> +}
> +
> +static void cp0_hpt_set_mode(enum clock_event_mode mode,
> + struct clock_event_device *evt)
> +{
> + switch (mode) {
> + case CLOCK_EVT_MODE_UNUSED:
> + case CLOCK_EVT_MODE_SHUTDOWN:
> + /*
> + * For now, we can't disable cp0 hpt interrupts. So we
> + * leave them enabled, and ignore them in this mode.
> + * Therefore we will get one useless but also harmless
> + * interrupt every 2^32 cycles...
> + */
> + cp0_hpt_ack();
Good idea...
> + break;
> + case CLOCK_EVT_MODE_ONESHOT:
> + /* nothing to do */
> + break;
> + case CLOCK_EVT_MODE_PERIODIC:
> + BUG();
> + };
> +}
> +
> +static struct clock_event_device hpt_clockevent __initdata = {
> + .name = MIPS_HPT_NAME,
> + .mode = CLOCK_EVT_MODE_UNUSED,
> + .features = CLOCK_EVT_FEAT_ONESHOT,
> + .shift = 32,
> + .set_mode = cp0_hpt_set_mode,
> + .set_next_event = cp0_hpt_set_next_event,
> + .irq = -1,
> +};
> +
> +static DEFINE_PER_CPU(struct clock_event_device, cp0_hpt_clock_events);
Oh, these are declared per-CPU at last...
> +static irqreturn_t cp0_hpt_interrupt(int irq, void *dev_id)
> +{
> + const int r2 = cpu_has_mips_r2;
> + struct clock_event_device *cd;
> +
> + /*
> + * Suckage alert:
> + * Before R2 of the architecture there was no way to see if a
> + * performance counter interrupt was pending, so we have to run
> + * the performance counter interrupt handler anyway.
> + */
> + if (perf_handler && perf_handler(irq, dev_id) == IRQ_HANDLED)
> + /*
> + * The performance counter overflow interrupt may be
> + * shared with the timer interrupt. If it is (!r2)
> + * then we can't reliably determine if a counter
> + * interrupt has also happened. So don't check for a
> + * timer interrupt in this case.
> + */
> + if (!r2)
> + goto out;
Might be folded into one if stmt...
> +
> + /*
> + * The same applies to performance counter interrupts. But with the
> + * above we now know that the reason we got here must be a timer
> + * interrupt. Being the paranoiacs we are we check anyway.
> + */
> + if (!r2 || (read_c0_cause() & (1 << 30))) {
> + /*
> + * We can get interrupts whereas the hpt clock event
> + * device has been disabled since we can't shut it
> + * down. So always ack the timer.
> + */
> + cp0_hpt_ack();
> +
> + cd = &__get_cpu_var(cp0_hpt_clock_events);
> + if (likely(cd->mode != CLOCK_EVT_MODE_SHUTDOWN))
Hm, I thought the upper level code takes care of this case... well, it
might have in 2.6.18 time. :-)
But maybe CLOCK_EVT_MODE_UNUSED should also be checked?
> + cd->event_handler(cd);
> + }
> +out:
> + return IRQ_HANDLED;
> +}
> +
> +struct irqaction hpt_irqaction = {
> + .handler = cp0_hpt_interrupt,
> + .flags = IRQF_DISABLED | IRQF_PERCPU,
> + .name = MIPS_HPT_NAME,
> +};
> +/*
> + * This function is used by platforms which use the hpt as clock
> + * source and timer.
> + */
> +int __init setup_cp0_hpt(struct cp0_hpt_info *info)
> +{
> + if (cp0_hpt_disabled)
> + goto out;
> + if (!cpu_has_counter)
> + goto disable;
> +
> + if (info->irq == 0)
> + goto disable;
Shouldn't harm clocksource, in theory.
> + if (info->get_freq == NULL)
> + goto disable;
> +
> + cp0_hpt_get_freq = info->get_freq;
> + perf_handler = info->perf_handler;
> +
> + setup_cp0_hpt_clocksource();
> + setup_cp0_hpt_clockevent();
Probably not both. It would have been the best thing to have the separate
init. functions...
> diff --git a/include/asm-mips/hpt.h b/include/asm-mips/hpt.h
> new file mode 100644
> index 0000000..2b62827
> --- /dev/null
> +++ b/include/asm-mips/hpt.h
> @@ -0,0 +1,30 @@
> +#ifndef _ASM_HPT_H
> +#define _ASM_HPT_H
> +
> +#ifdef CONFIG_CP0_HPT_TIMER
> +
> +struct cp0_hpt_info {
Not sure if we need the structure at this point at all...
> + /* FIXME: could we let the user override hpt ops ? */
No.
> + /* FIXME: should we add a disable_irq method ? */
Couldn't it be handled in somegeneric way?
> + int irq;
> + unsigned (*get_freq)(int cpu);
> +
> + /*
> + * The performance counter overflow irq may be shared with the
> + * hpt interrupt. In that case this handler will be called
> + * during a hpt interrupt.
> + */
> + irqreturn_t (*perf_handler)(int irq, void *dev_id);
Hm... what it's doing here, in this structure?
> +};
> +
> +
> +extern int setup_cp0_hpt(struct cp0_hpt_info *info);
> +extern void setup_cp0_hpt_clockevent(void);
No explicit 'extern' needed for functions -- they all have that memory
class by deafult.
WBR, Sergei
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-19 17:26 ` Sergei Shtylyov
2007-06-19 17:31 ` Sergei Shtylyov
@ 2007-06-19 19:34 ` Sergei Shtylyov
1 sibling, 0 replies; 56+ messages in thread
From: Sergei Shtylyov @ 2007-06-19 19:34 UTC (permalink / raw)
To: Franck Bui-Huu; +Cc: Atsushi Nemoto, ralf, macro, linux-mips
Hello, I wrote:
>> It matters only for clock source (well I
>> think) that's why I suggested to rewrite a clock source driver only
>> for this platform...
> Yeah, this platform certainly *needs* another clocksource than the
Not necessarily so -- we could use count1 *exclusively* as clocksource
after some setup, i.e. setting its comparator to all ones, hooking its IRQ and
enabling the counting.
> counter used for the clock events -- currently it's count/compare 2.
... and use that one as clockevent.
> And this platform also *needs* a separate clocksource driver as well
I meant to say "clockevent" here. :-)
> since the PNX8550 counters *do* support auto-reaload mode here -- in
> fact, this seems to be the only supported mode from the manual excerpt
> cited here:
> http://www.linux-mips.org/archives/linux-mips/2006-12/msg00194.html
WBR, Sergei
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-19 16:22 ` Sergei Shtylyov
2007-06-19 16:55 ` Franck Bui-Huu
@ 2007-06-19 21:58 ` Ralf Baechle
2007-06-20 10:27 ` Franck Bui-Huu
1 sibling, 1 reply; 56+ messages in thread
From: Ralf Baechle @ 2007-06-19 21:58 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: vagabon.xyz, Atsushi Nemoto, macro, linux-mips
On Tue, Jun 19, 2007 at 08:22:59PM +0400, Sergei Shtylyov wrote:
> From: Sergei Shtylyov <sshtylyov@ru.mvista.com>
> Date: Tue, 19 Jun 2007 20:22:59 +0400
> To: vagabon.xyz@gmail.com
> Cc: Atsushi Nemoto <anemo@mba.ocn.ne.jp>, ralf@linux-mips.org,
> macro@linux-mips.org, linux-mips@linux-mips.org
> Subject: Re: [PATCH 3/5] Deforest the function pointer jungle in the time
> code.
> Content-Type: text/plain; charset=us-ascii; format=flowed
>
> Atsushi Nemoto wrote:
>
> >>What do you mean by "pnx8550 can have customized copy of cp0_hpt
> >>routines" ? Do you mean that it should copy the whole clock event
> >>driver ?
>
> >>It seems to me that using cp0 hpt as a clock event only is a valid
> >>usage...
>
> >Well, I thought the customized cp0 clockevent codes (custom
> >.set_next_event routine is needed anyway, isn't it?) would be small
> >enough. But I did not investigate deeply. If generic cp0 hpt can
> >handle this beast without much bloating, it would be great.
>
> IMO, the generic code should only have the standard MIPS count/compare
> support and let the platform code to initialize it if it choses so and also
> register its own specific clock[source|event] devices if it choses so --
> i.e *not* what the current clocksource code does...
For practically every type of timer there are reasons why it is may be
undesierable such as being configured in a way that makes it undesirable
or unusable, unpredictable clock changes and more. So in practice only
the platform specific code can drive the initialization of all timer
devices and interrupts which reduces the generic code to sort of a
library and driver collection.
Ralf
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 5/5] Implement clockevents for R4000-style cp0 timer
2007-06-19 17:00 ` Sergei Shtylyov
@ 2007-06-20 8:15 ` Ralf Baechle
0 siblings, 0 replies; 56+ messages in thread
From: Ralf Baechle @ 2007-06-20 8:15 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: Franck Bui-Huu, Atsushi Nemoto, linux-mips
On Tue, Jun 19, 2007 at 09:00:22PM +0400, Sergei Shtylyov wrote:
> >Btw, you missed emma2rh_defconfig which builds GEN_RTC as a module. Silly
> >because it doesn't initialize rtc_mips_get_time or rtc_mips_set_time so
> >hasn't possible a chance to work as anything but a dummy rtc.
>
> EMMA2RH bpard doesn't seem to have an RTC.
I guess then having it fail rather then pretending it has has functinality
which isn't there seems to be the better thing.
Ralf
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-19 19:25 ` Sergei Shtylyov
@ 2007-06-20 10:24 ` Franck Bui-Huu
0 siblings, 0 replies; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-20 10:24 UTC (permalink / raw)
To: Sergei Shtylyov
Cc: Ralf Baechle, Maciej W. Rozycki, linux-mips, Atsushi Nemoto
Hi,
Thanks for considering.
Sergei Shtylyov wrote:
>> @@ -723,6 +723,14 @@ config GENERIC_TIME
>> bool
>> default y
>>
>> +config GENERIC_CLOCKEVENTS
>> + bool
>> + default y
>> +
>> +config CP0_HPT_TIMER
>
> I'd suggest just CP0_TIMER...
>
TIMER is confusing with timers implemented in kernel/timer.c
Maybe ?
CP0_HRT,
CP0_CLOCKS,
>>
>> +obj-$(CONFIG_CP0_HPT_TIMER) += hpt-cp0.o
>
> cp0-timer.o here too.
ditto.
>> +
>> +#define MIPS_HPT_NAME "cp0-hpt"
>
> I'd named it "cp0-timer" or something.
ditto
>> +static void cp0_hpt_set_mode(enum clock_event_mode mode,
>> + struct clock_event_device *evt)
>> +{
>> + switch (mode) {
>> + case CLOCK_EVT_MODE_UNUSED:
>> + case CLOCK_EVT_MODE_SHUTDOWN:
>> + /*
>> + * For now, we can't disable cp0 hpt interrupts. So we
>> + * leave them enabled, and ignore them in this mode.
>> + * Therefore we will get one useless but also harmless
>> + * interrupt every 2^32 cycles...
>> + */
>> + cp0_hpt_ack();
>
> Good idea...
What about this other alternative ?
static void cp0_hpt_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
switch (mode) {
case CLOCK_EVT_MODE_UNUSED:
free_irq(hpt_irq, NULL);
break;
case CLOCK_EVT_MODE_SHUTDOWN:
cp0_hpt_ack();
break;
case CLOCK_EVT_MODE_ONESHOT:
setup_irq(hpt_irq, &hpt_irqaction);
break;
case CLOCK_EVT_MODE_PERIODIC:
BUG();
};
}
>> +static irqreturn_t cp0_hpt_interrupt(int irq, void *dev_id)
>> +{
>> + const int r2 = cpu_has_mips_r2;
>> + struct clock_event_device *cd;
>> +
>> + /*
>> + * Suckage alert:
>> + * Before R2 of the architecture there was no way to see if a
>> + * performance counter interrupt was pending, so we have to run
>> + * the performance counter interrupt handler anyway.
>> + */
>> + if (perf_handler && perf_handler(irq, dev_id) == IRQ_HANDLED)
>> + /*
>> + * The performance counter overflow interrupt may be
>> + * shared with the timer interrupt. If it is (!r2)
>> + * then we can't reliably determine if a counter
>> + * interrupt has also happened. So don't check for a
>> + * timer interrupt in this case.
>> + */
>> + if (!r2)
>> + goto out;
>
> Might be folded into one if stmt...
>
If you don't mind I prefer let it as is. I think it's more readable and
the second comment right before the "if (!r2)" condition can be well
placed.
>> +
>> + /*
>> + * The same applies to performance counter interrupts. But with the
>> + * above we now know that the reason we got here must be a timer
>> + * interrupt. Being the paranoiacs we are we check anyway.
>> + */
>> + if (!r2 || (read_c0_cause() & (1 << 30))) {
>> + /*
>> + * We can get interrupts whereas the hpt clock event
>> + * device has been disabled since we can't shut it
>> + * down. So always ack the timer.
>> + */
>> + cp0_hpt_ack();
>> +
>> + cd = &__get_cpu_var(cp0_hpt_clock_events);
>> + if (likely(cd->mode != CLOCK_EVT_MODE_SHUTDOWN))
>
> Hm, I thought the upper level code takes care of this case... well, it
> might have in 2.6.18 time. :-)
Sorry I don't see what you mean. It's an interrupt handler, what
do you mean by "upper level code" ?
> But maybe CLOCK_EVT_MODE_UNUSED should also be checked?
yes. Actually this test should be:
if (likely(cd->mode == CLOCK_EVT_MODE_ONESHOT))
...
>
>> + cd->event_handler(cd);
>> + }
>> +out:
>> + return IRQ_HANDLED;
>> +}
>> +
>> +struct irqaction hpt_irqaction = {
>> + .handler = cp0_hpt_interrupt,
>> + .flags = IRQF_DISABLED | IRQF_PERCPU,
>> + .name = MIPS_HPT_NAME,
>> +};
>
>> +/*
>> + * This function is used by platforms which use the hpt as clock
>> + * source and timer.
>> + */
>> +int __init setup_cp0_hpt(struct cp0_hpt_info *info)
>> +{
>> + if (cp0_hpt_disabled)
>> + goto out;
>> + if (!cpu_has_counter)
>> + goto disable;
>> +
>> + if (info->irq == 0)
>> + goto disable;
>
> Shouldn't harm clocksource, in theory.
>
agreed.
>> + if (info->get_freq == NULL)
>> + goto disable;
>> +
>> + cp0_hpt_get_freq = info->get_freq;
>> + perf_handler = info->perf_handler;
>> +
>> + setup_cp0_hpt_clocksource();
>> + setup_cp0_hpt_clockevent();
>
> Probably not both. It would have been the best thing to have the
> separate
> init. functions...
OK.
>
>> diff --git a/include/asm-mips/hpt.h b/include/asm-mips/hpt.h
>> new file mode 100644
>> index 0000000..2b62827
>> --- /dev/null
>> +++ b/include/asm-mips/hpt.h
>> @@ -0,0 +1,30 @@
>> +#ifndef _ASM_HPT_H
>> +#define _ASM_HPT_H
>> +
>> +#ifdef CONFIG_CP0_HPT_TIMER
>> +
>> +struct cp0_hpt_info {
>
> Not sure if we need the structure at this point at all...
>
>> + /* FIXME: could we let the user override hpt ops ? */
>
> No.
>
Alright.
>> + /* FIXME: should we add a disable_irq method ? */
>
> Couldn't it be handled in somegeneric way?
>
Not really, or at least there're some configs where you can't. See
this thread from:
http://marc.info/?l=linux-mips&m=118121616820659&w=2
That said maybe we can provide a default disable_irq() that would
disable CP0 hpt irq from CP0. That would be the 'generic' way. And
we still give the possibility to override it through the cp0_hpt_info
structure. Of course the same thing would be needed to enable CP0
hpt interrupts.
What do you think ?
>> + int irq;
>> + unsigned (*get_freq)(int cpu);
>> +
>> + /*
>> + * The performance counter overflow irq may be shared with the
>> + * hpt interrupt. In that case this handler will be called
>> + * during a hpt interrupt.
>> + */
>> + irqreturn_t (*perf_handler)(int irq, void *dev_id);
>
> Hm... what it's doing here, in this structure?
>
As the comment above tries to explain, the cp0 hpt interrupts can
be shared with the perf interrupts on some systems.
Should I rephrase the comment ?
>> +};
>> +
>> +
>> +extern int setup_cp0_hpt(struct cp0_hpt_info *info);
>> +extern void setup_cp0_hpt_clockevent(void);
>
> No explicit 'extern' needed for functions -- they all have that
> memory class by deafult.
Just a matter of coding style. The same happens with "unsigned" and
"unsigned int"...
Thanks again,
--
Franck
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH 3/5] Deforest the function pointer jungle in the time code.
2007-06-19 21:58 ` Ralf Baechle
@ 2007-06-20 10:27 ` Franck Bui-Huu
0 siblings, 0 replies; 56+ messages in thread
From: Franck Bui-Huu @ 2007-06-20 10:27 UTC (permalink / raw)
To: Ralf Baechle; +Cc: Sergei Shtylyov, Atsushi Nemoto, macro, linux-mips
On 6/19/07, Ralf Baechle <ralf@linux-mips.org> wrote:
> For practically every type of timer there are reasons why it is may be
> undesierable such as being configured in a way that makes it undesirable
> or unusable, unpredictable clock changes and more. So in practice only
> the platform specific code can drive the initialization of all timer
> devices and interrupts which reduces the generic code to sort of a
> library and driver collection.
>
Yeah that's true. If you look at time_init() arch hook after patch 5/5
is applied, you can see that it's now:
void __init time_init(void)
{
plat_time_init();
plat_timer_setup();
}
--
Franck
^ permalink raw reply [flat|nested] 56+ messages in thread
end of thread, other threads:[~2007-06-20 13:56 UTC | newest]
Thread overview: 56+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-06-14 10:19 [RFD] Time rework [take #2] Franck Bui-Huu
2007-06-14 10:19 ` [PATCH 1/5] Use generic NTP code for all MIPS platforms Franck Bui-Huu
2007-06-14 10:19 ` [PATCH 2/5] Remove unused time.c for swarm Franck Bui-Huu
2007-06-14 10:19 ` [PATCH 3/5] Deforest the function pointer jungle in the time code Franck Bui-Huu
2007-06-14 11:17 ` Thomas Bogendoerfer
2007-06-14 13:43 ` Franck Bui-Huu
2007-06-14 14:09 ` Maciej W. Rozycki
2007-06-14 14:31 ` Franck Bui-Huu
2007-06-14 16:33 ` Maciej W. Rozycki
2007-06-14 16:54 ` Maciej W. Rozycki
2007-06-15 8:59 ` Franck Bui-Huu
2007-06-15 11:07 ` Maciej W. Rozycki
2007-06-15 13:26 ` Ralf Baechle
2007-06-15 14:08 ` Maciej W. Rozycki
2007-06-15 14:21 ` Ralf Baechle
2007-06-15 14:24 ` Franck Bui-Huu
2007-06-15 14:38 ` Ralf Baechle
2007-06-15 15:34 ` Franck Bui-Huu
2007-06-15 14:35 ` Sergei Shtylyov
2007-06-15 13:49 ` Ralf Baechle
2007-06-15 14:42 ` Sergei Shtylyov
2007-06-17 13:36 ` Franck Bui-Huu
2007-06-17 16:14 ` Atsushi Nemoto
2007-06-18 9:38 ` Franck Bui-Huu
2007-06-18 15:51 ` Atsushi Nemoto
2007-06-19 7:33 ` Franck Bui-Huu
2007-06-19 16:08 ` Atsushi Nemoto
2007-06-19 16:22 ` Sergei Shtylyov
2007-06-19 16:55 ` Franck Bui-Huu
2007-06-19 21:58 ` Ralf Baechle
2007-06-20 10:27 ` Franck Bui-Huu
2007-06-19 17:00 ` Franck Bui-Huu
2007-06-19 17:26 ` Sergei Shtylyov
2007-06-19 17:31 ` Sergei Shtylyov
2007-06-19 19:34 ` Sergei Shtylyov
2007-06-18 12:41 ` Franck Bui-Huu
2007-06-19 19:25 ` Sergei Shtylyov
2007-06-20 10:24 ` Franck Bui-Huu
2007-06-14 15:52 ` Franck Bui-Huu
2007-06-14 16:45 ` Maciej W. Rozycki
2007-06-14 10:20 ` [PATCH 4/5] Consolidate all variants of MIPS cp0 timer interrupt handlers Franck Bui-Huu
2007-06-14 10:20 ` [PATCH 5/5] Implement clockevents for R4000-style cp0 timer Franck Bui-Huu
2007-06-14 12:29 ` Atsushi Nemoto
2007-06-14 13:00 ` Franck Bui-Huu
2007-06-17 0:04 ` Ralf Baechle
2007-06-17 17:23 ` Atsushi Nemoto
2007-06-17 19:25 ` Ralf Baechle
2007-06-18 14:22 ` Franck Bui-Huu
2007-06-18 15:14 ` Ralf Baechle
2007-06-18 15:38 ` Franck Bui-Huu
2007-06-18 15:55 ` Franck Bui-Huu
2007-06-18 16:01 ` Ralf Baechle
2007-06-18 17:42 ` Ralf Baechle
2007-06-18 15:37 ` Ralf Baechle
2007-06-19 17:00 ` Sergei Shtylyov
2007-06-20 8:15 ` Ralf Baechle
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.