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