cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ptp_chardev.c (12554B)


      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}