Skip to content

Commit f3ddb8a

Browse files
shawn1221bjorn-helgaas
authored andcommitted
PCI: dw-rockchip: Add pcie_ltssm_state_transition tracepoint support
Rockchip platforms provide a 64x4 bytes debug FIFO to trace the LTSSM transition and data rate change history. These will be useful for debugging issues such as link failure, etc. Hence, expose these information over pcie_ltssm_state_transition tracepoint. Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com> [mani: commit log] Signed-off-by: Manivannan Sadhasivam <mani@kernel.org> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Tested-by: Anand Moon <linux.amoon@gmail.com> Reviewed-by: Steven Rostedt (Google) <rostedt@goodmis.org> Link: https://patch.msgid.link/1774403912-210670-4-git-send-email-shawn.lin@rock-chips.com
1 parent a3966a6 commit f3ddb8a

1 file changed

Lines changed: 111 additions & 0 deletions

File tree

drivers/pci/controller/dwc/pcie-dw-rockchip.c

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include <linux/platform_device.h>
2323
#include <linux/regmap.h>
2424
#include <linux/reset.h>
25+
#include <linux/workqueue.h>
26+
#include <trace/events/pci_controller.h>
2527

2628
#include "../../pci.h"
2729
#include "pcie-designware.h"
@@ -73,6 +75,20 @@
7375
#define PCIE_CLIENT_CDM_RASDES_TBA_L1_1 BIT(4)
7476
#define PCIE_CLIENT_CDM_RASDES_TBA_L1_2 BIT(5)
7577

78+
/* Debug FIFO information */
79+
#define PCIE_CLIENT_DBG_FIFO_MODE_CON 0x310
80+
#define PCIE_CLIENT_DBG_EN 0xffff0007
81+
#define PCIE_CLIENT_DBG_DIS 0xffff0000
82+
#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0 0x320
83+
#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1 0x324
84+
#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0 0x328
85+
#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1 0x32c
86+
#define PCIE_CLIENT_DBG_TRANSITION_DATA 0xffff0000
87+
#define PCIE_CLIENT_DBG_FIFO_STATUS 0x350
88+
#define PCIE_DBG_FIFO_RATE_MASK GENMASK(22, 20)
89+
#define PCIE_DBG_FIFO_L1SUB_MASK GENMASK(10, 8)
90+
#define PCIE_DBG_LTSSM_HISTORY_CNT 64
91+
7692
/* Hot Reset Control Register */
7793
#define PCIE_CLIENT_HOT_RESET_CTRL 0x180
7894
#define PCIE_LTSSM_APP_DLY2_EN BIT(1)
@@ -98,6 +114,7 @@ struct rockchip_pcie {
98114
struct irq_domain *irq_domain;
99115
const struct rockchip_pcie_of_data *data;
100116
bool supports_clkreq;
117+
struct delayed_work trace_work;
101118
};
102119

103120
struct rockchip_pcie_of_data {
@@ -208,6 +225,96 @@ static enum dw_pcie_ltssm rockchip_pcie_get_ltssm(struct dw_pcie *pci)
208225
return rockchip_pcie_get_ltssm_reg(rockchip) & PCIE_LTSSM_STATUS_MASK;
209226
}
210227

228+
#ifdef CONFIG_TRACING
229+
static void rockchip_pcie_ltssm_trace_work(struct work_struct *work)
230+
{
231+
struct rockchip_pcie *rockchip = container_of(work,
232+
struct rockchip_pcie,
233+
trace_work.work);
234+
struct dw_pcie *pci = &rockchip->pci;
235+
enum dw_pcie_ltssm state;
236+
u32 i, l1ss, prev_val = DW_PCIE_LTSSM_UNKNOWN, rate, val;
237+
238+
if (!trace_pcie_ltssm_state_transition_enabled())
239+
goto skip_trace;
240+
241+
for (i = 0; i < PCIE_DBG_LTSSM_HISTORY_CNT; i++) {
242+
val = rockchip_pcie_readl_apb(rockchip,
243+
PCIE_CLIENT_DBG_FIFO_STATUS);
244+
rate = FIELD_GET(PCIE_DBG_FIFO_RATE_MASK, val);
245+
l1ss = FIELD_GET(PCIE_DBG_FIFO_L1SUB_MASK, val);
246+
val = FIELD_GET(PCIE_LTSSM_STATUS_MASK, val);
247+
248+
/*
249+
* Hardware Mechanism: The ring FIFO employs two tracking
250+
* counters:
251+
* - 'last-read-point': maintains the user's last read position
252+
* - 'last-valid-point': tracks the HW's last state update
253+
*
254+
* Software Handling: When two consecutive LTSSM states are
255+
* identical, it indicates invalid subsequent data in the FIFO.
256+
* In this case, we skip the remaining entries. The dual counter
257+
* design ensures that on the next state transition, reading can
258+
* resume from the last user position.
259+
*/
260+
if ((i > 0 && val == prev_val) || val > DW_PCIE_LTSSM_RCVRY_EQ3)
261+
break;
262+
263+
state = prev_val = val;
264+
if (val == DW_PCIE_LTSSM_L1_IDLE) {
265+
if (l1ss == 2)
266+
state = DW_PCIE_LTSSM_L1_2;
267+
else if (l1ss == 1)
268+
state = DW_PCIE_LTSSM_L1_1;
269+
}
270+
271+
trace_pcie_ltssm_state_transition(dev_name(pci->dev),
272+
dw_pcie_ltssm_status_string(state),
273+
((rate + 1) > pci->max_link_speed) ?
274+
PCI_SPEED_UNKNOWN : PCIE_SPEED_2_5GT + rate);
275+
}
276+
277+
skip_trace:
278+
schedule_delayed_work(&rockchip->trace_work, msecs_to_jiffies(5000));
279+
}
280+
281+
static void rockchip_pcie_ltssm_trace(struct rockchip_pcie *rockchip,
282+
bool enable)
283+
{
284+
if (enable) {
285+
rockchip_pcie_writel_apb(rockchip,
286+
PCIE_CLIENT_DBG_TRANSITION_DATA,
287+
PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0);
288+
rockchip_pcie_writel_apb(rockchip,
289+
PCIE_CLIENT_DBG_TRANSITION_DATA,
290+
PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1);
291+
rockchip_pcie_writel_apb(rockchip,
292+
PCIE_CLIENT_DBG_TRANSITION_DATA,
293+
PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0);
294+
rockchip_pcie_writel_apb(rockchip,
295+
PCIE_CLIENT_DBG_TRANSITION_DATA,
296+
PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1);
297+
rockchip_pcie_writel_apb(rockchip,
298+
PCIE_CLIENT_DBG_EN,
299+
PCIE_CLIENT_DBG_FIFO_MODE_CON);
300+
301+
INIT_DELAYED_WORK(&rockchip->trace_work,
302+
rockchip_pcie_ltssm_trace_work);
303+
schedule_delayed_work(&rockchip->trace_work, 0);
304+
} else {
305+
rockchip_pcie_writel_apb(rockchip,
306+
PCIE_CLIENT_DBG_DIS,
307+
PCIE_CLIENT_DBG_FIFO_MODE_CON);
308+
cancel_delayed_work_sync(&rockchip->trace_work);
309+
}
310+
}
311+
#else
312+
static void rockchip_pcie_ltssm_trace(struct rockchip_pcie *rockchip,
313+
bool enable)
314+
{
315+
}
316+
#endif
317+
211318
static void rockchip_pcie_enable_ltssm(struct rockchip_pcie *rockchip)
212319
{
213320
rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_ENABLE_LTSSM,
@@ -291,6 +398,9 @@ static int rockchip_pcie_start_link(struct dw_pcie *pci)
291398
* 100us as we don't know how long should the device need to reset.
292399
*/
293400
msleep(PCIE_T_PVPERL_MS);
401+
402+
rockchip_pcie_ltssm_trace(rockchip, true);
403+
294404
gpiod_set_value_cansleep(rockchip->rst_gpio, 1);
295405

296406
return 0;
@@ -301,6 +411,7 @@ static void rockchip_pcie_stop_link(struct dw_pcie *pci)
301411
struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
302412

303413
rockchip_pcie_disable_ltssm(rockchip);
414+
rockchip_pcie_ltssm_trace(rockchip, false);
304415
}
305416

306417
static int rockchip_pcie_host_init(struct dw_pcie_rp *pp)

0 commit comments

Comments
 (0)