aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/hisi-ptt-decoder/hisi-ptt-pkt-decoder.c
blob: a17c423a526ddf798ee0cbc60c6030540e780510 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// SPDX-License-Identifier: GPL-2.0
/*
 * HiSilicon PCIe Trace and Tuning (PTT) support
 * Copyright (c) 2022 HiSilicon Technologies Co., Ltd.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <endian.h>
#include <byteswap.h>
#include <linux/bitops.h>
#include <stdarg.h>

#include "../color.h"
#include "hisi-ptt-pkt-decoder.h"

/*
 * For 8DW format, the bit[31:11] of DW0 is always 0x1fffff, which can be
 * used to distinguish the data format.
 * 8DW format is like:
 *   bits [                 31:11                 ][       10:0       ]
 *        |---------------------------------------|-------------------|
 *    DW0 [                0x1fffff               ][ Reserved (0x7ff) ]
 *    DW1 [                       Prefix                              ]
 *    DW2 [                     Header DW0                            ]
 *    DW3 [                     Header DW1                            ]
 *    DW4 [                     Header DW2                            ]
 *    DW5 [                     Header DW3                            ]
 *    DW6 [                   Reserved (0x0)                          ]
 *    DW7 [                        Time                               ]
 *
 * 4DW format is like:
 *   bits [31:30] [ 29:25 ][24][23][22][21][    20:11   ][    10:0    ]
 *        |-----|---------|---|---|---|---|-------------|-------------|
 *    DW0 [ Fmt ][  Type  ][T9][T8][TH][SO][   Length   ][    Time    ]
 *    DW1 [                     Header DW1                            ]
 *    DW2 [                     Header DW2                            ]
 *    DW3 [                     Header DW3                            ]
 */

enum hisi_ptt_8dw_pkt_field_type {
	HISI_PTT_8DW_CHK_AND_RSV0,
	HISI_PTT_8DW_PREFIX,
	HISI_PTT_8DW_HEAD0,
	HISI_PTT_8DW_HEAD1,
	HISI_PTT_8DW_HEAD2,
	HISI_PTT_8DW_HEAD3,
	HISI_PTT_8DW_RSV1,
	HISI_PTT_8DW_TIME,
	HISI_PTT_8DW_TYPE_MAX
};

enum hisi_ptt_4dw_pkt_field_type {
	HISI_PTT_4DW_HEAD1,
	HISI_PTT_4DW_HEAD2,
	HISI_PTT_4DW_HEAD3,
	HISI_PTT_4DW_TYPE_MAX
};

static const char * const hisi_ptt_8dw_pkt_field_name[] = {
	[HISI_PTT_8DW_PREFIX]	= "Prefix",
	[HISI_PTT_8DW_HEAD0]	= "Header DW0",
	[HISI_PTT_8DW_HEAD1]	= "Header DW1",
	[HISI_PTT_8DW_HEAD2]	= "Header DW2",
	[HISI_PTT_8DW_HEAD3]	= "Header DW3",
	[HISI_PTT_8DW_TIME]	= "Time"
};

static const char * const hisi_ptt_4dw_pkt_field_name[] = {
	[HISI_PTT_4DW_HEAD1]	= "Header DW1",
	[HISI_PTT_4DW_HEAD2]	= "Header DW2",
	[HISI_PTT_4DW_HEAD3]	= "Header DW3",
};

union hisi_ptt_4dw {
	struct {
		uint32_t format : 2;
		uint32_t type : 5;
		uint32_t t9 : 1;
		uint32_t t8 : 1;
		uint32_t th : 1;
		uint32_t so : 1;
		uint32_t len : 10;
		uint32_t time : 11;
	};
	uint32_t value;
};

static void hisi_ptt_print_pkt(const unsigned char *buf, int pos, const char *desc)
{
	const char *color = PERF_COLOR_BLUE;
	int i;

	printf(".");
	color_fprintf(stdout, color, "  %08x: ", pos);
	for (i = 0; i < HISI_PTT_FIELD_LENTH; i++)
		color_fprintf(stdout, color, "%02x ", buf[pos + i]);
	for (i = 0; i < HISI_PTT_MAX_SPACE_LEN; i++)
		color_fprintf(stdout, color, "   ");
	color_fprintf(stdout, color, "  %s\n", desc);
}

static int hisi_ptt_8dw_kpt_desc(const unsigned char *buf, int pos)
{
	int i;

	for (i = 0; i < HISI_PTT_8DW_TYPE_MAX; i++) {
		/* Do not show 8DW check field and reserved fields */
		if (i == HISI_PTT_8DW_CHK_AND_RSV0 || i == HISI_PTT_8DW_RSV1) {
			pos += HISI_PTT_FIELD_LENTH;
			continue;
		}

		hisi_ptt_print_pkt(buf, pos, hisi_ptt_8dw_pkt_field_name[i]);
		pos += HISI_PTT_FIELD_LENTH;
	}

	return hisi_ptt_pkt_size[HISI_PTT_8DW_PKT];
}

static void hisi_ptt_4dw_print_dw0(const unsigned char *buf, int pos)
{
	const char *color = PERF_COLOR_BLUE;
	union hisi_ptt_4dw dw0;
	int i;

	dw0.value = *(uint32_t *)(buf + pos);
	printf(".");
	color_fprintf(stdout, color, "  %08x: ", pos);
	for (i = 0; i < HISI_PTT_FIELD_LENTH; i++)
		color_fprintf(stdout, color, "%02x ", buf[pos + i]);
	for (i = 0; i < HISI_PTT_MAX_SPACE_LEN; i++)
		color_fprintf(stdout, color, "   ");

	color_fprintf(stdout, color,
		      "  %s %x %s %x %s %x %s %x %s %x %s %x %s %x %s %x\n",
		      "Format", dw0.format, "Type", dw0.type, "T9", dw0.t9,
		      "T8", dw0.t8, "TH", dw0.th, "SO", dw0.so, "Length",
		      dw0.len, "Time", dw0.time);
}

static int hisi_ptt_4dw_kpt_desc(const unsigned char *buf, int pos)
{
	int i;

	hisi_ptt_4dw_print_dw0(buf, pos);
	pos += HISI_PTT_FIELD_LENTH;

	for (i = 0; i < HISI_PTT_4DW_TYPE_MAX; i++) {
		hisi_ptt_print_pkt(buf, pos, hisi_ptt_4dw_pkt_field_name[i]);
		pos += HISI_PTT_FIELD_LENTH;
	}

	return hisi_ptt_pkt_size[HISI_PTT_4DW_PKT];
}

int hisi_ptt_pkt_desc(const unsigned char *buf, int pos, enum hisi_ptt_pkt_type type)
{
	if (type == HISI_PTT_8DW_PKT)
		return hisi_ptt_8dw_kpt_desc(buf, pos);

	return hisi_ptt_4dw_kpt_desc(buf, pos);
}