summaryrefslogtreecommitdiff
path: root/qrtr/debug.c
diff options
context:
space:
mode:
authorHsiu-Chang Chen <hsiuchangchen@google.com>2022-07-05 11:33:57 +0800
committerHsiu-Chang Chen <hsiuchangchen@google.com>2022-07-05 11:33:57 +0800
commitb3bbdb9cf83a472565ede2ae636367f448d79b54 (patch)
treeb7748870722efaa98445b18436a5c3b08c08399e /qrtr/debug.c
parenta669d625291d0f932429991e9855e2fc1f93f4f0 (diff)
downloadcnss2-b3bbdb9cf83a472565ede2ae636367f448d79b54.tar.gz
wcn6740: Update cnss/mhi/qmi/qrtr drivers
Migrate wlan codes to preCS release Bug: 237922233 Test: Regression Test Change-Id: I02eb261b022db86ace9a9f25327d55da1452c065
Diffstat (limited to 'qrtr/debug.c')
-rw-r--r--qrtr/debug.c200
1 files changed, 200 insertions, 0 deletions
diff --git a/qrtr/debug.c b/qrtr/debug.c
new file mode 100644
index 0000000..470c27f
--- /dev/null
+++ b/qrtr/debug.c
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/xarray.h>
+#include <linux/list.h>
+
+#include "debug.h"
+
+static LIST_HEAD(rtx_pkt_list);
+static DEFINE_SPINLOCK(rtx_pkt_list_lock);
+
+static DEFINE_XARRAY(rtx_records);
+static DEFINE_MUTEX(rtx_records_lock);
+
+static struct work_struct rtx_work;
+
+#define QRTR_FLAGS_CONFIRM_RX BIT(0)
+
+#define QRTR_PROTO_VER_1 1
+#define QRTR_PROTO_VER_2 3
+
+struct qrtr_hdr_v1 {
+ __le32 version;
+ __le32 type;
+ __le32 src_node_id;
+ __le32 src_port_id;
+ __le32 confirm_rx;
+ __le32 size;
+ __le32 dst_node_id;
+ __le32 dst_port_id;
+} __packed;
+
+struct qrtr_hdr_v2 {
+ u8 version;
+ u8 type;
+ u8 flags;
+ u8 optlen;
+ __le32 size;
+ __le16 src_node_id;
+ __le16 src_port_id;
+ __le16 dst_node_id;
+ __le16 dst_port_id;
+};
+
+struct qrtr_rtx_record {
+ u8 state;
+ unsigned long key;
+ struct timespec64 time;
+};
+
+struct qrtr_rtx_pkt {
+ u8 state;
+ unsigned long key;
+ struct list_head item;
+};
+
+void qrtr_log_resume_tx_node_erase(unsigned int node_id)
+{
+ unsigned long index;
+ struct qrtr_rtx_record *record;
+
+ mutex_lock(&rtx_records_lock);
+ xa_for_each(&rtx_records, index, record) {
+ if ((record->key >> 32) == node_id &&
+ record->state != RTX_UNREG_NODE) {
+ xa_erase(&rtx_records, record->key);
+ kfree(record);
+ }
+ }
+ mutex_unlock(&rtx_records_lock);
+
+ qrtr_log_resume_tx(node_id, 0, RTX_UNREG_NODE);
+}
+EXPORT_SYMBOL(qrtr_log_resume_tx_node_erase);
+
+static void qrtr_update_record(unsigned long key, u8 state)
+{
+ struct qrtr_rtx_record *record;
+
+ mutex_lock(&rtx_records_lock);
+ record = xa_load(&rtx_records, key);
+ if (!record) {
+ record = kzalloc(sizeof(*record), GFP_KERNEL);
+ if (!record) {
+ mutex_unlock(&rtx_records_lock);
+ return;
+ }
+
+ record->key = key;
+ record->state = state;
+ ktime_get_ts64(&record->time);
+ xa_store(&rtx_records, record->key, record, GFP_KERNEL);
+ mutex_unlock(&rtx_records_lock);
+ return;
+ }
+
+ if (record->state == RTX_REMOVE_RECORD) {
+ xa_erase(&rtx_records, record->key);
+ mutex_unlock(&rtx_records_lock);
+ kfree(record);
+ return;
+ }
+
+ record->state = state;
+ ktime_get_ts64(&record->time);
+ mutex_unlock(&rtx_records_lock);
+}
+
+static void qrtr_rtx_work(struct work_struct *work)
+{
+ struct qrtr_rtx_pkt *pkt, *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rtx_pkt_list_lock, flags);
+ list_for_each_entry_safe(pkt, tmp, &rtx_pkt_list, item) {
+ list_del(&pkt->item);
+ spin_unlock_irqrestore(&rtx_pkt_list_lock, flags);
+ qrtr_update_record(pkt->key, pkt->state);
+ kfree(pkt);
+ spin_lock_irqsave(&rtx_pkt_list_lock, flags);
+ }
+ spin_unlock_irqrestore(&rtx_pkt_list_lock, flags);
+}
+
+int qrtr_log_resume_tx(unsigned int node_id,
+ unsigned int port_id, u8 state)
+{
+ struct qrtr_rtx_pkt *pkt;
+ unsigned long flags;
+
+ pkt = kzalloc(sizeof(*pkt), GFP_ATOMIC);
+ if (!pkt)
+ return -ENOMEM;
+
+ pkt->state = state;
+ pkt->key = ((u64)node_id << 32 | port_id);
+
+ spin_lock_irqsave(&rtx_pkt_list_lock, flags);
+ list_add(&pkt->item, &rtx_pkt_list);
+ spin_unlock_irqrestore(&rtx_pkt_list_lock, flags);
+
+ schedule_work(&rtx_work);
+ return 0;
+}
+EXPORT_SYMBOL(qrtr_log_resume_tx);
+
+void qrtr_log_skb_failure(const void *data, size_t len)
+{
+ const struct qrtr_hdr_v1 *v1;
+ const struct qrtr_hdr_v2 *v2;
+ bool confirm_rx = false;
+ unsigned int node_id;
+ unsigned int port_id;
+ unsigned int ver;
+
+ ver = *(u8 *)data;
+ if (ver == QRTR_PROTO_VER_1 && len > sizeof(*v1)) {
+ v1 = data;
+ if (v1->confirm_rx) {
+ node_id = v1->src_port_id;
+ port_id = v1->src_port_id;
+ confirm_rx = true;
+ }
+ } else if (ver == QRTR_PROTO_VER_2 && len > sizeof(*v2)) {
+ v2 = data;
+ if (v2->flags & QRTR_FLAGS_CONFIRM_RX) {
+ node_id = v2->src_node_id;
+ port_id = v2->src_port_id;
+ confirm_rx = true;
+ }
+ } else {
+ pr_err("%s: Invalid version %d\n", __func__, ver);
+ }
+
+ if (confirm_rx)
+ qrtr_log_resume_tx(node_id, port_id,
+ RTX_SKB_ALLOC_FAIL);
+}
+EXPORT_SYMBOL(qrtr_log_skb_failure);
+
+void qrtr_debug_init(void)
+{
+ INIT_WORK(&rtx_work, qrtr_rtx_work);
+}
+EXPORT_SYMBOL(qrtr_debug_init);
+
+void qrtr_debug_remove(void)
+{
+ cancel_work_sync(&rtx_work);
+}
+EXPORT_SYMBOL(qrtr_debug_remove);
+
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. QRTR debug");
+MODULE_LICENSE("GPL v2");
+