From: Andres Salomon <dilinger@queued.net>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: Paul Fox <pgf@laptop.org>, Daniel Drake <dsd@laptop.org>,
"Richard A. Smith" <richard@laptop.org>,
linux-kernel@vger.kernel.org, libertas-dev@lists.infradead.org,
linux-wireless@vger.kernel.org, netdev@vger.kernel.org,
platform-driver-x86@vger.kernel.org, devel@driverdev.osuosl.org,
Thomas Gleixner <tglx@linutronix.de>,
Ingo Molnar <mingo@redhat.com>, "H. Peter Anvin" <hpa@zytor.com>,
x86@kernel.org, Dan Williams <dcbw@redhat.com>,
"John W. Linville" <linville@tuxdriver.com>,
Matthew Garrett <mjg@redhat.com>, Anton Vorontsov <cbou@mail.ru>,
David Woodhouse <dwmw2@infradead.org>,
Chris Ball <cjb@laptop.org>,
Jon Nettleton <jon.nettleton@gmail.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Subject: [PATCH 3/9] Platform: OLPC: allow EC cmd to be overridden, and create a workqueue to call it
Date: Wed, 18 Jul 2012 21:28:18 -0700 [thread overview]
Message-ID: <20120718212818.5ed01c8a@dev.queued.net> (raw)
In-Reply-To: <20120718182144.2d7b0b50@dev.queued.net>
This provides a new API allows different OLPC architectures to override the
EC driver. x86 and ARM OLPC machines use completely different EC backends.
The olpc_ec_cmd is synchronous, and waits for the workqueue to send the
command to the EC. Multiple callers can run olpc_ec_cmd() at once, and
they will by serialized and sleep while only one executes on the EC at a time.
We don't provide an unregister function, as that doesn't make sense within
the context of OLPC machines - there's only ever 1 EC, it's critical to
functionality, and it certainly not hotpluggable.
Signed-off-by: Andres Salomon <dilinger@queued.net>
---
drivers/platform/olpc/olpc-ec.c | 112 ++++++++++++++++++++++++++++++++++++++-
include/linux/olpc-ec.h | 6 ++
2 files changed, 116 insertions(+), 2 deletions(-)
diff --git a/drivers/platform/olpc/olpc-ec.c b/drivers/platform/olpc/olpc-ec.c
index 4202603..44e6a4f 100644
--- a/drivers/platform/olpc/olpc-ec.c
+++ b/drivers/platform/olpc/olpc-ec.c
@@ -5,12 +5,120 @@
*
* Licensed under the GPL v2 or later.
*/
+#include <linux/completion.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/olpc-ec.h>
#include <asm/olpc.h>
+struct ec_cmd_desc {
+ u8 cmd;
+ u8 *inbuf, *outbuf;
+ size_t inlen, outlen;
+
+ int err;
+ struct completion finished;
+ struct list_head node;
+
+ void *priv;
+};
+
+static void olpc_ec_worker(struct work_struct *w);
+
+static DECLARE_WORK(ec_worker, olpc_ec_worker);
+static LIST_HEAD(ec_cmd_q);
+static DEFINE_SPINLOCK(ec_cmd_q_lock);
+
+static struct olpc_ec_driver *ec_driver;
+static void *ec_cb_arg;
+static DEFINE_MUTEX(ec_cb_lock);
+
+void olpc_ec_driver_register(struct olpc_ec_driver *drv, void *arg)
+{
+ ec_driver = drv;
+ ec_cb_arg = arg;
+}
+EXPORT_SYMBOL_GPL(olpc_ec_driver_register);
+
+static void olpc_ec_worker(struct work_struct *w)
+{
+ struct ec_cmd_desc *desc = NULL;
+ unsigned long flags;
+
+ /* Grab the first pending command from the queue */
+ spin_lock_irqsave(&ec_cmd_q_lock, flags);
+ if (!list_empty(&ec_cmd_q)) {
+ desc = list_first_entry(&ec_cmd_q, struct ec_cmd_desc, node);
+ list_del(&desc->node);
+ }
+ spin_unlock_irqrestore(&ec_cmd_q_lock, flags);
+
+ /* Do we actually have anything to do? */
+ if (!desc)
+ return;
+
+ /* Protect the EC hw with a mutex; only run one cmd at a time */
+ mutex_lock(&ec_cb_lock);
+ desc->err = ec_driver->ec_cmd(desc->cmd, desc->inbuf, desc->inlen,
+ desc->outbuf, desc->outlen, ec_cb_arg);
+ mutex_unlock(&ec_cb_lock);
+
+ /* Finished, wake up olpc_ec_cmd() */
+ complete(&desc->finished);
+
+ /* Run the worker thread again in case there are more cmds pending */
+ schedule_work(&ec_worker);
+}
+
+/*
+ * Throw a cmd descripter onto the list. We now have SMP OLPC machines, so
+ * locking is pretty critical.
+ */
+static void queue_ec_descriptor(struct ec_cmd_desc *desc)
+{
+ unsigned long flags;
+
+ INIT_LIST_HEAD(&desc->node);
+
+ spin_lock_irqsave(&ec_cmd_q_lock, flags);
+ list_add_tail(&desc->node, &ec_cmd_q);
+ spin_unlock_irqrestore(&ec_cmd_q_lock, flags);
+
+ schedule_work(&ec_worker);
+}
+
int olpc_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf, size_t outlen)
{
- /* Currently a stub; this will be expanded upon later. */
- return olpc_ec_cmd_x86(cmd, inbuf, inlen, outbuf, outlen);
+ struct ec_cmd_desc desc;
+
+ /* XXX: this will be removed in later patches */
+ /* Are we using old-style callers? */
+ if (!ec_driver || !ec_driver->ec_cmd)
+ return olpc_ec_cmd_x86(cmd, inbuf, inlen, outbuf, outlen);
+
+ /* Ensure a driver and ec hook have been registered */
+ if (WARN_ON(!ec_driver || !ec_driver->ec_cmd))
+ return -ENODEV;
+
+ might_sleep();
+
+ desc.cmd = cmd;
+ desc.inbuf = inbuf;
+ desc.outbuf = outbuf;
+ desc.inlen = inlen;
+ desc.outlen = outlen;
+ desc.err = 0;
+ init_completion(&desc.finished);
+
+ queue_ec_descriptor(&desc);
+
+ /* Timeouts must be handled in the platform-specific EC hook */
+ wait_for_completion(&desc.finished);
+
+ /* The worker thread dequeues the cmd; no need to do anything here */
+ return desc.err;
}
EXPORT_SYMBOL_GPL(olpc_ec_cmd);
diff --git a/include/linux/olpc-ec.h b/include/linux/olpc-ec.h
index 6d4e426..231e96f 100644
--- a/include/linux/olpc-ec.h
+++ b/include/linux/olpc-ec.h
@@ -14,8 +14,14 @@
#define EC_SCI_QUERY 0x84
#define EC_EXT_SCI_QUERY 0x85
+struct olpc_ec_driver {
+ int (*ec_cmd)(u8, u8 *, size_t, u8 *, size_t, void *);
+};
+
#ifdef CONFIG_OLPC
+extern void olpc_ec_driver_register(struct olpc_ec_driver *drv, void *arg);
+
extern int olpc_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf,
size_t outlen);
--
1.7.2.5
WARNING: multiple messages have this Message-ID (diff)
From: Andres Salomon <dilinger@queued.net>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: devel@driverdev.osuosl.org, Daniel Drake <dsd@laptop.org>,
libertas-dev@lists.infradead.org, Dan Williams <dcbw@redhat.com>,
netdev@vger.kernel.org, Jon Nettleton <jon.nettleton@gmail.com>,
x86@kernel.org, linux-wireless@vger.kernel.org,
linux-kernel@vger.kernel.org,
platform-driver-x86@vger.kernel.org,
"Richard A. Smith" <richard@laptop.org>,
Paul Fox <pgf@laptop.org>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Anton Vorontsov <cbou@mail.ru>, "H. Peter Anvin" <hpa@zytor.com>,
Thomas Gleixner <tglx@linutronix.de>, Chris Ball <cjb@laptop.org>,
David Woodhouse <dwmw2@infradead.org>,
Ingo Molnar <mingo@redhat.com>,
"John W. Linville" <linville@tuxdriver.com>,
Matthew Garrett <mjg@redhat.com>
Subject: [PATCH 3/9] Platform: OLPC: allow EC cmd to be overridden, and create a workqueue to call it
Date: Wed, 18 Jul 2012 21:28:18 -0700 [thread overview]
Message-ID: <20120718212818.5ed01c8a@dev.queued.net> (raw)
In-Reply-To: <20120718182144.2d7b0b50@dev.queued.net>
This provides a new API allows different OLPC architectures to override the
EC driver. x86 and ARM OLPC machines use completely different EC backends.
The olpc_ec_cmd is synchronous, and waits for the workqueue to send the
command to the EC. Multiple callers can run olpc_ec_cmd() at once, and
they will by serialized and sleep while only one executes on the EC at a time.
We don't provide an unregister function, as that doesn't make sense within
the context of OLPC machines - there's only ever 1 EC, it's critical to
functionality, and it certainly not hotpluggable.
Signed-off-by: Andres Salomon <dilinger@queued.net>
---
drivers/platform/olpc/olpc-ec.c | 112 ++++++++++++++++++++++++++++++++++++++-
include/linux/olpc-ec.h | 6 ++
2 files changed, 116 insertions(+), 2 deletions(-)
diff --git a/drivers/platform/olpc/olpc-ec.c b/drivers/platform/olpc/olpc-ec.c
index 4202603..44e6a4f 100644
--- a/drivers/platform/olpc/olpc-ec.c
+++ b/drivers/platform/olpc/olpc-ec.c
@@ -5,12 +5,120 @@
*
* Licensed under the GPL v2 or later.
*/
+#include <linux/completion.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/olpc-ec.h>
#include <asm/olpc.h>
+struct ec_cmd_desc {
+ u8 cmd;
+ u8 *inbuf, *outbuf;
+ size_t inlen, outlen;
+
+ int err;
+ struct completion finished;
+ struct list_head node;
+
+ void *priv;
+};
+
+static void olpc_ec_worker(struct work_struct *w);
+
+static DECLARE_WORK(ec_worker, olpc_ec_worker);
+static LIST_HEAD(ec_cmd_q);
+static DEFINE_SPINLOCK(ec_cmd_q_lock);
+
+static struct olpc_ec_driver *ec_driver;
+static void *ec_cb_arg;
+static DEFINE_MUTEX(ec_cb_lock);
+
+void olpc_ec_driver_register(struct olpc_ec_driver *drv, void *arg)
+{
+ ec_driver = drv;
+ ec_cb_arg = arg;
+}
+EXPORT_SYMBOL_GPL(olpc_ec_driver_register);
+
+static void olpc_ec_worker(struct work_struct *w)
+{
+ struct ec_cmd_desc *desc = NULL;
+ unsigned long flags;
+
+ /* Grab the first pending command from the queue */
+ spin_lock_irqsave(&ec_cmd_q_lock, flags);
+ if (!list_empty(&ec_cmd_q)) {
+ desc = list_first_entry(&ec_cmd_q, struct ec_cmd_desc, node);
+ list_del(&desc->node);
+ }
+ spin_unlock_irqrestore(&ec_cmd_q_lock, flags);
+
+ /* Do we actually have anything to do? */
+ if (!desc)
+ return;
+
+ /* Protect the EC hw with a mutex; only run one cmd at a time */
+ mutex_lock(&ec_cb_lock);
+ desc->err = ec_driver->ec_cmd(desc->cmd, desc->inbuf, desc->inlen,
+ desc->outbuf, desc->outlen, ec_cb_arg);
+ mutex_unlock(&ec_cb_lock);
+
+ /* Finished, wake up olpc_ec_cmd() */
+ complete(&desc->finished);
+
+ /* Run the worker thread again in case there are more cmds pending */
+ schedule_work(&ec_worker);
+}
+
+/*
+ * Throw a cmd descripter onto the list. We now have SMP OLPC machines, so
+ * locking is pretty critical.
+ */
+static void queue_ec_descriptor(struct ec_cmd_desc *desc)
+{
+ unsigned long flags;
+
+ INIT_LIST_HEAD(&desc->node);
+
+ spin_lock_irqsave(&ec_cmd_q_lock, flags);
+ list_add_tail(&desc->node, &ec_cmd_q);
+ spin_unlock_irqrestore(&ec_cmd_q_lock, flags);
+
+ schedule_work(&ec_worker);
+}
+
int olpc_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf, size_t outlen)
{
- /* Currently a stub; this will be expanded upon later. */
- return olpc_ec_cmd_x86(cmd, inbuf, inlen, outbuf, outlen);
+ struct ec_cmd_desc desc;
+
+ /* XXX: this will be removed in later patches */
+ /* Are we using old-style callers? */
+ if (!ec_driver || !ec_driver->ec_cmd)
+ return olpc_ec_cmd_x86(cmd, inbuf, inlen, outbuf, outlen);
+
+ /* Ensure a driver and ec hook have been registered */
+ if (WARN_ON(!ec_driver || !ec_driver->ec_cmd))
+ return -ENODEV;
+
+ might_sleep();
+
+ desc.cmd = cmd;
+ desc.inbuf = inbuf;
+ desc.outbuf = outbuf;
+ desc.inlen = inlen;
+ desc.outlen = outlen;
+ desc.err = 0;
+ init_completion(&desc.finished);
+
+ queue_ec_descriptor(&desc);
+
+ /* Timeouts must be handled in the platform-specific EC hook */
+ wait_for_completion(&desc.finished);
+
+ /* The worker thread dequeues the cmd; no need to do anything here */
+ return desc.err;
}
EXPORT_SYMBOL_GPL(olpc_ec_cmd);
diff --git a/include/linux/olpc-ec.h b/include/linux/olpc-ec.h
index 6d4e426..231e96f 100644
--- a/include/linux/olpc-ec.h
+++ b/include/linux/olpc-ec.h
@@ -14,8 +14,14 @@
#define EC_SCI_QUERY 0x84
#define EC_EXT_SCI_QUERY 0x85
+struct olpc_ec_driver {
+ int (*ec_cmd)(u8, u8 *, size_t, u8 *, size_t, void *);
+};
+
#ifdef CONFIG_OLPC
+extern void olpc_ec_driver_register(struct olpc_ec_driver *drv, void *arg);
+
extern int olpc_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf,
size_t outlen);
--
1.7.2.5
next prev parent reply other threads:[~2012-07-19 4:28 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-07-19 1:21 [PATCH 0/9] OLPC: create a generic OLPC EC driver Andres Salomon
2012-07-19 1:25 ` [PATCH 1/9] Platform: OLPC: add a stub to drivers/platform/ for the " Andres Salomon
2012-07-19 1:26 ` [PATCH 2/9] drivers: OLPC: update various drivers to include olpc-ec.h Andres Salomon
2012-07-19 1:26 ` [PATCH 3/9] Platform: OLPC: allow EC cmd to be overridden, and create a workqueue to call it Andres Salomon
2012-07-19 1:27 ` [PATCH 4/9] Platform: OLPC: turn EC driver into a platform_driver Andres Salomon
2012-07-19 1:29 ` [PATCH 5/9] Platform: OLPC: add a suspended flag to the EC driver Andres Salomon
2012-07-19 1:31 ` [PATCH 6/9] x86: OLPC: switch over to using new EC driver on x86 Andres Salomon
2012-07-19 1:31 ` [PATCH 7/9] Platform: OLPC: move debugfs support from x86 EC driver Andres Salomon
2012-07-19 1:32 ` [PATCH 8/9] Platform: OLPC: move global variables into priv struct Andres Salomon
2012-07-19 1:32 ` [PATCH 9/9] x86: OLPC: move s/r-related EC cmds to EC driver Andres Salomon
2012-07-19 4:26 ` [PATCH 1/9] Platform: OLPC: add a stub to drivers/platform/ for the OLPC " Andres Salomon
2012-07-19 4:26 ` [PATCH 2/9] drivers: OLPC: update various drivers to include olpc-ec.h Andres Salomon
2012-07-19 4:28 ` Andres Salomon [this message]
2012-07-19 4:28 ` [PATCH 3/9] Platform: OLPC: allow EC cmd to be overridden, and create a workqueue to call it Andres Salomon
2012-07-19 4:28 ` [PATCH 4/9] Platform: OLPC: turn EC driver into a platform_driver Andres Salomon
2012-07-19 4:28 ` Andres Salomon
2012-07-19 4:28 ` [PATCH 5/9] Platform: OLPC: add a suspended flag to the EC driver Andres Salomon
2012-07-19 4:28 ` Andres Salomon
2012-07-19 4:28 ` [PATCH 6/9] x86: OLPC: switch over to using new EC driver on x86 Andres Salomon
2012-07-19 4:28 ` Andres Salomon
2012-07-19 4:36 ` Andres Salomon
2012-07-19 4:28 ` [PATCH 7/9] Platform: OLPC: move debugfs support from x86 EC driver Andres Salomon
2012-07-19 4:28 ` Andres Salomon
2012-07-19 4:29 ` [PATCH 8/9] Platform: OLPC: move global variables into priv struct Andres Salomon
2012-07-19 4:29 ` Andres Salomon
2012-07-19 4:29 ` [PATCH 9/9] x86: OLPC: move s/r-related EC cmds to EC driver Andres Salomon
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=20120718212818.5ed01c8a@dev.queued.net \
--to=dilinger@queued.net \
--cc=akpm@linux-foundation.org \
--cc=cbou@mail.ru \
--cc=cjb@laptop.org \
--cc=dcbw@redhat.com \
--cc=devel@driverdev.osuosl.org \
--cc=dsd@laptop.org \
--cc=dwmw2@infradead.org \
--cc=gregkh@linuxfoundation.org \
--cc=hpa@zytor.com \
--cc=jon.nettleton@gmail.com \
--cc=libertas-dev@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
--cc=linville@tuxdriver.com \
--cc=mingo@redhat.com \
--cc=mjg@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=pgf@laptop.org \
--cc=platform-driver-x86@vger.kernel.org \
--cc=richard@laptop.org \
--cc=tglx@linutronix.de \
--cc=x86@kernel.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.