Ignore:
Timestamp:
2018-02-12T10:11:47Z (6 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
5fe3f954
Parents:
2f762a7
git-author:
Ondřej Hlavatý <aearsis@…> (2018-02-05 03:28:50)
git-committer:
Ondřej Hlavatý <aearsis@…> (2018-02-12 10:11:47)
Message:

usb: rethinking DMA buffers

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/usbhost/src/usb_transfer_batch.c

    r2f762a7 r1d758fc  
    103103}
    104104
     105bool usb_transfer_batch_bounce_required(usb_transfer_batch_t *batch)
     106{
     107        if (!batch->size)
     108                return false;
     109
     110        unsigned flags = batch->dma_buffer.policy & DMA_POLICY_FLAGS_MASK;
     111        unsigned required_flags =
     112            batch->ep->required_transfer_buffer_policy & DMA_POLICY_FLAGS_MASK;
     113
     114        if (required_flags & ~flags)
     115                return true;
     116
     117        size_t chunk_mask = dma_policy_chunk_mask(batch->dma_buffer.policy);
     118        size_t required_chunk_mask =
     119             dma_policy_chunk_mask(batch->ep->required_transfer_buffer_policy);
     120
     121        /* If the chunks are at least as large as required, we're good */
     122        if ((required_chunk_mask & ~chunk_mask) == 0)
     123                return false;
     124
     125        size_t start_chunk = batch->offset & ~chunk_mask;
     126        size_t end_chunk = (batch->offset + batch->size - 1) & ~chunk_mask;
     127
     128        /* The requested area crosses a chunk boundary */
     129        if (start_chunk != end_chunk)
     130                return true;
     131
     132        return false;
     133}
     134
    105135errno_t usb_transfer_batch_bounce(usb_transfer_batch_t *batch)
    106136{
     
    108138        assert(!batch->is_bounced);
    109139
    110         if (dma_buffer_is_set(&batch->dma_buffer))
    111                 dma_buffer_unlock(&batch->dma_buffer, batch->buffer_size);
     140        dma_buffer_release(&batch->dma_buffer);
     141
     142        batch->original_buffer = batch->dma_buffer.virt + batch->offset;
    112143
    113144        usb_log_debug("Batch(%p): Buffer cannot be used directly, "
     
    115146
    116147        const errno_t err = dma_buffer_alloc_policy(&batch->dma_buffer,
    117             batch->buffer_size, batch->ep->transfer_buffer_policy);
     148            batch->size, batch->ep->transfer_buffer_policy);
    118149        if (err)
    119150                return err;
     
    121152        /* Copy the data out */
    122153        if (batch->dir == USB_DIRECTION_OUT)
    123                 memcpy(batch->dma_buffer.virt, batch->buffer, batch->buffer_size);
     154                memcpy(batch->dma_buffer.virt,
     155                    batch->original_buffer,
     156                    batch->size);
    124157
    125158        batch->is_bounced = true;
     159        batch->offset = 0;
     160
    126161        return err;
    127 }
    128 
    129 /**
    130  * Prepare a DMA buffer according to endpoint policy.
    131  *
    132  * If the buffer is suitable to be used directly, it is. Otherwise, a bounce
    133  * buffer is created.
    134  */
    135 errno_t usb_transfer_batch_prepare_buffer(usb_transfer_batch_t *batch, char *buf)
    136 {
    137         /* Empty transfers do not need a buffer */
    138         if (batch->buffer_size == 0)
    139                 return EOK;
    140 
    141         batch->buffer = buf;
    142 
    143         const dma_policy_t policy = batch->ep->transfer_buffer_policy;
    144 
    145         /*
    146          * We don't have enough information (yet, WIP) to know if we can skip
    147          * the bounce, so check the conditions carefully.
    148          */
    149         if (!dma_buffer_check_policy(buf, batch->buffer_size, policy))
    150                 return usb_transfer_batch_bounce(batch);
    151 
    152         /* Fill the buffer with virtual address and lock it for DMA */
    153         return dma_buffer_lock(&batch->dma_buffer, buf, batch->buffer_size);
    154162}
    155163
     
    167175            batch, USB_TRANSFER_BATCH_ARGS(*batch));
    168176
    169         if (batch->error == EOK && batch->buffer_size > 0) {
    170                 if (!batch->is_bounced) {
    171                         /* Unlock the buffer for DMA */
    172                         dma_buffer_unlock(&batch->dma_buffer,
    173                             batch->buffer_size);
     177        if (batch->error == EOK && batch->size > 0) {
     178                if (batch->is_bounced) {
     179                        /* We we're forced to use bounce buffer, copy it back */
     180                        if (batch->dir == USB_DIRECTION_IN)
     181                        memcpy(batch->original_buffer,
     182                            batch->dma_buffer.virt,
     183                            batch->transferred_size);
     184
     185                        dma_buffer_free(&batch->dma_buffer);
    174186                }
    175187                else {
    176                         /* We we're forced to use bounce buffer, copy it back */
    177                         if (batch->dir == USB_DIRECTION_IN)
    178                                 memcpy(batch->buffer,
    179                                     batch->dma_buffer.virt,
    180                                     batch->transferred_size);
    181 
    182                         dma_buffer_free(&batch->dma_buffer);
     188                        dma_buffer_release(&batch->dma_buffer);
    183189                }
    184190        }
Note: See TracChangeset for help on using the changeset viewer.