ptp: Support for multiple filtered timestamp event queue readers
Subsystems (5)
v5 cover ptp: Support for multiple filtered timestamp event queue readers
On systems with multiple timestamp event channels, there can be scenarios where multiple userspace readers want to access the timestamping data for various purposes.
One such example is wanting to use a pps out for time synchronization, and wanting to timestamp external events with the synchronized time base simultaneously.
Timestmp event consumers on the other hand, are often interested in a subset of the available timestamp channels. linuxptp ts2phc, for example, is not happy if more than one timestamping channel is active on the device it is reading from.
This patch-set introduces linked lists to support multiple timestamp event queue consumers, and timestamp event channel filters through IOCTLs, as well as a debugfs interface to do some simple verifications.
Xabier Marquiegui (6):
posix-clock: introduce posix_clock_context concept
ptp: Replace timestamp event queue with linked list
ptp: support multiple timestamp event readers
ptp: support event queue reader channel masks
ptp: add debugfs interface to see applied channel masks
ptp: add testptp mask test
drivers/ptp/ptp_chardev.c | 129 ++++++++++++++++---- drivers/ptp/ptp_clock.c | 45 ++++++- drivers/ptp/ptp_private.h | 28 +++-- drivers/ptp/ptp_sysfs.c | 13 +- include/linux/posix-clock.h | 22 ++-- include/uapi/linux/ptp_clock.h | 2 + kernel/time/posix-clock.c | 36 ++++-- tools/testing/selftests/ptp/ptpchmaskfmt.sh | 14 +++ tools/testing/selftests/ptp/testptp.c | 19 ++- 9 files changed, 248 insertions(+), 60 deletions(-) create mode 100644 tools/testing/selftests/ptp/ptpchmaskfmt.sh
---
v5:
- fix spelling on commit message
- fix memory leak on ptp_open
v4: https://lore.kernel.org/netdev/[email protected]/
- split modifications in different patches for improved organization
- rename posix_clock_user to posix_clock_context
- remove unnecessary flush_users clock operation
- remove unnecessary tests
- simpler queue clean procedure
- fix/clean comment lines
- simplified release procedures
- filter modifications exclusive to currently open instance for simplicity and security
- expand mask to 2048 channels
- make more secure and simple: mask is only applied to the testptp instance. Use debugfs to verify effects.
v3: https://lore.kernel.org/netdev/[email protected]/
- add this patchset overview file
- fix use of safe and non safe linked lists for loops
- introduce new posix_clock private_data and ida object ids for better dicrimination of timestamp consumers
- safer resource release procedures
- filter application by object id, aided by process id
- friendlier testptp implementation of event queue channel filters
v2: https://lore.kernel.org/netdev/[email protected]/
- fix ptp_poll() return value
- Style changes to comform to checkpatch strict suggestions
- more coherent ptp_read error exit routines
- fix testptp compilation error: unknown type name 'pid_t'
- rename mask variable for easier code traceability
- more detailed commit message with two examples
v1: https://lore.kernel.org/netdev/[email protected]/
---
PATCH v5 1/6 posix-clock: introduce posix_clock_context concept
Add the necessary structure to support custom private-data per posix-clock user.
The previous implementation of posix-clock assumed all file open instances need access to the same clock structure on private_data.
The need for individual data structures per file open instance has been identified when developing support for multiple timestamp event queue users for ptp_clock.
This patch introduces a generic posix_clock_context data structure as a solution to that, and similar problems.
---
v3:
- fix spelling on commit message
v2: https://lore.kernel.org/netdev/35e1e4f96e8ad58b4ee6a7fd46424f4cd6294353.1696511486.git.reibax@gmail.com/
- split from previous patch that combined more changes
- rename posix_clock_user to posix_clock_context
- remove unnecessary flush_users clock operation
- remove unnecessary tests
v1: https://lore.kernel.org/netdev/[email protected]/
--- drivers/ptp/ptp_chardev.c | 21 +++++++++++++-------- drivers/ptp/ptp_private.h | 16 +++++++++------- include/linux/posix-clock.h | 22 ++++++++++++++-------- kernel/time/posix-clock.c | 36 +++++++++++++++++++++++++++--------- 4 files changed, 63 insertions(+), 32 deletions(-)
drivers/ptp/ptp_chardev.c +13 -8
@@ -101,14 +101,16 @@ int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin,return 0 ; } -int ptp_open (struct posix_clock *pc,fmode_t fmode) +int ptp_open (struct posix_clock_context *pccontext,fmode_t fmode) {return 0 ; } -long ptp_ioctl (struct posix_clock *pc,unsigned int cmd,unsigned long arg) +long ptp_ioctl (struct posix_clock_context *pccontext,unsigned int cmd, +unsigned long arg) { - struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); +struct ptp_clock *ptp = + container_of(pccontext->clk, struct ptp_clock, clock);struct ptp_sys_offset_extended *extoff =NULL ;struct ptp_sys_offset_precise precise_offset;struct system_device_crosststamp xtstamp;
@@ -432,9 +434,11 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)return err; } -__poll_t ptp_poll (struct posix_clock *pc,struct file *fp,poll_table *wait) +__poll_t ptp_poll (struct posix_clock_context *pccontext,struct file *fp, +poll_table *wait) { - struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); +struct ptp_clock *ptp = + container_of(pccontext->clk, struct ptp_clock, clock);poll_wait (fp, &ptp->tsev_wq, wait);
@@ -443,10 +447,11 @@ __poll_t ptp_poll(struct posix_clock *pc, struct file *fp, poll_table *wait)#define EXTTS_BUFSIZE (PTP_BUF_TIMESTAMPS * sizeof(struct ptp_extts_event)) -ssize_t ptp_read (struct posix_clock *pc, -uint rdflags,char __user *buf,size_t cnt) +ssize_t ptp_read (struct posix_clock_context *pccontext,uint rdflags, +char __user *buf,size_t cnt) { - struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); +struct ptp_clock *ptp = + container_of(pccontext->clk, struct ptp_clock, clock);struct timestamp_event_queue *queue = &ptp->tsevq;struct ptp_extts_event *event;unsigned long flags;
drivers/ptp/ptp_private.h +9 -7
@@ -117,16 +117,18 @@ extern struct class *ptp_class;int ptp_set_pinfunc (struct ptp_clock *ptp,unsigned int pin,enum ptp_pin_function func,unsigned int chan); -long ptp_ioctl (struct posix_clock *pc, -unsigned int cmd,unsigned long arg); +long ptp_ioctl (struct posix_clock_context *pccontext,unsigned int cmd, +unsigned long arg); -int ptp_open (struct posix_clock *pc,fmode_t fmode); +int ptp_open (struct posix_clock_context *pccontext,fmode_t fmode); -ssize_t ptp_read (struct posix_clock *pc, -uint flags,char __user *buf,size_t cnt); +int ptp_release (struct posix_clock_context *pccontext); -__poll_t ptp_poll (struct posix_clock *pc, -struct file *fp,poll_table *wait); +ssize_t ptp_read (struct posix_clock_context *pccontext,uint flags,char __user *buf, +size_t cnt); + +__poll_t ptp_poll (struct posix_clock_context *pccontext,struct file *fp, +poll_table *wait);/* * see ptp_sysfs.c
include/linux/posix-clock.h +14 -8
@@ -14,6 +14,7 @@#include <linux/rwsem.h> struct posix_clock ; +struct posix_clock_context ;/** * struct posix_clock_operations - functional interface to the clock
@@ -50,18 +51,18 @@ struct posix_clock_operations {/* * Optional character device methods: */ -long (*ioctl) (struct posix_clock *pc, -unsigned int cmd,unsigned long arg); +long (*ioctl)(struct posix_clock_context *pccontext,unsigned int cmd, +unsigned long arg); -int (*open) (struct posix_clock *pc,fmode_t f_mode); +int (*open)(struct posix_clock_context *pccontext,fmode_t f_mode); -__poll_t (*poll) (struct posix_clock *pc, -struct file *file,poll_table *wait); +__poll_t (*poll)(struct posix_clock_context *pccontext,struct file *file, +poll_table *wait); -int (*release) (struct posix_clock *pc); +int (*release)(struct posix_clock_context *pccontext); -ssize_t (*read) (struct posix_clock *pc, -uint flags,char __user *buf,size_t cnt); +ssize_t (*read)(struct posix_clock_context *pccontext,uint flags, +char __user *buf,size_t cnt); };/**
@@ -90,6 +91,11 @@ struct posix_clock {bool zombie; }; +struct posix_clock_context { +struct posix_clock *clk; +void *private_clkdata; +}; +/** * posix_clock_register() - register a new clock * @clk: Pointer to the clock. Caller must provide 'ops' field
kernel/time/posix-clock.c +27 -9
@@ -19,7 +19,8 @@*/ static struct posix_clock *get_posix_clock (struct file *fp) { -struct posix_clock *clk = fp->private_data; +struct posix_clock_context *pccontext = fp->private_data; +struct posix_clock *clk = pccontext->clk;down_read (&clk->rwsem);
@@ -39,6 +40,7 @@ static void put_posix_clock(struct posix_clock *clk)static ssize_t posix_clock_read (struct file *fp,char __user *buf,size_t count,loff_t *ppos) { +struct posix_clock_context *pccontext = fp->private_data;struct posix_clock *clk =get_posix_clock (fp);int err = -EINVAL ;
@@ -46,7 +48,7 @@ static ssize_t posix_clock_read(struct file *fp, char __user *buf,return -ENODEV ;if (clk->ops.read) - err = clk->ops.read (clk, fp->f_flags, buf, count); + err = clk->ops.read (pccontext, fp->f_flags, buf, count);put_posix_clock (clk);
@@ -55,6 +57,7 @@ static ssize_t posix_clock_read(struct file *fp, char __user *buf,static __poll_t posix_clock_poll (struct file *fp,poll_table *wait) { +struct posix_clock_context *pccontext = fp->private_data;struct posix_clock *clk =get_posix_clock (fp);__poll_t result =0 ;
@@ -62,7 +65,7 @@ static __poll_t posix_clock_poll(struct file *fp, poll_table *wait)return EPOLLERR ;if (clk->ops.poll) - result = clk->ops.poll (clk, fp, wait); + result = clk->ops.poll (pccontext, fp, wait);put_posix_clock (clk);
@@ -72,6 +75,7 @@ static __poll_t posix_clock_poll(struct file *fp, poll_table *wait)static long posix_clock_ioctl (struct file *fp,unsigned int cmd,unsigned long arg) { +struct posix_clock_context *pccontext = fp->private_data;struct posix_clock *clk =get_posix_clock (fp);int err = -ENOTTY ;
@@ -79,7 +83,7 @@ static long posix_clock_ioctl(struct file *fp,return -ENODEV ;if (clk->ops.ioctl) - err = clk->ops.ioctl (clk, cmd, arg); + err = clk->ops.ioctl (pccontext, cmd, arg);put_posix_clock (clk);
@@ -90,6 +94,7 @@ static long posix_clock_ioctl(struct file *fp,static long posix_clock_compat_ioctl (struct file *fp,unsigned int cmd,unsigned long arg) { +struct posix_clock_context *pccontext = fp->private_data;struct posix_clock *clk =get_posix_clock (fp);int err = -ENOTTY ;
@@ -97,7 +102,7 @@ static long posix_clock_compat_ioctl(struct file *fp,return -ENODEV ;if (clk->ops.ioctl) - err = clk->ops.ioctl (clk, cmd, arg); + err = clk->ops.ioctl (pccontext, cmd, arg);put_posix_clock (clk);
@@ -110,6 +115,7 @@ static int posix_clock_open(struct inode *inode, struct file *fp)int err;struct posix_clock *clk = container_of(inode->i_cdev, struct posix_clock, cdev); +struct posix_clock_context *pccontext;down_read (&clk->rwsem);
@@ -117,14 +123,20 @@ static int posix_clock_open(struct inode *inode, struct file *fp) err = -ENODEV ; goto out; } + pccontext =kzalloc (sizeof (*pccontext),GFP_KERNEL ); +if (!pccontext) { + err = -ENOMEM ; + goto out; + } + pccontext->clk = clk; + fp->private_data = pccontext;if (clk->ops.open) - err = clk->ops.open (clk, fp->f_mode); + err = clk->ops.open (pccontext, fp->f_mode);else err =0 ;if (!err) {get_device (clk->dev); - fp->private_data = clk; } out:up_read (&clk->rwsem);
@@ -133,14 +145,20 @@ static int posix_clock_open(struct inode *inode, struct file *fp)static int posix_clock_release (struct inode *inode,struct file *fp) { -struct posix_clock *clk = fp->private_data; +struct posix_clock_context *pccontext = fp->private_data; +struct posix_clock *clk;int err =0 ; +if (!pccontext) +return -ENODEV ; + clk = pccontext->clk; +if (clk->ops.release) - err = clk->ops.release (clk); + err = clk->ops.release (pccontext);put_device (clk->dev); +kfree (pccontext); fp->private_data =NULL ;return err;
Signature · 1 line
2.30.2
Richard Cochran
maintainerRe: [PATCH net-next v5 1/6] posix-clock: introduce posix_clock_context concept
drivers/ptp/ptp_chardev.c int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin, · line 107
Quoted 5 lines · Xabier Marquiegui
drivers/ptp/ptp_chardev.c +1
-1-int ptp_open (struct posix_clock *pc,fmode_t fmode) +int ptp_open (struct posix_clock_context *pccontext,fmode_t fmode) {return 0 ; }
You are changing the functional interface, as needed, but I wonder whether drivers/ptp/ptp_chardev.c is the only driver that implements open/read/ioctl.
Did you audit the callers of posix_clock_register(), or maybe do a make allyesconfig ?
Thanks,
Richard
Re: [PATCH net-next v5 1/6] posix-clock: introduce posix_clock_context concept
Quoted 6 lines · Richard Cochran
You are changing the functional interface, as needed, but I wonder whether
drivers/ptp/ptp_chardev.cis the only driver that implements open/read/ioctl.Did you audit the callers of
posix_clock_register(), or maybe do amake allyesconfig?
Yes, I have been searching for other drivers using that call, but I haven't found any. I have also run compilations with allyesconfig in a couple of build machines, and have seen no errors thrown by the compiler.
Re: [PATCH net-next v5 1/6] posix-clock: introduce posix_clock_context concept
In reply to Xabier MarquieguiQuoted 11 lines · Xabier Marquiegui
Add the necessary structure to support custom private-data per posix-clock user.
The previous implementation of posix-clock assumed all file open instances need access to the same clock structure on
private_data.The need for individual data structures per file open instance has been identified when developing support for multiple timestamp event queue users for
ptp_clock.This patch introduces a generic
posix_clock_contextdata structure as a
"This patch .."
We already know that this is a patch.
https://www.kernel.org/doc/html/latest/process/submitting-patches.html#describe-your-changes
include/linux/posix-clock.h struct posix_clock { · line 97
Quoted 5 lines
include/linux/posix-clock.h +4
-0+struct posix_clock_context { +struct posix_clock *clk; +void *private_clkdata; +};
Thanks,
tglx
PATCH v5 2/6 ptp: Replace timestamp event queue with linked list
In reply to Xabier MarquieguiIntroduce linked lists to access the timestamp event queue.
---
v4: https://lore.kernel.org/netdev/a0aaf9c5347ea05deb8153511294676bc46f63d8.1696511486.git.reibax@gmail.com/
- simpler queue clean procedure
- fix/clean comment lines
v3: https://lore.kernel.org/netdev/[email protected]/
- fix use of safe and non safe linked lists for loops
v2: https://lore.kernel.org/netdev/[email protected]/
- Style changes to comform to checkpatch strict suggestions
v1: https://lore.kernel.org/netdev/[email protected]/
--- drivers/ptp/ptp_chardev.c | 12 ++++++++++-- drivers/ptp/ptp_clock.c | 26 ++++++++++++++++++++++++-- drivers/ptp/ptp_private.h | 4 +++- drivers/ptp/ptp_sysfs.c | 6 +++++- 4 files changed, 42 insertions(+), 6 deletions(-)
drivers/ptp/ptp_chardev.c +10 -2
@@ -439,10 +439,14 @@ __poll_t ptp_poll(struct posix_clock_context *pccontext, struct file *fp, {struct ptp_clock *ptp = container_of(pccontext->clk, struct ptp_clock, clock); +struct timestamp_event_queue *queue;poll_wait (fp, &ptp->tsev_wq, wait); -return queue_cnt (&ptp->tsevq) ?EPOLLIN :0 ; +/* Extract only the first element in the queue list */ + queue = list_first_entry(&ptp->tsevqs, struct timestamp_event_queue, qlist); + +return queue_cnt (queue) ?EPOLLIN :0 ; }#define EXTTS_BUFSIZE (PTP_BUF_TIMESTAMPS * sizeof(struct ptp_extts_event))
@@ -452,12 +456,16 @@ ssize_t ptp_read(struct posix_clock_context *pccontext, uint rdflags, {struct ptp_clock *ptp = container_of(pccontext->clk, struct ptp_clock, clock); -struct timestamp_event_queue *queue = &ptp->tsevq; +struct timestamp_event_queue *queue;struct ptp_extts_event *event;unsigned long flags;size_t qcnt, i;int result; +/* Extract only the first element in the queue list */ + queue = list_first_entry(&ptp->tsevqs, struct timestamp_event_queue, + qlist); +if (cnt %sizeof (struct ptp_extts_event ) !=0 )return -EINVAL ;
drivers/ptp/ptp_clock.c +24 -2
@@ -169,12 +169,21 @@ static struct posix_clock_operations ptp_clock_ops = {static void ptp_clock_release (struct device *dev) { struct ptp_clock *ptp = container_of(dev, struct ptp_clock, dev); +struct timestamp_event_queue *tsevq; +unsigned long flags;ptp_cleanup_pin_groups (ptp);kfree (ptp->vclock_index);mutex_destroy (&ptp->tsevq_mux);mutex_destroy (&ptp->pincfg_mux);mutex_destroy (&ptp->n_vclocks_mux); +/* Delete first entry */ + tsevq = list_first_entry(&ptp->tsevqs, struct timestamp_event_queue, + qlist); +spin_lock_irqsave (&tsevq->lock, flags); +list_del (&tsevq->qlist); +spin_unlock_irqrestore (&tsevq->lock, flags); +kfree (tsevq);ida_free (&ptp_clocks_map, ptp->index);kfree (ptp); }
@@ -206,6 +215,7 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, struct device *parent) {struct ptp_clock *ptp; +struct timestamp_event_queue *queue =NULL ;int err =0 , index, major =MAJOR (ptp_devt);size_t size;
@@ -228,7 +238,12 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, ptp->info = info; ptp->devid =MKDEV (major, index); ptp->index = index; -spin_lock_init (&ptp->tsevq.lock); +INIT_LIST_HEAD (&ptp->tsevqs); + queue =kzalloc (sizeof (*queue),GFP_KERNEL ); +if (!queue) + goto no_memory_queue; +spin_lock_init (&queue->lock); +list_add_tail (&queue->qlist, &ptp->tsevqs);mutex_init (&ptp->tsevq_mux);mutex_init (&ptp->pincfg_mux);mutex_init (&ptp->n_vclocks_mux);
@@ -333,6 +348,9 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,mutex_destroy (&ptp->tsevq_mux);mutex_destroy (&ptp->pincfg_mux);mutex_destroy (&ptp->n_vclocks_mux); +list_del (&queue->qlist); +kfree (queue); +no_memory_queue:ida_free (&ptp_clocks_map, index); no_slot:kfree (ptp);
@@ -375,6 +393,7 @@ EXPORT_SYMBOL(ptp_clock_unregister);void ptp_clock_event (struct ptp_clock *ptp,struct ptp_clock_event *event) { +struct timestamp_event_queue *tsevq;struct pps_event_time evt;switch (event->type) {
@@ -383,7 +402,10 @@ void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event)break ;case PTP_CLOCK_EXTTS : -enqueue_external_timestamp (&ptp->tsevq, event); +/* Enqueue timestamp on all queues */ +list_for_each_entry (tsevq, &ptp->tsevqs, qlist) { +enqueue_external_timestamp (tsevq, event); + }wake_up_interruptible (&ptp->tsev_wq);break ;
drivers/ptp/ptp_private.h +3 -1
@@ -15,6 +15,7 @@#include <linux/ptp_clock.h> #include <linux/ptp_clock_kernel.h> #include <linux/time.h> +#include <linux/list.h> #define PTP_MAX_TIMESTAMPS 128#define PTP_BUF_TIMESTAMPS 30
@@ -25,6 +26,7 @@ struct timestamp_event_queue {int head;int tail;spinlock_t lock; +struct list_head qlist; };struct ptp_clock {
@@ -35,7 +37,7 @@ struct ptp_clock {int index;/* index into clocks.map */ struct pps_device *pps_source;long dialed_frequency;/* remembers the frequency adjustment */ -struct timestamp_event_queue tsevq;/* simple fifo for time stamps */ +struct list_head tsevqs;/* timestamp fifo list */ struct mutex tsevq_mux;/* one process at a time reading the fifo */ struct mutex pincfg_mux;/* protect concurrent info->pin_config access */ wait_queue_head_t tsev_wq;
drivers/ptp/ptp_sysfs.c +5 -1
@@ -75,12 +75,16 @@ static ssize_t extts_fifo_show(struct device *dev, struct device_attribute *attr, char *page) { struct ptp_clock *ptp = dev_get_drvdata(dev); -struct timestamp_event_queue *queue = &ptp->tsevq; +struct timestamp_event_queue *queue;struct ptp_extts_event event;unsigned long flags;size_t qcnt;int cnt =0 ; +/* The sysfs fifo will always draw from the fist queue */ + queue = list_first_entry(&ptp->tsevqs, struct timestamp_event_queue, + qlist); +memset (&event,0 ,sizeof (event));if (mutex_lock_interruptible (&ptp->tsevq_mux))
Signature · 1 line
2.30.2
PATCH v5 3/6 ptp: support multiple timestamp event readers
In reply to Xabier MarquieguiUse linked lists to create one event queue per open file. This enables simultaneous readers for timestamp event queues.
---
v4: https://lore.kernel.org/netdev/32cf9345e1f06f62ad36b54bdd107baea7b079b6.1696511486.git.reibax@gmail.com/
- split modifications in different patches for improved organization
- simplified release procedures
- remove unnecessary checks
v3: https://lore.kernel.org/netdev/[email protected]/
- fix use of safe and non safe linked lists for loops
- introduce new posix_clock private_data and ida object ids for better
dicrimination of timestamp consumers
- safer resource release procedures
v2: https://lore.kernel.org/netdev/[email protected]/
- fix ptp_poll() return value
- Style changes to comform to checkpatch strict suggestions
- more coherent ptp_read error exit routines
v1: https://lore.kernel.org/netdev/[email protected]/
--- drivers/ptp/ptp_chardev.c | 68 ++++++++++++++++++++++++++++----------- drivers/ptp/ptp_clock.c | 6 ++-- drivers/ptp/ptp_private.h | 1 - drivers/ptp/ptp_sysfs.c | 9 +++--- 4 files changed, 55 insertions(+), 29 deletions(-)
drivers/ptp/ptp_chardev.c +49 -19
@@ -103,6 +103,31 @@ int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin,int ptp_open (struct posix_clock_context *pccontext,fmode_t fmode) { +struct ptp_clock *ptp = + container_of(pccontext->clk, struct ptp_clock, clock); +struct timestamp_event_queue *queue; + + queue =kzalloc (sizeof (*queue),GFP_KERNEL ); +if (!queue) +return -EINVAL ; +spin_lock_init (&queue->lock); +list_add_tail (&queue->qlist, &ptp->tsevqs); + pccontext->private_clkdata = queue; +return 0 ; +} + +int ptp_release (struct posix_clock_context *pccontext) +{ +struct timestamp_event_queue *queue = pccontext->private_clkdata; +unsigned long flags; + +if (queue) { + pccontext->private_clkdata =NULL ; +spin_lock_irqsave (&queue->lock, flags); +list_del (&queue->qlist); +spin_unlock_irqrestore (&queue->lock, flags); +kfree (queue); + }return 0 ; }
@@ -441,10 +466,11 @@ __poll_t ptp_poll(struct posix_clock_context *pccontext, struct file *fp, container_of(pccontext->clk, struct ptp_clock, clock);struct timestamp_event_queue *queue; -poll_wait (fp, &ptp->tsev_wq, wait); + queue = pccontext->private_clkdata; +if (!queue) +return EPOLLERR ; -/* Extract only the first element in the queue list */ - queue = list_first_entry(&ptp->tsevqs, struct timestamp_event_queue, qlist); +poll_wait (fp, &ptp->tsev_wq, wait);return queue_cnt (queue) ?EPOLLIN :0 ; }
@@ -462,36 +488,36 @@ ssize_t ptp_read(struct posix_clock_context *pccontext, uint rdflags,size_t qcnt, i;int result; -/* Extract only the first element in the queue list */ - queue = list_first_entry(&ptp->tsevqs, struct timestamp_event_queue, - qlist); + queue = pccontext->private_clkdata; +if (!queue) { + result = -EINVAL ; + goto exit; + } -if (cnt %sizeof (struct ptp_extts_event ) !=0 ) -return -EINVAL ; +if (cnt %sizeof (struct ptp_extts_event ) !=0 ) { + result = -EINVAL ; + goto exit; + }if (cnt >EXTTS_BUFSIZE ) cnt =EXTTS_BUFSIZE ; cnt = cnt /sizeof (struct ptp_extts_event ); -if (mutex_lock_interruptible (&ptp->tsevq_mux)) -return -ERESTARTSYS ; -if (wait_event_interruptible (ptp->tsev_wq, ptp->defunct ||queue_cnt (queue))) { -mutex_unlock (&ptp->tsevq_mux);return -ERESTARTSYS ; }if (ptp->defunct) { -mutex_unlock (&ptp->tsevq_mux); -return -ENODEV ; + result = -ENODEV ; + goto exit; } event =kmalloc (EXTTS_BUFSIZE ,GFP_KERNEL );if (!event) { -mutex_unlock (&ptp->tsevq_mux); -return -ENOMEM ; + result = -ENOMEM ; + goto exit; }spin_lock_irqsave (&queue->lock, flags);
@@ -510,12 +536,16 @@ ssize_t ptp_read(struct posix_clock_context *pccontext, uint rdflags, cnt = cnt *sizeof (struct ptp_extts_event ); -mutex_unlock (&ptp->tsevq_mux); - result = cnt; -if (copy_to_user (buf, event, cnt)) +if (copy_to_user (buf, event, cnt)) { result = -EFAULT ; + goto free_event; + } +free_event:kfree (event); +exit: +if (result <0 ) +ptp_release (pccontext);return result; }
drivers/ptp/ptp_clock.c +2 -4
@@ -162,6 +162,7 @@ static struct posix_clock_operations ptp_clock_ops = { .clock_settime = ptp_clock_settime, .ioctl = ptp_ioctl, .open = ptp_open, + .release = ptp_release, .poll = ptp_poll, .read = ptp_read, };
@@ -174,7 +175,6 @@ static void ptp_clock_release(struct device *dev)ptp_cleanup_pin_groups (ptp);kfree (ptp->vclock_index); -mutex_destroy (&ptp->tsevq_mux);mutex_destroy (&ptp->pincfg_mux);mutex_destroy (&ptp->n_vclocks_mux);/* Delete first entry */
@@ -242,9 +242,8 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, queue =kzalloc (sizeof (*queue),GFP_KERNEL );if (!queue) goto no_memory_queue; -spin_lock_init (&queue->lock);list_add_tail (&queue->qlist, &ptp->tsevqs); -mutex_init (&ptp->tsevq_mux); +spin_lock_init (&queue->lock);mutex_init (&ptp->pincfg_mux);mutex_init (&ptp->n_vclocks_mux);init_waitqueue_head (&ptp->tsev_wq);
@@ -345,7 +344,6 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,if (ptp->kworker)kthread_destroy_worker (ptp->kworker); kworker_err: -mutex_destroy (&ptp->tsevq_mux);mutex_destroy (&ptp->pincfg_mux);mutex_destroy (&ptp->n_vclocks_mux);list_del (&queue->qlist);
drivers/ptp/ptp_private.h +0 -1
@@ -38,7 +38,6 @@ struct ptp_clock {struct pps_device *pps_source;long dialed_frequency;/* remembers the frequency adjustment */ struct list_head tsevqs;/* timestamp fifo list */ -struct mutex tsevq_mux;/* one process at a time reading the fifo */ struct mutex pincfg_mux;/* protect concurrent info->pin_config access */ wait_queue_head_t tsev_wq;int defunct;/* tells readers to go away when clock is being removed */
drivers/ptp/ptp_sysfs.c +4 -5
@@ -81,15 +81,15 @@ static ssize_t extts_fifo_show(struct device *dev,size_t qcnt;int cnt =0 ; + cnt =list_count_nodes (&ptp->tsevqs); +if (cnt <=0 ) + goto out; +/* The sysfs fifo will always draw from the fist queue */ queue = list_first_entry(&ptp->tsevqs, struct timestamp_event_queue, qlist);memset (&event,0 ,sizeof (event)); - -if (mutex_lock_interruptible (&ptp->tsevq_mux)) -return -ERESTARTSYS ; -spin_lock_irqsave (&queue->lock, flags); qcnt =queue_cnt (queue);if (qcnt) {
@@ -104,7 +104,6 @@ static ssize_t extts_fifo_show(struct device *dev, cnt =snprintf (page,PAGE_SIZE ,"%u %lld %u\n" , event.index, event.t.sec, event.t.nsec); out: -mutex_unlock (&ptp->tsevq_mux);return cnt; } static DEVICE_ATTR(fifo, 0444, extts_fifo_show, NULL);
Signature · 1 line
2.30.2
PATCH v5 4/6 ptp: support event queue reader channel masks
In reply to Xabier MarquieguiOn systems with multiple timestamp event channels, some readers might want to receive only a subset of those channels.
This patch adds the necessary modifications to support timestamp event channel filtering, including two IOCTL operations:
- Clear all channels
- Enable one channel
The mask modification operations will be applied exclusively on the event queue assigned to the file descriptor used on the IOCTL operation, so the typical procedure to have a reader receiving only a subset of the enabled channels would be:
- Open device file
- ioctl: clear all channels
- ioctl: enable one channel
- start reading
Calling the enable one channel ioctl more than once will result in multiple enabled channels.
---
v5:
- fix memory leak on ptp_open
v4: https://lore.kernel.org/netdev/5525d56c5feff9b28c6caa93e03d8f198d7412ce.1696511486.git.reibax@gmail.com/
- split modifications in different patches for improved organization
- filter modifications exclusive to currently open instance for
simplicity and security
- expand mask to 2048 channels
- remove unnecessary tests
v3: https://lore.kernel.org/netdev/[email protected]/
- filter application by object id, aided by process id
- friendlier testptp implementation of event queue channel filters
v2: https://lore.kernel.org/netdev/[email protected]/
- fix testptp compilation error: unknown type name 'pid_t'
- rename mask variable for easier code traceability
- more detailed commit message with two examples
v1: https://lore.kernel.org/netdev/[email protected]/
--- drivers/ptp/ptp_chardev.c | 26 ++++++++++++++++++++++++++ drivers/ptp/ptp_clock.c | 12 ++++++++++-- drivers/ptp/ptp_private.h | 3 +++ include/uapi/linux/ptp_clock.h | 2 ++ 4 files changed, 41 insertions(+), 2 deletions(-)
drivers/ptp/ptp_chardev.c +26 -0
@@ -110,6 +110,12 @@ int ptp_open(struct posix_clock_context *pccontext, fmode_t fmode) queue =kzalloc (sizeof (*queue),GFP_KERNEL );if (!queue)return -EINVAL ; + queue->mask =bitmap_alloc (PTP_MAX_CHANNELS ,GFP_KERNEL ); +if (!queue->mask) { +kfree (queue); +return -EINVAL ; + } +bitmap_set (queue->mask,0 ,PTP_MAX_CHANNELS );spin_lock_init (&queue->lock);list_add_tail (&queue->qlist, &ptp->tsevqs); pccontext->private_clkdata = queue;
@@ -126,6 +132,7 @@ int ptp_release(struct posix_clock_context *pccontext)spin_lock_irqsave (&queue->lock, flags);list_del (&queue->qlist);spin_unlock_irqrestore (&queue->lock, flags); +bitmap_free (queue->mask);kfree (queue); }return 0 ;
@@ -141,6 +148,7 @@ long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd,struct system_device_crosststamp xtstamp;struct ptp_clock_info *ops = ptp->info;struct ptp_sys_offset *sysoff =NULL ; +struct timestamp_event_queue *tsevq;struct ptp_system_timestamp sts;struct ptp_clock_request req;struct ptp_clock_caps caps;
@@ -150,6 +158,8 @@ long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd,struct timespec64 ts;int enable, err =0 ; + tsevq = pccontext->private_clkdata; +switch (cmd) {case PTP_CLOCK_GETCAPS :
@@ -448,6 +458,22 @@ long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd,mutex_unlock (&ptp->pincfg_mux);break ; +case PTP_MASK_CLEAR_ALL : +bitmap_clear (tsevq->mask,0 ,PTP_MAX_CHANNELS ); +break ; + +case PTP_MASK_EN_SINGLE : +if (copy_from_user (&i, (void __user *)arg,sizeof (i))) { + err = -EFAULT ; +break ; + } +if (i >=PTP_MAX_CHANNELS ) { + err = -EFAULT ; +break ; + } +set_bit (i, tsevq->mask); +break ; +default : err = -ENOTTY ;break ;
drivers/ptp/ptp_clock.c +10 -2
@@ -183,6 +183,7 @@ static void ptp_clock_release(struct device *dev)spin_lock_irqsave (&tsevq->lock, flags);list_del (&tsevq->qlist);spin_unlock_irqrestore (&tsevq->lock, flags); +bitmap_free (tsevq->mask);kfree (tsevq);ida_free (&ptp_clocks_map, ptp->index);kfree (ptp);
@@ -243,6 +244,10 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,if (!queue) goto no_memory_queue;list_add_tail (&queue->qlist, &ptp->tsevqs); + queue->mask =bitmap_alloc (PTP_MAX_CHANNELS ,GFP_KERNEL ); +if (!queue->mask) + goto no_memory_bitmap; +bitmap_set (queue->mask,0 ,PTP_MAX_CHANNELS );spin_lock_init (&queue->lock);mutex_init (&ptp->pincfg_mux);mutex_init (&ptp->n_vclocks_mux);
@@ -346,6 +351,8 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, kworker_err:mutex_destroy (&ptp->pincfg_mux);mutex_destroy (&ptp->n_vclocks_mux); +bitmap_free (queue->mask); +no_memory_bitmap:list_del (&queue->qlist);kfree (queue); no_memory_queue:
@@ -400,9 +407,10 @@ void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event)break ;case PTP_CLOCK_EXTTS : -/* Enqueue timestamp on all queues */ +/* Enqueue timestamp on selected queues */ list_for_each_entry (tsevq, &ptp->tsevqs, qlist) { -enqueue_external_timestamp (tsevq, event); +if (test_bit ((unsigned int )event->index, tsevq->mask)) +enqueue_external_timestamp (tsevq, event); }wake_up_interruptible (&ptp->tsev_wq);break ;
drivers/ptp/ptp_private.h +3 -0
@@ -16,10 +16,12 @@#include <linux/ptp_clock_kernel.h> #include <linux/time.h> #include <linux/list.h> +#include <linux/bitmap.h> #define PTP_MAX_TIMESTAMPS 128#define PTP_BUF_TIMESTAMPS 30#define PTP_DEFAULT_MAX_VCLOCKS 20 +#define PTP_MAX_CHANNELS 2048struct timestamp_event_queue {struct ptp_extts_event buf[PTP_MAX_TIMESTAMPS ];
@@ -27,6 +29,7 @@ struct timestamp_event_queue {int tail;spinlock_t lock;struct list_head qlist; +unsigned long *mask; };struct ptp_clock {
include/uapi/linux/ptp_clock.h +2 -0
@@ -224,6 +224,8 @@ struct ptp_pin_desc { _IOWR(PTP_CLK_MAGIC, 17, struct ptp_sys_offset_precise)#define PTP_SYS_OFFSET_EXTENDED2 \ _IOWR(PTP_CLK_MAGIC, 18, struct ptp_sys_offset_extended) +#define PTP_MASK_CLEAR_ALL _IO(PTP_CLK_MAGIC, 19) +#define PTP_MASK_EN_SINGLE _IOW(PTP_CLK_MAGIC, 20, unsigned int)struct ptp_extts_event {struct ptp_clock_time t;/* Time event occured. */
Signature · 1 line
2.30.2
PATCH v5 5/6 ptp: add debugfs interface to see applied channel masks
In reply to Xabier MarquieguiUse debugfs to be able to view channel mask applied to every timestamp event queue.
Every time the device is opened, a new entry is created in $DEBUGFS_MOUNTPOINT/ptpN/$INSTANCE_ADDRESS/mask.
The mask value can be viewed grouped in 32bit decimal values using cat, or converted to hexadecimal with the included ptpchmaskfmt.sh script. 32 bit values are listed from least significant to most significant.
---
v1: https://lore.kernel.org/netdev/27d47d720dfa7a0b5a59b32626ed6d02745b6ee0.1696511486.git.reibax@gmail.com/
- First version
--- drivers/ptp/ptp_chardev.c | 14 ++++++++++++++ drivers/ptp/ptp_clock.c | 7 +++++++ drivers/ptp/ptp_private.h | 4 ++++ tools/testing/selftests/ptp/ptpchmaskfmt.sh | 14 ++++++++++++++ 4 files changed, 39 insertions(+) create mode 100644 tools/testing/selftests/ptp/ptpchmaskfmt.sh
drivers/ptp/ptp_chardev.c +14 -0
@@ -10,6 +10,7 @@#include <linux/sched.h> #include <linux/slab.h> #include <linux/timekeeping.h> +#include <linux/debugfs.h> #include <linux/nospec.h>
@@ -106,6 +107,7 @@ int ptp_open(struct posix_clock_context *pccontext, fmode_t fmode)struct ptp_clock *ptp = container_of(pccontext->clk, struct ptp_clock, clock);struct timestamp_event_queue *queue; +char debugfsname[32 ]; queue =kzalloc (sizeof (*queue),GFP_KERNEL );if (!queue)
@@ -119,6 +121,17 @@ int ptp_open(struct posix_clock_context *pccontext, fmode_t fmode)spin_lock_init (&queue->lock);list_add_tail (&queue->qlist, &ptp->tsevqs); pccontext->private_clkdata = queue; + +/* Debugfs contents */ +sprintf (debugfsname,"0x%p" , queue); + queue->debugfs_instance = +debugfs_create_dir (debugfsname, ptp->debugfs_root); + queue->dfs_bitmap.array = (u32 *)queue->mask; + queue->dfs_bitmap.n_elements = +DIV_ROUND_UP (PTP_MAX_CHANNELS ,BITS_PER_BYTE *sizeof (u32)); +debugfs_create_u32_array ("mask" ,0444 , queue->debugfs_instance, + &queue->dfs_bitmap); +return 0 ; }
@@ -128,6 +141,7 @@ int ptp_release(struct posix_clock_context *pccontext)unsigned long flags;if (queue) { +debugfs_remove (queue->debugfs_instance); pccontext->private_clkdata =NULL ;spin_lock_irqsave (&queue->lock, flags);list_del (&queue->qlist);
drivers/ptp/ptp_clock.c +7 -0
@@ -15,6 +15,7 @@#include <linux/slab.h> #include <linux/syscalls.h> #include <linux/uaccess.h> +#include <linux/debugfs.h> #include <uapi/linux/sched/types.h> #include "ptp_private.h"
@@ -185,6 +186,7 @@ static void ptp_clock_release(struct device *dev)spin_unlock_irqrestore (&tsevq->lock, flags);bitmap_free (tsevq->mask);kfree (tsevq); +debugfs_remove (ptp->debugfs_root);ida_free (&ptp_clocks_map, ptp->index);kfree (ptp); }
@@ -218,6 +220,7 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,struct ptp_clock *ptp;struct timestamp_event_queue *queue =NULL ;int err =0 , index, major =MAJOR (ptp_devt); +char debugfsname[8 ];size_t size;if (info->n_alarm >PTP_MAX_ALARMS )
@@ -339,6 +342,10 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,return ERR_PTR (err); } +/* Debugfs initialization */ +sprintf (debugfsname,"ptp%d" , ptp->index); + ptp->debugfs_root =debugfs_create_dir (debugfsname,NULL ); +return ptp; no_pps:
drivers/ptp/ptp_private.h +4 -0
@@ -17,6 +17,7 @@#include <linux/time.h> #include <linux/list.h> #include <linux/bitmap.h> +#include <linux/debugfs.h> #define PTP_MAX_TIMESTAMPS 128#define PTP_BUF_TIMESTAMPS 30
@@ -30,6 +31,8 @@ struct timestamp_event_queue {spinlock_t lock;struct list_head qlist;unsigned long *mask; +struct dentry *debugfs_instance; +struct debugfs_u32_array dfs_bitmap; };struct ptp_clock {
@@ -57,6 +60,7 @@ struct ptp_clock {struct mutex n_vclocks_mux;/* protect concurrent n_vclocks access */ bool is_virtual_clock;bool has_cycles; +struct dentry *debugfs_root; };#define info_to_vclock (d) container_of((d), struct ptp_vclock, info)
tools/testing/selftests/ptp/ptpchmaskfmt.sh new file +14 -0
@@ -0,0 +1,14 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# Simple helper script to transform ptp debugfs timestamp event queue filtering +# masks from decimal values to hexadecimal values + +# Only takes the debugfs mask file path as an argument +DEBUGFS_MASKFILE="${1}" + +#shellcheck disable=SC2013,SC2086 +for int in $(cat "$DEBUGFS_MASKFILE") ; do + printf '0x%08X ' "$int" +done +echo
Signature · 1 line
2.30.2
Jakub Kicinski
maintainerRe: [PATCH net-next v5 5/6] ptp: add debugfs interface to see applied channel masks
Quoted 3 lines · On Mon, 9 Oct 2023 00:49:20 +0200 Xabier Marquiegui wrote:
The mask value can be viewed grouped in 32bit decimal values using cat, or converted to hexadecimal with the included
ptpchmaskfmt.shscript. 32 bit values are listed from least significant to most significant.
If it's a self-test it should probably be included in the Makefile so that bots run it.
Signature · 1 line
pw-bot: cr
Re: [PATCH net-next v5 5/6] ptp: add debugfs interface to see applied channel masks
Quoted 4 lines · Jakub Kicinski
If it's a self-test it should probably be included in the
Makefileso that bots run it.Signature · 1 line
pw-bot: cr
Thank you for your input Jakub. It's actually designed as a debug tool for humans. I wasn't thinking about self-tests, and I can't really think of how that could be pulled of in this specific case. I hope that's ok. If not we can try to throw a few ideas around and see if we find a way.
Cheers.
Jakub Kicinski
maintainerRe: [PATCH net-next v5 5/6] ptp: add debugfs interface to see applied channel masks
Quoted 8 lines · On Thu, 12 Oct 2023 00:36:04 +0200 Xabier Marquiegui wrote:
Quoted 2 lines · Jakub Kicinski
If it's a self-test it should probably be included in the
Makefileso that bots run it.Thank you for your input Jakub. It's actually designed as a debug tool for humans. I wasn't thinking about self-tests, and I can't really think of how that could be pulled of in this specific case. I hope that's ok. If not we can try to throw a few ideas around and see if we find a way.
Let's not throw random non-test scripts into selftests. It adds confusion to our pitiful kernel testing story :(
The netdevsim driver which is supposed to be used for uAPI selftests now supports PHCs. Maybe we can extend it and build a proper-er test?
Whether we'd then want to move the debugfs entries onto netdevsim or leave them where you have then now is another question..
Re: [PATCH net-next v5 5/6] ptp: add debugfs interface to see applied channel masks
Quoted 5 lines · Jakub Kicinski
The netdevsim driver which is supposed to be used for uAPI selftests now supports PHCs. Maybe we can extend it and build a proper-er test?
Whether we'd then want to move the debugfs entries onto netdevsim or leave them where you have then now is another question..
That is an interesting idea. Thank you Jakub. I will start looking onto it at whatever pace my other duties allow me to give it some thought.
One challenge I anticipate encountering is that even if netdevsim has PHC support via the PTP mock implementation, we will probably have to think about how to simulate external timestamp events.
PATCH v5 6/6 ptp: add testptp mask test
In reply to Xabier MarquieguiAdd option to test timestamp event queue mask manipulation in testptp.
Option -F allows the user to specify a single channel that will be applied on the mask filter via IOCTL.
The test program will maintain the file open until user input is received.
This allows checking the effect of the IOCTL in debugfs.
eg:
Console 1:
``` Channel 12 exclusively enabled. Check on debugfs. Press any key to continue ```
Console 2:
``` 0x00000000 0x00000001 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ```
---
v2: https://lore.kernel.org/netdev/85bfc30fb60bc4e1d98fd8ea7f694c66172e9d5d.1696511486.git.reibax@gmail.com/
- split from previous patch that combined more changes
- make more secure and simple: mask is only applied to the testptp
instance. Use debugfs to verify effects.
v1: https://lore.kernel.org/netdev/[email protected]/
--- tools/testing/selftests/ptp/testptp.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)
tools/testing/selftests/ptp/testptp.c +18 -1
@@ -121,6 +121,7 @@ static void usage(char *progname)" -d name device to open\n" " -e val read 'val' external time stamp events\n" " -f val adjust the ptp clock frequency by 'val' ppb\n" +" -F chan Enable single channel mask and keep device open for debugfs verification.\n" " -g get the ptp clock time\n" " -h prints this message\n" " -i val index for event/trigger\n"
@@ -187,6 +188,7 @@ int main(int argc, char *argv[])int pps =-1 ;int seconds =0 ;int settime =0 ; +int channel =-1 ;int64_t t1, t2, tp;int64_t interval, offset;
@@ -196,7 +198,7 @@ int main(int argc, char *argv[]) progname =strrchr (argv[0 ],'/' ); progname = progname ?1 +progname : argv[0 ]; -while (EOF != (c =getopt (argc, argv,"cd:e:f:ghH:i:k:lL:n:o:p:P:sSt:T:w:x:Xz" ))) { +while (EOF != (c =getopt (argc, argv,"cd:e:f:F:ghH:i:k:lL:n:o:p:P:sSt:T:w:x:Xz" ))) {switch (c) {case 'c' : capabilities =1 ;
@@ -210,6 +212,9 @@ int main(int argc, char *argv[])case 'f' : adjfreq =atoi (optarg);break ; +case 'F' : + channel =atoi (optarg); +break ;case 'g' : gettime =1 ;break ;
@@ -604,6 +609,18 @@ int main(int argc, char *argv[])free (xts); } +if (channel >=0 ) { +if (ioctl (fd,PTP_MASK_CLEAR_ALL )) { +perror ("PTP_MASK_CLEAR_ALL" ); + }else if (ioctl (fd,PTP_MASK_EN_SINGLE , (unsigned int *)&channel)) { +perror ("PTP_MASK_EN_SINGLE" ); + }else { +printf ("Channel %d exclusively enabled. Check on debugfs.\n" , channel); +printf ("Press any key to continue\n." ); +getchar (); + } + } +close (fd);return 0 ; }
Signature · 1 line
2.30.2