Alt text

The target platform can provide particular clock chips and/or clock source drivers in addition to the architecture-specific ones. For instance, some device on a PCI bus could implement a timer chip which the application wants to use for timing its threads, in addition to the architected timer found on ARM64 and some ARM-based SoCs. In this case, we would need a specific clock driver, binding the timer hardware to the EVL core.

The EVL clock device interface gives you a framework for integrating such hardware into the real-time core, which in turns enables applications to use it.

EVL abstracts clock event devices and clock sources (timekeeping hardware) into a single clock element.

int evl_init_clock(struct evl_clock *clock, const struct cpumask *affinity)

Initializes a new clock which may be used to drive EVL core timers.

  • clock

    A descriptor describing the clock properties, which the core is also going to use for maintaining some runtime information. See below.

  • affinity

    The set of CPUs we may expect the backing clock device to tick on, usually denoting a per-CPU device. As a special case, passing a NULL affinity mask means that we have to deal with a global device which does not issue per-CPU events, in which case outstanding timers based on this clock will be maintained into a single global queue instead of per-CPU timer queues. At least one out-of-band CPU mentioned in evl_oob_cpus should be present in the clock affinity mask.

  • The clock descriptor should be filled in by the caller with the following information on entry to evl_init_clock():

    • .name: name of the clock. If the clock has public visibility, the file representing this clock in the /dev/evl hierarchy is named after it.

    • .resolution: the resolution of the clock in nanoseconds.

    • .flags: a set of creation flags for the new clock, defining its visibility:

      • EVL_CLONE_PUBLIC denotes a public clock which is represented by a device file in the /dev/evl file hierarchy, which makes it visible to application processes for sharing.

      • EVL_CLONE_PRIVATE denotes a clock which is private to the kernel. No device file appears for it in the /dev/evl file hierarchy.

    • .gravity: the clock gravity value, which is a set of static adjustment values to account for the basic latency of the target system for responding to timer events, as described in this document.

    • .ops: a set of operation handlers which should be implemented by the caller:

      • ktime_t (*read)(struct evl_clock *clock)

      • u64 (*read_cycles)(struct evl_clock *clock)

      • int (*set)(struct evl_clock *clock, ktime_t date)

      • void (*program_local_shot)(struct evl_clock *clock)

      • void (*program_remote_shot)(struct evl_clock *clock, struct evl_rq *rq)

      • int (*set_gravity)(struct evl_clock *clock, const struct evl_clock_gravity *p)

      • void (*reset_gravity)(struct evl_clock *clock)

      • void (*adjust)(struct evl_clock *clock)

    A typical example: the EVL core monotonic clock

    struct evl_clock evl_mono_clock = {
    	.name = EVL_CLOCK_MONOTONIC_DEV,  /* i.e. "monotonic" */
    	.resolution = 1,  /* nanosecond. */
    	.flags = EVL_CLONE_PUBLIC,
    	.ops = {
    		.read = read_mono_clock,
    		.read_cycles = read_mono_clock_cycles,
    		.program_local_shot = evl_program_proxy_tick,
    #ifdef CONFIG_SMP
    		.program_remote_shot = evl_send_timer_ipi,
    		.set_gravity = set_coreclk_gravity,
    		.reset_gravity = reset_coreclk_gravity,

    evl_init_clock() returns zero on success, or a negated error code otherwise:

    • -EEXIST The generated name is conflicting with an existing clock name.

    • -EINVAL Either clock->flags or affinity are wrong.

    • -ENAMETOOLONG The overall length of the device element’s file path including the generated name exceeds PATH_MAX.

    • -ENOMEM Not enough memory available.

    evl_init_slave_clock(struct evl_clock *clock, struct evl_clock *master)

    int evl_register_clock(struct evl_clock *clock, const struct cpumask *affinity)

    void evl_unregister_clock(struct evl_clock *clock)

    void evl_announce_tick(struct evl_clock *clock)

    void evl_adjust_timers(struct evl_clock *clock, ktime_t delta)

    ktime_t evl_read_clock(struct evl_clock *clock)

    ktime_t evl_ktime_monotonic(void)

    u64 evl_read_clock_cycles(struct evl_clock *clock)

    int evl_set_clock_time(struct evl_clock *clock, const struct timespec *ts)

    void evl_set_clock_resolution(struct evl_clock *clock, ktime_t resolution)

    ktime_t evl_get_clock_resolution(struct evl_clock *clock)

    int evl_set_clock_gravity(struct evl_clock *clock, const struct evl_clock_gravity *gravity)

    struct evl_clock *evl_get_clock_by_fd(int efd)

    void evl_put_clock(struct evl_clock *clock)

    Last modified: Thu, 06 Apr 2023 15:08:57 +0200