net: qrtr: add resume tx logging
Add xarray database to log both skb allocation failed packets and skb allocation success packets when cf flag bit is set in the packet. Change-Id: Iafc4c781e7fde37b8d19fc050dc9d769b31c306e Signed-off-by: Sivaji Boddupilli <quic_boddupil@quicinc.com>
This commit is contained in:
parent
e22e825e65
commit
4f7bb0f17b
@ -67,4 +67,12 @@ config QRTR_GUNYAH
|
||||
Router communication between two virtual machines. The transport
|
||||
uses dynamically shared memory and gunyah doorbells.
|
||||
|
||||
config QRTR_DEBUG
|
||||
bool "QRTR debug enhancements"
|
||||
help
|
||||
Say Y here to enable QRTR debug enhancements support and currently
|
||||
supporting logging of resume tx failure cases when skb alloc failed
|
||||
and confirm rx flag is set. Also logging the skb alloc failure
|
||||
while allocating skb in rx path.
|
||||
|
||||
endif # QRTR
|
||||
|
@ -1,6 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_QRTR) := qrtr.o ns.o
|
||||
|
||||
obj-$(CONFIG_QRTR) += qrtr.o
|
||||
qrtr-y := af_qrtr.o ns.o
|
||||
qrtr-$(CONFIG_QRTR_DEBUG) += debug.o
|
||||
obj-$(CONFIG_QRTR_SMD) += qrtr-smd.o
|
||||
qrtr-smd-y := smd.o
|
||||
obj-$(CONFIG_QRTR_TUN) += qrtr-tun.o
|
||||
|
@ -2,6 +2,7 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Sony Mobile Communications Inc.
|
||||
* Copyright (c) 2013, 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/module.h>
|
||||
@ -20,6 +21,7 @@
|
||||
#include <uapi/linux/sched/types.h>
|
||||
|
||||
#include "qrtr.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define QRTR_LOG_PAGE_CNT 4
|
||||
#define QRTR_INFO(ctx, x, ...) \
|
||||
@ -872,6 +874,7 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
|
||||
if (!skb) {
|
||||
skb = qrtr_get_backup(len);
|
||||
if (!skb) {
|
||||
qrtr_log_skb_failure(data, len);
|
||||
pr_err("qrtr: Unable to get skb with len:%lu\n", len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -944,6 +947,8 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
|
||||
qrtr_node_assign(node, le32_to_cpu(pkt->server.node));
|
||||
}
|
||||
|
||||
if (cb->confirm_rx)
|
||||
qrtr_log_resume_tx(cb->src_node, cb->src_port, RTX_SKB_ALLOC_SUCC);
|
||||
qrtr_log_rx_msg(node, skb);
|
||||
/* All control packets and non-local destined data packets should be
|
||||
* queued to the worker for forwarding handling.
|
||||
@ -1329,7 +1334,7 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
|
||||
|
||||
/* Wake up any transmitters waiting for resume-tx from the node */
|
||||
wake_up_interruptible_all(&node->resume_tx);
|
||||
|
||||
qrtr_log_resume_tx_node_erase(node->nid);
|
||||
qrtr_node_release(node);
|
||||
ep->node = NULL;
|
||||
}
|
||||
@ -1383,6 +1388,9 @@ static void qrtr_send_del_client(struct qrtr_sock *ipc)
|
||||
pkt->client.node = cpu_to_le32(ipc->us.sq_node);
|
||||
pkt->client.port = cpu_to_le32(ipc->us.sq_port);
|
||||
|
||||
qrtr_log_resume_tx(pkt->client.node, pkt->client.port,
|
||||
RTX_REMOVE_RECORD);
|
||||
|
||||
skb_set_owner_w(skb, &ipc->sk);
|
||||
|
||||
if (ipc->state == QRTR_STATE_MULTI) {
|
||||
@ -1788,6 +1796,8 @@ static int qrtr_send_resume_tx(struct qrtr_cb *cb)
|
||||
|
||||
skb = qrtr_alloc_ctrl_packet(&pkt);
|
||||
if (!skb) {
|
||||
qrtr_log_resume_tx(cb->src_node, cb->src_port,
|
||||
RTX_CTRL_SKB_ALLOC_FAIL);
|
||||
qrtr_node_release(node);
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -1798,7 +1808,7 @@ static int qrtr_send_resume_tx(struct qrtr_cb *cb)
|
||||
|
||||
ret = qrtr_node_enqueue(node, skb, QRTR_TYPE_RESUME_TX,
|
||||
&local, &remote, 0);
|
||||
|
||||
qrtr_log_resume_tx(cb->src_node, cb->src_port, RTX_SENT_ACK);
|
||||
qrtr_node_release(node);
|
||||
|
||||
return ret;
|
||||
@ -2081,6 +2091,7 @@ static int __init qrtr_proto_init(void)
|
||||
qrtr_ns_init();
|
||||
|
||||
qrtr_backup_init();
|
||||
qrtr_debug_init();
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -2093,6 +2104,7 @@ static void __exit qrtr_proto_fini(void)
|
||||
proto_unregister(&qrtr_proto);
|
||||
|
||||
qrtr_backup_deinit();
|
||||
qrtr_debug_remove();
|
||||
}
|
||||
module_exit(qrtr_proto_fini);
|
||||
|
200
net/qrtr/debug.c
Normal file
200
net/qrtr/debug.c
Normal file
@ -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");
|
||||
|
52
net/qrtr/debug.h
Normal file
52
net/qrtr/debug.h
Normal file
@ -0,0 +1,52 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __QRTR_DEBUG_H_
|
||||
#define __QRTR_DEBUG_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
enum {
|
||||
RTX_REMOVE_RECORD = 0xFF,
|
||||
RTX_SKB_ALLOC_FAIL = 0xAA,
|
||||
RTX_SKB_ALLOC_SUCC = 0xBB,
|
||||
RTX_SENT_ACK = 0xCC,
|
||||
RTX_CTRL_SKB_ALLOC_FAIL = 0xDD,
|
||||
RTX_UNREG_NODE = 0xEE,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_QRTR_DEBUG)
|
||||
|
||||
void qrtr_debug_init(void);
|
||||
|
||||
void qrtr_debug_remove(void);
|
||||
|
||||
void qrtr_log_resume_tx_node_erase(unsigned int node_id);
|
||||
|
||||
int qrtr_log_resume_tx(unsigned int node_id,
|
||||
unsigned int port_id, u8 state);
|
||||
|
||||
void qrtr_log_skb_failure(const void *data, size_t len);
|
||||
|
||||
#else
|
||||
|
||||
static inline void qrtr_debug_init(void) { }
|
||||
|
||||
static inline void qrtr_debug_remove(void) { }
|
||||
|
||||
static inline void qrtr_log_resume_tx_node_erase(unsigned int node_id) { }
|
||||
|
||||
static inline int qrtr_log_resume_tx(unsigned int node_id,
|
||||
unsigned int port_id, u8 state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void qrtr_log_skb_failure(const void *data, size_t len) { }
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user