On Fri, Jan 09, 2026 at 02:22:10PM +0800, Shawn Lin wrote:
> 在 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 <[email protected]>
> > > ---
> > > 
> > > 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.
> 

Ok. Thanks for clarification. It'd be worth to add it to the existing comment.

> > > +         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.
> 

Ah ok. It was not clear that L1_IDLE is L1.0

- Mani

-- 
மணிவண்ணன் சதாசிவம்

Reply via email to