clockeventsframework will be discussed. We already saw one framework in the second part of this chapter. It was
clocksourceframework. Both of these frameworks represent timekeeping abstractions in the Linux kernel.
clocksourceframework and and what its purpose. The main goal of the
clocksourceframework is to provide
timeline. As described in the documentation:
For example issuing the command 'date' on a Linux system will eventually read the clock source to determine exactly what time it is.
1193182Hz frequency, yet another one - ACPI PM timer with
3579545Hz frequency. Besides the drivers/clocksource directory, each architecture may provide own architecture-specific clock sources. For example x86 architecture provides High Precision Event Timer, or for example powerpc provides access to the processor timer through
clocksourceframework is to provide API to select best available clock source in the system i.e. a clock source with the highest frequency. Additional goal of the
clocksourceframework is to represent an atomic counter provided by a clock source in human units. In this time, nanoseconds are the favorite choice for the time value units of the given clock source in the Linux kernel.
clocksourceframework represented by the
clocksourcestructure which is defined in the include/linux/clocksource.h header code file which contains
nameof a clock source, rating of certain clock source in the system (a clock source with the higher frequency has the biggest rating in the system),
listof all registered clock source in the system,
disablefields to enable and disable a clock source, pointer to the
readfunction which must return an atomic counter of a clock source and etc.
clocksourcestructure provides two fields:
shiftwhich are needed for translation of an atomic counter which is provided by a certain clock source to the human units, i.e. nanoseconds. Translation occurs via following formula:
clocksourceframework provides an API for registration of clock source with different frequency scale factor:
Clock events are the conceptual reverse of clock sources
clock_event_devicestructure. This structure is defined in the include/linux/clockchips.h header file and contains a huge set of fields. as well as the
clocksourcestructure it has
namefields which contains human readable name of a clock event device, for example local APIC timer:
next_eventfunctions for a certain clock event device which are an interrupt handler, setter of next event and local storage for next event respectively. Yet another field of the
clock_event_devicestructure is -
featuresfield. Its value maybe on of the following generic features:
CLOCK_EVT_FEAT_PERIODICrepresents device which may be programmed to generate events periodically. The
CLOCK_EVT_FEAT_ONESHOTrepresents device which may generate an event only once. Besides these two features, there are also architecture-specific features. For example x86_64 supports two additional features:
CLOCK_EVT_FEAT_C3STOPmeans that a clock event device will be stopped in the C3 state. Additionally the
shiftfields as well as
clocksourcestructure also contains other fields, but we will consider it later.
clock_event_devicestructure, time is to look at the
clockeventsframework. To work with a clock event device, first of all we need to initialize
clock_event_devicestructure and register a clock events device. The
clockeventsframework provides following
APIfor registration of clock event devices:
clock_event_devicestructure which represents a clock event device.
clock_event_devicestructure with parameters of a certain clock event device. Let's take a look at one random clock event device in the Linux kernel source code. We can find one in the drivers/clocksource directory or try to take a look at an architecture-specific clock event device. Let's take for example - Periodic Interval Timer (PIT) for at91sam926x. You can find its implementation in the drivers/clocksource.
clock_event_devicestructure. This occurs in the
at91sam926x_pit_common_inittakes one parameter - pointer to the
pit_datastructure which contains
clock_event_devicestructure which will contain clock event related information of the
at91sam926xperiodic Interval Timer. At the start we fill
nameof the timer device and its
features. In our case we deal with periodic timer which as we already know may be programmed to generate events periodically.
multare familiar to us. They will be used to translate counter of our timer to nanoseconds. After this we set rating of the timer to
100. This means if there will not be timers with higher rating in the system, this timer will be used for timekeeping. The next field -
cpumaskindicates for which processors in the system the device will work. In our case, the device will work for the first processor. The
cpumask_ofmacro defined in the include/linux/cpumask.h header file and just expands to the call of the:
get_cpu_maskreturns the cpumask containing just a given
cpunumber. More about
cpumasksconcept you may read in the CPU masks in the Linux kernel part. In the last four lines of code we set callbacks for the clock event device suspend/resume, device shutdown and update of the clock event device state.
at91sam926xperiodic timer, we can register it by the call of the following functions:
clockevent_register_devicefunction. As I already wrote above, this function is defined in the kernel/time/clockevents.c source code file and starts from the initialization of the initial event device state:
CLOCK_EVT_STATE_DETACHED- a clock event device is not not used by
clockeventsframework. Actually it is initial state of all clock event devices;
CLOCK_EVT_STATE_SHUTDOWN- a clock event device is powered-off;
CLOCK_EVT_STATE_PERIODIC- a clock event device may be programmed to generate event periodically;
CLOCK_EVT_STATE_ONESHOT- a clock event device may be programmed to generate event only once;
CLOCK_EVT_STATE_ONESHOT_STOPPED- a clock event device was programmed to generate event only once and now it is temporary stopped.
clock_event_set_statefunction is pretty easy:
state_use_accessorsfield of the given
clock_event_devicestructure with the given value which is in our case is
CLOCK_EVT_STATE_DETACHED. Actually all clock event devices has this initial state during registration. The
state_use_accessorsfield of the
currentstate of the clock event device.
clock_event_devicestructure we check that the
cpumaskof the given clock event device is not zero:
at91sam926xperiodic timer to first processor. If the
cpumaskfield is zero, we check the number of possible processors in the system and print warning message if it is less than on. Additionally we set the
cpumaskof the given clock event device to the current processor. If you are interested in how the
smp_processor_idmacro is implemented, you can read more about it in the fourth part of the Linux kernel initialization process chapter.
raw_spin_unlock_irqrestoremacros disable local interrupts, however interrupts on other processors still may occur. We need to do it to prevent potential deadlock if we adding new clock event device to the list of clock event devices and an interrupt occurs from other clock event device.
tick_check_new_devicefunction which is defined in the kernel/time/tick-common.c source code file and checks do the new registered clock event device should be used or not. The
tick_check_new_devicefunction checks the given
clock_event_devicegets the current registered tick device which is represented by the
tick_devicestructure and compares their ratings and features. Actually
clockevents_exchange_devicefunction releases or in other words deleted the old clock event device from the
clockevent_deviceslist. The next function -
tick_setup_deviceas we may understand from its name, setups new tick device. This function check the mode of the new registered clock event device and call the
tick_setup_periodicfunction or the
tick_setup_oneshotdepends on the tick device mode:
clockevents_switch_stateto change state of the clock event device and the
clockevents_program_eventfunction to set next event of clock event device based on delta between the maximum and minimum difference current time and time for the next event. The
clockevents_switch_statefunction checks that the clock event device is not in the given state and calls the
__clockevents_switch_statefunction from the same source code file:
__clockevents_switch_statefunction just makes a call of the certain callback depends on the given state:
at91sam926xperiodic timer, the state is the
pit_clkevt_set_periodiccallback will be called. If we will read the documentation of the Periodic Interval Timer (PIT) for at91sam926x, we will see that there is
Periodic Interval Timer Mode Registerwhich allows us to control of periodic interval timer.
Periodic Interval Value- defines the value compared with the primary
20-bitcounter of the Periodic Interval Timer. The
Period Interval Timer Enabledif the bit is
Periodic Interval Timer Interrupt Enableif the bit is
1. So, to set periodic mode, we need to set
25bits in the
Periodic Interval Timer Mode Register. And we are doing it in the
AT91_PIT_PITIENare declared as:
clockevents_register_devicefunction. The last function in the
clockevents_releasedlist which contains released clock event devices (remember that they may occur after the call of the
clockevents_exchange_devicefunction). If this list is not empty, we go through clock event devices from the
clock_events_releasedlist and delete it from the
clockeventsframework is simple and clear. Architectures registered their clock event devices, in the clock events core. Users of the clockevents core can get clock event devices for their use. The
clockeventsframework provides notification mechanisms for various clock related management events like a clock event device registered or unregistered, a processor is offlined in system which supports CPU hotplug and etc.
clockevents_register_devicefunction. But generally, the clock event layer API is small. Besides the
APIfor clock event device registration, the
clockeventsframework provides functions to schedule the next event interrupt, clock event device notification service and support for suspend and resume for clock event devices.
timersconcept. In this part we continued to learn time management related stuff in the Linux kernel and saw a little about yet another framework -