diff options
Diffstat (limited to 'drivers/ptp/ptp_clock.c')
-rw-r--r-- | drivers/ptp/ptp_clock.c | 66 |
1 files changed, 43 insertions, 23 deletions
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index 15b804ba48..c56cd0f639 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -4,7 +4,6 @@ * * Copyright (C) 2010 OMICRON electronics GmbH */ -#include <linux/idr.h> #include <linux/device.h> #include <linux/err.h> #include <linux/init.h> @@ -16,6 +15,7 @@ #include <linux/syscalls.h> #include <linux/uaccess.h> #include <linux/debugfs.h> +#include <linux/xarray.h> #include <uapi/linux/sched/types.h> #include "ptp_private.h" @@ -25,13 +25,16 @@ #define PTP_PPS_EVENT PPS_CAPTUREASSERT #define PTP_PPS_MODE (PTP_PPS_DEFAULTS | PPS_CANWAIT | PPS_TSFMT_TSPEC) -struct class *ptp_class; +const struct class ptp_class = { + .name = "ptp", + .dev_groups = ptp_groups +}; /* private globals */ static dev_t ptp_devt; -static DEFINE_IDA(ptp_clocks_map); +static DEFINE_XARRAY_ALLOC(ptp_clocks_map); /* time stamp event queue operations */ @@ -44,18 +47,31 @@ static void enqueue_external_timestamp(struct timestamp_event_queue *queue, struct ptp_clock_event *src) { struct ptp_extts_event *dst; + struct timespec64 offset_ts; unsigned long flags; s64 seconds; u32 remainder; - seconds = div_u64_rem(src->timestamp, 1000000000, &remainder); + if (src->type == PTP_CLOCK_EXTTS) { + seconds = div_u64_rem(src->timestamp, 1000000000, &remainder); + } else if (src->type == PTP_CLOCK_EXTOFF) { + offset_ts = ns_to_timespec64(src->offset); + seconds = offset_ts.tv_sec; + remainder = offset_ts.tv_nsec; + } else { + WARN(1, "%s: unknown type %d\n", __func__, src->type); + return; + } spin_lock_irqsave(&queue->lock, flags); dst = &queue->buf[queue->tail]; dst->index = src->index; + dst->flags = PTP_EXTTS_EVENT_VALID; dst->t.sec = seconds; dst->t.nsec = remainder; + if (src->type == PTP_CLOCK_EXTOFF) + dst->flags |= PTP_EXT_OFFSET; /* Both WRITE_ONCE() are paired with READ_ONCE() in queue_cnt() */ if (!queue_free(queue)) @@ -188,7 +204,7 @@ static void ptp_clock_release(struct device *dev) bitmap_free(tsevq->mask); kfree(tsevq); debugfs_remove(ptp->debugfs_root); - ida_free(&ptp_clocks_map, ptp->index); + xa_erase(&ptp_clocks_map, ptp->index); kfree(ptp); } @@ -220,7 +236,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); + int err, index, major = MAJOR(ptp_devt); char debugfsname[16]; size_t size; @@ -228,16 +244,16 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, return ERR_PTR(-EINVAL); /* Initialize a clock structure. */ - err = -ENOMEM; ptp = kzalloc(sizeof(struct ptp_clock), GFP_KERNEL); - if (ptp == NULL) + if (!ptp) { + err = -ENOMEM; goto no_memory; + } - index = ida_alloc_max(&ptp_clocks_map, MINORMASK, GFP_KERNEL); - if (index < 0) { - err = index; + err = xa_alloc(&ptp_clocks_map, &index, ptp, xa_limit_31b, + GFP_KERNEL); + if (err) goto no_slot; - } ptp->clock.ops = ptp_clock_ops; ptp->info = info; @@ -245,13 +261,17 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, ptp->index = index; INIT_LIST_HEAD(&ptp->tsevqs); queue = kzalloc(sizeof(*queue), GFP_KERNEL); - if (!queue) + if (!queue) { + err = -ENOMEM; goto no_memory_queue; + } list_add_tail(&queue->qlist, &ptp->tsevqs); spin_lock_init(&ptp->tsevqs_lock); queue->mask = bitmap_alloc(PTP_MAX_CHANNELS, GFP_KERNEL); - if (!queue->mask) + if (!queue->mask) { + err = -ENOMEM; goto no_memory_bitmap; + } bitmap_set(queue->mask, 0, PTP_MAX_CHANNELS); spin_lock_init(&queue->lock); mutex_init(&ptp->pincfg_mux); @@ -322,7 +342,7 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, /* Initialize a new device of our class in our clock structure. */ device_initialize(&ptp->dev); ptp->dev.devt = ptp->devid; - ptp->dev.class = ptp_class; + ptp->dev.class = &ptp_class; ptp->dev.parent = parent; ptp->dev.groups = ptp->pin_attr_groups; ptp->dev.release = ptp_clock_release; @@ -365,7 +385,7 @@ no_memory_bitmap: list_del(&queue->qlist); kfree(queue); no_memory_queue: - ida_free(&ptp_clocks_map, index); + xa_erase(&ptp_clocks_map, index); no_slot: kfree(ptp); no_memory: @@ -417,6 +437,7 @@ void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event) break; case PTP_CLOCK_EXTTS: + case PTP_CLOCK_EXTOFF: /* Enqueue timestamp on selected queues */ spin_lock_irqsave(&ptp->tsevqs_lock, flags); list_for_each_entry(tsevq, &ptp->tsevqs, qlist) { @@ -495,19 +516,19 @@ EXPORT_SYMBOL(ptp_cancel_worker_sync); static void __exit ptp_exit(void) { - class_destroy(ptp_class); + class_unregister(&ptp_class); unregister_chrdev_region(ptp_devt, MINORMASK + 1); - ida_destroy(&ptp_clocks_map); + xa_destroy(&ptp_clocks_map); } static int __init ptp_init(void) { int err; - ptp_class = class_create("ptp"); - if (IS_ERR(ptp_class)) { + err = class_register(&ptp_class); + if (err) { pr_err("ptp: failed to allocate class\n"); - return PTR_ERR(ptp_class); + return err; } err = alloc_chrdev_region(&ptp_devt, 0, MINORMASK + 1, "ptp"); @@ -516,12 +537,11 @@ static int __init ptp_init(void) goto no_region; } - ptp_class->dev_groups = ptp_groups; pr_info("PTP clock support registered\n"); return 0; no_region: - class_destroy(ptp_class); + class_unregister(&ptp_class); return err; } |