Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset cc63815 in mainline


Ignore:
Timestamp:
2018-02-05T00:54:08Z (4 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
lfn, master, serial
Children:
fdc2253b
Parents:
5c69377
git-author:
Ondřej Hlavatý <aearsis@…> (2018-02-02 14:35:14)
git-committer:
Ondřej Hlavatý <aearsis@…> (2018-02-05 00:54:08)
Message:

usb dma_buffer: policy is now just a flag field, implement (un)locking

Location:
uspace/lib
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/drv/include/usbhc_iface.h

    r5c69377 rcc63815  
    103103} usb_target_t;
    104104
     105// FIXME: DMA buffers shall be part of libdrv anyway.
     106typedef unsigned dma_policy_t;
     107
    105108typedef struct usb_pipe_desc {
    106109        /** Endpoint number. */
  • uspace/lib/usb/include/usb/dma_buffer.h

    r5c69377 rcc63815  
    3232 * @brief USB host controller library: DMA buffer helpers
    3333 *
    34  * Simplifies usage of bounce buffers
     34 * Simplifies handling of buffers accessible to hardware. Defines properties of
     35 * such buffer, which can be communicated through IPC to allow higher layers to
     36 * allocate a buffer that is ready to be passed to HW right away (after being
     37 * shared through IPC).
    3538 *
    36  * Currently the minimum size allocated is a page, which is wasteful. Could be
    37  * extended to support memory pools, which will enable smaller units of
    38  * allocation.
     39 * Note that although allocated memory is always page-aligned, the buffer itself
     40 * may be only a part of it, justifying the existence of page-alignment and
     41 * page-crossing flags.
     42 *
     43 * Also, currently the buffers that are allocated are always contiguous and
     44 * page-aligned, regardless of whether the policy requires it. We blindly
     45 * believe this fact in dma_buffer_phys, which will yield wrong results if the
     46 * buffer is not contiguous.
    3947 */
    4048#ifndef LIB_USB_DMA_BUFFER
     
    4351#include <stdint.h>
    4452#include <stdlib.h>
     53#include <usbhc_iface.h>
    4554#include <errno.h>
    4655
    47 typedef const struct dma_policy {
    48         unsigned flags;
     56#define DMA_POLICY_4GiB         (1<<0)  /**< Must use only 32-bit addresses */
     57#define DMA_POLICY_PAGE_ALIGNED (1<<1)  /**< The first pointer must be page-aligned */
     58#define DMA_POLICY_CONTIGUOUS   (1<<2)  /**< Pages must follow each other physically */
     59#define DMA_POLICY_NOT_CROSSING (1<<3)  /**< Buffer must not cross page boundary. (Implies buffer is no larger than page).  */
    4960
    50 #define DMA_POLICY_F_4GiB       (1<<0)  /**< Must use only 32-bit addresses */
    51 #define DMA_POLICY_F_CONTIGUOUS (1<<1)  /**< Pages must follow each other physically */
    52 } dma_policy_t;
     61#define DMA_POLICY_STRICT       (-1U)
     62#define DMA_POLICY_DEFAULT      DMA_POLICY_STRICT
    5363
    5464typedef struct dma_buffer {
     
    5767} dma_buffer_t;
    5868
    59 extern int dma_buffer_alloc(dma_buffer_t *db, size_t size);
    60 extern int dma_buffer_alloc_policy(dma_buffer_t *, size_t, dma_policy_t *);
     69extern errno_t dma_buffer_alloc(dma_buffer_t *db, size_t size);
     70extern errno_t dma_buffer_alloc_policy(dma_buffer_t *, size_t, dma_policy_t);
    6171extern void dma_buffer_free(dma_buffer_t *);
    6272extern uintptr_t dma_buffer_phys(const dma_buffer_t *, void *);
    6373
    64 extern bool dma_buffer_check_policy(const void *, size_t, dma_policy_t *);
     74extern bool dma_buffer_check_policy(const void *, size_t, const dma_policy_t);
     75
     76extern errno_t dma_buffer_lock(dma_buffer_t *, void *, size_t);
     77extern void dma_buffer_unlock(dma_buffer_t *, size_t);
    6578
    6679static inline int dma_buffer_is_set(dma_buffer_t *db)
  • uspace/lib/usb/src/dma_buffer.c

    r5c69377 rcc63815  
    3939#include "usb/dma_buffer.h"
    4040
    41 const dma_policy_t dma_policy_default = {
    42         .flags = DMA_POLICY_F_4GiB | DMA_POLICY_F_CONTIGUOUS,
    43 };
    44 
    45 /**
    46  * The routine of allocating a DMA buffer. Inlined to force optimization for the
    47  * default policy.
    48  *
    49  * FIXME: We ignore the non-presence of contiguous flag, for now.
    50  */
    51 static inline int dma_buffer_alloc_internal(dma_buffer_t *db,
    52     size_t size, const dma_policy_t *policy)
     41/**
     42 * Allocate a DMA buffer.
     43 *
     44 * XXX: Currently cannot make much use of missing constraints, as it always
     45 * allocates page-aligned contiguous buffer. We rely on it in dma_buffer_phys.
     46 *
     47 * @param[in] db dma_buffer_t structure to fill
     48 * @param[in] size Size of the required memory space
     49 * @param[in] policy dma_policy_t flags to guide the allocation
     50 * @return Error code.
     51 */
     52errno_t dma_buffer_alloc_policy(dma_buffer_t *db, size_t size, dma_policy_t policy)
    5353{
    5454        assert(db);
    5555
    5656        const size_t real_size = ALIGN_UP(size, PAGE_SIZE);
    57         const bool need_4gib = !!(policy->flags & DMA_POLICY_F_4GiB);
     57        const bool need_4gib = !!(policy & DMA_POLICY_4GiB);
    5858
    5959        const uintptr_t flags = need_4gib ? DMAMEM_4GiB : 0;
     
    6767
    6868        if (ret == EOK) {
     69                /* Access the pages to force mapping */
     70                volatile char *buf = address;
     71                for (size_t i = 0; i < size; i += PAGE_SIZE)
     72                        buf[i] = 0xff;
     73
    6974                db->virt = address;
    7075                db->phys = phys;
     
    7378}
    7479
    75 /**
    76  * Allocate a DMA buffer.
    77  *
    78  * @param[in] db dma_buffer_t structure to fill
    79  * @param[in] size Size of the required memory space
    80  * @param[in] policy dma_policy_t structure to guide
    81  * @return Error code.
    82  */
    83 int dma_buffer_alloc_policy(dma_buffer_t *db, size_t size,
    84     const dma_policy_t *policy)
    85 {
    86         return dma_buffer_alloc_internal(db, size, policy);
    87 }
    8880
    8981/**
     
    9486 * @return Error code.
    9587 */
    96 int dma_buffer_alloc(dma_buffer_t *db, size_t size)
    97 {
    98         return dma_buffer_alloc_internal(db, size, &dma_policy_default);
     88errno_t dma_buffer_alloc(dma_buffer_t *db, size_t size)
     89{
     90        return dma_buffer_alloc_policy(db, size, DMA_POLICY_DEFAULT);
    9991}
    10092
     
    128120 * Check whether a memory area is compatible with a policy.
    129121 *
    130  * Useful to skip copying, if the buffer is already ready to be given to
    131  * hardware.
    132  */
    133 bool dma_buffer_check_policy(const void *buffer, size_t size, dma_policy_t *policy)
    134 {
    135         /* Buffer must be always page aligned */
    136         if (((uintptr_t) buffer) % PAGE_SIZE)
     122 * Useful to skip copying when the buffer is already ready to be given to
     123 * hardware as is.
     124 *
     125 * Note that the "as_get_physical_mapping" fails when the page is not mapped
     126 * yet, and that the caller is responsible for forcing the mapping.
     127 */
     128bool dma_buffer_check_policy(const void *buffer, size_t size, const dma_policy_t policy)
     129{
     130        uintptr_t addr = (uintptr_t) buffer;
     131
     132        const bool check_4gib       = !!(policy & DMA_POLICY_4GiB);
     133        const bool check_crossing   = !!(policy & DMA_POLICY_NOT_CROSSING);
     134        const bool check_alignment  = !!(policy & DMA_POLICY_PAGE_ALIGNED);
     135        const bool check_contiguous = !!(policy & DMA_POLICY_CONTIGUOUS);
     136
     137        /* Check the two conditions that are easy */
     138        if (check_crossing && (addr + size - 1) / PAGE_SIZE != addr / PAGE_SIZE)
    137139                goto violated;
    138140
    139         const bool check_4gib = !!(policy->flags & DMA_POLICY_F_4GiB);
    140         const bool check_contiguous = !!(policy->flags & DMA_POLICY_F_CONTIGUOUS);
     141        if (check_alignment && ((uintptr_t) buffer) % PAGE_SIZE)
     142                goto violated;
    141143
    142144        /*
     
    145147         */
    146148        if (check_contiguous || check_4gib) {
    147                 const void * virt = buffer;
     149                const void *virt = buffer;
    148150                uintptr_t phys;
    149151
     
    156158                        goto violated;
    157159
    158                 while (size <= PAGE_SIZE) {
     160                while (size >= PAGE_SIZE) {
    159161                        /* Move to the next page */
    160162                        virt += PAGE_SIZE;
     
    182184
    183185/**
     186 * Lock an arbitrary buffer for DMA operations, creating a DMA buffer.
     187 *
     188 * FIXME: To handle page-unaligned buffers, we need to calculate the base
     189 *        address and lock the whole first page. But as the operation is not yet
     190 *        implemented in the kernel, it doesn't matter.
     191 */
     192errno_t dma_buffer_lock(dma_buffer_t *db, void *virt, size_t size)
     193{
     194        db->virt = virt;
     195        return dmamem_map(db->virt, size, 0, 0, &db->phys);
     196}
     197
     198/**
     199 * Unlock a buffer for DMA operations.
     200 */
     201void dma_buffer_unlock(dma_buffer_t *db, size_t size)
     202{
     203        if (db->virt) {
     204                dmamem_unmap(db->virt, size);
     205                db->virt = NULL;
     206                db->phys = 0;
     207        }
     208}
     209
     210/**
    184211 * @}
    185212 */
Note: See TracChangeset for help on using the changeset viewer.