| 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 |
| |