staging/android: make sync_timeline internal to sw_sync
The only use sync_timeline will have in upstream kernel is for debugging through the SW_SYNC interface. So make it internal to SW_SYNC to avoid people use it in the future. Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Sumit Semwal <sumit.semwal@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
		
							parent
							
								
									d79892ad0b
								
							
						
					
					
						commit
						aff9da10e2
					
				| @ -24,26 +24,18 @@ config ANDROID_LOW_MEMORY_KILLER | ||||
| 	  scripts (/init.rc), and it defines priority values with minimum free memory size | ||||
| 	  for each priority. | ||||
| 
 | ||||
| config SYNC | ||||
| 	bool "Synchronization framework" | ||||
| 	default n | ||||
| 	select ANON_INODES | ||||
| 	select DMA_SHARED_BUFFER | ||||
| 	---help--- | ||||
| 	  This option enables the framework for synchronization between multiple | ||||
| 	  drivers.  Sync implementations can take advantage of hardware | ||||
| 	  synchronization built into devices like GPUs. | ||||
| 
 | ||||
| config SW_SYNC | ||||
| 	bool "Software synchronization objects" | ||||
| 	bool "Software synchronization framework" | ||||
| 	default n | ||||
| 	depends on SYNC | ||||
| 	depends on SYNC_FILE | ||||
| 	---help--- | ||||
| 	  A sync object driver that uses a 32bit counter to coordinate | ||||
| 	  synchronization.  Useful when there is no hardware primitive backing | ||||
| 	  the synchronization. | ||||
| 
 | ||||
| 	  WARNING: improper use of this can result in deadlocking kernel | ||||
| 	  drivers from userspace. Intended for test and debug only. | ||||
| 
 | ||||
| source "drivers/staging/android/ion/Kconfig" | ||||
| 
 | ||||
| endif # if ANDROID | ||||
|  | ||||
| @ -4,5 +4,4 @@ obj-y					+= ion/ | ||||
| 
 | ||||
| obj-$(CONFIG_ASHMEM)			+= ashmem.o | ||||
| obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER)	+= lowmemorykiller.o | ||||
| obj-$(CONFIG_SYNC)			+= sync.o sync_debug.o | ||||
| obj-$(CONFIG_SW_SYNC)			+= sw_sync.o | ||||
| obj-$(CONFIG_SW_SYNC)			+= sw_sync.o sync_debug.o | ||||
|  | ||||
| @ -17,11 +17,231 @@ | ||||
| #include <linux/file.h> | ||||
| #include <linux/fs.h> | ||||
| #include <linux/uaccess.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/sync_file.h> | ||||
| 
 | ||||
| #include "uapi/sw_sync.h" | ||||
| #include "sync.h" | ||||
| 
 | ||||
| #define CREATE_TRACE_POINTS | ||||
| #include "trace/sync.h" | ||||
| 
 | ||||
| static const struct fence_ops timeline_fence_ops; | ||||
| 
 | ||||
| static inline struct sync_pt *fence_to_sync_pt(struct fence *fence) | ||||
| { | ||||
| 	if (fence->ops != &timeline_fence_ops) | ||||
| 		return NULL; | ||||
| 	return container_of(fence, struct sync_pt, base); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * sync_timeline_create() - creates a sync object | ||||
|  * @drv_name:	sync_timeline driver name | ||||
|  * @name:	sync_timeline name | ||||
|  * | ||||
|  * Creates a new sync_timeline. Returns the sync_timeline object or NULL in | ||||
|  * case of error. | ||||
|  */ | ||||
| struct sync_timeline *sync_timeline_create(const char *drv_name, | ||||
| 					   const char *name) | ||||
| { | ||||
| 	struct sync_timeline *obj; | ||||
| 
 | ||||
| 	obj = kzalloc(sizeof(*obj), GFP_KERNEL); | ||||
| 	if (!obj) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	kref_init(&obj->kref); | ||||
| 	obj->context = fence_context_alloc(1); | ||||
| 	strlcpy(obj->name, name, sizeof(obj->name)); | ||||
| 	strlcpy(obj->drv_name, drv_name, sizeof(obj->drv_name)); | ||||
| 
 | ||||
| 	INIT_LIST_HEAD(&obj->child_list_head); | ||||
| 	INIT_LIST_HEAD(&obj->active_list_head); | ||||
| 	spin_lock_init(&obj->child_list_lock); | ||||
| 
 | ||||
| 	sync_timeline_debug_add(obj); | ||||
| 
 | ||||
| 	return obj; | ||||
| } | ||||
| 
 | ||||
| static void sync_timeline_free(struct kref *kref) | ||||
| { | ||||
| 	struct sync_timeline *obj = | ||||
| 		container_of(kref, struct sync_timeline, kref); | ||||
| 
 | ||||
| 	sync_timeline_debug_remove(obj); | ||||
| 
 | ||||
| 	kfree(obj); | ||||
| } | ||||
| 
 | ||||
| static void sync_timeline_get(struct sync_timeline *obj) | ||||
| { | ||||
| 	kref_get(&obj->kref); | ||||
| } | ||||
| 
 | ||||
| static void sync_timeline_put(struct sync_timeline *obj) | ||||
| { | ||||
| 	kref_put(&obj->kref, sync_timeline_free); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * sync_timeline_destroy() - destroys a sync object | ||||
|  * @obj:	sync_timeline to destroy | ||||
|  * | ||||
|  * A sync implementation should call this when the @obj is going away | ||||
|  * (i.e. module unload.)  @obj won't actually be freed until all its children | ||||
|  * fences are freed. | ||||
|  */ | ||||
| static void sync_timeline_destroy(struct sync_timeline *obj) | ||||
| { | ||||
| 	obj->destroyed = true; | ||||
| 	/*
 | ||||
| 	 * Ensure timeline is marked as destroyed before | ||||
| 	 * changing timeline's fences status. | ||||
| 	 */ | ||||
| 	smp_wmb(); | ||||
| 
 | ||||
| 	sync_timeline_put(obj); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * sync_timeline_signal() - signal a status change on a sync_timeline | ||||
|  * @obj:	sync_timeline to signal | ||||
|  * @inc:	num to increment on timeline->value | ||||
|  * | ||||
|  * A sync implementation should call this any time one of it's fences | ||||
|  * has signaled or has an error condition. | ||||
|  */ | ||||
| static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	struct sync_pt *pt, *next; | ||||
| 
 | ||||
| 	trace_sync_timeline(obj); | ||||
| 
 | ||||
| 	spin_lock_irqsave(&obj->child_list_lock, flags); | ||||
| 
 | ||||
| 	obj->value += inc; | ||||
| 
 | ||||
| 	list_for_each_entry_safe(pt, next, &obj->active_list_head, | ||||
| 				 active_list) { | ||||
| 		if (fence_is_signaled_locked(&pt->base)) | ||||
| 			list_del_init(&pt->active_list); | ||||
| 	} | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&obj->child_list_lock, flags); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * sync_pt_create() - creates a sync pt | ||||
|  * @parent:	fence's parent sync_timeline | ||||
|  * @size:	size to allocate for this pt | ||||
|  * @inc:	value of the fence | ||||
|  * | ||||
|  * Creates a new sync_pt as a child of @parent.  @size bytes will be | ||||
|  * allocated allowing for implementation specific data to be kept after | ||||
|  * the generic sync_timeline struct. Returns the sync_pt object or | ||||
|  * NULL in case of error. | ||||
|  */ | ||||
| static struct sync_pt *sync_pt_create(struct sync_timeline *obj, int size, | ||||
| 			     unsigned int value) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	struct sync_pt *pt; | ||||
| 
 | ||||
| 	if (size < sizeof(*pt)) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	pt = kzalloc(size, GFP_KERNEL); | ||||
| 	if (!pt) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&obj->child_list_lock, flags); | ||||
| 	sync_timeline_get(obj); | ||||
| 	fence_init(&pt->base, &timeline_fence_ops, &obj->child_list_lock, | ||||
| 		   obj->context, value); | ||||
| 	list_add_tail(&pt->child_list, &obj->child_list_head); | ||||
| 	INIT_LIST_HEAD(&pt->active_list); | ||||
| 	spin_unlock_irqrestore(&obj->child_list_lock, flags); | ||||
| 	return pt; | ||||
| } | ||||
| 
 | ||||
| static const char *timeline_fence_get_driver_name(struct fence *fence) | ||||
| { | ||||
| 	struct sync_timeline *parent = fence_parent(fence); | ||||
| 
 | ||||
| 	return parent->drv_name; | ||||
| } | ||||
| 
 | ||||
| static const char *timeline_fence_get_timeline_name(struct fence *fence) | ||||
| { | ||||
| 	struct sync_timeline *parent = fence_parent(fence); | ||||
| 
 | ||||
| 	return parent->name; | ||||
| } | ||||
| 
 | ||||
| static void timeline_fence_release(struct fence *fence) | ||||
| { | ||||
| 	struct sync_pt *pt = fence_to_sync_pt(fence); | ||||
| 	struct sync_timeline *parent = fence_parent(fence); | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	spin_lock_irqsave(fence->lock, flags); | ||||
| 	list_del(&pt->child_list); | ||||
| 	if (WARN_ON_ONCE(!list_empty(&pt->active_list))) | ||||
| 		list_del(&pt->active_list); | ||||
| 	spin_unlock_irqrestore(fence->lock, flags); | ||||
| 
 | ||||
| 	sync_timeline_put(parent); | ||||
| 	fence_free(fence); | ||||
| } | ||||
| 
 | ||||
| static bool timeline_fence_signaled(struct fence *fence) | ||||
| { | ||||
| 	struct sync_timeline *parent = fence_parent(fence); | ||||
| 
 | ||||
| 	return (fence->seqno > parent->value) ? false : true; | ||||
| } | ||||
| 
 | ||||
| static bool timeline_fence_enable_signaling(struct fence *fence) | ||||
| { | ||||
| 	struct sync_pt *pt = fence_to_sync_pt(fence); | ||||
| 	struct sync_timeline *parent = fence_parent(fence); | ||||
| 
 | ||||
| 	if (timeline_fence_signaled(fence)) | ||||
| 		return false; | ||||
| 
 | ||||
| 	list_add_tail(&pt->active_list, &parent->active_list_head); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static void timeline_fence_value_str(struct fence *fence, | ||||
| 				    char *str, int size) | ||||
| { | ||||
| 	snprintf(str, size, "%d", fence->seqno); | ||||
| } | ||||
| 
 | ||||
| static void timeline_fence_timeline_value_str(struct fence *fence, | ||||
| 					     char *str, int size) | ||||
| { | ||||
| 	struct sync_timeline *parent = fence_parent(fence); | ||||
| 
 | ||||
| 	snprintf(str, size, "%d", parent->value); | ||||
| } | ||||
| 
 | ||||
| static const struct fence_ops timeline_fence_ops = { | ||||
| 	.get_driver_name = timeline_fence_get_driver_name, | ||||
| 	.get_timeline_name = timeline_fence_get_timeline_name, | ||||
| 	.enable_signaling = timeline_fence_enable_signaling, | ||||
| 	.signaled = timeline_fence_signaled, | ||||
| 	.wait = fence_default_wait, | ||||
| 	.release = timeline_fence_release, | ||||
| 	.fence_value_str = timeline_fence_value_str, | ||||
| 	.timeline_value_str = timeline_fence_timeline_value_str, | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * *WARNING* | ||||
|  * | ||||
|  | ||||
| @ -1,199 +0,0 @@ | ||||
| /*
 | ||||
|  * drivers/base/sync.c | ||||
|  * | ||||
|  * Copyright (C) 2012 Google, Inc. | ||||
|  * | ||||
|  * This software is licensed under the terms of the GNU General Public | ||||
|  * License version 2, as published by the Free Software Foundation, and | ||||
|  * may be copied, distributed, and modified under those terms. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/export.h> | ||||
| #include <linux/slab.h> | ||||
| 
 | ||||
| #include "sync.h" | ||||
| 
 | ||||
| #define CREATE_TRACE_POINTS | ||||
| #include "trace/sync.h" | ||||
| 
 | ||||
| struct sync_timeline *sync_timeline_create(const char *drv_name, | ||||
| 					   const char *name) | ||||
| { | ||||
| 	struct sync_timeline *obj; | ||||
| 
 | ||||
| 	obj = kzalloc(sizeof(*obj), GFP_KERNEL); | ||||
| 	if (!obj) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	kref_init(&obj->kref); | ||||
| 	obj->context = fence_context_alloc(1); | ||||
| 	strlcpy(obj->name, name, sizeof(obj->name)); | ||||
| 	strlcpy(obj->drv_name, drv_name, sizeof(obj->drv_name)); | ||||
| 
 | ||||
| 	INIT_LIST_HEAD(&obj->child_list_head); | ||||
| 	INIT_LIST_HEAD(&obj->active_list_head); | ||||
| 	spin_lock_init(&obj->child_list_lock); | ||||
| 
 | ||||
| 	sync_timeline_debug_add(obj); | ||||
| 
 | ||||
| 	return obj; | ||||
| } | ||||
| EXPORT_SYMBOL(sync_timeline_create); | ||||
| 
 | ||||
| static void sync_timeline_free(struct kref *kref) | ||||
| { | ||||
| 	struct sync_timeline *obj = | ||||
| 		container_of(kref, struct sync_timeline, kref); | ||||
| 
 | ||||
| 	sync_timeline_debug_remove(obj); | ||||
| 
 | ||||
| 	kfree(obj); | ||||
| } | ||||
| 
 | ||||
| static void sync_timeline_get(struct sync_timeline *obj) | ||||
| { | ||||
| 	kref_get(&obj->kref); | ||||
| } | ||||
| 
 | ||||
| static void sync_timeline_put(struct sync_timeline *obj) | ||||
| { | ||||
| 	kref_put(&obj->kref, sync_timeline_free); | ||||
| } | ||||
| 
 | ||||
| void sync_timeline_destroy(struct sync_timeline *obj) | ||||
| { | ||||
| 	obj->destroyed = true; | ||||
| 	/*
 | ||||
| 	 * Ensure timeline is marked as destroyed before | ||||
| 	 * changing timeline's fences status. | ||||
| 	 */ | ||||
| 	smp_wmb(); | ||||
| 
 | ||||
| 	sync_timeline_put(obj); | ||||
| } | ||||
| EXPORT_SYMBOL(sync_timeline_destroy); | ||||
| 
 | ||||
| void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	struct sync_pt *pt, *next; | ||||
| 
 | ||||
| 	trace_sync_timeline(obj); | ||||
| 
 | ||||
| 	spin_lock_irqsave(&obj->child_list_lock, flags); | ||||
| 
 | ||||
| 	obj->value += inc; | ||||
| 
 | ||||
| 	list_for_each_entry_safe(pt, next, &obj->active_list_head, | ||||
| 				 active_list) { | ||||
| 		if (fence_is_signaled_locked(&pt->base)) | ||||
| 			list_del_init(&pt->active_list); | ||||
| 	} | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&obj->child_list_lock, flags); | ||||
| } | ||||
| EXPORT_SYMBOL(sync_timeline_signal); | ||||
| 
 | ||||
| struct sync_pt *sync_pt_create(struct sync_timeline *obj, int size, | ||||
| 			     unsigned int value) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	struct sync_pt *pt; | ||||
| 
 | ||||
| 	if (size < sizeof(*pt)) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	pt = kzalloc(size, GFP_KERNEL); | ||||
| 	if (!pt) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&obj->child_list_lock, flags); | ||||
| 	sync_timeline_get(obj); | ||||
| 	fence_init(&pt->base, &timeline_fence_ops, &obj->child_list_lock, | ||||
| 		   obj->context, value); | ||||
| 	list_add_tail(&pt->child_list, &obj->child_list_head); | ||||
| 	INIT_LIST_HEAD(&pt->active_list); | ||||
| 	spin_unlock_irqrestore(&obj->child_list_lock, flags); | ||||
| 	return pt; | ||||
| } | ||||
| EXPORT_SYMBOL(sync_pt_create); | ||||
| 
 | ||||
| static const char *timeline_fence_get_driver_name(struct fence *fence) | ||||
| { | ||||
| 	struct sync_timeline *parent = fence_parent(fence); | ||||
| 
 | ||||
| 	return parent->drv_name; | ||||
| } | ||||
| 
 | ||||
| static const char *timeline_fence_get_timeline_name(struct fence *fence) | ||||
| { | ||||
| 	struct sync_timeline *parent = fence_parent(fence); | ||||
| 
 | ||||
| 	return parent->name; | ||||
| } | ||||
| 
 | ||||
| static void timeline_fence_release(struct fence *fence) | ||||
| { | ||||
| 	struct sync_pt *pt = fence_to_sync_pt(fence); | ||||
| 	struct sync_timeline *parent = fence_parent(fence); | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	spin_lock_irqsave(fence->lock, flags); | ||||
| 	list_del(&pt->child_list); | ||||
| 	if (WARN_ON_ONCE(!list_empty(&pt->active_list))) | ||||
| 		list_del(&pt->active_list); | ||||
| 	spin_unlock_irqrestore(fence->lock, flags); | ||||
| 
 | ||||
| 	sync_timeline_put(parent); | ||||
| 	fence_free(fence); | ||||
| } | ||||
| 
 | ||||
| static bool timeline_fence_signaled(struct fence *fence) | ||||
| { | ||||
| 	struct sync_timeline *parent = fence_parent(fence); | ||||
| 
 | ||||
| 	return (fence->seqno > parent->value) ? false : true; | ||||
| } | ||||
| 
 | ||||
| static bool timeline_fence_enable_signaling(struct fence *fence) | ||||
| { | ||||
| 	struct sync_pt *pt = fence_to_sync_pt(fence); | ||||
| 	struct sync_timeline *parent = fence_parent(fence); | ||||
| 
 | ||||
| 	if (timeline_fence_signaled(fence)) | ||||
| 		return false; | ||||
| 
 | ||||
| 	list_add_tail(&pt->active_list, &parent->active_list_head); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static void timeline_fence_value_str(struct fence *fence, | ||||
| 				    char *str, int size) | ||||
| { | ||||
| 	snprintf(str, size, "%d", fence->seqno); | ||||
| } | ||||
| 
 | ||||
| static void timeline_fence_timeline_value_str(struct fence *fence, | ||||
| 					     char *str, int size) | ||||
| { | ||||
| 	struct sync_timeline *parent = fence_parent(fence); | ||||
| 
 | ||||
| 	snprintf(str, size, "%d", parent->value); | ||||
| } | ||||
| 
 | ||||
| const struct fence_ops timeline_fence_ops = { | ||||
| 	.get_driver_name = timeline_fence_get_driver_name, | ||||
| 	.get_timeline_name = timeline_fence_get_timeline_name, | ||||
| 	.enable_signaling = timeline_fence_enable_signaling, | ||||
| 	.signaled = timeline_fence_signaled, | ||||
| 	.wait = fence_default_wait, | ||||
| 	.release = timeline_fence_release, | ||||
| 	.fence_value_str = timeline_fence_value_str, | ||||
| 	.timeline_value_str = timeline_fence_timeline_value_str, | ||||
| }; | ||||
| @ -69,64 +69,6 @@ struct sync_pt { | ||||
| 	struct list_head active_list; | ||||
| }; | ||||
| 
 | ||||
| extern const struct fence_ops timeline_fence_ops; | ||||
| 
 | ||||
| static inline struct sync_pt *fence_to_sync_pt(struct fence *fence) | ||||
| { | ||||
| 	if (fence->ops != &timeline_fence_ops) | ||||
| 		return NULL; | ||||
| 	return container_of(fence, struct sync_pt, base); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * API for sync_timeline implementers | ||||
|  */ | ||||
| 
 | ||||
| /**
 | ||||
|  * sync_timeline_create() - creates a sync object | ||||
|  * @drv_name:	sync_timeline driver name | ||||
|  * @name:	sync_timeline name | ||||
|  * | ||||
|  * Creates a new sync_timeline. Returns the sync_timeline object or NULL in | ||||
|  * case of error. | ||||
|  */ | ||||
| struct sync_timeline *sync_timeline_create(const char *drv_name, | ||||
| 					   const char *name); | ||||
| 
 | ||||
| /**
 | ||||
|  * sync_timeline_destroy() - destroys a sync object | ||||
|  * @obj:	sync_timeline to destroy | ||||
|  * | ||||
|  * A sync implementation should call this when the @obj is going away | ||||
|  * (i.e. module unload.)  @obj won't actually be freed until all its children | ||||
|  * fences are freed. | ||||
|  */ | ||||
| void sync_timeline_destroy(struct sync_timeline *obj); | ||||
| 
 | ||||
| /**
 | ||||
|  * sync_timeline_signal() - signal a status change on a sync_timeline | ||||
|  * @obj:	sync_timeline to signal | ||||
|  * @inc:	num to increment on timeline->value | ||||
|  * | ||||
|  * A sync implementation should call this any time one of it's fences | ||||
|  * has signaled or has an error condition. | ||||
|  */ | ||||
| void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc); | ||||
| 
 | ||||
| /**
 | ||||
|  * sync_pt_create() - creates a sync pt | ||||
|  * @parent:	fence's parent sync_timeline | ||||
|  * @size:	size to allocate for this pt | ||||
|  * @inc:	value of the fence | ||||
|  * | ||||
|  * Creates a new sync_pt as a child of @parent.  @size bytes will be | ||||
|  * allocated allowing for implementation specific data to be kept after | ||||
|  * the generic sync_timeline struct. Returns the sync_pt object or | ||||
|  * NULL in case of error. | ||||
|  */ | ||||
| struct sync_pt *sync_pt_create(struct sync_timeline *parent, int size, | ||||
| 			       unsigned int inc); | ||||
| 
 | ||||
| #ifdef CONFIG_DEBUG_FS | ||||
| 
 | ||||
| extern const struct file_operations sw_sync_debugfs_fops; | ||||
|  | ||||
| @ -193,10 +193,8 @@ static __init int sync_debugfs_init(void) | ||||
| 
 | ||||
| 	debugfs_create_file("info", 0444, dbgfs, NULL, &sync_info_debugfs_fops); | ||||
| 
 | ||||
| #if IS_ENABLED(CONFIG_SW_SYNC) | ||||
| 	debugfs_create_file("sw_sync", 0644, dbgfs, NULL, | ||||
| 			    &sw_sync_debugfs_fops); | ||||
| #endif | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user