Home | History | Annotate | Download | only in pipe-loader
      1 /**************************************************************************
      2  *
      3  * Copyright 2011 Intel Corporation
      4  * Copyright 2012 Francisco Jerez
      5  * All Rights Reserved.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a
      8  * copy of this software and associated documentation files (the
      9  * "Software"), to deal in the Software without restriction, including
     10  * without limitation the rights to use, copy, modify, merge, publish,
     11  * distribute, sub license, and/or sell copies of the Software, and to
     12  * permit persons to whom the Software is furnished to do so, subject to
     13  * the following conditions:
     14  *
     15  * The above copyright notice and this permission notice (including the
     16  * next paragraph) shall be included in all copies or substantial portions
     17  * of the Software.
     18  *
     19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     22  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     26  *
     27  * Authors:
     28  *    Kristian Hgsberg <krh (at) bitplanet.net>
     29  *    Benjamin Franzke <benjaminfranzke (at) googlemail.com>
     30  *
     31  **************************************************************************/
     32 
     33 #include <fcntl.h>
     34 #include <stdio.h>
     35 #include <xf86drm.h>
     36 #include <unistd.h>
     37 
     38 #include "loader.h"
     39 #include "target-helpers/drm_helper_public.h"
     40 #include "state_tracker/drm_driver.h"
     41 #include "pipe_loader_priv.h"
     42 
     43 #include "util/u_memory.h"
     44 #include "util/u_dl.h"
     45 #include "util/u_debug.h"
     46 
     47 #define DRM_RENDER_NODE_DEV_NAME_FORMAT "%s/renderD%d"
     48 #define DRM_RENDER_NODE_MAX_NODES 63
     49 #define DRM_RENDER_NODE_MIN_MINOR 128
     50 #define DRM_RENDER_NODE_MAX_MINOR (DRM_RENDER_NODE_MIN_MINOR + DRM_RENDER_NODE_MAX_NODES)
     51 
     52 struct pipe_loader_drm_device {
     53    struct pipe_loader_device base;
     54    const struct drm_driver_descriptor *dd;
     55 #ifndef GALLIUM_STATIC_TARGETS
     56    struct util_dl_library *lib;
     57 #endif
     58    int fd;
     59 };
     60 
     61 #define pipe_loader_drm_device(dev) ((struct pipe_loader_drm_device *)dev)
     62 
     63 static const struct pipe_loader_ops pipe_loader_drm_ops;
     64 
     65 #ifdef GALLIUM_STATIC_TARGETS
     66 static const struct drm_conf_ret throttle_ret = {
     67    DRM_CONF_INT,
     68    {2},
     69 };
     70 
     71 static const struct drm_conf_ret share_fd_ret = {
     72    DRM_CONF_BOOL,
     73    {true},
     74 };
     75 
     76 static inline const struct drm_conf_ret *
     77 configuration_query(enum drm_conf conf)
     78 {
     79    switch (conf) {
     80    case DRM_CONF_THROTTLE:
     81       return &throttle_ret;
     82    case DRM_CONF_SHARE_FD:
     83       return &share_fd_ret;
     84    default:
     85       break;
     86    }
     87    return NULL;
     88 }
     89 
     90 static const struct drm_driver_descriptor driver_descriptors[] = {
     91     {
     92         .driver_name = "i915",
     93         .create_screen = pipe_i915_create_screen,
     94         .configuration = configuration_query,
     95     },
     96 #ifdef USE_VC4_SIMULATOR
     97     /* VC4 simulator and ILO (i965) are mutually exclusive (error at
     98      * configure). As the latter is unconditionally added, keep this one above
     99      * it.
    100      */
    101     {
    102         .driver_name = "i965",
    103         .create_screen = pipe_vc4_create_screen,
    104         .configuration = configuration_query,
    105     },
    106 #endif
    107     {
    108         .driver_name = "i965",
    109         .create_screen = pipe_ilo_create_screen,
    110         .configuration = configuration_query,
    111     },
    112     {
    113         .driver_name = "nouveau",
    114         .create_screen = pipe_nouveau_create_screen,
    115         .configuration = configuration_query,
    116     },
    117     {
    118         .driver_name = "r300",
    119         .create_screen = pipe_r300_create_screen,
    120         .configuration = configuration_query,
    121     },
    122     {
    123         .driver_name = "r600",
    124         .create_screen = pipe_r600_create_screen,
    125         .configuration = configuration_query,
    126     },
    127     {
    128         .driver_name = "radeonsi",
    129         .create_screen = pipe_radeonsi_create_screen,
    130         .configuration = configuration_query,
    131     },
    132     {
    133         .driver_name = "vmwgfx",
    134         .create_screen = pipe_vmwgfx_create_screen,
    135         .configuration = configuration_query,
    136     },
    137     {
    138         .driver_name = "kgsl",
    139         .create_screen = pipe_freedreno_create_screen,
    140         .configuration = configuration_query,
    141     },
    142     {
    143         .driver_name = "msm",
    144         .create_screen = pipe_freedreno_create_screen,
    145         .configuration = configuration_query,
    146     },
    147     {
    148         .driver_name = "virtio_gpu",
    149         .create_screen = pipe_virgl_create_screen,
    150         .configuration = configuration_query,
    151     },
    152     {
    153         .driver_name = "vc4",
    154         .create_screen = pipe_vc4_create_screen,
    155         .configuration = configuration_query,
    156     },
    157     {
    158         .driver_name = "etnaviv",
    159         .create_screen = pipe_etna_create_screen,
    160         .configuration = configuration_query,
    161     },
    162     {
    163         .driver_name = "imx-drm",
    164         .create_screen = pipe_imx_drm_create_screen,
    165         .configuration = configuration_query,
    166     }
    167 };
    168 #endif
    169 
    170 bool
    171 pipe_loader_drm_probe_fd(struct pipe_loader_device **dev, int fd)
    172 {
    173    struct pipe_loader_drm_device *ddev = CALLOC_STRUCT(pipe_loader_drm_device);
    174    int vendor_id, chip_id;
    175 
    176    if (!ddev)
    177       return false;
    178 
    179    if (loader_get_pci_id_for_fd(fd, &vendor_id, &chip_id)) {
    180       ddev->base.type = PIPE_LOADER_DEVICE_PCI;
    181       ddev->base.u.pci.vendor_id = vendor_id;
    182       ddev->base.u.pci.chip_id = chip_id;
    183    } else {
    184       ddev->base.type = PIPE_LOADER_DEVICE_PLATFORM;
    185    }
    186    ddev->base.ops = &pipe_loader_drm_ops;
    187    ddev->fd = fd;
    188 
    189    ddev->base.driver_name = loader_get_driver_for_fd(fd);
    190    if (!ddev->base.driver_name)
    191       goto fail;
    192 
    193 #ifdef GALLIUM_STATIC_TARGETS
    194    for (int i = 0; i < ARRAY_SIZE(driver_descriptors); i++) {
    195       if (strcmp(driver_descriptors[i].driver_name, ddev->base.driver_name) == 0) {
    196          ddev->dd = &driver_descriptors[i];
    197          break;
    198       }
    199    }
    200    if (!ddev->dd)
    201       goto fail;
    202 #else
    203    ddev->lib = pipe_loader_find_module(&ddev->base, PIPE_SEARCH_DIR);
    204    if (!ddev->lib)
    205       goto fail;
    206 
    207    ddev->dd = (const struct drm_driver_descriptor *)
    208       util_dl_get_proc_address(ddev->lib, "driver_descriptor");
    209 
    210    /* sanity check on the driver name */
    211    if (!ddev->dd || strcmp(ddev->dd->driver_name, ddev->base.driver_name) != 0)
    212       goto fail;
    213 #endif
    214 
    215    *dev = &ddev->base;
    216    return true;
    217 
    218   fail:
    219 #ifndef GALLIUM_STATIC_TARGETS
    220    if (ddev->lib)
    221       util_dl_close(ddev->lib);
    222 #endif
    223    FREE(ddev);
    224    return false;
    225 }
    226 
    227 static int
    228 open_drm_render_node_minor(int minor)
    229 {
    230    char path[PATH_MAX];
    231    snprintf(path, sizeof(path), DRM_RENDER_NODE_DEV_NAME_FORMAT, DRM_DIR_NAME,
    232             minor);
    233    return loader_open_device(path);
    234 }
    235 
    236 int
    237 pipe_loader_drm_probe(struct pipe_loader_device **devs, int ndev)
    238 {
    239    int i, j, fd;
    240 
    241    for (i = DRM_RENDER_NODE_MIN_MINOR, j = 0;
    242         i <= DRM_RENDER_NODE_MAX_MINOR; i++) {
    243       struct pipe_loader_device *dev;
    244 
    245       fd = open_drm_render_node_minor(i);
    246       if (fd < 0)
    247          continue;
    248 
    249       if (!pipe_loader_drm_probe_fd(&dev, fd)) {
    250          close(fd);
    251          continue;
    252       }
    253 
    254       if (j < ndev) {
    255          devs[j] = dev;
    256       } else {
    257          close(fd);
    258          dev->ops->release(&dev);
    259       }
    260       j++;
    261    }
    262 
    263    return j;
    264 }
    265 
    266 static void
    267 pipe_loader_drm_release(struct pipe_loader_device **dev)
    268 {
    269    struct pipe_loader_drm_device *ddev = pipe_loader_drm_device(*dev);
    270 
    271 #ifndef GALLIUM_STATIC_TARGETS
    272    if (ddev->lib)
    273       util_dl_close(ddev->lib);
    274 #endif
    275 
    276    close(ddev->fd);
    277    FREE(ddev->base.driver_name);
    278    FREE(ddev);
    279    *dev = NULL;
    280 }
    281 
    282 static const struct drm_conf_ret *
    283 pipe_loader_drm_configuration(struct pipe_loader_device *dev,
    284                               enum drm_conf conf)
    285 {
    286    struct pipe_loader_drm_device *ddev = pipe_loader_drm_device(dev);
    287 
    288    if (!ddev->dd->configuration)
    289       return NULL;
    290 
    291    return ddev->dd->configuration(conf);
    292 }
    293 
    294 static struct pipe_screen *
    295 pipe_loader_drm_create_screen(struct pipe_loader_device *dev)
    296 {
    297    struct pipe_loader_drm_device *ddev = pipe_loader_drm_device(dev);
    298 
    299    return ddev->dd->create_screen(ddev->fd);
    300 }
    301 
    302 static const struct pipe_loader_ops pipe_loader_drm_ops = {
    303    .create_screen = pipe_loader_drm_create_screen,
    304    .configuration = pipe_loader_drm_configuration,
    305    .release = pipe_loader_drm_release
    306 };
    307