On Fri, Jul 13, 2012 at 12:35 PM, Tom Cooksey <tom.cooksey(a)arm.com> wrote:
> My other thought is around atomicity. Could this be extended to
> (safely) allow for hardware devices which might want to access
> multiple buffers simultaneously? I think it probably can with
> some tweaks to the interface? An atomic function which does
> something like "give me all the fences for all these buffers
> and add this fence to each instead/as-well-as"?
fwiw, what I'm leaning …
[View More]towards right now is combining dma-fence w/
Maarten's idea of dma-buf-mgr (not sure if you saw his patches?). And
let dmabufmgr handle the multi-buffer reservation stuff. And possibly
the read vs write access, although this I'm not 100% sure on... the
other option being the concept of read vs write (or
exclusive/non-exclusive) fences.
In the current state, the fence is quite simple, and doesn't care
*what* it is fencing, which seems advantageous when you get into
trying to deal with combinations of devices sharing buffers, some of
whom can do hw sync, and some who can't. So having a bit of
partitioning from the code dealing w/ sequencing who can access the
buffers when and for what purpose seems like it might not be a bad
idea. Although I'm still working through the different alternatives.
BR,
-R
[View Less]
Hi Dave,
New pull for -next. Highlights:
- rc6/turbo support for hsw (Eugeni)
- improve corner-case of the reset handling code - gpu reset handling
should be rock-solid now
- support for fb offset > 4096 pixels on gen4+ (yeah, you need some fairly
big screens to hit that)
- the "Flush Me Harder" patch to fix the gen6+ fallout from disabling the
flushing_list
- no more /dev/agpgart on gen6+!
- HAS_PCH_xxx improvements from Paulo
- a few minor bits&pieces all over, most of it in …
[View More]thew hsw code
QA reported 2 regression, one due a bad cable (fixed by a walk to the next
radioshack) and one due to the HPD v2 patch - I owe you one for refusing
to take v2 for -fixes after v1 blew up on Linus' machine I guess ;-) The
later has a confirmed fix already queued up in my tree.
Regressions from the last pull are all fixed and some really good news:
We've finally fixed the last DP regression from 3.2. Although I'm vary of
that blowing up elseplaces, hence I prefer that we soak it in 3.6 a bit
before submitting it to stable.
Otherwise Chris is hunting down an obscure bug that got recently
introduced due to a funny interaction between two seemingly unrelated
patches, one improving our gpu death handling, the other preparing the
removal of the flushing_list. But he has patches already, although I'm
still complaining a bit about the commit messages ...
Wrt further pulls for 3.6 I'll merge feature-y stuff only at the end of
the current drm-intel-next cycle so that if this will miss 3.6 I can just
send you a pull for the bugfixes that are currently merged (or in the case
of Chris' patches, hopefully merged soon).
Yours, Daniel
PS: This pull will make the already existing conflict with Linus' tree a
bit more fun, but I think it should be still doable (the important thing
is to keep the revert from -fixes, but don't kill any other changes from
-next).
The following changes since commit 7b0cfee1a24efdfe0235bac62e53f686fe8a8e24:
Merge tag 'v3.5-rc4' into drm-intel-next-queued (2012-06-25 19:10:36 +0200)
are available in the git repository at:
git://people.freedesktop.org/~danvet/drm-intel tags/drm-intel-next-2012-07-06
for you to fetch changes up to 4acf518626cdad5bbf7aac9869bd4accbbfb4ad3:
drm/i915: program FDI_RX TP and FDI delays (2012-07-05 15:09:03 +0200)
----------------------------------------------------------------
Ben Widawsky (1):
drm/i915: linuxify create_hw_context()
Chris Wilson (2):
drm/i915: Group the GT routines together in both code and vtable
drm/i915: Implement w/a for sporadic read failures on waking from rc6
Daniel Vetter (15):
drm/i915: wrap up gt powersave enabling functions
drm/i915: make enable/disable_gt_powersave locking consistent
drm/i915: don't use dev->agp
drm/i915: disable drm agp support for !gen3 with kms enabled
agp/intel-agp: remove snb+ host bridge pciids
drm/i915: "Flush Me Harder" required on gen6+
drm/i915: fix up ilk rc6 disabling confusion
drm/i915: don't trylock in the gpu reset code
drm/i915: non-interruptible sleeps can't handle -EAGAIN
drm/i915: don't hang userspace when the gpu reset is stuck
drm/i915: properly SIGBUS on I/O errors
drm/i915: don't return a spurious -EIO from intel_ring_begin
drm/i915: introduce crtc->dspaddr_offset
drm/i915: adjust framebuffer base address on gen4+
drm/i915: introduce for_each_encoder_on_crtc
Eugeni Dodonov (11):
drm/i915: support Haswell force waking
drm/i915: add RPS configuration for Haswell
drm/i915: slightly improve gt enable/disable routines
drm/i915: enable RC6 by default on Haswell
drm/i915: disable RC6 when disabling rps
drm/i915: introduce haswell_init_clock_gating
drm/i915: enable RC6 workaround on Haswell
drm/i915: move force wake support into intel_pm
drm/i915: re-initialize DDI buffer translations after resume
drm/i915: prevent bogus intel_update_fbc notifications
drm/i915: program FDI_RX TP and FDI delays
Jesper Juhl (1):
drm/i915/sprite: Fix mem leak in intel_plane_init()
Jesse Barnes (3):
drm/i915: mask tiled bit when updating IVB sprites
drm/i915: correct IVB default sprite format
drm/i915: prefer wide & slow to fast & narrow in DP configs
Paulo Zanoni (5):
drm/i915: fix PIPE_WM_LINETIME definition
drm/i915: add PCH_NONE to enum intel_pch
drm/i915: get rid of dev_priv->info->has_pch_split
drm/i915: don't ironlake_init_pch_refclk() on LPT
drm/i915: fix PIPE_DDI_PORT_MASK
Ville Syrjälä (2):
drm/i915: Zero initialize mode_cmd
drm/i915: Reject page flips with changed format/offset/pitch
drivers/char/agp/intel-agp.c | 11 -
drivers/gpu/drm/i915/i915_dma.c | 9 +-
drivers/gpu/drm/i915/i915_drv.c | 172 ++------------
drivers/gpu/drm/i915/i915_drv.h | 28 ++-
drivers/gpu/drm/i915/i915_gem.c | 44 +++-
drivers/gpu/drm/i915/i915_gem_context.c | 50 ++--
drivers/gpu/drm/i915/i915_reg.h | 21 +-
drivers/gpu/drm/i915/i915_suspend.c | 5 +-
drivers/gpu/drm/i915/intel_ddi.c | 9 +
drivers/gpu/drm/i915/intel_display.c | 162 ++++++-------
drivers/gpu/drm/i915/intel_dp.c | 26 +-
drivers/gpu/drm/i915/intel_drv.h | 16 +-
drivers/gpu/drm/i915/intel_fb.c | 2 +-
drivers/gpu/drm/i915/intel_lvds.c | 6 +-
drivers/gpu/drm/i915/intel_pm.c | 396 +++++++++++++++++++++++++------
drivers/gpu/drm/i915/intel_ringbuffer.c | 34 +--
drivers/gpu/drm/i915/intel_sprite.c | 5 +-
drivers/gpu/drm/i915/intel_tv.c | 10 +-
18 files changed, 579 insertions(+), 427 deletions(-)
--
Daniel Vetter
Mail: daniel(a)ffwll.ch
Mobile: +41 (0)79 365 57 48
[View Less]
Hello,
I'm trying to figure out how to control the brightness of the screen of my
laptop, a Toshiba L885-10W.
The ACPI DSDT table contains the standard control methods, the setter (_BCM),
however, only sets a value in the record returned by ATIF method and send out a
notification:
CreateByteField (ATIB, 0x0C, BRIL) // ATIB is returned by ATIF
Store (Arg0, BRIL)
Notify (VGA, 0x81)
When using the ACPI sysfs backlight interface nothing happens (obviously).
0x81 seems also strange, according to …
[View More]the specification is
"Output Device Status Change: Used to notify OSPM whenever the state of any
output devices attached to the VGA controller has been changed. This event
will, for example, be generated when the user plugs-in or remove a CRT from
the VGA port. In this case, OSPM will re-enumerate all devices attached to
VGA"
and confuses KDE when using more than one screen (but this is a
different issue).
I suspect that the notification means that the radeon driver is supposed to
change the brightness; the GPU is a:
01:00.0 VGA compatible controller [0300]: Advanced Micro Devices [AMD] nee ATI Thames XT/GL [Radeon HD 7600M Series] [1002:6840]
kernel drivers says:
[drm] initializing kernel modesetting (TURKS 0x1002:0x6840 0x1179:0xFB22)
Poking around with avivotools it seems that AVIVO_LVDS_BACKLIGHT_CNTL (0x7af8)
is not present anymore...
Furthermore ATIF returns a different structure based on the parameter passed by
the caller; radeon drm driver always passes "1", the BRIL field is mentioned
only when passing "2" (it shouldn't matter, the field is set unconditionally,
but it seems some king of versioning); it seems a versioned data structure...
Do you have any information that you can share about ATIF and brightness
control on modern GPUs?
Luca
[View Less]
From: Rob Clark <rob(a)ti.com>
A dma-fence can be attached to a buffer which is being filled or consumed
by hw, to allow userspace to pass the buffer without waiting to another
device. For example, userspace can call page_flip ioctl to display the
next frame of graphics after kicking the GPU but while the GPU is still
rendering. The display device sharing the buffer with the GPU would
attach a callback to get notified when the GPU's rendering-complete IRQ
fires, to update the scan-out …
[View More]address of the display, without having to
wake up userspace.
A dma-fence is transient, one-shot deal. It is allocated and attached
to dma-buf's list of fences. When the one that attached it is done,
with the pending operation, it can signal the fence removing it from the
dma-buf's list of fences:
+ dma_buf_attach_fence()
+ dma_fence_signal()
Other drivers can access the current fence on the dma-buf (if any),
which increment's the fences refcnt:
+ dma_buf_get_fence()
+ dma_fence_put()
The one pending on the fence can add an async callback (and optionally
cancel it.. for example, to recover from GPU hangs):
+ dma_fence_add_callback()
+ dma_fence_cancel_callback()
Or wait synchronously (optionally with timeout or from atomic context):
+ dma_fence_wait()
A default software-only implementation is provided, which can be used
by drivers attaching a fence to a buffer when they have no other means
for hw sync. But a memory backed fence is also envisioned, because it
is common that GPU's can write to, or poll on some memory location for
synchronization. For example:
fence = dma_buf_get_fence(dmabuf);
if (fence->ops == &mem_dma_fence_ops) {
dma_buf *fence_buf;
mem_dma_fence_get_buf(fence, &fence_buf, &offset);
... tell the hw the memory location to wait on ...
} else {
/* fall-back to sw sync * /
dma_fence_add_callback(fence, my_cb);
}
The memory location is itself backed by dma-buf, to simplify mapping
to the device's address space, an idea borrowed from Maarten Lankhorst.
NOTE: the memory location fence is not implemented yet, the above is
just for explaining how it would work.
On SoC platforms, if some other hw mechanism is provided for synchronizing
between IP blocks, it could be supported as an alternate implementation
with it's own fence ops in a similar way.
The other non-sw implementations would wrap the add/cancel_callback and
wait fence ops, so that they can keep track if a device not supporting
hw sync is waiting on the fence, and in this case should arrange to
call dma_fence_signal() at some point after the condition has changed,
to notify other devices waiting on the fence. If there are no sw
waiters, this can be skipped to avoid waking the CPU unnecessarily.
The intention is to provide a userspace interface (presumably via eventfd)
later, to be used in conjunction with dma-buf's mmap support for sw access
to buffers (or for userspace apps that would prefer to do their own
synchronization).
---
drivers/base/Makefile | 2 +-
drivers/base/dma-buf.c | 3 +
drivers/base/dma-fence.c | 325 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/dma-buf.h | 3 +
include/linux/dma-fence.h | 118 ++++++++++++++++
5 files changed, 450 insertions(+), 1 deletion(-)
create mode 100644 drivers/base/dma-fence.c
create mode 100644 include/linux/dma-fence.h
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 5aa2d70..6e9f217 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_CMA) += dma-contiguous.o
obj-y += power/
obj-$(CONFIG_HAS_DMA) += dma-mapping.o
obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
-obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf.o
+obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf.o dma-fence.o
obj-$(CONFIG_ISA) += isa.o
obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index 24e88fe..b053236 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -39,6 +39,8 @@ static int dma_buf_release(struct inode *inode, struct file *file)
dmabuf = file->private_data;
+ WARN_ON(!list_empty(&dmabuf->fence_list));
+
dmabuf->ops->release(dmabuf);
kfree(dmabuf);
return 0;
@@ -119,6 +121,7 @@ struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops,
mutex_init(&dmabuf->lock);
INIT_LIST_HEAD(&dmabuf->attachments);
+ INIT_LIST_HEAD(&dmabuf->fence_list);
return dmabuf;
}
diff --git a/drivers/base/dma-fence.c b/drivers/base/dma-fence.c
new file mode 100644
index 0000000..a94ed01
--- /dev/null
+++ b/drivers/base/dma-fence.c
@@ -0,0 +1,325 @@
+/*
+ * Fence mechanism for dma-buf to allow for asynchronous dma access
+ *
+ * Copyright (C) 2012 Texas Instruments
+ * Author: Rob Clark <rob.clark(a)linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/export.h>
+#include <linux/dma-fence.h>
+
+static DEFINE_SPINLOCK(fence_lock);
+
+/**
+ * dma_buf_attach_fence - Attach a fence to a dma-buf.
+ *
+ * @buf: the dma-buf to attach to
+ * @fence: the fence to attach
+ *
+ * A fence can only be attached to a single dma-buf. The dma-buf takes
+ * ownership of the fence, which is unref'd when the fence is signaled.
+ * The fence takes a reference to the dma-buf so the buffer will not be
+ * freed while there is a pending fence.
+ */
+int dma_buf_attach_fence(struct dma_buf *buf, struct dma_fence *fence)
+{
+ if (WARN_ON(!buf || !fence || fence->buf))
+ return -EINVAL;
+
+ spin_lock(&fence_lock);
+ get_dma_buf(buf);
+ fence->buf = buf;
+ list_add(&fence->list_node, &buf->fence_list);
+ spin_unlock(&fence_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dma_buf_attach_fence);
+
+/**
+ * dma_fence_signal - Signal a fence.
+ *
+ * @fence: The fence to signal
+ *
+ * All registered callbacks will be called directly (synchronously) and
+ * all blocked waters will be awoken.
+ */
+int dma_fence_signal(struct dma_fence *fence)
+{
+ unsigned long flags;
+ int ret;
+
+ if (WARN_ON(!fence || !fence->buf))
+ return -EINVAL;
+
+ spin_lock_irqsave(&fence_lock, flags);
+ list_del(&fence->list_node);
+ spin_unlock_irqrestore(&fence_lock, flags);
+
+ dma_buf_put(fence->buf);
+ fence->buf = NULL;
+
+ ret = fence->ops->signal(fence);
+
+ dma_fence_put(fence);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dma_fence_signal);
+
+/**
+ * dma_buf_get_fence - Get the most recent pending fence attached to the
+ * dma-buf.
+ *
+ * @buf: the dma-buf whose fence to get
+ *
+ * If this returns NULL, there are no pending fences. Otherwise this
+ * takes a reference to the returned fence, so the caller must later
+ * call dma_fence_put() to release the reference.
+ */
+struct dma_fence *dma_buf_get_fence(struct dma_buf *buf)
+{
+ struct dma_fence *fence = NULL;
+
+ if (WARN_ON(!buf))
+ return ERR_PTR(-EINVAL);
+
+ spin_lock(&fence_lock);
+ if (!list_empty(&buf->fence_list)) {
+ fence = list_first_entry(&buf->fence_list,
+ struct dma_fence, list_node);
+ dma_fence_get(fence);
+ }
+ spin_unlock(&fence_lock);
+
+ return fence;
+}
+EXPORT_SYMBOL_GPL(dma_buf_get_fence);
+
+static void release_fence(struct kref *kref)
+{
+ struct dma_fence *fence =
+ container_of(kref, struct dma_fence, refcount);
+
+ WARN_ON(waitqueue_active(&fence->event_queue) || fence->buf);
+
+ kfree(fence);
+}
+
+/**
+ * dma_fence_put - Release a reference to the fence.
+ */
+void dma_fence_put(struct dma_fence *fence)
+{
+ WARN_ON(!fence);
+ kref_put(&fence->refcount, release_fence);
+}
+EXPORT_SYMBOL_GPL(dma_fence_put);
+
+/**
+ * dma_fence_get - Take a reference to the fence.
+ *
+ * In most cases this is used only internally by dma-fence.
+ */
+void dma_fence_get(struct dma_fence *fence)
+{
+ WARN_ON(!fence);
+ kref_get(&fence->refcount);
+}
+EXPORT_SYMBOL_GPL(dma_fence_get);
+
+/**
+ * dma_fence_add_callback - Add a callback to be called when the fence
+ * is signaled.
+ *
+ * @fence: The fence to wait on
+ * @cb: The callback to register
+ *
+ * Any number of callbacks can be registered to a fence, but a callback
+ * can only be registered to once fence at a time.
+ *
+ * Note that the callback can be called from an atomic context. If
+ * fence is already signaled, this function will return -EINVAL (and
+ * *not* call the callback)
+ */
+int dma_fence_add_callback(struct dma_fence *fence,
+ struct dma_fence_cb *cb)
+{
+ int ret = -EINVAL;
+
+ if (WARN_ON(!fence || !cb))
+ return -EINVAL;
+
+ spin_lock(&fence_lock);
+ if (fence->buf) {
+ dma_fence_get(fence);
+ cb->fence = fence;
+ ret = fence->ops->add_callback(fence, cb);
+ }
+ spin_unlock(&fence_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dma_fence_add_callback);
+
+/**
+ * dma_fence_cancel_callback - Remove a previously registered callback.
+ *
+ * @cb: The callback to unregister
+ *
+ * The callback will not be called after this function returns, but could
+ * be called before this function returns.
+ */
+int dma_fence_cancel_callback(struct dma_fence_cb *cb)
+{
+ struct dma_fence *fence;
+ int ret = -EINVAL;
+
+ if (WARN_ON(!cb))
+ return -EINVAL;
+
+ fence = cb->fence;
+
+ spin_lock(&fence_lock);
+ if (fence) {
+ ret = fence->ops->cancel_callback(cb);
+ cb->fence = NULL;
+ dma_fence_put(fence);
+ }
+ spin_unlock(&fence_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dma_fence_cancel_callback);
+
+/**
+ * dma_fence_wait - Wait for a fence to be signaled.
+ *
+ * @fence: The fence to wait on
+ * @interruptible: if true, do an interruptible wait
+ * @timeout: timeout, in jiffies
+ */
+int dma_fence_wait(struct dma_fence *fence, bool interruptible, long timeout)
+{
+ if (WARN_ON(!fence))
+ return -EINVAL;
+
+ return fence->ops->wait(fence, interruptible, timeout);
+}
+EXPORT_SYMBOL_GPL(dma_fence_wait);
+
+int __dma_fence_wake_func(wait_queue_t *wait, unsigned mode,
+ int flags, void *key)
+{
+ struct dma_fence_cb *cb =
+ container_of(wait, struct dma_fence_cb, base);
+ int ret;
+
+ ret = cb->func(cb, cb->fence);
+ dma_fence_put(cb->fence);
+ cb->fence = NULL;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__dma_fence_wake_func);
+
+/*
+ * Helpers intended to be used by the ops of the dma_fence implementation:
+ *
+ * NOTE: helpers and fxns intended to be used by other dma-fence
+ * implementations are not exported.. I'm not really sure if it makes
+ * sense to have a dma-fence implementation that is itself a module.
+ */
+
+void __dma_fence_init(struct dma_fence *fence, struct dma_fence_ops *ops)
+{
+ WARN_ON(!ops || !ops->signal || !ops->add_callback ||
+ !ops->cancel_callback || !ops->wait);
+
+ kref_init(&fence->refcount);
+ fence->ops = ops;
+ init_waitqueue_head(&fence->event_queue);
+}
+
+int dma_fence_helper_signal(struct dma_fence *fence)
+{
+ wake_up_all(&fence->event_queue);
+ return 0;
+}
+
+int dma_fence_helper_add_callback(struct dma_fence *fence,
+ struct dma_fence_cb *cb)
+{
+ add_wait_queue(&fence->event_queue, &cb->base);
+ return 0;
+}
+
+int dma_fence_helper_cancel_callback(struct dma_fence_cb *cb)
+{
+ struct dma_fence *fence = cb->fence;
+ remove_wait_queue(&fence->event_queue, &cb->base);
+ return 0;
+}
+
+int dma_fence_helper_wait(struct dma_fence *fence, bool interruptible,
+ long timeout)
+{
+ int ret;
+
+ if (interruptible) {
+ ret = wait_event_interruptible_timeout(fence->event_queue,
+ !fence->buf, timeout);
+ } else {
+ ret = wait_event_timeout(fence->event_queue,
+ !fence->buf, timeout);
+ }
+
+ return ret;
+}
+
+/*
+ * Pure sw implementation for dma-fence. The CPU always gets involved.
+ */
+
+static struct dma_fence_ops sw_fence_ops = {
+ .signal = dma_fence_helper_signal,
+ .add_callback = dma_fence_helper_add_callback,
+ .cancel_callback = dma_fence_helper_cancel_callback,
+ .wait = dma_fence_helper_wait,
+};
+
+/**
+ * dma_fence_create - Create a simple sw-only fence.
+ *
+ * This fence only supports signaling from/to CPU. Other implementations
+ * of dma-fence can be used to support hardware to hardware signaling, if
+ * supported by the hardware, and use the dma_fence_helper_* functions for
+ * compatibility with other devices that only support sw signaling.
+ */
+struct dma_fence *dma_fence_create(void)
+{
+ struct dma_fence *fence;
+
+ fence = kzalloc(sizeof(struct dma_fence), GFP_KERNEL);
+ if (!fence)
+ return ERR_PTR(-ENOMEM);
+
+ __dma_fence_init(fence, &sw_fence_ops);
+
+ return fence;
+}
+EXPORT_SYMBOL_GPL(dma_fence_create);
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index eb48f38..a0a0b64 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -29,6 +29,7 @@
#include <linux/scatterlist.h>
#include <linux/list.h>
#include <linux/dma-mapping.h>
+#include <linux/dma-fence.h>
#include <linux/fs.h>
struct device;
@@ -122,6 +123,8 @@ struct dma_buf {
/* mutex to serialize list manipulation and attach/detach */
struct mutex lock;
void *priv;
+ /* list of pending dma_fence's */
+ struct list_head fence_list;
};
/**
diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
new file mode 100644
index 0000000..ecda334
--- /dev/null
+++ b/include/linux/dma-fence.h
@@ -0,0 +1,118 @@
+/*
+ * Fence mechanism for dma-buf to allow for asynchronous dma access
+ *
+ * Copyright (C) 2012 Texas Instruments
+ * Author: Rob Clark <rob.clark(a)linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __DMA_FENCE_H__
+#define __DMA_FENCE_H__
+
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/dma-buf.h>
+
+struct dma_fence;
+struct dma_fence_ops;
+struct dma_fence_cb;
+
+struct dma_fence {
+ struct kref refcount;
+ struct dma_fence_ops *ops;
+ wait_queue_head_t event_queue;
+ struct list_head list_node; /* for dmabuf's fence_list */
+
+ /*
+ * This is initialized when the fence is attached to a dma-buf,
+ * and NULL'd before it is signaled. A fence can be attached to
+ * at most one dma-buf at a time.
+ */
+ struct dma_buf *buf;
+};
+
+typedef int (*dma_fence_func_t)(struct dma_fence_cb *cb,
+ struct dma_fence *fence);
+
+struct dma_fence_ops {
+ int (*signal)(struct dma_fence *fence);
+ int (*add_callback)(struct dma_fence *fence, struct dma_fence_cb *cb);
+ int (*cancel_callback)(struct dma_fence_cb *cb);
+ int (*wait)(struct dma_fence *fence, bool interruptible, long timeout);
+};
+
+struct dma_fence_cb {
+ wait_queue_t base;
+ dma_fence_func_t func;
+
+ /*
+ * This is initialized when the cb is added, and NULL'd when it
+ * is canceled or expired, so can be used to for error checking
+ * if the cb is already pending. A dma_fence_cb can be pending
+ * on at most one fence at a time.
+ */
+ struct dma_fence *fence;
+};
+
+int __dma_fence_wake_func(wait_queue_t *wait, unsigned mode,
+ int flags, void *key);
+
+#define DMA_FENCE_CB_INITIALIZER(cb_func) { \
+ .base = { .func = __dma_fence_wake_func }, \
+ .func = (cb_func), \
+ }
+
+#define DECLARE_DMA_FENCE(name, cb_func) \
+ struct dma_fence_cb name = DMA_FENCE_CB_INITIALIZER(cb_func)
+
+
+/*
+ * TODO does it make sense to be able to enable dma-fence without dma-buf,
+ * or visa versa?
+ */
+#ifdef CONFIG_DMA_SHARED_BUFFER
+
+int dma_buf_attach_fence(struct dma_buf *buf, struct dma_fence *fence);
+struct dma_fence *dma_buf_get_fence(struct dma_buf *buf);
+
+/* create a basic (pure sw) fence: */
+struct dma_fence *dma_fence_create(void);
+
+/* intended to be used by other dma_fence implementations: */
+void __dma_fence_init(struct dma_fence *fence, struct dma_fence_ops *ops);
+
+void dma_fence_get(struct dma_fence *fence);
+void dma_fence_put(struct dma_fence *fence);
+int dma_fence_signal(struct dma_fence *fence);
+
+int dma_fence_add_callback(struct dma_fence *fence,
+ struct dma_fence_cb *cb);
+int dma_fence_cancel_callback(struct dma_fence_cb *cb);
+int dma_fence_wait(struct dma_fence *fence, bool interruptible, long timeout);
+
+/* helpers intended to be used by the ops of the dma_fence implementation: */
+int dma_fence_helper_signal(struct dma_fence *fence);
+int dma_fence_helper_add_callback(struct dma_fence *fence,
+ struct dma_fence_cb *cb);
+int dma_fence_helper_cancel_callback(struct dma_fence_cb *cb);
+int dma_fence_helper_wait(struct dma_fence *fence, bool interruptible,
+ long timeout);
+
+#else
+// TODO
+#endif /* CONFIG_DMA_SHARED_BUFFER */
+
+#endif /* __DMA_FENCE_H__ */
--
1.7.9.5
[View Less]
https://bugzilla.kernel.org/show_bug.cgi?id=15748
Alan <alan(a)lxorguk.ukuu.org.uk> changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|NEW |RESOLVED
CC| |alan(a)lxorguk.ukuu.org.uk
Resolution| |OBSOLETE
--- Comment #2 from Alan <alan(a)lxorguk.ukuu.org.uk> 2012-07-…
[View More]11 15:08:31 ---
Closing as this code has changed hugely since the reported version
--
Configure bugmail: https://bugzilla.kernel.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching the assignee of the bug.
[View Less]