aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
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
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')
-rw-r--r--drivers/pci/Kconfig13
-rw-r--r--drivers/pci/ats.c113
2 files changed, 126 insertions, 0 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index fb1e9707f91e..cec66064ee4b 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -94,6 +94,19 @@ config PCI_PRI
94 94
95 If unsure, say N. 95 If unsure, say N.
96 96
97config PCI_PASID
98 bool "PCI PASID support"
99 depends on PCI
100 select PCI_ATS
101 help
102 Process Address Space Identifiers (PASIDs) can be used by PCI devices
103 to access more than one IO address space at the same time. To make
104 use of this feature an IOMMU is required which also supports PASIDs.
105 Select this option if you have such an IOMMU and want to compile the
106 driver for it into your kernel.
107
108 If unsure, say N.
109
97config PCI_IOAPIC 110config PCI_IOAPIC
98 bool 111 bool
99 depends on PCI 112 depends on PCI
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 */