/* * Copyright (c) 2017 Richard Braun. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct clock_cpu_data { struct syscnt sc_tick_intrs; }; static struct clock_cpu_data clock_cpu_data __percpu; union clock_global_time clock_global_time; static inline void __init clock_cpu_data_init(struct clock_cpu_data *cpu_data, unsigned int cpu) { char name[SYSCNT_NAME_SIZE]; snprintf(name, sizeof(name), "clock_tick_intrs/%u", cpu); syscnt_register(&cpu_data->sc_tick_intrs, name); } static int __init clock_setup(void) { for (unsigned int cpu = 0; cpu < cpu_count(); cpu++) { clock_cpu_data_init(percpu_ptr(clock_cpu_data, cpu), cpu); } return 0; } INIT_OP_DEFINE(clock_setup, INIT_OP_DEP(cpu_mp_probe, true), INIT_OP_DEP(syscnt_setup, true)); void clock_tick_intr(void) { struct clock_cpu_data *cpu_data; assert(thread_check_intr_context()); if (cpu_id() == 0) { #ifdef ATOMIC_HAVE_64B_OPS atomic_add(&clock_global_time.ticks, 1, ATOMIC_RELAXED); #else /* ATOMIC_HAVE_64B_OPS */ union clock_global_time t; t.ticks = clock_global_time.ticks; t.ticks++; atomic_store(&clock_global_time.high2, t.high1, ATOMIC_RELAXED); atomic_store(&clock_global_time.low, t.low, ATOMIC_RELEASE); atomic_store(&clock_global_time.high1, t.high1, ATOMIC_RELEASE); #endif /* ATOMIC_HAVE_64B_OPS */ } timer_report_periodic_event(); rcu_report_periodic_event(); sref_report_periodic_event(); work_report_periodic_event(); thread_report_periodic_event(); cpu_data = cpu_local_ptr(clock_cpu_data); syscnt_inc(&cpu_data->sc_tick_intrs); }