2019-05-20 07:19:02 +00:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
2011-04-22 10:03:08 +00:00
|
|
|
/*
|
|
|
|
* PTP 1588 clock support - private declarations for the core module.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2010 OMICRON electronics GmbH
|
|
|
|
*/
|
|
|
|
#ifndef _PTP_PRIVATE_H_
|
|
|
|
#define _PTP_PRIVATE_H_
|
|
|
|
|
|
|
|
#include <linux/cdev.h>
|
|
|
|
#include <linux/device.h>
|
ptp: introduce ptp auxiliary worker
Many PTP drivers required to perform some asynchronous or periodic work,
like periodically handling PHC counter overflow or handle delayed timestamp
for RX/TX network packets. In most of the cases, such work is implemented
using workqueues. Unfortunately, Kernel workqueues might introduce
significant delay in work scheduling under high system load and on -RT,
which could cause misbehavior of PTP drivers due to internal counter
overflow, for example, and there is no way to tune its execution policy and
priority manuallly.
Hence, The kthread_worker can be used insted of workqueues, as it create
separte named kthread for each worker and its its execution policy and
priority can be configured using chrt tool.
This prblem was reported for two drivers TI CPSW CPTS and dp83640, so
instead of modifying each of these driver it was proposed to add PTP
auxiliary worker to the PHC subsystem.
The patch adds PTP auxiliary worker in PHC subsystem using kthread_worker
and kthread_delayed_work and introduces two new PHC subsystem APIs:
- long (*do_aux_work)(struct ptp_clock_info *ptp) callback in
ptp_clock_info structure, which driver should assign if it require to
perform asynchronous or periodic work. Driver should return the delay of
the PTP next auxiliary work scheduling time (>=0) or negative value in case
further scheduling is not required.
- int ptp_schedule_worker(struct ptp_clock *ptp, unsigned long delay) which
allows schedule PTP auxiliary work.
The name of kthread_worker thread corresponds PTP PHC device name "ptp%d".
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-07-28 22:30:02 +00:00
|
|
|
#include <linux/kthread.h>
|
2011-04-22 10:03:08 +00:00
|
|
|
#include <linux/mutex.h>
|
|
|
|
#include <linux/posix-clock.h>
|
|
|
|
#include <linux/ptp_clock.h>
|
|
|
|
#include <linux/ptp_clock_kernel.h>
|
|
|
|
#include <linux/time.h>
|
|
|
|
|
|
|
|
#define PTP_MAX_TIMESTAMPS 128
|
|
|
|
#define PTP_BUF_TIMESTAMPS 30
|
2021-06-30 08:11:53 +00:00
|
|
|
#define PTP_DEFAULT_MAX_VCLOCKS 20
|
2011-04-22 10:03:08 +00:00
|
|
|
|
|
|
|
struct timestamp_event_queue {
|
|
|
|
struct ptp_extts_event buf[PTP_MAX_TIMESTAMPS];
|
|
|
|
int head;
|
|
|
|
int tail;
|
|
|
|
spinlock_t lock;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ptp_clock {
|
|
|
|
struct posix_clock clock;
|
2019-12-27 02:26:27 +00:00
|
|
|
struct device dev;
|
2011-04-22 10:03:08 +00:00
|
|
|
struct ptp_clock_info *info;
|
|
|
|
dev_t devid;
|
|
|
|
int index; /* index into clocks.map */
|
|
|
|
struct pps_device *pps_source;
|
2012-09-22 07:02:01 +00:00
|
|
|
long dialed_frequency; /* remembers the frequency adjustment */
|
2011-04-22 10:03:08 +00:00
|
|
|
struct timestamp_event_queue tsevq; /* simple fifo for time stamps */
|
|
|
|
struct mutex tsevq_mux; /* one process at a time reading the fifo */
|
2014-03-20 21:21:52 +00:00
|
|
|
struct mutex pincfg_mux; /* protect concurrent info->pin_config access */
|
2011-04-22 10:03:08 +00:00
|
|
|
wait_queue_head_t tsev_wq;
|
|
|
|
int defunct; /* tells readers to go away when clock is being removed */
|
2014-03-20 21:21:54 +00:00
|
|
|
struct device_attribute *pin_dev_attr;
|
|
|
|
struct attribute **pin_attr;
|
|
|
|
struct attribute_group pin_attr_group;
|
2017-02-14 18:23:34 +00:00
|
|
|
/* 1st entry is a pointer to the real group, 2nd is NULL terminator */
|
|
|
|
const struct attribute_group *pin_attr_groups[2];
|
ptp: introduce ptp auxiliary worker
Many PTP drivers required to perform some asynchronous or periodic work,
like periodically handling PHC counter overflow or handle delayed timestamp
for RX/TX network packets. In most of the cases, such work is implemented
using workqueues. Unfortunately, Kernel workqueues might introduce
significant delay in work scheduling under high system load and on -RT,
which could cause misbehavior of PTP drivers due to internal counter
overflow, for example, and there is no way to tune its execution policy and
priority manuallly.
Hence, The kthread_worker can be used insted of workqueues, as it create
separte named kthread for each worker and its its execution policy and
priority can be configured using chrt tool.
This prblem was reported for two drivers TI CPSW CPTS and dp83640, so
instead of modifying each of these driver it was proposed to add PTP
auxiliary worker to the PHC subsystem.
The patch adds PTP auxiliary worker in PHC subsystem using kthread_worker
and kthread_delayed_work and introduces two new PHC subsystem APIs:
- long (*do_aux_work)(struct ptp_clock_info *ptp) callback in
ptp_clock_info structure, which driver should assign if it require to
perform asynchronous or periodic work. Driver should return the delay of
the PTP next auxiliary work scheduling time (>=0) or negative value in case
further scheduling is not required.
- int ptp_schedule_worker(struct ptp_clock *ptp, unsigned long delay) which
allows schedule PTP auxiliary work.
The name of kthread_worker thread corresponds PTP PHC device name "ptp%d".
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-07-28 22:30:02 +00:00
|
|
|
struct kthread_worker *kworker;
|
|
|
|
struct kthread_delayed_work aux_work;
|
2021-06-30 08:11:53 +00:00
|
|
|
unsigned int max_vclocks;
|
|
|
|
unsigned int n_vclocks;
|
2021-06-30 08:11:54 +00:00
|
|
|
int *vclock_index;
|
2021-06-30 08:11:53 +00:00
|
|
|
struct mutex n_vclocks_mux; /* protect concurrent n_vclocks access */
|
|
|
|
bool is_virtual_clock;
|
2022-05-06 20:01:37 +00:00
|
|
|
bool has_cycles;
|
2011-04-22 10:03:08 +00:00
|
|
|
};
|
|
|
|
|
2021-06-30 08:11:52 +00:00
|
|
|
#define info_to_vclock(d) container_of((d), struct ptp_vclock, info)
|
|
|
|
#define cc_to_vclock(d) container_of((d), struct ptp_vclock, cc)
|
|
|
|
#define dw_to_vclock(d) container_of((d), struct ptp_vclock, refresh_work)
|
|
|
|
|
|
|
|
struct ptp_vclock {
|
|
|
|
struct ptp_clock *pclock;
|
|
|
|
struct ptp_clock_info info;
|
|
|
|
struct ptp_clock *clock;
|
2022-05-06 20:01:41 +00:00
|
|
|
struct hlist_node vclock_hash_node;
|
2021-06-30 08:11:52 +00:00
|
|
|
struct cyclecounter cc;
|
|
|
|
struct timecounter tc;
|
|
|
|
spinlock_t lock; /* protects tc/cc */
|
|
|
|
};
|
|
|
|
|
2011-04-22 10:03:08 +00:00
|
|
|
/*
|
|
|
|
* The function queue_cnt() is safe for readers to call without
|
|
|
|
* holding q->lock. Readers use this function to verify that the queue
|
|
|
|
* is nonempty before proceeding with a dequeue operation. The fact
|
|
|
|
* that a writer might concurrently increment the tail does not
|
|
|
|
* matter, since the queue remains nonempty nonetheless.
|
|
|
|
*/
|
|
|
|
static inline int queue_cnt(struct timestamp_event_queue *q)
|
|
|
|
{
|
|
|
|
int cnt = q->tail - q->head;
|
|
|
|
return cnt < 0 ? PTP_MAX_TIMESTAMPS + cnt : cnt;
|
|
|
|
}
|
|
|
|
|
2021-06-30 08:11:53 +00:00
|
|
|
/* Check if ptp virtual clock is in use */
|
|
|
|
static inline bool ptp_vclock_in_use(struct ptp_clock *ptp)
|
|
|
|
{
|
|
|
|
bool in_use = false;
|
|
|
|
|
|
|
|
if (mutex_lock_interruptible(&ptp->n_vclocks_mux))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!ptp->is_virtual_clock && ptp->n_vclocks)
|
|
|
|
in_use = true;
|
|
|
|
|
|
|
|
mutex_unlock(&ptp->n_vclocks_mux);
|
|
|
|
|
|
|
|
return in_use;
|
|
|
|
}
|
|
|
|
|
2022-05-06 20:01:37 +00:00
|
|
|
/* Check if ptp clock shall be free running */
|
|
|
|
static inline bool ptp_clock_freerun(struct ptp_clock *ptp)
|
|
|
|
{
|
|
|
|
if (ptp->has_cycles)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return ptp_vclock_in_use(ptp);
|
|
|
|
}
|
|
|
|
|
2021-06-30 08:11:55 +00:00
|
|
|
extern struct class *ptp_class;
|
|
|
|
|
2011-04-22 10:03:08 +00:00
|
|
|
/*
|
|
|
|
* see ptp_chardev.c
|
|
|
|
*/
|
|
|
|
|
2014-03-20 21:21:52 +00:00
|
|
|
/* caller must hold pincfg_mux */
|
|
|
|
int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin,
|
|
|
|
enum ptp_pin_function func, unsigned int chan);
|
|
|
|
|
2011-04-22 10:03:08 +00:00
|
|
|
long ptp_ioctl(struct posix_clock *pc,
|
|
|
|
unsigned int cmd, unsigned long arg);
|
|
|
|
|
|
|
|
int ptp_open(struct posix_clock *pc, fmode_t fmode);
|
|
|
|
|
|
|
|
ssize_t ptp_read(struct posix_clock *pc,
|
|
|
|
uint flags, char __user *buf, size_t cnt);
|
|
|
|
|
2017-07-03 10:39:46 +00:00
|
|
|
__poll_t ptp_poll(struct posix_clock *pc,
|
2011-04-22 10:03:08 +00:00
|
|
|
struct file *fp, poll_table *wait);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* see ptp_sysfs.c
|
|
|
|
*/
|
|
|
|
|
2013-07-24 22:05:20 +00:00
|
|
|
extern const struct attribute_group *ptp_groups[];
|
2011-04-22 10:03:08 +00:00
|
|
|
|
2017-02-14 18:23:34 +00:00
|
|
|
int ptp_populate_pin_groups(struct ptp_clock *ptp);
|
|
|
|
void ptp_cleanup_pin_groups(struct ptp_clock *ptp);
|
2011-04-22 10:03:08 +00:00
|
|
|
|
2021-06-30 08:11:52 +00:00
|
|
|
struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock);
|
|
|
|
void ptp_vclock_unregister(struct ptp_vclock *vclock);
|
2011-04-22 10:03:08 +00:00
|
|
|
#endif
|