Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d54853ef authored by Martin Schwidefsky's avatar Martin Schwidefsky
Browse files

[S390] ETR support.



This patch adds support for clock synchronization to an external time
reference (ETR). The external time reference sends an oscillator
signal and a synchronization signal every 2^20 microseconds to keep
the TOD clocks of all connected servers in sync. For availability
two ETR units can be connected to a machine. If the clock deviates
for more than the sync-check tolerance all cpus get a machine check
that indicates that the clock is out of sync. For the lovely details
how to get the clock back in sync see the code below.

Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent c1821c2e
Loading
Loading
Loading
Loading
+3 −5
Original line number Diff line number Diff line
@@ -125,15 +125,13 @@ void do_extint(struct pt_regs *regs, unsigned short code)
		 * Make sure that the i/o interrupt did not "overtake"
		 * the last HZ timer interrupt.
		 */
		account_ticks();
		account_ticks(S390_lowcore.int_clock);
	kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
        index = ext_hash(code);
	for (p = ext_int_hash[index]; p; p = p->next) {
		if (likely(p->code == code)) {
			if (likely(p->handler))
		if (likely(p->code == code))
			p->handler(code);
	}
	}
	irq_exit();
	set_irq_regs(old_regs);
}
+2 −1
Original line number Diff line number Diff line
@@ -457,9 +457,10 @@ int __devinit start_secondary(void *cpuvoid)
        /* Setup the cpu */
        cpu_init();
	preempt_disable();
        /* init per CPU timer */
	/* Enable TOD clock interrupts on the secondary cpu. */
        init_cpu_timer();
#ifdef CONFIG_VIRT_TIMER
	/* Enable cpu timer interrupts on the secondary cpu. */
        init_cpu_vtimer();
#endif
	/* Enable pfault pseudo page faults on this cpu. */
+1117 −62

File changed.

Preview size limit exceeded, changes collapsed.

+4 −4
Original line number Diff line number Diff line
@@ -524,16 +524,15 @@ EXPORT_SYMBOL(del_virt_timer);
void init_cpu_vtimer(void)
{
	struct vtimer_queue *vt_list;
	unsigned long cr0;

	/* kick the virtual timer */
	S390_lowcore.exit_timer = VTIMER_MAX_SLICE;
	S390_lowcore.last_update_timer = VTIMER_MAX_SLICE;
	asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
	asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock));
	__ctl_store(cr0, 0, 0);
	cr0 |= 0x400;
	__ctl_load(cr0, 0, 0);

	/* enable cpu timer interrupts */
	__ctl_set_bit(0,10);

	vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
	INIT_LIST_HEAD(&vt_list->list);
@@ -572,6 +571,7 @@ void __init vtime_init(void)
	if (register_idle_notifier(&vtimer_idle_nb))
		panic("Couldn't register idle notifier");

	/* Enable cpu timer interrupts on the boot cpu. */
	init_cpu_vtimer();
}
+34 −14
Original line number Diff line number Diff line
/*
 *  arch/s390/kernel/delay.c
 *  arch/s390/lib/delay.c
 *    Precise Delay Loops for S390
 *
 *  S390 version
@@ -13,10 +13,8 @@

#include <linux/sched.h>
#include <linux/delay.h>

#ifdef CONFIG_SMP
#include <asm/smp.h>
#endif
#include <linux/timex.h>
#include <linux/irqflags.h>

void __delay(unsigned long loops)
{
@@ -31,17 +29,39 @@ void __delay(unsigned long loops)
}

/*
 * Waits for 'usecs' microseconds using the tod clock, giving up the time slice
 * of the virtual PU inbetween to avoid congestion.
 * Waits for 'usecs' microseconds using the TOD clock comparator.
 */
void __udelay(unsigned long usecs)
{
	uint64_t start_cc;
	u64 end, time, jiffy_timer = 0;
	unsigned long flags, cr0, mask, dummy;

	local_irq_save(flags);
	if (raw_irqs_disabled_flags(flags)) {
		jiffy_timer = S390_lowcore.jiffy_timer;
		S390_lowcore.jiffy_timer = -1ULL - (4096 << 12);
		__ctl_store(cr0, 0, 0);
		dummy = (cr0 & 0xffff00e0) | 0x00000800;
		__ctl_load(dummy , 0, 0);
		mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT;
	} else
		mask = psw_kernel_bits | PSW_MASK_WAIT |
			PSW_MASK_EXT | PSW_MASK_IO;

        if (usecs == 0)
                return;
	start_cc = get_clock();
	end = get_clock() + ((u64) usecs << 12);
	do {
		cpu_relax();
	} while (((get_clock() - start_cc)/4096) < usecs);
		time = end < S390_lowcore.jiffy_timer ?
			end : S390_lowcore.jiffy_timer;
		set_clock_comparator(time);
		trace_hardirqs_on();
		__load_psw_mask(mask);
		local_irq_disable();
	} while (get_clock() < end);

	if (raw_irqs_disabled_flags(flags)) {
		__ctl_load(cr0, 0, 0);
		S390_lowcore.jiffy_timer = jiffy_timer;
	}
	set_clock_comparator(S390_lowcore.jiffy_timer);
	local_irq_restore(flags);
}
Loading