Clock Event Devices

Clock event devices are defined by the following data structure: <clockchips.h>

struct clock_event_device { const char *name; unsigned int features; unsigned long max_delta_ns; unsigned long min_delta_ns; unsigned long mult; int shift; int rating; int irq;

cpumask_t cpumask;

int (*set_next_event)(unsigned long evt, struct clock_event_device *); void (*set_mode)(enum clock_event_mode mode, struct clock_event_device *); void (*event_handler)(struct clock_event_device *); void (*broadcast)(cpumask_t mask); struct list_head list; enum clock_event_mode mode; ktime_t next_event;

Recall that clock event devices allow for registering an event that is going to happen at a defined point of time in the future. In comparison to a full-blown timer implementation, however, only a single event can be stored. The key elements of every clock_event_device are set_next_event because it allows for setting the time at which the event is going to take place, and event_handler, which is called when the event actually happens.

Besides, the elements of clock_event_device have the following purpose:

□ name is a human-readable representation for the event device. It shows up in /proc/timerlist.

□ max_delta_ns and min_delta_ns specify the maximum or minimum, respectively, difference between the current time and the time for the next event. Clocks work with individual frequencies at which device cycles occur, but the generic time subsystem expects a nanosecond value when the event shall take place. The auxiliary function clockevent_delta2ns helps to convert one representation into the other.

Consider, for instance, that the current time is 20, min_delta_ns is 2, and max_delta_ns is 40 (of course, the exemplary values do not represent any situation possible in reality). Then the next event can take place during the time interval [22,60] where the boundaries are included.

□ mult and shift are a multiplier and a divider, respectively, used to convert between clock cycles and nanosecond values.

□ The function pointed to by event_handler is called by the hardware interface code (which usually is architecture-specific) to pass clock events on to the generic layers.

□ irq specifies the number of the IRQ that is used by the event device. Note that this is only required for global devices. Per-CPU local devices use different hardware mechanisms to emit signals and set irq to -1.

□ cpumask specifies for which CPUs the event device works. A simple bitmask is employed for this purpose. Local devices are usually only responsible for a single CPU.

□ broadcast is required for the broadcasting implementation that provides a workaround for nonfunctional local APICs on IA-32 and AMD64 in power-saving mode. See Section 15.6 for more details.

□ rating allows — in analogy to the mechanism described for clock devices — comparison of clock event devices by explicitly rating their accuracy.

□ All instances of struct clock_event_device are kept on the global list clockevent_devices, and list is the list head required for this purpose.

The auxiliary function clockevents_register_device is used to register a new clock event device. This places the device on the global list.

□ ktime_t stores the absolute time of the next event.

Each event device is characterized by several features stored as a bit string in features. A number of constants in <clockchips.h> define possible features. For our purposes, two are of interest12:

□ Clock event devices that support periodic events (i.e., events that are repeated over and over again without the need to explicitly activate them by reprogramming the device) are identified by CLOCK_EVT_FEAT_PERIODIC.

□ clock_evt_feat_oneshot marks a clock capable of issuing one-shot events that happen exactly once. Basically, this is the opposite of periodic events.

set_mode points to a function that allows for toggling the desired mode of operation between periodic and one-shot mode. mode designates the current mode of operation. A clock can only be in either periodic or one-shot mode at a time, but it can nevertheless provide the ability to work in both modes — actually, most clocks allow both possibilities.

Generic code does not need to call set_next_event directly because the kernel provides the following auxiliary function for this task:

kernel/time/clockevents.c int clockevents_program_event(struct clock_event_device *dev, ktime_t expires, ktime_t now)

The (absolute) expiration time for the device dev is given in expires, while now denotes the current time. Usually the caller will directly pass the result of ktime_get() for this parameter.

On IA-32 and AMD64 systems, the role of the global clock event device is initially assumed by the PIT. The HPET takes over this duty once it has been initialized. To keep track of which device is used

12Recall that local APICs on IA-32 and AMD64 systems expose a problem: They stop working at certain power save levels. This problem is reported to the kernel by setting the ''feature'' CLOCK_EVT_FEAT_C3STOP, which should rather be named a mis-feature.

to handle global clock events on x86 systems, the global variable global_clock_event as defined in arch/x86/kernel/i8253.c is employed. It points to the clock_event_device instance for the global clock device that is currently in use.

Clock devices and clock event device are formally unconnected at the data structure level. However, one particular hardware chip in the system provides capabilities that allow fulfillment of the requirements for both interfaces, so the kernel usually registers a clock device and a clock event device per time hardware chip. Consider, for instance, the HPET device on IA-32 and AMD64 systems. The capabilities as clock source are collected in clocksource_hpet, while hpet_clockevent is an instance of clock_event_device. Both are defined in arch/x86/kernel/hpet.c. hpet_init first registers the clock source and then the clock event device. This adds two time-management objects to the kernel, but only a single piece of hardware is required.

Continue reading here: Info

Was this article helpful?

+1 0