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