1 /* CLOCK.C      (c) Copyright Jan Jaeger, 2000-2009                  */
2 /*              TOD Clock functions                                  */
3 
4 /*-------------------------------------------------------------------*/
5 /* The emulated hardware clock is based on the host clock, adjusted  */
6 /* by means of an offset and a steering rate.                        */
7 /*-------------------------------------------------------------------*/
8 
9 #include "hstdinc.h"
10 
11 #if !defined(_HENGINE_DLL_)
12 #define _HENGINE_DLL_
13 #endif
14 
15 #include "hercules.h"
16 
17 #include "opcode.h"
18 
19 #include "inline.h"
20 
21 #include "sr.h"
22 
23 #if !defined(_CLOCK_C_)
24 #define _CLOCK_C_
25 
26 #include "clock.h"
27 
28 // static int clock_state = CC_CLOCK_SET;
29 
30 static CSR old;
31 static CSR new;
32 static CSR *current = &new;
33 
csr_reset()34 void csr_reset()
35 {
36     new.start_time = 0;
37     new.base_offset = 0;
38     new.fine_s_rate = 0;
39     new.gross_s_rate = 0;
40     current = &new;
41     old = new;
42 }
43 
44 static U64 universal_tod;
universal_clock(void)45 static U64 universal_clock(void) /* really: any clock used as a base */
46 {
47     struct timeval tv;
48 
49     gettimeofday (&tv, NULL);
50 
51     /* Load number of seconds since 00:00:00 01 Jan 1970 */
52     universal_tod = (U64)tv.tv_sec;
53 
54     universal_tod += SECONDS_IN_SEVENTY_YEARS;
55 
56     /* Convert to microseconds */
57     universal_tod = (universal_tod * 1000000) + tv.tv_usec;
58 
59     /* Shift left 4 bits so that bits 0-7=TOD Clock Epoch,
60        bits 8-59=TOD Clock bits 0-51, bits 60-63=zero */
61     universal_tod <<= 4;
62 
63     return universal_tod;
64 }
65 
66 
67 /* The hercules hardware clock, based on the universal clock, but    */
68 /* running at its own speed as optionally set by set_tod_steering()  */
69 /* The hardware clock returns a unique value                         */
70 static double hw_steering = 0.0;  /* Current TOD clock steering rate */
71 static U64 hw_episode;           /* TOD of start of steering episode */
72 static S64 hw_offset = 0;       /* Current offset between TOD and HW */
73 // static U64 hw_tod = 0;             /* Globally defined in clock.h */
74 
hw_adjust(U64 base_tod)75 static inline U64 hw_adjust(U64 base_tod)
76 {
77     /* Apply hardware offset, this is the offset achieved by all
78        previous steering episodes */
79     base_tod += hw_offset;
80 
81     /* Apply the steering offset from the current steering episode */
82     base_tod += (S64)(base_tod - hw_episode) * hw_steering;
83 
84     /* Ensure that the clock returns a unique value */
85     if(hw_tod < base_tod)
86         return base_tod;
87     else
88     return hw_tod += 0x10;
89 }
90 
91 
hw_clock(void)92 U64 hw_clock(void)
93 {
94 U64 temp_tod;
95 
96     obtain_lock(&sysblk.todlock);
97 
98     /* Get the time of day (GMT) */
99     temp_tod = universal_clock();
100 
101     /* Ajust speed and ensure uniqueness */
102     hw_tod = hw_adjust(temp_tod);
103 
104     release_lock(&sysblk.todlock);
105 
106     return hw_tod;
107 }
108 
109 
hw_clock_l(void)110 static U64 hw_clock_l(void)
111 {
112     hw_tod = hw_adjust(universal_clock());
113 
114     return hw_tod;
115 }
116 
117 
118 /* set_tod_steering(double) sets a new steering rate.                */
119 /* When a new steering episode begins, the offset is adjusted,       */
120 /* and the new steering rate takes effect                            */
set_tod_steering(double steering)121 void set_tod_steering(double steering)
122 {
123     obtain_lock(&sysblk.todlock);
124     hw_offset = hw_clock_l() - universal_tod;
125     hw_episode = hw_tod;
126     hw_steering = steering;
127     release_lock(&sysblk.todlock);
128 }
129 
130 
131 /* Start a new episode */
start_new_episode()132 static inline void start_new_episode()
133 {
134     hw_offset = hw_tod - universal_tod;
135     hw_episode = hw_tod;
136     new.start_time = hw_episode;
137     hw_steering = ldexp(2,-44) * (S32)(new.fine_s_rate + new.gross_s_rate);
138     current = &new;
139 }
140 
141 
142 /* Prepare for a new episode */
prepare_new_episode()143 static inline void prepare_new_episode()
144 {
145     if(current == &new)
146     {
147         old = new;
148         current = &old;
149     }
150 }
151 
152 
153 /* Ajust the epoch for all active cpu's in the configuration */
adjust_epoch_cpu_all(U64 epoch)154 static U64 adjust_epoch_cpu_all(U64 epoch)
155 {
156 int cpu;
157 
158     /* Update the TOD clock of all CPU's in the configuration
159        as we simulate 1 shared TOD clock, and do not support the
160        TOD clock sync check */
161     for (cpu = 0; cpu < MAX_CPU; cpu++)
162     {
163         obtain_lock(&sysblk.cpulock[cpu]);
164         if (IS_CPU_ONLINE(cpu))
165             sysblk.regs[cpu]->tod_epoch = epoch;
166         release_lock(&sysblk.cpulock[cpu]);
167     }
168 
169     return epoch;
170 }
171 
172 
get_tod_steering(void)173 double get_tod_steering(void)
174 {
175     return hw_steering;
176 }
177 
178 
set_tod_epoch(S64 epoch)179 void set_tod_epoch(S64 epoch)
180 {
181     obtain_lock(&sysblk.todlock);
182     csr_reset();
183     tod_epoch = epoch;
184     release_lock(&sysblk.todlock);
185     adjust_epoch_cpu_all(epoch);
186 }
187 
188 
adjust_tod_epoch(S64 epoch)189 void adjust_tod_epoch(S64 epoch)
190 {
191     obtain_lock(&sysblk.todlock);
192     csr_reset();
193     tod_epoch += epoch;
194     release_lock(&sysblk.todlock);
195     adjust_epoch_cpu_all(tod_epoch);
196 }
197 
198 
set_tod_clock(U64 tod)199 void set_tod_clock(U64 tod)
200 {
201     set_tod_epoch(tod - hw_clock());
202 }
203 
204 
get_tod_epoch()205 S64 get_tod_epoch()
206 {
207     return tod_epoch;
208 }
209 
210 
set_gross_steering_rate(S32 gsr)211 static void set_gross_steering_rate(S32 gsr)
212 {
213     obtain_lock(&sysblk.todlock);
214     prepare_new_episode();
215     new.gross_s_rate = gsr;
216     release_lock(&sysblk.todlock);
217 }
218 
219 
set_fine_steering_rate(S32 fsr)220 static void set_fine_steering_rate(S32 fsr)
221 {
222     obtain_lock(&sysblk.todlock);
223     prepare_new_episode();
224     new.fine_s_rate = fsr;
225     release_lock(&sysblk.todlock);
226 }
227 
228 
set_tod_offset(S64 offset)229 static void set_tod_offset(S64 offset)
230 {
231     obtain_lock(&sysblk.todlock);
232     prepare_new_episode();
233     new.base_offset = offset;
234     release_lock(&sysblk.todlock);
235 }
236 
237 
adjust_tod_offset(S64 offset)238 static void adjust_tod_offset(S64 offset)
239 {
240     obtain_lock(&sysblk.todlock);
241     prepare_new_episode();
242     new.base_offset = old.base_offset + offset;
243     release_lock(&sysblk.todlock);
244 }
245 
246 
247 /* The cpu timer is internally kept as an offset to the hw_clock()
248  * the cpu timer counts down as the clock approaches the timer epoch
249  */
set_cpu_timer(REGS * regs,S64 timer)250 void set_cpu_timer(REGS *regs, S64 timer)
251 {
252     regs->cpu_timer = (timer >> 8) + hw_clock();
253 }
254 
255 
cpu_timer(REGS * regs)256 S64 cpu_timer(REGS *regs)
257 {
258 S64 timer;
259     timer = (regs->cpu_timer - hw_clock()) << 8;
260     return timer;
261 }
262 
263 
tod_clock(REGS * regs)264 U64 tod_clock(REGS *regs)
265 {
266 U64 current_tod;
267 
268     obtain_lock(&sysblk.todlock);
269 
270     current_tod = hw_clock_l();
271 
272     /* If we are in the old episode, and the new episode has arrived
273        then we must take action to start the new episode */
274     if(current == &old)
275         start_new_episode();
276 
277     /* Set the clock to the new updated value with offset applied */
278     current_tod += current->base_offset;
279 
280     tod_value = current_tod;
281 
282     release_lock(&sysblk.todlock);
283 
284     return current_tod + regs->tod_epoch;
285 }
286 
287 
288 #if defined(_FEATURE_INTERVAL_TIMER)
289 
290 
291 #if defined(_FEATURE_ECPSVM)
ecps_vtimer(REGS * regs)292 static inline S32 ecps_vtimer(REGS *regs)
293 {
294     return (S32)TOD_TO_ITIMER((S64)(regs->ecps_vtimer - hw_clock()));
295 }
296 
297 
set_ecps_vtimer(REGS * regs,S32 vtimer)298 static inline void set_ecps_vtimer(REGS *regs, S32 vtimer)
299 {
300     regs->ecps_vtimer = (U64)(hw_clock() + ITIMER_TO_TOD(vtimer));
301     regs->ecps_oldtmr = vtimer;
302 }
303 #endif /*defined(_FEATURE_ECPSVM)*/
304 
305 
int_timer(REGS * regs)306 S32 int_timer(REGS *regs)
307 {
308     return (S32)TOD_TO_ITIMER((S64)(regs->int_timer - hw_clock()));
309 }
310 
311 
set_int_timer(REGS * regs,S32 itimer)312 void set_int_timer(REGS *regs, S32 itimer)
313 {
314     regs->int_timer = (U64)(hw_clock() + ITIMER_TO_TOD(itimer));
315     regs->old_timer = itimer;
316 }
317 
318 
chk_int_timer(REGS * regs)319 int chk_int_timer(REGS *regs)
320 {
321 S32 itimer;
322 int pending = 0;
323 
324     itimer = int_timer(regs);
325     if(itimer < 0 && regs->old_timer >= 0)
326     {
327         ON_IC_ITIMER(regs);
328         pending = 1;
329         regs->old_timer=itimer;
330     }
331 #if defined(_FEATURE_ECPSVM)
332     if(regs->ecps_vtmrpt)
333     {
334         itimer = ecps_vtimer(regs);
335         if(itimer < 0 && regs->ecps_oldtmr >= 0)
336         {
337             ON_IC_ECPSVTIMER(regs);
338             pending += 2;
339         }
340     }
341 #endif /*defined(_FEATURE_ECPSVM)*/
342 
343     return pending;
344 }
345 #endif /*defined(_FEATURE_INTERVAL_TIMER)*/
346 
347 
348 /*-------------------------------------------------------------------*/
349 /* Update TOD clock                                                  */
350 /*                                                                   */
351 /* This function updates the TOD clock.                              */
352 /*                                                                   */
353 /* This function is called by timer_update_thread and by cpu_thread  */
354 /* instructions that manipulate any of the timer related entities    */
355 /* (clock comparator, cpu timer and interval timer).                 */
356 /*                                                                   */
357 /* Internal function `check_timer_event' is called which will signal */
358 /* any timer related interrupts to the appropriate cpu_thread.       */
359 /*                                                                   */
360 /* Callers *must* own the todlock and *must not* own the intlock.    */
361 /*                                                                   */
362 /* update_tod_clock() returns the tod delta, by which the cpu timer  */
363 /* has been adjusted.                                                */
364 /*                                                                   */
365 /*-------------------------------------------------------------------*/
366 // static U64 tod_value;
update_tod_clock(void)367 U64 update_tod_clock(void)
368 {
369 U64 new_clock;
370 
371     obtain_lock(&sysblk.todlock);
372 
373     new_clock = hw_clock_l();
374 
375     /* If we are in the old episode, and the new episode has arrived
376        then we must take action to start the new episode */
377     if(current == &old)
378         start_new_episode();
379 
380     /* Set the clock to the new updated value with offset applied */
381     new_clock += current->base_offset;
382     tod_value = new_clock;
383 
384     release_lock(&sysblk.todlock);
385 
386     /* Update the timers and check if either a clock related event has
387        become pending */
388     update_cpu_timer();
389 
390     return new_clock;
391 }
392 
393 #define SR_SYS_CLOCK_CURRENT_CSR          ( SR_SYS_CLOCK | 0x001 )
394 #define SR_SYS_CLOCK_UNIVERSAL_TOD        ( SR_SYS_CLOCK | 0x002 )
395 #define SR_SYS_CLOCK_HW_STEERING          ( SR_SYS_CLOCK | 0x004 )
396 #define SR_SYS_CLOCK_HW_EPISODE           ( SR_SYS_CLOCK | 0x005 )
397 #define SR_SYS_CLOCK_HW_OFFSET            ( SR_SYS_CLOCK | 0x006 )
398 
399 #define SR_SYS_CLOCK_OLD_CSR              ( SR_SYS_CLOCK | 0x100 )
400 #define SR_SYS_CLOCK_OLD_CSR_START_TIME   ( SR_SYS_CLOCK | 0x101 )
401 #define SR_SYS_CLOCK_OLD_CSR_BASE_OFFSET  ( SR_SYS_CLOCK | 0x102 )
402 #define SR_SYS_CLOCK_OLD_CSR_FINE_S_RATE  ( SR_SYS_CLOCK | 0x103 )
403 #define SR_SYS_CLOCK_OLD_CSR_GROSS_S_RATE ( SR_SYS_CLOCK | 0x104 )
404 
405 #define SR_SYS_CLOCK_NEW_CSR              ( SR_SYS_CLOCK | 0x200 )
406 #define SR_SYS_CLOCK_NEW_CSR_START_TIME   ( SR_SYS_CLOCK | 0x201 )
407 #define SR_SYS_CLOCK_NEW_CSR_BASE_OFFSET  ( SR_SYS_CLOCK | 0x202 )
408 #define SR_SYS_CLOCK_NEW_CSR_FINE_S_RATE  ( SR_SYS_CLOCK | 0x203 )
409 #define SR_SYS_CLOCK_NEW_CSR_GROSS_S_RATE ( SR_SYS_CLOCK | 0x204 )
410 
clock_hsuspend(void * file)411 int clock_hsuspend(void *file)
412 {
413     int i;
414     char buf[SR_MAX_STRING_LENGTH];
415 
416     i = (current == &new);
417     SR_WRITE_VALUE(file, SR_SYS_CLOCK_CURRENT_CSR, i, sizeof(i));
418     SR_WRITE_VALUE(file, SR_SYS_CLOCK_UNIVERSAL_TOD, universal_tod, sizeof(universal_tod));
419     snprintf(buf, sizeof(buf), "%f", hw_steering);
420     SR_WRITE_STRING(file, SR_SYS_CLOCK_HW_STEERING, buf);
421     SR_WRITE_VALUE(file, SR_SYS_CLOCK_HW_EPISODE, hw_episode, sizeof(hw_episode));
422     SR_WRITE_VALUE(file, SR_SYS_CLOCK_HW_OFFSET, hw_offset, sizeof(hw_offset));
423 
424     SR_WRITE_VALUE(file, SR_SYS_CLOCK_OLD_CSR_START_TIME,   old.start_time,   sizeof(old.start_time));
425     SR_WRITE_VALUE(file, SR_SYS_CLOCK_OLD_CSR_BASE_OFFSET,  old.base_offset,  sizeof(old.base_offset));
426     SR_WRITE_VALUE(file, SR_SYS_CLOCK_OLD_CSR_FINE_S_RATE,  old.fine_s_rate,  sizeof(old.fine_s_rate));
427     SR_WRITE_VALUE(file, SR_SYS_CLOCK_OLD_CSR_GROSS_S_RATE, old.gross_s_rate, sizeof(old.gross_s_rate));
428 
429     SR_WRITE_VALUE(file, SR_SYS_CLOCK_NEW_CSR_START_TIME,   new.start_time,   sizeof(new.start_time));
430     SR_WRITE_VALUE(file, SR_SYS_CLOCK_NEW_CSR_BASE_OFFSET,  new.base_offset,  sizeof(new.base_offset));
431     SR_WRITE_VALUE(file, SR_SYS_CLOCK_NEW_CSR_FINE_S_RATE,  new.fine_s_rate,  sizeof(new.fine_s_rate));
432     SR_WRITE_VALUE(file, SR_SYS_CLOCK_NEW_CSR_GROSS_S_RATE, new.gross_s_rate, sizeof(new.gross_s_rate));
433 
434     return 0;
435 }
436 
clock_hresume(void * file)437 int clock_hresume(void *file)
438 {
439     size_t key, len;
440     int i;
441     float f;
442     char buf[SR_MAX_STRING_LENGTH];
443 
444     memset(&old, 0, sizeof(CSR));
445     memset(&new, 0, sizeof(CSR));
446     current = &new;
447     universal_tod = 0;
448     hw_steering = 0.0;
449     hw_episode = 0;
450     hw_offset = 0;
451 
452     do {
453         SR_READ_HDR(file, key, len);
454         switch (key) {
455         case SR_SYS_CLOCK_CURRENT_CSR:
456             SR_READ_VALUE(file, len, &i, sizeof(i));
457             current = i ? &new : &old;
458             break;
459         case SR_SYS_CLOCK_UNIVERSAL_TOD:
460             SR_READ_VALUE(file, len, &universal_tod, sizeof(universal_tod));
461             break;
462         case SR_SYS_CLOCK_HW_STEERING:
463             SR_READ_STRING(file, buf, len);
464             sscanf(buf, "%f",&f);
465             hw_steering = f;
466             break;
467         case SR_SYS_CLOCK_HW_EPISODE:
468             SR_READ_VALUE(file, len, &hw_episode, sizeof(hw_episode));
469             break;
470         case SR_SYS_CLOCK_HW_OFFSET:
471             SR_READ_VALUE(file, len, &hw_offset, sizeof(hw_offset));
472             break;
473         case SR_SYS_CLOCK_OLD_CSR_START_TIME:
474             SR_READ_VALUE(file, len, &old.start_time, sizeof(old.start_time));
475             break;
476         case SR_SYS_CLOCK_OLD_CSR_BASE_OFFSET:
477             SR_READ_VALUE(file, len, &old.base_offset, sizeof(old.base_offset));
478             break;
479         case SR_SYS_CLOCK_OLD_CSR_FINE_S_RATE:
480             SR_READ_VALUE(file, len, &old.fine_s_rate, sizeof(old.fine_s_rate));
481             break;
482         case SR_SYS_CLOCK_OLD_CSR_GROSS_S_RATE:
483             SR_READ_VALUE(file, len, &old.gross_s_rate, sizeof(old.gross_s_rate));
484             break;
485         case SR_SYS_CLOCK_NEW_CSR_START_TIME:
486             SR_READ_VALUE(file, len, &new.start_time, sizeof(new.start_time));
487             break;
488         case SR_SYS_CLOCK_NEW_CSR_BASE_OFFSET:
489             SR_READ_VALUE(file, len, &new.base_offset, sizeof(new.base_offset));
490             break;
491         case SR_SYS_CLOCK_NEW_CSR_FINE_S_RATE:
492             SR_READ_VALUE(file, len, &new.fine_s_rate, sizeof(new.fine_s_rate));
493             break;
494         case SR_SYS_CLOCK_NEW_CSR_GROSS_S_RATE:
495             SR_READ_VALUE(file, len, &new.gross_s_rate, sizeof(new.gross_s_rate));
496             break;
497         default:
498             SR_READ_SKIP(file, len);
499             break;
500         }
501     } while ((key & SR_SYS_MASK) == SR_SYS_CLOCK);
502     return 0;
503 }
504 
505 
506 #endif
507 
508 
509 #if defined(FEATURE_INTERVAL_TIMER)
ARCH_DEP(_store_int_timer_2)510 static void ARCH_DEP(_store_int_timer_2) (REGS *regs,int getlock)
511 {
512 S32 itimer;
513 S32 vtimer=0;
514 
515     if(getlock)
516     {
517         OBTAIN_INTLOCK(regs->hostregs?regs:NULL);
518     }
519     itimer=int_timer(regs);
520     STORE_FW(regs->psa->inttimer, itimer);
521 #if defined(FEATURE_ECPSVM)
522     if(regs->ecps_vtmrpt)
523     {
524         vtimer=ecps_vtimer(regs);
525         STORE_FW(regs->ecps_vtmrpt, vtimer);
526     }
527 #endif /*defined(FEATURE_ECPSVM)*/
528 
529     chk_int_timer(regs);
530 #if defined(FEATURE_ECPSVM)
531     if(regs->ecps_vtmrpt)
532     {
533         regs->ecps_oldtmr = vtimer;
534     }
535 #endif /*defined(FEATURE_ECPSVM)*/
536 
537     if(getlock)
538     {
539         RELEASE_INTLOCK(regs->hostregs?regs:NULL);
540     }
541 }
542 
543 
ARCH_DEP(store_int_timer)544 DLL_EXPORT void ARCH_DEP(store_int_timer) (REGS *regs)
545 {
546     ARCH_DEP(_store_int_timer_2) (regs,1);
547 }
548 
549 
ARCH_DEP(store_int_timer_nolock)550 void ARCH_DEP(store_int_timer_nolock) (REGS *regs)
551 {
552     ARCH_DEP(_store_int_timer_2) (regs,0);
553 }
554 
555 
ARCH_DEP(fetch_int_timer)556 DLL_EXPORT void ARCH_DEP(fetch_int_timer) (REGS *regs)
557 {
558 S32 itimer;
559     FETCH_FW(itimer, regs->psa->inttimer);
560     OBTAIN_INTLOCK(regs->hostregs?regs:NULL);
561     set_int_timer(regs, itimer);
562 #if defined(FEATURE_ECPSVM)
563     if(regs->ecps_vtmrpt)
564     {
565         FETCH_FW(itimer, regs->ecps_vtmrpt);
566         set_ecps_vtimer(regs, itimer);
567     }
568 #endif /*defined(FEATURE_ECPSVM)*/
569     RELEASE_INTLOCK(regs->hostregs?regs:NULL);
570 }
571 #endif
572 
573 
574 #if defined(FEATURE_TOD_CLOCK_STEERING)
575 
ARCH_DEP(set_gross_s_rate)576 void ARCH_DEP(set_gross_s_rate) (REGS *regs)
577 {
578 S32 gsr;
579     gsr = ARCH_DEP(vfetch4) (regs->GR(1) & ADDRESS_MAXWRAP(regs), 1, regs);
580 
581     set_gross_steering_rate(gsr);
582 }
583 
584 
ARCH_DEP(set_fine_s_rate)585 void ARCH_DEP(set_fine_s_rate) (REGS *regs)
586 {
587 S32 fsr;
588     fsr = ARCH_DEP(vfetch4) (regs->GR(1) & ADDRESS_MAXWRAP(regs), 1, regs);
589 
590     set_fine_steering_rate(fsr);
591 }
592 
593 
ARCH_DEP(set_tod_offset)594 void ARCH_DEP(set_tod_offset) (REGS *regs)
595 {
596 S64 offset;
597     offset = ARCH_DEP(vfetch8) (regs->GR(1) & ADDRESS_MAXWRAP(regs), 1, regs);
598 
599     set_tod_offset(offset >> 8);
600 }
601 
602 
ARCH_DEP(adjust_tod_offset)603 void ARCH_DEP(adjust_tod_offset) (REGS *regs)
604 {
605 S64 offset;
606     offset = ARCH_DEP(vfetch8) (regs->GR(1) & ADDRESS_MAXWRAP(regs), 1, regs);
607 
608     adjust_tod_offset(offset >> 8);
609 }
610 
611 
ARCH_DEP(query_physical_clock)612 void ARCH_DEP(query_physical_clock) (REGS *regs)
613 {
614     ARCH_DEP(vstore8) (universal_clock() << 8, regs->GR(1) & ADDRESS_MAXWRAP(regs), 1, regs);
615 }
616 
617 
ARCH_DEP(query_steering_information)618 void ARCH_DEP(query_steering_information) (REGS *regs)
619 {
620 PTFFQSI qsi;
621     obtain_lock(&sysblk.todlock);
622     STORE_DW(qsi.physclk, universal_clock() << 8);
623     STORE_DW(qsi.oldestart, old.start_time << 8);
624     STORE_DW(qsi.oldebase, old.base_offset << 8);
625     STORE_FW(qsi.oldfsr, old.fine_s_rate );
626     STORE_FW(qsi.oldgsr, old.gross_s_rate );
627     STORE_DW(qsi.newestart, new.start_time << 8);
628     STORE_DW(qsi.newebase, new.base_offset << 8);
629     STORE_FW(qsi.newfsr, new.fine_s_rate );
630     STORE_FW(qsi.newgsr, new.gross_s_rate );
631     release_lock(&sysblk.todlock);
632 
633     ARCH_DEP(vstorec) (&qsi, sizeof(qsi)-1, regs->GR(1) & ADDRESS_MAXWRAP(regs), 1, regs);
634 }
635 
636 
ARCH_DEP(query_tod_offset)637 void ARCH_DEP(query_tod_offset) (REGS *regs)
638 {
639 PTFFQTO qto;
640     obtain_lock(&sysblk.todlock);
641     STORE_DW(qto.todoff, (hw_clock_l() - universal_tod) << 8);
642     STORE_DW(qto.physclk, universal_tod << 8);
643     STORE_DW(qto.ltodoff, current->base_offset << 8);
644     STORE_DW(qto.todepoch, regs->tod_epoch << 8);
645     release_lock(&sysblk.todlock);
646 
647     ARCH_DEP(vstorec) (&qto, sizeof(qto)-1, regs->GR(1) & ADDRESS_MAXWRAP(regs), 1, regs);
648 }
649 
650 
ARCH_DEP(query_available_functions)651 void ARCH_DEP(query_available_functions) (REGS *regs)
652 {
653 PTFFQAF qaf;
654     STORE_FW(qaf.sb[0] , 0xF0000000);        /* Functions 0x00..0x1F */
655     STORE_FW(qaf.sb[1] , 0x00000000);        /* Functions 0x20..0x3F */
656     STORE_FW(qaf.sb[2] , 0xF0000000);        /* Functions 0x40..0x5F */
657     STORE_FW(qaf.sb[3] , 0x00000000);        /* Functions 0x60..0x7F */
658 
659     ARCH_DEP(vstorec) (&qaf, sizeof(qaf)-1, regs->GR(1) & ADDRESS_MAXWRAP(regs), 1, regs);
660 }
661 #endif /*defined(FEATURE_TOD_CLOCK_STEERING)*/
662 
663 #if !defined(_GEN_ARCH)
664 
665 #if defined(_ARCHMODE2)
666  #define  _GEN_ARCH _ARCHMODE2
667  #include "clock.c"
668 #endif
669 
670 #if defined(_ARCHMODE3)
671  #undef   _GEN_ARCH
672  #define  _GEN_ARCH _ARCHMODE3
673  #include "clock.c"
674 #endif
675 
676 
677 #endif /*!defined(_GEN_ARCH)*/
678