Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* [PATCH v9 0/2] Introduce buffer synchronization framework
From: Inki Dae @ 2013-09-17 12:23 UTC (permalink / raw)
  To: dri-devel, linux-fbdev, linux-arm-kernel, linux-media,
	linaro-kernel
  Cc: Roger.Teague, jesse.barker, jesse.barker, maarten.lankhorst,
	sumit.semwal, kyungmin.park, myungjoo.ham, Inki Dae

Hi all,

This patch set introduces a buffer synchronization framework based
on DMA BUF[1] and based on ww-mutexes[2] for lock mechanism, and is
rebased on linux-3.12-rc1

The purpose of this framework is to provide not only buffer access
control to CPU and CPU, and CPU and DMA, and DMA and DMA but also
easy-to-use interfaces for device drivers and user application.
In addtion, this patch set suggests a way for enhancing performance.

Changelog v9:
- Delete only one sync object matched at DEL_OBJ_FROM_RSV macro.
- Fix memory leak issue at dmabuf_sync_single_lock()

Changelog v8:
Consider the write-and-then-read ordering pointed out by David Herrmann,
- The ordering issue means that a task don't take a lock to the dmabuf
  so this task would be stalled even though this task requested a lock to
  the dmabuf between other task unlocked and tries to lock the dmabuf
  again. For this, we have added a wait event mechanism using only generic
  APIs, wait_event_timeout and wake_up functions.

  The below is how to handle the ordering issue using this mechanism:
  1. Check if there is a sync object added prior to current task's one.
  2. If exists, it unlocks the dmabuf so that other task can take a lock
     to the dmabuf first.
  3. Wait for the wake up event from other task: current task will be
     waked up when other task unlocks the dmabuf.
  4. Take a lock to the dmabuf again.
- Code cleanups.

Changelog v7:
Fix things pointed out by Konrad Rzeszutek Wilk,
- Use EXPORT_SYMBOL_GPL instead of EXPORT_SYMBOL.
- Make sure to unlock and unreference all dmabuf objects
  when dmabuf_sync_fini() is called.
- Add more comments.
- Code cleanups.

Changelog v6:
- Fix sync lock to multiple reads.
- Add select system call support.
  . Wake up poll_wait when a dmabuf is unlocked.
- Remove unnecessary the use of mutex lock.
- Add private backend ops callbacks.
  . This ops has one callback for device drivers to clean up their
    sync object resource when the sync object is freed. For this,
    device drivers should implement the free callback properly.
- Update document file.

Changelog v5:
- Rmove a dependence on reservation_object: the reservation_object is used
  to hook up to ttm and dma-buf for easy sharing of reservations across
  devices. However, the dmabuf sync can be used for all dma devices; v4l2
  and drm based drivers, so doesn't need the reservation_object anymore.
  With regared to this, it adds 'void *sync' to dma_buf structure.
- All patches are rebased on mainline, Linux v3.10.

Changelog v4:
- Add user side interface for buffer synchronization mechanism and update
  descriptions related to the user side interface.

Changelog v3:
- remove cache operation relevant codes and update document file.

Changelog v2:
- use atomic_add_unless to avoid potential bug.
- add a macro for checking valid access type.
- code clean.

For generic user mode interface, we have used fcntl and select system
call[3]. As you know, user application sees a buffer object as a dma-buf
file descriptor. So fcntl() call with the file descriptor means to lock
some buffer region being managed by the dma-buf object. And select() call
means to wait for the completion of CPU or DMA access to the dma-buf
without locking. For more detail, you can refer to the dma-buf-sync.txt
in Documentation/

There are some cases user-space process needs this buffer synchronization
framework. One of which is to primarily enhance GPU rendering performance
in case that 3D app draws somthing in a buffer using CPU, and other process
composes the buffer with its own backbuffer using GPU.

In case of 3D app, the app calls glFlush to submit 3d commands to GPU driver
instead of glFinish for more performance. The reason, we call glFlush, is
that glFinish blocks caller's task until the execution of the 3d commands is
completed. So that makes GPU and CPU more idle. As a result, 3d rendering
performance with glFinish is quite lower than glFlush.

However, the use of glFlush has one issue that the the buffer shared with
GPU could be broken when CPU accesses the buffer just after glFlush because
CPU cannot be aware of the completion of GPU access to the buffer.
Of course, the app can be aware of that time using eglWaitGL but this function
is valid only in case of the same context.

The below summarizes how app's window is displayed on Tizen[4] platform:
1. X client requests a window buffer to Xorg.
2. X client draws something in the window buffer using CPU.
3. X client requests SWAP to Xorg.
4. Xorg notifies a damage event to Composite Manager.
5. Composite Manager gets the window buffer (front buffer) through
   DRI2GetBuffers.
6. Composite Manager composes the window buffer and its own back buffer
   using GPU. At this time, eglSwapBuffers is called: internally, 3d
   commands are flushed to gpu driver.
7. Composite Manager requests SWAP to Xorg.
8. Xorg performs drm page flip. At this time, the window buffer is
   displayed on screen.

Web app based on HTML5 also has the same issue. Web browser and Web app
are different process. The Web app can draw something in its own buffer using
CPU, and then the Web Browser can compose the buffer with its own back buffer.

Thus, in such cases, a shared buffer could be broken as one process draws
something in a buffer using CPU, when other process composes the buffer with
its own buffer using GPU without any locking mechanism. That is why we need
user land locking interface, fcntl system call.

And last one is a deferred page flip issue. This issue is that a window
buffer rendered can be displayed on screen in about 32ms in worst case:
assume that the gpu rendering is completed within 16ms.
That can be incurred when compositing a pixmap buffer with a window buffer
using GPU and when vsync is just started. At this time, Xorg waits for
a vblank event to get a window buffer so 3d rendering will be delayed
up to about 16ms. As a result, the window buffer would be displayed in
about two vsyncs (about 32ms) and in turn, that would show slow
responsiveness.

For this, we could enhance the responsiveness with locking mechanism: skipping
one vblank wait. I guess Android, Chrome OS, and other platforms are using
their own locking mechanisms with similar reason; Android sync driver, KDS, and
DMA fence.

The below shows the deferred page flip issue in worst case:

               |------------ <- vsync signal
               |<------ DRI2GetBuffers
               |
               |
               |
               |------------ <- vsync signal
               |<------ Request gpu rendering
          time |
               |
               |<------ Request page flip (deferred)
               |------------ <- vsync signal
               |<------ Displayed on screen
               |
               |
               |
               |------------ <- vsync signal

Thanks,
Inki Dae

References:
[1] http://lwn.net/Articles/470339/
[2] https://patchwork.kernel.org/patch/2625361/
[3] http://linux.die.net/man/2/fcntl
[4] https://www.tizen.org/

Inki Dae (2):
  dmabuf-sync: Add a buffer synchronization framework
  dma-buf: Add user interfaces for dmabuf sync support

 Documentation/dma-buf-sync.txt |  286 ++++++++++++
 drivers/base/Kconfig           |    7 +
 drivers/base/Makefile          |    1 +
 drivers/base/dma-buf.c         |   86 ++++
 drivers/base/dmabuf-sync.c     |  951 ++++++++++++++++++++++++++++++++++++++++
 include/linux/dma-buf.h        |   16 +
 include/linux/dmabuf-sync.h    |  257 +++++++++++
 7 files changed, 1604 insertions(+)
 create mode 100644 Documentation/dma-buf-sync.txt
 create mode 100644 drivers/base/dmabuf-sync.c
 create mode 100644 include/linux/dmabuf-sync.h

-- 
1.7.9.5


^ permalink raw reply

* [PATCH v9 1/2] dmabuf-sync: Add a buffer synchronization framework
From: Inki Dae @ 2013-09-17 12:23 UTC (permalink / raw)
  To: dri-devel, linux-fbdev, linux-arm-kernel, linux-media,
	linaro-kernel
  Cc: Roger.Teague, jesse.barker, jesse.barker, maarten.lankhorst,
	sumit.semwal, kyungmin.park, myungjoo.ham, Inki Dae
In-Reply-To: <1379420616-9194-1-git-send-email-inki.dae@samsung.com>

This patch adds a buffer synchronization framework based on DMA BUF[1]
and and based on ww-mutexes[2] for lock mechanism, and is rebased on
linux-3.12-rc1

The purpose of this framework is to provide not only buffer access control
to CPU and DMA but also easy-to-use interfaces for device drivers and
user application. This framework can be used for all dma devices using
system memory as dma buffer, especially for most ARM based SoCs.

Changelog v9:
- Delete only one sync object matched at DEL_OBJ_FROM_RSV macro.
- Fix memory leak issue at dmabuf_sync_single_lock()

Changelog v8:
Consider the write-and-then-read ordering pointed out by David Herrmann,
- The ordering issue means that a task don't take a lock to the dmabuf
  so this task would be stalled even though this task requested a lock to
  the dmabuf between other task unlocked and tries to lock the dmabuf
  again. For this, we have added a wait event mechanism using only generic
  APIs, wait_event_timeout and wake_up functions.

  The below is how to handle the ordering issue using this mechanism:
  1. Check if there is a sync object added prior to current task's one.
  2. If exists, it unlocks the dmabuf so that other task can take a lock
     to the dmabuf first.
  3. Wait for the wake up event from other task: current task will be
     waked up when other task unlocks the dmabuf.
  4. Take a lock to the dmabuf again.
- Code cleanups.

Changelog v7:
Fix things pointed out by Konrad Rzeszutek Wilk,
- Use EXPORT_SYMBOL_GPL instead of EXPORT_SYMBOL.
- make sure to unlock and unreference all dmabuf objects
  when dmabuf_sync_fini() is called.
- Add more comments.
- code cleanups.

Changelog v6:
- Fix sync lock to multiple reads.
- Add select system call support.
  . Wake up poll_wait when a dmabuf is unlocked.
- Remove unnecessary the use of mutex lock.
- Add private backend ops callbacks.
  . This ops has one callback for device drivers to clean up their
    sync object resource when the sync object is freed. For this,
    device drivers should implement the free callback properly.
- Update document file.

Changelog v5:
- Rmove a dependence on reservation_object: the reservation_object is used
  to hook up to ttm and dma-buf for easy sharing of reservations across
  devices. However, the dmabuf sync can be used for all dma devices; v4l2
  and drm based drivers, so doesn't need the reservation_object anymore.
  With regared to this, it adds 'void *sync' to dma_buf structure.
- All patches are rebased on mainline, Linux v3.10.

Changelog v4:
- Add user side interface for buffer synchronization mechanism and update
  descriptions related to the user side interface.

Changelog v3:
- remove cache operation relevant codes and update document file.

Changelog v2:
- use atomic_add_unless to avoid potential bug.
- add a macro for checking valid access type.
- code clean.

The mechanism of this framework has the following steps,
    1. Register dmabufs to a sync object - A task gets a new sync object and
    can add one or more dmabufs that the task wants to access.
    This registering should be performed when a device context or an event
    context such as a page flip event is created or before CPU accesses a shared
    buffer.

	dma_buf_sync_get(a sync object, a dmabuf);

    2. Lock a sync object - A task tries to lock all dmabufs added in its own
    sync object. Basically, the lock mechanism uses ww-mutex[1] to avoid dead
    lock issue and for race condition between CPU and CPU, CPU and DMA, and DMA
    and DMA. Taking a lock means that others cannot access all locked dmabufs
    until the task that locked the corresponding dmabufs, unlocks all the locked
    dmabufs.
    This locking should be performed before DMA or CPU accesses these dmabufs.

	dma_buf_sync_lock(a sync object);

    3. Unlock a sync object - The task unlocks all dmabufs added in its own sync
    object. The unlock means that the DMA or CPU accesses to the dmabufs have
    been completed so that others may access them.
    This unlocking should be performed after DMA or CPU has completed accesses
    to the dmabufs.

	dma_buf_sync_unlock(a sync object);

    4. Unregister one or all dmabufs from a sync object - A task unregisters
    the given dmabufs from the sync object. This means that the task dosen't
    want to lock the dmabufs.
    The unregistering should be performed after DMA or CPU has completed
    accesses to the dmabufs or when dma_buf_sync_lock() is failed.

	dma_buf_sync_put(a sync object, a dmabuf);
	dma_buf_sync_put_all(a sync object);

    The described steps may be summarized as:
	get -> lock -> CPU or DMA access to a buffer/s -> unlock -> put

This framework includes the following two features.
    1. read (shared) and write (exclusive) locks - A task is required to declare
    the access type when the task tries to register a dmabuf;
    READ, WRITE, READ DMA, or WRITE DMA.

    The below is example codes,
	struct dmabuf_sync *sync;

	sync = dmabuf_sync_init(...);
	...

	dmabuf_sync_get(sync, dmabuf, DMA_BUF_ACCESS_R);
	...

	And the below can be used as access types:
		DMA_BUF_ACCESS_R - CPU will access a buffer for read.
		DMA_BUF_ACCESS_W - CPU will access a buffer for read or write.
		DMA_BUF_ACCESS_DMA_R - DMA will access a buffer for read
		DMA_BUF_ACCESS_DMA_W - DMA will access a buffer for read or
					write.

    2. Mandatory resource releasing - a task cannot hold a lock indefinitely.
    A task may never try to unlock a buffer after taking a lock to the buffer.
    In this case, a timer handler to the corresponding sync object is called
    in five (default) seconds and then the timed-out buffer is unlocked by work
    queue handler to avoid lockups and to enforce resources of the buffer.

The below is how to use interfaces for device driver:
	1. Allocate and Initialize a sync object:
		static void xxx_dmabuf_sync_free(void *priv)
		{
			struct xxx_context *ctx = priv;

			if (!ctx)
				return;

			ctx->sync = NULL;
		}
		...

		static struct dmabuf_sync_priv_ops driver_specific_ops = {
			.free = xxx_dmabuf_sync_free,
		};
		...

		struct dmabuf_sync *sync;

		sync = dmabuf_sync_init("test sync", &driver_specific_ops, ctx);
		...

	2. Add a dmabuf to the sync object when setting up dma buffer relevant
	   registers:
		dmabuf_sync_get(sync, dmabuf, DMA_BUF_ACCESS_READ);
		...

	3. Lock all dmabufs of the sync object before DMA or CPU accesses
	   the dmabufs:
		dmabuf_sync_lock(sync);
		...

	4. Now CPU or DMA can access all dmabufs locked in step 3.

	5. Unlock all dmabufs added in a sync object after DMA or CPU access
	   to these dmabufs is completed:
		dmabuf_sync_unlock(sync);

	   And call the following functions to release all resources,
		dmabuf_sync_put_all(sync);
		dmabuf_sync_fini(sync);

	You can refer to actual example codes:
		"drm/exynos: add dmabuf sync support for g2d driver" and
		"drm/exynos: add dmabuf sync support for kms framework" from
		https://git.kernel.org/cgit/linux/kernel/git/daeinki/
		drm-exynos.git/log/?h=dmabuf-sync

And this framework includes fcntl[3] and select system call as interfaces
exported to user. As you know, user sees a buffer object as a dma-buf file
descriptor. fcntl() call with the file descriptor means to lock some buffer
region being managed by the dma-buf object. And select() call with the file
descriptor means to poll the completion event of CPU or DMA access to
the dma-buf.

The below is how to use interfaces for user application:

fcntl system call:

	struct flock filelock;

	1. Lock a dma buf:
		filelock.l_type = F_WRLCK or F_RDLCK;

		/* lock entire region to the dma buf. */
		filelock.lwhence = SEEK_CUR;
		filelock.l_start = 0;
		filelock.l_len = 0;

		fcntl(dmabuf fd, F_SETLKW or F_SETLK, &filelock);
		...
		CPU access to the dma buf

	2. Unlock a dma buf:
		filelock.l_type = F_UNLCK;

		fcntl(dmabuf fd, F_SETLKW or F_SETLK, &filelock);

		close(dmabuf fd) call would also unlock the dma buf. And for more
		detail, please refer to [3]

select system call:

	fd_set wdfs or rdfs;

	FD_ZERO(&wdfs or &rdfs);
	FD_SET(fd, &wdfs or &rdfs);

	select(fd + 1, &rdfs, NULL, NULL, NULL);
		or
	select(fd + 1, NULL, &wdfs, NULL, NULL);

	Every time select system call is called, a caller will wait for
	the completion of DMA or CPU access to a shared buffer if there
	is someone accessing the shared buffer. If no anyone then select
	system call will be returned at once.

References:
[1] http://lwn.net/Articles/470339/
[2] https://patchwork.kernel.org/patch/2625361/
[3] http://linux.die.net/man/2/fcntl

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 Documentation/dma-buf-sync.txt |  286 ++++++++++++
 drivers/base/Kconfig           |    7 +
 drivers/base/Makefile          |    1 +
 drivers/base/dma-buf.c         |    5 +
 drivers/base/dmabuf-sync.c     |  951 ++++++++++++++++++++++++++++++++++++++++
 include/linux/dma-buf.h        |   16 +
 include/linux/dmabuf-sync.h    |  257 +++++++++++
 7 files changed, 1523 insertions(+)
 create mode 100644 Documentation/dma-buf-sync.txt
 create mode 100644 drivers/base/dmabuf-sync.c
 create mode 100644 include/linux/dmabuf-sync.h

diff --git a/Documentation/dma-buf-sync.txt b/Documentation/dma-buf-sync.txt
new file mode 100644
index 0000000..5945c8a
--- /dev/null
+++ b/Documentation/dma-buf-sync.txt
@@ -0,0 +1,286 @@
+                    DMA Buffer Synchronization Framework
+                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                                  Inki Dae
+                      <inki dot dae at samsung dot com>
+                          <daeinki at gmail dot com>
+
+This document is a guide for device-driver writers describing the DMA buffer
+synchronization API. This document also describes how to use the API to
+use buffer synchronization mechanism between DMA and DMA, CPU and DMA, and
+CPU and CPU.
+
+The DMA Buffer synchronization API provides buffer synchronization mechanism;
+i.e., buffer access control to CPU and DMA, and easy-to-use interfaces for
+device drivers and user application. And this API can be used for all dma
+devices using system memory as dma buffer, especially for most ARM based SoCs.
+
+
+Motivation
+----------
+
+Buffer synchronization issue between DMA and DMA:
+	Sharing a buffer, a device cannot be aware of when the other device
+	will access the shared buffer: a device may access a buffer containing
+	wrong data if the device accesses the shared buffer while another
+	device is still accessing the shared buffer.
+	Therefore, a user process should have waited for the completion of DMA
+	access by another device before a device tries to access the shared
+	buffer.
+
+Buffer synchronization issue between CPU and DMA:
+	A user process should consider that when having to send a buffer, filled
+	by CPU, to a device driver for the device driver to access the buffer as
+	a input buffer while CPU and DMA are sharing the buffer.
+	This means that the user process needs to understand how the device
+	driver is worked. Hence, the conventional mechanism not only makes
+	user application complicated but also incurs performance overhead.
+
+Buffer synchronization issue between CPU and CPU:
+	In case that two processes share one buffer; shared with DMA also,
+	they may need some mechanism to allow process B to access the shared
+	buffer after the completion of CPU access by process A.
+	Therefore, process B should have waited for the completion of CPU access
+	by process A using the mechanism before trying to access the shared
+	buffer.
+
+What is the best way to solve these buffer synchronization issues?
+	We may need a common object that a device driver and a user process
+	notify the common object of when they try to access a shared buffer.
+	That way we could decide when we have to allow or not to allow for CPU
+	or DMA to access the shared buffer through the common object.
+	If so, what could become the common object? Right, that's a dma-buf[1].
+	Now we have already been using the dma-buf to share one buffer with
+	other drivers.
+
+
+Basic concept
+-------------
+
+The mechanism of this framework has the following steps,
+    1. Register dmabufs to a sync object - A task gets a new sync object and
+    can add one or more dmabufs that the task wants to access.
+    This registering should be performed when a device context or an event
+    context such as a page flip event is created or before CPU accesses a shared
+    buffer.
+
+	dma_buf_sync_get(a sync object, a dmabuf);
+
+    2. Lock a sync object - A task tries to lock all dmabufs added in its own
+    sync object. Basically, the lock mechanism uses ww-mutexes[2] to avoid dead
+    lock issue and for race condition between CPU and CPU, CPU and DMA, and DMA
+    and DMA. Taking a lock means that others cannot access all locked dmabufs
+    until the task that locked the corresponding dmabufs, unlocks all the locked
+    dmabufs.
+    This locking should be performed before DMA or CPU accesses these dmabufs.
+
+	dma_buf_sync_lock(a sync object);
+
+    3. Unlock a sync object - The task unlocks all dmabufs added in its own sync
+    object. The unlock means that the DMA or CPU accesses to the dmabufs have
+    been completed so that others may access them.
+    This unlocking should be performed after DMA or CPU has completed accesses
+    to the dmabufs.
+
+	dma_buf_sync_unlock(a sync object);
+
+    4. Unregister one or all dmabufs from a sync object - A task unregisters
+    the given dmabufs from the sync object. This means that the task dosen't
+    want to lock the dmabufs.
+    The unregistering should be performed after DMA or CPU has completed
+    accesses to the dmabufs or when dma_buf_sync_lock() is failed.
+
+	dma_buf_sync_put(a sync object, a dmabuf);
+	dma_buf_sync_put_all(a sync object);
+
+    The described steps may be summarized as:
+	get -> lock -> CPU or DMA access to a buffer/s -> unlock -> put
+
+This framework includes the following two features.
+    1. read (shared) and write (exclusive) locks - A task is required to declare
+    the access type when the task tries to register a dmabuf;
+    READ, WRITE, READ DMA, or WRITE DMA.
+
+    The below is example codes,
+	struct dmabuf_sync *sync;
+
+	sync = dmabuf_sync_init(NULL, "test sync");
+
+	dmabuf_sync_get(sync, dmabuf, DMA_BUF_ACCESS_R);
+	...
+
+    2. Mandatory resource releasing - a task cannot hold a lock indefinitely.
+    A task may never try to unlock a buffer after taking a lock to the buffer.
+    In this case, a timer handler to the corresponding sync object is called
+    in five (default) seconds and then the timed-out buffer is unlocked by work
+    queue handler to avoid lockups and to enforce resources of the buffer.
+
+
+Access types
+------------
+
+DMA_BUF_ACCESS_R - CPU will access a buffer for read.
+DMA_BUF_ACCESS_W - CPU will access a buffer for read or write.
+DMA_BUF_ACCESS_DMA_R - DMA will access a buffer for read
+DMA_BUF_ACCESS_DMA_W - DMA will access a buffer for read or write.
+
+
+Generic user interfaces
+-----------------------
+
+And this framework includes fcntl[3] and select system calls as interfaces
+exported to user. As you know, user sees a buffer object as a dma-buf file
+descriptor. fcntl() call with the file descriptor means to lock some buffer
+region being managed by the dma-buf object. And select call with the file
+descriptor means to poll the completion event of CPU or DMA access to
+the dma-buf.
+
+
+API set
+-------
+
+bool is_dmabuf_sync_supported(void)
+	- Check if dmabuf sync is supported or not.
+
+struct dmabuf_sync *dmabuf_sync_init(const char *name,
+					struct dmabuf_sync_priv_ops *ops,
+					void priv*)
+	- Allocate and initialize a new sync object. The caller can get a new
+	sync object for buffer synchronization. ops is used for device driver
+	to clean up its own sync object. For this, each device driver should
+	implement a free callback. priv is used for device driver to get its
+	device context when free callback is called.
+
+void dmabuf_sync_fini(struct dmabuf_sync *sync)
+	- Release all resources to the sync object.
+
+int dmabuf_sync_get(struct dmabuf_sync *sync, void *sync_buf,
+			unsigned int type)
+	- Get dmabuf sync object. Internally, this function allocates
+	a dmabuf_sync object and adds a given dmabuf to it, and also takes
+	a reference to the dmabuf. The caller can tie up multiple dmabufs
+	into one sync object by calling this function several times.
+
+void dmabuf_sync_put(struct dmabuf_sync *sync, struct dma_buf *dmabuf)
+	- Put dmabuf sync object to a given dmabuf. Internally, this function
+	removes a given dmabuf from a sync object and remove the sync object.
+	At this time, the dmabuf is putted.
+
+void dmabuf_sync_put_all(struct dmabuf_sync *sync)
+	- Put dmabuf sync object to dmabufs. Internally, this function removes
+	all dmabufs from a sync object and remove the sync object.
+	At this time, all dmabufs are putted.
+
+int dmabuf_sync_lock(struct dmabuf_sync *sync)
+	- Lock all dmabufs added in a sync object. The caller should call this
+	function prior to CPU or DMA access to the dmabufs so that others can
+	not access the dmabufs. Internally, this function avoids dead lock
+	issue with ww-mutexes.
+
+int dmabuf_sync_single_lock(struct dma_buf *dmabuf)
+	- Lock a dmabuf. The caller should call this
+	function prior to CPU or DMA access to the dmabuf so that others can
+	not access the dmabuf.
+
+int dmabuf_sync_unlock(struct dmabuf_sync *sync)
+	- Unlock all dmabufs added in a sync object. The caller should call
+	this function after CPU or DMA access to the dmabufs is completed so
+	that others can access the dmabufs.
+
+void dmabuf_sync_single_unlock(struct dma_buf *dmabuf)
+	- Unlock a dmabuf. The caller should call this function after CPU or
+	DMA access to the dmabuf is completed so that others can access
+	the dmabuf.
+
+
+Tutorial for device driver
+--------------------------
+
+1. Allocate and Initialize a sync object:
+	static void xxx_dmabuf_sync_free(void *priv)
+	{
+		struct xxx_context *ctx = priv;
+
+		if (!ctx)
+			return;
+
+		ctx->sync = NULL;
+	}
+	...
+
+	static struct dmabuf_sync_priv_ops driver_specific_ops = {
+		.free = xxx_dmabuf_sync_free,
+	};
+	...
+
+	struct dmabuf_sync *sync;
+
+	sync = dmabuf_sync_init("test sync", &driver_specific_ops, ctx);
+	...
+
+2. Add a dmabuf to the sync object when setting up dma buffer relevant registers:
+	dmabuf_sync_get(sync, dmabuf, DMA_BUF_ACCESS_READ);
+	...
+
+3. Lock all dmabufs of the sync object before DMA or CPU accesses the dmabufs:
+	dmabuf_sync_lock(sync);
+	...
+
+4. Now CPU or DMA can access all dmabufs locked in step 3.
+
+5. Unlock all dmabufs added in a sync object after DMA or CPU access to these
+   dmabufs is completed:
+	dmabuf_sync_unlock(sync);
+
+   And call the following functions to release all resources,
+	dmabuf_sync_put_all(sync);
+	dmabuf_sync_fini(sync);
+
+
+Tutorial for user application
+-----------------------------
+fcntl system call:
+
+	struct flock filelock;
+
+1. Lock a dma buf:
+	filelock.l_type = F_WRLCK or F_RDLCK;
+
+	/* lock entire region to the dma buf. */
+	filelock.lwhence = SEEK_CUR;
+	filelock.l_start = 0;
+	filelock.l_len = 0;
+
+	fcntl(dmabuf fd, F_SETLKW or F_SETLK, &filelock);
+	...
+	CPU access to the dma buf
+
+2. Unlock a dma buf:
+	filelock.l_type = F_UNLCK;
+
+	fcntl(dmabuf fd, F_SETLKW or F_SETLK, &filelock);
+
+	close(dmabuf fd) call would also unlock the dma buf. And for more
+	detail, please refer to [3]
+
+
+select system call:
+
+	fd_set wdfs or rdfs;
+
+	FD_ZERO(&wdfs or &rdfs);
+	FD_SET(fd, &wdfs or &rdfs);
+
+	select(fd + 1, &rdfs, NULL, NULL, NULL);
+		or
+	select(fd + 1, NULL, &wdfs, NULL, NULL);
+
+	Every time select system call is called, a caller will wait for
+	the completion of DMA or CPU access to a shared buffer if there
+	is someone accessing the shared buffer. If no anyone then select
+	system call will be returned at once.
+
+References:
+[1] http://lwn.net/Articles/470339/
+[2] https://patchwork.kernel.org/patch/2625361/
+[3] http://linux.die.net/man/2/fcntl
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index e373671..23e0fbf 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -200,6 +200,13 @@ config DMA_SHARED_BUFFER
 	  APIs extension; the file's descriptor can then be passed on to other
 	  driver.
 
+config DMABUF_SYNC
+	bool "DMABUF Synchronization Framework"
+	depends on DMA_SHARED_BUFFER
+	help
+	  This option enables dmabuf sync framework for buffer synchronization between
+	  DMA and DMA, CPU and DMA, and CPU and CPU.
+
 config DMA_CMA
 	bool "DMA Contiguous Memory Allocator"
 	depends on HAVE_DMA_CONTIGUOUS && CMA
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 94e8a80..e88d9b8 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -11,6 +11,7 @@ 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 reservation.o
+obj-$(CONFIG_DMABUF_SYNC) += dmabuf-sync.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 1e16cbd..3985751 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -29,6 +29,7 @@
 #include <linux/export.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <linux/dmabuf-sync.h>
 
 static inline int is_dma_buf_file(struct file *);
 
@@ -56,6 +57,8 @@ static int dma_buf_release(struct inode *inode, struct file *file)
 	list_del(&dmabuf->list_node);
 	mutex_unlock(&db_list.lock);
 
+	dmabuf_sync_reservation_fini(dmabuf);
+
 	kfree(dmabuf);
 	return 0;
 }
@@ -168,6 +171,8 @@ struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops,
 	file->f_mode |= FMODE_LSEEK;
 	dmabuf->file = file;
 
+	dmabuf_sync_reservation_init(dmabuf);
+
 	mutex_init(&dmabuf->lock);
 	INIT_LIST_HEAD(&dmabuf->attachments);
 
diff --git a/drivers/base/dmabuf-sync.c b/drivers/base/dmabuf-sync.c
new file mode 100644
index 0000000..b954865
--- /dev/null
+++ b/drivers/base/dmabuf-sync.c
@@ -0,0 +1,951 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics Co.Ltd
+ * Authors:
+ *	Inki Dae <inki.dae@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#include <linux/dmabuf-sync.h>
+
+#define MAX_SYNC_TIMEOUT	5	/* Second. */
+#define MAX_WAIT_TIMEOUT	2000	/* Millisecond. */
+
+#define WAKE_UP_SYNC_OBJ(obj) {			\
+		if (obj->waiting) {		\
+			obj->waiting = false;	\
+			wake_up(&obj->wq);	\
+		}				\
+	}
+
+#define DEL_OBJ_FROM_RSV(obj, rsv) {					\
+		struct dmabuf_sync_object *e, *n;			\
+									\
+		list_for_each_entry_safe(e, n, &rsv->syncs, r_head) {	\
+			if (e = obj && !e->task) {			\
+				list_del_init(&e->r_head);		\
+				break;					\
+			}						\
+		}							\
+}
+
+int dmabuf_sync_enabled = 1;
+
+MODULE_PARM_DESC(enabled, "Check if dmabuf sync is supported or not");
+module_param_named(enabled, dmabuf_sync_enabled, int, 0444);
+
+DEFINE_WW_CLASS(dmabuf_sync_ww_class);
+EXPORT_SYMBOL_GPL(dmabuf_sync_ww_class);
+
+static void dmabuf_sync_timeout_worker(struct work_struct *work)
+{
+	struct dmabuf_sync *sync = container_of(work, struct dmabuf_sync, work);
+	struct dmabuf_sync_object *sobj;
+
+	mutex_lock(&sync->lock);
+
+	list_for_each_entry(sobj, &sync->syncs, head) {
+		struct dmabuf_sync_reservation *rsvp = sobj->robj;
+
+		mutex_lock(&rsvp->lock);
+
+		pr_warn("%s: timeout = 0x%p [type = %d:%d, "
+					"refcnt = %d, locked = %d]\n",
+					sync->name, sobj->dmabuf,
+					rsvp->accessed_type,
+					sobj->access_type,
+					atomic_read(&rsvp->shared_cnt),
+					rsvp->locked);
+
+		if (rsvp->polled) {
+			rsvp->poll_event = true;
+			rsvp->polled = false;
+			wake_up_interruptible(&rsvp->poll_wait);
+		}
+
+		/*
+		 * Wake up a task blocked by dmabuf_sync_wait_prev_objs().
+		 *
+		 * If sobj->waiting is true, the task is waiting for the wake
+		 * up event so wake up the task if a given time period is
+		 * elapsed and current task is timed out.
+		 */
+		WAKE_UP_SYNC_OBJ(sobj);
+
+		/* Delete a sync object from reservation object of dmabuf. */
+		DEL_OBJ_FROM_RSV(sobj, rsvp);
+
+		if (atomic_add_unless(&rsvp->shared_cnt, -1, 1)) {
+			mutex_unlock(&rsvp->lock);
+			continue;
+		}
+
+		/* unlock only valid sync object. */
+		if (!rsvp->locked) {
+			mutex_unlock(&rsvp->lock);
+			continue;
+		}
+
+		mutex_unlock(&rsvp->lock);
+		ww_mutex_unlock(&rsvp->sync_lock);
+
+		mutex_lock(&rsvp->lock);
+		rsvp->locked = false;
+
+		if (sobj->access_type & DMA_BUF_ACCESS_R)
+			pr_warn("%s: r-unlocked = 0x%p\n",
+					sync->name, sobj->dmabuf);
+		else
+			pr_warn("%s: w-unlocked = 0x%p\n",
+					sync->name, sobj->dmabuf);
+
+		mutex_unlock(&rsvp->lock);
+	}
+
+	sync->status = 0;
+	mutex_unlock(&sync->lock);
+
+	dmabuf_sync_put_all(sync);
+	dmabuf_sync_fini(sync);
+}
+
+static void dmabuf_sync_lock_timeout(unsigned long arg)
+{
+	struct dmabuf_sync *sync = (struct dmabuf_sync *)arg;
+
+	schedule_work(&sync->work);
+}
+
+static void dmabuf_sync_wait_prev_objs(struct dmabuf_sync_object *sobj,
+					struct dmabuf_sync_reservation *rsvp,
+					struct ww_acquire_ctx *ctx)
+{
+	mutex_lock(&rsvp->lock);
+
+	/*
+	 * This function handles the write-and-then-read ordering issue.
+	 *
+	 * The ordering issue:
+	 * There is a case that a task don't take a lock to a dmabuf so
+	 * this task would be stalled even though this task requested a lock
+	 * to the dmabuf between other task unlocked and tries to lock
+	 * the dmabuf again.
+	 *
+	 * How to handle the ordering issue:
+	 * 1. Check if there is a sync object added prior to current task's one.
+	 * 2. If exists, it unlocks the dmabuf so that other task can take
+	 *	a lock to the dmabuf first.
+	 * 3. Wait for the wake up event from other task: current task will be
+	 *	waked up when other task unlocks the dmabuf.
+	 * 4. Take a lock to the dmabuf again.
+	 */
+	if (!list_empty(&rsvp->syncs)) {
+		struct dmabuf_sync_object *r_sobj, *next;
+
+		list_for_each_entry_safe(r_sobj, next, &rsvp->syncs,
+					r_head) {
+			long timeout;
+
+			/*
+			 * Find a sync object added to rsvp->syncs by other task
+			 * before current task tries to lock the dmabuf again.
+			 * If sobj = r_sobj, it means that there is no any task
+			 * that added its own sync object to rsvp->syncs so out
+			 * of this loop.
+			 */
+			if (sobj = r_sobj)
+				break;
+
+			/*
+			 * Unlock the dmabuf if there is a sync object added
+			 * to rsvp->syncs so that other task can take a lock
+			 * first.
+			 */
+			if (rsvp->locked) {
+				ww_mutex_unlock(&rsvp->sync_lock);
+				rsvp->locked = false;
+			}
+
+			r_sobj->waiting = true;
+
+			atomic_inc(&r_sobj->refcnt);
+			mutex_unlock(&rsvp->lock);
+
+			/* Wait for the wake up event from other task. */
+			timeout = wait_event_timeout(r_sobj->wq,
+					!r_sobj->waiting,
+					msecs_to_jiffies(MAX_WAIT_TIMEOUT));
+			if (!timeout) {
+				r_sobj->waiting = false;
+				pr_warn("wait event timeout: sobj = 0x%p\n",
+						r_sobj);
+
+				/*
+				 * A sync object from fcntl system call has no
+				 * timeout handler so delete ane free r_sobj
+				 * once timeout here without checking refcnt.
+				 */
+				if (r_sobj->task) {
+					list_del_init(&r_sobj->r_head);
+					kfree(r_sobj);
+				}
+			}
+
+			if (!atomic_add_unless(&r_sobj->refcnt, -1, 1))
+				kfree(r_sobj);
+
+			/*
+			 * Other task unlocked the dmabuf so take a lock again.
+			 */
+			ww_mutex_lock(&rsvp->sync_lock, ctx);
+
+			mutex_lock(&rsvp->lock);
+			rsvp->locked = true;
+		}
+	}
+
+	mutex_unlock(&rsvp->lock);
+}
+
+static int dmabuf_sync_lock_objs(struct dmabuf_sync *sync,
+					struct ww_acquire_ctx *ctx)
+{
+	struct dmabuf_sync_object *contended_sobj = NULL;
+	struct dmabuf_sync_object *res_sobj = NULL;
+	struct dmabuf_sync_object *sobj = NULL;
+	int ret;
+
+	if (ctx)
+		ww_acquire_init(ctx, &dmabuf_sync_ww_class);
+
+retry:
+	list_for_each_entry(sobj, &sync->syncs, head) {
+		struct dmabuf_sync_reservation *rsvp = sobj->robj;
+
+		if (WARN_ON(!rsvp))
+			continue;
+
+		mutex_lock(&rsvp->lock);
+
+		/*
+		 * Add a sync object to reservation object of dmabuf
+		 * to handle the write-and-then-read ordering issue.
+		 *
+		 * For more details, see dmabuf_sync_wait_prev_objs function.
+		 */
+		list_add_tail(&sobj->r_head, &rsvp->syncs);
+
+		/* Don't lock in case of read and read. */
+		if (rsvp->accessed_type & DMA_BUF_ACCESS_R &&
+		    sobj->access_type & DMA_BUF_ACCESS_R) {
+			atomic_inc(&rsvp->shared_cnt);
+			mutex_unlock(&rsvp->lock);
+			continue;
+		}
+
+		if (sobj = res_sobj) {
+			res_sobj = NULL;
+			mutex_unlock(&rsvp->lock);
+			continue;
+		}
+
+		mutex_unlock(&rsvp->lock);
+
+		ret = ww_mutex_lock(&rsvp->sync_lock, ctx);
+		if (ret < 0) {
+			contended_sobj = sobj;
+
+			if (ret = -EDEADLK)
+				pr_warn("%s: deadlock = 0x%p\n",
+					sync->name, sobj->dmabuf);
+			goto err;
+		}
+
+		mutex_lock(&rsvp->lock);
+		rsvp->locked = true;
+
+		mutex_unlock(&rsvp->lock);
+
+		/*
+		 * Check if there is a sync object added to reservation object
+		 * of dmabuf before current task takes a lock to the dmabuf.
+		 * And ithen wait for the for the wake up event from other task
+		 * if exists.
+		 */
+		dmabuf_sync_wait_prev_objs(sobj, rsvp, ctx);
+	}
+
+	if (ctx)
+		ww_acquire_done(ctx);
+
+	init_timer(&sync->timer);
+
+	sync->timer.data = (unsigned long)sync;
+	sync->timer.function = dmabuf_sync_lock_timeout;
+	sync->timer.expires = jiffies + (HZ * MAX_SYNC_TIMEOUT);
+
+	add_timer(&sync->timer);
+
+	return 0;
+
+err:
+	list_for_each_entry_continue_reverse(sobj, &sync->syncs, head) {
+		struct dmabuf_sync_reservation *rsvp = sobj->robj;
+
+		mutex_lock(&rsvp->lock);
+
+		/* Don't need to unlock in case of read and read. */
+		if (atomic_add_unless(&rsvp->shared_cnt, -1, 1)) {
+			mutex_unlock(&rsvp->lock);
+			continue;
+		}
+
+		/*
+		 * Delete a sync object from reservation object of dmabuf.
+		 *
+		 * The sync object was added to reservation object of dmabuf
+		 * just before ww_mutex_lock() is called.
+		 */
+		DEL_OBJ_FROM_RSV(sobj, rsvp);
+		mutex_unlock(&rsvp->lock);
+
+		ww_mutex_unlock(&rsvp->sync_lock);
+
+		mutex_lock(&rsvp->lock);
+		rsvp->locked = false;
+		mutex_unlock(&rsvp->lock);
+	}
+
+	if (res_sobj) {
+		struct dmabuf_sync_reservation *rsvp = res_sobj->robj;
+
+		mutex_lock(&rsvp->lock);
+
+		if (!atomic_add_unless(&rsvp->shared_cnt, -1, 1)) {
+			/*
+			 * Delete a sync object from reservation object
+			 * of dmabuf.
+			 */
+			DEL_OBJ_FROM_RSV(sobj, rsvp);
+			mutex_unlock(&rsvp->lock);
+
+			ww_mutex_unlock(&rsvp->sync_lock);
+
+			mutex_lock(&rsvp->lock);
+			rsvp->locked = false;
+		}
+
+		mutex_unlock(&rsvp->lock);
+	}
+
+	if (ret = -EDEADLK) {
+		ww_mutex_lock_slow(&contended_sobj->robj->sync_lock, ctx);
+		res_sobj = contended_sobj;
+
+		goto retry;
+	}
+
+	if (ctx)
+		ww_acquire_fini(ctx);
+
+	return ret;
+}
+
+static void dmabuf_sync_unlock_objs(struct dmabuf_sync *sync,
+					struct ww_acquire_ctx *ctx)
+{
+	struct dmabuf_sync_object *sobj;
+
+	if (list_empty(&sync->syncs))
+		return;
+
+	mutex_lock(&sync->lock);
+
+	list_for_each_entry(sobj, &sync->syncs, head) {
+		struct dmabuf_sync_reservation *rsvp = sobj->robj;
+
+		mutex_lock(&rsvp->lock);
+
+		if (rsvp->polled) {
+			rsvp->poll_event = true;
+			rsvp->polled = false;
+			wake_up_interruptible(&rsvp->poll_wait);
+		}
+
+		/*
+		 * Wake up a task blocked by dmabuf_sync_wait_prev_objs().
+		 *
+		 * If sobj->waiting is true, the task is waiting for wake_up
+		 * call. So wake up the task if a given time period was
+		 * elapsed so current task was timed out.
+		 */
+		WAKE_UP_SYNC_OBJ(sobj);
+
+		/* Delete a sync object from reservation object of dmabuf. */
+		DEL_OBJ_FROM_RSV(sobj, rsvp);
+
+		if (atomic_add_unless(&rsvp->shared_cnt, -1, 1)) {
+			mutex_unlock(&rsvp->lock);
+			continue;
+		}
+
+		mutex_unlock(&rsvp->lock);
+
+		ww_mutex_unlock(&rsvp->sync_lock);
+
+		mutex_lock(&rsvp->lock);
+		rsvp->locked = false;
+		mutex_unlock(&rsvp->lock);
+	}
+
+	mutex_unlock(&sync->lock);
+
+	if (ctx)
+		ww_acquire_fini(ctx);
+
+	del_timer(&sync->timer);
+}
+
+/**
+ * dmabuf_sync_is_supported - Check if dmabuf sync is supported or not.
+ */
+bool dmabuf_sync_is_supported(void)
+{
+	return dmabuf_sync_enabled = 1;
+}
+EXPORT_SYMBOL_GPL(dmabuf_sync_is_supported);
+
+/**
+ * dmabuf_sync_init - Allocate and initialize a dmabuf sync.
+ *
+ * @priv: A device private data.
+ * @name: A sync object name.
+ *
+ * This function should be called when a device context or an event
+ * context such as a page flip event is created. And the created
+ * dmabuf_sync object should be set to the context.
+ * The caller can get a new sync object for buffer synchronization
+ * through this function.
+ */
+struct dmabuf_sync *dmabuf_sync_init(const char *name,
+					struct dmabuf_sync_priv_ops *ops,
+					void *priv)
+{
+	struct dmabuf_sync *sync;
+
+	sync = kzalloc(sizeof(*sync), GFP_KERNEL);
+	if (!sync)
+		return ERR_PTR(-ENOMEM);
+
+	strncpy(sync->name, name, DMABUF_SYNC_NAME_SIZE);
+
+	sync->ops = ops;
+	sync->priv = priv;
+	INIT_LIST_HEAD(&sync->syncs);
+	mutex_init(&sync->lock);
+	INIT_WORK(&sync->work, dmabuf_sync_timeout_worker);
+
+	return sync;
+}
+EXPORT_SYMBOL_GPL(dmabuf_sync_init);
+
+/**
+ * dmabuf_sync_fini - Release a given dmabuf sync.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ *
+ * This function should be called if some operation is failed after
+ * dmabuf_sync_init call to release relevant resources, and after
+ * dmabuf_sync_unlock function is called.
+ */
+void dmabuf_sync_fini(struct dmabuf_sync *sync)
+{
+	struct dmabuf_sync_object *sobj;
+
+	if (WARN_ON(!sync))
+		return;
+
+	if (list_empty(&sync->syncs))
+		goto free_sync;
+
+	list_for_each_entry(sobj, &sync->syncs, head) {
+		struct dmabuf_sync_reservation *rsvp = sobj->robj;
+
+		mutex_lock(&rsvp->lock);
+
+		if (rsvp->locked) {
+			mutex_unlock(&rsvp->lock);
+			ww_mutex_unlock(&rsvp->sync_lock);
+
+			mutex_lock(&rsvp->lock);
+			rsvp->locked = false;
+		}
+
+		mutex_unlock(&rsvp->lock);
+	}
+
+	/*
+	 * If !list_empty(&sync->syncs) then it means that dmabuf_sync_put()
+	 * or dmabuf_sync_put_all() was never called. So unreference all
+	 * dmabuf objects added to sync->syncs, and remove them from the syncs.
+	 */
+	dmabuf_sync_put_all(sync);
+
+free_sync:
+	if (sync->ops && sync->ops->free)
+		sync->ops->free(sync->priv);
+
+	kfree(sync);
+}
+EXPORT_SYMBOL_GPL(dmabuf_sync_fini);
+
+/*
+ * dmabuf_sync_get_obj - Add a given object to sync's list.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ * @dmabuf: An object to dma_buf structure.
+ * @type: A access type to a dma buf.
+ *	The DMA_BUF_ACCESS_R means that this dmabuf could be accessed by
+ *	others for read access. On the other hand, the DMA_BUF_ACCESS_W
+ *	means that this dmabuf couldn't be accessed by others but would be
+ *	accessed by caller's dma exclusively. And the DMA_BUF_ACCESS_DMA can be
+ *	combined.
+ *
+ * This function creates and initializes a new dmabuf sync object and it adds
+ * the dmabuf sync object to syncs list to track and manage all dmabufs.
+ */
+static int dmabuf_sync_get_obj(struct dmabuf_sync *sync, struct dma_buf *dmabuf,
+					unsigned int type)
+{
+	struct dmabuf_sync_object *sobj;
+
+	if (!dmabuf->sync)
+		return -EFAULT;
+
+	if (!IS_VALID_DMA_BUF_ACCESS_TYPE(type))
+		return -EINVAL;
+
+	if ((type & DMA_BUF_ACCESS_RW) = DMA_BUF_ACCESS_RW)
+		type &= ~DMA_BUF_ACCESS_R;
+
+	sobj = kzalloc(sizeof(*sobj), GFP_KERNEL);
+	if (!sobj)
+		return -ENOMEM;
+
+	get_dma_buf(dmabuf);
+
+	sobj->dmabuf = dmabuf;
+	sobj->robj = dmabuf->sync;
+	sobj->access_type = type;
+	atomic_set(&sobj->refcnt, 1);
+	init_waitqueue_head(&sobj->wq);
+
+	mutex_lock(&sync->lock);
+	list_add_tail(&sobj->head, &sync->syncs);
+	mutex_unlock(&sync->lock);
+
+	return 0;
+}
+
+/*
+ * dmabuf_sync_put_obj - Release a given sync object.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ *
+ * This function should be called if some operation failed after
+ * dmabuf_sync_get_obj call to release a given sync object.
+ */
+static void dmabuf_sync_put_obj(struct dmabuf_sync *sync,
+					struct dma_buf *dmabuf)
+{
+	struct dmabuf_sync_object *sobj;
+
+	mutex_lock(&sync->lock);
+
+	list_for_each_entry(sobj, &sync->syncs, head) {
+		if (sobj->dmabuf != dmabuf)
+			continue;
+
+		dma_buf_put(sobj->dmabuf);
+
+		list_del_init(&sobj->head);
+
+		if (!atomic_add_unless(&sobj->refcnt, -1, 1))
+			kfree(sobj);
+		break;
+	}
+
+	if (list_empty(&sync->syncs))
+		sync->status = 0;
+
+	mutex_unlock(&sync->lock);
+}
+
+/*
+ * dmabuf_sync_put_objs - Release all sync objects of dmabuf_sync.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ *
+ * This function should be called if some operation failed after
+ * dmabuf_sync_get_obj call to release all sync objects.
+ */
+static void dmabuf_sync_put_objs(struct dmabuf_sync *sync)
+{
+	struct dmabuf_sync_object *sobj, *next;
+
+	mutex_lock(&sync->lock);
+
+	list_for_each_entry_safe(sobj, next, &sync->syncs, head) {
+		dma_buf_put(sobj->dmabuf);
+
+		list_del_init(&sobj->head);
+
+		if (!atomic_add_unless(&sobj->refcnt, -1, 1))
+			kfree(sobj);
+	}
+
+	mutex_unlock(&sync->lock);
+
+	sync->status = 0;
+}
+
+/**
+ * dmabuf_sync_lock - lock all dmabufs added to syncs list.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ *
+ * The caller should call this function prior to CPU or DMA access to
+ * the dmabufs so that others can not access the dmabufs.
+ * Internally, this function avoids dead lock issue with ww-mutex.
+ */
+int dmabuf_sync_lock(struct dmabuf_sync *sync)
+{
+	int ret;
+
+	if (!sync)
+		return -EFAULT;
+
+	if (list_empty(&sync->syncs))
+		return -EINVAL;
+
+	if (sync->status != DMABUF_SYNC_GOT)
+		return -EINVAL;
+
+	ret = dmabuf_sync_lock_objs(sync, &sync->ctx);
+	if (ret < 0)
+		return ret;
+
+	sync->status = DMABUF_SYNC_LOCKED;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(dmabuf_sync_lock);
+
+/**
+ * dmabuf_sync_unlock - unlock all objects added to syncs list.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ *
+ * The caller should call this function after CPU or DMA access to
+ * the dmabufs is completed so that others can access the dmabufs.
+ */
+int dmabuf_sync_unlock(struct dmabuf_sync *sync)
+{
+	if (!sync)
+		return -EFAULT;
+
+	/* If current dmabuf sync object wasn't reserved then just return. */
+	if (sync->status != DMABUF_SYNC_LOCKED)
+		return -EAGAIN;
+
+	dmabuf_sync_unlock_objs(sync, &sync->ctx);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dmabuf_sync_unlock);
+
+/**
+ * dmabuf_sync_single_lock - lock a dma buf.
+ *
+ * @dmabuf: A dma buf object that tries to lock.
+ * @type: A access type to a dma buf.
+ *	The DMA_BUF_ACCESS_R means that this dmabuf could be accessed by
+ *	others for read access. On the other hand, the DMA_BUF_ACCESS_W
+ *	means that this dmabuf couldn't be accessed by others but would be
+ *	accessed by caller's dma exclusively. And the DMA_BUF_ACCESS_DMA can
+ *	be combined with other.
+ * @wait: Indicate whether caller is blocked or not.
+ *	true means that caller will be blocked, and false means that this
+ *	function will return -EAGAIN if this caller can't take the lock
+ *	right now.
+ *
+ * The caller should call this function prior to CPU or DMA access to the dmabuf
+ * so that others cannot access the dmabuf.
+ */
+int dmabuf_sync_single_lock(struct dma_buf *dmabuf, unsigned int type,
+				bool wait)
+{
+	struct dmabuf_sync_reservation *robj;
+	struct dmabuf_sync_object *sobj;
+
+	if (!dmabuf->sync)
+		return -EFAULT;
+
+	if (!IS_VALID_DMA_BUF_ACCESS_TYPE(type))
+		return -EINVAL;
+
+	get_dma_buf(dmabuf);
+	robj = dmabuf->sync;
+
+	sobj = kzalloc(sizeof(*sobj), GFP_KERNEL);
+	if (!sobj) {
+		dma_buf_put(dmabuf);
+		return -ENOMEM;
+	}
+
+	sobj->dmabuf = dmabuf;
+	sobj->task = (unsigned long)current;
+	atomic_set(&sobj->refcnt, 1);
+	init_waitqueue_head(&sobj->wq);
+
+	mutex_lock(&robj->lock);
+
+	/*
+	 * Add a sync object to reservation object of dmabuf to handle
+	 * the write-and-then-read ordering issue.
+	 */
+	list_add_tail(&sobj->r_head, &robj->syncs);
+
+	/* Don't lock in case of read and read. */
+	if (robj->accessed_type & DMA_BUF_ACCESS_R && type & DMA_BUF_ACCESS_R) {
+		atomic_inc(&robj->shared_cnt);
+		mutex_unlock(&robj->lock);
+		return 0;
+	}
+
+	/*
+	 * In case of F_SETLK, just return -EAGAIN if this dmabuf has already
+	 * been locked.
+	 */
+	if (!wait && robj->locked) {
+		list_del_init(&sobj->r_head);
+		mutex_unlock(&robj->lock);
+		kfree(sobj);
+		dma_buf_put(dmabuf);
+		return -EAGAIN;
+	}
+
+	mutex_unlock(&robj->lock);
+
+	/* Unlocked by dmabuf_sync_single_unlock or dmabuf_sync_unlock. */
+	mutex_lock(&robj->sync_lock.base);
+
+	mutex_lock(&robj->lock);
+	robj->locked = true;
+	mutex_unlock(&robj->lock);
+
+	/*
+	 * Check if there is a sync object added to reservation object of
+	 * dmabuf before current task takes a lock to the dmabuf, and wait
+	 * for the for the wake up event from other task if exists.
+	 */
+	dmabuf_sync_wait_prev_objs(sobj, robj, NULL);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dmabuf_sync_single_lock);
+
+/**
+ * dmabuf_sync_single_unlock - unlock a dma buf.
+ *
+ * @dmabuf: A dma buf object that tries to unlock.
+ *
+ * The caller should call this function after CPU or DMA access to
+ * the dmabuf is completed so that others can access the dmabuf.
+ */
+void dmabuf_sync_single_unlock(struct dma_buf *dmabuf)
+{
+	struct dmabuf_sync_reservation *robj;
+	struct dmabuf_sync_object *sobj, *next;
+
+	if (!dmabuf->sync) {
+		WARN_ON(1);
+		return;
+	}
+
+	robj = dmabuf->sync;
+
+	mutex_lock(&robj->lock);
+
+	if (robj->polled) {
+		robj->poll_event = true;
+		robj->polled = false;
+		wake_up_interruptible(&robj->poll_wait);
+	}
+
+	/*
+	 * Wake up a blocked task/tasks by dmabuf_sync_wait_prev_objs()
+	 * with two steps.
+	 *
+	 * 1. Wake up a task waiting for the wake up event to a sync object
+	 *	of same task, and remove the sync object from reservation
+	 *	object of dmabuf, and then go to out: requested by same task.
+	 * 2. Wait up a task waiting for the wake up event to a sync object
+	 *	of other task, and remove the sync object if not existed
+	 *	at step 1: requested by other task.
+	 *
+	 * The reason, we have to handle it with the above two steps,
+	 * is that fcntl system call is called with a file descriptor so
+	 * kernel side cannot be aware of which sync object of robj->syncs
+	 * should be waked up and deleted at this function.
+	 * So for this, we use the above two steps to find a sync object
+	 * to be waked up.
+	 */
+	list_for_each_entry_safe(sobj, next, &robj->syncs, r_head) {
+		if (sobj->task = (unsigned long)current) {
+			/*
+			 * Wake up a task blocked by
+			 * dmabuf_sync_wait_prev_objs().
+			 */
+			WAKE_UP_SYNC_OBJ(sobj);
+
+			list_del_init(&sobj->r_head);
+
+			if (!atomic_add_unless(&sobj->refcnt, -1, 1))
+				kfree(sobj);
+			goto out;
+		}
+	}
+
+	list_for_each_entry_safe(sobj, next, &robj->syncs, r_head) {
+		if (sobj->task) {
+			/*
+			 * Wake up a task blocked by
+			 * dmabuf_sync_wait_prev_objs().
+			 */
+			WAKE_UP_SYNC_OBJ(sobj);
+
+			list_del_init(&sobj->r_head);
+
+			if (!atomic_add_unless(&sobj->refcnt, -1, 1))
+				kfree(sobj);
+			break;
+		}
+	}
+
+out:
+	if (atomic_add_unless(&robj->shared_cnt, -1 , 1)) {
+		mutex_unlock(&robj->lock);
+		dma_buf_put(dmabuf);
+		return;
+	}
+
+	mutex_unlock(&robj->lock);
+
+	mutex_unlock(&robj->sync_lock.base);
+
+	mutex_lock(&robj->lock);
+	robj->locked = false;
+	mutex_unlock(&robj->lock);
+
+	dma_buf_put(dmabuf);
+
+	return;
+}
+EXPORT_SYMBOL_GPL(dmabuf_sync_single_unlock);
+
+/**
+ * dmabuf_sync_get - Get dmabuf sync object.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ * @sync_buf: A dmabuf object to be synchronized with others.
+ * @type: A access type to a dma buf.
+ *	The DMA_BUF_ACCESS_R means that this dmabuf could be accessed by
+ *	others for read access. On the other hand, the DMA_BUF_ACCESS_W
+ *	means that this dmabuf couldn't be accessed by others but would be
+ *	accessed by caller's dma exclusively. And the DMA_BUF_ACCESS_DMA can
+ *	be combined with other.
+ *
+ * This function should be called after dmabuf_sync_init function is called.
+ * The caller can tie up multiple dmabufs into one sync object by calling this
+ * function several times. Internally, this function allocates
+ * a dmabuf_sync_object and adds a given dmabuf to it, and also takes
+ * a reference to a dmabuf.
+ */
+int dmabuf_sync_get(struct dmabuf_sync *sync, void *sync_buf, unsigned int type)
+{
+	int ret;
+
+	if (!sync || !sync_buf)
+		return -EFAULT;
+
+	ret = dmabuf_sync_get_obj(sync, sync_buf, type);
+	if (ret < 0)
+		return ret;
+
+	sync->status = DMABUF_SYNC_GOT;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dmabuf_sync_get);
+
+/**
+ * dmabuf_sync_put - Put dmabuf sync object to a given dmabuf.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ * @dmabuf: An dmabuf object.
+ *
+ * This function should be called if some operation is failed after
+ * dmabuf_sync_get function is called to release the dmabuf, or
+ * dmabuf_sync_unlock function is called. Internally, this function
+ * removes a given dmabuf from a sync object and remove the sync object.
+ * At this time, the dmabuf is putted.
+ */
+void dmabuf_sync_put(struct dmabuf_sync *sync, struct dma_buf *dmabuf)
+{
+	if (!sync || !dmabuf) {
+		WARN_ON(1);
+		return;
+	}
+
+	if (list_empty(&sync->syncs))
+		return;
+
+	dmabuf_sync_put_obj(sync, dmabuf);
+}
+EXPORT_SYMBOL_GPL(dmabuf_sync_put);
+
+/**
+ * dmabuf_sync_put_all - Put dmabuf sync object to dmabufs.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ *
+ * This function should be called if some operation is failed after
+ * dmabuf_sync_get function is called to release all sync objects, or
+ * dmabuf_sync_unlock function is called. Internally, this function
+ * removes dmabufs from a sync object and remove the sync object.
+ * At this time, all dmabufs are putted.
+ */
+void dmabuf_sync_put_all(struct dmabuf_sync *sync)
+{
+	if (!sync) {
+		WARN_ON(1);
+		return;
+	}
+
+	if (list_empty(&sync->syncs))
+		return;
+
+	dmabuf_sync_put_objs(sync);
+}
+EXPORT_SYMBOL_GPL(dmabuf_sync_put_all);
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index dfac5ed..0109673 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -115,6 +115,7 @@ struct dma_buf_ops {
  * @exp_name: name of the exporter; useful for debugging.
  * @list_node: node for dma_buf accounting and debugging.
  * @priv: exporter specific private data for this buffer object.
+ * @sync: sync object linked to this dma-buf
  */
 struct dma_buf {
 	size_t size;
@@ -128,6 +129,7 @@ struct dma_buf {
 	const char *exp_name;
 	struct list_head list_node;
 	void *priv;
+	void *sync;
 };
 
 /**
@@ -148,6 +150,20 @@ struct dma_buf_attachment {
 	void *priv;
 };
 
+#define	DMA_BUF_ACCESS_R	0x1
+#define DMA_BUF_ACCESS_W	0x2
+#define DMA_BUF_ACCESS_DMA	0x4
+#define DMA_BUF_ACCESS_RW	(DMA_BUF_ACCESS_R | DMA_BUF_ACCESS_W)
+#define DMA_BUF_ACCESS_DMA_R	(DMA_BUF_ACCESS_R | DMA_BUF_ACCESS_DMA)
+#define DMA_BUF_ACCESS_DMA_W	(DMA_BUF_ACCESS_W | DMA_BUF_ACCESS_DMA)
+#define DMA_BUF_ACCESS_DMA_RW	(DMA_BUF_ACCESS_DMA_R | DMA_BUF_ACCESS_DMA_W)
+#define IS_VALID_DMA_BUF_ACCESS_TYPE(t)	(t = DMA_BUF_ACCESS_R || \
+					 t = DMA_BUF_ACCESS_W || \
+					 t = DMA_BUF_ACCESS_DMA_R || \
+					 t = DMA_BUF_ACCESS_DMA_W || \
+					 t = DMA_BUF_ACCESS_RW || \
+					 t = DMA_BUF_ACCESS_DMA_RW)
+
 /**
  * get_dma_buf - convenience wrapper for get_file.
  * @dmabuf:	[in]	pointer to dma_buf
diff --git a/include/linux/dmabuf-sync.h b/include/linux/dmabuf-sync.h
new file mode 100644
index 0000000..fc0bb4e
--- /dev/null
+++ b/include/linux/dmabuf-sync.h
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics Co.Ltd
+ * Authors:
+ *	Inki Dae <inki.dae@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/ww_mutex.h>
+#include <linux/sched.h>
+#include <linux/dma-buf.h>
+
+#define DMABUF_SYNC_NAME_SIZE	64
+
+/*
+ * Status to a dmabuf_sync object.
+ *
+ * @DMABUF_SYNC_GOT: Indicate that one more dmabuf objects have been added
+ *			to a sync's list.
+ * @DMABUF_SYNC_LOCKED: Indicate that all dmabuf objects in a sync's list
+ *			have been locked.
+ */
+enum dmabuf_sync_status {
+	DMABUF_SYNC_GOT		= 1,
+	DMABUF_SYNC_LOCKED,
+};
+
+/*
+ * A structure for dmabuf_sync_reservation.
+ *
+ * @syncs: A list head to sync object and this is global to system.
+ *	This contains sync objects of tasks that requested a lock
+ *	to this dmabuf.
+ * @sync_lock: This provides read or write lock to a dmabuf.
+ *	Except in the below cases, a task will be blocked if the task
+ *	tries to lock a dmabuf for CPU or DMA access when other task
+ *	already locked the dmabuf.
+ *
+ *	Before		After
+ *	--------------------------
+ *	CPU read	CPU read
+ *	CPU read	DMA read
+ *	DMA read	CPU read
+ *	DMA read	DMA read
+ *
+ * @lock: Protecting a dmabuf_sync_reservation object.
+ * @poll_wait: A wait queue object to poll a dmabuf object.
+ * @poll_event: Indicate whether a dmabuf object - being polled -
+ *	was unlocked or not. If true, a blocked task will be out
+ *	of select system call.
+ * @poll: Indicate whether the polling to a dmabuf object was requested
+ *	or not by userspace.
+ * @shared_cnt: Shared count to a dmabuf object.
+ * @accessed_type: Indicate how and who a dmabuf object was accessed by.
+ *	One of the below types could be set.
+ *	DMA_BUF_ACCESS_R -> CPU access for read.
+ *	DMA_BUF_ACCRSS_W -> CPU access for write.
+ *	DMA_BUF_ACCESS_R | DMA_BUF_ACCESS_DMA -> DMA access for read.
+ *	DMA_BUF_ACCESS_W | DMA_BUF_ACCESS_DMA -> DMA access for write.
+ * @locked: Indicate whether a dmabuf object has been locked or not.
+ *
+ */
+struct dmabuf_sync_reservation {
+	struct list_head	syncs;
+	struct ww_mutex		sync_lock;
+	struct mutex		lock;
+	wait_queue_head_t	poll_wait;
+	unsigned int		poll_event;
+	unsigned int		polled;
+	atomic_t		shared_cnt;
+	unsigned int		accessed_type;
+	unsigned int		locked;
+};
+
+/*
+ * A structure for dmabuf_sync_object.
+ *
+ * @head: A list head to be added to dmabuf_sync's syncs.
+ * @r_head: A list head to be added to dmabuf_sync_reservation's syncs.
+ * @robj: A reservation_object object.
+ * @dma_buf: A dma_buf object.
+ * @task: An address value to current task.
+ *	This is used to indicate who is a owner of a sync object.
+ * @wq: A wait queue head.
+ *	This is used to guarantee that a task can take a lock to a dmabuf
+ *	if the task requested a lock to the dmabuf prior to other task.
+ *	For more details, see dmabuf_sync_wait_prev_objs function.
+ * @refcnt: A reference count to a sync object.
+ * @access_type: Indicate how a current task tries to access
+ *	a given buffer, and one of the below types could be set.
+ *	DMA_BUF_ACCESS_R -> CPU access for read.
+ *	DMA_BUF_ACCRSS_W -> CPU access for write.
+ *	DMA_BUF_ACCESS_R | DMA_BUF_ACCESS_DMA -> DMA access for read.
+ *	DMA_BUF_ACCESS_W | DMA_BUF_ACCESS_DMA -> DMA access for write.
+ * @waiting: Indicate whether current task is waiting for the wake up event
+ *	from other task or not.
+ */
+struct dmabuf_sync_object {
+	struct list_head		head;
+	struct list_head		r_head;
+	struct dmabuf_sync_reservation	*robj;
+	struct dma_buf			*dmabuf;
+	unsigned long			task;
+	wait_queue_head_t		wq;
+	atomic_t			refcnt;
+	unsigned int			access_type;
+	unsigned int			waiting;
+};
+
+struct dmabuf_sync_priv_ops {
+	void (*free)(void *priv);
+};
+
+/*
+ * A structure for dmabuf_sync.
+ *
+ * @syncs: A list head to sync object and this is global to system.
+ *	This contains sync objects of dmabuf_sync owner.
+ * @list: A list entry used as committed list node
+ * @lock: Protecting a dmabuf_sync object.
+ * @ctx: A current context for ww mutex.
+ * @work: A work struct to release resources at timeout.
+ * @priv: A private data.
+ * @name: A string to dmabuf sync owner.
+ * @timer: A timer list to avoid lockup and release resources.
+ * @status: Indicate current status (DMABUF_SYNC_GOT or DMABUF_SYNC_LOCKED).
+ */
+struct dmabuf_sync {
+	struct list_head		syncs;
+	struct list_head		list;
+	struct mutex			lock;
+	struct ww_acquire_ctx		ctx;
+	struct work_struct		work;
+	void				*priv;
+	struct dmabuf_sync_priv_ops	*ops;
+	char				name[DMABUF_SYNC_NAME_SIZE];
+	struct timer_list		timer;
+	unsigned int			status;
+};
+
+#ifdef CONFIG_DMABUF_SYNC
+
+extern struct ww_class dmabuf_sync_ww_class;
+
+static inline void dmabuf_sync_reservation_init(struct dma_buf *dmabuf)
+{
+	struct dmabuf_sync_reservation *obj;
+
+	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+	if (!obj)
+		return;
+
+	dmabuf->sync = obj;
+
+	ww_mutex_init(&obj->sync_lock, &dmabuf_sync_ww_class);
+
+	mutex_init(&obj->lock);
+	atomic_set(&obj->shared_cnt, 1);
+	INIT_LIST_HEAD(&obj->syncs);
+
+	init_waitqueue_head(&obj->poll_wait);
+}
+
+static inline void dmabuf_sync_reservation_fini(struct dma_buf *dmabuf)
+{
+	struct dmabuf_sync_reservation *obj;
+
+	if (!dmabuf->sync)
+		return;
+
+	obj = dmabuf->sync;
+
+	ww_mutex_destroy(&obj->sync_lock);
+
+	kfree(obj);
+}
+
+bool dmabuf_sync_is_supported(void);
+
+struct dmabuf_sync *dmabuf_sync_init(const char *name,
+					struct dmabuf_sync_priv_ops *ops,
+					void *priv);
+
+void dmabuf_sync_fini(struct dmabuf_sync *sync);
+
+int dmabuf_sync_lock(struct dmabuf_sync *sync);
+
+int dmabuf_sync_unlock(struct dmabuf_sync *sync);
+
+int dmabuf_sync_single_lock(struct dma_buf *dmabuf, unsigned int type,
+				bool wait);
+
+void dmabuf_sync_single_unlock(struct dma_buf *dmabuf);
+
+int dmabuf_sync_get(struct dmabuf_sync *sync, void *sync_buf,
+				unsigned int type);
+
+void dmabuf_sync_put(struct dmabuf_sync *sync, struct dma_buf *dmabuf);
+
+void dmabuf_sync_put_all(struct dmabuf_sync *sync);
+
+#else
+
+static inline void dmabuf_sync_reservation_init(struct dma_buf *dmabuf) { }
+
+static inline void dmabuf_sync_reservation_fini(struct dma_buf *dmabuf) { }
+
+static inline bool dmabuf_sync_is_supported(void) { return false; }
+
+static inline  struct dmabuf_sync *dmabuf_sync_init(const char *name,
+					struct dmabuf_sync_priv_ops *ops,
+					void *priv)
+{
+	return ERR_PTR(0);
+}
+
+static inline void dmabuf_sync_fini(struct dmabuf_sync *sync) { }
+
+static inline int dmabuf_sync_lock(struct dmabuf_sync *sync)
+{
+	return 0;
+}
+
+static inline int dmabuf_sync_unlock(struct dmabuf_sync *sync)
+{
+	return 0;
+}
+
+static inline int dmabuf_sync_single_lock(struct dma_buf *dmabuf,
+						unsigned int type,
+						bool wait)
+{
+	return 0;
+}
+
+static inline void dmabuf_sync_single_unlock(struct dma_buf *dmabuf)
+{
+	return;
+}
+
+static inline int dmabuf_sync_get(struct dmabuf_sync *sync,
+					void *sync_buf,
+					unsigned int type)
+{
+	return 0;
+}
+
+static inline void dmabuf_sync_put(struct dmabuf_sync *sync,
+					struct dma_buf *dmabuf) { }
+
+static inline void dmabuf_sync_put_all(struct dmabuf_sync *sync) { }
+
+#endif
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 2/2] dma-buf: Add user interfaces for dmabuf sync support
From: Inki Dae @ 2013-09-17 12:23 UTC (permalink / raw)
  To: dri-devel, linux-fbdev, linux-arm-kernel, linux-media,
	linaro-kernel
  Cc: Roger.Teague, jesse.barker, jesse.barker, maarten.lankhorst,
	sumit.semwal, kyungmin.park, myungjoo.ham, Inki Dae
In-Reply-To: <1379420616-9194-1-git-send-email-inki.dae@samsung.com>

This patch adds lock and poll callbacks to dma buf file operations,
and these callbacks will be called by fcntl and select system calls.

fcntl and select system calls can be used to wait for the completion
of DMA or CPU access to a shared dmabuf. The difference of them is
fcntl system call takes a lock after the completion but select system
call doesn't. So in case of fcntl system call, it's useful when a task
wants to access a shared dmabuf without any broken. On the other hand,
it's useful when a task wants to just wait for the completion.

Changelog v2:
- Add select system call support.
  . The purpose of this feature is to wait for the completion of DMA or
    CPU access to a dmabuf without that caller locks the dmabuf again
    after the completion.
    That is useful when caller wants to be aware of the completion of
    DMA access to the dmabuf, and the caller doesn't use intefaces for
    the DMA device driver.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/base/dma-buf.c |   81 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index 3985751..73234ba 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -29,6 +29,7 @@
 #include <linux/export.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <linux/poll.h>
 #include <linux/dmabuf-sync.h>
 
 static inline int is_dma_buf_file(struct file *);
@@ -106,10 +107,90 @@ static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence)
 	return base + offset;
 }
 
+static unsigned int dma_buf_poll(struct file *filp,
+					struct poll_table_struct *poll)
+{
+	struct dma_buf *dmabuf;
+	struct dmabuf_sync_reservation *robj;
+	int ret = 0;
+
+	if (!is_dma_buf_file(filp))
+		return POLLERR;
+
+	dmabuf = filp->private_data;
+	if (!dmabuf || !dmabuf->sync)
+		return POLLERR;
+
+	robj = dmabuf->sync;
+
+	mutex_lock(&robj->lock);
+
+	robj->polled = true;
+
+	/*
+	 * CPU or DMA access to this buffer has been completed, and
+	 * the blocked task has been waked up. Return poll event
+	 * so that the task can get out of select().
+	 */
+	if (robj->poll_event) {
+		robj->poll_event = false;
+		mutex_unlock(&robj->lock);
+		return POLLIN | POLLOUT;
+	}
+
+	/*
+	 * There is no anyone accessing this buffer so just return.
+	 */
+	if (!robj->locked) {
+		mutex_unlock(&robj->lock);
+		return POLLIN | POLLOUT;
+	}
+
+	poll_wait(filp, &robj->poll_wait, poll);
+
+	mutex_unlock(&robj->lock);
+
+	return ret;
+}
+
+static int dma_buf_lock(struct file *file, int cmd, struct file_lock *fl)
+{
+	struct dma_buf *dmabuf;
+	unsigned int type;
+	bool wait = false;
+
+	if (!is_dma_buf_file(file))
+		return -EINVAL;
+
+	dmabuf = file->private_data;
+
+	if ((fl->fl_type & F_UNLCK) = F_UNLCK) {
+		dmabuf_sync_single_unlock(dmabuf);
+		return 0;
+	}
+
+	/* convert flock type to dmabuf sync type. */
+	if ((fl->fl_type & F_WRLCK) = F_WRLCK)
+		type = DMA_BUF_ACCESS_W;
+	else if ((fl->fl_type & F_RDLCK) = F_RDLCK)
+		type = DMA_BUF_ACCESS_R;
+	else
+		return -EINVAL;
+
+	if (fl->fl_flags & FL_SLEEP)
+		wait = true;
+
+	/* TODO. the locking to certain region should also be considered. */
+
+	return dmabuf_sync_single_lock(dmabuf, type, wait);
+}
+
 static const struct file_operations dma_buf_fops = {
 	.release	= dma_buf_release,
 	.mmap		= dma_buf_mmap_internal,
 	.llseek		= dma_buf_llseek,
+	.poll		= dma_buf_poll,
+	.lock		= dma_buf_lock,
 };
 
 /*
-- 
1.7.9.5


^ permalink raw reply related

* Re: [PATCH 15/19] video: s1d13xxxfb: use dev_get_platdata()
From: Kristoffer Eriksson @ 2013-09-17 14:19 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <001501ceb364$340fdf40$9c2f9dc0$%han@samsung.com>

Acked-by: Kristoffer Ericson <kristoffer.ericson@gmail.com>

Jingoo Han skrev 2013-09-17 07:10:
> Use the wrapper function for retrieving the platform data instead of
> accessing dev->platform_data directly. This is a cosmetic change
> to make the code simpler and enhance the readability.
>
> Signed-off-by: Jingoo Han <jg1.han@samsung.com>
> ---
>   drivers/video/s1d13xxxfb.c |   12 ++++++------
>   1 file changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c
> index 05c2dc3..1399a46 100644
> --- a/drivers/video/s1d13xxxfb.c
> +++ b/drivers/video/s1d13xxxfb.c
> @@ -777,8 +777,8 @@ static int s1d13xxxfb_probe(struct platform_device *pdev)
>   	printk(KERN_INFO "Epson S1D13XXX FB Driver\n");
>   
>   	/* enable platform-dependent hardware glue, if any */
> -	if (pdev->dev.platform_data)
> -		pdata = pdev->dev.platform_data;
> +	if (dev_get_platdata(&pdev->dev))
> +		pdata = dev_get_platdata(&pdev->dev);
>   
>   	if (pdata && pdata->platform_init_video)
>   		pdata->platform_init_video();
> @@ -923,8 +923,8 @@ static int s1d13xxxfb_suspend(struct platform_device *dev, pm_message_t state)
>   	lcd_enable(s1dfb, 0);
>   	crt_enable(s1dfb, 0);
>   
> -	if (dev->dev.platform_data)
> -		pdata = dev->dev.platform_data;
> +	if (dev_get_platdata(&dev->dev))
> +		pdata = dev_get_platdata(&dev->dev);
>   
>   #if 0
>   	if (!s1dfb->disp_save)
> @@ -973,8 +973,8 @@ static int s1d13xxxfb_resume(struct platform_device *dev)
>   	while ((s1d13xxxfb_readreg(s1dfb, S1DREG_PS_STATUS) & 0x01))
>   		udelay(10);
>   
> -	if (dev->dev.platform_data)
> -		pdata = dev->dev.platform_data;
> +	if (dev_get_platdata(&dev->dev))
> +		pdata = dev_get_platdata(&dev->dev);
>   
>   	if (s1dfb->regs_save) {
>   		/* will write RO regs, *should* get away with it :) */


^ permalink raw reply

* Re: [PATCH] pwm-backlight: allow for non-increasing brightness levels
From: Mike Dunn @ 2013-09-17 14:23 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w, Richard Purdie, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Grant Likely,
	Rob Herring, linux-pwm-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Robert Jarzmik, Marek Vasut
In-Reply-To: <20130917093622.GB30088-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

On 09/17/2013 02:36 AM, Sascha Hauer wrote:
> Hi Mike,
> 
> On Thu, Sep 12, 2013 at 11:35:52AM -0700, Mike Dunn wrote:
>> Currently the driver assumes that the values specified in the brightness-levels
>> device tree property increase as they are parsed from left to right.  But boards
>> that invert the signal between the PWM output and the backlight will need to
>> specify decreasing brightness-levels.  This patch removes the assumption that
>> the last element of the array is the max value, and instead searches the array
>> for the max value and uses that as the normalizing value when determining the
>> duty cycle.
> 
> Note there's also support for inverted PWMs in the PWM framework
> provided your hardware supports this.


Yes, and in fact my first solution was to implement simulated polarity inversion
in the pwm driver, but that was shot down because polarity inversion is not
actually supported by the pwm hardware.  My inverter is external in the path
between the pwm output and the backlight.  Not sure of the reason for its presence.

Thanks,
Mike


^ permalink raw reply

* Re: [PATCH v11 0/8] PHY framework
From: Felipe Balbi @ 2013-09-17 15:41 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <5226F5E2.5010409@ti.com>

[-- Attachment #1: Type: text/plain, Size: 2279 bytes --]

On Wed, Sep 04, 2013 at 02:27:06PM +0530, Kishon Vijay Abraham I wrote:
> On Tuesday 03 September 2013 09:20 PM, Greg KH wrote:
> > On Tue, Sep 03, 2013 at 08:55:23PM +0530, Kishon Vijay Abraham I wrote:
> >> Hi Greg,
> >>
> >> On Wednesday 28 August 2013 12:50 AM, Felipe Balbi wrote:
> >>> Hi,
> >>>
> >>> On Mon, Aug 26, 2013 at 01:44:49PM +0530, Kishon Vijay Abraham I wrote:
> >>>> On Wednesday 21 August 2013 11:16 AM, Kishon Vijay Abraham I wrote:
> >>>>> Added a generic PHY framework that provides a set of APIs for the PHY drivers
> >>>>> to create/destroy a PHY and APIs for the PHY users to obtain a reference to
> >>>>> the PHY with or without using phandle.
> >>>>>
> >>>>> This framework will be of use only to devices that uses external PHY (PHY
> >>>>> functionality is not embedded within the controller).
> >>>>>
> >>>>> The intention of creating this framework is to bring the phy drivers spread
> >>>>> all over the Linux kernel to drivers/phy to increase code re-use and to
> >>>>> increase code maintainability.
> >>>>>
> >>>>> Comments to make PHY as bus wasn't done because PHY devices can be part of
> >>>>> other bus and making a same device attached to multiple bus leads to bad
> >>>>> design.
> >>>>>
> >>>>> If the PHY driver has to send notification on connect/disconnect, the PHY
> >>>>> driver should make use of the extcon framework. Using this susbsystem
> >>>>> to use extcon framwork will have to be analysed.
> >>>>>
> >>>>> You can find this patch series @
> >>>>> git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy.git testing
> >>>>
> >>>> Looks like there are not further comments on this series. Can you take this in
> >>>> your misc tree?
> >>>
> >>> Do you want me to queue these for you ? There are quite a few users for
> >>> this framework already and I know of at least 2 others which will show
> >>> up for v3.13.
> >>
> >> Can you queue this patch series? There are quite a few users already for this
> >> framework.
> > 
> > It will have to wait for 3.13 as the merge window for new features has
> > been closed for a week or so.  Sorry, I'll queue this up after 3.12-rc1
> > is out.
> 
> Alright, thanks.

Just a gentle ping on this one...

cheers

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH 03/15] OMAPDSS: fix DPI and SDI device ids
From: Tony Lindgren @ 2013-09-17 16:20 UTC (permalink / raw)
  To: Tomi Valkeinen; +Cc: linux-omap, linux-fbdev, Archit Taneja
In-Reply-To: <1377783120-14001-4-git-send-email-tomi.valkeinen@ti.com>

* Tomi Valkeinen <tomi.valkeinen@ti.com> [130829 06:40]:
> The DPI and SDI platform devices are currently created with the ID of
> -1. The ID doesn't currently affect anything.
> 
> However, we have added regulator supply entries for "omapdss_dpi.0" and
> "omapdss_sdi.0" to the board files, although these supply entries are
> not yet used. As the ID used for the devices is -1, these regulator
> supply entries will not work.
> 
> To fix the issue, assign ID of 0 to the devices. In the future there may
> be more than one DPI or SDI output, so it makes sense to have a proper
> ID for them.

This should be safe to queue by you along with other DSS patches:

Acked-by: Tony Lindgren <tony@atomide.com>
 
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
> ---
>  arch/arm/mach-omap2/display.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c
> index ff37be1..03a0516 100644
> --- a/arch/arm/mach-omap2/display.c
> +++ b/arch/arm/mach-omap2/display.c
> @@ -400,7 +400,7 @@ int __init omap_display_init(struct omap_dss_board_info *board_data)
>  
>  	/* Create devices for DPI and SDI */
>  
> -	pdev = create_simple_dss_pdev("omapdss_dpi", -1,
> +	pdev = create_simple_dss_pdev("omapdss_dpi", 0,
>  			board_data, sizeof(*board_data), dss_pdev);
>  	if (IS_ERR(pdev)) {
>  		pr_err("Could not build platform_device for omapdss_dpi\n");
> @@ -408,7 +408,7 @@ int __init omap_display_init(struct omap_dss_board_info *board_data)
>  	}
>  
>  	if (cpu_is_omap34xx()) {
> -		pdev = create_simple_dss_pdev("omapdss_sdi", -1,
> +		pdev = create_simple_dss_pdev("omapdss_sdi", 0,
>  				board_data, sizeof(*board_data), dss_pdev);
>  		if (IS_ERR(pdev)) {
>  			pr_err("Could not build platform_device for omapdss_sdi\n");
> -- 
> 1.8.1.2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v3 1/2] video: ARM CLCD: Add DT support
From: Pawel Moll @ 2013-09-17 16:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52376180.1090001@wwwdotorg.org>

On Mon, 2013-09-16 at 20:52 +0100, Stephen Warren wrote:
> I think the binding should either always use names as the key, or use
> indices in interrupts as the key. Hence, I'd word that more like:
> 
> - interrupt-names: either the single entry "combined" representing a
> 			combined interrupt output (CLCDINTR), or the
> 			four entries "mbe", "vcomp", "lnbu", "fuf"
> 			representing the individual CLCDMBEINTR,
> 			CLCDVCOMPINTR, CLCDLNBUINTR, CLCDFUFINTR
> 			interrupts.
> - interrupts: contains an interrupt specifier for each entry in
> 		 interrupt-names.

Cool, works for me.

> > +- arm,pl11x,panel-data-pads: array of 24 cells, each of them describing
> > +				a function of one of the CLD pads,
> > +				starting from 0 up to 23; each pad can
> > +				be described by one of the following values:
> > +	- 0: reserved (not connected)
> > +	- 0x100-0x107: color upper STN panel data 0 to 7
> ...
> 
> I assume those are the raw values that go into the HW?
> 
> > +				Example sets of values for standard
> > +				panel interfaces:
> > +	- PL110 single colour STN panel:
> > +			<0x107 0x106 0x105 0x104 0x103 0x102 0x101 0x100>,
> > +			<0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
> 
> The indentation of the introductory text seems a little odd. 

It follows the first paragraph of this property description. But I may
re-format all this stuff. Really looking forward some the formal
syntax :-)

> Do we really need so many examples?

They cover all standard cases. If I was to write a tree for a new
platform not knowing anything about CLCD, I think I'd appreciate this
and don't believe this extra kB or two is a problem. Do you?

> > +Optional properties:
> > +
> > +- arm,pl11x,framebuffer-base: a pair of two values, address and size,
> > +				defining the framebuffer to be used;
> > +				to be used only if it is *not*
> > +				part of normal memory, as described
> > +				in /memory node
> 
> If the framebuffer is part of /memory, what happens then? Is the address
> not fixed (so the HW isn't yet set up) and hence a driver should
> allocate it?

Yes, if it wants to display anything :-) And as this is a normal and
expected behaviour, I don't think it deserves a note in the
documentation. I'm open to any suggestions that would make the wording
above emphasize the "weirdness" of situations requiring the property.

Paweł



^ permalink raw reply

* Re: [PATCH v3 1/2] video: ARM CLCD: Add DT support
From: Pawel Moll @ 2013-09-17 16:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1379435799.9205.16.camel@hornet>

Uh, sorry, missed one...

On Tue, 2013-09-17 at 17:36 +0100, Pawel Moll wrote:
> On Mon, 2013-09-16 at 20:52 +0100, Stephen Warren wrote:
> > > +- arm,pl11x,panel-data-pads: array of 24 cells, each of them describing
> > > +				a function of one of the CLD pads,
> > > +				starting from 0 up to 23; each pad can
> > > +				be described by one of the following values:
> > > +	- 0: reserved (not connected)
> > > +	- 0x100-0x107: color upper STN panel data 0 to 7
> > ...
> > 
> > I assume those are the raw values that go into the HW?

No, they can be considered "labels", defining the way pads are used
(wired). Then, basing on this information, the driver is configuring the
cell, eg. selecting STN or TFT mode (thus switching the output between
panel formatter and raw RGB data source).

Paweł



^ permalink raw reply

* Re: [PATCH 02/11] omapdss: HDMI: create a HDMI PLL library
From: Mike Turquette @ 2013-09-17 19:40 UTC (permalink / raw)
  To: Tomi Valkeinen; +Cc: Archit Taneja, Linux OMAP Mailing List, linux-fbdev
In-Reply-To: <523828A7.8050204@ti.com>

On Tue, Sep 17, 2013 at 3:02 AM, Tomi Valkeinen <tomi.valkeinen@ti.com> wrote:
> On 17/09/13 12:38, Mike Turquette wrote:
>> Quoting Archit Taneja (2013-09-17 00:06:28)
>>> HDMI PLL is a block common to DSS in OMAP4, OMAP5 and DRA7x. Move the
>>> existing PLL functions from ti_hdmi_4xxx_ip.c and hdmi.c to a separate file.
>>> These funcs are called directly from the hdmi driver rather than hdmi_ip_ops
>>> function pointer calls.
>>>
>>> Add the PLL library function declarations to ti_hdmi.h. These will be shared
>>> amongst the omap4/5 hdmi platform drivers. Remove the PLL function pointer ops
>>> from the ti_hdmi_ip_ops struct. These will be shared amongst the omap4/5 hdmi
>>> platform drivers and other libraries.
>>>
>>> Signed-off-by: Archit Taneja <archit@ti.com>
>>
>> Would be cool to see this convert to the common clock framework
>> implementation (include/linux/clk-provider.h). It appears that this PLL
>> only needs to support .enable, .disable and .recalc_rate callbacks at
>> first glance.
>
> We've got a (very) long term plan to use CCF for DSS. And, if I'm not
> mistaken, the PLL used for HDMI and DSI is the same as used elsewhere in
> OMAP (I don't remember the PLL type name).
>
> I think the main issue with DSS clocks is that we require as exact
> clocks as possible, and there are multiple dividers/multipliers on the
> clock path. So we iterate over the divider/multiplier ranges, trying to
> find as good freq match as possible.
>
> So if the clock path is composed from "black boxes", and we can only ask
> for a certain frequency, and get back probably some other frequency, it
> gets quite difficult to find good clock matches. Well, at least I
> imagine so, I have not tried to implement that.

I hope that the existing CLK_SET_RATE_PARENT flag could help you get
the frequency you need; it causes a call to clk_set_rate(leaf_clk,
target_rate) to walk up the chain of parents and configure rates as
needed.

However I have been looking at standardizing a way to define clock
rate tables, possibly in DT. In many cases it is a board-specific
issue (e.g. different oscillators or other reference clocks that feed
into the SoC) and specifying rate tables in DT is one way to store
known-good configurations for complex clock subtrees.

Regards,
Mike

>
>  Tomi
>
>

^ permalink raw reply

* Re: [PATCH v3 1/2] video: ARM CLCD: Add DT support
From: Stephen Warren @ 2013-09-17 21:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1379436716.9205.25.camel@hornet>

On 09/17/2013 10:51 AM, Pawel Moll wrote:
> Uh, sorry, missed one...
> 
> On Tue, 2013-09-17 at 17:36 +0100, Pawel Moll wrote:
>> On Mon, 2013-09-16 at 20:52 +0100, Stephen Warren wrote:
>>>> +- arm,pl11x,panel-data-pads: array of 24 cells, each of them describing
>>>> +				a function of one of the CLD pads,
>>>> +				starting from 0 up to 23; each pad can
>>>> +				be described by one of the following values:
>>>> +	- 0: reserved (not connected)
>>>> +	- 0x100-0x107: color upper STN panel data 0 to 7
>>> ...
>>>
>>> I assume those are the raw values that go into the HW?
> 
> No, they can be considered "labels", defining the way pads are used
> (wired). Then, basing on this information, the driver is configuring the
> cell, eg. selecting STN or TFT mode (thus switching the output between
> panel formatter and raw RGB data source).

Oh, why not just use the raw values from the HW registers for this?

^ permalink raw reply

* Re: [PATCH v3 1/2] video: ARM CLCD: Add DT support
From: Stephen Warren @ 2013-09-17 21:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1379435799.9205.16.camel@hornet>

On 09/17/2013 10:36 AM, Pawel Moll wrote:
> On Mon, 2013-09-16 at 20:52 +0100, Stephen Warren wrote:
>> I think the binding should either always use names as the key, or use
>> indices in interrupts as the key. Hence, I'd word that more like:

>> Do we really need so many examples?
> 
> They cover all standard cases. If I was to write a tree for a new
> platform not knowing anything about CLCD, I think I'd appreciate this
> and don't believe this extra kB or two is a problem. Do you?

I guess it's not a problem. It's just unusual.

>>> +Optional properties:
>>> +
>>> +- arm,pl11x,framebuffer-base: a pair of two values, address and size,
>>> +				defining the framebuffer to be used;
>>> +				to be used only if it is *not*
>>> +				part of normal memory, as described
>>> +				in /memory node
>>
>> If the framebuffer is part of /memory, what happens then? Is the address
>> not fixed (so the HW isn't yet set up) and hence a driver should
>> allocate it?
> 
> Yes, if it wants to display anything :-) And as this is a normal and
> expected behaviour, I don't think it deserves a note in the
> documentation. I'm open to any suggestions that would make the wording
> above emphasize the "weirdness" of situations requiring the property.

Perhaps:

A pair of two values, address and size, defining the framebuffer to be
used. If not present, the framebuffer may be located anywhere in memory.

Or, is this intended to represent where the HW is already scanning out
from? If so, then perhaps:

A pair of two values, address and size, defining the location of the
framebuffer that the controller is currently configured to display. If
not present, the controller may or may not already be active.

(although presumably if the controller is already active, then the
address can simply be read out of the HW register, so there's no need
for a DT property).

^ permalink raw reply

* [PATCH] fbcon: fix deadlock in fbcon_generic_blank()
From: John Tapsell @ 2013-09-17 22:29 UTC (permalink / raw)
  To: Jean-Christophe Plagniol-Villard, Tomi Valkeinen
  Cc: Peter Hurley, Dave Airlie, linux-fbdev, linux-kernel

Do not lock fb_info when calling sending the FB_EVENT_CONBLANK
event.

In fbmem.c, the semantics are that we acquire the lock_fb_info first,
and then console_lock.  However when fbcon.c fbcon_generic_blank() is
called, the console lock could already be held.  Locking fb_info can
thus cause a deadlock.

fbmem.c sends the FB_EVENT_BLANK without locking lock_fb_info first, so
this change introduces similar behaviour.

Signed-off-by: John Tapsell <johnflux@gmail.com>

---
 drivers/video/console/fbcon.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 6b4fb5c..8546441 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -2333,13 +2333,9 @@ static void fbcon_generic_blank(struct vc_data
*vc, struct fb_info *info,
         vc->vc_video_erase_char = oldc;
     }

-
-    if (!lock_fb_info(info))
-        return;
     event.info = info;
     event.data = &blank;
     fb_notifier_call_chain(FB_EVENT_CONBLANK, &event);
-    unlock_fb_info(info);
 }

 static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
-- 
1.8.1.2

^ permalink raw reply related

* Re: [PATCH 02/11] omapdss: HDMI: create a HDMI PLL library
From: Tomi Valkeinen @ 2013-09-18  7:00 UTC (permalink / raw)
  To: Mike Turquette; +Cc: Archit Taneja, Linux OMAP Mailing List, linux-fbdev
In-Reply-To: <CAPtuhTh-6JJnpqp=0FCQqkPS2yBUmj7-zniY4vRQR9xq+t8htg@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1797 bytes --]

On 17/09/13 22:40, Mike Turquette wrote:

> I hope that the existing CLK_SET_RATE_PARENT flag could help you get
> the frequency you need; it causes a call to clk_set_rate(leaf_clk,
> target_rate) to walk up the chain of parents and configure rates as
> needed.

Hmm, I'm not quite sure what that does, but it doesn't sound like it
would help. The only way I know to find good clocks is to iterate over
the dividers for each clock on the path.

And to complicate things, clocks from the "middle" of the path are used
for some purposes, so it's not only the final clock that we're
interested in.

For example, DSI: DSI PLL produces a high freq clock that goes to DSI
PHY. That one is used for the DSI bus clock. The high freq clock from
DSI PLL also goes to two dividers, of which one goes to DSI IP, and the
second goes to DISPC. DISPC clock is then divided with two dividers in
row, and the resulting clock goes also to DSI IP.

All those different clocks have restrictions and dependencies to each
other, like this one needs to be higher than that one, or ClkA = N *
ClkB, etc.

> However I have been looking at standardizing a way to define clock
> rate tables, possibly in DT. In many cases it is a board-specific
> issue (e.g. different oscillators or other reference clocks that feed
> into the SoC) and specifying rate tables in DT is one way to store
> known-good configurations for complex clock subtrees.

Well, for some boards, which only have an LCD, we could probably get the
clock from a table. But if the display used (say, external monitor)
supports multiple resolutions, such a table is not feasible. We could
have some clocks there in the table, but we'd still need a dynamic way
to figure out the dividers for other clock rates.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]

^ permalink raw reply

* [PATCH] radeon: Conditionally compile PM code
From: Thierry Reding @ 2013-09-18 12:48 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Jean-Christophe Plagniol-Villard,
	Tomi Valkeinen
  Cc: linux-fbdev, linux-kernel

The power management code is only used on X86 and PowerMac. To prevent
the compiler from warning about unused code, only build when PM and one
of X86 or PowerMac is selected.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/video/aty/radeon_pm.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index f7091ec..f4317f1 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -1427,6 +1427,8 @@ static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo)
 	mdelay( 15);
 }
 
+#if defined(CONFIG_PM)
+#if defined(CONFIG_X86) || defined(CONFIG_PPC_PMAC)
 static void radeon_pm_reset_pad_ctlr_strength(struct radeonfb_info *rinfo)
 {
 	u32 tmp, tmp2;
@@ -1939,9 +1941,10 @@ static void radeon_reinitialize_M10(struct radeonfb_info *rinfo)
 	 */
 	radeon_pm_m10_enable_lvds_spread_spectrum(rinfo);
 }
+#endif
 
 #ifdef CONFIG_PPC_OF
-
+#ifdef CONFIG_PPC_PMAC
 static void radeon_pm_m9p_reconfigure_mc(struct radeonfb_info *rinfo)
 {
 	OUTREG(MC_CNTL, rinfo->save_regs[46]);
@@ -2202,6 +2205,8 @@ static void radeon_reinitialize_M9P(struct radeonfb_info *rinfo)
 	radeon_pm_restore_pixel_pll(rinfo);
 	radeon_pm_m10_enable_lvds_spread_spectrum(rinfo);
 }
+#endif
+#endif
 
 #if 0 /* Not ready yet */
 static void radeon_reinitialize_QW(struct radeonfb_info *rinfo)
-- 
1.8.4


^ permalink raw reply related

* Re: [PATCH v3 1/2] video: ARM CLCD: Add DT support
From: Pawel Moll @ 2013-09-18 16:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <5238CBE9.2060800@wwwdotorg.org>

On Tue, 2013-09-17 at 22:38 +0100, Stephen Warren wrote:
> >>> +Optional properties:
> >>> +
> >>> +- arm,pl11x,framebuffer-base: a pair of two values, address and size,
> >>> +				defining the framebuffer to be used;
> >>> +				to be used only if it is *not*
> >>> +				part of normal memory, as described
> >>> +				in /memory node
> >>
> >> If the framebuffer is part of /memory, what happens then? Is the address
> >> not fixed (so the HW isn't yet set up) and hence a driver should
> >> allocate it?
> > 
> > Yes, if it wants to display anything :-) And as this is a normal and
> > expected behaviour, I don't think it deserves a note in the
> > documentation. I'm open to any suggestions that would make the wording
> > above emphasize the "weirdness" of situations requiring the property.
> 
> Perhaps:
> 
> A pair of two values, address and size, defining the framebuffer to be
> used. If not present, the framebuffer may be located anywhere in memory.

Works with me, thanks!

On Tue, 2013-09-17 at 22:34 +0100, Stephen Warren wrote:
> > On Tue, 2013-09-17 at 17:36 +0100, Pawel Moll wrote:
> >> On Mon, 2013-09-16 at 20:52 +0100, Stephen Warren wrote:
> >>>> +- arm,pl11x,panel-data-pads: array of 24 cells, each of them describing
> >>>> +				a function of one of the CLD pads,
> >>>> +				starting from 0 up to 23; each pad can
> >>>> +				be described by one of the following values:
> >>>> +	- 0: reserved (not connected)
> >>>> +	- 0x100-0x107: color upper STN panel data 0 to 7
> >>> ...
> >>>
> >>> I assume those are the raw values that go into the HW?
> > 
> > No, they can be considered "labels", defining the way pads are used
> > (wired). Then, basing on this information, the driver is configuring the
> > cell, eg. selecting STN or TFT mode (thus switching the output between
> > panel formatter and raw RGB data source).
> 
> Oh, why not just use the raw values from the HW registers for this?

How do you mean? Based on the the way the "LCD data" lines are wired up,
the driver has to decide whether to select STN (LCDControl &= ~(1<<5))
or TFT mode (LCDControl |= 1<<5), then figures out what memory pixel
formats are possible (based on this will set LCDControl[3..1] in
runtime, depending on the mode selected by the user). There isn't a
separate register as such configuring output pads. It's just the way
they can used depends on the way they're wired up.

Paweł



^ permalink raw reply

* [PATCH] OMAPDSS: DISPC: set irq_safe for runtime PM
From: Tomi Valkeinen @ 2013-09-19 10:19 UTC (permalink / raw)
  To: linux-fbdev

We have a bug with omapdrm, where omapdrm calls dispc's pm_runtime
function in atomic context, and dispc's pm_runtime is not marked as
irq_safe:

BUG: sleeping function called from invalid context at drivers/base/power/runtime.c:952

Dispc's runtime PM callbacks are irq safe, so we can just set the
irq_safe flag to fix the issue.

However, in the long term, I'd rather have omapdrm manage the runtime PM
calls in a better way. Calling get/put for every small operation that
touches the dispc registers is very inefficient. It'd be better and
cleaner to have clear "in-use" and "not-in-use" states for dispc, so
that we don't need to do register context restore for small operations,
only to turn dispc off right afterwards.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 drivers/video/omap2/dss/dispc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 02a7340..4779750 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -3691,6 +3691,7 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
 	}
 
 	pm_runtime_enable(&pdev->dev);
+	pm_runtime_irq_safe(&pdev->dev);
 
 	r = dispc_runtime_get();
 	if (r)
-- 
1.8.1.2


^ permalink raw reply related

* Re: [PATCH] pwm-backlight: allow for non-increasing brightness levels
From: Thierry Reding @ 2013-09-19 11:56 UTC (permalink / raw)
  To: Mike Dunn
  Cc: Richard Purdie, Jingoo Han, Jean-Christophe Plagniol-Villard,
	Tomi Valkeinen, Grant Likely, Rob Herring,
	linux-pwm-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Robert Jarzmik, Marek Vasut
In-Reply-To: <1379010952-8928-1-git-send-email-mikedunn-kFrNdAxtuftBDgjK7y7TUQ@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 2176 bytes --]

On Thu, Sep 12, 2013 at 11:35:52AM -0700, Mike Dunn wrote:
> Currently the driver assumes that the values specified in the brightness-levels
> device tree property increase as they are parsed from left to right.  But boards
> that invert the signal between the PWM output and the backlight will need to
> specify decreasing brightness-levels.  This patch removes the assumption that
> the last element of the array is the max value, and instead searches the array
> for the max value and uses that as the normalizing value when determining the
> duty cycle.

"maximum value", "... and uses that as the scale to normalize the duty
cycle"?

Also please wrap commit messages at 72 characters.

> diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
> index 1fea627..d66aaa0 100644
> --- a/drivers/video/backlight/pwm_bl.c
> +++ b/drivers/video/backlight/pwm_bl.c
> @@ -27,6 +27,7 @@ struct pwm_bl_data {
>  	unsigned int		period;
>  	unsigned int		lth_brightness;
>  	unsigned int		*levels;
> +	unsigned int		max_level;

Perhaps call this "scale"? Otherwise there some potential to mix it up
with max_brightness.

> @@ -195,7 +196,15 @@ static int pwm_backlight_probe(struct platform_device *pdev)
>  	}
>  
>  	if (data->levels) {
> -		max = data->levels[data->max_brightness];
> +		int i, max_value = 0, max_idx = 0;

i should be unsigned int to match the type of data->max_brightness.

> +		for (i = 0; i <= data->max_brightness; i++) {

There should be a blank line above this one to increase readability.

> +			if (data->levels[i] > max_value) {
> +				max_value = data->levels[i];
> +				max_idx = i;
> +			}
> +		}
> +		pb->max_level = max_idx;

Some here.

Also I suggest to just drop the max_ prefix from the local variables.
Perhaps also simplify all of it to something like:

	for (i = 0; i <= data->max_brightness; i++)
		if (data->levels[i] > pb->scale)
			pb->scale = data->levels[i];

And get rid of the index altogether. That way you can use pb->scale
directly during the computation of the duty cycle and don't have to
index the levels array over and over again.

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH] OMAPDSS: DISPC: set irq_safe for runtime PM
From: Rob Clark @ 2013-09-19 15:14 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1379585958-24537-1-git-send-email-tomi.valkeinen@ti.com>

On Thu, Sep 19, 2013 at 6:19 AM, Tomi Valkeinen <tomi.valkeinen@ti.com> wrote:
> We have a bug with omapdrm, where omapdrm calls dispc's pm_runtime
> function in atomic context, and dispc's pm_runtime is not marked as
> irq_safe:
>
> BUG: sleeping function called from invalid context at drivers/base/power/runtime.c:952
>
> Dispc's runtime PM callbacks are irq safe, so we can just set the
> irq_safe flag to fix the issue.
>
> However, in the long term, I'd rather have omapdrm manage the runtime PM
> calls in a better way. Calling get/put for every small operation that
> touches the dispc registers is very inefficient. It'd be better and
> cleaner to have clear "in-use" and "not-in-use" states for dispc, so
> that we don't need to do register context restore for small operations,
> only to turn dispc off right afterwards.

hmm, quick mid-conference thought:  in msm, in crtc->prepare and
crtc->dpms(ON) I do clk_prepare_enable(), and inverse in
commit()/dpms(OFF).  (The extra ref held between prepare() and
commit() avoids turning things off mid-modeset.)  The net effect is
that we hold things on when the display is on.  Probably we should do
something similar in omapdrm?

BR,
-R


> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
> ---
>  drivers/video/omap2/dss/dispc.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
> index 02a7340..4779750 100644
> --- a/drivers/video/omap2/dss/dispc.c
> +++ b/drivers/video/omap2/dss/dispc.c
> @@ -3691,6 +3691,7 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
>         }
>
>         pm_runtime_enable(&pdev->dev);
> +       pm_runtime_irq_safe(&pdev->dev);
>
>         r = dispc_runtime_get();
>         if (r)
> --
> 1.8.1.2
>

^ permalink raw reply

* Re: [PATCH] pwm-backlight: allow for non-increasing brightness levels
From: Mike Dunn @ 2013-09-19 16:13 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Richard Purdie, Jingoo Han, Jean-Christophe Plagniol-Villard,
	Tomi Valkeinen, Grant Likely, Rob Herring,
	linux-pwm-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Robert Jarzmik, Marek Vasut
In-Reply-To: <20130919115650.GE10852@ulmo>

On 09/19/2013 04:56 AM, Thierry Reding wrote:
> On Thu, Sep 12, 2013 at 11:35:52AM -0700, Mike Dunn wrote:
>> Currently the driver assumes that the values specified in the brightness-levels
>> device tree property increase as they are parsed from left to right.  But boards
>> that invert the signal between the PWM output and the backlight will need to
>> specify decreasing brightness-levels.  This patch removes the assumption that
>> the last element of the array is the max value, and instead searches the array
>> for the max value and uses that as the normalizing value when determining the
>> duty cycle.
> 
> "maximum value", "... and uses that as the scale to normalize the duty
> cycle"?


It's been a while since my last math class... is "normalizing value" not the
correct term?  Maybe just "uses that in the duty cycle calculation"?


> 
> Also please wrap commit messages at 72 characters.


OK.  Sorry, didn't know.


> 
>> diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
>> index 1fea627..d66aaa0 100644
>> --- a/drivers/video/backlight/pwm_bl.c
>> +++ b/drivers/video/backlight/pwm_bl.c
>> @@ -27,6 +27,7 @@ struct pwm_bl_data {
>>  	unsigned int		period;
>>  	unsigned int		lth_brightness;
>>  	unsigned int		*levels;
>> +	unsigned int		max_level;
> 
> Perhaps call this "scale"? Otherwise there some potential to mix it up
> with max_brightness.


Yes, this name is thorny.  The code was somewhat confusing to me until I
realized that for the DT case, brightness and max_brightness are indices into
the levels[] array, whereas they are actual values for the platform_data case.
I'll go with "scale" if you prefer.


> 
>> @@ -195,7 +196,15 @@ static int pwm_backlight_probe(struct platform_device *pdev)
>>  	}
>>  
>>  	if (data->levels) {
>> -		max = data->levels[data->max_brightness];
>> +		int i, max_value = 0, max_idx = 0;
> 
> i should be unsigned int to match the type of data->max_brightness.


Yes, thanks.  I'm surprised there's no warning from the compiler.  I'm also
assigning an unsigned to a signed.


> 
>> +		for (i = 0; i <= data->max_brightness; i++) {
> 
> There should be a blank line above this one to increase readability.
> 
>> +			if (data->levels[i] > max_value) {
>> +				max_value = data->levels[i];
>> +				max_idx = i;
>> +			}
>> +		}
>> +		pb->max_level = max_idx;
> 
> Some here.
> 
> Also I suggest to just drop the max_ prefix from the local variables.
> Perhaps also simplify all of it to something like:
> 
> 	for (i = 0; i <= data->max_brightness; i++)
> 		if (data->levels[i] > pb->scale)
> 			pb->scale = data->levels[i];
> 
> And get rid of the index altogether. That way you can use pb->scale
> directly during the computation of the duty cycle and don't have to
> index the levels array over and over again.


Ok, if you prefer.  The reason I made max_level an index is for consistency.
For the DT case, brightness and max_brightness are indices, and I had already
been confused by the value-versus-index issue.

Thanks much for the review!  I'll ready a v2 patch.

Mike


^ permalink raw reply

* [PATCH 00/51] DMA mask changes
From: Russell King - ARM Linux @ 2013-09-19 21:22 UTC (permalink / raw)
  To: alsa-devel, b43-dev, devel, devicetree, dri-devel, e1000-devel,
	linux-arm-kernel, linux-crypto, linux-doc, linux-fbdev, linux-ide,
	linux-media, linux-mmc, linux-nvme, linux-omap, linuxppc-dev,
	linux-samsung-soc, linux-scsi, linux-tegra, linux-usb,
	linux-wireless, netdev, Solarflare linux maintainers,
	uclinux-dist-devel

This started out as a request to look at the DMA mask situation, and how
to solve the issues which we have on ARM - notably how the DMA mask
should be setup.

However, I started off reviewing how the dma_mask and coherent_dma_mask
was being used, and what I found was rather messy, and in some cases
rather buggy.  I tried to get some of the bug fixes in before the last
merge window, but it seems that the maintainers preferred to have the
full solution rather than a simple -rc suitable bug fix.

So, this is an attempt to clean things up.

The first point here is that drivers performing DMA should be calling
dma_set_mask()/dma_set_coherent_mask() in their probe function to verify
that DMA can be performed.  Lots of ARM drivers omit this step; please
refer to the DMA API documentation on this subject.

What this means is that the DMA mask provided by bus code is a default
value - nothing more.  It doesn't have to accurately reflect what the
device is actually capable of.  Apart from the storage for dev->dma_mask
being initialised for any device which is DMA capable, there is no other
initialisation which is strictly necessary at device creation time.

Now, these cleanups address two major areas:
1. The setting of DMA masks, particularly when both the coherent and
   streaming DMA masks are set together.

2. The initialisation of DMA masks by drivers - this seems to be becoming
   a popular habbit, one which may not be entirely the right solution.
   Rather than having this scattered throughout the tree, I've pulled
   that into a central location (and called it coercing the DMA mask -
   because it really is about forcing the DMA mask to be that value.)

3. Finally, addressing the long held misbelief that DMA masks somehow
   correspond with physical addresses.  We already have established
   long ago that dma_addr_t values returned from the DMA API are the
   values which you program into the DMA controller, and so are the
   bus addresses.  It is _only_ sane that DMA masks are also bus
   related too, and not related to physical address spaces.

(3) is a very important point for LPAE systems, which may still have
less than 4GB of memory, but this memory is all located above the 4GB
physical boundary.  This means with the current model, any device
using a 32-bit DMA mask fails - even though the DMA controller is
still only a 32-bit DMA controller but the 32-bit bus addresses map
to system memory.  To put it another way, the bus addresses have a
4GB physical offset on them.

This email is only being sent to the mailing lists in question, not to
anyone personally.  The list of individuals is far to great to do that.
I'm hoping no mailing lists reject the patches based on the number of
recipients.

Patches based on v3.12-rc1.

 Documentation/DMA-API-HOWTO.txt                   |   37 +++++++++------
 Documentation/DMA-API.txt                         |    8 +++
 arch/arm/include/asm/dma-mapping.h                |    8 +++
 arch/arm/mm/dma-mapping.c                         |   49 ++++++++++++++++++--
 arch/arm/mm/init.c                                |   12 +++---
 arch/arm/mm/mm.h                                  |    2 +
 arch/powerpc/kernel/vio.c                         |    3 +-
 block/blk-settings.c                              |    8 ++--
 drivers/amba/bus.c                                |    6 +--
 drivers/ata/pata_ixp4xx_cf.c                      |    5 ++-
 drivers/ata/pata_octeon_cf.c                      |    5 +-
 drivers/block/nvme-core.c                         |   10 ++---
 drivers/crypto/ixp4xx_crypto.c                    |   48 ++++++++++----------
 drivers/dma/amba-pl08x.c                          |    5 ++
 drivers/dma/dw/platform.c                         |    8 +--
 drivers/dma/edma.c                                |    6 +--
 drivers/dma/pl330.c                               |    4 ++
 drivers/firmware/dcdbas.c                         |   23 +++++-----
 drivers/firmware/google/gsmi.c                    |   13 +++--
 drivers/gpu/drm/exynos/exynos_drm_drv.c           |    6 ++-
 drivers/gpu/drm/omapdrm/omap_dmm_tiler.c          |    5 +-
 drivers/media/platform/omap3isp/isp.c             |    6 +-
 drivers/media/platform/omap3isp/isp.h             |    3 -
 drivers/mmc/card/queue.c                          |    3 +-
 drivers/mmc/host/sdhci-acpi.c                     |    5 +-
 drivers/net/ethernet/broadcom/b44.c               |    3 +-
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c  |    8 +---
 drivers/net/ethernet/brocade/bna/bnad.c           |   13 ++----
 drivers/net/ethernet/emulex/benet/be_main.c       |   12 +----
 drivers/net/ethernet/intel/e1000/e1000_main.c     |    9 +---
 drivers/net/ethernet/intel/e1000e/netdev.c        |   18 +++-----
 drivers/net/ethernet/intel/igb/igb_main.c         |   18 +++-----
 drivers/net/ethernet/intel/igbvf/netdev.c         |   18 +++-----
 drivers/net/ethernet/intel/ixgb/ixgb_main.c       |   16 ++-----
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c     |   15 ++----
 drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c |   15 ++----
 drivers/net/ethernet/nxp/lpc_eth.c                |    6 ++-
 drivers/net/ethernet/octeon/octeon_mgmt.c         |    5 +-
 drivers/net/ethernet/sfc/efx.c                    |   12 +-----
 drivers/net/wireless/b43/dma.c                    |    9 +---
 drivers/net/wireless/b43legacy/dma.c              |    9 +---
 drivers/of/platform.c                             |    3 -
 drivers/parport/parport_pc.c                      |    8 +++-
 drivers/scsi/scsi_lib.c                           |    2 +-
 drivers/staging/dwc2/platform.c                   |    5 +-
 drivers/staging/et131x/et131x.c                   |   17 +------
 drivers/staging/imx-drm/imx-drm-core.c            |    8 +++-
 drivers/staging/imx-drm/ipuv3-crtc.c              |    4 +-
 drivers/staging/media/dt3155v4l/dt3155v4l.c       |    5 +--
 drivers/usb/chipidea/ci_hdrc_imx.c                |    7 +--
 drivers/usb/dwc3/dwc3-exynos.c                    |    7 +--
 drivers/usb/gadget/lpc32xx_udc.c                  |    4 +-
 drivers/usb/host/bcma-hcd.c                       |    3 +-
 drivers/usb/host/ehci-atmel.c                     |    7 +--
 drivers/usb/host/ehci-octeon.c                    |    4 +-
 drivers/usb/host/ehci-omap.c                      |   10 ++--
 drivers/usb/host/ehci-orion.c                     |    7 +--
 drivers/usb/host/ehci-platform.c                  |   10 ++--
 drivers/usb/host/ehci-s5p.c                       |    7 +--
 drivers/usb/host/ehci-spear.c                     |    7 +--
 drivers/usb/host/ehci-tegra.c                     |    7 +--
 drivers/usb/host/ohci-at91.c                      |    9 ++--
 drivers/usb/host/ohci-exynos.c                    |    7 +--
 drivers/usb/host/ohci-nxp.c                       |    5 +-
 drivers/usb/host/ohci-octeon.c                    |    5 +-
 drivers/usb/host/ohci-omap3.c                     |   10 ++--
 drivers/usb/host/ohci-pxa27x.c                    |    8 ++--
 drivers/usb/host/ohci-sa1111.c                    |    6 +++
 drivers/usb/host/ohci-spear.c                     |    7 +--
 drivers/usb/host/ssb-hcd.c                        |    3 +-
 drivers/usb/host/uhci-platform.c                  |    7 +--
 drivers/usb/musb/am35x.c                          |   50 +++++++--------------
 drivers/usb/musb/da8xx.c                          |   49 +++++++-------------
 drivers/usb/musb/davinci.c                        |   48 +++++++-------------
 drivers/usb/musb/tusb6010.c                       |   49 +++++++-------------
 drivers/video/amba-clcd.c                         |    5 ++
 include/linux/amba/bus.h                          |    2 -
 include/linux/dma-mapping.h                       |   31 +++++++++++++
 sound/arm/pxa2xx-pcm.c                            |    9 +---
 sound/soc/atmel/atmel-pcm.c                       |   11 ++---
 sound/soc/blackfin/bf5xx-ac97-pcm.c               |   11 ++---
 sound/soc/blackfin/bf5xx-i2s-pcm.c                |   10 ++---
 sound/soc/davinci/davinci-pcm.c                   |    9 +---
 sound/soc/fsl/fsl_dma.c                           |    9 +---
 sound/soc/fsl/mpc5200_dma.c                       |   10 ++---
 sound/soc/jz4740/jz4740-pcm.c                     |   12 ++---
 sound/soc/kirkwood/kirkwood-dma.c                 |    9 +---
 sound/soc/nuc900/nuc900-pcm.c                     |    9 ++--
 sound/soc/omap/omap-pcm.c                         |   11 ++---
 sound/soc/pxa/pxa2xx-pcm.c                        |   11 ++---
 sound/soc/s6000/s6000-pcm.c                       |    9 +---
 sound/soc/samsung/dma.c                           |   11 ++---
 sound/soc/samsung/idma.c                          |   11 ++---
 93 files changed, 493 insertions(+), 566 deletions(-)


^ permalink raw reply

* [PATCH 01/51] DMA-API: provide a helper to set both DMA and coherent DMA masks
From: Russell King @ 2013-09-19 21:25 UTC (permalink / raw)
  To: alsa-devel, b43-dev, devel, devicetree, dri-devel, e1000-devel,
	linux-arm-kernel, linux-crypto, linux-doc, linux-fbdev, linux-ide,
	linux-media, linux-mmc, linux-nvme, linux-omap, linuxppc-dev,
	linux-samsung-soc, linux-scsi, linux-tegra, linux-usb,
	linux-wireless, netdev, Solarflare linux maintainers,
	uclinux-dist-devel
  Cc: Vinod Koul, Dan Williams, Rob Landley
In-Reply-To: <20130919212235.GD12758@n2100.arm.linux.org.uk>

Provide a helper to set both the DMA and coherent DMA masks to the
same value - this avoids duplicated code in a number of drivers,
sometimes with buggy error handling, and also allows us identify
which drivers do things differently.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 Documentation/DMA-API-HOWTO.txt |   37 ++++++++++++++++++++++---------------
 Documentation/DMA-API.txt       |    8 ++++++++
 include/linux/dma-mapping.h     |   14 ++++++++++++++
 3 files changed, 44 insertions(+), 15 deletions(-)

diff --git a/Documentation/DMA-API-HOWTO.txt b/Documentation/DMA-API-HOWTO.txt
index 14129f1..5e98303 100644
--- a/Documentation/DMA-API-HOWTO.txt
+++ b/Documentation/DMA-API-HOWTO.txt
@@ -101,14 +101,23 @@ style to do this even if your device holds the default setting,
 because this shows that you did think about these issues wrt. your
 device.
 
-The query is performed via a call to dma_set_mask():
+The query is performed via a call to dma_set_mask_and_coherent():
 
-	int dma_set_mask(struct device *dev, u64 mask);
+	int dma_set_mask_and_coherent(struct device *dev, u64 mask);
 
-The query for consistent allocations is performed via a call to
-dma_set_coherent_mask():
+which will query the mask for both streaming and coherent APIs together.
+If you have some special requirements, then the following two separate
+queries can be used instead:
 
-	int dma_set_coherent_mask(struct device *dev, u64 mask);
+	The query for streaming mappings is performed via a call to
+	dma_set_mask():
+
+		int dma_set_mask(struct device *dev, u64 mask);
+
+	The query for consistent allocations is performed via a call
+	to dma_set_coherent_mask():
+
+		int dma_set_coherent_mask(struct device *dev, u64 mask);
 
 Here, dev is a pointer to the device struct of your device, and mask
 is a bit mask describing which bits of an address your device
@@ -137,7 +146,7 @@ exactly why.
 
 The standard 32-bit addressing device would do something like this:
 
-	if (dma_set_mask(dev, DMA_BIT_MASK(32))) {
+	if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
 		printk(KERN_WARNING
 		       "mydev: No suitable DMA available.\n");
 		goto ignore_this_device;
@@ -171,22 +180,20 @@ If a card is capable of using 64-bit consistent allocations as well,
 
 	int using_dac, consistent_using_dac;
 
-	if (!dma_set_mask(dev, DMA_BIT_MASK(64))) {
+	if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) {
 		using_dac = 1;
 	   	consistent_using_dac = 1;
-		dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
-	} else if (!dma_set_mask(dev, DMA_BIT_MASK(32))) {
+	} else if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
 		using_dac = 0;
 		consistent_using_dac = 0;
-		dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
 	} else {
 		printk(KERN_WARNING
 		       "mydev: No suitable DMA available.\n");
 		goto ignore_this_device;
 	}
 
-dma_set_coherent_mask() will always be able to set the same or a
-smaller mask as dma_set_mask(). However for the rare case that a
+The coherent coherent mask will always be able to set the same or a
+smaller mask as the streaming mask. However for the rare case that a
 device driver only uses consistent allocations, one would have to
 check the return value from dma_set_coherent_mask().
 
@@ -199,9 +206,9 @@ Finally, if your device can only drive the low 24-bits of
 		goto ignore_this_device;
 	}
 
-When dma_set_mask() is successful, and returns zero, the kernel saves
-away this mask you have provided.  The kernel will use this
-information later when you make DMA mappings.
+When dma_set_mask() or dma_set_mask_and_coherent() is successful, and
+returns zero, the kernel saves away this mask you have provided.  The
+kernel will use this information later when you make DMA mappings.
 
 There is a case which we are aware of at this time, which is worth
 mentioning in this documentation.  If your device supports multiple
diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt
index 78a6c56..e865279 100644
--- a/Documentation/DMA-API.txt
+++ b/Documentation/DMA-API.txt
@@ -142,6 +142,14 @@ internal API for use by the platform than an external API for use by
 driver writers.
 
 int
+dma_set_mask_and_coherent(struct device *dev, u64 mask)
+
+Checks to see if the mask is possible and updates the device
+streaming and coherent DMA mask parameters if it is.
+
+Returns: 0 if successful and a negative error if not.
+
+int
 dma_set_mask(struct device *dev, u64 mask)
 
 Checks to see if the mask is possible and updates the device
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 3a8d0a2..ec951f9 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -97,6 +97,20 @@ static inline int dma_set_coherent_mask(struct device *dev, u64 mask)
 }
 #endif
 
+/*
+ * Set both the DMA mask and the coherent DMA mask to the same thing.
+ * Note that we don't check the return value from dma_set_coherent_mask()
+ * as the DMA API guarantees that the coherent DMA mask can be set to
+ * the same or smaller than the streaming DMA mask.
+ */
+static inline int dma_set_mask_and_coherent(struct device *dev, u64 mask)
+{
+	int rc = dma_set_mask(dev, mask);
+	if (rc = 0)
+		dma_set_coherent_mask(dev, mask);
+	return rc;
+}
+
 extern u64 dma_get_required_mask(struct device *dev);
 
 static inline unsigned int dma_get_max_seg_size(struct device *dev)
-- 
1.7.4.4


^ permalink raw reply related

* [PATCH 02/51] DMA-API: net: brocade/bna/bnad.c: fix 32-bit DMA mask handling
From: Russell King @ 2013-09-19 21:26 UTC (permalink / raw)
  To: alsa-devel, b43-dev, devel, devicetree, dri-devel, e1000-devel,
	linux-arm-kernel, linux-crypto, linux-doc, linux-fbdev, linux-ide,
	linux-media, linux-mmc, linux-nvme, linux-omap, linuxppc-dev,
	linux-samsung-soc, linux-scsi, linux-tegra, linux-usb,
	linux-wireless, netdev, Solarflare linux maintainers,
	uclinux-dist-devel
  Cc: Rasesh Mody
In-Reply-To: <20130919212235.GD12758@n2100.arm.linux.org.uk>

The fallback to 32-bit DMA mask is rather odd:
	if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) &&
	    !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) {
		*using_dac = true;
	} else {
		err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
		if (err) {
			err = dma_set_coherent_mask(&pdev->dev,
						    DMA_BIT_MASK(32));
			if (err)
				goto release_regions;
		}

This means we only try and set the coherent DMA mask if we failed to
set a 32-bit DMA mask, and only if both fail do we fail the driver.
Adjust this so that if either setting fails, we fail the driver - and
thereby end up properly setting both the DMA mask and the coherent
DMA mask in the fallback case.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/brocade/bna/bnad.c |   13 ++++---------
 1 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c
index b78e69e..45ce6e2 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.c
+++ b/drivers/net/ethernet/brocade/bna/bnad.c
@@ -3300,17 +3300,12 @@ bnad_pci_init(struct bnad *bnad,
 	err = pci_request_regions(pdev, BNAD_NAME);
 	if (err)
 		goto disable_device;
-	if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) &&
-	    !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) {
+	if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) {
 		*using_dac = true;
 	} else {
-		err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
-		if (err) {
-			err = dma_set_coherent_mask(&pdev->dev,
-						    DMA_BIT_MASK(32));
-			if (err)
-				goto release_regions;
-		}
+		err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+		if (err)
+			goto release_regions;
 		*using_dac = false;
 	}
 	pci_set_master(pdev);
-- 
1.7.4.4


^ permalink raw reply related

* [PATCH 03/51] DMA-API: net: intel/e1000e: fix 32-bit DMA mask handling
From: Russell King @ 2013-09-19 21:27 UTC (permalink / raw)
  To: alsa-devel, b43-dev, devel, devicetree, dri-devel, e1000-devel,
	linux-arm-kernel, linux-crypto, linux-doc, linux-fbdev, linux-ide,
	linux-media, linux-mmc, linux-nvme, linux-omap, linuxppc-dev,
	linux-samsung-soc, linux-scsi, linux-tegra, linux-usb,
	linux-wireless, netdev, Solarflare linux maintainers,
	uclinux-dist-devel
  Cc: Jeff Kirsher, Jesse Brandeburg, Bruce Allan, Carolyn Wyborny,
	Don Skidmore, Greg Rose, Peter P Waskiewicz Jr, Alex Duyck,
	John Ronciak, Tushar Dave
In-Reply-To: <20130919212235.GD12758@n2100.arm.linux.org.uk>

The fallback to 32-bit DMA mask is rather odd:
	err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
	if (!err) {
		err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
		if (!err)
			pci_using_dac = 1;
	} else {
		err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
		if (err) {
			err = dma_set_coherent_mask(&pdev->dev,
						    DMA_BIT_MASK(32));
			if (err) {
				dev_err(&pdev->dev,
					"No usable DMA configuration, aborting\n");
				goto err_dma;
			}
		}
	}
This means we only set the coherent DMA mask in the fallback path if
the DMA mask set failed, which is silly.  This fixes it to set the
coherent DMA mask only if dma_set_mask() succeeded, and to error out
if either fails.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/intel/e1000e/netdev.c |   18 ++++++------------
 1 files changed, 6 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index e87e9b0..519e293 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -6553,21 +6553,15 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		return err;
 
 	pci_using_dac = 0;
-	err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
+	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
 	if (!err) {
-		err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
-		if (!err)
-			pci_using_dac = 1;
+		pci_using_dac = 1;
 	} else {
-		err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+		err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
 		if (err) {
-			err = dma_set_coherent_mask(&pdev->dev,
-						    DMA_BIT_MASK(32));
-			if (err) {
-				dev_err(&pdev->dev,
-					"No usable DMA configuration, aborting\n");
-				goto err_dma;
-			}
+			dev_err(&pdev->dev,
+				"No usable DMA configuration, aborting\n");
+			goto err_dma;
 		}
 	}
 
-- 
1.7.4.4


^ permalink raw reply related

* [PATCH 04/51] DMA-API: net: intel/igb: fix 32-bit DMA mask handling
From: Russell King @ 2013-09-19 21:28 UTC (permalink / raw)
  To: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	b43-dev-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	e1000-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-crypto-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	linux-ide-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	linux-nvme-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-scsi-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA, Solarflare linux maintainers,
	uclinux-dist-devel-ZG0+EudsQA8dtHy/vicBwGD2FQJk+8+b
  Cc: Jeff Kirsher, Jesse Brandeburg, Bruce Allan, Carolyn Wyborny,
	Don Skidmore, Greg Rose, Peter P Waskiewicz Jr, Alex Duyck,
	John Ronciak, Tushar Dave
In-Reply-To: <20130919212235.GD12758-l+eeeJia6m9vn6HldHNs0ANdhmdF6hFW@public.gmane.org>

The fallback to 32-bit DMA mask is rather odd:
	err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
	if (!err) {
		err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
		if (!err)
			pci_using_dac = 1;
	} else {
		err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
		if (err) {
			err = dma_set_coherent_mask(&pdev->dev,
						    DMA_BIT_MASK(32));
			if (err) {
				dev_err(&pdev->dev,
					"No usable DMA configuration, aborting\n");
				goto err_dma;
			}
		}
	}
This means we only set the coherent DMA mask in the fallback path if
the DMA mask set failed, which is silly.  This fixes it to set the
coherent DMA mask only if dma_set_mask() succeeded, and to error out
if either fails.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/net/ethernet/intel/igb/igb_main.c |   18 ++++++------------
 1 files changed, 6 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 8cf44f2..7579383 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2034,21 +2034,15 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		return err;
 
 	pci_using_dac = 0;
-	err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
+	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
 	if (!err) {
-		err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
-		if (!err)
-			pci_using_dac = 1;
+		pci_using_dac = 1;
 	} else {
-		err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+		err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
 		if (err) {
-			err = dma_set_coherent_mask(&pdev->dev,
-						    DMA_BIT_MASK(32));
-			if (err) {
-				dev_err(&pdev->dev,
-					"No usable DMA configuration, aborting\n");
-				goto err_dma;
-			}
+			dev_err(&pdev->dev,
+				"No usable DMA configuration, aborting\n");
+			goto err_dma;
 		}
 	}
 
-- 
1.7.4.4


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox