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, desc: 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, desc: 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 | |