// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2022 Intel Corporation. */ #include #include #include #include #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 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 void t7xx_trace_port_uninit(struct t7xx_port *port) { struct dentry *debugfs_dir = port->t7xx_dev->debugfs_dir; struct rchan *relaych = port->log.relaych; if (!relaych) return; relay_close(relaych); debugfs_remove_recursive(debugfs_dir); port->log.relaych = NULL; } static int t7xx_trace_port_recv_skb(struct t7xx_port *port, struct sk_buff *skb) { struct rchan *relaych = port->log.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 = port->log.relaych; struct dentry *debugfs_wwan_dir; struct dentry *debugfs_dir; if (state != MD_STATE_READY || relaych) return; debugfs_wwan_dir = wwan_get_debugfs_dir(port->dev); if (IS_ERR(debugfs_wwan_dir)) return; debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, debugfs_wwan_dir); if (IS_ERR_OR_NULL(debugfs_dir)) { wwan_put_debugfs_dir(debugfs_wwan_dir); dev_err(port->dev, "Unable to create debugfs for trace"); return; } relaych = relay_open("relay_ch", debugfs_dir, T7XX_TRC_SUB_BUFF_SIZE, T7XX_TRC_N_SUB_BUFF, &relay_callbacks, NULL); if (!relaych) goto err_rm_debugfs_dir; wwan_put_debugfs_dir(debugfs_wwan_dir); port->log.relaych = relaych; port->t7xx_dev->debugfs_dir = debugfs_dir; return; err_rm_debugfs_dir: debugfs_remove_recursive(debugfs_dir); wwan_put_debugfs_dir(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, };