• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2023 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 #include "xe/intel_device_info.h"
25 
26 #include "common/intel_gem.h"
27 #include "dev/intel_device_info.h"
28 #include "dev/intel_hwconfig.h"
29 
30 #include "util/log.h"
31 
32 #include "drm-uapi/xe_drm.h"
33 
34 static void *
xe_query_alloc_fetch(int fd,uint32_t query_id,int32_t * len)35 xe_query_alloc_fetch(int fd, uint32_t query_id, int32_t *len)
36 {
37    struct drm_xe_device_query query = {
38       .query = query_id,
39    };
40    if (intel_ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query))
41       return NULL;
42 
43    void *data = calloc(1, query.size);
44    if (!data)
45       return NULL;
46 
47    query.data = (uintptr_t)data;
48    if (intel_ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query))
49       goto data_query_failed;
50 
51    if (len)
52       *len = query.size;
53    return data;
54 
55 data_query_failed:
56    free(data);
57    return NULL;
58 }
59 
60 static bool
xe_query_config(int fd,struct intel_device_info * devinfo)61 xe_query_config(int fd, struct intel_device_info *devinfo)
62 {
63    struct drm_xe_query_config *config;
64    config = xe_query_alloc_fetch(fd, DRM_XE_DEVICE_QUERY_CONFIG, NULL);
65    if (!config)
66       return false;
67 
68    if (config->info[DRM_XE_QUERY_CONFIG_FLAGS] & DRM_XE_QUERY_CONFIG_FLAG_HAS_VRAM)
69       devinfo->has_local_mem = true;
70 
71    devinfo->revision = (config->info[DRM_XE_QUERY_CONFIG_REV_AND_DEVICE_ID] >> 16) & 0xFFFF;
72    devinfo->gtt_size = 1ull << config->info[DRM_XE_QUERY_CONFIG_VA_BITS];
73    devinfo->mem_alignment = config->info[DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT];
74 
75    free(config);
76    return true;
77 }
78 
79 bool
intel_device_info_xe_query_regions(int fd,struct intel_device_info * devinfo,bool update)80 intel_device_info_xe_query_regions(int fd, struct intel_device_info *devinfo,
81                                    bool update)
82 {
83    struct drm_xe_query_mem_regions *regions;
84    regions = xe_query_alloc_fetch(fd, DRM_XE_DEVICE_QUERY_MEM_REGIONS, NULL);
85    if (!regions)
86       return false;
87 
88    for (int i = 0; i < regions->num_mem_regions; i++) {
89       struct drm_xe_mem_region *region = &regions->mem_regions[i];
90 
91       switch (region->mem_class) {
92       case DRM_XE_MEM_REGION_CLASS_SYSMEM: {
93          if (!update) {
94             devinfo->mem.sram.mem.klass = region->mem_class;
95             devinfo->mem.sram.mem.instance = region->instance;
96             devinfo->mem.sram.mappable.size = region->total_size;
97          } else {
98             assert(devinfo->mem.sram.mem.klass == region->mem_class);
99             assert(devinfo->mem.sram.mem.instance == region->instance);
100             assert(devinfo->mem.sram.mappable.size == region->total_size);
101          }
102          /* if running without elevated privileges Xe reports used == 0 */
103          devinfo->mem.sram.mappable.free = region->total_size - region->used;
104          break;
105       }
106       case DRM_XE_MEM_REGION_CLASS_VRAM: {
107          if (!update) {
108             devinfo->mem.vram.mem.klass = region->mem_class;
109             devinfo->mem.vram.mem.instance = region->instance;
110             devinfo->mem.vram.mappable.size = region->cpu_visible_size;
111             devinfo->mem.vram.unmappable.size = region->total_size - region->cpu_visible_size;
112          } else {
113             assert(devinfo->mem.vram.mem.klass == region->mem_class);
114             assert(devinfo->mem.vram.mem.instance == region->instance);
115             assert(devinfo->mem.vram.mappable.size == region->cpu_visible_size);
116             assert(devinfo->mem.vram.unmappable.size == (region->total_size - region->cpu_visible_size));
117          }
118          devinfo->mem.vram.mappable.free = devinfo->mem.vram.mappable.size - region->cpu_visible_used;
119          devinfo->mem.vram.unmappable.free = devinfo->mem.vram.unmappable.size - (region->used - region->cpu_visible_used);
120          break;
121       }
122       default:
123          mesa_loge("Unhandled Xe memory class");
124          break;
125       }
126    }
127 
128    devinfo->mem.use_class_instance = true;
129    free(regions);
130    return true;
131 }
132 
133 static bool
xe_query_gts(int fd,struct intel_device_info * devinfo)134 xe_query_gts(int fd, struct intel_device_info *devinfo)
135 {
136    struct drm_xe_query_gt_list *gt_list;
137    gt_list = xe_query_alloc_fetch(fd, DRM_XE_DEVICE_QUERY_GT_LIST, NULL);
138    if (!gt_list)
139       return false;
140 
141    for (uint32_t i = 0; i < gt_list->num_gt; i++) {
142       if (gt_list->gt_list[i].type == DRM_XE_QUERY_GT_TYPE_MAIN)
143          devinfo->timestamp_frequency = gt_list->gt_list[i].reference_clock;
144    }
145 
146    free(gt_list);
147    return true;
148 }
149 
150 void *
intel_device_info_xe_query_hwconfig(int fd,int32_t * len)151 intel_device_info_xe_query_hwconfig(int fd, int32_t *len)
152 {
153    return xe_query_alloc_fetch(fd, DRM_XE_DEVICE_QUERY_HWCONFIG, len);
154 }
155 
156 static bool
xe_query_process_hwconfig(int fd,struct intel_device_info * devinfo)157 xe_query_process_hwconfig(int fd, struct intel_device_info *devinfo)
158 {
159    int32_t len;
160    void *data = intel_device_info_xe_query_hwconfig(fd, &len);
161 
162    if (!data)
163       return false;
164 
165    bool ret = intel_hwconfig_process_table(devinfo, data, len);
166    free(data);
167    return ret;
168 }
169 
170 static void
xe_compute_topology(struct intel_device_info * devinfo,const uint8_t * geo_dss_mask,const uint32_t geo_dss_num_bytes,const uint32_t * eu_per_dss_mask)171 xe_compute_topology(struct intel_device_info * devinfo,
172                     const uint8_t *geo_dss_mask,
173                     const uint32_t geo_dss_num_bytes,
174                     const uint32_t *eu_per_dss_mask)
175 {
176    intel_device_info_topology_reset_masks(devinfo);
177    /* TGL/DG1/ADL-P: 1 slice x 6 dual sub slices
178     * RKL/ADL-S: 1 slice x 2 dual sub slices
179     * DG2: 8 slices x 4 dual sub slices
180     */
181    if (devinfo->verx10 >= 125) {
182       devinfo->max_slices = 8;
183       devinfo->max_subslices_per_slice = 4;
184    } else {
185       devinfo->max_slices = 1;
186       devinfo->max_subslices_per_slice = 6;
187    }
188    devinfo->max_eus_per_subslice = 16;
189    devinfo->subslice_slice_stride = 1;
190    devinfo->eu_slice_stride = DIV_ROUND_UP(16 * 4, 8);
191    devinfo->eu_subslice_stride = DIV_ROUND_UP(16, 8);
192 
193    assert((sizeof(uint32_t) * 8) >= devinfo->max_subslices_per_slice);
194    assert((sizeof(uint32_t) * 8) >= devinfo->max_eus_per_subslice);
195 
196    const uint32_t dss_mask_in_slice = (1u << devinfo->max_subslices_per_slice) - 1;
197    struct slice {
198       uint32_t dss_mask;
199       struct {
200          bool enabled;
201          uint32_t eu_mask;
202       } dual_subslice[INTEL_DEVICE_MAX_SUBSLICES];
203    } slices[INTEL_DEVICE_MAX_SLICES] = {};
204 
205    /* Compute and fill slices */
206    for (unsigned s = 0; s < devinfo->max_slices; s++) {
207       const unsigned first_bit = s * devinfo->max_subslices_per_slice;
208       const unsigned dss_index = first_bit / 8;
209       const unsigned shift = first_bit % 8;
210 
211       assert(geo_dss_num_bytes > dss_index);
212 
213       const uint32_t *dss_mask_ptr = (const uint32_t *)&geo_dss_mask[dss_index];
214       uint32_t dss_mask = *dss_mask_ptr;
215       dss_mask >>= shift;
216       dss_mask &= dss_mask_in_slice;
217 
218       if (dss_mask) {
219          slices[s].dss_mask = dss_mask;
220          for (uint32_t dss = 0; dss < devinfo->max_subslices_per_slice; dss++) {
221             if ((1u << dss) & slices[s].dss_mask) {
222                slices[s].dual_subslice[dss].enabled = true;
223                slices[s].dual_subslice[dss].eu_mask = *eu_per_dss_mask;
224             }
225          }
226       }
227    }
228 
229    /* Set devinfo masks */
230    for (unsigned s = 0; s < devinfo->max_slices; s++) {
231       if (!slices[s].dss_mask)
232          continue;
233 
234       devinfo->slice_masks |= (1u << s);
235 
236       for (unsigned ss = 0; ss < devinfo->max_subslices_per_slice; ss++) {
237          if (!slices[s].dual_subslice[ss].eu_mask)
238             continue;
239 
240          devinfo->subslice_masks[s * devinfo->subslice_slice_stride +
241                                  ss / 8] |= (1u << (ss % 8));
242 
243          for (unsigned eu = 0; eu < devinfo->max_eus_per_subslice; eu++) {
244             if (!(slices[s].dual_subslice[ss].eu_mask & (1u << eu)))
245                continue;
246 
247             devinfo->eu_masks[s * devinfo->eu_slice_stride +
248                               ss * devinfo->eu_subslice_stride +
249                               eu / 8] |= (1u << (eu % 8));
250          }
251       }
252 
253    }
254 
255    intel_device_info_topology_update_counts(devinfo);
256    intel_device_info_update_pixel_pipes(devinfo, devinfo->subslice_masks);
257    intel_device_info_update_l3_banks(devinfo);
258 }
259 
260 static bool
xe_query_topology(int fd,struct intel_device_info * devinfo)261 xe_query_topology(int fd, struct intel_device_info *devinfo)
262 {
263    struct drm_xe_query_topology_mask *topology;
264    int32_t len;
265    topology = xe_query_alloc_fetch(fd, DRM_XE_DEVICE_QUERY_GT_TOPOLOGY, &len);
266    if (!topology)
267       return false;
268 
269    uint32_t geo_dss_num_bytes = 0, *eu_per_dss_mask = NULL;
270    uint8_t *geo_dss_mask = NULL, *tmp;
271    const struct drm_xe_query_topology_mask *head = topology;
272 
273    tmp = (uint8_t *)topology + len;
274    const struct drm_xe_query_topology_mask *end = (struct drm_xe_query_topology_mask *)tmp;
275 
276    while (topology < end) {
277       if (topology->gt_id == 0) {
278          switch (topology->type) {
279          case DRM_XE_TOPO_DSS_GEOMETRY:
280             geo_dss_mask = topology->mask;
281             geo_dss_num_bytes = topology->num_bytes;
282             break;
283          case DRM_XE_TOPO_EU_PER_DSS:
284             eu_per_dss_mask = (uint32_t *)topology->mask;
285             break;
286          }
287       }
288 
289       topology = (struct drm_xe_query_topology_mask *)&topology->mask[topology->num_bytes];
290    }
291 
292    bool ret = true;
293    if (!geo_dss_num_bytes || !geo_dss_mask || !eu_per_dss_mask) {
294       ret = false;
295       goto parse_failed;
296    }
297 
298    xe_compute_topology(devinfo, geo_dss_mask, geo_dss_num_bytes, eu_per_dss_mask);
299 
300 parse_failed:
301    free((void *)head);
302    return ret;
303 }
304 
305 bool
intel_device_info_xe_get_info_from_fd(int fd,struct intel_device_info * devinfo)306 intel_device_info_xe_get_info_from_fd(int fd, struct intel_device_info *devinfo)
307 {
308    if (!intel_device_info_xe_query_regions(fd, devinfo, false))
309       return false;
310 
311    if (!xe_query_config(fd, devinfo))
312       return false;
313 
314    if (!xe_query_gts(fd, devinfo))
315       return false;
316 
317    if (xe_query_process_hwconfig(fd, devinfo))
318       intel_device_info_update_after_hwconfig(devinfo);
319 
320    if (!xe_query_topology(fd, devinfo))
321          return false;
322 
323    devinfo->has_context_isolation = true;
324    devinfo->has_mmap_offset = true;
325    devinfo->has_caching_uapi = false;
326    devinfo->has_set_pat_uapi = true;
327 
328    return true;
329 }
330