浏览代码

qcacmn: qdf: Add support to update tsf timestamp in data packet

Add support to update tsf timestamp on driver entry and
exit in data packet. This helps debug latency issue in
XR usecases

Change-Id: I00dcf2416513b94701c11f2a07b2dc74b665f573
CRs-Fixed: 3116365
Nirav Shah 3 年之前
父节点
当前提交
6340679db0
共有 2 个文件被更改,包括 364 次插入0 次删除
  1. 171 0
      qdf/inc/qdf_pkt_add_timestamp.h
  2. 193 0
      qdf/linux/src/qdf_pkt_add_timestamp.c

+ 171 - 0
qdf/inc/qdf_pkt_add_timestamp.h

@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: qdf_pkt_add_timestamp.h
+ * This file defines HLOS agnostic functions providing external interface
+ * for adding timestamp in packet payload.
+ */
+
+#if  !defined(_QDF_PKT_ADD_TS_H)
+#define _QDF_PKT_ADD_TS_H
+
+#include  <qdf_nbuf.h>
+#include  <qdf_types.h>
+#include  <qdf_trace.h>
+
+/**
+ * enum qdf_pkt_supported_proto - supported protocol for timestamp
+ * @QDF_PKT_PROTO_INVAL - invalid
+ * @QDF_PKT_PROTO_TCP - tcp protocol
+ * @QDF_PKT_PROTO_UDP - udp protocol
+ * @QDF_PKT_PROTO_MAX - max, keep it at last
+ */
+enum qdf_pkt_supported_proto {
+	QDF_PKT_PROTO_INVAL,
+	QDF_PKT_PROTO_TCP,
+	QDF_PKT_PROTO_UDP,
+	QDF_PKT_PROTO_MAX
+};
+
+/**
+ * enum qdf_pkt_timestamp_index - index of different timestamp
+ * @QDF_PKT_TX_DRIVER_ENTRY - tx driver entry timestamp
+ * @QDF_PKT_TX_DRIVER_EXIT - tx driver exit timestamp
+ * @QDF_PKT_RX_DRIVER_ENTRY - rx driver entry timestamp
+ * @QDF_PKT_RX_DRIVER_EXIT - rx driver exit timestamp
+ * @QDF_PKT_TIMESTAMP_MAX - maximum index, keep it at last
+ */
+enum qdf_pkt_timestamp_index {
+	QDF_PKT_TX_DRIVER_ENTRY,
+	QDF_PKT_TX_DRIVER_EXIT,
+	QDF_PKT_RX_DRIVER_ENTRY,
+	QDF_PKT_RX_DRIVER_EXIT,
+	QDF_PKT_TIMESTAMP_MAX
+};
+
+#ifdef CONFIG_DP_PKT_ADD_TIMESTAMP
+
+#define NUM_DP_PKT_TIMESTAMP_SUPPORT 4
+
+struct ts_info {
+	uint64_t sec;
+	uint64_t usec;
+} qdf_packed;
+
+struct ts {
+	struct ts_info ts_info[QDF_PKT_TIMESTAMP_MAX];
+} qdf_packed;
+
+#define QDF_PKT_PROTO_TCP_BIT	(1 << QDF_PKT_PROTO_TCP)
+#define QDF_PKT_PROTO_UDP_BIT	(1 << QDF_PKT_PROTO_UDP)
+
+struct dp_pkt_proto_info {
+	enum qdf_pkt_supported_proto proto;
+	uint16_t port;
+	uint16_t offset;
+};
+
+struct dp_pkt_add_ts_info {
+	uint8_t current_index;
+	uint16_t enable_protocol_bitmap;
+	struct dp_pkt_proto_info proto_info[NUM_DP_PKT_TIMESTAMP_SUPPORT];
+};
+
+/**
+ * qdf_set_dp_pkt_add_ts_info() - set protocol/port and offset info
+ *
+ * @proto: protocol to timestamp
+ * @port: destination port of protocol
+ * @offset: offset in payload
+ *
+ * Return: 0 for success
+ */
+int qdf_set_dp_pkt_add_ts_info(enum qdf_pkt_supported_proto proto,
+			       uint16_t port, uint16_t offset);
+
+/**
+ * qdf_clear_dp_pkt_add_ts_info() - clear all timestamp info
+ *
+ * Return: none
+ */
+void qdf_clear_dp_pkt_add_ts_info(void);
+
+/**
+ * qdf_show_dp_pkt_add_ts_info() - Update buffer with configured information
+ *
+ * @buf: buffer pointer to get information
+ * @size: size of the buffer
+ *
+ * Return: number of bytes update in buffer
+ */
+int qdf_show_dp_pkt_add_ts_info(char *buf, size_t size);
+
+/**
+ * qdf_add_dp_pkt_timestamp() - add timestamp in data payload
+ *
+ * @nbuf: network buffer
+ * @index: this decides offset in payload
+ * @time: timestamp to update
+ *
+ * Return: none
+ */
+void qdf_add_dp_pkt_timestamp(qdf_nbuf_t nbuf,
+			      enum qdf_pkt_timestamp_index index,
+			      uint64_t time);
+
+/**
+ * qdf_is_dp_pkt_timestamp_enabled() - check if packet timestamping is enabled
+ *
+ * Return: true/false
+ */
+bool qdf_is_dp_pkt_timestamp_enabled(void);
+#else
+
+static inline
+int qdf_set_dp_pkt_add_ts_info(enum qdf_pkt_supported_proto proto,
+			       uint16_t port, uint16_t offset)
+{
+	return 0;
+}
+
+static inline
+void qdf_clear_dp_pkt_add_ts_info(void)
+{
+}
+
+static inline
+int qdf_show_dp_pkt_add_ts_info(char *buf, size_t size)
+{
+	return 0;
+}
+
+static inline
+void qdf_add_dp_pkt_timestamp(qdf_nbuf_t nbuf,
+			      enum qdf_pkt_timestamp_index index, uint64_t time)
+{
+}
+
+static inline
+bool qdf_is_dp_pkt_timestamp_enabled(void)
+{
+	return false;
+}
+
+#endif
+#endif

+ 193 - 0
qdf/linux/src/qdf_pkt_add_timestamp.c

@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <qdf_pkt_add_timestamp.h>
+
+static struct dp_pkt_add_ts_info dp_pkt_ts_info;
+static int dp_pkt_add_timestamp;
+
+int qdf_set_dp_pkt_add_ts_info(enum qdf_pkt_supported_proto proto,
+			       uint16_t port, uint16_t offset)
+{
+	if (dp_pkt_ts_info.current_index >= NUM_DP_PKT_TIMESTAMP_SUPPORT) {
+		qdf_err("Only %d number of protocol supported",
+			NUM_DP_PKT_TIMESTAMP_SUPPORT);
+		return -EINVAL;
+	}
+
+	dp_pkt_ts_info.enable_protocol_bitmap |= (1 << proto);
+	dp_pkt_ts_info.proto_info[dp_pkt_ts_info.current_index].proto = proto;
+	dp_pkt_ts_info.proto_info[dp_pkt_ts_info.current_index].port = port;
+	dp_pkt_ts_info.proto_info[dp_pkt_ts_info.current_index++].offset =
+									offset;
+	dp_pkt_add_timestamp = 1;
+	return 0;
+}
+
+void qdf_clear_dp_pkt_add_ts_info(void)
+{
+	dp_pkt_add_timestamp = 0;
+	qdf_mem_zero(&dp_pkt_ts_info, sizeof(dp_pkt_ts_info));
+}
+
+static
+const char *qdf_get_proto_str(enum qdf_pkt_supported_proto proto)
+{
+	switch (proto) {
+	case QDF_PKT_PROTO_TCP:
+		return "TCP";
+	case QDF_PKT_PROTO_UDP:
+		return "UDP";
+	default:
+		return "Invalid";
+	}
+}
+
+int qdf_show_dp_pkt_add_ts_info(char *buf, size_t size)
+{
+	int i;
+	int cnt = 0;
+
+	qdf_debug("dp_pkt_add_timestamp %d", dp_pkt_add_timestamp);
+	qdf_debug("enable_protocol_bitmap %x",
+		  dp_pkt_ts_info.enable_protocol_bitmap);
+	qdf_debug("current_index %d", dp_pkt_ts_info.current_index);
+
+	cnt += scnprintf(buf + cnt, size - cnt, "dp_pkt_add_timestamp %d\n",
+			 dp_pkt_add_timestamp);
+	for (i = 0; i < dp_pkt_ts_info.current_index; i++) {
+		qdf_debug("proto %d port %d offset %d",
+			  dp_pkt_ts_info.proto_info[i].proto,
+			  dp_pkt_ts_info.proto_info[i].port,
+			  dp_pkt_ts_info.proto_info[i].offset);
+		if (size - cnt <= 0)
+			continue;
+		cnt += scnprintf(buf + cnt, size - cnt,
+				 "Protocol: %s Destination Port %d Offset %d\n",
+				 qdf_get_proto_str(
+					 dp_pkt_ts_info.proto_info[i].proto),
+				 dp_pkt_ts_info.proto_info[i].port,
+				 dp_pkt_ts_info.proto_info[i].offset);
+	}
+	return cnt;
+}
+
+bool qdf_is_dp_pkt_timestamp_enabled(void)
+{
+	return dp_pkt_add_timestamp;
+}
+
+static inline
+uint32_t qdf_get_tcp_offset(qdf_nbuf_t nbuf, uint16_t offset)
+{
+	uint16_t ip_header_len, tcp_header_len, tcp_header_off;
+	uint8_t *skb_data = (uint8_t *)qdf_nbuf_data(nbuf);
+
+	ip_header_len = ((uint8_t)(*(uint8_t *)
+				(skb_data + QDF_NBUF_TRAC_IPV4_OFFSET)) &
+			QDF_NBUF_TRAC_IPV4_HEADER_MASK) << 2;
+	tcp_header_off = QDF_NBUF_TRAC_IPV4_OFFSET + ip_header_len;
+	tcp_header_len = ((uint8_t)(*(uint8_t *)
+				(skb_data + tcp_header_off +
+				 QDF_NBUF_TRAC_TCP_HEADER_LEN_OFFSET))) >> 2;
+	return tcp_header_off + tcp_header_len + offset;
+}
+
+static inline
+uint32_t qdf_get_udp_offset(qdf_nbuf_t nbuf, uint16_t offset)
+{
+	uint16_t ip_header_len, udp_header_len;
+	uint8_t *skb_data = (uint8_t *)qdf_nbuf_data(nbuf);
+
+	ip_header_len = ((uint8_t)(*(uint8_t *)
+				(skb_data + QDF_NBUF_TRAC_IPV4_OFFSET)) &
+			QDF_NBUF_TRAC_IPV4_HEADER_MASK) << 2;
+	udp_header_len = 8;
+	return  QDF_NBUF_TRAC_IPV4_OFFSET + ip_header_len +
+		udp_header_len + offset;
+}
+
+static inline
+void qdf_add_ts(qdf_nbuf_t nbuf, uint32_t offset,
+		enum qdf_pkt_timestamp_index index, uint64_t time,
+		enum qdf_pkt_supported_proto proto)
+{
+	struct ts *ts_ptr;
+	struct ts_info *ts_info;
+	uint32_t total_offset;
+
+	if (proto == QDF_PKT_PROTO_TCP)
+		total_offset = qdf_get_tcp_offset(nbuf, offset);
+	else if (proto == QDF_PKT_PROTO_UDP)
+		total_offset = qdf_get_udp_offset(nbuf, offset);
+	else
+		return;
+
+	if (qdf_nbuf_len(nbuf) < total_offset + sizeof(struct ts))
+		return;
+
+	ts_ptr = (struct ts *)(qdf_nbuf_data(nbuf) + total_offset);
+	ts_info = &ts_ptr->ts_info[index];
+
+	ts_info->sec = time / 1000000;
+	ts_info->usec = time % 1000000;
+}
+
+void qdf_add_dp_pkt_timestamp(qdf_nbuf_t nbuf,
+			      enum qdf_pkt_timestamp_index index, uint64_t time)
+{
+	int i;
+	uint16_t port;
+	uint32_t offset;
+
+	if (dp_pkt_ts_info.enable_protocol_bitmap & QDF_PKT_PROTO_TCP_BIT) {
+		if (qdf_nbuf_is_ipv4_tcp_pkt(nbuf)) {
+			port =
+			    QDF_SWAP_U16(qdf_nbuf_data_get_tcp_dst_port(nbuf));
+			for (i = 0; i < dp_pkt_ts_info.current_index; i++) {
+				offset =  dp_pkt_ts_info.proto_info[i].offset;
+				if (dp_pkt_ts_info.proto_info[i].proto ==
+				    QDF_PKT_PROTO_TCP &&
+				    dp_pkt_ts_info.proto_info[i].port == port) {
+					qdf_add_ts(nbuf, offset, index, time,
+						   QDF_PKT_PROTO_TCP);
+					break;
+				}
+			}
+			return;
+		}
+	}
+
+	if (dp_pkt_ts_info.enable_protocol_bitmap & QDF_PKT_PROTO_UDP_BIT) {
+		if (qdf_nbuf_is_ipv4_udp_pkt(nbuf)) {
+			port =
+			    QDF_SWAP_U16(qdf_nbuf_data_get_tcp_dst_port(nbuf));
+			for (i = 0; i < dp_pkt_ts_info.current_index; i++) {
+				offset =  dp_pkt_ts_info.proto_info[i].offset;
+				if (dp_pkt_ts_info.proto_info[i].proto ==
+				    QDF_PKT_PROTO_UDP &&
+				    dp_pkt_ts_info.proto_info[i].port == port) {
+					qdf_add_ts(nbuf, offset, index, time,
+						   QDF_PKT_PROTO_UDP);
+					break;
+				}
+			}
+			return;
+		}
+	}
+}