^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright 2008 by Andreas Eversberg <andreas@eversberg.eu>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Quick API description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * A clock source registers using mISDN_register_clock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * name = text string to name clock source
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * priority = value to priorize clock sources (0 = default)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * ctl = callback function to enable/disable clock source
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * priv = private pointer of clock source
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * return = pointer to clock source structure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Note: Callback 'ctl' can be called before mISDN_register_clock returns!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * Also it can be called during mISDN_unregister_clock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * A clock source calls mISDN_clock_update with given samples elapsed, if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * enabled. If function call is delayed, tv must be set with the timestamp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * of the actual event.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * A clock source unregisters using mISDN_unregister_clock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * To get current clock, call mISDN_clock_get. The signed short value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * counts the number of samples since. Time since last clock event is added.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/stddef.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/ktime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/mISDNif.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include "core.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static u_int *debug;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static LIST_HEAD(iclock_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static DEFINE_RWLOCK(iclock_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static u16 iclock_count; /* counter of last clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static ktime_t iclock_timestamp; /* time stamp of last clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static int iclock_timestamp_valid; /* already received one timestamp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static struct mISDNclock *iclock_current;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) mISDN_init_clock(u_int *dp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) debug = dp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) iclock_timestamp = ktime_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) select_iclock(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct mISDNclock *iclock, *bestclock = NULL, *lastclock = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) int pri = -128;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) list_for_each_entry(iclock, &iclock_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (iclock->pri > pri) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) pri = iclock->pri;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) bestclock = iclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (iclock_current == iclock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) lastclock = iclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (lastclock && bestclock != lastclock) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) /* last used clock source still exists but changes, disable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (*debug & DEBUG_CLOCK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) printk(KERN_DEBUG "Old clock source '%s' disable.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) lastclock->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) lastclock->ctl(lastclock->priv, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (bestclock && bestclock != iclock_current) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /* new clock source selected, enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (*debug & DEBUG_CLOCK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) printk(KERN_DEBUG "New clock source '%s' enable.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) bestclock->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) bestclock->ctl(bestclock->priv, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (bestclock != iclock_current) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) /* no clock received yet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) iclock_timestamp_valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) iclock_current = bestclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct mISDNclock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) *mISDN_register_clock(char *name, int pri, clockctl_func_t *ctl, void *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) u_long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct mISDNclock *iclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (*debug & (DEBUG_CORE | DEBUG_CLOCK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) printk(KERN_DEBUG "%s: %s %d\n", __func__, name, pri);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) iclock = kzalloc(sizeof(struct mISDNclock), GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (!iclock) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) printk(KERN_ERR "%s: No memory for clock entry.\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) strncpy(iclock->name, name, sizeof(iclock->name) - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) iclock->pri = pri;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) iclock->priv = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) iclock->ctl = ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) write_lock_irqsave(&iclock_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) list_add_tail(&iclock->list, &iclock_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) select_iclock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) write_unlock_irqrestore(&iclock_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return iclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) EXPORT_SYMBOL(mISDN_register_clock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) mISDN_unregister_clock(struct mISDNclock *iclock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) u_long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (*debug & (DEBUG_CORE | DEBUG_CLOCK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) printk(KERN_DEBUG "%s: %s %d\n", __func__, iclock->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) iclock->pri);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) write_lock_irqsave(&iclock_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (iclock_current == iclock) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (*debug & DEBUG_CLOCK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) printk(KERN_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) "Current clock source '%s' unregisters.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) iclock->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) iclock->ctl(iclock->priv, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) list_del(&iclock->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) select_iclock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) write_unlock_irqrestore(&iclock_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) EXPORT_SYMBOL(mISDN_unregister_clock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) mISDN_clock_update(struct mISDNclock *iclock, int samples, ktime_t *timestamp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) u_long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) ktime_t timestamp_now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) u16 delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) write_lock_irqsave(&iclock_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (iclock_current != iclock) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) printk(KERN_ERR "%s: '%s' sends us clock updates, but we do "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) "listen to '%s'. This is a bug!\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) iclock->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) iclock_current ? iclock_current->name : "nothing");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) iclock->ctl(iclock->priv, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) write_unlock_irqrestore(&iclock_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (iclock_timestamp_valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /* increment sample counter by given samples */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) iclock_count += samples;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (timestamp) { /* timestamp must be set, if function call is delayed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) iclock_timestamp = *timestamp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) iclock_timestamp = ktime_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) /* calc elapsed time by system clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (timestamp) { /* timestamp must be set, if function call is delayed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) timestamp_now = *timestamp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) timestamp_now = ktime_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) delta = ktime_divns(ktime_sub(timestamp_now, iclock_timestamp),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) (NSEC_PER_SEC / 8000));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) /* add elapsed time to counter and set new timestamp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) iclock_count += delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) iclock_timestamp = timestamp_now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) iclock_timestamp_valid = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) if (*debug & DEBUG_CLOCK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) printk("Received first clock from source '%s'.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) iclock_current ? iclock_current->name : "nothing");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) write_unlock_irqrestore(&iclock_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) EXPORT_SYMBOL(mISDN_clock_update);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) unsigned short
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) mISDN_clock_get(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) u_long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) ktime_t timestamp_now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) u16 delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) u16 count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) read_lock_irqsave(&iclock_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) /* calc elapsed time by system clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) timestamp_now = ktime_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) delta = ktime_divns(ktime_sub(timestamp_now, iclock_timestamp),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) (NSEC_PER_SEC / 8000));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) /* add elapsed time to counter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) count = iclock_count + delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) read_unlock_irqrestore(&iclock_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) EXPORT_SYMBOL(mISDN_clock_get);