[PATCH 1/2] PCI: dwc: Add LTSSM tracing support to debugfs
Shawn Lin
shawn.lin at rock-chips.com
Tue Jan 6 01:18:38 PST 2026
Some platforms may provide LTSSM trace functionality, recording historical
LTSSM state transition information. This is very useful for debugging, such
as when certain devices cannot be recognized. Add an ltssm_trace operation
node in debugfs for platform which could provide these information to show
the LTSSM history.
Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
---
.../controller/dwc/pcie-designware-debugfs.c | 44 +++++++++++++++++++
drivers/pci/controller/dwc/pcie-designware.h | 6 +++
2 files changed, 50 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-designware-debugfs.c b/drivers/pci/controller/dwc/pcie-designware-debugfs.c
index df98fee69892..569e8e078ef2 100644
--- a/drivers/pci/controller/dwc/pcie-designware-debugfs.c
+++ b/drivers/pci/controller/dwc/pcie-designware-debugfs.c
@@ -511,6 +511,38 @@ static int ltssm_status_open(struct inode *inode, struct file *file)
return single_open(file, ltssm_status_show, inode->i_private);
}
+static struct dw_pcie_ltssm_history *dw_pcie_ltssm_trace(struct dw_pcie *pci)
+{
+ if (pci->ops && pci->ops->ltssm_trace)
+ return pci->ops->ltssm_trace(pci);
+
+ return NULL;
+}
+
+static int ltssm_trace_show(struct seq_file *s, void *v)
+{
+ struct dw_pcie *pci = s->private;
+ struct dw_pcie_ltssm_history *history;
+ enum dw_pcie_ltssm val;
+ u32 loop;
+
+ history = dw_pcie_ltssm_trace(pci);
+ if (!history)
+ return 0;
+
+ for (loop = 0; loop < history->count; loop++) {
+ val = history->states[loop];
+ seq_printf(s, "%s (0x%02x)\n", ltssm_status_string(val), val);
+ }
+
+ return 0;
+}
+
+static int ltssm_trace_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ltssm_trace_show, inode->i_private);
+}
+
#define dwc_debugfs_create(name) \
debugfs_create_file(#name, 0644, rasdes_debug, pci, \
&dbg_ ## name ## _fops)
@@ -552,6 +584,11 @@ static const struct file_operations dwc_pcie_ltssm_status_ops = {
.read = seq_read,
};
+static const struct file_operations dwc_pcie_ltssm_trace_ops = {
+ .open = ltssm_trace_open,
+ .read = seq_read,
+};
+
static void dwc_pcie_rasdes_debugfs_deinit(struct dw_pcie *pci)
{
struct dwc_pcie_rasdes_info *rinfo = pci->debugfs->rasdes_info;
@@ -644,6 +681,12 @@ static void dwc_pcie_ltssm_debugfs_init(struct dw_pcie *pci, struct dentry *dir)
&dwc_pcie_ltssm_status_ops);
}
+static void dwc_pcie_ltssm_trace_debugfs_init(struct dw_pcie *pci, struct dentry *dir)
+{
+ debugfs_create_file("ltssm_trace", 0444, dir, pci,
+ &dwc_pcie_ltssm_trace_ops);
+}
+
static int dw_pcie_ptm_check_capability(void *drvdata)
{
struct dw_pcie *pci = drvdata;
@@ -922,6 +965,7 @@ void dwc_pcie_debugfs_init(struct dw_pcie *pci, enum dw_pcie_device_mode mode)
err);
dwc_pcie_ltssm_debugfs_init(pci, dir);
+ dwc_pcie_ltssm_trace_debugfs_init(pci, dir);
pci->mode = mode;
pci->ptm_debugfs = pcie_ptm_create_debugfs(pci->dev, pci,
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 5cd27f5739f1..0df18995b7fe 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -395,6 +395,11 @@ enum dw_pcie_ltssm {
DW_PCIE_LTSSM_UNKNOWN = 0xFFFFFFFF,
};
+struct dw_pcie_ltssm_history {
+ enum dw_pcie_ltssm *states;
+ u32 count;
+};
+
struct dw_pcie_ob_atu_cfg {
int index;
int type;
@@ -499,6 +504,7 @@ struct dw_pcie_ops {
size_t size, u32 val);
bool (*link_up)(struct dw_pcie *pcie);
enum dw_pcie_ltssm (*get_ltssm)(struct dw_pcie *pcie);
+ struct dw_pcie_ltssm_history * (*ltssm_trace)(struct dw_pcie *pcie);
int (*start_link)(struct dw_pcie *pcie);
void (*stop_link)(struct dw_pcie *pcie);
int (*assert_perst)(struct dw_pcie *pcie, bool assert);
--
2.43.0
More information about the Linux-rockchip
mailing list