aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/Kconfig9
-rw-r--r--drivers/pci/ats.c167
-rw-r--r--include/linux/pci-ats.h42
-rw-r--r--include/linux/pci_regs.h12
4 files changed, 230 insertions, 0 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 1d8ce8395861..fb1e9707f91e 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -85,6 +85,15 @@ config PCI_IOV
85 85
86 If unsure, say N. 86 If unsure, say N.
87 87
88config PCI_PRI
89 bool "PCI PRI support"
90 select PCI_ATS
91 help
92 PRI is the PCI Page Request Interface. It allows PCI devices that are
93 behind an IOMMU to recover from page faults.
94
95 If unsure, say N.
96
88config PCI_IOAPIC 97config PCI_IOAPIC
89 bool 98 bool
90 depends on PCI 99 depends on PCI
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
index 5ceff3e16e1b..bf892a025d4f 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
@@ -2,9 +2,11 @@
2 * drivers/pci/ats.c 2 * drivers/pci/ats.c
3 * 3 *
4 * Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com> 4 * Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com>
5 * Copyright (C) 2011 Advanced Micro Devices,
5 * 6 *
6 * PCI Express I/O Virtualization (IOV) support. 7 * PCI Express I/O Virtualization (IOV) support.
7 * Address Translation Service 1.0 8 * Address Translation Service 1.0
9 * Page Request Interface added by Joerg Roedel <joerg.roedel@amd.com>
8 */ 10 */
9 11
10#include <linux/pci-ats.h> 12#include <linux/pci-ats.h>
@@ -156,3 +158,168 @@ int pci_ats_queue_depth(struct pci_dev *dev)
156 PCI_ATS_MAX_QDEP; 158 PCI_ATS_MAX_QDEP;
157} 159}
158EXPORT_SYMBOL_GPL(pci_ats_queue_depth); 160EXPORT_SYMBOL_GPL(pci_ats_queue_depth);
161
162#ifdef CONFIG_PCI_PRI
163/**
164 * pci_enable_pri - Enable PRI capability
165 * @ pdev: PCI device structure
166 *
167 * Returns 0 on success, negative value on error
168 */
169int pci_enable_pri(struct pci_dev *pdev, u32 reqs)
170{
171 u16 control, status;
172 u32 max_requests;
173 int pos;
174
175 pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
176 if (!pos)
177 return -EINVAL;
178
179 pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
180 pci_read_config_word(pdev, pos + PCI_PRI_STATUS_OFF, &status);
181 if ((control & PCI_PRI_ENABLE) || !(status & PCI_PRI_STATUS_STOPPED))
182 return -EBUSY;
183
184 pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ_OFF, &max_requests);
185 reqs = min(max_requests, reqs);
186 pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ_OFF, reqs);
187
188 control |= PCI_PRI_ENABLE;
189 pci_write_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, control);
190
191 return 0;
192}
193EXPORT_SYMBOL_GPL(pci_enable_pri);
194
195/**
196 * pci_disable_pri - Disable PRI capability
197 * @pdev: PCI device structure
198 *
199 * Only clears the enabled-bit, regardless of its former value
200 */
201void pci_disable_pri(struct pci_dev *pdev)
202{
203 u16 control;
204 int pos;
205
206 pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
207 if (!pos)
208 return;
209
210 pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
211 control &= ~PCI_PRI_ENABLE;
212 pci_write_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, control);
213}
214EXPORT_SYMBOL_GPL(pci_disable_pri);
215
216/**
217 * pci_pri_enabled - Checks if PRI capability is enabled
218 * @pdev: PCI device structure
219 *
220 * Returns true if PRI is enabled on the device, false otherwise
221 */
222bool pci_pri_enabled(struct pci_dev *pdev)
223{
224 u16 control;
225 int pos;
226
227 pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
228 if (!pos)
229 return false;
230
231 pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
232
233 return (control & PCI_PRI_ENABLE) ? true : false;
234}
235EXPORT_SYMBOL_GPL(pci_pri_enabled);
236
237/**
238 * pci_reset_pri - Resets device's PRI state
239 * @pdev: PCI device structure
240 *
241 * The PRI capability must be disabled before this function is called.
242 * Returns 0 on success, negative value on error.
243 */
244int pci_reset_pri(struct pci_dev *pdev)
245{
246 u16 control;
247 int pos;
248
249 pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
250 if (!pos)
251 return -EINVAL;
252
253 pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
254 if (control & PCI_PRI_ENABLE)
255 return -EBUSY;
256
257 control |= PCI_PRI_RESET;
258
259 pci_write_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, control);
260
261 return 0;
262}
263EXPORT_SYMBOL_GPL(pci_reset_pri);
264
265/**
266 * pci_pri_stopped - Checks whether the PRI capability is stopped
267 * @pdev: PCI device structure
268 *
269 * Returns true if the PRI capability on the device is disabled and the
270 * device has no outstanding PRI requests, false otherwise. The device
271 * indicates this via the STOPPED bit in the status register of the
272 * capability.
273 * The device internal state can be cleared by resetting the PRI state
274 * with pci_reset_pri(). This can force the capability into the STOPPED
275 * state.
276 */
277bool pci_pri_stopped(struct pci_dev *pdev)
278{
279 u16 control, status;
280 int pos;
281
282 pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
283 if (!pos)
284 return true;
285
286 pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
287 pci_read_config_word(pdev, pos + PCI_PRI_STATUS_OFF, &status);
288
289 if (control & PCI_PRI_ENABLE)
290 return false;
291
292 return (status & PCI_PRI_STATUS_STOPPED) ? true : false;
293}
294EXPORT_SYMBOL_GPL(pci_pri_stopped);
295
296/**
297 * pci_pri_status - Request PRI status of a device
298 * @pdev: PCI device structure
299 *
300 * Returns negative value on failure, status on success. The status can
301 * be checked against status-bits. Supported bits are currently:
302 * PCI_PRI_STATUS_RF: Response failure
303 * PCI_PRI_STATUS_UPRGI: Unexpected Page Request Group Index
304 * PCI_PRI_STATUS_STOPPED: PRI has stopped
305 */
306int pci_pri_status(struct pci_dev *pdev)
307{
308 u16 status, control;
309 int pos;
310
311 pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
312 if (!pos)
313 return -EINVAL;
314
315 pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
316 pci_read_config_word(pdev, pos + PCI_PRI_STATUS_OFF, &status);
317
318 /* Stopped bit is undefined when enable == 1, so clear it */
319 if (control & PCI_PRI_ENABLE)
320 status &= ~PCI_PRI_STATUS_STOPPED;
321
322 return status;
323}
324EXPORT_SYMBOL_GPL(pci_pri_status);
325#endif /* CONFIG_PCI_PRI */
diff --git a/include/linux/pci-ats.h b/include/linux/pci-ats.h
index 4eab42bf2af9..071395251abf 100644
--- a/include/linux/pci-ats.h
+++ b/include/linux/pci-ats.h
@@ -17,6 +17,7 @@ struct pci_ats {
17extern int pci_enable_ats(struct pci_dev *dev, int ps); 17extern int pci_enable_ats(struct pci_dev *dev, int ps);
18extern void pci_disable_ats(struct pci_dev *dev); 18extern void pci_disable_ats(struct pci_dev *dev);
19extern int pci_ats_queue_depth(struct pci_dev *dev); 19extern int pci_ats_queue_depth(struct pci_dev *dev);
20
20/** 21/**
21 * pci_ats_enabled - query the ATS status 22 * pci_ats_enabled - query the ATS status
22 * @dev: the PCI device 23 * @dev: the PCI device
@@ -51,4 +52,45 @@ static inline int pci_ats_enabled(struct pci_dev *dev)
51 52
52#endif /* CONFIG_PCI_IOV */ 53#endif /* CONFIG_PCI_IOV */
53 54
55#ifdef CONFIG_PCI_PRI
56
57extern int pci_enable_pri(struct pci_dev *pdev, u32 reqs);
58extern void pci_disable_pri(struct pci_dev *pdev);
59extern bool pci_pri_enabled(struct pci_dev *pdev);
60extern int pci_reset_pri(struct pci_dev *pdev);
61extern bool pci_pri_stopped(struct pci_dev *pdev);
62extern int pci_pri_status(struct pci_dev *pdev);
63
64#else /* CONFIG_PCI_PRI */
65
66static inline int pci_enable_pri(struct pci_dev *pdev, u32 reqs)
67{
68 return -ENODEV;
69}
70
71static inline void pci_disable_pri(struct pci_dev *pdev)
72{
73}
74
75static inline bool pci_pri_enabled(struct pci_dev *pdev)
76{
77 return false;
78}
79
80static inline int pci_reset_pri(struct pci_dev *pdev)
81{
82 return -ENODEV;
83}
84
85static inline bool pci_pri_stopped(struct pci_dev *pdev)
86{
87 return true;
88}
89
90static inline int pci_pri_status(struct pci_dev *pdev)
91{
92 return -ENODEV;
93}
94#endif /* CONFIG_PCI_PRI */
95
54#endif /* LINUX_PCI_ATS_H*/ 96#endif /* LINUX_PCI_ATS_H*/
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index e8840964aca1..7fc32aff94d2 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -663,6 +663,18 @@
663#define PCI_ATS_CTRL_STU(x) ((x) & 0x1f) /* Smallest Translation Unit */ 663#define PCI_ATS_CTRL_STU(x) ((x) & 0x1f) /* Smallest Translation Unit */
664#define PCI_ATS_MIN_STU 12 /* shift of minimum STU block */ 664#define PCI_ATS_MIN_STU 12 /* shift of minimum STU block */
665 665
666/* Page Request Interface */
667#define PCI_PRI_CAP 0x13 /* PRI capability ID */
668#define PCI_PRI_CONTROL_OFF 0x04 /* Offset of control register */
669#define PCI_PRI_STATUS_OFF 0x06 /* Offset of status register */
670#define PCI_PRI_ENABLE 0x0001 /* Enable mask */
671#define PCI_PRI_RESET 0x0002 /* Reset bit mask */
672#define PCI_PRI_STATUS_RF 0x0001 /* Request Failure */
673#define PCI_PRI_STATUS_UPRGI 0x0002 /* Unexpected PRG index */
674#define PCI_PRI_STATUS_STOPPED 0x0100 /* PRI Stopped */
675#define PCI_PRI_MAX_REQ_OFF 0x08 /* Cap offset for max reqs supported */
676#define PCI_PRI_ALLOC_REQ_OFF 0x0c /* Cap offset for max reqs allowed */
677
666/* Single Root I/O Virtualization */ 678/* Single Root I/O Virtualization */
667#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */ 679#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */
668#define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */ 680#define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */