1/*
2 * Copyright © 2021 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 "util/macros.h"
25#include "crashdec.h"
26
27static const char *hfi_msg_name(unsigned msgid);
28
29/*
30 * Decode HFI queues
31 */
32
33/* HFI message types */
34
35#define HFI_MSG_CMD 0
36#define HFI_MSG_ACK 1
37#define HFI_MSG_ACK_V1 2
38
39#define HFI_HEADER_ID(msg) ((msg) & 0xff)
40/* Note that header size includes the header itself: */
41#define HFI_HEADER_SIZE(msg) (((msg) >> 8) & 0xff)
42#define HFI_HEADER_TYPE(msg)   (((msg) >> 16) & 0xf)
43#define HFI_HEADER_SEQNUM(msg) (((msg) >> 20) & 0xfff)
44
45struct a6xx_hfi_queue_header {
46   uint32_t status;
47   uint32_t iova;
48   uint32_t type;
49   uint32_t size;
50   uint32_t msg_size;
51   uint32_t dropped;
52   uint32_t rx_watermark;
53   uint32_t tx_watermark;
54   uint32_t rx_request;
55   uint32_t tx_request;
56   uint32_t read_index;
57   uint32_t write_index;
58};
59
60struct a6xx_hfi_queue_table_header {
61   uint32_t version;
62   uint32_t size;               /* Size of the queue table in dwords */
63   uint32_t qhdr0_offset;       /* Offset of the first queue header */
64   uint32_t qhdr_size;          /* Size of the queue headers */
65   uint32_t num_queues;         /* Number of total queues */
66   uint32_t active_queues;      /* Number of active queues */
67   struct a6xx_hfi_queue_header queue[];
68};
69
70/*
71 * HFI message definitions:
72 */
73
74#define HFI_F2H_MSG_ACK 126
75
76struct a6xx_hfi_msg_response {
77   uint32_t header;
78   uint32_t ret_header;
79   uint32_t error;
80   uint32_t payload[16];
81};
82
83static void
84decode_F2H_MSG_ACK(struct a6xx_hfi_msg_response *msg)
85{
86   unsigned msgid = HFI_HEADER_ID(msg->ret_header);
87
88   printf("\t\t\t\tret_header: %s  (id=%u, size=%u, type=%u, seqnum=%u)\n",
89          hfi_msg_name(msgid), msgid, HFI_HEADER_SIZE(msg->ret_header),
90          HFI_HEADER_TYPE(msg->ret_header), HFI_HEADER_SEQNUM(msg->ret_header));
91   printf("\t\t\t\terror:      %u\n",     msg->error);
92}
93
94#define HFI_F2H_MSG_ERROR 100
95
96struct a6xx_hfi_msg_error {
97   uint32_t header;
98   uint32_t code;
99   uint32_t payload[2];
100};
101
102static void
103decode_F2H_MSG_ERROR(struct a6xx_hfi_msg_error *msg)
104{
105   printf("\t\t\t\tcode: %u\n", msg->code);
106}
107
108#define HFI_H2F_MSG_INIT 0
109
110struct a6xx_hfi_msg_gmu_init_cmd {
111   uint32_t header;
112   uint32_t seg_id;
113   uint32_t dbg_buffer_addr;
114   uint32_t dbg_buffer_size;
115   uint32_t boot_state;
116};
117
118static void
119decode_H2F_MSG_INIT(struct a6xx_hfi_msg_gmu_init_cmd *msg)
120{
121   printf("\t\t\t\tseg_id:          %u\n",     msg->seg_id);
122   printf("\t\t\t\tdbg_buffer_addr: 0x%08x\n", msg->dbg_buffer_addr);
123   printf("\t\t\t\tdbg_buffer_size: %u\n",     msg->dbg_buffer_size);
124   printf("\t\t\t\tboot_state:      %u\n",     msg->boot_state);
125}
126
127#define HFI_H2F_MSG_FW_VERSION 1
128
129struct a6xx_hfi_msg_fw_version {
130   uint32_t header;
131   uint32_t supported_version;
132};
133
134static void
135decode_H2F_MSG_FW_VERSION(struct a6xx_hfi_msg_fw_version *msg)
136{
137   printf("\t\t\t\tsupported_version: 0x%x\n", msg->supported_version);
138}
139
140#define HFI_H2F_MSG_PERF_TABLE 4
141
142struct perf_level {
143   uint32_t vote;
144   uint32_t freq;
145};
146
147struct perf_gx_level {
148   uint32_t vote;
149   uint32_t acd;
150   uint32_t freq;
151};
152
153struct a6xx_hfi_msg_perf_table_v1 {
154   uint32_t header;
155   uint32_t num_gpu_levels;
156   uint32_t num_gmu_levels;
157
158   struct perf_level gx_votes[16];
159   struct perf_level cx_votes[4];
160};
161
162struct a6xx_hfi_msg_perf_table {
163   uint32_t header;
164   uint32_t num_gpu_levels;
165   uint32_t num_gmu_levels;
166
167   struct perf_gx_level gx_votes[16];
168   struct perf_level cx_votes[4];
169};
170
171static void
172decode_H2F_MSG_PERF_TABLE(void *_msg)
173{
174   if (is_gmu_legacy()) {
175      struct a6xx_hfi_msg_perf_table_v1 *msg = _msg;
176      unsigned i;
177
178      printf("\t\t\t\tnum_gpu_levels: %u\n", msg->num_gpu_levels);
179      printf("\t\t\t\tnum_gmu_levels: %u\n", msg->num_gmu_levels);
180
181      assert(msg->num_gpu_levels <= ARRAY_SIZE(msg->gx_votes));
182      for (i = 0; i < msg->num_gpu_levels; i++) {
183         printf("\t\t\t\tgx_vote[%u]:    vote=%u, freq=%u\n", i,
184                msg->gx_votes[i].vote, msg->gx_votes[i].freq);
185      }
186
187      for (; i < ARRAY_SIZE(msg->gx_votes); i++) {
188         assert(!msg->gx_votes[i].vote);
189         assert(!msg->gx_votes[i].freq);
190      }
191
192      assert(msg->num_gmu_levels <= ARRAY_SIZE(msg->cx_votes));
193      for (i = 0; i < msg->num_gmu_levels; i++) {
194         printf("\t\t\t\tcx_vote[%u]:    vote=%u, freq=%u\n", i,
195                msg->cx_votes[i].vote, msg->cx_votes[i].freq);
196      }
197
198      for (; i < ARRAY_SIZE(msg->cx_votes); i++) {
199         assert(!msg->cx_votes[i].vote);
200         assert(!msg->cx_votes[i].freq);
201      }
202   } else {
203      struct a6xx_hfi_msg_perf_table *msg = _msg;
204      unsigned i;
205
206      printf("\t\t\t\tnum_gpu_levels: %u\n", msg->num_gpu_levels);
207      printf("\t\t\t\tnum_gmu_levels: %u\n", msg->num_gmu_levels);
208
209      assert(msg->num_gpu_levels <= ARRAY_SIZE(msg->gx_votes));
210      for (i = 0; i < msg->num_gpu_levels; i++) {
211         printf("\t\t\t\tgx_vote[%u]:    vote=%u, acd=%u, freq=%u\n", i,
212                msg->gx_votes[i].vote, msg->gx_votes[i].acd,
213                msg->gx_votes[i].freq);
214      }
215
216      for (; i < ARRAY_SIZE(msg->gx_votes); i++) {
217         assert(!msg->gx_votes[i].vote);
218         assert(!msg->gx_votes[i].acd);
219         assert(!msg->gx_votes[i].freq);
220      }
221
222      assert(msg->num_gmu_levels <= ARRAY_SIZE(msg->cx_votes));
223      for (i = 0; i < msg->num_gmu_levels; i++) {
224         printf("\t\t\t\tcx_vote[%u]:    vote=%u, freq=%u\n", i,
225                msg->cx_votes[i].vote, msg->cx_votes[i].freq);
226      }
227
228      for (; i < ARRAY_SIZE(msg->cx_votes); i++) {
229         assert(!msg->cx_votes[i].vote);
230         assert(!msg->cx_votes[i].freq);
231      }
232   }
233}
234
235#define HFI_H2F_MSG_BW_TABLE 3
236
237struct a6xx_hfi_msg_bw_table {
238   uint32_t header;
239   uint32_t bw_level_num;
240   uint32_t cnoc_cmds_num;
241   uint32_t ddr_cmds_num;
242   uint32_t cnoc_wait_bitmask;
243   uint32_t ddr_wait_bitmask;
244   uint32_t cnoc_cmds_addrs[6];
245   uint32_t cnoc_cmds_data[2][6];
246   uint32_t ddr_cmds_addrs[8];
247   uint32_t ddr_cmds_data[16][8];
248};
249
250static void
251decode_H2F_MSG_BW_TABLE(struct a6xx_hfi_msg_bw_table *msg)
252{
253   printf("\t\t\t\tbw_level_num:       %u\n",   msg->bw_level_num);
254   printf("\t\t\t\tcnoc_cmds_num:      %u\n",   msg->cnoc_cmds_num);
255   printf("\t\t\t\tddr_cmds_num:       %u\n",   msg->ddr_cmds_num);
256   printf("\t\t\t\tcnoc_wait_bitmask:  0x%x\n", msg->cnoc_wait_bitmask);
257   printf("\t\t\t\tddr_wait_bitmask:   0x%x\n", msg->ddr_wait_bitmask);
258   printf("\t\t\t\tcnoc_cmds_addrs:    %08x %08x %08x %08x %08x %08x\n",
259          msg->cnoc_cmds_addrs[0], msg->cnoc_cmds_addrs[1], msg->cnoc_cmds_addrs[2],
260          msg->cnoc_cmds_addrs[3], msg->cnoc_cmds_addrs[4], msg->cnoc_cmds_addrs[5]);
261   for (unsigned i = 0; i < ARRAY_SIZE(msg->cnoc_cmds_data); i++) {
262      printf("\t\t\t\tcnoc_cmds_data[%u]:  %08x %08x %08x %08x %08x %08x\n", i,
263             msg->cnoc_cmds_data[i][0], msg->cnoc_cmds_data[i][1], msg->cnoc_cmds_data[i][2],
264             msg->cnoc_cmds_data[i][3], msg->cnoc_cmds_data[i][4], msg->cnoc_cmds_data[i][5]);
265   }
266   printf("\t\t\t\tddr_cmds_addrs:     %08x %08x %08x %08x %08x %08x %08x %08x\n",
267          msg->ddr_cmds_addrs[0], msg->ddr_cmds_addrs[1], msg->ddr_cmds_addrs[2],
268          msg->ddr_cmds_addrs[3], msg->ddr_cmds_addrs[4], msg->ddr_cmds_addrs[5],
269          msg->ddr_cmds_addrs[6], msg->ddr_cmds_addrs[7]);
270   for (unsigned i = 0; i < ARRAY_SIZE(msg->ddr_cmds_data); i++) {
271      printf("\t\t\t\tddr_cmds_data[%u]:   %08x %08x %08x %08x %08x %08x %08x %08x\n", i,
272             msg->ddr_cmds_data[i][0], msg->ddr_cmds_data[i][1], msg->ddr_cmds_data[i][2],
273             msg->ddr_cmds_data[i][3], msg->ddr_cmds_data[i][4], msg->ddr_cmds_data[i][5],
274             msg->ddr_cmds_data[i][6], msg->ddr_cmds_data[i][7]);
275   }
276}
277
278#define HFI_H2F_MSG_TEST 5
279
280struct a6xx_hfi_msg_test {
281   uint32_t header;
282};
283
284static void
285decode_H2F_MSG_TEST(struct a6xx_hfi_msg_test *msg)
286{
287}
288
289#define HFI_H2F_MSG_START 10
290
291struct a6xx_hfi_msg_start {
292   uint32_t header;
293};
294
295static void
296decode_H2F_MSG_START(struct a6xx_hfi_msg_start *msg)
297{
298}
299
300#define HFI_H2F_MSG_CORE_FW_START 14
301
302struct a6xx_hfi_msg_core_fw_start {
303   uint32_t header;
304   uint32_t handle;
305};
306
307static void
308decode_H2F_MSG_CORE_FW_START(struct a6xx_hfi_msg_core_fw_start *msg)
309{
310   printf("\t\t\t\thandle: %u\n", msg->handle);
311}
312
313#define HFI_H2F_MSG_GX_BW_PERF_VOTE 30
314
315struct a6xx_hfi_gx_bw_perf_vote_cmd {
316   uint32_t header;
317   uint32_t ack_type;
318   uint32_t freq;
319   uint32_t bw;
320};
321
322static void
323decode_H2F_MSG_GX_BW_PERF_VOTE(struct a6xx_hfi_gx_bw_perf_vote_cmd *msg)
324{
325   printf("\t\t\t\tack_type: %u\n", msg->ack_type);
326   printf("\t\t\t\tfreq:     %u\n", msg->freq);
327   printf("\t\t\t\tbw:       %u\n", msg->bw);
328}
329
330#define HFI_H2F_MSG_PREPARE_SLUMBER 33
331
332struct a6xx_hfi_prep_slumber_cmd {
333   uint32_t header;
334   uint32_t bw;
335   uint32_t freq;
336};
337
338static void
339decode_H2F_MSG_PREPARE_SLUMBER(struct a6xx_hfi_prep_slumber_cmd *msg)
340{
341   printf("\t\t\t\tbw:   %u\n", msg->bw);
342   printf("\t\t\t\tfreq: %u\n", msg->freq);
343}
344
345static struct {
346   const char *name;
347   void (*decode)(void *);
348} hfi_msgs[] = {
349#define HFI_MSG(name) [HFI_ ## name] = { #name, (void (*)(void *))decode_ ## name }
350   HFI_MSG(F2H_MSG_ACK),
351   HFI_MSG(F2H_MSG_ERROR),
352   HFI_MSG(H2F_MSG_INIT),
353   HFI_MSG(H2F_MSG_FW_VERSION),
354   HFI_MSG(H2F_MSG_PERF_TABLE),
355   HFI_MSG(H2F_MSG_BW_TABLE),
356   HFI_MSG(H2F_MSG_TEST),
357   HFI_MSG(H2F_MSG_START),
358   HFI_MSG(H2F_MSG_CORE_FW_START),
359   HFI_MSG(H2F_MSG_GX_BW_PERF_VOTE),
360   HFI_MSG(H2F_MSG_PREPARE_SLUMBER),
361};
362
363static bool
364is_valid_msg_type(unsigned type)
365{
366   switch (type) {
367   case HFI_MSG_CMD:
368   case HFI_MSG_ACK:
369   case HFI_MSG_ACK_V1:
370      return true;
371   default:
372      return false;
373   }
374}
375
376static const char *
377hfi_msg_name(unsigned msgid)
378{
379   if (msgid < ARRAY_SIZE(hfi_msgs))
380      return hfi_msgs[msgid].name;
381   return NULL;
382}
383
384static bool
385is_valid_decode_start(struct a6xx_hfi_state *hfi, unsigned qidx, int32_t read_index)
386{
387   struct a6xx_hfi_queue_table_header *table = hfi->buf;
388   struct a6xx_hfi_queue_header *queue = &table->queue[qidx];
389   uint32_t offset = queue->iova - hfi->iova;
390   uint32_t *dw = (uint32_t *)(((uint8_t *)hfi->buf) + offset);
391   int last_seqno = -1;
392
393   if (read_index < 0)
394      return false;
395
396   while (read_index != queue->write_index) {
397      uint32_t hdr = dw[read_index];
398
399      if (!is_valid_msg_type(HFI_HEADER_TYPE(hdr)))
400         return false;
401
402      if (!hfi_msg_name(HFI_HEADER_ID(hdr)))
403         return false;
404
405      /* Header size should be at least 1, and not extend past the write_index: */
406      unsigned sz = HFI_HEADER_SIZE(hdr);
407      if (!is_gmu_legacy())
408         sz = ALIGN_POT(sz, 4);
409      int remaining = ((read_index + sz) + (queue->size - 1) -
410                       queue->write_index) % queue->size;
411      if ((sz == 0) || (remaining < 0))
412         return false;
413
414      /* Seqno should be one more than previous seqno: */
415      unsigned seqno = HFI_HEADER_SEQNUM(hdr);
416      if ((last_seqno != -1) && (((last_seqno + 1) & 0xfff) != seqno))
417         return false;
418
419      last_seqno = seqno;
420
421      read_index = (read_index + sz) % queue->size;
422   }
423
424   return true;
425}
426
427static void
428decode_hfi(struct a6xx_hfi_state *hfi, unsigned qidx, int32_t read_index)
429{
430   struct a6xx_hfi_queue_table_header *table = hfi->buf;
431   struct a6xx_hfi_queue_header *queue = &table->queue[qidx];
432   uint32_t offset = queue->iova - hfi->iova;
433   uint32_t *dw = (uint32_t *)(((uint8_t *)hfi->buf) + offset);
434
435   while (read_index != queue->write_index) {
436      uint32_t hdr = dw[read_index];
437      unsigned msgid = HFI_HEADER_ID(hdr);
438      unsigned sz    = HFI_HEADER_SIZE(hdr);
439      unsigned type  = HFI_HEADER_TYPE(hdr);
440      unsigned seqno = HFI_HEADER_SEQNUM(hdr);
441
442      assert(is_valid_msg_type(type));
443      assert(hfi_msg_name(msgid));
444
445      printf("\t\t\t------ %s (id=%u, size=%u, type=%u, seqnum=%u)\n",
446             hfi_msg_name(msgid), msgid, sz, type, seqno);
447
448      if (!is_gmu_legacy())
449         sz = ALIGN_POT(sz, 4);
450
451      uint32_t buf[sz];
452      for (unsigned i = 0; i < sz; i++) {
453         buf[i] = dw[(read_index + i) % queue->size];
454      }
455
456      if (type == HFI_MSG_CMD)
457         hfi_msgs[msgid].decode(buf);
458
459      dump_hex_ascii(buf, sz*4, 4);
460
461      read_index = (read_index + sz) % queue->size;
462   }
463}
464
465/* Search backwards from the most recent (last) history entry to try to
466 * find start of the oldest HFI message which has not been overwritten
467 * due to ringbuffer wraparound.
468 */
469static int32_t
470find_decode_start(struct a6xx_hfi_state *hfi, unsigned qidx)
471{
472   int i;
473
474   for (i = ARRAY_SIZE(hfi->history[qidx]) - 1; i >= 0; i--) {
475      if (!is_valid_decode_start(hfi, qidx, hfi->history[qidx][i]))
476         break;
477   }
478
479   /* Last entry was invalid, or we decremented below zero, so advance
480    * the index by one:
481    */
482   i++;
483
484   if (i >= ARRAY_SIZE(hfi->history[qidx]))
485      return -1;
486
487   return hfi->history[qidx][i];
488}
489
490void
491dump_gmu_hfi(struct a6xx_hfi_state *hfi)
492{
493   struct a6xx_hfi_queue_table_header *table = hfi->buf;
494
495   printf("\tversion:       %u\n", table->version);
496   printf("\tsize:          %u\n", table->size);
497   printf("\tqhdr0_offset:  %u\n", table->qhdr0_offset);
498   printf("\tqhdr_size:     %u\n", table->qhdr_size);
499   printf("\tnum_queues:    %u\n", table->num_queues);
500   printf("\tactive_queues: %u\n", table->active_queues);
501
502   for (unsigned i = 0; i < table->num_queues; i++) {
503      struct a6xx_hfi_queue_header *queue = &table->queue[i];
504
505      printf("\tqueue[%u]:\n", i);
506      printf("\t\tstatus:       0x%x\n", queue->status);
507      printf("\t\tiova:         0x%x\n", queue->iova);
508      printf("\t\ttype:         0x%x\n", queue->type);
509      printf("\t\tsize:         %u\n",   queue->size);
510      printf("\t\tmsg_size:     %u\n",   queue->msg_size);
511      printf("\t\tdropped:      %u\n",   queue->dropped);
512      printf("\t\trx_watermark: 0x%x\n", queue->rx_watermark);
513      printf("\t\ttx_watermark: 0x%x\n", queue->tx_watermark);
514      printf("\t\trx_request:   0x%x\n", queue->rx_request);
515      printf("\t\ttx_request:   0x%x\n", queue->tx_request);
516      printf("\t\tread_index:   %u\n",   queue->read_index);
517      printf("\t\twrite_index:  %u\n",   queue->write_index);
518
519      int32_t read_index = find_decode_start(hfi, i);
520      if (read_index >= 0)
521         decode_hfi(hfi, i, read_index);
522   }
523}
524