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