mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	x86/numachip: Introduce Numachip2 timer mechanisms
Add 1GHz 64-bit Numachip2 clocksource timer support for accurate system-wide timekeeping, as core TSCs are unsynchronised. Additionally, add a per-core clockevent mechanism that interrupts via the platform IPI vector after a programmed period. [ tglx: Taking it through x86 due to dependencies ] Signed-off-by: Daniel J Blueman <daniel@numascale.com> Acked-by: Steffen Persvold <sp@numascale.com> Cc: Daniel Lezcano <daniel.lezcano@linaro.org> Link: http://lkml.kernel.org/r/1442829745-29311-1-git-send-email-daniel@numascale.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
		
							parent
							
								
									ad03a9c25d
								
							
						
					
					
						commit
						ce2e572cfe
					
				
					 3 changed files with 105 additions and 0 deletions
				
			
		| 
						 | 
					@ -59,6 +59,10 @@ static inline void write_lcsr(unsigned long offset, unsigned int val)
 | 
				
			||||||
#define NUMACHIP2_LCSR_BASE       0xf0000000UL
 | 
					#define NUMACHIP2_LCSR_BASE       0xf0000000UL
 | 
				
			||||||
#define NUMACHIP2_LCSR_SIZE       0x1000000UL
 | 
					#define NUMACHIP2_LCSR_SIZE       0x1000000UL
 | 
				
			||||||
#define NUMACHIP2_APIC_ICR        0x100000
 | 
					#define NUMACHIP2_APIC_ICR        0x100000
 | 
				
			||||||
 | 
					#define NUMACHIP2_TIMER_DEADLINE  0x200000
 | 
				
			||||||
 | 
					#define NUMACHIP2_TIMER_INT       0x200008
 | 
				
			||||||
 | 
					#define NUMACHIP2_TIMER_NOW       0x200018
 | 
				
			||||||
 | 
					#define NUMACHIP2_TIMER_RESET     0x200020
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void __iomem *numachip2_lcsr_address(unsigned long offset)
 | 
					static inline void __iomem *numachip2_lcsr_address(unsigned long offset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -86,4 +90,9 @@ static inline void numachip2_write64_lcsr(unsigned long offset, u64 val)
 | 
				
			||||||
	writeq(val, numachip2_lcsr_address(offset));
 | 
						writeq(val, numachip2_lcsr_address(offset));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline unsigned int numachip2_timer(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return (smp_processor_id() % 48) << 6;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _ASM_X86_NUMACHIP_NUMACHIP_CSR_H */
 | 
					#endif /* _ASM_X86_NUMACHIP_NUMACHIP_CSR_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,3 +62,4 @@ obj-$(CONFIG_H8300)			+= h8300_timer8.o
 | 
				
			||||||
obj-$(CONFIG_H8300_TMR16)		+= h8300_timer16.o
 | 
					obj-$(CONFIG_H8300_TMR16)		+= h8300_timer16.o
 | 
				
			||||||
obj-$(CONFIG_H8300_TPU)			+= h8300_tpu.o
 | 
					obj-$(CONFIG_H8300_TPU)			+= h8300_tpu.o
 | 
				
			||||||
obj-$(CONFIG_CLKSRC_ST_LPC)		+= clksrc_st_lpc.o
 | 
					obj-$(CONFIG_CLKSRC_ST_LPC)		+= clksrc_st_lpc.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_X86_NUMACHIP)		+= numachip.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										95
									
								
								drivers/clocksource/numachip.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								drivers/clocksource/numachip.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,95 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Numascale AS. All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This software is licensed under the terms of the GNU General Public
 | 
				
			||||||
 | 
					 * License version 2, as published by the Free Software Foundation, and
 | 
				
			||||||
 | 
					 * may be copied, distributed, and modified under those terms.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/clockchips.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/irq.h>
 | 
				
			||||||
 | 
					#include <asm/numachip/numachip.h>
 | 
				
			||||||
 | 
					#include <asm/numachip/numachip_csr.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static DEFINE_PER_CPU(struct clock_event_device, cpu_ced);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static cycles_t numachip2_timer_read(struct clocksource *cs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return numachip2_read64_lcsr(NUMACHIP2_TIMER_NOW);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct clocksource numachip2_clocksource = {
 | 
				
			||||||
 | 
						.name            = "numachip2",
 | 
				
			||||||
 | 
						.rating          = 295,
 | 
				
			||||||
 | 
						.read            = numachip2_timer_read,
 | 
				
			||||||
 | 
						.mask            = CLOCKSOURCE_MASK(64),
 | 
				
			||||||
 | 
						.flags           = CLOCK_SOURCE_IS_CONTINUOUS,
 | 
				
			||||||
 | 
						.mult            = 1,
 | 
				
			||||||
 | 
						.shift           = 0,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int numachip2_set_next_event(unsigned long delta, struct clock_event_device *ced)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						numachip2_write64_lcsr(NUMACHIP2_TIMER_DEADLINE + numachip2_timer(),
 | 
				
			||||||
 | 
							delta);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct clock_event_device numachip2_clockevent = {
 | 
				
			||||||
 | 
						.name            = "numachip2",
 | 
				
			||||||
 | 
						.rating          = 400,
 | 
				
			||||||
 | 
						.set_next_event  = numachip2_set_next_event,
 | 
				
			||||||
 | 
						.features        = CLOCK_EVT_FEAT_ONESHOT,
 | 
				
			||||||
 | 
						.mult            = 1,
 | 
				
			||||||
 | 
						.shift           = 0,
 | 
				
			||||||
 | 
						.min_delta_ns    = 1250,
 | 
				
			||||||
 | 
						.max_delta_ns    = LONG_MAX,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void numachip_timer_interrupt(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct clock_event_device *ced = this_cpu_ptr(&cpu_ced);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ced->event_handler(ced);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static __init void numachip_timer_each(struct work_struct *work)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned local_apicid = __this_cpu_read(x86_cpu_to_apicid) & 0xff;
 | 
				
			||||||
 | 
						struct clock_event_device *ced = this_cpu_ptr(&cpu_ced);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Setup IPI vector to local core and relative timing mode */
 | 
				
			||||||
 | 
						numachip2_write64_lcsr(NUMACHIP2_TIMER_INT + numachip2_timer(),
 | 
				
			||||||
 | 
							(3 << 22) | (X86_PLATFORM_IPI_VECTOR << 14) |
 | 
				
			||||||
 | 
							(local_apicid << 6));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*ced = numachip2_clockevent;
 | 
				
			||||||
 | 
						ced->cpumask = cpumask_of(smp_processor_id());
 | 
				
			||||||
 | 
						clockevents_register_device(ced);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int __init numachip_timer_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (numachip_system != 2)
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Reset timer */
 | 
				
			||||||
 | 
						numachip2_write64_lcsr(NUMACHIP2_TIMER_RESET, 0);
 | 
				
			||||||
 | 
						clocksource_register_hz(&numachip2_clocksource, NSEC_PER_SEC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Setup per-cpu clockevents */
 | 
				
			||||||
 | 
						x86_platform_ipi_callback = numachip_timer_interrupt;
 | 
				
			||||||
 | 
						schedule_on_each_cpu(&numachip_timer_each);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					arch_initcall(numachip_timer_init);
 | 
				
			||||||
		Loading…
	
		Reference in a new issue