aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaarten Lankhorst <maarten.lankhorst@canonical.com>2014-07-01 06:57:20 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-07-08 15:50:59 -0400
commit606b23ad609c71cfb37eeb972ea4c901034edd3c (patch)
tree2c6493abc82330a61911937409ace22d78fd3893
parente941759c74a44d6ac2eed21bb0a38b21fe4559e2 (diff)
seqno-fence: Hardware dma-buf implementation of fencing (v6)
This type of fence can be used with hardware synchronization for simple hardware that can block execution until the condition (dma_buf[offset] - value) >= 0 has been met when WAIT_GEQUAL is used, or (dma_buf[offset] != 0) has been met when WAIT_NONZERO is set. A software fallback still has to be provided in case the fence is used with a device that doesn't support this mechanism. It is useful to expose this for graphics cards that have an op to support this. Some cards like i915 can export those, but don't have an option to wait, so they need the software fallback. I extended the original patch by Rob Clark. v1: Original v2: Renamed from bikeshed to seqno, moved into dma-fence.c since not much was left of the file. Lots of documentation added. v3: Use fence_ops instead of custom callbacks. Moved to own file to avoid circular dependency between dma-buf.h and fence.h v4: Add spinlock pointer to seqno_fence_init v5: Add condition member to allow wait for != 0. Fix small style errors pointed out by checkpatch. v6: Move to a separate file. Fix up api changes in fences. Signed-off-by: Maarten Lankhorst <maarten.lankhorst@canonical.com> Acked-by: Sumit Semwal <sumit.semwal@linaro.org> Acked-by: Daniel Vetter <daniel@ffwll.ch> Reviewed-by: Rob Clark <robdclark@gmail.com> #v4 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--Documentation/DocBook/device-drivers.tmpl2
-rw-r--r--MAINTAINERS2
-rw-r--r--drivers/dma-buf/Makefile2
-rw-r--r--drivers/dma-buf/seqno-fence.c73
-rw-r--r--include/linux/seqno-fence.h116
5 files changed, 193 insertions, 2 deletions
diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl
index e634657efb52..ed0ef00cd7bc 100644
--- a/Documentation/DocBook/device-drivers.tmpl
+++ b/Documentation/DocBook/device-drivers.tmpl
@@ -130,7 +130,9 @@ X!Edrivers/base/interface.c
130 <sect1><title>Device Drivers DMA Management</title> 130 <sect1><title>Device Drivers DMA Management</title>
131!Edrivers/dma-buf/dma-buf.c 131!Edrivers/dma-buf/dma-buf.c
132!Edrivers/dma-buf/fence.c 132!Edrivers/dma-buf/fence.c
133!Edrivers/dma-buf/seqno-fence.c
133!Iinclude/linux/fence.h 134!Iinclude/linux/fence.h
135!Iinclude/linux/seqno-fence.h
134!Iinclude/linux/reservation.h 136!Iinclude/linux/reservation.h
135!Edrivers/base/dma-coherent.c 137!Edrivers/base/dma-coherent.c
136!Edrivers/base/dma-mapping.c 138!Edrivers/base/dma-mapping.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 65c8f534b22f..7c97777dd1b3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2901,7 +2901,7 @@ L: linux-media@vger.kernel.org
2901L: dri-devel@lists.freedesktop.org 2901L: dri-devel@lists.freedesktop.org
2902L: linaro-mm-sig@lists.linaro.org 2902L: linaro-mm-sig@lists.linaro.org
2903F: drivers/dma-buf/ 2903F: drivers/dma-buf/
2904F: include/linux/dma-buf* include/linux/reservation.h include/linux/fence.h 2904F: include/linux/dma-buf* include/linux/reservation.h include/linux/*fence.h
2905F: Documentation/dma-buf-sharing.txt 2905F: Documentation/dma-buf-sharing.txt
2906T: git git://git.linaro.org/people/sumitsemwal/linux-dma-buf.git 2906T: git git://git.linaro.org/people/sumitsemwal/linux-dma-buf.git
2907 2907
diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
index d7825bfe630e..57a675f90cd0 100644
--- a/drivers/dma-buf/Makefile
+++ b/drivers/dma-buf/Makefile
@@ -1 +1 @@
obj-y := dma-buf.o fence.o reservation.o obj-y := dma-buf.o fence.o reservation.o seqno-fence.o
diff --git a/drivers/dma-buf/seqno-fence.c b/drivers/dma-buf/seqno-fence.c
new file mode 100644
index 000000000000..7d12a39a4b57
--- /dev/null
+++ b/drivers/dma-buf/seqno-fence.c
@@ -0,0 +1,73 @@
1/*
2 * seqno-fence, using a dma-buf to synchronize fencing
3 *
4 * Copyright (C) 2012 Texas Instruments
5 * Copyright (C) 2012-2014 Canonical Ltd
6 * Authors:
7 * Rob Clark <robdclark@gmail.com>
8 * Maarten Lankhorst <maarten.lankhorst@canonical.com>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 */
19
20#include <linux/slab.h>
21#include <linux/export.h>
22#include <linux/seqno-fence.h>
23
24static const char *seqno_fence_get_driver_name(struct fence *fence)
25{
26 struct seqno_fence *seqno_fence = to_seqno_fence(fence);
27 return seqno_fence->ops->get_driver_name(fence);
28}
29
30static const char *seqno_fence_get_timeline_name(struct fence *fence)
31{
32 struct seqno_fence *seqno_fence = to_seqno_fence(fence);
33 return seqno_fence->ops->get_timeline_name(fence);
34}
35
36static bool seqno_enable_signaling(struct fence *fence)
37{
38 struct seqno_fence *seqno_fence = to_seqno_fence(fence);
39 return seqno_fence->ops->enable_signaling(fence);
40}
41
42static bool seqno_signaled(struct fence *fence)
43{
44 struct seqno_fence *seqno_fence = to_seqno_fence(fence);
45 return seqno_fence->ops->signaled && seqno_fence->ops->signaled(fence);
46}
47
48static void seqno_release(struct fence *fence)
49{
50 struct seqno_fence *f = to_seqno_fence(fence);
51
52 dma_buf_put(f->sync_buf);
53 if (f->ops->release)
54 f->ops->release(fence);
55 else
56 fence_free(&f->base);
57}
58
59static signed long seqno_wait(struct fence *fence, bool intr, signed long timeout)
60{
61 struct seqno_fence *f = to_seqno_fence(fence);
62 return f->ops->wait(fence, intr, timeout);
63}
64
65const struct fence_ops seqno_fence_ops = {
66 .get_driver_name = seqno_fence_get_driver_name,
67 .get_timeline_name = seqno_fence_get_timeline_name,
68 .enable_signaling = seqno_enable_signaling,
69 .signaled = seqno_signaled,
70 .wait = seqno_wait,
71 .release = seqno_release,
72};
73EXPORT_SYMBOL(seqno_fence_ops);
diff --git a/include/linux/seqno-fence.h b/include/linux/seqno-fence.h
new file mode 100644
index 000000000000..3d6003de4b0d
--- /dev/null
+++ b/include/linux/seqno-fence.h
@@ -0,0 +1,116 @@
1/*
2 * seqno-fence, using a dma-buf to synchronize fencing
3 *
4 * Copyright (C) 2012 Texas Instruments
5 * Copyright (C) 2012 Canonical Ltd
6 * Authors:
7 * Rob Clark <robdclark@gmail.com>
8 * Maarten Lankhorst <maarten.lankhorst@canonical.com>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 */
19
20#ifndef __LINUX_SEQNO_FENCE_H
21#define __LINUX_SEQNO_FENCE_H
22
23#include <linux/fence.h>
24#include <linux/dma-buf.h>
25
26enum seqno_fence_condition {
27 SEQNO_FENCE_WAIT_GEQUAL,
28 SEQNO_FENCE_WAIT_NONZERO
29};
30
31struct seqno_fence {
32 struct fence base;
33
34 const struct fence_ops *ops;
35 struct dma_buf *sync_buf;
36 uint32_t seqno_ofs;
37 enum seqno_fence_condition condition;
38};
39
40extern const struct fence_ops seqno_fence_ops;
41
42/**
43 * to_seqno_fence - cast a fence to a seqno_fence
44 * @fence: fence to cast to a seqno_fence
45 *
46 * Returns NULL if the fence is not a seqno_fence,
47 * or the seqno_fence otherwise.
48 */
49static inline struct seqno_fence *
50to_seqno_fence(struct fence *fence)
51{
52 if (fence->ops != &seqno_fence_ops)
53 return NULL;
54 return container_of(fence, struct seqno_fence, base);
55}
56
57/**
58 * seqno_fence_init - initialize a seqno fence
59 * @fence: seqno_fence to initialize
60 * @lock: pointer to spinlock to use for fence
61 * @sync_buf: buffer containing the memory location to signal on
62 * @context: the execution context this fence is a part of
63 * @seqno_ofs: the offset within @sync_buf
64 * @seqno: the sequence # to signal on
65 * @ops: the fence_ops for operations on this seqno fence
66 *
67 * This function initializes a struct seqno_fence with passed parameters,
68 * and takes a reference on sync_buf which is released on fence destruction.
69 *
70 * A seqno_fence is a dma_fence which can complete in software when
71 * enable_signaling is called, but it also completes when
72 * (s32)((sync_buf)[seqno_ofs] - seqno) >= 0 is true
73 *
74 * The seqno_fence will take a refcount on the sync_buf until it's
75 * destroyed, but actual lifetime of sync_buf may be longer if one of the
76 * callers take a reference to it.
77 *
78 * Certain hardware have instructions to insert this type of wait condition
79 * in the command stream, so no intervention from software would be needed.
80 * This type of fence can be destroyed before completed, however a reference
81 * on the sync_buf dma-buf can be taken. It is encouraged to re-use the same
82 * dma-buf for sync_buf, since mapping or unmapping the sync_buf to the
83 * device's vm can be expensive.
84 *
85 * It is recommended for creators of seqno_fence to call fence_signal
86 * before destruction. This will prevent possible issues from wraparound at
87 * time of issue vs time of check, since users can check fence_is_signaled
88 * before submitting instructions for the hardware to wait on the fence.
89 * However, when ops.enable_signaling is not called, it doesn't have to be
90 * done as soon as possible, just before there's any real danger of seqno
91 * wraparound.
92 */
93static inline void
94seqno_fence_init(struct seqno_fence *fence, spinlock_t *lock,
95 struct dma_buf *sync_buf, uint32_t context,
96 uint32_t seqno_ofs, uint32_t seqno,
97 enum seqno_fence_condition cond,
98 const struct fence_ops *ops)
99{
100 BUG_ON(!fence || !sync_buf || !ops);
101 BUG_ON(!ops->wait || !ops->enable_signaling ||
102 !ops->get_driver_name || !ops->get_timeline_name);
103
104 /*
105 * ops is used in fence_init for get_driver_name, so needs to be
106 * initialized first
107 */
108 fence->ops = ops;
109 fence_init(&fence->base, &seqno_fence_ops, lock, context, seqno);
110 get_dma_buf(sync_buf);
111 fence->sync_buf = sync_buf;
112 fence->seqno_ofs = seqno_ofs;
113 fence->condition = cond;
114}
115
116#endif /* __LINUX_SEQNO_FENCE_H */