summaryrefslogtreecommitdiffstats
path: root/kernel/Documentation/driver-model/design-patterns.txt
diff options
context:
space:
mode:
authorYunhong Jiang <yunhong.jiang@intel.com>2015-08-04 12:17:53 -0700
committerYunhong Jiang <yunhong.jiang@intel.com>2015-08-04 15:44:42 -0700
commit9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (patch)
tree1c9cafbcd35f783a87880a10f85d1a060db1a563 /kernel/Documentation/driver-model/design-patterns.txt
parent98260f3884f4a202f9ca5eabed40b1354c489b29 (diff)
Add the rt linux 4.1.3-rt3 as base
Import the rt linux 4.1.3-rt3 as OPNFV kvm base. It's from git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git linux-4.1.y-rt and the base is: commit 0917f823c59692d751951bf5ea699a2d1e2f26a2 Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Date: Sat Jul 25 12:13:34 2015 +0200 Prepare v4.1.3-rt3 Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> We lose all the git history this way and it's not good. We should apply another opnfv project repo in future. Change-Id: I87543d81c9df70d99c5001fbdf646b202c19f423 Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Diffstat (limited to 'kernel/Documentation/driver-model/design-patterns.txt')
-rw-r--r--kernel/Documentation/driver-model/design-patterns.txt116
1 files changed, 116 insertions, 0 deletions
diff --git a/kernel/Documentation/driver-model/design-patterns.txt b/kernel/Documentation/driver-model/design-patterns.txt
new file mode 100644
index 000000000..ba7b2df64
--- /dev/null
+++ b/kernel/Documentation/driver-model/design-patterns.txt
@@ -0,0 +1,116 @@
+
+Device Driver Design Patterns
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This document describes a few common design patterns found in device drivers.
+It is likely that subsystem maintainers will ask driver developers to
+conform to these design patterns.
+
+1. State Container
+2. container_of()
+
+
+1. State Container
+~~~~~~~~~~~~~~~~~~
+
+While the kernel contains a few device drivers that assume that they will
+only be probed() once on a certain system (singletons), it is custom to assume
+that the device the driver binds to will appear in several instances. This
+means that the probe() function and all callbacks need to be reentrant.
+
+The most common way to achieve this is to use the state container design
+pattern. It usually has this form:
+
+struct foo {
+ spinlock_t lock; /* Example member */
+ (...)
+};
+
+static int foo_probe(...)
+{
+ struct foo *foo;
+
+ foo = devm_kzalloc(dev, sizeof(*foo), GFP_KERNEL);
+ if (!foo)
+ return -ENOMEM;
+ spin_lock_init(&foo->lock);
+ (...)
+}
+
+This will create an instance of struct foo in memory every time probe() is
+called. This is our state container for this instance of the device driver.
+Of course it is then necessary to always pass this instance of the
+state around to all functions that need access to the state and its members.
+
+For example, if the driver is registering an interrupt handler, you would
+pass around a pointer to struct foo like this:
+
+static irqreturn_t foo_handler(int irq, void *arg)
+{
+ struct foo *foo = arg;
+ (...)
+}
+
+static int foo_probe(...)
+{
+ struct foo *foo;
+
+ (...)
+ ret = request_irq(irq, foo_handler, 0, "foo", foo);
+}
+
+This way you always get a pointer back to the correct instance of foo in
+your interrupt handler.
+
+
+2. container_of()
+~~~~~~~~~~~~~~~~~
+
+Continuing on the above example we add an offloaded work:
+
+struct foo {
+ spinlock_t lock;
+ struct workqueue_struct *wq;
+ struct work_struct offload;
+ (...)
+};
+
+static void foo_work(struct work_struct *work)
+{
+ struct foo *foo = container_of(work, struct foo, offload);
+
+ (...)
+}
+
+static irqreturn_t foo_handler(int irq, void *arg)
+{
+ struct foo *foo = arg;
+
+ queue_work(foo->wq, &foo->offload);
+ (...)
+}
+
+static int foo_probe(...)
+{
+ struct foo *foo;
+
+ foo->wq = create_singlethread_workqueue("foo-wq");
+ INIT_WORK(&foo->offload, foo_work);
+ (...)
+}
+
+The design pattern is the same for an hrtimer or something similar that will
+return a single argument which is a pointer to a struct member in the
+callback.
+
+container_of() is a macro defined in <linux/kernel.h>
+
+What container_of() does is to obtain a pointer to the containing struct from
+a pointer to a member by a simple subtraction using the offsetof() macro from
+standard C, which allows something similar to object oriented behaviours.
+Notice that the contained member must not be a pointer, but an actual member
+for this to work.
+
+We can see here that we avoid having global pointers to our struct foo *
+instance this way, while still keeping the number of parameters passed to the
+work function to a single pointer.