From: David Edelsohn <hidden> Date: 2000-08-04 15:25:06
quoted
quoted
quoted
quoted
Gabriel Paubert writes:
Gabriel> What I need to know from people with an SMP machine:
Gabriel> - are the timebases synchronized ? Or is there a way to synchronize them ?
On RS/6000 CHRP (RS/6000 Platform Architecture), RTAS provides
freeze-time-base and thaw-time-base calls which signal all of the
processors inan SMP complex to stop and start the TB. I do not know of
any functionality within the PowerPC architecture which would allow
processors to coordinate their TBs without some external intervention.
Normally AIX boot freezes the TB, zeroes the TB on each processor,
and then starts the timebase synchronized. Because the functionality is
part of RTAS, this can be done at any time. I do not know what PreP SMP
systems do and I know that Apple discourages use of RTAS because it is not
intended to work.
David
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
From: Benjamin Herrenschmidt <hidden> Date: 2000-08-04 15:50:23
On RS/6000 CHRP (RS/6000 Platform Architecture), RTAS provides
freeze-time-base and thaw-time-base calls which signal all of the
processors inan SMP complex to stop and start the TB. I do not know of
any functionality within the PowerPC architecture which would allow
processors to coordinate their TBs without some external intervention.
Normally AIX boot freezes the TB, zeroes the TB on each processor,
and then starts the timebase synchronized. Because the functionality is
part of RTAS, this can be done at any time. I do not know what PreP SMP
systems do and I know that Apple discourages use of RTAS because it is not
intended to work.
On recent Core99 machines, Apple has a HW timer in the KeyLargo ASIC that
can be used to sync timebases. (It looks like a 64 bits bus-cycle timer,
but I'm not completely sure yet). There's also, I beleive, the OpenPIC timer.
Ben.
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
From: Gabriel Paubert <hidden> Date: 2000-08-07 11:51:32
On Fri, 4 Aug 2000, David Edelsohn wrote:
On RS/6000 CHRP (RS/6000 Platform Architecture), RTAS provides
freeze-time-base and thaw-time-base calls which signal all of the
processors inan SMP complex to stop and start the TB. I do not know of
any functionality within the PowerPC architecture which would allow
processors to coordinate their TBs without some external intervention.
Normally AIX boot freezes the TB, zeroes the TB on each processor,
and then starts the timebase synchronized. Because the functionality is
part of RTAS, this can be done at any time. I do not know what PreP SMP
systems do and I know that Apple discourages use of RTAS because it is not
intended to work.
Thanks for the info. AFAIK most (all?) PPC processors have a TBEN pin to
enable the timebase (whether it affects the decrementer or not is
irrelevant). On some chipsets (Motorola Falcon or Hawk at least) a few
bits in a system control register are designated to control these pins
with one bit per processor (although I fail to see why you would want to
enable or disable the timebases individually).
Hard reset also clears the timebase on all the processors I know, so the
time bases should be synchronized unless the firmware plays with them
(assuming the HRESET pins are wired together).
However, all I needed to know is whether the firmware will start the
machine with the timebases synchronized or not. As long as they are, the
patch I suggested should work and give consistent, microsecond resolution
gettimeofday on SMP. Actually only the low 32 bits of the timebase are
used in the current code (even on 64 bit processors BTW) but I'd expect
all 64 bits to be in sync anyway.
The only problem is to know what happens on SMP when a processor enters a
deep low power mode which stops the timebase. Synchronizing again the
timebase is not easy, probably system dependant and I don't have any
system to test it. For now I'll treat it as a `don't do it, then' since
ultimate power saving measures are not necessary in existing SMP systems.
Can anybody with a Macintosh SMP G4 confirm that the time bases are
synchronized at boot ?
Gabriel
(still waiting for test results on the patch, including 601 machines).
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
From: Gabriel Paubert <hidden> Date: 2000-08-07 12:33:00
On Fri, 4 Aug 2000, Benjamin Herrenschmidt wrote:
On recent Core99 machines, Apple has a HW timer in the KeyLargo ASIC that
can be used to sync timebases. (It looks like a 64 bits bus-cycle timer,
but I'm not completely sure yet). There's also, I beleive, the OpenPIC timer.
OpenPIC timers are not that easy to use since they are not guaranteed to
ultimately run off the same oscillator as the processor time base, so you
can't guarantee a stable mathematical relationship between the timebase
and an OpenPIC timer count register.
Of course it will work in many machines (you would have to sacrifice one
of the 4 timers to do this but that's not a big deal). You would also have
to keep the most significant timebase bits and some other data in some
other places (the OpenPIC timer has only 31 bits and runs at 1/8 the bus
clock on integrated Motorola OpenPICs but 1/8 the PCI clock if you have an
IBM MPIC2 chip). I'm looking for a solution for SMP which does not depend
on the exact underlying hardware (it may require IPI but these are quite
well encapsulated), like a few interlocked memory accesses to transmit the
timebase and check that they are close enough.
Oh, BTW, in the OpenPIC timer specification the following is so laughable:
- integral number of clock ticks per second
Knowing that this number is required to be >= 4 million and the stability
of typical computer oscillators, I can guarantee that the fractional part
can be used as a fairly good random number generator (provided you don't
measure it too often).
Regards,
Gabriel.
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
From: Benjamin Herrenschmidt <hidden> Date: 2000-08-07 13:18:42
Can anybody with a Macintosh SMP G4 confirm that the time bases are
synchronized at boot ?
AFAIK, on those machines, I think Apple uses their "timer" device in the
new version of the mac-io ASIC to sync. timebases.
Reading Apple's CPU startup code in Darwin is _very_ interesting in fact.
That's for example how I learned that the only way to correctly and
completely flush the cache is to either reserve CPU-specific regions of
memory, use the ROM, or have external HW assist. Without that, any
snooping on the bus will garbage the flush process.
Ben.
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
From: Paul Mackerras <hidden> Date: 2000-08-08 01:39:25
Gabriel Paubert writes:
Hard reset also clears the timebase on all the processors I know, so the
time bases should be synchronized unless the firmware plays with them
(assuming the HRESET pins are wired together).
Certainly on my 7600 with a 2-cpu powersurge board, with the code that
is currently in the devel kernel to use the tb register, you don't get
the same time on both cpus.
I haven't had a chance to look at your patch in detail yet, hopefully
soon. At a quick glance it seemed to be touching a lot of stuff so it
will take more than a quick glance. :-)
Paul.
--
Paul Mackerras, Senior Open Source Researcher, Linuxcare, Inc.
+61 2 6262 8990 tel, +61 2 6262 8991 fax
paulus@linuxcare.com.au, http://www.linuxcare.com.au/
Linuxcare. Support for the revolution.
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
From: Gabriel Paubert <hidden> Date: 2000-08-11 11:04:12
On Tue, 8 Aug 2000, Paul Mackerras wrote:
Gabriel Paubert writes:
quoted
Hard reset also clears the timebase on all the processors I know, so the
time bases should be synchronized unless the firmware plays with them
(assuming the HRESET pins are wired together).
Certainly on my 7600 with a 2-cpu powersurge board, with the code that
is currently in the devel kernel to use the tb register, you don't get
the same time on both cpus.
Yes, we need a way to check that the timebase are in sync and to sync
them if they are not. That's basically the same problem in any case.
The problem is to do it in a way that works on all machines...
However current code is so broken that, if you had a jiffy counter per
processor, you would see them drifting away.
I haven't had a chance to look at your patch in detail yet, hopefully
soon. At a quick glance it seemed to be touching a lot of stuff so it
will take more than a quick glance. :-)
It does not toch so much when you look carefully at it, only timekeeping
but it's basically an all or nothing (and some global variable name
changes to be sure that I catch all the occurences which add somewhat to
the patch size).
However,
I have still found bugs in my code (but it seems to be slowly converging).
I'm also considering switching to BitKeeper tree, and sending these
patches in smaller and more digestible chunks:
- improved timing stability (fixed interrupt rate)
- 601 support and faster gettimeofday (no divide anymore)
- preliminary SMP support (gettimeofday still would have jiffy
resolution on SMP)
The problem is that these parts are somewhat hard to disentangle. I'm
also already running 2.4.0-test6 from kernel.org which was not yet merged
in the BK tree a few hours ago and that includes a few things that I need.
Regards,
Gabriel
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
From: Paul Mackerras <hidden> Date: 2000-08-12 06:29:12
Gabriel Paubert writes:
quoted
Certainly on my 7600 with a 2-cpu powersurge board, with the code that
is currently in the devel kernel to use the tb register, you don't get
the same time on both cpus.
Yes, we need a way to check that the timebase are in sync and to sync
them if they are not. That's basically the same problem in any case.
The problem is to do it in a way that works on all machines...
Until we get SMP working on the 2-cpu G4 machines (hopefully I will be
getting one soon), the old powersurge board is the only supported SMP
powermac. I found with mine that when you start the second CPU, it
stops the decrementers (and I expect timebases as well) on both CPUs
until you send an interrupt from the primary to the secondary cpu.
So on this platform at least, we can get the decrementers and
timebases synchronized.
It does not toch so much when you look carefully at it, only timekeeping
but it's basically an all or nothing (and some global variable name
changes to be sure that I catch all the occurences which add somewhat to
the patch size).
I merged in your patch and tried it on my 7600/powersurge machine. It
seems to work just fine.
I have still found bugs in my code (but it seems to be slowly converging).
I'm also considering switching to BitKeeper tree, and sending these
patches in smaller and more digestible chunks:
I'm going to try to update the linuxppc_2_3 bitkeeper tree to -test6,
since Cort is busy moving at the moment. In the meantime I will
update the rsync tree at linuxcare.com.au::linux-pmac-devel with your
patch shortly.
The get/set rtc stuff on powermac still needs work. IMHO the way it
should work on powermacs is this:
- at boot, read the RTC and the xpram and apply the correction from
the xpram
- /dev/rtc reads and writes the RTC value directly (no timezone
correction)
- if the RTC is updated from other places in the kernel, read the
timezone recorded in xpram and apply that correction before writing
it to the RTC.
Paul.
--
Paul Mackerras, Senior Open Source Researcher, Linuxcare, Inc.
+61 2 6262 8990 tel, +61 2 6262 8991 fax
paulus@linuxcare.com.au, http://www.linuxcare.com.au/
Linuxcare. Support for the revolution.
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
From: Gabriel Paubert <hidden> Date: 2000-08-12 18:46:11
On Sat, 12 Aug 2000, Paul Mackerras wrote:
Gabriel Paubert writes:
quoted
quoted
Certainly on my 7600 with a 2-cpu powersurge board, with the code that
is currently in the devel kernel to use the tb register, you don't get
the same time on both cpus.
Yes, we need a way to check that the timebase are in sync and to sync
them if they are not. That's basically the same problem in any case.
The problem is to do it in a way that works on all machines...
Until we get SMP working on the 2-cpu G4 machines (hopefully I will be
getting one soon), the old powersurge board is the only supported SMP
powermac. I found with mine that when you start the second CPU, it
stops the decrementers (and I expect timebases as well) on both CPUs
until you send an interrupt from the primary to the secondary cpu.
I've just tested on my machines since it was not clear to me that the TBEN
pin would stop the decrementer or not: it does. It is the only way I know
to stop the timebase (besides stopping the clock that is).
There may still be issues with the ordering of time_init and starting the
second processor. We'll see...
So on this platform at least, we can get the decrementers and
timebases synchronized.
The only important registers are the timebases. First my patch got rid of
the gross `while (get_dec() == dval);' loop, which did not work properly
in any case. Depending on cache misses and external influences between
this loop and the setting of the decrementer, I got effective jiffy
frequency varying by 20ppm or so (that's about 200ns per 10 ms).
This had very nasty consequences even on my stratum 1 NTP server (just
compiling a kernel would make the clock drift by several milliseconds
before the PLL would react) on SMP this would have meant that the timer
interrupts would have been drifting away randomly from each other.
The solution I implemented is simple: use the time base as a reference and
generate a decrementer interrupt every n ticks of the timebase, even if
the 601 makes things more complex (the code in the patch I sent is
still wrong for 601, an improved one is coming soon).
I merged in your patch and tried it on my 7600/powersurge machine. It
seems to work just fine.
So are the timebases in sync ? I was preparing a patch which should work
even with unsynced timebases, but then gettimeofday can only have jiffy
resolution. Beware that my next patch might break it, however, but it's
the fun of writing code that you can't test yourself :-)
quoted
I have still found bugs in my code (but it seems to be slowly converging).
I'm also considering switching to BitKeeper tree, and sending these
patches in smaller and more digestible chunks:
I'm going to try to update the linuxppc_2_3 bitkeeper tree to -test6,
since Cort is busy moving at the moment. In the meantime I will
update the rsync tree at linuxcare.com.au::linux-pmac-devel with your
patch shortly.
I tried once to download your tree, but bandwidth to autralia is too small
from here.
The get/set rtc stuff on powermac still needs work. IMHO the way it
should work on powermacs is this:
- at boot, read the RTC and the xpram and apply the correction from
the xpram
Yes for PMAC. Apply the correction later (or never) for other machines.
BTW, man setttimeofday is very interesting about dst:
The field tz_dsttime contains a symbolic constant (values
are given below) that indicates in which part of the year
Daylight Saving Time is in force. (Note: its value is con-
stant throughout the year - it does not indicate that DST
is in force, it just selects an algorithm.) The daylight
saving time algorithms defined are as follows :
DST_NONE /* not on dst */
DST_USA /* USA style dst */
DST_AUST /* Australian style dst */
DST_WET /* Western European dst */
DST_MET /* Middle European dst */
DST_EET /* Eastern European dst */
DST_CAN /* Canada */
DST_GB /* Great Britain and Eire */
DST_RUM /* Rumania */
DST_TUR /* Turkey */
DST_AUSTALT /* Australian style with shift in 1986 */
Of course it turned out that the period in which Daylight
Saving Time is in force cannot be given by a simple algo-
rithm, one per country; indeed, this period is determined
by unpredictable political decisions. So this method of
representing time zones has been abandoned. Under Linux,
in a call to settimeofday the tz_dsttime field should be
zero.
So you might have to find another way to pass the dst field.
- /dev/rtc reads and writes the RTC value directly (no timezone
correction)
Right, note that there is a problem in get_rtc_time for some machines, if
we want this function to be used for the /dev/rtc driver, it should not
wait for the second boundary to return, or you can force one second busy
wait loop in the kernel by reading /dev/rtc which opens the doors to
interesting attacks ;-)
The right place to put this waiting loop is in time_init, supposing that
pmac_read_rtc through cuda or pmu does not wait for a second boundary.
I'm currently working on this, but I don't plan to update the code
for all machines: only PreP, CHRP and PMAC. This should provide enough
examples to apply to the other machines (which won't compile anyway due to
deliberate global variable name changes). The maintainers of other
machines can contact me if they need any help...
quoted
- if the RTC is updated from other places in the kernel, read the
timezone recorded in xpram and apply that correction before writing
it to the RTC.
Ok, fine for pmac. For other platforms I shall need a way to round to the
closest half hour before writing the clock when the NTP PLL is closed
(which is basically the only kernel part which updates the clock).
This will not yet be in the next patch set.
Regards,
Gabriel
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
From: Gabriel Paubert <hidden> Date: 2000-08-14 12:59:56
On Sat, 12 Aug 2000, Paul Mackerras wrote:
I merged in your patch and tried it on my 7600/powersurge machine. It
seems to work just fine.
Here is the first followup patch, which needs testing, to be applied on
top of the preceding one. This patch corrects 601 handling, cleans up many
other small things, should ensure that no decrementer interrupt is ever
lost on SMP and UP (unless blocked for >1s on 601 or 2^32 TB ticks on
others), and moves the initial time read loop in some get_rtc_time
functions to time_init. Precision on boot still has to be checked.
Booted on an MVME2600...
I'm not going to have time to switch to BK before end of September. Time
handling still needs more cleanups, I hope to do some in the next 2 weeks
but I'm very busy on other fronts.
Gabriel.
arch/ppc/kernel/chrp_time.c | 26 +++++----
arch/ppc/kernel/pmac_time.c | 4 -
arch/ppc/kernel/prep_setup.c | 48 +++++++++-------
arch/ppc/kernel/prep_time.c | 44 +++++----------
arch/ppc/kernel/time.c | 122 ++++++++++++++++++++++++++++++-------------
include/asm-ppc/hardirq.h | 7 ++
6 files changed, 155 insertions, 96 deletions
diff -Nru a/arch/ppc/kernel/chrp_time.c b/arch/ppc/kernel/chrp_time.c
--- a/arch/ppc/kernel/chrp_time.c Mon Aug 14 14:48:34 2000+++ b/arch/ppc/kernel/chrp_time.c Mon Aug 14 14:48:34 2000
@@ -115,28 +115,34 @@unsignedlong__chrpchrp_get_rtc_time(void){unsignedintyear,mon,day,hour,min,sec;-inti;+intuip,i;/* The Linux interpretation of the CMOS clock register contents:*WhentheUpdate-In-Progress(UIP)flaggoesfrom1to0,the*RTCregistersshowthesecondwhichhaspreciselyjuststarted.*Let'shopeotheroperatingsystemsinterprettheRTCthesameway.*/-/* read RTC exactly on falling edge of update flag */-for(i=0;i<1000000;i++)/* may take up to 1 second... */-if(chrp_cmos_clock_read(RTC_FREQ_SELECT)&RTC_UIP)-break;-for(i=0;i<1000000;i++)/* must try at least 2.228 ms */-if(!(chrp_cmos_clock_read(RTC_FREQ_SELECT)&RTC_UIP))-break;-do{/* Isn't this overkill ? UIP above should guarantee consistency */++/* Since the UIP flag is set for about 2.2 ms and the clock+*istypicallywrittenwithaprecisionof1jiffy,trying+*toobtainaprecisionbetterthanafewmillisecondsis+*anillusion.Onlyconsistencyisinteresting,thisalso+*allowstousetheroutinefor/dev/rtcwithoutapotential+*1secondkernelbusylooptriggeredbyanyreaderof/dev/rtc.+*/++for(i=0;i<1000000;i++){+uip=chrp_cmos_clock_read(RTC_FREQ_SELECT);sec=chrp_cmos_clock_read(RTC_SECONDS);min=chrp_cmos_clock_read(RTC_MINUTES);hour=chrp_cmos_clock_read(RTC_HOURS);day=chrp_cmos_clock_read(RTC_DAY_OF_MONTH);mon=chrp_cmos_clock_read(RTC_MONTH);year=chrp_cmos_clock_read(RTC_YEAR);-}while(sec!=chrp_cmos_clock_read(RTC_SECONDS));+uip|=chrp_cmos_clock_read(RTC_FREQ_SELECT);+if((uip&RTC_UIP)==0)break;+}+if(!(chrp_cmos_clock_read(RTC_CONTROL)&RTC_DM_BINARY)||RTC_ALWAYS_BCD){BCD_TO_BIN(sec);
--- a/arch/ppc/kernel/pmac_time.c Mon Aug 14 14:48:34 2000+++ b/arch/ppc/kernel/pmac_time.c Mon Aug 14 14:48:34 2000
@@ -219,8 +219,8 @@write_lock_irqsave(&xtime_lock,flags);xtime.tv_sec=pmac_get_rtc_time()+time_diff;set_dec(tb_ticks_per_jiffy);-/* No PBOOK has a 601 AFAIK, so use get_tbl not binary_tbl */-tb_last_stamp=get_tbl();+/* No PBOOK has a 601 AFAIK, so use get_tbl, not native */+last_jiffy_stamp(0)=tb_last_stamp=get_tbl();xtime.tv_usec=0;last_rtc_update=xtime.tv_sec;write_unlock_irqrestore(&xtime_lock,flags);
--- a/arch/ppc/kernel/prep_setup.c Mon Aug 14 14:48:34 2000+++ b/arch/ppc/kernel/prep_setup.c Mon Aug 14 14:48:34 2000
@@ -442,37 +442,41 @@free_irq(0,NULL);}+staticvoid__initmk48t59_init(void){+unsignedchartmp;-/* We use the NVRAM RTC to time a second to calibrate the decrementer. */+tmp=ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);+if(tmp&MK48T59_RTC_CB_STOP){+printk("Warning: RTC was stopped, date will be wrong.\n");+ppc_md.nvram_write_val(MK48T59_RTC_CONTROLB,+tmp&~MK48T59_RTC_CB_STOP);+/* Low frequency crystal oscillators may take a very long+*timetostartupandstabilize.Fornowjustignorethe+*theissue,butattemptingtocalibratethedecrementer+*fromtheRTCjustafterthiswakeupislikelytobevery+*inaccurate.Firmwareshouldnotallowtoload+*theOSwiththeclockstoppedanyway...+*/+}+/* Ensure that the clock registers are updated */+tmp=ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);+tmp&=~(MK48T59_RTC_CA_READ|MK48T59_RTC_CA_WRITE);+ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,tmp);+}++/* We use the NVRAM RTC to time a second to calibrate the decrementer,+*theRTCregistershavejustbeensetupintherightstatebythe+*precedingroutine.+*/void__initmk48t59_calibrate_decr(void){unsignedlongfreq;unsignedlongt1;-unsignedcharsave_control;longi;unsignedcharsec;--/* Make sure the time is not stopped. */-save_control=ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);--ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,-(save_control&(~MK48T59_RTC_CB_STOP)));--/* Now make sure the read bit is off so the value will change. */-save_control=ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);-save_control&=~MK48T59_RTC_CA_READ;-ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,save_control);--/* Read the seconds value to see when it changes. */sec=ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);-/* Actually this is bad for precicion, we should have a loop in-*whichweonlyreadthesecondscounter.nvram_read_valwrites-*theaddressbytesoneverycallandthistakesalotoftime.-*Perhapsannvram_wait_changemethodreturningatime-*stampwithaloopcountasparameterwouldbethesolution.-*/for(i=0;i<1000000;i++){/* may take up to 1 second... */t1=get_tbl();if(ppc_md.nvram_read_val(MK48T59_RTC_SECONDS)!=sec){
--- a/arch/ppc/kernel/prep_time.c Mon Aug 14 14:48:34 2000+++ b/arch/ppc/kernel/prep_time.c Mon Aug 14 14:48:34 2000
@@ -99,28 +99,34 @@unsignedlongmc146818_get_rtc_time(void){unsignedintyear,mon,day,hour,min,sec;-inti;+intuip,i;/* The Linux interpretation of the CMOS clock register contents:*WhentheUpdate-In-Progress(UIP)flaggoesfrom1to0,the*RTCregistersshowthesecondwhichhaspreciselyjuststarted.*Let'shopeotheroperatingsystemsinterprettheRTCthesameway.*/-/* read RTC exactly on falling edge of update flag */-for(i=0;i<1000000;i++)/* may take up to 1 second... */-if(CMOS_READ(RTC_FREQ_SELECT)&RTC_UIP)-break;-for(i=0;i<1000000;i++)/* must try at least 2.228 ms */-if(!(CMOS_READ(RTC_FREQ_SELECT)&RTC_UIP))-break;-do{/* Isn't this overkill ? UIP above should guarantee consistency */++/* Since the UIP flag is set for about 2.2 ms and the clock+*istypicallywrittenwithaprecisionof1jiffy,trying+*toobtainaprecisionbetterthanafewmillisecondsis+*anillusion.Onlyconsistencyisinteresting,thisalso+*allowstousetheroutinefor/dev/rtcwithoutapotential+*1secondkernelbusylooptriggeredbyanyreaderof/dev/rtc.+*/++for(i=0;i<1000000;i++){+uip=CMOS_READ(RTC_FREQ_SELECT);sec=CMOS_READ(RTC_SECONDS);min=CMOS_READ(RTC_MINUTES);hour=CMOS_READ(RTC_HOURS);day=CMOS_READ(RTC_DAY_OF_MONTH);mon=CMOS_READ(RTC_MONTH);year=CMOS_READ(RTC_YEAR);-}while(sec!=CMOS_READ(RTC_SECONDS));+uip|=CMOS_READ(RTC_FREQ_SELECT);+if((uip&RTC_UIP)==0)break;+}+if(!(CMOS_READ(RTC_CONTROL)&RTC_DM_BINARY)||RTC_ALWAYS_BCD){
@@ -179,26 +185,10 @@unsignedintyear,mon,day,hour,min,sec;inti;-/* Make sure the time is not stopped. */-save_control=ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);--ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,-(save_control&(~MK48T59_RTC_CB_STOP)));--/* Now make sure the read bit is off so the value will change. */+/* Simple: freeze the clock, read it and allow updates again */save_control=ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);save_control&=~MK48T59_RTC_CA_READ;ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,save_control);--/* Read the seconds value to see when it changes. */-sec=ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);--/* Wait until the seconds value changes, then read the value. */-for(i=0;i<1000000;i++){/* may take up to 1 second... */-if(ppc_md.nvram_read_val(MK48T59_RTC_SECONDS)!=sec){-break;-}-}/* Set the register to read the value. */ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
@@ -114,17 +127,12 @@}#endif /* CONFIG_SMP */-/* This might fail on 601 SMP systems, are there any out there ?-*TherightwaytodoitmightbetoaddaperCPUtimebasestamp-*intheperCPUinterruptstructure.Wouldthisbeacceptable?-*/-while((delta=tb_ticks_per_jiffy-tb_ticks_since(local_stamp))<=0){--local_stamp+=tb_ticks_per_jiffy;+do{+jiffy_stamp+=tb_ticks_per_jiffy;if(smp_processor_id())continue;/* We are in an interrupt, no need to save/restore flags */write_lock(&xtime_lock);-tb_last_stamp=local_stamp;+tb_last_stamp=jiffy_stamp;do_timer(regs);/**updatethertcwhenneeded,thisshouldbeperformedonthe
@@ -177,7 +186,14 @@read_lock_irqsave(&xtime_lock,flags);sec=xtime.tv_sec;usec=xtime.tv_usec;+#ifdef CONFIG_SMP+/* As long as timebases are not in sync, gettimeofday can only+*havejiffyresolutiononSMP.+*/+delta=0;+#elsedelta=tb_ticks_since(tb_last_stamp);+#endiflost_ticks=jiffies-wall_jiffies;read_unlock_irqrestore(&xtime_lock,flags);
@@ -193,15 +209,18 @@voiddo_settimeofday(structtimeval*tv){unsignedlongflags;-inttv_delta;+inttb_delta,new_usec,new_sec;write_lock_irqsave(&xtime_lock,flags);-/* the rtc has to be updated soon but *not* *now* to avoid-*introducingrandomfractionalsecondoffsets.Donotattemptthe-*updatebeforethenextsecondboundary.Actually,itwillnot-*beupdateduntilSTA_UNSYNCiscleared.Notealsothat+/* Updating the RTC is not the job of this code. If the time is+*steppedunderNTP,theRTCwillbeupdateafterSTA_UNSYNC+*iscleared.Toollikeclock/hwclockeithercopytheRTC+*tothesystemtime,inwhichcasethereisnopointinwriting+*totheRTCagain,orwritetotheRTCbutthentheydon'tcall+*settimeofdaytoperformthisoperation.Notealsothat*wedon'ttouchthedecrementersince:*a)itwouldlosetimerinterruptsynchronizationonSMP+*(ifitisworkingoneday)*b)itcouldmakeonejiffyspuriouslyshorterorlonger*whichwouldintroduceanothersourceofuncertaintypotentially*harmfultorelativelyshorttimers.
@@ -210,12 +229,26 @@*isnotalwaysamultipleof1/Hzseconds.*/-tv_delta=mulhwu(tb_to_us,tb_ticks_since(tb_last_stamp));-xtime.tv_sec=tv->tv_sec-((tv_delta>tv->tv_usec)?1:0);-xtime.tv_usec=tv->tv_usec+((tv_delta>tv->tv_usec)?-1000000:0)-tv_delta;-last_rtc_update=xtime.tv_sec-658;-+/* This works perfectly on SMP only if the tb are in sync but+*guaranteesanerror<1jiffyeveniftheyareoffbyeons,+*stillreasonablewhengettimeofdayresolutionis1jiffy.+*/+tb_delta=tb_ticks_since(last_jiffy_stamp(smp_processor_id()));+tb_delta+=(jiffies-wall_jiffies)*tb_ticks_per_jiffy;+new_sec=tv->tv_sec;+new_usec=tv->tv_usec-mulhwu(tb_to_us,tb_delta);+while(new_usec<0){+new_sec--;+new_usec+=1000000;+}+xtime.tv_usec=new_usec;+xtime.tv_sec=new_sec;++/* In case of a large backwards jump in time with NTP, we want the+*clocktobeupdatedassoonasthePLLisagaininlock.+*/+last_rtc_update=new_sec-658;+time_adjust=0;/* stop active adjtime() */time_status|=STA_UNSYNC;time_state=TIME_ERROR;/* p. 24, (a) */
@@ -227,6 +260,9 @@void__inittime_init(void){+time_tsec,old_sec;+unsignedold_stamp,stamp,elapsed;+/* This function is only called on the boot processor */unsignedlongflags;if(ppc_md.time_init!=NULL){
@@ -238,18 +274,38 @@tb_ticks_per_jiffy=DECREMENTER_COUNT_601;/* mulhwu_scale_factor(1000000000, 1000000) is 0x418937 */tb_to_us=0x418937;-}elseif(!smp_processor_id()){+}else{ppc_md.calibrate_decr();}+/* Now that the decrementer is calibrated, it can be used in case the+*clockisstuck,butthefactthatwehavetohandlethe601+*makesthingsmorecomplex.RepeatedlyreadtheRTCuntilthe+*nextsecondboundarytotrytoachievesomeprecision...+*/+stamp=get_native_tbl();+sec=ppc_md.get_rtc_time();+elapsed=0;+do{+old_stamp=stamp;+old_sec=sec;+stamp=get_native_tbl();+if(__USE_RTC()&&stamp<old_stamp)old_stamp-=1000000000;+elapsed+=stamp-old_stamp;+sec=ppc_md.get_rtc_time();+}while(sec==old_sec&&elapsed<2*HZ*tb_ticks_per_jiffy);+if(sec==old_sec){+printk("Warning: real time clock seems stuck!\n");+}write_lock_irqsave(&xtime_lock,flags);-xtime.tv_sec=ppc_md.get_rtc_time();-tb_last_stamp=get_native_tbl();-set_dec(tb_ticks_per_jiffy);+xtime.tv_sec=sec;+last_jiffy_stamp(0)=tb_last_stamp=stamp;xtime.tv_usec=0;/* No update now, we just read the time from the RTC ! */last_rtc_update=xtime.tv_sec;write_unlock_irqrestore(&xtime_lock,flags);+/* Not exact, but the timer interrupt takes care of this */+set_dec(tb_ticks_per_jiffy);}/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
--- a/include/asm-ppc/hardirq.h Mon Aug 14 14:48:34 2000+++ b/include/asm-ppc/hardirq.h Mon Aug 14 14:48:34 2000
@@ -5,16 +5,23 @@#include<asm/smp.h>/* entry.S is sensitive to the offsets of these fields */+/* The __last_jiffy_stamp field is needed to ensure that no decrementer+*interruptislostonSMPmachines.SinceonmostCPUsitisinthesame+*cachelineaslocal_irq_count,itischeaptoaccessandisalsousedonUP+*foruniformity.+*/typedefstruct{unsignedint__softirq_active;unsignedint__softirq_mask;unsignedint__local_irq_count;unsignedint__local_bh_count;unsignedint__syscall_count;+unsignedint__last_jiffy_stamp;}____cacheline_alignedirq_cpustat_t;#include<linux/irq_cpustat.h>/* Standard mappings for irq_cpustat_t above */+#define last_jiffy_stamp(cpu) __IRQ_STAT((cpu), __last_jiffy_stamp)/**Areweinaninterruptcontext?Eitherdoingbottomhalf*orhardwareinterruptprocessing?
Certainly on my 7600 with a 2-cpu powersurge board, with the code that
is currently in the devel kernel to use the tb register, you don't get
the same time on both cpus.
Yes, we need a way to check that the timebase are in sync and to sync
them if they are not. That's basically the same problem in any case.
The problem is to do it in a way that works on all machines...
Until we get SMP working on the 2-cpu G4 machines (hopefully I will be
getting one soon), the old powersurge board is the only supported SMP
powermac. I found with mine that when you start the second CPU, it
stops the decrementers (and I expect timebases as well) on both CPUs
until you send an interrupt from the primary to the secondary cpu.
Benh and I are pushing Mac G4 SMP patches into the recently
created linuxppc_2_5 tree. It currently seems to work reasonably well,
except there is some work needing to be done on syncing the timebases on
CPU's. I seem to have about a 14 second difference between the 2 CPU's on
the machine I'm testing on now.
(from ping -f)
43505 packets transmitted, 43504 packets received, 0% packet loss
round-trip min/avg/max = -144657.0/0.1/144657.3 ms
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/