diff options
author | Helge Deller <deller@gmx.de> | 2017-01-08 05:01:11 -0500 |
---|---|---|
committer | Helge Deller <deller@gmx.de> | 2017-05-10 11:46:14 -0400 |
commit | c8c3735997a3aa184fa81742bb6c4062a26af2f3 (patch) | |
tree | 3d6e8864e8935ac167efc3313913444b4eb2e811 | |
parent | c3e5523fcffdc9df8faa7d66f5ad8c1c833e1795 (diff) |
parisc: Enhance detection of synchronous cr16 clocksources
The cr16 clocks of the physical PARISC CPUs are usually nonsynchronous.
Nevertheless, it seems that each CPU socket (which holds two cores) of
PA8800 and PA8900 CPUs (e.g. in a C8000 workstation) is fed by the same
clock source, which makes the cr16 clocks of each CPU socket syncronous.
Let's try to detect such situations and mark the cr16 clocksource stable
on single-socket and single-core machines.
Signed-off-by: Helge Deller <deller@gmx.de>
-rw-r--r-- | arch/parisc/include/asm/processor.h | 2 | ||||
-rw-r--r-- | arch/parisc/kernel/processor.c | 5 | ||||
-rw-r--r-- | arch/parisc/kernel/time.c | 24 |
3 files changed, 26 insertions, 5 deletions
diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h index a3661ee6b060..ea4e6ae091d0 100644 --- a/arch/parisc/include/asm/processor.h +++ b/arch/parisc/include/asm/processor.h | |||
@@ -103,6 +103,8 @@ struct cpuinfo_parisc { | |||
103 | unsigned long bh_count; /* number of times bh was invoked */ | 103 | unsigned long bh_count; /* number of times bh was invoked */ |
104 | unsigned long fp_rev; | 104 | unsigned long fp_rev; |
105 | unsigned long fp_model; | 105 | unsigned long fp_model; |
106 | unsigned long cpu_num; /* CPU number from PAT firmware */ | ||
107 | unsigned long cpu_loc; /* CPU location from PAT firmware */ | ||
106 | unsigned int state; | 108 | unsigned int state; |
107 | struct parisc_device *dev; | 109 | struct parisc_device *dev; |
108 | unsigned long loops_per_jiffy; | 110 | unsigned long loops_per_jiffy; |
diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c index 85de47f4eb59..0ab32779dfa7 100644 --- a/arch/parisc/kernel/processor.c +++ b/arch/parisc/kernel/processor.c | |||
@@ -94,7 +94,7 @@ static int processor_probe(struct parisc_device *dev) | |||
94 | unsigned long txn_addr; | 94 | unsigned long txn_addr; |
95 | unsigned long cpuid; | 95 | unsigned long cpuid; |
96 | struct cpuinfo_parisc *p; | 96 | struct cpuinfo_parisc *p; |
97 | struct pdc_pat_cpu_num cpu_info __maybe_unused; | 97 | struct pdc_pat_cpu_num cpu_info = { }; |
98 | 98 | ||
99 | #ifdef CONFIG_SMP | 99 | #ifdef CONFIG_SMP |
100 | if (num_online_cpus() >= nr_cpu_ids) { | 100 | if (num_online_cpus() >= nr_cpu_ids) { |
@@ -113,6 +113,7 @@ static int processor_probe(struct parisc_device *dev) | |||
113 | */ | 113 | */ |
114 | cpuid = boot_cpu_data.cpu_count; | 114 | cpuid = boot_cpu_data.cpu_count; |
115 | txn_addr = dev->hpa.start; /* for legacy PDC */ | 115 | txn_addr = dev->hpa.start; /* for legacy PDC */ |
116 | cpu_info.cpu_num = cpu_info.cpu_loc = cpuid; | ||
116 | 117 | ||
117 | #ifdef CONFIG_64BIT | 118 | #ifdef CONFIG_64BIT |
118 | if (is_pdc_pat()) { | 119 | if (is_pdc_pat()) { |
@@ -180,6 +181,8 @@ static int processor_probe(struct parisc_device *dev) | |||
180 | p->hpa = dev->hpa.start; /* save CPU hpa */ | 181 | p->hpa = dev->hpa.start; /* save CPU hpa */ |
181 | p->cpuid = cpuid; /* save CPU id */ | 182 | p->cpuid = cpuid; /* save CPU id */ |
182 | p->txn_addr = txn_addr; /* save CPU IRQ address */ | 183 | p->txn_addr = txn_addr; /* save CPU IRQ address */ |
184 | p->cpu_num = cpu_info.cpu_num; | ||
185 | p->cpu_loc = cpu_info.cpu_loc; | ||
183 | #ifdef CONFIG_SMP | 186 | #ifdef CONFIG_SMP |
184 | /* | 187 | /* |
185 | ** FIXME: review if any other initialization is clobbered | 188 | ** FIXME: review if any other initialization is clobbered |
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 89421df70160..2d956aa0a38a 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c | |||
@@ -243,14 +243,30 @@ void __init time_init(void) | |||
243 | static int __init init_cr16_clocksource(void) | 243 | static int __init init_cr16_clocksource(void) |
244 | { | 244 | { |
245 | /* | 245 | /* |
246 | * The cr16 interval timers are not syncronized across CPUs, so mark | 246 | * The cr16 interval timers are not syncronized across CPUs on |
247 | * them unstable and lower rating on SMP systems. | 247 | * different sockets, so mark them unstable and lower rating on |
248 | * multi-socket SMP systems. | ||
248 | */ | 249 | */ |
249 | if (num_online_cpus() > 1) { | 250 | if (num_online_cpus() > 1) { |
250 | clocksource_cr16.flags = CLOCK_SOURCE_UNSTABLE; | 251 | int cpu; |
251 | clocksource_cr16.rating = 0; | 252 | unsigned long cpu0_loc; |
253 | cpu0_loc = per_cpu(cpu_data, 0).cpu_loc; | ||
254 | |||
255 | for_each_online_cpu(cpu) { | ||
256 | if (cpu0_loc == per_cpu(cpu_data, cpu).cpu_loc) | ||
257 | continue; | ||
258 | |||
259 | clocksource_cr16.name = "cr16_unstable"; | ||
260 | clocksource_cr16.flags = CLOCK_SOURCE_UNSTABLE; | ||
261 | clocksource_cr16.rating = 0; | ||
262 | break; | ||
263 | } | ||
252 | } | 264 | } |
253 | 265 | ||
266 | /* XXX: We may want to mark sched_clock stable here if cr16 clocks are | ||
267 | * in sync: | ||
268 | * (clocksource_cr16.flags == CLOCK_SOURCE_IS_CONTINUOUS) */ | ||
269 | |||
254 | /* register at clocksource framework */ | 270 | /* register at clocksource framework */ |
255 | clocksource_register_hz(&clocksource_cr16, | 271 | clocksource_register_hz(&clocksource_cr16, |
256 | 100 * PAGE0->mem_10msec); | 272 | 100 * PAGE0->mem_10msec); |