xref: /aosp_15_r20/external/mesa3d/src/gallium/winsys/svga/drm/vmw_screen.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright (c) 2009-2024 Broadcom. All Rights Reserved.
3  * The term “Broadcom” refers to Broadcom Inc.
4  * and/or its subsidiaries.
5  * SPDX-License-Identifier: MIT
6  */
7 
8 
9 #include "vmw_screen.h"
10 #include "vmw_fence.h"
11 #include "vmw_context.h"
12 #include "vmwgfx_drm.h"
13 #include "xf86drm.h"
14 
15 #include "util/os_file.h"
16 #include "util/u_memory.h"
17 #include "util/compiler.h"
18 #include "util/u_hash_table.h"
19 #ifdef MAJOR_IN_MKDEV
20 #include <sys/mkdev.h>
21 #endif
22 #ifdef MAJOR_IN_SYSMACROS
23 #include <sys/sysmacros.h>
24 #endif
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <sys/ioctl.h>
29 #include <sys/mman.h>
30 
31 static struct hash_table *dev_hash = NULL;
32 
vmw_dev_compare(const void * key1,const void * key2)33 static bool vmw_dev_compare(const void *key1, const void *key2)
34 {
35    return (major(*(dev_t *)key1) == major(*(dev_t *)key2) &&
36            minor(*(dev_t *)key1) == minor(*(dev_t *)key2));
37 }
38 
vmw_dev_hash(const void * key)39 static uint32_t vmw_dev_hash(const void *key)
40 {
41    return (major(*(dev_t *) key) << 16) | minor(*(dev_t *) key);
42 }
43 
44 #ifdef VMX86_STATS
45 /**
46  * Initializes mksstat TLS store.
47  */
48 static void
vmw_winsys_screen_init_mksstat(struct vmw_winsys_screen * vws)49 vmw_winsys_screen_init_mksstat(struct vmw_winsys_screen *vws)
50 {
51    size_t i;
52 
53    for (i = 0; i < ARRAY_SIZE(vws->mksstat_tls); ++i) {
54       vws->mksstat_tls[i].stat_pages = NULL;
55       vws->mksstat_tls[i].stat_id = -1UL;
56       vws->mksstat_tls[i].pid = 0;
57    }
58 }
59 
60 /**
61  * Deinits mksstat TLS store.
62  */
63 static void
vmw_winsys_screen_deinit_mksstat(struct vmw_winsys_screen * vws)64 vmw_winsys_screen_deinit_mksstat(struct vmw_winsys_screen *vws)
65 {
66    size_t i;
67 
68    for (i = 0; i < ARRAY_SIZE(vws->mksstat_tls); ++i) {
69       uint32_t expected = __atomic_load_n(&vws->mksstat_tls[i].pid, __ATOMIC_ACQUIRE);
70 
71       if (expected == -1U) {
72          fprintf(stderr, "%s encountered locked mksstat TLS entry at index %lu.\n", __func__, i);
73          continue;
74       }
75 
76       if (expected == 0)
77          continue;
78 
79       if (__atomic_compare_exchange_n(&vws->mksstat_tls[i].pid, &expected, 0, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) {
80          struct drm_vmw_mksstat_remove_arg arg = {
81             .id = vws->mksstat_tls[i].stat_id
82          };
83 
84          assert(vws->mksstat_tls[i].stat_pages);
85          assert(vws->mksstat_tls[i].stat_id != -1UL);
86 
87          if (drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_MKSSTAT_REMOVE, &arg, sizeof(arg))) {
88             fprintf(stderr, "%s could not ioctl: %s\n", __func__, strerror(errno));
89          } else if (munmap(vws->mksstat_tls[i].stat_pages, vmw_svga_winsys_stats_len())) {
90             fprintf(stderr, "%s could not munmap: %s\n", __func__, strerror(errno));
91          }
92       } else {
93          fprintf(stderr, "%s encountered volatile mksstat TLS entry at index %lu.\n", __func__, i);
94       }
95    }
96 }
97 
98 #endif
99 /* Called from vmw_drm_create_screen(), creates and initializes the
100  * vmw_winsys_screen structure, which is the main entity in this
101  * module.
102  * First, check whether a vmw_winsys_screen object already exists for
103  * this device, and in that case return that one, making sure that we
104  * have our own file descriptor open to DRM.
105  */
106 
107 struct vmw_winsys_screen *
vmw_winsys_create(int fd)108 vmw_winsys_create( int fd )
109 {
110    struct vmw_winsys_screen *vws;
111    struct stat stat_buf;
112    const char *getenv_val;
113 
114    if (dev_hash == NULL) {
115       dev_hash = _mesa_hash_table_create(NULL, vmw_dev_hash, vmw_dev_compare);
116       if (dev_hash == NULL)
117          return NULL;
118    }
119 
120    if (fstat(fd, &stat_buf))
121       return NULL;
122 
123    vws = util_hash_table_get(dev_hash, &stat_buf.st_rdev);
124    if (vws) {
125       vws->open_count++;
126       return vws;
127    }
128 
129    vws = CALLOC_STRUCT(vmw_winsys_screen);
130    if (!vws)
131       goto out_no_vws;
132 
133    vws->device = stat_buf.st_rdev;
134    vws->open_count = 1;
135    vws->ioctl.drm_fd = os_dupfd_cloexec(fd);
136    vws->force_coherent = false;
137    if (!vmw_ioctl_init(vws))
138       goto out_no_ioctl;
139 
140    vws->base.have_gb_dma = !vws->force_coherent;
141    vws->base.need_to_rebind_resources = false;
142    vws->base.have_transfer_from_buffer_cmd = vws->base.have_vgpu10;
143    vws->base.have_constant_buffer_offset_cmd =
144       vws->ioctl.have_drm_2_20 && vws->base.have_sm5;
145    vws->base.have_index_vertex_buffer_offset_cmd = false;
146    vws->base.have_rasterizer_state_v2_cmd =
147       vws->ioctl.have_drm_2_20 && vws->base.have_sm5;
148 
149    getenv_val = getenv("SVGA_FORCE_KERNEL_UNMAPS");
150    vws->cache_maps = !getenv_val || strcmp(getenv_val, "0") == 0;
151    vws->fence_ops = vmw_fence_ops_create(vws);
152    if (!vws->fence_ops)
153       goto out_no_fence_ops;
154 
155    if(!vmw_pools_init(vws))
156       goto out_no_pools;
157 
158    if (!vmw_winsys_screen_init_svga(vws))
159       goto out_no_svga;
160 
161 #ifdef VMX86_STATS
162    vmw_winsys_screen_init_mksstat(vws);
163 #endif
164    _mesa_hash_table_insert(dev_hash, &vws->device, vws);
165 
166    cnd_init(&vws->cs_cond);
167    mtx_init(&vws->cs_mutex, mtx_plain);
168 
169    return vws;
170 out_no_svga:
171    vmw_pools_cleanup(vws);
172 out_no_pools:
173    vws->fence_ops->destroy(vws->fence_ops);
174 out_no_fence_ops:
175    vmw_ioctl_cleanup(vws);
176 out_no_ioctl:
177    close(vws->ioctl.drm_fd);
178    FREE(vws);
179 out_no_vws:
180    return NULL;
181 }
182 
183 void
vmw_winsys_destroy(struct vmw_winsys_screen * vws)184 vmw_winsys_destroy(struct vmw_winsys_screen *vws)
185 {
186    if (--vws->open_count == 0) {
187       _mesa_hash_table_remove_key(dev_hash, &vws->device);
188       vmw_pools_cleanup(vws);
189       vws->fence_ops->destroy(vws->fence_ops);
190       vmw_ioctl_cleanup(vws);
191 #ifdef VMX86_STATS
192       vmw_winsys_screen_deinit_mksstat(vws);
193 #endif
194       close(vws->ioctl.drm_fd);
195       mtx_destroy(&vws->cs_mutex);
196       cnd_destroy(&vws->cs_cond);
197       FREE(vws);
198    }
199 }
200