aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/ats.c
diff options
context:
space:
mode:
authorJoerg Roedel <joerg.roedel@amd.com>2011-09-27 09:57:16 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2011-10-14 12:05:35 -0400
commit086ac11f6435c9dc2fe5025fc8ea3a1dbca273d6 (patch)
tree29e9445f029b73bac174900cb68d5e1fd2748cef /drivers/pci/ats.c
parentc320b976d7837c561ce4aa49dfe0a64f0e527ce4 (diff)
PCI: Add support for PASID capability
Devices supporting Process Address Space Identifiers (PASIDs) can use an IOMMU to access multiple IO address spaces at the same time. A PCIe device indicates support for this feature by implementing the PASID capability. This patch adds support for the capability to the Linux kernel. 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.c113
1 files changed, 113 insertions, 0 deletions
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
index bf892a025d4f..f727a09eb72f 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
@@ -7,6 +7,7 @@
7 * PCI Express I/O Virtualization (IOV) support. 7 * PCI Express I/O Virtualization (IOV) support.
8 * Address Translation Service 1.0 8 * Address Translation Service 1.0
9 * Page Request Interface added by Joerg Roedel <joerg.roedel@amd.com> 9 * Page Request Interface added by Joerg Roedel <joerg.roedel@amd.com>
10 * PASID support added by Joerg Roedel <joerg.roedel@amd.com>
10 */ 11 */
11 12
12#include <linux/pci-ats.h> 13#include <linux/pci-ats.h>
@@ -323,3 +324,115 @@ int pci_pri_status(struct pci_dev *pdev)
323} 324}
324EXPORT_SYMBOL_GPL(pci_pri_status); 325EXPORT_SYMBOL_GPL(pci_pri_status);
325#endif /* CONFIG_PCI_PRI */ 326#endif /* CONFIG_PCI_PRI */
327
328#ifdef CONFIG_PCI_PASID
329/**
330 * pci_enable_pasid - Enable the PASID capability
331 * @pdev: PCI device structure
332 * @features: Features to enable
333 *
334 * Returns 0 on success, negative value on error. This function checks
335 * whether the features are actually supported by the device and returns
336 * an error if not.
337 */
338int pci_enable_pasid(struct pci_dev *pdev, int features)
339{
340 u16 control, supported;
341 int pos;
342
343 pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
344 if (!pos)
345 return -EINVAL;
346
347 pci_read_config_word(pdev, pos + PCI_PASID_CONTROL_OFF, &control);
348 pci_read_config_word(pdev, pos + PCI_PASID_CAP_OFF, &supported);
349
350 if (!(supported & PCI_PASID_ENABLE))
351 return -EINVAL;
352
353 supported &= PCI_PASID_EXEC | PCI_PASID_PRIV;
354
355 /* User wants to enable anything unsupported? */
356 if ((supported & features) != features)
357 return -EINVAL;
358
359 control = PCI_PASID_ENABLE | features;
360
361 pci_write_config_word(pdev, pos + PCI_PASID_CONTROL_OFF, control);
362
363 return 0;
364}
365EXPORT_SYMBOL_GPL(pci_enable_pasid);
366
367/**
368 * pci_disable_pasid - Disable the PASID capability
369 * @pdev: PCI device structure
370 *
371 */
372void pci_disable_pasid(struct pci_dev *pdev)
373{
374 u16 control = 0;
375 int pos;
376
377 pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
378 if (!pos)
379 return;
380
381 pci_write_config_word(pdev, pos + PCI_PASID_CONTROL_OFF, control);
382}
383EXPORT_SYMBOL_GPL(pci_disable_pasid);
384
385/**
386 * pci_pasid_features - Check which PASID features are supported
387 * @pdev: PCI device structure
388 *
389 * Returns a negative value when no PASI capability is present.
390 * Otherwise is returns a bitmask with supported features. Current
391 * features reported are:
392 * PCI_PASID_ENABLE - PASID capability can be enabled
393 * PCI_PASID_EXEC - Execute permission supported
394 * PCI_PASID_PRIV - Priviledged mode supported
395 */
396int pci_pasid_features(struct pci_dev *pdev)
397{
398 u16 supported;
399 int pos;
400
401 pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
402 if (!pos)
403 return -EINVAL;
404
405 pci_read_config_word(pdev, pos + PCI_PASID_CAP_OFF, &supported);
406
407 supported &= PCI_PASID_ENABLE | PCI_PASID_EXEC | PCI_PASID_PRIV;
408
409 return supported;
410}
411EXPORT_SYMBOL_GPL(pci_pasid_features);
412
413#define PASID_NUMBER_SHIFT 8
414#define PASID_NUMBER_MASK (0x1f << PASID_NUMBER_SHIFT)
415/**
416 * pci_max_pasid - Get maximum number of PASIDs supported by device
417 * @pdev: PCI device structure
418 *
419 * Returns negative value when PASID capability is not present.
420 * Otherwise it returns the numer of supported PASIDs.
421 */
422int pci_max_pasids(struct pci_dev *pdev)
423{
424 u16 supported;
425 int pos;
426
427 pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
428 if (!pos)
429 return -EINVAL;
430
431 pci_read_config_word(pdev, pos + PCI_PASID_CAP_OFF, &supported);
432
433 supported = (supported & PASID_NUMBER_MASK) >> PASID_NUMBER_SHIFT;
434
435 return (1 << supported);
436}
437EXPORT_SYMBOL_GPL(pci_max_pasids);
438#endif /* CONFIG_PCI_PASID */