<div dir="ltr"><div class="gmail_extra"><br><br><div class="gmail_quote">2013/6/17 Maarten Lankhorst <span dir="ltr"><<a href="mailto:maarten.lankhorst@canonical.com" target="_blank">maarten.lankhorst@canonical.com</a>></span><br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">Op 17-06-13 15:04, Inki Dae schreef:<br>
<div><div class="h5">><br>
>> -----Original Message-----<br>
>> From: Maarten Lankhorst [mailto:<a href="mailto:maarten.lankhorst@canonical.com">maarten.lankhorst@canonical.com</a>]<br>
>> Sent: Monday, June 17, 2013 8:35 PM<br>
>> To: Inki Dae<br>
>> Cc: <a href="mailto:dri-devel@lists.freedesktop.org">dri-devel@lists.freedesktop.org</a>; <a href="mailto:linux-fbdev@vger.kernel.org">linux-fbdev@vger.kernel.org</a>; linux-<br>
>> <a href="mailto:arm-kernel@lists.infradead.org">arm-kernel@lists.infradead.org</a>; <a href="mailto:linux-media@vger.kernel.org">linux-media@vger.kernel.org</a>;<br>
>> <a href="mailto:daniel@ffwll.ch">daniel@ffwll.ch</a>; <a href="mailto:robdclark@gmail.com">robdclark@gmail.com</a>; <a href="mailto:kyungmin.park@samsung.com">kyungmin.park@samsung.com</a>;<br>
>> <a href="mailto:myungjoo.ham@samsung.com">myungjoo.ham@samsung.com</a>; <a href="mailto:yj44.cho@samsung.com">yj44.cho@samsung.com</a><br>
>> Subject: Re: [RFC PATCH v2] dmabuf-sync: Introduce buffer synchronization<br>
>> framework<br>
>><br>
>> Op 17-06-13 13:15, Inki Dae schreef:<br>
>>> This patch adds a buffer synchronization framework based on DMA BUF[1]<br>
>>> and reservation[2] to use dma-buf resource, and based on ww-mutexes[3]<br>
>>> for lock mechanism.<br>
>>><br>
>>> The purpose of this framework is not only to couple cache operations,<br>
>>> and buffer access control to CPU and DMA but also to provide easy-to-use<br>
>>> interfaces for device drivers and potentially user application<br>
>>> (not implemented for user applications, yet). And this framework can be<br>
>>> used for all dma devices using system memory as dma buffer, especially<br>
>>> for most ARM based SoCs.<br>
>>><br>
>>> Changelog v2:<br>
>>> - use atomic_add_unless to avoid potential bug.<br>
>>> - add a macro for checking valid access type.<br>
>>> - code clean.<br>
>>><br>
>>> The mechanism of this framework has the following steps,<br>
>>> 1. Register dmabufs to a sync object - A task gets a new sync object<br>
>> and<br>
>>> can add one or more dmabufs that the task wants to access.<br>
>>> This registering should be performed when a device context or an<br>
>> event<br>
>>> context such as a page flip event is created or before CPU accesses<br>
> a<br>
>> shared<br>
>>> buffer.<br>
>>><br>
>>> dma_buf_sync_get(a sync object, a dmabuf);<br>
>>><br>
>>> 2. Lock a sync object - A task tries to lock all dmabufs added in<br>
> its<br>
>> own<br>
>>> sync object. Basically, the lock mechanism uses ww-mutex[1] to avoid<br>
>> dead<br>
>>> lock issue and for race condition between CPU and CPU, CPU and DMA,<br>
>> and DMA<br>
>>> and DMA. Taking a lock means that others cannot access all locked<br>
>> dmabufs<br>
>>> until the task that locked the corresponding dmabufs, unlocks all<br>
> the<br>
>> locked<br>
>>> dmabufs.<br>
>>> This locking should be performed before DMA or CPU accesses these<br>
>> dmabufs.<br>
>>> dma_buf_sync_lock(a sync object);<br>
>>><br>
>>> 3. Unlock a sync object - The task unlocks all dmabufs added in its<br>
>> own sync<br>
>>> object. The unlock means that the DMA or CPU accesses to the dmabufs<br>
>> have<br>
>>> been completed so that others may access them.<br>
>>> This unlocking should be performed after DMA or CPU has completed<br>
>> accesses<br>
>>> to the dmabufs.<br>
>>><br>
>>> dma_buf_sync_unlock(a sync object);<br>
>>><br>
>>> 4. Unregister one or all dmabufs from a sync object - A task<br>
>> unregisters<br>
>>> the given dmabufs from the sync object. This means that the task<br>
>> dosen't<br>
>>> want to lock the dmabufs.<br>
>>> The unregistering should be performed after DMA or CPU has completed<br>
>>> accesses to the dmabufs or when dma_buf_sync_lock() is failed.<br>
>>><br>
>>> dma_buf_sync_put(a sync object, a dmabuf);<br>
>>> dma_buf_sync_put_all(a sync object);<br>
>>><br>
>>> The described steps may be summarized as:<br>
>>> get -> lock -> CPU or DMA access to a buffer/s -> unlock -> put<br>
>>><br>
>>> This framework includes the following two features.<br>
>>> 1. read (shared) and write (exclusive) locks - A task is required to<br>
>> declare<br>
>>> the access type when the task tries to register a dmabuf;<br>
>>> READ, WRITE, READ DMA, or WRITE DMA.<br>
>>><br>
>>> The below is example codes,<br>
>>> struct dmabuf_sync *sync;<br>
>>><br>
>>> sync = dmabuf_sync_init(NULL, "test sync");<br>
>>><br>
>>> dmabuf_sync_get(sync, dmabuf, DMA_BUF_ACCESS_READ);<br>
>>> ...<br>
>>><br>
>>> And the below can be used as access types:<br>
>>> DMA_BUF_ACCESS_READ,<br>
>>> - CPU will access a buffer for read.<br>
>>> DMA_BUF_ACCESS_WRITE,<br>
>>> - CPU will access a buffer for read or write.<br>
>>> DMA_BUF_ACCESS_READ | DMA_BUF_ACCESS_DMA,<br>
>>> - DMA will access a buffer for read<br>
>>> DMA_BUF_ACCESS_WRITE | DMA_BUF_ACCESS_DMA,<br>
>>> - DMA will access a buffer for read or write.<br>
>>><br>
>>> 2. Mandatory resource releasing - a task cannot hold a lock<br>
>> indefinitely.<br>
>>> A task may never try to unlock a buffer after taking a lock to the<br>
>> buffer.<br>
>>> In this case, a timer handler to the corresponding sync object is<br>
>> called<br>
>>> in five (default) seconds and then the timed-out buffer is unlocked<br>
>> by work<br>
>>> queue handler to avoid lockups and to enforce resources of the<br>
> buffer.<br>
>>> The below is how to use:<br>
>>> 1. Allocate and Initialize a sync object:<br>
>>> struct dmabuf_sync *sync;<br>
>>><br>
>>> sync = dmabuf_sync_init(NULL, "test sync");<br>
>>> ...<br>
>>><br>
>>> 2. Add a dmabuf to the sync object when setting up dma buffer<br>
>> relevant<br>
>>> registers:<br>
>>> dmabuf_sync_get(sync, dmabuf, DMA_BUF_ACCESS_READ);<br>
>>> ...<br>
>>><br>
>>> 3. Lock all dmabufs of the sync object before DMA or CPU accesses<br>
>>> the dmabufs:<br>
>>> dmabuf_sync_lock(sync);<br>
>>> ...<br>
>>><br>
>>> 4. Now CPU or DMA can access all dmabufs locked in step 3.<br>
>>><br>
>>> 5. Unlock all dmabufs added in a sync object after DMA or CPU<br>
>> access<br>
>>> to these dmabufs is completed:<br>
>>> dmabuf_sync_unlock(sync);<br>
>>><br>
>>> And call the following functions to release all resources,<br>
>>> dmabuf_sync_put_all(sync);<br>
>>> dmabuf_sync_fini(sync);<br>
>>><br>
>>> You can refer to actual example codes:<br>
>>> <a href="https://git.kernel.org/cgit/linux/kernel/git/daeinki/drm-" target="_blank">https://git.kernel.org/cgit/linux/kernel/git/daeinki/drm-</a><br>
>> exynos.git/<br>
>>> commit/?h=dmabuf-<br>
>> sync&id=4030bdee9bab5841ad32faade528d04cc0c5fc94<br>
>>> <a href="https://git.kernel.org/cgit/linux/kernel/git/daeinki/drm-" target="_blank">https://git.kernel.org/cgit/linux/kernel/git/daeinki/drm-</a><br>
>> exynos.git/<br>
>>> commit/?h=dmabuf-<br>
>> sync&id=6ca548e9ea9e865592719ef6b1cde58366af9f5c<br>
>>> The framework performs cache operation based on the previous and current<br>
>> access<br>
>>> types to the dmabufs after the locks to all dmabufs are taken:<br>
>>> Call dma_buf_begin_cpu_access() to invalidate cache if,<br>
>>> previous access type is DMA_BUF_ACCESS_WRITE | DMA and<br>
>>> current access type is DMA_BUF_ACCESS_READ<br>
>>><br>
>>> Call dma_buf_end_cpu_access() to clean cache if,<br>
>>> previous access type is DMA_BUF_ACCESS_WRITE and<br>
>>> current access type is DMA_BUF_ACCESS_READ | DMA<br>
>>><br>
>>> Such cache operations are invoked via dma-buf interfaces so the dma buf<br>
>> exporter<br>
>>> should implement dmabuf->ops->begin_cpu_access/end_cpu_access callbacks.<br>
>>><br>
>>> [1] <a href="http://lwn.net/Articles/470339/" target="_blank">http://lwn.net/Articles/470339/</a><br>
>>> [2] <a href="http://lwn.net/Articles/532616/" target="_blank">http://lwn.net/Articles/532616/</a><br>
>>> [3] <a href="https://patchwork-mail1.kernel.org/patch/2625321/" target="_blank">https://patchwork-mail1.kernel.org/patch/2625321/</a><br>
>>><br>
>> Looks to me like you're just writing an api similar to the android<br>
>> syncpoint for this.<br>
>> Is there any reason you had to reimplement the android syncpoint api?<br>
> Right, only difference is that maybe android sync driver, you mentioned as<br>
> syncpoint, doesn't use dma-buf resource. What I try to do is familiar to<br>
> android's one and also ARM's KDS (Kernel Dependency System). I think I<br>
> already mentioned enough through a document file about why I try to<br>
> implement this approach based on dma-buf; coupling cache operation and<br>
> buffer synchronization between CPU and DMA.<br>
</div></div>Making sure caching works correctly can be handled entirely in the begin_cpu_access/end_cpu_access callbacks, without requiring such.. framework</blockquote><div> </div><div>Cache work will be handled by the begin_cpu_access/end_cpu_access callbacks, actually by dmabuf exporter side. Could you give me your comments again after reading my answer to Ressell? I'd like to make you understand what I try to do.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid"><div class="im">
>> I'm not going into a full review, you may wish to rethink the design<br>
> first.<br>
>> All the criticisms I had with the original design approach still apply.<br>
>><br>
> Isn't that enough if what I try to do is similar to android sync driver?<br>
> It's very simple and that's all I try to do.:)<br>
</div>From what I can tell you should be able to make it work with just the use of fences, you don't need to keep the buffers locked for the entire duration,<br>
just plug in the last fence in the correct slots and you're done..<br></blockquote><div> </div><div>I'm afraid that I don't understand what you say. My approach doesn't use dma fence stuff anymore. Maybe it seems missing something. Could you show me simple example? A little summary is ok. Otherwise, where I can refer to example codes?</div>
<div> </div><div>Thanks,</div><div>Inki Dae</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">
</blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">
</blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">
I'm not sure if the android sync api is compatible enough, but you shouldn't need to write code in this way to make it work..<br>
<div class="im">>><br>
>> A few things that stand out from a casual glance:<br>
>><br>
>> bool is_dmabuf_sync_supported(void)<br>
>> -> any code that needs CONFIG_DMABUF_SYNC should select it in their<br>
>> kconfig<br>
>> runtime enabling/disabling of synchronization is a recipe for disaster,<br>
>> remove the !CONFIG_DMABUF_SYNC fallbacks.<br>
>> NEVER add a runtime way to influence locking behavior.<br>
>><br>
> Not enabling/disabling synchronization feature in runtime. That is<br>
> determined at build time.<br>
><br>
>> Considering you're also holding dmaobj->lock for the entire duration, is<br>
>> there any point to not simply call begin_cpu_access/end_cpu_access, and<br>
>> forget this ugly code ever existed?<br>
> You mean mutex_lock(&sync->lock)? Yeah, it seems unnecessary in that case.<br>
><br>
>> I still don't see the problem you're trying to solve..<br>
>><br>
> It's just to implement a thin sync framework coupling cache operation. This<br>
> approach is based on dma-buf for more generic implementation against android<br>
> sync driver or KDS.<br>
><br>
> The described steps may be summarized as:<br>
> lock -> cache operation -> CPU or DMA access to a buffer/s -> unlock<br>
><br>
> I think that there is no need to get complicated for such approach at least<br>
> for most devices sharing system memory. Simple is best.<br>
><br>
><br>
> Thanks,<br>
> Inki Dae<br>
><br>
>> ~Maarten<br>
<br>
</div><div><div class="h5">--<br>
To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in<br>
the body of a message to <a href="mailto:majordomo@vger.kernel.org">majordomo@vger.kernel.org</a><br>
More majordomo info at <a href="http://vger.kernel.org/majordomo-info.html" target="_blank">http://vger.kernel.org/majordomo-info.html</a><br>
</div></div></blockquote></div><br></div></div>