Commit 5e196d34a776420278e4117b4742cd9d3f2350ed

Authored by Alexander Gordeev
Committed by Linus Torvalds
1 parent 6f4229b511

pps: access pps device by direct pointer

Using device index as a pointer needs some unnecessary work to be done
every time the pointer is needed (in irq handler for example).  Using a
direct pointer is much more easy (and safe as well).

Signed-off-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
Acked-by: Rodolfo Giometti <giometti@linux.it>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 5 changed files with 82 additions and 158 deletions Side-by-side Diff

drivers/pps/clients/pps-ktimer.c
... ... @@ -31,7 +31,7 @@
31 31 * Global variables
32 32 */
33 33  
34   -static int source;
  34 +static struct pps_device *pps;
35 35 static struct timer_list ktimer;
36 36  
37 37 /*
... ... @@ -47,7 +47,7 @@
47 47  
48 48 pr_info("PPS event at %lu\n", jiffies);
49 49  
50   - pps_event(source, &ts, PPS_CAPTUREASSERT, NULL);
  50 + pps_event(pps, &ts, PPS_CAPTUREASSERT, NULL);
51 51  
52 52 mod_timer(&ktimer, jiffies + HZ);
53 53 }
54 54  
55 55  
... ... @@ -56,12 +56,11 @@
56 56 * The echo function
57 57 */
58 58  
59   -static void pps_ktimer_echo(int source, int event, void *data)
  59 +static void pps_ktimer_echo(struct pps_device *pps, int event, void *data)
60 60 {
61   - pr_info("echo %s %s for source %d\n",
  61 + dev_info(pps->dev, "echo %s %s\n",
62 62 event & PPS_CAPTUREASSERT ? "assert" : "",
63   - event & PPS_CAPTURECLEAR ? "clear" : "",
64   - source);
  63 + event & PPS_CAPTURECLEAR ? "clear" : "");
65 64 }
66 65  
67 66 /*
68 67  
69 68  
70 69  
71 70  
72 71  
73 72  
74 73  
... ... @@ -84,30 +83,27 @@
84 83  
85 84 static void __exit pps_ktimer_exit(void)
86 85 {
87   - del_timer_sync(&ktimer);
88   - pps_unregister_source(source);
  86 + dev_info(pps->dev, "ktimer PPS source unregistered\n");
89 87  
90   - pr_info("ktimer PPS source unregistered\n");
  88 + del_timer_sync(&ktimer);
  89 + pps_unregister_source(pps);
91 90 }
92 91  
93 92 static int __init pps_ktimer_init(void)
94 93 {
95   - int ret;
96   -
97   - ret = pps_register_source(&pps_ktimer_info,
  94 + pps = pps_register_source(&pps_ktimer_info,
98 95 PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
99   - if (ret < 0) {
  96 + if (pps == NULL) {
100 97 printk(KERN_ERR "cannot register ktimer source\n");
101   - return ret;
  98 + return -ENOMEM;
102 99 }
103   - source = ret;
104 100  
105 101 setup_timer(&ktimer, pps_ktimer_event, 0);
106 102 mod_timer(&ktimer, jiffies + HZ);
107 103  
108   - pr_info("ktimer PPS source registered at %d\n", source);
  104 + dev_info(pps->dev, "ktimer PPS source registered\n");
109 105  
110   - return 0;
  106 + return 0;
111 107 }
112 108  
113 109 module_init(pps_ktimer_init);
drivers/pps/clients/pps-ldisc.c
... ... @@ -29,7 +29,7 @@
29 29 static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status,
30 30 struct pps_event_time *ts)
31 31 {
32   - int id = (long)tty->disc_data;
  32 + struct pps_device *pps = (struct pps_device *)tty->disc_data;
33 33 struct pps_event_time __ts;
34 34  
35 35 /* First of all we get the time stamp... */
36 36  
37 37  
... ... @@ -39,12 +39,14 @@
39 39 if (!ts) /* No. Do it ourself! */
40 40 ts = &__ts;
41 41  
  42 + BUG_ON(pps == NULL);
  43 +
42 44 /* Now do the PPS event report */
43   - pps_event(id, ts, status ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR,
44   - NULL);
  45 + pps_event(pps, ts, status ? PPS_CAPTUREASSERT :
  46 + PPS_CAPTURECLEAR, NULL);
45 47  
46   - pr_debug("PPS %s at %lu on source #%d\n",
47   - status ? "assert" : "clear", jiffies, id);
  48 + dev_dbg(pps->dev, "PPS %s at %lu\n",
  49 + status ? "assert" : "clear", jiffies);
48 50 }
49 51  
50 52 static int (*alias_n_tty_open)(struct tty_struct *tty);
... ... @@ -54,6 +56,7 @@
54 56 struct pps_source_info info;
55 57 struct tty_driver *drv = tty->driver;
56 58 int index = tty->index + drv->name_base;
  59 + struct pps_device *pps;
57 60 int ret;
58 61  
59 62 info.owner = THIS_MODULE;
60 63  
61 64  
62 65  
63 66  
64 67  
65 68  
66 69  
67 70  
68 71  
... ... @@ -64,34 +67,42 @@
64 67 PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
65 68 PPS_CANWAIT | PPS_TSFMT_TSPEC;
66 69  
67   - ret = pps_register_source(&info, PPS_CAPTUREBOTH | \
  70 + pps = pps_register_source(&info, PPS_CAPTUREBOTH | \
68 71 PPS_OFFSETASSERT | PPS_OFFSETCLEAR);
69   - if (ret < 0) {
  72 + if (pps == NULL) {
70 73 pr_err("cannot register PPS source \"%s\"\n", info.path);
71   - return ret;
  74 + return -ENOMEM;
72 75 }
73   - tty->disc_data = (void *)(long)ret;
  76 + tty->disc_data = pps;
74 77  
75 78 /* Should open N_TTY ldisc too */
76 79 ret = alias_n_tty_open(tty);
77   - if (ret < 0)
78   - pps_unregister_source((long)tty->disc_data);
  80 + if (ret < 0) {
  81 + pr_err("cannot open tty ldisc \"%s\"\n", info.path);
  82 + goto err_unregister;
  83 + }
79 84  
80   - pr_info("PPS source #%d \"%s\" added\n", ret, info.path);
  85 + dev_info(pps->dev, "source \"%s\" added\n", info.path);
81 86  
82 87 return 0;
  88 +
  89 +err_unregister:
  90 + tty->disc_data = NULL;
  91 + pps_unregister_source(pps);
  92 + return ret;
83 93 }
84 94  
85 95 static void (*alias_n_tty_close)(struct tty_struct *tty);
86 96  
87 97 static void pps_tty_close(struct tty_struct *tty)
88 98 {
89   - int id = (long)tty->disc_data;
  99 + struct pps_device *pps = (struct pps_device *)tty->disc_data;
90 100  
91   - pps_unregister_source(id);
92 101 alias_n_tty_close(tty);
93 102  
94   - pr_info("PPS source #%d removed\n", id);
  103 + tty->disc_data = NULL;
  104 + dev_info(pps->dev, "removed\n");
  105 + pps_unregister_source(pps);
95 106 }
96 107  
97 108 static struct tty_ldisc_ops pps_ldisc_ops;
... ... @@ -32,11 +32,11 @@
32 32 #include <linux/slab.h>
33 33  
34 34 /*
35   - * Global variables
  35 + * Local variables
36 36 */
37 37  
38   -DEFINE_SPINLOCK(pps_idr_lock);
39   -DEFINE_IDR(pps_idr);
  38 +static DEFINE_SPINLOCK(pps_idr_lock);
  39 +static DEFINE_IDR(pps_idr);
40 40  
41 41 /*
42 42 * Local functions
... ... @@ -60,60 +60,6 @@
60 60 * Exported functions
61 61 */
62 62  
63   -/* pps_get_source - find a PPS source
64   - * @source: the PPS source ID.
65   - *
66   - * This function is used to find an already registered PPS source into the
67   - * system.
68   - *
69   - * The function returns NULL if found nothing, otherwise it returns a pointer
70   - * to the PPS source data struct (the refcounter is incremented by 1).
71   - */
72   -
73   -struct pps_device *pps_get_source(int source)
74   -{
75   - struct pps_device *pps;
76   - unsigned long flags;
77   -
78   - spin_lock_irqsave(&pps_idr_lock, flags);
79   -
80   - pps = idr_find(&pps_idr, source);
81   - if (pps != NULL)
82   - atomic_inc(&pps->usage);
83   -
84   - spin_unlock_irqrestore(&pps_idr_lock, flags);
85   -
86   - return pps;
87   -}
88   -
89   -/* pps_put_source - free the PPS source data
90   - * @pps: a pointer to the PPS source.
91   - *
92   - * This function is used to free a PPS data struct if its refcount is 0.
93   - */
94   -
95   -void pps_put_source(struct pps_device *pps)
96   -{
97   - unsigned long flags;
98   -
99   - spin_lock_irqsave(&pps_idr_lock, flags);
100   - BUG_ON(atomic_read(&pps->usage) == 0);
101   -
102   - if (!atomic_dec_and_test(&pps->usage)) {
103   - pps = NULL;
104   - goto exit;
105   - }
106   -
107   - /* No more reference to the PPS source. We can safely remove the
108   - * PPS data struct.
109   - */
110   - idr_remove(&pps_idr, pps->id);
111   -
112   -exit:
113   - spin_unlock_irqrestore(&pps_idr_lock, flags);
114   - kfree(pps);
115   -}
116   -
117 63 /* pps_register_source - add a PPS source in the system
118 64 * @info: the PPS info struct
119 65 * @default_params: the default PPS parameters of the new source
120 66  
... ... @@ -122,10 +68,11 @@
122 68 * source is described by info's fields and it will have, as default PPS
123 69 * parameters, the ones specified into default_params.
124 70 *
125   - * The function returns, in case of success, the PPS source ID.
  71 + * The function returns, in case of success, the PPS device. Otherwise NULL.
126 72 */
127 73  
128   -int pps_register_source(struct pps_source_info *info, int default_params)
  74 +struct pps_device *pps_register_source(struct pps_source_info *info,
  75 + int default_params)
129 76 {
130 77 struct pps_device *pps;
131 78 int id;
... ... @@ -168,7 +115,6 @@
168 115  
169 116 init_waitqueue_head(&pps->queue);
170 117 spin_lock_init(&pps->lock);
171   - atomic_set(&pps->usage, 1);
172 118  
173 119 /* Get new ID for the new PPS source */
174 120 if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) {
... ... @@ -211,7 +157,7 @@
211 157  
212 158 pr_info("new PPS source %s at ID %d\n", info->name, id);
213 159  
214   - return id;
  160 + return pps;
215 161  
216 162 free_idr:
217 163 spin_lock_irq(&pps_idr_lock);
218 164  
219 165  
220 166  
221 167  
222 168  
223 169  
224 170  
... ... @@ -224,38 +170,33 @@
224 170 pps_register_source_exit:
225 171 printk(KERN_ERR "pps: %s: unable to register source\n", info->name);
226 172  
227   - return err;
  173 + return NULL;
228 174 }
229 175 EXPORT_SYMBOL(pps_register_source);
230 176  
231 177 /* pps_unregister_source - remove a PPS source from the system
232   - * @source: the PPS source ID
  178 + * @pps: the PPS source
233 179 *
234 180 * This function is used to remove a previously registered PPS source from
235 181 * the system.
236 182 */
237 183  
238   -void pps_unregister_source(int source)
  184 +void pps_unregister_source(struct pps_device *pps)
239 185 {
240   - struct pps_device *pps;
  186 + unsigned int id = pps->id;
241 187  
242   - spin_lock_irq(&pps_idr_lock);
243   - pps = idr_find(&pps_idr, source);
  188 + pps_unregister_cdev(pps);
244 189  
245   - if (!pps) {
246   - BUG();
247   - spin_unlock_irq(&pps_idr_lock);
248   - return;
249   - }
  190 + spin_lock_irq(&pps_idr_lock);
  191 + idr_remove(&pps_idr, pps->id);
250 192 spin_unlock_irq(&pps_idr_lock);
251 193  
252   - pps_unregister_cdev(pps);
253   - pps_put_source(pps);
  194 + kfree(pps);
254 195 }
255 196 EXPORT_SYMBOL(pps_unregister_source);
256 197  
257 198 /* pps_event - register a PPS event into the system
258   - * @source: the PPS source ID
  199 + * @pps: the PPS device
259 200 * @ts: the event timestamp
260 201 * @event: the event type
261 202 * @data: userdef pointer
262 203  
263 204  
264 205  
265 206  
266 207  
267 208  
268 209  
... ... @@ -263,38 +204,32 @@
263 204 * This function is used by each PPS client in order to register a new
264 205 * PPS event into the system (it's usually called inside an IRQ handler).
265 206 *
266   - * If an echo function is associated with the PPS source it will be called
  207 + * If an echo function is associated with the PPS device it will be called
267 208 * as:
268   - * pps->info.echo(source, event, data);
  209 + * pps->info.echo(pps, event, data);
269 210 */
270   -
271   -void pps_event(int source, struct pps_event_time *ts, int event, void *data)
  211 +void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
  212 + void *data)
272 213 {
273   - struct pps_device *pps;
274 214 unsigned long flags;
275 215 int captured = 0;
276 216 struct pps_ktime ts_real;
277 217  
278 218 if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) {
279   - printk(KERN_ERR "pps: unknown event (%x) for source %d\n",
280   - event, source);
  219 + dev_err(pps->dev, "unknown event (%x)\n", event);
281 220 return;
282 221 }
283 222  
284   - pps = pps_get_source(source);
285   - if (!pps)
286   - return;
  223 + dev_dbg(pps->dev, "PPS event at %ld.%09ld\n",
  224 + ts->ts_real.tv_sec, ts->ts_real.tv_nsec);
287 225  
288   - pr_debug("PPS event on source %d at %ld.%09ld\n",
289   - pps->id, ts->ts_real.tv_sec, ts->ts_real.tv_nsec);
290   -
291 226 timespec_to_pps_ktime(&ts_real, ts->ts_real);
292 227  
293 228 spin_lock_irqsave(&pps->lock, flags);
294 229  
295 230 /* Must call the echo function? */
296 231 if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)))
297   - pps->info.echo(source, event, data);
  232 + pps->info.echo(pps, event, data);
298 233  
299 234 /* Check the event */
300 235 pps->current_mode = pps->params.mode;
... ... @@ -308,8 +243,8 @@
308 243 /* Save the time stamp */
309 244 pps->assert_tu = ts_real;
310 245 pps->assert_sequence++;
311   - pr_debug("capture assert seq #%u for source %d\n",
312   - pps->assert_sequence, source);
  246 + dev_dbg(pps->dev, "capture assert seq #%u\n",
  247 + pps->assert_sequence);
313 248  
314 249 captured = ~0;
315 250 }
... ... @@ -323,8 +258,8 @@
323 258 /* Save the time stamp */
324 259 pps->clear_tu = ts_real;
325 260 pps->clear_sequence++;
326   - pr_debug("capture clear seq #%u for source %d\n",
327   - pps->clear_sequence, source);
  261 + dev_dbg(pps->dev, "capture clear seq #%u\n",
  262 + pps->clear_sequence);
328 263  
329 264 captured = ~0;
330 265 }
... ... @@ -338,9 +273,6 @@
338 273 }
339 274  
340 275 spin_unlock_irqrestore(&pps->lock, flags);
341   -
342   - /* Now we can release the PPS source for (possible) deregistration */
343   - pps_put_source(pps);
344 276 }
345 277 EXPORT_SYMBOL(pps_event);
... ... @@ -204,12 +204,6 @@
204 204 {
205 205 struct pps_device *pps = container_of(inode->i_cdev,
206 206 struct pps_device, cdev);
207   - int found;
208   -
209   - found = pps_get_source(pps->id) != 0;
210   - if (!found)
211   - return -ENODEV;
212   -
213 207 file->private_data = pps;
214 208  
215 209 return 0;
... ... @@ -217,11 +211,6 @@
217 211  
218 212 static int pps_cdev_release(struct inode *inode, struct file *file)
219 213 {
220   - struct pps_device *pps = file->private_data;
221   -
222   - /* Free the PPS source and wake up (possible) deregistration */
223   - pps_put_source(pps);
224   -
225 214 return 0;
226 215 }
227 216  
228 217  
229 218  
230 219  
231 220  
... ... @@ -242,22 +231,23 @@
242 231 int pps_register_cdev(struct pps_device *pps)
243 232 {
244 233 int err;
  234 + dev_t devt;
245 235  
246   - pps->devno = MKDEV(MAJOR(pps_devt), pps->id);
  236 + devt = MKDEV(MAJOR(pps_devt), pps->id);
  237 +
247 238 cdev_init(&pps->cdev, &pps_cdev_fops);
248 239 pps->cdev.owner = pps->info.owner;
249 240  
250   - err = cdev_add(&pps->cdev, pps->devno, 1);
  241 + err = cdev_add(&pps->cdev, devt, 1);
251 242 if (err) {
252 243 printk(KERN_ERR "pps: %s: failed to add char device %d:%d\n",
253 244 pps->info.name, MAJOR(pps_devt), pps->id);
254 245 return err;
255 246 }
256   - pps->dev = device_create(pps_class, pps->info.dev, pps->devno, NULL,
  247 + pps->dev = device_create(pps_class, pps->info.dev, devt, pps,
257 248 "pps%d", pps->id);
258 249 if (IS_ERR(pps->dev))
259 250 goto del_cdev;
260   - dev_set_drvdata(pps->dev, pps);
261 251  
262 252 pr_debug("source %s got cdev (%d:%d)\n", pps->info.name,
263 253 MAJOR(pps_devt), pps->id);
... ... @@ -272,7 +262,7 @@
272 262  
273 263 void pps_unregister_cdev(struct pps_device *pps)
274 264 {
275   - device_destroy(pps_class, pps->devno);
  265 + device_destroy(pps_class, pps->dev->devt);
276 266 cdev_del(&pps->cdev);
277 267 }
278 268  
include/linux/pps_kernel.h
... ... @@ -31,13 +31,16 @@
31 31 * Global defines
32 32 */
33 33  
  34 +struct pps_device;
  35 +
34 36 /* The specific PPS source info */
35 37 struct pps_source_info {
36 38 char name[PPS_MAX_NAME_LEN]; /* simbolic name */
37 39 char path[PPS_MAX_NAME_LEN]; /* path of connected device */
38 40 int mode; /* PPS's allowed mode */
39 41  
40   - void (*echo)(int source, int event, void *data); /* PPS echo function */
  42 + void (*echo)(struct pps_device *pps,
  43 + int event, void *data); /* PPS echo function */
41 44  
42 45 struct module *owner;
43 46 struct device *dev;
44 47  
45 48  
46 49  
47 50  
... ... @@ -65,35 +68,27 @@
65 68 unsigned int id; /* PPS source unique ID */
66 69 struct cdev cdev;
67 70 struct device *dev;
68   - int devno;
69 71 struct fasync_struct *async_queue; /* fasync method */
70 72 spinlock_t lock;
71   -
72   - atomic_t usage; /* usage count */
73 73 };
74 74  
75 75 /*
76 76 * Global variables
77 77 */
78 78  
79   -extern spinlock_t pps_idr_lock;
80   -extern struct idr pps_idr;
81   -
82 79 extern struct device_attribute pps_attrs[];
83 80  
84 81 /*
85 82 * Exported functions
86 83 */
87 84  
88   -struct pps_device *pps_get_source(int source);
89   -extern void pps_put_source(struct pps_device *pps);
90   -extern int pps_register_source(struct pps_source_info *info,
91   - int default_params);
92   -extern void pps_unregister_source(int source);
  85 +extern struct pps_device *pps_register_source(
  86 + struct pps_source_info *info, int default_params);
  87 +extern void pps_unregister_source(struct pps_device *pps);
93 88 extern int pps_register_cdev(struct pps_device *pps);
94 89 extern void pps_unregister_cdev(struct pps_device *pps);
95   -extern void pps_event(int source, struct pps_event_time *ts, int event,
96   - void *data);
  90 +extern void pps_event(struct pps_device *pps,
  91 + struct pps_event_time *ts, int event, void *data);
97 92  
98 93 static inline void timespec_to_pps_ktime(struct pps_ktime *kt,
99 94 struct timespec ts)