root/drivers/media/pci/ivtv/ivtv-queue.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ivtv_buf_copy_from_user
  2. ivtv_buf_swap
  3. ivtv_queue_init
  4. ivtv_enqueue
  5. ivtv_dequeue
  6. ivtv_queue_move_buf
  7. ivtv_queue_move
  8. ivtv_flush_queues
  9. ivtv_stream_alloc
  10. ivtv_stream_free

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3     buffer queues.
   4     Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
   5     Copyright (C) 2004  Chris Kennedy <c@groovy.org>
   6     Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
   7 
   8  */
   9 
  10 #include "ivtv-driver.h"
  11 #include "ivtv-queue.h"
  12 
  13 int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes)
  14 {
  15         if (s->buf_size - buf->bytesused < copybytes)
  16                 copybytes = s->buf_size - buf->bytesused;
  17         if (copy_from_user(buf->buf + buf->bytesused, src, copybytes)) {
  18                 return -EFAULT;
  19         }
  20         buf->bytesused += copybytes;
  21         return copybytes;
  22 }
  23 
  24 void ivtv_buf_swap(struct ivtv_buffer *buf)
  25 {
  26         int i;
  27 
  28         for (i = 0; i < buf->bytesused; i += 4)
  29                 swab32s((u32 *)(buf->buf + i));
  30 }
  31 
  32 void ivtv_queue_init(struct ivtv_queue *q)
  33 {
  34         INIT_LIST_HEAD(&q->list);
  35         q->buffers = 0;
  36         q->length = 0;
  37         q->bytesused = 0;
  38 }
  39 
  40 void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q)
  41 {
  42         unsigned long flags;
  43 
  44         /* clear the buffer if it is going to be enqueued to the free queue */
  45         if (q == &s->q_free) {
  46                 buf->bytesused = 0;
  47                 buf->readpos = 0;
  48                 buf->b_flags = 0;
  49                 buf->dma_xfer_cnt = 0;
  50         }
  51         spin_lock_irqsave(&s->qlock, flags);
  52         list_add_tail(&buf->list, &q->list);
  53         q->buffers++;
  54         q->length += s->buf_size;
  55         q->bytesused += buf->bytesused - buf->readpos;
  56         spin_unlock_irqrestore(&s->qlock, flags);
  57 }
  58 
  59 struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q)
  60 {
  61         struct ivtv_buffer *buf = NULL;
  62         unsigned long flags;
  63 
  64         spin_lock_irqsave(&s->qlock, flags);
  65         if (!list_empty(&q->list)) {
  66                 buf = list_entry(q->list.next, struct ivtv_buffer, list);
  67                 list_del_init(q->list.next);
  68                 q->buffers--;
  69                 q->length -= s->buf_size;
  70                 q->bytesused -= buf->bytesused - buf->readpos;
  71         }
  72         spin_unlock_irqrestore(&s->qlock, flags);
  73         return buf;
  74 }
  75 
  76 static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from,
  77                 struct ivtv_queue *to, int clear)
  78 {
  79         struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list);
  80 
  81         list_move_tail(from->list.next, &to->list);
  82         from->buffers--;
  83         from->length -= s->buf_size;
  84         from->bytesused -= buf->bytesused - buf->readpos;
  85         /* special handling for q_free */
  86         if (clear)
  87                 buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0;
  88         to->buffers++;
  89         to->length += s->buf_size;
  90         to->bytesused += buf->bytesused - buf->readpos;
  91 }
  92 
  93 /* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'.
  94    If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'.
  95    If 'steal' != NULL, then buffers may also taken from that queue if
  96    needed, but only if 'from' is the free queue.
  97 
  98    The buffer is automatically cleared if it goes to the free queue. It is
  99    also cleared if buffers need to be taken from the 'steal' queue and
 100    the 'from' queue is the free queue.
 101 
 102    When 'from' is q_free, then needed_bytes is compared to the total
 103    available buffer length, otherwise needed_bytes is compared to the
 104    bytesused value. For the 'steal' queue the total available buffer
 105    length is always used.
 106 
 107    -ENOMEM is returned if the buffers could not be obtained, 0 if all
 108    buffers where obtained from the 'from' list and if non-zero then
 109    the number of stolen buffers is returned. */
 110 int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal,
 111                     struct ivtv_queue *to, int needed_bytes)
 112 {
 113         unsigned long flags;
 114         int rc = 0;
 115         int from_free = from == &s->q_free;
 116         int to_free = to == &s->q_free;
 117         int bytes_available, bytes_steal;
 118 
 119         spin_lock_irqsave(&s->qlock, flags);
 120         if (needed_bytes == 0) {
 121                 from_free = 1;
 122                 needed_bytes = from->length;
 123         }
 124 
 125         bytes_available = from_free ? from->length : from->bytesused;
 126         bytes_steal = (from_free && steal) ? steal->length : 0;
 127 
 128         if (bytes_available + bytes_steal < needed_bytes) {
 129                 spin_unlock_irqrestore(&s->qlock, flags);
 130                 return -ENOMEM;
 131         }
 132         while (steal && bytes_available < needed_bytes) {
 133                 struct ivtv_buffer *buf = list_entry(steal->list.prev, struct ivtv_buffer, list);
 134                 u16 dma_xfer_cnt = buf->dma_xfer_cnt;
 135 
 136                 /* move buffers from the tail of the 'steal' queue to the tail of the
 137                    'from' queue. Always copy all the buffers with the same dma_xfer_cnt
 138                    value, this ensures that you do not end up with partial frame data
 139                    if one frame is stored in multiple buffers. */
 140                 while (dma_xfer_cnt == buf->dma_xfer_cnt) {
 141                         list_move_tail(steal->list.prev, &from->list);
 142                         rc++;
 143                         steal->buffers--;
 144                         steal->length -= s->buf_size;
 145                         steal->bytesused -= buf->bytesused - buf->readpos;
 146                         buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0;
 147                         from->buffers++;
 148                         from->length += s->buf_size;
 149                         bytes_available += s->buf_size;
 150                         if (list_empty(&steal->list))
 151                                 break;
 152                         buf = list_entry(steal->list.prev, struct ivtv_buffer, list);
 153                 }
 154         }
 155         if (from_free) {
 156                 u32 old_length = to->length;
 157 
 158                 while (to->length - old_length < needed_bytes) {
 159                         ivtv_queue_move_buf(s, from, to, 1);
 160                 }
 161         }
 162         else {
 163                 u32 old_bytesused = to->bytesused;
 164 
 165                 while (to->bytesused - old_bytesused < needed_bytes) {
 166                         ivtv_queue_move_buf(s, from, to, to_free);
 167                 }
 168         }
 169         spin_unlock_irqrestore(&s->qlock, flags);
 170         return rc;
 171 }
 172 
 173 void ivtv_flush_queues(struct ivtv_stream *s)
 174 {
 175         ivtv_queue_move(s, &s->q_io, NULL, &s->q_free, 0);
 176         ivtv_queue_move(s, &s->q_full, NULL, &s->q_free, 0);
 177         ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0);
 178         ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0);
 179 }
 180 
 181 int ivtv_stream_alloc(struct ivtv_stream *s)
 182 {
 183         struct ivtv *itv = s->itv;
 184         int SGsize = sizeof(struct ivtv_sg_host_element) * s->buffers;
 185         int i;
 186 
 187         if (s->buffers == 0)
 188                 return 0;
 189 
 190         IVTV_DEBUG_INFO("Allocate %s%s stream: %d x %d buffers (%dkB total)\n",
 191                 s->dma != PCI_DMA_NONE ? "DMA " : "",
 192                 s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024);
 193 
 194         s->sg_pending = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN);
 195         if (s->sg_pending == NULL) {
 196                 IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name);
 197                 return -ENOMEM;
 198         }
 199         s->sg_pending_size = 0;
 200 
 201         s->sg_processing = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN);
 202         if (s->sg_processing == NULL) {
 203                 IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name);
 204                 kfree(s->sg_pending);
 205                 s->sg_pending = NULL;
 206                 return -ENOMEM;
 207         }
 208         s->sg_processing_size = 0;
 209 
 210         s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element),
 211                                         GFP_KERNEL|__GFP_NOWARN);
 212         if (s->sg_dma == NULL) {
 213                 IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name);
 214                 kfree(s->sg_pending);
 215                 s->sg_pending = NULL;
 216                 kfree(s->sg_processing);
 217                 s->sg_processing = NULL;
 218                 return -ENOMEM;
 219         }
 220         if (ivtv_might_use_dma(s)) {
 221                 s->sg_handle = pci_map_single(itv->pdev, s->sg_dma,
 222                                 sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
 223                 ivtv_stream_sync_for_cpu(s);
 224         }
 225 
 226         /* allocate stream buffers. Initially all buffers are in q_free. */
 227         for (i = 0; i < s->buffers; i++) {
 228                 struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer),
 229                                                 GFP_KERNEL|__GFP_NOWARN);
 230 
 231                 if (buf == NULL)
 232                         break;
 233                 buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL|__GFP_NOWARN);
 234                 if (buf->buf == NULL) {
 235                         kfree(buf);
 236                         break;
 237                 }
 238                 INIT_LIST_HEAD(&buf->list);
 239                 if (ivtv_might_use_dma(s)) {
 240                         buf->dma_handle = pci_map_single(s->itv->pdev,
 241                                 buf->buf, s->buf_size + 256, s->dma);
 242                         ivtv_buf_sync_for_cpu(s, buf);
 243                 }
 244                 ivtv_enqueue(s, buf, &s->q_free);
 245         }
 246         if (i == s->buffers)
 247                 return 0;
 248         IVTV_ERR("Couldn't allocate buffers for %s stream\n", s->name);
 249         ivtv_stream_free(s);
 250         return -ENOMEM;
 251 }
 252 
 253 void ivtv_stream_free(struct ivtv_stream *s)
 254 {
 255         struct ivtv_buffer *buf;
 256 
 257         /* move all buffers to q_free */
 258         ivtv_flush_queues(s);
 259 
 260         /* empty q_free */
 261         while ((buf = ivtv_dequeue(s, &s->q_free))) {
 262                 if (ivtv_might_use_dma(s))
 263                         pci_unmap_single(s->itv->pdev, buf->dma_handle,
 264                                 s->buf_size + 256, s->dma);
 265                 kfree(buf->buf);
 266                 kfree(buf);
 267         }
 268 
 269         /* Free SG Array/Lists */
 270         if (s->sg_dma != NULL) {
 271                 if (s->sg_handle != IVTV_DMA_UNMAPPED) {
 272                         pci_unmap_single(s->itv->pdev, s->sg_handle,
 273                                  sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
 274                         s->sg_handle = IVTV_DMA_UNMAPPED;
 275                 }
 276                 kfree(s->sg_pending);
 277                 kfree(s->sg_processing);
 278                 kfree(s->sg_dma);
 279                 s->sg_pending = NULL;
 280                 s->sg_processing = NULL;
 281                 s->sg_dma = NULL;
 282                 s->sg_pending_size = 0;
 283                 s->sg_processing_size = 0;
 284         }
 285 }

/* [<][>][^][v][top][bottom][index][help] */