at v4.7 5.3 kB view raw
1/* 2 * drivers/base/sync.c 3 * 4 * Copyright (C) 2012 Google, Inc. 5 * 6 * This software is licensed under the terms of the GNU General Public 7 * License version 2, as published by the Free Software Foundation, and 8 * may be copied, distributed, and modified under those terms. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 */ 16 17#include <linux/debugfs.h> 18#include <linux/export.h> 19#include <linux/kernel.h> 20#include <linux/sched.h> 21#include <linux/seq_file.h> 22#include <linux/slab.h> 23#include <linux/uaccess.h> 24#include <linux/anon_inodes.h> 25 26#include "sync.h" 27 28#define CREATE_TRACE_POINTS 29#include "trace/sync.h" 30 31static const struct fence_ops android_fence_ops; 32 33struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops, 34 int size, const char *name) 35{ 36 struct sync_timeline *obj; 37 38 if (size < sizeof(struct sync_timeline)) 39 return NULL; 40 41 obj = kzalloc(size, GFP_KERNEL); 42 if (!obj) 43 return NULL; 44 45 kref_init(&obj->kref); 46 obj->ops = ops; 47 obj->context = fence_context_alloc(1); 48 strlcpy(obj->name, name, sizeof(obj->name)); 49 50 INIT_LIST_HEAD(&obj->child_list_head); 51 INIT_LIST_HEAD(&obj->active_list_head); 52 spin_lock_init(&obj->child_list_lock); 53 54 sync_timeline_debug_add(obj); 55 56 return obj; 57} 58EXPORT_SYMBOL(sync_timeline_create); 59 60static void sync_timeline_free(struct kref *kref) 61{ 62 struct sync_timeline *obj = 63 container_of(kref, struct sync_timeline, kref); 64 65 sync_timeline_debug_remove(obj); 66 67 kfree(obj); 68} 69 70static void sync_timeline_get(struct sync_timeline *obj) 71{ 72 kref_get(&obj->kref); 73} 74 75static void sync_timeline_put(struct sync_timeline *obj) 76{ 77 kref_put(&obj->kref, sync_timeline_free); 78} 79 80void sync_timeline_destroy(struct sync_timeline *obj) 81{ 82 obj->destroyed = true; 83 /* 84 * Ensure timeline is marked as destroyed before 85 * changing timeline's fences status. 86 */ 87 smp_wmb(); 88 89 sync_timeline_put(obj); 90} 91EXPORT_SYMBOL(sync_timeline_destroy); 92 93void sync_timeline_signal(struct sync_timeline *obj) 94{ 95 unsigned long flags; 96 struct fence *fence, *next; 97 98 trace_sync_timeline(obj); 99 100 spin_lock_irqsave(&obj->child_list_lock, flags); 101 102 list_for_each_entry_safe(fence, next, &obj->active_list_head, 103 active_list) { 104 if (fence_is_signaled_locked(fence)) 105 list_del_init(&fence->active_list); 106 } 107 108 spin_unlock_irqrestore(&obj->child_list_lock, flags); 109} 110EXPORT_SYMBOL(sync_timeline_signal); 111 112struct fence *sync_pt_create(struct sync_timeline *obj, int size) 113{ 114 unsigned long flags; 115 struct fence *fence; 116 117 if (size < sizeof(*fence)) 118 return NULL; 119 120 fence = kzalloc(size, GFP_KERNEL); 121 if (!fence) 122 return NULL; 123 124 spin_lock_irqsave(&obj->child_list_lock, flags); 125 sync_timeline_get(obj); 126 fence_init(fence, &android_fence_ops, &obj->child_list_lock, 127 obj->context, ++obj->value); 128 list_add_tail(&fence->child_list, &obj->child_list_head); 129 INIT_LIST_HEAD(&fence->active_list); 130 spin_unlock_irqrestore(&obj->child_list_lock, flags); 131 return fence; 132} 133EXPORT_SYMBOL(sync_pt_create); 134 135static const char *android_fence_get_driver_name(struct fence *fence) 136{ 137 struct sync_timeline *parent = fence_parent(fence); 138 139 return parent->ops->driver_name; 140} 141 142static const char *android_fence_get_timeline_name(struct fence *fence) 143{ 144 struct sync_timeline *parent = fence_parent(fence); 145 146 return parent->name; 147} 148 149static void android_fence_release(struct fence *fence) 150{ 151 struct sync_timeline *parent = fence_parent(fence); 152 unsigned long flags; 153 154 spin_lock_irqsave(fence->lock, flags); 155 list_del(&fence->child_list); 156 if (WARN_ON_ONCE(!list_empty(&fence->active_list))) 157 list_del(&fence->active_list); 158 spin_unlock_irqrestore(fence->lock, flags); 159 160 sync_timeline_put(parent); 161 fence_free(fence); 162} 163 164static bool android_fence_signaled(struct fence *fence) 165{ 166 struct sync_timeline *parent = fence_parent(fence); 167 int ret; 168 169 ret = parent->ops->has_signaled(fence); 170 if (ret < 0) 171 fence->status = ret; 172 return ret; 173} 174 175static bool android_fence_enable_signaling(struct fence *fence) 176{ 177 struct sync_timeline *parent = fence_parent(fence); 178 179 if (android_fence_signaled(fence)) 180 return false; 181 182 list_add_tail(&fence->active_list, &parent->active_list_head); 183 return true; 184} 185 186static void android_fence_value_str(struct fence *fence, 187 char *str, int size) 188{ 189 struct sync_timeline *parent = fence_parent(fence); 190 191 if (!parent->ops->fence_value_str) { 192 if (size) 193 *str = 0; 194 return; 195 } 196 parent->ops->fence_value_str(fence, str, size); 197} 198 199static void android_fence_timeline_value_str(struct fence *fence, 200 char *str, int size) 201{ 202 struct sync_timeline *parent = fence_parent(fence); 203 204 if (!parent->ops->timeline_value_str) { 205 if (size) 206 *str = 0; 207 return; 208 } 209 parent->ops->timeline_value_str(parent, str, size); 210} 211 212static const struct fence_ops android_fence_ops = { 213 .get_driver_name = android_fence_get_driver_name, 214 .get_timeline_name = android_fence_get_timeline_name, 215 .enable_signaling = android_fence_enable_signaling, 216 .signaled = android_fence_signaled, 217 .wait = fence_default_wait, 218 .release = android_fence_release, 219 .fence_value_str = android_fence_value_str, 220 .timeline_value_str = android_fence_timeline_value_str, 221};