aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/ats.c
diff options
context:
space:
mode:
authorJoerg Roedel <joerg.roedel@amd.com>2011-09-27 09:57:15 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2011-10-14 12:05:34 -0400
commitc320b976d7837c561ce4aa49dfe0a64f0e527ce4 (patch)
tree09d12286e3c63ab15a472468795204eeb154f83c /drivers/pci/ats.c
parentd4c0636c2107010f0ef8c4dfbb1d6368ae3b3ed9 (diff)
PCI: Add implementation for PRI capability
Implement the necessary functions to handle PRI capabilities on PCIe devices. With PRI devices behind an IOMMU can signal page fault conditions to software and recover from such faults. Reviewed-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/ats.c')
-rw-r--r--drivers/pci/ats.c167
1 files changed, 167 insertions, 0 deletions
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 */