Commit 16daf3d9 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'wwan-debugfs-tweaks'

Sergey Ryazanov says:

====================
WWAN debugfs tweaks

This is a follow-up series to just applied IOSM (and WWAN) debugfs
interface support [1]. The series has two main goals:
1. move the driver-specific debugfs knobs to a subdirectory;
2. make the debugfs interface optional for both IOSM and for the WWAN
   core.

As for the first part, I must say that it was my mistake. I suggested to
place debugfs entries under a common per WWAN device directory. But I
missed the driver subdirectory in the example, so it become:

/sys/kernel/debugfs/wwan/wwan0/trace

Since the traces collection is a driver-specific feature, it is better
to keep it under the driver-specific subdirectory:

/sys/kernel/debugfs/wwan/wwan0/iosm/trace

It is desirable to be able to entirely disable the debugfs interface. It
can be disabled for several reasons, including security and consumed
storage space. See detailed rationale with usage example in the 4th
patch.

The changes themselves are relatively simple, but require a code
rearrangement. So to make changes clear, I chose to split them into
preparatory and main changes and properly describe each of them.

IOSM part is compile-tested only since I do not have IOSM supported
device, so it needs Ack from the driver developers.

I would like to thank Johannes Berg and Leon Romanovsky. Their
suggestions and comments helped a lot to rework the initial
over-engineered solution to something less confusing and much more
simple. Thanks!

1. https://lore.kernel.org/netdev/20211120162155.1216081-1-m.chetan.kumar@linux.intel.com
2. https://patchwork.kernel.org/project/netdevbpf/patch/20211204174033.950528-1-arnd@kernel.org/
====================

Link: https://lore.kernel.org/r/20211207092140.19142-1-ryazanov.s.a@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents a43a0720 283e6f5a
...@@ -16,6 +16,17 @@ config WWAN ...@@ -16,6 +16,17 @@ config WWAN
if WWAN if WWAN
config WWAN_DEBUGFS
bool "WWAN devices debugfs interface" if EXPERT
depends on DEBUG_FS
default y
help
Enables debugfs infrastructure for the WWAN core and device drivers.
If this option is selected, then you can find the debug interface
elements for each WWAN device in a directory that is corresponding to
the device name: debugfs/wwan/wwanX.
config WWAN_HWSIM config WWAN_HWSIM
tristate "Simulated WWAN device" tristate "Simulated WWAN device"
help help
...@@ -85,7 +96,7 @@ config IOSM ...@@ -85,7 +96,7 @@ config IOSM
tristate "IOSM Driver for Intel M.2 WWAN Device" tristate "IOSM Driver for Intel M.2 WWAN Device"
depends on INTEL_IOMMU depends on INTEL_IOMMU
select NET_DEVLINK select NET_DEVLINK
select RELAY select RELAY if WWAN_DEBUGFS
help help
This driver enables Intel M.2 WWAN Device communication. This driver enables Intel M.2 WWAN Device communication.
......
...@@ -21,7 +21,10 @@ iosm-y = \ ...@@ -21,7 +21,10 @@ iosm-y = \
iosm_ipc_mux_codec.o \ iosm_ipc_mux_codec.o \
iosm_ipc_devlink.o \ iosm_ipc_devlink.o \
iosm_ipc_flash.o \ iosm_ipc_flash.o \
iosm_ipc_coredump.o \ iosm_ipc_coredump.o
iosm-$(CONFIG_WWAN_DEBUGFS) += \
iosm_ipc_debugfs.o \
iosm_ipc_trace.o iosm_ipc_trace.o
obj-$(CONFIG_IOSM) := iosm.o obj-$(CONFIG_IOSM) := iosm.o
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2020-2021 Intel Corporation.
*/
#include <linux/debugfs.h>
#include <linux/wwan.h>
#include "iosm_ipc_imem.h"
#include "iosm_ipc_trace.h"
#include "iosm_ipc_debugfs.h"
void ipc_debugfs_init(struct iosm_imem *ipc_imem)
{
struct dentry *debugfs_pdev = wwan_get_debugfs_dir(ipc_imem->dev);
ipc_imem->debugfs_dir = debugfs_create_dir(KBUILD_MODNAME,
debugfs_pdev);
ipc_imem->trace = ipc_trace_init(ipc_imem);
if (!ipc_imem->trace)
dev_warn(ipc_imem->dev, "trace channel init failed");
}
void ipc_debugfs_deinit(struct iosm_imem *ipc_imem)
{
ipc_trace_deinit(ipc_imem->trace);
debugfs_remove_recursive(ipc_imem->debugfs_dir);
}
/* SPDX-License-Identifier: GPL-2.0-only
*
* Copyright (C) 2020-2021 Intel Corporation.
*/
#ifndef IOSM_IPC_DEBUGFS_H
#define IOSM_IPC_DEBUGFS_H
#ifdef CONFIG_WWAN_DEBUGFS
void ipc_debugfs_init(struct iosm_imem *ipc_imem);
void ipc_debugfs_deinit(struct iosm_imem *ipc_imem);
#else
static inline void ipc_debugfs_init(struct iosm_imem *ipc_imem) {}
static inline void ipc_debugfs_deinit(struct iosm_imem *ipc_imem) {}
#endif
#endif
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "iosm_ipc_imem.h" #include "iosm_ipc_imem.h"
#include "iosm_ipc_port.h" #include "iosm_ipc_port.h"
#include "iosm_ipc_trace.h" #include "iosm_ipc_trace.h"
#include "iosm_ipc_debugfs.h"
/* Check the wwan ips if it is valid with Channel as input. */ /* Check the wwan ips if it is valid with Channel as input. */
static int ipc_imem_check_wwan_ips(struct ipc_mem_channel *chnl) static int ipc_imem_check_wwan_ips(struct ipc_mem_channel *chnl)
...@@ -272,8 +273,8 @@ static void ipc_imem_dl_skb_process(struct iosm_imem *ipc_imem, ...@@ -272,8 +273,8 @@ static void ipc_imem_dl_skb_process(struct iosm_imem *ipc_imem,
if (port_id == IPC_MEM_CTRL_CHL_ID_7) if (port_id == IPC_MEM_CTRL_CHL_ID_7)
ipc_imem_sys_devlink_notify_rx(ipc_imem->ipc_devlink, ipc_imem_sys_devlink_notify_rx(ipc_imem->ipc_devlink,
skb); skb);
else if (port_id == ipc_imem->trace->chl_id) else if (ipc_is_trace_channel(ipc_imem, port_id))
ipc_trace_port_rx(ipc_imem->trace, skb); ipc_trace_port_rx(ipc_imem, skb);
else else
wwan_port_rx(ipc_imem->ipc_port[port_id]->iosm_port, wwan_port_rx(ipc_imem->ipc_port[port_id]->iosm_port,
skb); skb);
...@@ -554,11 +555,7 @@ static void ipc_imem_run_state_worker(struct work_struct *instance) ...@@ -554,11 +555,7 @@ static void ipc_imem_run_state_worker(struct work_struct *instance)
ctrl_chl_idx++; ctrl_chl_idx++;
} }
ipc_imem->trace = ipc_imem_trace_channel_init(ipc_imem); ipc_debugfs_init(ipc_imem);
if (!ipc_imem->trace) {
dev_err(ipc_imem->dev, "trace channel init failed");
return;
}
ipc_task_queue_send_task(ipc_imem, ipc_imem_send_mdm_rdy_cb, 0, NULL, 0, ipc_task_queue_send_task(ipc_imem, ipc_imem_send_mdm_rdy_cb, 0, NULL, 0,
false); false);
...@@ -1175,7 +1172,7 @@ void ipc_imem_cleanup(struct iosm_imem *ipc_imem) ...@@ -1175,7 +1172,7 @@ void ipc_imem_cleanup(struct iosm_imem *ipc_imem)
if (test_and_clear_bit(FULLY_FUNCTIONAL, &ipc_imem->flag)) { if (test_and_clear_bit(FULLY_FUNCTIONAL, &ipc_imem->flag)) {
ipc_mux_deinit(ipc_imem->mux); ipc_mux_deinit(ipc_imem->mux);
ipc_trace_deinit(ipc_imem->trace); ipc_debugfs_deinit(ipc_imem);
ipc_wwan_deinit(ipc_imem->wwan); ipc_wwan_deinit(ipc_imem->wwan);
ipc_port_deinit(ipc_imem->ipc_port); ipc_port_deinit(ipc_imem->ipc_port);
} }
......
...@@ -341,6 +341,7 @@ enum ipc_phase { ...@@ -341,6 +341,7 @@ enum ipc_phase {
* @ev_mux_net_transmit_pending:0 means inform the IPC tasklet to pass * @ev_mux_net_transmit_pending:0 means inform the IPC tasklet to pass
* @reset_det_n: Reset detect flag * @reset_det_n: Reset detect flag
* @pcie_wake_n: Pcie wake flag * @pcie_wake_n: Pcie wake flag
* @debugfs_dir: Debug FS directory for driver-specific entries
*/ */
struct iosm_imem { struct iosm_imem {
struct iosm_mmio *mmio; struct iosm_mmio *mmio;
...@@ -350,7 +351,9 @@ struct iosm_imem { ...@@ -350,7 +351,9 @@ struct iosm_imem {
struct iosm_mux *mux; struct iosm_mux *mux;
struct iosm_cdev *ipc_port[IPC_MEM_MAX_CHANNELS]; struct iosm_cdev *ipc_port[IPC_MEM_MAX_CHANNELS];
struct iosm_pcie *pcie; struct iosm_pcie *pcie;
#ifdef CONFIG_WWAN_DEBUGFS
struct iosm_trace *trace; struct iosm_trace *trace;
#endif
struct device *dev; struct device *dev;
enum ipc_mem_device_ipc_state ipc_requested_state; enum ipc_mem_device_ipc_state ipc_requested_state;
struct ipc_mem_channel channels[IPC_MEM_MAX_CHANNELS]; struct ipc_mem_channel channels[IPC_MEM_MAX_CHANNELS];
...@@ -380,6 +383,9 @@ struct iosm_imem { ...@@ -380,6 +383,9 @@ struct iosm_imem {
ev_mux_net_transmit_pending:1, ev_mux_net_transmit_pending:1,
reset_det_n:1, reset_det_n:1,
pcie_wake_n:1; pcie_wake_n:1;
#ifdef CONFIG_WWAN_DEBUGFS
struct dentry *debugfs_dir;
#endif
}; };
/** /**
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include "iosm_ipc_imem_ops.h" #include "iosm_ipc_imem_ops.h"
#include "iosm_ipc_port.h" #include "iosm_ipc_port.h"
#include "iosm_ipc_task_queue.h" #include "iosm_ipc_task_queue.h"
#include "iosm_ipc_trace.h"
/* Open a packet data online channel between the network layer and CP. */ /* Open a packet data online channel between the network layer and CP. */
int ipc_imem_sys_wwan_open(struct iosm_imem *ipc_imem, int if_id) int ipc_imem_sys_wwan_open(struct iosm_imem *ipc_imem, int if_id)
...@@ -108,23 +107,6 @@ void ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem, ...@@ -108,23 +107,6 @@ void ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem,
"failed to register the ipc_wwan interfaces"); "failed to register the ipc_wwan interfaces");
} }
/**
* ipc_imem_trace_channel_init - Initializes trace channel.
* @ipc_imem: Pointer to iosm_imem struct.
*
* Returns: Pointer to trace instance on success else NULL
*/
struct iosm_trace *ipc_imem_trace_channel_init(struct iosm_imem *ipc_imem)
{
struct ipc_chnl_cfg chnl_cfg = { 0 };
ipc_chnl_cfg_get(&chnl_cfg, IPC_MEM_CTRL_CHL_ID_3);
ipc_imem_channel_init(ipc_imem, IPC_CTYPE_CTRL, chnl_cfg,
IRQ_MOD_OFF);
return ipc_trace_init(ipc_imem);
}
/* Map SKB to DMA for transfer */ /* Map SKB to DMA for transfer */
static int ipc_imem_map_skb_to_dma(struct iosm_imem *ipc_imem, static int ipc_imem_map_skb_to_dma(struct iosm_imem *ipc_imem,
struct sk_buff *skb) struct sk_buff *skb)
......
...@@ -141,5 +141,5 @@ int ipc_imem_sys_devlink_read(struct iosm_devlink *ipc_devlink, u8 *data, ...@@ -141,5 +141,5 @@ int ipc_imem_sys_devlink_read(struct iosm_devlink *ipc_devlink, u8 *data,
*/ */
int ipc_imem_sys_devlink_write(struct iosm_devlink *ipc_devlink, int ipc_imem_sys_devlink_write(struct iosm_devlink *ipc_devlink,
unsigned char *buf, int count); unsigned char *buf, int count);
struct iosm_trace *ipc_imem_trace_channel_init(struct iosm_imem *ipc_imem);
#endif #endif
...@@ -17,11 +17,13 @@ ...@@ -17,11 +17,13 @@
/** /**
* ipc_trace_port_rx - Receive trace packet from cp and write to relay buffer * ipc_trace_port_rx - Receive trace packet from cp and write to relay buffer
* @ipc_trace: Pointer to the ipc trace data-struct * @ipc_imem: Pointer to iosm_imem structure
* @skb: Pointer to struct sk_buff * @skb: Pointer to struct sk_buff
*/ */
void ipc_trace_port_rx(struct iosm_trace *ipc_trace, struct sk_buff *skb) void ipc_trace_port_rx(struct iosm_imem *ipc_imem, struct sk_buff *skb)
{ {
struct iosm_trace *ipc_trace = ipc_imem->trace;
if (ipc_trace->ipc_rchan) if (ipc_trace->ipc_rchan)
relay_write(ipc_trace->ipc_rchan, skb->data, skb->len); relay_write(ipc_trace->ipc_rchan, skb->data, skb->len);
...@@ -132,9 +134,14 @@ static const struct file_operations ipc_trace_fops = { ...@@ -132,9 +134,14 @@ static const struct file_operations ipc_trace_fops = {
*/ */
struct iosm_trace *ipc_trace_init(struct iosm_imem *ipc_imem) struct iosm_trace *ipc_trace_init(struct iosm_imem *ipc_imem)
{ {
struct iosm_trace *ipc_trace = kzalloc(sizeof(*ipc_trace), GFP_KERNEL); struct ipc_chnl_cfg chnl_cfg = { 0 };
struct dentry *debugfs_pdev; struct iosm_trace *ipc_trace;
ipc_chnl_cfg_get(&chnl_cfg, IPC_MEM_CTRL_CHL_ID_3);
ipc_imem_channel_init(ipc_imem, IPC_CTYPE_CTRL, chnl_cfg,
IRQ_MOD_OFF);
ipc_trace = kzalloc(sizeof(*ipc_trace), GFP_KERNEL);
if (!ipc_trace) if (!ipc_trace)
return NULL; return NULL;
...@@ -144,15 +151,14 @@ struct iosm_trace *ipc_trace_init(struct iosm_imem *ipc_imem) ...@@ -144,15 +151,14 @@ struct iosm_trace *ipc_trace_init(struct iosm_imem *ipc_imem)
ipc_trace->chl_id = IPC_MEM_CTRL_CHL_ID_3; ipc_trace->chl_id = IPC_MEM_CTRL_CHL_ID_3;
mutex_init(&ipc_trace->trc_mutex); mutex_init(&ipc_trace->trc_mutex);
debugfs_pdev = wwan_get_debugfs_dir(ipc_imem->dev);
ipc_trace->ctrl_file = debugfs_create_file(IOSM_TRC_DEBUGFS_TRACE_CTRL, ipc_trace->ctrl_file = debugfs_create_file(IOSM_TRC_DEBUGFS_TRACE_CTRL,
IOSM_TRC_FILE_PERM, IOSM_TRC_FILE_PERM,
debugfs_pdev, ipc_imem->debugfs_dir,
ipc_trace, &ipc_trace_fops); ipc_trace, &ipc_trace_fops);
ipc_trace->ipc_rchan = relay_open(IOSM_TRC_DEBUGFS_TRACE, ipc_trace->ipc_rchan = relay_open(IOSM_TRC_DEBUGFS_TRACE,
debugfs_pdev, ipc_imem->debugfs_dir,
IOSM_TRC_SUB_BUFF_SIZE, IOSM_TRC_SUB_BUFF_SIZE,
IOSM_TRC_N_SUB_BUFF, IOSM_TRC_N_SUB_BUFF,
&relay_callbacks, NULL); &relay_callbacks, NULL);
...@@ -166,6 +172,9 @@ struct iosm_trace *ipc_trace_init(struct iosm_imem *ipc_imem) ...@@ -166,6 +172,9 @@ struct iosm_trace *ipc_trace_init(struct iosm_imem *ipc_imem)
*/ */
void ipc_trace_deinit(struct iosm_trace *ipc_trace) void ipc_trace_deinit(struct iosm_trace *ipc_trace)
{ {
if (!ipc_trace)
return;
debugfs_remove(ipc_trace->ctrl_file); debugfs_remove(ipc_trace->ctrl_file);
relay_close(ipc_trace->ipc_rchan); relay_close(ipc_trace->ipc_rchan);
mutex_destroy(&ipc_trace->trc_mutex); mutex_destroy(&ipc_trace->trc_mutex);
......
...@@ -45,7 +45,30 @@ struct iosm_trace { ...@@ -45,7 +45,30 @@ struct iosm_trace {
enum trace_ctrl_mode mode; enum trace_ctrl_mode mode;
}; };
#ifdef CONFIG_WWAN_DEBUGFS
static inline bool ipc_is_trace_channel(struct iosm_imem *ipc_mem, u16 chl_id)
{
return ipc_mem->trace && ipc_mem->trace->chl_id == chl_id;
}
struct iosm_trace *ipc_trace_init(struct iosm_imem *ipc_imem); struct iosm_trace *ipc_trace_init(struct iosm_imem *ipc_imem);
void ipc_trace_deinit(struct iosm_trace *ipc_trace); void ipc_trace_deinit(struct iosm_trace *ipc_trace);
void ipc_trace_port_rx(struct iosm_trace *ipc_trace, struct sk_buff *skb); void ipc_trace_port_rx(struct iosm_imem *ipc_imem, struct sk_buff *skb);
#else
static inline bool ipc_is_trace_channel(struct iosm_imem *ipc_mem, u16 chl_id)
{
return false;
}
static inline void ipc_trace_port_rx(struct iosm_imem *ipc_imem,
struct sk_buff *skb)
{
dev_kfree_skb(skb);
}
#endif
#endif #endif
...@@ -50,7 +50,9 @@ struct wwan_device { ...@@ -50,7 +50,9 @@ struct wwan_device {
atomic_t port_id; atomic_t port_id;
const struct wwan_ops *ops; const struct wwan_ops *ops;
void *ops_ctxt; void *ops_ctxt;
#ifdef CONFIG_WWAN_DEBUGFS
struct dentry *debugfs_dir; struct dentry *debugfs_dir;
#endif
}; };
/** /**
...@@ -146,6 +148,7 @@ static struct wwan_device *wwan_dev_get_by_name(const char *name) ...@@ -146,6 +148,7 @@ static struct wwan_device *wwan_dev_get_by_name(const char *name)
return to_wwan_dev(dev); return to_wwan_dev(dev);
} }
#ifdef CONFIG_WWAN_DEBUGFS
struct dentry *wwan_get_debugfs_dir(struct device *parent) struct dentry *wwan_get_debugfs_dir(struct device *parent)
{ {
struct wwan_device *wwandev; struct wwan_device *wwandev;
...@@ -157,6 +160,7 @@ struct dentry *wwan_get_debugfs_dir(struct device *parent) ...@@ -157,6 +160,7 @@ struct dentry *wwan_get_debugfs_dir(struct device *parent)
return wwandev->debugfs_dir; return wwandev->debugfs_dir;
} }
EXPORT_SYMBOL_GPL(wwan_get_debugfs_dir); EXPORT_SYMBOL_GPL(wwan_get_debugfs_dir);
#endif
/* This function allocates and registers a new WWAN device OR if a WWAN device /* This function allocates and registers a new WWAN device OR if a WWAN device
* already exist for the given parent, it gets a reference and return it. * already exist for the given parent, it gets a reference and return it.
...@@ -166,7 +170,6 @@ EXPORT_SYMBOL_GPL(wwan_get_debugfs_dir); ...@@ -166,7 +170,6 @@ EXPORT_SYMBOL_GPL(wwan_get_debugfs_dir);
static struct wwan_device *wwan_create_dev(struct device *parent) static struct wwan_device *wwan_create_dev(struct device *parent)
{ {
struct wwan_device *wwandev; struct wwan_device *wwandev;
const char *wwandev_name;
int err, id; int err, id;
/* The 'find-alloc-register' operation must be protected against /* The 'find-alloc-register' operation must be protected against
...@@ -206,9 +209,11 @@ static struct wwan_device *wwan_create_dev(struct device *parent) ...@@ -206,9 +209,11 @@ static struct wwan_device *wwan_create_dev(struct device *parent)
goto done_unlock; goto done_unlock;
} }
wwandev_name = kobject_name(&wwandev->dev.kobj); #ifdef CONFIG_WWAN_DEBUGFS
wwandev->debugfs_dir = debugfs_create_dir(wwandev_name, wwandev->debugfs_dir =
wwan_debugfs_dir); debugfs_create_dir(kobject_name(&wwandev->dev.kobj),
wwan_debugfs_dir);
#endif
done_unlock: done_unlock:
mutex_unlock(&wwan_register_lock); mutex_unlock(&wwan_register_lock);
...@@ -240,7 +245,9 @@ static void wwan_remove_dev(struct wwan_device *wwandev) ...@@ -240,7 +245,9 @@ static void wwan_remove_dev(struct wwan_device *wwandev)
ret = device_for_each_child(&wwandev->dev, NULL, is_wwan_child); ret = device_for_each_child(&wwandev->dev, NULL, is_wwan_child);
if (!ret) { if (!ret) {
#ifdef CONFIG_WWAN_DEBUGFS
debugfs_remove_recursive(wwandev->debugfs_dir); debugfs_remove_recursive(wwandev->debugfs_dir);
#endif
device_unregister(&wwandev->dev); device_unregister(&wwandev->dev);
} else { } else {
put_device(&wwandev->dev); put_device(&wwandev->dev);
...@@ -1140,7 +1147,9 @@ static int __init wwan_init(void) ...@@ -1140,7 +1147,9 @@ static int __init wwan_init(void)
goto destroy; goto destroy;
} }
#ifdef CONFIG_WWAN_DEBUGFS
wwan_debugfs_dir = debugfs_create_dir("wwan", NULL); wwan_debugfs_dir = debugfs_create_dir("wwan", NULL);
#endif
return 0; return 0;
......
...@@ -171,6 +171,13 @@ int wwan_register_ops(struct device *parent, const struct wwan_ops *ops, ...@@ -171,6 +171,13 @@ int wwan_register_ops(struct device *parent, const struct wwan_ops *ops,
void wwan_unregister_ops(struct device *parent); void wwan_unregister_ops(struct device *parent);
#ifdef CONFIG_WWAN_DEBUGFS
struct dentry *wwan_get_debugfs_dir(struct device *parent); struct dentry *wwan_get_debugfs_dir(struct device *parent);
#else
static inline struct dentry *wwan_get_debugfs_dir(struct device *parent)
{
return ERR_PTR(-ENODEV);
}
#endif
#endif /* __WWAN_H */ #endif /* __WWAN_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment