diff options
-rw-r--r-- | drivers/pci/Kconfig | 9 | ||||
-rw-r--r-- | drivers/pci/ats.c | 167 | ||||
-rw-r--r-- | include/linux/pci-ats.h | 42 | ||||
-rw-r--r-- | include/linux/pci_regs.h | 12 |
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 | ||
88 | config 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 | |||
88 | config PCI_IOAPIC | 97 | config 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 | } |
158 | EXPORT_SYMBOL_GPL(pci_ats_queue_depth); | 160 | EXPORT_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 | */ | ||
169 | int 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 | } | ||
193 | EXPORT_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 | */ | ||
201 | void 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 | } | ||
214 | EXPORT_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 | */ | ||
222 | bool 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 | } | ||
235 | EXPORT_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 | */ | ||
244 | int 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 | } | ||
263 | EXPORT_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 | */ | ||
277 | bool 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 | } | ||
294 | EXPORT_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 | */ | ||
306 | int 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 | } | ||
324 | EXPORT_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 { | |||
17 | extern int pci_enable_ats(struct pci_dev *dev, int ps); | 17 | extern int pci_enable_ats(struct pci_dev *dev, int ps); |
18 | extern void pci_disable_ats(struct pci_dev *dev); | 18 | extern void pci_disable_ats(struct pci_dev *dev); |
19 | extern int pci_ats_queue_depth(struct pci_dev *dev); | 19 | extern 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 | |||
57 | extern int pci_enable_pri(struct pci_dev *pdev, u32 reqs); | ||
58 | extern void pci_disable_pri(struct pci_dev *pdev); | ||
59 | extern bool pci_pri_enabled(struct pci_dev *pdev); | ||
60 | extern int pci_reset_pri(struct pci_dev *pdev); | ||
61 | extern bool pci_pri_stopped(struct pci_dev *pdev); | ||
62 | extern int pci_pri_status(struct pci_dev *pdev); | ||
63 | |||
64 | #else /* CONFIG_PCI_PRI */ | ||
65 | |||
66 | static inline int pci_enable_pri(struct pci_dev *pdev, u32 reqs) | ||
67 | { | ||
68 | return -ENODEV; | ||
69 | } | ||
70 | |||
71 | static inline void pci_disable_pri(struct pci_dev *pdev) | ||
72 | { | ||
73 | } | ||
74 | |||
75 | static inline bool pci_pri_enabled(struct pci_dev *pdev) | ||
76 | { | ||
77 | return false; | ||
78 | } | ||
79 | |||
80 | static inline int pci_reset_pri(struct pci_dev *pdev) | ||
81 | { | ||
82 | return -ENODEV; | ||
83 | } | ||
84 | |||
85 | static inline bool pci_pri_stopped(struct pci_dev *pdev) | ||
86 | { | ||
87 | return true; | ||
88 | } | ||
89 | |||
90 | static 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 */ |