• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2022 Google, Inc.
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 FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 #include <unistd.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 
28 #include "util/libsync.h"
29 #include "util/u_process.h"
30 
31 #include "virtio_priv.h"
32 
33 
34 static int virtio_execbuf_flush(struct fd_device *dev);
35 
36 static void
virtio_device_destroy(struct fd_device * dev)37 virtio_device_destroy(struct fd_device *dev)
38 {
39    struct virtio_device *virtio_dev = to_virtio_device(dev);
40 
41    util_vma_heap_finish(&virtio_dev->address_space);
42 }
43 
44 static uint32_t
virtio_handle_from_dmabuf(struct fd_device * dev,int fd)45 virtio_handle_from_dmabuf(struct fd_device *dev, int fd)
46 {
47    struct virtio_device *virtio_dev = to_virtio_device(dev);
48 
49    return vdrm_dmabuf_to_handle(virtio_dev->vdrm, fd);
50 }
51 
52 static void
virtio_close_handle(struct fd_bo * bo)53 virtio_close_handle(struct fd_bo *bo)
54 {
55    struct virtio_device *virtio_dev = to_virtio_device(bo->dev);
56 
57    vdrm_bo_close(virtio_dev->vdrm, bo->handle);
58 }
59 
60 static const struct fd_device_funcs funcs = {
61    .bo_new = virtio_bo_new,
62    .bo_from_handle = virtio_bo_from_handle,
63    .handle_from_dmabuf = virtio_handle_from_dmabuf,
64    .bo_from_dmabuf = fd_bo_from_dmabuf_drm,
65    .bo_close_handle = virtio_close_handle,
66    .pipe_new = virtio_pipe_new,
67    .flush = virtio_execbuf_flush,
68    .destroy = virtio_device_destroy,
69 };
70 
71 static void
set_debuginfo(struct fd_device * dev)72 set_debuginfo(struct fd_device *dev)
73 {
74    const char *comm = util_get_process_name();
75    static char cmdline[0x1000+1];
76    int fd = open("/proc/self/cmdline", O_RDONLY);
77    if (fd < 0)
78       return;
79 
80    int n = read(fd, cmdline, sizeof(cmdline) - 1);
81    if (n < 0)
82       return;
83 
84    /* arguments are separated by NULL, convert to spaces: */
85    for (int i = 0; i < n; i++) {
86       if (cmdline[i] == '\0') {
87          cmdline[i] = ' ';
88       }
89    }
90 
91    cmdline[n] = '\0';
92 
93    unsigned comm_len = strlen(comm) + 1;
94    unsigned cmdline_len = strlen(cmdline) + 1;
95 
96    struct msm_ccmd_set_debuginfo_req *req;
97 
98    unsigned req_len = align(sizeof(*req) + comm_len + cmdline_len, 4);
99 
100    req = malloc(req_len);
101 
102    req->hdr         = MSM_CCMD(SET_DEBUGINFO, req_len);
103    req->comm_len    = comm_len;
104    req->cmdline_len = cmdline_len;
105 
106    memcpy(&req->payload[0], comm, comm_len);
107    memcpy(&req->payload[comm_len], cmdline, cmdline_len);
108 
109    vdrm_send_req(to_virtio_device(dev)->vdrm, &req->hdr, false);
110 
111    free(req);
112 }
113 
114 struct fd_device *
virtio_device_new(int fd,drmVersionPtr version)115 virtio_device_new(int fd, drmVersionPtr version)
116 {
117    struct virgl_renderer_capset_drm caps;
118    struct virtio_device *virtio_dev;
119    struct vdrm_device *vdrm;
120    struct fd_device *dev;
121 
122    STATIC_ASSERT(FD_BO_PREP_READ == MSM_PREP_READ);
123    STATIC_ASSERT(FD_BO_PREP_WRITE == MSM_PREP_WRITE);
124    STATIC_ASSERT(FD_BO_PREP_NOSYNC == MSM_PREP_NOSYNC);
125 
126    /* Debug option to force fallback to virgl: */
127    if (debug_get_bool_option("FD_NO_VIRTIO", false))
128       return NULL;
129 
130    vdrm = vdrm_device_connect(fd, VIRTGPU_DRM_CONTEXT_MSM);
131    if (!vdrm) {
132       INFO_MSG("could not connect vdrm");
133       return NULL;
134    }
135 
136    caps = vdrm->caps;
137 
138    INFO_MSG("wire_format_version: %u", caps.wire_format_version);
139    INFO_MSG("version_major:       %u", caps.version_major);
140    INFO_MSG("version_minor:       %u", caps.version_minor);
141    INFO_MSG("version_patchlevel:  %u", caps.version_patchlevel);
142    INFO_MSG("has_cached_coherent: %u", caps.u.msm.has_cached_coherent);
143    INFO_MSG("va_start:            0x%0"PRIx64, caps.u.msm.va_start);
144    INFO_MSG("va_size:             0x%0"PRIx64, caps.u.msm.va_size);
145    INFO_MSG("gpu_id:              %u", caps.u.msm.gpu_id);
146    INFO_MSG("gmem_size:           %u", caps.u.msm.gmem_size);
147    INFO_MSG("gmem_base:           0x%0" PRIx64, caps.u.msm.gmem_base);
148    INFO_MSG("chip_id:             0x%0" PRIx64, caps.u.msm.chip_id);
149    INFO_MSG("max_freq:            %u", caps.u.msm.max_freq);
150 
151    if (caps.wire_format_version != 2) {
152       ERROR_MSG("Unsupported protocol version: %u", caps.wire_format_version);
153       goto error;
154    }
155 
156    if ((caps.version_major != 1) || (caps.version_minor < FD_VERSION_SOFTPIN)) {
157       ERROR_MSG("unsupported version: %u.%u.%u", caps.version_major,
158                 caps.version_minor, caps.version_patchlevel);
159       goto error;
160    }
161 
162    if (!caps.u.msm.va_size) {
163       ERROR_MSG("No address space");
164       goto error;
165    }
166 
167    virtio_dev = calloc(1, sizeof(*virtio_dev));
168    if (!virtio_dev)
169       goto error;
170 
171    dev = &virtio_dev->base;
172    dev->funcs = &funcs;
173    dev->fd = fd;
174    dev->version = caps.version_minor;
175    dev->has_cached_coherent = caps.u.msm.has_cached_coherent;
176 
177    p_atomic_set(&virtio_dev->next_blob_id, 1);
178    virtio_dev->shmem = to_msm_shmem(vdrm->shmem);
179    virtio_dev->vdrm = vdrm;
180 
181    util_queue_init(&dev->submit_queue, "sq", 8, 1, 0, NULL);
182 
183    dev->bo_size = sizeof(struct virtio_bo);
184 
185    set_debuginfo(dev);
186 
187    util_vma_heap_init(&virtio_dev->address_space,
188                       caps.u.msm.va_start,
189                       caps.u.msm.va_size);
190    simple_mtx_init(&virtio_dev->address_space_lock, mtx_plain);
191 
192    return dev;
193 
194 error:
195    vdrm_device_close(vdrm);
196    return NULL;
197 }
198 
199 static int
virtio_execbuf_flush(struct fd_device * dev)200 virtio_execbuf_flush(struct fd_device *dev)
201 {
202    return vdrm_flush(to_virtio_device(dev)->vdrm);
203 }
204 
205 /**
206  * Helper for simple pass-thru ioctls
207  */
208 int
virtio_simple_ioctl(struct fd_device * dev,unsigned cmd,void * _req)209 virtio_simple_ioctl(struct fd_device *dev, unsigned cmd, void *_req)
210 {
211    MESA_TRACE_FUNC();
212    struct vdrm_device *vdrm = to_virtio_device(dev)->vdrm;
213    unsigned req_len = sizeof(struct msm_ccmd_ioctl_simple_req);
214    unsigned rsp_len = sizeof(struct msm_ccmd_ioctl_simple_rsp);
215 
216    req_len += _IOC_SIZE(cmd);
217    if (cmd & IOC_OUT)
218       rsp_len += _IOC_SIZE(cmd);
219 
220    uint8_t buf[req_len];
221    struct msm_ccmd_ioctl_simple_req *req = (void *)buf;
222    struct msm_ccmd_ioctl_simple_rsp *rsp;
223 
224    req->hdr = MSM_CCMD(IOCTL_SIMPLE, req_len);
225    req->cmd = cmd;
226    memcpy(req->payload, _req, _IOC_SIZE(cmd));
227 
228    rsp = vdrm_alloc_rsp(vdrm, &req->hdr, rsp_len);
229 
230    int ret = vdrm_send_req(vdrm, &req->hdr, true);
231 
232    if (cmd & IOC_OUT)
233       memcpy(_req, rsp->payload, _IOC_SIZE(cmd));
234 
235    ret = rsp->ret;
236 
237    return ret;
238 }
239