Blame view

drivers/ptp/ptp_chardev.c 12.3 KB
74ba9207e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
d94ba80eb   Richard Cochran   ptp: Added a bran...
2
3
4
5
  /*
   * PTP 1588 clock support - character device implementation.
   *
   * Copyright (C) 2010 OMICRON electronics GmbH
d94ba80eb   Richard Cochran   ptp: Added a bran...
6
7
8
9
10
   */
  #include <linux/module.h>
  #include <linux/posix-clock.h>
  #include <linux/poll.h>
  #include <linux/sched.h>
c7ec0badc   Richard Cochran   ptp: reduce stack...
11
  #include <linux/slab.h>
719f1aa4a   Christopher S. Hall   ptp: Add PTP_SYS_...
12
  #include <linux/timekeeping.h>
d94ba80eb   Richard Cochran   ptp: Added a bran...
13

efa61c8cf   Gustavo A. R. Silva   ptp: fix Spectre ...
14
  #include <linux/nospec.h>
d94ba80eb   Richard Cochran   ptp: Added a bran...
15
  #include "ptp_private.h"
6092315df   Richard Cochran   ptp: introduce pr...
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
  static int ptp_disable_pinfunc(struct ptp_clock_info *ops,
  			       enum ptp_pin_function func, unsigned int chan)
  {
  	struct ptp_clock_request rq;
  	int err = 0;
  
  	memset(&rq, 0, sizeof(rq));
  
  	switch (func) {
  	case PTP_PF_NONE:
  		break;
  	case PTP_PF_EXTTS:
  		rq.type = PTP_CLK_REQ_EXTTS;
  		rq.extts.index = chan;
  		err = ops->enable(ops, &rq, 0);
  		break;
  	case PTP_PF_PEROUT:
  		rq.type = PTP_CLK_REQ_PEROUT;
  		rq.perout.index = chan;
  		err = ops->enable(ops, &rq, 0);
  		break;
  	case PTP_PF_PHYSYNC:
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	return err;
  }
  
  int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin,
  		    enum ptp_pin_function func, unsigned int chan)
  {
  	struct ptp_clock_info *info = ptp->info;
  	struct ptp_pin_desc *pin1 = NULL, *pin2 = &info->pin_config[pin];
  	unsigned int i;
  
  	/* Check to see if any other pin previously had this function. */
  	for (i = 0; i < info->n_pins; i++) {
  		if (info->pin_config[i].func == func &&
  		    info->pin_config[i].chan == chan) {
  			pin1 = &info->pin_config[i];
  			break;
  		}
  	}
  	if (pin1 && i == pin)
  		return 0;
  
  	/* Check the desired function and channel. */
  	switch (func) {
  	case PTP_PF_NONE:
  		break;
  	case PTP_PF_EXTTS:
  		if (chan >= info->n_ext_ts)
  			return -EINVAL;
  		break;
  	case PTP_PF_PEROUT:
  		if (chan >= info->n_per_out)
  			return -EINVAL;
  		break;
  	case PTP_PF_PHYSYNC:
72df7a724   Stefan Sørensen   ptp: Allow reassi...
77
78
  		if (chan != 0)
  			return -EINVAL;
9ba8376ce   Gustavo A. R. Silva   ptp: fix missing ...
79
  		break;
6092315df   Richard Cochran   ptp: introduce pr...
80
81
82
  	default:
  		return -EINVAL;
  	}
6092315df   Richard Cochran   ptp: introduce pr...
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  	if (info->verify(info, pin, func, chan)) {
  		pr_err("driver cannot use function %u on pin %u
  ", func, chan);
  		return -EOPNOTSUPP;
  	}
  
  	/* Disable whatever function was previously assigned. */
  	if (pin1) {
  		ptp_disable_pinfunc(info, func, chan);
  		pin1->func = PTP_PF_NONE;
  		pin1->chan = 0;
  	}
  	ptp_disable_pinfunc(info, pin2->func, pin2->chan);
  	pin2->func = func;
  	pin2->chan = chan;
  
  	return 0;
  }
d94ba80eb   Richard Cochran   ptp: Added a bran...
101
102
103
104
105
106
107
  int ptp_open(struct posix_clock *pc, fmode_t fmode)
  {
  	return 0;
  }
  
  long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
  {
d94ba80eb   Richard Cochran   ptp: Added a bran...
108
  	struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
361800876   Miroslav Lichvar   ptp: add PTP_SYS_...
109
  	struct ptp_sys_offset_extended *extoff = NULL;
fbb960ac2   Miroslav Lichvar   ptp: reorder decl...
110
111
  	struct ptp_sys_offset_precise precise_offset;
  	struct system_device_crosststamp xtstamp;
d94ba80eb   Richard Cochran   ptp: Added a bran...
112
  	struct ptp_clock_info *ops = ptp->info;
fbb960ac2   Miroslav Lichvar   ptp: reorder decl...
113
  	struct ptp_sys_offset *sysoff = NULL;
361800876   Miroslav Lichvar   ptp: add PTP_SYS_...
114
  	struct ptp_system_timestamp sts;
fbb960ac2   Miroslav Lichvar   ptp: reorder decl...
115
116
  	struct ptp_clock_request req;
  	struct ptp_clock_caps caps;
215b13dd2   Richard Cochran   ptp: add an ioctl...
117
  	struct ptp_clock_time *pct;
fbb960ac2   Miroslav Lichvar   ptp: reorder decl...
118
119
  	unsigned int i, pin_index;
  	struct ptp_pin_desc pd;
e13cfcb03   Richard Cochran   ptp: use the 64 b...
120
  	struct timespec64 ts;
d94ba80eb   Richard Cochran   ptp: Added a bran...
121
122
123
124
125
  	int enable, err = 0;
  
  	switch (cmd) {
  
  	case PTP_CLOCK_GETCAPS:
415606588   Felipe Balbi   PTP: introduce ne...
126
  	case PTP_CLOCK_GETCAPS2:
d94ba80eb   Richard Cochran   ptp: Added a bran...
127
  		memset(&caps, 0, sizeof(caps));
415606588   Felipe Balbi   PTP: introduce ne...
128

d94ba80eb   Richard Cochran   ptp: Added a bran...
129
130
131
132
133
  		caps.max_adj = ptp->info->max_adj;
  		caps.n_alarm = ptp->info->n_alarm;
  		caps.n_ext_ts = ptp->info->n_ext_ts;
  		caps.n_per_out = ptp->info->n_per_out;
  		caps.pps = ptp->info->pps;
6092315df   Richard Cochran   ptp: introduce pr...
134
  		caps.n_pins = ptp->info->n_pins;
719f1aa4a   Christopher S. Hall   ptp: Add PTP_SYS_...
135
  		caps.cross_timestamping = ptp->info->getcrosststamp != NULL;
d3f1cbd29   vincent cheng   ptp: Add adjust_p...
136
  		caps.adjust_phase = ptp->info->adjphase != NULL;
e23ef227d   Dan Carpenter   ptp: Return -EFAU...
137
138
  		if (copy_to_user((void __user *)arg, &caps, sizeof(caps)))
  			err = -EFAULT;
d94ba80eb   Richard Cochran   ptp: Added a bran...
139
140
141
  		break;
  
  	case PTP_EXTTS_REQUEST:
415606588   Felipe Balbi   PTP: introduce ne...
142
143
  	case PTP_EXTTS_REQUEST2:
  		memset(&req, 0, sizeof(req));
d94ba80eb   Richard Cochran   ptp: Added a bran...
144
145
146
147
148
  		if (copy_from_user(&req.extts, (void __user *)arg,
  				   sizeof(req.extts))) {
  			err = -EFAULT;
  			break;
  		}
cd734d54e   Richard Cochran   ptp: Validate req...
149
  		if (cmd == PTP_EXTTS_REQUEST2) {
6138e687c   Richard Cochran   ptp: Introduce st...
150
151
  			/* Tell the drivers to check the flags carefully. */
  			req.extts.flags |= PTP_STRICT_FLAGS;
cd734d54e   Richard Cochran   ptp: Validate req...
152
153
154
155
156
157
158
159
160
161
162
163
  			/* Make sure no reserved bit is set. */
  			if ((req.extts.flags & ~PTP_EXTTS_VALID_FLAGS) ||
  			    req.extts.rsv[0] || req.extts.rsv[1]) {
  				err = -EINVAL;
  				break;
  			}
  			/* Ensure one of the rising/falling edge bits is set. */
  			if ((req.extts.flags & PTP_ENABLE_FEATURE) &&
  			    (req.extts.flags & PTP_EXTTS_EDGES) == 0) {
  				err = -EINVAL;
  				break;
  			}
415606588   Felipe Balbi   PTP: introduce ne...
164
  		} else if (cmd == PTP_EXTTS_REQUEST) {
2df4de168   Jacob Keller   ptp: correctly di...
165
  			req.extts.flags &= PTP_EXTTS_V1_VALID_FLAGS;
415606588   Felipe Balbi   PTP: introduce ne...
166
167
168
  			req.extts.rsv[0] = 0;
  			req.extts.rsv[1] = 0;
  		}
d94ba80eb   Richard Cochran   ptp: Added a bran...
169
170
171
172
173
174
  		if (req.extts.index >= ops->n_ext_ts) {
  			err = -EINVAL;
  			break;
  		}
  		req.type = PTP_CLK_REQ_EXTTS;
  		enable = req.extts.flags & PTP_ENABLE_FEATURE ? 1 : 0;
62582a7ee   Richard Cochran   ptp: Avoid deadlo...
175
176
  		if (mutex_lock_interruptible(&ptp->pincfg_mux))
  			return -ERESTARTSYS;
d94ba80eb   Richard Cochran   ptp: Added a bran...
177
  		err = ops->enable(ops, &req, enable);
62582a7ee   Richard Cochran   ptp: Avoid deadlo...
178
  		mutex_unlock(&ptp->pincfg_mux);
d94ba80eb   Richard Cochran   ptp: Added a bran...
179
180
181
  		break;
  
  	case PTP_PEROUT_REQUEST:
415606588   Felipe Balbi   PTP: introduce ne...
182
183
  	case PTP_PEROUT_REQUEST2:
  		memset(&req, 0, sizeof(req));
d94ba80eb   Richard Cochran   ptp: Added a bran...
184
185
186
187
188
  		if (copy_from_user(&req.perout, (void __user *)arg,
  				   sizeof(req.perout))) {
  			err = -EFAULT;
  			break;
  		}
f65b71aa2   Vladimir Oltean   ptp: add ability ...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
  		if (cmd == PTP_PEROUT_REQUEST2) {
  			struct ptp_perout_request *perout = &req.perout;
  
  			if (perout->flags & ~PTP_PEROUT_VALID_FLAGS) {
  				err = -EINVAL;
  				break;
  			}
  			/*
  			 * The "on" field has undefined meaning if
  			 * PTP_PEROUT_DUTY_CYCLE isn't set, we must still treat
  			 * it as reserved, which must be set to zero.
  			 */
  			if (!(perout->flags & PTP_PEROUT_DUTY_CYCLE) &&
  			    (perout->rsv[0] || perout->rsv[1] ||
  			     perout->rsv[2] || perout->rsv[3])) {
  				err = -EINVAL;
  				break;
  			}
  			if (perout->flags & PTP_PEROUT_DUTY_CYCLE) {
  				/* The duty cycle must be subunitary. */
  				if (perout->on.sec > perout->period.sec ||
  				    (perout->on.sec == perout->period.sec &&
  				     perout->on.nsec > perout->period.nsec)) {
  					err = -ERANGE;
  					break;
  				}
  			}
c29f9aa35   Vladimir Oltean   ptp: only allow p...
216
217
218
219
220
221
222
223
224
225
226
227
228
  			if (perout->flags & PTP_PEROUT_PHASE) {
  				/*
  				 * The phase should be specified modulo the
  				 * period, therefore anything equal or larger
  				 * than 1 period is invalid.
  				 */
  				if (perout->phase.sec > perout->period.sec ||
  				    (perout->phase.sec == perout->period.sec &&
  				     perout->phase.nsec >= perout->period.nsec)) {
  					err = -ERANGE;
  					break;
  				}
  			}
415606588   Felipe Balbi   PTP: introduce ne...
229
  		} else if (cmd == PTP_PEROUT_REQUEST) {
2df4de168   Jacob Keller   ptp: correctly di...
230
  			req.perout.flags &= PTP_PEROUT_V1_VALID_FLAGS;
415606588   Felipe Balbi   PTP: introduce ne...
231
232
233
234
235
  			req.perout.rsv[0] = 0;
  			req.perout.rsv[1] = 0;
  			req.perout.rsv[2] = 0;
  			req.perout.rsv[3] = 0;
  		}
d94ba80eb   Richard Cochran   ptp: Added a bran...
236
237
238
239
240
241
  		if (req.perout.index >= ops->n_per_out) {
  			err = -EINVAL;
  			break;
  		}
  		req.type = PTP_CLK_REQ_PEROUT;
  		enable = req.perout.period.sec || req.perout.period.nsec;
62582a7ee   Richard Cochran   ptp: Avoid deadlo...
242
243
  		if (mutex_lock_interruptible(&ptp->pincfg_mux))
  			return -ERESTARTSYS;
d94ba80eb   Richard Cochran   ptp: Added a bran...
244
  		err = ops->enable(ops, &req, enable);
62582a7ee   Richard Cochran   ptp: Avoid deadlo...
245
  		mutex_unlock(&ptp->pincfg_mux);
d94ba80eb   Richard Cochran   ptp: Added a bran...
246
247
248
  		break;
  
  	case PTP_ENABLE_PPS:
415606588   Felipe Balbi   PTP: introduce ne...
249
250
  	case PTP_ENABLE_PPS2:
  		memset(&req, 0, sizeof(req));
d94ba80eb   Richard Cochran   ptp: Added a bran...
251
252
253
254
  		if (!capable(CAP_SYS_TIME))
  			return -EPERM;
  		req.type = PTP_CLK_REQ_PPS;
  		enable = arg ? 1 : 0;
62582a7ee   Richard Cochran   ptp: Avoid deadlo...
255
256
  		if (mutex_lock_interruptible(&ptp->pincfg_mux))
  			return -ERESTARTSYS;
d94ba80eb   Richard Cochran   ptp: Added a bran...
257
  		err = ops->enable(ops, &req, enable);
62582a7ee   Richard Cochran   ptp: Avoid deadlo...
258
  		mutex_unlock(&ptp->pincfg_mux);
d94ba80eb   Richard Cochran   ptp: Added a bran...
259
  		break;
719f1aa4a   Christopher S. Hall   ptp: Add PTP_SYS_...
260
  	case PTP_SYS_OFFSET_PRECISE:
415606588   Felipe Balbi   PTP: introduce ne...
261
  	case PTP_SYS_OFFSET_PRECISE2:
719f1aa4a   Christopher S. Hall   ptp: Add PTP_SYS_...
262
263
264
265
266
267
268
  		if (!ptp->info->getcrosststamp) {
  			err = -EOPNOTSUPP;
  			break;
  		}
  		err = ptp->info->getcrosststamp(ptp->info, &xtstamp);
  		if (err)
  			break;
02a9079c6   Vlad Tsyrklevich   drivers/ptp: Fix ...
269
  		memset(&precise_offset, 0, sizeof(precise_offset));
719f1aa4a   Christopher S. Hall   ptp: Add PTP_SYS_...
270
271
272
273
274
275
276
277
278
279
280
281
282
  		ts = ktime_to_timespec64(xtstamp.device);
  		precise_offset.device.sec = ts.tv_sec;
  		precise_offset.device.nsec = ts.tv_nsec;
  		ts = ktime_to_timespec64(xtstamp.sys_realtime);
  		precise_offset.sys_realtime.sec = ts.tv_sec;
  		precise_offset.sys_realtime.nsec = ts.tv_nsec;
  		ts = ktime_to_timespec64(xtstamp.sys_monoraw);
  		precise_offset.sys_monoraw.sec = ts.tv_sec;
  		precise_offset.sys_monoraw.nsec = ts.tv_nsec;
  		if (copy_to_user((void __user *)arg, &precise_offset,
  				 sizeof(precise_offset)))
  			err = -EFAULT;
  		break;
361800876   Miroslav Lichvar   ptp: add PTP_SYS_...
283
  	case PTP_SYS_OFFSET_EXTENDED:
415606588   Felipe Balbi   PTP: introduce ne...
284
  	case PTP_SYS_OFFSET_EXTENDED2:
361800876   Miroslav Lichvar   ptp: add PTP_SYS_...
285
286
287
288
289
290
291
292
293
294
  		if (!ptp->info->gettimex64) {
  			err = -EOPNOTSUPP;
  			break;
  		}
  		extoff = memdup_user((void __user *)arg, sizeof(*extoff));
  		if (IS_ERR(extoff)) {
  			err = PTR_ERR(extoff);
  			extoff = NULL;
  			break;
  		}
895ac1376   Eugene Syromiatnikov   ptp: check that r...
295
296
  		if (extoff->n_samples > PTP_MAX_SAMPLES
  		    || extoff->rsv[0] || extoff->rsv[1] || extoff->rsv[2]) {
361800876   Miroslav Lichvar   ptp: add PTP_SYS_...
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
  			err = -EINVAL;
  			break;
  		}
  		for (i = 0; i < extoff->n_samples; i++) {
  			err = ptp->info->gettimex64(ptp->info, &ts, &sts);
  			if (err)
  				goto out;
  			extoff->ts[i][0].sec = sts.pre_ts.tv_sec;
  			extoff->ts[i][0].nsec = sts.pre_ts.tv_nsec;
  			extoff->ts[i][1].sec = ts.tv_sec;
  			extoff->ts[i][1].nsec = ts.tv_nsec;
  			extoff->ts[i][2].sec = sts.post_ts.tv_sec;
  			extoff->ts[i][2].nsec = sts.post_ts.tv_nsec;
  		}
  		if (copy_to_user((void __user *)arg, extoff, sizeof(*extoff)))
  			err = -EFAULT;
  		break;
215b13dd2   Richard Cochran   ptp: add an ioctl...
314
  	case PTP_SYS_OFFSET:
415606588   Felipe Balbi   PTP: introduce ne...
315
  	case PTP_SYS_OFFSET2:
2ece068e1   Muhammad Falak R Wani   ptp: use memdup_u...
316
317
318
  		sysoff = memdup_user((void __user *)arg, sizeof(*sysoff));
  		if (IS_ERR(sysoff)) {
  			err = PTR_ERR(sysoff);
6756325a9   Dan Carpenter   ptp: oops in ptp_...
319
  			sysoff = NULL;
215b13dd2   Richard Cochran   ptp: add an ioctl...
320
321
  			break;
  		}
c3484c275   Richard Cochran   ptp: reduce stack...
322
  		if (sysoff->n_samples > PTP_MAX_SAMPLES) {
215b13dd2   Richard Cochran   ptp: add an ioctl...
323
324
325
  			err = -EINVAL;
  			break;
  		}
c3484c275   Richard Cochran   ptp: reduce stack...
326
327
  		pct = &sysoff->ts[0];
  		for (i = 0; i < sysoff->n_samples; i++) {
f696a21c2   Arnd Bergmann   ptp: replace getn...
328
  			ktime_get_real_ts64(&ts);
215b13dd2   Richard Cochran   ptp: add an ioctl...
329
330
331
  			pct->sec = ts.tv_sec;
  			pct->nsec = ts.tv_nsec;
  			pct++;
916444df3   Miroslav Lichvar   ptp: deprecate ge...
332
333
334
335
  			if (ops->gettimex64)
  				err = ops->gettimex64(ops, &ts, NULL);
  			else
  				err = ops->gettime64(ops, &ts);
83d0bdc73   Miroslav Lichvar   ptp: check gettim...
336
337
  			if (err)
  				goto out;
215b13dd2   Richard Cochran   ptp: add an ioctl...
338
339
340
341
  			pct->sec = ts.tv_sec;
  			pct->nsec = ts.tv_nsec;
  			pct++;
  		}
f696a21c2   Arnd Bergmann   ptp: replace getn...
342
  		ktime_get_real_ts64(&ts);
215b13dd2   Richard Cochran   ptp: add an ioctl...
343
344
  		pct->sec = ts.tv_sec;
  		pct->nsec = ts.tv_nsec;
c3484c275   Richard Cochran   ptp: reduce stack...
345
  		if (copy_to_user((void __user *)arg, sysoff, sizeof(*sysoff)))
215b13dd2   Richard Cochran   ptp: add an ioctl...
346
347
  			err = -EFAULT;
  		break;
6092315df   Richard Cochran   ptp: introduce pr...
348
  	case PTP_PIN_GETFUNC:
415606588   Felipe Balbi   PTP: introduce ne...
349
  	case PTP_PIN_GETFUNC2:
6092315df   Richard Cochran   ptp: introduce pr...
350
351
352
353
  		if (copy_from_user(&pd, (void __user *)arg, sizeof(pd))) {
  			err = -EFAULT;
  			break;
  		}
415606588   Felipe Balbi   PTP: introduce ne...
354
355
356
357
358
359
360
361
362
363
364
365
  		if ((pd.rsv[0] || pd.rsv[1] || pd.rsv[2]
  				|| pd.rsv[3] || pd.rsv[4])
  			&& cmd == PTP_PIN_GETFUNC2) {
  			err = -EINVAL;
  			break;
  		} else if (cmd == PTP_PIN_GETFUNC) {
  			pd.rsv[0] = 0;
  			pd.rsv[1] = 0;
  			pd.rsv[2] = 0;
  			pd.rsv[3] = 0;
  			pd.rsv[4] = 0;
  		}
6092315df   Richard Cochran   ptp: introduce pr...
366
367
368
369
370
  		pin_index = pd.index;
  		if (pin_index >= ops->n_pins) {
  			err = -EINVAL;
  			break;
  		}
efa61c8cf   Gustavo A. R. Silva   ptp: fix Spectre ...
371
  		pin_index = array_index_nospec(pin_index, ops->n_pins);
6092315df   Richard Cochran   ptp: introduce pr...
372
373
374
375
376
377
378
379
380
  		if (mutex_lock_interruptible(&ptp->pincfg_mux))
  			return -ERESTARTSYS;
  		pd = ops->pin_config[pin_index];
  		mutex_unlock(&ptp->pincfg_mux);
  		if (!err && copy_to_user((void __user *)arg, &pd, sizeof(pd)))
  			err = -EFAULT;
  		break;
  
  	case PTP_PIN_SETFUNC:
415606588   Felipe Balbi   PTP: introduce ne...
381
  	case PTP_PIN_SETFUNC2:
6092315df   Richard Cochran   ptp: introduce pr...
382
383
384
385
  		if (copy_from_user(&pd, (void __user *)arg, sizeof(pd))) {
  			err = -EFAULT;
  			break;
  		}
415606588   Felipe Balbi   PTP: introduce ne...
386
387
388
389
390
391
392
393
394
395
396
397
  		if ((pd.rsv[0] || pd.rsv[1] || pd.rsv[2]
  				|| pd.rsv[3] || pd.rsv[4])
  			&& cmd == PTP_PIN_SETFUNC2) {
  			err = -EINVAL;
  			break;
  		} else if (cmd == PTP_PIN_SETFUNC) {
  			pd.rsv[0] = 0;
  			pd.rsv[1] = 0;
  			pd.rsv[2] = 0;
  			pd.rsv[3] = 0;
  			pd.rsv[4] = 0;
  		}
6092315df   Richard Cochran   ptp: introduce pr...
398
399
400
401
402
  		pin_index = pd.index;
  		if (pin_index >= ops->n_pins) {
  			err = -EINVAL;
  			break;
  		}
efa61c8cf   Gustavo A. R. Silva   ptp: fix Spectre ...
403
  		pin_index = array_index_nospec(pin_index, ops->n_pins);
6092315df   Richard Cochran   ptp: introduce pr...
404
405
406
407
408
  		if (mutex_lock_interruptible(&ptp->pincfg_mux))
  			return -ERESTARTSYS;
  		err = ptp_set_pinfunc(ptp, pin_index, pd.func, pd.chan);
  		mutex_unlock(&ptp->pincfg_mux);
  		break;
d94ba80eb   Richard Cochran   ptp: Added a bran...
409
410
411
412
  	default:
  		err = -ENOTTY;
  		break;
  	}
c3484c275   Richard Cochran   ptp: reduce stack...
413

83d0bdc73   Miroslav Lichvar   ptp: check gettim...
414
  out:
361800876   Miroslav Lichvar   ptp: add PTP_SYS_...
415
  	kfree(extoff);
c3484c275   Richard Cochran   ptp: reduce stack...
416
  	kfree(sysoff);
d94ba80eb   Richard Cochran   ptp: Added a bran...
417
418
  	return err;
  }
afc9a42b7   Al Viro   the rest of drive...
419
  __poll_t ptp_poll(struct posix_clock *pc, struct file *fp, poll_table *wait)
d94ba80eb   Richard Cochran   ptp: Added a bran...
420
421
422
423
  {
  	struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
  
  	poll_wait(fp, &ptp->tsev_wq, wait);
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
424
  	return queue_cnt(&ptp->tsevq) ? EPOLLIN : 0;
d94ba80eb   Richard Cochran   ptp: Added a bran...
425
  }
c7ec0badc   Richard Cochran   ptp: reduce stack...
426
  #define EXTTS_BUFSIZE (PTP_BUF_TIMESTAMPS * sizeof(struct ptp_extts_event))
d94ba80eb   Richard Cochran   ptp: Added a bran...
427
428
429
430
431
  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;
c7ec0badc   Richard Cochran   ptp: reduce stack...
432
  	struct ptp_extts_event *event;
d94ba80eb   Richard Cochran   ptp: Added a bran...
433
434
  	unsigned long flags;
  	size_t qcnt, i;
c7ec0badc   Richard Cochran   ptp: reduce stack...
435
  	int result;
d94ba80eb   Richard Cochran   ptp: Added a bran...
436
437
438
  
  	if (cnt % sizeof(struct ptp_extts_event) != 0)
  		return -EINVAL;
c7ec0badc   Richard Cochran   ptp: reduce stack...
439
440
  	if (cnt > EXTTS_BUFSIZE)
  		cnt = EXTTS_BUFSIZE;
d94ba80eb   Richard Cochran   ptp: Added a bran...
441
442
443
444
445
446
447
448
449
450
451
  
  	cnt = cnt / sizeof(struct ptp_extts_event);
  
  	if (mutex_lock_interruptible(&ptp->tsevq_mux))
  		return -ERESTARTSYS;
  
  	if (wait_event_interruptible(ptp->tsev_wq,
  				     ptp->defunct || queue_cnt(queue))) {
  		mutex_unlock(&ptp->tsevq_mux);
  		return -ERESTARTSYS;
  	}
fb5a18cf7   Dan Carpenter   ptp: Fix some loc...
452
453
  	if (ptp->defunct) {
  		mutex_unlock(&ptp->tsevq_mux);
d94ba80eb   Richard Cochran   ptp: Added a bran...
454
  		return -ENODEV;
fb5a18cf7   Dan Carpenter   ptp: Fix some loc...
455
  	}
d94ba80eb   Richard Cochran   ptp: Added a bran...
456

c7ec0badc   Richard Cochran   ptp: reduce stack...
457
458
459
460
461
  	event = kmalloc(EXTTS_BUFSIZE, GFP_KERNEL);
  	if (!event) {
  		mutex_unlock(&ptp->tsevq_mux);
  		return -ENOMEM;
  	}
d94ba80eb   Richard Cochran   ptp: Added a bran...
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
  	spin_lock_irqsave(&queue->lock, flags);
  
  	qcnt = queue_cnt(queue);
  
  	if (cnt > qcnt)
  		cnt = qcnt;
  
  	for (i = 0; i < cnt; i++) {
  		event[i] = queue->buf[queue->head];
  		queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS;
  	}
  
  	spin_unlock_irqrestore(&queue->lock, flags);
  
  	cnt = cnt * sizeof(struct ptp_extts_event);
  
  	mutex_unlock(&ptp->tsevq_mux);
c7ec0badc   Richard Cochran   ptp: reduce stack...
479
  	result = cnt;
fb5a18cf7   Dan Carpenter   ptp: Fix some loc...
480
  	if (copy_to_user(buf, event, cnt))
c7ec0badc   Richard Cochran   ptp: reduce stack...
481
  		result = -EFAULT;
d94ba80eb   Richard Cochran   ptp: Added a bran...
482

c7ec0badc   Richard Cochran   ptp: reduce stack...
483
484
  	kfree(event);
  	return result;
d94ba80eb   Richard Cochran   ptp: Added a bran...
485
  }