Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/openrisc/kernel/sync-timer.c
26442 views
1
/*
2
* OR1K timer synchronisation
3
*
4
* Based on work from MIPS implementation.
5
*
6
* All CPUs will have their count registers synchronised to the CPU0 next time
7
* value. This can cause a small timewarp for CPU0. All other CPU's should
8
* not have done anything significant (but they may have had interrupts
9
* enabled briefly - prom_smp_finish() should not be responsible for enabling
10
* interrupts...)
11
*/
12
13
#include <linux/kernel.h>
14
#include <linux/irqflags.h>
15
#include <linux/cpumask.h>
16
17
#include <asm/time.h>
18
#include <asm/timex.h>
19
#include <linux/atomic.h>
20
#include <asm/barrier.h>
21
22
#include <asm/spr.h>
23
24
static unsigned int initcount;
25
static atomic_t count_count_start = ATOMIC_INIT(0);
26
static atomic_t count_count_stop = ATOMIC_INIT(0);
27
28
#define COUNTON 100
29
#define NR_LOOPS 3
30
31
void synchronise_count_master(int cpu)
32
{
33
int i;
34
unsigned long flags;
35
36
pr_info("Synchronize counters for CPU %u: ", cpu);
37
38
local_irq_save(flags);
39
40
/*
41
* We loop a few times to get a primed instruction cache,
42
* then the last pass is more or less synchronised and
43
* the master and slaves each set their cycle counters to a known
44
* value all at once. This reduces the chance of having random offsets
45
* between the processors, and guarantees that the maximum
46
* delay between the cycle counters is never bigger than
47
* the latency of information-passing (cachelines) between
48
* two CPUs.
49
*/
50
51
for (i = 0; i < NR_LOOPS; i++) {
52
/* slaves loop on '!= 2' */
53
while (atomic_read(&count_count_start) != 1)
54
mb();
55
atomic_set(&count_count_stop, 0);
56
smp_wmb();
57
58
/* Let the slave writes its count register */
59
atomic_inc(&count_count_start);
60
61
/* Count will be initialised to current timer */
62
if (i == 1)
63
initcount = get_cycles();
64
65
/*
66
* Everyone initialises count in the last loop:
67
*/
68
if (i == NR_LOOPS-1)
69
openrisc_timer_set(initcount);
70
71
/*
72
* Wait for slave to leave the synchronization point:
73
*/
74
while (atomic_read(&count_count_stop) != 1)
75
mb();
76
atomic_set(&count_count_start, 0);
77
smp_wmb();
78
atomic_inc(&count_count_stop);
79
}
80
/* Arrange for an interrupt in a short while */
81
openrisc_timer_set_next(COUNTON);
82
83
local_irq_restore(flags);
84
85
/*
86
* i386 code reported the skew here, but the
87
* count registers were almost certainly out of sync
88
* so no point in alarming people
89
*/
90
pr_cont("done.\n");
91
}
92
93
void synchronise_count_slave(int cpu)
94
{
95
int i;
96
97
/*
98
* Not every cpu is online at the time this gets called,
99
* so we first wait for the master to say everyone is ready
100
*/
101
102
for (i = 0; i < NR_LOOPS; i++) {
103
atomic_inc(&count_count_start);
104
while (atomic_read(&count_count_start) != 2)
105
mb();
106
107
/*
108
* Everyone initialises count in the last loop:
109
*/
110
if (i == NR_LOOPS-1)
111
openrisc_timer_set(initcount);
112
113
atomic_inc(&count_count_stop);
114
while (atomic_read(&count_count_stop) != 2)
115
mb();
116
}
117
/* Arrange for an interrupt in a short while */
118
openrisc_timer_set_next(COUNTON);
119
}
120
#undef NR_LOOPS
121
122