linux/drivers/ptp/ptp_chardev.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * PTP 1588 clock support - character device implementation.
   4 *
   5 * Copyright (C) 2010 OMICRON electronics GmbH
   6 */
   7#include <linux/module.h>
   8#include <linux/posix-clock.h>
   9#include <linux/poll.h>
  10#include <linux/sched.h>
  11#include <linux/slab.h>
  12#include <linux/timekeeping.h>
  13
  14#include <linux/nospec.h>
  15
  16#include "ptp_private.h"
  17
  18static int ptp_disable_pinfunc(struct ptp_clock_info *ops,
  19                               enum ptp_pin_function func, unsigned int chan)
  20{
  21        struct ptp_clock_request rq;
  22        int err = 0;
  23
  24        memset(&rq, 0, sizeof(rq));
  25
  26        switch (func) {
  27        case PTP_PF_NONE:
  28                break;
  29        case PTP_PF_EXTTS:
  30                rq.type = PTP_CLK_REQ_EXTTS;
  31                rq.extts.index = chan;
  32                err = ops->enable(ops, &rq, 0);
  33                break;
  34        case PTP_PF_PEROUT:
  35                rq.type = PTP_CLK_REQ_PEROUT;
  36                rq.perout.index = chan;
  37                err = ops->enable(ops, &rq, 0);
  38                break;
  39        case PTP_PF_PHYSYNC:
  40                break;
  41        default:
  42                return -EINVAL;
  43        }
  44
  45        return err;
  46}
  47
  48int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin,
  49                    enum ptp_pin_function func, unsigned int chan)
  50{
  51        struct ptp_clock_info *info = ptp->info;
  52        struct ptp_pin_desc *pin1 = NULL, *pin2 = &info->pin_config[pin];
  53        unsigned int i;
  54
  55        /* Check to see if any other pin previously had this function. */
  56        for (i = 0; i < info->n_pins; i++) {
  57                if (info->pin_config[i].func == func &&
  58                    info->pin_config[i].chan == chan) {
  59                        pin1 = &info->pin_config[i];
  60                        break;
  61                }
  62        }
  63        if (pin1 && i == pin)
  64                return 0;
  65
  66        /* Check the desired function and channel. */
  67        switch (func) {
  68        case PTP_PF_NONE:
  69                break;
  70        case PTP_PF_EXTTS:
  71                if (chan >= info->n_ext_ts)
  72                        return -EINVAL;
  73                break;
  74        case PTP_PF_PEROUT:
  75                if (chan >= info->n_per_out)
  76                        return -EINVAL;
  77                break;
  78        case PTP_PF_PHYSYNC:
  79                if (chan != 0)
  80                        return -EINVAL;
  81                break;
  82        default:
  83                return -EINVAL;
  84        }
  85
  86        if (info->verify(info, pin, func, chan)) {
  87                pr_err("driver cannot use function %u on pin %u\n", func, chan);
  88                return -EOPNOTSUPP;
  89        }
  90
  91        /* Disable whatever function was previously assigned. */
  92        if (pin1) {
  93                ptp_disable_pinfunc(info, func, chan);
  94                pin1->func = PTP_PF_NONE;
  95                pin1->chan = 0;
  96        }
  97        ptp_disable_pinfunc(info, pin2->func, pin2->chan);
  98        pin2->func = func;
  99        pin2->chan = chan;
 100
 101        return 0;
 102}
 103
 104int ptp_open(struct posix_clock *pc, fmode_t fmode)
 105{
 106        return 0;
 107}
 108
 109long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
 110{
 111        struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
 112        struct ptp_sys_offset_extended *extoff = NULL;
 113        struct ptp_sys_offset_precise precise_offset;
 114        struct system_device_crosststamp xtstamp;
 115        struct ptp_clock_info *ops = ptp->info;
 116        struct ptp_sys_offset *sysoff = NULL;
 117        struct ptp_system_timestamp sts;
 118        struct ptp_clock_request req;
 119        struct ptp_clock_caps caps;
 120        struct ptp_clock_time *pct;
 121        unsigned int i, pin_index;
 122        struct ptp_pin_desc pd;
 123        struct timespec64 ts;
 124        int enable, err = 0;
 125
 126        switch (cmd) {
 127
 128        case PTP_CLOCK_GETCAPS:
 129        case PTP_CLOCK_GETCAPS2:
 130                memset(&caps, 0, sizeof(caps));
 131
 132                caps.max_adj = ptp->info->max_adj;
 133                caps.n_alarm = ptp->info->n_alarm;
 134                caps.n_ext_ts = ptp->info->n_ext_ts;
 135                caps.n_per_out = ptp->info->n_per_out;
 136                caps.pps = ptp->info->pps;
 137                caps.n_pins = ptp->info->n_pins;
 138                caps.cross_timestamping = ptp->info->getcrosststamp != NULL;
 139                caps.adjust_phase = ptp->info->adjphase != NULL;
 140                if (copy_to_user((void __user *)arg, &caps, sizeof(caps)))
 141                        err = -EFAULT;
 142                break;
 143
 144        case PTP_EXTTS_REQUEST:
 145        case PTP_EXTTS_REQUEST2:
 146                memset(&req, 0, sizeof(req));
 147
 148                if (copy_from_user(&req.extts, (void __user *)arg,
 149                                   sizeof(req.extts))) {
 150                        err = -EFAULT;
 151                        break;
 152                }
 153                if (cmd == PTP_EXTTS_REQUEST2) {
 154                        /* Tell the drivers to check the flags carefully. */
 155                        req.extts.flags |= PTP_STRICT_FLAGS;
 156                        /* Make sure no reserved bit is set. */
 157                        if ((req.extts.flags & ~PTP_EXTTS_VALID_FLAGS) ||
 158                            req.extts.rsv[0] || req.extts.rsv[1]) {
 159                                err = -EINVAL;
 160                                break;
 161                        }
 162                        /* Ensure one of the rising/falling edge bits is set. */
 163                        if ((req.extts.flags & PTP_ENABLE_FEATURE) &&
 164                            (req.extts.flags & PTP_EXTTS_EDGES) == 0) {
 165                                err = -EINVAL;
 166                                break;
 167                        }
 168                } else if (cmd == PTP_EXTTS_REQUEST) {
 169                        req.extts.flags &= PTP_EXTTS_V1_VALID_FLAGS;
 170                        req.extts.rsv[0] = 0;
 171                        req.extts.rsv[1] = 0;
 172                }
 173                if (req.extts.index >= ops->n_ext_ts) {
 174                        err = -EINVAL;
 175                        break;
 176                }
 177                req.type = PTP_CLK_REQ_EXTTS;
 178                enable = req.extts.flags & PTP_ENABLE_FEATURE ? 1 : 0;
 179                if (mutex_lock_interruptible(&ptp->pincfg_mux))
 180                        return -ERESTARTSYS;
 181                err = ops->enable(ops, &req, enable);
 182                mutex_unlock(&ptp->pincfg_mux);
 183                break;
 184
 185        case PTP_PEROUT_REQUEST:
 186        case PTP_PEROUT_REQUEST2:
 187                memset(&req, 0, sizeof(req));
 188
 189                if (copy_from_user(&req.perout, (void __user *)arg,
 190                                   sizeof(req.perout))) {
 191                        err = -EFAULT;
 192                        break;
 193                }
 194                if (cmd == PTP_PEROUT_REQUEST2) {
 195                        struct ptp_perout_request *perout = &req.perout;
 196
 197                        if (perout->flags & ~PTP_PEROUT_VALID_FLAGS) {
 198                                err = -EINVAL;
 199                                break;
 200                        }
 201                        /*
 202                         * The "on" field has undefined meaning if
 203                         * PTP_PEROUT_DUTY_CYCLE isn't set, we must still treat
 204                         * it as reserved, which must be set to zero.
 205                         */
 206                        if (!(perout->flags & PTP_PEROUT_DUTY_CYCLE) &&
 207                            (perout->rsv[0] || perout->rsv[1] ||
 208                             perout->rsv[2] || perout->rsv[3])) {
 209                                err = -EINVAL;
 210                                break;
 211                        }
 212                        if (perout->flags & PTP_PEROUT_DUTY_CYCLE) {
 213                                /* The duty cycle must be subunitary. */
 214                                if (perout->on.sec > perout->period.sec ||
 215                                    (perout->on.sec == perout->period.sec &&
 216                                     perout->on.nsec > perout->period.nsec)) {
 217                                        err = -ERANGE;
 218                                        break;
 219                                }
 220                        }
 221                        if (perout->flags & PTP_PEROUT_PHASE) {
 222                                /*
 223                                 * The phase should be specified modulo the
 224                                 * period, therefore anything equal or larger
 225                                 * than 1 period is invalid.
 226                                 */
 227                                if (perout->phase.sec > perout->period.sec ||
 228                                    (perout->phase.sec == perout->period.sec &&
 229                                     perout->phase.nsec >= perout->period.nsec)) {
 230                                        err = -ERANGE;
 231                                        break;
 232                                }
 233                        }
 234                } else if (cmd == PTP_PEROUT_REQUEST) {
 235                        req.perout.flags &= PTP_PEROUT_V1_VALID_FLAGS;
 236                        req.perout.rsv[0] = 0;
 237                        req.perout.rsv[1] = 0;
 238                        req.perout.rsv[2] = 0;
 239                        req.perout.rsv[3] = 0;
 240                }
 241                if (req.perout.index >= ops->n_per_out) {
 242                        err = -EINVAL;
 243                        break;
 244                }
 245                req.type = PTP_CLK_REQ_PEROUT;
 246                enable = req.perout.period.sec || req.perout.period.nsec;
 247                if (mutex_lock_interruptible(&ptp->pincfg_mux))
 248                        return -ERESTARTSYS;
 249                err = ops->enable(ops, &req, enable);
 250                mutex_unlock(&ptp->pincfg_mux);
 251                break;
 252
 253        case PTP_ENABLE_PPS:
 254        case PTP_ENABLE_PPS2:
 255                memset(&req, 0, sizeof(req));
 256
 257                if (!capable(CAP_SYS_TIME))
 258                        return -EPERM;
 259                req.type = PTP_CLK_REQ_PPS;
 260                enable = arg ? 1 : 0;
 261                if (mutex_lock_interruptible(&ptp->pincfg_mux))
 262                        return -ERESTARTSYS;
 263                err = ops->enable(ops, &req, enable);
 264                mutex_unlock(&ptp->pincfg_mux);
 265                break;
 266
 267        case PTP_SYS_OFFSET_PRECISE:
 268        case PTP_SYS_OFFSET_PRECISE2:
 269                if (!ptp->info->getcrosststamp) {
 270                        err = -EOPNOTSUPP;
 271                        break;
 272                }
 273                err = ptp->info->getcrosststamp(ptp->info, &xtstamp);
 274                if (err)
 275                        break;
 276
 277                memset(&precise_offset, 0, sizeof(precise_offset));
 278                ts = ktime_to_timespec64(xtstamp.device);
 279                precise_offset.device.sec = ts.tv_sec;
 280                precise_offset.device.nsec = ts.tv_nsec;
 281                ts = ktime_to_timespec64(xtstamp.sys_realtime);
 282                precise_offset.sys_realtime.sec = ts.tv_sec;
 283                precise_offset.sys_realtime.nsec = ts.tv_nsec;
 284                ts = ktime_to_timespec64(xtstamp.sys_monoraw);
 285                precise_offset.sys_monoraw.sec = ts.tv_sec;
 286                precise_offset.sys_monoraw.nsec = ts.tv_nsec;
 287                if (copy_to_user((void __user *)arg, &precise_offset,
 288                                 sizeof(precise_offset)))
 289                        err = -EFAULT;
 290                break;
 291
 292        case PTP_SYS_OFFSET_EXTENDED:
 293        case PTP_SYS_OFFSET_EXTENDED2:
 294                if (!ptp->info->gettimex64) {
 295                        err = -EOPNOTSUPP;
 296                        break;
 297                }
 298                extoff = memdup_user((void __user *)arg, sizeof(*extoff));
 299                if (IS_ERR(extoff)) {
 300                        err = PTR_ERR(extoff);
 301                        extoff = NULL;
 302                        break;
 303                }
 304                if (extoff->n_samples > PTP_MAX_SAMPLES
 305                    || extoff->rsv[0] || extoff->rsv[1] || extoff->rsv[2]) {
 306                        err = -EINVAL;
 307                        break;
 308                }
 309                for (i = 0; i < extoff->n_samples; i++) {
 310                        err = ptp->info->gettimex64(ptp->info, &ts, &sts);
 311                        if (err)
 312                                goto out;
 313                        extoff->ts[i][0].sec = sts.pre_ts.tv_sec;
 314                        extoff->ts[i][0].nsec = sts.pre_ts.tv_nsec;
 315                        extoff->ts[i][1].sec = ts.tv_sec;
 316                        extoff->ts[i][1].nsec = ts.tv_nsec;
 317                        extoff->ts[i][2].sec = sts.post_ts.tv_sec;
 318                        extoff->ts[i][2].nsec = sts.post_ts.tv_nsec;
 319                }
 320                if (copy_to_user((void __user *)arg, extoff, sizeof(*extoff)))
 321                        err = -EFAULT;
 322                break;
 323
 324        case PTP_SYS_OFFSET:
 325        case PTP_SYS_OFFSET2:
 326                sysoff = memdup_user((void __user *)arg, sizeof(*sysoff));
 327                if (IS_ERR(sysoff)) {
 328                        err = PTR_ERR(sysoff);
 329                        sysoff = NULL;
 330                        break;
 331                }
 332                if (sysoff->n_samples > PTP_MAX_SAMPLES) {
 333                        err = -EINVAL;
 334                        break;
 335                }
 336                pct = &sysoff->ts[0];
 337                for (i = 0; i < sysoff->n_samples; i++) {
 338                        ktime_get_real_ts64(&ts);
 339                        pct->sec = ts.tv_sec;
 340                        pct->nsec = ts.tv_nsec;
 341                        pct++;
 342                        if (ops->gettimex64)
 343                                err = ops->gettimex64(ops, &ts, NULL);
 344                        else
 345                                err = ops->gettime64(ops, &ts);
 346                        if (err)
 347                                goto out;
 348                        pct->sec = ts.tv_sec;
 349                        pct->nsec = ts.tv_nsec;
 350                        pct++;
 351                }
 352                ktime_get_real_ts64(&ts);
 353                pct->sec = ts.tv_sec;
 354                pct->nsec = ts.tv_nsec;
 355                if (copy_to_user((void __user *)arg, sysoff, sizeof(*sysoff)))
 356                        err = -EFAULT;
 357                break;
 358
 359        case PTP_PIN_GETFUNC:
 360        case PTP_PIN_GETFUNC2:
 361                if (copy_from_user(&pd, (void __user *)arg, sizeof(pd))) {
 362                        err = -EFAULT;
 363                        break;
 364                }
 365                if ((pd.rsv[0] || pd.rsv[1] || pd.rsv[2]
 366                                || pd.rsv[3] || pd.rsv[4])
 367                        && cmd == PTP_PIN_GETFUNC2) {
 368                        err = -EINVAL;
 369                        break;
 370                } else if (cmd == PTP_PIN_GETFUNC) {
 371                        pd.rsv[0] = 0;
 372                        pd.rsv[1] = 0;
 373                        pd.rsv[2] = 0;
 374                        pd.rsv[3] = 0;
 375                        pd.rsv[4] = 0;
 376                }
 377                pin_index = pd.index;
 378                if (pin_index >= ops->n_pins) {
 379                        err = -EINVAL;
 380                        break;
 381                }
 382                pin_index = array_index_nospec(pin_index, ops->n_pins);
 383                if (mutex_lock_interruptible(&ptp->pincfg_mux))
 384                        return -ERESTARTSYS;
 385                pd = ops->pin_config[pin_index];
 386                mutex_unlock(&ptp->pincfg_mux);
 387                if (!err && copy_to_user((void __user *)arg, &pd, sizeof(pd)))
 388                        err = -EFAULT;
 389                break;
 390
 391        case PTP_PIN_SETFUNC:
 392        case PTP_PIN_SETFUNC2:
 393                if (copy_from_user(&pd, (void __user *)arg, sizeof(pd))) {
 394                        err = -EFAULT;
 395                        break;
 396                }
 397                if ((pd.rsv[0] || pd.rsv[1] || pd.rsv[2]
 398                                || pd.rsv[3] || pd.rsv[4])
 399                        && cmd == PTP_PIN_SETFUNC2) {
 400                        err = -EINVAL;
 401                        break;
 402                } else if (cmd == PTP_PIN_SETFUNC) {
 403                        pd.rsv[0] = 0;
 404                        pd.rsv[1] = 0;
 405                        pd.rsv[2] = 0;
 406                        pd.rsv[3] = 0;
 407                        pd.rsv[4] = 0;
 408                }
 409                pin_index = pd.index;
 410                if (pin_index >= ops->n_pins) {
 411                        err = -EINVAL;
 412                        break;
 413                }
 414                pin_index = array_index_nospec(pin_index, ops->n_pins);
 415                if (mutex_lock_interruptible(&ptp->pincfg_mux))
 416                        return -ERESTARTSYS;
 417                err = ptp_set_pinfunc(ptp, pin_index, pd.func, pd.chan);
 418                mutex_unlock(&ptp->pincfg_mux);
 419                break;
 420
 421        default:
 422                err = -ENOTTY;
 423                break;
 424        }
 425
 426out:
 427        kfree(extoff);
 428        kfree(sysoff);
 429        return err;
 430}
 431
 432__poll_t ptp_poll(struct posix_clock *pc, struct file *fp, poll_table *wait)
 433{
 434        struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
 435
 436        poll_wait(fp, &ptp->tsev_wq, wait);
 437
 438        return queue_cnt(&ptp->tsevq) ? EPOLLIN : 0;
 439}
 440
 441#define EXTTS_BUFSIZE (PTP_BUF_TIMESTAMPS * sizeof(struct ptp_extts_event))
 442
 443ssize_t ptp_read(struct posix_clock *pc,
 444                 uint rdflags, char __user *buf, size_t cnt)
 445{
 446        struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
 447        struct timestamp_event_queue *queue = &ptp->tsevq;
 448        struct ptp_extts_event *event;
 449        unsigned long flags;
 450        size_t qcnt, i;
 451        int result;
 452
 453        if (cnt % sizeof(struct ptp_extts_event) != 0)
 454                return -EINVAL;
 455
 456        if (cnt > EXTTS_BUFSIZE)
 457                cnt = EXTTS_BUFSIZE;
 458
 459        cnt = cnt / sizeof(struct ptp_extts_event);
 460
 461        if (mutex_lock_interruptible(&ptp->tsevq_mux))
 462                return -ERESTARTSYS;
 463
 464        if (wait_event_interruptible(ptp->tsev_wq,
 465                                     ptp->defunct || queue_cnt(queue))) {
 466                mutex_unlock(&ptp->tsevq_mux);
 467                return -ERESTARTSYS;
 468        }
 469
 470        if (ptp->defunct) {
 471                mutex_unlock(&ptp->tsevq_mux);
 472                return -ENODEV;
 473        }
 474
 475        event = kmalloc(EXTTS_BUFSIZE, GFP_KERNEL);
 476        if (!event) {
 477                mutex_unlock(&ptp->tsevq_mux);
 478                return -ENOMEM;
 479        }
 480
 481        spin_lock_irqsave(&queue->lock, flags);
 482
 483        qcnt = queue_cnt(queue);
 484
 485        if (cnt > qcnt)
 486                cnt = qcnt;
 487
 488        for (i = 0; i < cnt; i++) {
 489                event[i] = queue->buf[queue->head];
 490                queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS;
 491        }
 492
 493        spin_unlock_irqrestore(&queue->lock, flags);
 494
 495        cnt = cnt * sizeof(struct ptp_extts_event);
 496
 497        mutex_unlock(&ptp->tsevq_mux);
 498
 499        result = cnt;
 500        if (copy_to_user(buf, event, cnt))
 501                result = -EFAULT;
 502
 503        kfree(event);
 504        return result;
 505}
 506