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