xref: /aosp_15_r20/external/mesa3d/src/freedreno/decode/buffers.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright © 2012 Rob Clark <[email protected]>
3*61046927SAndroid Build Coastguard Worker  * SPDX-License-Identifier: MIT
4*61046927SAndroid Build Coastguard Worker  */
5*61046927SAndroid Build Coastguard Worker 
6*61046927SAndroid Build Coastguard Worker /*
7*61046927SAndroid Build Coastguard Worker  * Helper lib to track gpu buffers contents/address, and map between gpu and
8*61046927SAndroid Build Coastguard Worker  * host address while decoding cmdstream/crashdumps
9*61046927SAndroid Build Coastguard Worker  */
10*61046927SAndroid Build Coastguard Worker 
11*61046927SAndroid Build Coastguard Worker #include <assert.h>
12*61046927SAndroid Build Coastguard Worker #include <stdlib.h>
13*61046927SAndroid Build Coastguard Worker #include <string.h>
14*61046927SAndroid Build Coastguard Worker 
15*61046927SAndroid Build Coastguard Worker #include "util/rb_tree.h"
16*61046927SAndroid Build Coastguard Worker #include "buffers.h"
17*61046927SAndroid Build Coastguard Worker 
18*61046927SAndroid Build Coastguard Worker struct buffer {
19*61046927SAndroid Build Coastguard Worker    struct rb_node node;
20*61046927SAndroid Build Coastguard Worker    void *hostptr;
21*61046927SAndroid Build Coastguard Worker    unsigned int len;
22*61046927SAndroid Build Coastguard Worker    uint64_t gpuaddr;
23*61046927SAndroid Build Coastguard Worker 
24*61046927SAndroid Build Coastguard Worker    /* for 'once' mode, for buffers containing cmdstream keep track per offset
25*61046927SAndroid Build Coastguard Worker     * into buffer of which modes it has already been dumped;
26*61046927SAndroid Build Coastguard Worker     */
27*61046927SAndroid Build Coastguard Worker    struct {
28*61046927SAndroid Build Coastguard Worker       unsigned offset;
29*61046927SAndroid Build Coastguard Worker       unsigned dumped_mask;
30*61046927SAndroid Build Coastguard Worker    } offsets[256];
31*61046927SAndroid Build Coastguard Worker    unsigned noffsets;
32*61046927SAndroid Build Coastguard Worker };
33*61046927SAndroid Build Coastguard Worker 
34*61046927SAndroid Build Coastguard Worker static struct rb_tree buffers;
35*61046927SAndroid Build Coastguard Worker 
36*61046927SAndroid Build Coastguard Worker static int
buffer_insert_cmp(const struct rb_node * n1,const struct rb_node * n2)37*61046927SAndroid Build Coastguard Worker buffer_insert_cmp(const struct rb_node *n1, const struct rb_node *n2)
38*61046927SAndroid Build Coastguard Worker {
39*61046927SAndroid Build Coastguard Worker    const struct buffer *buf1 = (const struct buffer *)n1;
40*61046927SAndroid Build Coastguard Worker    const struct buffer *buf2 = (const struct buffer *)n2;
41*61046927SAndroid Build Coastguard Worker    /* Note that gpuaddr comparisions can overflow an int: */
42*61046927SAndroid Build Coastguard Worker    if (buf1->gpuaddr > buf2->gpuaddr)
43*61046927SAndroid Build Coastguard Worker       return 1;
44*61046927SAndroid Build Coastguard Worker    else if (buf1->gpuaddr < buf2->gpuaddr)
45*61046927SAndroid Build Coastguard Worker       return -1;
46*61046927SAndroid Build Coastguard Worker    return 0;
47*61046927SAndroid Build Coastguard Worker }
48*61046927SAndroid Build Coastguard Worker 
49*61046927SAndroid Build Coastguard Worker static int
buffer_search_cmp(const struct rb_node * node,const void * addrptr)50*61046927SAndroid Build Coastguard Worker buffer_search_cmp(const struct rb_node *node, const void *addrptr)
51*61046927SAndroid Build Coastguard Worker {
52*61046927SAndroid Build Coastguard Worker    const struct buffer *buf = (const struct buffer *)node;
53*61046927SAndroid Build Coastguard Worker    uint64_t gpuaddr = *(uint64_t *)addrptr;
54*61046927SAndroid Build Coastguard Worker    if (buf->gpuaddr + buf->len <= gpuaddr)
55*61046927SAndroid Build Coastguard Worker       return -1;
56*61046927SAndroid Build Coastguard Worker    else if (buf->gpuaddr > gpuaddr)
57*61046927SAndroid Build Coastguard Worker       return 1;
58*61046927SAndroid Build Coastguard Worker    return 0;
59*61046927SAndroid Build Coastguard Worker }
60*61046927SAndroid Build Coastguard Worker 
61*61046927SAndroid Build Coastguard Worker static struct buffer *
get_buffer(uint64_t gpuaddr)62*61046927SAndroid Build Coastguard Worker get_buffer(uint64_t gpuaddr)
63*61046927SAndroid Build Coastguard Worker {
64*61046927SAndroid Build Coastguard Worker    if (gpuaddr == 0)
65*61046927SAndroid Build Coastguard Worker       return NULL;
66*61046927SAndroid Build Coastguard Worker    return (struct buffer *)rb_tree_search(&buffers, &gpuaddr,
67*61046927SAndroid Build Coastguard Worker                                           buffer_search_cmp);
68*61046927SAndroid Build Coastguard Worker }
69*61046927SAndroid Build Coastguard Worker 
70*61046927SAndroid Build Coastguard Worker static int
buffer_contains_hostptr(struct buffer * buf,void * hostptr)71*61046927SAndroid Build Coastguard Worker buffer_contains_hostptr(struct buffer *buf, void *hostptr)
72*61046927SAndroid Build Coastguard Worker {
73*61046927SAndroid Build Coastguard Worker    return (buf->hostptr <= hostptr) && (hostptr < (buf->hostptr + buf->len));
74*61046927SAndroid Build Coastguard Worker }
75*61046927SAndroid Build Coastguard Worker 
76*61046927SAndroid Build Coastguard Worker uint64_t
gpuaddr(void * hostptr)77*61046927SAndroid Build Coastguard Worker gpuaddr(void *hostptr)
78*61046927SAndroid Build Coastguard Worker {
79*61046927SAndroid Build Coastguard Worker    rb_tree_foreach (struct buffer, buf, &buffers, node) {
80*61046927SAndroid Build Coastguard Worker       if (buffer_contains_hostptr(buf, hostptr))
81*61046927SAndroid Build Coastguard Worker          return buf->gpuaddr + (hostptr - buf->hostptr);
82*61046927SAndroid Build Coastguard Worker    }
83*61046927SAndroid Build Coastguard Worker    return 0;
84*61046927SAndroid Build Coastguard Worker }
85*61046927SAndroid Build Coastguard Worker 
86*61046927SAndroid Build Coastguard Worker uint64_t
gpubaseaddr(uint64_t gpuaddr)87*61046927SAndroid Build Coastguard Worker gpubaseaddr(uint64_t gpuaddr)
88*61046927SAndroid Build Coastguard Worker {
89*61046927SAndroid Build Coastguard Worker    struct buffer *buf = get_buffer(gpuaddr);
90*61046927SAndroid Build Coastguard Worker    if (buf)
91*61046927SAndroid Build Coastguard Worker       return buf->gpuaddr;
92*61046927SAndroid Build Coastguard Worker    else
93*61046927SAndroid Build Coastguard Worker       return 0;
94*61046927SAndroid Build Coastguard Worker }
95*61046927SAndroid Build Coastguard Worker 
96*61046927SAndroid Build Coastguard Worker void *
hostptr(uint64_t gpuaddr)97*61046927SAndroid Build Coastguard Worker hostptr(uint64_t gpuaddr)
98*61046927SAndroid Build Coastguard Worker {
99*61046927SAndroid Build Coastguard Worker    struct buffer *buf = get_buffer(gpuaddr);
100*61046927SAndroid Build Coastguard Worker    if (buf)
101*61046927SAndroid Build Coastguard Worker       return buf->hostptr + (gpuaddr - buf->gpuaddr);
102*61046927SAndroid Build Coastguard Worker    else
103*61046927SAndroid Build Coastguard Worker       return 0;
104*61046927SAndroid Build Coastguard Worker }
105*61046927SAndroid Build Coastguard Worker 
106*61046927SAndroid Build Coastguard Worker unsigned
hostlen(uint64_t gpuaddr)107*61046927SAndroid Build Coastguard Worker hostlen(uint64_t gpuaddr)
108*61046927SAndroid Build Coastguard Worker {
109*61046927SAndroid Build Coastguard Worker    struct buffer *buf = get_buffer(gpuaddr);
110*61046927SAndroid Build Coastguard Worker    if (buf)
111*61046927SAndroid Build Coastguard Worker       return buf->len + buf->gpuaddr - gpuaddr;
112*61046927SAndroid Build Coastguard Worker    else
113*61046927SAndroid Build Coastguard Worker       return 0;
114*61046927SAndroid Build Coastguard Worker }
115*61046927SAndroid Build Coastguard Worker 
116*61046927SAndroid Build Coastguard Worker bool
has_dumped(uint64_t gpuaddr,unsigned enable_mask)117*61046927SAndroid Build Coastguard Worker has_dumped(uint64_t gpuaddr, unsigned enable_mask)
118*61046927SAndroid Build Coastguard Worker {
119*61046927SAndroid Build Coastguard Worker    if (!gpuaddr)
120*61046927SAndroid Build Coastguard Worker       return false;
121*61046927SAndroid Build Coastguard Worker 
122*61046927SAndroid Build Coastguard Worker    struct buffer *b = get_buffer(gpuaddr);
123*61046927SAndroid Build Coastguard Worker    if (!b)
124*61046927SAndroid Build Coastguard Worker       return false;
125*61046927SAndroid Build Coastguard Worker 
126*61046927SAndroid Build Coastguard Worker    assert(gpuaddr >= b->gpuaddr);
127*61046927SAndroid Build Coastguard Worker    unsigned offset = gpuaddr - b->gpuaddr;
128*61046927SAndroid Build Coastguard Worker 
129*61046927SAndroid Build Coastguard Worker    unsigned n = 0;
130*61046927SAndroid Build Coastguard Worker    while (n < b->noffsets) {
131*61046927SAndroid Build Coastguard Worker       if (offset == b->offsets[n].offset)
132*61046927SAndroid Build Coastguard Worker          break;
133*61046927SAndroid Build Coastguard Worker       n++;
134*61046927SAndroid Build Coastguard Worker    }
135*61046927SAndroid Build Coastguard Worker 
136*61046927SAndroid Build Coastguard Worker    /* if needed, allocate a new offset entry: */
137*61046927SAndroid Build Coastguard Worker    if (n == b->noffsets) {
138*61046927SAndroid Build Coastguard Worker       b->noffsets++;
139*61046927SAndroid Build Coastguard Worker       assert(b->noffsets < ARRAY_SIZE(b->offsets));
140*61046927SAndroid Build Coastguard Worker       b->offsets[n].dumped_mask = 0;
141*61046927SAndroid Build Coastguard Worker       b->offsets[n].offset = offset;
142*61046927SAndroid Build Coastguard Worker    }
143*61046927SAndroid Build Coastguard Worker 
144*61046927SAndroid Build Coastguard Worker    if ((b->offsets[n].dumped_mask & enable_mask) == enable_mask)
145*61046927SAndroid Build Coastguard Worker       return true;
146*61046927SAndroid Build Coastguard Worker 
147*61046927SAndroid Build Coastguard Worker    b->offsets[n].dumped_mask |= enable_mask;
148*61046927SAndroid Build Coastguard Worker 
149*61046927SAndroid Build Coastguard Worker    return false;
150*61046927SAndroid Build Coastguard Worker }
151*61046927SAndroid Build Coastguard Worker 
152*61046927SAndroid Build Coastguard Worker void
reset_buffers(void)153*61046927SAndroid Build Coastguard Worker reset_buffers(void)
154*61046927SAndroid Build Coastguard Worker {
155*61046927SAndroid Build Coastguard Worker    rb_tree_foreach_safe (struct buffer, buf, &buffers, node) {
156*61046927SAndroid Build Coastguard Worker       rb_tree_remove(&buffers, &buf->node);
157*61046927SAndroid Build Coastguard Worker       free(buf->hostptr);
158*61046927SAndroid Build Coastguard Worker       free(buf);
159*61046927SAndroid Build Coastguard Worker    }
160*61046927SAndroid Build Coastguard Worker }
161*61046927SAndroid Build Coastguard Worker 
162*61046927SAndroid Build Coastguard Worker /**
163*61046927SAndroid Build Coastguard Worker  * Record buffer contents, takes ownership of hostptr (freed in
164*61046927SAndroid Build Coastguard Worker  * reset_buffers())
165*61046927SAndroid Build Coastguard Worker  */
166*61046927SAndroid Build Coastguard Worker void
add_buffer(uint64_t gpuaddr,unsigned int len,void * hostptr)167*61046927SAndroid Build Coastguard Worker add_buffer(uint64_t gpuaddr, unsigned int len, void *hostptr)
168*61046927SAndroid Build Coastguard Worker {
169*61046927SAndroid Build Coastguard Worker    struct buffer *buf = get_buffer(gpuaddr);
170*61046927SAndroid Build Coastguard Worker 
171*61046927SAndroid Build Coastguard Worker    if (!buf) {
172*61046927SAndroid Build Coastguard Worker       buf = calloc(sizeof(struct buffer), 1);
173*61046927SAndroid Build Coastguard Worker       buf->gpuaddr = gpuaddr;
174*61046927SAndroid Build Coastguard Worker       rb_tree_insert(&buffers, &buf->node, buffer_insert_cmp);
175*61046927SAndroid Build Coastguard Worker    }
176*61046927SAndroid Build Coastguard Worker 
177*61046927SAndroid Build Coastguard Worker    /* We can end up in scenarios where we capture parts of a buffer that
178*61046927SAndroid Build Coastguard Worker     * has been suballocated from twice, once as a dumped buffer and once
179*61046927SAndroid Build Coastguard Worker     * as a cmd.. possibly the kernel should get more clever about this,
180*61046927SAndroid Build Coastguard Worker     * but we need to tolerate it:
181*61046927SAndroid Build Coastguard Worker     */
182*61046927SAndroid Build Coastguard Worker    if (buf->gpuaddr != gpuaddr) {
183*61046927SAndroid Build Coastguard Worker       assert(gpuaddr > buf->gpuaddr);
184*61046927SAndroid Build Coastguard Worker       assert((gpuaddr + len) <= (buf->gpuaddr + buf->len));
185*61046927SAndroid Build Coastguard Worker 
186*61046927SAndroid Build Coastguard Worker       void *ptr = ((uint8_t *)buf->hostptr) + (gpuaddr - buf->gpuaddr);
187*61046927SAndroid Build Coastguard Worker       assert(!memcmp(ptr, hostptr, len));
188*61046927SAndroid Build Coastguard Worker 
189*61046927SAndroid Build Coastguard Worker       return;
190*61046927SAndroid Build Coastguard Worker    }
191*61046927SAndroid Build Coastguard Worker 
192*61046927SAndroid Build Coastguard Worker    buf->hostptr = hostptr;
193*61046927SAndroid Build Coastguard Worker    buf->len = len;
194*61046927SAndroid Build Coastguard Worker }
195