blob: 6e8236d5db730d011a14d12bbc7bc1c89d075932 [file] [log] [blame]
From 7fe9781df6872737d5ba6498aeaf43608358d812 Mon Sep 17 00:00:00 2001
From: Dinesh Kumar Sharma <dinesh.sharma@intel.corp-partner.google.com>
Date: Thu, 22 Sep 2022 11:56:50 +0530
Subject: [PATCH] CHROMIUM: Introduce Modem Logging functionality
The Modem Logging (MDL) port provides an interface to collect modem
logs for debugging purposes. MDL is supported by debugfs, the relay
interface, and the mtk_t7xx port infrastructure. MDL allows user-space
applications to start and control logging via MBIM port and to collect
logs via the relay interface, while port infrastructure facilitates
communication between the driver and the modem.
TOREVERT=b:197895466
BUG=b:215304027
TEST=Manual connectivity/traffic tests on Brya and build with W=1
TEST=cellular_ota
Change-Id: Iaaffcb470eee69b82a6523add38e5d1cbee2f70e
Signed-off-by: Dinesh Kumar Sharma <dinesh.sharma@intel.corp-partner.google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/3933167
Commit-Queue: Daniel Winkler <danielwinkler@google.com>
Tested-by: Daniel Winkler <danielwinkler@google.com>
Reviewed-by: Daniel Winkler <danielwinkler@google.com>
---
drivers/net/wwan/Kconfig | 1 +
drivers/net/wwan/t7xx/Makefile | 3 +
drivers/net/wwan/t7xx/t7xx_hif_cldma.c | 4 +
drivers/net/wwan/t7xx/t7xx_port.h | 6 +
drivers/net/wwan/t7xx/t7xx_port_proxy.c | 12 ++
drivers/net/wwan/t7xx/t7xx_port_proxy.h | 4 +
drivers/net/wwan/t7xx/t7xx_port_trace.c | 192 ++++++++++++++++++++++++
7 files changed, 222 insertions(+)
create mode 100644 drivers/net/wwan/t7xx/t7xx_port_trace.c
diff --git a/drivers/net/wwan/Kconfig b/drivers/net/wwan/Kconfig
index ac4d73b5626f438f6868736631b542c23b31368f..410b0245114e892808f1a445e34f954376e5d2ae 100644
--- a/drivers/net/wwan/Kconfig
+++ b/drivers/net/wwan/Kconfig
@@ -108,6 +108,7 @@ config IOSM
config MTK_T7XX
tristate "MediaTek PCIe 5G WWAN modem T7xx device"
depends on PCI
+ select RELAY if WWAN_DEBUGFS
help
Enables MediaTek PCIe based 5G WWAN modem (T7xx series) device.
Adapts WWAN framework and provides network interface like wwan0
diff --git a/drivers/net/wwan/t7xx/Makefile b/drivers/net/wwan/t7xx/Makefile
index dc6a7d682c159ec4b3899ab9f0efcce2c808f570..268ff9e87e5b3069af67858dd762283d1199c8a1 100644
--- a/drivers/net/wwan/t7xx/Makefile
+++ b/drivers/net/wwan/t7xx/Makefile
@@ -18,3 +18,6 @@ mtk_t7xx-y:= t7xx_pci.o \
t7xx_hif_dpmaif_rx.o \
t7xx_dpmaif.o \
t7xx_netdev.o
+
+mtk_t7xx-$(CONFIG_WWAN_DEBUGFS) += \
+ t7xx_port_trace.o \
diff --git a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c
index 6ff30cb8eb16ff269135dddf1eb95d9db6c219d3..9d9e770f957c68084d7b3723f84aae0e80ca65cf 100644
--- a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c
+++ b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c
@@ -59,6 +59,8 @@
#define CLDMA_JUMBO_BUFF_SZ (63 * 1024 + sizeof(struct ccci_header))
+#define CLDMA_MTU 3584 /* 3.5kB */
+
static void md_cd_queue_struct_reset(struct cldma_queue *queue, struct cldma_ctrl *md_ctrl,
enum mtk_txrx tx_rx, unsigned int index)
{
@@ -1018,6 +1020,8 @@ static int t7xx_cldma_late_init(struct cldma_ctrl *md_ctrl)
dev_err(md_ctrl->dev, "control TX ring init fail\n");
goto err_free_tx_ring;
}
+
+ md_ctrl->tx_ring[i].pkt_size = CLDMA_MTU;
}
for (j = 0; j < CLDMA_RXQ_NUM; j++) {
diff --git a/drivers/net/wwan/t7xx/t7xx_port.h b/drivers/net/wwan/t7xx/t7xx_port.h
index dc4133eb433a01d17358941473f904b881951504..79c8d690e3430e5008c371b16644039a23d0c61f 100644
--- a/drivers/net/wwan/t7xx/t7xx_port.h
+++ b/drivers/net/wwan/t7xx/t7xx_port.h
@@ -122,6 +122,12 @@ struct t7xx_port {
int rx_length_th;
bool chan_enable;
struct task_struct *thread;
+#ifdef CONFIG_WWAN_DEBUGFS
+ void *relaych;
+ struct dentry *ctrl_file;
+ struct dentry *debugfs_dir;
+ struct dentry *debugfs_wwan_dir;
+#endif
};
struct sk_buff *t7xx_port_alloc_skb(int payload);
diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.c b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
index d4de047ff0d49d782b3d5d74274d017fc478f531..894b1d11b2c9c1d80d012eaba6716549becc50b8 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_proxy.c
+++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
@@ -70,6 +70,18 @@ static const struct t7xx_port_conf t7xx_md_port_conf[] = {
.name = "MBIM",
.port_type = WWAN_PORT_MBIM,
}, {
+#ifdef CONFIG_WWAN_DEBUGFS
+ .tx_ch = PORT_CH_MD_LOG_TX,
+ .rx_ch = PORT_CH_MD_LOG_RX,
+ .txq_index = 7,
+ .rxq_index = 7,
+ .txq_exp_index = 7,
+ .rxq_exp_index = 7,
+ .path_id = CLDMA_ID_MD,
+ .ops = &t7xx_trace_port_ops,
+ .name = "mdlog",
+ }, {
+#endif
.tx_ch = PORT_CH_CONTROL_TX,
.rx_ch = PORT_CH_CONTROL_RX,
.txq_index = Q_IDX_CTRL,
diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.h b/drivers/net/wwan/t7xx/t7xx_port_proxy.h
index bc1ff5c6c7005be5d99e2b3af36e967b12ff020f..81d059fbc0fb4667bf0a5ec1f5f807c8a76a3e2e 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_proxy.h
+++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.h
@@ -87,6 +87,10 @@ struct ctrl_msg_header {
extern struct port_ops wwan_sub_port_ops;
extern struct port_ops ctl_port_ops;
+#ifdef CONFIG_WWAN_DEBUGFS
+extern struct port_ops t7xx_trace_port_ops;
+#endif
+
void t7xx_port_proxy_reset(struct port_proxy *port_prox);
void t7xx_port_proxy_uninit(struct port_proxy *port_prox);
int t7xx_port_proxy_init(struct t7xx_modem *md);
diff --git a/drivers/net/wwan/t7xx/t7xx_port_trace.c b/drivers/net/wwan/t7xx/t7xx_port_trace.c
new file mode 100644
index 0000000000000000000000000000000000000000..b4bf36203cc11f3810614b5ca7b0b13c65fd0a13
--- /dev/null
+++ b/drivers/net/wwan/t7xx/t7xx_port_trace.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Intel Corporation.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/debugfs.h>
+#include <linux/relay.h>
+#include <linux/skbuff.h>
+#include <linux/wwan.h>
+
+#include "t7xx_port.h"
+#include "t7xx_port_proxy.h"
+#include "t7xx_state_monitor.h"
+
+#define T7XX_TRC_SUB_BUFF_SIZE 131072
+#define T7XX_TRC_N_SUB_BUFF 32
+#define T7XX_TRC_FILE_PERM 0600
+
+static struct dentry *t7xx_trace_create_buf_file_handler(const char *filename,
+ struct dentry *parent,
+ umode_t mode,
+ struct rchan_buf *buf,
+ int *is_global)
+{
+ *is_global = 1;
+ return debugfs_create_file(filename, mode, parent, buf,
+ &relay_file_operations);
+}
+
+static int t7xx_trace_remove_buf_file_handler(struct dentry *dentry)
+{
+ debugfs_remove(dentry);
+ return 0;
+}
+
+static int t7xx_trace_subbuf_start_handler(struct rchan_buf *buf, void *subbuf,
+ void *prev_subbuf,
+ size_t prev_padding)
+{
+ if (relay_buf_full(buf)) {
+ pr_err_ratelimited("Relay_buf full dropping traces");
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct rchan_callbacks relay_callbacks = {
+ .subbuf_start = t7xx_trace_subbuf_start_handler,
+ .create_buf_file = t7xx_trace_create_buf_file_handler,
+ .remove_buf_file = t7xx_trace_remove_buf_file_handler,
+};
+
+static ssize_t t7xx_port_trace_write(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ struct t7xx_port *port = file->private_data;
+ size_t actual_len, alloc_size, txq_mtu;
+ const struct t7xx_port_conf *port_conf;
+ enum md_state md_state;
+ struct sk_buff *skb;
+ int ret;
+
+ port_conf = port->port_conf;
+ md_state = t7xx_fsm_get_md_state(port->t7xx_dev->md->fsm_ctl);
+ if (md_state == MD_STATE_WAITING_FOR_HS1 || md_state == MD_STATE_WAITING_FOR_HS2) {
+ dev_warn(port->dev, "port: %s ch: %d, write fail when md_state: %d\n",
+ port_conf->name, port_conf->tx_ch, md_state);
+ return -ENODEV;
+ }
+ txq_mtu = t7xx_get_port_mtu(port);
+ alloc_size = min_t(size_t, txq_mtu, len + sizeof(struct ccci_header));
+ actual_len = alloc_size - sizeof(struct ccci_header);
+ skb = t7xx_port_alloc_skb(alloc_size);
+ if (!skb) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ ret = copy_from_user(skb_put(skb, actual_len), buf, actual_len);
+ if (ret) {
+ ret = -EFAULT;
+ goto err_out;
+ }
+
+ ret = t7xx_port_send_skb(port, skb, 0, 0);
+ if (ret)
+ goto err_out;
+
+ return actual_len;
+
+err_out:
+ dev_err(port->dev, "write error done on %s, size: %zu, ret: %d\n",
+ port_conf->name, actual_len, ret);
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static const struct file_operations t7xx_trace_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .write = t7xx_port_trace_write,
+};
+
+static void t7xx_trace_port_uninit(struct t7xx_port *port)
+{
+ struct rchan *relaych = port->relaych;
+
+ if (!relaych)
+ return;
+
+ relay_close(relaych);
+ debugfs_remove_recursive(port->debugfs_dir);
+ wwan_put_debugfs_dir(port->debugfs_wwan_dir);
+}
+
+static int t7xx_trace_port_recv_skb(struct t7xx_port *port, struct sk_buff *skb)
+{
+ struct rchan *relaych = port->relaych;
+
+ if (!relaych)
+ return -EINVAL;
+
+ relay_write(relaych, skb->data, skb->len);
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+static void t7xx_port_trace_md_state_notify(struct t7xx_port *port, unsigned int state)
+{
+ struct rchan *relaych;
+
+ struct dentry *ctrl_file;
+
+ if (state != MD_STATE_READY || port->relaych)
+ return;
+
+ port->debugfs_wwan_dir = wwan_get_debugfs_dir(port->dev);
+ if (IS_ERR(port->debugfs_wwan_dir))
+ port->debugfs_wwan_dir = NULL;
+
+ port->debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, port->debugfs_wwan_dir);
+ if (IS_ERR_OR_NULL(port->debugfs_dir)) {
+ dev_err(port->dev, "Unable to create debugfs for trace");
+ return;
+ }
+
+ ctrl_file = devm_kzalloc(port->dev, sizeof(*ctrl_file), GFP_KERNEL);
+ if (!ctrl_file)
+ goto err_rm_debugfs_dir;
+
+ ctrl_file = debugfs_create_file("mdlog_ctrl",
+ T7XX_TRC_FILE_PERM,
+ port->debugfs_dir,
+ port,
+ &t7xx_trace_fops);
+
+ if (!ctrl_file)
+ goto err_rm_trace;
+
+ relaych = devm_kzalloc(port->dev, sizeof(*relaych), GFP_KERNEL);
+ if (!relaych)
+ goto err_rm_debugfs_dir;
+
+ relaych = relay_open("relay_ch",
+ port->debugfs_dir,
+ T7XX_TRC_SUB_BUFF_SIZE,
+ T7XX_TRC_N_SUB_BUFF,
+ &relay_callbacks, NULL);
+ if (!relaych)
+ goto err_rm_trace;
+
+ port->relaych = relaych;
+ port->ctrl_file = ctrl_file;
+ return;
+
+err_rm_trace:
+ kfree(relaych);
+ kfree(ctrl_file);
+
+err_rm_debugfs_dir:
+ debugfs_remove_recursive(port->debugfs_dir);
+ wwan_put_debugfs_dir(port->debugfs_wwan_dir);
+ dev_err(port->dev, "Unable to create trace port %s", port->port_conf->name);
+}
+
+struct port_ops t7xx_trace_port_ops = {
+ .recv_skb = t7xx_trace_port_recv_skb,
+ .uninit = t7xx_trace_port_uninit,
+ .md_state_notify = t7xx_port_trace_md_state_notify,
+};
--
2.38.1.584.g0f3c55d4c2-goog