Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 Apr 2015 15:15:33 +0200
From:      Svatopluk Kraus <onwahe@gmail.com>
To:        freebsd-arm@freebsd.org
Subject:   Re: bus_dmamap_sync() for bounced client buffers from user address space
Message-ID:  <CAFHCsPXiQoAkoj8Xbyup6dmJjPD8K%2BNNTtNTNjmVB=UZOPqHMQ@mail.gmail.com>
In-Reply-To: <CAFHCsPXBdeJX_yB%2B6AvM6jrsWdo8%2BZsJhVd5XK90RvXBFiqWvQ@mail.gmail.com>
References:  <CAFHCsPXBdeJX_yB%2B6AvM6jrsWdo8%2BZsJhVd5XK90RvXBFiqWvQ@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
Hmm, it was intented to be posted to arch. I've already fixed that.
So, I'm sorry for noise here.
Svatopluk Kraus

On Fri, Apr 24, 2015 at 3:11 PM, Svatopluk Kraus <onwahe@gmail.com> wrote:
> DMA can be done on client buffer from user address space. For example,
> thru bus_dmamap_load_uio() when uio->uio_segflg is UIO_USERSPACE. Such
> client buffer can bounce and then, it must be copied to and from
> bounce buffer in bus_dmamap_sync().
>
> Current implementations (in all archs) do not take into account that
> bus_dmamap_sync() is asynchronous for POSTWRITE and POSTREAD in
> general. It can be asynchronous for PREWRITE and PREREAD too. For
> example, in some driver implementations where DMA client buffers
> operations are buffered. In those cases, simple bcopy() is not
> correct.
>
> Demonstration of current implementation (x86) is the following:
>
> -----------------------------
> struct bounce_page {
>     vm_offset_t vaddr;      /* kva of bounce buffer */
>     bus_addr_t  busaddr;    /* Physical address */
>     vm_offset_t datavaddr;  /* kva of client data */
>     bus_addr_t  dataaddr;   /* client physical address */
>     bus_size_t  datacount;  /* client data count */
>     STAILQ_ENTRY(bounce_page) links;
> };
>
>
> if ((op & BUS_DMASYNC_PREWRITE) != 0) {
>     while (bpage != NULL) {
>         if (bpage->datavaddr != 0) {
>             bcopy((void *)bpage->datavaddr,
>                 (void *)bpage->vaddr,
>                 bpage->datacount);
>         } else {
>             physcopyout(bpage->dataaddr,
>                 (void *)bpage->vaddr,
>                 bpage->datacount);
>         }
>         bpage = STAILQ_NEXT(bpage, links);
>     }
>     dmat->bounce_zone->total_bounced++;
> }
> -----------------------------
>
> There are two things:
>
> (1) datavaddr is not always kva of client data, but sometimes it can
> be uva of client data.
> (2) bcopy() can be used only if datavaddr is kva or when map->pmap is
> current pmap.
>
> Note that there is an implication for bus_dmamap_load_uio() with
> uio->uio_segflg set to UIO_USERSPACE that used physical pages are
> in-core and wired. See "man bus_dma".
>
> There is not public interface to check that map->pmap is current pmap.
> So one solution is the following:
>
> if (bpage->datavaddr >= VM_MIN_KERNEL_ADDRESS) {
>         bcopy();
> } else {
>         physcopy();
> }
>
> If there will be public pmap_is_current() then another solution is the
> following:
>
> if (bpage->datavaddr != 0) && pmap_is_current(map->pmap)) {
>         bcopy();
> } else {
>         physcopy();
> }
>
> The second solution implies that context switch must not happen during
> bus_dmamap_sync() called from an interrupt routine. However, IMO, it's
> granted.
>
> Note that map->pmap should be always kernel_pmap for datavaddr >=
> VM_MIN_KERNEL_ADDRESS.
>
> Comments, different solutions, or objections?
>
> Svatopluk Kraus



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAFHCsPXiQoAkoj8Xbyup6dmJjPD8K%2BNNTtNTNjmVB=UZOPqHMQ>