Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ptp: support event queue reader channel masks

On systems with multiple timestamp event channels, some readers might
want to receive only a subset of those channels.

Add 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.

Signed-off-by: Xabier Marquiegui <reibax@gmail.com>
Suggested-by: Richard Cochran <richardcochran@gmail.com>
Suggested-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Xabier Marquiegui and committed by
David S. Miller
c5a445b1 8f5de6fb

+41 -2
+26
drivers/ptp/ptp_chardev.c
··· 110 110 queue = kzalloc(sizeof(*queue), GFP_KERNEL); 111 111 if (!queue) 112 112 return -EINVAL; 113 + queue->mask = bitmap_alloc(PTP_MAX_CHANNELS, GFP_KERNEL); 114 + if (!queue->mask) { 115 + kfree(queue); 116 + return -EINVAL; 117 + } 118 + bitmap_set(queue->mask, 0, PTP_MAX_CHANNELS); 113 119 spin_lock_init(&queue->lock); 114 120 list_add_tail(&queue->qlist, &ptp->tsevqs); 115 121 pccontext->private_clkdata = queue; ··· 132 126 spin_lock_irqsave(&queue->lock, flags); 133 127 list_del(&queue->qlist); 134 128 spin_unlock_irqrestore(&queue->lock, flags); 129 + bitmap_free(queue->mask); 135 130 kfree(queue); 136 131 } 137 132 return 0; ··· 148 141 struct system_device_crosststamp xtstamp; 149 142 struct ptp_clock_info *ops = ptp->info; 150 143 struct ptp_sys_offset *sysoff = NULL; 144 + struct timestamp_event_queue *tsevq; 151 145 struct ptp_system_timestamp sts; 152 146 struct ptp_clock_request req; 153 147 struct ptp_clock_caps caps; ··· 157 149 struct ptp_pin_desc pd; 158 150 struct timespec64 ts; 159 151 int enable, err = 0; 152 + 153 + tsevq = pccontext->private_clkdata; 160 154 161 155 switch (cmd) { 162 156 ··· 456 446 return -ERESTARTSYS; 457 447 err = ptp_set_pinfunc(ptp, pin_index, pd.func, pd.chan); 458 448 mutex_unlock(&ptp->pincfg_mux); 449 + break; 450 + 451 + case PTP_MASK_CLEAR_ALL: 452 + bitmap_clear(tsevq->mask, 0, PTP_MAX_CHANNELS); 453 + break; 454 + 455 + case PTP_MASK_EN_SINGLE: 456 + if (copy_from_user(&i, (void __user *)arg, sizeof(i))) { 457 + err = -EFAULT; 458 + break; 459 + } 460 + if (i >= PTP_MAX_CHANNELS) { 461 + err = -EFAULT; 462 + break; 463 + } 464 + set_bit(i, tsevq->mask); 459 465 break; 460 466 461 467 default:
+10 -2
drivers/ptp/ptp_clock.c
··· 183 183 spin_lock_irqsave(&tsevq->lock, flags); 184 184 list_del(&tsevq->qlist); 185 185 spin_unlock_irqrestore(&tsevq->lock, flags); 186 + bitmap_free(tsevq->mask); 186 187 kfree(tsevq); 187 188 ida_free(&ptp_clocks_map, ptp->index); 188 189 kfree(ptp); ··· 244 243 if (!queue) 245 244 goto no_memory_queue; 246 245 list_add_tail(&queue->qlist, &ptp->tsevqs); 246 + queue->mask = bitmap_alloc(PTP_MAX_CHANNELS, GFP_KERNEL); 247 + if (!queue->mask) 248 + goto no_memory_bitmap; 249 + bitmap_set(queue->mask, 0, PTP_MAX_CHANNELS); 247 250 spin_lock_init(&queue->lock); 248 251 mutex_init(&ptp->pincfg_mux); 249 252 mutex_init(&ptp->n_vclocks_mux); ··· 351 346 kworker_err: 352 347 mutex_destroy(&ptp->pincfg_mux); 353 348 mutex_destroy(&ptp->n_vclocks_mux); 349 + bitmap_free(queue->mask); 350 + no_memory_bitmap: 354 351 list_del(&queue->qlist); 355 352 kfree(queue); 356 353 no_memory_queue: ··· 407 400 break; 408 401 409 402 case PTP_CLOCK_EXTTS: 410 - /* Enqueue timestamp on all queues */ 403 + /* Enqueue timestamp on selected queues */ 411 404 list_for_each_entry(tsevq, &ptp->tsevqs, qlist) { 412 - enqueue_external_timestamp(tsevq, event); 405 + if (test_bit((unsigned int)event->index, tsevq->mask)) 406 + enqueue_external_timestamp(tsevq, event); 413 407 } 414 408 wake_up_interruptible(&ptp->tsev_wq); 415 409 break;
+3
drivers/ptp/ptp_private.h
··· 16 16 #include <linux/ptp_clock_kernel.h> 17 17 #include <linux/time.h> 18 18 #include <linux/list.h> 19 + #include <linux/bitmap.h> 19 20 20 21 #define PTP_MAX_TIMESTAMPS 128 21 22 #define PTP_BUF_TIMESTAMPS 30 22 23 #define PTP_DEFAULT_MAX_VCLOCKS 20 24 + #define PTP_MAX_CHANNELS 2048 23 25 24 26 struct timestamp_event_queue { 25 27 struct ptp_extts_event buf[PTP_MAX_TIMESTAMPS]; ··· 29 27 int tail; 30 28 spinlock_t lock; 31 29 struct list_head qlist; 30 + unsigned long *mask; 32 31 }; 33 32 34 33 struct ptp_clock {
+2
include/uapi/linux/ptp_clock.h
··· 224 224 _IOWR(PTP_CLK_MAGIC, 17, struct ptp_sys_offset_precise) 225 225 #define PTP_SYS_OFFSET_EXTENDED2 \ 226 226 _IOWR(PTP_CLK_MAGIC, 18, struct ptp_sys_offset_extended) 227 + #define PTP_MASK_CLEAR_ALL _IO(PTP_CLK_MAGIC, 19) 228 + #define PTP_MASK_EN_SINGLE _IOW(PTP_CLK_MAGIC, 20, unsigned int) 227 229 228 230 struct ptp_extts_event { 229 231 struct ptp_clock_time t; /* Time event occured. */