projects/linux·blob assoc-array-fixes · refs

509 lines · 11.4 KiB

1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * PPS core file
4 *
5 * Copyright (C) 2005-2009 Rodolfo Giometti <[email protected]>
6 */
7
8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9
10#include <linux/kernel.h>
11#include <linux/module.h>
12#include <linux/init.h>
13#include <linux/sched.h>
14#include <linux/uaccess.h>
15#include <linux/idr.h>
16#include <linux/mutex.h>
17#include <linux/cdev.h>
18#include <linux/poll.h>
19#include <linux/pps_kernel.h>
20#include <linux/slab.h>
21
22#include "kc.h"
23
24/*
25 * Local variables
26 */
27
28static int pps_major;
29static const struct class pps_class = {
30 .name = "pps",
31 .dev_groups = pps_groups
32};
33
34static DEFINE_MUTEX(pps_idr_lock);
35static DEFINE_IDR(pps_idr);
36
37/*
38 * Char device methods
39 */
40
41static __poll_t pps_cdev_poll(struct file *file, poll_table *wait)
42{
43 struct pps_device *pps = file->private_data;
44
45 poll_wait(file, &pps->queue, wait);
46
47 if (pps->last_fetched_ev == pps->last_ev)
48 return 0;
49
50 return EPOLLIN | EPOLLRDNORM;
51}
52
53static int pps_cdev_fasync(int fd, struct file *file, int on)
54{
55 struct pps_device *pps = file->private_data;
56 return fasync_helper(fd, file, on, &pps->async_queue);
57}
58
59static int pps_cdev_pps_fetch(struct pps_device *pps, struct pps_fdata *fdata)
60{
61 unsigned int ev = pps->last_ev;
62 int err = 0;
63
64 /* Manage the timeout */
65 if (fdata->timeout.flags & PPS_TIME_INVALID)
66 err = wait_event_interruptible(pps->queue,
67 ev != pps->last_ev);
68 else {
69 struct timespec64 ts;
70 unsigned long ticks;
71
72 dev_dbg(&pps->dev, "timeout %lld.%09d\n",
73 (long long) fdata->timeout.sec,
74 fdata->timeout.nsec);
75
76 if (fdata->timeout.sec < 0)
77 return -ETIMEDOUT;
78
79 ts.tv_sec = fdata->timeout.sec;
80 ts.tv_nsec = fdata->timeout.nsec;
81 ticks = timespec64_to_jiffies(&ts);
82
83 if (ticks != 0) {
84 err = wait_event_interruptible_timeout(
85 pps->queue,
86 ev != pps->last_ev,
87 ticks);
88 if (err == 0)
89 return -ETIMEDOUT;
90 }
91 }
92
93 /* Check for pending signals */
94 if (err == -ERESTARTSYS) {
95 dev_dbg(&pps->dev, "pending signal caught\n");
96 return -EINTR;
97 }
98
99 return 0;
100}
101
102static long pps_cdev_ioctl(struct file *file,
103 unsigned int cmd, unsigned long arg)
104{
105 struct pps_device *pps = file->private_data;
106 struct pps_kparams params;
107 void __user *uarg = (void __user *) arg;
108 int __user *iuarg = (int __user *) arg;
109 int err;
110
111 switch (cmd) {
112 case PPS_GETPARAMS:
113 dev_dbg(&pps->dev, "PPS_GETPARAMS\n");
114
115 spin_lock_irq(&pps->lock);
116
117 /* Get the current parameters */
118 params = pps->params;
119
120 spin_unlock_irq(&pps->lock);
121
122 err = copy_to_user(uarg, &params, sizeof(struct pps_kparams));
123 if (err)
124 return -EFAULT;
125
126 break;
127
128 case PPS_SETPARAMS:
129 dev_dbg(&pps->dev, "PPS_SETPARAMS\n");
130
131 /* Check the capabilities */
132 if (!capable(CAP_SYS_TIME))
133 return -EPERM;
134
135 err = copy_from_user(&params, uarg, sizeof(struct pps_kparams));
136 if (err)
137 return -EFAULT;
138 if (!(params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) {
139 dev_dbg(&pps->dev, "capture mode unspecified (%x)\n",
140 params.mode);
141 return -EINVAL;
142 }
143
144 /* Check for supported capabilities */
145 if ((params.mode & ~pps->info.mode) != 0) {
146 dev_dbg(&pps->dev, "unsupported capabilities (%x)\n",
147 params.mode);
148 return -EINVAL;
149 }
150
151 spin_lock_irq(&pps->lock);
152
153 /* Save the new parameters */
154 pps->params = params;
155
156 /* Restore the read only parameters */
157 if ((params.mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
158 /* section 3.3 of RFC 2783 interpreted */
159 dev_dbg(&pps->dev, "time format unspecified (%x)\n",
160 params.mode);
161 pps->params.mode |= PPS_TSFMT_TSPEC;
162 }
163 if (pps->info.mode & PPS_CANWAIT)
164 pps->params.mode |= PPS_CANWAIT;
165 pps->params.api_version = PPS_API_VERS;
166
167 /*
168 * Clear unused fields of pps_kparams to avoid leaking
169 * uninitialized data of the PPS_SETPARAMS caller via
170 * PPS_GETPARAMS
171 */
172 pps->params.assert_off_tu.flags = 0;
173 pps->params.clear_off_tu.flags = 0;
174
175 spin_unlock_irq(&pps->lock);
176
177 break;
178
179 case PPS_GETCAP:
180 dev_dbg(&pps->dev, "PPS_GETCAP\n");
181
182 err = put_user(pps->info.mode, iuarg);
183 if (err)
184 return -EFAULT;
185
186 break;
187
188 case PPS_FETCH: {
189 struct pps_fdata fdata;
190
191 dev_dbg(&pps->dev, "PPS_FETCH\n");
192
193 err = copy_from_user(&fdata, uarg, sizeof(struct pps_fdata));
194 if (err)
195 return -EFAULT;
196
197 err = pps_cdev_pps_fetch(pps, &fdata);
198 if (err)
199 return err;
200
201 /* Return the fetched timestamp and save last fetched event */
202 spin_lock_irq(&pps->lock);
203
204 pps->last_fetched_ev = pps->last_ev;
205
206 fdata.info.assert_sequence = pps->assert_sequence;
207 fdata.info.clear_sequence = pps->clear_sequence;
208 fdata.info.assert_tu = pps->assert_tu;
209 fdata.info.clear_tu = pps->clear_tu;
210 fdata.info.current_mode = pps->current_mode;
211
212 spin_unlock_irq(&pps->lock);
213
214 err = copy_to_user(uarg, &fdata, sizeof(struct pps_fdata));
215 if (err)
216 return -EFAULT;
217
218 break;
219 }
220 case PPS_KC_BIND: {
221 struct pps_bind_args bind_args;
222
223 dev_dbg(&pps->dev, "PPS_KC_BIND\n");
224
225 /* Check the capabilities */
226 if (!capable(CAP_SYS_TIME))
227 return -EPERM;
228
229 if (copy_from_user(&bind_args, uarg,
230 sizeof(struct pps_bind_args)))
231 return -EFAULT;
232
233 /* Check for supported capabilities */
234 if ((bind_args.edge & ~pps->info.mode) != 0) {
235 dev_err(&pps->dev, "unsupported capabilities (%x)\n",
236 bind_args.edge);
237 return -EINVAL;
238 }
239
240 /* Validate parameters roughly */
241 if (bind_args.tsformat != PPS_TSFMT_TSPEC ||
242 (bind_args.edge & ~PPS_CAPTUREBOTH) != 0 ||
243 bind_args.consumer != PPS_KC_HARDPPS) {
244 dev_err(&pps->dev, "invalid kernel consumer bind"
245 " parameters (%x)\n", bind_args.edge);
246 return -EINVAL;
247 }
248
249 err = pps_kc_bind(pps, &bind_args);
250 if (err < 0)
251 return err;
252
253 break;
254 }
255 default:
256 return -ENOTTY;
257 }
258
259 return 0;
260}
261
262#ifdef CONFIG_COMPAT
263static long pps_cdev_compat_ioctl(struct file *file,
264 unsigned int cmd, unsigned long arg)
265{
266 struct pps_device *pps = file->private_data;
267 void __user *uarg = (void __user *) arg;
268
269 cmd = _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(void *));
270
271 if (cmd == PPS_FETCH) {
272 struct pps_fdata_compat compat;
273 struct pps_fdata fdata;
274 int err;
275
276 dev_dbg(&pps->dev, "PPS_FETCH\n");
277
278 err = copy_from_user(&compat, uarg, sizeof(struct pps_fdata_compat));
279 if (err)
280 return -EFAULT;
281
282 memcpy(&fdata.timeout, &compat.timeout,
283 sizeof(struct pps_ktime_compat));
284
285 err = pps_cdev_pps_fetch(pps, &fdata);
286 if (err)
287 return err;
288
289 /* Return the fetched timestamp and save last fetched event */
290 spin_lock_irq(&pps->lock);
291
292 pps->last_fetched_ev = pps->last_ev;
293
294 compat.info.assert_sequence = pps->assert_sequence;
295 compat.info.clear_sequence = pps->clear_sequence;
296 compat.info.current_mode = pps->current_mode;
297
298 memcpy(&compat.info.assert_tu, &pps->assert_tu,
299 sizeof(struct pps_ktime_compat));
300 memcpy(&compat.info.clear_tu, &pps->clear_tu,
301 sizeof(struct pps_ktime_compat));
302
303 spin_unlock_irq(&pps->lock);
304
305 return copy_to_user(uarg, &compat,
306 sizeof(struct pps_fdata_compat)) ? -EFAULT : 0;
307 }
308
309 return pps_cdev_ioctl(file, cmd, arg);
310}
311#else
312#define pps_cdev_compat_ioctl NULL
313#endif
314
315static struct pps_device *pps_idr_get(unsigned long id)
316{
317 struct pps_device *pps;
318
319 mutex_lock(&pps_idr_lock);
320 pps = idr_find(&pps_idr, id);
321 if (pps)
322 get_device(&pps->dev);
323
324 mutex_unlock(&pps_idr_lock);
325 return pps;
326}
327
328static int pps_cdev_open(struct inode *inode, struct file *file)
329{
330 struct pps_device *pps = pps_idr_get(iminor(inode));
331
332 if (!pps)
333 return -ENODEV;
334
335 file->private_data = pps;
336 return 0;
337}
338
339static int pps_cdev_release(struct inode *inode, struct file *file)
340{
341 struct pps_device *pps = file->private_data;
342
343 WARN_ON(pps->id != iminor(inode));
344 put_device(&pps->dev);
345 return 0;
346}
347
348/*
349 * Char device stuff
350 */
351
352static const struct file_operations pps_cdev_fops = {
353 .owner = THIS_MODULE,
354 .poll = pps_cdev_poll,
355 .fasync = pps_cdev_fasync,
356 .compat_ioctl = pps_cdev_compat_ioctl,
357 .unlocked_ioctl = pps_cdev_ioctl,
358 .open = pps_cdev_open,
359 .release = pps_cdev_release,
360};
361
362static void pps_device_destruct(struct device *dev)
363{
364 struct pps_device *pps = dev_get_drvdata(dev);
365
366 pr_debug("deallocating pps%d\n", pps->id);
367 kfree(pps);
368}
369
370int pps_register_cdev(struct pps_device *pps)
371{
372 int err;
373
374 mutex_lock(&pps_idr_lock);
375 /*
376 * Get new ID for the new PPS source. After idr_alloc() calling
377 * the new source will be freely available into the kernel.
378 */
379 err = idr_alloc(&pps_idr, pps, 0, PPS_MAX_SOURCES, GFP_KERNEL);
380 if (err < 0) {
381 if (err == -ENOSPC) {
382 pr_err("%s: too many PPS sources in the system\n",
383 pps->info.name);
384 err = -EBUSY;
385 }
386 kfree(pps);
387 goto out_unlock;
388 }
389 pps->id = err;
390
391 pps->dev.class = &pps_class;
392 pps->dev.parent = pps->info.dev;
393 pps->dev.devt = MKDEV(pps_major, pps->id);
394 dev_set_drvdata(&pps->dev, pps);
395 dev_set_name(&pps->dev, "pps%d", pps->id);
396 pps->dev.release = pps_device_destruct;
397 err = device_register(&pps->dev);
398 if (err)
399 goto free_idr;
400
401 pr_debug("source %s got cdev (%d:%d)\n", pps->info.name, pps_major,
402 pps->id);
403
404 get_device(&pps->dev);
405 mutex_unlock(&pps_idr_lock);
406 return 0;
407
408free_idr:
409 idr_remove(&pps_idr, pps->id);
410 put_device(&pps->dev);
411out_unlock:
412 mutex_unlock(&pps_idr_lock);
413 return err;
414}
415
416void pps_unregister_cdev(struct pps_device *pps)
417{
418 pr_debug("unregistering pps%d\n", pps->id);
419 pps->lookup_cookie = NULL;
420 device_destroy(&pps_class, pps->dev.devt);
421
422 /* Now we can release the ID for re-use */
423 mutex_lock(&pps_idr_lock);
424 idr_remove(&pps_idr, pps->id);
425 put_device(&pps->dev);
426 mutex_unlock(&pps_idr_lock);
427}
428
429/*
430 * Look up a pps device by magic cookie.
431 * The cookie is usually a pointer to some enclosing device, but this
432 * code doesn't care; you should never be dereferencing it.
433 *
434 * This is a bit of a kludge that is currently used only by the PPS
435 * serial line discipline. It may need to be tweaked when a second user
436 * is found.
437 *
438 * There is no function interface for setting the lookup_cookie field.
439 * It's initialized to NULL when the pps device is created, and if a
440 * client wants to use it, just fill it in afterward.
441 *
442 * The cookie is automatically set to NULL in pps_unregister_source()
443 * so that it will not be used again, even if the pps device cannot
444 * be removed from the idr due to pending references holding the minor
445 * number in use.
446 *
447 * Since pps_idr holds a reference to the device, the returned
448 * pps_device is guaranteed to be valid until pps_unregister_cdev() is
449 * called on it. But after calling pps_unregister_cdev(), it may be
450 * freed at any time.
451 */
452struct pps_device *pps_lookup_dev(void const *cookie)
453{
454 struct pps_device *pps;
455 unsigned id;
456
457 rcu_read_lock();
458 idr_for_each_entry(&pps_idr, pps, id)
459 if (cookie == pps->lookup_cookie)
460 break;
461 rcu_read_unlock();
462 return pps;
463}
464EXPORT_SYMBOL(pps_lookup_dev);
465
466/*
467 * Module stuff
468 */
469
470static void __exit pps_exit(void)
471{
472 class_unregister(&pps_class);
473 __unregister_chrdev(pps_major, 0, PPS_MAX_SOURCES, "pps");
474}
475
476static int __init pps_init(void)
477{
478 int err;
479
480 err = class_register(&pps_class);
481 if (err) {
482 pr_err("failed to register class\n");
483 return err;
484 }
485
486 pps_major = __register_chrdev(0, 0, PPS_MAX_SOURCES, "pps",
487 &pps_cdev_fops);
488 if (pps_major < 0) {
489 pr_err("failed to allocate char device region\n");
490 goto remove_class;
491 }
492
493 pr_info("LinuxPPS API ver. %d registered\n", PPS_API_VERS);
494 pr_info("Software ver. %s - Copyright 2005-2007 Rodolfo Giometti "
495 "<[email protected]>\n", PPS_VERSION);
496
497 return 0;
498
499remove_class:
500 class_unregister(&pps_class);
501 return pps_major;
502}
503
504subsys_initcall(pps_init);
505module_exit(pps_exit);
506
507MODULE_AUTHOR("Rodolfo Giometti <[email protected]>");
508MODULE_DESCRIPTION("LinuxPPS support (RFC 2783) - ver. " PPS_VERSION);
509MODULE_LICENSE("GPL");