[LinuxPPS] [PATCH 02a/12] PPS: get rid of some pps_get_source() calls

George Spelvin linux at horizon.com
Tue Feb 10 04:57:30 CET 2009


This changes the kernel API to pass around a struct pps_device * instead
of an integer ID where possible.  In particular, avoiding the need to
call pps_get_source() in the pps_event() interrupt handler is a win.

(The comment above pps_event() is actually foreshadowing the next
commit in the series; it's not technically correct yet.)
---
 Documentation/pps/pps.txt       |    8 ++++--
 drivers/pps/clients/ktimer.c    |   19 +++++++-------
 drivers/pps/clients/pps-ldisc.c |   26 ++++++++++---------
 drivers/pps/kapi.c              |   51 ++++++++++++++++++--------------------
 include/linux/pps.h             |   13 ++++++----
 5 files changed, 61 insertions(+), 56 deletions(-)

diff --git a/Documentation/pps/pps.txt b/Documentation/pps/pps.txt
index 125f4ab..8470a69 100644
--- a/Documentation/pps/pps.txt
+++ b/Documentation/pps/pps.txt
@@ -85,12 +85,12 @@ pps_source_info_s as follows:
 and then calling the function pps_register_source() in your
 intialization routine as follows:
 
-    source = pps_register_source(&pps_ktimer_info,
+    pps = pps_register_source(&pps_ktimer_info,
 			PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
 
 The pps_register_source() prototype is:
 
-  int pps_register_source(struct pps_source_info_s *info, int default_params)
+  struct pps_source *pps_register_source(struct pps_source_info_s *info, int default_params)
 
 where "info" is a pointer to a structure that describes a particular
 PPS source, "default_params" tells the system what the initial default
@@ -98,11 +98,13 @@ parameters for the device should be (it is obvious that these parameters
 must be a subset of ones defined in the struct
 pps_source_info_s which describe the capabilities of the driver).
 
+The return value is either a pointer to a pps struct or an ERR_PTR.
+
 Once you have registered a new PPS source into the system you can
 signal an assert event (for example in the interrupt handler routine)
 just using:
 
-    pps_event(source, &ts, PPS_CAPTUREASSERT, ptr)
+    pps_event(pps, &ts, PPS_CAPTUREASSERT, ptr)
 
 where "ts" is the event's timestamp.
 
diff --git a/drivers/pps/clients/ktimer.c b/drivers/pps/clients/ktimer.c
index 259baa7..dc837a0 100644
--- a/drivers/pps/clients/ktimer.c
+++ b/drivers/pps/clients/ktimer.c
@@ -25,6 +25,7 @@
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/timer.h>
+#include <linux/err.h>
 
 #include <linux/pps.h>
 
@@ -32,7 +33,7 @@
  * Global variables
  */
 
-static int source;
+static struct pps_device *source;
 static struct timer_list ktimer;
 
 /*
@@ -62,12 +63,12 @@ static void pps_ktimer_event(unsigned long ptr)
  * The echo function
  */
 
-static void pps_ktimer_echo(int source, int event, void *data)
+static void pps_ktimer_echo(struct pps_device *pps, int event, void *data)
 {
 	pr_info("echo %s %s for source %d\n",
 		event & PPS_CAPTUREASSERT ? "assert" : "",
 		event & PPS_CAPTURECLEAR ? "clear" : "",
-		source);
+		pps->id);
 }
 
 /*
@@ -98,20 +99,20 @@ static void __exit pps_ktimer_exit(void)
 
 static int __init pps_ktimer_init(void)
 {
-	int ret;
+	struct pps_device *pps;
 
-	ret = pps_register_source(&pps_ktimer_info,
+	pps = pps_register_source(&pps_ktimer_info,
 				PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
-	if (ret < 0) {
+	if (IS_ERR(pps)) {
 		printk(KERN_ERR "cannot register ktimer source\n");
-		return ret;
+		return PTR_ERR(pps);
 	}
-	source = ret;
+	source = pps;
 
 	setup_timer(&ktimer, pps_ktimer_event, 0);
 	mod_timer(&ktimer, jiffies + HZ);
 
-	pr_info("ktimer PPS source registered at %d\n", source);
+	pr_info("ktimer PPS source registered at %d\n", pps->id);
 
 	return  0;
 }
diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c
index 0406f40..bc8b56a 100644
--- a/drivers/pps/clients/pps-ldisc.c
+++ b/drivers/pps/clients/pps-ldisc.c
@@ -29,7 +29,7 @@
 static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status,
 				struct timespec *ts)
 {
-	long id = (long) tty->disc_data;
+	struct pps_device *pps = tty->disc_data;
 	struct timespec __ts;
 	struct pps_ktime pps_ts;
 
@@ -42,11 +42,11 @@ static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status,
 	pps_ts.nsec = ts->tv_nsec;
 
 	/* Now do the PPS event report */
-	pps_event(id, &pps_ts, status ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR,
+	pps_event(pps, &pps_ts, status ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR,
 			NULL);
 
 	pr_debug("PPS %s at %lu on source #%d\n",
-			status ? "assert" : "clear", jiffies, (int) id);
+			status ? "assert" : "clear", jiffies, pps->id);
 }
 
 static int pps_tty_open(struct tty_struct *tty)
@@ -54,7 +54,8 @@ static int pps_tty_open(struct tty_struct *tty)
 	struct pps_source_info info;
 	struct tty_driver *drv = tty->driver;
 	int index = tty->index + drv->name_base;
-	long ret;
+	struct pps_device *pps;
+	int ret;
 
 	info.owner = THIS_MODULE;
 	info.dev = NULL;
@@ -64,30 +65,31 @@ static int pps_tty_open(struct tty_struct *tty)
 			PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
 			PPS_CANWAIT | PPS_TSFMT_TSPEC;
 
-	ret = pps_register_source(&info, PPS_CAPTUREBOTH | \
+	pps = pps_register_source(&info, PPS_CAPTUREBOTH | \
 				PPS_OFFSETASSERT | PPS_OFFSETCLEAR);
-	if (ret < 0) {
+	if (IS_ERR(pps)) {
 		pr_err("cannot register PPS source \"%s\"\n", info.path);
-		return ret;
+		return PTR_ERR(pps);
 	}
-	tty->disc_data = (void *) ret;
+	tty->disc_data = pps;
 
 	/* Should open N_TTY ldisc too */
 	ret = n_tty_open(tty);
 	if (ret < 0)
-		pps_unregister_source((long) tty->disc_data);
+		pps_unregister_source(tty->disc_data);
 
-	pr_info("PPS source #%d \"%s\" added\n", (int) ret, info.path);
+	pr_info("PPS source #%d \"%s\" added\n", pps->id, info.path);
 
 	return 0;
 }
 
 static void pps_tty_close(struct tty_struct *tty)
 {
-	long id = (long) tty->disc_data;
+	struct pps_device *pps = tty->disc_data;
+	int id = pps->id;
 
-	pps_unregister_source(id);
 	n_tty_close(tty);
+	pps_unregister_source(pps);
 
 	pr_info("PPS source #%d removed\n", (int) id);
 }
diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
index 917b379..4d6a2ed 100644
--- a/drivers/pps/kapi.c
+++ b/drivers/pps/kapi.c
@@ -124,7 +124,8 @@ exit:
  * The function returns, in case of success, the PPS source ID.
  */
 
-int pps_register_source(struct pps_source_info *info, int default_params)
+struct pps_device *
+pps_register_source(struct pps_source_info *info, int default_params)
 {
 	struct pps_device *pps;
 	int id;
@@ -198,7 +199,7 @@ int pps_register_source(struct pps_source_info *info, int default_params)
 
 	pr_info("new PPS source %s at ID %d\n", info->name, id);
 
-	return id;
+	return pps;
 
 free_idr:
 	spin_lock_irq(&pps_idr_lock);
@@ -211,7 +212,7 @@ kfree_pps:
 pps_register_source_exit:
 	printk(KERN_ERR "pps: %s: unable to register source\n", info->name);
 
-	return err;
+	return ERR_PTR(err);
 }
 EXPORT_SYMBOL(pps_register_source);
 
@@ -222,27 +223,19 @@ EXPORT_SYMBOL(pps_register_source);
  * the system.
  */
 
-void pps_unregister_source(int source)
+void pps_unregister_source(struct pps_device *pps)
 {
-	struct pps_device *pps;
-
-	spin_lock_irq(&pps_idr_lock);
-	pps = idr_find(&pps_idr, source);
-
 	if (!pps) {
 		BUG();
-		spin_unlock_irq(&pps_idr_lock);
 		return;
 	}
-	spin_unlock_irq(&pps_idr_lock);
-
 	pps_unregister_cdev(pps);
 	pps_put_source(pps);
 }
 EXPORT_SYMBOL(pps_unregister_source);
 
 /* pps_event - register a PPS event into the system
- * @source: the PPS source ID
+ * @pps: the pps_device structure
  * @ts: the event timestamp
  * @event: the event type
  * @data: userdef pointer
@@ -252,23 +245,30 @@ EXPORT_SYMBOL(pps_unregister_source);
  *
  * If an echo function is associated with the PPS source it will be called
  * as:
- *	pps->info.echo(source, event, data);
+ *	pps->info.echo(pps->id, event, data);
+ *
+ * NOTE: This function does no locking.  The caller must ensure that
+ * a) calls are serialized, and
+ * b) do not occur after pps_unregister_source is called.
+ * For current PPS clients, this is taken care of by:
+ * serial: a) struct uart_port's lock field, b) ldisc refcount
+ * ktimer: a) struct tvec_base's lock, b) del_timer_sync()
  */
 
-void pps_event(int source, struct pps_ktime *ts, int event, void *data)
+void
+pps_event(struct pps_device *pps, struct pps_ktime *ts, int event, void *data)
 {
-	struct pps_device *pps;
 	unsigned long flags;
 
+	if (!pps)
+		return;
+
 	if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) {
 		printk(KERN_ERR "pps: unknown event (%x) for source %d\n",
-			event, source);
+			event, pps->id);
 		return;
 	}
-
-	pps = pps_get_source(source);
-	if (!pps)
-		return;
+	event &= PPS_CAPTUREASSERT | PPS_CAPTURECLEAR;
 
 	pr_debug("PPS event on source %d at %llu.%06u\n",
 			pps->id, (unsigned long long) ts->sec, ts->nsec);
@@ -277,7 +277,7 @@ void pps_event(int source, struct pps_ktime *ts, int event, void *data)
 
 	/* Must call the echo function? */
 	if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)))
-		pps->info.echo(source, event, data);
+		pps->info.echo(pps, event, data);
 
 	/* Check the event */
 	pps->current_mode = pps->params.mode;
@@ -290,7 +290,7 @@ void pps_event(int source, struct pps_ktime *ts, int event, void *data)
 		pps->assert_tu = *ts;
 		pps->assert_sequence++;
 		pr_debug("capture assert seq #%u for source %d\n",
-			pps->assert_sequence, source);
+			pps->assert_sequence, pps->id);
 	}
 	if (event & PPS_CAPTURECLEAR) {
 		/* We have to add an offset? */
@@ -301,7 +301,7 @@ void pps_event(int source, struct pps_ktime *ts, int event, void *data)
 		pps->clear_tu = *ts;
 		pps->clear_sequence++;
 		pr_debug("capture clear seq #%u for source %d\n",
-			pps->clear_sequence, source);
+			pps->clear_sequence, pps->id);
 	}
 
 	pps->go = ~0;
@@ -310,8 +310,5 @@ void pps_event(int source, struct pps_ktime *ts, int event, void *data)
 	kill_fasync(&pps->async_queue, SIGIO, POLL_IN);
 
 	spin_unlock_irqrestore(&pps->lock, flags);
-
-	/* Now we can release the PPS source for (possible) deregistration */
-	pps_put_source(pps);
 }
 EXPORT_SYMBOL(pps_event);
diff --git a/include/linux/pps.h b/include/linux/pps.h
index d7719b3..c8cacdc 100644
--- a/include/linux/pps.h
+++ b/include/linux/pps.h
@@ -131,14 +131,16 @@ struct pps_fdata {
  * Global defines
  */
 
+struct pps_device;
+
 /* The specific PPS source info */
 struct pps_source_info {
 	char name[PPS_MAX_NAME_LEN];		/* simbolic name */
 	char path[PPS_MAX_NAME_LEN];		/* path of connected device */
 	int mode;				/* PPS's allowed mode */
 
-	void (*echo)(int source, int event, void *data); /* PPS echo function */
-
+	void (*echo)(struct pps_device *pps, int event, void *data);
+						/* PPS echo function */
 	struct module *owner;
 	struct device *dev;
 };
@@ -184,12 +186,13 @@ extern struct device_attribute pps_attrs[];
 
 struct pps_device *pps_get_source(int source);
 extern void pps_put_source(struct pps_device *pps);
-extern int pps_register_source(struct pps_source_info *info,
+extern struct pps_device *pps_register_source(struct pps_source_info *info,
 				int default_params);
-extern void pps_unregister_source(int source);
+extern void pps_unregister_source(struct pps_device *pps);
 extern int pps_register_cdev(struct pps_device *pps);
 extern void pps_unregister_cdev(struct pps_device *pps);
-extern void pps_event(int source, struct pps_ktime *ts, int event, void *data);
+extern void pps_event(struct pps_device *pps, struct pps_ktime *ts,
+				int event, void *data);
 
 #endif /* __KERNEL__ */
 
-- 
1.6.0.6




More information about the LinuxPPS mailing list