[PATCH v2 3/3] PCI: dw-rockchip: Add pcie_ltssm_state_transition trace support

Shawn Lin shawn.lin at rock-chips.com
Thu Jan 8 22:22:10 PST 2026


在 2026/01/09 星期五 13:55, Manivannan Sadhasivam 写道:
> On Fri, Jan 09, 2026 at 11:29:49AM +0800, Shawn Lin wrote:
>> Rockchip platforms provide a 64x4 bytes debug FIFO to trace the
>> LTSSM history. Any LTSSM change will be recorded. It's userful
>> for debug purpose, for example link failure, etc.
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>> ---
>>
>> Changes in v2:
>> - use tracepoint
>>
>>   drivers/pci/controller/dwc/pcie-dw-rockchip.c | 92 +++++++++++++++++++++++++++
>>   1 file changed, 92 insertions(+)
>>
>> diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
>> index 352f513..be9639aa 100644
>> --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
>> +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
>> @@ -22,6 +22,8 @@
>>   #include <linux/platform_device.h>
>>   #include <linux/regmap.h>
>>   #include <linux/reset.h>
>> +#include <linux/workqueue.h>
>> +#include <trace/events/pci_controller.h>
>>   
>>   #include "../../pci.h"
>>   #include "pcie-designware.h"
>> @@ -73,6 +75,18 @@
>>   #define  PCIE_CLIENT_CDM_RASDES_TBA_L1_1	BIT(4)
>>   #define  PCIE_CLIENT_CDM_RASDES_TBA_L1_2	BIT(5)
>>   
>> +/* Debug FIFO information */
>> +#define PCIE_CLIENT_DBG_FIFO_MODE_CON	0x310
>> +#define  PCIE_CLIENT_DBG_EN		0xffff0007
>> +#define  PCIE_CLIENT_DBG_DIS		0xffff0000
>> +#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0	0x320
>> +#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1	0x324
>> +#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0	0x328
>> +#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1	0x32c
>> +#define  PCIE_CLIENT_DBG_TRANSITION_DATA 0xffff0000
>> +#define PCIE_CLIENT_DBG_FIFO_STATUS	0x350
>> +#define PCIE_DBG_LTSSM_HISTORY_CNT	64
>> +
>>   /* Hot Reset Control Register */
>>   #define PCIE_CLIENT_HOT_RESET_CTRL	0x180
>>   #define  PCIE_LTSSM_APP_DLY2_EN		BIT(1)
>> @@ -96,6 +110,7 @@ struct rockchip_pcie {
>>   	struct irq_domain *irq_domain;
>>   	const struct rockchip_pcie_of_data *data;
>>   	bool supports_clkreq;
>> +	struct delayed_work trace_work;
>>   };
>>   
>>   struct rockchip_pcie_of_data {
>> @@ -206,6 +221,79 @@ static enum dw_pcie_ltssm rockchip_pcie_get_ltssm(struct dw_pcie *pci)
>>   	return rockchip_pcie_get_ltssm_reg(rockchip) & PCIE_LTSSM_STATUS_MASK;
>>   }
>>   
>> +#ifdef CONFIG_TRACING
>> +static void rockchip_pcie_ltssm_trace_work(struct work_struct *work)
>> +{
>> +	struct rockchip_pcie *rockchip = container_of(work, struct rockchip_pcie,
>> +						trace_work.work);
>> +	struct dw_pcie *pci = &rockchip->pci;
>> +	enum dw_pcie_ltssm state;
>> +	u32 val, rate, l1ss, loop, prev_val = DW_PCIE_LTSSM_UNKNOWN;
> 
> Reverse Xmas order please.
> 
>> +
>> +	for (loop = 0; loop < PCIE_DBG_LTSSM_HISTORY_CNT; loop++) {
> 
> s/loop/i?
> 
>> +		val = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_DBG_FIFO_STATUS);
>> +		rate = (val & GENMASK(22, 20)) >> 20;
>> +		l1ss = (val & GENMASK(10, 8)) >> 8;
>> +		val &= PCIE_LTSSM_STATUS_MASK;
> 
> Can you use FIELD_ macros here?
> 
>> +
>> +		/* Two consecutive identical LTSSM means invalid subsequent data */
> 
> Interesting. Does the hardware maintain a counter to track the reads? So once
> you break out of the loop and read it after 5s, you'll start from where you left
> i.e., the duplicate entry or from the start of the counter again?
> 

Yes, the ring FIFO maintains counters for recording both of 
last-read-point for user to continue to read, and last-valid-point for 
HW to
continue to update transition state. So we could start from where we
left.

>> +		if ((loop > 0 && val == prev_val) || val > DW_PCIE_LTSSM_RCVRY_EQ3)
>> +			break;
>> +
>> +		state = prev_val = val;
>> +		if (val == DW_PCIE_LTSSM_L1_IDLE) {
>> +			if (l1ss == 2)
>> +				state = DW_PCIE_LTSSM_L1_2;
>> +			else if (l1ss == 1)
>> +				state = DW_PCIE_LTSSM_L1_1;
> 
> I believe L1.0 is not supported.
> 

I'm not sure I follow this comment. state is DW_PCIE_LTSSM_L1_IDLE
(L1.0) if l1ss is neither 1 nor 2.

>> +		}
>> +
>> +		trace_pcie_ltssm_state_transition(dev_name(pci->dev),
>> +					dw_pcie_ltssm_status_string(state),
>> +					((rate + 1) > pci->max_link_speed) ?
>> +					PCI_SPEED_UNKNOWN : PCIE_SPEED_2_5GT + rate);
>> +	}
>> +
>> +	schedule_delayed_work(&rockchip->trace_work, msecs_to_jiffies(5000));
>> +}
>> +
>> +static void rockchip_pcie_ltssm_trace(struct rockchip_pcie *rockchip,
>> +				      bool en)
> 
> s/en/enable
> 
> - Mani
> 




More information about the Linux-rockchip mailing list