Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  ptp_vclock.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * PTP virtual clock driver
 *
 * Copyright 2021 NXP
 */

#include <linux/slab.h>
#include <linux/hashtable.h>
#include "ptp_private.h"

#define PTP_VCLOCK_CC_SHIFT  31
#define PTP_VCLOCK_CC_MULT  (1 << PTP_VCLOCK_CC_SHIFT)
#define PTP_VCLOCK_FADJ_SHIFT  9
#define PTP_VCLOCK_FADJ_DENOMINATOR 15625ULL
#define PTP_VCLOCK_REFRESH_INTERVAL (HZ * 2)

/* protects vclock_hash addition/deletion */
static DEFINE_SPINLOCK(vclock_hash_lock);

static DEFINE_READ_MOSTLY_HASHTABLE(vclock_hash, 8);

static void ptp_vclock_hash_add(struct ptp_vclock *vclock)
{
 spin_lock(&vclock_hash_lock);

 hlist_add_head_rcu(&vclock->vclock_hash_node,
      &vclock_hash[vclock->clock->index % HASH_SIZE(vclock_hash)]);

 spin_unlock(&vclock_hash_lock);
}

static void ptp_vclock_hash_del(struct ptp_vclock *vclock)
{
 spin_lock(&vclock_hash_lock);

 hlist_del_init_rcu(&vclock->vclock_hash_node);

 spin_unlock(&vclock_hash_lock);

 synchronize_rcu();
}

static int ptp_vclock_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
 struct ptp_vclock *vclock = info_to_vclock(ptp);
 s64 adj;

 adj = (s64)scaled_ppm << PTP_VCLOCK_FADJ_SHIFT;
 adj = div_s64(adj, PTP_VCLOCK_FADJ_DENOMINATOR);

 if (mutex_lock_interruptible(&vclock->lock))
  return -EINTR;
 timecounter_read(&vclock->tc);
 vclock->cc.mult = PTP_VCLOCK_CC_MULT + adj;
 mutex_unlock(&vclock->lock);

 return 0;
}

static int ptp_vclock_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
 struct ptp_vclock *vclock = info_to_vclock(ptp);

 if (mutex_lock_interruptible(&vclock->lock))
  return -EINTR;
 timecounter_adjtime(&vclock->tc, delta);
 mutex_unlock(&vclock->lock);

 return 0;
}

static int ptp_vclock_gettime(struct ptp_clock_info *ptp,
         struct timespec64 *ts)
{
 struct ptp_vclock *vclock = info_to_vclock(ptp);
 u64 ns;

 if (mutex_lock_interruptible(&vclock->lock))
  return -EINTR;
 ns = timecounter_read(&vclock->tc);
 mutex_unlock(&vclock->lock);
 *ts = ns_to_timespec64(ns);

 return 0;
}

static int ptp_vclock_gettimex(struct ptp_clock_info *ptp,
          struct timespec64 *ts,
          struct ptp_system_timestamp *sts)
{
 struct ptp_vclock *vclock = info_to_vclock(ptp);
 struct ptp_clock *pptp = vclock->pclock;
 struct timespec64 pts;
 int err;
 u64 ns;

 err = pptp->info->getcyclesx64(pptp->info, &pts, sts);
 if (err)
  return err;

 if (mutex_lock_interruptible(&vclock->lock))
  return -EINTR;
 ns = timecounter_cyc2time(&vclock->tc, timespec64_to_ns(&pts));
 mutex_unlock(&vclock->lock);

 *ts = ns_to_timespec64(ns);

 return 0;
}

static int ptp_vclock_settime(struct ptp_clock_info *ptp,
         const struct timespec64 *ts)
{
 struct ptp_vclock *vclock = info_to_vclock(ptp);
 u64 ns = timespec64_to_ns(ts);

 if (mutex_lock_interruptible(&vclock->lock))
  return -EINTR;
 timecounter_init(&vclock->tc, &vclock->cc, ns);
 mutex_unlock(&vclock->lock);

 return 0;
}

static int ptp_vclock_getcrosststamp(struct ptp_clock_info *ptp,
         struct system_device_crosststamp *xtstamp)
{
 struct ptp_vclock *vclock = info_to_vclock(ptp);
 struct ptp_clock *pptp = vclock->pclock;
 int err;
 u64 ns;

 err = pptp->info->getcrosscycles(pptp->info, xtstamp);
 if (err)
  return err;

 if (mutex_lock_interruptible(&vclock->lock))
  return -EINTR;
 ns = timecounter_cyc2time(&vclock->tc, ktime_to_ns(xtstamp->device));
 mutex_unlock(&vclock->lock);

 xtstamp->device = ns_to_ktime(ns);

 return 0;
}

static long ptp_vclock_refresh(struct ptp_clock_info *ptp)
{
 struct ptp_vclock *vclock = info_to_vclock(ptp);
 struct timespec64 ts;

 ptp_vclock_gettime(&vclock->info, &ts);

 return PTP_VCLOCK_REFRESH_INTERVAL;
}

static void ptp_vclock_set_subclass(struct ptp_clock *ptp)
{
 lockdep_set_subclass(&ptp->clock.rwsem, PTP_LOCK_VIRTUAL);
}

static const struct ptp_clock_info ptp_vclock_info = {
 .owner  = THIS_MODULE,
 .name  = "ptp virtual clock",
 .max_adj = 500000000,
 .adjfine = ptp_vclock_adjfine,
 .adjtime = ptp_vclock_adjtime,
 .settime64 = ptp_vclock_settime,
 .do_aux_work = ptp_vclock_refresh,
};

static u64 ptp_vclock_read(struct cyclecounter *cc)
{
 struct ptp_vclock *vclock = cc_to_vclock(cc);
 struct ptp_clock *ptp = vclock->pclock;
 struct timespec64 ts = {};

 ptp->info->getcycles64(ptp->info, &ts);

 return timespec64_to_ns(&ts);
}

static const struct cyclecounter ptp_vclock_cc = {
 .read = ptp_vclock_read,
 .mask = CYCLECOUNTER_MASK(32),
 .mult = PTP_VCLOCK_CC_MULT,
 .shift = PTP_VCLOCK_CC_SHIFT,
};

struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock)
{
 struct ptp_vclock *vclock;

 vclock = kzalloc(sizeof(*vclock), GFP_KERNEL);
 if (!vclock)
  return NULL;

 vclock->pclock = pclock;
 vclock->info = ptp_vclock_info;
 if (pclock->info->getcyclesx64)
  vclock->info.gettimex64 = ptp_vclock_gettimex;
 else
  vclock->info.gettime64 = ptp_vclock_gettime;
 if (pclock->info->getcrosscycles)
  vclock->info.getcrosststamp = ptp_vclock_getcrosststamp;
 vclock->cc = ptp_vclock_cc;

 snprintf(vclock->info.name, PTP_CLOCK_NAME_LEN, "ptp%d_virt",
   pclock->index);

 INIT_HLIST_NODE(&vclock->vclock_hash_node);

 mutex_init(&vclock->lock);

 vclock->clock = ptp_clock_register(&vclock->info, &pclock->dev);
 if (IS_ERR_OR_NULL(vclock->clock)) {
  kfree(vclock);
  return NULL;
 }

 ptp_vclock_set_subclass(vclock->clock);

 timecounter_init(&vclock->tc, &vclock->cc, 0);
 ptp_schedule_worker(vclock->clock, PTP_VCLOCK_REFRESH_INTERVAL);

 ptp_vclock_hash_add(vclock);

 return vclock;
}

void ptp_vclock_unregister(struct ptp_vclock *vclock)
{
 ptp_vclock_hash_del(vclock);

 ptp_clock_unregister(vclock->clock);
 kfree(vclock);
}

#if IS_BUILTIN(CONFIG_PTP_1588_CLOCK)
int ptp_get_vclocks_index(int pclock_index, int **vclock_index)
{
 char name[PTP_CLOCK_NAME_LEN] = "";
 struct ptp_clock *ptp;
 struct device *dev;
 int num = 0;

 if (pclock_index < 0)
  return num;

 snprintf(name, PTP_CLOCK_NAME_LEN, "ptp%d", pclock_index);
 dev = class_find_device_by_name(&ptp_class, name);
 if (!dev)
  return num;

 ptp = dev_get_drvdata(dev);

 if (mutex_lock_interruptible(&ptp->n_vclocks_mux)) {
  put_device(dev);
  return num;
 }

 *vclock_index = kzalloc(sizeof(int) * ptp->n_vclocks, GFP_KERNEL);
 if (!(*vclock_index))
  goto out;

 memcpy(*vclock_index, ptp->vclock_index, sizeof(int) * ptp->n_vclocks);
 num = ptp->n_vclocks;
out:
 mutex_unlock(&ptp->n_vclocks_mux);
 put_device(dev);
 return num;
}
EXPORT_SYMBOL(ptp_get_vclocks_index);

ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index)
{
 unsigned int hash = vclock_index % HASH_SIZE(vclock_hash);
 struct ptp_vclock *vclock;
 u64 ns;
 u64 vclock_ns = 0;

 ns = ktime_to_ns(*hwtstamp);

 rcu_read_lock();

 hlist_for_each_entry_rcu(vclock, &vclock_hash[hash], vclock_hash_node) {
  if (vclock->clock->index != vclock_index)
   continue;

  if (mutex_lock_interruptible(&vclock->lock))
   break;
  vclock_ns = timecounter_cyc2time(&vclock->tc, ns);
  mutex_unlock(&vclock->lock);
  break;
 }

 rcu_read_unlock();

 return ns_to_ktime(vclock_ns);
}
EXPORT_SYMBOL(ptp_convert_timestamp);
#endif

Messung V0.5
C=95 H=96 G=95

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge