xref: /OK3568_Linux_fs/kernel/drivers/pci/pcie/ptm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * PCI Express Precision Time Measurement
4*4882a593Smuzhiyun  * Copyright (c) 2016, Intel Corporation.
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <linux/module.h>
8*4882a593Smuzhiyun #include <linux/init.h>
9*4882a593Smuzhiyun #include <linux/pci.h>
10*4882a593Smuzhiyun #include "../pci.h"
11*4882a593Smuzhiyun 
pci_ptm_info(struct pci_dev * dev)12*4882a593Smuzhiyun static void pci_ptm_info(struct pci_dev *dev)
13*4882a593Smuzhiyun {
14*4882a593Smuzhiyun 	char clock_desc[8];
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun 	switch (dev->ptm_granularity) {
17*4882a593Smuzhiyun 	case 0:
18*4882a593Smuzhiyun 		snprintf(clock_desc, sizeof(clock_desc), "unknown");
19*4882a593Smuzhiyun 		break;
20*4882a593Smuzhiyun 	case 255:
21*4882a593Smuzhiyun 		snprintf(clock_desc, sizeof(clock_desc), ">254ns");
22*4882a593Smuzhiyun 		break;
23*4882a593Smuzhiyun 	default:
24*4882a593Smuzhiyun 		snprintf(clock_desc, sizeof(clock_desc), "%uns",
25*4882a593Smuzhiyun 			 dev->ptm_granularity);
26*4882a593Smuzhiyun 		break;
27*4882a593Smuzhiyun 	}
28*4882a593Smuzhiyun 	pci_info(dev, "PTM enabled%s, %s granularity\n",
29*4882a593Smuzhiyun 		 dev->ptm_root ? " (root)" : "", clock_desc);
30*4882a593Smuzhiyun }
31*4882a593Smuzhiyun 
pci_ptm_init(struct pci_dev * dev)32*4882a593Smuzhiyun void pci_ptm_init(struct pci_dev *dev)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	int pos;
35*4882a593Smuzhiyun 	u32 cap, ctrl;
36*4882a593Smuzhiyun 	u8 local_clock;
37*4882a593Smuzhiyun 	struct pci_dev *ups;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	if (!pci_is_pcie(dev))
40*4882a593Smuzhiyun 		return;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	/*
43*4882a593Smuzhiyun 	 * Enable PTM only on interior devices (root ports, switch ports,
44*4882a593Smuzhiyun 	 * etc.) on the assumption that it causes no link traffic until an
45*4882a593Smuzhiyun 	 * endpoint enables it.
46*4882a593Smuzhiyun 	 */
47*4882a593Smuzhiyun 	if ((pci_pcie_type(dev) == PCI_EXP_TYPE_ENDPOINT ||
48*4882a593Smuzhiyun 	     pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END))
49*4882a593Smuzhiyun 		return;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	/*
52*4882a593Smuzhiyun 	 * Switch Downstream Ports are not permitted to have a PTM
53*4882a593Smuzhiyun 	 * capability; their PTM behavior is controlled by the Upstream
54*4882a593Smuzhiyun 	 * Port (PCIe r5.0, sec 7.9.16).
55*4882a593Smuzhiyun 	 */
56*4882a593Smuzhiyun 	ups = pci_upstream_bridge(dev);
57*4882a593Smuzhiyun 	if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM &&
58*4882a593Smuzhiyun 	    ups && ups->ptm_enabled) {
59*4882a593Smuzhiyun 		dev->ptm_granularity = ups->ptm_granularity;
60*4882a593Smuzhiyun 		dev->ptm_enabled = 1;
61*4882a593Smuzhiyun 		return;
62*4882a593Smuzhiyun 	}
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
65*4882a593Smuzhiyun 	if (!pos)
66*4882a593Smuzhiyun 		return;
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap);
69*4882a593Smuzhiyun 	local_clock = (cap & PCI_PTM_GRANULARITY_MASK) >> 8;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	/*
72*4882a593Smuzhiyun 	 * There's no point in enabling PTM unless it's enabled in the
73*4882a593Smuzhiyun 	 * upstream device or this device can be a PTM Root itself.  Per
74*4882a593Smuzhiyun 	 * the spec recommendation (PCIe r3.1, sec 7.32.3), select the
75*4882a593Smuzhiyun 	 * furthest upstream Time Source as the PTM Root.
76*4882a593Smuzhiyun 	 */
77*4882a593Smuzhiyun 	if (ups && ups->ptm_enabled) {
78*4882a593Smuzhiyun 		ctrl = PCI_PTM_CTRL_ENABLE;
79*4882a593Smuzhiyun 		if (ups->ptm_granularity == 0)
80*4882a593Smuzhiyun 			dev->ptm_granularity = 0;
81*4882a593Smuzhiyun 		else if (ups->ptm_granularity > local_clock)
82*4882a593Smuzhiyun 			dev->ptm_granularity = ups->ptm_granularity;
83*4882a593Smuzhiyun 	} else {
84*4882a593Smuzhiyun 		if (cap & PCI_PTM_CAP_ROOT) {
85*4882a593Smuzhiyun 			ctrl = PCI_PTM_CTRL_ENABLE | PCI_PTM_CTRL_ROOT;
86*4882a593Smuzhiyun 			dev->ptm_root = 1;
87*4882a593Smuzhiyun 			dev->ptm_granularity = local_clock;
88*4882a593Smuzhiyun 		} else
89*4882a593Smuzhiyun 			return;
90*4882a593Smuzhiyun 	}
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	ctrl |= dev->ptm_granularity << 8;
93*4882a593Smuzhiyun 	pci_write_config_dword(dev, pos + PCI_PTM_CTRL, ctrl);
94*4882a593Smuzhiyun 	dev->ptm_enabled = 1;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	pci_ptm_info(dev);
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun 
pci_enable_ptm(struct pci_dev * dev,u8 * granularity)99*4882a593Smuzhiyun int pci_enable_ptm(struct pci_dev *dev, u8 *granularity)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun 	int pos;
102*4882a593Smuzhiyun 	u32 cap, ctrl;
103*4882a593Smuzhiyun 	struct pci_dev *ups;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	if (!pci_is_pcie(dev))
106*4882a593Smuzhiyun 		return -EINVAL;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
109*4882a593Smuzhiyun 	if (!pos)
110*4882a593Smuzhiyun 		return -EINVAL;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap);
113*4882a593Smuzhiyun 	if (!(cap & PCI_PTM_CAP_REQ))
114*4882a593Smuzhiyun 		return -EINVAL;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	/*
117*4882a593Smuzhiyun 	 * For a PCIe Endpoint, PTM is only useful if the endpoint can
118*4882a593Smuzhiyun 	 * issue PTM requests to upstream devices that have PTM enabled.
119*4882a593Smuzhiyun 	 *
120*4882a593Smuzhiyun 	 * For Root Complex Integrated Endpoints, there is no upstream
121*4882a593Smuzhiyun 	 * device, so there must be some implementation-specific way to
122*4882a593Smuzhiyun 	 * associate the endpoint with a time source.
123*4882a593Smuzhiyun 	 */
124*4882a593Smuzhiyun 	if (pci_pcie_type(dev) == PCI_EXP_TYPE_ENDPOINT) {
125*4882a593Smuzhiyun 		ups = pci_upstream_bridge(dev);
126*4882a593Smuzhiyun 		if (!ups || !ups->ptm_enabled)
127*4882a593Smuzhiyun 			return -EINVAL;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 		dev->ptm_granularity = ups->ptm_granularity;
130*4882a593Smuzhiyun 	} else if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END) {
131*4882a593Smuzhiyun 		dev->ptm_granularity = 0;
132*4882a593Smuzhiyun 	} else
133*4882a593Smuzhiyun 		return -EINVAL;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	ctrl = PCI_PTM_CTRL_ENABLE;
136*4882a593Smuzhiyun 	ctrl |= dev->ptm_granularity << 8;
137*4882a593Smuzhiyun 	pci_write_config_dword(dev, pos + PCI_PTM_CTRL, ctrl);
138*4882a593Smuzhiyun 	dev->ptm_enabled = 1;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	pci_ptm_info(dev);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	if (granularity)
143*4882a593Smuzhiyun 		*granularity = dev->ptm_granularity;
144*4882a593Smuzhiyun 	return 0;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun EXPORT_SYMBOL(pci_enable_ptm);
147