// 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); }