diff options
author | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2016-06-01 09:10:03 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2016-06-02 03:26:15 -0400 |
commit | b3dfbdf261e076a997f812323edfdba84ba80256 (patch) | |
tree | 06bf2fdb5d65c62aee083ae7867e45394def663e | |
parent | 76bf0db5543976ef50362db7071da367cb118532 (diff) |
dma-buf/fence: add fence_array fences v6
struct fence_array inherits from struct fence and carries a
collection of fences that needs to be waited together.
It is useful to translate a sync_file to a fence to remove the complexity
of dealing with sync_files on DRM drivers. So even if there are many
fences in the sync_file that needs to waited for a commit to happen,
they all get added to the fence_collection and passed for DRM use as
a standard struct fence.
That means that no changes needed to any driver besides supporting fences.
To avoid fence_array's fence allocates a new timeline if needed (when
combining fences from different timelines).
v2: Comments by Daniel Vetter:
- merge fence_collection_init() and fence_collection_add()
- only add callbacks at ->enable_signalling()
- remove fence_collection_put()
- check for type on to_fence_collection()
- adjust fence_is_later() and fence_later() to WARN_ON() if they
are used with collection fences.
v3: - Initialize fence_cb.node at fence init.
Comments by Chris Wilson:
- return "unbound" on fence_collection_get_timeline_name()
- don't stop adding callbacks if one fails
- remove redundant !! on fence_collection_enable_signaling()
- remove redundant () on fence_collection_signaled
- use fence_default_wait() instead
v4 (chk): Rework, simplification and cleanup:
- Drop FENCE_NO_CONTEXT handling, always allocate a context.
- Rename to fence_array.
- Return fixed driver name.
- Register only one callback at a time.
- Document that create function takes ownership of array.
v5 (chk): More work and fixes:
- Avoid deadlocks by adding all callbacks at once again.
- Stop trying to remove the callbacks.
- Provide context and sequence number for the array fence.
v6 (chk): Fixes found during testing
- Fix stupid typo in _enable_signaling().
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Acked-by: Sumit Semwal <sumit.semwal@linaro.org>
[danvet: Improve commit message as suggested by Gustavo.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1464786612-5010-3-git-send-email-deathsimple@vodafone.de
-rw-r--r-- | drivers/dma-buf/Makefile | 2 | ||||
-rw-r--r-- | drivers/dma-buf/fence-array.c | 127 | ||||
-rw-r--r-- | include/linux/fence-array.h | 72 |
3 files changed, 200 insertions, 1 deletions
diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index 4a424eca75ed..f353db213a81 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile | |||
@@ -1,2 +1,2 @@ | |||
1 | obj-y := dma-buf.o fence.o reservation.o seqno-fence.o | 1 | obj-y := dma-buf.o fence.o reservation.o seqno-fence.o fence-array.o |
2 | obj-$(CONFIG_SYNC_FILE) += sync_file.o | 2 | obj-$(CONFIG_SYNC_FILE) += sync_file.o |
diff --git a/drivers/dma-buf/fence-array.c b/drivers/dma-buf/fence-array.c new file mode 100644 index 000000000000..81412175a420 --- /dev/null +++ b/drivers/dma-buf/fence-array.c | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * fence-array: aggregate fences to be waited together | ||
3 | * | ||
4 | * Copyright (C) 2016 Collabora Ltd | ||
5 | * Copyright (C) 2016 Advanced Micro Devices, Inc. | ||
6 | * Authors: | ||
7 | * Gustavo Padovan <gustavo@padovan.org> | ||
8 | * Christian König <christian.koenig@amd.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/export.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/fence-array.h> | ||
23 | |||
24 | static void fence_array_cb_func(struct fence *f, struct fence_cb *cb); | ||
25 | |||
26 | static const char *fence_array_get_driver_name(struct fence *fence) | ||
27 | { | ||
28 | return "fence_array"; | ||
29 | } | ||
30 | |||
31 | static const char *fence_array_get_timeline_name(struct fence *fence) | ||
32 | { | ||
33 | return "unbound"; | ||
34 | } | ||
35 | |||
36 | static void fence_array_cb_func(struct fence *f, struct fence_cb *cb) | ||
37 | { | ||
38 | struct fence_array_cb *array_cb = | ||
39 | container_of(cb, struct fence_array_cb, cb); | ||
40 | struct fence_array *array = array_cb->array; | ||
41 | |||
42 | if (atomic_dec_and_test(&array->num_pending)) | ||
43 | fence_signal(&array->base); | ||
44 | } | ||
45 | |||
46 | static bool fence_array_enable_signaling(struct fence *fence) | ||
47 | { | ||
48 | struct fence_array *array = to_fence_array(fence); | ||
49 | struct fence_array_cb *cb = (void *)(&array[1]); | ||
50 | unsigned i; | ||
51 | |||
52 | for (i = 0; i < array->num_fences; ++i) { | ||
53 | cb[i].array = array; | ||
54 | if (fence_add_callback(array->fences[i], &cb[i].cb, | ||
55 | fence_array_cb_func)) | ||
56 | if (atomic_dec_and_test(&array->num_pending)) | ||
57 | return false; | ||
58 | } | ||
59 | |||
60 | return true; | ||
61 | } | ||
62 | |||
63 | static bool fence_array_signaled(struct fence *fence) | ||
64 | { | ||
65 | struct fence_array *array = to_fence_array(fence); | ||
66 | |||
67 | return atomic_read(&array->num_pending) == 0; | ||
68 | } | ||
69 | |||
70 | static void fence_array_release(struct fence *fence) | ||
71 | { | ||
72 | struct fence_array *array = to_fence_array(fence); | ||
73 | unsigned i; | ||
74 | |||
75 | for (i = 0; i < array->num_fences; ++i) | ||
76 | fence_put(array->fences[i]); | ||
77 | |||
78 | kfree(array->fences); | ||
79 | fence_free(fence); | ||
80 | } | ||
81 | |||
82 | const struct fence_ops fence_array_ops = { | ||
83 | .get_driver_name = fence_array_get_driver_name, | ||
84 | .get_timeline_name = fence_array_get_timeline_name, | ||
85 | .enable_signaling = fence_array_enable_signaling, | ||
86 | .signaled = fence_array_signaled, | ||
87 | .wait = fence_default_wait, | ||
88 | .release = fence_array_release, | ||
89 | }; | ||
90 | |||
91 | /** | ||
92 | * fence_array_create - Create a custom fence array | ||
93 | * @num_fences: [in] number of fences to add in the array | ||
94 | * @fences: [in] array containing the fences | ||
95 | * @context: [in] fence context to use | ||
96 | * @seqno: [in] sequence number to use | ||
97 | * | ||
98 | * Allocate a fence_array object and initialize the base fence with fence_init(). | ||
99 | * In case of error it returns NULL. | ||
100 | * | ||
101 | * The caller should allocte the fences array with num_fences size | ||
102 | * and fill it with the fences it wants to add to the object. Ownership of this | ||
103 | * array is take and fence_put() is used on each fence on release. | ||
104 | */ | ||
105 | struct fence_array *fence_array_create(int num_fences, struct fence **fences, | ||
106 | u64 context, unsigned seqno) | ||
107 | { | ||
108 | struct fence_array *array; | ||
109 | size_t size = sizeof(*array); | ||
110 | |||
111 | /* Allocate the callback structures behind the array. */ | ||
112 | size += num_fences * sizeof(struct fence_array_cb); | ||
113 | array = kzalloc(size, GFP_KERNEL); | ||
114 | if (!array) | ||
115 | return NULL; | ||
116 | |||
117 | spin_lock_init(&array->lock); | ||
118 | fence_init(&array->base, &fence_array_ops, &array->lock, | ||
119 | context, seqno); | ||
120 | |||
121 | array->num_fences = num_fences; | ||
122 | atomic_set(&array->num_pending, num_fences); | ||
123 | array->fences = fences; | ||
124 | |||
125 | return array; | ||
126 | } | ||
127 | EXPORT_SYMBOL(fence_array_create); | ||
diff --git a/include/linux/fence-array.h b/include/linux/fence-array.h new file mode 100644 index 000000000000..593ab983129e --- /dev/null +++ b/include/linux/fence-array.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * fence-array: aggregates fence to be waited together | ||
3 | * | ||
4 | * Copyright (C) 2016 Collabora Ltd | ||
5 | * Copyright (C) 2016 Advanced Micro Devices, Inc. | ||
6 | * Authors: | ||
7 | * Gustavo Padovan <gustavo@padovan.org> | ||
8 | * Christian König <christian.koenig@amd.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_FENCE_ARRAY_H | ||
21 | #define __LINUX_FENCE_ARRAY_H | ||
22 | |||
23 | #include <linux/fence.h> | ||
24 | |||
25 | /** | ||
26 | * struct fence_array_cb - callback helper for fence array | ||
27 | * @cb: fence callback structure for signaling | ||
28 | * @array: reference to the parent fence array object | ||
29 | */ | ||
30 | struct fence_array_cb { | ||
31 | struct fence_cb cb; | ||
32 | struct fence_array *array; | ||
33 | }; | ||
34 | |||
35 | /** | ||
36 | * struct fence_array - fence to represent an array of fences | ||
37 | * @base: fence base class | ||
38 | * @lock: spinlock for fence handling | ||
39 | * @num_fences: number of fences in the array | ||
40 | * @num_pending: fences in the array still pending | ||
41 | * @fences: array of the fences | ||
42 | */ | ||
43 | struct fence_array { | ||
44 | struct fence base; | ||
45 | |||
46 | spinlock_t lock; | ||
47 | unsigned num_fences; | ||
48 | atomic_t num_pending; | ||
49 | struct fence **fences; | ||
50 | }; | ||
51 | |||
52 | extern const struct fence_ops fence_array_ops; | ||
53 | |||
54 | /** | ||
55 | * to_fence_array - cast a fence to a fence_array | ||
56 | * @fence: fence to cast to a fence_array | ||
57 | * | ||
58 | * Returns NULL if the fence is not a fence_array, | ||
59 | * or the fence_array otherwise. | ||
60 | */ | ||
61 | static inline struct fence_array *to_fence_array(struct fence *fence) | ||
62 | { | ||
63 | if (fence->ops != &fence_array_ops) | ||
64 | return NULL; | ||
65 | |||
66 | return container_of(fence, struct fence_array, base); | ||
67 | } | ||
68 | |||
69 | struct fence_array *fence_array_create(int num_fences, struct fence **fences, | ||
70 | u64 context, unsigned seqno); | ||
71 | |||
72 | #endif /* __LINUX_FENCE_ARRAY_H */ | ||