Commit | Line | Data |
---|---|---|
09169146 GW |
1 | # README,v 3.1 1993/07/06 01:09:46 jbj Exp |
2 | ||
3 | PPSCLOCK 1.3 BETA Release | |
4 | ||
5 | Please send bugs and comments to ppsclock@ee.lbl.gov. | |
6 | ||
7 | This is SunOS 4 tty STREAMS module that can be used to interface | |
8 | the one-pulse-per-second output of an accurate external clock | |
9 | (e.g., a GPS receiver) to NTP. This module records the value of | |
10 | the Unix clock each time the 1pps pulse happens. The recorded | |
11 | value can then be read by an application using a CIOGETEV ioctl. | |
12 | ||
13 | We have been running this module with xntp3, SunOS 4.1.2 and a | |
14 | Magnavox MX4200 GPS receiver (a very nice, relatively inexpensive | |
15 | GPS box for use with NTP) and have been happy with the results: | |
16 | The time from when the GPS sends the 1pps pulse to when this code | |
17 | grabs the Unix time is an almost constant 15us on a SparcStation 1+ | |
18 | and 9us on a SparcStation 2 (there is conditionally compiled code | |
19 | in the driver that may help if you want to measure this interval | |
20 | yourself -- see below). | |
21 | ||
22 | Since the GPS is typically connected via an RS-232 serial port | |
23 | & since the SparcStation has too few serial ports, this module | |
24 | gets the 1pps signal via the same port used to get the GPS data. | |
25 | We do this by connecting the GPS 1pps output to `Carrier Detect' | |
26 | (RS-232 pin 8) on serial cable between the GPS & the Sparc. | |
27 | Since `Carrier Detect' transitions cause a high priority zs | |
28 | `service' interrupt on the Sparc (which is separate from the zs | |
29 | `data' interrupt used to collect ascii data from the GPS), this | |
30 | is a cheap way to turn the 1pps pulse into a Sparc interrupt. | |
31 | However, since `Carrier Detect' now has a non-standard meaning on | |
32 | the clock serial line, *YOU MUST SET "SOFT CARRIER" ON THE CLOCK | |
33 | SERIAL PORT* (i.e., the port you push this streams module onto). | |
34 | But note that this module changes the meaning of the `Carrier | |
35 | Detect' interrupt *only* on the port(s) it's pushed on; other | |
36 | serial ports continue to work as they always have & the special | |
37 | interpretation of `Carrier Detect' will go away whenever this | |
38 | steams module is popped (e.g., if xntpd exits). | |
39 | ||
40 | In order to use the 1pps pulse to correct both the Unix clock | |
41 | offset and frequency, the time between when the external clock | |
42 | signals 1pps and when this module records the Unix clock should | |
43 | be as small as possible and should be repeatable. The totally | |
44 | braindead AT&T STREAMS code makes it very difficult to achieve | |
45 | these objectives: The allocb/wput overhead adds about 700us of | |
46 | latency on a SS-1+ and the worthless stream 'scheduler' combined | |
47 | with doing everything at a relatively low interrupt priority | |
48 | adds about +-400us of jitter. So, to get a high quality time | |
49 | stamp, this module uses STREAMS *only* to get the ioctl request. | |
50 | It gets the 1pps signal by avoiding STREAMS code entirely and | |
51 | inserting itself directly into the hardware interrupt service path | |
52 | for the 1pps pulse. It does this by being *very* chummy with | |
53 | Sun's `zs' serial driver -- it basically steals the modem control | |
54 | interrupt from the zs. So *THIS IS NOT A GENERIC STREAMS MODULE*. | |
55 | It is designed to work with Sun's zs driver under SunOS 4. | |
56 | Expect it to break under Solaris-2. Expect it to not run on | |
57 | anything but a Sun. | |
58 | ||
59 | Also note that for our GPS clock, `1 second' seems to occur at the | |
60 | leading edge of the pulse so that's when we grab the timestamp. If | |
61 | your clock indicates 1pps on the trailing edge you should change the line: | |
62 | if ((s0 & ZSRR0_CD) != 0) { | |
63 | in ppsclock_intr to: | |
64 | if ((s0 & ZSRR0_CD) == 0) { | |
65 | to grab the time stamp on the trailing edge of the pulse. | |
66 | ||
67 | One final note about running this code on a Sun Sparcstation 1; we have | |
68 | found that you need revision 1.3 or higher proms with the Sun 4/60; | |
69 | this is because 1.2 and earlier roms listen to BOTH the A and B serial | |
70 | ports while selftesting; if you have something like a GPS receiver | |
71 | talking once a second at 4800 baud to a serial port, even if it's not | |
72 | the console serial port, the system will see a "break" and abort | |
73 | booting up. This makes it impossible to automatically reboot after a | |
74 | crash. | |
75 | ||
76 | ||
77 | Measuring Performance | |
78 | --------------------- | |
79 | We have frequently found the need for some non-invasive means | |
80 | to measure internal system performance numbers such as interrupt | |
81 | latencies. The following trick works pretty well: The SparcStation | |
82 | has a front panel LED that the system turns on at boot time then | |
83 | never changes. There is a register (the 'auxio' register) that the | |
84 | kernel can write to change the state of this LED & it costs almost | |
85 | exactly 1us to turn the LED off then on again. So, for example, | |
86 | you can measure the interrupt latency to when we grab unix time | |
87 | stamp by attaching a scope probe to the LED (it's easiest to stick | |
88 | the probe into the LED's connector on the motherboard) then trigger | |
89 | the scope off the appropriate edge of the 1pps pulse from the GPS. | |
90 | If you want to measure the amount of time some system routine | |
91 | takes, you can turn the LED off before calling the routine and | |
92 | on afterwards so the pulse width on the scope is a direct measure | |
93 | of the routine's execution time. If you want to play with this, | |
94 | there's code in ppsclock.c (conditional on the define PPSCLOCKLED) | |
95 | that will toggle the LED in the hardware interrupt handler for | |
96 | the 1pps intr. The time from whichever edge of the 1pps pulse | |
97 | you chose to stamp to when the LED goes off is the interrupt | |
98 | latency & the LED off time is a measure of the cost to call Sun's | |
99 | routine uniqtime (which reads the Unix time to 1us accuracy). | |
100 | ||
101 | By the way, if you try this & think the cost of calling Sun's | |
102 | `uniqtime' is appalling (42-85us/call -- we thought this was | |
103 | appalling) this distribution includes a replacement for it, | |
104 | microtime.s, that runs 10 times faster than Sun's code (~3us/call) | |
105 | & gives you a more accurate time. (If you install this, it will | |
106 | improve anything that gets high-res unix kernel time, including | |
107 | the gettimeofday system call that xntp uses). | |
108 | ||
109 | ||
110 | ||
111 | INSTALLATION | |
112 | ------------ | |
113 | These are some (sketchy) notes on installation of the SunOS 4 pps clock | |
114 | streams module. | |
115 | ||
116 | This directory contains: | |
117 | ||
118 | README - this file | |
119 | RELEASE - version of this releasethis | |
120 | CHANGES - description of differences between releases | |
121 | magnavox.ps - PostScript schematic (Magnavox rs422/rs232 converter) | |
122 | b-and-b.ps - PostScript schematic (B&B rs422/rs232 converter) | |
123 | Makefile - compilation rules | |
124 | ppstest - ppsclock test program (works with Magnavox | |
125 | MX4200 GPS -- you can probably use this as | |
126 | sample code illustrating the use of this | |
127 | streams module if you have some other kind | |
128 | of clock). | |
129 | sys - SunOS 4 kernel modules | |
130 | sys/genassym - genassym program for object-only (non-source) sites | |
131 | ||
132 | KERNEL CONFIGURATION | |
133 | -------------------- | |
134 | ||
135 | (1) Copy sys/sundev/ppsclock.c to /sys/sundev. | |
136 | ||
137 | (2) Copy sys/sys/ppsclock.h to /sys/sys (and /usr/include/sys if it | |
138 | is separate directory). | |
139 | ||
140 | (3) If you want to use the fast microtime module, copy | |
141 | sys/sun4c/microtime.s to /sys/sun4c. | |
142 | ||
143 | (4) Use sys/sun/str_conf.c.patch to patch /sys/sun/str_conf.c. | |
144 | Alternately, manually install the following lines in the | |
145 | appropriate places: | |
146 | ||
147 | #include "zs.h" | |
148 | [...] | |
149 | #if NZS > 0 | |
150 | #include "sys/ppsclock.h" | |
151 | extern struct streamtab ppsclockinfo; | |
152 | #endif | |
153 | [...] | |
154 | #if NZS > 0 | |
155 | { PPSCLOCKSTR, &ppsclockinfo }, | |
156 | #endif | |
157 | ||
158 | (5) Use sun4c/conf/files.patch to patch /sys/sun4c/conf/files. | |
159 | Alternately, manually install the following line in the | |
160 | appropriate place: | |
161 | ||
162 | sundev/ppsclock.c optional zs device-driver | |
163 | ||
164 | In addition, if you want to use the fast microtime module, | |
165 | use sun4c/conf/files.microtime.patch to patch | |
166 | /sys/sun4c/conf/files. Alternately, manually install the | |
167 | following line in the appropriate place: | |
168 | ||
169 | sun4c/microtime.s standard | |
170 | ||
171 | If you are using SunOS 4.1.3 and wish to support the sun4m | |
172 | architecture, apply the corresponding patches from the sun4m | |
173 | tree. | |
174 | ||
175 | (6) If you want to use the fast microtime module, and have full | |
176 | SunOS 4 source, use /sys/os/kern_clock.c.patch to patch | |
177 | /sys/os/kern_clock.c. Alternately, edit /sys/os/kern_clock.c | |
178 | and bracket the code for uniqtime() with the following two | |
179 | lines: | |
180 | ||
181 | #if !defined(sun4c) && !defined(sun4m) | |
182 | #endif | |
183 | ||
184 | If you DO NOT have full SunOS 4 source but still want to use | |
185 | the fast microtime, change the symbol table entry in for | |
186 | _uniqtime to _Uniqtime as follows: | |
187 | ||
188 | hell 1 % cd /sys/sun4c/OBJ # or /sys/sun4m | |
189 | hell 2 % mv kern_clock.o kern_clock.o.virgin | |
190 | hell 2 % cp kern_clock.o.virgin kern_clock.o | |
191 | hell 3 % chmod +w kern_clock.o | |
192 | hell 5 % strings -o -a kern_clock.o | grep -w _uniqtime | |
193 | 7892 _uniqtime | |
194 | hell 6 % adb -w kern_clock.o | |
195 | ?m 0 0xffffffff 0 | |
196 | 0t7892?s | |
197 | _dk_ndrive+0x12cc: _uniqtime | |
198 | .?x | |
199 | _dk_ndrive+0x12cc: 5f75 | |
200 | .?w5f55 | |
201 | _dk_ndrive+0x12cc: 0x5f75 = 0x5f55 | |
202 | .?s | |
203 | _dk_ndrive+0x12cc: _Uniqtime | |
204 | ^D | |
205 | ||
206 | (7) If you DO NOT have full SunOS 4 source, you are missing the | |
207 | source to genassym. Copy the "mini" genassym source from | |
208 | genassym/genassym.c to /sys/sun4c (and into /sys/sun4m if you | |
209 | have SunOS 4.1.3 and wish to support the sun4m architecture). | |
210 | ||
211 | Next, use sun4c/conf/Makefile.src.patch to patch | |
212 | /sys/sun4c/conf/Makefile.src (and possibly | |
213 | /sys/sun4m/conf/Makefile.src). | |
214 | ||
215 | Alternately, manually install the following rules in the | |
216 | prototype Makefile(s). | |
217 | ||
218 | assym.s: ${MACHINE}/genassym.c | |
219 | ${CC} -E ${CPPOPTS} ${MACHINE}/genassym.c > ./a.out.c | |
220 | cc ${COPTS} ./a.out.c | |
221 | ./a.out >assym.s | |
222 | rm -f ./a.out ./a.out.c | |
223 | ||
224 | (8) Config, build, and boot the new kernel. | |
225 | ||
226 | (9) If you have an MX4200, build the test program in the ppstest | |
227 | directory and run it. It waits for a message at 4800 | |
228 | baud and then prints both the message and the time stamp | |
229 | of the last "carrier detect" transition. |