xref: /aosp_15_r20/external/mesa3d/src/gfxstream/guest/GoldfishAddressSpace/AddressSpaceStream.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright 2020 Google
3*61046927SAndroid Build Coastguard Worker  * SPDX-License-Identifier: MIT
4*61046927SAndroid Build Coastguard Worker  */
5*61046927SAndroid Build Coastguard Worker #include "AddressSpaceStream.h"
6*61046927SAndroid Build Coastguard Worker 
7*61046927SAndroid Build Coastguard Worker #include <errno.h>
8*61046927SAndroid Build Coastguard Worker #include <stdio.h>
9*61046927SAndroid Build Coastguard Worker #include <stdlib.h>
10*61046927SAndroid Build Coastguard Worker #include <string.h>
11*61046927SAndroid Build Coastguard Worker #include <unistd.h>
12*61046927SAndroid Build Coastguard Worker 
13*61046927SAndroid Build Coastguard Worker #include "VirtGpu.h"
14*61046927SAndroid Build Coastguard Worker #include "util/log.h"
15*61046927SAndroid Build Coastguard Worker #include "util/perf/cpu_trace.h"
16*61046927SAndroid Build Coastguard Worker #include "virtgpu_gfxstream_protocol.h"
17*61046927SAndroid Build Coastguard Worker 
18*61046927SAndroid Build Coastguard Worker static const size_t kReadSize = 512 * 1024;
19*61046927SAndroid Build Coastguard Worker static const size_t kWriteOffset = kReadSize;
20*61046927SAndroid Build Coastguard Worker 
AddressSpaceStream(address_space_handle_t handle,uint32_t version,struct asg_context context,uint64_t ringOffset,uint64_t writeBufferOffset,struct address_space_ops ops)21*61046927SAndroid Build Coastguard Worker AddressSpaceStream::AddressSpaceStream(address_space_handle_t handle, uint32_t version,
22*61046927SAndroid Build Coastguard Worker                                        struct asg_context context, uint64_t ringOffset,
23*61046927SAndroid Build Coastguard Worker                                        uint64_t writeBufferOffset, struct address_space_ops ops)
24*61046927SAndroid Build Coastguard Worker     : IOStream(context.ring_config->flush_interval),
25*61046927SAndroid Build Coastguard Worker       m_ops(ops),
26*61046927SAndroid Build Coastguard Worker       m_tmpBuf(0),
27*61046927SAndroid Build Coastguard Worker       m_tmpBufSize(0),
28*61046927SAndroid Build Coastguard Worker       m_tmpBufXferSize(0),
29*61046927SAndroid Build Coastguard Worker       m_usingTmpBuf(0),
30*61046927SAndroid Build Coastguard Worker       m_readBuf(0),
31*61046927SAndroid Build Coastguard Worker       m_read(0),
32*61046927SAndroid Build Coastguard Worker       m_readLeft(0),
33*61046927SAndroid Build Coastguard Worker       m_handle(handle),
34*61046927SAndroid Build Coastguard Worker       m_version(version),
35*61046927SAndroid Build Coastguard Worker       m_context(context),
36*61046927SAndroid Build Coastguard Worker       m_ringOffset(ringOffset),
37*61046927SAndroid Build Coastguard Worker       m_writeBufferOffset(writeBufferOffset),
38*61046927SAndroid Build Coastguard Worker       m_writeBufferSize(context.ring_config->buffer_size),
39*61046927SAndroid Build Coastguard Worker       m_writeBufferMask(m_writeBufferSize - 1),
40*61046927SAndroid Build Coastguard Worker       m_buf((unsigned char*)context.buffer),
41*61046927SAndroid Build Coastguard Worker       m_writeStart(m_buf),
42*61046927SAndroid Build Coastguard Worker       m_writeStep(context.ring_config->flush_interval),
43*61046927SAndroid Build Coastguard Worker       m_notifs(0),
44*61046927SAndroid Build Coastguard Worker       m_written(0),
45*61046927SAndroid Build Coastguard Worker       m_backoffIters(0),
46*61046927SAndroid Build Coastguard Worker       m_backoffFactor(1),
47*61046927SAndroid Build Coastguard Worker       m_ringStorageSize(sizeof(struct asg_ring_storage) + m_writeBufferSize) {
48*61046927SAndroid Build Coastguard Worker     // We'll use this in the future, but at the moment,
49*61046927SAndroid Build Coastguard Worker     // it's a potential compile Werror.
50*61046927SAndroid Build Coastguard Worker     (void)m_ringStorageSize;
51*61046927SAndroid Build Coastguard Worker     (void)m_version;
52*61046927SAndroid Build Coastguard Worker }
53*61046927SAndroid Build Coastguard Worker 
~AddressSpaceStream()54*61046927SAndroid Build Coastguard Worker AddressSpaceStream::~AddressSpaceStream() {
55*61046927SAndroid Build Coastguard Worker     flush();
56*61046927SAndroid Build Coastguard Worker     ensureType3Finished();
57*61046927SAndroid Build Coastguard Worker     ensureType1Finished();
58*61046927SAndroid Build Coastguard Worker 
59*61046927SAndroid Build Coastguard Worker     if (!m_mapping) {
60*61046927SAndroid Build Coastguard Worker         m_ops.unmap(m_context.to_host, sizeof(struct asg_ring_storage));
61*61046927SAndroid Build Coastguard Worker         m_ops.unmap(m_context.buffer, m_writeBufferSize);
62*61046927SAndroid Build Coastguard Worker         m_ops.unclaim_shared(m_handle, m_ringOffset);
63*61046927SAndroid Build Coastguard Worker         m_ops.unclaim_shared(m_handle, m_writeBufferOffset);
64*61046927SAndroid Build Coastguard Worker     }
65*61046927SAndroid Build Coastguard Worker 
66*61046927SAndroid Build Coastguard Worker     m_ops.close(m_handle);
67*61046927SAndroid Build Coastguard Worker     if (m_readBuf) free(m_readBuf);
68*61046927SAndroid Build Coastguard Worker     if (m_tmpBuf) free(m_tmpBuf);
69*61046927SAndroid Build Coastguard Worker }
70*61046927SAndroid Build Coastguard Worker 
idealAllocSize(size_t len)71*61046927SAndroid Build Coastguard Worker size_t AddressSpaceStream::idealAllocSize(size_t len) {
72*61046927SAndroid Build Coastguard Worker     if (len > m_writeStep) return len;
73*61046927SAndroid Build Coastguard Worker     return m_writeStep;
74*61046927SAndroid Build Coastguard Worker }
75*61046927SAndroid Build Coastguard Worker 
allocBuffer(size_t minSize)76*61046927SAndroid Build Coastguard Worker void* AddressSpaceStream::allocBuffer(size_t minSize) {
77*61046927SAndroid Build Coastguard Worker     MESA_TRACE_SCOPE("allocBuffer");
78*61046927SAndroid Build Coastguard Worker     ensureType3Finished();
79*61046927SAndroid Build Coastguard Worker 
80*61046927SAndroid Build Coastguard Worker     if (!m_readBuf) {
81*61046927SAndroid Build Coastguard Worker         m_readBuf = (unsigned char*)malloc(kReadSize);
82*61046927SAndroid Build Coastguard Worker     }
83*61046927SAndroid Build Coastguard Worker 
84*61046927SAndroid Build Coastguard Worker     size_t allocSize =
85*61046927SAndroid Build Coastguard Worker         (m_writeStep < minSize ? minSize : m_writeStep);
86*61046927SAndroid Build Coastguard Worker 
87*61046927SAndroid Build Coastguard Worker     if (m_writeStep < allocSize) {
88*61046927SAndroid Build Coastguard Worker         if (!m_tmpBuf) {
89*61046927SAndroid Build Coastguard Worker             m_tmpBufSize = allocSize * 2;
90*61046927SAndroid Build Coastguard Worker             m_tmpBuf = (unsigned char*)malloc(m_tmpBufSize);
91*61046927SAndroid Build Coastguard Worker         }
92*61046927SAndroid Build Coastguard Worker 
93*61046927SAndroid Build Coastguard Worker         if (m_tmpBufSize < allocSize) {
94*61046927SAndroid Build Coastguard Worker             m_tmpBufSize = allocSize * 2;
95*61046927SAndroid Build Coastguard Worker             m_tmpBuf = (unsigned char*)realloc(m_tmpBuf, m_tmpBufSize);
96*61046927SAndroid Build Coastguard Worker         }
97*61046927SAndroid Build Coastguard Worker 
98*61046927SAndroid Build Coastguard Worker         if (!m_usingTmpBuf) {
99*61046927SAndroid Build Coastguard Worker             flush();
100*61046927SAndroid Build Coastguard Worker         }
101*61046927SAndroid Build Coastguard Worker 
102*61046927SAndroid Build Coastguard Worker         m_usingTmpBuf = true;
103*61046927SAndroid Build Coastguard Worker         m_tmpBufXferSize = allocSize;
104*61046927SAndroid Build Coastguard Worker         return m_tmpBuf;
105*61046927SAndroid Build Coastguard Worker     } else {
106*61046927SAndroid Build Coastguard Worker         if (m_usingTmpBuf) {
107*61046927SAndroid Build Coastguard Worker             writeFully(m_tmpBuf, m_tmpBufXferSize);
108*61046927SAndroid Build Coastguard Worker             m_usingTmpBuf = false;
109*61046927SAndroid Build Coastguard Worker             m_tmpBufXferSize = 0;
110*61046927SAndroid Build Coastguard Worker         }
111*61046927SAndroid Build Coastguard Worker 
112*61046927SAndroid Build Coastguard Worker         return m_writeStart;
113*61046927SAndroid Build Coastguard Worker     }
114*61046927SAndroid Build Coastguard Worker }
115*61046927SAndroid Build Coastguard Worker 
commitBuffer(size_t size)116*61046927SAndroid Build Coastguard Worker int AddressSpaceStream::commitBuffer(size_t size)
117*61046927SAndroid Build Coastguard Worker {
118*61046927SAndroid Build Coastguard Worker     if (size == 0) return 0;
119*61046927SAndroid Build Coastguard Worker 
120*61046927SAndroid Build Coastguard Worker     if (m_usingTmpBuf) {
121*61046927SAndroid Build Coastguard Worker         writeFully(m_tmpBuf, size);
122*61046927SAndroid Build Coastguard Worker         m_tmpBufXferSize = 0;
123*61046927SAndroid Build Coastguard Worker         m_usingTmpBuf = false;
124*61046927SAndroid Build Coastguard Worker         return 0;
125*61046927SAndroid Build Coastguard Worker     } else {
126*61046927SAndroid Build Coastguard Worker         int res = type1Write(m_writeStart - m_buf, size);
127*61046927SAndroid Build Coastguard Worker         advanceWrite();
128*61046927SAndroid Build Coastguard Worker         return res;
129*61046927SAndroid Build Coastguard Worker     }
130*61046927SAndroid Build Coastguard Worker }
131*61046927SAndroid Build Coastguard Worker 
readFully(void * ptr,size_t totalReadSize)132*61046927SAndroid Build Coastguard Worker const unsigned char *AddressSpaceStream::readFully(void *ptr, size_t totalReadSize)
133*61046927SAndroid Build Coastguard Worker {
134*61046927SAndroid Build Coastguard Worker 
135*61046927SAndroid Build Coastguard Worker     unsigned char* userReadBuf = static_cast<unsigned char*>(ptr);
136*61046927SAndroid Build Coastguard Worker 
137*61046927SAndroid Build Coastguard Worker     if (!userReadBuf) {
138*61046927SAndroid Build Coastguard Worker         if (totalReadSize > 0) {
139*61046927SAndroid Build Coastguard Worker             mesa_loge(
140*61046927SAndroid Build Coastguard Worker                 "AddressSpaceStream::commitBufferAndReadFully failed, userReadBuf=NULL, "
141*61046927SAndroid Build Coastguard Worker                 "totalReadSize %zu, lethal"
142*61046927SAndroid Build Coastguard Worker                 " error, exiting.",
143*61046927SAndroid Build Coastguard Worker                 totalReadSize);
144*61046927SAndroid Build Coastguard Worker             abort();
145*61046927SAndroid Build Coastguard Worker         }
146*61046927SAndroid Build Coastguard Worker         return nullptr;
147*61046927SAndroid Build Coastguard Worker     }
148*61046927SAndroid Build Coastguard Worker 
149*61046927SAndroid Build Coastguard Worker     // Advance buffered read if not yet consumed.
150*61046927SAndroid Build Coastguard Worker     size_t remaining = totalReadSize;
151*61046927SAndroid Build Coastguard Worker     size_t bufferedReadSize =
152*61046927SAndroid Build Coastguard Worker         m_readLeft < remaining ? m_readLeft : remaining;
153*61046927SAndroid Build Coastguard Worker 
154*61046927SAndroid Build Coastguard Worker     if (bufferedReadSize) {
155*61046927SAndroid Build Coastguard Worker         memcpy(userReadBuf,
156*61046927SAndroid Build Coastguard Worker                m_readBuf + (m_read - m_readLeft),
157*61046927SAndroid Build Coastguard Worker                bufferedReadSize);
158*61046927SAndroid Build Coastguard Worker         remaining -= bufferedReadSize;
159*61046927SAndroid Build Coastguard Worker         m_readLeft -= bufferedReadSize;
160*61046927SAndroid Build Coastguard Worker     }
161*61046927SAndroid Build Coastguard Worker 
162*61046927SAndroid Build Coastguard Worker     if (!remaining) return userReadBuf;
163*61046927SAndroid Build Coastguard Worker 
164*61046927SAndroid Build Coastguard Worker     // Read up to kReadSize bytes if all buffered read has been consumed.
165*61046927SAndroid Build Coastguard Worker     size_t maxRead = m_readLeft ? 0 : kReadSize;
166*61046927SAndroid Build Coastguard Worker     ssize_t actual = 0;
167*61046927SAndroid Build Coastguard Worker 
168*61046927SAndroid Build Coastguard Worker     if (maxRead) {
169*61046927SAndroid Build Coastguard Worker         actual = speculativeRead(m_readBuf, maxRead);
170*61046927SAndroid Build Coastguard Worker 
171*61046927SAndroid Build Coastguard Worker         // Updated buffered read size.
172*61046927SAndroid Build Coastguard Worker         if (actual > 0) {
173*61046927SAndroid Build Coastguard Worker             m_read = m_readLeft = actual;
174*61046927SAndroid Build Coastguard Worker         }
175*61046927SAndroid Build Coastguard Worker 
176*61046927SAndroid Build Coastguard Worker         if (actual == 0) {
177*61046927SAndroid Build Coastguard Worker             mesa_logd("%s: end of pipe", __FUNCTION__);
178*61046927SAndroid Build Coastguard Worker             return NULL;
179*61046927SAndroid Build Coastguard Worker         }
180*61046927SAndroid Build Coastguard Worker     }
181*61046927SAndroid Build Coastguard Worker 
182*61046927SAndroid Build Coastguard Worker     // Consume buffered read and read more if necessary.
183*61046927SAndroid Build Coastguard Worker     while (remaining) {
184*61046927SAndroid Build Coastguard Worker         bufferedReadSize = m_readLeft < remaining ? m_readLeft : remaining;
185*61046927SAndroid Build Coastguard Worker         if (bufferedReadSize) {
186*61046927SAndroid Build Coastguard Worker             memcpy(userReadBuf + (totalReadSize - remaining),
187*61046927SAndroid Build Coastguard Worker                    m_readBuf + (m_read - m_readLeft),
188*61046927SAndroid Build Coastguard Worker                    bufferedReadSize);
189*61046927SAndroid Build Coastguard Worker             remaining -= bufferedReadSize;
190*61046927SAndroid Build Coastguard Worker             m_readLeft -= bufferedReadSize;
191*61046927SAndroid Build Coastguard Worker             continue;
192*61046927SAndroid Build Coastguard Worker         }
193*61046927SAndroid Build Coastguard Worker 
194*61046927SAndroid Build Coastguard Worker         actual = speculativeRead(m_readBuf, kReadSize);
195*61046927SAndroid Build Coastguard Worker 
196*61046927SAndroid Build Coastguard Worker         if (actual == 0) {
197*61046927SAndroid Build Coastguard Worker             mesa_logd("%s: Failed reading from pipe: %d", __FUNCTION__, errno);
198*61046927SAndroid Build Coastguard Worker             return NULL;
199*61046927SAndroid Build Coastguard Worker         }
200*61046927SAndroid Build Coastguard Worker 
201*61046927SAndroid Build Coastguard Worker         if (actual > 0) {
202*61046927SAndroid Build Coastguard Worker             m_read = m_readLeft = actual;
203*61046927SAndroid Build Coastguard Worker             continue;
204*61046927SAndroid Build Coastguard Worker         }
205*61046927SAndroid Build Coastguard Worker     }
206*61046927SAndroid Build Coastguard Worker 
207*61046927SAndroid Build Coastguard Worker     resetBackoff();
208*61046927SAndroid Build Coastguard Worker     return userReadBuf;
209*61046927SAndroid Build Coastguard Worker }
210*61046927SAndroid Build Coastguard Worker 
read(void * buf,size_t * inout_len)211*61046927SAndroid Build Coastguard Worker const unsigned char *AddressSpaceStream::read(void *buf, size_t *inout_len) {
212*61046927SAndroid Build Coastguard Worker     unsigned char* dst = (unsigned char*)buf;
213*61046927SAndroid Build Coastguard Worker     size_t wanted = *inout_len;
214*61046927SAndroid Build Coastguard Worker     ssize_t actual = speculativeRead(dst, wanted);
215*61046927SAndroid Build Coastguard Worker 
216*61046927SAndroid Build Coastguard Worker     if (actual >= 0) {
217*61046927SAndroid Build Coastguard Worker         *inout_len = actual;
218*61046927SAndroid Build Coastguard Worker     } else {
219*61046927SAndroid Build Coastguard Worker         return nullptr;
220*61046927SAndroid Build Coastguard Worker     }
221*61046927SAndroid Build Coastguard Worker 
222*61046927SAndroid Build Coastguard Worker     return (const unsigned char*)dst;
223*61046927SAndroid Build Coastguard Worker }
224*61046927SAndroid Build Coastguard Worker 
writeFully(const void * buf,size_t size)225*61046927SAndroid Build Coastguard Worker int AddressSpaceStream::writeFully(const void* buf, size_t size) {
226*61046927SAndroid Build Coastguard Worker     MESA_TRACE_SCOPE("writeFully");
227*61046927SAndroid Build Coastguard Worker     ensureType3Finished();
228*61046927SAndroid Build Coastguard Worker     ensureType1Finished();
229*61046927SAndroid Build Coastguard Worker 
230*61046927SAndroid Build Coastguard Worker     m_context.ring_config->transfer_size = size;
231*61046927SAndroid Build Coastguard Worker     m_context.ring_config->transfer_mode = 3;
232*61046927SAndroid Build Coastguard Worker 
233*61046927SAndroid Build Coastguard Worker     size_t sent = 0;
234*61046927SAndroid Build Coastguard Worker     size_t preferredChunkSize = m_writeBufferSize / 4;
235*61046927SAndroid Build Coastguard Worker     size_t chunkSize = size < preferredChunkSize ? size : preferredChunkSize;
236*61046927SAndroid Build Coastguard Worker     const uint8_t* bufferBytes = (const uint8_t*)buf;
237*61046927SAndroid Build Coastguard Worker 
238*61046927SAndroid Build Coastguard Worker     bool hostPinged = false;
239*61046927SAndroid Build Coastguard Worker     while (sent < size) {
240*61046927SAndroid Build Coastguard Worker         size_t remaining = size - sent;
241*61046927SAndroid Build Coastguard Worker         size_t sendThisTime = remaining < chunkSize ? remaining : chunkSize;
242*61046927SAndroid Build Coastguard Worker 
243*61046927SAndroid Build Coastguard Worker         long sentChunks =
244*61046927SAndroid Build Coastguard Worker             ring_buffer_view_write(
245*61046927SAndroid Build Coastguard Worker                 m_context.to_host_large_xfer.ring,
246*61046927SAndroid Build Coastguard Worker                 &m_context.to_host_large_xfer.view,
247*61046927SAndroid Build Coastguard Worker                 bufferBytes + sent, sendThisTime, 1);
248*61046927SAndroid Build Coastguard Worker 
249*61046927SAndroid Build Coastguard Worker         if (!hostPinged && *(m_context.host_state) != ASG_HOST_STATE_CAN_CONSUME &&
250*61046927SAndroid Build Coastguard Worker             *(m_context.host_state) != ASG_HOST_STATE_RENDERING) {
251*61046927SAndroid Build Coastguard Worker             notifyAvailable();
252*61046927SAndroid Build Coastguard Worker             hostPinged = true;
253*61046927SAndroid Build Coastguard Worker         }
254*61046927SAndroid Build Coastguard Worker 
255*61046927SAndroid Build Coastguard Worker         if (sentChunks == 0) {
256*61046927SAndroid Build Coastguard Worker             ring_buffer_yield();
257*61046927SAndroid Build Coastguard Worker             backoff();
258*61046927SAndroid Build Coastguard Worker         }
259*61046927SAndroid Build Coastguard Worker 
260*61046927SAndroid Build Coastguard Worker         sent += sentChunks * sendThisTime;
261*61046927SAndroid Build Coastguard Worker 
262*61046927SAndroid Build Coastguard Worker         if (isInError()) {
263*61046927SAndroid Build Coastguard Worker             return -1;
264*61046927SAndroid Build Coastguard Worker         }
265*61046927SAndroid Build Coastguard Worker     }
266*61046927SAndroid Build Coastguard Worker 
267*61046927SAndroid Build Coastguard Worker     bool isRenderingAfter = ASG_HOST_STATE_RENDERING == __atomic_load_n(m_context.host_state, __ATOMIC_ACQUIRE);
268*61046927SAndroid Build Coastguard Worker 
269*61046927SAndroid Build Coastguard Worker     if (!isRenderingAfter) {
270*61046927SAndroid Build Coastguard Worker         notifyAvailable();
271*61046927SAndroid Build Coastguard Worker     }
272*61046927SAndroid Build Coastguard Worker 
273*61046927SAndroid Build Coastguard Worker     ensureType3Finished();
274*61046927SAndroid Build Coastguard Worker 
275*61046927SAndroid Build Coastguard Worker     resetBackoff();
276*61046927SAndroid Build Coastguard Worker     m_context.ring_config->transfer_mode = 1;
277*61046927SAndroid Build Coastguard Worker     m_written += size;
278*61046927SAndroid Build Coastguard Worker 
279*61046927SAndroid Build Coastguard Worker     float mb = (float)m_written / 1048576.0f;
280*61046927SAndroid Build Coastguard Worker     if (mb > 100.0f) {
281*61046927SAndroid Build Coastguard Worker         mesa_logd("%s: %f mb in %d notifs. %f mb/notif\n", __func__, mb, m_notifs,
282*61046927SAndroid Build Coastguard Worker                   m_notifs ? mb / (float)m_notifs : 0.0f);
283*61046927SAndroid Build Coastguard Worker         m_notifs = 0;
284*61046927SAndroid Build Coastguard Worker         m_written = 0;
285*61046927SAndroid Build Coastguard Worker     }
286*61046927SAndroid Build Coastguard Worker     return 0;
287*61046927SAndroid Build Coastguard Worker }
288*61046927SAndroid Build Coastguard Worker 
writeFullyAsync(const void * buf,size_t size)289*61046927SAndroid Build Coastguard Worker int AddressSpaceStream::writeFullyAsync(const void* buf, size_t size) {
290*61046927SAndroid Build Coastguard Worker     MESA_TRACE_SCOPE("writeFullyAsync");
291*61046927SAndroid Build Coastguard Worker     ensureType3Finished();
292*61046927SAndroid Build Coastguard Worker     ensureType1Finished();
293*61046927SAndroid Build Coastguard Worker 
294*61046927SAndroid Build Coastguard Worker     __atomic_store_n(&m_context.ring_config->transfer_size, size, __ATOMIC_RELEASE);
295*61046927SAndroid Build Coastguard Worker     m_context.ring_config->transfer_mode = 3;
296*61046927SAndroid Build Coastguard Worker 
297*61046927SAndroid Build Coastguard Worker     size_t sent = 0;
298*61046927SAndroid Build Coastguard Worker     size_t preferredChunkSize = m_writeBufferSize / 2;
299*61046927SAndroid Build Coastguard Worker     size_t chunkSize = size < preferredChunkSize ? size : preferredChunkSize;
300*61046927SAndroid Build Coastguard Worker     const uint8_t* bufferBytes = (const uint8_t*)buf;
301*61046927SAndroid Build Coastguard Worker 
302*61046927SAndroid Build Coastguard Worker     bool pingedHost = false;
303*61046927SAndroid Build Coastguard Worker 
304*61046927SAndroid Build Coastguard Worker     while (sent < size) {
305*61046927SAndroid Build Coastguard Worker         size_t remaining = size - sent;
306*61046927SAndroid Build Coastguard Worker         size_t sendThisTime = remaining < chunkSize ? remaining : chunkSize;
307*61046927SAndroid Build Coastguard Worker 
308*61046927SAndroid Build Coastguard Worker         long sentChunks =
309*61046927SAndroid Build Coastguard Worker             ring_buffer_view_write(
310*61046927SAndroid Build Coastguard Worker                 m_context.to_host_large_xfer.ring,
311*61046927SAndroid Build Coastguard Worker                 &m_context.to_host_large_xfer.view,
312*61046927SAndroid Build Coastguard Worker                 bufferBytes + sent, sendThisTime, 1);
313*61046927SAndroid Build Coastguard Worker 
314*61046927SAndroid Build Coastguard Worker         uint32_t hostState = __atomic_load_n(m_context.host_state, __ATOMIC_ACQUIRE);
315*61046927SAndroid Build Coastguard Worker 
316*61046927SAndroid Build Coastguard Worker         if (!pingedHost &&
317*61046927SAndroid Build Coastguard Worker             hostState != ASG_HOST_STATE_CAN_CONSUME &&
318*61046927SAndroid Build Coastguard Worker             hostState != ASG_HOST_STATE_RENDERING) {
319*61046927SAndroid Build Coastguard Worker             pingedHost = true;
320*61046927SAndroid Build Coastguard Worker             notifyAvailable();
321*61046927SAndroid Build Coastguard Worker         }
322*61046927SAndroid Build Coastguard Worker 
323*61046927SAndroid Build Coastguard Worker         if (sentChunks == 0) {
324*61046927SAndroid Build Coastguard Worker             ring_buffer_yield();
325*61046927SAndroid Build Coastguard Worker             backoff();
326*61046927SAndroid Build Coastguard Worker         }
327*61046927SAndroid Build Coastguard Worker 
328*61046927SAndroid Build Coastguard Worker         sent += sentChunks * sendThisTime;
329*61046927SAndroid Build Coastguard Worker 
330*61046927SAndroid Build Coastguard Worker         if (isInError()) {
331*61046927SAndroid Build Coastguard Worker             return -1;
332*61046927SAndroid Build Coastguard Worker         }
333*61046927SAndroid Build Coastguard Worker     }
334*61046927SAndroid Build Coastguard Worker 
335*61046927SAndroid Build Coastguard Worker 
336*61046927SAndroid Build Coastguard Worker     bool isRenderingAfter = ASG_HOST_STATE_RENDERING == __atomic_load_n(m_context.host_state, __ATOMIC_ACQUIRE);
337*61046927SAndroid Build Coastguard Worker 
338*61046927SAndroid Build Coastguard Worker     if (!isRenderingAfter) {
339*61046927SAndroid Build Coastguard Worker         notifyAvailable();
340*61046927SAndroid Build Coastguard Worker     }
341*61046927SAndroid Build Coastguard Worker 
342*61046927SAndroid Build Coastguard Worker     resetBackoff();
343*61046927SAndroid Build Coastguard Worker     m_context.ring_config->transfer_mode = 1;
344*61046927SAndroid Build Coastguard Worker     m_written += size;
345*61046927SAndroid Build Coastguard Worker 
346*61046927SAndroid Build Coastguard Worker     float mb = (float)m_written / 1048576.0f;
347*61046927SAndroid Build Coastguard Worker     if (mb > 100.0f) {
348*61046927SAndroid Build Coastguard Worker         mesa_logd("%s: %f mb in %d notifs. %f mb/notif\n", __func__, mb, m_notifs,
349*61046927SAndroid Build Coastguard Worker                   m_notifs ? mb / (float)m_notifs : 0.0f);
350*61046927SAndroid Build Coastguard Worker         m_notifs = 0;
351*61046927SAndroid Build Coastguard Worker         m_written = 0;
352*61046927SAndroid Build Coastguard Worker     }
353*61046927SAndroid Build Coastguard Worker     return 0;
354*61046927SAndroid Build Coastguard Worker }
355*61046927SAndroid Build Coastguard Worker 
commitBufferAndReadFully(size_t writeSize,void * userReadBufPtr,size_t totalReadSize)356*61046927SAndroid Build Coastguard Worker const unsigned char *AddressSpaceStream::commitBufferAndReadFully(
357*61046927SAndroid Build Coastguard Worker     size_t writeSize, void *userReadBufPtr, size_t totalReadSize) {
358*61046927SAndroid Build Coastguard Worker 
359*61046927SAndroid Build Coastguard Worker     if (m_usingTmpBuf) {
360*61046927SAndroid Build Coastguard Worker         writeFully(m_tmpBuf, writeSize);
361*61046927SAndroid Build Coastguard Worker         m_usingTmpBuf = false;
362*61046927SAndroid Build Coastguard Worker         m_tmpBufXferSize = 0;
363*61046927SAndroid Build Coastguard Worker         return readFully(userReadBufPtr, totalReadSize);
364*61046927SAndroid Build Coastguard Worker     } else {
365*61046927SAndroid Build Coastguard Worker         commitBuffer(writeSize);
366*61046927SAndroid Build Coastguard Worker         return readFully(userReadBufPtr, totalReadSize);
367*61046927SAndroid Build Coastguard Worker     }
368*61046927SAndroid Build Coastguard Worker }
369*61046927SAndroid Build Coastguard Worker 
isInError() const370*61046927SAndroid Build Coastguard Worker bool AddressSpaceStream::isInError() const {
371*61046927SAndroid Build Coastguard Worker     return 1 == m_context.ring_config->in_error;
372*61046927SAndroid Build Coastguard Worker }
373*61046927SAndroid Build Coastguard Worker 
speculativeRead(unsigned char * readBuffer,size_t trySize)374*61046927SAndroid Build Coastguard Worker ssize_t AddressSpaceStream::speculativeRead(unsigned char* readBuffer, size_t trySize) {
375*61046927SAndroid Build Coastguard Worker     ensureType3Finished();
376*61046927SAndroid Build Coastguard Worker     ensureType1Finished();
377*61046927SAndroid Build Coastguard Worker 
378*61046927SAndroid Build Coastguard Worker     size_t actuallyRead = 0;
379*61046927SAndroid Build Coastguard Worker 
380*61046927SAndroid Build Coastguard Worker     while (!actuallyRead) {
381*61046927SAndroid Build Coastguard Worker 
382*61046927SAndroid Build Coastguard Worker         uint32_t readAvail =
383*61046927SAndroid Build Coastguard Worker             ring_buffer_available_read(
384*61046927SAndroid Build Coastguard Worker                 m_context.from_host_large_xfer.ring,
385*61046927SAndroid Build Coastguard Worker                 &m_context.from_host_large_xfer.view);
386*61046927SAndroid Build Coastguard Worker 
387*61046927SAndroid Build Coastguard Worker         if (!readAvail) {
388*61046927SAndroid Build Coastguard Worker             ring_buffer_yield();
389*61046927SAndroid Build Coastguard Worker             backoff();
390*61046927SAndroid Build Coastguard Worker             continue;
391*61046927SAndroid Build Coastguard Worker         }
392*61046927SAndroid Build Coastguard Worker 
393*61046927SAndroid Build Coastguard Worker         uint32_t toRead = readAvail > trySize ?  trySize : readAvail;
394*61046927SAndroid Build Coastguard Worker 
395*61046927SAndroid Build Coastguard Worker         long stepsRead = ring_buffer_view_read(
396*61046927SAndroid Build Coastguard Worker             m_context.from_host_large_xfer.ring,
397*61046927SAndroid Build Coastguard Worker             &m_context.from_host_large_xfer.view,
398*61046927SAndroid Build Coastguard Worker             readBuffer, toRead, 1);
399*61046927SAndroid Build Coastguard Worker 
400*61046927SAndroid Build Coastguard Worker         actuallyRead += stepsRead * toRead;
401*61046927SAndroid Build Coastguard Worker 
402*61046927SAndroid Build Coastguard Worker         if (isInError()) {
403*61046927SAndroid Build Coastguard Worker             return -1;
404*61046927SAndroid Build Coastguard Worker         }
405*61046927SAndroid Build Coastguard Worker     }
406*61046927SAndroid Build Coastguard Worker 
407*61046927SAndroid Build Coastguard Worker     return actuallyRead;
408*61046927SAndroid Build Coastguard Worker }
409*61046927SAndroid Build Coastguard Worker 
notifyAvailable()410*61046927SAndroid Build Coastguard Worker void AddressSpaceStream::notifyAvailable() {
411*61046927SAndroid Build Coastguard Worker     MESA_TRACE_SCOPE("PING");
412*61046927SAndroid Build Coastguard Worker     struct address_space_ping request;
413*61046927SAndroid Build Coastguard Worker     request.metadata = ASG_NOTIFY_AVAILABLE;
414*61046927SAndroid Build Coastguard Worker     request.resourceId = m_resourceId;
415*61046927SAndroid Build Coastguard Worker     m_ops.ping(m_handle, &request);
416*61046927SAndroid Build Coastguard Worker     ++m_notifs;
417*61046927SAndroid Build Coastguard Worker }
418*61046927SAndroid Build Coastguard Worker 
getRelativeBufferPos(uint32_t pos)419*61046927SAndroid Build Coastguard Worker uint32_t AddressSpaceStream::getRelativeBufferPos(uint32_t pos) {
420*61046927SAndroid Build Coastguard Worker     return pos & m_writeBufferMask;
421*61046927SAndroid Build Coastguard Worker }
422*61046927SAndroid Build Coastguard Worker 
advanceWrite()423*61046927SAndroid Build Coastguard Worker void AddressSpaceStream::advanceWrite() {
424*61046927SAndroid Build Coastguard Worker     m_writeStart += m_context.ring_config->flush_interval;
425*61046927SAndroid Build Coastguard Worker 
426*61046927SAndroid Build Coastguard Worker     if (m_writeStart == m_buf + m_context.ring_config->buffer_size) {
427*61046927SAndroid Build Coastguard Worker         m_writeStart = m_buf;
428*61046927SAndroid Build Coastguard Worker     }
429*61046927SAndroid Build Coastguard Worker }
430*61046927SAndroid Build Coastguard Worker 
ensureConsumerFinishing()431*61046927SAndroid Build Coastguard Worker void AddressSpaceStream::ensureConsumerFinishing() {
432*61046927SAndroid Build Coastguard Worker     uint32_t currAvailRead = ring_buffer_available_read(m_context.to_host, 0);
433*61046927SAndroid Build Coastguard Worker 
434*61046927SAndroid Build Coastguard Worker     while (currAvailRead) {
435*61046927SAndroid Build Coastguard Worker         ring_buffer_yield();
436*61046927SAndroid Build Coastguard Worker         uint32_t nextAvailRead = ring_buffer_available_read(m_context.to_host, 0);
437*61046927SAndroid Build Coastguard Worker 
438*61046927SAndroid Build Coastguard Worker         if (nextAvailRead != currAvailRead) {
439*61046927SAndroid Build Coastguard Worker             break;
440*61046927SAndroid Build Coastguard Worker         }
441*61046927SAndroid Build Coastguard Worker 
442*61046927SAndroid Build Coastguard Worker         if (*(m_context.host_state) != ASG_HOST_STATE_CAN_CONSUME &&
443*61046927SAndroid Build Coastguard Worker             *(m_context.host_state) != ASG_HOST_STATE_RENDERING) {
444*61046927SAndroid Build Coastguard Worker             notifyAvailable();
445*61046927SAndroid Build Coastguard Worker             break;
446*61046927SAndroid Build Coastguard Worker         }
447*61046927SAndroid Build Coastguard Worker 
448*61046927SAndroid Build Coastguard Worker         backoff();
449*61046927SAndroid Build Coastguard Worker     }
450*61046927SAndroid Build Coastguard Worker }
451*61046927SAndroid Build Coastguard Worker 
ensureType1Finished()452*61046927SAndroid Build Coastguard Worker void AddressSpaceStream::ensureType1Finished() {
453*61046927SAndroid Build Coastguard Worker     MESA_TRACE_SCOPE("ensureType1Finished");
454*61046927SAndroid Build Coastguard Worker 
455*61046927SAndroid Build Coastguard Worker     uint32_t currAvailRead =
456*61046927SAndroid Build Coastguard Worker         ring_buffer_available_read(m_context.to_host, 0);
457*61046927SAndroid Build Coastguard Worker 
458*61046927SAndroid Build Coastguard Worker     while (currAvailRead) {
459*61046927SAndroid Build Coastguard Worker         backoff();
460*61046927SAndroid Build Coastguard Worker         ring_buffer_yield();
461*61046927SAndroid Build Coastguard Worker         currAvailRead = ring_buffer_available_read(m_context.to_host, 0);
462*61046927SAndroid Build Coastguard Worker         if (isInError()) {
463*61046927SAndroid Build Coastguard Worker             return;
464*61046927SAndroid Build Coastguard Worker         }
465*61046927SAndroid Build Coastguard Worker     }
466*61046927SAndroid Build Coastguard Worker }
467*61046927SAndroid Build Coastguard Worker 
ensureType3Finished()468*61046927SAndroid Build Coastguard Worker void AddressSpaceStream::ensureType3Finished() {
469*61046927SAndroid Build Coastguard Worker     MESA_TRACE_SCOPE("ensureType3Finished");
470*61046927SAndroid Build Coastguard Worker     uint32_t availReadLarge =
471*61046927SAndroid Build Coastguard Worker         ring_buffer_available_read(
472*61046927SAndroid Build Coastguard Worker             m_context.to_host_large_xfer.ring,
473*61046927SAndroid Build Coastguard Worker             &m_context.to_host_large_xfer.view);
474*61046927SAndroid Build Coastguard Worker     while (availReadLarge) {
475*61046927SAndroid Build Coastguard Worker         ring_buffer_yield();
476*61046927SAndroid Build Coastguard Worker         backoff();
477*61046927SAndroid Build Coastguard Worker         availReadLarge =
478*61046927SAndroid Build Coastguard Worker             ring_buffer_available_read(
479*61046927SAndroid Build Coastguard Worker                 m_context.to_host_large_xfer.ring,
480*61046927SAndroid Build Coastguard Worker                 &m_context.to_host_large_xfer.view);
481*61046927SAndroid Build Coastguard Worker         if (*(m_context.host_state) != ASG_HOST_STATE_CAN_CONSUME &&
482*61046927SAndroid Build Coastguard Worker             *(m_context.host_state) != ASG_HOST_STATE_RENDERING) {
483*61046927SAndroid Build Coastguard Worker             notifyAvailable();
484*61046927SAndroid Build Coastguard Worker         }
485*61046927SAndroid Build Coastguard Worker         if (isInError()) {
486*61046927SAndroid Build Coastguard Worker             return;
487*61046927SAndroid Build Coastguard Worker         }
488*61046927SAndroid Build Coastguard Worker     }
489*61046927SAndroid Build Coastguard Worker }
490*61046927SAndroid Build Coastguard Worker 
type1Write(uint32_t bufferOffset,size_t size)491*61046927SAndroid Build Coastguard Worker int AddressSpaceStream::type1Write(uint32_t bufferOffset, size_t size) {
492*61046927SAndroid Build Coastguard Worker     MESA_TRACE_SCOPE("type1Write");
493*61046927SAndroid Build Coastguard Worker 
494*61046927SAndroid Build Coastguard Worker     ensureType3Finished();
495*61046927SAndroid Build Coastguard Worker 
496*61046927SAndroid Build Coastguard Worker     size_t sent = 0;
497*61046927SAndroid Build Coastguard Worker     size_t sizeForRing = sizeof(struct asg_type1_xfer);
498*61046927SAndroid Build Coastguard Worker 
499*61046927SAndroid Build Coastguard Worker     struct asg_type1_xfer xfer = {
500*61046927SAndroid Build Coastguard Worker         bufferOffset,
501*61046927SAndroid Build Coastguard Worker         (uint32_t)size,
502*61046927SAndroid Build Coastguard Worker     };
503*61046927SAndroid Build Coastguard Worker 
504*61046927SAndroid Build Coastguard Worker     uint8_t* writeBufferBytes = (uint8_t*)(&xfer);
505*61046927SAndroid Build Coastguard Worker 
506*61046927SAndroid Build Coastguard Worker     uint32_t maxOutstanding = 1;
507*61046927SAndroid Build Coastguard Worker     uint32_t maxSteps = m_context.ring_config->buffer_size /
508*61046927SAndroid Build Coastguard Worker             m_context.ring_config->flush_interval;
509*61046927SAndroid Build Coastguard Worker 
510*61046927SAndroid Build Coastguard Worker     if (maxSteps > 1) maxOutstanding = maxSteps - 1;
511*61046927SAndroid Build Coastguard Worker 
512*61046927SAndroid Build Coastguard Worker     uint32_t ringAvailReadNow = ring_buffer_available_read(m_context.to_host, 0);
513*61046927SAndroid Build Coastguard Worker 
514*61046927SAndroid Build Coastguard Worker     while (ringAvailReadNow >= maxOutstanding * sizeForRing) {
515*61046927SAndroid Build Coastguard Worker         ringAvailReadNow = ring_buffer_available_read(m_context.to_host, 0);
516*61046927SAndroid Build Coastguard Worker     }
517*61046927SAndroid Build Coastguard Worker 
518*61046927SAndroid Build Coastguard Worker     bool hostPinged = false;
519*61046927SAndroid Build Coastguard Worker     while (sent < sizeForRing) {
520*61046927SAndroid Build Coastguard Worker 
521*61046927SAndroid Build Coastguard Worker         long sentChunks = ring_buffer_write(
522*61046927SAndroid Build Coastguard Worker             m_context.to_host,
523*61046927SAndroid Build Coastguard Worker             writeBufferBytes + sent,
524*61046927SAndroid Build Coastguard Worker             sizeForRing - sent, 1);
525*61046927SAndroid Build Coastguard Worker 
526*61046927SAndroid Build Coastguard Worker         if (!hostPinged &&
527*61046927SAndroid Build Coastguard Worker             *(m_context.host_state) != ASG_HOST_STATE_CAN_CONSUME &&
528*61046927SAndroid Build Coastguard Worker             *(m_context.host_state) != ASG_HOST_STATE_RENDERING) {
529*61046927SAndroid Build Coastguard Worker             notifyAvailable();
530*61046927SAndroid Build Coastguard Worker             hostPinged = true;
531*61046927SAndroid Build Coastguard Worker         }
532*61046927SAndroid Build Coastguard Worker 
533*61046927SAndroid Build Coastguard Worker         if (sentChunks == 0) {
534*61046927SAndroid Build Coastguard Worker             ring_buffer_yield();
535*61046927SAndroid Build Coastguard Worker             backoff();
536*61046927SAndroid Build Coastguard Worker         }
537*61046927SAndroid Build Coastguard Worker 
538*61046927SAndroid Build Coastguard Worker         sent += sentChunks * (sizeForRing - sent);
539*61046927SAndroid Build Coastguard Worker 
540*61046927SAndroid Build Coastguard Worker         if (isInError()) {
541*61046927SAndroid Build Coastguard Worker             return -1;
542*61046927SAndroid Build Coastguard Worker         }
543*61046927SAndroid Build Coastguard Worker     }
544*61046927SAndroid Build Coastguard Worker 
545*61046927SAndroid Build Coastguard Worker     bool isRenderingAfter = ASG_HOST_STATE_RENDERING == __atomic_load_n(m_context.host_state, __ATOMIC_ACQUIRE);
546*61046927SAndroid Build Coastguard Worker 
547*61046927SAndroid Build Coastguard Worker     if (!isRenderingAfter) {
548*61046927SAndroid Build Coastguard Worker         notifyAvailable();
549*61046927SAndroid Build Coastguard Worker     }
550*61046927SAndroid Build Coastguard Worker 
551*61046927SAndroid Build Coastguard Worker     m_written += size;
552*61046927SAndroid Build Coastguard Worker 
553*61046927SAndroid Build Coastguard Worker     float mb = (float)m_written / 1048576.0f;
554*61046927SAndroid Build Coastguard Worker     if (mb > 100.0f) {
555*61046927SAndroid Build Coastguard Worker         mesa_logd("%s: %f mb in %d notifs. %f mb/notif\n", __func__, mb, m_notifs,
556*61046927SAndroid Build Coastguard Worker                   m_notifs ? mb / (float)m_notifs : 0.0f);
557*61046927SAndroid Build Coastguard Worker         m_notifs = 0;
558*61046927SAndroid Build Coastguard Worker         m_written = 0;
559*61046927SAndroid Build Coastguard Worker     }
560*61046927SAndroid Build Coastguard Worker 
561*61046927SAndroid Build Coastguard Worker     resetBackoff();
562*61046927SAndroid Build Coastguard Worker     return 0;
563*61046927SAndroid Build Coastguard Worker }
564*61046927SAndroid Build Coastguard Worker 
backoff()565*61046927SAndroid Build Coastguard Worker void AddressSpaceStream::backoff() {
566*61046927SAndroid Build Coastguard Worker     static const uint32_t kBackoffItersThreshold = 50000000;
567*61046927SAndroid Build Coastguard Worker     static const uint32_t kBackoffFactorDoublingIncrement = 50000000;
568*61046927SAndroid Build Coastguard Worker     ++m_backoffIters;
569*61046927SAndroid Build Coastguard Worker 
570*61046927SAndroid Build Coastguard Worker     if (m_backoffIters > kBackoffItersThreshold) {
571*61046927SAndroid Build Coastguard Worker         usleep(m_backoffFactor);
572*61046927SAndroid Build Coastguard Worker         uint32_t itersSoFarAfterThreshold = m_backoffIters - kBackoffItersThreshold;
573*61046927SAndroid Build Coastguard Worker         if (itersSoFarAfterThreshold > kBackoffFactorDoublingIncrement) {
574*61046927SAndroid Build Coastguard Worker             m_backoffFactor = m_backoffFactor << 1;
575*61046927SAndroid Build Coastguard Worker             if (m_backoffFactor > 1000) m_backoffFactor = 1000;
576*61046927SAndroid Build Coastguard Worker             m_backoffIters = kBackoffItersThreshold;
577*61046927SAndroid Build Coastguard Worker         }
578*61046927SAndroid Build Coastguard Worker     }
579*61046927SAndroid Build Coastguard Worker }
580*61046927SAndroid Build Coastguard Worker 
resetBackoff()581*61046927SAndroid Build Coastguard Worker void AddressSpaceStream::resetBackoff() {
582*61046927SAndroid Build Coastguard Worker     m_backoffIters = 0;
583*61046927SAndroid Build Coastguard Worker     m_backoffFactor = 1;
584*61046927SAndroid Build Coastguard Worker }
585