Skip to content

Commit db847ad

Browse files
committed
Merge branch 'pci/ptm-debugfs'
- Add debugfs support for exposing DWC device-specific PTM context (Manivannan Sadhasivam) * pci/ptm-debugfs: PCI: qcom-ep: Mask PTM_UPDATING interrupt PCI: dwc: Add debugfs support for PTM context PCI: dwc: Pass DWC PCIe mode to dwc_pcie_debugfs_init() PCI: Add debugfs support for exposing PTM context
2 parents df52b63 + 5fbfae6 commit db847ad

File tree

10 files changed

+713
-5
lines changed

10 files changed

+713
-5
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
What: /sys/kernel/debug/pcie_ptm_*/local_clock
2+
Date: May 2025
3+
Contact: Manivannan Sadhasivam <[email protected]>
4+
Description:
5+
(RO) PTM local clock in nanoseconds. Applicable for both Root
6+
Complex and Endpoint controllers.
7+
8+
What: /sys/kernel/debug/pcie_ptm_*/master_clock
9+
Date: May 2025
10+
Contact: Manivannan Sadhasivam <[email protected]>
11+
Description:
12+
(RO) PTM master clock in nanoseconds. Applicable only for
13+
Endpoint controllers.
14+
15+
What: /sys/kernel/debug/pcie_ptm_*/t1
16+
Date: May 2025
17+
Contact: Manivannan Sadhasivam <[email protected]>
18+
Description:
19+
(RO) PTM T1 timestamp in nanoseconds. Applicable only for
20+
Endpoint controllers.
21+
22+
What: /sys/kernel/debug/pcie_ptm_*/t2
23+
Date: May 2025
24+
Contact: Manivannan Sadhasivam <[email protected]>
25+
Description:
26+
(RO) PTM T2 timestamp in nanoseconds. Applicable only for
27+
Root Complex controllers.
28+
29+
What: /sys/kernel/debug/pcie_ptm_*/t3
30+
Date: May 2025
31+
Contact: Manivannan Sadhasivam <[email protected]>
32+
Description:
33+
(RO) PTM T3 timestamp in nanoseconds. Applicable only for
34+
Root Complex controllers.
35+
36+
What: /sys/kernel/debug/pcie_ptm_*/t4
37+
Date: May 2025
38+
Contact: Manivannan Sadhasivam <[email protected]>
39+
Description:
40+
(RO) PTM T4 timestamp in nanoseconds. Applicable only for
41+
Endpoint controllers.
42+
43+
What: /sys/kernel/debug/pcie_ptm_*/context_update
44+
Date: May 2025
45+
Contact: Manivannan Sadhasivam <[email protected]>
46+
Description:
47+
(RW) Control the PTM context update mode. Applicable only for
48+
Endpoint controllers.
49+
50+
Following values are supported:
51+
52+
* auto = PTM context auto update trigger for every 10ms
53+
54+
* manual = PTM context manual update. Writing 'manual' to this
55+
file triggers PTM context update (default)
56+
57+
What: /sys/kernel/debug/pcie_ptm_*/context_valid
58+
Date: May 2025
59+
Contact: Manivannan Sadhasivam <[email protected]>
60+
Description:
61+
(RW) Control the PTM context validity (local clock timing).
62+
Applicable only for Root Complex controllers. PTM context is
63+
invalidated by hardware if the Root Complex enters low power
64+
mode or changes link frequency.
65+
66+
Following values are supported:
67+
68+
* 0 = PTM context invalid (default)
69+
70+
* 1 = PTM context valid

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18642,6 +18642,7 @@ Q: https://patchwork.kernel.org/project/linux-pci/list/
1864218642
B: https://bugzilla.kernel.org
1864318643
C: irc://irc.oftc.net/linux-pci
1864418644
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git
18645+
F: Documentation/ABI/testing/debugfs-pcie-ptm
1864518646
F: Documentation/devicetree/bindings/pci/
1864618647
F: drivers/pci/controller/
1864718648
F: drivers/pci/pci-bridge-emul.c

drivers/pci/controller/dwc/pcie-designware-debugfs.c

Lines changed: 251 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,16 +642,262 @@ static void dwc_pcie_ltssm_debugfs_init(struct dw_pcie *pci, struct dentry *dir)
642642
&dwc_pcie_ltssm_status_ops);
643643
}
644644

645+
static int dw_pcie_ptm_check_capability(void *drvdata)
646+
{
647+
struct dw_pcie *pci = drvdata;
648+
649+
pci->ptm_vsec_offset = dw_pcie_find_ptm_capability(pci);
650+
651+
return pci->ptm_vsec_offset;
652+
}
653+
654+
static int dw_pcie_ptm_context_update_write(void *drvdata, u8 mode)
655+
{
656+
struct dw_pcie *pci = drvdata;
657+
u32 val;
658+
659+
if (mode == PCIE_PTM_CONTEXT_UPDATE_AUTO) {
660+
val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL);
661+
val |= PTM_REQ_AUTO_UPDATE_ENABLED;
662+
dw_pcie_writel_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL, val);
663+
} else if (mode == PCIE_PTM_CONTEXT_UPDATE_MANUAL) {
664+
val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL);
665+
val &= ~PTM_REQ_AUTO_UPDATE_ENABLED;
666+
val |= PTM_REQ_START_UPDATE;
667+
dw_pcie_writel_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL, val);
668+
} else {
669+
return -EINVAL;
670+
}
671+
672+
return 0;
673+
}
674+
675+
static int dw_pcie_ptm_context_update_read(void *drvdata, u8 *mode)
676+
{
677+
struct dw_pcie *pci = drvdata;
678+
u32 val;
679+
680+
val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL);
681+
if (FIELD_GET(PTM_REQ_AUTO_UPDATE_ENABLED, val))
682+
*mode = PCIE_PTM_CONTEXT_UPDATE_AUTO;
683+
else
684+
/*
685+
* PTM_REQ_START_UPDATE is a self clearing register bit. So if
686+
* PTM_REQ_AUTO_UPDATE_ENABLED is not set, then it implies that
687+
* manual update is used.
688+
*/
689+
*mode = PCIE_PTM_CONTEXT_UPDATE_MANUAL;
690+
691+
return 0;
692+
}
693+
694+
static int dw_pcie_ptm_context_valid_write(void *drvdata, bool valid)
695+
{
696+
struct dw_pcie *pci = drvdata;
697+
u32 val;
698+
699+
if (valid) {
700+
val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL);
701+
val |= PTM_RES_CCONTEXT_VALID;
702+
dw_pcie_writel_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL, val);
703+
} else {
704+
val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL);
705+
val &= ~PTM_RES_CCONTEXT_VALID;
706+
dw_pcie_writel_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL, val);
707+
}
708+
709+
return 0;
710+
}
711+
712+
static int dw_pcie_ptm_context_valid_read(void *drvdata, bool *valid)
713+
{
714+
struct dw_pcie *pci = drvdata;
715+
u32 val;
716+
717+
val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL);
718+
*valid = !!FIELD_GET(PTM_RES_CCONTEXT_VALID, val);
719+
720+
return 0;
721+
}
722+
723+
static int dw_pcie_ptm_local_clock_read(void *drvdata, u64 *clock)
724+
{
725+
struct dw_pcie *pci = drvdata;
726+
u32 msb, lsb;
727+
728+
do {
729+
msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_LOCAL_MSB);
730+
lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_LOCAL_LSB);
731+
} while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_LOCAL_MSB));
732+
733+
*clock = ((u64) msb) << 32 | lsb;
734+
735+
return 0;
736+
}
737+
738+
static int dw_pcie_ptm_master_clock_read(void *drvdata, u64 *clock)
739+
{
740+
struct dw_pcie *pci = drvdata;
741+
u32 msb, lsb;
742+
743+
do {
744+
msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_MASTER_MSB);
745+
lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_MASTER_LSB);
746+
} while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_MASTER_MSB));
747+
748+
*clock = ((u64) msb) << 32 | lsb;
749+
750+
return 0;
751+
}
752+
753+
static int dw_pcie_ptm_t1_read(void *drvdata, u64 *clock)
754+
{
755+
struct dw_pcie *pci = drvdata;
756+
u32 msb, lsb;
757+
758+
do {
759+
msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_MSB);
760+
lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_LSB);
761+
} while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_MSB));
762+
763+
*clock = ((u64) msb) << 32 | lsb;
764+
765+
return 0;
766+
}
767+
768+
static int dw_pcie_ptm_t2_read(void *drvdata, u64 *clock)
769+
{
770+
struct dw_pcie *pci = drvdata;
771+
u32 msb, lsb;
772+
773+
do {
774+
msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_MSB);
775+
lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_LSB);
776+
} while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_MSB));
777+
778+
*clock = ((u64) msb) << 32 | lsb;
779+
780+
return 0;
781+
}
782+
783+
static int dw_pcie_ptm_t3_read(void *drvdata, u64 *clock)
784+
{
785+
struct dw_pcie *pci = drvdata;
786+
u32 msb, lsb;
787+
788+
do {
789+
msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_MSB);
790+
lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_LSB);
791+
} while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_MSB));
792+
793+
*clock = ((u64) msb) << 32 | lsb;
794+
795+
return 0;
796+
}
797+
798+
static int dw_pcie_ptm_t4_read(void *drvdata, u64 *clock)
799+
{
800+
struct dw_pcie *pci = drvdata;
801+
u32 msb, lsb;
802+
803+
do {
804+
msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_MSB);
805+
lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_LSB);
806+
} while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_MSB));
807+
808+
*clock = ((u64) msb) << 32 | lsb;
809+
810+
return 0;
811+
}
812+
813+
static bool dw_pcie_ptm_context_update_visible(void *drvdata)
814+
{
815+
struct dw_pcie *pci = drvdata;
816+
817+
return (pci->mode == DW_PCIE_EP_TYPE) ? true : false;
818+
}
819+
820+
static bool dw_pcie_ptm_context_valid_visible(void *drvdata)
821+
{
822+
struct dw_pcie *pci = drvdata;
823+
824+
return (pci->mode == DW_PCIE_RC_TYPE) ? true : false;
825+
}
826+
827+
static bool dw_pcie_ptm_local_clock_visible(void *drvdata)
828+
{
829+
/* PTM local clock is always visible */
830+
return true;
831+
}
832+
833+
static bool dw_pcie_ptm_master_clock_visible(void *drvdata)
834+
{
835+
struct dw_pcie *pci = drvdata;
836+
837+
return (pci->mode == DW_PCIE_EP_TYPE) ? true : false;
838+
}
839+
840+
static bool dw_pcie_ptm_t1_visible(void *drvdata)
841+
{
842+
struct dw_pcie *pci = drvdata;
843+
844+
return (pci->mode == DW_PCIE_EP_TYPE) ? true : false;
845+
}
846+
847+
static bool dw_pcie_ptm_t2_visible(void *drvdata)
848+
{
849+
struct dw_pcie *pci = drvdata;
850+
851+
return (pci->mode == DW_PCIE_RC_TYPE) ? true : false;
852+
}
853+
854+
static bool dw_pcie_ptm_t3_visible(void *drvdata)
855+
{
856+
struct dw_pcie *pci = drvdata;
857+
858+
return (pci->mode == DW_PCIE_RC_TYPE) ? true : false;
859+
}
860+
861+
static bool dw_pcie_ptm_t4_visible(void *drvdata)
862+
{
863+
struct dw_pcie *pci = drvdata;
864+
865+
return (pci->mode == DW_PCIE_EP_TYPE) ? true : false;
866+
}
867+
868+
const struct pcie_ptm_ops dw_pcie_ptm_ops = {
869+
.check_capability = dw_pcie_ptm_check_capability,
870+
.context_update_write = dw_pcie_ptm_context_update_write,
871+
.context_update_read = dw_pcie_ptm_context_update_read,
872+
.context_valid_write = dw_pcie_ptm_context_valid_write,
873+
.context_valid_read = dw_pcie_ptm_context_valid_read,
874+
.local_clock_read = dw_pcie_ptm_local_clock_read,
875+
.master_clock_read = dw_pcie_ptm_master_clock_read,
876+
.t1_read = dw_pcie_ptm_t1_read,
877+
.t2_read = dw_pcie_ptm_t2_read,
878+
.t3_read = dw_pcie_ptm_t3_read,
879+
.t4_read = dw_pcie_ptm_t4_read,
880+
.context_update_visible = dw_pcie_ptm_context_update_visible,
881+
.context_valid_visible = dw_pcie_ptm_context_valid_visible,
882+
.local_clock_visible = dw_pcie_ptm_local_clock_visible,
883+
.master_clock_visible = dw_pcie_ptm_master_clock_visible,
884+
.t1_visible = dw_pcie_ptm_t1_visible,
885+
.t2_visible = dw_pcie_ptm_t2_visible,
886+
.t3_visible = dw_pcie_ptm_t3_visible,
887+
.t4_visible = dw_pcie_ptm_t4_visible,
888+
};
889+
645890
void dwc_pcie_debugfs_deinit(struct dw_pcie *pci)
646891
{
647892
if (!pci->debugfs)
648893
return;
649894

895+
pcie_ptm_destroy_debugfs(pci->ptm_debugfs);
650896
dwc_pcie_rasdes_debugfs_deinit(pci);
651897
debugfs_remove_recursive(pci->debugfs->debug_dir);
652898
}
653899

654-
void dwc_pcie_debugfs_init(struct dw_pcie *pci)
900+
void dwc_pcie_debugfs_init(struct dw_pcie *pci, enum dw_pcie_device_mode mode)
655901
{
656902
char dirname[DWC_DEBUGFS_BUF_MAX];
657903
struct device *dev = pci->dev;
@@ -674,4 +920,8 @@ void dwc_pcie_debugfs_init(struct dw_pcie *pci)
674920
err);
675921

676922
dwc_pcie_ltssm_debugfs_init(pci, dir);
923+
924+
pci->mode = mode;
925+
pci->ptm_debugfs = pcie_ptm_create_debugfs(pci->dev, pci,
926+
&dw_pcie_ptm_ops);
677927
}

drivers/pci/controller/dwc/pcie-designware-ep.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1013,7 +1013,7 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep)
10131013

10141014
dw_pcie_ep_init_non_sticky_registers(pci);
10151015

1016-
dwc_pcie_debugfs_init(pci);
1016+
dwc_pcie_debugfs_init(pci, DW_PCIE_EP_TYPE);
10171017

10181018
return 0;
10191019

drivers/pci/controller/dwc/pcie-designware-host.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
574574
if (pp->ops->post_init)
575575
pp->ops->post_init(pp);
576576

577-
dwc_pcie_debugfs_init(pci);
577+
dwc_pcie_debugfs_init(pci, DW_PCIE_RC_TYPE);
578578

579579
return 0;
580580

drivers/pci/controller/dwc/pcie-designware.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ static const char * const dw_pcie_core_rsts[DW_PCIE_NUM_CORE_RSTS] = {
5454
[DW_PCIE_PWR_RST] = "pwr",
5555
};
5656

57+
static const struct dwc_pcie_vsec_id dwc_pcie_ptm_vsec_ids[] = {
58+
{ .vendor_id = PCI_VENDOR_ID_QCOM, /* EP */
59+
.vsec_id = 0x03, .vsec_rev = 0x1 },
60+
{ .vendor_id = PCI_VENDOR_ID_QCOM, /* RC */
61+
.vsec_id = 0x04, .vsec_rev = 0x1 },
62+
{ }
63+
};
64+
5765
static int dw_pcie_get_clocks(struct dw_pcie *pci)
5866
{
5967
int i, ret;
@@ -330,6 +338,12 @@ u16 dw_pcie_find_rasdes_capability(struct dw_pcie *pci)
330338
}
331339
EXPORT_SYMBOL_GPL(dw_pcie_find_rasdes_capability);
332340

341+
u16 dw_pcie_find_ptm_capability(struct dw_pcie *pci)
342+
{
343+
return dw_pcie_find_vsec_capability(pci, dwc_pcie_ptm_vsec_ids);
344+
}
345+
EXPORT_SYMBOL_GPL(dw_pcie_find_ptm_capability);
346+
333347
int dw_pcie_read(void __iomem *addr, int size, u32 *val)
334348
{
335349
if (!IS_ALIGNED((uintptr_t)addr, size)) {

0 commit comments

Comments
 (0)