Message ID | 20230830214101.509086-2-reibax@gmail.com (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | ptp: Demultiplexed timestamp channels | expand |
On Wed, Aug 30, 2023 at 11:41:01PM +0200, Xabier Marquiegui wrote: > +ssize_t ptp_dmtsc_read(struct file *file, char __user *buf, size_t cnt, > + loff_t *offset) > +{ > + struct ptp_dmtsc_cdev_info *cdev = file->private_data; > + > + return ptp_queue_read(cdev->pclock, buf, cnt, cdev->minor); > +} > + > +static const struct file_operations fops = { > + .owner = THIS_MODULE, > + .open = ptp_dmtsc_open, > + .read = ptp_dmtsc_read, > + .release = ptp_dmtsc_release > + }; I'll say it again... There is no need to add a new char dev! You will need a patch series of at least three patches, step by step: 1. Delete ptp_clock.tsevq Replace it will a linked list of `struct timestamp_event_queue` Populate the list with ONE queue in ptp_clock_register() This will be your first patch. It will have the same functionality as before. 2. Allocate a new `struct timestamp_event_queue` on posix_clock_operations.open() Add it into the list. Remove it again on posix_clock_operations.release() This will introduce new functionality, as all events will go to all consumers. 3. Introduce a new ioctl that filters events based on user preference. Hm? Thanks, Richard
Hi Xabier, kernel test robot noticed the following build warnings: [auto build test WARNING on net/main] [also build test WARNING on net-next/main linus/master horms-ipvs/master v6.5 next-20230830] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Xabier-Marquiegui/ptp-Demultiplexed-timestamp-channels/20230831-054428 base: net/main patch link: https://lore.kernel.org/r/20230830214101.509086-2-reibax%40gmail.com patch subject: [PATCH] ptp: Demultiplexed timestamp channels config: m68k-allyesconfig (https://download.01.org/0day-ci/archive/20230831/202308310809.wcvhamyw-lkp@intel.com/config) compiler: m68k-linux-gcc (GCC) 13.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20230831/202308310809.wcvhamyw-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202308310809.wcvhamyw-lkp@intel.com/ All warnings (new ones prefixed by >>): >> drivers/ptp/ptp_chardev.c:449:9: warning: no previous prototype for 'ptp_queue_read' [-Wmissing-prototypes] 449 | ssize_t ptp_queue_read(struct ptp_clock *ptp, char __user *buf, size_t cnt, | ^~~~~~~~~~~~~~ >> drivers/ptp/ptp_chardev.c:544:5: warning: no previous prototype for 'ptp_dmtsc_release' [-Wmissing-prototypes] 544 | int ptp_dmtsc_release(struct inode *inode, struct file *file) | ^~~~~~~~~~~~~~~~~ >> drivers/ptp/ptp_chardev.c:556:9: warning: no previous prototype for 'ptp_dmtsc_read' [-Wmissing-prototypes] 556 | ssize_t ptp_dmtsc_read(struct file *file, char __user *buf, size_t cnt, | ^~~~~~~~~~~~~~ >> drivers/ptp/ptp_chardev.c:571:6: warning: no previous prototype for 'ptp_dmtsc_cdev_clean' [-Wmissing-prototypes] 571 | void ptp_dmtsc_cdev_clean(struct ptp_clock *ptp) | ^~~~~~~~~~~~~~~~~~~~ In file included from include/linux/linkage.h:7, from include/linux/preempt.h:10, from arch/m68k/include/asm/irqflags.h:6, from include/linux/irqflags.h:17, from arch/m68k/include/asm/atomic.h:6, from include/linux/atomic.h:7, from include/linux/mm_types_task.h:13, from include/linux/mm_types.h:5, from include/linux/buildid.h:5, from include/linux/module.h:14, from drivers/ptp/ptp_chardev.c:7: drivers/ptp/ptp_chardev.c: In function 'ptp_dmtsc_dev_register': include/linux/export.h:31:21: error: passing argument 1 of 'class_create' from incompatible pointer type [-Werror=incompatible-pointer-types] 31 | #define THIS_MODULE ((struct module *)0) | ^~~~~~~~~~~~~~~~~~~~ | | | struct module * drivers/ptp/ptp_chardev.c:612:38: note: in expansion of macro 'THIS_MODULE' 612 | class_create(THIS_MODULE, "ptptsevqch_class"); | ^~~~~~~~~~~ In file included from include/linux/device.h:31, from include/linux/cdev.h:8, from include/linux/posix-clock.h:10, from drivers/ptp/ptp_chardev.c:8: include/linux/device/class.h:230:54: note: expected 'const char *' but argument is of type 'struct module *' 230 | struct class * __must_check class_create(const char *name); | ~~~~~~~~~~~~^~~~ drivers/ptp/ptp_chardev.c:612:25: error: too many arguments to function 'class_create' 612 | class_create(THIS_MODULE, "ptptsevqch_class"); | ^~~~~~~~~~~~ include/linux/device/class.h:230:29: note: declared here 230 | struct class * __must_check class_create(const char *name); | ^~~~~~~~~~~~ cc1: some warnings being treated as errors vim +/ptp_queue_read +449 drivers/ptp/ptp_chardev.c 448 > 449 ssize_t ptp_queue_read(struct ptp_clock *ptp, char __user *buf, size_t cnt, 450 int dmtsc) 451 { 452 struct timestamp_event_queue *queue; 453 struct mutex *tsevq_mux; 454 struct ptp_extts_event *event; 455 unsigned long flags; 456 size_t qcnt, i; 457 int result; 458 459 if (dmtsc < 0) { 460 queue = &ptp->tsevq; 461 tsevq_mux = &ptp->tsevq_mux; 462 } else { 463 queue = &ptp->dmtsc_devs.cdev_info[dmtsc].tsevq; 464 tsevq_mux = &ptp->dmtsc_devs.cdev_info[dmtsc].tsevq_mux; 465 } 466 467 if (cnt % sizeof(struct ptp_extts_event) != 0) 468 return -EINVAL; 469 470 if (cnt > EXTTS_BUFSIZE) 471 cnt = EXTTS_BUFSIZE; 472 473 cnt = cnt / sizeof(struct ptp_extts_event); 474 475 if (mutex_lock_interruptible(tsevq_mux)) 476 return -ERESTARTSYS; 477 478 if (wait_event_interruptible(ptp->tsev_wq, 479 ptp->defunct || queue_cnt(queue))) { 480 mutex_unlock(tsevq_mux); 481 return -ERESTARTSYS; 482 } 483 484 if (ptp->defunct) { 485 mutex_unlock(tsevq_mux); 486 return -ENODEV; 487 } 488 489 event = kmalloc(EXTTS_BUFSIZE, GFP_KERNEL); 490 if (!event) { 491 mutex_unlock(tsevq_mux); 492 return -ENOMEM; 493 } 494 495 spin_lock_irqsave(&queue->lock, flags); 496 497 qcnt = queue_cnt(queue); 498 499 if (cnt > qcnt) 500 cnt = qcnt; 501 502 for (i = 0; i < cnt; i++) { 503 event[i] = queue->buf[queue->head]; 504 queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS; 505 } 506 507 spin_unlock_irqrestore(&queue->lock, flags); 508 509 cnt = cnt * sizeof(struct ptp_extts_event); 510 511 mutex_unlock(tsevq_mux); 512 513 result = cnt; 514 if (copy_to_user(buf, event, cnt)) 515 result = -EFAULT; 516 517 kfree(event); 518 return result; 519 } 520 521 ssize_t ptp_read(struct posix_clock *pc, uint rdflags, char __user *buf, 522 size_t cnt) 523 { 524 struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); 525 526 return ptp_queue_read(ptp, buf, cnt, DMTSC_NOT); 527 } 528 529 static int ptp_dmtsc_open(struct inode *inode, struct file *file) 530 { 531 struct ptp_dmtsc_cdev_info *cdev = container_of( 532 inode->i_cdev, struct ptp_dmtsc_cdev_info, dmtsc_cdev); 533 534 file->private_data = cdev; 535 536 if (mutex_lock_interruptible(&cdev->pclock->dmtsc_en_mux)) 537 return -ERESTARTSYS; 538 cdev->pclock->dmtsc_en_flags |= (0x1 << (cdev->minor)); 539 mutex_unlock(&cdev->pclock->dmtsc_en_mux); 540 541 return stream_open(inode, file); 542 } 543 > 544 int ptp_dmtsc_release(struct inode *inode, struct file *file) 545 { 546 struct ptp_dmtsc_cdev_info *cdev = file->private_data; 547 548 if (mutex_lock_interruptible(&cdev->pclock->dmtsc_en_mux)) 549 return -ERESTARTSYS; 550 cdev->pclock->dmtsc_en_flags &= ~(0x1 << (cdev->minor)); 551 mutex_unlock(&cdev->pclock->dmtsc_en_mux); 552 553 return 0; 554 } 555 > 556 ssize_t ptp_dmtsc_read(struct file *file, char __user *buf, size_t cnt, 557 loff_t *offset) 558 { 559 struct ptp_dmtsc_cdev_info *cdev = file->private_data; 560 561 return ptp_queue_read(cdev->pclock, buf, cnt, cdev->minor); 562 } 563 564 static const struct file_operations fops = { 565 .owner = THIS_MODULE, 566 .open = ptp_dmtsc_open, 567 .read = ptp_dmtsc_read, 568 .release = ptp_dmtsc_release 569 }; 570 > 571 void ptp_dmtsc_cdev_clean(struct ptp_clock *ptp) 572 { 573 int idx, major; 574 dev_t device; 575 576 major = MAJOR(ptp->dmtsc_devs.devid); 577 for (idx = 0; idx < ptp->info->n_ext_ts; idx++) { 578 if (ptp->dmtsc_devs.cdev_info[idx].minor >= 0) { 579 device = MKDEV(major, idx); 580 device_destroy(ptp->dmtsc_devs.dmtsc_class, device); 581 cdev_del(&ptp->dmtsc_devs.cdev_info[idx].dmtsc_cdev); 582 ptp->dmtsc_devs.cdev_info[idx].minor = -1; 583 } 584 } 585 class_destroy(ptp->dmtsc_devs.dmtsc_class); 586 unregister_chrdev_region(ptp->dmtsc_devs.devid, ptp->info->n_ext_ts); 587 mutex_destroy(&ptp->dmtsc_devs.cdev_info[idx].tsevq_mux); 588 } 589
Hi Xabier, kernel test robot noticed the following build errors: [auto build test ERROR on net/main] [also build test ERROR on net-next/main linus/master horms-ipvs/master v6.5 next-20230831] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Xabier-Marquiegui/ptp-Demultiplexed-timestamp-channels/20230831-054428 base: net/main patch link: https://lore.kernel.org/r/20230830214101.509086-2-reibax%40gmail.com patch subject: [PATCH] ptp: Demultiplexed timestamp channels config: powerpc64-randconfig-r026-20230831 (https://download.01.org/0day-ci/archive/20230831/202308312155.cA1uQaGm-lkp@intel.com/config) compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project.git 4a5ac14ee968ff0ad5d2cc1ffa0299048db4c88a) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20230831/202308312155.cA1uQaGm-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202308312155.cA1uQaGm-lkp@intel.com/ All error/warnings (new ones prefixed by >>): >> drivers/ptp/ptp_chardev.c:449:9: warning: no previous prototype for function 'ptp_queue_read' [-Wmissing-prototypes] 449 | ssize_t ptp_queue_read(struct ptp_clock *ptp, char __user *buf, size_t cnt, | ^ drivers/ptp/ptp_chardev.c:449:1: note: declare 'static' if the function is not intended to be used outside of this translation unit 449 | ssize_t ptp_queue_read(struct ptp_clock *ptp, char __user *buf, size_t cnt, | ^ | static >> drivers/ptp/ptp_chardev.c:544:5: warning: no previous prototype for function 'ptp_dmtsc_release' [-Wmissing-prototypes] 544 | int ptp_dmtsc_release(struct inode *inode, struct file *file) | ^ drivers/ptp/ptp_chardev.c:544:1: note: declare 'static' if the function is not intended to be used outside of this translation unit 544 | int ptp_dmtsc_release(struct inode *inode, struct file *file) | ^ | static >> drivers/ptp/ptp_chardev.c:556:9: warning: no previous prototype for function 'ptp_dmtsc_read' [-Wmissing-prototypes] 556 | ssize_t ptp_dmtsc_read(struct file *file, char __user *buf, size_t cnt, | ^ drivers/ptp/ptp_chardev.c:556:1: note: declare 'static' if the function is not intended to be used outside of this translation unit 556 | ssize_t ptp_dmtsc_read(struct file *file, char __user *buf, size_t cnt, | ^ | static >> drivers/ptp/ptp_chardev.c:571:6: warning: no previous prototype for function 'ptp_dmtsc_cdev_clean' [-Wmissing-prototypes] 571 | void ptp_dmtsc_cdev_clean(struct ptp_clock *ptp) | ^ drivers/ptp/ptp_chardev.c:571:1: note: declare 'static' if the function is not intended to be used outside of this translation unit 571 | void ptp_dmtsc_cdev_clean(struct ptp_clock *ptp) | ^ | static >> drivers/ptp/ptp_chardev.c:612:30: error: too many arguments to function call, expected single argument 'name', have 2 arguments 612 | class_create(THIS_MODULE, "ptptsevqch_class"); | ~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~ include/linux/device/class.h:230:29: note: 'class_create' declared here 230 | struct class * __must_check class_create(const char *name); | ^ 4 warnings and 1 error generated. vim +/name +612 drivers/ptp/ptp_chardev.c 448 > 449 ssize_t ptp_queue_read(struct ptp_clock *ptp, char __user *buf, size_t cnt, 450 int dmtsc) 451 { 452 struct timestamp_event_queue *queue; 453 struct mutex *tsevq_mux; 454 struct ptp_extts_event *event; 455 unsigned long flags; 456 size_t qcnt, i; 457 int result; 458 459 if (dmtsc < 0) { 460 queue = &ptp->tsevq; 461 tsevq_mux = &ptp->tsevq_mux; 462 } else { 463 queue = &ptp->dmtsc_devs.cdev_info[dmtsc].tsevq; 464 tsevq_mux = &ptp->dmtsc_devs.cdev_info[dmtsc].tsevq_mux; 465 } 466 467 if (cnt % sizeof(struct ptp_extts_event) != 0) 468 return -EINVAL; 469 470 if (cnt > EXTTS_BUFSIZE) 471 cnt = EXTTS_BUFSIZE; 472 473 cnt = cnt / sizeof(struct ptp_extts_event); 474 475 if (mutex_lock_interruptible(tsevq_mux)) 476 return -ERESTARTSYS; 477 478 if (wait_event_interruptible(ptp->tsev_wq, 479 ptp->defunct || queue_cnt(queue))) { 480 mutex_unlock(tsevq_mux); 481 return -ERESTARTSYS; 482 } 483 484 if (ptp->defunct) { 485 mutex_unlock(tsevq_mux); 486 return -ENODEV; 487 } 488 489 event = kmalloc(EXTTS_BUFSIZE, GFP_KERNEL); 490 if (!event) { 491 mutex_unlock(tsevq_mux); 492 return -ENOMEM; 493 } 494 495 spin_lock_irqsave(&queue->lock, flags); 496 497 qcnt = queue_cnt(queue); 498 499 if (cnt > qcnt) 500 cnt = qcnt; 501 502 for (i = 0; i < cnt; i++) { 503 event[i] = queue->buf[queue->head]; 504 queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS; 505 } 506 507 spin_unlock_irqrestore(&queue->lock, flags); 508 509 cnt = cnt * sizeof(struct ptp_extts_event); 510 511 mutex_unlock(tsevq_mux); 512 513 result = cnt; 514 if (copy_to_user(buf, event, cnt)) 515 result = -EFAULT; 516 517 kfree(event); 518 return result; 519 } 520 521 ssize_t ptp_read(struct posix_clock *pc, uint rdflags, char __user *buf, 522 size_t cnt) 523 { 524 struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); 525 526 return ptp_queue_read(ptp, buf, cnt, DMTSC_NOT); 527 } 528 529 static int ptp_dmtsc_open(struct inode *inode, struct file *file) 530 { 531 struct ptp_dmtsc_cdev_info *cdev = container_of( 532 inode->i_cdev, struct ptp_dmtsc_cdev_info, dmtsc_cdev); 533 534 file->private_data = cdev; 535 536 if (mutex_lock_interruptible(&cdev->pclock->dmtsc_en_mux)) 537 return -ERESTARTSYS; 538 cdev->pclock->dmtsc_en_flags |= (0x1 << (cdev->minor)); 539 mutex_unlock(&cdev->pclock->dmtsc_en_mux); 540 541 return stream_open(inode, file); 542 } 543 > 544 int ptp_dmtsc_release(struct inode *inode, struct file *file) 545 { 546 struct ptp_dmtsc_cdev_info *cdev = file->private_data; 547 548 if (mutex_lock_interruptible(&cdev->pclock->dmtsc_en_mux)) 549 return -ERESTARTSYS; 550 cdev->pclock->dmtsc_en_flags &= ~(0x1 << (cdev->minor)); 551 mutex_unlock(&cdev->pclock->dmtsc_en_mux); 552 553 return 0; 554 } 555 > 556 ssize_t ptp_dmtsc_read(struct file *file, char __user *buf, size_t cnt, 557 loff_t *offset) 558 { 559 struct ptp_dmtsc_cdev_info *cdev = file->private_data; 560 561 return ptp_queue_read(cdev->pclock, buf, cnt, cdev->minor); 562 } 563 564 static const struct file_operations fops = { 565 .owner = THIS_MODULE, 566 .open = ptp_dmtsc_open, 567 .read = ptp_dmtsc_read, 568 .release = ptp_dmtsc_release 569 }; 570 > 571 void ptp_dmtsc_cdev_clean(struct ptp_clock *ptp) 572 { 573 int idx, major; 574 dev_t device; 575 576 major = MAJOR(ptp->dmtsc_devs.devid); 577 for (idx = 0; idx < ptp->info->n_ext_ts; idx++) { 578 if (ptp->dmtsc_devs.cdev_info[idx].minor >= 0) { 579 device = MKDEV(major, idx); 580 device_destroy(ptp->dmtsc_devs.dmtsc_class, device); 581 cdev_del(&ptp->dmtsc_devs.cdev_info[idx].dmtsc_cdev); 582 ptp->dmtsc_devs.cdev_info[idx].minor = -1; 583 } 584 } 585 class_destroy(ptp->dmtsc_devs.dmtsc_class); 586 unregister_chrdev_region(ptp->dmtsc_devs.devid, ptp->info->n_ext_ts); 587 mutex_destroy(&ptp->dmtsc_devs.cdev_info[idx].tsevq_mux); 588 } 589 590 int ptp_dmtsc_dev_register(struct ptp_clock *ptp) 591 { 592 int err, idx, major; 593 dev_t device; 594 struct device *dev; 595 596 /* Allocate memory for demuxed device management */ 597 ptp->dmtsc_devs.cdev_info = kcalloc(ptp->info->n_ext_ts, 598 sizeof(*ptp->dmtsc_devs.cdev_info), 599 GFP_KERNEL); 600 if (!ptp->dmtsc_devs.cdev_info) { 601 err = -ENODEV; 602 goto err; 603 } 604 for (idx = 0; idx < ptp->info->n_ext_ts; idx++) 605 ptp->dmtsc_devs.cdev_info[idx].minor = -1; 606 /* Create devices for all channels. The mask will control which of them get fed */ 607 err = alloc_chrdev_region(&ptp->dmtsc_devs.devid, 0, 608 ptp->info->n_ext_ts, "ptptsevqch"); 609 if (!err) { 610 major = MAJOR(ptp->dmtsc_devs.devid); 611 ptp->dmtsc_devs.dmtsc_class = > 612 class_create(THIS_MODULE, "ptptsevqch_class"); 613 for (idx = 0; idx < ptp->info->n_ext_ts; idx++) { 614 mutex_init(&ptp->dmtsc_devs.cdev_info[idx].tsevq_mux); 615 device = MKDEV(major, idx); 616 ptp->dmtsc_devs.cdev_info[idx].pclock = ptp; 617 cdev_init(&ptp->dmtsc_devs.cdev_info[idx].dmtsc_cdev, 618 &fops); 619 err = cdev_add( 620 &ptp->dmtsc_devs.cdev_info[idx].dmtsc_cdev, 621 device, 1); 622 if (err) { 623 goto cdev_clean; 624 } else { 625 ptp->dmtsc_devs.cdev_info[idx].minor = idx; 626 dev = device_create(ptp->dmtsc_devs.dmtsc_class, 627 &ptp->dev, device, NULL, 628 "ptp%dch%d", ptp->index, 629 idx); 630 if (IS_ERR(dev)) { 631 err = PTR_ERR(dev); 632 goto cdev_clean; 633 } 634 } 635 } 636 } else { 637 goto dev_clean; 638 } 639 return 0; 640 641 cdev_clean: 642 ptp_dmtsc_cdev_clean(ptp); 643 dev_clean: 644 kfree(ptp->dmtsc_devs.cdev_info); 645 ptp->dmtsc_devs.cdev_info = NULL; 646 err: 647 return err; 648 } 649
Hi Xabier, kernel test robot noticed the following build warnings: [auto build test WARNING on net/main] [also build test WARNING on net-next/main linus/master horms-ipvs/master v6.5 next-20230831] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Xabier-Marquiegui/ptp-Demultiplexed-timestamp-channels/20230831-054428 base: net/main patch link: https://lore.kernel.org/r/20230830214101.509086-2-reibax%40gmail.com patch subject: [PATCH] ptp: Demultiplexed timestamp channels config: um-i386_defconfig (https://download.01.org/0day-ci/archive/20230901/202309010030.U9g5VVWf-lkp@intel.com/config) compiler: gcc-7 (Ubuntu 7.5.0-6ubuntu2) 7.5.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20230901/202309010030.U9g5VVWf-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202309010030.U9g5VVWf-lkp@intel.com/ All warnings (new ones prefixed by >>): >> drivers/ptp/ptp_chardev.c:449:9: warning: no previous declaration for 'ptp_queue_read' [-Wmissing-declarations] ssize_t ptp_queue_read(struct ptp_clock *ptp, char __user *buf, size_t cnt, ^~~~~~~~~~~~~~ >> drivers/ptp/ptp_chardev.c:544:5: warning: no previous declaration for 'ptp_dmtsc_release' [-Wmissing-declarations] int ptp_dmtsc_release(struct inode *inode, struct file *file) ^~~~~~~~~~~~~~~~~ >> drivers/ptp/ptp_chardev.c:556:9: warning: no previous declaration for 'ptp_dmtsc_read' [-Wmissing-declarations] ssize_t ptp_dmtsc_read(struct file *file, char __user *buf, size_t cnt, ^~~~~~~~~~~~~~ >> drivers/ptp/ptp_chardev.c:571:6: warning: no previous declaration for 'ptp_dmtsc_cdev_clean' [-Wmissing-declarations] void ptp_dmtsc_cdev_clean(struct ptp_clock *ptp) ^~~~~~~~~~~~~~~~~~~~ In file included from include/linux/linkage.h:7:0, from include/linux/kernel.h:17, from include/linux/cpumask.h:10, from include/linux/mm_types_task.h:14, from include/linux/mm_types.h:5, from include/linux/buildid.h:5, from include/linux/module.h:14, from drivers/ptp/ptp_chardev.c:7: drivers/ptp/ptp_chardev.c: In function 'ptp_dmtsc_dev_register': include/linux/export.h:31:21: error: passing argument 1 of 'class_create' from incompatible pointer type [-Werror=incompatible-pointer-types] #define THIS_MODULE ((struct module *)0) ^ drivers/ptp/ptp_chardev.c:612:17: note: in expansion of macro 'THIS_MODULE' class_create(THIS_MODULE, "ptptsevqch_class"); ^~~~~~~~~~~ In file included from include/linux/device.h:31:0, from include/linux/cdev.h:8, from include/linux/posix-clock.h:10, from drivers/ptp/ptp_chardev.c:8: include/linux/device/class.h:230:29: note: expected 'const char *' but argument is of type 'struct module *' struct class * __must_check class_create(const char *name); ^~~~~~~~~~~~ drivers/ptp/ptp_chardev.c:612:4: error: too many arguments to function 'class_create' class_create(THIS_MODULE, "ptptsevqch_class"); ^~~~~~~~~~~~ In file included from include/linux/device.h:31:0, from include/linux/cdev.h:8, from include/linux/posix-clock.h:10, from drivers/ptp/ptp_chardev.c:8: include/linux/device/class.h:230:29: note: declared here struct class * __must_check class_create(const char *name); ^~~~~~~~~~~~ cc1: some warnings being treated as errors vim +/ptp_queue_read +449 drivers/ptp/ptp_chardev.c 448 > 449 ssize_t ptp_queue_read(struct ptp_clock *ptp, char __user *buf, size_t cnt, 450 int dmtsc) 451 { 452 struct timestamp_event_queue *queue; 453 struct mutex *tsevq_mux; 454 struct ptp_extts_event *event; 455 unsigned long flags; 456 size_t qcnt, i; 457 int result; 458 459 if (dmtsc < 0) { 460 queue = &ptp->tsevq; 461 tsevq_mux = &ptp->tsevq_mux; 462 } else { 463 queue = &ptp->dmtsc_devs.cdev_info[dmtsc].tsevq; 464 tsevq_mux = &ptp->dmtsc_devs.cdev_info[dmtsc].tsevq_mux; 465 } 466 467 if (cnt % sizeof(struct ptp_extts_event) != 0) 468 return -EINVAL; 469 470 if (cnt > EXTTS_BUFSIZE) 471 cnt = EXTTS_BUFSIZE; 472 473 cnt = cnt / sizeof(struct ptp_extts_event); 474 475 if (mutex_lock_interruptible(tsevq_mux)) 476 return -ERESTARTSYS; 477 478 if (wait_event_interruptible(ptp->tsev_wq, 479 ptp->defunct || queue_cnt(queue))) { 480 mutex_unlock(tsevq_mux); 481 return -ERESTARTSYS; 482 } 483 484 if (ptp->defunct) { 485 mutex_unlock(tsevq_mux); 486 return -ENODEV; 487 } 488 489 event = kmalloc(EXTTS_BUFSIZE, GFP_KERNEL); 490 if (!event) { 491 mutex_unlock(tsevq_mux); 492 return -ENOMEM; 493 } 494 495 spin_lock_irqsave(&queue->lock, flags); 496 497 qcnt = queue_cnt(queue); 498 499 if (cnt > qcnt) 500 cnt = qcnt; 501 502 for (i = 0; i < cnt; i++) { 503 event[i] = queue->buf[queue->head]; 504 queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS; 505 } 506 507 spin_unlock_irqrestore(&queue->lock, flags); 508 509 cnt = cnt * sizeof(struct ptp_extts_event); 510 511 mutex_unlock(tsevq_mux); 512 513 result = cnt; 514 if (copy_to_user(buf, event, cnt)) 515 result = -EFAULT; 516 517 kfree(event); 518 return result; 519 } 520 521 ssize_t ptp_read(struct posix_clock *pc, uint rdflags, char __user *buf, 522 size_t cnt) 523 { 524 struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); 525 526 return ptp_queue_read(ptp, buf, cnt, DMTSC_NOT); 527 } 528 529 static int ptp_dmtsc_open(struct inode *inode, struct file *file) 530 { 531 struct ptp_dmtsc_cdev_info *cdev = container_of( 532 inode->i_cdev, struct ptp_dmtsc_cdev_info, dmtsc_cdev); 533 534 file->private_data = cdev; 535 536 if (mutex_lock_interruptible(&cdev->pclock->dmtsc_en_mux)) 537 return -ERESTARTSYS; 538 cdev->pclock->dmtsc_en_flags |= (0x1 << (cdev->minor)); 539 mutex_unlock(&cdev->pclock->dmtsc_en_mux); 540 541 return stream_open(inode, file); 542 } 543 > 544 int ptp_dmtsc_release(struct inode *inode, struct file *file) 545 { 546 struct ptp_dmtsc_cdev_info *cdev = file->private_data; 547 548 if (mutex_lock_interruptible(&cdev->pclock->dmtsc_en_mux)) 549 return -ERESTARTSYS; 550 cdev->pclock->dmtsc_en_flags &= ~(0x1 << (cdev->minor)); 551 mutex_unlock(&cdev->pclock->dmtsc_en_mux); 552 553 return 0; 554 } 555 > 556 ssize_t ptp_dmtsc_read(struct file *file, char __user *buf, size_t cnt, 557 loff_t *offset) 558 { 559 struct ptp_dmtsc_cdev_info *cdev = file->private_data; 560 561 return ptp_queue_read(cdev->pclock, buf, cnt, cdev->minor); 562 } 563 564 static const struct file_operations fops = { 565 .owner = THIS_MODULE, 566 .open = ptp_dmtsc_open, 567 .read = ptp_dmtsc_read, 568 .release = ptp_dmtsc_release 569 }; 570 > 571 void ptp_dmtsc_cdev_clean(struct ptp_clock *ptp) 572 { 573 int idx, major; 574 dev_t device; 575 576 major = MAJOR(ptp->dmtsc_devs.devid); 577 for (idx = 0; idx < ptp->info->n_ext_ts; idx++) { 578 if (ptp->dmtsc_devs.cdev_info[idx].minor >= 0) { 579 device = MKDEV(major, idx); 580 device_destroy(ptp->dmtsc_devs.dmtsc_class, device); 581 cdev_del(&ptp->dmtsc_devs.cdev_info[idx].dmtsc_cdev); 582 ptp->dmtsc_devs.cdev_info[idx].minor = -1; 583 } 584 } 585 class_destroy(ptp->dmtsc_devs.dmtsc_class); 586 unregister_chrdev_region(ptp->dmtsc_devs.devid, ptp->info->n_ext_ts); 587 mutex_destroy(&ptp->dmtsc_devs.cdev_info[idx].tsevq_mux); 588 } 589
Thank you for your patience Richard, and thank you for guiding me. Let's see if I got closer to what we want this time. Let me know what you thing about these patches, please. Thanks, Xabier
diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index 362bf756e6b7..c31cfc5b0907 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -10,11 +10,14 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/timekeeping.h> - +#include <linux/cdev.h> +#include <linux/fs.h> #include <linux/nospec.h> #include "ptp_private.h" +#define DMTSC_NOT -1 + static int ptp_disable_pinfunc(struct ptp_clock_info *ops, enum ptp_pin_function func, unsigned int chan) { @@ -443,16 +446,24 @@ __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_queue_read(struct ptp_clock *ptp, char __user *buf, size_t cnt, + int dmtsc) { - struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); - struct timestamp_event_queue *queue = &ptp->tsevq; + struct timestamp_event_queue *queue; + struct mutex *tsevq_mux; struct ptp_extts_event *event; unsigned long flags; size_t qcnt, i; int result; + if (dmtsc < 0) { + queue = &ptp->tsevq; + tsevq_mux = &ptp->tsevq_mux; + } else { + queue = &ptp->dmtsc_devs.cdev_info[dmtsc].tsevq; + tsevq_mux = &ptp->dmtsc_devs.cdev_info[dmtsc].tsevq_mux; + } + if (cnt % sizeof(struct ptp_extts_event) != 0) return -EINVAL; @@ -461,23 +472,23 @@ ssize_t ptp_read(struct posix_clock *pc, cnt = cnt / sizeof(struct ptp_extts_event); - if (mutex_lock_interruptible(&ptp->tsevq_mux)) + if (mutex_lock_interruptible(tsevq_mux)) return -ERESTARTSYS; if (wait_event_interruptible(ptp->tsev_wq, ptp->defunct || queue_cnt(queue))) { - mutex_unlock(&ptp->tsevq_mux); + mutex_unlock(tsevq_mux); return -ERESTARTSYS; } if (ptp->defunct) { - mutex_unlock(&ptp->tsevq_mux); + mutex_unlock(tsevq_mux); return -ENODEV; } event = kmalloc(EXTTS_BUFSIZE, GFP_KERNEL); if (!event) { - mutex_unlock(&ptp->tsevq_mux); + mutex_unlock(tsevq_mux); return -ENOMEM; } @@ -497,7 +508,7 @@ ssize_t ptp_read(struct posix_clock *pc, cnt = cnt * sizeof(struct ptp_extts_event); - mutex_unlock(&ptp->tsevq_mux); + mutex_unlock(tsevq_mux); result = cnt; if (copy_to_user(buf, event, cnt)) @@ -506,3 +517,139 @@ ssize_t ptp_read(struct posix_clock *pc, kfree(event); return result; } + +ssize_t ptp_read(struct posix_clock *pc, uint rdflags, char __user *buf, + size_t cnt) +{ + struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); + + return ptp_queue_read(ptp, buf, cnt, DMTSC_NOT); +} + +static int ptp_dmtsc_open(struct inode *inode, struct file *file) +{ + struct ptp_dmtsc_cdev_info *cdev = container_of( + inode->i_cdev, struct ptp_dmtsc_cdev_info, dmtsc_cdev); + + file->private_data = cdev; + + if (mutex_lock_interruptible(&cdev->pclock->dmtsc_en_mux)) + return -ERESTARTSYS; + cdev->pclock->dmtsc_en_flags |= (0x1 << (cdev->minor)); + mutex_unlock(&cdev->pclock->dmtsc_en_mux); + + return stream_open(inode, file); +} + +int ptp_dmtsc_release(struct inode *inode, struct file *file) +{ + struct ptp_dmtsc_cdev_info *cdev = file->private_data; + + if (mutex_lock_interruptible(&cdev->pclock->dmtsc_en_mux)) + return -ERESTARTSYS; + cdev->pclock->dmtsc_en_flags &= ~(0x1 << (cdev->minor)); + mutex_unlock(&cdev->pclock->dmtsc_en_mux); + + return 0; +} + +ssize_t ptp_dmtsc_read(struct file *file, char __user *buf, size_t cnt, + loff_t *offset) +{ + struct ptp_dmtsc_cdev_info *cdev = file->private_data; + + return ptp_queue_read(cdev->pclock, buf, cnt, cdev->minor); +} + +static const struct file_operations fops = { + .owner = THIS_MODULE, + .open = ptp_dmtsc_open, + .read = ptp_dmtsc_read, + .release = ptp_dmtsc_release + }; + +void ptp_dmtsc_cdev_clean(struct ptp_clock *ptp) +{ + int idx, major; + dev_t device; + + major = MAJOR(ptp->dmtsc_devs.devid); + for (idx = 0; idx < ptp->info->n_ext_ts; idx++) { + if (ptp->dmtsc_devs.cdev_info[idx].minor >= 0) { + device = MKDEV(major, idx); + device_destroy(ptp->dmtsc_devs.dmtsc_class, device); + cdev_del(&ptp->dmtsc_devs.cdev_info[idx].dmtsc_cdev); + ptp->dmtsc_devs.cdev_info[idx].minor = -1; + } + } + class_destroy(ptp->dmtsc_devs.dmtsc_class); + unregister_chrdev_region(ptp->dmtsc_devs.devid, ptp->info->n_ext_ts); + mutex_destroy(&ptp->dmtsc_devs.cdev_info[idx].tsevq_mux); +} + +int ptp_dmtsc_dev_register(struct ptp_clock *ptp) +{ + int err, idx, major; + dev_t device; + struct device *dev; + + /* Allocate memory for demuxed device management */ + ptp->dmtsc_devs.cdev_info = kcalloc(ptp->info->n_ext_ts, + sizeof(*ptp->dmtsc_devs.cdev_info), + GFP_KERNEL); + if (!ptp->dmtsc_devs.cdev_info) { + err = -ENODEV; + goto err; + } + for (idx = 0; idx < ptp->info->n_ext_ts; idx++) + ptp->dmtsc_devs.cdev_info[idx].minor = -1; + /* Create devices for all channels. The mask will control which of them get fed */ + err = alloc_chrdev_region(&ptp->dmtsc_devs.devid, 0, + ptp->info->n_ext_ts, "ptptsevqch"); + if (!err) { + major = MAJOR(ptp->dmtsc_devs.devid); + ptp->dmtsc_devs.dmtsc_class = + class_create(THIS_MODULE, "ptptsevqch_class"); + for (idx = 0; idx < ptp->info->n_ext_ts; idx++) { + mutex_init(&ptp->dmtsc_devs.cdev_info[idx].tsevq_mux); + device = MKDEV(major, idx); + ptp->dmtsc_devs.cdev_info[idx].pclock = ptp; + cdev_init(&ptp->dmtsc_devs.cdev_info[idx].dmtsc_cdev, + &fops); + err = cdev_add( + &ptp->dmtsc_devs.cdev_info[idx].dmtsc_cdev, + device, 1); + if (err) { + goto cdev_clean; + } else { + ptp->dmtsc_devs.cdev_info[idx].minor = idx; + dev = device_create(ptp->dmtsc_devs.dmtsc_class, + &ptp->dev, device, NULL, + "ptp%dch%d", ptp->index, + idx); + if (IS_ERR(dev)) { + err = PTR_ERR(dev); + goto cdev_clean; + } + } + } + } else { + goto dev_clean; + } + return 0; + +cdev_clean: + ptp_dmtsc_cdev_clean(ptp); +dev_clean: + kfree(ptp->dmtsc_devs.cdev_info); + ptp->dmtsc_devs.cdev_info = NULL; +err: + return err; +} + +void ptp_dmtsc_dev_uregister(struct ptp_clock *ptp) +{ + ptp_dmtsc_cdev_clean(ptp); + kfree(ptp->dmtsc_devs.cdev_info); + ptp->dmtsc_devs.cdev_info = NULL; +} diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index 80f74e38c2da..0a42c27c3514 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -172,6 +172,7 @@ static void ptp_clock_release(struct device *dev) ptp_cleanup_pin_groups(ptp); kfree(ptp->vclock_index); + mutex_destroy(&ptp->dmtsc_en_mux); mutex_destroy(&ptp->tsevq_mux); mutex_destroy(&ptp->pincfg_mux); mutex_destroy(&ptp->n_vclocks_mux); @@ -232,7 +233,9 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, mutex_init(&ptp->tsevq_mux); mutex_init(&ptp->pincfg_mux); mutex_init(&ptp->n_vclocks_mux); + mutex_init(&ptp->dmtsc_en_mux); init_waitqueue_head(&ptp->tsev_wq); + ptp->dmtsc_en_flags = 0x0; if (ptp->info->getcycles64 || ptp->info->getcyclesx64) { ptp->has_cycles = true; @@ -307,21 +310,27 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, /* Create a posix clock and link it to the device. */ err = posix_clock_register(&ptp->clock, &ptp->dev); - if (err) { - if (ptp->pps_source) - pps_unregister_source(ptp->pps_source); + if (err) + goto reg_err; - if (ptp->kworker) - kthread_destroy_worker(ptp->kworker); + /* Create chardevs for demuxed external timestamp channels */ + if (ptp_dmtsc_dev_register(ptp)) + goto reg_err; - put_device(&ptp->dev); + return ptp; - pr_err("failed to create posix clock\n"); - return ERR_PTR(err); - } +reg_err: + ptp_dmtsc_dev_uregister(ptp); + if (ptp->pps_source) + pps_unregister_source(ptp->pps_source); - return ptp; + if (ptp->kworker) + kthread_destroy_worker(ptp->kworker); + + put_device(&ptp->dev); + pr_err("failed to create posix clock\n"); + return ERR_PTR(err); no_pps: ptp_cleanup_pin_groups(ptp); no_pin_groups: @@ -330,6 +339,7 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, if (ptp->kworker) kthread_destroy_worker(ptp->kworker); kworker_err: + mutex_destroy(&ptp->dmtsc_en_mux); mutex_destroy(&ptp->tsevq_mux); mutex_destroy(&ptp->pincfg_mux); mutex_destroy(&ptp->n_vclocks_mux); @@ -367,6 +377,8 @@ int ptp_clock_unregister(struct ptp_clock *ptp) if (ptp->pps_source) pps_unregister_source(ptp->pps_source); + ptp_dmtsc_dev_uregister(ptp); + posix_clock_unregister(&ptp->clock); return 0; @@ -378,12 +390,19 @@ void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event) struct pps_event_time evt; switch (event->type) { - case PTP_CLOCK_ALARM: break; case PTP_CLOCK_EXTTS: - enqueue_external_timestamp(&ptp->tsevq, event); + /* If event index demuxed queue mask is enabled send to dedicated fifo */ + if (ptp->dmtsc_en_flags & (0x1 << event->index)) { + enqueue_external_timestamp( + &ptp->dmtsc_devs.cdev_info[event->index].tsevq, + event); + } else { + enqueue_external_timestamp(&ptp->tsevq, event); + } + wake_up_interruptible(&ptp->tsev_wq); break; diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h index 75f58fc468a7..c473ef75d8d7 100644 --- a/drivers/ptp/ptp_private.h +++ b/drivers/ptp/ptp_private.h @@ -27,6 +27,20 @@ struct timestamp_event_queue { spinlock_t lock; }; +struct ptp_dmtsc_cdev_info { + struct cdev dmtsc_cdev; /* Demuxed event device chardev */ + int minor; /* Demuxed event queue chardev device minor */ + struct ptp_clock *pclock; /* Direct access to parent clock device */ + struct mutex tsevq_mux; /* Protect access to device management */ + struct timestamp_event_queue tsevq; /* simple fifo for time stamps */ +}; + +struct ptp_dmtsc_dev_info { + dev_t devid; + struct class *dmtsc_class; + struct ptp_dmtsc_cdev_info *cdev_info; +}; + struct ptp_clock { struct posix_clock clock; struct device dev; @@ -36,6 +50,11 @@ struct ptp_clock { struct pps_device *pps_source; long dialed_frequency; /* remembers the frequency adjustment */ struct timestamp_event_queue tsevq; /* simple fifo for time stamps */ + u32 dmtsc_en_flags; /* Demultiplexed timestamp channels enable flags */ + struct mutex + dmtsc_en_mux; /* Demultiplexed timestamp channels sysfs mutex */ + struct ptp_dmtsc_dev_info + dmtsc_devs; /* Demultiplexed timestamp channel access character devices */ 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; @@ -139,4 +158,7 @@ void ptp_cleanup_pin_groups(struct ptp_clock *ptp); struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock); void ptp_vclock_unregister(struct ptp_vclock *vclock); + +int ptp_dmtsc_dev_register(struct ptp_clock *ptp); +void ptp_dmtsc_dev_uregister(struct ptp_clock *ptp); #endif
Add the posibility to demultiplex the timestamp channels for external timestamp event channels. In some applications it can be necessary to have different consumers for different timestamp channels. For example, synchronize to an external pps source with linuxptp ts2phc while timestmping external events with another application. This commit maintains the original multiplexed queue and adds an individual queue per external timestamp channel. All enabled channels will be directed to the multiplexed queue by default. On file open, a specific channel will be redirected to the dedicated char device, and on close it will automatically go back to the multiplexed queue. Signed-off-by: Xabier Marquiegui <reibax@gmail.com> --- drivers/ptp/ptp_chardev.c | 167 +++++++++++++++++++++++++++++++++++--- drivers/ptp/ptp_clock.c | 43 +++++++--- drivers/ptp/ptp_private.h | 22 +++++ 3 files changed, 210 insertions(+), 22 deletions(-)