sync: oneshot_sync: Add oneshot_sync driver
Add the oneshot_sync driver as of msm-3.18 commit 7892968f (sync: oneshot_sync: Update oneshot_sync for new sync APIs). Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
This commit is contained in:
parent
39d07c3f5e
commit
881d8ec58a
8 changed files with 561 additions and 1 deletions
|
@ -432,7 +432,7 @@ int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_waiter *kwaiter)
|
|||
|
||||
#ifdef CONFIG_ONESHOT_SYNC
|
||||
|
||||
#include <linux/oneshot_sync.h>
|
||||
#include "oneshot_sync.h"
|
||||
|
||||
struct kgsl_syncsource {
|
||||
struct kref refcount;
|
||||
|
|
|
@ -75,6 +75,21 @@ config SW_SYNC_USER
|
|||
*WARNING* improper use of this can result in deadlocking kernel
|
||||
drivers from userspace.
|
||||
|
||||
config ONESHOT_SYNC
|
||||
bool "One shot sync objects"
|
||||
depends on SYNC
|
||||
help
|
||||
This sync driver provides a way to create sync objects that may
|
||||
be signaled by userspace. Unlike other sync objects, the
|
||||
sync objects created by this driver may be signaled in any order
|
||||
without changing the state of other sync objects on the timeline.
|
||||
|
||||
config ONESHOT_SYNC_USER
|
||||
bool "Userspace API for ONESHOT_SYNC"
|
||||
depends on SYNC
|
||||
help
|
||||
Provide a userspace API for creating oneshot sync objects.
|
||||
|
||||
source "drivers/staging/android/ion/Kconfig"
|
||||
|
||||
source "drivers/staging/android/fiq_debugger/Kconfig"
|
||||
|
|
|
@ -9,3 +9,4 @@ obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.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_ONESHOT_SYNC) += oneshot_sync.o
|
||||
|
|
435
drivers/staging/android/oneshot_sync.c
Normal file
435
drivers/staging/android/oneshot_sync.c
Normal file
|
@ -0,0 +1,435 @@
|
|||
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "sync.h"
|
||||
#include "oneshot_sync.h"
|
||||
|
||||
/**
|
||||
* struct oneshot_sync_timeline - a userspace signaled, out of order, timeline
|
||||
* @obj: base sync timeline
|
||||
* @lock: spinlock to guard other members
|
||||
* @state_list: list of oneshot_sync_states.
|
||||
* @id: next id for points creating oneshot_sync_pts
|
||||
*/
|
||||
struct oneshot_sync_timeline {
|
||||
struct sync_timeline obj;
|
||||
spinlock_t lock;
|
||||
struct list_head state_list;
|
||||
unsigned int id;
|
||||
};
|
||||
|
||||
#define to_oneshot_timeline(_p) \
|
||||
container_of((_p), struct oneshot_sync_timeline, obj)
|
||||
|
||||
/**
|
||||
* struct oneshot_sync_state - signal state for a group of oneshot points
|
||||
* @refcount: reference count for this structure.
|
||||
* @signaled: is this signaled or not?
|
||||
* @id: identifier for this state
|
||||
* @orig_fence: fence used to create this state, no is reference count held.
|
||||
* @timeline: back pointer to the timeline.
|
||||
*/
|
||||
struct oneshot_sync_state {
|
||||
struct kref refcount;
|
||||
struct list_head node;
|
||||
bool signaled;
|
||||
unsigned int id;
|
||||
struct sync_fence *orig_fence;
|
||||
struct oneshot_sync_timeline *timeline;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct oneshot_sync_pt
|
||||
* @sync_pt: base sync point structure
|
||||
* @state: reference counted pointer to the state of this pt
|
||||
*/
|
||||
struct oneshot_sync_pt {
|
||||
struct sync_pt sync_pt;
|
||||
struct oneshot_sync_state *state;
|
||||
bool dup;
|
||||
};
|
||||
#define to_oneshot_pt(_p) container_of((_p), struct oneshot_sync_pt, sync_pt)
|
||||
|
||||
static void oneshot_state_destroy(struct kref *ref)
|
||||
{
|
||||
struct oneshot_sync_state *state =
|
||||
container_of(ref, struct oneshot_sync_state, refcount);
|
||||
|
||||
spin_lock(&state->timeline->lock);
|
||||
list_del(&state->node);
|
||||
spin_unlock(&state->timeline->lock);
|
||||
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static void oneshot_state_put(struct oneshot_sync_state *state)
|
||||
{
|
||||
kref_put(&state->refcount, oneshot_state_destroy);
|
||||
}
|
||||
|
||||
static struct oneshot_sync_pt *
|
||||
oneshot_pt_create(struct oneshot_sync_timeline *timeline)
|
||||
{
|
||||
struct oneshot_sync_pt *pt = NULL;
|
||||
|
||||
pt = (struct oneshot_sync_pt *)sync_pt_create(&timeline->obj,
|
||||
sizeof(*pt));
|
||||
if (pt == NULL)
|
||||
return NULL;
|
||||
|
||||
pt->state = kzalloc(sizeof(struct oneshot_sync_state), GFP_KERNEL);
|
||||
if (pt->state == NULL)
|
||||
goto error;
|
||||
|
||||
kref_init(&pt->state->refcount);
|
||||
pt->state->signaled = false;
|
||||
pt->state->timeline = timeline;
|
||||
|
||||
spin_lock(&timeline->lock);
|
||||
/* assign an id to the state, which could be shared by several pts. */
|
||||
pt->state->id = ++(timeline->id);
|
||||
/* add this pt to the list of pts that can be signaled by userspace */
|
||||
list_add_tail(&pt->state->node, &timeline->state_list);
|
||||
spin_unlock(&timeline->lock);
|
||||
|
||||
return pt;
|
||||
error:
|
||||
if (pt)
|
||||
sync_pt_free(&pt->sync_pt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct sync_pt *oneshot_pt_dup(struct sync_pt *sync_pt)
|
||||
{
|
||||
struct oneshot_sync_pt *out_pt;
|
||||
struct oneshot_sync_pt *pt = to_oneshot_pt(sync_pt);
|
||||
|
||||
if (!kref_get_unless_zero(&pt->state->refcount))
|
||||
return NULL;
|
||||
|
||||
out_pt = (struct oneshot_sync_pt *)
|
||||
sync_pt_create(sync_pt_parent(sync_pt), sizeof(*out_pt));
|
||||
|
||||
if (out_pt == NULL) {
|
||||
oneshot_state_put(pt->state);
|
||||
return NULL;
|
||||
}
|
||||
out_pt->state = pt->state;
|
||||
out_pt->dup = true;
|
||||
|
||||
return &out_pt->sync_pt;
|
||||
}
|
||||
|
||||
static int oneshot_pt_has_signaled(struct sync_pt *sync_pt)
|
||||
{
|
||||
struct oneshot_sync_pt *pt = to_oneshot_pt(sync_pt);
|
||||
|
||||
return pt->state->signaled;
|
||||
}
|
||||
|
||||
static int oneshot_pt_compare(struct sync_pt *a, struct sync_pt *b)
|
||||
{
|
||||
struct oneshot_sync_pt *pt_a = to_oneshot_pt(a);
|
||||
struct oneshot_sync_pt *pt_b = to_oneshot_pt(b);
|
||||
/*
|
||||
* since oneshot sync points are order-independent,
|
||||
* return an arbitrary order which just happens to
|
||||
* prevent sync.c from collapsing the points.
|
||||
*/
|
||||
return (pt_a->state == pt_b->state) ? 0 : 1;
|
||||
}
|
||||
|
||||
static void oneshot_pt_free(struct sync_pt *sync_pt)
|
||||
{
|
||||
struct oneshot_sync_pt *pt = to_oneshot_pt(sync_pt);
|
||||
struct sync_timeline *parent = sync_pt_parent(sync_pt);
|
||||
struct oneshot_sync_timeline *timeline = parent != NULL?
|
||||
to_oneshot_timeline(parent) : NULL;
|
||||
|
||||
if (timeline != NULL) {
|
||||
spin_lock(&timeline->lock);
|
||||
/*
|
||||
* If this is the original pt (and fence), signal to avoid
|
||||
* deadlock. Unfornately, we can't signal the timeline here
|
||||
* safely, so there could be a delay until the pt's
|
||||
* state change is noticed.
|
||||
*/
|
||||
|
||||
if (pt->dup == false) {
|
||||
/*
|
||||
* If the original pt goes away, force it signaled to
|
||||
* avoid deadlock.
|
||||
*/
|
||||
if (!pt->state->signaled) {
|
||||
pr_debug("id %d: fence closed before signal.\n",
|
||||
pt->state->id);
|
||||
pt->state->signaled = true;
|
||||
}
|
||||
}
|
||||
spin_unlock(&timeline->lock);
|
||||
}
|
||||
oneshot_state_put(pt->state);
|
||||
}
|
||||
|
||||
static void oneshot_pt_value_str(struct sync_pt *sync_pt, char *str, int size)
|
||||
{
|
||||
struct oneshot_sync_pt *pt = to_oneshot_pt(sync_pt);
|
||||
|
||||
snprintf(str, size, "%u", pt->state->id);
|
||||
}
|
||||
|
||||
static struct sync_timeline_ops oneshot_timeline_ops = {
|
||||
.driver_name = "oneshot",
|
||||
.dup = oneshot_pt_dup,
|
||||
.has_signaled = oneshot_pt_has_signaled,
|
||||
.compare = oneshot_pt_compare,
|
||||
.free_pt = oneshot_pt_free,
|
||||
.pt_value_str = oneshot_pt_value_str,
|
||||
};
|
||||
|
||||
struct oneshot_sync_timeline *oneshot_timeline_create(const char *name)
|
||||
{
|
||||
struct oneshot_sync_timeline *timeline = NULL;
|
||||
static const char *default_name = "oneshot-timeline";
|
||||
|
||||
if (name == NULL)
|
||||
name = default_name;
|
||||
|
||||
timeline = (struct oneshot_sync_timeline *)
|
||||
sync_timeline_create(&oneshot_timeline_ops,
|
||||
sizeof(*timeline),
|
||||
name);
|
||||
|
||||
if (timeline == NULL)
|
||||
return NULL;
|
||||
|
||||
INIT_LIST_HEAD(&timeline->state_list);
|
||||
spin_lock_init(&timeline->lock);
|
||||
|
||||
return timeline;
|
||||
}
|
||||
EXPORT_SYMBOL(oneshot_timeline_create);
|
||||
|
||||
void oneshot_timeline_destroy(struct oneshot_sync_timeline *timeline)
|
||||
{
|
||||
if (timeline)
|
||||
sync_timeline_destroy(&timeline->obj);
|
||||
}
|
||||
EXPORT_SYMBOL(oneshot_timeline_destroy);
|
||||
|
||||
struct sync_fence *oneshot_fence_create(struct oneshot_sync_timeline *timeline,
|
||||
const char *name)
|
||||
{
|
||||
struct sync_fence *fence = NULL;
|
||||
struct oneshot_sync_pt *pt = NULL;
|
||||
|
||||
pt = oneshot_pt_create(timeline);
|
||||
if (pt == NULL)
|
||||
return NULL;
|
||||
|
||||
fence = sync_fence_create(name, &pt->sync_pt);
|
||||
if (fence == NULL) {
|
||||
sync_pt_free(&pt->sync_pt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pt->state->orig_fence = fence;
|
||||
|
||||
return fence;
|
||||
}
|
||||
EXPORT_SYMBOL(oneshot_fence_create);
|
||||
|
||||
int oneshot_fence_signal(struct oneshot_sync_timeline *timeline,
|
||||
struct sync_fence *fence)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct oneshot_sync_state *state = NULL;
|
||||
bool signaled = false;
|
||||
|
||||
if (timeline == NULL || fence == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&timeline->lock);
|
||||
list_for_each_entry(state, &timeline->state_list, node) {
|
||||
/*
|
||||
* If we have the point from this fence on our list,
|
||||
* this is is the original fence we created, so signal it.
|
||||
*/
|
||||
if (state->orig_fence == fence) {
|
||||
/* ignore attempts to signal multiple times */
|
||||
if (!state->signaled) {
|
||||
state->signaled = true;
|
||||
signaled = true;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&timeline->lock);
|
||||
if (ret == -EINVAL)
|
||||
pr_debug("fence: %p not from this timeline\n", fence);
|
||||
|
||||
if (signaled)
|
||||
sync_timeline_signal(&timeline->obj);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(oneshot_fence_signal);
|
||||
|
||||
#ifdef CONFIG_ONESHOT_SYNC_USER
|
||||
|
||||
static int oneshot_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct oneshot_sync_timeline *timeline = NULL;
|
||||
char name[32];
|
||||
char task_comm[TASK_COMM_LEN];
|
||||
|
||||
get_task_comm(task_comm, current);
|
||||
snprintf(name, sizeof(name), "%s-oneshot", task_comm);
|
||||
|
||||
timeline = oneshot_timeline_create(name);
|
||||
if (timeline == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
file->private_data = timeline;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oneshot_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct oneshot_sync_timeline *timeline = file->private_data;
|
||||
|
||||
oneshot_timeline_destroy(timeline);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long oneshot_ioctl_fence_create(struct oneshot_sync_timeline *timeline,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct oneshot_sync_create_fence param;
|
||||
int ret = -ENOMEM;
|
||||
struct sync_fence *fence = NULL;
|
||||
int fd = get_unused_fd_flags(0);
|
||||
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
if (copy_from_user(¶m, (void __user *)arg, sizeof(param))) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fence = oneshot_fence_create(timeline, param.name);
|
||||
if (fence == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
param.fence_fd = fd;
|
||||
|
||||
if (copy_to_user((void __user *)arg, ¶m, sizeof(param))) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sync_fence_install(fence, fd);
|
||||
ret = 0;
|
||||
out:
|
||||
if (ret) {
|
||||
if (fence)
|
||||
sync_fence_put(fence);
|
||||
put_unused_fd(fd);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static long oneshot_ioctl_fence_signal(struct oneshot_sync_timeline *timeline,
|
||||
unsigned long arg)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
int fd = -1;
|
||||
struct sync_fence *fence = NULL;
|
||||
|
||||
if (get_user(fd, (int __user *)arg))
|
||||
return -EFAULT;
|
||||
|
||||
fence = sync_fence_fdget(fd);
|
||||
if (fence == NULL)
|
||||
return -EBADF;
|
||||
|
||||
ret = oneshot_fence_signal(timeline, fence);
|
||||
sync_fence_put(fence);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long oneshot_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct oneshot_sync_timeline *timeline = file->private_data;
|
||||
|
||||
switch (cmd) {
|
||||
case ONESHOT_SYNC_IOC_CREATE_FENCE:
|
||||
return oneshot_ioctl_fence_create(timeline, arg);
|
||||
|
||||
case ONESHOT_SYNC_IOC_SIGNAL_FENCE:
|
||||
return oneshot_ioctl_fence_signal(timeline, arg);
|
||||
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct file_operations oneshot_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = oneshot_open,
|
||||
.release = oneshot_release,
|
||||
.unlocked_ioctl = oneshot_ioctl,
|
||||
.compat_ioctl = oneshot_ioctl,
|
||||
};
|
||||
static struct miscdevice oneshot_dev = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = "oneshot_sync",
|
||||
.fops = &oneshot_fops,
|
||||
};
|
||||
|
||||
static int __init oneshot_init(void)
|
||||
{
|
||||
return misc_register(&oneshot_dev);
|
||||
}
|
||||
|
||||
static void __exit oneshot_remove(void)
|
||||
{
|
||||
misc_deregister(&oneshot_dev);
|
||||
}
|
||||
|
||||
module_init(oneshot_init);
|
||||
module_exit(oneshot_remove);
|
||||
|
||||
#endif /* CONFIG_ONESHOT_SYNC_USER */
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
58
drivers/staging/android/oneshot_sync.h
Normal file
58
drivers/staging/android/oneshot_sync.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef LINUX_ONESHOT_SYNC_H
|
||||
#define LINUX_ONESHOT_SYNC_H
|
||||
|
||||
#include <uapi/linux/oneshot_sync.h>
|
||||
|
||||
struct oneshot_sync_timeline;
|
||||
struct sync_fence;
|
||||
|
||||
#ifdef CONFIG_ONESHOT_SYNC
|
||||
|
||||
struct oneshot_sync_timeline *oneshot_timeline_create(const char *name);
|
||||
|
||||
void oneshot_timeline_destroy(struct oneshot_sync_timeline *);
|
||||
|
||||
struct sync_fence *oneshot_fence_create(struct oneshot_sync_timeline *,
|
||||
const char *name);
|
||||
|
||||
int oneshot_fence_signal(struct oneshot_sync_timeline *, struct sync_fence *);
|
||||
|
||||
#else
|
||||
|
||||
static inline struct oneshot_sync_timeline *
|
||||
oneshot_timeline_create(const char *name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void oneshot_timeline_destroy(struct oneshot_sync_timeline *timeline)
|
||||
{
|
||||
}
|
||||
|
||||
struct sync_fence *oneshot_fence_create(struct oneshot_sync_timeline *timeline,
|
||||
const char *name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int oneshot_fence_signal(struct oneshot_sync_timeline *timeline,
|
||||
struct sync_fence *fence)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* LINUX_ONESHOT_SYNC_H */
|
49
drivers/staging/android/uapi/oneshot_sync.h
Normal file
49
drivers/staging/android/uapi/oneshot_sync.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
#ifndef ONESHOT_SYNC_H
|
||||
#define ONESHOT_SYNC_H
|
||||
|
||||
/**
|
||||
* DOC: Oneshot sync Userspace API
|
||||
*
|
||||
* Opening a file descriptor from /dev/oneshot_sync creates a * sync timeline
|
||||
* for userspace signaled fences. Userspace may create new fences from a
|
||||
* /dev/oneshot_sync file descriptor and then signal them by passing the fence
|
||||
* file descriptor in an ioctl() call on the fd used to create the fence.
|
||||
* Unlike most sync timelines, there is no ordering on a oneshot timeline.
|
||||
* Each fence may be signaled in any order without affecting the state of other
|
||||
* fences on the timeline.
|
||||
*/
|
||||
|
||||
#define ONESHOT_SYNC_IOC_MAGIC '1'
|
||||
|
||||
/**
|
||||
* struct oneshot_sync_create_fence - argument to create fence ioctl
|
||||
* @name: name of the new fence, to aid debugging.
|
||||
* @fence_fd: returned sync_fence file descriptor
|
||||
*/
|
||||
struct oneshot_sync_create_fence {
|
||||
char name[32];
|
||||
int fence_fd;
|
||||
};
|
||||
|
||||
/**
|
||||
* DOC: ONESHOT_SYNC_IOC_CREATE_FENCE - create a userspace signaled fence
|
||||
*
|
||||
* Create a fence that may be signaled by userspace by calling
|
||||
* ONESHOT_SYNC_IOC_SIGNAL_FENCE. There are no order dependencies between
|
||||
* these fences, but otherwise they behave like normal sync fences.
|
||||
* Argument is struct oneshot_sync_create_fence.
|
||||
*/
|
||||
#define ONESHOT_SYNC_IOC_CREATE_FENCE _IOWR(ONESHOT_SYNC_IOC_MAGIC, 1,\
|
||||
struct oneshot_sync_create_fence)
|
||||
|
||||
/**
|
||||
* DOC: ONESHOT_SYNC_IOC_SIGNAL_FENCE - signal a fence
|
||||
*
|
||||
* Signal a fence that was created by a ONESHOT_SYNC_IOC_CREATE_FENCE
|
||||
* call on the same file descriptor. This allows a fence to be shared
|
||||
* to other processes but only signaled by the process owning the fd
|
||||
* used to create the fence. Argument is the fence file descriptor.
|
||||
*/
|
||||
#define ONESHOT_SYNC_IOC_SIGNAL_FENCE _IOWR(ONESHOT_SYNC_IOC_MAGIC, 2,\
|
||||
int)
|
||||
#endif
|
|
@ -350,6 +350,7 @@ header-y += nvme.h
|
|||
header-y += nvram.h
|
||||
header-y += omap3isp.h
|
||||
header-y += omapfb.h
|
||||
header-y += oneshot_sync.h
|
||||
header-y += oom.h
|
||||
header-y += openvswitch.h
|
||||
header-y += packet_diag.h
|
||||
|
|
1
include/uapi/linux/oneshot_sync.h
Symbolic link
1
include/uapi/linux/oneshot_sync.h
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../../drivers/staging/android/uapi/oneshot_sync.h
|
Loading…
Add table
Reference in a new issue