Home | History | Annotate | Line # | Download | only in common
      1 /*
      2  * Copyright  2018 Intel Corporation
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     21  * IN THE SOFTWARE.
     22  */
     23 
     24 #ifndef INTEL_GEM_H
     25 #define INTEL_GEM_H
     26 
     27 #include "drm-uapi/i915_drm.h"
     28 
     29 #include <assert.h>
     30 #include <errno.h>
     31 #include <stdbool.h>
     32 #include <stdint.h>
     33 #include <stdlib.h>
     34 #include <unistd.h>
     35 #include <sys/ioctl.h>
     36 
     37 static inline uint64_t
     38 intel_canonical_address(uint64_t v)
     39 {
     40    /* From the Broadwell PRM Vol. 2a, MI_LOAD_REGISTER_MEM::MemoryAddress:
     41     *
     42     *    "This field specifies the address of the memory location where the
     43     *    register value specified in the DWord above will read from. The
     44     *    address specifies the DWord location of the data. Range =
     45     *    GraphicsVirtualAddress[63:2] for a DWord register GraphicsAddress
     46     *    [63:48] are ignored by the HW and assumed to be in correct
     47     *    canonical form [63:48] == [47]."
     48     */
     49    const int shift = 63 - 47;
     50    return (int64_t)(v << shift) >> shift;
     51 }
     52 
     53 /**
     54  * This returns a 48-bit address with the high 16 bits zeroed.
     55  *
     56  * It's the opposite of intel_canonicalize_address.
     57  */
     58 static inline uint64_t
     59 intel_48b_address(uint64_t v)
     60 {
     61    const int shift = 63 - 47;
     62    return (uint64_t)(v << shift) >> shift;
     63 }
     64 
     65 /**
     66  * Call ioctl, restarting if it is interupted
     67  */
     68 static inline int
     69 intel_ioctl(int fd, unsigned long request, void *arg)
     70 {
     71     int ret;
     72 
     73     do {
     74         ret = ioctl(fd, request, arg);
     75     } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
     76     return ret;
     77 }
     78 
     79 /**
     80  * A wrapper around DRM_IOCTL_I915_QUERY
     81  *
     82  * Unfortunately, the error semantics of this ioctl are rather annoying so
     83  * it's better to have a common helper.
     84  */
     85 static inline int
     86 intel_i915_query_flags(int fd, uint64_t query_id, uint32_t flags,
     87                        void *buffer, int32_t *buffer_len)
     88 {
     89    struct drm_i915_query_item item = {
     90       .query_id = query_id,
     91       .length = *buffer_len,
     92       .flags = flags,
     93       .data_ptr = (uintptr_t)buffer,
     94    };
     95 
     96    struct drm_i915_query args = {
     97       .num_items = 1,
     98       .flags = 0,
     99       .items_ptr = (uintptr_t)&item,
    100    };
    101 
    102    int ret = intel_ioctl(fd, DRM_IOCTL_I915_QUERY, &args);
    103    if (ret != 0)
    104       return -errno;
    105    else if (item.length < 0)
    106       return item.length;
    107 
    108    *buffer_len = item.length;
    109    return 0;
    110 }
    111 
    112 static inline int
    113 intel_i915_query(int fd, uint64_t query_id, void *buffer,
    114                  int32_t *buffer_len)
    115 {
    116    return intel_i915_query_flags(fd, query_id, 0, buffer, buffer_len);
    117 }
    118 
    119 /**
    120  * Query for the given data, allocating as needed
    121  *
    122  * The caller is responsible for freeing the returned pointer.
    123  */
    124 static inline void *
    125 intel_i915_query_alloc(int fd, uint64_t query_id)
    126 {
    127    int32_t length = 0;
    128    int ret = intel_i915_query(fd, query_id, NULL, &length);
    129    if (ret < 0)
    130       return NULL;
    131 
    132    void *data = calloc(1, length);
    133    assert(data != NULL); /* This shouldn't happen in practice */
    134    if (data == NULL)
    135       return NULL;
    136 
    137    ret = intel_i915_query(fd, query_id, data, &length);
    138    assert(ret == 0); /* We should have caught the error above */
    139    if (ret < 0) {
    140       free(data);
    141       return NULL;
    142    }
    143 
    144    return data;
    145 }
    146 
    147 bool intel_gem_supports_syncobj_wait(int fd);
    148 
    149 #endif /* INTEL_GEM_H */
    150