@@ -99,25 +99,19 @@ static struct pci_dev *pci_upstream_ptm(struct pci_dev *dev)
99
99
return NULL ;
100
100
}
101
101
102
+ /*
103
+ * Find the PTM Capability (if present) and extract the information we need
104
+ * to use it.
105
+ */
102
106
void pci_ptm_init (struct pci_dev * dev )
103
107
{
104
108
u16 ptm ;
105
- u32 cap , ctrl ;
106
- u8 local_clock ;
109
+ u32 cap ;
107
110
struct pci_dev * ups ;
108
111
109
112
if (!pci_is_pcie (dev ))
110
113
return ;
111
114
112
- /*
113
- * Enable PTM only on interior devices (root ports, switch ports,
114
- * etc.) on the assumption that it causes no link traffic until an
115
- * endpoint enables it.
116
- */
117
- if ((pci_pcie_type (dev ) == PCI_EXP_TYPE_ENDPOINT ||
118
- pci_pcie_type (dev ) == PCI_EXP_TYPE_RC_END ))
119
- return ;
120
-
121
115
ptm = pci_find_ext_capability (dev , PCI_EXT_CAP_ID_PTM );
122
116
if (!ptm )
123
117
return ;
@@ -126,76 +120,76 @@ void pci_ptm_init(struct pci_dev *dev)
126
120
pci_add_ext_cap_save_buffer (dev , PCI_EXT_CAP_ID_PTM , sizeof (u16 ));
127
121
128
122
pci_read_config_dword (dev , ptm + PCI_PTM_CAP , & cap );
129
- local_clock = (cap & PCI_PTM_GRANULARITY_MASK ) >> 8 ;
123
+ dev -> ptm_granularity = (cap & PCI_PTM_GRANULARITY_MASK ) >> 8 ;
130
124
131
125
/*
132
- * There's no point in enabling PTM unless it's enabled in the
133
- * upstream device or this device can be a PTM Root itself . Per
134
- * the spec recommendation (PCIe r3.1, sec 7.32.3), select the
135
- * furthest upstream Time Source as the PTM Root.
126
+ * Per the spec recommendation (PCIe r6.0, sec 7.9.15.3), select the
127
+ * furthest upstream Time Source as the PTM Root. For Endpoints,
128
+ * " the Effective Granularity is the maximum Local Clock Granularity
129
+ * reported by the PTM Root and all intervening PTM Time Sources."
136
130
*/
137
131
ups = pci_upstream_ptm (dev );
138
- if (ups && ups -> ptm_enabled ) {
139
- ctrl = PCI_PTM_CTRL_ENABLE ;
132
+ if (ups ) {
140
133
if (ups -> ptm_granularity == 0 )
141
134
dev -> ptm_granularity = 0 ;
142
- else if (ups -> ptm_granularity > local_clock )
135
+ else if (ups -> ptm_granularity > dev -> ptm_granularity )
143
136
dev -> ptm_granularity = ups -> ptm_granularity ;
144
- } else {
145
- if (cap & PCI_PTM_CAP_ROOT ) {
146
- ctrl = PCI_PTM_CTRL_ENABLE | PCI_PTM_CTRL_ROOT ;
147
- dev -> ptm_root = 1 ;
148
- dev -> ptm_granularity = local_clock ;
149
- } else
150
- return ;
151
- }
137
+ } else if (cap & PCI_PTM_CAP_ROOT ) {
138
+ dev -> ptm_root = 1 ;
139
+ } else if (pci_pcie_type (dev ) == PCI_EXP_TYPE_RC_END ) {
152
140
153
- ctrl |= dev -> ptm_granularity << 8 ;
154
- pci_write_config_dword (dev , ptm + PCI_PTM_CTRL , ctrl );
155
- dev -> ptm_enabled = 1 ;
141
+ /*
142
+ * Per sec 7.9.15.3, this should be the Local Clock
143
+ * Granularity of the associated Time Source. But it
144
+ * doesn't say how to find that Time Source.
145
+ */
146
+ dev -> ptm_granularity = 0 ;
147
+ }
156
148
157
- pci_ptm_info (dev );
149
+ if (pci_pcie_type (dev ) == PCI_EXP_TYPE_ROOT_PORT ||
150
+ pci_pcie_type (dev ) == PCI_EXP_TYPE_UPSTREAM )
151
+ pci_enable_ptm (dev , NULL );
158
152
}
159
153
154
+ /**
155
+ * pci_enable_ptm() - Enable Precision Time Measurement
156
+ * @dev: PCI device
157
+ * @granularity: pointer to return granularity
158
+ *
159
+ * Enable Precision Time Measurement for @dev. If successful and
160
+ * @granularity is non-NULL, return the Effective Granularity.
161
+ *
162
+ * Return: zero if successful, or -EINVAL if @dev lacks a PTM Capability or
163
+ * is not a PTM Root and lacks an upstream path of PTM-enabled devices.
164
+ */
160
165
int pci_enable_ptm (struct pci_dev * dev , u8 * granularity )
161
166
{
162
- u16 ptm ;
163
- u32 cap , ctrl ;
167
+ u16 ptm = dev -> ptm_cap ;
164
168
struct pci_dev * ups ;
169
+ u32 ctrl ;
165
170
166
- if (!pci_is_pcie (dev ))
167
- return - EINVAL ;
168
-
169
- ptm = pci_find_ext_capability (dev , PCI_EXT_CAP_ID_PTM );
170
171
if (!ptm )
171
172
return - EINVAL ;
172
173
173
- dev -> ptm_cap = ptm ;
174
- pci_read_config_dword (dev , ptm + PCI_PTM_CAP , & cap );
175
- if (!(cap & PCI_PTM_CAP_REQ ))
176
- return - EINVAL ;
177
-
178
174
/*
179
- * For a PCIe Endpoint, PTM is only useful if the endpoint can
180
- * issue PTM requests to upstream devices that have PTM enabled.
181
- *
182
- * For Root Complex Integrated Endpoints, there is no upstream
183
- * device, so there must be some implementation-specific way to
184
- * associate the endpoint with a time source .
175
+ * A device uses local PTM Messages to request time information
176
+ * from a PTM Root that's farther upstream. Every device along the
177
+ * path must support PTM and have it enabled so it can handle the
178
+ * messages. Therefore, if this device is not a PTM Root, the
179
+ * upstream link partner must have PTM enabled before we can enable
180
+ * PTM .
185
181
*/
186
- if (pci_pcie_type ( dev ) == PCI_EXP_TYPE_ENDPOINT ) {
182
+ if (! dev -> ptm_root ) {
187
183
ups = pci_upstream_ptm (dev );
188
184
if (!ups || !ups -> ptm_enabled )
189
185
return - EINVAL ;
190
-
191
- dev -> ptm_granularity = ups -> ptm_granularity ;
192
- } else if (pci_pcie_type (dev ) == PCI_EXP_TYPE_RC_END ) {
193
- dev -> ptm_granularity = 0 ;
194
- } else
195
- return - EINVAL ;
186
+ }
196
187
197
188
ctrl = PCI_PTM_CTRL_ENABLE ;
198
189
ctrl |= dev -> ptm_granularity << 8 ;
190
+ if (dev -> ptm_root )
191
+ ctrl |= PCI_PTM_CTRL_ROOT ;
192
+
199
193
pci_write_config_dword (dev , ptm + PCI_PTM_CTRL , ctrl );
200
194
dev -> ptm_enabled = 1 ;
201
195
0 commit comments