CTC++ Coverage Report - Execution Profile    #346/1532

Files Summary | Functions Summary | Execution Profile | Index | No Index
First | Previous | Next | Last


File: drivers/char/drm/drm_bufs.c
Instrumentation mode: function-decision-multicondition
TER: 0 % ( 0/823)

Start/ End/    
True False - Line Source

  1 /**
  2  * \file drm_bufs.c
  3  * Generic buffer template
  4  *
  5  * \author Rickard E. (Rik) Faith <faith@valinux.com>
  6  * \author Gareth Hughes <gareth@valinux.com>
  7  */
  8 
  9 /*
  10  * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com
  11  *
  12  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
  13  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  14  * All Rights Reserved.
  15  *
  16  * Permission is hereby granted, free of charge, to any person obtaining a
  17  * copy of this software and associated documentation files (the "Software"),
  18  * to deal in the Software without restriction, including without limitation
  19  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  20  * and/or sell copies of the Software, and to permit persons to whom the
  21  * Software is furnished to do so, subject to the following conditions:
  22  *
  23  * The above copyright notice and this permission notice (including the next
  24  * paragraph) shall be included in all copies or substantial portions of the
  25  * Software.
  26  *
  27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  28  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  29  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  30  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  31  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  32  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  33  * OTHER DEALINGS IN THE SOFTWARE.
  34  */
  35 
  36 #include <linux/vmalloc.h>
  37 #include "drmP.h"
  38 
 
- 39 unsigned long drm_get_resource_start(drm_device_t *dev, unsigned int resource)
  40 {
 - 41    return pci_resource_start(dev->pdev, resource);
  42 }
  43 EXPORT_SYMBOL(drm_get_resource_start);
  44 
 
- 45 unsigned long drm_get_resource_len(drm_device_t *dev, unsigned int resource)
  46 {
    47    return pci_resource_len(dev->pdev, resource);
- 47 ternary-?: ( ( ( ( dev -> pdev ) ) -> resource..
 - 47 return ( ( ( ( ( dev -> pdev ) ) -> resource [..
  48 }
  49 
  50 EXPORT_SYMBOL(drm_get_resource_len);
  51 
 
- 52 static drm_map_list_t *drm_find_matching_map(drm_device_t *dev,
  53                     drm_local_map_t *map)
  54 {
  55    struct list_head *list;
  56 
- 57    list_for_each(list, &dev->maplist->head) {
  58       drm_map_list_t *entry = list_entry(list, drm_map_list_t, head);
  59       if (entry->map && map->type == entry->map->type &&
- 60           entry->map->offset == map->offset) {
 - 60     T && T && T
 - 60     T && T && F
 - 60     T && F && _
 - 60     F && _ && _
 - 61          return entry;
  62       }
  63    }
  64 
 - 65    return NULL;
  66 }
  67 
  68 /*
  69  * Used to allocate 32-bit handles for mappings.
  70  */
  71 #define START_RANGE 0x10000000
  72 #define END_RANGE 0x40000000
  73 
  74 #ifdef _LP64
 
- 75 static __inline__ unsigned int HandleID(unsigned long lhandle,
  76                drm_device_t *dev)
  77 {
  78    static unsigned int map32_handle = START_RANGE;
  79    unsigned int hash;
  80 
- 81    if (lhandle & 0xffffffff00000000) {
  82       hash = map32_handle;
  83       map32_handle += PAGE_SIZE;
- 84       if (map32_handle > END_RANGE)
  85          map32_handle = START_RANGE;
    86    } else
  87       hash = lhandle;
  88 
- 89    while (1) {
  90       drm_map_list_t *_entry;
- 91       list_for_each_entry(_entry, &dev->maplist->head, head) {
- 92          if (_entry->user_token == hash)
 - 93             break;
  94       }
- 95       if (&_entry->head == &dev->maplist->head)
 - 96          return hash;
  97 
  98       hash += PAGE_SIZE;
  99       map32_handle += PAGE_SIZE;
  100    }
  101 }
  102 #else
  103 # define HandleID(x,dev) (unsigned int)(x)
  104 #endif
  105 
  106 /**
  107  * Ioctl to specify a range of memory that is available for mapping by a non-root process.
  108  *
  109  * \param inode device inode.
  110  * \param filp file pointer.
  111  * \param cmd command.
  112  * \param arg pointer to a drm_map structure.
  113  * \return zero on success or a negative value on error.
  114  *
  115  * Adjusts the memory offset to its absolute value according to the mapping
  116  * type.  Adds the map to the map list drm_device::maplist. Adds MTRR's where
  117  * applicable and if supported by the kernel.
  118  */
 
- 119 static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
  120             unsigned int size, drm_map_type_t type,
  121             drm_map_flags_t flags, drm_map_list_t ** maplist)
  122 {
  123    drm_map_t *map;
  124    drm_map_list_t *list;
  125    drm_dma_handle_t *dmah;
  126 
  127    map = drm_alloc(sizeof(*map), DRM_MEM_MAPS);
- 128    if (!map)
 - 129       return -ENOMEM;
  130 
  131    map->offset = offset;
  132    map->size = size;
  133    map->flags = flags;
  134    map->type = type;
  135 
  136    /* Only allow shared memory to be removable since we only keep enough
  137     * book keeping information about shared memory to allow for removal
  138     * when processes fork.
  139     */
- 140    if ((map->flags & _DRM_REMOVABLE) && map->type != _DRM_SHM) {
 - 140   (T) && T
 - 140   (T) && F
 - 140   (F) && _
  141       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
 - 142       return -EINVAL;
  143    }
    144    DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n",
- 144   if (drm_debug)
- 144 do-while (0)
  145         map->offset, map->size, map->type);
- 146    if ((map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK))) {
 - 146   (T) || (_)
 - 146   (F) || (T)
 - 146   (F) || (F)
  147       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
 - 148       return -EINVAL;
  149    }
  150    map->mtrr = -1;
  151    map->handle = NULL;
  152 
    153    switch (map->type) {
 - 154    case _DRM_REGISTERS:
 - 155    case _DRM_FRAME_BUFFER:
  156 #if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__)
  157       if (map->offset + (map->size-1) < map->offset ||
  158           map->offset < virt_to_phys(high_memory)) {
  159          drm_free(map, sizeof(*map), DRM_MEM_MAPS);
  160          return -EINVAL;
  161       }
  162 #endif
  163 #ifdef __alpha__
  164       map->offset += dev->hose->mem_space->start;
  165 #endif
  166       /* Some drivers preinitialize some maps, without the X Server
  167        * needing to be aware of it.  Therefore, we just return success
  168        * when the server tries to create a duplicate map.
  169        */
  170       list = drm_find_matching_map(dev, map);
- 171       if (list != NULL) {
- 172          if (list->map->size != map->size) {
    173             DRM_DEBUG("Matching maps of type %d with "
- 173         if (drm_debug)
- 173       do-while (0)
  174                  "mismatched sizes, (%ld vs %ld)\n",
  175                  map->type, map->size,
  176                  list->map->size);
  177             list->map->size = map->size;
  178          }
  179 
  180          drm_free(map, sizeof(*map), DRM_MEM_MAPS);
  181          *maplist = list;
 - 182          return 0;
  183       }
  184 
- 185       if (drm_core_has_MTRR(dev)) {
  186          if (map->type == _DRM_FRAME_BUFFER ||
- 187              (map->flags & _DRM_WRITE_COMBINING)) {
 - 187       T || (_)
 - 187       F || (T)
 - 187       F || (F)
  188             map->mtrr = mtrr_add(map->offset, map->size,
  189                        MTRR_TYPE_WRCOMB, 1);
  190          }
  191       }
- 192       if (map->type == _DRM_REGISTERS)
  193          map->handle = drm_ioremap(map->offset, map->size, dev);
 - 194       break;
  195 
 - 196    case _DRM_SHM:
  197       map->handle = vmalloc_32(map->size);
    198       DRM_DEBUG("%lu %d %p\n",
- 198     if (drm_debug)
- 198   do-while (0)
  199            map->size, drm_order(map->size), map->handle);
- 200       if (!map->handle) {
  201          drm_free(map, sizeof(*map), DRM_MEM_MAPS);
 - 202          return -ENOMEM;
  203       }
  204       map->offset = (unsigned long)map->handle;
- 205       if (map->flags & _DRM_CONTAINS_LOCK) {
  206          /* Prevent a 2nd X Server from creating a 2nd lock */
- 207          if (dev->lock.hw_lock != NULL) {
  208             vfree(map->handle);
  209             drm_free(map, sizeof(*map), DRM_MEM_MAPS);
 - 210             return -EBUSY;
  211          }
  212          dev->sigdata.lock = dev->lock.hw_lock = map->handle;   /* Pointer to lock */
  213       }
 - 214       break;
 - 215    case _DRM_AGP:
- 216       if (drm_core_has_AGP(dev)) {
  217 #ifdef __alpha__
  218          map->offset += dev->hose->mem_space->start;
  219 #endif
  220          map->offset += dev->agp->base;
  221          map->mtrr = dev->agp->agp_mtrr;   /* for getmap */
  222       }
 - 223       break;
 - 224    case _DRM_SCATTER_GATHER:
- 225       if (!dev->sg) {
  226          drm_free(map, sizeof(*map), DRM_MEM_MAPS);
 - 227          return -EINVAL;
  228       }
  229       map->offset += (unsigned long)dev->sg->virtual;
 - 230       break;
 - 231    case _DRM_CONSISTENT:
  232       /* dma_addr_t is 64bit on i386 with CONFIG_HIGHMEM64G,
  233        * As we're limiting the address to 2^32-1 (or less),
  234        * casting it down to 32 bits is no problem, but we
  235        * need to point to a 64bit variable first. */
  236       dmah = drm_pci_alloc(dev, map->size, map->size, 0xffffffffUL);
- 237       if (!dmah) {
  238          drm_free(map, sizeof(*map), DRM_MEM_MAPS);
 - 239          return -ENOMEM;
  240       }
  241       map->handle = dmah->vaddr;
  242       map->offset = (unsigned long)dmah->busaddr;
  243       kfree(dmah);
 - 244       break;
 - 245    default:
  246       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
 - 247       return -EINVAL;
  248    }
  249 
  250    list = drm_alloc(sizeof(*list), DRM_MEM_MAPS);
- 251    if (!list) {
  252       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
 - 253       return -EINVAL;
  254    }
  255    memset(list, 0, sizeof(*list));
  256    list->map = map;
  257 
  258    mutex_lock(&dev->struct_mutex);
  259    list_add(&list->head, &dev->maplist->head);
  260    /* Assign a 32-bit handle */
  261    /* We do it here so that dev->struct_mutex protects the increment */
  262    list->user_token = HandleID(map->type == _DRM_SHM
    263                 ? (unsigned long)map->handle
- 263 ternary-?: map -> type == _DRM_SHM
  264                 : map->offset, dev);
  265    mutex_unlock(&dev->struct_mutex);
  266 
  267    *maplist = list;
 - 268    return 0;
  269 }
  270 
 
- 271 int drm_addmap(drm_device_t * dev, unsigned int offset,
  272           unsigned int size, drm_map_type_t type,
  273           drm_map_flags_t flags, drm_local_map_t ** map_ptr)
  274 {
  275    drm_map_list_t *list;
  276    int rc;
  277 
  278    rc = drm_addmap_core(dev, offset, size, type, flags, &list);
- 279    if (!rc)
  280       *map_ptr = list->map;
 - 281    return rc;
  282 }
  283 
  284 EXPORT_SYMBOL(drm_addmap);
  285 
 
- 286 int drm_addmap_ioctl(struct inode *inode, struct file *filp,
  287            unsigned int cmd, unsigned long arg)
  288 {
  289    drm_file_t *priv = filp->private_data;
  290    drm_device_t *dev = priv->head->dev;
  291    drm_map_t map;
  292    drm_map_list_t *maplist;
  293    drm_map_t __user *argp = (void __user *)arg;
  294    int err;
  295 
- 296    if (!(filp->f_mode & 3))
 - 297       return -EACCES;   /* Require read/write */
  298 
- 299    if (copy_from_user(&map, argp, sizeof(map))) {
 - 300       return -EFAULT;
  301    }
  302 
- 303    if (!(capable(CAP_SYS_ADMIN) || map.type == _DRM_AGP))
 - 303   !(F || F)
 - 303   !(T || _)
 - 303   !(F || T)
 - 304       return -EPERM;
  305 
  306    err = drm_addmap_core(dev, map.offset, map.size, map.type, map.flags,
  307                &maplist);
  308 
- 309    if (err)
 - 310       return err;
  311 
- 312    if (copy_to_user(argp, maplist->map, sizeof(drm_map_t)))
 - 313       return -EFAULT;
  314 
  315    /* avoid a warning on 64-bit, this casting isn't very nice, but the API is set so too late */
- 316    if (put_user((void *)(unsigned long)maplist->user_token, &argp->handle))
 - 317       return -EFAULT;
 - 318    return 0;
  319 }
  320 
  321 /**
  322  * Remove a map private from list and deallocate resources if the mapping
  323  * isn't in use.
  324  *
  325  * \param inode device inode.
  326  * \param filp file pointer.
  327  * \param cmd command.
  328  * \param arg pointer to a drm_map_t structure.
  329  * \return zero on success or a negative value on error.
  330  *
  331  * Searches the map on drm_device::maplist, removes it from the list, see if
  332  * its being used, and free any associate resource (such as MTRR's) if it's not
  333  * being on use.
  334  *
  335  * \sa drm_addmap
  336  */
 
- 337 int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
  338 {
  339    struct list_head *list;
  340    drm_map_list_t *r_list = NULL;
  341    drm_dma_handle_t dmah;
  342 
  343    /* Find the list entry for the map and remove it */
- 344    list_for_each(list, &dev->maplist->head) {
  345       r_list = list_entry(list, drm_map_list_t, head);
  346 
- 347       if (r_list->map == map) {
  348          list_del(list);
  349          drm_free(list, sizeof(*list), DRM_MEM_MAPS);
 - 350          break;
  351       }
  352    }
  353 
  354    /* List has wrapped around to the head pointer, or it's empty and we
  355     * didn't find anything.
  356     */
- 357    if (list == (&dev->maplist->head)) {
 - 358       return -EINVAL;
  359    }
  360 
    361    switch (map->type) {
 - 362    case _DRM_REGISTERS:
  363       drm_ioremapfree(map->handle, map->size, dev);
  364       /* FALLTHROUGH */
 - 365    case _DRM_FRAME_BUFFER:
- 366       if (drm_core_has_MTRR(dev) && map->mtrr >= 0) {
 - 366     T && T
 - 366     T && F
 - 366     F && _
  367          int retcode;
  368          retcode = mtrr_del(map->mtrr, map->offset, map->size);
    369          DRM_DEBUG("mtrr_del=%d\n", retcode);
- 369       if (drm_debug)
- 369     do-while (0)
  370       }
 - 371       break;
 - 372    case _DRM_SHM:
  373       vfree(map->handle);
 - 374       break;
 - 375    case _DRM_AGP:
 - 376    case _DRM_SCATTER_GATHER:
 - 377       break;
 - 378    case _DRM_CONSISTENT:
  379       dmah.vaddr = map->handle;
  380       dmah.busaddr = map->offset;
  381       dmah.size = map->size;
  382       __drm_pci_free(dev, &dmah);
 - 383       break;
  384    }
  385    drm_free(map, sizeof(*map), DRM_MEM_MAPS);
  386 
 - 387    return 0;
  388 }
  389 EXPORT_SYMBOL(drm_rmmap_locked);
  390 
 
- 391 int drm_rmmap(drm_device_t *dev, drm_local_map_t *map)
  392 {
  393    int ret;
  394 
  395    mutex_lock(&dev->struct_mutex);
  396    ret = drm_rmmap_locked(dev, map);
  397    mutex_unlock(&dev->struct_mutex);
  398 
 - 399    return ret;
  400 }
  401 EXPORT_SYMBOL(drm_rmmap);
  402 
  403 /* The rmmap ioctl appears to be unnecessary.  All mappings are torn down on
  404  * the last close of the device, and this is necessary for cleanup when things
  405  * exit uncleanly.  Therefore, having userland manually remove mappings seems
  406  * like a pointless exercise since they're going away anyway.
  407  *
  408  * One use case might be after addmap is allowed for normal users for SHM and
  409  * gets used by drivers that the server doesn't need to care about.  This seems
  410  * unlikely.
  411  */
 
- 412 int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
  413           unsigned int cmd, unsigned long arg)
  414 {
  415    drm_file_t *priv = filp->private_data;
  416    drm_device_t *dev = priv->head->dev;
  417    drm_map_t request;
  418    drm_local_map_t *map = NULL;
  419    struct list_head *list;
  420    int ret;
  421 
- 422    if (copy_from_user(&request, (drm_map_t __user *) arg, sizeof(request))) {
 - 423       return -EFAULT;
  424    }
  425 
  426    mutex_lock(&dev->struct_mutex);
- 427    list_for_each(list, &dev->maplist->head) {
  428       drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);
  429 
  430       if (r_list->map &&
  431           r_list->user_token == (unsigned long)request.handle &&
- 432           r_list->map->flags & _DRM_REMOVABLE) {
 - 432     T && T && T
 - 432     T && T && F
 - 432     T && F && _
 - 432     F && _ && _
  433          map = r_list->map;
 - 434          break;
  435       }
  436    }
  437 
  438    /* List has wrapped around to the head pointer, or its empty we didn't
  439     * find anything.
  440     */
- 441    if (list == (&dev->maplist->head)) {
  442       mutex_unlock(&dev->struct_mutex);
 - 443       return -EINVAL;
  444    }
  445 
- 446    if (!map)
 - 447       return -EINVAL;
  448 
  449    /* Register and framebuffer maps are permanent */
- 450    if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) {
 - 450   (T) || (_)
 - 450   (F) || (T)
 - 450   (F) || (F)
  451       mutex_unlock(&dev->struct_mutex);
 - 452       return 0;
  453    }
  454 
  455    ret = drm_rmmap_locked(dev, map);
  456 
  457    mutex_unlock(&dev->struct_mutex);
  458 
 - 459    return ret;
  460 }
  461 
  462 /**
  463  * Cleanup after an error on one of the addbufs() functions.
  464  *
  465  * \param dev DRM device.
  466  * \param entry buffer entry where the error occurred.
  467  *
  468  * Frees any pages and buffers associated with the given entry.
  469  */
 
- 470 static void drm_cleanup_buf_error(drm_device_t * dev, drm_buf_entry_t * entry)
  471 {
  472    int i;
  473 
- 474    if (entry->seg_count)&nb