diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2011-09-27 09:57:16 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2011-10-14 12:05:35 -0400 |
commit | 086ac11f6435c9dc2fe5025fc8ea3a1dbca273d6 (patch) | |
tree | 29e9445f029b73bac174900cb68d5e1fd2748cef | |
parent | c320b976d7837c561ce4aa49dfe0a64f0e527ce4 (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>
-rw-r--r-- | drivers/pci/Kconfig | 13 | ||||
-rw-r--r-- | drivers/pci/ats.c | 113 | ||||
-rw-r--r-- | include/linux/pci-ats.h | 31 | ||||
-rw-r--r-- | include/linux/pci_regs.h | 8 |
4 files changed, 165 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 | ||
97 | config 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 | |||
97 | config PCI_IOAPIC | 110 | config 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 | } |
324 | EXPORT_SYMBOL_GPL(pci_pri_status); | 325 | EXPORT_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 | */ | ||
338 | int 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 | } | ||
365 | EXPORT_SYMBOL_GPL(pci_enable_pasid); | ||
366 | |||
367 | /** | ||
368 | * pci_disable_pasid - Disable the PASID capability | ||
369 | * @pdev: PCI device structure | ||
370 | * | ||
371 | */ | ||
372 | void 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 | } | ||
383 | EXPORT_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 | */ | ||
396 | int 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 | } | ||
411 | EXPORT_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 | */ | ||
422 | int 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 | } | ||
437 | EXPORT_SYMBOL_GPL(pci_max_pasids); | ||
438 | #endif /* CONFIG_PCI_PASID */ | ||
diff --git a/include/linux/pci-ats.h b/include/linux/pci-ats.h index 071395251abf..e3d0b3890249 100644 --- a/include/linux/pci-ats.h +++ b/include/linux/pci-ats.h | |||
@@ -93,4 +93,35 @@ static inline int pci_pri_status(struct pci_dev *pdev) | |||
93 | } | 93 | } |
94 | #endif /* CONFIG_PCI_PRI */ | 94 | #endif /* CONFIG_PCI_PRI */ |
95 | 95 | ||
96 | #ifdef CONFIG_PCI_PASID | ||
97 | |||
98 | extern int pci_enable_pasid(struct pci_dev *pdev, int features); | ||
99 | extern void pci_disable_pasid(struct pci_dev *pdev); | ||
100 | extern int pci_pasid_features(struct pci_dev *pdev); | ||
101 | extern int pci_max_pasids(struct pci_dev *pdev); | ||
102 | |||
103 | #else /* CONFIG_PCI_PASID */ | ||
104 | |||
105 | static inline int pci_enable_pasid(struct pci_dev *pdev, int features) | ||
106 | { | ||
107 | return -EINVAL; | ||
108 | } | ||
109 | |||
110 | static inline void pci_disable_pasid(struct pci_dev *pdev) | ||
111 | { | ||
112 | } | ||
113 | |||
114 | static inline int pci_pasid_features(struct pci_dev *pdev) | ||
115 | { | ||
116 | return -EINVAL; | ||
117 | } | ||
118 | |||
119 | static inline int pci_max_pasids(struct pci_dev *pdev) | ||
120 | { | ||
121 | return -EINVAL; | ||
122 | } | ||
123 | |||
124 | #endif /* CONFIG_PCI_PASID */ | ||
125 | |||
126 | |||
96 | #endif /* LINUX_PCI_ATS_H*/ | 127 | #endif /* LINUX_PCI_ATS_H*/ |
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index 7fc32aff94d2..b5d9657f3100 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h | |||
@@ -675,6 +675,14 @@ | |||
675 | #define PCI_PRI_MAX_REQ_OFF 0x08 /* Cap offset for max reqs supported */ | 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 */ | 676 | #define PCI_PRI_ALLOC_REQ_OFF 0x0c /* Cap offset for max reqs allowed */ |
677 | 677 | ||
678 | /* PASID capability */ | ||
679 | #define PCI_PASID_CAP 0x1b /* PASID capability ID */ | ||
680 | #define PCI_PASID_CAP_OFF 0x04 /* PASID feature register */ | ||
681 | #define PCI_PASID_CONTROL_OFF 0x06 /* PASID control register */ | ||
682 | #define PCI_PASID_ENABLE 0x01 /* Enable/Supported bit */ | ||
683 | #define PCI_PASID_EXEC 0x02 /* Exec permissions Enable/Supported */ | ||
684 | #define PCI_PASID_PRIV 0x04 /* Priviledge Mode Enable/Support */ | ||
685 | |||
678 | /* Single Root I/O Virtualization */ | 686 | /* Single Root I/O Virtualization */ |
679 | #define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */ | 687 | #define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */ |
680 | #define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */ | 688 | #define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */ |