Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2020-2021 Intel Corporation.
0004  */
0005 
0006 #include <linux/wwan.h>
0007 #include "iosm_ipc_trace.h"
0008 
0009 /* sub buffer size and number of sub buffer */
0010 #define IOSM_TRC_SUB_BUFF_SIZE 131072
0011 #define IOSM_TRC_N_SUB_BUFF 32
0012 
0013 #define IOSM_TRC_FILE_PERM 0600
0014 
0015 #define IOSM_TRC_DEBUGFS_TRACE "trace"
0016 #define IOSM_TRC_DEBUGFS_TRACE_CTRL "trace_ctrl"
0017 
0018 /**
0019  * ipc_trace_port_rx - Receive trace packet from cp and write to relay buffer
0020  * @ipc_imem:   Pointer to iosm_imem structure
0021  * @skb:        Pointer to struct sk_buff
0022  */
0023 void ipc_trace_port_rx(struct iosm_imem *ipc_imem, struct sk_buff *skb)
0024 {
0025     struct iosm_trace *ipc_trace = ipc_imem->trace;
0026 
0027     if (ipc_trace->ipc_rchan)
0028         relay_write(ipc_trace->ipc_rchan, skb->data, skb->len);
0029 
0030     dev_kfree_skb(skb);
0031 }
0032 
0033 /* Creates relay file in debugfs. */
0034 static struct dentry *
0035 ipc_trace_create_buf_file_handler(const char *filename,
0036                   struct dentry *parent,
0037                   umode_t mode,
0038                   struct rchan_buf *buf,
0039                   int *is_global)
0040 {
0041     *is_global = 1;
0042     return debugfs_create_file(filename, mode, parent, buf,
0043                    &relay_file_operations);
0044 }
0045 
0046 /* Removes relay file from debugfs. */
0047 static int ipc_trace_remove_buf_file_handler(struct dentry *dentry)
0048 {
0049     debugfs_remove(dentry);
0050     return 0;
0051 }
0052 
0053 static int ipc_trace_subbuf_start_handler(struct rchan_buf *buf, void *subbuf,
0054                       void *prev_subbuf,
0055                       size_t prev_padding)
0056 {
0057     if (relay_buf_full(buf)) {
0058         pr_err_ratelimited("Relay_buf full dropping traces");
0059         return 0;
0060     }
0061 
0062     return 1;
0063 }
0064 
0065 /* Relay interface callbacks */
0066 static struct rchan_callbacks relay_callbacks = {
0067     .subbuf_start = ipc_trace_subbuf_start_handler,
0068     .create_buf_file = ipc_trace_create_buf_file_handler,
0069     .remove_buf_file = ipc_trace_remove_buf_file_handler,
0070 };
0071 
0072 /* Copy the trace control mode to user buffer */
0073 static ssize_t ipc_trace_ctrl_file_read(struct file *filp, char __user *buffer,
0074                     size_t count, loff_t *ppos)
0075 {
0076     struct iosm_trace *ipc_trace = filp->private_data;
0077     char buf[16];
0078     int len;
0079 
0080     mutex_lock(&ipc_trace->trc_mutex);
0081     len = snprintf(buf, sizeof(buf), "%d\n", ipc_trace->mode);
0082     mutex_unlock(&ipc_trace->trc_mutex);
0083 
0084     return simple_read_from_buffer(buffer, count, ppos, buf, len);
0085 }
0086 
0087 /* Open and close the trace channel depending on user input */
0088 static ssize_t ipc_trace_ctrl_file_write(struct file *filp,
0089                      const char __user *buffer,
0090                      size_t count, loff_t *ppos)
0091 {
0092     struct iosm_trace *ipc_trace = filp->private_data;
0093     unsigned long val;
0094     int ret;
0095 
0096     ret = kstrtoul_from_user(buffer, count, 10, &val);
0097     if (ret)
0098         return ret;
0099 
0100     mutex_lock(&ipc_trace->trc_mutex);
0101     if (val == TRACE_ENABLE && ipc_trace->mode != TRACE_ENABLE) {
0102         ipc_trace->channel = ipc_imem_sys_port_open(ipc_trace->ipc_imem,
0103                                 ipc_trace->chl_id,
0104                                 IPC_HP_CDEV_OPEN);
0105         if (!ipc_trace->channel) {
0106             ret = -EIO;
0107             goto unlock;
0108         }
0109         ipc_trace->mode = TRACE_ENABLE;
0110     } else if (val == TRACE_DISABLE && ipc_trace->mode != TRACE_DISABLE) {
0111         ipc_trace->mode = TRACE_DISABLE;
0112         /* close trace channel */
0113         ipc_imem_sys_port_close(ipc_trace->ipc_imem,
0114                     ipc_trace->channel);
0115         relay_flush(ipc_trace->ipc_rchan);
0116     }
0117     ret = count;
0118 unlock:
0119     mutex_unlock(&ipc_trace->trc_mutex);
0120     return ret;
0121 }
0122 
0123 static const struct file_operations ipc_trace_fops = {
0124     .open = simple_open,
0125     .write = ipc_trace_ctrl_file_write,
0126     .read  = ipc_trace_ctrl_file_read,
0127 };
0128 
0129 /**
0130  * ipc_trace_init - Create trace interface & debugfs entries
0131  * @ipc_imem:   Pointer to iosm_imem structure
0132  *
0133  * Returns: Pointer to trace instance on success else NULL
0134  */
0135 struct iosm_trace *ipc_trace_init(struct iosm_imem *ipc_imem)
0136 {
0137     struct ipc_chnl_cfg chnl_cfg = { 0 };
0138     struct iosm_trace *ipc_trace;
0139 
0140     ipc_chnl_cfg_get(&chnl_cfg, IPC_MEM_CTRL_CHL_ID_3);
0141     ipc_imem_channel_init(ipc_imem, IPC_CTYPE_CTRL, chnl_cfg,
0142                   IRQ_MOD_OFF);
0143 
0144     ipc_trace = kzalloc(sizeof(*ipc_trace), GFP_KERNEL);
0145     if (!ipc_trace)
0146         return NULL;
0147 
0148     ipc_trace->mode = TRACE_DISABLE;
0149     ipc_trace->dev = ipc_imem->dev;
0150     ipc_trace->ipc_imem = ipc_imem;
0151     ipc_trace->chl_id = IPC_MEM_CTRL_CHL_ID_3;
0152 
0153     mutex_init(&ipc_trace->trc_mutex);
0154 
0155     ipc_trace->ctrl_file = debugfs_create_file(IOSM_TRC_DEBUGFS_TRACE_CTRL,
0156                            IOSM_TRC_FILE_PERM,
0157                            ipc_imem->debugfs_dir,
0158                            ipc_trace, &ipc_trace_fops);
0159 
0160     ipc_trace->ipc_rchan = relay_open(IOSM_TRC_DEBUGFS_TRACE,
0161                       ipc_imem->debugfs_dir,
0162                       IOSM_TRC_SUB_BUFF_SIZE,
0163                       IOSM_TRC_N_SUB_BUFF,
0164                       &relay_callbacks, NULL);
0165 
0166     return ipc_trace;
0167 }
0168 
0169 /**
0170  * ipc_trace_deinit - Closing relayfs, removing debugfs entries
0171  * @ipc_trace: Pointer to the iosm_trace data struct
0172  */
0173 void ipc_trace_deinit(struct iosm_trace *ipc_trace)
0174 {
0175     if (!ipc_trace)
0176         return;
0177 
0178     debugfs_remove(ipc_trace->ctrl_file);
0179     relay_close(ipc_trace->ipc_rchan);
0180     mutex_destroy(&ipc_trace->trc_mutex);
0181     kfree(ipc_trace);
0182 }