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>