diff mbox series

[net-next,v2,1/3] ptp: Replace timestamp event queue with linked list

Message ID 20230912220217.2008895-1-reibax@gmail.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series [net-next,v2,1/3] ptp: Replace timestamp event queue with linked list | expand

Checks

Context Check Description
netdev/series_format warning Series does not have a cover letter
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 1340 this patch: 1340
netdev/cc_maintainers success CCed 2 of 2 maintainers
netdev/build_clang success Errors and warnings before: 1363 this patch: 1363
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 1363 this patch: 1363
netdev/checkpatch warning WARNING: line length of 81 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Xabier Marquiegui Sept. 12, 2023, 10:02 p.m. UTC
This is the first of a set of patches to introduce linked lists to the
timestamp event queue. The final goal is to be able to have multiple
readers for the timestamp queue.

On this one we maintain the original feature set, and we just introduce
the linked lists to the data structure.

Signed-off-by: Xabier Marquiegui <reibax@gmail.com>
Suggested-by: Richard Cochran <richardcochran@gmail.com>
---
v2:
  - Style changes to comform to checkpatch strict suggestions
v1: https://lore.kernel.org/netdev/20230906104754.1324412-2-reibax@gmail.com/

 drivers/ptp/ptp_chardev.c | 16 ++++++++++++++--
 drivers/ptp/ptp_clock.c   | 30 ++++++++++++++++++++++++++++--
 drivers/ptp/ptp_private.h |  4 +++-
 drivers/ptp/ptp_sysfs.c   |  6 +++++-
 4 files changed, 50 insertions(+), 6 deletions(-)

Comments

Vinicius Costa Gomes Sept. 13, 2023, 12:05 a.m. UTC | #1
Xabier Marquiegui <reibax@gmail.com> writes:

> This is the first of a set of patches to introduce linked lists to the
> timestamp event queue. The final goal is to be able to have multiple
> readers for the timestamp queue.
>
> On this one we maintain the original feature set, and we just introduce
> the linked lists to the data structure.
>
> Signed-off-by: Xabier Marquiegui <reibax@gmail.com>
> Suggested-by: Richard Cochran <richardcochran@gmail.com>
> ---
> v2:
>   - Style changes to comform to checkpatch strict suggestions
> v1: https://lore.kernel.org/netdev/20230906104754.1324412-2-reibax@gmail.com/
>
>  drivers/ptp/ptp_chardev.c | 16 ++++++++++++++--
>  drivers/ptp/ptp_clock.c   | 30 ++++++++++++++++++++++++++++--
>  drivers/ptp/ptp_private.h |  4 +++-
>  drivers/ptp/ptp_sysfs.c   |  6 +++++-
>  4 files changed, 50 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c
> index 362bf756e6b7..197edf1179f1 100644
> --- a/drivers/ptp/ptp_chardev.c
> +++ b/drivers/ptp/ptp_chardev.c
> @@ -435,10 +435,16 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
>  __poll_t ptp_poll(struct posix_clock *pc, struct file *fp, poll_table *wait)
>  {
>  	struct ptp_clock *ptp = container_of(pc, 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
> +	 * TODO: Identify the relevant queue
> +	 */
> +	queue = list_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))
> @@ -447,12 +453,18 @@ 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);
> -	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
> +	 * TODO: Identify the relevant queue
> +	 */
> +	queue = list_first_entry(&ptp->tsevqs, struct timestamp_event_queue,
> +				 qlist);
> +
>  	if (cnt % sizeof(struct ptp_extts_event) != 0)
>  		return -EINVAL;
>  
> diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
> index 80f74e38c2da..7ac04a282ec5 100644
> --- a/drivers/ptp/ptp_clock.c
> +++ b/drivers/ptp/ptp_clock.c
> @@ -166,6 +166,18 @@ static struct posix_clock_operations ptp_clock_ops = {
>  	.read		= ptp_read,
>  };
>  
> +static void ptp_clean_queue_list(struct ptp_clock *ptp)
> +{
> +	struct timestamp_event_queue *element;
> +	struct list_head *pos;
> +
> +	list_for_each(pos, &ptp->tsevqs) {

Here it should be list_for_each_safe().

> +		element = list_entry(pos, struct timestamp_event_queue, qlist);
> +		list_del(pos);
> +		kfree(element);
> +	}
> +}
> +
>  static void ptp_clock_release(struct device *dev)
>  {
>  	struct ptp_clock *ptp = container_of(dev, struct ptp_clock, dev);
> @@ -175,6 +187,7 @@ static void ptp_clock_release(struct device *dev)
>  	mutex_destroy(&ptp->tsevq_mux);
>  	mutex_destroy(&ptp->pincfg_mux);
>  	mutex_destroy(&ptp->n_vclocks_mux);
> +	ptp_clean_queue_list(ptp);
>  	ida_free(&ptp_clocks_map, ptp->index);
>  	kfree(ptp);
>  }
> @@ -206,6 +219,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 +242,13 @@ 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);
> +	/* TODO - Transform or delete this mutex */
>  	mutex_init(&ptp->tsevq_mux);
>  	mutex_init(&ptp->pincfg_mux);
>  	mutex_init(&ptp->n_vclocks_mux);
> @@ -333,6 +353,8 @@ 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);
> +	ptp_clean_queue_list(ptp);
> +no_memory_queue:
>  	ida_free(&ptp_clocks_map, index);
>  no_slot:
>  	kfree(ptp);
> @@ -375,6 +397,7 @@ EXPORT_SYMBOL(ptp_clock_unregister);
>  
>  void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event)
>  {
> +	struct timestamp_event_queue *tsevq, *tsevq_alt;
>  	struct pps_event_time evt;
>  
>  	switch (event->type) {
> @@ -383,7 +406,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 other queues */
> +		list_for_each_entry_safe(tsevq, tsevq_alt, &ptp->tsevqs, qlist) {

The _safe() version is for when the "pos" entry can be removed inside
the loop. No need to use it here.

> +			enqueue_external_timestamp(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..314c21c39f6a 100644
> --- a/drivers/ptp/ptp_private.h
> +++ b/drivers/ptp/ptp_private.h
> @@ -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;
> diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c
> index 6e4d5456a885..2675f383cd0a 100644
> --- a/drivers/ptp/ptp_sysfs.c
> +++ b/drivers/ptp/ptp_sysfs.c
> @@ -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))
> -- 
> 2.34.1
>
>
Jiri Pirko Sept. 13, 2023, 7:56 a.m. UTC | #2
Wed, Sep 13, 2023 at 12:02:15AM CEST, reibax@gmail.com wrote:
>This is the first of a set of patches to introduce linked lists to the

You are talking about a set, please introduce a cover letter and do it
there. Let the individual patch descriptions apply only for the
individual patches.


>timestamp event queue. The final goal is to be able to have multiple
>readers for the timestamp queue.
>
>On this one we maintain the original feature set, and we just introduce
>the linked lists to the data structure.
>
>Signed-off-by: Xabier Marquiegui <reibax@gmail.com>
>Suggested-by: Richard Cochran <richardcochran@gmail.com>
Richard Cochran Sept. 14, 2023, 2:21 p.m. UTC | #3
On Wed, Sep 13, 2023 at 12:02:15AM +0200, Xabier Marquiegui wrote:
> This is the first of a set of patches to introduce linked lists to the
> timestamp event queue. The final goal is to be able to have multiple
> readers for the timestamp queue.
> 
> On this one we maintain the original feature set, and we just introduce
> the linked lists to the data structure.
> 
> Signed-off-by: Xabier Marquiegui <reibax@gmail.com>
> Suggested-by: Richard Cochran <richardcochran@gmail.com>
> ---
> v2:
>   - Style changes to comform to checkpatch strict suggestions
> v1: https://lore.kernel.org/netdev/20230906104754.1324412-2-reibax@gmail.com/

Overall this is much improved.  Still as Vinicius pointed out, there
are a couple of issues to be addressed:

- open file tracking
- list handling

Thanks,
Richard
kernel test robot Sept. 20, 2023, 3:40 p.m. UTC | #4
Hello,

kernel test robot noticed "general protection fault" on:

commit: eb1ea1d74fb2741a0ca47a38e38ba338b45ed791 ("[PATCH net-next v2 1/3] ptp: Replace timestamp event queue with linked list")
url: https://github.com/intel-lab-lkp/linux/commits/Xabier-Marquiegui/ptp-support-multiple-timestamp-event-readers/20230913-060341
base: https://git.kernel.org/cgit/linux/kernel/git/davem/net-next.git 8fc8911b66962c6ff4345e7000930a4bcc54ae5a
patch link: https://lore.kernel.org/all/20230912220217.2008895-1-reibax@gmail.com/
patch subject: [PATCH net-next v2 1/3] ptp: Replace timestamp event queue with linked list

in testcase: filebench
version: filebench-x86_64-22620e6-1_20221010
with following parameters:

	disk: 1HDD
	fs: ext4
	test: singlestreamwritedirect.f
	cpufreq_governor: performance



compiler: gcc-12
test machine: 96 threads 2 sockets (Ice Lake) with 128G memory



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 <oliver.sang@intel.com>
| Closes: https://lore.kernel.org/oe-lkp/202309202333.970afc72-oliver.sang@intel.com


due to some parse issue, we didn't capture full dmesg as a file, below is what
we captured from serial, FYI.


[   28.880910][    T1] general protection fault, probably for non-canonical address 0xdead000000000100: 0000 [#1] SMP NOPTI
[   28.891775][    T1] CPU: 95 PID: 1 Comm: swapper/0 Not tainted 6.5.0-12684-geb1ea1d74fb2 #1
[   28.900126][    T1] RIP: 0010:__list_del_entry_valid_or_report+0x4/0xf0
[   28.906746][    T1] Code: 00 00 66 66 2e 0f 1f 84 00 00 00 00 00 66 0f 1f 84 00 00 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa <48> 8b 17
 48 8b 4f 08 48 85 d2 74 3e 48 85 c9 74 4a 48 b8 00 01 00
[   28.926184][    T1] RSP: 0000:ffa000000014bbe8 EFLAGS: 00010283
[   28.932102][    T1] RAX: 0000000000031670 RBX: dead000000000100 RCX: 0000000000000000
[   28.939928][    T1] RDX: 0000000000000001 RSI: ffd4000061e82200 RDI: dead000000000100
[   28.947753][    T1] RBP: deacfffffffff0f0 R08: 0000000000000282 R09: ffffffff81c05b01
[   28.955580][    T1] R10: ff1100187a088000 R11: 0000000000000001 R12: ff110001c7a033f0
[   28.963402][    T1] R13: dead000000000122 R14: dead000000000100 R15: 0000000000000001
[   28.971220][    T1] FS:  0000000000000000(0000) GS:ff110020127c0000(0000) knlGS:0000000000000000
[   28.979999][    T1] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   28.986438][    T1] CR2: 0000000000000000 CR3: 000000206ea18001 CR4: 0000000000771ee0
[   28.994264][    T1] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   29.002088][    T1] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[   29.009914][    T1] PKRU: 55555554
[   29.013317][    T1] Call Trace:
[   29.016456][    T1]  <TASK>
[   29.019245][    T1]  ? die_addr+0x36/0xb0
[   29.023259][    T1]  ? exc_general_protection+0x19d/0x3b0
[   29.028659][    T1]  ? asm_exc_general_protection+0x26/0x30
[   29.034228][    T1]  ? ptp_clean_queue_list+0x31/0xb0
[   29.039283][    T1]  ? __list_del_entry_valid_or_report+0x4/0xf0
[   29.045287][    T1]  ptp_clean_queue_list+0x43/0xb0
[   29.050166][    T1]  ptp_clock_release+0x31/0x70
[   29.054787][    T1]  device_release+0x34/0xb0
[   29.059151][    T1]  kobject_cleanup+0x39/0x130
[   29.063684][    T1]  ptp_clock_unregister+0x93/0xf0
[   29.068564][    T1]  ixgbe_ptp_stop+0x23/0x70
[   29.072924][    T1]  ixgbe_close+0x23/0x130
[   29.077110][    T1]  __dev_close_many+0x9b/0x130
[   29.081736][    T1]  __dev_change_flags+0x1aa/0x270
[   29.086614][    T1]  dev_change_flags+0x26/0x70
[   29.091147][    T1]  ic_close_devs+0x64/0x130
[   29.095507][    T1]  ip_auto_config+0x458/0x5f0
[   29.100040][    T1]  ? __pfx_ip_auto_config+0x10/0x10
[   29.105090][    T1]  do_one_initcall+0x5a/0x2f0
[   29.109623][    T1]  do_initcalls+0xc6/0x170
[   29.113895][    T1]  kernel_init_freeable+0x25c/0x330
[   29.118948][    T1]  ? __pfx_kernel_init+0x10/0x10
[   29.123738][    T1]  kernel_init+0x1a/0x1f0
[   29.127925][    T1]  ret_from_fork+0x31/0x70
[   29.132197][    T1]  ? __pfx_kernel_init+0x10/0x10
[   29.136990][    T1]  ret_from_fork_asm+0x1b/0x30
[   29.141610][    T1]  </TASK>
[   29.144496][    T1] Modules linked in:
[   29.148255][    T1] ---[ end trace 0000000000000000 ]---
[   29.163209][    T1] pstore: backend (erst) writing error (-28)
[   29.169045][    T1] RIP: 0010:__list_del_entry_valid_or_report+0x4/0xf0
[   29.175657][    T1] Code: 00 00 66 66 2e 0f 1f 84 00 00 00 00 00 66 0f 1f 84 00 00 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa <48> 8b 17
 48 8b 4f 08 48 85 d2 74 3e 48 85 c9 74 4a 48 b8 00 01 00
[   29.195100][    T1] RSP: 0000:ffa000000014bbe8 EFLAGS: 00010283
[   29.201014][    T1] RAX: 0000000000031670 RBX: dead000000000100 RCX: 0000000000000000
[   29.208842][    T1] RDX: 0000000000000001 RSI: ffd4000061e82200 RDI: dead000000000100
[   29.216667][    T1] RBP: deacfffffffff0f0 R08: 0000000000000282 R09: ffffffff81c05b01
[   29.224490][    T1] R10: ff1100187a088000 R11: 0000000000000001 R12: ff110001c7a033f0
[   29.232315][    T1] R13: dead000000000122 R14: dead000000000100 R15: 0000000000000001
[   29.240140][    T1] FS:  0000000000000000(0000) GS:ff110020127c0000(0000) knlGS:0000000000000000
[   29.248919][    T1] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   29.255357][    T1] CR2: 0000000000000000 CR3: 000000206ea18001 CR4: 0000000000771ee0
[   29.263176][    T1] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   29.271002][    T1] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[   29.278827][    T1] PKRU: 55555554
[   29.282233][    T1] Kernel panic - not syncing: Fatal exception
[   29.288254][    T1] Kernel Offset: disabled
diff mbox series

Patch

diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c
index 362bf756e6b7..197edf1179f1 100644
--- a/drivers/ptp/ptp_chardev.c
+++ b/drivers/ptp/ptp_chardev.c
@@ -435,10 +435,16 @@  long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
 __poll_t ptp_poll(struct posix_clock *pc, struct file *fp, poll_table *wait)
 {
 	struct ptp_clock *ptp = container_of(pc, 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
+	 * TODO: Identify the relevant queue
+	 */
+	queue = list_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))
@@ -447,12 +453,18 @@  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);
-	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
+	 * TODO: Identify the relevant queue
+	 */
+	queue = list_first_entry(&ptp->tsevqs, struct timestamp_event_queue,
+				 qlist);
+
 	if (cnt % sizeof(struct ptp_extts_event) != 0)
 		return -EINVAL;
 
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index 80f74e38c2da..7ac04a282ec5 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -166,6 +166,18 @@  static struct posix_clock_operations ptp_clock_ops = {
 	.read		= ptp_read,
 };
 
+static void ptp_clean_queue_list(struct ptp_clock *ptp)
+{
+	struct timestamp_event_queue *element;
+	struct list_head *pos;
+
+	list_for_each(pos, &ptp->tsevqs) {
+		element = list_entry(pos, struct timestamp_event_queue, qlist);
+		list_del(pos);
+		kfree(element);
+	}
+}
+
 static void ptp_clock_release(struct device *dev)
 {
 	struct ptp_clock *ptp = container_of(dev, struct ptp_clock, dev);
@@ -175,6 +187,7 @@  static void ptp_clock_release(struct device *dev)
 	mutex_destroy(&ptp->tsevq_mux);
 	mutex_destroy(&ptp->pincfg_mux);
 	mutex_destroy(&ptp->n_vclocks_mux);
+	ptp_clean_queue_list(ptp);
 	ida_free(&ptp_clocks_map, ptp->index);
 	kfree(ptp);
 }
@@ -206,6 +219,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 +242,13 @@  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);
+	/* TODO - Transform or delete this mutex */
 	mutex_init(&ptp->tsevq_mux);
 	mutex_init(&ptp->pincfg_mux);
 	mutex_init(&ptp->n_vclocks_mux);
@@ -333,6 +353,8 @@  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);
+	ptp_clean_queue_list(ptp);
+no_memory_queue:
 	ida_free(&ptp_clocks_map, index);
 no_slot:
 	kfree(ptp);
@@ -375,6 +397,7 @@  EXPORT_SYMBOL(ptp_clock_unregister);
 
 void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event)
 {
+	struct timestamp_event_queue *tsevq, *tsevq_alt;
 	struct pps_event_time evt;
 
 	switch (event->type) {
@@ -383,7 +406,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 other queues */
+		list_for_each_entry_safe(tsevq, tsevq_alt, &ptp->tsevqs, qlist) {
+			enqueue_external_timestamp(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..314c21c39f6a 100644
--- a/drivers/ptp/ptp_private.h
+++ b/drivers/ptp/ptp_private.h
@@ -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;
diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c
index 6e4d5456a885..2675f383cd0a 100644
--- a/drivers/ptp/ptp_sysfs.c
+++ b/drivers/ptp/ptp_sysfs.c
@@ -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))