From: Alexander Gordeev <lasaine@lvk.cs.msu.su>
To: linux-kernel@vger.kernel.org
Cc: "Nikita V\. Youshchenko" <yoush@cs.msu.su>,
linuxpps@ml.enneenne.com,
Rodolfo Giometti <giometti@enneenne.com>,
Alexander Gordeev <lasaine@lvk.cs.msu.su>,
Andrew Morton <akpm@linux-foundation.org>,
Tejun Heo <tj@kernel.org>
Subject: [PATCHv4 08/17] pps: add async PPS event handler
Date: Thu, 18 Nov 2010 19:01:01 +0300 [thread overview]
Message-ID: <65eae4de46680aa8d644619f6dc61ba17f1fdc77.1290087479.git.lasaine@lvk.cs.msu.su> (raw)
In-Reply-To: <cover.1290087473.git.lasaine@lvk.cs.msu.su>
This handler should be called from an IRQ handler. It uses per-device
workqueue internally.
Signed-off-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
---
drivers/pps/clients/pps-ktimer.c | 2 +-
drivers/pps/clients/pps-ldisc.c | 2 +-
drivers/pps/kapi.c | 95 ++++++++++++++++++++++++++++++++++++--
drivers/pps/pps.c | 14 +++++-
include/linux/pps_kernel.h | 12 +++++
5 files changed, 117 insertions(+), 8 deletions(-)
diff --git a/drivers/pps/clients/pps-ktimer.c b/drivers/pps/clients/pps-ktimer.c
index 2728469..26ed7a2 100644
--- a/drivers/pps/clients/pps-ktimer.c
+++ b/drivers/pps/clients/pps-ktimer.c
@@ -48,7 +48,7 @@ static void pps_ktimer_event(unsigned long ptr)
dev_info(pps->dev, "PPS event at %lu\n", jiffies);
- pps_event(pps, &ts, PPS_CAPTUREASSERT, NULL);
+ pps_event_irq(pps, &ts, PPS_CAPTUREASSERT, NULL);
mod_timer(&ktimer, jiffies + HZ);
}
diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c
index 30789fa..7006f85 100644
--- a/drivers/pps/clients/pps-ldisc.c
+++ b/drivers/pps/clients/pps-ldisc.c
@@ -50,7 +50,7 @@ static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status,
/* Now do the PPS event report */
pps = (struct pps_device *)tty->disc_data;
if (pps != NULL) {
- pps_event(pps, ts, status ? PPS_CAPTUREASSERT :
+ pps_event_irq(pps, ts, status ? PPS_CAPTUREASSERT :
PPS_CAPTURECLEAR, NULL);
spin_unlock_irqrestore(&pps_ldisc_lock, flags);
dev_dbg(pps->dev, "PPS %s at %lu\n",
diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
index f5b2b78..ca3b4f8 100644
--- a/drivers/pps/kapi.c
+++ b/drivers/pps/kapi.c
@@ -32,9 +32,19 @@
#include <linux/slab.h>
/*
+ * Global variables
+ */
+
+/* PPS event workqueue */
+struct workqueue_struct *pps_event_workqueue;
+
+/*
* Local functions
*/
+static void assert_work_func(struct work_struct *work);
+static void clear_work_func(struct work_struct *work);
+
static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset)
{
ts->nsec += offset->nsec;
@@ -108,6 +118,9 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
init_waitqueue_head(&pps->queue);
spin_lock_init(&pps->lock);
+ INIT_WORK(&pps->assert_work, assert_work_func);
+ INIT_WORK(&pps->clear_work, clear_work_func);
+
/* Create the char device */
err = pps_register_cdev(pps);
if (err < 0) {
@@ -152,11 +165,12 @@ EXPORT_SYMBOL(pps_unregister_source);
* @event: the event type
* @data: userdef pointer
*
- * This function is used by each PPS client in order to register a new
- * PPS event into the system (it's usually called inside an IRQ handler).
+ * This function is used by PPS clients in order to register a new
+ * PPS event into the system. It should not be called from an IRQ
+ * handler. Use pps_event_irq instead.
*
- * If an echo function is associated with the PPS device it will be called
- * as:
+ * If an echo function is associated with the PPS device it will be
+ * called as:
* pps->info.echo(pps, event, data);
*/
void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
@@ -226,3 +240,76 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
spin_unlock_irqrestore(&pps->lock, flags);
}
EXPORT_SYMBOL(pps_event);
+
+/* Async event handlers */
+
+static void assert_work_func(struct work_struct *work)
+{
+ struct pps_device *pps = container_of(work,
+ struct pps_device, assert_work);
+
+ pps_event(pps, &pps->assert_work_ts, PPS_CAPTUREASSERT,
+ pps->assert_work_data);
+}
+
+static void clear_work_func(struct work_struct *work)
+{
+ struct pps_device *pps = container_of(work,
+ struct pps_device, clear_work);
+
+ pps_event(pps, &pps->clear_work_ts, PPS_CAPTURECLEAR,
+ pps->clear_work_data);
+}
+
+/* pps_event_irq - register a PPS event for deffered handling using
+ * workqueue
+ *
+ * @pps: the PPS device
+ * @ts: the event timestamp
+ * @event: the event type
+ * @data: userdef pointer
+ *
+ * This function is used by PPS clients in order to register a new
+ * PPS event into the system. It should be called from an IRQ handler
+ * only.
+ *
+ * If an echo function is associated with the PPS device it will be
+ * called as:
+ * pps->info.echo(pps, event, data);
+ */
+void pps_event_irq(struct pps_device *pps, struct pps_event_time *ts,
+ int event, void *data)
+{
+ /* check event type */
+ BUG_ON((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0);
+
+ if (event & PPS_CAPTUREASSERT) {
+ if (work_pending(&pps->assert_work)) {
+ dev_err(pps->dev, "deferred assert edge work haven't"
+ " been handled within a second\n");
+ /* FIXME: do something more intelligent
+ * then just exit */
+ } else {
+ /* now we can copy data safely */
+ pps->assert_work_ts = *ts;
+ pps->assert_work_data = data;
+
+ queue_work(pps_event_workqueue, &pps->assert_work);
+ }
+ }
+ if (event & PPS_CAPTURECLEAR) {
+ if (work_pending(&pps->clear_work)) {
+ dev_err(pps->dev, "deferred clear edge work haven't"
+ " been handled within a second\n");
+ /* FIXME: do something more intelligent
+ * then just exit */
+ } else {
+ /* now we can copy data safely */
+ pps->clear_work_ts = *ts;
+ pps->clear_work_data = data;
+
+ queue_work(pps_event_workqueue, &pps->clear_work);
+ }
+ }
+}
+EXPORT_SYMBOL(pps_event_irq);
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
index 79b4455..f642558 100644
--- a/drivers/pps/pps.c
+++ b/drivers/pps/pps.c
@@ -321,18 +321,26 @@ void pps_unregister_cdev(struct pps_device *pps)
static void __exit pps_exit(void)
{
- class_destroy(pps_class);
unregister_chrdev_region(pps_devt, PPS_MAX_SOURCES);
+ class_destroy(pps_class);
+ destroy_workqueue(pps_event_workqueue);
}
static int __init pps_init(void)
{
int err;
+ pps_event_workqueue = create_workqueue("pps");
+ if (!pps_event_workqueue) {
+ pr_err("failed to create workqueue\n");
+ return -ENOMEM;
+ }
+
pps_class = class_create(THIS_MODULE, "pps");
if (!pps_class) {
pr_err("failed to allocate class\n");
- return -ENOMEM;
+ err = -ENOMEM;
+ goto destroy_workqueue;
}
pps_class->dev_attrs = pps_attrs;
@@ -350,6 +358,8 @@ static int __init pps_init(void)
remove_class:
class_destroy(pps_class);
+destroy_workqueue:
+ destroy_workqueue(pps_event_workqueue);
return err;
}
diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h
index 1aedf50..5af0498 100644
--- a/include/linux/pps_kernel.h
+++ b/include/linux/pps_kernel.h
@@ -26,6 +26,7 @@
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/time.h>
+#include <linux/workqueue.h>
/*
* Global defines
@@ -70,6 +71,13 @@ struct pps_device {
struct device *dev;
struct fasync_struct *async_queue; /* fasync method */
spinlock_t lock;
+
+ struct work_struct assert_work;
+ struct work_struct clear_work;
+ struct pps_event_time assert_work_ts;
+ struct pps_event_time clear_work_ts;
+ void *assert_work_data;
+ void *clear_work_data;
};
/*
@@ -78,6 +86,8 @@ struct pps_device {
extern struct device_attribute pps_attrs[];
+extern struct workqueue_struct *pps_event_workqueue;
+
/*
* Exported functions
*/
@@ -89,6 +99,8 @@ extern int pps_register_cdev(struct pps_device *pps);
extern void pps_unregister_cdev(struct pps_device *pps);
extern void pps_event(struct pps_device *pps,
struct pps_event_time *ts, int event, void *data);
+extern void pps_event_irq(struct pps_device *pps,
+ struct pps_event_time *ts, int event, void *data);
static inline void timespec_to_pps_ktime(struct pps_ktime *kt,
struct timespec ts)
--
1.7.2.3
next prev parent reply other threads:[~2010-11-18 16:13 UTC|newest]
Thread overview: 50+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-11-18 16:00 [PATCHv4 00/17] pps: several fixes and improvements Alexander Gordeev
2010-11-18 16:00 ` [PATCHv4 01/17] pps: trivial fixes Alexander Gordeev
2010-11-18 16:00 ` [PATCHv4 02/17] pps: declare variables where they are used in switch Alexander Gordeev
2010-11-18 16:00 ` [PATCHv4 03/17] pps: fix race in PPS_FETCH handler Alexander Gordeev
2010-11-20 15:20 ` Rodolfo Giometti
2010-11-18 16:00 ` [PATCHv4 04/17] pps: unify timestamp gathering Alexander Gordeev
2010-11-18 16:00 ` [PATCHv4 05/17] pps: access pps device by direct pointer Alexander Gordeev
2010-11-20 15:44 ` Rodolfo Giometti
2010-11-20 22:33 ` Alexander Gordeev
2010-11-21 8:26 ` Rodolfo Giometti
2010-11-22 15:01 ` Alexander Gordeev
2010-11-21 14:12 ` Alan Cox
2010-11-22 14:55 ` Alexander Gordeev
2010-11-18 16:00 ` [PATCHv4 06/17] pps: convert printk/pr_* to dev_* Alexander Gordeev
2010-11-20 15:49 ` Rodolfo Giometti
2010-11-20 21:33 ` Alexander Gordeev
2010-11-20 21:42 ` Joe Perches
2010-11-20 22:38 ` Alexander Gordeev
2010-11-21 8:19 ` Rodolfo Giometti
2010-11-18 16:01 ` [PATCHv4 07/17] pps: move idr stuff to pps.c Alexander Gordeev
2010-11-20 15:51 ` Rodolfo Giometti
2010-11-18 16:01 ` Alexander Gordeev [this message]
2010-11-20 16:08 ` [PATCHv4 08/17] pps: add async PPS event handler Rodolfo Giometti
2010-11-20 23:23 ` Alexander Gordeev
2010-11-21 8:37 ` Rodolfo Giometti
2010-11-18 16:01 ` [PATCHv4 09/17] pps: don't disable interrupts when using spin locks Alexander Gordeev
2010-11-20 16:09 ` Rodolfo Giometti
2010-11-18 16:01 ` [PATCHv4 10/17] pps: use BUG_ON for kernel API safety checks Alexander Gordeev
2010-11-20 16:13 ` Rodolfo Giometti
2010-11-20 17:01 ` Joe Perches
2010-11-20 18:30 ` Rodolfo Giometti
2010-11-21 0:40 ` Alexander Gordeev
2010-11-21 1:18 ` Joe Perches
2010-11-21 8:42 ` Rodolfo Giometti
2010-11-21 0:13 ` Alexander Gordeev
2010-11-21 8:41 ` Rodolfo Giometti
2010-11-18 16:01 ` [PATCHv4 11/17] pps: simplify conditions a bit Alexander Gordeev
2010-11-20 16:15 ` Rodolfo Giometti
2010-11-18 16:01 ` [PATCHv4 12/17] pps: timestamp is always passed to dcd_change() Alexander Gordeev
2010-11-20 16:23 ` Rodolfo Giometti
2010-11-21 0:44 ` Alexander Gordeev
2010-11-21 8:42 ` Rodolfo Giometti
2010-11-18 16:01 ` [PATCHv4 13/17] ntp: add hardpps implementation Alexander Gordeev
2010-11-20 16:27 ` Rodolfo Giometti
2010-11-21 1:05 ` Alexander Gordeev
2010-11-18 16:01 ` [PATCHv4 14/17] pps: capture MONOTONIC_RAW timestamps as well Alexander Gordeev
2010-11-18 19:42 ` john stultz
2010-11-18 16:01 ` [PATCHv4 15/17] pps: add kernel consumer support Alexander Gordeev
2010-11-18 16:01 ` [PATCHv4 16/17] pps: add parallel port PPS client Alexander Gordeev
2010-11-18 16:01 ` [PATCHv4 17/17] pps: add parallel port PPS signal generator Alexander Gordeev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=65eae4de46680aa8d644619f6dc61ba17f1fdc77.1290087479.git.lasaine@lvk.cs.msu.su \
--to=lasaine@lvk.cs.msu.su \
--cc=akpm@linux-foundation.org \
--cc=giometti@enneenne.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linuxpps@ml.enneenne.com \
--cc=tj@kernel.org \
--cc=yoush@cs.msu.su \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®