1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * HiSilicon PCIe Trace and Tuning (PTT) support
4  * Copyright (c) 2022 HiSilicon Technologies Co., Ltd.
5  */
6 
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <endian.h>
11 #include <byteswap.h>
12 #include <linux/bitops.h>
13 #include <stdarg.h>
14 
15 #include "../color.h"
16 #include "hisi-ptt-pkt-decoder.h"
17 
18 /*
19  * For 8DW format, the bit[31:11] of DW0 is always 0x1fffff, which can be
20  * used to distinguish the data format.
21  * 8DW format is like:
22  *   bits [                 31:11                 ][       10:0       ]
23  *        |---------------------------------------|-------------------|
24  *    DW0 [                0x1fffff               ][ Reserved (0x7ff) ]
25  *    DW1 [                       Prefix                              ]
26  *    DW2 [                     Header DW0                            ]
27  *    DW3 [                     Header DW1                            ]
28  *    DW4 [                     Header DW2                            ]
29  *    DW5 [                     Header DW3                            ]
30  *    DW6 [                   Reserved (0x0)                          ]
31  *    DW7 [                        Time                               ]
32  *
33  * 4DW format is like:
34  *   bits [31:30] [ 29:25 ][24][23][22][21][    20:11   ][    10:0    ]
35  *        |-----|---------|---|---|---|---|-------------|-------------|
36  *    DW0 [ Fmt ][  Type  ][T9][T8][TH][SO][   Length   ][    Time    ]
37  *    DW1 [                     Header DW1                            ]
38  *    DW2 [                     Header DW2                            ]
39  *    DW3 [                     Header DW3                            ]
40  */
41 
42 enum hisi_ptt_8dw_pkt_field_type {
43 	HISI_PTT_8DW_CHK_AND_RSV0,
44 	HISI_PTT_8DW_PREFIX,
45 	HISI_PTT_8DW_HEAD0,
46 	HISI_PTT_8DW_HEAD1,
47 	HISI_PTT_8DW_HEAD2,
48 	HISI_PTT_8DW_HEAD3,
49 	HISI_PTT_8DW_RSV1,
50 	HISI_PTT_8DW_TIME,
51 	HISI_PTT_8DW_TYPE_MAX
52 };
53 
54 enum hisi_ptt_4dw_pkt_field_type {
55 	HISI_PTT_4DW_HEAD1,
56 	HISI_PTT_4DW_HEAD2,
57 	HISI_PTT_4DW_HEAD3,
58 	HISI_PTT_4DW_TYPE_MAX
59 };
60 
61 static const char * const hisi_ptt_8dw_pkt_field_name[] = {
62 	[HISI_PTT_8DW_PREFIX]	= "Prefix",
63 	[HISI_PTT_8DW_HEAD0]	= "Header DW0",
64 	[HISI_PTT_8DW_HEAD1]	= "Header DW1",
65 	[HISI_PTT_8DW_HEAD2]	= "Header DW2",
66 	[HISI_PTT_8DW_HEAD3]	= "Header DW3",
67 	[HISI_PTT_8DW_TIME]	= "Time"
68 };
69 
70 static const char * const hisi_ptt_4dw_pkt_field_name[] = {
71 	[HISI_PTT_4DW_HEAD1]	= "Header DW1",
72 	[HISI_PTT_4DW_HEAD2]	= "Header DW2",
73 	[HISI_PTT_4DW_HEAD3]	= "Header DW3",
74 };
75 
76 union hisi_ptt_4dw {
77 	struct {
78 		uint32_t format : 2;
79 		uint32_t type : 5;
80 		uint32_t t9 : 1;
81 		uint32_t t8 : 1;
82 		uint32_t th : 1;
83 		uint32_t so : 1;
84 		uint32_t len : 10;
85 		uint32_t time : 11;
86 	};
87 	uint32_t value;
88 };
89 
90 static void hisi_ptt_print_pkt(const unsigned char *buf, int pos, const char *desc)
91 {
92 	const char *color = PERF_COLOR_BLUE;
93 	int i;
94 
95 	printf(".");
96 	color_fprintf(stdout, color, "  %08x: ", pos);
97 	for (i = 0; i < HISI_PTT_FIELD_LENTH; i++)
98 		color_fprintf(stdout, color, "%02x ", buf[pos + i]);
99 	for (i = 0; i < HISI_PTT_MAX_SPACE_LEN; i++)
100 		color_fprintf(stdout, color, "   ");
101 	color_fprintf(stdout, color, "  %s\n", desc);
102 }
103 
104 static int hisi_ptt_8dw_kpt_desc(const unsigned char *buf, int pos)
105 {
106 	int i;
107 
108 	for (i = 0; i < HISI_PTT_8DW_TYPE_MAX; i++) {
109 		/* Do not show 8DW check field and reserved fields */
110 		if (i == HISI_PTT_8DW_CHK_AND_RSV0 || i == HISI_PTT_8DW_RSV1) {
111 			pos += HISI_PTT_FIELD_LENTH;
112 			continue;
113 		}
114 
115 		hisi_ptt_print_pkt(buf, pos, hisi_ptt_8dw_pkt_field_name[i]);
116 		pos += HISI_PTT_FIELD_LENTH;
117 	}
118 
119 	return hisi_ptt_pkt_size[HISI_PTT_8DW_PKT];
120 }
121 
122 static void hisi_ptt_4dw_print_dw0(const unsigned char *buf, int pos)
123 {
124 	const char *color = PERF_COLOR_BLUE;
125 	union hisi_ptt_4dw dw0;
126 	int i;
127 
128 	dw0.value = *(uint32_t *)(buf + pos);
129 	printf(".");
130 	color_fprintf(stdout, color, "  %08x: ", pos);
131 	for (i = 0; i < HISI_PTT_FIELD_LENTH; i++)
132 		color_fprintf(stdout, color, "%02x ", buf[pos + i]);
133 	for (i = 0; i < HISI_PTT_MAX_SPACE_LEN; i++)
134 		color_fprintf(stdout, color, "   ");
135 
136 	color_fprintf(stdout, color,
137 		      "  %s %x %s %x %s %x %s %x %s %x %s %x %s %x %s %x\n",
138 		      "Format", dw0.format, "Type", dw0.type, "T9", dw0.t9,
139 		      "T8", dw0.t8, "TH", dw0.th, "SO", dw0.so, "Length",
140 		      dw0.len, "Time", dw0.time);
141 }
142 
143 static int hisi_ptt_4dw_kpt_desc(const unsigned char *buf, int pos)
144 {
145 	int i;
146 
147 	hisi_ptt_4dw_print_dw0(buf, pos);
148 	pos += HISI_PTT_FIELD_LENTH;
149 
150 	for (i = 0; i < HISI_PTT_4DW_TYPE_MAX; i++) {
151 		hisi_ptt_print_pkt(buf, pos, hisi_ptt_4dw_pkt_field_name[i]);
152 		pos += HISI_PTT_FIELD_LENTH;
153 	}
154 
155 	return hisi_ptt_pkt_size[HISI_PTT_4DW_PKT];
156 }
157 
158 int hisi_ptt_pkt_desc(const unsigned char *buf, int pos, enum hisi_ptt_pkt_type type)
159 {
160 	if (type == HISI_PTT_8DW_PKT)
161 		return hisi_ptt_8dw_kpt_desc(buf, pos);
162 
163 	return hisi_ptt_4dw_kpt_desc(buf, pos);
164 }
165