d785ed945d
WWAN device is programmed to boot in normal mode or fastboot mode, when triggering a device reset through ACPI call or fastboot switch command. Maintain state machine synchronization and reprobe logic after a device reset. The PCIe device reset triggered by several ways. E.g.: - fastboot: echo "fastboot_switching" > /sys/bus/pci/devices/${bdf}/t7xx_mode. - reset: echo "reset" > /sys/bus/pci/devices/${bdf}/t7xx_mode. - IRQ: PCIe device request driver to reset itself by an interrupt request. Use pci_reset_function() as a generic way to reset device, save and restore the PCIe configuration before and after reset device to ensure the reprobe process. Suggestion from Bjorn: Link: https://lore.kernel.org/all/20230127133034.GA1364550@bhelgaas/ Signed-off-by: Jinjian Song <jinjian.song@fibocom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
118 lines
2.9 KiB
C
118 lines
2.9 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (C) 2022 Intel Corporation.
|
|
*/
|
|
|
|
#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
|
|
|
|
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,
|
|
};
|