hc
2025-02-14 bbb9540dc49f70f6b703d1c8d1b85fa5f602d86e
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
// SPDX-License-Identifier: GPL-2.0-only
/*
 *
 * Copyright (C) 2015 Numascale AS. All rights reserved.
 */
 
#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);