linux/drivers/clocksource/numachip.c
<<
>>
Prefs
   1/*
   2 *
   3 * Copyright (C) 2015 Numascale AS. All rights reserved.
   4 *
   5 * This software is licensed under the terms of the GNU General Public
   6 * License version 2, as published by the Free Software Foundation, and
   7 * may be copied, distributed, and modified under those terms.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 */
  15
  16#include <linux/clockchips.h>
  17
  18#include <asm/irq.h>
  19#include <asm/numachip/numachip.h>
  20#include <asm/numachip/numachip_csr.h>
  21
  22static DEFINE_PER_CPU(struct clock_event_device, numachip2_ced);
  23
  24static cycles_t numachip2_timer_read(struct clocksource *cs)
  25{
  26        return numachip2_read64_lcsr(NUMACHIP2_TIMER_NOW);
  27}
  28
  29static struct clocksource numachip2_clocksource = {
  30        .name            = "numachip2",
  31        .rating          = 295,
  32        .read            = numachip2_timer_read,
  33        .mask            = CLOCKSOURCE_MASK(64),
  34        .flags           = CLOCK_SOURCE_IS_CONTINUOUS,
  35        .mult            = 1,
  36        .shift           = 0,
  37};
  38
  39static int numachip2_set_next_event(unsigned long delta, struct clock_event_device *ced)
  40{
  41        numachip2_write64_lcsr(NUMACHIP2_TIMER_DEADLINE + numachip2_timer(),
  42                delta);
  43        return 0;
  44}
  45
  46static const struct clock_event_device numachip2_clockevent __initconst = {
  47        .name            = "numachip2",
  48        .rating          = 400,
  49        .set_next_event  = numachip2_set_next_event,
  50        .features        = CLOCK_EVT_FEAT_ONESHOT,
  51        .mult            = 1,
  52        .shift           = 0,
  53        .min_delta_ns    = 1250,
  54        .min_delta_ticks = 1250,
  55        .max_delta_ns    = LONG_MAX,
  56        .max_delta_ticks = LONG_MAX,
  57};
  58
  59static void numachip_timer_interrupt(void)
  60{
  61        struct clock_event_device *ced = this_cpu_ptr(&numachip2_ced);
  62
  63        ced->event_handler(ced);
  64}
  65
  66static __init void numachip_timer_each(struct work_struct *work)
  67{
  68        unsigned local_apicid = __this_cpu_read(x86_cpu_to_apicid) & 0xff;
  69        struct clock_event_device *ced = this_cpu_ptr(&numachip2_ced);
  70
  71        /* Setup IPI vector to local core and relative timing mode */
  72        numachip2_write64_lcsr(NUMACHIP2_TIMER_INT + numachip2_timer(),
  73                (3 << 22) | (X86_PLATFORM_IPI_VECTOR << 14) |
  74                (local_apicid << 6));
  75
  76        *ced = numachip2_clockevent;
  77        ced->cpumask = cpumask_of(smp_processor_id());
  78        clockevents_register_device(ced);
  79}
  80
  81static int __init numachip_timer_init(void)
  82{
  83        if (numachip_system != 2)
  84                return -ENODEV;
  85
  86        /* Reset timer */
  87        numachip2_write64_lcsr(NUMACHIP2_TIMER_RESET, 0);
  88        clocksource_register_hz(&numachip2_clocksource, NSEC_PER_SEC);
  89
  90        /* Setup per-cpu clockevents */
  91        x86_platform_ipi_callback = numachip_timer_interrupt;
  92        schedule_on_each_cpu(&numachip_timer_each);
  93
  94        return 0;
  95}
  96
  97arch_initcall(numachip_timer_init);
  98