1 /*
2 * Copyright 2023 Google
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "VirtioGpuAddressSpaceStream.h"
7
8 #include <errno.h>
9
10 #include "util/log.h"
11
GetRingParamsFromCapset(enum VirtGpuCapset capset,const VirtGpuCaps & caps,uint32_t & ringSize,uint32_t & bufferSize,uint32_t & blobAlignment)12 static bool GetRingParamsFromCapset(enum VirtGpuCapset capset, const VirtGpuCaps& caps,
13 uint32_t& ringSize, uint32_t& bufferSize,
14 uint32_t& blobAlignment) {
15 switch (capset) {
16 case kCapsetGfxStreamVulkan:
17 ringSize = caps.vulkanCapset.ringSize;
18 bufferSize = caps.vulkanCapset.bufferSize;
19 blobAlignment = caps.vulkanCapset.blobAlignment;
20 break;
21 case kCapsetGfxStreamMagma:
22 ringSize = caps.magmaCapset.ringSize;
23 bufferSize = caps.magmaCapset.bufferSize;
24 blobAlignment = caps.magmaCapset.blobAlignment;
25 break;
26 case kCapsetGfxStreamGles:
27 ringSize = caps.glesCapset.ringSize;
28 bufferSize = caps.glesCapset.bufferSize;
29 blobAlignment = caps.glesCapset.blobAlignment;
30 break;
31 case kCapsetGfxStreamComposer:
32 ringSize = caps.composerCapset.ringSize;
33 bufferSize = caps.composerCapset.bufferSize;
34 blobAlignment = caps.composerCapset.blobAlignment;
35 break;
36 default:
37 return false;
38 }
39
40 return true;
41 }
42
virtgpu_address_space_open()43 address_space_handle_t virtgpu_address_space_open() {
44 return (address_space_handle_t)(-EINVAL);
45 }
46
virtgpu_address_space_close(address_space_handle_t)47 void virtgpu_address_space_close(address_space_handle_t) {
48 // Handle opened by VirtioGpuDevice wrapper
49 }
50
virtgpu_address_space_ping(address_space_handle_t,struct address_space_ping * info)51 bool virtgpu_address_space_ping(address_space_handle_t, struct address_space_ping* info) {
52 int ret;
53 struct VirtGpuExecBuffer exec = {};
54 VirtGpuDevice* instance = VirtGpuDevice::getInstance();
55 struct gfxstreamContextPing ping = {};
56
57 ping.hdr.opCode = GFXSTREAM_CONTEXT_PING;
58 ping.resourceId = info->resourceId;
59
60 exec.command = static_cast<void*>(&ping);
61 exec.command_size = sizeof(ping);
62
63 ret = instance->execBuffer(exec, nullptr);
64 if (ret)
65 return false;
66
67 return true;
68 }
69
createVirtioGpuAddressSpaceStream(enum VirtGpuCapset capset)70 AddressSpaceStream* createVirtioGpuAddressSpaceStream(enum VirtGpuCapset capset) {
71 VirtGpuResourcePtr pipe, blob;
72 VirtGpuResourceMappingPtr pipeMapping, blobMapping;
73 struct VirtGpuExecBuffer exec = {};
74 struct VirtGpuCreateBlob blobCreate = {};
75 struct gfxstreamContextCreate contextCreate = {};
76
77 uint32_t ringSize = 0;
78 uint32_t bufferSize = 0;
79 uint32_t blobAlignment = 0;
80
81 char* blobAddr, *bufferPtr;
82 int ret;
83
84 VirtGpuDevice* instance = VirtGpuDevice::getInstance();
85 auto caps = instance->getCaps();
86
87 if (!GetRingParamsFromCapset(capset, caps, ringSize, bufferSize, blobAlignment)) {
88 mesa_loge("Failed to get ring parameters");
89 return nullptr;
90 }
91
92 blobCreate.blobId = 0;
93 blobCreate.blobMem = kBlobMemHost3d;
94 blobCreate.flags = kBlobFlagMappable;
95 blobCreate.size = ALIGN_POT(ringSize + bufferSize, blobAlignment);
96 blob = instance->createBlob(blobCreate);
97 if (!blob)
98 return nullptr;
99
100 // Context creation command
101 contextCreate.hdr.opCode = GFXSTREAM_CONTEXT_CREATE;
102 contextCreate.resourceId = blob->getResourceHandle();
103
104 exec.command = static_cast<void*>(&contextCreate);
105 exec.command_size = sizeof(contextCreate);
106
107 ret = instance->execBuffer(exec, blob.get());
108 if (ret)
109 return nullptr;
110
111 // Wait occurs on global timeline -- should we use context specific one?
112 ret = blob->wait();
113 if (ret)
114 return nullptr;
115
116 blobMapping = blob->createMapping();
117 if (!blobMapping)
118 return nullptr;
119
120 blobAddr = reinterpret_cast<char*>(blobMapping->asRawPtr());
121
122 bufferPtr = blobAddr + sizeof(struct asg_ring_storage);
123 struct asg_context context = asg_context_create(blobAddr, bufferPtr, bufferSize);
124
125 context.ring_config->transfer_mode = 1;
126 context.ring_config->host_consumed_pos = 0;
127 context.ring_config->guest_write_pos = 0;
128
129 struct address_space_ops ops = {
130 .open = virtgpu_address_space_open,
131 .close = virtgpu_address_space_close,
132 .ping = virtgpu_address_space_ping,
133 };
134
135 AddressSpaceStream* res =
136 new AddressSpaceStream((address_space_handle_t)(-1), 1, context, 0, 0, ops);
137
138 res->setMapping(blobMapping);
139 res->setResourceId(contextCreate.resourceId);
140 return res;
141 }
142