Blame view

drivers/clocksource/numachip.c 2.71 KB
81f7e3824   Eric Lee   Initial Release, ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
  /*
   *
   * 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, numachip2_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 const struct clock_event_device numachip2_clockevent __initconst = {
  	.name            = "numachip2",
  	.rating          = 400,
  	.set_next_event  = numachip2_set_next_event,
  	.features        = CLOCK_EVT_FEAT_ONESHOT,
  	.mult            = 1,
  	.shift           = 0,
  	.min_delta_ns    = 1250,
  	.min_delta_ticks = 1250,
  	.max_delta_ns    = LONG_MAX,
  	.max_delta_ticks = LONG_MAX,
  };
  
  static void numachip_timer_interrupt(void)
  {
  	struct clock_event_device *ced = this_cpu_ptr(&numachip2_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(&numachip2_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);